Commit Graph

464 Commits

Author SHA1 Message Date
aaddrick
d499d8dc02 fix: address code review findings for --doctor backend display
- Gate /dev/kvm fix hints behind _kvm_active check (was leaking
  unconditionally)
- Check COWORK_VM_BACKEND override in --doctor backend summary
  to match daemon's detectBackend() behavior
- Log hint when KVM deps are present but bwrap wins auto-detect,
  so upgrading users know about COWORK_VM_BACKEND=kvm

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-21 18:39:13 -04:00
aaddrick
39c9fea68c style: simplify KVM active check in --doctor cowork section
Replace repeated ${_kvm_flag,,} == kvm tests with a single
_kvm_active boolean. Use glob pattern [Kk][Vv][Mm] for
case-insensitive matching.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-21 18:34:51 -04:00
aaddrick
3ada749410 feat: make bubblewrap the default cowork isolation backend
Swap auto-detection order from KVM → bwrap → host to
bwrap → KVM → host. KVM remains available via
COWORK_VM_BACKEND=kvm.

- detectBackend(): check bwrap before KVM
- --doctor: bwrap checked first; KVM deps shown as info
  (not warnings) unless COWORK_VM_BACKEND=kvm is set
- Fix header comment inaccuracy about rootfs.qcow2 check
- Update README and handover docs to reflect new default

Fixes #326

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-21 18:33:00 -04:00
aaddrick
dee729b873 docs: update contributor credits for cbonnissent and arauhala
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 11:51:16 -04:00
aaddrick
cb770de3df docs: add ecrevisseMiroir to contributors for bwrap sandbox isolation
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 11:45:23 -04:00
Aaddrick
b83c7ab881 Merge pull request #309 from ecrevisseMiroir/fix/bwrap-session-paths-security
fix: bwrap backend mounts at guest paths and uses minimal sandbox root
2026-03-20 11:42:58 -04:00
Aaddrick
3be28525fe Merge pull request #318 from aaddrick/fix/315-windows-vm-configure
fix: don't trigger Windows VM configure on Linux
v1.3.19+claude1.1.7714
2026-03-20 11:21:52 -04:00
aaddrick
62e7dfcdd5 style: simplify Patch 9 comments and inline variable
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 11:17:51 -04:00
aaddrick
4711b2485e fix: don't trigger Windows VM configure on Linux (#315)
Patch 9 previously widened the win32 platform gate to include Linux,
which also activated the _.configure() call meant for Windows HCS
setup. This caused "Request timed out: configure" on Linux because
the RPC client expected an id-echoing response that the daemon didn't
provide (fixed separately in #313, but the call is unnecessary either
way).

Replace the widened gate with a separate Linux-only block injected
after the win32 block. This copies smol-bin VHDX to the bundle dir
(needed for KVM guest SDK access) without calling _.configure().

Fixes #315

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 11:13:46 -04:00
Aaddrick
803d165814 Merge pull request #314 from aaddrick/fix/311-nix-ispackaged-regression
fix: skip ELECTRON_FORCE_IS_PACKAGED for NixOS builds
2026-03-20 10:56:14 -04:00
aaddrick
c3cc5a6b16 fix: skip ELECTRON_FORCE_IS_PACKAGED for NixOS builds
On NixOS, Electron is a separate Nix store path from the app, so
process.resourcesPath points to Electron's resources dir rather than
the app's. Claude's app code uses app.isPackaged to choose between
resourcesPath-based and development-style fallback paths. Setting
ELECTRON_FORCE_IS_PACKAGED=true (introduced by PR #305) forces the
resourcesPath code paths, which resolve to the wrong location on
NixOS, causing a silent startup hang.

Skip the env var for 'nix' package type so isPackaged remains false,
restoring the working behavior from before PR #305.

Fixes #311

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 09:46:57 -04:00
Aaddrick
a61b384637 Merge pull request #313 from cbonnissent/fix/312-rpc-response-id
fix: echo request id in RPC responses for persistent connections
2026-03-20 09:07:52 -04:00
aaddrick
1e2db5c0fe docs: update sabiut contributor credit for checksum validation
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 08:47:33 -04:00
aaddrick
b6f9f86418 Merge origin/main into feature/checksum-validation
Resolve conflict: take main's updated URLs (v1.1.7714) while
keeping the new claude_exe_sha256 variable from this branch.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 08:46:45 -04:00
Charles Bonnissent
b9c35734f6 fix: echo request id in RPC responses for persistent connections (#312)
The socket server did not echo back the `id` field from client
requests. The Claude Desktop client has two RPC modes: one-shot
connections (no id needed) and persistent multiplexed connections
(responses matched by id). When the persistent mode is active,
responses without an id are silently dropped as "orphaned", causing
all RPC calls (configure, startVM, isGuestConnected, etc.) to
timeout after 30 seconds.

Fixes #312

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-20 11:57:24 +01:00
github-actions[bot]
5f5e1b56b3 Update Claude Desktop download URLs to version 1.1.7714
Updated download URLs resolved from official redirect endpoints.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
v1.3.18+claude1.1.7714
2026-03-20 01:37:50 +00:00
Mouad
219ddbe1ea fix: bwrap backend mounts at guest paths and uses minimal sandbox root
The BwrapBackend had two issues with its sandbox setup:

1. **Security: workDir fell back to $HOME making entire home writable.**
   The spawn `cwd` arrives as `/sessions/<name>` (a session root without
   the `/mnt/<mount>` suffix). `resolveWorkDir` could not translate this
   pattern via `translateGuestPath` and fell back to `os.homedir()`.
   This caused `--bind $HOME $HOME` to override the preceding
   `--ro-bind $HOME $HOME`, making the entire home directory writable
   inside the sandbox — defeating the purpose of read-only home
   protection for ~/.ssh, ~/.gnupg, etc.

2. **Broken paths: claude-code-vm translates all paths to /sessions/.**
   The claude-code-vm binary internally maps all paths (both input and
   output) to `/sessions/<name>/mnt/<mount>/` guest paths. The old code
   translated guest paths to host paths via `cleanSpawnArgs` and
   `buildSpawnEnv`, but the binary translated them right back. Since
   `/sessions/` did not exist inside the bwrap namespace, all file
   operations (ls, read, write) on the working directory failed.

The fix replaces the `--ro-bind / /` full-root approach with a minimal
tmpfs-based sandbox that only mounts what is needed:

- `--tmpfs /` as an empty root
- `/usr`, `/etc`, `/dev`, `/proc` bound read-only for system tools
- Fedora-style symlinks for `/bin`, `/lib`, `/lib64`, `/sbin`
- SDK binary directory bound read-only
- `/sessions/<name>/mnt/` created via `--dir`, with host directories
  bind-mounted at their guest paths (matching the KVM backend layout)
- `--chdir` sets the cwd inside the sandbox to the guest working dir

This eliminates the guest-to-host path translation for bwrap entirely
(args and env are passed through as-is) since the guest paths now
exist natively inside the sandbox.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 09:43:59 +09:00
Sum Abiut
382a59ce9f refactor: simplify verify_sha256 and checksum calls
- Use bash read builtin instead of awk for hash extraction
- Use grep -F for literal filename matching (dots in node tarball)
- Remove redundant error messages (verify_sha256 already reports)
2026-03-20 11:25:10 +11:00
Sum Abiut
1fc4e837a2 feat: add SHA-256 checksum validation for downloads
Add integrity verification for downloaded artifacts in build.sh:

- New verify_sha256() helper function for reusable hash checking
- Claude Desktop EXE: verified after download (skipped for --exe)
- Node.js tarball: verified against official SHASUMS256.txt
- CI workflow updated to compute and store hex SHA-256 hashes
  alongside existing SRI hashes for Nix

Hash placeholders are empty until the next CI version update
populates them. The verify function gracefully warns and skips
when no hash is available, so builds are not blocked.

appimagetool is excluded as it uses a rolling "continuous"
release where checksums change frequently.
2026-03-20 11:14:47 +11:00
Aaddrick
645a11133f Merge pull request #308 from aaddrick/fix/288-virtio9p-fallback
feat: add virtio-9p fallback when virtiofsd fails in KVM backend
2026-03-19 16:16:54 -04:00
aaddrick
473b0badab fix: use security_model=none for virtio-9p unprivileged operation
mapped-xattr stores guest uid/gid in extended attributes, which can
pollute host files and fail on filesystems without xattr support.

security_model=none is like passthrough but silently ignores chown
failures — specifically designed for unprivileged QEMU operation.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 16:11:27 -04:00
aaddrick
e9a09adb2b refactor: rename share constants to reflect both virtiofs and 9p usage
VIRTIOFS_GUEST_MOUNT and VIRTIO9P_MOUNT_TAG were named after specific
transport types but are now used for both virtiofs and 9p shares.
Rename to HOME_SHARE_GUEST_MOUNT and HOME_SHARE_MOUNT_TAG, and use
the mount tag constant in both device argument lines instead of
hardcoding 'claudeshared' in the virtiofs path.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 16:09:51 -04:00
aaddrick
e8a5651064 feat: add virtio-9p fallback when virtiofsd fails in KVM backend
The Rust virtiofsd (v1.10.0+) crashes when spawned as an unprivileged
user due to setgroups/capability requirements that fail outside
interactive shells. This affects Debian 13, Ubuntu 24.04, and other
modern distros.

Add virtio-9p as an automatic fallback:
- Try virtiofsd first (best performance)
- If virtiofsd fails to create its socket, fall back to virtio-9p
- virtio-9p is built into QEMU — no external daemon, no privileges
- Uses mapped-xattr security model for proper file ownership
- Same mount tag (claudeshared) so guest mount path is unchanged

Track share type with homeShareType ('virtiofs', '9p', or null):
- Only enable shared memory backend for virtiofs (not needed for 9p)
- Both types use the same guest mount path for path translation
- Properly reset on stopVM

Refs #288, #306

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 16:07:21 -04:00
Aaddrick
d7e9180b4d Merge pull request #305 from aaddrick/fix/282-nix-launcher
feat: add proper launcher script for NixOS with --doctor and Wayland support
v1.3.18+claude1.1.7464
2026-03-19 08:45:02 -04:00
aaddrick
99d91acb41 feat: add proper launcher script for NixOS with --doctor and Wayland support
The Nix build used makeWrapper which bypassed launcher-common.sh
entirely. NixOS users had no --doctor support, no CLAUDE_USE_WAYLAND
env var handling, no display detection, and no startup logging.

Replace makeWrapper with a full bash launcher script that sources
launcher-common.sh, matching the deb/RPM/AppImage launchers:
- --doctor diagnostic support
- CLAUDE_USE_WAYLAND env var for native Wayland mode
- Display backend auto-detection
- Stale lock and socket cleanup
- Startup logging to ~/.cache/claude-desktop-debian/launcher.log
- Cowork resources (smol-bin, plugin shim) installed to resources

Also adds 'nix' package type to build_electron_args for proper
--no-sandbox handling on Wayland.

Refs #282

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 08:37:28 -04:00
aaddrick
645ad92c49 docs: update jarrodcolburn contributor entry for gh-pages bloat fix
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 08:28:14 -04:00
Aaddrick
f610583559 Merge pull request #304 from aaddrick/fix/doctor-exit-code
fix: propagate run_doctor exit code in all launchers
2026-03-19 08:08:07 -04:00
aaddrick
3f7a3c2328 fix: propagate run_doctor exit code in all launchers
All three launchers (deb, RPM, AppImage) used bare `exit` after
`run_doctor`, discarding the return code. Now uses `exit $?` so
non-zero exit codes from doctor diagnostics propagate correctly.

Also adds joekale-pp to README contributors for RPM doctor support.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 08:03:35 -04:00
Aaddrick
dcb7b39393 Merge pull request #295 from joekale-pp/fix-rpm-doctor
add doctor processing to rpm launch
2026-03-19 08:01:32 -04:00
Aaddrick
12604fc135 Merge pull request #303 from aaddrick/fix/299-cleanup
fix: clean up CLAUDE_MENU_BAR boolean alias implementation
2026-03-19 07:45:46 -04:00
aaddrick
9b4ac63323 fix: clean up CLAUDE_MENU_BAR boolean alias implementation
Follow-up to PR #299:
- Log original env var value instead of lowercased in alias resolution
- Use single quotes for literal string per style guide
- Document yes/no aliases in CONFIGURATION.md table
- Update noctuum's contributor entry for boolean alias work

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 07:43:20 -04:00
Aaddrick
3cfb0b91cc Merge pull request #299 from noctuum/fix/298-menu-bar-boolean-aliases
fix: accept boolean aliases for CLAUDE_MENU_BAR env var
2026-03-19 07:41:52 -04:00
Aaddrick
2a5aa747de Merge pull request #302 from aaddrick/fix/288-cowork-smolbin-shim
feat: extract smol-bin and plugin shim for Linux Cowork
2026-03-19 07:22:12 -04:00
aaddrick
956eb72a32 style: use template literal instead of concatenation for log message
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 07:18:42 -04:00
aaddrick
a5f16b2d5c feat: extract smol-bin and plugin shim from Windows installer
The Windows installer contains smol-bin.x64.vhdx (SDK binaries for
KVM guest) and cowork-plugin-shim.sh (MCP plugin sandboxing). Both
were previously unavailable on Linux.

build.sh:
- Add copy_cowork_resources() to extract both files from the
  Windows installer nupkg to Electron resources directory
- Patch index.js smol-bin copy to run on Linux (was win32-only)

cowork-vm-service.js:
- Convert smol-bin.vhdx to qcow2 at startVM time (same pattern as
  rootfs conversion)
- Check bundleDir for smol-bin before falling back to VM_BASE_DIR

Refs #288

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 07:17:02 -04:00
aaddrick
2c62b79f0e docs: add cbonnissent to contributors for Cowork VM fix
Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 07:07:02 -04:00
Aaddrick
019643620b Merge pull request #301 from aaddrick/fix/288-cowork-vm-followup
fix: complete cowork KVM backend (bundlePath, hardening)
2026-03-19 07:06:23 -04:00
aaddrick
1d7699e71d fix: use app-provided bundlePath for VM images in KVM backend
The app downloads VM images (rootfs.vhdx, vmlinuz, initrd) to
~/.config/Claude/vm_bundles/claudevm.bundle/ and passes this as
bundlePath in startVM params. The KVM backend was ignoring it and
looking in ~/.local/share/claude-desktop/vm/ instead.

- Use bundlePath from startVM params for rootfs, vmlinuz, initrd
- Convert VHDX to qcow2 at startVM time (app downloads VHDX format)
- Fall back to VM_BASE_DIR if bundle dir has no rootfs
- Check bundleDir and VM_BASE_DIR for smol-bin.qcow2
- Remove rootfs check from backend detection (rootfs location not
  known until startVM, app may not have downloaded it yet)
- Downgrade missing smol-bin from error to info (SDK accessible
  via virtiofs when available)

Refs #288

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 06:58:56 -04:00
aaddrick
4bc44ec003 style: clean up log string formatting in KVM installSdk
Use consistent template literals for log messages and restructure
the path.join assignment for readability.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 06:48:26 -04:00
aaddrick
932044d888 fix: harden cowork VM service daemon after #300 merge
Follow-up to PR #300 addressing remaining issues found during
upstream source analysis:

- Add setDebugLogging method (app calls it, was returning unknown method)
- Fix _ensureSdkInstalled retry bug (clear pendingSdkInstall on failure)
- Add path traversal guard in KVM installSdk guest path computation
- Add startupStep event emissions during KVM VM boot sequence
- Add startupStep to FORWARDED_EVENTS for guest-originated events

Refs #288

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 06:46:30 -04:00
Aaddrick
52fa40a1fd Merge pull request #300 from cbonnissent/fix/288-cowork-vm-starting-up
Merging KVM cowork fixes. Follow-up PR incoming for remaining items.
2026-03-19 06:43:27 -04:00
Charles Bonnissent
5d6f897dee refactor: simplify KVM backend SDK install and virtiofs paths (#288)
- Extract _ensureSdkInstalled() to deduplicate SDK install logic
  in spawn() and installSdk()
- Hoist virtiofsSock declaration before try block to avoid
  redundant redeclaration in the virtiofs chardev section
- Add VIRTIOFS_GUEST_MOUNT constant to replace repeated magic string
- Use template literal consistently for error log message

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:51:49 +01:00
Charles Bonnissent
10e745add3 fix: send writeStdin as notification instead of request (#288)
The guest sdk-daemon treats stdin as a JSON-RPC notification
(fire-and-forget, no id, no response), not as a request. Sending it as
{type:"request"} causes the guest to reject with "unknown method" for
every method name variant. The correct wire format is:

  {type: "notification", method: "stdin", params: {id, data}}

This was the final blocker preventing Cowork from becoming interactive.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:44:25 +01:00
Charles Bonnissent
06a8cd3b8a fix: forward installSdk to guest and resolve guest SDK path (#288)
The guest sdk-daemon needs to know where the SDK binary is on the
virtiofs mount. Compute the guest-side path and forward the installSdk
RPC call to the guest. If the guest isn't connected yet, defer until
just before spawn.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:44:00 +01:00
Charles Bonnissent
283e669e44 fix: correct guest RPC wire protocol (#288)
Three protocol fixes for communication with the guest sdk-daemon:

- Wrap outgoing messages with {type:"request"} — the guest expects this
  envelope and ignores bare messages
- Handle guest event format {type:"event", event:"networkStatus"} in
  addition to the direct {type:"networkStatus"} format
- Extract msg.result from responses instead of passing the full envelope
  to callbacks
- Log decoded JSON for all guest messages and errors for debugging

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:42:46 +01:00
Charles Bonnissent
d96b787668 fix: correct virtiofs tag and guest mount path (#288)
The guest sdk-daemon mounts virtiofs with tag 'claudeshared' at
/mnt/.virtiofs-root, not 'hostshare' at /mnt/host. Mismatched tag
causes "wrong fs type, bad superblock" errors.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:41:59 +01:00
Charles Bonnissent
ae9289355d fix: attach session disk and smol-bin drive (#288)
The guest sdk-daemon expects:
- /dev/vdb: a blank writable disk for session storage (ext4)
- /dev/vdc: the smol-bin disk (readonly) containing SDK binaries

Without the session disk, the guest tries to format smol-bin and fails.
Without smol-bin, the guest sdk-daemon crashes at startup.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:41:35 +01:00
Charles Bonnissent
fc0d55fe7b fix: use shared memory backend for virtiofs (#288)
vhost-user-fs-pci requires shared memory. Without memory-backend-memfd
with share=on, QEMU fails with vhost VQ ring errors. Only enabled when
virtiofsd is running.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:41:12 +01:00
Charles Bonnissent
0eb5ce34d5 fix: wait for virtiofsd socket before starting QEMU (#288)
virtiofsd is spawned asynchronously but QEMU needs the socket to exist
when it starts. Without this wait, QEMU fails with "Connection refused"
and dies silently. Poll every 100ms for up to 5s.

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:40:53 +01:00
Charles Bonnissent
af1f2e320e fix: add ready event to FORWARDED_EVENTS (#288)
The guest sdk-daemon sends {"type":"event","event":"ready"} after boot.
Without 'ready' in FORWARDED_EVENTS, this event is silently dropped as
"unhandled guest message" and the app stays stuck on "starting up".

Co-Authored-By: Claude <claude@anthropic.com>
2026-03-19 10:40:29 +01:00