cool-workflow 0.1.79 → 0.1.81

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 (131) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +51 -3
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +64 -0
  6. package/apps/architecture-review-fast/workflow.js +153 -0
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/agent-config.js +21 -7
  12. package/dist/candidate-scoring.js +42 -22
  13. package/dist/capability-core.js +132 -17
  14. package/dist/capability-registry.js +138 -168
  15. package/dist/cli.js +97 -98
  16. package/dist/collaboration.js +5 -6
  17. package/dist/commit.js +20 -6
  18. package/dist/compare.js +18 -0
  19. package/dist/coordinator/classify.js +45 -0
  20. package/dist/coordinator/paths.js +42 -0
  21. package/dist/coordinator/util.js +129 -0
  22. package/dist/coordinator.js +127 -300
  23. package/dist/dispatch.js +35 -0
  24. package/dist/drive.js +79 -6
  25. package/dist/error-feedback.js +8 -4
  26. package/dist/evidence-reasoning.js +3 -3
  27. package/dist/execution-backend/agent.js +331 -0
  28. package/dist/execution-backend/probes.js +96 -0
  29. package/dist/execution-backend/util.js +47 -0
  30. package/dist/execution-backend.js +73 -421
  31. package/dist/mcp-server.js +79 -183
  32. package/dist/multi-agent/graph.js +84 -0
  33. package/dist/multi-agent/helpers.js +145 -0
  34. package/dist/multi-agent/paths.js +22 -0
  35. package/dist/multi-agent-eval/format.js +194 -0
  36. package/dist/multi-agent-eval/normalize.js +51 -0
  37. package/dist/multi-agent-eval.js +39 -244
  38. package/dist/multi-agent-host.js +0 -19
  39. package/dist/multi-agent.js +125 -314
  40. package/dist/node-snapshot.js +3 -3
  41. package/dist/observability/format.js +61 -0
  42. package/dist/observability/intake.js +98 -0
  43. package/dist/observability.js +14 -160
  44. package/dist/operator-ux/format.js +364 -0
  45. package/dist/operator-ux.js +22 -363
  46. package/dist/orchestrator/lifecycle-operations.js +2 -1
  47. package/dist/orchestrator/report.js +8 -0
  48. package/dist/orchestrator.js +26 -9
  49. package/dist/reclamation.js +26 -21
  50. package/dist/run-export.js +494 -25
  51. package/dist/run-registry/derive.js +172 -0
  52. package/dist/run-registry/format.js +124 -0
  53. package/dist/run-registry/gc.js +251 -0
  54. package/dist/run-registry/policy.js +16 -0
  55. package/dist/run-registry/queue.js +116 -0
  56. package/dist/run-registry.js +89 -597
  57. package/dist/run-state-schema.js +1 -0
  58. package/dist/sandbox-profile.js +43 -2
  59. package/dist/state-explosion/format.js +159 -0
  60. package/dist/state-explosion/helpers.js +82 -0
  61. package/dist/state-explosion.js +165 -304
  62. package/dist/state-node.js +19 -4
  63. package/dist/telemetry-attestation.js +55 -0
  64. package/dist/telemetry-demo.js +15 -3
  65. package/dist/telemetry-ledger.js +60 -15
  66. package/dist/topology.js +25 -8
  67. package/dist/triggers.js +33 -14
  68. package/dist/trust-audit.js +145 -33
  69. package/dist/version.js +1 -1
  70. package/dist/worker-isolation/helpers.js +51 -0
  71. package/dist/worker-isolation/paths.js +46 -0
  72. package/dist/worker-isolation.js +39 -115
  73. package/docs/agent-delegation-drive.7.md +71 -0
  74. package/docs/canonical-workflow-apps.7.md +37 -0
  75. package/docs/cli-mcp-parity.7.md +16 -0
  76. package/docs/contract-migration-tooling.7.md +6 -0
  77. package/docs/control-plane-scheduling.7.md +6 -0
  78. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  79. package/docs/durable-state-and-locking.7.md +8 -0
  80. package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
  81. package/docs/execution-backends.7.md +6 -0
  82. package/docs/index.md +2 -0
  83. package/docs/launch/demo.tape +28 -0
  84. package/docs/launch/launch-kit.md +96 -17
  85. package/docs/launch/pre-launch-checklist.md +53 -0
  86. package/docs/multi-agent-cli-mcp-surface.7.md +8 -0
  87. package/docs/multi-agent-eval-replay-harness.7.md +6 -0
  88. package/docs/multi-agent-operator-ux.7.md +6 -0
  89. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  90. package/docs/node-snapshot-diff-replay.7.md +6 -0
  91. package/docs/observability-cost-accounting.7.md +6 -0
  92. package/docs/project-index.md +27 -6
  93. package/docs/real-execution-backends.7.md +6 -0
  94. package/docs/release-and-migration.7.md +8 -0
  95. package/docs/release-tooling.7.md +6 -0
  96. package/docs/routines.md +23 -0
  97. package/docs/run-registry-control-plane.7.md +89 -2
  98. package/docs/run-retention-reclamation.7.md +8 -0
  99. package/docs/source-context-profiles.7.md +119 -0
  100. package/docs/state-explosion-management.7.md +13 -0
  101. package/docs/team-collaboration.7.md +6 -0
  102. package/docs/trust-model.md +267 -0
  103. package/docs/unix-principles.md +49 -1
  104. package/docs/vendor-manifest-loadability.7.md +43 -0
  105. package/docs/web-desktop-workbench.7.md +6 -0
  106. package/manifest/plugin.manifest.json +1 -1
  107. package/manifest/source-context-profiles.json +142 -0
  108. package/package.json +4 -1
  109. package/scripts/agents/builtin-templates.json +7 -0
  110. package/scripts/agents/claude-p-agent.js +129 -43
  111. package/scripts/architecture-review-fast.js +362 -0
  112. package/scripts/bump-version.js +5 -10
  113. package/scripts/canonical-apps-list.js +64 -0
  114. package/scripts/canonical-apps.js +36 -4
  115. package/scripts/coverage-gate.js +211 -0
  116. package/scripts/dogfood-release.js +1 -1
  117. package/scripts/golden-path.js +4 -4
  118. package/scripts/parity-check.js +5 -0
  119. package/scripts/release-check.js +5 -1
  120. package/scripts/source-context.js +291 -0
  121. package/scripts/version-sync-check.js +5 -7
  122. package/skills/ci-triage/SKILL.md +50 -0
  123. package/skills/ci-triage/agents/openai.yaml +4 -0
  124. package/skills/cool-workflow/SKILL.md +4 -1
  125. package/skills/deploy-check/SKILL.md +55 -0
  126. package/skills/deploy-check/agents/openai.yaml +4 -0
  127. package/skills/design-qa/SKILL.md +49 -0
  128. package/skills/design-qa/agents/openai.yaml +4 -0
  129. package/skills/pr-review/SKILL.md +45 -0
  130. package/skills/pr-review/agents/openai.yaml +4 -0
  131. package/dist/capability-dispatcher.js +0 -86
@@ -0,0 +1,142 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "profiles": {
4
+ "core": {
5
+ "description": "Default AI source context: runtime source, apps, package metadata, and agent wrappers; generated artifacts, tests, docs, release records, and long logs are manifest-only.",
6
+ "maxLines": 50000,
7
+ "include": [
8
+ "plugins/cool-workflow/src/**",
9
+ "plugins/cool-workflow/apps/**",
10
+ "plugins/cool-workflow/package.json",
11
+ "plugins/cool-workflow/tsconfig.json",
12
+ "plugins/cool-workflow/scripts/cw.js",
13
+ "plugins/cool-workflow/scripts/mcp-server.js",
14
+ "plugins/cool-workflow/scripts/agents/**"
15
+ ],
16
+ "exclude": [
17
+ "plugins/cool-workflow/dist/**",
18
+ "plugins/cool-workflow/test/**",
19
+ "plugins/cool-workflow/docs/**",
20
+ "docs/assets/**",
21
+ ".cw-release/**",
22
+ "CHANGELOG.md",
23
+ "ITERATION_LOG.md"
24
+ ]
25
+ },
26
+ "runtime": {
27
+ "description": "Runtime-kernel source context for state, orchestration, scheduling, execution, and shared types.",
28
+ "maxLines": 40000,
29
+ "include": [
30
+ "plugins/cool-workflow/src/**",
31
+ "plugins/cool-workflow/package.json",
32
+ "plugins/cool-workflow/tsconfig.json"
33
+ ],
34
+ "exclude": [
35
+ "plugins/cool-workflow/dist/**",
36
+ "plugins/cool-workflow/test/**",
37
+ "plugins/cool-workflow/docs/**",
38
+ "plugins/cool-workflow/apps/**",
39
+ "plugins/cool-workflow/scripts/**",
40
+ "docs/assets/**",
41
+ ".cw-release/**",
42
+ "CHANGELOG.md",
43
+ "ITERATION_LOG.md"
44
+ ]
45
+ },
46
+ "mcp": {
47
+ "description": "MCP and CLI surface context for capability registry, MCP server, CLI routing, and MCP launcher wrappers.",
48
+ "maxLines": 18000,
49
+ "include": [
50
+ "plugins/cool-workflow/src/capability-core.ts",
51
+ "plugins/cool-workflow/src/capability-registry.ts",
52
+ "plugins/cool-workflow/src/cli.ts",
53
+ "plugins/cool-workflow/src/mcp-server.ts",
54
+ "plugins/cool-workflow/src/types/**",
55
+ "plugins/cool-workflow/scripts/cw.js",
56
+ "plugins/cool-workflow/scripts/mcp-server.js",
57
+ "plugins/cool-workflow/package.json",
58
+ "plugins/cool-workflow/tsconfig.json"
59
+ ],
60
+ "exclude": [
61
+ "plugins/cool-workflow/dist/**",
62
+ "plugins/cool-workflow/test/**",
63
+ "plugins/cool-workflow/docs/**",
64
+ "docs/assets/**",
65
+ ".cw-release/**",
66
+ "CHANGELOG.md",
67
+ "ITERATION_LOG.md"
68
+ ]
69
+ },
70
+ "workflow-apps": {
71
+ "description": "Workflow App framework and canonical app context without the full runtime kernel.",
72
+ "maxLines": 18000,
73
+ "include": [
74
+ "plugins/cool-workflow/apps/**",
75
+ "plugins/cool-workflow/src/workflow-app-framework.ts",
76
+ "plugins/cool-workflow/src/orchestrator.ts",
77
+ "plugins/cool-workflow/src/orchestrator/**",
78
+ "plugins/cool-workflow/src/types/workflow-app.ts",
79
+ "plugins/cool-workflow/src/types/run.ts",
80
+ "plugins/cool-workflow/scripts/canonical-apps.js",
81
+ "plugins/cool-workflow/package.json",
82
+ "plugins/cool-workflow/tsconfig.json"
83
+ ],
84
+ "exclude": [
85
+ "plugins/cool-workflow/dist/**",
86
+ "plugins/cool-workflow/test/**",
87
+ "plugins/cool-workflow/docs/**",
88
+ "docs/assets/**",
89
+ ".cw-release/**",
90
+ "CHANGELOG.md",
91
+ "ITERATION_LOG.md"
92
+ ]
93
+ },
94
+ "release": {
95
+ "description": "Release-engineering context for gates, release flow, version sync, manifests, and package metadata.",
96
+ "maxLines": 12000,
97
+ "include": [
98
+ "AGENTS.md",
99
+ "plugins/cool-workflow/scripts/release-flow.js",
100
+ "plugins/cool-workflow/scripts/release-gate.sh",
101
+ "plugins/cool-workflow/scripts/dogfood-release.js",
102
+ "plugins/cool-workflow/scripts/gen-manifests.js",
103
+ "plugins/cool-workflow/scripts/version-sync-check.js",
104
+ "plugins/cool-workflow/scripts/bump-version.js",
105
+ "plugins/cool-workflow/package.json",
106
+ "plugins/cool-workflow/manifest/**",
107
+ "plugins/cool-workflow/docs/release-tooling.7.md"
108
+ ],
109
+ "exclude": [
110
+ "plugins/cool-workflow/dist/**",
111
+ "plugins/cool-workflow/test/**",
112
+ "docs/assets/**",
113
+ ".cw-release/**",
114
+ "CHANGELOG.md",
115
+ "ITERATION_LOG.md"
116
+ ]
117
+ },
118
+ "agent-wrappers": {
119
+ "description": "External agent delegation wrappers and neutral backend configuration context.",
120
+ "maxLines": 14000,
121
+ "include": [
122
+ "plugins/cool-workflow/scripts/agents/**",
123
+ "plugins/cool-workflow/scripts/architecture-review-fast.js",
124
+ "plugins/cool-workflow/src/agent-config.ts",
125
+ "plugins/cool-workflow/src/execution-backend.ts",
126
+ "plugins/cool-workflow/src/drive.ts",
127
+ "plugins/cool-workflow/src/types/execution-backend.ts",
128
+ "plugins/cool-workflow/src/types/drive.ts",
129
+ "plugins/cool-workflow/package.json",
130
+ "plugins/cool-workflow/docs/agent-delegation-drive.7.md"
131
+ ],
132
+ "exclude": [
133
+ "plugins/cool-workflow/dist/**",
134
+ "plugins/cool-workflow/test/**",
135
+ "docs/assets/**",
136
+ ".cw-release/**",
137
+ "CHANGELOG.md",
138
+ "ITERATION_LOG.md"
139
+ ]
140
+ }
141
+ }
142
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cool-workflow",
3
- "version": "0.1.79",
3
+ "version": "0.1.81",
4
4
  "bin": {
5
5
  "cool-workflow": "scripts/cw.js",
6
6
  "cw": "scripts/cw.js"
@@ -51,11 +51,14 @@
51
51
  "forward-ref": "node scripts/forward-ref-docs.js",
52
52
  "verify:container": "node scripts/verify-container-selfref.js",
53
53
  "gen:manifests": "node scripts/gen-manifests.js",
54
+ "manifest:load-check": "node test/vendor-manifest-load-smoke.js",
54
55
  "parity:check": "node scripts/parity-check.js --check",
55
56
  "version:sync": "node scripts/version-sync-check.js",
56
57
  "release:check": "node scripts/release-check.js",
57
58
  "test": "node dist/cli.js list && node test/run-all.js",
58
59
  "test:fast": "npm run build --if-present && node dist/cli.js list && node test/run-all.js --concurrency auto",
60
+ "test:ci": "node dist/cli.js list && node test/run-all.js --concurrency auto",
61
+ "test:coverage": "node dist/cli.js list && node scripts/coverage-gate.js --concurrency auto",
59
62
  "eval:replay": "tsc -p tsconfig.json && node test/multi-agent-eval-replay-harness-smoke.js",
60
63
  "ci": "npm run build && npm run check && npm run test && npm run release:check",
61
64
  "validate:schema": "node scripts/validate-run-state-schema.js"
@@ -0,0 +1,7 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "comment": "Builtin agent-delegation templates as DATA, not a hand-edited kernel TS literal (FreeBSD-audit L15). Each entry maps a vendor name to the wrapper script in THIS directory that `builtin:<name>` (or CW_AGENT_COMMAND=builtin:<name>) resolves to. Adding a vendor is a content/distribution step: drop a wrapper script here + add a line below — NO kernel edit. Still pure config: the wrapper is an out-of-process delegation script; CW never imports or calls a model API.",
4
+ "templates": {
5
+ "claude": "claude-p-agent.js"
6
+ }
7
+ }
@@ -5,27 +5,30 @@
5
5
  //
6
6
  // This is a CONFIG, NOT a CW dependency: CW spawns it out-of-process (argv-style,
7
7
  // shell:false, cwd = the target repo) and records its attested output; the model
8
- // runs in claude's process, never in CW. Node port of claude-p-agent.sh (which now
9
- // delegates here) so the documented onboarding path is portable (node-only repo
10
- // convention, Windows included).
8
+ // runs in claude's process, never in CW.
11
9
  //
12
10
  // It fulfills ONE worker: read the worker's input.md ({{input}}), delegate the
13
11
  // analysis to headless claude READ-ONLY, persist claude's final markdown to the
14
- // worker's result.md ({{result}}), and forward claude's JSON (model + usage) on
15
- // stdout so CW records the agent-REPORTED model and token usage as provenance.
12
+ // worker's result.md ({{result}}), and forward claude's JSON on STDOUT so CW
13
+ // records the agent-reported provenance.
16
14
  //
17
- // READ-ONLY by design: claude gets NO Write tool. The architecture-review app
18
- // declares the `readonly` sandbox profile the agent must not touch the repo.
19
- // This wrapper (the transport) writes the single result.md artifact itself, so
20
- // the worker completes WITHOUT granting the model file-write access.
15
+ // LIVE OUTPUT (Unix discipline): default output is the legacy `--output-format
16
+ // json` contract, forwarded verbatim on stdout. Set CW_AGENT_STREAM=1 to opt in
17
+ // to claude `stream-json`; only then does this wrapper render a human-readable
18
+ // trace to stderr, and only when stderr is a TTY. Diagnostics stay off stdout,
19
+ // and vendor-specific stream parsing lives HERE in the wrapper (policy), not in
20
+ // CW's core (which only forwards, never parses).
21
21
  //
22
- // Point CW at it (from plugins/cool-workflow/):
22
+ // READ-ONLY by design: claude gets NO Write tool; the architecture-review app
23
+ // declares the `readonly` sandbox profile. This wrapper (the transport) writes
24
+ // the single result.md artifact itself, so the worker completes without granting
25
+ // the model file-write access.
26
+ //
27
+ // Point CW at it (from plugins/cool-workflow/), or use the `builtin:claude` alias:
23
28
  // CW_AGENT_COMMAND="node $(pwd)/scripts/agents/claude-p-agent.js {{input}} {{result}}"
24
- // or per-invocation:
25
- // --agent-command "node $(pwd)/scripts/agents/claude-p-agent.js {{input}} {{result}}"
26
29
 
27
30
  const fs = require("node:fs");
28
- const { spawnSync } = require("node:child_process");
31
+ const { spawn, spawnSync } = require("node:child_process");
29
32
 
30
33
  const inputPath = process.argv[2];
31
34
  const resultPath = process.argv[3];
@@ -63,42 +66,125 @@ HARD RULES (the result is REJECTED otherwise):
63
66
  - "classification", if present, MUST be one of: real, conditional, non-issue, unknown.
64
67
  - Any finding with "severity" P0, P1, or P2 MUST include a NON-EMPTY "evidence" array.
65
68
  - The top-level "evidence" array MUST be NON-EMPTY with REAL file:line locators from this repo.
66
- - If you have no structured findings, use "findings": [] (empty) — never omit a finding's id.
67
- `;
69
+ - If you have no structured findings, use "findings": [] (empty) — never omit a finding's id.`;
68
70
 
69
71
  const prompt = `${fs.readFileSync(inputPath, "utf8")}\n${CONTRACT}`;
72
+ const streamEnabled = process.env.CW_AGENT_STREAM === "1" && process.env.CW_NO_STREAM !== "1";
73
+ const traceEnabled = streamEnabled && Boolean(process.stderr.isTTY);
70
74
 
71
- // Read-only analysis: NO Write tool, so claude cannot touch the repo. This wrapper
72
- // (the transport) persists claude's final markdown to the worker's result.md.
73
- // --output-format json so CW can read the agent-REPORTED model + usage from stdout
74
- // (the attested model; CW never uses CW_AGENT_MODEL as the attested model).
75
- const child = spawnSync("claude", ["-p", prompt, "--output-format", "json", "--allowedTools", "Read,Grep,Glob,Bash"], {
76
- encoding: "utf8",
77
- maxBuffer: 32 * 1024 * 1024,
78
- shell: false
79
- });
80
- if (child.error) {
81
- process.stderr.write(`claude spawn failed: ${child.error.message}\n`);
82
- process.exit(1);
75
+ if (!streamEnabled) {
76
+ // Legacy default: --output-format json and verbatim stdout forwarding. This is
77
+ // the public wrapper contract existing users already scripted against.
78
+ const child = spawnSync("claude", ["-p", prompt, "--output-format", "json", "--allowedTools", "Read,Grep,Glob,Bash"], {
79
+ encoding: "utf8",
80
+ maxBuffer: 32 * 1024 * 1024,
81
+ shell: false
82
+ });
83
+ if (child.error) {
84
+ process.stderr.write(`claude spawn failed: ${child.error.message}\n`);
85
+ process.exit(1);
86
+ }
87
+ if (child.status !== 0) {
88
+ process.stderr.write(String(child.stderr || `claude exited ${child.status}`));
89
+ process.exit(child.status === null ? 1 : child.status);
90
+ }
91
+
92
+ const out = String(child.stdout || "");
93
+ let parsed;
94
+ try {
95
+ parsed = JSON.parse(out);
96
+ } catch (error) {
97
+ process.stderr.write(`claude output was not JSON: ${error.message}\n`);
98
+ process.exit(1);
99
+ }
100
+
101
+ fs.writeFileSync(resultPath, String(parsed.result || ""), "utf8");
102
+ process.stdout.write(out);
103
+ process.exit(0);
83
104
  }
84
- if (child.status !== 0) {
85
- process.stderr.write(String(child.stderr || `claude exited ${child.status}`));
86
- process.exit(child.status === null ? 1 : child.status);
105
+
106
+ // Live trace → stderr only. Concise; one line per meaningful event.
107
+ function trace(line) {
108
+ if (!traceEnabled) return;
109
+ process.stderr.write(`${line}\n`);
110
+ }
111
+ function shortInput(tool, input) {
112
+ if (!input || typeof input !== "object") return "";
113
+ const v = input.file_path || input.path || input.pattern || input.command || input.query || input.url || "";
114
+ const s = String(v).replace(/\s+/g, " ").trim();
115
+ return s ? ` ${s.length > 80 ? s.slice(0, 77) + "…" : s}` : "";
87
116
  }
88
117
 
89
- const out = String(child.stdout || "");
90
- let parsed;
91
- try {
92
- parsed = JSON.parse(out);
93
- } catch (error) {
94
- // Fail closed: no parsable agent JSON no result.md CW records a failed hop.
95
- process.stderr.write(`claude output was not JSON: ${error.message}\n`);
96
- process.exit(1);
118
+ // stream-json so claude emits incremental NDJSON events we can render live, while
119
+ // we reconstruct the single {model, usage, result} object CW consumes on stdout.
120
+ const child = spawn(
121
+ "claude",
122
+ ["-p", prompt, "--output-format", "stream-json", "--verbose", "--allowedTools", "Read,Grep,Glob,Bash"],
123
+ { stdio: ["ignore", "pipe", "inherit"] } // claude's own stderr straight through
124
+ );
125
+
126
+ let model;
127
+ let usage;
128
+ let resultText;
129
+ let buf = "";
130
+
131
+ trace("● claude: reading the repo (read-only)…");
132
+
133
+ child.stdout.setEncoding("utf8");
134
+ child.stdout.on("data", (chunk) => {
135
+ buf += chunk;
136
+ let nl;
137
+ while ((nl = buf.indexOf("\n")) >= 0) {
138
+ const line = buf.slice(0, nl).trim();
139
+ buf = buf.slice(nl + 1);
140
+ if (!line) continue;
141
+ let ev;
142
+ try {
143
+ ev = JSON.parse(line);
144
+ } catch {
145
+ continue; // not a complete JSON line; ignore (defensive)
146
+ }
147
+ renderEvent(ev);
148
+ }
149
+ });
150
+
151
+ function renderEvent(ev) {
152
+ if (ev.type === "assistant" && ev.message) {
153
+ if (!model && typeof ev.message.model === "string") model = ev.message.model;
154
+ for (const part of ev.message.content || []) {
155
+ if (part.type === "text" && part.text && part.text.trim()) {
156
+ trace(` ${part.text.trim().replace(/\n+/g, "\n ")}`);
157
+ } else if (part.type === "tool_use") {
158
+ trace(` → ${part.name}${shortInput(part.name, part.input)}`);
159
+ }
160
+ }
161
+ } else if (ev.type === "system" && ev.subtype === "post_turn_summary" && ev.status_detail) {
162
+ trace(` · ${ev.status_detail}`);
163
+ } else if (ev.type === "result") {
164
+ if (typeof ev.result === "string") resultText = ev.result;
165
+ if (ev.usage && typeof ev.usage === "object") usage = ev.usage;
166
+ if (ev.is_error) trace(" ✗ claude reported an error result");
167
+ }
97
168
  }
98
169
 
99
- // Persist the AGENT's final markdown to the worker's result.md for CW's separate
100
- // acceptance layer. CW is only the transport; the content is the agent's.
101
- fs.writeFileSync(resultPath, String(parsed.result || ""), "utf8");
170
+ child.on("error", (err) => {
171
+ process.stderr.write(`claude spawn failed: ${err.message}\n`);
172
+ process.exit(1);
173
+ });
102
174
 
103
- // Hand the agent's JSON (model + usage + result) back to CW on stdout.
104
- process.stdout.write(out);
175
+ child.on("close", (code) => {
176
+ if (code !== 0) {
177
+ process.stderr.write(`claude exited ${code === null ? "(timeout/killed)" : code}\n`);
178
+ process.exit(code === null ? 1 : code);
179
+ }
180
+ if (typeof resultText !== "string") {
181
+ // Fail closed: no result event ⇒ no result.md ⇒ CW records a failed hop.
182
+ process.stderr.write("claude produced no result event — refusing to fabricate a result\n");
183
+ process.exit(1);
184
+ }
185
+ // Persist the AGENT's final markdown to the worker's result.md (CW is transport).
186
+ fs.writeFileSync(resultPath, resultText, "utf8");
187
+ trace("● done — result captured");
188
+ // The single JSON CW consumes on STDOUT (data channel): model + usage + result.
189
+ process.stdout.write(JSON.stringify({ model, usage, result: resultText }));
190
+ });