From 8305c96e20f3d6d05146b401c0410cb839c2b16e Mon Sep 17 00:00:00 2001 From: jknapp <1+jknapp@josh@dao-mail.com> Date: Wed, 23 Sep 2026 17:05:50 +0000 Subject: [PATCH] Terminal file viewer/editor + per-window app-command lockdown (#60) Clicking a file path in Claude's terminal output now opens the file in its own window with a CodeMirror 6 editor. The editor highlights the target line, live-reloads while the file changes, and saves explicitly with hash-based conflict detection. The viewer commands are gated by window label. Every app command is now ACL-gated per window through a Tauri AppManifest. build.rs checks the handler list against the capability files and fails the build on any mismatch. Co-Authored-By: Claude Opus 5.5 (1M context) --- .gitignore | 3 + CLAUDE.md | 50 +- app/package-lock.json | 348 ++ app/package.json | 15 + app/src-tauri/Cargo.toml | 2 + app/src-tauri/build.rs | 209 +- app/src-tauri/capabilities/default.json | 114 +- app/src-tauri/capabilities/file-viewer.json | 16 + app/src-tauri/gen/schemas/acl-manifests.json | 2 +- app/src-tauri/gen/schemas/capabilities.json | 2 +- app/src-tauri/gen/schemas/desktop-schema.json | 1380 +++++++ app/src-tauri/gen/schemas/linux-schema.json | 1380 +++++++ app/src-tauri/src/command_census.rs | 581 +++ app/src-tauri/src/commands/file_commands.rs | 33 +- .../src/commands/file_viewer_commands.rs | 365 ++ app/src-tauri/src/commands/mod.rs | 1 + app/src-tauri/src/file_viewer/mod.rs | 109 + app/src-tauri/src/file_viewer/poll.rs | 194 + app/src-tauri/src/file_viewer/registry.rs | 379 ++ app/src-tauri/src/file_viewer/resolve.rs | 166 + app/src-tauri/src/file_viewer/window.rs | 27 + app/src-tauri/src/file_viewer/write.rs | 604 +++ app/src-tauri/src/lib.rs | 181 +- .../projects/home/filePreview.test.ts | 20 + .../components/projects/home/filePreview.ts | 13 + .../components/terminal/TerminalView.test.tsx | 200 +- app/src/components/terminal/TerminalView.tsx | 253 +- .../terminal/filePathLinkProvider.test.ts | 70 + .../terminal/filePathLinkProvider.ts | 52 + app/src/index.css | 9 + app/src/lib/filePathLinks.test.ts | 104 + app/src/lib/filePathLinks.ts | 124 + app/src/lib/tauri-commands.ts | 21 +- app/src/lib/types.ts | 46 + app/src/lib/xtermLineJoin.test.ts | 49 + app/src/lib/xtermLineJoin.ts | 65 + app/src/test/capabilities.test.ts | 472 +++ app/src/viewer/CodeEditor.test.tsx | 61 + app/src/viewer/CodeEditor.tsx | 125 + app/src/viewer/EditorPane.test.tsx | 408 +++ app/src/viewer/EditorPane.tsx | 343 ++ app/src/viewer/ViewerApp.test.tsx | 65 + app/src/viewer/ViewerApp.tsx | 54 + app/src/viewer/editability.test.ts | 27 + app/src/viewer/editability.ts | 15 + app/src/viewer/highlightLine.test.ts | 31 + app/src/viewer/highlightLine.ts | 40 + app/src/viewer/ipcMessages.ts | 21 + app/src/viewer/languages.test.ts | 28 + app/src/viewer/languages.ts | 59 + app/src/viewer/main.tsx | 10 + app/src/viewer/textFormat.test.ts | 43 + app/src/viewer/textFormat.ts | 58 + app/src/viewer/useViewerPolling.test.ts | 43 + app/src/viewer/useViewerPolling.ts | 33 + app/src/viewer/viewerState.test.ts | 122 + app/src/viewer/viewerState.ts | 129 + app/src/viewer/viewerTheme.ts | 42 + app/src/vite-env.d.ts | 1 + app/viewer.html | 13 + app/vite.config.ts | 9 + .../plans/2026-09-22-app-manifest-lockdown.md | 1534 ++++++++ .../plans/2026-09-22-terminal-file-viewer.md | 3238 +++++++++++++++++ ...2026-09-22-app-manifest-lockdown-design.md | 536 +++ .../2026-09-22-terminal-file-viewer-design.md | 404 ++ 65 files changed, 15043 insertions(+), 108 deletions(-) create mode 100644 app/src-tauri/capabilities/file-viewer.json create mode 100644 app/src-tauri/src/command_census.rs create mode 100644 app/src-tauri/src/commands/file_viewer_commands.rs create mode 100644 app/src-tauri/src/file_viewer/mod.rs create mode 100644 app/src-tauri/src/file_viewer/poll.rs create mode 100644 app/src-tauri/src/file_viewer/registry.rs create mode 100644 app/src-tauri/src/file_viewer/resolve.rs create mode 100644 app/src-tauri/src/file_viewer/window.rs create mode 100644 app/src-tauri/src/file_viewer/write.rs create mode 100644 app/src/components/terminal/filePathLinkProvider.test.ts create mode 100644 app/src/components/terminal/filePathLinkProvider.ts create mode 100644 app/src/lib/filePathLinks.test.ts create mode 100644 app/src/lib/filePathLinks.ts create mode 100644 app/src/lib/xtermLineJoin.test.ts create mode 100644 app/src/lib/xtermLineJoin.ts create mode 100644 app/src/test/capabilities.test.ts create mode 100644 app/src/viewer/CodeEditor.test.tsx create mode 100644 app/src/viewer/CodeEditor.tsx create mode 100644 app/src/viewer/EditorPane.test.tsx create mode 100644 app/src/viewer/EditorPane.tsx create mode 100644 app/src/viewer/ViewerApp.test.tsx create mode 100644 app/src/viewer/ViewerApp.tsx create mode 100644 app/src/viewer/editability.test.ts create mode 100644 app/src/viewer/editability.ts create mode 100644 app/src/viewer/highlightLine.test.ts create mode 100644 app/src/viewer/highlightLine.ts create mode 100644 app/src/viewer/ipcMessages.ts create mode 100644 app/src/viewer/languages.test.ts create mode 100644 app/src/viewer/languages.ts create mode 100644 app/src/viewer/main.tsx create mode 100644 app/src/viewer/textFormat.test.ts create mode 100644 app/src/viewer/textFormat.ts create mode 100644 app/src/viewer/useViewerPolling.test.ts create mode 100644 app/src/viewer/useViewerPolling.ts create mode 100644 app/src/viewer/viewerState.test.ts create mode 100644 app/src/viewer/viewerState.ts create mode 100644 app/src/viewer/viewerTheme.ts create mode 100644 app/src/vite-env.d.ts create mode 100644 app/viewer.html create mode 100644 docs/superpowers/plans/2026-09-22-app-manifest-lockdown.md create mode 100644 docs/superpowers/plans/2026-09-22-terminal-file-viewer.md create mode 100644 docs/superpowers/specs/2026-09-22-app-manifest-lockdown-design.md create mode 100644 docs/superpowers/specs/2026-09-22-terminal-file-viewer-design.md diff --git a/.gitignore b/.gitignore index 3494414..733330e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ node_modules/ app/dist/ app/src-tauri/target/ +# Written by build.rs (tauri-build AppManifest); gen/schemas/acl-manifests.json is the +# tracked, reviewable form of the same information. +app/src-tauri/permissions/autogenerated/ Screenshot*.png code-review.md diff --git a/CLAUDE.md b/CLAUDE.md index 256ba7f..19db544 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -73,6 +73,16 @@ docker exec stdout → tokio task → emit("terminal-output-{sessionId}") → li - **`hooks/`** — All Tauri IPC calls are encapsulated in hooks (`useTerminal`, `useProjects`, `useDocker`, `useSettings`) - **`lib/tauri-commands.ts`** — Typed `invoke()` wrappers; TypeScript types in `lib/types.ts` must match Rust models - **`components/terminal/TerminalView.tsx`** — xterm.js integration with WebGL rendering, URL detection for OAuth flow +- **`viewer/`** — the terminal file viewer's window (second Vite entry `viewer.html` → + `src/viewer/main.tsx`; CodeMirror 6). `lib/filePathLinks.ts` decides what a path is; + `components/terminal/filePathLinkProvider.ts` registers it with xterm. The OSC 8 handler now + runs with `allowNonHttpProtocols` on and dispatches `file:` to the viewer, so every other scheme + must be refused *there*. `viewer.html` must never carry an inline `