cool-workflow 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/apps/architecture-review/app.json +1 -1
  4. package/apps/architecture-review-fast/app.json +1 -1
  5. package/apps/end-to-end-golden-path/app.json +1 -1
  6. package/apps/pr-review-fix-ci/app.json +1 -1
  7. package/apps/release-cut/app.json +1 -1
  8. package/apps/research-synthesis/app.json +1 -1
  9. package/dist/cli/dispatch.js +18 -86
  10. package/dist/cli/parseargv.js +5 -2
  11. package/dist/core/capability-data.js +270 -0
  12. package/dist/core/capability-table.js +16 -3504
  13. package/dist/core/format/help.js +28 -5
  14. package/dist/core/multi-agent/collaboration.js +3 -2
  15. package/dist/core/multi-agent/coordinator.js +4 -3
  16. package/dist/core/pipeline/commit-gate.js +2 -1
  17. package/dist/core/state/state-explosion/digest.js +3 -2
  18. package/dist/core/state/state-explosion/graph.js +9 -8
  19. package/dist/core/state/state-explosion/helpers.js +2 -1
  20. package/dist/core/trust/ledger.js +2 -1
  21. package/dist/core/types/execution-backend.js +18 -0
  22. package/dist/core/types/observability.js +7 -0
  23. package/dist/core/util/collate.js +23 -0
  24. package/dist/core/version.js +1 -1
  25. package/dist/shell/audit-cli.js +46 -2
  26. package/dist/shell/commit-summary.js +2 -1
  27. package/dist/shell/drive.js +26 -10
  28. package/dist/shell/evidence-reasoning.js +4 -3
  29. package/dist/shell/execution-backend/registry.js +2 -1
  30. package/dist/shell/execution-backend/types.js +0 -9
  31. package/dist/shell/fs-atomic.js +14 -1
  32. package/dist/shell/multi-agent-operator-ux.js +4 -3
  33. package/dist/shell/observability.js +12 -11
  34. package/dist/shell/onramp.js +17 -1
  35. package/dist/shell/operator-ux-text.js +2 -1
  36. package/dist/shell/operator-ux.js +7 -6
  37. package/dist/shell/pipeline-cli.js +82 -72
  38. package/dist/shell/reclamation-io.js +2 -1
  39. package/dist/shell/report.js +2 -1
  40. package/dist/shell/run-store.js +17 -0
  41. package/dist/shell/state-explosion-cli.js +2 -1
  42. package/dist/shell/topology-io.js +2 -1
  43. package/dist/shell/trust-audit.js +41 -2
  44. package/dist/shell/worker-cli.js +9 -1
  45. package/dist/shell/worker-isolation.js +34 -9
  46. package/dist/shell/workflow-app-loader.js +3 -2
  47. package/dist/wiring/capability-table/basics.js +66 -0
  48. package/dist/wiring/capability-table/exec-backend.js +162 -0
  49. package/dist/wiring/capability-table/index.js +42 -0
  50. package/dist/wiring/capability-table/multi-agent.js +623 -0
  51. package/dist/wiring/capability-table/parity.js +466 -0
  52. package/dist/wiring/capability-table/pipeline.js +280 -0
  53. package/dist/wiring/capability-table/registry-core.js +189 -0
  54. package/dist/wiring/capability-table/reporting.js +394 -0
  55. package/dist/wiring/capability-table/scheduling-registry.js +558 -0
  56. package/dist/wiring/capability-table/state.js +173 -0
  57. package/dist/wiring/capability-table/trust-ledger.js +134 -0
  58. package/dist/wiring/capability-table/workflow-apps.js +366 -0
  59. package/docs/agent-delegation-drive.7.md +2 -0
  60. package/docs/cli-mcp-parity.7.md +7 -2
  61. package/docs/contract-migration-tooling.7.md +2 -0
  62. package/docs/control-plane-scheduling.7.md +2 -0
  63. package/docs/durable-state-and-locking.7.md +22 -0
  64. package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
  65. package/docs/execution-backends.7.md +2 -0
  66. package/docs/index.md +1 -0
  67. package/docs/multi-agent-cli-mcp-surface.7.md +2 -0
  68. package/docs/multi-agent-eval-replay-harness.7.md +2 -0
  69. package/docs/multi-agent-operator-ux.7.md +2 -0
  70. package/docs/node-snapshot-diff-replay.7.md +2 -0
  71. package/docs/observability-cost-accounting.7.md +2 -0
  72. package/docs/project-index.md +25 -5
  73. package/docs/real-execution-backends.7.md +2 -0
  74. package/docs/release-and-migration.7.md +2 -0
  75. package/docs/release-tooling.7.md +2 -0
  76. package/docs/run-registry-control-plane.7.md +2 -0
  77. package/docs/run-retention-reclamation.7.md +2 -0
  78. package/docs/security-trust-hardening.7.md +30 -0
  79. package/docs/state-explosion-management.7.md +2 -0
  80. package/docs/team-collaboration.7.md +2 -0
  81. package/docs/trust-audit-anchor.7.md +69 -0
  82. package/docs/web-desktop-workbench.7.md +2 -0
  83. package/manifest/plugin.manifest.json +1 -1
  84. package/package.json +3 -1
  85. package/scripts/bump-version.js +24 -2
  86. package/scripts/canonical-apps.js +4 -4
  87. package/scripts/dogfood-release.js +1 -1
  88. package/scripts/golden-path.js +4 -4
  89. package/scripts/purity-baseline.json +68 -0
  90. package/scripts/purity-gate.js +239 -0
  91. package/scripts/release-check.js +8 -1
  92. package/scripts/version-sync-check.js +33 -12
  93. package/workflows/README.md +19 -0
@@ -106,6 +106,7 @@ function workerBlackboardManifest(run, task) {
106
106
  const verifier_1 = require("./verifier");
107
107
  const runner_1 = require("../core/pipeline/runner");
108
108
  const hash_1 = require("../core/hash");
109
+ const collate_1 = require("../core/util/collate");
109
110
  const telemetry_attestation_1 = require("../core/trust/telemetry-attestation");
110
111
  const telemetry_ledger_io_1 = require("./telemetry-ledger-io");
111
112
  exports.WORKER_ISOLATION_SCHEMA_VERSION = 1;
@@ -531,13 +532,37 @@ function recordWorkerOutput(run, workerId, resultPath, options = {}) {
531
532
  })
532
533
  : undefined;
533
534
  // Opt-in fail-closed gate (default off): when the operator requires
534
- // attested telemetry, a delegated hop whose verdict is not `attested`
535
- // is REJECTED here — BEFORE any accept-side state mutation — so the
536
- // drive parks it instead of recording unverifiable usage.
537
- if (options.requireAttestedTelemetry && telemetry && telemetry.status !== "attested") {
538
- const message = `Worker ${workerId} telemetry is ${telemetry.status} (${telemetry.reason || "unverified"}) and require-attested-telemetry is enabled refusing to accept a hop whose usage cannot be cryptographically verified`;
539
- recordWorkerFailure(run, workerId, message, { code: "telemetry-unattested-blocked", path: absoluteResultPath, retryable: false });
540
- throw new Error(message);
535
+ // attested telemetry, an accept whose usage cannot be verified is
536
+ // REJECTED here — BEFORE any accept-side state mutation — so the drive
537
+ // parks it instead of recording unverifiable usage. This fires on BOTH
538
+ // shapes: a delegation present but not attested (telemetry.status !==
539
+ // "attested"), and NO delegation metadata at all. The second shape is
540
+ // the gap a manual `cw worker output` / `cw result` accept used to slip
541
+ // through silently: options.agentDelegation was simply absent, so
542
+ // `telemetry` was undefined and the old `telemetry &&` condition
543
+ // short-circuited false — an unattested result could be laundered
544
+ // through the manual accept path even with the require flag on.
545
+ // --allow-unattested is the operator's explicit way past this: it never
546
+ // skips the gate silently, it records a telemetry.gate-override event.
547
+ if (options.requireAttestedTelemetry && (!telemetry || telemetry.status !== "attested")) {
548
+ if (options.allowUnattested) {
549
+ (0, trust_audit_1.recordTrustAuditEvent)(run, {
550
+ kind: "telemetry.gate-override",
551
+ decision: "allowed",
552
+ source: "operator",
553
+ workerId,
554
+ taskId: task.id,
555
+ metadata: { reason: "--allow-unattested", telemetryStatus: telemetry ? telemetry.status : "absent" },
556
+ });
557
+ }
558
+ else {
559
+ const code = telemetry ? "telemetry-unattested-blocked" : "telemetry-missing-blocked";
560
+ const message = telemetry
561
+ ? `Worker ${workerId} telemetry is ${telemetry.status} (${telemetry.reason || "unverified"}) and require-attested-telemetry is enabled — refusing to accept a hop whose usage cannot be cryptographically verified`
562
+ : `Worker ${workerId} carries no agent-delegation telemetry at all and require-attested-telemetry is enabled — refusing to accept an unattested manual result (pass --allow-unattested to record an audited override)`;
563
+ recordWorkerFailure(run, workerId, message, { code, path: absoluteResultPath, retryable: false });
564
+ throw new Error(message);
565
+ }
541
566
  }
542
567
  const agentDelegationMeta = delegation
543
568
  ? {
@@ -797,7 +822,7 @@ function listWorkerScopes(run, options = {}) {
797
822
  // silently drops workers whenever run.workers was reset.
798
823
  const merged = mergeScopes(run.workers || [], loadWorkerScopesFromDisk(run));
799
824
  run.workers = merged;
800
- const workers = merged.slice().sort((a, b) => a.id.localeCompare(b.id));
825
+ const workers = merged.slice().sort((a, b) => (0, collate_1.stableCompare)(a.id, b.id));
801
826
  return options.status ? workers.filter((w) => w.status === options.status) : workers;
802
827
  }
803
828
  function countByStatus(workers) {
@@ -824,7 +849,7 @@ function countBucket(values) {
824
849
  return counts;
825
850
  }
826
851
  function formatCountBucket(counts) {
827
- const entries = Object.entries(counts).sort(([a], [b]) => a.localeCompare(b));
852
+ const entries = Object.entries(counts).sort(([a], [b]) => (0, collate_1.stableCompare)(a, b));
828
853
  if (!entries.length)
829
854
  return "none";
830
855
  return entries.map(([k, v]) => `${k}=${v}`).join(", ");
@@ -75,6 +75,7 @@ const path = __importStar(require("node:path"));
75
75
  const app_schema_1 = require("../core/workflow-apps/app-schema");
76
76
  const sandbox_profile_1 = require("./sandbox-profile");
77
77
  const version_1 = require("../core/version");
78
+ const collate_1 = require("../core/util/collate");
78
79
  class WorkflowAppNotFoundError extends Error {
79
80
  constructor(appId) {
80
81
  super(`Workflow app not found: ${appId}`);
@@ -421,10 +422,10 @@ function listWorkflowAppRecords() {
421
422
  ...loadWorkflowFiles(workflowsDir).map((file) => loadWorkflowAppFromEntrypoint(file)),
422
423
  ...loadAppManifestFiles(appsDir).map((file) => loadWorkflowAppFromManifest(file)),
423
424
  ].sort((left, right) => {
424
- const byId = left.app.id.localeCompare(right.app.id);
425
+ const byId = (0, collate_1.stableCompare)(left.app.id, right.app.id);
425
426
  if (byId)
426
427
  return byId;
427
- return sourcePathOf(left).localeCompare(sourcePathOf(right));
428
+ return (0, collate_1.stableCompare)(sourcePathOf(left), sourcePathOf(right));
428
429
  });
429
430
  const seen = new Map();
430
431
  for (const record of records) {
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ // wiring/capability-table/basics.ts — MILESTONE 2's CLI bindings (version,
3
+ // list, status, sandbox.list). Split out of core/capability-table.ts,
4
+ // byte-for-byte (extracted with sed, not retyped).
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const registry_core_1 = require("./registry-core");
7
+ // ---------------------------------------------------------------------
8
+ // CLI bindings wired at THIS milestone (version, list, status,
9
+ // sandbox.list). `version` is cli-only per SPEC/mcp.md's declared
10
+ // one-surface list (`help` is handled directly by cli/entry.ts's
11
+ // top-level flag redirect, same as milestone 1 — it is not itself a
12
+ // dispatchable command row); `list`/`status`/`sandbox.list` reuse the mcp
13
+ // row's capability id and get a cli binding layered on top. Every handler
14
+ // below returns a `CliHandlerResult`; core/ never touches process.stdout
15
+ // or process.exitCode directly (see docs/rebuild/PLAN.md's core/shell split) —
16
+ // cli/dispatch.ts's generic executor performs the actual write.
17
+ // ---------------------------------------------------------------------
18
+ const version_1 = require("../../core/version");
19
+ const workflow_app_loader_1 = require("../../shell/workflow-app-loader");
20
+ const help_1 = require("../../core/format/help");
21
+ (0, registry_core_1.addCliOnlyCapability)("version", "Print the current cool-workflow version.", {
22
+ path: ["version"],
23
+ jsonMode: "default",
24
+ handler: () => ({ text: `${version_1.CURRENT_COOL_WORKFLOW_VERSION}\n` }),
25
+ }, "version is a local, no-run-state print; the old build never gave it an MCP peer.");
26
+ /** `cw search <keyword>` — filters the SAME real app discovery `cw list`
27
+ * shows, by id/title/summary (byte-behavior port of cli/dispatch.ts's
28
+ * milestone-1 carry-over `search` arm, moved here so the dispatchLegacy
29
+ * switch shrinks per its file header's rule). `hiddenFromHelp` keeps it
30
+ * out of the per-verb help listing exactly as before (it never had one —
31
+ * `search` only ever appeared in formatHelp's hard-coded "More commands"
32
+ * index line, which this row does not touch), so `cw help search` keeps
33
+ * its existing "Unknown command: search" text. */
34
+ (0, registry_core_1.addCliOnlyCapability)("search", "Search bundled workflows by id/title/summary keyword.", {
35
+ path: ["search"],
36
+ jsonMode: "flag",
37
+ hiddenFromHelp: true,
38
+ handler: (args) => {
39
+ const keyword = args.positionals.join(" ");
40
+ if (!keyword.trim()) {
41
+ throw new Error('Missing search keyword.\n Tip: cw search architecture to find workflows about architecture.');
42
+ }
43
+ const lower = keyword.toLowerCase();
44
+ const results = (0, workflow_app_loader_1.listWorkflowApps)()
45
+ .filter((a) => String(a.title).toLowerCase().includes(lower) ||
46
+ String(a.summary).toLowerCase().includes(lower) ||
47
+ String(a.id).toLowerCase().includes(lower))
48
+ .map((a) => ({ id: String(a.id), title: String(a.title), summary: String(a.summary) }));
49
+ return { json: results, text: (0, help_1.formatSearchResults)(keyword, results) };
50
+ },
51
+ }, "CLI-only discovery helper over the same real app data cw list shows; no MCP client needs a free-text search tool alongside cw_list's structured output.");
52
+ (0, registry_core_1.attachCliBinding)("list", {
53
+ path: ["list"],
54
+ jsonMode: "default",
55
+ handler: () => ({ json: (0, registry_core_1.listBundledWorkflows)() }),
56
+ });
57
+ (0, registry_core_1.attachCliBinding)("status", {
58
+ path: ["status"],
59
+ jsonMode: "flag",
60
+ handler: (args) => ({ json: (0, registry_core_1.statusPayload)(args.positionals[0]) }),
61
+ });
62
+ (0, registry_core_1.attachCliBinding)("sandbox.list", {
63
+ path: ["sandbox", "list"],
64
+ jsonMode: "default",
65
+ handler: () => ({ json: (0, registry_core_1.listBundledSandboxProfiles)() }),
66
+ });
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ // wiring/capability-table/exec-backend.ts — MILESTONE 5 (execution backend,
3
+ // agent spawn, sandbox) CLI bindings: sandbox.*, backend.*, app.run. Split
4
+ // out of core/capability-table.ts, byte-for-byte (extracted with sed, not
5
+ // retyped).
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const registry_core_1 = require("./registry-core");
8
+ // MILESTONE 5 (execution backend, agent spawn, sandbox) CLI bindings:
9
+ // sandbox.list|show|validate, backend.list|show|probe,
10
+ // backend.agent.config.show|set, doctor, fix. Handler BODIES live in
11
+ // shell/exec-backend-cli.ts / shell/doctor.ts (impure — env/fs reads);
12
+ // this table only wires argv shape -> handler call, per cli/dispatch.ts's
13
+ // generic executor contract. `sandbox.list`/`backend.list` are ALREADY
14
+ // declared MCP-only rows from milestone 2 (MCP_TOOL_DATA above) — this
15
+ // section layers a `cli` binding onto them (attachCliBinding) and replaces
16
+ // their milestone-2 placeholder `mcp.handler` with the real body, exactly
17
+ // as milestones 3/4 did for their own rows.
18
+ // ---------------------------------------------------------------------
19
+ const exec_backend_cli_1 = require("../../shell/exec-backend-cli");
20
+ const doctor_1 = require("../../shell/doctor");
21
+ const io_1 = require("../../cli/io");
22
+ const app_run_cli_1 = require("../../shell/app-run-cli");
23
+ (0, registry_core_1.attachCliBinding)("sandbox.list", {
24
+ path: ["sandbox", "list"],
25
+ jsonMode: "default",
26
+ handler: (args) => ({ json: (0, exec_backend_cli_1.listSandboxProfilesCli)(args.options) }),
27
+ });
28
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("sandbox.list").mcp.handler = (args) => (0, exec_backend_cli_1.listSandboxProfilesCli)(args);
29
+ // GAP #24: cw_sandbox_choose / cw_sandbox_resolve + cw_app_run were declared
30
+ // MCP-only rows with the notYetImplemented placeholder handler. Wire them to
31
+ // the ported shell bodies (both are MCP-only in the old build — no CLI path).
32
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("sandbox.choose").mcp.handler = (args) => (0, app_run_cli_1.sandboxChooseCli)(args);
33
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("sandbox.resolve").mcp.handler = (args) => (0, app_run_cli_1.sandboxChooseCli)(args);
34
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.run").mcp.handler = (args) => (0, app_run_cli_1.appRunCli)(args);
35
+ (0, registry_core_1.attachCliBinding)("sandbox.show", {
36
+ path: ["sandbox", "show"],
37
+ jsonMode: "default",
38
+ handler: (args) => ({ json: (0, exec_backend_cli_1.showSandboxProfileCli)((0, io_1.required)(args.positionals[0], "profile id"), args.options) }),
39
+ });
40
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("sandbox.show").mcp.handler = (args) => (0, exec_backend_cli_1.showSandboxProfileCli)((0, io_1.required)((0, io_1.optionalArg)(args.profileId), "profile id"), args);
41
+ (0, registry_core_1.attachCliBinding)("sandbox.validate", {
42
+ path: ["sandbox", "validate"],
43
+ jsonMode: "default",
44
+ handler: (args) => {
45
+ const result = (0, exec_backend_cli_1.validateSandboxProfileCli)((0, io_1.required)(args.positionals[0], "profile file"), args.options);
46
+ return { json: result, exitCode: result.valid ? undefined : 1 };
47
+ },
48
+ });
49
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("sandbox.validate").mcp.handler = (args) => (0, exec_backend_cli_1.validateSandboxProfileCli)((0, io_1.required)((0, io_1.optionalArg)(args.profileFile), "profile file"), args);
50
+ // PARITY: `sandbox.choose`/`sandbox.resolve` are BOTH-surface capabilities
51
+ // per SPEC/mcp.md (old build cli.path ["sandbox","choose"]/["sandbox",
52
+ // "resolve"]) — they were left MCP-only at GAP #24 (see the comment
53
+ // above sandboxChooseCli's mcp.handler wiring). Attach the same, already-
54
+ // working shell body as the cli.handler too, so the CLI front door and
55
+ // the parity payload probe both reach it (no new business logic, same
56
+ // function both surfaces already call over MCP).
57
+ (0, registry_core_1.attachCliBinding)("sandbox.choose", {
58
+ path: ["sandbox", "choose"],
59
+ jsonMode: "default",
60
+ handler: (args) => ({ json: (0, app_run_cli_1.sandboxChooseCli)(args.options) }),
61
+ });
62
+ (0, registry_core_1.attachCliBinding)("sandbox.resolve", {
63
+ path: ["sandbox", "resolve"],
64
+ jsonMode: "default",
65
+ handler: (args) => ({ json: (0, app_run_cli_1.sandboxChooseCli)(args.options) }),
66
+ });
67
+ (0, registry_core_1.attachCliBinding)("backend.list", {
68
+ path: ["backend", "list"],
69
+ jsonMode: "default",
70
+ handler: () => ({ json: (0, exec_backend_cli_1.listBackendsCli)() }),
71
+ });
72
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.list").mcp.handler = () => (0, exec_backend_cli_1.listBackendsCli)();
73
+ (0, registry_core_1.attachCliBinding)("backend.show", {
74
+ path: ["backend", "show"],
75
+ jsonMode: "default",
76
+ handler: (args) => ({ json: (0, exec_backend_cli_1.showBackendCli)((0, io_1.required)(args.positionals[0], "backend id")) }),
77
+ });
78
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.show").mcp.handler = (args) => (0, exec_backend_cli_1.showBackendCli)((0, io_1.required)((0, io_1.optionalArg)(args.backendId), "backend id"));
79
+ (0, registry_core_1.attachCliBinding)("backend.probe", {
80
+ path: ["backend", "probe"],
81
+ jsonMode: "default",
82
+ handler: (args) => ({ json: (0, exec_backend_cli_1.probeBackendCli)(args.positionals[0], args.options) }),
83
+ });
84
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.probe").mcp.handler = (args) => (0, exec_backend_cli_1.probeBackendCli)((0, io_1.optionalArg)(args.backendId), args);
85
+ // `backend agent config [show]` = read-only; `backend agent config set
86
+ // ...` = mutating. CLI path is ["backend", "agent"] (2 tokens, matching
87
+ // dispatchTable's supported path lengths); the remaining positionals
88
+ // ("config", "show"/"set") are read inside the handler, byte-exact to the
89
+ // old build's handleBackend "agent" case (src/cli/handlers/
90
+ // operational.ts:52-62).
91
+ (0, registry_core_1.attachCliBinding)("backend.agent.config.show", {
92
+ path: ["backend", "agent"],
93
+ helpPath: ["backend", "agent", "config"],
94
+ jsonMode: "default",
95
+ handler: (args) => {
96
+ const action = args.positionals[1];
97
+ if (action === "set")
98
+ return { json: (0, exec_backend_cli_1.backendAgentConfigSet)(args.options) };
99
+ return { json: (0, exec_backend_cli_1.backendAgentConfigShow)(args.options) };
100
+ },
101
+ });
102
+ // `backend.agent.config.set` shares the SAME dispatch path/handler as
103
+ // `.show` above (dispatchTable only supports 2-token paths, and the
104
+ // show-vs-set branch lives inside that one handler on positionals[1] —
105
+ // byte-exact to the old build's handleBackend "agent" case). This second
106
+ // attachCliBinding call exists ONLY so `cw help backend` lists both rows
107
+ // (cliCommandHelpRows iterates cliCapabilities(), one row per capability),
108
+ // matching the old registry's two declared rows sharing one caseTokens
109
+ // group; dispatchTable itself never reaches this row a second time because
110
+ // `backend.agent.config.show`'s row is found first by
111
+ // findCapabilityByCliPath's linear scan and its handler already covers
112
+ // both actions.
113
+ (0, registry_core_1.attachCliBinding)("backend.agent.config.set", {
114
+ path: ["backend", "agent"],
115
+ helpPath: ["backend", "agent", "config"],
116
+ jsonMode: "default",
117
+ handler: (args) => {
118
+ const action = args.positionals[1];
119
+ if (action === "set")
120
+ return { json: (0, exec_backend_cli_1.backendAgentConfigSet)(args.options) };
121
+ return { json: (0, exec_backend_cli_1.backendAgentConfigShow)(args.options) };
122
+ },
123
+ });
124
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.agent.config.show").mcp.handler = (args) => (0, exec_backend_cli_1.backendAgentConfigShow)(args);
125
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").mcp.handler = (args) => (0, exec_backend_cli_1.backendAgentConfigSet)(args);
126
+ // PARITY: `backend.agent.config.set` mutates $CW_HOME/agent-config.json
127
+ // (secret-stripped) before returning the effective config; both surfaces
128
+ // perform the same write, so it is a documented opt-out from the
129
+ // read-payload probe, not an undocumented divergence.
130
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").payloadIdentical = false;
131
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").reason =
132
+ "Mutating: persists $CW_HOME/agent-config.json (secret-stripped) before returning the effective config; both surfaces perform the same write — it is a surface-mutating verb, not a read probe.";
133
+ (0, registry_core_1.addCliOnlyCapability)("doctor", "Diagnose the host for setup problems (Node version, agent backend, agent binary on PATH, git, writable home/repo state) and print an actionable fix per check.", {
134
+ path: ["doctor"],
135
+ jsonMode: "flag",
136
+ handler: (args) => {
137
+ const report = (0, doctor_1.runDoctor)(args.options, process.env, String(args.options.cwd || process.cwd()));
138
+ // Byte-exact port of src/cli/command-surface.ts:170-176: both text
139
+ // branches are written as `${formatX(report)}\n` UNCONDITIONALLY —
140
+ // formatDoctorFixes already ends in its own "\n" (its last joined
141
+ // element is ""), so its case needs one MORE explicit "\n" here to
142
+ // reproduce that unconditional append; cli/dispatch.ts's generic
143
+ // renderer only appends "\n" when the text does NOT already end in
144
+ // one, so a bare `formatDoctorFixes(report)` here would silently
145
+ // drop the old build's trailing blank line.
146
+ const text = (0, io_1.wantsJson)(args.options) ? undefined : args.options.fix ? `${(0, doctor_1.formatDoctorFixes)(report)}\n` : (0, doctor_1.formatDoctorReport)(report);
147
+ return { json: report, text, exitCode: report.ok ? undefined : 1 };
148
+ },
149
+ }, "Environment diagnostics are inherently local to the CLI host — Node version, $PATH, $CW_HOME/cwd writability. An MCP client diagnosing the server process's environment is not meaningful; agents already receive the same readiness facts in their typed results (e.g. status: blocked, agentConfigured). Inspired by `brew doctor`.");
150
+ (0, registry_core_1.addCliOnlyCapability)("fix", "Print consolidated fix commands for CW setup issues.", {
151
+ path: ["fix"],
152
+ jsonMode: "human",
153
+ handler: (args) => {
154
+ const report = (0, doctor_1.runDoctor)(args.options, process.env, String(args.options.cwd || process.cwd()));
155
+ // See the "doctor" handler's comment above: formatDoctorFixes
156
+ // already ends in "\n", so one more explicit "\n" here reproduces
157
+ // src/cli/command-surface.ts:126-130's unconditional
158
+ // `${formatDoctorFixes(report)}\n` write.
159
+ return { text: `${(0, doctor_1.formatDoctorFixes)(report)}\n`, exitCode: report.ok ? undefined : 1 };
160
+ },
161
+ }, "Environment fix commands are local diagnostics, same reasoning as doctor.");
162
+ // ---------------------------------------------------------------------
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ // wiring/capability-table/index.ts — composes the capability table from
3
+ // registry-core (the shared machinery) plus every domain slice, in the
4
+ // EXACT original source order (REGISTRY array order is a pinned
5
+ // behavior: tools/list order, gen-parity-doc's byte-diff gate, cw help
6
+ // line order). Each slice is a plain module whose top-level
7
+ // attachCliBinding/addCliOnlyCapability/REGISTRY_BY_CAPABILITY calls run
8
+ // once, at first import — Node's module system guarantees that happens
9
+ // in exactly the order these imports are written below, the same
10
+ // guarantee the single original file relied on for its own top-to-bottom
11
+ // statement order.
12
+ //
13
+ // No slice imports another slice; every slice imports only from
14
+ // registry-core.ts, core/capability-data.ts, and shell/core as needed —
15
+ // so this file is the only place the full domain list is assembled, and
16
+ // there is no cross-slice circular dependency to reason about.
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
29
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ __exportStar(require("./registry-core"), exports);
33
+ require("./basics");
34
+ require("./state");
35
+ require("./exec-backend");
36
+ require("./pipeline");
37
+ require("./trust-ledger");
38
+ require("./multi-agent");
39
+ require("./scheduling-registry");
40
+ require("./reporting");
41
+ require("./workflow-apps");
42
+ __exportStar(require("./parity"), exports);