@vercel/factory 0.0.14 → 0.0.16
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/CHANGELOG.md +356 -0
- package/README.md +96 -2
- package/dist/agent-routes.d.mts +113 -0
- package/dist/agent-routes.mjs +91 -0
- package/dist/agent-routes.mjs.map +1 -0
- package/dist/api-contracts.d.mts +1768 -0
- package/dist/api-contracts.mjs +119 -0
- package/dist/api-contracts.mjs.map +1 -0
- package/dist/api-images.d.mts +30 -0
- package/dist/api-images.mjs +28 -0
- package/dist/api-images.mjs.map +1 -0
- package/dist/api-task-graph.mjs +57 -0
- package/dist/api-task-graph.mjs.map +1 -0
- package/dist/api.d.mts +111 -216
- package/dist/api.mjs +1063 -99
- package/dist/api.mjs.map +1 -1
- package/dist/approval-access.d.mts +39 -0
- package/dist/approval-access.mjs +62 -0
- package/dist/approval-access.mjs.map +1 -0
- package/dist/approval-contracts.d.mts +698 -0
- package/dist/approval-contracts.mjs +27 -0
- package/dist/approval-contracts.mjs.map +1 -0
- package/dist/approval.d.mts +49 -0
- package/dist/approval.mjs +39 -0
- package/dist/approval.mjs.map +1 -0
- package/dist/blob/artifacts.d.mts +37 -0
- package/dist/blob/artifacts.mjs +45 -0
- package/dist/blob/artifacts.mjs.map +1 -0
- package/dist/blob/index.d.mts +84 -12
- package/dist/blob/index.mjs +179 -45
- package/dist/blob/index.mjs.map +1 -1
- package/dist/budget.d.mts +115 -0
- package/dist/budget.mjs +147 -0
- package/dist/budget.mjs.map +1 -0
- package/dist/budgets.d.mts +4 -0
- package/dist/budgets.mjs +4 -0
- package/dist/build-factory.d.mts +7 -4
- package/dist/build-factory.mjs +2 -1
- package/dist/build-factory.mjs.map +1 -1
- package/dist/change-verification/brief.d.mts +9 -0
- package/dist/change-verification/brief.mjs +13 -0
- package/dist/change-verification/brief.mjs.map +1 -0
- package/dist/change-verification/dispatch.d.mts +37 -0
- package/dist/change-verification/dispatch.mjs +83 -0
- package/dist/change-verification/dispatch.mjs.map +1 -0
- package/dist/change-verification/eve-tool.d.mts +61 -0
- package/dist/change-verification/eve-tool.mjs +89 -0
- package/dist/change-verification/eve-tool.mjs.map +1 -0
- package/dist/change-verification/result.mjs +130 -0
- package/dist/change-verification/result.mjs.map +1 -0
- package/dist/changes/eve-record-change.d.mts +56 -0
- package/dist/changes/eve-record-change.mjs +131 -0
- package/dist/changes/eve-record-change.mjs.map +1 -0
- package/dist/changes/presentation.d.mts +14 -0
- package/dist/changes.d.mts +24 -0
- package/dist/changes.mjs +29 -0
- package/dist/changes.mjs.map +1 -0
- package/dist/client-events.d.mts +25 -0
- package/dist/client-events.mjs +45 -0
- package/dist/client-events.mjs.map +1 -0
- package/dist/client-stream.d.mts +28 -0
- package/dist/client-stream.mjs +210 -0
- package/dist/client-stream.mjs.map +1 -0
- package/dist/client-transcript.d.mts +41 -0
- package/dist/client-transcript.mjs +233 -0
- package/dist/client-transcript.mjs.map +1 -0
- package/dist/client.d.mts +343 -0
- package/dist/client.mjs +366 -0
- package/dist/client.mjs.map +1 -0
- package/dist/code-review/contracts.d.mts +27 -0
- package/dist/code-review/eve-post-review.d.mts +70 -0
- package/dist/code-review/eve-post-review.mjs +195 -0
- package/dist/code-review/eve-post-review.mjs.map +1 -0
- package/dist/code-review/eve-review-comments.d.mts +75 -0
- package/dist/code-review/eve-review-comments.mjs +193 -0
- package/dist/code-review/eve-review-comments.mjs.map +1 -0
- package/dist/code-review/github-contracts.d.mts +10 -0
- package/dist/code-review/github-reporter.d.mts +46 -0
- package/dist/code-review/github-reporter.mjs +262 -0
- package/dist/code-review/github-reporter.mjs.map +1 -0
- package/dist/code-review/preparation.d.mts +34 -0
- package/dist/code-review/preparation.mjs +23 -0
- package/dist/code-review/preparation.mjs.map +1 -0
- package/dist/code-review/stall.d.mts +17 -0
- package/dist/code-review/stall.mjs +30 -0
- package/dist/code-review/stall.mjs.map +1 -0
- package/dist/code-review.d.mts +7 -0
- package/dist/code-review.mjs +5 -0
- package/dist/communication.d.mts +9 -0
- package/dist/communication.mjs +9 -0
- package/dist/connectors/github.d.mts +26 -0
- package/dist/connectors/github.mjs +55 -0
- package/dist/connectors/github.mjs.map +1 -0
- package/dist/connectors/index.d.mts +35 -3
- package/dist/connectors/index.mjs +3 -52
- package/dist/connectors/index.mjs.map +1 -1
- package/dist/connectors/outbox.d.mts +34 -0
- package/dist/connectors/outbox.mjs +50 -0
- package/dist/connectors/outbox.mjs.map +1 -0
- package/dist/connectors/slack-approval-blocks.mjs +136 -0
- package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
- package/dist/connectors/slack-approvals.d.mts +29 -0
- package/dist/connectors/slack-approvals.mjs +346 -0
- package/dist/connectors/slack-approvals.mjs.map +1 -0
- package/dist/connectors/slack.d.mts +35 -52
- package/dist/connectors/slack.mjs +13 -85
- package/dist/connectors/slack.mjs.map +1 -1
- package/dist/deepsec/eve-tool.d.mts +110 -0
- package/dist/deepsec/eve-tool.mjs +166 -0
- package/dist/deepsec/eve-tool.mjs.map +1 -0
- package/dist/deepsec/finding.d.mts +84 -0
- package/dist/deepsec/finding.mjs +56 -0
- package/dist/deepsec/finding.mjs.map +1 -0
- package/dist/deepsec.d.mts +3 -0
- package/dist/delivery-metrics/metrics.d.mts +93 -0
- package/dist/delivery-metrics/metrics.mjs +200 -0
- package/dist/delivery-metrics/metrics.mjs.map +1 -0
- package/dist/delivery-metrics.d.mts +2 -0
- package/dist/delivery-metrics.mjs +2 -0
- package/dist/dispatch.d.mts +152 -0
- package/dist/dispatch.mjs +199 -0
- package/dist/dispatch.mjs.map +1 -0
- package/dist/errors.d.mts +15 -0
- package/dist/errors.mjs +38 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/eve/index.d.mts +209 -1277
- package/dist/eve/index.mjs +312 -1073
- package/dist/eve/index.mjs.map +1 -1
- package/dist/eve/invoke.d.mts +144 -0
- package/dist/eve/invoke.mjs +254 -0
- package/dist/eve/invoke.mjs.map +1 -0
- package/dist/eve/session-client.d.mts +186 -0
- package/dist/eve/session-client.mjs +245 -0
- package/dist/eve/session-client.mjs.map +1 -0
- package/dist/eve/task-execution.d.mts +380 -0
- package/dist/eve/task-execution.mjs +73 -0
- package/dist/eve/task-execution.mjs.map +1 -0
- package/dist/eve/task-session.d.mts +129 -0
- package/dist/eve/task-session.mjs +245 -0
- package/dist/eve/task-session.mjs.map +1 -0
- package/dist/eve/transcript.d.mts +37 -0
- package/dist/eve/transcript.mjs +69 -0
- package/dist/eve/transcript.mjs.map +1 -0
- package/dist/execution-public.d.mts +8 -0
- package/dist/execution-public.mjs +7 -0
- package/dist/execution.d.mts +183 -0
- package/dist/execution.mjs +223 -0
- package/dist/execution.mjs.map +1 -0
- package/dist/finding-remediation/admission.d.mts +53 -0
- package/dist/finding-remediation/admission.mjs +90 -0
- package/dist/finding-remediation/admission.mjs.map +1 -0
- package/dist/finding-remediation/brief.d.mts +14 -0
- package/dist/finding-remediation/brief.mjs +25 -0
- package/dist/finding-remediation/brief.mjs.map +1 -0
- package/dist/finding-remediation/eve-tool.d.mts +29 -0
- package/dist/finding-remediation/eve-tool.mjs +34 -0
- package/dist/finding-remediation/eve-tool.mjs.map +1 -0
- package/dist/findings/fingerprint.d.mts +14 -0
- package/dist/findings/fingerprint.mjs +28 -0
- package/dist/findings/fingerprint.mjs.map +1 -0
- package/dist/findings.d.mts +7 -0
- package/dist/findings.mjs +6 -0
- package/dist/github-app.d.mts +54 -0
- package/dist/github-app.mjs +121 -0
- package/dist/github-app.mjs.map +1 -0
- package/dist/github-publication.d.mts +199 -0
- package/dist/github-publication.mjs +442 -0
- package/dist/github-publication.mjs.map +1 -0
- package/dist/github-transfer.d.mts +81 -0
- package/dist/github-transfer.mjs +273 -0
- package/dist/github-transfer.mjs.map +1 -0
- package/dist/github.d.mts +446 -2
- package/dist/github.mjs +357 -56
- package/dist/github.mjs.map +1 -1
- package/dist/image-input.d.mts +51 -0
- package/dist/image-input.mjs +63 -0
- package/dist/image-input.mjs.map +1 -0
- package/dist/inbox-activity.d.mts +53 -0
- package/dist/inbox-activity.mjs +41 -0
- package/dist/inbox-activity.mjs.map +1 -0
- package/dist/index.d.mts +16 -484
- package/dist/index.mjs +15 -522
- package/dist/intake-contracts.d.mts +55 -0
- package/dist/intake-contracts.mjs +33 -0
- package/dist/intake-contracts.mjs.map +1 -0
- package/dist/integrations/deepsec.d.mts +5 -0
- package/dist/integrations/deepsec.mjs +3 -0
- package/dist/integrations/github.d.mts +11 -0
- package/dist/integrations/github.mjs +9 -0
- package/dist/integrations/slack.d.mts +5 -0
- package/dist/integrations/slack.mjs +5 -0
- package/dist/integrations/vercel.d.mts +5 -0
- package/dist/integrations/vercel.mjs +4 -0
- package/dist/merge-resolution/contracts.d.mts +17 -0
- package/dist/merge-resolution/contracts.mjs +19 -0
- package/dist/merge-resolution/contracts.mjs.map +1 -0
- package/dist/merge-resolution/eve-tools.d.mts +47 -0
- package/dist/merge-resolution/eve-tools.mjs +122 -0
- package/dist/merge-resolution/eve-tools.mjs.map +1 -0
- package/dist/model-settings.d.mts +41 -0
- package/dist/model-settings.mjs +35 -0
- package/dist/model-settings.mjs.map +1 -0
- package/dist/multi-repository-changes/coordination.d.mts +49 -0
- package/dist/multi-repository-changes/coordination.mjs +115 -0
- package/dist/multi-repository-changes/coordination.mjs.map +1 -0
- package/dist/planning/cancellation.mjs +82 -0
- package/dist/planning/cancellation.mjs.map +1 -0
- package/dist/planning/configuration.d.mts +23 -0
- package/dist/planning/configuration.mjs +56 -0
- package/dist/planning/configuration.mjs.map +1 -0
- package/dist/planning/contracts.d.mts +136 -0
- package/dist/planning/contracts.mjs +42 -0
- package/dist/planning/contracts.mjs.map +1 -0
- package/dist/planning/dependencies.mjs +44 -0
- package/dist/planning/dependencies.mjs.map +1 -0
- package/dist/planning/effects.mjs +122 -0
- package/dist/planning/effects.mjs.map +1 -0
- package/dist/planning/reconcile.mjs +279 -0
- package/dist/planning/reconcile.mjs.map +1 -0
- package/dist/planning/runtime.d.mts +27 -0
- package/dist/planning/runtime.mjs +25 -0
- package/dist/planning/runtime.mjs.map +1 -0
- package/dist/planning/state.mjs +92 -0
- package/dist/planning/state.mjs.map +1 -0
- package/dist/planning/turns.mjs +262 -0
- package/dist/planning/turns.mjs.map +1 -0
- package/dist/planning/validation.mjs +106 -0
- package/dist/planning/validation.mjs.map +1 -0
- package/dist/postgres/index.d.mts +48 -1
- package/dist/postgres/index.mjs +45 -3
- package/dist/postgres/index.mjs.map +1 -1
- package/dist/presets/software-development/approval.d.mts +14 -0
- package/dist/presets/software-development/approval.mjs +21 -0
- package/dist/presets/software-development/approval.mjs.map +1 -0
- package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
- package/dist/presets/software-development/deepsec-brief.mjs +14 -0
- package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
- package/dist/presets/software-development/dispatch.d.mts +56 -0
- package/dist/presets/software-development/dispatch.mjs +67 -0
- package/dist/presets/software-development/dispatch.mjs.map +1 -0
- package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
- package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
- package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
- package/dist/presets/software-development/eve.d.mts +18 -0
- package/dist/presets/software-development/eve.mjs +19 -0
- package/dist/presets/software-development/eve.mjs.map +1 -0
- package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
- package/dist/presets/software-development/finish-task-policy.mjs +9 -0
- package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
- package/dist/presets/software-development/recovery.d.mts +32 -0
- package/dist/presets/software-development/recovery.mjs +120 -0
- package/dist/presets/software-development/recovery.mjs.map +1 -0
- package/dist/presets/software-development/task-communication.d.mts +24 -0
- package/dist/presets/software-development/task-communication.mjs +157 -0
- package/dist/presets/software-development/task-communication.mjs.map +1 -0
- package/dist/presets/software-development.d.mts +10 -0
- package/dist/presets/software-development.mjs +9 -0
- package/dist/pull-requests/contracts.d.mts +72 -0
- package/dist/pull-requests/eve-fetch.d.mts +57 -0
- package/dist/pull-requests/eve-fetch.mjs +151 -0
- package/dist/pull-requests/eve-fetch.mjs.map +1 -0
- package/dist/pull-requests/github-label-manager.d.mts +27 -0
- package/dist/pull-requests/github-label-manager.mjs +40 -0
- package/dist/pull-requests/github-label-manager.mjs.map +1 -0
- package/dist/pull-requests/github-publisher.d.mts +67 -0
- package/dist/pull-requests/github-publisher.mjs +405 -0
- package/dist/pull-requests/github-publisher.mjs.map +1 -0
- package/dist/pull-requests.d.mts +6 -0
- package/dist/pull-requests.mjs +4 -0
- package/dist/receipts.d.mts +4 -0
- package/dist/receipts.mjs +3 -0
- package/dist/repositories.d.mts +18 -0
- package/dist/repositories.mjs +33 -0
- package/dist/repositories.mjs.map +1 -0
- package/dist/sandbox/command.d.mts +18 -0
- package/dist/sandbox/execution-abort.d.mts +16 -0
- package/dist/sandbox/execution-abort.mjs +49 -0
- package/dist/sandbox/execution-abort.mjs.map +1 -0
- package/dist/sandbox/execution-environment.d.mts +25 -0
- package/dist/sandbox/execution-run-ledger.d.mts +115 -0
- package/dist/sandbox/execution-run-ledger.mjs +209 -0
- package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
- package/dist/sandbox/execution.d.mts +54 -0
- package/dist/sandbox/execution.mjs +228 -0
- package/dist/sandbox/execution.mjs.map +1 -0
- package/dist/sandbox/harness-runner.d.mts +79 -0
- package/dist/sandbox/harness-runner.mjs +162 -0
- package/dist/sandbox/harness-runner.mjs.map +1 -0
- package/dist/sandbox/index.d.mts +10 -0
- package/dist/sandbox/index.mjs +7 -0
- package/dist/sandbox/task-environment.d.mts +50 -0
- package/dist/sandbox/task-environment.mjs +140 -0
- package/dist/sandbox/task-environment.mjs.map +1 -0
- package/dist/sandbox/workspace.d.mts +29 -0
- package/dist/sandbox/workspace.mjs +28 -0
- package/dist/sandbox/workspace.mjs.map +1 -0
- package/dist/schema/agent-route.d.mts +40 -0
- package/dist/schema/agent-route.mjs +33 -0
- package/dist/schema/agent-route.mjs.map +1 -0
- package/dist/schema/answer.d.mts +23 -0
- package/dist/schema/answer.mjs +21 -0
- package/dist/schema/answer.mjs.map +1 -0
- package/dist/schema/budget.d.mts +38 -0
- package/dist/schema/budget.mjs +30 -0
- package/dist/schema/budget.mjs.map +1 -0
- package/dist/schema/catalog.mjs +72 -0
- package/dist/schema/catalog.mjs.map +1 -0
- package/dist/schema/change.d.mts +117 -0
- package/dist/schema/change.mjs +68 -0
- package/dist/schema/change.mjs.map +1 -0
- package/dist/schema/common.d.mts +33 -0
- package/dist/{id-BLIkCVue.mjs → schema/common.mjs} +7 -16
- package/dist/schema/common.mjs.map +1 -0
- package/dist/schema/communication.d.mts +52 -0
- package/dist/{communication-Kd9nU5RP.mjs → schema/communication.mjs} +8 -3
- package/dist/schema/communication.mjs.map +1 -0
- package/dist/schema/execution.d.mts +101 -0
- package/dist/schema/execution.mjs +86 -0
- package/dist/schema/execution.mjs.map +1 -0
- package/dist/schema/factory-config.d.mts +122 -0
- package/dist/schema/factory-config.mjs +90 -0
- package/dist/schema/factory-config.mjs.map +1 -0
- package/dist/schema/finding.d.mts +125 -0
- package/dist/schema/finding.mjs +67 -0
- package/dist/schema/finding.mjs.map +1 -0
- package/dist/schema/id.d.mts +43 -0
- package/dist/schema/id.mjs +32 -0
- package/dist/schema/id.mjs.map +1 -0
- package/dist/schema/outbox.d.mts +240 -0
- package/dist/schema/outbox.mjs +53 -0
- package/dist/schema/outbox.mjs.map +1 -0
- package/dist/schema/question-route.mjs +16 -0
- package/dist/schema/question-route.mjs.map +1 -0
- package/dist/schema/receipt.d.mts +81 -0
- package/dist/schema/receipt.mjs +94 -0
- package/dist/schema/receipt.mjs.map +1 -0
- package/dist/schema/repository.d.mts +30 -0
- package/dist/schema/repository.mjs +29 -0
- package/dist/schema/repository.mjs.map +1 -0
- package/dist/schema/session.d.mts +136 -0
- package/dist/schema/session.mjs +54 -0
- package/dist/schema/session.mjs.map +1 -0
- package/dist/schema/signal.d.mts +105 -0
- package/dist/schema/signal.mjs +81 -0
- package/dist/schema/signal.mjs.map +1 -0
- package/dist/schema/slack-pr-notifications.d.mts +12 -0
- package/dist/schema/slack-pr-notifications.mjs +11 -0
- package/dist/schema/slack-pr-notifications.mjs.map +1 -0
- package/dist/schema/stored-session.mjs +10 -0
- package/dist/schema/stored-session.mjs.map +1 -0
- package/dist/schema/stored-task.mjs +20 -0
- package/dist/schema/stored-task.mjs.map +1 -0
- package/dist/schema/task-effect.d.mts +39 -0
- package/dist/schema/task-effect.mjs +29 -0
- package/dist/schema/task-effect.mjs.map +1 -0
- package/dist/schema/task-graph.d.mts +3173 -0
- package/dist/schema/task-graph.mjs +97 -0
- package/dist/schema/task-graph.mjs.map +1 -0
- package/dist/schema/task-message.d.mts +254 -0
- package/dist/schema/task-message.mjs +189 -0
- package/dist/schema/task-message.mjs.map +1 -0
- package/dist/schema/task.d.mts +273 -0
- package/dist/schema/task.mjs +200 -0
- package/dist/schema/task.mjs.map +1 -0
- package/dist/schema/transcript.d.mts +176 -0
- package/dist/schema/transcript.mjs +87 -0
- package/dist/schema/transcript.mjs.map +1 -0
- package/dist/schema/transitions.d.mts +50 -0
- package/dist/schema/transitions.mjs +303 -0
- package/dist/schema/transitions.mjs.map +1 -0
- package/dist/schema/work.d.mts +150 -0
- package/dist/schema/work.mjs +102 -0
- package/dist/schema/work.mjs.map +1 -0
- package/dist/session-previews.d.mts +76 -0
- package/dist/session-previews.mjs +55 -0
- package/dist/session-previews.mjs.map +1 -0
- package/dist/session-review.d.mts +120 -0
- package/dist/session-review.mjs +79 -0
- package/dist/session-review.mjs.map +1 -0
- package/dist/signal-triage.d.mts +20 -0
- package/dist/signal-triage.mjs +85 -0
- package/dist/signal-triage.mjs.map +1 -0
- package/dist/signals.d.mts +20 -0
- package/dist/signals.mjs +19 -0
- package/dist/signals.mjs.map +1 -0
- package/dist/stall.d.mts +41 -0
- package/dist/stall.mjs +83 -0
- package/dist/stall.mjs.map +1 -0
- package/dist/storage.d.mts +4 -0
- package/dist/storage.mjs +4 -0
- package/dist/store/driver.d.mts +65 -0
- package/dist/store/driver.mjs +42 -0
- package/dist/store/driver.mjs.map +1 -0
- package/dist/store/engine.d.mts +683 -0
- package/dist/store/engine.mjs +2309 -0
- package/dist/store/engine.mjs.map +1 -0
- package/dist/store/memory.d.mts +24 -0
- package/dist/store/memory.mjs +69 -0
- package/dist/store/memory.mjs.map +1 -0
- package/dist/store/slack-pr-notifications.d.mts +44 -0
- package/dist/store/slack-pr-notifications.mjs +121 -0
- package/dist/store/slack-pr-notifications.mjs.map +1 -0
- package/dist/store/task-effects.d.mts +38 -0
- package/dist/store/task-effects.mjs +118 -0
- package/dist/store/task-effects.mjs.map +1 -0
- package/dist/store/task-graphs.d.mts +60 -0
- package/dist/store/task-graphs.mjs +212 -0
- package/dist/store/task-graphs.mjs.map +1 -0
- package/dist/store/task-messages.d.mts +136 -0
- package/dist/store/task-messages.mjs +475 -0
- package/dist/store/task-messages.mjs.map +1 -0
- package/dist/store/task-work.d.mts +180 -0
- package/dist/store/task-work.mjs +137 -0
- package/dist/store/task-work.mjs.map +1 -0
- package/dist/store/work-notifications.d.mts +19 -0
- package/dist/store/work-notifications.mjs +48 -0
- package/dist/store/work-notifications.mjs.map +1 -0
- package/dist/sweep.d.mts +79 -0
- package/dist/sweep.mjs +171 -0
- package/dist/sweep.mjs.map +1 -0
- package/dist/task-communication.d.mts +35 -0
- package/dist/task-communication.mjs +47 -0
- package/dist/task-communication.mjs.map +1 -0
- package/dist/task-graph-view.d.mts +267 -0
- package/dist/task-graph-view.mjs +17 -0
- package/dist/task-graph-view.mjs.map +1 -0
- package/dist/task-message-processing.d.mts +60 -0
- package/dist/task-message-processing.mjs +200 -0
- package/dist/task-message-processing.mjs.map +1 -0
- package/dist/task-protocols.d.mts +80 -0
- package/dist/task-protocols.mjs +47 -0
- package/dist/task-protocols.mjs.map +1 -0
- package/dist/tasks.d.mts +17 -0
- package/dist/tasks.mjs +17 -0
- package/dist/vercel-git.d.mts +53 -0
- package/dist/vercel-git.mjs +344 -0
- package/dist/vercel-git.mjs.map +1 -0
- package/dist/vercel-github-api.d.mts +103 -0
- package/dist/vercel-github-api.mjs +363 -0
- package/dist/vercel-github-api.mjs.map +1 -0
- package/dist/vercel.d.mts +34 -2
- package/dist/vercel.mjs +49 -3
- package/dist/vercel.mjs.map +1 -1
- package/dist/work-triage/eve-tool.d.mts +29 -0
- package/dist/work-triage/eve-tool.mjs +32 -0
- package/dist/work-triage/eve-tool.mjs.map +1 -0
- package/dist/work-triage/find-existing-work.d.mts +32 -0
- package/dist/work-triage/find-existing-work.mjs +31 -0
- package/dist/work-triage/find-existing-work.mjs.map +1 -0
- package/dist/work-triage/github.d.mts +15 -0
- package/dist/work-triage/github.mjs +14 -0
- package/dist/work-triage/github.mjs.map +1 -0
- package/dist/work-triage.d.mts +4 -0
- package/dist/work-triage.mjs +3 -0
- package/dist/workflows.d.mts +146 -0
- package/dist/workflows.mjs +139 -0
- package/dist/workflows.mjs.map +1 -0
- package/dist/workspace-diff-assembly.d.mts +33 -0
- package/dist/workspace-diff-assembly.mjs +95 -0
- package/dist/workspace-diff-assembly.mjs.map +1 -0
- package/dist/workspace-diff.d.mts +90 -0
- package/dist/workspace-diff.mjs +61 -0
- package/dist/workspace-diff.mjs.map +1 -0
- package/dist/workspace-files-git.d.mts +15 -0
- package/dist/workspace-files-git.mjs +61 -0
- package/dist/workspace-files-git.mjs.map +1 -0
- package/dist/workspace-files.d.mts +107 -0
- package/dist/workspace-files.mjs +74 -0
- package/dist/workspace-files.mjs.map +1 -0
- package/dist/workspace-snapshot.d.mts +26 -0
- package/dist/workspace-snapshot.mjs +80 -0
- package/dist/workspace-snapshot.mjs.map +1 -0
- package/docs/getting-started.md +104 -0
- package/docs/index.md +100 -0
- package/docs/recipes/cancellation.md +215 -0
- package/docs/recipes/custom-workflow.md +153 -0
- package/docs/recipes/dependent-tasks.md +207 -0
- package/docs/recipes/eve-agent.md +277 -0
- package/docs/recipes/human-input.md +204 -0
- package/docs/recipes/persistence-recovery.md +268 -0
- package/docs/recipes/retry-recovery.md +241 -0
- package/docs/recipes/task-messaging.md +215 -0
- package/docs/recipes/typed-eve-result.md +161 -0
- package/docs/runtime-integration.md +137 -0
- package/package.json +142 -46
- package/dist/approval-JX2Px9IC.mjs +0 -132
- package/dist/approval-JX2Px9IC.mjs.map +0 -1
- package/dist/budget-DzSiIA4t.mjs +0 -42
- package/dist/budget-DzSiIA4t.mjs.map +0 -1
- package/dist/change-D2U6v7Ek.mjs +0 -554
- package/dist/change-D2U6v7Ek.mjs.map +0 -1
- package/dist/communication-Kd9nU5RP.mjs.map +0 -1
- package/dist/coordination-Cq08hb1l.mjs +0 -76
- package/dist/coordination-Cq08hb1l.mjs.map +0 -1
- package/dist/dispatch-BaZS3PT8.d.mts +0 -76
- package/dist/driver-BC0Mt5KG.d.mts +0 -34
- package/dist/driver-Bbd25rNM.mjs +0 -23
- package/dist/driver-Bbd25rNM.mjs.map +0 -1
- package/dist/engine-DFHU2Pe-.d.mts +0 -781
- package/dist/engine-WaUM2cGA.mjs +0 -1068
- package/dist/engine-WaUM2cGA.mjs.map +0 -1
- package/dist/factory-config-BoRXOw43.mjs +0 -50
- package/dist/factory-config-BoRXOw43.mjs.map +0 -1
- package/dist/factory-config-D2yU3G0c.d.mts +0 -58
- package/dist/github-C5HNBN6p.d.mts +0 -279
- package/dist/id-BLIkCVue.mjs.map +0 -1
- package/dist/index-Bw6hggoH.d.mts +0 -40
- package/dist/index.mjs.map +0 -1
- package/dist/task-CcOyOJ3k.mjs +0 -154
- package/dist/task-CcOyOJ3k.mjs.map +0 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { codingExecutionRequestSchema, executionArtifactSchema, executionLaunchKeySchema, executionResultSchema, taskAttemptRef, taskAttemptRefFromTask, taskAttemptRefSchema } from "./schema/execution.mjs";
|
|
2
|
+
import { BudgetExhaustedError, DEFAULT_MAX_LAUNCH_ATTEMPTS, DispatchRefusedError, ExecutionLaunchPendingError, dispatchTask } from "./dispatch.mjs";
|
|
3
|
+
import { workNotificationSchema } from "./store/work-notifications.mjs";
|
|
4
|
+
import { ExecutionFenceError, cancelExecution, executionLaunchKey, inspectExecution, launchExecution, recordExecutionUsage } from "./execution.mjs";
|
|
5
|
+
import { sweepQueued } from "./sweep.mjs";
|
|
6
|
+
import { stallWindowMinutes, sweepTaskStalls } from "./stall.mjs";
|
|
7
|
+
export { BudgetExhaustedError, DEFAULT_MAX_LAUNCH_ATTEMPTS, DispatchRefusedError, ExecutionFenceError, ExecutionLaunchPendingError, cancelExecution, codingExecutionRequestSchema, dispatchTask, executionArtifactSchema, executionLaunchKey, executionLaunchKeySchema, executionResultSchema, inspectExecution, launchExecution, recordExecutionUsage, stallWindowMinutes, sweepQueued, sweepTaskStalls, taskAttemptRef, taskAttemptRefFromTask, taskAttemptRefSchema, workNotificationSchema };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { ExecutionReference, Task } from "./schema/task.mjs";
|
|
2
|
+
import { CodingExecutionRequest, ExecutionLaunchKey, ExecutionResult, TaskAttemptRef } from "./schema/execution.mjs";
|
|
3
|
+
import { FactoryStores } from "./store/engine.mjs";
|
|
4
|
+
//#region src/execution.d.ts
|
|
5
|
+
/** Validated request and stable idempotency key passed to an execution provider. */
|
|
6
|
+
interface StartExecutionInput {
|
|
7
|
+
/** Exact Task-attempt request validated before the provider is called. */
|
|
8
|
+
readonly request: CodingExecutionRequest;
|
|
9
|
+
/** Stable key that must identify the same provider launch across retries and process restarts. */
|
|
10
|
+
readonly launchKey: ExecutionLaunchKey;
|
|
11
|
+
}
|
|
12
|
+
/** Current provider state when inspecting one recorded execution. */
|
|
13
|
+
type ExecutionInspectionResult = {
|
|
14
|
+
/** The recorded execution still exists and is safe for the workflow to reattach. */
|
|
15
|
+
status: "active";
|
|
16
|
+
} | {
|
|
17
|
+
/** The provider can no longer inspect or reattach the recorded execution. */
|
|
18
|
+
status: "expired";
|
|
19
|
+
} | {
|
|
20
|
+
/** The provider has immutable final evidence for the recorded execution. */
|
|
21
|
+
status: "finished";
|
|
22
|
+
result: ExecutionResult;
|
|
23
|
+
};
|
|
24
|
+
/** Provider-neutral boundary for retry-safe execution start, inspection, and cancellation. */
|
|
25
|
+
interface ExecutionAdapter {
|
|
26
|
+
/**
|
|
27
|
+
* Starts or recovers one launch by its stable key. Return only after provider acceptance is
|
|
28
|
+
* known. Throw `ExecutionLaunchPendingError` when acceptance is ambiguous; every other rejection
|
|
29
|
+
* promises that this call did not leave an untracked launch.
|
|
30
|
+
*
|
|
31
|
+
* @param input - Validated provider request and stable launch key.
|
|
32
|
+
* @returns The accepted execution reference for this logical launch.
|
|
33
|
+
*/
|
|
34
|
+
start(input: StartExecutionInput): Promise<ExecutionReference>;
|
|
35
|
+
/**
|
|
36
|
+
* Observes one exact provider handle without starting replacement work. Only `active` confirms
|
|
37
|
+
* that reattachment is safe; `expired` and `finished` require workflow-owned reconciliation.
|
|
38
|
+
*
|
|
39
|
+
* @param execution - Exact provider handle previously recorded on the Task.
|
|
40
|
+
* @returns Current provider state and final result when finished.
|
|
41
|
+
*/
|
|
42
|
+
inspect(execution: ExecutionReference): Promise<ExecutionInspectionResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Idempotently requests a stop and returns the provider's final observed result and usage. An
|
|
45
|
+
* adapter may report cancellation even when immediate interruption is unsupported; callers that
|
|
46
|
+
* require proof of inactivity must use provider-specific confirmation.
|
|
47
|
+
*
|
|
48
|
+
* @param execution - Exact provider handle to stop or confirm inactive.
|
|
49
|
+
* @returns Immutable final result and usage for that execution.
|
|
50
|
+
*/
|
|
51
|
+
stop(execution: ExecutionReference): Promise<ExecutionResult>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Error raised when an execution no longer matches the current running Task attempt.
|
|
55
|
+
* Reread the Task and discard the stale observation; do not apply it to the replacement attempt.
|
|
56
|
+
*/
|
|
57
|
+
declare class ExecutionFenceError extends Error {}
|
|
58
|
+
/** Store capabilities required to launch or reattach a coding execution. */
|
|
59
|
+
type LaunchExecutionStores = Pick<FactoryStores, "repositories" | "tasks">;
|
|
60
|
+
/** Store capabilities required to inspect a coding execution. */
|
|
61
|
+
type InspectExecutionStores = Pick<FactoryStores, "tasks">;
|
|
62
|
+
/** Store capabilities required to persist final execution usage. */
|
|
63
|
+
type RecordExecutionUsageStores = Pick<FactoryStores, "receipts" | "tasks">;
|
|
64
|
+
/** Store capabilities required to cancel and settle a coding execution. */
|
|
65
|
+
type CancelExecutionStores = RecordExecutionUsageStores;
|
|
66
|
+
/**
|
|
67
|
+
* Constructs the stable provider idempotency key for one exact Task attempt.
|
|
68
|
+
* Persist or deterministically recreate this key across launch recovery; a new attempt gets a new key.
|
|
69
|
+
*/
|
|
70
|
+
declare function executionLaunchKey(ref: TaskAttemptRef): ExecutionLaunchKey;
|
|
71
|
+
/** Dependencies and request used to start or reattach one coding execution. */
|
|
72
|
+
interface LaunchExecutionOptions {
|
|
73
|
+
/** Task and repository reads plus the durable execution-binding write. */
|
|
74
|
+
readonly stores: LaunchExecutionStores;
|
|
75
|
+
/** Exact running Task attempt and single repository supplied to the provider. */
|
|
76
|
+
readonly request: CodingExecutionRequest;
|
|
77
|
+
/** Provider boundary responsible for idempotent start and exact-handle inspection. */
|
|
78
|
+
readonly adapter: ExecutionAdapter;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Starts or reattaches one coding execution after dispatch has admitted its Task.
|
|
82
|
+
*
|
|
83
|
+
* @remarks
|
|
84
|
+
* The Task must still be `running` on the requested attempt and name exactly one enabled matching
|
|
85
|
+
* repository. If an execution is already recorded, this method inspects it and returns it only
|
|
86
|
+
* when the provider confirms it is active; it never starts an implicit replacement for a finished
|
|
87
|
+
* or expired handle.
|
|
88
|
+
*
|
|
89
|
+
* For a new launch, the adapter receives a stable key derived from the Task attempt. The method
|
|
90
|
+
* returns only after the provider reference is durably bound to that attempt. If acceptance or
|
|
91
|
+
* the binding write is ambiguous, it throws `ExecutionLaunchPendingError`; retry this operation
|
|
92
|
+
* with the same request so the same key can recover the launch. Reread the Task before applying
|
|
93
|
+
* any other error, because a concurrent writer may have replaced the attempt.
|
|
94
|
+
*
|
|
95
|
+
* @param options - Validated request, required stores, and provider adapter.
|
|
96
|
+
* @returns The recorded provider execution for the current running attempt.
|
|
97
|
+
* @throws `ExecutionFenceError` when Task attempt or execution ownership changes.
|
|
98
|
+
* @throws `ExecutionLaunchPendingError` when provider acceptance or durable binding is ambiguous.
|
|
99
|
+
*/
|
|
100
|
+
declare function launchExecution(options: LaunchExecutionOptions): Promise<ExecutionReference>;
|
|
101
|
+
/** Dependencies and Task-attempt identity used to inspect one execution. */
|
|
102
|
+
interface InspectExecutionOptions {
|
|
103
|
+
/** Task read used to establish and recheck the execution fence. */
|
|
104
|
+
readonly stores: InspectExecutionStores;
|
|
105
|
+
/** Exact running Task attempt whose recorded execution may be inspected. */
|
|
106
|
+
readonly task: TaskAttemptRef;
|
|
107
|
+
/** Provider boundary used only for observation. */
|
|
108
|
+
readonly adapter: ExecutionAdapter;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Inspects a recorded execution without granting provider evidence lifecycle authority.
|
|
112
|
+
*
|
|
113
|
+
* @remarks
|
|
114
|
+
* The Task must be running on the exact attempt and have a recorded execution. Ownership is
|
|
115
|
+
* checked again after the provider call so a concurrent replacement cannot attach stale results.
|
|
116
|
+
* Finished results are schema-validated and must identify that same execution. This method writes
|
|
117
|
+
* no Task state or usage; the workflow decides how to validate evidence and transition afterward.
|
|
118
|
+
*
|
|
119
|
+
* @param options - Exact Task attempt, Task store, and provider adapter.
|
|
120
|
+
* @returns Current provider state and a validated result when finished.
|
|
121
|
+
* @throws `ExecutionFenceError` when the attempt or execution changes during inspection.
|
|
122
|
+
*/
|
|
123
|
+
declare function inspectExecution(options: InspectExecutionOptions): Promise<ExecutionInspectionResult>;
|
|
124
|
+
/** Dependencies, Task-attempt identity, and provider result used to record usage. */
|
|
125
|
+
interface RecordExecutionUsageOptions {
|
|
126
|
+
/** Receipt and Task stores used for idempotent usage persistence. */
|
|
127
|
+
readonly stores: RecordExecutionUsageStores;
|
|
128
|
+
/** Exact Task attempt that owns the provider result. */
|
|
129
|
+
readonly task: TaskAttemptRef;
|
|
130
|
+
/** Final provider result whose execution must match the Task's recorded handle. */
|
|
131
|
+
readonly result: ExecutionResult;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Records one adapter's immutable final usage packet without changing Task lifecycle state.
|
|
135
|
+
*
|
|
136
|
+
* @remarks
|
|
137
|
+
* Known cost is delegated to the Task usage store under a deterministic turn key, making identical
|
|
138
|
+
* replay non-charging. This API records an immutable final usage packet; an adapter must not also
|
|
139
|
+
* report the same charges through per-step usage hooks, because those observations use independent
|
|
140
|
+
* idempotency keys and would be added twice. When cost is unknown, an idempotent `usage_unresolved`
|
|
141
|
+
* receipt is appended and the Task remains unsettled so its reservation is retained. The workflow
|
|
142
|
+
* or reconciler must later supply measured usage before settlement.
|
|
143
|
+
*
|
|
144
|
+
* @param options - Exact Task attempt, final provider result, and persistence stores.
|
|
145
|
+
* @returns The Task after usage persistence, or unchanged after unresolved-cost evidence.
|
|
146
|
+
* @throws `ExecutionFenceError` when the result belongs to another attempt or execution.
|
|
147
|
+
*/
|
|
148
|
+
declare function recordExecutionUsage(options: RecordExecutionUsageOptions): Promise<Task>;
|
|
149
|
+
/** Dependencies and reason used to cancel one exact Task execution attempt. */
|
|
150
|
+
interface CancelExecutionOptions {
|
|
151
|
+
/** Task and receipt stores used for cancellation, usage, and settlement. */
|
|
152
|
+
readonly stores: CancelExecutionStores;
|
|
153
|
+
/** Exact attempt to cancel; replacement attempts are refused. */
|
|
154
|
+
readonly task: TaskAttemptRef;
|
|
155
|
+
/** Provider boundary used to request an idempotent stop and read its final observed result. */
|
|
156
|
+
readonly adapter: ExecutionAdapter;
|
|
157
|
+
/** Human-readable cancellation reason retained in lifecycle evidence. */
|
|
158
|
+
readonly reason: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Cancels canonical Task work, then interrupts and settles its exact provider execution.
|
|
162
|
+
*
|
|
163
|
+
* @remarks
|
|
164
|
+
* The Task first durably enters `cancelled`, preventing later workflow completion from winning.
|
|
165
|
+
* Provider interruption happens afterward and cannot roll that transition back. An absent recorded
|
|
166
|
+
* execution produces durable `cancellation_unresolved` evidence and throws. Since execution
|
|
167
|
+
* binding accepts only running Tasks, a handle discovered after this point cannot be attached by
|
|
168
|
+
* retrying this helper; application-owned reconciliation must stop that handle and persist its
|
|
169
|
+
* cleanup evidence and measured settlement separately. If `adapter.stop` fails ambiguously, retry
|
|
170
|
+
* this same call—the cancelled transition and adapter stop are both expected to be idempotent.
|
|
171
|
+
*
|
|
172
|
+
* Returned final usage is recorded once. Known cost then settles the Task; unknown cost retains the
|
|
173
|
+
* reservation and leaves reconciliation evidence for later measurement.
|
|
174
|
+
*
|
|
175
|
+
* @param options - Exact Task attempt, cancellation reason, stores, and provider adapter.
|
|
176
|
+
* @returns The cancelled Task after provider usage recording and any possible settlement.
|
|
177
|
+
* @throws `ExecutionFenceError` when the attempt has been replaced.
|
|
178
|
+
* @throws When execution discovery is unresolved or the provider stop request fails.
|
|
179
|
+
*/
|
|
180
|
+
declare function cancelExecution(options: CancelExecutionOptions): Promise<Task>;
|
|
181
|
+
//#endregion
|
|
182
|
+
export { CancelExecutionOptions, CancelExecutionStores, ExecutionAdapter, ExecutionFenceError, ExecutionInspectionResult, InspectExecutionOptions, InspectExecutionStores, LaunchExecutionOptions, LaunchExecutionStores, RecordExecutionUsageOptions, RecordExecutionUsageStores, StartExecutionInput, cancelExecution, executionLaunchKey, inspectExecution, launchExecution, recordExecutionUsage };
|
|
183
|
+
//# sourceMappingURL=execution.d.mts.map
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { executionReferenceSchema } from "./schema/task.mjs";
|
|
2
|
+
import { codingExecutionRequestSchema, executionLaunchKeySchema, executionResultSchema, taskAttemptRefSchema } from "./schema/execution.mjs";
|
|
3
|
+
import { ExecutionLaunchPendingError } from "./dispatch.mjs";
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
|
+
//#region src/execution.ts
|
|
6
|
+
/**
|
|
7
|
+
* Error raised when an execution no longer matches the current running Task attempt.
|
|
8
|
+
* Reread the Task and discard the stale observation; do not apply it to the replacement attempt.
|
|
9
|
+
*/
|
|
10
|
+
var ExecutionFenceError = class extends Error {};
|
|
11
|
+
function sameExecution(left, right) {
|
|
12
|
+
return isDeepStrictEqual(left === void 0 ? void 0 : JSON.parse(JSON.stringify(left)), right === void 0 ? void 0 : JSON.parse(JSON.stringify(right)));
|
|
13
|
+
}
|
|
14
|
+
async function currentAttempt(stores, ref) {
|
|
15
|
+
const { taskId, attempt } = taskAttemptRefSchema.parse(ref);
|
|
16
|
+
const task = await stores.tasks.get(taskId);
|
|
17
|
+
if (!task || task.attempt !== attempt || task.state !== "running") throw new ExecutionFenceError(`Execution requires running Task ${taskId} at attempt ${attempt}`);
|
|
18
|
+
return task;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Constructs the stable provider idempotency key for one exact Task attempt.
|
|
22
|
+
* Persist or deterministically recreate this key across launch recovery; a new attempt gets a new key.
|
|
23
|
+
*/
|
|
24
|
+
function executionLaunchKey(ref) {
|
|
25
|
+
const { taskId, attempt } = taskAttemptRefSchema.parse(ref);
|
|
26
|
+
return executionLaunchKeySchema.parse(`factory-task:${taskId}:${attempt}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Starts or reattaches one coding execution after dispatch has admitted its Task.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* The Task must still be `running` on the requested attempt and name exactly one enabled matching
|
|
33
|
+
* repository. If an execution is already recorded, this method inspects it and returns it only
|
|
34
|
+
* when the provider confirms it is active; it never starts an implicit replacement for a finished
|
|
35
|
+
* or expired handle.
|
|
36
|
+
*
|
|
37
|
+
* For a new launch, the adapter receives a stable key derived from the Task attempt. The method
|
|
38
|
+
* returns only after the provider reference is durably bound to that attempt. If acceptance or
|
|
39
|
+
* the binding write is ambiguous, it throws `ExecutionLaunchPendingError`; retry this operation
|
|
40
|
+
* with the same request so the same key can recover the launch. Reread the Task before applying
|
|
41
|
+
* any other error, because a concurrent writer may have replaced the attempt.
|
|
42
|
+
*
|
|
43
|
+
* @param options - Validated request, required stores, and provider adapter.
|
|
44
|
+
* @returns The recorded provider execution for the current running attempt.
|
|
45
|
+
* @throws `ExecutionFenceError` when Task attempt or execution ownership changes.
|
|
46
|
+
* @throws `ExecutionLaunchPendingError` when provider acceptance or durable binding is ambiguous.
|
|
47
|
+
*/
|
|
48
|
+
async function launchExecution(options) {
|
|
49
|
+
const { stores, adapter } = options;
|
|
50
|
+
const request = codingExecutionRequestSchema.parse(options.request);
|
|
51
|
+
const ref = {
|
|
52
|
+
taskId: request.taskId,
|
|
53
|
+
attempt: request.attempt
|
|
54
|
+
};
|
|
55
|
+
const task = await currentAttempt(stores, ref);
|
|
56
|
+
if (task.repositoryIds.length !== 1) throw new Error("Execution requires exactly one repository");
|
|
57
|
+
const repository = await stores.repositories.get(task.repositoryIds[0]);
|
|
58
|
+
if (!repository?.enabled || repository.slug !== request.repository.slug) throw new Error("Execution repository must match the Task's enabled repository");
|
|
59
|
+
if (task.execution) {
|
|
60
|
+
const observed = await adapter.inspect(task.execution);
|
|
61
|
+
if (!sameExecution((await currentAttempt(stores, ref)).execution, task.execution)) throw new ExecutionFenceError("Execution changed during reattachment");
|
|
62
|
+
if (observed.status !== "active") throw new Error(`Execution is ${observed.status}; workflow must reconcile its outcome before continuing`);
|
|
63
|
+
return task.execution;
|
|
64
|
+
}
|
|
65
|
+
const execution = executionReferenceSchema.parse(await adapter.start({
|
|
66
|
+
request,
|
|
67
|
+
launchKey: executionLaunchKey(ref)
|
|
68
|
+
}));
|
|
69
|
+
try {
|
|
70
|
+
await stores.tasks.recordExecution(task.id, {
|
|
71
|
+
execution,
|
|
72
|
+
expectAttempt: task.attempt
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
let current;
|
|
76
|
+
try {
|
|
77
|
+
current = await stores.tasks.get(task.id);
|
|
78
|
+
} catch (cause) {
|
|
79
|
+
throw new ExecutionLaunchPendingError("Execution binding requires recovery with its original key", { cause });
|
|
80
|
+
}
|
|
81
|
+
if (!current || current.attempt !== task.attempt || current.state !== "running" || current.execution && !sameExecution(current.execution, execution)) {
|
|
82
|
+
await adapter.stop(execution);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
throw new ExecutionLaunchPendingError("Execution binding requires recovery with its original key", { cause: error });
|
|
86
|
+
}
|
|
87
|
+
return execution;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Inspects a recorded execution without granting provider evidence lifecycle authority.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* The Task must be running on the exact attempt and have a recorded execution. Ownership is
|
|
94
|
+
* checked again after the provider call so a concurrent replacement cannot attach stale results.
|
|
95
|
+
* Finished results are schema-validated and must identify that same execution. This method writes
|
|
96
|
+
* no Task state or usage; the workflow decides how to validate evidence and transition afterward.
|
|
97
|
+
*
|
|
98
|
+
* @param options - Exact Task attempt, Task store, and provider adapter.
|
|
99
|
+
* @returns Current provider state and a validated result when finished.
|
|
100
|
+
* @throws `ExecutionFenceError` when the attempt or execution changes during inspection.
|
|
101
|
+
*/
|
|
102
|
+
async function inspectExecution(options) {
|
|
103
|
+
const { stores, adapter } = options;
|
|
104
|
+
const task = await currentAttempt(stores, options.task);
|
|
105
|
+
if (!task.execution) throw new Error(`Task ${options.task.taskId} has no recorded execution`);
|
|
106
|
+
const observed = await adapter.inspect(task.execution);
|
|
107
|
+
if (!sameExecution((await currentAttempt(stores, options.task)).execution, task.execution)) throw new ExecutionFenceError("Execution changed during inspection");
|
|
108
|
+
if (observed.status !== "finished") return observed;
|
|
109
|
+
const result = executionResultSchema.parse(observed.result);
|
|
110
|
+
if (!sameExecution(result.execution, task.execution)) throw new ExecutionFenceError("Result belongs to another execution");
|
|
111
|
+
return {
|
|
112
|
+
status: "finished",
|
|
113
|
+
result
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Records one adapter's immutable final usage packet without changing Task lifecycle state.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* Known cost is delegated to the Task usage store under a deterministic turn key, making identical
|
|
121
|
+
* replay non-charging. This API records an immutable final usage packet; an adapter must not also
|
|
122
|
+
* report the same charges through per-step usage hooks, because those observations use independent
|
|
123
|
+
* idempotency keys and would be added twice. When cost is unknown, an idempotent `usage_unresolved`
|
|
124
|
+
* receipt is appended and the Task remains unsettled so its reservation is retained. The workflow
|
|
125
|
+
* or reconciler must later supply measured usage before settlement.
|
|
126
|
+
*
|
|
127
|
+
* @param options - Exact Task attempt, final provider result, and persistence stores.
|
|
128
|
+
* @returns The Task after usage persistence, or unchanged after unresolved-cost evidence.
|
|
129
|
+
* @throws `ExecutionFenceError` when the result belongs to another attempt or execution.
|
|
130
|
+
*/
|
|
131
|
+
async function recordExecutionUsage(options) {
|
|
132
|
+
const { stores } = options;
|
|
133
|
+
const { taskId, attempt } = taskAttemptRefSchema.parse(options.task);
|
|
134
|
+
const result = executionResultSchema.parse(options.result);
|
|
135
|
+
const task = await stores.tasks.get(taskId);
|
|
136
|
+
if (!task || task.attempt !== attempt || !sameExecution(task.execution, result.execution)) throw new ExecutionFenceError("Usage belongs to a different Task attempt or execution");
|
|
137
|
+
if (result.usage.costUsd === void 0) {
|
|
138
|
+
await stores.receipts.append({
|
|
139
|
+
taskId,
|
|
140
|
+
repositoryIds: task.repositoryIds,
|
|
141
|
+
kind: task.kind,
|
|
142
|
+
state: "usage_unresolved",
|
|
143
|
+
phase: "budget",
|
|
144
|
+
attempt,
|
|
145
|
+
execution: result.execution,
|
|
146
|
+
reason: "Execution cost is unknown; retain the reservation until measured usage is available",
|
|
147
|
+
dedupeKey: `execution:${taskId}:${attempt}:usage-unresolved`
|
|
148
|
+
});
|
|
149
|
+
return task;
|
|
150
|
+
}
|
|
151
|
+
return stores.tasks.recordUsage(taskId, {
|
|
152
|
+
step: {
|
|
153
|
+
turnId: `execution:${attempt}:${result.execution.provider}:${result.execution.sessionId}`,
|
|
154
|
+
stepIndex: 0,
|
|
155
|
+
costUsd: result.usage.costUsd,
|
|
156
|
+
inputTokens: result.usage.inputTokens,
|
|
157
|
+
outputTokens: result.usage.outputTokens
|
|
158
|
+
},
|
|
159
|
+
fence: {
|
|
160
|
+
attempt,
|
|
161
|
+
execution: result.execution
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Cancels canonical Task work, then interrupts and settles its exact provider execution.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* The Task first durably enters `cancelled`, preventing later workflow completion from winning.
|
|
170
|
+
* Provider interruption happens afterward and cannot roll that transition back. An absent recorded
|
|
171
|
+
* execution produces durable `cancellation_unresolved` evidence and throws. Since execution
|
|
172
|
+
* binding accepts only running Tasks, a handle discovered after this point cannot be attached by
|
|
173
|
+
* retrying this helper; application-owned reconciliation must stop that handle and persist its
|
|
174
|
+
* cleanup evidence and measured settlement separately. If `adapter.stop` fails ambiguously, retry
|
|
175
|
+
* this same call—the cancelled transition and adapter stop are both expected to be idempotent.
|
|
176
|
+
*
|
|
177
|
+
* Returned final usage is recorded once. Known cost then settles the Task; unknown cost retains the
|
|
178
|
+
* reservation and leaves reconciliation evidence for later measurement.
|
|
179
|
+
*
|
|
180
|
+
* @param options - Exact Task attempt, cancellation reason, stores, and provider adapter.
|
|
181
|
+
* @returns The cancelled Task after provider usage recording and any possible settlement.
|
|
182
|
+
* @throws `ExecutionFenceError` when the attempt has been replaced.
|
|
183
|
+
* @throws When execution discovery is unresolved or the provider stop request fails.
|
|
184
|
+
*/
|
|
185
|
+
async function cancelExecution(options) {
|
|
186
|
+
const { stores, adapter, reason } = options;
|
|
187
|
+
const { taskId, attempt } = taskAttemptRefSchema.parse(options.task);
|
|
188
|
+
let task = await stores.tasks.get(taskId);
|
|
189
|
+
if (!task || task.attempt !== attempt) throw new ExecutionFenceError("Cancellation belongs to a replaced attempt");
|
|
190
|
+
if (task.state !== "cancelled") task = await stores.tasks.transition(taskId, "cancelled", {
|
|
191
|
+
expectFrom: task.state,
|
|
192
|
+
expectAttempt: attempt,
|
|
193
|
+
reason
|
|
194
|
+
});
|
|
195
|
+
if (!task.execution) {
|
|
196
|
+
const reason = "Cancellation is recorded; execution discovery is still required before stop and settlement";
|
|
197
|
+
await stores.receipts.append({
|
|
198
|
+
taskId,
|
|
199
|
+
repositoryIds: task.repositoryIds,
|
|
200
|
+
kind: task.kind,
|
|
201
|
+
state: "cancellation_unresolved",
|
|
202
|
+
phase: "cleanup",
|
|
203
|
+
attempt,
|
|
204
|
+
reason,
|
|
205
|
+
dedupeKey: `execution:${taskId}:${attempt}:cancellation-unresolved`
|
|
206
|
+
});
|
|
207
|
+
throw new Error(reason);
|
|
208
|
+
}
|
|
209
|
+
const result = executionResultSchema.parse(await adapter.stop(task.execution));
|
|
210
|
+
task = await recordExecutionUsage({
|
|
211
|
+
stores,
|
|
212
|
+
task: {
|
|
213
|
+
taskId,
|
|
214
|
+
attempt
|
|
215
|
+
},
|
|
216
|
+
result
|
|
217
|
+
});
|
|
218
|
+
return result.usage.costUsd === void 0 ? task : stores.tasks.settle(taskId, { cost: { totalUsd: task.usage.costUsd } });
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
export { ExecutionFenceError, cancelExecution, executionLaunchKey, inspectExecution, launchExecution, recordExecutionUsage };
|
|
222
|
+
|
|
223
|
+
//# sourceMappingURL=execution.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.mjs","names":[],"sources":["../src/execution.ts"],"sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { ExecutionLaunchPendingError } from \"./dispatch\";\nimport {\n codingExecutionRequestSchema,\n executionLaunchKeySchema,\n executionResultSchema,\n taskAttemptRefSchema,\n type CodingExecutionRequest,\n type ExecutionResult,\n type ExecutionLaunchKey,\n type TaskAttemptRef,\n} from \"./schema/execution\";\nimport { executionReferenceSchema, type ExecutionReference, type Task } from \"./schema/task\";\nimport type { FactoryStores } from \"./store/engine\";\n\n/** Validated request and stable idempotency key passed to an execution provider. */\nexport interface StartExecutionInput {\n /** Exact Task-attempt request validated before the provider is called. */\n readonly request: CodingExecutionRequest;\n /** Stable key that must identify the same provider launch across retries and process restarts. */\n readonly launchKey: ExecutionLaunchKey;\n}\n\n/** Current provider state when inspecting one recorded execution. */\nexport type ExecutionInspectionResult =\n | {\n /** The recorded execution still exists and is safe for the workflow to reattach. */\n status: \"active\";\n }\n | {\n /** The provider can no longer inspect or reattach the recorded execution. */\n status: \"expired\";\n }\n | {\n /** The provider has immutable final evidence for the recorded execution. */\n status: \"finished\";\n result: ExecutionResult;\n };\n\n/** Provider-neutral boundary for retry-safe execution start, inspection, and cancellation. */\nexport interface ExecutionAdapter {\n /**\n * Starts or recovers one launch by its stable key. Return only after provider acceptance is\n * known. Throw `ExecutionLaunchPendingError` when acceptance is ambiguous; every other rejection\n * promises that this call did not leave an untracked launch.\n *\n * @param input - Validated provider request and stable launch key.\n * @returns The accepted execution reference for this logical launch.\n */\n start(input: StartExecutionInput): Promise<ExecutionReference>;\n /**\n * Observes one exact provider handle without starting replacement work. Only `active` confirms\n * that reattachment is safe; `expired` and `finished` require workflow-owned reconciliation.\n *\n * @param execution - Exact provider handle previously recorded on the Task.\n * @returns Current provider state and final result when finished.\n */\n inspect(execution: ExecutionReference): Promise<ExecutionInspectionResult>;\n /**\n * Idempotently requests a stop and returns the provider's final observed result and usage. An\n * adapter may report cancellation even when immediate interruption is unsupported; callers that\n * require proof of inactivity must use provider-specific confirmation.\n *\n * @param execution - Exact provider handle to stop or confirm inactive.\n * @returns Immutable final result and usage for that execution.\n */\n stop(execution: ExecutionReference): Promise<ExecutionResult>;\n}\n\n/**\n * Error raised when an execution no longer matches the current running Task attempt.\n * Reread the Task and discard the stale observation; do not apply it to the replacement attempt.\n */\nexport class ExecutionFenceError extends Error {}\n\nfunction sameExecution(\n left: ExecutionReference | undefined,\n right: ExecutionReference | undefined,\n): boolean {\n // JSON persistence omits optional undefined fields; compare the persisted representation.\n return isDeepStrictEqual(\n left === undefined ? undefined : JSON.parse(JSON.stringify(left)),\n right === undefined ? undefined : JSON.parse(JSON.stringify(right)),\n );\n}\n\nasync function currentAttempt(\n stores: Pick<FactoryStores, \"tasks\">,\n ref: TaskAttemptRef,\n): Promise<Task> {\n const { taskId, attempt } = taskAttemptRefSchema.parse(ref);\n const task = await stores.tasks.get(taskId);\n if (!task || task.attempt !== attempt || task.state !== \"running\") {\n throw new ExecutionFenceError(\n `Execution requires running Task ${taskId} at attempt ${attempt}`,\n );\n }\n return task;\n}\n\n/** Store capabilities required to launch or reattach a coding execution. */\nexport type LaunchExecutionStores = Pick<FactoryStores, \"repositories\" | \"tasks\">;\n\n/** Store capabilities required to inspect a coding execution. */\nexport type InspectExecutionStores = Pick<FactoryStores, \"tasks\">;\n\n/** Store capabilities required to persist final execution usage. */\nexport type RecordExecutionUsageStores = Pick<FactoryStores, \"receipts\" | \"tasks\">;\n\n/** Store capabilities required to cancel and settle a coding execution. */\nexport type CancelExecutionStores = RecordExecutionUsageStores;\n\n/**\n * Constructs the stable provider idempotency key for one exact Task attempt.\n * Persist or deterministically recreate this key across launch recovery; a new attempt gets a new key.\n */\nexport function executionLaunchKey(ref: TaskAttemptRef): ExecutionLaunchKey {\n const { taskId, attempt } = taskAttemptRefSchema.parse(ref);\n return executionLaunchKeySchema.parse(`factory-task:${taskId}:${attempt}`);\n}\n\n/** Dependencies and request used to start or reattach one coding execution. */\nexport interface LaunchExecutionOptions {\n /** Task and repository reads plus the durable execution-binding write. */\n readonly stores: LaunchExecutionStores;\n /** Exact running Task attempt and single repository supplied to the provider. */\n readonly request: CodingExecutionRequest;\n /** Provider boundary responsible for idempotent start and exact-handle inspection. */\n readonly adapter: ExecutionAdapter;\n}\n\n/**\n * Starts or reattaches one coding execution after dispatch has admitted its Task.\n *\n * @remarks\n * The Task must still be `running` on the requested attempt and name exactly one enabled matching\n * repository. If an execution is already recorded, this method inspects it and returns it only\n * when the provider confirms it is active; it never starts an implicit replacement for a finished\n * or expired handle.\n *\n * For a new launch, the adapter receives a stable key derived from the Task attempt. The method\n * returns only after the provider reference is durably bound to that attempt. If acceptance or\n * the binding write is ambiguous, it throws `ExecutionLaunchPendingError`; retry this operation\n * with the same request so the same key can recover the launch. Reread the Task before applying\n * any other error, because a concurrent writer may have replaced the attempt.\n *\n * @param options - Validated request, required stores, and provider adapter.\n * @returns The recorded provider execution for the current running attempt.\n * @throws `ExecutionFenceError` when Task attempt or execution ownership changes.\n * @throws `ExecutionLaunchPendingError` when provider acceptance or durable binding is ambiguous.\n */\nexport async function launchExecution(\n options: LaunchExecutionOptions,\n): Promise<ExecutionReference> {\n const { stores, adapter } = options;\n const request = codingExecutionRequestSchema.parse(options.request);\n const ref = { taskId: request.taskId, attempt: request.attempt };\n const task = await currentAttempt(stores, ref);\n if (task.repositoryIds.length !== 1) throw new Error(\"Execution requires exactly one repository\");\n const repository = await stores.repositories.get(task.repositoryIds[0]!);\n if (!repository?.enabled || repository.slug !== request.repository.slug) {\n throw new Error(\"Execution repository must match the Task's enabled repository\");\n }\n if (task.execution) {\n const observed = await adapter.inspect(task.execution);\n const current = await currentAttempt(stores, ref);\n if (!sameExecution(current.execution, task.execution))\n throw new ExecutionFenceError(\"Execution changed during reattachment\");\n if (observed.status !== \"active\")\n throw new Error(\n `Execution is ${observed.status}; workflow must reconcile its outcome before continuing`,\n );\n return task.execution;\n }\n const execution = executionReferenceSchema.parse(\n await adapter.start({ request, launchKey: executionLaunchKey(ref) }),\n );\n try {\n await stores.tasks.recordExecution(task.id, {\n execution: execution,\n expectAttempt: task.attempt,\n });\n } catch (error) {\n let current;\n try {\n current = await stores.tasks.get(task.id);\n } catch (cause) {\n throw new ExecutionLaunchPendingError(\n \"Execution binding requires recovery with its original key\",\n { cause },\n );\n }\n if (\n !current ||\n current.attempt !== task.attempt ||\n current.state !== \"running\" ||\n (current.execution && !sameExecution(current.execution, execution))\n ) {\n await adapter.stop(execution);\n throw error;\n }\n throw new ExecutionLaunchPendingError(\n \"Execution binding requires recovery with its original key\",\n { cause: error },\n );\n }\n return execution;\n}\n\n/** Dependencies and Task-attempt identity used to inspect one execution. */\nexport interface InspectExecutionOptions {\n /** Task read used to establish and recheck the execution fence. */\n readonly stores: InspectExecutionStores;\n /** Exact running Task attempt whose recorded execution may be inspected. */\n readonly task: TaskAttemptRef;\n /** Provider boundary used only for observation. */\n readonly adapter: ExecutionAdapter;\n}\n\n/**\n * Inspects a recorded execution without granting provider evidence lifecycle authority.\n *\n * @remarks\n * The Task must be running on the exact attempt and have a recorded execution. Ownership is\n * checked again after the provider call so a concurrent replacement cannot attach stale results.\n * Finished results are schema-validated and must identify that same execution. This method writes\n * no Task state or usage; the workflow decides how to validate evidence and transition afterward.\n *\n * @param options - Exact Task attempt, Task store, and provider adapter.\n * @returns Current provider state and a validated result when finished.\n * @throws `ExecutionFenceError` when the attempt or execution changes during inspection.\n */\nexport async function inspectExecution(\n options: InspectExecutionOptions,\n): Promise<ExecutionInspectionResult> {\n const { stores, adapter } = options;\n const task = await currentAttempt(stores, options.task);\n if (!task.execution) throw new Error(`Task ${options.task.taskId} has no recorded execution`);\n const observed = await adapter.inspect(task.execution);\n const current = await currentAttempt(stores, options.task);\n if (!sameExecution(current.execution, task.execution))\n throw new ExecutionFenceError(\"Execution changed during inspection\");\n if (observed.status !== \"finished\") return observed;\n const result = executionResultSchema.parse(observed.result);\n if (!sameExecution(result.execution, task.execution))\n throw new ExecutionFenceError(\"Result belongs to another execution\");\n return { status: \"finished\", result };\n}\n\n/** Dependencies, Task-attempt identity, and provider result used to record usage. */\nexport interface RecordExecutionUsageOptions {\n /** Receipt and Task stores used for idempotent usage persistence. */\n readonly stores: RecordExecutionUsageStores;\n /** Exact Task attempt that owns the provider result. */\n readonly task: TaskAttemptRef;\n /** Final provider result whose execution must match the Task's recorded handle. */\n readonly result: ExecutionResult;\n}\n\n/**\n * Records one adapter's immutable final usage packet without changing Task lifecycle state.\n *\n * @remarks\n * Known cost is delegated to the Task usage store under a deterministic turn key, making identical\n * replay non-charging. This API records an immutable final usage packet; an adapter must not also\n * report the same charges through per-step usage hooks, because those observations use independent\n * idempotency keys and would be added twice. When cost is unknown, an idempotent `usage_unresolved`\n * receipt is appended and the Task remains unsettled so its reservation is retained. The workflow\n * or reconciler must later supply measured usage before settlement.\n *\n * @param options - Exact Task attempt, final provider result, and persistence stores.\n * @returns The Task after usage persistence, or unchanged after unresolved-cost evidence.\n * @throws `ExecutionFenceError` when the result belongs to another attempt or execution.\n */\nexport async function recordExecutionUsage(options: RecordExecutionUsageOptions): Promise<Task> {\n const { stores } = options;\n const { taskId, attempt } = taskAttemptRefSchema.parse(options.task);\n const result = executionResultSchema.parse(options.result);\n const task = await stores.tasks.get(taskId);\n if (!task || task.attempt !== attempt || !sameExecution(task.execution, result.execution)) {\n throw new ExecutionFenceError(\"Usage belongs to a different Task attempt or execution\");\n }\n if (result.usage.costUsd === undefined) {\n await stores.receipts.append({\n taskId,\n repositoryIds: task.repositoryIds,\n kind: task.kind,\n state: \"usage_unresolved\",\n phase: \"budget\",\n attempt,\n execution: result.execution,\n reason: \"Execution cost is unknown; retain the reservation until measured usage is available\",\n dedupeKey: `execution:${taskId}:${attempt}:usage-unresolved`,\n });\n return task;\n }\n return stores.tasks.recordUsage(taskId, {\n step: {\n turnId: `execution:${attempt}:${result.execution.provider}:${result.execution.sessionId}`,\n stepIndex: 0,\n costUsd: result.usage.costUsd,\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n },\n fence: { attempt, execution: result.execution },\n });\n}\n\n/** Dependencies and reason used to cancel one exact Task execution attempt. */\nexport interface CancelExecutionOptions {\n /** Task and receipt stores used for cancellation, usage, and settlement. */\n readonly stores: CancelExecutionStores;\n /** Exact attempt to cancel; replacement attempts are refused. */\n readonly task: TaskAttemptRef;\n /** Provider boundary used to request an idempotent stop and read its final observed result. */\n readonly adapter: ExecutionAdapter;\n /** Human-readable cancellation reason retained in lifecycle evidence. */\n readonly reason: string;\n}\n\n/**\n * Cancels canonical Task work, then interrupts and settles its exact provider execution.\n *\n * @remarks\n * The Task first durably enters `cancelled`, preventing later workflow completion from winning.\n * Provider interruption happens afterward and cannot roll that transition back. An absent recorded\n * execution produces durable `cancellation_unresolved` evidence and throws. Since execution\n * binding accepts only running Tasks, a handle discovered after this point cannot be attached by\n * retrying this helper; application-owned reconciliation must stop that handle and persist its\n * cleanup evidence and measured settlement separately. If `adapter.stop` fails ambiguously, retry\n * this same call—the cancelled transition and adapter stop are both expected to be idempotent.\n *\n * Returned final usage is recorded once. Known cost then settles the Task; unknown cost retains the\n * reservation and leaves reconciliation evidence for later measurement.\n *\n * @param options - Exact Task attempt, cancellation reason, stores, and provider adapter.\n * @returns The cancelled Task after provider usage recording and any possible settlement.\n * @throws `ExecutionFenceError` when the attempt has been replaced.\n * @throws When execution discovery is unresolved or the provider stop request fails.\n */\nexport async function cancelExecution(options: CancelExecutionOptions): Promise<Task> {\n const { stores, adapter, reason } = options;\n const { taskId, attempt } = taskAttemptRefSchema.parse(options.task);\n let task = await stores.tasks.get(taskId);\n if (!task || task.attempt !== attempt)\n throw new ExecutionFenceError(\"Cancellation belongs to a replaced attempt\");\n if (task.state !== \"cancelled\") {\n task = await stores.tasks.transition(taskId, \"cancelled\", {\n expectFrom: task.state,\n expectAttempt: attempt,\n reason,\n });\n }\n if (!task.execution) {\n const reason =\n \"Cancellation is recorded; execution discovery is still required before stop and settlement\";\n await stores.receipts.append({\n taskId,\n repositoryIds: task.repositoryIds,\n kind: task.kind,\n state: \"cancellation_unresolved\",\n phase: \"cleanup\",\n attempt,\n reason,\n dedupeKey: `execution:${taskId}:${attempt}:cancellation-unresolved`,\n });\n throw new Error(reason);\n }\n const result = executionResultSchema.parse(await adapter.stop(task.execution));\n task = await recordExecutionUsage({ stores, task: { taskId, attempt }, result });\n return result.usage.costUsd === undefined\n ? task\n : stores.tasks.settle(taskId, { cost: { totalUsd: task.usage!.costUsd } });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ApprovalPolicy } from "../approval.mjs";
|
|
2
|
+
import { RepositoryId, SignalId, TaskId } from "../schema/id.mjs";
|
|
3
|
+
import { AgentRoute } from "../agent-routes.mjs";
|
|
4
|
+
import { ReplyTo } from "../schema/common.mjs";
|
|
5
|
+
import { FactoryStores } from "../store/engine.mjs";
|
|
6
|
+
import { Finding } from "../schema/finding.mjs";
|
|
7
|
+
//#region src/finding-remediation/admission.d.ts
|
|
8
|
+
/** Store capabilities required to admit a finding and its remediation Task. */
|
|
9
|
+
type AdmitFindingStores = Pick<FactoryStores, "repositories" | "signals" | "tasks">;
|
|
10
|
+
/** Routing, approval, provenance, and reply policy for admitting a finding to remediation. */
|
|
11
|
+
interface AdmitFindingOptions {
|
|
12
|
+
/** Application-selected route for executing the resulting fix. */
|
|
13
|
+
readonly route: AgentRoute;
|
|
14
|
+
/** Signal source the finding is recorded under. Defaults to security_scan. */
|
|
15
|
+
readonly source?: string;
|
|
16
|
+
/** Which resulting Tasks wait for a human. Defaults to the neutral allow policy. */
|
|
17
|
+
readonly approval?: ApprovalPolicy;
|
|
18
|
+
/** Inherit a trusted originating Task's reply destination, when available. */
|
|
19
|
+
readonly replyTo?: ReplyTo;
|
|
20
|
+
/** Human initiator retained when a requested investigation creates a separate repair root. */
|
|
21
|
+
readonly operator?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Repository finding and remediation policy supplied to one admission attempt. */
|
|
24
|
+
interface AdmitFindingInput extends AdmitFindingOptions {
|
|
25
|
+
readonly repositoryId: RepositoryId;
|
|
26
|
+
readonly finding: Finding;
|
|
27
|
+
}
|
|
28
|
+
/** Outcome of admitting a finding, including missing-repository and duplicate no-ops. */
|
|
29
|
+
type AdmitFindingResult = {
|
|
30
|
+
recorded: false;
|
|
31
|
+
reasonCode: "repository_not_found";
|
|
32
|
+
reason: string;
|
|
33
|
+
} | {
|
|
34
|
+
recorded: false;
|
|
35
|
+
reasonCode: "duplicate";
|
|
36
|
+
reason: string;
|
|
37
|
+
duplicate: true;
|
|
38
|
+
signalId: SignalId;
|
|
39
|
+
} | {
|
|
40
|
+
recorded: true;
|
|
41
|
+
signalId: SignalId;
|
|
42
|
+
taskId: TaskId;
|
|
43
|
+
approval: "required" | "not_required";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Admit one finding as an accepted Signal and a routed remediation Task.
|
|
47
|
+
* The finding fingerprint is the Signal delivery id, making repeated reports
|
|
48
|
+
* of the same problem idempotent.
|
|
49
|
+
*/
|
|
50
|
+
declare function admitFinding(stores: AdmitFindingStores, input: AdmitFindingInput): Promise<AdmitFindingResult>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { AdmitFindingInput, AdmitFindingOptions, AdmitFindingResult, AdmitFindingStores, admitFinding };
|
|
53
|
+
//# sourceMappingURL=admission.d.mts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { allowByDefaultApprovalPolicy, requiresApproval } from "../approval.mjs";
|
|
2
|
+
import { routeTaskWork } from "../agent-routes.mjs";
|
|
3
|
+
import { findingFingerprint } from "../findings/fingerprint.mjs";
|
|
4
|
+
//#region src/finding-remediation/admission.ts
|
|
5
|
+
function isLostRaceError(error) {
|
|
6
|
+
return error instanceof Error && (error.name === "VersionConflictError" || error.name === "InvalidTransitionError");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Admit one finding as an accepted Signal and a routed remediation Task.
|
|
10
|
+
* The finding fingerprint is the Signal delivery id, making repeated reports
|
|
11
|
+
* of the same problem idempotent.
|
|
12
|
+
*/
|
|
13
|
+
async function admitFinding(stores, input) {
|
|
14
|
+
const { repositoryId, finding } = input;
|
|
15
|
+
const options = input;
|
|
16
|
+
if (options.route.taskKind !== "code_change") throw new Error("Finding fixes require a code_change agent route.");
|
|
17
|
+
const source = options.source ?? "security_scan";
|
|
18
|
+
if (await stores.repositories.get(repositoryId) === null) return {
|
|
19
|
+
recorded: false,
|
|
20
|
+
reasonCode: "repository_not_found",
|
|
21
|
+
reason: `repository ${repositoryId} does not exist`
|
|
22
|
+
};
|
|
23
|
+
const fingerprint = findingFingerprint(repositoryId, finding);
|
|
24
|
+
const signal = await stores.signals.create({
|
|
25
|
+
repositoryId,
|
|
26
|
+
source,
|
|
27
|
+
deliveryId: fingerprint,
|
|
28
|
+
replyTo: options.replyTo ?? {
|
|
29
|
+
channel: "finding",
|
|
30
|
+
address: fingerprint
|
|
31
|
+
},
|
|
32
|
+
payload: finding
|
|
33
|
+
});
|
|
34
|
+
if (signal.outcome !== "pending") return {
|
|
35
|
+
recorded: false,
|
|
36
|
+
reasonCode: "duplicate",
|
|
37
|
+
duplicate: true,
|
|
38
|
+
signalId: signal.id,
|
|
39
|
+
reason: `already recorded as ${signal.id}`
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
await stores.signals.decide(signal.id, {
|
|
43
|
+
outcome: "accepted",
|
|
44
|
+
detail: finding.priority,
|
|
45
|
+
reason: `${finding.tool ?? "scanner"} reported it, ${finding.verification.level} by ${finding.verification.method}`
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (isLostRaceError(error)) {
|
|
49
|
+
const current = await stores.signals.get(signal.id);
|
|
50
|
+
if (current !== null && current.outcome !== "pending") return {
|
|
51
|
+
recorded: false,
|
|
52
|
+
reasonCode: "duplicate",
|
|
53
|
+
duplicate: true,
|
|
54
|
+
signalId: signal.id,
|
|
55
|
+
reason: `already recorded as ${signal.id}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
const approval = requiresApproval(options.approval ?? allowByDefaultApprovalPolicy, {
|
|
61
|
+
source,
|
|
62
|
+
kind: "code_change",
|
|
63
|
+
priority: finding.priority
|
|
64
|
+
});
|
|
65
|
+
const task = await stores.tasks.create({
|
|
66
|
+
repositoryIds: [repositoryId],
|
|
67
|
+
kind: "code_change",
|
|
68
|
+
work: routeTaskWork({
|
|
69
|
+
route: options.route,
|
|
70
|
+
title: finding.title.trim().slice(0, 256),
|
|
71
|
+
input: { signalId: signal.id }
|
|
72
|
+
}),
|
|
73
|
+
origin: {
|
|
74
|
+
signalId: signal.id,
|
|
75
|
+
...options.operator === void 0 ? {} : { operator: options.operator }
|
|
76
|
+
},
|
|
77
|
+
replyTo: signal.replyTo,
|
|
78
|
+
...approval ? { approval: "required" } : {}
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
recorded: true,
|
|
82
|
+
signalId: signal.id,
|
|
83
|
+
taskId: task.id,
|
|
84
|
+
approval: approval ? "required" : "not_required"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { admitFinding };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=admission.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admission.mjs","names":[],"sources":["../../src/finding-remediation/admission.ts"],"sourcesContent":["import { routeTaskWork, type AgentRoute } from \"../agent-routes\";\nimport { allowByDefaultApprovalPolicy, requiresApproval, type ApprovalPolicy } from \"../approval\";\nimport { findingFingerprint } from \"../findings/fingerprint\";\nimport type { ReplyTo } from \"../schema/common\";\nimport type { Finding } from \"../schema/finding\";\nimport type { RepositoryId, SignalId, TaskId } from \"../schema/id\";\nimport type { FactoryStores } from \"../store/engine\";\n\n/** Store capabilities required to admit a finding and its remediation Task. */\nexport type AdmitFindingStores = Pick<FactoryStores, \"repositories\" | \"signals\" | \"tasks\">;\n\n// Matched by name, not instanceof: the Blob driver is a separate package entry\n// point, so its error classes are distinct objects from any imported here.\nfunction isLostRaceError(error: unknown): boolean {\n return (\n error instanceof Error &&\n (error.name === \"VersionConflictError\" || error.name === \"InvalidTransitionError\")\n );\n}\n\n/** Routing, approval, provenance, and reply policy for admitting a finding to remediation. */\nexport interface AdmitFindingOptions {\n /** Application-selected route for executing the resulting fix. */\n readonly route: AgentRoute;\n /** Signal source the finding is recorded under. Defaults to security_scan. */\n readonly source?: string;\n /** Which resulting Tasks wait for a human. Defaults to the neutral allow policy. */\n readonly approval?: ApprovalPolicy;\n /** Inherit a trusted originating Task's reply destination, when available. */\n readonly replyTo?: ReplyTo;\n /** Human initiator retained when a requested investigation creates a separate repair root. */\n readonly operator?: string;\n}\n\n/** Repository finding and remediation policy supplied to one admission attempt. */\nexport interface AdmitFindingInput extends AdmitFindingOptions {\n readonly repositoryId: RepositoryId;\n readonly finding: Finding;\n}\n\n/** Outcome of admitting a finding, including missing-repository and duplicate no-ops. */\nexport type AdmitFindingResult =\n | { recorded: false; reasonCode: \"repository_not_found\"; reason: string }\n | {\n recorded: false;\n reasonCode: \"duplicate\";\n reason: string;\n duplicate: true;\n signalId: SignalId;\n }\n | {\n recorded: true;\n signalId: SignalId;\n taskId: TaskId;\n approval: \"required\" | \"not_required\";\n };\n\n/**\n * Admit one finding as an accepted Signal and a routed remediation Task.\n * The finding fingerprint is the Signal delivery id, making repeated reports\n * of the same problem idempotent.\n */\nexport async function admitFinding(\n stores: AdmitFindingStores,\n input: AdmitFindingInput,\n): Promise<AdmitFindingResult> {\n const { repositoryId, finding } = input;\n const options: AdmitFindingOptions = input;\n if (options.route.taskKind !== \"code_change\") {\n throw new Error(\"Finding fixes require a code_change agent route.\");\n }\n const source = options.source ?? \"security_scan\";\n const repository = await stores.repositories.get(repositoryId);\n if (repository === null) {\n return {\n recorded: false,\n reasonCode: \"repository_not_found\",\n reason: `repository ${repositoryId} does not exist`,\n };\n }\n\n const fingerprint = findingFingerprint(repositoryId, finding);\n const signal = await stores.signals.create({\n repositoryId,\n source,\n deliveryId: fingerprint,\n replyTo: options.replyTo ?? { channel: \"finding\", address: fingerprint },\n payload: finding,\n });\n if (signal.outcome !== \"pending\") {\n return {\n recorded: false,\n reasonCode: \"duplicate\",\n duplicate: true,\n signalId: signal.id,\n reason: `already recorded as ${signal.id}`,\n };\n }\n\n try {\n await stores.signals.decide(signal.id, {\n outcome: \"accepted\",\n detail: finding.priority,\n reason: `${finding.tool ?? \"scanner\"} reported it, ${finding.verification.level} by ${finding.verification.method}`,\n });\n } catch (error) {\n if (isLostRaceError(error)) {\n const current = await stores.signals.get(signal.id);\n if (current !== null && current.outcome !== \"pending\") {\n return {\n recorded: false,\n reasonCode: \"duplicate\",\n duplicate: true,\n signalId: signal.id,\n reason: `already recorded as ${signal.id}`,\n };\n }\n }\n throw error;\n }\n\n const approval = requiresApproval(options.approval ?? allowByDefaultApprovalPolicy, {\n source,\n kind: \"code_change\",\n priority: finding.priority,\n });\n const task = await stores.tasks.create({\n repositoryIds: [repositoryId],\n kind: \"code_change\",\n work: routeTaskWork({\n route: options.route,\n title: finding.title.trim().slice(0, 256),\n input: { signalId: signal.id },\n }),\n origin: {\n signalId: signal.id,\n ...(options.operator === undefined ? {} : { operator: options.operator }),\n },\n replyTo: signal.replyTo,\n ...(approval ? { approval: \"required\" as const } : {}),\n });\n\n return {\n recorded: true,\n signalId: signal.id,\n taskId: task.id,\n approval: approval ? \"required\" : \"not_required\",\n };\n}\n"],"mappings":";;;;AAaA,SAAS,gBAAgB,OAAyB;CAChD,OACE,iBAAiB,UAChB,MAAM,SAAS,0BAA0B,MAAM,SAAS;AAE7D;;;;;;AA4CA,eAAsB,aACpB,QACA,OAC6B;CAC7B,MAAM,EAAE,cAAc,YAAY;CAClC,MAAM,UAA+B;CACrC,IAAI,QAAQ,MAAM,aAAa,eAC7B,MAAM,IAAI,MAAM,kDAAkD;CAEpE,MAAM,SAAS,QAAQ,UAAU;CAEjC,IAAI,MADqB,OAAO,aAAa,IAAI,YAAY,MAC1C,MACjB,OAAO;EACL,UAAU;EACV,YAAY;EACZ,QAAQ,cAAc,aAAa;CACrC;CAGF,MAAM,cAAc,mBAAmB,cAAc,OAAO;CAC5D,MAAM,SAAS,MAAM,OAAO,QAAQ,OAAO;EACzC;EACA;EACA,YAAY;EACZ,SAAS,QAAQ,WAAW;GAAE,SAAS;GAAW,SAAS;EAAY;EACvE,SAAS;CACX,CAAC;CACD,IAAI,OAAO,YAAY,WACrB,OAAO;EACL,UAAU;EACV,YAAY;EACZ,WAAW;EACX,UAAU,OAAO;EACjB,QAAQ,uBAAuB,OAAO;CACxC;CAGF,IAAI;EACF,MAAM,OAAO,QAAQ,OAAO,OAAO,IAAI;GACrC,SAAS;GACT,QAAQ,QAAQ;GAChB,QAAQ,GAAG,QAAQ,QAAQ,UAAU,gBAAgB,QAAQ,aAAa,MAAM,MAAM,QAAQ,aAAa;EAC7G,CAAC;CACH,SAAS,OAAO;EACd,IAAI,gBAAgB,KAAK,GAAG;GAC1B,MAAM,UAAU,MAAM,OAAO,QAAQ,IAAI,OAAO,EAAE;GAClD,IAAI,YAAY,QAAQ,QAAQ,YAAY,WAC1C,OAAO;IACL,UAAU;IACV,YAAY;IACZ,WAAW;IACX,UAAU,OAAO;IACjB,QAAQ,uBAAuB,OAAO;GACxC;EAEJ;EACA,MAAM;CACR;CAEA,MAAM,WAAW,iBAAiB,QAAQ,YAAY,8BAA8B;EAClF;EACA,MAAM;EACN,UAAU,QAAQ;CACpB,CAAC;CACD,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO;EACrC,eAAe,CAAC,YAAY;EAC5B,MAAM;EACN,MAAM,cAAc;GAClB,OAAO,QAAQ;GACf,OAAO,QAAQ,MAAM,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG;GACxC,OAAO,EAAE,UAAU,OAAO,GAAG;EAC/B,CAAC;EACD,QAAQ;GACN,UAAU,OAAO;GACjB,GAAI,QAAQ,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,SAAS;EACzE;EACA,SAAS,OAAO;EAChB,GAAI,WAAW,EAAE,UAAU,WAAoB,IAAI,CAAC;CACtD,CAAC;CAED,OAAO;EACL,UAAU;EACV,UAAU,OAAO;EACjB,QAAQ,KAAK;EACb,UAAU,WAAW,aAAa;CACpC;AACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Repository } from "../schema/repository.mjs";
|
|
2
|
+
import { Task } from "../schema/task.mjs";
|
|
3
|
+
import { FactoryStores } from "../store/engine.mjs";
|
|
4
|
+
import { Finding } from "../schema/finding.mjs";
|
|
5
|
+
//#region src/finding-remediation/brief.d.ts
|
|
6
|
+
/** Store capabilities required to recover a finding from a Task's source Signal. */
|
|
7
|
+
type FindingLookupStores = Pick<FactoryStores, "signals">;
|
|
8
|
+
/** Find the finding behind a Task when its originating Signal carries one. */
|
|
9
|
+
declare function findFindingForTask(stores: FindingLookupStores, task: Task): Promise<Finding | null>;
|
|
10
|
+
/** Format the factual starting brief for a finding-remediation Task. */
|
|
11
|
+
declare function formatFindingRemediationBrief(task: Task, repository: Repository, finding: Finding | null): string;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { FindingLookupStores, findFindingForTask, formatFindingRemediationBrief };
|
|
14
|
+
//# sourceMappingURL=brief.d.mts.map
|