cloving 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +235 -206
- package/dist/src/agent-harness-shell.d.ts +2 -1
- package/dist/src/agent-harness-shell.js +8 -5
- package/dist/src/authority/command-wait-checks.d.ts +8 -0
- package/dist/src/authority/command-wait-checks.js +88 -0
- package/dist/src/authority/command-wait-results.d.ts +15 -0
- package/dist/src/authority/command-wait-results.js +73 -0
- package/dist/src/authority/command-wait-view.d.ts +21 -0
- package/dist/src/authority/command-wait-view.js +34 -0
- package/dist/src/authority/command-waits.d.ts +39 -0
- package/dist/src/authority/command-waits.js +97 -0
- package/dist/src/authority/commands.js +22 -1
- package/dist/src/authority/dispatch-decision.d.ts +8 -0
- package/dist/src/authority/dispatch-decision.js +26 -1
- package/dist/src/authority/effect-requests.js +6 -3
- package/dist/src/authority/effect-results.js +4 -2
- package/dist/src/authority/history-state.d.ts +2 -0
- package/dist/src/authority/history-state.js +13 -1
- package/dist/src/authority/instants.d.ts +1 -0
- package/dist/src/authority/instants.js +21 -0
- package/dist/src/authority/reduction-state.d.ts +2 -0
- package/dist/src/authority/reduction-state.js +5 -0
- package/dist/src/authority/reduction.js +24 -0
- package/dist/src/authority/status-input.d.ts +2 -0
- package/dist/src/authority/status.d.ts +2 -0
- package/dist/src/authority/status.js +1 -0
- package/dist/src/authority/stop-sequence.d.ts +1 -0
- package/dist/src/authority/stop-sequence.js +2 -1
- package/dist/src/authority/transitions.d.ts +6 -4
- package/dist/src/authority/transitions.js +7 -0
- package/dist/src/broker/actor/authority-queries.d.ts +2 -1
- package/dist/src/broker/actor/authority-queries.js +14 -5
- package/dist/src/broker/actor/authority-receipts.js +1 -1
- package/dist/src/broker/actor/authority-settings.js +2 -2
- package/dist/src/broker/actor/authority-upgrades.d.ts +19 -2
- package/dist/src/broker/actor/authority-upgrades.js +7 -2
- package/dist/src/broker/actor/delivery-intents.js +2 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
- package/dist/src/broker/actor/effect-delivery.js +15 -2
- package/dist/src/broker/actor/effect-plan.js +11 -2
- package/dist/src/broker/actor/effect-queries.d.ts +4 -0
- package/dist/src/broker/actor/effect-queries.js +9 -1
- package/dist/src/broker/actor/effect-turn.js +2 -0
- package/dist/src/broker/actor/stop-plan.js +9 -3
- package/dist/src/broker/actor/stop-turn.d.ts +2 -0
- package/dist/src/broker/actor/stop-turn.js +24 -11
- package/dist/src/broker/actor/turn-draft.d.ts +1 -0
- package/dist/src/broker/actor/turn-draft.js +4 -0
- package/dist/src/broker/actor/turn-state.js +5 -1
- package/dist/src/broker/authority-admission.js +60 -0
- package/dist/src/broker/authority-restore.d.ts +2 -0
- package/dist/src/broker/authority-restore.js +35 -1
- package/dist/src/broker/command-wait-restore.d.ts +31 -0
- package/dist/src/broker/command-wait-restore.js +86 -0
- package/dist/src/broker/decision-restore.d.ts +1 -1
- package/dist/src/broker/decision-restore.js +1 -0
- package/dist/src/broker/effect-upgrade.d.ts +2 -0
- package/dist/src/broker/effect-upgrade.js +8 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +42 -3
- package/dist/src/cli/chat-stores.d.ts +2 -0
- package/dist/src/cli/chat-stores.js +113 -0
- package/dist/src/cli/client.d.ts +4 -1
- package/dist/src/cli/client.js +9 -3
- package/dist/src/cli/command-requests.d.ts +17 -0
- package/dist/src/cli/command-requests.js +43 -0
- package/dist/src/cli/command-waits.d.ts +9 -0
- package/dist/src/cli/command-waits.js +51 -0
- package/dist/src/cli/commands.js +14 -41
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/doctor-workflows.d.ts +5 -2
- package/dist/src/cli/doctor-workflows.js +12 -7
- package/dist/src/cli/doctor.js +6 -9
- package/dist/src/cli/harness-probes.d.ts +2 -0
- package/dist/src/cli/harness-probes.js +1 -1
- package/dist/src/cli/harness-processes.d.ts +6 -0
- package/dist/src/cli/harness-processes.js +36 -0
- package/dist/src/cli/init-command.d.ts +9 -0
- package/dist/src/cli/init-command.js +52 -0
- package/dist/src/cli/init-prompt-command.d.ts +10 -0
- package/dist/src/cli/init-prompt-command.js +145 -0
- package/dist/src/cli/init-prompt.d.ts +35 -0
- package/dist/src/cli/init-prompt.js +74 -0
- package/dist/src/cli/init-selection.d.ts +13 -0
- package/dist/src/cli/init-selection.js +75 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +37 -7
- package/dist/src/cli/mcp-server.d.ts +1 -0
- package/dist/src/cli/mcp-server.js +156 -0
- package/dist/src/cli/mcp-tools.d.ts +15 -0
- package/dist/src/cli/mcp-tools.js +80 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +17 -30
- package/dist/src/cli/report-ci-jobs.d.ts +23 -0
- package/dist/src/cli/report-ci-jobs.js +103 -0
- package/dist/src/cli/report-ci-usage.d.ts +9 -0
- package/dist/src/cli/report-ci-usage.js +185 -0
- package/dist/src/cli/report-ci.d.ts +13 -0
- package/dist/src/cli/report-ci.js +74 -0
- package/dist/src/cli/report-closures.d.ts +6 -0
- package/dist/src/cli/report-closures.js +97 -0
- package/dist/src/cli/report-flow.d.ts +7 -0
- package/dist/src/cli/report-flow.js +122 -0
- package/dist/src/cli/report-github-reader.d.ts +29 -0
- package/dist/src/cli/report-github-reader.js +157 -0
- package/dist/src/cli/report-github.d.ts +15 -8
- package/dist/src/cli/report-github.js +131 -150
- package/dist/src/cli/report-operator.d.ts +3 -0
- package/dist/src/cli/report-operator.js +40 -0
- package/dist/src/cli/report-ready.d.ts +3 -0
- package/dist/src/cli/report-ready.js +96 -0
- package/dist/src/cli/report-text.d.ts +9 -0
- package/dist/src/cli/report-text.js +33 -0
- package/dist/src/cli/report.d.ts +1 -0
- package/dist/src/cli/report.js +104 -27
- package/dist/src/cli/runtime-arguments.d.ts +2 -1
- package/dist/src/cli/runtime-arguments.js +7 -2
- package/dist/src/cli/schedule-arguments.d.ts +14 -0
- package/dist/src/cli/schedule-arguments.js +26 -0
- package/dist/src/cli/schedule-render.d.ts +22 -0
- package/dist/src/cli/schedule-render.js +73 -0
- package/dist/src/cli/terminal-text.d.ts +3 -0
- package/dist/src/cli/terminal-text.js +28 -0
- package/dist/src/cli/usage-render.d.ts +1 -0
- package/dist/src/cli/usage-render.js +28 -1
- package/dist/src/cli/usage.d.ts +1 -1
- package/dist/src/cli/usage.js +50 -7
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-board-view.js +19 -2
- package/dist/src/cli/watch-board.d.ts +4 -2
- package/dist/src/cli/watch-board.js +53 -43
- package/dist/src/cli/watch-card-forms.d.ts +1 -1
- package/dist/src/cli/watch-card-forms.js +11 -10
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +2 -11
- package/dist/src/cli/watch-header-view.d.ts +0 -5
- package/dist/src/cli/watch-header-view.js +8 -20
- package/dist/src/cli/watch-model.d.ts +4 -1
- package/dist/src/cli/watch-model.js +17 -11
- package/dist/src/cli/watch-page.js +12 -14
- package/dist/src/cli/watch-phases.d.ts +12 -3
- package/dist/src/cli/watch-phases.js +68 -11
- package/dist/src/cli/watch-pr-board.js +1 -1
- package/dist/src/cli/watch-pr-command.d.ts +1 -0
- package/dist/src/cli/watch-pull-request.js +18 -8
- package/dist/src/cli/watch-reads.d.ts +2 -0
- package/dist/src/cli/watch-reads.js +17 -16
- package/dist/src/cli/watch-render.d.ts +14 -0
- package/dist/src/cli/watch-run-input.d.ts +0 -1
- package/dist/src/cli/watch-run-input.js +0 -13
- package/dist/src/cli/watch-server.js +6 -6
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +59 -5
- package/dist/src/command-wait.d.ts +4 -0
- package/dist/src/command-wait.js +45 -0
- package/dist/src/configuration-change.d.ts +7 -0
- package/dist/src/configuration-change.js +14 -0
- package/dist/src/configuration-schema.d.ts +9 -0
- package/dist/src/configuration-schema.js +6 -2
- package/dist/src/daemon/attachment-file.d.ts +6 -0
- package/dist/src/daemon/attachment-file.js +86 -0
- package/dist/src/daemon/attachments.d.ts +14 -0
- package/dist/src/daemon/attachments.js +17 -0
- package/dist/src/daemon/claude-recovery.d.ts +50 -0
- package/dist/src/daemon/claude-recovery.js +204 -0
- package/dist/src/daemon/claude-stream.d.ts +27 -0
- package/dist/src/daemon/claude-stream.js +63 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -25
- package/dist/src/daemon/claude-turn.js +64 -81
- package/dist/src/daemon/claude-worker.d.ts +2 -1
- package/dist/src/daemon/claude-worker.js +124 -122
- package/dist/src/daemon/daemon-adapters.d.ts +2 -0
- package/dist/src/daemon/daemon-adapters.js +26 -2
- package/dist/src/daemon/daemon-loops.d.ts +3 -1
- package/dist/src/daemon/daemon-loops.js +3 -1
- package/dist/src/daemon/daemon.js +14 -6
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +149 -0
- package/dist/src/daemon/github-ci-filters.d.ts +6 -0
- package/dist/src/daemon/github-ci-filters.js +138 -0
- package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
- package/dist/src/daemon/github-ci-workflows.js +148 -0
- package/dist/src/daemon/github-ci.js +22 -4
- package/dist/src/daemon/github-issue-methods.d.ts +2 -0
- package/dist/src/daemon/github-issue-methods.js +37 -2
- package/dist/src/daemon/github-merge-call.d.ts +2 -1
- package/dist/src/daemon/github-merge-call.js +10 -3
- package/dist/src/daemon/github-merge.js +52 -24
- package/dist/src/daemon/github-methods.js +12 -2
- package/dist/src/daemon/github-operation.d.ts +4 -0
- package/dist/src/daemon/github-operation.js +6 -0
- package/dist/src/daemon/github-worker.d.ts +4 -0
- package/dist/src/daemon/github-worker.js +6 -0
- package/dist/src/daemon/issue-queue.d.ts +1 -1
- package/dist/src/daemon/issue-queue.js +16 -11
- package/dist/src/daemon/notify-events.d.ts +6 -0
- package/dist/src/daemon/notify-events.js +84 -0
- package/dist/src/daemon/notify-journal.js +1 -1
- package/dist/src/daemon/notify-message.d.ts +4 -1
- package/dist/src/daemon/notify-message.js +36 -0
- package/dist/src/daemon/notify.d.ts +1 -1
- package/dist/src/daemon/notify.js +5 -77
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/resume-index-lock.d.ts +13 -0
- package/dist/src/daemon/resume-index-lock.js +160 -0
- package/dist/src/daemon/resume-worktree.d.ts +7 -0
- package/dist/src/daemon/resume-worktree.js +29 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -12
- package/dist/src/daemon/retrying-turn.js +98 -172
- package/dist/src/daemon/schedule-control.d.ts +26 -0
- package/dist/src/daemon/schedule-control.js +110 -0
- package/dist/src/daemon/schedule-journal.d.ts +2 -15
- package/dist/src/daemon/schedule-journal.js +67 -4
- package/dist/src/daemon/ticket-registration.d.ts +2 -7
- package/dist/src/daemon/ticket-registration.js +15 -81
- package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
- package/dist/src/daemon/turn-attempt-journal.js +136 -0
- package/dist/src/daemon/turn-attempts.d.ts +47 -0
- package/dist/src/daemon/turn-attempts.js +166 -0
- package/dist/src/daemon/turn-report.d.ts +8 -1
- package/dist/src/daemon/turn-report.js +39 -0
- package/dist/src/daemon/work-tree.d.ts +9 -0
- package/dist/src/daemon/work-tree.js +20 -0
- package/dist/src/daemon/worker-profile.d.ts +8 -0
- package/dist/src/daemon/worker-profile.js +40 -0
- package/dist/src/daemon/workflow-schedules.d.ts +3 -0
- package/dist/src/daemon/workflow-schedules.js +98 -45
- package/dist/src/daemon/worktree-processes.d.ts +9 -0
- package/dist/src/daemon/worktree-processes.js +151 -0
- package/dist/src/doctor-report.d.ts +3 -5
- package/dist/src/doctor-report.js +6 -13
- package/dist/src/harness-start.d.ts +15 -0
- package/dist/src/harness-start.js +37 -0
- package/dist/src/host/command-wait.d.ts +38 -0
- package/dist/src/host/command-wait.js +115 -0
- package/dist/src/host/start-delivery.d.ts +5 -7
- package/dist/src/host/start-delivery.js +3 -15
- package/dist/src/host/step-bridge-host.d.ts +2 -0
- package/dist/src/host/step-bridge-host.js +21 -0
- package/dist/src/operation-identity.d.ts +1 -0
- package/dist/src/operation-identity.js +4 -0
- package/dist/src/private-config.schema.json +40 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +2 -2
- package/dist/src/project-settings.js +3 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/relay/relay-service.d.ts +3 -0
- package/dist/src/relay/relay-service.js +5 -3
- package/dist/src/report-ci.d.ts +164 -0
- package/dist/src/report-ci.js +32 -0
- package/dist/src/report-effects.d.ts +15 -0
- package/dist/src/report-effects.js +212 -0
- package/dist/src/report-flow-types.d.ts +38 -0
- package/dist/src/report-flow-types.js +7 -0
- package/dist/src/report-flow.d.ts +43 -0
- package/dist/src/report-flow.js +193 -0
- package/dist/src/report-operator.d.ts +67 -0
- package/dist/src/report-operator.js +25 -0
- package/dist/src/report-quality.d.ts +221 -0
- package/dist/src/report-quality.js +94 -0
- package/dist/src/report-ready.d.ts +23 -0
- package/dist/src/report-ready.js +117 -0
- package/dist/src/report-statistics.d.ts +2 -1
- package/dist/src/report-statistics.js +40 -4
- package/dist/src/report.d.ts +588 -47
- package/dist/src/report.js +156 -41
- package/dist/src/schedule-progress.d.ts +33 -0
- package/dist/src/schedule-progress.js +45 -0
- package/dist/src/service/active-tickets.js +6 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/replies.d.ts +8 -1
- package/dist/src/service/replies.js +11 -0
- package/dist/src/service/run-handlers.js +22 -2
- package/dist/src/service/run-metadata.d.ts +15 -1
- package/dist/src/service/run-metadata.js +93 -8
- package/dist/src/service/service.d.ts +4 -0
- package/dist/src/service/service.js +8 -8
- package/dist/src/service/submission-handler.js +18 -4
- package/dist/src/service/worker-port.js +9 -1
- package/dist/src/service/worker-totals.d.ts +2 -0
- package/dist/src/service/worker-totals.js +1 -1
- package/dist/src/step-bridge.d.ts +20 -0
- package/dist/src/steps/command-wait.d.ts +12 -0
- package/dist/src/steps/command-wait.js +26 -0
- package/dist/src/steps/open-decision-wait.d.ts +2 -0
- package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
- package/dist/src/steps/review-by-person.js +4 -1
- package/dist/src/steps/wait-for-command.d.ts +3 -0
- package/dist/src/steps/wait-for-command.js +17 -0
- package/dist/src/steps/wait-for-decision.js +1 -1
- package/dist/src/storage/command-wait-rows.d.ts +30 -0
- package/dist/src/storage/command-wait-rows.js +96 -0
- package/dist/src/storage/decision-snapshots.d.ts +8 -1
- package/dist/src/storage/decision-snapshots.js +15 -1
- package/dist/src/storage/domain-changes.d.ts +2 -0
- package/dist/src/storage/domain-changes.js +3 -0
- package/dist/src/storage/domain-schema.d.ts +13 -1
- package/dist/src/storage/domain-schema.js +31 -4
- package/dist/src/storage/effect-schema.d.ts +1 -0
- package/dist/src/storage/effect-schema.js +5 -0
- package/dist/src/testing-requests.d.ts +15 -0
- package/dist/src/testing-requests.js +93 -0
- package/dist/src/testing.d.ts +4 -10
- package/dist/src/testing.js +33 -86
- package/dist/src/worker-usage.d.ts +1 -0
- package/dist/src/worker-usage.js +3 -0
- package/dist/src/workflow-candidate.d.ts +1 -0
- package/dist/src/workflow-candidate.js +12 -1
- package/dist/src/workflow-contracts.d.ts +1 -0
- package/dist/src/workflow-contracts.js +9 -2
- package/dist/src/workflow-discovery.d.ts +2 -13
- package/dist/src/workflow-discovery.js +1 -13
- package/dist/src/workflow-refusals.js +0 -1
- package/dist/src/workflows.d.ts +1 -1
- package/dist/src/workflows.js +1 -1
- package/dist/tools/red-green-command.d.ts +1 -0
- package/dist/tools/red-green-command.js +174 -0
- package/dist/tools/red-green-process.d.ts +10 -0
- package/dist/tools/red-green-process.js +59 -0
- package/dist/tools/self-host-processes.d.ts +2 -0
- package/dist/tools/self-host-processes.js +32 -13
- package/dist/tools/self-host-project.js +13 -78
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +42 -10
- package/dist/tools/template-command.d.ts +1 -0
- package/dist/tools/template-command.js +160 -0
- package/dist/tools/template-copy.d.ts +11 -0
- package/dist/tools/template-copy.js +130 -0
- package/dist/tools/template-files.d.ts +17 -0
- package/dist/tools/template-files.js +74 -0
- package/dist/tools/workflow-bundles.js +1 -0
- package/dist/tools/workflow-candidate-counts.js +2 -2
- package/dist/tools/workflow-candidate-shape.d.ts +3 -0
- package/dist/tools/workflow-candidate-shape.js +90 -0
- package/dist/tools/workflow-candidate-source.js +15 -1
- package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
- package/dist/tools/workflow-candidate-syntax.js +24 -94
- package/dist/tools/workflow-command.js +1 -2
- package/dist/tools/workflow-folders.d.ts +2 -3
- package/dist/tools/workflow-folders.js +1 -1
- package/package.json +16 -8
- package/templates/develop/README.md +12 -0
- package/templates/develop/develop/flow-tests.ts +37 -0
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/turn.ts +2 -1
- package/templates/idea-to-issue/README.md +27 -0
- package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
- package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
- package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
- package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
- package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
- package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
- package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
- package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
- package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
- package/templates/idea-to-issue/idea-to-issue.ts +49 -0
- package/templates/idea-to-issue/template.json +81 -0
- package/templates/review-day/README.md +97 -0
- package/templates/review-day/review-day/critique.ts +58 -0
- package/templates/review-day/review-day/decision.ts +29 -0
- package/templates/review-day/review-day/facts.ts +69 -0
- package/templates/review-day/review-day/label.ts +29 -0
- package/templates/review-day/review-day/next.ts +28 -0
- package/templates/review-day/review-day/post.ts +27 -0
- package/templates/review-day/review-day/report.ts +98 -0
- package/templates/review-day/review-day/rules.ts +12 -0
- package/templates/review-day/review-day/scenarios.ts +76 -0
- package/templates/review-day/review-day/turn.ts +73 -0
- package/templates/review-day/review-day.declaration.json +16 -0
- package/templates/review-day/review-day.test.ts +362 -0
- package/templates/review-day/review-day.ts +37 -0
- package/templates/review-day/template.json +56 -0
- package/dist/src/cli/watch-start-view.d.ts +0 -18
- package/dist/src/cli/watch-start-view.js +0 -77
- package/dist/src/steps/decision-gate.d.ts +0 -3
- package/dist/workflows/develop-prd.d.ts +0 -7
- package/dist/workflows/develop-prd.js +0 -165
- package/dist/workflows/develop-ticket.d.ts +0 -9
- package/dist/workflows/develop-ticket.js +0 -207
- package/dist/workflows/issue-labels.d.ts +0 -16
- package/dist/workflows/issue-labels.js +0 -70
- package/dist/workflows/ticket-prompts.d.ts +0 -35
- package/dist/workflows/ticket-prompts.js +0 -147
|
@@ -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,5 +1,5 @@
|
|
|
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"];
|
|
3
3
|
export type DoctorCode = (typeof doctorCodes)[number];
|
|
4
4
|
export interface DoctorObservation {
|
|
5
5
|
readonly result: "ok" | "fail" | "skip";
|
|
@@ -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",
|
|
@@ -25,6 +26,7 @@ export const doctorFixes = {
|
|
|
25
26
|
"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
27
|
"greptile-review": "Install the Greptile app at https://github.com/apps/greptile, then open a first pull request: gh pr create",
|
|
27
28
|
"settings-files": "Fix the project JSON: ${EDITOR:-vi} .cloving/config.json; for private JSON, edit <config>/cloving/projects/<repository-id>.json",
|
|
29
|
+
"no-workflow": "cloving init",
|
|
28
30
|
"runtime-directory": 'Select a private writable runtime: CLOVING_RUNTIME_DIR="$HOME/.local/state/cloving/doctor/run" cloving doctor',
|
|
29
31
|
service: "Start the service: cloving start",
|
|
30
32
|
"ticket-command": "Set tickets.command to an executable list: ${EDITOR:-vi} .cloving/config.json",
|
|
@@ -38,33 +40,24 @@ export function doctorExitCode(checks) {
|
|
|
38
40
|
? 1
|
|
39
41
|
: 0;
|
|
40
42
|
}
|
|
41
|
-
export function requiredDoctorCodes(workflows
|
|
43
|
+
export function requiredDoctorCodes(workflows) {
|
|
42
44
|
const codes = new Set([
|
|
43
45
|
"git-repository",
|
|
44
46
|
"node-version",
|
|
45
47
|
"default-harness",
|
|
46
48
|
"settings-files",
|
|
49
|
+
"no-workflow",
|
|
47
50
|
"runtime-directory",
|
|
48
51
|
]);
|
|
49
52
|
if (workflows.some((workflow) => workflow.capabilities.includes("github"))) {
|
|
50
53
|
codes.add("gh-login");
|
|
51
54
|
codes.add("github-origin");
|
|
52
55
|
}
|
|
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)) {
|
|
56
|
+
if (workflows.some((workflow) => workflow.queue === true)) {
|
|
61
57
|
codes.add("next-command");
|
|
62
58
|
codes.add("queue-interval");
|
|
63
59
|
}
|
|
64
|
-
if (workflows.some((workflow) => hasTicketField(workflow.input))
|
|
65
|
-
bundled.some((name) => ["develop-ticket", "develop-issue"].includes(name)))
|
|
60
|
+
if (workflows.some((workflow) => hasTicketField(workflow.input)))
|
|
66
61
|
codes.add("ticket-command");
|
|
67
|
-
if (bundled.includes("develop-prd"))
|
|
68
|
-
codes.add("private-texts");
|
|
69
62
|
return [...codes];
|
|
70
63
|
}
|
|
@@ -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
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { type TaggedRun } from "./world-runs.ts";
|
|
2
|
-
export type WorkflowFunction = (input: unknown
|
|
3
|
-
export interface
|
|
4
|
-
readonly gateId
|
|
5
|
-
readonly decision
|
|
6
|
-
readonly answer
|
|
7
|
-
}
|
|
8
|
-
export interface RunIntent extends Partial<Continuation> {
|
|
2
|
+
export type WorkflowFunction = (input: unknown) => Promise<unknown>;
|
|
3
|
+
export interface RunIntent {
|
|
4
|
+
readonly gateId?: string;
|
|
5
|
+
readonly decision?: string;
|
|
6
|
+
readonly answer?: string | null;
|
|
9
7
|
readonly kind: string;
|
|
10
8
|
readonly runId: string;
|
|
11
9
|
readonly operationId: string;
|
|
@@ -17,27 +17,15 @@ async function reconciled(parts, intent) {
|
|
|
17
17
|
evidence: found.map((run) => `world-run:${run.receipt}`).join(" "),
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
async function continuation(parts, intent) {
|
|
21
|
-
const { kind, gateId, decision, answer } = intent;
|
|
22
|
-
if (kind === "start-run")
|
|
23
|
-
return undefined;
|
|
24
|
-
if (kind !== "continue-run" || gateId === undefined || decision === undefined)
|
|
25
|
-
throw new Error(`unsupported-intent: ${kind}`);
|
|
26
|
-
if (answer === undefined || answer === null)
|
|
27
|
-
return { gateId, decision, answer: null };
|
|
28
|
-
const text = await parts.document(answer);
|
|
29
|
-
if (text === undefined)
|
|
30
|
-
throw new Error(`answer-not-available: ${gateId}`);
|
|
31
|
-
return { gateId, decision, answer: text };
|
|
32
|
-
}
|
|
33
20
|
async function delivered(parts, intent) {
|
|
34
|
-
|
|
21
|
+
if (intent.kind !== "start-run")
|
|
22
|
+
throw new Error(`unsupported-intent: ${intent.kind}`);
|
|
35
23
|
const workflow = await parts.workflow(intent);
|
|
36
24
|
const input = await parts.input(intent.runId);
|
|
37
25
|
if (workflow === undefined || input === undefined)
|
|
38
26
|
throw new Error(`start-not-available: ${intent.runId}`);
|
|
39
27
|
const argument = JSON.parse(input);
|
|
40
|
-
const started = await start(workflow, [argument
|
|
28
|
+
const started = await start(workflow, [argument], {
|
|
41
29
|
attributes: {
|
|
42
30
|
[runTag]: intent.runId,
|
|
43
31
|
[operationTag]: intent.operationId,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CommandWaitPorts } from "./command-wait.ts";
|
|
1
2
|
import { type GateOpening, type GateReceipt, type WaitRegistration } from "./gate-bridge.ts";
|
|
2
3
|
export type { GateOpening, GateReceipt, WaitRegistration, } from "./gate-bridge.ts";
|
|
3
4
|
import { type RunWaitPorts } from "./run-wait.ts";
|
|
@@ -41,6 +42,7 @@ export interface BridgeTiming {
|
|
|
41
42
|
}
|
|
42
43
|
export declare const bridgeTiming: BridgeTiming;
|
|
43
44
|
export interface BridgePorts {
|
|
45
|
+
readonly commandWait?: CommandWaitPorts;
|
|
44
46
|
readonly decisionReceived?: (runId: string, gateId: string) => Promise<boolean>;
|
|
45
47
|
readonly runWait?: RunWaitPorts;
|
|
46
48
|
readonly call: () => StepCall;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { commandWaitBridge } from "./command-wait.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3
4
|
import { getStepMetadata, getWorkflowMetadata } from "workflow";
|
|
@@ -155,9 +156,29 @@ async function gate(hold, request) {
|
|
|
155
156
|
return { kind: "unavailable", reason: "unknown-world-run" };
|
|
156
157
|
return await openBridgeGate(hold.ports, subject);
|
|
157
158
|
}
|
|
159
|
+
function hostCommandWait(hold) {
|
|
160
|
+
return commandWaitBridge({
|
|
161
|
+
...(hold.ports.commandWait === undefined
|
|
162
|
+
? {}
|
|
163
|
+
: { commandWait: hold.ports.commandWait }),
|
|
164
|
+
stopped: hold.ports.stopped,
|
|
165
|
+
pollMilliseconds: hold.timing.pollMilliseconds,
|
|
166
|
+
retryMilliseconds: hold.timing.retryMilliseconds,
|
|
167
|
+
runStatus: async (runId) => (await hold.ports.state()).runs[runId]?.status,
|
|
168
|
+
subject: async () => {
|
|
169
|
+
const call = hold.ports.call();
|
|
170
|
+
const world = await located(hold, call.worldRunId);
|
|
171
|
+
if (world === undefined)
|
|
172
|
+
return undefined;
|
|
173
|
+
await inWork(hold, world.runId);
|
|
174
|
+
return { runId: world.runId, commandId: transportOf(call) };
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
}
|
|
158
178
|
export function stepBridge(ports) {
|
|
159
179
|
const hold = { ports, timing: ports.timing ?? bridgeTiming };
|
|
160
180
|
return {
|
|
181
|
+
...hostCommandWait(hold),
|
|
161
182
|
effect: (request) => effect(hold, request),
|
|
162
183
|
gate: (request) => gate(hold, request),
|
|
163
184
|
waitForDecision: async (request) => {
|
|
@@ -48,6 +48,10 @@ export function operationScope(operationId) {
|
|
|
48
48
|
return null;
|
|
49
49
|
return { run, operation };
|
|
50
50
|
}
|
|
51
|
+
export function operationPhase(operationId) {
|
|
52
|
+
const [marker, , , phase] = parsedList(operationId);
|
|
53
|
+
return marker === "cloving-operation" && isComponent(phase) ? phase : null;
|
|
54
|
+
}
|
|
51
55
|
function parsedList(text) {
|
|
52
56
|
try {
|
|
53
57
|
const value = JSON.parse(text);
|
|
@@ -19,6 +19,42 @@
|
|
|
19
19
|
"type": "string",
|
|
20
20
|
"pattern": "\\S"
|
|
21
21
|
}
|
|
22
|
+
},
|
|
23
|
+
"redGreen": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"test": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"minItems": 1,
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^[^\\u0000]+$"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"testFiles": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"pattern": "^[^\\u0000]+$"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"prepare": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"minItems": 1,
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"pattern": "^[^\\u0000]+$"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"assertionPattern": {
|
|
50
|
+
"type": "string"
|
|
51
|
+
},
|
|
52
|
+
"skipPattern": {
|
|
53
|
+
"type": "string"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"required": ["test", "testFiles"],
|
|
57
|
+
"additionalProperties": false
|
|
22
58
|
}
|
|
23
59
|
},
|
|
24
60
|
"additionalProperties": false
|
|
@@ -49,6 +85,10 @@
|
|
|
49
85
|
"minimum": 10,
|
|
50
86
|
"maximum": 3600
|
|
51
87
|
},
|
|
88
|
+
"dailySpendLimitUsd": {
|
|
89
|
+
"type": "number",
|
|
90
|
+
"exclusiveMinimum": 0
|
|
91
|
+
},
|
|
52
92
|
"lanes": {
|
|
53
93
|
"type": "integer",
|
|
54
94
|
"minimum": 1,
|
|
@@ -19,6 +19,42 @@
|
|
|
19
19
|
"type": "string",
|
|
20
20
|
"pattern": "\\S"
|
|
21
21
|
}
|
|
22
|
+
},
|
|
23
|
+
"redGreen": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"test": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"minItems": 1,
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^[^\\u0000]+$"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"testFiles": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"pattern": "^[^\\u0000]+$"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"prepare": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"minItems": 1,
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"pattern": "^[^\\u0000]+$"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"assertionPattern": {
|
|
50
|
+
"type": "string"
|
|
51
|
+
},
|
|
52
|
+
"skipPattern": {
|
|
53
|
+
"type": "string"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"required": ["test", "testFiles"],
|
|
57
|
+
"additionalProperties": false
|
|
22
58
|
}
|
|
23
59
|
},
|
|
24
60
|
"additionalProperties": false
|
|
@@ -49,6 +85,10 @@
|
|
|
49
85
|
"minimum": 10,
|
|
50
86
|
"maximum": 3600
|
|
51
87
|
},
|
|
88
|
+
"dailySpendLimitUsd": {
|
|
89
|
+
"type": "number",
|
|
90
|
+
"exclusiveMinimum": 0
|
|
91
|
+
},
|
|
52
92
|
"lanes": {
|
|
53
93
|
"type": "integer",
|
|
54
94
|
"minimum": 1,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type Configuration } from "./configuration-schema.ts";
|
|
1
|
+
import { type Configuration, type RedGreenSettings } from "./configuration-schema.ts";
|
|
2
2
|
import type { TurnProfiles } from "./turn-profile.ts";
|
|
3
3
|
import type { TokenPrices } from "./token-prices.ts";
|
|
4
4
|
export type SettingSource = "environment" | "private" | "project";
|
|
5
|
-
export type SettingValue = string | number | readonly string[] | TurnProfiles | TokenPrices;
|
|
5
|
+
export type SettingValue = string | number | readonly string[] | TurnProfiles | TokenPrices | RedGreenSettings;
|
|
6
6
|
export declare const settingVariables: Readonly<Record<string, string>>;
|
|
7
7
|
export declare function absoluteWorkflowFolder(folder: string | undefined): string | undefined;
|
|
8
8
|
export declare function configurationRoot(environment: Readonly<NodeJS.ProcessEnv>, home: string): string;
|