Skip to content

v1.8.0

Choose a tag to compare

@claustrum-ci claustrum-ci released this 09 Aug 22:59
b594e54

Compare with 1.7.3

Features

  • -install no longer bounds the -cli-url download at 5 minutes by default, so a slow-but-honest download the reference completes now succeeds rather than failing with cliError "download failed: context deadline exceeded (Client.Timeout or context cancellation while reading body)"; opt-in via -cli-download-timeout or the cli-download-timeout key in claustrum.conf. (#246)
  • -install no longer bounds the <cli> --version runnability probe at 15 seconds by default, so a slow-but-working CLI installs instead of failing with cliError "installed cli at <path> is not runnable" and having its staged binary deleted; opt-in via -cli-probe-timeout or the cli-probe-timeout key in claustrum.conf. (#245)
  • -install no longer caps the decompressed CLI or the download body at 512 MiB by default, so a large CLI installs instead of failing with a cliError the reference daemon never produces; opt-in via -max-cli-bytes or the max-cli-bytes key in claustrum.conf. (#238)
  • files.extract_tar no longer caps extraction at 512 MiB by default, so a large tree extracts instead of failing with an error the reference daemon never produces; the cap is now opt-in via -max-extract-bytes or the max-extract-bytes key in claustrum.conf. (#236)
  • files.read no longer refuses a non-regular path by default, so reading a character device such as /dev/null returns {"content":"","exists":true} as the reference daemon does instead of a claustrum-only -32602 "files.read: not a regular file"; the guard is now opt-in via -files-read-regular-only or the files-read-regular-only key in claustrum.conf, which restores the bound on a writerless FIFO and on unbounded device reads. (#250)
  • The daemon no longer bounds every git invocation at 60 seconds by default, so a slow-but-honest git on a large or cold repository completes instead of being SIGKILLed into a claustrum-only -32603 "signal: killed" (or a git worktree remove timed out after …) where the reference showed no such deadline at the durations probed; now opt-in via -git-timeout or the git-timeout key in claustrum.conf. (#248)
  • -install no longer bounds the linux ldd --version libc probe at 5 seconds by default, so a slow ldd's answer stands instead of being killed into a fallback classification — the reference daemon showed no such deadline against a stalled ldd at the durations probed; the deadline is now opt-in via -libc-probe-timeout or the libc-probe-timeout key in claustrum.conf. (#251)

Fixes

  • The exit stream frame now arrives at most 5 seconds after a spawned process exits, instead of waiting forever when the command left a background grandchild holding its stdout. (#186)
  • A reply's id is now the request's id decoded and re-encoded rather than the raw bytes echoed back, so a non-integer id such as 1.0, 1e2 or {"b":1,"a":2} is canonicalized exactly as the reference returns it. (#188)
  • -install now creates the CLI directory chain owner-only (0700) like the reference, instead of 0755 which left the installed CLI world-traversable. (#191)
  • A non-200 CLI download now reports download failed with status <code> like the reference, instead of a differently-worded message that also leaked the download URL into the __INSTALL_RESULT__ line. (#197)
  • A zero-byte -token-file is now a fatal startup error instead of producing a daemon that listens but can never be authenticated to, and the daemon now logs a failed token-file unlink, a child stream read error, and a discarded stdin queue rather than passing over them in silence. (#200)
  • Report the reference daemon's error text for files.list on a non-directory, files.extract_tar failing to open the archive, and process.spawn with an unusable cwd. (#175)
  • Expand a leading ~ to the home directory on every path parameter, so files.*, git.* and process.spawn no longer fail or create a literal ~ directory. (#176)
  • A ~-prefixed path is now cleaned lexically like the reference — ~/link/../x means ~/x even when link is a symlink, ~//f and ~/a/./b and a trailing ~/wt/ collapse, and bare ~ alone stays verbatim — which is wire-visible on eight frames, most sharply on files.stat/files.validate where a trailing separator on a regular file previously answered not a directory and now succeeds. (#205)
  • files.extract_tar now carries the reference's create <entry>: prefix when an archive entry's target lands on an existing directory, so the error field reads create ../sub: open <dest>: is a directory instead of the bare Go error. (#226)
  • files.extract_tar now refuses a Windows volume or UNC share root as destDir — previously only the literal / was refused, so C:\ passed the guard and reached the os.RemoveAll that clears the destination before extracting. (#225)
  • files.read now applies the reference's 256 KiB (262144-byte) default cap when maxBytes is absent, zero, or negative, instead of reading the file without any limit; an explicit positive maxBytes is still honored verbatim. (#189)
  • Wait for the login-shell PATH extraction before the first process.spawn builds its child environment, so the first command finds binaries in ~/.local/bin and nvm. (#168)
  • git.list_branches reads git's stdout only and reports a failed for-each-ref as -32603 exit status <n>, so a broken ref no longer lists git's warning: line as a branch and a corrupt refs database no longer returns that failure as branch names. (#213)
  • git.status and git.list_branches now recognize a bare repository and a .git directory as repositories, and git.worktree_create ignores a sourceBranch that is not a local branch instead of failing the request. (#178)
  • git.status now trims the whole porcelain output before splitting it, so the first change loses its leading space and every later one keeps it, matching the reference. (#185)
  • Keep the leading space on git.status porcelain lines so a client can tell a staged change from an unstaged change. (#167)
  • git.status now reads only git's stdout, so warnings git writes to stderr (an unreadable core.excludesFile, for example) no longer appear as entries in changes and no longer make a clean repo report as dirty. (#193)
  • The daemon now recovers from a panic in any request handler instead of crashing, replying -32603 "recovered panic: <v>" and staying up for other connections, so a handler bug can no longer orphan managed child processes or leave a stale socket behind. (#243)
  • -install no longer executes ldd when the musl loader marker already answers the question, and it consumes the local -cli-zst blob once decompression succeeds rather than only on a fully successful install — both matching the reference. (#216)
  • -install now removes leftover .fetch-* download temporaries, which previously counted against -cli-keep and could delete every real CLI version, and it prunes only after an install that succeeded. (#180)
  • -install stages the CLI at .fetch-<random> and sweeps stray *.zst blobs so leftovers no longer take a -cli-keep slot; an occupied cliPath is cleared instead of failing with a rename error; a failed cli-dir creation carries the mkdir cli dir: prefix; -cli-version must name a single entry inside -cli-dir, so a version reaching outside via .. or a symlink can no longer delete a directory there, and one the orphan sweep claims (.fetch-* or *.zst) is refused; the new CLI is renamed into place before the old one is cleared, so two installs in one cli-dir cannot leave it empty; if another install reclaims its staging file, it retries once instead of failing. (#196)
  • process.killAndWait clamps timeoutMs at 30000 ms instead of 600000 ms, so a caller asking for a longer grace against a signal-ignoring child now gets its exit frame at 30 s, matching the reference. (#214)
  • The login-shell PATH is now applied only to spawned children, not the daemon's own environment, so the daemon no longer resolves its own git through the user's PATH; a non-executable $SHELL falls back to a usable shell instead of failing extraction, and a missing PATH sentinel is logged with the shell's output. (#199)
  • Login-shell PATH extraction now gives up after 4 seconds instead of 10, matching the reference, so a slow login shell no longer delays the first process.spawn or hands spawned children a PATH the reference would not have applied. (#190)
  • -install now reports musl when a musl loader of any architecture is present, and reports no libc at all on macOS and Windows, matching the reference daemon. (#183)
  • process.kill and process.killAndWait now match signal names case-sensitively and no longer map QUIT to SIGQUIT, so a request naming quit sends SIGTERM like the reference instead of a SIGQUIT that dumps core. (#203)
  • Reject a negative offset on process.stdin and a negative fromSeq on process.reattach, which before silently dropped the first bytes of the child's stdin. (#173)
  • files.stat, files.read and files.validate now report a stat failure other than "does not exist" instead of the missing-path result — e.g. a path component that is a file. (#177)
  • Exited processes are now dropped from the process table 15 minutes after they finish, freeing their replay buffers, so process.reattach on a long-finished id reports found:false as the reference does. (#187)
  • process.killAndWait now waits 7 seconds for a SIGKILL'd process to be reaped instead of 5, matching the reference daemon, so a child that is reaped between those two points is reported as dead rather than still running. (#242)
  • process.reattach now transfers the frame stream to the reattaching connection like the reference, so a previously attached connection stops receiving instead of both getting every frame after a resume. (#202)
  • files.extract_tar now refuses a destDir that is or contains the home directory, so a tilde or relative path can no longer reach the recursive delete it performs before unpacking — paths under home, such as ~/.claude/…, are unaffected. (#231)
  • git.worktree_remove now refuses a worktreePath that is or contains the home directory, so a tilde or relative path can no longer reach the recursive delete it performs when git fails — the method previously had no path guard of any kind. (#232)
  • -serve now writes its output to remote-server.log beside the socket (mode 0600) instead of the launcher's stdout and stderr, and the file survives a graceful shutdown. (#181)
  • The per-process replay buffer counts its 16 MiB cap in serialized frame bytes, not base64 payload alone, so process.reattach's firstSeq matches the reference on small-frame workloads instead of retaining ~9% too many frames. (#215)
  • Cap the per-process replay buffer at 16 MiB instead of 50 MiB, so process.reattach reports the same firstSeq floor as the reference daemon. (#174)
  • git.info emits repoSlug only for a canonical github.com remote whose owner and repo pass the reference's charset rules, not for any remote URL with two path segments, so GitLab, Bitbucket, self-hosted, and www.github.com remotes report "". (#192)
  • claustrum -serve with neither -token-file nor -token-fd now daemonizes and refuses to start in the detached child, so the launcher reports its ~10s accept timeout as the reference does, instead of exiting immediately with the specific reason. (#217)
  • -serve now creates a missing socket directory (mode 0700) instead of refusing to start, and waits until the daemon is accepting before returning, so a client connecting immediately after launch no longer races an unopened socket. (#195)
  • claustrum now prefers zsh over bash when $SHELL is unusable and discards a login PATH whose extraction timed out, both matching the reference. (#212)
  • server.shutdown is no longer authenticated, matching the reference, so claustrum --stop --socket <sock> works with no CLAUDE_RPC_TOKEN; every other method still requires auth. (#206)
  • process.kill and process.killAndWait now deliver a non-KILL signal to the spawned process alone, not its whole process group, so a graceful stop no longer kills the background jobs the command started, while escalate:true still sweeps the group with SIGKILL as the reference does. (#194)
  • Pipelined process.stdin requests on one connection now reach the child in the order they were sent, instead of racing and scrambling the byte stream. (#201)
  • -stop now gives up waiting for the daemon's reply after 2 seconds like the reference instead of blocking forever, and no longer echoes that reply frame to stdout. (#198)
  • claustrum -stop now unlinks the socket path on every exit path — including when the dial fails and no daemon was ever reached — matching the reference, so a stale socket no longer blocks the next -serve from binding. (#217)
  • git.worktree_create now copies .claude/ and the files named by .worktreeinclude into the new worktree, which previously came up with tracked files only. (#182)
  • git.worktree_remove now deletes the branch given in branchName, including a branch that is not merged, in place of leaving it in the repository. (#179)
  • git.worktree_remove now removes the worktree directory itself when git refuses (e.g. a locked worktree) and reports success:false with an error when that cleanup also fails, instead of answering success:true while leaving the directory in place; a git worktree remove that hits claustrum's opt-in git deadline is reported rather than treated as a refusal, so a wedged git no longer triggers that cleanup. (#204)

Performance

  • -install streams the download to a temporary file and hashes it as it arrives, and hashes and decompresses the local -cli-zst blob straight from disk, so peak memory is flat in the blob size (measured 886 MB to 10 MB on a 400 MiB download) with no change to any cliError or install outcome. (#238)