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
|
@@ -8,7 +8,7 @@ function queueBusy(value) {
|
|
|
8
8
|
throw new Error("invalid-queue-status");
|
|
9
9
|
return busy;
|
|
10
10
|
}
|
|
11
|
-
export async function
|
|
11
|
+
export async function queueStatus(settings) {
|
|
12
12
|
let count = 0;
|
|
13
13
|
let after = "";
|
|
14
14
|
do {
|
|
@@ -20,13 +20,17 @@ export async function activeQueueRuns(settings) {
|
|
|
20
20
|
throw new Error(reply.error.code);
|
|
21
21
|
const busy = queueBusy(reply.result["queue"]);
|
|
22
22
|
if (busy !== undefined)
|
|
23
|
-
return
|
|
23
|
+
return {
|
|
24
|
+
busy,
|
|
25
|
+
holding: record(record(reply.result["queue"])?.["spend"])?.["holding"] ===
|
|
26
|
+
true,
|
|
27
|
+
};
|
|
24
28
|
const runs = reply.result["runs"];
|
|
25
29
|
if (!Array.isArray(runs))
|
|
26
30
|
throw new Error("invalid-run-list");
|
|
27
31
|
count += runs.filter((value) => {
|
|
28
32
|
const run = record(value);
|
|
29
|
-
return (run?.["workflowId"] ===
|
|
33
|
+
return (run?.["workflowId"] === settings.workflowId &&
|
|
30
34
|
!["completed", "failed", "cancelled"].includes(String(run["state"])));
|
|
31
35
|
}).length;
|
|
32
36
|
const next = reply.result["next"];
|
|
@@ -34,5 +38,14 @@ export async function activeQueueRuns(settings) {
|
|
|
34
38
|
throw new Error("invalid-run-page");
|
|
35
39
|
after = next;
|
|
36
40
|
} while (after !== null);
|
|
37
|
-
return count;
|
|
41
|
+
return { busy: count, holding: false };
|
|
42
|
+
}
|
|
43
|
+
export function spendNotice() {
|
|
44
|
+
let held = false;
|
|
45
|
+
return ({ holding }) => {
|
|
46
|
+
if (holding && !held)
|
|
47
|
+
process.stderr.write("Queue holding for spend limit\n");
|
|
48
|
+
held = holding;
|
|
49
|
+
return holding;
|
|
50
|
+
};
|
|
38
51
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface LockIdentity {
|
|
2
|
+
readonly path: string;
|
|
3
|
+
readonly dev: number;
|
|
4
|
+
readonly ino: number;
|
|
5
|
+
readonly ctimeMs: number;
|
|
6
|
+
readonly mtimeMs: number;
|
|
7
|
+
}
|
|
8
|
+
export interface OwnedIndexLock extends LockIdentity {
|
|
9
|
+
readonly processIds: readonly number[];
|
|
10
|
+
}
|
|
11
|
+
export declare function ownedIndexLock(path: string): Promise<OwnedIndexLock | undefined>;
|
|
12
|
+
export declare function removeStoppedIndexLock(lock: OwnedIndexLock, signal: AbortSignal): Promise<boolean>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { lstat, readdir, readFile, stat, unlink } from "node:fs/promises";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
const execute = promisify(execFile);
|
|
5
|
+
function disappeared(error) {
|
|
6
|
+
return (error instanceof Error &&
|
|
7
|
+
"code" in error &&
|
|
8
|
+
(error.code === "ENOENT" || error.code === "ESRCH"));
|
|
9
|
+
}
|
|
10
|
+
async function descriptorUsesLock(path, lock) {
|
|
11
|
+
try {
|
|
12
|
+
const opened = await stat(path);
|
|
13
|
+
if (opened.dev !== lock.dev || opened.ino !== lock.ino)
|
|
14
|
+
return false;
|
|
15
|
+
const information = await readFile(path.replace("/fd/", "/fdinfo/"), "utf8");
|
|
16
|
+
const flags = /^flags:\s+([0-7]+)$/m.exec(information)?.[1];
|
|
17
|
+
const inode = /^ino:\s+(\d+)$/m.exec(information)?.[1];
|
|
18
|
+
if (flags === undefined || Number(inode) !== lock.ino)
|
|
19
|
+
return undefined;
|
|
20
|
+
return (Number.parseInt(flags, 8) & 3) !== 0;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return disappeared(error) ? false : undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function processUsesLock(directory, lock) {
|
|
27
|
+
try {
|
|
28
|
+
for (const descriptor of await readdir(`${directory}/fd`)) {
|
|
29
|
+
const used = await descriptorUsesLock(`${directory}/fd/${descriptor}`, lock);
|
|
30
|
+
if (used !== false)
|
|
31
|
+
return used;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (disappeared(error))
|
|
37
|
+
return false;
|
|
38
|
+
if (!(error instanceof Error) ||
|
|
39
|
+
!("code" in error) ||
|
|
40
|
+
(error.code !== "EACCES" && error.code !== "EPERM"))
|
|
41
|
+
return undefined;
|
|
42
|
+
return (await unrelatedProcess(directory, lock)) ? false : undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function unrelatedProcess(directory, lock) {
|
|
46
|
+
if (lock.uid !== process.geteuid?.() || (lock.mode & 0o022) !== 0)
|
|
47
|
+
return false;
|
|
48
|
+
try {
|
|
49
|
+
const status = await readFile(`${directory}/status`, "utf8");
|
|
50
|
+
const users = /^Uid:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/m.exec(status);
|
|
51
|
+
return (users !== null &&
|
|
52
|
+
users
|
|
53
|
+
.slice(1)
|
|
54
|
+
.map(Number)
|
|
55
|
+
.every((user) => Number.isSafeInteger(user) && user !== lock.uid));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function lockOwners(lock) {
|
|
62
|
+
if (process.platform === "linux") {
|
|
63
|
+
const processIds = [];
|
|
64
|
+
for (const entry of await readdir("/proc")) {
|
|
65
|
+
if (!/^\d+$/.test(entry))
|
|
66
|
+
continue;
|
|
67
|
+
const used = await processUsesLock(`/proc/${entry}`, lock);
|
|
68
|
+
if (used === undefined)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (used)
|
|
71
|
+
processIds.push(Number(entry));
|
|
72
|
+
}
|
|
73
|
+
return processIds;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const { stdout, stderr } = await execute("lsof", ["-Fpfa", "--", lock.path], {
|
|
77
|
+
encoding: "utf8",
|
|
78
|
+
timeout: 5000,
|
|
79
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
80
|
+
});
|
|
81
|
+
return stderr === "" ? writableOwners(stdout) : undefined;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function writableOwner(record) {
|
|
88
|
+
const [header, ...descriptors] = record.trim().split(/^f/m);
|
|
89
|
+
const processId = Number(header?.trim().slice(1));
|
|
90
|
+
const access = descriptors.map((descriptor) => descriptor.split("\n")[1]);
|
|
91
|
+
if (!Number.isSafeInteger(processId) ||
|
|
92
|
+
processId < 1 ||
|
|
93
|
+
descriptors.length === 0 ||
|
|
94
|
+
access.some((mode) => mode !== "ar" && mode !== "aw" && mode !== "au"))
|
|
95
|
+
return undefined;
|
|
96
|
+
return access.some((mode) => mode === "aw" || mode === "au")
|
|
97
|
+
? processId
|
|
98
|
+
: null;
|
|
99
|
+
}
|
|
100
|
+
function writableOwners(text) {
|
|
101
|
+
const owners = text
|
|
102
|
+
.trim()
|
|
103
|
+
.split(/(?=^p)/m)
|
|
104
|
+
.map(writableOwner);
|
|
105
|
+
return owners.includes(undefined)
|
|
106
|
+
? undefined
|
|
107
|
+
: [
|
|
108
|
+
...new Set(owners.filter((owner) => typeof owner === "number")),
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
export async function ownedIndexLock(path) {
|
|
112
|
+
try {
|
|
113
|
+
const identity = await lstat(path);
|
|
114
|
+
if (!identity.isFile())
|
|
115
|
+
return undefined;
|
|
116
|
+
const lock = {
|
|
117
|
+
path,
|
|
118
|
+
dev: identity.dev,
|
|
119
|
+
ino: identity.ino,
|
|
120
|
+
ctimeMs: identity.ctimeMs,
|
|
121
|
+
mtimeMs: identity.mtimeMs,
|
|
122
|
+
uid: identity.uid,
|
|
123
|
+
mode: identity.mode,
|
|
124
|
+
};
|
|
125
|
+
const processIds = await lockOwners(lock);
|
|
126
|
+
return processIds === undefined || processIds.length === 0
|
|
127
|
+
? undefined
|
|
128
|
+
: { ...lock, processIds };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function stopped(processId) {
|
|
135
|
+
try {
|
|
136
|
+
process.kill(processId, 0);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return error instanceof Error && "code" in error && error.code === "ESRCH";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export async function removeStoppedIndexLock(lock, signal) {
|
|
144
|
+
try {
|
|
145
|
+
if (!lock.processIds.every(stopped))
|
|
146
|
+
return false;
|
|
147
|
+
const after = await lstat(lock.path);
|
|
148
|
+
if (signal.aborted ||
|
|
149
|
+
lock.dev !== after.dev ||
|
|
150
|
+
lock.ino !== after.ino ||
|
|
151
|
+
lock.ctimeMs !== after.ctimeMs ||
|
|
152
|
+
lock.mtimeMs !== after.mtimeMs)
|
|
153
|
+
return false;
|
|
154
|
+
await unlink(lock.path);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IndexFailure } from "./retry-worktree.ts";
|
|
2
|
+
export declare function resumeWorktree(request: {
|
|
3
|
+
readonly directory: string;
|
|
4
|
+
readonly folder: string;
|
|
5
|
+
readonly signal: AbortSignal;
|
|
6
|
+
readonly stopMilliseconds?: number;
|
|
7
|
+
}): Promise<IndexFailure | null>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ownedIndexLock, removeStoppedIndexLock } from "./resume-index-lock.js";
|
|
2
|
+
import { stopTreeProcesses } from "./worktree-processes.js";
|
|
3
|
+
import { indexFailure } from "./retry-worktree.js";
|
|
4
|
+
async function inspectLock(failure) {
|
|
5
|
+
if (failure?.lockPath === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
return ownedIndexLock(failure.lockPath);
|
|
8
|
+
}
|
|
9
|
+
export async function resumeWorktree(request) {
|
|
10
|
+
const aborted = () => request.signal.aborted;
|
|
11
|
+
const before = await indexFailure(request);
|
|
12
|
+
const lock = await inspectLock(before);
|
|
13
|
+
if (aborted())
|
|
14
|
+
return before;
|
|
15
|
+
const stopped = await stopTreeProcesses(request);
|
|
16
|
+
const locked = await indexFailure(request);
|
|
17
|
+
if (!stopped)
|
|
18
|
+
return (locked ?? {
|
|
19
|
+
reason: "worktree-index-locked",
|
|
20
|
+
fix: "Stop the remaining work tree processes before resuming the turn.",
|
|
21
|
+
});
|
|
22
|
+
if (locked?.reason !== "worktree-index-locked" || aborted())
|
|
23
|
+
return locked;
|
|
24
|
+
if (lock === undefined ||
|
|
25
|
+
lock.path !== locked.lockPath ||
|
|
26
|
+
!(await removeStoppedIndexLock(lock, request.signal)))
|
|
27
|
+
return locked;
|
|
28
|
+
return indexFailure(request);
|
|
29
|
+
}
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import { type TokenPrices } from "../token-prices.ts";
|
|
2
1
|
import { type RunningTurn, type TurnStart } from "./claude-turn.ts";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
readonly fallbackModels?: readonly string[];
|
|
6
|
-
readonly retryDelay?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
interface RetryOptions extends RetrySettings {
|
|
9
|
-
readonly stopping?: AbortController;
|
|
10
|
-
readonly stopMilliseconds?: number;
|
|
11
|
-
readonly metadata: Readonly<Record<string, unknown>>;
|
|
12
|
-
}
|
|
2
|
+
import { type RetryOptions } from "./turn-attempts.ts";
|
|
3
|
+
export type { RetrySettings } from "./turn-attempts.ts";
|
|
13
4
|
export declare function startRetriedTurn(start: TurnStart, options: RetryOptions): Promise<RunningTurn>;
|
|
14
|
-
export {};
|
|
@@ -1,41 +1,17 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { mkdir } from "node:fs/promises";
|
|
3
1
|
import { setTimeout as delay } from "node:timers/promises";
|
|
4
|
-
import {
|
|
5
|
-
import { commandModel, replaceCommandModel, estimatedCostUsd, priceForModel, } from "../token-prices.js";
|
|
6
|
-
import { capacityRefusal, retryKind, startTurn, } from "./claude-turn.js";
|
|
2
|
+
import { startTurn, } from "./claude-turn.js";
|
|
7
3
|
import { turnHead, retryEvidence, indexFailure } from "./retry-worktree.js";
|
|
8
4
|
import { readRecord, writeRecord } from "./operation-journal.js";
|
|
9
|
-
import {
|
|
5
|
+
import { resumeWorktree } from "./resume-worktree.js";
|
|
6
|
+
import { readResume, resumedCommand, resumePrompt } from "./claude-recovery.js";
|
|
7
|
+
import { attemptCommand, combined, kindOf, } from "./turn-attempts.js";
|
|
8
|
+
import { prepareAttempt, attemptJournal, recordedEnd, } from "./turn-attempt-journal.js";
|
|
10
9
|
const waits = { capacity: [60_000, 180_000], network: [600_000, 2_400_000] };
|
|
11
10
|
const networkContinuation = "An earlier attempt stopped because the network was not available. Continue from the current state of the work tree. Check each earlier commit, push, review comment and message. Do not repeat a write that is done. Stop and report a write whose result is not known.";
|
|
12
11
|
const continuation = "An earlier attempt stopped because the model was at capacity; continue from the current state of the work tree.\n\n";
|
|
13
12
|
function written(folder, entry) {
|
|
14
13
|
return writeRecord(folder, { ...entry, permissions: "private" });
|
|
15
14
|
}
|
|
16
|
-
function total(values) {
|
|
17
|
-
if (values.includes(null))
|
|
18
|
-
return null;
|
|
19
|
-
return priceOf(values.reduce((sum, value) => sum + (value ?? 0), 0));
|
|
20
|
-
}
|
|
21
|
-
function combined(attempts) {
|
|
22
|
-
const { ends } = attempts;
|
|
23
|
-
const last = ends.at(-1) ?? { exitCode: null, result: undefined };
|
|
24
|
-
const result = last.result ?? ends.find((end) => end.result)?.result;
|
|
25
|
-
if (result === undefined)
|
|
26
|
-
return last;
|
|
27
|
-
return {
|
|
28
|
-
...last,
|
|
29
|
-
result: {
|
|
30
|
-
...result,
|
|
31
|
-
attempts: ends.map((end, index) => attemptUsage(attempts, { end, attempt: index + 1 })),
|
|
32
|
-
...(last.result === undefined ? { failed: true, text: "" } : {}),
|
|
33
|
-
usage: sumUsage(ends.map((end) => end.result?.usage ?? usageOf(null))),
|
|
34
|
-
costUsd: total(ends.map((end) => end.result?.costUsd ?? null)),
|
|
35
|
-
turns: total(ends.map((end) => end.result?.turns ?? null)),
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
15
|
function controlled(attempts, start) {
|
|
40
16
|
const turn = startTurn(start);
|
|
41
17
|
const stop = () => {
|
|
@@ -49,66 +25,6 @@ function controlled(attempts, start) {
|
|
|
49
25
|
}),
|
|
50
26
|
};
|
|
51
27
|
}
|
|
52
|
-
function attemptCommand(attempts, attempt) {
|
|
53
|
-
const { start, options } = attempts;
|
|
54
|
-
const original = start.command;
|
|
55
|
-
const previous = attempts.ends[attempt - 2];
|
|
56
|
-
const fallback = previous !== undefined && kindOf(attempts, previous) === "capacity"
|
|
57
|
-
? options.fallbackModels?.[attempt - 3]
|
|
58
|
-
: undefined;
|
|
59
|
-
const command = fallback === undefined ? original : replaceCommandModel(original, fallback);
|
|
60
|
-
const model = start.output === "text" ? null : commandModel(command);
|
|
61
|
-
return {
|
|
62
|
-
command,
|
|
63
|
-
model,
|
|
64
|
-
...(fallback !== undefined && model === null
|
|
65
|
-
? { fallbackReason: "fallback-model-unavailable" }
|
|
66
|
-
: {}),
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function attemptUsage(attempts, completion) {
|
|
70
|
-
const { end, attempt } = completion;
|
|
71
|
-
const result = end.result ?? {
|
|
72
|
-
model: null,
|
|
73
|
-
usage: usageOf(null),
|
|
74
|
-
costUsd: null,
|
|
75
|
-
pricingModel: undefined,
|
|
76
|
-
};
|
|
77
|
-
const model = result.model ?? attemptCommand(attempts, attempt).model;
|
|
78
|
-
const usage = result.usage;
|
|
79
|
-
return {
|
|
80
|
-
attempt,
|
|
81
|
-
retryKind: kindOf(attempts, end),
|
|
82
|
-
model,
|
|
83
|
-
...(end.result?.models === undefined ? {} : { models: end.result.models }),
|
|
84
|
-
usage,
|
|
85
|
-
costUsd: result.costUsd,
|
|
86
|
-
estimatedCostUsd: attemptEstimate(attempts, { end, model, usage }),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function attemptEstimate(attempts, result) {
|
|
90
|
-
const worker = attempts.start.worker ?? "claude";
|
|
91
|
-
if (!nativeHarness(worker))
|
|
92
|
-
return null;
|
|
93
|
-
const models = result.end.result?.models;
|
|
94
|
-
const prices = attempts.options.tokenPrices ?? {};
|
|
95
|
-
return estimatedCostUsd(result.usage, worker === "gemini" && models !== undefined
|
|
96
|
-
? { worker, models, prices }
|
|
97
|
-
: {
|
|
98
|
-
worker,
|
|
99
|
-
price: priceForModel(prices, result.end.result?.pricingModel === undefined
|
|
100
|
-
? result.model
|
|
101
|
-
: result.end.result.pricingModel),
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
function kindOf(attempts, end) {
|
|
105
|
-
const { worker, output } = attempts.start;
|
|
106
|
-
if (output === "text" || !["claude", "codex"].includes(worker ?? "claude"))
|
|
107
|
-
return null;
|
|
108
|
-
if (worker !== "codex")
|
|
109
|
-
return retryKind(end.result);
|
|
110
|
-
return capacityRefusal(end.result) ? "capacity" : null;
|
|
111
|
-
}
|
|
112
28
|
async function promptOf(attempts) {
|
|
113
29
|
const { start, ends, stopping, turnStartCommit } = attempts;
|
|
114
30
|
if (ends.length === 0)
|
|
@@ -118,53 +34,42 @@ async function promptOf(attempts) {
|
|
|
118
34
|
const evidence = await retryEvidence({ directory: start.directory, signal: stopping.signal }, turnStartCommit);
|
|
119
35
|
return `${networkContinuation}\n\nCommits since the start of this turn:\n${evidence}\n\n${start.prompt}`;
|
|
120
36
|
}
|
|
37
|
+
function launchCommand(attempts, prepared) {
|
|
38
|
+
const { entry, selected } = prepared;
|
|
39
|
+
if (entry.resumedAfter === undefined)
|
|
40
|
+
return selected.command;
|
|
41
|
+
return (resumedCommand({
|
|
42
|
+
worker: attempts.start.worker,
|
|
43
|
+
command: selected.command,
|
|
44
|
+
sessionId: attempts.options.resume?.sessionId ?? "",
|
|
45
|
+
}) ?? selected.command);
|
|
46
|
+
}
|
|
121
47
|
async function launched(attempts, prompt = attempts.start.prompt) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
const selected = attemptCommand(attempts, attempt);
|
|
125
|
-
const folder = attempt === 1
|
|
126
|
-
? start.folder
|
|
127
|
-
: join(start.folder, `attempt-${String(attempt)}`);
|
|
128
|
-
const entry = {
|
|
129
|
-
...options.metadata,
|
|
130
|
-
turnStartCommit: attempts.turnStartCommit,
|
|
131
|
-
model: selected.model,
|
|
132
|
-
...(selected.fallbackReason === undefined
|
|
133
|
-
? {}
|
|
134
|
-
: { fallbackReason: selected.fallbackReason }),
|
|
135
|
-
attempt,
|
|
136
|
-
startedAt: attempt === 1 ? attempts.startedAt : new Date().toISOString(),
|
|
137
|
-
};
|
|
138
|
-
await written(start.folder, {
|
|
139
|
-
name: "started.json",
|
|
140
|
-
value: {
|
|
141
|
-
...entry,
|
|
142
|
-
startedAt: attempts.startedAt,
|
|
143
|
-
phase: "starting",
|
|
144
|
-
processId: null,
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
await mkdir(folder, { recursive: true, mode: 0o700 });
|
|
148
|
-
if (attempts.stopping.signal.aborted)
|
|
48
|
+
const prepared = await prepareAttempt(attempts);
|
|
49
|
+
if (prepared === undefined || attempts.stopping.signal.aborted)
|
|
149
50
|
return undefined;
|
|
51
|
+
const { start } = attempts;
|
|
52
|
+
const { entry, folder } = prepared;
|
|
53
|
+
const journal = attemptJournal(attempts, entry);
|
|
150
54
|
const turn = controlled(attempts, {
|
|
151
55
|
...start,
|
|
152
|
-
command:
|
|
56
|
+
command: launchCommand(attempts, prepared),
|
|
57
|
+
progress: journal.progress,
|
|
153
58
|
folder,
|
|
154
|
-
...(attempt === 1 ? {} : { activityFolder: start.folder }),
|
|
155
|
-
prompt,
|
|
59
|
+
...(entry.attempt === 1 ? {} : { activityFolder: start.folder }),
|
|
60
|
+
prompt: entry.resumedAfter === undefined ? prompt : resumePrompt,
|
|
156
61
|
});
|
|
157
62
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
63
|
+
await journal.running(turn.processId);
|
|
64
|
+
return {
|
|
65
|
+
...turn,
|
|
66
|
+
ended: turn.ended.then((end) => ({
|
|
67
|
+
...end,
|
|
68
|
+
...(entry.resumedAfter === undefined
|
|
69
|
+
? {}
|
|
70
|
+
: { resumedAfter: entry.resumedAfter }),
|
|
71
|
+
})),
|
|
72
|
+
};
|
|
168
73
|
}
|
|
169
74
|
catch (error) {
|
|
170
75
|
turn.stop(0);
|
|
@@ -172,34 +77,6 @@ async function launched(attempts, prompt = attempts.start.prompt) {
|
|
|
172
77
|
throw error;
|
|
173
78
|
}
|
|
174
79
|
}
|
|
175
|
-
async function recordedEnd(attempts, completion) {
|
|
176
|
-
const { start, ends, options } = attempts;
|
|
177
|
-
const { processId, end } = completion;
|
|
178
|
-
const attempt = ends.length;
|
|
179
|
-
const selected = attemptCommand(attempts, attempt);
|
|
180
|
-
const name = `attempt-${String(attempt)}.json`;
|
|
181
|
-
const started = await readRecord(start.folder, name);
|
|
182
|
-
const startedAt = Reflect.get(Object(started), "startedAt");
|
|
183
|
-
if (typeof startedAt !== "string")
|
|
184
|
-
throw new Error("attempt-start-time-missing");
|
|
185
|
-
await written(start.folder, {
|
|
186
|
-
name,
|
|
187
|
-
value: {
|
|
188
|
-
...options.metadata,
|
|
189
|
-
turnStartCommit: attempts.turnStartCommit,
|
|
190
|
-
...attemptUsage(attempts, { end, attempt }),
|
|
191
|
-
...(selected.fallbackReason === undefined
|
|
192
|
-
? {}
|
|
193
|
-
: { fallbackReason: selected.fallbackReason }),
|
|
194
|
-
attempt,
|
|
195
|
-
processId,
|
|
196
|
-
startedAt,
|
|
197
|
-
endedAt: new Date().toISOString(),
|
|
198
|
-
exitCode: end.exitCode,
|
|
199
|
-
capacity: capacityRefusal(end.result),
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
80
|
async function waited(attempts, milliseconds) {
|
|
204
81
|
const { start, options, stopping, ends } = attempts;
|
|
205
82
|
await written(start.folder, {
|
|
@@ -250,8 +127,9 @@ async function finished(attempts, first) {
|
|
|
250
127
|
const end = await turn.ended;
|
|
251
128
|
ends.push(end);
|
|
252
129
|
await recordedEnd(attempts, { processId: turn.processId, end });
|
|
253
|
-
|
|
254
|
-
|
|
130
|
+
if (interruptedChild(attempts, { processId: turn.processId, end }))
|
|
131
|
+
return resumedChild(attempts);
|
|
132
|
+
const milliseconds = retryWait(attempts, end);
|
|
255
133
|
if (cancelled(attempts) || milliseconds === undefined)
|
|
256
134
|
break;
|
|
257
135
|
await waited(attempts, milliseconds);
|
|
@@ -262,9 +140,59 @@ async function finished(attempts, first) {
|
|
|
262
140
|
return prepared;
|
|
263
141
|
turn = await launched(attempts, prepared);
|
|
264
142
|
}
|
|
143
|
+
return attemptOutcome(attempts);
|
|
144
|
+
}
|
|
145
|
+
function interruptedChild(attempts, completion) {
|
|
146
|
+
const { start } = attempts;
|
|
147
|
+
const { processId, end } = completion;
|
|
148
|
+
return (!cancelled(attempts) &&
|
|
149
|
+
(start.worker ?? "claude") === "claude" &&
|
|
150
|
+
start.output !== "text" &&
|
|
151
|
+
processId !== null &&
|
|
152
|
+
end.exitCode !== 0 &&
|
|
153
|
+
end.result === undefined);
|
|
154
|
+
}
|
|
155
|
+
async function resumedChild(attempts) {
|
|
156
|
+
const started = await readRecord(attempts.start.folder, "started.json");
|
|
157
|
+
const resume = await readResume(attempts.start.folder, started);
|
|
158
|
+
if (resume === undefined)
|
|
159
|
+
return { ...combined(attempts), reason: "claude-turn-interrupted" };
|
|
160
|
+
const locked = await resumeWorktree({
|
|
161
|
+
directory: attempts.start.directory,
|
|
162
|
+
folder: attempts.start.folder,
|
|
163
|
+
signal: attempts.stopping.signal,
|
|
164
|
+
stopMilliseconds: attempts.grace.milliseconds,
|
|
165
|
+
});
|
|
166
|
+
if (locked !== null)
|
|
167
|
+
return { ...combined(attempts), reason: locked.reason };
|
|
168
|
+
const prepared = await preparedRetry(attempts);
|
|
169
|
+
if (typeof prepared !== "string")
|
|
170
|
+
return prepared;
|
|
171
|
+
const recovered = {
|
|
172
|
+
...attempts,
|
|
173
|
+
options: { ...attempts.options, resume },
|
|
174
|
+
ends: [...resume.ends],
|
|
175
|
+
};
|
|
176
|
+
const turn = await launched(recovered);
|
|
177
|
+
return turn === undefined
|
|
178
|
+
? attemptOutcome(recovered)
|
|
179
|
+
: finished(recovered, turn);
|
|
180
|
+
}
|
|
181
|
+
function retryWait(attempts, end) {
|
|
182
|
+
const kind = kindOf(attempts, end);
|
|
183
|
+
if (kind === null)
|
|
184
|
+
return undefined;
|
|
185
|
+
if (attemptCommand(attempts, attempts.ends.length + 1).budgetUsd === 0) {
|
|
186
|
+
attempts.failure = "claude-turn-budget-exhausted";
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
return waits[kind][attempts.ends.filter((end) => end.resumedAfter === undefined).length - 1];
|
|
190
|
+
}
|
|
191
|
+
function attemptOutcome(attempts) {
|
|
265
192
|
return {
|
|
266
193
|
...combined(attempts),
|
|
267
|
-
...(
|
|
194
|
+
...(attempts.failure === undefined ? {} : { reason: attempts.failure }),
|
|
195
|
+
...(cancelled(attempts) ? { stopped: true } : {}),
|
|
268
196
|
};
|
|
269
197
|
}
|
|
270
198
|
function cancelled(attempts) {
|
|
@@ -272,28 +200,26 @@ function cancelled(attempts) {
|
|
|
272
200
|
}
|
|
273
201
|
export async function startRetriedTurn(start, options) {
|
|
274
202
|
const stopping = options.stopping ?? new AbortController();
|
|
275
|
-
const turnStartCommit =
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
203
|
+
const turnStartCommit = options.resume === undefined
|
|
204
|
+
? await turnHead({
|
|
205
|
+
directory: start.directory,
|
|
206
|
+
signal: stopping.signal,
|
|
207
|
+
})
|
|
208
|
+
: options.resume.turnStartCommit;
|
|
279
209
|
const attempts = {
|
|
280
210
|
turnStartCommit,
|
|
281
211
|
start,
|
|
282
|
-
startedAt: new Date().toISOString(),
|
|
212
|
+
startedAt: options.resume?.startedAt ?? new Date().toISOString(),
|
|
283
213
|
options,
|
|
284
214
|
stopping,
|
|
285
|
-
ends: [],
|
|
286
|
-
grace: { milliseconds: options.stopMilliseconds ??
|
|
215
|
+
ends: [...(options.resume?.ends ?? [])],
|
|
216
|
+
grace: { milliseconds: options.stopMilliseconds ?? 15_000 },
|
|
287
217
|
};
|
|
288
218
|
const turn = await launched(attempts);
|
|
289
219
|
if (turn === undefined)
|
|
290
220
|
return {
|
|
291
221
|
processId: null,
|
|
292
|
-
ended: Promise.resolve(
|
|
293
|
-
exitCode: null,
|
|
294
|
-
result: undefined,
|
|
295
|
-
stopped: true,
|
|
296
|
-
}),
|
|
222
|
+
ended: Promise.resolve(attemptOutcome(attempts)),
|
|
297
223
|
stop: () => {
|
|
298
224
|
stopping.abort();
|
|
299
225
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SchedulePort, ScheduleProgress } from "../schedule-progress.ts";
|
|
2
|
+
import type { DeclaredWorkflow } from "../workflow-declaration.ts";
|
|
3
|
+
import type { scheduleJournal } from "./schedule-journal.ts";
|
|
4
|
+
type Journal = Awaited<ReturnType<typeof scheduleJournal>>;
|
|
5
|
+
interface ScheduleState {
|
|
6
|
+
readonly journal: Journal;
|
|
7
|
+
readonly declarations: readonly DeclaredWorkflow[];
|
|
8
|
+
readonly clock: () => number;
|
|
9
|
+
readonly recoverPending: (entry: {
|
|
10
|
+
readonly workflowId: string;
|
|
11
|
+
readonly progress: ScheduleProgress;
|
|
12
|
+
}) => Promise<ScheduleProgress>;
|
|
13
|
+
}
|
|
14
|
+
export declare function scheduleConnection(): {
|
|
15
|
+
readonly request: SchedulePort;
|
|
16
|
+
readonly connect: (port: SchedulePort) => void;
|
|
17
|
+
};
|
|
18
|
+
export declare function scheduleControl(settings: ScheduleState & {
|
|
19
|
+
readonly signal: AbortSignal;
|
|
20
|
+
readonly tick: () => Promise<void>;
|
|
21
|
+
}): {
|
|
22
|
+
readonly request: SchedulePort;
|
|
23
|
+
readonly tick: () => Promise<void>;
|
|
24
|
+
readonly drain: () => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|