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

View File

@@ -88,22 +88,23 @@ export function CondensedLogo() {
}
let t5;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Text bold={true}>Open Claude</Text>;
t5 = <Text bold={true}>OPEN CLAUDE</Text>;
$[8] = t5;
} else {
t5 = $[8];
}
let t6;
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;
$[10] = t6;
} else {
t6 = $[10];
}
const t6a = 'Open terminal for any LLM';
let t7;
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;
$[12] = truncatedBilling;
$[13] = truncatedModel;
@@ -114,7 +115,7 @@ export function CondensedLogo() {
const t8 = agentName ? `@${agentName} · ${truncatedCwd}` : truncatedCwd;
let t9;
if ($[15] !== t8) {
t9 = <Text dimColor={true}>{t8}</Text>;
t9 = <Text><Text color="inactive">Path</Text><Text dimColor={true}> {t8}</Text></Text>;
$[15] = t8;
$[16] = t9;
} else {
@@ -140,7 +141,7 @@ export function CondensedLogo() {
}
let t12;
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;
$[24] = t11;
$[25] = t6;

View File

@@ -250,8 +250,8 @@ export function LogoV2() {
}
const layoutMode = getLayoutMode(columns);
const userTheme = resolveThemeSetting(getGlobalConfig().theme);
const borderTitle = ` ${color("claude", userTheme)("Claude Code")} ${color("inactive", userTheme)(`v${version}`)} `;
const compactBorderTitle = color("claude", userTheme)(" Claude Code ");
const borderTitle = ` ${color("text", userTheme)("Open Claude")} ${color("inactive", userTheme)(`v${version}`)} `;
const compactBorderTitle = color("text", userTheme)(" Open Claude ");
if (layoutMode === "compact") {
let welcomeMessage = formatWelcomeMessage(username);
if (stringWidth(welcomeMessage) > columns - 4) {
@@ -328,7 +328,7 @@ export function LogoV2() {
t18 = $[42];
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 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 t11 = "column";
const t12 = "round";
const t13 = "claude";
const t13 = "inactive";
let t14;
if ($[44] !== borderTitle) {
t14 = {
@@ -359,12 +359,12 @@ export function LogoV2() {
t14 = $[45];
}
const T2 = Box;
const t15 = layoutMode === "horizontal" ? "row" : "column";
const t16 = 1;
const t15 = "column";
const t16 = 0;
const t17 = 1;
let t18;
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;
$[47] = t18;
} else {
@@ -379,7 +379,7 @@ export function LogoV2() {
}
let t20;
if ($[49] !== modelLine) {
t20 = <Text dimColor={true}>{modelLine}</Text>;
t20 = <Text><Text color="inactive">Model</Text><Text dimColor={true}> {modelLine}</Text></Text>;
$[49] = modelLine;
$[50] = t20;
} else {
@@ -387,7 +387,7 @@ export function LogoV2() {
}
let t21;
if ($[51] !== cwdLine) {
t21 = <Text dimColor={true}>{cwdLine}</Text>;
t21 = <Text><Text color="inactive">Path</Text><Text dimColor={true}> {cwdLine}</Text></Text>;
$[51] = cwdLine;
$[52] = t21;
} else {
@@ -395,7 +395,7 @@ export function LogoV2() {
}
let t22;
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;
$[54] = t21;
$[55] = t22;
@@ -403,9 +403,9 @@ export function LogoV2() {
t22 = $[55];
}
let t23;
if ($[56] !== leftWidth || $[57] !== t18 || $[58] !== t22) {
t23 = <Box flexDirection="column" width={leftWidth} justifyContent="space-between" alignItems="center" minHeight={9}>{t18}{t19}{t22}</Box>;
$[56] = leftWidth;
if ($[56] !== columns || $[57] !== t18 || $[58] !== t22) {
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] = columns;
$[57] = t18;
$[58] = t22;
$[59] = t23;
@@ -414,13 +414,13 @@ export function LogoV2() {
}
let t24;
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;
$[61] = t24;
} else {
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;
if ($[62] !== T2 || $[63] !== t15 || $[64] !== t23 || $[65] !== t24 || $[66] !== t25) {
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 {
title: 'Recent activity',
title: 'Recent Sessions',
lines,
footer: lines.length > 0 ? '/resume for more' : undefined,
emptyMessage: 'No recent activity'
emptyMessage: 'No recent sessions'
};
}
export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
@@ -39,9 +39,9 @@ export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
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 {
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,
footer: lines.length > 0 ? '/release-notes for more' : undefined,
emptyMessage
@@ -73,7 +73,7 @@ export function createProjectOnboardingFeed(steps: Step[]): FeedConfig {
}
export function createGuestPassesFeed(): FeedConfig {
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 {
title: '3 guest passes',
lines: [],

View File

@@ -6,6 +6,7 @@ import {
codexStreamToAnthropic,
convertAnthropicMessagesToResponsesInput,
convertCodexResponseToAnthropicMessage,
convertToolsToResponsesTools,
} from './codexShim.js'
import {
resolveCodexApiCredentials,
@@ -71,6 +72,77 @@ describe('Codex provider config', () => {
})
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', () => {
const items = convertAnthropicMessagesToResponsesInput([
{

View File

@@ -300,13 +300,75 @@ export function convertToolsToResponsesTools(
): ResponsesTool[] {
return tools
.filter(tool => tool.name && tool.name !== 'ToolSearchTool')
.map(tool => ({
type: 'function',
name: tool.name ?? 'tool',
description: tool.description ?? '',
parameters: tool.input_schema ?? { type: 'object', properties: {} },
strict: true,
}))
.map(tool => {
const parameters = tool.input_schema ?? { type: 'object', properties: {} }
return {
type: 'function',
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 {

View File

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