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
package/dist/run-registry.js
DELETED
|
@@ -1,850 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Run Registry / Control Plane (v0.1.28) — a DERIVED, rebuildable index over the
|
|
3
|
-
// runs that live under each repo's `.cw/runs/<id>/`, plus a home-level cross-repo
|
|
4
|
-
// registry. It manages many runs across repos: search, resume, archive, queue,
|
|
5
|
-
// cross-repo history, and failed-run rerun.
|
|
6
|
-
//
|
|
7
|
-
// BSD / Unix discipline (each non-trivial choice cites its tenet):
|
|
8
|
-
//
|
|
9
|
-
// - SEPARATE MECHANISM FROM POLICY. The per-run `.cw/runs/<id>/state.json` is the
|
|
10
|
-
// SINGLE SOURCE OF TRUTH (loadRunFromCwd) and is never owned or mutated here.
|
|
11
|
-
// The registry is MECHANISM: a derived cache, rebuilt from source on demand.
|
|
12
|
-
// Retention windows, queue ordering, and archive thresholds are POLICY and live
|
|
13
|
-
// in RunRegistryPolicy / explicit flags, never baked into the index.
|
|
14
|
-
//
|
|
15
|
-
// - DERIVED, NOT AUTHORITATIVE (fail closed). Every record carries a
|
|
16
|
-
// `sourceFingerprint`; every read reports `valid|stale|absent` freshness, just
|
|
17
|
-
// like the v0.1.25 state-explosion summaries. We ALWAYS re-derive a record from
|
|
18
|
-
// source state when source is present, and surface `missing` (never a fabricated
|
|
19
|
-
// status) when it is gone. An unreadable run is never treated as success.
|
|
20
|
-
//
|
|
21
|
-
// - APPEND-ONLY HISTORY; NEVER MUTATE THE PAST. Resume continues an existing run
|
|
22
|
-
// from durable state (read-only over source). Rerun creates a NEW run that
|
|
23
|
-
// records a provenance link to the original; the failed run is preserved.
|
|
24
|
-
// Archive is an overlay mark, not a delete — source truth stays in place and
|
|
25
|
-
// stays searchable.
|
|
26
|
-
//
|
|
27
|
-
// - EXPLICIT, INSPECTABLE STATE. Cross-repo discovery and the queue are plain
|
|
28
|
-
// files under a home registry ($CW_HOME / XDG), readable and diffable. No hidden
|
|
29
|
-
// database, no daemon required to read state.
|
|
30
|
-
//
|
|
31
|
-
// - STABLE INTERFACES. Pre-v0.1.28 single-repo runs keep working with an empty /
|
|
32
|
-
// rebuildable registry; nothing about `.cw/runs/` layout changes.
|
|
33
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
34
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
35
|
-
};
|
|
36
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.formatQueueList = exports.formatHistory = exports.formatResume = exports.formatGcVerify = exports.formatGcRun = exports.formatGcPlan = exports.formatRunShow = exports.formatRunSearch = exports.formatRegistryReport = exports.RunRegistry = exports.RUN_REGISTRY_SCHEMA_VERSION = exports.DEFAULT_RUN_REGISTRY_POLICY = exports.isRunLifecycleState = exports.compareQueue = void 0;
|
|
38
|
-
exports.resolveCwHome = resolveCwHome;
|
|
39
|
-
exports.deriveLifecycle = deriveLifecycle;
|
|
40
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
41
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
42
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
43
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
44
|
-
const state_1 = require("./state");
|
|
45
|
-
// planReclamation/runReclamation/verifyReclamation/ReclamationError moved with the
|
|
46
|
-
// GC cluster into ./run-registry/gc (FreeBSD-audit R2 deep).
|
|
47
|
-
const compare_1 = require("./compare");
|
|
48
|
-
const derive_1 = require("./run-registry/derive");
|
|
49
|
-
Object.defineProperty(exports, "compareQueue", { enumerable: true, get: function () { return derive_1.compareQueue; } });
|
|
50
|
-
Object.defineProperty(exports, "isRunLifecycleState", { enumerable: true, get: function () { return derive_1.isRunLifecycleState; } });
|
|
51
|
-
const gc_1 = require("./run-registry/gc");
|
|
52
|
-
const queue_1 = require("./run-registry/queue");
|
|
53
|
-
const policy_1 = require("./run-registry/policy");
|
|
54
|
-
Object.defineProperty(exports, "DEFAULT_RUN_REGISTRY_POLICY", { enumerable: true, get: function () { return policy_1.DEFAULT_RUN_REGISTRY_POLICY; } });
|
|
55
|
-
Object.defineProperty(exports, "RUN_REGISTRY_SCHEMA_VERSION", { enumerable: true, get: function () { return policy_1.RUN_REGISTRY_SCHEMA_VERSION; } });
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Home registry location (EXPLICIT, INSPECTABLE STATE)
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
/** Resolve the home registry root: CW_HOME, then XDG_STATE_HOME/cool-workflow,
|
|
60
|
-
* then ~/.local/state/cool-workflow. Always a plain directory of plain files. */
|
|
61
|
-
function resolveCwHome(env = process.env) {
|
|
62
|
-
if (env.CW_HOME && String(env.CW_HOME).trim())
|
|
63
|
-
return node_path_1.default.resolve(String(env.CW_HOME));
|
|
64
|
-
if (env.XDG_STATE_HOME && String(env.XDG_STATE_HOME).trim()) {
|
|
65
|
-
return node_path_1.default.join(node_path_1.default.resolve(String(env.XDG_STATE_HOME)), "cool-workflow");
|
|
66
|
-
}
|
|
67
|
-
return node_path_1.default.join(node_os_1.default.homedir(), ".local", "state", "cool-workflow");
|
|
68
|
-
}
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// Fingerprints (same shape/strength as state-explosion's)
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
function fingerprintStrings(values) {
|
|
73
|
-
const hash = node_crypto_1.default.createHash("sha256");
|
|
74
|
-
hash.update(JSON.stringify([...values].sort()));
|
|
75
|
-
return `sha256:${hash.digest("hex").slice(0, 32)}`;
|
|
76
|
-
}
|
|
77
|
-
/** Content fingerprint of a run's source state.json. Structural, not just mtime,
|
|
78
|
-
* so a tampered task status trips `stale` even if updatedAt is unchanged. */
|
|
79
|
-
function fingerprintRun(run) {
|
|
80
|
-
const parts = [
|
|
81
|
-
`id:${run.id}`,
|
|
82
|
-
`updatedAt:${run.updatedAt}`,
|
|
83
|
-
`loopStage:${run.loopStage}`,
|
|
84
|
-
`schema:${run.schemaVersion}`
|
|
85
|
-
];
|
|
86
|
-
for (const task of [...run.tasks].sort((a, b) => (0, compare_1.compareBytes)(a.id, b.id))) {
|
|
87
|
-
parts.push(`task:${task.id}:${task.status}`);
|
|
88
|
-
}
|
|
89
|
-
for (const commit of [...run.commits].sort((a, b) => (0, compare_1.compareBytes)(a.id, b.id))) {
|
|
90
|
-
parts.push(`commit:${commit.id}:${commit.verifierGated ? "gated" : "checkpoint"}`);
|
|
91
|
-
}
|
|
92
|
-
for (const phase of [...run.phases].sort((a, b) => (0, compare_1.compareBytes)(a.id, b.id))) {
|
|
93
|
-
parts.push(`phase:${phase.id}:${phase.status}`);
|
|
94
|
-
}
|
|
95
|
-
for (const fb of [...(run.feedback || [])].sort((a, b) => (0, compare_1.compareBytes)(a.id, b.id))) {
|
|
96
|
-
parts.push(`feedback:${fb.id}:${fb.status}`);
|
|
97
|
-
}
|
|
98
|
-
return fingerprintStrings(parts);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Classify a run's lifecycle purely from its source state. First match wins:
|
|
102
|
-
* 1. running > 0 -> running
|
|
103
|
-
* 2. openFeedback > 0 -> blocked (failures under correction)
|
|
104
|
-
* 3. failed > 0 -> failed
|
|
105
|
-
* 4. total > 0 && completed === total -> completed
|
|
106
|
-
* 5. verifierGatedCommits > 0 && pending === 0 -> completed (commit-only runs)
|
|
107
|
-
* 6. completed > 0 -> running (mid-flight)
|
|
108
|
-
* 7. otherwise -> queued
|
|
109
|
-
* The classifier never invents status; `archived` is applied as an overlay on
|
|
110
|
-
* top of this by deriveRecord, which keeps `derivedLifecycle` for search.
|
|
111
|
-
*/
|
|
112
|
-
function deriveLifecycle(input) {
|
|
113
|
-
if (input.running > 0)
|
|
114
|
-
return "running";
|
|
115
|
-
if (input.openFeedback > 0)
|
|
116
|
-
return "blocked";
|
|
117
|
-
if (input.failed > 0)
|
|
118
|
-
return "failed";
|
|
119
|
-
if (input.total > 0 && input.completed === input.total)
|
|
120
|
-
return "completed";
|
|
121
|
-
if (input.verifierGatedCommits > 0 && input.pending === 0)
|
|
122
|
-
return "completed";
|
|
123
|
-
if (input.completed > 0)
|
|
124
|
-
return "running";
|
|
125
|
-
return "queued";
|
|
126
|
-
}
|
|
127
|
-
function lifecycleInputs(run) {
|
|
128
|
-
const tasks = run.tasks || [];
|
|
129
|
-
return {
|
|
130
|
-
total: tasks.length,
|
|
131
|
-
pending: tasks.filter((t) => t.status === "pending").length,
|
|
132
|
-
running: tasks.filter((t) => t.status === "running").length,
|
|
133
|
-
failed: tasks.filter((t) => t.status === "failed").length,
|
|
134
|
-
completed: tasks.filter((t) => t.status === "completed").length,
|
|
135
|
-
verifierGatedCommits: (run.commits || []).filter((c) => c.verifierGated).length,
|
|
136
|
-
openFeedback: (run.feedback || []).filter((f) => f.status === "open" || f.status === "tasked").length,
|
|
137
|
-
loopStage: run.loopStage
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
// ---------------------------------------------------------------------------
|
|
141
|
-
// The registry
|
|
142
|
-
// ---------------------------------------------------------------------------
|
|
143
|
-
class RunRegistry {
|
|
144
|
-
repoRoot;
|
|
145
|
-
homeRoot;
|
|
146
|
-
planner;
|
|
147
|
-
constructor(cwd = process.cwd(), planner, env = process.env) {
|
|
148
|
-
this.repoRoot = node_path_1.default.resolve(cwd);
|
|
149
|
-
this.homeRoot = resolveCwHome(env);
|
|
150
|
-
this.planner = planner;
|
|
151
|
-
}
|
|
152
|
-
// ---- path helpers -------------------------------------------------------
|
|
153
|
-
repoRunsDir(repo) {
|
|
154
|
-
return node_path_1.default.join(repo, ".cw", "runs");
|
|
155
|
-
}
|
|
156
|
-
repoRegistryDir(repo) {
|
|
157
|
-
return node_path_1.default.join(repo, ".cw", "registry");
|
|
158
|
-
}
|
|
159
|
-
// Public so the carved queue cluster (run-registry/queue.ts) can resolve the
|
|
160
|
-
// home-registry dir without reaching into private state (QueueHost).
|
|
161
|
-
homeRegistryDir() {
|
|
162
|
-
return node_path_1.default.join(this.homeRoot, "registry");
|
|
163
|
-
}
|
|
164
|
-
// ---- per-repo overlays (plain files) ------------------------------------
|
|
165
|
-
// Overlay reads distinguish ABSENT (clean default) from PRESENT-but-corrupt
|
|
166
|
-
// (fail closed). readJson throws `Invalid JSON in <file>` on a present file
|
|
167
|
-
// that won't parse; we let that propagate instead of swallowing it. Swallowing
|
|
168
|
-
// is the absent-vs-corrupt conflation telemetry-ledger.ts flags as the bug that
|
|
169
|
-
// "let a corrupt overlay verify green" — here it would silently un-archive every
|
|
170
|
-
// archived run / drop every provenance link. This is authoritative durable state.
|
|
171
|
-
// A present overlay must parse to a JSON OBJECT. readJson already fails closed
|
|
172
|
-
// on unparseable bytes; this catches the next shape over: valid JSON that is
|
|
173
|
-
// `null`, an array, or a scalar. Without it `parsed.archived` throws a cryptic
|
|
174
|
-
// TypeError (null) or silently reads `undefined` (array) and the whole registry
|
|
175
|
-
// scan breaks. Fail closed with a clear message instead.
|
|
176
|
-
requireOverlayObject(parsed, file) {
|
|
177
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
178
|
-
throw new Error(`Corrupt overlay ${file}: expected a JSON object, got ${Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed}`);
|
|
179
|
-
}
|
|
180
|
-
return parsed;
|
|
181
|
-
}
|
|
182
|
-
loadArchiveOverlay(repo) {
|
|
183
|
-
const file = node_path_1.default.join(this.repoRegistryDir(repo), "archive.json");
|
|
184
|
-
if (!node_fs_1.default.existsSync(file))
|
|
185
|
-
return { schemaVersion: 1, archived: {} };
|
|
186
|
-
const parsed = this.requireOverlayObject((0, state_1.readJson)(file), file);
|
|
187
|
-
return { schemaVersion: 1, archived: parsed.archived || {} };
|
|
188
|
-
}
|
|
189
|
-
loadProvenanceOverlay(repo) {
|
|
190
|
-
const file = node_path_1.default.join(this.repoRegistryDir(repo), "provenance.json");
|
|
191
|
-
if (!node_fs_1.default.existsSync(file))
|
|
192
|
-
return { schemaVersion: 1, links: {} };
|
|
193
|
-
const parsed = this.requireOverlayObject((0, state_1.readJson)(file), file);
|
|
194
|
-
return { schemaVersion: 1, links: parsed.links || {} };
|
|
195
|
-
}
|
|
196
|
-
loadRepoOverlays(repo) {
|
|
197
|
-
return {
|
|
198
|
-
archive: this.loadArchiveOverlay(repo),
|
|
199
|
-
provenance: this.loadProvenanceOverlay(repo)
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
/** Default queue priority from POLICY (QueueHost). Exposed so the carved queue
|
|
203
|
-
* cluster never re-derives policy. */
|
|
204
|
-
get defaultQueuePriority() {
|
|
205
|
-
return policy_1.DEFAULT_RUN_REGISTRY_POLICY.defaultQueuePriority;
|
|
206
|
-
}
|
|
207
|
-
// ---- home registry files ------------------------------------------------
|
|
208
|
-
reposFilePath() {
|
|
209
|
-
return node_path_1.default.join(this.homeRegistryDir(), "repos.json");
|
|
210
|
-
}
|
|
211
|
-
loadRepos() {
|
|
212
|
-
const file = this.reposFilePath();
|
|
213
|
-
// Absent => no registered repos. Present-but-corrupt must fail closed: a
|
|
214
|
-
// swallowed parse error here silently drops every cross-repo root the
|
|
215
|
-
// operator registered, shrinking the home index to the current repo with no
|
|
216
|
-
// signal. Let readJson's `Invalid JSON` throw surface the corruption.
|
|
217
|
-
if (!node_fs_1.default.existsSync(file))
|
|
218
|
-
return { schemaVersion: 1, repos: [] };
|
|
219
|
-
const parsed = this.requireOverlayObject((0, state_1.readJson)(file), file);
|
|
220
|
-
return { schemaVersion: 1, repos: Array.isArray(parsed.repos) ? parsed.repos : [] };
|
|
221
|
-
}
|
|
222
|
-
/** Persisted union of registered repo roots and the current repo, deduped and
|
|
223
|
-
* sorted. Read-only: does NOT write repos.json (reads stay pure). */
|
|
224
|
-
knownRepos() {
|
|
225
|
-
const roots = new Set([this.repoRoot]);
|
|
226
|
-
for (const entry of this.loadRepos().repos)
|
|
227
|
-
roots.add(node_path_1.default.resolve(entry.root));
|
|
228
|
-
return [...roots].sort();
|
|
229
|
-
}
|
|
230
|
-
/** Register a repo root into the home repos.json (idempotent). Only mutating
|
|
231
|
-
* operations call this; reads never do. */
|
|
232
|
-
registerRepo(repo = this.repoRoot) {
|
|
233
|
-
const resolved = node_path_1.default.resolve(repo);
|
|
234
|
-
const file = this.reposFilePath();
|
|
235
|
-
// Cross-process read-modify-write: lock so a concurrent register can't drop a
|
|
236
|
-
// repo (v0.1.40, P1-D), and persist durably.
|
|
237
|
-
return (0, state_1.withFileLock)(file, () => {
|
|
238
|
-
const current = this.loadRepos();
|
|
239
|
-
const already = current.repos.some((entry) => node_path_1.default.resolve(entry.root) === resolved);
|
|
240
|
-
if (!already)
|
|
241
|
-
current.repos.push({ root: resolved, addedAt: new Date().toISOString() });
|
|
242
|
-
current.repos.sort((a, b) => (0, compare_1.compareBytes)(a.root, b.root));
|
|
243
|
-
(0, state_1.writeJson)(file, current, { durable: true });
|
|
244
|
-
return { registered: !already, repos: current.repos.map((entry) => entry.root) };
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
// Queue file helpers + queueAdd/List/Show/Drain now live in ./run-registry/queue
|
|
248
|
-
// (FreeBSD-audit R2 deep). These remain as thin delegators; `this` satisfies the
|
|
249
|
-
// QueueHost contract structurally (repoRoot, defaultQueuePriority,
|
|
250
|
-
// homeRegistryDir, registerRepo).
|
|
251
|
-
loadQueue() {
|
|
252
|
-
return (0, queue_1.loadQueue)(this);
|
|
253
|
-
}
|
|
254
|
-
// Public queue accessors for the v0.1.37 control-plane scheduler (it operates ON
|
|
255
|
-
// this queue store via pure functions in scheduling.ts; the queue file is never
|
|
256
|
-
// duplicated). The scheduling-policy file lives beside the queue in the home
|
|
257
|
-
// registry, plain and diffable.
|
|
258
|
-
loadQueueEntries() {
|
|
259
|
-
return this.loadQueue();
|
|
260
|
-
}
|
|
261
|
-
saveQueueEntries(entries) {
|
|
262
|
-
(0, queue_1.saveQueue)(this, entries);
|
|
263
|
-
}
|
|
264
|
-
schedulingPolicyPath() {
|
|
265
|
-
return node_path_1.default.join(this.homeRegistryDir(), "scheduling-policy.json");
|
|
266
|
-
}
|
|
267
|
-
// ---- record derivation (always from source) -----------------------------
|
|
268
|
-
/** Derive a RunRecord from a run directory's source state.json. Returns the
|
|
269
|
-
* record, or null when source is unreadable/unsupported (caller decides how to
|
|
270
|
-
* surface `missing` — we never fabricate a status). */
|
|
271
|
-
deriveRecord(repo, runDir, overlays = this.loadRepoOverlays(repo)) {
|
|
272
|
-
const statePath = node_path_1.default.join(runDir, "state.json");
|
|
273
|
-
if (!node_fs_1.default.existsSync(statePath))
|
|
274
|
-
return null;
|
|
275
|
-
let run;
|
|
276
|
-
try {
|
|
277
|
-
const result = (0, state_1.loadRunStateFile)(statePath, { dryRun: true });
|
|
278
|
-
if (result.report.status === "unsupported")
|
|
279
|
-
return null;
|
|
280
|
-
run = result.run;
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
const li = lifecycleInputs(run);
|
|
286
|
-
const derived = deriveLifecycle(li);
|
|
287
|
-
const archive = overlays.archive.archived[run.id];
|
|
288
|
-
const provenance = overlays.provenance.links[run.id];
|
|
289
|
-
// Run Retention & Provable Reclamation (v0.1.39): the per-run reclaimed.json
|
|
290
|
-
// overlay (if any) raises the disk-tier above `archived` and downgrades the
|
|
291
|
-
// capability. Derived from source, never invented.
|
|
292
|
-
const reclaim = (0, derive_1.loadReclaimedFromDir)(runDir);
|
|
293
|
-
const lastTombstone = reclaim.tombstones[reclaim.tombstones.length - 1];
|
|
294
|
-
const tier = lastTombstone ? "reclaimed" : archive ? "archived" : "live";
|
|
295
|
-
const capability = lastTombstone ? lastTombstone.capability : "re-runnable";
|
|
296
|
-
const capabilityReason = lastTombstone
|
|
297
|
-
? lastTombstone.capabilityReason
|
|
298
|
-
: archive
|
|
299
|
-
? "archived-full"
|
|
300
|
-
: "live-full";
|
|
301
|
-
return {
|
|
302
|
-
schemaVersion: 1,
|
|
303
|
-
runId: run.id,
|
|
304
|
-
appId: run.workflow.app?.id,
|
|
305
|
-
appVersion: run.workflow.app?.version,
|
|
306
|
-
workflowId: run.workflow.id,
|
|
307
|
-
title: run.workflow.title,
|
|
308
|
-
repo,
|
|
309
|
-
runDir,
|
|
310
|
-
statePath,
|
|
311
|
-
createdAt: run.createdAt,
|
|
312
|
-
updatedAt: run.updatedAt,
|
|
313
|
-
loopStage: run.loopStage,
|
|
314
|
-
lifecycle: lastTombstone ? "reclaimed" : archive ? "archived" : derived,
|
|
315
|
-
derivedLifecycle: derived,
|
|
316
|
-
archived: Boolean(archive),
|
|
317
|
-
archivedAt: archive?.archivedAt,
|
|
318
|
-
archiveReason: archive?.reason,
|
|
319
|
-
tier,
|
|
320
|
-
capability,
|
|
321
|
-
capabilityReason,
|
|
322
|
-
reclaimedAt: lastTombstone?.reclaimedAt,
|
|
323
|
-
reclaimedBytes: reclaim.tombstones.reduce((sum, t) => sum + (t.bytesFreed || 0), 0) || undefined,
|
|
324
|
-
tombstoneHash: lastTombstone?.tombstoneHash,
|
|
325
|
-
tasks: {
|
|
326
|
-
total: li.total,
|
|
327
|
-
pending: li.pending,
|
|
328
|
-
running: li.running,
|
|
329
|
-
failed: li.failed,
|
|
330
|
-
completed: li.completed
|
|
331
|
-
},
|
|
332
|
-
commitCount: (run.commits || []).length,
|
|
333
|
-
verifierGatedCommitCount: li.verifierGatedCommits,
|
|
334
|
-
openFeedbackCount: li.openFeedback,
|
|
335
|
-
backends: (0, derive_1.distinctBackends)(run),
|
|
336
|
-
inputsDigest: (0, derive_1.digestInputs)(run.inputs),
|
|
337
|
-
sourceFingerprint: fingerprintRun(run),
|
|
338
|
-
freshness: "valid",
|
|
339
|
-
provenance
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
/** Scan one repo's `.cw/runs/` and derive a record per run, deterministically
|
|
343
|
-
* ordered (createdAt asc, then runId). Unreadable runs are skipped here; the
|
|
344
|
-
* freshness layer is responsible for reporting persisted-but-missing runs. */
|
|
345
|
-
scanRepo(repo) {
|
|
346
|
-
const runsDir = this.repoRunsDir(repo);
|
|
347
|
-
if (!node_fs_1.default.existsSync(runsDir))
|
|
348
|
-
return [];
|
|
349
|
-
const overlays = this.loadRepoOverlays(repo);
|
|
350
|
-
const records = [];
|
|
351
|
-
for (const entry of node_fs_1.default.readdirSync(runsDir, { withFileTypes: true })) {
|
|
352
|
-
if (!entry.isDirectory())
|
|
353
|
-
continue;
|
|
354
|
-
const record = this.deriveRecord(repo, node_path_1.default.join(runsDir, entry.name), overlays);
|
|
355
|
-
if (record)
|
|
356
|
-
records.push(record);
|
|
357
|
-
}
|
|
358
|
-
return records.sort(derive_1.compareRecords);
|
|
359
|
-
}
|
|
360
|
-
// ---- index construction (current truth) ---------------------------------
|
|
361
|
-
/** Build the CURRENT index fresh from source for the requested scope. This is
|
|
362
|
-
* the authoritative-from-source view; persistence/freshness is layered on top. */
|
|
363
|
-
buildIndex(scope) {
|
|
364
|
-
const repos = scope === "home" ? this.knownRepos() : [this.repoRoot];
|
|
365
|
-
const records = [];
|
|
366
|
-
for (const repo of repos)
|
|
367
|
-
records.push(...this.scanRepo(repo));
|
|
368
|
-
records.sort(derive_1.compareRecords);
|
|
369
|
-
const queue = scope === "home" ? this.loadQueue() : this.loadQueue().filter((q) => node_path_1.default.resolve(q.repo) === this.repoRoot);
|
|
370
|
-
const sourceFingerprint = fingerprintStrings([
|
|
371
|
-
...repos.map((r) => `repo:${r}`),
|
|
372
|
-
...records.map((r) => `${r.runId}:${r.sourceFingerprint}:${r.lifecycle}`)
|
|
373
|
-
]);
|
|
374
|
-
return {
|
|
375
|
-
schemaVersion: 1,
|
|
376
|
-
scope,
|
|
377
|
-
root: scope === "home" ? this.homeRoot : this.repoRoot,
|
|
378
|
-
generatedAt: new Date().toISOString(),
|
|
379
|
-
sourceFingerprint,
|
|
380
|
-
repos,
|
|
381
|
-
records,
|
|
382
|
-
queue,
|
|
383
|
-
counts: (0, derive_1.countRecords)(records)
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
persistedIndexPath(scope) {
|
|
387
|
-
return scope === "home"
|
|
388
|
-
? node_path_1.default.join(this.homeRegistryDir(), "index.json")
|
|
389
|
-
: node_path_1.default.join(this.repoRegistryDir(this.repoRoot), "index.json");
|
|
390
|
-
}
|
|
391
|
-
loadPersistedIndex(scope) {
|
|
392
|
-
const file = this.persistedIndexPath(scope);
|
|
393
|
-
if (!node_fs_1.default.existsSync(file))
|
|
394
|
-
return undefined;
|
|
395
|
-
try {
|
|
396
|
-
const parsed = (0, state_1.readJson)(file);
|
|
397
|
-
if (!parsed || parsed.schemaVersion !== 1)
|
|
398
|
-
return undefined;
|
|
399
|
-
return parsed;
|
|
400
|
-
}
|
|
401
|
-
catch {
|
|
402
|
-
return undefined;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
/** Refresh (recompute and persist) the index. registers the current repo into
|
|
406
|
-
* the home registry so cross-repo discovery finds it later. MECHANISM only:
|
|
407
|
-
* never touches source state.json. */
|
|
408
|
-
refresh(options = {}) {
|
|
409
|
-
const scope = options.scope || "repo";
|
|
410
|
-
// Registering the current repo is what makes a single-repo run discoverable
|
|
411
|
-
// cross-repo. Always safe (idempotent) and never mutates run source.
|
|
412
|
-
this.registerRepo(this.repoRoot);
|
|
413
|
-
const index = this.buildIndex(scope);
|
|
414
|
-
(0, state_1.writeJson)(this.persistedIndexPath(scope), index);
|
|
415
|
-
if (scope === "repo") {
|
|
416
|
-
// A repo refresh also keeps the home aggregate fresh enough to discover this
|
|
417
|
-
// repo's runs, without forcing a full cross-repo rebuild.
|
|
418
|
-
const homeIndex = this.buildIndex("home");
|
|
419
|
-
(0, state_1.writeJson)(this.persistedIndexPath("home"), homeIndex);
|
|
420
|
-
}
|
|
421
|
-
return this.report(scope, index);
|
|
422
|
-
}
|
|
423
|
-
/** Read the index with explicit freshness against current source. Re-derives
|
|
424
|
-
* every record from source (never fabricates); compares to the persisted cache
|
|
425
|
-
* to report valid|stale|absent + staleRuns/missingRuns. */
|
|
426
|
-
show(options = {}) {
|
|
427
|
-
const scope = options.scope || "repo";
|
|
428
|
-
return this.report(scope, this.buildIndex(scope));
|
|
429
|
-
}
|
|
430
|
-
report(scope, current) {
|
|
431
|
-
const persisted = this.loadPersistedIndex(scope);
|
|
432
|
-
const currentById = new Map(current.records.map((r) => [r.runId, r]));
|
|
433
|
-
let status = persisted ? "valid" : "absent";
|
|
434
|
-
const staleRuns = [];
|
|
435
|
-
const missingRuns = [];
|
|
436
|
-
if (persisted) {
|
|
437
|
-
if (persisted.sourceFingerprint !== current.sourceFingerprint)
|
|
438
|
-
status = "stale";
|
|
439
|
-
for (const prior of persisted.records) {
|
|
440
|
-
const now = currentById.get(prior.runId);
|
|
441
|
-
if (!now) {
|
|
442
|
-
missingRuns.push(prior.runId);
|
|
443
|
-
}
|
|
444
|
-
else if (now.sourceFingerprint !== prior.sourceFingerprint) {
|
|
445
|
-
staleRuns.push(prior.runId);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
if (staleRuns.length || missingRuns.length)
|
|
449
|
-
status = "stale";
|
|
450
|
-
}
|
|
451
|
-
const refreshCmd = scope === "home" ? "node scripts/cw.js registry refresh --scope home" : "node scripts/cw.js registry refresh";
|
|
452
|
-
return {
|
|
453
|
-
schemaVersion: 1,
|
|
454
|
-
scope,
|
|
455
|
-
root: current.root,
|
|
456
|
-
generatedAt: current.generatedAt,
|
|
457
|
-
freshness: {
|
|
458
|
-
status,
|
|
459
|
-
persistedFingerprint: persisted?.sourceFingerprint,
|
|
460
|
-
currentFingerprint: current.sourceFingerprint,
|
|
461
|
-
staleRuns: staleRuns.sort(),
|
|
462
|
-
missingRuns: missingRuns.sort()
|
|
463
|
-
},
|
|
464
|
-
index: current,
|
|
465
|
-
counts: current.counts,
|
|
466
|
-
nextAction: status === "valid" ? "node scripts/cw.js run search" : refreshCmd
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
// ---- search (deterministic, paginated) ----------------------------------
|
|
470
|
-
search(raw = {}) {
|
|
471
|
-
const scope = raw.scope || "home";
|
|
472
|
-
const index = this.buildIndex(scope);
|
|
473
|
-
const report = this.report(scope, index);
|
|
474
|
-
const query = {
|
|
475
|
-
text: (0, derive_1.optionalLower)(raw.text),
|
|
476
|
-
app: (0, derive_1.optionalLower)(raw.app),
|
|
477
|
-
status: raw.status,
|
|
478
|
-
repo: raw.repo ? node_path_1.default.resolve(raw.repo) : undefined,
|
|
479
|
-
since: raw.since,
|
|
480
|
-
until: raw.until,
|
|
481
|
-
includeArchived: raw.includeArchived ?? true,
|
|
482
|
-
offset: (0, derive_1.clampInt)(raw.offset, 0, 0),
|
|
483
|
-
limit: (0, derive_1.clampInt)(raw.limit, 50, 1)
|
|
484
|
-
};
|
|
485
|
-
let records = index.records.filter((record) => (0, derive_1.matchesQuery)(record, query));
|
|
486
|
-
if (!query.includeArchived)
|
|
487
|
-
records = records.filter((record) => !record.archived);
|
|
488
|
-
records.sort(derive_1.compareRecords);
|
|
489
|
-
const total = records.length;
|
|
490
|
-
const page = records.slice(query.offset, query.offset + query.limit);
|
|
491
|
-
return {
|
|
492
|
-
schemaVersion: 1,
|
|
493
|
-
scope,
|
|
494
|
-
query,
|
|
495
|
-
freshness: report.freshness.status,
|
|
496
|
-
total,
|
|
497
|
-
offset: query.offset,
|
|
498
|
-
limit: query.limit,
|
|
499
|
-
records: page,
|
|
500
|
-
nextAction: report.freshness.status === "valid"
|
|
501
|
-
? "node scripts/cw.js run show <run-id>"
|
|
502
|
-
: "node scripts/cw.js registry refresh"
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
list(options = {}) {
|
|
506
|
-
return this.search({
|
|
507
|
-
scope: options.scope || "home",
|
|
508
|
-
includeArchived: options.includeArchived ?? true,
|
|
509
|
-
limit: options.limit,
|
|
510
|
-
offset: options.offset
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
// ---- resolve one run by id (cross-repo, fail-closed) --------------------
|
|
514
|
-
/** Resolve a run by id, preferring the current repo, then any registered repo.
|
|
515
|
-
* Returns found=false with freshness `missing` (and the last-known persisted
|
|
516
|
-
* record, clearly flagged) when source is gone. */
|
|
517
|
-
showRun(runId, options = {}) {
|
|
518
|
-
const scope = options.scope || "home";
|
|
519
|
-
const located = this.locate(runId, scope);
|
|
520
|
-
if (located) {
|
|
521
|
-
return {
|
|
522
|
-
schemaVersion: 1,
|
|
523
|
-
runId,
|
|
524
|
-
found: true,
|
|
525
|
-
freshness: "valid",
|
|
526
|
-
resolvedFrom: located.from,
|
|
527
|
-
repo: located.record.repo,
|
|
528
|
-
record: located.record,
|
|
529
|
-
nextAction: located.record.archived
|
|
530
|
-
? "node scripts/cw.js run resume " + runId
|
|
531
|
-
: "node scripts/cw.js run show " + runId
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
// Not present in source. Surface the last-known persisted record (if any),
|
|
535
|
-
// flagged `missing` — never as a live status.
|
|
536
|
-
const persisted = this.findPersisted(runId, scope);
|
|
537
|
-
return {
|
|
538
|
-
schemaVersion: 1,
|
|
539
|
-
runId,
|
|
540
|
-
found: false,
|
|
541
|
-
freshness: "missing",
|
|
542
|
-
repo: persisted?.repo,
|
|
543
|
-
persisted,
|
|
544
|
-
nextAction: "node scripts/cw.js registry refresh" + (scope === "home" ? " --scope home" : "")
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
// Public so the carved gc cluster (run-registry/gc.ts) can resolve a run
|
|
548
|
-
// repo-first without reaching into private state (GcHost).
|
|
549
|
-
locate(runId, scope) {
|
|
550
|
-
// Current repo first (least astonishment: cwd wins).
|
|
551
|
-
const here = this.deriveRecordForRun(this.repoRoot, runId);
|
|
552
|
-
if (here)
|
|
553
|
-
return { record: here, from: "repo" };
|
|
554
|
-
if (scope === "repo")
|
|
555
|
-
return undefined;
|
|
556
|
-
for (const repo of this.knownRepos()) {
|
|
557
|
-
if (node_path_1.default.resolve(repo) === this.repoRoot)
|
|
558
|
-
continue;
|
|
559
|
-
const record = this.deriveRecordForRun(repo, runId);
|
|
560
|
-
if (record)
|
|
561
|
-
return { record, from: "home" };
|
|
562
|
-
}
|
|
563
|
-
return undefined;
|
|
564
|
-
}
|
|
565
|
-
deriveRecordForRun(repo, runId) {
|
|
566
|
-
const runDir = node_path_1.default.join(this.repoRunsDir(repo), runId);
|
|
567
|
-
if (!node_fs_1.default.existsSync(node_path_1.default.join(runDir, "state.json")))
|
|
568
|
-
return null;
|
|
569
|
-
return this.deriveRecord(repo, runDir);
|
|
570
|
-
}
|
|
571
|
-
findPersisted(runId, scope) {
|
|
572
|
-
for (const s of scope === "home" ? ["home", "repo"] : ["repo"]) {
|
|
573
|
-
const persisted = this.loadPersistedIndex(s);
|
|
574
|
-
const hit = persisted?.records.find((r) => r.runId === runId);
|
|
575
|
-
if (hit)
|
|
576
|
-
return hit;
|
|
577
|
-
}
|
|
578
|
-
return undefined;
|
|
579
|
-
}
|
|
580
|
-
// Public so the carved gc cluster (run-registry/gc.ts) can load source state
|
|
581
|
-
// for a resolved run without reaching into private state (GcHost).
|
|
582
|
-
loadRun(repo, runId) {
|
|
583
|
-
const statePath = node_path_1.default.join(this.repoRunsDir(repo), runId, "state.json");
|
|
584
|
-
if (!node_fs_1.default.existsSync(statePath))
|
|
585
|
-
throw new Error(`Run not found: ${runId}`);
|
|
586
|
-
const result = (0, state_1.loadRunStateFile)(statePath, { dryRun: true });
|
|
587
|
-
if (result.report.status === "unsupported") {
|
|
588
|
-
throw new Error(`Unsupported run state for ${runId}: ${result.report.errors.join("; ")}`);
|
|
589
|
-
}
|
|
590
|
-
return result.run;
|
|
591
|
-
}
|
|
592
|
-
// ---- resume (continue from durable state; read-only over source) --------
|
|
593
|
-
resume(runId, options = {}) {
|
|
594
|
-
const scope = options.scope || "home";
|
|
595
|
-
const located = this.locate(runId, scope);
|
|
596
|
-
if (!located) {
|
|
597
|
-
throw new Error(`Cannot resume: run ${runId} not found in source state (fail closed; try registry refresh).`);
|
|
598
|
-
}
|
|
599
|
-
const record = located.record;
|
|
600
|
-
const run = this.loadRun(record.repo, runId);
|
|
601
|
-
const limit = (0, derive_1.clampInt)(options.limit, 5, 1);
|
|
602
|
-
const nextTasks = (run.tasks || [])
|
|
603
|
-
.filter((t) => t.status === "pending" || t.status === "running")
|
|
604
|
-
.slice(0, limit)
|
|
605
|
-
.map((t) => ({ id: t.id, phase: t.phase, status: t.status, taskPath: t.taskPath }));
|
|
606
|
-
const terminal = record.derivedLifecycle === "completed" || record.derivedLifecycle === "failed";
|
|
607
|
-
const resumable = nextTasks.length > 0 || (!terminal && record.derivedLifecycle !== "completed");
|
|
608
|
-
const nextActions = [];
|
|
609
|
-
if (nextTasks.length) {
|
|
610
|
-
nextActions.push({
|
|
611
|
-
command: `node scripts/cw.js dispatch ${runId} --cwd ${record.repo}`,
|
|
612
|
-
reason: `Continue ${nextTasks.length} pending/running task(s) from durable state.`
|
|
613
|
-
});
|
|
614
|
-
nextActions.push({
|
|
615
|
-
command: `node scripts/cw.js multi-agent step ${runId} --cwd ${record.repo}`,
|
|
616
|
-
reason: "Take one deterministic host step without spawning agents."
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
else if (record.derivedLifecycle === "failed") {
|
|
620
|
-
nextActions.push({
|
|
621
|
-
command: `node scripts/cw.js run rerun ${runId}`,
|
|
622
|
-
reason: "Run terminated as failed with no runnable tasks; rerun as a new linked run."
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
nextActions.push({
|
|
627
|
-
command: `node scripts/cw.js status ${runId} --cwd ${record.repo} --json`,
|
|
628
|
-
reason: "No runnable tasks remain; inspect status.",
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
return {
|
|
632
|
-
schemaVersion: 1,
|
|
633
|
-
runId,
|
|
634
|
-
repo: record.repo,
|
|
635
|
-
runDir: record.runDir,
|
|
636
|
-
statePath: record.statePath,
|
|
637
|
-
resolvedFrom: located.from,
|
|
638
|
-
lifecycle: record.lifecycle,
|
|
639
|
-
derivedLifecycle: record.derivedLifecycle,
|
|
640
|
-
loopStage: record.loopStage,
|
|
641
|
-
freshness: "valid",
|
|
642
|
-
resumable,
|
|
643
|
-
reason: record.archived ? "Run is archived; resuming reads durable state without un-archiving." : undefined,
|
|
644
|
-
record,
|
|
645
|
-
nextTasks,
|
|
646
|
-
nextActions
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
// ---- archive (overlay mark; never deletes source) -----------------------
|
|
650
|
-
archive(runId, options = {}) {
|
|
651
|
-
const scope = options.scope || "home";
|
|
652
|
-
const located = this.locate(runId, scope);
|
|
653
|
-
if (!located)
|
|
654
|
-
throw new Error(`Cannot archive: run ${runId} not found in source state (fail closed).`);
|
|
655
|
-
const repo = located.record.repo;
|
|
656
|
-
const file = node_path_1.default.join(this.repoRegistryDir(repo), "archive.json");
|
|
657
|
-
// Lock the archive-overlay read-modify-write (v0.1.40, P1-D) + durable write.
|
|
658
|
-
(0, state_1.withFileLock)(file, () => {
|
|
659
|
-
const overlay = this.loadArchiveOverlay(repo);
|
|
660
|
-
if (options.unarchive) {
|
|
661
|
-
delete overlay.archived[runId];
|
|
662
|
-
}
|
|
663
|
-
else {
|
|
664
|
-
overlay.archived[runId] = { archivedAt: new Date().toISOString(), reason: options.reason };
|
|
665
|
-
}
|
|
666
|
-
(0, state_1.writeJson)(file, overlay, { durable: true });
|
|
667
|
-
});
|
|
668
|
-
const record = this.deriveRecord(repo, located.record.runDir);
|
|
669
|
-
return {
|
|
670
|
-
runId,
|
|
671
|
-
repo,
|
|
672
|
-
archived: record.archived,
|
|
673
|
-
archivedAt: record.archivedAt,
|
|
674
|
-
reason: record.archiveReason,
|
|
675
|
-
record,
|
|
676
|
-
overlayPath: file
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
/** Apply a retention POLICY: archive eligible runs older than the window. The
|
|
680
|
-
* window/states are policy inputs, never baked into the index. Returns the set
|
|
681
|
-
* archived; archives are overlay marks, so nothing is destroyed. */
|
|
682
|
-
archiveByPolicy(policy = policy_1.DEFAULT_RUN_REGISTRY_POLICY, options = {}) {
|
|
683
|
-
const scope = options.scope || "home";
|
|
684
|
-
if (!policy.archiveOlderThanDays || policy.archiveOlderThanDays <= 0) {
|
|
685
|
-
return { policy, archived: [], eligible: 0 };
|
|
686
|
-
}
|
|
687
|
-
const nowMs = options.now ? Date.parse(options.now) : Date.now();
|
|
688
|
-
const cutoff = nowMs - policy.archiveOlderThanDays * 24 * 60 * 60 * 1000;
|
|
689
|
-
const index = this.buildIndex(scope);
|
|
690
|
-
const eligible = index.records.filter((r) => !r.archived && policy.archiveStates.includes(r.derivedLifecycle) && Date.parse(r.updatedAt) < cutoff);
|
|
691
|
-
const archived = [];
|
|
692
|
-
for (const record of eligible) {
|
|
693
|
-
this.archive(record.runId, { reason: `retention:${policy.archiveOlderThanDays}d`, scope });
|
|
694
|
-
archived.push(record.runId);
|
|
695
|
-
}
|
|
696
|
-
return { policy, archived: archived.sort(), eligible: eligible.length };
|
|
697
|
-
}
|
|
698
|
-
// ---- Run Retention & Provable Reclamation (v0.1.39) ----------------------
|
|
699
|
-
// A small, verifiable GC built on the archive overlay. `gc plan` is a pure
|
|
700
|
-
// dry-run (frees nothing); `gc run` executes the write-ahead reclamation
|
|
701
|
-
// transaction (skeleton → tombstone → fsync → free); `gc verify` re-proves a
|
|
702
|
-
// reclaimed run independently. Eligibility is explicit and fail-closed.
|
|
703
|
-
// Implementations live in ./run-registry/gc (FreeBSD-audit R2 deep); these are
|
|
704
|
-
// thin delegators preserving the public surface. `this` satisfies GcHost
|
|
705
|
-
// (buildIndex, locate, loadRun).
|
|
706
|
-
/** Resolve the effective reclamation policy (defaults reclaim NOTHING). */
|
|
707
|
-
reclamationPolicy(overrides = {}) {
|
|
708
|
-
return (0, gc_1.reclamationPolicy)(overrides);
|
|
709
|
-
}
|
|
710
|
-
/** Dry-run: compute eligible runs, per-kind bytes that WOULD be freed, and the
|
|
711
|
-
* capability downgrade. Frees NOTHING. */
|
|
712
|
-
gcPlan(options = {}) {
|
|
713
|
-
return (0, gc_1.gcPlan)(this, options);
|
|
714
|
-
}
|
|
715
|
-
/** Execute the write-ahead reclamation transaction for eligible runs. Bounded
|
|
716
|
-
* (`maxReclaimRuns` / `maxReclaimBytes`), fail-closed on any incomplete
|
|
717
|
-
* skeleton. Produces a tombstone and frees the bulk. */
|
|
718
|
-
gcRun(options = {}) {
|
|
719
|
-
return (0, gc_1.gcRun)(this, options);
|
|
720
|
-
}
|
|
721
|
-
/** Re-prove a reclaimed run: skeleton schema-complete, tombstone chain
|
|
722
|
-
* recomputed-and-untampered, each reconstructable artifact re-derived from its
|
|
723
|
-
* RETAINED inputs to its expectDigest, and eligible-when-reclaimed. */
|
|
724
|
-
gcVerify(runId, options = {}) {
|
|
725
|
-
return (0, gc_1.gcVerify)(this, runId, options);
|
|
726
|
-
}
|
|
727
|
-
// ---- rerun (NEW run linked to the original; original preserved) ---------
|
|
728
|
-
rerun(runId, options = {}) {
|
|
729
|
-
if (!this.planner)
|
|
730
|
-
throw new Error("rerun requires a run planner (CoolWorkflowRunner)");
|
|
731
|
-
const scope = options.scope || "home";
|
|
732
|
-
const located = this.locate(runId, scope);
|
|
733
|
-
if (!located)
|
|
734
|
-
throw new Error(`Cannot rerun: run ${runId} not found in source state (fail closed).`);
|
|
735
|
-
const original = located.record;
|
|
736
|
-
const originalRun = this.loadRun(original.repo, runId);
|
|
737
|
-
const appId = originalRun.workflow.app?.id || originalRun.workflow.id;
|
|
738
|
-
// Reuse the original inputs verbatim, pinned to the original repo so the new
|
|
739
|
-
// run lands beside it. We never fork run creation — this is runner.plan.
|
|
740
|
-
const inputs = { ...(originalRun.inputs || {}), cwd: original.repo, repo: original.repo };
|
|
741
|
-
const newRun = this.planner.plan(appId, inputs);
|
|
742
|
-
const priorProv = original.provenance;
|
|
743
|
-
const provenance = {
|
|
744
|
-
rerunOf: runId,
|
|
745
|
-
rerunOfRepo: original.repo,
|
|
746
|
-
originRunId: priorProv?.originRunId || runId,
|
|
747
|
-
generation: (priorProv?.generation || 0) + 1,
|
|
748
|
-
reason: options.reason || "rerun of failed run",
|
|
749
|
-
createdAt: new Date().toISOString()
|
|
750
|
-
};
|
|
751
|
-
// Record provenance in the per-repo overlay (derived metadata), NOT in the
|
|
752
|
-
// original run's source state — the past is never mutated.
|
|
753
|
-
const provFile = node_path_1.default.join(this.repoRegistryDir(original.repo), "provenance.json");
|
|
754
|
-
// Lock the read-modify-write: a concurrent rerun/archive on the same repo
|
|
755
|
-
// overlay would otherwise last-writer-wins and drop a provenance link. The
|
|
756
|
-
// sibling writers (registerRepo, archive) already serialize via withFileLock.
|
|
757
|
-
(0, state_1.withFileLock)(provFile, () => {
|
|
758
|
-
const provOverlay = this.loadProvenanceOverlay(original.repo);
|
|
759
|
-
provOverlay.links[newRun.id] = provenance;
|
|
760
|
-
(0, state_1.writeJson)(provFile, provOverlay, { durable: true });
|
|
761
|
-
});
|
|
762
|
-
return {
|
|
763
|
-
schemaVersion: 1,
|
|
764
|
-
originalRunId: runId,
|
|
765
|
-
originalRepo: original.repo,
|
|
766
|
-
originalLifecycle: original.lifecycle,
|
|
767
|
-
newRunId: newRun.id,
|
|
768
|
-
repo: original.repo,
|
|
769
|
-
appId: newRun.workflow.app?.id || appId,
|
|
770
|
-
workflowId: newRun.workflow.id,
|
|
771
|
-
statePath: newRun.paths.state,
|
|
772
|
-
reportPath: newRun.paths.report,
|
|
773
|
-
pendingTasks: newRun.tasks.filter((t) => t.status === "pending").length,
|
|
774
|
-
provenance,
|
|
775
|
-
nextActions: [
|
|
776
|
-
{ command: `node scripts/cw.js run resume ${newRun.id}`, reason: "Continue the new linked run." },
|
|
777
|
-
{ command: `node scripts/cw.js run show ${runId}`, reason: "The original failed run is preserved for audit." }
|
|
778
|
-
]
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
// ---- queue (durable, ordered; drained by the host) ----------------------
|
|
782
|
-
// Implementations live in ./run-registry/queue (FreeBSD-audit R2 deep); these
|
|
783
|
-
// are thin delegators preserving the public surface. `this` satisfies QueueHost.
|
|
784
|
-
queueAdd(options = {}) {
|
|
785
|
-
return (0, queue_1.queueAdd)(this, options);
|
|
786
|
-
}
|
|
787
|
-
queueList(options = {}) {
|
|
788
|
-
return (0, queue_1.queueList)(this, options);
|
|
789
|
-
}
|
|
790
|
-
queueShow(id) {
|
|
791
|
-
return (0, queue_1.queueShow)(this, id);
|
|
792
|
-
}
|
|
793
|
-
queueDrain(options = {}) {
|
|
794
|
-
return (0, queue_1.queueDrain)(this, options);
|
|
795
|
-
}
|
|
796
|
-
// ---- cross-repo history (unified timeline) ------------------------------
|
|
797
|
-
history(options = {}) {
|
|
798
|
-
const scope = options.scope || "home";
|
|
799
|
-
const index = this.buildIndex(scope);
|
|
800
|
-
const report = this.report(scope, index);
|
|
801
|
-
const app = (0, derive_1.optionalLower)(options.app);
|
|
802
|
-
const limit = (0, derive_1.clampInt)(options.limit, 50, 1);
|
|
803
|
-
const offset = (0, derive_1.clampInt)(options.offset, 0, 0);
|
|
804
|
-
let records = index.records;
|
|
805
|
-
if (app)
|
|
806
|
-
records = records.filter((r) => (r.appId || r.workflowId || "").toLowerCase().includes(app));
|
|
807
|
-
if (options.status)
|
|
808
|
-
records = records.filter((r) => r.lifecycle === options.status || r.derivedLifecycle === options.status);
|
|
809
|
-
const ordered = [...records].sort(derive_1.compareHistory);
|
|
810
|
-
const total = ordered.length;
|
|
811
|
-
const page = ordered.slice(offset, offset + limit);
|
|
812
|
-
const entries = page.map((r) => ({
|
|
813
|
-
runId: r.runId,
|
|
814
|
-
repo: r.repo,
|
|
815
|
-
appId: r.appId,
|
|
816
|
-
workflowId: r.workflowId,
|
|
817
|
-
lifecycle: r.lifecycle,
|
|
818
|
-
loopStage: r.loopStage,
|
|
819
|
-
createdAt: r.createdAt,
|
|
820
|
-
updatedAt: r.updatedAt,
|
|
821
|
-
freshness: r.freshness,
|
|
822
|
-
provenance: r.provenance
|
|
823
|
-
}));
|
|
824
|
-
return {
|
|
825
|
-
schemaVersion: 1,
|
|
826
|
-
scope,
|
|
827
|
-
freshness: report.freshness.status,
|
|
828
|
-
total,
|
|
829
|
-
offset,
|
|
830
|
-
limit,
|
|
831
|
-
repos: index.repos,
|
|
832
|
-
entries,
|
|
833
|
-
nextAction: report.freshness.status === "valid" ? "node scripts/cw.js run show <run-id>" : "node scripts/cw.js registry refresh --scope home"
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
exports.RunRegistry = RunRegistry;
|
|
838
|
-
// Human formatting (CLI-only) now lives in ./run-registry/format.ts (FreeBSD-
|
|
839
|
-
// audit R2: rendering carved out of the registry class). Re-exported so that
|
|
840
|
-
// importers of "./run-registry" see an unchanged surface.
|
|
841
|
-
var format_1 = require("./run-registry/format");
|
|
842
|
-
Object.defineProperty(exports, "formatRegistryReport", { enumerable: true, get: function () { return format_1.formatRegistryReport; } });
|
|
843
|
-
Object.defineProperty(exports, "formatRunSearch", { enumerable: true, get: function () { return format_1.formatRunSearch; } });
|
|
844
|
-
Object.defineProperty(exports, "formatRunShow", { enumerable: true, get: function () { return format_1.formatRunShow; } });
|
|
845
|
-
Object.defineProperty(exports, "formatGcPlan", { enumerable: true, get: function () { return format_1.formatGcPlan; } });
|
|
846
|
-
Object.defineProperty(exports, "formatGcRun", { enumerable: true, get: function () { return format_1.formatGcRun; } });
|
|
847
|
-
Object.defineProperty(exports, "formatGcVerify", { enumerable: true, get: function () { return format_1.formatGcVerify; } });
|
|
848
|
-
Object.defineProperty(exports, "formatResume", { enumerable: true, get: function () { return format_1.formatResume; } });
|
|
849
|
-
Object.defineProperty(exports, "formatHistory", { enumerable: true, get: function () { return format_1.formatHistory; } });
|
|
850
|
-
Object.defineProperty(exports, "formatQueueList", { enumerable: true, get: function () { return format_1.formatQueueList; } });
|