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,10 +1,12 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3
3
|
import { mutate } from "../cli/client.js";
|
|
4
|
-
import { record } from "../protocol.js";
|
|
4
|
+
import { record, } from "../protocol.js";
|
|
5
5
|
import { runIdentity } from "../service/submission-handler.js";
|
|
6
6
|
import { configuredSchedules } from "../workflow-schedule.js";
|
|
7
7
|
import { declaredInput } from "./declared-input.js";
|
|
8
|
+
import { finishedScheduleRun } from "../schedule-progress.js";
|
|
9
|
+
import { scheduleControl } from "./schedule-control.js";
|
|
8
10
|
import { scheduleJournal, } from "./schedule-journal.js";
|
|
9
11
|
export function scheduledDeclarations(settings, limits) {
|
|
10
12
|
try {
|
|
@@ -60,6 +62,8 @@ async function pending(settings, entry) {
|
|
|
60
62
|
const { pending: planned, ...rest } = progress;
|
|
61
63
|
if (planned === undefined)
|
|
62
64
|
return progress;
|
|
65
|
+
if (progress.state !== "active")
|
|
66
|
+
throw new Error("invalid-schedule-state");
|
|
63
67
|
const identity = commandId(workflowId, progress.lastSlot);
|
|
64
68
|
if (planned.kind === "skip") {
|
|
65
69
|
const receipt = await settings.submit({
|
|
@@ -86,10 +90,7 @@ async function pending(settings, entry) {
|
|
|
86
90
|
throw new Error(reply.error.code);
|
|
87
91
|
return { ...rest, activeCommandId: identity };
|
|
88
92
|
}
|
|
89
|
-
async function
|
|
90
|
-
if (progress.activeCommandId === undefined)
|
|
91
|
-
return undefined;
|
|
92
|
-
const runId = runIdentity(progress.activeCommandId);
|
|
93
|
+
async function scheduledRunStatus(settings, runId) {
|
|
93
94
|
const reply = await request(settings, {
|
|
94
95
|
operation: "status",
|
|
95
96
|
parameters: { runId },
|
|
@@ -99,45 +100,76 @@ async function active(settings, progress) {
|
|
|
99
100
|
const run = record(reply.result["run"]);
|
|
100
101
|
if (typeof run?.["state"] !== "string")
|
|
101
102
|
throw new Error("invalid-schedule-run");
|
|
103
|
+
return run;
|
|
104
|
+
}
|
|
105
|
+
async function active(settings, progress) {
|
|
106
|
+
if (progress.activeCommandId === undefined)
|
|
107
|
+
return progress;
|
|
108
|
+
const now = (settings.scheduleClock ?? Date.now)();
|
|
109
|
+
const observedAt = settings.observationClock();
|
|
110
|
+
const next = settings.nextObservations.get(progress.activeCommandId) ?? 0;
|
|
111
|
+
const due = progress.state === "active" && now >= progress.nextAt;
|
|
112
|
+
if (!due && observedAt < next)
|
|
113
|
+
return progress;
|
|
114
|
+
const runId = runIdentity(progress.activeCommandId);
|
|
115
|
+
const run = await scheduledRunStatus(settings, runId);
|
|
116
|
+
settings.nextObservations.set(progress.activeCommandId, observedAt + 5000);
|
|
102
117
|
if (run["condition"] === "cancelling")
|
|
103
|
-
return
|
|
104
|
-
|
|
118
|
+
return progress;
|
|
119
|
+
if (!["completed", "failed", "cancelled"].includes(String(run["state"])))
|
|
120
|
+
return progress;
|
|
121
|
+
settings.nextObservations.delete(progress.activeCommandId);
|
|
122
|
+
return finishedScheduleRun(progress, {
|
|
123
|
+
runId,
|
|
124
|
+
status: run,
|
|
125
|
+
now: (settings.scheduleClock ?? Date.now)(),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function advance(settings, declaration) {
|
|
129
|
+
settings.signal.throwIfAborted();
|
|
130
|
+
const { workflowId, schedule } = declaration;
|
|
131
|
+
if (schedule === undefined)
|
|
132
|
+
return;
|
|
133
|
+
let progress = settings.journal.entries.get(workflowId);
|
|
134
|
+
if (progress === undefined)
|
|
135
|
+
throw new Error("missing-schedule-state");
|
|
136
|
+
if (progress.pending !== undefined) {
|
|
137
|
+
progress = await pending(settings, { workflowId, progress });
|
|
138
|
+
settings.journal.entries.set(workflowId, progress);
|
|
139
|
+
await settings.journal.save();
|
|
140
|
+
if (settings.now < progress.nextAt)
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const observed = await active(settings, progress);
|
|
144
|
+
if (observed !== progress) {
|
|
145
|
+
progress = observed;
|
|
146
|
+
settings.journal.entries.set(workflowId, progress);
|
|
147
|
+
await settings.journal.save();
|
|
148
|
+
}
|
|
149
|
+
if (progress.state !== "active" || settings.now < progress.nextAt)
|
|
150
|
+
return;
|
|
151
|
+
const runId = progress.activeCommandId === undefined
|
|
105
152
|
? undefined
|
|
106
|
-
:
|
|
153
|
+
: runIdentity(progress.activeCommandId);
|
|
154
|
+
const planned = runId === undefined
|
|
155
|
+
? { kind: "run", input: schedule.input }
|
|
156
|
+
: { kind: "skip", runId };
|
|
157
|
+
const elapsed = Math.floor((settings.now - progress.nextAt) / (schedule.everySeconds * 1000)) + 1;
|
|
158
|
+
progress = {
|
|
159
|
+
...progress,
|
|
160
|
+
lastSlot: progress.lastSlot + elapsed,
|
|
161
|
+
nextAt: progress.nextAt + elapsed * schedule.everySeconds * 1000,
|
|
162
|
+
pending: planned,
|
|
163
|
+
};
|
|
164
|
+
settings.journal.entries.set(workflowId, progress);
|
|
165
|
+
await settings.journal.save();
|
|
166
|
+
settings.journal.entries.set(workflowId, await pending(settings, { workflowId, progress }));
|
|
167
|
+
await settings.journal.save();
|
|
107
168
|
}
|
|
108
169
|
async function tick(settings, journal) {
|
|
109
170
|
const now = (settings.scheduleClock ?? Date.now)();
|
|
110
|
-
for (const declaration of settings.declarations ?? [])
|
|
111
|
-
settings
|
|
112
|
-
const { workflowId, schedule } = declaration;
|
|
113
|
-
if (schedule === undefined)
|
|
114
|
-
continue;
|
|
115
|
-
let progress = journal.entries.get(workflowId);
|
|
116
|
-
if (progress === undefined)
|
|
117
|
-
throw new Error("missing-schedule-state");
|
|
118
|
-
if (progress.pending !== undefined) {
|
|
119
|
-
progress = await pending(settings, { workflowId, progress });
|
|
120
|
-
journal.entries.set(workflowId, progress);
|
|
121
|
-
await journal.save();
|
|
122
|
-
}
|
|
123
|
-
if (now < progress.nextAt)
|
|
124
|
-
continue;
|
|
125
|
-
const runId = await active(settings, progress);
|
|
126
|
-
const planned = runId === undefined
|
|
127
|
-
? { kind: "run", input: schedule.input }
|
|
128
|
-
: { kind: "skip", runId };
|
|
129
|
-
const elapsed = Math.floor((now - progress.nextAt) / (schedule.everySeconds * 1000)) + 1;
|
|
130
|
-
progress = {
|
|
131
|
-
...progress,
|
|
132
|
-
lastSlot: progress.lastSlot + elapsed,
|
|
133
|
-
nextAt: progress.nextAt + elapsed * schedule.everySeconds * 1000,
|
|
134
|
-
pending: planned,
|
|
135
|
-
};
|
|
136
|
-
journal.entries.set(workflowId, progress);
|
|
137
|
-
await journal.save();
|
|
138
|
-
journal.entries.set(workflowId, await pending(settings, { workflowId, progress }));
|
|
139
|
-
await journal.save();
|
|
140
|
-
}
|
|
171
|
+
for (const declaration of settings.declarations ?? [])
|
|
172
|
+
await advance({ ...settings, journal, now }, declaration);
|
|
141
173
|
}
|
|
142
174
|
async function initialized(settings) {
|
|
143
175
|
const journal = await scheduleJournal(join(settings.directory, "state"));
|
|
@@ -150,36 +182,57 @@ async function initialized(settings) {
|
|
|
150
182
|
if (prior?.everySeconds === schedule.everySeconds)
|
|
151
183
|
continue;
|
|
152
184
|
journal.entries.set(workflowId, {
|
|
153
|
-
...prior
|
|
185
|
+
...(prior ?? {
|
|
186
|
+
lastSlot: 0,
|
|
187
|
+
state: "active",
|
|
188
|
+
failuresInRow: 0,
|
|
189
|
+
failedRunIds: [],
|
|
190
|
+
}),
|
|
154
191
|
everySeconds: schedule.everySeconds,
|
|
155
|
-
lastSlot: prior?.lastSlot ?? 0,
|
|
156
192
|
nextAt: now + schedule.everySeconds * 1000,
|
|
157
193
|
});
|
|
158
194
|
}
|
|
159
|
-
|
|
195
|
+
if (settings.declarations?.some((entry) => entry.schedule !== undefined))
|
|
196
|
+
await journal.save();
|
|
160
197
|
return journal;
|
|
161
198
|
}
|
|
162
199
|
export async function workflowSchedules(settings) {
|
|
163
|
-
|
|
164
|
-
return { stop: () => Promise.resolve() };
|
|
200
|
+
const declarations = settings.declarations ?? [];
|
|
165
201
|
const journal = await initialized(settings);
|
|
166
202
|
const stopping = new AbortController();
|
|
167
203
|
const stopped = () => stopping.signal.aborted;
|
|
204
|
+
const context = {
|
|
205
|
+
...settings,
|
|
206
|
+
signal: stopping.signal,
|
|
207
|
+
nextObservations: new Map(),
|
|
208
|
+
observationClock: settings.scheduleObservationClock ?? (() => performance.now()),
|
|
209
|
+
};
|
|
210
|
+
const control = scheduleControl({
|
|
211
|
+
journal,
|
|
212
|
+
declarations,
|
|
213
|
+
clock: settings.scheduleClock ?? Date.now,
|
|
214
|
+
signal: stopping.signal,
|
|
215
|
+
recoverPending: (entry) => pending(context, entry),
|
|
216
|
+
tick: () => tick(context, journal),
|
|
217
|
+
});
|
|
168
218
|
const running = (async () => {
|
|
169
219
|
while (!stopped()) {
|
|
170
220
|
await delay(250, undefined, { signal: stopping.signal }).catch(() => undefined);
|
|
171
221
|
if (stopped())
|
|
172
222
|
return;
|
|
173
|
-
await tick(
|
|
223
|
+
await control.tick();
|
|
174
224
|
}
|
|
175
225
|
})().catch((error) => {
|
|
176
226
|
if (!stopped())
|
|
177
227
|
process.stderr.write(`Schedules stopped: ${String(error)}\n`);
|
|
228
|
+
stopping.abort();
|
|
178
229
|
});
|
|
179
230
|
return {
|
|
231
|
+
request: control.request,
|
|
180
232
|
stop: async () => {
|
|
181
233
|
stopping.abort();
|
|
182
234
|
await running;
|
|
235
|
+
await control.drain();
|
|
183
236
|
},
|
|
184
237
|
};
|
|
185
238
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function recordedProcessDirectory(processId: number): Promise<string | undefined>;
|
|
2
|
+
interface StopRequest {
|
|
3
|
+
readonly directory: string;
|
|
4
|
+
readonly folder: string;
|
|
5
|
+
readonly signal: AbortSignal;
|
|
6
|
+
readonly stopMilliseconds?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function stopTreeProcesses(request: StopRequest): Promise<boolean>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { readdir, readlink, realpath } from "node:fs/promises";
|
|
3
|
+
import { resolve, sep } from "node:path";
|
|
4
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { writeRecord } from "./operation-journal.js";
|
|
7
|
+
const execute = promisify(execFile);
|
|
8
|
+
async function output(command, arguments_) {
|
|
9
|
+
return (await execute(command, arguments_, {
|
|
10
|
+
encoding: "utf8",
|
|
11
|
+
timeout: 5000,
|
|
12
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
13
|
+
})).stdout;
|
|
14
|
+
}
|
|
15
|
+
async function directories() {
|
|
16
|
+
if (process.platform === "linux") {
|
|
17
|
+
const entries = await readdir("/proc");
|
|
18
|
+
const links = await Promise.all(entries
|
|
19
|
+
.filter((entry) => /^\d+$/.test(entry))
|
|
20
|
+
.map(async (entry) => {
|
|
21
|
+
const directory = await readlink(`/proc/${entry}/cwd`).catch(() => undefined);
|
|
22
|
+
return [Number(entry), directory];
|
|
23
|
+
}));
|
|
24
|
+
return new Map(links.filter((entry) => entry[1] !== undefined));
|
|
25
|
+
}
|
|
26
|
+
const text = await output("lsof", ["-d", "cwd", "-Fpn", "-n", "-P"]);
|
|
27
|
+
const found = new Map();
|
|
28
|
+
let processId = 0;
|
|
29
|
+
for (const line of text.split("\n")) {
|
|
30
|
+
if (line.startsWith("p"))
|
|
31
|
+
processId = Number(line.slice(1));
|
|
32
|
+
if (line.startsWith("n"))
|
|
33
|
+
found.set(processId, line.slice(1));
|
|
34
|
+
}
|
|
35
|
+
return found;
|
|
36
|
+
}
|
|
37
|
+
async function processes() {
|
|
38
|
+
try {
|
|
39
|
+
const text = await output("ps", ["-axo", "pid=,pgid=,uid="]);
|
|
40
|
+
const entries = text
|
|
41
|
+
.trim()
|
|
42
|
+
.split("\n")
|
|
43
|
+
.map((line) => {
|
|
44
|
+
const [processId = 0, group = 0, user = -1] = line
|
|
45
|
+
.trim()
|
|
46
|
+
.split(/\s+/)
|
|
47
|
+
.map(Number);
|
|
48
|
+
return { processId, group, user };
|
|
49
|
+
});
|
|
50
|
+
const working = await directories();
|
|
51
|
+
return entries.map((entry) => {
|
|
52
|
+
const directory = working.get(entry.processId);
|
|
53
|
+
return { ...entry, ...(directory === undefined ? {} : { directory }) };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function inTree(entry, directory) {
|
|
61
|
+
if (entry.processId <= 1 ||
|
|
62
|
+
entry.processId === process.pid ||
|
|
63
|
+
entry.directory === undefined)
|
|
64
|
+
return false;
|
|
65
|
+
const root = resolve(directory);
|
|
66
|
+
return entry.directory === root || entry.directory.startsWith(root + sep);
|
|
67
|
+
}
|
|
68
|
+
export async function recordedProcessDirectory(processId) {
|
|
69
|
+
return (await processes())?.find((entry) => entry.processId === processId)
|
|
70
|
+
?.directory;
|
|
71
|
+
}
|
|
72
|
+
function terminate(entries, request) {
|
|
73
|
+
const { directory, signal } = request;
|
|
74
|
+
const maySignal = (entry) => entry.user === process.getuid?.() && inTree(entry, directory);
|
|
75
|
+
const found = entries.filter(maySignal);
|
|
76
|
+
const groups = new Set();
|
|
77
|
+
for (const entry of found) {
|
|
78
|
+
const safeGroup = entry.group > 1 &&
|
|
79
|
+
entries.filter((other) => other.group === entry.group).every(maySignal);
|
|
80
|
+
const target = safeGroup ? -entry.group : entry.processId;
|
|
81
|
+
if (groups.has(target))
|
|
82
|
+
continue;
|
|
83
|
+
groups.add(target);
|
|
84
|
+
try {
|
|
85
|
+
process.kill(target, signal);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return found.map((entry) => entry.processId);
|
|
92
|
+
}
|
|
93
|
+
async function treeSnapshot(directory) {
|
|
94
|
+
const entries = await processes();
|
|
95
|
+
return entries?.some((entry) => inTree(entry, directory)) === false
|
|
96
|
+
? processes()
|
|
97
|
+
: entries;
|
|
98
|
+
}
|
|
99
|
+
async function waitForTree(request, deadline) {
|
|
100
|
+
while (!request.signal.aborted) {
|
|
101
|
+
const entries = await treeSnapshot(request.directory);
|
|
102
|
+
if (entries === undefined ||
|
|
103
|
+
!entries.some((entry) => inTree(entry, request.directory)) ||
|
|
104
|
+
performance.now() >= deadline)
|
|
105
|
+
return entries;
|
|
106
|
+
await delay(Math.min(250, Math.max(0, deadline - performance.now())));
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
export async function stopTreeProcesses(request) {
|
|
111
|
+
const directory = await realpath(request.directory).catch(() => undefined);
|
|
112
|
+
return directory === undefined
|
|
113
|
+
? false
|
|
114
|
+
: stopCanonicalTree({ ...request, directory });
|
|
115
|
+
}
|
|
116
|
+
async function stopCanonicalTree(request) {
|
|
117
|
+
const entries = await treeSnapshot(request.directory);
|
|
118
|
+
const aborted = () => request.signal.aborted;
|
|
119
|
+
if (entries === undefined || aborted())
|
|
120
|
+
return false;
|
|
121
|
+
const processIds = terminate(entries, {
|
|
122
|
+
directory: request.directory,
|
|
123
|
+
signal: "SIGTERM",
|
|
124
|
+
});
|
|
125
|
+
let remaining = processIds.length === 0
|
|
126
|
+
? entries
|
|
127
|
+
: await waitForTree(request, performance.now() + (request.stopMilliseconds ?? 15_000));
|
|
128
|
+
if (remaining === undefined || aborted())
|
|
129
|
+
return recordCleanup(request, { processIds, remaining });
|
|
130
|
+
const killed = terminate(remaining, {
|
|
131
|
+
directory: request.directory,
|
|
132
|
+
signal: "SIGKILL",
|
|
133
|
+
});
|
|
134
|
+
processIds.push(...killed);
|
|
135
|
+
if (killed.length > 0)
|
|
136
|
+
remaining = await waitForTree(request, performance.now() + 1000);
|
|
137
|
+
return recordCleanup(request, { processIds, remaining });
|
|
138
|
+
}
|
|
139
|
+
async function recordCleanup(request, cleanup) {
|
|
140
|
+
const remainingProcessIds = cleanup.remaining
|
|
141
|
+
?.filter((entry) => inTree(entry, request.directory))
|
|
142
|
+
.map((entry) => entry.processId);
|
|
143
|
+
await writeRecord(request.folder, {
|
|
144
|
+
name: "resume-processes.json",
|
|
145
|
+
value: {
|
|
146
|
+
processIds: [...new Set(cleanup.processIds)],
|
|
147
|
+
remainingProcessIds,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
return !request.signal.aborted && remainingProcessIds?.length === 0;
|
|
151
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type SubmissionContract } from "./submission.ts";
|
|
2
|
-
export declare const doctorCodes: readonly ["git-repository", "node-version", "harnesses", "default-harness", "gh-login", "github-origin", "greptile-review", "settings-files", "runtime-directory", "service", "ticket-command", "next-command", "check-command", "queue-interval", "private-texts"];
|
|
2
|
+
export declare const doctorCodes: readonly ["git-repository", "node-version", "harnesses", "default-harness", "gh-login", "github-origin", "greptile-review", "settings-files", "no-workflow", "runtime-directory", "service", "ticket-command", "next-command", "check-command", "queue-interval", "private-texts", "retention"];
|
|
3
3
|
export type DoctorCode = (typeof doctorCodes)[number];
|
|
4
4
|
export interface DoctorObservation {
|
|
5
|
-
readonly result: "ok" | "fail" | "skip";
|
|
5
|
+
readonly result: "ok" | "warn" | "fail" | "skip";
|
|
6
6
|
readonly detail: string;
|
|
7
7
|
}
|
|
8
8
|
export interface DoctorCheck extends DoctorObservation {
|
|
@@ -14,11 +14,9 @@ export declare const doctorFixes: Readonly<Record<DoctorCode, string>>;
|
|
|
14
14
|
export declare function doctorExitCode(checks: readonly DoctorCheck[]): number;
|
|
15
15
|
export interface DoctorWorkflow {
|
|
16
16
|
readonly queue?: boolean;
|
|
17
|
-
readonly scope: "
|
|
17
|
+
readonly scope: "project" | "user";
|
|
18
18
|
readonly workflowId: string;
|
|
19
19
|
readonly capabilities: readonly string[];
|
|
20
20
|
readonly input?: SubmissionContract;
|
|
21
21
|
}
|
|
22
|
-
export declare function requiredDoctorCodes(workflows: readonly DoctorWorkflow[]
|
|
23
|
-
readonly queueSeconds: string | undefined;
|
|
24
|
-
}): readonly DoctorCode[];
|
|
22
|
+
export declare function requiredDoctorCodes(workflows: readonly DoctorWorkflow[]): readonly DoctorCode[];
|
|
@@ -8,6 +8,7 @@ export const doctorCodes = [
|
|
|
8
8
|
"github-origin",
|
|
9
9
|
"greptile-review",
|
|
10
10
|
"settings-files",
|
|
11
|
+
"no-workflow",
|
|
11
12
|
"runtime-directory",
|
|
12
13
|
"service",
|
|
13
14
|
"ticket-command",
|
|
@@ -15,6 +16,7 @@ export const doctorCodes = [
|
|
|
15
16
|
"check-command",
|
|
16
17
|
"queue-interval",
|
|
17
18
|
"private-texts",
|
|
19
|
+
"retention",
|
|
18
20
|
];
|
|
19
21
|
export const doctorFixes = {
|
|
20
22
|
"git-repository": "Change to the repository, or run: git init",
|
|
@@ -25,6 +27,7 @@ export const doctorFixes = {
|
|
|
25
27
|
"github-origin": "Set a GitHub origin: git remote add origin git@github.com:OWNER/REPO.git || git remote set-url origin git@github.com:OWNER/REPO.git",
|
|
26
28
|
"greptile-review": "Install the Greptile app at https://github.com/apps/greptile, then open a first pull request: gh pr create",
|
|
27
29
|
"settings-files": "Fix the project JSON: ${EDITOR:-vi} .cloving/config.json; for private JSON, edit <config>/cloving/projects/<repository-id>.json",
|
|
30
|
+
"no-workflow": "cloving init",
|
|
28
31
|
"runtime-directory": 'Select a private writable runtime: CLOVING_RUNTIME_DIR="$HOME/.local/state/cloving/doctor/run" cloving doctor',
|
|
29
32
|
service: "Start the service: cloving start",
|
|
30
33
|
"ticket-command": "Set tickets.command to an executable list: ${EDITOR:-vi} .cloving/config.json",
|
|
@@ -32,39 +35,31 @@ export const doctorFixes = {
|
|
|
32
35
|
"check-command": "Set checks.beforeMerge to an executable list: ${EDITOR:-vi} .cloving/config.json",
|
|
33
36
|
"queue-interval": "Set an interval from 10 to 3600: CLOVING_QUEUE_SECONDS=30 cloving doctor",
|
|
34
37
|
"private-texts": `Set a nonblank private text: CLOVING_PRIVATE_TEXTS='["TEXT TO KEEP PRIVATE"]' cloving doctor`,
|
|
38
|
+
retention: "Set a retention period: cloving config set retention.days 30 --private",
|
|
35
39
|
};
|
|
36
40
|
export function doctorExitCode(checks) {
|
|
37
41
|
return checks.some((check) => check.required && check.result !== "ok")
|
|
38
42
|
? 1
|
|
39
43
|
: 0;
|
|
40
44
|
}
|
|
41
|
-
export function requiredDoctorCodes(workflows
|
|
45
|
+
export function requiredDoctorCodes(workflows) {
|
|
42
46
|
const codes = new Set([
|
|
43
47
|
"git-repository",
|
|
44
48
|
"node-version",
|
|
45
49
|
"default-harness",
|
|
46
50
|
"settings-files",
|
|
51
|
+
"no-workflow",
|
|
47
52
|
"runtime-directory",
|
|
48
53
|
]);
|
|
49
54
|
if (workflows.some((workflow) => workflow.capabilities.includes("github"))) {
|
|
50
55
|
codes.add("gh-login");
|
|
51
56
|
codes.add("github-origin");
|
|
52
57
|
}
|
|
53
|
-
|
|
54
|
-
.filter((workflow) => workflow.scope === "bundled")
|
|
55
|
-
.map((workflow) => workflow.workflowId);
|
|
56
|
-
const issue = bundled.includes("develop-issue");
|
|
57
|
-
if (issue)
|
|
58
|
-
codes.add("check-command");
|
|
59
|
-
if (workflows.some((workflow) => workflow.queue === true) ||
|
|
60
|
-
(issue && options.queueSeconds !== undefined)) {
|
|
58
|
+
if (workflows.some((workflow) => workflow.queue === true)) {
|
|
61
59
|
codes.add("next-command");
|
|
62
60
|
codes.add("queue-interval");
|
|
63
61
|
}
|
|
64
|
-
if (workflows.some((workflow) => hasTicketField(workflow.input))
|
|
65
|
-
bundled.some((name) => ["develop-ticket", "develop-issue"].includes(name)))
|
|
62
|
+
if (workflows.some((workflow) => hasTicketField(workflow.input)))
|
|
66
63
|
codes.add("ticket-command");
|
|
67
|
-
if (bundled.includes("develop-prd"))
|
|
68
|
-
codes.add("private-texts");
|
|
69
64
|
return [...codes];
|
|
70
65
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ShellMode } from "./agent-harness-shell.ts";
|
|
2
|
+
import type { HarnessSelection } from "./configuration-change.ts";
|
|
3
|
+
export interface HarnessStartRequest {
|
|
4
|
+
readonly executable: string;
|
|
5
|
+
readonly arguments: readonly string[];
|
|
6
|
+
readonly directory: string;
|
|
7
|
+
readonly environment: Readonly<Record<string, string | undefined>>;
|
|
8
|
+
}
|
|
9
|
+
export declare function harnessStartRequest(entry: HarnessSelection & {
|
|
10
|
+
readonly shellMode?: ShellMode;
|
|
11
|
+
}, context: {
|
|
12
|
+
readonly repository: string;
|
|
13
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
}): HarnessStartRequest;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { shellArguments, shellRunScript, } from "./agent-harness-shell.js";
|
|
2
|
+
const shellStartScript = `
|
|
3
|
+
set +m
|
|
4
|
+
kind=
|
|
5
|
+
if [ -n "\${ZSH_VERSION-}" ]; then
|
|
6
|
+
kind=$(builtin whence -w -- "$1" 2>/dev/null) || kind=
|
|
7
|
+
kind="\${kind##*: }"
|
|
8
|
+
elif [ -n "\${BASH_VERSION-}" ]; then
|
|
9
|
+
kind=$(builtin type -t -- "$1" 2>/dev/null) || kind=
|
|
10
|
+
fi
|
|
11
|
+
case "$kind" in
|
|
12
|
+
function|alias) ;;
|
|
13
|
+
*) printf '%s\\n' 'Open your agent in this repository and tell it: run \`cloving init-prompt\`.' >&2; exit 1 ;;
|
|
14
|
+
esac
|
|
15
|
+
${shellRunScript}
|
|
16
|
+
`;
|
|
17
|
+
export function harnessStartRequest(entry, context) {
|
|
18
|
+
const argumentsList = entry.name === "opencode"
|
|
19
|
+
? ["--prompt", context.message]
|
|
20
|
+
: [context.message];
|
|
21
|
+
const executable = entry.kind === "shell" ? (context.environment["SHELL"] ?? "") : entry.path;
|
|
22
|
+
const args = entry.kind === "shell"
|
|
23
|
+
? [
|
|
24
|
+
...shellArguments(entry.shellMode ?? "login"),
|
|
25
|
+
shellStartScript,
|
|
26
|
+
"cloving-init",
|
|
27
|
+
entry.path,
|
|
28
|
+
...argumentsList,
|
|
29
|
+
]
|
|
30
|
+
: argumentsList;
|
|
31
|
+
return {
|
|
32
|
+
executable,
|
|
33
|
+
arguments: args,
|
|
34
|
+
directory: context.repository,
|
|
35
|
+
environment: context.environment,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CommandWaitState } from "../authority/command-waits.ts";
|
|
2
|
+
import type { CommandWaitRequest, CommandWaitProgress } from "../step-bridge.ts";
|
|
3
|
+
interface WaitName {
|
|
4
|
+
readonly runId: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
}
|
|
7
|
+
interface WaitCall extends WaitName {
|
|
8
|
+
readonly commandId: string;
|
|
9
|
+
}
|
|
10
|
+
interface WaitReceipt {
|
|
11
|
+
readonly kind: string;
|
|
12
|
+
readonly reason?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CommandWaitPorts {
|
|
15
|
+
readonly open: (request: WaitCall & {
|
|
16
|
+
readonly input: string;
|
|
17
|
+
}) => Promise<WaitReceipt>;
|
|
18
|
+
readonly check: (request: WaitCall) => Promise<WaitReceipt>;
|
|
19
|
+
readonly read: (request: WaitName) => Promise<CommandWaitState | undefined>;
|
|
20
|
+
}
|
|
21
|
+
interface WaitHost {
|
|
22
|
+
readonly commandWait?: CommandWaitPorts;
|
|
23
|
+
readonly runStatus: (runId: string) => Promise<string | undefined>;
|
|
24
|
+
readonly subject: () => Promise<{
|
|
25
|
+
readonly runId: string;
|
|
26
|
+
readonly commandId: string;
|
|
27
|
+
} | undefined>;
|
|
28
|
+
readonly stopped: AbortSignal;
|
|
29
|
+
readonly pollMilliseconds: number;
|
|
30
|
+
readonly retryMilliseconds: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function commandWaitBridge(host: WaitHost): {
|
|
33
|
+
openCommandWait: (request: CommandWaitRequest) => Promise<CommandWaitProgress>;
|
|
34
|
+
checkCommandWait: (request: {
|
|
35
|
+
readonly name: string;
|
|
36
|
+
}) => Promise<CommandWaitProgress>;
|
|
37
|
+
};
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import { commandWaitValue, isCommandWaitRequest } from "../command-wait.js";
|
|
3
|
+
function progress(wait) {
|
|
4
|
+
if (wait === undefined)
|
|
5
|
+
return { kind: "refused", reason: "unknown-command-wait" };
|
|
6
|
+
if (wait.state === "waiting")
|
|
7
|
+
return waiting(wait);
|
|
8
|
+
if (wait.state === "timed-out")
|
|
9
|
+
return { kind: "timed-out", reason: "command-wait-timeout" };
|
|
10
|
+
if (wait.state !== "completed")
|
|
11
|
+
return { kind: "failed", reason: wait.reason ?? "command-wait-failed" };
|
|
12
|
+
const value = JSON.parse(wait.result ?? "null");
|
|
13
|
+
return commandWaitValue(value)
|
|
14
|
+
? { kind: "ready", value }
|
|
15
|
+
: { kind: "failed", reason: "command-wait-invalid-output" };
|
|
16
|
+
}
|
|
17
|
+
function refused(receipt) {
|
|
18
|
+
if (["accepted", "duplicate"].includes(receipt.kind))
|
|
19
|
+
return undefined;
|
|
20
|
+
return {
|
|
21
|
+
kind: receipt.kind === "failed" ? "failed" : "refused",
|
|
22
|
+
reason: receipt.reason ?? receipt.kind,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function requested(context, send) {
|
|
26
|
+
const { host, call, retryReasons = ["service-busy"] } = context;
|
|
27
|
+
for (;;) {
|
|
28
|
+
if (host.stopped.aborted)
|
|
29
|
+
await new Promise(() => undefined);
|
|
30
|
+
const receipt = await send();
|
|
31
|
+
if (receipt.kind !== "rejected" ||
|
|
32
|
+
!retryReasons.includes(receipt.reason ?? ""))
|
|
33
|
+
return receipt;
|
|
34
|
+
if (receipt.reason === "command-wait-run-not-running" &&
|
|
35
|
+
!["queued", "running", "waiting_gate", "paused"].includes((await host.runStatus(call.runId)) ?? ""))
|
|
36
|
+
return receipt;
|
|
37
|
+
await delay(host.retryMilliseconds, undefined, {
|
|
38
|
+
signal: host.stopped,
|
|
39
|
+
}).catch(() => undefined);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function settled(context, request) {
|
|
43
|
+
const { host, port } = context;
|
|
44
|
+
for (;;) {
|
|
45
|
+
if (host.stopped.aborted)
|
|
46
|
+
await new Promise(() => undefined);
|
|
47
|
+
const wait = await port.read(request);
|
|
48
|
+
if (wait?.state !== "waiting" || wait.checkOperation === null)
|
|
49
|
+
return progress(wait);
|
|
50
|
+
await delay(host.pollMilliseconds, undefined, {
|
|
51
|
+
signal: host.stopped,
|
|
52
|
+
}).catch(() => undefined);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function commandWaitBridge(host) {
|
|
56
|
+
return {
|
|
57
|
+
openCommandWait: async (request) => {
|
|
58
|
+
if (!isCommandWaitRequest(request))
|
|
59
|
+
return { kind: "refused", reason: "invalid-command-wait-request" };
|
|
60
|
+
const subject = await host.subject();
|
|
61
|
+
const port = host.commandWait;
|
|
62
|
+
if (subject === undefined || port === undefined)
|
|
63
|
+
return { kind: "unavailable", reason: "cloving-host-unavailable" };
|
|
64
|
+
const call = {
|
|
65
|
+
...subject,
|
|
66
|
+
name: request.name,
|
|
67
|
+
input: JSON.stringify(request.input),
|
|
68
|
+
};
|
|
69
|
+
const receipt = await requested({
|
|
70
|
+
host,
|
|
71
|
+
call,
|
|
72
|
+
retryReasons: ["service-busy", "command-wait-run-not-running"],
|
|
73
|
+
}, () => port.open(call));
|
|
74
|
+
return (refused(receipt) ??
|
|
75
|
+
progress(await port.read({ ...subject, name: request.name })));
|
|
76
|
+
},
|
|
77
|
+
checkCommandWait: async (request) => {
|
|
78
|
+
const subject = await host.subject();
|
|
79
|
+
const port = host.commandWait;
|
|
80
|
+
if (subject === undefined || port === undefined)
|
|
81
|
+
return { kind: "unavailable", reason: "cloving-host-unavailable" };
|
|
82
|
+
const call = { ...subject, name: request.name };
|
|
83
|
+
const wait = await port.read(call);
|
|
84
|
+
if (wait?.state !== "waiting")
|
|
85
|
+
return progress(wait);
|
|
86
|
+
if (wait.checkOperation !== null)
|
|
87
|
+
return await settled({ host, port }, call);
|
|
88
|
+
if (wait.nextCheckAt !== null &&
|
|
89
|
+
Date.now() < Math.min(wait.nextCheckAt, wait.deadline))
|
|
90
|
+
return progress(wait);
|
|
91
|
+
const receipt = await requested({ host, call }, () => port.check(call));
|
|
92
|
+
return checkReply(receipt, wait) ?? (await settled({ host, port }, call));
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function checkReply(receipt, wait) {
|
|
97
|
+
if (receipt.reason === "command-wait-timeout")
|
|
98
|
+
return { kind: "timed-out", reason: receipt.reason };
|
|
99
|
+
if (receipt.reason === "command-wait-run-not-running")
|
|
100
|
+
return waiting(wait, Date.now() + 1000);
|
|
101
|
+
if ([
|
|
102
|
+
"command-wait-check-in-flight",
|
|
103
|
+
"command-wait-check-not-due",
|
|
104
|
+
"command-wait-ended",
|
|
105
|
+
].includes(receipt.reason ?? ""))
|
|
106
|
+
return undefined;
|
|
107
|
+
return refused(receipt);
|
|
108
|
+
}
|
|
109
|
+
function waiting(wait, nextCheckAt = wait.nextCheckAt ?? wait.deadline) {
|
|
110
|
+
return {
|
|
111
|
+
kind: "pending",
|
|
112
|
+
deadline: wait.deadline,
|
|
113
|
+
nextCheckAt,
|
|
114
|
+
};
|
|
115
|
+
}
|