@wardby/cli 0.2.1 → 0.4.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 +53 -4
- package/README.md +52 -13
- package/dist/claude-coding-worker/driver.d.ts +6 -1
- package/dist/claude-coding-worker/driver.js +27 -1
- package/dist/claude-coding-worker/main.js +2 -0
- package/dist/claude-coding-worker/tool-socket.d.ts +9 -0
- package/dist/claude-coding-worker/tool-socket.js +26 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +14 -4
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +284 -36
- package/dist/coding/base-commit.d.ts +6 -0
- package/dist/coding/base-commit.js +12 -0
- package/dist/coding/collect-exclude.d.ts +25 -0
- package/dist/coding/collect-exclude.js +76 -0
- package/dist/coding/profile.d.ts +67 -22
- package/dist/coding/profile.js +58 -25
- package/dist/coding/protected-path-wording.d.ts +24 -0
- package/dist/coding/protected-path-wording.js +55 -0
- package/dist/coding/protected-paths.d.ts +31 -0
- package/dist/coding/protected-paths.js +48 -0
- package/dist/coding/protocol.d.ts +91 -4
- package/dist/coding/protocol.js +123 -12
- package/dist/coding/provider.d.ts +6 -1
- package/dist/coding/provider.js +16 -9
- package/dist/coding/registry/adapters.d.ts +2 -0
- package/dist/coding/registry/adapters.js +9 -0
- package/dist/coding/registry/allowlist.d.ts +9 -0
- package/dist/coding/registry/allowlist.js +28 -0
- package/dist/coding/registry/json-scan.d.ts +55 -0
- package/dist/coding/registry/json-scan.js +191 -0
- package/dist/coding/registry/lockfiles.d.ts +6 -0
- package/dist/coding/registry/lockfiles.js +89 -0
- package/dist/coding/registry/npm-lockfile.d.ts +9 -0
- package/dist/coding/registry/npm-lockfile.js +73 -0
- package/dist/coding/registry/npm-plan.d.ts +29 -0
- package/dist/coding/registry/npm-plan.js +289 -0
- package/dist/coding/registry/npm.d.ts +7 -0
- package/dist/coding/registry/npm.js +252 -0
- package/dist/coding/registry/pypi.d.ts +4 -0
- package/dist/coding/registry/pypi.js +210 -0
- package/dist/coding/registry/report.d.ts +37 -0
- package/dist/coding/registry/report.js +31 -0
- package/dist/coding/registry/token.d.ts +4 -0
- package/dist/coding/registry/token.js +7 -0
- package/dist/coding/registry/types.d.ts +286 -0
- package/dist/coding/registry/types.js +19 -0
- package/dist/coding/registry/worker-config.d.ts +14 -0
- package/dist/coding/registry/worker-config.js +31 -0
- package/dist/coding/services/builtins.d.ts +22 -0
- package/dist/coding/services/builtins.js +85 -0
- package/dist/coding/services/catalog.d.ts +443 -0
- package/dist/coding/services/catalog.js +159 -0
- package/dist/coding/services/declaration.d.ts +11 -0
- package/dist/coding/services/declaration.js +114 -0
- package/dist/coding/services/note.d.ts +8 -0
- package/dist/coding/services/note.js +15 -0
- package/dist/coding/services/resolve.d.ts +25 -0
- package/dist/coding/services/resolve.js +50 -0
- package/dist/coding/services/wording.d.ts +25 -0
- package/dist/coding/services/wording.js +70 -0
- package/dist/coding-proxy/main.js +24 -4
- package/dist/coding-worker/artifact.d.ts +6 -0
- package/dist/coding-worker/debug-trace.d.ts +37 -0
- package/dist/coding-worker/debug-trace.js +117 -0
- package/dist/coding-worker/driver.d.ts +13 -1
- package/dist/coding-worker/driver.js +102 -13
- package/dist/coding-worker/errors.js +8 -0
- package/dist/coding-worker/main.js +10 -2
- package/dist/coding-worker/sdk.d.ts +2 -2
- package/dist/coding-worker/sdk.js +7 -2
- package/dist/coding-worker/types.d.ts +3 -0
- package/dist/config/providers.d.ts +66 -0
- package/dist/config/providers.js +137 -0
- package/dist/core/attribution.d.ts +101 -0
- package/dist/core/attribution.js +208 -0
- package/dist/core/budget-groups.d.ts +120 -10
- package/dist/core/budget-groups.js +133 -24
- package/dist/core/budget-wording.d.ts +22 -0
- package/dist/core/budget-wording.js +55 -0
- package/dist/core/coding-queue.d.ts +3 -0
- package/dist/core/coding-queue.js +6 -2
- package/dist/core/coding-service-status.d.ts +11 -0
- package/dist/core/coding-service-status.js +17 -0
- package/dist/core/cost-report.d.ts +88 -0
- package/dist/core/cost-report.js +248 -0
- package/dist/core/datastores.js +18 -2
- package/dist/core/db.d.ts +5 -1
- package/dist/core/db.js +8 -2
- package/dist/core/dispatch.d.ts +74 -7
- package/dist/core/dispatch.js +382 -47
- package/dist/core/engine-native.js +44 -14
- package/dist/core/glob.d.ts +10 -0
- package/dist/core/glob.js +33 -0
- package/dist/core/grants.d.ts +86 -0
- package/dist/core/grants.js +126 -0
- package/dist/core/host-events.d.ts +72 -0
- package/dist/core/host-events.js +597 -0
- package/dist/core/host-identity-links.d.ts +54 -0
- package/dist/core/host-identity-links.js +189 -0
- package/dist/core/host-status.d.ts +78 -0
- package/dist/core/host-status.js +228 -0
- package/dist/core/in-flight-runs.d.ts +8 -0
- package/dist/core/in-flight-runs.js +56 -0
- package/dist/core/issue-bridge.d.ts +60 -0
- package/dist/core/issue-bridge.js +189 -0
- package/dist/core/issue-dedupe.d.ts +70 -0
- package/dist/core/issue-dedupe.js +255 -0
- package/dist/core/issue-events.d.ts +42 -0
- package/dist/core/issue-events.js +155 -0
- package/dist/core/issue-status.d.ts +29 -0
- package/dist/core/issue-status.js +241 -0
- package/dist/core/issue-tracker-tools.d.ts +64 -0
- package/dist/core/issue-tracker-tools.js +850 -0
- package/dist/core/model-usage.d.ts +10 -0
- package/dist/core/model-usage.js +24 -0
- package/dist/core/provider-wording.d.ts +12 -0
- package/dist/core/provider-wording.js +44 -0
- package/dist/core/reconciler.d.ts +42 -2
- package/dist/core/reconciler.js +97 -2
- package/dist/core/repo-access.d.ts +99 -0
- package/dist/core/repo-access.js +136 -0
- package/dist/core/review-host-checks.d.ts +11 -0
- package/dist/core/review-host-checks.js +41 -0
- package/dist/core/review-host-tools.d.ts +47 -0
- package/dist/core/review-host-tools.js +354 -0
- package/dist/core/run-heartbeat.d.ts +27 -0
- package/dist/core/run-heartbeat.js +54 -0
- package/dist/core/run-pricing.d.ts +61 -0
- package/dist/core/run-pricing.js +56 -0
- package/dist/core/runner.d.ts +33 -8
- package/dist/core/runner.js +410 -62
- package/dist/core/scheduler.d.ts +4 -1
- package/dist/core/scheduler.js +3 -2
- package/dist/core/secrets.d.ts +11 -2
- package/dist/core/secrets.js +25 -6
- package/dist/core/self-defects.d.ts +80 -0
- package/dist/core/self-defects.js +180 -0
- package/dist/core/subagent-memory-tools.d.ts +1 -1
- package/dist/core/subagent-memory-tools.js +16 -3
- package/dist/core/tool-admin.d.ts +81 -0
- package/dist/core/tool-admin.js +129 -0
- package/dist/core/tool-names.d.ts +42 -0
- package/dist/core/tool-names.js +67 -0
- package/dist/core/untrusted-content.d.ts +32 -0
- package/dist/core/untrusted-content.js +72 -0
- package/dist/core/webhooks.d.ts +17 -2
- package/dist/core/webhooks.js +42 -3
- package/dist/generated/prisma/browser.d.ts +166 -0
- package/dist/generated/prisma/client.d.ts +166 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +152 -52
- package/dist/generated/prisma/enums.d.ts +13 -0
- package/dist/generated/prisma/enums.js +12 -1
- package/dist/generated/prisma/internal/class.d.ts +242 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +2571 -577
- package/dist/generated/prisma/internal/prismaNamespace.js +312 -6
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +328 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +312 -6
- package/dist/generated/prisma/models/Agent.d.ts +682 -1
- package/dist/generated/prisma/models/AgentIssueProject.d.ts +1838 -0
- package/dist/generated/prisma/models/AgentIssueProject.js +1 -0
- package/dist/generated/prisma/models/AgentRepository.d.ts +1425 -0
- package/dist/generated/prisma/models/AgentRepository.js +1 -0
- package/dist/generated/prisma/models/AgentTool.d.ts +95 -1
- package/dist/generated/prisma/models/AuthUser.d.ts +56 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +258 -7
- package/dist/generated/prisma/models/CodingProxySession.d.ts +195 -2
- package/dist/generated/prisma/models/CodingRun.d.ts +1405 -95
- package/dist/generated/prisma/models/CodingRunServiceStatus.d.ts +1404 -0
- package/dist/generated/prisma/models/CodingRunServiceStatus.js +1 -0
- package/dist/generated/prisma/models/CodingService.d.ts +1348 -0
- package/dist/generated/prisma/models/CodingService.js +1 -0
- package/dist/generated/prisma/models/HostEventDelivery.d.ts +946 -0
- package/dist/generated/prisma/models/HostEventDelivery.js +1 -0
- package/dist/generated/prisma/models/HostIdentity.d.ts +1232 -0
- package/dist/generated/prisma/models/HostIdentity.js +1 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.d.ts +1473 -0
- package/dist/generated/prisma/models/HostIdentityLinkRequest.js +1 -0
- package/dist/generated/prisma/models/IssueFingerprint.d.ts +1183 -0
- package/dist/generated/prisma/models/IssueFingerprint.js +1 -0
- package/dist/generated/prisma/models/IssuePullRequest.d.ts +1255 -0
- package/dist/generated/prisma/models/IssuePullRequest.js +1 -0
- package/dist/generated/prisma/models/ModelCatalogEntry.d.ts +1322 -0
- package/dist/generated/prisma/models/ModelCatalogEntry.js +1 -0
- package/dist/generated/prisma/models/Principal.d.ts +455 -0
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +1148 -0
- package/dist/generated/prisma/models/RegistryAllowance.js +1 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +1219 -0
- package/dist/generated/prisma/models/RegistryApprovedVersion.js +1 -0
- package/dist/generated/prisma/models/RegistryFetch.d.ts +1428 -0
- package/dist/generated/prisma/models/RegistryFetch.js +1 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.d.ts +1294 -0
- package/dist/generated/prisma/models/RegistryPlanRefusal.js +1 -0
- package/dist/generated/prisma/models/RegistryVersionFact.d.ts +1085 -0
- package/dist/generated/prisma/models/RegistryVersionFact.js +1 -0
- package/dist/generated/prisma/models/ResourceGrant.d.ts +1437 -0
- package/dist/generated/prisma/models/ResourceGrant.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +1402 -82
- package/dist/generated/prisma/models/RunAttribution.d.ts +1259 -0
- package/dist/generated/prisma/models/RunAttribution.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +1239 -0
- package/dist/generated/prisma/models/RunHostCheck.js +1 -0
- package/dist/generated/prisma/models/RunHostStatus.d.ts +1315 -0
- package/dist/generated/prisma/models/RunHostStatus.js +1 -0
- package/dist/generated/prisma/models/RunIssueStatus.d.ts +1199 -0
- package/dist/generated/prisma/models/RunIssueStatus.js +1 -0
- package/dist/generated/prisma/models/RunModelUsage.d.ts +1316 -0
- package/dist/generated/prisma/models/RunModelUsage.js +1 -0
- package/dist/generated/prisma/models/Tool.d.ts +15 -3
- package/dist/generated/prisma/models/WorkItem.d.ts +1408 -0
- package/dist/generated/prisma/models/WorkItem.js +1 -0
- package/dist/generated/prisma/models.d.ts +22 -0
- package/dist/help/build.d.ts +1 -0
- package/dist/help/build.js +9 -0
- package/dist/help/catalog.d.ts +24 -0
- package/dist/help/catalog.js +160 -0
- package/dist/help/cli.d.ts +2 -0
- package/dist/help/cli.js +65 -0
- package/dist/help/runtime.d.ts +3 -0
- package/dist/help/runtime.js +44 -0
- package/dist/help/search.d.ts +9 -0
- package/dist/help/search.js +104 -0
- package/dist/help-index.json +999 -0
- package/dist/import/cli-args.js +3 -2
- package/dist/import/create.d.ts +5 -0
- package/dist/import/create.js +67 -13
- package/dist/import/index.js +19 -9
- package/dist/import/neutral-schema.d.ts +18 -18
- package/dist/knowledge/check.d.ts +13 -0
- package/dist/knowledge/check.js +69 -0
- package/dist/knowledge/cli.d.ts +14 -0
- package/dist/knowledge/cli.js +67 -0
- package/dist/knowledge/concept.d.ts +54 -0
- package/dist/knowledge/concept.js +78 -0
- package/dist/knowledge/note.d.ts +11 -0
- package/dist/knowledge/note.js +39 -0
- package/dist/knowledge/relevance.d.ts +11 -0
- package/dist/knowledge/relevance.js +14 -0
- package/dist/knowledge/span-hash.d.ts +3 -0
- package/dist/knowledge/span-hash.js +16 -0
- package/dist/mcp/auth/access.d.ts +72 -0
- package/dist/mcp/auth/access.js +58 -0
- package/dist/mcp/auth/grants-cli.d.ts +149 -0
- package/dist/mcp/auth/grants-cli.js +518 -0
- package/dist/mcp/auth/host-account-cli.d.ts +2 -0
- package/dist/mcp/auth/host-account-cli.js +47 -0
- package/dist/mcp/auth/ownership.d.ts +25 -51
- package/dist/mcp/auth/ownership.js +19 -14
- package/dist/mcp/auth/repo-authorization.d.ts +22 -0
- package/dist/mcp/auth/repo-authorization.js +51 -0
- package/dist/mcp/auth/resource-server.d.ts +33 -2
- package/dist/mcp/auth/resource-server.js +99 -3
- package/dist/mcp/auth/self-hosted/browser.js +2 -2
- package/dist/mcp/auth/self-hosted/cli.js +47 -13
- package/dist/mcp/auth/self-hosted/credentials.d.ts +23 -5
- package/dist/mcp/auth/self-hosted/credentials.js +62 -4
- package/dist/mcp/auth/self-hosted/session.d.ts +7 -6
- package/dist/mcp/context.d.ts +30 -1
- package/dist/mcp/errors.d.ts +25 -6
- package/dist/mcp/errors.js +98 -0
- package/dist/mcp/host-events/deliveries.d.ts +9 -0
- package/dist/mcp/host-events/deliveries.js +17 -0
- package/dist/mcp/host-events/github-ingress.d.ts +38 -0
- package/dist/mcp/host-events/github-ingress.js +83 -0
- package/dist/mcp/host-events/github-user-callback.d.ts +18 -0
- package/dist/mcp/host-events/github-user-callback.js +50 -0
- package/dist/mcp/host-events/jira-ingress.d.ts +29 -0
- package/dist/mcp/host-events/jira-ingress.js +92 -0
- package/dist/mcp/index.d.ts +10 -1
- package/dist/mcp/index.js +187 -19
- package/dist/mcp/server.js +32 -11
- package/dist/mcp/tools/agents.js +519 -50
- package/dist/mcp/tools/budget-groups.js +3 -3
- package/dist/mcp/tools/cost-report.d.ts +8 -0
- package/dist/mcp/tools/cost-report.js +60 -0
- package/dist/mcp/tools/datastore.js +22 -15
- package/dist/mcp/tools/grants.d.ts +2 -0
- package/dist/mcp/tools/grants.js +239 -0
- package/dist/mcp/tools/help.d.ts +5 -0
- package/dist/mcp/tools/help.js +67 -0
- package/dist/mcp/tools/host-accounts.d.ts +2 -0
- package/dist/mcp/tools/host-accounts.js +114 -0
- package/dist/mcp/tools/issue-projects.d.ts +2 -0
- package/dist/mcp/tools/issue-projects.js +238 -0
- package/dist/mcp/tools/memory.d.ts +7 -1
- package/dist/mcp/tools/memory.js +5 -5
- package/dist/mcp/tools/model-catalog.d.ts +22 -0
- package/dist/mcp/tools/model-catalog.js +423 -0
- package/dist/mcp/tools/repositories.d.ts +2 -0
- package/dist/mcp/tools/repositories.js +182 -0
- package/dist/mcp/tools/runs.d.ts +6 -0
- package/dist/mcp/tools/runs.js +60 -6
- package/dist/mcp/tools/scheduling.js +3 -6
- package/dist/mcp/tools/secrets.js +18 -6
- package/dist/mcp/tools/services.d.ts +2 -0
- package/dist/mcp/tools/services.js +222 -0
- package/dist/mcp/tools/subagents.js +52 -16
- package/dist/mcp/tools/tools.d.ts +41 -0
- package/dist/mcp/tools/tools.js +201 -40
- package/dist/mcp/tools/trigger.js +65 -7
- package/dist/mcp/tools/webhooks.js +15 -4
- package/dist/mcp/transport/streamable-http.d.ts +15 -0
- package/dist/mcp/transport/streamable-http.js +55 -3
- package/dist/mcp/webhooks/ingress.d.ts +2 -1
- package/dist/mcp/webhooks/ingress.js +9 -2
- package/dist/providers/auth/delegating.d.ts +19 -0
- package/dist/providers/auth/delegating.js +71 -0
- package/dist/providers/auth/index.d.ts +2 -0
- package/dist/providers/auth/index.js +11 -0
- package/dist/providers/auth/self-hosted.d.ts +10 -2
- package/dist/providers/auth/self-hosted.js +55 -6
- package/dist/providers/auth/types.d.ts +6 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +4 -1
- package/dist/providers/coding-proxy/memory-ledger.js +31 -3
- package/dist/providers/coding-proxy/metering.d.ts +6 -1
- package/dist/providers/coding-proxy/metering.js +41 -4
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +17 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +106 -8
- package/dist/providers/coding-proxy/proxy.d.ts +25 -2
- package/dist/providers/coding-proxy/proxy.js +561 -38
- package/dist/providers/coding-proxy/registry/audit.d.ts +131 -0
- package/dist/providers/coding-proxy/registry/audit.js +380 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/bounded-fetch.js +77 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +58 -0
- package/dist/providers/coding-proxy/registry/plan.js +304 -0
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +34 -0
- package/dist/providers/coding-proxy/registry/prisma-store.js +151 -0
- package/dist/providers/coding-proxy/registry/service.d.ts +213 -0
- package/dist/providers/coding-proxy/registry/service.js +1137 -0
- package/dist/providers/coding-proxy/registry/store.d.ts +127 -0
- package/dist/providers/coding-proxy/registry/store.js +70 -0
- package/dist/providers/coding-proxy/runtime.d.ts +17 -0
- package/dist/providers/coding-proxy/runtime.js +63 -0
- package/dist/providers/coding-proxy/secure-fetch.js +0 -1
- package/dist/providers/coding-proxy/server.d.ts +11 -0
- package/dist/providers/coding-proxy/server.js +163 -0
- package/dist/providers/coding-proxy/types.d.ts +33 -1
- package/dist/providers/coding-proxy/types.js +12 -1
- package/dist/providers/engine/types.d.ts +29 -0
- package/dist/providers/executor/build.d.ts +2 -2
- package/dist/providers/executor/composition.d.ts +3 -0
- package/dist/providers/executor/composition.js +28 -1
- package/dist/providers/executor/container.d.ts +134 -4
- package/dist/providers/executor/container.js +394 -37
- package/dist/providers/executor/dbos.d.ts +4 -3
- package/dist/providers/executor/dbos.js +7 -5
- package/dist/providers/executor/in-process.d.ts +2 -3
- package/dist/providers/executor/routing.d.ts +13 -0
- package/dist/providers/executor/routing.js +18 -0
- package/dist/providers/executor/types.d.ts +34 -0
- package/dist/providers/issue-tracker/adf.d.ts +31 -0
- package/dist/providers/issue-tracker/adf.js +181 -0
- package/dist/providers/issue-tracker/index.d.ts +5 -0
- package/dist/providers/issue-tracker/index.js +12 -0
- package/dist/providers/issue-tracker/jira-client.d.ts +41 -0
- package/dist/providers/issue-tracker/jira-client.js +151 -0
- package/dist/providers/issue-tracker/jira-events.d.ts +3 -0
- package/dist/providers/issue-tracker/jira-events.js +98 -0
- package/dist/providers/issue-tracker/jira.d.ts +116 -0
- package/dist/providers/issue-tracker/jira.js +502 -0
- package/dist/providers/issue-tracker/types.d.ts +269 -0
- package/dist/providers/issue-tracker/types.js +16 -0
- package/dist/providers/jobs/claude-tool-setup.d.ts +23 -0
- package/dist/providers/jobs/claude-tool-setup.js +50 -0
- package/dist/providers/jobs/collect-prune.d.ts +7 -0
- package/dist/providers/jobs/collect-prune.js +27 -0
- package/dist/providers/jobs/docker-isolation.d.ts +48 -3
- package/dist/providers/jobs/docker-isolation.js +213 -22
- package/dist/providers/jobs/docker-services.d.ts +35 -0
- package/dist/providers/jobs/docker-services.js +191 -0
- package/dist/providers/jobs/docker.d.ts +53 -2
- package/dist/providers/jobs/docker.js +307 -32
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +1 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +12 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +17 -2
- package/dist/providers/jobs/kubernetes-isolation.js +238 -57
- package/dist/providers/jobs/kubernetes-platform.d.ts +10 -4
- package/dist/providers/jobs/kubernetes-platform.js +11 -5
- package/dist/providers/jobs/kubernetes-preflight.js +3 -0
- package/dist/providers/jobs/kubernetes.d.ts +24 -2
- package/dist/providers/jobs/kubernetes.js +153 -22
- package/dist/providers/jobs/service-state.d.ts +22 -0
- package/dist/providers/jobs/service-state.js +17 -0
- package/dist/providers/jobs/types.d.ts +18 -0
- package/dist/providers/llm/anthropic.d.ts +3 -3
- package/dist/providers/llm/anthropic.js +3 -5
- package/dist/providers/llm/bedrock.d.ts +3 -3
- package/dist/providers/llm/bedrock.js +3 -8
- package/dist/providers/llm/catalog-lookup.d.ts +10 -0
- package/dist/providers/llm/catalog-lookup.js +15 -0
- package/dist/providers/llm/catalog-shipped.d.ts +18 -0
- package/dist/providers/llm/catalog-shipped.js +197 -0
- package/dist/providers/llm/catalog-store.d.ts +58 -0
- package/dist/providers/llm/catalog-store.js +138 -0
- package/dist/providers/llm/catalog-types.d.ts +66 -0
- package/dist/providers/llm/catalog-types.js +64 -0
- package/dist/providers/llm/catalog.d.ts +61 -0
- package/dist/providers/llm/catalog.js +147 -0
- package/dist/providers/llm/claude-messages.d.ts +5 -1
- package/dist/providers/llm/claude-messages.js +1 -0
- package/dist/providers/llm/claude-provider.d.ts +10 -12
- package/dist/providers/llm/claude-provider.js +15 -6
- package/dist/providers/llm/index.d.ts +9 -6
- package/dist/providers/llm/index.js +8 -5
- package/dist/providers/llm/openai.d.ts +14 -5
- package/dist/providers/llm/openai.js +24 -14
- package/dist/providers/llm/pricing-core.d.ts +5 -3
- package/dist/providers/llm/registration.js +8 -12
- package/dist/providers/llm/routing.d.ts +21 -11
- package/dist/providers/llm/routing.js +47 -13
- package/dist/providers/llm/types.d.ts +12 -0
- package/dist/providers/llm/types.js +8 -1
- package/dist/providers/review-host/diff-lines.d.ts +16 -0
- package/dist/providers/review-host/diff-lines.js +59 -0
- package/dist/providers/review-host/github-events.d.ts +6 -0
- package/dist/providers/review-host/github-events.js +226 -0
- package/dist/providers/review-host/github-user-auth.d.ts +38 -0
- package/dist/providers/review-host/github-user-auth.js +128 -0
- package/dist/providers/review-host/github.d.ts +57 -0
- package/dist/providers/review-host/github.js +568 -0
- package/dist/providers/review-host/index.d.ts +12 -0
- package/dist/providers/review-host/index.js +30 -0
- package/dist/providers/review-host/review-format.d.ts +19 -0
- package/dist/providers/review-host/review-format.js +59 -0
- package/dist/providers/review-host/types.d.ts +309 -0
- package/dist/providers/review-host/types.js +24 -0
- package/dist/providers/vcs/git.d.ts +16 -6
- package/dist/providers/vcs/git.js +78 -34
- package/dist/providers/vcs/github.d.ts +94 -3
- package/dist/providers/vcs/github.js +223 -17
- package/dist/providers/vcs/types.d.ts +48 -4
- package/dist/quickstart/index.d.ts +2 -0
- package/dist/quickstart/index.js +36 -8
- package/dist/sandbox/fetch-policy.d.ts +20 -2
- package/dist/sandbox/fetch-policy.js +64 -3
- package/dist/sandbox/host-functions.d.ts +9 -1
- package/dist/sandbox/host-functions.js +12 -5
- package/dist/serve.js +8 -2
- package/dist/viewer/api-schema.d.ts +2757 -0
- package/dist/viewer/api-schema.js +165 -0
- package/dist/viewer/build-schemas.d.ts +2 -0
- package/dist/viewer/build-schemas.js +18 -0
- package/dist/viewer/event-bus.d.ts +38 -0
- package/dist/viewer/event-bus.js +232 -0
- package/dist/viewer/graph.d.ts +40 -0
- package/dist/viewer/graph.js +243 -0
- package/dist/viewer/http.d.ts +30 -0
- package/dist/viewer/http.js +133 -0
- package/dist/viewer/run-detail.d.ts +4 -0
- package/dist/viewer/run-detail.js +61 -0
- package/dist/wardby-bin.js +11 -0
- package/docs/README.md +40 -0
- package/docs/agent-recipes.md +383 -0
- package/docs/architecture-runtime.md +90 -0
- package/docs/assets/brand/wardby-icon-512.png +0 -0
- package/docs/assets/brand/wardby-icon.svg +16 -0
- package/docs/assets/brand/wardby-mascot-profile-512.png +0 -0
- package/docs/assets/brand/wardby-mascot.png +0 -0
- package/docs/assets/brand/wardby-mascot.svg +5 -0
- package/docs/assets/wardby-workflow.svg +106 -0
- package/docs/code-review-agents.md +508 -0
- package/docs/coding-agent-setup.md +175 -0
- package/docs/coding-packages.md +455 -0
- package/docs/coding-services.md +300 -0
- package/docs/coding-worker-byo-images.md +98 -0
- package/docs/coding-worker-isolation.md +1068 -0
- package/docs/getting-started-gke.md +632 -0
- package/docs/getting-started-identity-provider.md +319 -0
- package/docs/getting-started.md +147 -0
- package/docs/jira-agents.md +649 -0
- package/docs/knowledge.md +387 -0
- package/docs/models.md +221 -0
- package/docs/observability.md +53 -0
- package/docs/release-verification.md +66 -0
- package/docs/security-deployment.md +667 -0
- package/docs/viewer-api.md +142 -0
- package/help/admin-viewer.md +39 -0
- package/help/agent-recipes.md +173 -0
- package/help/architecture-agent.md +189 -0
- package/help/builder-agent.md +80 -0
- package/help/code-review-agents.md +37 -0
- package/help/coding-packages.md +31 -0
- package/help/coding-services.md +71 -0
- package/help/cost-attribution.md +67 -0
- package/help/creating-agents.md +90 -0
- package/help/deploy-gke.md +45 -0
- package/help/deployment-targets.md +39 -0
- package/help/errors/budget-group-exhausted.md +25 -0
- package/help/errors/docker-isolation-unsupported.md +26 -0
- package/help/errors/model-unavailable.md +63 -0
- package/help/errors/protected-path.md +45 -0
- package/help/errors/repo-access.md +27 -0
- package/help/errors/service-declaration-invalid.md +27 -0
- package/help/errors/service-declaration-unavailable.md +25 -0
- package/help/errors/service-launcher-unsupported.md +30 -0
- package/help/errors/service-not-allowed.md +27 -0
- package/help/errors/service-unknown.md +23 -0
- package/help/errors/service-unready.md +49 -0
- package/help/getting-started.md +32 -0
- package/help/github.md +48 -0
- package/help/identity-and-access.md +44 -0
- package/help/jira.md +135 -0
- package/help/knowledge.md +47 -0
- package/help/mcp.md +30 -0
- package/help/models.md +90 -0
- package/help/native-capabilities.md +30 -0
- package/help/observability.md +41 -0
- package/help/operating-agents.md +36 -0
- package/help/security.md +27 -0
- package/help/troubleshooting/budgets.md +32 -0
- package/help/troubleshooting/coding-workers.md +47 -0
- package/help/troubleshooting/repository-access.md +27 -0
- package/package.json +14 -3
- package/prisma/migrations/20260925010000_coding_collect_exclude/migration.sql +8 -0
- package/prisma/migrations/20260925015000_allowed_egress_default/migration.sql +8 -0
- package/prisma/migrations/20260925020000_coding_package_registry/migration.sql +55 -0
- package/prisma/migrations/20260925030000_tool_name_per_owner/migration.sql +11 -0
- package/prisma/migrations/20260926010000_run_trigger_host_event/migration.sql +7 -0
- package/prisma/migrations/20260926020000_code_review_hosts/migration.sql +53 -0
- package/prisma/migrations/20260926030000_auth_user_roles/migration.sql +9 -0
- package/prisma/migrations/20260926040000_agent_effort/migration.sql +6 -0
- package/prisma/migrations/20260926050000_registry_lockfile_plan/migration.sql +32 -0
- package/prisma/migrations/20260926050000_repo_access_authorization/migration.sql +82 -0
- package/prisma/migrations/20260926060000_registry_plan_refusal/migration.sql +19 -0
- package/prisma/migrations/20260926100000_registry_plan_refusal_published_at/migration.sql +5 -0
- package/prisma/migrations/20260926190000_run_host_status/migration.sql +18 -0
- package/prisma/migrations/20260926210000_run_host_status_at_dispatch/migration.sql +5 -0
- package/prisma/migrations/20260927010000_resource_grants/migration.sql +72 -0
- package/prisma/migrations/20260927020000_proxy_session_budget_exhausted/migration.sql +3 -0
- package/prisma/migrations/20260927030000_coding_debug_trace/migration.sql +4 -0
- package/prisma/migrations/20260927040000_proxy_session_upstream_failure/migration.sql +3 -0
- package/prisma/migrations/20260927050000_coding_run_services/migration.sql +74 -0
- package/prisma/migrations/20260928000000_coding_run_tool_image/migration.sql +5 -0
- package/prisma/migrations/20260930000000_jira_issue_projects/migration.sql +34 -0
- package/prisma/migrations/20261001000000_jira_phase2_allowlists/migration.sql +3 -0
- package/prisma/migrations/20261001010000_jira_link_types_allowlist/migration.sql +2 -0
- package/prisma/migrations/20261002000000_jira_coding_bridge/migration.sql +28 -0
- package/prisma/migrations/20261002010000_jira_issue_creation/migration.sql +25 -0
- package/prisma/migrations/20261003000000_issue_cost_attribution/migration.sql +56 -0
- package/prisma/migrations/20261003010000_coding_run_service_status/migration.sql +23 -0
- package/prisma/migrations/20261003020000_viewer_notify/migration.sql +54 -0
- package/prisma/migrations/20261003030000_viewer_notify_fixes/migration.sql +47 -0
- package/prisma/migrations/20261003040000_viewer_indexes/migration.sql +12 -0
- package/prisma/migrations/20261004000000_model_catalog/migration.sql +26 -0
- package/prisma/schema.prisma +663 -21
- package/dist/mcp/tools/models.d.ts +0 -8
- package/dist/mcp/tools/models.js +0 -15
- package/dist/providers/llm/pricing-anthropic.d.ts +0 -4
- package/dist/providers/llm/pricing-anthropic.js +0 -30
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +0 -12
- package/dist/providers/llm/pricing-bedrock-claude.js +0 -37
- package/dist/providers/llm/pricing.d.ts +0 -30
- package/dist/providers/llm/pricing.js +0 -74
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linking a wardby principal to its verified host identity (GitHub today).
|
|
3
|
+
*
|
|
4
|
+
* 1. startHostIdentityLink: a single-use OAuth state and a PKCE verifier are
|
|
5
|
+
* stored (the state only as a hash) for 10 minutes; the caller gets the
|
|
6
|
+
* host's authorize URL.
|
|
7
|
+
* 2. completeHostIdentityCallback: the host redirects the browser back with
|
|
8
|
+
* the state; it is consumed atomically, the code is exchanged (the user
|
|
9
|
+
* token is revoked at once by the authorizer), and a one-time
|
|
10
|
+
* confirmation code is shown to the person in the browser.
|
|
11
|
+
* 3. confirmHostIdentityLink: the SAME principal that started the link
|
|
12
|
+
* submits the code (at most 5 tries). Only then is the identity stored.
|
|
13
|
+
*
|
|
14
|
+
* Step 3 is what stops an attacker from sending a victim their own authorize
|
|
15
|
+
* URL: the host skips its consent screen for users who already authorized the
|
|
16
|
+
* App, so one click would otherwise bind the victim's identity to the
|
|
17
|
+
* attacker's principal. The code is shown only in the victim's browser.
|
|
18
|
+
* A host user belongs to at most one principal.
|
|
19
|
+
*/
|
|
20
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
21
|
+
import { Prisma } from "#prisma";
|
|
22
|
+
import { logger } from "./logger.js";
|
|
23
|
+
const log = logger.child({ module: "host-identity-links" });
|
|
24
|
+
export const HOST_LINK_TTL_MS = 10 * 60_000;
|
|
25
|
+
export const HOST_LINK_MAX_ATTEMPTS = 5;
|
|
26
|
+
export const HOST_LINK_MAX_PENDING = 5;
|
|
27
|
+
const BASE32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
28
|
+
const CODE_LENGTH = 8;
|
|
29
|
+
export class HostLinkError extends Error {
|
|
30
|
+
status;
|
|
31
|
+
constructor(status, message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.name = "HostLinkError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** The browser callback a provider's link flow returns to (registered as the App's Callback URL). */
|
|
38
|
+
export function userCallbackPath(provider) {
|
|
39
|
+
return `/hosts/${provider}/user-callback`;
|
|
40
|
+
}
|
|
41
|
+
function sha256(value) {
|
|
42
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function confirmationCode() {
|
|
45
|
+
// 5 bits per character from a uniformly random byte's low bits (256 % 32 === 0: no bias).
|
|
46
|
+
return [...randomBytes(CODE_LENGTH)].map((b) => BASE32[b & 31]).join("");
|
|
47
|
+
}
|
|
48
|
+
export async function startHostIdentityLink(input) {
|
|
49
|
+
const now = input.now ?? new Date();
|
|
50
|
+
const provider = input.authorizer.provider;
|
|
51
|
+
await input.db.hostIdentityLinkRequest.deleteMany({ where: { expiresAt: { lte: now } } });
|
|
52
|
+
const pending = await input.db.hostIdentityLinkRequest.count({
|
|
53
|
+
where: { principalId: input.principalId, provider },
|
|
54
|
+
});
|
|
55
|
+
if (pending >= HOST_LINK_MAX_PENDING) {
|
|
56
|
+
throw new HostLinkError(429, "Too many account links in progress; finish one or wait 10 minutes.");
|
|
57
|
+
}
|
|
58
|
+
const state = randomBytes(32).toString("base64url");
|
|
59
|
+
const codeVerifier = randomBytes(32).toString("base64url");
|
|
60
|
+
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
|
|
61
|
+
const expiresAt = new Date(now.getTime() + HOST_LINK_TTL_MS);
|
|
62
|
+
await input.db.hostIdentityLinkRequest.create({
|
|
63
|
+
data: { principalId: input.principalId, provider, stateHash: sha256(state), codeVerifier, expiresAt },
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
authorizeUrl: input.authorizer.authorizeUrl({ state, codeChallenge, redirectUri: input.redirectUri }),
|
|
67
|
+
expiresAt,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export async function completeHostIdentityCallback(input) {
|
|
71
|
+
const now = input.now ?? new Date();
|
|
72
|
+
if (!input.state || !input.code || input.state.length > 256 || input.code.length > 256)
|
|
73
|
+
return { kind: "invalid" };
|
|
74
|
+
const stateHash = sha256(input.state);
|
|
75
|
+
// Single use: only the first callback for a live state wins.
|
|
76
|
+
const { count } = await input.db.hostIdentityLinkRequest.updateMany({
|
|
77
|
+
where: { stateHash, provider: input.authorizer.provider, callbackAt: null, expiresAt: { gt: now } },
|
|
78
|
+
data: { callbackAt: now },
|
|
79
|
+
});
|
|
80
|
+
if (count !== 1)
|
|
81
|
+
return { kind: "invalid" };
|
|
82
|
+
const request = await input.db.hostIdentityLinkRequest.findUnique({
|
|
83
|
+
where: { stateHash },
|
|
84
|
+
include: { principal: { select: { subject: true } } },
|
|
85
|
+
});
|
|
86
|
+
if (!request)
|
|
87
|
+
return { kind: "invalid" };
|
|
88
|
+
let user;
|
|
89
|
+
try {
|
|
90
|
+
user = await input.authorizer.complete({
|
|
91
|
+
code: input.code,
|
|
92
|
+
codeVerifier: request.codeVerifier,
|
|
93
|
+
redirectUri: input.redirectUri,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
log.warn({ err, provider: request.provider }, "host account link: the host refused the authorization");
|
|
98
|
+
await input.db.hostIdentityLinkRequest.delete({ where: { id: request.id } }).catch(() => undefined);
|
|
99
|
+
return { kind: "failed" };
|
|
100
|
+
}
|
|
101
|
+
const code = confirmationCode();
|
|
102
|
+
await input.db.hostIdentityLinkRequest.update({
|
|
103
|
+
where: { id: request.id },
|
|
104
|
+
// The verifier has done its job; keep nothing reusable.
|
|
105
|
+
data: { hostUserId: user.hostUserId, login: user.login, confirmHash: sha256(code), codeVerifier: "" },
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
kind: "confirm",
|
|
109
|
+
code: `${code.slice(0, 4)}-${code.slice(4)}`,
|
|
110
|
+
login: user.login,
|
|
111
|
+
subject: request.principal.subject,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export async function confirmHostIdentityLink(input) {
|
|
115
|
+
const now = input.now ?? new Date();
|
|
116
|
+
const code = input.confirmationCode.toUpperCase().replace(/[\s-]/g, "");
|
|
117
|
+
if (!new RegExp(`^[${BASE32}]{${CODE_LENGTH}}$`).test(code)) {
|
|
118
|
+
throw new HostLinkError(400, "The confirmation code is 8 letters and digits, as shown on the page (XXXX-XXXX).");
|
|
119
|
+
}
|
|
120
|
+
const request = await input.db.hostIdentityLinkRequest.findFirst({
|
|
121
|
+
where: {
|
|
122
|
+
principalId: input.principalId,
|
|
123
|
+
provider: input.provider,
|
|
124
|
+
confirmHash: { not: null },
|
|
125
|
+
hostUserId: { not: null },
|
|
126
|
+
login: { not: null },
|
|
127
|
+
attempts: { lt: HOST_LINK_MAX_ATTEMPTS },
|
|
128
|
+
expiresAt: { gt: now },
|
|
129
|
+
},
|
|
130
|
+
orderBy: { callbackAt: "desc" },
|
|
131
|
+
});
|
|
132
|
+
if (!request?.confirmHash || !request.hostUserId || !request.login)
|
|
133
|
+
throw noPendingLink();
|
|
134
|
+
// Spend an attempt BEFORE comparing, atomically: concurrent guesses can't
|
|
135
|
+
// each get a comparison before the counter saturates.
|
|
136
|
+
const claimed = await input.db.hostIdentityLinkRequest.updateMany({
|
|
137
|
+
where: { id: request.id, attempts: { lt: HOST_LINK_MAX_ATTEMPTS }, expiresAt: { gt: now } },
|
|
138
|
+
data: { attempts: { increment: 1 } },
|
|
139
|
+
});
|
|
140
|
+
if (claimed.count !== 1)
|
|
141
|
+
throw noPendingLink();
|
|
142
|
+
const presented = Buffer.from(sha256(code), "hex");
|
|
143
|
+
const expected = Buffer.from(request.confirmHash, "hex");
|
|
144
|
+
if (presented.length !== expected.length || !timingSafeEqual(presented, expected)) {
|
|
145
|
+
const after = await input.db.hostIdentityLinkRequest.findUnique({ where: { id: request.id } });
|
|
146
|
+
const left = Math.max(0, HOST_LINK_MAX_ATTEMPTS - (after?.attempts ?? HOST_LINK_MAX_ATTEMPTS));
|
|
147
|
+
throw new HostLinkError(400, left > 0
|
|
148
|
+
? `That confirmation code is not right; ${left} attempt${left === 1 ? "" : "s"} left.`
|
|
149
|
+
: "That confirmation code is not right, and this link attempt is used up. Start again with link_host_account.");
|
|
150
|
+
}
|
|
151
|
+
const hostUserId = request.hostUserId;
|
|
152
|
+
const login = request.login;
|
|
153
|
+
try {
|
|
154
|
+
await input.db.$transaction(async (tx) => {
|
|
155
|
+
// Consume the request first: a concurrent confirmation of the same code loses here.
|
|
156
|
+
// (Its attempt was already spent above, so attempts may now equal the limit.)
|
|
157
|
+
const consumed = await tx.hostIdentityLinkRequest.deleteMany({
|
|
158
|
+
where: { id: request.id, expiresAt: { gt: now } },
|
|
159
|
+
});
|
|
160
|
+
if (consumed.count !== 1)
|
|
161
|
+
throw new HostLinkError(404, "This link attempt is no longer valid; start again.");
|
|
162
|
+
const holder = await tx.hostIdentity.findUnique({
|
|
163
|
+
where: { provider_hostUserId: { provider: input.provider, hostUserId } },
|
|
164
|
+
});
|
|
165
|
+
if (holder && holder.principalId !== input.principalId)
|
|
166
|
+
throw alreadyLinked();
|
|
167
|
+
await tx.hostIdentity.upsert({
|
|
168
|
+
where: { principalId_provider: { principalId: input.principalId, provider: input.provider } },
|
|
169
|
+
create: { principalId: input.principalId, provider: input.provider, hostUserId, login },
|
|
170
|
+
update: { hostUserId, login, linkedAt: now },
|
|
171
|
+
});
|
|
172
|
+
}, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable });
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
if (err instanceof HostLinkError)
|
|
176
|
+
throw err;
|
|
177
|
+
if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2002")
|
|
178
|
+
throw alreadyLinked();
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
return { hostUserId, login };
|
|
182
|
+
}
|
|
183
|
+
function noPendingLink() {
|
|
184
|
+
return new HostLinkError(404, "No account link is waiting for a confirmation code from you. Start again with link_host_account (no code).");
|
|
185
|
+
}
|
|
186
|
+
function alreadyLinked() {
|
|
187
|
+
return new HostLinkError(409, "That GitHub account is already linked to another wardby account. An operator can unlink it " +
|
|
188
|
+
"(`wardby auth host-account unlink --subject <subject>`) if it should move to you.");
|
|
189
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The status comment for a run started by an @-mention. Where to comment is
|
|
3
|
+
* recorded with the run itself (mentionStatusRow, written in the dispatch
|
|
4
|
+
* transaction); the "working on it" comment is posted right after the webhook
|
|
5
|
+
* is answered, and edited once with the outcome — the pull requests its coding
|
|
6
|
+
* sub-runs opened or updated, the agent's reply when none came out, or why it
|
|
7
|
+
* did not succeed. A run that ends before its comment was posted (the instance
|
|
8
|
+
* died first, say) still gets one: the reconciler posts the outcome as a new
|
|
9
|
+
* comment. Best effort throughout: nothing here throws.
|
|
10
|
+
*/
|
|
11
|
+
import type { Prisma, PrismaClient, Run } from "#prisma";
|
|
12
|
+
import type { CodeReviewHost, ReviewHostProvider, ReviewHostRegistry } from "../providers/review-host/types.js";
|
|
13
|
+
export type HostStatusDb = Pick<PrismaClient, "runHostStatus" | "run">;
|
|
14
|
+
export type FinishedRun = Pick<Run, "id" | "status" | "finalText">;
|
|
15
|
+
/** The parts of a CodingRun result this comment uses. */
|
|
16
|
+
export interface PullRequestOutcome {
|
|
17
|
+
outcome: "pull_request_opened" | "pull_request_updated";
|
|
18
|
+
repository: string;
|
|
19
|
+
pullRequestNumber: number;
|
|
20
|
+
/** The result's own pull request URL; absent from a malformed result. */
|
|
21
|
+
pullRequestUrl?: string;
|
|
22
|
+
/** The code host the repository is on. */
|
|
23
|
+
codeProvider: string;
|
|
24
|
+
/** The coding sub-run that produced it; set by collectRunOutcome. */
|
|
25
|
+
runId?: string;
|
|
26
|
+
}
|
|
27
|
+
/** A sub-run that ended without succeeding. */
|
|
28
|
+
export interface FailedChild {
|
|
29
|
+
id: string;
|
|
30
|
+
status: string;
|
|
31
|
+
/** The coding sub-run's failure category; `provider_<class>` names a model-provider refusal. */
|
|
32
|
+
failureCategory?: string | null;
|
|
33
|
+
/** The sub-run's Run.error; read only for a service refusal's host sentence (coding/services/wording.ts). */
|
|
34
|
+
error?: string | null;
|
|
35
|
+
/** The service names on the coding sub-run (CodingRun.services), for one that never became ready. */
|
|
36
|
+
services?: string[];
|
|
37
|
+
}
|
|
38
|
+
export declare const runLine: (runId: string) => string;
|
|
39
|
+
export declare function workingBody(runId: string): string;
|
|
40
|
+
/** The status row for a mention run, created in the same transaction as the run. */
|
|
41
|
+
export declare function mentionStatusRow(provider: ReviewHostProvider, event: {
|
|
42
|
+
repository: string;
|
|
43
|
+
number: number;
|
|
44
|
+
replyToReviewCommentId?: string;
|
|
45
|
+
}, runId: string): Prisma.RunHostStatusUncheckedCreateInput;
|
|
46
|
+
export declare function outcomeBody(run: FinishedRun, repository: string, pullRequests: PullRequestOutcome[], failedChildren?: FailedChild[], opts?: {
|
|
47
|
+
budgetSentence?: string;
|
|
48
|
+
noPullRequestText?: string;
|
|
49
|
+
/** The agent's reply IS the answer (no separate reply comment): shown as written, not quoted. */
|
|
50
|
+
replyAsAnswer?: boolean;
|
|
51
|
+
}): string;
|
|
52
|
+
/** What collectRunOutcome reads: a run's children and, when out of budget, its budget facts. */
|
|
53
|
+
export type RunOutcomeDb = Pick<PrismaClient, "run">;
|
|
54
|
+
/** The parts of a finished run's outcome a status comment reports; shared by GitHub and Jira status comments. */
|
|
55
|
+
export declare function collectRunOutcome(db: RunOutcomeDb, run: FinishedRun): Promise<{
|
|
56
|
+
pullRequests: PullRequestOutcome[];
|
|
57
|
+
failedChildren: FailedChild[];
|
|
58
|
+
budgetSentence?: string;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Writes a finished run's outcome to its status comment and marks it
|
|
62
|
+
* complete: edits the comment when it exists; when it does not yet, posts the
|
|
63
|
+
* outcome as a new comment only if `postIfMissing` (the reconciler, well after
|
|
64
|
+
* the run ended), and otherwise leaves the row for postMentionStatus, which
|
|
65
|
+
* is about to post it. A failed host call leaves the row open for the
|
|
66
|
+
* reconciler to retry.
|
|
67
|
+
*/
|
|
68
|
+
export declare function completeHostStatus(db: HostStatusDb, run: FinishedRun, hosts: ReviewHostRegistry | undefined, opts?: {
|
|
69
|
+
postIfMissing?: boolean;
|
|
70
|
+
}): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Posts the "working on it" comment for a mention run whose status row was
|
|
73
|
+
* written at dispatch, and records the comment on the row. When the run
|
|
74
|
+
* already ended (a fast failure can beat this follow-up), completes it at
|
|
75
|
+
* once. Does nothing when the row is gone, already has a comment, or is
|
|
76
|
+
* already complete. Never throws.
|
|
77
|
+
*/
|
|
78
|
+
export declare function postMentionStatus(db: HostStatusDb, host: CodeReviewHost, runId: string, hosts: ReviewHostRegistry | undefined): Promise<void>;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { CODING_CODE_PROVIDER } from "../coding/protocol.js";
|
|
2
|
+
import { storedServiceNames } from "../coding/services/catalog.js";
|
|
3
|
+
import { SERVICE_UNREADY_CATEGORY, serviceRefusalSentence, serviceUnreadySentence, } from "../coding/services/wording.js";
|
|
4
|
+
import { PROTECTED_PATH_CATEGORY, PROTECTED_PATH_HOST_LINE } from "../coding/protected-path-wording.js";
|
|
5
|
+
import { loadBudgetSentence } from "./budget-wording.js";
|
|
6
|
+
import { logger } from "./logger.js";
|
|
7
|
+
import { providerClassOfCategory, providerSentence } from "./provider-wording.js";
|
|
8
|
+
const log = logger.child({ module: "host-status" });
|
|
9
|
+
/** Keeps the edited comment readable; the full reply stays on the run. */
|
|
10
|
+
const MAX_REPLY_CHARS = 2000;
|
|
11
|
+
const TERMINAL = new Set(["succeeded", "failed", "refused", "lost", "budget_exhausted", "cancelled"]);
|
|
12
|
+
export const runLine = (runId) => `<sub>wardby run \`${runId}\`</sub>`;
|
|
13
|
+
export function workingBody(runId) {
|
|
14
|
+
return `👀 Working on it.\n\n${runLine(runId)}`;
|
|
15
|
+
}
|
|
16
|
+
/** The status row for a mention run, created in the same transaction as the run. */
|
|
17
|
+
export function mentionStatusRow(provider, event, runId) {
|
|
18
|
+
return {
|
|
19
|
+
runId,
|
|
20
|
+
provider,
|
|
21
|
+
repository: event.repository,
|
|
22
|
+
number: event.number,
|
|
23
|
+
commentKind: event.replyToReviewCommentId ? "inline" : "conversation",
|
|
24
|
+
replyToReviewCommentId: event.replyToReviewCommentId ?? null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function pullRequestOutcome(result) {
|
|
28
|
+
if (!result || typeof result !== "object")
|
|
29
|
+
return null;
|
|
30
|
+
const r = result;
|
|
31
|
+
if (r.outcome !== "pull_request_opened" && r.outcome !== "pull_request_updated")
|
|
32
|
+
return null;
|
|
33
|
+
if (typeof r.repository !== "string" || typeof r.pullRequestNumber !== "number")
|
|
34
|
+
return null;
|
|
35
|
+
if (!Number.isInteger(r.pullRequestNumber) || r.pullRequestNumber <= 0)
|
|
36
|
+
return null;
|
|
37
|
+
return {
|
|
38
|
+
outcome: r.outcome,
|
|
39
|
+
repository: r.repository,
|
|
40
|
+
pullRequestNumber: r.pullRequestNumber,
|
|
41
|
+
codeProvider: CODING_CODE_PROVIDER,
|
|
42
|
+
...(typeof r.pullRequestUrl === "string" ? { pullRequestUrl: r.pullRequestUrl } : {}),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** The agent's reply as a quote, cut to MAX_REPLY_CHARS, with @-mentions defused so nobody is pinged. */
|
|
46
|
+
const cutReply = (text) => text.length > MAX_REPLY_CHARS ? `${text.slice(0, MAX_REPLY_CHARS)}…` : text;
|
|
47
|
+
function quoteReply(text) {
|
|
48
|
+
return cutReply(text)
|
|
49
|
+
.replace(/@(?=[\w-])/g, "@")
|
|
50
|
+
.split("\n")
|
|
51
|
+
.map((line) => `> ${line}`)
|
|
52
|
+
.join("\n");
|
|
53
|
+
}
|
|
54
|
+
export function outcomeBody(run, repository, pullRequests, failedChildren = [], opts = {}) {
|
|
55
|
+
const links = pullRequests.map((pr) => {
|
|
56
|
+
const ref = pr.repository.toLowerCase() === repository.toLowerCase()
|
|
57
|
+
? `#${pr.pullRequestNumber}`
|
|
58
|
+
: `${pr.repository}#${pr.pullRequestNumber}`;
|
|
59
|
+
return pr.outcome === "pull_request_opened" ? `Opened ${ref}` : `Pushed changes to ${ref}`;
|
|
60
|
+
});
|
|
61
|
+
const partial = links.length > 0 ? `\n\n${links.join(", ")}.` : "";
|
|
62
|
+
const footer = runLine(run.id);
|
|
63
|
+
if (run.status === "lost") {
|
|
64
|
+
return `❌ Interrupted before it finished (for example, wardby restarted). Repeat your request to retry.${partial}\n\n${footer}`;
|
|
65
|
+
}
|
|
66
|
+
if (run.status === "budget_exhausted" || run.status === "refused") {
|
|
67
|
+
// A refused run could not start for lack of budget; see budgetSentence.
|
|
68
|
+
return `❌ ${opts.budgetSentence ?? "Out of budget."}${partial}\n\n${footer}`;
|
|
69
|
+
}
|
|
70
|
+
if (run.status !== "succeeded") {
|
|
71
|
+
// Only the status: a run's error text can carry internal detail that does not belong on the host.
|
|
72
|
+
return `❌ Stopped: the run ended with status \`${run.status}\`.${partial}\n\n${footer}`;
|
|
73
|
+
}
|
|
74
|
+
const reply = run.finalText?.trim();
|
|
75
|
+
const quoted = reply ? `\n\n${quoteReply(reply)}` : "";
|
|
76
|
+
if (failedChildren.length > 0) {
|
|
77
|
+
// The agent itself finished, but the work it handed off did not.
|
|
78
|
+
const outOfBudget = failedChildren.filter((c) => c.status === "budget_exhausted");
|
|
79
|
+
const providerClassOf = (c) => c.status === "failed" ? providerClassOfCategory(c.failureCategory) : null;
|
|
80
|
+
// A coding sub-run its services stopped: refused at dispatch, or a sidecar never became ready.
|
|
81
|
+
const serviceSentenceOf = (c) => c.status === "refused"
|
|
82
|
+
? serviceRefusalSentence(c.error)
|
|
83
|
+
: c.status === "failed" && c.failureCategory === SERVICE_UNREADY_CATEGORY
|
|
84
|
+
? serviceUnreadySentence(c.services ?? [])
|
|
85
|
+
: null;
|
|
86
|
+
// No path reaches this comment (see coding/protected-path-wording.ts), only the category.
|
|
87
|
+
const protectedPathOf = (c) => c.status === "failed" && c.failureCategory === PROTECTED_PATH_CATEGORY;
|
|
88
|
+
const providerClasses = new Set(failedChildren.map(providerClassOf).filter((c) => c !== null));
|
|
89
|
+
const serviceSentences = new Set(failedChildren.map(serviceSentenceOf).filter((s) => s !== null));
|
|
90
|
+
const protectedPathFailed = failedChildren.some(protectedPathOf);
|
|
91
|
+
const other = failedChildren.filter((c) => c.status !== "budget_exhausted" &&
|
|
92
|
+
providerClassOf(c) === null &&
|
|
93
|
+
serviceSentenceOf(c) === null &&
|
|
94
|
+
!protectedPathOf(c));
|
|
95
|
+
const lines = [];
|
|
96
|
+
if (outOfBudget.length > 0) {
|
|
97
|
+
lines.push(`A sub-run ran out of budget: ${outOfBudget.map((c) => `\`${c.id}\``).join(", ")}.`);
|
|
98
|
+
}
|
|
99
|
+
// The class only, never the provider's code: the sentence says who has to act.
|
|
100
|
+
for (const providerClass of providerClasses) {
|
|
101
|
+
lines.push(`A sub-run could not reach the model: ${providerSentence(providerClass)}`);
|
|
102
|
+
}
|
|
103
|
+
// The fixed sentence only, never the Run.error code in front of it.
|
|
104
|
+
for (const sentence of serviceSentences) {
|
|
105
|
+
lines.push(`A sub-run could not start: ${sentence}`);
|
|
106
|
+
}
|
|
107
|
+
if (protectedPathFailed)
|
|
108
|
+
lines.push(PROTECTED_PATH_HOST_LINE);
|
|
109
|
+
if (other.length > 0) {
|
|
110
|
+
lines.push(`A sub-run did not succeed: ${other.map((c) => `\`${c.id}\` (\`${c.status}\`)`).join(", ")}.`);
|
|
111
|
+
}
|
|
112
|
+
return `❌ ${lines.join(" ")}${partial}${quoted}\n\n${footer}`;
|
|
113
|
+
}
|
|
114
|
+
if (links.length > 0)
|
|
115
|
+
return `✅ ${links.join(", ")}.\n\n${footer}`;
|
|
116
|
+
if (opts.replyAsAnswer && reply)
|
|
117
|
+
return `✅ ${cutReply(reply)}\n\n${footer}`;
|
|
118
|
+
return `✅ ${opts.noPullRequestText ?? "Finished without opening a pull request."}${quoted}\n\n${footer}`;
|
|
119
|
+
}
|
|
120
|
+
/** The parts of a finished run's outcome a status comment reports; shared by GitHub and Jira status comments. */
|
|
121
|
+
export async function collectRunOutcome(db, run) {
|
|
122
|
+
const children = await db.run.findMany({
|
|
123
|
+
where: { parentRunId: run.id },
|
|
124
|
+
select: {
|
|
125
|
+
id: true,
|
|
126
|
+
status: true,
|
|
127
|
+
error: true,
|
|
128
|
+
codingRun: { select: { result: true, failureCategory: true, services: true } },
|
|
129
|
+
},
|
|
130
|
+
orderBy: { startedAt: "asc" },
|
|
131
|
+
});
|
|
132
|
+
const pullRequests = children
|
|
133
|
+
.map((c) => {
|
|
134
|
+
const pr = pullRequestOutcome(c.codingRun?.result);
|
|
135
|
+
return pr ? { ...pr, runId: c.id } : null;
|
|
136
|
+
})
|
|
137
|
+
.filter((pr) => pr !== null);
|
|
138
|
+
const failedChildren = children
|
|
139
|
+
.filter((c) => TERMINAL.has(c.status) && c.status !== "succeeded")
|
|
140
|
+
.map((c) => ({
|
|
141
|
+
id: c.id,
|
|
142
|
+
status: c.status,
|
|
143
|
+
failureCategory: c.codingRun?.failureCategory ?? null,
|
|
144
|
+
error: c.error ?? null,
|
|
145
|
+
services: storedServiceNames(c.codingRun?.services),
|
|
146
|
+
}));
|
|
147
|
+
const budgetSentence = run.status === "budget_exhausted" || run.status === "refused"
|
|
148
|
+
? await loadBudgetSentence(db, run.id, run.status)
|
|
149
|
+
: undefined;
|
|
150
|
+
return { pullRequests, failedChildren, ...(budgetSentence ? { budgetSentence } : {}) };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Writes a finished run's outcome to its status comment and marks it
|
|
154
|
+
* complete: edits the comment when it exists; when it does not yet, posts the
|
|
155
|
+
* outcome as a new comment only if `postIfMissing` (the reconciler, well after
|
|
156
|
+
* the run ended), and otherwise leaves the row for postMentionStatus, which
|
|
157
|
+
* is about to post it. A failed host call leaves the row open for the
|
|
158
|
+
* reconciler to retry.
|
|
159
|
+
*/
|
|
160
|
+
export async function completeHostStatus(db, run, hosts, opts = {}) {
|
|
161
|
+
if (!hosts)
|
|
162
|
+
return;
|
|
163
|
+
try {
|
|
164
|
+
const status = await db.runHostStatus.findUnique({ where: { runId: run.id } });
|
|
165
|
+
if (!status || status.completedAt)
|
|
166
|
+
return;
|
|
167
|
+
if (!status.commentId && !opts.postIfMissing)
|
|
168
|
+
return;
|
|
169
|
+
const host = hosts[status.provider];
|
|
170
|
+
if (!host)
|
|
171
|
+
return;
|
|
172
|
+
const { pullRequests, failedChildren, budgetSentence } = await collectRunOutcome(db, run);
|
|
173
|
+
const body = outcomeBody(run, status.repository, pullRequests, failedChildren, { budgetSentence });
|
|
174
|
+
let commentId = status.commentId;
|
|
175
|
+
if (commentId) {
|
|
176
|
+
await host.editComment(status.repository, {
|
|
177
|
+
kind: status.commentKind === "inline" ? "inline" : "conversation",
|
|
178
|
+
id: commentId,
|
|
179
|
+
body,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
commentId = (await host.comment(status.repository, {
|
|
184
|
+
number: status.number,
|
|
185
|
+
body,
|
|
186
|
+
...(status.replyToReviewCommentId ? { replyToReviewCommentId: status.replyToReviewCommentId } : {}),
|
|
187
|
+
})).id;
|
|
188
|
+
}
|
|
189
|
+
await db.runHostStatus.update({ where: { runId: run.id }, data: { commentId, completedAt: new Date() } });
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
log.warn({ err, runId: run.id }, "could not complete the run's status comment");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Posts the "working on it" comment for a mention run whose status row was
|
|
197
|
+
* written at dispatch, and records the comment on the row. When the run
|
|
198
|
+
* already ended (a fast failure can beat this follow-up), completes it at
|
|
199
|
+
* once. Does nothing when the row is gone, already has a comment, or is
|
|
200
|
+
* already complete. Never throws.
|
|
201
|
+
*/
|
|
202
|
+
export async function postMentionStatus(db, host, runId, hosts) {
|
|
203
|
+
try {
|
|
204
|
+
const status = await db.runHostStatus.findUnique({ where: { runId } });
|
|
205
|
+
if (!status || status.commentId || status.completedAt)
|
|
206
|
+
return;
|
|
207
|
+
const posted = await host.comment(status.repository, {
|
|
208
|
+
number: status.number,
|
|
209
|
+
body: workingBody(runId),
|
|
210
|
+
...(status.replyToReviewCommentId ? { replyToReviewCommentId: status.replyToReviewCommentId } : {}),
|
|
211
|
+
});
|
|
212
|
+
const claimed = await db.runHostStatus.updateMany({
|
|
213
|
+
where: { runId, commentId: null, completedAt: null },
|
|
214
|
+
data: { commentId: posted.id },
|
|
215
|
+
});
|
|
216
|
+
if (claimed.count === 0) {
|
|
217
|
+
// The reconciler posted the outcome meanwhile; this comment is surplus.
|
|
218
|
+
log.warn({ runId }, "status comment posted after the outcome; leaving both");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const run = await db.run.findUnique({ where: { id: runId }, select: { id: true, status: true, finalText: true } });
|
|
222
|
+
if (run && TERMINAL.has(run.status))
|
|
223
|
+
await completeHostStatus(db, run, hosts);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
log.warn({ err, runId }, "could not post the status comment");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Registers a run for the duration of `work`. */
|
|
2
|
+
export declare function trackRun<T>(runId: string, work: () => Promise<T>): Promise<T>;
|
|
3
|
+
export declare function inFlightRunIds(): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Resolves once no run is executing, or after `timeoutMs`, whichever is
|
|
6
|
+
* first. Returns the ids still executing at that point (empty when drained).
|
|
7
|
+
*/
|
|
8
|
+
export declare function waitForInFlightRuns(timeoutMs: number): Promise<string[]>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counts the native runs executing in this process, so a shutdown can wait
|
|
3
|
+
* for them instead of abandoning them. Every native run, however it was
|
|
4
|
+
* started (a direct start, a DBOS workflow, a workflow adopted from a dead
|
|
5
|
+
* instance), goes through executeRun, which registers here. Coding jobs are
|
|
6
|
+
* not counted: they run in their own pods and a new instance collects them.
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "./logger.js";
|
|
9
|
+
const log = logger.child({ module: "in-flight-runs" });
|
|
10
|
+
const active = new Set();
|
|
11
|
+
let waiters = [];
|
|
12
|
+
/** Registers a run for the duration of `work`. */
|
|
13
|
+
export async function trackRun(runId, work) {
|
|
14
|
+
active.add(runId);
|
|
15
|
+
try {
|
|
16
|
+
return await work();
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
active.delete(runId);
|
|
20
|
+
if (active.size === 0) {
|
|
21
|
+
const done = waiters;
|
|
22
|
+
waiters = [];
|
|
23
|
+
for (const wake of done)
|
|
24
|
+
wake();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function inFlightRunIds() {
|
|
29
|
+
return [...active];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolves once no run is executing, or after `timeoutMs`, whichever is
|
|
33
|
+
* first. Returns the ids still executing at that point (empty when drained).
|
|
34
|
+
*/
|
|
35
|
+
export async function waitForInFlightRuns(timeoutMs) {
|
|
36
|
+
if (active.size === 0 || timeoutMs <= 0)
|
|
37
|
+
return inFlightRunIds();
|
|
38
|
+
log.info({ runIds: inFlightRunIds(), timeoutMs }, "waiting for in-flight runs before shutdown");
|
|
39
|
+
await new Promise((resolve) => {
|
|
40
|
+
const timer = setTimeout(() => {
|
|
41
|
+
waiters = waiters.filter((w) => w !== wake);
|
|
42
|
+
resolve();
|
|
43
|
+
}, timeoutMs);
|
|
44
|
+
const wake = () => {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
resolve();
|
|
47
|
+
};
|
|
48
|
+
waiters.push(wake);
|
|
49
|
+
});
|
|
50
|
+
const remaining = inFlightRunIds();
|
|
51
|
+
if (remaining.length > 0)
|
|
52
|
+
log.warn({ runIds: remaining }, "shutdown drain timed out; these runs are abandoned");
|
|
53
|
+
else
|
|
54
|
+
log.info("in-flight runs finished; shutting down");
|
|
55
|
+
return remaining;
|
|
56
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Links a run's pull requests to the issue that started it: records each
|
|
3
|
+
* issue/PR pair, puts a web link on the issue, and applies the link's
|
|
4
|
+
* configured status move. Provider-neutral: a code host is only ever
|
|
5
|
+
* { provider, repository, number }. The issue key comes from the run tree
|
|
6
|
+
* (RunIssueStatus), never from model output. The status move is a control-plane
|
|
7
|
+
* action (not gated by allowedTransitions). Nothing here throws, except
|
|
8
|
+
* handlePullRequestClosed's lookup before it has claimed anything (so the
|
|
9
|
+
* webhook delivery is rolled back and redelivered).
|
|
10
|
+
*/
|
|
11
|
+
import { type PrismaClient } from "#prisma";
|
|
12
|
+
import { type IssueTracker, type IssueTrackerRegistry } from "../providers/issue-tracker/types.js";
|
|
13
|
+
export type IssueBridgeDb = Pick<PrismaClient, "issuePullRequest">;
|
|
14
|
+
export type PullRequestClosedDb = Pick<PrismaClient, "issuePullRequest" | "agentIssueProject">;
|
|
15
|
+
export interface BridgedPullRequest {
|
|
16
|
+
codeProvider: string;
|
|
17
|
+
repository: string;
|
|
18
|
+
number: number;
|
|
19
|
+
url: string;
|
|
20
|
+
openedByRunId: string;
|
|
21
|
+
outcome: "pull_request_opened" | "pull_request_updated";
|
|
22
|
+
}
|
|
23
|
+
export interface RecordPullRequestsInput {
|
|
24
|
+
issueKey: string;
|
|
25
|
+
issueProvider: string;
|
|
26
|
+
agentId: string;
|
|
27
|
+
/** The status the link moves the issue to when a pull request is opened, if configured. */
|
|
28
|
+
onPullRequestOpened?: string | null;
|
|
29
|
+
pullRequests: BridgedPullRequest[];
|
|
30
|
+
}
|
|
31
|
+
export declare const pullRequestGlobalId: (pr: Pick<BridgedPullRequest, "codeProvider" | "repository" | "number">) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Returns sentences for the outcome comment (a refused status move); empty
|
|
34
|
+
* when there is nothing to say. Safe to repeat (a retried completion): each
|
|
35
|
+
* pair's side effects happen once — the status move only when this call newly
|
|
36
|
+
* recorded an opened pull request, and a merged/closed pair is never re-linked
|
|
37
|
+
* (re-posting its web link would un-resolve it). An unreadable store skips
|
|
38
|
+
* both rather than risk repeating them.
|
|
39
|
+
*/
|
|
40
|
+
export declare function recordPullRequests(db: IssueBridgeDb, tracker: IssueTracker, input: RecordPullRequestsInput): Promise<{
|
|
41
|
+
notes: string[];
|
|
42
|
+
}>;
|
|
43
|
+
export interface ClosedPullRequest {
|
|
44
|
+
codeProvider: string;
|
|
45
|
+
repository: string;
|
|
46
|
+
number: number;
|
|
47
|
+
merged: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A pull request wardby recorded against an issue was merged or closed: marks
|
|
51
|
+
* each still-open pair, and, where the agent's link to the issue's project is
|
|
52
|
+
* still write, comments on the issue (and on merge resolves the web link and
|
|
53
|
+
* applies the link's onPullRequestMerged move). Only rows wardby wrote are
|
|
54
|
+
* touched, matched by the host's own identity for the PR — nothing from the
|
|
55
|
+
* PR's text. The row is claimed first (open → merged/closed), so a duplicate
|
|
56
|
+
* or concurrent delivery finds nothing to do. Throws only when the lookup of
|
|
57
|
+
* linked rows fails — before anything is claimed — so the caller's webhook
|
|
58
|
+
* delivery is rolled back and redelivered; never throws after that.
|
|
59
|
+
*/
|
|
60
|
+
export declare function handlePullRequestClosed(db: PullRequestClosedDb, trackers: IssueTrackerRegistry | undefined, pr: ClosedPullRequest): Promise<void>;
|