Files
2pac bedd7b7953 v0.7.0: FUSE remote-mount mode + daemon-start + optional-dep fixes (#15)
* [Phase 1] Daemon-start fix + Optional FUSE subpackage fix

- daemon.ts: respawn via process.argv[1] so npm-installed CLI starts cleanly
  (was: dist/index.ts ENOENT under the isCompiled heuristic).
- fuse-helper-linux-{x64,arm64}: drop libc array; os+cpu is the correct
  constraint and matches esbuild/swc/rollup convention. Fixes npm silently
  skipping the optional FUSE subpackage on first global install.
- cli/package.json: relax exact 0.6.1 pins to ^0.7.0 (npm/cli#4828 family).
- sync-versions.ts: preserve carets on @desplega.ai/agent-fs-fuse-* pins.
- daemon-respawn.test.ts: regression test for the npm-install layout.

* [Phase 2] CLI plumbing — mount --remote flag + helper arg passing

- mount.ts: new --remote / --api-url / --api-key flags. Skips local daemon
  socket check when remote; forwards API key via child env only, never argv.
  Implicit remote opt-in when --api-url/--api-key supplied without --remote.
- fuse-args.ts: pure buildHelperSpawnArgs() composing argv + env for
  local vs remote modes; enforces mutual exclusion invariants.
- remote-config.ts: resolveRemoteCreds() with flags > env > config
  precedence; tolerant of auth.apiKey fallback + malformed config.
- 21 unit tests (12 for fuse-args, 9 for remote-config).

Helper still rejects --api-url — intentional, Phase 3 lands HTTP transport.

* [Phase 3] HttpIpcClient — read-only ops + new CLI args

- Cargo.toml: reqwest 0.12 (rustls-tls/json/stream — no native-tls for
  musl-static compat), bytes, once_cell, wiremock dev-dep, clap `env`.
- main.rs: --api-url / --api-key clap args (env-backed, hide_env_values
  on key). Transport selection branches on both-present.
- ipc.rs: HttpIpcClient for Ping/Hello/ListDrives/DefaultDriveSlug/
  GetAttr/ReadDir/OpenRead. Mutating ops return synthetic EROFS until
  Phase 4 (safer than unreachable!()). Shared with_retry helper between
  Unix + HTTP clients. Drive-table + auth/me caches. get_attr dir-probe
  fallback via ls mirrors daemon handlers.ts behavior.
- fs.rs: relax I to ?Sized; add FuserAdapter::from_arc for the unsized
  dyn IpcTrait path. Existing Sized constructor preserved for tests.
- tests/http_ipc_roundtrip.rs: 10 wiremock-driven integration tests.
- Dockerfile.test: bump pinned toolchain 1.85.0→1.86.0 (reqwest →
  icu_* MSRV).

54 Rust tests pass. Release binary size 2.5 MB (1.7× baseline).

* [Phase 4] HttpIpcClient — write ops + conflict handling

- ipc.rs: real HTTP impls replace Phase 3 EROFS stubs for OpenWrite,
  CreateFile, Truncate, Unlink, Rename, Mkdir, Rmdir. Added
  parse_version_headers (ETag → version, X-Agent-Fs-Content-Hash) and
  decode_http_error helpers.
- 409 EDIT_CONFLICT propagates through Response::Error → kernel sees
  EIO via the existing errno mapping.
- Rename across drives short-circuits to EXDEV without an HTTP call.
- Truncate reuses do_open_read + do_open_write for the RMW path so URL
  encoding + header parsing stay in one place.
- Mkdir is a true local no-op matching daemon behaviour.
- 11 new wiremock tests covering write happy / conflict / EXDEV / mkdir
  / rmdir / truncate paths. 64 total tests green.

Docker --http harness deferred to Phase 5.

* [Phase 5] E2E coverage for remote mount

- scripts/e2e-remote-mount.ts: Docker-based harness. Daemon on host,
  helper in container, talking over host.docker.internal. 9 ops:
  mount, ls drives + current symlink, mkdir, host→mount visibility,
  echo+cat roundtrip, ls reflects new file, mv within drive, rm,
  fusermount3 -u. ~4 min wallclock end-to-end with cargo build.
- Dockerfile.e2e-fuse: bump rustc 1.85→1.86 (matches Phase 3's
  Dockerfile.test bump — reqwest → icu_* MSRV). Benefits the existing
  e2e.ts FUSE suite too.
- README.md: link to the harness from the FUSE mount section.
- bun.lock: catch up to 0.6.1 + ^0.7.0 caret pins already on disk.

* [Phase 6] docs/mounting — general + sprite + e2b + hetzner

- docs/mounting/README.md: ASCII two-topology diagram (local daemon vs
  --remote), prereqs table, auth model, top-4 troubleshooting cribbed
  from the 2026-05-18 sprite test, per-env doc table.
- docs/mounting/sprite.md: the 4 prereq commands + idempotent one-liner
  bash script for re-running on fresh sprites.
- docs/mounting/e2b.md: marked Status: untested; documents expected
  Dockerfile + mount flow + risk checklist + CLI fallback. Existing
  fuse-compat.md confirms E2B kernel has CONFIG_FUSE_FS=y; remaining
  unknowns flagged for reader reports.
- docs/mounting/hetzner.md: 4-step happy path + systemd unit example.
- README.md: link to docs/mounting/README.md under FUSE section;
  consolidated with Phase 5's --remote subsection without duplication.

* [Phase 7] v0.7.0: FUSE remote-mount + daemon-start + optional-dep fixes

- Version bump to 0.7.0 across all packages, plugin, Cargo, openapi.
- skills/agent-fs/SKILL.md: mount/fuse/remote/sandbox triggers added;
  Remote mode section + --remote command-table row; sprite prereqs
  example in workflow examples.
- Release notes filed under thoughts/taras/learnings/ (notes/ dir is
  blocked by validate-thoughts.py hook).
- Plan checkboxes updated for pre-release verification; post-tag-push
  boxes left unchecked until release.sh runs.

Pre-release verification all green:
- typecheck, 324 unit tests, e2e (68/68), e2e-remote-mount (9/9)
- cargo test (64), clippy --all-targets -D warnings, fmt --check

* qa: v0.7.0 Hetzner + sprite end-to-end passed

- Hetzner VM (cx23, Ubuntu 24.04): B-1..B-7 all PASS. agent-fs 0.7.0
  installed via npm (Node 22 + Bun), daemon-start bug fixed, mount
  --remote against fly works, write/mv/rm roundtrip clean.
- Sprite (code-health-scan, Ubuntu 25.10): C-1..C-6 all PASS. All 4
  FUSE prereqs already in place. bun install -g, native cargo build
  (1m6s), mount --remote against fly works end-to-end.

Findings (not blocking 0.7.0, follow-ups):
- F-1: npm install -g aborts on Ubuntu 24.04 default Node 18.19.1 due
  to node-llama-cpp postinstall syntax error. Workaround: Node 20+ or
  bun install -g (which the Hetzner doc already recommends). README's
  npm snippet should match.
- F-2: 'default' drive appears 3x under mount root (multi-org flat
  namespace artifact). Same behavior under local-daemon path.
2026-05-19 00:49:13 +02:00
..