@wardby/cli 0.5.3 → 0.6.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/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 +7 -1
- package/dist/claude-coding-worker/driver.js +38 -5
- package/dist/claude-coding-worker/sdk.js +13 -4
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +5 -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 +141 -5
- package/dist/coding/claude-context.d.ts +45 -0
- package/dist/coding/claude-context.js +434 -0
- package/dist/coding/profile.d.ts +12 -0
- package/dist/coding/profile.js +6 -0
- package/dist/coding/protocol.d.ts +104 -0
- package/dist/coding/protocol.js +87 -3
- package/dist/coding-worker/artifact.d.ts +8 -0
- package/dist/coding-worker/artifact.js +2 -2
- package/dist/coding-worker/driver.js +2 -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/types.d.ts +2 -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 +53 -0
- package/dist/config/providers.js +92 -6
- package/dist/core/db.d.ts +16 -6
- package/dist/core/db.js +12 -10
- package/dist/core/dispatch.d.ts +11 -0
- package/dist/core/dispatch.js +36 -1
- package/dist/core/engine-native.js +9 -5
- package/dist/core/host-events.d.ts +49 -3
- package/dist/core/host-events.js +289 -15
- package/dist/core/issue-bridge.js +42 -2
- package/dist/core/issue-events.js +12 -1
- package/dist/core/issue-status.js +14 -3
- package/dist/core/merge-order-check.d.ts +129 -0
- package/dist/core/merge-order-check.js +336 -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 +25 -0
- package/dist/core/notification-templates.js +105 -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/reconciler.d.ts +4 -2
- package/dist/core/reconciler.js +29 -5
- package/dist/core/related-pull-requests.d.ts +48 -4
- package/dist/core/related-pull-requests.js +113 -11
- package/dist/core/repo-access.d.ts +15 -0
- package/dist/core/repo-access.js +66 -0
- package/dist/core/review-fix.d.ts +37 -0
- package/dist/core/review-fix.js +207 -6
- package/dist/core/review-host-tools.d.ts +20 -0
- package/dist/core/review-host-tools.js +58 -2
- package/dist/core/runner.d.ts +336 -3
- package/dist/core/runner.js +894 -317
- package/dist/core/secret-broker-config.d.ts +103 -0
- package/dist/core/secret-broker-config.js +112 -0
- package/dist/core/secrets.d.ts +39 -4
- package/dist/core/secrets.js +148 -40
- 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 +82 -0
- package/dist/core/workflow-events.js +44 -0
- package/dist/core/workflow-run-events.d.ts +16 -0
- package/dist/core/workflow-run-events.js +40 -0
- package/dist/generated/prisma/browser.d.ts +58 -0
- package/dist/generated/prisma/client.d.ts +58 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +150 -0
- package/dist/generated/prisma/enums.d.ts +27 -0
- package/dist/generated/prisma/enums.js +23 -0
- package/dist/generated/prisma/internal/class.d.ts +88 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +772 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +135 -4
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +139 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -4
- package/dist/generated/prisma/models/Agent.d.ts +360 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +73 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1675 -0
- package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1517 -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/Run.d.ts +826 -1
- package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
- 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 +8 -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 +1363 -176
- package/dist/import/create.js +17 -0
- package/dist/import/neutral-schema.d.ts +6 -2
- package/dist/import/neutral-schema.js +2 -0
- package/dist/mcp/auth/access.d.ts +1 -0
- 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/context.d.ts +6 -0
- package/dist/mcp/host-events/github-ingress.d.ts +23 -1
- package/dist/mcp/host-events/github-ingress.js +68 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +59 -10
- package/dist/mcp/tools/agents.js +82 -11
- package/dist/mcp/tools/notification-channels.d.ts +2 -0
- package/dist/mcp/tools/notification-channels.js +293 -0
- package/dist/mcp/tools/power.d.ts +2 -0
- package/dist/mcp/tools/power.js +77 -0
- package/dist/mcp/tools/runs.d.ts +0 -6
- package/dist/mcp/tools/runs.js +7 -2
- 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 +200 -10
- package/dist/mcp/tools/secret-elicitation-server.js +8 -1
- 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 +184 -7
- package/dist/mcp/tools/tools.d.ts +1 -1
- package/dist/mcp/tools/tools.js +22 -2
- 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 +74 -0
- package/dist/native-worker/docker-launcher.js +237 -0
- package/dist/native-worker/gateway-server.d.ts +39 -0
- package/dist/native-worker/gateway-server.js +315 -0
- package/dist/native-worker/gateway.d.ts +44 -0
- package/dist/native-worker/gateway.js +197 -0
- package/dist/native-worker/http-server.d.ts +22 -0
- package/dist/native-worker/http-server.js +109 -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 +102 -0
- package/dist/native-worker/kubernetes-launcher.js +335 -0
- package/dist/native-worker/launch.d.ts +45 -0
- package/dist/native-worker/launch.js +44 -0
- package/dist/native-worker/ledger.d.ts +109 -0
- package/dist/native-worker/ledger.js +192 -0
- package/dist/native-worker/loopback.d.ts +12 -0
- package/dist/native-worker/loopback.js +49 -0
- package/dist/native-worker/main.d.ts +7 -0
- package/dist/native-worker/main.js +74 -0
- package/dist/native-worker/protocol.d.ts +744 -0
- package/dist/native-worker/protocol.js +200 -0
- package/dist/native-worker/sandbox-executor.d.ts +68 -0
- package/dist/native-worker/sandbox-executor.js +210 -0
- package/dist/native-worker/stdio.d.ts +29 -0
- package/dist/native-worker/stdio.js +188 -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 +115 -0
- 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 +13 -1
- 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/engine/types.d.ts +19 -0
- package/dist/providers/engine/types.js +22 -0
- package/dist/providers/executor/composition.d.ts +24 -1
- package/dist/providers/executor/composition.js +39 -6
- package/dist/providers/executor/container.d.ts +24 -1
- package/dist/providers/executor/container.js +101 -11
- package/dist/providers/executor/dbos.d.ts +42 -0
- package/dist/providers/executor/dbos.js +118 -12
- package/dist/providers/executor/deferred.d.ts +56 -0
- package/dist/providers/executor/deferred.js +119 -0
- package/dist/providers/executor/routing.d.ts +37 -10
- package/dist/providers/executor/routing.js +73 -32
- package/dist/providers/executor/types.d.ts +12 -0
- package/dist/providers/jobs/docker.js +3 -3
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +21 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +42 -1
- package/dist/providers/jobs/kubernetes-api.d.ts +17 -1
- package/dist/providers/jobs/kubernetes-api.js +7 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
- package/dist/providers/jobs/kubernetes-client.js +52 -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 +3 -1
- package/dist/providers/jobs/kubernetes-isolation.js +6 -0
- 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 +36 -1
- package/dist/providers/jobs/kubernetes.js +74 -4
- 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 +9 -0
- package/dist/providers/review-host/github.d.ts +11 -1
- package/dist/providers/review-host/github.js +50 -0
- package/dist/providers/review-host/types.d.ts +23 -0
- package/dist/providers/vcs/github.d.ts +32 -6
- package/dist/providers/vcs/github.js +74 -16
- package/dist/quickstart/coding-seed.d.ts +10 -3
- package/dist/quickstart/coding-seed.js +74 -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 +1 -1
- 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/host-functions.d.ts +34 -0
- package/dist/sandbox/host-functions.js +144 -80
- 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 +162 -0
- package/dist/sandbox/user-tool.d.ts +14 -0
- package/dist/sandbox/user-tool.js +32 -0
- package/dist/serve.js +18 -0
- package/dist/viewer/api-schema.d.ts +210 -14
- package/dist/viewer/api-schema.js +22 -0
- package/dist/viewer/build-schemas.js +4 -1
- 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 +172 -0
- package/docs/README.md +7 -0
- package/docs/agent-recipes.md +57 -8
- package/docs/architecture-runtime.md +16 -1
- package/docs/code-review-agents.md +139 -5
- package/docs/coding-agent-setup.md +113 -5
- package/docs/coding-packages.md +4 -2
- package/docs/coding-services.md +3 -1
- package/docs/coding-worker-byo-images.md +198 -6
- package/docs/coding-worker-isolation.md +68 -14
- package/docs/getting-started-gke.md +225 -9
- package/docs/getting-started-identity-provider.md +21 -10
- package/docs/getting-started.md +5 -4
- package/docs/jira-agents.md +5 -1
- package/docs/native-sandbox.md +635 -0
- package/docs/release-verification.md +9 -0
- package/docs/security-deployment.md +113 -12
- package/docs/slack-notifications.md +252 -0
- package/docs/tool-secrets.md +252 -0
- package/docs/viewer-api.md +46 -5
- package/docs/viewer-api.openapi.yml +1404 -0
- package/help/admin-viewer.md +6 -2
- package/help/agent-recipes.md +27 -0
- package/help/architecture-agent.md +1 -1
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +3 -6
- package/help/code-review-agents.md +68 -6
- package/help/deploy-gke.md +8 -1
- package/help/deployment-targets.md +25 -14
- package/help/errors/coding-provider-not-configured.md +2 -2
- package/help/errors/database-auth-invalid.md +28 -0
- package/help/errors/github-account-not-allowed.md +25 -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/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-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-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 +20 -0
- package/help/errors/native-sandbox-worker-lost.md +20 -0
- package/help/errors/native-sandbox-worker-unready.md +22 -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-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/getting-started.md +4 -5
- package/help/github.md +18 -1
- package/help/identity-and-access.md +5 -1
- package/help/local-repositories.md +2 -3
- package/help/low-power-mode.md +125 -0
- package/help/merge-order-check.md +117 -0
- package/help/mobile-app.md +54 -0
- package/help/native-sandbox.md +136 -0
- package/help/observability.md +8 -0
- package/help/related-pull-requests.md +70 -9
- package/help/repo-instructions-and-skills.md +91 -0
- package/help/review-fix-rounds.md +10 -0
- package/help/slack-notifications.md +62 -0
- package/help/troubleshooting/coding-workers.md +21 -0
- package/package.json +11 -4
- 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/schema.prisma +362 -91
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class FakeChatProvider {
|
|
2
|
+
name = "slack";
|
|
3
|
+
posts = [];
|
|
4
|
+
updates = [];
|
|
5
|
+
channels = new Map();
|
|
6
|
+
queuedErrors = {
|
|
7
|
+
postMessage: [],
|
|
8
|
+
updateMessage: [],
|
|
9
|
+
channelInfo: [],
|
|
10
|
+
authTest: [],
|
|
11
|
+
};
|
|
12
|
+
nextTs = 1;
|
|
13
|
+
failNext(method, err) {
|
|
14
|
+
this.queuedErrors[method].push(err);
|
|
15
|
+
}
|
|
16
|
+
consumeFailure(method) {
|
|
17
|
+
const err = this.queuedErrors[method].shift();
|
|
18
|
+
if (err)
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
async postMessage(channelId, msg, opts = {}) {
|
|
22
|
+
this.consumeFailure("postMessage");
|
|
23
|
+
const ts = `${this.nextTs++}.000`;
|
|
24
|
+
this.posts.push({ channelId, ts, msg, threadTs: opts.threadTs, broadcast: opts.broadcast });
|
|
25
|
+
return { ts };
|
|
26
|
+
}
|
|
27
|
+
async updateMessage(channelId, ts, msg) {
|
|
28
|
+
this.consumeFailure("updateMessage");
|
|
29
|
+
this.updates.push({ channelId, ts, msg });
|
|
30
|
+
}
|
|
31
|
+
async channelInfo(channel) {
|
|
32
|
+
this.consumeFailure("channelInfo");
|
|
33
|
+
return this.channels.get(channel) ?? null;
|
|
34
|
+
}
|
|
35
|
+
async authTest() {
|
|
36
|
+
this.consumeFailure("authTest");
|
|
37
|
+
return { team: "fake", botUserId: "UFAKE" };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ChatProviderRegistry } from "./types.js";
|
|
2
|
+
export * from "./types.js";
|
|
3
|
+
/** One provider per configured chat service; empty when Slack is not configured. */
|
|
4
|
+
export declare function buildChatProviders(env?: NodeJS.ProcessEnv, fetchImpl?: typeof fetch): ChatProviderRegistry;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { loadSlackConfig } from "../../config/providers.js";
|
|
2
|
+
import { SlackChatProvider } from "./slack.js";
|
|
3
|
+
export * from "./types.js";
|
|
4
|
+
/** One provider per configured chat service; empty when Slack is not configured. */
|
|
5
|
+
export function buildChatProviders(env = process.env, fetchImpl) {
|
|
6
|
+
const slack = loadSlackConfig(env);
|
|
7
|
+
return slack ? { slack: new SlackChatProvider(slack, fetchImpl) } : {};
|
|
8
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack Web API client for workflow notifications: chat.postMessage,
|
|
3
|
+
* chat.update, conversations.info, auth.test. Plain fetch (JSON bodies for
|
|
4
|
+
* writes, form-encoded for reads), bot token. Every failure becomes a ChatError with a normalized code the
|
|
5
|
+
* dispatcher acts on; Slack's own error string is kept for the operator.
|
|
6
|
+
*/
|
|
7
|
+
import type { SlackConfig } from "../../config/providers.js";
|
|
8
|
+
import { type ChatMessage, type ChatProvider } from "./types.js";
|
|
9
|
+
export declare class SlackChatProvider implements ChatProvider {
|
|
10
|
+
private readonly config;
|
|
11
|
+
private readonly fetchImpl;
|
|
12
|
+
readonly name: "slack";
|
|
13
|
+
constructor(config: SlackConfig, fetchImpl?: typeof fetch);
|
|
14
|
+
/**
|
|
15
|
+
* `form` for read methods (conversations.info, auth.test): Slack accepts JSON
|
|
16
|
+
* bodies only on write methods and answers a read method's JSON body with
|
|
17
|
+
* invalid_arguments.
|
|
18
|
+
*/
|
|
19
|
+
private call;
|
|
20
|
+
private messageBody;
|
|
21
|
+
postMessage(channelId: string, msg: ChatMessage, opts?: {
|
|
22
|
+
threadTs?: string;
|
|
23
|
+
broadcast?: boolean;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
ts: string;
|
|
26
|
+
}>;
|
|
27
|
+
updateMessage(channelId: string, ts: string, msg: ChatMessage): Promise<void>;
|
|
28
|
+
channelInfo(channel: string): Promise<{
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
isPrivate: boolean;
|
|
32
|
+
} | null>;
|
|
33
|
+
authTest(): Promise<{
|
|
34
|
+
team: string;
|
|
35
|
+
botUserId: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ChatError } from "./types.js";
|
|
2
|
+
const CHANNEL_UNREACHABLE = new Set(["channel_not_found", "not_in_channel", "is_archived"]);
|
|
3
|
+
const AUTH_FAILED = new Set([
|
|
4
|
+
"invalid_auth",
|
|
5
|
+
"not_authed",
|
|
6
|
+
"token_revoked",
|
|
7
|
+
"token_expired",
|
|
8
|
+
"account_inactive",
|
|
9
|
+
"missing_scope",
|
|
10
|
+
]);
|
|
11
|
+
const TIMEOUT_MS = 10_000;
|
|
12
|
+
function classify(slackError) {
|
|
13
|
+
if (CHANNEL_UNREACHABLE.has(slackError))
|
|
14
|
+
return "channel_unreachable";
|
|
15
|
+
if (AUTH_FAILED.has(slackError))
|
|
16
|
+
return "auth_failed";
|
|
17
|
+
if (slackError === "message_not_found")
|
|
18
|
+
return "message_not_found";
|
|
19
|
+
if (slackError === "ratelimited")
|
|
20
|
+
return "rate_limited";
|
|
21
|
+
return "transient";
|
|
22
|
+
}
|
|
23
|
+
export class SlackChatProvider {
|
|
24
|
+
config;
|
|
25
|
+
fetchImpl;
|
|
26
|
+
name = "slack";
|
|
27
|
+
constructor(config, fetchImpl = fetch) {
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.fetchImpl = fetchImpl;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* `form` for read methods (conversations.info, auth.test): Slack accepts JSON
|
|
33
|
+
* bodies only on write methods and answers a read method's JSON body with
|
|
34
|
+
* invalid_arguments.
|
|
35
|
+
*/
|
|
36
|
+
async call(method, body, encoding = "json") {
|
|
37
|
+
let res;
|
|
38
|
+
try {
|
|
39
|
+
res = await this.fetchImpl(`${this.config.apiBaseUrl}/${method}`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
authorization: `Bearer ${this.config.botToken}`,
|
|
43
|
+
"content-type": encoding === "json" ? "application/json; charset=utf-8" : "application/x-www-form-urlencoded",
|
|
44
|
+
},
|
|
45
|
+
body: encoding === "json"
|
|
46
|
+
? JSON.stringify(body)
|
|
47
|
+
: new URLSearchParams(Object.fromEntries(Object.entries(body).map(([k, v]) => [k, String(v)]))).toString(),
|
|
48
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
throw new ChatError("transient", err instanceof Error ? err.message : String(err));
|
|
53
|
+
}
|
|
54
|
+
if (res.status === 429) {
|
|
55
|
+
const seconds = Number(res.headers.get("retry-after") ?? "1");
|
|
56
|
+
throw new ChatError("rate_limited", "ratelimited", (Number.isFinite(seconds) && seconds > 0 ? seconds : 1) * 1000);
|
|
57
|
+
}
|
|
58
|
+
if (!res.ok)
|
|
59
|
+
throw new ChatError("transient", `http_${res.status}`);
|
|
60
|
+
const json = (await res.json().catch(() => ({ ok: false, error: "invalid_json" })));
|
|
61
|
+
if (json.ok !== true) {
|
|
62
|
+
const slackError = typeof json.error === "string" ? json.error : "unknown_error";
|
|
63
|
+
throw new ChatError(classify(slackError), slackError);
|
|
64
|
+
}
|
|
65
|
+
return json;
|
|
66
|
+
}
|
|
67
|
+
messageBody(msg) {
|
|
68
|
+
return {
|
|
69
|
+
text: msg.text,
|
|
70
|
+
...(msg.blocks ? { blocks: msg.blocks } : {}),
|
|
71
|
+
...(this.config.customize && msg.username ? { username: msg.username } : {}),
|
|
72
|
+
...(this.config.customize && msg.iconEmoji ? { icon_emoji: msg.iconEmoji } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async postMessage(channelId, msg, opts = {}) {
|
|
76
|
+
const json = await this.call("chat.postMessage", {
|
|
77
|
+
channel: channelId,
|
|
78
|
+
...this.messageBody(msg),
|
|
79
|
+
...(opts.threadTs ? { thread_ts: opts.threadTs } : {}),
|
|
80
|
+
...(opts.threadTs && opts.broadcast ? { reply_broadcast: true } : {}),
|
|
81
|
+
unfurl_links: false,
|
|
82
|
+
unfurl_media: false,
|
|
83
|
+
});
|
|
84
|
+
return { ts: String(json.ts) };
|
|
85
|
+
}
|
|
86
|
+
async updateMessage(channelId, ts, msg) {
|
|
87
|
+
await this.call("chat.update", { channel: channelId, ts, ...this.messageBody(msg) });
|
|
88
|
+
}
|
|
89
|
+
async channelInfo(channel) {
|
|
90
|
+
try {
|
|
91
|
+
const json = await this.call("conversations.info", { channel }, "form");
|
|
92
|
+
const c = json.channel;
|
|
93
|
+
return { id: c.id, name: c.name, isPrivate: c.is_private === true };
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof ChatError && err.code === "channel_unreachable")
|
|
97
|
+
return null;
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async authTest() {
|
|
102
|
+
const json = await this.call("auth.test", {}, "form");
|
|
103
|
+
return { team: String(json.team), botUserId: String(json.user_id) };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral chat surface for outbound workflow notifications. Slack is
|
|
3
|
+
* the first (and only) implementation (./slack.ts). wardby only ever posts
|
|
4
|
+
* or updates messages here — it never reads channel history or listens for
|
|
5
|
+
* events.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CHAT_PROVIDERS: readonly ["slack"];
|
|
8
|
+
export type ChatProviderName = (typeof CHAT_PROVIDERS)[number];
|
|
9
|
+
export type ChatErrorCode = "rate_limited" | "channel_unreachable" | "auth_failed" | "message_not_found" | "transient";
|
|
10
|
+
export declare class ChatError extends Error {
|
|
11
|
+
readonly code: ChatErrorCode;
|
|
12
|
+
readonly slackError: string;
|
|
13
|
+
readonly retryAfterMs?: number | undefined;
|
|
14
|
+
constructor(code: ChatErrorCode, slackError: string, retryAfterMs?: number | undefined);
|
|
15
|
+
}
|
|
16
|
+
export interface ChatMessage {
|
|
17
|
+
text: string;
|
|
18
|
+
blocks?: unknown[];
|
|
19
|
+
username?: string;
|
|
20
|
+
iconEmoji?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ChatProvider {
|
|
23
|
+
readonly name: ChatProviderName;
|
|
24
|
+
postMessage(channelId: string, msg: ChatMessage, opts?: {
|
|
25
|
+
threadTs?: string;
|
|
26
|
+
broadcast?: boolean;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
ts: string;
|
|
29
|
+
}>;
|
|
30
|
+
updateMessage(channelId: string, ts: string, msg: ChatMessage): Promise<void>;
|
|
31
|
+
/** null when the bot cannot see the channel; throws ChatError("auth_failed") on missing scope. */
|
|
32
|
+
channelInfo(channel: string): Promise<{
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
isPrivate: boolean;
|
|
36
|
+
} | null>;
|
|
37
|
+
authTest(): Promise<{
|
|
38
|
+
team: string;
|
|
39
|
+
botUserId: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export type ChatProviderRegistry = Partial<Record<ChatProviderName, ChatProvider>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral chat surface for outbound workflow notifications. Slack is
|
|
3
|
+
* the first (and only) implementation (./slack.ts). wardby only ever posts
|
|
4
|
+
* or updates messages here — it never reads channel history or listens for
|
|
5
|
+
* events.
|
|
6
|
+
*/
|
|
7
|
+
export const CHAT_PROVIDERS = ["slack"];
|
|
8
|
+
export class ChatError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
slackError;
|
|
11
|
+
retryAfterMs;
|
|
12
|
+
constructor(code, slackError, retryAfterMs) {
|
|
13
|
+
super(`chat_error:${code}:${slackError}`);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.slackError = slackError;
|
|
16
|
+
this.retryAfterMs = retryAfterMs;
|
|
17
|
+
this.name = "ChatError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -48,6 +48,25 @@ export interface LoadedTool {
|
|
|
48
48
|
* only on earlier step results and on `agent` fields fixed at run start.
|
|
49
49
|
*/
|
|
50
50
|
export type StepRunner = <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Part of the StepRunner contract: a step runner may throw this when another
|
|
53
|
+
* execution of the same run recorded the step first, so this attempt no
|
|
54
|
+
* longer owns the run. The attempt must stop without writing the run (the
|
|
55
|
+
* winner does that); engines and the runner rethrow it untouched.
|
|
56
|
+
*/
|
|
57
|
+
export declare class RunOwnershipLostError extends Error {
|
|
58
|
+
readonly step: string;
|
|
59
|
+
/**
|
|
60
|
+
* Usage the losing step's body reported before its result was discarded
|
|
61
|
+
* (an LLM turn's token counts and cost), when the step runner saw it. Not
|
|
62
|
+
* recorded on any run: the winner's result replaces it. Logged only.
|
|
63
|
+
*/
|
|
64
|
+
readonly discardedUsage?: Readonly<Record<string, number>>;
|
|
65
|
+
constructor(step: string, options?: {
|
|
66
|
+
cause?: unknown;
|
|
67
|
+
discardedUsage?: Readonly<Record<string, number>>;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
51
70
|
/** The no-checkpoint default: run the step body directly. */
|
|
52
71
|
export declare const runStepInline: StepRunner;
|
|
53
72
|
/**
|
|
@@ -12,5 +12,27 @@
|
|
|
12
12
|
* which engine is driving: an engine that calls a provider SDK directly
|
|
13
13
|
* blinds the pre-flight refuse and mid-stream cutoff, and is not allowed.
|
|
14
14
|
*/
|
|
15
|
+
/**
|
|
16
|
+
* Part of the StepRunner contract: a step runner may throw this when another
|
|
17
|
+
* execution of the same run recorded the step first, so this attempt no
|
|
18
|
+
* longer owns the run. The attempt must stop without writing the run (the
|
|
19
|
+
* winner does that); engines and the runner rethrow it untouched.
|
|
20
|
+
*/
|
|
21
|
+
export class RunOwnershipLostError extends Error {
|
|
22
|
+
step;
|
|
23
|
+
/**
|
|
24
|
+
* Usage the losing step's body reported before its result was discarded
|
|
25
|
+
* (an LLM turn's token counts and cost), when the step runner saw it. Not
|
|
26
|
+
* recorded on any run: the winner's result replaces it. Logged only.
|
|
27
|
+
*/
|
|
28
|
+
discardedUsage;
|
|
29
|
+
constructor(step, options) {
|
|
30
|
+
super(`run_ownership_lost: another execution recorded step "${step}" first; this attempt stops.`, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
31
|
+
this.name = "RunOwnershipLostError";
|
|
32
|
+
this.step = step;
|
|
33
|
+
if (options?.discardedUsage)
|
|
34
|
+
this.discardedUsage = options.discardedUsage;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
15
37
|
/** The no-checkpoint default: run the step body directly. */
|
|
16
38
|
export const runStepInline = (_name, fn) => fn();
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import { type ProviderConfig } from "../../config/providers.js";
|
|
3
|
+
import { type Power } from "../../core/power.js";
|
|
4
|
+
import { type ReReviewDeps } from "../../core/review-fix.js";
|
|
3
5
|
import type { KubernetesApi } from "../jobs/kubernetes-api.js";
|
|
4
6
|
import type { Executor } from "./types.js";
|
|
5
7
|
import { type RepoAccessGate } from "../../core/repo-access.js";
|
|
8
|
+
/**
|
|
9
|
+
* The coding-run terminal hook: a review-fix round's coding run that made no change re-reviews
|
|
10
|
+
* the PR once (core/review-fix.ts). Started in the background so the executor's terminal path
|
|
11
|
+
* (and the slot release after it) never waits on the host; idempotent, and never throws.
|
|
12
|
+
* `deps` is read only when a run finishes, after composition returned.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reReviewOnCodingRunTerminal(deps: () => ReReviewDeps): (runId: string) => void;
|
|
6
15
|
export interface ConfiguredExecutorOptions {
|
|
7
16
|
native: Executor;
|
|
17
|
+
/**
|
|
18
|
+
* Runs native agents whose run snapshot says `sandbox`. Composed whether or
|
|
19
|
+
* not a coding job launcher is configured. Absent: sandbox runs go to
|
|
20
|
+
* `native`, whose runner refuses them (RoutingExecutor).
|
|
21
|
+
*/
|
|
22
|
+
nativeSandbox?: Executor;
|
|
8
23
|
db: PrismaClient;
|
|
9
24
|
env?: NodeJS.ProcessEnv;
|
|
10
25
|
providerConfig?: ProviderConfig;
|
|
@@ -12,6 +27,14 @@ export interface ConfiguredExecutorOptions {
|
|
|
12
27
|
kubernetesApi?: KubernetesApi;
|
|
13
28
|
/** Repository authorization for coding runs; built from the configured review hosts when absent. */
|
|
14
29
|
repoAccess?: RepoAccessGate;
|
|
30
|
+
/**
|
|
31
|
+
* Low-power mode, built once by the composition root and shared. Used only by the Kubernetes
|
|
32
|
+
* launcher (wakes the coding proxy before a run); absent: `DISABLED_POWER`.
|
|
33
|
+
*/
|
|
34
|
+
power?: Power;
|
|
15
35
|
}
|
|
16
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Builds container execution only when Docker or Kubernetes is explicitly
|
|
38
|
+
* selected, and native sandbox routing whenever a sandbox executor is given.
|
|
39
|
+
*/
|
|
17
40
|
export declare function buildConfiguredExecutor(options: ConfiguredExecutorOptions): Executor;
|
|
@@ -5,6 +5,8 @@ import { summarizeRegistryFetches } from "../../coding/registry/report.js";
|
|
|
5
5
|
import { drainCodingQueue } from "../../core/coding-queue.js";
|
|
6
6
|
import { prismaServiceStateReporter } from "../../core/coding-service-status.js";
|
|
7
7
|
import { logger } from "../../core/logger.js";
|
|
8
|
+
import { DISABLED_POWER } from "../../core/power.js";
|
|
9
|
+
import { reReviewAfterNoChangeFix } from "../../core/review-fix.js";
|
|
8
10
|
import { EnvironmentCredentialResolver } from "../coding-proxy/environment-credentials.js";
|
|
9
11
|
import { CodingProxy } from "../coding-proxy/proxy.js";
|
|
10
12
|
import { PrismaProxyLedger } from "../coding-proxy/prisma-ledger.js";
|
|
@@ -22,12 +24,33 @@ import { createRepoAccessGate } from "../../core/repo-access.js";
|
|
|
22
24
|
import { buildIssueTrackers } from "../issue-tracker/index.js";
|
|
23
25
|
import { buildReviewHosts } from "../review-host/index.js";
|
|
24
26
|
const compositionLog = logger.child({ module: "executor-composition" });
|
|
25
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* The coding-run terminal hook: a review-fix round's coding run that made no change re-reviews
|
|
29
|
+
* the PR once (core/review-fix.ts). Started in the background so the executor's terminal path
|
|
30
|
+
* (and the slot release after it) never waits on the host; idempotent, and never throws.
|
|
31
|
+
* `deps` is read only when a run finishes, after composition returned.
|
|
32
|
+
*/
|
|
33
|
+
export function reReviewOnCodingRunTerminal(deps) {
|
|
34
|
+
return (runId) => {
|
|
35
|
+
void Promise.resolve()
|
|
36
|
+
.then(() => reReviewAfterNoChangeFix(runId, deps()))
|
|
37
|
+
.catch((err) => compositionLog.warn({ err, runId }, "no-change re-review hook failed"));
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds container execution only when Docker or Kubernetes is explicitly
|
|
42
|
+
* selected, and native sandbox routing whenever a sandbox executor is given.
|
|
43
|
+
*/
|
|
26
44
|
export function buildConfiguredExecutor(options) {
|
|
27
45
|
const env = options.env ?? process.env;
|
|
28
46
|
const providerConfig = options.providerConfig ?? loadProviderConfig(env);
|
|
29
|
-
if (providerConfig.jobs !== "docker" && providerConfig.jobs !== "kubernetes")
|
|
30
|
-
|
|
47
|
+
if (providerConfig.jobs !== "docker" && providerConfig.jobs !== "kubernetes") {
|
|
48
|
+
if (!options.nativeSandbox)
|
|
49
|
+
return options.native;
|
|
50
|
+
// No coding launcher: coding runs reach the native executor, whose runner fails them with
|
|
51
|
+
// the "needs a container executor" explanation, exactly as without this wrapper.
|
|
52
|
+
return new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, options.native, options.nativeSandbox);
|
|
53
|
+
}
|
|
31
54
|
const github = loadGitHubVcsConfig(env);
|
|
32
55
|
const config = loadContainerExecutorConfig(env);
|
|
33
56
|
// Each provider's images are optional, but a coding launcher with neither can run nothing.
|
|
@@ -80,6 +103,7 @@ export function buildConfiguredExecutor(options) {
|
|
|
80
103
|
resolveCapability: (runId) => capabilities.get(runId),
|
|
81
104
|
readyTimeoutMs: kubernetes.readyTimeoutMs,
|
|
82
105
|
enforcementExecTimeoutMs: kubernetes.enforcementExecTimeoutMs,
|
|
106
|
+
power: options.power ?? DISABLED_POWER,
|
|
83
107
|
preflight: async () => {
|
|
84
108
|
const { proxyIp } = await runKubernetesPreflight({
|
|
85
109
|
api,
|
|
@@ -112,7 +136,9 @@ export function buildConfiguredExecutor(options) {
|
|
|
112
136
|
}
|
|
113
137
|
const issueTrackers = buildIssueTrackers(env);
|
|
114
138
|
const concurrency = loadCodingConcurrencyConfig(env);
|
|
115
|
-
|
|
139
|
+
const reviewHosts = buildReviewHosts(env, options.db);
|
|
140
|
+
const repoAccess = options.repoAccess ?? createRepoAccessGate({ db: options.db, hosts: reviewHosts });
|
|
141
|
+
// The release and terminal hooks need the composed RoutingExecutor, which only exists
|
|
116
142
|
// after the ContainerExecutor it wraps is built. The closure reads
|
|
117
143
|
// `composed` only when a run finishes, which is after this function returns.
|
|
118
144
|
const coding = new ContainerExecutor({
|
|
@@ -131,12 +157,19 @@ export function buildConfiguredExecutor(options) {
|
|
|
131
157
|
anthropicCredentialRef: config.anthropicCredentialRef,
|
|
132
158
|
limits: { cpus: config.cpus, memoryMb: config.memoryMb, pids: config.pids, diskMb: config.diskMb },
|
|
133
159
|
maxDiskMb: config.maxDiskMb,
|
|
134
|
-
repoAccess
|
|
160
|
+
repoAccess,
|
|
135
161
|
issueUrl: (provider, key) => (provider === "jira" ? issueTrackers.jira?.issueUrl(key) : undefined),
|
|
136
162
|
registryReport: async (runId) => {
|
|
137
163
|
const rows = await options.db.registryFetch.findMany({ where: { runId }, orderBy: { createdAt: "asc" } });
|
|
138
164
|
return summarizeRegistryFetches(rows);
|
|
139
165
|
},
|
|
166
|
+
onCodingRunTerminal: reReviewOnCodingRunTerminal(() => ({
|
|
167
|
+
db: options.db,
|
|
168
|
+
executor: composed,
|
|
169
|
+
hosts: reviewHosts,
|
|
170
|
+
repoAccess,
|
|
171
|
+
issueTrackers,
|
|
172
|
+
})),
|
|
140
173
|
onSlotReleased: () => {
|
|
141
174
|
void drainCodingQueue({
|
|
142
175
|
db: options.db,
|
|
@@ -150,6 +183,6 @@ export function buildConfiguredExecutor(options) {
|
|
|
150
183
|
});
|
|
151
184
|
},
|
|
152
185
|
});
|
|
153
|
-
const composed = new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, coding);
|
|
186
|
+
const composed = new RoutingExecutor(new PrismaExecutionKindResolver(options.db), options.native, coding, options.nativeSandbox);
|
|
154
187
|
return composed;
|
|
155
188
|
}
|
|
@@ -44,6 +44,8 @@ export interface ContainerRunSnapshot {
|
|
|
44
44
|
/** The issue that triggered this run (CodingRun.issueProvider/issueKey); null when none. */
|
|
45
45
|
issueProvider?: string | null;
|
|
46
46
|
issueKey?: string | null;
|
|
47
|
+
/** Step in the delegating agent's declared merge order (CodingRun.mergeOrder); null = no order. */
|
|
48
|
+
mergeOrder?: number | null;
|
|
47
49
|
budgetUsd: number;
|
|
48
50
|
/** The agent's own per-run budget; `budgetUsd` is less when its budget group had less left. */
|
|
49
51
|
agentBudgetUsd?: number;
|
|
@@ -63,6 +65,10 @@ export interface ContainerRunSnapshot {
|
|
|
63
65
|
debugTrace?: boolean;
|
|
64
66
|
/** Claude Code turn limit, fixed at dispatch (CodingRun.maxTurns); null = the worker default. */
|
|
65
67
|
maxTurns?: number | null;
|
|
68
|
+
/** Load the repo's agent skills, fixed at dispatch (CodingRun.repoSkills); absent on older snapshots = true. */
|
|
69
|
+
repoSkills?: boolean;
|
|
70
|
+
/** Claude Code loading mode, fixed at dispatch (CodingRun.claudeBareMode); absent on older snapshots = true. */
|
|
71
|
+
claudeBareMode?: boolean;
|
|
66
72
|
/** Coding-run services resolved at dispatch (CodingRun.services); parsed with parseStoredServices. */
|
|
67
73
|
services?: unknown;
|
|
68
74
|
/** The terminal failure category, once the run has one (CodingRun.failureCategory). */
|
|
@@ -195,6 +201,15 @@ export interface ContainerExecutorOptions {
|
|
|
195
201
|
* than on the next scheduler tick. Never called for a run that was queued.
|
|
196
202
|
*/
|
|
197
203
|
onSlotReleased?: () => void;
|
|
204
|
+
/**
|
|
205
|
+
* Called with the run id at the end of each terminal finish of a collected
|
|
206
|
+
* job (succeeded, no change, budget, or failed), after the terminal write
|
|
207
|
+
* and cleanup. It may run more than once for one run (a replayed or
|
|
208
|
+
* duplicate finish), so it must be idempotent; a rejection or throw is
|
|
209
|
+
* logged and never reaches the terminal path. composition.ts wires the
|
|
210
|
+
* review-fix re-review here, so this executor imports no review logic.
|
|
211
|
+
*/
|
|
212
|
+
onCodingRunTerminal?: (runId: string) => Promise<void> | void;
|
|
198
213
|
/**
|
|
199
214
|
* Loads this run's RegistryFetch ledger (composition.ts wires the Prisma
|
|
200
215
|
* query) so finalizeChanges can surface installed/refused packages in the
|
|
@@ -278,6 +293,8 @@ export declare class ContainerExecutor implements Executor {
|
|
|
278
293
|
private modelTerms;
|
|
279
294
|
private preflight;
|
|
280
295
|
private finishTerminal;
|
|
296
|
+
/** Runs the onCodingRunTerminal hook; nothing it does, throws, or rejects reaches the caller. */
|
|
297
|
+
private notifyTerminal;
|
|
281
298
|
/** The package report is informational: any failure loading it (a
|
|
282
299
|
* rejection, a synchronous throw, or a malformed result) yields no
|
|
283
300
|
* package section rather than failing finalization. */
|
|
@@ -286,7 +303,11 @@ export declare class ContainerExecutor implements Executor {
|
|
|
286
303
|
resolveCodingWorkerImage(selector: CodingImageSelector): string;
|
|
287
304
|
/** Claude's tool-runner image for the agent's toolchain, at dispatch (Executor.resolveCodingToolImage); null for Codex. */
|
|
288
305
|
resolveCodingToolImage(selector: CodingImageSelector): string | null;
|
|
289
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* The tool runner is what runs a Claude agent's commands, so it is what the toolchain selects —
|
|
308
|
+
* unless the agent has a BYO workerImageRef, which replaces the tool runner directly (never the
|
|
309
|
+
* agent image; see resolveCodingWorkerImage).
|
|
310
|
+
*/
|
|
290
311
|
private claudeToolImage;
|
|
291
312
|
/** Coding-run services: the repository's declaration at its base ref (Executor.readCodingServiceDeclaration). */
|
|
292
313
|
readCodingServiceDeclaration(input: {
|
|
@@ -302,6 +323,8 @@ export declare class ContainerExecutor implements Executor {
|
|
|
302
323
|
}): Promise<string | null>;
|
|
303
324
|
/** The job launcher decides (Kubernetes and Docker start services for both providers). */
|
|
304
325
|
supportsCodingServices(provider: CodingProvider): boolean;
|
|
326
|
+
/** Delegates to the job launcher's own warm-up (Executor.warmUp); a no-op for a launcher without one. */
|
|
327
|
+
warmUp(): Promise<void>;
|
|
305
328
|
private requireCurrent;
|
|
306
329
|
/**
|
|
307
330
|
* False when the launcher reports this run's job would not fit the cluster right now; the run
|