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
|
@@ -9,8 +9,9 @@ export declare function knownMerge(operation: Operation, expected: ReviewedPull
|
|
|
9
9
|
readonly updated: string;
|
|
10
10
|
}): Promise<{
|
|
11
11
|
readonly head: string;
|
|
12
|
+
readonly open: boolean;
|
|
12
13
|
readonly merged: string | undefined;
|
|
13
14
|
}>;
|
|
14
15
|
export declare function mergePull(operation: Operation, pull: ReviewedPull & {
|
|
15
16
|
readonly updated: string;
|
|
16
|
-
}): Promise<string>;
|
|
17
|
+
}): Promise<string | Error>;
|
|
@@ -15,11 +15,12 @@ export async function knownMerge(operation, expected) {
|
|
|
15
15
|
`${repositoryPath}/pulls/${String(expected.number)}`,
|
|
16
16
|
]));
|
|
17
17
|
const head = commitOf(field(pull, "head"), "sha");
|
|
18
|
+
const open = field(pull, "state") === "open";
|
|
18
19
|
if (field(pull, "merged") !== true)
|
|
19
|
-
return { head, merged: undefined };
|
|
20
|
+
return { head, open, merged: undefined };
|
|
20
21
|
if (head !== expected.commit && head !== expected.updated)
|
|
21
22
|
throw new Error("merged-other-commit");
|
|
22
|
-
return { head, merged: commitOf(pull, "merge_commit_sha") };
|
|
23
|
+
return { head, open, merged: commitOf(pull, "merge_commit_sha") };
|
|
23
24
|
}
|
|
24
25
|
async function mergedNow(operation, pull) {
|
|
25
26
|
const reply = JSON.parse(await operation.calls.gh([
|
|
@@ -63,11 +64,17 @@ export function mergePull(operation, pull) {
|
|
|
63
64
|
},
|
|
64
65
|
statuses: pull.updated === pull.commit ? [] : [405, 409],
|
|
65
66
|
}).catch(async (error) => {
|
|
66
|
-
if (!(error instanceof Error)
|
|
67
|
+
if (!(error instanceof Error))
|
|
68
|
+
throw error;
|
|
69
|
+
const refused = error.message === "github-call-failed" &&
|
|
70
|
+
[405, 409].includes(Number(field(error, "status")));
|
|
71
|
+
if (error.message !== "github-network-failed" && !refused)
|
|
67
72
|
throw error;
|
|
68
73
|
const known = await knownMerge(operation, pull);
|
|
69
74
|
if (known.merged !== undefined)
|
|
70
75
|
return known.merged;
|
|
76
|
+
if (refused && known.open)
|
|
77
|
+
return error;
|
|
71
78
|
throw error;
|
|
72
79
|
});
|
|
73
80
|
}
|
|
@@ -136,35 +136,64 @@ async function readyHead(operation, pull) {
|
|
|
136
136
|
let recorded = pull.recorded;
|
|
137
137
|
let remote = pull.remote;
|
|
138
138
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
139
|
-
const updated = await
|
|
139
|
+
const updated = await pushedHead(operation, {
|
|
140
|
+
...pull,
|
|
140
141
|
tree,
|
|
141
|
-
commit: pull.commit,
|
|
142
142
|
recorded,
|
|
143
|
-
|
|
143
|
+
remote,
|
|
144
144
|
});
|
|
145
|
-
if (updated !== pull.commit && recorded !== updated)
|
|
146
|
-
await writeRecord(operation.folder, {
|
|
147
|
-
name: "updated-head.json",
|
|
148
|
-
value: { commit: pull.commit, updated },
|
|
149
|
-
});
|
|
150
|
-
if (updated !== pull.commit && remote !== updated)
|
|
151
|
-
await operation.calls.git(tree.path, [
|
|
152
|
-
"push",
|
|
153
|
-
"--quiet",
|
|
154
|
-
"origin",
|
|
155
|
-
`${updated}:refs/heads/${tree.branch}`,
|
|
156
|
-
]);
|
|
157
145
|
const ci = await waitForCi(operation, updated);
|
|
158
146
|
if (ci !== undefined)
|
|
159
147
|
return ci;
|
|
160
|
-
const newest = await fetched(operation, await defaultBranch(operation));
|
|
161
|
-
if ((await operation.calls.git(tree.path, ["merge-base", updated, newest])).trim() === newest)
|
|
162
|
-
return updated;
|
|
163
148
|
recorded = updated;
|
|
164
149
|
remote = updated;
|
|
150
|
+
if (!(await containsBase(operation, updated)))
|
|
151
|
+
continue;
|
|
152
|
+
const merged = await mergePull(operation, { ...pull, updated });
|
|
153
|
+
if (typeof merged === "string")
|
|
154
|
+
return { updated, merged };
|
|
155
|
+
if (await containsBase(operation, updated))
|
|
156
|
+
throw merged;
|
|
157
|
+
await recordRefusal(operation, { error: merged, updated, attempt });
|
|
165
158
|
}
|
|
166
159
|
throw new Error("base-moved");
|
|
167
160
|
}
|
|
161
|
+
async function recordRefusal(operation, refusal) {
|
|
162
|
+
const observation = await operation.observe?.({
|
|
163
|
+
condition: "working",
|
|
164
|
+
reason: "github-merge-refused",
|
|
165
|
+
evidence: `github-merge/HTTP-${String(field(refusal.error, "status"))}/head-${refusal.updated}/merge-main`,
|
|
166
|
+
attempt: refusal.attempt + 1,
|
|
167
|
+
limit: 3,
|
|
168
|
+
});
|
|
169
|
+
if (observation !== undefined &&
|
|
170
|
+
!["accepted", "duplicate"].includes(observation.kind))
|
|
171
|
+
throw new Error("github-call-failed");
|
|
172
|
+
}
|
|
173
|
+
async function pushedHead(operation, pull) {
|
|
174
|
+
const updated = await refreshed(operation, pull);
|
|
175
|
+
if (updated !== pull.commit && pull.recorded !== updated)
|
|
176
|
+
await writeRecord(operation.folder, {
|
|
177
|
+
name: "updated-head.json",
|
|
178
|
+
value: { commit: pull.commit, updated },
|
|
179
|
+
});
|
|
180
|
+
if (updated !== pull.commit && pull.remote !== updated)
|
|
181
|
+
await operation.calls.git(pull.tree.path, [
|
|
182
|
+
"push",
|
|
183
|
+
"--quiet",
|
|
184
|
+
"origin",
|
|
185
|
+
`${updated}:refs/heads/${pull.tree.branch}`,
|
|
186
|
+
]);
|
|
187
|
+
return updated;
|
|
188
|
+
}
|
|
189
|
+
async function containsBase(operation, updated) {
|
|
190
|
+
const newest = await fetched(operation, await defaultBranch(operation));
|
|
191
|
+
return ((await operation.calls.git(existingTree(operation).path, [
|
|
192
|
+
"merge-base",
|
|
193
|
+
updated,
|
|
194
|
+
newest,
|
|
195
|
+
])).trim() === newest);
|
|
196
|
+
}
|
|
168
197
|
function checkOutput(cause) {
|
|
169
198
|
return commandOutput(cause).slice(-6_000);
|
|
170
199
|
}
|
|
@@ -209,12 +238,11 @@ async function completedMerge(operation, pull) {
|
|
|
209
238
|
...pull,
|
|
210
239
|
updated: recorded ?? pull.commit,
|
|
211
240
|
});
|
|
212
|
-
const
|
|
241
|
+
const result = known.merged === undefined
|
|
213
242
|
? await readyHead(operation, { ...pull, recorded, remote: known.head })
|
|
214
|
-
:
|
|
215
|
-
if (
|
|
216
|
-
return
|
|
217
|
-
const merged = known.merged ?? (await mergePull(operation, { ...pull, updated }));
|
|
243
|
+
: { updated: recorded ?? pull.commit, merged: known.merged };
|
|
244
|
+
if ("reason" in result)
|
|
245
|
+
return result;
|
|
218
246
|
await removed(operation, place);
|
|
219
|
-
return { number: pull.number, commit: pull.commit,
|
|
247
|
+
return { number: pull.number, commit: pull.commit, ...result };
|
|
220
248
|
}
|
|
@@ -2,15 +2,20 @@ import { setTimeout as delay } from "node:timers/promises";
|
|
|
2
2
|
import { appendFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { findingsOf, scoreOf, } from "./github-calls.js";
|
|
5
|
+
import { attachAsset } from "./github-attach.js";
|
|
5
6
|
import { closeIssue, partialIssue } from "./github-ticket-status.js";
|
|
6
7
|
import { merge } from "./github-merge.js";
|
|
7
|
-
import { createIssue, discard } from "./github-issue-methods.js";
|
|
8
|
+
import { captureDraft, createIssue, discard, repositoryName, } from "./github-issue-methods.js";
|
|
8
9
|
import { existingTree, defaultBranch, changeChecked, field, githubTiming, repositoryPath, text, } from "./github-operation.js";
|
|
9
10
|
import { workTree } from "./work-tree.js";
|
|
10
11
|
const triggerText = "@greptileai";
|
|
11
12
|
const maximumReviewRequests = 3;
|
|
12
13
|
export const methodReasons = new Set([
|
|
14
|
+
"attachment-not-available",
|
|
15
|
+
"attachment-too-large",
|
|
13
16
|
"draft-not-available",
|
|
17
|
+
"draft-changed",
|
|
18
|
+
"draft-too-large",
|
|
14
19
|
"invalid-draft",
|
|
15
20
|
"post-uncertain",
|
|
16
21
|
"private-texts-not-set",
|
|
@@ -77,7 +82,10 @@ function labels(operation, name) {
|
|
|
77
82
|
});
|
|
78
83
|
}
|
|
79
84
|
async function label(operation) {
|
|
80
|
-
const repository =
|
|
85
|
+
const repository = !Object.hasOwn(operation.payload, "owner") &&
|
|
86
|
+
!Object.hasOwn(operation.payload, "repository")
|
|
87
|
+
? repositoryName(await operation.calls.gh(["repo", "view", "--json", "nameWithOwner"]))
|
|
88
|
+
: `${text(operation, "owner")}/${text(operation, "repository")}`;
|
|
81
89
|
const number = integer(operation, "number");
|
|
82
90
|
if (!/^[\w.-]+\/[\w.-]+$/.test(repository) || !Number.isSafeInteger(number))
|
|
83
91
|
throw new Error("invalid-payload");
|
|
@@ -262,8 +270,10 @@ export const methods = new Map([
|
|
|
262
270
|
["partial-issue", partialIssue],
|
|
263
271
|
["label", label],
|
|
264
272
|
["create-issue", createIssue],
|
|
273
|
+
["capture-draft", captureDraft],
|
|
265
274
|
["discard", discard],
|
|
266
275
|
["open-pr", openPull],
|
|
276
|
+
["attach-asset", attachAsset],
|
|
267
277
|
["wait-review", waitReview],
|
|
268
278
|
[
|
|
269
279
|
"merge",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CallSettings, Calls } from "./github-calls.ts";
|
|
2
|
+
import type { ObservationReport } from "../service/worker-port.ts";
|
|
2
3
|
export interface GithubTiming {
|
|
3
4
|
readonly pollMilliseconds: number;
|
|
4
5
|
readonly triggerMilliseconds: number;
|
|
@@ -20,6 +21,9 @@ export interface Operation {
|
|
|
20
21
|
readonly payload: Readonly<Record<string, unknown>>;
|
|
21
22
|
readonly signal: AbortSignal;
|
|
22
23
|
readonly folder: string;
|
|
24
|
+
readonly observe?: (report: Pick<ObservationReport, "condition" | "reason" | "evidence" | "attempt" | "limit">) => Promise<{
|
|
25
|
+
readonly kind: string;
|
|
26
|
+
} | undefined>;
|
|
23
27
|
}
|
|
24
28
|
export interface Place {
|
|
25
29
|
readonly path: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { rm } from "node:fs/promises";
|
|
5
|
+
import { attachmentFolder } from "./attachments.js";
|
|
4
6
|
import { treePlace } from "./work-tree.js";
|
|
5
7
|
export const githubTiming = {
|
|
6
8
|
pollMilliseconds: 30_000,
|
|
@@ -32,6 +34,10 @@ export async function removeWorktree(operation, place) {
|
|
|
32
34
|
await repository(["worktree", "remove", "--force", place.path]);
|
|
33
35
|
if ((await repository(["branch", "--list", place.branch])).trim() !== "")
|
|
34
36
|
await repository(["branch", "-D", place.branch]);
|
|
37
|
+
await rm(attachmentFolder({
|
|
38
|
+
worktrees: operation.settings.worktrees,
|
|
39
|
+
target: operation.target,
|
|
40
|
+
}), { recursive: true, force: true });
|
|
35
41
|
}
|
|
36
42
|
export async function defaultBranch(operation) {
|
|
37
43
|
const reference = await operation.calls.git(operation.settings.repository, [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Delivery } from "../broker/actor/delivery-intents.ts";
|
|
2
|
+
import type { ObservationReport } from "../service/worker-port.ts";
|
|
2
3
|
import { type MethodSettings } from "./github-methods.ts";
|
|
3
4
|
import { type WorkerReport } from "./operation-journal.ts";
|
|
4
5
|
export type { GithubTiming } from "./github-methods.ts";
|
|
@@ -6,6 +7,9 @@ export interface GithubWorkerSettings extends MethodSettings {
|
|
|
6
7
|
readonly journal: string;
|
|
7
8
|
readonly document: (digest: string) => Promise<string | undefined>;
|
|
8
9
|
readonly report: (report: WorkerReport) => Promise<unknown>;
|
|
10
|
+
readonly observe?: (report: ObservationReport) => Promise<{
|
|
11
|
+
readonly kind: string;
|
|
12
|
+
}>;
|
|
9
13
|
readonly operationStatus: (operationId: string) => Promise<string | undefined>;
|
|
10
14
|
readonly runStatus: (runId: string) => Promise<string | undefined>;
|
|
11
15
|
}
|
|
@@ -47,6 +47,12 @@ async function outcome(parts, run) {
|
|
|
47
47
|
target: intent.target,
|
|
48
48
|
payload,
|
|
49
49
|
signal,
|
|
50
|
+
observe: async (observation) => settings.observe?.({
|
|
51
|
+
...observation,
|
|
52
|
+
runId: intent.runId,
|
|
53
|
+
operationId: intent.operationId,
|
|
54
|
+
commandId: `github:${run.key}:merge-refused:${String(observation.attempt)}`,
|
|
55
|
+
}),
|
|
50
56
|
});
|
|
51
57
|
return {
|
|
52
58
|
outcome: "completed",
|
|
@@ -4,7 +4,7 @@ interface QueueSettings {
|
|
|
4
4
|
readonly intervalMilliseconds: number;
|
|
5
5
|
readonly lanes?: number;
|
|
6
6
|
readonly resetQueue?: boolean;
|
|
7
|
-
readonly workflowId
|
|
7
|
+
readonly workflowId: string;
|
|
8
8
|
}
|
|
9
9
|
export declare function issueQueue(settings: QueueSettings): {
|
|
10
10
|
readonly stop: () => Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { queueStatus, spendNotice } from "./queue-status.js";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -155,7 +155,7 @@ async function submit(settings, pending) {
|
|
|
155
155
|
const reply = await send(settings.runtimeDirectory, {
|
|
156
156
|
operation: "run",
|
|
157
157
|
parameters: {
|
|
158
|
-
workflowId: settings.workflowId
|
|
158
|
+
workflowId: settings.workflowId,
|
|
159
159
|
source: "ticket",
|
|
160
160
|
submission: { ticket: "next" },
|
|
161
161
|
commandId,
|
|
@@ -178,6 +178,7 @@ async function submit(settings, pending) {
|
|
|
178
178
|
"workflow-active",
|
|
179
179
|
"ticket-active",
|
|
180
180
|
"ticket-dependency-open",
|
|
181
|
+
"queue-spend-limit",
|
|
181
182
|
].includes(reply.error.code))
|
|
182
183
|
throw new Error(reply.error.code);
|
|
183
184
|
pending.commands.delete(commandId);
|
|
@@ -242,7 +243,13 @@ async function cycle(settings, signal) {
|
|
|
242
243
|
pending.failures.length = 0;
|
|
243
244
|
await pending.save();
|
|
244
245
|
}
|
|
245
|
-
const
|
|
246
|
+
const update = updateHold(settings.directory, pending);
|
|
247
|
+
const notice = spendNotice();
|
|
248
|
+
const holding = async (activeRuns = 0) => {
|
|
249
|
+
const updating = await update(activeRuns);
|
|
250
|
+
const spend = notice(await queueStatus(settings));
|
|
251
|
+
return updating || spend;
|
|
252
|
+
};
|
|
246
253
|
await rm(join(settings.directory, "queue-submission"), { force: true });
|
|
247
254
|
await recover(settings, pending);
|
|
248
255
|
const stopped = () => signal.aborted;
|
|
@@ -252,15 +259,13 @@ async function cycle(settings, signal) {
|
|
|
252
259
|
return;
|
|
253
260
|
const pendingRuns = await completed(settings, pending);
|
|
254
261
|
const lanes = settings.lanes ?? 1;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const held = await holding(activeRuns);
|
|
261
|
-
if (activeRuns >= lanes || activeRuns < pendingRuns)
|
|
262
|
+
const status = await queueStatus(settings);
|
|
263
|
+
const spend = notice(status);
|
|
264
|
+
const updating = await update(status.busy);
|
|
265
|
+
if (Math.max(pendingRuns, status.busy) >= lanes ||
|
|
266
|
+
status.busy < pendingRuns)
|
|
262
267
|
continue;
|
|
263
|
-
if (
|
|
268
|
+
if (updating || spend)
|
|
264
269
|
continue;
|
|
265
270
|
if (stopped())
|
|
266
271
|
return;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type NotifyEvent } from "./notify-message.ts";
|
|
2
|
+
export type OutcomeCache = Map<string, {
|
|
3
|
+
readonly latestSequence: number;
|
|
4
|
+
readonly event: NotifyEvent | undefined;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function notificationEvents(runtimeDirectory: string, cache: OutcomeCache): Promise<readonly NotifyEvent[]>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { send } from "../cli/client.js";
|
|
2
|
+
import { record } from "../protocol.js";
|
|
3
|
+
import { decisionNotification, outcomeNotification, scheduleStopNotifications, } from "./notify-message.js";
|
|
4
|
+
async function request(runtimeDirectory, request) {
|
|
5
|
+
const reply = await send(runtimeDirectory, request);
|
|
6
|
+
if (reply.kind === "error")
|
|
7
|
+
throw new Error(reply.error.code);
|
|
8
|
+
return reply.result;
|
|
9
|
+
}
|
|
10
|
+
function rows(value) {
|
|
11
|
+
if (!Array.isArray(value))
|
|
12
|
+
throw new Error("invalid-notify-list");
|
|
13
|
+
return value.map((item) => {
|
|
14
|
+
const row = record(item);
|
|
15
|
+
if (row === undefined)
|
|
16
|
+
throw new Error("invalid-notify-row");
|
|
17
|
+
return row;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async function scheduleNotifications(runtimeDirectory) {
|
|
21
|
+
const reply = await send(runtimeDirectory, {
|
|
22
|
+
operation: "schedule",
|
|
23
|
+
parameters: { action: "list" },
|
|
24
|
+
});
|
|
25
|
+
if (reply.kind !== "error")
|
|
26
|
+
return rows(reply.result["stops"]).flatMap(scheduleStopNotifications);
|
|
27
|
+
if (reply.error.code === "schedules-unavailable")
|
|
28
|
+
return [];
|
|
29
|
+
throw new Error(reply.error.code);
|
|
30
|
+
}
|
|
31
|
+
async function observedOutcome(summary, source) {
|
|
32
|
+
const { runtimeDirectory, cache } = source;
|
|
33
|
+
const latestSequence = summary["latestSequence"];
|
|
34
|
+
if (typeof latestSequence !== "number")
|
|
35
|
+
throw new Error("invalid-notify-sequence");
|
|
36
|
+
const runId = String(summary["runId"]);
|
|
37
|
+
const previous = cache.get(runId);
|
|
38
|
+
if (previous !== undefined && previous.latestSequence === latestSequence)
|
|
39
|
+
return previous.event;
|
|
40
|
+
const status = await request(runtimeDirectory, {
|
|
41
|
+
operation: "status",
|
|
42
|
+
parameters: { runId },
|
|
43
|
+
});
|
|
44
|
+
const run = record(status["run"]);
|
|
45
|
+
if (run === undefined)
|
|
46
|
+
throw new Error("invalid-notify-status");
|
|
47
|
+
const event = outcomeNotification(run);
|
|
48
|
+
cache.set(runId, { latestSequence, event });
|
|
49
|
+
return event;
|
|
50
|
+
}
|
|
51
|
+
export async function notificationEvents(runtimeDirectory, cache) {
|
|
52
|
+
const found = [];
|
|
53
|
+
const runs = new Map();
|
|
54
|
+
let after = "";
|
|
55
|
+
do {
|
|
56
|
+
const page = await request(runtimeDirectory, {
|
|
57
|
+
operation: "status",
|
|
58
|
+
parameters: { after, limit: 500 },
|
|
59
|
+
});
|
|
60
|
+
for (const summary of rows(page["runs"])) {
|
|
61
|
+
runs.set(String(summary["runId"]), summary);
|
|
62
|
+
const outcome = await observedOutcome(summary, {
|
|
63
|
+
runtimeDirectory,
|
|
64
|
+
cache,
|
|
65
|
+
});
|
|
66
|
+
if (outcome !== undefined)
|
|
67
|
+
found.push(outcome);
|
|
68
|
+
}
|
|
69
|
+
const next = page["next"];
|
|
70
|
+
if (next !== null && (typeof next !== "string" || next <= after))
|
|
71
|
+
throw new Error("invalid-notify-page");
|
|
72
|
+
after = next;
|
|
73
|
+
} while (after !== null);
|
|
74
|
+
const questions = await request(runtimeDirectory, {
|
|
75
|
+
operation: "questions",
|
|
76
|
+
parameters: {},
|
|
77
|
+
});
|
|
78
|
+
for (const decision of rows(questions["decisions"])) {
|
|
79
|
+
const run = runs.get(String(decision["runId"]));
|
|
80
|
+
if (run !== undefined)
|
|
81
|
+
found.push(decisionNotification(run, decision));
|
|
82
|
+
}
|
|
83
|
+
return [...found, ...(await scheduleNotifications(runtimeDirectory))];
|
|
84
|
+
}
|
|
@@ -46,7 +46,7 @@ function notification(value) {
|
|
|
46
46
|
const message = record(value);
|
|
47
47
|
if (message === undefined)
|
|
48
48
|
return false;
|
|
49
|
-
return (["decision", "blocked", "failed"].includes(String(message["event"])) &&
|
|
49
|
+
return (["decision", "blocked", "failed", "schedule-stopped"].includes(String(message["event"])) &&
|
|
50
50
|
["event", "runId", "workflowId", "subject", "body"].every((field) => typeof message[field] === "string"));
|
|
51
51
|
}
|
|
52
52
|
function deliveryState(value) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type Fields } from "../protocol.ts";
|
|
2
2
|
export interface Notification {
|
|
3
|
-
readonly event: "decision" | "blocked" | "failed";
|
|
3
|
+
readonly event: "decision" | "blocked" | "failed" | "schedule-stopped";
|
|
4
4
|
readonly runId: string;
|
|
5
5
|
readonly workflowId: string;
|
|
6
6
|
readonly subject: string;
|
|
7
7
|
readonly body: string;
|
|
8
|
+
readonly failedRunIds?: readonly string[];
|
|
8
9
|
}
|
|
9
10
|
export interface NotifyEvent {
|
|
10
11
|
readonly key: string;
|
|
@@ -12,3 +13,5 @@ export interface NotifyEvent {
|
|
|
12
13
|
}
|
|
13
14
|
export declare function decisionNotification(run: Fields, decision: Fields): NotifyEvent;
|
|
14
15
|
export declare function outcomeNotification(run: Fields): NotifyEvent | undefined;
|
|
16
|
+
export declare function stoppedScheduleNotification(schedule: Fields): NotifyEvent | undefined;
|
|
17
|
+
export declare function scheduleStopNotifications(schedule: Fields): readonly NotifyEvent[];
|
|
@@ -47,3 +47,39 @@ export function outcomeNotification(run) {
|
|
|
47
47
|
}),
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
+
export function stoppedScheduleNotification(schedule) {
|
|
51
|
+
if (schedule["state"] !== "stopped")
|
|
52
|
+
return undefined;
|
|
53
|
+
const failedRunIds = schedule["failedRunIds"];
|
|
54
|
+
if (!Array.isArray(failedRunIds) || failedRunIds.length !== 3)
|
|
55
|
+
throw new Error("invalid-stopped-schedule");
|
|
56
|
+
const ids = failedRunIds.map((runId) => String(runId));
|
|
57
|
+
const workflowId = String(schedule["workflowId"]);
|
|
58
|
+
return {
|
|
59
|
+
key: `schedule-stopped:${workflowId}:${String(schedule["stoppedSlot"])}`,
|
|
60
|
+
message: {
|
|
61
|
+
...message({ workflowId, runId: ids[2] }, {
|
|
62
|
+
event: "schedule-stopped",
|
|
63
|
+
body: body(`Schedule stopped after three failed runs:\n${ids.join("\n")}`, [`cloving schedule resume ${workflowId}`]),
|
|
64
|
+
}),
|
|
65
|
+
failedRunIds: ids,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function scheduleStopNotifications(schedule) {
|
|
70
|
+
const stops = schedule["stops"];
|
|
71
|
+
if (stops === undefined) {
|
|
72
|
+
const event = stoppedScheduleNotification(schedule);
|
|
73
|
+
return event === undefined ? [] : [event];
|
|
74
|
+
}
|
|
75
|
+
if (!Array.isArray(stops))
|
|
76
|
+
throw new Error("invalid-stopped-schedule");
|
|
77
|
+
return stops.flatMap((stop) => {
|
|
78
|
+
const event = stoppedScheduleNotification({
|
|
79
|
+
...record(stop),
|
|
80
|
+
workflowId: schedule["workflowId"],
|
|
81
|
+
state: "stopped",
|
|
82
|
+
});
|
|
83
|
+
return event === undefined ? [] : [event];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
import { recordedNotifications, saveNotifications, } from "./notify-journal.js";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { send } from "../cli/client.js";
|
|
5
4
|
import { deliveryBackoffMilliseconds } from "../delivery-backoff.js";
|
|
6
|
-
import {
|
|
7
|
-
import { decisionNotification, outcomeNotification, } from "./notify-message.js";
|
|
5
|
+
import { notificationEvents } from "./notify-events.js";
|
|
8
6
|
const retentionMilliseconds = 7 * 24 * 60 * 60_000;
|
|
9
|
-
async function request(runtimeDirectory, request) {
|
|
10
|
-
const reply = await send(runtimeDirectory, request);
|
|
11
|
-
if (reply.kind === "error")
|
|
12
|
-
throw new Error(reply.error.code);
|
|
13
|
-
return reply.result;
|
|
14
|
-
}
|
|
15
|
-
function rows(value) {
|
|
16
|
-
if (!Array.isArray(value))
|
|
17
|
-
throw new Error("invalid-notify-list");
|
|
18
|
-
return value.map((item) => {
|
|
19
|
-
const row = record(item);
|
|
20
|
-
if (row === undefined)
|
|
21
|
-
throw new Error("invalid-notify-row");
|
|
22
|
-
return row;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
7
|
async function flushNotifications(journal) {
|
|
26
8
|
if (journal.unsaved.size === 0)
|
|
27
9
|
return;
|
|
@@ -36,60 +18,6 @@ async function finishDelivery(journal, entry) {
|
|
|
36
18
|
journal.unsaved.set(entry.key, entry);
|
|
37
19
|
await flushNotifications(journal);
|
|
38
20
|
}
|
|
39
|
-
async function observedOutcome(summary, source) {
|
|
40
|
-
const { runtimeDirectory, cache } = source;
|
|
41
|
-
const latestSequence = summary["latestSequence"];
|
|
42
|
-
if (typeof latestSequence !== "number")
|
|
43
|
-
throw new Error("invalid-notify-sequence");
|
|
44
|
-
const runId = String(summary["runId"]);
|
|
45
|
-
const previous = cache.get(runId);
|
|
46
|
-
if (previous !== undefined && previous.latestSequence === latestSequence)
|
|
47
|
-
return previous.event;
|
|
48
|
-
const status = await request(runtimeDirectory, {
|
|
49
|
-
operation: "status",
|
|
50
|
-
parameters: { runId },
|
|
51
|
-
});
|
|
52
|
-
const run = record(status["run"]);
|
|
53
|
-
if (run === undefined)
|
|
54
|
-
throw new Error("invalid-notify-status");
|
|
55
|
-
const event = outcomeNotification(run);
|
|
56
|
-
cache.set(runId, { latestSequence, event });
|
|
57
|
-
return event;
|
|
58
|
-
}
|
|
59
|
-
async function events(runtimeDirectory, cache) {
|
|
60
|
-
const found = [];
|
|
61
|
-
const runs = new Map();
|
|
62
|
-
let after = "";
|
|
63
|
-
do {
|
|
64
|
-
const page = await request(runtimeDirectory, {
|
|
65
|
-
operation: "status",
|
|
66
|
-
parameters: { after, limit: 500 },
|
|
67
|
-
});
|
|
68
|
-
for (const summary of rows(page["runs"])) {
|
|
69
|
-
runs.set(String(summary["runId"]), summary);
|
|
70
|
-
const outcome = await observedOutcome(summary, {
|
|
71
|
-
runtimeDirectory,
|
|
72
|
-
cache,
|
|
73
|
-
});
|
|
74
|
-
if (outcome !== undefined)
|
|
75
|
-
found.push(outcome);
|
|
76
|
-
}
|
|
77
|
-
const next = page["next"];
|
|
78
|
-
if (next !== null && (typeof next !== "string" || next <= after))
|
|
79
|
-
throw new Error("invalid-notify-page");
|
|
80
|
-
after = next;
|
|
81
|
-
} while (after !== null);
|
|
82
|
-
const questions = await request(runtimeDirectory, {
|
|
83
|
-
operation: "questions",
|
|
84
|
-
parameters: {},
|
|
85
|
-
});
|
|
86
|
-
for (const decision of rows(questions["decisions"])) {
|
|
87
|
-
const run = runs.get(String(decision["runId"]));
|
|
88
|
-
if (run !== undefined)
|
|
89
|
-
found.push(decisionNotification(run, decision));
|
|
90
|
-
}
|
|
91
|
-
return found;
|
|
92
|
-
}
|
|
93
21
|
export function notifyCommand(command, notification) {
|
|
94
22
|
return new Promise((resolve, reject) => {
|
|
95
23
|
const [executable = "", ...argumentsList] = command;
|
|
@@ -210,7 +138,7 @@ async function check(settings, journal) {
|
|
|
210
138
|
journal.retiredKeys.add(key);
|
|
211
139
|
}
|
|
212
140
|
}
|
|
213
|
-
for (const event of await
|
|
141
|
+
for (const event of await notificationEvents(settings.runtimeDirectory, journal.cache)) {
|
|
214
142
|
if (journal.entries.has(event.key) || journal.retiredKeys.has(event.key))
|
|
215
143
|
continue;
|
|
216
144
|
const entry = {
|
|
@@ -237,12 +165,12 @@ export async function notifyRuns(settings) {
|
|
|
237
165
|
unsaved: new Map(),
|
|
238
166
|
};
|
|
239
167
|
if (recorded === undefined) {
|
|
240
|
-
for (const event of await
|
|
168
|
+
for (const event of await notificationEvents(settings.runtimeDirectory, cache))
|
|
241
169
|
journal.entries.set(event.key, {
|
|
242
170
|
...event,
|
|
243
|
-
state: "sent",
|
|
171
|
+
state: event.message.event === "schedule-stopped" ? "pending" : "sent",
|
|
244
172
|
attempts: 0,
|
|
245
|
-
lastAttemptAt: Date.now(),
|
|
173
|
+
lastAttemptAt: event.message.event === "schedule-stopped" ? null : Date.now(),
|
|
246
174
|
lastFailure: null,
|
|
247
175
|
});
|
|
248
176
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function queueStatus(settings: {
|
|
2
2
|
readonly runtimeDirectory: string;
|
|
3
|
-
readonly workflowId
|
|
4
|
-
}): Promise<
|
|
3
|
+
readonly workflowId: string;
|
|
4
|
+
}): Promise<{
|
|
5
|
+
readonly busy: number;
|
|
6
|
+
readonly holding: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function spendNotice(): (status: {
|
|
9
|
+
readonly holding: boolean;
|
|
10
|
+
}) => boolean;
|