mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 10:59:32 +01:00
fix(tabs): a Claude worktree session gets its case's default group too
Merge-time fix for #676 (review finding 1 and nit 7). The Git worktrees modal launches Claude through POST /api/sessions with workingDir <case>/.claude/worktrees/<name>, which inferLocalCaseName did not recognise, so the session landed in Ungrouped while the same gesture for any other CLI (quick-start with the case name) landed in the group. The inference now strips a trailing .claude/worktrees/<name> lexically before its two checks, reusing CLAUDE_WORKTREE_PATH (hoisted to module scope). It also runs only for a named workingDir, never on the server's own cwd, as the hook and skill injection above already do. Route tests for both, failing without the fix; api-reference and architecture-invariants say so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
74c980413a
commit
5a677bf03c
4 files changed
+49
-10
No files matched your search
@@ -207,6 +207,9 @@ const CODEMAN_CONFIG_DIR = getDataDir();
|
||||
|
||||
const SAFE_CASE_NAME = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
/** `<repo>/.claude/worktrees/<name>`: the layout Claude Code's own worktree feature creates. */
|
||||
const CLAUDE_WORKTREE_PATH = /^(.*)\/\.claude\/worktrees\/([^/]+)\/?$/;
|
||||
|
||||
/** Did the committed layout put this session in a named group (not Ungrouped)? */
|
||||
function landedInGroup(layout: TabLayout | undefined, sessionId: string): boolean {
|
||||
return !!layout?.groups.some((group) => group.refs.some((ref) => ref.kind === 'session' && ref.id === sessionId));
|
||||
@@ -215,12 +218,16 @@ function landedInGroup(layout: TabLayout | undefined, sessionId: string): boolea
|
||||
/**
|
||||
* The case a POST /api/sessions `workingDir` belongs to, for its default session
|
||||
* group: a direct child of the caller's case space, or (admin / single-user, as
|
||||
* GET /api/cases lists them) a linked case's exact path. Lexical only: the
|
||||
* browser sends the path the case list gave it, and this must never touch a
|
||||
* possibly-dead mount. Anything else is no case, which keeps today's placement.
|
||||
* GET /api/cases lists them) a linked case's exact path, or a Claude worktree
|
||||
* (`<case>/.claude/worktrees/<name>`) of either. Lexical only: the browser sends
|
||||
* the path the case list gave it, and this must never touch a possibly-dead
|
||||
* mount. Anything else is no case, which keeps today's placement.
|
||||
*/
|
||||
async function inferLocalCaseName(req: FastifyRequest, workingDir: string): Promise<string | undefined> {
|
||||
const target = resolvePath(workingDir);
|
||||
// The Git worktrees modal launches Claude through this route in the worktree, and every other CLI
|
||||
// through quick-start with the case name: both are sessions of that case.
|
||||
const resolved = resolvePath(workingDir);
|
||||
const target = CLAUDE_WORKTREE_PATH.exec(resolved)?.[1] || resolved;
|
||||
const user = getAuthUser(req);
|
||||
if (dirname(target) === resolvePath(resolveCasesDir(user))) {
|
||||
const name = basename(target);
|
||||
@@ -1442,7 +1449,8 @@ export function registerSessionRoutes(
|
||||
parentSessionId: resolveParentSessionId(ctx, req, body.parentSessionId, owner),
|
||||
});
|
||||
|
||||
const placementCase = remote ? undefined : await inferLocalCaseName(req, workingDir);
|
||||
// Only a named workingDir: without one the session starts in the server's own cwd, which is no case.
|
||||
const placementCase = remote || !body.workingDir ? undefined : await inferLocalCaseName(req, workingDir);
|
||||
const placement = {
|
||||
...(body.tabGroupId ? { tabGroupId: body.tabGroupId } : {}),
|
||||
...(placementCase ? { caseName: placementCase } : {}),
|
||||
@@ -4722,9 +4730,6 @@ export function registerSessionRoutes(
|
||||
worktreeRepo?: string;
|
||||
};
|
||||
|
||||
/** `<repo>/.claude/worktrees/<name>` — the layout Claude Code's own worktree feature creates. */
|
||||
const CLAUDE_WORKTREE_PATH = /^(.*)\/\.claude\/worktrees\/([^/]+)\/?$/;
|
||||
|
||||
/**
|
||||
* Recover cwd / branch / worktree from a transcript chunk.
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user