@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,346 @@
|
|
|
1
|
+
import { outboxIdSchema, receiptIdSchema, taskIdSchema } from "../schema/id.mjs";
|
|
2
|
+
import { ApprovalAccessError, createApprovalAccess } from "../approval-access.mjs";
|
|
3
|
+
import { ApprovalError } from "../store/engine.mjs";
|
|
4
|
+
import { createOutboxCommunicationRouter } from "./outbox.mjs";
|
|
5
|
+
import { slackApprovalMessage, slackApprovalModal, slackApprovalPrefix, slackReasonAction, slackReasonBlock } from "./slack-approval-blocks.mjs";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/connectors/slack-approvals.ts
|
|
9
|
+
const slackId = z.string().regex(/^[A-Z][A-Z0-9]+$/u).describe("Slack provider identifier.");
|
|
10
|
+
const timestamp = z.string().regex(/^\d+\.\d+$/u).describe("Slack message timestamp.");
|
|
11
|
+
const targetSchema = z.strictObject({
|
|
12
|
+
channelId: slackId.describe("Channel receiving the approval message."),
|
|
13
|
+
threadTs: timestamp.optional().describe("Original thread, when work started in Slack.")
|
|
14
|
+
});
|
|
15
|
+
const metadataSchema = z.strictObject({
|
|
16
|
+
taskId: taskIdSchema.describe("Task addressed by the rejection modal."),
|
|
17
|
+
actor: z.string().min(1).describe("Actor that opened the modal; rechecked against the signed submitting actor."),
|
|
18
|
+
channelId: slackId,
|
|
19
|
+
messageTs: timestamp
|
|
20
|
+
});
|
|
21
|
+
const callbackSchema = z.looseObject({
|
|
22
|
+
type: z.enum(["block_actions", "view_submission"]).describe("Supported approval interaction."),
|
|
23
|
+
team: z.looseObject({ id: slackId }).describe("Workspace that hosts the app installation."),
|
|
24
|
+
user: z.looseObject({ id: slackId }).describe("Verified Slack user who interacted."),
|
|
25
|
+
channel: z.looseObject({ id: slackId }).optional().describe("Channel containing the clicked message."),
|
|
26
|
+
message: z.looseObject({ ts: timestamp }).optional().describe("Clicked message."),
|
|
27
|
+
trigger_id: z.string().min(1).optional().describe("Short-lived Slack modal trigger."),
|
|
28
|
+
actions: z.array(z.looseObject({
|
|
29
|
+
action_id: z.string().describe("Factory approval action."),
|
|
30
|
+
value: taskIdSchema.describe("Task associated with the clicked action.")
|
|
31
|
+
})).length(1).optional().describe("One explicit approval action."),
|
|
32
|
+
view: z.looseObject({
|
|
33
|
+
callback_id: z.string().describe("Modal callback identifier."),
|
|
34
|
+
private_metadata: z.string().describe("Task and originating message binding."),
|
|
35
|
+
state: z.looseObject({ values: z.record(z.string(), z.record(z.string(), z.looseObject({ value: z.string().nullable().optional().describe("Text input value.") }))) }).describe("Submitted modal fields.")
|
|
36
|
+
}).optional().describe("Submitted rejection modal.")
|
|
37
|
+
});
|
|
38
|
+
const receiptKey = (id) => `slack:approval:${id}`;
|
|
39
|
+
const receiptId = (key) => receiptIdSchema.parse(`rcpt_${createHash("sha256").update(`custom:${key}`).digest("hex").slice(0, 32)}`);
|
|
40
|
+
const outboxId = (key) => outboxIdSchema.parse(`out_${createHash("sha256").update(key).digest("hex").slice(0, 32)}`);
|
|
41
|
+
const waiting = (task) => task.approval === "required" && task.state === "queued";
|
|
42
|
+
const acknowledgement = () => new Response(null, { status: 200 });
|
|
43
|
+
/** Slack is a projection of the same Task decision used by HTTP clients. */
|
|
44
|
+
function createSlackApprovals(options) {
|
|
45
|
+
const { stores } = options;
|
|
46
|
+
const access = createApprovalAccess(options);
|
|
47
|
+
async function request(operation, body) {
|
|
48
|
+
const result = z.looseObject({ ok: z.literal(true) }).safeParse(await options.request(operation, body));
|
|
49
|
+
if (!result.success) throw new Error(`Slack ${operation} did not succeed`);
|
|
50
|
+
return result.data;
|
|
51
|
+
}
|
|
52
|
+
async function presented(id) {
|
|
53
|
+
return stores.receipts.get(receiptId(receiptKey(id)));
|
|
54
|
+
}
|
|
55
|
+
function target(task) {
|
|
56
|
+
if (task.replyTo.channel === "slack") {
|
|
57
|
+
const [channelId, threadTs] = task.replyTo.address.split(":");
|
|
58
|
+
return targetSchema.parse({
|
|
59
|
+
channelId,
|
|
60
|
+
threadTs
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return options.approvalChannel ? targetSchema.parse({ channelId: options.approvalChannel }) : null;
|
|
64
|
+
}
|
|
65
|
+
async function enqueue(task, existing) {
|
|
66
|
+
const destination = existing?.delivery ? targetSchema.parse({ channelId: existing.delivery.replyTo.address.split(":")[0] }) : target(task);
|
|
67
|
+
if (!destination) return null;
|
|
68
|
+
const decision = await stores.tasks.approvalReceipt(task.id);
|
|
69
|
+
const suffix = existing ? `${decision?.receiptId ?? "closed"}:${task.approval}:${task.state}` : "present";
|
|
70
|
+
return (await stores.outbox.enqueue({
|
|
71
|
+
eventId: `${receiptKey(task.id)}:${suffix}`,
|
|
72
|
+
repositoryIds: task.repositoryIds,
|
|
73
|
+
taskId: task.id,
|
|
74
|
+
replyTo: {
|
|
75
|
+
channel: "slack",
|
|
76
|
+
address: existing?.delivery?.replyTo.address ?? `${destination.channelId}:${destination.threadTs ?? ""}`
|
|
77
|
+
},
|
|
78
|
+
outcome: "needs_human",
|
|
79
|
+
data: {
|
|
80
|
+
factoryApproval: true,
|
|
81
|
+
target: destination
|
|
82
|
+
}
|
|
83
|
+
})).event;
|
|
84
|
+
}
|
|
85
|
+
async function reconcile(tasks) {
|
|
86
|
+
let queued = 0;
|
|
87
|
+
for (const task of tasks) {
|
|
88
|
+
if (task.approval === void 0) continue;
|
|
89
|
+
try {
|
|
90
|
+
await access.view(task);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof ApprovalAccessError) continue;
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
const existing = await presented(task.id);
|
|
96
|
+
if ((existing || waiting(task)) && await enqueue(task, existing)) queued++;
|
|
97
|
+
}
|
|
98
|
+
return queued;
|
|
99
|
+
}
|
|
100
|
+
async function deliver(event) {
|
|
101
|
+
if (event.data.factoryApproval !== true || event.replyTo.channel !== "slack" || !event.taskId) throw new Error("Expected a Slack approval notification");
|
|
102
|
+
const task = await stores.tasks.get(event.taskId);
|
|
103
|
+
if (!task || task.approval === void 0) return;
|
|
104
|
+
let view;
|
|
105
|
+
try {
|
|
106
|
+
view = await access.view(task);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof ApprovalAccessError) return;
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
const existing = await presented(task.id);
|
|
112
|
+
if (existing?.delivery) {
|
|
113
|
+
if (z.looseObject({ team_id: slackId }).parse(await request("auth.test", {})).team_id !== existing.delivery.workspaceId) throw new Error("Slack approval message belongs to another workspace");
|
|
114
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
115
|
+
await request("chat.update", {
|
|
116
|
+
channel: existing.delivery.replyTo.address.split(":")[0],
|
|
117
|
+
ts: existing.delivery.messageId,
|
|
118
|
+
...slackApprovalMessage(view),
|
|
119
|
+
unfurl_links: false,
|
|
120
|
+
unfurl_media: false
|
|
121
|
+
});
|
|
122
|
+
const latest = await stores.tasks.get(task.id);
|
|
123
|
+
if (!latest) return;
|
|
124
|
+
let current;
|
|
125
|
+
try {
|
|
126
|
+
current = await access.view(latest);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error instanceof ApprovalAccessError) return;
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
if (current.decision?.receiptId === view.decision?.receiptId && latest.state === view.task.state && latest.approval === view.task.approval) return;
|
|
132
|
+
view = current;
|
|
133
|
+
}
|
|
134
|
+
throw new Error("Task changed while updating its approval message; retry the current projection");
|
|
135
|
+
}
|
|
136
|
+
const delivery = await stores.outbox.get(outboxId(event.eventId));
|
|
137
|
+
if (!waiting(task) && (!delivery || delivery.attempt < 2)) return;
|
|
138
|
+
const destination = targetSchema.parse(event.data.target);
|
|
139
|
+
const configured = target(task);
|
|
140
|
+
if (!configured || configured.channelId !== destination.channelId || configured.threadTs !== destination.threadTs) throw new Error("Approval destination changed; the recorded notification cannot be rerouted");
|
|
141
|
+
const identity = z.looseObject({ team_id: slackId }).parse(await request("auth.test", {}));
|
|
142
|
+
const hash = createHash("sha256").update(receiptKey(task.id)).digest("hex").slice(0, 32);
|
|
143
|
+
const clientMessageId = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20)}`;
|
|
144
|
+
let messageId;
|
|
145
|
+
if (delivery && delivery.attempt > 1) {
|
|
146
|
+
let cursor;
|
|
147
|
+
for (let page = 0; page < 5; page++) {
|
|
148
|
+
const history = z.looseObject({
|
|
149
|
+
messages: z.array(z.looseObject({
|
|
150
|
+
ts: timestamp,
|
|
151
|
+
client_msg_id: z.string().optional()
|
|
152
|
+
})),
|
|
153
|
+
response_metadata: z.looseObject({ next_cursor: z.string().optional() }).optional(),
|
|
154
|
+
has_more: z.boolean().optional()
|
|
155
|
+
}).parse(await request(destination.threadTs ? "conversations.replies" : "conversations.history", {
|
|
156
|
+
channel: destination.channelId,
|
|
157
|
+
...destination.threadTs ? { ts: destination.threadTs } : {},
|
|
158
|
+
oldest: String(Date.parse(delivery.createdAt) / 1e3 - 5),
|
|
159
|
+
limit: 100,
|
|
160
|
+
...cursor ? { cursor } : {}
|
|
161
|
+
}));
|
|
162
|
+
messageId = history.messages.find((message) => message.client_msg_id === clientMessageId)?.ts;
|
|
163
|
+
if (messageId) break;
|
|
164
|
+
cursor = history.response_metadata?.next_cursor || void 0;
|
|
165
|
+
if (!cursor) {
|
|
166
|
+
if (history.has_more) throw new Error("Slack approval history was incomplete; retry before posting again");
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
if (page === 4) throw new Error("Slack approval recovery exceeded its history window; retry before posting again");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (!messageId && !waiting(task)) return;
|
|
173
|
+
const result = messageId ? { ts: messageId } : z.looseObject({ ts: timestamp }).parse(await request("chat.postMessage", {
|
|
174
|
+
channel: destination.channelId,
|
|
175
|
+
...destination.threadTs ? { thread_ts: destination.threadTs } : {},
|
|
176
|
+
...slackApprovalMessage(view),
|
|
177
|
+
unfurl_links: false,
|
|
178
|
+
unfurl_media: false,
|
|
179
|
+
client_msg_id: clientMessageId
|
|
180
|
+
}));
|
|
181
|
+
await stores.receipts.append({
|
|
182
|
+
dedupeKey: receiptKey(task.id),
|
|
183
|
+
repositoryIds: task.repositoryIds,
|
|
184
|
+
taskId: task.id,
|
|
185
|
+
kind: task.kind,
|
|
186
|
+
state: "approval_presented",
|
|
187
|
+
phase: "communication",
|
|
188
|
+
delivery: {
|
|
189
|
+
replyTo: {
|
|
190
|
+
channel: "slack",
|
|
191
|
+
address: `${destination.channelId}:${destination.threadTs ?? result.ts}`
|
|
192
|
+
},
|
|
193
|
+
messageId: result.ts,
|
|
194
|
+
workspaceId: identity.team_id
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
await deliver(event);
|
|
198
|
+
}
|
|
199
|
+
async function binding(payload, id, channelId, messageTs) {
|
|
200
|
+
const actor = `slack:${payload.team.id}:${payload.user.id}`;
|
|
201
|
+
const taskId = taskIdSchema.parse(id);
|
|
202
|
+
const view = await access.get(actor, taskId);
|
|
203
|
+
const receipt = await presented(taskId);
|
|
204
|
+
if (!receipt?.delivery || receipt.delivery.workspaceId !== payload.team.id || receipt.delivery.replyTo.channel !== "slack" || receipt.delivery.replyTo.address.split(":")[0] !== channelId || receipt.delivery.messageId !== messageTs) throw new ApprovalAccessError(403, "This interaction does not match the recorded approval message");
|
|
205
|
+
return view;
|
|
206
|
+
}
|
|
207
|
+
const deliveryRouter = createOutboxCommunicationRouter({
|
|
208
|
+
stores,
|
|
209
|
+
router: {
|
|
210
|
+
channels: ["slack"],
|
|
211
|
+
deliver
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
async function refresh(task) {
|
|
215
|
+
const event = await enqueue(task, await presented(task.id));
|
|
216
|
+
if (event) await deliveryRouter.deliver(event);
|
|
217
|
+
}
|
|
218
|
+
async function updatePresented(taskId) {
|
|
219
|
+
if (!(await presented(taskId))?.delivery) return false;
|
|
220
|
+
const task = await stores.tasks.get(taskId);
|
|
221
|
+
if (!task) return false;
|
|
222
|
+
await refresh(task);
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
async function click(payload) {
|
|
226
|
+
const actor = `slack:${payload.team.id}:${payload.user.id}`;
|
|
227
|
+
const action = payload.actions?.[0];
|
|
228
|
+
if (!action || !payload.channel || !payload.message) throw new ApprovalAccessError(400, "Approval action is missing its message binding");
|
|
229
|
+
const view = await binding(payload, action.value, payload.channel.id, payload.message.ts);
|
|
230
|
+
const kind = action.action_id.slice(slackApprovalPrefix.length);
|
|
231
|
+
if (kind === "approve" || kind === "retry") {
|
|
232
|
+
const decision = kind === "retry" ? view.decision : null;
|
|
233
|
+
if (kind === "retry" && (!decision || decision.decidedBy !== actor)) throw new ApprovalAccessError(403, "Only the original operator can finish this decision");
|
|
234
|
+
await refresh((await access.decide({
|
|
235
|
+
actor,
|
|
236
|
+
taskId: view.task.id,
|
|
237
|
+
action: decision?.state === "rejected" ? "reject" : "approve",
|
|
238
|
+
input: { reason: decision?.reason }
|
|
239
|
+
})).task);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (![
|
|
243
|
+
"reject",
|
|
244
|
+
"evidence",
|
|
245
|
+
"decision"
|
|
246
|
+
].includes(kind) || !payload.trigger_id) throw new ApprovalAccessError(400, "Unsupported approval action or missing modal trigger");
|
|
247
|
+
if (kind === "reject" && !waiting(view.task)) {
|
|
248
|
+
await refresh(view.task);
|
|
249
|
+
throw new ApprovalAccessError(409, "This proposal already has a decision or is no longer awaiting approval");
|
|
250
|
+
}
|
|
251
|
+
const metadata = JSON.stringify({
|
|
252
|
+
taskId: view.task.id,
|
|
253
|
+
actor,
|
|
254
|
+
channelId: payload.channel.id,
|
|
255
|
+
messageTs: payload.message.ts
|
|
256
|
+
});
|
|
257
|
+
await request("views.open", {
|
|
258
|
+
trigger_id: payload.trigger_id,
|
|
259
|
+
view: slackApprovalModal(view, kind === "reject" ? "reject" : kind === "decision" ? "decision" : "evidence", metadata)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
async function clickWithFeedback(payload) {
|
|
263
|
+
try {
|
|
264
|
+
await click(payload);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
options.reportError?.(error);
|
|
267
|
+
if (!payload.channel) return;
|
|
268
|
+
const known = error instanceof ApprovalAccessError || error instanceof ApprovalError;
|
|
269
|
+
try {
|
|
270
|
+
await request("chat.postEphemeral", {
|
|
271
|
+
channel: payload.channel.id,
|
|
272
|
+
user: payload.user.id,
|
|
273
|
+
text: known ? error.message : "The request could not finish. Retry the same action; an already recorded decision will not be duplicated."
|
|
274
|
+
});
|
|
275
|
+
} catch (feedbackError) {
|
|
276
|
+
options.reportError?.(feedbackError);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async function submit(payload, waitUntil) {
|
|
281
|
+
try {
|
|
282
|
+
if (!payload.view) throw new ApprovalAccessError(400, "Missing rejection modal");
|
|
283
|
+
const metadata = metadataSchema.parse(JSON.parse(payload.view.private_metadata));
|
|
284
|
+
const actor = `slack:${payload.team.id}:${payload.user.id}`;
|
|
285
|
+
if (metadata.actor !== actor) throw new ApprovalAccessError(403, "Only the operator who opened this modal can submit it");
|
|
286
|
+
await binding(payload, metadata.taskId, metadata.channelId, metadata.messageTs);
|
|
287
|
+
const reason = payload.view.state.values[slackReasonBlock]?.[slackReasonAction]?.value?.trim();
|
|
288
|
+
if (!reason) throw new ApprovalAccessError(400, "Add a reason before rejecting this proposal");
|
|
289
|
+
const updated = await access.decide({
|
|
290
|
+
actor,
|
|
291
|
+
taskId: metadata.taskId,
|
|
292
|
+
action: "reject",
|
|
293
|
+
input: { reason }
|
|
294
|
+
});
|
|
295
|
+
const event = await enqueue(updated.task, await presented(updated.task.id));
|
|
296
|
+
if (event) waitUntil(deliveryRouter.deliver(event).catch((error) => {
|
|
297
|
+
options.reportError?.(error);
|
|
298
|
+
}));
|
|
299
|
+
return acknowledgement();
|
|
300
|
+
} catch (error) {
|
|
301
|
+
options.reportError?.(error);
|
|
302
|
+
return Response.json({
|
|
303
|
+
response_action: "errors",
|
|
304
|
+
errors: { [slackReasonBlock]: error instanceof ApprovalAccessError || error instanceof ApprovalError ? error.message : "Could not finish. Submit again with the same reason to recover the decision." }
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async function handle(request, waitUntil) {
|
|
309
|
+
if (request.method !== "POST" || !request.headers.get("content-type")?.includes("application/x-www-form-urlencoded")) return null;
|
|
310
|
+
const raw = await request.clone().text();
|
|
311
|
+
if (raw.length > 256e3) return new Response("Payload too large", { status: 413 });
|
|
312
|
+
let input;
|
|
313
|
+
try {
|
|
314
|
+
input = JSON.parse(new URLSearchParams(raw).get("payload") ?? "null");
|
|
315
|
+
} catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
const route = z.looseObject({
|
|
319
|
+
type: z.string().optional(),
|
|
320
|
+
actions: z.array(z.looseObject({ action_id: z.string() })).optional(),
|
|
321
|
+
view: z.looseObject({ callback_id: z.string() }).optional()
|
|
322
|
+
}).safeParse(input);
|
|
323
|
+
if (!route.success || !(route.data.actions?.some((action) => action.action_id.startsWith("factory_approval:")) || route.data.view?.callback_id === "factory_approval_reject")) return null;
|
|
324
|
+
try {
|
|
325
|
+
await options.verify(request, raw);
|
|
326
|
+
} catch {
|
|
327
|
+
return new Response("unauthorized", { status: 401 });
|
|
328
|
+
}
|
|
329
|
+
const parsed = callbackSchema.safeParse(input);
|
|
330
|
+
if (!parsed.success) return new Response("Invalid approval interaction", { status: 400 });
|
|
331
|
+
const payload = parsed.data;
|
|
332
|
+
if (payload.type === "view_submission") return submit(payload, waitUntil);
|
|
333
|
+
waitUntil(clickWithFeedback(payload));
|
|
334
|
+
return acknowledgement();
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
handle,
|
|
338
|
+
reconcile,
|
|
339
|
+
deliver,
|
|
340
|
+
updatePresented
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
//#endregion
|
|
344
|
+
export { createSlackApprovals };
|
|
345
|
+
|
|
346
|
+
//# sourceMappingURL=slack-approvals.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-approvals.mjs","names":[],"sources":["../../src/connectors/slack-approvals.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\nimport {\n ApprovalAccessError,\n createApprovalAccess,\n type ApprovalAccessOptions,\n type ApprovalAccessStores,\n} from \"../approval-access\";\nimport type { ApprovalView } from \"../approval-contracts\";\nimport type { CommunicationEvent } from \"../schema/communication\";\nimport { taskIdSchema, type TaskId } from \"../schema/id\";\nimport { outboxIdSchema, receiptIdSchema, type OutboxId, type ReceiptId } from \"../schema/id\";\nimport type { Receipt } from \"../schema/receipt\";\nimport type { Task } from \"../schema/task\";\nimport { ApprovalError } from \"../store/engine\";\nimport type { FactoryStores } from \"../store/engine\";\nimport {\n slackApprovalMessage,\n slackApprovalModal,\n slackApprovalPrefix,\n slackRejectionCallback,\n slackReasonAction,\n slackReasonBlock,\n} from \"./slack-approval-blocks\";\nimport { createOutboxCommunicationRouter } from \"./outbox\";\n\nconst slackId = z\n .string()\n .regex(/^[A-Z][A-Z0-9]+$/u)\n .describe(\"Slack provider identifier.\");\nconst timestamp = z\n .string()\n .regex(/^\\d+\\.\\d+$/u)\n .describe(\"Slack message timestamp.\");\nconst targetSchema = z.strictObject({\n channelId: slackId.describe(\"Channel receiving the approval message.\"),\n threadTs: timestamp.optional().describe(\"Original thread, when work started in Slack.\"),\n});\nconst metadataSchema = z.strictObject({\n taskId: taskIdSchema.describe(\"Task addressed by the rejection modal.\"),\n actor: z\n .string()\n .min(1)\n .describe(\"Actor that opened the modal; rechecked against the signed submitting actor.\"),\n channelId: slackId,\n messageTs: timestamp,\n});\nconst callbackSchema = z.looseObject({\n type: z.enum([\"block_actions\", \"view_submission\"]).describe(\"Supported approval interaction.\"),\n team: z.looseObject({ id: slackId }).describe(\"Workspace that hosts the app installation.\"),\n user: z.looseObject({ id: slackId }).describe(\"Verified Slack user who interacted.\"),\n channel: z\n .looseObject({ id: slackId })\n .optional()\n .describe(\"Channel containing the clicked message.\"),\n message: z.looseObject({ ts: timestamp }).optional().describe(\"Clicked message.\"),\n trigger_id: z.string().min(1).optional().describe(\"Short-lived Slack modal trigger.\"),\n actions: z\n .array(\n z.looseObject({\n action_id: z.string().describe(\"Factory approval action.\"),\n value: taskIdSchema.describe(\"Task associated with the clicked action.\"),\n }),\n )\n .length(1)\n .optional()\n .describe(\"One explicit approval action.\"),\n view: z\n .looseObject({\n callback_id: z.string().describe(\"Modal callback identifier.\"),\n private_metadata: z.string().describe(\"Task and originating message binding.\"),\n state: z\n .looseObject({\n values: z.record(\n z.string(),\n z.record(\n z.string(),\n z.looseObject({\n value: z.string().nullable().optional().describe(\"Text input value.\"),\n }),\n ),\n ),\n })\n .describe(\"Submitted modal fields.\"),\n })\n .optional()\n .describe(\"Submitted rejection modal.\"),\n});\ntype Callback = z.infer<typeof callbackSchema>;\ntype Target = z.infer<typeof targetSchema>;\n\n/** Store capabilities required to present and decide Slack approvals. */\nexport type SlackApprovalsStores = ApprovalAccessStores &\n Pick<FactoryStores, \"outbox\" | \"receipts\">;\n\n/** Configures authenticated Slack presentation and handling for durable Task approvals. */\nexport interface SlackApprovalsOptions extends Omit<ApprovalAccessOptions, \"stores\"> {\n readonly stores: SlackApprovalsStores;\n /** Explicit fallback destination for work with no Slack reply thread. */\n approvalChannel?: string;\n request(operation: string, body: unknown): Promise<unknown>;\n /** Authenticate the original request and body before accepting any interaction. */\n verify(request: Request, body: string): Promise<void>;\n reportError?(error: unknown): void;\n}\n\n/** Slack approval projection, interaction handler, and reconciliation operations. */\nexport interface SlackApprovals {\n handle(request: Request, waitUntil: (task: Promise<unknown>) => void): Promise<Response | null>;\n reconcile(tasks: readonly Task[]): Promise<number>;\n deliver(event: CommunicationEvent): Promise<void>;\n updatePresented(taskId: Task[\"id\"]): Promise<boolean>;\n}\n\nconst receiptKey = (id: string) => `slack:approval:${id}`;\nconst receiptId = (key: string): ReceiptId =>\n receiptIdSchema.parse(\n `rcpt_${createHash(\"sha256\").update(`custom:${key}`).digest(\"hex\").slice(0, 32)}`,\n );\nconst outboxId = (key: string): OutboxId =>\n outboxIdSchema.parse(`out_${createHash(\"sha256\").update(key).digest(\"hex\").slice(0, 32)}`);\nconst waiting = (task: Task) => task.approval === \"required\" && task.state === \"queued\";\nconst acknowledgement = () => new Response(null, { status: 200 });\n\n/** Slack is a projection of the same Task decision used by HTTP clients. */\nexport function createSlackApprovals(options: SlackApprovalsOptions): SlackApprovals {\n const { stores } = options;\n const access = createApprovalAccess(options);\n async function request(operation: string, body: unknown) {\n const result = z\n .looseObject({ ok: z.literal(true) })\n .safeParse(await options.request(operation, body));\n if (!result.success) throw new Error(`Slack ${operation} did not succeed`);\n return result.data;\n }\n async function presented(id: TaskId) {\n return stores.receipts.get(receiptId(receiptKey(id)));\n }\n function target(task: Task): Target | null {\n if (task.replyTo.channel === \"slack\") {\n const [channelId, threadTs] = task.replyTo.address.split(\":\");\n return targetSchema.parse({ channelId, threadTs });\n }\n return options.approvalChannel\n ? targetSchema.parse({ channelId: options.approvalChannel })\n : null;\n }\n async function enqueue(task: Task, existing: Receipt | null) {\n const destination = existing?.delivery\n ? targetSchema.parse({ channelId: existing.delivery.replyTo.address.split(\":\")[0] })\n : target(task);\n if (!destination) return null;\n const decision = await stores.tasks.approvalReceipt(task.id);\n const suffix = existing\n ? `${decision?.receiptId ?? \"closed\"}:${task.approval}:${task.state}`\n : \"present\";\n const saved = await stores.outbox.enqueue({\n eventId: `${receiptKey(task.id)}:${suffix}`,\n repositoryIds: task.repositoryIds,\n taskId: task.id,\n replyTo: {\n channel: \"slack\",\n address:\n existing?.delivery?.replyTo.address ??\n `${destination.channelId}:${destination.threadTs ?? \"\"}`,\n },\n outcome: \"needs_human\",\n data: { factoryApproval: true, target: destination },\n });\n return saved.event;\n }\n async function reconcile(tasks: readonly Task[]) {\n let queued = 0;\n for (const task of tasks) {\n if (task.approval === undefined) continue;\n try {\n await access.view(task);\n } catch (error) {\n if (error instanceof ApprovalAccessError) continue;\n throw error;\n }\n const existing = await presented(task.id);\n if ((existing || waiting(task)) && (await enqueue(task, existing))) queued++;\n }\n return queued;\n }\n async function deliver(event: CommunicationEvent): Promise<void> {\n if (event.data.factoryApproval !== true || event.replyTo.channel !== \"slack\" || !event.taskId)\n throw new Error(\"Expected a Slack approval notification\");\n const task = await stores.tasks.get(event.taskId);\n if (!task || task.approval === undefined) return;\n let view: ApprovalView;\n try {\n view = await access.view(task);\n } catch (error) {\n if (error instanceof ApprovalAccessError) return;\n throw error;\n }\n const existing = await presented(task.id);\n if (existing?.delivery) {\n const identity = z.looseObject({ team_id: slackId }).parse(await request(\"auth.test\", {}));\n if (identity.team_id !== existing.delivery.workspaceId)\n throw new Error(\"Slack approval message belongs to another workspace\");\n for (let attempt = 0; attempt < 3; attempt++) {\n await request(\"chat.update\", {\n channel: existing.delivery.replyTo.address.split(\":\")[0],\n ts: existing.delivery.messageId,\n ...slackApprovalMessage(view),\n unfurl_links: false,\n unfurl_media: false,\n });\n const latest = await stores.tasks.get(task.id);\n if (!latest) return;\n let current: ApprovalView;\n try {\n current = await access.view(latest);\n } catch (error) {\n if (error instanceof ApprovalAccessError) return;\n throw error;\n }\n if (\n current.decision?.receiptId === view.decision?.receiptId &&\n latest.state === view.task.state &&\n latest.approval === view.task.approval\n )\n return;\n view = current;\n }\n throw new Error(\n \"Task changed while updating its approval message; retry the current projection\",\n );\n }\n const delivery = await stores.outbox.get(outboxId(event.eventId));\n if (!waiting(task) && (!delivery || delivery.attempt < 2)) return;\n const destination = targetSchema.parse(event.data.target);\n const configured = target(task);\n if (\n !configured ||\n configured.channelId !== destination.channelId ||\n configured.threadTs !== destination.threadTs\n )\n throw new Error(\"Approval destination changed; the recorded notification cannot be rerouted\");\n const identity = z.looseObject({ team_id: slackId }).parse(await request(\"auth.test\", {}));\n const hash = createHash(\"sha256\").update(receiptKey(task.id)).digest(\"hex\").slice(0, 32);\n const clientMessageId = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20)}`;\n let messageId: string | undefined;\n if (delivery && delivery.attempt > 1) {\n let cursor: string | undefined;\n for (let page = 0; page < 5; page++) {\n const history = z\n .looseObject({\n messages: z.array(\n z.looseObject({ ts: timestamp, client_msg_id: z.string().optional() }),\n ),\n response_metadata: z.looseObject({ next_cursor: z.string().optional() }).optional(),\n has_more: z.boolean().optional(),\n })\n .parse(\n await request(\n destination.threadTs ? \"conversations.replies\" : \"conversations.history\",\n {\n channel: destination.channelId,\n ...(destination.threadTs ? { ts: destination.threadTs } : {}),\n oldest: String(Date.parse(delivery.createdAt) / 1000 - 5),\n limit: 100,\n ...(cursor ? { cursor } : {}),\n },\n ),\n );\n messageId = history.messages.find(\n (message) => message.client_msg_id === clientMessageId,\n )?.ts;\n if (messageId) break;\n cursor = history.response_metadata?.next_cursor || undefined;\n if (!cursor) {\n if (history.has_more)\n throw new Error(\"Slack approval history was incomplete; retry before posting again\");\n break;\n }\n if (page === 4)\n throw new Error(\n \"Slack approval recovery exceeded its history window; retry before posting again\",\n );\n }\n }\n if (!messageId && !waiting(task)) return;\n const result = messageId\n ? { ts: messageId }\n : z.looseObject({ ts: timestamp }).parse(\n await request(\"chat.postMessage\", {\n channel: destination.channelId,\n ...(destination.threadTs ? { thread_ts: destination.threadTs } : {}),\n ...slackApprovalMessage(view),\n unfurl_links: false,\n unfurl_media: false,\n client_msg_id: clientMessageId,\n }),\n );\n await stores.receipts.append({\n dedupeKey: receiptKey(task.id),\n repositoryIds: task.repositoryIds,\n taskId: task.id,\n kind: task.kind,\n state: \"approval_presented\",\n phase: \"communication\",\n delivery: {\n replyTo: {\n channel: \"slack\",\n address: `${destination.channelId}:${destination.threadTs ?? result.ts}`,\n },\n messageId: result.ts,\n workspaceId: identity.team_id,\n },\n });\n await deliver(event);\n }\n async function binding(\n payload: Callback,\n id: string,\n channelId: string,\n messageTs: string,\n ): Promise<ApprovalView> {\n const actor = `slack:${payload.team.id}:${payload.user.id}`;\n const taskId = taskIdSchema.parse(id);\n const view = await access.get(actor, taskId);\n const receipt = await presented(taskId);\n if (\n !receipt?.delivery ||\n receipt.delivery.workspaceId !== payload.team.id ||\n receipt.delivery.replyTo.channel !== \"slack\" ||\n receipt.delivery.replyTo.address.split(\":\")[0] !== channelId ||\n receipt.delivery.messageId !== messageTs\n ) {\n throw new ApprovalAccessError(\n 403,\n \"This interaction does not match the recorded approval message\",\n );\n }\n return view;\n }\n const deliveryRouter = createOutboxCommunicationRouter({\n stores,\n router: { channels: [\"slack\"], deliver },\n });\n async function refresh(task: Task) {\n const event = await enqueue(task, await presented(task.id));\n if (event) await deliveryRouter.deliver(event);\n }\n async function updatePresented(taskId: Task[\"id\"]): Promise<boolean> {\n if (!(await presented(taskId))?.delivery) return false;\n const task = await stores.tasks.get(taskId);\n if (!task) return false;\n await refresh(task);\n return true;\n }\n async function click(payload: Callback) {\n const actor = `slack:${payload.team.id}:${payload.user.id}`;\n const action = payload.actions?.[0];\n if (!action || !payload.channel || !payload.message)\n throw new ApprovalAccessError(400, \"Approval action is missing its message binding\");\n const view = await binding(payload, action.value, payload.channel.id, payload.message.ts);\n const kind = action.action_id.slice(slackApprovalPrefix.length);\n if (kind === \"approve\" || kind === \"retry\") {\n const decision = kind === \"retry\" ? view.decision : null;\n if (kind === \"retry\" && (!decision || decision.decidedBy !== actor))\n throw new ApprovalAccessError(403, \"Only the original operator can finish this decision\");\n const updated = await access.decide({\n actor,\n taskId: view.task.id,\n action: decision?.state === \"rejected\" ? \"reject\" : \"approve\",\n input: { reason: decision?.reason },\n });\n await refresh(updated.task);\n return;\n }\n if (![\"reject\", \"evidence\", \"decision\"].includes(kind) || !payload.trigger_id)\n throw new ApprovalAccessError(400, \"Unsupported approval action or missing modal trigger\");\n if (kind === \"reject\" && !waiting(view.task)) {\n await refresh(view.task);\n throw new ApprovalAccessError(\n 409,\n \"This proposal already has a decision or is no longer awaiting approval\",\n );\n }\n const metadata = JSON.stringify({\n taskId: view.task.id,\n actor,\n channelId: payload.channel.id,\n messageTs: payload.message.ts,\n });\n await request(\"views.open\", {\n trigger_id: payload.trigger_id,\n view: slackApprovalModal(\n view,\n kind === \"reject\" ? \"reject\" : kind === \"decision\" ? \"decision\" : \"evidence\",\n metadata,\n ),\n });\n }\n async function clickWithFeedback(payload: Callback) {\n try {\n await click(payload);\n } catch (error) {\n options.reportError?.(error);\n if (!payload.channel) return;\n const known = error instanceof ApprovalAccessError || error instanceof ApprovalError;\n try {\n await request(\"chat.postEphemeral\", {\n channel: payload.channel.id,\n user: payload.user.id,\n text: known\n ? error.message\n : \"The request could not finish. Retry the same action; an already recorded decision will not be duplicated.\",\n });\n } catch (feedbackError) {\n options.reportError?.(feedbackError);\n }\n }\n }\n async function submit(\n payload: Callback,\n waitUntil: (task: Promise<unknown>) => void,\n ): Promise<Response> {\n try {\n if (!payload.view) throw new ApprovalAccessError(400, \"Missing rejection modal\");\n const metadata = metadataSchema.parse(JSON.parse(payload.view.private_metadata));\n const actor = `slack:${payload.team.id}:${payload.user.id}`;\n if (metadata.actor !== actor)\n throw new ApprovalAccessError(403, \"Only the operator who opened this modal can submit it\");\n await binding(payload, metadata.taskId, metadata.channelId, metadata.messageTs);\n const reason =\n payload.view.state.values[slackReasonBlock]?.[slackReasonAction]?.value?.trim();\n if (!reason)\n throw new ApprovalAccessError(400, \"Add a reason before rejecting this proposal\");\n const updated = await access.decide({\n actor,\n taskId: metadata.taskId,\n action: \"reject\",\n input: { reason },\n });\n const event = await enqueue(updated.task, await presented(updated.task.id));\n if (event)\n waitUntil(\n deliveryRouter.deliver(event).catch((error: unknown) => {\n options.reportError?.(error);\n }),\n );\n return acknowledgement();\n } catch (error) {\n options.reportError?.(error);\n return Response.json({\n response_action: \"errors\",\n errors: {\n [slackReasonBlock]:\n error instanceof ApprovalAccessError || error instanceof ApprovalError\n ? error.message\n : \"Could not finish. Submit again with the same reason to recover the decision.\",\n },\n });\n }\n }\n async function handle(\n request: Request,\n waitUntil: (task: Promise<unknown>) => void,\n ): Promise<Response | null> {\n if (\n request.method !== \"POST\" ||\n !request.headers.get(\"content-type\")?.includes(\"application/x-www-form-urlencoded\")\n )\n return null;\n const raw = await request.clone().text();\n if (raw.length > 256_000) return new Response(\"Payload too large\", { status: 413 });\n let input: unknown;\n try {\n input = JSON.parse(new URLSearchParams(raw).get(\"payload\") ?? \"null\");\n } catch {\n return null;\n }\n const route = z\n .looseObject({\n type: z.string().optional(),\n actions: z.array(z.looseObject({ action_id: z.string() })).optional(),\n view: z.looseObject({ callback_id: z.string() }).optional(),\n })\n .safeParse(input);\n if (\n !route.success ||\n !(\n route.data.actions?.some((action) => action.action_id.startsWith(slackApprovalPrefix)) ||\n route.data.view?.callback_id === slackRejectionCallback\n )\n )\n return null;\n try {\n await options.verify(request, raw);\n } catch {\n return new Response(\"unauthorized\", { status: 401 });\n }\n const parsed = callbackSchema.safeParse(input);\n if (!parsed.success) return new Response(\"Invalid approval interaction\", { status: 400 });\n const payload = parsed.data;\n if (payload.type === \"view_submission\") return submit(payload, waitUntil);\n waitUntil(clickWithFeedback(payload));\n return acknowledgement();\n }\n return { handle, reconcile, deliver, updatePresented };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { RepositorySlug } from "../schema/repository.mjs";
|
|
2
|
+
import { MaybePromise } from "../schema/common.mjs";
|
|
3
|
+
import { CommunicationEvent } from "../schema/communication.mjs";
|
|
4
|
+
import { CommunicationAdapter, NormalizedSignal } from "./index.mjs";
|
|
5
|
+
import { SlackApprovals, SlackApprovalsOptions, SlackApprovalsStores, createSlackApprovals } from "./slack-approvals.mjs";
|
|
3
6
|
//#region src/connectors/slack.d.ts
|
|
7
|
+
/** Fully rendered Slack delivery with a stable idempotency key and resolved destination. */
|
|
4
8
|
interface SlackCommunicationDelivery {
|
|
5
9
|
eventId: string;
|
|
6
10
|
clientMessageId: string;
|
|
@@ -13,80 +17,59 @@ interface SlackCommunicationDelivery {
|
|
|
13
17
|
threadTs: string;
|
|
14
18
|
};
|
|
15
19
|
}
|
|
20
|
+
/** Slack-specific communication adapter with an inspectable mrkdwn renderer. */
|
|
16
21
|
interface SlackCommunicationAdapter extends CommunicationAdapter {
|
|
17
22
|
readonly channel: "slack";
|
|
18
23
|
render(event: CommunicationEvent): string;
|
|
19
24
|
}
|
|
25
|
+
/** Configures Slack rendering, provider delivery, and durable delivery projection. */
|
|
20
26
|
interface SlackCommunicationAdapterOptions {
|
|
21
27
|
send(delivery: SlackCommunicationDelivery): Promise<void>;
|
|
22
28
|
render?: (event: CommunicationEvent) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Runs once send() resolves without throwing, i.e. once Slack has
|
|
31
|
+
* confirmed delivery. Errors propagate so the outbox retries with the same
|
|
32
|
+
* client message ID until both the send and its durable projection succeed.
|
|
33
|
+
*/
|
|
34
|
+
onDelivered?: (event: CommunicationEvent) => MaybePromise<void>;
|
|
23
35
|
}
|
|
36
|
+
/** The channel and thread extracted from a Slack reply address. */
|
|
24
37
|
interface SlackReplyTarget {
|
|
25
38
|
channelId: string;
|
|
26
39
|
threadTs: string;
|
|
27
40
|
}
|
|
28
|
-
type SlackPullRequestSelection = {
|
|
29
|
-
status: "none";
|
|
30
|
-
} | {
|
|
31
|
-
status: "ambiguous";
|
|
32
|
-
} | {
|
|
33
|
-
status: "selected";
|
|
34
|
-
pullRequestNumber: number;
|
|
35
|
-
};
|
|
36
|
-
/** Resolve an explicit pull-request reference after the repository has been selected. */
|
|
37
|
-
declare function selectSlackPullRequest(text: string, repositorySlug: string): SlackPullRequestSelection;
|
|
38
41
|
/** Parse Eve's Slack continuation token into its channel and thread target. */
|
|
39
42
|
declare function parseSlackReplyAddress(address: string): SlackReplyTarget;
|
|
40
43
|
/** Render a provider-neutral communication event as Slack mrkdwn. */
|
|
41
44
|
declare function renderSlackCommunicationEvent(input: CommunicationEvent): string;
|
|
42
45
|
/** Bind Slack rendering and delivery to the channel-neutral communication contract. */
|
|
43
46
|
declare function createSlackCommunicationAdapter(options: SlackCommunicationAdapterOptions): SlackCommunicationAdapter;
|
|
47
|
+
/** Authenticated Slack message metadata after repository and reply context resolution. */
|
|
44
48
|
interface SlackMessageEvent {
|
|
45
|
-
teamId: string;
|
|
46
|
-
channelId: string;
|
|
47
|
-
messageTs: string;
|
|
48
|
-
threadTs: string;
|
|
49
|
-
actorId: string;
|
|
50
|
-
text: string;
|
|
51
|
-
replyAddress: string;
|
|
52
|
-
repositorySlugs: readonly [
|
|
53
|
-
payload: unknown;
|
|
49
|
+
readonly teamId: string;
|
|
50
|
+
readonly channelId: string;
|
|
51
|
+
readonly messageTs: string;
|
|
52
|
+
readonly threadTs: string;
|
|
53
|
+
readonly actorId: string;
|
|
54
|
+
readonly text: string;
|
|
55
|
+
readonly replyAddress: string;
|
|
56
|
+
readonly repositorySlugs: readonly [RepositorySlug, ...RepositorySlug[]];
|
|
57
|
+
readonly payload: unknown;
|
|
54
58
|
}
|
|
59
|
+
/** A normalized Slack signal with the authenticated message and repository scope retained. */
|
|
55
60
|
interface SlackMessageSignal extends NormalizedSignal<"slack"> {
|
|
56
|
-
repositorySlugs: readonly [
|
|
57
|
-
message: {
|
|
58
|
-
teamId: string;
|
|
59
|
-
channelId: string;
|
|
60
|
-
messageTs: string;
|
|
61
|
-
threadTs: string;
|
|
62
|
-
actorId: string;
|
|
63
|
-
text: string;
|
|
61
|
+
readonly repositorySlugs: readonly [RepositorySlug, ...RepositorySlug[]];
|
|
62
|
+
readonly message: {
|
|
63
|
+
readonly teamId: string;
|
|
64
|
+
readonly channelId: string;
|
|
65
|
+
readonly messageTs: string;
|
|
66
|
+
readonly threadTs: string;
|
|
67
|
+
readonly actorId: string;
|
|
68
|
+
readonly text: string;
|
|
64
69
|
};
|
|
65
70
|
}
|
|
66
71
|
/** Normalize an Eve-verified Slack message after the caller resolves its repositories. */
|
|
67
72
|
declare function normalizeSlackMessage(event: SlackMessageEvent): SlackMessageSignal;
|
|
68
|
-
type SlackRepositorySelection = {
|
|
69
|
-
status: "selected";
|
|
70
|
-
repositorySlug: string;
|
|
71
|
-
} | {
|
|
72
|
-
status: "required";
|
|
73
|
-
} | {
|
|
74
|
-
status: "ambiguous";
|
|
75
|
-
repositorySlugs: readonly string[];
|
|
76
|
-
};
|
|
77
|
-
type SlackRepositoriesSelection = {
|
|
78
|
-
status: "selected";
|
|
79
|
-
repositorySlugs: readonly [string, ...string[]];
|
|
80
|
-
} | {
|
|
81
|
-
status: "required";
|
|
82
|
-
};
|
|
83
|
-
/** Select every named configured repository, preserving configuration order. */
|
|
84
|
-
declare function selectSlackRepositories(text: string, repositories: readonly string[]): SlackRepositoriesSelection;
|
|
85
|
-
/**
|
|
86
|
-
* Select the only configured repository, or match a full slug, unique short
|
|
87
|
-
* name, or GitHub repository URL when a Slack surface fronts multiple repositories.
|
|
88
|
-
*/
|
|
89
|
-
declare function selectSlackRepository(text: string, repositories: readonly string[]): SlackRepositorySelection;
|
|
90
73
|
//#endregion
|
|
91
|
-
export { SlackCommunicationAdapter, SlackCommunicationAdapterOptions, SlackCommunicationDelivery, SlackMessageEvent, SlackMessageSignal,
|
|
74
|
+
export { type SlackApprovals, type SlackApprovalsOptions, type SlackApprovalsStores, SlackCommunicationAdapter, SlackCommunicationAdapterOptions, SlackCommunicationDelivery, SlackMessageEvent, SlackMessageSignal, SlackReplyTarget, createSlackApprovals, createSlackCommunicationAdapter, normalizeSlackMessage, parseSlackReplyAddress, renderSlackCommunicationEvent };
|
|
92
75
|
//# sourceMappingURL=slack.d.mts.map
|