diff --git a/src/core/parser-claude.test.ts b/src/core/parser-claude.test.ts index 7a82eeb1..fb92fcaf 100644 --- a/src/core/parser-claude.test.ts +++ b/src/core/parser-claude.test.ts @@ -483,4 +483,19 @@ describe('parseClaudeSessions', () => { expect(session.requests[0].skillsUsed).toHaveLength(1); }); }); + + it('stores the Claude session cwd as workspaceRootPath', () => { + // The cwd recorded on user records is the project root. Surfacing it as + // workspaceRootPath lets config-health / SDLC workspace scans resolve the + // repo for Claude sessions, the same way the Codex parser already does. + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'claude-cwd-test-')); + withProjectsDir('s.jsonl', [ + makeUser('hello', '2025-06-15T10:00:00Z', { cwd }), + makeAssistant('hi there'), + ], (projectsDir) => { + const session = parseClaudeSessions(projectsDir)[0].sessions[0]; + expect(session.workspaceRootPath).toBe(cwd); + }); + fs.rmSync(cwd, { recursive: true, force: true }); + }); }); diff --git a/src/core/parser-claude.ts b/src/core/parser-claude.ts index dfbc17b7..5e12059c 100644 --- a/src/core/parser-claude.ts +++ b/src/core/parser-claude.ts @@ -675,6 +675,7 @@ function parseClaudeSessionFile(filePath: string, wsId: string, wsName: string): lastMessageDate: lastTs, requests, hasDevcontainer: detectDevcontainerFromRequests(requests, cwd), + workspaceRootPath: cwd || undefined, launcherKind, entrypoint, }); diff --git a/src/core/parser-opencode.test.ts b/src/core/parser-opencode.test.ts index 09e5894f..e19dabc6 100644 --- a/src/core/parser-opencode.test.ts +++ b/src/core/parser-opencode.test.ts @@ -91,4 +91,29 @@ describe('parseOpenCodeSessions', () => { }, ); }); + + it('stores the OpenCode session directory as workspaceRootPath', () => { + // rawSession.directory is the project root. Surfacing it as + // workspaceRootPath lets config-health / SDLC workspace scans resolve the + // repo for OpenCode sessions, the same way the Codex parser already does. + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-dir-test-')); + withStorage( + { id: 'sess-dir', directory: dir, time: { created: 1700000000000 } }, + [ + { id: 'u1', sessionID: 'sess-dir', role: 'user', time: { created: 1700000000000 }, summary: { title: 'hi' } }, + { + id: 'a1', sessionID: 'sess-dir', role: 'assistant', parentID: 'u1', + time: { created: 1700000001000, completed: 1700000002000 }, + modelID: 'claude-sonnet-4', + tokens: { input: 100, output: 20 }, + }, + ], + (storageDir) => { + const sessions = parseOpenCodeSessions(storageDir); + expect(sessions).toHaveLength(1); + expect(sessions[0].workspaceRootPath).toBe(dir); + }, + ); + fs.rmSync(dir, { recursive: true, force: true }); + }); }); diff --git a/src/core/parser-opencode.ts b/src/core/parser-opencode.ts index b380d10e..0705c37b 100644 --- a/src/core/parser-opencode.ts +++ b/src/core/parser-opencode.ts @@ -300,6 +300,7 @@ function parseOpenCodeSession(rawSession: OcSession, storageDir: string): Sessio lastMessageDate: lastTs || (rawSession.time?.updated || null), requests, hasDevcontainer: detectDevcontainerFromRequests(requests, rawSession.directory), + workspaceRootPath: rawSession.directory || undefined, }); }