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
package/dist/src/token-prices.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { priceOf, usageOf } from "./worker-usage.js";
|
|
1
|
+
import { priceOf, sumPrices, usageOf, } from "./worker-usage.js";
|
|
2
2
|
import { record } from "./protocol.js";
|
|
3
3
|
export const builtInPriceTable = {
|
|
4
4
|
date: "2026-10-18",
|
|
@@ -90,16 +90,29 @@ export function replaceCommandModel(command, model) {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
export function estimatedCostUsd(usage, pricing) {
|
|
93
|
+
return "models" in pricing
|
|
94
|
+
? modelCostUsd(pricing)
|
|
95
|
+
: singleCostUsd(usage, pricing);
|
|
96
|
+
}
|
|
97
|
+
function modelCostUsd(pricing) {
|
|
98
|
+
return sumPrices(pricing.models.map(({ model, usage: counts }) => singleCostUsd(counts, {
|
|
99
|
+
worker: "gemini",
|
|
100
|
+
price: priceForModel(pricing.prices, model),
|
|
101
|
+
})));
|
|
102
|
+
}
|
|
103
|
+
function singleCostUsd(usage, pricing) {
|
|
93
104
|
const { worker, price } = pricing;
|
|
94
105
|
const counts = usageOf(usage);
|
|
95
106
|
const cached = counts.cache_read_input_tokens;
|
|
96
107
|
const output = counts.output_tokens;
|
|
97
108
|
if (price === undefined ||
|
|
109
|
+
(worker === "cursor-agent" && counts.cache_creation_input_tokens !== 0) ||
|
|
98
110
|
counts.input_tokens === null ||
|
|
99
111
|
cached === null ||
|
|
100
112
|
output === null)
|
|
101
113
|
return null;
|
|
102
|
-
const input = counts.input_tokens -
|
|
114
|
+
const input = counts.input_tokens -
|
|
115
|
+
(worker === "codex" || worker === "gemini" ? cached : 0);
|
|
103
116
|
if (input < 0)
|
|
104
117
|
return null;
|
|
105
118
|
return priceOf((input / 1_000_000) * price.input +
|
package/dist/src/turn-profile.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fields = [
|
|
2
|
+
"harness",
|
|
2
3
|
"env",
|
|
3
4
|
"allowedTools",
|
|
4
5
|
"model",
|
|
@@ -29,6 +30,8 @@ function environment(value) {
|
|
|
29
30
|
text(item)));
|
|
30
31
|
}
|
|
31
32
|
function validField(name, value) {
|
|
33
|
+
if (name === "harness")
|
|
34
|
+
return typeof value === "string" && /^[a-z][a-z0-9-]{0,63}$/.test(value);
|
|
32
35
|
if (name === "env")
|
|
33
36
|
return environment(value);
|
|
34
37
|
if (name === "allowedTools" || name === "workflows")
|
|
@@ -71,7 +74,11 @@ function retained(argumentsList, values) {
|
|
|
71
74
|
for (let index = 0; index < argumentsList.length;) {
|
|
72
75
|
const argument = argumentsList[index] ?? "";
|
|
73
76
|
const name = argument.split("=")[0] ?? "";
|
|
74
|
-
const
|
|
77
|
+
const aliases = {
|
|
78
|
+
"--allowed-tools": "--allowedTools",
|
|
79
|
+
"-m": "--model",
|
|
80
|
+
};
|
|
81
|
+
const flag = aliases[name] ?? name;
|
|
75
82
|
if (!values.has(flag)) {
|
|
76
83
|
kept.push(argument);
|
|
77
84
|
index += 1;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
export type RetryKind = "capacity" | "network";
|
|
1
2
|
export interface WorkerUsage {
|
|
3
|
+
readonly cache_creation_input_tokens?: number | null;
|
|
2
4
|
readonly input_tokens: number | null;
|
|
3
5
|
readonly cache_read_input_tokens: number | null;
|
|
4
6
|
readonly output_tokens: number | null;
|
|
5
7
|
}
|
|
6
8
|
export interface WorkerTurnUsage {
|
|
9
|
+
readonly model?: string;
|
|
10
|
+
readonly summary?: string;
|
|
11
|
+
readonly harness?: string;
|
|
7
12
|
readonly attempts?: readonly WorkerAttemptUsage[];
|
|
8
13
|
readonly estimatedCostUsd: number | null;
|
|
9
14
|
readonly operationId: string;
|
|
@@ -11,12 +16,19 @@ export interface WorkerTurnUsage {
|
|
|
11
16
|
readonly costUsd: number | null;
|
|
12
17
|
}
|
|
13
18
|
export interface WorkerAttemptUsage {
|
|
19
|
+
readonly models?: readonly WorkerModelUsage[];
|
|
20
|
+
readonly retryKind?: RetryKind | null;
|
|
14
21
|
readonly attempt: number;
|
|
15
22
|
readonly model: string | null;
|
|
16
23
|
readonly usage: WorkerUsage;
|
|
17
24
|
readonly costUsd: number | null;
|
|
18
25
|
readonly estimatedCostUsd: number | null;
|
|
19
26
|
}
|
|
27
|
+
export interface WorkerModelUsage {
|
|
28
|
+
readonly model: string;
|
|
29
|
+
readonly usage: WorkerUsage;
|
|
30
|
+
}
|
|
31
|
+
export declare function modelUsageOf(value: unknown): readonly WorkerModelUsage[] | undefined;
|
|
20
32
|
export interface WorkerTotals {
|
|
21
33
|
readonly estimatedCostUsd: number | null;
|
|
22
34
|
readonly workerTurns: readonly WorkerTurnUsage[];
|
|
@@ -29,3 +41,7 @@ export declare function usageOf(value: unknown): WorkerUsage;
|
|
|
29
41
|
export declare function sumUsage(values: readonly WorkerUsage[]): WorkerUsage;
|
|
30
42
|
export declare function sumPrices(values: readonly (number | null)[]): number | null;
|
|
31
43
|
export declare function workerTotals(workerTurns: readonly WorkerTurnUsage[]): WorkerTotals;
|
|
44
|
+
export declare function attemptsOf(value: unknown): readonly WorkerAttemptUsage[] | undefined;
|
|
45
|
+
export declare function attemptFields(value: unknown): {
|
|
46
|
+
readonly attempts?: readonly WorkerAttemptUsage[];
|
|
47
|
+
};
|
package/dist/src/worker-usage.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export function modelUsageOf(value) {
|
|
2
|
+
if (!Array.isArray(value))
|
|
3
|
+
return undefined;
|
|
4
|
+
return value.flatMap((entry) => {
|
|
5
|
+
if (typeof entry !== "object" || entry === null)
|
|
6
|
+
return [];
|
|
7
|
+
const model = Reflect.get(entry, "model");
|
|
8
|
+
if (typeof model !== "string")
|
|
9
|
+
return [];
|
|
10
|
+
return [{ model, usage: usageOf(Reflect.get(entry, "usage")) }];
|
|
11
|
+
});
|
|
12
|
+
}
|
|
1
13
|
export function priceOf(value) {
|
|
2
14
|
return typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
3
15
|
? value
|
|
@@ -11,6 +23,11 @@ export function tokenCount(value) {
|
|
|
11
23
|
export function usageOf(value) {
|
|
12
24
|
const fields = typeof value === "object" && value !== null ? value : {};
|
|
13
25
|
return {
|
|
26
|
+
...(Object.hasOwn(fields, "cache_creation_input_tokens")
|
|
27
|
+
? {
|
|
28
|
+
cache_creation_input_tokens: tokenCount(Reflect.get(fields, "cache_creation_input_tokens")),
|
|
29
|
+
}
|
|
30
|
+
: {}),
|
|
14
31
|
input_tokens: tokenCount(Reflect.get(fields, "input_tokens")),
|
|
15
32
|
cache_read_input_tokens: tokenCount(Reflect.get(fields, "cache_read_input_tokens")),
|
|
16
33
|
output_tokens: tokenCount(Reflect.get(fields, "output_tokens")),
|
|
@@ -23,6 +40,11 @@ function total(values) {
|
|
|
23
40
|
}
|
|
24
41
|
export function sumUsage(values) {
|
|
25
42
|
return {
|
|
43
|
+
...(values.some((value) => Object.hasOwn(value, "cache_creation_input_tokens"))
|
|
44
|
+
? {
|
|
45
|
+
cache_creation_input_tokens: total(values.map((value) => value.cache_creation_input_tokens ?? null)),
|
|
46
|
+
}
|
|
47
|
+
: {}),
|
|
26
48
|
input_tokens: total(values.map((value) => value.input_tokens)),
|
|
27
49
|
cache_read_input_tokens: total(values.map((value) => value.cache_read_input_tokens)),
|
|
28
50
|
output_tokens: total(values.map((value) => value.output_tokens)),
|
|
@@ -42,3 +64,38 @@ export function workerTotals(workerTurns) {
|
|
|
42
64
|
estimatedCostUsd: sumPrices(workerTurns.map((turn) => turn.estimatedCostUsd)),
|
|
43
65
|
};
|
|
44
66
|
}
|
|
67
|
+
function retryKindField(value) {
|
|
68
|
+
return value === null || value === "capacity" || value === "network"
|
|
69
|
+
? { retryKind: value }
|
|
70
|
+
: {};
|
|
71
|
+
}
|
|
72
|
+
export function attemptsOf(value) {
|
|
73
|
+
if (!Array.isArray(value))
|
|
74
|
+
return undefined;
|
|
75
|
+
return value.flatMap((entry) => {
|
|
76
|
+
const fields = typeof entry === "object" && entry !== null ? entry : {};
|
|
77
|
+
const field = (name) => Reflect.get(fields, name);
|
|
78
|
+
const attempt = tokenCount(field("attempt"));
|
|
79
|
+
const model = field("model");
|
|
80
|
+
const models = modelUsageOf(field("models"));
|
|
81
|
+
if (attempt === null ||
|
|
82
|
+
attempt === 0 ||
|
|
83
|
+
(model !== null && typeof model !== "string"))
|
|
84
|
+
return [];
|
|
85
|
+
return [
|
|
86
|
+
{
|
|
87
|
+
...retryKindField(field("retryKind")),
|
|
88
|
+
attempt,
|
|
89
|
+
model,
|
|
90
|
+
...(models === undefined ? {} : { models }),
|
|
91
|
+
usage: usageOf(field("usage")),
|
|
92
|
+
costUsd: priceOf(field("costUsd")),
|
|
93
|
+
estimatedCostUsd: priceOf(field("estimatedCostUsd")),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
export function attemptFields(value) {
|
|
99
|
+
const attempts = attemptsOf(value);
|
|
100
|
+
return attempts === undefined ? {} : { attempts };
|
|
101
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommandWaits } from "./workflow-declaration.ts";
|
|
1
2
|
export interface ToolchainIdentity {
|
|
2
3
|
readonly sdk: string;
|
|
3
4
|
readonly world: string;
|
|
@@ -23,11 +24,15 @@ export interface AdmissionPolicy {
|
|
|
23
24
|
readonly capabilities: readonly string[];
|
|
24
25
|
}
|
|
25
26
|
export interface ExecutionManifest {
|
|
27
|
+
readonly queue?: boolean;
|
|
26
28
|
readonly name: string;
|
|
27
29
|
readonly workflowId: string;
|
|
28
30
|
readonly steps: readonly string[];
|
|
29
31
|
readonly capabilities: readonly string[];
|
|
30
32
|
readonly handoffs?: readonly string[];
|
|
33
|
+
readonly commands?: readonly string[];
|
|
34
|
+
readonly commandWaits?: CommandWaits;
|
|
35
|
+
readonly bundleDigest?: string;
|
|
31
36
|
readonly artifacts: Readonly<Record<string, string>>;
|
|
32
37
|
readonly resources: Readonly<Record<string, string>>;
|
|
33
38
|
readonly toolchain: ToolchainIdentity;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type WorkflowDeclaration } from "./workflow-declaration.ts";
|
|
1
|
+
import { type WorkflowQueueCode, type WorkflowDeclaration } from "./workflow-declaration.ts";
|
|
2
2
|
export interface CandidateDeclaration {
|
|
3
3
|
readonly workflow: WorkflowDeclaration;
|
|
4
4
|
readonly methods: Readonly<Record<string, readonly string[]>>;
|
|
@@ -6,12 +6,14 @@ export interface CandidateDeclaration {
|
|
|
6
6
|
export interface CandidateImport {
|
|
7
7
|
readonly module: string;
|
|
8
8
|
readonly names: readonly string[];
|
|
9
|
+
readonly source?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface CandidateEffect {
|
|
11
12
|
readonly capability: string | null;
|
|
12
13
|
readonly method: string | null;
|
|
13
14
|
}
|
|
14
15
|
export interface CandidateAnalysis {
|
|
16
|
+
readonly localSources?: readonly string[];
|
|
15
17
|
readonly imports: readonly CandidateImport[];
|
|
16
18
|
readonly effects: readonly CandidateEffect[];
|
|
17
19
|
readonly directEffects: readonly string[];
|
|
@@ -20,10 +22,13 @@ export interface CandidateAnalysis {
|
|
|
20
22
|
readonly knownUnitTotal: number;
|
|
21
23
|
}
|
|
22
24
|
export type InstalledWorkflowExports = Readonly<Record<string, readonly string[]>>;
|
|
23
|
-
export type WorkflowCandidateCode = "invalid-declaration" | "forbidden-import" | "missing-export" | "unsupported-source" | "dynamic-effect" | "undeclared-effect" | "effect-limit" | "direct-effect";
|
|
25
|
+
export type WorkflowCandidateCode = WorkflowQueueCode | "invalid-declaration" | "forbidden-import" | "missing-export" | "unsupported-source" | "dynamic-effect" | "undeclared-effect" | "effect-limit" | "direct-effect";
|
|
24
26
|
export interface WorkflowCandidateInput {
|
|
25
27
|
readonly declaration: unknown;
|
|
26
28
|
readonly analysis: CandidateAnalysis;
|
|
27
29
|
readonly installedExports: InstalledWorkflowExports;
|
|
28
30
|
}
|
|
31
|
+
export declare function workflowHelperPath(source: string, imported: string): string | undefined;
|
|
32
|
+
export declare function isCandidateDeclaration(value: unknown): value is CandidateDeclaration;
|
|
29
33
|
export declare function checkWorkflowCandidate(input: WorkflowCandidateInput): readonly WorkflowCandidateCode[];
|
|
34
|
+
export declare function candidateDeclarationRefusals(value: unknown): readonly WorkflowCandidateCode[];
|
|
@@ -1,22 +1,58 @@
|
|
|
1
1
|
import { record } from "./protocol.js";
|
|
2
|
-
import { isWorkflowDeclaration, } from "./workflow-declaration.js";
|
|
2
|
+
import { isWorkflowDeclaration, workflowQueueRefusals, } from "./workflow-declaration.js";
|
|
3
3
|
const workflowModules = [
|
|
4
4
|
"cloving/workflows",
|
|
5
5
|
"cloving/workflows/steps/decision-gate",
|
|
6
|
+
"cloving/workflows/steps/wait-for-decision",
|
|
7
|
+
"cloving/workflows/steps/review-by-person",
|
|
8
|
+
"cloving/workflows/steps/review-by-agent",
|
|
9
|
+
"cloving/workflows/steps/merge-by-person",
|
|
10
|
+
"cloving/workflows/steps/merge-when-green",
|
|
11
|
+
"cloving/workflows/steps/review-subject",
|
|
6
12
|
"cloving/workflows/steps/load-cycle",
|
|
7
13
|
"cloving/workflows/steps/protected-effect",
|
|
8
14
|
"cloving/workflows/steps/handoff",
|
|
15
|
+
"cloving/workflows/steps/wait-for-run",
|
|
16
|
+
"cloving/workflows/steps/run-command",
|
|
17
|
+
"cloving/workflows/steps/sleep",
|
|
9
18
|
];
|
|
19
|
+
export function workflowHelperPath(source, imported) {
|
|
20
|
+
if (!imported.startsWith("./"))
|
|
21
|
+
return undefined;
|
|
22
|
+
const parts = [
|
|
23
|
+
...source.split("/").slice(0, -1),
|
|
24
|
+
...imported.slice(2).split("/"),
|
|
25
|
+
];
|
|
26
|
+
if (parts.length < 2 ||
|
|
27
|
+
parts.some((part) => part.length === 0 ||
|
|
28
|
+
part === "." ||
|
|
29
|
+
part === ".." ||
|
|
30
|
+
part.toUpperCase() === "NODE_MODULES" ||
|
|
31
|
+
/[\\:\0]/.test(part) ||
|
|
32
|
+
part.startsWith("~")))
|
|
33
|
+
return undefined;
|
|
34
|
+
const path = parts.join("/");
|
|
35
|
+
return path.endsWith(".ts") && !path.endsWith(".d.ts") ? path : undefined;
|
|
36
|
+
}
|
|
37
|
+
function allowedImport(entry, analysis) {
|
|
38
|
+
if (workflowModules.includes(entry.module))
|
|
39
|
+
return true;
|
|
40
|
+
const path = workflowHelperPath(entry.source ?? "candidate.ts", entry.module);
|
|
41
|
+
return path !== undefined && (analysis.localSources ?? []).includes(path);
|
|
42
|
+
}
|
|
10
43
|
function isMethodList(value) {
|
|
11
44
|
return (Array.isArray(value) &&
|
|
12
45
|
value.length > 0 &&
|
|
13
46
|
Array.from(value).every((method) => typeof method === "string" && method.trim().length > 0) &&
|
|
14
47
|
new Set(value).size === value.length);
|
|
15
48
|
}
|
|
16
|
-
function isCandidateDeclaration(value) {
|
|
49
|
+
export function isCandidateDeclaration(value) {
|
|
17
50
|
const fields = record(value);
|
|
18
51
|
if (!fields ||
|
|
19
|
-
Object.keys(fields).some((key) =>
|
|
52
|
+
Object.keys(fields).some((key) => !["workflow", "methods", "template"].includes(key)) ||
|
|
53
|
+
(Object.hasOwn(fields, "template") &&
|
|
54
|
+
(typeof fields["template"] !== "string" ||
|
|
55
|
+
!/^[a-z][a-z0-9-]{0,63}$/.test(fields["template"]))))
|
|
20
56
|
return false;
|
|
21
57
|
const workflow = fields["workflow"];
|
|
22
58
|
const methods = record(fields["methods"]);
|
|
@@ -28,10 +64,10 @@ function isCandidateDeclaration(value) {
|
|
|
28
64
|
}
|
|
29
65
|
export function checkWorkflowCandidate(input) {
|
|
30
66
|
if (!isCandidateDeclaration(input.declaration))
|
|
31
|
-
return
|
|
67
|
+
return candidateDeclarationRefusals(input.declaration);
|
|
32
68
|
const { analysis, declaration, installedExports } = input;
|
|
33
69
|
const codes = [];
|
|
34
|
-
if (analysis.imports.some((entry) => !
|
|
70
|
+
if (analysis.imports.some((entry) => !allowedImport(entry, analysis)))
|
|
35
71
|
codes.push("forbidden-import");
|
|
36
72
|
if (analysis.imports.some((entry) => {
|
|
37
73
|
if (!workflowModules.includes(entry.module))
|
|
@@ -58,3 +94,9 @@ export function checkWorkflowCandidate(input) {
|
|
|
58
94
|
codes.push("unsupported-source");
|
|
59
95
|
return [...new Set(codes)].sort();
|
|
60
96
|
}
|
|
97
|
+
export function candidateDeclarationRefusals(value) {
|
|
98
|
+
if (isCandidateDeclaration(value))
|
|
99
|
+
return [];
|
|
100
|
+
const codes = workflowQueueRefusals(record(value)?.["workflow"]);
|
|
101
|
+
return codes.length > 0 ? codes : ["invalid-declaration"];
|
|
102
|
+
}
|
|
@@ -1,22 +1,40 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SubmissionContract } from "./submission.ts";
|
|
2
|
+
import { type WorkflowSchedule } from "./workflow-schedule.ts";
|
|
2
3
|
export interface WorkflowStage {
|
|
3
4
|
readonly name: string;
|
|
4
5
|
readonly label: string;
|
|
5
6
|
readonly operations?: readonly string[];
|
|
6
7
|
readonly gateKinds?: readonly ("approval" | "question")[];
|
|
8
|
+
readonly gateIds?: readonly string[];
|
|
7
9
|
}
|
|
8
10
|
export type WorkflowStages = Readonly<Record<string, readonly WorkflowStage[]>>;
|
|
11
|
+
export interface CommandWaitDeclaration {
|
|
12
|
+
readonly command: string;
|
|
13
|
+
readonly maximumWaitSeconds: number;
|
|
14
|
+
readonly pollEverySeconds: number;
|
|
15
|
+
}
|
|
16
|
+
export type CommandWaits = Readonly<Record<string, CommandWaitDeclaration>>;
|
|
9
17
|
export interface WorkflowDeclaration {
|
|
10
18
|
readonly workflowId: string;
|
|
11
19
|
readonly effectLimit: number;
|
|
12
|
-
readonly capabilities: readonly ("claude" | "github" | "
|
|
20
|
+
readonly capabilities: readonly ("claude" | "github" | "command")[];
|
|
13
21
|
readonly input: SubmissionContract;
|
|
14
22
|
readonly stages?: readonly WorkflowStage[];
|
|
15
23
|
readonly handoffs?: readonly string[];
|
|
24
|
+
readonly commands?: readonly string[];
|
|
25
|
+
readonly commandWaits?: CommandWaits;
|
|
26
|
+
readonly queue?: boolean;
|
|
27
|
+
readonly schedule?: WorkflowSchedule;
|
|
16
28
|
}
|
|
17
29
|
export interface DeclaredWorkflow extends WorkflowDeclaration {
|
|
18
30
|
readonly functionName: string;
|
|
19
31
|
}
|
|
32
|
+
export type WorkflowQueueCode = "queue-needs-ticket-field" | "queue-input-incomplete";
|
|
33
|
+
export declare function workflowQueueRefusals(value: unknown): readonly WorkflowQueueCode[];
|
|
20
34
|
export declare function isWorkflowStages(value: unknown): value is readonly WorkflowStage[];
|
|
21
|
-
export declare function
|
|
35
|
+
export declare function isWorkflowNames(value: unknown): value is readonly string[];
|
|
36
|
+
export declare function isCommandWaits(value: unknown, permissions: {
|
|
37
|
+
readonly capabilities: readonly string[];
|
|
38
|
+
readonly commands: readonly string[];
|
|
39
|
+
}): value is CommandWaits;
|
|
22
40
|
export declare function isWorkflowDeclaration(value: unknown): value is WorkflowDeclaration;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { record } from "./protocol.js";
|
|
2
|
+
import { hasTicketField, } from "./submission.js";
|
|
3
|
+
import { checkWorkflowSchedule, } from "./workflow-schedule.js";
|
|
4
|
+
export function workflowQueueRefusals(value) {
|
|
5
|
+
const declaration = record(value);
|
|
6
|
+
if (declaration?.["queue"] !== true || !isInput(declaration["input"]))
|
|
7
|
+
return [];
|
|
8
|
+
const input = declaration["input"];
|
|
9
|
+
if (!hasTicketField(input))
|
|
10
|
+
return ["queue-needs-ticket-field"];
|
|
11
|
+
return Object.entries(input.fields).some(([name, rule]) => name !== "ticket" && (rule === "string" || rule.optional !== true))
|
|
12
|
+
? ["queue-input-incomplete"]
|
|
13
|
+
: [];
|
|
14
|
+
}
|
|
2
15
|
function keys(fields, allowed) {
|
|
3
16
|
return (fields !== undefined &&
|
|
4
17
|
Object.keys(fields).every((key) => allowed.includes(key)));
|
|
@@ -28,7 +41,9 @@ function isField(value) {
|
|
|
28
41
|
return false;
|
|
29
42
|
if (fields["type"] === "integer")
|
|
30
43
|
return integerBounds(fields);
|
|
31
|
-
return ((fields["type"] === "string" ||
|
|
44
|
+
return ((fields["type"] === "string" ||
|
|
45
|
+
fields["type"] === "boolean" ||
|
|
46
|
+
fields["type"] === "ticket") &&
|
|
32
47
|
!Object.hasOwn(fields, "minimum") &&
|
|
33
48
|
!Object.hasOwn(fields, "maximum"));
|
|
34
49
|
}
|
|
@@ -39,7 +54,7 @@ function isInput(value) {
|
|
|
39
54
|
const fields = record(input["fields"]);
|
|
40
55
|
return (integer(input["maximumBytes"], { minimum: 1, maximum: 1_048_576 }) &&
|
|
41
56
|
fields !== undefined &&
|
|
42
|
-
Object.
|
|
57
|
+
Object.entries(fields).every(([name, rule]) => isField(rule) && (rule.type !== "ticket" || name === "ticket")));
|
|
43
58
|
}
|
|
44
59
|
function matches(value, pattern) {
|
|
45
60
|
return typeof value === "string" && pattern.test(value);
|
|
@@ -56,18 +71,20 @@ function isStageLabel(label) {
|
|
|
56
71
|
}
|
|
57
72
|
function isStage(value) {
|
|
58
73
|
const stage = record(value);
|
|
59
|
-
if (!keys(stage, ["name", "label", "operations", "gateKinds"]))
|
|
74
|
+
if (!keys(stage, ["name", "label", "operations", "gateKinds", "gateIds"]))
|
|
60
75
|
return false;
|
|
61
76
|
const { name, label } = stage;
|
|
62
77
|
const operations = Object.hasOwn(stage, "operations")
|
|
63
78
|
? stage["operations"]
|
|
64
79
|
: [];
|
|
65
80
|
const gateKinds = Object.hasOwn(stage, "gateKinds") ? stage["gateKinds"] : [];
|
|
81
|
+
const gateIds = Object.hasOwn(stage, "gateIds") ? stage["gateIds"] : [];
|
|
66
82
|
return (matches(name, /^[A-Za-z0-9-]{1,64}$/) &&
|
|
67
83
|
isStageLabel(label) &&
|
|
68
84
|
selectors(operations, /^[A-Za-z0-9._:/-]{1,128}$/) &&
|
|
69
85
|
selectors(gateKinds, /^(approval|question)$/) &&
|
|
70
|
-
|
|
86
|
+
selectors(gateIds, /^[A-Za-z0-9._:/-]{1,128}$/) &&
|
|
87
|
+
operations.length + gateKinds.length + gateIds.length > 0);
|
|
71
88
|
}
|
|
72
89
|
function unique(values) {
|
|
73
90
|
return new Set(values).size === values.length;
|
|
@@ -81,18 +98,55 @@ export function isWorkflowStages(value) {
|
|
|
81
98
|
return (unique(stages.map((stage) => stage.name)) &&
|
|
82
99
|
unique(stages.map((stage) => stage.label)) &&
|
|
83
100
|
unique(stages.flatMap((stage) => stage.operations ?? [])) &&
|
|
84
|
-
unique(stages.flatMap((stage) => stage.gateKinds ?? []))
|
|
101
|
+
unique(stages.flatMap((stage) => stage.gateKinds ?? [])) &&
|
|
102
|
+
unique(stages.flatMap((stage) => stage.gateIds ?? [])));
|
|
85
103
|
}
|
|
86
104
|
function isCapabilities(value) {
|
|
87
105
|
return (Array.isArray(value) &&
|
|
88
106
|
value.length > 0 &&
|
|
89
107
|
value.every((capability) => capability === "claude" ||
|
|
90
108
|
capability === "github" ||
|
|
91
|
-
capability === "
|
|
109
|
+
capability === "command"));
|
|
92
110
|
}
|
|
93
|
-
export function
|
|
111
|
+
export function isWorkflowNames(value) {
|
|
94
112
|
return selectors(value, /^[A-Za-z0-9-]{1,64}$/) && unique(value);
|
|
95
113
|
}
|
|
114
|
+
function declaredCommands(declaration, capabilities) {
|
|
115
|
+
const commands = declaration["commands"];
|
|
116
|
+
if (Object.hasOwn(declaration, "commands") && !isWorkflowNames(commands))
|
|
117
|
+
return false;
|
|
118
|
+
return ((!capabilities.includes("command") ||
|
|
119
|
+
(Array.isArray(commands) && commands.length > 0)) &&
|
|
120
|
+
declaredCommandWaits(declaration, capabilities));
|
|
121
|
+
}
|
|
122
|
+
function isCommandWait(value) {
|
|
123
|
+
const wait = record(value);
|
|
124
|
+
if (!keys(wait, ["command", "maximumWaitSeconds", "pollEverySeconds"]))
|
|
125
|
+
return false;
|
|
126
|
+
return (typeof wait["command"] === "string" &&
|
|
127
|
+
integer(wait["maximumWaitSeconds"], { minimum: 60, maximum: 2_592_000 }) &&
|
|
128
|
+
integer(wait["pollEverySeconds"], { minimum: 60, maximum: 86_400 }) &&
|
|
129
|
+
Number(wait["pollEverySeconds"]) <= Number(wait["maximumWaitSeconds"]));
|
|
130
|
+
}
|
|
131
|
+
export function isCommandWaits(value, permissions) {
|
|
132
|
+
const waits = record(value);
|
|
133
|
+
if (waits === undefined)
|
|
134
|
+
return false;
|
|
135
|
+
return Object.entries(waits).every(([name, wait]) => matches(name, /^[A-Za-z0-9-]{1,64}$/) &&
|
|
136
|
+
name.trim() === name &&
|
|
137
|
+
isCommandWait(wait) &&
|
|
138
|
+
permissions.capabilities.includes("command") &&
|
|
139
|
+
permissions.commands.includes(wait.command));
|
|
140
|
+
}
|
|
141
|
+
function declaredCommandWaits(declaration, capabilities) {
|
|
142
|
+
if (!Object.hasOwn(declaration, "commandWaits"))
|
|
143
|
+
return true;
|
|
144
|
+
const commands = declaration["commands"];
|
|
145
|
+
return isCommandWaits(declaration["commandWaits"], {
|
|
146
|
+
capabilities,
|
|
147
|
+
commands: isWorkflowNames(commands) ? commands : [],
|
|
148
|
+
});
|
|
149
|
+
}
|
|
96
150
|
export function isWorkflowDeclaration(value) {
|
|
97
151
|
const declaration = record(value);
|
|
98
152
|
if (!keys(declaration, [
|
|
@@ -102,14 +156,28 @@ export function isWorkflowDeclaration(value) {
|
|
|
102
156
|
"input",
|
|
103
157
|
"stages",
|
|
104
158
|
"handoffs",
|
|
159
|
+
"commands",
|
|
160
|
+
"commandWaits",
|
|
161
|
+
"queue",
|
|
162
|
+
"schedule",
|
|
105
163
|
]))
|
|
106
164
|
return false;
|
|
107
|
-
const { workflowId, effectLimit, capabilities, input
|
|
165
|
+
const { workflowId, effectLimit, capabilities, input } = declaration;
|
|
108
166
|
return (matches(workflowId, /^[A-Za-z0-9-]{1,64}$/) &&
|
|
109
167
|
integer(effectLimit, { minimum: 1, maximum: 100 }) &&
|
|
110
168
|
isCapabilities(capabilities) &&
|
|
169
|
+
declaredCommands(declaration, capabilities) &&
|
|
111
170
|
isInput(input) &&
|
|
171
|
+
declaredOptions(declaration, input));
|
|
172
|
+
}
|
|
173
|
+
function declaredOptions(declaration, input) {
|
|
174
|
+
return ((!Object.hasOwn(declaration, "queue") ||
|
|
175
|
+
typeof declaration["queue"] === "boolean") &&
|
|
176
|
+
workflowQueueRefusals(declaration).length === 0 &&
|
|
112
177
|
(!Object.hasOwn(declaration, "stages") ||
|
|
113
178
|
isWorkflowStages(declaration["stages"])) &&
|
|
114
|
-
(!Object.hasOwn(declaration, "handoffs") ||
|
|
179
|
+
(!Object.hasOwn(declaration, "handoffs") ||
|
|
180
|
+
isWorkflowNames(declaration["handoffs"])) &&
|
|
181
|
+
(!Object.hasOwn(declaration, "schedule") ||
|
|
182
|
+
checkWorkflowSchedule(input, declaration["schedule"]).kind === "valid"));
|
|
115
183
|
}
|
|
@@ -4,11 +4,12 @@ export interface WorkflowReservation {
|
|
|
4
4
|
readonly functionName?: string;
|
|
5
5
|
}
|
|
6
6
|
export interface WorkflowDiscoveryIdentity {
|
|
7
|
+
readonly queue?: boolean;
|
|
7
8
|
readonly baseName: string;
|
|
8
9
|
readonly workflowId: string | undefined;
|
|
9
10
|
readonly functionNames: readonly string[];
|
|
10
11
|
}
|
|
11
|
-
export type WorkflowConflictCode = "workflow-conflict" | "bundled-name-reserved";
|
|
12
|
+
export type WorkflowConflictCode = "workflow-conflict" | "bundled-name-reserved" | "queue-workflow-conflict";
|
|
12
13
|
export declare function workflowConflicts(candidates: readonly WorkflowDiscoveryIdentity[], bundled: readonly WorkflowReservation[]): readonly (readonly WorkflowConflictCode[])[];
|
|
13
14
|
export declare const bundledWorkflowIds: {
|
|
14
15
|
readonly ticket: "develop-ticket";
|
|
@@ -16,8 +16,11 @@ export function workflowConflicts(candidates, bundled) {
|
|
|
16
16
|
...entry,
|
|
17
17
|
functionNames: entry.functionName === undefined ? [] : [entry.functionName],
|
|
18
18
|
})));
|
|
19
|
-
|
|
19
|
+
const queued = candidates.filter((candidate) => candidate.queue === true);
|
|
20
|
+
return keys.map((names, index) => {
|
|
20
21
|
const codes = [];
|
|
22
|
+
if (queued.length > 1 && candidates[index]?.queue === true)
|
|
23
|
+
codes.push("queue-workflow-conflict");
|
|
21
24
|
if (names.some((name) => reserved.has(name)))
|
|
22
25
|
codes.push("bundled-name-reserved");
|
|
23
26
|
if (names.some((name) => (counts.get(name) ?? 0) > 1))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Fields } from "./protocol.ts";
|
|
2
|
+
import { type SubmissionContract } from "./submission.ts";
|
|
3
|
+
export interface WorkflowSchedule {
|
|
4
|
+
readonly everySeconds: number;
|
|
5
|
+
readonly input: Fields;
|
|
6
|
+
}
|
|
7
|
+
export type ScheduleCheck = {
|
|
8
|
+
readonly kind: "valid";
|
|
9
|
+
readonly schedule: WorkflowSchedule;
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "rejected";
|
|
12
|
+
readonly code: string;
|
|
13
|
+
};
|
|
14
|
+
interface ScheduleSource {
|
|
15
|
+
readonly workflowId: string;
|
|
16
|
+
readonly input: SubmissionContract;
|
|
17
|
+
readonly schedule?: WorkflowSchedule;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseSchedulesSetting(value: string | undefined): unknown;
|
|
20
|
+
export declare function configuredSchedules(declarations: readonly ScheduleSource[], overrides: unknown): Readonly<Record<string, WorkflowSchedule>>;
|
|
21
|
+
export declare function checkWorkflowSchedule(contract: SubmissionContract, value: unknown): ScheduleCheck;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { record } from "./protocol.js";
|
|
2
|
+
import { checkSubmission } from "./submission.js";
|
|
3
|
+
export function parseSchedulesSetting(value) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(value ?? "{}");
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
throw new Error("invalid-schedules");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function configuredSchedules(declarations, overrides) {
|
|
12
|
+
const settings = record(overrides);
|
|
13
|
+
if (settings === undefined)
|
|
14
|
+
throw new Error("invalid-schedules");
|
|
15
|
+
if (Object.keys(settings).some((id) => !declarations.some((entry) => entry.workflowId === id)))
|
|
16
|
+
throw new Error("unknown-schedule-workflow");
|
|
17
|
+
const schedules = [];
|
|
18
|
+
for (const declaration of declarations) {
|
|
19
|
+
const { workflowId } = declaration;
|
|
20
|
+
const selected = Object.hasOwn(settings, workflowId)
|
|
21
|
+
? settings[workflowId]
|
|
22
|
+
: declaration.schedule;
|
|
23
|
+
if (selected === undefined && !Object.hasOwn(settings, workflowId))
|
|
24
|
+
continue;
|
|
25
|
+
const checked = checkWorkflowSchedule(declaration.input, selected);
|
|
26
|
+
if (checked.kind === "rejected")
|
|
27
|
+
throw new Error(checked.code);
|
|
28
|
+
schedules.push([workflowId, checked.schedule]);
|
|
29
|
+
}
|
|
30
|
+
return Object.fromEntries(schedules);
|
|
31
|
+
}
|
|
32
|
+
export function checkWorkflowSchedule(contract, value) {
|
|
33
|
+
const fields = record(value);
|
|
34
|
+
const seconds = fields?.["everySeconds"];
|
|
35
|
+
if (fields === undefined ||
|
|
36
|
+
Object.keys(fields).some((key) => !["everySeconds", "input"].includes(key)) ||
|
|
37
|
+
typeof seconds !== "number" ||
|
|
38
|
+
!Number.isInteger(seconds) ||
|
|
39
|
+
seconds < 60 ||
|
|
40
|
+
seconds > 86400)
|
|
41
|
+
return { kind: "rejected", code: "invalid-schedule-interval" };
|
|
42
|
+
const checked = checkSubmission(contract, {
|
|
43
|
+
workflowId: "schedule",
|
|
44
|
+
source: "declared",
|
|
45
|
+
submission: fields["input"],
|
|
46
|
+
});
|
|
47
|
+
if (checked.kind === "rejected")
|
|
48
|
+
return { kind: "rejected", code: "invalid-schedule-input" };
|
|
49
|
+
return {
|
|
50
|
+
kind: "valid",
|
|
51
|
+
schedule: { everySeconds: seconds, input: checked.submission },
|
|
52
|
+
};
|
|
53
|
+
}
|