@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
|
@@ -9,7 +9,7 @@ function extractCodingTask(req) {
|
|
|
9
9
|
const parsed = CodingTaskOverrideSchema.safeParse(req.body.task);
|
|
10
10
|
return parsed.success ? parsed.data : undefined;
|
|
11
11
|
}
|
|
12
|
-
export async function handleWebhookIngress(webhookId, req, db, executor) {
|
|
12
|
+
export async function handleWebhookIngress(webhookId, req, db, executor, issueTrackers) {
|
|
13
13
|
const secret = extractSecret(req);
|
|
14
14
|
if (!secret) {
|
|
15
15
|
return { status: 401, body: { error: "invalid_secret", error_description: "No webhook secret presented." } };
|
|
@@ -18,11 +18,18 @@ export async function handleWebhookIngress(webhookId, req, db, executor) {
|
|
|
18
18
|
if (req.body.task !== undefined && codingTask === undefined) {
|
|
19
19
|
return { status: 400, body: { error: "invalid_task" } };
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
// `wardbyIssue`, not `issue`: forwarded third-party payloads (GitHub, Jira)
|
|
22
|
+
// carry their own top-level `issue` object, which is not ours to read.
|
|
23
|
+
const result = await resolveWebhookRun(webhookId, secret, db, executor, codingTask, {
|
|
24
|
+
issue: req.body.wardbyIssue,
|
|
25
|
+
issueTrackers,
|
|
26
|
+
});
|
|
22
27
|
if (result.ok) {
|
|
23
28
|
return { status: 202, body: { runId: result.runId } };
|
|
24
29
|
}
|
|
25
30
|
switch (result.reason) {
|
|
31
|
+
case "invalid_issue":
|
|
32
|
+
return { status: 400, body: { error: "invalid_issue", error_description: result.message } };
|
|
26
33
|
case "not_found":
|
|
27
34
|
return { status: 404, body: { error: "not_found" } };
|
|
28
35
|
case "invalid_secret":
|
|
@@ -13,7 +13,25 @@ export interface DelegatingAuthConfig {
|
|
|
13
13
|
issuer?: string;
|
|
14
14
|
audience?: string;
|
|
15
15
|
jwksUri?: string;
|
|
16
|
+
/**
|
|
17
|
+
* AUTH_ROLE_CLAIM: the access-token claim carrying the IdP's roles/groups —
|
|
18
|
+
* an exact top-level claim name first (e.g. Auth0's namespaced
|
|
19
|
+
* `https://wardby.example/roles`, Okta `groups`, FusionAuth `roles`), else
|
|
20
|
+
* a dotted path into nested objects (Keycloak `realm_access.roles`).
|
|
21
|
+
*/
|
|
22
|
+
roleClaim?: string;
|
|
23
|
+
/**
|
|
24
|
+
* AUTH_ROLE_MAP: comma-separated `idpValue=wardbyRole` pairs, e.g.
|
|
25
|
+
* `wardby-admin=admin,wardby-packages=package-approver,wardby-services=service-manager`.
|
|
26
|
+
*/
|
|
27
|
+
roleMap?: string;
|
|
16
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses AUTH_ROLE_MAP. Whitespace around entries and around `=` is ignored;
|
|
31
|
+
* an unknown wardby role, or a malformed or empty entry, is a startup error.
|
|
32
|
+
* The LAST `=` splits an entry (wardby role names never contain one).
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseRoleMap(value: string): Map<string, string[]>;
|
|
17
35
|
/**
|
|
18
36
|
* Every spelling of the configured audience a token may legitimately carry.
|
|
19
37
|
*
|
|
@@ -35,6 +53,7 @@ export declare class DelegatingAuthProvider implements AuthProvider {
|
|
|
35
53
|
private readonly config;
|
|
36
54
|
private readonly audiences;
|
|
37
55
|
private readonly jwks;
|
|
56
|
+
private readonly roleMap?;
|
|
38
57
|
constructor(config: DelegatingAuthConfig, jwks?: JWTVerifyGetKey);
|
|
39
58
|
verifyBearer(token: string): Promise<VerifiedToken>;
|
|
40
59
|
profile(idToken: string): Promise<AuthProfile>;
|
|
@@ -10,6 +10,63 @@
|
|
|
10
10
|
import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from "jose";
|
|
11
11
|
import { AudienceError, NotSupportedError } from "./types.js";
|
|
12
12
|
import { requireSubject } from "./subject.js";
|
|
13
|
+
import { ROLE_NAMES, isRoleName } from "../../mcp/auth/resource-server.js";
|
|
14
|
+
/**
|
|
15
|
+
* Parses AUTH_ROLE_MAP. Whitespace around entries and around `=` is ignored;
|
|
16
|
+
* an unknown wardby role, or a malformed or empty entry, is a startup error.
|
|
17
|
+
* The LAST `=` splits an entry (wardby role names never contain one).
|
|
18
|
+
*/
|
|
19
|
+
export function parseRoleMap(value) {
|
|
20
|
+
const map = new Map();
|
|
21
|
+
const entries = value.split(",").map((e) => e.trim());
|
|
22
|
+
if (entries.every((e) => !e))
|
|
23
|
+
throw new Error("AUTH_ROLE_MAP is empty.");
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry)
|
|
26
|
+
continue;
|
|
27
|
+
const at = entry.lastIndexOf("=");
|
|
28
|
+
const idpValue = at > 0 ? entry.slice(0, at).trim() : "";
|
|
29
|
+
const role = at > 0 ? entry.slice(at + 1).trim() : "";
|
|
30
|
+
if (!idpValue || !role)
|
|
31
|
+
throw new Error(`AUTH_ROLE_MAP entry "${entry}" must look like idpValue=wardbyRole.`);
|
|
32
|
+
if (!isRoleName(role))
|
|
33
|
+
throw new Error(`AUTH_ROLE_MAP maps "${idpValue}" to unknown role "${role}" (known: ${ROLE_NAMES.join(", ")}).`);
|
|
34
|
+
map.set(idpValue, [...new Set([...(map.get(idpValue) ?? []), role])]);
|
|
35
|
+
}
|
|
36
|
+
return map;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolves `claim` in a verified payload: an exact top-level name wins (claim
|
|
40
|
+
* names may themselves contain dots and slashes), otherwise a dotted path.
|
|
41
|
+
*/
|
|
42
|
+
function resolveClaim(payload, claim) {
|
|
43
|
+
if (Object.prototype.hasOwnProperty.call(payload, claim))
|
|
44
|
+
return payload[claim];
|
|
45
|
+
if (!claim.includes("."))
|
|
46
|
+
return undefined;
|
|
47
|
+
let value = payload;
|
|
48
|
+
for (const part of claim.split(".")) {
|
|
49
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
50
|
+
return undefined;
|
|
51
|
+
if (!Object.prototype.hasOwnProperty.call(value, part))
|
|
52
|
+
return undefined;
|
|
53
|
+
value = value[part];
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Maps a resolved claim (a string, or an array of strings) through the role
|
|
59
|
+
* map; unmapped values are ignored, and any other shape yields no roles.
|
|
60
|
+
*/
|
|
61
|
+
function rolesFromClaim(value, map) {
|
|
62
|
+
const values = typeof value === "string" ? [value] : Array.isArray(value) ? value : [];
|
|
63
|
+
const roles = new Set();
|
|
64
|
+
for (const v of values)
|
|
65
|
+
if (typeof v === "string")
|
|
66
|
+
for (const r of map.get(v) ?? [])
|
|
67
|
+
roles.add(r);
|
|
68
|
+
return [...roles];
|
|
69
|
+
}
|
|
13
70
|
/**
|
|
14
71
|
* Every spelling of the configured audience a token may legitimately carry.
|
|
15
72
|
*
|
|
@@ -53,9 +110,16 @@ export class DelegatingAuthProvider {
|
|
|
53
110
|
config;
|
|
54
111
|
audiences;
|
|
55
112
|
jwks;
|
|
113
|
+
roleMap;
|
|
56
114
|
constructor(config, jwks) {
|
|
57
115
|
if (!config.issuer || !config.audience)
|
|
58
116
|
throw new Error("AUTH_ISSUER and AUTH_AUDIENCE are required.");
|
|
117
|
+
// Half a configuration would silently give everyone no roles while
|
|
118
|
+
// looking configured — refuse to start instead.
|
|
119
|
+
if ((config.roleClaim !== undefined || config.roleMap !== undefined) && (!config.roleClaim || !config.roleMap))
|
|
120
|
+
throw new Error("AUTH_ROLE_CLAIM and AUTH_ROLE_MAP must be set together (or both left unset).");
|
|
121
|
+
if (config.roleMap)
|
|
122
|
+
this.roleMap = parseRoleMap(config.roleMap);
|
|
59
123
|
this.config = config;
|
|
60
124
|
this.audiences = audienceCandidates(config.audience);
|
|
61
125
|
if (jwks) {
|
|
@@ -80,6 +144,13 @@ export class DelegatingAuthProvider {
|
|
|
80
144
|
email: typeof payload.email === "string" ? payload.email : undefined,
|
|
81
145
|
roles: Array.isArray(payload.roles) ? payload.roles.map(String) : [],
|
|
82
146
|
scopes: scopesFromClaim(payload.scope ?? payload.scp),
|
|
147
|
+
// Read from the bearer token validated above for this issuer and
|
|
148
|
+
// audience (signature, expiry too); the IdP should mint that audience
|
|
149
|
+
// only into access tokens. Unconfigured, every caller has no roles
|
|
150
|
+
// and privileged operations are refused.
|
|
151
|
+
wardbyRoles: this.config.roleClaim && this.roleMap
|
|
152
|
+
? rolesFromClaim(resolveClaim(payload, this.config.roleClaim), this.roleMap)
|
|
153
|
+
: [],
|
|
83
154
|
};
|
|
84
155
|
}
|
|
85
156
|
catch (err) {
|
|
@@ -8,4 +8,6 @@ import type { AuthProviderKind, AuthConfig } from "../../config/providers.js";
|
|
|
8
8
|
import type { AuthProvider } from "./types.js";
|
|
9
9
|
export { DelegatingAuthProvider } from "./delegating.js";
|
|
10
10
|
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
11
|
+
/** Configuration that is valid but almost certainly not what the operator meant. */
|
|
12
|
+
export declare function authConfigWarnings(kind: AuthProviderKind, config: AuthConfig): string[];
|
|
11
13
|
export declare function buildAuthProvider(kind: AuthProviderKind, config: AuthConfig, db: PrismaClient): AuthProvider;
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { DelegatingAuthProvider } from "./delegating.js";
|
|
2
2
|
import { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
3
|
+
import { logger } from "../../core/logger.js";
|
|
3
4
|
export { DelegatingAuthProvider } from "./delegating.js";
|
|
4
5
|
export { SelfHostedAuthProvider } from "./self-hosted.js";
|
|
6
|
+
/** Configuration that is valid but almost certainly not what the operator meant. */
|
|
7
|
+
export function authConfigWarnings(kind, config) {
|
|
8
|
+
const warnings = [];
|
|
9
|
+
if (kind === "self-hosted" && (config.roleClaim || config.roleMap))
|
|
10
|
+
warnings.push("AUTH_ROLE_CLAIM / AUTH_ROLE_MAP are set but ignored with AUTH_PROVIDER=self-hosted: self-hosted roles " +
|
|
11
|
+
"come from the database (`wardby auth user grant --subject <s> --role <role>`).");
|
|
12
|
+
return warnings;
|
|
13
|
+
}
|
|
5
14
|
export function buildAuthProvider(kind, config, db) {
|
|
15
|
+
for (const warning of authConfigWarnings(kind, config))
|
|
16
|
+
logger.warn({ module: "auth" }, warning);
|
|
6
17
|
if (kind === "self-hosted") {
|
|
7
18
|
if (!config.audience || !config.signingKey || !config.credentialHashKey) {
|
|
8
19
|
throw new Error("AUTH_AUDIENCE, AUTH_SIGNING_KEY, and AUTH_CREDENTIAL_HASH_KEY are required.");
|
|
@@ -4,6 +4,13 @@ import { Credentials } from "../../mcp/auth/self-hosted/credentials.js";
|
|
|
4
4
|
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
5
5
|
import type { AuthorizeParams, RegisterClientParams, SelfHostedAuthConfig, TokenParams, TokenResult } from "./authorization-server.js";
|
|
6
6
|
export type { AuthorizeParams, RegisterClientParams, SelfHostedAuthConfig, TokenParams, TokenResult, } from "./authorization-server.js";
|
|
7
|
+
/**
|
|
8
|
+
* Whether `requested` is one of a client's registered redirect URIs. A native
|
|
9
|
+
* app's loopback redirect may differ from its registration only in port: it
|
|
10
|
+
* listens on whatever port the OS hands it (RFC 8252 §7.3). Everything else —
|
|
11
|
+
* scheme, host, path, query — must match exactly, with no userinfo or fragment.
|
|
12
|
+
*/
|
|
13
|
+
export declare function redirectMatches(registered: readonly string[], requested: string): boolean;
|
|
7
14
|
export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
8
15
|
readonly db: PrismaClient;
|
|
9
16
|
readonly credentials: Credentials;
|
|
@@ -39,18 +46,19 @@ export declare class SelfHostedAuthProvider implements AuthProvider {
|
|
|
39
46
|
clientId: string;
|
|
40
47
|
};
|
|
41
48
|
} & {
|
|
42
|
-
id: string;
|
|
43
49
|
createdAt: Date;
|
|
50
|
+
id: string;
|
|
44
51
|
state: string | null;
|
|
52
|
+
clientId: string;
|
|
45
53
|
expiresAt: Date;
|
|
46
54
|
resource: string;
|
|
47
|
-
clientId: string;
|
|
48
55
|
consumedAt: Date | null;
|
|
49
56
|
redirectUri: string;
|
|
50
57
|
codeChallenge: string;
|
|
51
58
|
requestedScope: string;
|
|
52
59
|
};
|
|
53
60
|
challenge: string;
|
|
61
|
+
scopes: string[];
|
|
54
62
|
}>;
|
|
55
63
|
consent(sessionToken: string, interactionId: string, challenge: string, approve: boolean): Promise<string>;
|
|
56
64
|
handleToken(params: TokenParams): Promise<TokenResult>;
|
|
@@ -3,17 +3,53 @@ import { SignJWT, jwtVerify } from "jose";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { NotSupportedError } from "./types.js";
|
|
5
5
|
import { requireSubject } from "./subject.js";
|
|
6
|
-
import { SCOPES_SUPPORTED } from "../../mcp/auth/resource-server.js";
|
|
6
|
+
import { SCOPES_SUPPORTED, limitScope } from "../../mcp/auth/resource-server.js";
|
|
7
7
|
import { canonicalUrl } from "../../mcp/transport/http-limits.js";
|
|
8
8
|
import { Credentials, DAY, decodeKey, lockUser } from "../../mcp/auth/self-hosted/credentials.js";
|
|
9
9
|
import { Sessions } from "../../mcp/auth/self-hosted/session.js";
|
|
10
|
+
const LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
|
|
11
|
+
/**
|
|
12
|
+
* Whether `requested` is one of a client's registered redirect URIs. A native
|
|
13
|
+
* app's loopback redirect may differ from its registration only in port: it
|
|
14
|
+
* listens on whatever port the OS hands it (RFC 8252 §7.3). Everything else —
|
|
15
|
+
* scheme, host, path, query — must match exactly, with no userinfo or fragment.
|
|
16
|
+
*/
|
|
17
|
+
export function redirectMatches(registered, requested) {
|
|
18
|
+
if (registered.includes(requested))
|
|
19
|
+
return true;
|
|
20
|
+
let want;
|
|
21
|
+
try {
|
|
22
|
+
want = new URL(requested);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (want.protocol !== "http:" || !LOOPBACK_HOSTS.includes(want.hostname))
|
|
28
|
+
return false;
|
|
29
|
+
return registered.some((value) => {
|
|
30
|
+
try {
|
|
31
|
+
const have = new URL(value);
|
|
32
|
+
return (have.protocol === "http:" &&
|
|
33
|
+
have.hostname === want.hostname &&
|
|
34
|
+
have.pathname === want.pathname &&
|
|
35
|
+
have.search === want.search &&
|
|
36
|
+
!want.username &&
|
|
37
|
+
!want.password &&
|
|
38
|
+
!requested.includes("#") // URL.hash is "" for a bare "#"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
10
46
|
function validRedirect(value) {
|
|
11
47
|
try {
|
|
12
48
|
const u = new URL(value);
|
|
13
49
|
return (!value.includes("#") &&
|
|
14
50
|
!u.username &&
|
|
15
51
|
!u.password &&
|
|
16
|
-
(u.protocol === "https:" || (u.protocol === "http:" &&
|
|
52
|
+
(u.protocol === "https:" || (u.protocol === "http:" && LOOPBACK_HOSTS.includes(u.hostname))));
|
|
17
53
|
}
|
|
18
54
|
catch {
|
|
19
55
|
return false;
|
|
@@ -104,9 +140,10 @@ export class SelfHostedAuthProvider {
|
|
|
104
140
|
throw new Error("Invalid resource.");
|
|
105
141
|
const client = await this.db.oAuthClient.findUnique({ where: { clientId: p.clientId } });
|
|
106
142
|
const metadata = client?.metadata;
|
|
107
|
-
if (!metadata?.redirect_uris
|
|
143
|
+
if (!redirectMatches(metadata?.redirect_uris ?? [], p.redirectUri) ||
|
|
144
|
+
!metadata?.grant_types?.includes("authorization_code"))
|
|
108
145
|
throw new Error("Invalid client or redirect.");
|
|
109
|
-
const scope =
|
|
146
|
+
const scope = limitScope(p.scope, SCOPES_SUPPORTED);
|
|
110
147
|
const request = await this.db.oAuthAuthorizationRequest.create({
|
|
111
148
|
data: {
|
|
112
149
|
clientId: p.clientId,
|
|
@@ -129,7 +166,10 @@ export class SelfHostedAuthProvider {
|
|
|
129
166
|
if (!interaction || interaction.consumedAt || interaction.expiresAt.getTime() <= Date.now())
|
|
130
167
|
throw new Error("Invalid interaction.");
|
|
131
168
|
const challenge = await this.sessions.challenge("consent", session.sessionId, interactionId);
|
|
132
|
-
|
|
169
|
+
// Exactly what approving issues: the stored (supported-only) request.
|
|
170
|
+
// It's fixed when the interaction is created, so what the page shows
|
|
171
|
+
// can't drift from what consent() puts on the code.
|
|
172
|
+
return { interaction, challenge, scopes: interaction.requestedScope.split(" ").filter(Boolean) };
|
|
133
173
|
}
|
|
134
174
|
async consent(sessionToken, interactionId, challenge, approve) {
|
|
135
175
|
const first = await this.sessions.get(sessionToken);
|
|
@@ -339,7 +379,16 @@ export class SelfHostedAuthProvider {
|
|
|
339
379
|
family.clientId !== payload.client_id ||
|
|
340
380
|
payload.scope !== family.scope)
|
|
341
381
|
throw new Error("Invalid token.");
|
|
342
|
-
|
|
382
|
+
// Roles are read from the database on every request (no caching), so a
|
|
383
|
+
// grant or revocation applies to live tokens immediately. Scopes stay
|
|
384
|
+
// exactly what the user consented to; roles decide whether the
|
|
385
|
+
// privileged ones are honoured (resource-server.ts requireScope).
|
|
386
|
+
return {
|
|
387
|
+
subject,
|
|
388
|
+
scopes: family.scope.split(/\s+/).filter(Boolean),
|
|
389
|
+
roles: [],
|
|
390
|
+
wardbyRoles: family.user.roles ?? [],
|
|
391
|
+
};
|
|
343
392
|
}
|
|
344
393
|
async cleanup() {
|
|
345
394
|
const now = new Date();
|
|
@@ -32,6 +32,12 @@ export interface VerifiedToken {
|
|
|
32
32
|
scopes: string[];
|
|
33
33
|
email?: string;
|
|
34
34
|
roles?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* wardby roles (not the IdP's raw `roles`), decided by the provider at
|
|
37
|
+
* verification time: self-hosted reads AuthUser.roles live; delegating
|
|
38
|
+
* maps the configured signed claim through AUTH_ROLE_MAP. Absent = none.
|
|
39
|
+
*/
|
|
40
|
+
wardbyRoles?: string[];
|
|
35
41
|
}
|
|
36
42
|
export interface AuthTokens {
|
|
37
43
|
idToken: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CreateProxySessionInput, type ProxyLedger, type ProxyRequest, type ProxySession, type ProxyUsage, type ReserveProxyRequestInput, type ReserveProxyRequestResult } from "./types.js";
|
|
2
2
|
/** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
|
|
3
3
|
export declare class MemoryProxyLedger implements ProxyLedger {
|
|
4
4
|
private readonly sessions;
|
|
@@ -12,6 +12,9 @@ export declare class MemoryProxyLedger implements ProxyLedger {
|
|
|
12
12
|
release(requestId: string, upstreamStatus: number): Promise<void>;
|
|
13
13
|
markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
|
|
14
14
|
cancelSession(sessionId: string): Promise<void>;
|
|
15
|
+
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
16
|
+
recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
|
|
17
|
+
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
15
18
|
getRequest(requestId: string): Promise<ProxyRequest | null>;
|
|
16
19
|
private requiredRequest;
|
|
17
20
|
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
import { normalizeProxyModelTerms, } from "./types.js";
|
|
1
2
|
function cloneSession(session) {
|
|
2
|
-
return {
|
|
3
|
+
return {
|
|
4
|
+
...session,
|
|
5
|
+
allowedModels: [...session.allowedModels],
|
|
6
|
+
deadlineAt: new Date(session.deadlineAt),
|
|
7
|
+
budgetExhaustedAt: session.budgetExhaustedAt ? new Date(session.budgetExhaustedAt) : null,
|
|
8
|
+
upstreamFailure: session.upstreamFailure ?? null,
|
|
9
|
+
terms: session.terms
|
|
10
|
+
? { version: session.terms.version, entry: { ...session.terms.entry, efforts: [...session.terms.entry.efforts] } }
|
|
11
|
+
: null,
|
|
12
|
+
};
|
|
3
13
|
}
|
|
4
14
|
function cloneRequest(request) {
|
|
5
15
|
return {
|
|
@@ -20,7 +30,12 @@ export class MemoryProxyLedger {
|
|
|
20
30
|
}
|
|
21
31
|
if (this.sessionByCapability.has(input.capabilityHash))
|
|
22
32
|
throw new Error("proxy_capability_collision");
|
|
23
|
-
const session = {
|
|
33
|
+
const session = {
|
|
34
|
+
...input,
|
|
35
|
+
allowedModels: [...input.allowedModels],
|
|
36
|
+
status: "active",
|
|
37
|
+
terms: input.terms ? normalizeProxyModelTerms(input.terms) : null,
|
|
38
|
+
};
|
|
24
39
|
this.sessions.set(session.id, session);
|
|
25
40
|
this.sessionByCapability.set(session.capabilityHash, session.id);
|
|
26
41
|
}
|
|
@@ -48,8 +63,10 @@ export class MemoryProxyLedger {
|
|
|
48
63
|
if (request.status === "reserved" || request.status === "uncertain")
|
|
49
64
|
committedOrHeld += request.reservationUsd;
|
|
50
65
|
}
|
|
51
|
-
if (committedOrHeld + input.reservationUsd >= session.budgetUsd)
|
|
66
|
+
if (committedOrHeld + input.reservationUsd >= session.budgetUsd) {
|
|
67
|
+
session.budgetExhaustedAt ??= new Date(input.now);
|
|
52
68
|
return { outcome: "budget_exhausted" };
|
|
69
|
+
}
|
|
53
70
|
const request = { ...input, pricing: { ...input.pricing }, status: "reserved" };
|
|
54
71
|
this.requests.set(request.id, request);
|
|
55
72
|
this.requestBySessionKey.set(lookupKey, request.id);
|
|
@@ -90,6 +107,17 @@ export class MemoryProxyLedger {
|
|
|
90
107
|
if (session)
|
|
91
108
|
session.status = "cancelled";
|
|
92
109
|
}
|
|
110
|
+
async budgetExhausted(sessionId) {
|
|
111
|
+
return Boolean(this.sessions.get(sessionId)?.budgetExhaustedAt);
|
|
112
|
+
}
|
|
113
|
+
async recordUpstreamFailure(sessionId, code) {
|
|
114
|
+
const session = this.sessions.get(sessionId);
|
|
115
|
+
if (session)
|
|
116
|
+
session.upstreamFailure ??= code;
|
|
117
|
+
}
|
|
118
|
+
async upstreamFailure(sessionId) {
|
|
119
|
+
return this.sessions.get(sessionId)?.upstreamFailure ?? null;
|
|
120
|
+
}
|
|
93
121
|
async getRequest(requestId) {
|
|
94
122
|
const request = this.requests.get(requestId);
|
|
95
123
|
return request ? cloneRequest(request) : null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ModelPricing } from "../llm/pricing.js";
|
|
1
|
+
import { type ModelPricing } from "../llm/pricing-core.js";
|
|
2
2
|
import type { PricingSnapshot, ProxyUsage } from "./types.js";
|
|
3
3
|
export declare function parseAuthoritativeUsage(value: unknown): ProxyUsage;
|
|
4
4
|
export declare function parseAnthropicAuthoritativeUsage(value: unknown): ProxyUsage;
|
|
@@ -8,8 +8,12 @@ export declare function fingerprintRequest(body: string): string;
|
|
|
8
8
|
export interface TerminalUsage {
|
|
9
9
|
terminal: boolean;
|
|
10
10
|
usage?: ProxyUsage;
|
|
11
|
+
/** Set when the upstream ended the response as failed or incomplete: its error code. */
|
|
12
|
+
failure?: string;
|
|
11
13
|
}
|
|
12
14
|
export declare function terminalUsageFromSseFrame(frame: string): TerminalUsage;
|
|
15
|
+
/** The safe error code in an upstream error body (a stream event or a rejected response's JSON), if any. */
|
|
16
|
+
export declare function safeUpstreamErrorCode(record: Record<string, unknown>): string | undefined;
|
|
13
17
|
/** Accumulates Anthropic's split input/output usage until message_stop. */
|
|
14
18
|
export declare class AnthropicSseUsageTracker {
|
|
15
19
|
private startUsage?;
|
|
@@ -17,4 +21,5 @@ export declare class AnthropicSseUsageTracker {
|
|
|
17
21
|
private stopped;
|
|
18
22
|
consume(frame: string): TerminalUsage;
|
|
19
23
|
}
|
|
24
|
+
/** The rates a request is billed at, tagged with their version. Picks only the price fields: a catalog entry's routing/shape fields stay out of the ledger. */
|
|
20
25
|
export declare function pricingSnapshot(version: string, pricing: ModelPricing): PricingSnapshot;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { computeCost } from "../llm/pricing.js";
|
|
2
|
+
import { computeCost } from "../llm/pricing-core.js";
|
|
3
3
|
const MAX_SAFE_TOKENS = 2_000_000_000;
|
|
4
4
|
function tokenCount(value, name) {
|
|
5
5
|
if (!Number.isSafeInteger(value) || value < 0 || value > MAX_SAFE_TOKENS) {
|
|
@@ -74,13 +74,36 @@ export function terminalUsageFromSseFrame(frame) {
|
|
|
74
74
|
if (!event || typeof event !== "object")
|
|
75
75
|
return { terminal: false };
|
|
76
76
|
const record = event;
|
|
77
|
-
|
|
77
|
+
// A stream-level error event (quota, rate limit, server error) ends the response with no usage.
|
|
78
|
+
if (record.type === "error")
|
|
79
|
+
return { terminal: true, failure: upstreamErrorCode(record) };
|
|
80
|
+
const failed = record.type === "response.failed" || record.type === "response.incomplete";
|
|
81
|
+
if (record.type !== "response.completed" && !failed)
|
|
78
82
|
return { terminal: false };
|
|
79
83
|
const response = record.response;
|
|
80
84
|
if (!response || typeof response !== "object")
|
|
81
85
|
throw new Error("invalid_upstream_terminal_event");
|
|
82
86
|
const usage = response.usage;
|
|
83
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
terminal: true,
|
|
89
|
+
usage: usage == null ? undefined : parseAuthoritativeUsage(usage),
|
|
90
|
+
...(failed ? { failure: upstreamErrorCode(response) } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const SAFE_ERROR_CODE = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
94
|
+
/** The upstream's own error code, never its message: codes are fixed identifiers, messages can echo input. */
|
|
95
|
+
function upstreamErrorCode(record) {
|
|
96
|
+
return safeUpstreamErrorCode(record) ?? "unknown";
|
|
97
|
+
}
|
|
98
|
+
/** The safe error code in an upstream error body (a stream event or a rejected response's JSON), if any. */
|
|
99
|
+
export function safeUpstreamErrorCode(record) {
|
|
100
|
+
const nested = (key) => {
|
|
101
|
+
const value = record[key];
|
|
102
|
+
return value && typeof value === "object" ? value : undefined;
|
|
103
|
+
};
|
|
104
|
+
const candidates = [nested("error")?.code, nested("error")?.type, nested("incomplete_details")?.reason, record.code];
|
|
105
|
+
const code = candidates.find((value) => typeof value === "string" && SAFE_ERROR_CODE.test(value));
|
|
106
|
+
return typeof code === "string" ? code : undefined;
|
|
84
107
|
}
|
|
85
108
|
function sseEvent(frame) {
|
|
86
109
|
const lines = frame.split("\n");
|
|
@@ -118,6 +141,9 @@ export class AnthropicSseUsageTracker {
|
|
|
118
141
|
if (!value)
|
|
119
142
|
return { terminal: false };
|
|
120
143
|
switch (value.type) {
|
|
144
|
+
// A stream-level error event (quota, rate limit, server error) ends the response with no usage.
|
|
145
|
+
case "error":
|
|
146
|
+
return { terminal: true, failure: upstreamErrorCode(value) };
|
|
121
147
|
case "message_start": {
|
|
122
148
|
if (this.startUsage || !value.message || typeof value.message !== "object") {
|
|
123
149
|
throw new Error("invalid_upstream_sse");
|
|
@@ -156,6 +182,17 @@ export class AnthropicSseUsageTracker {
|
|
|
156
182
|
}
|
|
157
183
|
}
|
|
158
184
|
}
|
|
185
|
+
/** The rates a request is billed at, tagged with their version. Picks only the price fields: a catalog entry's routing/shape fields stay out of the ledger. */
|
|
159
186
|
export function pricingSnapshot(version, pricing) {
|
|
160
|
-
|
|
187
|
+
const snapshot = {
|
|
188
|
+
version,
|
|
189
|
+
encoding: pricing.encoding,
|
|
190
|
+
inputPerMTok: pricing.inputPerMTok,
|
|
191
|
+
outputPerMTok: pricing.outputPerMTok,
|
|
192
|
+
};
|
|
193
|
+
if (pricing.cachedInputPerMTok !== undefined)
|
|
194
|
+
snapshot.cachedInputPerMTok = pricing.cachedInputPerMTok;
|
|
195
|
+
if (pricing.cacheWritePerMTok !== undefined)
|
|
196
|
+
snapshot.cacheWritePerMTok = pricing.cacheWritePerMTok;
|
|
197
|
+
return snapshot;
|
|
161
198
|
}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import type { PrismaClient } from "#prisma";
|
|
2
2
|
import type { CreateProxySessionInput, ProxyLedger, ProxyRequest, ProxySession, ProxyUsage, ReserveProxyRequestInput, ReserveProxyRequestResult } from "./types.js";
|
|
3
3
|
export type PrismaProxyLedgerDb = Pick<PrismaClient, "$transaction" | "$queryRaw" | "$executeRaw">;
|
|
4
|
+
/** How long a ledger transaction waits for a pool connection (Prisma's
|
|
5
|
+
* default is 2 s). A model request fails outright when this runs out, so it
|
|
6
|
+
* gets more room than the default; its pool is also kept apart from the
|
|
7
|
+
* package registry's (coding-proxy/main.ts). */
|
|
8
|
+
export declare const LEDGER_TRANSACTION_MAX_WAIT_MS = 5000;
|
|
9
|
+
/** How long a ledger transaction may run once started (Prisma's default is
|
|
10
|
+
* 5 s). Each is a handful of small queries, but a proxy busy with package
|
|
11
|
+
* installs (the registry's dependency walk parses large npm documents on the
|
|
12
|
+
* same event loop) can stall between them; a live lockfile install expired
|
|
13
|
+
* one ("A commit cannot be executed on an expired transaction") and failed
|
|
14
|
+
* the model request. The row lock it holds is per session, so a longer
|
|
15
|
+
* window only delays that run's own next request. */
|
|
16
|
+
export declare const LEDGER_TRANSACTION_TIMEOUT_MS = 20000;
|
|
4
17
|
export declare class PrismaProxyLedger implements ProxyLedger {
|
|
5
18
|
private readonly db;
|
|
6
19
|
constructor(db: PrismaProxyLedgerDb);
|
|
20
|
+
private transaction;
|
|
7
21
|
createSession(input: CreateProxySessionInput): Promise<void>;
|
|
8
22
|
findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
|
|
9
23
|
reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
|
|
@@ -11,5 +25,8 @@ export declare class PrismaProxyLedger implements ProxyLedger {
|
|
|
11
25
|
release(requestId: string, upstreamStatus: number): Promise<void>;
|
|
12
26
|
markUncertain(requestId: string, upstreamStatus?: number): Promise<void>;
|
|
13
27
|
cancelSession(sessionId: string): Promise<void>;
|
|
28
|
+
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
29
|
+
recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
|
|
30
|
+
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
14
31
|
getRequest(requestId: string): Promise<ProxyRequest | null>;
|
|
15
32
|
}
|