Merge pull request #54 from kevincodex1/feature/updated-branding

Feature/updated branding
This commit is contained in:
Kevin Codex
2026-04-01 23:42:07 +08:00
committed by GitHub
7 changed files with 196 additions and 61 deletions

View File

@@ -34,41 +34,41 @@ type Segments = {
const POSES: Record<ClawdPose, Segments> = { const POSES: Record<ClawdPose, Segments> = {
default: { default: {
r1L: ' ╭', r1L: ' ╭',
r1E: '○ ○ ', r1E: '◌ ◌ ',
r1R: '╮', r1R: '╮',
r2L: ' ', r2L: ' ',
r2R: ' ' r2R: ' '
}, },
'look-left': { 'look-left': {
r1L: ' ╭', r1L: ' ╭',
r1E: '◔ ', r1E: '◔ ',
r1R: '╮', r1R: '╮',
r2L: ' ', r2L: ' ',
r2R: ' ' r2R: ' '
}, },
'look-right': { 'look-right': {
r1L: ' ╭', r1L: ' ╭',
r1E: ' ◔ ', r1E: ' ◔ ',
r1R: '╮', r1R: '╮',
r2L: ' ', r2L: ' ',
r2R: ' ' r2R: ' '
}, },
'arms-up': { 'arms-up': {
r1L: '\\╭', r1L: '\\╭',
r1E: '○ ○ ', r1E: '◌ ◌ ',
r1R: '╮/', r1R: '╮/',
r2L: ' ', r2L: ' ',
r2R: ' ' r2R: ' '
} }
}; };
// Apple Terminal uses a bg-fill trick (see below), so only eye poses make // Apple Terminal uses a bg-fill trick (see below), so only eye poses make
// sense. Arm poses fall back to default. // sense. Arm poses fall back to default.
const APPLE_EYES: Record<ClawdPose, string> = { const APPLE_EYES: Record<ClawdPose, string> = {
default: ' ○ ○ ', default: ' ◌ ◌ ',
'look-left': ' ◔ ', 'look-left': ' ◔ ',
'look-right': ' ◔ ', 'look-right': ' ◔ ',
'arms-up': ' ○ ○ ' 'arms-up': ' ◌ ◌ '
}; };
export function Clawd(t0) { export function Clawd(t0) {
const $ = _c(26); const $ = _c(26);
@@ -98,7 +98,7 @@ export function Clawd(t0) {
const p = POSES[pose]; const p = POSES[pose];
let t3; let t3;
if ($[4] !== p.r1L) { if ($[4] !== p.r1L) {
t3 = <Text color="clawd_body">{p.r1L}</Text>; t3 = <Text color="text">{p.r1L}</Text>;
$[4] = p.r1L; $[4] = p.r1L;
$[5] = t3; $[5] = t3;
} else { } else {
@@ -106,7 +106,7 @@ export function Clawd(t0) {
} }
let t4; let t4;
if ($[6] !== p.r1E) { if ($[6] !== p.r1E) {
t4 = <Text color="clawd_body" backgroundColor="clawd_background">{p.r1E}</Text>; t4 = <Text color="text">{p.r1E}</Text>;
$[6] = p.r1E; $[6] = p.r1E;
$[7] = t4; $[7] = t4;
} else { } else {
@@ -114,7 +114,7 @@ export function Clawd(t0) {
} }
let t5; let t5;
if ($[8] !== p.r1R) { if ($[8] !== p.r1R) {
t5 = <Text color="clawd_body">{p.r1R}</Text>; t5 = <Text color="text">{p.r1R}</Text>;
$[8] = p.r1R; $[8] = p.r1R;
$[9] = t5; $[9] = t5;
} else { } else {
@@ -132,7 +132,7 @@ export function Clawd(t0) {
} }
let t7; let t7;
if ($[14] !== p.r2L) { if ($[14] !== p.r2L) {
t7 = <Text color="clawd_body">{p.r2L}</Text>; t7 = <Text color="text">{p.r2L}</Text>;
$[14] = p.r2L; $[14] = p.r2L;
$[15] = t7; $[15] = t7;
} else { } else {
@@ -140,14 +140,14 @@ export function Clawd(t0) {
} }
let t8; let t8;
if ($[16] === Symbol.for("react.memo_cache_sentinel")) { if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
t8 = <Text color="clawd_body" backgroundColor="clawd_background">OPEN </Text>; t8 = <Text color="text"> OC </Text>;
$[16] = t8; $[16] = t8;
} else { } else {
t8 = $[16]; t8 = $[16];
} }
let t9; let t9;
if ($[17] !== p.r2R) { if ($[17] !== p.r2R) {
t9 = <Text color="clawd_body">{p.r2R}</Text>; t9 = <Text color="text">{p.r2R}</Text>;
$[17] = p.r2R; $[17] = p.r2R;
$[18] = t9; $[18] = t9;
} else { } else {
@@ -164,7 +164,7 @@ export function Clawd(t0) {
} }
let t11; let t11;
if ($[22] === Symbol.for("react.memo_cache_sentinel")) { if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
t11 = <Text color="clawd_body">{" "}{" "}</Text>; t11 = <Text color="inactive">{" "}{" "}</Text>;
$[22] = t11; $[22] = t11;
} else { } else {
t11 = $[22]; t11 = $[22];
@@ -187,7 +187,7 @@ function AppleTerminalClawd(t0) {
} = t0; } = t0;
let t1; let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) { if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Text color="clawd_body"></Text>; t1 = <Text color="text"></Text>;
$[0] = t1; $[0] = t1;
} else { } else {
t1 = $[0]; t1 = $[0];
@@ -195,7 +195,7 @@ function AppleTerminalClawd(t0) {
const t2 = APPLE_EYES[pose]; const t2 = APPLE_EYES[pose];
let t3; let t3;
if ($[1] !== t2) { if ($[1] !== t2) {
t3 = <Text color="clawd_background" backgroundColor="clawd_body">{t2}</Text>; t3 = <Text color="text">{t2}</Text>;
$[1] = t2; $[1] = t2;
$[2] = t3; $[2] = t3;
} else { } else {
@@ -203,7 +203,7 @@ function AppleTerminalClawd(t0) {
} }
let t4; let t4;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) { if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t4 = <Text color="clawd_body"></Text>; t4 = <Text color="text"></Text>;
$[3] = t4; $[3] = t4;
} else { } else {
t4 = $[3]; t4 = $[3];

View File

@@ -88,22 +88,23 @@ export function CondensedLogo() {
} }
let t5; let t5;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) { if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Text bold={true}>Open Claude</Text>; t5 = <Text bold={true}>OPEN CLAUDE</Text>;
$[8] = t5; $[8] = t5;
} else { } else {
t5 = $[8]; t5 = $[8];
} }
let t6; let t6;
if ($[9] !== truncatedVersion) { if ($[9] !== truncatedVersion) {
t6 = <Text>{t5}{" "}<Text dimColor={true}>v{truncatedVersion}</Text></Text>; t6 = <Text>{t5} <Text dimColor={true}>v{truncatedVersion}</Text></Text>;
$[9] = truncatedVersion; $[9] = truncatedVersion;
$[10] = t6; $[10] = t6;
} else { } else {
t6 = $[10]; t6 = $[10];
} }
const t6a = 'Open terminal for any LLM';
let t7; let t7;
if ($[11] !== shouldSplit || $[12] !== truncatedBilling || $[13] !== truncatedModel) { if ($[11] !== shouldSplit || $[12] !== truncatedBilling || $[13] !== truncatedModel) {
t7 = shouldSplit ? <><Text dimColor={true}>{truncatedModel}</Text><Text dimColor={true}>{truncatedBilling}</Text></> : <Text dimColor={true}>{truncatedModel} · {truncatedBilling}</Text>; t7 = shouldSplit ? <><Text><Text color="inactive">Model</Text><Text dimColor={true}> {truncatedModel}</Text></Text><Text><Text color="inactive">Mode</Text><Text dimColor={true}> {truncatedBilling}</Text></Text></> : <Text><Text color="inactive">Model</Text><Text dimColor={true}> {truncatedModel} · {truncatedBilling}</Text></Text>;
$[11] = shouldSplit; $[11] = shouldSplit;
$[12] = truncatedBilling; $[12] = truncatedBilling;
$[13] = truncatedModel; $[13] = truncatedModel;
@@ -114,7 +115,7 @@ export function CondensedLogo() {
const t8 = agentName ? `@${agentName} · ${truncatedCwd}` : truncatedCwd; const t8 = agentName ? `@${agentName} · ${truncatedCwd}` : truncatedCwd;
let t9; let t9;
if ($[15] !== t8) { if ($[15] !== t8) {
t9 = <Text dimColor={true}>{t8}</Text>; t9 = <Text><Text color="inactive">Path</Text><Text dimColor={true}> {t8}</Text></Text>;
$[15] = t8; $[15] = t8;
$[16] = t9; $[16] = t9;
} else { } else {
@@ -140,7 +141,7 @@ export function CondensedLogo() {
} }
let t12; let t12;
if ($[23] !== t10 || $[24] !== t11 || $[25] !== t6 || $[26] !== t7 || $[27] !== t9) { if ($[23] !== t10 || $[24] !== t11 || $[25] !== t6 || $[26] !== t7 || $[27] !== t9) {
t12 = <OffscreenFreeze><Box flexDirection="row" gap={2} alignItems="center">{t4}<Box flexDirection="column">{t6}{t7}{t9}{t10}{t11}</Box></Box></OffscreenFreeze>; t12 = <OffscreenFreeze><Box borderStyle="round" borderColor="inactive" paddingX={2} paddingY={0} flexDirection="row" gap={2} alignItems="center"><Box flexDirection="column" alignItems="center"><Text color="inactive"></Text>{t4}<Text color="inactive"></Text></Box><Box flexDirection="column"><Text bold={true}>OPEN CLAUDE</Text><Text dimColor={true}>{t6a}</Text><Box marginTop={1}>{t6}</Box>{t7}{t9}{t10}{t11}</Box></Box></OffscreenFreeze>;
$[23] = t10; $[23] = t10;
$[24] = t11; $[24] = t11;
$[25] = t6; $[25] = t6;

View File

@@ -250,8 +250,8 @@ export function LogoV2() {
} }
const layoutMode = getLayoutMode(columns); const layoutMode = getLayoutMode(columns);
const userTheme = resolveThemeSetting(getGlobalConfig().theme); const userTheme = resolveThemeSetting(getGlobalConfig().theme);
const borderTitle = ` ${color("claude", userTheme)("Claude Code")} ${color("inactive", userTheme)(`v${version}`)} `; const borderTitle = ` ${color("text", userTheme)("Open Claude")} ${color("inactive", userTheme)(`v${version}`)} `;
const compactBorderTitle = color("claude", userTheme)(" Claude Code "); const compactBorderTitle = color("text", userTheme)(" Open Claude ");
if (layoutMode === "compact") { if (layoutMode === "compact") {
let welcomeMessage = formatWelcomeMessage(username); let welcomeMessage = formatWelcomeMessage(username);
if (stringWidth(welcomeMessage) > columns - 4) { if (stringWidth(welcomeMessage) > columns - 4) {
@@ -328,7 +328,7 @@ export function LogoV2() {
t18 = $[42]; t18 = $[42];
t19 = $[43]; t19 = $[43];
} }
return <><OffscreenFreeze><Box flexDirection="column" borderStyle="round" borderColor="claude" borderText={t11} paddingX={1} paddingY={1} alignItems="center" width={columns}><Text bold={true}>{welcomeMessage}</Text>{t12}{t13}<Text dimColor={true}>{billingType}</Text><Text dimColor={true}>{agentName ? `@${agentName} · ${truncatedCwd}` : truncatedCwd}</Text></Box></OffscreenFreeze>{t14}{t15}{t16}{t17}{t18}{t19}</>; return <><OffscreenFreeze><Box flexDirection="column" borderStyle="round" borderColor="inactive" borderText={t11} paddingX={1} paddingY={1} alignItems="center" width={columns}><Text bold={true}>{welcomeMessage}</Text>{t12}{t13}<Text dimColor={true}>{billingType}</Text><Text dimColor={true}>{agentName ? `@${agentName} · ${truncatedCwd}` : truncatedCwd}</Text></Box></OffscreenFreeze>{t14}{t15}{t16}{t17}{t18}{t19}</>;
} }
const welcomeMessage_0 = formatWelcomeMessage(username); const welcomeMessage_0 = formatWelcomeMessage(username);
const modelLine = showAccountIdentity && !process.env.IS_DEMO && config.oauthAccount?.organizationName ? `${modelDisplayName} · ${billingType} · ${config.oauthAccount.organizationName}` : `${modelDisplayName} · ${billingType}`; const modelLine = showAccountIdentity && !process.env.IS_DEMO && config.oauthAccount?.organizationName ? `${modelDisplayName} · ${billingType} · ${config.oauthAccount.organizationName}` : `${modelDisplayName} · ${billingType}`;
@@ -344,7 +344,7 @@ export function LogoV2() {
const T1 = Box; const T1 = Box;
const t11 = "column"; const t11 = "column";
const t12 = "round"; const t12 = "round";
const t13 = "claude"; const t13 = "inactive";
let t14; let t14;
if ($[44] !== borderTitle) { if ($[44] !== borderTitle) {
t14 = { t14 = {
@@ -359,12 +359,12 @@ export function LogoV2() {
t14 = $[45]; t14 = $[45];
} }
const T2 = Box; const T2 = Box;
const t15 = layoutMode === "horizontal" ? "row" : "column"; const t15 = "column";
const t16 = 1; const t16 = 0;
const t17 = 1; const t17 = 1;
let t18; let t18;
if ($[46] !== welcomeMessage_0) { if ($[46] !== welcomeMessage_0) {
t18 = <Box marginTop={1}><Text bold={true}>{welcomeMessage_0}</Text></Box>; t18 = <Box marginTop={1} flexDirection="column" alignItems="center"><Text bold={true}>OPEN CLAUDE</Text><Text dimColor={true}>open terminal for any LLM</Text><Text color="inactive"></Text><Text bold={true}>{welcomeMessage_0}</Text></Box>;
$[46] = welcomeMessage_0; $[46] = welcomeMessage_0;
$[47] = t18; $[47] = t18;
} else { } else {
@@ -379,7 +379,7 @@ export function LogoV2() {
} }
let t20; let t20;
if ($[49] !== modelLine) { if ($[49] !== modelLine) {
t20 = <Text dimColor={true}>{modelLine}</Text>; t20 = <Text><Text color="inactive">Model</Text><Text dimColor={true}> {modelLine}</Text></Text>;
$[49] = modelLine; $[49] = modelLine;
$[50] = t20; $[50] = t20;
} else { } else {
@@ -387,7 +387,7 @@ export function LogoV2() {
} }
let t21; let t21;
if ($[51] !== cwdLine) { if ($[51] !== cwdLine) {
t21 = <Text dimColor={true}>{cwdLine}</Text>; t21 = <Text><Text color="inactive">Path</Text><Text dimColor={true}> {cwdLine}</Text></Text>;
$[51] = cwdLine; $[51] = cwdLine;
$[52] = t21; $[52] = t21;
} else { } else {
@@ -395,7 +395,7 @@ export function LogoV2() {
} }
let t22; let t22;
if ($[53] !== t20 || $[54] !== t21) { if ($[53] !== t20 || $[54] !== t21) {
t22 = <Box flexDirection="column" alignItems="center">{t20}{t21}</Box>; t22 = <Box flexDirection="column" alignItems="center"><Text dimColor={true}></Text>{t20}{t21}</Box>;
$[53] = t20; $[53] = t20;
$[54] = t21; $[54] = t21;
$[55] = t22; $[55] = t22;
@@ -403,9 +403,9 @@ export function LogoV2() {
t22 = $[55]; t22 = $[55];
} }
let t23; let t23;
if ($[56] !== leftWidth || $[57] !== t18 || $[58] !== t22) { if ($[56] !== columns || $[57] !== t18 || $[58] !== t22) {
t23 = <Box flexDirection="column" width={leftWidth} justifyContent="space-between" alignItems="center" minHeight={9}>{t18}{t19}{t22}</Box>; t23 = <Box flexDirection="column" width="100%" justifyContent="center" alignItems="center" minHeight={11}><Box borderStyle="round" borderColor="inactive" paddingX={3} paddingY={1} width="100%" justifyContent="center" alignItems="center" minHeight={11}><Box flexDirection="column" alignItems="center" justifyContent="center">{t18}<Box marginY={1}>{t19}</Box>{t22}</Box></Box></Box>;
$[56] = leftWidth; $[56] = columns;
$[57] = t18; $[57] = t18;
$[58] = t22; $[58] = t22;
$[59] = t23; $[59] = t23;
@@ -414,13 +414,13 @@ export function LogoV2() {
} }
let t24; let t24;
if ($[60] !== layoutMode) { if ($[60] !== layoutMode) {
t24 = layoutMode === "horizontal" && <Box height="100%" borderStyle="single" borderColor="claude" borderDimColor={true} borderTop={false} borderBottom={false} borderLeft={false} />; t24 = false;
$[60] = layoutMode; $[60] = layoutMode;
$[61] = t24; $[61] = t24;
} else { } else {
t24 = $[61]; t24 = $[61];
} }
const t25 = layoutMode === "horizontal" && <FeedColumn feeds={showOnboarding ? [createProjectOnboardingFeed(getSteps()), createRecentActivityFeed(activities)] : showGuestPassesUpsell ? [createRecentActivityFeed(activities), createGuestPassesFeed()] : showOverageCreditUpsell ? [createRecentActivityFeed(activities), createOverageCreditFeed()] : [createRecentActivityFeed(activities), createWhatsNewFeed(changelog)]} maxWidth={rightWidth} />; const t25 = <FeedColumn feeds={showOnboarding ? [createProjectOnboardingFeed(getSteps()), createRecentActivityFeed(activities)] : showGuestPassesUpsell ? [createRecentActivityFeed(activities), createGuestPassesFeed()] : showOverageCreditUpsell ? [createRecentActivityFeed(activities), createOverageCreditFeed()] : [createRecentActivityFeed(activities), createWhatsNewFeed(changelog)]} maxWidth={columns - 4} />;
let t26; let t26;
if ($[62] !== T2 || $[63] !== t15 || $[64] !== t23 || $[65] !== t24 || $[66] !== t25) { if ($[62] !== T2 || $[63] !== t15 || $[64] !== t23 || $[65] !== t24 || $[66] !== t25) {
t26 = <T2 flexDirection={t15} paddingX={t16} gap={t17}>{t23}{t24}{t25}</T2>; t26 = <T2 flexDirection={t15} paddingX={t16} gap={t17}>{t23}{t24}{t25}</T2>;

View File

@@ -18,10 +18,10 @@ export function createRecentActivityFeed(activities: LogOption[]): FeedConfig {
}; };
}); });
return { return {
title: 'Recent activity', title: 'Recent Sessions',
lines, lines,
footer: lines.length > 0 ? '/resume for more' : undefined, footer: lines.length > 0 ? '/resume for more' : undefined,
emptyMessage: 'No recent activity' emptyMessage: 'No recent sessions'
}; };
} }
export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig { export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
@@ -39,9 +39,9 @@ export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
text: note text: note
}; };
}); });
const emptyMessage = "external" === 'ant' ? 'Unable to fetch latest claude-cli-internal commits' : 'Check the Claude Code changelog for updates'; const emptyMessage = "external" === 'ant' ? 'Unable to fetch latest claude-cli-internal commits' : 'Check /release-notes for recent updates';
return { return {
title: "external" === 'ant' ? "What's new [ANT-ONLY: Latest CC commits]" : "What's new", title: "external" === 'ant' ? "Open Claude Updates [ANT-ONLY: Latest CC commits]" : "Open Claude Updates",
lines, lines,
footer: lines.length > 0 ? '/release-notes for more' : undefined, footer: lines.length > 0 ? '/release-notes for more' : undefined,
emptyMessage emptyMessage
@@ -73,7 +73,7 @@ export function createProjectOnboardingFeed(steps: Step[]): FeedConfig {
} }
export function createGuestPassesFeed(): FeedConfig { export function createGuestPassesFeed(): FeedConfig {
const reward = getCachedReferrerReward(); const reward = getCachedReferrerReward();
const subtitle = reward ? `Share Claude Code and earn ${formatCreditAmount(reward)} of extra usage` : 'Share Claude Code with friends'; const subtitle = reward ? `Share Open Claude and earn ${formatCreditAmount(reward)} of extra usage` : 'Share Open Claude with friends';
return { return {
title: '3 guest passes', title: '3 guest passes',
lines: [], lines: [],

View File

@@ -6,6 +6,7 @@ import {
codexStreamToAnthropic, codexStreamToAnthropic,
convertAnthropicMessagesToResponsesInput, convertAnthropicMessagesToResponsesInput,
convertCodexResponseToAnthropicMessage, convertCodexResponseToAnthropicMessage,
convertToolsToResponsesTools,
} from './codexShim.js' } from './codexShim.js'
import { import {
resolveCodexApiCredentials, resolveCodexApiCredentials,
@@ -71,6 +72,77 @@ describe('Codex provider config', () => {
}) })
describe('Codex request translation', () => { describe('Codex request translation', () => {
test('disables strict mode for tools with optional parameters', () => {
const tools = convertToolsToResponsesTools([
{
name: 'Agent',
description: 'Spawn a sub-agent',
input_schema: {
type: 'object',
properties: {
description: { type: 'string' },
prompt: { type: 'string' },
subagent_type: { type: 'string' },
},
required: ['description', 'prompt'],
additionalProperties: false,
},
},
])
expect(tools).toEqual([
{
type: 'function',
name: 'Agent',
description: 'Spawn a sub-agent',
parameters: {
type: 'object',
properties: {
description: { type: 'string' },
prompt: { type: 'string' },
subagent_type: { type: 'string' },
},
required: ['description', 'prompt'],
additionalProperties: false,
},
},
])
})
test('keeps strict mode for tools whose schema already matches Responses requirements', () => {
const tools = convertToolsToResponsesTools([
{
name: 'Ping',
description: 'Ping tool',
input_schema: {
type: 'object',
properties: {
value: { type: 'string' },
},
required: ['value'],
additionalProperties: false,
},
},
])
expect(tools).toEqual([
{
type: 'function',
name: 'Ping',
description: 'Ping tool',
parameters: {
type: 'object',
properties: {
value: { type: 'string' },
},
required: ['value'],
additionalProperties: false,
},
strict: true,
},
])
})
test('converts assistant tool use and user tool result into Responses items', () => { test('converts assistant tool use and user tool result into Responses items', () => {
const items = convertAnthropicMessagesToResponsesInput([ const items = convertAnthropicMessagesToResponsesInput([
{ {

View File

@@ -300,13 +300,75 @@ export function convertToolsToResponsesTools(
): ResponsesTool[] { ): ResponsesTool[] {
return tools return tools
.filter(tool => tool.name && tool.name !== 'ToolSearchTool') .filter(tool => tool.name && tool.name !== 'ToolSearchTool')
.map(tool => ({ .map(tool => {
type: 'function', const parameters = tool.input_schema ?? { type: 'object', properties: {} }
name: tool.name ?? 'tool',
description: tool.description ?? '', return {
parameters: tool.input_schema ?? { type: 'object', properties: {} }, type: 'function',
strict: true, name: tool.name ?? 'tool',
})) description: tool.description ?? '',
parameters,
...(isStrictResponsesSchema(parameters) ? { strict: true } : {}),
}
})
}
function isStrictResponsesSchema(schema: unknown): boolean {
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
return true
}
const record = schema as Record<string, unknown>
const type = record.type
if (type === 'object') {
const properties =
record.properties && typeof record.properties === 'object' && !Array.isArray(record.properties)
? (record.properties as Record<string, unknown>)
: {}
const propertyKeys = Object.keys(properties)
const required = Array.isArray(record.required)
? record.required.filter((value): value is string => typeof value === 'string')
: null
if (propertyKeys.length > 0) {
if (!required) return false
const requiredSet = new Set(required)
for (const key of propertyKeys) {
if (!requiredSet.has(key)) {
return false
}
}
}
for (const child of Object.values(properties)) {
if (!isStrictResponsesSchema(child)) {
return false
}
}
}
const combinators = ['anyOf', 'oneOf', 'allOf'] as const
for (const key of combinators) {
if (key in record) {
const value = record[key]
if (!Array.isArray(value) || value.some(item => !isStrictResponsesSchema(item))) {
return false
}
}
}
if ('items' in record) {
const items = record.items
if (Array.isArray(items)) {
return items.every(item => isStrictResponsesSchema(item))
}
return isStrictResponsesSchema(items)
}
return true
} }
function convertToolChoice(toolChoice: unknown): unknown { function convertToolChoice(toolChoice: unknown): unknown {

View File

@@ -96,9 +96,9 @@ export function calculateOptimalLeftWidth(
*/ */
export function formatWelcomeMessage(username: string | null): string { export function formatWelcomeMessage(username: string | null): string {
if (!username || username.length > MAX_USERNAME_LENGTH) { if (!username || username.length > MAX_USERNAME_LENGTH) {
return 'Welcome back!' return 'Welcome to Open Claude'
} }
return `Welcome back ${username}!` return `Welcome back, ${username}`
} }
/** /**