Skip to content

fix: file-link and session-sidebar review follow-ups from 1.19.0 - #310

Merged
Ark0N merged 1 commit into
masterfrom
fix/files-sidebar-followups
Aug 16, 2026
Merged

fix: file-link and session-sidebar review follow-ups from 1.19.0#310
Ark0N merged 1 commit into
masterfrom
fix/files-sidebar-followups

Conversation

@Ark0N

Copy link
Copy Markdown
Owner

Five follow-ups left by the post-merge reviews of PR #306 (clickable file paths) and PR #307 (session sidebar), all shipped in 1.19.0.

1. Media extension lists had a third, diverging copy

VIDEO_ATTACHMENT_EXTENSIONS / AUDIO_ATTACHMENT_EXTENSIONS in src/attachment-registry.ts are the single source for what plays in the preview overlay, and panels-ui.js mirrors them for the <video>/<audio> markup. The third copy, FILE_PREVIEW_EXTENSIONS in constants.js (which decides whether a clicked terminal/chat path opens the preview overlay or the tail/log viewer), was missing m4v ogv ogg oga m4a aac flac opus. Result: clicking an in-workspace .m4a an agent had just produced opened the log viewer and rendered binary noise, while the same file in /tmp played fine through the attachment path.

Fix: the missing extensions are added, and a new static guard, test/media-extension-parity.test.ts (same technique as test/sse-registry-parity.test.ts), pins all three copies: every registry media extension must appear in FILE_PREVIEW_EXTENSIONS, and the panels-ui.jsVIDEO_EXTS/AUDIO_EXTS sets must exactly equal the registry sets.

2. /etc links were guaranteed dead

FILE_PATH_LINK_PATTERN (the ONE pattern feeding both the xterm link provider and the response viewer's linkifier) listed etc in its root alternation, but /etc is unconditionally in DEFAULT_BLOCKED_TREES server-side, so every /etc/... link rendered clickable and then 403'd on click. etc is removed from the alternation, in its single source only; both consumers inherit the change. test/link-provider-regex.test.ts and test/response-viewer-file-links.test.ts gain negative cases (/etc/hosts, plus the extension-bearing /etc/app/config.json that only the root removal keeps out).

3. Sidebar count disagreed with the list under it

updateSidebarCount() rendered this.sessions.size, but the sidebar list also shows web-tab rows and is filterable: 3 sessions + 2 dashboards read "3" above 5 rows, and a filter matching one row still read "3". It now counts the rows actually on the list (.session-tab rows, web tabs included, minus .tab-filtered-out), falling back to the session map before the first render. applySidebarFilter() refreshes the count at its tail, so it also follows the filter box per keystroke (the box calls applySidebarFilter directly via oninput, with no render in between); the previously separate updateSidebarCount() calls after each applySidebarFilter site are folded in. test/session-list-layout.test.ts pins the new behavior.

4. Stale connectors on incremental renders in sidebar layout

In _renderSessionTabsImmediate() the connection-line redraw was gated on this._lineageEdgeCount > 0. That count is permanently 0 in sidebar layout (lineage arcs are skipped there), yet subagent/ultracode connectors still anchor to tab rects, and a badge appearing changes ROW HEIGHTS in the vertical list, sliding every connector below it off its anchor. PR #307 already widened the strip-scroll listener's gate to this._lineageEdgeCount > 0 || this.isSessionSidebarActive?.() for exactly this reason; the incremental-render gate now gets the same widening.

5. ~/.claude.json and ~/.claude/settings.json were servable but credential-bearing

isSensitivePath() names secret members individually so the surrounding trees stay attachable, but these two escaped: ~/.claude/settings.json can hold env: {ANTHROPIC_API_KEY: ...} and apiKeyHelper by schema (settings.local.json shares that schema), and ~/.claude.json holds account/OAuth-adjacent state. A blanket /\.claude\/settings\.json$/ would wrongly block the CASE-level .claude/settings.json files users legitimately view and edit in the File Viewer (model override, hooks), so the new entries are HOME-anchored: homedir() is read INSIDE isSensitivePath at check time, per the file's own rule about module-load captures being wrong when HOME changes later (per-file test fixtures). Blocked exactly: <home>/.claude.json, <home>/.claude/settings.json, <home>/.claude/settings.local.json. Case-level copies, transcripts and team state stay attachable; test/sensitive-path.test.ts covers both directions, including a .claude/settings.json under a different home.

Verification

  • npm run test:ci: 261 files passed, 5202 tests passed (12 skipped, pre-existing)
  • Targeted suites: media-extension-parity, link-provider-regex, response-viewer-file-links, session-list-layout, sensitive-path, routes/file-routes-attachment-path-guard, routes/file-routes, attachment-magic, file-browser-hidden, file-preview-media: all green
  • tsc --noEmit, npm run lint, npm run format:check, npm run check:frontend-syntax, npm run check:public-assets: all clean

Five post-merge review items from PRs #306 (clickable file paths) and
#307 (session sidebar):
- constants.js FILE_PREVIEW_EXTENSIONS gains the media extensions it was
missing vs the single-source sets in attachment-registry.ts (m4v ogv
ogg oga m4a aac flac opus), so an in-workspace .m4a opens the preview
player instead of the log viewer; new test/media-extension-parity.test.ts
pins all three copies (constants.js, panels-ui.js, attachment-registry.ts)
against each other.
- FILE_PATH_LINK_PATTERN drops `etc` from its root alternation: /etc is
unconditionally in DEFAULT_BLOCKED_TREES, so every /etc link 403'd.
Negative cases added to the link-provider and response-viewer tests.
- updateSidebarCount() counts the rows actually on the sidebar list
(session rows + web-tab rows, minus filtered-out ones) instead of
this.sessions.size, and applySidebarFilter() refreshes it so the count
follows the filter box per keystroke.
- The incremental-render connection-line gate now also fires in sidebar
layout (this._lineageEdgeCount is permanently 0 there), matching the
strip-scroll listener widened in #307, so a badge changing row heights
redraws subagent/ultracode connectors.
- isSensitivePath() blocks ~/.claude.json, ~/.claude/settings.json and
~/.claude/settings.local.json (credential-bearing by schema), anchored
to homedir() read at check time so case-level .claude/settings*.json
files stay servable in the File Viewer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ark0N
Ark0N merged commit 631913f into masterAug 16, 2026
2 checks passed
Sign up for freeto 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.

2 participants

@Ark0N@claude