cloving 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +525 -185
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +1 -0
- package/dist/src/authority/commands.js +24 -4
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +6 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +7 -1
- package/dist/src/broker/actor/authority-queries.js +17 -2
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +4 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +22 -9
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +2 -1
- package/dist/src/cli/render.js +44 -28
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +70 -44
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +1 -1
- package/dist/src/cli/watch-board-view.js +8 -2
- package/dist/src/cli/watch-board.js +23 -10
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +7 -2
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.js +17 -4
- package/dist/src/cli/watch-page.js +48 -12
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pull-request.d.ts +3 -1
- package/dist/src/cli/watch-pull-request.js +4 -0
- package/dist/src/cli/watch-render.d.ts +9 -1
- package/dist/src/cli/watch-server.js +23 -5
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +37 -1
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +6 -20
- package/dist/src/cli/watch-view.js +14 -106
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +19 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -3
- package/dist/src/daemon/claude-worker.js +65 -76
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +2 -33
- package/dist/src/daemon/daemon.js +126 -132
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +1 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.js +89 -8
- package/dist/src/daemon/github-merge-call.d.ts +2 -0
- package/dist/src/daemon/github-merge.js +7 -3
- package/dist/src/daemon/github-methods.js +10 -0
- package/dist/src/daemon/github-operation.d.ts +1 -0
- package/dist/src/daemon/github-retry.js +8 -44
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +3 -26
- package/dist/src/daemon/notify.js +2 -1
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -0
- package/dist/src/daemon/retrying-turn.js +108 -30
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-registration.d.ts +5 -7
- package/dist/src/daemon/ticket-registration.js +85 -40
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +5 -0
- package/dist/src/execution-pin.js +67 -4
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +1 -1
- package/dist/src/host/start-delivery.js +10 -3
- package/dist/src/host/step-bridge-host.d.ts +6 -20
- package/dist/src/host/step-bridge-host.js +44 -58
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/registry.d.ts +16 -3
- package/dist/src/service/registry.js +34 -3
- package/dist/src/service/replies.d.ts +9 -1
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +14 -55
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +18 -2
- package/dist/src/service/service.js +23 -7
- package/dist/src/service/submission-handler.d.ts +0 -1
- package/dist/src/service/submission-handler.js +6 -34
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +8 -23
- package/dist/src/step-bridge.d.ts +23 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/token-prices.d.ts +12 -4
- package/dist/src/token-prices.js +15 -2
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +16 -0
- package/dist/src/worker-usage.js +57 -0
- package/dist/src/workflow-admission.d.ts +5 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +47 -5
- package/dist/src/workflow-declaration.d.ts +21 -3
- package/dist/src/workflow-declaration.js +77 -9
- package/dist/src/workflow-discovery.d.ts +2 -1
- package/dist/src/workflow-discovery.js +4 -1
- package/dist/src/workflow-refusals.js +3 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +11 -1
- package/dist/src/workflows.js +8 -0
- package/dist/tools/admit-workflow.d.ts +1 -0
- package/dist/tools/admit-workflow.js +18 -5
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +4 -0
- package/dist/tools/self-host-project.js +61 -14
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +86 -61
- package/dist/tools/workflow-candidate-counts.d.ts +6 -2
- package/dist/tools/workflow-candidate-counts.js +31 -16
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +2 -0
- package/dist/tools/workflow-candidate-program.js +36 -8
- package/dist/tools/workflow-candidate-source.js +77 -15
- package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
- package/dist/tools/workflow-candidate-syntax.js +70 -26
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +1 -0
- package/dist/tools/workflow-folder-capture.js +47 -2
- package/dist/tools/workflow-folders.d.ts +17 -1
- package/dist/tools/workflow-folders.js +59 -6
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-ticket.js +1 -1
- package/dist/workflows/ticket-prompts.js +5 -1
- package/package.json +46 -4
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -42
- package/dist/src/chats/analysis-batches.js +0 -97
- package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
- package/dist/src/chats/analysis-checkpoint.js +0 -31
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -18
- package/dist/src/chats/analysis-input.js +0 -97
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-merge.d.ts +0 -16
- package/dist/src/chats/analysis-merge.js +0 -134
- package/dist/src/chats/analysis-prompt.d.ts +0 -18
- package/dist/src/chats/analysis-prompt.js +0 -42
- package/dist/src/chats/analysis-proposal.d.ts +0 -4
- package/dist/src/chats/analysis-proposal.js +0 -41
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -4
- package/dist/src/chats/analysis-shape.js +0 -235
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/reference-mapping.d.ts +0 -16
- package/dist/src/chats/reference-mapping.js +0 -153
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
- package/dist/src/chats/workflow-generation-projection.js +0 -75
- package/dist/src/chats/workflow-generation-source.d.ts +0 -25
- package/dist/src/chats/workflow-generation-source.js +0 -124
- package/dist/src/chats/workflow-generation-text.d.ts +0 -23
- package/dist/src/chats/workflow-generation-text.js +0 -74
- package/dist/src/chats/workflow-generation.d.ts +0 -69
- package/dist/src/chats/workflow-generation.js +0 -142
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -20
- package/dist/src/daemon/analysis-worker.js +0 -271
- package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
- package/dist/src/daemon/chats-batch-binding.js +0 -99
- package/dist/src/daemon/chats-capture.d.ts +0 -18
- package/dist/src/daemon/chats-capture.js +0 -194
- package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
- package/dist/src/daemon/chats-checkpoints.js +0 -186
- package/dist/src/daemon/chats-files.d.ts +0 -42
- package/dist/src/daemon/chats-files.js +0 -252
- package/dist/src/daemon/chats-follow-up.d.ts +0 -38
- package/dist/src/daemon/chats-follow-up.js +0 -180
- package/dist/src/daemon/chats-question.d.ts +0 -15
- package/dist/src/daemon/chats-question.js +0 -93
- package/dist/src/daemon/chats-worker.d.ts +0 -13
- package/dist/src/daemon/chats-worker.js +0 -201
- package/dist/workflows/analyze-chats.d.ts +0 -15
- package/dist/workflows/analyze-chats.declaration.json +0 -22
- package/dist/workflows/analyze-chats.js +0 -250
package/dist/tools/self-host.js
CHANGED
|
@@ -1,77 +1,74 @@
|
|
|
1
|
+
import { turnHarness, harnessDefaults, nativeHarness, } from "../src/harness-defaults.js";
|
|
2
|
+
import { absoluteWorkflowFolder } from "../src/project-settings.js";
|
|
3
|
+
import { projectConfiguration, projectRoot, topLevel, } from "./project-configuration.js";
|
|
1
4
|
import { isProfilesFile } from "../src/turn-profile.js";
|
|
5
|
+
import { parseCommands, parseCommandSeconds, } from "../src/command-settings.js";
|
|
2
6
|
import { parseFallbackModels, parseTokenPrices, } from "../src/token-prices.js";
|
|
3
|
-
import {
|
|
4
|
-
import { readFile, realpath, writeFile } from "node:fs/promises";
|
|
7
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
5
8
|
import { homedir } from "node:os";
|
|
6
9
|
import { dirname, extname, join, resolve } from "node:path";
|
|
7
10
|
import { pathToFileURL } from "node:url";
|
|
8
11
|
import { preparedProject, } from "./self-host-project.js";
|
|
9
12
|
import { selfUpdateMilliseconds } from "./self-update-host.js";
|
|
10
13
|
import { hostedPrograms } from "./self-host-processes.js";
|
|
14
|
+
import { workflowBundleLoader } from "./self-host-workflows.js";
|
|
15
|
+
import { adoptRuntimeDirectory } from "./self-host-runtime.js";
|
|
16
|
+
import { parseSchedulesSetting } from "../src/workflow-schedule.js";
|
|
11
17
|
const product = resolve(import.meta.dirname, "..");
|
|
12
18
|
const flags = process.argv.slice(2);
|
|
13
19
|
function flag(name) {
|
|
14
|
-
const index = flags.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return execFileSync("git", ["-C", given, "rev-parse", "--show-toplevel"], {
|
|
20
|
-
encoding: "utf8",
|
|
21
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
22
|
-
}).trim();
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return given;
|
|
26
|
-
}
|
|
20
|
+
const index = flags.findLastIndex((argument) => argument === name || argument.startsWith(`${name}=`));
|
|
21
|
+
const argument = flags[index];
|
|
22
|
+
return argument === name
|
|
23
|
+
? flags[index + 1]
|
|
24
|
+
: argument?.slice(name.length + 1);
|
|
27
25
|
}
|
|
28
26
|
const runtimeArgument = flag("--runtime");
|
|
29
27
|
if (runtimeArgument === undefined)
|
|
30
28
|
throw new Error("The start program needs --runtime. Use: cloving start");
|
|
31
|
-
const
|
|
29
|
+
const repository = await projectRoot(flag("--repository") ?? process.cwd());
|
|
30
|
+
const configuration = await projectConfiguration(repository, process.env);
|
|
31
|
+
const environment = configuration.environment;
|
|
32
|
+
const selectedRuntime = await adoptRuntimeDirectory({
|
|
33
|
+
runtime: resolve(runtimeArgument),
|
|
34
|
+
repository,
|
|
35
|
+
legacyRuntime: flag("--legacy-runtime"),
|
|
36
|
+
adoptionRecord: flag("--adoption-record"),
|
|
37
|
+
});
|
|
38
|
+
const runtime = selectedRuntime.runtime;
|
|
32
39
|
const directory = dirname(runtime);
|
|
33
|
-
const repository = await realpath(topLevel(resolve(flag("--repository") ?? process.cwd())));
|
|
34
40
|
const updateMilliseconds = await selfUpdateMilliseconds({
|
|
35
|
-
seconds:
|
|
41
|
+
seconds: environment["CLOVING_SELF_UPDATE_SECONDS"],
|
|
36
42
|
repository,
|
|
37
43
|
product: extname(import.meta.filename) === ".ts" ? topLevel(product) : product,
|
|
38
44
|
});
|
|
39
45
|
const client = flag("--client") ?? "cloving";
|
|
40
46
|
const project = join(directory, "project");
|
|
41
|
-
const concurrency = Number(
|
|
42
|
-
const leaseText =
|
|
47
|
+
const concurrency = Number(environment["CLOVING_HOST_BOUND"] ?? "8");
|
|
48
|
+
const leaseText = environment["CLOVING_OWNERSHIP_LEASE_SECONDS"];
|
|
43
49
|
const leaseSeconds = leaseText === undefined ? undefined : Number(leaseText);
|
|
44
|
-
const defaultCommand = [
|
|
45
|
-
"claude",
|
|
46
|
-
"-p",
|
|
47
|
-
"--output-format",
|
|
48
|
-
"stream-json",
|
|
49
|
-
"--verbose",
|
|
50
|
-
"--permission-mode",
|
|
51
|
-
"acceptEdits",
|
|
52
|
-
"--allowedTools",
|
|
53
|
-
"Bash,Read,Edit,Write,Glob,Grep,WebSearch,WebFetch",
|
|
54
|
-
"--max-budget-usd",
|
|
55
|
-
"5",
|
|
56
|
-
];
|
|
57
|
-
const defaultCodexCommand = [
|
|
58
|
-
"codex",
|
|
59
|
-
"exec",
|
|
60
|
-
"--json",
|
|
61
|
-
"--dangerously-bypass-approvals-and-sandbox",
|
|
62
|
-
"--skip-git-repo-check",
|
|
63
|
-
"-",
|
|
64
|
-
];
|
|
65
50
|
function selectedWorker() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
51
|
+
return checkedWorker(environment["CLOVING_WORKER"] ?? "claude");
|
|
52
|
+
}
|
|
53
|
+
function checkedWorker(name) {
|
|
54
|
+
try {
|
|
55
|
+
return turnHarness({
|
|
56
|
+
worker: name,
|
|
57
|
+
...(configuration.harness === undefined
|
|
58
|
+
? {}
|
|
59
|
+
: { harness: configuration.harness }),
|
|
60
|
+
}).worker;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error(`The daemon did not start: harness-no-worker: ${name}`, {
|
|
64
|
+
cause: error,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
70
67
|
}
|
|
71
68
|
async function profilesFile() {
|
|
72
|
-
const path =
|
|
69
|
+
const path = environment["CLOVING_PROFILES"];
|
|
73
70
|
if (path === undefined)
|
|
74
|
-
return
|
|
71
|
+
return configuration.profiles;
|
|
75
72
|
try {
|
|
76
73
|
const value = JSON.parse(await readFile(path, "utf8"));
|
|
77
74
|
if (isProfilesFile(value))
|
|
@@ -83,17 +80,17 @@ async function profilesFile() {
|
|
|
83
80
|
throw new Error("The daemon did not start: invalid-profiles");
|
|
84
81
|
}
|
|
85
82
|
function queueLanes() {
|
|
86
|
-
const value =
|
|
83
|
+
const value = environment["CLOVING_QUEUE_LANES"];
|
|
87
84
|
if (value === undefined)
|
|
88
85
|
return 1;
|
|
89
86
|
if (!/^[1-4]$/.test(value))
|
|
90
87
|
throw new Error("The daemon did not start: invalid-queue-lanes");
|
|
91
|
-
if (
|
|
88
|
+
if (environment["CLOVING_QUEUE_SECONDS"] === undefined)
|
|
92
89
|
throw new Error("The daemon did not start: queue-lanes-needs-queue");
|
|
93
90
|
return Number(value);
|
|
94
91
|
}
|
|
95
92
|
function queueInterval(commands) {
|
|
96
|
-
const value =
|
|
93
|
+
const value = environment["CLOVING_QUEUE_SECONDS"];
|
|
97
94
|
if (value === undefined)
|
|
98
95
|
return undefined;
|
|
99
96
|
const seconds = Number(value);
|
|
@@ -109,7 +106,7 @@ function queueInterval(commands) {
|
|
|
109
106
|
return seconds * 1000;
|
|
110
107
|
}
|
|
111
108
|
function listed(name) {
|
|
112
|
-
const given =
|
|
109
|
+
const given = environment[name];
|
|
113
110
|
if (given === undefined)
|
|
114
111
|
return undefined;
|
|
115
112
|
const list = JSON.parse(given);
|
|
@@ -135,22 +132,27 @@ await import("./main.mjs");
|
|
|
135
132
|
await writeFile(join(project, "main.mjs"), `import * as workflows from "./artifacts/client.mjs";
|
|
136
133
|
import { POST } from "./artifacts/flow.mjs";
|
|
137
134
|
import { startDaemon } from ${source("src/daemon/daemon.ts")};
|
|
138
|
-
|
|
135
|
+
${workflowBundleLoader()}
|
|
136
|
+
const opening = await startDaemon({ ...JSON.parse(${JSON.stringify(JSON.stringify(settings))}), workflows, handler: POST, loadBundle: loadWorkflowBundle });
|
|
139
137
|
if (opening.kind !== "started") {
|
|
140
138
|
process.stderr.write("The daemon did not start: " + opening.reason + ": " + opening.detail + "\\n");
|
|
141
139
|
process.exit(1);
|
|
142
140
|
}
|
|
143
|
-
process.stdout.write(${JSON.stringify(guide())});
|
|
141
|
+
process.stdout.write(${JSON.stringify(guide(workflows))});
|
|
144
142
|
const stop = async () => { await opening.daemon.close(); process.exit(0); };
|
|
145
143
|
process.once("SIGINT", stop);
|
|
146
144
|
process.once("SIGTERM", stop);
|
|
147
145
|
`);
|
|
148
146
|
}
|
|
149
|
-
function guide() {
|
|
147
|
+
function guide(workflows) {
|
|
150
148
|
return [
|
|
151
149
|
"Cloving runs. Stop it with Control-C.",
|
|
152
150
|
`Repository: ${repository}`,
|
|
151
|
+
`Runtime directory: ${runtime}`,
|
|
153
152
|
`Work trees: ${join(directory, "worktrees")}`,
|
|
153
|
+
...(selectedRuntime.note === "" ? [] : [selectedRuntime.note]),
|
|
154
|
+
...Object.entries(configuration.sources).map(([field, source]) => `${field}: ${source}`),
|
|
155
|
+
...workflows.workflowRefusals.map((refusal) => `Refused workflow ${refusal.scope} ${refusal.label}: ${refusal.codes.join(", ")}`),
|
|
154
156
|
"Commands for a second terminal:",
|
|
155
157
|
` ${client} run develop-ticket --ticket <ticket-id>`,
|
|
156
158
|
` ${client} run develop-issue --ticket <ticket-id>`,
|
|
@@ -162,13 +164,27 @@ function guide() {
|
|
|
162
164
|
"",
|
|
163
165
|
].join("\n");
|
|
164
166
|
}
|
|
165
|
-
const tokenPrices = parseTokenPrices(
|
|
166
|
-
const
|
|
167
|
+
const tokenPrices = parseTokenPrices(environment["CLOVING_TOKEN_PRICES"]);
|
|
168
|
+
const commands = parseCommands(environment["CLOVING_COMMANDS"]);
|
|
169
|
+
const commandSeconds = parseCommandSeconds(environment["CLOVING_COMMAND_SECONDS"]);
|
|
170
|
+
const fallbackModels = parseFallbackModels(environment["CLOVING_FALLBACK_MODELS"]);
|
|
167
171
|
const profiles = await profilesFile();
|
|
172
|
+
const schedules = parseSchedulesSetting(environment["CLOVING_SCHEDULES"]);
|
|
168
173
|
const worker = selectedWorker();
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
function nativeCommands() {
|
|
175
|
+
const names = new Set([
|
|
176
|
+
worker,
|
|
177
|
+
...Object.values(profiles).map((profile) => checkedWorker(profile.harness ?? worker)),
|
|
178
|
+
]);
|
|
179
|
+
return Object.fromEntries([...names].filter(nativeHarness).flatMap((name) => {
|
|
180
|
+
const variable = harnessDefaults(name).variable;
|
|
181
|
+
const command = variable === undefined ? undefined : listed(variable);
|
|
182
|
+
return command === undefined ? [] : [[name, command]];
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
const workerCommands = nativeCommands();
|
|
186
|
+
const harness = configuration.harness ?? {};
|
|
187
|
+
const command = turnHarness({ worker, workerCommands, harness }).command;
|
|
172
188
|
const nextCommand = listed("CLOVING_NEXT_COMMAND");
|
|
173
189
|
const ticketCommand = listed("CLOVING_TICKET_COMMAND");
|
|
174
190
|
const lanes = queueLanes();
|
|
@@ -178,12 +194,19 @@ const manifests = await preparedProject({
|
|
|
178
194
|
project,
|
|
179
195
|
repository,
|
|
180
196
|
home: homedir(),
|
|
181
|
-
xdgConfigHome:
|
|
197
|
+
xdgConfigHome: environment["XDG_CONFIG_HOME"],
|
|
198
|
+
userFolder: absoluteWorkflowFolder(environment["CLOVING_WORKFLOW_FOLDER"]),
|
|
182
199
|
});
|
|
183
200
|
await launchers({
|
|
201
|
+
commands,
|
|
202
|
+
commandSeconds,
|
|
203
|
+
schedules,
|
|
184
204
|
tokenPrices,
|
|
185
205
|
fallbackModels,
|
|
186
206
|
worker,
|
|
207
|
+
workerCommands,
|
|
208
|
+
harness,
|
|
209
|
+
shell: environment["SHELL"] ?? "/bin/sh",
|
|
187
210
|
profiles,
|
|
188
211
|
command,
|
|
189
212
|
ticketCommand,
|
|
@@ -193,6 +216,7 @@ await launchers({
|
|
|
193
216
|
resetQueue: flags.includes("--reset-queue"),
|
|
194
217
|
notifyCommand: listed("CLOVING_NOTIFY_COMMAND"),
|
|
195
218
|
githubCommand: listed("CLOVING_GH_COMMAND"),
|
|
219
|
+
requiredChecks: listed("CLOVING_REQUIRED_CHECKS") ?? null,
|
|
196
220
|
checkCommand: listed("CLOVING_CHECK_COMMAND"),
|
|
197
221
|
privateTexts: listed("CLOVING_PRIVATE_TEXTS"),
|
|
198
222
|
}, manifests);
|
|
@@ -203,5 +227,6 @@ process.exitCode = await hostedPrograms({
|
|
|
203
227
|
directory,
|
|
204
228
|
repository,
|
|
205
229
|
updateMilliseconds,
|
|
206
|
-
watchPort:
|
|
230
|
+
watchPort: environment["CLOVING_WATCH_PORT"] ?? "3663",
|
|
231
|
+
phoneRelay: environment["CLOVING_PHONE_RELAY"] ?? "on",
|
|
207
232
|
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { type CandidateSymbols } from "./workflow-candidate-syntax.ts";
|
|
3
|
-
interface Totals {
|
|
3
|
+
export interface Totals {
|
|
4
4
|
readonly knownCallCount: number;
|
|
5
5
|
readonly knownUnitTotal: number;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
interface CountSymbols extends CandidateSymbols {
|
|
8
|
+
readonly localTotals?: (node: ts.Node) => Totals | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function candidateEffectTotals(source: ts.Node, symbols: CountSymbols): Totals;
|
|
11
|
+
export declare function candidateLoopRepetitions(node: ts.IterationStatement, symbols: CandidateSymbols): number | undefined;
|
|
8
12
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { protectedCall,
|
|
2
|
+
import { protectedCall, helperCall, } from "./workflow-candidate-syntax.js";
|
|
3
|
+
import { propertyName } from "./workflow-candidate-fields.js";
|
|
3
4
|
import { referenceSymbol } from "./workflow-source-effects.js";
|
|
4
5
|
const zero = { knownCallCount: 0, knownUnitTotal: 0 };
|
|
5
6
|
function add(first, second) {
|
|
@@ -21,7 +22,7 @@ function multiply(total, repetitions) {
|
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
24
|
function units(node, symbols) {
|
|
24
|
-
if (
|
|
25
|
+
if (helperCall(node, symbols))
|
|
25
26
|
return 1;
|
|
26
27
|
const argument = node.arguments[0];
|
|
27
28
|
if (!argument || !ts.isObjectLiteralExpression(argument))
|
|
@@ -29,10 +30,8 @@ function units(node, symbols) {
|
|
|
29
30
|
const property = argument.properties.find((entry) => entry.name && propertyName(entry.name) === "units");
|
|
30
31
|
if (!property || !ts.isPropertyAssignment(property))
|
|
31
32
|
return 0;
|
|
32
|
-
const value = constantNumber(property.initializer);
|
|
33
|
-
return
|
|
34
|
-
? value
|
|
35
|
-
: 0;
|
|
33
|
+
const value = Number(constantNumber(property.initializer));
|
|
34
|
+
return Number.isSafeInteger(value) && value > 0 ? value : 0;
|
|
36
35
|
}
|
|
37
36
|
function loopIncrement(node, variable) {
|
|
38
37
|
if ((ts.isPostfixUnaryExpression(node) || ts.isPrefixUnaryExpression(node)) &&
|
|
@@ -210,19 +209,35 @@ export function candidateEffectTotals(source, symbols) {
|
|
|
210
209
|
return add(count(node.expression), multiply(add(count(node.initializer), count(node.statement)), arrayIterations(node, symbols)));
|
|
211
210
|
if (ts.isSwitchStatement(node))
|
|
212
211
|
return add(count(node.expression), switchTotals(node.caseBlock, count));
|
|
213
|
-
|
|
214
|
-
? {
|
|
215
|
-
knownCallCount: 1,
|
|
216
|
-
knownUnitTotal: units(node, symbols),
|
|
217
|
-
}
|
|
218
|
-
: zero;
|
|
219
|
-
ts.forEachChild(node, (child) => {
|
|
220
|
-
total = add(total, count(child));
|
|
221
|
-
});
|
|
222
|
-
return total;
|
|
212
|
+
return nodeTotals(node, { symbols, count });
|
|
223
213
|
}
|
|
224
214
|
return count(source);
|
|
225
215
|
}
|
|
216
|
+
function nodeTotals(node, input) {
|
|
217
|
+
const local = input.symbols.localTotals?.(node);
|
|
218
|
+
if (local && ts.isFunctionLike(node))
|
|
219
|
+
return local;
|
|
220
|
+
let total = local ??
|
|
221
|
+
(protectedCall(node, input.symbols)
|
|
222
|
+
? { knownCallCount: 1, knownUnitTotal: units(node, input.symbols) }
|
|
223
|
+
: zero);
|
|
224
|
+
ts.forEachChild(node, (child) => {
|
|
225
|
+
total = add(total, input.count(child));
|
|
226
|
+
});
|
|
227
|
+
return total;
|
|
228
|
+
}
|
|
229
|
+
export function candidateLoopRepetitions(node, symbols) {
|
|
230
|
+
if (ts.isForStatement(node))
|
|
231
|
+
return loopIterations(node, symbols);
|
|
232
|
+
if (ts.isForOfStatement(node) &&
|
|
233
|
+
ts.isArrayLiteralExpression(node.expression) &&
|
|
234
|
+
!uncertainLoopBody(node.statement, {
|
|
235
|
+
checker: symbols.checker,
|
|
236
|
+
counter: undefined,
|
|
237
|
+
}))
|
|
238
|
+
return node.expression.elements.length;
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
226
241
|
function arrayIterations(node, symbols) {
|
|
227
242
|
if (!ts.isArrayLiteralExpression(node.expression))
|
|
228
243
|
return 1;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
export declare function propertyName(name: ts.PropertyName): string | undefined;
|
|
3
|
+
export declare function propertyInitializer(node: ts.Node | undefined, field: string): ts.Expression | undefined;
|
|
4
|
+
export declare function literalField(node: ts.Node | undefined, field: string): string | null;
|
|
5
|
+
export declare function invalidFields(object: ts.ObjectLiteralExpression): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
export function propertyName(name) {
|
|
3
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name))
|
|
4
|
+
return name.text;
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
export function propertyInitializer(node, field) {
|
|
8
|
+
if (!node || !ts.isObjectLiteralExpression(node))
|
|
9
|
+
return undefined;
|
|
10
|
+
const property = node.properties.find((entry) => entry.name && propertyName(entry.name) === field);
|
|
11
|
+
return property && ts.isPropertyAssignment(property)
|
|
12
|
+
? property.initializer
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
15
|
+
export function literalField(node, field) {
|
|
16
|
+
const value = propertyInitializer(node, field);
|
|
17
|
+
return value && ts.isStringLiteral(value) ? value.text : null;
|
|
18
|
+
}
|
|
19
|
+
export function invalidFields(object) {
|
|
20
|
+
const names = object.properties.map((entry) => entry.name && propertyName(entry.name));
|
|
21
|
+
return (names.includes(undefined) ||
|
|
22
|
+
new Set(names).size !== names.length ||
|
|
23
|
+
object.properties.some((entry) => !ts.isPropertyAssignment(entry)));
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { type Totals } from "./workflow-candidate-counts.ts";
|
|
3
|
+
import { type CandidateSymbols } from "./workflow-candidate-syntax.ts";
|
|
4
|
+
export declare function helperEffectTotals(input: {
|
|
5
|
+
readonly symbols: CandidateSymbols;
|
|
6
|
+
readonly sources: readonly ts.SourceFile[];
|
|
7
|
+
}): {
|
|
8
|
+
readonly totals?: Totals;
|
|
9
|
+
readonly unsupportedForms: readonly string[];
|
|
10
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { candidateEffectTotals, candidateLoopRepetitions, } from "./workflow-candidate-counts.js";
|
|
3
|
+
import { protectedCall, } from "./workflow-candidate-syntax.js";
|
|
4
|
+
import { resolvedSymbol } from "./workflow-candidate-program.js";
|
|
5
|
+
import { referenceSymbol, typeOnlyEffectNode, } from "./workflow-source-effects.js";
|
|
6
|
+
const zero = { knownCallCount: 0, knownUnitTotal: 0 };
|
|
7
|
+
export function helperEffectTotals(input) {
|
|
8
|
+
const { symbols, sources } = input;
|
|
9
|
+
const unsupportedForms = [];
|
|
10
|
+
if (sources.length === 1)
|
|
11
|
+
return { unsupportedForms };
|
|
12
|
+
const active = new Set();
|
|
13
|
+
const totals = new Map();
|
|
14
|
+
const functions = localFunctions(sources);
|
|
15
|
+
const functionAt = (node) => localFunctionAt(node, { checker: symbols.checker, functions });
|
|
16
|
+
function count(declaration) {
|
|
17
|
+
const cached = totals.get(declaration);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
if (active.has(declaration)) {
|
|
21
|
+
unsupportedForms.push("recursive-helper-effects");
|
|
22
|
+
return zero;
|
|
23
|
+
}
|
|
24
|
+
active.add(declaration);
|
|
25
|
+
const result = candidateEffectTotals(declaration, {
|
|
26
|
+
...symbols,
|
|
27
|
+
localTotals: (node) => {
|
|
28
|
+
if (ts.isFunctionLike(node) && node !== declaration)
|
|
29
|
+
return zero;
|
|
30
|
+
if (!ts.isCallExpression(node) || !ts.isIdentifier(node.expression))
|
|
31
|
+
return undefined;
|
|
32
|
+
const called = functionAt(node.expression);
|
|
33
|
+
return called && effectful.has(called) ? count(called) : undefined;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
active.delete(declaration);
|
|
37
|
+
totals.set(declaration, result);
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
const effectful = effectfulFunctions({ functions, functionAt, symbols });
|
|
41
|
+
if ([...effectful].every((entry) => entry.getSourceFile() === symbols.source))
|
|
42
|
+
return { unsupportedForms };
|
|
43
|
+
for (const source of sources)
|
|
44
|
+
inspectHelperReferences(source, {
|
|
45
|
+
functionAt,
|
|
46
|
+
effectful,
|
|
47
|
+
symbols,
|
|
48
|
+
unsupportedForms,
|
|
49
|
+
});
|
|
50
|
+
for (const declaration of effectful)
|
|
51
|
+
count(declaration);
|
|
52
|
+
const workflow = [...functions].find((entry) => entry.getSourceFile() === symbols.source &&
|
|
53
|
+
(ts.getCombinedModifierFlags(entry) & ts.ModifierFlags.Export) !== 0);
|
|
54
|
+
return { totals: workflow ? count(workflow) : zero, unsupportedForms };
|
|
55
|
+
}
|
|
56
|
+
function localFunctions(sources) {
|
|
57
|
+
return new Set(sources.flatMap((source) => source.statements.filter((node) => ts.isFunctionDeclaration(node) && node.body !== undefined)));
|
|
58
|
+
}
|
|
59
|
+
function localFunctionAt(node, input) {
|
|
60
|
+
const symbol = resolvedSymbol(input.checker, referenceSymbol(node, {
|
|
61
|
+
parent: node.parent,
|
|
62
|
+
checker: input.checker,
|
|
63
|
+
}));
|
|
64
|
+
return symbol?.declarations?.find((entry) => ts.isFunctionDeclaration(entry) && input.functions.has(entry));
|
|
65
|
+
}
|
|
66
|
+
function effectfulFunctions(input) {
|
|
67
|
+
const effectful = new Set();
|
|
68
|
+
const calls = (node) => {
|
|
69
|
+
if (typeOnlyEffectNode(node))
|
|
70
|
+
return false;
|
|
71
|
+
if (protectedCall(node, input.symbols))
|
|
72
|
+
return true;
|
|
73
|
+
const called = ts.isIdentifier(node) ? input.functionAt(node) : undefined;
|
|
74
|
+
if (called && effectful.has(called))
|
|
75
|
+
return true;
|
|
76
|
+
return ts.forEachChild(node, (child) => calls(child) || undefined) ?? false;
|
|
77
|
+
};
|
|
78
|
+
let previous = -1;
|
|
79
|
+
while (previous !== effectful.size) {
|
|
80
|
+
previous = effectful.size;
|
|
81
|
+
for (const declaration of input.functions)
|
|
82
|
+
if (calls(declaration))
|
|
83
|
+
effectful.add(declaration);
|
|
84
|
+
}
|
|
85
|
+
return effectful;
|
|
86
|
+
}
|
|
87
|
+
function inspectHelperReferences(source, input) {
|
|
88
|
+
function visit(node) {
|
|
89
|
+
if (typeOnlyEffectNode(node))
|
|
90
|
+
return;
|
|
91
|
+
if (source !== input.symbols.source &&
|
|
92
|
+
protectedCall(node, input.symbols) &&
|
|
93
|
+
!checkedHelperContext(node, input.symbols))
|
|
94
|
+
input.unsupportedForms.push("uncheckable-helper-effects");
|
|
95
|
+
const declaration = ts.isIdentifier(node)
|
|
96
|
+
? input.functionAt(node)
|
|
97
|
+
: undefined;
|
|
98
|
+
if (declaration &&
|
|
99
|
+
input.effectful.has(declaration) &&
|
|
100
|
+
ts.isIdentifier(node) &&
|
|
101
|
+
!checkedHelperReference(node, input.symbols))
|
|
102
|
+
input.unsupportedForms.push("uncheckable-helper-effects");
|
|
103
|
+
ts.forEachChild(node, visit);
|
|
104
|
+
}
|
|
105
|
+
visit(source);
|
|
106
|
+
}
|
|
107
|
+
function checkedHelperReference(node, symbols) {
|
|
108
|
+
if (ts.isFunctionDeclaration(node.parent) && node.parent.name === node)
|
|
109
|
+
return true;
|
|
110
|
+
if (ts.isImportSpecifier(node.parent))
|
|
111
|
+
return true;
|
|
112
|
+
if (!ts.isCallExpression(node.parent) ||
|
|
113
|
+
node.parent.expression !== node ||
|
|
114
|
+
node.parent.questionDotToken !== undefined)
|
|
115
|
+
return false;
|
|
116
|
+
return checkedHelperContext(node.parent, symbols);
|
|
117
|
+
}
|
|
118
|
+
function checkedHelperContext(node, symbols) {
|
|
119
|
+
let parent = node;
|
|
120
|
+
while (!ts.isFunctionLike(parent)) {
|
|
121
|
+
if (ts.isSourceFile(parent))
|
|
122
|
+
return false;
|
|
123
|
+
if (ts.isIterationStatement(parent, false) &&
|
|
124
|
+
candidateLoopRepetitions(parent, symbols) === undefined)
|
|
125
|
+
return false;
|
|
126
|
+
parent = parent.parent;
|
|
127
|
+
}
|
|
128
|
+
return ts.isFunctionDeclaration(parent) && ts.isSourceFile(parent.parent);
|
|
129
|
+
}
|
|
@@ -2,10 +2,12 @@ import ts from "typescript";
|
|
|
2
2
|
export declare const candidatePackageRoot: string;
|
|
3
3
|
export interface CandidatePackageOptions {
|
|
4
4
|
readonly packageRoot?: string;
|
|
5
|
+
readonly helpers?: Readonly<Record<string, string>>;
|
|
5
6
|
}
|
|
6
7
|
export declare function resolvedSymbol(checker: ts.TypeChecker, symbol: ts.Symbol | undefined): ts.Symbol | undefined;
|
|
7
8
|
export declare function candidateProgram(text: string, installed?: CandidatePackageOptions): {
|
|
8
9
|
readonly program: ts.Program;
|
|
9
10
|
readonly source: ts.SourceFile;
|
|
11
|
+
readonly sources: readonly ts.SourceFile[];
|
|
10
12
|
readonly modules: ReadonlyMap<string, ts.SourceFile>;
|
|
11
13
|
};
|
|
@@ -2,6 +2,7 @@ import { dirname, join, resolve, sep } from "node:path";
|
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import metadata from "#package" with { type: "json" };
|
|
5
|
+
import { workflowHelperPath } from "../src/workflow-candidate.js";
|
|
5
6
|
export const candidatePackageRoot = dirname(fileURLToPath(import.meta.resolve("#package")));
|
|
6
7
|
export function resolvedSymbol(checker, symbol) {
|
|
7
8
|
if (!symbol || (symbol.flags & ts.SymbolFlags.Alias) === 0)
|
|
@@ -11,6 +12,12 @@ export function resolvedSymbol(checker, symbol) {
|
|
|
11
12
|
export function candidateProgram(text, installed = {}) {
|
|
12
13
|
const packageRoot = resolve(installed.packageRoot ?? candidatePackageRoot);
|
|
13
14
|
const candidate = join(packageRoot, "candidate.ts");
|
|
15
|
+
const sources = new Map([[candidate, text]]);
|
|
16
|
+
for (const [name, content] of Object.entries(installed.helpers ?? {})) {
|
|
17
|
+
if (workflowHelperPath("candidate.ts", `./${name}`) !== name)
|
|
18
|
+
throw new Error("invalid-workflow-helper");
|
|
19
|
+
sources.set(join(packageRoot, name), content);
|
|
20
|
+
}
|
|
14
21
|
const entries = new Map(Object.entries(metadata.exports).map(([name, entry]) => [
|
|
15
22
|
`cloving${name.slice(1)}`,
|
|
16
23
|
resolve(packageRoot, entry.types),
|
|
@@ -24,8 +31,8 @@ export function candidateProgram(text, installed = {}) {
|
|
|
24
31
|
strict: true,
|
|
25
32
|
noEmit: true,
|
|
26
33
|
};
|
|
27
|
-
const host = trustedHost({
|
|
28
|
-
const program = ts.createProgram([
|
|
34
|
+
const host = trustedHost({ sources, options, entries, packageRoot });
|
|
35
|
+
const program = ts.createProgram([...sources.keys(), ...entries.values()], options, host);
|
|
29
36
|
const source = program.getSourceFile(candidate);
|
|
30
37
|
if (!source)
|
|
31
38
|
throw new Error("candidate-analysis-unavailable");
|
|
@@ -36,15 +43,25 @@ export function candidateProgram(text, installed = {}) {
|
|
|
36
43
|
throw new Error("candidate-surface-unavailable");
|
|
37
44
|
modules.set(name, declaration);
|
|
38
45
|
}
|
|
39
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
program,
|
|
48
|
+
source,
|
|
49
|
+
modules,
|
|
50
|
+
sources: [...sources.keys()].map((name) => {
|
|
51
|
+
const entry = program.getSourceFile(name);
|
|
52
|
+
if (!entry)
|
|
53
|
+
throw new Error("candidate-analysis-unavailable");
|
|
54
|
+
return entry;
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
40
57
|
}
|
|
41
58
|
function trustedHost(input) {
|
|
42
|
-
const {
|
|
59
|
+
const { sources, options, entries, packageRoot } = input;
|
|
43
60
|
const libraries = dirname(ts.getDefaultLibFilePath(options)) + sep;
|
|
44
61
|
const declarations = join(packageRoot, "dist/src") + sep;
|
|
45
62
|
const readFile = (file) => {
|
|
46
|
-
if (file
|
|
47
|
-
return
|
|
63
|
+
if (sources.has(file))
|
|
64
|
+
return sources.get(file);
|
|
48
65
|
const absolute = resolve(file);
|
|
49
66
|
if (!absolute.endsWith(".d.ts"))
|
|
50
67
|
return undefined;
|
|
@@ -70,8 +87,19 @@ function trustedHost(input) {
|
|
|
70
87
|
extension: ts.Extension.Dts,
|
|
71
88
|
},
|
|
72
89
|
};
|
|
73
|
-
if (containingFile
|
|
74
|
-
|
|
90
|
+
if (sources.has(containingFile)) {
|
|
91
|
+
const importer = containingFile
|
|
92
|
+
.slice(packageRoot.length + 1)
|
|
93
|
+
.split(sep)
|
|
94
|
+
.join("/");
|
|
95
|
+
const local = workflowHelperPath(importer, name);
|
|
96
|
+
const target = local && join(packageRoot, local);
|
|
97
|
+
return {
|
|
98
|
+
resolvedModule: target && sources.has(target)
|
|
99
|
+
? { resolvedFileName: target, extension: ts.Extension.Ts }
|
|
100
|
+
: undefined,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
75
103
|
return ts.resolveModuleName(name, containingFile, options, host);
|
|
76
104
|
});
|
|
77
105
|
return host;
|