feat(files): add "This computer" local file browser - #473
Merged
Conversation
roxi3906
added a commit
to roxi3906/open-science
that referenced
this pull request
Aug 3, 2026
…clid-35cb9b Resolves the conflicts blocking PR aipoch#473 against 103 new upstream commits. Conflicts and how they were resolved: - src/main/ipc.ts — upstream moved every handler registration behind declareElectronAdapter() and already had an 'uploads' adapter, so the duplicate bare registerUploadIpcHandlers() call was dropped and the onStandaloneUploadSaved broadcast folded into upstream's adapter. Same for session-persistence and project-files, whose adapters upstream already owns. The genuinely new local-fs registration is wrapped in its own adapter. - src/main/uploads/ipc.ts — kept the extracted runLocalStaging() helper and the stage-local-path handler that upstream had inlined/absent, and migrated all 11 registrations from ipcMain.handle to the new typed ipcMainHandle. - src/renderer/.../PreviewPanel.tsx — took upstream's PreviewPanelSurface extraction, then hand-ported the keep-tool-panels-mounted logic into the new component. Upstream's extraction rendered an empty <section />, which would have dropped the local browser's current directory on every tab switch. Also regenerated, not textually merged: - src/shared/web-api-map.generated.ts (path moved from src/renderer/web/) - Prisma client, for the new UnreadTaskSession model And registered the six new preload channels (localFs.* and uploads.stageLocalPath) in the public-surface inventory test upstream added. Verification: typecheck clean; lint 0 errors, 0 warnings on changed files; full suite 682/699 files pass. The two reds (notebook/kernel-executor.test.ts and skills/literature-review/kernel.test.ts) are byte-identical to upstream here and fail for environment reasons — the latter needs Python 3.10+ for `X | None`.
roxi3906
force-pushed
the
claude/beautiful-euclid-35cb9b
branch
2 times, most recently
from
August 3, 2026 05:53
4d7ea0b to
cb5ac34
Compare
Add a "This computer" mode to the Files panel so users can browse the local filesystem, preview files, and pull them into a project without leaving the app. - local-fs main service + IPC (getRoots, listDir, readPreview, openPath, reveal) with path validation shared through src/shared/local-fs.ts - LocalFileBrowser listing with breadcrumb navigation, plus LocalFileHeaderActions for "Save as artifact" - route the preview surface through a shared preview-file-item shape so managed files and local paths render with the same renderers - save-as-artifact reuses the composer upload pipeline: it publishes a ManagedFile with source='upload' so the file appears under "Your uploads", and threads the active projectId through so the project-files:changed event is not dropped Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The local-fs handlers were the only ones in the repo calling ipcMain.handle directly, so the registry never tracked them: adapter teardown saw zero added channels and left the handlers installed, and the Web RPC router rejected every call with "Unregistered Web RPC channel". Routing them through ipcMainHandle also makes them reachable over the Web seam, which they should not be for a paired remote browser. Reading and opening host paths is native-host authority, so the five local-fs channels join REMOTE_LOCAL_ONLY_RPC_CHANNELS alongside compute:reveal-in-folder, together with uploads:stage-local-path, whose sibling stage-local-file is already web-blocked.
The conflict resolution meant to preserve tool-panel state (the local file browser's current directory) across a switch to a file preview, but it returned a <section> wrapper for the inactive case and <PreviewToolPanel> for the active one. React reconciles by element type at a given position, so every activation change unmounted and re-created the subtree, discarding the state the wrapper existed to protect. Tool items now always render <PreviewToolPanel>, which toggles `hidden` itself, so the element type at that position never changes. Expansion is gated on the panel being active so a background tab cannot open a modal over another tab.
resolveManagedFilePath ended in a bare `return localFsService.resolveFilePath`, making arbitrary host-path resolution the default branch for anything that is not artifact/upload/notebook-input. Any source added to ManagedPreviewSource later would have inherited that path silently. The 'local' case is now named explicitly and the tail asserts `never`, so an unhandled source is a compile error and, if one reaches runtime anyway, a rejected promise instead of a host-path lookup.
stage-local-path checked only that sourcePath was a non-blank string, then passed it straight to stat(). It now runs the same validateLocalPath check the local-fs browser applies, so relative paths and control characters are rejected at the IPC boundary instead of surfacing as raw ENOENT from Node. Staging commits bytes into .pending/ and releases the writer lease before the separate SQLite publish, so a throw there left a file with no Version row and no sweep to reclaim it. A failed publish now discards the staged copy and rethrows.
roxi3906
force-pushed
the
claude/beautiful-euclid-35cb9b
branch
from
August 3, 2026 06:21
cb5ac34 to
6d302e4
Compare
roxi3906
marked this pull request as ready for review
August 3, 2026 06:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a local-filesystem file browser ("This computer") as a sibling to the existing remote SSH browser. Local files open as standard preview-workbench tabs and render through the shared preview pipeline. Entry point is a new LOCAL section in the Files-panel Artifacts dropdown.
What's included
src/shared/local-fs.ts+ tests): pure types,validateLocalPath,resolveLocalPath,sortLocalEntries,isSensitiveLocalPath, and the reservedLOCAL_BOOKMARKS_KEY.src/main/local-fs/):LocalFsService(list / preview / roots / reveal / openPath) backed bynode:fs, entry-capped and realpath-canonicalized. The same instance also feeds the managed-preview resolver, so local images/PDFs stream through the same validated path.window.api.localFs(5 methods);'local'added toPreviewFileSource/ManagedPreviewSource; regenerated web api map.LocalFileBrowser(back/up/refresh, editable address bar, Go-to with fixed Home + pin/unpin bookmarks, sensitive-file/dir confirm) andLocalFileHeaderActions(Reveal in Finder + Copy path / Open-with), replacing "Download" in the header and fallback surfaces for local files.Security model
Deliberately "Home start, full-disk navigable" — paths are not confined to a storage root; validation rejects only malformed input (non-absolute / control chars) and
realpathcanonicalizes symlinks/...The arbitrary-path read via
source: 'local'is reachable only by the trusted main renderer: theopen-science-preview://protocol resolves opaque, owner-scoped resource IDs (never renderer-supplied paths), the HTML preview sandbox runs underdefault-src 'none'; connect-src 'none'with no preload, and local Office files skip the OOPIF pipeline.acquire/readRange/releaseare isolated perownerId(webContents).Sensitive-path warning covers credential directories (
.ssh/.aws/.gnupg) on entry, dotenv files, and suffix-less secret files (SSH private keys, cloudcredentials,.pgpass,.p12/.pfx).Testing
tsc --noEmiton both node and web projects — clean.local-fs+ mainlocal-fs/servicesuites pass (20 tests, incl. new suffix-less-secret cases); previously verified managed-preview / office-preview suites unaffected.LocalFileBrowser,LocalFileHeaderActions) have no unit tests — verified via typecheck/lint only.Deferred / not included
docs/local-artifacts-mockup.html.🤖 Generated with Claude Code