@wardby/cli 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +33 -0
- package/README.md +25 -14
- package/dist/claude-coding-worker/context.d.ts +22 -0
- package/dist/claude-coding-worker/context.js +92 -0
- package/dist/claude-coding-worker/driver.d.ts +7 -1
- package/dist/claude-coding-worker/driver.js +38 -5
- package/dist/claude-coding-worker/sdk.js +13 -4
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +5 -2
- package/dist/cli-native-mode.d.ts +9 -0
- package/dist/cli-native-mode.js +20 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +141 -5
- package/dist/coding/claude-context.d.ts +45 -0
- package/dist/coding/claude-context.js +434 -0
- package/dist/coding/profile.d.ts +12 -0
- package/dist/coding/profile.js +6 -0
- package/dist/coding/protocol.d.ts +104 -0
- package/dist/coding/protocol.js +87 -3
- package/dist/coding-worker/artifact.d.ts +8 -0
- package/dist/coding-worker/artifact.js +2 -2
- package/dist/coding-worker/driver.js +2 -0
- package/dist/coding-worker/sdk.d.ts +6 -0
- package/dist/coding-worker/sdk.js +1 -0
- package/dist/coding-worker/skills.d.ts +23 -0
- package/dist/coding-worker/skills.js +117 -0
- package/dist/coding-worker/types.d.ts +2 -0
- package/dist/config/github-allowed-accounts.d.ts +15 -0
- package/dist/config/github-allowed-accounts.js +36 -0
- package/dist/config/low-power.d.ts +12 -0
- package/dist/config/low-power.js +18 -0
- package/dist/config/mobile.d.ts +12 -0
- package/dist/config/mobile.js +18 -0
- package/dist/config/providers.d.ts +53 -0
- package/dist/config/providers.js +92 -6
- package/dist/core/db.d.ts +16 -6
- package/dist/core/db.js +12 -10
- package/dist/core/dispatch.d.ts +11 -0
- package/dist/core/dispatch.js +36 -1
- package/dist/core/engine-native.js +9 -5
- package/dist/core/host-events.d.ts +49 -3
- package/dist/core/host-events.js +289 -15
- package/dist/core/issue-bridge.js +42 -2
- package/dist/core/issue-events.js +12 -1
- package/dist/core/issue-status.js +14 -3
- package/dist/core/merge-order-check.d.ts +129 -0
- package/dist/core/merge-order-check.js +336 -0
- package/dist/core/notification-dispatcher.d.ts +70 -0
- package/dist/core/notification-dispatcher.js +368 -0
- package/dist/core/notification-templates.d.ts +25 -0
- package/dist/core/notification-templates.js +105 -0
- package/dist/core/notifications.d.ts +10 -0
- package/dist/core/notifications.js +38 -0
- package/dist/core/pg-auth.d.ts +22 -0
- package/dist/core/pg-auth.js +152 -0
- package/dist/core/power-composition.d.ts +16 -0
- package/dist/core/power-composition.js +37 -0
- package/dist/core/power-idle.d.ts +14 -0
- package/dist/core/power-idle.js +30 -0
- package/dist/core/power.d.ts +71 -0
- package/dist/core/power.js +202 -0
- package/dist/core/reconciler.d.ts +4 -2
- package/dist/core/reconciler.js +29 -5
- package/dist/core/related-pull-requests.d.ts +48 -4
- package/dist/core/related-pull-requests.js +113 -11
- package/dist/core/repo-access.d.ts +15 -0
- package/dist/core/repo-access.js +66 -0
- package/dist/core/review-fix.d.ts +37 -0
- package/dist/core/review-fix.js +207 -6
- package/dist/core/review-host-tools.d.ts +20 -0
- package/dist/core/review-host-tools.js +58 -2
- package/dist/core/runner.d.ts +336 -3
- package/dist/core/runner.js +894 -317
- package/dist/core/secret-broker-config.d.ts +103 -0
- package/dist/core/secret-broker-config.js +112 -0
- package/dist/core/secrets.d.ts +39 -4
- package/dist/core/secrets.js +148 -40
- package/dist/core/workflow-event-recorder.d.ts +14 -0
- package/dist/core/workflow-event-recorder.js +120 -0
- package/dist/core/workflow-events.d.ts +82 -0
- package/dist/core/workflow-events.js +44 -0
- package/dist/core/workflow-run-events.d.ts +16 -0
- package/dist/core/workflow-run-events.js +40 -0
- package/dist/generated/prisma/browser.d.ts +58 -0
- package/dist/generated/prisma/client.d.ts +58 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +150 -0
- package/dist/generated/prisma/enums.d.ts +27 -0
- package/dist/generated/prisma/enums.js +23 -0
- package/dist/generated/prisma/internal/class.d.ts +88 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +772 -1
- package/dist/generated/prisma/internal/prismaNamespace.js +135 -4
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +139 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +135 -4
- package/dist/generated/prisma/models/Agent.d.ts +360 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +73 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +205 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +78 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +1675 -0
- package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1517 -0
- package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
- package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
- package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
- package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
- package/dist/generated/prisma/models/NotificationChannel.js +1 -0
- package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
- package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
- package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
- package/dist/generated/prisma/models/NotificationThread.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +826 -1
- package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
- package/dist/generated/prisma/models/Secret.d.ts +37 -1
- package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
- package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
- package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
- package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
- package/dist/generated/prisma/models.d.ts +8 -0
- package/dist/help/build.js +4 -2
- package/dist/help/catalog.d.ts +1 -1
- package/dist/help/catalog.js +31 -6
- package/dist/help-index.json +1363 -176
- package/dist/import/create.js +17 -0
- package/dist/import/neutral-schema.d.ts +6 -2
- package/dist/import/neutral-schema.js +2 -0
- package/dist/mcp/auth/access.d.ts +1 -0
- package/dist/mcp/auth/repo-authorization.js +14 -0
- package/dist/mcp/auth/resource-server.d.ts +2 -1
- package/dist/mcp/auth/resource-server.js +7 -2
- package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/browser.js +19 -6
- package/dist/mcp/context.d.ts +6 -0
- package/dist/mcp/host-events/github-ingress.d.ts +23 -1
- package/dist/mcp/host-events/github-ingress.js +68 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +59 -10
- package/dist/mcp/tools/agents.js +82 -11
- package/dist/mcp/tools/notification-channels.d.ts +2 -0
- package/dist/mcp/tools/notification-channels.js +293 -0
- package/dist/mcp/tools/power.d.ts +2 -0
- package/dist/mcp/tools/power.js +77 -0
- package/dist/mcp/tools/runs.d.ts +0 -6
- package/dist/mcp/tools/runs.js +7 -2
- package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
- package/dist/mcp/tools/secret-broker-compat.js +23 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
- package/dist/mcp/tools/secret-elicitation-form.js +200 -10
- package/dist/mcp/tools/secret-elicitation-server.js +8 -1
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
- package/dist/mcp/tools/secret-elicitation.js +110 -12
- package/dist/mcp/tools/secrets.js +184 -7
- package/dist/mcp/tools/tools.d.ts +1 -1
- package/dist/mcp/tools/tools.js +22 -2
- package/dist/native-worker/composition.d.ts +23 -0
- package/dist/native-worker/composition.js +77 -0
- package/dist/native-worker/docker-isolation.d.ts +65 -0
- package/dist/native-worker/docker-isolation.js +183 -0
- package/dist/native-worker/docker-launcher.d.ts +74 -0
- package/dist/native-worker/docker-launcher.js +237 -0
- package/dist/native-worker/gateway-server.d.ts +39 -0
- package/dist/native-worker/gateway-server.js +315 -0
- package/dist/native-worker/gateway.d.ts +44 -0
- package/dist/native-worker/gateway.js +197 -0
- package/dist/native-worker/http-server.d.ts +22 -0
- package/dist/native-worker/http-server.js +109 -0
- package/dist/native-worker/http-transport.d.ts +17 -0
- package/dist/native-worker/http-transport.js +88 -0
- package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
- package/dist/native-worker/kubernetes-isolation.js +218 -0
- package/dist/native-worker/kubernetes-launcher.d.ts +102 -0
- package/dist/native-worker/kubernetes-launcher.js +335 -0
- package/dist/native-worker/launch.d.ts +45 -0
- package/dist/native-worker/launch.js +44 -0
- package/dist/native-worker/ledger.d.ts +109 -0
- package/dist/native-worker/ledger.js +192 -0
- package/dist/native-worker/loopback.d.ts +12 -0
- package/dist/native-worker/loopback.js +49 -0
- package/dist/native-worker/main.d.ts +7 -0
- package/dist/native-worker/main.js +74 -0
- package/dist/native-worker/protocol.d.ts +744 -0
- package/dist/native-worker/protocol.js +200 -0
- package/dist/native-worker/sandbox-executor.d.ts +68 -0
- package/dist/native-worker/sandbox-executor.js +210 -0
- package/dist/native-worker/stdio.d.ts +29 -0
- package/dist/native-worker/stdio.js +188 -0
- package/dist/native-worker/warm-delivery.d.ts +16 -0
- package/dist/native-worker/warm-delivery.js +33 -0
- package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
- package/dist/native-worker/warm-pool-ledger.js +73 -0
- package/dist/native-worker/warm-pool.d.ts +107 -0
- package/dist/native-worker/warm-pool.js +283 -0
- package/dist/native-worker/worker.d.ts +17 -0
- package/dist/native-worker/worker.js +115 -0
- package/dist/providers/auth/authorization-server.d.ts +3 -0
- package/dist/providers/auth/index.js +2 -0
- package/dist/providers/auth/self-hosted.d.ts +13 -1
- package/dist/providers/auth/self-hosted.js +54 -4
- package/dist/providers/chat/fake.d.ts +46 -0
- package/dist/providers/chat/fake.js +39 -0
- package/dist/providers/chat/index.d.ts +4 -0
- package/dist/providers/chat/index.js +8 -0
- package/dist/providers/chat/slack.d.ts +37 -0
- package/dist/providers/chat/slack.js +105 -0
- package/dist/providers/chat/types.d.ts +42 -0
- package/dist/providers/chat/types.js +19 -0
- package/dist/providers/engine/types.d.ts +19 -0
- package/dist/providers/engine/types.js +22 -0
- package/dist/providers/executor/composition.d.ts +24 -1
- package/dist/providers/executor/composition.js +39 -6
- package/dist/providers/executor/container.d.ts +24 -1
- package/dist/providers/executor/container.js +101 -11
- package/dist/providers/executor/dbos.d.ts +42 -0
- package/dist/providers/executor/dbos.js +118 -12
- package/dist/providers/executor/deferred.d.ts +56 -0
- package/dist/providers/executor/deferred.js +119 -0
- package/dist/providers/executor/routing.d.ts +37 -10
- package/dist/providers/executor/routing.js +73 -32
- package/dist/providers/executor/types.d.ts +12 -0
- package/dist/providers/jobs/docker.js +3 -3
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +21 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +42 -1
- package/dist/providers/jobs/kubernetes-api.d.ts +17 -1
- package/dist/providers/jobs/kubernetes-api.js +7 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
- package/dist/providers/jobs/kubernetes-client.js +52 -3
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +3 -1
- package/dist/providers/jobs/kubernetes-isolation.js +6 -0
- package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
- package/dist/providers/jobs/kubernetes-platform.js +38 -1
- package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
- package/dist/providers/jobs/kubernetes-preflight.js +4 -2
- package/dist/providers/jobs/kubernetes.d.ts +36 -1
- package/dist/providers/jobs/kubernetes.js +74 -4
- package/dist/providers/jobs/metadata-probes.d.ts +11 -0
- package/dist/providers/jobs/metadata-probes.js +13 -0
- package/dist/providers/jobs/types.d.ts +9 -0
- package/dist/providers/review-host/github.d.ts +11 -1
- package/dist/providers/review-host/github.js +50 -0
- package/dist/providers/review-host/types.d.ts +23 -0
- package/dist/providers/vcs/github.d.ts +32 -6
- package/dist/providers/vcs/github.js +74 -16
- package/dist/quickstart/coding-seed.d.ts +10 -3
- package/dist/quickstart/coding-seed.js +74 -3
- package/dist/quickstart/images.d.ts +2 -0
- package/dist/quickstart/images.js +7 -1
- package/dist/quickstart/reviewer-prompt.d.ts +1 -1
- package/dist/quickstart/reviewer-prompt.js +1 -1
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/brokered-fetch.d.ts +23 -0
- package/dist/sandbox/brokered-fetch.js +37 -0
- package/dist/sandbox/host-functions.d.ts +34 -0
- package/dist/sandbox/host-functions.js +144 -80
- package/dist/sandbox/prelude.js +7 -1
- package/dist/sandbox/run-in-sandbox.d.ts +19 -0
- package/dist/sandbox/run-in-sandbox.js +28 -10
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +3 -1
- package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
- package/dist/sandbox/secret-broker-sigv4.js +49 -0
- package/dist/sandbox/secret-broker.d.ts +34 -0
- package/dist/sandbox/secret-broker.js +162 -0
- package/dist/sandbox/user-tool.d.ts +14 -0
- package/dist/sandbox/user-tool.js +32 -0
- package/dist/serve.js +18 -0
- package/dist/viewer/api-schema.d.ts +210 -14
- package/dist/viewer/api-schema.js +22 -0
- package/dist/viewer/build-schemas.js +4 -1
- package/dist/viewer/event-bus.d.ts +6 -0
- package/dist/viewer/event-bus.js +16 -7
- package/dist/viewer/graph.d.ts +5 -2
- package/dist/viewer/graph.js +7 -2
- package/dist/viewer/http.d.ts +0 -1
- package/dist/viewer/http.js +2 -2
- package/dist/viewer/infra.js +25 -2
- package/dist/viewer/limits.d.ts +4 -0
- package/dist/viewer/limits.js +4 -0
- package/dist/viewer/openapi.d.ts +15 -0
- package/dist/viewer/openapi.js +172 -0
- package/docs/README.md +7 -0
- package/docs/agent-recipes.md +57 -8
- package/docs/architecture-runtime.md +16 -1
- package/docs/code-review-agents.md +139 -5
- package/docs/coding-agent-setup.md +113 -5
- package/docs/coding-packages.md +4 -2
- package/docs/coding-services.md +3 -1
- package/docs/coding-worker-byo-images.md +198 -6
- package/docs/coding-worker-isolation.md +68 -14
- package/docs/getting-started-gke.md +225 -9
- package/docs/getting-started-identity-provider.md +21 -10
- package/docs/getting-started.md +5 -4
- package/docs/jira-agents.md +5 -1
- package/docs/native-sandbox.md +635 -0
- package/docs/release-verification.md +9 -0
- package/docs/security-deployment.md +113 -12
- package/docs/slack-notifications.md +252 -0
- package/docs/tool-secrets.md +252 -0
- package/docs/viewer-api.md +46 -5
- package/docs/viewer-api.openapi.yml +1404 -0
- package/help/admin-viewer.md +6 -2
- package/help/agent-recipes.md +27 -0
- package/help/architecture-agent.md +1 -1
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +3 -6
- package/help/code-review-agents.md +68 -6
- package/help/deploy-gke.md +8 -1
- package/help/deployment-targets.md +25 -14
- package/help/errors/coding-provider-not-configured.md +2 -2
- package/help/errors/database-auth-invalid.md +28 -0
- package/help/errors/github-account-not-allowed.md +25 -0
- package/help/errors/low-power-disabled.md +29 -0
- package/help/errors/low-power-scale-forbidden.md +35 -0
- package/help/errors/low-power-wake-timeout.md +30 -0
- package/help/errors/mobile-disabled.md +31 -0
- package/help/errors/native-sandbox-capacity.md +22 -0
- package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
- package/help/errors/native-sandbox-docker-failed.md +20 -0
- package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
- package/help/errors/native-sandbox-image-not-pinned.md +19 -0
- package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
- package/help/errors/native-sandbox-network-unenforced.md +22 -0
- package/help/errors/native-sandbox-requires-catalog.md +31 -0
- package/help/errors/native-sandbox-unavailable.md +19 -0
- package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +20 -0
- package/help/errors/native-sandbox-worker-lost.md +20 -0
- package/help/errors/native-sandbox-worker-unready.md +22 -0
- package/help/errors/secret-broker-body-invalid.md +26 -0
- package/help/errors/secret-broker-changed.md +20 -0
- package/help/errors/secret-broker-config-invalid.md +30 -0
- package/help/errors/secret-broker-conflict.md +27 -0
- package/help/errors/secret-broker-destination-denied.md +28 -0
- package/help/errors/secret-broker-value-invalid.md +28 -0
- package/help/errors/secret-brokered.md +24 -0
- package/help/errors/secret-not-brokered.md +25 -0
- package/help/errors/slack-auth-failed.md +48 -0
- package/help/errors/slack-channel-unreachable.md +39 -0
- package/help/errors/slack-not-configured.md +33 -0
- package/help/getting-started.md +4 -5
- package/help/github.md +18 -1
- package/help/identity-and-access.md +5 -1
- package/help/local-repositories.md +2 -3
- package/help/low-power-mode.md +125 -0
- package/help/merge-order-check.md +117 -0
- package/help/mobile-app.md +54 -0
- package/help/native-sandbox.md +136 -0
- package/help/observability.md +8 -0
- package/help/related-pull-requests.md +70 -9
- package/help/repo-instructions-and-skills.md +91 -0
- package/help/review-fix-rounds.md +10 -0
- package/help/slack-notifications.md +62 -0
- package/help/troubleshooting/coding-workers.md +21 -0
- package/package.json +11 -4
- package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
- package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
- package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
- package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
- package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
- package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
- package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
- package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
- package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
- package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
- package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
- package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
- package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
- package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
- package/prisma/schema.prisma +362 -91
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collects the Claude Code context a repository ships for itself, so a coding
|
|
3
|
+
* run can hand it to the worker: the instruction files (`CLAUDE.md`,
|
|
4
|
+
* `.claude/CLAUDE.md`, and the files they pull in with `@path` imports) and,
|
|
5
|
+
* when repository skills are enabled, each `.claude/skills/<name>/SKILL.md`.
|
|
6
|
+
*
|
|
7
|
+
* Only those files are read, and every one must pass `isAllowedContextPath`
|
|
8
|
+
* (an import of anything else, such as `.claude/settings.json`, `.mcp.json`,
|
|
9
|
+
* `CLAUDE.local.md`, or a non-Markdown file, is skipped as `not_allowed`).
|
|
10
|
+
* Repository settings, hooks, MCP configuration, agents, and commands under
|
|
11
|
+
* `.claude/` are never collected.
|
|
12
|
+
*
|
|
13
|
+
* Repository content is untrusted, so the reader is deliberately strict:
|
|
14
|
+
* - every path must stay inside the workspace (no absolute, `~`, or `..`
|
|
15
|
+
* imports, nothing under `.git/`);
|
|
16
|
+
* - symlinks are refused, both the file itself and any directory on the way
|
|
17
|
+
* to it, so a link cannot pull in a file from outside the checkout;
|
|
18
|
+
* - only regular, valid UTF-8 files of at most 64 KiB are read, at most 200
|
|
19
|
+
* files and 256 KiB in total; `@imports` are followed at most 5 levels deep.
|
|
20
|
+
*
|
|
21
|
+
* A file that breaks a rule is left out and reported in `skipped` with the
|
|
22
|
+
* reason (the first 50; further ones are only counted in `skippedOverflow`,
|
|
23
|
+
* as are imports beyond the first 100 of a file, which are not followed);
|
|
24
|
+
* nothing a repository contains makes this function throw.
|
|
25
|
+
*
|
|
26
|
+
* If a repository has no `CLAUDE.md` or `.claude/CLAUDE.md` but does have an
|
|
27
|
+
* `AGENTS.md`, a one-line `CLAUDE.md` that imports it is synthesized, so
|
|
28
|
+
* repositories written for other coding agents still get their instructions.
|
|
29
|
+
*/
|
|
30
|
+
import { constants } from "node:fs";
|
|
31
|
+
import { lstat, open, opendir, realpath } from "node:fs/promises";
|
|
32
|
+
import { join, posix } from "node:path";
|
|
33
|
+
import { CLAUDE_CONTEXT_LIMITS, isAllowedContextPath, isSafeContextPath } from "./protocol.js";
|
|
34
|
+
/** Content of the `CLAUDE.md` synthesized for a repository that only has `AGENTS.md`. */
|
|
35
|
+
export const AGENTS_BRIDGE = "@AGENTS.md\n";
|
|
36
|
+
const ROOTS = ["CLAUDE.md", ".claude/CLAUDE.md"];
|
|
37
|
+
const SKILLS_DIR = ".claude/skills";
|
|
38
|
+
const MAX_IMPORT_DEPTH = 5;
|
|
39
|
+
/** At most this many `skipped` entries are recorded; the rest are only counted in `skippedOverflow`. */
|
|
40
|
+
export const MAX_RECORDED_SKIPS = 50;
|
|
41
|
+
/** Only the first this-many distinct `@imports` of each file are followed; the rest are counted in `skippedOverflow`. */
|
|
42
|
+
export const MAX_IMPORTS_PER_FILE = 100;
|
|
43
|
+
/**
|
|
44
|
+
* At most this many `.claude/skills` entries are considered (matching the Codex worker's scan cap);
|
|
45
|
+
* if there are more, the rest are neither read nor counted beyond adding one to `skippedOverflow`.
|
|
46
|
+
*/
|
|
47
|
+
export const MAX_SKILL_ENTRIES = 2000;
|
|
48
|
+
const FENCE = /^ {0,3}(`{3,}|~{3,})/;
|
|
49
|
+
const IMPORT = /(?:^|\s)@([^\s`]+)/gm;
|
|
50
|
+
const TRAILING_PUNCTUATION = new Set([".", ",", ";", ":", ")"]);
|
|
51
|
+
/**
|
|
52
|
+
* Removes inline code spans from one paragraph in a single linear pass. A run
|
|
53
|
+
* of backticks opens a span that ends at the next run of exactly the same
|
|
54
|
+
* length; a run with no closing partner is kept as literal text. Spans never
|
|
55
|
+
* cross paragraphs because the caller passes one paragraph at a time.
|
|
56
|
+
*/
|
|
57
|
+
function stripInlineCode(paragraph) {
|
|
58
|
+
const runs = [];
|
|
59
|
+
for (let i = 0; i < paragraph.length;) {
|
|
60
|
+
if (paragraph[i] !== "`") {
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const start = i;
|
|
65
|
+
while (i < paragraph.length && paragraph[i] === "`")
|
|
66
|
+
i++;
|
|
67
|
+
runs.push({ start, end: i });
|
|
68
|
+
}
|
|
69
|
+
if (runs.length === 0)
|
|
70
|
+
return paragraph;
|
|
71
|
+
// Indexes of the runs of each length, in order, with a pointer that only
|
|
72
|
+
// moves forward, so finding every closer costs linear time overall.
|
|
73
|
+
const byLength = new Map();
|
|
74
|
+
runs.forEach((run, index) => {
|
|
75
|
+
const length = run.end - run.start;
|
|
76
|
+
const entry = byLength.get(length) ?? { indexes: [], next: 0 };
|
|
77
|
+
entry.indexes.push(index);
|
|
78
|
+
byLength.set(length, entry);
|
|
79
|
+
});
|
|
80
|
+
let output = "";
|
|
81
|
+
let copied = 0;
|
|
82
|
+
for (let i = 0; i < runs.length;) {
|
|
83
|
+
const entry = byLength.get(runs[i].end - runs[i].start);
|
|
84
|
+
while (entry.next < entry.indexes.length && entry.indexes[entry.next] <= i)
|
|
85
|
+
entry.next++;
|
|
86
|
+
if (entry.next >= entry.indexes.length) {
|
|
87
|
+
i++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const closer = entry.indexes[entry.next];
|
|
91
|
+
output += paragraph.slice(copied, runs[i].start);
|
|
92
|
+
copied = runs[closer].end;
|
|
93
|
+
i = closer + 1;
|
|
94
|
+
}
|
|
95
|
+
return output + paragraph.slice(copied);
|
|
96
|
+
}
|
|
97
|
+
function trimTrailingPunctuation(token) {
|
|
98
|
+
let end = token.length;
|
|
99
|
+
while (end > 0 && TRAILING_PUNCTUATION.has(token[end - 1]))
|
|
100
|
+
end--;
|
|
101
|
+
return token.slice(0, end);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns the `@path` imports in a Markdown instruction file, in order and
|
|
105
|
+
* de-duplicated. Imports inside fenced code blocks and inline code spans are
|
|
106
|
+
* ignored, as is an `@` not preceded by whitespace (an e-mail address). Runs
|
|
107
|
+
* in time linear in the input, whatever the repository puts in it.
|
|
108
|
+
*/
|
|
109
|
+
export function importsOf(markdown) {
|
|
110
|
+
const paragraphs = [];
|
|
111
|
+
let paragraph = [];
|
|
112
|
+
const endParagraph = () => {
|
|
113
|
+
if (paragraph.length > 0)
|
|
114
|
+
paragraphs.push(stripInlineCode(paragraph.join("\n")));
|
|
115
|
+
paragraph = [];
|
|
116
|
+
};
|
|
117
|
+
let fence;
|
|
118
|
+
for (const line of markdown.split("\n")) {
|
|
119
|
+
const marker = FENCE.exec(line)?.[1];
|
|
120
|
+
if (fence !== undefined) {
|
|
121
|
+
if (marker !== undefined && marker[0] === fence[0] && marker.length >= fence.length)
|
|
122
|
+
fence = undefined;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (marker !== undefined) {
|
|
126
|
+
endParagraph();
|
|
127
|
+
fence = marker;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (line.trim() === "")
|
|
131
|
+
endParagraph();
|
|
132
|
+
else
|
|
133
|
+
paragraph.push(line);
|
|
134
|
+
}
|
|
135
|
+
endParagraph();
|
|
136
|
+
const found = new Set();
|
|
137
|
+
for (const text of paragraphs) {
|
|
138
|
+
for (const match of text.matchAll(IMPORT)) {
|
|
139
|
+
const target = trimTrailingPunctuation(match[1]);
|
|
140
|
+
if (target.length > 0)
|
|
141
|
+
found.add(target);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return [...found];
|
|
145
|
+
}
|
|
146
|
+
function isMissing(error) {
|
|
147
|
+
const code = error.code;
|
|
148
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
149
|
+
}
|
|
150
|
+
/** Maps a filesystem error on repository content to a skip reason (or "absent"). */
|
|
151
|
+
function failure(error) {
|
|
152
|
+
if (isMissing(error))
|
|
153
|
+
return { kind: "absent" };
|
|
154
|
+
if (error.code === "ELOOP")
|
|
155
|
+
return { kind: "skip", reason: "symlink" };
|
|
156
|
+
return { kind: "skip", reason: "not_file" };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Checks `rel` without reading it: every directory from the workspace down
|
|
160
|
+
* must be a real directory (a symlink is refused), and the file itself must be
|
|
161
|
+
* a regular file no larger than the per-file limit.
|
|
162
|
+
*/
|
|
163
|
+
async function inspect(workspace, rel) {
|
|
164
|
+
const segments = rel.split("/");
|
|
165
|
+
let current = workspace;
|
|
166
|
+
for (const segment of segments.slice(0, -1)) {
|
|
167
|
+
current = join(current, segment);
|
|
168
|
+
let stats;
|
|
169
|
+
try {
|
|
170
|
+
stats = await lstat(current);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return failure(error);
|
|
174
|
+
}
|
|
175
|
+
if (stats.isSymbolicLink())
|
|
176
|
+
return { kind: "skip", reason: "symlink" };
|
|
177
|
+
if (!stats.isDirectory())
|
|
178
|
+
return { kind: "absent" };
|
|
179
|
+
}
|
|
180
|
+
let stats;
|
|
181
|
+
try {
|
|
182
|
+
stats = await lstat(join(workspace, rel));
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
return failure(error);
|
|
186
|
+
}
|
|
187
|
+
if (stats.isSymbolicLink())
|
|
188
|
+
return { kind: "skip", reason: "symlink" };
|
|
189
|
+
if (!stats.isFile())
|
|
190
|
+
return { kind: "skip", reason: "not_file" };
|
|
191
|
+
if (stats.size > CLAUDE_CONTEXT_LIMITS.maxFileBytes)
|
|
192
|
+
return { kind: "skip", reason: "too_large" };
|
|
193
|
+
return { kind: "file", stats };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Reads a file that `inspect` accepted, re-checking against the open handle so
|
|
197
|
+
* a swap between the check and the read is caught: O_NOFOLLOW refuses a final
|
|
198
|
+
* symlink, the descriptor must be the inode that was inspected, the resolved
|
|
199
|
+
* path must still sit at the same place inside the workspace (no directory on
|
|
200
|
+
* the way became a symlink), and no more than the per-file limit is read even
|
|
201
|
+
* if the file grew.
|
|
202
|
+
*/
|
|
203
|
+
async function readChecked(realWorkspace, workspace, rel, inspected) {
|
|
204
|
+
const absolute = join(workspace, rel);
|
|
205
|
+
let handle;
|
|
206
|
+
try {
|
|
207
|
+
handle = await open(absolute, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
return failure(error);
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const stats = await handle.stat();
|
|
214
|
+
if (!stats.isFile())
|
|
215
|
+
return { kind: "skip", reason: "not_file" };
|
|
216
|
+
if (stats.ino !== inspected.ino || stats.dev !== inspected.dev)
|
|
217
|
+
return { kind: "skip", reason: "symlink" };
|
|
218
|
+
if ((await realpath(absolute)) !== join(realWorkspace, rel))
|
|
219
|
+
return { kind: "skip", reason: "symlink" };
|
|
220
|
+
const limit = CLAUDE_CONTEXT_LIMITS.maxFileBytes;
|
|
221
|
+
const buffer = Buffer.alloc(limit + 1);
|
|
222
|
+
let length = 0;
|
|
223
|
+
while (length < buffer.length) {
|
|
224
|
+
const { bytesRead } = await handle.read(buffer, length, buffer.length - length, length);
|
|
225
|
+
if (bytesRead === 0)
|
|
226
|
+
break;
|
|
227
|
+
length += bytesRead;
|
|
228
|
+
}
|
|
229
|
+
if (length > limit)
|
|
230
|
+
return { kind: "skip", reason: "too_large" };
|
|
231
|
+
return { kind: "ok", bytes: buffer.subarray(0, length) };
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
return failure(error);
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
await handle.close().catch(() => undefined);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Resolves an `@import` written in `importer` to a repository-relative path,
|
|
242
|
+
* or reports it as outside the repository. An import that is absolute,
|
|
243
|
+
* home-relative (`~`), or climbs above the repository root is reported as
|
|
244
|
+
* written, since it has no repository-relative form; one that resolves inside
|
|
245
|
+
* the repository but to a refused location (such as `.git/`) is reported by
|
|
246
|
+
* its normalized repository-relative path.
|
|
247
|
+
*/
|
|
248
|
+
function resolveImport(importer, target) {
|
|
249
|
+
if (target.startsWith("~") || target.startsWith("/"))
|
|
250
|
+
return { skip: target };
|
|
251
|
+
const resolved = posix.normalize(posix.join(posix.dirname(importer), target.replace(/^(\.\/)+/, "")));
|
|
252
|
+
if (resolved === ".." || resolved.startsWith("../"))
|
|
253
|
+
return { skip: target };
|
|
254
|
+
if (!isSafeContextPath(resolved))
|
|
255
|
+
return { skip: resolved };
|
|
256
|
+
return { path: resolved };
|
|
257
|
+
}
|
|
258
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
259
|
+
/**
|
|
260
|
+
* Builds the Claude Code context for the checkout at `workspace`. Files are
|
|
261
|
+
* ordered roots first, then imports breadth-first, then skills by directory
|
|
262
|
+
* name. A file reached more than once is read once. Once the next file would
|
|
263
|
+
* exceed the file-count or total-size limit, it and every later candidate are
|
|
264
|
+
* reported as `limit` without being read.
|
|
265
|
+
*/
|
|
266
|
+
export async function buildClaudeContext(workspace, options) {
|
|
267
|
+
const realWorkspace = await realpath(workspace);
|
|
268
|
+
const files = [];
|
|
269
|
+
const skipped = [];
|
|
270
|
+
const seen = new Set();
|
|
271
|
+
let totalBytes = 0;
|
|
272
|
+
let limitReached = false;
|
|
273
|
+
let skippedOverflow = 0;
|
|
274
|
+
const skip = (path, reason) => {
|
|
275
|
+
if (skipped.length < MAX_RECORDED_SKIPS)
|
|
276
|
+
skipped.push({ path, reason });
|
|
277
|
+
else
|
|
278
|
+
skippedOverflow++;
|
|
279
|
+
};
|
|
280
|
+
const importsToFollow = (content) => {
|
|
281
|
+
const targets = importsOf(content);
|
|
282
|
+
skippedOverflow += Math.max(0, targets.length - MAX_IMPORTS_PER_FILE);
|
|
283
|
+
return targets.slice(0, MAX_IMPORTS_PER_FILE);
|
|
284
|
+
};
|
|
285
|
+
const add = (path, content) => {
|
|
286
|
+
const size = Buffer.byteLength(content);
|
|
287
|
+
if (files.length >= CLAUDE_CONTEXT_LIMITS.maxFiles || totalBytes + size > CLAUDE_CONTEXT_LIMITS.maxTotalBytes) {
|
|
288
|
+
limitReached = true;
|
|
289
|
+
skip(path, "limit");
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
files.push({ path, content });
|
|
293
|
+
totalBytes += size;
|
|
294
|
+
return true;
|
|
295
|
+
};
|
|
296
|
+
/** Loads one candidate; returns its content when it was added, otherwise undefined. */
|
|
297
|
+
const load = async (rel) => {
|
|
298
|
+
// Once the limit is reached nothing more is loaded, so later candidates are not even inspected
|
|
299
|
+
// (a candidate that does not exist is then also reported as limit).
|
|
300
|
+
if (limitReached)
|
|
301
|
+
return void skip(rel, "limit");
|
|
302
|
+
const inspection = await inspect(workspace, rel);
|
|
303
|
+
if (inspection.kind === "absent")
|
|
304
|
+
return undefined;
|
|
305
|
+
if (inspection.kind === "skip")
|
|
306
|
+
return void skip(rel, inspection.reason);
|
|
307
|
+
if (files.length >= CLAUDE_CONTEXT_LIMITS.maxFiles ||
|
|
308
|
+
totalBytes + inspection.stats.size > CLAUDE_CONTEXT_LIMITS.maxTotalBytes) {
|
|
309
|
+
limitReached = true;
|
|
310
|
+
return void skip(rel, "limit");
|
|
311
|
+
}
|
|
312
|
+
const read = await readChecked(realWorkspace, workspace, rel, inspection.stats);
|
|
313
|
+
if (read.kind === "absent")
|
|
314
|
+
return undefined;
|
|
315
|
+
if (read.kind === "skip")
|
|
316
|
+
return void skip(rel, read.reason);
|
|
317
|
+
let content;
|
|
318
|
+
try {
|
|
319
|
+
content = decoder.decode(read.bytes);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
return void skip(rel, "not_utf8");
|
|
323
|
+
}
|
|
324
|
+
return add(rel, content) ? content : undefined;
|
|
325
|
+
};
|
|
326
|
+
// Roots, or the AGENTS.md bridge when neither root path exists at all. A
|
|
327
|
+
// root that exists but is refused (a symlink, too large, ...) is reported
|
|
328
|
+
// and does not fall back to AGENTS.md.
|
|
329
|
+
const queue = [];
|
|
330
|
+
let rootExists = false;
|
|
331
|
+
for (const root of ROOTS) {
|
|
332
|
+
seen.add(root);
|
|
333
|
+
if ((await inspect(workspace, root)).kind !== "absent")
|
|
334
|
+
rootExists = true;
|
|
335
|
+
queue.push({ path: root, depth: 0 });
|
|
336
|
+
}
|
|
337
|
+
if (!rootExists && (await inspect(workspace, "AGENTS.md")).kind !== "absent") {
|
|
338
|
+
queue.length = 0;
|
|
339
|
+
seen.add("AGENTS.md");
|
|
340
|
+
const agents = await load("AGENTS.md");
|
|
341
|
+
if (agents !== undefined) {
|
|
342
|
+
// The bridge goes first, as the file that imports AGENTS.md.
|
|
343
|
+
files.unshift({ path: "CLAUDE.md", content: AGENTS_BRIDGE });
|
|
344
|
+
totalBytes += Buffer.byteLength(AGENTS_BRIDGE);
|
|
345
|
+
for (const target of importsToFollow(agents))
|
|
346
|
+
enqueue("AGENTS.md", target, 2);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function enqueue(importer, target, depth) {
|
|
350
|
+
const resolved = resolveImport(importer, target);
|
|
351
|
+
const path = "path" in resolved ? resolved.path : resolved.skip;
|
|
352
|
+
if (seen.has(path))
|
|
353
|
+
return;
|
|
354
|
+
seen.add(path);
|
|
355
|
+
if ("skip" in resolved)
|
|
356
|
+
skip(resolved.skip, "outside_repo");
|
|
357
|
+
// Settings, hooks, MCP configuration, agents, commands, and anything not Markdown are never
|
|
358
|
+
// read, whatever an instruction file imports.
|
|
359
|
+
else if (!isAllowedContextPath(path))
|
|
360
|
+
skip(path, "not_allowed");
|
|
361
|
+
else
|
|
362
|
+
queue.push({ path, depth });
|
|
363
|
+
}
|
|
364
|
+
for (let next = queue.shift(); next !== undefined; next = queue.shift()) {
|
|
365
|
+
const content = await load(next.path);
|
|
366
|
+
if (content === undefined || next.depth >= MAX_IMPORT_DEPTH)
|
|
367
|
+
continue;
|
|
368
|
+
for (const target of importsToFollow(content))
|
|
369
|
+
enqueue(next.path, target, next.depth + 1);
|
|
370
|
+
}
|
|
371
|
+
if (options.skills) {
|
|
372
|
+
const listing = await skillNames(workspace, skip);
|
|
373
|
+
if (listing.truncated)
|
|
374
|
+
skippedOverflow++;
|
|
375
|
+
for (const name of listing.names) {
|
|
376
|
+
const rel = `${SKILLS_DIR}/${name}/SKILL.md`;
|
|
377
|
+
if (seen.has(rel))
|
|
378
|
+
continue;
|
|
379
|
+
seen.add(rel);
|
|
380
|
+
if (!isSafeContextPath(rel))
|
|
381
|
+
skip(rel, "outside_repo");
|
|
382
|
+
else if (!isAllowedContextPath(rel))
|
|
383
|
+
skip(rel, "not_allowed");
|
|
384
|
+
else
|
|
385
|
+
await load(rel);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return { files, skipped, skippedOverflow };
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Lists the entries of `.claude/skills`, sorted by name: at most
|
|
392
|
+
* `MAX_SKILL_ENTRIES` of them, in directory order, with `truncated` set when
|
|
393
|
+
* more exist. A missing skills directory yields none; a symlinked one is
|
|
394
|
+
* reported and yields none.
|
|
395
|
+
*/
|
|
396
|
+
async function skillNames(workspace, skip) {
|
|
397
|
+
const none = { names: [], truncated: false };
|
|
398
|
+
for (const directory of [".claude", SKILLS_DIR]) {
|
|
399
|
+
let stats;
|
|
400
|
+
try {
|
|
401
|
+
stats = await lstat(join(workspace, directory));
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return none;
|
|
405
|
+
}
|
|
406
|
+
if (stats.isSymbolicLink()) {
|
|
407
|
+
skip(directory, "symlink");
|
|
408
|
+
return none;
|
|
409
|
+
}
|
|
410
|
+
if (!stats.isDirectory())
|
|
411
|
+
return none;
|
|
412
|
+
}
|
|
413
|
+
const names = [];
|
|
414
|
+
let truncated = false;
|
|
415
|
+
try {
|
|
416
|
+
const dir = await opendir(join(workspace, SKILLS_DIR));
|
|
417
|
+
try {
|
|
418
|
+
for (let entry = await dir.read(); entry !== null; entry = await dir.read()) {
|
|
419
|
+
if (names.length >= MAX_SKILL_ENTRIES) {
|
|
420
|
+
truncated = true;
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
names.push(entry.name);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
await dir.close().catch(() => undefined);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
return none;
|
|
432
|
+
}
|
|
433
|
+
return { names: names.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)), truncated };
|
|
434
|
+
}
|
package/dist/coding/profile.d.ts
CHANGED
|
@@ -30,11 +30,15 @@ export declare const CodingProfileSchema: z.ZodObject<{
|
|
|
30
30
|
minReleaseAgeDays?: number | undefined;
|
|
31
31
|
}>>;
|
|
32
32
|
services: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>>;
|
|
33
|
+
repoSkills: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
claudeBareMode: z.ZodDefault<z.ZodBoolean>;
|
|
33
35
|
}, "strict", z.ZodTypeAny, {
|
|
34
36
|
repository: string;
|
|
35
37
|
baseRef: string;
|
|
36
38
|
maxTurns: number | null;
|
|
37
39
|
services: string[];
|
|
40
|
+
repoSkills: boolean;
|
|
41
|
+
claudeBareMode: boolean;
|
|
38
42
|
provider: "codex" | "claude-code";
|
|
39
43
|
timeoutSec: number;
|
|
40
44
|
protectedPaths: string[];
|
|
@@ -54,6 +58,8 @@ export declare const CodingProfileSchema: z.ZodObject<{
|
|
|
54
58
|
baseRef?: string | undefined;
|
|
55
59
|
maxTurns?: number | null | undefined;
|
|
56
60
|
services?: string[] | undefined;
|
|
61
|
+
repoSkills?: boolean | undefined;
|
|
62
|
+
claudeBareMode?: boolean | undefined;
|
|
57
63
|
provider?: "codex" | "claude-code" | undefined;
|
|
58
64
|
timeoutSec?: number | undefined;
|
|
59
65
|
protectedPaths?: string[] | undefined;
|
|
@@ -96,11 +102,15 @@ export declare const CodingProfilePatchSchema: z.ZodObject<{
|
|
|
96
102
|
minReleaseAgeDays?: number | undefined;
|
|
97
103
|
}>>;
|
|
98
104
|
services: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>>;
|
|
105
|
+
repoSkills: z.ZodOptional<z.ZodBoolean>;
|
|
106
|
+
claudeBareMode: z.ZodOptional<z.ZodBoolean>;
|
|
99
107
|
}, "strict", z.ZodTypeAny, {
|
|
100
108
|
repository?: string | undefined;
|
|
101
109
|
baseRef?: string | undefined;
|
|
102
110
|
maxTurns?: number | null | undefined;
|
|
103
111
|
services?: string[] | undefined;
|
|
112
|
+
repoSkills?: boolean | undefined;
|
|
113
|
+
claudeBareMode?: boolean | undefined;
|
|
104
114
|
provider?: "codex" | "claude-code" | undefined;
|
|
105
115
|
timeoutSec?: number | undefined;
|
|
106
116
|
protectedPaths?: string[] | undefined;
|
|
@@ -120,6 +130,8 @@ export declare const CodingProfilePatchSchema: z.ZodObject<{
|
|
|
120
130
|
baseRef?: string | undefined;
|
|
121
131
|
maxTurns?: number | null | undefined;
|
|
122
132
|
services?: string[] | undefined;
|
|
133
|
+
repoSkills?: boolean | undefined;
|
|
134
|
+
claudeBareMode?: boolean | undefined;
|
|
123
135
|
provider?: "codex" | "claude-code" | undefined;
|
|
124
136
|
timeoutSec?: number | undefined;
|
|
125
137
|
protectedPaths?: string[] | undefined;
|
package/dist/coding/profile.js
CHANGED
|
@@ -136,6 +136,8 @@ const codingProfileFields = {
|
|
|
136
136
|
packagePolicy: packagePolicySchema,
|
|
137
137
|
/** Coding-run services this agent's runs may start: catalog names, any version (docs/coding-services.md). */
|
|
138
138
|
services: AllowedServiceNamesSchema,
|
|
139
|
+
repoSkills: z.boolean(),
|
|
140
|
+
claudeBareMode: z.boolean(),
|
|
139
141
|
};
|
|
140
142
|
export const CodingProfileSchema = z
|
|
141
143
|
.object({
|
|
@@ -155,6 +157,8 @@ export const CodingProfileSchema = z
|
|
|
155
157
|
packageAllowlist: codingProfileFields.packageAllowlist.default({}),
|
|
156
158
|
packagePolicy: codingProfileFields.packagePolicy.default({}),
|
|
157
159
|
services: codingProfileFields.services.default([]),
|
|
160
|
+
repoSkills: codingProfileFields.repoSkills.default(true),
|
|
161
|
+
claudeBareMode: codingProfileFields.claudeBareMode.default(true),
|
|
158
162
|
})
|
|
159
163
|
.strict();
|
|
160
164
|
export const CodingProfilePatchSchema = z
|
|
@@ -175,5 +179,7 @@ export const CodingProfilePatchSchema = z
|
|
|
175
179
|
packageAllowlist: codingProfileFields.packageAllowlist.optional(),
|
|
176
180
|
packagePolicy: codingProfileFields.packagePolicy.optional(),
|
|
177
181
|
services: codingProfileFields.services.optional(),
|
|
182
|
+
repoSkills: codingProfileFields.repoSkills.optional(),
|
|
183
|
+
claudeBareMode: codingProfileFields.claudeBareMode.optional(),
|
|
178
184
|
})
|
|
179
185
|
.strict();
|
|
@@ -3,6 +3,14 @@ export declare const CODING_PROTOCOL_VERSION: 1;
|
|
|
3
3
|
/** The code host every coding run's repository and pull request live on (see pullRequestUrlSchema); the one place to change when another is added. */
|
|
4
4
|
export declare const CODING_CODE_PROVIDER = "github";
|
|
5
5
|
export declare const MAX_CODING_ARTIFACT_BYTES: number;
|
|
6
|
+
/** The worker input artifact (input.json): larger than results because it can carry Claude Code repo context. */
|
|
7
|
+
export declare const MAX_CODING_INPUT_BYTES: number;
|
|
8
|
+
/** Bounds on CodingTaskInput.claudeContext, enforced by the builder (src/coding/claude-context.ts) and this schema. */
|
|
9
|
+
export declare const CLAUDE_CONTEXT_LIMITS: {
|
|
10
|
+
readonly maxFiles: 200;
|
|
11
|
+
readonly maxFileBytes: number;
|
|
12
|
+
readonly maxTotalBytes: number;
|
|
13
|
+
};
|
|
6
14
|
export declare const MAX_CODING_TASK_BYTES: number;
|
|
7
15
|
/** Room reserved at the end of a composed task for lines the executor appends (e.g. the base commit). */
|
|
8
16
|
export declare const CODING_TASK_TRAILER_RESERVE_BYTES = 256;
|
|
@@ -86,6 +94,31 @@ export declare const MAX_CODING_TURNS = 1000;
|
|
|
86
94
|
export declare const DEFAULT_CLAUDE_MAX_TURNS = 200;
|
|
87
95
|
/** Longest line a debug-traced worker writes to its log (src/coding-worker/debug-trace.ts). */
|
|
88
96
|
export declare const MAX_DEBUG_TRACE_LINE_BYTES: number;
|
|
97
|
+
/**
|
|
98
|
+
* A repo-relative POSIX path with no empty, ".", or ".." segment, no backslash, no control
|
|
99
|
+
* character, and nothing under .git.
|
|
100
|
+
*/
|
|
101
|
+
export declare function isSafeContextPath(path: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Whether a Claude Code context file may be shipped to (and written by) the worker: a safe path
|
|
104
|
+
* that is CLAUDE.md, .claude/CLAUDE.md, AGENTS.md, a .claude/skills/<name>/SKILL.md, or any other
|
|
105
|
+
* Markdown file outside every .claude directory that is not a CLAUDE.local.md. This keeps
|
|
106
|
+
* repository settings, hooks, MCP configuration, agents, commands, and personal memory out of
|
|
107
|
+
* Claude Code's native loading. Not part of the input schema: a refused file is dropped, and never
|
|
108
|
+
* fails the run.
|
|
109
|
+
*/
|
|
110
|
+
export declare function isAllowedContextPath(path: string): boolean;
|
|
111
|
+
export declare const ClaudeContextFileSchema: z.ZodObject<{
|
|
112
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
|
113
|
+
content: z.ZodEffects<z.ZodString, string, string>;
|
|
114
|
+
}, "strict", z.ZodTypeAny, {
|
|
115
|
+
path: string;
|
|
116
|
+
content: string;
|
|
117
|
+
}, {
|
|
118
|
+
path: string;
|
|
119
|
+
content: string;
|
|
120
|
+
}>;
|
|
121
|
+
export type ClaudeContextFile = z.infer<typeof ClaudeContextFileSchema>;
|
|
89
122
|
export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
90
123
|
schemaVersion: z.ZodLiteral<1>;
|
|
91
124
|
runId: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, string, string>, string, string>;
|
|
@@ -144,6 +177,45 @@ export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
144
177
|
version: string;
|
|
145
178
|
testEnv: Record<string, string>;
|
|
146
179
|
}>, "many">>;
|
|
180
|
+
/**
|
|
181
|
+
* Load the repository's agent skills (CodingAgentProfile.repoSkills, fixed on the run at
|
|
182
|
+
* dispatch). Absent means true; the control plane writes the key only when false, so other
|
|
183
|
+
* runs' input is unchanged for workers that predate it.
|
|
184
|
+
*/
|
|
185
|
+
repoSkills: z.ZodOptional<z.ZodBoolean>;
|
|
186
|
+
/**
|
|
187
|
+
* Claude Code runs (CodingAgentProfile.claudeBareMode, fixed on the run at dispatch): false
|
|
188
|
+
* turns off Claude Code's bare mode so it loads claudeContext natively. Absent means true;
|
|
189
|
+
* written only when false.
|
|
190
|
+
*/
|
|
191
|
+
claudeBareMode: z.ZodOptional<z.ZodBoolean>;
|
|
192
|
+
/**
|
|
193
|
+
* Claude Code runs: the repository's CLAUDE.md, its @imports, and (when repoSkills) each
|
|
194
|
+
* .claude/skills/<name>/SKILL.md, read by the control plane from the prepared workspace.
|
|
195
|
+
* Absent when there is nothing to load.
|
|
196
|
+
*/
|
|
197
|
+
claudeContext: z.ZodOptional<z.ZodObject<{
|
|
198
|
+
files: z.ZodArray<z.ZodObject<{
|
|
199
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
|
200
|
+
content: z.ZodEffects<z.ZodString, string, string>;
|
|
201
|
+
}, "strict", z.ZodTypeAny, {
|
|
202
|
+
path: string;
|
|
203
|
+
content: string;
|
|
204
|
+
}, {
|
|
205
|
+
path: string;
|
|
206
|
+
content: string;
|
|
207
|
+
}>, "many">;
|
|
208
|
+
}, "strict", z.ZodTypeAny, {
|
|
209
|
+
files: {
|
|
210
|
+
path: string;
|
|
211
|
+
content: string;
|
|
212
|
+
}[];
|
|
213
|
+
}, {
|
|
214
|
+
files: {
|
|
215
|
+
path: string;
|
|
216
|
+
content: string;
|
|
217
|
+
}[];
|
|
218
|
+
}>>;
|
|
147
219
|
}, "strict", z.ZodTypeAny, {
|
|
148
220
|
repository: string;
|
|
149
221
|
schemaVersion: 1;
|
|
@@ -164,6 +236,14 @@ export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
164
236
|
version: string;
|
|
165
237
|
testEnv: Record<string, string>;
|
|
166
238
|
}[] | undefined;
|
|
239
|
+
repoSkills?: boolean | undefined;
|
|
240
|
+
claudeBareMode?: boolean | undefined;
|
|
241
|
+
claudeContext?: {
|
|
242
|
+
files: {
|
|
243
|
+
path: string;
|
|
244
|
+
content: string;
|
|
245
|
+
}[];
|
|
246
|
+
} | undefined;
|
|
167
247
|
}, {
|
|
168
248
|
repository: string;
|
|
169
249
|
schemaVersion: 1;
|
|
@@ -184,6 +264,14 @@ export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
184
264
|
version: string;
|
|
185
265
|
testEnv: Record<string, string>;
|
|
186
266
|
}[] | undefined;
|
|
267
|
+
repoSkills?: boolean | undefined;
|
|
268
|
+
claudeBareMode?: boolean | undefined;
|
|
269
|
+
claudeContext?: {
|
|
270
|
+
files: {
|
|
271
|
+
path: string;
|
|
272
|
+
content: string;
|
|
273
|
+
}[];
|
|
274
|
+
} | undefined;
|
|
187
275
|
}>, {
|
|
188
276
|
repository: string;
|
|
189
277
|
schemaVersion: 1;
|
|
@@ -204,6 +292,14 @@ export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
204
292
|
version: string;
|
|
205
293
|
testEnv: Record<string, string>;
|
|
206
294
|
}[] | undefined;
|
|
295
|
+
repoSkills?: boolean | undefined;
|
|
296
|
+
claudeBareMode?: boolean | undefined;
|
|
297
|
+
claudeContext?: {
|
|
298
|
+
files: {
|
|
299
|
+
path: string;
|
|
300
|
+
content: string;
|
|
301
|
+
}[];
|
|
302
|
+
} | undefined;
|
|
207
303
|
}, {
|
|
208
304
|
repository: string;
|
|
209
305
|
schemaVersion: 1;
|
|
@@ -224,6 +320,14 @@ export declare const CodingTaskInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
224
320
|
version: string;
|
|
225
321
|
testEnv: Record<string, string>;
|
|
226
322
|
}[] | undefined;
|
|
323
|
+
repoSkills?: boolean | undefined;
|
|
324
|
+
claudeBareMode?: boolean | undefined;
|
|
325
|
+
claudeContext?: {
|
|
326
|
+
files: {
|
|
327
|
+
path: string;
|
|
328
|
+
content: string;
|
|
329
|
+
}[];
|
|
330
|
+
} | undefined;
|
|
227
331
|
}>;
|
|
228
332
|
export declare const CodingAgentOutputSchema: z.ZodEffects<z.ZodObject<{
|
|
229
333
|
schemaVersion: z.ZodLiteral<1>;
|