cloving 1.3.0 → 1.4.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/README.md +235 -206
- package/dist/src/agent-harness-shell.d.ts +2 -1
- package/dist/src/agent-harness-shell.js +8 -5
- package/dist/src/authority/command-wait-checks.d.ts +8 -0
- package/dist/src/authority/command-wait-checks.js +88 -0
- package/dist/src/authority/command-wait-results.d.ts +15 -0
- package/dist/src/authority/command-wait-results.js +73 -0
- package/dist/src/authority/command-wait-view.d.ts +21 -0
- package/dist/src/authority/command-wait-view.js +34 -0
- package/dist/src/authority/command-waits.d.ts +39 -0
- package/dist/src/authority/command-waits.js +97 -0
- package/dist/src/authority/commands.js +22 -1
- package/dist/src/authority/dispatch-decision.d.ts +8 -0
- package/dist/src/authority/dispatch-decision.js +26 -1
- package/dist/src/authority/effect-requests.js +6 -3
- package/dist/src/authority/effect-results.js +4 -2
- package/dist/src/authority/history-state.d.ts +2 -0
- package/dist/src/authority/history-state.js +13 -1
- package/dist/src/authority/instants.d.ts +1 -0
- package/dist/src/authority/instants.js +21 -0
- package/dist/src/authority/reduction-state.d.ts +2 -0
- package/dist/src/authority/reduction-state.js +5 -0
- package/dist/src/authority/reduction.js +24 -0
- package/dist/src/authority/status-input.d.ts +2 -0
- package/dist/src/authority/status.d.ts +2 -0
- package/dist/src/authority/status.js +1 -0
- package/dist/src/authority/stop-sequence.d.ts +1 -0
- package/dist/src/authority/stop-sequence.js +2 -1
- package/dist/src/authority/transitions.d.ts +6 -4
- package/dist/src/authority/transitions.js +7 -0
- package/dist/src/broker/actor/authority-queries.d.ts +2 -1
- package/dist/src/broker/actor/authority-queries.js +14 -5
- package/dist/src/broker/actor/authority-receipts.js +1 -1
- package/dist/src/broker/actor/authority-settings.js +2 -2
- package/dist/src/broker/actor/authority-upgrades.d.ts +19 -2
- package/dist/src/broker/actor/authority-upgrades.js +7 -2
- package/dist/src/broker/actor/delivery-intents.js +2 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
- package/dist/src/broker/actor/effect-delivery.js +15 -2
- package/dist/src/broker/actor/effect-plan.js +11 -2
- package/dist/src/broker/actor/effect-queries.d.ts +4 -0
- package/dist/src/broker/actor/effect-queries.js +9 -1
- package/dist/src/broker/actor/effect-turn.js +2 -0
- package/dist/src/broker/actor/stop-plan.js +9 -3
- package/dist/src/broker/actor/stop-turn.d.ts +2 -0
- package/dist/src/broker/actor/stop-turn.js +24 -11
- package/dist/src/broker/actor/turn-draft.d.ts +1 -0
- package/dist/src/broker/actor/turn-draft.js +4 -0
- package/dist/src/broker/actor/turn-state.js +5 -1
- package/dist/src/broker/authority-admission.js +60 -0
- package/dist/src/broker/authority-restore.d.ts +2 -0
- package/dist/src/broker/authority-restore.js +35 -1
- package/dist/src/broker/command-wait-restore.d.ts +31 -0
- package/dist/src/broker/command-wait-restore.js +86 -0
- package/dist/src/broker/decision-restore.d.ts +1 -1
- package/dist/src/broker/decision-restore.js +1 -0
- package/dist/src/broker/effect-upgrade.d.ts +2 -0
- package/dist/src/broker/effect-upgrade.js +8 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +42 -3
- package/dist/src/cli/chat-stores.d.ts +2 -0
- package/dist/src/cli/chat-stores.js +113 -0
- package/dist/src/cli/client.d.ts +4 -1
- package/dist/src/cli/client.js +9 -3
- package/dist/src/cli/command-requests.d.ts +17 -0
- package/dist/src/cli/command-requests.js +43 -0
- package/dist/src/cli/command-waits.d.ts +9 -0
- package/dist/src/cli/command-waits.js +51 -0
- package/dist/src/cli/commands.js +14 -41
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/doctor-workflows.d.ts +5 -2
- package/dist/src/cli/doctor-workflows.js +12 -7
- package/dist/src/cli/doctor.js +6 -9
- package/dist/src/cli/harness-probes.d.ts +2 -0
- package/dist/src/cli/harness-probes.js +1 -1
- package/dist/src/cli/harness-processes.d.ts +6 -0
- package/dist/src/cli/harness-processes.js +36 -0
- package/dist/src/cli/init-command.d.ts +9 -0
- package/dist/src/cli/init-command.js +52 -0
- package/dist/src/cli/init-prompt-command.d.ts +10 -0
- package/dist/src/cli/init-prompt-command.js +145 -0
- package/dist/src/cli/init-prompt.d.ts +35 -0
- package/dist/src/cli/init-prompt.js +74 -0
- package/dist/src/cli/init-selection.d.ts +13 -0
- package/dist/src/cli/init-selection.js +75 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +37 -7
- package/dist/src/cli/mcp-server.d.ts +1 -0
- package/dist/src/cli/mcp-server.js +156 -0
- package/dist/src/cli/mcp-tools.d.ts +15 -0
- package/dist/src/cli/mcp-tools.js +80 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +17 -30
- package/dist/src/cli/report-ci-jobs.d.ts +23 -0
- package/dist/src/cli/report-ci-jobs.js +103 -0
- package/dist/src/cli/report-ci-usage.d.ts +9 -0
- package/dist/src/cli/report-ci-usage.js +185 -0
- package/dist/src/cli/report-ci.d.ts +13 -0
- package/dist/src/cli/report-ci.js +74 -0
- package/dist/src/cli/report-closures.d.ts +6 -0
- package/dist/src/cli/report-closures.js +97 -0
- package/dist/src/cli/report-flow.d.ts +7 -0
- package/dist/src/cli/report-flow.js +122 -0
- package/dist/src/cli/report-github-reader.d.ts +29 -0
- package/dist/src/cli/report-github-reader.js +157 -0
- package/dist/src/cli/report-github.d.ts +15 -8
- package/dist/src/cli/report-github.js +131 -150
- package/dist/src/cli/report-operator.d.ts +3 -0
- package/dist/src/cli/report-operator.js +40 -0
- package/dist/src/cli/report-ready.d.ts +3 -0
- package/dist/src/cli/report-ready.js +96 -0
- package/dist/src/cli/report-text.d.ts +9 -0
- package/dist/src/cli/report-text.js +33 -0
- package/dist/src/cli/report.d.ts +1 -0
- package/dist/src/cli/report.js +104 -27
- package/dist/src/cli/runtime-arguments.d.ts +2 -1
- package/dist/src/cli/runtime-arguments.js +7 -2
- package/dist/src/cli/schedule-arguments.d.ts +14 -0
- package/dist/src/cli/schedule-arguments.js +26 -0
- package/dist/src/cli/schedule-render.d.ts +22 -0
- package/dist/src/cli/schedule-render.js +73 -0
- package/dist/src/cli/terminal-text.d.ts +3 -0
- package/dist/src/cli/terminal-text.js +28 -0
- package/dist/src/cli/usage-render.d.ts +1 -0
- package/dist/src/cli/usage-render.js +28 -1
- package/dist/src/cli/usage.d.ts +1 -1
- package/dist/src/cli/usage.js +50 -7
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-board-view.js +19 -2
- package/dist/src/cli/watch-board.d.ts +4 -2
- package/dist/src/cli/watch-board.js +53 -43
- package/dist/src/cli/watch-card-forms.d.ts +1 -1
- package/dist/src/cli/watch-card-forms.js +11 -10
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +2 -11
- package/dist/src/cli/watch-header-view.d.ts +0 -5
- package/dist/src/cli/watch-header-view.js +8 -20
- package/dist/src/cli/watch-model.d.ts +4 -1
- package/dist/src/cli/watch-model.js +17 -11
- package/dist/src/cli/watch-page.js +12 -14
- package/dist/src/cli/watch-phases.d.ts +12 -3
- package/dist/src/cli/watch-phases.js +68 -11
- package/dist/src/cli/watch-pr-board.js +1 -1
- package/dist/src/cli/watch-pr-command.d.ts +1 -0
- package/dist/src/cli/watch-pull-request.js +18 -8
- package/dist/src/cli/watch-reads.d.ts +2 -0
- package/dist/src/cli/watch-reads.js +17 -16
- package/dist/src/cli/watch-render.d.ts +14 -0
- package/dist/src/cli/watch-run-input.d.ts +0 -1
- package/dist/src/cli/watch-run-input.js +0 -13
- package/dist/src/cli/watch-server.js +6 -6
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +59 -5
- package/dist/src/command-wait.d.ts +4 -0
- package/dist/src/command-wait.js +45 -0
- package/dist/src/configuration-change.d.ts +7 -0
- package/dist/src/configuration-change.js +14 -0
- package/dist/src/configuration-schema.d.ts +9 -0
- package/dist/src/configuration-schema.js +6 -2
- package/dist/src/daemon/attachment-file.d.ts +6 -0
- package/dist/src/daemon/attachment-file.js +86 -0
- package/dist/src/daemon/attachments.d.ts +14 -0
- package/dist/src/daemon/attachments.js +17 -0
- package/dist/src/daemon/claude-recovery.d.ts +50 -0
- package/dist/src/daemon/claude-recovery.js +204 -0
- package/dist/src/daemon/claude-stream.d.ts +27 -0
- package/dist/src/daemon/claude-stream.js +63 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -25
- package/dist/src/daemon/claude-turn.js +64 -81
- package/dist/src/daemon/claude-worker.d.ts +2 -1
- package/dist/src/daemon/claude-worker.js +124 -122
- package/dist/src/daemon/daemon-adapters.d.ts +2 -0
- package/dist/src/daemon/daemon-adapters.js +26 -2
- package/dist/src/daemon/daemon-loops.d.ts +3 -1
- package/dist/src/daemon/daemon-loops.js +3 -1
- package/dist/src/daemon/daemon.js +14 -6
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +149 -0
- package/dist/src/daemon/github-ci-filters.d.ts +6 -0
- package/dist/src/daemon/github-ci-filters.js +138 -0
- package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
- package/dist/src/daemon/github-ci-workflows.js +148 -0
- package/dist/src/daemon/github-ci.js +22 -4
- package/dist/src/daemon/github-issue-methods.d.ts +2 -0
- package/dist/src/daemon/github-issue-methods.js +37 -2
- package/dist/src/daemon/github-merge-call.d.ts +2 -1
- package/dist/src/daemon/github-merge-call.js +10 -3
- package/dist/src/daemon/github-merge.js +52 -24
- package/dist/src/daemon/github-methods.js +12 -2
- package/dist/src/daemon/github-operation.d.ts +4 -0
- package/dist/src/daemon/github-operation.js +6 -0
- package/dist/src/daemon/github-worker.d.ts +4 -0
- package/dist/src/daemon/github-worker.js +6 -0
- package/dist/src/daemon/issue-queue.d.ts +1 -1
- package/dist/src/daemon/issue-queue.js +16 -11
- package/dist/src/daemon/notify-events.d.ts +6 -0
- package/dist/src/daemon/notify-events.js +84 -0
- package/dist/src/daemon/notify-journal.js +1 -1
- package/dist/src/daemon/notify-message.d.ts +4 -1
- package/dist/src/daemon/notify-message.js +36 -0
- package/dist/src/daemon/notify.d.ts +1 -1
- package/dist/src/daemon/notify.js +5 -77
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/resume-index-lock.d.ts +13 -0
- package/dist/src/daemon/resume-index-lock.js +160 -0
- package/dist/src/daemon/resume-worktree.d.ts +7 -0
- package/dist/src/daemon/resume-worktree.js +29 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -12
- package/dist/src/daemon/retrying-turn.js +98 -172
- package/dist/src/daemon/schedule-control.d.ts +26 -0
- package/dist/src/daemon/schedule-control.js +110 -0
- package/dist/src/daemon/schedule-journal.d.ts +2 -15
- package/dist/src/daemon/schedule-journal.js +67 -4
- package/dist/src/daemon/ticket-registration.d.ts +2 -7
- package/dist/src/daemon/ticket-registration.js +15 -81
- package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
- package/dist/src/daemon/turn-attempt-journal.js +136 -0
- package/dist/src/daemon/turn-attempts.d.ts +47 -0
- package/dist/src/daemon/turn-attempts.js +166 -0
- package/dist/src/daemon/turn-report.d.ts +8 -1
- package/dist/src/daemon/turn-report.js +39 -0
- package/dist/src/daemon/work-tree.d.ts +9 -0
- package/dist/src/daemon/work-tree.js +20 -0
- package/dist/src/daemon/worker-profile.d.ts +8 -0
- package/dist/src/daemon/worker-profile.js +40 -0
- package/dist/src/daemon/workflow-schedules.d.ts +3 -0
- package/dist/src/daemon/workflow-schedules.js +98 -45
- package/dist/src/daemon/worktree-processes.d.ts +9 -0
- package/dist/src/daemon/worktree-processes.js +151 -0
- package/dist/src/doctor-report.d.ts +3 -5
- package/dist/src/doctor-report.js +6 -13
- package/dist/src/harness-start.d.ts +15 -0
- package/dist/src/harness-start.js +37 -0
- package/dist/src/host/command-wait.d.ts +38 -0
- package/dist/src/host/command-wait.js +115 -0
- package/dist/src/host/start-delivery.d.ts +5 -7
- package/dist/src/host/start-delivery.js +3 -15
- package/dist/src/host/step-bridge-host.d.ts +2 -0
- package/dist/src/host/step-bridge-host.js +21 -0
- package/dist/src/operation-identity.d.ts +1 -0
- package/dist/src/operation-identity.js +4 -0
- package/dist/src/private-config.schema.json +40 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +2 -2
- package/dist/src/project-settings.js +3 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/relay/relay-service.d.ts +3 -0
- package/dist/src/relay/relay-service.js +5 -3
- package/dist/src/report-ci.d.ts +164 -0
- package/dist/src/report-ci.js +32 -0
- package/dist/src/report-effects.d.ts +15 -0
- package/dist/src/report-effects.js +212 -0
- package/dist/src/report-flow-types.d.ts +38 -0
- package/dist/src/report-flow-types.js +7 -0
- package/dist/src/report-flow.d.ts +43 -0
- package/dist/src/report-flow.js +193 -0
- package/dist/src/report-operator.d.ts +67 -0
- package/dist/src/report-operator.js +25 -0
- package/dist/src/report-quality.d.ts +221 -0
- package/dist/src/report-quality.js +94 -0
- package/dist/src/report-ready.d.ts +23 -0
- package/dist/src/report-ready.js +117 -0
- package/dist/src/report-statistics.d.ts +2 -1
- package/dist/src/report-statistics.js +40 -4
- package/dist/src/report.d.ts +588 -47
- package/dist/src/report.js +156 -41
- package/dist/src/schedule-progress.d.ts +33 -0
- package/dist/src/schedule-progress.js +45 -0
- package/dist/src/service/active-tickets.js +6 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/replies.d.ts +8 -1
- package/dist/src/service/replies.js +11 -0
- package/dist/src/service/run-handlers.js +22 -2
- package/dist/src/service/run-metadata.d.ts +15 -1
- package/dist/src/service/run-metadata.js +93 -8
- package/dist/src/service/service.d.ts +4 -0
- package/dist/src/service/service.js +8 -8
- package/dist/src/service/submission-handler.js +18 -4
- package/dist/src/service/worker-port.js +9 -1
- package/dist/src/service/worker-totals.d.ts +2 -0
- package/dist/src/service/worker-totals.js +1 -1
- package/dist/src/step-bridge.d.ts +20 -0
- package/dist/src/steps/command-wait.d.ts +12 -0
- package/dist/src/steps/command-wait.js +26 -0
- package/dist/src/steps/open-decision-wait.d.ts +2 -0
- package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
- package/dist/src/steps/review-by-person.js +4 -1
- package/dist/src/steps/wait-for-command.d.ts +3 -0
- package/dist/src/steps/wait-for-command.js +17 -0
- package/dist/src/steps/wait-for-decision.js +1 -1
- package/dist/src/storage/command-wait-rows.d.ts +30 -0
- package/dist/src/storage/command-wait-rows.js +96 -0
- package/dist/src/storage/decision-snapshots.d.ts +8 -1
- package/dist/src/storage/decision-snapshots.js +15 -1
- package/dist/src/storage/domain-changes.d.ts +2 -0
- package/dist/src/storage/domain-changes.js +3 -0
- package/dist/src/storage/domain-schema.d.ts +13 -1
- package/dist/src/storage/domain-schema.js +31 -4
- package/dist/src/storage/effect-schema.d.ts +1 -0
- package/dist/src/storage/effect-schema.js +5 -0
- package/dist/src/testing-requests.d.ts +15 -0
- package/dist/src/testing-requests.js +93 -0
- package/dist/src/testing.d.ts +4 -10
- package/dist/src/testing.js +33 -86
- package/dist/src/worker-usage.d.ts +1 -0
- package/dist/src/worker-usage.js +3 -0
- package/dist/src/workflow-candidate.d.ts +1 -0
- package/dist/src/workflow-candidate.js +12 -1
- package/dist/src/workflow-contracts.d.ts +1 -0
- package/dist/src/workflow-contracts.js +9 -2
- package/dist/src/workflow-discovery.d.ts +2 -13
- package/dist/src/workflow-discovery.js +1 -13
- package/dist/src/workflow-refusals.js +0 -1
- package/dist/src/workflows.d.ts +1 -1
- package/dist/src/workflows.js +1 -1
- package/dist/tools/red-green-command.d.ts +1 -0
- package/dist/tools/red-green-command.js +174 -0
- package/dist/tools/red-green-process.d.ts +10 -0
- package/dist/tools/red-green-process.js +59 -0
- package/dist/tools/self-host-processes.d.ts +2 -0
- package/dist/tools/self-host-processes.js +32 -13
- package/dist/tools/self-host-project.js +13 -78
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +42 -10
- package/dist/tools/template-command.d.ts +1 -0
- package/dist/tools/template-command.js +160 -0
- package/dist/tools/template-copy.d.ts +11 -0
- package/dist/tools/template-copy.js +130 -0
- package/dist/tools/template-files.d.ts +17 -0
- package/dist/tools/template-files.js +74 -0
- package/dist/tools/workflow-bundles.js +1 -0
- package/dist/tools/workflow-candidate-counts.js +2 -2
- package/dist/tools/workflow-candidate-shape.d.ts +3 -0
- package/dist/tools/workflow-candidate-shape.js +90 -0
- package/dist/tools/workflow-candidate-source.js +15 -1
- package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
- package/dist/tools/workflow-candidate-syntax.js +24 -94
- package/dist/tools/workflow-command.js +1 -2
- package/dist/tools/workflow-folders.d.ts +2 -3
- package/dist/tools/workflow-folders.js +1 -1
- package/package.json +16 -8
- package/templates/develop/README.md +12 -0
- package/templates/develop/develop/flow-tests.ts +37 -0
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/turn.ts +2 -1
- package/templates/idea-to-issue/README.md +27 -0
- package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
- package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
- package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
- package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
- package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
- package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
- package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
- package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
- package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
- package/templates/idea-to-issue/idea-to-issue.ts +49 -0
- package/templates/idea-to-issue/template.json +81 -0
- package/templates/review-day/README.md +97 -0
- package/templates/review-day/review-day/critique.ts +58 -0
- package/templates/review-day/review-day/decision.ts +29 -0
- package/templates/review-day/review-day/facts.ts +69 -0
- package/templates/review-day/review-day/label.ts +29 -0
- package/templates/review-day/review-day/next.ts +28 -0
- package/templates/review-day/review-day/post.ts +27 -0
- package/templates/review-day/review-day/report.ts +98 -0
- package/templates/review-day/review-day/rules.ts +12 -0
- package/templates/review-day/review-day/scenarios.ts +76 -0
- package/templates/review-day/review-day/turn.ts +73 -0
- package/templates/review-day/review-day.declaration.json +16 -0
- package/templates/review-day/review-day.test.ts +362 -0
- package/templates/review-day/review-day.ts +37 -0
- package/templates/review-day/template.json +56 -0
- package/dist/src/cli/watch-start-view.d.ts +0 -18
- package/dist/src/cli/watch-start-view.js +0 -77
- package/dist/src/steps/decision-gate.d.ts +0 -3
- package/dist/workflows/develop-prd.d.ts +0 -7
- package/dist/workflows/develop-prd.js +0 -165
- package/dist/workflows/develop-ticket.d.ts +0 -9
- package/dist/workflows/develop-ticket.js +0 -207
- package/dist/workflows/issue-labels.d.ts +0 -16
- package/dist/workflows/issue-labels.js +0 -70
- package/dist/workflows/ticket-prompts.d.ts +0 -35
- package/dist/workflows/ticket-prompts.js +0 -147
|
@@ -36,3 +36,24 @@ export function notBefore(value, bound) {
|
|
|
36
36
|
export function isAfter(value, bound) {
|
|
37
37
|
return notBefore(value, bound) && !notBefore(bound, value);
|
|
38
38
|
}
|
|
39
|
+
function leapDaysBefore(year) {
|
|
40
|
+
const previous = year - 1;
|
|
41
|
+
return (Math.floor(previous / 4) -
|
|
42
|
+
Math.floor(previous / 100) +
|
|
43
|
+
Math.floor(previous / 400));
|
|
44
|
+
}
|
|
45
|
+
export function instantMilliseconds(value) {
|
|
46
|
+
if (!isInstant(value))
|
|
47
|
+
throw new Error("invalid-instant");
|
|
48
|
+
const year = Number(value.slice(0, 4));
|
|
49
|
+
const month = Number(value.slice(5, 7));
|
|
50
|
+
let days = Number(value.slice(8, 10)) - 1;
|
|
51
|
+
for (let preceding = 1; preceding < month; preceding += 1)
|
|
52
|
+
days += daysIn(year, preceding);
|
|
53
|
+
days += 365 * (year - 1970) + leapDaysBefore(year) - leapDaysBefore(1970);
|
|
54
|
+
return (days * 86_400_000 +
|
|
55
|
+
Number(value.slice(11, 13)) * 3_600_000 +
|
|
56
|
+
Number(value.slice(14, 16)) * 60_000 +
|
|
57
|
+
Number(value.slice(17, 19)) * 1000 +
|
|
58
|
+
Number(value.slice(20, 23)));
|
|
59
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CommandWaitsState } from "./command-waits.ts";
|
|
1
2
|
import { type RunDetails } from "./details.ts";
|
|
2
3
|
import { type GateState } from "./gates.ts";
|
|
3
4
|
import { type Disposition, type EffectState } from "./operations.ts";
|
|
@@ -20,6 +21,7 @@ export interface Recorded {
|
|
|
20
21
|
}
|
|
21
22
|
export interface Change extends Recorded {
|
|
22
23
|
readonly moved?: RunState;
|
|
24
|
+
readonly commandWaits?: CommandWaitsState;
|
|
23
25
|
readonly gates?: readonly GateState[];
|
|
24
26
|
readonly added?: readonly EffectIntent[];
|
|
25
27
|
readonly questions?: number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { closedCommandWaits } from "./command-waits.js";
|
|
1
2
|
import { operationIdentity } from "../operation-identity.js";
|
|
2
3
|
import { continued } from "./details.js";
|
|
3
4
|
import { gateKey } from "./gates.js";
|
|
@@ -40,12 +41,16 @@ function nextDetails(change) {
|
|
|
40
41
|
}
|
|
41
42
|
export function applied(state, change) {
|
|
42
43
|
const { event } = change;
|
|
44
|
+
const waits = change.commandWaits ?? state.commandWaits;
|
|
43
45
|
return {
|
|
44
46
|
kind: "applied",
|
|
45
47
|
...(change.disposition === undefined
|
|
46
48
|
? {}
|
|
47
49
|
: { disposition: change.disposition }),
|
|
48
50
|
state: {
|
|
51
|
+
...(waits === undefined
|
|
52
|
+
? {}
|
|
53
|
+
: { commandWaits: closedCommandWaits(waits, event) }),
|
|
49
54
|
sequence: event.sequence,
|
|
50
55
|
runs: change.moved
|
|
51
56
|
? { ...state.runs, [event.runId]: change.moved }
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { checkedCommandWait } from "./command-wait-checks.js";
|
|
2
|
+
import { waitEffectTime, waitEffectChange } from "./command-wait-results.js";
|
|
3
|
+
import { commandWaitKey, commandWaitsAfter, validCommandWaitTime, } from "./command-waits.js";
|
|
1
4
|
import { admittedDetails, observed } from "./details.js";
|
|
2
5
|
import { settled } from "./gates.js";
|
|
3
6
|
import { admittedBudgets } from "./budgets.js";
|
|
@@ -57,6 +60,8 @@ function dispatched(state, recorded) {
|
|
|
57
60
|
function effect(rule) {
|
|
58
61
|
return (state, recorded) => {
|
|
59
62
|
const { event, run } = recorded;
|
|
63
|
+
if (!waitEffectTime(state.commandWaits ?? {}, event))
|
|
64
|
+
return invalid("invalid-recorded-time");
|
|
60
65
|
const result = rule(state.effects, { event, runStatus: run.status });
|
|
61
66
|
if (result.kind === "invalid")
|
|
62
67
|
return result;
|
|
@@ -64,6 +69,7 @@ function effect(rule) {
|
|
|
64
69
|
return applied(state, {
|
|
65
70
|
...recorded,
|
|
66
71
|
effects: result.effects,
|
|
72
|
+
...waitEffectChange(state, { event, result }),
|
|
67
73
|
...(result.released === undefined ? {} : { released: result.released }),
|
|
68
74
|
...(result.disposition === undefined
|
|
69
75
|
? {}
|
|
@@ -78,8 +84,24 @@ function effect(rule) {
|
|
|
78
84
|
});
|
|
79
85
|
};
|
|
80
86
|
}
|
|
87
|
+
const changeCommandWait = (state, recorded) => {
|
|
88
|
+
const { event, run } = recorded;
|
|
89
|
+
const waits = state.commandWaits ?? {};
|
|
90
|
+
const key = commandWaitKey(event.runId, event.payload["waitName"] ?? "");
|
|
91
|
+
if (event.type === "command-wait.opened" &&
|
|
92
|
+
waits[key] === undefined &&
|
|
93
|
+
run.status !== "running")
|
|
94
|
+
return invalid("command-wait-run-not-running");
|
|
95
|
+
const result = commandWaitsAfter(waits, event);
|
|
96
|
+
return result.kind === "invalid"
|
|
97
|
+
? result
|
|
98
|
+
: applied(state, { ...recorded, commandWaits: result.waits });
|
|
99
|
+
};
|
|
81
100
|
const handlers = {
|
|
82
101
|
"schedule.skipped": applied,
|
|
102
|
+
"command-wait.opened": changeCommandWait,
|
|
103
|
+
"command-wait.checked": checkedCommandWait,
|
|
104
|
+
"command-wait.expired": changeCommandWait,
|
|
83
105
|
"effect.requested": effect(requested),
|
|
84
106
|
"lease.granted": effect(granted),
|
|
85
107
|
"lease.expired": effect(leaseExpired),
|
|
@@ -146,6 +168,8 @@ function created(state, recorded) {
|
|
|
146
168
|
};
|
|
147
169
|
}
|
|
148
170
|
export function reduce(state, event) {
|
|
171
|
+
if (!validCommandWaitTime(state.commandWaits ?? {}, event))
|
|
172
|
+
return invalid("invalid-command-wait-time");
|
|
149
173
|
if (event.sequence !== state.sequence + 1)
|
|
150
174
|
return invalid("sequence-gap");
|
|
151
175
|
if (state.commands[event.commandId])
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommandWaitView } from "./command-wait-view.ts";
|
|
1
2
|
import type { RunDetails } from "./details.ts";
|
|
2
3
|
import type { GateState } from "./gates.ts";
|
|
3
4
|
import type { RunClosure } from "./stop-sequence.ts";
|
|
@@ -21,6 +22,7 @@ export interface BudgetSummary {
|
|
|
21
22
|
readonly spent: number;
|
|
22
23
|
}
|
|
23
24
|
export interface StatusInput {
|
|
25
|
+
readonly commandWaits: readonly CommandWaitView[];
|
|
24
26
|
readonly run: RunState;
|
|
25
27
|
readonly details: RunDetails | undefined;
|
|
26
28
|
readonly gates: readonly GateState[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommandWaitView } from "./command-wait-view.ts";
|
|
1
2
|
import { type EffectView, type Recovery } from "./status-effects.ts";
|
|
2
3
|
import { type BudgetSummary, type StatusInput } from "./status-input.ts";
|
|
3
4
|
import type { RunStatus } from "./transitions.ts";
|
|
@@ -5,6 +6,7 @@ export { unresolved, unresolvedEffects } from "./status-closure.ts";
|
|
|
5
6
|
export type { EffectView } from "./status-effects.ts";
|
|
6
7
|
export type { Assessment, BudgetSummary, EffectSummary, OperationSummary, StatusInput, } from "./status-input.ts";
|
|
7
8
|
export interface RunView {
|
|
9
|
+
readonly commandWaits: readonly CommandWaitView[];
|
|
8
10
|
readonly runId: string;
|
|
9
11
|
readonly workflow: string;
|
|
10
12
|
readonly state: RunStatus;
|
|
@@ -266,6 +266,7 @@ export function runView(input) {
|
|
|
266
266
|
attempts: observation?.attempt ?? 0,
|
|
267
267
|
limit: observation?.limit ?? null,
|
|
268
268
|
},
|
|
269
|
+
commandWaits: input.commandWaits,
|
|
269
270
|
budget: input.budget,
|
|
270
271
|
effects: effectViews(input.effects),
|
|
271
272
|
nextAction: assessment.nextAction,
|
|
@@ -39,7 +39,8 @@ const stopPurposes = ["stop", "reconcile"];
|
|
|
39
39
|
export function stopCount(subject, cancelledSequence) {
|
|
40
40
|
return subject.attempts.filter((attempt) => attempt.outcome !== null &&
|
|
41
41
|
stopPurposes.includes(attempt.purpose) &&
|
|
42
|
-
attempt.stagedSequence >=
|
|
42
|
+
attempt.stagedSequence >=
|
|
43
|
+
Math.max(cancelledSequence, subject.stopSequence ?? 0)).length;
|
|
43
44
|
}
|
|
44
45
|
const uncertainStatuses = ["recovering", "blocked"];
|
|
45
46
|
function uncertain(subject) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommandWaitsState } from "./command-waits.ts";
|
|
1
2
|
import type { RunDetails } from "./details.ts";
|
|
2
3
|
import type { GateState } from "./gates.ts";
|
|
3
4
|
import type { EffectState } from "./operations.ts";
|
|
@@ -26,9 +27,10 @@ export interface AuthorityState {
|
|
|
26
27
|
readonly gates: Readonly<Record<string, GateState>>;
|
|
27
28
|
readonly details: Readonly<Record<string, RunDetails>>;
|
|
28
29
|
readonly questions: number;
|
|
30
|
+
readonly commandWaits?: CommandWaitsState;
|
|
29
31
|
readonly effects: EffectState;
|
|
30
32
|
}
|
|
31
|
-
export declare const eventTypes: readonly ["run.created", "run.started", "gate.opened", "gate.wait-registered", "gate.decided", "gate.expired", "run.paused", "run.resumed", "run.completed", "run.failed", "run.cancelled", "run.observed", "step.dispatched", "effect.requested", "lease.granted", "lease.expired", "effect.reported", "operation.reconciled", "schedule.skipped"];
|
|
33
|
+
export declare const eventTypes: readonly ["run.created", "run.started", "gate.opened", "gate.wait-registered", "gate.decided", "gate.expired", "run.paused", "run.resumed", "run.completed", "run.failed", "run.cancelled", "run.observed", "step.dispatched", "effect.requested", "lease.granted", "lease.expired", "effect.reported", "operation.reconciled", "schedule.skipped", "command-wait.opened", "command-wait.checked", "command-wait.expired"];
|
|
32
34
|
export type EventType = (typeof eventTypes)[number];
|
|
33
35
|
export interface AuthorityEvent {
|
|
34
36
|
readonly sequence: number;
|
|
@@ -39,8 +41,8 @@ export interface AuthorityEvent {
|
|
|
39
41
|
readonly request: string;
|
|
40
42
|
readonly payload: Readonly<Record<string, string>>;
|
|
41
43
|
}
|
|
42
|
-
export declare const numberFields: readonly ["expectedRevision", "expectedObservation", "generation", "attempt", "limit", "effectLimit", "units", "recoveryLimit", "leaseGeneration", "sourceGeneration", "capacity", "slot"];
|
|
43
|
-
export declare const textFields: readonly ["parentRunId", "chainId", "workflow", "workflowId", "submission", "input", "resolver", "gateId", "gateKind", "waitMode", "subject", "prompt", "expiresAt", "decision", "answer", "condition", "reason", "evidence", "retryAt", "operationId", "receipt", "capabilities", "capability", "method", "target", "payload", "inputDigest", "resource", "transport", "source", "worker", "outcome", "outcomeReason", "promotionId", "ticketStatus", "issueUpdate", "result", "actor"];
|
|
44
|
+
export declare const numberFields: readonly ["expectedRevision", "expectedObservation", "generation", "attempt", "limit", "effectLimit", "units", "recoveryLimit", "leaseGeneration", "sourceGeneration", "capacity", "slot", "maximumWaitSeconds", "pollEverySeconds"];
|
|
45
|
+
export declare const textFields: readonly ["parentRunId", "chainId", "workflow", "workflowId", "submission", "input", "resolver", "gateId", "gateKind", "waitMode", "subject", "prompt", "expiresAt", "decision", "answer", "condition", "reason", "evidence", "retryAt", "operationId", "receipt", "capabilities", "capability", "method", "target", "payload", "inputDigest", "resource", "transport", "source", "worker", "outcome", "outcomeReason", "promotionId", "ticketStatus", "issueUpdate", "result", "actor", "waitName", "commandOutput"];
|
|
44
46
|
export type NumberField = (typeof numberFields)[number];
|
|
45
47
|
export type TextField = (typeof textFields)[number];
|
|
46
48
|
export type AuthorityCommand = {
|
|
@@ -48,7 +50,7 @@ export type AuthorityCommand = {
|
|
|
48
50
|
readonly commandId: string;
|
|
49
51
|
readonly runId: string;
|
|
50
52
|
} & Readonly<Partial<Record<NumberField, number>>> & Readonly<Partial<Record<TextField, string>>>;
|
|
51
|
-
export type Move = Exclude<EventType, "run.created" | "step.dispatched" | "gate.wait-registered" | "run.observed" | "effect.requested" | "lease.granted" | "lease.expired" | "effect.reported" | "operation.reconciled" | "schedule.skipped">;
|
|
53
|
+
export type Move = Exclude<EventType, "run.created" | "step.dispatched" | "gate.wait-registered" | "run.observed" | "effect.requested" | "lease.granted" | "lease.expired" | "effect.reported" | "operation.reconciled" | "schedule.skipped" | "command-wait.opened" | "command-wait.checked" | "command-wait.expired">;
|
|
52
54
|
export declare const terminal: readonly RunStatus[];
|
|
53
55
|
export type Transition = {
|
|
54
56
|
readonly kind: "moved";
|
|
@@ -18,6 +18,9 @@ export const eventTypes = [
|
|
|
18
18
|
"effect.reported",
|
|
19
19
|
"operation.reconciled",
|
|
20
20
|
"schedule.skipped",
|
|
21
|
+
"command-wait.opened",
|
|
22
|
+
"command-wait.checked",
|
|
23
|
+
"command-wait.expired",
|
|
21
24
|
];
|
|
22
25
|
export const numberFields = [
|
|
23
26
|
"expectedRevision",
|
|
@@ -32,6 +35,8 @@ export const numberFields = [
|
|
|
32
35
|
"sourceGeneration",
|
|
33
36
|
"capacity",
|
|
34
37
|
"slot",
|
|
38
|
+
"maximumWaitSeconds",
|
|
39
|
+
"pollEverySeconds",
|
|
35
40
|
];
|
|
36
41
|
export const textFields = [
|
|
37
42
|
"parentRunId",
|
|
@@ -72,6 +77,8 @@ export const textFields = [
|
|
|
72
77
|
"issueUpdate",
|
|
73
78
|
"result",
|
|
74
79
|
"actor",
|
|
80
|
+
"waitName",
|
|
81
|
+
"commandOutput",
|
|
75
82
|
];
|
|
76
83
|
export const terminal = [
|
|
77
84
|
"completed",
|
|
@@ -33,6 +33,7 @@ export interface CompletionCursor {
|
|
|
33
33
|
readonly terminal?: boolean;
|
|
34
34
|
}
|
|
35
35
|
export interface RunRecord extends RunState {
|
|
36
|
+
readonly admissionCommandId: string | null;
|
|
36
37
|
readonly sequence: number;
|
|
37
38
|
}
|
|
38
39
|
export interface AuthorityQueries {
|
|
@@ -43,7 +44,7 @@ export interface AuthorityQueries {
|
|
|
43
44
|
readonly eventsAfter: (cursor: EventCursor) => Promise<EventPage>;
|
|
44
45
|
readonly latestCompletion: (cursor: CompletionCursor) => Promise<PublishedEvent | undefined>;
|
|
45
46
|
readonly sequences: () => Promise<Sequences>;
|
|
46
|
-
readonly workflowIds: () => Promise<Readonly<Record<string, string>>>;
|
|
47
|
+
readonly workflowIds: (runIds?: readonly string[]) => Promise<Readonly<Record<string, string>>>;
|
|
47
48
|
readonly runOrigins: () => Promise<RunOrigins>;
|
|
48
49
|
readonly runLinks: () => Promise<Readonly<Record<string, RunLinks>>>;
|
|
49
50
|
}
|
|
@@ -6,11 +6,15 @@ import { storedEvents, storedRun } from "../authority-restore.js";
|
|
|
6
6
|
import { documentDigest } from "../decision-restore.js";
|
|
7
7
|
import { runLinks, } from "../../authority/handoff-chain.js";
|
|
8
8
|
async function run(connection, runId) {
|
|
9
|
-
const row = await connection.get("SELECT run_id, status, revision, workflow, paused_from, gates, sequence FROM runs WHERE run_id = ?", [runId]);
|
|
9
|
+
const row = await connection.get("SELECT r.run_id, r.status, r.revision, r.workflow, r.paused_from, r.gates, r.sequence, c.command_id AS admission_command_id FROM runs r LEFT JOIN events c ON c.run_id = r.run_id AND c.type = 'run.created' WHERE r.run_id = ? ORDER BY c.sequence LIMIT 1", [runId]);
|
|
10
10
|
if (row === undefined)
|
|
11
11
|
return undefined;
|
|
12
12
|
const record = runRow(row);
|
|
13
|
-
return {
|
|
13
|
+
return {
|
|
14
|
+
...storedRun(record),
|
|
15
|
+
sequence: record.sequence,
|
|
16
|
+
admissionCommandId: optionalText(row, "admission_command_id"),
|
|
17
|
+
};
|
|
14
18
|
}
|
|
15
19
|
async function runOrigins(connection, cursor) {
|
|
16
20
|
const rows = await connection.all("SELECT run_id, json_extract(payload, '$.parentRunId') AS parent_run_id, coalesce(json_extract(payload, '$.chainId'), run_id) AS chain_id FROM events WHERE type = 'run.created' AND sequence > ? AND sequence <= ? ORDER BY sequence", [cursor.after, cursor.through]);
|
|
@@ -84,8 +88,13 @@ async function sequences(connection) {
|
|
|
84
88
|
times: Object.fromEntries(rows.map((row) => [text(row, "run_id"), text(row, "recorded_at")])),
|
|
85
89
|
};
|
|
86
90
|
}
|
|
87
|
-
async function workflowIds(connection) {
|
|
88
|
-
|
|
91
|
+
async function workflowIds(connection, runIds) {
|
|
92
|
+
if (runIds?.length === 0)
|
|
93
|
+
return {};
|
|
94
|
+
const scoped = runIds === undefined
|
|
95
|
+
? ""
|
|
96
|
+
: ` AND d.run_id IN (${runIds.map(() => "?").join(", ")})`;
|
|
97
|
+
const rows = await connection.all(`SELECT d.run_id, json_extract(s.body, '$.workflowId') AS workflow_id FROM run_details d JOIN documents s ON s.digest = d.submission WHERE json_valid(s.body) AND json_type(s.body, '$.workflowId') = 'text'${scoped}`, runIds);
|
|
89
98
|
return Object.fromEntries(rows.map((row) => [text(row, "run_id"), text(row, "workflow_id")]));
|
|
90
99
|
}
|
|
91
100
|
function cachedOrigins(read) {
|
|
@@ -142,7 +151,7 @@ export function authorityQueries(read) {
|
|
|
142
151
|
eventsAfter: (cursor) => read((connection) => eventsAfter(connection, cursor)),
|
|
143
152
|
latestCompletion: (cursor) => read((connection) => latestCompletion(connection, cursor)),
|
|
144
153
|
sequences: () => read(sequences),
|
|
145
|
-
workflowIds: () => read(workflowIds),
|
|
154
|
+
workflowIds: (runIds) => read((connection) => workflowIds(connection, runIds)),
|
|
146
155
|
runOrigins: origins,
|
|
147
156
|
runLinks: currentLinks,
|
|
148
157
|
};
|
|
@@ -24,7 +24,7 @@ export function oversized(request) {
|
|
|
24
24
|
command["kind"] === "report-effect" &&
|
|
25
25
|
command["worker"] === "command";
|
|
26
26
|
const limit = report
|
|
27
|
-
? maximumRequestBytes + commandLimits.stdoutBytes *
|
|
27
|
+
? maximumRequestBytes + commandLimits.stdoutBytes * 12
|
|
28
28
|
: maximumRequestBytes;
|
|
29
29
|
return Buffer.byteLength(JSON.stringify(request)) > limit;
|
|
30
30
|
}
|
|
@@ -52,8 +52,8 @@ export function librarySettings(timing, log) {
|
|
|
52
52
|
tableNamePrefix: "solid_",
|
|
53
53
|
maxAttempts: 1,
|
|
54
54
|
maxActivationDurationMilliseconds: 50,
|
|
55
|
-
maxPayloadBytes: 900_000 + commandLimits.stdoutBytes *
|
|
56
|
-
maxResultBytes: 900_000 + commandLimits.stdoutBytes *
|
|
55
|
+
maxPayloadBytes: 900_000 + commandLimits.stdoutBytes * 12,
|
|
56
|
+
maxResultBytes: 900_000 + commandLimits.stdoutBytes * 12,
|
|
57
57
|
logger: lineLogger(log ?? standardError),
|
|
58
58
|
leaseDurationMilliseconds: timing.leaseMilliseconds,
|
|
59
59
|
leaseRenewalIntervalMilliseconds: timing.renewalMilliseconds,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { upgradeCommandWaits, upgradeCommandWaitChecks } from "../command-wait-restore.ts";
|
|
2
|
+
import { loadDecided, loadEffected, loadWaiting, loadCurrent } from "../../storage/decision-snapshots.ts";
|
|
2
3
|
import { loadSnapshot } from "../../storage/domain-rows.ts";
|
|
3
4
|
import { upgradeDecisions } from "../decision-upgrade.ts";
|
|
4
|
-
import { upgradeEffects } from "../effect-upgrade.ts";
|
|
5
|
+
import { upgradeEffects, upgradeEventIndexes, upgradeSpendingIndexes } from "../effect-upgrade.ts";
|
|
5
6
|
declare const upgrades: readonly [{
|
|
6
7
|
readonly from: "adopted";
|
|
7
8
|
readonly load: typeof loadSnapshot;
|
|
@@ -10,6 +11,22 @@ declare const upgrades: readonly [{
|
|
|
10
11
|
readonly from: "decided";
|
|
11
12
|
readonly load: typeof loadDecided;
|
|
12
13
|
readonly apply: typeof upgradeEffects;
|
|
14
|
+
}, {
|
|
15
|
+
readonly from: "effected";
|
|
16
|
+
readonly load: typeof loadEffected;
|
|
17
|
+
readonly apply: typeof upgradeCommandWaits;
|
|
18
|
+
}, {
|
|
19
|
+
readonly from: "waiting";
|
|
20
|
+
readonly load: typeof loadWaiting;
|
|
21
|
+
readonly apply: typeof upgradeCommandWaitChecks;
|
|
22
|
+
}, {
|
|
23
|
+
readonly from: "checked";
|
|
24
|
+
readonly load: typeof loadCurrent;
|
|
25
|
+
readonly apply: typeof upgradeSpendingIndexes;
|
|
26
|
+
}, {
|
|
27
|
+
readonly from: "indexed";
|
|
28
|
+
readonly load: typeof loadCurrent;
|
|
29
|
+
readonly apply: typeof upgradeEventIndexes;
|
|
13
30
|
}];
|
|
14
31
|
export type UpgradeStep = (typeof upgrades)[number];
|
|
15
32
|
export declare function upgradeSteps(kind: string): readonly UpgradeStep[];
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { upgradeCommandWaits, upgradeCommandWaitChecks, } from "../command-wait-restore.js";
|
|
2
|
+
import { loadDecided, loadEffected, loadWaiting, loadCurrent, } from "../../storage/decision-snapshots.js";
|
|
2
3
|
import { loadSnapshot } from "../../storage/domain-rows.js";
|
|
3
4
|
import { upgradeDecisions } from "../decision-upgrade.js";
|
|
4
|
-
import { upgradeEffects } from "../effect-upgrade.js";
|
|
5
|
+
import { upgradeEffects, upgradeEventIndexes, upgradeSpendingIndexes, } from "../effect-upgrade.js";
|
|
5
6
|
const upgrades = [
|
|
6
7
|
{ from: "adopted", load: loadSnapshot, apply: upgradeDecisions },
|
|
7
8
|
{ from: "decided", load: loadDecided, apply: upgradeEffects },
|
|
9
|
+
{ from: "effected", load: loadEffected, apply: upgradeCommandWaits },
|
|
10
|
+
{ from: "waiting", load: loadWaiting, apply: upgradeCommandWaitChecks },
|
|
11
|
+
{ from: "checked", load: loadCurrent, apply: upgradeSpendingIndexes },
|
|
12
|
+
{ from: "indexed", load: loadCurrent, apply: upgradeEventIndexes },
|
|
8
13
|
];
|
|
9
14
|
export function upgradeSteps(kind) {
|
|
10
15
|
const first = upgrades.findIndex((step) => step.from === kind);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { commandWaitDeadline } from "../command-wait-restore.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { delivers, isSettled } from "../../authority/gates.js";
|
|
3
4
|
import { eligibleIntents, } from "../../authority/reducer.js";
|
|
@@ -26,6 +27,7 @@ export function protectedIntent(state, attempt) {
|
|
|
26
27
|
.filter((lease) => lease.resourceKey === operation.leaseKey)
|
|
27
28
|
.map((lease) => ({
|
|
28
29
|
...intent,
|
|
30
|
+
...commandWaitDeadline(state.commandWaits ?? {}, operation.operationId),
|
|
29
31
|
workflow,
|
|
30
32
|
purpose,
|
|
31
33
|
inputDigest: operation.inputDigest,
|
|
@@ -16,4 +16,4 @@ export interface Attempt {
|
|
|
16
16
|
readonly effectId: string;
|
|
17
17
|
}
|
|
18
18
|
export declare function deliverEffect(parts: EffectDelivery, attempt: Attempt): Promise<JsonObject>;
|
|
19
|
-
export declare function protectedArguments(value: JsonObject): EffectArguments
|
|
19
|
+
export declare function protectedArguments(value: JsonObject): EffectArguments & Pick<ProtectedIntent, "commandDeadline">;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dispatchCommandWait, readCommandWaitDeadline, } from "../command-wait-restore.js";
|
|
1
2
|
import { dispatchDecision, } from "../../authority/dispatch-decision.js";
|
|
2
3
|
import { integer, optionalInteger, optionalText, text, } from "../../storage/domain-rows.js";
|
|
3
4
|
import { budgetRow } from "../../storage/effect-rows.js";
|
|
@@ -16,11 +17,16 @@ const absent = {
|
|
|
16
17
|
budget: undefined,
|
|
17
18
|
};
|
|
18
19
|
async function dispatchRead(connection, attempt) {
|
|
19
|
-
const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
|
|
20
|
+
const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, p.method, p.target, p.payload, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
|
|
20
21
|
if (row === undefined)
|
|
21
22
|
return absent;
|
|
22
23
|
const workflow = text(row, "workflow");
|
|
23
24
|
return {
|
|
25
|
+
...(await dispatchCommandWait(connection, {
|
|
26
|
+
runId: attempt.intent.runId,
|
|
27
|
+
workflow,
|
|
28
|
+
operationId: attempt.intent.operationId,
|
|
29
|
+
})),
|
|
24
30
|
attempt: {
|
|
25
31
|
outcome: optionalText(row, "outcome"),
|
|
26
32
|
inputDigest: text(row, "input_digest"),
|
|
@@ -37,6 +43,9 @@ async function dispatchRead(connection, attempt) {
|
|
|
37
43
|
status: text(row, "operation_status"),
|
|
38
44
|
capability: text(row, "capability"),
|
|
39
45
|
units: integer(row, "units"),
|
|
46
|
+
method: text(row, "method"),
|
|
47
|
+
target: text(row, "target"),
|
|
48
|
+
payload: text(row, "payload"),
|
|
40
49
|
},
|
|
41
50
|
budget: storedBudget(budgetRow(row)),
|
|
42
51
|
lease: {
|
|
@@ -52,7 +61,8 @@ async function called(parts, call) {
|
|
|
52
61
|
const adapterCall = parts.delivery[name]?.bind(parts.delivery);
|
|
53
62
|
if (adapterCall === undefined)
|
|
54
63
|
return { kind: "unknown", reason: "stop-not-supported" };
|
|
55
|
-
|
|
64
|
+
const deadline = await parts.reader.connection((connection) => readCommandWaitDeadline(connection, intent));
|
|
65
|
+
return settlement(await parts.calls.call(intent.operationId, (signal) => adapterCall({ ...intent, ...deadline }, signal)), intent.capability === "command"
|
|
56
66
|
? commandLimits.resultBytes
|
|
57
67
|
: parts.effects.resultBytes);
|
|
58
68
|
}
|
|
@@ -126,5 +136,8 @@ export function protectedArguments(value) {
|
|
|
126
136
|
method: text(value, "method"),
|
|
127
137
|
target: text(value, "target"),
|
|
128
138
|
payload: text(value, "payload"),
|
|
139
|
+
...(typeof value["commandDeadline"] === "string"
|
|
140
|
+
? { commandDeadline: value["commandDeadline"] }
|
|
141
|
+
: {}),
|
|
129
142
|
};
|
|
130
143
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { operationPhase } from "../../operation-identity.js";
|
|
2
|
+
import { endedCommandWaitCheck } from "../../authority/command-waits.js";
|
|
1
3
|
import { isInstant } from "../../authority/instants.js";
|
|
2
4
|
import { promotions } from "../../authority/leases.js";
|
|
3
5
|
import { execute } from "../../authority/reducer.js";
|
|
@@ -45,7 +47,9 @@ function closure(state, operation) {
|
|
|
45
47
|
return ["run-ended"];
|
|
46
48
|
const exhausted = (state.effects.budgets[operation.runId]?.exhaustedSequence ?? null) !==
|
|
47
49
|
null;
|
|
48
|
-
return exhausted
|
|
50
|
+
return exhausted && operationPhase(operation.operationId) !== "command-wait"
|
|
51
|
+
? ["budget-exhausted"]
|
|
52
|
+
: [];
|
|
49
53
|
}
|
|
50
54
|
function unblocked(state, followUp) {
|
|
51
55
|
const steps = [];
|
|
@@ -95,6 +99,9 @@ const outcomes = {
|
|
|
95
99
|
}),
|
|
96
100
|
completed: (attempt) => stated({
|
|
97
101
|
outcome: "completed",
|
|
102
|
+
...(attempt.worker === "command"
|
|
103
|
+
? { commandOutput: attempt.result }
|
|
104
|
+
: {}),
|
|
98
105
|
result: attempt.result === null ? null : documentDigest(attempt.result),
|
|
99
106
|
reason: attempt.reason,
|
|
100
107
|
...identified(attempt),
|
|
@@ -155,7 +162,9 @@ function acceptedNow(reconciling) {
|
|
|
155
162
|
export function reconciliations(state, reconciling) {
|
|
156
163
|
const accepted = acceptedNow(reconciling);
|
|
157
164
|
const rejected = rejectedReports(reconciling.results);
|
|
158
|
-
const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" &&
|
|
165
|
+
const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" &&
|
|
166
|
+
!endedCommandWaitCheck(state.commandWaits ?? {}, operation.operationId) &&
|
|
167
|
+
live(operation);
|
|
159
168
|
const live = (operation) => (operation.status === "recovering" &&
|
|
160
169
|
!accepted.has(operation.operationId)) ||
|
|
161
170
|
(operation.status === "blocked" && rejected.has(operation.operationId));
|
|
@@ -8,6 +8,10 @@ export interface OperationView extends OperationRow {
|
|
|
8
8
|
}
|
|
9
9
|
export type StoredDisposition = Omit<Evidence, "sequence">;
|
|
10
10
|
export interface EffectQueries {
|
|
11
|
+
readonly workerTurns: (window: {
|
|
12
|
+
readonly after: string;
|
|
13
|
+
readonly through: string;
|
|
14
|
+
}) => Promise<readonly OperationView[]>;
|
|
11
15
|
readonly operation: (operationId: string) => Promise<OperationView | undefined>;
|
|
12
16
|
readonly operations: (runId: string) => Promise<readonly OperationView[]>;
|
|
13
17
|
readonly evidence: (runId: string) => Promise<readonly number[]>;
|
|
@@ -34,7 +34,9 @@ const viewColumns = operationColumns
|
|
|
34
34
|
.map((name) => `o.${name}`)
|
|
35
35
|
.join(", ");
|
|
36
36
|
const waitCause = "CASE WHEN o.status != 'waiting' THEN NULL WHEN r.status != 'running' THEN 'run-not-running' WHEN EXISTS (SELECT 1 FROM leases h WHERE h.resource_key = o.lease_key AND h.state != 'released') THEN 'resource' ELSE 'ready' END";
|
|
37
|
-
const
|
|
37
|
+
const viewSelection = `SELECT ${viewColumns}, l.generation AS lease_generation, ${waitCause} AS wait_cause`;
|
|
38
|
+
const viewJoins = "JOIN runs r ON r.run_id = o.run_id LEFT JOIN leases l ON l.resource_key = o.lease_key AND l.operation_id = o.operation_id AND l.state != 'released'";
|
|
39
|
+
const viewed = `${viewSelection} FROM operations o ${viewJoins}`;
|
|
38
40
|
function operationView(row) {
|
|
39
41
|
return {
|
|
40
42
|
...operationRow(row),
|
|
@@ -52,6 +54,11 @@ async function operations(connection, runId) {
|
|
|
52
54
|
const rows = await connection.all(`${viewed} WHERE o.run_id = ? ORDER BY o.requested_sequence`, [runId]);
|
|
53
55
|
return rows.map(operationView);
|
|
54
56
|
}
|
|
57
|
+
async function workerTurns(connection, window) {
|
|
58
|
+
const settled = await connection.all(`${viewSelection} FROM events e CROSS JOIN operations o ${viewJoins} WHERE o.settled_sequence = e.sequence AND o.capability = 'claude' AND julianday(e.recorded_at) > julianday(?) AND julianday(e.recorded_at) <= julianday(?)`, [window.after, window.through]);
|
|
59
|
+
const open = await connection.all(`${viewSelection} FROM operations o INDEXED BY operations_worker_open ${viewJoins} WHERE o.capability = 'claude' AND o.settled_sequence IS NULL AND o.status NOT IN ('refused', 'completed', 'failed', 'stopped', 'cancelled')`);
|
|
60
|
+
return [...settled, ...open].map(operationView);
|
|
61
|
+
}
|
|
55
62
|
async function evidence(connection, runId) {
|
|
56
63
|
const rows = await connection.all("SELECT e.sequence FROM effect_evidence e JOIN events v ON v.sequence = e.sequence WHERE e.run_id = ? AND (e.disposition IN ('rejected', 'denied', 'refused') OR (v.type = 'operation.reconciled' AND json_extract(v.payload, '$.outcome') = 'unknown')) ORDER BY e.sequence", [runId]);
|
|
57
64
|
return rows.map((row) => integer(row, "sequence"));
|
|
@@ -74,6 +81,7 @@ async function budget(connection, runId) {
|
|
|
74
81
|
}
|
|
75
82
|
export function effectQueries(read, settings) {
|
|
76
83
|
return {
|
|
84
|
+
workerTurns: (window) => read((connection) => workerTurns(connection, window)),
|
|
77
85
|
stops: (runId) => read((connection) => stops(connection, runId)),
|
|
78
86
|
closure: (runId) => read((connection) => storedClosure(connection, { runId, stopLimit: settings.stopLimit })),
|
|
79
87
|
settledAt: (runId) => read((connection) => settledAt(connection, runId)),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readCommandWaitDeadline } from "../command-wait-restore.js";
|
|
1
2
|
import { detailColumns, detailRow } from "../../storage/decision-rows.js";
|
|
2
3
|
import { integer, runRow, text, } from "../../storage/domain-rows.js";
|
|
3
4
|
import { storedRun } from "../authority-restore.js";
|
|
@@ -57,6 +58,7 @@ export async function pendingEffect(connection, attempt) {
|
|
|
57
58
|
return {
|
|
58
59
|
...intent,
|
|
59
60
|
purpose,
|
|
61
|
+
...(await readCommandWaitDeadline(connection, intent)),
|
|
60
62
|
inputDigest: text(row, "input_digest"),
|
|
61
63
|
leaseGeneration: integer(row, "generation"),
|
|
62
64
|
capability: text(row, "capability"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { endedCommandWaitCheck } from "../../authority/command-waits.js";
|
|
1
2
|
import { stopAttempts, } from "../../authority/stop-sequence.js";
|
|
2
3
|
import { observingIntent, protectedIntent, } from "./delivery-intents.js";
|
|
3
4
|
function present(state, planning) {
|
|
@@ -33,9 +34,14 @@ export function presentSubjects(state, planning) {
|
|
|
33
34
|
}
|
|
34
35
|
export function stopIntents(state, planning) {
|
|
35
36
|
const { runId, stopping } = planning;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const cancelled = state.runs[runId]?.status === "cancelled";
|
|
38
|
+
const subjects = presentSubjects(state, planning).flatMap((subject) => {
|
|
39
|
+
if (endedCommandWaitCheck(state.commandWaits ?? {}, subject.operationId))
|
|
40
|
+
return [
|
|
41
|
+
{ ...subject, stopSequence: subject.stopSequence ?? state.sequence },
|
|
42
|
+
];
|
|
43
|
+
return cancelled ? [subject] : [];
|
|
44
|
+
});
|
|
39
45
|
return stopAttempts(subjects, {
|
|
40
46
|
cancelledSequence: planning.cancelledNow[0] ?? stopping.cancelledSequence ?? 0,
|
|
41
47
|
stopLimit: planning.stopLimit,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { StopSubject } from "../../authority/stop-sequence.ts";
|
|
2
|
+
import type { CommandWaitsState } from "../../authority/command-waits.ts";
|
|
2
3
|
import { type SqlConnection } from "../../storage/domain-rows.ts";
|
|
3
4
|
export interface Stopping {
|
|
4
5
|
readonly subjects: readonly StopSubject[];
|
|
@@ -10,6 +11,7 @@ export declare function turnStopping(connection: SqlConnection, scope: {
|
|
|
10
11
|
readonly runId: string;
|
|
11
12
|
readonly status: string | undefined;
|
|
12
13
|
readonly kind: string;
|
|
14
|
+
readonly commandWaits?: CommandWaitsState;
|
|
13
15
|
}): Promise<Stopping>;
|
|
14
16
|
export declare function droppedRuns(connection: SqlConnection, rule: {
|
|
15
17
|
readonly limit: number;
|