Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ export type ExternalRunner = (args: {
export const App: FC<{
manager: SessionManager;
cwd?: string;
model?: string;
messages?: Messages;
runExternal?: ExternalRunner;
}> = ({
manager,
cwd,
model,
// 既定は ja。index.tsx が解決済みカタログを注入する。
messages = catalogs.ja,
runExternal,
Expand Down Expand Up @@ -83,6 +85,7 @@ export const App: FC<{
onOpenExternal={runExternal ? openExternal : undefined}
onQuit={quit}
cwd={cwd}
model={model}
/>
</Box>
</MessagesProvider>
Expand Down
8 changes: 8 additions & 0 deletions src/core/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export interface Messages {
/** 起動バナー(banner.tsx) */
banner: {
subtitle: string;
/** 使用中モデルの表示(設定 model。未設定は CLI 既定)。 */
model: (name: string) => string;
/** model 未設定時に表示するプレースホルダ(CLI 既定)。 */
defaultModel: string;
};
/** 下部モード行(status-footer.tsx) */
footer: {
Expand Down Expand Up @@ -128,6 +132,8 @@ const ja: Messages = {
},
banner: {
subtitle: '並列 Claude Code セッションを git worktree 上で実行',
model: (name) => `モデル: ${name}`,
defaultModel: 'CLI 既定',
},
footer: {
autoMode: '自動モード',
Expand Down Expand Up @@ -184,6 +190,8 @@ const en: Messages = {
},
banner: {
subtitle: 'Parallel Claude Code sessions in git worktrees',
model: (name) => `model: ${name}`,
defaultModel: 'CLI default',
},
footer: {
autoMode: 'auto mode on',
Expand Down
8 changes: 7 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,13 @@ async function main(): Promise<void> {
};

const { waitUntilExit } = render(
<App manager={manager} cwd={repoRoot} messages={t} runExternal={runExternal} />,
<App
manager={manager}
cwd={repoRoot}
model={config.model}
messages={t}
runExternal={runExternal}
/>,
{ exitOnCtrlC: false },
);
await waitUntilExit();
Expand Down
34 changes: 34 additions & 0 deletions src/ui/banner.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render } from 'ink-testing-library';
import { describe, expect, it } from 'vitest';
import { messages } from '@/core';
import { Banner } from './banner';
import { MessagesProvider } from './i18n-context';

function renderBanner(props: Parameters<typeof Banner>[0], lang: 'ja' | 'en' = 'en') {
return render(
<MessagesProvider value={messages[lang]}>
<Banner {...props} />
</MessagesProvider>,
);
}

describe('Banner', () => {
it('設定されたモデル名をヘッダに表示する', () => {
const { lastFrame } = renderBanner({ sessionCount: 0, model: 'claude-opus-4-8' }, 'en');
expect(lastFrame()).toContain('model: claude-opus-4-8');
});

it('モデル未設定なら CLI 既定を表示する', () => {
const { lastFrame } = renderBanner({ sessionCount: 0 }, 'en');
expect(lastFrame()).toContain('model: CLI default');
});

it('モデル行は cwd 行の上に描画される', () => {
const { lastFrame } = renderBanner(
{ sessionCount: 0, model: 'sonnet', cwd: '/tmp/repo' },
'en',
);
const frame = lastFrame() ?? '';
expect(frame.indexOf('model: sonnet')).toBeLessThan(frame.indexOf('/tmp/repo'));
});
});
12 changes: 7 additions & 5 deletions src/ui/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ const LOGO_ROWS = LOGO.map((line, row) => ({
* Borderless startup header echoing Claude Code's banner: the mascot on the left
* and identity / subtitle / cwd on the right (vertically centered against it).
*/
export const Banner: FC<{ cwd?: string; sessionCount: number; totalCostUsd?: number }> = ({
cwd,
sessionCount,
totalCostUsd = 0,
}) => {
export const Banner: FC<{
cwd?: string;
model?: string;
sessionCount: number;
totalCostUsd?: number;
}> = ({ cwd, model, sessionCount, totalCostUsd = 0 }) => {
const m = useMessages();
return (
<Box>
Expand All @@ -76,6 +77,7 @@ export const Banner: FC<{ cwd?: string; sessionCount: number; totalCostUsd?: num
</Text>
</Text>
<Text dimColor>{m.banner.subtitle}</Text>
<Text dimColor>{m.banner.model(model ?? m.banner.defaultModel)}</Text>
{cwd ? <Text dimColor>{cwd}</Text> : null}
</Box>
</Box>
Expand Down
10 changes: 8 additions & 2 deletions src/ui/session-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export const SessionList: FC<{
onOpenExternal?: OpenExternal;
onQuit: () => void;
cwd?: string;
}> = ({ manager, onOpenExternal, onQuit, cwd }) => {
model?: string;
}> = ({ manager, onOpenExternal, onQuit, cwd, model }) => {
const m = useMessages();
const sessions = useSessions(manager);
const mode = useRunMode(manager);
Expand Down Expand Up @@ -246,7 +247,12 @@ export const SessionList: FC<{

return (
<Box flexDirection="column" flexGrow={1} padding={1}>
<Banner cwd={cwd} sessionCount={sessions.length} totalCostUsd={totalCostUsd(sessions)} />
<Banner
cwd={cwd}
model={model}
sessionCount={sessions.length}
totalCostUsd={totalCostUsd(sessions)}
/>

{/* flexGrow で残り高さを占め、入力欄とフッタを画面最下部へ押し下げる */}
<Box ref={rowsRef} flexDirection="column" marginY={1} flexGrow={1} overflowY="hidden">
Expand Down
Loading