Skip to content

Fix Claude Code project names collapsing to a parent folder#540

Merged
iamtoruk merged 1 commit into
getagentseal:mainfrom
ozymandiashh:fix/493-claude-project-name
Jun 21, 2026
Merged

Fix Claude Code project names collapsing to a parent folder#540
iamtoruk merged 1 commit into
getagentseal:mainfrom
ozymandiashh:fix/493-claude-project-name

Conversation

@ozymandiashh

Copy link
Copy Markdown
Contributor

Summary

Closes #493 by showing the real Claude Code project leaf in the "By Project" panel (TUI + menubar dropdown) and stopping sibling projects from collapsing under a parent folder.

Root cause

Two independent paths produced a parent folder or a wrong fragment instead of the project leaf:

  1. Stray ancestor .git over-grouping. resolveCanonicalProjectPath (src/parser.ts) walked up to the nearest .git and used it as the canonical project path. That is correct for a real linked worktree, but if a parent directory of several projects happens to contain a .git (a dotfiles bare repo, an accidental git init in ~/Projects/), every sibling resolved to that parent — so the panel rendered Projects (or home) for all of them.
  2. Hyphenated names destroyed in the no-cwd fallback. When a Claude session has no cwd metadata, projectPath fell back to unsanitizePath(dirName), which blindly replaces every - with /. A slug like Projects-Content-OS became projects/content/os, and projectName() then pop()-ed it to os.

What changed

  • resolveCanonicalProjectPath now canonicalizes to the main repo only for a real linked git worktree (.git is a file whose gitdir: points at <main>/.git/worktrees/<name>). For an ordinary repo, or when a .git is found only at an ancestor, it keeps the session's own cwd instead of absorbing it into the parent.
  • The Claude no-cwd fallback keeps the lossy directory slug intact (claudeSlugFallbackPath) instead of inventing path segments.
  • projectName() (src/overview.ts) only basenames absolute paths; a relative slug-shaped name is shown as-is rather than split on invented separators.
  • Regression tests in tests/parser-claude-cwd.test.ts and tests/overview.test.ts for: sibling projects under a shared parent .git, hyphenated slug with absent cwd, and the no-cwd fallback. One existing test that asserted the old fallback-slug -> fallback/slug behavior was updated to expect the slug kept intact.

Behavior change worth flagging (re: #375)

PR #375 ("Group git worktrees under main project") also caused sessions launched from a subdirectory of an ordinary repo to group up to the repo root. With this change, a non-worktree subdirectory session keeps its own cwd (it appears under its own directory rather than the repo root). Real git-worktree grouping is unchanged. I went with the worktree-only rule because there is no unambiguous signal to tell a project's own repo from an accidental ancestor .git. If you'd prefer to preserve subdirectory-to-repo-root grouping for ordinary repos, I'm happy to take a more surgical approach — just let me know.

Validation

Checks run (en_US locale):

npm test -- --run tests/parser-claude-cwd.test.ts tests/overview.test.ts tests/providers/claude.test.ts  - 20 tests passed
npm test -- --run                                                                                         - 1275 tests passed
npx semgrep --config .semgrep/rules/no-bracket-assign-hot-paths.yml src/                                  - 0 findings
npm run build (bundle-litellm + tsup)                                                                     - build success
npx tsc --noEmit                                                                                          - clean

The new tests fail on origin/main (verified by reverting only the source change) and pass with the fix, so the fix is causally required. Worktree-grouping and separate-git-dir tests remain green.

Notes

  • npm run build regenerated src/data/litellm-snapshot.json / pricing-fallback.json; both were restored — unrelated to this fix.

The 'By Project' panel collapsed sibling Claude Code projects to a parent
folder in two cases:

1) resolveCanonicalProjectPath walked up to ANY ancestor .git and used it as
   the canonical project. A stray .git in a parent of several projects (a
   dotfiles bare repo, an accidental git init) made every sibling resolve to
   that parent ('Projects'/'home'). Now only a real linked worktree (.git is a
   FILE pointing at <main>/.git/worktrees/<name>) canonicalizes to its main
   repo; an ordinary repo or a stray ancestor .git keeps the session's own cwd
   as the project. Genuine worktree grouping is preserved.

2) When a Claude session has no cwd metadata, the dir slug was unsanitized by
   replacing every '-' with '/', inventing path segments that overview then
   split on, so 'Projects-Content-OS' rendered as 'os'. The lossy slug is now
   kept intact, and overview only basenames ABSOLUTE paths.

Fixes getagentseal#493
@iamtoruk iamtoruk merged commit a12db6e into getagentseal:main Jun 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

By Project dashboard shows parent folder name instead of actual project name for Claude Code projects

2 participants