@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,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model catalog over MCP (docs/models.md). Reading it (list_models,
|
|
3
|
+
* get_model) needs only agents:read: anyone deciding what to put in an
|
|
4
|
+
* Agent.model needs to see what's routable, what it costs, and whether it's
|
|
5
|
+
* shipped or a deployment override — entries hold no secrets. Changing it
|
|
6
|
+
* (set_model, disable_model, reset_model) needs models:admin, a privileged
|
|
7
|
+
* scope honoured only with a role granting it (model-manager or admin;
|
|
8
|
+
* resource-server.ts): an entry decides what every principal's runs on that
|
|
9
|
+
* model id are priced and shaped as. Each change is audit-logged (event
|
|
10
|
+
* models.catalog.<action>). Runs already dispatched keep the entry they
|
|
11
|
+
* started with (CatalogEntry snapshots, not live lookups) — a write here
|
|
12
|
+
* never reprices or reshapes a run in flight.
|
|
13
|
+
*
|
|
14
|
+
* Correctness of a write never depends on the process's installed
|
|
15
|
+
* CatalogStore, which can be stale (it polls on an interval) or briefly
|
|
16
|
+
* unreachable:
|
|
17
|
+
* - `set_model`'s provider-conflict check reads `ctx.db` directly (plus the
|
|
18
|
+
* static shipped catalog, which is never stale), not the in-memory
|
|
19
|
+
* catalog — a conflicting row written by another process/replica and
|
|
20
|
+
* not yet polled in here must still be caught.
|
|
21
|
+
* - Every write's response and audit event are built from the data just
|
|
22
|
+
* written (what we know is true), never from a post-write re-read of the
|
|
23
|
+
* catalog — so a refresh failure can never turn a successful write into
|
|
24
|
+
* an unaudited one, or into an error.
|
|
25
|
+
* - `deps.refresh` is still called best-effort after each write (so this
|
|
26
|
+
* process's own routing picks up the change promptly); a failure is
|
|
27
|
+
* logged and swallowed, never thrown.
|
|
28
|
+
* - `set_model` additionally re-checks ownership after a *successful*
|
|
29
|
+
* refresh: two processes racing to claim the same model id under
|
|
30
|
+
* different providers can both write (the compound key is
|
|
31
|
+
* (provider, modelId), not modelId alone) — `buildCatalog` then silently
|
|
32
|
+
* picks one winner. If the merge didn't pick us, we report an error
|
|
33
|
+
* rather than success, even though our own row did get written.
|
|
34
|
+
*/
|
|
35
|
+
import { z } from "zod";
|
|
36
|
+
import { logger } from "../../core/logger.js";
|
|
37
|
+
import { McpError } from "../errors.js";
|
|
38
|
+
import { textResult } from "./text-result.js";
|
|
39
|
+
import { MODEL_PROVIDERS, THINKING_MODES, TOKENIZER_ENCODINGS, entryOf, sameEntry, } from "../../providers/llm/catalog-types.js";
|
|
40
|
+
import { LLM_EFFORT_LEVELS } from "../../providers/llm/types.js";
|
|
41
|
+
import { ownerOf, rowFromRecord } from "../../providers/llm/catalog.js";
|
|
42
|
+
import { currentModelCatalog } from "../../providers/llm/catalog-store.js";
|
|
43
|
+
import { SHIPPED_CATALOG_VERSION } from "../../providers/llm/catalog-shipped.js";
|
|
44
|
+
const modelsLog = logger.child({ module: "mcp-model-catalog" });
|
|
45
|
+
const RATE_FIELDS = ["inputPerMTok", "outputPerMTok", "cachedInputPerMTok", "cacheWritePerMTok"];
|
|
46
|
+
function parse(schema, label, value) {
|
|
47
|
+
const result = schema.safeParse(value);
|
|
48
|
+
if (!result.success) {
|
|
49
|
+
const details = result.error.issues
|
|
50
|
+
.map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`)
|
|
51
|
+
.join("; ");
|
|
52
|
+
throw new McpError(400, `Invalid ${label}: ${details}`);
|
|
53
|
+
}
|
|
54
|
+
return result.data;
|
|
55
|
+
}
|
|
56
|
+
const ModelIdSchema = z
|
|
57
|
+
.string()
|
|
58
|
+
.min(1)
|
|
59
|
+
.max(200)
|
|
60
|
+
.regex(/^[A-Za-z0-9._:/-]+$/, "modelId must match ^[A-Za-z0-9._:/-]+$");
|
|
61
|
+
const ModelIdArgSchema = z.object({ modelId: ModelIdSchema }).strict();
|
|
62
|
+
const ListModelsSchema = z.object({ includeDisabled: z.boolean().optional() }).strict();
|
|
63
|
+
const SetModelSchema = z
|
|
64
|
+
.object({
|
|
65
|
+
provider: z.enum(MODEL_PROVIDERS),
|
|
66
|
+
modelId: ModelIdSchema,
|
|
67
|
+
encoding: z.enum(TOKENIZER_ENCODINGS),
|
|
68
|
+
inputPerMTok: z.number().finite().nonnegative(),
|
|
69
|
+
outputPerMTok: z.number().finite().nonnegative(),
|
|
70
|
+
cachedInputPerMTok: z.number().finite().nonnegative(),
|
|
71
|
+
cacheWritePerMTok: z.number().finite().nonnegative(),
|
|
72
|
+
efforts: z
|
|
73
|
+
.array(z.enum(LLM_EFFORT_LEVELS))
|
|
74
|
+
.refine((efforts) => new Set(efforts).size === efforts.length, "efforts must not repeat a level"),
|
|
75
|
+
thinkingMode: z.enum(THINKING_MODES),
|
|
76
|
+
sourceUrl: z
|
|
77
|
+
.string()
|
|
78
|
+
.url()
|
|
79
|
+
.refine((url) => url.startsWith("https://"), "sourceUrl must start with https://"),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
82
|
+
/** A resolved entry as the tools serve it: the merged fields plus whether this deployment can route to it right now. */
|
|
83
|
+
function view(entry, llm) {
|
|
84
|
+
return { ...entry, routable: llm.hasProvider(entry.provider) };
|
|
85
|
+
}
|
|
86
|
+
function audit(ctx, action, info) {
|
|
87
|
+
modelsLog.info({
|
|
88
|
+
event: `models.catalog.${action}`,
|
|
89
|
+
provider: info.provider,
|
|
90
|
+
...(info.providers && info.providers.length > 1 ? { providers: info.providers } : {}),
|
|
91
|
+
modelId: info.modelId,
|
|
92
|
+
sourceUrl: info.sourceUrl,
|
|
93
|
+
before: info.before,
|
|
94
|
+
after: info.after,
|
|
95
|
+
by: ctx.principal.id,
|
|
96
|
+
}, "model catalog changed");
|
|
97
|
+
}
|
|
98
|
+
/** Best-effort: logs and swallows a refresh failure rather than letting it fail (or un-audit) an already-committed write. Returns whether it actually ran and succeeded. */
|
|
99
|
+
async function refreshBestEffort(refresh, context) {
|
|
100
|
+
if (!refresh)
|
|
101
|
+
return false;
|
|
102
|
+
try {
|
|
103
|
+
await refresh();
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
modelsLog.warn({ event: "models.catalog.refresh_failed", ...context, err: err instanceof Error ? err.message : String(err) }, "model catalog refresh failed after a write; the write stands, but routing may lag until the next poll");
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `shipped` says whether `modelId` is a shipped model: if so, `provider` is
|
|
113
|
+
* necessarily its shipped provider (ownerOf), and no action — disabling
|
|
114
|
+
* or resetting the override, or anything else — ever lets a different
|
|
115
|
+
* provider claim it, so the message says that plainly rather than pointing
|
|
116
|
+
* at a remedy that doesn't exist. For a non-shipped id, `reset_model` is the
|
|
117
|
+
* only thing that frees it for another provider: `disable_model` keeps the
|
|
118
|
+
* row (and its provider claim) in place, it just flips `enabled`, so
|
|
119
|
+
* disabling never frees the id either, whether `enabled` is currently true
|
|
120
|
+
* or false.
|
|
121
|
+
*/
|
|
122
|
+
function conflictError(modelId, provider, enabled, shipped) {
|
|
123
|
+
if (shipped) {
|
|
124
|
+
return new McpError(409, `Model "${modelId}" is a shipped model: it always belongs to provider "${provider}" and can never be ` +
|
|
125
|
+
`served by another provider — disabling or resetting the override does not change that.`);
|
|
126
|
+
}
|
|
127
|
+
return enabled
|
|
128
|
+
? new McpError(409, `Model "${modelId}" is already served by provider "${provider}"; reset_model it first to free the id ` +
|
|
129
|
+
`for another provider (disable_model does not free it).`)
|
|
130
|
+
: new McpError(409, `Model "${modelId}" is reserved by a disabled entry for provider "${provider}"; reset_model it first.`);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The post-write ownership-race error: our own row for `inputProvider` was
|
|
134
|
+
* written, but a refresh right after showed `nowOwner` winning the merge
|
|
135
|
+
* instead (the first-claim-wins rule — see `ownerOf` in catalog.ts). Named
|
|
136
|
+
* after the thing that actually fixes it (reset_model, which clears every
|
|
137
|
+
* row for the id, `nowOwner`'s included) rather than telling the caller to
|
|
138
|
+
* "retry set_model", which would just hit the pre-write conflict check again
|
|
139
|
+
* (or, if the race repeats, loop). Exported so its exact wording can be unit
|
|
140
|
+
* tested directly — forcing the genuine two-process write race that triggers
|
|
141
|
+
* this through the public tool-call surface isn't practical: it requires a
|
|
142
|
+
* competing write to land in the narrow window between this handler's own
|
|
143
|
+
* pre-write ownership check and its own write, which a single-process test
|
|
144
|
+
* harness has no way to inject mid-call.
|
|
145
|
+
*/
|
|
146
|
+
export function raceLostError(modelId, inputProvider, nowOwner) {
|
|
147
|
+
return new McpError(409, `Model "${modelId}" was written for provider "${inputProvider}" but is not serving it: provider "${nowOwner}" ` +
|
|
148
|
+
`owns it in the merged catalog. reset_model removes every row for "${modelId}" (including "${nowOwner}"'s); ` +
|
|
149
|
+
`set_model can then claim it for "${inputProvider}".`);
|
|
150
|
+
}
|
|
151
|
+
const modelIdProperty = {
|
|
152
|
+
type: "string",
|
|
153
|
+
description: 'Exact string an Agent.model must equal, e.g. "claude-sonnet-5".',
|
|
154
|
+
};
|
|
155
|
+
const setModelProperties = {
|
|
156
|
+
provider: { type: "string", enum: [...MODEL_PROVIDERS], description: "Which adapter routes calls to this model." },
|
|
157
|
+
modelId: modelIdProperty,
|
|
158
|
+
encoding: {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: [...TOKENIZER_ENCODINGS],
|
|
161
|
+
description: "Tokenizer encoding used to pre-count tokens for budget enforcement before any call.",
|
|
162
|
+
},
|
|
163
|
+
inputPerMTok: {
|
|
164
|
+
type: "number",
|
|
165
|
+
minimum: 0,
|
|
166
|
+
description: "USD per million input tokens, the provider's published rate.",
|
|
167
|
+
},
|
|
168
|
+
outputPerMTok: {
|
|
169
|
+
type: "number",
|
|
170
|
+
minimum: 0,
|
|
171
|
+
description: "USD per million output tokens, the provider's published rate.",
|
|
172
|
+
},
|
|
173
|
+
cachedInputPerMTok: {
|
|
174
|
+
type: "number",
|
|
175
|
+
minimum: 0,
|
|
176
|
+
description: "USD per million cache-read input tokens. The provider's own cache-read rate, never derived from inputPerMTok.",
|
|
177
|
+
},
|
|
178
|
+
cacheWritePerMTok: {
|
|
179
|
+
type: "number",
|
|
180
|
+
minimum: 0,
|
|
181
|
+
description: "USD per million cache-write input tokens. The provider's own cache-write rate, never derived from inputPerMTok.",
|
|
182
|
+
},
|
|
183
|
+
efforts: {
|
|
184
|
+
type: "array",
|
|
185
|
+
items: { type: "string", enum: [...LLM_EFFORT_LEVELS] },
|
|
186
|
+
description: "Reasoning effort levels this model accepts, lowest to highest; empty = never send one. Claude Code coding runs may send only these levels, so include the model's default (usually high; medium on some models).",
|
|
187
|
+
},
|
|
188
|
+
thinkingMode: {
|
|
189
|
+
type: "string",
|
|
190
|
+
enum: [...THINKING_MODES],
|
|
191
|
+
description: '"adaptive" (effort-based), "manual" (fixed budget_tokens, no effort), or "none" (no thinking parameter).',
|
|
192
|
+
},
|
|
193
|
+
sourceUrl: {
|
|
194
|
+
type: "string",
|
|
195
|
+
description: "The provider's own pricing page for this exact model (https). Rates must be its published numbers, never derived.",
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
export function registerModelCatalogTools(mcp, deps = {}) {
|
|
199
|
+
mcp.registerTool({
|
|
200
|
+
name: "list_models",
|
|
201
|
+
scope: "agents:read",
|
|
202
|
+
description: "The merged model catalog (shipped models overlaid with this deployment's overrides): id, pricing, encoding, effort levels, and whether this deployment can route to it right now (routable).",
|
|
203
|
+
inputSchema: {
|
|
204
|
+
type: "object",
|
|
205
|
+
additionalProperties: false,
|
|
206
|
+
properties: {
|
|
207
|
+
includeDisabled: { type: "boolean", description: "Also return models an admin has disabled." },
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
handler: async (rawArgs, ctx) => {
|
|
211
|
+
const { includeDisabled } = parse(ListModelsSchema, "list_models arguments", rawArgs);
|
|
212
|
+
const catalog = currentModelCatalog();
|
|
213
|
+
const llm = ctx.providers.llm;
|
|
214
|
+
const result = {
|
|
215
|
+
models: catalog.entries().map((entry) => view(entry, llm)),
|
|
216
|
+
};
|
|
217
|
+
if (includeDisabled)
|
|
218
|
+
result.disabled = catalog.disabledEntries().map((entry) => view(entry, llm));
|
|
219
|
+
return textResult(result);
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
mcp.registerTool({
|
|
223
|
+
name: "get_model",
|
|
224
|
+
scope: "agents:read",
|
|
225
|
+
description: "One catalog entry in full, active or disabled. For an override of a shipped model, also returns the shipped entry it shadows.",
|
|
226
|
+
inputSchema: {
|
|
227
|
+
type: "object",
|
|
228
|
+
additionalProperties: false,
|
|
229
|
+
required: ["modelId"],
|
|
230
|
+
properties: { modelId: modelIdProperty },
|
|
231
|
+
},
|
|
232
|
+
handler: async (rawArgs, ctx) => {
|
|
233
|
+
const { modelId } = parse(ModelIdArgSchema, "get_model arguments", rawArgs);
|
|
234
|
+
const catalog = currentModelCatalog();
|
|
235
|
+
const entry = catalog.get(modelId) ?? catalog.disabledEntries().find((e) => e.modelId === modelId);
|
|
236
|
+
if (!entry) {
|
|
237
|
+
throw new McpError(404, `Model "${modelId}" is not in the catalog (neither active nor disabled). See list_models.`);
|
|
238
|
+
}
|
|
239
|
+
const llm = ctx.providers.llm;
|
|
240
|
+
const shipped = entry.origin === "override" ? catalog.shippedEntry(modelId) : undefined;
|
|
241
|
+
return textResult({ model: view(entry, llm), ...(shipped ? { shipped } : {}) });
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
mcp.registerTool({
|
|
245
|
+
name: "set_model",
|
|
246
|
+
scope: "models:admin",
|
|
247
|
+
description: "Model managers (models:admin): add or override a catalog entry. Every field is required — there is no partial update, so the whole entry is always literal and auditable. Refused (409) when the model id belongs to a different provider: a shipped id always belongs to its shipped provider and can never be reassigned; a non-shipped id already claimed by another provider (its row active or disabled) is freed only by reset_model on that id, never by disable_model. Zero rates come back as warnings, not errors.",
|
|
248
|
+
inputSchema: {
|
|
249
|
+
type: "object",
|
|
250
|
+
additionalProperties: false,
|
|
251
|
+
required: [
|
|
252
|
+
"provider",
|
|
253
|
+
"modelId",
|
|
254
|
+
"encoding",
|
|
255
|
+
"inputPerMTok",
|
|
256
|
+
"outputPerMTok",
|
|
257
|
+
"cachedInputPerMTok",
|
|
258
|
+
"cacheWritePerMTok",
|
|
259
|
+
"efforts",
|
|
260
|
+
"thinkingMode",
|
|
261
|
+
"sourceUrl",
|
|
262
|
+
],
|
|
263
|
+
properties: setModelProperties,
|
|
264
|
+
},
|
|
265
|
+
handler: async (rawArgs, ctx) => {
|
|
266
|
+
const input = parse(SetModelSchema, "set_model arguments", rawArgs);
|
|
267
|
+
const { sourceUrl, ...entry } = input;
|
|
268
|
+
// Ownership is checked against the database directly, not the process's
|
|
269
|
+
// (possibly stale, poll-interval-old) installed catalog: a row written
|
|
270
|
+
// by another process/replica must be caught even if this process
|
|
271
|
+
// hasn't refreshed since. The static shipped catalog is never stale,
|
|
272
|
+
// so it's safe to read from the in-memory catalog either way. The
|
|
273
|
+
// check is buildCatalog's own ownership function (ownerOf), not "any
|
|
274
|
+
// different-provider row blocks": for a shipped id, an orphaned
|
|
275
|
+
// other-provider row (dead in the merge no matter what) must not
|
|
276
|
+
// falsely block the true (shipped) owner, and must not be let through
|
|
277
|
+
// just because it happens to share its own provider with input.provider.
|
|
278
|
+
// Every raw row counts as a claim here, malformed ones included (unlike
|
|
279
|
+
// the merge, which never sees them): a malformed row still occupies the
|
|
280
|
+
// id, and reset_model is what clears it.
|
|
281
|
+
const existingRows = await ctx.db.modelCatalogEntry.findMany({ where: { modelId: input.modelId } });
|
|
282
|
+
const shippedEntry = currentModelCatalog().shippedEntry(input.modelId);
|
|
283
|
+
const owner = ownerOf(shippedEntry, existingRows);
|
|
284
|
+
if (owner && owner.provider !== input.provider) {
|
|
285
|
+
throw conflictError(input.modelId, owner.provider, owner.enabled, !!shippedEntry);
|
|
286
|
+
}
|
|
287
|
+
const ownRow = existingRows.find((row) => row.provider === input.provider);
|
|
288
|
+
const parsedOwnRow = ownRow ? rowFromRecord(ownRow) : null;
|
|
289
|
+
const before = parsedOwnRow
|
|
290
|
+
? entryOf(parsedOwnRow)
|
|
291
|
+
: shippedEntry && shippedEntry.provider === input.provider
|
|
292
|
+
? entryOf(shippedEntry)
|
|
293
|
+
: null;
|
|
294
|
+
const data = { ...entry, efforts: [...entry.efforts], enabled: true, sourceUrl, updatedBy: ctx.principal.id };
|
|
295
|
+
const row = await ctx.db.modelCatalogEntry.upsert({
|
|
296
|
+
where: { provider_modelId: { provider: input.provider, modelId: input.modelId } },
|
|
297
|
+
create: data,
|
|
298
|
+
update: data,
|
|
299
|
+
});
|
|
300
|
+
// Audited from the data we know was written — independent of whether
|
|
301
|
+
// the refresh below succeeds, so a transient refresh failure can
|
|
302
|
+
// never leave a committed write un-audited.
|
|
303
|
+
const after = entryOf(entry);
|
|
304
|
+
audit(ctx, "set", { provider: input.provider, modelId: input.modelId, sourceUrl, before, after });
|
|
305
|
+
const warnings = RATE_FIELDS.filter((field) => input[field] === 0).map((field) => `${field} is 0: confirm against ${sourceUrl}`);
|
|
306
|
+
const refreshed = await refreshBestEffort(deps.refresh, { action: "set", modelId: input.modelId });
|
|
307
|
+
// Two processes racing to claim the same id under different providers
|
|
308
|
+
// can both write (the unique key is (provider, modelId), not modelId
|
|
309
|
+
// alone); buildCatalog then silently picks one winner. If a refresh
|
|
310
|
+
// just told us the merge didn't pick us, our own row is dead on
|
|
311
|
+
// arrival — report an error rather than success.
|
|
312
|
+
if (refreshed) {
|
|
313
|
+
const nowOwner = currentModelCatalog().get(input.modelId)?.provider;
|
|
314
|
+
if (nowOwner && nowOwner !== input.provider) {
|
|
315
|
+
throw raceLostError(input.modelId, input.provider, nowOwner);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const llm = ctx.providers.llm;
|
|
319
|
+
const resolved = {
|
|
320
|
+
...entry,
|
|
321
|
+
origin: "override",
|
|
322
|
+
priceVersion: row.updatedAt instanceof Date ? row.updatedAt.toISOString() : new Date().toISOString(),
|
|
323
|
+
sourceUrl,
|
|
324
|
+
updatedBy: ctx.principal.id,
|
|
325
|
+
...(shippedEntry ? { shippedDiffers: !sameEntry(shippedEntry, entry) } : {}),
|
|
326
|
+
};
|
|
327
|
+
return textResult({ model: view(resolved, llm), warnings });
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
mcp.registerTool({
|
|
331
|
+
name: "disable_model",
|
|
332
|
+
scope: "models:admin",
|
|
333
|
+
description: "Model managers (models:admin): remove a model from routing without deleting its history. Keeps a disabled row under its own provider so no other provider can claim the id until reset_model clears it.",
|
|
334
|
+
inputSchema: {
|
|
335
|
+
type: "object",
|
|
336
|
+
additionalProperties: false,
|
|
337
|
+
required: ["modelId"],
|
|
338
|
+
properties: { modelId: modelIdProperty },
|
|
339
|
+
},
|
|
340
|
+
handler: async (rawArgs, ctx) => {
|
|
341
|
+
const { modelId } = parse(ModelIdArgSchema, "disable_model arguments", rawArgs);
|
|
342
|
+
const catalog = currentModelCatalog();
|
|
343
|
+
const active = catalog.get(modelId);
|
|
344
|
+
if (!active) {
|
|
345
|
+
throw new McpError(404, `No active model "${modelId}" to disable (it may already be disabled, or unknown). See list_models.`);
|
|
346
|
+
}
|
|
347
|
+
const before = entryOf(active);
|
|
348
|
+
const sourceUrl = active.sourceUrl ?? `shipped:${SHIPPED_CATALOG_VERSION}`;
|
|
349
|
+
const data = {
|
|
350
|
+
...before,
|
|
351
|
+
efforts: [...before.efforts],
|
|
352
|
+
enabled: false,
|
|
353
|
+
sourceUrl,
|
|
354
|
+
updatedBy: ctx.principal.id,
|
|
355
|
+
};
|
|
356
|
+
const row = await ctx.db.modelCatalogEntry.upsert({
|
|
357
|
+
where: { provider_modelId: { provider: active.provider, modelId } },
|
|
358
|
+
create: data,
|
|
359
|
+
update: data,
|
|
360
|
+
});
|
|
361
|
+
// Disabling never changes the core CatalogEntry fields, so "after" is
|
|
362
|
+
// "before" — audited from the write we just made, not a post-refresh
|
|
363
|
+
// re-read, same reasoning as set_model.
|
|
364
|
+
const after = before;
|
|
365
|
+
audit(ctx, "disable", { provider: active.provider, modelId, sourceUrl, before, after });
|
|
366
|
+
await refreshBestEffort(deps.refresh, { action: "disable", modelId });
|
|
367
|
+
const llm = ctx.providers.llm;
|
|
368
|
+
const shippedEntry = catalog.shippedEntry(modelId);
|
|
369
|
+
const resolved = {
|
|
370
|
+
...before,
|
|
371
|
+
origin: "override",
|
|
372
|
+
priceVersion: row.updatedAt instanceof Date ? row.updatedAt.toISOString() : new Date().toISOString(),
|
|
373
|
+
sourceUrl,
|
|
374
|
+
updatedBy: ctx.principal.id,
|
|
375
|
+
...(shippedEntry ? { shippedDiffers: !sameEntry(shippedEntry, before) } : {}),
|
|
376
|
+
};
|
|
377
|
+
return textResult({ disabled: view(resolved, llm) });
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
mcp.registerTool({
|
|
381
|
+
name: "reset_model",
|
|
382
|
+
scope: "models:admin",
|
|
383
|
+
description: "Model managers (models:admin): remove every catalog row for a model id, reverting to the shipped entry (if any) or removing it entirely. 404 if there is no row to remove (an unmodified shipped model, or an unknown id).",
|
|
384
|
+
inputSchema: {
|
|
385
|
+
type: "object",
|
|
386
|
+
additionalProperties: false,
|
|
387
|
+
required: ["modelId"],
|
|
388
|
+
properties: { modelId: modelIdProperty },
|
|
389
|
+
},
|
|
390
|
+
handler: async (rawArgs, ctx) => {
|
|
391
|
+
const { modelId } = parse(ModelIdArgSchema, "reset_model arguments", rawArgs);
|
|
392
|
+
// The 404 decision and the audited `providers` list are both based on
|
|
393
|
+
// the RAW rows, not rows that parse cleanly through rowFromRecord: a
|
|
394
|
+
// row can be malformed (fails parsing) yet still exist and still
|
|
395
|
+
// occupy the id. Deciding "nothing to reset" or omitting a provider
|
|
396
|
+
// from the audit based on parse success would delete a malformed row
|
|
397
|
+
// silently and leave the id permanently stuck — set_model's
|
|
398
|
+
// DB-sourced conflict check would keep seeing it (via ownerOf)
|
|
399
|
+
// and refusing every provider forever, with no tool able to clear it.
|
|
400
|
+
const rawRows = await ctx.db.modelCatalogEntry.findMany({ where: { modelId } });
|
|
401
|
+
if (rawRows.length === 0) {
|
|
402
|
+
throw new McpError(404, `No catalog row for "${modelId}" to reset (it is either unmodified shipped, or unknown).`);
|
|
403
|
+
}
|
|
404
|
+
const providers = [...new Set(rawRows.map((row) => String(row.provider)))];
|
|
405
|
+
const parsedRows = rawRows.map((row) => rowFromRecord(row)).filter((row) => row !== null);
|
|
406
|
+
const before = parsedRows.length > 0 ? entryOf(parsedRows[0]) : null;
|
|
407
|
+
const sourceUrl = parsedRows[0]?.sourceUrl;
|
|
408
|
+
await ctx.db.modelCatalogEntry.deleteMany({ where: { modelId } });
|
|
409
|
+
// The shipped entry is static (compiled-in), never stale, so "after"
|
|
410
|
+
// and the response's "now" can both be built from it directly,
|
|
411
|
+
// without depending on the refresh below at all.
|
|
412
|
+
const shippedEntry = currentModelCatalog().shippedEntry(modelId);
|
|
413
|
+
const after = shippedEntry ? entryOf(shippedEntry) : null;
|
|
414
|
+
audit(ctx, "reset", { provider: providers[0], providers, modelId, sourceUrl, before, after });
|
|
415
|
+
await refreshBestEffort(deps.refresh, { action: "reset", modelId });
|
|
416
|
+
const llm = ctx.providers.llm;
|
|
417
|
+
const now = shippedEntry
|
|
418
|
+
? view({ ...shippedEntry, origin: "shipped", priceVersion: `shipped:${SHIPPED_CATALOG_VERSION}` }, llm)
|
|
419
|
+
: null;
|
|
420
|
+
return textResult({ reset: modelId, now });
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentRepository CRUD — which repositories on which code-review host a
|
|
3
|
+
* native agent may act on, and which host events trigger it. Linking needs
|
|
4
|
+
* more than owning the agent: the owner's own linked GitHub account must have
|
|
5
|
+
* the link's access on the repository (write for a write link, read for a
|
|
6
|
+
* read link), or a wardby admin must approve it explicitly (adminOverride).
|
|
7
|
+
* The authorization is stamped on the link and re-checked whenever the link
|
|
8
|
+
* is used (core/repo-access.ts). A repository is an owner binding (resource-
|
|
9
|
+
* sharing grants spec §3.4.3): link/unlink are the agent owner's alone (or
|
|
10
|
+
* an admin's explicit approval), whatever grants others hold on the agent,
|
|
11
|
+
* and owner-less agents can't be linked.
|
|
12
|
+
* See docs/private/2026-09-26-repo-access-authorization-spec-and-plan.md.
|
|
13
|
+
*/
|
|
14
|
+
import { Prisma } from "#prisma";
|
|
15
|
+
import { normalizeGitHubRepository } from "../../coding/protocol.js";
|
|
16
|
+
import { requireAgentAccess, requireBindingOwner } from "../auth/access.js";
|
|
17
|
+
import { authorizeRepositoryForSet } from "../auth/repo-authorization.js";
|
|
18
|
+
import { requireScope } from "../auth/resource-server.js";
|
|
19
|
+
import { McpError } from "../errors.js";
|
|
20
|
+
import { textResult } from "./text-result.js";
|
|
21
|
+
const PROVIDERS = ["github"];
|
|
22
|
+
const TRIGGERS = ["pull_request", "mention", "push"];
|
|
23
|
+
const CHECK_NAME = /^[A-Za-z0-9][A-Za-z0-9 ._/()-]{0,99}$/;
|
|
24
|
+
function normalizeRepository(provider, repository) {
|
|
25
|
+
try {
|
|
26
|
+
if (provider === "github")
|
|
27
|
+
return normalizeGitHubRepository(repository);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// fall through
|
|
31
|
+
}
|
|
32
|
+
throw new McpError(400, `invalid repository "${repository}" for provider ${provider}`);
|
|
33
|
+
}
|
|
34
|
+
async function assertNoConflicts(tx, args) {
|
|
35
|
+
if (args.triggers.length === 0 && args.checkName === null)
|
|
36
|
+
return;
|
|
37
|
+
const others = await tx.agentRepository.findMany({
|
|
38
|
+
where: { provider: args.provider, repository: args.repository, NOT: { agentId: args.agentId } },
|
|
39
|
+
});
|
|
40
|
+
if (args.triggers.includes("mention") && others.some((o) => o.triggers.includes("mention"))) {
|
|
41
|
+
throw new McpError(409, `Another agent already handles @-mentions on ${args.repository}.`);
|
|
42
|
+
}
|
|
43
|
+
// Against every other link, whatever its triggers: a check name identifies
|
|
44
|
+
// one agent's verdict on the repository (also a unique index).
|
|
45
|
+
if (args.checkName !== null && others.some((o) => o.checkName === args.checkName)) {
|
|
46
|
+
throw checkNameTaken(args.checkName, args.repository);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function checkNameTaken(checkName, repository) {
|
|
50
|
+
return new McpError(409, `Another agent already uses check name "${checkName}" on ${repository}.`);
|
|
51
|
+
}
|
|
52
|
+
export function registerRepositoryTools(mcp) {
|
|
53
|
+
mcp.registerTool({
|
|
54
|
+
name: "link_repository",
|
|
55
|
+
scope: "agents:write",
|
|
56
|
+
description: "Links a native agent you own to a repository on a code-review host, with its access, event triggers, and checkName. " +
|
|
57
|
+
"Triggers: pull_request (review each PR push), mention (answer @mentions), push (start on merges to the default branch). " +
|
|
58
|
+
"Your linked GitHub account (link_host_account) must have write access to the repository for a write link, or read for a " +
|
|
59
|
+
"read link; a wardby admin may instead approve it with adminOverride. checkName is only allowed (and required) with the " +
|
|
60
|
+
"pull_request trigger, and is unique per repository. Re-linking an already-linked repository replaces its access, " +
|
|
61
|
+
"triggers, and checkName (an omitted field is cleared, not kept) and re-checks access — always send the full desired state.",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
properties: {
|
|
66
|
+
agentId: { type: "string" },
|
|
67
|
+
provider: { type: "string", enum: [...PROVIDERS] },
|
|
68
|
+
repository: { type: "string", minLength: 1, maxLength: 300 },
|
|
69
|
+
access: { type: "string", enum: ["read", "write"] },
|
|
70
|
+
triggers: { type: "array", items: { type: "string", enum: [...TRIGGERS] }, uniqueItems: true },
|
|
71
|
+
checkName: { type: "string", minLength: 1, maxLength: 100 },
|
|
72
|
+
adminOverride: {
|
|
73
|
+
type: "boolean",
|
|
74
|
+
description: "Admins only (agents:admin with the admin role): approve this link without checking GitHub access, recorded as an admin approval. Allowed on any agent that has an owner, not only the admin's own.",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
required: ["agentId", "repository", "access"],
|
|
78
|
+
},
|
|
79
|
+
handler: async (args, ctx) => {
|
|
80
|
+
// An admin approving a repository explicitly may do it on any agent
|
|
81
|
+
// (the role already allows reassigning any agent with make_owner);
|
|
82
|
+
// everyone else, admins included, links only agents they own.
|
|
83
|
+
let agent;
|
|
84
|
+
if (args.adminOverride === true) {
|
|
85
|
+
requireScope(ctx, ctx.canonicalUri, "agents:admin");
|
|
86
|
+
agent = await ctx.db.agent.findUnique({ where: { id: args.agentId } });
|
|
87
|
+
if (!agent)
|
|
88
|
+
throw new McpError(404, `Agent "${args.agentId}" not found.`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
agent = (await requireAgentAccess(ctx, args.agentId, "read")).agent;
|
|
92
|
+
requireBindingOwner(ctx, agent);
|
|
93
|
+
}
|
|
94
|
+
if (agent.kind !== "native") {
|
|
95
|
+
throw new McpError(400, "Repository links are for native agents only; coding agents use codingProfile.repository.");
|
|
96
|
+
}
|
|
97
|
+
const provider = args.provider ?? "github";
|
|
98
|
+
const repository = normalizeRepository(provider, args.repository);
|
|
99
|
+
const triggers = [...new Set(args.triggers ?? [])];
|
|
100
|
+
if (triggers.length > 0 && args.access !== "write")
|
|
101
|
+
throw new McpError(400, "Event triggers need write access.");
|
|
102
|
+
const checkName = args.checkName ?? null;
|
|
103
|
+
if (triggers.includes("pull_request") && !checkName) {
|
|
104
|
+
throw new McpError(400, "checkName is required with the pull_request trigger.");
|
|
105
|
+
}
|
|
106
|
+
if (checkName !== null && !triggers.includes("pull_request")) {
|
|
107
|
+
throw new McpError(400, "checkName needs the pull_request trigger (a check is only published for a dispatched PR).");
|
|
108
|
+
}
|
|
109
|
+
if (checkName !== null && !CHECK_NAME.test(checkName))
|
|
110
|
+
throw new McpError(400, "invalid checkName");
|
|
111
|
+
// The host call happens before, and outside, the serializable transaction.
|
|
112
|
+
const authorization = await authorizeRepositoryForSet(ctx, {
|
|
113
|
+
ownerId: agent.ownerId,
|
|
114
|
+
provider,
|
|
115
|
+
repository,
|
|
116
|
+
kind: args.access,
|
|
117
|
+
adminOverride: args.adminOverride === true,
|
|
118
|
+
});
|
|
119
|
+
let link;
|
|
120
|
+
try {
|
|
121
|
+
link = await ctx.db.$transaction(async (tx) => {
|
|
122
|
+
await assertNoConflicts(tx, { agentId: args.agentId, provider, repository, triggers, checkName });
|
|
123
|
+
const fields = { access: args.access, triggers, checkName, ...authorization };
|
|
124
|
+
return tx.agentRepository.upsert({
|
|
125
|
+
where: { agentId_provider_repository: { agentId: args.agentId, provider, repository } },
|
|
126
|
+
create: { agentId: args.agentId, provider, repository, ...fields },
|
|
127
|
+
update: fields,
|
|
128
|
+
});
|
|
129
|
+
}, { isolationLevel: "Serializable" });
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (checkName !== null && err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2002") {
|
|
133
|
+
throw checkNameTaken(checkName, repository);
|
|
134
|
+
}
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
return textResult({ linked: true, link });
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
mcp.registerTool({
|
|
141
|
+
name: "unlink_repository",
|
|
142
|
+
scope: "agents:write",
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: "object",
|
|
145
|
+
additionalProperties: false,
|
|
146
|
+
properties: {
|
|
147
|
+
agentId: { type: "string" },
|
|
148
|
+
provider: { type: "string", enum: [...PROVIDERS] },
|
|
149
|
+
repository: { type: "string", minLength: 1, maxLength: 300 },
|
|
150
|
+
},
|
|
151
|
+
required: ["agentId", "repository"],
|
|
152
|
+
},
|
|
153
|
+
handler: async (args, ctx) => {
|
|
154
|
+
const { agent } = await requireAgentAccess(ctx, args.agentId, "read");
|
|
155
|
+
requireBindingOwner(ctx, agent);
|
|
156
|
+
const provider = args.provider ?? "github";
|
|
157
|
+
const repository = normalizeRepository(provider, args.repository);
|
|
158
|
+
const { count } = await ctx.db.agentRepository.deleteMany({
|
|
159
|
+
where: { agentId: args.agentId, provider, repository },
|
|
160
|
+
});
|
|
161
|
+
return textResult({ unlinked: count > 0 });
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
mcp.registerTool({
|
|
165
|
+
name: "list_repositories",
|
|
166
|
+
scope: "agents:read",
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: "object",
|
|
169
|
+
additionalProperties: false,
|
|
170
|
+
properties: { agentId: { type: "string" } },
|
|
171
|
+
required: ["agentId"],
|
|
172
|
+
},
|
|
173
|
+
handler: async (args, ctx) => {
|
|
174
|
+
await requireAgentAccess(ctx, args.agentId, "read");
|
|
175
|
+
const links = await ctx.db.agentRepository.findMany({
|
|
176
|
+
where: { agentId: args.agentId },
|
|
177
|
+
orderBy: { createdAt: "asc" },
|
|
178
|
+
});
|
|
179
|
+
return textResult({ repositories: links });
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
}
|
package/dist/mcp/tools/runs.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import type { WardbyMcpServer } from "../server.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run visibility (resource-sharing grants spec §3.5, A6): a run's output is
|
|
4
|
+
* the triggerer's and the agent owner's, never every reader's. The owner
|
|
5
|
+
* (and the stdio operator) sees every run; anyone else only runs with
|
|
6
|
+
* Run.triggeredById equal to themselves.
|
|
7
|
+
*/
|
|
2
8
|
export declare function registerRunTools(mcp: WardbyMcpServer): void;
|