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
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// core/format/help.ts — formatHelp, formatCommandHelp.
|
|
3
|
+
//
|
|
4
|
+
// Pure functions of already-loaded data. Byte-exact port of
|
|
5
|
+
// src/orchestrator.ts:899-1007 in the old build (formatHelp,
|
|
6
|
+
// formatCommandHelp) plus the color helpers `bold`/`dim` keyed off stdout.
|
|
7
|
+
//
|
|
8
|
+
// LOAD-BEARING LAYOUT (docs/rebuild/PLAN.md byte-compat item 14 — do not "clean up"):
|
|
9
|
+
// - The command-line rows under "Cool Workflow" and the `cw <path...>`
|
|
10
|
+
// rows in formatCommandHelp use a 2-space indent. The CLI/MCP parity
|
|
11
|
+
// help-token checker parses ONLY 2-space lines as command tokens.
|
|
12
|
+
// - The trailing note line ("Run cw help <command> ...") uses a
|
|
13
|
+
// DELIBERATE 4-space indent so that same 2-space parser skips it and
|
|
14
|
+
// never mistakes it for a command token.
|
|
15
|
+
//
|
|
16
|
+
// The header/flags/more-commands banner text stays hard-coded (it is not
|
|
17
|
+
// capability-table data — see SPEC/cli-help/_root.txt). The per-verb
|
|
18
|
+
// subcommand-row table (`COMMAND_HELP_ROWS`) is now a MIX: verbs whose
|
|
19
|
+
// capability already has a `cli` binding in core/capability-table.ts
|
|
20
|
+
// (`list`, `version`, `status`, `doctor`, `fix`, `backend`, `sandbox` as of
|
|
21
|
+
// milestone 5) are dropped from the literal table below and read from the
|
|
22
|
+
// capability table instead, via `cliCommandHelpRows()`; every other verb
|
|
23
|
+
// stays literal here until its own milestone lands. This satisfies
|
|
24
|
+
// docs/rebuild/PLAN.md milestone 2's own "done when": a CLI `--help` walk and an MCP
|
|
25
|
+
// `tools/list` round-trip read the SAME table rows for any capability
|
|
26
|
+
// wired into both.
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.formatHelp = formatHelp;
|
|
29
|
+
exports.formatCommandHelp = formatCommandHelp;
|
|
30
|
+
exports.formatInfo = formatInfo;
|
|
31
|
+
const capability_table_1 = require("../capability-table");
|
|
32
|
+
/** src/orchestrator.ts:934-951 — the exact "More commands" token set, in
|
|
33
|
+
* this exact order (space-joined in the source, pipe-joined for display). */
|
|
34
|
+
const MORE_COMMANDS_TOKENS = [
|
|
35
|
+
"list", "search", "info", "init", "plan", "status", "next", "dispatch",
|
|
36
|
+
"result", "state", "commit", "report", "app", "sandbox", "backend",
|
|
37
|
+
"contract", "node", "feedback", "worker", "audit", "candidate", "review",
|
|
38
|
+
"loop", "schedule", "routine", "registry", "run", "queue", "clones",
|
|
39
|
+
"orphans", "history", "quickstart", "audit-run", "multi-agent", "topology",
|
|
40
|
+
"summary", "blackboard", "coordinator", "metrics", "operator", "sched",
|
|
41
|
+
"gc", "telemetry", "migration", "demo", "workbench", "approve", "reject",
|
|
42
|
+
"comment", "handoff", "ledger", "graph", "eval", "man", "version",
|
|
43
|
+
"update", "fix",
|
|
44
|
+
];
|
|
45
|
+
const MORE_COMMANDS_WRAP_WIDTH = 76;
|
|
46
|
+
/** src/orchestrator.ts:940-951 — greedily pack pipe-joined tokens into
|
|
47
|
+
* lines of at most `width` columns, INCLUDING the 2-space indent in the
|
|
48
|
+
* width check (a token is never split). Returns lines WITH the 2-space
|
|
49
|
+
* indent already applied — callers must not add another one. */
|
|
50
|
+
function wrapPipeJoined(tokens, width) {
|
|
51
|
+
const lines = [];
|
|
52
|
+
let line = " ";
|
|
53
|
+
for (const token of tokens) {
|
|
54
|
+
const sep = line.length > 2 ? "|" : "";
|
|
55
|
+
if (line.length + sep.length + token.length > width) {
|
|
56
|
+
lines.push(line);
|
|
57
|
+
line = " ";
|
|
58
|
+
}
|
|
59
|
+
line += (line.length > 2 ? "|" : "") + token;
|
|
60
|
+
}
|
|
61
|
+
if (line.length > 2)
|
|
62
|
+
lines.push(line);
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
65
|
+
/** src/orchestrator.ts:988-1007 — the per-verb subcommand rows, keyed by
|
|
66
|
+
* the verb (`cli.path[0]` in the old registry). Verbs whose capability
|
|
67
|
+
* now has a real `cli` binding in core/capability-table.ts (`list`,
|
|
68
|
+
* `version`, `status`) are read from `cliCommandHelpRows()` instead (see
|
|
69
|
+
* `formatCommandHelp` below) and are DELIBERATELY ABSENT from this
|
|
70
|
+
* literal table — do not re-add them here, that would be exactly the
|
|
71
|
+
* hand-sync drift this milestone's table exists to remove. Every other
|
|
72
|
+
* verb stays literal until its own milestone lands. */
|
|
73
|
+
const COMMAND_HELP_ROWS = {
|
|
74
|
+
help: [{ command: "cw help", summary: "Print the human CLI help text." }],
|
|
75
|
+
// NOTE: "ledger" is not listed here any more — ledger propose/review/
|
|
76
|
+
// verify/apply/list are now real capability-table rows (milestone 8,
|
|
77
|
+
// core/capability-table.ts) and come from cliCommandHelpRows("ledger")
|
|
78
|
+
// below, so their summary text lives in exactly one place.
|
|
79
|
+
//
|
|
80
|
+
// "clones" (and, below, "schedule"/"routine"/"sched"/"registry"/"queue"/
|
|
81
|
+
// "gc"/"orphans") STAY literal here even though milestone 10 gave each
|
|
82
|
+
// verb a real capability-table row: that row's OWN `cli.path` is the
|
|
83
|
+
// bare 1-token verb (e.g. ["clones"]) because dispatchTable only
|
|
84
|
+
// supports 1- or 2-token paths and these verbs each have MANY
|
|
85
|
+
// subcommands handled by one internal switch — so the row's `cli`
|
|
86
|
+
// binding is a dispatch/usage-error mechanism, not a per-subcommand
|
|
87
|
+
// help entry, and is marked `hiddenFromHelp` for exactly that reason
|
|
88
|
+
// (core/capability-table.ts). The per-subcommand summaries a human
|
|
89
|
+
// reads via `cw help clones` therefore still come from literal rows
|
|
90
|
+
// here, same as every other not-yet-per-subcommand-tabled verb below.
|
|
91
|
+
clones: [
|
|
92
|
+
{
|
|
93
|
+
command: "cw clones gc",
|
|
94
|
+
summary: "Reclaim cached remote-source checkouts: a TTL sweep (--older-than-days, default 30) or --all. Deletes only inside the clones cache.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
command: "cw clones list",
|
|
98
|
+
summary: "List the cached remote-source checkouts that --link/URL reviews populate (origin URL, kind, commit, age, bytes). Read-only.",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
schedule: [
|
|
102
|
+
{ command: "cw schedule create", summary: "Create a scheduled CW task." },
|
|
103
|
+
{ command: "cw schedule list", summary: "List scheduled CW tasks." },
|
|
104
|
+
{ command: "cw schedule delete", summary: "Delete a scheduled CW task." },
|
|
105
|
+
{ command: "cw schedule due", summary: "List due scheduled CW tasks." },
|
|
106
|
+
{ command: "cw schedule complete", summary: "Mark a scheduled task complete." },
|
|
107
|
+
{ command: "cw schedule pause", summary: "Pause a scheduled CW task." },
|
|
108
|
+
{ command: "cw schedule resume", summary: "Resume a scheduled CW task." },
|
|
109
|
+
{ command: "cw schedule run-now", summary: "Create an immediate scheduled-task run record." },
|
|
110
|
+
{ command: "cw schedule history", summary: "List scheduled-task run history." },
|
|
111
|
+
{ command: "cw schedule daemon", summary: "Tick the wall-clock scheduler once (--once) or run forever." },
|
|
112
|
+
],
|
|
113
|
+
routine: [
|
|
114
|
+
{ command: "cw routine create", summary: "Create a routine-style API/GitHub trigger." },
|
|
115
|
+
{ command: "cw routine list", summary: "List routine-style triggers." },
|
|
116
|
+
{ command: "cw routine delete", summary: "Delete a routine-style trigger." },
|
|
117
|
+
{ command: "cw routine fire", summary: "Record an API/GitHub trigger event." },
|
|
118
|
+
{ command: "cw routine events", summary: "List routine trigger events." },
|
|
119
|
+
],
|
|
120
|
+
sched: [
|
|
121
|
+
{ command: "cw sched plan", summary: "Read-only control-plane lease plan for the queue+policy+now." },
|
|
122
|
+
{ command: "cw sched lease", summary: "Claim eligible queue entries as leases (concurrency-bounded)." },
|
|
123
|
+
{ command: "cw sched release", summary: "Release a held lease (failed -> retry/backoff or park)." },
|
|
124
|
+
{ command: "cw sched complete", summary: "Complete a held lease (terminal success)." },
|
|
125
|
+
{ command: "cw sched reclaim", summary: "Reclaim expired leases (each counts a failed attempt)." },
|
|
126
|
+
{ command: "cw sched reset", summary: "Reset a parked entry to ready (operator recovery)." },
|
|
127
|
+
{ command: "cw sched policy", summary: "Show or set the scheduling policy (concurrency/attempts/backoff/TTL)." },
|
|
128
|
+
],
|
|
129
|
+
registry: [
|
|
130
|
+
{ command: "cw registry refresh", summary: "Recompute and persist the derived run registry index." },
|
|
131
|
+
{ command: "cw registry show", summary: "Read the run registry index with valid|stale|absent freshness." },
|
|
132
|
+
],
|
|
133
|
+
queue: [
|
|
134
|
+
{ command: "cw queue add", summary: "Enqueue a pending/planned run with explicit ordering policy." },
|
|
135
|
+
{ command: "cw queue list", summary: "List the durable run queue in policy order." },
|
|
136
|
+
{ command: "cw queue drain", summary: "Mark the next ready queue entries drained (the host still executes)." },
|
|
137
|
+
{ command: "cw queue show", summary: "Show one durable queue entry." },
|
|
138
|
+
],
|
|
139
|
+
gc: [
|
|
140
|
+
{
|
|
141
|
+
command: "cw gc plan",
|
|
142
|
+
summary: "Dry-run plan of run reclamation (per-kind bytes + capability downgrade); frees nothing.",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
command: "cw gc run",
|
|
146
|
+
summary: "Execute the write-ahead reclamation transaction (skeleton -> tombstone -> fsync -> free).",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
command: "cw gc verify",
|
|
150
|
+
summary: "Re-prove a reclaimed run: skeleton-complete, tombstone chain untampered, artifacts reconstructable.",
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
orphans: [
|
|
154
|
+
{
|
|
155
|
+
command: "cw orphans list",
|
|
156
|
+
summary: "List run directories under .cw/runs/ that the run registry cannot see (no state.json — a killed/interrupted process never wrote one), with age + bytes. Read-only.",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
command: "cw orphans gc",
|
|
160
|
+
summary: "Reclaim orphan run directories (no state.json): an age sweep (--min-age-minutes, default 60) or --all. Deletes only inside a scanned repo's .cw/runs/, never a run the registry knows about.",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
run: [
|
|
164
|
+
// NOTE: neither "cw run drive" row is listed here any more. The first
|
|
165
|
+
// (read-only preview, "Preview the next agent-delegation...") is now a
|
|
166
|
+
// real capability-table row (run.drive, PARITY WIRING) with its own
|
|
167
|
+
// `cli.path`; the second (mutating "Drive a run by delegating...") is
|
|
168
|
+
// also a real capability-table row (run.drive.step, milestone 6+7)
|
|
169
|
+
// whose `helpPath` override displays it under the same "cw run drive"
|
|
170
|
+
// command column. Both come from cliCommandHelpRows("run") below, so
|
|
171
|
+
// neither is hand-duplicated here. Same for run archive/list/rerun/
|
|
172
|
+
// resume/search/show (milestone 10, core/capability-table.ts) — only
|
|
173
|
+
// the not-yet-implemented run-export family (milestone 11) stays
|
|
174
|
+
// literal here.
|
|
175
|
+
{
|
|
176
|
+
command: "cw run export",
|
|
177
|
+
summary: "Export a run to a portable archive with run-local files and digest integrity.",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
command: "cw run import",
|
|
181
|
+
summary: "Restore a portable run archive into a target repo and verify restored file digests.",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
command: "cw run inspect-archive",
|
|
185
|
+
summary: "Read-only integrity inspection of a portable run archive without importing it.",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
command: "cw run restore",
|
|
189
|
+
summary: "Fail-closed restore of a portable run archive: integrity-inspect, import, and verify in one step; refuses anything that does not verify.",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
command: "cw run verify-import",
|
|
193
|
+
summary: "Verify an imported run against its restore manifest and telemetry chain.",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
// NOTE: "quickstart" is not listed here any more — it is now a real
|
|
197
|
+
// capability-table row (milestone 6+7, core/capability-table.ts) and
|
|
198
|
+
// comes from cliCommandHelpRows("quickstart") below, so its summary
|
|
199
|
+
// text lives in exactly one place.
|
|
200
|
+
man: [{ command: "cw man", summary: "Show a man page from docs/ (e.g. cw man release-tooling)." }],
|
|
201
|
+
// NOTE: "demo" is not listed here any more — demo tamper/bundle are now
|
|
202
|
+
// real capability-table rows (milestone 8, core/capability-table.ts)
|
|
203
|
+
// and come from cliCommandHelpRows("demo") below.
|
|
204
|
+
};
|
|
205
|
+
/** src/orchestrator.ts:899-933 — the top-level `cw help` text. Color is
|
|
206
|
+
* intentionally NOT applied here (this milestone's conformance runs pipe
|
|
207
|
+
* stdout, so NO_COLOR/non-TTY always wins); byte content matches the
|
|
208
|
+
* plain-text capture at SPEC/cli-help/_root.txt exactly. */
|
|
209
|
+
function formatHelp() {
|
|
210
|
+
const moreCommandsLines = wrapPipeJoined(MORE_COMMANDS_TOKENS, MORE_COMMANDS_WRAP_WIDTH);
|
|
211
|
+
const lines = [
|
|
212
|
+
"Cool Workflow",
|
|
213
|
+
"",
|
|
214
|
+
' -q "question" [-claude|-codex|-gemini|-deepseek] Ask a question, get a report',
|
|
215
|
+
' -q "question" --link <url> Review a remote repo by URL',
|
|
216
|
+
" version Show version",
|
|
217
|
+
" update Update to latest release",
|
|
218
|
+
" doctor Check setup",
|
|
219
|
+
" fix Show fix commands for setup issues",
|
|
220
|
+
"",
|
|
221
|
+
"Flags",
|
|
222
|
+
" -q, --question TEXT The task or question to answer",
|
|
223
|
+
" -r, --repo PATH Target repository path (default: .)",
|
|
224
|
+
" -d, --dir PATH Project folder to review (alias for --repo)",
|
|
225
|
+
" -claude Use Claude agent",
|
|
226
|
+
" -codex Use Codex agent",
|
|
227
|
+
" -gemini Use Gemini (via opencode)",
|
|
228
|
+
" -deepseek Use DeepSeek (via opencode)",
|
|
229
|
+
" --verbose Show full agent narration live (default: compact)",
|
|
230
|
+
" --full Verbose, plus the report printed inline at the end",
|
|
231
|
+
" --no-color Disable ANSI color (also honors NO_COLOR / FORCE_COLOR)",
|
|
232
|
+
"",
|
|
233
|
+
"More commands",
|
|
234
|
+
...moreCommandsLines,
|
|
235
|
+
"",
|
|
236
|
+
" Run cw help <command> for one command's subcommands and descriptions.",
|
|
237
|
+
];
|
|
238
|
+
return `${lines.join("\n")}\n`;
|
|
239
|
+
}
|
|
240
|
+
/** MILESTONE 2 — the capability-table projection half of
|
|
241
|
+
* `COMMAND_HELP_ROWS`: every declared `cli` binding whose `path[0]`
|
|
242
|
+
* matches `verb` becomes one row, `cw <path.join(" ")>` / `summary`.
|
|
243
|
+
* Merged into `formatCommandHelp` below so a verb can have BOTH literal
|
|
244
|
+
* rows (not-yet-migrated subcommands) and table-derived rows (migrated
|
|
245
|
+
* ones) without duplicating data by hand. */
|
|
246
|
+
function cliCommandHelpRows(verb) {
|
|
247
|
+
return (0, capability_table_1.cliCapabilities)()
|
|
248
|
+
.filter((row) => row.cli.path[0] === verb && !row.cli.hiddenFromHelp)
|
|
249
|
+
.map((row) => ({ command: `cw ${(row.cli.helpPath ?? row.cli.path).join(" ")}`, summary: row.summary }));
|
|
250
|
+
}
|
|
251
|
+
/** src/orchestrator.ts:988-1007 — `formatCommandHelp(verb)`. Unknown verb
|
|
252
|
+
* gives a SOFT text (never a throw); known verb lists its registry rows,
|
|
253
|
+
* sorted by command string, padded to the longest command column + 2
|
|
254
|
+
* (capped at 40, per the old registry's own cap; none of the milestone-1
|
|
255
|
+
* fixture rows exceed it). */
|
|
256
|
+
function formatCommandHelp(verb, suggestCommand) {
|
|
257
|
+
const rows = [...(COMMAND_HELP_ROWS[verb] ?? []), ...cliCommandHelpRows(verb)];
|
|
258
|
+
if (rows.length === 0) {
|
|
259
|
+
const hint = suggestCommand(verb);
|
|
260
|
+
const lines = [`Unknown command: ${verb}`];
|
|
261
|
+
if (hint)
|
|
262
|
+
lines.push(` Did you mean: cw ${hint}`);
|
|
263
|
+
lines.push(" Try: cw help (list all commands)");
|
|
264
|
+
return `${lines.join("\n")}\n`;
|
|
265
|
+
}
|
|
266
|
+
const sorted = [...rows].sort((a, b) => (a.command < b.command ? -1 : a.command > b.command ? 1 : 0));
|
|
267
|
+
const longest = Math.min(40, Math.max(...sorted.map((row) => row.command.length)));
|
|
268
|
+
const lines = [`cw ${verb}`, ""];
|
|
269
|
+
for (const row of sorted) {
|
|
270
|
+
const padded = row.command.padEnd(longest, " ");
|
|
271
|
+
lines.push(` ${padded} ${row.summary}`);
|
|
272
|
+
}
|
|
273
|
+
return `${lines.join("\n")}\n`;
|
|
274
|
+
}
|
|
275
|
+
/** `cw info <id>` human card — MILESTONE 12. Byte-exact in spirit to
|
|
276
|
+
* src/orchestrator.ts:899-929's `formatInfo` (color stripped, matching
|
|
277
|
+
* this file's own `formatHelp`/`formatCommandHelp` — styling, if any, is
|
|
278
|
+
* applied by the shell layer, never here). `data` is the `showApp`/
|
|
279
|
+
* `showWorkflowApp` payload. */
|
|
280
|
+
function formatInfo(appId, data) {
|
|
281
|
+
const inputs = (Array.isArray(data.inputs) ? data.inputs : []);
|
|
282
|
+
const phases = (Array.isArray(data.phases) ? data.phases : []);
|
|
283
|
+
const lines = [`cw info ${appId}`];
|
|
284
|
+
if (data.title)
|
|
285
|
+
lines.push(` Title: ${data.title}`);
|
|
286
|
+
if (data.version)
|
|
287
|
+
lines.push(` Version: ${data.version}`);
|
|
288
|
+
if (data.summary)
|
|
289
|
+
lines.push(` Summary: ${data.summary}`);
|
|
290
|
+
if (data.author)
|
|
291
|
+
lines.push(` Author: ${typeof data.author === "object" ? data.author.name : data.author}`);
|
|
292
|
+
if (data.compatible !== undefined)
|
|
293
|
+
lines.push(` Compatible: ${data.compatible ? "yes" : "no"}`);
|
|
294
|
+
if (inputs.length > 0) {
|
|
295
|
+
lines.push(" Inputs:");
|
|
296
|
+
for (const one of inputs) {
|
|
297
|
+
const name = one.name || "";
|
|
298
|
+
const type = one.type || "string";
|
|
299
|
+
const required = one.required ? ", required" : "";
|
|
300
|
+
const def = one.default ? `, default: ${one.default}` : "";
|
|
301
|
+
const desc = one.description ? ` — ${one.description}` : "";
|
|
302
|
+
lines.push(` - ${name} (${type}${required}${def})${desc}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (Array.isArray(data.sandboxProfiles) && data.sandboxProfiles.length > 0) {
|
|
306
|
+
lines.push(` Sandbox: ${data.sandboxProfiles.join(", ")}`);
|
|
307
|
+
}
|
|
308
|
+
const taskCount = data.taskCount || 0;
|
|
309
|
+
if (phases.length > 0) {
|
|
310
|
+
lines.push(` Phases: ${phases.length} phase${phases.length !== 1 ? "s" : ""}, ${taskCount} task${taskCount !== 1 ? "s" : ""}`);
|
|
311
|
+
}
|
|
312
|
+
lines.push(` Run: cw quickstart ${appId} --repo . --question "..."`);
|
|
313
|
+
return lines.join("\n");
|
|
314
|
+
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// core/format/state-explosion-text.ts — formatStateExplosionReport,
|
|
3
|
+
// formatCompactGraph, formatBlackboardDigest, stateExplosionReportLines.
|
|
4
|
+
//
|
|
5
|
+
// MILESTONE 4. Byte-exact port of the old build's
|
|
6
|
+
// src/state-explosion/format.ts. CLI text only — never affects `--json`/
|
|
7
|
+
// MCP payloads. Pure: a record object in, strings out.
|
|
8
|
+
//
|
|
9
|
+
// Evidence: SPEC/state-core.md "Human formatters (CLI text only, never
|
|
10
|
+
// --json)".
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.formatStateExplosionReport = formatStateExplosionReport;
|
|
4
13
|
exports.formatCompactGraph = formatCompactGraph;
|
|
@@ -141,7 +150,7 @@ function stateExplosionReportLines(report) {
|
|
|
141
150
|
const lines = [
|
|
142
151
|
`- Records: ${size.total}; graph nodes: ${size.graphNodes}; graph edges: ${size.graphEdges}; messages: ${size.messages}`,
|
|
143
152
|
`- Compaction: ${size.compactionRecommended ? "recommended" : "not needed"}`,
|
|
144
|
-
`- Summary freshness: ${report.freshness.status}
|
|
153
|
+
`- Summary freshness: ${report.freshness.status}`,
|
|
145
154
|
];
|
|
146
155
|
for (const reason of size.reasons)
|
|
147
156
|
lines.push(` - ${reason}`);
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// core/hash.ts — THE one hash/stringify module.
|
|
3
|
+
//
|
|
4
|
+
// Pure. No fs, no child_process, no net, no process.env, no Date.now(), no
|
|
5
|
+
// Math.random(). Every input the old build fed these functions (a run id, a
|
|
6
|
+
// content object, a list of strings) still comes in as a plain function
|
|
7
|
+
// argument here.
|
|
8
|
+
//
|
|
9
|
+
// Per docs/rebuild/PLAN.md's byte-compat section ("Hash dedup — three shapes, not one
|
|
10
|
+
// edge case"), this file must keep THREE things separate, each with its own
|
|
11
|
+
// name, never collapsed into a single flagged helper:
|
|
12
|
+
//
|
|
13
|
+
// 1. Three hash SPELLINGS: `sha256` (prefixed, 64 hex), `fingerprintStrings`
|
|
14
|
+
// (prefixed, 32 hex, SORTS its input), `stableHash` (prefixed, 64 hex,
|
|
15
|
+
// key-sorted JSON), plus `sha256Bytes` (bare hex, archive-only — never
|
|
16
|
+
// mix with the other three).
|
|
17
|
+
// 2. Three DIVERGENT stringify-before-hash behaviors: `ledgerStableStringify`
|
|
18
|
+
// (no undefined special-casing), `telemetryStableStringify` (top-level
|
|
19
|
+
// undefined -> the string "null"), `eventHashInput` (JSON round-trip
|
|
20
|
+
// FIRST, to drop undefined-valued keys, THEN sort-and-stringify).
|
|
21
|
+
// 3. One shared recursive key-sort primitive, `stableStringify`, that the
|
|
22
|
+
// three wrappers above are each built from explicitly — not a single
|
|
23
|
+
// function with a flag.
|
|
24
|
+
//
|
|
25
|
+
// Evidence: SPEC/ledger-trust.md "Hash form", "Handoff ledger entry",
|
|
26
|
+
// "Telemetry ledger record", "Trust-audit chain"; SPEC/types-util.md
|
|
27
|
+
// "Fingerprint / hash formats"; SPEC/state-core.md "Fingerprint / hash
|
|
28
|
+
// formats", "Contract-migration prover invariants".
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.sha256 = sha256;
|
|
31
|
+
exports.sha256Bytes = sha256Bytes;
|
|
32
|
+
exports.fingerprintStrings = fingerprintStrings;
|
|
33
|
+
exports.fingerprintRecords = fingerprintRecords;
|
|
34
|
+
exports.stableHash = stableHash;
|
|
35
|
+
exports.stableStringify = stableStringify;
|
|
36
|
+
exports.ledgerStableStringify = ledgerStableStringify;
|
|
37
|
+
exports.telemetryStableStringify = telemetryStableStringify;
|
|
38
|
+
exports.eventHashInput = eventHashInput;
|
|
39
|
+
const node_crypto_1 = require("node:crypto");
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// 1. Hash spellings
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/** Prefixed `sha256:` + all 64 hex chars. Used by both hash chains,
|
|
44
|
+
* promptDigest, resultDigest, reportedUsageDigest, the ledger digest.
|
|
45
|
+
* (src/execution-backend/util.ts:13-15 in the old build.) */
|
|
46
|
+
function sha256(value) {
|
|
47
|
+
return `sha256:${(0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex")}`;
|
|
48
|
+
}
|
|
49
|
+
/** BARE hex, no prefix. Archive file digests only (run-export.ts). Never mix
|
|
50
|
+
* with the other three hash spellings in this file. */
|
|
51
|
+
function sha256Bytes(bytes) {
|
|
52
|
+
return (0, node_crypto_1.createHash)("sha256").update(bytes).digest("hex");
|
|
53
|
+
}
|
|
54
|
+
/** Prefixed `sha256:` + only the FIRST 32 hex chars, over SORTED JSON-array
|
|
55
|
+
* input. Sorts a COPY (`[...values].sort()`) with the JS default sort
|
|
56
|
+
* (UTF-16 code-unit order) — never mutates the caller's array. Used by
|
|
57
|
+
* snapshot ids, state-explosion fingerprints, evidence-reasoning
|
|
58
|
+
* fingerprints. (src/util/fingerprint.ts:6-10.) */
|
|
59
|
+
function fingerprintStrings(values) {
|
|
60
|
+
const hash = (0, node_crypto_1.createHash)("sha256");
|
|
61
|
+
hash.update(JSON.stringify([...values].sort()));
|
|
62
|
+
return `sha256:${hash.digest("hex").slice(0, 32)}`;
|
|
63
|
+
}
|
|
64
|
+
/** Maps each record to `"<id>:<status or empty>"`, sorts, then fingerprints.
|
|
65
|
+
* `updatedAt` is accepted in the record shape but NEVER used.
|
|
66
|
+
* (src/util/fingerprint.ts:12-14.) */
|
|
67
|
+
function fingerprintRecords(records) {
|
|
68
|
+
return fingerprintStrings(records.map((r) => `${r.id}:${r.status || ""}`).sort());
|
|
69
|
+
}
|
|
70
|
+
/** Prefixed `sha256:` + all 64 hex chars, over recursively KEY-SORTED JSON
|
|
71
|
+
* (not normalized — used to prove a source snapshot was not mutated). Used
|
|
72
|
+
* by the contract-migration prover. (src/contract-migration.ts:90-103.) */
|
|
73
|
+
function stableHash(value) {
|
|
74
|
+
return `sha256:${(0, node_crypto_1.createHash)("sha256").update(stableStringify(value)).digest("hex")}`;
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// 2/3. The one shared sort-and-stringify primitive, plus the three named,
|
|
78
|
+
// independently-divergent wrapper behaviors.
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
/** Deterministic JSON with recursively sorted object keys. Never special-
|
|
81
|
+
* cases a top-level `undefined` — `JSON.stringify(undefined)` returns
|
|
82
|
+
* `undefined` (not a string), matching plain `JSON.stringify` behavior at
|
|
83
|
+
* the top level. This IS the canonical primitive every wrapper below calls;
|
|
84
|
+
* it is not itself one of the three named divergent behaviors. */
|
|
85
|
+
function stableStringify(value) {
|
|
86
|
+
if (value === null || typeof value !== "object") {
|
|
87
|
+
return JSON.stringify(value);
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
91
|
+
}
|
|
92
|
+
const keys = Object.keys(value).sort();
|
|
93
|
+
const body = keys
|
|
94
|
+
.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`)
|
|
95
|
+
.join(",");
|
|
96
|
+
return `{${body}}`;
|
|
97
|
+
}
|
|
98
|
+
/** `src/ledger.ts`'s `stableStringify` — sorts keys recursively, NO special-
|
|
99
|
+
* casing of a top-level `undefined`. A top-level `undefined` is not a real
|
|
100
|
+
* call site here in practice, but this must not be assumed to behave like
|
|
101
|
+
* `telemetryStableStringify` below. Byte-identical to `stableStringify`;
|
|
102
|
+
* kept as its own named export because the old build kept a private copy
|
|
103
|
+
* in ledger.ts with this exact (non-)behavior, and the plan requires each
|
|
104
|
+
* divergent behavior to stay separately named and separately tested. */
|
|
105
|
+
function ledgerStableStringify(value) {
|
|
106
|
+
return stableStringify(value);
|
|
107
|
+
}
|
|
108
|
+
/** `src/telemetry-attestation.ts`'s `stableStringify` — sorts keys
|
|
109
|
+
* recursively, AND maps a top-level `undefined` input to the literal
|
|
110
|
+
* string `"null"` (via `JSON.stringify(value) ?? "null"`). Divergent from
|
|
111
|
+
* `ledgerStableStringify` exactly at the top-level-undefined edge. */
|
|
112
|
+
function telemetryStableStringify(value) {
|
|
113
|
+
if (value === null || typeof value !== "object") {
|
|
114
|
+
return JSON.stringify(value) ?? "null";
|
|
115
|
+
}
|
|
116
|
+
if (Array.isArray(value)) {
|
|
117
|
+
return `[${value.map(telemetryStableStringify).join(",")}]`;
|
|
118
|
+
}
|
|
119
|
+
const entries = Object.keys(value)
|
|
120
|
+
.sort()
|
|
121
|
+
.map((key) => `${JSON.stringify(key)}:${telemetryStableStringify(value[key])}`);
|
|
122
|
+
return `{${entries.join(",")}}`;
|
|
123
|
+
}
|
|
124
|
+
/** `src/trust-audit.ts`'s `eventHash` input builder: JSON-round-trips the
|
|
125
|
+
* value FIRST (`JSON.parse(JSON.stringify(value))`), which DROPS every key
|
|
126
|
+
* (nested or top-level) whose value is `undefined`, and ONLY THEN runs the
|
|
127
|
+
* sort-and-stringify step. This is a pre-pass that changes the shape being
|
|
128
|
+
* hashed, not just a formatting rule on top of the same shape — so record-
|
|
129
|
+
* time hashes (over an in-memory event that may carry nested `undefined`)
|
|
130
|
+
* equal verify-time hashes (over the parsed-from-disk event, which never
|
|
131
|
+
* had those keys to begin with). Caller is responsible for stripping the
|
|
132
|
+
* `eventHash` field itself before calling this (this function hashes
|
|
133
|
+
* exactly what it is given). */
|
|
134
|
+
function eventHashInput(value) {
|
|
135
|
+
const roundTripped = JSON.parse(JSON.stringify(value));
|
|
136
|
+
return stableStringify(roundTripped);
|
|
137
|
+
}
|