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,15 @@
|
|
|
1
|
+
import { type LimitReading } from "./provider-limits.js";
|
|
2
|
+
import type { Store } from "./store.js";
|
|
3
|
+
/** Ask Codex for its limits: its app server over stdio, in its own process group and a scratch folder, one read,
|
|
4
|
+
* then gone (killed if it lingers). Resolves once the process has ended; null when Codex isn't installed or doesn't
|
|
5
|
+
* answer in time. A key account has no windows but says so (`billing`). */
|
|
6
|
+
export declare function readCodexLimits(options?: {
|
|
7
|
+
command?: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
graceMs?: number;
|
|
10
|
+
}): Promise<LimitReading | null>;
|
|
11
|
+
/** The loop beside the console: Codex's limits and account every five minutes while Toolroll runs Codex on its
|
|
12
|
+
* plan. Never in tests, the demo, or the end-to-end harness (which runs with the person's own sign-in), and never while
|
|
13
|
+
* a Codex build is running (both would refresh the same sign-in). One read at a time: the next waits for the last
|
|
14
|
+
* process to end. */
|
|
15
|
+
export declare function startCodexLimits(store: Store, everyMs?: number): () => void;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/** Codex's plan limits and account, read from its app server (v105): kept apart from provider-limits.ts so the run
|
|
2
|
+
* pipeline that notes Claude's readings never loads Codex's transport. */
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { codingEnvironment } from "./coding-provider.js";
|
|
6
|
+
import { codexLimitsOf, record } from "./provider-limits.js";
|
|
7
|
+
import { billingOf } from "./spend.js";
|
|
8
|
+
import { envValue } from "./names.js";
|
|
9
|
+
/** How Codex says its account bills (`account/read`'s account): a ChatGPT sign-in is its plan unless the plan itself is
|
|
10
|
+
* billed by use; a key or Amazon Bedrock is a key. */
|
|
11
|
+
function accountBilling(account) {
|
|
12
|
+
const type = account?.["type"];
|
|
13
|
+
if (typeof type !== "string")
|
|
14
|
+
return undefined;
|
|
15
|
+
if (type.toLowerCase() === "chatgpt")
|
|
16
|
+
return typeof account["planType"] === "string" && /usage.?based/i.test(account["planType"]) ? "api-key" : "subscription";
|
|
17
|
+
return /api.?key|bedrock/i.test(type) ? "api-key" : undefined;
|
|
18
|
+
}
|
|
19
|
+
/** End the app server and everything it started: its process group, then a kill after a grace period. */
|
|
20
|
+
function end(child, graceMs) {
|
|
21
|
+
return new Promise(done => {
|
|
22
|
+
const signal = (name) => {
|
|
23
|
+
try {
|
|
24
|
+
if (child.pid !== undefined && process.platform !== "win32")
|
|
25
|
+
process.kill(-child.pid, name);
|
|
26
|
+
else
|
|
27
|
+
child.kill(name);
|
|
28
|
+
}
|
|
29
|
+
catch { /* gone */ }
|
|
30
|
+
};
|
|
31
|
+
// The leader may be gone while something it started lives on: the group hears it either way.
|
|
32
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
33
|
+
signal("SIGKILL");
|
|
34
|
+
return done();
|
|
35
|
+
}
|
|
36
|
+
const hard = setTimeout(() => { signal("SIGKILL"); setTimeout(done, 1_000).unref?.(); }, graceMs);
|
|
37
|
+
hard.unref?.();
|
|
38
|
+
child.once("exit", () => { clearTimeout(hard); done(); });
|
|
39
|
+
signal("SIGTERM");
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Ask Codex for its limits: its app server over stdio, in its own process group and a scratch folder, one read,
|
|
43
|
+
* then gone (killed if it lingers). Resolves once the process has ended; null when Codex isn't installed or doesn't
|
|
44
|
+
* answer in time. A key account has no windows but says so (`billing`). */
|
|
45
|
+
export function readCodexLimits(options = {}) {
|
|
46
|
+
return new Promise(resolve => {
|
|
47
|
+
const env = codingEnvironment();
|
|
48
|
+
// Its plan's limits: a key in the environment would make it an API account.
|
|
49
|
+
for (const key of ["OPENAI_API_KEY", "CODEX_API_KEY"])
|
|
50
|
+
delete env[key];
|
|
51
|
+
let child;
|
|
52
|
+
try {
|
|
53
|
+
child = spawn(options.command ?? "codex", ["app-server", "--listen", "stdio://"], {
|
|
54
|
+
cwd: tmpdir(), env, shell: false, windowsHide: true, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "ignore"],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
resolve(null);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
let settled = false;
|
|
62
|
+
let buffered = "";
|
|
63
|
+
let billing;
|
|
64
|
+
let limits;
|
|
65
|
+
let accountRead = false;
|
|
66
|
+
const finish = (reading) => {
|
|
67
|
+
if (settled)
|
|
68
|
+
return;
|
|
69
|
+
settled = true;
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
const answer = reading ?? (billing === undefined ? null : { provider: "codex", plan: null, windows: [], partial: true, billing });
|
|
72
|
+
void end(child, options.graceMs ?? 3_000).then(() => resolve(answer === null || billing === undefined ? answer : { ...answer, billing }));
|
|
73
|
+
};
|
|
74
|
+
const timer = setTimeout(() => finish(limits ?? null), options.timeoutMs ?? 15_000);
|
|
75
|
+
child.once("error", () => finish(null));
|
|
76
|
+
child.once("exit", () => finish(null));
|
|
77
|
+
child.stdin?.on("error", () => finish(null));
|
|
78
|
+
child.stdout?.setEncoding("utf8");
|
|
79
|
+
child.stdout?.on("data", (chunk) => {
|
|
80
|
+
buffered += chunk;
|
|
81
|
+
if (buffered.length > 256 * 1024)
|
|
82
|
+
return finish(null);
|
|
83
|
+
let newline;
|
|
84
|
+
while ((newline = buffered.indexOf("\n")) !== -1) {
|
|
85
|
+
const line = buffered.slice(0, newline);
|
|
86
|
+
buffered = buffered.slice(newline + 1);
|
|
87
|
+
let message = null;
|
|
88
|
+
try {
|
|
89
|
+
message = record(JSON.parse(line));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (message?.["id"] === 1) {
|
|
95
|
+
child.stdin?.write([{ jsonrpc: "2.0", method: "initialized" }, { jsonrpc: "2.0", id: 2, method: "account/rateLimits/read" },
|
|
96
|
+
{ jsonrpc: "2.0", id: 3, method: "account/read", params: {} }].map(one => `${JSON.stringify(one)}\n`).join(""));
|
|
97
|
+
}
|
|
98
|
+
else if (message?.["id"] === 2) {
|
|
99
|
+
limits = message["error"] === undefined ? codexLimitsOf(message["result"]) : null;
|
|
100
|
+
}
|
|
101
|
+
else if (message?.["id"] === 3) {
|
|
102
|
+
accountRead = true;
|
|
103
|
+
billing = accountBilling(record(record(message["result"])?.["account"]));
|
|
104
|
+
}
|
|
105
|
+
if (limits !== undefined && accountRead)
|
|
106
|
+
finish(limits);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
child.stdin?.write(`${JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { clientInfo: { name: "toolroll", version: "1" } } })}\n`);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** The loop beside the console: Codex's limits and account every five minutes while Toolroll runs Codex on its
|
|
113
|
+
* plan. Never in tests, the demo, or the end-to-end harness (which runs with the person's own sign-in), and never while
|
|
114
|
+
* a Codex build is running (both would refresh the same sign-in). One read at a time: the next waits for the last
|
|
115
|
+
* process to end. */
|
|
116
|
+
export function startCodexLimits(store, everyMs = 5 * 60_000) {
|
|
117
|
+
if (process.env["VITEST"] !== undefined || envValue(process.env, "NO_PLAN_PROBE") !== undefined || store.isDemo())
|
|
118
|
+
return () => { };
|
|
119
|
+
let stopped = false, busy = false;
|
|
120
|
+
const pass = async () => {
|
|
121
|
+
if (stopped || busy || billingOf("codex") !== "subscription")
|
|
122
|
+
return;
|
|
123
|
+
// A Codex run started in the last few hours and not finished: let it have the sign-in to itself.
|
|
124
|
+
const recent = new Date(Date.now() - 6 * 3_600_000).toISOString();
|
|
125
|
+
if (store.handle.prepare("SELECT 1 AS live FROM run WHERE provider = 'codex' AND outcome IS NULL AND started_at > ? LIMIT 1").get(recent) !== undefined)
|
|
126
|
+
return;
|
|
127
|
+
busy = true;
|
|
128
|
+
try {
|
|
129
|
+
const reading = await readCodexLimits();
|
|
130
|
+
if (reading !== null && !stopped)
|
|
131
|
+
store.recordProviderLimits(reading, new Date());
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// The next pass tries again.
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
busy = false;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const timer = setInterval(() => void pass(), everyMs);
|
|
141
|
+
timer.unref?.();
|
|
142
|
+
const first = setTimeout(() => void pass(), 10_000);
|
|
143
|
+
first.unref?.();
|
|
144
|
+
return () => { stopped = true; clearInterval(timer); clearTimeout(first); };
|
|
145
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Store } from './store.js';
|
|
2
|
+
export type CodingContextMetadata = {
|
|
3
|
+
version: 1;
|
|
4
|
+
repo: string;
|
|
5
|
+
identity: string;
|
|
6
|
+
baseRevision: string;
|
|
7
|
+
knowledge: {
|
|
8
|
+
revision: number;
|
|
9
|
+
selectionSha256: string;
|
|
10
|
+
references: {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
path: string | null;
|
|
14
|
+
sourceSha: string | null;
|
|
15
|
+
sourceRevision: string | null;
|
|
16
|
+
}[];
|
|
17
|
+
omitted: {
|
|
18
|
+
title: string;
|
|
19
|
+
reason: string;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
skills: {
|
|
23
|
+
revision: number;
|
|
24
|
+
packages: {
|
|
25
|
+
name: string;
|
|
26
|
+
sha256: string;
|
|
27
|
+
skillFile: string;
|
|
28
|
+
}[];
|
|
29
|
+
};
|
|
30
|
+
directory: string | null;
|
|
31
|
+
files: {
|
|
32
|
+
path: string;
|
|
33
|
+
sha256: string;
|
|
34
|
+
}[];
|
|
35
|
+
};
|
|
36
|
+
export type CodingContext = {
|
|
37
|
+
text: string;
|
|
38
|
+
metadata: CodingContextMetadata;
|
|
39
|
+
sha256: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Call before thread/start with the canonical project and the exact worktree
|
|
43
|
+
* base. Persist the returned object with the coding session and reuse it on
|
|
44
|
+
* resume; calling this again intentionally selects a new context version.
|
|
45
|
+
* root is a coordinator-owned directory outside repository worktrees.
|
|
46
|
+
*/
|
|
47
|
+
export declare function prepareCodingContext(store: Store, args: {
|
|
48
|
+
repo: string;
|
|
49
|
+
actor: string;
|
|
50
|
+
baseRevision: string;
|
|
51
|
+
prompt: string;
|
|
52
|
+
root: string;
|
|
53
|
+
}): CodingContext;
|
|
54
|
+
/** Integrity check for a persisted capture. The caller must separately recheck current account access. */
|
|
55
|
+
export declare function verifyCodingContext(context: CodingContext, repo: string, baseRevision: string): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Managed context captured once for a native coding session; no synthetic worker runs. */
|
|
2
|
+
import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { basename, dirname, join, resolve, relative, isAbsolute, sep } from 'node:path';
|
|
5
|
+
import { KNOWLEDGE_GUIDANCE, selectProjectKnowledge } from './project-knowledge.js';
|
|
6
|
+
import { materializeProjectSkills, PROJECT_SKILLS_GUIDANCE, selectProjectSkills } from './project-skills.js';
|
|
7
|
+
import { learningIdentity, learningSha } from './project-learning.js';
|
|
8
|
+
function freeze(value) {
|
|
9
|
+
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
10
|
+
for (const child of Object.values(value))
|
|
11
|
+
freeze(child);
|
|
12
|
+
Object.freeze(value);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
const digest = (text, metadata) => learningSha(JSON.stringify({ text, metadata }));
|
|
17
|
+
const fileDigest = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
18
|
+
function futureRealPath(path) {
|
|
19
|
+
let existing = resolve(path);
|
|
20
|
+
const suffix = [];
|
|
21
|
+
while (!existsSync(existing)) {
|
|
22
|
+
suffix.unshift(basename(existing));
|
|
23
|
+
existing = dirname(existing);
|
|
24
|
+
}
|
|
25
|
+
if (!statSync(existing).isDirectory())
|
|
26
|
+
throw Error('Choose a directory for managed coding context.');
|
|
27
|
+
return resolve(realpathSync(existing), ...suffix);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Call before thread/start with the canonical project and the exact worktree
|
|
31
|
+
* base. Persist the returned object with the coding session and reuse it on
|
|
32
|
+
* resume; calling this again intentionally selects a new context version.
|
|
33
|
+
* root is a coordinator-owned directory outside repository worktrees.
|
|
34
|
+
*/
|
|
35
|
+
export function prepareCodingContext(store, args) {
|
|
36
|
+
const captured = store.transact(() => {
|
|
37
|
+
const knowledge = selectProjectKnowledge(store, { repo: args.repo, actor: args.actor, query: args.prompt, baseRevision: args.baseRevision });
|
|
38
|
+
const skills = selectProjectSkills(store, args.repo, args.actor);
|
|
39
|
+
return { identity: learningIdentity(args.repo), knowledge, skills };
|
|
40
|
+
});
|
|
41
|
+
// The materialized package must not become an agent-authored repository
|
|
42
|
+
// change or replace native .agents, .codex, AGENTS.md, or MCP configuration.
|
|
43
|
+
const root = futureRealPath(args.root);
|
|
44
|
+
const fromRepo = relative(args.repo, root);
|
|
45
|
+
if (!fromRepo || (!fromRepo.startsWith('..' + sep) && !isAbsolute(fromRepo) && fromRepo !== '..'))
|
|
46
|
+
throw Error('Store managed coding context outside the project worktree.');
|
|
47
|
+
const supplied = materializeProjectSkills(captured.skills, root, 'coding');
|
|
48
|
+
const directory = supplied.directory === null ? null : realpathSync(supplied.directory);
|
|
49
|
+
const parts = [];
|
|
50
|
+
if (captured.knowledge.revision > 0)
|
|
51
|
+
parts.push(KNOWLEDGE_GUIDANCE, JSON.stringify(captured.knowledge));
|
|
52
|
+
if (supplied.catalog.length)
|
|
53
|
+
parts.push('Project skills supplied for this coding session. ' + PROJECT_SKILLS_GUIDANCE, JSON.stringify(supplied.catalog));
|
|
54
|
+
const text = parts.length ? '\nToolroll project context, frozen when this coding session started. Native repository and home instructions, tools, and MCP configuration still apply.\n' + parts.join('\n') + '\n' : '';
|
|
55
|
+
const metadata = {
|
|
56
|
+
version: 1,
|
|
57
|
+
repo: args.repo,
|
|
58
|
+
identity: captured.identity,
|
|
59
|
+
baseRevision: args.baseRevision,
|
|
60
|
+
knowledge: {
|
|
61
|
+
revision: captured.knowledge.revision,
|
|
62
|
+
selectionSha256: learningSha(JSON.stringify(captured.knowledge)),
|
|
63
|
+
references: captured.knowledge.references.map(({ id, title, path, sourceSha, sourceRevision }) => ({ id, title, path, sourceSha, sourceRevision })),
|
|
64
|
+
omitted: captured.knowledge.omitted,
|
|
65
|
+
},
|
|
66
|
+
skills: {
|
|
67
|
+
revision: captured.skills.revision,
|
|
68
|
+
packages: supplied.catalog.map(skill => ({ name: skill.name, sha256: skill.version, skillFile: skill.skillFile })),
|
|
69
|
+
},
|
|
70
|
+
directory,
|
|
71
|
+
files: captured.skills.packages.flatMap(skill => skill.files.map(file => ({ path: `${skill.name}/${file.path}`, sha256: fileDigest(Buffer.from(file.base64, 'base64')) }))),
|
|
72
|
+
};
|
|
73
|
+
return freeze({ text, metadata, sha256: digest(text, metadata) });
|
|
74
|
+
}
|
|
75
|
+
/** Integrity check for a persisted capture. The caller must separately recheck current account access. */
|
|
76
|
+
export function verifyCodingContext(context, repo, baseRevision) {
|
|
77
|
+
if (context.metadata.version !== 1 || context.metadata.repo !== repo || context.metadata.baseRevision !== baseRevision || context.metadata.identity !== learningIdentity(repo) || context.sha256 !== digest(context.text, context.metadata))
|
|
78
|
+
throw Error('The coding session context could not be verified.');
|
|
79
|
+
if (context.metadata.files.length && context.metadata.directory === null)
|
|
80
|
+
throw Error('The coding session skill files are unavailable.');
|
|
81
|
+
try {
|
|
82
|
+
for (const file of context.metadata.files) {
|
|
83
|
+
const directory = context.metadata.directory;
|
|
84
|
+
const path = join(directory, file.path);
|
|
85
|
+
if (file.path.split('/').some(segment => !segment || segment === '.' || segment === '..') || isAbsolute(file.path) || realpathSync(path) !== path || !statSync(path).isFile() || fileDigest(readFileSync(path)) !== file.sha256)
|
|
86
|
+
throw Error('Changed skill file.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
throw Error('A coding session skill file changed or is unavailable.', { cause });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type AcceptanceCriterion } from './scope.js';
|
|
2
|
+
import type { Store } from './store.js';
|
|
3
|
+
export type CodingHandoffPreview = {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
repo: string;
|
|
6
|
+
base: string;
|
|
7
|
+
candidate: string;
|
|
8
|
+
title: string;
|
|
9
|
+
originalPrompt: string;
|
|
10
|
+
changedPaths: string[];
|
|
11
|
+
};
|
|
12
|
+
type ReceiptTerms = CodingHandoffPreview & {
|
|
13
|
+
version: 1;
|
|
14
|
+
identity: string;
|
|
15
|
+
actor: string;
|
|
16
|
+
generation: number;
|
|
17
|
+
goal: string;
|
|
18
|
+
acceptance: AcceptanceCriterion[];
|
|
19
|
+
outOfScope: string;
|
|
20
|
+
};
|
|
21
|
+
export type CodingHandoffReceipt = ReceiptTerms & {
|
|
22
|
+
id: string;
|
|
23
|
+
taskId: string;
|
|
24
|
+
branch: string;
|
|
25
|
+
};
|
|
26
|
+
export type CodingHandoffInput = {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
repo: string;
|
|
29
|
+
base: string;
|
|
30
|
+
candidate: string;
|
|
31
|
+
title: string;
|
|
32
|
+
goal: string;
|
|
33
|
+
acceptance: unknown;
|
|
34
|
+
actor: string;
|
|
35
|
+
};
|
|
36
|
+
type Handoff = {
|
|
37
|
+
taskId: string;
|
|
38
|
+
scopeDigest: string;
|
|
39
|
+
receipt: CodingHandoffReceipt;
|
|
40
|
+
};
|
|
41
|
+
export declare function codingHandoffPreview(store: Store, input: {
|
|
42
|
+
sessionId: string;
|
|
43
|
+
actor: string;
|
|
44
|
+
}): CodingHandoffPreview;
|
|
45
|
+
/** Returns null only for ordinary tasks. A coding marker always requires its receipt. */
|
|
46
|
+
export declare function readCodingHandoff(store: Store, taskId: string): Handoff | null;
|
|
47
|
+
/** No agent dispatch, approval, push, or modification of an existing Git ref. */
|
|
48
|
+
export declare function createCodingHandoff(store: Store, input: CodingHandoffInput): Handoff;
|
|
49
|
+
/** Called before setup and immediately before recording the attempt's base. */
|
|
50
|
+
export declare function verifyCodingHandoffBase(store: Store, input: {
|
|
51
|
+
taskId: string;
|
|
52
|
+
taskRef: number;
|
|
53
|
+
repo: string;
|
|
54
|
+
branch: string;
|
|
55
|
+
head: string;
|
|
56
|
+
}): void;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/** A committed native session enters the existing review flow, never another executor. */
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
3
|
+
import { lstatSync, realpathSync } from 'node:fs';
|
|
4
|
+
import { sqliteRuntime } from './sqlite-runtime.js';
|
|
5
|
+
import { codingCatalogPath } from './coding-update.js';
|
|
6
|
+
import { updateAdmissionPaused } from './desktop-update-gate.js';
|
|
7
|
+
import { learningIdentity, learningSha } from './project-learning.js';
|
|
8
|
+
import { fileTaskProposal } from './proposal.js';
|
|
9
|
+
import { parseAcceptanceCriteria, proposeGuarded } from './scope.js';
|
|
10
|
+
import { validateTaskText } from './task-text.js';
|
|
11
|
+
import { PROOF_LIMITS } from './proof.js';
|
|
12
|
+
import { readPreparedEvidence } from './prepared-evidence.js';
|
|
13
|
+
import { BRANCH_PREFIXES, taskBranch } from './names.js';
|
|
14
|
+
const PREFIX = 'coding:';
|
|
15
|
+
const SHA = /^[a-f0-9]{40}$/;
|
|
16
|
+
const EXCLUSIONS = 'Verify the saved candidate only. Further code changes need a new review task.';
|
|
17
|
+
const SCHEMA = `
|
|
18
|
+
CREATE TABLE IF NOT EXISTS coding_handoff (id TEXT PRIMARY KEY, payload TEXT NOT NULL, sha TEXT NOT NULL, created_at TEXT NOT NULL);
|
|
19
|
+
CREATE TABLE IF NOT EXISTS coding_handoff_scope (id TEXT PRIMARY KEY REFERENCES coding_handoff(id), payload TEXT NOT NULL, sha TEXT NOT NULL);
|
|
20
|
+
CREATE TRIGGER IF NOT EXISTS coding_handoff_no_update BEFORE UPDATE ON coding_handoff BEGIN SELECT RAISE(ABORT,'Coding handoff receipts are immutable'); END;
|
|
21
|
+
CREATE TRIGGER IF NOT EXISTS coding_handoff_no_delete BEFORE DELETE ON coding_handoff BEGIN SELECT RAISE(ABORT,'Coding handoff receipts are immutable'); END;
|
|
22
|
+
CREATE TRIGGER IF NOT EXISTS coding_handoff_scope_no_update BEFORE UPDATE ON coding_handoff_scope BEGIN SELECT RAISE(ABORT,'Coding handoff seals are immutable'); END;
|
|
23
|
+
CREATE TRIGGER IF NOT EXISTS coding_handoff_scope_no_delete BEFORE DELETE ON coding_handoff_scope BEGIN SELECT RAISE(ABORT,'Coding handoff seals are immutable'); END;
|
|
24
|
+
`;
|
|
25
|
+
function catalog(store, readOnly) {
|
|
26
|
+
const path = codingCatalogPath(store.handle);
|
|
27
|
+
if (path === null)
|
|
28
|
+
throw Error('This installation has no saved coding catalog.');
|
|
29
|
+
try {
|
|
30
|
+
const stat = lstatSync(path);
|
|
31
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
32
|
+
throw Error('Not a regular catalog.');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw Error('The coding catalog is missing or linked. Preserve the session and restore its catalog.');
|
|
36
|
+
}
|
|
37
|
+
const db = new (sqliteRuntime().DatabaseSync)(path, { readOnly });
|
|
38
|
+
try {
|
|
39
|
+
db.exec('PRAGMA busy_timeout=3000');
|
|
40
|
+
for (const table of ['coding_session', 'coding_item', 'coding_submission', 'coding_request']) {
|
|
41
|
+
if (!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(table))
|
|
42
|
+
throw Error('The coding catalog is incomplete.');
|
|
43
|
+
}
|
|
44
|
+
if (!readOnly)
|
|
45
|
+
db.exec(SCHEMA);
|
|
46
|
+
return db;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
db.close();
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function git(repo, args) {
|
|
54
|
+
try {
|
|
55
|
+
return execFileSync('git', ['--no-optional-locks', '--no-replace-objects', '--no-lazy-fetch', '-c', 'core.hooksPath=/dev/null', '-C', repo, ...args], {
|
|
56
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 60_000, maxBuffer: 1_048_576,
|
|
57
|
+
}).trimEnd();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw Error('The committed coding result could not be verified in Git. Check the project and try again.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function branchHead(repo, branch) {
|
|
64
|
+
try {
|
|
65
|
+
return execFileSync('git', ['--no-optional-locks', '--no-replace-objects', '-C', repo, 'rev-parse', '--verify', '--quiet', `refs/heads/${branch}`], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.status === 1)
|
|
69
|
+
return null;
|
|
70
|
+
throw Error('The review branch could not be inspected.');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function actorGeneration(store, actor, repo) {
|
|
74
|
+
const account = store.accountOf(actor);
|
|
75
|
+
if (!store.schemaCurrent() || !account || !store.isInstanceOperator(actor) || !store.accountCanAccess(actor, repo))
|
|
76
|
+
throw Error('An installation operator must review this coding result.');
|
|
77
|
+
if (updateAdmissionPaused(store.handle))
|
|
78
|
+
throw Error('Toolroll is updating. Create the review task after the update finishes.');
|
|
79
|
+
return account.generation;
|
|
80
|
+
}
|
|
81
|
+
function sessionFor(db, store, sessionId, actor) {
|
|
82
|
+
if (!/^[a-f0-9]{32}$/.test(sessionId))
|
|
83
|
+
throw Error('Choose a saved coding session.');
|
|
84
|
+
const row = db.prepare('SELECT owner,generation,repo,document FROM coding_session WHERE id=?').get(sessionId);
|
|
85
|
+
if (!row || row['owner'] !== actor)
|
|
86
|
+
throw Error('This coding session is not available to your account.');
|
|
87
|
+
const session = JSON.parse(String(row['document']));
|
|
88
|
+
const generation = actorGeneration(store, actor, String(row['repo']));
|
|
89
|
+
if (row['generation'] !== generation || session.id !== sessionId || session.owner !== actor || session.generation !== generation || session.repo !== row['repo'])
|
|
90
|
+
throw Error('The coding session no longer matches your account or project.');
|
|
91
|
+
return session;
|
|
92
|
+
}
|
|
93
|
+
function preview(db, store, sessionId, actor) {
|
|
94
|
+
const session = sessionFor(db, store, sessionId, actor);
|
|
95
|
+
if (!['ready', 'interrupted', 'failed'].includes(session.status) || session.turnId !== null || session.deliveryReviewRequired ||
|
|
96
|
+
db.prepare("SELECT 1 FROM coding_submission WHERE session=? AND status IN ('preparing','pending','uncertain')").get(sessionId) ||
|
|
97
|
+
db.prepare("SELECT 1 FROM coding_request WHERE session=? AND status='pending'").get(sessionId))
|
|
98
|
+
throw Error('Finish the current coding action and resolve uncertain delivery before creating a review task.');
|
|
99
|
+
if (!SHA.test(session.base))
|
|
100
|
+
throw Error('The coding session has no exact starting commit.');
|
|
101
|
+
learningIdentity(session.repo);
|
|
102
|
+
if (git(session.worktree, ['symbolic-ref', '--short', 'HEAD']) !== session.branch ||
|
|
103
|
+
realpathSync(git(session.worktree, ['rev-parse', '--path-format=absolute', '--git-common-dir'])) !== realpathSync(git(session.repo, ['rev-parse', '--path-format=absolute', '--git-common-dir'])))
|
|
104
|
+
throw Error('The coding checkout no longer matches its saved project and branch.');
|
|
105
|
+
if (git(session.worktree, ['status', '--porcelain=v1', '-z', '--untracked-files=all']) !== '')
|
|
106
|
+
throw Error('Commit the coding changes before creating a review task. Uncommitted work stays in the coding session.');
|
|
107
|
+
const candidate = git(session.worktree, ['rev-parse', '--verify', 'HEAD^{commit}']);
|
|
108
|
+
if (!SHA.test(candidate))
|
|
109
|
+
throw Error('The coding result has no exact commit.');
|
|
110
|
+
git(session.repo, ['merge-base', '--is-ancestor', session.base, candidate]);
|
|
111
|
+
const changedPaths = git(session.repo, ['diff', '--name-only', '--no-renames', '-z', session.base, candidate]).split('\0').filter(Boolean);
|
|
112
|
+
if (!changedPaths.length)
|
|
113
|
+
throw Error('There are no committed changes to review.');
|
|
114
|
+
if (changedPaths.length > PROOF_LIMITS.changed || changedPaths.some(path => Buffer.byteLength(path) > PROOF_LIMITS.changedPath || /[\x00-\x1f\x7f]/.test(path)))
|
|
115
|
+
throw Error('The complete coding change exceeds the current evidence limits. Split it into explicitly scoped changes before review.');
|
|
116
|
+
const first = db.prepare("SELECT payload FROM coding_item WHERE session=? AND json_extract(payload,'$.type')='userMessage' ORDER BY position LIMIT 1").get(sessionId);
|
|
117
|
+
const originalPrompt = first ? JSON.parse(String(first['payload'])).text : null;
|
|
118
|
+
if (typeof originalPrompt !== 'string' || !originalPrompt.trim())
|
|
119
|
+
throw Error('The session’s original request is unavailable. Restore its conversation before creating a review task.');
|
|
120
|
+
return { sessionId, repo: session.repo, base: session.base, candidate, title: session.title, originalPrompt, changedPaths };
|
|
121
|
+
}
|
|
122
|
+
export function codingHandoffPreview(store, input) {
|
|
123
|
+
const db = catalog(store, true);
|
|
124
|
+
try {
|
|
125
|
+
return preview(db, store, input.sessionId, input.actor);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
db.close();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function makeReceipt(terms) {
|
|
132
|
+
const id = learningSha(JSON.stringify(terms)).slice(0, 32), taskId = `coding-review-${id}`;
|
|
133
|
+
return { ...terms, id, taskId, branch: taskBranch(taskId) };
|
|
134
|
+
}
|
|
135
|
+
function parseReceipt(row) {
|
|
136
|
+
const payload = String(row['payload']);
|
|
137
|
+
if (learningSha(payload) !== row['sha'])
|
|
138
|
+
throw Error('The coding handoff receipt could not be verified.');
|
|
139
|
+
const receipt = JSON.parse(payload);
|
|
140
|
+
const { id, taskId, branch, ...terms } = receipt;
|
|
141
|
+
const expected = makeReceipt(terms);
|
|
142
|
+
if (receipt.version !== 1 || row['id'] !== id || id !== expected.id || taskId !== expected.taskId || !BRANCH_PREFIXES.some(prefix => branch === `${prefix}${taskId}`) || !SHA.test(receipt.base) || !SHA.test(receipt.candidate))
|
|
143
|
+
throw Error('The coding handoff receipt identity could not be verified.');
|
|
144
|
+
return receipt;
|
|
145
|
+
}
|
|
146
|
+
function sealPayload(receipt, scopeDigest) {
|
|
147
|
+
return JSON.stringify({ version: 1, id: receipt.id, receiptSha256: learningSha(JSON.stringify(receipt)), scopeDigest });
|
|
148
|
+
}
|
|
149
|
+
function verifySeal(db, receipt, digest) {
|
|
150
|
+
const seal = db.prepare('SELECT payload,sha FROM coding_handoff_scope WHERE id=?').get(receipt.id);
|
|
151
|
+
if (!seal || seal['payload'] !== sealPayload(receipt, digest) || learningSha(String(seal['payload'])) !== seal['sha'])
|
|
152
|
+
throw Error('The coding review scope changed or its saved receipt is missing. Create a new review task for the current terms.');
|
|
153
|
+
}
|
|
154
|
+
/** Returns null only for ordinary tasks. A coding marker always requires its receipt. */
|
|
155
|
+
export function readCodingHandoff(store, taskId) {
|
|
156
|
+
const provenance = store.filedViaOf(taskId);
|
|
157
|
+
if (!provenance?.startsWith(PREFIX))
|
|
158
|
+
return null;
|
|
159
|
+
if (!/^coding:[a-f0-9]{32}$/.test(provenance))
|
|
160
|
+
throw Error('The coding handoff identity is invalid.');
|
|
161
|
+
const db = catalog(store, true);
|
|
162
|
+
try {
|
|
163
|
+
const row = db.prepare('SELECT * FROM coding_handoff WHERE id=?').get(provenance.slice(PREFIX.length));
|
|
164
|
+
if (!row)
|
|
165
|
+
throw Error('The coding handoff receipt is missing. Restore it before review.');
|
|
166
|
+
const receipt = parseReceipt(row), scope = store.getScope(taskId), ref = store.lookupRef(taskId);
|
|
167
|
+
if (receipt.taskId !== taskId || ref?.repo !== receipt.repo || receipt.identity !== learningIdentity(receipt.repo) || !scope || scope.termsProblem != null || scope.candidate !== receipt.candidate)
|
|
168
|
+
throw Error('The coding review no longer matches its saved project, candidate or scope.');
|
|
169
|
+
verifySeal(db, receipt, scope.digest);
|
|
170
|
+
return { taskId, scopeDigest: scope.digest, receipt };
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
db.close();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** No agent dispatch, approval, push, or modification of an existing Git ref. */
|
|
177
|
+
export function createCodingHandoff(store, input) {
|
|
178
|
+
const invalid = validateTaskText({ title: input.title, goal: input.goal });
|
|
179
|
+
if (invalid)
|
|
180
|
+
throw Error(invalid.message);
|
|
181
|
+
if (!input.goal.trim())
|
|
182
|
+
throw Error('Describe what this result should achieve.');
|
|
183
|
+
const parsed = parseAcceptanceCriteria(input.acceptance);
|
|
184
|
+
if (parsed.problems.length || !parsed.criteria.length)
|
|
185
|
+
throw Error(parsed.problems.map(problem => problem.message).join(' ') || 'Add at least one acceptance criterion.');
|
|
186
|
+
const db = catalog(store, false);
|
|
187
|
+
try {
|
|
188
|
+
const shown = preview(db, store, input.sessionId, input.actor);
|
|
189
|
+
if (shown.repo !== input.repo || shown.base !== input.base || shown.candidate !== input.candidate)
|
|
190
|
+
throw Error('The coding result changed. Review the current committed result before creating its task.');
|
|
191
|
+
if (parsed.criteria.some(criterion => criterion.evidence.includes('screenshot')))
|
|
192
|
+
readPreparedEvidence(shown.repo, shown.candidate, true);
|
|
193
|
+
const receipt = makeReceipt({ ...shown, version: 1, identity: learningIdentity(input.repo), actor: input.actor,
|
|
194
|
+
generation: actorGeneration(store, input.actor, input.repo), title: input.title.trim(), goal: input.goal.trim(), acceptance: parsed.criteria, outOfScope: EXCLUSIONS });
|
|
195
|
+
const payload = JSON.stringify(receipt), sha = learningSha(payload);
|
|
196
|
+
db.exec('BEGIN IMMEDIATE');
|
|
197
|
+
let reserved = false;
|
|
198
|
+
try {
|
|
199
|
+
const prior = db.prepare('SELECT * FROM coding_handoff WHERE id=?').get(receipt.id);
|
|
200
|
+
if (prior) {
|
|
201
|
+
if (JSON.stringify(parseReceipt(prior)) !== payload)
|
|
202
|
+
throw Error('This coding handoff conflicts with its saved receipt.');
|
|
203
|
+
reserved = true;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
if (store.lookupRef(receipt.taskId) || branchHead(input.repo, receipt.branch) !== null)
|
|
207
|
+
throw Error('The review task or branch already exists. It has been preserved.');
|
|
208
|
+
db.prepare('INSERT INTO coding_handoff VALUES(?,?,?,?)').run(receipt.id, payload, sha, new Date().toISOString());
|
|
209
|
+
}
|
|
210
|
+
db.exec('COMMIT');
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
db.exec('ROLLBACK');
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
if (store.lookupRef(receipt.taskId)) {
|
|
217
|
+
const existing = readCodingHandoff(store, receipt.taskId);
|
|
218
|
+
if (!reserved || !existing || JSON.stringify(existing.receipt) !== payload)
|
|
219
|
+
throw Error('This task belongs to another handoff. It has been preserved.');
|
|
220
|
+
const head = branchHead(input.repo, receipt.branch);
|
|
221
|
+
if (head === null)
|
|
222
|
+
throw Error('The saved review branch is missing. Restore it before continuing.');
|
|
223
|
+
verifyCodingHandoffBase(store, { taskId: receipt.taskId, taskRef: store.lookupRef(receipt.taskId).id, repo: receipt.repo, branch: receipt.branch, head });
|
|
224
|
+
return existing;
|
|
225
|
+
}
|
|
226
|
+
const current = branchHead(input.repo, receipt.branch);
|
|
227
|
+
const refMessage = `Toolroll coding handoff ${sha}`;
|
|
228
|
+
if (current === null)
|
|
229
|
+
git(input.repo, ['update-ref', '--create-reflog', '-m', refMessage, `refs/heads/${receipt.branch}`, input.base, '0'.repeat(40)]);
|
|
230
|
+
else if (!reserved || current !== input.base || git(input.repo, ['reflog', 'show', '-1', '--format=%gs', `refs/heads/${receipt.branch}`]) !== refMessage)
|
|
231
|
+
throw Error('The reserved review branch changed. It has been preserved; create a new handoff.');
|
|
232
|
+
// No checked-out/leased branch is adopted, even if its HEAD happens to match.
|
|
233
|
+
if (git(input.repo, ['worktree', 'list', '--porcelain']).split('\n').includes(`branch refs/heads/${receipt.branch}`))
|
|
234
|
+
throw Error('The review branch is already checked out. Its work has been preserved.');
|
|
235
|
+
return store.transact(() => {
|
|
236
|
+
if (actorGeneration(store, input.actor, input.repo) !== receipt.generation)
|
|
237
|
+
throw Error('Your account changed. Sign in again.');
|
|
238
|
+
if (branchHead(input.repo, receipt.branch) !== receipt.base)
|
|
239
|
+
throw Error('The review branch moved before filing. Its work has been preserved.');
|
|
240
|
+
const made = fileTaskProposal(store, { id: receipt.taskId, title: receipt.title, repo: receipt.repo, goal: receipt.goal,
|
|
241
|
+
outOfScope: receipt.outOfScope, acceptance: receipt.acceptance, filedVia: PREFIX + receipt.id, filedBy: { name: input.actor, kind: "person" }, planning: 'skip', admittedRepos: [receipt.repo] }, new Date());
|
|
242
|
+
if (!made.ok)
|
|
243
|
+
throw Error(made.message);
|
|
244
|
+
const ref = store.lookupRef(made.id);
|
|
245
|
+
const proposed = proposeGuarded(store, { taskId: made.id, author: input.actor, taskRef: ref.id, sawDigest: store.getScope(made.id).digest,
|
|
246
|
+
goal: receipt.goal, outOfScope: receipt.outOfScope, acceptance: receipt.acceptance, candidate: receipt.candidate, now: new Date() });
|
|
247
|
+
if (!proposed.ok)
|
|
248
|
+
throw Error(proposed.message || 'The prepared review scope could not be saved.');
|
|
249
|
+
const seal = sealPayload(receipt, proposed.scope.digest);
|
|
250
|
+
const prior = db.prepare('SELECT 1 FROM coding_handoff_scope WHERE id=?').get(receipt.id);
|
|
251
|
+
if (prior)
|
|
252
|
+
verifySeal(db, receipt, proposed.scope.digest);
|
|
253
|
+
else
|
|
254
|
+
db.prepare('INSERT INTO coding_handoff_scope VALUES(?,?,?)').run(receipt.id, seal, learningSha(seal));
|
|
255
|
+
// The durable sidecar seal precedes the main transaction commit. Failure
|
|
256
|
+
// here rolls back the ordinary task; receipt and branch remain recoverable.
|
|
257
|
+
return { taskId: made.id, scopeDigest: proposed.scope.digest, receipt };
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
db.close();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/** Called before setup and immediately before recording the attempt's base. */
|
|
265
|
+
export function verifyCodingHandoffBase(store, input) {
|
|
266
|
+
const handoff = readCodingHandoff(store, input.taskId);
|
|
267
|
+
if (!handoff)
|
|
268
|
+
return;
|
|
269
|
+
const { receipt } = handoff;
|
|
270
|
+
if (store.lookupRef(input.taskId)?.id !== input.taskRef || input.repo !== receipt.repo || input.branch !== receipt.branch)
|
|
271
|
+
throw Error('The coding review is assigned to a different task, project or branch.');
|
|
272
|
+
const pinned = store.firstBuilderBase(input.taskRef, input.branch);
|
|
273
|
+
if (!SHA.test(input.head) || (pinned ?? input.head) !== receipt.base)
|
|
274
|
+
throw Error('The review branch no longer starts at the coding session’s original commit. Its work has been preserved; create a new review task.');
|
|
275
|
+
if (pinned !== null)
|
|
276
|
+
git(receipt.repo, ['merge-base', '--is-ancestor', receipt.base, input.head]);
|
|
277
|
+
}
|