claws-code 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/claws-auto.md +90 -0
- package/.claude/commands/claws-bin.md +28 -0
- package/.claude/commands/claws-cleanup.md +28 -0
- package/.claude/commands/claws-do.md +82 -0
- package/.claude/commands/claws-fix.md +40 -0
- package/.claude/commands/claws-goal.md +111 -0
- package/.claude/commands/claws-help.md +54 -0
- package/.claude/commands/claws-plan.md +103 -0
- package/.claude/commands/claws-report.md +29 -0
- package/.claude/commands/claws-status.md +37 -0
- package/.claude/commands/claws-update.md +32 -0
- package/.claude/commands/claws.md +64 -0
- package/.claude/rules/claws-default-behavior.md +76 -0
- package/.claude/settings.json +112 -0
- package/.claude/settings.local.json +19 -0
- package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
- package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
- package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
- package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
- package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
- package/CHANGELOG.md +1949 -0
- package/LICENSE +21 -0
- package/README.md +420 -0
- package/bin/cli.js +84 -0
- package/cli.js +223 -0
- package/docs/ARCHITECTURE.md +511 -0
- package/docs/event-protocol.md +588 -0
- package/docs/features.md +562 -0
- package/docs/guide.md +891 -0
- package/docs/index.html +716 -0
- package/docs/protocol.md +323 -0
- package/extension/.vscodeignore +15 -0
- package/extension/CHANGELOG.md +1906 -0
- package/extension/LICENSE +21 -0
- package/extension/README.md +137 -0
- package/extension/docs/features.md +424 -0
- package/extension/docs/protocol.md +197 -0
- package/extension/esbuild.mjs +25 -0
- package/extension/icon.png +0 -0
- package/extension/native/.metadata.json +10 -0
- package/extension/native/node-pty/LICENSE +69 -0
- package/extension/native/node-pty/README.md +165 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
- package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
- package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
- package/extension/native/node-pty/lib/index.js +52 -0
- package/extension/native/node-pty/lib/index.js.map +1 -0
- package/extension/native/node-pty/lib/interfaces.js +7 -0
- package/extension/native/node-pty/lib/interfaces.js.map +1 -0
- package/extension/native/node-pty/lib/shared/conout.js +11 -0
- package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
- package/extension/native/node-pty/lib/terminal.js +190 -0
- package/extension/native/node-pty/lib/terminal.js.map +1 -0
- package/extension/native/node-pty/lib/types.js +7 -0
- package/extension/native/node-pty/lib/types.js.map +1 -0
- package/extension/native/node-pty/lib/unixTerminal.js +346 -0
- package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/utils.js +39 -0
- package/extension/native/node-pty/lib/utils.js.map +1 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
- package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
- package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
- package/extension/native/node-pty/package.json +64 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
- package/extension/package-lock.json +605 -0
- package/extension/package.json +343 -0
- package/extension/scripts/bundle-native.mjs +104 -0
- package/extension/scripts/deploy-dev.mjs +60 -0
- package/extension/src/ansi-strip.ts +52 -0
- package/extension/src/backends/vscode/claws-pty.ts +483 -0
- package/extension/src/backends/vscode/status-bar.ts +99 -0
- package/extension/src/backends/vscode/vscode-backend.ts +282 -0
- package/extension/src/capture-store.ts +125 -0
- package/extension/src/event-log.ts +629 -0
- package/extension/src/event-schemas.ts +478 -0
- package/extension/src/extension.js +492 -0
- package/extension/src/extension.ts +873 -0
- package/extension/src/lifecycle-engine.ts +60 -0
- package/extension/src/lifecycle-rules.ts +171 -0
- package/extension/src/lifecycle-store.ts +506 -0
- package/extension/src/peer-registry.ts +176 -0
- package/extension/src/pipeline-registry.ts +82 -0
- package/extension/src/platform.ts +64 -0
- package/extension/src/protocol.ts +532 -0
- package/extension/src/server-config.ts +98 -0
- package/extension/src/server.ts +2210 -0
- package/extension/src/task-registry.ts +51 -0
- package/extension/src/terminal-backend.ts +211 -0
- package/extension/src/terminal-manager.ts +395 -0
- package/extension/src/topic-registry.ts +70 -0
- package/extension/src/topic-utils.ts +46 -0
- package/extension/src/transport.ts +45 -0
- package/extension/src/uninstall-cleanup.ts +232 -0
- package/extension/src/wave-registry.ts +314 -0
- package/extension/src/websocket-transport.ts +153 -0
- package/extension/tsconfig.json +23 -0
- package/lib/capabilities.js +145 -0
- package/lib/dry-run.js +43 -0
- package/lib/install.js +1018 -0
- package/lib/mcp-setup.js +92 -0
- package/lib/platform.js +240 -0
- package/lib/preflight.js +152 -0
- package/lib/shell-hook.js +343 -0
- package/lib/uninstall.js +162 -0
- package/lib/verify.js +166 -0
- package/mcp_server.js +3529 -0
- package/package.json +48 -0
- package/rules/claws-default-behavior.md +72 -0
- package/scripts/_helpers/atomic-file.mjs +137 -0
- package/scripts/_helpers/fix-repair.js +64 -0
- package/scripts/_helpers/json-safe.mjs +218 -0
- package/scripts/bump-version.sh +84 -0
- package/scripts/codegen/gen-docs.mjs +61 -0
- package/scripts/codegen/gen-json-schema.mjs +62 -0
- package/scripts/codegen/gen-mcp-tools.mjs +358 -0
- package/scripts/codegen/gen-types.mjs +172 -0
- package/scripts/codegen/index.mjs +42 -0
- package/scripts/dev-hooks/check-extension-dirs.js +77 -0
- package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
- package/scripts/dev-hooks/check-stale-main.js +55 -0
- package/scripts/dev-hooks/check-tag-pushed.js +51 -0
- package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
- package/scripts/dev-vsix-install.sh +60 -0
- package/scripts/fix.sh +702 -0
- package/scripts/gen-client-types.mjs +81 -0
- package/scripts/git-hooks/pre-commit +31 -0
- package/scripts/hooks/lifecycle-state.js +61 -0
- package/scripts/hooks/package.json +4 -0
- package/scripts/hooks/post-tool-use-claws.js +292 -0
- package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
- package/scripts/hooks/pre-tool-use-claws.js +206 -0
- package/scripts/hooks/session-start-claws.js +97 -0
- package/scripts/hooks/stop-claws.js +88 -0
- package/scripts/inject-claude-md.js +205 -0
- package/scripts/inject-dev-hooks.js +96 -0
- package/scripts/inject-global-claude-md.js +140 -0
- package/scripts/inject-settings-hooks.js +370 -0
- package/scripts/install.ps1 +146 -0
- package/scripts/install.sh +1729 -0
- package/scripts/monitor-arm-watch.js +155 -0
- package/scripts/rebuild-node-pty.sh +245 -0
- package/scripts/report.sh +232 -0
- package/scripts/shell-hook.fish +164 -0
- package/scripts/shell-hook.ps1 +33 -0
- package/scripts/shell-hook.sh +232 -0
- package/scripts/stream-events.js +399 -0
- package/scripts/terminal-wrapper.sh +36 -0
- package/scripts/test-enforcement.sh +132 -0
- package/scripts/test-install.sh +174 -0
- package/scripts/test-installer-parity.sh +135 -0
- package/scripts/test-template-enforcement.sh +76 -0
- package/scripts/uninstall.sh +143 -0
- package/scripts/update.sh +337 -0
- package/scripts/verify-release.sh +323 -0
- package/scripts/verify-wrapped.sh +194 -0
- package/templates/CLAUDE.global.md +135 -0
- package/templates/CLAUDE.project.md +37 -0
|
@@ -0,0 +1,1906 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Claws will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.8.0] - 2026-05-13
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Renamed npm package from `claws` to `claws-code`** — mirrors `claude-code` branding, making the pairing unmistakably clear. Install command is now `npx claws-code install`. Binary entry point is `claws-code`; backward-compat alias `claws` kept for one minor (removed in v0.9). VS Code extension publisher ID (`neunaha.claws`), slash commands (`/claws-*`), and MCP tool names (`claws_*`) are unchanged.
|
|
12
|
+
|
|
13
|
+
## [Unreleased]
|
|
14
|
+
|
|
15
|
+
### Internal
|
|
16
|
+
- **v0.8 P3.3 — installer dry-run threading + 11-scenario test suite** — `lib/install.js`: fix `writeMcpJson` never being called (`.mcp.json` was silently skipped every install); added call in `_prepareCLawsBin` for both live and dry-run paths. Fix `_injectClaudeMd` dry-run gap: `inject-claude-md.js` has no `--dry-run` support so the call is now guarded at the lib level (logs + returns early in dry-run mode); `inject-global-claude-md.js` does support `--dry-run` so it is still invoked with the flag. `test/installer.test.js`: 11-scenario matrix using `node:test`, sandboxed `HOME` via child-process env override (real `~/.claude/` is never touched): (a) fresh install — `.claws-bin`, `.mcp.json`, commands, skills, rules; (b) re-install idempotent — single `CLAWS:BEGIN`, valid `settings.json`; (c) upgrade — Bug 1 sweeps stale `claws-*.md`, Bug 2 sweeps stale skill dirs; (d) dry-run — sha256 before/after equal, stdout has `[dry-run]` lines; (e) `--no-hooks` — `settings.json` gets no claws entries; (f) `--vscode-cli` override — install succeeds with custom CLI path; (g) missing VS Code CLI — clean exit, no unhandled exception/stack trace; (h) uninstall — `.claws-bin`, `CLAUDE.md` block, rule, hooks all removed; (i) status — passing checks for pre-installed state; (j) `--version` — matches `package.json` version; (k) preflight failure — no partial state written. All 11/11 pass. `package.json` gains `test:installer-full` script.
|
|
17
|
+
- **v0.8 P3.1 — Node installer Mac/Linux core** — `bin/cli.js`: CLI entrypoint with `util.parseArgs`; routes `install | update | uninstall | status | --version`. `lib/preflight.js`: Node ≥18, git, VS Code CLI, HOME-writable checks. `lib/install.js`: 8-phase installer (preflight → .claws-bin → CLAUDE.md injection → hooks → commands+Bug1 → skills+Bug2 → extension → shell hook). `lib/capabilities.js`: Bug 1/Bug 2 sweep + command/skill/rule copy with configurable targetRoot. `lib/shell-hook.js`: versioned `# >>> claws-code shell hook >>>` block injection/removal; idempotent. `lib/mcp-setup.js`: atomic `.mcp.json` merge (claws entry); malformed-file-safe. `lib/verify.js`: post-install check + `status` dashboard. `lib/dry-run.js`: fs-operation wrappers that log `[dry-run] would <action>` instead of executing when dryRun=true. `lib/uninstall.js`: full reverse sequence (extension, .claws-bin, .mcp.json CLAWS:BEGIN blocks, hooks, rule, commands, skills, shell hook). `package.json`: bin field updated to `claws-code → ./bin/cli.js` (alias `claws` kept). 21/21 installer-platform tests green.
|
|
18
|
+
- **v0.8 P2.1 — multi-arch bundle + Windows test coverage (~37 new checks)** — `extension/scripts/bundle-native.mjs`: win32 Electron detection via `LOCALAPPDATA`/`Programs`/`C:\Program Files` paths (VSCode, Cursor); M-23 warning condition includes `platform === 'win32'`; spawn-helper skip explicitly noted for win32. New tests: `pty-windows-shell.test.js` (5), `named-pipe-server.test.js` (7), `conpty-marker-scan.test.js` (5), `claws-windows-paths.test.js` (6), `bundle-native-multiarch.test.js` (4). Adapted existing tests: `bundle-native-arch.test.js` (+2 = 8), `bundle-native-editor-detect.test.js` (+1 = 10), `bundle-native-spawn.test.js` (+2 = 7), `terminal-manager.test.js` (+1 = 5), `native-bundle.test.js` (+1 = 5), `pty-lifecycle.test.js` (+1 = 14), `oversized-line.test.js` (+1 = 4), `profile-provider.test.js` (+1 = 7), `extension-rebuild-pty-timeout.test.js` (+1 = 7). 5 new `test:*` scripts in `package.json`. Full suite: 0 failures.
|
|
19
|
+
- **v0.8 P2.1 — transport.ts + win32 platform helpers + pipe-aware clients** — New `extension/src/transport.ts`: `getServerEndpoint(workspaceRoot, platform?)` returns `\\.\pipe\claws-<sha256[0:8] of lowercase workspaceRoot>` on win32 and `.claws/claws.sock` under workspaceRoot on mac/linux; `isNamedPipe()` helper for `fs.unlink`/`chmod` guards; injectable `platform` param for unit tests. `extension/src/platform.ts`: win32 branch of `getProcessHelpers()` now returns `{pid: shellPid, basename: null}` (was throwing "not implemented"). `extension/src/backends/vscode/claws-pty.ts`: win32 stub in `getForegroundProcess()` — returns shell PID + `path.basename(shellPath)` instead of calling `pgrep`/`ps`; safety gate still warns correctly with null/unknown basename. `mcp_server.js`: pipe-aware `getSocket()` for win32 using same sha256[0:8] algorithm; `_findWorkspaceRoot()` walks up for `.claws/` directory; `_logL2File()` guarded against named pipe path. `scripts/stream-events.js`: pipe-aware `findSocket()` for win32; `_findWorkspaceRootWin()` helper; unix walk unchanged.
|
|
20
|
+
- **v0.8 P3.2 — `lib/platform.js` + installer-platform tests** — New CommonJS platform helper module (`lib/platform.js`) centralizing all cross-platform detection for the Node installer. Exports: `findCodeCli()` (env override → known win32/darwin/linux paths → which/where fallback), `detectOneDrivePath(homeDir)`, `longPathPreflight(homeDir)` (warns on paths >100 chars or OneDrive-rooted), `defenderExclusionCommand(installPath)` (PowerShell Add-MpPreference snippet, null on non-Windows), `getDefaultShellRcFile()` (zsh/bash/fish/$PROFILE by platform + $SHELL), `dryRunLog(msg)`. All helpers accept internal `_opts` for platform/env injection, enabling mocked unit tests without modifying `process.platform`. `test/installer-platform.test.js`: 21 checks across 6 suites using `node:test`. `package.json` gains `test:installer` script. `bin/` created for future `bin/cli.js` (P3.1 entry point).
|
|
21
|
+
- **v0.8 P1 commit 3 — server.ts consumes TerminalBackend (zero vscode.* imports)** — `ServerOptions.terminalManager` → `ServerOptions.backend: TerminalBackend`. All terminal ops (list, create, send, exec, close, readLog) route through the interface. `vscode.*` and `TerminalManager` imports removed from `server.ts`. `exec` degrades gracefully when `backend.execCommand` is absent. `terminal:created`/`terminal:closed` events replace `setTerminalCloseCallback`. `ExtendedBackend` optional-chain pattern exposes VS Code-specific extras. `extension.ts` constructs `VsCodeBackend` and passes it as `backend`; `execWaiters` WeakMap moves to `VsCodeBackend`. `terminal-backend.ts` adds VS Code-optional fields to `BackendTerminalInfo` and expands `TerminalClosedEvent.origin`. Test baseline: 764 checks / 94 suites / 0 failures (unchanged).
|
|
22
|
+
- **v0.8 P1 commit 2 — move claws-pty + status-bar to backends/vscode/ + add VsCodeBackend adapter** — `git mv extension/src/claws-pty.ts extension/src/backends/vscode/claws-pty.ts` and `git mv extension/src/status-bar.ts extension/src/backends/vscode/status-bar.ts`. Fixed relative imports in moved files (`./capture-store` → `../../capture-store`, `./server` → `../../server`). Updated import paths in `extension.ts` and `terminal-manager.ts`. Updated test file source-read paths in `lh-stack-regression.test.js` and `pty-lifecycle.test.js`. Created `extension/src/backends/vscode/vscode-backend.ts`: `VsCodeBackend implements TerminalBackend`, wraps TerminalManager + CaptureStore, owns execWaiters, exposes setStateChangeCallback/setContentChangeCallback for server.ts to wire. No behavior changes.
|
|
23
|
+
- **v0.8 P1 commit 1 — TerminalBackend interface + platform.ts + MockBackend** — Pure additions, no behavior change. `extension/src/terminal-backend.ts`: full `TerminalBackend` interface + all supporting types (`BackendCreateOptions`, `BackendTerminalInfo`, `BackendLogSlice`, `BackendSendOptions`, event types, `TerminalBackendFactory`, `BackendFactoryOptions`). `extension/src/platform.ts`: `NodePlatform` type alias (`'win32' | 'darwin' | 'linux'`), `isWindows`/`isMac`/`isLinux` predicates, `getProcessHelpers()` factory (darwin+linux branches using pgrep/ps; win32 throws P2 stub). `extension/test/fixtures/mock-backend.ts`: `MockBackend implements TerminalBackend` with in-memory state, EventEmitter-based events, and test helpers (`injectData`, `getSentTexts`). No existing file modified.
|
|
24
|
+
- **Pre-P1.1 gate** — cleared 7 pre-existing test failures (4 in `test:worker-fixes-v079` + 3 hidden by suite-abort) so `npm test` exits clean before v0.8 P1 (TerminalBackend extraction) begins. Fixes: `worker-fixes-v079` regexes updated to match current code (safeMission, detectCompletion, general -ef guard); `install.sh` uncommitted-work error message updated; `terminal-manager.test.js` updated for `close()` signature with `origin` param; `worker-boot-paste-collapse.test.js` extraction terminator updated (`_dswTick` → `_setupDetachWatcher`).
|
|
25
|
+
|
|
26
|
+
## [0.7.14] - 2026-05-12
|
|
27
|
+
|
|
28
|
+
### Internal
|
|
29
|
+
- **Pre-release polish** — `mcp_server.js` `initialize` response `serverInfo.version` bumped from stale `'0.7.10'` to `'0.7.14'` (W21 F5; eliminates spurious client-version-drift warnings). One-line stale comment in `extension/test/claws-ws-transport.test.js:242` updated from `orchestratorPresent` → `rootOrchestratorPresent` to match the assertion two lines below.
|
|
30
|
+
|
|
31
|
+
### Fixed (runtime)
|
|
32
|
+
- **Bug 14 — scope orchestrator singleton guard by waveId** — Wave LEAD sub-workers calling `claws_hello({role:'orchestrator', waveId:'...', subWorkerRole:'lead'})` were unconditionally rejected with `'orchestrator already registered'` because `hasOrchestrator()` scanned all peers globally without waveId scoping. Root cause: the flat single-session model made it impossible for a LEAD to register as orchestrator alongside the main session, blocking all privileged commands (`broadcast`, `task.assign`, `deliver-cmd`). Fix: replaced `hasOrchestrator()` with `hasRootOrchestrator()` which filters peers without a `waveId`; guard updated to `!r.waveId && hasRootOrchestrator()`. Error message updated to `'root orchestrator already registered'`. `mcp_server.js` `claws_hello` handler now forwards `waveId`/`subWorkerRole` to the server and returns `rootOrchestratorPresent` (renamed from `orchestratorPresent`). `claws_hello` schema in `gen-mcp-tools.mjs` adds `waveId`/`subWorkerRole` fields. All consumers (`mcp_server.js`, ws-transport test, pconn-identity mock) updated to new field name. 7 checks in `claws-v2-hello.test.js` including new waveId-scoped LEAD hello. Refs: `.local/plans/v0714/investigations/bug14-orchestrator-claim-race.md`.
|
|
33
|
+
- **Bug 15 — emit `system.terminal.<id>.alive` in heartbeat loop** — `stream-events.js --keep-alive-on <termId>` exited with code 2 ("no events for terminal X within 120000ms") even while the LEAD was visibly alive. Root cause: no periodic bus event was keyed by `terminal_id`. `vehicle.<id>.state/content` fire only on startup transitions; `system.heartbeat` carries no `terminal_id`; worker heartbeats (`WorkerHeartbeatV1`) have no `terminal_id` field. Fix: inside the extension's heartbeat timer body (`server.ts`), after existing `system.heartbeat` / `system.metrics` emissions, iterate `terminalManager.liveTerminalIds()` and emit `system.terminal.<id>.alive` with `{ terminal_id, ts }` for every live terminal. Fires every 60 s (heartbeat cadence); the 120 s stale threshold gives a 2× safety margin. `liveTerminalIds()` already existed on `TerminalManager` (added in LH-9). Zero changes to `stream-events.js` or `mcp_server.js`. Independently fixes both the Hello-failure cascade (Bug 14) and the latent gap for any correctly-helloed worker in a long quiet-computation phase (H15.A + H15.B). Regression test: `claws-terminal-alive.test.js` (7 checks) with a 200ms heartbeat interval for sub-second wall-clock time.
|
|
34
|
+
- **Bug 12 — residual race: retry on "orchestrator already registered"** — Sim pass 6 confirmed W30's Bug 12 fix correctly surfaces the hello failure but has no recovery: extension returns `{ok:false, error:'orchestrator already registered'}` when a concurrent `_pconnEnsureRegistered` caller reconnects before the old socket's FIN is processed, leaving the old peer in the extension's Map. No retry existed, so every subsequent L2 publish failed for the rest of the session. Deep fix: exponential-backoff retry in `_pconnEnsureRegistered` — up to 3 attempts (100ms → 200ms → 400ms delays) specifically on "already registered" errors. The delay gives the extension's event loop time to delete the stale peer. On exhaustion throws with retry count for diagnostics. Retry uses `_helloInFlight` dedup to prevent concurrent callers from sending multiple simultaneous hellos. 6 new unit checks in `pconn-identity.test.js`: positive (2 failures then success, `orchestratorHelloCount=3`) and negative (all fail, 12 total hello attempts, 0 publishes). Refs: `.local/plans/v0714/investigations/bug12-pconn-peer-loss.md` (Fix 4), `.local/audits/v0714-validation-report-pass6.md` (Bug 12 race section).
|
|
35
|
+
- **Bug 12 — _pconn socket-identity guard + ok-checks** — W26 investigation confirmed `_pconn` undergoes disconnect/reconnect cycles. Three intersecting defects masked the failures: (1) `_pconnEnsureRegistered` didn't verify hello succeeded, silently proceeding with `peerId=null` on `ok:false`; (2) no socket-identity guard — `_pconn.peerId` could belong to a closed socket while `_pconn.socket` pointed to a new one; (3) no ok-check at publish call sites, causing extension rejections to be logged as "publish-succeeded". Fix: `_pconn` gains `socketId` (incremented per connect) and `helloSocketId` (set on hello success). Guard in `_pconnEnsureRegistered` skips hello only when `peerId` is set AND `helloSocketId === socketId`; mismatch forces re-hello. `_pconnEnsureRegistered` now throws on `ok:false` instead of silent return. `_pconnWriteOrThrow` helper added; 28 call sites migrated. Unit tests in `extension/test/pconn-identity.test.js` (15 checks).
|
|
36
|
+
- **Bug 13 — split arm-intent from arm-execution (two-stage L2 state machine)** — W27 investigation confirmed the L2 30s timer races Claude's response composition latency. The timer measured from MCP tool invocation (server-side); the arm-execution signal arrived after Claude composed its next message and called `Monitor()`, which under load exceeds 30s. Deep fix: two-state machine in `PeerRegistry`. `pendingArms` set tracks corrIds whose intent is registered but `stream-events.js` hello has not yet completed. `monitors.register-intent` RPC is called at every spawn site in `mcp_server.js` immediately after corrId allocation. `recordMonitorClaim` now graduates corrId from `pendingArms` → `armedCorrelations`. `monitors.is-corr-armed` RPC is extended with `claimed` / `pending` fields (backward-compatible `armed` field preserved). L2 `setTimeout` at all 4 sites now distinguishes: no intent at 30s → true orphan, publish immediately; pending at 30s → arm in flight, re-check at +60s (90s total); claimed → silent. 5 new state-machine checks added to `monitor-corr-arm.test.js` (15 total).
|
|
37
|
+
- **Bug 11 — `claws_dispatch_subworker` `_dswCwd` undeclared + watcher consolidation** — `ReferenceError: _dswCwd is not defined` thrown inside the `setImmediate` boot block, silently caught by the surrounding `try/catch`, preventing Claude from launching in every dispatched sub-worker. Symptom: LEAD spawns sub-worker via `claws_dispatch_subworker`, terminal appears in `claws_list`, Claude never boots, terminal stays open forever, `claws_workers_wait` times out. Phase 1: add `const _dswCwd = …` before `setImmediate`. Phase 2 (structural): `_fpTick` (`claws_worker` fast-path) and `_dswTick` (`claws_dispatch_subworker`) were near-identical ~150-line watcher implementations that had drifted — BUG-26 was applied asymmetrically, `_dswCwd` (Bug 11) lived undetected for the same copy-paste reason. Extracted `_setupDetachWatcher` helper (HB L4/L5/L6, `detectCompletion`, pub scan, auto-close); applied at both sites. `tick` in `runBlockingWorker` (structurally different: no HB, dead `_msState` tracking, different timeout behavior) is left in place. Future BUG-26-class regressions in the LEAD/wave path are now structurally impossible. Root cause in `.local/plans/v0714/investigations/army-shell-autoclose.md` (Divergence 2).
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
- **Bug 12 PCONN/peer-registry debug instrumentation** — `PeerRegistry` gains `notifyRegister()` / `notifyUnregister()` methods that write structured JSON to `.claws/peer-registry-trace.log` on every peer lifecycle event. `ClawsServer` wires these at hello and `handleDisconnect`. `mcp_server.js` gains per-socket `_pconnSocketSeq` IDs and `PCONN-DEBUG:` log lines at every connect attempt, hello send/ack, write start/response, and reconnect cycle, plus a `write-failed-silently` log when `resp.ok === false`. Investigation-only; no logic changes.
|
|
41
|
+
- **Bug 13 arm-race observability** — `stream-events.js --wait` now logs a stderr line when the `monitorCorrelationId` hello is dispatched (`hello sent | corrId=… | t=…`). Permanent observability trace; no logic change. Enables comparing arm-dispatch time against the L2 30s window during future arm-race investigations. Root cause documented in `.local/plans/v0714/investigations/bug13-arm-race.md`.
|
|
42
|
+
|
|
43
|
+
### Fixed (runtime)
|
|
44
|
+
- **Bug 6 L1 — `unwrapMcpResponse` forward-compat normalizer** — PostToolUse hook silently exited at the `if (!resp.ok)` guard because `unwrapMcpResponse` didn't handle the bare-array `tool_response` shape Claude Code currently emits (`[{type:'text', text:'<JSON>'}]`). Affected root-session AND nested-TUI calls equally; unit tests passed because they used pre-unwrapped synthetic data. Rewrote as a proper forward-compat normalizer: handles three observed shapes (bare array, wrapped object, plain object) plus null/undefined. Unknown shapes return `null` AND emit a structured diagnostic to `/tmp/claws-hook-diag.log` so future format changes never silently break the hook. Caller updated to check for `null` return before checking `resp.ok`. Fixture-driven unit tests in `extension/test/unwrap-mcp-response.test.js` replay real captured stdin from `/tmp/claws-hook-stdin-*.json` (W15 forensic trace, pids 80621 + 81977). E2E validated: watcher log `/tmp/claws-monitor-arm-watch-<corrId>.log` created on first spawned worker after fix. Root cause documented in `.local/plans/v0714/investigations/bug6-hook-nested-context.md`.
|
|
45
|
+
|
|
46
|
+
## [0.7.14] - 2026-05-11
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
- **Layer 2 debug instrumentation** — `mcp_server.js` all 4 Layer 2 `setTimeout` callbacks now emit `L2-DEBUG:` lines at every decision branch (callback-entered, rpc-result, skip-publish, about-to-publish, pconn-registered, publish-succeeded/failed, outer-error). A new `_logL2File()` helper writes in parallel to `.claws/l2-debug.log` for file-based capture. Investigation-only; no logic changes. Covered sites: `runBlockingWorker`, `claws_create`, `claws_worker-fast-path`, `claws_dispatch_subworker`.
|
|
50
|
+
|
|
51
|
+
## [0.7.14] - 2026-05-08
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- **Bug 1** — `install.sh` now sweeps stale `claws-*.md` / `claws.md` command files from `$TARGET/.claude/commands` before copying. Prior installs accumulated every renamed/deleted command (PEDI had 27; installer ships 8). User-added commands (no `claws-` prefix) are untouched.
|
|
55
|
+
- **Bug 2** — `install.sh` now sweeps stale `claws-*` skill directories from `$TARGET/.claude/skills` before copying. Retired skill `claws-orchestration-engine` (renamed to `claws-prompt-templates` in v0.7.13) no longer lingers after upgrade.
|
|
56
|
+
- **Rules idempotence** — `claws-default-behavior.md` is now removed before re-copy so a stale version can never survive an upgrade.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- **`extension/test/install-sweep.test.sh`** (8 checks) — verifies command sweep, skill sweep, user-content preservation, and source markers; registered in `npm test` chain.
|
|
60
|
+
- **Bug 3 — cold-start preamble in entry-point slash commands** — models deliberated over plan mode / TodoWrite / pre-verification on first `/claws-do` invocation, stalling or falling back to Bash. MANDATORY ordered preamble added to all entry-point commands (`claws.md`, `claws-do.md`, `claws-fix.md`, `claws-help.md`, `claws-status.md`): acknowledge → skip plan mode → skip TodoWrite → trust sidecar → classify → spawn immediately → arm Monitor verbatim from `monitor_arm_command` → wait. Also covers Bug 6 Layer 0: Monitor arming imperative explicitly says "MUST be the very next tool call after spawn."
|
|
61
|
+
- **Bug 8 — fast-path BUG-26 analog for shell workers** — `_dispatchTool` (claws_worker, detach=true) was running the 15s TUI-specific submit-verification loop for shell workers (`launch_claude=false`), causing `_fpMarkerScanFrom` to land past the already-printed `__CLAWS_DONE__` marker; detach watcher scanned an empty slice forever and auto-close never fired. Applied the BUG-26 guard (present in `runBlockingWorker` since LH-15) to the fast-path: verification loop and post-mission offset snapshot are now wrapped in `if (launchClaude)`; shell workers keep `_fpMarkerScanFrom=0` so the watcher scans the full log.
|
|
62
|
+
- **Bug 4 — worker binary alias UX** — two new MCP tools (`claws_set_bin`, `claws_get_bin`) surface the existing `.claws/claude-bin` / `CLAWS_CLAUDE_BIN` plumbing. New `/claws-bin` slash command (set/reset/get). Natural-language imperative added to `CLAUDE.global.md` so "use claude-neu for workers" resolves automatically. Schema regenerated (39 → 41 tools). `install.sh` post-install banner now lists the three override mechanisms.
|
|
63
|
+
- **Bug 5 — Monitor in-process rearm** — `stream-events.js --wait` now supports `--keep-alive-on <termId>`. When the inner timer fires, a 3-check decision runs: (1) `system.worker.completed` in events.log → exit 0; (2) `system.terminal.closed` / `system.worker.terminated` in events.log → exit 0; (3) `eventsSeen(termId, staleMs)` — terminal active on bus within threshold → rearm in place. Otherwise exit 2 (truly stuck). New flags: `--stale-threshold <ms>` (default 120 s) and `--rearm-cycle <ms>` (default = `--timeout-ms`). All 5 `monitor_arm_command` emission sites in `mcp_server.js` updated: `--keep-alive-on` appended, `timeout_ms` raised from 600 000 → 7 200 000 (2 h). `extension/test/monitor-rearm.test.js` (6 unit branches) registered in `npm test` chain.
|
|
64
|
+
- **Bug 7 — `system.worker.terminated` identity fix** — `server.ts` now attaches `correlation_id` (already in scope from the `system.terminal.closed` lookup) to the `system.worker.terminated` payload when lifecycle state has it. `terminal_id` is a session-local integer VS Code recycles on extension reload; `correlation_id` is a UUID globally unique across sessions. `stream-events.js` rearmDecisionLoop Check 2 simultaneously drops its `terminal_id` fallback (`system.worker.terminated` matched by `termId`) and replaces it with corrId-only matching for both `system.terminal.closed` and `system.worker.terminated`, eliminating false-positive Monitor exits caused by prior-session log entries with the same numeric terminal ID.
|
|
65
|
+
- **Bug 9 — `claws-wave-lead/SKILL.md` instruction quality** — step 0 ("Arm Monitor on .claws/events.log via Bash run_in_background") replaced with a note that the sidecar is already running. Explicit Monitor()-only prohibition added (no Bash backgrounding for event observation). Sub-worker dispatch section expanded with a worked `Monitor(command=r.monitor_arm_command)` example. Obsolete BUG-03 capabilities comment removed from step 1 (auto-granted since v0.7.13).
|
|
66
|
+
- **Bug 6 Layer 1 — per-worker Monitor pgrep watcher** — `lifecycle.monitors[]` is pre-populated by `mcp_server.js` atomically at spawn time, so the PostToolUse hook's `monitors.some()` check is vacuously satisfied even when no OS-level `stream-events.js` process is arming. New `scripts/monitor-arm-watch.js` sleeps `grace_ms` (10 s default), runs `pgrep -f 'stream-events.js.*--wait <corrId>'`, and publishes `system.monitor.unarmed` to the bus if no match. `post-tool-use-claws.js` wired with `extractWorkerEntries()` + `spawnWatchers()` — spawns one detached watcher per worker for every spawn-class tool call (`claws_worker` / `claws_fleet` / `claws_dispatch_subworker` / `claws_create`); hook stays under 100 ms. Unit tests in `extension/test/monitor-arm-watch.test.js` (2 branches). Layer 2 (`hello`-with-`monitorCorrelationId`) closes the loophole structurally.
|
|
67
|
+
- **Bug 6 Layer 2 — `hello`-with-`monitorCorrelationId`** — closes the structural loophole where `lifecycle.monitors[]` pre-population makes per-worker Monitor verification vacuously satisfied. `stream-events.js --wait <corrId>` now includes `monitorCorrelationId: corrId` in its `hello` frame. Server (`peer-registry.ts`: new `PeerRegistry` class with `armedCorrelations Map<corrId,peerId>`; `server.ts`: `hello` handler records the claim, `handleDisconnect` removes it on peer close) tracks which corrIds have an active Monitor process. New `monitors.is-corr-armed` RPC (`{ correlation_id }` → `{ ok, armed, peerId }`) exposes the state. Spawn handlers (`claws_worker`, `runBlockingWorker`/fleet, `claws_dispatch_subworker`, `claws_create`) each fire a parallel 30 s grace `setTimeout` calling `monitors.is-corr-armed`; if the corrId is not claimed, logs a Layer-2-specific warning and publishes `system.monitor.unarmed` (same topic as Layer 1; consumers dedupe on `corrId`). `extension/test/monitor-corr-arm.test.js` (9 checks) covers claim, no-claim, disconnect-cleanup, RPC before/after hello, and error case.
|
|
68
|
+
|
|
69
|
+
### Internal
|
|
70
|
+
- **Bug 6 forensic trace** — `post-tool-use-claws.js` now appends a one-line entry to `/tmp/claws-hook-trace.log` at the very top (before any logic) and dumps the raw PostToolUse stdin to `/tmp/claws-hook-stdin-<pid>.json` at the top of `run()`. Both writes are in try/catch and never throw. Added as permanent observability to detect future `tool_response` format regressions; see `.local/plans/v0714/investigations/bug6-hook-nested-context.md`.
|
|
71
|
+
|
|
72
|
+
### Fixed (runtime)
|
|
73
|
+
- **Bug 6 Layer 1 — watcher subprocess publish reliability** — sim pass 3 (`.local/audits/v0714-validation-report-pass3-recovered.md`, Sim 4) found 0 `system.monitor.unarmed` events for real workers. Root cause: `.claude/settings.json` has a `hooks.PostToolUse` array (Bash dev-hooks), and Claude Code treats project settings as authoritative for hook types present there, overriding the global `~/.claude/settings.json` PostToolUse entries entirely. The `mcp__claws__claws_worker` (and sibling) matchers existed only in the global settings, so the PostToolUse hook process was never spawned and `monitor-arm-watch.js` was never launched. Fix: mirror the four claws MCP PostToolUse entries from global settings into `.claude/settings.json`. Also hardened `monitor-arm-watch.js` (absolute `/usr/bin/pgrep` path; startup + per-exit stderr lines with corrId/socket/cwd/reason — never exits silently) and `post-tool-use-claws.js` (watcher stdio redirected from `'ignore'` to per-corrId `/tmp/claws-monitor-arm-watch-<corrId>.log`; explicit `cwd=project-root` on spawn). Validated via manual E2E trigger: watcher log shows `exit 1 | reason=unarmed-published`; `system.monitor.unarmed` event appears in `events.log` for the real worker corrId.
|
|
74
|
+
- **Bug 6 Layer 1 — missing `.claws-bin/monitor-arm-watch.js` deploy** — `scripts/monitor-arm-watch.js` (added in commit 1849ee9) was never deployed to `.claws-bin/`. The `post-tool-use-claws.js` hook resolves the watcher path as `path.join(__dirname, '..', 'monitor-arm-watch.js')` → `.claws-bin/monitor-arm-watch.js`; the file did not exist → spawn silently failed → 0 Layer 1 events fired at runtime. Fix: created `.claws-bin/monitor-arm-watch.js` as a symlink to `../scripts/monitor-arm-watch.js`, mirroring the existing `mcp_server.js` / `stream-events.js` pattern. `install.sh` updated to create the same symlink (and `cp` equivalent for non-dev installs) on every fresh install.
|
|
75
|
+
- **Bug 6 enforcement runtime — Layer 1 + Layer 2 publish reliability** — sim pass 2 (`.local/audits/v0714-validation-report-pass2.md`) found both enforcement layers silently failing in live MCP fast-path context. Layer 1 (`post-tool-use-claws.js`): Claude Code passes MCP tool responses as `{ content: [{ type: 'text', text: '<JSON>' }] }`; the hook checked `resp.ok` directly on the wrapper (undefined), short-circuiting before spawning `monitor-arm-watch.js`. Fixed with `unwrapMcpResponse()` helper that parses the text content first. Layer 2 (`mcp_server.js`): the 30 s `setTimeout` callbacks called `_pconnWrite()` without `_pconnEnsureRegistered()` — if `_pconn` was not registered at fire time (e.g., after a 25 s Claude boot), the write threw and was silently swallowed. Fixed by adding `_pconnEnsureRegistered(sock)` before every Layer 2 `_pconnWrite` at all four sites (`claws_worker` fast-path, `runBlockingWorker`, `claws_create`, `claws_dispatch_subworker`). Silent `catch` replaced with logged `catch` at all sites. Smoke test: `extension/test/bug6-enforcement-runtime.test.js` (4 checks).
|
|
76
|
+
|
|
77
|
+
### Tests
|
|
78
|
+
- **Stale assertion alignment** — three pre-existing test assertions encoding old pre-v0.7.14 behavior updated: `monitor-rearm.test.js` (c) now injects `correlation_id` in the synthetic `system.worker.terminated` event (matching Bug 7 corrId-only Check 2 path); `lh-stack-regression.test.js` D8 updated from `timeout_ms=600000` → `7200000` with `--keep-alive-on` presence check (Bug 5 cascade); E4 rewritten to verify Option A (stream-events.js references `system.worker.terminated` and `system.terminal.closed`, both matched by corrId) instead of the rejected Option B. lh-stack: 51/51 PASS.
|
|
79
|
+
|
|
80
|
+
## [0.7.13] - 2026-05-05
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
- **`claws_done()`** (LH-18) — zero-arg MCP tool, primary worker-completion primitive. Reads `CLAWS_TERMINAL_ID` from worker env, publishes `system.worker.completed`, closes terminal. Mission preambles trimmed to single line.
|
|
84
|
+
- **LH-stack regression suite** (`lh-stack-regression.test.js`, 51 checks across 7 sections) — locks LH-9/10/11/12 + LH-18/18.1 invariants. No overlap with existing lifecycle-store (58), lh9-state-bulletproof (40), or stream-events-wait (8) suites.
|
|
85
|
+
- **LH-12 `--wait` mode** in `scripts/stream-events.js` — native `--wait <uuid>` replaces 5-layer awk/grep Monitor pipeline; direct `correlation_id` equality match, no regex, no shell quoting. Exit codes: 0 match, 1 connect failure, 2 socket close, 3 timeout.
|
|
86
|
+
- **LH-10 `correlation_id`** on `system.terminal.closed` + `monitors[]` reconcile-on-boot in lifecycle-store.
|
|
87
|
+
- **LH-9 bulletproof state management** — single-writer TTL watchdog (10 min idle / 4 h max), reconcile-on-boot, Stop-hook defang; `markActivity` + `findExpiredWorkers` + slot reuse for stale CLOSED entries.
|
|
88
|
+
- **LH-1 wave violation auto-close** — silent sub-workers auto-closed at 25s threshold via `wave_violation` close origin.
|
|
89
|
+
- **Phase 4a bus-based completion** — workers publish `worker.<id>.complete`; orchestrator subscribes via `_pconn` wildcard; pty marker remains fallback.
|
|
90
|
+
- **`claws_marketing/`** workshop folder + 6 AI-generated README images (fal.ai Nano Banana Pro, 2K 16:9): social-preview, before-after, install-flow, architecture, wrapped-terminal, claws-done-completion.
|
|
91
|
+
- **`scripts/test-template-enforcement.sh`** — 10-assertion CI test for CLAUDE.md injection chain (tool list, phases, idempotence, sentinel migration).
|
|
92
|
+
- **`scripts/dev-vsix-install.sh`** + `npm run install:vsix` — full VSIX reinstall for VS Code extension refresh (~25s); complements fast `deploy:dev` path.
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
- **LH-13 consolidation** — 27→8 commands, 6→3 skills; `claws_worker`/`claws_fleet`/`claws_dispatch_subworker` replace manual 7-step boot; 5 daily + 3 system command mental model.
|
|
96
|
+
- **LH-14 completion convention** — `__CLAWS_DONE__` canonical marker replaces per-worker variants; 5-layer F1–F5 convention; `claws_publish` elevated to PRIMARY in mission preambles.
|
|
97
|
+
- **LH-14.1 mode-aware `detach`** — mission-mode `claws_worker(mission=...)` → `detach:true`; command-mode `claws_worker(command=...)` → `detach:false`.
|
|
98
|
+
- **LH-11 silent Monitor template** — awk filter flipped to silent-until-pattern; one notification per worker at terminal state; `system.worker.terminated` added to alternation.
|
|
99
|
+
- **Worker boot detection** — `❯` + `cost:$` stable for 3 polls replaces legacy `bypass permissions` string match (v0.7.9).
|
|
100
|
+
- **CLAUDE.md injection** now parametric: tool list from `mcp_server.js` dispatch handlers, phases from `lifecycle-store.ts`, version from `package.json`; versioned sentinels for clean cross-version upgrades.
|
|
101
|
+
- **Templates** (`CLAUDE.global.md`, `CLAUDE.project.md`) rewritten new-user-first with `claws_done()` primary, per-worker Monitor pattern, full 11-phase lifecycle.
|
|
102
|
+
- **Extension README** rewritten marketplace-focused (137 lines from 295); **Root README** refreshed with 39-tool grouped table, Wave Army section, behavioral injection enforcement section.
|
|
103
|
+
- **Extension `package.json`** v0.7.13, categories `[Other,AI,Machine Learning]`, +keywords `mcp`/`wave-army`/`workers`, galleryBanner `#111318`, `screenshots[]` added.
|
|
104
|
+
- **Skill rename** `claws-orchestration-engine` → `claws-prompt-templates` in cli.js + 4 doc files; F3 updated from `claws_publish(...)` to `claws_done()` across all mission templates.
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
- **LH-18.1** — `claws_done()` publish path: replaced broken `clawsRpcStateful` with `_pconnEnsureRegistered` + `_pconnWrite` (`protocol: claws/2`); `system.worker.completed` now lands on bus with `completion_signal:'claws_done'`.
|
|
108
|
+
- **LH-15** — shell-worker marker: regex tolerates zsh `\` line-wrap artifact; server-side auto-wrap adds `[CLAWS_PUB]` bus event + `__CLAWS_DONE__` marker after every `claws_worker(command=...)`.
|
|
109
|
+
- **LH-11.1** — awk `\\.` → `[.]` fix; LH-11 silent Monitors were matching nothing due to regex literal misparse across all 5 spawn sites.
|
|
110
|
+
- **LH-3** — `claws_dispatch_subworker` paste-collapse submit parity with `runBlockingWorker` (signal-based predicates, 15s deadline, 5-nudge retry).
|
|
111
|
+
- **Worker boot paste-collapse** (latent v0.7.11 bug, 9fd97ac) — submit verification polls buffer growth or placeholder removal rather than byte-count comparison.
|
|
112
|
+
- **T9** — FAILED lifecycle phase now recoverable: `plan()` from FAILED resets arrays, increments `mission_n`, preserves `failure_cause`.
|
|
113
|
+
- **T8** — `claws_workers_wait` checks all 4 completion signals (marker, error_marker, pub_complete, terminated); adds `min_complete` parameter and per-worker `signal` field.
|
|
114
|
+
- **`uninstall-cleanup.ts`** skill array expanded: `claws-wave-lead` + `claws-wave-subworker` added; `claws-orchestration-engine` retained for backward-compat cleanup.
|
|
115
|
+
- **install.sh** `EXPECTED_MIN_VERSION` + **fix.sh** `EXT_VERSION` fallbacks bumped to 0.7.13.
|
|
116
|
+
|
|
117
|
+
## [0.7.12] - 2026-05-03 — Install UX hardening + heartbeat parser foundation
|
|
118
|
+
|
|
119
|
+
### In Progress (heartbeat v0.7.12)
|
|
120
|
+
|
|
121
|
+
- HB-L1 (in progress for v0.7.12): heartbeat parser primitives added — pure functions in mcp_server.js for TUI state detection. No runtime change yet; foundation for state machine in HB-L3+. Functions: parseToolIndicators, parseCostFooter, parseSpinnerActivity, parsePromptIdle, parseTodoWrite, parseErrorIndicators. Anchor: docs/heartbeat-architecture.md §V.E.
|
|
122
|
+
- HB-L2 (in progress for v0.7.12): WorkerHeartbeatV1 extended with optional kind/summary/cost/etc fields. Backward-compat additive. No runtime change yet.
|
|
123
|
+
- HB-L3 (in progress for v0.7.12): WorkerHeartbeatStateMachine class added to mcp_server.js. Tracks BOOTING/READY/WORKING/POST_WORK/COMPLETE transitions from pty observation. Not yet wired (L4 next).
|
|
124
|
+
- HB-L4 fix: heartbeat wiring moved from runBlockingWorker → fast-path watcher (the default for claws_worker). L4 verification now works. Reload VS Code + /mcp + spawn a claws_worker to see kind=heartbeat events every 30s.
|
|
125
|
+
- HB-L4 polish: dropped cost_usd from heartbeat (was bogus — showed orchestrator's overall session cost ~$2376, not per-worker cost). Tokens (in/out) remain. Fixed BOOTING→READY transition to fire on bypass-permissions detection alone (was waiting for prompt-idle which never happens during active work).
|
|
126
|
+
- HB-L4 cascade fix: READY→WORKING now uses cumulative toolCount (idempotent across ticks), no longer stuck at READY when boot+tool land in the same observe() tick.
|
|
127
|
+
- FIX-MON: canonical monitor pattern streams heartbeats + auto-exits on completion — orchestrator's `monitor_arm_command` now subscribes to `worker.<termId>.heartbeat,system.worker.*` and uses `awk '{print; fflush()} /system\.worker\.completed/{exit}'` instead of a completion-only `grep -m1`. Eliminates the blind window between spawn and completion; single awk wrapper emits each heartbeat line immediately AND exits cleanly on completion via SIGPIPE cascade. Five sites updated; new test: `extension/test/monitor-pattern.test.js`.
|
|
128
|
+
- FIX-MON-V2: monitor pattern v2 — switched CLAWS_TOPIC from comma-separated `worker.<id>.heartbeat,system.worker.*` to `'**'` wildcard. `scripts/stream-events.js:43` reads CLAWS_TOPIC as one literal string and passes it directly to the server's subscribe call; the comma-separated form was treated as a single invalid topic name, silently dropping all heartbeat notifications. Fix: subscribe to `'**'` (everything) and let the existing `grep --line-buffered correlation_id` filter narrow to the target worker. Verified live. Test: `extension/test/monitor-pattern.test.js` updated to 4/4 assertions.
|
|
129
|
+
- FIX-CLOSE-CALLBACK: `TerminalManager.close()` now invokes the close callback synchronously before deleting from the `byTerminal` map. Root cause of the lifecycle silent-mutation bug (audit 6e68a76): `close()` called `terminal.dispose()` then immediately deleted the `byTerminal` entry; VS Code's async `onDidCloseTerminal` fired after the entry was gone, so `onTerminalClosed()` bailed at its early-return guard and `system.worker.terminated` was never emitted. Every programmatic close (claws_close, fast-path watcher) was silently skipping the bus event. Monitors waiting on `system.worker.completed/terminated` hung indefinitely. Fix: call `this.onTerminalClose?.(key, rec.wrapped)` BEFORE `dispose()` and `byTerminal.delete()`. The existing `if (!id) return` guard in `onTerminalClosed()` is now idempotent — it means "already cleaned up". Test: `extension/test/terminal-manager.test.js` (4 checks).
|
|
130
|
+
- FIX-PARSER: `parseToolIndicators` regex `\s+` → `\s*` — Claude TUI renders `⏺Bash(args)` with zero whitespace between `⏺` and the tool name (hex: `e2 8f ba 42 61 73 68`). The `\s+` requirement caused 0/124 ticker matches in real pty samples; `this.toolCount` stayed at 0 forever; state machine never transitioned READY→WORKING. Fix is backward-compatible: `\s*` still accepts the documented `⏺ Bash(args)` form. Verified against 62KB captured pty fixture. Test: `extension/test/parse-tool-indicators.test.js` (5 checks, audit 6c1bd43).
|
|
131
|
+
- HB-L7: POST_WORK detection now publishes `kind=mission_complete` heartbeats. When the state machine fires POST_WORK→COMPLETE (spinner gone + prompt idle + bytes idle ≥20s), the fast-path watcher emits a one-shot heartbeat with `kind=mission_complete`, rich summary (`Xm Ys · N tool calls`), duration_ms, total_tool_calls, and tokens. Guard `_fpMissionCompletePublished` prevents double-fire. Test: `extension/test/mission-complete-heartbeat.test.js` (9 checks).
|
|
132
|
+
- HB-L8 (BIG FIX): when state machine detects sustained TUI idle (POST_WORK→COMPLETE), watcher now publishes `system.worker.completed` with `completion_signal:"tui_idle"`, clears interval, marks lifecycle completed, and auto-closes the terminal (per `close_on_complete: true`, default). Solves M15 marker-skip pattern: Claude finishes work + reaches `❯` prompt without running F3 printf → previously hung until 180s timeout, now completes in ~25-30s. Guard `_fpTuiIdleCompleted` gates `detectCompletion` path to prevent double-publish. Existing completion paths (marker, error_marker, pub_complete, Wave D terminated) remain primary. Test: `extension/test/tui-idle-completion.test.js` (8 checks).
|
|
133
|
+
- v0.7.12 prompt-idle fix: `parsePromptIdle` now scans the last 10 lines for the `❯` prompt instead of just the last non-empty line. Required for L7/L8 to actually fire — Claude TUI renders the prompt above the bypass-permissions footer, not as the last line. Test: `extension/test/parse-prompt-idle.test.js` (4 checks).
|
|
134
|
+
- v0.7.12 prompt-idle v2: `parsePromptIdle` now detects the `"⏵⏵ bypass permissions on"` footer instead of the `❯` char. ANSI strip collapses the `❯` prompt onto a multi-component single line (box-drawing border + ❯ + border), defeating the previous regex even with 10-line scan. Scans last 30 lines for the bypass-permissions substring — plain text that survives strip cleanly. Test: `parse-prompt-idle.test.js` rewritten with 4 cases (real TUI layout, working state, empty, stale-history).
|
|
135
|
+
- v0.7.12 post-work gate fix: dropped `bytesIdle` requirement from WORKING→POST_WORK transition. Claude Code's prompt suggestion feature emits pty bytes when idle, blocking the previous `bytesIdle` gate. Now: spinner-stopped + prompt-visible is sufficient. Test: new `WORKING→POST_WORK fires even with recent pty bytes` check in `heartbeat-state-machine.test.js`.
|
|
136
|
+
- HB-L5: kind=progress heartbeats with 5s burst aggregation. Fast-path watcher publishes activity bursts in real-time, collapsed to one summary per window. Richer orchestrator visibility between 30s backstop ticks.
|
|
137
|
+
- HB-L6: kind=approach + kind=error heartbeats. Fast-path watcher publishes TodoWrite plans (deduped by JSON.stringify compare) and Bash errors (deduped by errorsCount). Richer orchestrator observability.
|
|
138
|
+
- v0.7.12 hotfix: DISARMED L8 tui_idle auto-close. Destructive false-positives killed long-thinking workers (audit, deep edits). L7 mission_complete heartbeat publish stays for observability. Marker/error_marker/timeout/Wave-D paths unchanged.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Fixed
|
|
143
|
+
|
|
144
|
+
#### Fix #1 (P0): ESM project crash — `mcp_server.js` fails to start in projects with `"type":"module"`
|
|
145
|
+
- **Impact**: ~50% of modern Node projects (Next.js, Vite, ESM-default tooling) hit `ReferenceError: require is not defined in ES module scope` on MCP server startup. Install appeared to succeed but Claws never functioned.
|
|
146
|
+
- **Root cause**: Node inherits `"type":"module"` from the nearest parent `package.json`. `.claws-bin/` had no own `package.json`, so `mcp_server.js` (CommonJS) was loaded as ESM.
|
|
147
|
+
- **Fix**: `scripts/install.sh` now writes `<project>/.claws-bin/package.json` with `{"type":"commonjs"}` to scope the override to `.claws-bin/` only. User's project files are unaffected. `update.sh` and `fix.sh` auto-restore the file so existing installs without it get fixed automatically.
|
|
148
|
+
|
|
149
|
+
#### Fix #2 (P1): dev-hooks leak into every user project — SessionStart hook spam
|
|
150
|
+
- **Impact**: every Claude Code session in a user project fired `SessionStart:startup hook error` for contributor diagnostic scripts (`check-stale-main.js`, `check-tag-pushed.js`, etc.) that have no relevance outside a Claws contributor environment.
|
|
151
|
+
- **Root cause**: `scripts/install.sh` unconditionally copied `scripts/dev-hooks/*.js` and registered them in `<project>/.claude/settings.json` for every install.
|
|
152
|
+
- **Fix**: dev-hooks install is now gated behind `CLAWS_INSTALL_DEV_HOOKS=1` env var. Default install path skips them entirely. Contributors installing into the Claws source tree (`scripts/install.sh` + `extension/src/` detected) get dev-hooks automatically without the flag.
|
|
153
|
+
|
|
154
|
+
#### Fix #3 (P1): `monitor_arm_command` pointed at wrong `stream-events.js` path in user installs
|
|
155
|
+
- **Impact**: orchestrators received a `monitor_arm_command` referencing `<project>/scripts/stream-events.js`, which doesn't exist in user installs (the file is at `<project>/.claws-bin/stream-events.js`). Per-worker Monitor commands failed immediately, forcing fallback to deprecated `tail -F events.log` (anti-pattern A1).
|
|
156
|
+
- **Root cause**: 5 occurrences in `mcp_server.js` computed the path from the socket location (`path.dirname(path.resolve(sock))`) instead of from `__dirname`, producing the wrong result outside the dev source tree.
|
|
157
|
+
- **Fix**: extracted a `STREAM_EVENTS_JS` constant at module load time using a multi-candidate resolver anchored to `__dirname` (same logic as the existing `_ensureSidecarOrThrow` resolver). All 5 `monitor_arm_command` generators now use it.
|
|
158
|
+
|
|
159
|
+
#### Fix #5 (P2): `uninstall.sh` — clarify that `code --uninstall-extension` is machine-wide
|
|
160
|
+
- **Impact**: users running `uninstall.sh` from one project folder followed the printed `code --uninstall-extension neunaha.claws` instruction, not realising it removes Claws from their editor globally — breaking Claws in any other project they had it installed in.
|
|
161
|
+
- **Fix**: added two-line warning above the printed command explaining the machine-wide scope and advising against running it if Claws is active in other projects.
|
|
162
|
+
|
|
163
|
+
### Deferred
|
|
164
|
+
- **Bug #4** (shell-mode `claws_worker` command-path pipe-mode anomaly) deferred to v0.7.13 — fix scope unknown, needs investigation.
|
|
165
|
+
|
|
166
|
+
## [0.7.11] - 2026-05-03 — Install Just Works™ (UX-first install)
|
|
167
|
+
|
|
168
|
+
### Changed
|
|
169
|
+
- **`scripts/install.sh`: removed the v0.7.9 dirty-tree guard from default install path.** `~/.claws-src` is install.sh's working directory — not a user dev clone — and treating it as protected was wrong UX. The script now hard-resets `~/.claws-src` to `origin/main` on every run, so install.sh just works in any folder for any user (new install or upgrading from v0.7.9/v0.7.10) with no manual stash/force-reset/CLAWS_FORCE_RESET dance.
|
|
170
|
+
- **Contributor escape hatch unchanged**: contributors who want a protected dev clone use `CLAWS_DIR=/path/to/dev/claws bash <(curl ...)` to point install at a different working dir. The default `~/.claws-src` is now treated as throwaway by design.
|
|
171
|
+
- **Opt-in protection**: `CLAWS_DEV_PROTECT=1 bash <(curl ...)` re-enables the old v0.7.9 dirty-tree guard for the rare case someone wants safety on the default `~/.claws-src` path. Most users should use `CLAWS_DIR=` instead.
|
|
172
|
+
- **Net effect for users**: zero friction. Run `bash <(curl -fsSL https://raw.githubusercontent.com/neunaha/claws/main/scripts/install.sh)` in any folder, get Claws.
|
|
173
|
+
|
|
174
|
+
### Why this changed
|
|
175
|
+
v0.7.9 added a guard meant to protect contributors from accidentally losing in-flight work via `git reset --hard`. But the guard fired on auto-generated tracked files (e.g., `extension/native/.metadata.json` bundledAt timestamp), blocking every user's second install. v0.7.10's hotfix gitignored the metadata file, but existing v0.7.9 users still hit the guard during upgrade because their old `~/.claws-src` was at v0.7.9 commit (pre-gitignore). v0.7.11 removes the guard entirely — the architectural insight is that install.sh OWNS its working directory and should hard-reset freely.
|
|
176
|
+
|
|
177
|
+
## [0.7.10] - 2026-05-03 — 10-phase lifecycle (Wave A+B+C+D) + auto-advance engine + event-driven completion
|
|
178
|
+
|
|
179
|
+
### Fixed (post-release hotfix, force-tagged)
|
|
180
|
+
- **Install blocker**: `extension/native/.metadata.json` was tracked in git but rewritten with a fresh `bundledAt` timestamp on every native rebuild. Every user's second install hit the P3 hygiene guard ("uncommitted changes — refusing to git reset --hard"). Now gitignored and untracked. `git rm --cached` removes it from the index; existing installs that pull this fix will silently drop the tracked copy. Per ARCHITECTURE.md P4 (build artifacts shouldn't be tracked).
|
|
181
|
+
|
|
182
|
+
### Added
|
|
183
|
+
- **`docs/ARCHITECTURE.md`** (NEW): comprehensive canonical architecture anchor — 10 principles, system map (extension ↔ MCP server ↔ lifecycle engine), anti-patterns catalog (A1–A5), known-gaps roadmap §IX. Commit d831820. All architectural changes must pass §X anchoring protocol before landing.
|
|
184
|
+
- **Wave C closure — PostToolUse hook fail-closes spawn → monitor race** (`scripts/hooks/post-tool-use-claws.js`, NEW): after every spawn-class MCP tool call returns, waits up to ~5 s for `lifecycle.monitors[terminal_id]` to be registered. If missing, publishes `wave.violation` event (kind=monitor-missing) and auto-closes the orphaned terminal with a stderr warning. `inject-settings-hooks.js` registers four explicit PostToolUse matchers (claws_create/worker/fleet/dispatch_subworker), tagged `_source:'claws'`, dual-form canonical+fallback. Closes the spawn → monitor race window flagged in ARCHITECTURE.md §VI. New `extension/test/post-tool-use-monitor-gate.test.js` (15 checks): no-socket bail, non-spawn-class no-op, no-terminal-id no-op, monitor registered → pass, monitor missing → violate+close, 5 s self-kill.
|
|
185
|
+
- **Task #58 — multi-signal completion detection in detach watchers.** Adds three backup signals beyond the printf marker: explicit `[CLAWS_PUB] topic=worker.<id>.complete` line, idle-timeout (no pty activity for `idle_timeout_ms` after `min_runtime_ms` warm-up), and existing error-marker remains. ANY signal fires → publish system.worker.completed → auto-close → mark-worker-status('closed') → engine cascade. Payload now includes `completion_signal`. Defaults: idle_timeout_ms=30000, min_runtime_ms=30000.
|
|
186
|
+
- **Wave D — LifecycleEngine** (`extension/src/lifecycle-engine.ts`, NEW): in-process auto-advance state machine. Wired into the three lifecycle mutation handlers (`register-spawn`, `register-monitor`, `mark-worker-status`). On each worker state change, calls `nextAutoPhase()` from `lifecycle-rules.ts`; if a transition is recommended and passes `canTransition` + gate checks, calls `store.setPhase(next)` and emits `lifecycle.phase-changed` on the bus. Cascades safely (safety loop of 10) for multi-step transitions (DEPLOY→OBSERVE→HARVEST in a single call). Eliminates orchestrator camping in SPAWN — phases self-progress as work happens.
|
|
187
|
+
- **Lifecycle schema v3** (`extension/src/lifecycle-store.ts`): SESSION-BOOT through SESSION-END phases (10), `worker_mode` (single|fleet|army), `expected_workers`, `spawned_workers` map, `monitors` map, `registerSpawn`/`registerMonitor`/`markWorkerStatus` methods.
|
|
188
|
+
- **`extension/src/lifecycle-rules.ts`** (NEW): pure validators for transitions, gates, auto-advance decisions.
|
|
189
|
+
- **New lifecycle commands**: `lifecycle.register-spawn`, `lifecycle.register-monitor`, `lifecycle.mark-worker-status`.
|
|
190
|
+
- **D+F integration (Wave A — all spawn-class tools)**: `claws_create`, `claws_worker` fast-path, `runBlockingWorker` (+ `claws_fleet` which routes through it), and `claws_dispatch_subworker` all generate `correlation_id` + atomically call `lifecycle.register-spawn` + `lifecycle.register-monitor`. All detach watchers include `correlation_id` in `system.worker.spawned` / `system.worker.completed` event payloads and call `lifecycle.mark-worker-status` on every terminal transition (completed / failed / timeout). `lifecycle.spawned_workers` + `lifecycle.monitors` maps now populate for every worker regardless of which spawn-class tool was used.
|
|
191
|
+
- feat(v0.7.10) — Wave D part 1: extension now publishes `system.worker.terminated` on `onDidCloseTerminal` for any Claws-tracked wrapped terminal. `TerminalManager.setTerminalCloseCallback` wired from `ClawsServer` constructor; fires only for `wrapped=true` terminals. New test `test:ondidclose-publish` (8 checks) verifies publish + payload + unwrapped suppression. Per ARCHITECTURE.md P1 + Wave D roadmap. Adds `'terminated'` to `WorkerStatus` type + `TERMINAL_WORKER_STATUSES` set.
|
|
192
|
+
- feat(v0.7.10) — Wave D part 2: detach watchers in `mcp_server.js` recognize `system.worker.terminated` as 4th completion signal (alongside marker/error/pub_complete). `detectCompletion` extended with `terminatedSet` param; `_pconn` subscribes to `system.worker.terminated` on first registration; `_workerTerminatedSet` updated on every push frame. When worker's terminal closes, watcher fires `system.worker.completed` with `completion_signal:'terminated'` without waiting for marker. Closes the M15 marker-skip gap (`.local/audits/m15-marker-skip-gap.md`). `multisignal-completion.test.js` extended with 3 `terminated` cases. Also fixes pre-existing bug: detach-watcher `detectCompletion` callsite was passing `_msState` object as `termId` arg, breaking `pub_complete` signal in that path; corrected to `String(termId)`.
|
|
193
|
+
- docs(v0.7.10) — `templates/CLAUDE.global.md`: codified F1/F2/F3 numbered-final-actions worker convention (per `.local/audits/m15-marker-skip-gap.md`). Reduces marker-skip rate by framing final Bash calls as a numbered checklist with rationale.
|
|
194
|
+
- scripts(v0.7.10) — `scripts/install.sh`: dev-mode symlinks, `scripts/uninstall.sh` (NEW), Linux ABI support for bundled node-pty, install backup pruning (keeps last 3 only).
|
|
195
|
+
- 60 unit tests covering lifecycle-store + lifecycle-rules.
|
|
196
|
+
|
|
197
|
+
### Changed
|
|
198
|
+
- **Wave B — bus-stream Monitor primitive in all spawn-class tool responses**: `monitor_arm_command` strings returned by `claws_create`, `claws_worker`, `runBlockingWorker`/`claws_fleet`, and `claws_dispatch_subworker` now use the canonical `Monitor + stream-events.js` pattern (CLAUDE.md principle #5). Subscribes directly to the pub/sub bus, filters by `correlation_id`, exits on first `system.worker.completed` event (`grep -m1`). Sub-100ms latency, immune to SIGURG idle-kill, appears as 'monitor' in the Claude Code task panel. The old `Bash(until grep -qE…events.log)` passive polling pattern is fully removed.
|
|
199
|
+
- **Wave C enforcement** (`pre-tool-use-claws.js`, `session-start-claws.js`): SessionStart now auto-spawns the `stream-events.js` sidecar on boot; PreToolUse Monitor arm gate hard-blocks spawn-class tools until a Monitor is armed; both hooks recognize the canonical bus-stream sidecar pattern and no longer demand the deprecated `tail -F` satisfier.
|
|
200
|
+
- templates (`templates/CLAUDE.project.md`, `templates/CLAUDE.global.md`): updated Monitor arm command, peerId heartbeat interval, and sidecar boot instructions to match canonical Wave B/C pattern.
|
|
201
|
+
- `.claude/commands/` + `.claude/skills/`: all 24 slash commands and orchestration-engine skill aligned with non-blocking defaults and canonical `monitor_arm_command` shape.
|
|
202
|
+
- `claws_lifecycle_plan` now requires `worker_mode` + `expected_workers` args (declares mission shape upfront).
|
|
203
|
+
|
|
204
|
+
### Fixed
|
|
205
|
+
- **CRITICAL: claws_worker fast-path boot detection.** The default `detach:true` code path had only `sleep(400)` before sending mission paste — too short for Claude TUI to boot. Multi-line missions landed in shell prompt before Claude was ready, sat in input box without ever submitting. Now polls for `❯` + `cost:$` stable for 3 polls, then waits 5000ms post-readiness settle. Mirrors `runBlockingWorker` pattern. Verified end-to-end with real Claude worker test.
|
|
206
|
+
- fix(v0.7.10) — Wave C SIGURG resolution (Task #63): `pre-tool-use-claws.js` now accepts the canonical `stream-events.js` sidecar (auto-spawned by SessionStart) as a valid Monitor satisfier. Eliminates the recurring "Hook satisfier failed exit 144" task notifications. Old `tail -F` check kept as deprecated fallback for one release. Per ARCHITECTURE.md P9 + anti-pattern A1. New regression test: `test:pre-tool-use-sidecar-recognized` (7 assertions).
|
|
207
|
+
- **BUG-A** — `nextAutoPhase` had cases for SPAWN, DEPLOY, OBSERVE, CLEANUP but missing HARVEST. Engine cascaded 4 transitions then stopped. Now adds HARVEST→CLEANUP transition (gated by `canCleanup`), enabling 5-transition auto-cascade through the mission cycle.
|
|
208
|
+
- **BUG-B** — Detach watchers in `mcp_server.js` (4 callsites: runBlockingWorker, blocking-worker happy-path, fast-path watcher, dispatch_subworker) auto-closed terminals on marker match but never notified the lifecycle store of closure. `workers[].closed` stayed false, blocking `canReflect` gate forever. Fix: after successful close, call `lifecycle.mark-worker-status` with `status='closed'` so the lifecycle store flips the flag. Now CLEANUP→REFLECT can auto-advance once all spawns are closed.
|
|
209
|
+
- **M20 install.sh calibration** — step 8 verification now checks PostToolUse spawn-class hooks in addition to PreToolUse, so a partial Wave C install is surfaced at install time instead of silently running without the monitor race-close gate.
|
|
210
|
+
- **M20 update.sh calibration** — post-update health check extended with PostToolUse spawn-class hook presence check; warns with auto-fix command if Wave C entries are absent.
|
|
211
|
+
- **M20 fix.sh calibration** — check 8b detects and auto-repairs missing PostToolUse entries (pre-Wave C installs); check 9 hook probe now covers `post-tool-use-claws.js` alongside session-start/pre-tool-use/stop.
|
|
212
|
+
|
|
213
|
+
## [0.7.10-pre] - 2026-05-01 — Direct-prompt missions (revert v0.7.9 file-referrer + boot retry)
|
|
214
|
+
|
|
215
|
+
v0.7.10 deletes the two new abstractions v0.7.9 introduced (file-referrer mission delivery and boot retry) and returns to the v0.7.4 contract: **the mission text becomes Claude Code's input as if a human typed it.** No /tmp file. No "Read /tmp/.../mission.md and follow it precisely." prompt. The v0.7.9 marker false-match is still fixed, but via a much simpler mechanism: capture the pty scan offset *after* the payload + echo settle, so the user's mission text never re-matches the completion marker.
|
|
216
|
+
|
|
217
|
+
### Fixed — claws_fleet sharedDefaults undefined-key bug
|
|
218
|
+
|
|
219
|
+
The first claws_fleet implementation wrote `sharedDefaults = { cwd: args.cwd, model: args.model, ... }` unconditionally — when the caller omitted any of those keys, the spread `{ ...sharedDefaults, ...w }` propagated `undefined` values into `runBlockingWorker`. Inside, `{ ...DEFAULTS, ...args }` let the undefined clobber the model default, producing a launch line of `claude --dangerously-skip-permissions --model undefined` that broke the spawn and left workers hanging at `pid=-1`. Fix: build `sharedDefaults` by INCLUDING ONLY keys the caller actually set. Same defensive filter for per-worker overrides via `wClean`. Regression test added.
|
|
220
|
+
|
|
221
|
+
### Removed (rolled back from v0.7.9)
|
|
222
|
+
|
|
223
|
+
- **File-referrer pattern.** No mission file in `/tmp`. No `runToken`. No `fileNonce`. No `mission_file` / `run_token` worker return-value fields. Mission goes directly to Claude Code's input prompt.
|
|
224
|
+
- **Boot retry** (`boot_retries`). Sending the launch command a second time was harmful — it typed `claude ...` into an already-booted Claude Code TUI as a user prompt, which the user saw as a confusing "second claude command". Now: single launch attempt, proceed best-effort if `boot_marker` isn't seen within `boot_wait_ms`.
|
|
225
|
+
|
|
226
|
+
### Kept (the only correctness fix that survived from v0.7.9)
|
|
227
|
+
|
|
228
|
+
- **Marker scan offset** — `markerScanFrom` is captured **after** the payload is sent and the echo lands (400ms sleep), so the poll loop only scans bytes produced by Claude *after* the mission was submitted. The user's mission text (now echoed in the pty log) cannot false-match the completion marker.
|
|
229
|
+
- **`boot_marker` default** — `'bypass permissions'` (matches the Claude Code v2.x bypass-mode footer; legacy `'Claude Code'` never matched the ANSI-stripped banner).
|
|
230
|
+
- **`scripts/install.sh` skill-loop self-collision guard** — `-ef` (same-inode) test prevents the loop from `rm`-ing the source when `TARGET == INSTALL_DIR` on dev machines.
|
|
231
|
+
- **`scripts/install.sh` uncommitted-work guard** — Step 1's `git reset --hard origin/main` refuses to run on a dirty tree unless `CLAWS_FORCE_RESET=1` is set, so contributor edits are no longer silently destroyed.
|
|
232
|
+
|
|
233
|
+
### Added — claws_fleet detach mode + claws_workers_wait
|
|
234
|
+
|
|
235
|
+
`claws_fleet` now accepts `detach=true`, which returns immediately after spawning each worker terminal (no marker poll) — the default blocking behavior is completely unchanged. Detached fleets are meant to be observed by a follow-up call to the new `claws_workers_wait` tool, which polls an array of terminal ids until each emits its `complete_marker` or `error_marker` (or times out). The two together enable a fire-and-monitor pattern where the orchestrator can do other work between spawning and harvesting. `claws_fleet` also migrated internally from `Promise.all` to `Promise.allSettled` so a single failed worker no longer aborts the entire fleet — each result is individually wrapped and the summary always covers all N workers. Tool count grows 37 → 38.
|
|
236
|
+
|
|
237
|
+
### Added — `claws_fleet` (real parallel orchestration)
|
|
238
|
+
|
|
239
|
+
`claws_fleet({ workers: [{name, mission, …}] })` is the new MCP tool for true parallel worker fan-out. Internally calls `runBlockingWorker` for each entry inside `Promise.all`, so all workers spawn and run concurrently within a **single MCP tool/call**. This bypasses Claude Code's MCP client-side serialization (which awaits each tool/call response before sending the next) — calling `claws_worker` N times from one assistant message still serializes, but `claws_fleet` returns one consolidated result with `wall_clock_ms`, `max_individual_ms`, `sum_individual_ms`, and per-worker results. Tool count grows 36 → 37.
|
|
240
|
+
|
|
241
|
+
### Fixed — bulletproof marker scan offset
|
|
242
|
+
|
|
243
|
+
`runBlockingWorker`'s `markerScanFrom` capture replaced the timing-fragile 400ms fixed sleep with a **poll-for-settle loop** (up to 5s): waits until either the pty buffer grows by 200+ bytes past pre-send length OR a TUI indicator appears (`Pasted text`, `tokens`, `thinking`, `Synthesizing`, `Combobulating`, `Brewed`, etc.), then captures the offset. Eliminates the false-completion that hit `para-auditor` in the v0.7.10 parallel test, where Claude Code v2.x delayed the input echo past the 400ms window and the marker substring in the mission body false-matched on echo.
|
|
244
|
+
|
|
245
|
+
### Added — `docs/mcp-tools-guide.md` (calibration matrix)
|
|
246
|
+
|
|
247
|
+
Comprehensive when-to-use-which guide for all 37 MCP tools. TL;DR decision matrix, mission-style cookbook (single / fleet / wave army), lifecycle gates table, anti-patterns, and the concurrent-dispatch caveats explaining why `claws_fleet` exists.
|
|
248
|
+
|
|
249
|
+
### Fixed — MCP main-loop concurrent dispatch (the critical fan-out fix)
|
|
250
|
+
|
|
251
|
+
`mcp_server.js:1304` — the MCP `tools/call` branch used to `await handleTool(...)` inside the main `while (true)` loop. That made the loop **strictly serial**: every tool call blocked the next message read. When `claws_worker` sat in its poll loop for up to `timeout_ms`, the next tool call couldn't even start until the first either matched its marker or timed out. Three "parallel" `claws_worker` calls actually queued up sequentially — fan-out and wave-army patterns were broken.
|
|
252
|
+
|
|
253
|
+
Now the dispatch is fire-and-forget: `handleTool(...).then(respond).catch(respond)`. The main loop reads the next message immediately, multiple handlers interleave on the JS event loop, and N parallel `claws_worker` calls actually run concurrently with their own pty terminals. JSON-RPC responses can arrive out-of-order relative to requests (allowed by spec; each response carries the matching id). State sharing is safe — `_pconn.pending` uses unique rids, `_eventBuffer` push is single-statement-atomic, `_circuitBreaker` reads/writes are racy but benign.
|
|
254
|
+
|
|
255
|
+
### Tests
|
|
256
|
+
|
|
257
|
+
`extension/test/worker-fixes-v079.test.js` rewritten to lock down v0.7.10's contract: 11 static-analysis checks covering the four correctness fixes plus **explicit assertions that the file-referrer pattern and boot-retry loop are NOT present, AND that `tools/call` dispatches concurrently (no `await` on `handleTool`)**. Future contributors who try to reintroduce the broken patterns will fail this test.
|
|
258
|
+
|
|
259
|
+
### Added — single-source-of-truth version
|
|
260
|
+
|
|
261
|
+
- **`scripts/bump-version.sh <X.Y.Z>`** — the only blessed way to change the project version. Updates root `package.json`, `extension/package.json`, and `extension/package-lock.json` (root + nested `packages[""]`) atomically. Validates SemVer 2.0 strictness (rejects four-segment versions like `0.7.7.1` that VS Code's manifest validator can't parse).
|
|
262
|
+
- **`extension/test/version-drift.test.js`** — fails the suite if any of the four version fields disagree, or if the version isn't SemVer 2.0 compliant. Wired into `npm test`. Catches the class of bug that left `extension/package-lock.json` stale at `0.7.5` for three releases without anyone noticing.
|
|
263
|
+
|
|
264
|
+
### Backwards compatibility
|
|
265
|
+
|
|
266
|
+
`claws_worker(name, mission)` API is unchanged. All call patterns from v0.7.4 onward continue to work as they did pre-v0.7.9. The worker return value drops `mission_file` and `run_token` (those fields were introduced in v0.7.9 and are gone with the file-referrer they belonged to).
|
|
267
|
+
|
|
268
|
+
## [0.7.9] - 2026-04-30 — claws_worker reliability overhaul
|
|
269
|
+
|
|
270
|
+
**`claws_worker` v0.7.8 was effectively unusable** for any caller passing a multi-line `mission` to Claude Code: workers either false-completed in 1–2 seconds (marker collision on input echo) or sat forever in collapsed-paste limbo (Claude Code v2.x auto-detects multi-line bursts as paste). The only working pattern was hand-rolling a single-line file referrer with a token never present in the mission text. v0.7.9 makes that pattern automatic, and adds boot retry + a correct boot marker.
|
|
271
|
+
|
|
272
|
+
> **Follow-up patches (post-tag, force-pushed onto v0.7.9):**
|
|
273
|
+
> - **Fix A** — `scripts/install.sh` skill-copy loop: added `-ef` (same-inode) guard so the loop skips the `rm -rf` + `cp -r` pair when source and destination resolve to the same directory. Without this, dev machines where `~/.claws-src` symlinks to the project root had install.sh wipe the source skill before it could be copied — install.sh aborted at step 6, never running steps 7–9.
|
|
274
|
+
> - **Fix B** — `mcp_server.js` `runBlockingWorker` file-referrer: decoupled the mission file path nonce from the run-token. The initial v0.7.9 implementation embedded `runToken` directly in the file path; the path was in the single-line referrer payload, which was echoed into the pty log on send, where the marker scanner false-matched. New behavior: independent `fileNonce` for the path, `runToken` lives only inside the file content (where Claude's Read tool ingests it but the pty never sees it).
|
|
275
|
+
> - **Fix C** — `scripts/install.sh` Step 1: added an uncommitted-work guard before the `git reset --hard origin/main`. install.sh used to silently destroy local edits on dev boxes where INSTALL_DIR == project root. The guard refuses to reset on a dirty tree unless `CLAWS_FORCE_RESET=1` is set; clear error explains the three escape hatches (commit, force, or use a different `CLAWS_DIR`).
|
|
276
|
+
> - Regression test: `extension/test/worker-fixes-v079.test.js` grew from 14 → 19 static-analysis checks covering all three follow-ups.
|
|
277
|
+
|
|
278
|
+
**No API change.** Existing `claws_worker(name, mission)` calls just work. Existing `command:` / `launch_claude=false` / explicit `complete_marker` paths preserve v0.7.8 behavior exactly.
|
|
279
|
+
|
|
280
|
+
### Fixed
|
|
281
|
+
|
|
282
|
+
- **Bug 1 — Marker false-match on input echo (`mcp_server.js:531`)** The poll loop did `text.includes(complete_marker)` over the entire pty buffer including the echo of the mission text the worker just sent. Any marker substring referenced in the mission triggered immediate false-completion. v0.7.9 captures `markerScanFrom = pty_log_length` after the payload is sent and only scans bytes added *after* that point.
|
|
283
|
+
- **Bug 2 — Bracketed-paste mission never submits in Claude Code v2.x** Claude Code auto-detects multi-line bursts as paste and collapses to `[Pasted text #N +M lines] paste again to expand`. The trailing CR `runBlockingWorker` sent did not escape that collapsed state, so the mission never ran. v0.7.9 introduces a **file-referrer pattern** for Claude Code missions: the mission body is written to a temp file with a per-spawn random run-token, and the worker sends a single-line referrer (`Read /tmp/claws-mission-…md and follow it precisely.`) that fits on one line and bypasses paste detection entirely. Mission file is cleaned up on auto-close.
|
|
284
|
+
- **Bug 4 — Boot marker default never matched** `boot_marker` defaulted to `'Claude Code'` (with a space), but the ANSI-stripped Claude Code v2.x banner renders as `ClaudeCodev2.1.123` — no space. Worker burned the full 8s `boot_wait_ms` on every spawn before falling through. New default: `'bypass permissions'`, which matches the bypass-mode footer reliably.
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
|
|
288
|
+
- **Boot retry** (`boot_retries`, default 2) — if the first boot attempt times out without seeing the boot marker, `runBlockingWorker` re-sends the launch command and waits another `boot_wait_ms`. Caps at the configured retry count, then proceeds best-effort.
|
|
289
|
+
- **`mission_file` and `run_token` in the worker return value** — surfaces the file path and per-spawn token used by the file-referrer pattern, for debugging and inspection. Both are `null` when the legacy path is used (explicit marker, `command:` mode, or `launch_claude=false`).
|
|
290
|
+
|
|
291
|
+
### Compatibility
|
|
292
|
+
|
|
293
|
+
The file-referrer pattern is **opt-out, not opt-in**:
|
|
294
|
+
- Default for `claws_worker(name, mission)` with `launch_claude=true` (the common case).
|
|
295
|
+
- **Skipped** when the caller passes an explicit `complete_marker` — the user signalled they want their own marker semantics; v0.7.9 just adds the scan-offset fix to make that marker bulletproof against echo-match.
|
|
296
|
+
- **Skipped** for `command:` mode (shell workers, no Claude Code). Scan-offset still applies.
|
|
297
|
+
- **Skipped** when `launch_claude=false`. Mission goes directly to whatever shell or REPL is running.
|
|
298
|
+
- File-write failure (e.g. `/tmp` readonly) falls back to the v0.7.8 direct-send path — degraded but matches prior contract.
|
|
299
|
+
|
|
300
|
+
### Out-of-scope (deferred to v0.7.10)
|
|
301
|
+
|
|
302
|
+
- **Bug 3 — `claws_send` first-character duplication** (cosmetic: `cclaude`, `eecho`). Visual artifact in pty echo only; bytes arriving at the shell are correct. Needs byte-level pty trace to root-cause.
|
|
303
|
+
- Send-retry on stuck paste (would require activity-detection heuristic).
|
|
304
|
+
- `[Pasted text]` detection + auto-recovery (re-send as single-line with file referrer).
|
|
305
|
+
|
|
306
|
+
## [0.7.8] - 2026-04-30 — Re-release of v0.7.7.1 with semver-compliant version
|
|
307
|
+
|
|
308
|
+
**Hot-fix replacing v0.7.7.1.** v0.7.7.1 used a four-segment version (`MAJOR.MINOR.PATCH.BUILD`) which is not valid per the [SemVer 2.0 spec](https://semver.org/spec/v2.0.0.html) — only `MAJOR.MINOR.PATCH` is allowed. VS Code's extension manifest validator rejected the `0.7.7.1` extension with "Extension version is not semver compatible" and disabled it for users who updated. v0.7.8 contains the same fixes as v0.7.7.1 with a properly-incremented PATCH segment so VS Code accepts and enables the extension.
|
|
309
|
+
|
|
310
|
+
### Action required for users hit by 0.7.7.1
|
|
311
|
+
|
|
312
|
+
Run `/claws-update` again — install.sh will deploy the v0.7.8 VSIX over the disabled v0.7.7.1 entry. Reload VS Code (Developer: Reload Window) and the extension activates again. No manual cleanup needed.
|
|
313
|
+
|
|
314
|
+
### Fixed
|
|
315
|
+
|
|
316
|
+
- **Banner suppression bug** `scripts/shell-hook.sh:24` — dropped `export` from `CLAWS_BANNER_SHOWN=1`. The variable was meant to scope to the current shell only (suppress re-paint on `source`), but `export` made it leak into every child process. When VS Code was launched from a banner-painted shell, every terminal it spawned inherited `CLAWS_BANNER_SHOWN=1` pre-set and the banner never painted. With `export` removed, each new interactive shell starts with no flag, paints once, and child processes get a clean slate. Verified: banner paints reliably with `v0.7.8` in fresh terminals.
|
|
317
|
+
- **Worker spawn cwd + model defaults** `mcp_server.js` `runBlockingWorker` — `claws_worker` now passes `cwd` to the create RPC (defaulting to the MCP server's `process.cwd()` so workers land in the project root, not `$HOME`) and launches Claude Code with `--model claude-sonnet-4-6` by default. Both overridable via new `cwd` and `model` args. Previously, workers landed in `$HOME`, hit the trust dialog, failed the project MCP socket walk-up, and booted whichever model the user's shell defaulted to (often Opus xhigh). Schema regenerated; codegen test still passes (36 tools).
|
|
318
|
+
- **GAP-3** `scripts/install.sh` — when update.sh's `--ff-only` pull diverged and exported `GIT_PULL_OK=0`, install.sh's own `git reset --hard origin/main` would succeed, leaving the source fresh but with the stale `GIT_PULL_OK=0` flag still gating CLAUDE.md re-injection. install.sh now flips `GIT_PULL_OK=1` after a successful force-reset so the new template + tool list lands.
|
|
319
|
+
- **GAP-1** `scripts/install.sh:559` — `EXPECTED_MIN_VERSION` bumped from `"0.7.4"` to `"0.7.7"`.
|
|
320
|
+
- **GAP-2** `scripts/install.sh:1182-1185` — corrected misleading comment about hook bin path. Documentation only.
|
|
321
|
+
|
|
322
|
+
## [0.7.7.1] - 2026-04-30 — WITHDRAWN (invalid semver)
|
|
323
|
+
|
|
324
|
+
This version was published with a four-segment string (`0.7.7.1`) which is not valid per [SemVer 2.0](https://semver.org/spec/v2.0.0.html). VS Code disabled the extension. **Use [v0.7.8](#078---2026-04-30--re-release-of-v0771-with-semver-compliant-version) instead** — same fixes, valid version.
|
|
325
|
+
|
|
326
|
+
## [0.7.7] - 2026-04-30 — Development Discipline Hooks
|
|
327
|
+
|
|
328
|
+
### Fixed (v0.7.7-bulletproof)
|
|
329
|
+
|
|
330
|
+
- **P0-1** `scripts/fix.sh` — added explicit `~/.claude/settings.json` JSON validity check (check 7b). Malformed settings caused ALL hooks to fail silently per session. Fix.sh now detects the issue, backs up the file, and re-injects Claws hooks via `inject-settings-hooks.js`.
|
|
331
|
+
- **P1-2** `scripts/inject-dev-hooks.js` — replaced raw `JSON.parse` + `writeFileSync` with `json-safe.mjs` `mergeIntoFile` (JSONC-tolerant, atomic, abort-on-malformed). Previously, a comment in `.claude/settings.json` caused silent parse failure, `{}` fallback, and full overwrite — destroying all pre-existing project hooks.
|
|
332
|
+
- **P1-1** `scripts/inject-settings-hooks.js` — legacy array hooks (early Claude Code) now migrated to object format before remove+add. Previously, adding named properties to a JS array caused new hooks to be silently dropped by `JSON.stringify`. Both `--update` and add-only paths now migrate array→object first.
|
|
333
|
+
- **D-2** `.claude/settings.json` (dev-box) — migrated dev-hook command paths from `scripts/dev-hooks/` (source path) to `.claws-bin/dev-hooks/` (canonical production path). Removed legacy inner-`_source` format entries that the inject script could not update automatically due to format mismatch.
|
|
334
|
+
- **P3-6** `scripts/update.sh` — added `--dry-run` flag. When passed, skips the installer step and instead prints the git diff stat from `origin/main` plus pending local commits — useful for previewing what an update would change before applying it.
|
|
335
|
+
- **P3-5** `scripts/install.sh` — VSIX post-install stale cleanup now polls up to 1s (5×200ms) for the extracted extension directory to appear before deciding it's absent. Previously, VS Code's async VSIX extraction could cause the cleanup to skip and warn on every install.
|
|
336
|
+
- **P3-1/2/3** `scripts/install.sh` — three hygiene fixes: (1) deploy `schemas/client-types.d.ts` to `.claws-bin/schemas/` for typed SDK consumers; (2) replace 5 hardcoded `if [ -d .claude/skills/<name> ]` blocks with a `for _skill_src in .claude/skills/claws-* dev-protocol-*` loop so new skills are picked up automatically; (3) emit `warn` when `claws-sdk.js` is absent instead of silently skipping.
|
|
337
|
+
- **P2-4** `scripts/fix.sh` — when the socket is LIVE, now probes terminal list for wrapped terminals with missing `logPath` (indicates `script(1)` failed at pty allocation time). On Linux, also checks `command -v script` and suggests `bsdutils` install if absent.
|
|
338
|
+
- **P2-3** `scripts/fix.sh` — MCP handshake failure now triggers auto-recovery: copies `mcp_server.js` from `$INSTALL_DIR` to `.claws-bin/` and re-probes the handshake once. Previously the script reported the failure and stopped.
|
|
339
|
+
- **P2-1** `scripts/shell-hook.sh` — now exports `CLAWS_DIR` at source time (detected from script location, falls back to `~/.claws-src`). Updated `/claws-fix` and `/claws-update` slash commands to use `${CLAWS_DIR:-$HOME/.claws-src}` instead of hardcoded `~/.claws-src`, so a `CLAWS_DIR` override is honored end-to-end.
|
|
340
|
+
- **P2-2** `scripts/install.sh` and `scripts/fix.sh` — added `.claws-bin` symlink guard before `mkdir -p`. Detects and removes dangling or unexpected symlinks at `$PROJECT_ROOT/.claws-bin` before creating the directory, preventing silent deployment to the wrong target path.
|
|
341
|
+
- **P1-5** `scripts/fix.sh` — added shell-hook sourcing check (check 6b). Greps `.zshrc` / `.bashrc` for a `shell-hook.sh` source line; if absent, appends one automatically so `claws-ls`, `claws-new`, `claws-run`, and `claws-log` functions are available in new terminals.
|
|
342
|
+
- **P1-4** `scripts/fix.sh` — added unconditional `.claws-bin` integrity check (check 4c), independent of the `.mcp.json` registration gate. Detects missing directory, missing `mcp_server.js`, and dangling symlinks, then auto-repairs by copying from `$INSTALL_DIR`. Previously, a broken `.claws-bin` was only repaired when `.mcp.json` was also missing.
|
|
343
|
+
- **P1-3** `scripts/fix.sh` — replaced `ls … | head -1` with a full `for inst` loop over all `neunaha.claws-*` entries per editor dir. Added post-scan duplicate detection that warns when multiple copies exist in the same editor, preventing silent load-order conflicts.
|
|
344
|
+
- **D-1** `schemas/mcp-tools.json` — registered 5 missing MCP tools: `claws_drain_events`, `claws_pipeline_create`, `claws_pipeline_list`, `claws_pipeline_close`, `claws_dispatch_subworker`. These handlers existed in `mcp_server.js` but were invisible to AI orchestrators because `tools/list` reads from the schema file.
|
|
345
|
+
- **A-5** `scripts/install.sh` — `STEP_TOTAL` bumped from 8 to 9 to match actual step count (cosmetic — install used to render `9/8 Verifying`).
|
|
346
|
+
|
|
347
|
+
### Added
|
|
348
|
+
|
|
349
|
+
- **Five dev-hook scripts** in `scripts/dev-hooks/`: `check-stale-main`, `check-tag-pushed`, `check-tag-vs-main`, `check-open-claws-terminals`, `check-extension-dirs` — each exits 0 (warn-only, never blocks), logs to `/tmp/claws-dev-hooks.log`.
|
|
350
|
+
- **`scripts/inject-dev-hooks.js`** — idempotent safe-merge hook registration; tags all entries with `_source:"claws-dev-hooks"` for clean removal; skips re-registration if hook already present.
|
|
351
|
+
- **`install.sh` and `update.sh`** — now deploy dev hooks to `<project>/.claws-bin/dev-hooks/` and register them via `inject-dev-hooks.js` on both fresh install and update paths.
|
|
352
|
+
- **`scripts/shell-hook.sh` runtime version** — banner version is now read at runtime from `CLAWS_VERSION` env var or nearest `package.json` (walks up from CWD); no more hardcoded `v0.x.y` that drifts across releases. Banner also detects pipe-mode (non-interactive) and suppresses the command list in that context.
|
|
353
|
+
- **`templates/CLAUDE.project.md`** — new "Development Discipline (enforced by hooks)" section with 7 best-practice bullets covering stale-main pulls, semver compliance, extension-dir safety, CLAUDE.md re-injection, pre-PR drift check, tag discipline, and Claws terminal policy.
|
|
354
|
+
- **WaveRegistry lifecycle hardening** — wave lifecycle state machine enforces valid transitions (PLANNED→RUNNING→COMPLETE/FAILED); stale wave entries GC'd after configurable TTL; `claws_wave_status` now returns `phase` + `elapsedMs`.
|
|
355
|
+
- **Army-style nested wave harvest** (`extension/src/wave-registry.ts`, `server.ts`) — `WaveRecord` gains `parentWave?`, `subWorkerTerminals[]`, `harvestedAt?`, `orphanedTerminals[]`; `WaveRegistry.trackTerminal()` records TIDs spawned by wave-affiliated peers; `harvestWave()` returns orphaned TIDs for auto-close on `wave.complete`; lead-silence violation timer fires `wave.<id>.violation {kind:"silent_lead_with_active_subs"}` when LEAD goes quiet with active sub-worker terminals.
|
|
356
|
+
- **`WaveHarvestedV1` schema** (`event-schemas.ts`) — typed schema for `wave.*.harvested` events; registered in `SCHEMA_BY_NAME` and `TOPIC_REGISTRY`.
|
|
357
|
+
- **`claws_wave_status` nested tree** (`mcp_server.js`) — response now includes `lead: {peerId, peerName, terminalId, status, lastSeenMs}` and `subWorkers[].terminalId`; `subWorkerTerminals` flat array exposed.
|
|
358
|
+
- **`PeerConnection`** (`peer-registry.ts`) — gains `waveId?` and `subWorkerRole?` to persist wave affiliation from `hello` across subsequent commands.
|
|
359
|
+
|
|
360
|
+
### Fixed (carries all v0.7.6.1 patch fixes)
|
|
361
|
+
|
|
362
|
+
- **P0-1** `mcp_server.js` — `claws_worker` circuit breaker: skips reconnect if last failure < 30 s ago; `_scanAndPublishCLAWSPUB` trips `scanDisabled` after 3 consecutive socket errors; default `timeout_ms` reduced 1 800 000 → 300 000 ms.
|
|
363
|
+
- **P0-2** `extension/src/server.ts` — orchestrator peers exempt from per-peer publish rate limit; no self-deadlock during high-volume waves.
|
|
364
|
+
- **P1-1** `extension/src/server-config.ts` — `DEFAULT_STRICT_EVENT_VALIDATION` flipped `false` → `true`; W4 validation active by default.
|
|
365
|
+
- **P1-2** `mcp_server.js` — `_eventBuffer.maxWaiters=10` cap; excess `wait_ms` requests return error immediately; `system.bus.ring-overflow` event emitted once per eviction batch.
|
|
366
|
+
- **P1-5/P1-6** `scripts/install.sh` — deploy blocks for `claws-wave-lead`, `claws-wave-subworker`, `dev-protocol-piafeur` skills.
|
|
367
|
+
- **P1-7** `schemas/mcp-tools.json` + `mcp_server.js` — all 5 `claws_task_*` tools (`claws_task_assign`, `claws_task_update`, `claws_task_complete`, `claws_task_cancel`, `claws_task_list`) registered in schemas and MCP handlers.
|
|
368
|
+
- **P1-8** `scripts/shell-hook.sh` — banner version no longer drifts across releases (see Added above).
|
|
369
|
+
|
|
370
|
+
### Known Issues
|
|
371
|
+
|
|
372
|
+
- `auto-subscribe-cmd.test.js` — emits `envelope:invalid` under `strictEventValidation=true`; pre-existing since v0.7.6.1 P1-1 flip. Not introduced by v0.7.7.
|
|
373
|
+
- `claws-v2-rate.test.js` — same `envelope:invalid` root cause. Pre-existing.
|
|
374
|
+
- `claws-v2-typed-rpc.test.js` — `rpc.call` timeout on test teardown; pre-existing race condition unrelated to v0.7.7 changes.
|
|
375
|
+
|
|
376
|
+
## [0.7.6.1] - 2026-04-30 — Bug-fix patch (8 P0/P1 code + 2 hot-fixes)
|
|
377
|
+
|
|
378
|
+
### Fixed
|
|
379
|
+
|
|
380
|
+
- **P0-1/P2-3** `mcp_server.js` — circuit breaker: `_pconnEnsureRegistered` skips reconnect if last failure < 30s ago; `_scanAndPublishCLAWSPUB` trips `scanDisabled` after 3 consecutive socket errors, resumes on explicit reconnect; default `timeout_ms` reduced 1,800,000 → 300,000 ms (5 min).
|
|
381
|
+
- **P0-2** `extension/src/server.ts` — orchestrator peers exempt from per-peer publish rate limit; orchestrator management commands can no longer be self-rate-limited during high-volume waves. Peer role looked up via `this.peers.get(peerId)?.role` before the bucket check.
|
|
382
|
+
- **P1-1** `extension/src/server-config.ts` — `DEFAULT_STRICT_EVENT_VALIDATION` flipped `false` → `true`; the W4 validation guarantee is now active by default; unregistered topics pass through unchecked (the existing `if (dataSchema !== null)` guard in server.ts handles this).
|
|
383
|
+
- **P1-2** `mcp_server.js` — `_eventBuffer.maxWaiters=10` cap; excess `wait_ms` requests return an error immediately; `system.bus.ring-overflow` event emitted once per eviction batch (via `setImmediate` dedup guard `_overflowPending`).
|
|
384
|
+
- **P1-5/P1-6** `scripts/install.sh` — copy blocks added for `claws-wave-lead`, `claws-wave-subworker`, `dev-protocol-piafeur` skills; existing `claws*.md` glob already covers `claws-wave-lead.md` and `claws-army.md` commands; `claws-update` on existing projects now picks up all three skills.
|
|
385
|
+
- **P1-7** `schemas/mcp-tools.json` + `mcp_server.js` — added `claws_task_assign`, `claws_task_update`, `claws_task_complete`, `claws_task_cancel`, `claws_task_list` tool definitions (schemas) and their MCP handler stubs routing to `task.*` protocol commands via the stateful socket; `claws_schema_get` no longer returns not-found for these 5 tools.
|
|
386
|
+
- **P1-8** `scripts/shell-hook.sh:66` — banner version updated `v0.6.1` → `v0.7.6`; was 7 releases stale.
|
|
387
|
+
- **HOT-FIX A** — ran `inject-claude-md.js` against `/Users/ANISH.NEUNAHA/Desktop/Claws`; `CLAWS:BEGIN` block now present.
|
|
388
|
+
- **HOT-FIX B** — removed stale `~/.vscode/extensions/neunaha.claws-0.7.4/` and `neunaha.claws-0.7.5/`; only `neunaha.claws-0.7.6` remains.
|
|
389
|
+
|
|
390
|
+
## [0.7.6] - 2026-04-30 — Claws TCP — full architectural release (10 waves + embedder)
|
|
391
|
+
|
|
392
|
+
### Fixed — Ship restoration
|
|
393
|
+
|
|
394
|
+
- `extension/scripts/deploy-dev.mjs`: deploy loop now copies `README.md`, `CHANGELOG.md`, `icon.png` alongside `dist/` and `native/` — these were previously skipped, causing blank display in the VS Code Extensions panel.
|
|
395
|
+
- `extension/CHANGELOG.md`: synced from root CHANGELOG (was stale at v0.5.3, now complete through v0.7.6).
|
|
396
|
+
- `scripts/inject-claude-md.js`: `TOOLS_V2` expanded with all v0.7.6 MCP tools — `claws_lifecycle_{plan,advance,snapshot,reflect}`, `claws_wave_{create,status,complete}`, `claws_deliver_cmd`, `claws_cmd_ack`, `claws_schema_{list,get}`, `claws_rpc_call`.
|
|
397
|
+
|
|
398
|
+
### Added — W10/L18+L19 Token Auth + WebSocket Transport (Wave 10 — FINAL)
|
|
399
|
+
|
|
400
|
+
- `extension/src/server-config.ts` — `AuthConfig` (`enabled`, `tokenPath`), `WebSocketConfig` (`enabled`, `port`, `certPath`, `keyPath`) sub-configs added to `ServerConfig`; `defaultServerConfig` defaults to both disabled.
|
|
401
|
+
- `extension/src/protocol.ts` — `HelloRequest` gains `token?`, `nonce?`, `timestamp?` fields for L18 auth.
|
|
402
|
+
- `extension/src/server.ts` — `validateAuthToken()`: HMAC-SHA256 over `peerName:role:nonce:timestamp`; checks token present, timestamp ≤5 min stale, nonce single-use, HMAC `timingSafeEqual`; `usedNonces` Set cleared on `stop()`; auth called at start of `hello` handler before any other logic; `wsTransport.start()` invoked in `start()` chain when `webSocket.enabled`; `wsTransport.stop()` in `stop()`.
|
|
403
|
+
- `extension/src/websocket-transport.ts` (new) — `WebSocketTransport` class: `WsSocketAdapter` wraps `ws.WebSocket` in a `net.Socket`-compatible EventEmitter shim (adapts message→data, close→end, write strips `\n` and calls `ws.send`); `WebSocketServer` created over http/https server; TLS when `certPath`+`keyPath` provided; loaded lazily so no cost when WS disabled.
|
|
404
|
+
- `extension/src/extension.ts` — `getConfig()` wires `auth.*` and `webSocket.*` from VS Code settings.
|
|
405
|
+
- `extension/package.json` — `ws@8` + `@types/ws@8` as optional/dev deps; VS Code config contributions for all 6 new config keys; `test:auth` and `test:ws-transport` scripts; both added to `test` chain.
|
|
406
|
+
- `extension/test/claws-auth.test.js` (new) — 6-check auth suite: no-token, wrong-HMAC, valid-HMAC, stale-timestamp, nonce-reuse, auth-disabled.
|
|
407
|
+
- `extension/test/claws-ws-transport.test.js` (new) — 5-check WS suite: hello, pub/sub round-trip, shared peer registry with Unix socket, protocol tag, worker auto-subscribe.
|
|
408
|
+
|
|
409
|
+
### Added — W8/L16+L7 Typed RPC + Schema Registry (Wave 8)
|
|
410
|
+
|
|
411
|
+
- `extension/src/server.ts` — `rpc.call` command: synchronous blocking RPC — caller's request is held open (like `exec`) until the target peer publishes to `rpc.response.<callerPeerId>.<requestId>` or the timeout fires; `rpcPending` correlation map with `clearTimeout` cleanup on resolution; `schema.list` command returns sorted keys from `SCHEMA_BY_NAME`; `schema.get` command returns a simplified JSON representation via `serializeZodSchema` (recursive Zod `_def` traversal covering object, string, number, boolean, array, record, enum, literal, optional, nullable, unknown).
|
|
412
|
+
- `extension/src/event-schemas.ts` — `RpcRequestV1` (requestId uuid, method, params optional, callerPeerId) and `RpcResponseV1` (requestId, ok, result optional, error optional) Zod schemas; both registered in `SCHEMA_BY_NAME` (32 → 35 with PipelineStepV1).
|
|
413
|
+
- `extension/src/topic-registry.ts` — `rpc.*.request` and `rpc.response.**` patterns registered; registry grows 32 → 34.
|
|
414
|
+
- `extension/src/protocol.ts` — `RpcCallRequest`, `SchemaListRequest`, `SchemaGetRequest` interfaces added to `ClawsRequest` union.
|
|
415
|
+
- `mcp_server.js` — `claws_schema_list`, `claws_schema_get`, `claws_rpc_call` handlers.
|
|
416
|
+
- `scripts/codegen/gen-mcp-tools.mjs` — descriptions and input schemas for the 3 new tools (`claws_schema_list`, `claws_schema_get`, `claws_rpc_call`); tool count grows 23 → 26; `schemas/mcp-tools.json` is fully generated — no hand-edits needed.
|
|
417
|
+
- `schemas/json/rpc-request-v1.json`, `schemas/json/rpc-response-v1.json`, `schemas/json/pipeline-step-v1.json` — generated JSON Schema files (pipeline-step-v1 was missing from prior run).
|
|
418
|
+
- `scripts/gen-client-types.mjs` (new) — standalone codegen script: bundles `event-schemas.ts` via esbuild, walks `SCHEMA_BY_NAME`, emits `schemas/client-types.d.ts` with TypeScript interface declarations for all 35 schemas; zero additional deps (uses esbuild already in extension devDeps).
|
|
419
|
+
- `schemas/client-types.d.ts` (new) — generated TypeScript client type declarations; one `export interface` per SCHEMA_BY_NAME entry; union/nullable/optional/record/array types all handled.
|
|
420
|
+
- `extension/test/claws-v2-typed-rpc.test.js` (new) — 40-check integration suite: round-trip RPC (<500ms), timeout (300ms), unknown-peer error, `schema.list` (checks rpc/worker/cmd names), `schema.get` (positive + negative), validation (missing method/targetPeerId).
|
|
421
|
+
|
|
422
|
+
### Added — W9/L11+L17 Pipeline Composition + Workflow DAG Foundation (Wave 9)
|
|
423
|
+
|
|
424
|
+
- `extension/src/pipeline-registry.ts` (new) — `PipelineRegistry` with `create`, `get`, `list`, `close`, `findBySource`, `clear`; `PipelineRecord` and `PipelineStep` types; `pipe_NNNN` monotonic IDs; `findBySource` returns only active pipelines for O(n) output-wiring dispatch.
|
|
425
|
+
- `extension/src/server.ts` — `pipeline.create` handler (orchestrator-only, ≥2 steps with source+sink required); `pipeline.list` and `pipeline.close` handlers; output→sink wiring in `publish` handler: `output.<id>.*` topics matched by regex, active pipelines found via `findBySource`, text forwarded to sink via pty `writeInjected` or VS Code `sendText`, `pipeline.<id>.step.<stepId>` event emitted for each delivery.
|
|
426
|
+
- `extension/src/event-schemas.ts` — `PipelineStepV1` Zod schema (pipelineId, stepId, role, terminalId, state, ts); `SCHEMA_BY_NAME` grows from 34 → 35 (also adds previously-missing `rpc-request-v1` and `rpc-response-v1` entries).
|
|
427
|
+
- `extension/src/topic-registry.ts` — `pipeline.*.step.*`, `pipeline.*.created`, `pipeline.*.closed` patterns registered; registry grows 31 → 34.
|
|
428
|
+
- `extension/src/protocol.ts` — `PipelineCreateRequest`, `PipelineListRequest`, `PipelineCloseRequest` interfaces added to the `ClawsRequest` union.
|
|
429
|
+
- `mcp_server.js` — `claws_pipeline_create`, `claws_pipeline_list`, `claws_pipeline_close` handlers.
|
|
430
|
+
- `schemas/mcp-tools.json` — 3 new tool definitions for the pipeline MCP tools.
|
|
431
|
+
- `extension/test/claws-v2-pipeline.test.js` (new) — 34-check integration suite: create/list/close lifecycle (pipeline.*.created push, list active, close emits pipeline.*.closed, list shows closed state), output wiring (output.tA.line publish → step event + sink sendText), error cases (empty steps, missing source/sink, unknown pipelineId), topic subscription acceptance.
|
|
432
|
+
|
|
433
|
+
### Added — W6/L10 Structured Control — deliver-cmd + cmd.ack (Wave 6)
|
|
434
|
+
|
|
435
|
+
- `extension/src/server.ts` — `deliver-cmd` handler: orchestrator-only; validates target peer exists, deduplicates by `idempotencyKey`, allocates monotonic `seq`, appends to event log, and pushes the command envelope to the worker's auto-subscription topic. `cmd.ack` handler: worker-only; fans out `cmd.<peerId>.ack` to all subscribed orchestrators with the `seq` and `status` fields.
|
|
436
|
+
- `extension/src/protocol.ts` — `DeliverCmdRequest` and `CmdAckRequest` interfaces added to the `ClawsRequest` union.
|
|
437
|
+
- `extension/src/event-schemas.ts` — `CmdDeliverV1` and `CmdAckV1` Zod schemas; `SCHEMA_BY_NAME` grows from 30 → 32.
|
|
438
|
+
- `extension/src/topic-registry.ts` — `cmd.*.ack` pattern registered with `CmdAckV1` schema; registry grows 28 → 29.
|
|
439
|
+
- `mcp_server.js` — `claws_deliver_cmd` and `claws_cmd_ack` MCP tool handlers.
|
|
440
|
+
- `schemas/mcp-tools.json` — 21 → 23 tools; `schemas/json/cmd-deliver-v1.json` and `schemas/json/cmd-ack-v1.json` generated.
|
|
441
|
+
- `scripts/codegen/gen-mcp-tools.mjs` — descriptions and input schemas for the two new tools.
|
|
442
|
+
- `extension/test/claws-v2-control.test.js` — 31-check integration suite (6 suites): basic delivery (push frame, seq number), idempotency (duplicate key returns `{ok:true, duplicate:true}` without re-push), unknown peer error, role gating (orchestrator cannot call `cmd.ack`), event-log durability, and `cmd.*.ack` registry subscription.
|
|
443
|
+
|
|
444
|
+
### Added — W7/L13+L14 Observability and Rate Control (Wave 7)
|
|
445
|
+
|
|
446
|
+
- `extension/src/event-log.ts` — `lastSequence` getter: returns the last successfully appended sequence number (min 0); used by `system.metrics` heartbeat payload.
|
|
447
|
+
- `extension/src/server-config.ts` — `maxPublishRateHz` (default 10 000) and `maxQueueDepth` (default 500) added to `ServerConfig`; `DEFAULT_MAX_PUBLISH_RATE_HZ` and `DEFAULT_MAX_QUEUE_DEPTH` exported.
|
|
448
|
+
- `extension/src/extension.ts` — `getConfig()` wires `maxPublishRateHz` and `maxQueueDepth` from `claws.*` VS Code settings.
|
|
449
|
+
- `extension/src/server.ts` — L13: heartbeat timer now emits `system.metrics` (publishRate_per_sec, queueDepth, peerCount, eventLogLastSeq, uptimeMs, ts) and `system.peer.metrics.<peerId>` for peers with drops or rate-limit hits; per-heartbeat publish counter resets each tick.
|
|
450
|
+
- `extension/src/server.ts` — L14: per-peer sliding 1-second rate limiter; publish requests exceeding `maxPublishRateHz` return `{ok:false,error:'rate-limit-exceeded'}`; `serverInFlight` admission-control counter (incremented synchronously before any `await`) rejects beyond `maxQueueDepth` with `{ok:false,error:'admission-control:backlog'}`; rate check fires before admission so high-rate publishers get the semantically correct error code.
|
|
451
|
+
- `extension/src/event-schemas.ts` — `SystemMetricsV1` and `SystemPeerMetricsV1` Zod schemas added; registered in `SCHEMA_BY_NAME`.
|
|
452
|
+
- `extension/src/topic-registry.ts` — `system.metrics` and `system.peer.metrics.*` registered with their schemas.
|
|
453
|
+
- `schemas/json/system-metrics-v1.json`, `schemas/json/system-peer-metrics-v1.json` — JSON Schema representations of the two new event types.
|
|
454
|
+
- `extension/test/claws-v2-rate.test.js` — 19-check integration test suite: system.metrics shape and cadence, burst rate-limit rejection, admission-control:backlog, system.peer.metrics per-peer emission with rateLimitHits, 1s backoff recovery, peerCount tracking.
|
|
455
|
+
|
|
456
|
+
### Added — W5/L8 Event Log Durability Hardening (Wave 5)
|
|
457
|
+
|
|
458
|
+
- `extension/src/event-log.ts` — `EventLogWriter.runRetention(retentionDays)`: deletes `.jsonl` segments (and companion `.idx` files) whose mtime is older than `retentionDays` days; closes the open fd before unlinking the active segment so no EBUSY on Linux; removes deleted entries from the in-memory manifest and flushes to disk.
|
|
459
|
+
- `extension/src/event-log.ts` — `EventLogWriter.compact()`: on startup, merges all segments smaller than 1 KB (COMPACT_SIZE_THRESHOLD) into a single merged `.jsonl` using atomic tmp-then-rename; preserves event sequence ordering; rebuilds the `.idx` for the merged segment.
|
|
460
|
+
- `extension/src/event-log.ts` — Per-segment `.idx` files: `topic<TAB>byte_offset` index written atomically alongside each `.jsonl` on `close()` and `rotate()`; offsets are the exact byte positions of each record's start, enabling O(1) seek for filtered replay. Written via tmp-then-rename for atomicity.
|
|
461
|
+
- `extension/src/server-config.ts` — `EventLogConfig` interface with `retentionDays` (default 7) and `compact` (default true); added to `ServerConfig` as `eventLog` field; `DEFAULT_EVENT_LOG_RETENTION_DAYS` and `DEFAULT_EVENT_LOG_COMPACT` constants exported.
|
|
462
|
+
- `extension/src/server.ts` — `start()` calls `eventLog.compact()` after `open()` when `eventLog.compact` config is true; heartbeat timer calls `eventLog.runRetention(retentionDays)` each tick.
|
|
463
|
+
- `extension/src/extension.ts` — `getConfig()` now populates `eventLog.retentionDays` and `eventLog.compact` from VS Code settings (`claws.eventLog.*`).
|
|
464
|
+
- `extension/test/claws-event-log-retention.test.js` — 10-check test suite: retention deletes old segments and keeps recent; manifest updated; fd closed before deletion; `.idx` written and parseable; `compact()` merges 3 small segments into 1; sequence ordering preserved; `scanFrom` replay works after compaction; byte offsets in `.idx` match actual line starts.
|
|
465
|
+
|
|
466
|
+
### Added — W1/L4 Vehicle State Machine
|
|
467
|
+
|
|
468
|
+
- `extension/src/protocol.ts` — `TerminalDescriptor` now includes `vehicleState?: 'PROVISIONING' | 'BOOTING' | 'READY' | 'BUSY' | 'IDLE' | 'CLOSING' | 'CLOSED'` so `list` responses expose the current vehicle state.
|
|
469
|
+
- `extension/src/event-schemas.ts` — `VehicleStateV1` Zod schema (terminalId, from, to, ts); `VehicleStateEnum` with all 7 states. `SCHEMA_BY_NAME` updated to include `vehicle-state-v1`.
|
|
470
|
+
- `extension/src/topic-registry.ts` — three new topic patterns registered: `vehicle.*.state`, `vehicle.*.created`, `vehicle.*.closed`.
|
|
471
|
+
- `extension/src/claws-pty.ts` — `ClawsPtyOptions` gains two optional hooks: `onOpenHook` (fires when VS Code calls Pseudoterminal.open()) and `onFirstOutputHook` (fires on the first byte of pty output). These let TerminalManager drive state transitions without coupling to the pty internals.
|
|
472
|
+
- `extension/src/terminal-manager.ts` — `TerminalRecord` grows `vehicleState: VehicleStateName`; `TerminalManager` gains `setStateChangeCallback(cb)` and a private `transitionState(rec, to)` that enforces the valid-transition table (PROVISIONING→BOOTING→READY→BUSY/IDLE→CLOSING→CLOSED). `createWrapped` emits PROVISIONING then immediately BOOTING; `onOpenHook` fires BOOTING→READY when the pty opens; `close` and `onTerminalClosed` emit CLOSING→CLOSED.
|
|
473
|
+
- `extension/src/server.ts` — wires `setStateChangeCallback` in the constructor; the callback calls `emitSystemEvent('vehicle.<id>.state', {terminalId, from, to, ts})` so every transition is appended to the event log and fanned out to subscribers.
|
|
474
|
+
- `extension/test/claws-v2-vehicle-state.test.js` — 19-assertion integration test suite covering: PROVISIONING→BOOTING and BOOTING→READY push frames, close emitting CLOSING→CLOSED, vehicleState in list responses, ordering invariants, payload structure (terminalId, from, to, ts).
|
|
475
|
+
|
|
476
|
+
### Added — Wave Army Protocol (embedder wave)
|
|
477
|
+
|
|
478
|
+
The embedder wave introduces the Wave Army Protocol — a structured multi-agent orchestration layer built on the claws/2 pub/sub bus. Every wave has a typed lifecycle (create → sub-workers boot → sub-workers complete → lead emits complete) with violation detection and disciplined per-role obligations.
|
|
479
|
+
|
|
480
|
+
**Protocol layer (shipped):**
|
|
481
|
+
- `extension/src/protocol.ts` — `SubWorkerRole` type (`lead | tester | reviewer | auditor | bench | doc`); `ContractedRoles` constant; `HelloRequest` extended with optional `waveId` and `subWorkerRole`; `WaveCreateRequest`, `WaveCompleteRequest`, `WaveStatusRequest` added to `ClawsRequest` union.
|
|
482
|
+
- `extension/src/event-schemas.ts` — 7 new Zod schemas: `WaveLeadBootV1`, `WaveLeadCompleteV1`, `WaveTesterRedCompleteV1`, `WaveReviewFindingV1`, `WaveAuditFindingV1`, `WaveBenchMetricV1`, `WaveDocCompleteV1`. `SCHEMA_BY_NAME` grows from 24 to 31 entries.
|
|
483
|
+
- `extension/src/topic-registry.ts` — `wave.**` catch-all pattern registered; specific wave schemas bound in `SCHEMA_BY_NAME`.
|
|
484
|
+
- `extension/src/wave-registry.ts` — new `WaveRegistry` class tracking active waves: per-role heartbeat timers fire `wave.<N>.violation` after 25s silence; `createWave`, `recordHeartbeat`, `markSubWorkerComplete`, `completeWave`, `handlePeerDisconnect`, `dispose`.
|
|
485
|
+
- `extension/src/server.ts` — `WaveRegistry` wired into `ClawsServer`; handlers for `wave.create`, `wave.status`, `wave.complete`; `hello` records sub-worker heartbeat when `waveId+subWorkerRole` present; `handleDisconnect` notifies registry.
|
|
486
|
+
|
|
487
|
+
**MCP tools (shipped):** `claws_wave_create`, `claws_wave_status`, `claws_wave_complete`, `claws_dispatch_subworker` added to `mcp_server.js` handler dispatch; `schemas/mcp-tools.json` updated with all 4 tool schemas (total grows by 4).
|
|
488
|
+
|
|
489
|
+
**Discipline contract embedded (shipped):** `templates/CLAUDE.project.md` and `templates/CLAUDE.global.md` gain "Wave Discipline Contract (mandatory)" sections listing all 8 sub-worker rules (heartbeat, boot event, phase events, error events, no --no-verify, full suite before commit, type check per .ts file, complete event). `scripts/hooks/session-start-claws.js` extended to include wave discipline summary block when Claws socket is detected.
|
|
490
|
+
|
|
491
|
+
### Fixed — embedder wave reviewer findings (F28/F29)
|
|
492
|
+
|
|
493
|
+
- `mcp_server.js` `claws_dispatch_subworker` — F28 (MEDIUM): switched mission delivery from `newline:true` to `newline:false` + separate `\r` submit, matching the established `claws_worker` pattern; prevents spurious double-LF in Claude TUI mid-think (reviewer finding F28).
|
|
494
|
+
- `mcp_server.js` `claws_dispatch_subworker` — F29 (LOW): boot-poll loop now tracks `nextOffset` from each `readLog` response and passes it as `offset` on the next call; eliminates repeated full-log reads during the 25 s boot window.
|
|
495
|
+
|
|
496
|
+
**Skills (shipped):** `.claude/skills/claws-wave-lead/SKILL.md` and `.claude/skills/claws-wave-subworker/SKILL.md` — full role contracts, boot sequences, schema references.
|
|
497
|
+
|
|
498
|
+
**Commands (shipped):** `.claude/commands/claws-wave-lead.md` (LEAD activation flow) and `.claude/commands/claws-army.md` (full army deployment with monitoring and completion criteria).
|
|
499
|
+
|
|
500
|
+
### Added — W2/L15 Event Log Replay + L9 Observation
|
|
501
|
+
|
|
502
|
+
- `extension/src/event-log.ts` — `EventLogReader` class: `scanFrom(cursor, topicPattern)` async generator reads segments from a byte-offset cursor position, filters records by topic pattern via `matchTopic()`, handles both manifest-based and directory-scan segment discovery.
|
|
503
|
+
- `extension/src/server.ts` — `subscribe` handler now validates `fromCursor` format (`parseCursor` → null = reject with `invalid cursor format`); registers subscription in `subscriptionIndex` **before** replay starts (atomicity — no live events missed during replay); `setImmediate` dispatches `replayFromCursor` so the subscribe ACK is sent first. `replayFromCursor` sends `{push:'message', replayed:true}` frames then a `{push:'caught-up', subscriptionId, replayedCount, resumeCursor}` terminal signal.
|
|
504
|
+
- `extension/src/protocol.ts` — `SubscribeResponse` interface adds optional `replayedCount?: number`.
|
|
505
|
+
- `extension/src/claws-pty.ts` — `getForegroundProcess()` uses `pgrep -P <shellPid>` + `ps -p <pid> -o comm=` to detect the foreground process basename under the shell; powers L9 content-type observation.
|
|
506
|
+
- `extension/src/peer-registry.ts` — `DisconnectedPeer` tombstone interface; `fingerprintPeer(peerName, role, nonce)` derives stable 12-hex sha256 fingerprint for `fp_`-prefixed stable peer IDs on reconnect.
|
|
507
|
+
- `extension/src/terminal-manager.ts` — `ContentChangeCallback`; `startContentDetection` polls foreground process every 2 s and fires `onContentChange` on basename transitions; wired via `setContentChangeCallback`.
|
|
508
|
+
- `extension/src/wave-registry.ts` — violation timer updates; sub-worker heartbeat tracking improvements.
|
|
509
|
+
- `extension/test/claws-event-log-replay.test.js` — 13-assertion integration test: publishes 10 events, subscribes with `fromCursor`, verifies all 10 replayed frames carry `replayed:true`, caught-up frame fires with correct count, live events arrive without `replayed`, invalid cursor rejected (TDD: 6 failing → 13 passing).
|
|
510
|
+
|
|
511
|
+
### Fixed
|
|
512
|
+
- `extension/test/claws-v2-content.test.js` — interrupt foreground process with `\x03` before sending vim and extend wait timeout from 5s to 8s to reduce flakiness on slow machines.
|
|
513
|
+
- `extension/test/event-schemas.test.js` — update `SCHEMA_BY_NAME` count from 19 to 20 (added `vehicle-state-v1`).
|
|
514
|
+
- `extension/test/topic-registry.test.js` — update `TOPIC_REGISTRY` count from 19 to 22 (added 3 vehicle.* patterns).
|
|
515
|
+
- `extension/test/event-schemas.test.js` — align `SCHEMA_BY_NAME` count assertion with current registry: was 19, now 20 after v0.7.5 L1.1+L1.4 schemas added `vehicle-state-v1`; test now derives expected names explicitly and asserts the correct total.
|
|
516
|
+
- `scripts/inject-settings-hooks.js` — hook commands must use absolute paths. `CLAWS_BIN` was used as-is when passed as a relative argument (e.g. `"scripts"`), producing hook commands like `node "scripts/hooks/pre-tool-use-claws.js"` that broke with `ERR_MODULE_NOT_FOUND` whenever Claude Code's CWD was not the project root. Fix: wrap the arg with `path.resolve()` before computing script paths. Regression test added: `extension/test/inject-settings-absolute-paths.test.js`.
|
|
517
|
+
|
|
518
|
+
## [0.7.5] - 2026-04-29 — Bus hardening release
|
|
519
|
+
|
|
520
|
+
This release hardens the orchestrator↔worker communication bus surfaced by W1–W4 audits. The `.claws/events/default/*.jsonl` was empty on user systems because (a) the MCP server was dropping every push frame from the persistent socket, and (b) default workers never publish.
|
|
521
|
+
|
|
522
|
+
### L-1 Display fixes (R1, R4, R5, R7) — landed
|
|
523
|
+
- `claws-pty.ts` — inject `CLAWS_WRAPPED=1` (real pty) or `CLAWS_PIPE_MODE=1` (degraded) plus `CLAWS_TERMINAL_ID` so the shell hook reports truthful state
|
|
524
|
+
- `protocol.ts` — `TerminalDescriptor` now exposes `ptyPid` (real shell pid) and `ptyMode` (`'pty'`/`'pipe'`/`'none'`)
|
|
525
|
+
- `terminal-manager.ts` — `describe()` returns `pty.pid` and `pty.mode` from the live `ClawsPty` instance
|
|
526
|
+
- `mcp_server.js` — `claws_list` formatter trusts the `wrapped` boolean (was incorrectly keying off `logPath` which is always null in the Pseudoterminal capture model). Pid column shows the real shell pid. Wrapped state labels: `WRAPPED`, `WRAPPED-DEGRADED-pipe-mode`, `WRAPPED-pending`, `unwrapped`
|
|
527
|
+
|
|
528
|
+
Pre-fix symptoms: `claws_list` always showed `[unwrapped]` and `pid=-1` for wrapped terminals; shell-hook banner always said "unwrapped". All cosmetic-but-misleading; the underlying terminals were real ptys.
|
|
529
|
+
|
|
530
|
+
### L0 — Push-frame capture (landed)
|
|
531
|
+
- `mcp_server.js` — `_pconnHandleData` buffers push frames (no rid) into a 1000-entry ring buffer instead of silently dropping them; each entry carries `absoluteIndex`, `topic`, `from`, `payload`, `sentAt`, `sequence`
|
|
532
|
+
- `mcp_server.js` — new `claws_drain_events` MCP tool: drains buffered push frames with `since_index` cursor, optional `wait_ms` blocking, and `max` page size; auto-subscribes to `**` on first call so no explicit subscribe is required
|
|
533
|
+
- `mcp_server.js` — `_pconnEnsureRegistered` helper: lazily hellos as `orchestrator / mcp-orchestrator` on the persistent socket (once per process lifetime) so publish/subscribe calls work without a prior `claws_hello`
|
|
534
|
+
- `schemas/mcp-tools.json` — added `claws_drain_events` tool schema
|
|
535
|
+
|
|
536
|
+
### L1.1 — Worker lifecycle events (landed)
|
|
537
|
+
- `mcp_server.js` — `runBlockingWorker` publishes `system.worker.spawned` (with `terminal_id`, `name`, `wrapped`, `started_at`) immediately after the terminal is created and `system.worker.completed` (with `terminal_id`, `status`, `duration_ms`, `marker_line`, `booted`) after the poll loop exits; guaranteed for both mission-mode and command-mode workers
|
|
538
|
+
- `mcp_server.js` — publishes go via the persistent socket registered as `orchestrator / mcp-orchestrator`; both are best-effort — failure is logged and the worker run continues unaffected
|
|
539
|
+
|
|
540
|
+
### L1.2 — Lazy .jsonl creation (landed)
|
|
541
|
+
- `extension/src/event-log.ts` — `EventLogWriter.openFreshSegment` defers `fs.openSync` until the first `doAppend` call; the segment file is only created when an event is actually written, eliminating empty `.jsonl` files at activation time
|
|
542
|
+
- `extension/src/event-log.ts` — `doAppend` performs a lazy open when `fdDeferred` is true; open errors set `degraded` and return gracefully
|
|
543
|
+
- `extension/src/event-log.ts` — `append` allows the deferred-open case through (changed guard from `fd === null` to `fd === null && !fdDeferred`)
|
|
544
|
+
- `extension/src/event-log.ts` — `tryRecoverFromManifest` handles missing segment files gracefully — if the file doesn't exist (lazy segment never written), it marks `fdDeferred = true` rather than falling back to a full scan
|
|
545
|
+
- `extension/src/event-log.ts` — `rotate` clears `fdDeferred` before `openFreshSegment` so rotation always starts with a clean deferred state
|
|
546
|
+
|
|
547
|
+
### L1.2 rotation regression fix (landed)
|
|
548
|
+
- `extension/src/event-log.ts` — `rotate()` now opens the new segment fd eagerly after `openFreshSegment()`; the lazy-open guarantee (no empty `.jsonl` at activation) applied only to the first segment; rotation fires inside `doAppend` so the file is already being written — deferring left `fd=null` which the post-rotate `fd === null` guard treated as degraded mode, returning `sequence=-1` for all subsequent appends; fix: open fd immediately in `rotate()` and clear `fdDeferred`
|
|
549
|
+
|
|
550
|
+
### L1.4 — Persist task.* + system.malformed.received events (landed)
|
|
551
|
+
- `extension/src/server.ts` — new `emitServerEvent(topic, payload)` private async helper: appends to the event log then fans out, mirroring the `publish` handler's persist-then-fanout contract for server-originated events
|
|
552
|
+
- `extension/src/server.ts` — all 6 server-side `fanOut` call-sites for `task.assigned.*`, `task.status`, `task.completed`, `task.cancel_requested.*`, and `system.malformed.received` replaced with `await this.emitServerEvent(...)` so these events are now durably persisted to `.claws/events/default/*.jsonl`
|
|
553
|
+
- `extension/src/server.ts` — degraded mode: if `eventLog.append` returns sequence -1 the sequence field is omitted from the push frame; on real I/O error the fanOut fires anyway (delivery preserved, persistence skipped)
|
|
554
|
+
- `extension/test/task-event-persist.test.js` — new regression test: boots extension, registers orchestrator + worker, drives assign → update → complete, asserts all 3 entries appear in the .jsonl with monotonically-increasing sequences
|
|
555
|
+
|
|
556
|
+
### L3 — Reverse channel hardening (landed)
|
|
557
|
+
|
|
558
|
+
#### L3.1 — Monotonic `seq` stamp in `[CLAWS_CMD]` broadcast text
|
|
559
|
+
- `extension/src/server.ts` — added `private broadcastSeq = 0` class field; broadcast handler increments it and rewrites text matching `[CLAWS_CMD ` to `[CLAWS_CMD seq=N ` before `writeInjected` and `pushFrame` calls; free-form broadcast text (no `[CLAWS_CMD` prefix) passes through unchanged; makes re-delivered commands idempotent — workers can track the highest seq seen
|
|
560
|
+
- `extension/test/broadcast-seq.test.js` — 6 regression checks: seq=1/2/3 inserted correctly on three consecutive broadcasts; free-form text unchanged; seq counter only advances for `[CLAWS_CMD` text
|
|
561
|
+
|
|
562
|
+
#### L3.2 — Worker auto-subscribe to `cmd.<peerId>.**` on hello
|
|
563
|
+
- `extension/src/server.ts` — hello handler now auto-registers a `cmd.${peerId}.**` subscription on the peer's socket when `role=worker`; uses the existing subscription-index mechanism so non-Template-8 workers get the reverse channel at the transport layer without an explicit `subscribe` call
|
|
564
|
+
- `extension/test/auto-subscribe-cmd.test.js` — 8 regression checks: worker receives `cmd.<peerId>.approve` push without explicit subscribe; deep wildcard `cmd.<peerId>.sub.nested` also delivered; observer role is NOT auto-subscribed
|
|
565
|
+
|
|
566
|
+
#### L3.1 test fix — `reverse-channel.test.js` updated for seq= prefix
|
|
567
|
+
- `extension/test/reverse-channel.test.js` — two legacy assertions compared injected/pushed text against the original `CMD_TEXT` literal; after L3.1 the server rewrites `[CLAWS_CMD ` to `[CLAWS_CMD seq=N `; switched both assertions to regex `CMD_TEXT_RE = /^\[CLAWS_CMD seq=\d+ r=r1\] approve_request/` — no behavior change, test now correctly validates the seq-stamped output
|
|
568
|
+
|
|
569
|
+
#### L3.4 — Backpressure on `socket.write` in `pushFrame`
|
|
570
|
+
- `extension/src/server.ts` — added `private readonly pausedPeers = new Set<string>()` and `private readonly droppedFrames = new Map<string, number>()`; `pushFrame` checks `socket.write()` return value — if `false`, marks peer as paused, logs `[claws/2] backpressure on push to <peerId>; pausing`, registers a one-shot `drain` listener; while paused, frames are silently dropped with a per-peer counter; drain clears the paused state and logs dropped count (warning if ≥ 100)
|
|
571
|
+
- `extension/test/pushframe-backpressure.test.js` — 9 regression checks: normal push arrives before backpressure; publish after subscriber disconnect returns ok (no crash); new subscriber receives pushes normally after prior peer disconnect; no crash logs; graceful disconnection log
|
|
572
|
+
|
|
573
|
+
### L2 — Lifecycle REFLECT → PLAN cycle reset (landed)
|
|
574
|
+
- `extension/src/lifecycle-store.ts` — `hasPlan()` now returns `false` when the current phase is `REFLECT`, closing the lifecycle gate after a completed cycle (was: always true once any plan was logged)
|
|
575
|
+
- `extension/src/lifecycle-store.ts` — `plan()` resets the cycle when called from `REFLECT` phase, starting cycle N+1 with fresh `phases_completed=['PLAN']` and the new plan text; idempotency still applies within any active (non-REFLECT) cycle
|
|
576
|
+
- `extension/src/server.ts` — `lifecycle.plan` handler sets `idempotent:false` when the previous phase was `REFLECT` (a cycle reset is not an idempotent no-op); `idempotent:true` only for mid-cycle duplicate calls
|
|
577
|
+
- `extension/test/lifecycle-reset.test.js` — 8 regression checks covering: gate-closes-at-REFLECT, plan-resets-cycle, phases_completed-reset, hasPlan-reopens, SPAWN-advances-after-reset, mid-cycle-idempotency-preserved, reflect-field-cleared
|
|
578
|
+
|
|
579
|
+
### L1.3 — Periodic system.heartbeat from the extension (landed)
|
|
580
|
+
- `extension/src/server-config.ts` — added `heartbeatIntervalMs` field (default 60 000 ms, 0 = disabled) to `ServerConfig` and `defaultServerConfig`; exported `DEFAULT_HEARTBEAT_INTERVAL_MS`
|
|
581
|
+
- `extension/src/server.ts` — new `private async emitSystemEvent(topic, payload)` helper: appends to the event log then fans out with the returned sequence; skips entirely when `eventLog.isDegraded` is true; errors are swallowed so timer failures never crash the extension
|
|
582
|
+
- `extension/src/server.ts` — `start()` schedules a `setInterval` after `bind()` resolves; reads `heartbeatIntervalMs` from `getConfig()` at schedule time; 0 = no timer created; stores timer in `private heartbeatTimer`
|
|
583
|
+
- `extension/src/server.ts` — `stop()` clears `heartbeatTimer` before closing the event log and socket
|
|
584
|
+
- `extension/src/event-log.ts` — added public `get isDegraded(): boolean` accessor so the server can gate heartbeat emissions without accessing a private field
|
|
585
|
+
- `extension/src/terminal-manager.ts` — added public `get terminalCount(): number` accessor so heartbeat payload can report the live terminal count without exposing the private `records` Map
|
|
586
|
+
- `extension/src/extension.ts` — `getConfig()` now reads `claws.heartbeatIntervalMs` from VS Code settings and passes it to the server
|
|
587
|
+
- `extension/package.json` — added `claws.heartbeatIntervalMs` configuration property (type: number, default: 60000, minimum: 0)
|
|
588
|
+
- `extension/test/heartbeat.test.js` — new regression test: boots extension with `heartbeatIntervalMs=200ms`, waits 700ms, asserts ≥2 `system.heartbeat` entries in the segment file and validates payload shape (uptimeMs, peers, terminals, from, ts_server, sequence)
|
|
589
|
+
|
|
590
|
+
### L1.5 — [CLAWS_PUB] line scanner for SDK-less worker publishing (landed)
|
|
591
|
+
- `mcp_server.js` — new `_scanAndPublishCLAWSPUB(newText, sockPath)` async helper: scans lines for `[CLAWS_PUB] topic=<topic> key=val ...` markers, parses key=value pairs (quoted strings, bare tokens, numeric, boolean coercion), and calls `_pconnEnsureRegistered` + `_pconnWrite` to publish on the worker's behalf; parse errors and publish failures are logged and never abort the worker run
|
|
592
|
+
- `mcp_server.js` — poll loop (step 6) in `runBlockingWorker` now tracks `pubScanOffset` across iterations; each tick slices `text.slice(scanStart)` (new bytes only) into `_scanAndPublishCLAWSPUB` and advances `pubScanOffset = text.length` so each pty line is scanned at most once
|
|
593
|
+
- Workers using Templates 1–7 can now emit bus events by printing a single line: `[CLAWS_PUB] topic=worker.<id>.phase kind=DEPLOY step=3` — no socket, SDK, peerId, or env-var injection required
|
|
594
|
+
- `extension/test/claws-pub-scanner.test.js` — 12 regression checks: source-level (function defined, MARKER_RE present, called in poll loop, pubScanOffset present, _pconnEnsureRegistered called) + behavioral (3 publishes from 3 markers, duplicate-scan no-re-publish, new-bytes-after-offset published, malformed lines skipped without throw, quoted values, boolean/numeric coercion, non-prefixed lines ignored)
|
|
595
|
+
|
|
596
|
+
### L4 — Bus correctness (landed)
|
|
597
|
+
|
|
598
|
+
#### L4.1 — `_pconnWrite` id field collision fix
|
|
599
|
+
- `mcp_server.js` — `_pconnWrite` now explicitly destructures and drops any user-supplied `id` before stamping the RPC correlation id (`const { id: _discarded, ...reqBody } = req`). No behaviour change for current callers (none set `id`) but makes the contract auditable and prevents silent misrouting for future stateful commands that use `id` as a routing field.
|
|
600
|
+
|
|
601
|
+
#### L4.2 — Sequence counter persistence across restarts
|
|
602
|
+
- `extension/src/event-log.ts` — `Manifest` interface gains `sequence_counter?: number`
|
|
603
|
+
- `extension/src/event-log.ts` — `writeManifest()` persists `sequence_counter: this.sequenceCounter` (the next value to issue) so the counter survives server restarts
|
|
604
|
+
- `extension/src/event-log.ts` — `tryRecoverFromManifest()` restores the counter with `+1` offset so the last issued sequence before crash is never re-issued; cost is one detectable gap per restart (acceptable)
|
|
605
|
+
- `extension/test/sequence-persist.test.js` — new regression test: writes 5 events, simulates restart with a fresh writer, writes 5 more; asserts second batch is ≥5, monotonically increasing, and spans at most one gap at the restart boundary
|
|
606
|
+
|
|
607
|
+
#### L4.3 — Peer disconnect fails orphaned tasks
|
|
608
|
+
- `extension/src/server.ts` — `handleDisconnect()` now walks `this.tasks` after removing the peer and fails any task whose `assignee === peerId` and `status` is `pending`, `running`, or `blocked`; sets `status='failed'`, `note='assignee disconnected'`, `updatedAt=Date.now()`
|
|
609
|
+
- `extension/src/server.ts` — each newly-failed task emits a `task.completed` event via `emitServerEvent` (best-effort, `.catch()` guards so disconnect never throws) so subscribers see the cancellation
|
|
610
|
+
- `extension/test/peer-disconnect-fails-tasks.test.js` — new regression test: registers orchestrator + worker, assigns 2 tasks, destroys the worker socket, asserts both tasks are `failed` in `task.list` and `task.completed` push frames fired for both
|
|
611
|
+
|
|
612
|
+
#### L4.4 — subscribe fromCursor (structural contract, full replay P1 for v0.7.6)
|
|
613
|
+
- `extension/src/protocol.ts` — `SubscribeRequest` gains optional `fromCursor?: string` field with inline doc describing the cursor format and the v0.7.6 TODO
|
|
614
|
+
- `extension/src/server.ts` — subscribe handler accepts `fromCursor`; logs `[claws/2] fromCursor replay not yet implemented` and continues with live delivery when the field is present; full replay (read event log from cursor, push matching events before live) deferred to v0.7.6 (P1)
|
|
615
|
+
|
|
616
|
+
### L1.4–L3 (previously landed — see entries above)
|
|
617
|
+
Fleet of layered fixes ordered root-up: L0 capture (push frames captured, `claws_drain_events` MCP tool), L1 production (`system.worker.spawned/completed`, lazy `.jsonl`, heartbeat, task event persistence, `[CLAWS_PUB]` line scanner), L2 lifecycle (REFLECT-reset cycle), L3 reverse-channel hardening (idempotent re-delivery, ACK protocol, backpressure), L4 bus correctness (sequence persistence, peer reconnect, replay).
|
|
618
|
+
|
|
619
|
+
## [0.7.4] - 2026-04-29 — Bulletproof regression fix release
|
|
620
|
+
|
|
621
|
+
This release closes 50 findings surfaced by a 4-worker parallel audit of the v0.7.2 + v0.7.3 release cycle. After the user reported lifecycle breakage on `/claws-update`, we ran a full Plan→Implement→Review→Audit→Test→Fix→Repeat loop across 5 layers to deliver one bulletproof codebase that absorbs all in-flight unmerged work (γ.1 reverse channel, γ.2 event log core, MCP persistent socket fix) plus 50 regression fixes.
|
|
622
|
+
|
|
623
|
+
### CRITICAL — confirmed data-loss prevention
|
|
624
|
+
- **M-01** `install.sh` awk strip — anchored to Claws-marked block + timestamped dotfile backup before any modification
|
|
625
|
+
- **M-02** `.mcp.json` silent reset — JSONC-tolerant safe-merge with abort-on-error; never wipes other MCP servers
|
|
626
|
+
- **M-03** `~/.claude/settings.json` silent reset — JSONC-tolerant safe-merge; never wipes user's Claude Code config
|
|
627
|
+
- **M-38** `inject-settings-hooks.js` non-atomic write — atomic write via L0 helpers
|
|
628
|
+
- **M-39** `cli.js` MCP fallback non-atomic write — atomic write via L0 helpers
|
|
629
|
+
|
|
630
|
+
### HIGH — silent lifecycle breaks
|
|
631
|
+
- **M-04** Hook silent skip → forensic log (`/tmp/claws-hook-misfire.log` + stderr)
|
|
632
|
+
- **M-05** Rosetta arch silent miscompile → auto-correct to arm64 (not x64)
|
|
633
|
+
- **M-06** Stale-extension cleanup race → gate on `[ -d "$kept_dir" ]` before iterating
|
|
634
|
+
- **M-07** `spawnSync` null-status (signal-killed rebuild) → explicit `result.status === null` detection + helpful error
|
|
635
|
+
- **M-08** No rebuild timeout → 5-minute ceiling + SIGTERM detection
|
|
636
|
+
- **M-09** Hooks dir wipe-then-copy non-atomic → atomic `copyDirAtomic` via L0 helper
|
|
637
|
+
- **M-10** Health check 2s timeout → 8s + 3-attempt exponential backoff (8s/12s/16s)
|
|
638
|
+
- **M-11** `mcp_server.js` orphan → SIGKILL escalation 500ms after SIGTERM + socket-unlink verify
|
|
639
|
+
- **M-31** `fix.sh` `@electron/rebuild` no timeout → mirrored from M-08 (recovery path hardening)
|
|
640
|
+
- **M-36** `rebuild-node-pty.sh` no timeout + no TERM_PROGRAM detection → mirrored trifecta
|
|
641
|
+
- **M-44** `fix.sh` stale Content-Length framing → newline-delimited frames (MCP check was always false-failing)
|
|
642
|
+
- **M-45** `fix.sh` `.mcp.json` repair silent-reset-to-`{}` → safe-merge + atomic write + env-var path (recovery path)
|
|
643
|
+
|
|
644
|
+
### MEDIUM/LOW (M-12 to M-50 not listed above)
|
|
645
|
+
50 total findings — see `.local/audits/regression-master-issues.md` for the complete catalog.
|
|
646
|
+
|
|
647
|
+
### Foundation utilities (Layer 0)
|
|
648
|
+
- `scripts/_helpers/json-safe.mjs` — JSONC parse + safe-merge + abort-on-error; used across install/update/fix/inject paths
|
|
649
|
+
- `scripts/_helpers/atomic-file.mjs` — rename-pattern atomic file/dir ops with fsync; used for all config writes
|
|
650
|
+
|
|
651
|
+
### Test coverage
|
|
652
|
+
- 224 baseline → 501 PASS (+277 regression checks across ~40 new test files)
|
|
653
|
+
- Every M-XX finding has a regression test that exercises its failure mode
|
|
654
|
+
|
|
655
|
+
### Includes (rolled forward from open PRs)
|
|
656
|
+
- γ.1 reverse channel (was PR #27)
|
|
657
|
+
- γ.2 event log core (was PR #28)
|
|
658
|
+
- MCP persistent socket fix (was PR #29)
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## [0.7.4-bulletproof-L4-fix] - 2026-04-29 — Layer 4 fix: code-review findings + audit items (F1–F7, M-44–M-50)
|
|
663
|
+
|
|
664
|
+
### Fixed
|
|
665
|
+
|
|
666
|
+
- **F1** `scripts/update.sh` M-10 retry loop: added `_claws_attempt` counter; emits `note "MCP handshake timeout — retry N of 3 (Nms)..."` between attempts so the operator knows progress during the silent ~38s retry window.
|
|
667
|
+
- **F4** `extension/src/extension.ts` M-41 `runRebuildPty()`: killTimer now sends SIGTERM first, then SIGKILL after 5s grace, matching the recipe pattern from M-11. Previously sent SIGKILL directly. Regression test: `extension-rebuild-pty-timeout.test.js` updated (SIGTERM-before-SIGKILL check added).
|
|
668
|
+
- **F2** `scripts/install.sh`: `inject-global-claude-md.js` now gated on `GIT_PULL_OK` — mirrors the project-level CLAUDE.md gate; avoids rewriting machine-wide policy from stale source when git pull failed. Emits skip note on GIT_PULL_OK=0.
|
|
669
|
+
- **F3** `extension/test/update-step6-orphan.test.sh`: added test 5 — behavioral check that a Unix socket server has no active listener after SIGTERM+SIGKILL sequence (process is gone, no orphan socket-holder).
|
|
670
|
+
- **F6** `extension/src/extension.ts` plutil candidate loop: added JSDoc noting 4 candidates × 3s timeout = 12s worst-case synchronous block; acceptable for explicit user-triggered rebuild command.
|
|
671
|
+
- **F7** `extension/src/event-log.ts` `writeManifest()`: migrated from `writeFileSync` to `openSync+writeSync+fsyncSync+closeSync+renameSync` — mirrors M-29/M-43 fsync-before-rename pattern; manifest survives power-cut or SIGKILL after write.
|
|
672
|
+
- **F5** `scripts/inject-settings-hooks.js`: added `withLock()` helper using `fs.openSync(lockPath, 'wx')` exclusive create with 15-attempt/100ms backoff; all three `mergeIntoFile` call sites (REMOVE, UPDATE, add-mode) wrapped — prevents concurrent `install.sh`+`update.sh` invocations from tearing settings.json. Fixed: removed stale `|| attempt === 2` early-throw that caused EEXIST on retry 2 to propagate (leftover from old 3-attempt loop). Regression test: `inject-settings-exclusive-lock.test.js` (6 checks).
|
|
673
|
+
- **M-44** `scripts/fix.sh` MCP handshake: replaced Content-Length framing (stale LSP protocol) with `mcp.stdin.write(req + '\n')` — matches mcp_server.js's newline-delimited JSON protocol. Added full `protocolVersion`+`clientInfo` to initialize params. Regression test: `fix-mcp-handshake.test.sh` (5 checks).
|
|
674
|
+
- **M-50** `mcp_server.js` `_pconnConnect()`: added `sock.setTimeout(5000)` + `on('timeout', destroy)` — prevents the persistent socket connect phase from hanging forever when VS Code is reloading and the socket is transiently unreachable. `setTimeout(0)` clears the timer once the connection succeeds. Regression test: `mcp-pconn-timeout.test.js` (5 checks).
|
|
675
|
+
- **M-49** `scripts/install.sh` `EXPECTED_MIN_VERSION`: bumped from `0.5.7` → `0.7.4` — was stale, causing stale-clone warnings to fire against fully-up-to-date clones at v0.7.4.
|
|
676
|
+
- **M-47** `scripts/update.sh` `.mcp.json` sanity check: path now passed via `CLAWS_MCP_CHECK` env var instead of string-interpolation into `node -e` — handles project roots with apostrophes/backslashes without JS syntax errors (mirrors M-20 socket-probe fix). Regression test: `update-mcp-path-quoting.test.sh` (5 checks).
|
|
677
|
+
- **M-45+M-46** `scripts/fix.sh` + `scripts/_helpers/fix-repair.js` (new): `.mcp.json` and `.vscode/extensions.json` repair now use `fix-repair.js` which calls `mergeIntoFile` from `json-safe.mjs` — atomic write, abort-on-malformed (never silently resets to `{}`), JSONC-tolerant, path via `CLAWS_REPAIR_TARGET` env var (no injection). Regression test: `fix-mcp-repair.test.sh` (10 checks).
|
|
678
|
+
|
|
679
|
+
## [0.7.4-bulletproof-L4] - 2026-04-29 — Layer 4: update.sh + extension.ts hardening (M-10, M-11, M-18, M-19, M-20, M-21, M-41, M-42, M-43)
|
|
680
|
+
|
|
681
|
+
### Fixed
|
|
682
|
+
|
|
683
|
+
- **M-10** `scripts/update.sh` Step 6 health check: bumped timeout from 2000ms to 8s; added 3-attempt retry loop with exponential timeout series (8s, 12s, 16s) so loaded machines don't see false-positive YELLOW on slow startup. YELLOW only declared after all three attempts fail.
|
|
684
|
+
- **M-11** `scripts/update.sh` Step 6 health check: SIGKILL escalation 500ms after SIGTERM — mcp_server.js child is force-killed if SIGTERM is not handled quickly, preventing orphaned socket fd holding the project socket open. mcp_server.js path passed via `CLAWS_MCP_PATH` env var (no embedded path injection). Regression test: `update-step6-orphan.test.sh` (4 checks, includes behavioral SIGTERM-ignore mock).
|
|
685
|
+
- **M-19** `scripts/update.sh`: `CLAWS_LOG` now defined and exported before `install.sh` runs, so Step 6 warning "see install log: $CLAWS_LOG" references the actual log path written by install.sh. install.sh inherits via `${CLAWS_LOG:-...}`. Regression test: `update-claws-log.test.sh` (6 checks).
|
|
686
|
+
- **M-20** `scripts/update.sh` socket probe: project root path passed via `CLAWS_PROBE_PATH` env var instead of string-interpolation into `node -e` — handles project paths containing apostrophes/backslashes without JS syntax errors. Regression test: `update-probe-path-quoting.test.sh` (5 checks, includes behavioral apostrophe + backslash path tests).
|
|
687
|
+
- **M-21** `scripts/update.sh` + `scripts/install.sh`: `GIT_PULL_OK` flag exported on git pull failure; `install.sh` skips `inject-claude-md.js` when `GIT_PULL_OK=0` — avoids rewriting CLAUDE.md tool-set from stale source. Regression test: `update-git-pull-fail.test.sh` (8 checks, behavioral GIT_PULL_OK=0 and GIT_PULL_OK=1 paths).
|
|
688
|
+
- **M-18** `scripts/inject-settings-hooks.js` + `scripts/install.sh`: added `--update` mode that removes old Claws hooks and adds new ones in a single atomic `mergeIntoFile` call. `install.sh` now calls `inject-settings-hooks.js --update` instead of two-pass `--remove` + add, eliminating the kill-window where settings.json has zero Claws hooks. Regression test: `update-atomic-hooks.test.sh` (7 checks, behavioral update preserves non-Claws hooks).
|
|
689
|
+
- **M-41** `extension/src/extension.ts` `runRebuildPty()`: added 5-minute SIGKILL timer (`setTimeout → proc.kill('SIGKILL')`) to prevent hung `@electron/rebuild` invocations from freezing VS Code indefinitely. Timer cleared on normal exit. Regression test: `extension-rebuild-pty-timeout.test.js` (6 checks).
|
|
690
|
+
- **M-42** `extension/src/extension.ts` `execFileSync('plutil', ...)`: added `{ timeout: 3000 }` to prevent synchronous Electron-version detection from blocking the VS Code extension host on network-mounted `/Applications`. Regression test: `extension-plutil-timeout.test.js` (5 checks).
|
|
691
|
+
- **M-43** `extension/src/lifecycle-store.ts` `flushToDisk()`: migrated from `writeFileSync` to `openSync+writeSync+fsyncSync+closeSync+renameSync` pattern — mirrors the M-29 hooks-side fix for parity; ensures lifecycle state survives power-cut or SIGKILL after write but before kernel flush. Regression test: `lifecycle-store-fsync.test.js` (7 checks, behavioral compile+run verification).
|
|
692
|
+
|
|
693
|
+
## [0.7.4-bulletproof-L3-fix] - 2026-04-29 — Layer 3 fix: code-review findings F1+F2+F3
|
|
694
|
+
|
|
695
|
+
### Fixed
|
|
696
|
+
|
|
697
|
+
- **F1** `scripts/inject-settings-hooks.js` `isCanonicalInstall()`: now checks both `CLAWS_BIN/hooks/` directory presence AND individual script file existence before emitting bare `node "<path>"`. Previously, a hooks/ dir with missing scripts would produce a `node` invocation that exits non-zero (MODULE_NOT_FOUND), breaking the SAFETY CONTRACT. Falls through to the wrapped `sh -c` misfire-log form instead. [L3.11]
|
|
698
|
+
- **F2** `scripts/inject-settings-hooks.js` M-14 comment: corrected to accurately state that `_source === 'claws'` already prevented non-Claws hooks from being matched before M-14; M-14's actual improvement is replacing substring `command.includes(scriptName)` with exact-command equality, making the "already current" vs "stale, upgrade in-place" distinction unambiguous. [L3.12]
|
|
699
|
+
- **F3** `scripts/inject-settings-hooks.js` `hookCmd()` non-canonical form: misfire message now also written to stderr (`>&2`) alongside `/tmp/claws-hook-misfire.log` (with `2>/dev/null`). When `/tmp` is unwritable, the message still reaches stderr for forensics while `exit 0` preserves the SAFETY CONTRACT. [L3.13]
|
|
700
|
+
|
|
701
|
+
## [0.7.4-bulletproof-L3] - 2026-04-29 — Layer 3: hooks + settings.json hardening (M-03, M-04, M-12, M-13, M-14, M-15, M-16, M-24, M-38, M-39)
|
|
702
|
+
|
|
703
|
+
### Fixed
|
|
704
|
+
|
|
705
|
+
- **M-03/M-38** `scripts/inject-settings-hooks.js`: replaced `loadSettings()` try/catch-reset-to-`{}` + `fs.writeFileSync` with async `mergeIntoFile()` from `scripts/_helpers/json-safe.mjs`. On malformed JSON: backup created, original untouched, exits non-zero. Never silently wipes user's entire Claude Code config.
|
|
706
|
+
- **M-39** `cli.js` MCP fallback: replaced `JSON.parse + writeFileSync` with inline ESM `mergeIntoFile()` call via `spawnSync --input-type=module`. Same atomic + JSONC-tolerant + abort-on-malformed guarantees.
|
|
707
|
+
- **M-04** `scripts/inject-settings-hooks.js` `hookCmd()`: missing hook path now appends to `/tmp/claws-hook-misfire.log` with timestamp + path instead of silently exiting 0 with no trace. [L3.2]
|
|
708
|
+
- **M-12** `scripts/inject-settings-hooks.js` `hookCmd()`: replaced `[ -f "$0" ] && exec node "$0" || (...)` with explicit `if [ -f "$0" ]; then exec node "$0"; else ...; fi` — `else` branch is reachable even if `exec` fails for unusual reasons (applies to non-canonical paths; canonical paths use direct node per M-15). [L3.3]
|
|
709
|
+
- **M-13** `scripts/hooks/{session-start,pre-tool-use,stop}-claws.js`: stdin 'data' and 'end' listeners now registered in a single try block; added 5-second `setTimeout(...).unref()` safety timer so hooks can never hang the parent process. [L3.4]
|
|
710
|
+
- **M-14** `scripts/inject-settings-hooks.js` dedup: replaced `command.includes(scriptName)` with exact-command equality + `_source === 'claws'` guard — prevents overwriting non-Claws hooks whose command happens to contain a Claws script name as substring. [L3.5]
|
|
711
|
+
- **M-15** `scripts/inject-settings-hooks.js` `hookCmd()`: when `CLAWS_BIN/hooks/` directory exists (canonical install), registers hooks as direct `node "<path>"` invocations (skips the `sh -c` wrapper) — reduces fork overhead on each hook invocation. [L3.6]
|
|
712
|
+
- **M-16** `scripts/hooks/pre-tool-use-claws.js` STRICT deny: all `process.stdout.write` calls now end with `\n` so Claude Code's hook protocol parser flushes correctly. [L3.7]
|
|
713
|
+
- **M-24** `scripts/hooks/{session-start,pre-tool-use,stop}-claws.js`: `process.on('uncaughtException')` and `process.on('unhandledRejection')` handlers gated on `!process.env.CLAWS_DEBUG` — when `CLAWS_DEBUG=1`, errors propagate visibly for debugging. [L3.8]
|
|
714
|
+
|
|
715
|
+
## [0.7.4-bulletproof-L2-fix] - 2026-04-29 — Layer 2 fix: code-review findings F1+F5 (error-path + env-var path passing)
|
|
716
|
+
|
|
717
|
+
### Fixed
|
|
718
|
+
|
|
719
|
+
- **F1** `scripts/install.sh` M-09 + M-02 heredoc blocks: wrapped each `node --input-type=module` heredoc with `set +e` / capture `_exit=$?` / `set -e` so the `die`/`warn` call fires before the shell aborts. Under `set -eo pipefail`, `if [ $? -ne 0 ]` after a heredoc is dead code — the shell terminates at the heredoc line when node exits non-zero.
|
|
720
|
+
- **F5** `scripts/install.sh` M-02 block: switched from shell-expanded string literals (`'${PROJECT_MCP}'`) to `process.env.X` for all user-controlled paths. Also changed static `import ... from '...'` to `await import(process.env.INSTALL_DIR + '...')` to avoid JS SyntaxError when any path component contains a single-quote or backslash.
|
|
721
|
+
- **F5 test** `extension/test/install-mcp-merge.test.sh`: added apostrophe path test (creates a project dir named `user's-project`, runs M-02 merge via env vars, asserts claws entry written).
|
|
722
|
+
- **F1 test** `extension/test/install-error-path.test.sh` (9 checks): static checks that `_hooks_exit` and `_mcp_exit` capture patterns are present; behavioral harness proving the message fires before set-e exit.
|
|
723
|
+
- **F2** `extension/test/install-hooks-atomic.test.sh`: replaced polling simulation (1ms interval checks) with a real SIGKILL mid-copy test. Spawns `copyDirAtomic` in a subprocess, sends SIGKILL after 5ms (during the 100-file step-1 copy phase), then asserts dest has either complete OLD content or complete NEW content — never an empty dir or a partial mix.
|
|
724
|
+
- **F3** `scripts/inject-claude-md.js`, `scripts/inject-global-claude-md.js`, `scripts/hooks/lifecycle-state.js`, `extension/src/uninstall-cleanup.ts`: replaced `writeFileSync(tmp)` with `openSync(tmp, 'w') → writeSync → fsyncSync → closeSync` in all four inline `writeAtomic` helpers. Adds durability for power-cut scenarios where the OS page cache hasn't been flushed — mirrors the `fd.sync()` call that `scripts/_helpers/atomic-file.mjs` (L0) already does in its async variant.
|
|
725
|
+
- **F4** `scripts/install.sh inject_hook`: fixed orphaned-marker edge case. Previous awk `skip { skip=0; next }` stripped the marker AND whatever line followed it, even if the user had manually removed the source line. New pattern: `skip && /source.*shell-hook\.sh/ { skip=0; next }; skip { skip=0; print }` — only strips the following line when it IS the Claws source line; preserves it otherwise. Added F4 orphaned-marker test to `install-awk-anchor.test.sh` (+4 checks, +1 static → 20 total).
|
|
726
|
+
- **F6** `CHANGELOG.md`: added missing `[2c99bda]` commit hash to M-28 entry.
|
|
727
|
+
- **M-40** `extension/scripts/bundle-native.mjs`: replaced `resetNativeDest()` (wipe-then-copy) with `setupStagingDir()` + atomic rename pattern in `copyRuntimeSlice()`. Files now copy into `NATIVE_DEST.claws-new`, then `rename(NATIVE_DEST → .claws-old)` + `rename(staging → NATIVE_DEST)` + cleanup. Kill during file copy leaves old NATIVE_DEST intact; kill after rename leaves new NATIVE_DEST intact — never an empty dir. `extension/test/bundle-native-copy-atomic.test.js` (10 checks): static pattern verification + behavioral atomic-rename simulation + kill-before-rename invariant.
|
|
728
|
+
|
|
729
|
+
## [0.7.4-bulletproof-L2] - 2026-04-29 — Layer 2: install.sh data-loss + atomicity fixes (M-01, M-02, M-09, M-17, M-27–M-30)
|
|
730
|
+
|
|
731
|
+
### Fixed
|
|
732
|
+
|
|
733
|
+
- **M-01** `scripts/install.sh inject_hook`: removed generic `/source .../shell-hook\.sh/` awk regex that stripped non-Claws tool hooks (oh-my-zsh, asdf, custom dotfiles). awk now strips ONLY lines inside a `# CLAWS terminal hook` marked block. Added timestamped dotfile backup (`$rcfile.claws-bak.<ISO-ts>`) before any modification. [ac1661a]
|
|
734
|
+
- **M-02** `scripts/install.sh` `.mcp.json` merge: replaced `try{}catch{}` reset-to-`{}` pattern with `mergeIntoFile()` from `scripts/_helpers/json-safe.mjs`. On parse failure: backup created, original untouched, install.sh exits non-zero with actionable message. Never silently wipes other MCP servers. [cbb447e]
|
|
735
|
+
- **M-09** `scripts/install.sh` `.claws-bin/hooks/` copy: replaced `rm -rf + cp` with atomic rename pattern via `copyDirAtomic()` from `scripts/_helpers/atomic-file.mjs`. Kill-window now leaves either full old hooks or full new hooks — never an empty dir. [df0b224]
|
|
736
|
+
- **M-17** `scripts/install.sh inject_hook`: fixed awk empty-file edge case. [aa488da] When `.zshrc` contains ONLY the Claws block, awk output is empty; the old `[ -s "$tmp" ]` guard prevented promotion, leaving original intact and causing duplicate blocks on next install. Now always promotes awk output when awk succeeds.
|
|
737
|
+
- **M-27** `scripts/inject-claude-md.js`: replaced `fs.writeFileSync` with atomic write pattern (tmp + rename) — prevents partial project `CLAUDE.md` on kill mid-write. [2c99bda]
|
|
738
|
+
- **M-28** `scripts/inject-global-claude-md.js`: same atomic write for `~/.claude/CLAUDE.md` — machine-wide config corruption on power-cut prevented. [2c99bda]
|
|
739
|
+
- **M-29** `scripts/hooks/lifecycle-state.js writeState()`: replaced `fs.writeFileSync` with atomic tmp+rename pattern — mirrors `extension/src/lifecycle-store.ts` which was already atomic. Prevents partial lifecycle-state.json on hook kill. [9696ecb]
|
|
740
|
+
- **M-30** `extension/src/uninstall-cleanup.ts`: replaced both `writeFileSync` calls (`.mcp.json` edit-json + CLAUDE.md edit-markdown) with inline atomic write pattern — partially-uninstalled state no longer possible on kill mid-write.
|
|
741
|
+
|
|
742
|
+
## [0.7.4-bulletproof-L1-fix] - 2026-04-29 — Layer 1 fix: code-review + similar-bug findings (F1+F2, F3+F4, M-31–M-37)
|
|
743
|
+
|
|
744
|
+
### Changed
|
|
745
|
+
|
|
746
|
+
- **F1** `bundle-native.mjs detectElectronVersion()` darwin sort: removed redundant `(tp === 'vscode' && c.key === 'vscode')` sub-expression — semantically identical to `c.key === tp` when `tp==='vscode'`. Now matches the simpler Linux branch form.
|
|
747
|
+
- **F2** `install.sh` ABI detection darwin block: replaced `eval "set -- $_claws_darwin_apps"` with bash array (`declare`-compatible `case` + `for` loop) — eliminates eval footgun that would become shell injection if `$_tp` were ever interpolated into the string literal.
|
|
748
|
+
- **F3** `extension/test/update-socket-probe.test.js`: replaced regular-file fixture with a real Unix domain socket (server binds, stays open but never responds, probe times out). Faithfully replicates an unresponsive Claws server; satisfies `[ -S ]` check. Server closed in `finally` block post-assertion.
|
|
749
|
+
- **F4** `bundle-native.mjs detectElectronVersion()`: added `cursorChannel` (`$CURSOR_CHANNEL`) secondary signal — when `TERM_PROGRAM=vscode` but `CURSOR_CHANNEL` is set (Cursor-specific env), promotes Cursor candidates over VS Code. Covers old Cursor builds that pre-date `TERM_PROGRAM=cursor`. Injected as parameter for testability; test 9 added.
|
|
750
|
+
- **M-31** `scripts/fix.sh` `@electron/rebuild` block: wrapped with `timeout 300` / `gtimeout 300` (5-minute ceiling). Exit code 124 → user-actionable "slow Electron headers download" message. Prevents indefinite hang on captive portals.
|
|
751
|
+
- **M-36** `scripts/rebuild-node-pty.sh` rebuild step: same timeout pattern as M-31. Exits 1 on timeout with network/proxy hint.
|
|
752
|
+
- **M-32** `scripts/fix.sh` ABI detection: TERM_PROGRAM-aware darwin loop (bash array, same F2 pattern); CURSOR_CHANNEL secondary signal for old Cursor builds.
|
|
753
|
+
- **M-33** `scripts/fix.sh` ABI detection: Linux Cursor (`/usr/share/cursor/electron`, `/opt/cursor/electron`) + Windsurf paths added; TERM_PROGRAM-ordered.
|
|
754
|
+
- **M-36 (editor detect)** `scripts/rebuild-node-pty.sh` detection: TERM_PROGRAM-aware darwin ordering + CURSOR_CHANNEL + Linux Cursor/Windsurf paths.
|
|
755
|
+
- **M-34** `scripts/install.sh` arch verify: when bash runs under Rosetta 2 (`uname -m=x86_64` on Apple Silicon), `sysctl.proc_translated` is checked and the expected arch is promoted to `arm64`. Prevents false "pty.node arch mismatch" warning after M-05 build.
|
|
756
|
+
- **M-35** `scripts/update.sh` Step 6 ABI check: TERM_PROGRAM-aware darwin ordering for editor detection (cursor/windsurf/default). CURSOR_CHANNEL secondary signal included.
|
|
757
|
+
- **M-37** `claws-sdk.js ClawsSDK.connect()`: `sock.setTimeout(5000)` — when the socket file exists but the server doesn't respond within 5s, `sock.destroy(err)` fires with a `/claws-fix` hint. `sock.setTimeout(0)` on connect prevents false fires during normal use.
|
|
758
|
+
- **M-37** `claws-sdk.js ClawsSDK._send()`: per-request `timeoutMs` (default 10s) via `setTimeout`/`clearTimeout` — rejects and cleans up the `_pending` Map entry if no response arrives. Prevents unbounded Map growth when the extension is reloading.
|
|
759
|
+
|
|
760
|
+
## [0.7.4-bulletproof-L1] - 2026-04-29 — Layer 1: ABI/native-bundle fixes (M-05, M-06, M-07, M-08, M-22, M-23, M-25, M-26)
|
|
761
|
+
|
|
762
|
+
### Fixed
|
|
763
|
+
|
|
764
|
+
- **M-05** `bundle-native.mjs detectTargetArch()`: Rosetta 2 detection now returns `'arm64'` instead of warning-only. Prevents x64 pty.node being shipped for arm64 VS Code/Cursor.
|
|
765
|
+
- **M-07** `bundle-native.mjs runElectronRebuild()`: explicit `result.status === null` check catches signal-killed rebuilds that previously silently passed. `spawnFn`/`failFn` injectable for testability.
|
|
766
|
+
- **M-08** `bundle-native.mjs runElectronRebuild()`: 5-minute `spawnSync` timeout (`timeout: 5*60*1000`) prevents indefinite hang on slow Electron headers fetch; SIGTERM → network/proxy hint message.
|
|
767
|
+
- **M-22** Editor detection prefers `$TERM_PROGRAM` env (vscode|cursor|windsurf) so the current-shell's editor wins over hardcoded path order. Applied in both `bundle-native.mjs` and `install.sh` ABI drift block.
|
|
768
|
+
- **M-23** When Electron version detection returns empty, emits explicit warning recommending `CLAWS_ELECTRON_VERSION` env override.
|
|
769
|
+
- **M-25** Linux Cursor/Windsurf install paths added to ABI detection candidates (`/usr/share/cursor/electron`, `/opt/cursor/electron`, `/usr/share/windsurf/electron`, `/opt/windsurf/electron`).
|
|
770
|
+
- **M-26** `update.sh` socket probe is now health-check only — never deletes socket on failed probe (races with VS Code hot-reload); defers destructive cleanup to user-explicit `/claws-fix` with actionable hint.
|
|
771
|
+
- **M-06** `install.sh` stale-extension cleanup loop gated on `[ -d "$kept_dir" ]`; skips with warning if just-installed directory has not yet extracted (VS Code async VSIX extraction), preventing total extension loss race.
|
|
772
|
+
|
|
773
|
+
## [0.7.4-bulletproof] - 2026-04-29 — Layer 0: shared helpers (M-02, M-03, M-01, M-09 foundation)
|
|
774
|
+
|
|
775
|
+
### Added
|
|
776
|
+
|
|
777
|
+
- `scripts/_helpers/json-safe.mjs` — JSONC-tolerant parse + `mergeIntoFile` that aborts on parse error (never silently resets to `{}`). Supports `//` line comments, `/* block comments */`, and trailing commas. Foundation for M-02 (`.mcp.json` wipe) and M-03 (`settings.json` wipe) fixes.
|
|
778
|
+
- `scripts/_helpers/atomic-file.mjs` — rename-pattern atomic write/dir-copy + `backupFile`. Foundation for M-01 (dotfile backup) and M-09 (hooks copy atomicity) fixes. Per-call nonce on tmp filenames ensures correctness under concurrent invocations. `@throws {Error}` documented for ENOENT on `backupFile` (F5).
|
|
779
|
+
- `json-safe.mjs` review fixes: `/* block comments */` stripped (F3), pid+nonce tmp suffix (F1), fsync before rename (F2).
|
|
780
|
+
- `atomic-file.test.js` test 3 strengthened: asserts all 10 concurrent writes succeed with `Promise.allSettled` + exact content match (F4).
|
|
781
|
+
|
|
782
|
+
## [0.7.4] - 2026-04-28 — Phase γ (reverse channel + event log) + MCP socket fix
|
|
783
|
+
|
|
784
|
+
This release integrates Phase γ (γ.1 reverse channel + γ.2 persistent event log)
|
|
785
|
+
and fixes a high-severity architectural bug in `mcp_server.js` that made all
|
|
786
|
+
stateful claws/2 MCP flows fail silently.
|
|
787
|
+
|
|
788
|
+
### Fixed (CRITICAL — issue 09)
|
|
789
|
+
|
|
790
|
+
- **`mcp_server.js` now maintains a single persistent socket** for stateful
|
|
791
|
+
claws/2 commands (`claws_hello`, `claws_subscribe`, `claws_publish`,
|
|
792
|
+
`claws_broadcast`, `claws_peers`). Previously each MCP tool call opened a
|
|
793
|
+
fresh socket, sent one frame, and destroyed it. The claws/2 protocol binds
|
|
794
|
+
peer state to a single connection; hello on socket A registered a peer and
|
|
795
|
+
closed; publish on socket B had no peer and returned "call hello first".
|
|
796
|
+
Stateless claws/1 commands (`list`, `create`, `send`, `close`, `readLog`,
|
|
797
|
+
`poll`, `exec`, `lifecycle.*`) continue to use per-call sockets.
|
|
798
|
+
Fix: module-level `_pconn` object with `_pconnEnsure()` / `_pconnWrite()` /
|
|
799
|
+
`clawsRpcStateful()`. Auto-reconnects on socket close; re-issues hello if a
|
|
800
|
+
prior identity was cached.
|
|
801
|
+
|
|
802
|
+
### Added (Phase γ.1 — reverse channel, integrated from branch)
|
|
803
|
+
|
|
804
|
+
- **`[CLAWS_CMD]` reverse channel**: orchestrator can broadcast a command token
|
|
805
|
+
into every worker's terminal via `{ inject: true }` on `claws_broadcast`.
|
|
806
|
+
Extension writes the text directly into the pty using `writeInjected()` with
|
|
807
|
+
bracketed paste. Worker skill (`/claws-streaming-worker`) scans its log for
|
|
808
|
+
the `[CLAWS_CMD]` prefix and routes to a named handler. Slash command
|
|
809
|
+
`/claws-broadcast` exposes the pattern. Integration test: `reverse-channel.test.js`
|
|
810
|
+
(12 checks). Commits: `80893ab`, `36bfece`, `d9c883a`, `4c434f9`.
|
|
811
|
+
|
|
812
|
+
### Added (Phase γ.2 — persistent event log, integrated from branch)
|
|
813
|
+
|
|
814
|
+
- **Append-only event log** (`EventLogWriter` in `extension/src/event-log.ts`).
|
|
815
|
+
Every `publish` call is durably written to `.claws/events/default/*.jsonl`
|
|
816
|
+
before fan-out. Segment rotation on size (10 MB) and age (1 hour). Atomic
|
|
817
|
+
manifest updates (`manifest.json`) for crash recovery. Sequence counter
|
|
818
|
+
monotonically increasing across segment boundaries. 15-check test suite:
|
|
819
|
+
`event-log.test.js`. Commits: `37acac1`, `0150572`, `f16f399`.
|
|
820
|
+
|
|
821
|
+
### Tests
|
|
822
|
+
|
|
823
|
+
- New: `extension/test/mcp-publish-flow.test.js` — spawns `mcp_server.js` as
|
|
824
|
+
a child process, calls `claws_hello` + `claws_publish` via MCP JSON-RPC,
|
|
825
|
+
asserts ok:true and event record on disk. Guards issue 09 regression.
|
|
826
|
+
Added `test:mcp-publish-flow` script and wired into `npm test`.
|
|
827
|
+
- Suite total: 224 checks across 21 suites (was 219 across 20).
|
|
828
|
+
|
|
829
|
+
### Version markers
|
|
830
|
+
|
|
831
|
+
- `extension/package.json` → 0.7.4
|
|
832
|
+
- `package.json` (root CLI) → 0.7.4
|
|
833
|
+
- `mcp_server.js` serverInfo → 0.7.4
|
|
834
|
+
- `claws-sdk.js` VERSION → 0.7.4
|
|
835
|
+
|
|
836
|
+
## [0.7.3] - 2026-04-28 — Bulletproof `/claws-update`
|
|
837
|
+
|
|
838
|
+
User-reported breakage on a real upgrade: `/claws-update` ran cleanly but
|
|
839
|
+
left MCP unable to connect. VS Code reload didn't fix it; running the
|
|
840
|
+
installer again in the same project didn't fix it. Root cause was an
|
|
841
|
+
Electron-ABI rebuild gap that none of the existing checks covered, plus
|
|
842
|
+
a blunt socket-cleanup that destroyed live state.
|
|
843
|
+
|
|
844
|
+
This release reworks `update.sh`, `install.sh`, and `fix.sh` so a future
|
|
845
|
+
`/claws-update` can never produce the same broken state. See
|
|
846
|
+
`.local/audits/update-sh-deep-audit.md` for the full bug catalog.
|
|
847
|
+
|
|
848
|
+
### Fixed (CRITICAL — caused the user-reported breakage)
|
|
849
|
+
|
|
850
|
+
- **Electron-ABI mismatch is now auto-detected** (`scripts/install.sh`).
|
|
851
|
+
Previously, `needs_rebuild_native` only triggered if the binary was
|
|
852
|
+
missing, the user passed `CLAWS_FORCE_REBUILD_NPTY=1`, or the git SHA
|
|
853
|
+
changed. If the user updated VS Code to a newer Electron version while
|
|
854
|
+
Claws was already installed, install.sh saw the binary present, the
|
|
855
|
+
SHA unchanged, and **skipped the rebuild** — the bundled `pty.node`
|
|
856
|
+
was now ABI-mismatched, the extension silently fell into pipe-mode,
|
|
857
|
+
and wrapped terminals (the entire MCP-driven workflow) broke. Fix:
|
|
858
|
+
read `electronVersion` from `extension/native/.metadata.json`,
|
|
859
|
+
compare against the currently-installed editor's Electron version,
|
|
860
|
+
force a rebuild on mismatch. macOS via `plutil` on Electron Framework
|
|
861
|
+
Info.plist; Linux via `electron --version` from common install paths.
|
|
862
|
+
Audit finding #1.
|
|
863
|
+
|
|
864
|
+
- **`/claws-fix` now propagates the rebuilt `pty.node` to every installed
|
|
865
|
+
extension dir** (`scripts/fix.sh`). Previously, fix.sh rebuilt
|
|
866
|
+
node-pty in `~/.claws-src/extension/node_modules/node-pty/` but VS Code
|
|
867
|
+
loads the extension from `~/.vscode/extensions/neunaha.claws-X.Y.Z/native/`
|
|
868
|
+
— a different copy. So the rebuild had no visible effect after reload.
|
|
869
|
+
Fix: copy the freshly-built pty.node into the source's `native/`
|
|
870
|
+
bundle AND into every `~/.{vscode,vscode-insiders,cursor,windsurf}/extensions/neunaha.claws-*/native/...`
|
|
871
|
+
directory, then update `native/.metadata.json` so future ABI checks
|
|
872
|
+
see the new version. Audit finding #3.
|
|
873
|
+
|
|
874
|
+
### Fixed (HIGH)
|
|
875
|
+
|
|
876
|
+
- **Safe socket cleanup in `update.sh`** (`scripts/update.sh:86`).
|
|
877
|
+
Previously: `find -name claws.sock -mtime +1 -delete`. If the user
|
|
878
|
+
kept VS Code open for >24 hours, the live socket file's mtime was
|
|
879
|
+
stale and `update.sh` deleted it. The running extension still held
|
|
880
|
+
the socket fd internally, but the path was gone — every subsequent
|
|
881
|
+
MCP child process got `ENOENT`. Replaced with a Node-based connect
|
|
882
|
+
probe: only delete the socket if it fails a 800ms `list` ping.
|
|
883
|
+
Live sockets are preserved. Audit finding #2.
|
|
884
|
+
|
|
885
|
+
- **Visible `git pull` failure in `update.sh`**. The previous version
|
|
886
|
+
treated "no changes" and "git pull failed" identically (same dim
|
|
887
|
+
`note()` output). On network errors / dirty source / merge conflicts,
|
|
888
|
+
the user proceeded silently with stale source. Now: distinguishes
|
|
889
|
+
the two cases, prints the actual git error, and warns when running
|
|
890
|
+
install.sh against a stale local clone. Audit finding #5.
|
|
891
|
+
|
|
892
|
+
### Added
|
|
893
|
+
|
|
894
|
+
- **Post-update health check in `update.sh`** (Step 6). After install.sh
|
|
895
|
+
returns, verifies pty.node ABI parity, `.mcp.json` JSON validity, and
|
|
896
|
+
MCP server `initialize` handshake. If any check fails, prints a yellow
|
|
897
|
+
WARNING banner with concrete recovery steps before the success line.
|
|
898
|
+
Stops the user from being surprised an hour later. Audit finding #4.
|
|
899
|
+
|
|
900
|
+
### Fixed (CRITICAL — "solve hook errors forever" — three-layer fix)
|
|
901
|
+
|
|
902
|
+
User-reported recurring class of failure: `SessionStart:startup hook
|
|
903
|
+
error / Failed with non-blocking status code: file:///.../hooks/X.js:14`
|
|
904
|
+
on every Bash tool call. Three distinct trigger paths, each closed:
|
|
905
|
+
|
|
906
|
+
- **Layer 1 — Hook scripts can never crash.** All three hook scripts
|
|
907
|
+
(`session-start-claws.js`, `pre-tool-use-claws.js`, `stop-claws.js`)
|
|
908
|
+
now have `process.on('uncaughtException')` + `unhandledRejection`
|
|
909
|
+
handlers registered as the first executable lines, plus full
|
|
910
|
+
try/catch wrapping around the body, plus lazy-require for any
|
|
911
|
+
cross-script deps (`stop-claws.js`'s `lifecycle-state` module). Any
|
|
912
|
+
internal error → silent `process.exit(0)`. Garbage stdin, missing
|
|
913
|
+
deps, ESM-loader confusion — all become no-ops instead of visible
|
|
914
|
+
errors. Verified: `printf garbage | node hook.js` → exit 0 for all
|
|
915
|
+
three hooks.
|
|
916
|
+
|
|
917
|
+
- **Layer 2 — Missing hook paths silent-skip instead of erroring.**
|
|
918
|
+
`inject-settings-hooks.js` now registers each hook command as
|
|
919
|
+
`sh -c '[ -f "$0" ] && exec node "$0" || exit 0' "<scriptPath>"`
|
|
920
|
+
instead of plain `node "<scriptPath>"`. If the path 404s (install
|
|
921
|
+
dir moved, sandbox path leaked, prior install removed), the
|
|
922
|
+
shell sees no file and exits 0 silently. Claude Code never
|
|
923
|
+
surfaces the error. Path-existence is checked at every tool call,
|
|
924
|
+
zero perf cost (sh + test). The injector's `alreadyPresent`
|
|
925
|
+
detection now also recognises and replaces old plain-format
|
|
926
|
+
entries on upgrade — no duplicate accumulation.
|
|
927
|
+
|
|
928
|
+
- **Layer 3 — `/claws-fix` auto-heals stale hook registrations.**
|
|
929
|
+
Two new checks added to `scripts/fix.sh`:
|
|
930
|
+
- "Hook script paths in `~/.claude/settings.json`" — extracts the
|
|
931
|
+
`.js` path from each Claws hook command (whether wrapped or
|
|
932
|
+
plain), tests `fs.existsSync`, lists any 404s, and re-runs
|
|
933
|
+
`inject-settings-hooks.js --remove + add` to re-register from
|
|
934
|
+
the current install dir. Self-healing.
|
|
935
|
+
- "Hook scripts execute cleanly" — invokes each registered hook
|
|
936
|
+
with synthetic stdin under a Node-based 5s timeout (replaces
|
|
937
|
+
macOS-incompatible `timeout` cmd), and reports any non-zero
|
|
938
|
+
exit. Surfaces pre-v0.7.3 hook scripts that don't have the
|
|
939
|
+
safety wrappers.
|
|
940
|
+
|
|
941
|
+
Together: any recurrence of the hook-error class is auto-detected
|
|
942
|
+
and auto-repaired by the next `/claws-fix` run.
|
|
943
|
+
|
|
944
|
+
This closes a recurring failure class that has bitten users since
|
|
945
|
+
the Claws hook chain shipped in v0.6.x.
|
|
946
|
+
|
|
947
|
+
## [0.7.2] - 2026-04-28 — Audit-driven hardening
|
|
948
|
+
|
|
949
|
+
User-reported regression on a real ESM project (`/Users/miles/dev/tokenomic/`)
|
|
950
|
+
plus the consolidated findings of the four-worker codebase audit
|
|
951
|
+
(`.local/audits/audit-{1,2,3,4}-*.md`). Net effect of this release:
|
|
952
|
+
|
|
953
|
+
- Hooks no longer crash in modern Node/TypeScript projects whose root
|
|
954
|
+
`package.json` declares `"type": "module"`.
|
|
955
|
+
- Stale shell-rc source lines from prior installs are reliably cleaned even
|
|
956
|
+
on macOS Monterey (BSD sed pre-Ventura) and on every Linux.
|
|
957
|
+
- Files removed from `scripts/hooks/` between releases no longer survive in
|
|
958
|
+
users' `.claws-bin/hooks/`.
|
|
959
|
+
- Linux x86_64 installs no longer print a false-positive arch warning every
|
|
960
|
+
time. Zsh-only syntax in `~/.zshrc` no longer triggers a misleading
|
|
961
|
+
"syntax error" warning.
|
|
962
|
+
- The `/claws-do` and `/claws-worker` slash commands now route one-shot shell
|
|
963
|
+
commands through `claws_exec` and reserve wrapped terminals for hosting
|
|
964
|
+
Claude Code workers. Closes the user-reported bug where wrapped terminals
|
|
965
|
+
ran shell commands instead of booting a Claude Code instance.
|
|
966
|
+
|
|
967
|
+
### Fixed (HIGH)
|
|
968
|
+
|
|
969
|
+
- **ESM-project hook crash** (`scripts/hooks/package.json` new + install.sh).
|
|
970
|
+
In projects whose root `package.json` declares `"type":"module"`, Node
|
|
971
|
+
walked up from the hook script and inherited the ESM type, so the
|
|
972
|
+
CommonJS `require('fs')` at the top of every Claws hook crashed at line 14.
|
|
973
|
+
The user (Miles) saw `Failed with non-blocking status code: file:///…/.claws-bin/hooks/pre-tool-use-claws.js:14` once per Bash tool call. Fix:
|
|
974
|
+
ship a `package.json` shim (`{"type":"commonjs"}`) alongside the hook
|
|
975
|
+
scripts so Node loads them as CJS regardless of the surrounding project's
|
|
976
|
+
ESM type. Audit 4 surfaced this as a follow-up gap (no audit covered ESM
|
|
977
|
+
projects directly — added to the matrix going forward).
|
|
978
|
+
|
|
979
|
+
- **Stale `.claws-bin/hooks/` overlay** (`scripts/install.sh`). The hooks
|
|
980
|
+
copy step used to overlay new files on top of the existing directory
|
|
981
|
+
without first wiping it. Files removed in a newer release (e.g.
|
|
982
|
+
`post-tool-use-claws.js`, deleted in v0.6.5) survived indefinitely in
|
|
983
|
+
every existing project's `.claws-bin/hooks/`, and `~/.claude/settings.json`
|
|
984
|
+
still referenced them. Fix: `rm -rf "$PROJECT_ROOT/.claws-bin/hooks"`
|
|
985
|
+
before the copy. Audit 4 finding I, audit 2 findings A/B.
|
|
986
|
+
|
|
987
|
+
- **Multi-project hook displacement** (`scripts/install.sh`,
|
|
988
|
+
`scripts/inject-settings-hooks.js`). Hook registration in
|
|
989
|
+
`~/.claude/settings.json` pointed at `$PROJECT_ROOT/.claws-bin/hooks/`,
|
|
990
|
+
so each new project install silently displaced every prior project's hook
|
|
991
|
+
registration — last install won globally. Deleting a project also orphaned
|
|
992
|
+
its hook commands in settings.json, leaving broken entries that fired on
|
|
993
|
+
every Bash call. Fix: pass `$INSTALL_DIR/scripts` to the hook injector so
|
|
994
|
+
`hookCmd` resolves to `$INSTALL_DIR/scripts/hooks/<script>.js` — the
|
|
995
|
+
committed source-of-truth. One registration now serves all projects;
|
|
996
|
+
`/claws-update` from any project refreshes it; project deletion never
|
|
997
|
+
orphans it. Audit 3 finding A.
|
|
998
|
+
|
|
999
|
+
- **BSD sed self-heal regression** (`scripts/install.sh:inject_hook`). The
|
|
1000
|
+
`# CLAWS terminal hook` cleanup used `sed '/pat/,+1d'` — the `,+N` range
|
|
1001
|
+
is a GNU sed extension. macOS ≤ Monterey ships a BSD sed that silently
|
|
1002
|
+
treats `+1` as the literal line number 1, so only the marker line was
|
|
1003
|
+
deleted and the `source ".../shell-hook.sh"` line on the next line
|
|
1004
|
+
survived. Subsequent installs no longer matched the marker (already
|
|
1005
|
+
gone) and the orphan source line stayed forever. Fix: replaced sed with
|
|
1006
|
+
a portable awk pass that also nukes any standalone orphaned
|
|
1007
|
+
`source .../shell-hook.sh` line — heals existing damage on the next
|
|
1008
|
+
install. Audit 4 finding G — the single highest-leverage item in that
|
|
1009
|
+
audit.
|
|
1010
|
+
|
|
1011
|
+
### Fixed (MEDIUM)
|
|
1012
|
+
|
|
1013
|
+
- **Linux x86_64 false-positive arch warning** (`scripts/install.sh:431`).
|
|
1014
|
+
`uname -m` returns `x86_64` (underscore) but `file(1)` reports the binary
|
|
1015
|
+
as `x86-64` (hyphen). Every legitimate Linux x86_64 install used to print
|
|
1016
|
+
`pty.node architecture may not match current machine (x86_64)`. Fix:
|
|
1017
|
+
match both spellings via `uname -m | sed 's/_/-/g'`. Audit 1 finding H-1.
|
|
1018
|
+
|
|
1019
|
+
- **Misleading "zshrc syntax error" warning** (`scripts/install.sh:1068`).
|
|
1020
|
+
`bash -n ~/.zshrc` flagged any zsh-specific construct (`setopt`,
|
|
1021
|
+
`autoload -Uz`, `zstyle`, …) as a syntax error after every install. Fix:
|
|
1022
|
+
prefer `zsh -n` when zsh is installed (it almost always is when
|
|
1023
|
+
`~/.zshrc` exists). Audit 1 finding H-2.
|
|
1024
|
+
|
|
1025
|
+
### Changed (slash command docs — no code change)
|
|
1026
|
+
|
|
1027
|
+
- **`/claws-do` and `/claws-worker`** now require classifying the request
|
|
1028
|
+
before creating a terminal:
|
|
1029
|
+
- One-shot shell command (`npm test`, `pytest`, `cargo build`) → use
|
|
1030
|
+
`claws_exec`. No terminal. No cleanup.
|
|
1031
|
+
- Mission-shaped task (refactor, fix bug, multi-step) → 7-step Claude
|
|
1032
|
+
Code boot sequence + `MISSION_COMPLETE` marker.
|
|
1033
|
+
Closes the user-reported regression where wrapped terminals were hosting
|
|
1034
|
+
bare shell commands instead of Claude Code instances. The new
|
|
1035
|
+
`/claws-do` doc explicitly forbids the old "send shell command into
|
|
1036
|
+
wrapped terminal" pattern.
|
|
1037
|
+
|
|
1038
|
+
### Audit findings deferred to v0.7.3+
|
|
1039
|
+
|
|
1040
|
+
- Stale VS Code extension dirs after symlink fallback (audit 4 K gap 1) —
|
|
1041
|
+
rare, low-impact.
|
|
1042
|
+
- Lifecycle-state `v` field validation (audit 4 J) — future hardening.
|
|
1043
|
+
- Offline / corporate-firewall bypass path (audit 4 A) — needs `--no-network`
|
|
1044
|
+
flag and `CLAWS_DIR` semantics review; out of scope for a hotfix.
|
|
1045
|
+
|
|
1046
|
+
## [0.7.1] - 2026-04-28 — Fresh-install fix
|
|
1047
|
+
|
|
1048
|
+
### Fixed (CRITICAL — fresh installs were silently broken)
|
|
1049
|
+
|
|
1050
|
+
`scripts/install.sh` was producing a partially-working system on every fresh
|
|
1051
|
+
project install since v0.6.5+ shipped the lifecycle hook chain. Issue 11 in
|
|
1052
|
+
`.local/issues/` documents the four layered bugs surfaced by an end-to-end
|
|
1053
|
+
install test against a clean `/tmp/claws-fresh-install-test/`.
|
|
1054
|
+
|
|
1055
|
+
- **Hook source path was wrong.** `install.sh` copied lifecycle hooks from
|
|
1056
|
+
`$INSTALL_DIR/.claws-bin/hooks/` — a path that is gitignored and therefore
|
|
1057
|
+
missing on every fresh `git clone`. The committed source-of-truth is
|
|
1058
|
+
`$INSTALL_DIR/scripts/hooks/`. Fixed: copy from the right source.
|
|
1059
|
+
Result: `<project>/.claws-bin/hooks/` is now populated as designed.
|
|
1060
|
+
- **`inject-settings-hooks.js` got the wrong directory.** It was invoked
|
|
1061
|
+
with `$INSTALL_DIR/.claws-bin` (source-clone path), so registered hook
|
|
1062
|
+
commands in `~/.claude/settings.json` pointed at non-existent files. Fixed:
|
|
1063
|
+
pass `$PROJECT_ROOT/.claws-bin` so registered paths are project-local and
|
|
1064
|
+
match the deployed copies. Lifecycle hooks (PreToolUse, SessionStart, Stop)
|
|
1065
|
+
now resolve correctly on every fresh install.
|
|
1066
|
+
- **`schemas/` deployment was incomplete.** Only `schemas/mcp-tools.json`
|
|
1067
|
+
was being copied. The 20 `schemas/json/*.json` and the
|
|
1068
|
+
`schemas/types/event-protocol.d.ts` were NOT. Fixed: copy the whole
|
|
1069
|
+
`schemas/` tree (`mcp-tools.json` + `json/` + `types/`). External schema
|
|
1070
|
+
consumers (worker SDKs, validators, IDE hints) now find the artifacts.
|
|
1071
|
+
- **Verifier flagged missing hooks dir as a warning, not a failure.** With
|
|
1072
|
+
the source-path bug fixed, the `.claws-bin/hooks/` directory should always
|
|
1073
|
+
be present after install — so its absence is now a hard `_miss`, not a soft
|
|
1074
|
+
`warn`. Catches regressions immediately rather than letting them slip past
|
|
1075
|
+
the install banner.
|
|
1076
|
+
|
|
1077
|
+
### Added
|
|
1078
|
+
|
|
1079
|
+
- `CLAWS_NO_GLOBAL_HOOKS=1` env var. When set, `install.sh` skips registering
|
|
1080
|
+
Claws hooks in `~/.claude/settings.json`. Useful for testing, CI, and
|
|
1081
|
+
sandboxed installs where the user's global Claude Code config should not
|
|
1082
|
+
be touched. Surfaced as a need during the issue-11 reproduction (running
|
|
1083
|
+
install.sh against a temp dir for testing was clobbering the dev
|
|
1084
|
+
environment's hook registration).
|
|
1085
|
+
|
|
1086
|
+
## [0.7.0] - 2026-04-28 — Phase β: streaming foundation
|
|
1087
|
+
|
|
1088
|
+
### Fixed (post-deploy)
|
|
1089
|
+
|
|
1090
|
+
- **`extension/scripts/deploy-dev.mjs`** — also copies `extension/package.json`
|
|
1091
|
+
into each `~/.vscode/extensions/<publisher>.<name>-*/` directory. VS Code
|
|
1092
|
+
reads the version label from the installed dir's `package.json`, so without
|
|
1093
|
+
this copy the Extensions panel keeps showing the pre-deploy version even
|
|
1094
|
+
after the bundle has been updated. Surfaced during the v0.7.0 integration
|
|
1095
|
+
test (issue 10 in `.local/issues/`).
|
|
1096
|
+
|
|
1097
|
+
### Fixed (post-review)
|
|
1098
|
+
|
|
1099
|
+
Three issues were found in the Phase β code review and addressed in this
|
|
1100
|
+
release before merge:
|
|
1101
|
+
|
|
1102
|
+
- **BLOCKING-1** — `claws-sdk.js` `hello()` was overwriting `CLAWS_PEER_ID`
|
|
1103
|
+
with the server-assigned connection peer id, so SDK publishes were
|
|
1104
|
+
routing to `worker.<server-id>.*` instead of the documented
|
|
1105
|
+
`worker.<CLAWS_PEER_ID>.*`. The constructor now captures `CLAWS_PEER_ID`
|
|
1106
|
+
into an immutable `_topicPeerId` field that all publish methods use for
|
|
1107
|
+
topic construction; `hello()` never overwrites it.
|
|
1108
|
+
- **BLOCKING-2** — `publishBoot`/`publishPhase`/`publishHeartbeat` (and
|
|
1109
|
+
others) were constructing payloads whose field names did not match the
|
|
1110
|
+
corresponding Zod schemas (`reason` vs `transition_reason`, `phase` vs
|
|
1111
|
+
`current_phase`, missing `model`/`parent_peer_id`/`cwd`/`terminal_id`,
|
|
1112
|
+
etc.). Every SDK publish was triggering `system.malformed.received` even
|
|
1113
|
+
in normal operation. All payload field names now match the schemas
|
|
1114
|
+
exactly. Schema names also switched from PascalCase (`WorkerBootV1`) to
|
|
1115
|
+
kebab-case (`worker-boot-v1`) to match the `SCHEMA_BY_NAME` convention.
|
|
1116
|
+
- **MAJOR-1** — `extension/package.json` `build` and `compile` scripts now
|
|
1117
|
+
prepend `npm run schemas` so committed artifacts under `schemas/` cannot
|
|
1118
|
+
silently fall stale relative to `event-schemas.ts`.
|
|
1119
|
+
|
|
1120
|
+
### Added
|
|
1121
|
+
|
|
1122
|
+
**Schemas-as-code (Zod → committed JSON, TypeScript, docs)**
|
|
1123
|
+
- `extension/src/event-schemas.ts`: Zod v3 schema definitions as the single
|
|
1124
|
+
source of truth for all 19 event types — `EnvelopeV1`, 5 worker schemas,
|
|
1125
|
+
8 cmd schemas, 6 system schemas, enums, and `SCHEMA_BY_NAME` lookup
|
|
1126
|
+
- `extension/src/topic-registry.ts`: `TOPIC_REGISTRY` (19 entries) and
|
|
1127
|
+
`schemaForTopic()` lookup; `topic-utils.ts` extracted to avoid circular deps
|
|
1128
|
+
- `npm run schemas` codegen pipeline: bundles TS via esbuild, then generates
|
|
1129
|
+
`schemas/json/` (20 JSON Schema files), `schemas/types/event-protocol.d.ts`,
|
|
1130
|
+
`docs/event-protocol.md` topic table, and `schemas/mcp-tools.json`
|
|
1131
|
+
- All generated files committed — no runtime build step required
|
|
1132
|
+
|
|
1133
|
+
**Server-side publish validation (soft-reject mode by default)**
|
|
1134
|
+
- `server.ts` publish handler validates `EnvelopeV1` and per-topic data
|
|
1135
|
+
schema before fan-out using the Zod schemas
|
|
1136
|
+
- Soft-reject (default): on failure, emits `system.malformed.received` with
|
|
1137
|
+
`{ from, topic, error: ZodIssues }`, then still fans the event out
|
|
1138
|
+
- Strict mode (`claws.strictEventValidation=true`): hard-rejects with
|
|
1139
|
+
`{ ok:false, error:'envelope:invalid'|'payload:invalid', details }`;
|
|
1140
|
+
no fan-out occurs
|
|
1141
|
+
- Migration note: soft-reject is the default in v0.7.0; flips to strict in
|
|
1142
|
+
v0.8.0 to give existing callers one release cycle to adopt the envelope
|
|
1143
|
+
|
|
1144
|
+
**MCP tool descriptors generated from Zod schemas**
|
|
1145
|
+
- All 18 MCP tools defined as Zod schemas in `scripts/codegen/gen-mcp-tools.mjs`
|
|
1146
|
+
- `schemas/mcp-tools.json` committed and consumed by `mcp_server.js` at startup
|
|
1147
|
+
- `tools/list` response is byte-identical to the previous hand-written array
|
|
1148
|
+
- `mcp_server.js` startup guard exits clearly if the file is absent
|
|
1149
|
+
|
|
1150
|
+
**Claws SDK — zero-dep typed publish helpers**
|
|
1151
|
+
- `claws-sdk.js` (repo root, copied to `.claws-bin/` by installer): dual CLI
|
|
1152
|
+
+ module API for workers to publish typed `EnvelopeV1` frames
|
|
1153
|
+
- CLI verbs: `publish boot|phase|event|heartbeat|complete`
|
|
1154
|
+
- Module: `ClawsSDK` class with `connect()`, `hello()`, `publishBoot()`,
|
|
1155
|
+
`publishPhase()`, `publishEvent()`, `publishHeartbeat()`, `publishComplete()`
|
|
1156
|
+
- Socket auto-discovery (walks up from `cwd`); reads env `CLAWS_PEER_ID`,
|
|
1157
|
+
`CLAWS_PEER_NAME`, `CLAWS_TERMINAL_ID`
|
|
1158
|
+
- Migration note: SDK is opt-in for Phase β — legacy `claws_publish` with raw
|
|
1159
|
+
payloads continues to work in soft-reject mode
|
|
1160
|
+
|
|
1161
|
+
**Streaming Worker orchestration pattern**
|
|
1162
|
+
- Template 8 in `.claude/skills/prompt-templates/SKILL.md`: full streaming
|
|
1163
|
+
worker mission boilerplate with checkpoint publish table and orchestrator
|
|
1164
|
+
setup guide
|
|
1165
|
+
- `.claude/skills/claws-orchestration-engine/SKILL.md` Phase 4 OBSERVE
|
|
1166
|
+
refactored to event-driven sidecar pattern with heartbeat-based stuck
|
|
1167
|
+
detection; legacy `claws_read_log` polling documented as fallback
|
|
1168
|
+
- New slash command `.claude/commands/claws-streaming-worker.md`
|
|
1169
|
+
|
|
1170
|
+
### Tests
|
|
1171
|
+
|
|
1172
|
+
192 checks across 18 suites (all green):
|
|
1173
|
+
- 34 unit checks — `event-schemas.test.js`
|
|
1174
|
+
- 14 unit checks — `topic-registry.test.js`
|
|
1175
|
+
- 7 integration checks — `server-validation.test.js`
|
|
1176
|
+
- 7 static + smoke checks — `mcp-tools-codegen.test.js`
|
|
1177
|
+
- 7 CLI + integration checks — `sdk-cli.test.js`
|
|
1178
|
+
- 123 pre-existing checks (suites 1–13) unchanged
|
|
1179
|
+
|
|
1180
|
+
---
|
|
1181
|
+
|
|
1182
|
+
## [Unreleased] - Phase β: streaming foundation
|
|
1183
|
+
|
|
1184
|
+
### Added — β.5 Claws SDK (commit 5/7)
|
|
1185
|
+
|
|
1186
|
+
**Zero-dependency worker publish helper:**
|
|
1187
|
+
- `claws-sdk.js` (repo root): dual CLI + module API for workers to publish
|
|
1188
|
+
typed `EnvelopeV1` frames; zero deps (stdlib `net`, `crypto`, `fs` only)
|
|
1189
|
+
- CLI: `node .claws-bin/claws-sdk.js publish boot|phase|event|heartbeat|complete [flags]`
|
|
1190
|
+
- Module: `const { ClawsSDK } = require('.claws-bin/claws-sdk.js')` —
|
|
1191
|
+
`connect()`, `hello()`, `publishBoot()`, `publishPhase()`,
|
|
1192
|
+
`publishEvent()`, `publishHeartbeat()`, `publishComplete()`
|
|
1193
|
+
- Socket auto-discovery: walks up from `cwd` looking for `.claws/claws.sock`
|
|
1194
|
+
- Reads env: `CLAWS_SOCKET`, `CLAWS_PEER_ID` (required for publish),
|
|
1195
|
+
`CLAWS_PEER_NAME`, `CLAWS_TERMINAL_ID`
|
|
1196
|
+
- `--help` / `--version` (`0.7.0`) / clean error on missing `CLAWS_PEER_ID`
|
|
1197
|
+
- `scripts/install.sh`: copies `schemas/mcp-tools.json` → `.claws-bin/schemas/`
|
|
1198
|
+
(required by `mcp_server.js` at runtime) and `claws-sdk.js` → `.claws-bin/`
|
|
1199
|
+
- 7 checks in `extension/test/sdk-cli.test.js` (static CLI + module API +
|
|
1200
|
+
live server integration via built extension bundle)
|
|
1201
|
+
- `extension/package.json`: adds `test:sdk` script, 192 checks across 18 suites
|
|
1202
|
+
|
|
1203
|
+
---
|
|
1204
|
+
|
|
1205
|
+
### Added — β.4 MCP tool descriptor migration (commit 4/7)
|
|
1206
|
+
|
|
1207
|
+
**MCP tool descriptors generated from Zod schemas:**
|
|
1208
|
+
- `scripts/codegen/gen-mcp-tools.mjs`: defines all 18 MCP tools as Zod schemas
|
|
1209
|
+
with verbatim descriptions; writes `schemas/mcp-tools.json` at codegen time
|
|
1210
|
+
- `schemas/mcp-tools.json`: committed generated file — 18 tool descriptors
|
|
1211
|
+
consumed by `mcp_server.js` at startup
|
|
1212
|
+
- `mcp_server.js`: replaced 224-line hand-written `TOOLS` array with
|
|
1213
|
+
`require('./schemas/mcp-tools.json')`; adds startup guard that exits with
|
|
1214
|
+
a clear message when the file is absent
|
|
1215
|
+
- 7 checks in `extension/test/mcp-tools-codegen.test.js` (static JSON checks
|
|
1216
|
+
+ `mcp_server.js` `tools/list` stdio smoke test)
|
|
1217
|
+
- `extension/package.json`: adds `test:mcp-codegen` script and appends it to
|
|
1218
|
+
the `test` chain (185 checks total across 17 suites)
|
|
1219
|
+
|
|
1220
|
+
---
|
|
1221
|
+
|
|
1222
|
+
### Added — β.1 Schemas + β.1 Server Validation (commits 1–2/7)
|
|
1223
|
+
|
|
1224
|
+
**Zod schema definitions as single source of truth for all event types:**
|
|
1225
|
+
- `extension/src/event-schemas.ts`: `EnvelopeV1`, 5 worker schemas
|
|
1226
|
+
(`WorkerBootV1`, `WorkerPhaseV1`, `WorkerEventV1`, `WorkerHeartbeatV1`,
|
|
1227
|
+
`WorkerCompleteV1`), 8 cmd schemas, 6 system schemas, enums
|
|
1228
|
+
(`PHASES`, `EventKindEnum`, `ClawsRoleEnum`, `ResultEnum`, `SeverityEnum`),
|
|
1229
|
+
and `SCHEMA_BY_NAME` lookup map
|
|
1230
|
+
- `extension/src/topic-utils.ts`: standalone `matchTopic` + `matchSegments`
|
|
1231
|
+
extracted from `peer-registry.ts` (§7.7 refactor — clean dep graph)
|
|
1232
|
+
- `extension/src/topic-registry.ts`: `TOPIC_REGISTRY` (19 entries),
|
|
1233
|
+
`schemaForTopic(topic)` lookup
|
|
1234
|
+
- `extension/src/peer-registry.ts`: now re-exports `matchTopic` from
|
|
1235
|
+
`topic-utils.ts`; backward compatible for all existing callers
|
|
1236
|
+
- 34 unit checks in `test/event-schemas.test.js`
|
|
1237
|
+
- 14 unit checks in `test/topic-registry.test.js`
|
|
1238
|
+
- `zod@^3` and `zod-to-json-schema@^3` added as devDependencies
|
|
1239
|
+
|
|
1240
|
+
**Codegen pipeline (`npm run schemas`):**
|
|
1241
|
+
- `scripts/codegen/index.mjs`: bundles `event-schemas.ts` via esbuild → CJS,
|
|
1242
|
+
then calls each generator in sequence
|
|
1243
|
+
- `scripts/codegen/gen-json-schema.mjs`: iterates exported Zod schemas, calls
|
|
1244
|
+
`zodToJsonSchema()`, writes 20 files to `schemas/json/`
|
|
1245
|
+
- `scripts/codegen/gen-types.mjs`: writes `schemas/types/event-protocol.d.ts`
|
|
1246
|
+
with hand-templated type aliases for all 19 event schemas
|
|
1247
|
+
- `scripts/codegen/gen-docs.mjs`: regenerates schema reference table in
|
|
1248
|
+
`docs/event-protocol.md` between `<!-- BEGIN/END GENERATED SCHEMAS -->` markers
|
|
1249
|
+
- `extension/package.json`: adds `"schemas"` script; `build` unchanged
|
|
1250
|
+
(codegen is an explicit separate step — run before build for full pipeline)
|
|
1251
|
+
- `.gitignore`: adds `extension/dist/event-schemas.bundle.cjs` (temp artifact)
|
|
1252
|
+
- `docs/event-protocol.md`: adds `BEGIN/END GENERATED SCHEMAS` markers with
|
|
1253
|
+
initial generated content
|
|
1254
|
+
- `schemas/` directory committed with all 20 JSON Schema files and `.d.ts`
|
|
1255
|
+
|
|
1256
|
+
**Server-side publish validation with soft-reject mode:**
|
|
1257
|
+
- `server.ts` publish handler now validates envelope (`EnvelopeV1`) and data
|
|
1258
|
+
payload (`schemaForTopic`) before fan-out
|
|
1259
|
+
- Soft-reject mode (default): on failure, emits `system.malformed.received`
|
|
1260
|
+
with `{ from, topic, error: ZodIssues }`, then still fans out the event
|
|
1261
|
+
- Strict mode (`claws.strictEventValidation=true`): hard-rejects with
|
|
1262
|
+
`{ ok:false, error:'envelope:invalid'|'payload:invalid', details }`;
|
|
1263
|
+
no fan-out occurs
|
|
1264
|
+
- `server-config.ts`: new `strictEventValidation: boolean` field
|
|
1265
|
+
(default `false`); `DEFAULT_STRICT_EVENT_VALIDATION` constant
|
|
1266
|
+
- `extension.ts`: wires `strictEventValidation` from VS Code settings
|
|
1267
|
+
- `extension/package.json`: adds `claws.strictEventValidation` VS Code config
|
|
1268
|
+
- 7 integration checks in `test/server-validation.test.js`
|
|
1269
|
+
|
|
1270
|
+
---
|
|
1271
|
+
|
|
1272
|
+
## [0.6.5] - 2026-04-28
|
|
1273
|
+
|
|
1274
|
+
### Added — Phase α: server-side lifecycle gate
|
|
1275
|
+
|
|
1276
|
+
The lifecycle enforcement trust boundary moves from Claude Code hooks (which do
|
|
1277
|
+
not reliably fire on MCP tool calls) into the socket server itself. Every
|
|
1278
|
+
transport — MCP, raw Bash socket, and future WebSocket — is gated by the same
|
|
1279
|
+
server-side check.
|
|
1280
|
+
|
|
1281
|
+
**Server-owned lifecycle state (`LifecycleStore`):**
|
|
1282
|
+
A new `LifecycleStore` class holds lifecycle state in memory (authoritative) and
|
|
1283
|
+
persists it atomically to `.claws/lifecycle-state.json` via tmp-rename. The
|
|
1284
|
+
server constructs the store on startup and is the only writer. No client — not
|
|
1285
|
+
even the model — can write the state file to bypass the gate.
|
|
1286
|
+
|
|
1287
|
+
**Server-side gate on `create`:**
|
|
1288
|
+
The `create` command handler now calls `lifecycleStore.hasPlan()` as its first
|
|
1289
|
+
action. When no plan exists, `create` is rejected immediately with:
|
|
1290
|
+
```json
|
|
1291
|
+
{ "ok": false, "error": "lifecycle:plan-required", "message": "..." }
|
|
1292
|
+
```
|
|
1293
|
+
This error is identical regardless of whether the caller is the MCP server, a
|
|
1294
|
+
raw Bash `node -e` snippet, or a future WebSocket client.
|
|
1295
|
+
|
|
1296
|
+
**Four new socket commands:**
|
|
1297
|
+
- `lifecycle.plan` — log the PLAN phase; idempotent; returns state + `idempotent` flag
|
|
1298
|
+
- `lifecycle.advance` — advance the state machine one step; enforces legal transitions
|
|
1299
|
+
- `lifecycle.snapshot` — read-only state query; no side effects
|
|
1300
|
+
- `lifecycle.reflect` — terminal REFLECT transition with persisted retrospective text
|
|
1301
|
+
|
|
1302
|
+
**Four new MCP tools:**
|
|
1303
|
+
`claws_lifecycle_plan`, `claws_lifecycle_advance`, `claws_lifecycle_snapshot`,
|
|
1304
|
+
`claws_lifecycle_reflect`. All wrap the new socket commands. The plan tool's
|
|
1305
|
+
description explains the server gate so the model knows to call it first.
|
|
1306
|
+
|
|
1307
|
+
**`/claws-plan` now uses MCP tool, not Write:**
|
|
1308
|
+
Step 2 of `/claws-plan` previously instructed the model to write
|
|
1309
|
+
`.claws/lifecycle-state.json` directly. It now invokes
|
|
1310
|
+
`mcp__claws__claws_lifecycle_plan(plan="...")` — the server writes the file
|
|
1311
|
+
under its own ownership.
|
|
1312
|
+
|
|
1313
|
+
**PostToolUse hook removed:**
|
|
1314
|
+
`scripts/hooks/post-tool-use-claws.js` is deleted. This hook never reliably
|
|
1315
|
+
fired on MCP tool calls (issue 06) and phase advancement now happens at the
|
|
1316
|
+
server dispatch layer. Keeping it was dead code.
|
|
1317
|
+
|
|
1318
|
+
**PreToolUse hook simplified:**
|
|
1319
|
+
`scripts/hooks/pre-tool-use-claws.js` no longer contains lifecycle gate blocks
|
|
1320
|
+
for `mcp__claws__*` tools. The Bash long-running pattern guard (soft nudge /
|
|
1321
|
+
CLAWS_STRICT hard-block) is retained — it remains useful for observability.
|
|
1322
|
+
|
|
1323
|
+
**Raw-socket bypass instructions removed from claws-do.md:**
|
|
1324
|
+
All `net.createConnection` / "raw socket via node" fallback instructions are
|
|
1325
|
+
removed from `.claude/commands/claws-do.md`. If MCP fails to load, the user is
|
|
1326
|
+
directed to reload VS Code — not to bypass via Bash.
|
|
1327
|
+
|
|
1328
|
+
**install.sh migration:**
|
|
1329
|
+
The hooks-registration step now runs `inject-settings-hooks.js --remove` before
|
|
1330
|
+
re-registering. This cleanly removes the stale PostToolUse entry from
|
|
1331
|
+
`~/.claude/settings.json` on re-install without touching non-Claws hooks.
|
|
1332
|
+
|
|
1333
|
+
> **Note for users who edited settings.json manually:** if you removed the
|
|
1334
|
+
> `_source: "claws"` tag from a hook entry, `inject-settings-hooks.js --remove`
|
|
1335
|
+
> will not find it. Verify your `~/.claude/settings.json` has no PostToolUse
|
|
1336
|
+
> entry for `post-tool-use-claws.js` after upgrading.
|
|
1337
|
+
|
|
1338
|
+
**Post-review fixes (M1+M2+M3 — applied as immediate follow-up):**
|
|
1339
|
+
Three issues found in the post-merge review have been addressed in this release.
|
|
1340
|
+
M1: `lifecycle.advance` (and `lifecycle.reflect`) error responses now return the
|
|
1341
|
+
stable machine-readable code in `error` and the human-readable detail in a
|
|
1342
|
+
separate `message` field, matching the §2.3 contract already implemented by the
|
|
1343
|
+
other lifecycle handlers. M2: `lifecycle.advance` returns `idempotent: true` when
|
|
1344
|
+
the requested phase equals the current phase (no-op transition), as specified in
|
|
1345
|
+
§2.3. M3: All remaining "or raw socket" bypass phrasing in `claws-do.md` is
|
|
1346
|
+
removed; the affected prohibition lines are rephrased without the term.
|
|
1347
|
+
|
|
1348
|
+
Files changed:
|
|
1349
|
+
- `extension/src/lifecycle-store.ts` — new `LifecycleStore` class (pure Node.js)
|
|
1350
|
+
- `extension/src/protocol.ts` — `LifecycleState`, `LifecyclePlanRequest`,
|
|
1351
|
+
`LifecycleAdvanceRequest`, `LifecycleSnapshotRequest`, `LifecycleReflectRequest`
|
|
1352
|
+
added; all four added to `ClawsRequest` union
|
|
1353
|
+
- `extension/src/server.ts` — import + field + constructor wiring; gate check in
|
|
1354
|
+
`create` handler; four new `lifecycle.*` command handlers
|
|
1355
|
+
- `mcp_server.js` — four new tool descriptors + four new `handleTool` cases
|
|
1356
|
+
- `.claude/commands/claws-do.md` — raw-socket bypass instructions removed
|
|
1357
|
+
- `.claude/commands/claws-plan.md` — step 2 now invokes `claws_lifecycle_plan`;
|
|
1358
|
+
lifecycle table updated to remove `(post-tool-use hook auto-advances)` reference
|
|
1359
|
+
- `scripts/hooks/post-tool-use-claws.js` — **deleted**
|
|
1360
|
+
- `scripts/hooks/pre-tool-use-claws.js` — lifecycle gate blocks removed; Bash guard kept
|
|
1361
|
+
- `scripts/inject-settings-hooks.js` — PostToolUse entry removed; 3 hooks remain
|
|
1362
|
+
- `scripts/install.sh` — hooks registration updated to `--remove` then re-register
|
|
1363
|
+
- `extension/test/lifecycle-store.test.js` — 25 unit tests (all pass)
|
|
1364
|
+
- `extension/test/lifecycle-server.test.js` — 8 integration tests (7 original + 1
|
|
1365
|
+
new illegal-transition test; idempotent:true assertion added to advance test)
|
|
1366
|
+
|
|
1367
|
+
## [0.6.4] - 2026-04-28
|
|
1368
|
+
|
|
1369
|
+
### Added — CLAWS_STRICT mode (first Hard enforcement mechanism)
|
|
1370
|
+
|
|
1371
|
+
Until v0.6.4 every Claws enforcement layer was advisory: CLAUDE.md blocks,
|
|
1372
|
+
SessionStart/PreToolUse/Stop hooks all *suggested* the Claws path but the
|
|
1373
|
+
model could still fall back to plain Bash for long-running orchestration
|
|
1374
|
+
work. This release ships the first hard block.
|
|
1375
|
+
|
|
1376
|
+
When `CLAWS_STRICT=1` is set in the user's environment (or in
|
|
1377
|
+
`~/.claude/settings.json` `env` block), the PreToolUse hook returns
|
|
1378
|
+
`permissionDecision: "deny"` for Bash commands that match long-running
|
|
1379
|
+
patterns (servers, watchers, `nohup`, `nodemon`, `pnpm/bun start|dev|serve|watch`,
|
|
1380
|
+
etc.). The deny reason is an actionable four-step recipe: `claws_create` →
|
|
1381
|
+
`claws_send` → `claws_read_log` → `claws_close`. Claude Code blocks the
|
|
1382
|
+
tool call and the model pivots.
|
|
1383
|
+
|
|
1384
|
+
The pattern list is conservative — only commands that are unambiguously
|
|
1385
|
+
long-running. Ordinary commands like `ls`, `git status`, one-shot builds,
|
|
1386
|
+
or short tests pass through unchanged. `CLAWS_STRICT` defaults to off; no
|
|
1387
|
+
behavior change for existing users.
|
|
1388
|
+
|
|
1389
|
+
The mechanism uses Claude Code's documented PreToolUse hook protocol
|
|
1390
|
+
(`hookSpecificOutput.permissionDecision`); no Claude Code change required.
|
|
1391
|
+
|
|
1392
|
+
Files changed:
|
|
1393
|
+
- `scripts/hooks/pre-tool-use-claws.js` — added `STRICT` branch with
|
|
1394
|
+
`hookSpecificOutput.permissionDecision: "deny"` + actionable reason.
|
|
1395
|
+
Pattern list expanded with `pnpm`, `bun`, `hypercorn`, `nodemon`,
|
|
1396
|
+
`nohup`. Word-boundary anchored to reduce false positives.
|
|
1397
|
+
|
|
1398
|
+
### Fixed — settings.json schema URL + install.sh housekeeping
|
|
1399
|
+
|
|
1400
|
+
- `.claude/settings.json` — `$schema` URL was `json-schema.store.org` (typo);
|
|
1401
|
+
corrected to `json.schemastore.org`. Closes the "Found 1 settings issue"
|
|
1402
|
+
warning surfaced by `/doctor`.
|
|
1403
|
+
- `scripts/install.sh` — copies `scripts/stream-events.js` into `.claws-bin/`
|
|
1404
|
+
during install so the event-streaming sidecar (referenced in
|
|
1405
|
+
`docs/event-protocol.md`) is available out of the box. Documents
|
|
1406
|
+
`CLAWS_STRICT` env var in the header. Fixes the install-time MCP
|
|
1407
|
+
handshake probe to use newline-delimited JSON (matches the v0.6.1 server
|
|
1408
|
+
framing fix; the probe was still using LSP `Content-Length` framing and
|
|
1409
|
+
failing silently).
|
|
1410
|
+
|
|
1411
|
+
## [0.6.3] - 2026-04-28
|
|
1412
|
+
|
|
1413
|
+
### Fixed — claws_send submit reliability for TUI workers
|
|
1414
|
+
|
|
1415
|
+
Multi-line text sent via `claws_send` with `newline=true` was not registering as
|
|
1416
|
+
a discrete Enter keypress in Ink-based TUIs (Claude Code). The trailing CR
|
|
1417
|
+
arrived in the same write as the bracketed-paste close marker and got bundled
|
|
1418
|
+
into the TUI's paste-detection burst, leaving the input populated but never
|
|
1419
|
+
submitted. Empirical workaround: send the CR via raw socket as a separate write.
|
|
1420
|
+
This release encodes the workaround into the send path itself.
|
|
1421
|
+
|
|
1422
|
+
Two-part fix:
|
|
1423
|
+
- `extension/src/claws-pty.ts:writeInjected` — when bracketed paste is used and
|
|
1424
|
+
`withNewline=true`, the trailing `\r` is emitted in a separate `write()` call
|
|
1425
|
+
after a 30 ms delay. The pause closes the TUI's paste-detection window before
|
|
1426
|
+
the CR arrives, so it registers as Enter.
|
|
1427
|
+
- `mcp_server.js:claws_send` — auto-sets `paste: true` when text contains `\n`
|
|
1428
|
+
or `\r`. The tool description always promised this; the server never
|
|
1429
|
+
enforced it.
|
|
1430
|
+
|
|
1431
|
+
End-to-end verified: a multi-line `claws_send` with `newline=true` now submits
|
|
1432
|
+
on the first try in a Claude Code worker terminal — no raw-socket CR fallback
|
|
1433
|
+
needed.
|
|
1434
|
+
|
|
1435
|
+
### Added — npm run deploy:dev for local extension iteration
|
|
1436
|
+
|
|
1437
|
+
`extension/scripts/deploy-dev.mjs` (called via `npm run deploy:dev`) copies the
|
|
1438
|
+
freshly built `dist/extension.js` and `native/` bundle into every installed
|
|
1439
|
+
extension directory under `~/.vscode/extensions/<publisher>.<name>-*/`. Closes
|
|
1440
|
+
the silent gap where `npm run build` produced a new bundle that VS Code never
|
|
1441
|
+
loaded because the editor only reads from its installed-extensions dir.
|
|
1442
|
+
|
|
1443
|
+
### Fixed — install.sh now cleans stale install dirs
|
|
1444
|
+
|
|
1445
|
+
After a successful `code --install-extension <vsix>`, the installer now removes
|
|
1446
|
+
older `<publisher>.<name>-X.Y.Z` directories so VS Code's extension picker
|
|
1447
|
+
isn't confused by lingering versions. Previously, prior installs (e.g. stuck
|
|
1448
|
+
on a lock when a window was open) could leave multiple version dirs under
|
|
1449
|
+
`~/.vscode/extensions/` indefinitely.
|
|
1450
|
+
|
|
1451
|
+
### Fixed — version manifests now track CHANGELOG
|
|
1452
|
+
|
|
1453
|
+
`extension/package.json` was stuck at `0.6.0` and root `package.json` at
|
|
1454
|
+
`0.5.3` despite CHANGELOG, README, CLAUDE.md, and the `v0.6.1` git tag all
|
|
1455
|
+
declaring `0.6.1`. Result: every reinstall packaged a VSIX labeled `0.6.0`,
|
|
1456
|
+
and VS Code's extension UI kept showing `0.6.0` even when the bytes had moved
|
|
1457
|
+
on. Both manifests now match the CHANGELOG.
|
|
1458
|
+
|
|
1459
|
+
## [0.6.2] - 2026-04-28
|
|
1460
|
+
|
|
1461
|
+
### Added — Lifecycle gate (PLAN→REFLECT) for orchestration
|
|
1462
|
+
|
|
1463
|
+
Multi-terminal orchestration via Claws now follows an enforced 8-phase lifecycle:
|
|
1464
|
+
PLAN → SPAWN → DEPLOY → OBSERVE → RECOVER → HARVEST → CLEANUP → REFLECT.
|
|
1465
|
+
A PreToolUse gate blocks `claws_create` (and any `claws_*` tool) until a PLAN
|
|
1466
|
+
file exists at `.claws/lifecycle-state.json`. The `/claws-plan` slash command
|
|
1467
|
+
writes this file and unlocks terminal creation.
|
|
1468
|
+
|
|
1469
|
+
Why: pre-0.6.2, orchestrators could spawn workers without stating a mission,
|
|
1470
|
+
which led to runaway terminals, no audit trail, and no shared memory of what
|
|
1471
|
+
each worker was supposed to do. The gate forces a one-paragraph plan before
|
|
1472
|
+
any worker is created.
|
|
1473
|
+
|
|
1474
|
+
Components:
|
|
1475
|
+
- `scripts/hooks/lifecycle-state.js` — shared module that read/writes the
|
|
1476
|
+
state machine.
|
|
1477
|
+
- `scripts/hooks/pre-tool-use-claws.js` — gate logic that returns a blocking
|
|
1478
|
+
error when no PLAN exists.
|
|
1479
|
+
- `scripts/hooks/post-tool-use-claws.js` — auto-advances phase after each
|
|
1480
|
+
`claws_*` tool call.
|
|
1481
|
+
- `scripts/hooks/stop-claws.js` — checks lifecycle state on Stop and reminds
|
|
1482
|
+
the model to close terminals + write REFLECT before session end.
|
|
1483
|
+
- `scripts/inject-settings-hooks.js` — registers the new PostToolUse hook
|
|
1484
|
+
matcher (`mcp__claws__*`).
|
|
1485
|
+
- `.claude/commands/claws-plan.md` — new `/claws-plan` slash command.
|
|
1486
|
+
|
|
1487
|
+
### Added — Event-streaming sidecar protocol
|
|
1488
|
+
|
|
1489
|
+
A convention layer over the existing claws/2 pub-sub for real-time, no-polling
|
|
1490
|
+
orchestration. Workers emit lifecycle events on well-known topics; orchestrators
|
|
1491
|
+
subscribe via a long-lived sidecar process that prints each push frame as one
|
|
1492
|
+
JSON line on stdout — designed to be spawned via `run_in_background` and
|
|
1493
|
+
consumed by Monitor-style line tailing.
|
|
1494
|
+
|
|
1495
|
+
- `docs/event-protocol.md` — event shapes, command channel, state machine.
|
|
1496
|
+
- `scripts/stream-events.js` — sidecar implementation. Holds one persistent
|
|
1497
|
+
socket, registers as a peer, subscribes to a topic pattern, emits JSON-line
|
|
1498
|
+
events per push frame.
|
|
1499
|
+
|
|
1500
|
+
### Housekeeping
|
|
1501
|
+
|
|
1502
|
+
- `scripts/git-hooks/pre-commit` — repo-local hook that enforces CHANGELOG
|
|
1503
|
+
updates for code commits. Installed by `scripts/install.sh` into
|
|
1504
|
+
`.git/hooks/`.
|
|
1505
|
+
- `.gitignore` — ignore `.claude/scheduled_tasks.lock` (runtime artifact
|
|
1506
|
+
from the scheduling system).
|
|
1507
|
+
|
|
1508
|
+
## [0.6.1] - 2026-04-22
|
|
1509
|
+
|
|
1510
|
+
### Fixed — MCP server stdio framing (CRITICAL)
|
|
1511
|
+
|
|
1512
|
+
The MCP server was implementing **LSP-style `Content-Length` framing** instead of the
|
|
1513
|
+
**newline-delimited JSON** the MCP spec requires for stdio transport. Result: every
|
|
1514
|
+
JSON-RPC request from Claude Code (`initialize`, `tools/list`, every tool call) hung
|
|
1515
|
+
forever — the server was waiting for `Content-Length: NNN\r\n\r\n` headers that never
|
|
1516
|
+
came. `/mcp` showed "claws — needs auth" / "Failed to reconnect"; `mcp__claws__*` tools
|
|
1517
|
+
were never actually available in any Claude Code session, regardless of install state.
|
|
1518
|
+
|
|
1519
|
+
Fix: `readMessage()` now reads line-by-line; `writeMessage()` appends `\n` instead of a
|
|
1520
|
+
Content-Length header. Verified end-to-end: `initialize` → response, `tools/list` →
|
|
1521
|
+
all 14 tools, `claws_ping` callable from a real Claude Code session.
|
|
1522
|
+
|
|
1523
|
+
The prior "GAP-2 + GAP-3 — MCP spec compliance" commit (b5c2c7c) only fixed the
|
|
1524
|
+
`isError` shape and stderr logging — it never tested the JSON-RPC handshake, so the
|
|
1525
|
+
framing bug shipped in every release through 0.6.0.
|
|
1526
|
+
|
|
1527
|
+
Also bumped `serverInfo.version` from `0.6.0` → `0.6.1`.
|
|
1528
|
+
|
|
1529
|
+
### Added — Behavioral Injection Enforcement (Lifecycle enforcement overhaul)
|
|
1530
|
+
|
|
1531
|
+
Closes the lifecycle enforcement gap identified in `.local/audits/lifecycle-enforcement-gap.md`.
|
|
1532
|
+
Prior to this release, Claude Code defaulted to Bash in new sessions because the behavioral
|
|
1533
|
+
injection system was advisory wallpaper — the strong imperative content existed in orphaned
|
|
1534
|
+
files that nothing auto-loaded.
|
|
1535
|
+
|
|
1536
|
+
**Templates (Wave 1)**
|
|
1537
|
+
- `templates/CLAUDE.project.md` — replaces orphaned `templates/CLAUDE.claws.md`. New template uses
|
|
1538
|
+
imperative framing (`MUST`/`ALWAYS`/`NEVER`) and includes the full 7-step worker boot sequence,
|
|
1539
|
+
lifecycle phase list, and tool inventory with placeholder substitution.
|
|
1540
|
+
- `templates/CLAUDE.global.md` — new machine-wide policy template. Injected into `~/.claude/CLAUDE.md`
|
|
1541
|
+
so every Claude Code session on the machine sees the lifecycle rules, even in non-Claws projects.
|
|
1542
|
+
- `.claude/skills/claws-orchestration-engine/SKILL.md` — rewritten with full 8-phase lifecycle
|
|
1543
|
+
(PLAN→SPAWN→DEPLOY→OBSERVE→RECOVER→HARVEST→CLEANUP→REFLECT) inlined. Removed false claim
|
|
1544
|
+
that lifecycle auto-loads on MCP registration. Deleted dead `lifecycle.yaml`.
|
|
1545
|
+
- `.claude/commands/claws-boot.md` — new `/claws-boot` slash command codifying the exact 7-step
|
|
1546
|
+
worker boot sequence (create → activate → trust → bypass → mission → CR).
|
|
1547
|
+
- `rules/claws-default-behavior.md` — added ECC-only scope note; canonical rules now live in
|
|
1548
|
+
the injected `CLAUDE.md` block.
|
|
1549
|
+
|
|
1550
|
+
**Injector scripts (Wave 2)**
|
|
1551
|
+
- `scripts/inject-claude-md.js` — rewritten to read from `templates/CLAUDE.project.md` instead of
|
|
1552
|
+
hardcoded advisory copy. Substitutes 8 placeholders (`{PROJECT_NAME}`, `{SOCKET_PATH}`,
|
|
1553
|
+
`{TOOLS_V1_LIST}`, `{TOOLS_V2_LIST}`, `{CMDS_LIST}`, etc.).
|
|
1554
|
+
- `scripts/inject-global-claude-md.js` — new script. Writes machine-wide Claws policy to
|
|
1555
|
+
`~/.claude/CLAUDE.md` using `<!-- CLAWS-GLOBAL:BEGIN v1 -->` sentinel. Idempotent.
|
|
1556
|
+
- `scripts/inject-settings-hooks.js` — new script. Registers `SessionStart`, `PreToolUse:Bash`,
|
|
1557
|
+
and `Stop` hooks in `~/.claude/settings.json` with `_source:"claws"` tag for clean uninstall.
|
|
1558
|
+
Supports `--remove` flag to strip all Claws hooks without touching others.
|
|
1559
|
+
- `.claws-bin/hooks/session-start-claws.js` — fires on every Claude Code session start in a Claws
|
|
1560
|
+
project (socket detected). Emits lifecycle rules as a system-reminder.
|
|
1561
|
+
- `.claws-bin/hooks/pre-tool-use-claws.js` — nudges long-running Bash commands toward `claws_create`.
|
|
1562
|
+
- `.claws-bin/hooks/stop-claws.js` — reminds model to close terminals before session ends.
|
|
1563
|
+
|
|
1564
|
+
**Installer wiring (Wave 3)**
|
|
1565
|
+
- `scripts/install.sh` — three additive additions (zero line deletions):
|
|
1566
|
+
- Vendors `hooks/*.js` into project `.claws-bin/hooks/`
|
|
1567
|
+
- Calls `inject-global-claude-md.js` after project CLAUDE.md injection
|
|
1568
|
+
- Calls `inject-settings-hooks.js` to register lifecycle hooks on every install
|
|
1569
|
+
- Adds `.claws-bin/hooks/` to post-install verification checklist
|
|
1570
|
+
|
|
1571
|
+
**Testing**
|
|
1572
|
+
- `scripts/test-enforcement.sh` — integration test covering the full pipeline:
|
|
1573
|
+
inject-claude-md.js (idempotency + imperative content), inject-global-claude-md.js (dry-run),
|
|
1574
|
+
inject-settings-hooks.js (dry-run + tag verification), session-start hook (socket detection),
|
|
1575
|
+
hook exit codes.
|
|
1576
|
+
|
|
1577
|
+
## [0.6.0] - 2026-04-21
|
|
1578
|
+
|
|
1579
|
+
### Added — claws/2 Agentic SDLC Protocol (Phase A + B)
|
|
1580
|
+
|
|
1581
|
+
**New protocol version `claws/2`** — a backward-compatible extension of `claws/1` that adds a message bus, peer identity, and a task registry so an orchestrator Claude can coordinate a fleet of worker Claudes over the existing Unix socket.
|
|
1582
|
+
|
|
1583
|
+
Key additions (all new commands are additive — `claws/1` clients continue to work unchanged):
|
|
1584
|
+
|
|
1585
|
+
- **`hello` handshake** — clients register as `orchestrator`, `worker`, or `observer`. Returns a stable `peerId` for the session. Exactly one orchestrator allowed per socket; a second registration returns an error. Workers that disconnect trigger `worker.offline.<peerId>` events.
|
|
1586
|
+
|
|
1587
|
+
- **Peer registry** (`peer-registry.ts`) — in-memory map of live peers keyed by peerId. Tracks role, peerName, terminalId, subscriptions, and lastSeen. Cleared on extension reload. `WeakMap<Socket, peerId>` enables O(1) cleanup on disconnect.
|
|
1588
|
+
|
|
1589
|
+
- **`subscribe` / `unsubscribe` / `publish`** — named topic pub/sub over the existing socket. Topic patterns support `*` (one segment) and `**` (many segments). Server fans out to matching subscribers. `echo: true` delivers to the sender too.
|
|
1590
|
+
|
|
1591
|
+
- **Server-push frames** — new frame format with `push: 'message'` and no `rid` field. Clients distinguish push frames from responses by the absence of `rid`. Implemented via a dedicated `pushFrame()` helper that catches write errors without crashing the server.
|
|
1592
|
+
|
|
1593
|
+
- **`broadcast`** — orchestrator-only shorthand that fans out a text message to all workers (or all peers by role). Optional `inject: true` also sends the text into each peer's associated terminal via bracketed paste — the "kill switch" for hung workers.
|
|
1594
|
+
|
|
1595
|
+
- **`ping`** — lightweight heartbeat command. Returns `serverTime`. Any command from a peer refreshes its `lastSeen`.
|
|
1596
|
+
|
|
1597
|
+
- **Task registry** (`task-registry.ts`) — in-memory task lifecycle with five commands:
|
|
1598
|
+
- `task.assign` (orchestrator) — creates a task, delivers via pub/sub and/or terminal inject
|
|
1599
|
+
- `task.update` (worker, own tasks only) — reports progress; publishes `task.status`
|
|
1600
|
+
- `task.complete` (worker, own tasks only, idempotent) — finalises the task; publishes `task.completed`
|
|
1601
|
+
- `task.cancel` (orchestrator) — sets `cancelRequested`; publishes `task.cancel_requested.<assignee>`
|
|
1602
|
+
- `task.list` (any role) — filtered snapshot by assignee, status, or updatedAt cursor
|
|
1603
|
+
|
|
1604
|
+
- **MCP client tools** (`mcp_server.js`) — six new tools expose claws/2 to Claude Code: `claws_hello`, `claws_subscribe`, `claws_publish`, `claws_broadcast`, `claws_ping`, `claws_peers`.
|
|
1605
|
+
|
|
1606
|
+
### Fixed
|
|
1607
|
+
- **`.mcp.json` now emits absolute paths** — `command`, `args[0]`, `cwd`, and `CLAWS_SOCKET` are pinned to absolute paths at install time. Eliminates silent failures for nvm/volta/asdf users and CWD-sensitive Claude Code launches. The file is machine-specific and gitignored; the embedded README now says so.
|
|
1608
|
+
|
|
1609
|
+
### Tests
|
|
1610
|
+
- 11 suites, 90+ checks. Three new suites added: `claws-v2-hello` (hello handshake + peer registry), `claws-v2-pubsub` (subscribe/unsubscribe/publish/broadcast + wildcard matching), `claws-v2-tasks` (full task lifecycle including push-frame delivery assertions).
|
|
1611
|
+
|
|
1612
|
+
## [0.5.11] - 2026-04-19
|
|
1613
|
+
|
|
1614
|
+
### Milestone
|
|
1615
|
+
- **First successful external install verified.** End-to-end install on a fresh machine by a user outside the dev environment completed without issues — extension loaded, socket connected, MCP tools live, shell hooks active.
|
|
1616
|
+
|
|
1617
|
+
### Fixed
|
|
1618
|
+
- **Network pre-check before native build (R3.5).** Before `npm run build` runs `@electron/rebuild`, the installer now probes `https://github.com` with a 5-second timeout (curl, then wget fallback). Air-gapped machines or broken network configurations get an immediate actionable warning — including `CLAWS_ELECTRON_VERSION` and `CLAWS_FORCE_REBUILD_NPTY=0` escape hatches — rather than a silent 3-minute hang waiting for Electron headers that will never arrive.
|
|
1619
|
+
- **Nushell hook injection added (R5.4).** After the fish hook block, the installer now checks for `~/.config/nushell/env.nu` or `config.nu`. If either exists and doesn't already contain `CLAWS_DIR`, it appends `$env.CLAWS_DIR` and `$env.CLAWS_SOCKET` assignments in native Nushell syntax. Nushell users no longer need to manually export these variables.
|
|
1620
|
+
- **VSIX install retried with sudo on permission failure (R4.7/B7).** The `--install-extension` loop now attempts a plain install first, then falls back to `sudo` if the first attempt fails (common when the extensions directory is owned by root on shared machines). Both success and failure paths log the outcome.
|
|
1621
|
+
- **Post-install extensions directory verification (R4.10).** After each editor install attempt, the installer checks `~/$HOME/.<editor>/extensions/neunaha.claws-*` to confirm the VSIX actually landed — rather than trusting the undocumented VS Code exit code alone. The verified/unverified distinction is reported in the install log.
|
|
1622
|
+
- **Per-editor ABI mismatch warning (R3.7).** After confirming the native `pty.node` build, the installer reads the `electronVersion` field from Cursor, Windsurf, and VS Code Insiders app bundles. If any editor's Electron version differs from the version the binary was built for, a targeted warning is emitted per editor explaining pipe-mode fallback and providing the exact `CLAWS_ELECTRON_VERSION=<version>` rebuild command.
|
|
1623
|
+
- **Explicit `--arch` passed to `@electron/rebuild` (R3.10).** `bundle-native.mjs` now calls `detectTargetArch()` which honours `CLAWS_ELECTRON_ARCH` env override, then falls back to `process.arch`. On macOS, if Node.js reports `x64` while actually running under Rosetta 2 (detected via `sysctl sysctl.proc_translated`), the user is warned that the binary will be x64 and given the `CLAWS_ELECTRON_ARCH=arm64` override. The detected arch is passed as `--arch` to `@electron/rebuild`.
|
|
1624
|
+
- **`--useCache` and `--cachePath` added to `@electron/rebuild` (R3.4).** Repeated installs no longer recompile `node-pty` from scratch when the ABI-correct binary is already cached. Cache lives at `<repo>/../.electron-rebuild-cache` and is keyed by Electron version + arch.
|
|
1625
|
+
|
|
1626
|
+
## [0.5.10] - 2026-04-19
|
|
1627
|
+
|
|
1628
|
+
### Fixed
|
|
1629
|
+
- **Fish shell hook no longer requires `bass` (R5.3/B3).** Created a standalone `scripts/shell-hook.fish` in pure fish syntax that replicates everything in `shell-hook.sh` — startup banner with socket status and terminal count, plus all four shell functions (`claws-ls`, `claws-new`, `claws-run`, `claws-log`). The `conf.d` loader now sets `CLAWS_DIR`/`CLAWS_SOCKET` and sources `shell-hook.fish` directly. Fish users without `bass` (the majority) previously got only an env var export; now they get the full experience unconditionally.
|
|
1630
|
+
- **Disk space pre-check added (R8.7).** Installer checks `df -k $HOME` at the start of the dependency preflight and warns if less than 500MB is free, before spending time on a clone + native build that will fail mid-way.
|
|
1631
|
+
- **Build failure error now targets the root cause (R8.8).** After a failed `npm run build`, the installer scans `$CLAWS_LOG` for keywords (Xcode/CLT, network/ENOTFOUND, python/gyp) and emits a specific fix command for each case instead of a generic "common causes" list.
|
|
1632
|
+
- **Sensitive env vars purged before `CLAWS_DEBUG` trace (R8.9).** When `CLAWS_DEBUG=1` enables `set -x`, the installer now unsets `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `GITHUB_TOKEN`, `NPM_TOKEN`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and similar vars before enabling the trace, so secrets never appear in debug logs.
|
|
1633
|
+
- **Zed editor documented as unsupported (R4.12).** If `zed` is found in PATH, the installer now prints an explicit info message explaining that Claws is VS Code/Cursor/Windsurf-only (VSIX format) and Zed is not supported.
|
|
1634
|
+
- **`CLAWS_SOCKET` relative-path constraint documented inline (R6.4/B9).** Added a JS comment directly inside the `.mcp.json` write block explaining that `.claws/claws.sock` is relative to Claude Code's CWD (workspace root) and how to use an absolute path for non-standard setups.
|
|
1635
|
+
|
|
1636
|
+
## [0.5.9] - 2026-04-19
|
|
1637
|
+
|
|
1638
|
+
### Fixed
|
|
1639
|
+
- **git minimum version check (R2.1).** Installer now parses the major version from `git --version` and aborts with a clear upgrade message if it's below 2.x.
|
|
1640
|
+
- **git clone stderr was silently discarded (R1.4).** `git clone --quiet` and `git fetch --quiet` swallowed all error output. Removed `--quiet`; errors now append to `$CLAWS_LOG` so network failures and auth errors are inspectable.
|
|
1641
|
+
- **CLAWS_REF pinning mechanism added (R1.5).** `CLAWS_REF="${CLAWS_REF:-main}"` lets users pin to a tag or branch (`CLAWS_REF=v0.5.9 bash install.sh`). All `origin/main` references replaced with `origin/$CLAWS_REF`. Initial clone now tries `--branch $CLAWS_REF` first (works for tags and branches), falls back to default-branch clone.
|
|
1642
|
+
- **git fsck integrity check after clone and update (R1.6).** After every successful clone or update, `git fsck --no-dangling` runs and warns if integrity fails, catching partial/corrupted clones before the build.
|
|
1643
|
+
- **Shallow clone for first-time installs (R1.7).** Initial `git clone` now uses `--depth 1`, significantly reducing download size for users who don't need full history.
|
|
1644
|
+
- **pty.node architecture verification (R3.9).** After the native build, `file "$NATIVE_PTY_BIN"` is checked against `uname -m`. A mismatch (e.g. x86_64 binary on arm64) emits a warning pointing to `$CLAWS_LOG`.
|
|
1645
|
+
- **Step 4 "Runtime check" was a no-op (B4).** The step previously just printed "No Python required — runtime ready" and did nothing. Replaced with a live `node` reachability check (verifies Node.js is still in PATH mid-install) and a pre-check that `mcp_server.js` exists in the clone before the copy step.
|
|
1646
|
+
- **`.gitignore` not created for new projects (R6.13).** The `.claws/` gitignore guard previously skipped projects with no `.gitignore`. Now calls `touch` first so the entry is written regardless.
|
|
1647
|
+
- **inject-claude-md.js error message too generic (B8).** Failure message now references `$CLAWS_LOG` for details instead of just "injector failed".
|
|
1648
|
+
- **No bash -n smoke test after shell hook injection (R5.8).** After each `inject_hook` call for zsh, bash, and bash_profile, the installer now runs `bash -n` on the modified rc file and warns if a syntax error is detected.
|
|
1649
|
+
- **Step-8 .mcp.json check was file-exists only (R7.6).** Replaced with a full `JSON.parse` validation — a truncated or corrupted `.mcp.json` now correctly fails the verification step rather than passing silently.
|
|
1650
|
+
- **Node.js PATH not surfaced in verification (R7.10).** Step 8 now logs the full `process.execPath` of the Node.js binary found in PATH, with a note that GUI-launched VS Code may resolve a different Node.
|
|
1651
|
+
- **Electron version not visible before build (R2.7/R3.2).** Installer now pre-detects the VS Code/Cursor/Windsurf Electron version from their app bundles (macOS) or binaries (Linux) before `npm run build` starts, surfacing the ABI target in the install log.
|
|
1652
|
+
- **@electron/rebuild not verified after npm install (R2.8).** Added `require.resolve('@electron/rebuild')` check after `npm install`; warns immediately if the package is missing rather than letting the build fail 2 minutes later with a cryptic error.
|
|
1653
|
+
|
|
1654
|
+
## [0.5.8] - 2026-04-19
|
|
1655
|
+
|
|
1656
|
+
### Fixed
|
|
1657
|
+
- **nvm/fnm hints were dead code (B10).** Worker B placed the nvm/fnm detection hints *after* the `case "$PLATFORM"` block whose every arm calls `die()`. Since `die()` exits immediately, the hints could never execute — every user with Node installed via nvm or fnm got a generic "node not found" with no actionable guidance. Moved both hints to before the `case` block so they print before the installer exits.
|
|
1658
|
+
- **Stale-clone detection was always-false (B11).** Worker C's dynamic-version fix (v0.5.7) read `EXPECTED_MIN_VERSION` from `extension/package.json`, then immediately set `EXT_VERSION="$EXPECTED_MIN_VERSION"` — making both variables identical. The comparison `[ "$EXT_VERSION" != "$EXPECTED_MIN_VERSION" ]` was therefore always false, silently disabling the stale-clone guard entirely. Restored the original two-variable pattern: `EXPECTED_MIN_VERSION` is hardcoded to the release baseline (`"0.5.7"`); `EXT_VERSION` is dynamically read from the clone's `package.json` at runtime. A stale clone now correctly aborts with a recovery command. EXT_VERSION fallback changed from `"0.5.6"` to `"0.0.0"` so a broken read always triggers the check rather than silently passing.
|
|
1659
|
+
|
|
1660
|
+
## [0.5.7] - 2026-04-19
|
|
1661
|
+
|
|
1662
|
+
### Fixed
|
|
1663
|
+
- **Fish shell hook broken on first install.** The previous fish config block used `source` (invalid in fish) to load the POSIX shell hook. Replaced with native fish syntax: sets `$CLAWS_DIR` as a global env var and optionally calls `bass` to source the POSIX hook if available. Fish users no longer land in a broken `claws_worker` state on first install.
|
|
1664
|
+
- **shell-hook.sh existence guard.** Installer now hard-fails if `shell-hook.sh` is absent from `$INSTALL_DIR/scripts/` before attempting injection, surfacing incomplete clones early.
|
|
1665
|
+
- **No-op source removed from installer end.** The trailing `source "$INSTALL_DIR/scripts/shell-hook.sh"` ran in a subshell and exported nothing to the user's shell. Replaced with an explicit `info` message to open a new terminal.
|
|
1666
|
+
- **Dead code removed from preflight.** `detect_ext_dir()` function and `EXT_DIR` variable were defined but never referenced; removed entirely.
|
|
1667
|
+
- **npm minimum version enforced.** Installer now requires npm 7+ and aborts with a clear upgrade command (`npm install -g npm`) if the detected version is older.
|
|
1668
|
+
- **nvm/fnm hints when node is missing.** If `node` is not found and `~/.nvm` or `~/.fnm` exists, installer surfaces the exact command to activate the version manager before failing.
|
|
1669
|
+
- **Windows guard added.** Git Bash / MSYS / Cygwin environments now get an immediate `die` with a WSL2 redirect instead of failing mid-install on Unix-specific operations.
|
|
1670
|
+
- **Architecture logged in preflight.** `uname -m` output (`x86_64` / `arm64`) now appears in the preflight summary — essential context for diagnosing node-pty ABI mismatches.
|
|
1671
|
+
- **`EXPECTED_MIN_VERSION` is now dynamic.** Previously hardcoded to a static string at script-release time; now read from `extension/package.json` at runtime so version drift between the script and the manifest is impossible.
|
|
1672
|
+
- **vsce output routed to `$CLAWS_LOG`.** VSIX packaging errors were silently swallowed (`>/dev/null 2>&1`). Now appended to the install log file so failures are inspectable without re-running with verbose flags.
|
|
1673
|
+
- **Publisher field pre-checked before VSIX packaging.** If `extension/package.json` is missing the `publisher` field, `vsce` fails with an opaque error. Installer now checks the field and warns early.
|
|
1674
|
+
- **VSIX size sanity check.** A packaged VSIX under 50 KB is almost certainly missing the native binary (`!native/**` absent from `.vscodeignore`). Installer now rejects suspiciously small VSIXes rather than installing a broken extension.
|
|
1675
|
+
- **`.mcp.json` validated after write.** The node script that writes `.mcp.json` is now followed by a `JSON.parse` check; invalid JSON emits `bad` messages pointing to the log before continuing.
|
|
1676
|
+
- **`.claws/` added to project `.gitignore` automatically.** If the project `.gitignore` exists but doesn't contain `.claws/`, the installer appends it.
|
|
1677
|
+
- **`inject-claude-md.js` existence guard.** Before invoking `inject-claude-md.js`, the installer now checks both candidate paths and skips with a `warn` if neither exists, rather than crashing.
|
|
1678
|
+
- **Shell hook verification before final banner.** Installer now checks `~/.zshrc`, `~/.bashrc`, and `~/.bash_profile` for the hook marker and warns if none is found, prompting the user to source it manually.
|
|
1679
|
+
|
|
1680
|
+
## [0.5.6] - 2026-04-18
|
|
1681
|
+
|
|
1682
|
+
### Fixed
|
|
1683
|
+
- **VSIX never installed (regression in v0.5.5).** The v0.5.5 rewrite of the build section forgot to set `BUILD_OK=1` after a successful `npm run build`, so the condition at line 486 (`[ "${BUILD_OK:-0}" = "1" ]`) was always false. Every user was silently getting the symlink fallback — VSIX install was completely bypassed.
|
|
1684
|
+
- **git pull --ff-only failed silently AND printed a green checkmark anyway.** On a dirty `~/.claws-src/` (local changes, diverged history, offline), `git pull --ff-only` would fail, `warn` would fire, and then `ok "updated"` would print unconditionally on the next line. Replaced with `git fetch origin main && git reset --hard origin/main`. On failure, installer now hard-exits with a concrete recovery command (`rm -rf ~/.claws-src && re-run`).
|
|
1685
|
+
- **Version stale check warned and continued.** When git fetch/reset updated `~/.claws-src/` to a newer version, the old `EXPECTED_MIN_VERSION` check would detect a mismatch and warn — but then continue with the stale code. Now dies with the recovery command instead of silently shipping v0.4.0 while the banner says v0.5.6.
|
|
1686
|
+
- **Linux Electron detection completely absent from bundle-native.mjs.** On Linux, `detectElectronVersion()` had no detection logic and fell straight to the hardcoded fallback (`39.8.5`). VS Code on modern Ubuntu typically ships Electron 30–35, so every Linux user got the wrong ABI → pipe-mode. Added detection via VS Code's bundled `electron` binary at known Linux install paths (`/usr/share/code/electron`, `/opt/visual-studio-code/electron`, `/snap/code/current/electron`, etc.).
|
|
1687
|
+
|
|
1688
|
+
## [0.5.5] - 2026-04-18
|
|
1689
|
+
|
|
1690
|
+
### Fixed
|
|
1691
|
+
- **Pipe-mode-after-install bug eliminated for good.** Previously, `scripts/install.sh` had two separate node-pty handling paths: `npm run build` (which runs `bundle-native.mjs` → `@electron/rebuild` → copies the ABI-correct binary into `extension/native/node-pty/`) AND a *second, redundant* `@electron/rebuild` run against `node_modules/node-pty/` whose output never made it into the VSIX. If `npm run build` failed silently, the installer fell back to legacy JS, packaged a VSIX without a working `native/node-pty/build/Release/pty.node`, and the extension landed in pipe-mode — exactly what Miles was seeing. The installer now has ONE canonical build path: `npm run build`. If it fails, the installer aborts with a concrete diagnostic (Xcode CLT missing, @electron/rebuild network failure, node-gyp error) instead of shipping a broken VSIX. After the build, it hard-verifies `native/node-pty/build/Release/pty.node` exists and reports which Electron version it was built for; if the binary is missing, install aborts rather than completing "successfully" with a VSIX that can't load node-pty.
|
|
1692
|
+
- **Pre-flight Xcode Command Line Tools check on macOS.** `@electron/rebuild` needs a C compiler. The installer now checks `xcode-select -p` up front and aborts with the exact recovery command (`xcode-select --install`) before wasting the user's time attempting a build that cannot succeed.
|
|
1693
|
+
- **`npm run build` output is no longer silent during install.** The previous `--silent` flag hid `@electron/rebuild` progress and compile errors, turning every native build failure into an invisible "falling back to legacy JS" warn. Users now see the bundle-native.mjs output on screen and in `$CLAWS_LOG`, so diagnosing a broken build is a copy-paste away.
|
|
1694
|
+
|
|
1695
|
+
### Removed
|
|
1696
|
+
- Redundant second `@electron/rebuild` run against `node_modules/node-pty/` in `install.sh`. `bundle-native.mjs` is the single source of truth for the ABI-correct binary; the duplicated rebuild only rebuilt a directory the VSIX didn't ship and masked `bundle-native.mjs` failures.
|
|
1697
|
+
|
|
1698
|
+
### Migration notes
|
|
1699
|
+
- Users affected by pipe-mode just need to re-run the curl install once. The v0.5.5 installer will either produce a working VSIX (binary present, Electron version matches) or abort with a concrete next step — no more invisible failures.
|
|
1700
|
+
|
|
1701
|
+
## [0.5.4] - 2026-04-18
|
|
1702
|
+
|
|
1703
|
+
### Fixed
|
|
1704
|
+
- **Shell hook injection now self-heals on every install/update.** The old `inject_hook` in `scripts/install.sh` only *added* a `source /path/to/shell-hook.sh` line when no `# CLAWS terminal hook` marker was present; it never removed stale entries. Users who ran the installer under a different `CLAWS_DIR` (e.g. pointing at a project root during testing) ended up with broken `.zshrc` lines like `source:31: no such file or directory: /Users/miles/renew/scripts/shell-hook.sh` that fired on every new shell. The function now strips any existing `# CLAWS terminal hook` marker plus the following line via `sed`, then appends a fresh entry using the current `INSTALL_DIR`. If a stale path was removed, the banner reports `refreshed in .zshrc (removed stale path)` so the fix is visible.
|
|
1705
|
+
- **Fish shell config is now idempotent too.** `~/.config/fish/conf.d/claws.fish` was only written when absent, leaving stale `INSTALL_DIR` references alive across reinstalls. The installer now overwrites it unconditionally so fish stays in sync with the zsh/bash hooks.
|
|
1706
|
+
|
|
1707
|
+
### Migration notes
|
|
1708
|
+
- Users affected by stale `.zshrc` / `.bashrc` / `.bash_profile` lines just need to re-run the curl install once. The v0.5.4 installer deletes the broken line and installs a fresh one in the same pass — no manual editing of dotfiles required.
|
|
1709
|
+
|
|
1710
|
+
## [0.5.3] - 2026-04-18
|
|
1711
|
+
|
|
1712
|
+
### Changed
|
|
1713
|
+
- **Extension install path switched from symlink to `code --install-extension <vsix>`.** When VS Code's CLI is available, the installer now packages the extension as a `.vsix`, runs `code --install-extension --force` for every detected editor (VS Code, Cursor, Insiders, Windsurf), and VS Code itself handles extension registration and shows its standard "Reload to activate?" toast in any running window. Single-click activation vs the old "hope VS Code noticed the symlink" pattern.
|
|
1714
|
+
- **Install banner reports the install method** explicitly: `(method: vsix)` or `(method: symlink)` so users know which code path landed.
|
|
1715
|
+
|
|
1716
|
+
### Added
|
|
1717
|
+
- `CLAWS_DEV_SYMLINK=1` env var forces symlink install (developer workflow — edit TypeScript → reload → test without re-packaging).
|
|
1718
|
+
- Detects editor CLIs in both `$PATH` and macOS app bundles (`/Applications/<Editor>.app/Contents/Resources/app/bin/<cli>`) so VSIX install works even when the user never ran "Shell Command: Install 'code' in PATH".
|
|
1719
|
+
- Symlink install remains as fallback when VSIX packaging fails, when `npx` is unavailable, or when `CLAWS_DEV_SYMLINK=1` is set. Never silent — the banner shows which path was used.
|
|
1720
|
+
|
|
1721
|
+
### Fixed
|
|
1722
|
+
- The previous symlink-only install required users to manually `Developer: Reload Window` and hope VS Code picked up the new symlink. VSIX install via `code --install-extension` means VS Code proactively notices the extension and prompts the user via its own toast.
|
|
1723
|
+
|
|
1724
|
+
### Migration notes
|
|
1725
|
+
- Re-run the curl install once. The new installer will package a VSIX, call `code --install-extension --force`, and VS Code will show a reload toast in any open window (or auto-load on next open). No change needed in how you invoke `/claws-update` or the install curl URL.
|
|
1726
|
+
- Works now because Phase 2 (v0.4.0) moved `node-pty` from `node_modules/` to `native/node-pty/` — `vsce package` used to strip `node_modules/` and break the runtime load, but `.vscodeignore` allows `!native/**` through so the VSIX now contains the ABI-correct binary.
|
|
1727
|
+
|
|
1728
|
+
## [0.5.2] - 2026-04-18
|
|
1729
|
+
|
|
1730
|
+
### Fixed
|
|
1731
|
+
- **Stale-clone bug (critical)** — The installer's `git pull --ff-only --quiet || warn` allowed a failed fetch (dirty tree, diverged history, network hiccup) to fall through to "✓ updated" without actually updating `~/.claws-src/`. Users ended up running the installer against stale source and seeing banners like "Terminal Control Bridge v0.4.0 — installed" even though main was at v0.5.1. Replaced with `git fetch origin main && git reset --hard origin/main`, with an explicit SHA-transition log line (`✓ already at origin/main (abc1234)` or `✓ updated abc1234 → def5678`).
|
|
1732
|
+
- **Stale-version detection in step 2b** — The installer now compares the extension's actual `package.json` version against an `EXPECTED_MIN_VERSION` pinned at script-release time. If the working tree is older than what this installer expects, the installer prints a loud warning with the recovery command (`rm -rf ~/.claws-src && re-run`).
|
|
1733
|
+
- **Installer failure modes made explicit** — `git fetch` failing now prints a concrete diagnostic suggesting offline/diverged causes; `git reset --hard` failing prints a clean-slate recovery command and exits rather than continuing with broken state.
|
|
1734
|
+
|
|
1735
|
+
### Migration notes
|
|
1736
|
+
- This is a transparent upgrade — users on v0.5.0 / v0.5.1 just need to re-run the curl install command. The new installer force-resets their `~/.claws-src/` to match origin/main.
|
|
1737
|
+
- If your `~/.claws-src/` had local edits (unlikely but possible), they'll be lost by the reset. `~/.claws-src/` is not meant to be edited by hand; do development in a separate clone.
|
|
1738
|
+
|
|
1739
|
+
## [0.5.1] - 2026-04-18
|
|
1740
|
+
|
|
1741
|
+
### Added
|
|
1742
|
+
- **Extension copy in every project** — `install.sh` now copies the built VS Code extension (`dist/`, `native/`, `package.json`, `README`, `CHANGELOG`) into `<project>/.claws-bin/extension/` on every install and update. Purely for visibility — VS Code still loads the extension from the user-level install at `~/.vscode/extensions/neunaha.claws-<version>`, not from this copy. Size: ~300–400 KB per project. Opt out with `CLAWS_SKIP_EXTENSION_COPY=1`.
|
|
1743
|
+
- **`.claws-bin/README.md`** — auto-generated in every project. Documents what each file in `.claws-bin/` does, explains why the extension lives at user-scope (VS Code design), provides gitignore guidance, and includes install + update curl URLs for teammates.
|
|
1744
|
+
- **Verify step** now reports the presence of the project-local extension copy + the `README.md`.
|
|
1745
|
+
|
|
1746
|
+
### Changed
|
|
1747
|
+
- **End-of-install banner rewritten** — the post-install instructions are now a single action: **Reload VS Code**. The Claude Code restart step is no longer called out as a separate required action; new `claude` sessions auto-pick-up `.mcp.json` without manual restart (only users mid-session in a pre-install Claude Code need to restart, which is their natural lifecycle anyway).
|
|
1748
|
+
- Banner now prints the exact extension symlink path (`~/.vscode/extensions/neunaha.claws-<version>`) AND the project-local visible copy path, so users can see both where VS Code loads from and where the files live in their project.
|
|
1749
|
+
|
|
1750
|
+
### Migration notes from v0.5.0
|
|
1751
|
+
- No code changes required. Next `/claws-update` automatically gets the extension copy and README. Existing project files (`.mcp.json`, `.claude/`, `CLAUDE.md`) are untouched.
|
|
1752
|
+
- If you want to opt out of the extension copy (disk-sensitive projects, etc.): set `CLAWS_SKIP_EXTENSION_COPY=1` before running install/update. The extension still installs at user-scope.
|
|
1753
|
+
- The new files are safe to commit (~300 KB total) OR gitignore — see `<project>/.claws-bin/README.md` for guidance.
|
|
1754
|
+
|
|
1755
|
+
## [0.5.0] - 2026-04-18
|
|
1756
|
+
|
|
1757
|
+
### Architecture
|
|
1758
|
+
- **Phase 6 hardening sweep** — server, core modules, and extension polish landed in two passes (6A + 6B). Net result: 57 automated checks (up from 22 in v0.4.0), full async deactivate lifecycle, runtime-readable server config, stable UUID-based profile adoption, and a marketplace-ready command surface.
|
|
1759
|
+
- **`server-config.ts` provider pattern** — the socket server no longer holds hard-coded values for exec-timeout / poll-limit. Extension-level code passes a `ServerConfigProvider` closure that reads live from `vscode.workspace.getConfiguration('claws')` on every request, so `settings.json` edits take effect without a window reload.
|
|
1760
|
+
- **`IntrospectProvider` pattern** — the new `introspect` protocol command is powered by a provider passed into the server, keeping `server.ts` free of any direct `vscode` import. One snapshot shape is consumed by both the CLI-via-socket path and the in-UI Health Check command.
|
|
1761
|
+
- **UUID-based profile adoption** — wrapped terminals spawned via the `+` dropdown now embed a crypto-random UUID token in the terminal name (visible as `Claws Wrapped N · abcd1234 [full-uuid]`). Match-on-open is by UUID, not numeric id, eliminating the race where two simultaneous profile provisions could bind to each other's PTY.
|
|
1762
|
+
|
|
1763
|
+
### Added
|
|
1764
|
+
- **`introspect` socket command** — returns `extensionVersion`, `nodeVersion`, `electronAbi`, `platform`, `nodePty: { loaded, loadedFrom, error }`, `servers: [{ workspace, socket }]`, `terminals`, `uptime_ms`. Feeds both the MCP client diagnostics and the in-UI Health Check.
|
|
1765
|
+
- **`Claws: Uninstall Cleanup` command** — scans open workspace folders, inventories Claws-installed files (`.mcp.json` claws entry, `.claws-bin/`, `.claude/commands/claws-*.md`, skill directories, `.vscode/extensions.json` recommendations, `CLAUDE.md` fenced block), shows a per-folder confirmation, removes only what was actually installed, and writes a summary to the Output channel. Reversible-by-git, destructive-outside-git — modal warning before every removal.
|
|
1766
|
+
- **Status bar item** — right-aligned, priority 100, shows `$(terminal) Claws (N)` where N is the live terminal count. Tooltip is a rich `MarkdownString` with socket list, node-pty status, and version. Click → Health Check. Color shifts to warning-yellow in pipe-mode, error-red when no server is running. Auto-refreshes every 30s via `unref`'d interval.
|
|
1767
|
+
- **Command palette `Claws:` grouping** — every contributed command now has an explicit `"category": "Claws"`, so the palette renders them as one cluster.
|
|
1768
|
+
- **Keybindings** (chord, non-intrusive): `ctrl+alt+c h` / `cmd+alt+c h` → Health Check; `ctrl+alt+c l` / `cmd+alt+c l` → Show Log; `ctrl+alt+c s` / `cmd+alt+c s` → Show Status.
|
|
1769
|
+
- **`claws.statusBar` command** — manual refresh + re-show hook for the status bar item; useful after a theme swap or a window focus cycle.
|
|
1770
|
+
- **Version-mismatch detection** — when a client request includes `clientVersion`, the server compares against the running extension version and logs a one-shot warning to the Output channel on drift ≥ 1 minor release. MCP server version is also displayed in the Health Check by reading `<workspace>/.claws-bin/package.json` or parsing a `version: 'x.y.z'` literal from the MCP source.
|
|
1771
|
+
- **`onCommand:` activationEvents** — `claws.healthCheck`, `claws.showLog`, `claws.status`, `claws.statusBar`, `claws.listTerminals`, `claws.rebuildPty`, `claws.uninstallCleanup` are all registered as activation triggers alongside `onStartupFinished`, so users can invoke diagnostic commands even if the startup activation was skipped.
|
|
1772
|
+
- **Two new test suites** — `test/profile-provider.test.js` (6 checks: provider registration, UUID match-on-open, concurrent provision safety, socket-visible adoption) and `test/multi-connection.test.js` (8 checks: 3 concurrent connections × 3 interleaved requests, per-connection rid correlation, introspect shape). Run via `npm run test:profile` and `npm run test:multiconn`.
|
|
1773
|
+
- **Phase 6A checks** (already landed, recapped here for completeness): oversized-line defense + fresh-connection-still-alive probe, capture-store ring-buffer trim + stripAnsi coverage, config hot-reload, pty lifecycle (`mode`, `hasOpened`, `ageMs`, sanitizeEnv), orphan-PTY scan timer in `TerminalManager.dispose()`, and protocol-tag rejection.
|
|
1774
|
+
|
|
1775
|
+
### Changed
|
|
1776
|
+
- **`displayName`** bumped from `"Claws — Terminal Control Bridge"` to `"Claws: Programmable Terminal Bridge"`. Clearer marketplace positioning; leads with the outcome ("programmable") rather than the mechanism ("bridge").
|
|
1777
|
+
- **`claws.status`** emits a markdown-style status block with section headers (`# Claws Status`, `## Sockets`, `## Runtime`) instead of a single-line dump. Renders well in the Output channel and copies cleanly into bug reports.
|
|
1778
|
+
- **`claws.listTerminals`** now opens a VS Code QuickPick with each terminal as a selectable item (`id · name · wrapped(pty)/unwrapped · pid`). Selecting an item calls `terminal.show()` on it. Falls through to an info message when no terminals are open.
|
|
1779
|
+
- **`deactivate()` is now async** — returns `Promise<void>`. Stops every server in the `servers` Map, calls `TerminalManager.dispose()` to clear the orphan-PTY scan timer, disposes every pending profile PTY, disposes the status bar item and its refresh timer, disposes the Output channel, and logs a final state line (`N/M sockets closed`). Wrapped in a `Promise.race` with a 3-second ceiling so a slow dispose can't hang VS Code shutdown.
|
|
1780
|
+
- **Extension `version`** bumped to `0.5.0`. Root `package.json` (`claws-cli`) and `mcp_server.js` `serverInfo.version` also bumped to `0.5.0` for parity.
|
|
1781
|
+
|
|
1782
|
+
### Fixed
|
|
1783
|
+
- **#6 — createWrapped vs profile-provider name collision.** Name-based match-on-open was brittle when two provisions ran concurrently (both could use "Claws Wrapped 3" before the id increment landed). Now every pending profile carries a UUID token in its name; `onDidOpenTerminal` matches by full-UUID substring. The orphan-timeout path is preserved.
|
|
1784
|
+
- **#13/#14 — unwired `ServerOptions.getConfig`.** Phase 6A shipped the hook but the extension never passed a value in. v0.5.0 wires it to `cfg('execTimeoutMs', …)` / `cfg('pollLimit', …)`.
|
|
1785
|
+
- Test mocks updated to cover the new `vscode.window.createStatusBarItem`, `MarkdownString`, `ThemeColor`, and `StatusBarAlignment` surface area. Existing tests continue to pass against both sync and async `deactivate()` call shapes.
|
|
1786
|
+
|
|
1787
|
+
### Deprecated
|
|
1788
|
+
- Nothing newly deprecated in 0.5.0. The 0.4.0-era deprecations (`scripts/terminal-wrapper.sh`, `extension/src/extension.js`) remain — both are scheduled for removal once the Pseudoterminal path has been marketplace-published.
|
|
1789
|
+
|
|
1790
|
+
### Migration notes for v0.4 users
|
|
1791
|
+
- The new `Claws: Uninstall Cleanup` command is OPT-IN — it never runs automatically. It's safe to ignore unless you're actually removing Claws from a project.
|
|
1792
|
+
- Keybindings are added; if you already have `ctrl+alt+c`-prefixed chords bound to something else, VS Code will surface the conflict in `Keyboard Shortcuts`. Override ours there; the extension will still work without them.
|
|
1793
|
+
- The status bar item is visible by default. To hide it, right-click the status bar and uncheck "Claws".
|
|
1794
|
+
- If you were consuming `deactivate()` externally (unit tests, harness scripts), it now returns a Promise. `await ext.deactivate()` is the correct invocation. Calling without `await` still works but the 100ms sleep you may have used to drain teardown is now strictly unnecessary.
|
|
1795
|
+
- `claws.listTerminals` used to dump to the Output channel; it now opens a QuickPick. If you had a keybinding or macro that expected Output-channel output, use the new `claws.status` which still renders a textual block.
|
|
1796
|
+
|
|
1797
|
+
## [0.4.0] - 2026-04-18
|
|
1798
|
+
|
|
1799
|
+
### Architecture
|
|
1800
|
+
- **Extension rewritten in TypeScript** — 8 modular files (`extension.ts`, `server.ts`, `terminal-manager.ts`, `claws-pty.ts`, `capture-store.ts`, `protocol.ts`, `safety.ts`, `ansi-strip.ts`), strict mode, esbuild bundle → `dist/extension.js`.
|
|
1801
|
+
- **Pseudoterminal replaces `script(1)` wrapping** — wrapped terminals now run under VS Code's native `vscode.Pseudoterminal` with `node-pty` (or `child_process` pipe-mode fallback). Fixes TUI rendering corruption in Claude Code, vim, htop, k9s, and other Ink/ncurses apps.
|
|
1802
|
+
- **In-memory ring buffer replaces file-tailing** for `readLog` on Pseudoterminal-backed terminals. No more `.claws/terminals/*.log` files for new wrapped terminals; the buffer is configurable via `claws.maxCaptureBytes` (default 1 MB per terminal).
|
|
1803
|
+
|
|
1804
|
+
### Added
|
|
1805
|
+
- **Blocking `claws_worker` lifecycle** — one tool call runs the full worker flow: spawn wrapped terminal → optional Claude Code boot with `boot_marker` detection → send mission → poll capture buffer for `complete_marker` / `error_markers` → harvest last N lines → auto-close → return structured result with `status`, `duration_ms`, `marker_line`, `cleaned_up`, `harvest`. Configurable via `timeout_ms`, `boot_wait_ms`, `poll_interval_ms`, `harvest_lines`, `close_on_complete`. Legacy fire-and-forget behavior via `detach: true`.
|
|
1806
|
+
- **Project-local install** — `scripts/install.sh` now writes into the current project root as the primary target:
|
|
1807
|
+
- `<project>/.mcp.json` — registers Claws MCP server with relative path `./.claws-bin/mcp_server.js`
|
|
1808
|
+
- `<project>/.claws-bin/{mcp_server.js,shell-hook.sh}` — self-contained, no dependency on `~/.claws-src`
|
|
1809
|
+
- `<project>/.claude/commands/` — all 19 `claws-*` slash commands
|
|
1810
|
+
- `<project>/.claude/rules/claws-default-behavior.md`
|
|
1811
|
+
- `<project>/.claude/skills/{claws-orchestration-engine,claws-prompt-templates}/`
|
|
1812
|
+
- Global `~/.claude/*` install is now opt-in via `CLAWS_GLOBAL_CONFIG=1` and `CLAWS_GLOBAL_MCP=1`.
|
|
1813
|
+
- **Dynamic CLAUDE.md injection** — fenced with `<!-- CLAWS:BEGIN --> ... <!-- CLAWS:END -->`. Block content is generated at install time (lists actually-installed tools and slash commands). Re-install replaces only the fenced section, preserving every other line of the project's CLAUDE.md.
|
|
1814
|
+
- **Automatic legacy CLAUDE.md migration** — on upgrade, the installer strips the old `## CLAWS — Terminal Orchestration Active` section (v0.1–v0.3) before inserting the new fenced block. Original project content on either side of the old section is preserved.
|
|
1815
|
+
- **Extension test suite** — `extension/test/smoke.test.js` (5 checks: bundle load, socket server, protocol, cleanup) and `extension/test/worker.test.js` (6 checks: blocking lifecycle, marker detection, detach mode) — both run via `npm test`.
|
|
1816
|
+
- **Big end-of-install ASCII banner** with 3-step activation guidance (reload VS Code → restart Claude Code → `/claws-help`) and troubleshooting pointer (`/claws-fix`).
|
|
1817
|
+
|
|
1818
|
+
### Changed
|
|
1819
|
+
- Extension entry point: `main` now points at `./dist/extension.js` (built from TypeScript). Legacy `./src/extension.js` is preserved as a fallback; the installer repoints `main` to it if the TypeScript build fails.
|
|
1820
|
+
- Install verification expanded from 4 to 10 checks; MCP handshake test uses a portable Node driver (no dependency on GNU `timeout`, works on macOS out of the box).
|
|
1821
|
+
- `extension/package.json` adds `devDependencies` (`typescript`, `esbuild`, `@types/vscode`, `@types/node`) and `optionalDependencies` (`node-pty`). Pure Node stdlib remains the only runtime requirement.
|
|
1822
|
+
|
|
1823
|
+
### Deprecated
|
|
1824
|
+
- `scripts/terminal-wrapper.sh` — kept for v0.1–v0.3 compatibility but unused by new Pseudoterminal-backed wrapped terminals. Will be removed in v0.5.
|
|
1825
|
+
- `extension/src/extension.js` (legacy JS) — kept as fallback; will be removed once Pseudoterminal path is marketplace-published.
|
|
1826
|
+
|
|
1827
|
+
### Migration notes for v0.3 users running `/claws-update`
|
|
1828
|
+
- Your project gets a new `.mcp.json`, `.claws-bin/`, and project-local `.claude/` — safe to commit or gitignore per your preference.
|
|
1829
|
+
- CLAUDE.md's legacy Claws section is automatically stripped and replaced with the new fenced block. Expect to see `CLAUDE.md legacy section migrated; Claws block inserted` during install.
|
|
1830
|
+
- The old global `~/.claude/settings.json` claws MCP entry remains but becomes inactive when the project-local `.mcp.json` takes precedence. Safe to leave or remove manually.
|
|
1831
|
+
- `claws_worker` return-text format changed. If you had automation parsing the old output (`worker 'X' spawned with Claude Code...`), it will need updating. The new format leads with `worker 'X' COMPLETED|FAILED|TIMEOUT` followed by structured fields and a `── harvest (last lines) ──` section.
|
|
1832
|
+
|
|
1833
|
+
## [0.3.0] - 2026-04-14
|
|
1834
|
+
|
|
1835
|
+
### Changed
|
|
1836
|
+
- MCP server rewritten from Python to Node.js — zero dependencies
|
|
1837
|
+
- Install no longer requires Python, pip, or brew
|
|
1838
|
+
- Shell hook commands rewritten from Python to Node.js
|
|
1839
|
+
|
|
1840
|
+
### Removed
|
|
1841
|
+
- Python dependency from install path (Python client remains as optional)
|
|
1842
|
+
|
|
1843
|
+
## [0.2.0] - 2026-04-18
|
|
1844
|
+
|
|
1845
|
+
### Added
|
|
1846
|
+
- **MCP Server** — register once, every Claude Code session gets 8 terminal control tools natively
|
|
1847
|
+
- **Orchestration Engine skill** — 7 patterns (scout, single worker, parallel fleet, AI session driver, pipeline stages, watchdog, orchestrator with delegation)
|
|
1848
|
+
- **Lifecycle YAML protocol** — 8-phase terminal lifecycle (plan → spawn → deploy → observe → recover → harvest → cleanup → reflect)
|
|
1849
|
+
- **Prompt engineering guide** — `/claws-help` with 5 levels from beginner to power user
|
|
1850
|
+
- **Default behavior rule** — Claude prefers visible Claws terminals over silent Bash
|
|
1851
|
+
- **CLAUDE.md injection** — installer appends Claws orchestration context to project CLAUDE.md
|
|
1852
|
+
- **Shell hook** — every terminal shows CLAWS banner with bridge status + 4 shell commands (claws-ls, claws-new, claws-run, claws-log)
|
|
1853
|
+
- **Auto-launch Claude Code** — `claws_worker` auto-starts `claude --dangerously-skip-permissions` in worker terminals
|
|
1854
|
+
- **Click-to-copy install prompt** on landing page
|
|
1855
|
+
- **npx claws-cli** — Node.js CLI installer with `claude mcp add` support
|
|
1856
|
+
- **11 slash commands** — /claws-help, /claws-install, /claws-update, /claws-status, /claws-connect, /claws-create, /claws-send, /claws-exec, /claws-read, /claws-worker, /claws-fleet
|
|
1857
|
+
- **7 prompt templates** — single worker, analysis, multi-commit, pair programming, parallel fleet, graphify-driven, error recovery
|
|
1858
|
+
- **6 cinematic capability images** — terminal mgmt, pty capture, exec, safety gate, MCP, cross-device
|
|
1859
|
+
- **GitHub Pages landing page** — full website with carousels, stats, animations, case studies
|
|
1860
|
+
- **Cross-platform installer** — bash (macOS/Linux) + PowerShell (Windows), auto-detects VS Code/Cursor/Windsurf
|
|
1861
|
+
- **Live demo test script** — spawns 3 parallel workers to prove orchestration works
|
|
1862
|
+
|
|
1863
|
+
### Fixed
|
|
1864
|
+
- Linux `script(1)` compatibility — auto-detects BSD vs GNU arg order
|
|
1865
|
+
- Shell injection in `claws-run` — commands passed via temp file, not interpolated
|
|
1866
|
+
- `nc -U` dependency removed — all shell commands use Python sockets
|
|
1867
|
+
- Install step numbering consistent [1/8] through [8/8]
|
|
1868
|
+
- MCP server tilde path warning in docs
|
|
1869
|
+
- Installer never exits — `set +e`, all checks are warnings not blockers
|
|
1870
|
+
- `pip` install uses `python -m pip` with `--break-system-packages` for macOS compatibility
|
|
1871
|
+
|
|
1872
|
+
### Changed
|
|
1873
|
+
- `/claws-update` is now a full rebuild (re-runs entire installer), not just git pull
|
|
1874
|
+
|
|
1875
|
+
## [0.1.0] - 2026-04-17
|
|
1876
|
+
|
|
1877
|
+
### Added
|
|
1878
|
+
- Initial release
|
|
1879
|
+
- Unix socket server with newline-delimited JSON protocol
|
|
1880
|
+
- Terminal management: list, create, show, send, close
|
|
1881
|
+
- Wrapped terminals via `script(1)` for full pty capture
|
|
1882
|
+
- `readLog` command with ANSI stripping
|
|
1883
|
+
- `exec` command with file-based output capture
|
|
1884
|
+
- `poll` command for shell-integration event streaming
|
|
1885
|
+
- Safety gate: foreground process detection + warnings for non-shell TUIs
|
|
1886
|
+
- Bracketed paste mode for multi-line sends
|
|
1887
|
+
- "Claws Wrapped Terminal" dropdown profile
|
|
1888
|
+
- Python client library (`claws-client`)
|
|
1889
|
+
- Example scripts: basic orchestrator, parallel workers
|
|
1890
|
+
|
|
1891
|
+
- docs(architecture) — comprehensive ARCHITECTURE.md as the canonical anchor: charter, 10 architectural principles (event-driven only, atomic writes, hooks safety, no orchestrator-side patches, etc.), full system layer map, protocol specs, lifecycle architecture, 5-layer enforcement chain, test invariants, anti-patterns catalog (10 burned-in lessons), known gaps + roadmap, and an anchoring protocol for future PRs.
|
|
1892
|
+
- fix(v0.7.10) — worker-fixes-v079.test: sync scanText check to detectCompletion(scanText,opt) (replaces scanText.includes pattern removed when findStandaloneMarker was introduced); restore 17/17 pass.
|
|
1893
|
+
- fix(v0.7.10) — claws-v2-vehicle-state.test: add workerMode:single+expectedWorkers:1 to lifecycle.plan call and lifecycle.advance to SPAWN before create (canSpawn gate, schema v3 required fields).
|
|
1894
|
+
- fix(v0.7.10) — lifecycle-store.ts: add M-43 sentinel comment to flushToDisk() (fsyncSync-before-renameSync parity with M-29; fixes lifecycle-store-fsync test).
|
|
1895
|
+
- feat(v0.7.10) — scripts: install.sh dev-mode symlink branch (eliminates source/.claws-bin drift), F-11 .electron-abi cache, dynamic EXPECTED_MIN_VERSION, .gitignore auto-additions, backup pruning; install.ps1 stub directs Windows to WSL2; update.sh Linux Electron ABI detection + BUG-28 health check; uninstall.sh idempotent 5-step removal.
|
|
1896
|
+
- feat(v0.7.10) — templates: CLAUDE.global.md + CLAUDE.project.md add capabilities:[push] requirement (BUG-03), worker.<peerId>.heartbeat correction (BUG-06), Sidecar mandatory section, Monitor mandatory section.
|
|
1897
|
+
- docs(v0.7.10) — commands + skills aligned with non-blocking defaults: claws-army/fleet/wave-lead/worker.md document fire/poll/audit pattern; claws-orchestration-engine SKILL upgraded to 10-phase ring; wave-lead/wave-subworker SKILLs add Monitor arm step 0 + BUG-03/06/10 fixes. New /claws-install command. New claws-prompt-templates SKILL library. New .claude/rules/ dir. README tool count synced 14→38.
|
|
1898
|
+
- fix(v0.7.10) — test fixture sync: lifecycle-server.test now expects [SESSION-BOOT, PLAN]; reverse-channel.test calls lifecycle.advance to SPAWN; server-validation.test expects payload:invalid; worker-fixes-v079.test regex syncs for detach !== false + findStandaloneMarker. Removes unused Phase import (lifecycle-engine.ts) and dead _requireCapability method (server.ts).
|
|
1899
|
+
- test(v0.7.10) — non-blocking-defaults (10 checks: detach !== false default, withMaxHold 8s ceiling) and sidecar-enforcement (18 checks: _ensureSidecarOrThrow guards all 4 spawn handlers, singleton dedup, read-only handlers ungated). Both pass.
|
|
1900
|
+
|
|
1901
|
+
- **chore(v0.7.10)**: Wave C precursor work landed — pre-tool-use hook fail-closed (BUG-16 argv0 allowlist, BUG-27 mcp_server.js edit gate, BUG-28 spawn-class Monitor arm gate); session-start spawns sidecar + emits "FIRST ACTION arm Monitor" reminder; stop hook kills sidecar + orphan tails + grace file; inject-settings-hooks.js registers four explicit per-tool PreToolUse matchers (claws_create/worker/fleet/dispatch_subworker) as belt-and-suspenders.
|
|
1902
|
+
- **test(v0.7.10)**: Two new regression suites — non-blocking-defaults (10 checks: detach !== false default, withMaxHold 8s ceiling) and sidecar-enforcement (18 checks: _ensureSidecarOrThrow guards all 4 spawn handlers, singleton dedup, read-only handlers ungated). Both pass.
|
|
1903
|
+
- **fix(v0.7.10)**: Test fixture sync — lifecycle-server now expects [SESSION-BOOT, PLAN]; reverse-channel calls lifecycle.advance to SPAWN; server-validation expects payload:invalid (not envelope:invalid); worker-fixes-v079 regex updates for detach !== false + findStandaloneMarker. Removes unused Phase import from lifecycle-engine.ts and dead _requireCapability method from server.ts.
|
|
1904
|
+
- **docs(v0.7.10)**: Slash commands + skills aligned with non-blocking defaults — claws-army/fleet/wave-lead/worker.md document fire/poll/audit pattern; claws-orchestration-engine SKILL upgraded to 10-phase ring with mode-fork spawn table; wave-lead/wave-subworker SKILLs add Monitor arm step 0, BUG-03 capabilities:[\'push\'] workaround, BUG-06 worker.<peerId>.heartbeat fix, BUG-10 drain-and-wait LEAD harvest. New /claws-install command. New claws-prompt-templates SKILL library. README tool count synced 14→38; uninstall section rewritten; Windows section directs to WSL2.
|
|
1905
|
+
- **feat(v0.7.10)**: Templates updated — CLAUDE.global.md + CLAUDE.project.md add capabilities:[\'push\'] requirement (BUG-03), worker.<peerId>.heartbeat correction (BUG-06), Sidecar mandatory section, Monitor mandatory section with lifecycle-bound description pattern.
|
|
1906
|
+
- **feat(v0.7.10)**: Scripts — install.sh dev-mode symlink branch (eliminates source↔.claws-bin drift), F-11 .electron-abi cache, dynamic EXPECTED_MIN_VERSION from package.json, .gitignore auto-additions, backup pruning (3 most recent); install.ps1 stub directs Windows to WSL2; update.sh adds Linux Electron ABI detection + BUG-28 health check; uninstall.sh idempotent 5-step removal.
|