@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,56 @@
|
|
|
1
|
+
import { findingSchema } from "../schema/finding.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/deepsec/finding.ts
|
|
4
|
+
/** Deepsec's exported finding shape, as far as Factory depends on it. */
|
|
5
|
+
const deepsecFindingSchema = z.looseObject({
|
|
6
|
+
title: z.string().min(1),
|
|
7
|
+
description: z.string().min(1),
|
|
8
|
+
severity: z.string().min(1),
|
|
9
|
+
metadata: z.looseObject({
|
|
10
|
+
filePath: z.string().min(1).optional(),
|
|
11
|
+
lineNumbers: z.array(z.number().int().min(1)).readonly().optional(),
|
|
12
|
+
vulnSlug: z.string().min(1).optional(),
|
|
13
|
+
confidence: z.string().optional(),
|
|
14
|
+
runId: z.string().optional()
|
|
15
|
+
}).optional()
|
|
16
|
+
}).readonly();
|
|
17
|
+
const deepsecFindingsSchema = z.array(deepsecFindingSchema).readonly();
|
|
18
|
+
/** Deepsec export document accepted by the optional scanner adapter. */
|
|
19
|
+
const deepsecExportSchema = z.union([deepsecFindingsSchema, z.looseObject({ findings: deepsecFindingsSchema }).transform((value) => value.findings)]);
|
|
20
|
+
const priorityBySeverity = {
|
|
21
|
+
CRITICAL: "P0",
|
|
22
|
+
HIGH: "P1",
|
|
23
|
+
MEDIUM: "P2",
|
|
24
|
+
HIGH_BUG: "P2",
|
|
25
|
+
BUG: "P3",
|
|
26
|
+
LOW: "P3"
|
|
27
|
+
};
|
|
28
|
+
/** Validate and convert one Deepsec finding into Factory's normalized Finding contract. */
|
|
29
|
+
function findingFromDeepsec(input) {
|
|
30
|
+
const raw = deepsecFindingSchema.parse(input);
|
|
31
|
+
const meta = raw.metadata ?? {};
|
|
32
|
+
const confidence = (meta.confidence ?? "").toLowerCase();
|
|
33
|
+
const line = meta.lineNumbers?.[0];
|
|
34
|
+
const endLine = meta.lineNumbers === void 0 ? void 0 : Math.max(...meta.lineNumbers);
|
|
35
|
+
return findingSchema.parse({
|
|
36
|
+
title: raw.title.replace(/^\[[A-Z_]+\]\s*/u, "").slice(0, 200),
|
|
37
|
+
body: raw.description.slice(0, 8e3),
|
|
38
|
+
...meta.filePath === void 0 ? {} : { path: meta.filePath.slice(0, 500) },
|
|
39
|
+
...line === void 0 ? {} : { line },
|
|
40
|
+
...endLine === void 0 || endLine === line ? {} : { endLine },
|
|
41
|
+
priority: priorityBySeverity[raw.severity.toUpperCase()] ?? "P3",
|
|
42
|
+
category: "security",
|
|
43
|
+
verification: {
|
|
44
|
+
level: confidence === "high" ? "supported" : "unverified",
|
|
45
|
+
method: "static_analysis",
|
|
46
|
+
summary: `deepsec ${meta.vulnSlug ?? "finding"} with ${confidence || "unknown"} confidence${meta.runId === void 0 ? "" : ` (run ${meta.runId})`}.`,
|
|
47
|
+
limitations: "AI-assisted static analysis of the checkout; not reproduced at runtime."
|
|
48
|
+
},
|
|
49
|
+
tool: "deepsec",
|
|
50
|
+
...meta.vulnSlug === void 0 ? {} : { ruleId: meta.vulnSlug }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { deepsecExportSchema, deepsecFindingSchema, findingFromDeepsec };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=finding.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding.mjs","names":[],"sources":["../../src/deepsec/finding.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { findingSchema, type Finding, type FindingPriority } from \"../schema/finding\";\n\n/** Deepsec's exported finding shape, as far as Factory depends on it. */\nexport const deepsecFindingSchema = z\n .looseObject({\n title: z.string().min(1),\n description: z.string().min(1),\n severity: z.string().min(1),\n metadata: z\n .looseObject({\n filePath: z.string().min(1).optional(),\n lineNumbers: z.array(z.number().int().min(1)).readonly().optional(),\n vulnSlug: z.string().min(1).optional(),\n confidence: z.string().optional(),\n runId: z.string().optional(),\n })\n .optional(),\n })\n .readonly();\n\nconst deepsecFindingsSchema = z.array(deepsecFindingSchema).readonly();\n\n/** Deepsec export document accepted by the optional scanner adapter. */\nexport const deepsecExportSchema = z.union([\n deepsecFindingsSchema,\n z.looseObject({ findings: deepsecFindingsSchema }).transform((value) => value.findings),\n]);\n\n/** Provider payload accepted for one Deepsec finding before normalization. */\nexport type DeepsecFindingInput = z.input<typeof deepsecFindingSchema>;\n\n/** Parsed Deepsec finding payload used by the normalization adapter. */\nexport type DeepsecFinding = z.output<typeof deepsecFindingSchema>;\n\n/** Provider export document accepted before its wrapper is normalized. */\nexport type DeepsecExportInput = z.input<typeof deepsecExportSchema>;\n\n/** Parsed list of Deepsec findings produced by the export schema. */\nexport type DeepsecExport = z.output<typeof deepsecExportSchema>;\n\nconst priorityBySeverity: Record<string, FindingPriority> = {\n CRITICAL: \"P0\",\n HIGH: \"P1\",\n MEDIUM: \"P2\",\n HIGH_BUG: \"P2\",\n BUG: \"P3\",\n LOW: \"P3\",\n};\n\n/** Validate and convert one Deepsec finding into Factory's normalized Finding contract. */\nexport function findingFromDeepsec(input: DeepsecFindingInput): Finding {\n const raw = deepsecFindingSchema.parse(input);\n const meta = raw.metadata ?? {};\n const confidence = (meta.confidence ?? \"\").toLowerCase();\n const line = meta.lineNumbers?.[0];\n const endLine = meta.lineNumbers === undefined ? undefined : Math.max(...meta.lineNumbers);\n return findingSchema.parse({\n title: raw.title.replace(/^\\[[A-Z_]+\\]\\s*/u, \"\").slice(0, 200),\n body: raw.description.slice(0, 8000),\n ...(meta.filePath === undefined ? {} : { path: meta.filePath.slice(0, 500) }),\n ...(line === undefined ? {} : { line }),\n ...(endLine === undefined || endLine === line ? {} : { endLine }),\n priority: priorityBySeverity[raw.severity.toUpperCase()] ?? \"P3\",\n category: \"security\",\n verification: {\n level: confidence === \"high\" ? \"supported\" : \"unverified\",\n method: \"static_analysis\",\n summary: `deepsec ${meta.vulnSlug ?? \"finding\"} with ${confidence || \"unknown\"} confidence${meta.runId === undefined ? \"\" : ` (run ${meta.runId})`}.`,\n limitations: \"AI-assisted static analysis of the checkout; not reproduced at runtime.\",\n },\n tool: \"deepsec\",\n ...(meta.vulnSlug === undefined ? {} : { ruleId: meta.vulnSlug }),\n });\n}\n"],"mappings":";;;;AAIA,MAAa,uBAAuB,EACjC,YAAY;CACX,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACvB,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC7B,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAC1B,UAAU,EACP,YAAY;EACX,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EACrC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;EAClE,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;EACrC,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;EAChC,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC7B,CAAC,CAAC,CACD,SAAS;AACd,CAAC,CAAC,CACD,SAAS;AAEZ,MAAM,wBAAwB,EAAE,MAAM,oBAAoB,CAAC,CAAC,SAAS;;AAGrE,MAAa,sBAAsB,EAAE,MAAM,CACzC,uBACA,EAAE,YAAY,EAAE,UAAU,sBAAsB,CAAC,CAAC,CAAC,WAAW,UAAU,MAAM,QAAQ,CACxF,CAAC;AAcD,MAAM,qBAAsD;CAC1D,UAAU;CACV,MAAM;CACN,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;AACP;;AAGA,SAAgB,mBAAmB,OAAqC;CACtE,MAAM,MAAM,qBAAqB,MAAM,KAAK;CAC5C,MAAM,OAAO,IAAI,YAAY,CAAC;CAC9B,MAAM,cAAc,KAAK,cAAc,GAAA,CAAI,YAAY;CACvD,MAAM,OAAO,KAAK,cAAc;CAChC,MAAM,UAAU,KAAK,gBAAgB,KAAA,IAAY,KAAA,IAAY,KAAK,IAAI,GAAG,KAAK,WAAW;CACzF,OAAO,cAAc,MAAM;EACzB,OAAO,IAAI,MAAM,QAAQ,oBAAoB,EAAE,CAAC,CAAC,MAAM,GAAG,GAAG;EAC7D,MAAM,IAAI,YAAY,MAAM,GAAG,GAAI;EACnC,GAAI,KAAK,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,MAAM,GAAG,GAAG,EAAE;EAC3E,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC,GAAI,YAAY,KAAA,KAAa,YAAY,OAAO,CAAC,IAAI,EAAE,QAAQ;EAC/D,UAAU,mBAAmB,IAAI,SAAS,YAAY,MAAM;EAC5D,UAAU;EACV,cAAc;GACZ,OAAO,eAAe,SAAS,cAAc;GAC7C,QAAQ;GACR,SAAS,WAAW,KAAK,YAAY,UAAU,QAAQ,cAAc,UAAU,aAAa,KAAK,UAAU,KAAA,IAAY,KAAK,SAAS,KAAK,MAAM,GAAG;GACnJ,aAAa;EACf;EACA,MAAM;EACN,GAAI,KAAK,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,SAAS;CACjE,CAAC;AACH"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { DeepsecExport, DeepsecExportInput, DeepsecFinding, DeepsecFindingInput, deepsecExportSchema, deepsecFindingSchema, findingFromDeepsec } from "./deepsec/finding.mjs";
|
|
2
|
+
import { DeepsecAgent, DeepsecCommandResult, DeepsecCredentialCommandInput, DeepsecScanFailure, DeepsecScanFailureCode, DeepsecScanFinding, DeepsecScanInput, DeepsecScanResult, DeepsecScanSuccess, DeepsecScanTool, DeepsecScanToolOptions, DeepsecScanToolStores, DeepsecThinkingLevel, createDeepsecScanTool, deepsecScanInputSchema } from "./deepsec/eve-tool.mjs";
|
|
3
|
+
export { type DeepsecAgent, type DeepsecCommandResult, type DeepsecCredentialCommandInput, type DeepsecExport, type DeepsecExportInput, type DeepsecFinding, type DeepsecFindingInput, type DeepsecScanFailure, type DeepsecScanFailureCode, type DeepsecScanFinding, type DeepsecScanInput, type DeepsecScanResult, type DeepsecScanSuccess, type DeepsecScanTool, type DeepsecScanToolOptions, type DeepsecScanToolStores, type DeepsecThinkingLevel, createDeepsecScanTool, deepsecExportSchema, deepsecFindingSchema, deepsecScanInputSchema, findingFromDeepsec };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Signal } from "../schema/signal.mjs";
|
|
2
|
+
import { Task } from "../schema/task.mjs";
|
|
3
|
+
import { TaskGraph } from "../schema/task-graph.mjs";
|
|
4
|
+
import { Change, ChangeLevel } from "../schema/change.mjs";
|
|
5
|
+
import { Receipt } from "../schema/receipt.mjs";
|
|
6
|
+
//#region src/delivery-metrics/metrics.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The derived review bucket from the default risk x confidence table. Derived
|
|
9
|
+
* at read time, never stored; "blocked" is a bucket, not a change state.
|
|
10
|
+
*/
|
|
11
|
+
type ChangeReviewBucket = "stamp" | "review" | "blocked";
|
|
12
|
+
/** Risk and confidence inputs used to derive a human-review bucket. */
|
|
13
|
+
interface ChangeReviewFactors {
|
|
14
|
+
risk: ChangeLevel;
|
|
15
|
+
confidence: ChangeLevel;
|
|
16
|
+
}
|
|
17
|
+
/** Derives the default human-review bucket from a change's risk and confidence. */
|
|
18
|
+
declare function changeReviewBucket(input: ChangeReviewFactors): ChangeReviewBucket;
|
|
19
|
+
/** Validated ledger rows used to derive Factory metrics and health. */
|
|
20
|
+
interface DeliveryLedgerRows {
|
|
21
|
+
changes: readonly Change[];
|
|
22
|
+
signals: readonly Signal[];
|
|
23
|
+
receipts: readonly Receipt[];
|
|
24
|
+
tasks: readonly Task[];
|
|
25
|
+
/** Validated graph snapshots keyed by rootTaskId. Missing snapshots make health yellow, never runnable. */
|
|
26
|
+
graphs?: ReadonlyMap<string, TaskGraph>;
|
|
27
|
+
}
|
|
28
|
+
/** Options controlling ledger metric evaluation. */
|
|
29
|
+
interface ComputeLedgerMetricsOptions {
|
|
30
|
+
/** Evaluation time; defaults to the current time. */
|
|
31
|
+
now?: Date;
|
|
32
|
+
/** Days a landed change must hold without a rollback. Default 7. */
|
|
33
|
+
holdDays?: number;
|
|
34
|
+
}
|
|
35
|
+
/** Product metrics derived deterministically from ledger rows. */
|
|
36
|
+
interface DeliveryMetrics {
|
|
37
|
+
/**
|
|
38
|
+
* Changes a human merged that reached deployed (rolled_out for high risk)
|
|
39
|
+
* and did not roll back within the hold window. Includes provisional ones.
|
|
40
|
+
*/
|
|
41
|
+
landed: number;
|
|
42
|
+
/** Landed changes still inside the hold window; the number may drop. */
|
|
43
|
+
provisional: number;
|
|
44
|
+
/** landed / (landed + rolled back + closed after ready). Null when nothing decided. */
|
|
45
|
+
stickRate: number | null;
|
|
46
|
+
/**
|
|
47
|
+
* Not computable from ledger rows: needs a record of human commits pushed
|
|
48
|
+
* to the pull request after ready, which nothing writes today.
|
|
49
|
+
*/
|
|
50
|
+
stampedClean: null;
|
|
51
|
+
/** Median ms from the ready receipt to the merged receipt, per review bucket. */
|
|
52
|
+
humanTimeMs: {
|
|
53
|
+
stamp: number | null;
|
|
54
|
+
review: number | null;
|
|
55
|
+
};
|
|
56
|
+
/** Sum of settled task cost over landed changes / landed. Null until budgets settle. */
|
|
57
|
+
costPerLandedUsd: number | null;
|
|
58
|
+
/** Signals triage turned away plus changes closed in verification. */
|
|
59
|
+
filtered: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The six product metrics from ledger rows alone. One rule governs them: a
|
|
63
|
+
* change counts only after a human merged it and it stayed. Activity that
|
|
64
|
+
* never landed is not a result. Compute over rows already filtered to the
|
|
65
|
+
* period and repositories you are reporting on.
|
|
66
|
+
*/
|
|
67
|
+
declare function computeLedgerMetrics(rows: DeliveryLedgerRows, options?: ComputeLedgerMetricsOptions): DeliveryMetrics;
|
|
68
|
+
/** Overall repository health severity derived from operational evidence. */
|
|
69
|
+
type RepositoryHealthColor = "green" | "yellow" | "red";
|
|
70
|
+
/** Options controlling repository health evaluation. */
|
|
71
|
+
interface ComputeRepositoryHealthOptions {
|
|
72
|
+
now?: Date;
|
|
73
|
+
/** Open-change cap from factory configuration; omitted disables that check. */
|
|
74
|
+
maxOpenChanges?: number;
|
|
75
|
+
/** Minutes an eligible executable task may remain queued before health turns yellow. Default 5. */
|
|
76
|
+
maxQueuedMinutes?: number;
|
|
77
|
+
}
|
|
78
|
+
/** Explainable repository health derived from ledger and graph state. */
|
|
79
|
+
interface RepositoryHealth {
|
|
80
|
+
readonly color: RepositoryHealthColor;
|
|
81
|
+
/** Every rule that fired, so the color is explainable from rows. */
|
|
82
|
+
readonly reasons: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Green, yellow, or red from rows, never from a model. Budget threshold and
|
|
86
|
+
* onboarding rules are not evaluated here yet: budget notices live on the
|
|
87
|
+
* budgets collection (not in these rows), and onboarding investigations are
|
|
88
|
+
* not recorded.
|
|
89
|
+
*/
|
|
90
|
+
declare function computeRepositoryHealth(rows: DeliveryLedgerRows, options?: ComputeRepositoryHealthOptions): RepositoryHealth;
|
|
91
|
+
//#endregion
|
|
92
|
+
export { ChangeReviewBucket, ChangeReviewFactors, ComputeLedgerMetricsOptions, ComputeRepositoryHealthOptions, DeliveryLedgerRows, DeliveryMetrics, RepositoryHealth, RepositoryHealthColor, changeReviewBucket, computeLedgerMetrics, computeRepositoryHealth };
|
|
93
|
+
//# sourceMappingURL=metrics.d.mts.map
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
//#region src/delivery-metrics/metrics.ts
|
|
2
|
+
const bucketTable = {
|
|
3
|
+
low: {
|
|
4
|
+
low: "review",
|
|
5
|
+
medium: "stamp",
|
|
6
|
+
high: "stamp"
|
|
7
|
+
},
|
|
8
|
+
medium: {
|
|
9
|
+
low: "review",
|
|
10
|
+
medium: "review",
|
|
11
|
+
high: "stamp"
|
|
12
|
+
},
|
|
13
|
+
high: {
|
|
14
|
+
low: "blocked",
|
|
15
|
+
medium: "review",
|
|
16
|
+
high: "review"
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Derives the default human-review bucket from a change's risk and confidence. */
|
|
20
|
+
function changeReviewBucket(input) {
|
|
21
|
+
return bucketTable[input.risk][input.confidence];
|
|
22
|
+
}
|
|
23
|
+
function collectFacts(rows) {
|
|
24
|
+
const byChange = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const receipt of rows.receipts) {
|
|
26
|
+
if (receipt.kind !== "change" || receipt.changeId === void 0) continue;
|
|
27
|
+
const list = byChange.get(receipt.changeId) ?? [];
|
|
28
|
+
list.push(receipt);
|
|
29
|
+
byChange.set(receipt.changeId, list);
|
|
30
|
+
}
|
|
31
|
+
const at = (receipts, state) => {
|
|
32
|
+
const found = receipts?.find((receipt) => receipt.state === state);
|
|
33
|
+
return found === void 0 ? null : Date.parse(found.recordedAt);
|
|
34
|
+
};
|
|
35
|
+
return rows.changes.map((change) => {
|
|
36
|
+
const receipts = byChange.get(change.id);
|
|
37
|
+
const requiredState = change.risk === "high" ? "rolled_out" : "deployed";
|
|
38
|
+
return {
|
|
39
|
+
change,
|
|
40
|
+
readyAt: at(receipts, "ready"),
|
|
41
|
+
mergedAt: at(receipts, "merged"),
|
|
42
|
+
reachedAt: at(receipts, requiredState),
|
|
43
|
+
rolledBackAt: at(receipts, "rolled_back")
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** True for a change a human saw as ready and then closed unmerged. */
|
|
48
|
+
function closedAfterReady(facts) {
|
|
49
|
+
return facts.change.state === "closed" && (facts.readyAt !== null || facts.change.decidedBy !== void 0);
|
|
50
|
+
}
|
|
51
|
+
function median(values) {
|
|
52
|
+
if (values.length === 0) return null;
|
|
53
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
54
|
+
const mid = Math.floor(sorted.length / 2);
|
|
55
|
+
return sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The six product metrics from ledger rows alone. One rule governs them: a
|
|
59
|
+
* change counts only after a human merged it and it stayed. Activity that
|
|
60
|
+
* never landed is not a result. Compute over rows already filtered to the
|
|
61
|
+
* period and repositories you are reporting on.
|
|
62
|
+
*/
|
|
63
|
+
function computeLedgerMetrics(rows, options = {}) {
|
|
64
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
65
|
+
const holdMs = (options.holdDays ?? 7) * 24 * 60 * 60 * 1e3;
|
|
66
|
+
const facts = collectFacts(rows);
|
|
67
|
+
let landed = 0;
|
|
68
|
+
let provisional = 0;
|
|
69
|
+
let rolledBack = 0;
|
|
70
|
+
let closedAfterReadyCount = 0;
|
|
71
|
+
let closedInVerification = 0;
|
|
72
|
+
const landedChangeIds = /* @__PURE__ */ new Set();
|
|
73
|
+
for (const fact of facts) {
|
|
74
|
+
const { change } = fact;
|
|
75
|
+
if (fact.rolledBackAt !== null) {
|
|
76
|
+
rolledBack += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (change.state === "closed") {
|
|
80
|
+
if (closedAfterReady(fact)) closedAfterReadyCount += 1;
|
|
81
|
+
else closedInVerification += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (change.decidedBy !== void 0 && fact.reachedAt !== null) {
|
|
85
|
+
landed += 1;
|
|
86
|
+
landedChangeIds.add(change.id);
|
|
87
|
+
if (now - fact.reachedAt < holdMs) provisional += 1;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const stickDenominator = landed + rolledBack + closedAfterReadyCount;
|
|
91
|
+
const humanTimes = {
|
|
92
|
+
stamp: [],
|
|
93
|
+
review: []
|
|
94
|
+
};
|
|
95
|
+
for (const fact of facts) {
|
|
96
|
+
if (fact.readyAt === null || fact.mergedAt === null) continue;
|
|
97
|
+
const bucket = changeReviewBucket({
|
|
98
|
+
risk: fact.change.risk,
|
|
99
|
+
confidence: fact.change.confidence
|
|
100
|
+
});
|
|
101
|
+
if (bucket === "blocked") continue;
|
|
102
|
+
humanTimes[bucket].push(fact.mergedAt - fact.readyAt);
|
|
103
|
+
}
|
|
104
|
+
let settledOverLanded = 0;
|
|
105
|
+
let sawSettledCost = false;
|
|
106
|
+
for (const task of rows.tasks) {
|
|
107
|
+
if (task.settledUsd === void 0) continue;
|
|
108
|
+
if (task.kind === "code_change" && task.changeId !== void 0 && landedChangeIds.has(task.changeId)) {
|
|
109
|
+
settledOverLanded += task.settledUsd;
|
|
110
|
+
sawSettledCost = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const rejectedSignals = rows.signals.filter((signal) => signal.outcome !== "pending" && signal.outcome !== "accepted").length;
|
|
114
|
+
return {
|
|
115
|
+
landed,
|
|
116
|
+
provisional,
|
|
117
|
+
stickRate: stickDenominator === 0 ? null : landed / stickDenominator,
|
|
118
|
+
stampedClean: null,
|
|
119
|
+
humanTimeMs: {
|
|
120
|
+
stamp: median(humanTimes.stamp),
|
|
121
|
+
review: median(humanTimes.review)
|
|
122
|
+
},
|
|
123
|
+
costPerLandedUsd: sawSettledCost && landed > 0 ? settledOverLanded / landed : null,
|
|
124
|
+
filtered: rejectedSignals + closedInVerification
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const openChangeStates = /* @__PURE__ */ new Set(["verifying", "ready"]);
|
|
128
|
+
function matchesGraphNode(task, node) {
|
|
129
|
+
return task.id === node.taskId && task.rootTaskId === node.admission.rootTaskId && task.parentTaskId === node.parentTaskId && task.repositoryIds.length === node.admission.repositoryIds.length && task.repositoryIds.every((id, index) => id === node.admission.repositoryIds[index]);
|
|
130
|
+
}
|
|
131
|
+
function dependencyStatus(task, tasks, graphs) {
|
|
132
|
+
const graph = graphs?.get(task.rootTaskId);
|
|
133
|
+
const node = graph?.nodes.find((entry) => entry.taskId === task.id);
|
|
134
|
+
if (!graph || graph.rootTaskId !== task.rootTaskId || !node || !matchesGraphNode(task, node)) return "unknown";
|
|
135
|
+
let ready = true;
|
|
136
|
+
for (const id of node.dependencies) {
|
|
137
|
+
const dependency = tasks.get(id);
|
|
138
|
+
const dependencyNode = graph.nodes.find((entry) => entry.taskId === id);
|
|
139
|
+
if (!dependency || !dependencyNode || !matchesGraphNode(dependency, dependencyNode)) return "unknown";
|
|
140
|
+
if (dependency.state !== "succeeded") ready = false;
|
|
141
|
+
}
|
|
142
|
+
return ready ? "ready" : "waiting";
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Green, yellow, or red from rows, never from a model. Budget threshold and
|
|
146
|
+
* onboarding rules are not evaluated here yet: budget notices live on the
|
|
147
|
+
* budgets collection (not in these rows), and onboarding investigations are
|
|
148
|
+
* not recorded.
|
|
149
|
+
*/
|
|
150
|
+
function computeRepositoryHealth(rows, options = {}) {
|
|
151
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
152
|
+
const dayMs = 864e5;
|
|
153
|
+
const red = [];
|
|
154
|
+
const yellow = [];
|
|
155
|
+
const tasksById = new Map(rows.tasks.map((task) => [task.id, task]));
|
|
156
|
+
for (const receipt of rows.receipts) {
|
|
157
|
+
if (now - Date.parse(receipt.recordedAt) >= dayMs) continue;
|
|
158
|
+
if (receipt.state === "rolled_back") red.push(`rollback in the last 24h (${receipt.receiptId})`);
|
|
159
|
+
if (receipt.state === "cancelled" && receipt.reason?.toLowerCase().includes("kill")) red.push(`kill in the last 24h (${receipt.receiptId})`);
|
|
160
|
+
}
|
|
161
|
+
const openQuestions = rows.tasks.filter((task) => task.kind === "question" && task.state === "needs_human").length;
|
|
162
|
+
if (openQuestions > 0) yellow.push(`${openQuestions} open question(s)`);
|
|
163
|
+
const needsHuman = rows.tasks.filter((task) => task.kind !== "question" && task.state === "needs_human").length;
|
|
164
|
+
if (needsHuman > 0) yellow.push(`${needsHuman} task(s) waiting on a human`);
|
|
165
|
+
const maxQueuedMinutes = options.maxQueuedMinutes ?? 5;
|
|
166
|
+
let staleQueued = 0;
|
|
167
|
+
let unknownDependencies = 0;
|
|
168
|
+
for (const task of rows.tasks) {
|
|
169
|
+
const status = dependencyStatus(task, tasksById, rows.graphs);
|
|
170
|
+
if (status === "unknown") unknownDependencies += 1;
|
|
171
|
+
if (status === "ready" && task.state === "queued" && task.approval !== "required" && task.approval !== "denied" && now - Date.parse(task.updatedAt) >= maxQueuedMinutes * 60 * 1e3) staleQueued += 1;
|
|
172
|
+
}
|
|
173
|
+
if (unknownDependencies > 0) yellow.push(`${unknownDependencies} task(s) with missing or inconsistent graph/dependency snapshots`);
|
|
174
|
+
if (staleQueued > 0) yellow.push(`${staleQueued} eligible task(s) queued for at least ${maxQueuedMinutes} minutes`);
|
|
175
|
+
const blocked = rows.changes.filter((change) => openChangeStates.has(change.state) && changeReviewBucket({
|
|
176
|
+
risk: change.risk,
|
|
177
|
+
confidence: change.confidence
|
|
178
|
+
}) === "blocked").length;
|
|
179
|
+
if (blocked > 0) yellow.push(`${blocked} change(s) in the blocked bucket`);
|
|
180
|
+
if (options.maxOpenChanges !== void 0) {
|
|
181
|
+
const open = rows.changes.filter((change) => openChangeStates.has(change.state)).length;
|
|
182
|
+
if (open >= options.maxOpenChanges) yellow.push(`open changes at the cap (${open}/${options.maxOpenChanges})`);
|
|
183
|
+
}
|
|
184
|
+
if (red.length > 0) return {
|
|
185
|
+
color: "red",
|
|
186
|
+
reasons: red
|
|
187
|
+
};
|
|
188
|
+
if (yellow.length > 0) return {
|
|
189
|
+
color: "yellow",
|
|
190
|
+
reasons: yellow
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
color: "green",
|
|
194
|
+
reasons: []
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
export { changeReviewBucket, computeLedgerMetrics, computeRepositoryHealth };
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=metrics.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.mjs","names":[],"sources":["../../src/delivery-metrics/metrics.ts"],"sourcesContent":["import type { Change, ChangeLevel } from \"../schema/change\";\nimport type { Receipt } from \"../schema/receipt\";\nimport type { Signal } from \"../schema/signal\";\nimport type { Task } from \"../schema/task\";\nimport type { TaskGraph, TaskGraphNode } from \"../schema/task-graph\";\n\n/**\n * The derived review bucket from the default risk x confidence table. Derived\n * at read time, never stored; \"blocked\" is a bucket, not a change state.\n */\nexport type ChangeReviewBucket = \"stamp\" | \"review\" | \"blocked\";\n\nconst bucketTable: Record<ChangeLevel, Record<ChangeLevel, ChangeReviewBucket>> = {\n low: { low: \"review\", medium: \"stamp\", high: \"stamp\" },\n medium: { low: \"review\", medium: \"review\", high: \"stamp\" },\n high: { low: \"blocked\", medium: \"review\", high: \"review\" },\n};\n\n/** Risk and confidence inputs used to derive a human-review bucket. */\nexport interface ChangeReviewFactors {\n risk: ChangeLevel;\n confidence: ChangeLevel;\n}\n\n/** Derives the default human-review bucket from a change's risk and confidence. */\nexport function changeReviewBucket(input: ChangeReviewFactors): ChangeReviewBucket {\n return bucketTable[input.risk][input.confidence];\n}\n\n/** Validated ledger rows used to derive Factory metrics and health. */\nexport interface DeliveryLedgerRows {\n changes: readonly Change[];\n signals: readonly Signal[];\n receipts: readonly Receipt[];\n tasks: readonly Task[];\n /** Validated graph snapshots keyed by rootTaskId. Missing snapshots make health yellow, never runnable. */\n graphs?: ReadonlyMap<string, TaskGraph>;\n}\n\n/** Options controlling ledger metric evaluation. */\nexport interface ComputeLedgerMetricsOptions {\n /** Evaluation time; defaults to the current time. */\n now?: Date;\n /** Days a landed change must hold without a rollback. Default 7. */\n holdDays?: number;\n}\n\n/** Product metrics derived deterministically from ledger rows. */\nexport interface DeliveryMetrics {\n /**\n * Changes a human merged that reached deployed (rolled_out for high risk)\n * and did not roll back within the hold window. Includes provisional ones.\n */\n landed: number;\n /** Landed changes still inside the hold window; the number may drop. */\n provisional: number;\n /** landed / (landed + rolled back + closed after ready). Null when nothing decided. */\n stickRate: number | null;\n /**\n * Not computable from ledger rows: needs a record of human commits pushed\n * to the pull request after ready, which nothing writes today.\n */\n stampedClean: null;\n /** Median ms from the ready receipt to the merged receipt, per review bucket. */\n humanTimeMs: { stamp: number | null; review: number | null };\n /** Sum of settled task cost over landed changes / landed. Null until budgets settle. */\n costPerLandedUsd: number | null;\n /** Signals triage turned away plus changes closed in verification. */\n filtered: number;\n}\n\ninterface ChangeFacts {\n change: Change;\n readyAt: number | null;\n mergedAt: number | null;\n reachedAt: number | null;\n rolledBackAt: number | null;\n}\n\nfunction collectFacts(rows: DeliveryLedgerRows): ChangeFacts[] {\n const byChange = new Map<string, Receipt[]>();\n for (const receipt of rows.receipts) {\n if (receipt.kind !== \"change\" || receipt.changeId === undefined) continue;\n const list = byChange.get(receipt.changeId) ?? [];\n list.push(receipt);\n byChange.set(receipt.changeId, list);\n }\n const at = (receipts: Receipt[] | undefined, state: string): number | null => {\n const found = receipts?.find((receipt) => receipt.state === state);\n return found === undefined ? null : Date.parse(found.recordedAt);\n };\n return rows.changes.map((change) => {\n const receipts = byChange.get(change.id);\n const requiredState = change.risk === \"high\" ? \"rolled_out\" : \"deployed\";\n return {\n change,\n readyAt: at(receipts, \"ready\"),\n mergedAt: at(receipts, \"merged\"),\n reachedAt: at(receipts, requiredState),\n rolledBackAt: at(receipts, \"rolled_back\"),\n };\n });\n}\n\n/** True for a change a human saw as ready and then closed unmerged. */\nfunction closedAfterReady(facts: ChangeFacts): boolean {\n return (\n facts.change.state === \"closed\" &&\n (facts.readyAt !== null || facts.change.decidedBy !== undefined)\n );\n}\n\nfunction median(values: number[]): number | null {\n if (values.length === 0) return null;\n const sorted = [...values].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;\n}\n\n/**\n * The six product metrics from ledger rows alone. One rule governs them: a\n * change counts only after a human merged it and it stayed. Activity that\n * never landed is not a result. Compute over rows already filtered to the\n * period and repositories you are reporting on.\n */\nexport function computeLedgerMetrics(\n rows: DeliveryLedgerRows,\n options: ComputeLedgerMetricsOptions = {},\n): DeliveryMetrics {\n const now = (options.now ?? new Date()).getTime();\n const holdMs = (options.holdDays ?? 7) * 24 * 60 * 60 * 1000;\n const facts = collectFacts(rows);\n\n let landed = 0;\n let provisional = 0;\n let rolledBack = 0;\n let closedAfterReadyCount = 0;\n let closedInVerification = 0;\n const landedChangeIds = new Set<string>();\n\n for (const fact of facts) {\n const { change } = fact;\n if (fact.rolledBackAt !== null) {\n rolledBack += 1;\n continue;\n }\n if (change.state === \"closed\") {\n if (closedAfterReady(fact)) closedAfterReadyCount += 1;\n else closedInVerification += 1;\n continue;\n }\n if (change.decidedBy !== undefined && fact.reachedAt !== null) {\n landed += 1;\n landedChangeIds.add(change.id);\n if (now - fact.reachedAt < holdMs) provisional += 1;\n }\n }\n\n const stickDenominator = landed + rolledBack + closedAfterReadyCount;\n const humanTimes: Record<\"stamp\" | \"review\", number[]> = { stamp: [], review: [] };\n for (const fact of facts) {\n if (fact.readyAt === null || fact.mergedAt === null) continue;\n const bucket = changeReviewBucket({\n risk: fact.change.risk,\n confidence: fact.change.confidence,\n });\n if (bucket === \"blocked\") continue;\n humanTimes[bucket].push(fact.mergedAt - fact.readyAt);\n }\n\n let settledOverLanded = 0;\n let sawSettledCost = false;\n for (const task of rows.tasks) {\n if (task.settledUsd === undefined) continue;\n if (\n task.kind === \"code_change\" &&\n task.changeId !== undefined &&\n landedChangeIds.has(task.changeId)\n ) {\n settledOverLanded += task.settledUsd;\n sawSettledCost = true;\n }\n }\n\n const rejectedSignals = rows.signals.filter(\n (signal) => signal.outcome !== \"pending\" && signal.outcome !== \"accepted\",\n ).length;\n\n return {\n landed,\n provisional,\n stickRate: stickDenominator === 0 ? null : landed / stickDenominator,\n stampedClean: null,\n humanTimeMs: { stamp: median(humanTimes.stamp), review: median(humanTimes.review) },\n costPerLandedUsd: sawSettledCost && landed > 0 ? settledOverLanded / landed : null,\n filtered: rejectedSignals + closedInVerification,\n };\n}\n\n/** Overall repository health severity derived from operational evidence. */\nexport type RepositoryHealthColor = \"green\" | \"yellow\" | \"red\";\n\n/** Options controlling repository health evaluation. */\nexport interface ComputeRepositoryHealthOptions {\n now?: Date;\n /** Open-change cap from factory configuration; omitted disables that check. */\n maxOpenChanges?: number;\n /** Minutes an eligible executable task may remain queued before health turns yellow. Default 5. */\n maxQueuedMinutes?: number;\n}\n\n/** Explainable repository health derived from ledger and graph state. */\nexport interface RepositoryHealth {\n readonly color: RepositoryHealthColor;\n /** Every rule that fired, so the color is explainable from rows. */\n readonly reasons: readonly string[];\n}\n\nconst openChangeStates = new Set([\"verifying\", \"ready\"]);\n\nfunction matchesGraphNode(task: Task, node: TaskGraphNode): boolean {\n return (\n task.id === node.taskId &&\n task.rootTaskId === node.admission.rootTaskId &&\n task.parentTaskId === node.parentTaskId &&\n task.repositoryIds.length === node.admission.repositoryIds.length &&\n task.repositoryIds.every((id, index) => id === node.admission.repositoryIds[index])\n );\n}\n\nfunction dependencyStatus(\n task: Task,\n tasks: ReadonlyMap<string, Task>,\n graphs: DeliveryLedgerRows[\"graphs\"],\n): \"ready\" | \"waiting\" | \"unknown\" {\n const graph = graphs?.get(task.rootTaskId);\n const node = graph?.nodes.find((entry) => entry.taskId === task.id);\n if (!graph || graph.rootTaskId !== task.rootTaskId || !node || !matchesGraphNode(task, node)) {\n return \"unknown\";\n }\n let ready = true;\n for (const id of node.dependencies) {\n const dependency = tasks.get(id);\n const dependencyNode = graph.nodes.find((entry) => entry.taskId === id);\n if (!dependency || !dependencyNode || !matchesGraphNode(dependency, dependencyNode))\n return \"unknown\";\n if (dependency.state !== \"succeeded\") ready = false;\n }\n return ready ? \"ready\" : \"waiting\";\n}\n\n/**\n * Green, yellow, or red from rows, never from a model. Budget threshold and\n * onboarding rules are not evaluated here yet: budget notices live on the\n * budgets collection (not in these rows), and onboarding investigations are\n * not recorded.\n */\nexport function computeRepositoryHealth(\n rows: DeliveryLedgerRows,\n options: ComputeRepositoryHealthOptions = {},\n): RepositoryHealth {\n const now = (options.now ?? new Date()).getTime();\n const dayMs = 24 * 60 * 60 * 1000;\n const red: string[] = [];\n const yellow: string[] = [];\n const tasksById = new Map(rows.tasks.map((task) => [task.id, task]));\n\n for (const receipt of rows.receipts) {\n if (now - Date.parse(receipt.recordedAt) >= dayMs) continue;\n if (receipt.state === \"rolled_back\")\n red.push(`rollback in the last 24h (${receipt.receiptId})`);\n if (receipt.state === \"cancelled\" && receipt.reason?.toLowerCase().includes(\"kill\")) {\n red.push(`kill in the last 24h (${receipt.receiptId})`);\n }\n }\n\n const openQuestions = rows.tasks.filter(\n (task) => task.kind === \"question\" && task.state === \"needs_human\",\n ).length;\n if (openQuestions > 0) yellow.push(`${openQuestions} open question(s)`);\n\n const needsHuman = rows.tasks.filter(\n (task) => task.kind !== \"question\" && task.state === \"needs_human\",\n ).length;\n if (needsHuman > 0) yellow.push(`${needsHuman} task(s) waiting on a human`);\n\n const maxQueuedMinutes = options.maxQueuedMinutes ?? 5;\n let staleQueued = 0;\n let unknownDependencies = 0;\n for (const task of rows.tasks) {\n const status = dependencyStatus(task, tasksById, rows.graphs);\n if (status === \"unknown\") unknownDependencies += 1;\n if (\n status === \"ready\" &&\n task.state === \"queued\" &&\n task.approval !== \"required\" &&\n task.approval !== \"denied\" &&\n now - Date.parse(task.updatedAt) >= maxQueuedMinutes * 60 * 1000\n )\n staleQueued += 1;\n }\n if (unknownDependencies > 0) {\n yellow.push(\n `${unknownDependencies} task(s) with missing or inconsistent graph/dependency snapshots`,\n );\n }\n if (staleQueued > 0) {\n yellow.push(`${staleQueued} eligible task(s) queued for at least ${maxQueuedMinutes} minutes`);\n }\n\n const blocked = rows.changes.filter(\n (change) =>\n openChangeStates.has(change.state) &&\n changeReviewBucket({ risk: change.risk, confidence: change.confidence }) === \"blocked\",\n ).length;\n if (blocked > 0) yellow.push(`${blocked} change(s) in the blocked bucket`);\n\n if (options.maxOpenChanges !== undefined) {\n const open = rows.changes.filter((change) => openChangeStates.has(change.state)).length;\n if (open >= options.maxOpenChanges) {\n yellow.push(`open changes at the cap (${open}/${options.maxOpenChanges})`);\n }\n }\n\n if (red.length > 0) return { color: \"red\", reasons: red };\n if (yellow.length > 0) return { color: \"yellow\", reasons: yellow };\n return { color: \"green\", reasons: [] };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { ChangeReviewBucket, ComputeLedgerMetricsOptions, ComputeRepositoryHealthOptions, DeliveryLedgerRows, DeliveryMetrics, RepositoryHealth, RepositoryHealthColor, changeReviewBucket, computeLedgerMetrics, computeRepositoryHealth } from "./delivery-metrics/metrics.mjs";
|
|
2
|
+
export { type ChangeReviewBucket, type ComputeLedgerMetricsOptions, type ComputeRepositoryHealthOptions, type DeliveryLedgerRows, type DeliveryMetrics, type RepositoryHealth, type RepositoryHealthColor, changeReviewBucket, computeLedgerMetrics, computeRepositoryHealth };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { TaskId } from "./schema/id.mjs";
|
|
2
|
+
import { AgentRouteBinding } from "./schema/agent-route.mjs";
|
|
3
|
+
import { ExecutionReference, Task } from "./schema/task.mjs";
|
|
4
|
+
import "./agent-routes.mjs";
|
|
5
|
+
import { DateClock } from "./schema/common.mjs";
|
|
6
|
+
import { BudgetLimits, BudgetMonth } from "./schema/budget.mjs";
|
|
7
|
+
import { FactoryStores } from "./store/engine.mjs";
|
|
8
|
+
//#region src/dispatch.d.ts
|
|
9
|
+
/** Minimal persistence capabilities required to gate and record one dispatch. */
|
|
10
|
+
type DispatchStores = Pick<FactoryStores, "graphs" | "receipts" | "tasks">;
|
|
11
|
+
/**
|
|
12
|
+
* The provider may have accepted the request, so the running attempt must remain available for
|
|
13
|
+
* recovery with its original launch key. Catchers must not queue a replacement attempt blindly.
|
|
14
|
+
*/
|
|
15
|
+
declare class ExecutionLaunchPendingError extends Error {}
|
|
16
|
+
/** Stable machine-readable reason a Task could not be dispatched. */
|
|
17
|
+
type DispatchRefusalCode = "route_mismatch" | "awaiting_approval" | "approval_denied" | "dependencies_unsatisfied" | "dispatch_race";
|
|
18
|
+
/** Non-terminal dispatch refusal that identifies the gated Task and retryable reason. */
|
|
19
|
+
declare class DispatchRefusedError extends Error {
|
|
20
|
+
/** Exact Task whose current dispatch attempt was refused. */
|
|
21
|
+
readonly taskId: TaskId;
|
|
22
|
+
/** Stable gate or race category suitable for branching and telemetry. */
|
|
23
|
+
readonly code: DispatchRefusalCode;
|
|
24
|
+
/** Human-readable refusal context; canonical Task state remains authoritative. */
|
|
25
|
+
readonly reason: string;
|
|
26
|
+
constructor(taskId: TaskId, code: DispatchRefusalCode, reason: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* An exhausted budget is definitive, not a retryable refusal: the task has
|
|
30
|
+
* already been failed and receipted when this throws, so it never re-enters
|
|
31
|
+
* the sweep. Operator retry recovers it once budget frees up.
|
|
32
|
+
*/
|
|
33
|
+
declare class BudgetExhaustedError extends Error {
|
|
34
|
+
/** Exact Task already transitioned to `failed` by the exhausted admission. */
|
|
35
|
+
readonly taskId: TaskId;
|
|
36
|
+
/** UTC budget month whose limit refused the reservation. */
|
|
37
|
+
readonly month: BudgetMonth;
|
|
38
|
+
/** Counted settled cost and live reservations observed for that month. */
|
|
39
|
+
readonly spendUsd: number;
|
|
40
|
+
constructor(taskId: TaskId, month: BudgetMonth, spendUsd: number);
|
|
41
|
+
}
|
|
42
|
+
/** Factory-wide reservation limits and snapshot used to gate one dispatch. */
|
|
43
|
+
interface DispatchBudget {
|
|
44
|
+
/** Factory-wide monthly ceiling and amount reserved for each admitted Task. */
|
|
45
|
+
limits: Pick<BudgetLimits, "totalUsd" | "perTaskReservationUsd">;
|
|
46
|
+
/** Defaults to true. False records reservations without enforcing the monthly ceiling. */
|
|
47
|
+
enforce?: boolean;
|
|
48
|
+
/** Defaults to the current UTC month. */
|
|
49
|
+
month?: BudgetMonth;
|
|
50
|
+
/** Clock used only to derive the reservation month and timestamp. Defaults to `new Date()`. */
|
|
51
|
+
now?: DateClock;
|
|
52
|
+
/** A dispatcher-wide snapshot used to calculate spend without another list. */
|
|
53
|
+
tasks?: readonly Task[];
|
|
54
|
+
}
|
|
55
|
+
interface DispatchContext {
|
|
56
|
+
/** Exact workflow-confirmed continuation attempt; other replacement attempts count as retries. */
|
|
57
|
+
continuationAttempt?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Maximum Task attempt number allowed for launch failure retries. Defaults to 45. A normal
|
|
60
|
+
* failure below the limit requeues the Task, which increments its attempt for the next sweep.
|
|
61
|
+
*/
|
|
62
|
+
maxLaunchAttempts?: number;
|
|
63
|
+
/** Reserve-before-execution policy for this dispatch. */
|
|
64
|
+
budget?: DispatchBudget;
|
|
65
|
+
}
|
|
66
|
+
/** Exact provider launch or explicit workflow-owned execution for one Task dispatch. */
|
|
67
|
+
type DispatchOptions = DispatchContext & ({
|
|
68
|
+
/** Required exact binding when the Task declares an agent route. */
|
|
69
|
+
route?: AgentRouteBinding;
|
|
70
|
+
/**
|
|
71
|
+
* Starts the durable execution for the task (an Eve agent run). Runs after
|
|
72
|
+
* the task has won the queued -> running transition. Its provider reference
|
|
73
|
+
* is mandatory so recovery can always find an accepted run.
|
|
74
|
+
*/
|
|
75
|
+
launch: (task: Task) => Promise<ExecutionReference>;
|
|
76
|
+
workflowOwned?: never;
|
|
77
|
+
} | {
|
|
78
|
+
/**
|
|
79
|
+
* Marks route-less work whose workflow advances the running Task without a provider
|
|
80
|
+
* session. The caller must schedule that workflow after this admission returns.
|
|
81
|
+
*/
|
|
82
|
+
workflowOwned: true;
|
|
83
|
+
route?: never;
|
|
84
|
+
launch?: never;
|
|
85
|
+
});
|
|
86
|
+
/** Task identity and exact launch mode supplied to one dispatch attempt. */
|
|
87
|
+
type DispatchTaskInput = {
|
|
88
|
+
readonly taskId: TaskId;
|
|
89
|
+
} & DispatchOptions;
|
|
90
|
+
/** Default launch-attempt allowance covering delayed identity provisioning. */
|
|
91
|
+
declare const DEFAULT_MAX_LAUNCH_ATTEMPTS = 45;
|
|
92
|
+
/**
|
|
93
|
+
* Claims one queued Task and starts its exact execution mode.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* Dispatch first checks route, approval, dependency, and optional budget gates, then atomically
|
|
97
|
+
* transitions the Task from `queued` to `running`. Only the winner invokes `launch`. A successful
|
|
98
|
+
* provider dispatch returns only after its execution reference is stored; it does not mean the
|
|
99
|
+
* Task completed. `workflowOwned: true` returns the claimed running Task without starting a
|
|
100
|
+
* provider session.
|
|
101
|
+
*
|
|
102
|
+
* An ordinary launch failure is rethrown after a best-effort transition back to `queued`, or to
|
|
103
|
+
* `failed` once `maxLaunchAttempts` is exhausted. `ExecutionLaunchPendingError` instead leaves the
|
|
104
|
+
* attempt running because the provider may have accepted the request; recovery must inspect or
|
|
105
|
+
* repeat the launch with the original idempotency key. Budget exhaustion fails and receipts the
|
|
106
|
+
* Task before throwing `BudgetExhaustedError`. Since compensating transitions are best-effort,
|
|
107
|
+
* callers handling any thrown launch error should reread canonical Task state before deciding
|
|
108
|
+
* whether to schedule another attempt.
|
|
109
|
+
*
|
|
110
|
+
* @param stores - Task, graph, and receipt stores that own the dispatch gates.
|
|
111
|
+
* @param input - Exact Task identity plus either a launcher or workflow-owned marker.
|
|
112
|
+
* @returns The running Task, including its durably recorded execution when a launcher was used.
|
|
113
|
+
* @throws `RecordNotFoundError` when the Task is absent.
|
|
114
|
+
* @throws `DispatchRefusedError` when routing, approval, dependencies, or a budget-admission race refuses dispatch.
|
|
115
|
+
* @throws `InvalidTransitionError` when the Task is no longer queued when this caller claims it.
|
|
116
|
+
* @throws `BudgetExhaustedError` after the Task has been failed because no reservation fits.
|
|
117
|
+
* @throws `ExecutionLaunchPendingError` when provider acceptance is ambiguous and requires recovery.
|
|
118
|
+
* @see The shipped `docs/recipes/eve-agent.md` and `docs/recipes/retry-recovery.md` recipes.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import {
|
|
123
|
+
* DispatchRefusedError,
|
|
124
|
+
* dispatchTask,
|
|
125
|
+
* type DispatchStores,
|
|
126
|
+
* } from "@vercel/factory/execution";
|
|
127
|
+
* import type { TaskId } from "@vercel/factory/tasks";
|
|
128
|
+
* import { parseAgentRouteBinding } from "@vercel/factory/workflows";
|
|
129
|
+
*
|
|
130
|
+
* declare const stores: DispatchStores;
|
|
131
|
+
* declare const taskId: TaskId;
|
|
132
|
+
* const route = parseAgentRouteBinding({ id: "worker", version: 1 });
|
|
133
|
+
*
|
|
134
|
+
* try {
|
|
135
|
+
* await dispatchTask(stores, {
|
|
136
|
+
* taskId,
|
|
137
|
+
* route,
|
|
138
|
+
* launch: async () => ({ provider: "eve", sessionId: "ses_example" }),
|
|
139
|
+
* });
|
|
140
|
+
* } catch (error) {
|
|
141
|
+
* if (error instanceof DispatchRefusedError) {
|
|
142
|
+
* // `error.code` identifies the gate; canonical Task state remains authoritative.
|
|
143
|
+
* } else {
|
|
144
|
+
* throw error;
|
|
145
|
+
* }
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function dispatchTask(stores: DispatchStores, input: DispatchTaskInput): Promise<Task>;
|
|
150
|
+
//#endregion
|
|
151
|
+
export { BudgetExhaustedError, DEFAULT_MAX_LAUNCH_ATTEMPTS, DispatchBudget, DispatchOptions, DispatchRefusalCode, DispatchRefusedError, DispatchStores, DispatchTaskInput, ExecutionLaunchPendingError, dispatchTask };
|
|
152
|
+
//# sourceMappingURL=dispatch.d.mts.map
|