cloving 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +584 -144
- package/assets/watch-fonts/fira-code-OFL.md +93 -0
- package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-OFL.md +93 -0
- package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
- package/assets/watch-fonts/manifest.json +112 -0
- package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
- package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +2 -0
- package/dist/src/authority/commands.js +49 -8
- package/dist/src/authority/dispatch-decision.d.ts +1 -0
- package/dist/src/authority/dispatch-decision.js +7 -4
- package/dist/src/authority/events.js +2 -2
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/handoff-chain.d.ts +24 -0
- package/dist/src/authority/handoff-chain.js +46 -0
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reconciliation.d.ts +1 -0
- package/dist/src/authority/reconciliation.js +18 -11
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +9 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +11 -1
- package/dist/src/broker/actor/authority-queries.js +67 -3
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +3 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +13 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +26 -5
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +3 -1
- package/dist/src/cli/render.js +102 -39
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +74 -45
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +12 -1
- package/dist/src/cli/watch-board-view.js +64 -12
- package/dist/src/cli/watch-board.d.ts +7 -1
- package/dist/src/cli/watch-board.js +61 -16
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +12 -3
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.d.ts +10 -4
- package/dist/src/cli/watch-model.js +49 -59
- package/dist/src/cli/watch-page.js +67 -14
- package/dist/src/cli/watch-phases.js +3 -3
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pr-command.d.ts +5 -2
- package/dist/src/cli/watch-pr-command.js +41 -4
- package/dist/src/cli/watch-pr-identity.d.ts +14 -2
- package/dist/src/cli/watch-pr-identity.js +25 -0
- package/dist/src/cli/watch-pr-observer.d.ts +1 -0
- package/dist/src/cli/watch-pr-observer.js +48 -6
- package/dist/src/cli/watch-pull-request.d.ts +12 -0
- package/dist/src/cli/watch-pull-request.js +134 -0
- package/dist/src/cli/watch-reads.d.ts +7 -1
- package/dist/src/cli/watch-reads.js +42 -20
- package/dist/src/cli/watch-render.d.ts +23 -2
- package/dist/src/cli/watch-render.js +2 -1
- package/dist/src/cli/watch-server.js +56 -7
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +38 -2
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +10 -17
- package/dist/src/cli/watch-view.js +33 -77
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +20 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -5
- package/dist/src/daemon/claude-worker.js +64 -80
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +3 -30
- package/dist/src/daemon/daemon.js +132 -110
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +7 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-calls.d.ts +4 -0
- package/dist/src/daemon/github-calls.js +16 -7
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.d.ts +6 -0
- package/dist/src/daemon/github-ci.js +251 -0
- package/dist/src/daemon/github-merge-call.d.ts +16 -0
- package/dist/src/daemon/github-merge-call.js +73 -0
- package/dist/src/daemon/github-merge.d.ts +3 -5
- package/dist/src/daemon/github-merge.js +59 -98
- package/dist/src/daemon/github-methods.d.ts +28 -0
- package/dist/src/daemon/github-methods.js +90 -16
- package/dist/src/daemon/github-operation.d.ts +3 -0
- package/dist/src/daemon/github-retry.d.ts +6 -0
- package/dist/src/daemon/github-retry.js +13 -0
- package/dist/src/daemon/github-ticket-status.js +27 -1
- package/dist/src/daemon/github-worker.js +2 -1
- package/dist/src/daemon/handoff-worker.d.ts +10 -0
- package/dist/src/daemon/handoff-worker.js +232 -0
- package/dist/src/daemon/issue-queue.d.ts +2 -0
- package/dist/src/daemon/issue-queue.js +92 -63
- package/dist/src/daemon/notify-journal.d.ts +18 -0
- package/dist/src/daemon/notify-journal.js +108 -0
- package/dist/src/daemon/notify-message.js +2 -1
- package/dist/src/daemon/notify.js +177 -37
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +5 -0
- package/dist/src/daemon/retrying-turn.js +145 -21
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
- package/dist/src/daemon/ticket-dependency-waits.js +60 -0
- package/dist/src/daemon/ticket-registration.d.ts +10 -8
- package/dist/src/daemon/ticket-registration.js +146 -47
- package/dist/src/daemon/ticket-source.d.ts +4 -1
- package/dist/src/daemon/ticket-source.js +8 -2
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-visibility.d.ts +2 -0
- package/dist/src/decision-visibility.js +10 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +9 -0
- package/dist/src/execution-pin.js +86 -2
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +3 -2
- package/dist/src/host/start-delivery.js +11 -4
- package/dist/src/host/step-bridge-host.d.ts +6 -19
- package/dist/src/host/step-bridge-host.js +57 -55
- package/dist/src/host/world-reconciliation.d.ts +1 -0
- package/dist/src/host/world-reconciliation.js +3 -0
- package/dist/src/host/world-runs.js +5 -0
- package/dist/src/issue-identity.d.ts +6 -0
- package/dist/src/issue-identity.js +23 -0
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/queue-runs.d.ts +3 -0
- package/dist/src/service/queue-runs.js +39 -0
- package/dist/src/service/registry.d.ts +22 -3
- package/dist/src/service/registry.js +51 -8
- package/dist/src/service/replies.d.ts +10 -0
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +45 -54
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +21 -2
- package/dist/src/service/service.js +23 -5
- package/dist/src/service/submission-handler.js +70 -19
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +10 -1
- package/dist/src/step-bridge.d.ts +32 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/handoff.d.ts +2 -0
- package/dist/src/steps/handoff.js +13 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-dependencies.d.ts +1 -0
- package/dist/src/ticket-dependencies.js +15 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/ticket-status.js +7 -4
- package/dist/src/token-prices.d.ts +14 -4
- package/dist/src/token-prices.js +56 -11
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +25 -0
- package/dist/src/worker-usage.js +58 -1
- package/dist/src/workflow-admission.d.ts +6 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +48 -5
- package/dist/src/workflow-contracts.d.ts +2 -0
- package/dist/src/workflow-contracts.js +8 -3
- package/dist/src/workflow-declaration.d.ts +31 -2
- package/dist/src/workflow-declaration.js +140 -16
- package/dist/src/workflow-discovery.d.ts +19 -0
- package/dist/src/workflow-discovery.js +36 -0
- package/dist/src/workflow-refusals.d.ts +6 -0
- package/dist/src/workflow-refusals.js +42 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +12 -1
- package/dist/src/workflows.js +9 -0
- package/dist/tools/admit-workflow.d.ts +14 -0
- package/dist/tools/admit-workflow.js +107 -0
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +21 -0
- package/dist/tools/self-host-project.js +224 -0
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +106 -135
- package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
- package/dist/tools/workflow-bundle-dependencies.js +93 -0
- package/dist/tools/workflow-bundles.d.ts +20 -0
- package/dist/tools/workflow-bundles.js +173 -0
- package/dist/tools/workflow-candidate-counts.d.ts +12 -0
- package/dist/tools/workflow-candidate-counts.js +266 -0
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +13 -0
- package/dist/tools/workflow-candidate-program.js +106 -0
- package/dist/tools/workflow-candidate-source.d.ts +6 -0
- package/dist/tools/workflow-candidate-source.js +169 -0
- package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
- package/dist/tools/workflow-candidate-syntax.js +263 -0
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +18 -0
- package/dist/tools/workflow-folder-capture.js +261 -0
- package/dist/tools/workflow-folders.d.ts +49 -0
- package/dist/tools/workflow-folders.js +203 -0
- package/dist/tools/workflow-source-effects.d.ts +10 -0
- package/dist/tools/workflow-source-effects.js +213 -0
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-prd.js +71 -3
- package/dist/workflows/develop-ticket.js +6 -1
- package/dist/workflows/ticket-prompts.js +17 -3
- package/package.json +66 -6
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -24
- package/dist/src/chats/analysis-batches.js +0 -83
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -12
- package/dist/src/chats/analysis-input.js +0 -83
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-prompt.d.ts +0 -10
- package/dist/src/chats/analysis-prompt.js +0 -16
- package/dist/src/chats/analysis-proposal.d.ts +0 -2
- package/dist/src/chats/analysis-proposal.js +0 -32
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -3
- package/dist/src/chats/analysis-shape.js +0 -228
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -22
- package/dist/src/daemon/analysis-worker.js +0 -219
- package/dist/src/daemon/chats-files.d.ts +0 -15
- package/dist/src/daemon/chats-files.js +0 -113
- package/dist/src/daemon/chats-worker.d.ts +0 -12
- package/dist/src/daemon/chats-worker.js +0 -200
- package/dist/workflows/analyze-chats.d.ts +0 -10
- package/dist/workflows/analyze-chats.declaration.json +0 -9
- package/dist/workflows/analyze-chats.js +0 -73
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { shellArgument } from "./runtime-directory.js";
|
|
2
|
+
import { record } from "../protocol.js";
|
|
3
|
+
import { listedSetting } from "./doctor-local.js";
|
|
4
|
+
import { prRepository } from "./watch-pr-identity.js";
|
|
5
|
+
async function read(context, argumentsList) {
|
|
6
|
+
const output = await context.probe(context.command[0] ?? "", {
|
|
7
|
+
arguments: [...context.command.slice(1), ...argumentsList],
|
|
8
|
+
env: context.environment,
|
|
9
|
+
directory: context.repository,
|
|
10
|
+
bytes: 8 * 1024 * 1024,
|
|
11
|
+
});
|
|
12
|
+
if (output.reason !== null)
|
|
13
|
+
throw new Error(output.reason === "probe-timeout"
|
|
14
|
+
? "GitHub read timed out after 10 seconds"
|
|
15
|
+
: "GitHub command failed: " + output.reason);
|
|
16
|
+
return output.stdout;
|
|
17
|
+
}
|
|
18
|
+
async function origin(context) {
|
|
19
|
+
const output = await context.probe("git", {
|
|
20
|
+
arguments: ["remote", "get-url", "origin"],
|
|
21
|
+
env: context.environment,
|
|
22
|
+
directory: context.repository,
|
|
23
|
+
});
|
|
24
|
+
const identity = output.reason === null ? prRepository(output.stdout.trim()) : null;
|
|
25
|
+
const valid = identity !== null;
|
|
26
|
+
return {
|
|
27
|
+
observation: {
|
|
28
|
+
result: valid ? "ok" : "fail",
|
|
29
|
+
detail: valid
|
|
30
|
+
? `GitHub origin ${identity.host}/${identity.owner}/${identity.repository}`
|
|
31
|
+
: "origin is absent or is not on GitHub",
|
|
32
|
+
},
|
|
33
|
+
identity: valid ? identity : null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function list(text) {
|
|
37
|
+
const value = JSON.parse(text);
|
|
38
|
+
if (!Array.isArray(value))
|
|
39
|
+
throw new Error("Invalid GitHub response");
|
|
40
|
+
return Array.from(value).flatMap((item) => Array.isArray(item) ? Array.from(item) : [item]);
|
|
41
|
+
}
|
|
42
|
+
async function botActivity(context, pull) {
|
|
43
|
+
const { identity, number } = pull;
|
|
44
|
+
for (const endpoint of [
|
|
45
|
+
`pulls/${String(number)}/reviews`,
|
|
46
|
+
`issues/${String(number)}/comments`,
|
|
47
|
+
`pulls/${String(number)}/comments`,
|
|
48
|
+
]) {
|
|
49
|
+
const entries = list(await read(context, [
|
|
50
|
+
"api",
|
|
51
|
+
"--method",
|
|
52
|
+
"GET",
|
|
53
|
+
"--hostname",
|
|
54
|
+
identity.host,
|
|
55
|
+
"--paginate",
|
|
56
|
+
"--slurp",
|
|
57
|
+
`repos/${identity.owner}/${identity.repository}/${endpoint}?per_page=100`,
|
|
58
|
+
]));
|
|
59
|
+
if (entries.some((entry) => record(record(entry)?.["user"])?.["login"] === "greptile-apps[bot]"))
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
async function greptile(context, identity) {
|
|
65
|
+
const pulls = list(await read(context, [
|
|
66
|
+
"pr",
|
|
67
|
+
"list",
|
|
68
|
+
"--repo",
|
|
69
|
+
`${identity.host}/${identity.owner}/${identity.repository}`,
|
|
70
|
+
"--state",
|
|
71
|
+
"all",
|
|
72
|
+
"--limit",
|
|
73
|
+
"20",
|
|
74
|
+
"--json",
|
|
75
|
+
"number",
|
|
76
|
+
]));
|
|
77
|
+
if (pulls.length === 0)
|
|
78
|
+
return { result: "skip", detail: "No pull requests in this repository" };
|
|
79
|
+
for (const pull of pulls.slice(0, 20)) {
|
|
80
|
+
const number = record(pull)?.["number"];
|
|
81
|
+
if (typeof number !== "number" ||
|
|
82
|
+
!Number.isSafeInteger(number) ||
|
|
83
|
+
number < 1)
|
|
84
|
+
throw new Error("Invalid GitHub pull request");
|
|
85
|
+
if (await botActivity(context, { identity, number }))
|
|
86
|
+
return {
|
|
87
|
+
result: "ok",
|
|
88
|
+
detail: "Recent activity of greptile-apps[bot]; this does not establish a usable review",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
result: "fail",
|
|
93
|
+
detail: "No Greptile review or comment found on the last 20 pull requests. This does not prove Greptile is not installed",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export async function githubObservations(repository, options) {
|
|
97
|
+
const { environment, probe } = options;
|
|
98
|
+
const command = environment["CLOVING_GH_COMMAND"] === undefined
|
|
99
|
+
? ["gh"]
|
|
100
|
+
: (listedSetting(environment["CLOVING_GH_COMMAND"]) ?? []);
|
|
101
|
+
const context = { repository, environment, command, probe };
|
|
102
|
+
const found = await origin(context);
|
|
103
|
+
const host = found.identity?.host ?? "github.com";
|
|
104
|
+
const observations = {
|
|
105
|
+
"github-origin": found.observation,
|
|
106
|
+
"greptile-review": {
|
|
107
|
+
result: "skip",
|
|
108
|
+
detail: "GitHub login or origin prerequisite unavailable",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
const loginFix = `Log in with the configured command: ${command.map(shellArgument).join(" ")} auth login --hostname ${shellArgument(host)}`;
|
|
112
|
+
try {
|
|
113
|
+
await read(context, ["auth", "status", "--hostname", host]);
|
|
114
|
+
observations["gh-login"] = {
|
|
115
|
+
result: "ok",
|
|
116
|
+
detail: `Configured GitHub command is authenticated on ${host}`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
observations["gh-login"] = {
|
|
121
|
+
result: "fail",
|
|
122
|
+
detail: error instanceof Error ? error.message : "GitHub login unavailable",
|
|
123
|
+
};
|
|
124
|
+
return { observations, loginFix };
|
|
125
|
+
}
|
|
126
|
+
if (found.identity !== null) {
|
|
127
|
+
try {
|
|
128
|
+
observations["greptile-review"] = await greptile(context, found.identity);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
observations["greptile-review"] = {
|
|
132
|
+
result: "fail",
|
|
133
|
+
detail: error instanceof Error ? error.message : "GitHub read failed",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { observations, loginFix };
|
|
138
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DoctorObservation } from "../doctor-report.ts";
|
|
2
|
+
import { type HarnessSettings } from "../harness-defaults.ts";
|
|
3
|
+
import type { ProbeRunner } from "./probe-command.ts";
|
|
4
|
+
export declare function harnessObservations(environment: Readonly<NodeJS.ProcessEnv>, location: {
|
|
5
|
+
readonly directory: string;
|
|
6
|
+
readonly settingsValid: boolean;
|
|
7
|
+
readonly probe: ProbeRunner;
|
|
8
|
+
readonly commandEnvironment: Readonly<NodeJS.ProcessEnv>;
|
|
9
|
+
readonly harness?: HarnessSettings["harness"];
|
|
10
|
+
}): Promise<{
|
|
11
|
+
readonly harnesses: DoctorObservation;
|
|
12
|
+
readonly selected: DoctorObservation;
|
|
13
|
+
}>;
|
|
@@ -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 {};
|