toolroll 0.5.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 +1113 -0
- package/THIRD_PARTY_NOTICES.md +449 -0
- package/dist/accent-colors.d.ts +48 -0
- package/dist/accent-colors.js +122 -0
- package/dist/action-ledger.d.ts +26 -0
- package/dist/action-ledger.js +75 -0
- package/dist/agent-fence.d.ts +42 -0
- package/dist/agent-fence.js +183 -0
- package/dist/agentconfig.d.ts +216 -0
- package/dist/agentconfig.js +454 -0
- package/dist/api-tokens.d.ts +16 -0
- package/dist/api-tokens.js +27 -0
- package/dist/approval-policy.d.ts +69 -0
- package/dist/approval-policy.js +137 -0
- package/dist/approval-rules-ui.d.ts +25 -0
- package/dist/approval-rules-ui.js +39 -0
- package/dist/assignment-adapters.d.ts +180 -0
- package/dist/assignment-adapters.js +239 -0
- package/dist/assignment-brief.d.ts +71 -0
- package/dist/assignment-brief.js +129 -0
- package/dist/assignment-delivery.d.ts +56 -0
- package/dist/assignment-delivery.js +160 -0
- package/dist/assignment-presentation.d.ts +26 -0
- package/dist/assignment-presentation.js +80 -0
- package/dist/assignment-status.d.ts +62 -0
- package/dist/assignment-status.js +152 -0
- package/dist/assignment-ui.d.ts +71 -0
- package/dist/assignment-ui.js +103 -0
- package/dist/assignment.d.ts +222 -0
- package/dist/assignment.js +399 -0
- package/dist/attest.d.ts +56 -0
- package/dist/attest.js +153 -0
- package/dist/backend.d.ts +97 -0
- package/dist/backend.js +166 -0
- package/dist/backup-ui.d.ts +22 -0
- package/dist/backup-ui.js +59 -0
- package/dist/backup.d.ts +84 -0
- package/dist/backup.js +421 -0
- package/dist/beads.d.ts +34 -0
- package/dist/beads.js +135 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +22 -0
- package/dist/board.d.ts +150 -0
- package/dist/board.js +210 -0
- package/dist/boot-identity.d.ts +63 -0
- package/dist/boot-identity.js +99 -0
- package/dist/browser/THIRD_PARTY_NOTICES.txt +2295 -0
- package/dist/browser/workspace.css +4 -0
- package/dist/browser/workspace.js +225 -0
- package/dist/browser-crew.d.ts +11 -0
- package/dist/browser-crew.js +50 -0
- package/dist/browser-shell.d.ts +8 -0
- package/dist/browser-shell.js +60 -0
- package/dist/browser-workspace.d.ts +780 -0
- package/dist/browser-workspace.js +47 -0
- package/dist/budget-alerts.d.ts +19 -0
- package/dist/budget-alerts.js +46 -0
- package/dist/builder.d.ts +370 -0
- package/dist/builder.js +3262 -0
- package/dist/capscan.d.ts +35 -0
- package/dist/capscan.js +113 -0
- package/dist/chat-acceptance.d.ts +71 -0
- package/dist/chat-acceptance.js +120 -0
- package/dist/chat-actions.d.ts +265 -0
- package/dist/chat-actions.js +1273 -0
- package/dist/chat-channel.d.ts +109 -0
- package/dist/chat-channel.js +652 -0
- package/dist/chat-continuity.d.ts +32 -0
- package/dist/chat-continuity.js +317 -0
- package/dist/chat-controls.d.ts +113 -0
- package/dist/chat-controls.js +53 -0
- package/dist/chat-delivery-state.d.ts +159 -0
- package/dist/chat-delivery-state.js +309 -0
- package/dist/chat-delivery.d.ts +38 -0
- package/dist/chat-delivery.js +693 -0
- package/dist/chat-display.d.ts +1 -0
- package/dist/chat-display.js +18 -0
- package/dist/chat-evidence.d.ts +123 -0
- package/dist/chat-evidence.js +207 -0
- package/dist/chat-flow.d.ts +44 -0
- package/dist/chat-flow.js +215 -0
- package/dist/chat-inbox.d.ts +57 -0
- package/dist/chat-inbox.js +123 -0
- package/dist/chat-polish.d.ts +16 -0
- package/dist/chat-polish.js +135 -0
- package/dist/chat-review.d.ts +46 -0
- package/dist/chat-review.js +98 -0
- package/dist/chat-rooms.d.ts +123 -0
- package/dist/chat-rooms.js +216 -0
- package/dist/chat-task-actions.d.ts +44 -0
- package/dist/chat-task-actions.js +79 -0
- package/dist/check-progress.d.ts +51 -0
- package/dist/check-progress.js +290 -0
- package/dist/child-database.d.ts +12 -0
- package/dist/child-database.js +30 -0
- package/dist/claim.d.ts +688 -0
- package/dist/claim.js +1740 -0
- package/dist/cli.d.ts +137 -0
- package/dist/cli.js +1461 -0
- package/dist/codex-limits.d.ts +15 -0
- package/dist/codex-limits.js +145 -0
- package/dist/coding-context.d.ts +55 -0
- package/dist/coding-context.js +92 -0
- package/dist/coding-handoff.d.ts +57 -0
- package/dist/coding-handoff.js +277 -0
- package/dist/coding-provider.d.ts +72 -0
- package/dist/coding-provider.js +424 -0
- package/dist/coding-shipping-ui.d.ts +4 -0
- package/dist/coding-shipping-ui.js +12 -0
- package/dist/coding-types.d.ts +62 -0
- package/dist/coding-types.js +1 -0
- package/dist/coding-ui.d.ts +17 -0
- package/dist/coding-ui.js +364 -0
- package/dist/coding-update.d.ts +15 -0
- package/dist/coding-update.js +149 -0
- package/dist/coding-workspace.d.ts +124 -0
- package/dist/coding-workspace.js +768 -0
- package/dist/container-state.d.ts +5 -0
- package/dist/container-state.js +62 -0
- package/dist/containment.d.ts +197 -0
- package/dist/containment.js +559 -0
- package/dist/contest.d.ts +318 -0
- package/dist/contest.js +753 -0
- package/dist/control-setup.d.ts +35 -0
- package/dist/control-setup.js +40 -0
- package/dist/control-ui.d.ts +29 -0
- package/dist/control-ui.js +53 -0
- package/dist/controller-service.d.ts +1 -0
- package/dist/controller-service.js +19 -0
- package/dist/controller-supervisor.d.ts +30 -0
- package/dist/controller-supervisor.js +104 -0
- package/dist/converse.d.ts +304 -0
- package/dist/converse.js +849 -0
- package/dist/coordinator-proposals.d.ts +29 -0
- package/dist/coordinator-proposals.js +137 -0
- package/dist/coordinator.d.ts +186 -0
- package/dist/coordinator.js +447 -0
- package/dist/credentials-ui.d.ts +25 -0
- package/dist/credentials-ui.js +48 -0
- package/dist/daemon.d.ts +209 -0
- package/dist/daemon.js +604 -0
- package/dist/decision.d.ts +120 -0
- package/dist/decision.js +388 -0
- package/dist/demo.d.ts +55 -0
- package/dist/demo.js +992 -0
- package/dist/desktop-access.d.ts +28 -0
- package/dist/desktop-access.js +88 -0
- package/dist/desktop-bundle.d.ts +16 -0
- package/dist/desktop-bundle.js +74 -0
- package/dist/desktop-host.d.ts +54 -0
- package/dist/desktop-host.js +508 -0
- package/dist/desktop-update-gate.d.ts +12 -0
- package/dist/desktop-update-gate.js +91 -0
- package/dist/desktop-update-recovery.d.ts +14 -0
- package/dist/desktop-update-recovery.js +243 -0
- package/dist/desktop-update.d.ts +110 -0
- package/dist/desktop-update.js +740 -0
- package/dist/discord-api.d.ts +20 -0
- package/dist/discord-api.js +138 -0
- package/dist/discord-chat.d.ts +16 -0
- package/dist/discord-chat.js +381 -0
- package/dist/discord-settings.d.ts +7 -0
- package/dist/discord-settings.js +75 -0
- package/dist/discord.d.ts +10 -0
- package/dist/discord.js +169 -0
- package/dist/discover.d.ts +75 -0
- package/dist/discover.js +150 -0
- package/dist/dispatch.d.ts +100 -0
- package/dist/dispatch.js +311 -0
- package/dist/dispose.d.ts +161 -0
- package/dist/dispose.js +803 -0
- package/dist/email-settings.d.ts +34 -0
- package/dist/email-settings.js +50 -0
- package/dist/envelope.d.ts +47 -0
- package/dist/envelope.js +105 -0
- package/dist/evidence-pack.d.ts +185 -0
- package/dist/evidence-pack.js +258 -0
- package/dist/evidence.d.ts +345 -0
- package/dist/evidence.js +782 -0
- package/dist/exec.d.ts +285 -0
- package/dist/exec.js +1841 -0
- package/dist/exhaustion.d.ts +85 -0
- package/dist/exhaustion.js +141 -0
- package/dist/export-ui.d.ts +4 -0
- package/dist/export-ui.js +17 -0
- package/dist/export.d.ts +48 -0
- package/dist/export.js +305 -0
- package/dist/flow-actions.d.ts +77 -0
- package/dist/flow-actions.js +203 -0
- package/dist/flow-code.d.ts +50 -0
- package/dist/flow-code.js +159 -0
- package/dist/flow-draft.d.ts +38 -0
- package/dist/flow-draft.js +80 -0
- package/dist/flow-engine.d.ts +66 -0
- package/dist/flow-engine.js +416 -0
- package/dist/flow-insights.d.ts +95 -0
- package/dist/flow-insights.js +149 -0
- package/dist/flow-live.d.ts +24 -0
- package/dist/flow-live.js +150 -0
- package/dist/flow-people.d.ts +24 -0
- package/dist/flow-people.js +91 -0
- package/dist/flow-replies.d.ts +48 -0
- package/dist/flow-replies.js +113 -0
- package/dist/flow-scripts.d.ts +38 -0
- package/dist/flow-scripts.js +73 -0
- package/dist/flow-secrets.d.ts +13 -0
- package/dist/flow-secrets.js +45 -0
- package/dist/flow-sort.d.ts +82 -0
- package/dist/flow-sort.js +153 -0
- package/dist/flow-steps.d.ts +40 -0
- package/dist/flow-steps.js +408 -0
- package/dist/flow-triggers.d.ts +244 -0
- package/dist/flow-triggers.js +959 -0
- package/dist/flows-ui.d.ts +20 -0
- package/dist/flows-ui.js +175 -0
- package/dist/flows.d.ts +229 -0
- package/dist/flows.js +968 -0
- package/dist/fonts.d.ts +19 -0
- package/dist/fonts.js +19 -0
- package/dist/gaps.d.ts +35 -0
- package/dist/gaps.js +101 -0
- package/dist/gate-failure.d.ts +40 -0
- package/dist/gate-failure.js +66 -0
- package/dist/git.d.ts +54 -0
- package/dist/git.js +94 -0
- package/dist/google-mail.d.ts +58 -0
- package/dist/google-mail.js +151 -0
- package/dist/grant.d.ts +136 -0
- package/dist/grant.js +238 -0
- package/dist/graph.d.ts +164 -0
- package/dist/graph.js +383 -0
- package/dist/guides.d.ts +22 -0
- package/dist/guides.js +363 -0
- package/dist/held.d.ts +150 -0
- package/dist/held.js +799 -0
- package/dist/invoke.d.ts +112 -0
- package/dist/invoke.js +780 -0
- package/dist/issues.d.ts +41 -0
- package/dist/issues.js +131 -0
- package/dist/job-object-helper.ps1 +252 -0
- package/dist/jsonl-discriminants.d.ts +11 -0
- package/dist/jsonl-discriminants.js +93 -0
- package/dist/keys.d.ts +104 -0
- package/dist/keys.js +229 -0
- package/dist/kits-ui.d.ts +17 -0
- package/dist/kits-ui.js +46 -0
- package/dist/kits.d.ts +86 -0
- package/dist/kits.js +215 -0
- package/dist/knowledge-cli.d.ts +101 -0
- package/dist/knowledge-cli.js +92 -0
- package/dist/knowledge-ui.d.ts +24 -0
- package/dist/knowledge-ui.js +40 -0
- package/dist/lead-context.d.ts +8 -0
- package/dist/lead-context.js +56 -0
- package/dist/lead-follow.d.ts +22 -0
- package/dist/lead-follow.js +167 -0
- package/dist/lead-status.d.ts +75 -0
- package/dist/lead-status.js +285 -0
- package/dist/ledger-chain.d.ts +46 -0
- package/dist/ledger-chain.js +187 -0
- package/dist/ledger-csv.d.ts +4 -0
- package/dist/ledger-csv.js +11 -0
- package/dist/ledger-view.d.ts +24 -0
- package/dist/ledger-view.js +58 -0
- package/dist/limits-ui.d.ts +26 -0
- package/dist/limits-ui.js +67 -0
- package/dist/link.d.ts +72 -0
- package/dist/link.js +217 -0
- package/dist/live.d.ts +96 -0
- package/dist/live.js +366 -0
- package/dist/liveness.d.ts +30 -0
- package/dist/liveness.js +42 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +25 -0
- package/dist/mailbox.d.ts +57 -0
- package/dist/mailbox.js +150 -0
- package/dist/maintenance.d.ts +11 -0
- package/dist/maintenance.js +35 -0
- package/dist/mate-cli.d.ts +52 -0
- package/dist/mate-cli.js +345 -0
- package/dist/mate-contract.d.ts +10 -0
- package/dist/mate-contract.js +30 -0
- package/dist/mate-doors.d.ts +69 -0
- package/dist/mate-doors.js +548 -0
- package/dist/mate-progress.d.ts +29 -0
- package/dist/mate-progress.js +121 -0
- package/dist/mate-tools.d.ts +94 -0
- package/dist/mate-tools.js +1878 -0
- package/dist/mate.d.ts +92 -0
- package/dist/mate.js +435 -0
- package/dist/mcp-connect.d.ts +103 -0
- package/dist/mcp-connect.js +252 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +651 -0
- package/dist/memory-cli.d.ts +466 -0
- package/dist/memory-cli.js +111 -0
- package/dist/memory-pass.d.ts +160 -0
- package/dist/memory-pass.js +409 -0
- package/dist/metrics.d.ts +3 -0
- package/dist/metrics.js +56 -0
- package/dist/mobile-viewport.d.ts +3 -0
- package/dist/mobile-viewport.js +37 -0
- package/dist/model-catalog.d.ts +118 -0
- package/dist/model-catalog.js +376 -0
- package/dist/models-cli.d.ts +102 -0
- package/dist/models-cli.js +66 -0
- package/dist/models-ui.d.ts +34 -0
- package/dist/models-ui.js +68 -0
- package/dist/modes.d.ts +80 -0
- package/dist/modes.js +182 -0
- package/dist/monitoring-settings.d.ts +44 -0
- package/dist/monitoring-settings.js +173 -0
- package/dist/monitoring-ui.d.ts +20 -0
- package/dist/monitoring-ui.js +51 -0
- package/dist/monitoring.d.ts +34 -0
- package/dist/monitoring.js +221 -0
- package/dist/names.d.ts +67 -0
- package/dist/names.js +102 -0
- package/dist/observations.d.ts +40 -0
- package/dist/observations.js +211 -0
- package/dist/oidc.d.ts +71 -0
- package/dist/oidc.js +182 -0
- package/dist/onboard.d.ts +108 -0
- package/dist/onboard.js +325 -0
- package/dist/openrouter-models.d.ts +30 -0
- package/dist/openrouter-models.js +120 -0
- package/dist/operate.d.ts +118 -0
- package/dist/operate.js +11321 -0
- package/dist/peek-cli.d.ts +97 -0
- package/dist/peek-cli.js +215 -0
- package/dist/peek.d.ts +134 -0
- package/dist/peek.js +578 -0
- package/dist/phase-routing.d.ts +307 -0
- package/dist/phase-routing.js +658 -0
- package/dist/plan-auto.d.ts +14 -0
- package/dist/plan-auto.js +92 -0
- package/dist/plan.d.ts +186 -0
- package/dist/plan.js +401 -0
- package/dist/planner-source.d.ts +251 -0
- package/dist/planner-source.js +460 -0
- package/dist/planner.d.ts +75 -0
- package/dist/planner.js +992 -0
- package/dist/policy-ui.d.ts +20 -0
- package/dist/policy-ui.js +41 -0
- package/dist/policy.d.ts +111 -0
- package/dist/policy.js +231 -0
- package/dist/prepared-evidence.d.ts +16 -0
- package/dist/prepared-evidence.js +96 -0
- package/dist/pricing.d.ts +45 -0
- package/dist/pricing.js +77 -0
- package/dist/principal.d.ts +42 -0
- package/dist/principal.js +82 -0
- package/dist/probe.d.ts +46 -0
- package/dist/probe.js +79 -0
- package/dist/process-custody.d.ts +17 -0
- package/dist/process-custody.js +91 -0
- package/dist/process-liveness.d.ts +10 -0
- package/dist/process-liveness.js +81 -0
- package/dist/process-recovery-anchor.d.ts +75 -0
- package/dist/process-recovery-anchor.js +188 -0
- package/dist/process-recovery-coalition.d.ts +25 -0
- package/dist/process-recovery-coalition.js +105 -0
- package/dist/process-recovery-eligibility.d.ts +178 -0
- package/dist/process-recovery-eligibility.js +170 -0
- package/dist/process-recovery-native.d.ts +172 -0
- package/dist/process-recovery-native.js +592 -0
- package/dist/process-recovery-provenance.d.ts +163 -0
- package/dist/process-recovery-provenance.js +292 -0
- package/dist/process-recovery-services.d.ts +56 -0
- package/dist/process-recovery-services.js +191 -0
- package/dist/process-recovery-settlement.d.ts +32 -0
- package/dist/process-recovery-settlement.js +132 -0
- package/dist/process-recovery.d.ts +41 -0
- package/dist/process-recovery.js +91 -0
- package/dist/process-tree.d.ts +41 -0
- package/dist/process-tree.js +264 -0
- package/dist/project-access.d.ts +14 -0
- package/dist/project-access.js +34 -0
- package/dist/project-cli.d.ts +18 -0
- package/dist/project-cli.js +104 -0
- package/dist/project-delete-ui.d.ts +22 -0
- package/dist/project-delete-ui.js +48 -0
- package/dist/project-delete.d.ts +55 -0
- package/dist/project-delete.js +413 -0
- package/dist/project-knowledge.d.ts +111 -0
- package/dist/project-knowledge.js +241 -0
- package/dist/project-learning.d.ts +100 -0
- package/dist/project-learning.js +438 -0
- package/dist/project-memory.d.ts +81 -0
- package/dist/project-memory.js +264 -0
- package/dist/project-skills.d.ts +152 -0
- package/dist/project-skills.js +660 -0
- package/dist/project-tools.d.ts +219 -0
- package/dist/project-tools.js +796 -0
- package/dist/project.d.ts +61 -0
- package/dist/project.js +125 -0
- package/dist/prompt.d.ts +22 -0
- package/dist/prompt.js +72 -0
- package/dist/proof.d.ts +513 -0
- package/dist/proof.js +1140 -0
- package/dist/proposal.d.ts +82 -0
- package/dist/proposal.js +210 -0
- package/dist/provider-connection.d.ts +22 -0
- package/dist/provider-connection.js +98 -0
- package/dist/provider-limits.d.ts +35 -0
- package/dist/provider-limits.js +95 -0
- package/dist/provider.d.ts +279 -0
- package/dist/provider.js +935 -0
- package/dist/publish.d.ts +107 -0
- package/dist/publish.js +650 -0
- package/dist/pulls.d.ts +118 -0
- package/dist/pulls.js +240 -0
- package/dist/push.d.ts +95 -0
- package/dist/push.js +353 -0
- package/dist/quality.d.ts +8 -0
- package/dist/quality.js +6 -0
- package/dist/recipe-ui.d.ts +18 -0
- package/dist/recipe-ui.js +152 -0
- package/dist/recipes.d.ts +81 -0
- package/dist/recipes.js +332 -0
- package/dist/remote.d.ts +67 -0
- package/dist/remote.js +122 -0
- package/dist/render.d.ts +64 -0
- package/dist/render.js +587 -0
- package/dist/report-summary.d.ts +13 -0
- package/dist/report-summary.js +15 -0
- package/dist/repos.d.ts +65 -0
- package/dist/repos.js +277 -0
- package/dist/repository-context-ui.d.ts +2 -0
- package/dist/repository-context-ui.js +10 -0
- package/dist/repository-context.d.ts +67 -0
- package/dist/repository-context.js +376 -0
- package/dist/restart-certification.d.ts +134 -0
- package/dist/restart-certification.js +226 -0
- package/dist/result-actions.d.ts +28 -0
- package/dist/result-actions.js +270 -0
- package/dist/result-completion.d.ts +18 -0
- package/dist/result-completion.js +66 -0
- package/dist/result-review.d.ts +213 -0
- package/dist/result-review.js +430 -0
- package/dist/retention-ui.d.ts +12 -0
- package/dist/retention-ui.js +39 -0
- package/dist/retention.d.ts +72 -0
- package/dist/retention.js +288 -0
- package/dist/review-context.d.ts +243 -0
- package/dist/review-context.js +1043 -0
- package/dist/review-evidence.d.ts +33 -0
- package/dist/review-evidence.js +56 -0
- package/dist/reviewer.d.ts +97 -0
- package/dist/reviewer.js +202 -0
- package/dist/routine.d.ts +228 -0
- package/dist/routine.js +764 -0
- package/dist/runner.d.ts +266 -0
- package/dist/runner.js +399 -0
- package/dist/scan.d.ts +32 -0
- package/dist/scan.js +92 -0
- package/dist/scope.d.ts +695 -0
- package/dist/scope.js +1176 -0
- package/dist/scout-report.d.ts +42 -0
- package/dist/scout-report.js +108 -0
- package/dist/scout.d.ts +69 -0
- package/dist/scout.js +351 -0
- package/dist/serve.d.ts +313 -0
- package/dist/serve.js +21776 -0
- package/dist/session-brief.d.ts +8 -0
- package/dist/session-brief.js +24 -0
- package/dist/session-cli.d.ts +13 -0
- package/dist/session-cli.js +284 -0
- package/dist/session-contract.d.ts +183 -0
- package/dist/session-contract.js +122 -0
- package/dist/session-http.d.ts +19 -0
- package/dist/session-http.js +154 -0
- package/dist/session-server.d.ts +12 -0
- package/dist/session-server.js +37 -0
- package/dist/session-service.d.ts +22 -0
- package/dist/session-service.js +157 -0
- package/dist/setup-guide.d.ts +39 -0
- package/dist/setup-guide.js +93 -0
- package/dist/sign-in-guard.d.ts +45 -0
- package/dist/sign-in-guard.js +74 -0
- package/dist/skills-ui.d.ts +11 -0
- package/dist/skills-ui.js +58 -0
- package/dist/skills.d.ts +97 -0
- package/dist/skills.js +276 -0
- package/dist/slack-api.d.ts +55 -0
- package/dist/slack-api.js +229 -0
- package/dist/slack-chat.d.ts +28 -0
- package/dist/slack-chat.js +413 -0
- package/dist/slack-settings.d.ts +7 -0
- package/dist/slack-settings.js +75 -0
- package/dist/slack-state.d.ts +13 -0
- package/dist/slack-state.js +9 -0
- package/dist/slack.d.ts +13 -0
- package/dist/slack.js +167 -0
- package/dist/spend-ui.d.ts +28 -0
- package/dist/spend-ui.js +95 -0
- package/dist/spend.d.ts +142 -0
- package/dist/spend.js +313 -0
- package/dist/sqlite-runtime.d.ts +3 -0
- package/dist/sqlite-runtime.js +6 -0
- package/dist/sso-settings.d.ts +33 -0
- package/dist/sso-settings.js +103 -0
- package/dist/sso-ui.d.ts +22 -0
- package/dist/sso-ui.js +39 -0
- package/dist/storage.d.ts +15 -0
- package/dist/storage.js +84 -0
- package/dist/store.d.ts +7754 -0
- package/dist/store.js +23279 -0
- package/dist/structured-output.d.ts +58 -0
- package/dist/structured-output.js +103 -0
- package/dist/style-asset.d.ts +7 -0
- package/dist/style-asset.js +41 -0
- package/dist/subscription-chat.d.ts +46 -0
- package/dist/subscription-chat.js +275 -0
- package/dist/summary.d.ts +33 -0
- package/dist/summary.js +71 -0
- package/dist/supervisor.mjs +297 -0
- package/dist/surface.d.ts +63 -0
- package/dist/surface.js +352 -0
- package/dist/sync.d.ts +94 -0
- package/dist/sync.js +279 -0
- package/dist/task-composer.d.ts +13 -0
- package/dist/task-composer.js +52 -0
- package/dist/task-control.d.ts +165 -0
- package/dist/task-control.js +214 -0
- package/dist/task-outcome-cli.d.ts +10 -0
- package/dist/task-outcome-cli.js +92 -0
- package/dist/task-text.d.ts +30 -0
- package/dist/task-text.js +41 -0
- package/dist/team-cli.d.ts +15 -0
- package/dist/team-cli.js +618 -0
- package/dist/team-contract.d.ts +92 -0
- package/dist/team-contract.js +1 -0
- package/dist/team-http.d.ts +17 -0
- package/dist/team-http.js +144 -0
- package/dist/team-leads.d.ts +81 -0
- package/dist/team-leads.js +565 -0
- package/dist/team-runtime.d.ts +27 -0
- package/dist/team-runtime.js +264 -0
- package/dist/team-ui.d.ts +3 -0
- package/dist/team-ui.js +9 -0
- package/dist/team-updates.d.ts +8 -0
- package/dist/team-updates.js +57 -0
- package/dist/teammate-admin.d.ts +53 -0
- package/dist/teammate-admin.js +111 -0
- package/dist/teammate-desk.d.ts +60 -0
- package/dist/teammate-desk.js +154 -0
- package/dist/teammate-memory.d.ts +64 -0
- package/dist/teammate-memory.js +196 -0
- package/dist/teammate-question.d.ts +59 -0
- package/dist/teammate-question.js +175 -0
- package/dist/teammate-tools.d.ts +108 -0
- package/dist/teammate-tools.js +271 -0
- package/dist/teammate-week.d.ts +68 -0
- package/dist/teammate-week.js +132 -0
- package/dist/teammate-work.d.ts +76 -0
- package/dist/teammate-work.js +280 -0
- package/dist/teammates-ui.d.ts +20 -0
- package/dist/teammates-ui.js +166 -0
- package/dist/teammates.d.ts +180 -0
- package/dist/teammates.js +253 -0
- package/dist/teams-api.d.ts +33 -0
- package/dist/teams-api.js +204 -0
- package/dist/teams-chat.d.ts +26 -0
- package/dist/teams-chat.js +215 -0
- package/dist/teams-settings.d.ts +12 -0
- package/dist/teams-settings.js +57 -0
- package/dist/teams.d.ts +21 -0
- package/dist/teams.js +124 -0
- package/dist/telegram-flow.d.ts +49 -0
- package/dist/telegram-flow.js +110 -0
- package/dist/telegram-mate.d.ts +137 -0
- package/dist/telegram-mate.js +707 -0
- package/dist/telegram-progress.d.ts +14 -0
- package/dist/telegram-progress.js +129 -0
- package/dist/telegram-settings.d.ts +9 -0
- package/dist/telegram-settings.js +36 -0
- package/dist/telegram-status.d.ts +75 -0
- package/dist/telegram-status.js +265 -0
- package/dist/telegram-team.d.ts +85 -0
- package/dist/telegram-team.js +359 -0
- package/dist/telegram.d.ts +230 -0
- package/dist/telegram.js +1931 -0
- package/dist/templates.d.ts +65 -0
- package/dist/templates.js +118 -0
- package/dist/tool-launcher.d.ts +1 -0
- package/dist/tool-launcher.js +101 -0
- package/dist/tools-ui.d.ts +30 -0
- package/dist/tools-ui.js +40 -0
- package/dist/transitions-recipes.d.ts +1 -0
- package/dist/transitions-recipes.js +203 -0
- package/dist/tree-proof.d.ts +34 -0
- package/dist/tree-proof.js +58 -0
- package/dist/verification-evidence.d.ts +44 -0
- package/dist/verification-evidence.js +238 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +10 -0
- package/dist/webhooks.d.ts +91 -0
- package/dist/webhooks.js +283 -0
- package/dist/work-index.d.ts +68 -0
- package/dist/work-index.js +384 -0
- package/dist/work-summary.d.ts +57 -0
- package/dist/work-summary.js +116 -0
- package/dist/workspace-motion.d.ts +4 -0
- package/dist/workspace-motion.js +133 -0
- package/dist/workspace-revision.d.ts +19 -0
- package/dist/workspace-revision.js +92 -0
- package/dist/workspace-ui.d.ts +204 -0
- package/dist/workspace-ui.js +411 -0
- package/dist/worktree-notices.d.ts +13 -0
- package/dist/worktree-notices.js +17 -0
- package/dist/worktree.d.ts +249 -0
- package/dist/worktree.js +720 -0
- package/package.json +122 -0
- package/scripts/canary-assertions.mjs +42 -0
- package/scripts/crash-canary.mjs +253 -0
- package/scripts/fixtures/crash-process.mjs +74 -0
- package/scripts/fixtures/pilot-scenarios.mjs +85 -0
- package/scripts/fixtures/restart-service.mjs +27 -0
- package/scripts/launchd-certification.mjs +143 -0
- package/scripts/pilot.mjs +121 -0
- package/scripts/proof-preflight.mjs +140 -0
- package/scripts/provider-canary.mjs +379 -0
- package/scripts/recovery-canary.mjs +135 -0
- package/scripts/restart-certification.mjs +98 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { modeTermsFromJson } from "./modes.js";
|
|
2
|
+
import { plannerContractOf, plannerSourceDigest } from "./planner-source.js";
|
|
3
|
+
import { modeFilingCoverage, propose } from "./scope.js";
|
|
4
|
+
export const PLAN_AUTO_SCHEMA = `CREATE TABLE IF NOT EXISTS plan_authorization (
|
|
5
|
+
task_id TEXT PRIMARY KEY REFERENCES task(id),
|
|
6
|
+
source_digest TEXT NOT NULL,
|
|
7
|
+
scope_digest TEXT NOT NULL,
|
|
8
|
+
mode_digest TEXT NOT NULL,
|
|
9
|
+
signed_by TEXT NOT NULL,
|
|
10
|
+
created_at TEXT NOT NULL
|
|
11
|
+
);`;
|
|
12
|
+
function plainPlan(store, taskId) {
|
|
13
|
+
const ref = store.lookupRef(taskId);
|
|
14
|
+
return ref !== null && ref.deliverable === "branch" && ref.coordinatorCid === null &&
|
|
15
|
+
store.activeTournamentTerms(ref.id) === null && store.openAuthorizationFor(ref.id) === null && store.mirrorByTask(taskId) === null;
|
|
16
|
+
}
|
|
17
|
+
/** Join the console's authority-free proposal to the authenticated filing
|
|
18
|
+
* road in one transaction. Planning defers the seal until verified ingestion. */
|
|
19
|
+
export function applyModeToNewFiling(store, taskId, actor, now) {
|
|
20
|
+
const ref = store.lookupRef(taskId);
|
|
21
|
+
const scope = store.getScope(taskId);
|
|
22
|
+
const coverage = modeFilingCoverage(store, ref?.repo ?? null, actor, now);
|
|
23
|
+
if (ref === null || scope === null || scope.proposedVia != null || coverage === null)
|
|
24
|
+
return;
|
|
25
|
+
const filed = propose(store, { taskId, goal: scope.goal, outOfScope: scope.outOfScope, touches: scope.touches, acceptance: scope.acceptance,
|
|
26
|
+
budgetMicrousd: scope.budgetMicrousd ?? coverage.defaultBudgetMicrousd,
|
|
27
|
+
qualityMode: scope.qualityMode ?? "default", riskLevel: scope.riskLevel ?? "routine",
|
|
28
|
+
...(coverage.escalated ? { posture: "escalated" } : {}), now });
|
|
29
|
+
if (ref.plan === "requested")
|
|
30
|
+
authorizePlanUnderMode(store, taskId, actor, now);
|
|
31
|
+
else if (filed.profileState === "resolved")
|
|
32
|
+
store.sealScopeApproval(taskId, actor, now, {}, { kind: "mode", modeDigest: coverage.digest });
|
|
33
|
+
}
|
|
34
|
+
/** Called only by credentialed operator roads, never by proposal/intake
|
|
35
|
+
* code. This authorizes the exact filed contract, not arbitrary future
|
|
36
|
+
* planner text. Rewrites, mode renewal, expiry and revocation fail closed. */
|
|
37
|
+
export function authorizePlanUnderMode(store, taskId, actor, now) {
|
|
38
|
+
return store.transact(() => {
|
|
39
|
+
const ref = store.lookupRef(taskId);
|
|
40
|
+
if (ref === null || ref.repo === null || ref.plan !== "requested" || !plainPlan(store, taskId) || store.hasLiveClaim(ref.id, now))
|
|
41
|
+
return false;
|
|
42
|
+
const mode = store.activeMode(ref.repo, now);
|
|
43
|
+
const terms = mode === null ? null : modeTermsFromJson(mode.termsJson);
|
|
44
|
+
if (mode === null || mode.signedBy !== actor || !terms?.planAuto || !terms.autoApproveFiling || !store.accountCanAccess(actor, ref.repo))
|
|
45
|
+
return false;
|
|
46
|
+
const source = plannerContractOf(store, taskId);
|
|
47
|
+
if (!source.ok || source.contract.scope === null || source.contract.revision !== null)
|
|
48
|
+
return false;
|
|
49
|
+
const scope = source.contract.scope;
|
|
50
|
+
if (scope.proposedVia !== null || scope.acceptance.length === 0 || scope.touches.length === 0 || scope.terms.profileState !== "resolved" || store.scopeSealed(taskId))
|
|
51
|
+
return false;
|
|
52
|
+
store.raw().prepare(`INSERT INTO plan_authorization(task_id,source_digest,scope_digest,mode_digest,signed_by,created_at) VALUES (?,?,?,?,?,?)
|
|
53
|
+
ON CONFLICT(task_id) DO UPDATE SET source_digest=excluded.source_digest,scope_digest=excluded.scope_digest,mode_digest=excluded.mode_digest,signed_by=excluded.signed_by,created_at=excluded.created_at`)
|
|
54
|
+
.run(taskId, plannerSourceDigest(source.contract), scope.digest, mode.digest, actor, now.toISOString());
|
|
55
|
+
store.recordAction({ at: now.toISOString(), actor, repo: ref.repo, taskId, runId: null, action: "unchanged plan pre-authorized", outcome: "authorized", source: "work" });
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** Read-side status only; finalization still proves the authority anew. */
|
|
60
|
+
export function planAutoPending(store, taskId, now) {
|
|
61
|
+
const ref = store.lookupRef(taskId);
|
|
62
|
+
if (ref?.repo == null || ref.plan !== "requested" || !plainPlan(store, taskId))
|
|
63
|
+
return false;
|
|
64
|
+
const row = store.raw().prepare("SELECT * FROM plan_authorization WHERE task_id=?").get(taskId);
|
|
65
|
+
if (row === undefined)
|
|
66
|
+
return false;
|
|
67
|
+
const mode = store.activeMode(ref.repo, now);
|
|
68
|
+
const terms = mode === null ? null : modeTermsFromJson(mode.termsJson);
|
|
69
|
+
const source = plannerContractOf(store, taskId);
|
|
70
|
+
return mode !== null && terms?.planAuto === true && terms.autoApproveFiling && mode.digest === row["mode_digest"] && mode.signedBy === row["signed_by"] &&
|
|
71
|
+
store.accountCanAccess(mode.signedBy, ref.repo) && source.ok && plannerSourceDigest(source.contract) === row["source_digest"];
|
|
72
|
+
}
|
|
73
|
+
/** Inside the verified planner finalization transaction, after the source,
|
|
74
|
+
* artifact, contract changes and lease fence have all been checked. */
|
|
75
|
+
export function sealUnchangedPlanUnderMode(store, taskId, sourceDigest, runId, eligible, now) {
|
|
76
|
+
const authorization = store.raw().prepare("SELECT * FROM plan_authorization WHERE task_id = ?").get(taskId);
|
|
77
|
+
if (authorization === undefined)
|
|
78
|
+
return false;
|
|
79
|
+
// One conclusion consumes the authorization even when it needs a human.
|
|
80
|
+
store.raw().prepare("DELETE FROM plan_authorization WHERE task_id = ?").run(taskId);
|
|
81
|
+
const ref = store.lookupRef(taskId);
|
|
82
|
+
const scope = store.getScope(taskId);
|
|
83
|
+
const mode = ref?.repo == null ? null : store.activeMode(ref.repo, now);
|
|
84
|
+
const terms = mode === null ? null : modeTermsFromJson(mode.termsJson);
|
|
85
|
+
const by = String(authorization["signed_by"]);
|
|
86
|
+
const covered = eligible && plainPlan(store, taskId) && sourceDigest === authorization["source_digest"] && scope?.digest === authorization["scope_digest"] &&
|
|
87
|
+
mode !== null && mode.digest === authorization["mode_digest"] && mode.signedBy === by &&
|
|
88
|
+
terms?.planAuto === true && terms.autoApproveFiling && store.accountCanAccess(by, ref?.repo ?? null);
|
|
89
|
+
const approved = covered && store.sealScopeApproval(taskId, by, now, {}, { kind: "mode", modeDigest: mode.digest });
|
|
90
|
+
store.recordAction({ at: now.toISOString(), actor: by, repo: ref?.repo ?? null, taskId, runId, action: "plan auto-approval", outcome: approved ? "approved" : "needs approval", source: "work" });
|
|
91
|
+
return approved;
|
|
92
|
+
}
|
package/dist/plan.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The planner's terminal handoff, parsed with the 422 rule: fail closed,
|
|
3
|
+
* every problem reported at once, stable reasons, caps and control-character
|
|
4
|
+
* rejection on every string — because a plan payload reaches terminals, the
|
|
5
|
+
* approve card, and the builder's brief (Codex planning review, question 2:
|
|
6
|
+
* the scope proposal is authority-bearing, so it gets the park discipline).
|
|
7
|
+
*/
|
|
8
|
+
import { type AcceptanceCriterion } from "./scope.js";
|
|
9
|
+
export type PlanProblem = {
|
|
10
|
+
reason: string;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
export type ParsedPlan = {
|
|
14
|
+
goal: string;
|
|
15
|
+
outOfScope: string | null;
|
|
16
|
+
touches: string[];
|
|
17
|
+
/** v39: the rubric the planner drafts alongside the goal — mandatory,
|
|
18
|
+
* because the planner is a scope-producing road like any other (the
|
|
19
|
+
* scope text names it explicitly). A malformed or empty rubric fails
|
|
20
|
+
* the whole plan the same way a missing goal always has. */
|
|
21
|
+
acceptance: AcceptanceCriterion[];
|
|
22
|
+
/** The plan document, markdown, rendered fenced-inert everywhere. */
|
|
23
|
+
plan: string;
|
|
24
|
+
/** Why the filed contract must change (contract handoff, task 1): a
|
|
25
|
+
* planner that proposes different goal/outOfScope/touches/acceptance
|
|
26
|
+
* than the operator filed says so HERE, or the plan is malformed. Null
|
|
27
|
+
* when the plan reproduces the filed terms, or when none were filed. */
|
|
28
|
+
amendment: string | null;
|
|
29
|
+
};
|
|
30
|
+
/** A deliberately small execution plan. The signed scope remains the
|
|
31
|
+
* authority; this is the durable road the builder is expected to follow.
|
|
32
|
+
* Fixed sections make the handoff scannable in the console and prevent the
|
|
33
|
+
* planner from hiding the useful parts in a long essay. */
|
|
34
|
+
export type ExecutionPlanDocument = {
|
|
35
|
+
approach: string;
|
|
36
|
+
milestones: string[];
|
|
37
|
+
dependencies: string[];
|
|
38
|
+
risks: string[];
|
|
39
|
+
proof: string[];
|
|
40
|
+
};
|
|
41
|
+
export type ExecutionPlanDocumentResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
document: ExecutionPlanDocument;
|
|
44
|
+
} | {
|
|
45
|
+
ok: false;
|
|
46
|
+
problems: PlanProblem[];
|
|
47
|
+
};
|
|
48
|
+
/** Parse the planner's human-readable artifact without executing Markdown.
|
|
49
|
+
* Older free-form plan artifacts remain renderable through the caller's
|
|
50
|
+
* fallback, while every newly accepted planner handoff uses this shape. */
|
|
51
|
+
export declare function parseExecutionPlanDocument(raw: string): ExecutionPlanDocumentResult;
|
|
52
|
+
/**
|
|
53
|
+
* The inverse of `parseExecutionPlanDocument`: the canonical fenced-section
|
|
54
|
+
* markdown for a document the parser already admitted.
|
|
55
|
+
*
|
|
56
|
+
* A builder's revision proposal arrives as free-form text that the parser
|
|
57
|
+
* validates and reduces to this shape; what gets STORED — and later
|
|
58
|
+
* hash-verified, re-read, and quoted into the next brief — is rendered back
|
|
59
|
+
* from that validated shape, never the agent's raw bytes (the scout
|
|
60
|
+
* report's rule, and settleProof's). `parseExecutionPlanDocument` composed
|
|
61
|
+
* with this function is the identity on every document the parser admits:
|
|
62
|
+
* sections in their fixed order, one bullet per item, nothing else.
|
|
63
|
+
*/
|
|
64
|
+
export declare function renderExecutionPlanDocument(document: ExecutionPlanDocument): string;
|
|
65
|
+
export type PlanParseResult = {
|
|
66
|
+
ok: true;
|
|
67
|
+
plan: ParsedPlan;
|
|
68
|
+
} | {
|
|
69
|
+
ok: false;
|
|
70
|
+
problems: PlanProblem[];
|
|
71
|
+
};
|
|
72
|
+
/** Caps matching the scope ritual's fields, plus the document itself. */
|
|
73
|
+
export declare const PLAN_LIMITS: {
|
|
74
|
+
readonly payload: number;
|
|
75
|
+
readonly goal: 2000;
|
|
76
|
+
readonly outOfScope: 2000;
|
|
77
|
+
readonly touch: 200;
|
|
78
|
+
readonly touches: 32;
|
|
79
|
+
readonly document: number;
|
|
80
|
+
readonly amendment: 1000;
|
|
81
|
+
};
|
|
82
|
+
export declare function parsePlan(raw: string): PlanParseResult;
|
|
83
|
+
export type MilestoneState = "pending" | "current" | "completed" | "blocked";
|
|
84
|
+
export type Milestone = {
|
|
85
|
+
id: string;
|
|
86
|
+
description: string;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* A milestone's identity is its position plus a short hash of its
|
|
90
|
+
* normalized text — stable across re-reads of the same revision, but a
|
|
91
|
+
* milestone whose wording changes materially becomes a NEW identity rather
|
|
92
|
+
* than silently inheriting stale completion state from a differently-worded
|
|
93
|
+
* predecessor.
|
|
94
|
+
*/
|
|
95
|
+
export declare function milestoneId(index: number, description: string): string;
|
|
96
|
+
export declare function milestonesOf(document: ExecutionPlanDocument): Milestone[];
|
|
97
|
+
export type ProgressEntry = {
|
|
98
|
+
id: string;
|
|
99
|
+
state: MilestoneState;
|
|
100
|
+
note: string | null;
|
|
101
|
+
};
|
|
102
|
+
/** The builder's atomic progress checkpoint: every milestone in the plan
|
|
103
|
+
* revision it received, exactly once each, bound to that revision's exact
|
|
104
|
+
* hash so a checkpoint can never be misread against a different plan. */
|
|
105
|
+
export type ProgressSnapshot = {
|
|
106
|
+
revisionHash: string;
|
|
107
|
+
milestones: ProgressEntry[];
|
|
108
|
+
};
|
|
109
|
+
export type ProgressParseResult = {
|
|
110
|
+
ok: true;
|
|
111
|
+
snapshot: ProgressSnapshot;
|
|
112
|
+
} | {
|
|
113
|
+
ok: false;
|
|
114
|
+
problems: PlanProblem[];
|
|
115
|
+
};
|
|
116
|
+
export declare const PROGRESS_LIMITS: {
|
|
117
|
+
readonly payload: number;
|
|
118
|
+
readonly note: 300;
|
|
119
|
+
readonly milestones: 12;
|
|
120
|
+
};
|
|
121
|
+
/** Parse a progress checkpoint written by a running build. `expectedRevisionHash`
|
|
122
|
+
* and `knownIds` come from the plan revision the build's brief actually
|
|
123
|
+
* named — a snapshot naming a different revision, an unknown milestone id,
|
|
124
|
+
* a missing milestone, or more than one "current" milestone fails closed
|
|
125
|
+
* with every problem at once, the same 422 rule as the plan itself. */
|
|
126
|
+
export declare function parseProgressSnapshot(raw: string, expectedRevisionHash: string, knownIds: readonly string[]): ProgressParseResult;
|
|
127
|
+
/** Whether a checkpoint transition is a legitimate update or a regression:
|
|
128
|
+
* once a milestone is completed it never reverts — an agent restating an
|
|
129
|
+
* old snapshot (a stale pulse, a retried read) must never erase progress
|
|
130
|
+
* that a later, newer checkpoint already recorded. */
|
|
131
|
+
export declare function isMilestoneRegression(previous: MilestoneState | undefined, next: MilestoneState): boolean;
|
|
132
|
+
export type PlanRevisionProposal = {
|
|
133
|
+
/** The complete replacement plan document — the same shape the planner
|
|
134
|
+
* itself produces, never a diff, so a revision is always fully readable
|
|
135
|
+
* on its own. */
|
|
136
|
+
document: ExecutionPlanDocument;
|
|
137
|
+
/** Why: the named dependency, risk, or implementation assumption the
|
|
138
|
+
* repository evidence invalidated. */
|
|
139
|
+
reason: string;
|
|
140
|
+
/** Where: a path, commit, or command output the operator (or a later
|
|
141
|
+
* reader) can go re-check. */
|
|
142
|
+
evidenceLink: string;
|
|
143
|
+
};
|
|
144
|
+
export type PlanRevisionProposalParseResult = {
|
|
145
|
+
ok: true;
|
|
146
|
+
proposal: PlanRevisionProposal;
|
|
147
|
+
} | {
|
|
148
|
+
ok: false;
|
|
149
|
+
problems: PlanProblem[];
|
|
150
|
+
};
|
|
151
|
+
export declare const REVISION_LIMITS: {
|
|
152
|
+
readonly payload: number;
|
|
153
|
+
readonly reason: 2000;
|
|
154
|
+
readonly evidenceLink: 500;
|
|
155
|
+
};
|
|
156
|
+
/** Parse the builder's terminal revision-proposal file: a complete
|
|
157
|
+
* replacement plan document plus the evidence that invalidated the one it
|
|
158
|
+
* was given. One proposal per build — the caller enforces that by never
|
|
159
|
+
* offering the agent more than one nonce-named path to write. */
|
|
160
|
+
export declare function parsePlanRevisionProposal(raw: string): PlanRevisionProposalParseResult;
|
|
161
|
+
/** The exact authority a build's approval rests on: the signed scope
|
|
162
|
+
* (goal, out-of-scope, touches, acceptance, permissions, quality, budget —
|
|
163
|
+
* everything folded into the scope digest) plus publication authority
|
|
164
|
+
* (branch vs. report). A plan revision may only auto-resume when this is
|
|
165
|
+
* byte-identical to what it was when the build started; anything else
|
|
166
|
+
* stays paused for a person, named. */
|
|
167
|
+
export type AuthoritySnapshot = {
|
|
168
|
+
scopeDigest: string;
|
|
169
|
+
deliverable: "branch" | "report";
|
|
170
|
+
};
|
|
171
|
+
export declare function authoritySnapshotDigest(snapshot: AuthoritySnapshot): string;
|
|
172
|
+
export type AuthorityChangeField = "signed-scope" | "publication-authority";
|
|
173
|
+
export type RevisionAuthorityCheck = {
|
|
174
|
+
kind: "plan-only";
|
|
175
|
+
} | {
|
|
176
|
+
kind: "authority-change";
|
|
177
|
+
changed: AuthorityChangeField[];
|
|
178
|
+
};
|
|
179
|
+
/** Classify a revision against the complete authority snapshot the build
|
|
180
|
+
* actually started under. Everything the builder's own proposal can name is
|
|
181
|
+
* plan-only by construction (it carries no scope fields at all) — this
|
|
182
|
+
* check exists as the defense against the world moving underneath a live
|
|
183
|
+
* build: if the signed scope or publication authority changed by any other
|
|
184
|
+
* road while the build ran, the revision is never auto-applied, whatever it
|
|
185
|
+
* proposes. */
|
|
186
|
+
export declare function classifyRevisionAuthority(previous: AuthoritySnapshot, current: AuthoritySnapshot): RevisionAuthorityCheck;
|
package/dist/plan.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The planner's terminal handoff, parsed with the 422 rule: fail closed,
|
|
3
|
+
* every problem reported at once, stable reasons, caps and control-character
|
|
4
|
+
* rejection on every string — because a plan payload reaches terminals, the
|
|
5
|
+
* approve card, and the builder's brief (Codex planning review, question 2:
|
|
6
|
+
* the scope proposal is authority-bearing, so it gets the park discipline).
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { hasForbiddenControls } from "./decision.js";
|
|
10
|
+
import { parseAcceptanceCriteria } from "./scope.js";
|
|
11
|
+
const EXECUTION_PLAN_SECTIONS = ["approach", "milestones", "dependencies", "risks", "proof"];
|
|
12
|
+
const EXECUTION_PLAN_LIST_CAP = 12;
|
|
13
|
+
const EXECUTION_PLAN_ITEM_CAP = 600;
|
|
14
|
+
/** Parse the planner's human-readable artifact without executing Markdown.
|
|
15
|
+
* Older free-form plan artifacts remain renderable through the caller's
|
|
16
|
+
* fallback, while every newly accepted planner handoff uses this shape. */
|
|
17
|
+
export function parseExecutionPlanDocument(raw) {
|
|
18
|
+
const problems = [];
|
|
19
|
+
if (Buffer.byteLength(raw, "utf8") > PLAN_LIMITS.document) {
|
|
20
|
+
return { ok: false, problems: [{ reason: "plan-too-long", message: `plan is over ${PLAN_LIMITS.document} bytes` }] };
|
|
21
|
+
}
|
|
22
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
23
|
+
if (hasForbiddenControls(normalized)) {
|
|
24
|
+
return { ok: false, problems: [{ reason: "plan-controls", message: "plan carries control characters that could become terminal escapes" }] };
|
|
25
|
+
}
|
|
26
|
+
const sections = new Map();
|
|
27
|
+
let current = null;
|
|
28
|
+
let lastSection = -1;
|
|
29
|
+
for (const line of normalized.split("\n")) {
|
|
30
|
+
const heading = /^##\s+(.+?)\s*$/.exec(line);
|
|
31
|
+
if (heading !== null) {
|
|
32
|
+
const name = (heading[1] ?? "").trim().toLowerCase();
|
|
33
|
+
if (!EXECUTION_PLAN_SECTIONS.includes(name)) {
|
|
34
|
+
problems.push({ reason: "plan-unknown-section", message: `plan section \"${heading[1]}\" is not one of Approach, Milestones, Dependencies, Risks, or Proof` });
|
|
35
|
+
current = null;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const position = EXECUTION_PLAN_SECTIONS.indexOf(name);
|
|
39
|
+
if (position < lastSection) {
|
|
40
|
+
problems.push({ reason: "plan-section-order", message: "plan sections must stay in order: Approach, Milestones, Dependencies, Risks, Proof" });
|
|
41
|
+
}
|
|
42
|
+
lastSection = Math.max(lastSection, position);
|
|
43
|
+
if (sections.has(name))
|
|
44
|
+
problems.push({ reason: `plan-duplicate-${name}`, message: `plan has more than one ${name} section` });
|
|
45
|
+
sections.set(name, []);
|
|
46
|
+
current = name;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (current === null) {
|
|
50
|
+
if (line.trim() !== "")
|
|
51
|
+
problems.push({ reason: "plan-preamble", message: "plan must start with ## Approach" });
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
sections.get(current)?.push(line);
|
|
55
|
+
}
|
|
56
|
+
for (const section of EXECUTION_PLAN_SECTIONS) {
|
|
57
|
+
if (!sections.has(section))
|
|
58
|
+
problems.push({ reason: `plan-missing-${section}`, message: `plan needs a ## ${section[0]?.toUpperCase()}${section.slice(1)} section` });
|
|
59
|
+
}
|
|
60
|
+
if (problems.length > 0)
|
|
61
|
+
return { ok: false, problems };
|
|
62
|
+
const approach = (sections.get("approach") ?? []).join("\n").trim();
|
|
63
|
+
if (approach === "")
|
|
64
|
+
problems.push({ reason: "plan-empty-approach", message: "Approach must say how the work will be done" });
|
|
65
|
+
if (approach.length > 2_000)
|
|
66
|
+
problems.push({ reason: "plan-approach-too-long", message: "Approach is over 2000 characters" });
|
|
67
|
+
const list = (name) => {
|
|
68
|
+
const items = [];
|
|
69
|
+
for (const line of sections.get(name) ?? []) {
|
|
70
|
+
if (line.trim() === "")
|
|
71
|
+
continue;
|
|
72
|
+
const item = /^(?:[-*]\s+|\d+[.)]\s+)(.+)$/.exec(line.trim())?.[1]?.trim();
|
|
73
|
+
if (item === undefined || item === "") {
|
|
74
|
+
problems.push({ reason: `plan-bad-${name}-item`, message: `${name} entries must be bullets or numbered items` });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (item.length > EXECUTION_PLAN_ITEM_CAP) {
|
|
78
|
+
problems.push({ reason: `plan-${name}-item-too-long`, message: `${name} entries are capped at ${EXECUTION_PLAN_ITEM_CAP} characters` });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
items.push(item);
|
|
82
|
+
}
|
|
83
|
+
if (items.length === 0)
|
|
84
|
+
problems.push({ reason: `plan-empty-${name}`, message: `${name} needs at least one item (use \"None found.\" when honest)` });
|
|
85
|
+
if (items.length > EXECUTION_PLAN_LIST_CAP)
|
|
86
|
+
problems.push({ reason: `plan-too-many-${name}`, message: `${name} is capped at ${EXECUTION_PLAN_LIST_CAP} items` });
|
|
87
|
+
return items;
|
|
88
|
+
};
|
|
89
|
+
const document = {
|
|
90
|
+
approach,
|
|
91
|
+
milestones: list("milestones"),
|
|
92
|
+
dependencies: list("dependencies"),
|
|
93
|
+
risks: list("risks"),
|
|
94
|
+
proof: list("proof"),
|
|
95
|
+
};
|
|
96
|
+
return problems.length === 0 ? { ok: true, document } : { ok: false, problems };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The inverse of `parseExecutionPlanDocument`: the canonical fenced-section
|
|
100
|
+
* markdown for a document the parser already admitted.
|
|
101
|
+
*
|
|
102
|
+
* A builder's revision proposal arrives as free-form text that the parser
|
|
103
|
+
* validates and reduces to this shape; what gets STORED — and later
|
|
104
|
+
* hash-verified, re-read, and quoted into the next brief — is rendered back
|
|
105
|
+
* from that validated shape, never the agent's raw bytes (the scout
|
|
106
|
+
* report's rule, and settleProof's). `parseExecutionPlanDocument` composed
|
|
107
|
+
* with this function is the identity on every document the parser admits:
|
|
108
|
+
* sections in their fixed order, one bullet per item, nothing else.
|
|
109
|
+
*/
|
|
110
|
+
export function renderExecutionPlanDocument(document) {
|
|
111
|
+
const bullets = (items) => items.map(item => `- ${item}`);
|
|
112
|
+
return [
|
|
113
|
+
"## Approach",
|
|
114
|
+
document.approach,
|
|
115
|
+
"",
|
|
116
|
+
"## Milestones",
|
|
117
|
+
...bullets(document.milestones),
|
|
118
|
+
"",
|
|
119
|
+
"## Dependencies",
|
|
120
|
+
...bullets(document.dependencies),
|
|
121
|
+
"",
|
|
122
|
+
"## Risks",
|
|
123
|
+
...bullets(document.risks),
|
|
124
|
+
"",
|
|
125
|
+
"## Proof",
|
|
126
|
+
...bullets(document.proof),
|
|
127
|
+
"",
|
|
128
|
+
].join("\n");
|
|
129
|
+
}
|
|
130
|
+
/** Caps matching the scope ritual's fields, plus the document itself. */
|
|
131
|
+
export const PLAN_LIMITS = {
|
|
132
|
+
payload: 64 * 1024,
|
|
133
|
+
goal: 2_000,
|
|
134
|
+
outOfScope: 2_000,
|
|
135
|
+
touch: 200,
|
|
136
|
+
touches: 32,
|
|
137
|
+
document: 16 * 1024,
|
|
138
|
+
amendment: 1_000,
|
|
139
|
+
};
|
|
140
|
+
function refuse(reason, message) {
|
|
141
|
+
return { ok: false, problems: [{ reason, message }] };
|
|
142
|
+
}
|
|
143
|
+
function describe(value) {
|
|
144
|
+
if (value === undefined)
|
|
145
|
+
return "nothing";
|
|
146
|
+
if (value === null)
|
|
147
|
+
return "null";
|
|
148
|
+
if (typeof value === "string")
|
|
149
|
+
return `a ${value.length}-char string`;
|
|
150
|
+
return `a ${Array.isArray(value) ? "array" : typeof value}`;
|
|
151
|
+
}
|
|
152
|
+
function prose(value, field, cap, required, problems) {
|
|
153
|
+
if (value === undefined || value === null || value === "") {
|
|
154
|
+
if (required)
|
|
155
|
+
problems.push({ reason: `missing-${field}`, message: `${field} is required` });
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
if (typeof value !== "string") {
|
|
159
|
+
problems.push({ reason: `bad-${field}`, message: `${field} must be a string (got ${describe(value)})` });
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
if (value.length > cap) {
|
|
163
|
+
problems.push({ reason: `${field}-too-long`, message: `${field} is over ${cap} characters` });
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
if (hasForbiddenControls(value)) {
|
|
167
|
+
problems.push({ reason: `${field}-controls`, message: `${field} carries control characters that could become terminal escapes` });
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
export function parsePlan(raw) {
|
|
173
|
+
if (Buffer.byteLength(raw, "utf8") > PLAN_LIMITS.payload) {
|
|
174
|
+
return refuse("too-large", `the payload is over ${PLAN_LIMITS.payload} bytes`);
|
|
175
|
+
}
|
|
176
|
+
let parsed;
|
|
177
|
+
try {
|
|
178
|
+
parsed = JSON.parse(raw);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
return refuse("not-json", `the payload is not JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
182
|
+
}
|
|
183
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
184
|
+
return refuse("not-an-object", "the payload must be one JSON object");
|
|
185
|
+
}
|
|
186
|
+
const body = parsed;
|
|
187
|
+
const problems = [];
|
|
188
|
+
const goal = prose(body["goal"], "goal", PLAN_LIMITS.goal, true, problems);
|
|
189
|
+
const outOfScope = prose(body["outOfScope"], "outOfScope", PLAN_LIMITS.outOfScope, false, problems);
|
|
190
|
+
const document = prose(body["plan"], "plan", PLAN_LIMITS.document, true, problems);
|
|
191
|
+
const amendment = prose(body["amendment"], "amendment", PLAN_LIMITS.amendment, false, problems);
|
|
192
|
+
const touches = [];
|
|
193
|
+
if (body["touches"] !== undefined && body["touches"] !== null) {
|
|
194
|
+
if (!Array.isArray(body["touches"])) {
|
|
195
|
+
problems.push({ reason: "bad-touches", message: `touches must be an array of paths (got ${describe(body["touches"])})` });
|
|
196
|
+
}
|
|
197
|
+
else if (body["touches"].length > PLAN_LIMITS.touches) {
|
|
198
|
+
problems.push({ reason: "touches-too-many", message: `touches lists ${body["touches"].length} paths — cap is ${PLAN_LIMITS.touches}` });
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
for (const [index, one] of body["touches"].entries()) {
|
|
202
|
+
const path = prose(one, `touches[${index}]`, PLAN_LIMITS.touch, true, problems);
|
|
203
|
+
if (path !== null) {
|
|
204
|
+
if (/[\n\t]/.test(path)) {
|
|
205
|
+
problems.push({ reason: `touches[${index}]-multiline`, message: `touches[${index}] must be one line` });
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
touches.push(path);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const acceptanceParse = parseAcceptanceCriteria(body["acceptance"]);
|
|
215
|
+
for (const problem of acceptanceParse.problems) {
|
|
216
|
+
problems.push({ reason: problem.reason, message: problem.message });
|
|
217
|
+
}
|
|
218
|
+
if (acceptanceParse.problems.length === 0 && acceptanceParse.criteria.length === 0) {
|
|
219
|
+
problems.push({ reason: "missing-acceptance", message: "acceptance is required — at least one signed criterion the build will be judged against" });
|
|
220
|
+
}
|
|
221
|
+
if (document !== null) {
|
|
222
|
+
const execution = parseExecutionPlanDocument(document);
|
|
223
|
+
if (!execution.ok) {
|
|
224
|
+
problems.push(...execution.problems);
|
|
225
|
+
}
|
|
226
|
+
else if (acceptanceParse.problems.length === 0) {
|
|
227
|
+
const proof = execution.document.proof.join("\n");
|
|
228
|
+
for (const criterion of acceptanceParse.criteria) {
|
|
229
|
+
const mentioned = new RegExp(`(^|[^A-Za-z0-9_-])${criterion.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([^A-Za-z0-9_-]|$)`).test(proof);
|
|
230
|
+
if (!mentioned) {
|
|
231
|
+
problems.push({ reason: `plan-proof-missing-${criterion.id}`, message: `Proof must name acceptance criterion ${criterion.id}` });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (problems.length > 0)
|
|
237
|
+
return { ok: false, problems };
|
|
238
|
+
return {
|
|
239
|
+
ok: true,
|
|
240
|
+
plan: { goal: goal, outOfScope, touches, acceptance: acceptanceParse.criteria, plan: document, amendment },
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const MILESTONE_STATES = ["pending", "current", "completed", "blocked"];
|
|
244
|
+
/**
|
|
245
|
+
* A milestone's identity is its position plus a short hash of its
|
|
246
|
+
* normalized text — stable across re-reads of the same revision, but a
|
|
247
|
+
* milestone whose wording changes materially becomes a NEW identity rather
|
|
248
|
+
* than silently inheriting stale completion state from a differently-worded
|
|
249
|
+
* predecessor.
|
|
250
|
+
*/
|
|
251
|
+
export function milestoneId(index, description) {
|
|
252
|
+
const hash = createHash("sha256").update(description.trim().toLowerCase(), "utf8").digest("hex").slice(0, 8);
|
|
253
|
+
return `m${index + 1}-${hash}`;
|
|
254
|
+
}
|
|
255
|
+
export function milestonesOf(document) {
|
|
256
|
+
return document.milestones.map((description, index) => ({ id: milestoneId(index, description), description }));
|
|
257
|
+
}
|
|
258
|
+
export const PROGRESS_LIMITS = {
|
|
259
|
+
payload: 8 * 1024,
|
|
260
|
+
note: 300,
|
|
261
|
+
milestones: EXECUTION_PLAN_LIST_CAP,
|
|
262
|
+
};
|
|
263
|
+
/** Parse a progress checkpoint written by a running build. `expectedRevisionHash`
|
|
264
|
+
* and `knownIds` come from the plan revision the build's brief actually
|
|
265
|
+
* named — a snapshot naming a different revision, an unknown milestone id,
|
|
266
|
+
* a missing milestone, or more than one "current" milestone fails closed
|
|
267
|
+
* with every problem at once, the same 422 rule as the plan itself. */
|
|
268
|
+
export function parseProgressSnapshot(raw, expectedRevisionHash, knownIds) {
|
|
269
|
+
if (Buffer.byteLength(raw, "utf8") > PROGRESS_LIMITS.payload) {
|
|
270
|
+
return { ok: false, problems: [{ reason: "progress-too-large", message: `progress is over ${PROGRESS_LIMITS.payload} bytes` }] };
|
|
271
|
+
}
|
|
272
|
+
let parsed;
|
|
273
|
+
try {
|
|
274
|
+
parsed = JSON.parse(raw);
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
return { ok: false, problems: [{ reason: "progress-not-json", message: `progress is not JSON: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
278
|
+
}
|
|
279
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
280
|
+
return { ok: false, problems: [{ reason: "progress-not-an-object", message: "progress must be one JSON object" }] };
|
|
281
|
+
}
|
|
282
|
+
const body = parsed;
|
|
283
|
+
const problems = [];
|
|
284
|
+
const revisionHash = typeof body["revisionHash"] === "string" ? body["revisionHash"] : null;
|
|
285
|
+
if (revisionHash === null) {
|
|
286
|
+
problems.push({ reason: "progress-missing-revision", message: "progress must name revisionHash" });
|
|
287
|
+
}
|
|
288
|
+
else if (revisionHash !== expectedRevisionHash) {
|
|
289
|
+
problems.push({ reason: "progress-stale-revision", message: "progress names a plan revision that is not the one this build received" });
|
|
290
|
+
}
|
|
291
|
+
const rawMilestones = body["milestones"];
|
|
292
|
+
const milestones = [];
|
|
293
|
+
if (!Array.isArray(rawMilestones)) {
|
|
294
|
+
problems.push({ reason: "progress-bad-milestones", message: `milestones must be an array (got ${describe(rawMilestones)})` });
|
|
295
|
+
}
|
|
296
|
+
else if (rawMilestones.length > PROGRESS_LIMITS.milestones) {
|
|
297
|
+
problems.push({ reason: "progress-too-many-milestones", message: `milestones is capped at ${PROGRESS_LIMITS.milestones} entries` });
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
const seen = new Set();
|
|
301
|
+
for (const [index, entryRaw] of rawMilestones.entries()) {
|
|
302
|
+
if (typeof entryRaw !== "object" || entryRaw === null || Array.isArray(entryRaw)) {
|
|
303
|
+
problems.push({ reason: `progress-bad-entry-${index}`, message: `milestones[${index}] must be an object` });
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const entry = entryRaw;
|
|
307
|
+
const id = typeof entry["id"] === "string" ? entry["id"] : null;
|
|
308
|
+
const state = typeof entry["state"] === "string" ? entry["state"] : null;
|
|
309
|
+
const note = prose(entry["note"], `milestones[${index}].note`, PROGRESS_LIMITS.note, false, problems);
|
|
310
|
+
if (id === null || !knownIds.includes(id)) {
|
|
311
|
+
problems.push({ reason: `progress-unknown-milestone-${index}`, message: `milestones[${index}] names a milestone id not in this plan revision` });
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (seen.has(id)) {
|
|
315
|
+
problems.push({ reason: `progress-duplicate-milestone-${index}`, message: `milestone ${id} appears more than once` });
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
seen.add(id);
|
|
319
|
+
if (state === null || !MILESTONE_STATES.includes(state)) {
|
|
320
|
+
problems.push({ reason: `progress-bad-state-${index}`, message: `milestones[${index}].state must be one of ${MILESTONE_STATES.join(", ")}` });
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
milestones.push({ id, state: state, note });
|
|
324
|
+
}
|
|
325
|
+
for (const knownId of knownIds) {
|
|
326
|
+
if (!seen.has(knownId))
|
|
327
|
+
problems.push({ reason: "progress-missing-milestone", message: `progress must report every milestone in the plan revision (missing ${knownId})` });
|
|
328
|
+
}
|
|
329
|
+
if (milestones.filter(entry => entry.state === "current").length > 1) {
|
|
330
|
+
problems.push({ reason: "progress-multiple-current", message: "at most one milestone may be current at a time" });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (problems.length > 0)
|
|
334
|
+
return { ok: false, problems };
|
|
335
|
+
return { ok: true, snapshot: { revisionHash: revisionHash, milestones } };
|
|
336
|
+
}
|
|
337
|
+
/** Whether a checkpoint transition is a legitimate update or a regression:
|
|
338
|
+
* once a milestone is completed it never reverts — an agent restating an
|
|
339
|
+
* old snapshot (a stale pulse, a retried read) must never erase progress
|
|
340
|
+
* that a later, newer checkpoint already recorded. */
|
|
341
|
+
export function isMilestoneRegression(previous, next) {
|
|
342
|
+
return previous === "completed" && next !== "completed";
|
|
343
|
+
}
|
|
344
|
+
export const REVISION_LIMITS = {
|
|
345
|
+
payload: 32 * 1024,
|
|
346
|
+
reason: 2_000,
|
|
347
|
+
evidenceLink: 500,
|
|
348
|
+
};
|
|
349
|
+
/** Parse the builder's terminal revision-proposal file: a complete
|
|
350
|
+
* replacement plan document plus the evidence that invalidated the one it
|
|
351
|
+
* was given. One proposal per build — the caller enforces that by never
|
|
352
|
+
* offering the agent more than one nonce-named path to write. */
|
|
353
|
+
export function parsePlanRevisionProposal(raw) {
|
|
354
|
+
if (Buffer.byteLength(raw, "utf8") > REVISION_LIMITS.payload) {
|
|
355
|
+
return { ok: false, problems: [{ reason: "revision-too-large", message: `revision proposal is over ${REVISION_LIMITS.payload} bytes` }] };
|
|
356
|
+
}
|
|
357
|
+
let parsed;
|
|
358
|
+
try {
|
|
359
|
+
parsed = JSON.parse(raw);
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
return { ok: false, problems: [{ reason: "revision-not-json", message: `revision proposal is not JSON: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
363
|
+
}
|
|
364
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
365
|
+
return { ok: false, problems: [{ reason: "revision-not-an-object", message: "revision proposal must be one JSON object" }] };
|
|
366
|
+
}
|
|
367
|
+
const body = parsed;
|
|
368
|
+
const problems = [];
|
|
369
|
+
const reason = prose(body["reason"], "reason", REVISION_LIMITS.reason, true, problems);
|
|
370
|
+
const evidenceLink = prose(body["evidenceLink"], "evidenceLink", REVISION_LIMITS.evidenceLink, true, problems);
|
|
371
|
+
const planText = prose(body["plan"], "plan", PLAN_LIMITS.document, true, problems);
|
|
372
|
+
let document = null;
|
|
373
|
+
if (planText !== null) {
|
|
374
|
+
const execution = parseExecutionPlanDocument(planText);
|
|
375
|
+
if (!execution.ok)
|
|
376
|
+
problems.push(...execution.problems);
|
|
377
|
+
else
|
|
378
|
+
document = execution.document;
|
|
379
|
+
}
|
|
380
|
+
if (problems.length > 0)
|
|
381
|
+
return { ok: false, problems };
|
|
382
|
+
return { ok: true, proposal: { document: document, reason: reason, evidenceLink: evidenceLink } };
|
|
383
|
+
}
|
|
384
|
+
export function authoritySnapshotDigest(snapshot) {
|
|
385
|
+
return createHash("sha256").update(`${snapshot.scopeDigest}\u0000${snapshot.deliverable}`, "utf8").digest("hex").slice(0, 32);
|
|
386
|
+
}
|
|
387
|
+
/** Classify a revision against the complete authority snapshot the build
|
|
388
|
+
* actually started under. Everything the builder's own proposal can name is
|
|
389
|
+
* plan-only by construction (it carries no scope fields at all) — this
|
|
390
|
+
* check exists as the defense against the world moving underneath a live
|
|
391
|
+
* build: if the signed scope or publication authority changed by any other
|
|
392
|
+
* road while the build ran, the revision is never auto-applied, whatever it
|
|
393
|
+
* proposes. */
|
|
394
|
+
export function classifyRevisionAuthority(previous, current) {
|
|
395
|
+
const changed = [];
|
|
396
|
+
if (previous.scopeDigest !== current.scopeDigest)
|
|
397
|
+
changed.push("signed-scope");
|
|
398
|
+
if (previous.deliverable !== current.deliverable)
|
|
399
|
+
changed.push("publication-authority");
|
|
400
|
+
return changed.length === 0 ? { kind: "plan-only" } : { kind: "authority-change", changed };
|
|
401
|
+
}
|