cloving 1.1.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 +584 -144
- package/assets/watch-fonts/fira-code-OFL.md +93 -0
- package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-OFL.md +93 -0
- package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
- package/assets/watch-fonts/manifest.json +112 -0
- package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
- package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- 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 +2 -0
- package/dist/src/authority/commands.js +49 -8
- package/dist/src/authority/dispatch-decision.d.ts +1 -0
- package/dist/src/authority/dispatch-decision.js +7 -4
- package/dist/src/authority/events.js +2 -2
- 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/handoff-chain.d.ts +24 -0
- package/dist/src/authority/handoff-chain.js +46 -0
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reconciliation.d.ts +1 -0
- package/dist/src/authority/reconciliation.js +18 -11
- 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 +9 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +11 -1
- package/dist/src/broker/actor/authority-queries.js +67 -3
- 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 +3 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +13 -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 +26 -5
- 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 +3 -1
- package/dist/src/cli/render.js +102 -39
- 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 +74 -45
- 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 +12 -1
- package/dist/src/cli/watch-board-view.js +64 -12
- package/dist/src/cli/watch-board.d.ts +7 -1
- package/dist/src/cli/watch-board.js +61 -16
- 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 +12 -3
- 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.d.ts +10 -4
- package/dist/src/cli/watch-model.js +49 -59
- package/dist/src/cli/watch-page.js +67 -14
- package/dist/src/cli/watch-phases.js +3 -3
- 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-pr-command.d.ts +5 -2
- package/dist/src/cli/watch-pr-command.js +41 -4
- package/dist/src/cli/watch-pr-identity.d.ts +14 -2
- package/dist/src/cli/watch-pr-identity.js +25 -0
- package/dist/src/cli/watch-pr-observer.d.ts +1 -0
- package/dist/src/cli/watch-pr-observer.js +48 -6
- package/dist/src/cli/watch-pull-request.d.ts +12 -0
- package/dist/src/cli/watch-pull-request.js +134 -0
- package/dist/src/cli/watch-reads.d.ts +7 -1
- package/dist/src/cli/watch-reads.js +42 -20
- package/dist/src/cli/watch-render.d.ts +23 -2
- package/dist/src/cli/watch-render.js +2 -1
- package/dist/src/cli/watch-server.js +56 -7
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +38 -2
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +10 -17
- package/dist/src/cli/watch-view.js +33 -77
- 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 +20 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -5
- package/dist/src/daemon/claude-worker.js +64 -80
- 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 +3 -30
- package/dist/src/daemon/daemon.js +132 -110
- 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 +7 -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-calls.d.ts +4 -0
- package/dist/src/daemon/github-calls.js +16 -7
- 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.d.ts +6 -0
- package/dist/src/daemon/github-ci.js +251 -0
- package/dist/src/daemon/github-merge-call.d.ts +16 -0
- package/dist/src/daemon/github-merge-call.js +73 -0
- package/dist/src/daemon/github-merge.d.ts +3 -5
- package/dist/src/daemon/github-merge.js +59 -98
- package/dist/src/daemon/github-methods.d.ts +28 -0
- package/dist/src/daemon/github-methods.js +90 -16
- package/dist/src/daemon/github-operation.d.ts +3 -0
- package/dist/src/daemon/github-retry.d.ts +6 -0
- package/dist/src/daemon/github-retry.js +13 -0
- package/dist/src/daemon/github-ticket-status.js +27 -1
- package/dist/src/daemon/github-worker.js +2 -1
- package/dist/src/daemon/handoff-worker.d.ts +10 -0
- package/dist/src/daemon/handoff-worker.js +232 -0
- package/dist/src/daemon/issue-queue.d.ts +2 -0
- package/dist/src/daemon/issue-queue.js +92 -63
- package/dist/src/daemon/notify-journal.d.ts +18 -0
- package/dist/src/daemon/notify-journal.js +108 -0
- package/dist/src/daemon/notify-message.js +2 -1
- package/dist/src/daemon/notify.js +177 -37
- 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 +5 -0
- package/dist/src/daemon/retrying-turn.js +145 -21
- 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-dependency-waits.d.ts +18 -0
- package/dist/src/daemon/ticket-dependency-waits.js +60 -0
- package/dist/src/daemon/ticket-registration.d.ts +10 -8
- package/dist/src/daemon/ticket-registration.js +146 -47
- package/dist/src/daemon/ticket-source.d.ts +4 -1
- package/dist/src/daemon/ticket-source.js +8 -2
- 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-visibility.d.ts +2 -0
- package/dist/src/decision-visibility.js +10 -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 +9 -0
- package/dist/src/execution-pin.js +86 -2
- 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 +3 -2
- package/dist/src/host/start-delivery.js +11 -4
- package/dist/src/host/step-bridge-host.d.ts +6 -19
- package/dist/src/host/step-bridge-host.js +57 -55
- package/dist/src/host/world-reconciliation.d.ts +1 -0
- package/dist/src/host/world-reconciliation.js +3 -0
- package/dist/src/host/world-runs.js +5 -0
- package/dist/src/issue-identity.d.ts +6 -0
- package/dist/src/issue-identity.js +23 -0
- 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/queue-runs.d.ts +3 -0
- package/dist/src/service/queue-runs.js +39 -0
- package/dist/src/service/registry.d.ts +22 -3
- package/dist/src/service/registry.js +51 -8
- package/dist/src/service/replies.d.ts +10 -0
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +45 -54
- 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 +21 -2
- package/dist/src/service/service.js +23 -5
- package/dist/src/service/submission-handler.js +70 -19
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +10 -1
- package/dist/src/step-bridge.d.ts +32 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/handoff.d.ts +2 -0
- package/dist/src/steps/handoff.js +13 -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-dependencies.d.ts +1 -0
- package/dist/src/ticket-dependencies.js +15 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/ticket-status.js +7 -4
- package/dist/src/token-prices.d.ts +14 -4
- package/dist/src/token-prices.js +56 -11
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +25 -0
- package/dist/src/worker-usage.js +58 -1
- package/dist/src/workflow-admission.d.ts +6 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +48 -5
- package/dist/src/workflow-contracts.d.ts +2 -0
- package/dist/src/workflow-contracts.js +8 -3
- package/dist/src/workflow-declaration.d.ts +31 -2
- package/dist/src/workflow-declaration.js +140 -16
- package/dist/src/workflow-discovery.d.ts +19 -0
- package/dist/src/workflow-discovery.js +36 -0
- package/dist/src/workflow-refusals.d.ts +6 -0
- package/dist/src/workflow-refusals.js +42 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +12 -1
- package/dist/src/workflows.js +9 -0
- package/dist/tools/admit-workflow.d.ts +14 -0
- package/dist/tools/admit-workflow.js +107 -0
- 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 +21 -0
- package/dist/tools/self-host-project.js +224 -0
- 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 +106 -135
- package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
- package/dist/tools/workflow-bundle-dependencies.js +93 -0
- package/dist/tools/workflow-bundles.d.ts +20 -0
- package/dist/tools/workflow-bundles.js +173 -0
- package/dist/tools/workflow-candidate-counts.d.ts +12 -0
- package/dist/tools/workflow-candidate-counts.js +266 -0
- 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 +13 -0
- package/dist/tools/workflow-candidate-program.js +106 -0
- package/dist/tools/workflow-candidate-source.d.ts +6 -0
- package/dist/tools/workflow-candidate-source.js +169 -0
- package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
- package/dist/tools/workflow-candidate-syntax.js +263 -0
- 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 +18 -0
- package/dist/tools/workflow-folder-capture.js +261 -0
- package/dist/tools/workflow-folders.d.ts +49 -0
- package/dist/tools/workflow-folders.js +203 -0
- package/dist/tools/workflow-source-effects.d.ts +10 -0
- package/dist/tools/workflow-source-effects.js +213 -0
- 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-prd.js +71 -3
- package/dist/workflows/develop-ticket.js +6 -1
- package/dist/workflows/ticket-prompts.js +17 -3
- package/package.json +66 -6
- 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 -24
- package/dist/src/chats/analysis-batches.js +0 -83
- 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 -12
- package/dist/src/chats/analysis-input.js +0 -83
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-prompt.d.ts +0 -10
- package/dist/src/chats/analysis-prompt.js +0 -16
- package/dist/src/chats/analysis-proposal.d.ts +0 -2
- package/dist/src/chats/analysis-proposal.js +0 -32
- 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 -3
- package/dist/src/chats/analysis-shape.js +0 -228
- 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/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/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 -22
- package/dist/src/daemon/analysis-worker.js +0 -219
- package/dist/src/daemon/chats-files.d.ts +0 -15
- package/dist/src/daemon/chats-files.js +0 -113
- package/dist/src/daemon/chats-worker.d.ts +0 -12
- package/dist/src/daemon/chats-worker.js +0 -200
- package/dist/workflows/analyze-chats.d.ts +0 -10
- package/dist/workflows/analyze-chats.declaration.json +0 -9
- package/dist/workflows/analyze-chats.js +0 -73
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import { send } from "../cli/client.js";
|
|
3
|
+
import { record } from "../protocol.js";
|
|
4
|
+
import { runIdentity } from "../service/submission-handler.js";
|
|
5
|
+
import { located, readRecord, writeRecord } from "./operation-journal.js";
|
|
6
|
+
const attempts = 10;
|
|
7
|
+
const uncertain = [
|
|
8
|
+
"outcome-unknown",
|
|
9
|
+
"service-unavailable",
|
|
10
|
+
"service-busy",
|
|
11
|
+
"storage-failure",
|
|
12
|
+
"authority-unavailable",
|
|
13
|
+
"resolver-timeout",
|
|
14
|
+
"resolver-failure",
|
|
15
|
+
];
|
|
16
|
+
function own(intent) {
|
|
17
|
+
return (intent.kind === "protected-effect" &&
|
|
18
|
+
intent.capability === "handoff" &&
|
|
19
|
+
intent.method === "run" &&
|
|
20
|
+
intent.target !== undefined &&
|
|
21
|
+
intent.payload !== undefined &&
|
|
22
|
+
intent.leaseGeneration !== undefined);
|
|
23
|
+
}
|
|
24
|
+
function completed(runId) {
|
|
25
|
+
return {
|
|
26
|
+
kind: "completed",
|
|
27
|
+
worker: "handoff",
|
|
28
|
+
receipt: runId,
|
|
29
|
+
result: runId,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function saved(folder) {
|
|
33
|
+
const stored = record(await readRecord(folder, "result.json"));
|
|
34
|
+
if (stored === undefined)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (stored["kind"] === "completed" && typeof stored["result"] === "string")
|
|
37
|
+
return completed(stored["result"]);
|
|
38
|
+
if (stored["kind"] === "failed" && typeof stored["reason"] === "string")
|
|
39
|
+
return { kind: "failed", reason: stored["reason"] };
|
|
40
|
+
throw new Error("invalid-handoff-journal");
|
|
41
|
+
}
|
|
42
|
+
async function retained(folder, outcome) {
|
|
43
|
+
if (["completed", "failed"].includes(outcome.kind))
|
|
44
|
+
await writeRecord(folder, {
|
|
45
|
+
name: "result.json",
|
|
46
|
+
value: outcome,
|
|
47
|
+
permissions: "private",
|
|
48
|
+
});
|
|
49
|
+
return outcome;
|
|
50
|
+
}
|
|
51
|
+
function outcome(reply) {
|
|
52
|
+
if (reply.kind !== "error") {
|
|
53
|
+
const runId = reply.result["runId"];
|
|
54
|
+
return reply.result["kind"] === "run-admitted" && typeof runId === "string"
|
|
55
|
+
? completed(runId)
|
|
56
|
+
: { kind: "unknown" };
|
|
57
|
+
}
|
|
58
|
+
if (reply.error.code === "workflow-active")
|
|
59
|
+
return undefined;
|
|
60
|
+
if (reply.error.code === "chain-limit")
|
|
61
|
+
return { kind: "failed", reason: "chain-limit" };
|
|
62
|
+
return uncertain.includes(reply.error.code)
|
|
63
|
+
? { kind: "unknown" }
|
|
64
|
+
: { kind: "failed", reason: "handoff-input-refused" };
|
|
65
|
+
}
|
|
66
|
+
async function input(settings, intent) {
|
|
67
|
+
const text = await settings.document(intent.payload);
|
|
68
|
+
try {
|
|
69
|
+
return record(JSON.parse(text ?? "null"));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function submit(settings, call) {
|
|
76
|
+
const { intent, signal } = call;
|
|
77
|
+
if (!own(intent))
|
|
78
|
+
return { kind: "failed", reason: "unsupported-effect" };
|
|
79
|
+
const { folder } = located(settings.journal, intent.operationId);
|
|
80
|
+
const known = await saved(folder);
|
|
81
|
+
if (known !== undefined)
|
|
82
|
+
return known;
|
|
83
|
+
const submission = await input(settings, intent);
|
|
84
|
+
if (submission === undefined)
|
|
85
|
+
return retained(folder, {
|
|
86
|
+
kind: "failed",
|
|
87
|
+
reason: "handoff-input-refused",
|
|
88
|
+
});
|
|
89
|
+
const previous = await busyAttempts(folder);
|
|
90
|
+
for (let busy = previous; busy < attempts; busy += 1) {
|
|
91
|
+
if (!(await allowed(settings, { intent, signal })))
|
|
92
|
+
return { kind: "unknown" };
|
|
93
|
+
const reply = await submitted(settings, {
|
|
94
|
+
intent,
|
|
95
|
+
submission,
|
|
96
|
+
signal,
|
|
97
|
+
folder,
|
|
98
|
+
});
|
|
99
|
+
if (reply === undefined)
|
|
100
|
+
return { kind: "unknown" };
|
|
101
|
+
const result = outcome(reply);
|
|
102
|
+
if (result !== undefined)
|
|
103
|
+
return retained(folder, result);
|
|
104
|
+
await writeRecord(folder, {
|
|
105
|
+
name: "attempts.json",
|
|
106
|
+
value: { busy: busy + 1 },
|
|
107
|
+
permissions: "private",
|
|
108
|
+
});
|
|
109
|
+
if (busy + 1 < attempts)
|
|
110
|
+
await delay(settings.retryMilliseconds ?? 1000, undefined, {
|
|
111
|
+
signal,
|
|
112
|
+
}).catch(() => undefined);
|
|
113
|
+
}
|
|
114
|
+
return retained(folder, { kind: "failed", reason: "handoff-start-timeout" });
|
|
115
|
+
}
|
|
116
|
+
async function submitted(settings, call) {
|
|
117
|
+
const { intent, submission, folder, signal } = call;
|
|
118
|
+
const marker = (status) => writeRecord(folder, {
|
|
119
|
+
name: "submission.json",
|
|
120
|
+
value: { processId: process.pid, pending: status === "pending" },
|
|
121
|
+
permissions: "private",
|
|
122
|
+
});
|
|
123
|
+
await marker("pending");
|
|
124
|
+
if (!(await allowed(settings, { intent, signal }))) {
|
|
125
|
+
await marker("settled");
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
const reply = await send(settings.runtimeDirectory, {
|
|
129
|
+
operation: "run",
|
|
130
|
+
parameters: {
|
|
131
|
+
workflowId: intent.target,
|
|
132
|
+
source: "input",
|
|
133
|
+
submission,
|
|
134
|
+
commandId: `handoff:${intent.operationId}`,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
if (reply.kind !== "error" || reply.error.code !== "outcome-unknown")
|
|
138
|
+
await marker("settled");
|
|
139
|
+
return reply;
|
|
140
|
+
}
|
|
141
|
+
async function allowed(settings, call) {
|
|
142
|
+
try {
|
|
143
|
+
call.signal.throwIfAborted();
|
|
144
|
+
const status = await settings.runStatus(call.intent.runId);
|
|
145
|
+
call.signal.throwIfAborted();
|
|
146
|
+
return status === "running";
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function inFlight(folder) {
|
|
153
|
+
const marker = record(await readRecord(folder, "submission.json"));
|
|
154
|
+
if (marker?.["pending"] !== true)
|
|
155
|
+
return false;
|
|
156
|
+
const pid = marker["processId"];
|
|
157
|
+
if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0)
|
|
158
|
+
throw new Error("invalid-handoff-journal");
|
|
159
|
+
try {
|
|
160
|
+
process.kill(pid, 0);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return !(error instanceof Error &&
|
|
165
|
+
"code" in error &&
|
|
166
|
+
error.code === "ESRCH");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function busyAttempts(folder) {
|
|
170
|
+
const previous = record(await readRecord(folder, "attempts.json"))?.["busy"] ?? 0;
|
|
171
|
+
if (typeof previous !== "number" ||
|
|
172
|
+
!Number.isSafeInteger(previous) ||
|
|
173
|
+
previous < 0 ||
|
|
174
|
+
previous > attempts)
|
|
175
|
+
throw new Error("invalid-handoff-journal");
|
|
176
|
+
return previous;
|
|
177
|
+
}
|
|
178
|
+
async function observed(settings, intent) {
|
|
179
|
+
if (!own(intent))
|
|
180
|
+
return { kind: "failed", reason: "unsupported-effect" };
|
|
181
|
+
const known = await saved(located(settings.journal, intent.operationId).folder);
|
|
182
|
+
if (known !== undefined)
|
|
183
|
+
return known;
|
|
184
|
+
const reply = await send(settings.runtimeDirectory, {
|
|
185
|
+
operation: "status",
|
|
186
|
+
parameters: { runId: runIdentity(`handoff:${intent.operationId}`) },
|
|
187
|
+
});
|
|
188
|
+
if (reply.kind === "error")
|
|
189
|
+
return reply.error.code === "unknown-run"
|
|
190
|
+
? {
|
|
191
|
+
kind: (await inFlight(located(settings.journal, intent.operationId).folder))
|
|
192
|
+
? "unknown"
|
|
193
|
+
: "absent",
|
|
194
|
+
}
|
|
195
|
+
: { kind: "unknown" };
|
|
196
|
+
const runId = record(reply.result["run"])?.["runId"];
|
|
197
|
+
return typeof runId === "string" ? completed(runId) : { kind: "unknown" };
|
|
198
|
+
}
|
|
199
|
+
export function handoffWorker(settings) {
|
|
200
|
+
const pending = new Map();
|
|
201
|
+
const deliver = (intent, signal) => {
|
|
202
|
+
const known = pending.get(intent.operationId);
|
|
203
|
+
if (known !== undefined)
|
|
204
|
+
return known.result;
|
|
205
|
+
const stopping = new AbortController();
|
|
206
|
+
const result = submit(settings, {
|
|
207
|
+
intent,
|
|
208
|
+
signal: AbortSignal.any([signal, stopping.signal]),
|
|
209
|
+
}).finally(() => pending.delete(intent.operationId));
|
|
210
|
+
pending.set(intent.operationId, { stopping, result });
|
|
211
|
+
return result;
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
deliver,
|
|
215
|
+
reconcile: (intent) => observed(settings, intent),
|
|
216
|
+
retry: async (intent, signal) => {
|
|
217
|
+
if (!own(intent))
|
|
218
|
+
return { kind: "failed", reason: "unsupported-effect" };
|
|
219
|
+
const { folder } = located(settings.journal, intent.operationId);
|
|
220
|
+
if (!(await inFlight(folder)))
|
|
221
|
+
return { kind: "unknown" };
|
|
222
|
+
return deliver(intent, signal);
|
|
223
|
+
},
|
|
224
|
+
stop: async (intent) => {
|
|
225
|
+
const active = pending.get(intent.operationId);
|
|
226
|
+
active?.stopping.abort();
|
|
227
|
+
await active?.result;
|
|
228
|
+
const known = await observed(settings, intent);
|
|
229
|
+
return known.kind === "absent" ? { kind: "stopped" } : known;
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
@@ -2,7 +2,9 @@ interface QueueSettings {
|
|
|
2
2
|
readonly directory: string;
|
|
3
3
|
readonly runtimeDirectory: string;
|
|
4
4
|
readonly intervalMilliseconds: number;
|
|
5
|
+
readonly lanes?: number;
|
|
5
6
|
readonly resetQueue?: boolean;
|
|
7
|
+
readonly workflowId?: string;
|
|
6
8
|
}
|
|
7
9
|
export declare function issueQueue(settings: QueueSettings): {
|
|
8
10
|
readonly stop: () => Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { activeQueueRuns } from "./queue-status.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -76,6 +77,34 @@ async function recover(settings, pending) {
|
|
|
76
77
|
await pending.save();
|
|
77
78
|
}
|
|
78
79
|
}
|
|
80
|
+
async function trackedRuns(runtimeDirectory, commands) {
|
|
81
|
+
if (commands.length === 0)
|
|
82
|
+
return [];
|
|
83
|
+
if (commands.length === 1) {
|
|
84
|
+
const commandId = String(commands[0]);
|
|
85
|
+
const run = await runStatus(runtimeDirectory, commandId);
|
|
86
|
+
if (run === undefined)
|
|
87
|
+
throw new Error("queue-run-missing");
|
|
88
|
+
return [{ commandId, run }];
|
|
89
|
+
}
|
|
90
|
+
const reply = await send(runtimeDirectory, {
|
|
91
|
+
operation: "status",
|
|
92
|
+
parameters: { runIds: commands.map(runIdentity) },
|
|
93
|
+
});
|
|
94
|
+
if (reply.kind === "error")
|
|
95
|
+
throw new Error(reply.error.code);
|
|
96
|
+
const runs = reply.result["runs"];
|
|
97
|
+
if (!Array.isArray(runs))
|
|
98
|
+
throw new Error("invalid-run-list");
|
|
99
|
+
return commands.map((commandId) => {
|
|
100
|
+
const run = runs
|
|
101
|
+
.map(record)
|
|
102
|
+
.find((item) => item?.["runId"] === runIdentity(commandId));
|
|
103
|
+
if (run === undefined)
|
|
104
|
+
throw new Error("queue-run-missing");
|
|
105
|
+
return { commandId, run };
|
|
106
|
+
});
|
|
107
|
+
}
|
|
79
108
|
function handedOff(run) {
|
|
80
109
|
const outcome = record(run["outcome"]);
|
|
81
110
|
return (run["state"] === "completed" &&
|
|
@@ -88,55 +117,36 @@ function checkFailureLimit(pending) {
|
|
|
88
117
|
if (pending.failures.length >= 3)
|
|
89
118
|
throw new QueueFailureLimit(`3 runs in a row ended without handoff: ${pending.failures.join(", ")}`);
|
|
90
119
|
}
|
|
120
|
+
async function retired(pending, ending) {
|
|
121
|
+
const { commandId, run } = ending;
|
|
122
|
+
pending.commands.delete(commandId);
|
|
123
|
+
if (handedOff(run))
|
|
124
|
+
pending.failures.length = 0;
|
|
125
|
+
else
|
|
126
|
+
pending.failures.push(runIdentity(commandId));
|
|
127
|
+
await pending.save();
|
|
128
|
+
checkFailureLimit(pending);
|
|
129
|
+
if (handedOff(run))
|
|
130
|
+
return;
|
|
131
|
+
const outcome = record(run["outcome"]);
|
|
132
|
+
process.stderr.write(`Queue run ended ${String(outcome?.["kind"] ?? run["state"])}${outcome?.["issueUpdate"] === "failed" ? "; issueUpdate: failed" : ""}: ${runIdentity(commandId)}; continuing\n`);
|
|
133
|
+
}
|
|
91
134
|
async function completed(settings, pending) {
|
|
92
135
|
checkFailureLimit(pending);
|
|
93
|
-
let
|
|
136
|
+
let pendingRuns = 0;
|
|
137
|
+
const endings = [];
|
|
94
138
|
const tracked = [...pending.commands].filter((commandId) => commandId !== pending.retryCommandId);
|
|
95
|
-
for (const commandId of tracked) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
throw new Error("queue-run-missing");
|
|
99
|
-
if (!terminal(run)) {
|
|
100
|
-
pendingRun = true;
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
pending.commands.delete(commandId);
|
|
104
|
-
if (handedOff(run))
|
|
105
|
-
pending.failures.length = 0;
|
|
139
|
+
for (const { commandId, run } of await trackedRuns(settings.runtimeDirectory, tracked)) {
|
|
140
|
+
if (terminal(run))
|
|
141
|
+
endings.push({ commandId, run });
|
|
106
142
|
else
|
|
107
|
-
|
|
108
|
-
await pending.save();
|
|
109
|
-
checkFailureLimit(pending);
|
|
110
|
-
if (!handedOff(run)) {
|
|
111
|
-
const outcome = record(run["outcome"]);
|
|
112
|
-
process.stderr.write(`Queue run ended ${String(outcome?.["kind"] ?? run["state"])}${outcome?.["issueUpdate"] === "failed" ? "; issueUpdate: failed" : ""}: ${runIdentity(commandId)}; continuing\n`);
|
|
113
|
-
}
|
|
143
|
+
pendingRuns += 1;
|
|
114
144
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const reply = await send(runtimeDirectory, {
|
|
121
|
-
operation: "status",
|
|
122
|
-
parameters: { after, limit: 500 },
|
|
123
|
-
});
|
|
124
|
-
if (reply.kind === "error")
|
|
125
|
-
throw new Error(reply.error.code);
|
|
126
|
-
const runs = reply.result["runs"];
|
|
127
|
-
if (!Array.isArray(runs))
|
|
128
|
-
throw new Error("invalid-run-list");
|
|
129
|
-
if (runs.some((value) => {
|
|
130
|
-
const run = record(value);
|
|
131
|
-
return run?.["workflowId"] === "develop-issue" && !terminal(run);
|
|
132
|
-
}))
|
|
133
|
-
return true;
|
|
134
|
-
const next = reply.result["next"];
|
|
135
|
-
if (next !== null && (typeof next !== "string" || next <= after))
|
|
136
|
-
throw new Error("invalid-run-page");
|
|
137
|
-
after = next;
|
|
138
|
-
} while (after !== null);
|
|
139
|
-
return false;
|
|
145
|
+
endings.sort((first, second) => Number(first.run["terminalSequence"] ?? first.run["latestSequence"] ?? 0) -
|
|
146
|
+
Number(second.run["terminalSequence"] ?? second.run["latestSequence"] ?? 0));
|
|
147
|
+
for (const ending of endings)
|
|
148
|
+
await retired(pending, ending);
|
|
149
|
+
return pendingRuns;
|
|
140
150
|
}
|
|
141
151
|
async function submit(settings, pending) {
|
|
142
152
|
const commandId = pending.retryCommandId ?? randomUUID();
|
|
@@ -145,7 +155,7 @@ async function submit(settings, pending) {
|
|
|
145
155
|
const reply = await send(settings.runtimeDirectory, {
|
|
146
156
|
operation: "run",
|
|
147
157
|
parameters: {
|
|
148
|
-
workflowId: "develop-issue",
|
|
158
|
+
workflowId: settings.workflowId ?? "develop-issue",
|
|
149
159
|
source: "ticket",
|
|
150
160
|
submission: { ticket: "next" },
|
|
151
161
|
commandId,
|
|
@@ -163,19 +173,38 @@ async function submit(settings, pending) {
|
|
|
163
173
|
process.stderr.write(`Queue ${reply.error.code}: command ${commandId}; will retry\n`);
|
|
164
174
|
return;
|
|
165
175
|
}
|
|
166
|
-
if (![
|
|
176
|
+
if (![
|
|
177
|
+
"no-ready-ticket",
|
|
178
|
+
"workflow-active",
|
|
179
|
+
"ticket-active",
|
|
180
|
+
"ticket-dependency-open",
|
|
181
|
+
].includes(reply.error.code))
|
|
167
182
|
throw new Error(reply.error.code);
|
|
168
183
|
pending.commands.delete(commandId);
|
|
169
184
|
await pending.save();
|
|
170
185
|
}
|
|
186
|
+
async function pendingUpdate(directory) {
|
|
187
|
+
return readFile(join(directory, "pending-self-update"), "utf8").catch((error) => {
|
|
188
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
189
|
+
return undefined;
|
|
190
|
+
throw error;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
async function holdStarted(pending, observed) {
|
|
194
|
+
const { mark, activeRuns } = observed;
|
|
195
|
+
const timestamp = Number(mark);
|
|
196
|
+
if (!Number.isFinite(timestamp) || timestamp <= 0)
|
|
197
|
+
throw new Error("invalid-pending-self-update");
|
|
198
|
+
if (pending.selfUpdateHold?.mark !== mark || activeRuns > 0) {
|
|
199
|
+
pending.selfUpdateHold = { mark, startedAt: Date.now() };
|
|
200
|
+
await pending.save();
|
|
201
|
+
}
|
|
202
|
+
return pending.selfUpdateHold.startedAt;
|
|
203
|
+
}
|
|
171
204
|
function updateHold(directory, pending) {
|
|
172
205
|
let notice;
|
|
173
|
-
return async () => {
|
|
174
|
-
const mark = await
|
|
175
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
176
|
-
return undefined;
|
|
177
|
-
throw error;
|
|
178
|
-
});
|
|
206
|
+
return async (activeRuns = 0) => {
|
|
207
|
+
const mark = await pendingUpdate(directory);
|
|
179
208
|
if (mark === undefined && pending.selfUpdateHold !== undefined) {
|
|
180
209
|
pending.selfUpdateHold = undefined;
|
|
181
210
|
await pending.save();
|
|
@@ -184,14 +213,8 @@ function updateHold(directory, pending) {
|
|
|
184
213
|
notice = undefined;
|
|
185
214
|
return false;
|
|
186
215
|
}
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
throw new Error("invalid-pending-self-update");
|
|
190
|
-
if (pending.selfUpdateHold?.mark !== mark) {
|
|
191
|
-
pending.selfUpdateHold = { mark, startedAt: Date.now() };
|
|
192
|
-
await pending.save();
|
|
193
|
-
}
|
|
194
|
-
const holding = Date.now() - pending.selfUpdateHold.startedAt < 30 * 60 * 1000;
|
|
216
|
+
const startedAt = await holdStarted(pending, { mark, activeRuns });
|
|
217
|
+
const holding = activeRuns > 0 || Date.now() - startedAt < 30 * 60 * 1000;
|
|
195
218
|
const line = holding
|
|
196
219
|
? "Queue holding for pending self-update\n"
|
|
197
220
|
: "Queue continuing after pending self-update time limit\n";
|
|
@@ -227,11 +250,17 @@ async function cycle(settings, signal) {
|
|
|
227
250
|
await delay(settings.intervalMilliseconds, undefined, { signal }).catch(() => undefined);
|
|
228
251
|
if (stopped())
|
|
229
252
|
return;
|
|
230
|
-
|
|
253
|
+
const pendingRuns = await completed(settings, pending);
|
|
254
|
+
const lanes = settings.lanes ?? 1;
|
|
255
|
+
if (pendingRuns >= lanes) {
|
|
256
|
+
await holding(pendingRuns);
|
|
231
257
|
continue;
|
|
232
|
-
|
|
258
|
+
}
|
|
259
|
+
const activeRuns = await activeQueueRuns(settings);
|
|
260
|
+
const held = await holding(activeRuns);
|
|
261
|
+
if (activeRuns >= lanes || activeRuns < pendingRuns)
|
|
233
262
|
continue;
|
|
234
|
-
if (
|
|
263
|
+
if (held)
|
|
235
264
|
continue;
|
|
236
265
|
if (stopped())
|
|
237
266
|
return;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Notification } from "./notify-message.ts";
|
|
2
|
+
export interface DeliveryEntry {
|
|
3
|
+
readonly key: string;
|
|
4
|
+
readonly message: Notification | null;
|
|
5
|
+
readonly state: "pending" | "sent" | "failed";
|
|
6
|
+
readonly attempts: number;
|
|
7
|
+
readonly lastAttemptAt: number | null;
|
|
8
|
+
readonly lastFailure: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface RecordedNotifications {
|
|
11
|
+
readonly entries: Map<string, DeliveryEntry>;
|
|
12
|
+
readonly retiredKeys: Set<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare function recordedNotifications(file: string): Promise<RecordedNotifications | undefined>;
|
|
15
|
+
export declare function saveNotifications(file: string, journal: {
|
|
16
|
+
readonly entries: ReadonlyMap<string, DeliveryEntry>;
|
|
17
|
+
readonly retiredKeys: ReadonlySet<string>;
|
|
18
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { open, readFile, rename } from "node:fs/promises";
|
|
2
|
+
import { record } from "../protocol.js";
|
|
3
|
+
export async function recordedNotifications(file) {
|
|
4
|
+
const text = await readFile(file, "utf8").catch((error) => {
|
|
5
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
6
|
+
return undefined;
|
|
7
|
+
throw error;
|
|
8
|
+
});
|
|
9
|
+
if (text === undefined)
|
|
10
|
+
return undefined;
|
|
11
|
+
const value = JSON.parse(text);
|
|
12
|
+
const journal = record(value);
|
|
13
|
+
if (journal?.["version"] === 1 && Array.isArray(journal["entries"])) {
|
|
14
|
+
const entries = journal["entries"].map(deliveryEntry);
|
|
15
|
+
const found = new Map(entries.map((entry) => [entry.key, entry]));
|
|
16
|
+
if (found.size !== entries.length)
|
|
17
|
+
throw new Error("invalid-notify-record");
|
|
18
|
+
return {
|
|
19
|
+
entries: found,
|
|
20
|
+
retiredKeys: recordedKeys(journal["retiredKeys"] ?? []),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const keys = recordedKeys(value);
|
|
24
|
+
return {
|
|
25
|
+
retiredKeys: new Set(),
|
|
26
|
+
entries: new Map([...keys].map((key) => [
|
|
27
|
+
key,
|
|
28
|
+
{
|
|
29
|
+
key,
|
|
30
|
+
message: null,
|
|
31
|
+
state: "sent",
|
|
32
|
+
attempts: 0,
|
|
33
|
+
lastAttemptAt: Date.now(),
|
|
34
|
+
lastFailure: null,
|
|
35
|
+
},
|
|
36
|
+
])),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function recordedKeys(value) {
|
|
40
|
+
if (!Array.isArray(value) ||
|
|
41
|
+
!value.every((key) => typeof key === "string"))
|
|
42
|
+
throw new Error("invalid-notify-record");
|
|
43
|
+
return new Set(value.map(String));
|
|
44
|
+
}
|
|
45
|
+
function notification(value) {
|
|
46
|
+
const message = record(value);
|
|
47
|
+
if (message === undefined)
|
|
48
|
+
return false;
|
|
49
|
+
return (["decision", "blocked", "failed"].includes(String(message["event"])) &&
|
|
50
|
+
["event", "runId", "workflowId", "subject", "body"].every((field) => typeof message[field] === "string"));
|
|
51
|
+
}
|
|
52
|
+
function deliveryState(value) {
|
|
53
|
+
return value === "pending" || value === "sent" || value === "failed";
|
|
54
|
+
}
|
|
55
|
+
function attemptCount(value) {
|
|
56
|
+
return (typeof value === "number" &&
|
|
57
|
+
Number.isInteger(value) &&
|
|
58
|
+
value >= 0 &&
|
|
59
|
+
value <= 5);
|
|
60
|
+
}
|
|
61
|
+
function attemptTime(value) {
|
|
62
|
+
return (value === null ||
|
|
63
|
+
(typeof value === "number" && Number.isSafeInteger(value) && value >= 0));
|
|
64
|
+
}
|
|
65
|
+
function deliveryEntry(value) {
|
|
66
|
+
const { key, message, state, attempts, lastAttemptAt, lastFailure } = record(value) ?? {};
|
|
67
|
+
if (typeof key !== "string" ||
|
|
68
|
+
!deliveryState(state) ||
|
|
69
|
+
!attemptCount(attempts))
|
|
70
|
+
throw new Error("invalid-notify-record");
|
|
71
|
+
if (!attemptTime(lastAttemptAt) ||
|
|
72
|
+
!(lastFailure === null || typeof lastFailure === "string"))
|
|
73
|
+
throw new Error("invalid-notify-record");
|
|
74
|
+
const content = { message, state };
|
|
75
|
+
if (!entryMessage(content))
|
|
76
|
+
throw new Error("invalid-notify-record");
|
|
77
|
+
return {
|
|
78
|
+
key,
|
|
79
|
+
message: content.message,
|
|
80
|
+
state,
|
|
81
|
+
attempts,
|
|
82
|
+
lastAttemptAt,
|
|
83
|
+
lastFailure,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function entryMessage(entry) {
|
|
87
|
+
return entry.message === null
|
|
88
|
+
? entry.state === "sent"
|
|
89
|
+
: notification(entry.message);
|
|
90
|
+
}
|
|
91
|
+
export async function saveNotifications(file, journal) {
|
|
92
|
+
const temporary = await open(`${file}.tmp`, "w", 0o600);
|
|
93
|
+
try {
|
|
94
|
+
await temporary.chmod(0o600);
|
|
95
|
+
await temporary.writeFile(JSON.stringify({
|
|
96
|
+
version: 1,
|
|
97
|
+
entries: [...journal.entries.values()],
|
|
98
|
+
...(journal.retiredKeys.size > 0
|
|
99
|
+
? { retiredKeys: [...journal.retiredKeys] }
|
|
100
|
+
: {}),
|
|
101
|
+
}) + "\n");
|
|
102
|
+
await temporary.sync();
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await temporary.close();
|
|
106
|
+
}
|
|
107
|
+
await rename(`${file}.tmp`, file);
|
|
108
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { operationalDecision } from "../decision-visibility.js";
|
|
1
2
|
import { decisionLines, runStatus } from "../cli/render.js";
|
|
2
3
|
import { record } from "../protocol.js";
|
|
3
4
|
function body(text, commands) {
|
|
@@ -17,7 +18,7 @@ function message(run, content) {
|
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
export function decisionNotification(run, decision) {
|
|
20
|
-
const lines = decisionLines(decision);
|
|
21
|
+
const lines = decisionLines(operationalDecision(decision, String(run["workflowId"])));
|
|
21
22
|
const allowed = decision["allowed"];
|
|
22
23
|
const count = Array.isArray(allowed) ? allowed.length : 0;
|
|
23
24
|
const split = lines.length - count;
|