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
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { turnCommand } from "./turn-command.js";
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import { createWriteStream, mkdtempSync, rmSync } from "node:fs";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { codexStream } from "./codex-stream.js";
|
|
5
|
-
import {
|
|
6
|
+
import { cursorStream } from "./cursor-stream.js";
|
|
7
|
+
import { opencodeStream } from "./opencode-stream.js";
|
|
8
|
+
import { textOutput } from "./text-output.js";
|
|
9
|
+
import { grokResultFields, grokUsageWarnings } from "../grok-result.js";
|
|
10
|
+
import { geminiStream } from "./gemini-stream.js";
|
|
11
|
+
import { priceOf, modelUsageOf, usageOf, } from "../worker-usage.js";
|
|
6
12
|
import { commandModel } from "../token-prices.js";
|
|
7
|
-
import {
|
|
13
|
+
import { shellTurnScript } from "../agent-harness-shell.js";
|
|
8
14
|
function parsed(line) {
|
|
9
15
|
try {
|
|
10
16
|
const value = JSON.parse(line);
|
|
@@ -20,21 +26,39 @@ function numberOf(value) {
|
|
|
20
26
|
function textOf(value) {
|
|
21
27
|
return typeof value === "string" ? value : null;
|
|
22
28
|
}
|
|
29
|
+
function networkFailure(result) {
|
|
30
|
+
return (result?.failed === true &&
|
|
31
|
+
result.text.startsWith("API Error: Can't reach the API server"));
|
|
32
|
+
}
|
|
23
33
|
export function capacityRefusal(result) {
|
|
34
|
+
if (networkFailure(result))
|
|
35
|
+
return false;
|
|
24
36
|
return (result?.failed === true &&
|
|
25
37
|
["success", "error_during_execution"].includes(result.subtype ?? "error_during_execution") &&
|
|
26
38
|
(result.text ===
|
|
27
39
|
"Selected model is at capacity. Please try a different model." ||
|
|
28
40
|
result.errorType === "overloaded"));
|
|
29
41
|
}
|
|
30
|
-
export function
|
|
42
|
+
export function retryKind(result) {
|
|
43
|
+
if (networkFailure(result))
|
|
44
|
+
return "network";
|
|
45
|
+
return capacityRefusal(result) ? "capacity" : null;
|
|
46
|
+
}
|
|
47
|
+
export function succeeded(end) {
|
|
48
|
+
return (end.reason === undefined &&
|
|
49
|
+
end.exitCode === 0 &&
|
|
50
|
+
end.result?.failed === false);
|
|
51
|
+
}
|
|
52
|
+
export function streamResult(line, worker) {
|
|
31
53
|
if (!line.includes('"result"'))
|
|
32
54
|
return undefined;
|
|
33
55
|
const record = parsed(line);
|
|
34
56
|
const field = (name) => Reflect.get(Object(record), name);
|
|
35
57
|
if (field("type") !== "result")
|
|
36
58
|
return undefined;
|
|
59
|
+
const models = modelUsageOf(field("models"));
|
|
37
60
|
return {
|
|
61
|
+
...(models === undefined ? {} : { models }),
|
|
38
62
|
...(typeof field("subtype") === "string"
|
|
39
63
|
? { subtype: String(field("subtype")) }
|
|
40
64
|
: {}),
|
|
@@ -48,6 +72,7 @@ export function streamResult(line) {
|
|
|
48
72
|
model: textOf(field("model")),
|
|
49
73
|
sessionId: textOf(field("session_id")),
|
|
50
74
|
turns: numberOf(field("num_turns")),
|
|
75
|
+
...(worker === "grok" ? grokResultFields(record) : {}),
|
|
51
76
|
};
|
|
52
77
|
}
|
|
53
78
|
function ended(stream) {
|
|
@@ -55,12 +80,7 @@ function ended(stream) {
|
|
|
55
80
|
stream.end(settle);
|
|
56
81
|
});
|
|
57
82
|
}
|
|
58
|
-
function turnEnvironment(configuration, start) {
|
|
59
|
-
if (start.mode === "analysis")
|
|
60
|
-
return {
|
|
61
|
-
...analysisEnvironment(start.folder),
|
|
62
|
-
CLAUDE_CODE_OAUTH_TOKEN: start.analysisToken,
|
|
63
|
-
};
|
|
83
|
+
export function turnEnvironment(configuration, start) {
|
|
64
84
|
const excluded = new Set([
|
|
65
85
|
"GH_TOKEN",
|
|
66
86
|
"GITHUB_TOKEN",
|
|
@@ -75,25 +95,42 @@ function turnEnvironment(configuration, start) {
|
|
|
75
95
|
if (start.turnId !== undefined)
|
|
76
96
|
environment["CLOVING_TURN_ID"] = start.turnId;
|
|
77
97
|
environment["GH_CONFIG_DIR"] = configuration;
|
|
98
|
+
if (start.worker === "opencode")
|
|
99
|
+
environment["OPENCODE_PERMISSION"] = '{"*":"allow"}';
|
|
78
100
|
return environment;
|
|
79
101
|
}
|
|
80
102
|
function spawnTurn(start) {
|
|
81
103
|
const configuration = mkdtempSync(join(start.folder, "gh-config-"));
|
|
82
|
-
const
|
|
104
|
+
const { parts, standardInput } = turnCommand(start);
|
|
105
|
+
const command = start.shell === undefined
|
|
106
|
+
? parts
|
|
107
|
+
: [
|
|
108
|
+
start.shell,
|
|
109
|
+
"-l",
|
|
110
|
+
"-i",
|
|
111
|
+
"-c",
|
|
112
|
+
shellTurnScript,
|
|
113
|
+
"cloving-harness",
|
|
114
|
+
configuration,
|
|
115
|
+
...parts,
|
|
116
|
+
];
|
|
117
|
+
const [executable = "", ...fixed] = command;
|
|
83
118
|
try {
|
|
84
119
|
const child = spawn(executable, fixed, {
|
|
85
120
|
cwd: start.directory,
|
|
86
121
|
env: turnEnvironment(configuration, start),
|
|
87
122
|
stdio: ["pipe", "pipe", "pipe"],
|
|
123
|
+
detached: start.shell !== undefined,
|
|
88
124
|
});
|
|
89
|
-
return { child, configuration };
|
|
125
|
+
return { child, configuration, standardInput };
|
|
90
126
|
}
|
|
91
127
|
catch (error) {
|
|
92
128
|
rmSync(configuration, { recursive: true, force: true });
|
|
93
129
|
throw error;
|
|
94
130
|
}
|
|
95
131
|
}
|
|
96
|
-
function receivedLines(stream,
|
|
132
|
+
function receivedLines(stream, input) {
|
|
133
|
+
const { lines, worker } = input;
|
|
97
134
|
for (const line of lines) {
|
|
98
135
|
const event = parsed(line);
|
|
99
136
|
const field = (name) => Reflect.get(Object(event), name);
|
|
@@ -102,7 +139,7 @@ function receivedLines(stream, lines) {
|
|
|
102
139
|
stream.errorType = textOf(field("error"));
|
|
103
140
|
if (type === "system" || type === "result")
|
|
104
141
|
stream.model = textOf(field("model")) ?? stream.model;
|
|
105
|
-
const result = streamResult(line);
|
|
142
|
+
const result = streamResult(line, worker);
|
|
106
143
|
if (result !== undefined) {
|
|
107
144
|
const errorType = result.errorType ?? stream.errorType;
|
|
108
145
|
stream.result = {
|
|
@@ -113,16 +150,31 @@ function receivedLines(stream, lines) {
|
|
|
113
150
|
}
|
|
114
151
|
}
|
|
115
152
|
function activityOutput(start) {
|
|
116
|
-
if (start.mode === "analysis")
|
|
117
|
-
return undefined;
|
|
118
153
|
const output = createWriteStream(join(start.activityFolder ?? start.folder, "turn.jsonl"), { flags: start.activityFolder === undefined ? "w" : "a" });
|
|
119
154
|
if (start.activityFolder !== undefined)
|
|
120
155
|
output.write("\n");
|
|
121
156
|
return output;
|
|
122
157
|
}
|
|
123
|
-
function
|
|
158
|
+
function streamAdapter(worker) {
|
|
159
|
+
if (worker === "codex")
|
|
160
|
+
return codexStream();
|
|
161
|
+
if (worker === "cursor-agent")
|
|
162
|
+
return cursorStream();
|
|
163
|
+
if (worker === "gemini")
|
|
164
|
+
return geminiStream();
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
function turnOutput(start, child) {
|
|
124
168
|
const output = activityOutput(start);
|
|
125
|
-
|
|
169
|
+
if (start.output === "text")
|
|
170
|
+
return textOutput(child, { output, limit: start.resultBytes ?? 48_000 });
|
|
171
|
+
const translated = start.worker === "opencode" ? opencodeStream() : undefined;
|
|
172
|
+
const adapter = translated ?? streamAdapter(start.worker);
|
|
173
|
+
const { stdout, stderr } = child;
|
|
174
|
+
if (translated !== undefined) {
|
|
175
|
+
stderr.setEncoding("utf8");
|
|
176
|
+
stderr.on("data", translated.stderr);
|
|
177
|
+
}
|
|
126
178
|
const stream = {
|
|
127
179
|
pending: "",
|
|
128
180
|
result: undefined,
|
|
@@ -130,66 +182,72 @@ function turnOutput(start, stdout) {
|
|
|
130
182
|
errorType: null,
|
|
131
183
|
};
|
|
132
184
|
const received = (lines) => {
|
|
133
|
-
receivedLines(stream,
|
|
185
|
+
receivedLines(stream, {
|
|
186
|
+
lines,
|
|
187
|
+
...(start.worker === undefined ? {} : { worker: start.worker }),
|
|
188
|
+
});
|
|
134
189
|
};
|
|
135
190
|
const written = (lines) => {
|
|
136
191
|
for (const line of lines)
|
|
137
|
-
output
|
|
192
|
+
output.write(`${line}\n`);
|
|
138
193
|
received(lines);
|
|
139
194
|
};
|
|
140
195
|
stdout.setEncoding("utf8");
|
|
141
196
|
stdout.on("data", (chunk) => {
|
|
142
|
-
if (
|
|
143
|
-
output
|
|
197
|
+
if (adapter === undefined)
|
|
198
|
+
output.write(chunk);
|
|
144
199
|
const lines = `${stream.pending}${chunk}`.split("\n");
|
|
145
200
|
stream.pending = lines.pop() ?? "";
|
|
146
|
-
if (
|
|
147
|
-
written(lines.flatMap(
|
|
201
|
+
if (adapter !== undefined) {
|
|
202
|
+
written(lines.flatMap(adapter.line));
|
|
148
203
|
return;
|
|
149
204
|
}
|
|
150
205
|
received(lines);
|
|
151
206
|
});
|
|
152
207
|
return async (exitCode) => {
|
|
153
|
-
if (
|
|
154
|
-
written(
|
|
155
|
-
written([
|
|
208
|
+
if (adapter !== undefined) {
|
|
209
|
+
written(adapter.line(stream.pending));
|
|
210
|
+
written([adapter.result(exitCode)]);
|
|
156
211
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (codex === undefined)
|
|
212
|
+
await ended(output);
|
|
213
|
+
if (adapter === undefined)
|
|
160
214
|
received([stream.pending]);
|
|
161
215
|
const result = stream.result;
|
|
162
216
|
return result === undefined
|
|
163
217
|
? undefined
|
|
164
218
|
: {
|
|
165
219
|
...result,
|
|
166
|
-
model: result.model ??
|
|
167
|
-
stream.model ??
|
|
168
|
-
commandModel(start.mode === "analysis" ? analysisCommand() : start.command),
|
|
220
|
+
model: result.model ?? stream.model ?? commandModel(start.command),
|
|
169
221
|
};
|
|
170
222
|
};
|
|
171
223
|
}
|
|
172
|
-
function
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
224
|
+
function signalTurn(turn, signal) {
|
|
225
|
+
const { child, start } = turn;
|
|
226
|
+
if (start.shell === undefined || child.pid === undefined) {
|
|
227
|
+
child.kill(signal);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
process.kill(-child.pid, signal);
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
const code = Reflect.get(Object(error), "code");
|
|
235
|
+
if (code !== "ESRCH" && code !== "EPERM")
|
|
236
|
+
throw error;
|
|
237
|
+
child.kill(signal);
|
|
238
|
+
}
|
|
183
239
|
}
|
|
184
240
|
export function startTurn(start) {
|
|
185
|
-
const { child, configuration } = spawnTurn(start);
|
|
186
|
-
const output = turnOutput(start, child
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
child.stderr.
|
|
241
|
+
const { child, configuration, standardInput } = spawnTurn(start);
|
|
242
|
+
const output = turnOutput(start, child);
|
|
243
|
+
const warnings = grokUsageWarnings();
|
|
244
|
+
if (start.worker === "grok") {
|
|
245
|
+
child.stderr.setEncoding("utf8");
|
|
246
|
+
child.stderr.on("data", warnings.write);
|
|
247
|
+
}
|
|
248
|
+
child.stderr.pipe(createWriteStream(join(start.folder, "turn.stderr.log")));
|
|
191
249
|
child.stdin.on("error", () => undefined);
|
|
192
|
-
child.stdin.end(
|
|
250
|
+
child.stdin.end(standardInput);
|
|
193
251
|
const closed = new Promise((settle) => {
|
|
194
252
|
child.once("error", () => undefined);
|
|
195
253
|
child.once("close", settle);
|
|
@@ -200,17 +258,22 @@ export function startTurn(start) {
|
|
|
200
258
|
ended: closed
|
|
201
259
|
.then(async (exitCode) => {
|
|
202
260
|
timers.forEach(clearTimeout);
|
|
261
|
+
const result = await output(exitCode);
|
|
203
262
|
return {
|
|
204
263
|
exitCode,
|
|
205
|
-
result:
|
|
264
|
+
result: result !== undefined && warnings.incomplete()
|
|
265
|
+
? { ...result, usage: usageOf(null), costUsd: null }
|
|
266
|
+
: result,
|
|
206
267
|
};
|
|
207
268
|
})
|
|
208
269
|
.finally(() => {
|
|
209
270
|
rmSync(configuration, { recursive: true, force: true });
|
|
210
271
|
}),
|
|
211
272
|
stop: (graceMilliseconds) => {
|
|
212
|
-
child
|
|
213
|
-
timers.push(setTimeout(() =>
|
|
273
|
+
signalTurn({ child, start }, "SIGTERM");
|
|
274
|
+
timers.push(setTimeout(() => {
|
|
275
|
+
signalTurn({ child, start }, "SIGKILL");
|
|
276
|
+
}, graceMilliseconds).unref());
|
|
214
277
|
},
|
|
215
278
|
};
|
|
216
279
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { type HarnessSettings } from "../harness-defaults.ts";
|
|
1
2
|
import { type TurnProfiles } from "../turn-profile.ts";
|
|
2
3
|
import type { Delivery } from "../broker/actor/delivery-intents.ts";
|
|
3
|
-
import { type Worker } from "./claude-turn.ts";
|
|
4
4
|
import { type RetrySettings } from "./retrying-turn.ts";
|
|
5
5
|
import { type WorkerReport } from "./operation-journal.ts";
|
|
6
|
-
export interface ClaudeWorkerSettings extends RetrySettings {
|
|
7
|
-
readonly worker?: Worker;
|
|
6
|
+
export interface ClaudeWorkerSettings extends RetrySettings, HarnessSettings {
|
|
8
7
|
readonly profiles?: TurnProfiles;
|
|
9
8
|
readonly workflowId?: (runId: string) => Promise<string | undefined>;
|
|
10
9
|
readonly repository: string;
|
|
@@ -16,6 +15,7 @@ export interface ClaudeWorkerSettings extends RetrySettings {
|
|
|
16
15
|
readonly stopMilliseconds?: number;
|
|
17
16
|
}
|
|
18
17
|
export interface ClaudeWorker extends Delivery {
|
|
18
|
+
readonly harness: (operationId: string) => Promise<string | undefined>;
|
|
19
19
|
readonly stop: NonNullable<Delivery["stop"]>;
|
|
20
20
|
readonly close: () => Promise<void>;
|
|
21
21
|
}
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
import { sumPrices } from "../worker-usage.js";
|
|
4
|
-
import { analysisWorker } from "./analysis-worker.js";
|
|
5
|
-
import { analysisMethod } from "./analysis-launch.js";
|
|
2
|
+
import { turnHarness } from "../harness-defaults.js";
|
|
6
3
|
import { profileCommand, } from "../turn-profile.js";
|
|
7
|
-
import {} from "./claude-turn.js";
|
|
4
|
+
import { succeeded } from "./claude-turn.js";
|
|
5
|
+
import { turnReport } from "./turn-report.js";
|
|
8
6
|
import { startRetriedTurn } from "./retrying-turn.js";
|
|
9
7
|
import { interrupted, located, operationKey, readRecord as read, replied, reportOf, writeRecord as written, } from "./operation-journal.js";
|
|
10
|
-
import {
|
|
8
|
+
import { treeFailure, workTree } from "./work-tree.js";
|
|
11
9
|
export const claudeLimits = {
|
|
12
10
|
summaryCharacters: 16_000,
|
|
13
11
|
resultBytes: 48_000,
|
|
14
12
|
stopMilliseconds: 2_000,
|
|
15
13
|
};
|
|
16
14
|
const worker = "claude";
|
|
15
|
+
async function recordedHarness(journal, operationId) {
|
|
16
|
+
const { folder } = located(journal, operationId);
|
|
17
|
+
const started = await read(folder, "started.json").catch(() => undefined);
|
|
18
|
+
const harness = Reflect.get(Object(started), "harness");
|
|
19
|
+
return typeof harness === "string" ? harness : undefined;
|
|
20
|
+
}
|
|
17
21
|
function alive(processId) {
|
|
18
22
|
if (typeof processId !== "number")
|
|
19
23
|
return false;
|
|
@@ -41,58 +45,25 @@ async function reconciled(parts, intent) {
|
|
|
41
45
|
await written(folder, { name: "result.json", value: ending });
|
|
42
46
|
return replied({ receipt: key, worker }, ending);
|
|
43
47
|
}
|
|
44
|
-
async function resultText(tree, result) {
|
|
45
|
-
const fields = {
|
|
46
|
-
ticketStatus: ticketStatus(result.text),
|
|
47
|
-
summary: result.text.slice(0, claudeLimits.summaryCharacters),
|
|
48
|
-
...(await changes(tree)),
|
|
49
|
-
worktree: tree.path,
|
|
50
|
-
costUsd: result.costUsd,
|
|
51
|
-
usage: result.usage,
|
|
52
|
-
model: result.model,
|
|
53
|
-
...(result.attempts === undefined ? {} : { attempts: result.attempts }),
|
|
54
|
-
estimatedCostUsd: sumPrices((result.attempts ?? []).map((attempt) => attempt.estimatedCostUsd)),
|
|
55
|
-
sessionId: result.sessionId,
|
|
56
|
-
turns: result.turns,
|
|
57
|
-
};
|
|
58
|
-
const text = JSON.stringify(fields);
|
|
59
|
-
const excess = Buffer.byteLength(text) - claudeLimits.resultBytes;
|
|
60
|
-
if (excess <= 0)
|
|
61
|
-
return { text };
|
|
62
|
-
const kept = Math.max(0, fields.summary.length - excess);
|
|
63
|
-
const shortened = JSON.stringify({
|
|
64
|
-
...fields,
|
|
65
|
-
summary: fields.summary.slice(0, kept),
|
|
66
|
-
});
|
|
67
|
-
if (Buffer.byteLength(shortened) <= claudeLimits.resultBytes)
|
|
68
|
-
return { text: shortened };
|
|
69
|
-
const metadata = JSON.stringify({
|
|
70
|
-
...fields,
|
|
71
|
-
ticketStatus: undefined,
|
|
72
|
-
summary: "",
|
|
73
|
-
});
|
|
74
|
-
return {
|
|
75
|
-
reason: "claude-result-too-large",
|
|
76
|
-
...(Buffer.byteLength(metadata) <= claudeLimits.resultBytes
|
|
77
|
-
? { text: metadata }
|
|
78
|
-
: {}),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
48
|
async function outcome(running, end) {
|
|
82
49
|
const endedAt = new Date().toISOString();
|
|
83
50
|
const { result } = end;
|
|
84
|
-
const report = result === undefined
|
|
51
|
+
const report = result === undefined
|
|
52
|
+
? {}
|
|
53
|
+
: await turnReport({
|
|
54
|
+
tree: running.tree,
|
|
55
|
+
harness: running.harness,
|
|
56
|
+
limits: claudeLimits,
|
|
57
|
+
}, result);
|
|
85
58
|
const { text, reason } = report;
|
|
86
|
-
if (reason === undefined &&
|
|
87
|
-
text !== undefined &&
|
|
88
|
-
end.exitCode === 0 &&
|
|
89
|
-
result?.failed === false)
|
|
59
|
+
if (succeeded(end) && reason === undefined && text !== undefined)
|
|
90
60
|
return { outcome: "completed", result: text, endedAt };
|
|
91
61
|
if (running.stopping.requested)
|
|
92
62
|
return { outcome: "stopped", endedAt };
|
|
93
63
|
return {
|
|
94
64
|
outcome: "failed",
|
|
95
|
-
reason: reason ?? "claude-turn-failed",
|
|
65
|
+
reason: end.reason ?? reason ?? "claude-turn-failed",
|
|
66
|
+
...(end.detail === undefined ? {} : { detail: end.detail }),
|
|
96
67
|
...(text === undefined ? {} : { result: text }),
|
|
97
68
|
endedAt,
|
|
98
69
|
};
|
|
@@ -105,9 +76,12 @@ async function concluded(parts, running) {
|
|
|
105
76
|
}
|
|
106
77
|
async function begun(parts, start) {
|
|
107
78
|
const { intent, key, folder, tree, prompt } = start;
|
|
79
|
+
const { harness } = start;
|
|
80
|
+
const stopping = { requested: false, controller: new AbortController() };
|
|
108
81
|
const turn = startRetriedTurn({
|
|
109
|
-
|
|
110
|
-
|
|
82
|
+
...harness,
|
|
83
|
+
resultBytes: claudeLimits.resultBytes,
|
|
84
|
+
command: profileCommand(harness.command, start.profile),
|
|
111
85
|
environment: start.profile.env ?? {},
|
|
112
86
|
turnId: `${intent.runId}-${key}`,
|
|
113
87
|
directory: tree.path,
|
|
@@ -115,7 +89,9 @@ async function begun(parts, start) {
|
|
|
115
89
|
prompt,
|
|
116
90
|
}, {
|
|
117
91
|
...parts.settings,
|
|
92
|
+
stopping: stopping.controller,
|
|
118
93
|
metadata: {
|
|
94
|
+
harness: harness.worker,
|
|
119
95
|
operationId: intent.operationId,
|
|
120
96
|
target: intent.target,
|
|
121
97
|
branch: tree.branch,
|
|
@@ -123,7 +99,6 @@ async function begun(parts, start) {
|
|
|
123
99
|
startCommit: tree.startCommit,
|
|
124
100
|
},
|
|
125
101
|
});
|
|
126
|
-
const stopping = { requested: false };
|
|
127
102
|
parts.active.set(key, {
|
|
128
103
|
turn,
|
|
129
104
|
stopping,
|
|
@@ -169,16 +144,30 @@ async function runWorkflow(settings, runId) {
|
|
|
169
144
|
return undefined;
|
|
170
145
|
}
|
|
171
146
|
}
|
|
147
|
+
function unsupportedProfile(profile, harness) {
|
|
148
|
+
if (harness.output === "text" && profile.model !== undefined)
|
|
149
|
+
return "profile-model-not-supported";
|
|
150
|
+
if (harness.worker === "claude")
|
|
151
|
+
return undefined;
|
|
152
|
+
return [
|
|
153
|
+
profile.allowedTools,
|
|
154
|
+
profile.permissionMode,
|
|
155
|
+
profile.maxBudgetUsd,
|
|
156
|
+
].some((value) => value !== undefined)
|
|
157
|
+
? "profile-needs-claude"
|
|
158
|
+
: undefined;
|
|
159
|
+
}
|
|
172
160
|
async function selectedProfile(settings, intent) {
|
|
173
161
|
if (intent.method === "run-turn")
|
|
174
162
|
return {};
|
|
175
|
-
if (settings.worker === "codex")
|
|
176
|
-
return "profile-needs-claude";
|
|
177
163
|
const name = intent.method.slice("run-turn:".length);
|
|
178
164
|
const profiles = settings.profiles ?? {};
|
|
179
165
|
const profile = Object.hasOwn(profiles, name) ? profiles[name] : undefined;
|
|
180
166
|
if (profile === undefined)
|
|
181
167
|
return "unknown-profile";
|
|
168
|
+
const unsupported = unsupportedProfile(profile, turnHarness(settings, profile));
|
|
169
|
+
if (unsupported !== undefined)
|
|
170
|
+
return unsupported;
|
|
182
171
|
if (profile.workflows === undefined)
|
|
183
172
|
return profile;
|
|
184
173
|
const workflowId = await runWorkflow(settings, intent.runId);
|
|
@@ -217,11 +206,19 @@ async function delivered(parts, call) {
|
|
|
217
206
|
const first = await firstTurn(settings, { tree, intent });
|
|
218
207
|
if (aborted())
|
|
219
208
|
return failure("claude-start-aborted");
|
|
220
|
-
await begun(parts, {
|
|
209
|
+
await begun(parts, {
|
|
210
|
+
...place,
|
|
211
|
+
intent,
|
|
212
|
+
tree: first,
|
|
213
|
+
prompt,
|
|
214
|
+
profile,
|
|
215
|
+
harness: turnHarness(settings, profile),
|
|
216
|
+
});
|
|
221
217
|
return { receipt: place.key, worker };
|
|
222
218
|
}
|
|
223
219
|
async function halted(parts, active) {
|
|
224
220
|
active.stopping.requested = true;
|
|
221
|
+
active.stopping.controller.abort();
|
|
225
222
|
const turn = await active.turn.catch(() => undefined);
|
|
226
223
|
turn?.stop(parts.settings.stopMilliseconds ?? claudeLimits.stopMilliseconds);
|
|
227
224
|
await active.concluded;
|
|
@@ -236,35 +233,27 @@ async function stopped(parts, intent) {
|
|
|
236
233
|
export function claudeWorker(settings) {
|
|
237
234
|
if (settings.command.length === 0)
|
|
238
235
|
throw new Error("invalid-claude-command");
|
|
236
|
+
turnHarness(settings);
|
|
237
|
+
for (const profile of Object.values(settings.profiles ?? {}))
|
|
238
|
+
turnHarness(settings, profile);
|
|
239
239
|
const parts = {
|
|
240
240
|
settings,
|
|
241
241
|
active: new Map(),
|
|
242
242
|
stopping: new AbortController(),
|
|
243
243
|
};
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
Object.hasOwn(settings.profiles ?? {}, "analyze-chats") ||
|
|
248
|
-
(await runWorkflow(settings, intent.runId)) !== "analyze-chats")
|
|
249
|
-
return failure("analysis-worker-unavailable");
|
|
250
|
-
return run();
|
|
251
|
-
};
|
|
244
|
+
const guarded = (intent, run) => intent.method === "run-turn:analyze-chats"
|
|
245
|
+
? Promise.resolve(failure("unsupported-effect"))
|
|
246
|
+
: run();
|
|
252
247
|
return {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
? guarded(intent, () => analysis.reconcile(intent, signal))
|
|
261
|
-
: reconciled(parts, intent),
|
|
262
|
-
stop: (intent, signal) => intent.method === analysisMethod
|
|
263
|
-
? guarded(intent, () => analysis.stop(intent, signal))
|
|
264
|
-
: stopped(parts, intent),
|
|
248
|
+
harness: (operationId) => recordedHarness(settings.journal, operationId),
|
|
249
|
+
deliver: (intent, signal) => guarded(intent, () => delivered(parts, {
|
|
250
|
+
intent,
|
|
251
|
+
signal: AbortSignal.any([signal, parts.stopping.signal]),
|
|
252
|
+
})),
|
|
253
|
+
reconcile: (intent) => guarded(intent, () => reconciled(parts, intent)),
|
|
254
|
+
stop: (intent) => guarded(intent, () => stopped(parts, intent)),
|
|
265
255
|
close: async () => {
|
|
266
256
|
parts.stopping.abort();
|
|
267
|
-
await analysis.close();
|
|
268
257
|
await Promise.all([...parts.active.values()].map((active) => halted(parts, active)));
|
|
269
258
|
},
|
|
270
259
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CommandEffects } from "../command-settings.ts";
|
|
2
|
+
export declare function claimCommand(folder: string): Promise<boolean>;
|
|
3
|
+
export declare function commandStarted(folder: string): Promise<boolean>;
|
|
4
|
+
export declare function recordCommandResult(folder: string, value: unknown): Promise<boolean>;
|
|
5
|
+
export declare function commandEffects(journal: string): CommandEffects;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { link, mkdir, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { located, readRecord } from "./operation-journal.js";
|
|
5
|
+
import { record } from "../protocol.js";
|
|
6
|
+
function alreadyExists(error) {
|
|
7
|
+
if (Reflect.get(Object(error), "code") === "EEXIST")
|
|
8
|
+
return false;
|
|
9
|
+
throw error;
|
|
10
|
+
}
|
|
11
|
+
export async function claimCommand(folder) {
|
|
12
|
+
await mkdir(dirname(folder), { recursive: true, mode: 0o700 });
|
|
13
|
+
return mkdir(folder, { mode: 0o700 }).then(() => true, alreadyExists);
|
|
14
|
+
}
|
|
15
|
+
export async function commandStarted(folder) {
|
|
16
|
+
return stat(folder).then(() => true, (error) => {
|
|
17
|
+
if (Reflect.get(Object(error), "code") === "ENOENT")
|
|
18
|
+
return false;
|
|
19
|
+
throw error;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export async function recordCommandResult(folder, value) {
|
|
23
|
+
const staged = join(folder, `${randomUUID()}.staged`);
|
|
24
|
+
await writeFile(staged, JSON.stringify(value), { mode: 0o600, flag: "wx" });
|
|
25
|
+
try {
|
|
26
|
+
return await link(staged, join(folder, "result.json")).then(() => true, alreadyExists);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await rm(staged);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function commandEffects(journal) {
|
|
33
|
+
const completed = new Map();
|
|
34
|
+
return (effects) => Promise.all(effects.map(async (effect) => {
|
|
35
|
+
const { key, folder } = located(journal, effect.operationId);
|
|
36
|
+
const cached = completed.get(key);
|
|
37
|
+
if (cached !== undefined)
|
|
38
|
+
return { ...effect, ...cached };
|
|
39
|
+
const result = record(await readRecord(folder, "result.json"));
|
|
40
|
+
const exitCode = result?.["exitCode"];
|
|
41
|
+
const duration = result?.["durationMilliseconds"];
|
|
42
|
+
const metadata = {
|
|
43
|
+
exitCode: typeof exitCode === "number" ? exitCode : null,
|
|
44
|
+
durationMilliseconds: typeof duration === "number" ? duration : null,
|
|
45
|
+
};
|
|
46
|
+
if (result !== undefined)
|
|
47
|
+
completed.set(key, metadata);
|
|
48
|
+
return { ...effect, ...metadata };
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface CommandStart {
|
|
2
|
+
readonly command: readonly string[];
|
|
3
|
+
readonly directory: string;
|
|
4
|
+
readonly folder: string;
|
|
5
|
+
readonly payload: string;
|
|
6
|
+
readonly runId: string;
|
|
7
|
+
readonly operationId: string;
|
|
8
|
+
readonly seconds: number;
|
|
9
|
+
readonly deadline?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CommandEnd {
|
|
12
|
+
readonly stdout: string;
|
|
13
|
+
readonly exitCode: number | null;
|
|
14
|
+
readonly durationMilliseconds: number;
|
|
15
|
+
readonly reason?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RunningCommand {
|
|
18
|
+
readonly ended: Promise<CommandEnd>;
|
|
19
|
+
readonly stop: () => void;
|
|
20
|
+
}
|
|
21
|
+
export interface CommandClock {
|
|
22
|
+
readonly now: () => number;
|
|
23
|
+
readonly timer: (wait: {
|
|
24
|
+
readonly milliseconds: number;
|
|
25
|
+
readonly expired: () => void;
|
|
26
|
+
}) => () => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function startCommand(start: CommandStart, clock?: CommandClock): RunningCommand;
|