looply-cli 0.0.0-stage → 0.3.0
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/LICENSE +21 -0
- package/README.md +137 -3
- package/dist/.src-hash +1 -0
- package/dist/acceptance-observe.d.ts +108 -0
- package/dist/acceptance-observe.d.ts.map +1 -0
- package/dist/acceptance-observe.js +152 -0
- package/dist/acceptance-observe.js.map +1 -0
- package/dist/agent-cmd.d.ts +131 -0
- package/dist/agent-cmd.d.ts.map +1 -0
- package/dist/agent-cmd.js +154 -0
- package/dist/agent-cmd.js.map +1 -0
- package/dist/agent-contained.d.ts +114 -0
- package/dist/agent-contained.d.ts.map +1 -0
- package/dist/agent-contained.js +292 -0
- package/dist/agent-contained.js.map +1 -0
- package/dist/agent-driver.d.ts +130 -0
- package/dist/agent-driver.d.ts.map +1 -0
- package/dist/agent-driver.js +170 -0
- package/dist/agent-driver.js.map +1 -0
- package/dist/agent-envelope.d.ts +94 -0
- package/dist/agent-envelope.d.ts.map +1 -0
- package/dist/agent-envelope.js +214 -0
- package/dist/agent-envelope.js.map +1 -0
- package/dist/agent-exec.d.ts +182 -0
- package/dist/agent-exec.d.ts.map +1 -0
- package/dist/agent-exec.js +125 -0
- package/dist/agent-exec.js.map +1 -0
- package/dist/agent-runtime.d.ts +23 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +143 -0
- package/dist/agent-runtime.js.map +1 -0
- package/dist/approval-gate-read.d.ts +66 -0
- package/dist/approval-gate-read.d.ts.map +1 -0
- package/dist/approval-gate-read.js +138 -0
- package/dist/approval-gate-read.js.map +1 -0
- package/dist/approval-resolution.d.ts +87 -0
- package/dist/approval-resolution.d.ts.map +1 -0
- package/dist/approval-resolution.js +100 -0
- package/dist/approval-resolution.js.map +1 -0
- package/dist/approval-resumes.d.ts +102 -0
- package/dist/approval-resumes.d.ts.map +1 -0
- package/dist/approval-resumes.js +167 -0
- package/dist/approval-resumes.js.map +1 -0
- package/dist/ask-brain.d.ts +167 -0
- package/dist/ask-brain.d.ts.map +1 -0
- package/dist/ask-brain.js +355 -0
- package/dist/ask-brain.js.map +1 -0
- package/dist/autonomy-authority.d.ts +80 -0
- package/dist/autonomy-authority.d.ts.map +1 -0
- package/dist/autonomy-authority.js +82 -0
- package/dist/autonomy-authority.js.map +1 -0
- package/dist/autonomy-controller.d.ts +321 -0
- package/dist/autonomy-controller.d.ts.map +1 -0
- package/dist/autonomy-controller.js +517 -0
- package/dist/autonomy-controller.js.map +1 -0
- package/dist/autonomy-store.d.ts +327 -0
- package/dist/autonomy-store.d.ts.map +1 -0
- package/dist/autonomy-store.js +581 -0
- package/dist/autonomy-store.js.map +1 -0
- package/dist/autonomy-tick.d.ts +257 -0
- package/dist/autonomy-tick.d.ts.map +1 -0
- package/dist/autonomy-tick.js +616 -0
- package/dist/autonomy-tick.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +2727 -0
- package/dist/bin.js.map +1 -0
- package/dist/brain-advice.d.ts +21 -0
- package/dist/brain-advice.d.ts.map +1 -0
- package/dist/brain-advice.js +51 -0
- package/dist/brain-advice.js.map +1 -0
- package/dist/candidate-replay-runtime.d.ts +125 -0
- package/dist/candidate-replay-runtime.d.ts.map +1 -0
- package/dist/candidate-replay-runtime.js +188 -0
- package/dist/candidate-replay-runtime.js.map +1 -0
- package/dist/checkout-carry.d.ts +76 -0
- package/dist/checkout-carry.d.ts.map +1 -0
- package/dist/checkout-carry.js +125 -0
- package/dist/checkout-carry.js.map +1 -0
- package/dist/citation-readers.d.ts +26 -0
- package/dist/citation-readers.d.ts.map +1 -0
- package/dist/citation-readers.js +102 -0
- package/dist/citation-readers.js.map +1 -0
- package/dist/command-receipts.d.ts +79 -0
- package/dist/command-receipts.d.ts.map +1 -0
- package/dist/command-receipts.js +143 -0
- package/dist/command-receipts.js.map +1 -0
- package/dist/command-runner.d.ts +32 -0
- package/dist/command-runner.d.ts.map +1 -0
- package/dist/command-runner.js +108 -0
- package/dist/command-runner.js.map +1 -0
- package/dist/compatible-sets.d.ts +67 -0
- package/dist/compatible-sets.d.ts.map +1 -0
- package/dist/compatible-sets.js +81 -0
- package/dist/compatible-sets.js.map +1 -0
- package/dist/compile-check.d.ts +31 -0
- package/dist/compile-check.d.ts.map +1 -0
- package/dist/compile-check.js +34 -0
- package/dist/compile-check.js.map +1 -0
- package/dist/compile-store.d.ts +16 -0
- package/dist/compile-store.d.ts.map +1 -0
- package/dist/compile-store.js +21 -0
- package/dist/compile-store.js.map +1 -0
- package/dist/completion.d.ts +106 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +131 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +549 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +763 -0
- package/dist/config.js.map +1 -0
- package/dist/control-file.d.ts +142 -0
- package/dist/control-file.d.ts.map +1 -0
- package/dist/control-file.js +144 -0
- package/dist/control-file.js.map +1 -0
- package/dist/coordinator-state.d.ts +131 -0
- package/dist/coordinator-state.d.ts.map +1 -0
- package/dist/coordinator-state.js +380 -0
- package/dist/coordinator-state.js.map +1 -0
- package/dist/coordinator.d.ts +95 -0
- package/dist/coordinator.d.ts.map +1 -0
- package/dist/coordinator.js +97 -0
- package/dist/coordinator.js.map +1 -0
- package/dist/cursor-store.d.ts +53 -0
- package/dist/cursor-store.d.ts.map +1 -0
- package/dist/cursor-store.js +98 -0
- package/dist/cursor-store.js.map +1 -0
- package/dist/daemon-cmd.d.ts +239 -0
- package/dist/daemon-cmd.d.ts.map +1 -0
- package/dist/daemon-cmd.js +1751 -0
- package/dist/daemon-cmd.js.map +1 -0
- package/dist/daemon-lock.d.ts +140 -0
- package/dist/daemon-lock.d.ts.map +1 -0
- package/dist/daemon-lock.js +352 -0
- package/dist/daemon-lock.js.map +1 -0
- package/dist/daemon-recovery.d.ts +78 -0
- package/dist/daemon-recovery.d.ts.map +1 -0
- package/dist/daemon-recovery.js +161 -0
- package/dist/daemon-recovery.js.map +1 -0
- package/dist/daemon.d.ts +368 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +601 -0
- package/dist/daemon.js.map +1 -0
- package/dist/declared-response-shape.d.ts +93 -0
- package/dist/declared-response-shape.d.ts.map +1 -0
- package/dist/declared-response-shape.js +200 -0
- package/dist/declared-response-shape.js.map +1 -0
- package/dist/declared-surfaces.d.ts +16 -0
- package/dist/declared-surfaces.d.ts.map +1 -0
- package/dist/declared-surfaces.js +19 -0
- package/dist/declared-surfaces.js.map +1 -0
- package/dist/depends-review.d.ts +113 -0
- package/dist/depends-review.d.ts.map +1 -0
- package/dist/depends-review.js +110 -0
- package/dist/depends-review.js.map +1 -0
- package/dist/doctor.d.ts +91 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +71 -0
- package/dist/doctor.js.map +1 -0
- package/dist/edge-approval.d.ts +105 -0
- package/dist/edge-approval.d.ts.map +1 -0
- package/dist/edge-approval.js +100 -0
- package/dist/edge-approval.js.map +1 -0
- package/dist/evidence-cache.d.ts +45 -0
- package/dist/evidence-cache.d.ts.map +1 -0
- package/dist/evidence-cache.js +90 -0
- package/dist/evidence-cache.js.map +1 -0
- package/dist/evidence-cmd.d.ts +133 -0
- package/dist/evidence-cmd.d.ts.map +1 -0
- package/dist/evidence-cmd.js +347 -0
- package/dist/evidence-cmd.js.map +1 -0
- package/dist/evidence-facts.d.ts +40 -0
- package/dist/evidence-facts.d.ts.map +1 -0
- package/dist/evidence-facts.js +114 -0
- package/dist/evidence-facts.js.map +1 -0
- package/dist/exclusive-lock.d.ts +52 -0
- package/dist/exclusive-lock.d.ts.map +1 -0
- package/dist/exclusive-lock.js +150 -0
- package/dist/exclusive-lock.js.map +1 -0
- package/dist/exec-domains.d.ts +140 -0
- package/dist/exec-domains.d.ts.map +1 -0
- package/dist/exec-domains.js +287 -0
- package/dist/exec-domains.js.map +1 -0
- package/dist/exemption-store.d.ts +197 -0
- package/dist/exemption-store.d.ts.map +1 -0
- package/dist/exemption-store.js +266 -0
- package/dist/exemption-store.js.map +1 -0
- package/dist/explicit-start-gate.d.ts +96 -0
- package/dist/explicit-start-gate.d.ts.map +1 -0
- package/dist/explicit-start-gate.js +103 -0
- package/dist/explicit-start-gate.js.map +1 -0
- package/dist/fs-trouble.d.ts +70 -0
- package/dist/fs-trouble.d.ts.map +1 -0
- package/dist/fs-trouble.js +98 -0
- package/dist/fs-trouble.js.map +1 -0
- package/dist/gate.d.ts +278 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +278 -0
- package/dist/gate.js.map +1 -0
- package/dist/git-driver.d.ts +519 -0
- package/dist/git-driver.d.ts.map +1 -0
- package/dist/git-driver.js +900 -0
- package/dist/git-driver.js.map +1 -0
- package/dist/git-push-executor.d.ts +41 -0
- package/dist/git-push-executor.d.ts.map +1 -0
- package/dist/git-push-executor.js +142 -0
- package/dist/git-push-executor.js.map +1 -0
- package/dist/glob.d.ts +26 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +93 -0
- package/dist/glob.js.map +1 -0
- package/dist/goal-adaptive.d.ts +295 -0
- package/dist/goal-adaptive.d.ts.map +1 -0
- package/dist/goal-adaptive.js +393 -0
- package/dist/goal-adaptive.js.map +1 -0
- package/dist/goal-compile.d.ts +342 -0
- package/dist/goal-compile.d.ts.map +1 -0
- package/dist/goal-compile.js +444 -0
- package/dist/goal-compile.js.map +1 -0
- package/dist/goal-depends-executor.d.ts +55 -0
- package/dist/goal-depends-executor.d.ts.map +1 -0
- package/dist/goal-depends-executor.js +202 -0
- package/dist/goal-depends-executor.js.map +1 -0
- package/dist/goal-execution-evidence.d.ts +135 -0
- package/dist/goal-execution-evidence.d.ts.map +1 -0
- package/dist/goal-execution-evidence.js +159 -0
- package/dist/goal-execution-evidence.js.map +1 -0
- package/dist/goal-gap.d.ts +140 -0
- package/dist/goal-gap.d.ts.map +1 -0
- package/dist/goal-gap.js +197 -0
- package/dist/goal-gap.js.map +1 -0
- package/dist/goal-met-target.d.ts +98 -0
- package/dist/goal-met-target.d.ts.map +1 -0
- package/dist/goal-met-target.js +92 -0
- package/dist/goal-met-target.js.map +1 -0
- package/dist/goal-ownership.d.ts +416 -0
- package/dist/goal-ownership.d.ts.map +1 -0
- package/dist/goal-ownership.js +576 -0
- package/dist/goal-ownership.js.map +1 -0
- package/dist/goal-runs.d.ts +82 -0
- package/dist/goal-runs.d.ts.map +1 -0
- package/dist/goal-runs.js +120 -0
- package/dist/goal-runs.js.map +1 -0
- package/dist/goal-store.d.ts +146 -0
- package/dist/goal-store.d.ts.map +1 -0
- package/dist/goal-store.js +294 -0
- package/dist/goal-store.js.map +1 -0
- package/dist/goal-view.d.ts +156 -0
- package/dist/goal-view.d.ts.map +1 -0
- package/dist/goal-view.js +499 -0
- package/dist/goal-view.js.map +1 -0
- package/dist/governed-approvals.d.ts +152 -0
- package/dist/governed-approvals.d.ts.map +1 -0
- package/dist/governed-approvals.js +246 -0
- package/dist/governed-approvals.js.map +1 -0
- package/dist/governed-broker.d.ts +169 -0
- package/dist/governed-broker.d.ts.map +1 -0
- package/dist/governed-broker.js +196 -0
- package/dist/governed-broker.js.map +1 -0
- package/dist/governed-run.d.ts +220 -0
- package/dist/governed-run.d.ts.map +1 -0
- package/dist/governed-run.js +406 -0
- package/dist/governed-run.js.map +1 -0
- package/dist/grant-reconcile.d.ts +63 -0
- package/dist/grant-reconcile.d.ts.map +1 -0
- package/dist/grant-reconcile.js +121 -0
- package/dist/grant-reconcile.js.map +1 -0
- package/dist/index-for-head.d.ts +56 -0
- package/dist/index-for-head.d.ts.map +1 -0
- package/dist/index-for-head.js +103 -0
- package/dist/index-for-head.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/init-detect.d.ts +39 -0
- package/dist/init-detect.d.ts.map +1 -0
- package/dist/init-detect.js +188 -0
- package/dist/init-detect.js.map +1 -0
- package/dist/integration-deps.d.ts +62 -0
- package/dist/integration-deps.d.ts.map +1 -0
- package/dist/integration-deps.js +251 -0
- package/dist/integration-deps.js.map +1 -0
- package/dist/integration-runtime.d.ts +458 -0
- package/dist/integration-runtime.d.ts.map +1 -0
- package/dist/integration-runtime.js +681 -0
- package/dist/integration-runtime.js.map +1 -0
- package/dist/integration.d.ts +45 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +87 -0
- package/dist/integration.js.map +1 -0
- package/dist/integrator.d.ts +84 -0
- package/dist/integrator.d.ts.map +1 -0
- package/dist/integrator.js +193 -0
- package/dist/integrator.js.map +1 -0
- package/dist/lane-claims.d.ts +174 -0
- package/dist/lane-claims.d.ts.map +1 -0
- package/dist/lane-claims.js +218 -0
- package/dist/lane-claims.js.map +1 -0
- package/dist/lane-coverage.d.ts +87 -0
- package/dist/lane-coverage.d.ts.map +1 -0
- package/dist/lane-coverage.js +129 -0
- package/dist/lane-coverage.js.map +1 -0
- package/dist/ledger-replay.d.ts +115 -0
- package/dist/ledger-replay.d.ts.map +1 -0
- package/dist/ledger-replay.js +155 -0
- package/dist/ledger-replay.js.map +1 -0
- package/dist/ledger-store.d.ts +68 -0
- package/dist/ledger-store.d.ts.map +1 -0
- package/dist/ledger-store.js +111 -0
- package/dist/ledger-store.js.map +1 -0
- package/dist/loop-safety-observer.d.ts +132 -0
- package/dist/loop-safety-observer.d.ts.map +1 -0
- package/dist/loop-safety-observer.js +76 -0
- package/dist/loop-safety-observer.js.map +1 -0
- package/dist/loop-safety-store.d.ts +339 -0
- package/dist/loop-safety-store.d.ts.map +1 -0
- package/dist/loop-safety-store.js +800 -0
- package/dist/loop-safety-store.js.map +1 -0
- package/dist/machine-store.d.ts +54 -0
- package/dist/machine-store.d.ts.map +1 -0
- package/dist/machine-store.js +149 -0
- package/dist/machine-store.js.map +1 -0
- package/dist/mcp-main.d.ts +2 -0
- package/dist/mcp-main.d.ts.map +1 -0
- package/dist/mcp-main.js +116 -0
- package/dist/mcp-main.js.map +1 -0
- package/dist/mcp-server.d.ts +72 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +259 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/model-routing.d.ts +75 -0
- package/dist/model-routing.d.ts.map +1 -0
- package/dist/model-routing.js +108 -0
- package/dist/model-routing.js.map +1 -0
- package/dist/model-transport.d.ts +188 -0
- package/dist/model-transport.d.ts.map +1 -0
- package/dist/model-transport.js +625 -0
- package/dist/model-transport.js.map +1 -0
- package/dist/notify-cadence.d.ts +55 -0
- package/dist/notify-cadence.d.ts.map +1 -0
- package/dist/notify-cadence.js +68 -0
- package/dist/notify-cadence.js.map +1 -0
- package/dist/notify-channel.d.ts +69 -0
- package/dist/notify-channel.d.ts.map +1 -0
- package/dist/notify-channel.js +151 -0
- package/dist/notify-channel.js.map +1 -0
- package/dist/notify.d.ts +71 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +125 -0
- package/dist/notify.js.map +1 -0
- package/dist/observation-inventory.d.ts +65 -0
- package/dist/observation-inventory.d.ts.map +1 -0
- package/dist/observation-inventory.js +139 -0
- package/dist/observation-inventory.js.map +1 -0
- package/dist/owned-children.d.ts +45 -0
- package/dist/owned-children.d.ts.map +1 -0
- package/dist/owned-children.js +64 -0
- package/dist/owned-children.js.map +1 -0
- package/dist/packet-for-goal.d.ts +19 -0
- package/dist/packet-for-goal.d.ts.map +1 -0
- package/dist/packet-for-goal.js +32 -0
- package/dist/packet-for-goal.js.map +1 -0
- package/dist/pair-cmd.d.ts +85 -0
- package/dist/pair-cmd.d.ts.map +1 -0
- package/dist/pair-cmd.js +205 -0
- package/dist/pair-cmd.js.map +1 -0
- package/dist/partial-asker.d.ts +96 -0
- package/dist/partial-asker.d.ts.map +1 -0
- package/dist/partial-asker.js +117 -0
- package/dist/partial-asker.js.map +1 -0
- package/dist/pdf-text-lines.d.ts +17 -0
- package/dist/pdf-text-lines.d.ts.map +1 -0
- package/dist/pdf-text-lines.js +70 -0
- package/dist/pdf-text-lines.js.map +1 -0
- package/dist/pdf-text-worker.d.ts +2 -0
- package/dist/pdf-text-worker.d.ts.map +1 -0
- package/dist/pdf-text-worker.js +81 -0
- package/dist/pdf-text-worker.js.map +1 -0
- package/dist/pdf-text.d.ts +56 -0
- package/dist/pdf-text.d.ts.map +1 -0
- package/dist/pdf-text.js +64 -0
- package/dist/pdf-text.js.map +1 -0
- package/dist/pending-action.d.ts +154 -0
- package/dist/pending-action.d.ts.map +1 -0
- package/dist/pending-action.js +148 -0
- package/dist/pending-action.js.map +1 -0
- package/dist/preemptor.d.ts +40 -0
- package/dist/preemptor.d.ts.map +1 -0
- package/dist/preemptor.js +49 -0
- package/dist/preemptor.js.map +1 -0
- package/dist/programme-mode.d.ts +29 -0
- package/dist/programme-mode.d.ts.map +1 -0
- package/dist/programme-mode.js +50 -0
- package/dist/programme-mode.js.map +1 -0
- package/dist/progress-view.d.ts +14 -0
- package/dist/progress-view.d.ts.map +1 -0
- package/dist/progress-view.js +114 -0
- package/dist/progress-view.js.map +1 -0
- package/dist/project-graph-builder.d.ts +81 -0
- package/dist/project-graph-builder.d.ts.map +1 -0
- package/dist/project-graph-builder.js +246 -0
- package/dist/project-graph-builder.js.map +1 -0
- package/dist/project-graph-runtime.d.ts +86 -0
- package/dist/project-graph-runtime.d.ts.map +1 -0
- package/dist/project-graph-runtime.js +112 -0
- package/dist/project-graph-runtime.js.map +1 -0
- package/dist/project-index-builder.d.ts +96 -0
- package/dist/project-index-builder.d.ts.map +1 -0
- package/dist/project-index-builder.js +298 -0
- package/dist/project-index-builder.js.map +1 -0
- package/dist/project-index-facts.d.ts +51 -0
- package/dist/project-index-facts.d.ts.map +1 -0
- package/dist/project-index-facts.js +117 -0
- package/dist/project-index-facts.js.map +1 -0
- package/dist/project-index-store.d.ts +97 -0
- package/dist/project-index-store.d.ts.map +1 -0
- package/dist/project-index-store.js +140 -0
- package/dist/project-index-store.js.map +1 -0
- package/dist/project-memory-store.d.ts +127 -0
- package/dist/project-memory-store.d.ts.map +1 -0
- package/dist/project-memory-store.js +302 -0
- package/dist/project-memory-store.js.map +1 -0
- package/dist/proposal-store.d.ts +14 -0
- package/dist/proposal-store.d.ts.map +1 -0
- package/dist/proposal-store.js +19 -0
- package/dist/proposal-store.js.map +1 -0
- package/dist/prover.d.ts +80 -0
- package/dist/prover.d.ts.map +1 -0
- package/dist/prover.js +137 -0
- package/dist/prover.js.map +1 -0
- package/dist/provider-identity-store.d.ts +34 -0
- package/dist/provider-identity-store.d.ts.map +1 -0
- package/dist/provider-identity-store.js +72 -0
- package/dist/provider-identity-store.js.map +1 -0
- package/dist/provider-identity.d.ts +104 -0
- package/dist/provider-identity.d.ts.map +1 -0
- package/dist/provider-identity.js +167 -0
- package/dist/provider-identity.js.map +1 -0
- package/dist/provider-limit.d.ts +79 -0
- package/dist/provider-limit.d.ts.map +1 -0
- package/dist/provider-limit.js +148 -0
- package/dist/provider-limit.js.map +1 -0
- package/dist/provider-preflight.d.ts +171 -0
- package/dist/provider-preflight.d.ts.map +1 -0
- package/dist/provider-preflight.js +395 -0
- package/dist/provider-preflight.js.map +1 -0
- package/dist/provider-state.d.ts +120 -0
- package/dist/provider-state.d.ts.map +1 -0
- package/dist/provider-state.js +182 -0
- package/dist/provider-state.js.map +1 -0
- package/dist/providers.d.ts +132 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +161 -0
- package/dist/providers.js.map +1 -0
- package/dist/publication-recorder.d.ts +117 -0
- package/dist/publication-recorder.d.ts.map +1 -0
- package/dist/publication-recorder.js +124 -0
- package/dist/publication-recorder.js.map +1 -0
- package/dist/pursuit-delivery.d.ts +24 -0
- package/dist/pursuit-delivery.d.ts.map +1 -0
- package/dist/pursuit-delivery.js +38 -0
- package/dist/pursuit-delivery.js.map +1 -0
- package/dist/queue-store.d.ts +132 -0
- package/dist/queue-store.d.ts.map +1 -0
- package/dist/queue-store.js +185 -0
- package/dist/queue-store.js.map +1 -0
- package/dist/queue-summary.d.ts +14 -0
- package/dist/queue-summary.d.ts.map +1 -0
- package/dist/queue-summary.js +82 -0
- package/dist/queue-summary.js.map +1 -0
- package/dist/queue-view.d.ts +20 -0
- package/dist/queue-view.d.ts.map +1 -0
- package/dist/queue-view.js +163 -0
- package/dist/queue-view.js.map +1 -0
- package/dist/queue-write-lease.d.ts +106 -0
- package/dist/queue-write-lease.d.ts.map +1 -0
- package/dist/queue-write-lease.js +282 -0
- package/dist/queue-write-lease.js.map +1 -0
- package/dist/rails-home.d.ts +162 -0
- package/dist/rails-home.d.ts.map +1 -0
- package/dist/rails-home.js +452 -0
- package/dist/rails-home.js.map +1 -0
- package/dist/rails-migrations.d.ts +75 -0
- package/dist/rails-migrations.d.ts.map +1 -0
- package/dist/rails-migrations.js +199 -0
- package/dist/rails-migrations.js.map +1 -0
- package/dist/rails-stores.d.ts +49 -0
- package/dist/rails-stores.d.ts.map +1 -0
- package/dist/rails-stores.js +100 -0
- package/dist/rails-stores.js.map +1 -0
- package/dist/reaper.d.ts +69 -0
- package/dist/reaper.d.ts.map +1 -0
- package/dist/reaper.js +152 -0
- package/dist/reaper.js.map +1 -0
- package/dist/record-store.d.ts +36 -0
- package/dist/record-store.d.ts.map +1 -0
- package/dist/record-store.js +78 -0
- package/dist/record-store.js.map +1 -0
- package/dist/recovery-io.d.ts +50 -0
- package/dist/recovery-io.d.ts.map +1 -0
- package/dist/recovery-io.js +122 -0
- package/dist/recovery-io.js.map +1 -0
- package/dist/recovery.d.ts +146 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +110 -0
- package/dist/recovery.js.map +1 -0
- package/dist/redraw.d.ts +34 -0
- package/dist/redraw.d.ts.map +1 -0
- package/dist/redraw.js +62 -0
- package/dist/redraw.js.map +1 -0
- package/dist/rejected-evidence.d.ts +255 -0
- package/dist/rejected-evidence.d.ts.map +1 -0
- package/dist/rejected-evidence.js +324 -0
- package/dist/rejected-evidence.js.map +1 -0
- package/dist/report-cmd.d.ts +32 -0
- package/dist/report-cmd.d.ts.map +1 -0
- package/dist/report-cmd.js +201 -0
- package/dist/report-cmd.js.map +1 -0
- package/dist/repos-cmd.d.ts +80 -0
- package/dist/repos-cmd.d.ts.map +1 -0
- package/dist/repos-cmd.js +240 -0
- package/dist/repos-cmd.js.map +1 -0
- package/dist/request-body-shape.d.ts +93 -0
- package/dist/request-body-shape.d.ts.map +1 -0
- package/dist/request-body-shape.js +407 -0
- package/dist/request-body-shape.js.map +1 -0
- package/dist/requirement-claims.d.ts +89 -0
- package/dist/requirement-claims.d.ts.map +1 -0
- package/dist/requirement-claims.js +92 -0
- package/dist/requirement-claims.js.map +1 -0
- package/dist/retention-apply-runtime.d.ts +105 -0
- package/dist/retention-apply-runtime.d.ts.map +1 -0
- package/dist/retention-apply-runtime.js +269 -0
- package/dist/retention-apply-runtime.js.map +1 -0
- package/dist/reverify.d.ts +41 -0
- package/dist/reverify.d.ts.map +1 -0
- package/dist/reverify.js +69 -0
- package/dist/reverify.js.map +1 -0
- package/dist/round-records.d.ts +65 -0
- package/dist/round-records.d.ts.map +1 -0
- package/dist/round-records.js +61 -0
- package/dist/round-records.js.map +1 -0
- package/dist/round-runner.d.ts +924 -0
- package/dist/round-runner.d.ts.map +1 -0
- package/dist/round-runner.js +1693 -0
- package/dist/round-runner.js.map +1 -0
- package/dist/run-approval.d.ts +180 -0
- package/dist/run-approval.d.ts.map +1 -0
- package/dist/run-approval.js +199 -0
- package/dist/run-approval.js.map +1 -0
- package/dist/run-cmd.d.ts +359 -0
- package/dist/run-cmd.d.ts.map +1 -0
- package/dist/run-cmd.js +4418 -0
- package/dist/run-cmd.js.map +1 -0
- package/dist/run-delivery.d.ts +71 -0
- package/dist/run-delivery.d.ts.map +1 -0
- package/dist/run-delivery.js +104 -0
- package/dist/run-delivery.js.map +1 -0
- package/dist/run-ended.d.ts +75 -0
- package/dist/run-ended.d.ts.map +1 -0
- package/dist/run-ended.js +27 -0
- package/dist/run-ended.js.map +1 -0
- package/dist/run-ending-locator.d.ts +125 -0
- package/dist/run-ending-locator.d.ts.map +1 -0
- package/dist/run-ending-locator.js +133 -0
- package/dist/run-ending-locator.js.map +1 -0
- package/dist/run-launcher.d.ts +459 -0
- package/dist/run-launcher.d.ts.map +1 -0
- package/dist/run-launcher.js +652 -0
- package/dist/run-launcher.js.map +1 -0
- package/dist/run-lease.d.ts +208 -0
- package/dist/run-lease.d.ts.map +1 -0
- package/dist/run-lease.js +301 -0
- package/dist/run-lease.js.map +1 -0
- package/dist/run-refusal-marks.d.ts +189 -0
- package/dist/run-refusal-marks.d.ts.map +1 -0
- package/dist/run-refusal-marks.js +249 -0
- package/dist/run-refusal-marks.js.map +1 -0
- package/dist/run-start-marks.d.ts +153 -0
- package/dist/run-start-marks.d.ts.map +1 -0
- package/dist/run-start-marks.js +269 -0
- package/dist/run-start-marks.js.map +1 -0
- package/dist/scan-cmd.d.ts +14 -0
- package/dist/scan-cmd.d.ts.map +1 -0
- package/dist/scan-cmd.js +270 -0
- package/dist/scan-cmd.js.map +1 -0
- package/dist/scan-events.d.ts +50 -0
- package/dist/scan-events.d.ts.map +1 -0
- package/dist/scan-events.js +91 -0
- package/dist/scan-events.js.map +1 -0
- package/dist/scan.d.ts +191 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +417 -0
- package/dist/scan.js.map +1 -0
- package/dist/scope-rule.d.ts +148 -0
- package/dist/scope-rule.d.ts.map +1 -0
- package/dist/scope-rule.js +121 -0
- package/dist/scope-rule.js.map +1 -0
- package/dist/self-repo-id.d.ts +18 -0
- package/dist/self-repo-id.d.ts.map +1 -0
- package/dist/self-repo-id.js +70 -0
- package/dist/self-repo-id.js.map +1 -0
- package/dist/serve-cmd.d.ts +115 -0
- package/dist/serve-cmd.d.ts.map +1 -0
- package/dist/serve-cmd.js +505 -0
- package/dist/serve-cmd.js.map +1 -0
- package/dist/serve.d.ts +167 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +336 -0
- package/dist/serve.js.map +1 -0
- package/dist/server-client.d.ts +766 -0
- package/dist/server-client.d.ts.map +1 -0
- package/dist/server-client.js +475 -0
- package/dist/server-client.js.map +1 -0
- package/dist/session-adapter-runtime.d.ts +195 -0
- package/dist/session-adapter-runtime.d.ts.map +1 -0
- package/dist/session-adapter-runtime.js +373 -0
- package/dist/session-adapter-runtime.js.map +1 -0
- package/dist/session-checkpoint-runtime.d.ts +62 -0
- package/dist/session-checkpoint-runtime.d.ts.map +1 -0
- package/dist/session-checkpoint-runtime.js +268 -0
- package/dist/session-checkpoint-runtime.js.map +1 -0
- package/dist/session-control-transport.d.ts +106 -0
- package/dist/session-control-transport.d.ts.map +1 -0
- package/dist/session-control-transport.js +232 -0
- package/dist/session-control-transport.js.map +1 -0
- package/dist/session-observation-store.d.ts +98 -0
- package/dist/session-observation-store.d.ts.map +1 -0
- package/dist/session-observation-store.js +155 -0
- package/dist/session-observation-store.js.map +1 -0
- package/dist/session-observe-runtime.d.ts +123 -0
- package/dist/session-observe-runtime.d.ts.map +1 -0
- package/dist/session-observe-runtime.js +317 -0
- package/dist/session-observe-runtime.js.map +1 -0
- package/dist/session-store.d.ts +98 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +116 -0
- package/dist/session-store.js.map +1 -0
- package/dist/sessions-cmd.d.ts +202 -0
- package/dist/sessions-cmd.d.ts.map +1 -0
- package/dist/sessions-cmd.js +609 -0
- package/dist/sessions-cmd.js.map +1 -0
- package/dist/settings-overlay.d.ts +53 -0
- package/dist/settings-overlay.d.ts.map +1 -0
- package/dist/settings-overlay.js +175 -0
- package/dist/settings-overlay.js.map +1 -0
- package/dist/setup-prompt.d.ts +34 -0
- package/dist/setup-prompt.d.ts.map +1 -0
- package/dist/setup-prompt.js +92 -0
- package/dist/setup-prompt.js.map +1 -0
- package/dist/setup.d.ts +103 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +283 -0
- package/dist/setup.js.map +1 -0
- package/dist/shared-grants.d.ts +164 -0
- package/dist/shared-grants.d.ts.map +1 -0
- package/dist/shared-grants.js +242 -0
- package/dist/shared-grants.js.map +1 -0
- package/dist/signals.d.ts +55 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +85 -0
- package/dist/signals.js.map +1 -0
- package/dist/source-cmd.d.ts +201 -0
- package/dist/source-cmd.d.ts.map +1 -0
- package/dist/source-cmd.js +684 -0
- package/dist/source-cmd.js.map +1 -0
- package/dist/source-verdict.d.ts +99 -0
- package/dist/source-verdict.d.ts.map +1 -0
- package/dist/source-verdict.js +182 -0
- package/dist/source-verdict.js.map +1 -0
- package/dist/spend-ledger.d.ts +350 -0
- package/dist/spend-ledger.d.ts.map +1 -0
- package/dist/spend-ledger.js +546 -0
- package/dist/spend-ledger.js.map +1 -0
- package/dist/stale-run-sweep.d.ts +79 -0
- package/dist/stale-run-sweep.d.ts.map +1 -0
- package/dist/stale-run-sweep.js +116 -0
- package/dist/stale-run-sweep.js.map +1 -0
- package/dist/start-attempts.d.ts +385 -0
- package/dist/start-attempts.d.ts.map +1 -0
- package/dist/start-attempts.js +613 -0
- package/dist/start-attempts.js.map +1 -0
- package/dist/status-cmd.d.ts +28 -0
- package/dist/status-cmd.d.ts.map +1 -0
- package/dist/status-cmd.js +116 -0
- package/dist/status-cmd.js.map +1 -0
- package/dist/stop-follow-up.d.ts +107 -0
- package/dist/stop-follow-up.d.ts.map +1 -0
- package/dist/stop-follow-up.js +172 -0
- package/dist/stop-follow-up.js.map +1 -0
- package/dist/surface-lease.d.ts +118 -0
- package/dist/surface-lease.d.ts.map +1 -0
- package/dist/surface-lease.js +485 -0
- package/dist/surface-lease.js.map +1 -0
- package/dist/sync.d.ts +54 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +93 -0
- package/dist/sync.js.map +1 -0
- package/dist/syncing-ledger.d.ts +45 -0
- package/dist/syncing-ledger.d.ts.map +1 -0
- package/dist/syncing-ledger.js +53 -0
- package/dist/syncing-ledger.js.map +1 -0
- package/dist/temp-fixtures.d.ts +68 -0
- package/dist/temp-fixtures.d.ts.map +1 -0
- package/dist/temp-fixtures.js +38 -0
- package/dist/temp-fixtures.js.map +1 -0
- package/dist/token-window.d.ts +84 -0
- package/dist/token-window.d.ts.map +1 -0
- package/dist/token-window.js +143 -0
- package/dist/token-window.js.map +1 -0
- package/dist/tool-bridge.d.ts +177 -0
- package/dist/tool-bridge.d.ts.map +1 -0
- package/dist/tool-bridge.js +329 -0
- package/dist/tool-bridge.js.map +1 -0
- package/dist/tool-call-record.d.ts +197 -0
- package/dist/tool-call-record.d.ts.map +1 -0
- package/dist/tool-call-record.js +276 -0
- package/dist/tool-call-record.js.map +1 -0
- package/dist/tool-protocol.d.ts +135 -0
- package/dist/tool-protocol.d.ts.map +1 -0
- package/dist/tool-protocol.js +104 -0
- package/dist/tool-protocol.js.map +1 -0
- package/dist/tool-worker.d.ts +3 -0
- package/dist/tool-worker.d.ts.map +1 -0
- package/dist/tool-worker.js +478 -0
- package/dist/tool-worker.js.map +1 -0
- package/dist/toolchain-mirror.d.ts +86 -0
- package/dist/toolchain-mirror.d.ts.map +1 -0
- package/dist/toolchain-mirror.js +307 -0
- package/dist/toolchain-mirror.js.map +1 -0
- package/dist/trusted-git.d.ts +243 -0
- package/dist/trusted-git.d.ts.map +1 -0
- package/dist/trusted-git.js +920 -0
- package/dist/trusted-git.js.map +1 -0
- package/dist/ui.d.ts +76 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +118 -0
- package/dist/ui.js.map +1 -0
- package/dist/untrusted-exec.d.ts +275 -0
- package/dist/untrusted-exec.d.ts.map +1 -0
- package/dist/untrusted-exec.js +479 -0
- package/dist/untrusted-exec.js.map +1 -0
- package/dist/untrusted-gate.d.ts +73 -0
- package/dist/untrusted-gate.d.ts.map +1 -0
- package/dist/untrusted-gate.js +226 -0
- package/dist/untrusted-gate.js.map +1 -0
- package/dist/uploader.d.ts +153 -0
- package/dist/uploader.d.ts.map +1 -0
- package/dist/uploader.js +204 -0
- package/dist/uploader.js.map +1 -0
- package/dist/verifier.d.ts +66 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +170 -0
- package/dist/verifier.js.map +1 -0
- package/dist/verify-apply.d.ts +26 -0
- package/dist/verify-apply.d.ts.map +1 -0
- package/dist/verify-apply.js +36 -0
- package/dist/verify-apply.js.map +1 -0
- package/dist/verify-cmd.d.ts +44 -0
- package/dist/verify-cmd.d.ts.map +1 -0
- package/dist/verify-cmd.js +125 -0
- package/dist/verify-cmd.js.map +1 -0
- package/dist/verify-pass.d.ts +73 -0
- package/dist/verify-pass.d.ts.map +1 -0
- package/dist/verify-pass.js +103 -0
- package/dist/verify-pass.js.map +1 -0
- package/dist/welcome.d.ts +43 -0
- package/dist/welcome.d.ts.map +1 -0
- package/dist/welcome.js +116 -0
- package/dist/welcome.js.map +1 -0
- package/dist/workspace-provisioner.d.ts +65 -0
- package/dist/workspace-provisioner.d.ts.map +1 -0
- package/dist/workspace-provisioner.js +66 -0
- package/dist/workspace-provisioner.js.map +1 -0
- package/dist/workspace-quarantine.d.ts +64 -0
- package/dist/workspace-quarantine.d.ts.map +1 -0
- package/dist/workspace-quarantine.js +156 -0
- package/dist/workspace-quarantine.js.map +1 -0
- package/dist/workspace-residue-sweep.d.ts +113 -0
- package/dist/workspace-residue-sweep.d.ts.map +1 -0
- package/dist/workspace-residue-sweep.js +158 -0
- package/dist/workspace-residue-sweep.js.map +1 -0
- package/dist/workspace.d.ts +639 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +2026 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +52 -4
- package/win/CredProbe.cs +64 -0
- package/win/FakeClaude.cs +56 -0
- package/win/HandleProbe.cs +116 -0
- package/win/TokenProbe.cs +53 -0
- package/win/appcontainer.ps1 +500 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,763 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfigError = exports.DEFAULTS = exports.PUBLISH_POLICIES = void 0;
|
|
4
|
+
exports.mayPublish = mayPublish;
|
|
5
|
+
exports.parseConfig = parseConfig;
|
|
6
|
+
exports.configWarnings = configWarnings;
|
|
7
|
+
const yaml_1 = require("yaml");
|
|
8
|
+
const core_1 = require("@looply/core");
|
|
9
|
+
const agent_exec_1 = require("./agent-exec");
|
|
10
|
+
const model_routing_1 = require("./model-routing");
|
|
11
|
+
const integration_1 = require("./integration");
|
|
12
|
+
exports.PUBLISH_POLICIES = ['never', 'on-approval', 'manual'];
|
|
13
|
+
/**
|
|
14
|
+
* May Looply itself publish, under this policy?
|
|
15
|
+
*
|
|
16
|
+
* ONE PREDICATE, so that no caller has to remember that `manual` means "not
|
|
17
|
+
* Looply". Two call sites reasoning about the enum separately is how one of
|
|
18
|
+
* them eventually treats an unfamiliar value as permission.
|
|
19
|
+
*/
|
|
20
|
+
function mayPublish(policy) {
|
|
21
|
+
return policy === 'on-approval';
|
|
22
|
+
}
|
|
23
|
+
exports.DEFAULTS = {
|
|
24
|
+
run: { minHours: 4, maxRounds: 400, cooldownS: 5, carryIntoCheckouts: [], maxConcurrentRuns: 1, perRoundSafety: false, surfaces: false, integration: false, brain: false },
|
|
25
|
+
machine: {
|
|
26
|
+
maxWorkspaces: 1,
|
|
27
|
+
maxAgentsInFlight: 1,
|
|
28
|
+
coordinator: false,
|
|
29
|
+
provisionWorkspaces: false,
|
|
30
|
+
preemption: false,
|
|
31
|
+
reapProvisioned: false,
|
|
32
|
+
idleCheckoutMinutes: 60,
|
|
33
|
+
integrate: false,
|
|
34
|
+
},
|
|
35
|
+
publish: { policy: 'never' },
|
|
36
|
+
rails: { exemptions: 'ask', prodEnvFiles: ['.env'] },
|
|
37
|
+
queue: { topupThreshold: 5, topupSize: 10, maxSameShape: 3 },
|
|
38
|
+
proof: { enabled: true, onPartial: 'ask', askWindowMin: 20 },
|
|
39
|
+
notify: { channel: 'sms', everyMin: 30 },
|
|
40
|
+
agent: agent_exec_1.DEFAULT_AGENT,
|
|
41
|
+
};
|
|
42
|
+
class ConfigError extends Error {
|
|
43
|
+
key;
|
|
44
|
+
constructor(key, message) {
|
|
45
|
+
super(`config: ${key} — ${message}`);
|
|
46
|
+
this.key = key;
|
|
47
|
+
this.name = 'ConfigError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.ConfigError = ConfigError;
|
|
51
|
+
const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
52
|
+
function str(o, key, path, fallback) {
|
|
53
|
+
const v = o[key];
|
|
54
|
+
if (v === undefined) {
|
|
55
|
+
if (fallback !== undefined)
|
|
56
|
+
return fallback;
|
|
57
|
+
throw new ConfigError(`${path}.${key}`, 'is required');
|
|
58
|
+
}
|
|
59
|
+
if (typeof v !== 'string' || !v.trim())
|
|
60
|
+
throw new ConfigError(`${path}.${key}`, 'must be a non-empty string');
|
|
61
|
+
return v;
|
|
62
|
+
}
|
|
63
|
+
function num(o, key, path, fallback, min = 0) {
|
|
64
|
+
const v = o[key];
|
|
65
|
+
if (v === undefined)
|
|
66
|
+
return fallback;
|
|
67
|
+
if (typeof v !== 'number' || !Number.isFinite(v))
|
|
68
|
+
throw new ConfigError(`${path}.${key}`, 'must be a number');
|
|
69
|
+
if (v < min)
|
|
70
|
+
throw new ConfigError(`${path}.${key}`, `must be >= ${min}`);
|
|
71
|
+
return v;
|
|
72
|
+
}
|
|
73
|
+
function bool(o, key, path, fallback) {
|
|
74
|
+
const v = o[key];
|
|
75
|
+
if (v === undefined)
|
|
76
|
+
return fallback;
|
|
77
|
+
if (typeof v !== 'boolean')
|
|
78
|
+
throw new ConfigError(`${path}.${key}`, 'must be true or false');
|
|
79
|
+
return v;
|
|
80
|
+
}
|
|
81
|
+
function strList(o, key, path, fallback = []) {
|
|
82
|
+
const v = o[key];
|
|
83
|
+
if (v === undefined)
|
|
84
|
+
return fallback;
|
|
85
|
+
if (!Array.isArray(v) || v.some((x) => typeof x !== 'string')) {
|
|
86
|
+
throw new ConfigError(`${path}.${key}`, 'must be a list of strings');
|
|
87
|
+
}
|
|
88
|
+
return v;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* `agent.models` and `agent.effort`, or nothing at all.
|
|
92
|
+
*
|
|
93
|
+
* ⚠️ REFUSED HERE, NOT AT ROUND ONE. A model id with a space in it, a role
|
|
94
|
+
* nobody has, or a Fable model named for an agent: each is the kind of mistake
|
|
95
|
+
* that should stop a run before it starts, not after the first model call has
|
|
96
|
+
* been paid for — the same reasoning `provider` is checked on. The rule itself
|
|
97
|
+
* lives in `model-routing.ts` so `looply doctor` can name the same key.
|
|
98
|
+
*/
|
|
99
|
+
function roleModelsOf(agent) {
|
|
100
|
+
const out = {};
|
|
101
|
+
const raw = agent['models'];
|
|
102
|
+
if (raw !== undefined) {
|
|
103
|
+
if (!isObj(raw))
|
|
104
|
+
throw new ConfigError('agent.models', 'must be a map of role to model id');
|
|
105
|
+
const models = {};
|
|
106
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
107
|
+
if (typeof value !== 'string')
|
|
108
|
+
throw new ConfigError(`agent.models.${key}`, 'must be a model id');
|
|
109
|
+
models[key] = value;
|
|
110
|
+
}
|
|
111
|
+
const verdict = (0, model_routing_1.checkRoleModels)(models);
|
|
112
|
+
if (!verdict.ok)
|
|
113
|
+
throw new ConfigError(verdict.key, verdict.because);
|
|
114
|
+
out.models = models;
|
|
115
|
+
}
|
|
116
|
+
if (agent['effort'] !== undefined) {
|
|
117
|
+
out.effort = oneOf(agent, 'effort', 'agent', model_routing_1.EFFORT_LEVELS, 'high');
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
function oneOf(o, key, path, allowed, fallback) {
|
|
122
|
+
const v = o[key];
|
|
123
|
+
if (v === undefined)
|
|
124
|
+
return fallback;
|
|
125
|
+
if (typeof v !== 'string' || !allowed.includes(v)) {
|
|
126
|
+
throw new ConfigError(`${path}.${key}`, `must be one of ${allowed.join(' | ')}`);
|
|
127
|
+
}
|
|
128
|
+
return v;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Read the human decisions, refusing anything malformed rather than guessing.
|
|
132
|
+
*
|
|
133
|
+
* An absent block is an empty list — a project that has recorded no decisions
|
|
134
|
+
* is the ordinary case, not an error. A malformed ENTRY is dropped rather than
|
|
135
|
+
* failing the whole config: a person editing YAML by hand should not lose their
|
|
136
|
+
* ability to run because one entry is half-written, and the entries that are
|
|
137
|
+
* well-formed still mean what they say.
|
|
138
|
+
*/
|
|
139
|
+
function parseDecisions(raw) {
|
|
140
|
+
if (!Array.isArray(raw))
|
|
141
|
+
return [];
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const entry of raw) {
|
|
144
|
+
if (!isObj(entry))
|
|
145
|
+
continue;
|
|
146
|
+
const subject = entry['subject'];
|
|
147
|
+
const decision = entry['decision'];
|
|
148
|
+
if (typeof subject !== 'string' || typeof decision !== 'string')
|
|
149
|
+
continue;
|
|
150
|
+
if (subject.trim() === '' || decision.trim() === '')
|
|
151
|
+
continue;
|
|
152
|
+
out.push({ subject: subject.trim(), decision: decision.trim() });
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
function parseGates(raw) {
|
|
157
|
+
if (raw === undefined)
|
|
158
|
+
throw new ConfigError('gates', 'is required — a run with no checks proves nothing');
|
|
159
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
160
|
+
throw new ConfigError('gates', 'must be a non-empty list');
|
|
161
|
+
}
|
|
162
|
+
const seen = new Set();
|
|
163
|
+
return raw.map((entry, i) => {
|
|
164
|
+
const path = `gates[${i}]`;
|
|
165
|
+
if (!isObj(entry))
|
|
166
|
+
throw new ConfigError(path, 'must be an object');
|
|
167
|
+
const name = str(entry, 'name', path);
|
|
168
|
+
if (seen.has(name))
|
|
169
|
+
throw new ConfigError(path, `duplicate step name ${JSON.stringify(name)}`);
|
|
170
|
+
seen.add(name);
|
|
171
|
+
const step = { name, run: str(entry, 'run', path) };
|
|
172
|
+
const timeoutS = num(entry, 'timeout_s', path, 0, 1);
|
|
173
|
+
if (timeoutS)
|
|
174
|
+
step.timeoutS = timeoutS;
|
|
175
|
+
if (entry['when'] !== undefined)
|
|
176
|
+
step.when = str(entry, 'when', path);
|
|
177
|
+
if (bool(entry, 'required', path, false))
|
|
178
|
+
step.required = true;
|
|
179
|
+
return step;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const PREDICATE_KEYS = ['equals', 'one_of', 'at_least', 'known'];
|
|
183
|
+
/**
|
|
184
|
+
* `machine.programme.acceptance` and its probes.
|
|
185
|
+
*
|
|
186
|
+
* Every refusal names the exact key, the same way the limits block does.
|
|
187
|
+
*/
|
|
188
|
+
function parseAcceptance(raw, probesRaw) {
|
|
189
|
+
const A = 'machine.programme.acceptance';
|
|
190
|
+
const PR = 'machine.programme.acceptance_probes';
|
|
191
|
+
const probes = [];
|
|
192
|
+
if (probesRaw !== undefined) {
|
|
193
|
+
if (!Array.isArray(probesRaw))
|
|
194
|
+
throw new ConfigError(PR, 'must be a list of { fact, run }');
|
|
195
|
+
probesRaw.forEach((entry, i) => {
|
|
196
|
+
if (!isObj(entry))
|
|
197
|
+
throw new ConfigError(`${PR}[${i}]`, 'must be { fact, run }');
|
|
198
|
+
const fact = entry['fact'];
|
|
199
|
+
const run = entry['run'];
|
|
200
|
+
if (typeof fact !== 'string' || !(0, core_1.isAcceptanceFact)(fact) || !fact.startsWith('probe.')) {
|
|
201
|
+
throw new ConfigError(`${PR}[${i}].fact`, 'must be a probe fact named probe.<lower-case-name>');
|
|
202
|
+
}
|
|
203
|
+
if (typeof run !== 'string' || run.trim() === '') {
|
|
204
|
+
throw new ConfigError(`${PR}[${i}].run`, 'is required — a probe with no command reads nothing');
|
|
205
|
+
}
|
|
206
|
+
if (probes.some((p) => p.fact === fact))
|
|
207
|
+
throw new ConfigError(`${PR}[${i}].fact`, `is declared twice: ${fact}`);
|
|
208
|
+
probes.push({ fact, run: run.trim() });
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (raw === undefined) {
|
|
212
|
+
if (probes.length > 0) {
|
|
213
|
+
throw new ConfigError(`${PR}[0].fact`, `reads ${probes[0]?.fact} and nothing requires it — declare it under acceptance, or remove the probe`);
|
|
214
|
+
}
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
if (!isObj(raw))
|
|
218
|
+
throw new ConfigError(A, 'must be a block of fact -> predicate');
|
|
219
|
+
const acceptance = {};
|
|
220
|
+
for (const fact of Object.keys(raw).sort()) {
|
|
221
|
+
if (!(0, core_1.isAcceptanceFact)(fact)) {
|
|
222
|
+
throw new ConfigError(`${A}.${fact}`, `is not a verification-environment fact (${core_1.ACCEPTANCE_FACTS.join(', ')}, or probe.<name>)`);
|
|
223
|
+
}
|
|
224
|
+
const spec = raw[fact];
|
|
225
|
+
if (!isObj(spec))
|
|
226
|
+
throw new ConfigError(`${A}.${fact}`, `must be one of { ${PREDICATE_KEYS.join(' | ')} }`);
|
|
227
|
+
const given = PREDICATE_KEYS.filter((k) => spec[k] !== undefined);
|
|
228
|
+
if (given.length !== 1) {
|
|
229
|
+
throw new ConfigError(`${A}.${fact}`, `needs exactly one of ${PREDICATE_KEYS.join(', ')} — found ${given.length === 0 ? 'none' : given.join(' and ')}`);
|
|
230
|
+
}
|
|
231
|
+
const key = given[0];
|
|
232
|
+
if (key === 'known') {
|
|
233
|
+
if (spec['known'] !== true)
|
|
234
|
+
throw new ConfigError(`${A}.${fact}.known`, 'must be true — it means "any value, but it must be readable"');
|
|
235
|
+
acceptance[fact] = { kind: 'known' };
|
|
236
|
+
}
|
|
237
|
+
else if (key === 'equals') {
|
|
238
|
+
const v = spec['equals'];
|
|
239
|
+
if (typeof v !== 'string' || v.trim() === '')
|
|
240
|
+
throw new ConfigError(`${A}.${fact}.equals`, 'must be a non-empty string');
|
|
241
|
+
acceptance[fact] = { kind: 'equals', value: v.trim() };
|
|
242
|
+
}
|
|
243
|
+
else if (key === 'one_of') {
|
|
244
|
+
const v = spec['one_of'];
|
|
245
|
+
if (!Array.isArray(v) || v.length === 0 || v.some((x) => typeof x !== 'string' || x.trim() === '')) {
|
|
246
|
+
throw new ConfigError(`${A}.${fact}.one_of`, 'must be a non-empty list of non-empty strings');
|
|
247
|
+
}
|
|
248
|
+
acceptance[fact] = { kind: 'one-of', values: v.map((x) => x.trim()) };
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
const v = spec['at_least'];
|
|
252
|
+
if (typeof v !== 'string' || !/[0-9]/.test(v)) {
|
|
253
|
+
throw new ConfigError(`${A}.${fact}.at_least`, 'must be a string containing a version, e.g. node@20.11.0 — the compare is dotted-numeric');
|
|
254
|
+
}
|
|
255
|
+
acceptance[fact] = { kind: 'at-least', version: v.trim() };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* 🔴 THE PAIRING, BOTH WAYS. Checked after both halves parse, so the message
|
|
260
|
+
* names the fact rather than the first structural problem it met.
|
|
261
|
+
*/
|
|
262
|
+
for (const fact of Object.keys(acceptance)) {
|
|
263
|
+
if (fact.startsWith('probe.') && !probes.some((p) => p.fact === fact)) {
|
|
264
|
+
throw new ConfigError(`${A}.${fact}`, `requires ${fact} and nothing reads it — add a probe under acceptance_probes, or remove the requirement`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const p of probes) {
|
|
268
|
+
if (acceptance[p.fact] === undefined) {
|
|
269
|
+
throw new ConfigError(`${PR}`, `reads ${p.fact} and nothing requires it — declare it under acceptance, or remove the probe`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
...(Object.keys(acceptance).length === 0 ? {} : { acceptance }),
|
|
274
|
+
...(probes.length === 0 ? {} : { acceptanceProbes: probes }),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const PROGRAMME_LIMIT_KEYS = ['max_workspaces', 'max_agents_in_flight', 'starts_per_grant', 'window_minutes', 'integration_ref'];
|
|
278
|
+
/**
|
|
279
|
+
* `machine.programme` as a block: `{ on: true, limits: { … } }`. Refused whole
|
|
280
|
+
* when `on` is not true, a limit is missing or out of range, the ref is not the
|
|
281
|
+
* lane's, or a key is not part of it — each refusal names the exact key.
|
|
282
|
+
* Absent, or a boolean, is not a block (slice 1 or nothing).
|
|
283
|
+
*/
|
|
284
|
+
function parseProgrammeBlock(raw) {
|
|
285
|
+
if (raw === undefined || typeof raw === 'boolean')
|
|
286
|
+
return null;
|
|
287
|
+
if (!isObj(raw))
|
|
288
|
+
throw new ConfigError('machine.programme', 'must be true, false, or a block { on, limits }');
|
|
289
|
+
const extra = Object.keys(raw).filter((k) => k !== 'on' && k !== 'limits' && k !== 'acceptance' && k !== 'acceptance_probes');
|
|
290
|
+
if (extra.length > 0) {
|
|
291
|
+
throw new ConfigError(`machine.programme.${extra.sort()[0]}`, 'is not part of programme mode (on, limits, acceptance, acceptance_probes)');
|
|
292
|
+
}
|
|
293
|
+
if (raw['on'] !== true) {
|
|
294
|
+
throw new ConfigError('machine.programme.on', 'must be true — a block declares programme mode on; leave the block out to keep manual defaults');
|
|
295
|
+
}
|
|
296
|
+
if (!isObj(raw['limits'])) {
|
|
297
|
+
throw new ConfigError('machine.programme.limits', `is required — programme mode needs its limits declared (${PROGRAMME_LIMIT_KEYS.join(', ')})`);
|
|
298
|
+
}
|
|
299
|
+
const limits = raw['limits'];
|
|
300
|
+
const P = 'machine.programme.limits';
|
|
301
|
+
for (const key of PROGRAMME_LIMIT_KEYS) {
|
|
302
|
+
if (limits[key] === undefined)
|
|
303
|
+
throw new ConfigError(`${P}.${key}`, 'is required — programme mode needs every limit declared');
|
|
304
|
+
}
|
|
305
|
+
const stray = Object.keys(limits).filter((k) => !PROGRAMME_LIMIT_KEYS.includes(k));
|
|
306
|
+
if (stray.length > 0)
|
|
307
|
+
throw new ConfigError(`${P}.${stray.sort()[0]}`, `is not a programme limit (${PROGRAMME_LIMIT_KEYS.join(', ')})`);
|
|
308
|
+
const startsPerGrant = num(limits, 'starts_per_grant', P, 1, 1);
|
|
309
|
+
if (startsPerGrant > core_1.MAX_AUTONOMOUS_STARTS)
|
|
310
|
+
throw new ConfigError(`${P}.starts_per_grant`, `must be <= ${core_1.MAX_AUTONOMOUS_STARTS}`);
|
|
311
|
+
const integrationRef = str(limits, 'integration_ref', P);
|
|
312
|
+
if (integrationRef !== integration_1.INTEGRATION_BRANCH) {
|
|
313
|
+
throw new ConfigError(`${P}.integration_ref`, `must be ${integration_1.INTEGRATION_BRANCH} — the lane integrates there and takes no other ref yet`);
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
limits: {
|
|
317
|
+
maxWorkspaces: num(limits, 'max_workspaces', P, 1, 1),
|
|
318
|
+
maxAgentsInFlight: num(limits, 'max_agents_in_flight', P, 1, 1),
|
|
319
|
+
startsPerGrant,
|
|
320
|
+
windowMinutes: num(limits, 'window_minutes', P, 1, 1),
|
|
321
|
+
integrationRef,
|
|
322
|
+
},
|
|
323
|
+
...parseAcceptance(raw['acceptance'], raw['acceptance_probes']),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/** A knob the umbrella declares: set there only; a copy beside the block must agree. */
|
|
327
|
+
function declaredOr(o, key, declared, fallback) {
|
|
328
|
+
if (declared === undefined)
|
|
329
|
+
return num(o, key, 'machine', fallback, 1);
|
|
330
|
+
if (o[key] !== undefined && o[key] !== declared) {
|
|
331
|
+
throw new ConfigError(`machine.${key}`, 'is declared in machine.programme.limits — set it there only');
|
|
332
|
+
}
|
|
333
|
+
return declared;
|
|
334
|
+
}
|
|
335
|
+
function parseConfig(text) {
|
|
336
|
+
let raw;
|
|
337
|
+
try {
|
|
338
|
+
raw = (0, yaml_1.parse)(text);
|
|
339
|
+
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
throw new ConfigError('<root>', `is not valid YAML: ${e.message}`);
|
|
342
|
+
}
|
|
343
|
+
if (!isObj(raw))
|
|
344
|
+
throw new ConfigError('<root>', 'must be a mapping');
|
|
345
|
+
const project = isObj(raw['project']) ? raw['project'] : undefined;
|
|
346
|
+
if (!project)
|
|
347
|
+
throw new ConfigError('project', 'is required');
|
|
348
|
+
const run = isObj(raw['run']) ? raw['run'] : {};
|
|
349
|
+
const rails = isObj(raw['rails']) ? raw['rails'] : {};
|
|
350
|
+
const machine = isObj(raw['machine']) ? raw['machine'] : {};
|
|
351
|
+
const scope = isObj(raw['scope']) ? raw['scope'] : {};
|
|
352
|
+
const queue = isObj(raw['queue']) ? raw['queue'] : {};
|
|
353
|
+
const proof = isObj(raw['proof']) ? raw['proof'] : {};
|
|
354
|
+
const notify = isObj(raw['notify']) ? raw['notify'] : {};
|
|
355
|
+
const publish = isObj(raw['publish']) ? raw['publish'] : {};
|
|
356
|
+
const agent = isObj(raw['agent']) ? raw['agent'] : {};
|
|
357
|
+
const server = isObj(raw['server']) ? raw['server'] : undefined;
|
|
358
|
+
const repos = Array.isArray(raw['repos']) ? raw['repos'] : undefined;
|
|
359
|
+
const sessions = isObj(raw['sessions']) ? raw['sessions'] : undefined;
|
|
360
|
+
const crossRepoNeeds = Array.isArray(raw['cross_repo_needs']) ? raw['cross_repo_needs'] : undefined;
|
|
361
|
+
// M6-10: the umbrella, read first — while it is on, every face defaults to on and the limits feed their knobs.
|
|
362
|
+
const umbrella = parseProgrammeBlock(machine['programme']);
|
|
363
|
+
const under = umbrella !== null;
|
|
364
|
+
const cfg = {
|
|
365
|
+
project: { name: str(project, 'name', 'project') },
|
|
366
|
+
run: {
|
|
367
|
+
minHours: num(run, 'min_hours', 'run', exports.DEFAULTS.run.minHours, 0),
|
|
368
|
+
maxRounds: num(run, 'max_rounds', 'run', exports.DEFAULTS.run.maxRounds, 1),
|
|
369
|
+
cooldownS: num(run, 'cooldown_s', 'run', exports.DEFAULTS.run.cooldownS, 0),
|
|
370
|
+
carryIntoCheckouts: strList(run, 'carry_into_checkouts', 'run'),
|
|
371
|
+
maxConcurrentRuns: num(run, 'max_concurrent_runs', 'run', exports.DEFAULTS.run.maxConcurrentRuns, 1),
|
|
372
|
+
perRoundSafety: bool(run, 'per_round_safety', 'run', false),
|
|
373
|
+
surfaces: bool(run, 'surfaces', 'run', false),
|
|
374
|
+
integration: bool(run, 'integration', 'run', under),
|
|
375
|
+
brain: bool(run, 'brain', 'run', under),
|
|
376
|
+
},
|
|
377
|
+
machine: {
|
|
378
|
+
maxWorkspaces: declaredOr(machine, 'max_workspaces', umbrella?.limits.maxWorkspaces, exports.DEFAULTS.machine.maxWorkspaces),
|
|
379
|
+
maxAgentsInFlight: declaredOr(machine, 'max_agents_in_flight', umbrella?.limits.maxAgentsInFlight, exports.DEFAULTS.machine.maxAgentsInFlight),
|
|
380
|
+
coordinator: bool(machine, 'coordinator', 'machine', under ? true : exports.DEFAULTS.machine.coordinator),
|
|
381
|
+
provisionWorkspaces: bool(machine, 'provision_workspaces', 'machine', under),
|
|
382
|
+
preemption: bool(machine, 'preemption', 'machine', under),
|
|
383
|
+
reapProvisioned: bool(machine, 'reap_provisioned', 'machine', under),
|
|
384
|
+
idleCheckoutMinutes: num(machine, 'idle_checkout_minutes', 'machine', 60, 0),
|
|
385
|
+
integrate: bool(machine, 'integrate', 'machine', under),
|
|
386
|
+
programme: under ? true : bool(machine, 'programme', 'machine', false),
|
|
387
|
+
...(umbrella === null ? {} : { programmeMode: umbrella }),
|
|
388
|
+
/**
|
|
389
|
+
* ⚠️ ALL OR NOTHING, AND ONLY WHEN THE BLOCK IS PRESENT. A half-specified
|
|
390
|
+
* envelope is worse than none: three ceilings written and one defaulted
|
|
391
|
+
* to something the person never chose is a limit they did not agree to,
|
|
392
|
+
* on a mechanism whose whole job is to stop the machine. The numbers that
|
|
393
|
+
* ARE defaulted here are defaulted only once somebody has written the
|
|
394
|
+
* block, which is the moment they have asked to be bounded.
|
|
395
|
+
*/
|
|
396
|
+
...(isObj(machine['envelope'])
|
|
397
|
+
? {
|
|
398
|
+
envelope: (() => {
|
|
399
|
+
const env = machine['envelope'];
|
|
400
|
+
const windowMinutes = num(env, 'window_minutes', 'machine.envelope', 60, 1);
|
|
401
|
+
const wallMinutes = num(env, 'max_wall_clock_minutes', 'machine.envelope', 8 * 60, 1);
|
|
402
|
+
const maxUsd = env['max_usd'];
|
|
403
|
+
return {
|
|
404
|
+
maxConcurrentRuns: num(env, 'max_concurrent_runs', 'machine.envelope', 1, 1),
|
|
405
|
+
maxStartsPerWindow: num(env, 'max_starts_per_window', 'machine.envelope', 20, 1),
|
|
406
|
+
windowMs: windowMinutes * 60_000,
|
|
407
|
+
maxWallClockMs: wallMinutes * 60_000,
|
|
408
|
+
...(maxUsd === undefined
|
|
409
|
+
? {}
|
|
410
|
+
: {
|
|
411
|
+
maxUsd: num(env, 'max_usd', 'machine.envelope', 0, 0),
|
|
412
|
+
/**
|
|
413
|
+
* 🔴 ABSENT MEANS ABSENT. IT USED TO MEAN ZERO,
|
|
414
|
+
* WHICH MEANT THE CEILING DID NOTHING.
|
|
415
|
+
*
|
|
416
|
+
* MEASURED: `max_usd: 25` with no estimate, sixteen
|
|
417
|
+
* starts — SIXTEEN ADMITTED. Each reservation held $0,
|
|
418
|
+
* so every start re-read a machine that intended to
|
|
419
|
+
* spend nothing and every one of them passed. The
|
|
420
|
+
* warning below has always said such a project would
|
|
421
|
+
* refuse; the parser quietly disagreed with it.
|
|
422
|
+
*
|
|
423
|
+
* Undefined makes an unpriced start unmeasurable, which
|
|
424
|
+
* `withinEnvelope` refuses — the behaviour the warning
|
|
425
|
+
* describes, and the one a person who wrote a dollar
|
|
426
|
+
* ceiling asked for.
|
|
427
|
+
*/
|
|
428
|
+
...(env['estimate_usd_per_start'] === undefined
|
|
429
|
+
? {}
|
|
430
|
+
: {
|
|
431
|
+
estimateUsdPerStart: num(env, 'estimate_usd_per_start', 'machine.envelope', 0, 0),
|
|
432
|
+
}),
|
|
433
|
+
}),
|
|
434
|
+
};
|
|
435
|
+
})(),
|
|
436
|
+
}
|
|
437
|
+
: {}),
|
|
438
|
+
},
|
|
439
|
+
gates: parseGates(raw['gates']),
|
|
440
|
+
decisions: parseDecisions(raw['decisions']),
|
|
441
|
+
rails: {
|
|
442
|
+
forbiddenPaths: strList(rails, 'forbidden_paths', 'rails'),
|
|
443
|
+
prodPatterns: strList(rails, 'prod_patterns', 'rails'),
|
|
444
|
+
prodEnvFiles: strList(rails, 'prod_env_files', 'rails', exports.DEFAULTS.rails.prodEnvFiles),
|
|
445
|
+
exemptions: oneOf(rails, 'exemptions', 'rails', ['ask', 'never'], exports.DEFAULTS.rails.exemptions),
|
|
446
|
+
},
|
|
447
|
+
scope: {
|
|
448
|
+
free: strList(scope, 'free', 'scope'),
|
|
449
|
+
additive: strList(scope, 'additive', 'scope'),
|
|
450
|
+
// The presence of the BLOCK, not of either list: `scope: {}` is a
|
|
451
|
+
// declaration, and so is one naming only `additive`.
|
|
452
|
+
declared: isObj(raw['scope']),
|
|
453
|
+
},
|
|
454
|
+
queue: {
|
|
455
|
+
topupThreshold: num(queue, 'topup_threshold', 'queue', exports.DEFAULTS.queue.topupThreshold, 0),
|
|
456
|
+
topupSize: num(queue, 'topup_size', 'queue', exports.DEFAULTS.queue.topupSize, 1),
|
|
457
|
+
maxSameShape: num(queue, 'max_same_shape', 'queue', exports.DEFAULTS.queue.maxSameShape, 1),
|
|
458
|
+
},
|
|
459
|
+
proof: {
|
|
460
|
+
enabled: bool(proof, 'enabled', 'proof', exports.DEFAULTS.proof.enabled),
|
|
461
|
+
onPartial: oneOf(proof, 'on_partial', 'proof', ['ask', 'keep', 'discard'], exports.DEFAULTS.proof.onPartial),
|
|
462
|
+
/**
|
|
463
|
+
* 🔴 HOW LONG A ROUND WAITS FOR THE ANSWER, and it is the same number
|
|
464
|
+
* written on the question's deadline. §6.C asks to *"keep independent
|
|
465
|
+
* work moving"*; a round is the loop's only thread, so waiting IS the
|
|
466
|
+
* cost. A minimum of one minute rather than zero: a window of zero is a
|
|
467
|
+
* question asked and abandoned in the same breath.
|
|
468
|
+
*/
|
|
469
|
+
askWindowMin: num(proof, 'ask_window_min', 'proof', exports.DEFAULTS.proof.askWindowMin, 1),
|
|
470
|
+
},
|
|
471
|
+
notify: {
|
|
472
|
+
channel: str(notify, 'channel', 'notify', exports.DEFAULTS.notify.channel),
|
|
473
|
+
everyMin: num(notify, 'every_min', 'notify', exports.DEFAULTS.notify.everyMin, 0),
|
|
474
|
+
},
|
|
475
|
+
// ABSENT MEANS `never`. A config that says nothing about publishing has not
|
|
476
|
+
// granted anything, and a value this build does not recognise throws like
|
|
477
|
+
// every other enum here — which is stricter than defaulting, because the
|
|
478
|
+
// run refuses to start at all rather than starting with a guess.
|
|
479
|
+
publish: {
|
|
480
|
+
policy: oneOf(publish, 'policy', 'publish', exports.PUBLISH_POLICIES, exports.DEFAULTS.publish.policy),
|
|
481
|
+
},
|
|
482
|
+
agent: {
|
|
483
|
+
command: str(agent, 'command', 'agent', exports.DEFAULTS.agent.command),
|
|
484
|
+
// Deliberately allowed to be empty: an agent with no such flag should be
|
|
485
|
+
// startable without inventing one for it.
|
|
486
|
+
outputFormatFlag: agent['output_format_flag'] === ''
|
|
487
|
+
? ''
|
|
488
|
+
: str(agent, 'output_format_flag', 'agent', exports.DEFAULTS.agent.outputFormatFlag),
|
|
489
|
+
/**
|
|
490
|
+
* An absolute path to the built-in provider's executable, for an
|
|
491
|
+
* installation that is not beside node. Absent means "find the package",
|
|
492
|
+
* which is the ordinary case. Validated at launch, not here: this
|
|
493
|
+
* function parses a file and must not touch the filesystem.
|
|
494
|
+
*/
|
|
495
|
+
...(typeof agent['executable'] === 'string' && agent['executable'] !== ''
|
|
496
|
+
? { executable: str(agent, 'executable', 'agent', '') }
|
|
497
|
+
: {}),
|
|
498
|
+
// Where a configured agent's runtime lives, for containment to grant.
|
|
499
|
+
// Absent for the built-in provider, which finds its own package.
|
|
500
|
+
runtime: strList(agent, 'runtime', 'agent'),
|
|
501
|
+
// Names only. The value comes from the daemon's environment, so a key
|
|
502
|
+
// never has to be written into a config file to reach the agent.
|
|
503
|
+
env: strList(agent, 'env', 'agent'),
|
|
504
|
+
/**
|
|
505
|
+
* The arguments that turn a CONFIGURED provider's own tools off.
|
|
506
|
+
*
|
|
507
|
+
* 🔴 REQUIRED FOR A CONFIGURED PROVIDER, AND THE TRANSPORT REFUSES
|
|
508
|
+
* WITHOUT IT. The built-in provider is mediated by flags looply knows;
|
|
509
|
+
* for anything else looply cannot guess, and a guessed flag that silently
|
|
510
|
+
* does nothing reads exactly like one that works. Empty here means the
|
|
511
|
+
* launch is refused rather than run unmediated.
|
|
512
|
+
*/
|
|
513
|
+
noHostTools: strList(agent, 'no_host_tools', 'agent'),
|
|
514
|
+
/**
|
|
515
|
+
* Which model each role runs, and how hard. Built-in provider only; see
|
|
516
|
+
* `model-routing.ts` for the rule that keeps a Fable model on the brain.
|
|
517
|
+
* Absent keys are absent from the spec, so a file that says nothing
|
|
518
|
+
* produces the invocation it always did.
|
|
519
|
+
*/
|
|
520
|
+
...roleModelsOf(agent),
|
|
521
|
+
/**
|
|
522
|
+
* WHICH AGENT KEYS THE FILE ACTUALLY CONTAINED.
|
|
523
|
+
*
|
|
524
|
+
* 🔴 WITHOUT THIS, A PRESET COULD NEVER WIN. `resolveProvider` treated a
|
|
525
|
+
* present `command` as "the person wrote one" — but `command` always has
|
|
526
|
+
* a value, because THIS function defaults it to Claude's. So the
|
|
527
|
+
* truthiness test was true for every project on earth, the preset's
|
|
528
|
+
* command was overridden every time, and somebody who wrote
|
|
529
|
+
* `provider: codex` got Claude while being shown a warning about codex
|
|
530
|
+
* that reads as confirmation.
|
|
531
|
+
*
|
|
532
|
+
* ⚠️ THE KEYS, NOT THE VALUES. "Absent" and "written, and equal to the
|
|
533
|
+
* default" are different statements and only one of them should lose to
|
|
534
|
+
* a preset. A person who explicitly writes Claude's command line beside
|
|
535
|
+
* `provider: codex` is saying something, even if it is a mistake, and it
|
|
536
|
+
* is not this function's place to discard it silently.
|
|
537
|
+
*/
|
|
538
|
+
declared: Object.keys(agent).filter((k) => agent[k] !== undefined),
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
// ⚠️ VALIDATED HERE, NOT AT ROUND 1. A misspelled provider name is the kind
|
|
542
|
+
// of mistake that should stop a run before it starts, not after the first
|
|
543
|
+
// model call has been spent finding out.
|
|
544
|
+
const providerName = agent['provider'];
|
|
545
|
+
if (providerName !== undefined && providerName !== '') {
|
|
546
|
+
cfg.provider = str(agent, 'provider', 'agent');
|
|
547
|
+
}
|
|
548
|
+
const id = project['id'];
|
|
549
|
+
if (id !== undefined)
|
|
550
|
+
cfg.project.id = str(project, 'id', 'project');
|
|
551
|
+
const to = notify['to'];
|
|
552
|
+
if (to !== undefined)
|
|
553
|
+
cfg.notify.to = str(notify, 'to', 'notify');
|
|
554
|
+
if (server) {
|
|
555
|
+
cfg.server = { url: str(server, 'url', 'server') };
|
|
556
|
+
if (server['machine_token_file'] !== undefined) {
|
|
557
|
+
cfg.server.machineTokenFile = str(server, 'machine_token_file', 'server');
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Validated strictly at load, like everything else here: a cross-repo mistake
|
|
562
|
+
* found at hour three of a run has already cost the night.
|
|
563
|
+
*/
|
|
564
|
+
if (repos !== undefined) {
|
|
565
|
+
const seen = new Set();
|
|
566
|
+
cfg.repos = repos.map((entry, i) => {
|
|
567
|
+
const at = `repos[${i}]`;
|
|
568
|
+
if (!isObj(entry))
|
|
569
|
+
throw new ConfigError(at, 'must be an object with id and path');
|
|
570
|
+
const id = str(entry, 'id', at);
|
|
571
|
+
if (!/^[A-Za-z0-9._-]+$/.test(id)) {
|
|
572
|
+
throw new ConfigError(`${at}.id`, 'must be letters, digits, dot, dash or underscore - it is an identity, not a path');
|
|
573
|
+
}
|
|
574
|
+
if (seen.has(id))
|
|
575
|
+
throw new ConfigError(`${at}.id`, `${id} is declared twice`);
|
|
576
|
+
seen.add(id);
|
|
577
|
+
return { id, path: str(entry, 'path', at) };
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
if (sessions !== undefined) {
|
|
581
|
+
const out = {};
|
|
582
|
+
if (sessions['repo'] !== undefined)
|
|
583
|
+
out.repo = str(sessions, 'repo', 'sessions');
|
|
584
|
+
if (sessions['budget_owner'] !== undefined)
|
|
585
|
+
out.budgetOwner = str(sessions, 'budget_owner', 'sessions');
|
|
586
|
+
// ⚠️ The PRESENCE of the key is the grant, so an explicitly empty list is a
|
|
587
|
+
// grant of nothing rather than no grant at all — the same distinction
|
|
588
|
+
// `scope.declared` draws two fields up.
|
|
589
|
+
if (sessions['scope'] !== undefined)
|
|
590
|
+
out.scope = strList(sessions, 'scope', 'sessions');
|
|
591
|
+
cfg.sessions = out;
|
|
592
|
+
}
|
|
593
|
+
if (crossRepoNeeds !== undefined) {
|
|
594
|
+
cfg.crossRepoNeeds = crossRepoNeeds.map((entry, i) => {
|
|
595
|
+
const at = `cross_repo_needs[${i}]`;
|
|
596
|
+
if (!isObj(entry))
|
|
597
|
+
throw new ConfigError(at, 'must be an object with repo and what');
|
|
598
|
+
// ⚠️ `repo` is NOT checked against `repos:` here. That is
|
|
599
|
+
// `crossRepoBlockedBy`'s answer — `undeclared` — and making it a load
|
|
600
|
+
// error instead would refuse a config whose only fault is that the two
|
|
601
|
+
// lists are being edited in either order.
|
|
602
|
+
return { repo: str(entry, 'repo', at), what: str(entry, 'what', at) };
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
// M6-10: the umbrella's window is the envelope's; declared once, in the limits.
|
|
606
|
+
if (umbrella !== null && cfg.machine !== undefined) {
|
|
607
|
+
const windowMs = umbrella.limits.windowMinutes * 60_000;
|
|
608
|
+
if (cfg.machine.envelope !== undefined) {
|
|
609
|
+
if (cfg.machine.envelope.windowMs !== windowMs) {
|
|
610
|
+
throw new ConfigError('machine.envelope.window_minutes', 'is declared in machine.programme.limits — set it there only');
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
/**
|
|
615
|
+
* 🔴 THE OWNER'S `max_agents_in_flight` IS THE RUN CEILING OF THE ENVELOPE
|
|
616
|
+
* LOOPLY WRITES FOR THEM — it used to be a hard-coded 1.
|
|
617
|
+
*
|
|
618
|
+
* Nobody declared that 1: the owner declares their limits in the block,
|
|
619
|
+
* and this envelope exists only because the block implies one. So a
|
|
620
|
+
* programme declared "2 agents in flight", the coordinator placed two
|
|
621
|
+
* goals in two checkouts, and the autonomy tick then refused the second
|
|
622
|
+
* Start on every cadence — "1 run(s) are in flight and the envelope
|
|
623
|
+
* allows 1 (maxConcurrentRuns)" — while the run that raced past it
|
|
624
|
+
* refused itself with the same sentence. MEASURED live (LIVE-2). An
|
|
625
|
+
* envelope the owner writes themselves is theirs and is untouched above.
|
|
626
|
+
*/
|
|
627
|
+
cfg.machine = {
|
|
628
|
+
...cfg.machine,
|
|
629
|
+
envelope: {
|
|
630
|
+
maxConcurrentRuns: umbrella.limits.maxAgentsInFlight,
|
|
631
|
+
maxStartsPerWindow: 20,
|
|
632
|
+
windowMs,
|
|
633
|
+
maxWallClockMs: 8 * 60 * 60_000,
|
|
634
|
+
},
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return cfg;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Warnings that do not block a run but that a user should see before starting one.
|
|
642
|
+
* Silence here was how the previous harness shipped 166 commits whose trailer
|
|
643
|
+
* named a check that had never run.
|
|
644
|
+
*/
|
|
645
|
+
function configWarnings(cfg) {
|
|
646
|
+
const warnings = [];
|
|
647
|
+
if (!cfg.rails.forbiddenPaths.length) {
|
|
648
|
+
warnings.push('rails.forbidden_paths is empty — nothing in this repo is off limits');
|
|
649
|
+
}
|
|
650
|
+
if (!cfg.gates.some((g) => g.required)) {
|
|
651
|
+
warnings.push('no gate step is marked required — a green gate proves less than you think');
|
|
652
|
+
}
|
|
653
|
+
if (!cfg.proof.enabled) {
|
|
654
|
+
warnings.push('proof.enabled is false — rounds will commit on a green build alone');
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* M6-20 / §6.C: WHO CAN BE ASKED, AND WHAT HAPPENS IF NOBODY ANSWERS.
|
|
658
|
+
*
|
|
659
|
+
* 🔴 THE ORIGINAL WARNING WAS TRUE FOR A YEAR. `on_partial: ask` was the
|
|
660
|
+
* default, no CLI code produced a question, and a run answered its own with
|
|
661
|
+
* `discard` (the audit's F-03). It also said what it was waiting for —
|
|
662
|
+
* *"Making it really ask is a change to the round protocol and the owner's
|
|
663
|
+
* decision"* — and `OWNER_CHARTER.md` §6.C is that decision, so a paired
|
|
664
|
+
* machine now raises a real question and waits `ask_window_min` for it.
|
|
665
|
+
*
|
|
666
|
+
* ⚠️ AN UNPAIRED ONE STILL CANNOT, AND THAT IS WHY BOTH HALVES ARE NAMED.
|
|
667
|
+
* `parseConfig` is pure and cannot read the pairing, so guessing which half
|
|
668
|
+
* a reader is in would make this warning wrong for somebody.
|
|
669
|
+
*/
|
|
670
|
+
if (cfg.proof.enabled && cfg.proof.onPartial === 'ask') {
|
|
671
|
+
warnings.push(`proof.on_partial is "ask": a paired machine raises a question and waits ${cfg.proof.askWindowMin} ` +
|
|
672
|
+
'minutes for an answer on your phone; an unpaired one has nobody to ask and discards, saying so on ' +
|
|
673
|
+
'the run\'s feed and on the item. Set it to "keep" or "discard" to decide without being asked');
|
|
674
|
+
}
|
|
675
|
+
if (cfg.notify.everyMin === 0) {
|
|
676
|
+
warnings.push('notify.every_min is 0 — this run will report nothing, including when it finishes');
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* 🔴 THE ONE BREAKING CHANGE IN THIS PROJECT'S HISTORY, SAID OUT LOUD AT
|
|
680
|
+
* LAST — IT USED TO ANNOUNCE ITSELF AT ROUND 1 OF AN OVERNIGHT RUN.
|
|
681
|
+
*
|
|
682
|
+
* Phase 6 made `agent.no_host_tools` REQUIRED of any configured provider,
|
|
683
|
+
* and the refusal lives in the transport: the first model call fails with a
|
|
684
|
+
* sentence naming the field. Nothing before that said anything — not
|
|
685
|
+
* `parseConfig`, not `looply doctor`, not `looply doctor --provider`, which
|
|
686
|
+
* returned PASS on exactly the configuration where every model call is
|
|
687
|
+
* refused.
|
|
688
|
+
*
|
|
689
|
+
* MEASURED by the cycle that found it: a config with no `provider:` line at
|
|
690
|
+
* all, just `agent: command: mycli exec`, parses clean, warns about nothing,
|
|
691
|
+
* passes doctor, and is refused at the first model call. That is EVERY
|
|
692
|
+
* project that ever set `agent.command` — not only the ones using a preset —
|
|
693
|
+
* and for each of them looply looked healthy right up to the moment it spent
|
|
694
|
+
* their evening finding out.
|
|
695
|
+
*
|
|
696
|
+
* ⚠️ THE REQUIREMENT ITSELF IS RIGHT AND IS NOT SOFTENED HERE. Looply cannot
|
|
697
|
+
* guess the flag that turns an unknown binary's tools off, and a guessed
|
|
698
|
+
* flag that silently does nothing reads exactly like one that works. What
|
|
699
|
+
* changes is WHEN a person is told: at the moment they can still fix it,
|
|
700
|
+
* rather than after the first model call has been spent.
|
|
701
|
+
*/
|
|
702
|
+
/**
|
|
703
|
+
* 🔴 A DOLLAR CEILING WITH NOTHING TO ESTIMATE AGAINST REFUSES EVERY START.
|
|
704
|
+
*
|
|
705
|
+
* Not a hypothetical: admission writes its own reservation first, reads the
|
|
706
|
+
* window back, and an unpriced reservation makes that window unmeasurable —
|
|
707
|
+
* which `withinEnvelope` refuses on, correctly. So a person who writes
|
|
708
|
+
* `max_usd` and nothing else gets a machine that never starts anything, with
|
|
709
|
+
* the only explanation a sentence in a daemon log at 3am.
|
|
710
|
+
*/
|
|
711
|
+
/**
|
|
712
|
+
* 🔴 THE CEILINGS THAT DISAGREE — AND THIS SENTENCE IS WHAT THE COORDINATOR
|
|
713
|
+
* END-TO-END PROOF COST AN HOUR TO LEARN.
|
|
714
|
+
*
|
|
715
|
+
* A project set `machine.max_workspaces: 2`; the scheduler correctly placed
|
|
716
|
+
* two goals in two checkouts; and exactly ONE run ever registered. The second
|
|
717
|
+
* was refused by `run.max_concurrent_runs`, which defaults to 1, AFTER a
|
|
718
|
+
* workspace had been cut, a goal placed and a process spawned. Neither number
|
|
719
|
+
* was wrong and nothing anywhere said they disagreed.
|
|
720
|
+
*
|
|
721
|
+
* ⚠️ IT NAMES THE BINDING CEILING RATHER THAN GUESSING AN INTENT. Looply does
|
|
722
|
+
* not raise anybody's limit for them — that is their decision — it only
|
|
723
|
+
* refuses to let the disagreement stay invisible.
|
|
724
|
+
*/
|
|
725
|
+
const trouble = (0, core_1.concurrencyTrouble)({
|
|
726
|
+
workspaces: cfg.machine?.maxWorkspaces,
|
|
727
|
+
runs: cfg.run.maxConcurrentRuns,
|
|
728
|
+
agents: cfg.machine?.maxAgentsInFlight,
|
|
729
|
+
});
|
|
730
|
+
if (trouble !== null)
|
|
731
|
+
warnings.push(trouble);
|
|
732
|
+
const envelope = cfg.machine?.envelope;
|
|
733
|
+
if (envelope?.maxUsd !== undefined && !((envelope.estimateUsdPerStart ?? 0) > 0)) {
|
|
734
|
+
warnings.push('machine.envelope.max_usd is set but estimate_usd_per_start is not — every autonomous start ' +
|
|
735
|
+
'will be REFUSED, because admission cannot show an unpriced start is under a dollar ceiling. ' +
|
|
736
|
+
'Set estimate_usd_per_start to what you expect one run to cost');
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* 🔴 A `provider:` PRESET IS A CONFIGURED COMMAND TOO — AND THIS TEST COULD NOT
|
|
740
|
+
* SEE ONE, SO `looply doctor` PASSED A PROJECT WHOSE EVERY MODEL CALL REFUSES.
|
|
741
|
+
*
|
|
742
|
+
* `agent.command` still holds the DEFAULT at parse time when a preset is
|
|
743
|
+
* named: `resolveProvider` substitutes the preset's command later, at run
|
|
744
|
+
* time. So `configured` was false, no warning was pushed, doctor printed none
|
|
745
|
+
* and exited 0 — and the first model call of the first run was refused by a
|
|
746
|
+
* message naming the very field doctor had just declined to mention.
|
|
747
|
+
*
|
|
748
|
+
* MEASURED: a config of `agent:
|
|
749
|
+
provider: "codex"` and nothing else —
|
|
750
|
+
* `looply doctor` exit 0, no mention of `no_host_tools`.
|
|
751
|
+
*/
|
|
752
|
+
const configured = cfg.agent.command !== exports.DEFAULTS.agent.command ||
|
|
753
|
+
(cfg.provider !== undefined && cfg.provider !== '');
|
|
754
|
+
if (configured && (cfg.agent.noHostTools?.length ?? 0) === 0) {
|
|
755
|
+
warnings.push('agent.no_host_tools is not set, and this project configures its own agent command ' +
|
|
756
|
+
'(directly, or through a provider preset) — ' +
|
|
757
|
+
'every model call will be REFUSED until it is. Looply gives a model no host tools and ' +
|
|
758
|
+
'cannot guess the argument that turns an unknown binary\'s own tools off; set it to those ' +
|
|
759
|
+
'arguments (for example `no_host_tools: ["--no-tools"]`)');
|
|
760
|
+
}
|
|
761
|
+
return warnings;
|
|
762
|
+
}
|
|
763
|
+
//# sourceMappingURL=config.js.map
|