cool-workflow 0.2.4 → 0.2.6
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/.gemini-plugin/mcp.json +10 -0
- package/.gemini-plugin/plugin.json +40 -0
- package/.opencode-plugin/mcp.json +10 -0
- package/.opencode-plugin/plugin.json +40 -0
- package/README.md +204 -48
- 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/cli/dispatch.js +32 -4
- package/dist/cli/entry.js +11 -19
- package/dist/cli/global-flags.js +113 -0
- package/dist/cli/parseargv.js +7 -1
- package/dist/core/capability-data.js +337 -8
- package/dist/core/format/help.js +73 -3
- package/dist/core/format/recovery-hint.js +32 -0
- package/dist/core/multi-agent/collaboration.js +35 -6
- package/dist/core/multi-agent/runtime.js +7 -0
- package/dist/core/multi-agent/trust-policy.js +7 -1
- package/dist/core/pipeline/contract.js +7 -0
- package/dist/core/pipeline/error-feedback.js +2 -2
- package/dist/core/state/run-paths.js +3 -30
- package/dist/core/trust/evidence-grounding.js +13 -1
- package/dist/core/util/cli-args.js +22 -0
- package/dist/core/version.js +1 -1
- package/dist/mcp/dispatch.js +22 -2
- package/dist/mcp/server.js +215 -36
- package/dist/mcp/tool-process.js +181 -0
- package/dist/mcp-server.js +28 -1
- package/dist/shell/agent-config.js +11 -2
- package/dist/shell/audit-cli.js +1 -1
- package/dist/shell/commit.js +8 -2
- package/dist/shell/coordinator-io.js +73 -1
- package/dist/shell/drive.js +195 -128
- package/dist/shell/error-feedback-io.js +6 -0
- package/dist/shell/execution-backend/agent.js +201 -26
- package/dist/shell/execution-backend/container.js +44 -10
- package/dist/shell/execution-backend/local.js +33 -0
- package/dist/shell/fs-atomic.js +96 -12
- package/dist/shell/ledger-cli.js +9 -2
- package/dist/shell/metrics-cli.js +1 -1
- package/dist/shell/multi-agent-cli.js +9 -2
- package/dist/shell/multi-agent-operator-ux.js +1 -1
- package/dist/shell/observability.js +7 -4
- package/dist/shell/onramp.js +48 -5
- package/dist/shell/operator-ux.js +1 -1
- package/dist/shell/perf-trace.js +136 -0
- package/dist/shell/pipeline.js +3 -2
- package/dist/shell/reclamation-io.js +10 -9
- package/dist/shell/report-view-cli.js +2 -0
- package/dist/shell/run-export-cli.js +5 -2
- package/dist/shell/run-export.js +293 -31
- package/dist/shell/run-registry-io.js +8 -0
- package/dist/shell/run-store.js +183 -3
- package/dist/shell/scheduler-io.js +101 -10
- package/dist/shell/state-explosion-cli.js +4 -1
- package/dist/shell/telemetry-demo.js +1 -1
- package/dist/shell/telemetry-ledger-io.js +36 -24
- package/dist/shell/trust-audit.js +178 -36
- package/dist/shell/workbench-host.js +121 -10
- package/dist/shell/workbench.js +83 -6
- package/dist/shell/worker-isolation.js +1 -1
- package/dist/wiring/capability-table/basics.js +5 -0
- package/dist/wiring/capability-table/exec-backend.js +40 -22
- package/dist/wiring/capability-table/parity.js +10 -5
- package/dist/wiring/capability-table/pipeline.js +32 -0
- package/dist/wiring/capability-table/registry-core.js +26 -3
- package/dist/wiring/capability-table/reporting.js +7 -1
- package/dist/wiring/capability-table/scheduling-registry.js +8 -2
- package/dist/wiring/capability-table/trust-ledger.js +54 -12
- package/docs/agent-delegation-drive.7.md +17 -0
- package/docs/cli-mcp-parity.7.md +46 -5
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +38 -0
- package/docs/cross-agent-ledger.7.md +20 -8
- 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 +4 -4
- package/docs/getting-started.md +40 -32
- package/docs/index.md +17 -0
- package/docs/launch/demo.tape +4 -3
- package/docs/mcp-app-surface.7.md +27 -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/project-index.md +53 -9
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +12 -0
- package/docs/routine.7.md +22 -0
- package/docs/run-registry-control-plane.7.md +37 -9
- package/docs/run-retention-reclamation.7.md +12 -4
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/trust-audit-anchor.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +72 -2
- package/docs/workflow-app-framework.7.md +31 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +4 -3
- package/package.json +6 -3
- package/scripts/agents/agent-adapter-core.js +26 -0
- package/scripts/agents/claude-p-agent.js +4 -1
- package/scripts/agents/codex-agent.js +4 -0
- package/scripts/agents/cw-attest-wrap.js +1 -1
- package/scripts/agents/gemini-agent.js +4 -0
- package/scripts/agents/opencode-agent.js +5 -0
- package/scripts/block-unapproved-tag.js +160 -0
- package/scripts/canonical-apps.js +4 -4
- package/scripts/children/batch-delegate-child.js +72 -4
- package/scripts/children/http-batch-delegate-child.js +132 -0
- package/scripts/children/http-delegate-child.js +8 -0
- package/scripts/dogfood-release.js +2 -2
- package/scripts/fake-date-for-reproduction.js +1 -1
- package/scripts/gen-manifests.js +32 -61
- package/scripts/golden-path.js +4 -4
- package/scripts/lang-policy-check.js +82 -0
- package/scripts/parity-check.js +42 -23
- package/scripts/purity-baseline.json +0 -3
- package/scripts/purity-gate.js +16 -3
- package/scripts/release-check.js +2 -1
- package/scripts/release-flow.js +169 -41
- package/scripts/release-gate.js +208 -0
- package/scripts/release-oneclick.js +38 -7
- package/scripts/release-tags.js +47 -0
- package/scripts/schema-version-inventory.json +31 -0
- package/scripts/validate-run-state-schema.js +95 -4
- package/scripts/verdict-keygen.js +2 -2
- package/scripts/verify-bump-reproduction.js +193 -0
- package/scripts/verify-release-verdict.js +139 -0
- package/scripts/verify-verdict-signature.js +1 -1
- package/ui/workbench/app.css +50 -10
- package/ui/workbench/app.js +269 -34
- package/ui/workbench/index.html +4 -2
- package/ui/workbench/inspection.js +51 -0
- package/ui/workbench/navigation.js +44 -0
- package/docs/agent-framework.md +0 -177
- package/docs/designs/handoff-ledger.md +0 -145
- package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +0 -40
- package/docs/launch/launch-kit.md +0 -195
- package/docs/launch/pre-launch-checklist.md +0 -53
- package/docs/readme-v0.1.87-full.md +0 -301
- package/docs/routines.md +0 -101
- package/docs/scheduled-tasks.md +0 -80
- package/scripts/agents/claude-p-agent.sh +0 -9
- package/scripts/block-unapproved-tag.sh +0 -75
- package/scripts/release-gate.sh +0 -94
- package/scripts/verify-bump-reproduction.sh +0 -148
- package/scripts/verify-container-selfref.js +0 -64
|
@@ -169,6 +169,14 @@ LLM step (the reviewer) is **delegated** through CW's agent backend, so whicheve
|
|
|
169
169
|
model you set up does the review. CW starts the agent argv-style (`shell:false`),
|
|
170
170
|
takes on the agent's own credentials, and pulls in no model SDK — the red line.
|
|
171
171
|
|
|
172
|
+
The control plane runs the deterministic gate once. It keeps a failed child
|
|
173
|
+
command's short tail on stderr for the operator, but never puts that tail in a
|
|
174
|
+
saved verdict. The reviewer does not run that gate again. It checks judgment
|
|
175
|
+
questions the gate cannot check. A reviewer rejection has exact `REJECTED`,
|
|
176
|
+
`kind: semantic-review`, and numbered facts with repo-relative `file:line`
|
|
177
|
+
places. Other rejection text is invalid reviewer output: the cut stops, no tag
|
|
178
|
+
is made, and it is not a verified code rejection.
|
|
179
|
+
|
|
172
180
|
```bash
|
|
173
181
|
# the operator's one-command release (scripts/release-oneclick.js — preflight,
|
|
174
182
|
# gated cut, tag-only push, CI wait, npm confirmation, verdict-record PR):
|
|
@@ -320,3 +328,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
|
|
|
320
328
|
0.2.3
|
|
321
329
|
|
|
322
330
|
0.2.4
|
|
331
|
+
|
|
332
|
+
0.2.5
|
|
333
|
+
|
|
334
|
+
0.2.6
|
package/docs/routine.7.md
CHANGED
|
@@ -67,6 +67,28 @@ and fills out the prompt.
|
|
|
67
67
|
| 0 | Command done |
|
|
68
68
|
| 1 | Error (bad arguments, missing trigger, etc.) |
|
|
69
69
|
|
|
70
|
+
## EXAMPLES
|
|
71
|
+
|
|
72
|
+
Long architecture reviews as background routines: use
|
|
73
|
+
`architecture-review-fast` for the foreground user path, then put the full
|
|
74
|
+
`architecture-review` app in line as background work so a deep look-over does
|
|
75
|
+
not get in the way of a back-and-forth session:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
node scripts/architecture-review-fast.js \
|
|
79
|
+
--repo /path/to/repo \
|
|
80
|
+
--question "Is this architecture sound?" \
|
|
81
|
+
--metrics \
|
|
82
|
+
--schedule-full
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The wrapper makes a one-shot reminder schedule whose `workflowId` is
|
|
86
|
+
`architecture-review`. The schedule prompt carries the foreground fast run id,
|
|
87
|
+
fast report path, and source-context digest/profile, and asks the background
|
|
88
|
+
agent to give back the full review report path and digest. `--metrics` is
|
|
89
|
+
optional and reports foreground time plus agent-spawn and result-cache-hit
|
|
90
|
+
counts for the fast run.
|
|
91
|
+
|
|
70
92
|
## SEE ALSO
|
|
71
93
|
|
|
72
94
|
cw sched — durable run-queue scheduling for workflow runs
|
|
@@ -123,6 +123,11 @@ adds the drive outcome to the result under a `drive` field. The default (no
|
|
|
123
123
|
gives `drive.status="blocked"` (fail-closed, never a made-up completion); CW
|
|
124
124
|
hands worker execution to your agent and never runs a model itself.
|
|
125
125
|
|
|
126
|
+
Human output with `--drive` or `--once` prints the drive status, worker counts,
|
|
127
|
+
each drive step, and the terminal commit id when there is one. This makes a
|
|
128
|
+
blocked or failed drive clear without `--json`. Bare `run resume` keeps its old
|
|
129
|
+
text as it is.
|
|
130
|
+
|
|
126
131
|
## Queue
|
|
127
132
|
|
|
128
133
|
`queue add` adds a durable entry to the end of `$CW_HOME/registry/queue.json` with an
|
|
@@ -177,6 +182,15 @@ whose top-level integrity block is *absent* — closing the legacy fail-open sea
|
|
|
177
182
|
where a stripped-integrity archive imported unverified. Unset (the default) keeps
|
|
178
183
|
legacy integrity-less archives byte-identical; the flag is mechanism, not policy.
|
|
179
184
|
|
|
185
|
+
An operator can also set `CW_MAX_RUN_ARCHIVE_BYTES`,
|
|
186
|
+
`CW_MAX_RUN_ARCHIVE_FILES`, or `CW_MAX_RUN_ARCHIVE_CONTENT_BYTES`. Each value
|
|
187
|
+
has to be a positive safe integer. The first sets a raw file byte limit before
|
|
188
|
+
the archive is read. The second sets a normalized file row limit. The last sets
|
|
189
|
+
the total decoded content byte limit, checked from declared sizes before decode
|
|
190
|
+
and again while content is decoded. A bad setting or over-limit archive stops
|
|
191
|
+
before a run directory is made. With all three unset, import, inspect, restore,
|
|
192
|
+
and offline bundle check keep their present behavior.
|
|
193
|
+
|
|
180
194
|
The archive's run id becomes a directory name under `DIR/.cw/runs/`, so import
|
|
181
195
|
also refuses any run id that is not a single safe path segment (`[A-Za-z0-9._-]`,
|
|
182
196
|
with no separator and not the `.` or `..` component) and asserts the resolved run
|
|
@@ -216,11 +230,20 @@ before importing a bad archive. It is a true preview of import: under
|
|
|
216
230
|
turn away) also inspects as `ok:false`; with the env unset (default) an absent integrity
|
|
217
231
|
block is only reported, not failed.
|
|
218
232
|
|
|
233
|
+
The file table is checked before any write. Every row needs a known role, a
|
|
234
|
+
safe size, a sha256 value, and a relative path. Paths are made portable and
|
|
235
|
+
then have to be unique. `state.json`, `import-manifest.json`, and lock files
|
|
236
|
+
are made by the restore work and are not accepted from an archive. A bad row
|
|
237
|
+
or two rows with the same path make inspect, import, and restore fail closed.
|
|
238
|
+
No run directory is made for that input.
|
|
239
|
+
|
|
219
240
|
**Restore in one fail-closed step.** `run restore PATH --target DIR [--json]`
|
|
220
|
-
does the whole move-a-run-to-another-machine flow as
|
|
221
|
-
step
|
|
222
|
-
|
|
223
|
-
|
|
241
|
+
does the whole move-a-run-to-another-machine flow as one atomic, fail-closed
|
|
242
|
+
step. It integrity-**inspects** the bundle first, imports it into a same-disk
|
|
243
|
+
staging tree, and checks the file, telemetry, trust-audit, and run-state records there.
|
|
244
|
+
Only then does it put final paths into state and publish the run with one
|
|
245
|
+
directory rename. It reports `ok:true` only after a check of the published
|
|
246
|
+
tree. This closes a real gap: `run import` runs a
|
|
224
247
|
verification (it re-proves restored file digests, the **telemetry ledger**, and
|
|
225
248
|
the **trust-audit hash chain**) and reports it, but does NOT fail on it — it
|
|
226
249
|
exits `0` even when that chain does not verify. So a run whose telemetry or
|
|
@@ -229,13 +252,14 @@ made-up success. `run restore` refuses exactly that: it fails closed on the same
|
|
|
229
252
|
verification `import` only reports. A bundle that fails the up-front integrity
|
|
230
253
|
inspect is refused **before any import**, so nothing is written and the run is
|
|
231
254
|
never left part-restored; the result carries `imported:null` and `verify:null`.
|
|
232
|
-
A bundle that imports but fails
|
|
233
|
-
`ok:false`
|
|
255
|
+
A bundle that imports in staging but fails a chain check is reported with
|
|
256
|
+
`ok:false`, `imported:null`, and no final run. A final run with the same id is
|
|
257
|
+
never merged or replaced. A staging write fault is cleaned up. It exits `1`
|
|
258
|
+
whenever `ok:false`, so `cw run restore <path>` is a
|
|
234
259
|
single command that either lands a fully-proven run or refuses with a non-zero
|
|
235
|
-
exit — never a made-up success. The result is structured
|
|
260
|
+
exit — never a made-up success or a half-written final run. The result is structured
|
|
236
261
|
(`{ schemaVersion, ok, target, inspect, imported, verify, registry }`) so it is
|
|
237
|
-
scriptable. `run import` and `run inspect-archive` are unchanged
|
|
238
|
-
thin composition of `inspectArchive` + `importRun` (reusing its verification).
|
|
262
|
+
scriptable. `run import` and `run inspect-archive` are unchanged.
|
|
239
263
|
|
|
240
264
|
MCP gives the same mechanisms as `cw_run_export`, `cw_run_import`,
|
|
241
265
|
`cw_run_verify_import`, `cw_run_inspect_archive`, and `cw_run_restore`; the CLI
|
|
@@ -482,3 +506,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
|
|
|
482
506
|
0.2.3
|
|
483
507
|
|
|
484
508
|
0.2.4
|
|
509
|
+
|
|
510
|
+
0.2.5
|
|
511
|
+
|
|
512
|
+
0.2.6
|
|
@@ -109,16 +109,20 @@ node points to a freed path. Opt out with `--keep-scratch`.
|
|
|
109
109
|
|
|
110
110
|
## Commit snapshots — never reconstructable, always downgrades to verify-only
|
|
111
111
|
|
|
112
|
-
`commitState`
|
|
113
|
-
|
|
112
|
+
`commitState` writes only the commit's own (small, bounded) record into
|
|
113
|
+
`commits/<id>.json` on every commit — it no longer embeds the whole run, so
|
|
114
|
+
these files stay small and do not grow with the run's size. Reclaiming them
|
|
114
115
|
frees the run's superseded, non-`verifierGated` "checkpoint" commit snapshots —
|
|
115
116
|
the run's LATEST commit and every `verifierGated` commit (the actual
|
|
116
117
|
audit-significant milestones) are always kept. `run.commits`' own lightweight
|
|
117
118
|
metadata (id, `verifierGated`, evidence digests, acceptance rationale — everything
|
|
118
119
|
`extractSkeleton` seals) lives in `state.json`, not the snapshot file, so it stays
|
|
119
|
-
fully intact and queryable regardless.
|
|
120
|
-
|
|
120
|
+
fully intact and queryable regardless. A commit snapshot is treated as never
|
|
121
|
+
reconstructable — there is no `ReconstructionRecipe` for it — so reclaiming even
|
|
121
122
|
one downgrades capability to `verify-only`, never `re-runnable-by-reconstruction`.
|
|
123
|
+
This is left conservative on purpose: even though the snapshot file's content is
|
|
124
|
+
now a strict subset of what `state.json` already keeps durably, the reclaim
|
|
125
|
+
classification does not (yet) treat that as a basis for reconstruction.
|
|
122
126
|
Each reclaimed commit's own `StateNode` had its `snapshot` artifact stripped (not
|
|
123
127
|
re-pointed — there is no retained alternative) before the free, so `prepareFree`'s
|
|
124
128
|
dangling-reference proof covers this kind too. Opt out with `--keep-commits`.
|
|
@@ -288,3 +292,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
|
|
|
288
292
|
0.2.3
|
|
289
293
|
|
|
290
294
|
0.2.4
|
|
295
|
+
|
|
296
|
+
0.2.5
|
|
297
|
+
|
|
298
|
+
0.2.6
|
|
@@ -10,6 +10,28 @@ speed and the MCP server (JSON-RPC over stdio) showed things for machine context
|
|
|
10
10
|
Workbench lets a person look at a run quickly — and adds NOTHING else. It works out,
|
|
11
11
|
decides, and keeps nothing that the CLI/MCP cannot already make.
|
|
12
12
|
|
|
13
|
+
## Simple UI rules
|
|
14
|
+
|
|
15
|
+
The Workbench follows three public sets of rules:
|
|
16
|
+
|
|
17
|
+
- FreeBSD [style(9)](https://man.freebsd.org/cgi/man.cgi?query=style&sektion=9)
|
|
18
|
+
says that usage text has to agree with the man page and that error text has
|
|
19
|
+
to be easy to find. CW keeps command words and error words clear and fixed.
|
|
20
|
+
- FreeBSD [hier(7)](https://man.freebsd.org/cgi/man.cgi?query=hier&sektion=7)
|
|
21
|
+
gives each sort of file one place. The Workbench keeps no state; `.cw/`
|
|
22
|
+
stays the one state source.
|
|
23
|
+
- Homebrew [brew(1)](https://docs.brew.sh/Manpage) puts its essential commands
|
|
24
|
+
before its full command list, and gives `help`, `doctor`, `info`, and
|
|
25
|
+
`search`. CW gives one clear next command in place of a hidden recovery
|
|
26
|
+
action. Homebrew [External Commands](https://docs.brew.sh/External-Commands)
|
|
27
|
+
also shows how a front door may be added without a change to the tool's
|
|
28
|
+
inside parts. The Workbench stays a view over present CW capabilities.
|
|
29
|
+
- Codex [Best practices](https://learn.chatgpt.com/guides/best-practices.md)
|
|
30
|
+
puts context, checks, and review in the work path. Its
|
|
31
|
+
[app commands](https://learn.chatgpt.com/docs/reference/commands.md) keep
|
|
32
|
+
search, key movement, and Back/Forward movement close at hand. The
|
|
33
|
+
Workbench keeps the run and panel in the page address for the same reason.
|
|
34
|
+
|
|
13
35
|
## The third front door (mechanism vs policy)
|
|
14
36
|
|
|
15
37
|
The kernel and the durable `.cw/` state are the MECHANISM. The CLI, the MCP
|
|
@@ -85,6 +107,7 @@ The host has least privilege and is local by default:
|
|
|
85
107
|
|
|
86
108
|
- it binds the loopback interface `127.0.0.1` ONLY — never a public address
|
|
87
109
|
- it is READ-ONLY: every route is `GET`; any write verb is turned away with `405`
|
|
110
|
+
- a read view makes no audit, metrics, or other derived file under `.cw/`
|
|
88
111
|
- it turns away non-localhost `Host` headers (a DNS-rebinding defense) with `403`
|
|
89
112
|
- it turns away path traversal out of `ui/workbench/` with `403`
|
|
90
113
|
- it serves nothing past the current user's `.cw/` scope and the Run Registry's
|
|
@@ -97,9 +120,16 @@ capability core entry that already exists — never a side code path — so it c
|
|
|
97
120
|
CLI/MCP and is covered by the parity gate.
|
|
98
121
|
|
|
99
122
|
Authentication is opt-in, not on by default: set `CW_WORKBENCH_TOKEN` and every
|
|
100
|
-
request must carry it as `Authorization: Bearer <token>` or `?token=<token>`
|
|
123
|
+
`/api/*` request must carry it as `Authorization: Bearer <token>` or `?token=<token>`
|
|
101
124
|
(timing-safe compare); left unset, the loopback/read-only/GET-only controls
|
|
102
|
-
above are the only defense and any local process can read.
|
|
125
|
+
above are the only defense and any local process can read. The static UI files
|
|
126
|
+
(`/ui/*`, and `/` when the UI is installed) are served without the token: they
|
|
127
|
+
are fixed code with no run data, and the browser needs them before the page can
|
|
128
|
+
say anything at all. The fallback `/` page (used when the UI is not installed)
|
|
129
|
+
stays behind the token, because it holds the serve descriptor with the repo
|
|
130
|
+
root path. Open the page as `/?token=<token>`: the UI reads the token from the
|
|
131
|
+
page address and adds it to every `/api/*` request; without it the page still
|
|
132
|
+
loads and tells you to reopen it with the token. Pass
|
|
103
133
|
`--require-token` to `cw workbench serve` to fail closed instead: the server
|
|
104
134
|
refuses to start at all unless `CW_WORKBENCH_TOKEN` is already set. This is a
|
|
105
135
|
strict opt-in — leaving it off keeps today's default behavior unchanged.
|
|
@@ -113,6 +143,29 @@ cw workbench view <run-id> [--json] # five-panel WorkbenchRunView for on
|
|
|
113
143
|
cw workbench serve [--port N] [--scope repo|home] [--once|--json] [--require-token]
|
|
114
144
|
```
|
|
115
145
|
|
|
146
|
+
The page address may name one run and one panel:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
#run=<encoded-run-id>&tab=<graph|blackboard|worker|candidate|audit|metrics|collaboration>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The `run` value is needed for a run view. With no `tab`, the page uses
|
|
153
|
+
`graph`. A bad tab name is changed to `graph`. Back, Forward, and page reload
|
|
154
|
+
keep the named view. The Workbench token stays in the page query and is never
|
|
155
|
+
put in this fragment.
|
|
156
|
+
|
|
157
|
+
The run list and panels work with a keyboard. Left and Right move through the
|
|
158
|
+
panel tabs; Home and End go to the first and last tab. The active tab and its
|
|
159
|
+
panel are joined with the standard ARIA tab and tabpanel links.
|
|
160
|
+
|
|
161
|
+
When a present panel payload has an `integrity`, `problems`,
|
|
162
|
+
`missingEvidence`, `nextAction`, or `nextActions` fact, the page puts a small
|
|
163
|
+
`What matters` block before the full panel record. It copies only source
|
|
164
|
+
values. It does not make a new state, rank, or action. An empty problem or
|
|
165
|
+
missing-evidence list is shown as `none`. A field with a shape the page does
|
|
166
|
+
not know is left out of the block. The full structured view or JSON stays
|
|
167
|
+
under the block.
|
|
168
|
+
|
|
116
169
|
`cw workbench serve` with `--once`/`--json` prints the serve descriptor (bind
|
|
117
170
|
host/port, scope, routes) and stops without starting a server; the default starts
|
|
118
171
|
the localhost host (like `schedule daemon`). The MCP tools `cw_workbench_view` and
|
|
@@ -282,3 +335,20 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
|
|
|
282
335
|
0.2.3
|
|
283
336
|
|
|
284
337
|
0.2.4
|
|
338
|
+
|
|
339
|
+
## Workbench UI/host round 2 (Unreleased)
|
|
340
|
+
|
|
341
|
+
- With `CW_WORKBENCH_TOKEN` set, the page now works: the static UI files are
|
|
342
|
+
open, and every `/api/*` request stays behind the token (see "Trust
|
|
343
|
+
boundary" above). The UI reads `?token=` from the page address, and a 401
|
|
344
|
+
answer tells you to reopen the page with the token.
|
|
345
|
+
- `cw workbench view --json` (and `/api/run/:runId`) gains a `lifecycle` key:
|
|
346
|
+
the run registry's own state for the run
|
|
347
|
+
(queued|running|blocked|completed|failed|archived|reclaimed). The key is
|
|
348
|
+
left out when the run cannot be classified, so those payloads keep their
|
|
349
|
+
old bytes. The UI shows it as a badge in the run header, with one
|
|
350
|
+
next-step line when a run is blocked or failed.
|
|
351
|
+
|
|
352
|
+
0.2.5
|
|
353
|
+
|
|
354
|
+
0.2.6
|
|
@@ -32,6 +32,37 @@ runner owns state transitions, dispatch, result recording, verifier gates,
|
|
|
32
32
|
commits, and reports. A workflow app owns its own inputs, phases, task
|
|
33
33
|
prompts, evidence needs, and sandbox profile hints.
|
|
34
34
|
|
|
35
|
+
Every CW workflow keeps to one loop, and the loop maps to real framework
|
|
36
|
+
operations:
|
|
37
|
+
|
|
38
|
+
| Loop stage | framework operation | Responsibility |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| Interpret | `plan()` | Load workflow, check inputs, make tasks |
|
|
41
|
+
| Act | `dispatch()` | Move tasks that can run from pending to running |
|
|
42
|
+
| Observe | `recordResult()` | Read Markdown/JSON-RPC result evidence |
|
|
43
|
+
| Adjust | verifier gates | Check evidence and pick the next phase |
|
|
44
|
+
| Checkpoint | `commitState()` | Take a snapshot of state after important changes |
|
|
45
|
+
|
|
46
|
+
The language split is on purpose: the platform is TypeScript
|
|
47
|
+
(`src/*.ts -> dist/*.js`, strongly typed so it is simple to keep up), while
|
|
48
|
+
workflow apps are plain JavaScript modules (`apps/<app-id>/workflow.js`,
|
|
49
|
+
legacy `workflows/*.workflow.js`) so workflow scripts run without `ts-node`.
|
|
50
|
+
|
|
51
|
+
Verification and verdict tasks give back a `cw:result` JSON fence:
|
|
52
|
+
|
|
53
|
+
````text
|
|
54
|
+
```cw:result
|
|
55
|
+
{
|
|
56
|
+
"summary": "short summary",
|
|
57
|
+
"findings": [],
|
|
58
|
+
"evidence": ["/absolute/path/file.ts:42"]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
````
|
|
62
|
+
|
|
63
|
+
CW says no to high-priority findings without evidence. This keeps agent work
|
|
64
|
+
nearer to engineering output you can look into than to free talk.
|
|
65
|
+
|
|
35
66
|
The framework is kept small on purpose. The public app helpers are:
|
|
36
67
|
|
|
37
68
|
- `defineWorkflowApp(definition)`
|
|
@@ -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.2.
|
|
5
|
+
"version": "0.2.6",
|
|
6
6
|
"license": "BSD-2-Clause",
|
|
7
7
|
"homepage": "https://github.com/coo1white/cool-workflow",
|
|
8
8
|
"author": {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"profiles": {
|
|
4
4
|
"core": {
|
|
5
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":
|
|
6
|
+
"maxLines": 52000,
|
|
7
7
|
"include": [
|
|
8
8
|
"plugins/cool-workflow/src/**",
|
|
9
9
|
"plugins/cool-workflow/apps/**",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"runtime": {
|
|
27
27
|
"description": "Runtime-kernel source context for state, orchestration, scheduling, execution, and shared types.",
|
|
28
|
-
"maxLines":
|
|
28
|
+
"maxLines": 49000,
|
|
29
29
|
"include": [
|
|
30
30
|
"plugins/cool-workflow/src/**",
|
|
31
31
|
"plugins/cool-workflow/package.json",
|
|
@@ -95,7 +95,8 @@
|
|
|
95
95
|
"include": [
|
|
96
96
|
"AGENTS.md",
|
|
97
97
|
"plugins/cool-workflow/scripts/release-flow.js",
|
|
98
|
-
"plugins/cool-workflow/scripts/release-gate.
|
|
98
|
+
"plugins/cool-workflow/scripts/release-gate.js",
|
|
99
|
+
"plugins/cool-workflow/scripts/release-tags.js",
|
|
99
100
|
"plugins/cool-workflow/scripts/dogfood-release.js",
|
|
100
101
|
"plugins/cool-workflow/scripts/gen-manifests.js",
|
|
101
102
|
"plugins/cool-workflow/scripts/version-sync-check.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cool-workflow",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"bin": {
|
|
5
5
|
"cool-workflow": "scripts/cw.js",
|
|
6
6
|
"cw": "scripts/cw.js"
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
".claude-plugin/",
|
|
28
28
|
".codex-plugin/",
|
|
29
|
+
".gemini-plugin/",
|
|
30
|
+
".opencode-plugin/",
|
|
29
31
|
".mcp.json",
|
|
30
32
|
"manifest/",
|
|
31
33
|
"README.md",
|
|
@@ -44,6 +46,7 @@
|
|
|
44
46
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
45
47
|
"dist:check": "node scripts/dist-drift-check.js",
|
|
46
48
|
"purity:check": "node scripts/purity-gate.js",
|
|
49
|
+
"lang:check": "node scripts/lang-policy-check.js",
|
|
47
50
|
"golden-path": "node scripts/golden-path.js",
|
|
48
51
|
"dogfood:release": "node scripts/dogfood-release.js",
|
|
49
52
|
"canonical-apps": "node scripts/canonical-apps.js",
|
|
@@ -55,7 +58,6 @@
|
|
|
55
58
|
"bump:version": "node scripts/bump-version.js",
|
|
56
59
|
"new:feature": "node scripts/new-feature.js",
|
|
57
60
|
"forward-ref": "node scripts/forward-ref-docs.js",
|
|
58
|
-
"verify:container": "node scripts/verify-container-selfref.js",
|
|
59
61
|
"gen:manifests": "node scripts/gen-manifests.js",
|
|
60
62
|
"gen:parity": "node scripts/gen-parity-doc.js",
|
|
61
63
|
"manifest:load-check": "node test/vendor-manifest-load-smoke.js",
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
"test:unit": "node dist/cli.js version > /dev/null && node test/run-unit.js",
|
|
74
76
|
"eval:replay": "tsc -p tsconfig.json && node test/multi-agent-eval-replay-harness-smoke.js",
|
|
75
77
|
"ci": "npm run build && npm run check && npm run test && npm run release:check",
|
|
76
|
-
"validate:schema": "node scripts/validate-run-state-schema.js"
|
|
78
|
+
"validate:schema": "node scripts/validate-run-state-schema.js",
|
|
79
|
+
"bench:workbench:deep": "node ../../scripts/bench/workbench-load.js"
|
|
77
80
|
},
|
|
78
81
|
"devDependencies": {
|
|
79
82
|
"@types/node": "^26.1.1",
|
|
@@ -490,8 +490,34 @@ function buildFailureDetail({ label, code, childStderr, partialText }) {
|
|
|
490
490
|
return codeText;
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
// CW may set CW_AGENT_VENDOR_PIDFILE when it runs a shipped wrapper. We write
|
|
494
|
+
// the vendor child's PID there so CW can reap the vendor if it has to SIGKILL
|
|
495
|
+
// this wrapper on a timeout: a SIGKILL is uncatchable, so the wrapper cannot
|
|
496
|
+
// forward the stop to its vendor child itself, and the vendor would otherwise
|
|
497
|
+
// live on as an orphan and keep spending (see execution-backend/agent.ts). The
|
|
498
|
+
// file is removed as soon as the vendor exits, so a stale PID is never reaped.
|
|
499
|
+
// Best-effort: fs errors are ignored -- reaping is a safety net, not a
|
|
500
|
+
// correctness dependency -- and an arbitrary CW_AGENT_COMMAND that never calls
|
|
501
|
+
// this is simply not covered.
|
|
502
|
+
function recordVendorPid(child, env = process.env) {
|
|
503
|
+
const pidfile = env.CW_AGENT_VENDOR_PIDFILE;
|
|
504
|
+
if (!pidfile || !child || !child.pid) return child;
|
|
505
|
+
try { fs.writeFileSync(pidfile, String(child.pid), "utf8"); } catch { /* best-effort */ }
|
|
506
|
+
let cleared = false;
|
|
507
|
+
const clear = () => {
|
|
508
|
+
if (cleared) return;
|
|
509
|
+
cleared = true;
|
|
510
|
+
try { fs.unlinkSync(pidfile); } catch { /* already gone */ }
|
|
511
|
+
};
|
|
512
|
+
child.once("close", clear);
|
|
513
|
+
child.once("exit", clear);
|
|
514
|
+
process.once("exit", clear);
|
|
515
|
+
return child;
|
|
516
|
+
}
|
|
517
|
+
|
|
493
518
|
module.exports = {
|
|
494
519
|
RESULT_CONTRACT,
|
|
520
|
+
recordVendorPid, // write the vendor child's PID to CW_AGENT_VENDOR_PIDFILE so cw can reap it on a timeout
|
|
495
521
|
buildPrompt,
|
|
496
522
|
streamEnabled,
|
|
497
523
|
traceEnabled,
|
|
@@ -34,7 +34,7 @@ const { spawn, spawnSync } = require("node:child_process");
|
|
|
34
34
|
// wrappers instead of carrying a private copy. A drifted inline copy (ASCII
|
|
35
35
|
// hyphens silently became em-dashes here) meant claude was sent a different
|
|
36
36
|
// instruction text than the other providers for the same contract.
|
|
37
|
-
const { buildPrompt, createRenderer, persistStderr, toolLabel, summarizeToolResult, buildFailureDetail } = require("./agent-adapter-core");
|
|
37
|
+
const { buildPrompt, createRenderer, persistStderr, toolLabel, summarizeToolResult, buildFailureDetail, recordVendorPid } = require("./agent-adapter-core");
|
|
38
38
|
|
|
39
39
|
const inputPath = process.argv[2];
|
|
40
40
|
const resultPath = process.argv[3];
|
|
@@ -103,6 +103,9 @@ const child = spawn(
|
|
|
103
103
|
["-p", prompt, "--output-format", "stream-json", "--verbose", "--allowedTools", "Read,Grep,Glob"],
|
|
104
104
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
105
105
|
);
|
|
106
|
+
// Record the vendor PID so cw can reap this claude process if it SIGKILLs the
|
|
107
|
+
// wrapper on a timeout (see agent-adapter-core recordVendorPid).
|
|
108
|
+
recordVendorPid(child);
|
|
106
109
|
|
|
107
110
|
let model;
|
|
108
111
|
let usage;
|
|
@@ -43,6 +43,7 @@ const {
|
|
|
43
43
|
flushJsonLines,
|
|
44
44
|
parseJsonLines,
|
|
45
45
|
persistStderr,
|
|
46
|
+
recordVendorPid,
|
|
46
47
|
writeResult
|
|
47
48
|
} = require("./agent-adapter-core");
|
|
48
49
|
|
|
@@ -133,6 +134,9 @@ const child = spawn("codex", args, {
|
|
|
133
134
|
stdio: ["pipe", "pipe", "pipe"],
|
|
134
135
|
shell: false
|
|
135
136
|
});
|
|
137
|
+
// Record the vendor PID so cw can reap this codex process if it SIGKILLs the
|
|
138
|
+
// wrapper on a timeout (see agent-adapter-core recordVendorPid).
|
|
139
|
+
recordVendorPid(child);
|
|
136
140
|
|
|
137
141
|
child.stdin.setDefaultEncoding("utf8");
|
|
138
142
|
child.stdin.end(prompt);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// Point CW at it (from plugins/cool-workflow/), keeping your inner agent intact:
|
|
21
21
|
// CW_AGENT_ATTEST_PRIVKEY=$PWD/cw-attest.key \
|
|
22
22
|
// CW_AGENT_COMMAND="node $PWD/scripts/agents/cw-attest-wrap.js --manifest {{manifest}} -- \
|
|
23
|
-
//
|
|
23
|
+
// node $PWD/scripts/agents/claude-p-agent.js {{input}} {{result}}"
|
|
24
24
|
// and configure CW's verify side: CW_AGENT_ATTEST_PUBKEY=$PWD/cw-attest.pub
|
|
25
25
|
//
|
|
26
26
|
// Honest posture: if no private key is set, or the agent reports no usage, the
|
|
@@ -24,6 +24,7 @@ const {
|
|
|
24
24
|
flushJsonLines,
|
|
25
25
|
parseJsonLines,
|
|
26
26
|
persistStderr,
|
|
27
|
+
recordVendorPid,
|
|
27
28
|
writeResult
|
|
28
29
|
} = require("./agent-adapter-core");
|
|
29
30
|
|
|
@@ -71,6 +72,9 @@ const child = spawn("gemini", args, {
|
|
|
71
72
|
stdio: ["ignore", "pipe", "pipe"],
|
|
72
73
|
shell: false
|
|
73
74
|
});
|
|
75
|
+
// Record the vendor PID so cw can reap this gemini process if it SIGKILLs the
|
|
76
|
+
// wrapper on a timeout (see agent-adapter-core recordVendorPid).
|
|
77
|
+
recordVendorPid(child);
|
|
74
78
|
|
|
75
79
|
child.stdout.setEncoding("utf8");
|
|
76
80
|
child.stdout.on("data", (chunk) => {
|
|
@@ -29,6 +29,7 @@ const {
|
|
|
29
29
|
flushJsonLines,
|
|
30
30
|
parseJsonLines,
|
|
31
31
|
persistStderr,
|
|
32
|
+
recordVendorPid,
|
|
32
33
|
writeResult
|
|
33
34
|
} = require("./agent-adapter-core");
|
|
34
35
|
|
|
@@ -124,6 +125,10 @@ const child = spawn("opencode", args, {
|
|
|
124
125
|
stdio: ["ignore", "pipe", "pipe"],
|
|
125
126
|
shell: false
|
|
126
127
|
});
|
|
128
|
+
// Record the vendor PID so cw can reap this opencode process (also used by the
|
|
129
|
+
// deepseek wrapper, which re-exports this file) if it SIGKILLs the wrapper on a
|
|
130
|
+
// timeout (see agent-adapter-core recordVendorPid).
|
|
131
|
+
recordVendorPid(child);
|
|
127
132
|
|
|
128
133
|
child.stdout.setEncoding("utf8");
|
|
129
134
|
child.stdout.on("data", (chunk) => {
|