@wardby/cli 0.1.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 +131 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +282 -0
- package/bin/wardby.js +3 -0
- package/deploy/local/docker-compose.yml +19 -0
- package/dist/claude-coding-worker/driver.d.ts +70 -0
- package/dist/claude-coding-worker/driver.js +128 -0
- package/dist/claude-coding-worker/main.d.ts +2 -0
- package/dist/claude-coding-worker/main.js +41 -0
- package/dist/claude-coding-worker/sdk.d.ts +4 -0
- package/dist/claude-coding-worker/sdk.js +43 -0
- package/dist/claude-coding-worker/tool-relay.d.ts +1 -0
- package/dist/claude-coding-worker/tool-relay.js +9 -0
- package/dist/cli-help.d.ts +1 -0
- package/dist/cli-help.js +20 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +629 -0
- package/dist/coding/observability.d.ts +59 -0
- package/dist/coding/observability.js +77 -0
- package/dist/coding/profile.d.ts +88 -0
- package/dist/coding/profile.js +137 -0
- package/dist/coding/protocol.d.ts +345 -0
- package/dist/coding/protocol.js +445 -0
- package/dist/coding/provider.d.ts +4 -0
- package/dist/coding/provider.js +18 -0
- package/dist/coding-proxy/main.d.ts +1 -0
- package/dist/coding-proxy/main.js +51 -0
- package/dist/coding-worker/artifact.d.ts +16 -0
- package/dist/coding-worker/artifact.js +37 -0
- package/dist/coding-worker/driver.d.ts +46 -0
- package/dist/coding-worker/driver.js +158 -0
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +23 -0
- package/dist/coding-worker/isolation-probe.d.ts +1 -0
- package/dist/coding-worker/isolation-probe.js +146 -0
- package/dist/coding-worker/keeper.d.ts +4 -0
- package/dist/coding-worker/keeper.js +29 -0
- package/dist/coding-worker/main.d.ts +2 -0
- package/dist/coding-worker/main.js +43 -0
- package/dist/coding-worker/sdk.d.ts +26 -0
- package/dist/coding-worker/sdk.js +28 -0
- package/dist/coding-worker/types.d.ts +64 -0
- package/dist/coding-worker/types.js +1 -0
- package/dist/config/providers.d.ts +158 -0
- package/dist/config/providers.js +162 -0
- package/dist/core/budget-groups.d.ts +72 -0
- package/dist/core/budget-groups.js +149 -0
- package/dist/core/budget.d.ts +63 -0
- package/dist/core/budget.js +69 -0
- package/dist/core/coding-queue.d.ts +32 -0
- package/dist/core/coding-queue.js +54 -0
- package/dist/core/cron.d.ts +31 -0
- package/dist/core/cron.js +43 -0
- package/dist/core/datastores.d.ts +41 -0
- package/dist/core/datastores.js +105 -0
- package/dist/core/db.d.ts +2 -0
- package/dist/core/db.js +2 -0
- package/dist/core/dispatch.d.ts +81 -0
- package/dist/core/dispatch.js +184 -0
- package/dist/core/engine-native.d.ts +29 -0
- package/dist/core/engine-native.js +259 -0
- package/dist/core/http-runtime.d.ts +7 -0
- package/dist/core/http-runtime.js +101 -0
- package/dist/core/lease.d.ts +13 -0
- package/dist/core/lease.js +22 -0
- package/dist/core/logger.d.ts +13 -0
- package/dist/core/logger.js +45 -0
- package/dist/core/memory-tools.d.ts +11 -0
- package/dist/core/memory-tools.js +122 -0
- package/dist/core/reconciler.d.ts +45 -0
- package/dist/core/reconciler.js +152 -0
- package/dist/core/runner.d.ts +87 -0
- package/dist/core/runner.js +529 -0
- package/dist/core/scheduler.d.ts +47 -0
- package/dist/core/scheduler.js +121 -0
- package/dist/core/secrets.d.ts +46 -0
- package/dist/core/secrets.js +100 -0
- package/dist/core/subagent-memory-tools.d.ts +18 -0
- package/dist/core/subagent-memory-tools.js +121 -0
- package/dist/core/timing.d.ts +7 -0
- package/dist/core/timing.js +7 -0
- package/dist/core/webhooks.d.ts +23 -0
- package/dist/core/webhooks.js +113 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.js +13 -0
- package/dist/import/budgets.d.ts +16 -0
- package/dist/import/budgets.js +21 -0
- package/dist/import/bundle.d.ts +16 -0
- package/dist/import/bundle.js +61 -0
- package/dist/import/cli-args.d.ts +2 -0
- package/dist/import/cli-args.js +44 -0
- package/dist/import/create.d.ts +34 -0
- package/dist/import/create.js +363 -0
- package/dist/import/index.d.ts +25 -0
- package/dist/import/index.js +130 -0
- package/dist/import/model-gate.d.ts +1 -0
- package/dist/import/model-gate.js +3 -0
- package/dist/import/neutral-schema.d.ts +369 -0
- package/dist/import/neutral-schema.js +109 -0
- package/dist/import/preflight.d.ts +41 -0
- package/dist/import/preflight.js +71 -0
- package/dist/import/report.d.ts +5 -0
- package/dist/import/report.js +98 -0
- package/dist/import/tool-scan.d.ts +8 -0
- package/dist/import/tool-scan.js +20 -0
- package/dist/mcp/auth/ownership.d.ts +113 -0
- package/dist/mcp/auth/ownership.js +87 -0
- package/dist/mcp/auth/principal.d.ts +9 -0
- package/dist/mcp/auth/principal.js +9 -0
- package/dist/mcp/auth/resource-server.d.ts +47 -0
- package/dist/mcp/auth/resource-server.js +82 -0
- package/dist/mcp/auth/self-hosted/browser.d.ts +3 -0
- package/dist/mcp/auth/self-hosted/browser.js +273 -0
- package/dist/mcp/auth/self-hosted/cli.d.ts +2 -0
- package/dist/mcp/auth/self-hosted/cli.js +39 -0
- package/dist/mcp/auth/self-hosted/credentials.d.ts +58 -0
- package/dist/mcp/auth/self-hosted/credentials.js +106 -0
- package/dist/mcp/auth/self-hosted/rate-limit.d.ts +13 -0
- package/dist/mcp/auth/self-hosted/rate-limit.js +20 -0
- package/dist/mcp/auth/self-hosted/session.d.ts +36 -0
- package/dist/mcp/auth/self-hosted/session.js +110 -0
- package/dist/mcp/capabilities.d.ts +11 -0
- package/dist/mcp/capabilities.js +10 -0
- package/dist/mcp/context.d.ts +46 -0
- package/dist/mcp/context.js +1 -0
- package/dist/mcp/errors.d.ts +13 -0
- package/dist/mcp/errors.js +22 -0
- package/dist/mcp/index.d.ts +32 -0
- package/dist/mcp/index.js +187 -0
- package/dist/mcp/jsonrpc.d.ts +8 -0
- package/dist/mcp/jsonrpc.js +1 -0
- package/dist/mcp/server.d.ts +107 -0
- package/dist/mcp/server.js +203 -0
- package/dist/mcp/tasks/manager.d.ts +63 -0
- package/dist/mcp/tasks/manager.js +103 -0
- package/dist/mcp/tools/agents.d.ts +2 -0
- package/dist/mcp/tools/agents.js +375 -0
- package/dist/mcp/tools/budget-groups.d.ts +2 -0
- package/dist/mcp/tools/budget-groups.js +136 -0
- package/dist/mcp/tools/datastore.d.ts +2 -0
- package/dist/mcp/tools/datastore.js +217 -0
- package/dist/mcp/tools/memory.d.ts +3 -0
- package/dist/mcp/tools/memory.js +60 -0
- package/dist/mcp/tools/models.d.ts +8 -0
- package/dist/mcp/tools/models.js +15 -0
- package/dist/mcp/tools/runs.d.ts +2 -0
- package/dist/mcp/tools/runs.js +61 -0
- package/dist/mcp/tools/scheduling.d.ts +2 -0
- package/dist/mcp/tools/scheduling.js +48 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -0
- package/dist/mcp/tools/secret-elicitation-form.js +93 -0
- package/dist/mcp/tools/secret-elicitation-server.d.ts +5 -0
- package/dist/mcp/tools/secret-elicitation-server.js +57 -0
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -0
- package/dist/mcp/tools/secret-elicitation.js +52 -0
- package/dist/mcp/tools/secrets.d.ts +13 -0
- package/dist/mcp/tools/secrets.js +124 -0
- package/dist/mcp/tools/subagents.d.ts +2 -0
- package/dist/mcp/tools/subagents.js +133 -0
- package/dist/mcp/tools/text-result.d.ts +6 -0
- package/dist/mcp/tools/text-result.js +3 -0
- package/dist/mcp/tools/tools.d.ts +2 -0
- package/dist/mcp/tools/tools.js +211 -0
- package/dist/mcp/tools/trigger.d.ts +2 -0
- package/dist/mcp/tools/trigger.js +120 -0
- package/dist/mcp/tools/webhooks.d.ts +2 -0
- package/dist/mcp/tools/webhooks.js +34 -0
- package/dist/mcp/transport/http-limits.d.ts +17 -0
- package/dist/mcp/transport/http-limits.js +92 -0
- package/dist/mcp/transport/stdio.d.ts +23 -0
- package/dist/mcp/transport/stdio.js +6 -0
- package/dist/mcp/transport/streamable-http.d.ts +34 -0
- package/dist/mcp/transport/streamable-http.js +158 -0
- package/dist/mcp/unattended-schedules.d.ts +15 -0
- package/dist/mcp/unattended-schedules.js +21 -0
- package/dist/mcp/webhooks/ingress.d.ts +17 -0
- package/dist/mcp/webhooks/ingress.js +33 -0
- package/dist/observability/config.d.ts +6 -0
- package/dist/observability/config.js +20 -0
- package/dist/observability/metrics-server.d.ts +11 -0
- package/dist/observability/metrics-server.js +47 -0
- package/dist/observability/metrics.d.ts +36 -0
- package/dist/observability/metrics.js +158 -0
- package/dist/providers/auth/authorization-server.d.ts +41 -0
- package/dist/providers/auth/authorization-server.js +1 -0
- package/dist/providers/auth/delegating.d.ts +44 -0
- package/dist/providers/auth/delegating.js +105 -0
- package/dist/providers/auth/index.d.ts +11 -0
- package/dist/providers/auth/index.js +20 -0
- package/dist/providers/auth/release-gate.d.ts +1 -0
- package/dist/providers/auth/release-gate.js +4 -0
- package/dist/providers/auth/self-hosted.d.ts +78 -0
- package/dist/providers/auth/self-hosted.js +377 -0
- package/dist/providers/auth/subject.d.ts +1 -0
- package/dist/providers/auth/subject.js +6 -0
- package/dist/providers/auth/types.d.ts +63 -0
- package/dist/providers/auth/types.js +22 -0
- package/dist/providers/coding-proxy/deny-port.d.ts +5 -0
- package/dist/providers/coding-proxy/deny-port.js +45 -0
- package/dist/providers/coding-proxy/environment-credentials.d.ts +7 -0
- package/dist/providers/coding-proxy/environment-credentials.js +16 -0
- package/dist/providers/coding-proxy/index.d.ts +7 -0
- package/dist/providers/coding-proxy/index.js +7 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +17 -0
- package/dist/providers/coding-proxy/memory-ledger.js +103 -0
- package/dist/providers/coding-proxy/metering.d.ts +20 -0
- package/dist/providers/coding-proxy/metering.js +161 -0
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -0
- package/dist/providers/coding-proxy/prisma-ledger.js +213 -0
- package/dist/providers/coding-proxy/proxy.d.ts +75 -0
- package/dist/providers/coding-proxy/proxy.js +721 -0
- package/dist/providers/coding-proxy/runtime.d.ts +18 -0
- package/dist/providers/coding-proxy/runtime.js +39 -0
- package/dist/providers/coding-proxy/secure-fetch.d.ts +9 -0
- package/dist/providers/coding-proxy/secure-fetch.js +72 -0
- package/dist/providers/coding-proxy/server.d.ts +17 -0
- package/dist/providers/coding-proxy/server.js +139 -0
- package/dist/providers/coding-proxy/types.d.ts +99 -0
- package/dist/providers/coding-proxy/types.js +1 -0
- package/dist/providers/datastore/index.d.ts +2 -0
- package/dist/providers/datastore/index.js +2 -0
- package/dist/providers/datastore/postgres.d.ts +20 -0
- package/dist/providers/datastore/postgres.js +130 -0
- package/dist/providers/datastore/scoped.d.ts +10 -0
- package/dist/providers/datastore/scoped.js +46 -0
- package/dist/providers/datastore/types.d.ts +31 -0
- package/dist/providers/datastore/types.js +7 -0
- package/dist/providers/email/types.d.ts +46 -0
- package/dist/providers/email/types.js +8 -0
- package/dist/providers/engine/index.d.ts +1 -0
- package/dist/providers/engine/index.js +1 -0
- package/dist/providers/engine/types.d.ts +67 -0
- package/dist/providers/engine/types.js +16 -0
- package/dist/providers/executor/build.d.ts +6 -0
- package/dist/providers/executor/build.js +15 -0
- package/dist/providers/executor/composition.d.ts +14 -0
- package/dist/providers/executor/composition.js +123 -0
- package/dist/providers/executor/container.d.ts +184 -0
- package/dist/providers/executor/container.js +936 -0
- package/dist/providers/executor/dbos-status.d.ts +50 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +53 -0
- package/dist/providers/executor/dbos.js +269 -0
- package/dist/providers/executor/in-process.d.ts +18 -0
- package/dist/providers/executor/in-process.js +38 -0
- package/dist/providers/executor/index.d.ts +8 -0
- package/dist/providers/executor/index.js +8 -0
- package/dist/providers/executor/routing.d.ts +48 -0
- package/dist/providers/executor/routing.js +70 -0
- package/dist/providers/executor/types.d.ts +55 -0
- package/dist/providers/executor/types.js +1 -0
- package/dist/providers/index.d.ts +43 -0
- package/dist/providers/index.js +18 -0
- package/dist/providers/jobs/docker-isolation.d.ts +166 -0
- package/dist/providers/jobs/docker-isolation.js +724 -0
- package/dist/providers/jobs/docker.d.ts +127 -0
- package/dist/providers/jobs/docker.js +1027 -0
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +98 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +142 -0
- package/dist/providers/jobs/fake.d.ts +23 -0
- package/dist/providers/jobs/fake.js +132 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +60 -0
- package/dist/providers/jobs/kubernetes-api.js +20 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +36 -0
- package/dist/providers/jobs/kubernetes-client.js +171 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +49 -0
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +141 -0
- package/dist/providers/jobs/kubernetes-isolation.d.ts +147 -0
- package/dist/providers/jobs/kubernetes-isolation.js +607 -0
- package/dist/providers/jobs/kubernetes-platform.d.ts +177 -0
- package/dist/providers/jobs/kubernetes-platform.js +280 -0
- package/dist/providers/jobs/kubernetes-preflight.d.ts +59 -0
- package/dist/providers/jobs/kubernetes-preflight.js +339 -0
- package/dist/providers/jobs/kubernetes-witness.d.ts +10 -0
- package/dist/providers/jobs/kubernetes-witness.js +193 -0
- package/dist/providers/jobs/kubernetes.d.ts +127 -0
- package/dist/providers/jobs/kubernetes.js +874 -0
- package/dist/providers/jobs/safe-extract.d.ts +9 -0
- package/dist/providers/jobs/safe-extract.js +325 -0
- package/dist/providers/jobs/types.d.ts +78 -0
- package/dist/providers/jobs/types.js +6 -0
- package/dist/providers/jobs/workspace-swap.d.ts +2 -0
- package/dist/providers/jobs/workspace-swap.js +47 -0
- package/dist/providers/llm/anthropic.d.ts +13 -0
- package/dist/providers/llm/anthropic.js +21 -0
- package/dist/providers/llm/bedrock.d.ts +19 -0
- package/dist/providers/llm/bedrock.js +33 -0
- package/dist/providers/llm/claude-messages.d.ts +106 -0
- package/dist/providers/llm/claude-messages.js +157 -0
- package/dist/providers/llm/claude-provider.d.ts +40 -0
- package/dist/providers/llm/claude-provider.js +31 -0
- package/dist/providers/llm/index.d.ts +10 -0
- package/dist/providers/llm/index.js +10 -0
- package/dist/providers/llm/openai.d.ts +23 -0
- package/dist/providers/llm/openai.js +156 -0
- package/dist/providers/llm/pricing-anthropic.d.ts +4 -0
- package/dist/providers/llm/pricing-anthropic.js +30 -0
- package/dist/providers/llm/pricing-bedrock-claude.d.ts +12 -0
- package/dist/providers/llm/pricing-bedrock-claude.js +37 -0
- package/dist/providers/llm/pricing-core.d.ts +26 -0
- package/dist/providers/llm/pricing-core.js +17 -0
- package/dist/providers/llm/pricing.d.ts +30 -0
- package/dist/providers/llm/pricing.js +74 -0
- package/dist/providers/llm/registration.d.ts +8 -0
- package/dist/providers/llm/registration.js +39 -0
- package/dist/providers/llm/routing.d.ts +25 -0
- package/dist/providers/llm/routing.js +32 -0
- package/dist/providers/llm/types.d.ts +85 -0
- package/dist/providers/llm/types.js +12 -0
- package/dist/providers/memory/index.d.ts +2 -0
- package/dist/providers/memory/index.js +2 -0
- package/dist/providers/memory/postgres.d.ts +20 -0
- package/dist/providers/memory/postgres.js +72 -0
- package/dist/providers/memory/types.d.ts +32 -0
- package/dist/providers/memory/types.js +17 -0
- package/dist/providers/secrets/app-key.d.ts +8 -0
- package/dist/providers/secrets/app-key.js +50 -0
- package/dist/providers/secrets/index.d.ts +10 -0
- package/dist/providers/secrets/index.js +13 -0
- package/dist/providers/secrets/transfer-envelope.d.ts +12 -0
- package/dist/providers/secrets/transfer-envelope.js +35 -0
- package/dist/providers/secrets/types.d.ts +18 -0
- package/dist/providers/secrets/types.js +12 -0
- package/dist/providers/storage/types.d.ts +18 -0
- package/dist/providers/storage/types.js +7 -0
- package/dist/providers/vcs/git.d.ts +105 -0
- package/dist/providers/vcs/git.js +710 -0
- package/dist/providers/vcs/github.d.ts +105 -0
- package/dist/providers/vcs/github.js +394 -0
- package/dist/providers/vcs/index.d.ts +6 -0
- package/dist/providers/vcs/index.js +26 -0
- package/dist/providers/vcs/types.d.ts +118 -0
- package/dist/providers/vcs/types.js +1 -0
- package/dist/sandbox/bounded-json.d.ts +2 -0
- package/dist/sandbox/bounded-json.js +36 -0
- package/dist/sandbox/bridge.d.ts +15 -0
- package/dist/sandbox/bridge.js +78 -0
- package/dist/sandbox/eval-core.d.ts +37 -0
- package/dist/sandbox/eval-core.js +159 -0
- package/dist/sandbox/fetch-policy.d.ts +24 -0
- package/dist/sandbox/fetch-policy.js +96 -0
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +5 -0
- package/dist/sandbox/generated/zod.bundle.js +1 -0
- package/dist/sandbox/host-functions.d.ts +29 -0
- package/dist/sandbox/host-functions.js +168 -0
- package/dist/sandbox/limits.d.ts +39 -0
- package/dist/sandbox/limits.js +39 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/crash.js +6 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/echo.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/reject.js +5 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.d.ts +1 -0
- package/dist/sandbox/parser-worker/__fixtures__/spin-forever.js +11 -0
- package/dist/sandbox/parser-worker/pool.d.ts +13 -0
- package/dist/sandbox/parser-worker/pool.js +111 -0
- package/dist/sandbox/parser-worker/worker.d.ts +14 -0
- package/dist/sandbox/parser-worker/worker.js +63 -0
- package/dist/sandbox/pii-redaction.d.ts +1 -0
- package/dist/sandbox/pii-redaction.js +29 -0
- package/dist/sandbox/prelude.d.ts +26 -0
- package/dist/sandbox/prelude.js +408 -0
- package/dist/sandbox/quickjs-module.d.ts +13 -0
- package/dist/sandbox/quickjs-module.js +19 -0
- package/dist/sandbox/run-in-sandbox.d.ts +34 -0
- package/dist/sandbox/run-in-sandbox.js +53 -0
- package/dist/sandbox/safe-fetch.d.ts +26 -0
- package/dist/sandbox/safe-fetch.js +140 -0
- package/dist/sandbox/tool-capabilities.d.ts +66 -0
- package/dist/sandbox/tool-capabilities.js +103 -0
- package/dist/sandbox/zod-params.d.ts +22 -0
- package/dist/sandbox/zod-params.js +60 -0
- package/dist/serve.d.ts +14 -0
- package/dist/serve.js +54 -0
- package/dist/wardby-bin.d.ts +2 -0
- package/dist/wardby-bin.js +20 -0
- package/package.json +123 -0
- package/prisma/migrations/20260905000000_init/migration.sql +34 -0
- package/prisma/migrations/20260905010000_scheduler_durability/migration.sql +31 -0
- package/prisma/migrations/20260905020000_tools_multiturn/migration.sql +47 -0
- package/prisma/migrations/20260905030000_cache_tool_json_schema/migration.sql +13 -0
- package/prisma/migrations/20260906000000_mcp_phase4/migration.sql +115 -0
- package/prisma/migrations/20260906010000_run_final_text/migration.sql +7 -0
- package/prisma/migrations/20260906020000_run_turns/migration.sql +6 -0
- package/prisma/migrations/20260906030000_task_principal_id/migration.sql +5 -0
- package/prisma/migrations/20260906040000_secure_self_hosted_oauth/migration.sql +67 -0
- package/prisma/migrations/20260906050000_phase5_coding_agents/migration.sql +52 -0
- package/prisma/migrations/20260906060000_tool_capability_scoping/migration.sql +22 -0
- package/prisma/migrations/20260906070000_datastore_pii_flag/migration.sql +6 -0
- package/prisma/migrations/20260906080000_secret_elicitation_outcomes/migration.sql +13 -0
- package/prisma/migrations/20260907010000_coding_proxy_ledger/migration.sql +57 -0
- package/prisma/migrations/20260907020000_budget_groups/migration.sql +24 -0
- package/prisma/migrations/20260907030000_coding_webhook_task_override/migration.sql +4 -0
- package/prisma/migrations/20260908010000_run_execution_backend/migration.sql +2 -0
- package/prisma/migrations/20260908020000_coding_run_audit_metadata/migration.sql +7 -0
- package/prisma/migrations/20260910010000_agent_secret_bound_name/migration.sql +16 -0
- package/prisma/migrations/20260911010000_coding_worker_toolchains/migration.sql +5 -0
- package/prisma/migrations/20260912010000_coding_provider_contract/migration.sql +24 -0
- package/prisma/migrations/20260912020000_coding_proxy_protocol/migration.sql +10 -0
- package/prisma/migrations/20260912030000_agent_memory/migration.sql +18 -0
- package/prisma/migrations/20260912040000_named_shared_datastores/migration.sql +68 -0
- package/prisma/migrations/20260913000000_run_trigger_webhook/migration.sql +2 -0
- package/prisma/migrations/20260913010000_agent_sub_agent/migration.sql +32 -0
- package/prisma/migrations/20260913020000_run_task_override/migration.sql +5 -0
- package/prisma/migrations/20260913030000_coding_run_root/migration.sql +11 -0
- package/prisma/migrations/20260922010000_coding_run_queued_at/migration.sql +8 -0
- package/prisma/migrations/20260922020000_coding_workspace_disk/migration.sql +8 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +723 -0
- package/scripts/git-askpass.sh +11 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Minimal CLI.
|
|
4
|
+
*
|
|
5
|
+
* wardby agent create --name <n> --model <m> --prompt <p> --budget <usd> [--schedule "<cron>"] [--timezone <tz>] [--memory-enabled]
|
|
6
|
+
* wardby agent list
|
|
7
|
+
* wardby agent schedule <name> --cron "<expr>" [--timezone <tz>] [--disable]
|
|
8
|
+
* wardby run <name>
|
|
9
|
+
* wardby runs [--agent <name>] [--limit N] [--status <s>]
|
|
10
|
+
* wardby scheduler [--scope default]
|
|
11
|
+
* wardby mcp (MCP_TRANSPORT=stdio|http selects the transport; authoring/
|
|
12
|
+
* control is MCP-first from here — this floor keeps working
|
|
13
|
+
* before/without an MCP client)
|
|
14
|
+
* wardby serve [--scope default] (everything: mcp + scheduler + reconciler; the
|
|
15
|
+
* image's default command, and what a
|
|
16
|
+
* single-container deployment should run)
|
|
17
|
+
*/
|
|
18
|
+
import "./env.js";
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
21
|
+
import { parseArgs } from "node:util";
|
|
22
|
+
import { promisify } from "node:util";
|
|
23
|
+
import { loadCodingConcurrencyConfig, loadContainerExecutorConfig, loadKubernetesJobConfig, loadProviderConfig, } from "./config/providers.js";
|
|
24
|
+
import { drainCodingQueue } from "./core/coding-queue.js";
|
|
25
|
+
import { isImmutableDockerImage } from "./providers/jobs/docker-isolation.js";
|
|
26
|
+
import { ClientNodeKubernetesApi } from "./providers/jobs/kubernetes-client.js";
|
|
27
|
+
import { describePreflightFailure, kubernetesPreflight } from "./providers/jobs/kubernetes-preflight.js";
|
|
28
|
+
import { RoutingLlmProvider, resolveLlmRegistrations } from "./providers/llm/index.js";
|
|
29
|
+
import { buildConfiguredExecutor, buildExecutor } from "./providers/executor/index.js";
|
|
30
|
+
import { PostgresDatastore } from "./providers/datastore/index.js";
|
|
31
|
+
import { PostgresAgentMemory } from "./providers/memory/index.js";
|
|
32
|
+
import { buildSecretCipher } from "./providers/secrets/index.js";
|
|
33
|
+
import { prisma } from "./core/db.js";
|
|
34
|
+
import { runAgent } from "./core/runner.js";
|
|
35
|
+
import { validateCronExpression } from "./core/cron.js";
|
|
36
|
+
import { startScheduler } from "./core/scheduler.js";
|
|
37
|
+
import { startReconciler } from "./core/reconciler.js";
|
|
38
|
+
import { NativeEngine } from "./core/engine-native.js";
|
|
39
|
+
import { logger } from "./core/logger.js";
|
|
40
|
+
import { deriveJsonSchema } from "./sandbox/zod-params.js";
|
|
41
|
+
import { ToolCapabilitiesPatchSchema } from "./sandbox/tool-capabilities.js";
|
|
42
|
+
import { startMcp } from "./mcp/index.js";
|
|
43
|
+
import { startServe } from "./serve.js";
|
|
44
|
+
import { authCommand } from "./mcp/auth/self-hosted/cli.js";
|
|
45
|
+
import { parseImportArgs } from "./import/cli-args.js";
|
|
46
|
+
import { runImport } from "./import/index.js";
|
|
47
|
+
import { CLI_USAGE } from "./cli-help.js";
|
|
48
|
+
const cliLog = logger.child({ module: "cli" });
|
|
49
|
+
const RUN_STATUSES = [
|
|
50
|
+
"pending",
|
|
51
|
+
"running",
|
|
52
|
+
"succeeded",
|
|
53
|
+
"failed",
|
|
54
|
+
"refused",
|
|
55
|
+
"lost",
|
|
56
|
+
"budget_exhausted",
|
|
57
|
+
"cancelled",
|
|
58
|
+
];
|
|
59
|
+
const execFile = promisify(execFileCallback);
|
|
60
|
+
function fail(message) {
|
|
61
|
+
console.error(`error: ${message}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
function buildLlmProvider() {
|
|
65
|
+
const result = resolveLlmRegistrations();
|
|
66
|
+
if (result.kind === "no-credentials") {
|
|
67
|
+
fail("No LLM credentials present. Set OPENAI_API_KEY, ANTHROPIC_API_KEY, and/or BEDROCK_REGION (or AWS_REGION).");
|
|
68
|
+
}
|
|
69
|
+
return new RoutingLlmProvider(result.registrations);
|
|
70
|
+
}
|
|
71
|
+
function buildEngine() {
|
|
72
|
+
const config = loadProviderConfig();
|
|
73
|
+
if (config.engine !== "native") {
|
|
74
|
+
fail(`ENGINE "${config.engine}" has no adapter yet (only "native").`);
|
|
75
|
+
}
|
|
76
|
+
return new NativeEngine();
|
|
77
|
+
}
|
|
78
|
+
function buildDatastore(cipher) {
|
|
79
|
+
const config = loadProviderConfig();
|
|
80
|
+
if (config.datastore !== "postgres") {
|
|
81
|
+
fail(`DATASTORE "${String(config.datastore)}" has no adapter yet (only "postgres").`);
|
|
82
|
+
}
|
|
83
|
+
return new PostgresDatastore(prisma, cipher);
|
|
84
|
+
}
|
|
85
|
+
function buildMemory() {
|
|
86
|
+
return new PostgresAgentMemory(prisma);
|
|
87
|
+
}
|
|
88
|
+
function buildSecrets() {
|
|
89
|
+
const config = loadProviderConfig();
|
|
90
|
+
try {
|
|
91
|
+
return buildSecretCipher(config);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function agentCreate(args) {
|
|
98
|
+
const { values } = parseArgs({
|
|
99
|
+
args,
|
|
100
|
+
options: {
|
|
101
|
+
name: { type: "string" },
|
|
102
|
+
model: { type: "string" },
|
|
103
|
+
prompt: { type: "string" },
|
|
104
|
+
budget: { type: "string" },
|
|
105
|
+
schedule: { type: "string" },
|
|
106
|
+
timezone: { type: "string" },
|
|
107
|
+
"max-turns": { type: "string" },
|
|
108
|
+
"memory-enabled": { type: "boolean" },
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
if (!values.name || !values.model || !values.prompt || !values.budget) {
|
|
112
|
+
fail("agent create requires --name, --model, --prompt, and --budget.");
|
|
113
|
+
}
|
|
114
|
+
const budgetUsd = Number(values.budget);
|
|
115
|
+
if (!Number.isFinite(budgetUsd) || budgetUsd <= 0) {
|
|
116
|
+
fail(`--budget must be a positive number, got "${values.budget}".`);
|
|
117
|
+
}
|
|
118
|
+
const maxTurns = values["max-turns"] ? Number(values["max-turns"]) : 10;
|
|
119
|
+
if (!Number.isInteger(maxTurns) || maxTurns <= 0) {
|
|
120
|
+
fail(`--max-turns must be a positive integer, got "${values["max-turns"]}".`);
|
|
121
|
+
}
|
|
122
|
+
const timezone = values.timezone ?? "UTC";
|
|
123
|
+
if (values.schedule) {
|
|
124
|
+
try {
|
|
125
|
+
validateCronExpression(values.schedule, timezone);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
fail(`invalid --schedule/--timezone: ${err instanceof Error ? err.message : String(err)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const agent = await prisma.agent.create({
|
|
132
|
+
data: {
|
|
133
|
+
name: values.name,
|
|
134
|
+
model: values.model,
|
|
135
|
+
systemPrompt: values.prompt,
|
|
136
|
+
budgetUsd,
|
|
137
|
+
schedule: values.schedule ?? null,
|
|
138
|
+
timezone,
|
|
139
|
+
maxTurns,
|
|
140
|
+
memoryEnabled: values["memory-enabled"] ?? false,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
console.log(agent.id);
|
|
144
|
+
}
|
|
145
|
+
async function toolCreate(args) {
|
|
146
|
+
const { values } = parseArgs({
|
|
147
|
+
args,
|
|
148
|
+
options: {
|
|
149
|
+
name: { type: "string" },
|
|
150
|
+
description: { type: "string" },
|
|
151
|
+
params: { type: "string" },
|
|
152
|
+
code: { type: "string" },
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
if (!values.name || !values.description || !values.params || !values.code) {
|
|
156
|
+
fail("tool create requires --name, --description, --params <file>, and --code <file>.");
|
|
157
|
+
}
|
|
158
|
+
let paramsZod;
|
|
159
|
+
let code;
|
|
160
|
+
try {
|
|
161
|
+
paramsZod = readFileSync(values.params, "utf8");
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
fail(`could not read --params file "${values.params}": ${err instanceof Error ? err.message : String(err)}`);
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
code = readFileSync(values.code, "utf8");
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
fail(`could not read --code file "${values.code}": ${err instanceof Error ? err.message : String(err)}`);
|
|
171
|
+
}
|
|
172
|
+
// Fails at registration, not at call time: a malformed schema never gets
|
|
173
|
+
// persisted. The derived schema is cached on the row (no "update tool"
|
|
174
|
+
// path exists, so it can never go stale) rather than re-derived per run.
|
|
175
|
+
const schemaResult = await deriveJsonSchema(paramsZod);
|
|
176
|
+
if (!schemaResult.ok) {
|
|
177
|
+
fail(`invalid --params schema: ${schemaResult.errorMessage}`);
|
|
178
|
+
}
|
|
179
|
+
const tool = await prisma.tool.create({
|
|
180
|
+
data: {
|
|
181
|
+
name: values.name,
|
|
182
|
+
description: values.description,
|
|
183
|
+
paramsZod: paramsZod,
|
|
184
|
+
jsonSchema: schemaResult.value,
|
|
185
|
+
code: code,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
console.log(tool.id);
|
|
189
|
+
}
|
|
190
|
+
async function toolAttach(args, detach) {
|
|
191
|
+
const { values, positionals } = parseArgs({
|
|
192
|
+
args,
|
|
193
|
+
allowPositionals: true,
|
|
194
|
+
options: {
|
|
195
|
+
"allow-secret": { type: "string", multiple: true },
|
|
196
|
+
"allow-datastore-prefix": { type: "string", multiple: true },
|
|
197
|
+
"allow-host": { type: "string", multiple: true },
|
|
198
|
+
// "<boundName>:<prefix>" — repeatable, one prefix per flag; grouped
|
|
199
|
+
// below into { [boundName]: prefix[] }, mirroring how
|
|
200
|
+
// allow-datastore-prefix maps to the agent's own private store.
|
|
201
|
+
"allow-shared-datastore-prefix": { type: "string", multiple: true },
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
const [toolName, agentName] = positionals;
|
|
205
|
+
if (!toolName || !agentName) {
|
|
206
|
+
fail(`tool ${detach ? "detach" : "attach"} requires <tool-name> <agent-name>.`);
|
|
207
|
+
}
|
|
208
|
+
const tool = await prisma.tool.findUnique({ where: { name: toolName } });
|
|
209
|
+
if (!tool)
|
|
210
|
+
fail(`unknown tool "${toolName}".`);
|
|
211
|
+
const agent = await prisma.agent.findUnique({ where: { name: agentName } });
|
|
212
|
+
if (!agent)
|
|
213
|
+
fail(`unknown agent "${agentName}".`);
|
|
214
|
+
if (detach) {
|
|
215
|
+
await prisma.agentTool.deleteMany({ where: { agentId: agent.id, toolId: tool.id } });
|
|
216
|
+
console.log(`detached "${toolName}" from "${agentName}".`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
let allowedSharedDatastorePrefixes;
|
|
220
|
+
if (values["allow-shared-datastore-prefix"]) {
|
|
221
|
+
allowedSharedDatastorePrefixes = {};
|
|
222
|
+
for (const entry of values["allow-shared-datastore-prefix"]) {
|
|
223
|
+
const sep = entry.indexOf(":");
|
|
224
|
+
if (sep < 0) {
|
|
225
|
+
fail(`invalid --allow-shared-datastore-prefix "${entry}" — expected "<boundName>:<prefix>".`);
|
|
226
|
+
}
|
|
227
|
+
const boundName = entry.slice(0, sep);
|
|
228
|
+
const prefix = entry.slice(sep + 1);
|
|
229
|
+
(allowedSharedDatastorePrefixes[boundName] ??= []).push(prefix);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const patch = ToolCapabilitiesPatchSchema.safeParse({
|
|
233
|
+
allowedSecrets: values["allow-secret"],
|
|
234
|
+
allowedDatastorePrefixes: values["allow-datastore-prefix"],
|
|
235
|
+
allowedHosts: values["allow-host"],
|
|
236
|
+
allowedSharedDatastorePrefixes,
|
|
237
|
+
});
|
|
238
|
+
if (!patch.success) {
|
|
239
|
+
fail(`invalid tool capabilities: ${patch.error.issues.map((i) => i.message).join("; ")}`);
|
|
240
|
+
}
|
|
241
|
+
await prisma.agentTool.upsert({
|
|
242
|
+
where: { agentId_toolId: { agentId: agent.id, toolId: tool.id } },
|
|
243
|
+
create: {
|
|
244
|
+
agentId: agent.id,
|
|
245
|
+
toolId: tool.id,
|
|
246
|
+
allowedSecrets: patch.data.allowedSecrets ?? [],
|
|
247
|
+
allowedDatastorePrefixes: patch.data.allowedDatastorePrefixes ?? [],
|
|
248
|
+
allowedHosts: patch.data.allowedHosts ?? [],
|
|
249
|
+
allowedSharedDatastorePrefixes: patch.data.allowedSharedDatastorePrefixes ?? {},
|
|
250
|
+
},
|
|
251
|
+
update: {
|
|
252
|
+
...(patch.data.allowedSecrets !== undefined ? { allowedSecrets: patch.data.allowedSecrets } : {}),
|
|
253
|
+
...(patch.data.allowedDatastorePrefixes !== undefined
|
|
254
|
+
? { allowedDatastorePrefixes: patch.data.allowedDatastorePrefixes }
|
|
255
|
+
: {}),
|
|
256
|
+
...(patch.data.allowedHosts !== undefined ? { allowedHosts: patch.data.allowedHosts } : {}),
|
|
257
|
+
...(patch.data.allowedSharedDatastorePrefixes !== undefined
|
|
258
|
+
? { allowedSharedDatastorePrefixes: patch.data.allowedSharedDatastorePrefixes }
|
|
259
|
+
: {}),
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
console.log(`attached "${toolName}" to "${agentName}".`);
|
|
263
|
+
}
|
|
264
|
+
async function toolList(args) {
|
|
265
|
+
const { values } = parseArgs({ args, options: { agent: { type: "string" } } });
|
|
266
|
+
if (values.agent) {
|
|
267
|
+
const agent = await prisma.agent.findUnique({ where: { name: values.agent } });
|
|
268
|
+
if (!agent)
|
|
269
|
+
fail(`unknown agent "${values.agent}".`);
|
|
270
|
+
const attached = await prisma.agentTool.findMany({ where: { agentId: agent.id }, include: { tool: true } });
|
|
271
|
+
if (attached.length === 0) {
|
|
272
|
+
console.log(`no tools attached to "${values.agent}".`);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
for (const a of attached)
|
|
276
|
+
console.log(`${a.tool.name} ${a.tool.description}`);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const tools = await prisma.tool.findMany({ orderBy: { name: "asc" } });
|
|
280
|
+
if (tools.length === 0) {
|
|
281
|
+
console.log("no tools registered.");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
for (const t of tools)
|
|
285
|
+
console.log(`${t.name} ${t.description}`);
|
|
286
|
+
}
|
|
287
|
+
async function agentSchedule(args) {
|
|
288
|
+
const [name, ...rest] = args;
|
|
289
|
+
if (!name) {
|
|
290
|
+
fail('agent schedule requires an agent name: wardby agent schedule <name> --cron "<expr>"');
|
|
291
|
+
}
|
|
292
|
+
const { values } = parseArgs({
|
|
293
|
+
args: rest,
|
|
294
|
+
options: {
|
|
295
|
+
cron: { type: "string" },
|
|
296
|
+
timezone: { type: "string" },
|
|
297
|
+
disable: { type: "boolean" },
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
const agent = await prisma.agent.findUnique({ where: { name: name } });
|
|
301
|
+
if (!agent) {
|
|
302
|
+
fail(`unknown agent "${name}".`);
|
|
303
|
+
}
|
|
304
|
+
if (values.disable) {
|
|
305
|
+
await prisma.agent.update({ where: { name: name }, data: { scheduleEnabled: false } });
|
|
306
|
+
console.log(`schedule disabled for "${name}".`);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const timezone = values.timezone ?? agent.timezone;
|
|
310
|
+
const schedule = values.cron ?? agent.schedule;
|
|
311
|
+
if (!schedule) {
|
|
312
|
+
fail("no --cron given and the agent has no existing schedule to re-enable.");
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
validateCronExpression(schedule, timezone);
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
fail(`invalid --cron/--timezone: ${err instanceof Error ? err.message : String(err)}`);
|
|
319
|
+
}
|
|
320
|
+
await prisma.agent.update({
|
|
321
|
+
where: { name: name },
|
|
322
|
+
data: { schedule, timezone, scheduleEnabled: true },
|
|
323
|
+
});
|
|
324
|
+
console.log(`schedule set for "${name}": "${schedule}" (${timezone}).`);
|
|
325
|
+
}
|
|
326
|
+
async function agentList() {
|
|
327
|
+
const agents = await prisma.agent.findMany({ orderBy: { name: "asc" } });
|
|
328
|
+
if (agents.length === 0) {
|
|
329
|
+
console.log("no agents registered.");
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
for (const agent of agents) {
|
|
333
|
+
const schedule = agent.schedule
|
|
334
|
+
? `${agent.scheduleEnabled ? "enabled" : "disabled"}: ${agent.schedule} (${agent.timezone})`
|
|
335
|
+
: "manual";
|
|
336
|
+
console.log(`${agent.name} ${agent.kind.padEnd(6)} ${agent.model} ` +
|
|
337
|
+
`$${Number(agent.budgetUsd).toFixed(4)} ${agent.maxTurns} turns memory ${agent.memoryEnabled ? "on" : "off"} ${schedule}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function run(name) {
|
|
341
|
+
if (!name) {
|
|
342
|
+
fail("run requires an agent name: wardby run <name>");
|
|
343
|
+
}
|
|
344
|
+
const agent = await prisma.agent.findUnique({ where: { name } });
|
|
345
|
+
if (!agent)
|
|
346
|
+
fail(`unknown agent "${name}".`);
|
|
347
|
+
if (agent.kind === "coding") {
|
|
348
|
+
fail("Coding agents are MCP-first: use trigger_agent so task input and ownership are recorded safely.");
|
|
349
|
+
}
|
|
350
|
+
const llm = buildLlmProvider();
|
|
351
|
+
const engine = buildEngine();
|
|
352
|
+
const secrets = buildSecrets();
|
|
353
|
+
const datastore = buildDatastore(secrets);
|
|
354
|
+
const memory = buildMemory();
|
|
355
|
+
let run;
|
|
356
|
+
try {
|
|
357
|
+
run = await runAgent(name, { llm, engine, datastore, secrets, memory }, prisma, (delta) => {
|
|
358
|
+
process.stdout.write(delta);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
363
|
+
}
|
|
364
|
+
process.stdout.write("\n");
|
|
365
|
+
const completedAgent = await prisma.agent.findUnique({ where: { id: run.agentId } });
|
|
366
|
+
const budgetUsd = completedAgent ? Number(completedAgent.budgetUsd) : NaN;
|
|
367
|
+
if (run.status === "succeeded" || run.status === "budget_exhausted") {
|
|
368
|
+
const marker = run.status === "succeeded" ? "✓" : "◐";
|
|
369
|
+
console.log(`${marker} run ${run.id} (${run.status}) — ${run.tokensIn} in / ${run.tokensOut} out — ` +
|
|
370
|
+
`$${Number(run.costUsd).toFixed(6)} (budget $${budgetUsd.toFixed(4)})`);
|
|
371
|
+
if (run.status === "budget_exhausted")
|
|
372
|
+
process.exitCode = 1;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
console.error(`✗ run ${run.id} — ${run.status}: ${run.error ?? "unknown error"}`);
|
|
376
|
+
process.exitCode = 1;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function noopExecutor() {
|
|
380
|
+
return { async start() { }, async stop() { } };
|
|
381
|
+
}
|
|
382
|
+
async function codingOps(args) {
|
|
383
|
+
const [operation, ...rest] = args;
|
|
384
|
+
const config = loadProviderConfig();
|
|
385
|
+
if (config.jobs !== "docker" && config.jobs !== "kubernetes") {
|
|
386
|
+
fail("coding operations require JOB_LAUNCHER=docker or kubernetes.");
|
|
387
|
+
}
|
|
388
|
+
const container = loadContainerExecutorConfig();
|
|
389
|
+
if (config.jobs === "kubernetes") {
|
|
390
|
+
if (!container.workerImage)
|
|
391
|
+
fail("CODING_WORKER_IMAGE is required when JOB_LAUNCHER=kubernetes.");
|
|
392
|
+
}
|
|
393
|
+
else if (!container.workerImage || !container.proxyContainer) {
|
|
394
|
+
fail("CODING_WORKER_IMAGE and CODING_PROXY_CONTAINER are required when JOB_LAUNCHER=docker.");
|
|
395
|
+
}
|
|
396
|
+
if (operation === "preflight" && config.jobs === "kubernetes") {
|
|
397
|
+
const kubernetes = loadKubernetesJobConfig();
|
|
398
|
+
let checks;
|
|
399
|
+
try {
|
|
400
|
+
const api = new ClientNodeKubernetesApi({ context: kubernetes.context });
|
|
401
|
+
checks = await kubernetesPreflight({
|
|
402
|
+
api,
|
|
403
|
+
config: kubernetes,
|
|
404
|
+
workerImage: container.workerImage,
|
|
405
|
+
maxDiskMb: container.maxDiskMb,
|
|
406
|
+
timeoutMs: kubernetes.preflightTimeoutMs,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
fail(`coding preflight failed: ${describePreflightFailure(error)}`);
|
|
411
|
+
}
|
|
412
|
+
console.log(`coding preflight passed (${checks.join(", ")}) for ${container.workerImage}`);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (operation === "preflight") {
|
|
416
|
+
if (!isImmutableDockerImage(container.workerImage)) {
|
|
417
|
+
fail("CODING_WORKER_IMAGE must use an immutable repository digest or local image ID.");
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
await execFile("docker", ["image", "inspect", container.workerImage], { maxBuffer: 1024 * 1024 });
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
fail(`Docker cannot inspect coding worker image "${container.workerImage}".`);
|
|
424
|
+
}
|
|
425
|
+
console.log(`coding preflight passed for ${container.workerImage}`);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (operation === "cleanup") {
|
|
429
|
+
const { values } = parseArgs({ args: rest, options: { "run-id": { type: "string" } } });
|
|
430
|
+
if (!values["run-id"])
|
|
431
|
+
fail("coding cleanup requires --run-id <id>.");
|
|
432
|
+
const executor = buildConfiguredExecutor({ native: noopExecutor(), db: prisma });
|
|
433
|
+
await executor.stop(values["run-id"], "operator cleanup");
|
|
434
|
+
console.log(`coding cleanup requested for run ${values["run-id"]}`);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
fail("coding requires preflight or cleanup --run-id <id>.");
|
|
438
|
+
}
|
|
439
|
+
async function listRuns(args) {
|
|
440
|
+
const { values } = parseArgs({
|
|
441
|
+
args,
|
|
442
|
+
options: {
|
|
443
|
+
agent: { type: "string" },
|
|
444
|
+
limit: { type: "string" },
|
|
445
|
+
status: { type: "string" },
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
const limit = values.limit ? Number(values.limit) : 20;
|
|
449
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
450
|
+
fail(`--limit must be a positive integer, got "${values.limit}".`);
|
|
451
|
+
}
|
|
452
|
+
if (values.status && !RUN_STATUSES.includes(values.status)) {
|
|
453
|
+
fail(`--status must be one of ${RUN_STATUSES.join(", ")}, got "${values.status}".`);
|
|
454
|
+
}
|
|
455
|
+
let agentId;
|
|
456
|
+
if (values.agent) {
|
|
457
|
+
const agent = await prisma.agent.findUnique({ where: { name: values.agent } });
|
|
458
|
+
if (!agent) {
|
|
459
|
+
fail(`unknown agent "${values.agent}".`);
|
|
460
|
+
}
|
|
461
|
+
agentId = agent.id;
|
|
462
|
+
}
|
|
463
|
+
const runs = await prisma.run.findMany({
|
|
464
|
+
where: {
|
|
465
|
+
...(agentId ? { agentId } : {}),
|
|
466
|
+
...(values.status ? { status: values.status } : {}),
|
|
467
|
+
},
|
|
468
|
+
include: { agent: true },
|
|
469
|
+
orderBy: { startedAt: "desc" },
|
|
470
|
+
take: limit,
|
|
471
|
+
});
|
|
472
|
+
if (runs.length === 0) {
|
|
473
|
+
console.log("no runs found.");
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
for (const r of runs) {
|
|
477
|
+
const finished = r.finishedAt ? r.finishedAt.toISOString() : "-";
|
|
478
|
+
console.log(`${r.id} ${r.agent.name.padEnd(20)} ${r.trigger.padEnd(9)} ${r.status.padEnd(9)} ` +
|
|
479
|
+
`${String(r.tokensIn).padStart(6)} in / ${String(r.tokensOut).padStart(6)} out ` +
|
|
480
|
+
`$${Number(r.costUsd).toFixed(6)} started ${r.startedAt.toISOString()} finished ${finished}`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
async function scheduler(args) {
|
|
484
|
+
const { values } = parseArgs({ args, options: { scope: { type: "string" } } });
|
|
485
|
+
const scope = values.scope ?? "default";
|
|
486
|
+
// Parsed before anything starts, so a malformed CODING_MAX_CONCURRENT or
|
|
487
|
+
// CODING_QUEUE_TIMEOUT_SEC fails fast.
|
|
488
|
+
const concurrency = loadCodingConcurrencyConfig();
|
|
489
|
+
const config = loadProviderConfig();
|
|
490
|
+
const llm = buildLlmProvider();
|
|
491
|
+
const engine = buildEngine();
|
|
492
|
+
const secrets = buildSecrets();
|
|
493
|
+
const datastore = buildDatastore(secrets);
|
|
494
|
+
const memory = buildMemory();
|
|
495
|
+
const nativeExecutor = buildExecutor(config, { llm, engine, datastore, secrets, memory }, prisma);
|
|
496
|
+
const executor = buildConfiguredExecutor({ native: nativeExecutor, db: prisma, providerConfig: config });
|
|
497
|
+
await executor.launch?.();
|
|
498
|
+
const reconciler = startReconciler({ db: prisma, executor });
|
|
499
|
+
const sched = startScheduler({
|
|
500
|
+
executor,
|
|
501
|
+
db: prisma,
|
|
502
|
+
scope,
|
|
503
|
+
onLeaderTick: async () => {
|
|
504
|
+
await drainCodingQueue({ db: prisma, executor, ...concurrency });
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
console.log(`wardby scheduler started (scope "${scope}"). Press Ctrl+C to stop.`);
|
|
508
|
+
await new Promise((resolve) => {
|
|
509
|
+
const shutdown = () => {
|
|
510
|
+
console.log("\nwardby scheduler shutting down...");
|
|
511
|
+
sched.stop();
|
|
512
|
+
reconciler.stop();
|
|
513
|
+
void Promise.resolve(executor.close?.())
|
|
514
|
+
.catch((err) => cliLog.warn({ err }, "executor close failed during scheduler shutdown"))
|
|
515
|
+
.finally(resolve);
|
|
516
|
+
};
|
|
517
|
+
process.once("SIGINT", shutdown);
|
|
518
|
+
process.once("SIGTERM", shutdown);
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
async function mcp() {
|
|
522
|
+
const handle = await startMcp();
|
|
523
|
+
// startMcp() resolves once the transport is up (bound/listening), not
|
|
524
|
+
// when it stops — block here the same way `scheduler` does, so main()'s
|
|
525
|
+
// `finally { prisma.$disconnect() }` doesn't tear the connection down
|
|
526
|
+
// out from under a server that's still supposed to be running.
|
|
527
|
+
//
|
|
528
|
+
// stderr, not stdout: in stdio mode stdout IS the JSON-RPC protocol
|
|
529
|
+
// stream (unlike `scheduler`, which owns no such stream), so a stray
|
|
530
|
+
// console.log here would corrupt every stdio-connected client.
|
|
531
|
+
console.error("wardby mcp started. Press Ctrl+C to stop.");
|
|
532
|
+
await new Promise((resolve) => {
|
|
533
|
+
const shutdown = () => {
|
|
534
|
+
console.error("\nwardby mcp shutting down...");
|
|
535
|
+
void Promise.resolve(handle.close())
|
|
536
|
+
.catch((err) => cliLog.warn({ err }, "mcp handle close failed during shutdown"))
|
|
537
|
+
.finally(resolve);
|
|
538
|
+
};
|
|
539
|
+
process.once("SIGINT", shutdown);
|
|
540
|
+
process.once("SIGTERM", shutdown);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
async function serve(args) {
|
|
544
|
+
const { values } = parseArgs({ args, options: { scope: { type: "string" } } });
|
|
545
|
+
const handle = await startServe({ scope: values.scope });
|
|
546
|
+
// stderr, like `mcp`: stdout must stay clean in case a future transport
|
|
547
|
+
// multiplexes it, and this keeps the two commands' output consistent.
|
|
548
|
+
console.error(`wardby serve started (scope "${values.scope ?? "default"}"). Press Ctrl+C to stop.`);
|
|
549
|
+
await new Promise((resolve) => {
|
|
550
|
+
const shutdown = () => {
|
|
551
|
+
console.error("\nwardby serve shutting down...");
|
|
552
|
+
void handle
|
|
553
|
+
.close()
|
|
554
|
+
.catch((err) => cliLog.warn({ err }, "serve close failed during shutdown"))
|
|
555
|
+
.finally(resolve);
|
|
556
|
+
};
|
|
557
|
+
process.once("SIGINT", shutdown);
|
|
558
|
+
process.once("SIGTERM", shutdown);
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
async function importCommand(rest) {
|
|
562
|
+
const opts = parseImportArgs(rest);
|
|
563
|
+
const { report, result } = await runImport({ ...opts, db: prisma, env: process.env });
|
|
564
|
+
console.log(report);
|
|
565
|
+
if (result) {
|
|
566
|
+
for (const w of result.webhookSecrets)
|
|
567
|
+
console.log(`webhook secret (${w.agentName}): ${w.secret}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function main() {
|
|
571
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
572
|
+
try {
|
|
573
|
+
if (command === "auth") {
|
|
574
|
+
await authCommand(rest, prisma, process.env.AUTH_CREDENTIAL_HASH_KEY ?? "");
|
|
575
|
+
}
|
|
576
|
+
else if (command === "agent" && rest[0] === "create") {
|
|
577
|
+
await agentCreate(rest.slice(1));
|
|
578
|
+
}
|
|
579
|
+
else if (command === "agent" && rest[0] === "list") {
|
|
580
|
+
await agentList();
|
|
581
|
+
}
|
|
582
|
+
else if (command === "agent" && rest[0] === "schedule") {
|
|
583
|
+
await agentSchedule(rest.slice(1));
|
|
584
|
+
}
|
|
585
|
+
else if (command === "tool" && rest[0] === "create") {
|
|
586
|
+
await toolCreate(rest.slice(1));
|
|
587
|
+
}
|
|
588
|
+
else if (command === "tool" && rest[0] === "attach") {
|
|
589
|
+
await toolAttach(rest.slice(1), false);
|
|
590
|
+
}
|
|
591
|
+
else if (command === "tool" && rest[0] === "detach") {
|
|
592
|
+
await toolAttach(rest.slice(1), true);
|
|
593
|
+
}
|
|
594
|
+
else if (command === "tool" && rest[0] === "list") {
|
|
595
|
+
await toolList(rest.slice(1));
|
|
596
|
+
}
|
|
597
|
+
else if (command === "run") {
|
|
598
|
+
await run(rest[0]);
|
|
599
|
+
}
|
|
600
|
+
else if (command === "runs") {
|
|
601
|
+
await listRuns(rest);
|
|
602
|
+
}
|
|
603
|
+
else if (command === "coding") {
|
|
604
|
+
await codingOps(rest);
|
|
605
|
+
}
|
|
606
|
+
else if (command === "scheduler") {
|
|
607
|
+
await scheduler(rest);
|
|
608
|
+
}
|
|
609
|
+
else if (command === "mcp") {
|
|
610
|
+
await mcp();
|
|
611
|
+
}
|
|
612
|
+
else if (command === "serve") {
|
|
613
|
+
await serve(rest);
|
|
614
|
+
}
|
|
615
|
+
else if (command === "import") {
|
|
616
|
+
await importCommand(rest);
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
fail(CLI_USAGE);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
finally {
|
|
623
|
+
await prisma.$disconnect();
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
main().catch((err) => {
|
|
627
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
628
|
+
process.exit(1);
|
|
629
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata-only lifecycle telemetry for coding runs. Keep untrusted task and
|
|
3
|
+
* repository data out of this boundary so log retention cannot become source
|
|
4
|
+
* retention by accident.
|
|
5
|
+
*/
|
|
6
|
+
export type CodingLifecycleStage = "queued" | "prepared" | "launched" | "running" | "budget_cutoff" | "stopping" | "collected" | "pull_request_opened" | "pull_request_updated" | "terminal" | "cleanup";
|
|
7
|
+
export interface CodingLifecycleEvent {
|
|
8
|
+
stage: CodingLifecycleStage;
|
|
9
|
+
runId: string;
|
|
10
|
+
/** Opaque launcher handle, never a container command line or environment. */
|
|
11
|
+
jobId?: string;
|
|
12
|
+
outcome?: "succeeded" | "failed" | "refused" | "lost" | "budget_exhausted" | "cancelled";
|
|
13
|
+
failureCategory?: string;
|
|
14
|
+
diagnosticId?: string;
|
|
15
|
+
durationMs?: number;
|
|
16
|
+
budgetReservedUsd?: number;
|
|
17
|
+
budgetActualUsd?: number;
|
|
18
|
+
cleanupSucceeded?: boolean;
|
|
19
|
+
/** Enumerated execution metadata only; never a model request or source field. */
|
|
20
|
+
workerProvider?: "codex" | "claude-code";
|
|
21
|
+
proxyProtocol?: "openai-responses" | "anthropic-messages";
|
|
22
|
+
}
|
|
23
|
+
export interface CodingRunObserver {
|
|
24
|
+
emit(event: CodingLifecycleEvent): void;
|
|
25
|
+
}
|
|
26
|
+
export interface CodingMetricsSnapshot {
|
|
27
|
+
stages: Record<CodingLifecycleStage, number>;
|
|
28
|
+
terminalOutcomes: Record<string, number>;
|
|
29
|
+
activeJobs: number;
|
|
30
|
+
cleanupFailures: number;
|
|
31
|
+
budgetReservedUsd: number;
|
|
32
|
+
budgetActualUsd: number;
|
|
33
|
+
runtimeMsTotal: number;
|
|
34
|
+
}
|
|
35
|
+
/** A small exporter-neutral aggregate that monitoring adapters can scrape or forward. */
|
|
36
|
+
export declare class CodingMetrics implements CodingRunObserver {
|
|
37
|
+
private readonly stages;
|
|
38
|
+
private readonly terminalOutcomes;
|
|
39
|
+
private activeJobs;
|
|
40
|
+
private cleanupFailures;
|
|
41
|
+
private budgetReservedUsd;
|
|
42
|
+
private budgetActualUsd;
|
|
43
|
+
private runtimeMsTotal;
|
|
44
|
+
emit(event: CodingLifecycleEvent): void;
|
|
45
|
+
snapshot(): CodingMetricsSnapshot;
|
|
46
|
+
}
|
|
47
|
+
export declare class PinoCodingRunObserver implements CodingRunObserver {
|
|
48
|
+
private readonly metrics;
|
|
49
|
+
constructor(metrics?: CodingMetrics);
|
|
50
|
+
emit(event: CodingLifecycleEvent): void;
|
|
51
|
+
snapshot(): CodingMetricsSnapshot;
|
|
52
|
+
}
|
|
53
|
+
/** Default application observer. Production log infrastructure owns retention. */
|
|
54
|
+
export declare const codingRunObserver: PinoCodingRunObserver;
|
|
55
|
+
export declare class InMemoryCodingRunObserver implements CodingRunObserver {
|
|
56
|
+
readonly events: CodingLifecycleEvent[];
|
|
57
|
+
readonly metrics: CodingMetrics;
|
|
58
|
+
emit(event: CodingLifecycleEvent): void;
|
|
59
|
+
}
|