cool-workflow 0.1.96 → 0.1.98
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-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/candidate-scoring.js +3 -3
- package/dist/capability-core.js +9 -1
- package/dist/capability-registry.js +7 -1
- package/dist/cli/command-surface.js +4 -0
- package/dist/cli/handlers/ledger.js +169 -0
- package/dist/cli/handlers/scheduling.js +7 -1
- package/dist/drive.js +108 -61
- package/dist/execution-backend/agent.js +84 -24
- package/dist/execution-backend.js +25 -5
- package/dist/ledger.js +313 -0
- package/dist/mcp/tool-call.js +36 -0
- package/dist/mcp/tool-definitions.js +26 -0
- package/dist/mcp-server.js +4 -0
- package/dist/onramp.js +2 -0
- package/dist/orchestrator/app-operations.js +6 -0
- package/dist/orchestrator/cli-options.js +8 -2
- package/dist/orchestrator/lifecycle-operations.js +40 -13
- package/dist/orchestrator/migration-operations.js +1 -1
- package/dist/orchestrator.js +11 -3
- package/dist/remote-source.js +10 -3
- package/dist/run-export.js +45 -5
- package/dist/sandbox-profile.js +6 -1
- package/dist/triggers.js +7 -1
- package/dist/version.js +1 -1
- package/dist/workbench-host.js +18 -2
- package/docs/agent-delegation-drive.7.md +4 -0
- package/docs/cli-mcp-parity.7.md +16 -2
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- package/docs/cross-agent-ledger.7.md +217 -0
- package/docs/demo.7.md +80 -0
- package/docs/designs/handoff-ledger.md +145 -0
- package/docs/doctor.7.md +97 -0
- package/docs/durable-state-and-locking.7.md +4 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
- package/docs/execution-backends.7.md +4 -0
- package/docs/fix.7.md +44 -0
- package/docs/handoff-setup.md +120 -0
- package/docs/init.7.md +62 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
- package/docs/multi-agent-eval-replay-harness.7.md +4 -0
- package/docs/multi-agent-operator-ux.7.md +4 -0
- package/docs/node-snapshot-diff-replay.7.md +4 -0
- package/docs/observability-cost-accounting.7.md +4 -0
- package/docs/pipeline-verbs.7.md +93 -0
- package/docs/project-index.md +28 -5
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +4 -0
- package/docs/routine.7.md +73 -0
- package/docs/run-registry-control-plane.7.md +4 -0
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +4 -0
- package/manifest/README.md +16 -10
- package/manifest/plugin.manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/agents/agent-adapter-core.js +4 -1
- package/scripts/agents/codex-agent.js +34 -4
- package/scripts/canonical-apps.js +4 -4
- package/scripts/children/batch-delegate-child.js +40 -13
- package/scripts/children/http-delegate-child.js +2 -1
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
- package/scripts/release-flow.js +31 -17
package/docs/project-index.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Cool Workflow Project Index
|
|
2
2
|
|
|
3
|
-
Generated from the current repository code on 2026-
|
|
3
|
+
Generated from the current repository code on 2026-07-03 by `npm run sync:project-index`.
|
|
4
4
|
|
|
5
5
|
## Snapshot
|
|
6
6
|
|
|
7
7
|
- Package: `cool-workflow`
|
|
8
|
-
- Version: `0.1.
|
|
9
|
-
- Source modules: `
|
|
8
|
+
- Version: `0.1.98`
|
|
9
|
+
- Source modules: `69`
|
|
10
10
|
- Workflow apps: `8`
|
|
11
|
-
- Docs: `
|
|
12
|
-
- Smoke tests: `
|
|
11
|
+
- Docs: `61`
|
|
12
|
+
- Smoke tests: `172`
|
|
13
13
|
- Repository: https://github.com/coo1white/cool-workflow
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
@@ -93,6 +93,7 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
93
93
|
- [evidence-reasoning.ts](../src/evidence-reasoning.ts)
|
|
94
94
|
- [execution-backend.ts](../src/execution-backend.ts)
|
|
95
95
|
- [gates.ts](../src/gates.ts)
|
|
96
|
+
- [ledger.ts](../src/ledger.ts)
|
|
96
97
|
- [loop-expansion.ts](../src/loop-expansion.ts)
|
|
97
98
|
- [mcp-surface.ts](../src/mcp-surface.ts)
|
|
98
99
|
- [multi-agent-eval.ts](../src/multi-agent-eval.ts)
|
|
@@ -145,14 +146,20 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
145
146
|
- [Contract Migration Tooling](contract-migration-tooling.7.md)
|
|
146
147
|
- [Control-Plane Scheduling](control-plane-scheduling.7.md)
|
|
147
148
|
- [Coordinator / Blackboard](coordinator-blackboard.7.md)
|
|
149
|
+
- [Cross-Agent Handoff Ledger](cross-agent-ledger.7.md)
|
|
150
|
+
- [DEMO(7)](demo.7.md)
|
|
151
|
+
- [DOCTOR(7)](doctor.7.md)
|
|
148
152
|
- [Dogfood One Real Repo](dogfood-one-real-repo.7.md)
|
|
149
153
|
- [Durable State & Locking](durable-state-and-locking.7.md)
|
|
150
154
|
- [End-to-End Golden Path](end-to-end-golden-path.7.md)
|
|
151
155
|
- [ERROR-FEEDBACK(7)](error-feedback.7.md)
|
|
152
156
|
- [Evidence Adoption Reasoning Chain](evidence-adoption-reasoning-chain.7.md)
|
|
153
157
|
- [EXECUTION-BACKENDS(7)](execution-backends.7.md)
|
|
158
|
+
- [FIX(7)](fix.7.md)
|
|
154
159
|
- [Getting Started](getting-started.md)
|
|
160
|
+
- [Handoff ledger — shared-repo setup (T2a)](handoff-setup.md)
|
|
155
161
|
- [Cool Workflow Docs](index.md)
|
|
162
|
+
- [INIT(7)](init.7.md)
|
|
156
163
|
- [MCP App Surface](mcp-app-surface.7.md)
|
|
157
164
|
- [Multi-Agent CLI + MCP Surface](multi-agent-cli-mcp-surface.7.md)
|
|
158
165
|
- [Multi-Agent Eval & Replay Harness](multi-agent-eval-replay-harness.7.md)
|
|
@@ -164,6 +171,7 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
164
171
|
- [Observability + Cost Accounting](observability-cost-accounting.7.md)
|
|
165
172
|
- [Operator UX](operator-ux.7.md)
|
|
166
173
|
- [PIPELINE-RUNNER(7)](pipeline-runner.7.md)
|
|
174
|
+
- [PIPELINE-VERBS(7)](pipeline-verbs.7.md)
|
|
167
175
|
- [Cool Workflow Project Index](project-index.md)
|
|
168
176
|
- [Cool Workflow](readme-v0.1.87-full.md)
|
|
169
177
|
- [Real Execution Backend Integrations](real-execution-backends.7.md)
|
|
@@ -172,6 +180,7 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
172
180
|
- [Release Tooling](release-tooling.7.md)
|
|
173
181
|
- [Remote-Source Review (`--link`)](remote-source-review.7.md)
|
|
174
182
|
- [Verifiable Report Bundle](report-verifiable-bundle.7.md)
|
|
183
|
+
- [ROUTINE(7)](routine.7.md)
|
|
175
184
|
- [Routines](routines.md)
|
|
176
185
|
- [Run Registry / Control Plane](run-registry-control-plane.7.md)
|
|
177
186
|
- [Run Retention & Provable Reclamation](run-retention-reclamation.7.md)
|
|
@@ -196,6 +205,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
196
205
|
|
|
197
206
|
- [agent-config-atomic-write-smoke.js](../test/agent-config-atomic-write-smoke.js)
|
|
198
207
|
- [agent-delegation-drive-smoke.js](../test/agent-delegation-drive-smoke.js)
|
|
208
|
+
- [agent-stream-gate-smoke.js](../test/agent-stream-gate-smoke.js)
|
|
199
209
|
- [append-run-node-no-realloc-smoke.js](../test/append-run-node-no-realloc-smoke.js)
|
|
200
210
|
- [architecture-review-fast-automation-smoke.js](../test/architecture-review-fast-automation-smoke.js)
|
|
201
211
|
- [architecture-review-fast-phase-cache-smoke.js](../test/architecture-review-fast-phase-cache-smoke.js)
|
|
@@ -203,6 +213,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
203
213
|
- [artifact-integrity-smoke.js](../test/artifact-integrity-smoke.js)
|
|
204
214
|
- [audit-verify-smoke.js](../test/audit-verify-smoke.js)
|
|
205
215
|
- [backend-registry-smoke.js](../test/backend-registry-smoke.js)
|
|
216
|
+
- [batch-output-overflow-smoke.js](../test/batch-output-overflow-smoke.js)
|
|
206
217
|
- [blackboard-state-explosion-management-smoke.js](../test/blackboard-state-explosion-management-smoke.js)
|
|
207
218
|
- [block-unapproved-tag-smoke.js](../test/block-unapproved-tag-smoke.js)
|
|
208
219
|
- [budget-scaling-loop-smoke.js](../test/budget-scaling-loop-smoke.js)
|
|
@@ -228,6 +239,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
228
239
|
- [collaboration-ops-unit-smoke.js](../test/collaboration-ops-unit-smoke.js)
|
|
229
240
|
- [concurrency-default-smoke.js](../test/concurrency-default-smoke.js)
|
|
230
241
|
- [concurrent-failure-semantics-smoke.js](../test/concurrent-failure-semantics-smoke.js)
|
|
242
|
+
- [concurrent-subworkflow-cache-nesting-smoke.js](../test/concurrent-subworkflow-cache-nesting-smoke.js)
|
|
231
243
|
- [concurrent-workflow-dsl-smoke.js](../test/concurrent-workflow-dsl-smoke.js)
|
|
232
244
|
- [contract-migration-tooling-smoke.js](../test/contract-migration-tooling-smoke.js)
|
|
233
245
|
- [control-plane-scheduling-smoke.js](../test/control-plane-scheduling-smoke.js)
|
|
@@ -235,11 +247,14 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
235
247
|
- [cw-help-per-command-smoke.js](../test/cw-help-per-command-smoke.js)
|
|
236
248
|
- [dead-export-removal-guard-smoke.js](../test/dead-export-removal-guard-smoke.js)
|
|
237
249
|
- [deepseek-agent-wrapper-smoke.js](../test/deepseek-agent-wrapper-smoke.js)
|
|
250
|
+
- [deferred-checkpoint-batching-smoke.js](../test/deferred-checkpoint-batching-smoke.js)
|
|
238
251
|
- [demo-bundle-smoke.js](../test/demo-bundle-smoke.js)
|
|
239
252
|
- [det-ids-b-smoke.js](../test/det-ids-b-smoke.js)
|
|
240
253
|
- [doctor-smoke.js](../test/doctor-smoke.js)
|
|
241
254
|
- [dogfood-architecture-review-smoke.js](../test/dogfood-architecture-review-smoke.js)
|
|
242
255
|
- [dogfood-release-smoke.js](../test/dogfood-release-smoke.js)
|
|
256
|
+
- [drive-concurrency-flag-smoke.js](../test/drive-concurrency-flag-smoke.js)
|
|
257
|
+
- [drive-exhaustion-blocked-smoke.js](../test/drive-exhaustion-blocked-smoke.js)
|
|
243
258
|
- [durable-atomic-write-smoke.js](../test/durable-atomic-write-smoke.js)
|
|
244
259
|
- [end-to-end-demo-smoke.js](../test/end-to-end-demo-smoke.js)
|
|
245
260
|
- [end-to-end-golden-path-smoke.js](../test/end-to-end-golden-path-smoke.js)
|
|
@@ -257,6 +272,9 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
257
272
|
- [h7-custom-profile-persist-smoke.js](../test/h7-custom-profile-persist-smoke.js)
|
|
258
273
|
- [headline-commands-smoke.js](../test/headline-commands-smoke.js)
|
|
259
274
|
- [incremental-resume-smoke.js](../test/incremental-resume-smoke.js)
|
|
275
|
+
- [ledger-apply-smoke.js](../test/ledger-apply-smoke.js)
|
|
276
|
+
- [ledger-resolution-smoke.js](../test/ledger-resolution-smoke.js)
|
|
277
|
+
- [ledger-verify-smoke.js](../test/ledger-verify-smoke.js)
|
|
260
278
|
- [loop-bounded-expansion-smoke.js](../test/loop-bounded-expansion-smoke.js)
|
|
261
279
|
- [mcp-app-surface-smoke.js](../test/mcp-app-surface-smoke.js)
|
|
262
280
|
- [mcp-surface-registry-smoke.js](../test/mcp-surface-registry-smoke.js)
|
|
@@ -282,6 +300,9 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
282
300
|
- [operator-ux-smoke.js](../test/operator-ux-smoke.js)
|
|
283
301
|
- [parallel-onramp-smoke.js](../test/parallel-onramp-smoke.js)
|
|
284
302
|
- [parity-doc-sync-smoke.js](../test/parity-doc-sync-smoke.js)
|
|
303
|
+
- [parse-guard-smoke.js](../test/parse-guard-smoke.js)
|
|
304
|
+
- [parse-hardening-round2-smoke.js](../test/parse-hardening-round2-smoke.js)
|
|
305
|
+
- [path-containment-smoke.js](../test/path-containment-smoke.js)
|
|
285
306
|
- [pdca-blackboard-loop-smoke.js](../test/pdca-blackboard-loop-smoke.js)
|
|
286
307
|
- [pii-redaction-smoke.js](../test/pii-redaction-smoke.js)
|
|
287
308
|
- [pipeline-auto-advance-smoke.js](../test/pipeline-auto-advance-smoke.js)
|
|
@@ -300,6 +321,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
300
321
|
- [release-check-skip-smoke.js](../test/release-check-skip-smoke.js)
|
|
301
322
|
- [release-flow-smoke.js](../test/release-flow-smoke.js)
|
|
302
323
|
- [release-gate-smoke.js](../test/release-gate-smoke.js)
|
|
324
|
+
- [release-pipeline-hygiene-smoke.js](../test/release-pipeline-hygiene-smoke.js)
|
|
303
325
|
- [release-tooling-smoke.js](../test/release-tooling-smoke.js)
|
|
304
326
|
- [remote-link-archive-smoke.js](../test/remote-link-archive-smoke.js)
|
|
305
327
|
- [remote-link-git-smoke.js](../test/remote-link-git-smoke.js)
|
|
@@ -323,6 +345,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
323
345
|
- [run-resume-drive-smoke.js](../test/run-resume-drive-smoke.js)
|
|
324
346
|
- [run-retention-reclamation-smoke.js](../test/run-retention-reclamation-smoke.js)
|
|
325
347
|
- [sample-determinism-smoke.js](../test/sample-determinism-smoke.js)
|
|
348
|
+
- [sandbox-env-batch-hardening-smoke.js](../test/sandbox-env-batch-hardening-smoke.js)
|
|
326
349
|
- [sandbox-profile-smoke.js](../test/sandbox-profile-smoke.js)
|
|
327
350
|
- [sched-policy-validation-smoke.js](../test/sched-policy-validation-smoke.js)
|
|
328
351
|
- [schedule-routine-daemon-smoke.js](../test/schedule-routine-daemon-smoke.js)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ROUTINE(7)
|
|
2
|
+
|
|
3
|
+
## NAME
|
|
4
|
+
|
|
5
|
+
`cw routine` — make and manage trigger-based workflow routines
|
|
6
|
+
|
|
7
|
+
## SYNOPSIS
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
node dist/cli.js routine create --kind api|github --prompt PROMPT [--match JSON]
|
|
11
|
+
node dist/cli.js routine list [--kind KIND]
|
|
12
|
+
node dist/cli.js routine delete <trigger-id>
|
|
13
|
+
node dist/cli.js routine fire <kind> <payload-file>
|
|
14
|
+
node dist/cli.js routine events [<trigger-id>]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## DESCRIPTION
|
|
18
|
+
|
|
19
|
+
`cw routine` is the local trigger bridge for CW. It lets you make named
|
|
20
|
+
triggers that fire when something happens — an API event, a GitHub webhook, or
|
|
21
|
+
another outside signal. Each trigger carries a prompt template; when fired,
|
|
22
|
+
the prompt gets filled with the event data and handed to an agent host.
|
|
23
|
+
|
|
24
|
+
CW keeps routine data in:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
.cw/routines/triggers.json
|
|
28
|
+
.cw/routines/payloads/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
CW itself does not run a web server or listen for webhooks. The routine bridge
|
|
32
|
+
is a local data store that can be joined to GitHub Actions, webhooks, cron, or
|
|
33
|
+
a small HTTP adapter.
|
|
34
|
+
|
|
35
|
+
## COMMANDS
|
|
36
|
+
|
|
37
|
+
**create**
|
|
38
|
+
: Make a new trigger. `--kind` is `api` or `github`. `--prompt` is the prompt
|
|
39
|
+
template the agent will see. `--match` is an optional JSON object that filters
|
|
40
|
+
events (for example, `{"action":"opened"}` for GitHub pull requests).
|
|
41
|
+
|
|
42
|
+
**list**
|
|
43
|
+
: List all triggers, or filter by kind with `--kind`.
|
|
44
|
+
|
|
45
|
+
**delete**
|
|
46
|
+
: Remove a trigger by its id.
|
|
47
|
+
|
|
48
|
+
**fire**
|
|
49
|
+
: Record an event against a trigger. Give the trigger kind and a path to a
|
|
50
|
+
JSON payload file. CW matches the payload against the trigger's match rules
|
|
51
|
+
and fills out the prompt.
|
|
52
|
+
|
|
53
|
+
**events**
|
|
54
|
+
: List the events that have been recorded for a trigger.
|
|
55
|
+
|
|
56
|
+
## FILES
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
.cw/routines/triggers.json
|
|
60
|
+
.cw/routines/payloads/<event-id>.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## EXIT CODES
|
|
64
|
+
|
|
65
|
+
| Exit | Meaning |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| 0 | Command done |
|
|
68
|
+
| 1 | Error (bad arguments, missing trigger, etc.) |
|
|
69
|
+
|
|
70
|
+
## SEE ALSO
|
|
71
|
+
|
|
72
|
+
cw sched — durable run-queue scheduling for workflow runs
|
|
73
|
+
control-plane-scheduling.7.md — the full scheduling and run management design
|
package/manifest/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Vendor Manifest Source of Truth
|
|
2
2
|
|
|
3
3
|
Every agent host scans a different, hard-coded manifest directory
|
|
4
|
-
(`.claude-plugin/`, `.codex-plugin/`, `.agents
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
shared runtime (`skills/`, `dist/`,
|
|
8
|
-
logic; each manifest is a thin
|
|
4
|
+
(`.claude-plugin/`, `.codex-plugin/`, `.agents/`, `.gemini-plugin/`,
|
|
5
|
+
`.opencode-plugin/`) with a different JSON shape. You cannot unify the directory
|
|
6
|
+
or the schema — so we do not try. Instead, all vendor manifests are **generated**
|
|
7
|
+
from one neutral source and point at the same shared runtime (`skills/`, `dist/`,
|
|
8
|
+
`apps/`, the MCP server). No vendor forks the logic; each manifest is a thin
|
|
9
|
+
adapter.
|
|
9
10
|
|
|
10
11
|
This is the mechanism/policy split: shared assets are mechanism, per-vendor
|
|
11
12
|
manifests are policy.
|
|
@@ -25,13 +26,18 @@ npm run gen:manifests -- --check # fail (exit 1) if any generated file drifted
|
|
|
25
26
|
|
|
26
27
|
## Generated outputs (do NOT hand-edit)
|
|
27
28
|
|
|
29
|
+
Five vendors are generated today. Paths are repo-root-relative.
|
|
30
|
+
|
|
28
31
|
| Vendor | Marketplace | Plugin manifest | MCP config | MCP path var |
|
|
29
32
|
| --- | --- | --- | --- | --- |
|
|
30
|
-
| Claude Code |
|
|
31
|
-
| Codex
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
| Claude Code | `.claude-plugin/marketplace.json` | `plugins/cool-workflow/.claude-plugin/plugin.json` | `plugins/cool-workflow/.mcp.json` (auto-discovered) | `${CLAUDE_PLUGIN_ROOT}/` |
|
|
34
|
+
| Codex | `.agents/plugins/marketplace.json` | `plugins/cool-workflow/.codex-plugin/plugin.json` | `plugins/cool-workflow/.codex-plugin/mcp.json` | `./` |
|
|
35
|
+
| `.agents` | — | `.agents/plugins/cool-workflow/plugin.json` | `.agents/plugins/cool-workflow/mcp.json` | `./` |
|
|
36
|
+
| Gemini | — | `plugins/cool-workflow/.gemini-plugin/plugin.json` | `plugins/cool-workflow/.gemini-plugin/mcp.json` | `./` |
|
|
37
|
+
| OpenCode | — | `plugins/cool-workflow/.opencode-plugin/plugin.json` | `plugins/cool-workflow/.opencode-plugin/mcp.json` | `./` |
|
|
38
|
+
|
|
39
|
+
Each vendor reads its **own** MCP file, so the plugin-root path variable never
|
|
40
|
+
collides.
|
|
35
41
|
|
|
36
42
|
## Adding a new vendor (Cursor, Windsurf, …)
|
|
37
43
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"_comment": "SINGLE SOURCE OF TRUTH for every vendor manifest. Edit THIS file, then run `npm run gen:manifests`. Do NOT hand-edit the generated vendor manifests (.claude-plugin/, .codex-plugin/, .agents/, .mcp.json) — `npm run gen:manifests -- --check` (run by release:check) will fail if they drift from this source.",
|
|
3
3
|
"identity": {
|
|
4
4
|
"name": "cool-workflow",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.98",
|
|
6
6
|
"license": "BSD-2-Clause",
|
|
7
7
|
"homepage": "https://github.com/coo1white/cool-workflow",
|
|
8
8
|
"author": {
|
package/package.json
CHANGED
|
@@ -457,9 +457,12 @@ function emitReport(model, usage, resultText) {
|
|
|
457
457
|
// `logs/agent-stderr.log` sibling is the natural home. Advisory only: never throws,
|
|
458
458
|
// never changes the exit code or the recorded evidence.
|
|
459
459
|
function persistStderr(resultPath, text) {
|
|
460
|
-
|
|
460
|
+
let t = String(text || "").trim();
|
|
461
461
|
if (!t || !resultPath) return;
|
|
462
462
|
try {
|
|
463
|
+
t = String(t).replace(/\b(sk-[A-Za-z0-9_-]{20,}|ghp_[A-Za-z0-9]{20,}|xox[bprs]-[A-Za-z0-9-]{20,}|Bearer\s+\S+|Authorization:\s*\S+|api[_-]?key[=:]\s*\S+|token[=:]\s*\S+)/gi, (match) => match.slice(0, 4) + "***[REDACTED]");
|
|
464
|
+
const cap = 4096;
|
|
465
|
+
if (t.length > cap) t = t.slice(0, cap) + `\n [truncated from ${t.length} bytes]`;
|
|
463
466
|
const dir = path.join(path.dirname(resultPath), "logs");
|
|
464
467
|
fs.mkdirSync(dir, { recursive: true });
|
|
465
468
|
fs.writeFileSync(path.join(dir, "agent-stderr.log"), `${t}\n`, "utf8");
|
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
// per-run override that does NOT touch the user's interactive codex. Tune with
|
|
22
22
|
// CW_CODEX_REASONING_EFFORT (default "low"); set it to "medium"/"high" to opt back
|
|
23
23
|
// into more thinking.
|
|
24
|
+
//
|
|
25
|
+
// REVIEW MODE: the default low-effort / read-only sandbox is right for a fast
|
|
26
|
+
// delegated worker or a liveness probe — but WRONG for an independent RELEASE
|
|
27
|
+
// reviewer, which must actually RE-RUN the gate (build, tests, regenerate dist)
|
|
28
|
+
// to earn its verdict. A read-only sandbox can't execute that gate, so the model
|
|
29
|
+
// is structurally unable to verify and tends to fabricate a REJECTED. The release
|
|
30
|
+
// path therefore sets CW_RELEASE_REVIEW=1 (a vendor-agnostic signal from
|
|
31
|
+
// release-flow.js): on that signal this wrapper raises reasoning to "high" and
|
|
32
|
+
// opens the sandbox to "workspace-write" so codex can run the gate it is judging.
|
|
33
|
+
// Explicit CW_CODEX_REASONING_EFFORT / CW_CODEX_SANDBOX always win over the signal.
|
|
24
34
|
|
|
25
35
|
const fs = require("node:fs");
|
|
26
36
|
const os = require("node:os");
|
|
@@ -80,11 +90,31 @@ function recordJsonLine(line) {
|
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
|
|
83
|
-
|
|
93
|
+
// A release review (CW_RELEASE_REVIEW=1) must execute the gate it judges, so it
|
|
94
|
+
// needs both stronger reasoning and a sandbox that can write inside the workspace.
|
|
95
|
+
// Explicit env overrides win; otherwise the review signal lifts the fast defaults.
|
|
96
|
+
const reviewMode = process.env.CW_RELEASE_REVIEW === "1";
|
|
84
97
|
|
|
85
98
|
// Cap codex's reasoning effort for CW runs (speed) — overrides config.toml for
|
|
86
|
-
// THIS invocation only. Default "low"; CW_CODEX_REASONING_EFFORT opts back up
|
|
87
|
-
|
|
99
|
+
// THIS invocation only. Default "low"; CW_CODEX_REASONING_EFFORT opts back up, and
|
|
100
|
+
// a release review defaults to "high".
|
|
101
|
+
const effort = process.env.CW_CODEX_REASONING_EFFORT || (reviewMode ? "high" : "low");
|
|
102
|
+
|
|
103
|
+
// Sandbox: read-only is the POLA default (a worker/probe only reads). A release
|
|
104
|
+
// review opens to workspace-write so codex can build/test/regenerate the gate.
|
|
105
|
+
// CW_CODEX_SANDBOX overrides both; an unknown value fails closed (never silently
|
|
106
|
+
// downgraded to read-only, which would re-create the can't-verify failure mode).
|
|
107
|
+
const SANDBOX_MODES = new Set(["read-only", "workspace-write", "danger-full-access"]);
|
|
108
|
+
const sandbox = process.env.CW_CODEX_SANDBOX || (reviewMode ? "workspace-write" : "read-only");
|
|
109
|
+
if (!SANDBOX_MODES.has(sandbox)) {
|
|
110
|
+
process.stderr.write(
|
|
111
|
+
`codex-agent: invalid CW_CODEX_SANDBOX="${sandbox}" — expected one of ${[...SANDBOX_MODES].join(", ")}\n`
|
|
112
|
+
);
|
|
113
|
+
process.exit(2);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
render.action(`codex: reading the repo (${sandbox})…`);
|
|
117
|
+
|
|
88
118
|
const args = [
|
|
89
119
|
"exec",
|
|
90
120
|
"--json",
|
|
@@ -93,7 +123,7 @@ const args = [
|
|
|
93
123
|
"--output-last-message",
|
|
94
124
|
finalPath,
|
|
95
125
|
"--sandbox",
|
|
96
|
-
|
|
126
|
+
sandbox,
|
|
97
127
|
"--color",
|
|
98
128
|
"never",
|
|
99
129
|
"-"
|
|
@@ -83,7 +83,7 @@ const canonicalApps = [
|
|
|
83
83
|
"--source",
|
|
84
84
|
"plugins/cool-workflow/docs/workflow-app-framework.7.md",
|
|
85
85
|
"--scope",
|
|
86
|
-
"Cool Workflow v0.1.
|
|
86
|
+
"Cool Workflow v0.1.98",
|
|
87
87
|
"--freshness",
|
|
88
88
|
"as of release preparation"
|
|
89
89
|
]
|
|
@@ -117,14 +117,14 @@ function main() {
|
|
|
117
117
|
assert.ok(summary, `${app.id} must appear in app list`);
|
|
118
118
|
assert.equal(summary.sourceKind, "app-directory");
|
|
119
119
|
assert.equal(summary.legacy, false);
|
|
120
|
-
assert.equal(summary.version, "0.1.
|
|
120
|
+
assert.equal(summary.version, "0.1.98");
|
|
121
121
|
|
|
122
122
|
const validation = runJson(["app", "validate", manifestPath]);
|
|
123
123
|
assert.equal(validation.valid, true, `${app.id} manifest must validate`);
|
|
124
124
|
|
|
125
125
|
const shown = runJson(["app", "show", app.id]);
|
|
126
126
|
assert.equal(shown.app.id, app.id);
|
|
127
|
-
assert.equal(shown.app.version, "0.1.
|
|
127
|
+
assert.equal(shown.app.version, "0.1.98");
|
|
128
128
|
assert.ok(shown.app.metadata.canonical, `${app.id} must be marked canonical`);
|
|
129
129
|
assert.ok(shown.app.sandboxProfiles.length > 0, `${app.id} must declare sandbox profiles`);
|
|
130
130
|
assertTaskIdsUnique(shown);
|
|
@@ -135,7 +135,7 @@ function main() {
|
|
|
135
135
|
const plan = runJson(["plan", app.id, ...app.args(workspace)]);
|
|
136
136
|
const state = JSON.parse(fs.readFileSync(plan.statePath, "utf8"));
|
|
137
137
|
assert.equal(state.workflow.app.id, app.id);
|
|
138
|
-
assert.equal(state.workflow.app.version, "0.1.
|
|
138
|
+
assert.equal(state.workflow.app.version, "0.1.98");
|
|
139
139
|
assert.equal(state.workflow.app.metadata.canonical, true);
|
|
140
140
|
assert.ok(state.tasks.some((task) => task.requiresEvidence), `${app.id} plan must include evidence gates`);
|
|
141
141
|
assert.ok(state.tasks.every((task) => task.sandboxProfileId), `${app.id} plan must include sandbox hints`);
|
|
@@ -8,43 +8,66 @@
|
|
|
8
8
|
//
|
|
9
9
|
// Reads jobs JSON on stdin, spawns ALL concurrently (shell:false, inherited env —
|
|
10
10
|
// the agent's own credentials resolve; CW never reads them), per-job SIGTERM at
|
|
11
|
-
// timeoutMs + SIGKILL at +5s, caps each captured stdout at 32MB
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// timeoutMs + SIGKILL at +5s, caps each captured stdout at 32MB. Streams ONE
|
|
12
|
+
// NDJSON line per job — `{i, spawnError?, exitCode, stdout}\n` — the INSTANT
|
|
13
|
+
// that job settles (not once at the end): the parent's spawnSync call has its
|
|
14
|
+
// own combined-output cap, so writing incrementally means a job whose line
|
|
15
|
+
// already flushed keeps its real outcome even if a LATER job's output pushes
|
|
16
|
+
// the combined stream over that cap and the whole child gets killed. `i` is
|
|
17
|
+
// the job's index (settle order is concurrent, not submission order — the
|
|
18
|
+
// parent cannot infer which line belongs to which job without it). stderr is
|
|
19
|
+
// drained (a full pipe must never wedge a child). A kill yields exitCode null
|
|
20
|
+
// — the no-exit-code refusal.
|
|
14
21
|
//
|
|
15
22
|
// THE RED LINE: this child only `spawn`s the operator-resolved agent binary with
|
|
16
|
-
// shell:false. It imports NO model SDK and reads NO credentials.
|
|
17
|
-
// stay byte-identical to the previous embedded string.
|
|
23
|
+
// shell:false. It imports NO model SDK and reads NO credentials.
|
|
18
24
|
|
|
19
25
|
const { spawn } = require("node:child_process");
|
|
20
26
|
let raw = "";
|
|
27
|
+
const MAX_STDIN_BYTES = 32 * 1024 * 1024;
|
|
21
28
|
process.stdin.setEncoding("utf8");
|
|
22
|
-
process.stdin.on("data", (d) => (raw += d)
|
|
29
|
+
process.stdin.on("data", (d) => { if (raw.length < MAX_STDIN_BYTES) raw += d; });
|
|
23
30
|
process.stdin.on("end", () => {
|
|
24
|
-
|
|
31
|
+
let jobs;
|
|
32
|
+
try {
|
|
33
|
+
jobs = JSON.parse(raw);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
process.stdout.write(JSON.stringify([{ spawnError: `invalid stdin JSON: ${String(e && e.message || e)}`, exitCode: null, stdout: "" }]));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
25
38
|
if (!jobs.length) { process.stdout.write("[]"); return; }
|
|
26
|
-
const out = new Array(jobs.length);
|
|
27
|
-
let pending = jobs.length;
|
|
28
39
|
const CAP = 32 * 1024 * 1024;
|
|
29
40
|
jobs.forEach((job, i) => {
|
|
30
41
|
let stdout = "";
|
|
42
|
+
let stdoutBytes = 0;
|
|
43
|
+
let stdoutTruncated = false;
|
|
31
44
|
let settled = false;
|
|
32
45
|
const settle = (o) => {
|
|
33
46
|
if (settled) return;
|
|
34
47
|
settled = true;
|
|
35
|
-
|
|
36
|
-
if (--pending === 0) process.stdout.write(JSON.stringify(out));
|
|
48
|
+
process.stdout.write(JSON.stringify({ i, ...o }) + "\n");
|
|
37
49
|
};
|
|
38
50
|
let child;
|
|
39
51
|
try {
|
|
40
|
-
child = spawn(job.binary, job.args, { cwd: job.cwd, env: process.env, shell: false });
|
|
52
|
+
child = spawn(job.binary, job.args, { cwd: job.cwd, env: job.env || process.env, shell: false });
|
|
41
53
|
} catch (error) {
|
|
42
54
|
settle({ spawnError: String((error && error.message) || error), exitCode: null, stdout: "" });
|
|
43
55
|
return;
|
|
44
56
|
}
|
|
45
57
|
const term = setTimeout(() => { try { child.kill("SIGTERM"); } catch {} }, job.timeoutMs);
|
|
46
58
|
const kill = setTimeout(() => { try { child.kill("SIGKILL"); } catch {} }, job.timeoutMs + 5000);
|
|
47
|
-
child.stdout.on("data", (d) => {
|
|
59
|
+
child.stdout.on("data", (d) => {
|
|
60
|
+
const chunk = Buffer.isBuffer(d) ? d : Buffer.from(String(d));
|
|
61
|
+
stdoutBytes += chunk.length;
|
|
62
|
+
if (stdoutTruncated) return;
|
|
63
|
+
const remaining = CAP - Buffer.byteLength(stdout);
|
|
64
|
+
if (remaining <= 0 || chunk.length > remaining) {
|
|
65
|
+
stdoutTruncated = true;
|
|
66
|
+
if (remaining > 0) stdout += chunk.subarray(0, remaining).toString();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
stdout += chunk.toString();
|
|
70
|
+
});
|
|
48
71
|
child.stderr.on("data", () => {});
|
|
49
72
|
child.on("error", (error) => {
|
|
50
73
|
clearTimeout(term); clearTimeout(kill);
|
|
@@ -52,6 +75,10 @@ process.stdin.on("end", () => {
|
|
|
52
75
|
});
|
|
53
76
|
child.on("close", (code) => {
|
|
54
77
|
clearTimeout(term); clearTimeout(kill);
|
|
78
|
+
if (stdoutTruncated) {
|
|
79
|
+
settle({ spawnError: `stdout exceeded ${CAP} byte cap (${stdoutBytes} bytes)`, exitCode: null, stdout: "" });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
55
82
|
settle({ exitCode: typeof code === "number" ? code : null, stdout });
|
|
56
83
|
});
|
|
57
84
|
});
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
// API request. Behavior MUST stay byte-identical to the previous embedded string.
|
|
16
16
|
|
|
17
17
|
(async () => {
|
|
18
|
-
const
|
|
18
|
+
const MAX_STDIN_BYTES = 32 * 1024 * 1024;
|
|
19
|
+
const read = () => new Promise((res) => { let b = ""; process.stdin.on("data", (c) => { if (b.length < MAX_STDIN_BYTES) b += c; }); process.stdin.on("end", () => res(b)); });
|
|
19
20
|
try {
|
|
20
21
|
const job = JSON.parse((await read()) || "{}");
|
|
21
22
|
const endpoint = process.env.CW_DELEGATE_ENDPOINT;
|
|
@@ -6,7 +6,7 @@ const fs = require("node:fs");
|
|
|
6
6
|
const path = require("node:path");
|
|
7
7
|
const { CoolWorkflowRunner } = require("../dist/orchestrator.js");
|
|
8
8
|
|
|
9
|
-
const TARGET_VERSION = "0.1.
|
|
9
|
+
const TARGET_VERSION = "0.1.98";
|
|
10
10
|
const PREVIOUS_VERSION = "0.1.31";
|
|
11
11
|
const pluginRoot = path.resolve(__dirname, "..");
|
|
12
12
|
const repoRoot = path.resolve(pluginRoot, "..", "..");
|
package/scripts/golden-path.js
CHANGED
|
@@ -33,7 +33,7 @@ function main() {
|
|
|
33
33
|
const appValidation = runJson(["app", "validate", "end-to-end-golden-path"], pluginRoot);
|
|
34
34
|
assert.equal(appValidation.valid, true);
|
|
35
35
|
assert.equal(appValidation.summary.id, "end-to-end-golden-path");
|
|
36
|
-
assert.equal(appValidation.summary.version, "0.1.
|
|
36
|
+
assert.equal(appValidation.summary.version, "0.1.98");
|
|
37
37
|
|
|
38
38
|
const plan = runJson(
|
|
39
39
|
[
|
|
@@ -42,7 +42,7 @@ function main() {
|
|
|
42
42
|
"--repo",
|
|
43
43
|
tmp,
|
|
44
44
|
"--question",
|
|
45
|
-
"Prove the deterministic v0.1.
|
|
45
|
+
"Prove the deterministic v0.1.98 end-to-end golden path."
|
|
46
46
|
],
|
|
47
47
|
pluginRoot
|
|
48
48
|
);
|
|
@@ -52,7 +52,7 @@ function main() {
|
|
|
52
52
|
|
|
53
53
|
let state = readJson(plan.statePath);
|
|
54
54
|
assert.equal(state.workflow.app.id, "end-to-end-golden-path");
|
|
55
|
-
assert.equal(state.workflow.app.version, "0.1.
|
|
55
|
+
assert.equal(state.workflow.app.version, "0.1.98");
|
|
56
56
|
assert.equal(state.loopStage, "interpret");
|
|
57
57
|
|
|
58
58
|
const dispatch = runJson(["dispatch", plan.runId, "--limit", "1", "--sandbox", "readonly"], tmp);
|
|
@@ -195,7 +195,7 @@ function main() {
|
|
|
195
195
|
assert.equal(reportPath, plan.reportPath);
|
|
196
196
|
assert.ok(fs.existsSync(reportPath));
|
|
197
197
|
const report = fs.readFileSync(reportPath, "utf8");
|
|
198
|
-
assert.match(report, /Workflow App: end-to-end-golden-path@0\.1\.
|
|
198
|
+
assert.match(report, /Workflow App: end-to-end-golden-path@0\.1\.98/);
|
|
199
199
|
assert.match(report, /## Candidates/);
|
|
200
200
|
assert.match(report, /## Trust Audit/);
|
|
201
201
|
assert.match(report, /## Acceptance Rationale/);
|