From 659fc0648639d526128514802680f94e9bc17ba2 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Fri, 20 Mar 2026 15:56:38 +1100 Subject: [PATCH 1/2] fix(ui): derive repo root for tool call path shortening when not explicitly provided SessionModal now falls back to session.workingDir when the repoDir prop isn't passed (e.g. when opened from ProjectSection or NoteModal). makePathsRelative also tries ancestor directories of the given base path, so repos with a subpath (worktree_root/apps/staged) correctly shorten file paths that reference the worktree root. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../lib/features/sessions/SessionModal.svelte | 6 +++++- .../features/sessions/sessionModalHelpers.ts | 20 +++++++++++++++++-- apps/staged/src/lib/types.ts | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/staged/src/lib/features/sessions/SessionModal.svelte b/apps/staged/src/lib/features/sessions/SessionModal.svelte index 8c2750a1..ad29fb53 100644 --- a/apps/staged/src/lib/features/sessions/SessionModal.svelte +++ b/apps/staged/src/lib/features/sessions/SessionModal.svelte @@ -90,6 +90,10 @@ let { sessionId, onClose, repoDir, branchId, projectId, noteInfo, onOpenNote }: Props = $props(); + /** Effective repo directory for path shortening — prefers the explicit prop, + * falls back to the session's working directory. */ + let effectiveRepoDir = $derived(repoDir ?? session?.workingDir ?? null); + // ========================================================================= // State // ========================================================================= @@ -967,7 +971,7 @@ {:else}
- {#each groupByVerb(group.pairs, repoDir, !isLive || sending || grouped.findIndex((g, i) => i > groupIdx && g.type === 'user') !== -1) as vg, vgIdx} + {#each groupByVerb(group.pairs, effectiveRepoDir, !isLive || sending || grouped.findIndex((g, i) => i > groupIdx && g.type === 'user') !== -1) as vg, vgIdx} {#if vg.items.length === 1} {@const item = vg.items[0]} {@const isExpanded = expandedTools.has(item.pair.call.id)} diff --git a/apps/staged/src/lib/features/sessions/sessionModalHelpers.ts b/apps/staged/src/lib/features/sessions/sessionModalHelpers.ts index 6503274e..86c58336 100644 --- a/apps/staged/src/lib/features/sessions/sessionModalHelpers.ts +++ b/apps/staged/src/lib/features/sessions/sessionModalHelpers.ts @@ -30,11 +30,27 @@ export function parseToolCall(content: string): ParsedToolCall | null { /** * Replace absolute paths that fall within `repoDir` with relative paths. * If repoDir is empty/null, returns the text unchanged. + * + * When the exact `repoDir` prefix isn't found in the text, ancestor directories + * are tried (up to 3 levels). This handles the common case where the session's + * working directory includes a repo subpath (e.g. `worktree_root/apps/staged`) + * but tool call paths reference the worktree root directly. */ export function makePathsRelative(text: string, repoDir: string | null | undefined): string { if (!repoDir) return text; - const prefix = repoDir.endsWith('/') ? repoDir : repoDir + '/'; - return text.replaceAll(prefix, ''); + + let dir = repoDir; + for (let i = 0; i < 4; i++) { + const prefix = dir.endsWith('/') ? dir : dir + '/'; + if (text.includes(prefix)) { + return text.replaceAll(prefix, ''); + } + const parentEnd = dir.lastIndexOf('/'); + if (parentEnd <= 0) break; + dir = dir.slice(0, parentEnd); + } + + return text; } const TOOL_VERBS: Record = { diff --git a/apps/staged/src/lib/types.ts b/apps/staged/src/lib/types.ts index ee1ab389..f9a6011f 100644 --- a/apps/staged/src/lib/types.ts +++ b/apps/staged/src/lib/types.ts @@ -208,6 +208,7 @@ export interface Session { id: string; prompt: string; status: SessionStatus; + workingDir: string; agentId: string | null; errorMessage: string | null; createdAt: number; From 8cbebae776a6259ccd323b83b941fec91ba057cd Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Fri, 20 Mar 2026 16:05:50 +1100 Subject: [PATCH 2/2] fix(ui): explicitly pass repoDir to SessionModal from all call sites ProjectSection now derives repoDir from the first branch with a worktree path. SessionLauncher explicitly passes null (standalone sessions have no repo). Removes the implicit session.workingDir fallback in SessionModal so the prop is always provided by the caller. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/staged/src/lib/features/projects/ProjectSection.svelte | 1 + .../staged/src/lib/features/sessions/SessionLauncher.svelte | 6 +++++- apps/staged/src/lib/features/sessions/SessionModal.svelte | 6 +----- apps/staged/src/lib/types.ts | 1 - 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/staged/src/lib/features/projects/ProjectSection.svelte b/apps/staged/src/lib/features/projects/ProjectSection.svelte index 48727c9e..fcea01cd 100644 --- a/apps/staged/src/lib/features/projects/ProjectSection.svelte +++ b/apps/staged/src/lib/features/projects/ProjectSection.svelte @@ -663,6 +663,7 @@ )} b.worktreePath)?.worktreePath ?? null} projectId={project.id} noteInfo={noteForSession ? { id: noteForSession.id, title: noteForSession.title, content: noteForSession.content } diff --git a/apps/staged/src/lib/features/sessions/SessionLauncher.svelte b/apps/staged/src/lib/features/sessions/SessionLauncher.svelte index bc0466c3..af7928b1 100644 --- a/apps/staged/src/lib/features/sessions/SessionLauncher.svelte +++ b/apps/staged/src/lib/features/sessions/SessionLauncher.svelte @@ -238,7 +238,11 @@ {#each [...openModals] as modalSessionId (modalSessionId)} - closeModal(modalSessionId)} /> + closeModal(modalSessionId)} + /> {/each}