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.
Files changed (180) hide show
  1. package/.claude/commands/claws-auto.md +90 -0
  2. package/.claude/commands/claws-bin.md +28 -0
  3. package/.claude/commands/claws-cleanup.md +28 -0
  4. package/.claude/commands/claws-do.md +82 -0
  5. package/.claude/commands/claws-fix.md +40 -0
  6. package/.claude/commands/claws-goal.md +111 -0
  7. package/.claude/commands/claws-help.md +54 -0
  8. package/.claude/commands/claws-plan.md +103 -0
  9. package/.claude/commands/claws-report.md +29 -0
  10. package/.claude/commands/claws-status.md +37 -0
  11. package/.claude/commands/claws-update.md +32 -0
  12. package/.claude/commands/claws.md +64 -0
  13. package/.claude/rules/claws-default-behavior.md +76 -0
  14. package/.claude/settings.json +112 -0
  15. package/.claude/settings.local.json +19 -0
  16. package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
  17. package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
  18. package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
  19. package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
  20. package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
  21. package/CHANGELOG.md +1949 -0
  22. package/LICENSE +21 -0
  23. package/README.md +420 -0
  24. package/bin/cli.js +84 -0
  25. package/cli.js +223 -0
  26. package/docs/ARCHITECTURE.md +511 -0
  27. package/docs/event-protocol.md +588 -0
  28. package/docs/features.md +562 -0
  29. package/docs/guide.md +891 -0
  30. package/docs/index.html +716 -0
  31. package/docs/protocol.md +323 -0
  32. package/extension/.vscodeignore +15 -0
  33. package/extension/CHANGELOG.md +1906 -0
  34. package/extension/LICENSE +21 -0
  35. package/extension/README.md +137 -0
  36. package/extension/docs/features.md +424 -0
  37. package/extension/docs/protocol.md +197 -0
  38. package/extension/esbuild.mjs +25 -0
  39. package/extension/icon.png +0 -0
  40. package/extension/native/.metadata.json +10 -0
  41. package/extension/native/node-pty/LICENSE +69 -0
  42. package/extension/native/node-pty/README.md +165 -0
  43. package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
  44. package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
  45. package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
  46. package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
  47. package/extension/native/node-pty/lib/index.js +52 -0
  48. package/extension/native/node-pty/lib/index.js.map +1 -0
  49. package/extension/native/node-pty/lib/interfaces.js +7 -0
  50. package/extension/native/node-pty/lib/interfaces.js.map +1 -0
  51. package/extension/native/node-pty/lib/shared/conout.js +11 -0
  52. package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
  53. package/extension/native/node-pty/lib/terminal.js +190 -0
  54. package/extension/native/node-pty/lib/terminal.js.map +1 -0
  55. package/extension/native/node-pty/lib/types.js +7 -0
  56. package/extension/native/node-pty/lib/types.js.map +1 -0
  57. package/extension/native/node-pty/lib/unixTerminal.js +346 -0
  58. package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
  59. package/extension/native/node-pty/lib/utils.js +39 -0
  60. package/extension/native/node-pty/lib/utils.js.map +1 -0
  61. package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
  62. package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
  63. package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
  64. package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
  65. package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
  66. package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
  67. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  68. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
  69. package/extension/native/node-pty/package.json +64 -0
  70. package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  71. package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  72. package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  73. package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  74. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  75. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  76. package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  77. package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  78. package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
  79. package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
  80. package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
  81. package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  82. package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  83. package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  84. package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  85. package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
  86. package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
  87. package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
  88. package/extension/package-lock.json +605 -0
  89. package/extension/package.json +343 -0
  90. package/extension/scripts/bundle-native.mjs +104 -0
  91. package/extension/scripts/deploy-dev.mjs +60 -0
  92. package/extension/src/ansi-strip.ts +52 -0
  93. package/extension/src/backends/vscode/claws-pty.ts +483 -0
  94. package/extension/src/backends/vscode/status-bar.ts +99 -0
  95. package/extension/src/backends/vscode/vscode-backend.ts +282 -0
  96. package/extension/src/capture-store.ts +125 -0
  97. package/extension/src/event-log.ts +629 -0
  98. package/extension/src/event-schemas.ts +478 -0
  99. package/extension/src/extension.js +492 -0
  100. package/extension/src/extension.ts +873 -0
  101. package/extension/src/lifecycle-engine.ts +60 -0
  102. package/extension/src/lifecycle-rules.ts +171 -0
  103. package/extension/src/lifecycle-store.ts +506 -0
  104. package/extension/src/peer-registry.ts +176 -0
  105. package/extension/src/pipeline-registry.ts +82 -0
  106. package/extension/src/platform.ts +64 -0
  107. package/extension/src/protocol.ts +532 -0
  108. package/extension/src/server-config.ts +98 -0
  109. package/extension/src/server.ts +2210 -0
  110. package/extension/src/task-registry.ts +51 -0
  111. package/extension/src/terminal-backend.ts +211 -0
  112. package/extension/src/terminal-manager.ts +395 -0
  113. package/extension/src/topic-registry.ts +70 -0
  114. package/extension/src/topic-utils.ts +46 -0
  115. package/extension/src/transport.ts +45 -0
  116. package/extension/src/uninstall-cleanup.ts +232 -0
  117. package/extension/src/wave-registry.ts +314 -0
  118. package/extension/src/websocket-transport.ts +153 -0
  119. package/extension/tsconfig.json +23 -0
  120. package/lib/capabilities.js +145 -0
  121. package/lib/dry-run.js +43 -0
  122. package/lib/install.js +1018 -0
  123. package/lib/mcp-setup.js +92 -0
  124. package/lib/platform.js +240 -0
  125. package/lib/preflight.js +152 -0
  126. package/lib/shell-hook.js +343 -0
  127. package/lib/uninstall.js +162 -0
  128. package/lib/verify.js +166 -0
  129. package/mcp_server.js +3529 -0
  130. package/package.json +48 -0
  131. package/rules/claws-default-behavior.md +72 -0
  132. package/scripts/_helpers/atomic-file.mjs +137 -0
  133. package/scripts/_helpers/fix-repair.js +64 -0
  134. package/scripts/_helpers/json-safe.mjs +218 -0
  135. package/scripts/bump-version.sh +84 -0
  136. package/scripts/codegen/gen-docs.mjs +61 -0
  137. package/scripts/codegen/gen-json-schema.mjs +62 -0
  138. package/scripts/codegen/gen-mcp-tools.mjs +358 -0
  139. package/scripts/codegen/gen-types.mjs +172 -0
  140. package/scripts/codegen/index.mjs +42 -0
  141. package/scripts/dev-hooks/check-extension-dirs.js +77 -0
  142. package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
  143. package/scripts/dev-hooks/check-stale-main.js +55 -0
  144. package/scripts/dev-hooks/check-tag-pushed.js +51 -0
  145. package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
  146. package/scripts/dev-vsix-install.sh +60 -0
  147. package/scripts/fix.sh +702 -0
  148. package/scripts/gen-client-types.mjs +81 -0
  149. package/scripts/git-hooks/pre-commit +31 -0
  150. package/scripts/hooks/lifecycle-state.js +61 -0
  151. package/scripts/hooks/package.json +4 -0
  152. package/scripts/hooks/post-tool-use-claws.js +292 -0
  153. package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
  154. package/scripts/hooks/pre-tool-use-claws.js +206 -0
  155. package/scripts/hooks/session-start-claws.js +97 -0
  156. package/scripts/hooks/stop-claws.js +88 -0
  157. package/scripts/inject-claude-md.js +205 -0
  158. package/scripts/inject-dev-hooks.js +96 -0
  159. package/scripts/inject-global-claude-md.js +140 -0
  160. package/scripts/inject-settings-hooks.js +370 -0
  161. package/scripts/install.ps1 +146 -0
  162. package/scripts/install.sh +1729 -0
  163. package/scripts/monitor-arm-watch.js +155 -0
  164. package/scripts/rebuild-node-pty.sh +245 -0
  165. package/scripts/report.sh +232 -0
  166. package/scripts/shell-hook.fish +164 -0
  167. package/scripts/shell-hook.ps1 +33 -0
  168. package/scripts/shell-hook.sh +232 -0
  169. package/scripts/stream-events.js +399 -0
  170. package/scripts/terminal-wrapper.sh +36 -0
  171. package/scripts/test-enforcement.sh +132 -0
  172. package/scripts/test-install.sh +174 -0
  173. package/scripts/test-installer-parity.sh +135 -0
  174. package/scripts/test-template-enforcement.sh +76 -0
  175. package/scripts/uninstall.sh +143 -0
  176. package/scripts/update.sh +337 -0
  177. package/scripts/verify-release.sh +323 -0
  178. package/scripts/verify-wrapped.sh +194 -0
  179. package/templates/CLAUDE.global.md +135 -0
  180. package/templates/CLAUDE.project.md +37 -0
@@ -0,0 +1,62 @@
1
+ // gen-json-schema.mjs — Generate schemas/json/*.json from Zod schemas.
2
+ // Called by index.mjs. Default export is the generator function.
3
+
4
+ import { writeFileSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { createRequire } from 'module';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+
11
+ // Convert PascalCase schema name to kebab-case filename.
12
+ // WorkerBootV1 → worker-boot-v1, EnvelopeV1 → envelope-v1
13
+ function toKebab(name) {
14
+ return name
15
+ .replace(/([A-Z])/g, (m, c, i) => (i === 0 ? c : '-' + c))
16
+ .toLowerCase();
17
+ }
18
+
19
+ // Predicate: is this export a top-level event schema (not a helper)?
20
+ // Matches names ending in V + digit, excluding ArtifactSchema.
21
+ function isEventSchema(name, value) {
22
+ return (
23
+ /[A-Z].+V\d+$/.test(name) &&
24
+ value !== null &&
25
+ typeof value === 'object' &&
26
+ typeof value.safeParse === 'function'
27
+ );
28
+ }
29
+
30
+ export default async function genJsonSchema(bundlePath, repoRoot, extRoot) {
31
+ const require = createRequire(__filename);
32
+
33
+ // Load zodToJsonSchema from extension's node_modules.
34
+ const extRequire = createRequire(join(extRoot, 'package.json'));
35
+ const { zodToJsonSchema } = extRequire('zod-to-json-schema');
36
+
37
+ // Load the bundled schemas.
38
+ const schemas = require(bundlePath);
39
+
40
+ const outDir = join(repoRoot, 'schemas', 'json');
41
+ let count = 0;
42
+
43
+ for (const [name, schema] of Object.entries(schemas)) {
44
+ if (!isEventSchema(name, schema)) continue;
45
+ const kebab = toKebab(name);
46
+ const jsonSchema = zodToJsonSchema(schema, {
47
+ name: kebab,
48
+ $refStrategy: 'none',
49
+ });
50
+ // Annotate with $schema and title.
51
+ const out = {
52
+ $schema: 'http://json-schema.org/draft-07/schema#',
53
+ title: kebab,
54
+ ...jsonSchema,
55
+ };
56
+ const outPath = join(outDir, `${kebab}.json`);
57
+ writeFileSync(outPath, JSON.stringify(out, null, 2) + '\n', 'utf8');
58
+ count++;
59
+ }
60
+
61
+ console.log(`[codegen/gen-json-schema] wrote ${count} JSON Schema files to schemas/json/`);
62
+ }
@@ -0,0 +1,358 @@
1
+ // gen-mcp-tools.mjs — Generate schemas/mcp-tools.json from Zod input schemas.
2
+ // Called by index.mjs. Default export is the generator function.
3
+ // Descriptions are preserved verbatim from the hand-written mcp_server.js array.
4
+
5
+ import { writeFileSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { createRequire } from 'module';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+
12
+ // ── Tool descriptions (verbatim from mcp_server.js) ──────────────────────────
13
+ const DESC = {
14
+ claws_list:
15
+ "List all open VS Code terminals with their ID, name, PID, shell integration status, active state, and pty log path (null if not wrapped). Use this to discover what's running before sending commands.",
16
+ claws_create:
17
+ "Create a new VS Code terminal. Set wrapped=true to enable full pty logging — this lets you read everything that happens in the terminal including TUI sessions (Claude Code, vim, htop, REPLs). The terminal appears visibly in VS Code's panel.",
18
+ claws_send:
19
+ 'Send text into a terminal. The text arrives at whatever input is active — shell prompt, TUI input field, REPL prompt. Multi-line text is auto-wrapped in bracketed paste mode. Set newline=false to send raw keystrokes without Enter.',
20
+ claws_exec:
21
+ 'Execute a shell command in a terminal and capture the output (stdout + stderr + exit code). Uses file-based capture — works in any terminal type. Waits for the command to finish.',
22
+ claws_read_log:
23
+ "Read a wrapped terminal's pty log with ANSI escapes stripped. Returns clean, readable text of everything that happened — including TUI sessions, build output, AI coding assistant transcripts. Only works for terminals created with wrapped=true.",
24
+ claws_poll:
25
+ 'Stream shell-integration command-completion events across all terminals. Pass since=cursor to get only new events. Note: unreliable in wrapped terminals — use claws_read_log instead.',
26
+ claws_close:
27
+ 'Close and dispose a terminal. Always close terminals you created when the work is done.',
28
+ claws_worker:
29
+ 'Run a complete worker lifecycle in one blocking call: creates a wrapped terminal, optionally launches Claude Code with --dangerously-skip-permissions, sends the mission prompt, polls the capture buffer for a completion marker (default MISSION_COMPLETE) or error markers, harvests the final output, and auto-closes. Returns a structured result. Set detach=true for the legacy fire-and-forget behavior.',
30
+ claws_hello:
31
+ 'Register this Claude session with the Claws server as an orchestrator or worker peer. Must be called before subscribe, publish, or task commands. Returns a peerId for this session.',
32
+ claws_subscribe:
33
+ "Subscribe to a topic pattern on the Claws message bus. Patterns support wildcards: '*' matches one segment, '**' matches many. Examples: 'task.status', 'worker.*', 'task.**'. Returns a subscriptionId.",
34
+ claws_publish:
35
+ 'Publish a payload to a topic on the Claws message bus. All peers subscribed to a matching pattern will receive a push frame.',
36
+ claws_broadcast:
37
+ "Orchestrator-only: send a text message to all workers (or all peers). Optionally inject the text directly into each worker's terminal via bracketed paste. Useful as a kill-switch or coordination signal.",
38
+ claws_ping:
39
+ "Check that the Claws server is reachable. Returns the server's current timestamp. Useful as a heartbeat.",
40
+ claws_peers:
41
+ 'List all currently registered peers on the Claws server (claws/2 connections that have called hello). Returns role, peerName, terminalId, and lastSeen for each peer.',
42
+ claws_lifecycle_plan:
43
+ 'Log the PLAN phase — required before any claws_create call. The server-side lifecycle gate blocks terminal creation until this succeeds. Provide a 1–3 sentence summary of what you are about to do. Idempotent: safe to call twice.',
44
+ claws_lifecycle_advance:
45
+ 'Advance the server-side lifecycle state machine to the next phase. Legal transitions per event-protocol.md §4: PLAN→SPAWN, SPAWN→DEPLOY|RECOVER|FAILED, DEPLOY→OBSERVE|RECOVER|FAILED, OBSERVE→HARVEST|RECOVER|FAILED, RECOVER→DEPLOY|OBSERVE|FAILED, HARVEST→CLEANUP|FAILED, CLEANUP→REFLECT|FAILED. Idempotent: advancing to the current phase is a no-op.',
46
+ claws_lifecycle_snapshot:
47
+ 'Read the current server-side lifecycle state without changing it. Returns null when no PLAN has been logged yet. Use this to check what phase you are in before sending lifecycle commands.',
48
+ claws_lifecycle_reflect:
49
+ 'Terminal lifecycle transition: advance to REFLECT and persist your retrospective text. Call this after CLEANUP when all workers are closed and you have assessed the session. The REFLECT phase is terminal — no further transitions are allowed.',
50
+ claws_wave_create:
51
+ "Register a new wave on the server, initialising heartbeat tracking for each expected sub-worker role. Call this as LEAD immediately after hello. waveId should be a stable human-readable slug (e.g. 'embedder-v1'). The server fires a 25s violation timer per sub-worker that resets on each heartbeat.",
52
+ claws_wave_status:
53
+ 'Fetch a live snapshot of the wave: sub-worker heartbeat timestamps, completion flags, and wave-level complete/summary fields. Use this to monitor progress or diagnose silent sub-workers.',
54
+ claws_wave_complete:
55
+ 'Mark the wave as complete on the server. Clears all sub-worker violation timers. Call this after every sub-worker has published its complete event and the LEAD has committed, built, and run the full test suite. Only the peer that created the wave (LEAD) may call this.',
56
+ claws_deliver_cmd:
57
+ "Deliver a typed command envelope to a specific worker peer over the pub/sub bus. The server validates the payload against the declared schema, allocates a monotonic sequence number, and pushes the command to the worker's auto-subscription. Use idempotencyKey (a UUID) to make retries safe — duplicate keys return {ok:true, duplicate:true} without re-delivering.",
58
+ claws_cmd_ack:
59
+ 'Acknowledge receipt and execution of a delivered command (worker-only). The server fans out a cmd.<workerPeerId>.ack event to all orchestrator subscribers. status must be one of: executed, rejected, duplicate.',
60
+ claws_schema_list:
61
+ 'Return a sorted list of all Zod schema names registered in the Claws schema registry. Use this to discover which schemas are available before calling claws_schema_get.',
62
+ claws_schema_get:
63
+ "Return a simplified JSON representation of one registered Zod schema by name (e.g. 'worker-boot-v1', 'rpc-request-v1'). Use claws_schema_list to discover valid names.",
64
+ claws_rpc_call:
65
+ 'Issue a typed RPC call to a target peer. The server routes the call to rpc.<targetPeerId>.request and waits for the worker to publish a response to rpc.response.<callerPeerId>.<requestId>. Returns the result or a timeout error.',
66
+ claws_task_assign:
67
+ "Orchestrator-only: assign a task to a worker peer. The worker receives a task.assigned.<peerId> push event. Use deliver='inject' to also write the prompt directly into the worker's terminal.",
68
+ claws_task_update:
69
+ 'Worker-only: update the status or progress of an assigned task. Emits a task.status push event so orchestrators can track progress.',
70
+ claws_task_complete:
71
+ 'Worker-only: mark a task as succeeded, failed, or skipped. Idempotent — calling again on an already-completed task is safe. Emits a task.completed push event.',
72
+ claws_task_cancel:
73
+ 'Orchestrator-only: request cancellation of an active task. Emits task.cancel_requested.<assignee> so the worker can react. Does not forcibly terminate the worker.',
74
+ claws_task_list:
75
+ 'List tasks in the server registry. Optionally filter by assignee peerId, status, or last-updated timestamp. Available to all peers.',
76
+ claws_drain_events:
77
+ 'Drain buffered push-frame events from the persistent socket. On first call auto-subscribes to all topics (**). Returns events received since since_index with a dropped count for aged-out events. Set wait_ms > 0 to block until at least one new event arrives or the timeout fires.',
78
+ claws_pipeline_create:
79
+ 'Create a named pipeline with an ordered list of step definitions on the Claws server. Each step can be a string (shell command) or a structured object. Returns a pipelineId.',
80
+ claws_pipeline_list:
81
+ 'List all pipelines currently registered on the Claws server.',
82
+ claws_pipeline_close:
83
+ 'Close and remove a pipeline from the Claws server by pipelineId.',
84
+ claws_done:
85
+ 'Signal that this worker is complete. Reads CLAWS_TERMINAL_ID from the environment, publishes system.worker.completed to the Claws bus, and closes the terminal. Zero arguments — call this as the final action when your mission is finished.',
86
+ claws_dispatch_subworker:
87
+ 'Spawn a wrapped terminal for a wave sub-worker, launch Claude Code with --dangerously-skip-permissions, wait for the trust prompt, confirm bypass, and send the mission prompt. Returns terminalId and bootOk status. Use inside a wave after claws_wave_create.',
88
+ claws_fleet:
89
+ 'Spawn a fleet of workers in parallel (single tool call). Internally fans out via Promise.allSettled so all workers boot and run concurrently. Each entry in workers mirrors claws_worker args; shared top-level fields (cwd, model, timeout_ms, etc.) act as defaults overridden per-worker. Set detach=true for non-blocking spawn (pair with claws_workers_wait). Returns a fleet summary with wall-clock time, per-worker status, and marker lines.',
90
+ claws_workers_wait:
91
+ 'Poll a set of already-spawned terminal ids (from claws_fleet detach=true or claws_create) for completion. Checks all 4 signals: marker, error_marker, pub_complete ([CLAWS_PUB] topic=worker.<id>.complete), and Wave D terminated (system.worker.completed bus event). Supports min_complete to return when N of M workers finish rather than waiting for all. Returns per-worker results with status, signal, and duration.',
92
+ claws_set_bin: 'Set the worker binary for spawns. Writes <project>/.claws/claude-bin. Pass {name: "<binary>"} to set, or {} to clear (revert to default "claude").',
93
+ claws_get_bin: 'Returns the currently-resolved worker binary and where it came from (file / env:CLAWS_CLAUDE_BIN / default).',
94
+ claws_reload_window: 'Trigger a VS Code window reload from MCP. Sends workbench.action.reloadWindow via the extension. The response may not arrive — the reload kills the extension host, which is expected. Use after extension changes to activate the new code without switching to VS Code.',
95
+ claws_reload_mcp: 'Restart the MCP server process. Returns ok:true, then exits cleanly so the MCP supervisor auto-respawns. Use after mcp_server.js changes to pick up the new code without a manual reconnect.',
96
+ };
97
+
98
+ export default async function genMcpTools(_bundlePath, repoRoot, extRoot) {
99
+ const require = createRequire(__filename);
100
+ const extRequire = createRequire(join(extRoot, 'package.json'));
101
+ const { zodToJsonSchema } = extRequire('zod-to-json-schema');
102
+ const { z } = extRequire('zod');
103
+
104
+ // ── Build tool definitions ─────────────────────────────────────────────────
105
+
106
+ function tool(name, schema) {
107
+ const inputSchema = zodToJsonSchema(schema, { $refStrategy: 'none' });
108
+ // Remove the $schema field zodToJsonSchema adds at the top level
109
+ delete inputSchema.$schema;
110
+ return { name, description: DESC[name], inputSchema };
111
+ }
112
+
113
+ const TOOLS = [
114
+ tool('claws_list', z.object({})),
115
+
116
+ tool('claws_create', z.object({
117
+ name: z.string().describe('Terminal display name'),
118
+ cwd: z.string().describe('Working directory (absolute path)').optional(),
119
+ wrapped: z.boolean().describe('Enable script(1) pty logging for full read-back. Defaults to true — all worker terminals should be wrapped for observability. Set false only for interactive UI terminals where logging is undesired.').optional(),
120
+ })),
121
+
122
+ tool('claws_send', z.object({
123
+ id: z.string().describe('Terminal ID from claws_list or claws_create'),
124
+ text: z.string().describe('Text to send'),
125
+ newline: z.boolean().describe('Append Enter after text (default true)').optional(),
126
+ })),
127
+
128
+ tool('claws_exec', z.object({
129
+ id: z.string().describe('Terminal ID'),
130
+ command: z.string().describe('Shell command to execute'),
131
+ timeout_ms: z.number().int().describe('Max wait time in ms (default 180000)').optional(),
132
+ })),
133
+
134
+ tool('claws_read_log', z.object({
135
+ id: z.string().describe('Terminal ID (must be wrapped)'),
136
+ lines: z.number().int().describe('Number of lines to return from the tail (default 50)').optional(),
137
+ })),
138
+
139
+ tool('claws_poll', z.object({
140
+ since: z.number().int().describe('Sequence cursor — return only events after this (default 0)').optional(),
141
+ })),
142
+
143
+ tool('claws_close', z.object({
144
+ id: z.string().describe('Terminal ID to close'),
145
+ })),
146
+
147
+ tool('claws_worker', z.object({
148
+ name: z.string().describe('Worker name (terminal tab)'),
149
+ mission: z.string().describe('Mission prompt sent to Claude Code. Include your completion marker (default MISSION_COMPLETE) so the blocker knows when to stop.').optional(),
150
+ command: z.string().describe('Alternative to mission: raw shell command sent to a wrapped terminal. Implies launch_claude=false.').optional(),
151
+ cwd: z.string().describe('Working directory for the worker terminal. Defaults to the MCP server cwd (project root) so the worker lands in a trusted folder with the project MCP socket reachable.').optional(),
152
+ model: z.string().describe('Claude Code model flag value. Defaults to "claude-sonnet-4-6" — Sonnet is mandatory for workers per project policy.').optional(),
153
+ launch_claude: z.boolean().describe('Launch claude --dangerously-skip-permissions before sending mission (default: true if mission present, false if command present)').optional(),
154
+ detach: z.boolean().describe('Return immediately after spawning. Default depends on mode: true for mission, false for command. Pass explicitly to override.').optional(),
155
+ timeout_ms: z.number().int().describe('Max wait for completion in ms (default 300000 = 5 min).').optional(),
156
+ boot_wait_ms: z.number().int().describe('Max wait for Claude Code boot before sending mission (default 8000).').optional(),
157
+ boot_marker: z.string().describe('Substring that indicates Claude booted (default "Claude Code").').optional(),
158
+ complete_marker: z.string().describe('Substring that signals success (default "MISSION_COMPLETE").').optional(),
159
+ error_markers: z.array(z.string()).describe('Substrings that signal failure (default ["MISSION_FAILED"]).').optional(),
160
+ poll_interval_ms: z.number().int().describe('How often to check the capture buffer (default 1500).').optional(),
161
+ harvest_lines: z.number().int().describe('Tail N lines of output to return on completion (default 200).').optional(),
162
+ close_on_complete: z.boolean().describe('Auto-close the terminal after completion (default true).').optional(),
163
+ })),
164
+
165
+ tool('claws_fleet', z.object({
166
+ workers: z.array(z.object({
167
+ name: z.string(),
168
+ mission: z.string().optional(),
169
+ command: z.string().optional(),
170
+ cwd: z.string().optional(),
171
+ model: z.string().optional(),
172
+ complete_marker: z.string().optional(),
173
+ error_markers: z.array(z.string()).optional(),
174
+ timeout_ms: z.number().int().optional(),
175
+ boot_wait_ms: z.number().int().optional(),
176
+ launch_claude: z.boolean().optional(),
177
+ })).describe('Worker configs to spawn in parallel (single tool call internally fans out via Promise.all).'),
178
+ cwd: z.string().describe('Shared default cwd.').optional(),
179
+ model: z.string().describe('Shared default model.').optional(),
180
+ timeout_ms: z.number().int().describe('Shared default per-worker timeout.').optional(),
181
+ boot_wait_ms: z.number().int().describe('Shared default boot wait.').optional(),
182
+ poll_interval_ms: z.number().int().describe('Shared default poll interval.').optional(),
183
+ harvest_lines: z.number().int().describe('Shared default harvest lines.').optional(),
184
+ close_on_complete: z.boolean().describe('Shared default auto-close.').optional(),
185
+ detach: z.boolean().describe('If true, return immediately after each worker is spawned (no marker poll). Companion to claws_workers_wait.').optional(),
186
+ })),
187
+
188
+ tool('claws_workers_wait', z.object({
189
+ terminal_ids: z.array(z.union([z.string(), z.number()])).describe('Terminal ids to poll (from claws_fleet detach=true or claws_create).'),
190
+ complete_marker: z.string().describe("Substring that signals success (default 'MISSION_COMPLETE').").optional(),
191
+ error_markers: z.array(z.string()).describe("Substrings that signal failure (default ['MISSION_FAILED']).").optional(),
192
+ timeout_ms: z.number().int().describe('Max wait in ms (default 300000).').optional(),
193
+ poll_interval_ms: z.number().int().describe('Poll cadence (default 1500).').optional(),
194
+ min_complete: z.number().int().describe('Return once this many workers complete (default = all workers). Workers still pending are reported in the pending array.').optional(),
195
+ })),
196
+
197
+ tool('claws_hello', z.object({
198
+ role: z.enum(['orchestrator', 'worker', 'observer']).describe('Peer role. Orchestrator may assign/cancel/broadcast; worker may publish status and claim tasks; observer is read-only.'),
199
+ peerName: z.string().describe("Human label for this peer (e.g. 'sdlc-lead', 'test-worker-1')."),
200
+ terminalId: z.string().describe('Optional: associate this peer with a specific terminal id so the server can correlate logs and do inject fan-out.').optional(),
201
+ capabilities: z.array(z.string()).describe('Optional list of capability strings the peer advertises (server intersects with its own).').optional(),
202
+ waveId: z.string().describe('Wave id this peer belongs to (wave army protocol). Required when registering as a wave LEAD with role=orchestrator so the server scopes the singleton guard to root peers only.').optional(),
203
+ subWorkerRole: z.string().describe("Sub-worker role within the wave (e.g. 'lead', 'tester', 'reviewer'). Used with waveId for wave army heartbeat tracking.").optional(),
204
+ })),
205
+
206
+ tool('claws_subscribe', z.object({
207
+ topic: z.string().describe('Topic pattern to subscribe to (dot-namespaced, supports * and ** wildcards).'),
208
+ })),
209
+
210
+ tool('claws_publish', z.object({
211
+ topic: z.string().describe('Topic to publish on.'),
212
+ payload: z.record(z.unknown()).describe('The message payload (arbitrary JSON object).'),
213
+ echo: z.boolean().describe('If true, sender also receives the message (default false).').optional(),
214
+ })),
215
+
216
+ tool('claws_broadcast', z.object({
217
+ text: z.string().describe('The text payload to broadcast.'),
218
+ targetRole: z.enum(['worker', 'orchestrator', 'observer', 'all']).describe("Which role(s) to target (default 'worker').").optional(),
219
+ inject: z.boolean().describe("If true, text is also sent into each peer's associated terminal via bracketed paste (default false).").optional(),
220
+ })),
221
+
222
+ tool('claws_ping', z.object({})),
223
+
224
+ tool('claws_peers', z.object({})),
225
+
226
+ tool('claws_lifecycle_plan', z.object({
227
+ plan: z.string().describe('1–3 sentence mission summary. What you are doing, why, and what success looks like.'),
228
+ })),
229
+
230
+ tool('claws_lifecycle_advance', z.object({
231
+ to: z.enum(['SPAWN', 'DEPLOY', 'OBSERVE', 'RECOVER', 'HARVEST', 'CLEANUP', 'REFLECT', 'FAILED']).describe('Target phase.'),
232
+ reason: z.string().describe('Optional human-readable transition reason (logged in state).').optional(),
233
+ })),
234
+
235
+ tool('claws_lifecycle_snapshot', z.object({})),
236
+
237
+ tool('claws_lifecycle_reflect', z.object({
238
+ reflect: z.string().describe('Retrospective text: what succeeded, what failed, what to improve next time.'),
239
+ })),
240
+
241
+ tool('claws_wave_create', z.object({
242
+ waveId: z.string().describe("Stable human-readable wave identifier (e.g. 'embedder-v1', 'bus-hardening-r2')."),
243
+ layers: z.array(z.string()).describe("Human-readable layer or goal labels this wave covers (e.g. ['L1-schemas', 'L2-handlers']).").optional(),
244
+ manifest: z.array(z.enum(['lead', 'tester', 'reviewer', 'auditor', 'bench', 'doc'])).describe('Expected sub-worker roles. One violation timer is started per role.'),
245
+ })),
246
+
247
+ tool('claws_wave_status', z.object({
248
+ waveId: z.string().describe('Wave identifier to inspect.'),
249
+ })),
250
+
251
+ tool('claws_wave_complete', z.object({
252
+ waveId: z.string().describe('Wave identifier to complete.'),
253
+ summary: z.string().describe('One-paragraph retrospective: what shipped, test result, any regressions.'),
254
+ commits: z.array(z.string()).describe('Git commit SHAs produced during this wave.').optional(),
255
+ regressionClean: z.boolean().describe('True if the full test suite passed with no regressions after the wave\'s changes.').optional(),
256
+ })),
257
+
258
+ tool('claws_deliver_cmd', z.object({
259
+ targetPeerId: z.string().describe('peerId of the worker to receive the command.'),
260
+ cmdTopic: z.string().describe('Full topic the server will push on (e.g. cmd.p_000002.abort).'),
261
+ payload: z.record(z.unknown()).describe('EnvelopeV1 payload: {v:1, id:uuid, schema:string, from_peer, from_name, ts_published, data}.'),
262
+ idempotencyKey: z.string().uuid().describe('Client-generated UUID. Duplicate keys return {ok:true, duplicate:true} without re-delivering.'),
263
+ })),
264
+
265
+ tool('claws_cmd_ack', z.object({
266
+ seq: z.number().int().nonnegative().describe('Sequence number from the deliver-cmd response.'),
267
+ status: z.enum(['executed', 'rejected', 'duplicate']).describe('Execution outcome reported by the worker.'),
268
+ correlation_id: z.string().uuid().describe('Optional UUID carried through for orchestrator correlation.').optional(),
269
+ })),
270
+
271
+ tool('claws_schema_list', z.object({})),
272
+
273
+ tool('claws_schema_get', z.object({
274
+ name: z.string().describe("Schema name as returned by claws_schema_list (e.g. 'worker-boot-v1')."),
275
+ })),
276
+
277
+ tool('claws_rpc_call', z.object({
278
+ targetPeerId: z.string().describe('peerId of the peer to call.'),
279
+ method: z.string().describe("RPC method name (e.g. 'introspect', 'status')."),
280
+ params: z.record(z.unknown()).describe('Optional method parameters.').optional(),
281
+ timeoutMs: z.number().int().min(100).max(30000).describe('Milliseconds before the call times out. Default: 5000.').optional(),
282
+ })),
283
+
284
+ tool('claws_task_assign', z.object({
285
+ title: z.string().describe('Short human-readable task title.'),
286
+ assignee: z.string().describe('peerId of the worker peer to assign the task to.'),
287
+ prompt: z.string().describe('Full task instructions delivered to the worker.'),
288
+ timeoutMs: z.number().int().describe('Optional deadline in milliseconds from now.').optional(),
289
+ deliver: z.enum(['publish', 'inject', 'both']).describe("How to deliver the prompt: publish (bus only), inject (terminal only), both (default: publish).").optional(),
290
+ })),
291
+
292
+ tool('claws_task_update', z.object({
293
+ taskId: z.string().describe("Task ID as returned by claws_task_assign (e.g. 't_000001')."),
294
+ status: z.enum(['pending', 'in_progress', 'blocked']).describe('New task status.'),
295
+ progressPct: z.number().min(0).max(100).describe('Optional progress percentage (0–100).').optional(),
296
+ note: z.string().describe('Optional human-readable progress note.').optional(),
297
+ })),
298
+
299
+ tool('claws_task_complete', z.object({
300
+ taskId: z.string().describe('Task ID as returned by claws_task_assign.'),
301
+ status: z.enum(['succeeded', 'failed', 'skipped']).describe('Final task outcome.'),
302
+ result: z.string().describe('Optional human-readable result summary.').optional(),
303
+ artifacts: z.array(z.string()).describe('Optional list of output artifact paths or identifiers.').optional(),
304
+ })),
305
+
306
+ tool('claws_task_cancel', z.object({
307
+ taskId: z.string().describe('Task ID to cancel.'),
308
+ reason: z.string().describe('Optional human-readable cancellation reason.').optional(),
309
+ })),
310
+
311
+ tool('claws_task_list', z.object({
312
+ assignee: z.string().describe('Filter by assignee peerId.').optional(),
313
+ status: z.enum(['pending', 'in_progress', 'blocked', 'succeeded', 'failed', 'skipped']).describe('Filter by task status.').optional(),
314
+ since: z.number().int().describe('Return only tasks updated at or after this epoch-ms timestamp.').optional(),
315
+ })),
316
+
317
+ // D-1: tools present in mcp_server.js handlers but previously missing from schema
318
+ tool('claws_drain_events', z.object({
319
+ since_index: z.number().int().describe('Return only events with absoluteIndex greater than this value. Default 0 (return all buffered events).').optional(),
320
+ wait_ms: z.number().int().describe('Block up to this many milliseconds for at least one new event. Default 0 (return immediately).').optional(),
321
+ max: z.number().int().describe('Maximum number of events to return. Default 100.').optional(),
322
+ })),
323
+
324
+ tool('claws_pipeline_create', z.object({
325
+ name: z.string().describe('Human-readable pipeline name.').optional(),
326
+ steps: z.union([z.array(z.unknown()), z.string()]).describe('Ordered pipeline steps. Each step may be a shell-command string or a structured step object. Pass a JSON string if the client cannot send a raw array.'),
327
+ })),
328
+
329
+ tool('claws_pipeline_list', z.object({})),
330
+
331
+ tool('claws_pipeline_close', z.object({
332
+ pipelineId: z.string().describe('Pipeline ID as returned by claws_pipeline_create.'),
333
+ })),
334
+
335
+ tool('claws_done', z.object({})),
336
+
337
+ tool('claws_dispatch_subworker', z.object({
338
+ waveId: z.string().describe('Wave identifier (from claws_wave_create) this sub-worker belongs to.'),
339
+ role: z.string().describe('Sub-worker role label (e.g. "tester", "reviewer"). Used to name the terminal and register the heartbeat slot.'),
340
+ mission: z.string().describe('Mission prompt sent to Claude Code after boot. Include your completion marker.'),
341
+ cwd: z.string().describe('Working directory for the spawned terminal (absolute path).').optional(),
342
+ })),
343
+
344
+ tool('claws_set_bin', z.object({
345
+ name: z.string().describe('Binary name to use (e.g. "claude-neu", "claude-anish"). Omit or pass empty string to clear.').optional(),
346
+ })),
347
+
348
+ tool('claws_get_bin', z.object({})),
349
+
350
+ tool('claws_reload_window', z.object({})),
351
+
352
+ tool('claws_reload_mcp', z.object({})),
353
+ ];
354
+
355
+ const outPath = join(repoRoot, 'schemas', 'mcp-tools.json');
356
+ writeFileSync(outPath, JSON.stringify(TOOLS, null, 2) + '\n', 'utf8');
357
+ console.log(`[codegen/gen-mcp-tools] wrote ${TOOLS.length} tool descriptors to schemas/mcp-tools.json`);
358
+ }
@@ -0,0 +1,172 @@
1
+ // gen-types.mjs — Generate schemas/types/event-protocol.d.ts.
2
+ // Called by index.mjs. Default export is the generator function.
3
+ // Produces ambient TypeScript declarations for external consumers.
4
+
5
+ import { writeFileSync } from 'fs';
6
+ import { join } from 'path';
7
+
8
+ // The type definitions below are templated from the Zod schemas in
9
+ // extension/src/event-schemas.ts. Keep in sync when schemas change.
10
+ const DTS_CONTENT = `\
11
+ // @generated — do not edit. Run: npm run schemas (from extension/)
12
+ // Source: extension/src/event-schemas.ts
13
+
14
+ export type Phase =
15
+ | 'PLAN' | 'SPAWN' | 'DEPLOY' | 'OBSERVE' | 'RECOVER'
16
+ | 'HARVEST' | 'CLEANUP' | 'REFLECT' | 'FAILED';
17
+
18
+ export type EventKind =
19
+ | 'BLOCKED' | 'REQUEST' | 'HARVEST' | 'ERROR'
20
+ | 'DECISION' | 'PROGRESS' | 'LOG';
21
+
22
+ export type ClawsRole = 'orchestrator' | 'worker' | 'observer';
23
+ export type ResultKind = 'ok' | 'failed' | 'cancelled';
24
+ export type SeverityLevel = 'info' | 'warn' | 'error' | 'fatal';
25
+
26
+ export interface Envelope {
27
+ v: 1;
28
+ id: string;
29
+ correlation_id?: string | null;
30
+ parent_id?: string | null;
31
+ from_peer: string;
32
+ from_name: string;
33
+ terminal_id?: string | null;
34
+ ts_published: string;
35
+ ts_server?: string;
36
+ sequence?: number;
37
+ schema: string;
38
+ data: unknown;
39
+ }
40
+
41
+ export interface Artifact {
42
+ path: string;
43
+ type: string;
44
+ size_bytes?: number;
45
+ }
46
+
47
+ // ── Worker schemas ────────────────────────────────────────────────────────────
48
+
49
+ export interface WorkerBoot {
50
+ model: string;
51
+ role: ClawsRole;
52
+ parent_peer_id: string | null;
53
+ mission_summary: string;
54
+ capabilities: string[];
55
+ cwd: string;
56
+ terminal_id: string;
57
+ }
58
+
59
+ export interface WorkerPhase {
60
+ phase: Phase;
61
+ prev: Phase | null;
62
+ transition_reason: string;
63
+ phases_completed: Phase[];
64
+ metadata?: Record<string, unknown>;
65
+ }
66
+
67
+ export interface WorkerEvent {
68
+ kind: EventKind;
69
+ severity: SeverityLevel;
70
+ message: string;
71
+ request_id?: string;
72
+ data?: Record<string, unknown>;
73
+ }
74
+
75
+ export interface WorkerHeartbeat {
76
+ current_phase: Phase;
77
+ time_in_phase_ms: number;
78
+ tokens_used: number;
79
+ cost_usd: number;
80
+ last_event_id: string | null;
81
+ active_sub_workers: string[];
82
+ }
83
+
84
+ export interface WorkerComplete {
85
+ result: ResultKind;
86
+ summary: string;
87
+ artifacts: Artifact[];
88
+ phases_completed: Phase[];
89
+ total_tokens: number;
90
+ total_cost_usd: number;
91
+ duration_ms: number;
92
+ }
93
+
94
+ // ── Command schemas ───────────────────────────────────────────────────────────
95
+
96
+ export interface CmdApprove {
97
+ correlation_id: string;
98
+ payload?: Record<string, unknown>;
99
+ }
100
+
101
+ export interface CmdReject {
102
+ correlation_id: string;
103
+ reason: string;
104
+ }
105
+
106
+ export interface CmdAbort {
107
+ reason: string;
108
+ }
109
+
110
+ export interface CmdPause {}
111
+ export interface CmdResume {}
112
+
113
+ export interface CmdSetPhase {
114
+ phase: Phase;
115
+ reason: string;
116
+ }
117
+
118
+ export interface CmdSpawn {
119
+ name: string;
120
+ mission: string;
121
+ model?: string;
122
+ }
123
+
124
+ export interface CmdInjectText {
125
+ text: string;
126
+ paste?: boolean;
127
+ }
128
+
129
+ // ── System schemas ────────────────────────────────────────────────────────────
130
+
131
+ export interface SystemPeerJoined {
132
+ peerId: string;
133
+ role: ClawsRole;
134
+ peerName: string;
135
+ ts: string;
136
+ }
137
+
138
+ export interface SystemPeerLeft {
139
+ peerId: string;
140
+ role: ClawsRole;
141
+ reason: 'clean' | 'crash' | 'timeout';
142
+ }
143
+
144
+ export interface SystemPeerStale {
145
+ peerId: string;
146
+ last_seen: number;
147
+ missed_heartbeats: number;
148
+ }
149
+
150
+ export interface SystemGateFired {
151
+ tool: string;
152
+ reason: string;
153
+ peerId: string;
154
+ }
155
+
156
+ export interface SystemBudgetWarning {
157
+ current_usd: number;
158
+ threshold_usd: number;
159
+ }
160
+
161
+ export interface SystemMalformedReceived {
162
+ from: string;
163
+ topic: string;
164
+ error: unknown;
165
+ }
166
+ `;
167
+
168
+ export default async function genTypes(_bundlePath, repoRoot) {
169
+ const outPath = join(repoRoot, 'schemas', 'types', 'event-protocol.d.ts');
170
+ writeFileSync(outPath, DTS_CONTENT, 'utf8');
171
+ console.log('[codegen/gen-types] wrote schemas/types/event-protocol.d.ts');
172
+ }
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ // Codegen pipeline orchestrator.
3
+ // Run via: npm run schemas (from extension/)
4
+ // Usage: node ../scripts/codegen/index.mjs
5
+ //
6
+ // Bundles event-schemas.ts → CJS, then calls each generator in sequence.
7
+ // Outputs land in schemas/ at the repo root (committed to git).
8
+
9
+ import { execSync } from 'child_process';
10
+ import { join, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { mkdirSync } from 'fs';
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const repoRoot = join(__dirname, '../..');
16
+ const extRoot = join(repoRoot, 'extension');
17
+ const bundlePath = join(extRoot, 'dist', 'event-schemas.bundle.cjs');
18
+
19
+ // Ensure output dirs exist
20
+ mkdirSync(join(repoRoot, 'schemas', 'json'), { recursive: true });
21
+ mkdirSync(join(repoRoot, 'schemas', 'types'), { recursive: true });
22
+
23
+ // 1. Bundle event-schemas.ts so generators can require() it (zod included).
24
+ const esbuildBin = join(extRoot, 'node_modules', '.bin', 'esbuild');
25
+ const srcPath = join(extRoot, 'src', 'event-schemas.ts');
26
+ execSync(
27
+ `"${esbuildBin}" "${srcPath}" --bundle --format=cjs --platform=node --outfile="${bundlePath}"`,
28
+ { stdio: 'pipe' },
29
+ );
30
+
31
+ // 2. Run generators in sequence.
32
+ const { default: genJsonSchema } = await import('./gen-json-schema.mjs');
33
+ const { default: genTypes } = await import('./gen-types.mjs');
34
+ const { default: genDocs } = await import('./gen-docs.mjs');
35
+ const { default: genMcpTools } = await import('./gen-mcp-tools.mjs');
36
+
37
+ await genJsonSchema(bundlePath, repoRoot, extRoot);
38
+ await genTypes(bundlePath, repoRoot);
39
+ await genDocs(repoRoot);
40
+ await genMcpTools(bundlePath, repoRoot, extRoot);
41
+
42
+ console.log('[codegen] schemas generated successfully');