cloving 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +329 -215
- 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-health.d.ts +9 -0
- package/dist/src/broker/actor/authority-health.js +24 -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-runtime.d.ts +4 -2
- package/dist/src/broker/actor/authority-runtime.js +29 -20
- package/dist/src/broker/actor/authority-session.d.ts +6 -19
- package/dist/src/broker/actor/authority-session.js +66 -88
- package/dist/src/broker/actor/authority-settings.d.ts +2 -1
- package/dist/src/broker/actor/authority-settings.js +6 -3
- package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
- package/dist/src/broker/actor/authority-upgrades.js +8 -2
- package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
- package/dist/src/broker/actor/authority-watchdog.js +31 -9
- package/dist/src/broker/actor/authority.js +3 -1
- 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/projection-memory.d.ts +43 -0
- package/dist/src/broker/actor/projection-memory.js +207 -0
- package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
- package/dist/src/broker/actor/runtime-parts.js +8 -3
- 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 +3 -0
- package/dist/src/broker/effect-upgrade.js +11 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +43 -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 +7 -2
- package/dist/src/cli/client.js +13 -7
- package/dist/src/cli/command-requests.d.ts +46 -0
- package/dist/src/cli/command-requests.js +84 -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 +70 -88
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/config-notice.js +5 -2
- package/dist/src/cli/doctor-retention.d.ts +2 -0
- package/dist/src/cli/doctor-retention.js +93 -0
- 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 +11 -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 +242 -0
- package/dist/src/cli/queue-arguments.d.ts +15 -0
- package/dist/src/cli/queue-arguments.js +31 -0
- package/dist/src/cli/queue-render.d.ts +3 -0
- package/dist/src/cli/queue-render.js +26 -0
- package/dist/src/cli/reload-render.d.ts +2 -0
- package/dist/src/cli/reload-render.js +12 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +54 -38
- 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 +18 -3
- package/dist/src/cli/runtime-arguments.js +29 -20
- 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/toolchain.d.ts +1 -0
- package/dist/src/cli/toolchain.js +1 -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 +2 -2
- package/dist/src/cli/usage.js +89 -11
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-api-document.d.ts +430 -0
- package/dist/src/cli/watch-api-document.js +291 -0
- package/dist/src/cli/watch-api-run.d.ts +56 -0
- package/dist/src/cli/watch-api-run.js +112 -0
- package/dist/src/cli/watch-api.d.ts +17 -0
- package/dist/src/cli/watch-api.js +230 -0
- 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 +1 -5
- package/dist/src/cli/watch-header-view.js +17 -21
- package/dist/src/cli/watch-model.d.ts +5 -1
- package/dist/src/cli/watch-model.js +20 -11
- package/dist/src/cli/watch-page.js +15 -15
- 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 +3 -0
- package/dist/src/cli/watch-reads.js +22 -20
- package/dist/src/cli/watch-render.d.ts +15 -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 +24 -10
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +73 -12
- 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-display.js +2 -0
- package/dist/src/configuration-schema.d.ts +14 -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 +208 -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 +5 -4
- package/dist/src/daemon/claude-worker.js +127 -126
- package/dist/src/daemon/daemon-adapters.d.ts +9 -0
- package/dist/src/daemon/daemon-adapters.js +33 -5
- package/dist/src/daemon/daemon-loops.d.ts +5 -1
- package/dist/src/daemon/daemon-loops.js +18 -10
- package/dist/src/daemon/daemon.js +80 -61
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +222 -0
- package/dist/src/daemon/github-calls.js +1 -1
- 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 +18 -4
- 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 +4 -1
- package/dist/src/daemon/issue-queue.js +76 -78
- package/dist/src/daemon/merge-turns.d.ts +10 -0
- package/dist/src/daemon/merge-turns.js +37 -0
- 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-control.d.ts +13 -0
- package/dist/src/daemon/queue-control.js +86 -0
- package/dist/src/daemon/queue-journal.d.ts +20 -0
- package/dist/src/daemon/queue-journal.js +89 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/record-archive.d.ts +19 -0
- package/dist/src/daemon/record-archive.js +82 -0
- package/dist/src/daemon/record-sweep.d.ts +24 -0
- package/dist/src/daemon/record-sweep.js +147 -0
- 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/settings-reload.d.ts +26 -0
- package/dist/src/daemon/settings-reload.js +82 -0
- 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-details.d.ts +4 -0
- package/dist/src/daemon/turn-details.js +33 -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 +9 -0
- package/dist/src/daemon/worker-profile.js +44 -0
- package/dist/src/daemon/workflow-generations.d.ts +7 -4
- package/dist/src/daemon/workflow-generations.js +22 -14
- package/dist/src/daemon/workflow-reload.d.ts +41 -0
- package/dist/src/daemon/workflow-reload.js +244 -0
- package/dist/src/daemon/workflow-replay.d.ts +2 -1
- package/dist/src/daemon/workflow-replay.js +7 -3
- 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 +4 -6
- package/dist/src/doctor-report.js +8 -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 +71 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +16 -2
- package/dist/src/project-settings.js +35 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/queue-state.d.ts +26 -0
- package/dist/src/queue-state.js +34 -0
- package/dist/src/record-retention.d.ts +46 -0
- package/dist/src/record-retention.js +81 -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 +11 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/dispatcher.d.ts +4 -0
- package/dist/src/service/dispatcher.js +33 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-handlers.d.ts +4 -0
- package/dist/src/service/queue-handlers.js +32 -0
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/registry.d.ts +28 -2
- package/dist/src/service/registry.js +48 -0
- package/dist/src/service/replies.d.ts +22 -8
- package/dist/src/service/replies.js +16 -2
- package/dist/src/service/run-handlers.js +37 -12
- 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 +11 -3
- package/dist/src/service/service.js +22 -37
- 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 +6 -0
- package/dist/src/service/worker-totals.js +8 -1
- package/dist/src/service/workflow-reload.d.ts +35 -0
- package/dist/src/service/workflow-reload.js +52 -0
- 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 -2
- package/dist/src/storage/decision-snapshots.js +16 -8
- package/dist/src/storage/domain-changes.d.ts +3 -1
- package/dist/src/storage/domain-changes.js +4 -0
- package/dist/src/storage/domain-schema.d.ts +16 -1
- package/dist/src/storage/domain-schema.js +35 -4
- package/dist/src/storage/effect-schema.d.ts +2 -0
- package/dist/src/storage/effect-schema.js +9 -0
- package/dist/src/storage/projection-changes.d.ts +12 -0
- package/dist/src/storage/projection-changes.js +194 -0
- package/dist/src/storage/projection-lookups.d.ts +7 -0
- package/dist/src/storage/projection-lookups.js +30 -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-declaration.d.ts +1 -0
- package/dist/src/workflow-declaration.js +3 -0
- 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/compile-workflows.js +3 -0
- package/dist/tools/project-configuration.d.ts +7 -2
- package/dist/tools/project-configuration.js +30 -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 +69 -26
- package/dist/tools/self-host-project.d.ts +2 -0
- package/dist/tools/self-host-project.js +30 -77
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +76 -34
- 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-program.d.ts +4 -2
- package/dist/tools/workflow-candidate-program.js +30 -11
- 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.d.ts +1 -0
- package/dist/tools/workflow-candidate-source.js +26 -4
- 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 +17 -9
- package/templates/develop/README.md +93 -4
- package/templates/develop/develop/flow-tests.ts +38 -1
- package/templates/develop/develop/interruption-tests.ts +157 -0
- package/templates/develop/develop/local.ts +1 -0
- package/templates/develop/develop/option-tests.ts +138 -9
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/red-green.ts +55 -0
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/report.ts +31 -11
- package/templates/develop/develop/round.ts +1 -0
- package/templates/develop/develop/scenarios.ts +27 -0
- package/templates/develop/develop/turn.ts +28 -7
- package/templates/develop/develop.declaration.json +1 -1
- package/templates/develop/develop.test.ts +4 -0
- package/templates/develop/template.json +29 -2
- 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
|
@@ -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 locked = await resumeWorktree({
|
|
157
|
+
directory: attempts.start.directory,
|
|
158
|
+
folder: attempts.start.folder,
|
|
159
|
+
signal: attempts.stopping.signal,
|
|
160
|
+
stopMilliseconds: attempts.grace.milliseconds,
|
|
161
|
+
});
|
|
162
|
+
if (locked !== null)
|
|
163
|
+
return { ...combined(attempts), reason: locked.reason };
|
|
164
|
+
const started = await readRecord(attempts.start.folder, "started.json");
|
|
165
|
+
const resume = await readResume(attempts.start.folder, started);
|
|
166
|
+
if (resume === undefined)
|
|
167
|
+
return { ...combined(attempts), reason: "claude-turn-interrupted" };
|
|
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 {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { scheduleStops } from "../schedule-progress.js";
|
|
2
|
+
import { runIdentity } from "../service/submission-handler.js";
|
|
3
|
+
import { failed, invalidRequest, result } from "../service/replies.js";
|
|
4
|
+
function summary(workflowId, progress) {
|
|
5
|
+
return {
|
|
6
|
+
workflowId,
|
|
7
|
+
everySeconds: progress.everySeconds,
|
|
8
|
+
state: progress.state,
|
|
9
|
+
failuresInRow: progress.failuresInRow,
|
|
10
|
+
failedRunIds: progress.failedRunIds,
|
|
11
|
+
lastSlot: progress.lastSlot,
|
|
12
|
+
nextAt: progress.state === "active" ? progress.nextAt : null,
|
|
13
|
+
activeRunId: progress.activeCommandId === undefined
|
|
14
|
+
? null
|
|
15
|
+
: runIdentity(progress.activeCommandId),
|
|
16
|
+
stoppedAt: progress.stoppedAt ?? null,
|
|
17
|
+
stoppedSlot: progress.stoppedSlot ?? null,
|
|
18
|
+
stops: scheduleStops(progress),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function scheduleConnection() {
|
|
22
|
+
let port;
|
|
23
|
+
return {
|
|
24
|
+
request: (parameters) => port?.(parameters) ??
|
|
25
|
+
Promise.resolve(failed("schedules-unavailable", {})),
|
|
26
|
+
connect: (connected) => {
|
|
27
|
+
port = connected;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function change(settings, command) {
|
|
32
|
+
const { workflowId, action, now } = command;
|
|
33
|
+
const { journal } = settings;
|
|
34
|
+
let prior = journal.entries.get(workflowId);
|
|
35
|
+
if (prior === undefined)
|
|
36
|
+
return failed("unknown-schedule", { workflowId });
|
|
37
|
+
const state = action === "pause" ? "paused" : "active";
|
|
38
|
+
if (prior.state === state)
|
|
39
|
+
return result("schedule", { schedule: summary(workflowId, prior) });
|
|
40
|
+
if (prior.pending !== undefined) {
|
|
41
|
+
prior = await settings.recoverPending({ workflowId, progress: prior });
|
|
42
|
+
journal.entries.set(workflowId, prior);
|
|
43
|
+
await journal.save();
|
|
44
|
+
}
|
|
45
|
+
const rest = { ...prior };
|
|
46
|
+
delete rest.stoppedAt;
|
|
47
|
+
delete rest.stoppedSlot;
|
|
48
|
+
const progress = action === "pause"
|
|
49
|
+
? { ...prior, state, stops: scheduleStops(prior) }
|
|
50
|
+
: {
|
|
51
|
+
...rest,
|
|
52
|
+
state,
|
|
53
|
+
failuresInRow: 0,
|
|
54
|
+
failedRunIds: [],
|
|
55
|
+
stops: scheduleStops(prior),
|
|
56
|
+
nextAt: now + prior.everySeconds * 1000,
|
|
57
|
+
};
|
|
58
|
+
journal.entries.set(workflowId, progress);
|
|
59
|
+
try {
|
|
60
|
+
await journal.save();
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
journal.entries.set(workflowId, prior);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
return result("schedule", { schedule: summary(workflowId, progress) });
|
|
67
|
+
}
|
|
68
|
+
function request(settings, parameters) {
|
|
69
|
+
const { action, workflowId } = parameters;
|
|
70
|
+
const scheduled = settings.declarations.filter((entry) => entry.schedule !== undefined);
|
|
71
|
+
if (action === "list")
|
|
72
|
+
return Promise.resolve(result("schedules", {
|
|
73
|
+
stops: Array.from(settings.journal.entries, ([workflowId, progress]) => ({
|
|
74
|
+
workflowId,
|
|
75
|
+
stops: scheduleStops(progress),
|
|
76
|
+
})),
|
|
77
|
+
schedules: scheduled.flatMap((entry) => {
|
|
78
|
+
const progress = settings.journal.entries.get(entry.workflowId);
|
|
79
|
+
return progress === undefined
|
|
80
|
+
? []
|
|
81
|
+
: [summary(entry.workflowId, progress)];
|
|
82
|
+
}),
|
|
83
|
+
}));
|
|
84
|
+
if ((action !== "pause" && action !== "resume") ||
|
|
85
|
+
typeof workflowId !== "string")
|
|
86
|
+
return Promise.resolve(invalidRequest("Use list, pause or resume with a workflow ID."));
|
|
87
|
+
if (!scheduled.some((entry) => entry.workflowId === workflowId))
|
|
88
|
+
return Promise.resolve(failed("unknown-schedule", { workflowId }));
|
|
89
|
+
return change(settings, {
|
|
90
|
+
workflowId,
|
|
91
|
+
action,
|
|
92
|
+
now: settings.clock(),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
export function scheduleControl(settings) {
|
|
96
|
+
let running = Promise.resolve();
|
|
97
|
+
const serialized = (operation) => {
|
|
98
|
+
const next = running.then(async () => {
|
|
99
|
+
settings.signal.throwIfAborted();
|
|
100
|
+
return operation();
|
|
101
|
+
});
|
|
102
|
+
running = next.then(() => undefined, () => undefined);
|
|
103
|
+
return next;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
request: (parameters) => serialized(() => request(settings, parameters)).catch(() => failed("schedules-unavailable", {})),
|
|
107
|
+
tick: () => serialized(settings.tick),
|
|
108
|
+
drain: () => running,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export type PendingSlot
|
|
3
|
-
readonly kind: "run";
|
|
4
|
-
readonly input: Fields;
|
|
5
|
-
} | {
|
|
6
|
-
readonly kind: "skip";
|
|
7
|
-
readonly runId: string;
|
|
8
|
-
};
|
|
9
|
-
export interface ScheduleProgress {
|
|
10
|
-
readonly everySeconds: number;
|
|
11
|
-
readonly nextAt: number;
|
|
12
|
-
readonly lastSlot: number;
|
|
13
|
-
readonly activeCommandId?: string;
|
|
14
|
-
readonly pending?: PendingSlot;
|
|
15
|
-
}
|
|
1
|
+
import type { ScheduleProgress } from "../schedule-progress.ts";
|
|
2
|
+
export type { PendingSlot, ScheduleProgress } from "../schedule-progress.ts";
|
|
16
3
|
export declare function scheduleJournal(directory: string): Promise<{
|
|
17
4
|
readonly entries: Map<string, ScheduleProgress>;
|
|
18
5
|
readonly save: () => Promise<void>;
|
|
@@ -23,10 +23,68 @@ function isProgress(value) {
|
|
|
23
23
|
const fields = record(value);
|
|
24
24
|
if (fields === undefined)
|
|
25
25
|
return false;
|
|
26
|
-
const { activeCommandId
|
|
26
|
+
const { activeCommandId } = fields;
|
|
27
27
|
return (timing(fields) &&
|
|
28
|
-
(
|
|
29
|
-
(
|
|
28
|
+
control(fields) &&
|
|
29
|
+
history(fields) &&
|
|
30
|
+
pendingProgress(fields) &&
|
|
31
|
+
(activeCommandId === undefined || isCommandId(activeCommandId)));
|
|
32
|
+
}
|
|
33
|
+
function pendingProgress(fields) {
|
|
34
|
+
const { pending, state } = fields;
|
|
35
|
+
if (pending === undefined)
|
|
36
|
+
return true;
|
|
37
|
+
return (state === undefined || state === "active") && pendingSlot(pending);
|
|
38
|
+
}
|
|
39
|
+
function stopped(fields) {
|
|
40
|
+
const { state, stoppedAt, stoppedSlot } = fields;
|
|
41
|
+
if (stoppedAt === undefined && stoppedSlot === undefined)
|
|
42
|
+
return state !== "stopped";
|
|
43
|
+
return (whole(stoppedAt) &&
|
|
44
|
+
whole(stoppedSlot) &&
|
|
45
|
+
stoppedSlot <= Number(fields["lastSlot"]));
|
|
46
|
+
}
|
|
47
|
+
function failures(fields) {
|
|
48
|
+
const { failuresInRow, failedRunIds } = fields;
|
|
49
|
+
return (whole(failuresInRow) &&
|
|
50
|
+
failuresInRow <= 3 &&
|
|
51
|
+
Array.isArray(failedRunIds) &&
|
|
52
|
+
failedRunIds.length === failuresInRow &&
|
|
53
|
+
failedRunIds.every(isRecordKey) &&
|
|
54
|
+
new Set(failedRunIds).size === failuresInRow);
|
|
55
|
+
}
|
|
56
|
+
function history(fields) {
|
|
57
|
+
const stops = fields["stops"];
|
|
58
|
+
if (stops === undefined)
|
|
59
|
+
return true;
|
|
60
|
+
if (!Array.isArray(stops))
|
|
61
|
+
return false;
|
|
62
|
+
let previousSlot = -1;
|
|
63
|
+
for (const item of stops) {
|
|
64
|
+
const stop = record(item);
|
|
65
|
+
if (stop === undefined)
|
|
66
|
+
return false;
|
|
67
|
+
const slot = stop["stoppedSlot"];
|
|
68
|
+
if (!whole(slot) || !whole(stop["stoppedAt"]))
|
|
69
|
+
return false;
|
|
70
|
+
if (slot <= previousSlot || slot > Number(fields["lastSlot"]))
|
|
71
|
+
return false;
|
|
72
|
+
if (!failures({ ...stop, failuresInRow: 3 }))
|
|
73
|
+
return false;
|
|
74
|
+
previousSlot = slot;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
function control(fields) {
|
|
79
|
+
const { state, failuresInRow, failedRunIds } = fields;
|
|
80
|
+
if (state === undefined &&
|
|
81
|
+
failuresInRow === undefined &&
|
|
82
|
+
failedRunIds === undefined)
|
|
83
|
+
return (fields["stoppedAt"] === undefined && fields["stoppedSlot"] === undefined);
|
|
84
|
+
return (["active", "paused", "stopped"].includes(String(state)) &&
|
|
85
|
+
failures(fields) &&
|
|
86
|
+
stopped(fields) &&
|
|
87
|
+
(state !== "stopped" || failuresInRow === 3));
|
|
30
88
|
}
|
|
31
89
|
export async function scheduleJournal(directory) {
|
|
32
90
|
const file = join(directory, "schedules.json");
|
|
@@ -42,7 +100,12 @@ export async function scheduleJournal(directory) {
|
|
|
42
100
|
for (const [workflowId, value] of Object.entries(parsed)) {
|
|
43
101
|
if (!isProgress(value))
|
|
44
102
|
throw new Error("invalid-schedule-state");
|
|
45
|
-
entries.set(workflowId,
|
|
103
|
+
entries.set(workflowId, {
|
|
104
|
+
...value,
|
|
105
|
+
state: value.state ?? "active",
|
|
106
|
+
failuresInRow: value.failuresInRow ?? 0,
|
|
107
|
+
failedRunIds: value.failedRunIds ?? [],
|
|
108
|
+
});
|
|
46
109
|
}
|
|
47
110
|
return {
|
|
48
111
|
entries,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type HarnessSettings } from "../harness-defaults.ts";
|
|
2
|
+
import { type TurnSettings } from "../project-settings.ts";
|
|
3
|
+
import type { SettingChanges } from "../service/workflow-reload.ts";
|
|
4
|
+
import { type TurnProfiles } from "../turn-profile.ts";
|
|
5
|
+
export type SettingDigests = Readonly<Record<string, string>>;
|
|
6
|
+
export interface ReloadedSettings {
|
|
7
|
+
readonly turnSettings: TurnSettings;
|
|
8
|
+
readonly settingDigests: SettingDigests;
|
|
9
|
+
}
|
|
10
|
+
export interface TurnSettingsSource {
|
|
11
|
+
readonly current: () => TurnSettings;
|
|
12
|
+
readonly replace: (next: TurnSettings) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function turnSettingsSource(initial: TurnSettings): TurnSettingsSource;
|
|
15
|
+
export declare function reloadedSettings(output: Readonly<Record<string, unknown>> | undefined): ReloadedSettings | undefined;
|
|
16
|
+
export declare function settingChanges(current: SettingDigests, next: SettingDigests): SettingChanges;
|
|
17
|
+
export declare function keptDigests(current: SettingDigests, change: {
|
|
18
|
+
readonly digests: SettingDigests;
|
|
19
|
+
readonly reloadedFields: readonly string[];
|
|
20
|
+
}): SettingDigests;
|
|
21
|
+
export declare function profileRefusal(settings: HarnessSettings & {
|
|
22
|
+
readonly profiles?: TurnProfiles;
|
|
23
|
+
}, turnSettings: TurnSettings): {
|
|
24
|
+
readonly code: string;
|
|
25
|
+
readonly detail: string;
|
|
26
|
+
} | undefined;
|