diff --git a/README.md b/README.md index 73bd6bca..c9b1c127 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ Stdin mode is selected with intent-first rules: | `--keep-alive` | false | Keep server running after browser disconnects (stop manually with Ctrl+C) | | `--background` | false | Keep the server running in the background and output JSON connection info | | `--context ` | git default (3) | Limit surrounding context lines per change (`0` shows changes only; not available with `--pr` or stdin) | +| `--title ` | - | Custom browser tab title, to tell review sessions apart when several difit instances are open | ## 💬 Comment System diff --git a/src/cli/index.ts b/src/cli/index.ts index 3f8d4037..cd462d3a 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -90,6 +90,7 @@ interface CliOptions { background?: boolean; context?: number; mergeBase?: boolean; + title?: string; } const program = new Command(); @@ -128,6 +129,7 @@ program '--merge-base', 'resolve the base revision with git merge-base before diffing (Git revision mode only)', ) + .option('--title <title>', 'custom browser tab title for this review session') .action(async (commitish: string, compareWith: string | undefined, options: CliOptions) => { try { const isBackgroundChild = process.env[BACKGROUND_CHILD_ENV] === '1'; @@ -234,6 +236,7 @@ program openBrowser: options.open, clearComments: options.clean, keepAlive: options.keepAlive, + title: options.title, ...(commentImports.length > 0 ? { commentImports } : {}), }); @@ -297,6 +300,7 @@ program contextLines: options.context, diffMode: determineDiffMode(selection, compareWith), repoPath, + title: options.title, ...(commentImports.length > 0 ? { commentImports } : {}), }); diff --git a/src/client/App.test.tsx b/src/client/App.test.tsx index a8bd0fdf..608a80c1 100644 --- a/src/client/App.test.tsx +++ b/src/client/App.test.tsx @@ -1078,3 +1078,21 @@ describe('App Component - Mobile sidebar auto-close', () => { }); }); }); + +describe('App Component - Custom tab title', () => { + beforeEach(() => { + vi.clearAllMocks(); + mockComments = []; + mockConfirm.mockReturnValue(false); + }); + + it('sets document.title from the diff response when --title is provided', async () => { + mockFetch({ ...mockDiffResponse, title: 'DEV-1234 review' }); + + renderApp(); + + await waitFor(() => { + expect(document.title).toBe('DEV-1234 review'); + }); + }); +}); diff --git a/src/client/App.tsx b/src/client/App.tsx index dde8039c..ea0b22c8 100644 --- a/src/client/App.tsx +++ b/src/client/App.tsx @@ -717,6 +717,7 @@ function App() { } setDiffData(data); setDiffDataVersion((prev) => prev + 1); + if (data.title) document.title = data.title; // Update resolved revision state from server response setResolvedBaseRevision( diff --git a/src/server/server.test.ts b/src/server/server.test.ts index b6542ba9..c6b8e62e 100644 --- a/src/server/server.test.ts +++ b/src/server/server.test.ts @@ -466,6 +466,21 @@ describe('Server Integration Tests', () => { expect(data).toHaveProperty('requestedTargetCommitish', 'HEAD'); }); + it('GET /api/diff includes the custom title when --title is set', async () => { + const result = await startServer({ + selection: { targetCommitish: 'HEAD', baseCommitish: 'HEAD^' }, + preferredPort: 9035, + title: 'DEV-1234 review', + }); + servers.push(result.server); + + const response = await fetch(`http://localhost:${result.port}/api/diff`); + const data = (await response.json()) as any; + + expect(response.ok).toBe(true); + expect(data).toHaveProperty('title', 'DEV-1234 review'); + }); + it('GET /api/diff returns a JSON 500 on parse failure and does not poison subsequent requests', async () => { const parser = parserInstances.at(-1); parser?.parseDiff.mockClear(); diff --git a/src/server/server.ts b/src/server/server.ts index c8feaa11..dff4e03c 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -59,6 +59,7 @@ interface ServerOptions { diffMode?: DiffMode; repoPath?: string; contextLines?: number; + title?: string; } const GENERATED_STATUS_CACHE_TTL_MS = 60_000; @@ -364,6 +365,7 @@ export async function startServer( requestedBaseMode, clearComments: options.clearComments, repositoryId, + title: options.title, commentImports: shouldIncludeCommentImports ? initialCommentImports : undefined, commentImportId: shouldIncludeCommentImports ? commentImportId : undefined, }); diff --git a/src/types/diff.ts b/src/types/diff.ts index 7cc345b1..64353711 100644 --- a/src/types/diff.ts +++ b/src/types/diff.ts @@ -61,6 +61,7 @@ export interface DiffResponse { repositoryId?: string; commentImports?: CommentImport[]; commentImportId?: string; + title?: string; } export interface GeneratedStatusResponse {