@wardby/cli 0.5.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +33 -0
- package/README.md +25 -14
- package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
- package/dist/claude-coding-worker/context.d.ts +22 -0
- package/dist/claude-coding-worker/context.js +92 -0
- package/dist/claude-coding-worker/driver.d.ts +27 -3
- package/dist/claude-coding-worker/driver.js +161 -20
- package/dist/claude-coding-worker/main.js +34 -6
- package/dist/claude-coding-worker/sdk.js +25 -5
- package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
- package/dist/claude-coding-worker/tool-socket.js +111 -0
- package/dist/claude-coding-worker/transcript.d.ts +18 -0
- package/dist/claude-coding-worker/transcript.js +77 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +6 -2
- package/dist/cli-native-mode.d.ts +9 -0
- package/dist/cli-native-mode.js +20 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +161 -11
- package/dist/coding/claude-context.d.ts +45 -0
- package/dist/coding/claude-context.js +434 -0
- package/dist/coding/continuation-wording.d.ts +35 -0
- package/dist/coding/continuation-wording.js +73 -0
- package/dist/coding/linked-issue-note.d.ts +23 -0
- package/dist/coding/linked-issue-note.js +47 -0
- package/dist/coding/merge-wording.d.ts +28 -0
- package/dist/coding/merge-wording.js +78 -0
- package/dist/coding/pr-description-note.d.ts +9 -0
- package/dist/coding/pr-description-note.js +32 -0
- package/dist/coding/profile.d.ts +50 -118
- package/dist/coding/profile.js +51 -4
- package/dist/coding/protected-path-wording.d.ts +8 -0
- package/dist/coding/protected-path-wording.js +1 -1
- package/dist/coding/protocol.d.ts +292 -270
- package/dist/coding/protocol.js +322 -15
- package/dist/coding/redact.d.ts +3 -0
- package/dist/coding/redact.js +12 -0
- package/dist/coding/registry/allowlist.d.ts +12 -0
- package/dist/coding/registry/allowlist.js +14 -1
- package/dist/coding/registry/audit-mode.d.ts +153 -0
- package/dist/coding/registry/audit-mode.js +304 -0
- package/dist/coding/registry/lockfile-shared.d.ts +36 -0
- package/dist/coding/registry/lockfile-shared.js +128 -0
- package/dist/coding/registry/lockfiles.js +1 -1
- package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
- package/dist/coding/registry/npm-lockfile-formats.js +41 -0
- package/dist/coding/registry/npm-lockfile.d.ts +8 -4
- package/dist/coding/registry/npm-lockfile.js +4 -6
- package/dist/coding/registry/npm.js +78 -8
- package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
- package/dist/coding/registry/pnpm-lockfile.js +189 -0
- package/dist/coding/registry/pypi-plan.d.ts +50 -0
- package/dist/coding/registry/pypi-plan.js +406 -0
- package/dist/coding/registry/pypi-requirements.d.ts +58 -0
- package/dist/coding/registry/pypi-requirements.js +155 -0
- package/dist/coding/registry/pypi.d.ts +3 -27
- package/dist/coding/registry/pypi.js +40 -154
- package/dist/coding/registry/refusal-hints.d.ts +20 -0
- package/dist/coding/registry/refusal-hints.js +61 -0
- package/dist/coding/registry/refusal-wording.d.ts +11 -0
- package/dist/coding/registry/refusal-wording.js +56 -0
- package/dist/coding/registry/report.d.ts +70 -8
- package/dist/coding/registry/report.js +112 -5
- package/dist/coding/registry/types.d.ts +58 -8
- package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
- package/dist/coding/registry/yarn-lockfile.js +367 -0
- package/dist/coding/services/catalog.d.ts +37 -351
- package/dist/coding/transcript/claude-code.d.ts +13 -0
- package/dist/coding/transcript/claude-code.js +273 -0
- package/dist/coding/transcript/download-protocol.d.ts +30 -0
- package/dist/coding/transcript/download-protocol.js +18 -0
- package/dist/coding/transcript/format.d.ts +20 -0
- package/dist/coding/transcript/format.js +32 -0
- package/dist/coding/transcript/recorder.d.ts +51 -0
- package/dist/coding/transcript/recorder.js +225 -0
- package/dist/coding/transcript/resume/checkout.d.ts +31 -0
- package/dist/coding/transcript/resume/checkout.js +203 -0
- package/dist/coding/transcript/resume/command.d.ts +17 -0
- package/dist/coding/transcript/resume/command.js +176 -0
- package/dist/coding/transcript/resume/download.d.ts +20 -0
- package/dist/coding/transcript/resume/download.js +153 -0
- package/dist/coding/transcript/resume/launch.d.ts +38 -0
- package/dist/coding/transcript/resume/launch.js +128 -0
- package/dist/coding/transcript/resume/session-file.d.ts +13 -0
- package/dist/coding/transcript/resume/session-file.js +79 -0
- package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
- package/dist/coding/transcript/resume/stand-in.js +49 -0
- package/dist/coding-worker/artifact.d.ts +16 -3
- package/dist/coding-worker/artifact.js +5 -3
- package/dist/coding-worker/debug-trace.d.ts +6 -5
- package/dist/coding-worker/debug-trace.js +13 -18
- package/dist/coding-worker/dependency-cache.d.mts +229 -0
- package/dist/coding-worker/dependency-cache.mjs +2123 -0
- package/dist/coding-worker/driver.d.ts +4 -3
- package/dist/coding-worker/driver.js +118 -38
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/sdk.d.ts +6 -0
- package/dist/coding-worker/sdk.js +1 -0
- package/dist/coding-worker/skills.d.ts +23 -0
- package/dist/coding-worker/skills.js +117 -0
- package/dist/coding-worker/task-note.d.ts +11 -0
- package/dist/coding-worker/task-note.js +13 -0
- package/dist/coding-worker/types.d.ts +13 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/github-allowed-accounts.d.ts +15 -0
- package/dist/config/github-allowed-accounts.js +36 -0
- package/dist/config/low-power.d.ts +12 -0
- package/dist/config/low-power.js +18 -0
- package/dist/config/mobile.d.ts +12 -0
- package/dist/config/mobile.js +18 -0
- package/dist/config/providers.d.ts +65 -3
- package/dist/config/providers.js +147 -11
- package/dist/config/test-simulators.d.ts +82 -0
- package/dist/config/test-simulators.js +305 -0
- package/dist/core/async-context.d.ts +2 -0
- package/dist/core/async-context.js +12 -0
- package/dist/core/budget-events.d.ts +108 -0
- package/dist/core/budget-events.js +346 -0
- package/dist/core/budget-groups.d.ts +50 -1
- package/dist/core/budget-groups.js +236 -27
- package/dist/core/budget-stopped-head.d.ts +46 -0
- package/dist/core/budget-stopped-head.js +81 -0
- package/dist/core/budget-topup.d.ts +51 -0
- package/dist/core/budget-topup.js +156 -0
- package/dist/core/budget-wording.d.ts +16 -2
- package/dist/core/budget-wording.js +40 -2
- package/dist/core/coding-queue.d.ts +2 -1
- package/dist/core/coding-queue.js +7 -0
- package/dist/core/cron.d.ts +19 -1
- package/dist/core/cron.js +17 -0
- package/dist/core/datastores.js +1 -1
- package/dist/core/db.d.ts +16 -6
- package/dist/core/db.js +12 -10
- package/dist/core/deferred-coding.d.ts +14 -0
- package/dist/core/deferred-coding.js +62 -0
- package/dist/core/delegation-child.d.ts +25 -0
- package/dist/core/delegation-child.js +37 -0
- package/dist/core/dispatch.d.ts +53 -0
- package/dist/core/dispatch.js +167 -57
- package/dist/core/engine-native.js +10 -6
- package/dist/core/error-code.d.ts +38 -0
- package/dist/core/error-code.js +168 -0
- package/dist/core/grants.d.ts +19 -6
- package/dist/core/grants.js +55 -6
- package/dist/core/host-events.d.ts +67 -5
- package/dist/core/host-events.js +571 -37
- package/dist/core/host-status.d.ts +85 -3
- package/dist/core/host-status.js +298 -20
- package/dist/core/issue-bridge.d.ts +50 -6
- package/dist/core/issue-bridge.js +151 -20
- package/dist/core/issue-events.d.ts +1 -1
- package/dist/core/issue-events.js +16 -11
- package/dist/core/issue-status.d.ts +1 -1
- package/dist/core/issue-status.js +68 -29
- package/dist/core/logger.d.ts +5 -0
- package/dist/core/logger.js +14 -1
- package/dist/core/lost-run-children.d.ts +6 -0
- package/dist/core/lost-run-children.js +32 -0
- package/dist/core/mark-ready.d.ts +34 -0
- package/dist/core/mark-ready.js +152 -0
- package/dist/core/markdown-code.d.ts +8 -0
- package/dist/core/markdown-code.js +107 -0
- package/dist/core/memory-tools.js +7 -0
- package/dist/core/merge-order-check.d.ts +130 -0
- package/dist/core/merge-order-check.js +343 -0
- package/dist/core/notification-dispatcher.d.ts +70 -0
- package/dist/core/notification-dispatcher.js +368 -0
- package/dist/core/notification-templates.d.ts +19 -0
- package/dist/core/notification-templates.js +139 -0
- package/dist/core/notifications.d.ts +10 -0
- package/dist/core/notifications.js +38 -0
- package/dist/core/pg-auth.d.ts +22 -0
- package/dist/core/pg-auth.js +152 -0
- package/dist/core/power-composition.d.ts +16 -0
- package/dist/core/power-composition.js +37 -0
- package/dist/core/power-idle.d.ts +14 -0
- package/dist/core/power-idle.js +30 -0
- package/dist/core/power.d.ts +71 -0
- package/dist/core/power.js +202 -0
- package/dist/core/pull-request-state-sync.js +2 -2
- package/dist/core/reconciler.d.ts +8 -5
- package/dist/core/reconciler.js +37 -6
- package/dist/core/related-pull-requests.d.ts +59 -7
- package/dist/core/related-pull-requests.js +140 -25
- package/dist/core/reply-parts.d.ts +21 -0
- package/dist/core/reply-parts.js +73 -0
- package/dist/core/repo-access.d.ts +15 -0
- package/dist/core/repo-access.js +66 -0
- package/dist/core/review-fix.d.ts +38 -1
- package/dist/core/review-fix.js +209 -7
- package/dist/core/review-host-checks.d.ts +1 -1
- package/dist/core/review-host-tools.d.ts +23 -0
- package/dist/core/review-host-tools.js +156 -14
- package/dist/core/review-reads.d.ts +55 -0
- package/dist/core/review-reads.js +233 -0
- package/dist/core/run-status.d.ts +12 -0
- package/dist/core/run-status.js +12 -0
- package/dist/core/runner.d.ts +384 -5
- package/dist/core/runner.js +1244 -372
- package/dist/core/schedule-start.d.ts +12 -0
- package/dist/core/schedule-start.js +14 -0
- package/dist/core/secret-broker-config.d.ts +39 -0
- package/dist/core/secret-broker-config.js +112 -0
- package/dist/core/secret-guard.d.ts +46 -0
- package/dist/core/secret-guard.js +104 -0
- package/dist/core/secret-guarded-stores.d.ts +12 -0
- package/dist/core/secret-guarded-stores.js +41 -0
- package/dist/core/secret-spans.d.ts +50 -0
- package/dist/core/secret-spans.js +94 -0
- package/dist/core/secrets.d.ts +39 -4
- package/dist/core/secrets.js +148 -40
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- package/dist/core/workflow-event-recorder.d.ts +14 -0
- package/dist/core/workflow-event-recorder.js +120 -0
- package/dist/core/workflow-events.d.ts +94 -0
- package/dist/core/workflow-events.js +48 -0
- package/dist/core/workflow-run-events.d.ts +18 -0
- package/dist/core/workflow-run-events.js +75 -0
- package/dist/core/zod-json-schema.d.ts +4 -0
- package/dist/core/zod-json-schema.js +39 -0
- package/dist/core/zod3-window.d.ts +35 -0
- package/dist/core/zod3-window.js +124 -0
- package/dist/generated/prisma/browser.d.ts +92 -3
- package/dist/generated/prisma/client.d.ts +92 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
- package/dist/generated/prisma/enums.d.ts +37 -0
- package/dist/generated/prisma/enums.js +31 -0
- package/dist/generated/prisma/internal/class.d.ts +132 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
- package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
- package/dist/generated/prisma/models/Agent.d.ts +464 -7
- package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -1
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
- package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +1841 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
- package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
- package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
- package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
- package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1713 -0
- package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
- package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
- package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
- package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
- package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
- package/dist/generated/prisma/models/NotificationChannel.js +1 -0
- package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
- package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
- package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
- package/dist/generated/prisma/models/NotificationThread.js +1 -0
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
- package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
- package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +1619 -58
- package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
- package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
- package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
- package/dist/generated/prisma/models/RunTranscript.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +37 -1
- package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
- package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
- package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
- package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
- package/dist/generated/prisma/models.d.ts +12 -0
- package/dist/help/build.js +4 -2
- package/dist/help/catalog.d.ts +1 -1
- package/dist/help/catalog.js +31 -6
- package/dist/help-index.json +2584 -146
- package/dist/import/create.js +49 -3
- package/dist/import/neutral-schema.d.ts +50 -277
- package/dist/import/neutral-schema.js +7 -4
- package/dist/knowledge/check.d.ts +1 -1
- package/dist/knowledge/cli.d.ts +11 -1
- package/dist/knowledge/cli.js +37 -4
- package/dist/knowledge/concept.d.ts +3 -19
- package/dist/knowledge/location.d.ts +31 -0
- package/dist/knowledge/location.js +78 -0
- package/dist/mcp/auth/access.d.ts +11 -2
- package/dist/mcp/auth/access.js +15 -1
- package/dist/mcp/auth/ownership.d.ts +7 -7
- package/dist/mcp/auth/repo-authorization.js +14 -0
- package/dist/mcp/auth/resource-server.d.ts +2 -1
- package/dist/mcp/auth/resource-server.js +7 -2
- package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/browser.js +19 -6
- package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
- package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
- package/dist/mcp/context.d.ts +6 -0
- package/dist/mcp/host-events/github-ingress.d.ts +25 -1
- package/dist/mcp/host-events/github-ingress.js +70 -1
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.js +117 -20
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +33 -14
- package/dist/mcp/tools/agents.d.ts +4 -0
- package/dist/mcp/tools/agents.js +277 -24
- package/dist/mcp/tools/datastore.js +17 -8
- package/dist/mcp/tools/grants.js +9 -3
- package/dist/mcp/tools/memory.js +11 -1
- package/dist/mcp/tools/notification-channels.d.ts +2 -0
- package/dist/mcp/tools/notification-channels.js +293 -0
- package/dist/mcp/tools/packages.d.ts +2 -0
- package/dist/mcp/tools/packages.js +195 -0
- package/dist/mcp/tools/power.d.ts +2 -0
- package/dist/mcp/tools/power.js +77 -0
- package/dist/mcp/tools/repositories.js +18 -5
- package/dist/mcp/tools/run-access.d.ts +16 -0
- package/dist/mcp/tools/run-access.js +25 -0
- package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
- package/dist/mcp/tools/run-transcript-download.js +129 -0
- package/dist/mcp/tools/run-transcript.d.ts +19 -0
- package/dist/mcp/tools/run-transcript.js +70 -0
- package/dist/mcp/tools/runs.d.ts +0 -6
- package/dist/mcp/tools/runs.js +41 -14
- package/dist/mcp/tools/scheduling.js +3 -1
- package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
- package/dist/mcp/tools/secret-broker-compat.js +23 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
- package/dist/mcp/tools/secret-elicitation-form.js +205 -10
- package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
- package/dist/mcp/tools/secret-elicitation-server.js +10 -54
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
- package/dist/mcp/tools/secret-elicitation.js +110 -12
- package/dist/mcp/tools/secrets.js +186 -9
- package/dist/mcp/tools/stop-run.d.ts +2 -0
- package/dist/mcp/tools/stop-run.js +82 -0
- package/dist/mcp/tools/subagents.js +2 -2
- package/dist/mcp/tools/tools.d.ts +2 -2
- package/dist/mcp/tools/tools.js +47 -11
- package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
- package/dist/mcp/transport/stdio-link-host.js +67 -0
- package/dist/mcp/transport/streamable-http.d.ts +13 -0
- package/dist/mcp/transport/streamable-http.js +41 -1
- package/dist/native-worker/composition.d.ts +23 -0
- package/dist/native-worker/composition.js +77 -0
- package/dist/native-worker/docker-isolation.d.ts +65 -0
- package/dist/native-worker/docker-isolation.js +183 -0
- package/dist/native-worker/docker-launcher.d.ts +110 -0
- package/dist/native-worker/docker-launcher.js +297 -0
- package/dist/native-worker/gateway-server.d.ts +77 -0
- package/dist/native-worker/gateway-server.js +412 -0
- package/dist/native-worker/gateway.d.ts +70 -0
- package/dist/native-worker/gateway.js +263 -0
- package/dist/native-worker/http-server.d.ts +24 -0
- package/dist/native-worker/http-server.js +113 -0
- package/dist/native-worker/http-transport.d.ts +17 -0
- package/dist/native-worker/http-transport.js +88 -0
- package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
- package/dist/native-worker/kubernetes-isolation.js +218 -0
- package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
- package/dist/native-worker/kubernetes-launcher.js +375 -0
- package/dist/native-worker/launch.d.ts +62 -0
- package/dist/native-worker/launch.js +49 -0
- package/dist/native-worker/ledger.d.ts +125 -0
- package/dist/native-worker/ledger.js +245 -0
- package/dist/native-worker/loopback.d.ts +12 -0
- package/dist/native-worker/loopback.js +44 -0
- package/dist/native-worker/main.d.ts +8 -0
- package/dist/native-worker/main.js +85 -0
- package/dist/native-worker/protocol.d.ts +296 -0
- package/dist/native-worker/protocol.js +246 -0
- package/dist/native-worker/sandbox-executor.d.ts +83 -0
- package/dist/native-worker/sandbox-executor.js +284 -0
- package/dist/native-worker/stderr-redaction.d.ts +77 -0
- package/dist/native-worker/stderr-redaction.js +237 -0
- package/dist/native-worker/stdio.d.ts +29 -0
- package/dist/native-worker/stdio.js +189 -0
- package/dist/native-worker/warm-delivery.d.ts +16 -0
- package/dist/native-worker/warm-delivery.js +33 -0
- package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
- package/dist/native-worker/warm-pool-ledger.js +73 -0
- package/dist/native-worker/warm-pool.d.ts +107 -0
- package/dist/native-worker/warm-pool.js +283 -0
- package/dist/native-worker/worker.d.ts +17 -0
- package/dist/native-worker/worker.js +141 -0
- package/dist/observability/metrics.js +6 -1
- package/dist/providers/auth/authorization-server.d.ts +3 -0
- package/dist/providers/auth/index.js +2 -0
- package/dist/providers/auth/self-hosted.d.ts +14 -2
- package/dist/providers/auth/self-hosted.js +54 -4
- package/dist/providers/chat/fake.d.ts +46 -0
- package/dist/providers/chat/fake.js +39 -0
- package/dist/providers/chat/index.d.ts +4 -0
- package/dist/providers/chat/index.js +8 -0
- package/dist/providers/chat/slack.d.ts +37 -0
- package/dist/providers/chat/slack.js +105 -0
- package/dist/providers/chat/types.d.ts +42 -0
- package/dist/providers/chat/types.js +19 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
- package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
- package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
- package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
- package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
- package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
- package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
- package/dist/providers/coding-proxy/hold.d.ts +32 -0
- package/dist/providers/coding-proxy/hold.js +86 -0
- package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
- package/dist/providers/coding-proxy/interrupted.js +104 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/memory-ledger.js +84 -8
- package/dist/providers/coding-proxy/metering.d.ts +16 -0
- package/dist/providers/coding-proxy/metering.js +27 -4
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
- package/dist/providers/coding-proxy/proxy.d.ts +14 -1
- package/dist/providers/coding-proxy/proxy.js +166 -14
- package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
- package/dist/providers/coding-proxy/registry/audit.js +94 -17
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
- package/dist/providers/coding-proxy/registry/plan.js +201 -48
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
- package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
- package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
- package/dist/providers/coding-proxy/registry/service.js +579 -112
- package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
- package/dist/providers/coding-proxy/registry/store.js +54 -1
- package/dist/providers/coding-proxy/runtime.d.ts +4 -0
- package/dist/providers/coding-proxy/runtime.js +78 -16
- package/dist/providers/coding-proxy/server.d.ts +6 -1
- package/dist/providers/coding-proxy/server.js +45 -1
- package/dist/providers/coding-proxy/types.d.ts +65 -1
- package/dist/providers/datastore/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +36 -2
- package/dist/providers/engine/types.js +39 -0
- package/dist/providers/executor/composition.d.ts +31 -1
- package/dist/providers/executor/composition.js +81 -8
- package/dist/providers/executor/container.d.ts +385 -9
- package/dist/providers/executor/container.js +1234 -99
- package/dist/providers/executor/dbos-status.d.ts +31 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +91 -0
- package/dist/providers/executor/dbos.js +319 -26
- package/dist/providers/executor/deferred.d.ts +44 -0
- package/dist/providers/executor/deferred.js +100 -0
- package/dist/providers/executor/in-process.d.ts +9 -1
- package/dist/providers/executor/in-process.js +14 -4
- package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
- package/dist/providers/executor/linked-issue-reader.js +30 -0
- package/dist/providers/executor/routing.d.ts +39 -10
- package/dist/providers/executor/routing.js +77 -32
- package/dist/providers/executor/types.d.ts +25 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/issue-tracker/types.d.ts +17 -0
- package/dist/providers/issue-tracker/types.js +39 -1
- package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
- package/dist/providers/jobs/claude-tool-setup.js +5 -2
- package/dist/providers/jobs/docker-isolation.d.ts +8 -0
- package/dist/providers/jobs/docker-isolation.js +17 -0
- package/dist/providers/jobs/docker.d.ts +1 -0
- package/dist/providers/jobs/docker.js +29 -4
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
- package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
- package/dist/providers/jobs/kubernetes-api.js +17 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
- package/dist/providers/jobs/kubernetes-client.js +61 -3
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
- package/dist/providers/jobs/kubernetes-isolation.js +23 -1
- package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
- package/dist/providers/jobs/kubernetes-platform.js +38 -1
- package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
- package/dist/providers/jobs/kubernetes-preflight.js +4 -2
- package/dist/providers/jobs/kubernetes.d.ts +42 -2
- package/dist/providers/jobs/kubernetes.js +178 -19
- package/dist/providers/jobs/metadata-probes.d.ts +11 -0
- package/dist/providers/jobs/metadata-probes.js +13 -0
- package/dist/providers/jobs/types.d.ts +42 -0
- package/dist/providers/jobs/types.js +13 -1
- package/dist/providers/llm/anthropic.js +5 -1
- package/dist/providers/llm/bedrock.d.ts +0 -12
- package/dist/providers/llm/bedrock.js +4 -0
- package/dist/providers/llm/claude-messages.d.ts +3 -1
- package/dist/providers/llm/claude-messages.js +4 -1
- package/dist/providers/llm/claude-provider.d.ts +2 -2
- package/dist/providers/llm/claude-provider.js +2 -2
- package/dist/providers/llm/openai.d.ts +2 -2
- package/dist/providers/llm/openai.js +6 -2
- package/dist/providers/llm/routing.d.ts +2 -2
- package/dist/providers/llm/routing.js +2 -2
- package/dist/providers/llm/types.d.ts +12 -2
- package/dist/providers/review-host/github-events.d.ts +9 -1
- package/dist/providers/review-host/github-events.js +34 -12
- package/dist/providers/review-host/github.d.ts +39 -2
- package/dist/providers/review-host/github.js +274 -29
- package/dist/providers/review-host/local.d.ts +8 -4
- package/dist/providers/review-host/local.js +49 -31
- package/dist/providers/review-host/patch-pages.d.ts +41 -0
- package/dist/providers/review-host/patch-pages.js +176 -0
- package/dist/providers/review-host/review-format.d.ts +19 -1
- package/dist/providers/review-host/review-format.js +38 -7
- package/dist/providers/review-host/types.d.ts +157 -2
- package/dist/providers/review-host/types.js +8 -0
- package/dist/providers/storage/gcs.d.ts +63 -0
- package/dist/providers/storage/gcs.js +69 -0
- package/dist/providers/storage/index.d.ts +15 -0
- package/dist/providers/storage/index.js +14 -0
- package/dist/providers/storage/local.d.ts +24 -0
- package/dist/providers/storage/local.js +92 -0
- package/dist/providers/storage/meter.d.ts +14 -0
- package/dist/providers/storage/meter.js +34 -0
- package/dist/providers/storage/s3.d.ts +41 -0
- package/dist/providers/storage/s3.js +107 -0
- package/dist/providers/storage/types.d.ts +37 -3
- package/dist/providers/storage/types.js +21 -4
- package/dist/providers/vcs/git.d.ts +33 -2
- package/dist/providers/vcs/git.js +324 -22
- package/dist/providers/vcs/github-remote.d.ts +26 -3
- package/dist/providers/vcs/github-remote.js +124 -14
- package/dist/providers/vcs/github.d.ts +246 -12
- package/dist/providers/vcs/github.js +521 -61
- package/dist/providers/vcs/index.js +8 -1
- package/dist/providers/vcs/pr-description.d.ts +127 -0
- package/dist/providers/vcs/pr-description.js +270 -0
- package/dist/providers/vcs/remote.d.ts +33 -1
- package/dist/providers/vcs/routing.d.ts +4 -2
- package/dist/providers/vcs/routing.js +6 -0
- package/dist/providers/vcs/types.d.ts +80 -3
- package/dist/quickstart/coding-seed.d.ts +21 -3
- package/dist/quickstart/coding-seed.js +283 -3
- package/dist/quickstart/images.d.ts +2 -0
- package/dist/quickstart/images.js +7 -1
- package/dist/quickstart/reviewer-prompt.d.ts +1 -1
- package/dist/quickstart/reviewer-prompt.js +6 -6
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/brokered-fetch.d.ts +23 -0
- package/dist/sandbox/brokered-fetch.js +37 -0
- package/dist/sandbox/generated/zod.bundle.js +62 -1
- package/dist/sandbox/generated/zod3.bundle.js +5 -0
- package/dist/sandbox/host-functions.d.ts +35 -0
- package/dist/sandbox/host-functions.js +150 -91
- package/dist/sandbox/prelude.js +7 -1
- package/dist/sandbox/run-in-sandbox.d.ts +19 -0
- package/dist/sandbox/run-in-sandbox.js +28 -10
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +3 -1
- package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
- package/dist/sandbox/secret-broker-sigv4.js +49 -0
- package/dist/sandbox/secret-broker.d.ts +34 -0
- package/dist/sandbox/secret-broker.js +161 -0
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- package/dist/sandbox/user-tool.d.ts +14 -0
- package/dist/sandbox/user-tool.js +32 -0
- package/dist/sandbox/zod-params.d.ts +37 -5
- package/dist/sandbox/zod-params.js +181 -26
- package/dist/serve.js +25 -0
- package/dist/viewer/api-schema.d.ts +372 -2454
- package/dist/viewer/api-schema.js +29 -0
- package/dist/viewer/build-schemas.js +10 -3
- package/dist/viewer/event-bus.d.ts +6 -0
- package/dist/viewer/event-bus.js +16 -7
- package/dist/viewer/graph.d.ts +5 -2
- package/dist/viewer/graph.js +7 -2
- package/dist/viewer/http.d.ts +0 -1
- package/dist/viewer/http.js +2 -2
- package/dist/viewer/infra.js +25 -2
- package/dist/viewer/limits.d.ts +4 -0
- package/dist/viewer/limits.js +4 -0
- package/dist/viewer/openapi.d.ts +15 -0
- package/dist/viewer/openapi.js +170 -0
- package/dist/wardby-bin.js +10 -0
- package/docs/README.md +7 -0
- package/docs/agent-recipes.md +114 -27
- package/docs/architecture-runtime.md +16 -1
- package/docs/code-review-agents.md +689 -45
- package/docs/coding-agent-setup.md +602 -12
- package/docs/coding-packages.md +1037 -92
- package/docs/coding-services.md +30 -13
- package/docs/coding-worker-byo-images.md +218 -6
- package/docs/coding-worker-isolation.md +173 -44
- package/docs/getting-started-gke.md +332 -129
- package/docs/getting-started-identity-provider.md +31 -11
- package/docs/getting-started.md +14 -4
- package/docs/jira-agents.md +22 -9
- package/docs/knowledge/blob-not-found-semantics.md +41 -0
- package/docs/knowledge/bounded-file-descriptor.md +52 -0
- package/docs/knowledge/delegation-admission-slots.md +52 -0
- package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
- package/docs/knowledge/import-rename-target.md +52 -0
- package/docs/knowledge/index.md +57 -0
- package/docs/knowledge/log.md +9 -0
- package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
- package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
- package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
- package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
- package/docs/knowledge/overview-cli.md +74 -0
- package/docs/knowledge/overview-coding-proxy.md +72 -0
- package/docs/knowledge/overview-coding.md +72 -0
- package/docs/knowledge/overview-config.md +60 -0
- package/docs/knowledge/overview-core.md +72 -0
- package/docs/knowledge/overview-deploy.md +83 -0
- package/docs/knowledge/overview-mcp.md +61 -0
- package/docs/knowledge/overview-prisma.md +72 -0
- package/docs/knowledge/overview-providers.md +89 -0
- package/docs/knowledge/overview-sandbox.md +83 -0
- package/docs/knowledge/overview-surfaces.md +83 -0
- package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
- package/docs/knowledge/proxy-settlement-projections.md +41 -0
- package/docs/knowledge/run-pricing-first-writer.md +43 -0
- package/docs/knowledge/schedule-claim-transaction.md +41 -0
- package/docs/knowledge/secret-entry-replica-contract.md +52 -0
- package/docs/knowledge/terminal-run-first-writer.md +41 -0
- package/docs/knowledge/transactional-agent-authorization.md +52 -0
- package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
- package/docs/knowledge/warm-input-publication.md +30 -0
- package/docs/knowledge/workspace-staging-failure.md +54 -0
- package/docs/knowledge.md +54 -14
- package/docs/native-sandbox.md +731 -0
- package/docs/observability.md +4 -0
- package/docs/release-verification.md +9 -0
- package/docs/security-deployment.md +146 -14
- package/docs/slack-notifications.md +268 -0
- package/docs/tool-secrets.md +284 -0
- package/docs/viewer-api.md +46 -5
- package/docs/viewer-api.openapi.yml +1404 -0
- package/help/admin-viewer.md +29 -3
- package/help/agent-recipes.md +27 -0
- package/help/architecture-agent.md +11 -6
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +6 -7
- package/help/builder-agent.md +19 -6
- package/help/code-review-agents.md +243 -10
- package/help/coding-packages.md +156 -6
- package/help/cost-attribution.md +9 -5
- package/help/creating-agents.md +14 -1
- package/help/dependency-cache.md +143 -0
- package/help/deploy-gke.md +23 -9
- package/help/deployment-targets.md +25 -14
- package/help/errors/budget-exhausted.md +187 -0
- package/help/errors/budget-group-exhausted.md +5 -1
- package/help/errors/coding-provider-not-configured.md +2 -2
- package/help/errors/coding-stream-quota-exceeded.md +33 -0
- package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
- package/help/errors/continuation-closed.md +9 -12
- package/help/errors/database-auth-invalid.md +28 -0
- package/help/errors/delegation-conflict.md +24 -0
- package/help/errors/file-list-truncated.md +45 -0
- package/help/errors/full-read-required.md +49 -0
- package/help/errors/github-account-not-allowed.md +29 -0
- package/help/errors/graph-incomplete.md +43 -0
- package/help/errors/graph-limit.md +43 -0
- package/help/errors/low-power-disabled.md +29 -0
- package/help/errors/low-power-scale-forbidden.md +35 -0
- package/help/errors/low-power-wake-timeout.md +30 -0
- package/help/errors/merge-conflict.md +49 -0
- package/help/errors/mobile-disabled.md +31 -0
- package/help/errors/native-sandbox-capacity.md +22 -0
- package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
- package/help/errors/native-sandbox-docker-failed.md +20 -0
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
- package/help/errors/native-sandbox-image-not-pinned.md +19 -0
- package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-network-unenforced.md +22 -0
- package/help/errors/native-sandbox-requires-catalog.md +31 -0
- package/help/errors/native-sandbox-unavailable.md +19 -0
- package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +21 -0
- package/help/errors/native-sandbox-worker-lost.md +20 -0
- package/help/errors/native-sandbox-worker-unready.md +22 -0
- package/help/errors/package-not-allowed-pending.md +52 -0
- package/help/errors/package-not-allowed.md +51 -0
- package/help/errors/package-refusals.md +43 -0
- package/help/errors/patch-cursor-malformed.md +31 -0
- package/help/errors/run-lost.md +39 -0
- package/help/errors/run-transcript-download.md +44 -0
- package/help/errors/secret-broker-body-invalid.md +26 -0
- package/help/errors/secret-broker-changed.md +20 -0
- package/help/errors/secret-broker-config-invalid.md +30 -0
- package/help/errors/secret-broker-conflict.md +27 -0
- package/help/errors/secret-broker-destination-denied.md +28 -0
- package/help/errors/secret-broker-value-invalid.md +28 -0
- package/help/errors/secret-brokered.md +24 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/secret-not-brokered.md +25 -0
- package/help/errors/slack-auth-failed.md +48 -0
- package/help/errors/slack-channel-unreachable.md +39 -0
- package/help/errors/slack-not-configured.md +33 -0
- package/help/errors/target-merge.md +40 -0
- package/help/fix-merge-conflicts.md +73 -0
- package/help/getting-started.md +4 -5
- package/help/github-app-setup.md +132 -0
- package/help/github.md +40 -1
- package/help/identity-and-access.md +7 -1
- package/help/jira.md +23 -6
- package/help/knowledge.md +16 -7
- package/help/local-repositories.md +3 -4
- package/help/low-power-mode.md +131 -0
- package/help/merge-order-check.md +122 -0
- package/help/mobile-app.md +54 -0
- package/help/native-capabilities.md +29 -1
- package/help/native-sandbox.md +150 -0
- package/help/observability.md +8 -0
- package/help/operating-agents.md +5 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +80 -16
- package/help/repo-instructions-and-skills.md +91 -0
- package/help/resume-runs-locally.md +131 -0
- package/help/review-fix-rounds.md +43 -1
- package/help/sharing-agents.md +59 -0
- package/help/slack-notifications.md +76 -0
- package/help/status-comments.md +31 -0
- package/help/stop-run.md +58 -0
- package/help/troubleshooting/budgets.md +28 -0
- package/help/troubleshooting/coding-workers.md +99 -7
- package/package.json +27 -13
- package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
- package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
- package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
- package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
- package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
- package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
- package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
- package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
- package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
- package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
- package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
- package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
- package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
- package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
- package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
- package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
- package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
- package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
- package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
- package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
- package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
- package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
- package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
- package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
- package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
- package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
- package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
- package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
- package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
- package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
- package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
- package/prisma/schema.prisma +631 -146
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
|
@@ -11,16 +11,71 @@
|
|
|
11
11
|
* The heartbeat is kept while the workflow runs here so the reconciler's
|
|
12
12
|
* stale-heartbeat detection is unchanged; the reconciler consults
|
|
13
13
|
* `recover()` (Task 6) before declaring a DBOS run lost.
|
|
14
|
+
*
|
|
15
|
+
* A stalled-but-alive owner can overlap an adopted attempt of the same run:
|
|
16
|
+
* whichever records a step second loses ownership, stops at that step
|
|
17
|
+
* without writing the run, and hands the SDK's conflict back so DBOS parks
|
|
18
|
+
* it as a duplicate execution (see dbosStep and runInsideWorkflow). After a
|
|
19
|
+
* takeover the fork has its own workflow id, so the two never share a step:
|
|
20
|
+
* the original stops the same way when it meets the takeover's cancel
|
|
21
|
+
* (dbosStepFor), and its start() handle writes nothing.
|
|
14
22
|
*/
|
|
15
23
|
import { DBOS, Error as DbosErrors } from "@dbos-inc/dbos-sdk";
|
|
16
|
-
import
|
|
24
|
+
import pg from "pg";
|
|
25
|
+
import { RunOwnershipLostError, StepReplayMismatchError } from "../engine/types.js";
|
|
26
|
+
import { executeRun, failNativeRun, loseNativeRun, nativeRunIntegrations, RunCancelledError, stopAwareStep, } from "../../core/runner.js";
|
|
17
27
|
import { markRunFailedFromExecutorError } from "../../core/dispatch.js";
|
|
18
28
|
import { prisma as defaultDb } from "../../core/db.js";
|
|
19
29
|
import { HEARTBEAT_INTERVAL_MS } from "../../core/timing.js";
|
|
30
|
+
import { DRIVABLE } from "../../core/run-status.js";
|
|
20
31
|
import { logger } from "../../core/logger.js";
|
|
21
|
-
import {
|
|
32
|
+
import { databaseAuthFromEnv, pgConnectionConfig } from "../../core/pg-auth.js";
|
|
33
|
+
import { ADOPTION_EXHAUSTED_REASON, STEPS_CHANGED_REASON, decideRecovery, decideTakeover, shouldGiveUpAdoption, versionMismatchReason, } from "./dbos-status.js";
|
|
22
34
|
export const DBOS_BACKEND = "dbos";
|
|
23
35
|
const dbosLog = logger.child({ module: "dbos-executor" });
|
|
36
|
+
/** DBOS's own system pool size (DEFAULT_POOL_SIZE in the SDK's system_database.js); kept for ours. */
|
|
37
|
+
const DBOS_SYSTEM_POOL_SIZE = 10;
|
|
38
|
+
/** DBOS's own connect timeout when the URL sets no connect_timeout (getClientConfig in the SDK's utils.js). */
|
|
39
|
+
const DBOS_CONNECT_TIMEOUT_MS = 10_000;
|
|
40
|
+
/**
|
|
41
|
+
* DBOS.setConfig input. Under password auth this is exactly what launch() always passed, and DBOS
|
|
42
|
+
* opens its own pool from the URL. Under rds-iam DBOS gets a pool whose password is the IAM token;
|
|
43
|
+
* DBOS then runs its migrations, queries and LISTEN through that pool and never opens a URL
|
|
44
|
+
* connection (system_database.js: a custom pool skips database creation and is what every
|
|
45
|
+
* connection borrows from). The pool copies what DBOS would have set on its own: size, connect
|
|
46
|
+
* timeout and application_name. DBOS never ends a pool it was given — see endSystemPool().
|
|
47
|
+
*/
|
|
48
|
+
export function dbosLaunchConfig(config, executorId, auth, pgAuth) {
|
|
49
|
+
const url = config.systemDatabaseUrl;
|
|
50
|
+
const launch = {
|
|
51
|
+
name: "wardby",
|
|
52
|
+
systemDatabaseUrl: url,
|
|
53
|
+
systemDatabaseSchemaName: config.schemaName,
|
|
54
|
+
executorID: executorId,
|
|
55
|
+
runAdminServer: false,
|
|
56
|
+
logLevel: "warn",
|
|
57
|
+
};
|
|
58
|
+
if (auth !== "rds-iam")
|
|
59
|
+
return launch;
|
|
60
|
+
const connection = pgConnectionConfig(url, auth, pgAuth); // validates the URL first
|
|
61
|
+
const connectTimeout = Number.parseInt(new URL(url).searchParams.get("connect_timeout") ?? "", 10);
|
|
62
|
+
const pool = new pg.Pool({
|
|
63
|
+
application_name: `dbos_transact_${executorId}`,
|
|
64
|
+
...connection,
|
|
65
|
+
max: DBOS_SYSTEM_POOL_SIZE,
|
|
66
|
+
connectionTimeoutMillis: connectTimeout ? connectTimeout * 1000 : DBOS_CONNECT_TIMEOUT_MS,
|
|
67
|
+
});
|
|
68
|
+
// DBOS attaches no listener to a caller's pool; an idle connection's error would otherwise crash the process.
|
|
69
|
+
pool.on("error", (err) => dbosLog.warn({ err }, "DBOS system database pool error"));
|
|
70
|
+
return { ...launch, systemDatabasePool: pool };
|
|
71
|
+
}
|
|
72
|
+
/** The pool launch() handed DBOS, if any. Module-level like DBOS itself: whoever shuts DBOS down ends it. */
|
|
73
|
+
let systemPool;
|
|
74
|
+
async function endSystemPool() {
|
|
75
|
+
const pool = systemPool;
|
|
76
|
+
systemPool = undefined;
|
|
77
|
+
await pool?.end().catch((err) => dbosLog.warn({ err }, "failed to close the DBOS system database pool"));
|
|
78
|
+
}
|
|
24
79
|
/** The executor whose deps the registered workflow uses. Set by launch(). */
|
|
25
80
|
let activeExecutor;
|
|
26
81
|
/** Setter (rather than `activeExecutor = this` inline) to avoid aliasing `this` to a variable. */
|
|
@@ -36,6 +91,27 @@ function setActiveExecutor(executor) {
|
|
|
36
91
|
* `runInsideWorkflow`'s finally.
|
|
37
92
|
*/
|
|
38
93
|
const cancellationReasons = new Map();
|
|
94
|
+
/**
|
|
95
|
+
* The id a takeover gives the fork of workflow `from` under application `version`. Deterministic, so
|
|
96
|
+
* a takeover that forked but never recorded the fork finishes it rather than forking again; and
|
|
97
|
+
* descendants share their ancestor's id as a prefix, which isForkOf relies on.
|
|
98
|
+
*/
|
|
99
|
+
export function forkWorkflowId(from, version) {
|
|
100
|
+
return `${from}@${version}`;
|
|
101
|
+
}
|
|
102
|
+
/** Whether workflow `id` was forked from `from`, directly or through further forks (forkWorkflowId). */
|
|
103
|
+
export function isForkOf(id, from) {
|
|
104
|
+
return id.startsWith(`${from}@`);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The DBOS workflow id that drives a run: `Run.executionWorkflowId` once the
|
|
108
|
+
* run's workflow was forked under a new application version, otherwise the
|
|
109
|
+
* run id (a run's first workflow is started with its run id).
|
|
110
|
+
*/
|
|
111
|
+
export async function workflowIdOf(db, runId) {
|
|
112
|
+
const row = await db.run.findUnique({ where: { id: runId }, select: { executionWorkflowId: true } });
|
|
113
|
+
return row?.executionWorkflowId ?? runId;
|
|
114
|
+
}
|
|
39
115
|
/**
|
|
40
116
|
* Bind the engine's step boundary to a DBOS checkpointed step. Never
|
|
41
117
|
* retried: a retry would re-spend.
|
|
@@ -44,23 +120,108 @@ const cancellationReasons = new Map();
|
|
|
44
120
|
* out of the next step boundary. Translated here into a `RunCancelledError`
|
|
45
121
|
* so executeRun's backstop records `cancelled` plus the operator's reason,
|
|
46
122
|
* rather than `failed` plus an SDK-internal message.
|
|
123
|
+
*
|
|
124
|
+
* DBOS signals that another execution of this workflow recorded the step
|
|
125
|
+
* first by throwing `DBOSWorkflowConflictError` after this attempt's step
|
|
126
|
+
* body already ran. Translated into a `RunOwnershipLostError` (carrying the
|
|
127
|
+
* discarded step's usage, if any, for the log) so executeRun's backstop stops
|
|
128
|
+
* this attempt without writing the run; runInsideWorkflow turns it back into
|
|
129
|
+
* the SDK error.
|
|
130
|
+
*
|
|
131
|
+
* DBOS signals that a replay reached a step whose recorded name differs (the
|
|
132
|
+
* run was recorded by a release whose steps differ, e.g. after a takeover
|
|
133
|
+
* fork) by throwing `DBOSUnexpectedStepError`. Translated into a
|
|
134
|
+
* `StepReplayMismatchError`, which executeRun's backstop settles as `lost`
|
|
135
|
+
* (runInsideWorkflow does it for a mismatch at the load step, which is outside
|
|
136
|
+
* that backstop).
|
|
137
|
+
*/
|
|
138
|
+
export const dbosStep = (name, fn) => runDbosStep(name, fn);
|
|
139
|
+
/**
|
|
140
|
+
* dbosStep for one run's workflow body. A cancellation of a workflow the run has moved off (its
|
|
141
|
+
* `executionWorkflowId` names a fork of it) is not a stop: recover() took the run over (forked it) and cancelled this,
|
|
142
|
+
* the forked-from workflow, while its owner was still alive. That attempt stops like one that lost
|
|
143
|
+
* a step's checkpoint (RunOwnershipLostError: no terminal write), so the fork, not a reasonless
|
|
144
|
+
* "cancelled" from the original, settles the run. takeOver records the fork's id before it
|
|
145
|
+
* cancels, so the original always reads the new id by the time it sees the cancel.
|
|
146
|
+
*/
|
|
147
|
+
export function dbosStepFor(db, runId) {
|
|
148
|
+
const supersedes = async (cancelledWorkflowId) => {
|
|
149
|
+
// A failed read falls back to an ordinary cancellation, as before this check existed.
|
|
150
|
+
const current = await workflowIdOf(db, runId).catch(() => cancelledWorkflowId);
|
|
151
|
+
return isForkOf(current, cancelledWorkflowId);
|
|
152
|
+
};
|
|
153
|
+
return (name, fn) => runDbosStep(name, fn, supersedes);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* dbosStepFor behind the same per-step row read as inline runs (stopAwareStep), failing open. DBOS
|
|
157
|
+
* stops a workflow it was told to cancel, but stop() can cancel only the workflow the run names, and
|
|
158
|
+
* a takeover's fork is named only once recorded: a fork already running before that (or whose
|
|
159
|
+
* record failed) would otherwise keep paying for turns under a run stop() already made terminal.
|
|
160
|
+
* The same read fences out a taken-over original as soon as the run names its fork, before the
|
|
161
|
+
* takeover's cancel lands, and even when that cancel failed: it stops as an ownership loss, without
|
|
162
|
+
* a terminal write or the settle side effects (host checks, status comments) the fork owns.
|
|
47
163
|
*/
|
|
48
|
-
|
|
164
|
+
export function stopAwareDbosStep(db, runId) {
|
|
165
|
+
return stopAwareStep(db, runId, dbosStepFor(db, runId), {
|
|
166
|
+
failOpen: true,
|
|
167
|
+
ownership: { workflowId: () => DBOS.workflowID, forkedFrom: isForkOf },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async function runDbosStep(name, fn, supersededBy) {
|
|
171
|
+
let ran;
|
|
49
172
|
try {
|
|
50
|
-
return await DBOS.runStep(
|
|
173
|
+
return await DBOS.runStep(async () => {
|
|
174
|
+
const value = await fn();
|
|
175
|
+
ran = { value };
|
|
176
|
+
return value;
|
|
177
|
+
}, { name, retriesAllowed: false });
|
|
51
178
|
}
|
|
52
179
|
catch (err) {
|
|
53
180
|
if (err instanceof DbosErrors.DBOSWorkflowCancelledError) {
|
|
181
|
+
if (await supersededBy?.(err.workflowID))
|
|
182
|
+
throw new RunOwnershipLostError(name, { cause: err });
|
|
54
183
|
const reason = cancellationReasons.get(err.workflowID);
|
|
55
184
|
throw new RunCancelledError(`Run cancelled: ${reason ?? "no reason given"}`);
|
|
56
185
|
}
|
|
186
|
+
if (err instanceof DbosErrors.DBOSWorkflowConflictError) {
|
|
187
|
+
const discardedUsage = usageOf(ran?.value);
|
|
188
|
+
throw new RunOwnershipLostError(name, { cause: err, ...(discardedUsage ? { discardedUsage } : {}) });
|
|
189
|
+
}
|
|
190
|
+
if (err instanceof DbosErrors.DBOSUnexpectedStepError)
|
|
191
|
+
throw new StepReplayMismatchError(name, { cause: err });
|
|
57
192
|
throw err;
|
|
58
193
|
}
|
|
59
|
-
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The numeric `usage` fields of a step result, if it has any (an LLM turn's
|
|
197
|
+
* token counts and cost). Tool steps return a string and yield nothing.
|
|
198
|
+
*/
|
|
199
|
+
function usageOf(value) {
|
|
200
|
+
if (typeof value !== "object" || value === null || !("usage" in value))
|
|
201
|
+
return undefined;
|
|
202
|
+
const usage = value.usage;
|
|
203
|
+
if (typeof usage !== "object" || usage === null)
|
|
204
|
+
return undefined;
|
|
205
|
+
const numeric = Object.entries(usage).filter((entry) => typeof entry[1] === "number");
|
|
206
|
+
return numeric.length > 0 ? Object.fromEntries(numeric) : undefined;
|
|
207
|
+
}
|
|
60
208
|
/**
|
|
61
209
|
* Registered once at module load — DBOS requires registration before
|
|
62
210
|
* launch(). The body must be deterministic between steps; everything
|
|
63
211
|
* non-deterministic in executeRun/engine is inside a runStep.
|
|
212
|
+
*
|
|
213
|
+
* Replay constraints. A run's workflow is replayed both by a same-version
|
|
214
|
+
* resume and, when recover() takes a waiting lead over after a deploy, by a
|
|
215
|
+
* fork that runs this body under the *new* release against steps the *old*
|
|
216
|
+
* release recorded (see decideTakeover). So:
|
|
217
|
+
* - Code between steps must stay deterministic and safe to repeat: it runs
|
|
218
|
+
* again on every replay, now possibly under newer code.
|
|
219
|
+
* - Step names and their order must only change in ways a replay can still
|
|
220
|
+
* follow; a replay that meets a different recorded name ends the run lost
|
|
221
|
+
* with STEPS_CHANGED_REASON (executeRun's backstop, or runInsideWorkflow).
|
|
222
|
+
* - New code must accept step outputs recorded by the previous release (the
|
|
223
|
+
* `turn:N:llm` TurnResult, tool results). A release that changes a recorded
|
|
224
|
+
* shape keeps reading the old one, or a takeover fails at that step (lost).
|
|
64
225
|
*/
|
|
65
226
|
const runWorkflow = DBOS.registerWorkflow(async (runId) => {
|
|
66
227
|
const self = activeExecutor;
|
|
@@ -112,15 +273,24 @@ export class DbosExecutor {
|
|
|
112
273
|
}
|
|
113
274
|
setActiveExecutor(this);
|
|
114
275
|
if (!DBOS.isInitialized()) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
276
|
+
const launchConfig = dbosLaunchConfig(this.config, this.id, databaseAuthFromEnv());
|
|
277
|
+
systemPool = launchConfig.systemDatabasePool;
|
|
278
|
+
try {
|
|
279
|
+
DBOS.setConfig(launchConfig);
|
|
280
|
+
await DBOS.launch();
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
// DBOS.launch can throw after it initialized (registering the application version, starting
|
|
284
|
+
// event receivers). Shut that half-launched DBOS down so the next launch() starts clean, then
|
|
285
|
+
// end the pool either way: the next launch() makes a new one.
|
|
286
|
+
if (activeExecutor === this)
|
|
287
|
+
setActiveExecutor(undefined);
|
|
288
|
+
if (DBOS.isInitialized()) {
|
|
289
|
+
await DBOS.shutdown().catch((shutdownErr) => dbosLog.warn({ err: shutdownErr }, "failed to shut down DBOS after a failed launch"));
|
|
290
|
+
}
|
|
291
|
+
await endSystemPool();
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
124
294
|
}
|
|
125
295
|
this.launched = true;
|
|
126
296
|
dbosLog.info({ executorId: DBOS.executorID }, "DBOS executor launched");
|
|
@@ -129,9 +299,18 @@ export class DbosExecutor {
|
|
|
129
299
|
if (!this.launched)
|
|
130
300
|
return;
|
|
131
301
|
this.launched = false;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
302
|
+
try {
|
|
303
|
+
await DBOS.shutdown({ workflowCompletionTimeoutMS: 5_000 });
|
|
304
|
+
}
|
|
305
|
+
finally {
|
|
306
|
+
// Only now: shutdown first lets the queue runner finish the dispatch it is in, so a workflow
|
|
307
|
+
// the queue claimed just before (a takeover's fork, an adoption) still starts. Without its
|
|
308
|
+
// executor its body would throw, and DBOS could record that as the workflow's outcome: the
|
|
309
|
+
// next process would then mark a run failed that was only waiting to be taken over.
|
|
310
|
+
if (activeExecutor === this)
|
|
311
|
+
setActiveExecutor(undefined);
|
|
312
|
+
await endSystemPool();
|
|
313
|
+
}
|
|
135
314
|
}
|
|
136
315
|
/** Where a run this executor marks failed files its self-defect (no-op without a configured issue tracker). */
|
|
137
316
|
get selfDefects() {
|
|
@@ -169,6 +348,15 @@ export class DbosExecutor {
|
|
|
169
348
|
// the same failure — dispatchRun's own `.catch` around `start()` calls
|
|
170
349
|
// it too — which is harmless precisely because it is conditional and
|
|
171
350
|
// idempotent: the second call matches zero rows.
|
|
351
|
+
//
|
|
352
|
+
// A workflow that recover() took over (forked, then cancelled) no longer drives the run: the
|
|
353
|
+
// fork does, and settles it. Its rejection is the takeover's cancel, not the run's failure.
|
|
354
|
+
if ((await workflowIdOf(this.db, runId).catch(() => runId)) !== runId) {
|
|
355
|
+
// The error's name only: this path adds no message text to any output.
|
|
356
|
+
const error = err instanceof Error ? err.name : typeof err;
|
|
357
|
+
dbosLog.info({ runId, error }, "the run's original workflow ended after a takeover; its fork drives the run");
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
172
360
|
await markRunFailedFromExecutorError(this.db, runId, err, this.selfDefects);
|
|
173
361
|
throw err;
|
|
174
362
|
}
|
|
@@ -180,11 +368,43 @@ export class DbosExecutor {
|
|
|
180
368
|
if (!this.launched)
|
|
181
369
|
await this.launch();
|
|
182
370
|
dbosLog.info({ runId, reason }, "cancelling durable run");
|
|
371
|
+
// The terminal write comes first and is conditional (the first writer wins), so the run is
|
|
372
|
+
// cancelled with the caller's reason even when its workflow runs in another process (where the
|
|
373
|
+
// reason map below is empty) or has no workflow at all yet (cancelWorkflow then matches
|
|
374
|
+
// nothing). The workflow's next step then throws, and its own terminal write matches no row.
|
|
375
|
+
// The cancel is still attempted when that settle throws (a host or issue update failing after
|
|
376
|
+
// the write) or the database is unreachable: a cancelled row whose workflow kept going would
|
|
377
|
+
// keep spending. The settle's error, if any, is the one rethrown.
|
|
378
|
+
let settleFailed;
|
|
379
|
+
try {
|
|
380
|
+
const row = await this.db.run.findUnique({ where: { id: runId }, select: { status: true } });
|
|
381
|
+
if (row && (row.status === "pending" || row.status === "running")) {
|
|
382
|
+
await failNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, new RunCancelledError(reason ?? "The run was cancelled."));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch (err) {
|
|
386
|
+
settleFailed = { err };
|
|
387
|
+
}
|
|
183
388
|
// Recorded before the cancel so the workflow's next step boundary can
|
|
184
389
|
// find it: DBOS only reports "cancelled", never why.
|
|
185
|
-
|
|
390
|
+
// Keyed by both ids: dbosStep looks it up by the cancelled workflow's id, which is the forked
|
|
391
|
+
// id for a forked run. A failed read targets the run id, the workflow of any run never forked.
|
|
392
|
+
const workflowId = await workflowIdOf(this.db, runId).catch(() => runId);
|
|
393
|
+
if (reason) {
|
|
186
394
|
cancellationReasons.set(runId, reason);
|
|
187
|
-
|
|
395
|
+
cancellationReasons.set(workflowId, reason);
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
await DBOS.cancelWorkflow(workflowId);
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
if (!settleFailed)
|
|
402
|
+
throw err;
|
|
403
|
+
// The error's name only: this path adds no message text to any output.
|
|
404
|
+
dbosLog.warn({ runId, error: err instanceof Error ? err.name : typeof err }, "could not cancel the workflow");
|
|
405
|
+
}
|
|
406
|
+
if (settleFailed)
|
|
407
|
+
throw settleFailed.err;
|
|
188
408
|
}
|
|
189
409
|
/**
|
|
190
410
|
* Answer the reconciler for a stale run. Never relaunches: `resume`
|
|
@@ -213,13 +433,12 @@ export class DbosExecutor {
|
|
|
213
433
|
// DBOS gates recovery and dequeue on application_version. A workflow
|
|
214
434
|
// recorded under a different version is never dequeued here, so
|
|
215
435
|
// resuming it would be an unbounded loop that holds the run
|
|
216
|
-
// `running` forever
|
|
436
|
+
// `running` forever. Instead it is forked under this version when it
|
|
437
|
+
// is only waiting on durable children, and otherwise given up at once
|
|
438
|
+
// so the reconciler reaps it (takeOver).
|
|
217
439
|
const mismatch = versionMismatchReason(status?.applicationVersion, DBOS.applicationVersion);
|
|
218
|
-
if (mismatch)
|
|
219
|
-
this.
|
|
220
|
-
dbosLog.warn({ runId: handle.runId, workflowVersion: status?.applicationVersion }, mismatch);
|
|
221
|
-
return { state: "lost", reason: mismatch };
|
|
222
|
-
}
|
|
440
|
+
if (mismatch)
|
|
441
|
+
return this.takeOver(handle, mismatch, status?.applicationVersion);
|
|
223
442
|
// Belt and braces for every other reason a resume can fail to take
|
|
224
443
|
// (an id we can't dequeue for, a queue that never drains): bound the
|
|
225
444
|
// number of adoptions of one run so the reconciler stops re-driving
|
|
@@ -253,6 +472,56 @@ export class DbosExecutor {
|
|
|
253
472
|
return { state: "lost", reason: decision.reason };
|
|
254
473
|
}
|
|
255
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* A workflow recorded under another application version: fork it under this one when it is only
|
|
477
|
+
* waiting on durable children (decideTakeover), otherwise answer lost with the mismatch. The
|
|
478
|
+
* fork counts as an adoption attempt, so repeated failed takeovers of one run end lost too.
|
|
479
|
+
*/
|
|
480
|
+
async takeOver(handle, mismatch, workflowVersion) {
|
|
481
|
+
const steps = (await DBOS.listWorkflowSteps(handle.id)) ?? [];
|
|
482
|
+
const children = await this.db.run.findMany({
|
|
483
|
+
where: { parentRunId: handle.runId, status: { in: [...DRIVABLE] } },
|
|
484
|
+
select: { status: true, nativeExecutionMode: true, agent: { select: { kind: true } } },
|
|
485
|
+
});
|
|
486
|
+
const decision = decideTakeover(steps.map((s) => ({ functionID: s.functionID, name: s.name, output: s.output })), children.map((c) => ({ status: c.status, kind: c.agent.kind, nativeExecutionMode: c.nativeExecutionMode })), mismatch);
|
|
487
|
+
if (decision.action === "lost") {
|
|
488
|
+
this.resumeAttempts.delete(handle.runId);
|
|
489
|
+
dbosLog.warn({ runId: handle.runId, workflowVersion }, mismatch);
|
|
490
|
+
return { state: "lost", reason: decision.reason };
|
|
491
|
+
}
|
|
492
|
+
const attempts = this.resumeAttempts.get(handle.runId) ?? 0;
|
|
493
|
+
if (shouldGiveUpAdoption(attempts)) {
|
|
494
|
+
this.resumeAttempts.delete(handle.runId);
|
|
495
|
+
dbosLog.warn({ runId: handle.runId, attempts }, "giving up on taking over durable run");
|
|
496
|
+
return { state: "lost", reason: ADOPTION_EXHAUSTED_REASON };
|
|
497
|
+
}
|
|
498
|
+
this.resumeAttempts.set(handle.runId, attempts + 1);
|
|
499
|
+
// Deterministic, so a takeover that forked but never recorded the fork (the run write below
|
|
500
|
+
// failed, or the process died) is finished by the next pass rather than forked a second time:
|
|
501
|
+
// two workflows driving one run would each spend on every turn. DBOS inserts a fork's row with
|
|
502
|
+
// a plain INSERT (bulkForkWorkflows in the SDK's system_database.js), so a repeated id would
|
|
503
|
+
// fail on the key: look first, and treat a lost race the same way.
|
|
504
|
+
const forkedId = forkWorkflowId(handle.id, DBOS.applicationVersion);
|
|
505
|
+
if (!(await DBOS.getWorkflowStatus(forkedId))) {
|
|
506
|
+
try {
|
|
507
|
+
await DBOS.forkWorkflow(handle.id, decision.startStep, {
|
|
508
|
+
newWorkflowID: forkedId,
|
|
509
|
+
applicationVersion: DBOS.applicationVersion,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
catch (err) {
|
|
513
|
+
if (!(await DBOS.getWorkflowStatus(forkedId)))
|
|
514
|
+
throw err;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const forked = DBOS.retrieveWorkflow(forkedId);
|
|
518
|
+
await this.db.run.update({ where: { id: handle.runId }, data: { executionWorkflowId: forkedId } });
|
|
519
|
+
// So nothing can dequeue the original again (it stays recorded as forked from).
|
|
520
|
+
await DBOS.cancelWorkflow(handle.id).catch((err) => dbosLog.warn({ err, runId: handle.runId }, "could not cancel the forked-from workflow"));
|
|
521
|
+
dbosLog.info({ runId: handle.runId, from: handle.id, to: forkedId, startStep: decision.startStep, workflowVersion }, "run taken over under this application version");
|
|
522
|
+
void forked.getResult().catch((err) => dbosLog.error({ err, runId: handle.runId }, "taken-over run failed"));
|
|
523
|
+
return { state: "active" };
|
|
524
|
+
}
|
|
256
525
|
/** Workflow body. Public only so the module-level registration can reach it. */
|
|
257
526
|
async runInsideWorkflow(runId) {
|
|
258
527
|
const beat = () => this.db.run.update({ where: { id: runId }, data: { heartbeatAt: new Date() } }).catch(() => {
|
|
@@ -261,11 +530,35 @@ export class DbosExecutor {
|
|
|
261
530
|
await beat();
|
|
262
531
|
const timer = setInterval(() => void beat(), this.heartbeatIntervalMs);
|
|
263
532
|
try {
|
|
264
|
-
await executeRun(runId, this.providers, this.db, undefined,
|
|
533
|
+
await executeRun(runId, this.providers, this.db, undefined, stopAwareDbosStep(this.db, runId));
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
// An ownership loss leaves the workflow body as the SDK's own conflict error, so DBOS takes
|
|
537
|
+
// its duplicate-execution path: it records nothing and parks this attempt until the winner
|
|
538
|
+
// records the outcome. Any other error escaping here would be recorded as the workflow's
|
|
539
|
+
// outcome while the winner still runs. The runner already logged the loss. A forked-from
|
|
540
|
+
// workflow's own cancellation (dbosStepFor) goes back as itself: DBOS parks that too.
|
|
541
|
+
if (err instanceof RunOwnershipLostError) {
|
|
542
|
+
throw err.cause instanceof DbosErrors.DBOSWorkflowConflictError ||
|
|
543
|
+
err.cause instanceof DbosErrors.DBOSWorkflowCancelledError
|
|
544
|
+
? err.cause
|
|
545
|
+
: new DbosErrors.DBOSWorkflowConflictError(DBOS.workflowID ?? runId);
|
|
546
|
+
}
|
|
547
|
+
// A replay met a step the recorded run does not have at the load step, ahead of executeRun's
|
|
548
|
+
// backstop (which settles a mismatch in any later step itself).
|
|
549
|
+
if (err instanceof StepReplayMismatchError) {
|
|
550
|
+
dbosLog.warn({ err, runId }, "replay no longer matches the recorded run");
|
|
551
|
+
// The same settle as executeRun's backstop: lost (first writer wins), its children stopped.
|
|
552
|
+
await loseNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, STEPS_CHANGED_REASON);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
throw err;
|
|
265
556
|
}
|
|
266
557
|
finally {
|
|
267
558
|
clearInterval(timer);
|
|
268
559
|
cancellationReasons.delete(runId);
|
|
560
|
+
if (DBOS.workflowID)
|
|
561
|
+
cancellationReasons.delete(DBOS.workflowID);
|
|
269
562
|
}
|
|
270
563
|
}
|
|
271
564
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Executor for a process that must never start or stop runs itself: the
|
|
3
|
+
* native sandbox gateway (docs/native-sandbox.md). Sandbox workers can reach
|
|
4
|
+
* the gateway, so it holds no Docker socket, cluster credential, or in-process
|
|
5
|
+
* engine; a child it dispatches is only recorded (Run.startDeferredAt) and a
|
|
6
|
+
* stop it needs only requested (Run.stopRequestedAt). The scheduler leader
|
|
7
|
+
* carries both out through the server's own executor (`drainDeferredRuns`).
|
|
8
|
+
*
|
|
9
|
+
* Coding dispatch is recorded unresolved (`defersCodingResolution`): the worker image,
|
|
10
|
+
* service declaration and knowledge files are resolved by the process that starts the run
|
|
11
|
+
* (the drain's `beforeStart` hook), not here.
|
|
12
|
+
*/
|
|
13
|
+
import type { PrismaClient } from "#prisma";
|
|
14
|
+
import type { Executor } from "./types.js";
|
|
15
|
+
export type DeferredExecutorDb = Pick<PrismaClient, "run">;
|
|
16
|
+
export declare class DeferredExecutor implements Executor {
|
|
17
|
+
private readonly db;
|
|
18
|
+
readonly defersCodingResolution = true;
|
|
19
|
+
constructor(db: DeferredExecutorDb);
|
|
20
|
+
start(runId: string): Promise<void>;
|
|
21
|
+
stop(runId: string, reason?: string): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export interface DrainDeferredRunsOptions {
|
|
24
|
+
db: Pick<PrismaClient, "run">;
|
|
25
|
+
executor: Executor;
|
|
26
|
+
/** Where a start failure is recorded; defaults to marking the run failed with the error. */
|
|
27
|
+
onStartFailed?: (runId: string, err: unknown) => Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Runs after a row is claimed and before `executor.start`. Resolves inputs the deferring process
|
|
30
|
+
* could not; false means the hook ended the run itself so it must not start. A throw is handled
|
|
31
|
+
* like a start failure.
|
|
32
|
+
*/
|
|
33
|
+
beforeStart?: (runId: string) => Promise<boolean>;
|
|
34
|
+
limit?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Starts runs a deferred executor dispatched, and stops runs it asked to stop, through the
|
|
38
|
+
* server's executor. Called on the scheduler leader's tick. Each row is claimed by clearing its
|
|
39
|
+
* marker in a conditional update first, so two drains never start or stop the same run twice.
|
|
40
|
+
*/
|
|
41
|
+
export declare function drainDeferredRuns(options: DrainDeferredRunsOptions): Promise<{
|
|
42
|
+
started: number;
|
|
43
|
+
stopped: number;
|
|
44
|
+
}>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Executor for a process that must never start or stop runs itself: the
|
|
3
|
+
* native sandbox gateway (docs/native-sandbox.md). Sandbox workers can reach
|
|
4
|
+
* the gateway, so it holds no Docker socket, cluster credential, or in-process
|
|
5
|
+
* engine; a child it dispatches is only recorded (Run.startDeferredAt) and a
|
|
6
|
+
* stop it needs only requested (Run.stopRequestedAt). The scheduler leader
|
|
7
|
+
* carries both out through the server's own executor (`drainDeferredRuns`).
|
|
8
|
+
*
|
|
9
|
+
* Coding dispatch is recorded unresolved (`defersCodingResolution`): the worker image,
|
|
10
|
+
* service declaration and knowledge files are resolved by the process that starts the run
|
|
11
|
+
* (the drain's `beforeStart` hook), not here.
|
|
12
|
+
*/
|
|
13
|
+
import { logger } from "../../core/logger.js";
|
|
14
|
+
const deferredLog = logger.child({ module: "deferred-executor" });
|
|
15
|
+
export class DeferredExecutor {
|
|
16
|
+
db;
|
|
17
|
+
defersCodingResolution = true;
|
|
18
|
+
constructor(db) {
|
|
19
|
+
this.db = db;
|
|
20
|
+
}
|
|
21
|
+
async start(runId) {
|
|
22
|
+
await this.db.run.updateMany({ where: { id: runId, status: "pending" }, data: { startDeferredAt: new Date() } });
|
|
23
|
+
}
|
|
24
|
+
async stop(runId, reason) {
|
|
25
|
+
// Never started: nothing runs it, so it can simply end here.
|
|
26
|
+
const cancelled = await this.db.run.updateMany({
|
|
27
|
+
where: { id: runId, status: "pending", startDeferredAt: { not: null } },
|
|
28
|
+
data: {
|
|
29
|
+
status: "cancelled",
|
|
30
|
+
error: reason ?? "Cancelled before it started.",
|
|
31
|
+
finishedAt: new Date(),
|
|
32
|
+
startDeferredAt: null,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
if (cancelled.count > 0)
|
|
36
|
+
return;
|
|
37
|
+
await this.db.run.updateMany({
|
|
38
|
+
where: { id: runId, status: { in: ["pending", "running"] } },
|
|
39
|
+
data: { stopRequestedAt: new Date(), stopRequestReason: reason ?? null },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Starts runs a deferred executor dispatched, and stops runs it asked to stop, through the
|
|
45
|
+
* server's executor. Called on the scheduler leader's tick. Each row is claimed by clearing its
|
|
46
|
+
* marker in a conditional update first, so two drains never start or stop the same run twice.
|
|
47
|
+
*/
|
|
48
|
+
export async function drainDeferredRuns(options) {
|
|
49
|
+
const { db, executor } = options;
|
|
50
|
+
const limit = options.limit ?? 50;
|
|
51
|
+
let started = 0;
|
|
52
|
+
let stopped = 0;
|
|
53
|
+
const toStart = await db.run.findMany({
|
|
54
|
+
where: { startDeferredAt: { not: null }, status: "pending" },
|
|
55
|
+
orderBy: { startDeferredAt: "asc" },
|
|
56
|
+
take: limit,
|
|
57
|
+
select: { id: true },
|
|
58
|
+
});
|
|
59
|
+
for (const { id } of toStart) {
|
|
60
|
+
const claimed = await db.run.updateMany({
|
|
61
|
+
where: { id, startDeferredAt: { not: null }, status: "pending" },
|
|
62
|
+
data: { startDeferredAt: null },
|
|
63
|
+
});
|
|
64
|
+
if (claimed.count === 0)
|
|
65
|
+
continue;
|
|
66
|
+
started += 1;
|
|
67
|
+
// Not awaited: an in-process executor's start runs the whole run.
|
|
68
|
+
void (async () => {
|
|
69
|
+
if (options.beforeStart && !(await options.beforeStart(id)))
|
|
70
|
+
return;
|
|
71
|
+
await executor.start(id);
|
|
72
|
+
})().catch(async (err) => {
|
|
73
|
+
deferredLog.error({ err, runId: id }, "deferred run failed to start");
|
|
74
|
+
await (options.onStartFailed?.(id, err) ??
|
|
75
|
+
db.run.updateMany({
|
|
76
|
+
where: { id, status: { in: ["pending", "running"] } },
|
|
77
|
+
data: { status: "failed", error: err instanceof Error ? err.message : String(err), finishedAt: new Date() },
|
|
78
|
+
}));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const toStop = await db.run.findMany({
|
|
82
|
+
where: { stopRequestedAt: { not: null } },
|
|
83
|
+
orderBy: { stopRequestedAt: "asc" },
|
|
84
|
+
take: limit,
|
|
85
|
+
select: { id: true, stopRequestReason: true, status: true },
|
|
86
|
+
});
|
|
87
|
+
for (const row of toStop) {
|
|
88
|
+
const claimed = await db.run.updateMany({
|
|
89
|
+
where: { id: row.id, stopRequestedAt: { not: null } },
|
|
90
|
+
data: { stopRequestedAt: null, stopRequestReason: null },
|
|
91
|
+
});
|
|
92
|
+
if (claimed.count === 0 || !["pending", "running"].includes(row.status))
|
|
93
|
+
continue;
|
|
94
|
+
stopped += 1;
|
|
95
|
+
await executor.stop(row.id, row.stopRequestReason ?? undefined).catch((err) => {
|
|
96
|
+
deferredLog.warn({ err, runId: row.id }, "deferred stop request failed");
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return { started, stopped };
|
|
100
|
+
}
|
|
@@ -13,5 +13,13 @@ export declare class InProcessExecutor implements Executor {
|
|
|
13
13
|
private readonly heartbeatIntervalMs;
|
|
14
14
|
constructor(providers: NativeRunProviders, db?: RunnerDb, heartbeatIntervalMs?: number);
|
|
15
15
|
start(runId: string): Promise<void>;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Records the run cancelled (only while it is still pending or running: the first terminal write
|
|
18
|
+
* wins) and settles it like any finished run (its review check, status comments, notifications).
|
|
19
|
+
* The engine itself is stopped cooperatively: executeRun's inline step runner reads the run's row
|
|
20
|
+
* before every step (stopAwareStep), so the process executing it, this one or another, stops it
|
|
21
|
+
* at the next step boundary, and a run that has not started yet never does. A step already in
|
|
22
|
+
* flight (one model turn or tool call) finishes first; its spend is still recorded.
|
|
23
|
+
*/
|
|
24
|
+
stop(runId: string, reason?: string): Promise<void>;
|
|
17
25
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* heartbeat and recovers the run to `lost` rather than leaving it stuck
|
|
6
6
|
* `running` forever.
|
|
7
7
|
*/
|
|
8
|
-
import { executeRun } from "../../core/runner.js";
|
|
8
|
+
import { executeRun, failNativeRun, nativeRunIntegrations, RunCancelledError, } from "../../core/runner.js";
|
|
9
9
|
import { prisma as defaultDb } from "../../core/db.js";
|
|
10
10
|
import { HEARTBEAT_INTERVAL_MS } from "../../core/timing.js";
|
|
11
11
|
export class InProcessExecutor {
|
|
@@ -31,8 +31,18 @@ export class InProcessExecutor {
|
|
|
31
31
|
clearInterval(timer);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Records the run cancelled (only while it is still pending or running: the first terminal write
|
|
36
|
+
* wins) and settles it like any finished run (its review check, status comments, notifications).
|
|
37
|
+
* The engine itself is stopped cooperatively: executeRun's inline step runner reads the run's row
|
|
38
|
+
* before every step (stopAwareStep), so the process executing it, this one or another, stops it
|
|
39
|
+
* at the next step boundary, and a run that has not started yet never does. A step already in
|
|
40
|
+
* flight (one model turn or tool call) finishes first; its spend is still recorded.
|
|
41
|
+
*/
|
|
42
|
+
async stop(runId, reason) {
|
|
43
|
+
const run = await this.db.run.findUnique({ where: { id: runId }, select: { status: true } });
|
|
44
|
+
if (!run || (run.status !== "pending" && run.status !== "running"))
|
|
45
|
+
return;
|
|
46
|
+
await failNativeRun({ runId, db: this.db, providers: this.providers, ...nativeRunIntegrations(this.providers, this.db) }, new RunCancelledError(reason ?? "The run was cancelled."));
|
|
37
47
|
}
|
|
38
48
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IssueTrackerRegistry } from "../issue-tracker/types.js";
|
|
2
|
+
import type { ReviewHostRegistry } from "../review-host/types.js";
|
|
3
|
+
import type { LinkedIssueRef } from "./container.js";
|
|
4
|
+
/**
|
|
5
|
+
* The executor's readLinkedIssue: a GitHub issue through the review host's
|
|
6
|
+
* issue read (the App's installation token for the run's repository), a Jira
|
|
7
|
+
* issue through the configured tracker. Null when the number is a pull
|
|
8
|
+
* request, the issue is missing, or no host or tracker is configured.
|
|
9
|
+
*/
|
|
10
|
+
export declare function linkedIssueReader(deps: {
|
|
11
|
+
hosts: ReviewHostRegistry;
|
|
12
|
+
issueTrackers: IssueTrackerRegistry;
|
|
13
|
+
}): (ref: LinkedIssueRef) => Promise<{
|
|
14
|
+
title: string;
|
|
15
|
+
body: string;
|
|
16
|
+
} | null>;
|