@wardby/cli 0.5.2 → 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/local-git.js +9 -1
- 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/registry/pypi.d.ts +25 -1
- package/dist/coding/registry/pypi.js +140 -16
- package/dist/coding/registry/types.d.ts +17 -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 +56 -2
- 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/http-runtime.js +13 -6
- 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 +1492 -113
- 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/ownership.d.ts +1 -1
- 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 +83 -12
- 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/coding-proxy/mock-upstream.d.ts +33 -0
- package/dist/providers/coding-proxy/mock-upstream.js +116 -0
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +3 -0
- package/dist/providers/coding-proxy/registry/prisma-store.js +17 -0
- package/dist/providers/coding-proxy/registry/service.d.ts +4 -0
- package/dist/providers/coding-proxy/registry/service.js +20 -3
- package/dist/providers/coding-proxy/registry/store.d.ts +18 -1
- package/dist/providers/coding-proxy/registry/store.js +33 -0
- package/dist/providers/coding-proxy/runtime.js +12 -1
- package/dist/providers/coding-proxy/types.d.ts +2 -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 +16 -1
- package/dist/providers/jobs/kubernetes-isolation.js +58 -5
- 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 +56 -7
- package/dist/providers/jobs/kubernetes.js +117 -36
- 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/llm/openai.js +0 -1
- 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-db.js +14 -2
- package/dist/quickstart/coding-doctor.d.ts +3 -0
- package/dist/quickstart/coding-doctor.js +3 -0
- package/dist/quickstart/coding-images.d.ts +9 -0
- package/dist/quickstart/coding-images.js +39 -0
- package/dist/quickstart/coding-seed.d.ts +20 -1
- package/dist/quickstart/coding-seed.js +96 -7
- package/dist/quickstart/coding.d.ts +2 -0
- package/dist/quickstart/coding.js +75 -3
- package/dist/quickstart/config.d.ts +2 -0
- package/dist/quickstart/config.js +4 -0
- package/dist/quickstart/images.d.ts +13 -0
- package/dist/quickstart/images.js +80 -12
- package/dist/quickstart/index.d.ts +0 -2
- package/dist/quickstart/index.js +10 -14
- package/dist/quickstart/manifests.d.ts +56 -0
- package/dist/quickstart/manifests.js +523 -0
- package/dist/quickstart/python-detect.d.ts +10 -0
- package/dist/quickstart/python-detect.js +32 -0
- package/dist/quickstart/repo-packages.d.ts +10 -0
- package/dist/quickstart/repo-packages.js +132 -0
- package/dist/quickstart/reviewer-prompt.d.ts +12 -0
- package/dist/quickstart/reviewer-prompt.js +84 -0
- package/dist/quickstart/scenarios.d.ts +19 -0
- package/dist/quickstart/scenarios.js +28 -0
- package/dist/quickstart/sync-reviewer-prompt.d.ts +1 -0
- package/dist/quickstart/sync-reviewer-prompt.js +10 -0
- 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 +214 -18
- 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 +127 -2
- package/docs/coding-packages.md +105 -5
- package/docs/coding-services.md +3 -1
- package/docs/coding-worker-byo-images.md +239 -2
- package/docs/coding-worker-isolation.md +88 -23
- package/docs/getting-started-gke.md +225 -9
- package/docs/getting-started-identity-provider.md +21 -10
- package/docs/getting-started.md +140 -11
- package/docs/jira-agents.md +5 -1
- package/docs/knowledge.md +11 -0
- 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 +136 -0
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +195 -0
- package/help/code-review-agents.md +68 -6
- package/help/coding-packages.md +31 -2
- package/help/creating-agents.md +14 -0
- package/help/deploy-gke.md +37 -6
- package/help/deployment-targets.md +24 -13
- 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 +18 -0
- package/help/github.md +18 -1
- package/help/identity-and-access.md +5 -1
- package/help/local-repositories.md +35 -5
- 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 +13 -5
- 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
package/dist/import/create.js
CHANGED
|
@@ -14,6 +14,16 @@ import { PostgresDatastore } from "../providers/datastore/postgres.js";
|
|
|
14
14
|
import { decryptTransferEnvelope } from "../providers/secrets/transfer-envelope.js";
|
|
15
15
|
import { mapBudget } from "./budgets.js";
|
|
16
16
|
import { EVERYONE_KEY, everyoneGrantData } from "../core/grants.js";
|
|
17
|
+
import { loadNativeSandboxConfig } from "../config/providers.js";
|
|
18
|
+
/** Whether this process has a native sandbox configured; a bad configuration counts as not configured. */
|
|
19
|
+
function nativeSandboxConfigured() {
|
|
20
|
+
try {
|
|
21
|
+
return loadNativeSandboxConfig(process.env) !== undefined;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
17
27
|
export async function createFromBundle(bundle, recon, opts) {
|
|
18
28
|
const { db, cipher, ownerId, secretMode, transferPrivateKey, allowOpenFetch } = opts;
|
|
19
29
|
const agentOwnerId = opts.agentOwnerId === undefined ? ownerId : opts.agentOwnerId;
|
|
@@ -91,9 +101,16 @@ export async function createFromBundle(bundle, recon, opts) {
|
|
|
91
101
|
maxTurns: a.maxTurns,
|
|
92
102
|
scheduleEnabled,
|
|
93
103
|
ownerId: agentOwnerId,
|
|
104
|
+
...(a.nativeExecutionMode
|
|
105
|
+
? { nativeExecutionMode: a.nativeExecutionMode === "sandbox" ? "sandbox" : "control_plane" }
|
|
106
|
+
: {}),
|
|
94
107
|
},
|
|
95
108
|
update: {},
|
|
96
109
|
});
|
|
110
|
+
if (a.nativeExecutionMode === "sandbox" && !nativeSandboxConfigured()) {
|
|
111
|
+
warnings.push(`agent ${a.name}: nativeExecutionMode is "sandbox" but NATIVE_SANDBOX_LAUNCHER is not configured here; ` +
|
|
112
|
+
"its runs fail with native_sandbox_unavailable until the server that runs it has a native sandbox");
|
|
113
|
+
}
|
|
97
114
|
agentIdMap.set(a.name, agent.id);
|
|
98
115
|
if (agentOwnerId !== null && agent.ownerId === agentOwnerId) {
|
|
99
116
|
ownedAgentIds.add(agent.id);
|
|
@@ -93,6 +93,8 @@ export declare const NeutralAgentSchema: z.ZodObject<{
|
|
|
93
93
|
ownerEmail: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
94
94
|
kind: z.ZodDefault<z.ZodEnum<["native"]>>;
|
|
95
95
|
memoryEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
96
|
+
/** Where the agent's runs execute; absent = control-plane. Native agents only (every imported agent is native). */
|
|
97
|
+
nativeExecutionMode: z.ZodOptional<z.ZodEnum<["control-plane", "sandbox"]>>;
|
|
96
98
|
unmodeled: z.ZodDefault<z.ZodObject<{
|
|
97
99
|
description: z.ZodOptional<z.ZodDefault<z.ZodNullable<z.ZodString>>>;
|
|
98
100
|
slug: z.ZodOptional<z.ZodDefault<z.ZodNullable<z.ZodString>>>;
|
|
@@ -125,6 +127,7 @@ export declare const NeutralAgentSchema: z.ZodObject<{
|
|
|
125
127
|
slug?: string | null | undefined;
|
|
126
128
|
emailAllowlist?: unknown;
|
|
127
129
|
};
|
|
130
|
+
nativeExecutionMode?: "sandbox" | "control-plane" | undefined;
|
|
128
131
|
}, {
|
|
129
132
|
name: string;
|
|
130
133
|
model: string;
|
|
@@ -134,6 +137,7 @@ export declare const NeutralAgentSchema: z.ZodObject<{
|
|
|
134
137
|
systemPrompt: string;
|
|
135
138
|
scheduleEnabled: boolean;
|
|
136
139
|
kind?: "native" | undefined;
|
|
140
|
+
nativeExecutionMode?: "sandbox" | "control-plane" | undefined;
|
|
137
141
|
schedule?: string | null | undefined;
|
|
138
142
|
timezone?: string | undefined;
|
|
139
143
|
memoryEnabled?: boolean | undefined;
|
|
@@ -252,12 +256,12 @@ export declare const NeutralAgentSecretSchema: z.ZodObject<{
|
|
|
252
256
|
secretName: z.ZodString;
|
|
253
257
|
alias: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
254
258
|
}, "strip", z.ZodTypeAny, {
|
|
255
|
-
agentName: string;
|
|
256
259
|
secretName: string;
|
|
260
|
+
agentName: string;
|
|
257
261
|
alias: string | null;
|
|
258
262
|
}, {
|
|
259
|
-
agentName: string;
|
|
260
263
|
secretName: string;
|
|
264
|
+
agentName: string;
|
|
261
265
|
alias?: string | null | undefined;
|
|
262
266
|
}>;
|
|
263
267
|
export type NeutralAgentSecret = z.infer<typeof NeutralAgentSecretSchema>;
|
|
@@ -34,6 +34,8 @@ export const NeutralAgentSchema = z.object({
|
|
|
34
34
|
ownerEmail: z.string().nullable().default(null),
|
|
35
35
|
kind: z.enum(["native"]).default("native"),
|
|
36
36
|
memoryEnabled: z.boolean().default(false),
|
|
37
|
+
/** Where the agent's runs execute; absent = control-plane. Native agents only (every imported agent is native). */
|
|
38
|
+
nativeExecutionMode: z.enum(["control-plane", "sandbox"]).optional(),
|
|
37
39
|
unmodeled: z
|
|
38
40
|
.object({
|
|
39
41
|
description: z.string().nullable().default(null),
|
|
@@ -46,6 +46,7 @@ export declare function requireAgentAccess(ctx: McpRequestContext, id: string, r
|
|
|
46
46
|
kind: import("#prisma").AgentKind;
|
|
47
47
|
id: string;
|
|
48
48
|
ownerId: string | null;
|
|
49
|
+
nativeExecutionMode: import("#prisma").NativeExecutionMode;
|
|
49
50
|
systemPrompt: string;
|
|
50
51
|
schedule: string | null;
|
|
51
52
|
timezone: string;
|
|
@@ -72,9 +72,9 @@ export declare function assertStrictlyOwnedTool(tool: Tool | null, id: string, p
|
|
|
72
72
|
* triggered them. No canRead/null=public path exists here on purpose.
|
|
73
73
|
*/
|
|
74
74
|
export declare function requireOwnedTask(db: PrismaClient, taskId: string, principalId: string): Promise<{
|
|
75
|
+
error: import("@prisma/client/runtime/client").JsonValue | null;
|
|
75
76
|
status: import("#prisma").TaskStatus;
|
|
76
77
|
runId: string | null;
|
|
77
|
-
error: import("@prisma/client/runtime/client").JsonValue | null;
|
|
78
78
|
createdAt: Date;
|
|
79
79
|
updatedAt: Date;
|
|
80
80
|
kind: import("#prisma").TaskKind;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* side and the rules; the host call happens here, before any transaction.
|
|
7
7
|
*/
|
|
8
8
|
import { LocalRepoError, isLocalRepository, loadLocalRepoRoots, resolveLocalRepository, } from "../../coding/local-repo.js";
|
|
9
|
+
import { GITHUB_ACCOUNT_NOT_ALLOWED } from "../../config/github-allowed-accounts.js";
|
|
9
10
|
import { requiredLevel } from "../../core/repo-access.js";
|
|
10
11
|
import { McpError } from "../errors.js";
|
|
11
12
|
import { requireScope } from "./resource-server.js";
|
|
@@ -39,6 +40,13 @@ export async function authorizeRepositoryForSet(ctx, input) {
|
|
|
39
40
|
await canonicalLocalRepository(input.repository);
|
|
40
41
|
return stamp("local_root");
|
|
41
42
|
}
|
|
43
|
+
// A server-wide boundary: no admin approval reaches past it.
|
|
44
|
+
const accountDenied = await ctx.providers.repoAccess?.checkAccount?.(input.provider, input.repository);
|
|
45
|
+
if (accountDenied && !accountDenied.ok) {
|
|
46
|
+
if (accountDenied.reason === "github_account_not_allowed")
|
|
47
|
+
throw accountNotAllowed(input.repository);
|
|
48
|
+
throw new McpError(503, `Could not check whether ${input.repository}'s GitHub account is served right now; try again later.`);
|
|
49
|
+
}
|
|
42
50
|
if (input.adminOverride) {
|
|
43
51
|
// Role-gated: the scope alone never suffices (resource-server.ts).
|
|
44
52
|
requireScope(ctx, ctx.canonicalUri, "agents:admin");
|
|
@@ -66,7 +74,13 @@ export async function authorizeRepositoryForSet(ctx, input) {
|
|
|
66
74
|
case "insufficient_permission":
|
|
67
75
|
throw new McpError(403, `Your linked GitHub account has ${decision.level ?? "no"} access to ${input.repository}; ` +
|
|
68
76
|
`this needs ${required}. Ask a repository admin for access, or a wardby admin to approve it (adminOverride).`);
|
|
77
|
+
case "github_account_not_allowed":
|
|
78
|
+
throw accountNotAllowed(input.repository);
|
|
69
79
|
default:
|
|
70
80
|
throw new McpError(503, `Could not verify your GitHub access to ${input.repository} right now (is the GitHub App installed on it?). Try again.`);
|
|
71
81
|
}
|
|
72
82
|
}
|
|
83
|
+
function accountNotAllowed(repository) {
|
|
84
|
+
return new McpError(403, `${GITHUB_ACCOUNT_NOT_ALLOWED}: ${repository} belongs to a GitHub account this server does not serve. ` +
|
|
85
|
+
"An operator can add the account to WARDBY_GITHUB_ALLOWED_ACCOUNTS.");
|
|
86
|
+
}
|
|
@@ -18,7 +18,8 @@ export declare const SCOPES_SUPPORTED: string[];
|
|
|
18
18
|
* services:manage changes the coding-run service catalog, which decides what
|
|
19
19
|
* runs next to every coding run that names an entry; admin:view reads every
|
|
20
20
|
* owner's runs (the admin viewer API); models:admin changes the model catalog,
|
|
21
|
-
* which prices every principal's runs
|
|
21
|
+
* which prices every principal's runs; power:manage scales the shared coding
|
|
22
|
+
* proxy and native gateway to zero (power_sleep) and reads their state.
|
|
22
23
|
* A token scope only DELEGATES — it never authorizes on its own:
|
|
23
24
|
* requireScope/requireAnyScope honour one only when one of the caller's
|
|
24
25
|
* roles (McpRequestContext.roles, resolved live per request) grants it.
|
|
@@ -27,6 +27,9 @@ export const SCOPES_SUPPORTED = [
|
|
|
27
27
|
// Add, override, disable and reset model catalog entries (see docs/models.md).
|
|
28
28
|
// Reading the catalog (list_models, get_model) is agents:read.
|
|
29
29
|
"models:admin",
|
|
30
|
+
// Scale the coding proxy and native gateway to zero now (power_sleep) and
|
|
31
|
+
// read their state (power_status); low-power mode only (docs/getting-started-gke.md).
|
|
32
|
+
"power:manage",
|
|
30
33
|
];
|
|
31
34
|
/**
|
|
32
35
|
* Scopes whose operations reach beyond the caller's own (or public)
|
|
@@ -36,7 +39,8 @@ export const SCOPES_SUPPORTED = [
|
|
|
36
39
|
* services:manage changes the coding-run service catalog, which decides what
|
|
37
40
|
* runs next to every coding run that names an entry; admin:view reads every
|
|
38
41
|
* owner's runs (the admin viewer API); models:admin changes the model catalog,
|
|
39
|
-
* which prices every principal's runs
|
|
42
|
+
* which prices every principal's runs; power:manage scales the shared coding
|
|
43
|
+
* proxy and native gateway to zero (power_sleep) and reads their state.
|
|
40
44
|
* A token scope only DELEGATES — it never authorizes on its own:
|
|
41
45
|
* requireScope/requireAnyScope honour one only when one of the caller's
|
|
42
46
|
* roles (McpRequestContext.roles, resolved live per request) grants it.
|
|
@@ -47,13 +51,14 @@ export const PRIVILEGED_SCOPES = [
|
|
|
47
51
|
"services:manage",
|
|
48
52
|
"admin:view",
|
|
49
53
|
"models:admin",
|
|
54
|
+
"power:manage",
|
|
50
55
|
];
|
|
51
56
|
/**
|
|
52
57
|
* The built-in roles and the permissions (privileged scope names) each
|
|
53
58
|
* grants. No roles = member: every non-privileged scope, nothing privileged.
|
|
54
59
|
*/
|
|
55
60
|
export const ROLE_PERMISSIONS = {
|
|
56
|
-
admin: ["agents:admin", "packages:approve", "services:manage", "admin:view", "models:admin"],
|
|
61
|
+
admin: ["agents:admin", "packages:approve", "services:manage", "admin:view", "models:admin", "power:manage"],
|
|
57
62
|
"package-approver": ["packages:approve"],
|
|
58
63
|
"service-manager": ["services:manage"],
|
|
59
64
|
"model-manager": ["models:admin"],
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import type
|
|
2
|
+
import { type SelfHostedAuthProvider } from "../../../providers/auth/self-hosted.js";
|
|
3
3
|
export declare function browserHandler(provider: SelfHostedAuthProvider): (req: IncomingMessage, res: ServerResponse, url: URL, body: unknown) => Promise<boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID, randomBytes } from "node:crypto";
|
|
2
|
+
import { MobileDisabledError } from "../../../providers/auth/self-hosted.js";
|
|
2
3
|
import { PostgresRateLimiter, RateLimitError } from "./rate-limit.js";
|
|
3
4
|
import { logger } from "../../../core/logger.js";
|
|
4
5
|
import { PAGE_STYLE } from "../../shared/page-style.js";
|
|
@@ -120,12 +121,24 @@ export function browserHandler(provider) {
|
|
|
120
121
|
// here is already a public PKCE client with validated redirect URIs.
|
|
121
122
|
if (p.application_type !== undefined && p.application_type !== "native" && p.application_type !== "web")
|
|
122
123
|
throw new Error("unsupported application_type");
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
let registered;
|
|
125
|
+
try {
|
|
126
|
+
registered = await provider.registerClient({
|
|
127
|
+
redirectUris: p.redirect_uris,
|
|
128
|
+
clientName: p.client_name,
|
|
129
|
+
grantTypes: p.grant_types,
|
|
130
|
+
tokenEndpointAuthMethod: p.token_endpoint_auth_method,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
// The one registration error that names its reason: the operator
|
|
135
|
+
// must turn mobile sign-in on. Everything else stays generic below.
|
|
136
|
+
if (err instanceof MobileDisabledError) {
|
|
137
|
+
json(res, 400, { error: "invalid_redirect_uri", error_description: err.message });
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
129
142
|
json(res, 201, {
|
|
130
143
|
client_id: registered.clientId,
|
|
131
144
|
token_endpoint_auth_method: "none",
|
package/dist/mcp/context.d.ts
CHANGED
|
@@ -13,10 +13,14 @@ import type { ProviderRegistry } from "../providers/index.js";
|
|
|
13
13
|
import type { RepoAccessGate } from "../core/repo-access.js";
|
|
14
14
|
import type { IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
|
|
15
15
|
import type { HostUserAuthorizerRegistry, ReviewHostRegistry } from "../providers/review-host/types.js";
|
|
16
|
+
import type { Power } from "../core/power.js";
|
|
17
|
+
import type { ChatProviderRegistry } from "../providers/chat/types.js";
|
|
16
18
|
export type McpProviders = Pick<ProviderRegistry, "llm" | "engine" | "datastore" | "secrets" | "executor" | "memory"> & {
|
|
17
19
|
reviewHosts?: ReviewHostRegistry;
|
|
18
20
|
/** Issue trackers (Jira); empty or absent = no issue-tracker integration. */
|
|
19
21
|
issueTrackers?: IssueTrackerRegistry;
|
|
22
|
+
/** Chat providers for workflow notifications (Slack); empty or absent = notifications off. */
|
|
23
|
+
chat?: ChatProviderRegistry;
|
|
20
24
|
/** Identity linking (link_host_account); empty or absent = linking disabled. */
|
|
21
25
|
hostUserAuthorizers?: HostUserAuthorizerRegistry;
|
|
22
26
|
/**
|
|
@@ -25,6 +29,8 @@ export type McpProviders = Pick<ProviderRegistry, "llm" | "engine" | "datastore"
|
|
|
25
29
|
* only admin approvals still work.
|
|
26
30
|
*/
|
|
27
31
|
repoAccess?: RepoAccessGate;
|
|
32
|
+
/** Low-power mode (scale idle proxy/gateway to zero); absent = DISABLED_POWER. */
|
|
33
|
+
power?: Power;
|
|
28
34
|
};
|
|
29
35
|
export interface McpRequestContext {
|
|
30
36
|
principal: Principal;
|
|
@@ -19,10 +19,22 @@ export interface GitHubIngressDeps {
|
|
|
19
19
|
/** For a merged/closed PR's linked issue; absent → closed PRs are ignored. */
|
|
20
20
|
issueTrackers?: IssueTrackerRegistry;
|
|
21
21
|
webhookSecret: string | undefined;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The App's id, slug, and owner (the owner is always served). Throwing fails
|
|
24
|
+
* the request closed. `fresh` bypasses any cache; it is used before an
|
|
25
|
+
* uninstall, since the owner can change while the server runs.
|
|
26
|
+
*/
|
|
27
|
+
appIdentity: (opts?: {
|
|
28
|
+
fresh?: boolean;
|
|
29
|
+
}) => Promise<{
|
|
23
30
|
id: number;
|
|
24
31
|
slug: string;
|
|
32
|
+
ownerLogin: string;
|
|
25
33
|
}>;
|
|
34
|
+
/** Accounts served in addition to the App's owner (WARDBY_GITHUB_ALLOWED_ACCOUNTS). */
|
|
35
|
+
allowedAccounts: () => ReadonlySet<string>;
|
|
36
|
+
/** Removes the App from an installation on an account that isn't served; absent = ignore only. */
|
|
37
|
+
uninstallInstallation?: (installationId: number) => Promise<void>;
|
|
26
38
|
now?: () => Date;
|
|
27
39
|
}
|
|
28
40
|
export interface GitHubIngressResult {
|
|
@@ -31,6 +43,16 @@ export interface GitHubIngressResult {
|
|
|
31
43
|
/** Cosmetic follow-ups (reactions) to run after the response is sent. */
|
|
32
44
|
afterResponse?: () => Promise<void>;
|
|
33
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Which GitHub account an event belongs to. Installation events name it on
|
|
48
|
+
* the installation; repository events carry only installation.id, so the
|
|
49
|
+
* repository's owner stands in.
|
|
50
|
+
*/
|
|
51
|
+
export declare function eventAccount(eventName: string, payload: unknown): {
|
|
52
|
+
login: string;
|
|
53
|
+
installationId?: number;
|
|
54
|
+
uninstall: boolean;
|
|
55
|
+
} | undefined;
|
|
34
56
|
export declare function handleGitHubEventIngress(req: {
|
|
35
57
|
headers: Record<string, string | undefined>;
|
|
36
58
|
rawBody: string;
|
|
@@ -9,8 +9,38 @@ import { maybePruneHostEventDeliveries } from "./deliveries.js";
|
|
|
9
9
|
import { routeHostEvent } from "../../core/host-events.js";
|
|
10
10
|
import { logger } from "../../core/logger.js";
|
|
11
11
|
import { normalizeGitHubEvent, verifyGitHubSignature } from "../../providers/review-host/github-events.js";
|
|
12
|
+
import { isGitHubAccountAllowed, trustedAccounts } from "../../config/github-allowed-accounts.js";
|
|
12
13
|
const log = logger.child({ module: "github-ingress" });
|
|
13
14
|
const SAFE_DELIVERY = /^[A-Za-z0-9-]{1,100}$/;
|
|
15
|
+
const INSTALLATION_EVENTS = new Set(["installation", "installation_repositories"]);
|
|
16
|
+
function field(value, key) {
|
|
17
|
+
return value !== null && typeof value === "object" ? value[key] : undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Which GitHub account an event belongs to. Installation events name it on
|
|
21
|
+
* the installation; repository events carry only installation.id, so the
|
|
22
|
+
* repository's owner stands in.
|
|
23
|
+
*/
|
|
24
|
+
export function eventAccount(eventName, payload) {
|
|
25
|
+
if (INSTALLATION_EVENTS.has(eventName)) {
|
|
26
|
+
const installation = field(payload, "installation");
|
|
27
|
+
const login = field(field(installation, "account"), "login");
|
|
28
|
+
const id = field(installation, "id");
|
|
29
|
+
if (typeof login !== "string" || login === "")
|
|
30
|
+
return undefined;
|
|
31
|
+
return {
|
|
32
|
+
login,
|
|
33
|
+
...(typeof id === "number" && Number.isSafeInteger(id) && id > 0 ? { installationId: id } : {}),
|
|
34
|
+
uninstall: field(payload, "action") !== "deleted",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const repository = field(payload, "repository");
|
|
38
|
+
const fullName = field(repository, "full_name");
|
|
39
|
+
const owner = typeof fullName === "string" && fullName.includes("/")
|
|
40
|
+
? fullName.split("/", 1)[0]
|
|
41
|
+
: field(field(repository, "owner"), "login");
|
|
42
|
+
return typeof owner === "string" && owner !== "" ? { login: owner, uninstall: false } : undefined;
|
|
43
|
+
}
|
|
14
44
|
export async function handleGitHubEventIngress(req, deps) {
|
|
15
45
|
if (!deps.webhookSecret)
|
|
16
46
|
return { status: 404, body: { error: "not_found" } };
|
|
@@ -31,6 +61,44 @@ export async function handleGitHubEventIngress(req, deps) {
|
|
|
31
61
|
return { status: 400, body: { error: "invalid_json" } };
|
|
32
62
|
}
|
|
33
63
|
const app = await deps.appIdentity();
|
|
64
|
+
const account = eventAccount(eventName, payload);
|
|
65
|
+
if (account && !isGitHubAccountAllowed(trustedAccounts(app.ownerLogin, deps.allowedAccounts()), account.login)) {
|
|
66
|
+
// Never the body: only the account and what we do about it.
|
|
67
|
+
log.warn({ event: eventName, account: account.login, installationId: account.installationId, deliveryId }, "GitHub event from an account this server does not serve ignored");
|
|
68
|
+
const uninstall = deps.uninstallInstallation;
|
|
69
|
+
const installationId = account.installationId;
|
|
70
|
+
return {
|
|
71
|
+
status: 202,
|
|
72
|
+
body: { ignored: "account_not_allowed" },
|
|
73
|
+
...(account.uninstall && uninstall && installationId !== undefined
|
|
74
|
+
? {
|
|
75
|
+
afterResponse: async () => {
|
|
76
|
+
// Destructive, so re-check against a fresh owner read: the cached
|
|
77
|
+
// owner may be stale after an ownership transfer or rename.
|
|
78
|
+
let fresh;
|
|
79
|
+
try {
|
|
80
|
+
fresh = await deps.appIdentity({ fresh: true });
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
log.warn({ err, account: account.login, installationId }, "could not re-read the App owner; not removing the App from the installation");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (isGitHubAccountAllowed(trustedAccounts(fresh.ownerLogin, deps.allowedAccounts()), account.login)) {
|
|
87
|
+
log.info({ account: account.login, installationId }, "account is served after re-reading the App owner; not removing the App from the installation");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
await uninstall(installationId);
|
|
92
|
+
log.warn({ account: account.login, installationId }, "removed the App from an installation on an account this server does not serve");
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
log.warn({ err, account: account.login, installationId }, "could not remove the App from a foreign installation");
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
: {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
34
102
|
const event = normalizeGitHubEvent(eventName, payload, app);
|
|
35
103
|
// An event we don't act on must never claim the delivery id: recording it
|
|
36
104
|
// here would let a later, real delivery of the same id (GitHub does reuse
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -37,5 +37,18 @@ export interface StartMcpOptions {
|
|
|
37
37
|
*/
|
|
38
38
|
schedulerAttached?: boolean;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Fire-and-forget: starts the executor's start-up warm-up (e.g. KubernetesJobLauncher's memoized
|
|
42
|
+
* cluster preflight, via RoutingExecutor -> ContainerExecutor -> the job launcher's own `warmUp`)
|
|
43
|
+
* right when a long-running server process starts, so its first coding run doesn't pay for it.
|
|
44
|
+
* Never awaited by its caller and never throws: `warmUp()` on every implementation already swallows
|
|
45
|
+
* its own failure (logging it instead), but this still guards the call site against a surprise
|
|
46
|
+
* rejection, since nothing here may block or fail server start-up. Called from `startMcp` below —
|
|
47
|
+
* i.e. from `wardby mcp` (stdio and HTTP) and from `wardby serve`, which shares this same start-up
|
|
48
|
+
* path — and, separately, from `cli.ts`'s `scheduler()` (`wardby scheduler`), which dispatches
|
|
49
|
+
* scheduled coding runs through its own Kubernetes executor but never starts an MCP server. Never
|
|
50
|
+
* called from a one-shot CLI command (`wardby run`, `coding preflight`, migrations, imports).
|
|
51
|
+
*/
|
|
52
|
+
export declare function warmUpExecutor(executor: Pick<McpProviders["executor"], "warmUp">): void;
|
|
40
53
|
/** The real CLI entry point: `wardby mcp`. Reads config from the environment, starts stdio or HTTP per MCP_TRANSPORT. */
|
|
41
54
|
export declare function startMcp(options?: StartMcpOptions): Promise<McpServerHandle>;
|
package/dist/mcp/index.js
CHANGED
|
@@ -22,14 +22,18 @@ import { startModelCatalog } from "../providers/llm/catalog-store.js";
|
|
|
22
22
|
import { PostgresDatastore } from "../providers/datastore/index.js";
|
|
23
23
|
import { PostgresAgentMemory } from "../providers/memory/index.js";
|
|
24
24
|
import { buildConfiguredExecutor, buildExecutor } from "../providers/executor/index.js";
|
|
25
|
+
import { buildNativeSandboxExecutor } from "../native-worker/composition.js";
|
|
25
26
|
import { buildSecretCipher } from "../providers/secrets/index.js";
|
|
26
27
|
import { buildIssueTrackers } from "../providers/issue-tracker/index.js";
|
|
27
28
|
import { buildHostUserAuthorizers, buildReviewHosts } from "../providers/review-host/index.js";
|
|
29
|
+
import { buildChatProviders } from "../providers/chat/index.js";
|
|
28
30
|
import { createRepoAccessGate } from "../core/repo-access.js";
|
|
29
31
|
import { userCallbackPath } from "../core/host-identity-links.js";
|
|
30
32
|
import { buildAuthProvider } from "../providers/auth/index.js";
|
|
31
33
|
import { GitHubAppClient } from "../providers/vcs/github.js";
|
|
34
|
+
import { loadGitHubAllowedAccounts } from "../config/github-allowed-accounts.js";
|
|
32
35
|
import { buildMcpServer } from "./server.js";
|
|
36
|
+
import { buildPower } from "../core/power-composition.js";
|
|
33
37
|
import { countUnattendedSchedules, unattendedSchedulesWarning } from "./unattended-schedules.js";
|
|
34
38
|
import { runStdioServer } from "./transport/stdio.js";
|
|
35
39
|
import { startHttpServer } from "./transport/streamable-http.js";
|
|
@@ -43,6 +47,7 @@ import { registerAgentTools } from "./tools/agents.js";
|
|
|
43
47
|
import { registerServiceTools } from "./tools/services.js";
|
|
44
48
|
import { registerBudgetGroupTools } from "./tools/budget-groups.js";
|
|
45
49
|
import { registerModelCatalogTools } from "./tools/model-catalog.js";
|
|
50
|
+
import { registerPowerTools } from "./tools/power.js";
|
|
46
51
|
import { registerHelpTools } from "./tools/help.js";
|
|
47
52
|
import { registerTriggerTool } from "./tools/trigger.js";
|
|
48
53
|
import { registerToolAuthoringTools } from "./tools/tools.js";
|
|
@@ -54,12 +59,14 @@ import { registerSubAgentTools } from "./tools/subagents.js";
|
|
|
54
59
|
import { registerGrantTools } from "./tools/grants.js";
|
|
55
60
|
import { registerRepositoryTools } from "./tools/repositories.js";
|
|
56
61
|
import { registerIssueProjectTools } from "./tools/issue-projects.js";
|
|
62
|
+
import { registerNotificationChannelTools } from "./tools/notification-channels.js";
|
|
57
63
|
import { registerHostAccountTools } from "./tools/host-accounts.js";
|
|
58
64
|
import { registerMemoryTools } from "./tools/memory.js";
|
|
59
65
|
import { registerSecretsTools } from "./tools/secrets.js";
|
|
60
66
|
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
61
67
|
import { createStdioSecretElicitationHost } from "./tools/secret-elicitation-server.js";
|
|
62
68
|
import { SECRET_ELICITATION_PATH } from "./tools/secret-elicitation-form.js";
|
|
69
|
+
import { installWorkflowEventRecorder } from "../core/notifications.js";
|
|
63
70
|
import { logger } from "../core/logger.js";
|
|
64
71
|
const mcpLog = logger.child({ module: "mcp-index" });
|
|
65
72
|
const SELF_HOSTED_CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // hourly
|
|
@@ -105,6 +112,7 @@ export function registerAllTools(mcp, opts) {
|
|
|
105
112
|
registerServiceTools(mcp);
|
|
106
113
|
registerBudgetGroupTools(mcp);
|
|
107
114
|
registerModelCatalogTools(mcp, { refresh: opts.refreshModelCatalog });
|
|
115
|
+
registerPowerTools(mcp);
|
|
108
116
|
registerHelpTools(mcp);
|
|
109
117
|
registerTriggerTool(mcp);
|
|
110
118
|
registerToolAuthoringTools(mcp);
|
|
@@ -116,6 +124,7 @@ export function registerAllTools(mcp, opts) {
|
|
|
116
124
|
registerGrantTools(mcp);
|
|
117
125
|
registerRepositoryTools(mcp);
|
|
118
126
|
registerIssueProjectTools(mcp);
|
|
127
|
+
registerNotificationChannelTools(mcp);
|
|
119
128
|
registerHostAccountTools(mcp);
|
|
120
129
|
registerMemoryTools(mcp);
|
|
121
130
|
registerSecretsTools(mcp, {
|
|
@@ -139,6 +148,11 @@ export function buildMcpProviders() {
|
|
|
139
148
|
const reviewHosts = buildReviewHosts(process.env, prisma);
|
|
140
149
|
const issueTrackers = buildIssueTrackers();
|
|
141
150
|
const hostUserAuthorizers = buildHostUserAuthorizers();
|
|
151
|
+
// Installed here (not just serve/scheduler) so `wardby mcp`, which handles
|
|
152
|
+
// webhooks, records events too; only serve and the scheduler command start
|
|
153
|
+
// the dispatcher.
|
|
154
|
+
const chat = buildChatProviders();
|
|
155
|
+
installWorkflowEventRecorder(prisma, chat);
|
|
142
156
|
// One gate (and one cache) for the whole process: set-time checks in the
|
|
143
157
|
// MCP tools, repo_* calls in native runs, coding runs, and host events.
|
|
144
158
|
const repoAccess = createRepoAccessGate({ db: prisma, hosts: reviewHosts });
|
|
@@ -161,7 +175,17 @@ export function buildMcpProviders() {
|
|
|
161
175
|
repoAccess,
|
|
162
176
|
};
|
|
163
177
|
const nativeExecutor = buildExecutor(providerConfig, nativeProviders, prisma);
|
|
164
|
-
|
|
178
|
+
// One Power for the process, shared by both executors (wake) and the scheduler leader (sleep).
|
|
179
|
+
const power = buildPower({ env: process.env, db: prisma });
|
|
180
|
+
const executor = buildConfiguredExecutor({
|
|
181
|
+
native: nativeExecutor,
|
|
182
|
+
db: prisma,
|
|
183
|
+
providerConfig,
|
|
184
|
+
repoAccess,
|
|
185
|
+
power,
|
|
186
|
+
// Sandbox-mode native runs (docs/native-sandbox.md); undefined when NATIVE_SANDBOX_LAUNCHER is unset.
|
|
187
|
+
nativeSandbox: buildNativeSandboxExecutor({ db: prisma, providers: nativeProviders, power }),
|
|
188
|
+
});
|
|
165
189
|
nativeProviders.executor = executor;
|
|
166
190
|
return {
|
|
167
191
|
providers: {
|
|
@@ -175,6 +199,8 @@ export function buildMcpProviders() {
|
|
|
175
199
|
issueTrackers,
|
|
176
200
|
hostUserAuthorizers,
|
|
177
201
|
repoAccess,
|
|
202
|
+
chat,
|
|
203
|
+
power,
|
|
178
204
|
},
|
|
179
205
|
};
|
|
180
206
|
}
|
|
@@ -187,11 +213,31 @@ async function closeQuietly(promise, what) {
|
|
|
187
213
|
mcpLog.warn({ err }, `${what} failed during MCP shutdown`);
|
|
188
214
|
}
|
|
189
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Fire-and-forget: starts the executor's start-up warm-up (e.g. KubernetesJobLauncher's memoized
|
|
218
|
+
* cluster preflight, via RoutingExecutor -> ContainerExecutor -> the job launcher's own `warmUp`)
|
|
219
|
+
* right when a long-running server process starts, so its first coding run doesn't pay for it.
|
|
220
|
+
* Never awaited by its caller and never throws: `warmUp()` on every implementation already swallows
|
|
221
|
+
* its own failure (logging it instead), but this still guards the call site against a surprise
|
|
222
|
+
* rejection, since nothing here may block or fail server start-up. Called from `startMcp` below —
|
|
223
|
+
* i.e. from `wardby mcp` (stdio and HTTP) and from `wardby serve`, which shares this same start-up
|
|
224
|
+
* path — and, separately, from `cli.ts`'s `scheduler()` (`wardby scheduler`), which dispatches
|
|
225
|
+
* scheduled coding runs through its own Kubernetes executor but never starts an MCP server. Never
|
|
226
|
+
* called from a one-shot CLI command (`wardby run`, `coding preflight`, migrations, imports).
|
|
227
|
+
*/
|
|
228
|
+
export function warmUpExecutor(executor) {
|
|
229
|
+
void executor.warmUp?.()?.catch((err) => {
|
|
230
|
+
mcpLog.warn({ err }, "executor warm-up failed unexpectedly");
|
|
231
|
+
});
|
|
232
|
+
}
|
|
190
233
|
/** The real CLI entry point: `wardby mcp`. Reads config from the environment, starts stdio or HTTP per MCP_TRANSPORT. */
|
|
191
234
|
export async function startMcp(options = {}) {
|
|
192
235
|
const mcpConfig = loadMcpConfig();
|
|
193
236
|
// Parsed up front so a malformed value fails at startup, not at shutdown.
|
|
194
237
|
const drainSeconds = loadShutdownDrainSeconds();
|
|
238
|
+
// Parsed now so a malformed list stops startup instead of failing every event.
|
|
239
|
+
const allowedAccounts = loadGitHubAllowedAccounts();
|
|
240
|
+
mcpLog.info({ additionalAccounts: [...allowedAccounts] }, "GitHub App serves its owner plus WARDBY_GITHUB_ALLOWED_ACCOUNTS");
|
|
195
241
|
// Loads the model catalog before anything else: running on the shipped
|
|
196
242
|
// catalog alone (the fallback currentModelCatalog() uses before a store
|
|
197
243
|
// is installed) would quietly re-enable models an admin turned off.
|
|
@@ -202,6 +248,7 @@ export async function startMcp(options = {}) {
|
|
|
202
248
|
const modelCatalog = await startModelCatalog(prisma);
|
|
203
249
|
const providers = options.providers ?? buildMcpProviders().providers;
|
|
204
250
|
await providers.executor.launch?.();
|
|
251
|
+
warmUpExecutor(providers.executor);
|
|
205
252
|
if (!options.schedulerAttached)
|
|
206
253
|
await warnIfNothingWillFireSchedules();
|
|
207
254
|
if (mcpConfig.transport === "stdio") {
|
|
@@ -254,7 +301,14 @@ export async function startMcp(options = {}) {
|
|
|
254
301
|
const eventConfig = loadGitHubEventConfig();
|
|
255
302
|
const githubConfig = loadGitHubVcsConfig();
|
|
256
303
|
const reviewHosts = providers.reviewHosts;
|
|
257
|
-
const
|
|
304
|
+
const githubApp = githubConfig.appId && githubConfig.privateKey
|
|
305
|
+
? new GitHubAppClient({
|
|
306
|
+
appId: githubConfig.appId,
|
|
307
|
+
privateKey: githubConfig.privateKey,
|
|
308
|
+
apiVersion: githubConfig.apiVersion,
|
|
309
|
+
})
|
|
310
|
+
: undefined;
|
|
311
|
+
const githubEvents = eventConfig.webhookSecret && reviewHosts?.github && githubApp
|
|
258
312
|
? {
|
|
259
313
|
github: {
|
|
260
314
|
db: prisma,
|
|
@@ -263,14 +317,9 @@ export async function startMcp(options = {}) {
|
|
|
263
317
|
repoAccess: providers.repoAccess ?? createRepoAccessGate({ db: prisma, hosts: reviewHosts }),
|
|
264
318
|
...(providers.issueTrackers ? { issueTrackers: providers.issueTrackers } : {}),
|
|
265
319
|
webhookSecret: eventConfig.webhookSecret,
|
|
266
|
-
appIdentity: (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
privateKey: githubConfig.privateKey,
|
|
270
|
-
apiVersion: githubConfig.apiVersion,
|
|
271
|
-
});
|
|
272
|
-
return () => client.appIdentity();
|
|
273
|
-
})(),
|
|
320
|
+
appIdentity: (opts) => githubApp.appIdentity(opts),
|
|
321
|
+
allowedAccounts: () => allowedAccounts,
|
|
322
|
+
uninstallInstallation: (id) => githubApp.deleteInstallation(id),
|
|
274
323
|
},
|
|
275
324
|
}
|
|
276
325
|
: undefined;
|