cloving 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +525 -185
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +1 -0
- package/dist/src/authority/commands.js +24 -4
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +6 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +7 -1
- package/dist/src/broker/actor/authority-queries.js +17 -2
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +4 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +22 -9
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +2 -1
- package/dist/src/cli/render.js +44 -28
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +70 -44
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +1 -1
- package/dist/src/cli/watch-board-view.js +8 -2
- package/dist/src/cli/watch-board.js +23 -10
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +7 -2
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.js +17 -4
- package/dist/src/cli/watch-page.js +48 -12
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pull-request.d.ts +3 -1
- package/dist/src/cli/watch-pull-request.js +4 -0
- package/dist/src/cli/watch-render.d.ts +9 -1
- package/dist/src/cli/watch-server.js +23 -5
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +37 -1
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +6 -20
- package/dist/src/cli/watch-view.js +14 -106
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +19 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -3
- package/dist/src/daemon/claude-worker.js +65 -76
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +2 -33
- package/dist/src/daemon/daemon.js +126 -132
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +1 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.js +89 -8
- package/dist/src/daemon/github-merge-call.d.ts +2 -0
- package/dist/src/daemon/github-merge.js +7 -3
- package/dist/src/daemon/github-methods.js +10 -0
- package/dist/src/daemon/github-operation.d.ts +1 -0
- package/dist/src/daemon/github-retry.js +8 -44
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +3 -26
- package/dist/src/daemon/notify.js +2 -1
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -0
- package/dist/src/daemon/retrying-turn.js +108 -30
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-registration.d.ts +5 -7
- package/dist/src/daemon/ticket-registration.js +85 -40
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +5 -0
- package/dist/src/execution-pin.js +67 -4
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +1 -1
- package/dist/src/host/start-delivery.js +10 -3
- package/dist/src/host/step-bridge-host.d.ts +6 -20
- package/dist/src/host/step-bridge-host.js +44 -58
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/registry.d.ts +16 -3
- package/dist/src/service/registry.js +34 -3
- package/dist/src/service/replies.d.ts +9 -1
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +14 -55
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +18 -2
- package/dist/src/service/service.js +23 -7
- package/dist/src/service/submission-handler.d.ts +0 -1
- package/dist/src/service/submission-handler.js +6 -34
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +8 -23
- package/dist/src/step-bridge.d.ts +23 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/token-prices.d.ts +12 -4
- package/dist/src/token-prices.js +15 -2
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +16 -0
- package/dist/src/worker-usage.js +57 -0
- package/dist/src/workflow-admission.d.ts +5 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +47 -5
- package/dist/src/workflow-declaration.d.ts +21 -3
- package/dist/src/workflow-declaration.js +77 -9
- package/dist/src/workflow-discovery.d.ts +2 -1
- package/dist/src/workflow-discovery.js +4 -1
- package/dist/src/workflow-refusals.js +3 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +11 -1
- package/dist/src/workflows.js +8 -0
- package/dist/tools/admit-workflow.d.ts +1 -0
- package/dist/tools/admit-workflow.js +18 -5
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +4 -0
- package/dist/tools/self-host-project.js +61 -14
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +86 -61
- package/dist/tools/workflow-candidate-counts.d.ts +6 -2
- package/dist/tools/workflow-candidate-counts.js +31 -16
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +2 -0
- package/dist/tools/workflow-candidate-program.js +36 -8
- package/dist/tools/workflow-candidate-source.js +77 -15
- package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
- package/dist/tools/workflow-candidate-syntax.js +70 -26
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +1 -0
- package/dist/tools/workflow-folder-capture.js +47 -2
- package/dist/tools/workflow-folders.d.ts +17 -1
- package/dist/tools/workflow-folders.js +59 -6
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-ticket.js +1 -1
- package/dist/workflows/ticket-prompts.js +5 -1
- package/package.json +46 -4
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -42
- package/dist/src/chats/analysis-batches.js +0 -97
- package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
- package/dist/src/chats/analysis-checkpoint.js +0 -31
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -18
- package/dist/src/chats/analysis-input.js +0 -97
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-merge.d.ts +0 -16
- package/dist/src/chats/analysis-merge.js +0 -134
- package/dist/src/chats/analysis-prompt.d.ts +0 -18
- package/dist/src/chats/analysis-prompt.js +0 -42
- package/dist/src/chats/analysis-proposal.d.ts +0 -4
- package/dist/src/chats/analysis-proposal.js +0 -41
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -4
- package/dist/src/chats/analysis-shape.js +0 -235
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/reference-mapping.d.ts +0 -16
- package/dist/src/chats/reference-mapping.js +0 -153
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
- package/dist/src/chats/workflow-generation-projection.js +0 -75
- package/dist/src/chats/workflow-generation-source.d.ts +0 -25
- package/dist/src/chats/workflow-generation-source.js +0 -124
- package/dist/src/chats/workflow-generation-text.d.ts +0 -23
- package/dist/src/chats/workflow-generation-text.js +0 -74
- package/dist/src/chats/workflow-generation.d.ts +0 -69
- package/dist/src/chats/workflow-generation.js +0 -142
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -20
- package/dist/src/daemon/analysis-worker.js +0 -271
- package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
- package/dist/src/daemon/chats-batch-binding.js +0 -99
- package/dist/src/daemon/chats-capture.d.ts +0 -18
- package/dist/src/daemon/chats-capture.js +0 -194
- package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
- package/dist/src/daemon/chats-checkpoints.js +0 -186
- package/dist/src/daemon/chats-files.d.ts +0 -42
- package/dist/src/daemon/chats-files.js +0 -252
- package/dist/src/daemon/chats-follow-up.d.ts +0 -38
- package/dist/src/daemon/chats-follow-up.js +0 -180
- package/dist/src/daemon/chats-question.d.ts +0 -15
- package/dist/src/daemon/chats-question.js +0 -93
- package/dist/src/daemon/chats-worker.d.ts +0 -13
- package/dist/src/daemon/chats-worker.js +0 -201
- package/dist/workflows/analyze-chats.d.ts +0 -15
- package/dist/workflows/analyze-chats.declaration.json +0 -22
- package/dist/workflows/analyze-chats.js +0 -250
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { constants, stat } from "node:fs/promises";
|
|
2
|
+
import { basename, resolve } from "node:path";
|
|
3
|
+
import { shellArguments, shellBlock, shellProbeScript, } from "../agent-harness-shell.js";
|
|
4
|
+
import { harnessDefinition, harnessVersion, } from "../agent-harness-versions.js";
|
|
5
|
+
import { harnessDefaults, nativeHarness, turnHarness, } from "../harness-defaults.js";
|
|
6
|
+
import { accessibleFile, commandObservation, executableProgram, listedSetting, } from "./doctor-local.js";
|
|
7
|
+
import { discoverHarnesses } from "./harness-probes.js";
|
|
8
|
+
export async function harnessObservations(environment, location) {
|
|
9
|
+
const discovery = await discoverHarnesses({
|
|
10
|
+
env: environment,
|
|
11
|
+
probe: location.probe,
|
|
12
|
+
});
|
|
13
|
+
const harnesses = {
|
|
14
|
+
result: discovery.entries.some((entry) => entry.working) ? "ok" : "fail",
|
|
15
|
+
detail: JSON.stringify(discovery),
|
|
16
|
+
};
|
|
17
|
+
if (!location.settingsValid)
|
|
18
|
+
return {
|
|
19
|
+
harnesses,
|
|
20
|
+
selected: { result: "skip", detail: "Settings files are invalid" },
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
harnesses,
|
|
24
|
+
selected: await selectedHarnessObservation(environment, location),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function shellScriptIndex(arguments_, shell) {
|
|
28
|
+
const terminators = shell === "zsh" ? ["--", "-b"] : ["--"];
|
|
29
|
+
let optionOperand = false;
|
|
30
|
+
for (const [index, argument] of arguments_.entries()) {
|
|
31
|
+
if (optionOperand) {
|
|
32
|
+
optionOperand = false;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (terminators.includes(argument))
|
|
36
|
+
return index + 1;
|
|
37
|
+
if (/^-[^-oO]*c/.test(argument) ||
|
|
38
|
+
["--command", "--version", "--help"].includes(argument))
|
|
39
|
+
return undefined;
|
|
40
|
+
if (/^[-+][^-]*[oO]$/.test(argument) ||
|
|
41
|
+
["--rcfile", "--init-file", "--emulate"].includes(argument)) {
|
|
42
|
+
optionOperand = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (/^[-+]/.test(argument))
|
|
46
|
+
continue;
|
|
47
|
+
return index;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
async function missingFile(path) {
|
|
52
|
+
try {
|
|
53
|
+
await stat(path);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const envOptionsWithValue = ["-u", "--unset", "-C", "--chdir", "-P"];
|
|
61
|
+
function envProgram(arguments_) {
|
|
62
|
+
let index = 0;
|
|
63
|
+
while (index < arguments_.length) {
|
|
64
|
+
const part = arguments_[index] ?? "";
|
|
65
|
+
if (["-S", "--split-string"].includes(part))
|
|
66
|
+
return { index: index + 1, split: true };
|
|
67
|
+
if (/^(-S|--split-string=)./.test(part))
|
|
68
|
+
return { index, split: true };
|
|
69
|
+
if (!/^(-|[A-Za-z_]\w*=)/.test(part))
|
|
70
|
+
return { index, split: false };
|
|
71
|
+
index += envOptionsWithValue.includes(part) ? 2 : 1;
|
|
72
|
+
}
|
|
73
|
+
return { index, split: false };
|
|
74
|
+
}
|
|
75
|
+
const shells = ["sh", "bash", "dash", "zsh", "ksh"];
|
|
76
|
+
function envVersionArguments(arguments_, worker) {
|
|
77
|
+
const { index, split } = envProgram(arguments_);
|
|
78
|
+
if (index >= arguments_.length)
|
|
79
|
+
return [];
|
|
80
|
+
const prefix = arguments_.slice(0, index + 1);
|
|
81
|
+
if (split)
|
|
82
|
+
return [...prefix, "--version"];
|
|
83
|
+
const wrapped = wrappedVersionArguments(arguments_.slice(index), worker);
|
|
84
|
+
return wrapped.length === 0 ? [] : [...prefix, ...wrapped];
|
|
85
|
+
}
|
|
86
|
+
function wrappedVersionArguments(command, worker) {
|
|
87
|
+
const [program = "", ...arguments_] = command;
|
|
88
|
+
const name = basename(program);
|
|
89
|
+
if (name === "env")
|
|
90
|
+
return envVersionArguments(arguments_, worker);
|
|
91
|
+
if (!shells.includes(name))
|
|
92
|
+
return launcherVersionArguments(name, { arguments: arguments_, worker });
|
|
93
|
+
const script = shellScriptIndex(arguments_, name);
|
|
94
|
+
return script === undefined
|
|
95
|
+
? []
|
|
96
|
+
: [...arguments_.slice(0, script + 1), "--version"];
|
|
97
|
+
}
|
|
98
|
+
function launcherVersionArguments(program, launch) {
|
|
99
|
+
const arguments_ = launch.arguments;
|
|
100
|
+
if (program === "node") {
|
|
101
|
+
const script = arguments_[arguments_[0] === "--" ? 1 : 0];
|
|
102
|
+
return script !== undefined && !script.startsWith("-")
|
|
103
|
+
? ["--", script, "--version"]
|
|
104
|
+
: [];
|
|
105
|
+
}
|
|
106
|
+
return !nativeHarness(launch.worker) ||
|
|
107
|
+
arguments_.length === 0 ||
|
|
108
|
+
[launch.worker, "claude", "codex"].includes(program)
|
|
109
|
+
? ["--version"]
|
|
110
|
+
: [];
|
|
111
|
+
}
|
|
112
|
+
async function harnessVersionArguments(command, location) {
|
|
113
|
+
const [program = "", ...arguments_] = command;
|
|
114
|
+
const shell = basename(program);
|
|
115
|
+
if (shell === "env")
|
|
116
|
+
return envVersionArguments(arguments_, location.worker);
|
|
117
|
+
if (!shells.includes(shell))
|
|
118
|
+
return launcherVersionArguments(shell, {
|
|
119
|
+
arguments: arguments_,
|
|
120
|
+
worker: location.worker,
|
|
121
|
+
});
|
|
122
|
+
const index = shellScriptIndex(arguments_, shell);
|
|
123
|
+
const script = index === undefined ? undefined : arguments_[index];
|
|
124
|
+
if (script === undefined)
|
|
125
|
+
return [];
|
|
126
|
+
let path = resolve(location.directory, script);
|
|
127
|
+
if (!script.includes("/") &&
|
|
128
|
+
["sh", "bash", "dash"].includes(shell) &&
|
|
129
|
+
(await missingFile(path)))
|
|
130
|
+
path =
|
|
131
|
+
(await accessibleFile(script, { ...location, mode: constants.R_OK })) ??
|
|
132
|
+
path;
|
|
133
|
+
return [...arguments_.slice(0, index), path, "--version"];
|
|
134
|
+
}
|
|
135
|
+
function existingDirectory(path) {
|
|
136
|
+
return stat(path).then((entry) => (entry.isDirectory() ? path : undefined), () => undefined);
|
|
137
|
+
}
|
|
138
|
+
async function usableHarnessCommand(command, location) {
|
|
139
|
+
const configured = listedSetting(command) ?? [];
|
|
140
|
+
const program = configured[0];
|
|
141
|
+
if (!program)
|
|
142
|
+
return false;
|
|
143
|
+
const arguments_ = await harnessVersionArguments(configured, {
|
|
144
|
+
directory: location.directory,
|
|
145
|
+
environment: location.commandEnvironment,
|
|
146
|
+
worker: location.worker,
|
|
147
|
+
});
|
|
148
|
+
if (arguments_.length === 0)
|
|
149
|
+
return false;
|
|
150
|
+
const path = await executableProgram(program, {
|
|
151
|
+
directory: location.directory,
|
|
152
|
+
environment: location.commandEnvironment,
|
|
153
|
+
});
|
|
154
|
+
if (path === undefined)
|
|
155
|
+
return false;
|
|
156
|
+
const directory = await existingDirectory(location.directory);
|
|
157
|
+
const output = await location.probe(path, {
|
|
158
|
+
arguments: arguments_,
|
|
159
|
+
env: location.commandEnvironment,
|
|
160
|
+
...(directory === undefined ? {} : { directory }),
|
|
161
|
+
});
|
|
162
|
+
return (output.reason === null &&
|
|
163
|
+
harnessVersion(output.stdout, harnessDefinition(basename(path)).versionPattern) !== null);
|
|
164
|
+
}
|
|
165
|
+
function workerCommands(environment, name) {
|
|
166
|
+
const variable = harnessDefaults(name).variable;
|
|
167
|
+
if (variable === undefined)
|
|
168
|
+
return {};
|
|
169
|
+
const command = listedSetting(environment[variable]);
|
|
170
|
+
return command === undefined ? {} : { [name]: command };
|
|
171
|
+
}
|
|
172
|
+
function selectedHarness(environment, harness) {
|
|
173
|
+
try {
|
|
174
|
+
return turnHarness({
|
|
175
|
+
...(environment["CLOVING_WORKER"] === undefined
|
|
176
|
+
? {}
|
|
177
|
+
: { worker: environment["CLOVING_WORKER"] }),
|
|
178
|
+
workerCommands: workerCommands(environment, configuredHarnessName(environment, harness) ?? "claude"),
|
|
179
|
+
...(harness === undefined ? {} : { harness }),
|
|
180
|
+
shell: environment["SHELL"] ?? "/bin/sh",
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function usableShellHarness(selected, location) {
|
|
188
|
+
const directory = await existingDirectory(location.directory);
|
|
189
|
+
const output = await location.probe(selected.shell, {
|
|
190
|
+
arguments: [
|
|
191
|
+
...shellArguments("login"),
|
|
192
|
+
shellProbeScript,
|
|
193
|
+
"cloving-harness-probe",
|
|
194
|
+
selected.command[0] ?? selected.worker,
|
|
195
|
+
"shell",
|
|
196
|
+
],
|
|
197
|
+
env: location.commandEnvironment,
|
|
198
|
+
...(directory === undefined ? {} : { directory }),
|
|
199
|
+
});
|
|
200
|
+
return (output.reason === null &&
|
|
201
|
+
harnessVersion(shellBlock(output.stdout, 0) ?? "", harnessDefinition(selected.worker).versionPattern) !== null);
|
|
202
|
+
}
|
|
203
|
+
async function selectedProbe(selected, location) {
|
|
204
|
+
const shell = selected.shell;
|
|
205
|
+
if (shell !== undefined)
|
|
206
|
+
return {
|
|
207
|
+
usable: await usableShellHarness({ ...selected, shell }, location),
|
|
208
|
+
effective: {
|
|
209
|
+
result: "ok",
|
|
210
|
+
detail: `${JSON.stringify(selected.command)} through the login shell ${shell}`,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
const command = JSON.stringify(selected.command);
|
|
214
|
+
return {
|
|
215
|
+
usable: await usableHarnessCommand(command, {
|
|
216
|
+
...location,
|
|
217
|
+
worker: selected.worker,
|
|
218
|
+
}),
|
|
219
|
+
effective: await commandObservation(command, {
|
|
220
|
+
directory: location.directory,
|
|
221
|
+
environment: location.commandEnvironment,
|
|
222
|
+
}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function configuredHarnessName(environment, harness) {
|
|
226
|
+
return environment["CLOVING_WORKER"] ?? harness?.name;
|
|
227
|
+
}
|
|
228
|
+
async function selectedHarnessObservation(environment, location) {
|
|
229
|
+
const configured = configuredHarnessName(environment, location.harness);
|
|
230
|
+
const selected = selectedHarness(environment, location.harness);
|
|
231
|
+
if (selected === undefined)
|
|
232
|
+
return {
|
|
233
|
+
result: "fail",
|
|
234
|
+
detail: `harness ${configured ?? "claude"}; harness-no-worker`,
|
|
235
|
+
};
|
|
236
|
+
const { usable, effective } = await selectedProbe(selected, location);
|
|
237
|
+
const label = configured === undefined ? " (default)" : "";
|
|
238
|
+
return {
|
|
239
|
+
result: usable && effective.result === "ok" ? "ok" : "fail",
|
|
240
|
+
detail: `harness ${selected.worker}${label}; probe ${usable ? "ok" : "failed or unsupported command"}; ${effective.detail}`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DoctorObservation } from "../doctor-report.ts";
|
|
2
|
+
export declare function listedSetting(text: string | undefined): readonly string[] | undefined;
|
|
3
|
+
export declare function nodeObservation(version: string): DoctorObservation;
|
|
4
|
+
export declare function executableProgram(program: string, location: {
|
|
5
|
+
readonly directory: string;
|
|
6
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
7
|
+
}): Promise<string | undefined>;
|
|
8
|
+
export declare function accessibleFile(program: string, location: {
|
|
9
|
+
readonly directory: string;
|
|
10
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
11
|
+
readonly mode: number;
|
|
12
|
+
}): Promise<string | undefined>;
|
|
13
|
+
export declare function commandObservation(text: string | undefined, location: {
|
|
14
|
+
readonly directory: string;
|
|
15
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
16
|
+
}): Promise<DoctorObservation>;
|
|
17
|
+
export declare function queueObservation(text: string | undefined): DoctorObservation;
|
|
18
|
+
export declare function privateTextsObservation(text: string | undefined): DoctorObservation;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { access, constants, stat } from "node:fs/promises";
|
|
2
|
+
import { delimiter, resolve } from "node:path";
|
|
3
|
+
import { supportedNode, supportedNodes } from "./toolchain.js";
|
|
4
|
+
export function listedSetting(text) {
|
|
5
|
+
try {
|
|
6
|
+
const list = JSON.parse(text ?? "null");
|
|
7
|
+
if (Array.isArray(list) &&
|
|
8
|
+
list.every((item) => typeof item === "string" && !item.includes("\0")))
|
|
9
|
+
return list.map(String);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
export function nodeObservation(version) {
|
|
17
|
+
return {
|
|
18
|
+
result: supportedNode(version) ? "ok" : "fail",
|
|
19
|
+
detail: `Node ${version}; workflow admission requires Node ${supportedNodes}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export async function executableProgram(program, location) {
|
|
23
|
+
return accessibleFile(program, { ...location, mode: constants.X_OK });
|
|
24
|
+
}
|
|
25
|
+
export async function accessibleFile(program, location) {
|
|
26
|
+
const paths = program.includes("/")
|
|
27
|
+
? [program]
|
|
28
|
+
: (location.environment["PATH"] ?? "")
|
|
29
|
+
.split(delimiter)
|
|
30
|
+
.map((directory) => resolve(location.directory, directory, program));
|
|
31
|
+
for (const candidate of paths) {
|
|
32
|
+
const path = resolve(location.directory, candidate);
|
|
33
|
+
try {
|
|
34
|
+
await access(path, location.mode);
|
|
35
|
+
if ((await stat(path)).isFile())
|
|
36
|
+
return path;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
export async function commandObservation(text, location) {
|
|
45
|
+
const command = listedSetting(text);
|
|
46
|
+
const program = command?.[0];
|
|
47
|
+
if (!program)
|
|
48
|
+
return { result: "fail", detail: "An executable command list is required" };
|
|
49
|
+
const path = await executableProgram(program, location);
|
|
50
|
+
return {
|
|
51
|
+
result: path === undefined ? "fail" : "ok",
|
|
52
|
+
detail: `${JSON.stringify(command)} from ${location.directory}; ${path ?? "program is not executable"}. Availability now does not guarantee an untracked file exists in a later worktree`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function queueObservation(text) {
|
|
56
|
+
const seconds = Number(text);
|
|
57
|
+
const valid = text !== undefined &&
|
|
58
|
+
/^\d+$/.test(text) &&
|
|
59
|
+
Number.isInteger(seconds) &&
|
|
60
|
+
seconds >= 10 &&
|
|
61
|
+
seconds <= 3600;
|
|
62
|
+
return {
|
|
63
|
+
result: valid ? "ok" : "fail",
|
|
64
|
+
detail: valid
|
|
65
|
+
? `${String(seconds)} seconds`
|
|
66
|
+
: "queue.everySeconds must be a whole number from 10 to 3600",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function privateTextsObservation(text) {
|
|
70
|
+
const valid = listedSetting(text)?.some((value) => value.trim().length > 0) === true;
|
|
71
|
+
return {
|
|
72
|
+
result: valid ? "ok" : "fail",
|
|
73
|
+
detail: valid
|
|
74
|
+
? "Nonblank private texts configured"
|
|
75
|
+
: "privateTexts needs at least one nonblank text",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DoctorObservation } from "../doctor-report.ts";
|
|
2
|
+
import type { ProbeRunner } from "./probe-command.ts";
|
|
3
|
+
export interface DoctorRuntime {
|
|
4
|
+
readonly runtime: string | undefined;
|
|
5
|
+
readonly project: string | undefined;
|
|
6
|
+
readonly observation: DoctorObservation;
|
|
7
|
+
}
|
|
8
|
+
export declare function runtimeObservation(repository: string, options: {
|
|
9
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
10
|
+
readonly probe: ProbeRunner;
|
|
11
|
+
}): Promise<DoctorRuntime>;
|
|
12
|
+
export declare function serviceObservation(location: DoctorRuntime, options: {
|
|
13
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
14
|
+
readonly probe: ProbeRunner;
|
|
15
|
+
}): Promise<DoctorObservation>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { access, constants, lstat, realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname, join, relative, resolve } from "node:path";
|
|
3
|
+
import { socketAddress } from "../broker/socket-address.js";
|
|
4
|
+
import { record } from "../protocol.js";
|
|
5
|
+
import { adoptionRecordPath, runtimeDirectory, legacyRuntimeDirectory, } from "./runtime-directory.js";
|
|
6
|
+
async function writableDirectory(path) {
|
|
7
|
+
let existing = path;
|
|
8
|
+
for (;;) {
|
|
9
|
+
try {
|
|
10
|
+
const entry = await stat(existing);
|
|
11
|
+
if (!entry.isDirectory())
|
|
12
|
+
throw new Error(`${existing} is not a directory`);
|
|
13
|
+
await access(existing, constants.W_OK | constants.X_OK);
|
|
14
|
+
return existing;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!(error instanceof Error &&
|
|
18
|
+
"code" in error &&
|
|
19
|
+
error.code === "ENOENT"))
|
|
20
|
+
throw new Error(`Folder is not writable: ${existing}`, {
|
|
21
|
+
cause: error,
|
|
22
|
+
});
|
|
23
|
+
const parent = dirname(existing);
|
|
24
|
+
if (parent === existing)
|
|
25
|
+
throw error;
|
|
26
|
+
existing = parent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function runtimePrivacy(path) {
|
|
31
|
+
const entry = await lstat(path).catch((error) => {
|
|
32
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
33
|
+
return undefined;
|
|
34
|
+
throw error;
|
|
35
|
+
});
|
|
36
|
+
if (entry === undefined)
|
|
37
|
+
return "owner and mode will be set at creation";
|
|
38
|
+
if (!entry.isDirectory())
|
|
39
|
+
throw new Error("Runtime is not a directory");
|
|
40
|
+
if (entry.uid !== process.getuid?.())
|
|
41
|
+
throw new Error("Runtime owner is a different user");
|
|
42
|
+
const mode = entry.mode & 0o777;
|
|
43
|
+
if ((mode & 0o077) !== 0)
|
|
44
|
+
throw new Error(`Runtime mode ${mode.toString(8)} is not private`);
|
|
45
|
+
return `owner ${String(entry.uid)}, mode ${mode.toString(8)}`;
|
|
46
|
+
}
|
|
47
|
+
async function selectedRuntime(repository, options) {
|
|
48
|
+
const { environment, probe } = options;
|
|
49
|
+
const runtime = runtimeDirectory(environment, repository);
|
|
50
|
+
if (runtime === undefined)
|
|
51
|
+
throw new Error("Runtime directory is not configured");
|
|
52
|
+
const recordPath = adoptionRecordPath(environment, repository);
|
|
53
|
+
if (environment["CLOVING_RUNTIME_DIR"] || recordPath === undefined)
|
|
54
|
+
return { runtime: resolve(runtime), recordPath: undefined };
|
|
55
|
+
const recorded = await lstat(recordPath).catch((error) => {
|
|
56
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
57
|
+
return undefined;
|
|
58
|
+
throw error;
|
|
59
|
+
});
|
|
60
|
+
if (recorded !== undefined)
|
|
61
|
+
return { runtime, recordPath };
|
|
62
|
+
const legacy = legacyRuntimeDirectory(environment);
|
|
63
|
+
if (legacy === undefined)
|
|
64
|
+
return { runtime, recordPath: undefined };
|
|
65
|
+
const output = await probe(process.execPath, {
|
|
66
|
+
arguments: [
|
|
67
|
+
join(import.meta.dirname, "../../tools", `doctor-adoption${extname(import.meta.filename)}`),
|
|
68
|
+
resolve(runtime),
|
|
69
|
+
repository,
|
|
70
|
+
resolve(legacy),
|
|
71
|
+
recordPath,
|
|
72
|
+
],
|
|
73
|
+
env: environment,
|
|
74
|
+
});
|
|
75
|
+
if (output.reason !== null)
|
|
76
|
+
throw new Error("Unable to inspect legacy runtime adoption");
|
|
77
|
+
return parsedSelection(output.stdout, recordPath);
|
|
78
|
+
}
|
|
79
|
+
function parsedSelection(text, recordPath) {
|
|
80
|
+
const selected = record(JSON.parse(text));
|
|
81
|
+
const path = selected?.["runtime"];
|
|
82
|
+
if (typeof path !== "string")
|
|
83
|
+
throw new Error("Invalid runtime selection");
|
|
84
|
+
return {
|
|
85
|
+
runtime: resolve(path),
|
|
86
|
+
recordPath: typeof selected?.["adoptionRecord"] === "string" ? recordPath : undefined,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async function generatedProjectDirectory(parent) {
|
|
90
|
+
const existing = await writableDirectory(parent);
|
|
91
|
+
return join(await realpath(existing), relative(existing, parent), "project");
|
|
92
|
+
}
|
|
93
|
+
export async function runtimeObservation(repository, options) {
|
|
94
|
+
let runtime;
|
|
95
|
+
let project;
|
|
96
|
+
try {
|
|
97
|
+
const selected = await selectedRuntime(repository, options);
|
|
98
|
+
const runtimePath = selected.runtime;
|
|
99
|
+
runtime = runtimePath;
|
|
100
|
+
const privacy = await runtimePrivacy(runtime);
|
|
101
|
+
project = await generatedProjectDirectory(dirname(runtime));
|
|
102
|
+
const address = socketAddress(join(runtime, "control.sock"), {
|
|
103
|
+
directory: project,
|
|
104
|
+
});
|
|
105
|
+
if (address.kind === "refused")
|
|
106
|
+
throw new Error(address.detail);
|
|
107
|
+
const paths = [
|
|
108
|
+
runtime,
|
|
109
|
+
dirname(runtime),
|
|
110
|
+
...[
|
|
111
|
+
"project",
|
|
112
|
+
"workflow-bundles",
|
|
113
|
+
"state",
|
|
114
|
+
"world",
|
|
115
|
+
"journal",
|
|
116
|
+
"worktrees",
|
|
117
|
+
"github",
|
|
118
|
+
"handoffs",
|
|
119
|
+
].map((folder) => join(dirname(runtimePath), folder)),
|
|
120
|
+
];
|
|
121
|
+
if (selected.recordPath !== undefined)
|
|
122
|
+
paths.push(dirname(selected.recordPath));
|
|
123
|
+
for (const path of paths)
|
|
124
|
+
await writableDirectory(path);
|
|
125
|
+
return {
|
|
126
|
+
runtime,
|
|
127
|
+
project,
|
|
128
|
+
observation: {
|
|
129
|
+
result: "ok",
|
|
130
|
+
detail: `${runtime}; socket ${address.path} (${String(Buffer.byteLength(address.path))} bytes); ${privacy}; runtime, parent, adoption record and start folders are writable`,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
return {
|
|
136
|
+
runtime,
|
|
137
|
+
project,
|
|
138
|
+
observation: {
|
|
139
|
+
result: "fail",
|
|
140
|
+
detail: error instanceof Error ? error.message : "Runtime inspection failed",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export async function serviceObservation(location, options) {
|
|
146
|
+
const { environment, probe } = options;
|
|
147
|
+
const { runtime, project } = location;
|
|
148
|
+
if (runtime === undefined ||
|
|
149
|
+
project === undefined ||
|
|
150
|
+
location.observation.result !== "ok")
|
|
151
|
+
return { result: "skip", detail: "Runtime prerequisite unavailable" };
|
|
152
|
+
const entry = await lstat(join(runtime, "control.sock")).catch((error) => {
|
|
153
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
154
|
+
return undefined;
|
|
155
|
+
throw error;
|
|
156
|
+
});
|
|
157
|
+
if (entry === undefined)
|
|
158
|
+
return { result: "skip", detail: "No service for this repository" };
|
|
159
|
+
const result = await probe(process.execPath, {
|
|
160
|
+
arguments: [
|
|
161
|
+
join(import.meta.dirname, `doctor-service${extname(import.meta.filename)}`),
|
|
162
|
+
runtime,
|
|
163
|
+
],
|
|
164
|
+
env: environment,
|
|
165
|
+
directory: project,
|
|
166
|
+
milliseconds: 5000,
|
|
167
|
+
});
|
|
168
|
+
const usable = result.reason === null &&
|
|
169
|
+
record(JSON.parse(result.stdout))?.["kind"] === "result";
|
|
170
|
+
return {
|
|
171
|
+
result: usable ? "ok" : "fail",
|
|
172
|
+
detail: usable
|
|
173
|
+
? "Service answers from its generated project folder"
|
|
174
|
+
: "Service did not answer successfully within 5 seconds",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { send } from "./client.js";
|
|
2
|
+
async function main() {
|
|
3
|
+
const runtime = process.argv[2];
|
|
4
|
+
if (runtime === undefined) {
|
|
5
|
+
process.exitCode = 1;
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
process.stdout.write(JSON.stringify(await send(runtime, { operation: "status", parameters: { limit: 1 } })) + "\n");
|
|
9
|
+
}
|
|
10
|
+
if (process.argv[1] === import.meta.filename)
|
|
11
|
+
await main();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { configurationRoot, absoluteWorkflowFolder, } from "../project-settings.js";
|
|
5
|
+
import { isCandidateDeclaration } from "../workflow-candidate.js";
|
|
6
|
+
import { bundledWorkflowIds } from "../workflow-discovery.js";
|
|
7
|
+
export const bundledDoctorWorkflows = Object.values(bundledWorkflowIds).map((workflowId) => ({
|
|
8
|
+
scope: "bundled",
|
|
9
|
+
workflowId,
|
|
10
|
+
capabilities: ["claude", "github"],
|
|
11
|
+
}));
|
|
12
|
+
export async function doctorWorkflows(repository, environment) {
|
|
13
|
+
const discovered = [];
|
|
14
|
+
for (const [scope, folder] of [
|
|
15
|
+
["project", join(repository, ".cloving/workflows")],
|
|
16
|
+
[
|
|
17
|
+
"user",
|
|
18
|
+
absoluteWorkflowFolder(environment["CLOVING_WORKFLOW_FOLDER"]) ??
|
|
19
|
+
join(configurationRoot(environment, homedir()), "cloving/workflows"),
|
|
20
|
+
],
|
|
21
|
+
]) {
|
|
22
|
+
const files = await readdir(folder).catch((error) => {
|
|
23
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
24
|
+
return [];
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
for (const file of files.filter((file) => file.endsWith(".ts") &&
|
|
28
|
+
!file.endsWith(".d.ts") &&
|
|
29
|
+
!file.endsWith(".test.ts"))) {
|
|
30
|
+
const text = await readFile(join(folder, file.slice(0, -3) + ".declaration.json"), "utf8").catch(() => undefined);
|
|
31
|
+
if (text === undefined)
|
|
32
|
+
continue;
|
|
33
|
+
let declaration;
|
|
34
|
+
try {
|
|
35
|
+
declaration = JSON.parse(text);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (isCandidateDeclaration(declaration))
|
|
41
|
+
discovered.push({ scope, ...declaration.workflow });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [...bundledDoctorWorkflows, ...discovered];
|
|
45
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DoctorCheck } from "../doctor-report.ts";
|
|
2
|
+
import type { ProbeRunner } from "./probe-command.ts";
|
|
3
|
+
interface DoctorOptions {
|
|
4
|
+
readonly repository: string | undefined;
|
|
5
|
+
readonly environment: Readonly<NodeJS.ProcessEnv>;
|
|
6
|
+
readonly probe: ProbeRunner;
|
|
7
|
+
}
|
|
8
|
+
export declare function doctorReport(options: DoctorOptions): Promise<{
|
|
9
|
+
readonly version: 1;
|
|
10
|
+
readonly checks: readonly DoctorCheck[];
|
|
11
|
+
}>;
|
|
12
|
+
export declare function doctorCommand(options: DoctorOptions & {
|
|
13
|
+
readonly json: boolean;
|
|
14
|
+
}): Promise<number>;
|
|
15
|
+
export {};
|