cloving 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +525 -185
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +1 -0
- package/dist/src/authority/commands.js +24 -4
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +6 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +7 -1
- package/dist/src/broker/actor/authority-queries.js +17 -2
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +4 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +22 -9
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +2 -1
- package/dist/src/cli/render.js +44 -28
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +70 -44
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +1 -1
- package/dist/src/cli/watch-board-view.js +8 -2
- package/dist/src/cli/watch-board.js +23 -10
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +7 -2
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.js +17 -4
- package/dist/src/cli/watch-page.js +48 -12
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pull-request.d.ts +3 -1
- package/dist/src/cli/watch-pull-request.js +4 -0
- package/dist/src/cli/watch-render.d.ts +9 -1
- package/dist/src/cli/watch-server.js +23 -5
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +37 -1
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +6 -20
- package/dist/src/cli/watch-view.js +14 -106
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +19 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -3
- package/dist/src/daemon/claude-worker.js +65 -76
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +2 -33
- package/dist/src/daemon/daemon.js +126 -132
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +1 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.js +89 -8
- package/dist/src/daemon/github-merge-call.d.ts +2 -0
- package/dist/src/daemon/github-merge.js +7 -3
- package/dist/src/daemon/github-methods.js +10 -0
- package/dist/src/daemon/github-operation.d.ts +1 -0
- package/dist/src/daemon/github-retry.js +8 -44
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +3 -26
- package/dist/src/daemon/notify.js +2 -1
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -0
- package/dist/src/daemon/retrying-turn.js +108 -30
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-registration.d.ts +5 -7
- package/dist/src/daemon/ticket-registration.js +85 -40
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +5 -0
- package/dist/src/execution-pin.js +67 -4
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +1 -1
- package/dist/src/host/start-delivery.js +10 -3
- package/dist/src/host/step-bridge-host.d.ts +6 -20
- package/dist/src/host/step-bridge-host.js +44 -58
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/registry.d.ts +16 -3
- package/dist/src/service/registry.js +34 -3
- package/dist/src/service/replies.d.ts +9 -1
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +14 -55
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +18 -2
- package/dist/src/service/service.js +23 -7
- package/dist/src/service/submission-handler.d.ts +0 -1
- package/dist/src/service/submission-handler.js +6 -34
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +8 -23
- package/dist/src/step-bridge.d.ts +23 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/token-prices.d.ts +12 -4
- package/dist/src/token-prices.js +15 -2
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +16 -0
- package/dist/src/worker-usage.js +57 -0
- package/dist/src/workflow-admission.d.ts +5 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +47 -5
- package/dist/src/workflow-declaration.d.ts +21 -3
- package/dist/src/workflow-declaration.js +77 -9
- package/dist/src/workflow-discovery.d.ts +2 -1
- package/dist/src/workflow-discovery.js +4 -1
- package/dist/src/workflow-refusals.js +3 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +11 -1
- package/dist/src/workflows.js +8 -0
- package/dist/tools/admit-workflow.d.ts +1 -0
- package/dist/tools/admit-workflow.js +18 -5
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +4 -0
- package/dist/tools/self-host-project.js +61 -14
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +86 -61
- package/dist/tools/workflow-candidate-counts.d.ts +6 -2
- package/dist/tools/workflow-candidate-counts.js +31 -16
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +2 -0
- package/dist/tools/workflow-candidate-program.js +36 -8
- package/dist/tools/workflow-candidate-source.js +77 -15
- package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
- package/dist/tools/workflow-candidate-syntax.js +70 -26
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +1 -0
- package/dist/tools/workflow-folder-capture.js +47 -2
- package/dist/tools/workflow-folders.d.ts +17 -1
- package/dist/tools/workflow-folders.js +59 -6
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-ticket.js +1 -1
- package/dist/workflows/ticket-prompts.js +5 -1
- package/package.json +46 -4
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -42
- package/dist/src/chats/analysis-batches.js +0 -97
- package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
- package/dist/src/chats/analysis-checkpoint.js +0 -31
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -18
- package/dist/src/chats/analysis-input.js +0 -97
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-merge.d.ts +0 -16
- package/dist/src/chats/analysis-merge.js +0 -134
- package/dist/src/chats/analysis-prompt.d.ts +0 -18
- package/dist/src/chats/analysis-prompt.js +0 -42
- package/dist/src/chats/analysis-proposal.d.ts +0 -4
- package/dist/src/chats/analysis-proposal.js +0 -41
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -4
- package/dist/src/chats/analysis-shape.js +0 -235
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/reference-mapping.d.ts +0 -16
- package/dist/src/chats/reference-mapping.js +0 -153
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
- package/dist/src/chats/workflow-generation-projection.js +0 -75
- package/dist/src/chats/workflow-generation-source.d.ts +0 -25
- package/dist/src/chats/workflow-generation-source.js +0 -124
- package/dist/src/chats/workflow-generation-text.d.ts +0 -23
- package/dist/src/chats/workflow-generation-text.js +0 -74
- package/dist/src/chats/workflow-generation.d.ts +0 -69
- package/dist/src/chats/workflow-generation.js +0 -142
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -20
- package/dist/src/daemon/analysis-worker.js +0 -271
- package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
- package/dist/src/daemon/chats-batch-binding.js +0 -99
- package/dist/src/daemon/chats-capture.d.ts +0 -18
- package/dist/src/daemon/chats-capture.js +0 -194
- package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
- package/dist/src/daemon/chats-checkpoints.js +0 -186
- package/dist/src/daemon/chats-files.d.ts +0 -42
- package/dist/src/daemon/chats-files.js +0 -252
- package/dist/src/daemon/chats-follow-up.d.ts +0 -38
- package/dist/src/daemon/chats-follow-up.js +0 -180
- package/dist/src/daemon/chats-question.d.ts +0 -15
- package/dist/src/daemon/chats-question.js +0 -93
- package/dist/src/daemon/chats-worker.d.ts +0 -13
- package/dist/src/daemon/chats-worker.js +0 -201
- package/dist/workflows/analyze-chats.d.ts +0 -15
- package/dist/workflows/analyze-chats.declaration.json +0 -22
- package/dist/workflows/analyze-chats.js +0 -250
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { analysisFollowUp, analysisFollowUpPrompt, analysisLaunchBytes, } from "../chats/analysis-prompt.js";
|
|
4
|
-
import { prepareAnalysisBatch } from "../chats/analysis-batches.js";
|
|
5
|
-
import { isAnalysisSnapshot, analysisDocumentBytes, } from "../chats/analysis-input.js";
|
|
6
|
-
import { record } from "../protocol.js";
|
|
7
|
-
import { sumPrices } from "../worker-usage.js";
|
|
8
|
-
import { startRetriedTurn } from "./retrying-turn.js";
|
|
9
|
-
import { analysisAvailable, analysisMethod } from "./analysis-launch.js";
|
|
10
|
-
import { analysisToken } from "./analysis-token.js";
|
|
11
|
-
import { located, readRecord, writeRecord, replied, reportOf, interrupted, } from "./operation-journal.js";
|
|
12
|
-
function own(intent) {
|
|
13
|
-
return (intent.kind === "protected-effect" &&
|
|
14
|
-
intent.capability === "claude" &&
|
|
15
|
-
intent.method === analysisMethod &&
|
|
16
|
-
intent.target !== undefined &&
|
|
17
|
-
intent.payload !== undefined &&
|
|
18
|
-
intent.leaseGeneration !== undefined);
|
|
19
|
-
}
|
|
20
|
-
function failed(reason) {
|
|
21
|
-
return { kind: "failed", reason };
|
|
22
|
-
}
|
|
23
|
-
function firstBatch(snapshot) {
|
|
24
|
-
const batch = prepareAnalysisBatch(snapshot, {
|
|
25
|
-
nextRecordIndex: 0,
|
|
26
|
-
completedBatchCount: 0,
|
|
27
|
-
previousResult: null,
|
|
28
|
-
});
|
|
29
|
-
if (batch.kind === "refused")
|
|
30
|
-
throw new Error(batch.code);
|
|
31
|
-
if (batch.nextRecordIndex !== batch.totalRecords)
|
|
32
|
-
throw new Error("analysis-too-large");
|
|
33
|
-
return batch;
|
|
34
|
-
}
|
|
35
|
-
function promptOf(text, target) {
|
|
36
|
-
if (text !== undefined && Buffer.byteLength(text) > analysisDocumentBytes)
|
|
37
|
-
throw new Error("analysis-too-large");
|
|
38
|
-
const payload = record(JSON.parse(text ?? "null"));
|
|
39
|
-
if (payload === undefined)
|
|
40
|
-
throw new Error("analysis-input-refused");
|
|
41
|
-
const snapshot = payload["snapshot"];
|
|
42
|
-
if (!isAnalysisSnapshot(snapshot) || snapshot.importId !== target)
|
|
43
|
-
throw new Error("analysis-input-refused");
|
|
44
|
-
const followUp = "followUp" in payload ? analysisFollowUp(payload["followUp"]) : undefined;
|
|
45
|
-
const data = batchInput(snapshot, payload);
|
|
46
|
-
const prompt = turnPrompt(data, followUp);
|
|
47
|
-
if (analysisLaunchBytes(prompt) > analysisDocumentBytes)
|
|
48
|
-
throw new Error("analysis-too-large");
|
|
49
|
-
return prompt;
|
|
50
|
-
}
|
|
51
|
-
function turnPrompt(data, followUp) {
|
|
52
|
-
const context = data.context === undefined ? {} : { context: data.context };
|
|
53
|
-
if (followUp === undefined)
|
|
54
|
-
return data.prompt;
|
|
55
|
-
return analysisFollowUpPrompt(data.snapshot, { ...followUp, ...context });
|
|
56
|
-
}
|
|
57
|
-
function batchInput(snapshot, payload) {
|
|
58
|
-
if (!("context" in payload)) {
|
|
59
|
-
const batch = firstBatch(snapshot);
|
|
60
|
-
return { snapshot: batch.snapshot, prompt: batch.prompt };
|
|
61
|
-
}
|
|
62
|
-
const context = record(payload["context"]);
|
|
63
|
-
if (context === undefined || Object.keys(context).length !== 3)
|
|
64
|
-
throw new Error("analysis-input-refused");
|
|
65
|
-
const position = [context["batchIndex"], context["firstRecordIndex"]];
|
|
66
|
-
if (!position.every((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0) ||
|
|
67
|
-
Number(position[0]) > 3)
|
|
68
|
-
throw new Error("analysis-input-refused");
|
|
69
|
-
if (context["previousResult"] !== null &&
|
|
70
|
-
record(context["previousResult"]) === undefined)
|
|
71
|
-
throw new Error("analysis-input-refused");
|
|
72
|
-
return {
|
|
73
|
-
snapshot,
|
|
74
|
-
context,
|
|
75
|
-
prompt: JSON.stringify({ evidence: snapshot, context }),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async function cleaned(folder) {
|
|
79
|
-
await Promise.all(["configuration", "working"].map((name) => rm(join(folder, name), { recursive: true, force: true })));
|
|
80
|
-
}
|
|
81
|
-
async function privateRecord(folder, entry) {
|
|
82
|
-
await writeRecord(folder, { ...entry, permissions: "private" });
|
|
83
|
-
}
|
|
84
|
-
function outcome(end) {
|
|
85
|
-
const endedAt = new Date().toISOString();
|
|
86
|
-
if (end.stopped)
|
|
87
|
-
return { outcome: "stopped", endedAt };
|
|
88
|
-
const result = end.result;
|
|
89
|
-
if (result === undefined)
|
|
90
|
-
return { ...interrupted("analysis-turn-failed"), endedAt };
|
|
91
|
-
const fields = {
|
|
92
|
-
costUsd: result.costUsd,
|
|
93
|
-
usage: result.usage,
|
|
94
|
-
model: result.model,
|
|
95
|
-
...(result.attempts === undefined ? {} : { attempts: result.attempts }),
|
|
96
|
-
sessionId: result.sessionId,
|
|
97
|
-
turns: result.turns,
|
|
98
|
-
estimatedCostUsd: sumPrices((result.attempts ?? []).map((attempt) => attempt.estimatedCostUsd)),
|
|
99
|
-
};
|
|
100
|
-
if (end.exitCode !== 0 || result.failed)
|
|
101
|
-
return {
|
|
102
|
-
outcome: "failed",
|
|
103
|
-
reason: "analysis-turn-failed",
|
|
104
|
-
endedAt,
|
|
105
|
-
result: JSON.stringify(fields),
|
|
106
|
-
};
|
|
107
|
-
if (Buffer.byteLength(result.text, "utf8") > 16_000)
|
|
108
|
-
return {
|
|
109
|
-
outcome: "failed",
|
|
110
|
-
reason: "analysis-reply-too-large",
|
|
111
|
-
endedAt,
|
|
112
|
-
result: JSON.stringify(fields),
|
|
113
|
-
};
|
|
114
|
-
return {
|
|
115
|
-
outcome: "completed",
|
|
116
|
-
endedAt,
|
|
117
|
-
result: JSON.stringify({ ...fields, reply: result.text }),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function running(processId) {
|
|
121
|
-
if (typeof processId !== "number")
|
|
122
|
-
return false;
|
|
123
|
-
try {
|
|
124
|
-
process.kill(processId, 0);
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
async function reconcile(parts, intent) {
|
|
132
|
-
if (!own(intent))
|
|
133
|
-
return failed("unsupported-effect");
|
|
134
|
-
const { key, folder } = located(parts.settings.journal, intent.operationId);
|
|
135
|
-
const result = await readRecord(folder, "result.json");
|
|
136
|
-
if (result !== undefined) {
|
|
137
|
-
await cleaned(folder);
|
|
138
|
-
return replied({ receipt: key, worker: "claude" }, result);
|
|
139
|
-
}
|
|
140
|
-
if (parts.active.has(key))
|
|
141
|
-
return { kind: "accepted", receipt: key, worker: "claude" };
|
|
142
|
-
const started = await readRecord(folder, "started.json");
|
|
143
|
-
if (started === undefined)
|
|
144
|
-
return { kind: "absent" };
|
|
145
|
-
if (running(record(started)?.["processId"]))
|
|
146
|
-
return { kind: "unknown", evidence: key };
|
|
147
|
-
const ending = interrupted("analysis-turn-failed");
|
|
148
|
-
await privateRecord(folder, { name: "result.json", value: ending });
|
|
149
|
-
await cleaned(folder);
|
|
150
|
-
return replied({ receipt: key, worker: "claude" }, ending);
|
|
151
|
-
}
|
|
152
|
-
async function begun(parts, opening) {
|
|
153
|
-
const { intent, folder, key, directory, prompt } = opening;
|
|
154
|
-
const started = {
|
|
155
|
-
operationId: intent.operationId,
|
|
156
|
-
target: intent.target,
|
|
157
|
-
mode: "analysis",
|
|
158
|
-
startedAt: new Date().toISOString(),
|
|
159
|
-
};
|
|
160
|
-
const turn = await startRetriedTurn({
|
|
161
|
-
mode: "analysis",
|
|
162
|
-
analysisToken: opening.token,
|
|
163
|
-
command: [],
|
|
164
|
-
folder,
|
|
165
|
-
directory,
|
|
166
|
-
prompt,
|
|
167
|
-
}, { ...parts.settings, metadata: started });
|
|
168
|
-
const done = turn.ended
|
|
169
|
-
.then(async (end) => {
|
|
170
|
-
const result = outcome(end);
|
|
171
|
-
await privateRecord(folder, { name: "result.json", value: result });
|
|
172
|
-
await cleaned(folder);
|
|
173
|
-
await parts.settings.report(reportOf({ intent, worker: "claude", commandId: `analysis-turn:${key}` }, result));
|
|
174
|
-
})
|
|
175
|
-
.catch(() => undefined)
|
|
176
|
-
.finally(() => parts.active.delete(key));
|
|
177
|
-
parts.active.set(key, { turn, done });
|
|
178
|
-
}
|
|
179
|
-
function cancelled(parts, signal) {
|
|
180
|
-
return signal.aborted || parts.stopping.signal.aborted;
|
|
181
|
-
}
|
|
182
|
-
async function deliver(parts, call) {
|
|
183
|
-
const { intent, signal } = call;
|
|
184
|
-
if (!own(intent))
|
|
185
|
-
return failed("unsupported-effect");
|
|
186
|
-
const known = await reconcile(parts, intent);
|
|
187
|
-
if (known.kind !== "absent")
|
|
188
|
-
return known;
|
|
189
|
-
const { key, folder } = located(parts.settings.journal, intent.operationId);
|
|
190
|
-
const text = await parts.settings.document(intent.payload);
|
|
191
|
-
let prompt;
|
|
192
|
-
try {
|
|
193
|
-
prompt = promptOf(text, intent.target);
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
return failed(error instanceof Error && error.message === "analysis-too-large"
|
|
197
|
-
? "analysis-too-large"
|
|
198
|
-
: "analysis-input-refused");
|
|
199
|
-
}
|
|
200
|
-
await mkdir(join(folder, "configuration"), { recursive: true, mode: 0o700 });
|
|
201
|
-
if (!(await analysisAvailable(folder))) {
|
|
202
|
-
await cleaned(folder);
|
|
203
|
-
return failed("analysis-worker-unavailable");
|
|
204
|
-
}
|
|
205
|
-
if (cancelled(parts, signal)) {
|
|
206
|
-
await cleaned(folder);
|
|
207
|
-
return failed("analysis-turn-failed");
|
|
208
|
-
}
|
|
209
|
-
const credential = await analysisToken(folder, signal);
|
|
210
|
-
if (cancelled(parts, signal)) {
|
|
211
|
-
await cleaned(folder);
|
|
212
|
-
return failed("analysis-turn-failed");
|
|
213
|
-
}
|
|
214
|
-
if ("error" in credential) {
|
|
215
|
-
await cleaned(folder);
|
|
216
|
-
return {
|
|
217
|
-
...failed("analysis-worker-unavailable"),
|
|
218
|
-
result: JSON.stringify({ error: credential.error }),
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
const directory = join(folder, "working");
|
|
222
|
-
await mkdir(directory, { mode: 0o700 });
|
|
223
|
-
await begun(parts, {
|
|
224
|
-
intent,
|
|
225
|
-
key,
|
|
226
|
-
folder,
|
|
227
|
-
directory,
|
|
228
|
-
prompt,
|
|
229
|
-
token: credential.token,
|
|
230
|
-
});
|
|
231
|
-
return { receipt: key, worker: "claude" };
|
|
232
|
-
}
|
|
233
|
-
async function halted(parts, active) {
|
|
234
|
-
active.turn.stop(parts.settings.stopMilliseconds ?? 2_000);
|
|
235
|
-
await active.done;
|
|
236
|
-
}
|
|
237
|
-
function delivered(parts, call) {
|
|
238
|
-
if (cancelled(parts, call.signal))
|
|
239
|
-
return Promise.resolve(failed("analysis-turn-failed"));
|
|
240
|
-
const key = call.intent.operationId;
|
|
241
|
-
const known = parts.preparing.get(key);
|
|
242
|
-
if (known !== undefined)
|
|
243
|
-
return known;
|
|
244
|
-
const signal = AbortSignal.any([call.signal, parts.stopping.signal]);
|
|
245
|
-
const pending = deliver(parts, { ...call, signal }).finally(() => parts.preparing.delete(key));
|
|
246
|
-
parts.preparing.set(key, pending);
|
|
247
|
-
return pending;
|
|
248
|
-
}
|
|
249
|
-
export function analysisWorker(settings) {
|
|
250
|
-
const parts = {
|
|
251
|
-
settings,
|
|
252
|
-
active: new Map(),
|
|
253
|
-
preparing: new Map(),
|
|
254
|
-
stopping: new AbortController(),
|
|
255
|
-
};
|
|
256
|
-
return {
|
|
257
|
-
deliver: (intent, signal) => delivered(parts, { intent, signal }),
|
|
258
|
-
reconcile: (intent) => reconcile(parts, intent),
|
|
259
|
-
stop: async (intent) => {
|
|
260
|
-
const active = parts.active.get(located(settings.journal, intent.operationId).key);
|
|
261
|
-
if (active !== undefined)
|
|
262
|
-
await halted(parts, active);
|
|
263
|
-
return reconcile(parts, intent);
|
|
264
|
-
},
|
|
265
|
-
close: async () => {
|
|
266
|
-
parts.stopping.abort();
|
|
267
|
-
await Promise.all(parts.preparing.values());
|
|
268
|
-
await Promise.all([...parts.active.values()].map((active) => halted(parts, active)));
|
|
269
|
-
},
|
|
270
|
-
};
|
|
271
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type AnalysisSnapshot } from "../chats/analysis-input.ts";
|
|
2
|
-
import { type AnalysisCapture } from "./chats-capture.ts";
|
|
3
|
-
interface AnalysisBatchBindingInput {
|
|
4
|
-
readonly runId: string;
|
|
5
|
-
readonly importId: string;
|
|
6
|
-
readonly snapshot: AnalysisSnapshot | undefined;
|
|
7
|
-
readonly batch?: unknown;
|
|
8
|
-
}
|
|
9
|
-
export declare function boundAnalysisBatch(directory: string, input: AnalysisBatchBindingInput): Promise<{
|
|
10
|
-
capture: AnalysisCapture;
|
|
11
|
-
snapshot: AnalysisSnapshot;
|
|
12
|
-
batch: {
|
|
13
|
-
batchIndex: number;
|
|
14
|
-
nextRecordIndex: number;
|
|
15
|
-
};
|
|
16
|
-
previous: import("../chats/analysis-checkpoint.ts").AnalysisCheckpoint;
|
|
17
|
-
}>;
|
|
18
|
-
export declare function previousCheckpoint(folder: string, input: {
|
|
19
|
-
readonly capture: AnalysisCapture;
|
|
20
|
-
readonly batchIndex: number;
|
|
21
|
-
readonly snapshot: AnalysisSnapshot;
|
|
22
|
-
}): Promise<import("../chats/analysis-checkpoint.ts").AnalysisCheckpoint>;
|
|
23
|
-
export {};
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { record } from "../protocol.js";
|
|
3
|
-
import { initialAnalysisCheckpoint, batchAnalysisCheckpoint, } from "../chats/analysis-checkpoint.js";
|
|
4
|
-
import { analysisEvidence, } from "../chats/analysis-input.js";
|
|
5
|
-
import { mergeAnalysisBatch } from "../chats/analysis-merge.js";
|
|
6
|
-
import { prepareAnalysisBatch } from "../chats/analysis-batches.js";
|
|
7
|
-
import { checkpointProposal } from "../chats/analysis-proposal.js";
|
|
8
|
-
import { findAnalysisCapture, readCapturedAnalysisSnapshot, } from "./chats-capture.js";
|
|
9
|
-
import { boundedAnalysisFile, inspectAnalysisFiles } from "./chats-files.js";
|
|
10
|
-
export async function boundAnalysisBatch(directory, input) {
|
|
11
|
-
const capture = await findAnalysisCapture(directory, {
|
|
12
|
-
runId: input.runId,
|
|
13
|
-
importId: input.importId,
|
|
14
|
-
});
|
|
15
|
-
if (capture === undefined)
|
|
16
|
-
throw new Error("analysis-output-failed");
|
|
17
|
-
const snapshot = await readCapturedAnalysisSnapshot(directory, capture);
|
|
18
|
-
const binding = record(input.batch);
|
|
19
|
-
const batchIndex = binding?.["batchIndex"] ?? 0;
|
|
20
|
-
if (typeof batchIndex !== "number")
|
|
21
|
-
throw new Error("analysis-output-failed");
|
|
22
|
-
const previous = await previousCheckpoint(join(directory, `capture-${capture.key}`), {
|
|
23
|
-
capture,
|
|
24
|
-
batchIndex,
|
|
25
|
-
snapshot,
|
|
26
|
-
});
|
|
27
|
-
const prepared = prepareAnalysisBatch(snapshot, {
|
|
28
|
-
nextRecordIndex: previous.nextRecordIndex,
|
|
29
|
-
completedBatchCount: previous.completedBatchCount,
|
|
30
|
-
previousResult: previous.result,
|
|
31
|
-
});
|
|
32
|
-
if (prepared.kind === "refused")
|
|
33
|
-
throw new Error("analysis-output-failed");
|
|
34
|
-
if (input.snapshot !== undefined &&
|
|
35
|
-
JSON.stringify(input.batch === undefined ? snapshot : prepared.snapshot) !==
|
|
36
|
-
JSON.stringify(input.snapshot))
|
|
37
|
-
throw new Error("analysis-output-failed");
|
|
38
|
-
if (!matchingBatchBinding(input.batch, {
|
|
39
|
-
capturedDigest: capture.digest,
|
|
40
|
-
batchIndex,
|
|
41
|
-
nextRecordIndex: prepared.nextRecordIndex,
|
|
42
|
-
totalRecords: capture.totalRecords,
|
|
43
|
-
}))
|
|
44
|
-
throw new Error("analysis-output-failed");
|
|
45
|
-
return {
|
|
46
|
-
capture,
|
|
47
|
-
snapshot,
|
|
48
|
-
batch: { batchIndex, nextRecordIndex: prepared.nextRecordIndex },
|
|
49
|
-
previous,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function matchingBatchBinding(binding, expected) {
|
|
53
|
-
if (binding === undefined)
|
|
54
|
-
return expected.nextRecordIndex === expected.totalRecords;
|
|
55
|
-
const fields = record(binding);
|
|
56
|
-
return ["capturedDigest", "batchIndex", "nextRecordIndex"].every((name) => fields?.[name] === Reflect.get(expected, name));
|
|
57
|
-
}
|
|
58
|
-
export async function previousCheckpoint(folder, input) {
|
|
59
|
-
const { capture, batchIndex } = input;
|
|
60
|
-
if (!Number.isSafeInteger(batchIndex) || batchIndex < 0 || batchIndex > 3)
|
|
61
|
-
throw new Error("analysis-input-refused");
|
|
62
|
-
const initial = initialAnalysisCheckpoint(capture);
|
|
63
|
-
if (batchIndex === 0)
|
|
64
|
-
return initial;
|
|
65
|
-
const name = `analysis-checkpoint-${String(batchIndex)}.json`;
|
|
66
|
-
const text = await boundedAnalysisFile(join(folder, name), {
|
|
67
|
-
permissions: 0o600,
|
|
68
|
-
});
|
|
69
|
-
const checkpoint = restoreCheckpoint(text, input);
|
|
70
|
-
await inspectAnalysisFiles(folder, {
|
|
71
|
-
cycleId: `checkpoint-${String(batchIndex)}`,
|
|
72
|
-
analysis: JSON.stringify(checkpoint) + "\n",
|
|
73
|
-
proposal: checkpointProposal(checkpoint),
|
|
74
|
-
});
|
|
75
|
-
return checkpoint;
|
|
76
|
-
}
|
|
77
|
-
function restoreCheckpoint(text, input) {
|
|
78
|
-
const value = record(JSON.parse(text));
|
|
79
|
-
const result = record(value?.["result"]);
|
|
80
|
-
const nextRecordIndex = value?.["nextRecordIndex"];
|
|
81
|
-
if (result === undefined || typeof nextRecordIndex !== "number")
|
|
82
|
-
throw new Error("analysis-output-failed");
|
|
83
|
-
const merged = mergeAnalysisBatch({
|
|
84
|
-
previousResult: null,
|
|
85
|
-
candidate: Object.fromEntries(Object.entries(result).filter(([key]) => key !== "limitations")),
|
|
86
|
-
evidence: analysisEvidence(input.snapshot),
|
|
87
|
-
nextRecordIndex,
|
|
88
|
-
});
|
|
89
|
-
if (!merged.accepted)
|
|
90
|
-
throw new Error("analysis-output-failed");
|
|
91
|
-
const checkpoint = batchAnalysisCheckpoint(input.capture, {
|
|
92
|
-
batchIndex: input.batchIndex - 1,
|
|
93
|
-
nextRecordIndex,
|
|
94
|
-
result: merged.result,
|
|
95
|
-
});
|
|
96
|
-
if (text !== JSON.stringify(checkpoint) + "\n")
|
|
97
|
-
throw new Error("analysis-output-failed");
|
|
98
|
-
return checkpoint;
|
|
99
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type AnalysisSnapshot } from "../chats/analysis-input.ts";
|
|
2
|
-
export interface AnalysisCapture {
|
|
3
|
-
readonly schemaVersion: 1;
|
|
4
|
-
readonly key: string;
|
|
5
|
-
readonly runId: string;
|
|
6
|
-
readonly importId: string;
|
|
7
|
-
readonly digest: string;
|
|
8
|
-
readonly totalRecords: number;
|
|
9
|
-
}
|
|
10
|
-
export declare function captureAnalysisSnapshot(directory: string, binding: {
|
|
11
|
-
readonly runId: string;
|
|
12
|
-
readonly importId: string;
|
|
13
|
-
}): Promise<AnalysisCapture>;
|
|
14
|
-
export declare function findAnalysisCapture(directory: string, binding: {
|
|
15
|
-
readonly runId: string;
|
|
16
|
-
readonly importId: string;
|
|
17
|
-
}): Promise<AnalysisCapture | undefined>;
|
|
18
|
-
export declare function readCapturedAnalysisSnapshot(directory: string, capture: AnalysisCapture): Promise<AnalysisSnapshot>;
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { lstat, mkdtemp, readdir, rename, rm } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { record } from "../protocol.js";
|
|
5
|
-
import { analysisEvidence, validAnalysisImportId, } from "../chats/analysis-input.js";
|
|
6
|
-
import { validateDestination } from "../chats/destination.js";
|
|
7
|
-
import { initialAnalysisCheckpoint } from "../chats/analysis-checkpoint.js";
|
|
8
|
-
import { checkpointProposal } from "../chats/analysis-proposal.js";
|
|
9
|
-
import { boundedAnalysisFile, matchingPrivateFile, readAnalysisCorpus, readAnalysisSnapshot, } from "./chats-files.js";
|
|
10
|
-
export async function captureAnalysisSnapshot(directory, binding) {
|
|
11
|
-
const key = captureKey(binding);
|
|
12
|
-
const folder = join(directory, `capture-${key}`);
|
|
13
|
-
await validateDestination(directory);
|
|
14
|
-
await reclaimAbandonedCaptures(directory);
|
|
15
|
-
const existing = await findAnalysisCapture(directory, binding);
|
|
16
|
-
if (existing !== undefined)
|
|
17
|
-
return existing;
|
|
18
|
-
const temporary = await mkdtemp(join(directory, `.capture-${key}-${String(process.pid)}-`));
|
|
19
|
-
try {
|
|
20
|
-
const capture = await writeCapture(directory, {
|
|
21
|
-
...binding,
|
|
22
|
-
folder: temporary,
|
|
23
|
-
});
|
|
24
|
-
try {
|
|
25
|
-
await rename(temporary, folder);
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
if (!(error instanceof Error &&
|
|
29
|
-
"code" in error &&
|
|
30
|
-
(error.code === "EEXIST" || error.code === "ENOTEMPTY")))
|
|
31
|
-
throw error;
|
|
32
|
-
const published = await findAnalysisCapture(directory, binding);
|
|
33
|
-
if (published === undefined)
|
|
34
|
-
throw error;
|
|
35
|
-
return published;
|
|
36
|
-
}
|
|
37
|
-
return capture;
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
if (missingRedaction(error))
|
|
41
|
-
throw new Error("redaction-required", { cause: error });
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
finally {
|
|
45
|
-
await rm(temporary, { recursive: true, force: true });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function missingRedaction(error) {
|
|
49
|
-
if (!(error instanceof Error) ||
|
|
50
|
-
!("code" in error) ||
|
|
51
|
-
error.code !== "ENOENT" ||
|
|
52
|
-
!("path" in error) ||
|
|
53
|
-
typeof error.path !== "string")
|
|
54
|
-
return false;
|
|
55
|
-
return (error.path.endsWith("/redaction.json") ||
|
|
56
|
-
error.path.endsWith("/redacted.jsonl"));
|
|
57
|
-
}
|
|
58
|
-
async function reclaimAbandonedCaptures(directory) {
|
|
59
|
-
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
60
|
-
if (entry.isDirectory() && absentCaptureOwner(entry.name))
|
|
61
|
-
await rm(join(directory, entry.name), { recursive: true, force: true });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function absentCaptureOwner(name) {
|
|
65
|
-
const owner = /^\.capture-[a-f0-9]{64}-([1-9][0-9]*)-[A-Za-z0-9]{6}$/.exec(name)?.[1];
|
|
66
|
-
if (owner === undefined)
|
|
67
|
-
return false;
|
|
68
|
-
const processId = Number(owner);
|
|
69
|
-
if (!Number.isSafeInteger(processId))
|
|
70
|
-
return false;
|
|
71
|
-
try {
|
|
72
|
-
process.kill(processId, 0);
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
return error instanceof Error && "code" in error && error.code === "ESRCH";
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
export async function findAnalysisCapture(directory, binding) {
|
|
80
|
-
const folder = join(directory, `capture-${captureKey(binding)}`);
|
|
81
|
-
const stats = await lstat(folder).catch((error) => {
|
|
82
|
-
if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
|
|
83
|
-
throw error;
|
|
84
|
-
return undefined;
|
|
85
|
-
});
|
|
86
|
-
if (stats === undefined)
|
|
87
|
-
return undefined;
|
|
88
|
-
const capture = await capturedReference(folder, binding);
|
|
89
|
-
await readCapturedAnalysisSnapshot(directory, capture);
|
|
90
|
-
return capture;
|
|
91
|
-
}
|
|
92
|
-
async function writeCapture(directory, input) {
|
|
93
|
-
const snapshot = await copiedSnapshot(directory, {
|
|
94
|
-
folder: input.folder,
|
|
95
|
-
importId: input.importId,
|
|
96
|
-
});
|
|
97
|
-
const evidence = analysisEvidence(snapshot);
|
|
98
|
-
const capture = {
|
|
99
|
-
schemaVersion: 1,
|
|
100
|
-
key: captureKey(input),
|
|
101
|
-
runId: input.runId,
|
|
102
|
-
importId: input.importId,
|
|
103
|
-
digest: snapshotDigest(snapshot),
|
|
104
|
-
totalRecords: evidence.records.length,
|
|
105
|
-
};
|
|
106
|
-
await matchingPrivateFile(join(input.folder, "capture.json"), JSON.stringify(capture) + "\n");
|
|
107
|
-
await ensureInitialCheckpoint(input.folder, capture);
|
|
108
|
-
return capture;
|
|
109
|
-
}
|
|
110
|
-
export async function readCapturedAnalysisSnapshot(directory, capture) {
|
|
111
|
-
const key = captureKey(capture);
|
|
112
|
-
if (capture.key !== key)
|
|
113
|
-
throw new Error("analysis-input-refused");
|
|
114
|
-
const folder = join(directory, `capture-${key}`);
|
|
115
|
-
const stored = await capturedReference(folder, capture);
|
|
116
|
-
if (stored.digest !== capture.digest ||
|
|
117
|
-
stored.totalRecords !== capture.totalRecords ||
|
|
118
|
-
record(capture)?.["schemaVersion"] !== 1)
|
|
119
|
-
throw new Error("analysis-input-refused");
|
|
120
|
-
const snapshot = await readAnalysisSnapshot(folder, {
|
|
121
|
-
importId: capture.importId,
|
|
122
|
-
permissions: 0o600,
|
|
123
|
-
});
|
|
124
|
-
const evidence = analysisEvidence(snapshot);
|
|
125
|
-
if (snapshotDigest(snapshot) !== capture.digest ||
|
|
126
|
-
evidence.records.length !== capture.totalRecords)
|
|
127
|
-
throw new Error("analysis-input-refused");
|
|
128
|
-
await ensureInitialCheckpoint(folder, capture);
|
|
129
|
-
return snapshot;
|
|
130
|
-
}
|
|
131
|
-
async function ensureInitialCheckpoint(folder, capture) {
|
|
132
|
-
const checkpoint = initialAnalysisCheckpoint(capture);
|
|
133
|
-
for (const [name, expected] of [
|
|
134
|
-
["checkpoint-0.json", JSON.stringify(checkpoint) + "\n"],
|
|
135
|
-
["proposal-0.txt", checkpointProposal(checkpoint)],
|
|
136
|
-
]) {
|
|
137
|
-
await matchingPrivateFile(join(folder, name), expected);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function captureKey(binding) {
|
|
141
|
-
if (!validAnalysisImportId(binding.importId) ||
|
|
142
|
-
!/^[A-Za-z0-9_-]{1,128}$/.test(binding.runId))
|
|
143
|
-
throw new Error("analysis-input-refused");
|
|
144
|
-
return createHash("sha256")
|
|
145
|
-
.update(JSON.stringify([binding.runId, binding.importId]))
|
|
146
|
-
.digest("hex");
|
|
147
|
-
}
|
|
148
|
-
function snapshotDigest(snapshot) {
|
|
149
|
-
return createHash("sha256").update(JSON.stringify(snapshot)).digest("hex");
|
|
150
|
-
}
|
|
151
|
-
async function copiedSnapshot(directory, capture) {
|
|
152
|
-
const redaction = await boundedAnalysisFile(join(directory, "redaction.json"));
|
|
153
|
-
await matchingPrivateFile(join(capture.folder, "redaction.json"), redaction);
|
|
154
|
-
const corpus = await readAnalysisCorpus(join(directory, "redacted.jsonl"), {
|
|
155
|
-
output: join(capture.folder, "redacted.jsonl"),
|
|
156
|
-
});
|
|
157
|
-
const structure = await boundedAnalysisFile(join(directory, "structure.json"));
|
|
158
|
-
await matchingPrivateFile(join(capture.folder, "structure.json"), structure);
|
|
159
|
-
return { importId: capture.importId, redaction, corpus, structure };
|
|
160
|
-
}
|
|
161
|
-
async function capturedReference(folder, binding) {
|
|
162
|
-
await validateDestination(folder);
|
|
163
|
-
if (((await lstat(folder)).mode & 0o777) !== 0o700)
|
|
164
|
-
throw new Error("analysis-output-failed");
|
|
165
|
-
const value = record(JSON.parse(await boundedAnalysisFile(join(folder, "capture.json"), {
|
|
166
|
-
permissions: 0o600,
|
|
167
|
-
})));
|
|
168
|
-
const identity = {
|
|
169
|
-
schemaVersion: 1,
|
|
170
|
-
key: captureKey(binding),
|
|
171
|
-
runId: binding.runId,
|
|
172
|
-
importId: binding.importId,
|
|
173
|
-
};
|
|
174
|
-
if (value === undefined ||
|
|
175
|
-
Object.keys(value).length !== 6 ||
|
|
176
|
-
!Object.entries(identity).every(([key, expected]) => value[key] === expected))
|
|
177
|
-
throw new Error("analysis-input-refused");
|
|
178
|
-
const digest = value["digest"];
|
|
179
|
-
const totalRecords = value["totalRecords"];
|
|
180
|
-
if (typeof digest !== "string" ||
|
|
181
|
-
!/^[a-f0-9]{64}$/.test(digest) ||
|
|
182
|
-
typeof totalRecords !== "number" ||
|
|
183
|
-
!Number.isSafeInteger(totalRecords) ||
|
|
184
|
-
totalRecords < 0)
|
|
185
|
-
throw new Error("analysis-input-refused");
|
|
186
|
-
return {
|
|
187
|
-
schemaVersion: 1,
|
|
188
|
-
key: identity.key,
|
|
189
|
-
runId: binding.runId,
|
|
190
|
-
importId: binding.importId,
|
|
191
|
-
digest,
|
|
192
|
-
totalRecords,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { type AnalysisCheckpoint } from "../chats/analysis-checkpoint.ts";
|
|
2
|
-
import { type AnalysisSnapshot } from "../chats/analysis-input.ts";
|
|
3
|
-
import { type AnalysisBatchPreparation } from "../chats/analysis-batches.ts";
|
|
4
|
-
import { type AnalysisCapture } from "./chats-capture.ts";
|
|
5
|
-
import { type AnalysisDraftInput } from "./chats-files.ts";
|
|
6
|
-
interface CheckpointInput {
|
|
7
|
-
readonly capture: AnalysisCapture;
|
|
8
|
-
readonly candidate: unknown;
|
|
9
|
-
readonly batchIndex: number;
|
|
10
|
-
readonly nextRecordIndex: number;
|
|
11
|
-
readonly mode: "deliver" | "reconcile";
|
|
12
|
-
}
|
|
13
|
-
interface FinalizeInput {
|
|
14
|
-
readonly runId: string;
|
|
15
|
-
readonly importId: string;
|
|
16
|
-
readonly cycleId: string;
|
|
17
|
-
readonly snapshot: AnalysisSnapshot | undefined;
|
|
18
|
-
readonly candidate: unknown;
|
|
19
|
-
readonly mode: "deliver" | "reconcile";
|
|
20
|
-
readonly batch?: unknown;
|
|
21
|
-
readonly draft?: AnalysisDraftInput;
|
|
22
|
-
}
|
|
23
|
-
export declare function finalizeAnalysis(directory: string, input: FinalizeInput): Promise<(Awaited<ReturnType<typeof saveAnalysisCheckpoint>> & {
|
|
24
|
-
readonly next?: AnalysisBatchPreparation | undefined;
|
|
25
|
-
}) | {
|
|
26
|
-
readonly kind: "absent";
|
|
27
|
-
}>;
|
|
28
|
-
export declare function saveAnalysisCheckpoint(directory: string, input: CheckpointInput): Promise<{
|
|
29
|
-
kind: "committed" | "absent";
|
|
30
|
-
checkpoint: AnalysisCheckpoint & {
|
|
31
|
-
readonly result: import("../chats/analysis-contract.ts").AnalysisResult;
|
|
32
|
-
};
|
|
33
|
-
receipt: string;
|
|
34
|
-
} | {
|
|
35
|
-
kind: "refused";
|
|
36
|
-
codes: readonly import("../chats/analysis-merge.ts").AnalysisMergeCode[];
|
|
37
|
-
} | {
|
|
38
|
-
kind: "absent";
|
|
39
|
-
codes?: never;
|
|
40
|
-
}>;
|
|
41
|
-
export {};
|