Skip to content

feat: open single file from disk with linked autosave#4

Merged
ijbo merged 4 commits into
mainfrom
feat/open-file-from-disk
Jun 22, 2026
Merged

feat: open single file from disk with linked autosave#4
ijbo merged 4 commits into
mainfrom
feat/open-file-from-disk

Conversation

@ijbo

@ijbo ijbo commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

Adds an "Open File" button to the workspace sidebar that opens a single file from disk via showOpenFilePicker and keeps it linked — edits autosave straight back to that exact file on disk, independently of the existing folder-backed workspace mode.

Originally requested because clicking New Document → Open Folder only let you connect a whole folder; there was no way to open and edit one file from disk.

How it works

  • disk-workspace.js — new single-file handle API: openSingleFile, linkSingleFile, hasSingleFile, writeSingleFile, unlinkSingleFile, unlinkAllSingleFiles, restoreSingleFiles. Handles are persisted to IndexedDB (file:<id> keys) so links survive reloads.
  • workspace.jsM.wsOpenDiskFile() reads the picked file into a deduped, manually-named workspace entry and links its handle; delete/rename paths are guarded so single-linked files never trigger folder-mode I/O.
  • cloud-share.js — the real per-keystroke autosave now writes back to the linked file.
  • index.html — the ws-open-file button.

Bugs found via multi-agent review and fixed

A deep multi-agent review (4 dimensions × adversarial verification, 16 verified findings) caught that the first implementation looked done but didn't actually save to disk on the main path. All fixed:

Severity Bug Fix
🔴 critical Edits never reached disk — keystroke autosave (saveToLocalStorage) only had a folder-mode branch Single-file write-back branch + pagehide/beforeunload flush
🟠 major Picked handle was read-only Request readwrite permission in the click gesture on open
🟠 major No write serialization → out-of-order corruption Per-id write queue
🟠 major Delete/rename could destroy a same-named file in a connected folder hasSingleFile guards skip folder-mode removeEntry/renameFileInPath
🟠 major Deleting the last file truncated the linked disk file Unlink before clearing
🟠 major Folder connect/reconnect orphaned single-file handles unlinkAllSingleFiles() on rebuild
🟡 minor Redundant write on open, orphan-handle leak, silent persist failure, .md forced onto .txt, unwanted cloud copy Each addressed

Testing

  • Verified live in the browser preview: keystroke autosave writes to disk; serialization preserves order under slow I/O; zero redundant writes on open; permission requested on open; delete/rename guards behave.
  • disk-workspace.spec.js: 30 passing, no regressions (the one pre-existing modal-click flake fails identically on main).
  • ESLint: no new errors/warnings on changed files.
  • Security check (pre-commit): 0 critical.

Note: Chromium-only (File System Access API), same as the existing "Open Folder". The button auto-hides where unsupported.

🤖 Generated with Claude Code

ijbo and others added 4 commits June 22, 2026 17:02
Add an "Open File" button to the workspace sidebar that opens one file via
showOpenFilePicker and keeps it linked, so edits autosave back to that exact
file on disk independently of folder-workspace mode.

New single-file handle API in disk-workspace.js (openSingleFile, linkSingleFile,
writeSingleFile, unlinkSingleFile, unlinkAllSingleFiles, restoreSingleFiles) with
IndexedDB-persisted handles that survive reloads, plus M.wsOpenDiskFile() in
workspace.js.

Fixes found via multi-agent review:
- critical: edits never reached disk — per-keystroke autosave (cloud-share.js
  saveToLocalStorage) only wrote in folder mode; added single-file write-back
  branch + pagehide/beforeunload flush
- major: request readwrite permission in-gesture on open; per-id write
  serialization queue; guard delete/rename so single-linked files never trigger
  folder-mode removeEntry/renameFileInPath; don't truncate the last file; unlink
  single-file handles on folder connect/reconnect instead of orphaning them
- minor: no redundant write on open, orphan-handle pruning, persistence-failure
  warning, preserve .txt/.log extension on rename, no auto cloud copy for local files

Verified live + 30 passing disk-workspace.spec.js tests, no regressions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The .claude/ directory holds machine-specific Claude Code config, a
scheduled-task lock, launch.json, and session worktrees — none of which
belong in the repo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…branch}})

docker/metadata-action used type=sha,prefix={{branch}}- but {{branch}} is
empty on pull_request events, producing an invalid tag :-<sha>. Use a static
sha- prefix; branch/PR identity is still captured by the ref-based tag rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ijbo ijbo merged commit 48a1010 into main Jun 22, 2026
4 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.

1 participant