cloving 1.2.0 → 1.3.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 +525 -185
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +1 -0
- package/dist/src/authority/commands.js +24 -4
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +6 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +7 -1
- package/dist/src/broker/actor/authority-queries.js +17 -2
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +4 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +22 -9
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +2 -1
- package/dist/src/cli/render.js +44 -28
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +70 -44
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +1 -1
- package/dist/src/cli/watch-board-view.js +8 -2
- package/dist/src/cli/watch-board.js +23 -10
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +7 -2
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.js +17 -4
- package/dist/src/cli/watch-page.js +48 -12
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pull-request.d.ts +3 -1
- package/dist/src/cli/watch-pull-request.js +4 -0
- package/dist/src/cli/watch-render.d.ts +9 -1
- package/dist/src/cli/watch-server.js +23 -5
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +37 -1
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +6 -20
- package/dist/src/cli/watch-view.js +14 -106
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +19 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -3
- package/dist/src/daemon/claude-worker.js +65 -76
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +2 -33
- package/dist/src/daemon/daemon.js +126 -132
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +1 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.js +89 -8
- package/dist/src/daemon/github-merge-call.d.ts +2 -0
- package/dist/src/daemon/github-merge.js +7 -3
- package/dist/src/daemon/github-methods.js +10 -0
- package/dist/src/daemon/github-operation.d.ts +1 -0
- package/dist/src/daemon/github-retry.js +8 -44
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +3 -26
- package/dist/src/daemon/notify.js +2 -1
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -0
- package/dist/src/daemon/retrying-turn.js +108 -30
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-registration.d.ts +5 -7
- package/dist/src/daemon/ticket-registration.js +85 -40
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +5 -0
- package/dist/src/execution-pin.js +67 -4
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +1 -1
- package/dist/src/host/start-delivery.js +10 -3
- package/dist/src/host/step-bridge-host.d.ts +6 -20
- package/dist/src/host/step-bridge-host.js +44 -58
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/registry.d.ts +16 -3
- package/dist/src/service/registry.js +34 -3
- package/dist/src/service/replies.d.ts +9 -1
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +14 -55
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +18 -2
- package/dist/src/service/service.js +23 -7
- package/dist/src/service/submission-handler.d.ts +0 -1
- package/dist/src/service/submission-handler.js +6 -34
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +8 -23
- package/dist/src/step-bridge.d.ts +23 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/token-prices.d.ts +12 -4
- package/dist/src/token-prices.js +15 -2
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +16 -0
- package/dist/src/worker-usage.js +57 -0
- package/dist/src/workflow-admission.d.ts +5 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +47 -5
- package/dist/src/workflow-declaration.d.ts +21 -3
- package/dist/src/workflow-declaration.js +77 -9
- package/dist/src/workflow-discovery.d.ts +2 -1
- package/dist/src/workflow-discovery.js +4 -1
- package/dist/src/workflow-refusals.js +3 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +11 -1
- package/dist/src/workflows.js +8 -0
- package/dist/tools/admit-workflow.d.ts +1 -0
- package/dist/tools/admit-workflow.js +18 -5
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +4 -0
- package/dist/tools/self-host-project.js +61 -14
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +86 -61
- package/dist/tools/workflow-candidate-counts.d.ts +6 -2
- package/dist/tools/workflow-candidate-counts.js +31 -16
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +2 -0
- package/dist/tools/workflow-candidate-program.js +36 -8
- package/dist/tools/workflow-candidate-source.js +77 -15
- package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
- package/dist/tools/workflow-candidate-syntax.js +70 -26
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +1 -0
- package/dist/tools/workflow-folder-capture.js +47 -2
- package/dist/tools/workflow-folders.d.ts +17 -1
- package/dist/tools/workflow-folders.js +59 -6
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-ticket.js +1 -1
- package/dist/workflows/ticket-prompts.js +5 -1
- package/package.json +46 -4
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -42
- package/dist/src/chats/analysis-batches.js +0 -97
- package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
- package/dist/src/chats/analysis-checkpoint.js +0 -31
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -18
- package/dist/src/chats/analysis-input.js +0 -97
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-merge.d.ts +0 -16
- package/dist/src/chats/analysis-merge.js +0 -134
- package/dist/src/chats/analysis-prompt.d.ts +0 -18
- package/dist/src/chats/analysis-prompt.js +0 -42
- package/dist/src/chats/analysis-proposal.d.ts +0 -4
- package/dist/src/chats/analysis-proposal.js +0 -41
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -4
- package/dist/src/chats/analysis-shape.js +0 -235
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/reference-mapping.d.ts +0 -16
- package/dist/src/chats/reference-mapping.js +0 -153
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
- package/dist/src/chats/workflow-generation-projection.js +0 -75
- package/dist/src/chats/workflow-generation-source.d.ts +0 -25
- package/dist/src/chats/workflow-generation-source.js +0 -124
- package/dist/src/chats/workflow-generation-text.d.ts +0 -23
- package/dist/src/chats/workflow-generation-text.js +0 -74
- package/dist/src/chats/workflow-generation.d.ts +0 -69
- package/dist/src/chats/workflow-generation.js +0 -142
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -20
- package/dist/src/daemon/analysis-worker.js +0 -271
- package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
- package/dist/src/daemon/chats-batch-binding.js +0 -99
- package/dist/src/daemon/chats-capture.d.ts +0 -18
- package/dist/src/daemon/chats-capture.js +0 -194
- package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
- package/dist/src/daemon/chats-checkpoints.js +0 -186
- package/dist/src/daemon/chats-files.d.ts +0 -42
- package/dist/src/daemon/chats-files.js +0 -252
- package/dist/src/daemon/chats-follow-up.d.ts +0 -38
- package/dist/src/daemon/chats-follow-up.js +0 -180
- package/dist/src/daemon/chats-question.d.ts +0 -15
- package/dist/src/daemon/chats-question.js +0 -93
- package/dist/src/daemon/chats-worker.d.ts +0 -13
- package/dist/src/daemon/chats-worker.js +0 -201
- package/dist/workflows/analyze-chats.d.ts +0 -15
- package/dist/workflows/analyze-chats.declaration.json +0 -22
- package/dist/workflows/analyze-chats.js +0 -250
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
interface RunIntent {
|
|
2
|
+
readonly runId: string;
|
|
3
|
+
readonly gateId?: string;
|
|
4
|
+
readonly decision?: string;
|
|
5
|
+
readonly answer?: string | null;
|
|
6
|
+
}
|
|
7
|
+
interface ResumeParts {
|
|
8
|
+
readonly runs: () => Promise<readonly {
|
|
9
|
+
readonly operationId: string | null;
|
|
10
|
+
readonly receipt: string;
|
|
11
|
+
}[]>;
|
|
12
|
+
readonly document: (digest: string) => Promise<string | undefined>;
|
|
13
|
+
}
|
|
14
|
+
export declare function reconciledDecision(parts: ResumeParts, intent: RunIntent): Promise<{
|
|
15
|
+
readonly kind: "accepted";
|
|
16
|
+
readonly receipt: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "absent";
|
|
19
|
+
}>;
|
|
20
|
+
export declare function deliveredDecision(parts: ResumeParts, request: {
|
|
21
|
+
readonly intent: RunIntent;
|
|
22
|
+
readonly signal: AbortSignal | undefined;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
readonly receipt: string;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function stoppedDecision(parts: ResumeParts & {
|
|
27
|
+
readonly cancel: (receipt: string) => Promise<string>;
|
|
28
|
+
}, intent: RunIntent): Promise<{
|
|
29
|
+
readonly kind: "stopped";
|
|
30
|
+
readonly receipt: string;
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: "unknown";
|
|
33
|
+
readonly evidence: string;
|
|
34
|
+
}>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { resumeHook } from "workflow/api";
|
|
2
|
+
import { getWorld } from "workflow/runtime";
|
|
3
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4
|
+
import { decisionToken } from "../decision-wait.js";
|
|
5
|
+
import { namesRunIntent } from "../authority/operations.js";
|
|
6
|
+
async function runSubject(receipt, token) {
|
|
7
|
+
const world = await getWorld();
|
|
8
|
+
let page = await world.events.list({
|
|
9
|
+
runId: receipt,
|
|
10
|
+
resolveData: "none",
|
|
11
|
+
pagination: { limit: 1000, sortOrder: "asc" },
|
|
12
|
+
});
|
|
13
|
+
const events = [...page.data];
|
|
14
|
+
while (page.hasMore && page.cursor !== null) {
|
|
15
|
+
page = await world.events.list({
|
|
16
|
+
runId: receipt,
|
|
17
|
+
resolveData: "none",
|
|
18
|
+
pagination: { limit: 1000, sortOrder: "asc", cursor: page.cursor },
|
|
19
|
+
});
|
|
20
|
+
events.push(...page.data);
|
|
21
|
+
}
|
|
22
|
+
const created = events.find((event) => event.eventType === "hook_created" && event.eventData.token === token);
|
|
23
|
+
const hookId = created?.correlationId;
|
|
24
|
+
return {
|
|
25
|
+
runId: receipt,
|
|
26
|
+
token,
|
|
27
|
+
hookId,
|
|
28
|
+
received: hookId !== undefined &&
|
|
29
|
+
events.some((event) => event.eventType === "hook_received" && event.correlationId === hookId),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function subject(parts, intent) {
|
|
33
|
+
if (intent.gateId === undefined)
|
|
34
|
+
throw new Error("missing-decision-gate");
|
|
35
|
+
const token = decisionToken(intent.runId, intent.gateId);
|
|
36
|
+
const runs = (await parts.runs()).filter((run) => namesRunIntent(run.operationId ?? "", intent.runId));
|
|
37
|
+
const latest = runs.at(-1);
|
|
38
|
+
if (latest === undefined)
|
|
39
|
+
throw new Error("missing-decision-run");
|
|
40
|
+
const matches = [];
|
|
41
|
+
for (const run of runs) {
|
|
42
|
+
const found = await runSubject(run.receipt, token);
|
|
43
|
+
if (found.hookId !== undefined)
|
|
44
|
+
matches.push(found);
|
|
45
|
+
}
|
|
46
|
+
if (matches.length > 1)
|
|
47
|
+
throw new Error("conflicting-decision-hooks");
|
|
48
|
+
return (matches[0] ?? {
|
|
49
|
+
runId: latest.receipt,
|
|
50
|
+
token,
|
|
51
|
+
hookId: undefined,
|
|
52
|
+
received: false,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export async function reconciledDecision(parts, intent) {
|
|
56
|
+
const found = await subject(parts, intent);
|
|
57
|
+
return found.received
|
|
58
|
+
? { kind: "accepted", receipt: found.runId }
|
|
59
|
+
: { kind: "absent" };
|
|
60
|
+
}
|
|
61
|
+
export async function deliveredDecision(parts, request) {
|
|
62
|
+
const { intent, signal } = request;
|
|
63
|
+
let found = await subject(parts, intent);
|
|
64
|
+
while (!found.received && found.hookId === undefined) {
|
|
65
|
+
await delay(20, undefined, signal === undefined ? {} : { signal });
|
|
66
|
+
found = await subject(parts, intent);
|
|
67
|
+
}
|
|
68
|
+
if (found.received)
|
|
69
|
+
return { receipt: found.runId };
|
|
70
|
+
if (intent.decision === undefined)
|
|
71
|
+
throw new Error("missing-decision");
|
|
72
|
+
const answer = intent.answer === undefined || intent.answer === null
|
|
73
|
+
? null
|
|
74
|
+
: await parts.document(intent.answer);
|
|
75
|
+
if (answer === undefined)
|
|
76
|
+
throw new Error("missing-decision-answer");
|
|
77
|
+
await resumeHook(found.token, { decision: intent.decision, answer });
|
|
78
|
+
return { receipt: found.runId };
|
|
79
|
+
}
|
|
80
|
+
export async function stoppedDecision(parts, intent) {
|
|
81
|
+
const found = await subject(parts, intent);
|
|
82
|
+
const status = await parts.cancel(found.runId);
|
|
83
|
+
return ["cancelled", "completed", "failed"].includes(status)
|
|
84
|
+
? { kind: "stopped", receipt: found.runId }
|
|
85
|
+
: { kind: "unknown", evidence: `world-run:${found.runId} ${status}` };
|
|
86
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DecisionWait, GateRequest, GateResult } from "../step-bridge.ts";
|
|
2
|
+
export interface GateReceipt {
|
|
3
|
+
readonly kind: string;
|
|
4
|
+
readonly reason?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GateOpening {
|
|
7
|
+
readonly waitMode?: "hook";
|
|
8
|
+
readonly runId: string;
|
|
9
|
+
readonly commandId: string;
|
|
10
|
+
readonly expectedRevision: number;
|
|
11
|
+
readonly gateId: string;
|
|
12
|
+
readonly kind: "question" | "approval";
|
|
13
|
+
readonly prompt: string;
|
|
14
|
+
readonly subject: string;
|
|
15
|
+
readonly expiresAt?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface WaitRegistration {
|
|
18
|
+
readonly runId: string;
|
|
19
|
+
readonly commandId: string;
|
|
20
|
+
readonly gateId: string;
|
|
21
|
+
}
|
|
22
|
+
interface GatePorts {
|
|
23
|
+
readonly stopped: AbortSignal;
|
|
24
|
+
readonly timing?: {
|
|
25
|
+
readonly pollMilliseconds: number;
|
|
26
|
+
readonly retryMilliseconds: number;
|
|
27
|
+
};
|
|
28
|
+
readonly state: () => Promise<{
|
|
29
|
+
readonly runs: Readonly<Record<string, {
|
|
30
|
+
readonly revision: number;
|
|
31
|
+
} | undefined>>;
|
|
32
|
+
readonly gates: Readonly<Record<string, unknown>>;
|
|
33
|
+
}>;
|
|
34
|
+
readonly openGate: (opening: GateOpening) => Promise<GateReceipt>;
|
|
35
|
+
readonly registerWait: (wait: WaitRegistration) => Promise<GateReceipt>;
|
|
36
|
+
}
|
|
37
|
+
interface GateSubject {
|
|
38
|
+
readonly waitMode?: "hook";
|
|
39
|
+
readonly runId: string;
|
|
40
|
+
readonly transport: string;
|
|
41
|
+
readonly request: GateRequest;
|
|
42
|
+
}
|
|
43
|
+
export declare function openBridgeGate(ports: GatePorts, subject: GateSubject): Promise<GateResult>;
|
|
44
|
+
export declare function waitForBridgeDecision(ports: GatePorts & {
|
|
45
|
+
readonly document: (digest: string) => Promise<string | undefined>;
|
|
46
|
+
readonly decisionReceived: (runId: string, gateId: string) => Promise<boolean>;
|
|
47
|
+
}, subject: GateSubject): Promise<DecisionWait>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
3
|
+
import { gateKey } from "../authority/gates.js";
|
|
4
|
+
import { decisionToken } from "../decision-wait.js";
|
|
5
|
+
import { record } from "../protocol.js";
|
|
6
|
+
const committed = ["accepted", "duplicate"];
|
|
7
|
+
function promptDigest(request) {
|
|
8
|
+
return `sha256:${createHash("sha256").update(request.prompt).digest("hex")}`;
|
|
9
|
+
}
|
|
10
|
+
function sameHookSubject(value, request) {
|
|
11
|
+
const gate = record(value);
|
|
12
|
+
return (gate?.["subject"] === promptDigest(request) &&
|
|
13
|
+
gate["kind"] === request.kind &&
|
|
14
|
+
gate["wait"] === "hook");
|
|
15
|
+
}
|
|
16
|
+
async function paused(hold, milliseconds) {
|
|
17
|
+
await delay(milliseconds, undefined, { signal: hold.ports.stopped }).catch(() => undefined);
|
|
18
|
+
if (hold.ports.stopped.aborted)
|
|
19
|
+
await new Promise(() => undefined);
|
|
20
|
+
}
|
|
21
|
+
function verdict(hold, receipt) {
|
|
22
|
+
if (receipt === undefined || receipt.kind === "failed")
|
|
23
|
+
return hold.timing.retryMilliseconds;
|
|
24
|
+
if (committed.includes(receipt.kind))
|
|
25
|
+
return "committed";
|
|
26
|
+
if (receipt.reason === "service-busy")
|
|
27
|
+
return hold.timing.retryMilliseconds;
|
|
28
|
+
if (receipt.reason === "stale-revision")
|
|
29
|
+
return hold.timing.pollMilliseconds;
|
|
30
|
+
return { kind: "refused", reason: receipt.reason ?? receipt.kind };
|
|
31
|
+
}
|
|
32
|
+
async function gateCommand(hold, send) {
|
|
33
|
+
for (;;) {
|
|
34
|
+
await paused(hold, 0);
|
|
35
|
+
const result = verdict(hold, await send().catch(() => undefined));
|
|
36
|
+
if (result === "committed")
|
|
37
|
+
return undefined;
|
|
38
|
+
if (typeof result !== "number")
|
|
39
|
+
return result;
|
|
40
|
+
await paused(hold, result);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function opening(hold, subject) {
|
|
44
|
+
const { runId, transport, request } = subject;
|
|
45
|
+
const { gateId, kind, prompt } = request;
|
|
46
|
+
const state = await hold.ports.state();
|
|
47
|
+
const run = state.runs[runId];
|
|
48
|
+
if (run === undefined)
|
|
49
|
+
return { kind: "rejected", reason: "unknown-run" };
|
|
50
|
+
const key = gateKey(runId, gateId);
|
|
51
|
+
const exists = Object.hasOwn(state.gates, key);
|
|
52
|
+
if (exists &&
|
|
53
|
+
subject.waitMode === "hook" &&
|
|
54
|
+
!sameHookSubject(state.gates[key], request))
|
|
55
|
+
return { kind: "rejected", reason: "gate-subject-changed" };
|
|
56
|
+
if (exists)
|
|
57
|
+
return { kind: "duplicate" };
|
|
58
|
+
return await hold.ports.openGate({
|
|
59
|
+
...(subject.waitMode === undefined ? {} : { waitMode: subject.waitMode }),
|
|
60
|
+
runId,
|
|
61
|
+
commandId: `${transport}:open:${gateId}`,
|
|
62
|
+
expectedRevision: run.revision,
|
|
63
|
+
gateId,
|
|
64
|
+
kind,
|
|
65
|
+
prompt,
|
|
66
|
+
subject: promptDigest(request),
|
|
67
|
+
...(request.expiresAt === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: { expiresAt: request.expiresAt }),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export async function openBridgeGate(ports, subject) {
|
|
73
|
+
const hold = {
|
|
74
|
+
ports,
|
|
75
|
+
timing: ports.timing ?? { pollMilliseconds: 20, retryMilliseconds: 1000 },
|
|
76
|
+
};
|
|
77
|
+
const refusal = await gateCommand(hold, () => opening(hold, subject));
|
|
78
|
+
if (refusal !== undefined)
|
|
79
|
+
return refusal;
|
|
80
|
+
if (subject.waitMode === "hook")
|
|
81
|
+
return {
|
|
82
|
+
kind: "opened",
|
|
83
|
+
decisionId: decisionToken(subject.runId, subject.request.gateId),
|
|
84
|
+
};
|
|
85
|
+
const waited = await gateCommand(hold, () => ports.registerWait({
|
|
86
|
+
runId: subject.runId,
|
|
87
|
+
commandId: `${subject.transport}:wait:${subject.request.gateId}`,
|
|
88
|
+
gateId: subject.request.gateId,
|
|
89
|
+
}));
|
|
90
|
+
return waited ?? { kind: "opened", decisionId: subject.request.gateId };
|
|
91
|
+
}
|
|
92
|
+
export async function waitForBridgeDecision(ports, subject) {
|
|
93
|
+
const hold = {
|
|
94
|
+
ports,
|
|
95
|
+
timing: ports.timing ?? { pollMilliseconds: 20, retryMilliseconds: 1000 },
|
|
96
|
+
};
|
|
97
|
+
await paused(hold, 0);
|
|
98
|
+
const state = await ports.state();
|
|
99
|
+
const key = gateKey(subject.runId, subject.request.gateId);
|
|
100
|
+
const gate = state.gates[key];
|
|
101
|
+
if (Object.hasOwn(state.gates, key) &&
|
|
102
|
+
!sameHookSubject(gate, subject.request))
|
|
103
|
+
throw new Error("gate-subject-changed");
|
|
104
|
+
const outcome = record(record(gate)?.["outcome"]);
|
|
105
|
+
if (outcome !== undefined &&
|
|
106
|
+
(await ports.decisionReceived(subject.runId, subject.request.gateId)))
|
|
107
|
+
return await storedDecision(ports, outcome);
|
|
108
|
+
const opening = await openBridgeGate(ports, { ...subject, waitMode: "hook" });
|
|
109
|
+
if (opening.kind !== "opened")
|
|
110
|
+
throw new Error(opening.reason);
|
|
111
|
+
return { token: opening.decisionId };
|
|
112
|
+
}
|
|
113
|
+
async function storedDecision(ports, outcome) {
|
|
114
|
+
const decision = ["approved", "denied", "answered", "expired"].find((value) => value === outcome["decision"]);
|
|
115
|
+
if (decision === undefined)
|
|
116
|
+
throw new Error("invalid-decision-outcome");
|
|
117
|
+
const digest = outcome["answer"];
|
|
118
|
+
if (digest !== null && typeof digest !== "string")
|
|
119
|
+
throw new Error("invalid-decision-answer");
|
|
120
|
+
const answer = digest === null ? null : await ports.document(digest);
|
|
121
|
+
if (answer === undefined)
|
|
122
|
+
throw new Error("missing-decision-answer");
|
|
123
|
+
return { decision, answer };
|
|
124
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RunWaitTarget } from "../run-wait.ts";
|
|
2
|
+
import type { RunWaitOutcome, RunWaitRequest } from "../step-bridge.ts";
|
|
3
|
+
export interface RunWaitPorts {
|
|
4
|
+
readonly now?: () => number;
|
|
5
|
+
readonly target: (runId: string) => Promise<RunWaitTarget | undefined>;
|
|
6
|
+
readonly observe: (report: {
|
|
7
|
+
readonly runId: string;
|
|
8
|
+
readonly commandId: string;
|
|
9
|
+
readonly condition: string;
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
readonly evidence?: string;
|
|
12
|
+
readonly retryAt?: string;
|
|
13
|
+
readonly operationId?: string;
|
|
14
|
+
}) => Promise<{
|
|
15
|
+
readonly kind: string;
|
|
16
|
+
readonly reason?: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function runWait(ports: RunWaitPorts, wait: {
|
|
20
|
+
readonly caller: {
|
|
21
|
+
readonly runId: string;
|
|
22
|
+
readonly stepId: string;
|
|
23
|
+
readonly startedAt: number;
|
|
24
|
+
};
|
|
25
|
+
readonly request: RunWaitRequest;
|
|
26
|
+
}): Promise<RunWaitOutcome>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FatalError, RetryableError } from "workflow";
|
|
2
|
+
import { runWaitResult } from "../run-wait.js";
|
|
3
|
+
export async function runWait(ports, wait) {
|
|
4
|
+
const { caller, request } = wait;
|
|
5
|
+
const now = (ports.now ?? Date.now)();
|
|
6
|
+
const result = runWaitResult(request, {
|
|
7
|
+
callerRunId: caller.runId,
|
|
8
|
+
startedAt: caller.startedAt,
|
|
9
|
+
now,
|
|
10
|
+
target: await ports.target(request.runId),
|
|
11
|
+
});
|
|
12
|
+
const waiting = result.kind === "waiting";
|
|
13
|
+
const receipt = await ports.observe({
|
|
14
|
+
runId: caller.runId,
|
|
15
|
+
commandId: `${caller.stepId}:run-wait:${waiting ? "waiting" : "ended"}`,
|
|
16
|
+
condition: waiting ? "waiting-run" : "working",
|
|
17
|
+
reason: waiting ? "awaiting-run" : "in-progress",
|
|
18
|
+
operationId: caller.stepId,
|
|
19
|
+
...(result.kind !== "waiting"
|
|
20
|
+
? {}
|
|
21
|
+
: {
|
|
22
|
+
evidence: request.runId,
|
|
23
|
+
retryAt: new Date(result.deadline).toISOString(),
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
if (!["accepted", "duplicate"].includes(receipt.kind))
|
|
27
|
+
throw new RetryableError("run-wait-observation-unavailable", {
|
|
28
|
+
retryAfter: 1000,
|
|
29
|
+
});
|
|
30
|
+
if (result.kind === "refused")
|
|
31
|
+
throw new FatalError(result.reason);
|
|
32
|
+
if (result.kind === "completed")
|
|
33
|
+
return result.outcome;
|
|
34
|
+
throw new RetryableError("awaiting-run", {
|
|
35
|
+
retryAfter: Math.max(1, Math.min(1000, result.deadline - now)),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -33,7 +33,7 @@ export interface StartParts {
|
|
|
33
33
|
}
|
|
34
34
|
export interface StartDelivery {
|
|
35
35
|
readonly reconcile: (intent: RunIntent) => Promise<RunOutcome>;
|
|
36
|
-
readonly deliver: (intent: RunIntent) => Promise<{
|
|
36
|
+
readonly deliver: (intent: RunIntent, signal?: AbortSignal) => Promise<{
|
|
37
37
|
readonly receipt: string;
|
|
38
38
|
}>;
|
|
39
39
|
readonly stop: (intent: RunIntent) => Promise<RunOutcome>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { start } from "workflow/api";
|
|
2
2
|
import { operationTag, runTag } from "./world-runs.js";
|
|
3
|
+
import { deliveredDecision, reconciledDecision, stoppedDecision, } from "./decision-resume.js";
|
|
3
4
|
const ends = ["cancelled", "completed", "failed"];
|
|
4
5
|
async function segments(parts, intent) {
|
|
5
6
|
return (await parts.runs()).filter((run) => run.operationId === intent.operationId);
|
|
@@ -61,8 +62,14 @@ async function stopped(parts, intent) {
|
|
|
61
62
|
}
|
|
62
63
|
export function startDelivery(parts) {
|
|
63
64
|
return {
|
|
64
|
-
reconcile: (intent) =>
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
reconcile: (intent) => intent.kind === "resume-hook"
|
|
66
|
+
? reconciledDecision(parts, intent)
|
|
67
|
+
: reconciled(parts, intent),
|
|
68
|
+
deliver: (intent, signal) => intent.kind === "resume-hook"
|
|
69
|
+
? deliveredDecision(parts, { intent, signal })
|
|
70
|
+
: delivered(parts, intent),
|
|
71
|
+
stop: (intent) => intent.kind === "resume-hook"
|
|
72
|
+
? stoppedDecision(parts, intent)
|
|
73
|
+
: stopped(parts, intent),
|
|
67
74
|
};
|
|
68
75
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { type GateOpening, type GateReceipt, type WaitRegistration } from "./gate-bridge.ts";
|
|
2
|
+
export type { GateOpening, GateReceipt, WaitRegistration, } from "./gate-bridge.ts";
|
|
3
|
+
import { type RunWaitPorts } from "./run-wait.ts";
|
|
1
4
|
import { type ProtectedRequest, type StepBridge } from "../step-bridge.ts";
|
|
2
5
|
export interface StepCall {
|
|
3
6
|
readonly worldRunId: string;
|
|
4
7
|
readonly stepId: string;
|
|
5
8
|
readonly attempt: number;
|
|
9
|
+
readonly startedAt?: number;
|
|
6
10
|
}
|
|
7
11
|
export declare function sdkStepCall(): StepCall;
|
|
8
12
|
export interface OperationRead {
|
|
@@ -30,25 +34,6 @@ interface BridgeIdentity {
|
|
|
30
34
|
export interface BridgeRequest extends ProtectedRequest, BridgeIdentity {
|
|
31
35
|
readonly runId: string;
|
|
32
36
|
}
|
|
33
|
-
export interface GateReceipt {
|
|
34
|
-
readonly kind: string;
|
|
35
|
-
readonly reason?: string;
|
|
36
|
-
}
|
|
37
|
-
export interface GateOpening {
|
|
38
|
-
readonly runId: string;
|
|
39
|
-
readonly commandId: string;
|
|
40
|
-
readonly expectedRevision: number;
|
|
41
|
-
readonly gateId: string;
|
|
42
|
-
readonly kind: "question" | "approval";
|
|
43
|
-
readonly prompt: string;
|
|
44
|
-
readonly subject: string;
|
|
45
|
-
readonly expiresAt?: string;
|
|
46
|
-
}
|
|
47
|
-
export interface WaitRegistration {
|
|
48
|
-
readonly runId: string;
|
|
49
|
-
readonly commandId: string;
|
|
50
|
-
readonly gateId: string;
|
|
51
|
-
}
|
|
52
37
|
export interface BridgeTiming {
|
|
53
38
|
readonly lookupTries: number;
|
|
54
39
|
readonly pollMilliseconds: number;
|
|
@@ -56,6 +41,8 @@ export interface BridgeTiming {
|
|
|
56
41
|
}
|
|
57
42
|
export declare const bridgeTiming: BridgeTiming;
|
|
58
43
|
export interface BridgePorts {
|
|
44
|
+
readonly decisionReceived?: (runId: string, gateId: string) => Promise<boolean>;
|
|
45
|
+
readonly runWait?: RunWaitPorts;
|
|
59
46
|
readonly call: () => StepCall;
|
|
60
47
|
readonly run: (worldRunId: string) => Promise<{
|
|
61
48
|
readonly runId: string;
|
|
@@ -77,4 +64,3 @@ export interface BridgePorts {
|
|
|
77
64
|
}
|
|
78
65
|
export declare function stepBridge(ports: BridgePorts): StepBridge;
|
|
79
66
|
export declare function registerStepBridge(bridge: StepBridge): () => void;
|
|
80
|
-
export {};
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3
3
|
import { getStepMetadata, getWorkflowMetadata } from "workflow";
|
|
4
|
-
import {
|
|
4
|
+
import { openBridgeGate, waitForBridgeDecision, } from "./gate-bridge.js";
|
|
5
|
+
import { runWait } from "./run-wait.js";
|
|
6
|
+
import { reconciledDecision } from "./decision-resume.js";
|
|
7
|
+
import { taggedRuns } from "./world-runs.js";
|
|
5
8
|
import { stepBridgeKey, } from "../step-bridge.js";
|
|
6
9
|
export function sdkStepCall() {
|
|
7
|
-
const { stepId, attempt } = getStepMetadata();
|
|
8
|
-
return {
|
|
10
|
+
const { stepId, attempt, stepStartedAt } = getStepMetadata();
|
|
11
|
+
return {
|
|
12
|
+
worldRunId: getWorkflowMetadata().workflowRunId,
|
|
13
|
+
stepId,
|
|
14
|
+
attempt,
|
|
15
|
+
startedAt: stepStartedAt.getTime(),
|
|
16
|
+
};
|
|
9
17
|
}
|
|
10
18
|
export const bridgeTiming = {
|
|
11
19
|
lookupTries: 250,
|
|
@@ -129,74 +137,52 @@ async function effect(hold, request) {
|
|
|
129
137
|
return answer;
|
|
130
138
|
return await settled(hold, answer.operationId);
|
|
131
139
|
}
|
|
132
|
-
function
|
|
133
|
-
if (receipt === undefined || receipt.kind === "failed")
|
|
134
|
-
return hold.timing.retryMilliseconds;
|
|
135
|
-
if (committed.includes(receipt.kind))
|
|
136
|
-
return "committed";
|
|
137
|
-
if (receipt.reason === "service-busy")
|
|
138
|
-
return hold.timing.retryMilliseconds;
|
|
139
|
-
if (receipt.reason === "stale-revision")
|
|
140
|
-
return hold.timing.pollMilliseconds;
|
|
141
|
-
return { kind: "refused", reason: receipt.reason ?? receipt.kind };
|
|
142
|
-
}
|
|
143
|
-
async function gateCommand(hold, send) {
|
|
144
|
-
for (;;) {
|
|
145
|
-
await paused(hold, 0);
|
|
146
|
-
const result = verdict(hold, await send().catch(() => undefined));
|
|
147
|
-
if (result === "committed")
|
|
148
|
-
return undefined;
|
|
149
|
-
if (typeof result !== "number")
|
|
150
|
-
return result;
|
|
151
|
-
await paused(hold, result);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
async function opening(hold, subject) {
|
|
155
|
-
const { runId, transport, request } = subject;
|
|
156
|
-
const { gateId, kind, prompt } = request;
|
|
157
|
-
const state = await hold.ports.state();
|
|
158
|
-
const run = state.runs[runId];
|
|
159
|
-
if (run === undefined)
|
|
160
|
-
return { kind: "rejected", reason: "unknown-run" };
|
|
161
|
-
if (Object.hasOwn(state.gates, gateKey(runId, gateId)))
|
|
162
|
-
return { kind: "duplicate" };
|
|
163
|
-
return await hold.ports.openGate({
|
|
164
|
-
runId,
|
|
165
|
-
commandId: `${transport}:open:${gateId}`,
|
|
166
|
-
expectedRevision: run.revision,
|
|
167
|
-
gateId,
|
|
168
|
-
kind,
|
|
169
|
-
prompt,
|
|
170
|
-
subject: `sha256:${createHash("sha256").update(prompt).digest("hex")}`,
|
|
171
|
-
...(request.expiresAt === undefined
|
|
172
|
-
? {}
|
|
173
|
-
: { expiresAt: request.expiresAt }),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
async function gate(hold, request) {
|
|
140
|
+
async function gateSubject(hold, request) {
|
|
177
141
|
const call = hold.ports.call();
|
|
178
142
|
const world = await located(hold, call.worldRunId);
|
|
179
143
|
if (world === undefined)
|
|
180
|
-
return
|
|
144
|
+
return undefined;
|
|
181
145
|
await inWork(hold, world.runId);
|
|
182
|
-
|
|
146
|
+
return {
|
|
147
|
+
request,
|
|
183
148
|
runId: world.runId,
|
|
184
149
|
transport: transportOf(call),
|
|
185
|
-
request,
|
|
186
150
|
};
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return refusal ?? { kind: "opened", decisionId: request.gateId };
|
|
151
|
+
}
|
|
152
|
+
async function gate(hold, request) {
|
|
153
|
+
const subject = await gateSubject(hold, request);
|
|
154
|
+
if (subject === undefined)
|
|
155
|
+
return { kind: "unavailable", reason: "unknown-world-run" };
|
|
156
|
+
return await openBridgeGate(hold.ports, subject);
|
|
194
157
|
}
|
|
195
158
|
export function stepBridge(ports) {
|
|
196
159
|
const hold = { ports, timing: ports.timing ?? bridgeTiming };
|
|
197
160
|
return {
|
|
198
161
|
effect: (request) => effect(hold, request),
|
|
199
162
|
gate: (request) => gate(hold, request),
|
|
163
|
+
waitForDecision: async (request) => {
|
|
164
|
+
const subject = await gateSubject(hold, request);
|
|
165
|
+
if (subject === undefined)
|
|
166
|
+
throw new Error("unknown-world-run");
|
|
167
|
+
return await waitForBridgeDecision({
|
|
168
|
+
...ports,
|
|
169
|
+
decisionReceived: ports.decisionReceived ??
|
|
170
|
+
(async (runId, gateId) => (await reconciledDecision({ runs: taggedRuns, document: ports.document }, { runId, gateId })).kind === "accepted"),
|
|
171
|
+
}, subject);
|
|
172
|
+
},
|
|
173
|
+
waitForRun: async (request) => {
|
|
174
|
+
const call = ports.call();
|
|
175
|
+
const world = await located(hold, call.worldRunId);
|
|
176
|
+
if (world === undefined ||
|
|
177
|
+
ports.runWait === undefined ||
|
|
178
|
+
call.startedAt === undefined)
|
|
179
|
+
throw new Error("cloving-host-unavailable");
|
|
180
|
+
await inWork(hold, world.runId);
|
|
181
|
+
return await runWait(ports.runWait, {
|
|
182
|
+
caller: { ...world, stepId: call.stepId, startedAt: call.startedAt },
|
|
183
|
+
request,
|
|
184
|
+
});
|
|
185
|
+
},
|
|
200
186
|
handoff: (request) => effect(hold, {
|
|
201
187
|
scope: {
|
|
202
188
|
phase: "handoff",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface PullRequest {
|
|
2
|
+
readonly number: number;
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly commit: string;
|
|
5
|
+
readonly target: string;
|
|
6
|
+
}
|
|
7
|
+
export type MergeCheckName = "beforeMerge";
|
|
8
|
+
export interface MergeRequest {
|
|
9
|
+
readonly pull: PullRequest;
|
|
10
|
+
readonly check: MergeCheckName | null;
|
|
11
|
+
readonly round?: number;
|
|
12
|
+
}
|
|
13
|
+
export type MergeReason = "check-failed" | "merge-conflict" | "ci-failed" | "ci-pending" | "check-not-configured" | "not-approved";
|
|
14
|
+
export interface MergeResult {
|
|
15
|
+
readonly merged: boolean;
|
|
16
|
+
readonly reason: MergeReason | null;
|
|
17
|
+
readonly output: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function mergeRequest(value: unknown): Required<MergeRequest>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { record } from "./protocol.js";
|
|
2
|
+
import { commitId } from "./review-subject.js";
|
|
3
|
+
export function mergeRequest(value) {
|
|
4
|
+
const request = record(value);
|
|
5
|
+
const pull = pullRequest(request?.["pull"]);
|
|
6
|
+
const check = request?.["check"];
|
|
7
|
+
if (request === undefined ||
|
|
8
|
+
pull === undefined ||
|
|
9
|
+
!Object.hasOwn(request, "check") ||
|
|
10
|
+
(check !== null && check !== "beforeMerge"))
|
|
11
|
+
throw new Error("invalid-merge-request");
|
|
12
|
+
return { pull, check, round: mergeRound(request["round"] ?? 1) };
|
|
13
|
+
}
|
|
14
|
+
function mergeRound(value) {
|
|
15
|
+
if (!positiveInteger(value))
|
|
16
|
+
throw new Error("invalid-merge-request");
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function pullRequest(value) {
|
|
20
|
+
const pull = record(value);
|
|
21
|
+
const { number, url, commit, target } = pull ?? {};
|
|
22
|
+
if (!positiveInteger(number) ||
|
|
23
|
+
typeof url !== "string" ||
|
|
24
|
+
!commitId(commit) ||
|
|
25
|
+
typeof target !== "string" ||
|
|
26
|
+
target.trim() === "")
|
|
27
|
+
return undefined;
|
|
28
|
+
return { number, url, commit, target };
|
|
29
|
+
}
|
|
30
|
+
function positiveInteger(value) {
|
|
31
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function canonicalJson(value: unknown): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function canonicalJson(value) {
|
|
2
|
+
if (value === null || typeof value === "boolean" || typeof value === "string")
|
|
3
|
+
return JSON.stringify(value);
|
|
4
|
+
if (typeof value === "number" && !Number.isSafeInteger(value))
|
|
5
|
+
throw new Error("canonical-json-number: Only safe integers are allowed.");
|
|
6
|
+
if (typeof value === "number")
|
|
7
|
+
return String(value);
|
|
8
|
+
if (Array.isArray(value))
|
|
9
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
10
|
+
if (typeof value !== "object")
|
|
11
|
+
throw new Error("canonical-json-value: The value is not JSON.");
|
|
12
|
+
const fields = Object.keys(value)
|
|
13
|
+
.sort()
|
|
14
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(Reflect.get(value, key))}`);
|
|
15
|
+
return `{${fields.join(",")}}`;
|
|
16
|
+
}
|