From 0b231edd4350801bedaef817c878d11da99d79e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sculier?= Date: Sat, 11 Apr 2026 17:45:41 +0200 Subject: [PATCH] Fix quick-start to resolve linked cases before codeman-cases fallback /api/quick-start was always resolving caseName against CASES_DIR, ignoring any entries in ~/.codeman/linked-cases.json. This caused sessions to start in ~/codeman-cases/ even when the case was linked to an external project directory. Fix: read linked-cases.json first and prefer that path, falling back to validatePathWithinBase only when no link is found. --- src/web/routes/session-routes.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/web/routes/session-routes.ts b/src/web/routes/session-routes.ts index 7f20c5d4..2a4a85e7 100644 --- a/src/web/routes/session-routes.ts +++ b/src/web/routes/session-routes.ts @@ -6,6 +6,7 @@ import { FastifyInstance } from 'fastify'; import { join, dirname } from 'node:path'; +import { homedir } from 'node:os'; import { existsSync, statSync, mkdirSync, writeFileSync } from 'node:fs'; import { execFile } from 'node:child_process'; import fs from 'node:fs/promises'; @@ -53,6 +54,9 @@ import { RunSummaryTracker } from '../../run-summary.js'; import { MAX_INPUT_LENGTH, MAX_SESSION_NAME_LENGTH } from '../../config/terminal-limits.js'; +// Path to linked-cases registry (same file used by case-routes resolveCasePath) +const LINKED_CASES_FILE = join(homedir(), '.codeman', 'linked-cases.json'); + // Pre-compiled regex for terminal buffer cleaning (avoids per-request compilation) // eslint-disable-next-line no-control-regex const CLAUDE_BANNER_PATTERN = /\x1b\[1mClaud/; @@ -919,12 +923,23 @@ export function registerSessionRoutes( } } - const casePath = validatePathWithinBase(caseName, CASES_DIR); + // Resolve case path: check linked-cases registry first, then fall back to CASES_DIR. + // This mirrors the behaviour of resolveCasePath() in case-routes so that linked + // external project directories are honoured by quick-start just like regular case routes. + let linkedCases: Record = {}; + try { + const raw = await fs.readFile(LINKED_CASES_FILE, 'utf-8'); + linkedCases = JSON.parse(raw); + } catch { + // File missing or unparseable — treat as empty registry + } + const linkedCasePath = linkedCases[caseName]; + const casePath = linkedCasePath || validatePathWithinBase(caseName, CASES_DIR); if (!casePath) { return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid case path'); } - // Create case folder and CLAUDE.md if it doesn't exist + // Create case folder and CLAUDE.md if it doesn't exist (only for non-linked cases) if (!existsSync(casePath)) { try { mkdirSync(casePath, { recursive: true }); @@ -1098,7 +1113,7 @@ export function registerSessionRoutes( text.length < 8 ) continue; - return text.length > MAX_PROMPT_LEN ? text.slice(0, MAX_PROMPT_LEN) + '…' : text; + return text.length > MAX_PROMPT_LEN ? text.slice(0, MAX_PROMPT_LEN) + '\u2026' : text; } catch { // Malformed line — skip }