cool-workflow 0.2.1 → 0.2.3
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/cli/dispatch.js +29 -91
- package/dist/cli/entry.js +41 -1
- package/dist/cli/io.js +6 -2
- package/dist/cli/parseargv.js +6 -2
- package/dist/core/capability-data.js +271 -0
- package/dist/core/capability-table.js +16 -3504
- package/dist/core/format/completion.js +68 -0
- package/dist/core/format/help.js +50 -8
- package/dist/core/format/safe-json.js +73 -0
- package/dist/core/format/state-explosion-text.js +1 -1
- package/dist/core/multi-agent/candidate-scoring.js +5 -1
- package/dist/core/multi-agent/collaboration.js +6 -5
- package/dist/core/multi-agent/coordinator.js +9 -8
- package/dist/core/multi-agent/runtime.js +4 -4
- package/dist/core/multi-agent/topology.js +3 -3
- package/dist/core/pipeline/commit-gate.js +2 -1
- package/dist/core/pipeline/dispatch.js +18 -4
- package/dist/core/pipeline/drive-decide.js +2 -1
- package/dist/core/state/migrations.js +16 -1
- package/dist/core/state/state-explosion/digest.js +16 -15
- package/dist/core/state/state-explosion/graph.js +26 -19
- package/dist/core/state/state-explosion/helpers.js +2 -1
- package/dist/core/state/state-explosion/report.js +6 -6
- package/dist/core/trust/ledger.js +2 -1
- package/dist/core/types/execution-backend.js +18 -0
- package/dist/core/types/observability.js +7 -0
- package/dist/core/util/collate.js +23 -0
- package/dist/core/util/numeric-flag.js +40 -0
- package/dist/core/version.js +1 -1
- package/dist/mcp/server.js +99 -11
- package/dist/shell/audit-cli.js +99 -23
- package/dist/shell/commit-summary.js +2 -1
- package/dist/shell/coordinator-io.js +73 -13
- package/dist/shell/dispatch.js +1 -1
- package/dist/shell/doctor.js +80 -1
- package/dist/shell/drive.js +269 -59
- package/dist/shell/eval-text.js +2 -2
- package/dist/shell/evidence-reasoning.js +8 -7
- package/dist/shell/execution-backend/agent.js +20 -1
- package/dist/shell/execution-backend/container.js +4 -1
- package/dist/shell/execution-backend/local.js +4 -1
- package/dist/shell/execution-backend/registry.js +2 -1
- package/dist/shell/execution-backend/types.js +0 -9
- package/dist/shell/feedback-cli.js +6 -6
- package/dist/shell/fs-atomic.js +232 -30
- package/dist/shell/man-cli.js +6 -0
- package/dist/shell/metrics-cli.js +2 -1
- package/dist/shell/multi-agent-cli.js +367 -323
- package/dist/shell/multi-agent-host.js +9 -9
- package/dist/shell/multi-agent-operator-ux.js +82 -39
- package/dist/shell/node-store.js +10 -4
- package/dist/shell/observability.js +13 -12
- package/dist/shell/onramp.js +17 -1
- package/dist/shell/operator-ux-text.js +24 -23
- package/dist/shell/operator-ux.js +22 -20
- package/dist/shell/orchestrator.js +49 -38
- package/dist/shell/pipeline-cli.js +168 -111
- package/dist/shell/reclamation-io.js +16 -5
- package/dist/shell/registry-cli.js +19 -17
- package/dist/shell/remote-source.js +13 -8
- package/dist/shell/report-cli.js +45 -0
- package/dist/shell/report.js +4 -2
- package/dist/shell/run-registry-io.js +77 -19
- package/dist/shell/run-store.js +91 -2
- package/dist/shell/scheduling-io.js +12 -13
- package/dist/shell/state-cli.js +2 -7
- package/dist/shell/state-explosion-cli.js +19 -10
- package/dist/shell/topology-io.js +38 -6
- package/dist/shell/trust-audit.js +264 -23
- package/dist/shell/trust-policy-io.js +1 -1
- package/dist/shell/worker-cli.js +41 -29
- package/dist/shell/worker-isolation.js +34 -9
- package/dist/shell/workflow-app-loader.js +3 -2
- package/dist/wiring/capability-table/basics.js +91 -0
- package/dist/wiring/capability-table/exec-backend.js +171 -0
- package/dist/wiring/capability-table/index.js +42 -0
- package/dist/wiring/capability-table/multi-agent.js +630 -0
- package/dist/wiring/capability-table/parity.js +467 -0
- package/dist/wiring/capability-table/pipeline.js +292 -0
- package/dist/wiring/capability-table/registry-core.js +208 -0
- package/dist/wiring/capability-table/reporting.js +435 -0
- package/dist/wiring/capability-table/scheduling-registry.js +592 -0
- package/dist/wiring/capability-table/state.js +181 -0
- package/dist/wiring/capability-table/trust-ledger.js +158 -0
- package/dist/wiring/capability-table/workflow-apps.js +381 -0
- package/docs/agent-delegation-drive.7.md +4 -0
- package/docs/candidate-scoring.7.md +1 -1
- package/docs/canonical-workflow-apps.7.md +7 -7
- package/docs/cli-mcp-parity.7.md +13 -3
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- package/docs/coordinator-blackboard.7.md +17 -17
- package/docs/dogfood-one-real-repo.7.md +11 -11
- package/docs/durable-state-and-locking.7.md +24 -0
- package/docs/end-to-end-golden-path.7.md +14 -14
- package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
- package/docs/execution-backends.7.md +4 -0
- package/docs/getting-started.md +37 -37
- package/docs/index.md +1 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +21 -17
- package/docs/multi-agent-eval-replay-harness.7.md +17 -13
- package/docs/multi-agent-operator-ux.7.md +23 -19
- package/docs/multi-agent-runtime-core.7.md +22 -22
- package/docs/multi-agent-topologies.7.md +6 -6
- package/docs/multi-agent-trust-policy-audit.7.md +11 -11
- package/docs/node-snapshot-diff-replay.7.md +4 -0
- package/docs/observability-cost-accounting.7.md +4 -0
- package/docs/operator-ux.7.md +34 -34
- package/docs/pipeline-runner.7.md +4 -4
- package/docs/project-index.md +48 -5
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +5 -1
- package/docs/release-tooling.7.md +4 -0
- package/docs/routines.md +4 -4
- package/docs/run-registry-control-plane.7.md +23 -19
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/scheduled-tasks.md +14 -14
- package/docs/security-trust-hardening.7.md +43 -13
- package/docs/state-explosion-management.7.md +14 -10
- package/docs/team-collaboration.7.md +4 -0
- package/docs/trust-audit-anchor.7.md +71 -0
- package/docs/unix-principles.md +3 -1
- package/docs/verifier-gated-commit.7.md +1 -1
- package/docs/web-desktop-workbench.7.md +4 -0
- package/docs/workflow-app-framework.7.md +13 -13
- package/manifest/plugin.manifest.json +1 -1
- package/package.json +4 -2
- package/scripts/agents/claude-p-agent.js +2 -2
- package/scripts/block-unapproved-tag.sh +23 -2
- package/scripts/bump-version.js +24 -2
- package/scripts/canonical-apps.js +4 -4
- package/scripts/children/batch-delegate-child.js +52 -2
- package/scripts/dogfood-release.js +1 -1
- package/scripts/fake-date-for-reproduction.js +44 -0
- package/scripts/golden-path.js +4 -4
- package/scripts/purity-baseline.json +71 -0
- package/scripts/purity-gate.js +239 -0
- package/scripts/release-check.js +8 -1
- package/scripts/release-flow.js +57 -1
- package/scripts/verdict-keygen.js +83 -0
- package/scripts/verify-bump-reproduction.sh +148 -0
- package/scripts/verify-verdict-signature.js +61 -0
- package/scripts/version-sync-check.js +33 -12
- package/skills/cool-workflow/SKILL.md +9 -9
- package/skills/cool-workflow/references/commands.md +89 -88
- package/ui/workbench/app.css +37 -1
- package/ui/workbench/app.js +124 -6
- package/workflows/README.md +19 -0
|
@@ -20,7 +20,7 @@ const repoRoot = path.resolve(pluginRoot, "..", "..");
|
|
|
20
20
|
// CI checks out HEAD, so HEAD === the tree it is releasing.
|
|
21
21
|
//
|
|
22
22
|
// Fallback to the filesystem only when we cannot read from HEAD: not a git work
|
|
23
|
-
// tree, or the path is not tracked at HEAD
|
|
23
|
+
// tree, or the path is not tracked at HEAD.
|
|
24
24
|
// node + git only — no ripgrep (CI portability rule).
|
|
25
25
|
const insideGitWorkTree = (() => {
|
|
26
26
|
const r = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: repoRoot, encoding: "utf8" });
|
|
@@ -36,7 +36,7 @@ function readReleaseSource(relativePath) {
|
|
|
36
36
|
maxBuffer: 1024 * 1024 * 32
|
|
37
37
|
});
|
|
38
38
|
if (r.status === 0) return { text: r.stdout, exists: true, fromHead: true };
|
|
39
|
-
// Not tracked at HEAD — fall through to the working tree
|
|
39
|
+
// Not tracked at HEAD — fall through to the working tree.
|
|
40
40
|
}
|
|
41
41
|
const abs = path.join(repoRoot, relativePath);
|
|
42
42
|
if (!fs.existsSync(abs)) return { text: null, exists: false, fromHead: false };
|
|
@@ -56,9 +56,14 @@ const canonicalApps = CANONICAL_APP_IDS;
|
|
|
56
56
|
function main() {
|
|
57
57
|
const checks = [];
|
|
58
58
|
checkJson("plugins/cool-workflow/package.json", "version", VERSION, checks);
|
|
59
|
-
// package-lock.json is
|
|
60
|
-
//
|
|
59
|
+
// package-lock.json is tracked now, but the documented install still works
|
|
60
|
+
// without it (`npm install --no-package-lock`), so only validate it when
|
|
61
|
+
// present. Check BOTH version fields: the top-level one and the root-package
|
|
62
|
+
// entry packages[""].version — the second one is the field npm keeps in step
|
|
63
|
+
// with package.json on `npm install`, and it is the one that went stale
|
|
64
|
+
// (0.1.97) through the v0.2.0/v0.2.1 cuts while only the first was checked.
|
|
61
65
|
checkJsonIfPresent("plugins/cool-workflow/package-lock.json", "version", VERSION, checks);
|
|
66
|
+
checkNestedJsonIfPresent("plugins/cool-workflow/package-lock.json", ["packages", "", "version"], VERSION, checks);
|
|
62
67
|
checkJson("plugins/cool-workflow/.codex-plugin/plugin.json", "version", VERSION, checks);
|
|
63
68
|
checkJson("plugins/cool-workflow/server.json", "version", VERSION, checks);
|
|
64
69
|
checkNestedJson("plugins/cool-workflow/server.json", ["packages", 0, "version"], VERSION, checks);
|
|
@@ -160,7 +165,7 @@ function main() {
|
|
|
160
165
|
checkIncludes("plugins/cool-workflow/docs/run-retention-reclamation.7.md", VERSION, checks);
|
|
161
166
|
checkIncludes("plugins/cool-workflow/docs/index.md", "run-retention-reclamation.7.md", checks);
|
|
162
167
|
checkIncludes("plugins/cool-workflow/test/run-retention-reclamation-smoke.js", "run-retention-reclamation-smoke", checks);
|
|
163
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
168
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/scheduling-registry.ts", "gc.plan", checks);
|
|
164
169
|
checkIncludes("plugins/cool-workflow/docs/durable-state-and-locking.7.md", "Durable State & Locking", checks);
|
|
165
170
|
checkIncludes("plugins/cool-workflow/docs/durable-state-and-locking.7.md", VERSION, checks);
|
|
166
171
|
checkIncludes("plugins/cool-workflow/docs/index.md", "durable-state-and-locking.7.md", checks);
|
|
@@ -168,33 +173,37 @@ function main() {
|
|
|
168
173
|
checkIncludes("plugins/cool-workflow/src/shell/fs-atomic.ts", "withFileLock", checks);
|
|
169
174
|
checkIncludes("plugins/cool-workflow/src/shell/drive.ts", "driveStep", checks);
|
|
170
175
|
checkIncludes("plugins/cool-workflow/dist/shell/drive.js", "driveStep", checks);
|
|
171
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
176
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/pipeline.ts", "run.drive", checks);
|
|
172
177
|
checkIncludes("plugins/cool-workflow/src/shell/collaboration-io.ts", "deriveReviewState", checks);
|
|
173
178
|
checkIncludes("plugins/cool-workflow/dist/shell/collaboration-io.js", "deriveReviewState", checks);
|
|
174
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
179
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/multi-agent.ts", "review.status", checks);
|
|
175
180
|
checkIncludes("plugins/cool-workflow/src/shell/observability.ts", "deriveMetricsReport", checks);
|
|
176
181
|
checkIncludes("plugins/cool-workflow/dist/shell/observability.js", "deriveMetricsReport", checks);
|
|
177
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
182
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/reporting.ts", "metrics.show", checks);
|
|
178
183
|
checkIncludes("plugins/cool-workflow/manifest/pricing.policy.json", "schemaVersion", checks);
|
|
179
184
|
checkIncludes("plugins/cool-workflow/src/shell/workbench.ts", "buildWorkbenchRunView", checks);
|
|
180
185
|
checkIncludes("plugins/cool-workflow/dist/shell/workbench.js", "buildWorkbenchRunView", checks);
|
|
181
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
186
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/reporting.ts", "workbench.view", checks);
|
|
182
187
|
checkIncludes("plugins/cool-workflow/src/shell/execution-backend/registry.ts", "ExecutionBackend", checks);
|
|
183
188
|
checkIncludes("plugins/cool-workflow/dist/shell/execution-backend/registry.js", "ExecutionBackend", checks);
|
|
184
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
189
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/exec-backend.ts", "backend.list", checks);
|
|
185
190
|
checkIncludes("plugins/cool-workflow/src/shell/run-registry-io.ts", "RunRegistry", checks);
|
|
186
191
|
checkIncludes("plugins/cool-workflow/dist/shell/run-registry-io.js", "RunRegistry", checks);
|
|
187
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
192
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/scheduling-registry.ts", "registry.refresh", checks);
|
|
188
193
|
checkIncludes("plugins/cool-workflow/package.json", "parity:check", checks);
|
|
189
194
|
checkIncludes("plugins/cool-workflow/scripts/parity-check.js", "buildParityReport", checks);
|
|
190
195
|
checkIncludes("plugins/cool-workflow/test/cli-mcp-parity-smoke.js", "cli-mcp-parity-smoke", checks);
|
|
191
|
-
checkIncludes("plugins/cool-workflow/src/
|
|
196
|
+
checkIncludes("plugins/cool-workflow/src/wiring/capability-table/registry-core.ts", "export const REGISTRY", checks);
|
|
192
197
|
checkIncludes("plugins/cool-workflow/src/shell/pipeline-cli.ts", "planSummary", checks);
|
|
193
198
|
checkIncludes("plugins/cool-workflow/dist/core/capability-table.js", "REGISTRY", checks);
|
|
194
199
|
checkIncludes("plugins/cool-workflow/docs/multi-agent-runtime-core.7.md", "Multi-Agent Runtime Core", checks);
|
|
195
200
|
checkIncludes("plugins/cool-workflow/docs/dogfood-one-real-repo.7.md", "Dogfood One Real Repo", checks);
|
|
196
201
|
checkIncludes("plugins/cool-workflow/docs/getting-started.md", "npm run release:check", checks);
|
|
197
202
|
checkIncludes("plugins/cool-workflow/package.json", "eval:replay", checks);
|
|
203
|
+
checkIncludes("plugins/cool-workflow/docs/trust-audit-anchor.7.md", "Trust Audit Anchor", checks);
|
|
204
|
+
checkIncludes("plugins/cool-workflow/docs/trust-audit-anchor.7.md", VERSION, checks);
|
|
205
|
+
checkIncludes("plugins/cool-workflow/docs/index.md", "trust-audit-anchor.7.md", checks);
|
|
206
|
+
checkIncludes("plugins/cool-workflow/test/trust-audit-anchor-smoke.js", "trust-audit-anchor-smoke", checks);
|
|
198
207
|
checkIncludes("plugins/cool-workflow/docs/release-and-migration.7.md", VERSION, checks);
|
|
199
208
|
checkIncludes("CHANGELOG.md", `## ${VERSION}`, checks);
|
|
200
209
|
checkIncludes("RELEASE.md", VERSION, checks);
|
|
@@ -227,6 +236,18 @@ function checkNestedJson(relativePath, keyPath, expected, checks) {
|
|
|
227
236
|
checks.push({ path: relativePath, key: keyPath.join("."), value });
|
|
228
237
|
}
|
|
229
238
|
|
|
239
|
+
function checkNestedJsonIfPresent(relativePath, keyPath, expected, checks) {
|
|
240
|
+
const src = readReleaseSource(relativePath);
|
|
241
|
+
if (!src.exists) {
|
|
242
|
+
checks.push({ path: relativePath, key: keyPath.join("."), skipped: "absent" });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
let value = JSON.parse(src.text);
|
|
246
|
+
for (const key of keyPath) value = value?.[key];
|
|
247
|
+
assert.equal(value, expected, `${relativePath}.${keyPath.join(".")} must be ${expected}`);
|
|
248
|
+
checks.push({ path: relativePath, key: keyPath.join("."), value });
|
|
249
|
+
}
|
|
250
|
+
|
|
230
251
|
function checkJsonIfPresent(relativePath, key, expected, checks) {
|
|
231
252
|
const src = readReleaseSource(relativePath);
|
|
232
253
|
if (!src.exists) {
|
|
@@ -62,16 +62,16 @@ Use this loop to explain workflow progress when reporting status.
|
|
|
62
62
|
## Operating Loop
|
|
63
63
|
|
|
64
64
|
1. Pick or create a workflow.
|
|
65
|
-
2. `
|
|
65
|
+
2. `cw plan <workflow-id> ...` from the plugin root (or the
|
|
66
66
|
absolute plugin script path).
|
|
67
|
-
3. `
|
|
67
|
+
3. `cw dispatch <run-id> --limit N` to create a dispatch
|
|
68
68
|
manifest for the current phase. Add `--sandbox <profile-id>` when an explicit
|
|
69
69
|
worker policy profile is needed.
|
|
70
70
|
4. If — and only if — the user explicitly asked for agents, spawn one subagent
|
|
71
71
|
per dispatched task with disjoint scopes.
|
|
72
72
|
5. Save each subagent summary to `.cw/runs/<run-id>/results/<task-id>.md`.
|
|
73
|
-
6. `
|
|
74
|
-
7. When all required work is complete, `
|
|
73
|
+
6. `cw result <run-id> <task-id> <result-file>`.
|
|
74
|
+
7. When all required work is complete, `cw report <run-id>`.
|
|
75
75
|
8. Synthesize the final user-facing answer from the report and verified
|
|
76
76
|
evidence.
|
|
77
77
|
|
|
@@ -114,11 +114,11 @@ report chain. See `references/commands.md` for the exact invocations.
|
|
|
114
114
|
## Essential Commands
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
cw list
|
|
118
|
+
cw plan architecture-review --repo /path/to/repo --question "Is this architecture sound?"
|
|
119
|
+
cw dispatch <run-id> --limit 6
|
|
120
|
+
cw result <run-id> <task-id> /path/to/result.md
|
|
121
|
+
cw report <run-id> --show
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
When working in this repository, the plugin root is `plugins/cool-workflow`.
|
|
@@ -26,19 +26,20 @@ absolute plugin script path. Run data is written to `.cw/runs/<run-id>/` under
|
|
|
26
26
|
## Discovery & apps
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
cw list
|
|
30
|
+
cw search architecture
|
|
31
|
+
cw app list
|
|
32
|
+
cw app show architecture-review
|
|
33
|
+
cw app show pr-review-fix-ci
|
|
34
|
+
cw app show release-cut
|
|
35
|
+
cw app show research-synthesis
|
|
36
|
+
cw app validate apps/architecture-review/app.json
|
|
37
|
+
cw app show workflow-app-framework-demo
|
|
38
|
+
cw app validate apps/workflow-app-framework-demo/app.json
|
|
39
|
+
cw app validate end-to-end-golden-path
|
|
40
|
+
cw app package workflow-app-framework-demo
|
|
41
|
+
cw app init my-app --title "My App"
|
|
42
|
+
cw init my-workflow --title "My Workflow"
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
The canonical app ids are `architecture-review`, `pr-review-fix-ci`,
|
|
@@ -62,16 +63,16 @@ harness; the reviewer is delegated via `CW_AGENT_COMMAND`/`CW_AGENT_ENDPOINT`
|
|
|
62
63
|
## Plan / dispatch / result / report
|
|
63
64
|
|
|
64
65
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
cw plan architecture-review --repo /path/to/repo --question "Is this architecture sound?"
|
|
67
|
+
cw status <run-id>
|
|
68
|
+
cw status <run-id> --json
|
|
69
|
+
cw graph <run-id>
|
|
70
|
+
cw graph <run-id> --json
|
|
71
|
+
cw dispatch <run-id> --limit 6
|
|
72
|
+
cw dispatch <run-id> --sandbox readonly
|
|
73
|
+
cw result <run-id> <task-id> /path/to/result.md
|
|
74
|
+
cw report <run-id>
|
|
75
|
+
cw report <run-id> --show
|
|
75
76
|
```
|
|
76
77
|
|
|
77
78
|
Operator UX is human-readable by default for `status`, `graph`, report
|
|
@@ -87,12 +88,12 @@ role, group, fanout/fanin, blackboard, coordinator, candidate, commit, and audit
|
|
|
87
88
|
records — deterministic recipes, not hidden autonomous coordination.
|
|
88
89
|
|
|
89
90
|
```bash
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
cw topology list
|
|
92
|
+
cw topology show map-reduce
|
|
93
|
+
cw topology validate map-reduce
|
|
94
|
+
cw topology apply <run-id> map-reduce --task task-id --mapper-count 2
|
|
95
|
+
cw topology summary <run-id>
|
|
96
|
+
cw topology graph <run-id>
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
## Multi-agent host surface
|
|
@@ -103,22 +104,22 @@ plumbing. It wraps the topology, multi-agent, blackboard, candidate, commit, and
|
|
|
103
104
|
audit primitives; it does not replace them.
|
|
104
105
|
|
|
105
106
|
```bash
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
cw multi-agent run <run-id> --topology judge-panel --task task-id
|
|
108
|
+
cw multi-agent status <run-id>
|
|
109
|
+
cw multi-agent step <run-id> --sandbox readonly
|
|
110
|
+
cw multi-agent blackboard <run-id> summary
|
|
111
|
+
cw multi-agent score <run-id> candidate-id --criterion correctness=1 --evidence ref
|
|
112
|
+
cw multi-agent select <run-id> candidate-id --reason "verified winner"
|
|
112
113
|
```
|
|
113
114
|
|
|
114
115
|
Operator views (who depends on whom, who is blocked, which evidence was adopted):
|
|
115
116
|
|
|
116
117
|
```bash
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
cw multi-agent summary <run-id>
|
|
119
|
+
cw multi-agent graph <run-id>
|
|
120
|
+
cw multi-agent dependencies <run-id>
|
|
121
|
+
cw multi-agent failures <run-id>
|
|
122
|
+
cw multi-agent evidence <run-id>
|
|
122
123
|
```
|
|
123
124
|
|
|
124
125
|
State Explosion Management — when a run grows too large to read, use derived,
|
|
@@ -126,11 +127,11 @@ provenance-backed digests (they never delete raw records and fail closed when
|
|
|
126
127
|
stale; every synthetic node carries source ids and an expansion command):
|
|
127
128
|
|
|
128
129
|
```bash
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
cw summary refresh <run-id>
|
|
131
|
+
cw summary show <run-id>
|
|
132
|
+
cw blackboard summarize <run-id>
|
|
133
|
+
cw multi-agent summarize <run-id>
|
|
134
|
+
cw multi-agent graph <run-id> --view compact|critical-path|failures|... [--focus <id>] [--depth <n>]
|
|
134
135
|
```
|
|
135
136
|
|
|
136
137
|
Trust / Policy / Audit — inspect role authority, message provenance, blackboard
|
|
@@ -138,11 +139,11 @@ write decisions, judge rationale, panel decisions, and why a result is trusted
|
|
|
138
139
|
(missing policy/evidence/provenance/rationale fail closed):
|
|
139
140
|
|
|
140
141
|
```bash
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
cw audit multi-agent <run-id>
|
|
143
|
+
cw audit policy <run-id>
|
|
144
|
+
cw audit role <run-id>
|
|
145
|
+
cw audit blackboard <run-id>
|
|
146
|
+
cw audit judge <run-id>
|
|
146
147
|
```
|
|
147
148
|
|
|
148
149
|
## Multi-agent low-level state
|
|
@@ -154,12 +155,12 @@ transitions, duplicate memberships, ambiguous dispatch attachment, and missing
|
|
|
154
155
|
fanin evidence fail closed.
|
|
155
156
|
|
|
156
157
|
```bash
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
158
|
+
cw multi-agent run <run-id> --id ma --objective "coordinated work"
|
|
159
|
+
cw multi-agent role <run-id> role --multi-agent-run ma --responsibility "do work" --required-evidence "result evidence"
|
|
160
|
+
cw multi-agent group <run-id> group --multi-agent-run ma --task task-id
|
|
161
|
+
cw multi-agent fanout <run-id> fanout --group group --reason "split work" --role role --task task-id
|
|
162
|
+
cw dispatch <run-id> --multi-agent-run ma --multi-agent-group group --multi-agent-role role --multi-agent-fanout fanout
|
|
163
|
+
cw multi-agent fanin <run-id> fanin --group group --fanout fanout --required-role role
|
|
163
164
|
```
|
|
164
165
|
|
|
165
166
|
## Eval & replay
|
|
@@ -168,12 +169,12 @@ Use when a topology-backed multi-agent run needs release-gate evidence.
|
|
|
168
169
|
Artifacts live under `.cw/evals/<suite-id>/` as plain JSON plus `report.md`.
|
|
169
170
|
|
|
170
171
|
```bash
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
cw eval snapshot <run-id> --id suite-id
|
|
173
|
+
cw eval replay .cw/evals/suite-id/snapshot.json
|
|
174
|
+
cw eval compare .cw/evals/suite-id/snapshot.json .cw/evals/suite-id/replay-run.json
|
|
175
|
+
cw eval score .cw/evals/suite-id/replay-run.json
|
|
176
|
+
cw eval gate .cw/evals/suite-id
|
|
177
|
+
cw eval report .cw/evals/suite-id/replay-run.json
|
|
177
178
|
```
|
|
178
179
|
|
|
179
180
|
## Blackboard & coordinator
|
|
@@ -183,14 +184,14 @@ context frames, artifact refs, snapshots, and coordinator decisions under
|
|
|
183
184
|
`.cw/runs/<run-id>/blackboard/`.
|
|
184
185
|
|
|
185
186
|
```bash
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
cw blackboard summary <run-id>
|
|
188
|
+
cw blackboard topic create <run-id> --id topic --title "Shared context"
|
|
189
|
+
cw blackboard message post <run-id> --topic topic --body "message"
|
|
190
|
+
cw blackboard context put <run-id> --topic topic --kind fact --key finding --value "evidence-backed fact"
|
|
191
|
+
cw blackboard artifact add <run-id> --topic topic --path /path/to/result.md --kind worker-result
|
|
192
|
+
cw blackboard snapshot <run-id>
|
|
193
|
+
cw coordinator summary <run-id>
|
|
194
|
+
cw coordinator decision <run-id> --kind conflict-resolution --outcome accepted --reason "evidence supports this"
|
|
194
195
|
```
|
|
195
196
|
|
|
196
197
|
## Sandbox profiles
|
|
@@ -201,10 +202,10 @@ CW enforces profile validation and worker result acceptance; the agent host
|
|
|
201
202
|
enforces OS/process/network/environment controls.
|
|
202
203
|
|
|
203
204
|
```bash
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
cw sandbox list
|
|
206
|
+
cw sandbox show readonly
|
|
207
|
+
cw sandbox validate ./site-sandbox.json
|
|
208
|
+
cw worker manifest <run-id> <worker-id>
|
|
208
209
|
```
|
|
209
210
|
|
|
210
211
|
## Commit, state & summaries
|
|
@@ -214,14 +215,14 @@ dry-runs migration and normalization; newer unsupported schemas fail closed and
|
|
|
214
215
|
unknown user data is preserved.
|
|
215
216
|
|
|
216
217
|
```bash
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
cw commit <run-id> --verifier <node-id> --reason "verified result"
|
|
219
|
+
cw commit <run-id> --selection <selection-id> --reason "verified winner"
|
|
220
|
+
cw commit <run-id> --allow-unverified-checkpoint --reason "manual checkpoint"
|
|
221
|
+
cw worker summary <run-id>
|
|
222
|
+
cw candidate summary <run-id>
|
|
223
|
+
cw feedback summary <run-id>
|
|
224
|
+
cw commit summary <run-id>
|
|
225
|
+
cw state check <run-id>
|
|
225
226
|
```
|
|
226
227
|
|
|
227
228
|
## Scheduling & routines
|
|
@@ -232,12 +233,12 @@ prompt is handled. `routine create`/`routine fire` handle API/GitHub trigger
|
|
|
232
233
|
events.
|
|
233
234
|
|
|
234
235
|
```bash
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
236
|
+
cw loop --intervalMinutes 30 --prompt "Continue this workflow."
|
|
237
|
+
cw schedule create --kind loop --intervalMinutes 30 --prompt "Continue this workflow."
|
|
238
|
+
cw schedule due
|
|
239
|
+
cw schedule daemon --once
|
|
240
|
+
cw routine create --kind github --prompt "Handle this GitHub event."
|
|
241
|
+
cw routine fire github payload.json
|
|
241
242
|
```
|
|
242
243
|
|
|
243
244
|
## Release & maintenance npm scripts
|
package/ui/workbench/app.css
CHANGED
|
@@ -12,6 +12,20 @@
|
|
|
12
12
|
--absent: #d29922;
|
|
13
13
|
--bad: #f85149;
|
|
14
14
|
}
|
|
15
|
+
@media (prefers-color-scheme: light) {
|
|
16
|
+
:root {
|
|
17
|
+
--bg: #f6f7f9;
|
|
18
|
+
--panel: #ffffff;
|
|
19
|
+
--panel-2: #eef0f4;
|
|
20
|
+
--ink: #1b1f27;
|
|
21
|
+
--muted: #5b6472;
|
|
22
|
+
--line: #d7dce4;
|
|
23
|
+
--accent: #1a6fd6;
|
|
24
|
+
--present: #1a7f37;
|
|
25
|
+
--absent: #9a6700;
|
|
26
|
+
--bad: #cf222e;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
15
29
|
* { box-sizing: border-box; }
|
|
16
30
|
body {
|
|
17
31
|
margin: 0;
|
|
@@ -45,8 +59,17 @@ input[type="search"] {
|
|
|
45
59
|
}
|
|
46
60
|
.run-list li:hover { border-color: var(--accent); }
|
|
47
61
|
.run-list li.active { border-color: var(--accent); background: var(--panel-2); }
|
|
48
|
-
.run-list .rid { font-family: ui-monospace, monospace; font-size: 12px; }
|
|
62
|
+
.run-list .rid { font-family: ui-monospace, monospace; font-size: 12px; display: flex; align-items: center; gap: 6px; }
|
|
49
63
|
.run-list .meta { color: var(--muted); font-size: 11px; margin-top: 2px; }
|
|
64
|
+
.status-dot {
|
|
65
|
+
display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: none;
|
|
66
|
+
background: var(--muted);
|
|
67
|
+
}
|
|
68
|
+
.status-dot.running { background: var(--accent); }
|
|
69
|
+
.status-dot.completed { background: var(--present); }
|
|
70
|
+
.status-dot.queued, .status-dot.archived, .status-dot.reclaimed { background: var(--muted); }
|
|
71
|
+
.status-dot.blocked { background: var(--absent); }
|
|
72
|
+
.status-dot.failed { background: var(--bad); }
|
|
50
73
|
.detail { overflow-y: auto; padding: 16px 20px; }
|
|
51
74
|
.detail .empty { color: var(--muted); }
|
|
52
75
|
.tabs { display: flex; gap: 6px; flex-wrap: wrap; border-bottom: 1px solid var(--line); padding-bottom: 8px; margin-bottom: 12px; }
|
|
@@ -74,3 +97,16 @@ pre.json {
|
|
|
74
97
|
.kv { display: flex; gap: 16px; flex-wrap: wrap; padding: 8px 12px; font-size: 12px; color: var(--muted); }
|
|
75
98
|
.kv b { color: var(--ink); font-weight: 600; }
|
|
76
99
|
.err { color: var(--bad); }
|
|
100
|
+
.struct-block { padding: 10px 12px; border-top: 1px solid var(--line); }
|
|
101
|
+
.struct-block:first-child { border-top: none; }
|
|
102
|
+
.struct-block .struct-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 6px; }
|
|
103
|
+
.struct-table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
104
|
+
.struct-table th, .struct-table td {
|
|
105
|
+
text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--line);
|
|
106
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; vertical-align: top;
|
|
107
|
+
}
|
|
108
|
+
.struct-table th { color: var(--muted); font-weight: 400; }
|
|
109
|
+
.struct-edges { list-style: none; margin: 0; padding: 0; font-size: 12px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
110
|
+
.struct-edges li { padding: 3px 0; }
|
|
111
|
+
.struct-edges .arrow { color: var(--muted); padding: 0 6px; }
|
|
112
|
+
.struct-empty { color: var(--muted); font-size: 12px; }
|
package/ui/workbench/app.js
CHANGED
|
@@ -62,20 +62,22 @@ async function loadIndex() {
|
|
|
62
62
|
const reg = view.registry || {};
|
|
63
63
|
const fresh = document.getElementById("registry-freshness");
|
|
64
64
|
fresh.innerHTML = "";
|
|
65
|
-
fresh.append("registry ", freshnessBadge(reg.freshness), ` · scope ${view.scope}`);
|
|
65
|
+
fresh.append("registry ", freshnessBadge(reg.freshness && reg.freshness.status), ` · scope ${view.scope}`);
|
|
66
66
|
const records = (view.runs && view.runs.records) || [];
|
|
67
67
|
if (!records.length) {
|
|
68
68
|
list.appendChild(el("li", { class: "muted", text: "no runs indexed in this scope" }));
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
for (const record of records) {
|
|
72
|
+
const lifecycle = record.lifecycle || record.status || "";
|
|
72
73
|
const li = el("li", { class: state.activeRunId === record.runId ? "active" : "" }, [
|
|
73
|
-
el("div", { class: "rid"
|
|
74
|
+
el("div", { class: "rid" }, [
|
|
75
|
+
el("span", { class: `status-dot ${lifecycle}`, title: lifecycle || "unknown" }),
|
|
76
|
+
document.createTextNode(record.runId)
|
|
77
|
+
]),
|
|
74
78
|
el("div", {
|
|
75
79
|
class: "meta",
|
|
76
|
-
text: [record.appId || record.workflowId,
|
|
77
|
-
.filter(Boolean)
|
|
78
|
-
.join(" · ")
|
|
80
|
+
text: [record.appId || record.workflowId, lifecycle, record.repo].filter(Boolean).join(" · ")
|
|
79
81
|
})
|
|
80
82
|
]);
|
|
81
83
|
li.addEventListener("click", () => selectRun(record.runId));
|
|
@@ -138,13 +140,129 @@ function renderPanel(name, panel) {
|
|
|
138
140
|
card.appendChild(head);
|
|
139
141
|
card.appendChild(el("div", { class: "kv" }, [el("span", { class: "src", text: panel.cli }), el("span", { class: "src", text: panel.mcp })]));
|
|
140
142
|
if (panel.status === "present") {
|
|
141
|
-
card.appendChild(el("pre", { class: "json", text: JSON.stringify(panel.data, null, 2) }));
|
|
143
|
+
card.appendChild(renderStructured(panel.data) || el("pre", { class: "json", text: JSON.stringify(panel.data, null, 2) }));
|
|
142
144
|
} else {
|
|
143
145
|
card.appendChild(el("div", { class: "absent-note", text: `absent — ${panel.error || "source unreadable"}` }));
|
|
144
146
|
}
|
|
145
147
|
return card;
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
// Purely presentational shape-detection: recognizes the two payload shapes
|
|
151
|
+
// that recur across several capabilities (a nodes/edges graph, and one or
|
|
152
|
+
// more TrustAuditEvent[] arrays) and tables them instead of dumping raw
|
|
153
|
+
// JSON. Anything that doesn't match either shape falls back to the plain
|
|
154
|
+
// JSON dump in renderPanel — no per-capability special-casing.
|
|
155
|
+
function isNodeEdgeGraph(data) {
|
|
156
|
+
return !!data && Array.isArray(data.nodes) && Array.isArray(data.edges);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isEventArray(value) {
|
|
160
|
+
return (
|
|
161
|
+
Array.isArray(value) &&
|
|
162
|
+
value.length > 0 &&
|
|
163
|
+
value.every((item) => item && typeof item === "object" && typeof item.kind === "string" && typeof item.decision === "string")
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function renderStructured(data) {
|
|
168
|
+
if (isNodeEdgeGraph(data)) return renderGraph(data);
|
|
169
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
170
|
+
const eventKeys = Object.keys(data).filter((key) => isEventArray(data[key]));
|
|
171
|
+
if (eventKeys.length > 0) return renderEventGroups(data, eventKeys);
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function renderGraph(data) {
|
|
177
|
+
const wrap = el("div");
|
|
178
|
+
const nodesBlock = el("div", { class: "struct-block" }, [el("div", { class: "struct-title", text: `nodes (${data.nodes.length})` })]);
|
|
179
|
+
if (data.nodes.length === 0) {
|
|
180
|
+
nodesBlock.appendChild(el("div", { class: "struct-empty", text: "none" }));
|
|
181
|
+
} else {
|
|
182
|
+
const table = el("table", { class: "struct-table" }, [
|
|
183
|
+
el("tr", {}, ["id", "kind", "status", "label"].map((h) => el("th", { text: h })))
|
|
184
|
+
]);
|
|
185
|
+
for (const node of data.nodes) {
|
|
186
|
+
table.appendChild(
|
|
187
|
+
el("tr", {}, [
|
|
188
|
+
el("td", { text: node.id }),
|
|
189
|
+
el("td", { text: node.kind }),
|
|
190
|
+
el("td", { text: node.status }),
|
|
191
|
+
el("td", { text: node.label })
|
|
192
|
+
])
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
nodesBlock.appendChild(table);
|
|
196
|
+
}
|
|
197
|
+
wrap.appendChild(nodesBlock);
|
|
198
|
+
|
|
199
|
+
const edgesBlock = el("div", { class: "struct-block" }, [el("div", { class: "struct-title", text: `edges (${data.edges.length})` })]);
|
|
200
|
+
if (data.edges.length === 0) {
|
|
201
|
+
edgesBlock.appendChild(el("div", { class: "struct-empty", text: "none" }));
|
|
202
|
+
} else {
|
|
203
|
+
const list = el("ul", { class: "struct-edges" });
|
|
204
|
+
for (const edge of data.edges) {
|
|
205
|
+
list.appendChild(
|
|
206
|
+
el("li", {}, [
|
|
207
|
+
document.createTextNode(edge.from),
|
|
208
|
+
el("span", { class: "arrow", text: edge.label ? `--${edge.label}-->` : "-->" }),
|
|
209
|
+
document.createTextNode(edge.to)
|
|
210
|
+
])
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
edgesBlock.appendChild(list);
|
|
214
|
+
}
|
|
215
|
+
wrap.appendChild(edgesBlock);
|
|
216
|
+
return wrap;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function humanizeKey(key) {
|
|
220
|
+
return key.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function renderEventGroups(data, confirmedEventKeys) {
|
|
224
|
+
// At least one sibling array on this object is confirmed TrustAuditEvent-
|
|
225
|
+
// shaped -- so its OTHER array fields that happen to be empty (e.g. a
|
|
226
|
+
// healthy `policyViolations: []`) are almost certainly the same family
|
|
227
|
+
// and read better as their own "(0)" table than buried in the raw
|
|
228
|
+
// "other fields" JSON below. An empty array can't self-identify by
|
|
229
|
+
// content, so this only widens the match within an already-confirmed
|
|
230
|
+
// object, never anywhere else.
|
|
231
|
+
const eventKeys = Object.keys(data).filter(
|
|
232
|
+
(key) => confirmedEventKeys.includes(key) || (Array.isArray(data[key]) && data[key].length === 0)
|
|
233
|
+
);
|
|
234
|
+
const wrap = el("div");
|
|
235
|
+
for (const key of eventKeys) {
|
|
236
|
+
const events = [...data[key]].sort((a, b) => String(a.createdAt || "").localeCompare(String(b.createdAt || "")));
|
|
237
|
+
const block = el("div", { class: "struct-block" }, [el("div", { class: "struct-title", text: `${humanizeKey(key)} (${events.length})` })]);
|
|
238
|
+
const table = el("table", { class: "struct-table" }, [
|
|
239
|
+
el("tr", {}, ["time", "kind", "decision", "source", "actor"].map((h) => el("th", { text: h })))
|
|
240
|
+
]);
|
|
241
|
+
for (const event of events) {
|
|
242
|
+
table.appendChild(
|
|
243
|
+
el("tr", {}, [
|
|
244
|
+
el("td", { text: event.createdAt || "" }),
|
|
245
|
+
el("td", { text: event.kind || "" }),
|
|
246
|
+
el("td", { text: event.decision || "" }),
|
|
247
|
+
el("td", { text: event.source || "" }),
|
|
248
|
+
el("td", { text: event.actor || event.workerId || event.taskId || "" })
|
|
249
|
+
])
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
block.appendChild(table);
|
|
253
|
+
wrap.appendChild(block);
|
|
254
|
+
}
|
|
255
|
+
const rest = Object.keys(data).filter((key) => !eventKeys.includes(key) && key !== "schemaVersion" && key !== "runId");
|
|
256
|
+
const restData = {};
|
|
257
|
+
for (const key of rest) restData[key] = data[key];
|
|
258
|
+
if (Object.keys(restData).length > 0) {
|
|
259
|
+
const block = el("div", { class: "struct-block" }, [el("div", { class: "struct-title", text: "other fields" })]);
|
|
260
|
+
block.appendChild(el("pre", { class: "json", text: JSON.stringify(restData, null, 2) }));
|
|
261
|
+
wrap.appendChild(block);
|
|
262
|
+
}
|
|
263
|
+
return wrap;
|
|
264
|
+
}
|
|
265
|
+
|
|
148
266
|
document.getElementById("refresh").addEventListener("click", loadIndex);
|
|
149
267
|
document.getElementById("filter").addEventListener("input", debounce(loadIndex, 200));
|
|
150
268
|
|