cool-workflow 0.1.98 → 0.2.1
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/README.md +18 -7
- package/apps/architecture-review/app.json +2 -2
- package/apps/architecture-review/workflow.js +12 -12
- 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 +236 -0
- package/dist/cli/entry.js +120 -0
- package/dist/cli/io.js +21 -4
- package/dist/cli/parseargv.js +157 -0
- package/dist/cli.js +6 -33
- package/dist/core/capability-table.js +3518 -0
- package/dist/core/format/help.js +314 -0
- package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
- package/dist/core/hash.js +137 -0
- package/dist/core/multi-agent/candidate-scoring.js +219 -0
- package/dist/core/multi-agent/collaboration.js +481 -0
- package/dist/core/multi-agent/coordinator.js +515 -0
- package/dist/core/multi-agent/eval-replay.js +306 -0
- package/dist/core/multi-agent/runtime.js +929 -0
- package/dist/core/multi-agent/topology.js +298 -0
- package/dist/core/multi-agent/trust-policy.js +197 -0
- package/dist/core/pipeline/commit-gate.js +320 -0
- package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
- package/dist/core/pipeline/dispatch.js +103 -0
- package/dist/core/pipeline/drive-decide.js +227 -0
- package/dist/core/pipeline/error-feedback.js +161 -0
- package/dist/core/pipeline/loop-expansion.js +124 -0
- package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
- package/dist/core/pipeline/runner.js +230 -0
- package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
- package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
- package/dist/core/state/node-projection.js +95 -0
- package/dist/core/state/node-snapshot.js +230 -0
- package/dist/core/state/run-paths.js +93 -0
- package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
- package/dist/core/state/schema.js +50 -0
- package/dist/core/state/state-explosion/digest.js +243 -0
- package/dist/core/state/state-explosion/graph.js +527 -0
- package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
- package/dist/core/state/state-explosion/report.js +187 -0
- package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
- package/dist/{state-node.js → core/state/state-node.js} +90 -113
- package/dist/core/state/types.js +19 -0
- package/dist/{validation.js → core/state/validation.js} +64 -131
- package/dist/core/trust/evidence-grounding.js +134 -0
- package/dist/core/trust/ledger.js +199 -0
- package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
- package/dist/core/trust/telemetry-ledger.js +127 -0
- package/dist/core/types.js +20 -0
- package/dist/core/version.js +16 -0
- package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
- package/dist/mcp/dispatch.js +104 -0
- package/dist/mcp/server.js +144 -0
- package/dist/mcp-server.js +6 -84
- package/dist/{agent-config.js → shell/agent-config.js} +118 -71
- package/dist/shell/app-run-cli.js +88 -0
- package/dist/shell/audit-cli.js +259 -0
- package/dist/shell/audit-provenance.js +83 -0
- package/dist/shell/candidate-scoring-io.js +459 -0
- package/dist/shell/collaboration-io.js +264 -0
- package/dist/shell/commit-summary.js +104 -0
- package/dist/shell/commit.js +290 -0
- package/dist/shell/coordinator-io.js +476 -0
- package/dist/shell/demo-cli.js +19 -0
- package/dist/shell/dispatch.js +162 -0
- package/dist/shell/doctor.js +292 -0
- package/dist/shell/drive.js +885 -0
- package/dist/shell/error-feedback-io.js +305 -0
- package/dist/shell/eval-io.js +473 -0
- package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
- package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
- package/dist/shell/exec-backend-cli.js +88 -0
- package/dist/shell/execution-backend/agent.js +507 -0
- package/dist/shell/execution-backend/ci.js +15 -0
- package/dist/shell/execution-backend/container.js +69 -0
- package/dist/shell/execution-backend/envelopes.js +55 -0
- package/dist/shell/execution-backend/local.js +113 -0
- package/dist/shell/execution-backend/probes.js +175 -0
- package/dist/shell/execution-backend/registry.js +402 -0
- package/dist/shell/execution-backend/remote.js +128 -0
- package/dist/shell/execution-backend/types.js +11 -0
- package/dist/shell/feedback-cli.js +81 -0
- package/dist/shell/feedback-operations.js +48 -0
- package/dist/shell/fs-atomic.js +276 -0
- package/dist/shell/harness.js +98 -0
- package/dist/shell/ledger-cli.js +212 -0
- package/dist/shell/ledger-io.js +169 -0
- package/dist/shell/man-cli.js +89 -0
- package/dist/shell/metrics-cli.js +100 -0
- package/dist/shell/multi-agent-cli.js +1002 -0
- package/dist/shell/multi-agent-host.js +563 -0
- package/dist/shell/multi-agent-io.js +387 -0
- package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
- package/dist/shell/node-store.js +124 -0
- package/dist/{observability/format.js → shell/observability-format.js} +7 -1
- package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
- package/dist/{observability.js → shell/observability.js} +159 -332
- package/dist/{onramp.js → shell/onramp.js} +11 -0
- package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
- package/dist/shell/operator-ux.js +431 -0
- package/dist/shell/orchestrator.js +231 -0
- package/dist/shell/pipeline-cli.js +667 -0
- package/dist/shell/pipeline.js +217 -0
- package/dist/shell/reclamation-io.js +1366 -0
- package/dist/shell/registry-cli.js +344 -0
- package/dist/{remote-source.js → shell/remote-source.js} +2 -2
- package/dist/shell/report-cli.js +101 -0
- package/dist/shell/report-view-cli.js +117 -0
- package/dist/{orchestrator → shell}/report.js +289 -282
- package/dist/shell/reporter.js +62 -0
- package/dist/shell/run-export-cli.js +106 -0
- package/dist/shell/run-export.js +680 -0
- package/dist/shell/run-registry-io.js +1014 -0
- package/dist/shell/run-store.js +164 -0
- package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
- package/dist/{scheduler.js → shell/scheduler-io.js} +257 -48
- package/dist/shell/scheduling-io.js +321 -0
- package/dist/shell/state-cli.js +181 -0
- package/dist/shell/state-explosion-cli.js +197 -0
- package/dist/shell/telemetry-cli.js +85 -0
- package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
- package/dist/shell/telemetry-ledger-io.js +132 -0
- package/dist/{term.js → shell/term.js} +36 -46
- package/dist/shell/topology-io.js +361 -0
- package/dist/shell/trust-audit.js +472 -0
- package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
- package/dist/shell/verifier.js +48 -0
- package/dist/shell/workbench-host.js +258 -0
- package/dist/shell/workbench-text.js +18 -0
- package/dist/shell/workbench.js +170 -0
- package/dist/shell/worker-cli.js +124 -0
- package/dist/shell/worker-isolation.js +852 -0
- package/dist/shell/workflow-app-loader.js +650 -0
- package/docs/agent-delegation-drive.7.md +4 -0
- package/docs/cli-mcp-parity.7.md +282 -219
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -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/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 +6 -1
- package/docs/project-index.md +137 -71
- 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/remote-source-review.7.md +4 -4
- package/docs/report-verifiable-bundle.7.md +1 -1
- package/docs/run-registry-control-plane.7.md +4 -0
- package/docs/run-retention-reclamation.7.md +25 -0
- package/docs/security-trust-hardening.7.md +3 -1
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +15 -1
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +9 -13
- package/package.json +1 -1
- package/scripts/agents/agent-adapter-core.js +22 -2
- package/scripts/agents/claude-p-agent.js +8 -3
- package/scripts/agents/cw-attest-wrap.js +2 -2
- package/scripts/agents/gemini-agent.js +5 -1
- package/scripts/agents/opencode-agent.js +5 -1
- package/scripts/bump-version.js +4 -3
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-architecture-review.js +2 -3
- package/scripts/dogfood-release.js +3 -3
- package/scripts/gen-parity-doc.js +15 -2
- package/scripts/golden-path.js +4 -4
- package/scripts/onramp-check.js +1 -1
- package/scripts/parity-check.js +38 -21
- package/scripts/release-flow.js +2 -2
- package/scripts/sync-project-index.js +51 -27
- package/scripts/validate-run-state-schema.js +2 -2
- package/scripts/version-sync-check.js +30 -30
- package/dist/candidate-scoring.js +0 -729
- package/dist/capability-core.js +0 -1189
- package/dist/capability-registry.js +0 -885
- package/dist/cli/command-surface.js +0 -494
- package/dist/cli/format.js +0 -56
- package/dist/cli/handlers/audit.js +0 -82
- package/dist/cli/handlers/blackboard.js +0 -81
- package/dist/cli/handlers/candidate.js +0 -40
- package/dist/cli/handlers/clones.js +0 -34
- package/dist/cli/handlers/collaboration.js +0 -61
- package/dist/cli/handlers/eval.js +0 -40
- package/dist/cli/handlers/ledger.js +0 -169
- package/dist/cli/handlers/maintenance.js +0 -107
- package/dist/cli/handlers/multi-agent.js +0 -165
- package/dist/cli/handlers/node.js +0 -41
- package/dist/cli/handlers/operational.js +0 -155
- package/dist/cli/handlers/operator.js +0 -146
- package/dist/cli/handlers/registry.js +0 -68
- package/dist/cli/handlers/run.js +0 -153
- package/dist/cli/handlers/scheduling.js +0 -132
- package/dist/cli/handlers/workbench.js +0 -41
- package/dist/cli/handlers/worker.js +0 -45
- package/dist/cli/run-summary.js +0 -45
- package/dist/clones.js +0 -162
- package/dist/collaboration.js +0 -726
- package/dist/commit.js +0 -592
- package/dist/compare.js +0 -18
- package/dist/coordinator/classify.js +0 -45
- package/dist/coordinator/paths.js +0 -42
- package/dist/coordinator/util.js +0 -126
- package/dist/coordinator.js +0 -990
- package/dist/daemon.js +0 -44
- package/dist/dispatch.js +0 -250
- package/dist/doctor.js +0 -212
- package/dist/drive.js +0 -864
- package/dist/error-feedback.js +0 -419
- package/dist/evidence-grounding.js +0 -184
- package/dist/execution-backend/agent.js +0 -354
- package/dist/execution-backend/probes.js +0 -112
- package/dist/execution-backend/util.js +0 -47
- package/dist/execution-backend.js +0 -961
- package/dist/gates.js +0 -48
- package/dist/harness.js +0 -61
- package/dist/ledger.js +0 -313
- package/dist/loop-expansion.js +0 -60
- package/dist/mcp/tool-call.js +0 -470
- package/dist/mcp/tool-definitions.js +0 -1066
- package/dist/mcp-surface.js +0 -30
- package/dist/multi-agent/graph.js +0 -84
- package/dist/multi-agent/helpers.js +0 -141
- package/dist/multi-agent/ids.js +0 -20
- package/dist/multi-agent/paths.js +0 -22
- package/dist/multi-agent-eval/normalize.js +0 -51
- package/dist/multi-agent-eval.js +0 -678
- package/dist/multi-agent-host.js +0 -777
- package/dist/multi-agent.js +0 -984
- package/dist/node-projection.js +0 -59
- package/dist/node-snapshot.js +0 -260
- package/dist/operator-ux.js +0 -631
- package/dist/orchestrator/app-operations.js +0 -211
- package/dist/orchestrator/audit-operations.js +0 -182
- package/dist/orchestrator/candidate-operations.js +0 -117
- package/dist/orchestrator/cli-options.js +0 -294
- package/dist/orchestrator/collaboration-operations.js +0 -86
- package/dist/orchestrator/feedback-operations.js +0 -81
- package/dist/orchestrator/host-operations.js +0 -78
- package/dist/orchestrator/lifecycle-operations.js +0 -650
- package/dist/orchestrator/migration-operations.js +0 -44
- package/dist/orchestrator/multi-agent-operations.js +0 -362
- package/dist/orchestrator/topology-operations.js +0 -84
- package/dist/orchestrator.js +0 -925
- package/dist/pipeline-runner.js +0 -285
- package/dist/reclamation/hash.js +0 -72
- package/dist/reclamation.js +0 -812
- package/dist/reporter.js +0 -67
- package/dist/run-export.js +0 -815
- package/dist/run-registry/derive.js +0 -175
- package/dist/run-registry/format.js +0 -124
- package/dist/run-registry/gc.js +0 -251
- package/dist/run-registry/policy.js +0 -16
- package/dist/run-registry/queue.js +0 -115
- package/dist/run-registry.js +0 -850
- package/dist/run-state-schema.js +0 -68
- package/dist/scheduling.js +0 -184
- package/dist/state-explosion.js +0 -1014
- package/dist/state.js +0 -367
- package/dist/telemetry-ledger.js +0 -196
- package/dist/topology.js +0 -565
- package/dist/triggers.js +0 -184
- package/dist/trust-audit.js +0 -644
- package/dist/types/blackboard.js +0 -2
- package/dist/types/candidate.js +0 -2
- package/dist/types/collaboration.js +0 -2
- package/dist/types/core.js +0 -2
- package/dist/types/drive.js +0 -10
- package/dist/types/error-feedback.js +0 -2
- package/dist/types/evidence-reasoning.js +0 -2
- package/dist/types/execution-backend.js +0 -2
- package/dist/types/multi-agent.js +0 -2
- package/dist/types/observability.js +0 -2
- package/dist/types/pipeline.js +0 -2
- package/dist/types/reclamation.js +0 -8
- package/dist/types/report-bundle.js +0 -6
- package/dist/types/result.js +0 -2
- package/dist/types/run-registry.js +0 -2
- package/dist/types/run.js +0 -2
- package/dist/types/sandbox.js +0 -2
- package/dist/types/schedule.js +0 -2
- package/dist/types/state-node.js +0 -2
- package/dist/types/topology.js +0 -2
- package/dist/types/trust.js +0 -2
- package/dist/types/workbench.js +0 -2
- package/dist/types/worker.js +0 -2
- package/dist/types/workflow-app.js +0 -2
- package/dist/types.js +0 -44
- package/dist/util/fingerprint.js +0 -19
- package/dist/util/fingerprint.test.js +0 -27
- package/dist/verifier.js +0 -78
- package/dist/version.js +0 -8
- package/dist/workbench-host.js +0 -192
- package/dist/workbench.js +0 -192
- package/dist/worker-accept/acceptance.js +0 -114
- package/dist/worker-accept/blackboard-fanout.js +0 -80
- package/dist/worker-accept/blackboard-linkage.js +0 -19
- package/dist/worker-accept/context.js +0 -2
- package/dist/worker-accept/telemetry-ledger.js +0 -126
- package/dist/worker-accept/validation.js +0 -77
- package/dist/worker-accept/verifier-completion.js +0 -73
- package/dist/worker-isolation/helpers.js +0 -51
- package/dist/worker-isolation/paths.js +0 -46
- package/dist/worker-isolation.js +0 -656
- package/dist/workflow-api.js +0 -131
- /package/dist/{types → core/types}/boundary.js +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
//
|
|
2
|
+
// shell/term.ts — zero-dependency terminal styling.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// MILESTONE 5 (docs/rebuild/PLAN.md build order, step 5, doctor/fix): TTY-gated
|
|
5
|
+
// ANSI formatting, so a piped run (every conformance case pipes with
|
|
6
|
+
// NO_COLOR=1) prints plain text. EXTENDED at MILESTONE 11 (reporting/
|
|
7
|
+
// observability) with the rest of the old build's src/term.ts: indent,
|
|
8
|
+
// sectionHeader, phaseProgressLine, printSuccessSummary, stripAnsi,
|
|
9
|
+
// visibleWidth, truncate, formatFindingsSummary, FindingRow — byte-exact
|
|
10
|
+
// port of plugins/cool-workflow/src/term.ts:81-210.
|
|
9
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
12
|
exports.bold = bold;
|
|
11
13
|
exports.dim = dim;
|
|
@@ -14,9 +16,9 @@ exports.yellow = yellow;
|
|
|
14
16
|
exports.red = red;
|
|
15
17
|
exports.cyan = cyan;
|
|
16
18
|
exports.doctorGlyph = doctorGlyph;
|
|
17
|
-
exports.indent = indent;
|
|
18
|
-
exports.nextHint = nextHint;
|
|
19
19
|
exports.tryHint = tryHint;
|
|
20
|
+
exports.nextHint = nextHint;
|
|
21
|
+
exports.indent = indent;
|
|
20
22
|
exports.sectionHeader = sectionHeader;
|
|
21
23
|
exports.phaseProgressLine = phaseProgressLine;
|
|
22
24
|
exports.printSuccessSummary = printSuccessSummary;
|
|
@@ -27,9 +29,6 @@ exports.formatFindingsSummary = formatFindingsSummary;
|
|
|
27
29
|
function isTTY(stream = process.stderr) {
|
|
28
30
|
return Boolean(stream.isTTY);
|
|
29
31
|
}
|
|
30
|
-
/** Whether to emit ANSI color on a stream, honoring the de-facto env standards:
|
|
31
|
-
* NO_COLOR / CW_NO_COLOR (any non-empty value) disable; FORCE_COLOR (non-"0") forces on
|
|
32
|
-
* even when piped; otherwise fall back to isTTY. The `--no-color` flag sets CW_NO_COLOR. */
|
|
33
32
|
function colorEnabled(stream, env = process.env) {
|
|
34
33
|
if ((env.NO_COLOR ?? "") !== "" || (env.CW_NO_COLOR ?? "") !== "")
|
|
35
34
|
return false;
|
|
@@ -37,7 +36,6 @@ function colorEnabled(stream, env = process.env) {
|
|
|
37
36
|
return true;
|
|
38
37
|
return isTTY(stream);
|
|
39
38
|
}
|
|
40
|
-
// ---- ansi codes ----
|
|
41
39
|
const ansi = {
|
|
42
40
|
reset: "\x1b[0m",
|
|
43
41
|
bold: "\x1b[1m",
|
|
@@ -47,7 +45,6 @@ const ansi = {
|
|
|
47
45
|
red: "\x1b[31m",
|
|
48
46
|
cyan: "\x1b[36m",
|
|
49
47
|
};
|
|
50
|
-
// ---- styled text ----
|
|
51
48
|
function style(code, text, stream) {
|
|
52
49
|
if (!colorEnabled(stream))
|
|
53
50
|
return text;
|
|
@@ -71,7 +68,6 @@ function red(text, stream) {
|
|
|
71
68
|
function cyan(text, stream) {
|
|
72
69
|
return style(ansi.cyan, text, stream);
|
|
73
70
|
}
|
|
74
|
-
// ---- semantic helpers ----
|
|
75
71
|
/** Returns the styled glyph + label for a doctor check severity. */
|
|
76
72
|
function doctorGlyph(status, stream) {
|
|
77
73
|
const glyph = { ok: "✓", warn: "!", fail: "✗" };
|
|
@@ -82,42 +78,41 @@ function doctorGlyph(status, stream) {
|
|
|
82
78
|
};
|
|
83
79
|
return color[status](`${glyph[status]}`, stream);
|
|
84
80
|
}
|
|
85
|
-
/**
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
return text.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
81
|
+
/** A `Try: <cmd>` recovery hint (brew-style; the command stays plain to copy). */
|
|
82
|
+
function tryHint(cmd, stream) {
|
|
83
|
+
return `${dim("Try:", stream)} ${cmd}`;
|
|
89
84
|
}
|
|
90
85
|
/** A `Next: <cmd>` hint line (the command stays plain so it is copy-pasteable). */
|
|
91
86
|
function nextHint(cmd, stream) {
|
|
92
87
|
return `${dim("Next:", stream)} ${cmd}`;
|
|
93
88
|
}
|
|
94
|
-
/**
|
|
95
|
-
function
|
|
96
|
-
|
|
89
|
+
/** Render a multi-line block with consistent 2-space indentation. */
|
|
90
|
+
function indent(text, spaces = 2) {
|
|
91
|
+
const prefix = " ".repeat(spaces);
|
|
92
|
+
return text
|
|
93
|
+
.split("\n")
|
|
94
|
+
.map((line) => `${prefix}${line}`)
|
|
95
|
+
.join("\n");
|
|
97
96
|
}
|
|
98
97
|
/** A `==> Title` section header (brew-style). */
|
|
99
98
|
function sectionHeader(title, stream) {
|
|
100
99
|
return `${bold("==>", stream)} ${title}`;
|
|
101
100
|
}
|
|
102
|
-
/** A phase-progress line: `==> Map ✓ (6/6)` / `==> Assess … (3/6)`. Parallel
|
|
103
|
-
* use ⇉, sequential use …; a finished phase uses a green ✓. */
|
|
101
|
+
/** A phase-progress line: `==> Map ✓ (6/6)` / `==> Assess … (3/6)`. Parallel
|
|
102
|
+
* phases use ⇉, sequential use …; a finished phase uses a green ✓. */
|
|
104
103
|
function phaseProgressLine(name, done, total, mode, stream) {
|
|
105
104
|
const complete = total > 0 && done >= total;
|
|
106
|
-
const glyph = complete ? green("✓", stream) :
|
|
105
|
+
const glyph = complete ? green("✓", stream) : mode === "parallel" ? "⇉" : "…";
|
|
107
106
|
const count = total > 0 ? ` (${done}/${total})` : "";
|
|
108
107
|
return `${sectionHeader(name, stream)} ${glyph}${count}`;
|
|
109
108
|
}
|
|
110
|
-
/** Print a success summary to stderr (TTY-gated).
|
|
111
|
-
*
|
|
112
|
-
* command. Pipe-friendly: silent when stderr is not a TTY, so it never pollutes
|
|
113
|
-
* piped/`--json` stdout. A non-complete run with no agent configured gets a brew-style
|
|
114
|
-
* `Try: cw doctor` recovery line; otherwise `Next: cw status <id>` to inspect. */
|
|
109
|
+
/** Print a success summary to stderr (TTY-gated). Silent when stderr is
|
|
110
|
+
* not a TTY, so it never pollutes piped/`--json` stdout. */
|
|
115
111
|
function printSuccessSummary(fields, stream) {
|
|
116
112
|
if (!isTTY(stream))
|
|
117
113
|
return;
|
|
118
114
|
const s = stream || process.stderr;
|
|
119
|
-
const counts =
|
|
120
|
-
? ` — ${fields.completedWorkers}/${fields.plannedWorkers}` : "";
|
|
115
|
+
const counts = typeof fields.completedWorkers === "number" && typeof fields.plannedWorkers === "number" ? ` — ${fields.completedWorkers}/${fields.plannedWorkers}` : "";
|
|
121
116
|
s.write(`\n${green("✓", s)} Report: ${fields.reportPath}\n`);
|
|
122
117
|
if (fields.status === "complete") {
|
|
123
118
|
s.write(` ${green("✓", s)} Status: complete${counts}\n`);
|
|
@@ -125,8 +120,6 @@ function printSuccessSummary(fields, stream) {
|
|
|
125
120
|
}
|
|
126
121
|
else {
|
|
127
122
|
s.write(` ${yellow("!", s)} Status: ${fields.status}${counts}\n`);
|
|
128
|
-
// No agent backend is the #1 first-run blocker — point at the one command that
|
|
129
|
-
// diagnoses and prints the fix, brew-style. Otherwise inspect the run's state.
|
|
130
123
|
if (fields.agentConfigured === false)
|
|
131
124
|
s.write(` ${tryHint("cw doctor", s)}\n`);
|
|
132
125
|
else
|
|
@@ -139,13 +132,15 @@ const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
|
139
132
|
function stripAnsi(text) {
|
|
140
133
|
return text.replace(ANSI_RE, "");
|
|
141
134
|
}
|
|
142
|
-
/** Visible width of a string, ignoring ANSI. Counts each code point as
|
|
143
|
-
* minor caveat for wide (CJK/emoji) glyphs, acceptable
|
|
135
|
+
/** Visible width of a string, ignoring ANSI. Counts each code point as
|
|
136
|
+
* width 1 — a known minor caveat for wide (CJK/emoji) glyphs, acceptable
|
|
137
|
+
* for one-line status truncation. */
|
|
144
138
|
function visibleWidth(text) {
|
|
145
139
|
return [...stripAnsi(text)].length;
|
|
146
140
|
}
|
|
147
|
-
/** Truncate a (possibly styled) string to `maxWidth` visible columns,
|
|
148
|
-
* Operates on the PLAIN text (callers truncate
|
|
141
|
+
/** Truncate a (possibly styled) string to `maxWidth` visible columns,
|
|
142
|
+
* appending `…` when cut. Operates on the PLAIN text (callers truncate
|
|
143
|
+
* before styling), so no ANSI is split. */
|
|
149
144
|
function truncate(text, maxWidth) {
|
|
150
145
|
if (maxWidth <= 0)
|
|
151
146
|
return "";
|
|
@@ -157,12 +152,10 @@ function truncate(text, maxWidth) {
|
|
|
157
152
|
return `${chars.slice(0, maxWidth - 1).join("")}…`;
|
|
158
153
|
}
|
|
159
154
|
// ---- findings summary table (end-of-run, compact) ----
|
|
160
|
-
/** Severity order for sorting + counting (most severe first). */
|
|
161
155
|
const SEVERITY_ORDER = ["P0", "P1", "P2", "P3", "none"];
|
|
162
|
-
/** Render a compact findings summary assembled from the run's `cw:result`
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* Returns "" when there are no findings (caller prints nothing). */
|
|
156
|
+
/** Render a compact findings summary assembled from the run's `cw:result`
|
|
157
|
+
* blocks: a one-line count headline plus a small id/severity/class
|
|
158
|
+
* table. Returns "" when there are no findings. */
|
|
166
159
|
function formatFindingsSummary(findings, stream) {
|
|
167
160
|
if (!findings.length)
|
|
168
161
|
return "";
|
|
@@ -180,10 +173,7 @@ function formatFindingsSummary(findings, stream) {
|
|
|
180
173
|
const rows = [...findings].sort((a, b) => order(a.severity) - order(b.severity));
|
|
181
174
|
const sevW = Math.max(8, ...rows.map((r) => (r.severity || "none").length));
|
|
182
175
|
const clsW = Math.max(5, ...rows.map((r) => (r.classification || "unknown").length));
|
|
183
|
-
const lines = [
|
|
184
|
-
`${bold("Findings:", stream)} ${findings.length} — ${counts}`,
|
|
185
|
-
dim(` ${"SEVERITY".padEnd(sevW)} ${"CLASS".padEnd(clsW)} ID`, stream)
|
|
186
|
-
];
|
|
176
|
+
const lines = [`${bold("Findings:", stream)} ${findings.length} — ${counts}`, dim(` ${"SEVERITY".padEnd(sevW)} ${"CLASS".padEnd(clsW)} ID`, stream)];
|
|
187
177
|
for (const r of rows) {
|
|
188
178
|
const sev = (r.severity || "none").padEnd(sevW);
|
|
189
179
|
const cls = (r.classification || "unknown").padEnd(clsW);
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// shell/topology-io.ts — applyTopology's IO wiring: materializes the
|
|
3
|
+
// blackboard + multi-agent state a topology needs, then persists the
|
|
4
|
+
// topology-run record.
|
|
5
|
+
//
|
|
6
|
+
// MILESTONE 9. Byte-exact port of the impure half of the old build's
|
|
7
|
+
// src/topology.ts's applyTopology + summarizeTopologies/buildTopologyGraph/
|
|
8
|
+
// showTopologyRun/persistTopologyState.
|
|
9
|
+
//
|
|
10
|
+
// Evidence: SPEC/multi-agent.md section B; plugins/cool-workflow/src/
|
|
11
|
+
// topology.ts:139-455 (byte-exact source for the wiring sequence).
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.ensureTopologyState = ensureTopologyState;
|
|
47
|
+
exports.persistTopologyState = persistTopologyState;
|
|
48
|
+
exports.applyTopology = applyTopology;
|
|
49
|
+
exports.showTopologyRun = showTopologyRun;
|
|
50
|
+
exports.summarizeTopologies = summarizeTopologies;
|
|
51
|
+
exports.buildTopologyGraph = buildTopologyGraph;
|
|
52
|
+
exports.formatTopologySummaryText = formatTopologySummaryText;
|
|
53
|
+
exports.formatTopologyGraphText = formatTopologyGraphText;
|
|
54
|
+
const fs = __importStar(require("node:fs"));
|
|
55
|
+
const path = __importStar(require("node:path"));
|
|
56
|
+
const fs_atomic_1 = require("./fs-atomic");
|
|
57
|
+
const node_store_1 = require("./node-store");
|
|
58
|
+
const state_node_1 = require("../core/state/state-node");
|
|
59
|
+
const contract_1 = require("../core/pipeline/contract");
|
|
60
|
+
const trust_audit_1 = require("./trust-audit");
|
|
61
|
+
const hash_1 = require("../core/hash");
|
|
62
|
+
const hash_2 = require("../core/hash");
|
|
63
|
+
const topo = __importStar(require("../core/multi-agent/topology"));
|
|
64
|
+
const multi_agent_io_1 = require("./multi-agent-io");
|
|
65
|
+
const coordinator_io_1 = require("./coordinator-io");
|
|
66
|
+
function topologyRoot(run) {
|
|
67
|
+
return run.paths.topologiesDir || path.join(run.paths.runDir, "topologies");
|
|
68
|
+
}
|
|
69
|
+
function topologyRunPath(run, id) {
|
|
70
|
+
const safe = id.replace(/[^a-zA-Z0-9_.:-]+/g, "_");
|
|
71
|
+
return path.join(topologyRoot(run), "runs", `${safe}.json`);
|
|
72
|
+
}
|
|
73
|
+
function ensureTopologyState(run) {
|
|
74
|
+
run.paths.topologiesDir = topologyRoot(run);
|
|
75
|
+
fs.mkdirSync(run.paths.topologiesDir, { recursive: true });
|
|
76
|
+
fs.mkdirSync(path.join(run.paths.topologiesDir, "runs"), { recursive: true });
|
|
77
|
+
const existing = run.topologies;
|
|
78
|
+
const state = existing || { schemaVersion: topo.TOPOLOGY_SCHEMA_VERSION, runs: [] };
|
|
79
|
+
state.schemaVersion = topo.TOPOLOGY_SCHEMA_VERSION;
|
|
80
|
+
state.runs = state.runs || [];
|
|
81
|
+
run.topologies = state;
|
|
82
|
+
return state;
|
|
83
|
+
}
|
|
84
|
+
function persistTopologyState(run) {
|
|
85
|
+
const state = ensureTopologyState(run);
|
|
86
|
+
(0, fs_atomic_1.writeJson)(path.join(topologyRoot(run), "index.json"), {
|
|
87
|
+
schemaVersion: topo.TOPOLOGY_SCHEMA_VERSION,
|
|
88
|
+
runId: run.id,
|
|
89
|
+
counts: { runs: state.runs.length },
|
|
90
|
+
runs: state.runs.map((record) => ({ id: record.id, topologyId: record.topologyId, status: record.status, updatedAt: record.updatedAt })),
|
|
91
|
+
});
|
|
92
|
+
for (const record of state.runs)
|
|
93
|
+
(0, fs_atomic_1.writeJson)(topologyRunPath(run, record.id), record);
|
|
94
|
+
}
|
|
95
|
+
function now() {
|
|
96
|
+
return new Date().toISOString();
|
|
97
|
+
}
|
|
98
|
+
function compact(value) {
|
|
99
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
100
|
+
}
|
|
101
|
+
function appendTopologyNode(run, record, status) {
|
|
102
|
+
(0, node_store_1.appendRunNode)(run, (0, state_node_1.createStateNode)({
|
|
103
|
+
id: `${run.id}:topology:${record.id}`,
|
|
104
|
+
kind: "topology-run",
|
|
105
|
+
status,
|
|
106
|
+
loopStage: run.loopStage,
|
|
107
|
+
outputs: { topologyId: record.topologyId, status: record.status },
|
|
108
|
+
artifacts: [{ id: "topology-run", kind: "json", path: topologyRunPath(run, record.id) }],
|
|
109
|
+
parents: [`${run.id}:multi-agent:${record.multiAgentRunId}`, `${run.id}:blackboard:${record.blackboardId}`],
|
|
110
|
+
contractId: contract_1.DEFAULT_PIPELINE_CONTRACT_ID,
|
|
111
|
+
metadata: { topologyId: record.topologyId, topologyRunId: record.id },
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
function applyTopology(run, topologyId, input = {}) {
|
|
115
|
+
const validation = topo.validateTopologyDefinition(topologyId);
|
|
116
|
+
if (!validation.valid || !validation.definition) {
|
|
117
|
+
throw new Error(`Invalid topology ${topologyId}: ${validation.issues.map((entry) => entry.message).join("; ")}`);
|
|
118
|
+
}
|
|
119
|
+
const definition = validation.definition;
|
|
120
|
+
const state = ensureTopologyState(run);
|
|
121
|
+
const taskIds = topo.selectedTaskIds(run.tasks, input.taskIds);
|
|
122
|
+
const id = input.id || topo.topologyRunId(definition, taskIds, run.id, state.runs.length, (value) => (0, hash_1.sha256)((0, hash_2.stableStringify)(value)));
|
|
123
|
+
if (state.runs.some((record) => record.id === id))
|
|
124
|
+
throw new Error(`Duplicate MultiAgentTopologyRun id: ${id}`);
|
|
125
|
+
const board = (0, coordinator_io_1.resolveBlackboard)(run, { id: input.blackboardId || `${id}-blackboard`, title: `${definition.title} Blackboard`, tags: ["topology", definition.id] });
|
|
126
|
+
const topics = definition.blackboardTopics.map((topic) => (0, coordinator_io_1.createBlackboardTopic)(run, { id: `${id}-${topic.id}`, title: topic.title, description: topic.description, blackboardId: board.id, tags: ["topology", definition.id] }));
|
|
127
|
+
const multiAgentRun = (0, multi_agent_io_1.createMultiAgentRun)(run, {
|
|
128
|
+
id: input.multiAgentRunId || `${id}-ma`,
|
|
129
|
+
title: input.title || definition.title,
|
|
130
|
+
objective: definition.summary,
|
|
131
|
+
blackboardId: board.id,
|
|
132
|
+
topicIds: topics.map((topic) => topic.id),
|
|
133
|
+
metadata: { topologyId: definition.id, topologyRunId: id },
|
|
134
|
+
});
|
|
135
|
+
const roleIds = [];
|
|
136
|
+
for (const role of topo.materializedRoles(definition, topo.withLegacyRoleCounts(input))) {
|
|
137
|
+
const record = (0, multi_agent_io_1.createAgentRole)(run, {
|
|
138
|
+
id: `${id}-${role.id}`,
|
|
139
|
+
multiAgentRunId: multiAgentRun.id,
|
|
140
|
+
title: role.title,
|
|
141
|
+
responsibilities: role.responsibilities,
|
|
142
|
+
requiredEvidence: role.requiredEvidence,
|
|
143
|
+
expectedArtifacts: role.expectedArtifacts,
|
|
144
|
+
faninObligations: role.faninObligations,
|
|
145
|
+
blackboardId: board.id,
|
|
146
|
+
topicIds: topics.map((topic) => topic.id),
|
|
147
|
+
metadata: { topologyId: definition.id, topologyRunId: id, topologyRoleId: role.id },
|
|
148
|
+
});
|
|
149
|
+
roleIds.push(record.id);
|
|
150
|
+
}
|
|
151
|
+
const group = (0, multi_agent_io_1.createAgentGroup)(run, { id: `${id}-group`, multiAgentRunId: multiAgentRun.id, title: `${definition.title} Group`, phase: definition.title, taskIds, blackboardId: board.id, topicIds: topics.map((topic) => topic.id), metadata: { topologyId: definition.id, topologyRunId: id } });
|
|
152
|
+
const fanoutRoles = topo.fanoutRoleIds(roleIds);
|
|
153
|
+
const fanout = (0, multi_agent_io_1.createAgentFanout)(run, {
|
|
154
|
+
id: `${id}-fanout`,
|
|
155
|
+
multiAgentRunId: multiAgentRun.id,
|
|
156
|
+
groupId: group.id,
|
|
157
|
+
reason: `${definition.id} topology fanout`,
|
|
158
|
+
roleIds: fanoutRoles,
|
|
159
|
+
taskIds,
|
|
160
|
+
concurrencyLimit: fanoutRoles.length,
|
|
161
|
+
expectedReturnShape: `${definition.title} worker output must include cw:result evidence and blackboard-indexable artifacts/messages.`,
|
|
162
|
+
blackboardId: board.id,
|
|
163
|
+
topicIds: topics.map((topic) => topic.id),
|
|
164
|
+
metadata: { topologyId: definition.id, topologyRunId: id, fanoutStrategy: definition.fanoutStrategy },
|
|
165
|
+
});
|
|
166
|
+
const message = (0, coordinator_io_1.postBlackboardMessage)(run, { topicId: topics[0].id, blackboardId: board.id, body: `${definition.title} topology applied. Roles=${roleIds.join(", ")} fanout=${fanout.id}.`, tags: ["topology", definition.id], metadata: { topologyRunId: id } });
|
|
167
|
+
const decision = (0, coordinator_io_1.recordCoordinatorDecision)(run, {
|
|
168
|
+
blackboardId: board.id,
|
|
169
|
+
topicId: topics[0].id,
|
|
170
|
+
kind: "context-update",
|
|
171
|
+
outcome: "accepted",
|
|
172
|
+
reason: `${definition.title} topology materialized on multi-agent runtime and blackboard.`,
|
|
173
|
+
subjectIds: [multiAgentRun.id, group.id, fanout.id],
|
|
174
|
+
messageIds: [message.id],
|
|
175
|
+
tags: ["topology", definition.id],
|
|
176
|
+
metadata: { topologyRunId: id },
|
|
177
|
+
});
|
|
178
|
+
let fanin;
|
|
179
|
+
if (input.collectInitialFanin) {
|
|
180
|
+
fanin = (0, multi_agent_io_1.collectAgentFanin)(run, { id: `${id}-fanin-initial`, multiAgentRunId: multiAgentRun.id, groupId: group.id, fanoutId: fanout.id, requiredRoleIds: fanout.roleIds, strategy: definition.faninStrategy, blackboardId: board.id, topicIds: topics.map((topic) => topic.id), metadata: { topologyId: definition.id, topologyRunId: id } });
|
|
181
|
+
}
|
|
182
|
+
const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
|
|
183
|
+
kind: "topology.create",
|
|
184
|
+
decision: "recorded",
|
|
185
|
+
source: "runtime-derived",
|
|
186
|
+
topologyId: definition.id,
|
|
187
|
+
topologyRunId: id,
|
|
188
|
+
multiAgentRunId: multiAgentRun.id,
|
|
189
|
+
agentGroupId: group.id,
|
|
190
|
+
agentFanoutId: fanout.id,
|
|
191
|
+
blackboardId: board.id,
|
|
192
|
+
blackboardMessageId: message.id,
|
|
193
|
+
coordinatorDecisionId: decision.id,
|
|
194
|
+
metadata: { fanoutStrategy: definition.fanoutStrategy, faninStrategy: definition.faninStrategy },
|
|
195
|
+
});
|
|
196
|
+
const stamp = now();
|
|
197
|
+
const record = {
|
|
198
|
+
schemaVersion: topo.TOPOLOGY_SCHEMA_VERSION,
|
|
199
|
+
id,
|
|
200
|
+
runId: run.id,
|
|
201
|
+
topologyId: definition.id,
|
|
202
|
+
createdAt: stamp,
|
|
203
|
+
updatedAt: stamp,
|
|
204
|
+
status: fanin?.status === "blocked" ? "blocked" : "planned",
|
|
205
|
+
title: input.title || definition.title,
|
|
206
|
+
multiAgentRunId: multiAgentRun.id,
|
|
207
|
+
blackboardId: board.id,
|
|
208
|
+
topicIds: topics.map((topic) => topic.id),
|
|
209
|
+
roleIds,
|
|
210
|
+
groupIds: [group.id],
|
|
211
|
+
fanoutIds: [fanout.id],
|
|
212
|
+
faninIds: fanin ? [fanin.id] : [],
|
|
213
|
+
messageIds: [message.id],
|
|
214
|
+
artifactRefIds: [],
|
|
215
|
+
coordinatorDecisionIds: [decision.id],
|
|
216
|
+
candidateIds: [],
|
|
217
|
+
selectionIds: [],
|
|
218
|
+
commitIds: [],
|
|
219
|
+
missingEvidence: fanin?.blockedReasons || definition.requiredEvidence,
|
|
220
|
+
conflicts: [],
|
|
221
|
+
nextActions: topo.nextActionsFor(run.id, id, fanout.id),
|
|
222
|
+
links: {
|
|
223
|
+
workflowRunId: run.id,
|
|
224
|
+
multiAgentRunId: multiAgentRun.id,
|
|
225
|
+
blackboardId: board.id,
|
|
226
|
+
blackboardTopicIds: topics.map((topic) => topic.id),
|
|
227
|
+
agentRoleIds: roleIds,
|
|
228
|
+
agentGroupIds: [group.id],
|
|
229
|
+
agentFanoutIds: [fanout.id],
|
|
230
|
+
agentFaninIds: fanin ? [fanin.id] : [],
|
|
231
|
+
coordinatorDecisionIds: [decision.id],
|
|
232
|
+
candidateIds: [],
|
|
233
|
+
selectionIds: [],
|
|
234
|
+
commitIds: [],
|
|
235
|
+
auditEventIds: [audit.id],
|
|
236
|
+
},
|
|
237
|
+
metadata: compact({ ...(input.metadata || {}), topology: definition }),
|
|
238
|
+
};
|
|
239
|
+
state.runs.push(record);
|
|
240
|
+
appendTopologyNode(run, record, topo.statusToNodeStatus(record.status));
|
|
241
|
+
(0, trust_audit_1.recordTrustAuditEvent)(run, {
|
|
242
|
+
kind: "topology.verdict",
|
|
243
|
+
decision: record.status === "blocked" ? "failed" : "recorded",
|
|
244
|
+
source: "cw-validated",
|
|
245
|
+
topologyId: definition.id,
|
|
246
|
+
topologyRunId: id,
|
|
247
|
+
multiAgentRunId: multiAgentRun.id,
|
|
248
|
+
agentFanoutId: fanout.id,
|
|
249
|
+
agentFaninId: fanin?.id,
|
|
250
|
+
blackboardId: board.id,
|
|
251
|
+
coordinatorDecisionId: decision.id,
|
|
252
|
+
metadata: { status: record.status, missingEvidence: record.missingEvidence },
|
|
253
|
+
});
|
|
254
|
+
persistTopologyState(run);
|
|
255
|
+
return record;
|
|
256
|
+
}
|
|
257
|
+
function showTopologyRun(run, topologyRunId) {
|
|
258
|
+
const record = ensureTopologyState(run).runs.find((entry) => entry.id === topologyRunId);
|
|
259
|
+
if (!record)
|
|
260
|
+
throw new Error(`Unknown topology run id: ${topologyRunId}`);
|
|
261
|
+
return record;
|
|
262
|
+
}
|
|
263
|
+
function countBy(items, pick) {
|
|
264
|
+
const counts = {};
|
|
265
|
+
for (const item of items)
|
|
266
|
+
counts[pick(item)] = (counts[pick(item)] || 0) + 1;
|
|
267
|
+
return counts;
|
|
268
|
+
}
|
|
269
|
+
function summarizeTopologies(run) {
|
|
270
|
+
const state = ensureTopologyState(run);
|
|
271
|
+
const multi = run.multiAgent || {};
|
|
272
|
+
const fanins = multi.fanins || [];
|
|
273
|
+
const active = state.runs.map((record) => {
|
|
274
|
+
const inferredFanins = fanins.filter((fanin) => record.groupIds.includes(fanin.groupId) || record.fanoutIds.includes(fanin.fanoutId || ""));
|
|
275
|
+
const allFaninIds = topo.unique([...record.faninIds, ...inferredFanins.map((fanin) => fanin.id)]);
|
|
276
|
+
const blocked = inferredFanins.filter((fanin) => fanin.status === "blocked" || !fanin.verifierReady);
|
|
277
|
+
const ready = inferredFanins.some((fanin) => fanin.verifierReady);
|
|
278
|
+
const missingEvidence = topo.unique([...record.missingEvidence, ...blocked.flatMap((fanin) => fanin.blockedReasons)]);
|
|
279
|
+
return {
|
|
280
|
+
id: record.id,
|
|
281
|
+
topologyId: record.topologyId,
|
|
282
|
+
status: ready ? "ready" : blocked.length ? "blocked" : record.status,
|
|
283
|
+
multiAgentRunId: record.multiAgentRunId,
|
|
284
|
+
blackboardId: record.blackboardId,
|
|
285
|
+
roles: record.roleIds,
|
|
286
|
+
groups: record.groupIds,
|
|
287
|
+
topics: record.topicIds,
|
|
288
|
+
fanouts: record.fanoutIds,
|
|
289
|
+
fanins: allFaninIds,
|
|
290
|
+
missingEvidence,
|
|
291
|
+
conflicts: record.conflicts,
|
|
292
|
+
readiness: ready ? "fanin ready" : missingEvidence.length ? "missing evidence" : "awaiting worker output",
|
|
293
|
+
nextActions: ready ? [`node scripts/cw.js candidate register ${run.id} --result-node <reducer-or-panel-result>`] : record.nextActions,
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
return {
|
|
297
|
+
runId: run.id,
|
|
298
|
+
totalRuns: state.runs.length,
|
|
299
|
+
runsByStatus: countBy(active, (record) => record.status),
|
|
300
|
+
officialTopologies: topo.listTopologyDefinitions().map((definition) => definition.id),
|
|
301
|
+
active,
|
|
302
|
+
nextAction: active.find((record) => record.nextActions.length)?.nextActions[0] || `node scripts/cw.js topology apply ${run.id} map-reduce --task <task-id>`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function buildTopologyGraph(run) {
|
|
306
|
+
const state = ensureTopologyState(run);
|
|
307
|
+
return topo.buildTopologyGraphFromRuns(run.id, state.runs, (id) => topologyRunPath(run, id));
|
|
308
|
+
}
|
|
309
|
+
function formatTopologyCounts(counts) {
|
|
310
|
+
const entries = Object.entries(counts).sort(([a], [b]) => a.localeCompare(b));
|
|
311
|
+
if (!entries.length)
|
|
312
|
+
return "none";
|
|
313
|
+
return entries.map(([k, v]) => `${k}=${v}`).join(", ");
|
|
314
|
+
}
|
|
315
|
+
/** `cw topology summary <run>` human text — port of the old build's
|
|
316
|
+
* formatTopologyPanel (operator-ux/format.ts): a `Topologies` rollup with
|
|
317
|
+
* per-run roles/topics/fanout/fanin/readiness. */
|
|
318
|
+
function formatTopologySummaryText(summary) {
|
|
319
|
+
const lines = [
|
|
320
|
+
"Topologies",
|
|
321
|
+
` runs=${summary.totalRuns}; status=${formatTopologyCounts(summary.runsByStatus)}; official=${summary.officialTopologies.join(", ")}`,
|
|
322
|
+
];
|
|
323
|
+
for (const record of summary.active.slice(0, 6)) {
|
|
324
|
+
lines.push(` ${record.id}: ${record.topologyId}, status=${record.status}, readiness=${record.readiness}`);
|
|
325
|
+
lines.push(` run=${record.multiAgentRunId} board=${record.blackboardId}`);
|
|
326
|
+
lines.push(` roles=${record.roles.join(", ") || "none"} topics=${record.topics.join(", ") || "none"}`);
|
|
327
|
+
lines.push(` fanout=${record.fanouts.join(", ") || "none"} fanin=${record.fanins.join(", ") || "none"}`);
|
|
328
|
+
for (const missing of record.missingEvidence.slice(0, 4))
|
|
329
|
+
lines.push(` missing=${missing}`);
|
|
330
|
+
for (const conflict of record.conflicts.slice(0, 4))
|
|
331
|
+
lines.push(` conflict=${conflict}`);
|
|
332
|
+
if (record.nextActions[0])
|
|
333
|
+
lines.push(` next=${record.nextActions[0]}`);
|
|
334
|
+
}
|
|
335
|
+
if (summary.nextAction)
|
|
336
|
+
lines.push(` next=${summary.nextAction}`);
|
|
337
|
+
return lines.join("\n");
|
|
338
|
+
}
|
|
339
|
+
/** `cw topology graph <run>` human text — the same `Run Graph:` render
|
|
340
|
+
* `cw graph` uses, over the topology graph's nodes/edges (old build:
|
|
341
|
+
* formatOperatorGraph({ runId, nodes, edges })). */
|
|
342
|
+
function formatTopologyGraphText(runId, graph) {
|
|
343
|
+
const lines = [`Run Graph: ${runId}`, "", "Nodes"];
|
|
344
|
+
const groups = {};
|
|
345
|
+
for (const node of graph.nodes)
|
|
346
|
+
(groups[node.kind] ||= []).push(node);
|
|
347
|
+
for (const kind of Object.keys(groups).sort()) {
|
|
348
|
+
lines.push(` ${kind}`);
|
|
349
|
+
for (const node of groups[kind]) {
|
|
350
|
+
const suffix = node.path ? ` -> ${node.path}` : "";
|
|
351
|
+
lines.push(` [${node.status}] ${node.id} (${node.label})${suffix}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
lines.push("", "Edges");
|
|
355
|
+
if (!graph.edges.length)
|
|
356
|
+
lines.push(" none");
|
|
357
|
+
for (const edge of graph.edges) {
|
|
358
|
+
lines.push(` ${edge.from} -> ${edge.to}${edge.label ? ` (${edge.label})` : ""}`);
|
|
359
|
+
}
|
|
360
|
+
return lines.join("\n");
|
|
361
|
+
}
|