fix(file-picker): default the case picker to Codeman Cases, not Home

The "Link Existing" case picker opens with an empty path and no
sessionId, so the browse endpoint's fallback root picked whichever
root happened to be first in the list — which was always `Home`.

On the native default that's harmless (~/codeman-cases nests inside
Home anyway), but a Docker deployment binds CODEMAN_APPDATA_PATH
(Home) and CODEMAN_CASES_PATH at unrelated host paths, so the picker
opened somewhere with no cases in sight. Worse: if CODEMAN_CASES_PATH
is ever changed after cases already exist, the old cases directory
lingers, still reachable, under Home — indistinguishable at a glance
from the real one under the new Codeman Cases root.

Prefer the Codeman Cases root in the fallback chain, ahead of the
generic roots[0].

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R9ZSTEenc8soSu9bTi8Xru
This commit is contained in:
Devvyn
2026-09-05 17:14:05 +08:00
co-authored by Claude Sonnet 5
parent 6f7add7ce4
commit 06febfa032
2 changed files with 29 additions and 1 deletions
+15
View File
@@ -10,6 +10,7 @@ import { Readable } from 'node:stream';
import { createRouteTestHarness, type RouteTestHarness } from './_route-test-utils.js';
import { registerFileRoutes } from '../../src/web/routes/file-routes.js';
import { ApiErrorCode } from '../../src/types.js';
import { CASES_DIR } from '../../src/web/route-helpers.js';
// Mock fs/promises for file operations
vi.mock('node:fs/promises', () => ({
@@ -114,6 +115,20 @@ describe('file-routes', () => {
]);
});
it('defaults to the Codeman Cases root, not Home, when linking a case with no path chosen yet', async () => {
// The "Link Existing" case picker opens with an empty path and no
// sessionId. `Home` and `Codeman Cases` are unrelated bind mounts under
// Docker, so falling back to whichever root happened to be listed first
// could open the picker somewhere with no cases in it at all — and, worse,
// make a stale directory from a since-changed CODEMAN_CASES_PATH look like
// a normal thing to stumble across while browsing for one to link.
const res = await harness.app.inject({ method: 'GET', url: '/api/filesystem/browse' });
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
expect(body.data.path).toBe(CASES_DIR);
});
it('rejects paths outside the configured roots', async () => {
const res = await harness.app.inject({
method: 'GET',