@webpresso/agent-kit 3.1.30 → 3.3.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/README.md +53 -15
- package/bin/_run.js +183 -20
- package/catalog/AGENTS.md.tpl +3 -3
- package/catalog/agent/agents/implementer.md +45 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
- package/catalog/agent/rules/pre-implementation.md +28 -1
- package/catalog/agent/rules/supported-agent-clis.md +9 -0
- package/catalog/agent/rules/typescript-version.md +50 -0
- package/catalog/agent/skills/codex/SKILL.md +25 -1
- package/catalog/agent/skills/verify/SKILL.md +4 -2
- package/catalog/docs/templates/blueprint.md +1 -1
- package/dist/esm/audit/agents.js +1 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
- package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
- package/dist/esm/audit/blueprint-trust.js +14 -10
- package/dist/esm/audit/changeset-evidence.d.ts +23 -0
- package/dist/esm/audit/changeset-evidence.js +30 -0
- package/dist/esm/audit/changeset-required.d.ts +10 -0
- package/dist/esm/audit/changeset-required.js +73 -0
- package/dist/esm/audit/ci-guardrails-detection.d.ts +27 -0
- package/dist/esm/audit/ci-guardrails-detection.js +68 -0
- package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
- package/dist/esm/audit/ci-guardrails-wiring.js +80 -0
- package/dist/esm/audit/ci-test-perf.js +30 -0
- package/dist/esm/audit/command-surface.js +4 -2
- package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
- package/dist/esm/audit/host-substitution-risk.js +256 -0
- package/dist/esm/audit/registry.d.ts +4 -4
- package/dist/esm/audit/registry.js +13 -1
- package/dist/esm/audit/toolchain-isolation.js +1 -2
- package/dist/esm/audit/typescript-version.d.ts +2 -0
- package/dist/esm/audit/typescript-version.js +123 -0
- package/dist/esm/blueprint/core/parser.js +101 -2
- package/dist/esm/blueprint/core/schema.d.ts +1 -0
- package/dist/esm/blueprint/core/schema.js +26 -0
- package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
- package/dist/esm/blueprint/core/validation/criteria.js +41 -2
- package/dist/esm/blueprint/core/validation/state.js +25 -14
- package/dist/esm/blueprint/db/migrations/run.js +4 -2
- package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
- package/dist/esm/blueprint/lifecycle/audit.js +87 -20
- package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
- package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
- package/dist/esm/blueprint/lifecycle/local.js +19 -3
- package/dist/esm/blueprint/lifecycle/review-provenance.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/review-provenance.js +68 -12
- package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +97 -0
- package/dist/esm/blueprint/lifecycle/rollout-anchor.js +161 -0
- package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
- package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
- package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
- package/dist/esm/blueprint/sync/client.d.ts +2 -1
- package/dist/esm/blueprint/sync/client.js +1 -1
- package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
- package/dist/esm/blueprint/trust/command-runner.js +148 -0
- package/dist/esm/blueprint/trust/dossier.d.ts +1 -0
- package/dist/esm/blueprint/trust/dossier.js +40 -6
- package/dist/esm/blueprint/trust/gates.d.ts +7 -0
- package/dist/esm/blueprint/trust/gates.js +20 -0
- package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
- package/dist/esm/blueprint/trust/promotion.js +74 -112
- package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
- package/dist/esm/blueprint/trust/scaffold.js +64 -0
- package/dist/esm/blueprint/trust/validator.d.ts +1 -0
- package/dist/esm/blueprint/trust/validator.js +7 -1
- package/dist/esm/blueprint/utils/archive.js +27 -5
- package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
- package/dist/esm/blueprint/utils/document-paths.js +45 -12
- package/dist/esm/build/cli-mcp-parity.js +15 -0
- package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
- package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +43 -0
- package/dist/esm/cli/commands/agent-launch.d.ts +8 -1
- package/dist/esm/cli/commands/agent-launch.js +93 -4
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit-core.js +8 -1
- package/dist/esm/cli/commands/audit.js +21 -5
- package/dist/esm/cli/commands/blueprint/execution.js +18 -6
- package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
- package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
- package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
- package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
- package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
- package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
- package/dist/esm/cli/commands/blueprint/router.js +13 -1
- package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
- package/dist/esm/cli/commands/ci-preflight.js +30 -6
- package/dist/esm/cli/commands/compile.js +5 -31
- package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
- package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
- package/dist/esm/cli/commands/doctor.js +5 -0
- package/dist/esm/cli/commands/hook.d.ts +5 -0
- package/dist/esm/cli/commands/hook.js +15 -9
- package/dist/esm/cli/commands/init/config.js +2 -2
- package/dist/esm/cli/commands/init/convergence-apply.d.ts +88 -0
- package/dist/esm/cli/commands/init/convergence-apply.js +325 -0
- package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
- package/dist/esm/cli/commands/init/convergence-state.js +54 -0
- package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
- package/dist/esm/cli/commands/init/convergence.js +57 -0
- package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
- package/dist/esm/cli/commands/init/git-convergence.js +168 -0
- package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
- package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
- package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
- package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
- package/dist/esm/cli/commands/init/host-visibility.js +94 -5
- package/dist/esm/cli/commands/init/index.d.ts +3 -0
- package/dist/esm/cli/commands/init/index.js +326 -173
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
- package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
- package/dist/esm/cli/commands/init/merge.d.ts +1 -0
- package/dist/esm/cli/commands/init/merge.js +30 -1
- package/dist/esm/cli/commands/init/package-root.d.ts +7 -0
- package/dist/esm/cli/commands/init/package-root.js +10 -2
- package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
- package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +20 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +61 -5
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +54 -24
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +22 -0
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +230 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
- package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
- package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
- package/dist/esm/cli/commands/opencode-probe.d.ts +107 -0
- package/dist/esm/cli/commands/opencode-probe.js +323 -0
- package/dist/esm/cli/commands/opencode-rotate.d.ts +72 -0
- package/dist/esm/cli/commands/opencode-rotate.js +147 -0
- package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
- package/dist/esm/cli/commands/public-readiness.js +42 -0
- package/dist/esm/cli/commands/quality-runner.js +3 -3
- package/dist/esm/cli/commands/review.d.ts +35 -3
- package/dist/esm/cli/commands/review.js +751 -209
- package/dist/esm/cli/commands/run-wait.d.ts +2 -0
- package/dist/esm/cli/commands/run-wait.js +122 -0
- package/dist/esm/cli/commands/rust-check.d.ts +24 -0
- package/dist/esm/cli/commands/rust-check.js +110 -0
- package/dist/esm/cli/commands/setup-help.js +1 -1
- package/dist/esm/cli/commands/setup-repair-help.js +1 -1
- package/dist/esm/cli/commands/typecheck.d.ts +1 -0
- package/dist/esm/cli/commands/typecheck.js +30 -1
- package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +6 -0
- package/dist/esm/cli/commands/worktree/router-dispatch.js +126 -9
- package/dist/esm/cli/commands/worktree/router.js +10 -0
- package/dist/esm/cli/direct-provider-launch.js +9 -5
- package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
- package/dist/esm/cli/optional-tool-freshness.js +219 -9
- package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
- package/dist/esm/daemon/domains/git-actions.js +136 -0
- package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
- package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
- package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
- package/dist/esm/daemon/domains/sessions-search.js +29 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
- package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
- package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
- package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
- package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/git-handlers.js +27 -0
- package/dist/esm/daemon/handlers/product.d.ts +7 -0
- package/dist/esm/daemon/handlers/product.js +10 -119
- package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
- package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
- package/dist/esm/daemon/handlers/shared.d.ts +5 -0
- package/dist/esm/daemon/handlers/shared.js +16 -0
- package/dist/esm/daemon/methods.d.ts +8 -1
- package/dist/esm/daemon/methods.js +7 -0
- package/dist/esm/daemon/protocol/contract.d.ts +43 -0
- package/dist/esm/daemon/protocol/contract.js +26 -0
- package/dist/esm/daemon/protocol/index.d.ts +1 -1
- package/dist/esm/daemon/protocol/index.js +1 -1
- package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
- package/dist/esm/hooks/__conformance__/matrix.js +137 -0
- package/dist/esm/hooks/conformance/batch.js +5 -0
- package/dist/esm/hooks/doctor.d.ts +5 -3
- package/dist/esm/hooks/doctor.js +67 -16
- package/dist/esm/hooks/permission-request/index.js +9 -3
- package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
- package/dist/esm/hooks/permission-request/policy.js +13 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
- package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/logger.js +16 -0
- package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/runner.js +68 -16
- package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
- package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
- package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +6 -1
- package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
- package/dist/esm/hooks/shared/guard-outcome.js +215 -0
- package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
- package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
- package/dist/esm/hooks/shared/types.d.ts +8 -5
- package/dist/esm/hooks/shared/types.js +50 -9
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +92 -0
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.d.ts +5 -0
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +109 -11
- package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
- package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
- package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
- package/dist/esm/mcp/blueprint/registration.js +3 -2
- package/dist/esm/mcp/server.d.ts +1 -0
- package/dist/esm/mcp/server.js +27 -0
- package/dist/esm/mcp/tools/_names.d.ts +1 -1
- package/dist/esm/mcp/tools/_names.js +5 -0
- package/dist/esm/mcp/tools/_registry.js +10 -0
- package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
- package/dist/esm/mcp/tools/_shared/result.js +44 -1
- package/dist/esm/mcp/tools/audit.d.ts +5 -1
- package/dist/esm/mcp/tools/audit.js +42 -0
- package/dist/esm/mcp/tools/audits.d.ts +4 -0
- package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
- package/dist/esm/mcp/tools/ci-preflight.js +183 -0
- package/dist/esm/mcp/tools/pr-upsert.js +39 -1
- package/dist/esm/mcp/tools/review-run.d.ts +28 -0
- package/dist/esm/mcp/tools/review-run.js +216 -0
- package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
- package/dist/esm/mcp/tools/run-wait.js +593 -0
- package/dist/esm/mcp/tools/session-fetch-and-index.d.ts +1 -1
- package/dist/esm/mcp/tools/session-id.d.ts +3 -0
- package/dist/esm/mcp/tools/session-id.js +45 -0
- package/dist/esm/mcp/tools/session-info.d.ts +3 -0
- package/dist/esm/mcp/tools/session-info.js +49 -0
- package/dist/esm/output-transforms/audit.d.ts +23 -0
- package/dist/esm/output-transforms/audit.js +47 -0
- package/dist/esm/output-transforms/index.js +2 -0
- package/dist/esm/package.json +2 -0
- package/dist/esm/platform/client.d.ts +7 -1
- package/dist/esm/platform/github-contract-source.d.ts +2 -1
- package/dist/esm/pr-description/contract.js +24 -4
- package/dist/esm/review/authority.js +27 -14
- package/dist/esm/review/availability.d.ts +33 -0
- package/dist/esm/review/availability.js +122 -20
- package/dist/esm/review/delivery-verifier.d.ts +27 -0
- package/dist/esm/review/delivery-verifier.js +115 -0
- package/dist/esm/review/events.d.ts +3 -2
- package/dist/esm/review/events.js +23 -3
- package/dist/esm/review/execution/adapters.d.ts +11 -1
- package/dist/esm/review/execution/adapters.js +36 -10
- package/dist/esm/review/execution/artifacts.d.ts +1 -1
- package/dist/esm/review/execution/output-policy.d.ts +2 -0
- package/dist/esm/review/execution/output-policy.js +12 -0
- package/dist/esm/review/execution/review-checkout.js +121 -21
- package/dist/esm/review/execution/supervisor.js +36 -4
- package/dist/esm/review/execution/types.d.ts +9 -0
- package/dist/esm/review/opencode-account.d.ts +24 -0
- package/dist/esm/review/opencode-account.js +68 -0
- package/dist/esm/review/opencode-auth.d.ts +33 -0
- package/dist/esm/review/opencode-auth.js +79 -0
- package/dist/esm/review/subject.d.ts +25 -0
- package/dist/esm/review/subject.js +116 -26
- package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
- package/dist/esm/runtime/opencode-account-materializer.js +33 -0
- package/dist/esm/rust/affected-manifests.d.ts +38 -0
- package/dist/esm/rust/affected-manifests.js +69 -0
- package/dist/esm/session-memory/fetch-index.d.ts +1 -1
- package/dist/esm/status/snapshot.js +32 -25
- package/dist/esm/test/duration-sequencer.d.ts +20 -0
- package/dist/esm/test/duration-sequencer.js +54 -0
- package/dist/esm/test/shard-durations.json +922 -0
- package/dist/esm/test/worker-budget.d.ts +6 -0
- package/dist/esm/test/worker-budget.js +59 -1
- package/dist/esm/test-helpers/global-setup.d.ts +1 -2
- package/dist/esm/test-helpers/global-setup.js +79 -32
- package/dist/esm/typecheck/planner.d.ts +9 -1
- package/dist/esm/typecheck/planner.js +31 -0
- package/dist/esm/ultragoal/service.d.ts +7 -0
- package/dist/esm/ultragoal/service.js +42 -2
- package/dist/esm/utils/write-json-file.js +3 -1
- package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
- package/dist/esm/worktrees/codex-project-trust.js +56 -0
- package/dist/esm/worktrees/orphan-scan.d.ts +50 -0
- package/dist/esm/worktrees/orphan-scan.js +211 -0
- package/dist/esm/worktrees/registry.d.ts +8 -0
- package/dist/esm/worktrees/registry.js +18 -3
- package/package.json +18 -13
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare const WEBPRESSO_MCP_SERVER_NAME = "webpresso";
|
|
2
|
+
/**
|
|
3
|
+
* The single canonical launch spec for the webpresso MCP server. `name` is the
|
|
4
|
+
* server alias every host registers; `args` are appended after the resolved
|
|
5
|
+
* `wp` launcher; `env` is forwarded to the spawned process by every
|
|
6
|
+
* env-capable channel. `WP_SKIP_UPDATE_CHECK=1` keeps MCP startup from doing a
|
|
7
|
+
* network update probe on every host session.
|
|
8
|
+
*/
|
|
9
|
+
export declare const WEBPRESSO_MCP_SPEC: {
|
|
10
|
+
readonly name: "webpresso";
|
|
11
|
+
readonly args: readonly ["mcp"];
|
|
12
|
+
readonly env: {
|
|
13
|
+
readonly WP_SKIP_UPDATE_CHECK: "1";
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type WebpressoMcpSpec = typeof WEBPRESSO_MCP_SPEC;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve `binary` against PATH, returning the first executable candidate.
|
|
19
|
+
* Returns the candidate as an absolute path: relative PATH entries (`bin`,
|
|
20
|
+
* `.`) resolve against the current working directory — persisting them
|
|
21
|
+
* verbatim into host configs would resolve differently in later sessions.
|
|
22
|
+
* No realpath is taken, so generated configs stay anchored to a stable
|
|
23
|
+
* global-bin symlink rather than a version-pinned store path.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveExecutableOnPath(binary: string, env: NodeJS.ProcessEnv): string | null;
|
|
26
|
+
export interface WebpressoInstallProbe {
|
|
27
|
+
/** Test seam — override the candidate roots. Default: probe in fixed order. */
|
|
28
|
+
candidates?: readonly string[];
|
|
29
|
+
/** Test seam — resolve the stable global `wp` shim available on PATH. */
|
|
30
|
+
stableEntry?: () => string | null;
|
|
31
|
+
/** Test seam — verify that a PATH entry is the Webpresso command. */
|
|
32
|
+
stableEntryIsWebpresso?: (entryPath: string) => boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the absolute path to webpresso's global `bin/wp` launcher on this
|
|
36
|
+
* machine. Probes the locations consumers use to install webpresso, in order
|
|
37
|
+
* of stability:
|
|
38
|
+
*
|
|
39
|
+
* 1. the stable global `wp` shim available on PATH
|
|
40
|
+
* 2. the currently executing `@webpresso/agent-kit` package
|
|
41
|
+
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
42
|
+
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
43
|
+
* Returns `null` when none of the candidates contain a usable `bin/wp`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function findWebpressoMcpEntry(probe?: WebpressoInstallProbe): string | null;
|
|
46
|
+
export declare function resolveWebpressoMcpEntry(probe?: WebpressoInstallProbe): {
|
|
47
|
+
entryPath: string | null;
|
|
48
|
+
checked: readonly string[];
|
|
49
|
+
};
|
|
50
|
+
export declare function isWebpressoWpEntry(entryPath: string): boolean;
|
|
51
|
+
/** Run a discovery probe with bounded output and SIGKILL escalation. */
|
|
52
|
+
export declare function runQuiet(cmd: string, args: readonly string[], timeoutMs?: number): string | null;
|
|
53
|
+
/** Launch tuple for the webpresso MCP server given a resolved `wp` launcher. */
|
|
54
|
+
export declare function agentKitMcpLaunchCommand(entryPath: string): {
|
|
55
|
+
command: string;
|
|
56
|
+
args: string[];
|
|
57
|
+
};
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Webpresso MCP server spec + shared `wp` binary resolver.
|
|
3
|
+
*
|
|
4
|
+
* One source of truth for how every supported host launches the webpresso MCP
|
|
5
|
+
* server. Each host channel (Claude plugin manifest, Codex plugin manifest,
|
|
6
|
+
* Codex `config.toml`, OpenCode `opencode.json`, Grok `.grok/config.toml`)
|
|
7
|
+
* projects this spec into its own config dialect. The two committed plugin
|
|
8
|
+
* manifests reference the launcher via `${CLAUDE_PLUGIN_ROOT}`/`${PLUGIN_ROOT}`;
|
|
9
|
+
* the setup-time writers resolve an absolute `bin/wp` path via
|
|
10
|
+
* {@link findWebpressoMcpEntry}. Compare channels *semantically* (command
|
|
11
|
+
* basename, args, env) — never byte-for-byte.
|
|
12
|
+
*/
|
|
13
|
+
import { accessSync, constants, existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { pathCandidates } from "#runtime/command-exists.js";
|
|
19
|
+
export const WEBPRESSO_MCP_SERVER_NAME = "webpresso";
|
|
20
|
+
/**
|
|
21
|
+
* The single canonical launch spec for the webpresso MCP server. `name` is the
|
|
22
|
+
* server alias every host registers; `args` are appended after the resolved
|
|
23
|
+
* `wp` launcher; `env` is forwarded to the spawned process by every
|
|
24
|
+
* env-capable channel. `WP_SKIP_UPDATE_CHECK=1` keeps MCP startup from doing a
|
|
25
|
+
* network update probe on every host session.
|
|
26
|
+
*/
|
|
27
|
+
export const WEBPRESSO_MCP_SPEC = {
|
|
28
|
+
name: WEBPRESSO_MCP_SERVER_NAME,
|
|
29
|
+
args: ["mcp"],
|
|
30
|
+
env: { WP_SKIP_UPDATE_CHECK: "1" },
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Resolve `binary` against PATH, returning the first executable candidate.
|
|
34
|
+
* Returns the candidate as an absolute path: relative PATH entries (`bin`,
|
|
35
|
+
* `.`) resolve against the current working directory — persisting them
|
|
36
|
+
* verbatim into host configs would resolve differently in later sessions.
|
|
37
|
+
* No realpath is taken, so generated configs stay anchored to a stable
|
|
38
|
+
* global-bin symlink rather than a version-pinned store path.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveExecutableOnPath(binary, env) {
|
|
41
|
+
for (const candidate of pathCandidates(binary, {
|
|
42
|
+
pathEnv: env.PATH,
|
|
43
|
+
pathExtEnv: env.PATHEXT,
|
|
44
|
+
})) {
|
|
45
|
+
try {
|
|
46
|
+
if (!statSync(candidate).isFile())
|
|
47
|
+
continue;
|
|
48
|
+
if (process.platform !== "win32")
|
|
49
|
+
accessSync(candidate, constants.X_OK);
|
|
50
|
+
return isAbsolute(candidate) ? candidate : resolve(candidate);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Continue scanning PATH.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const WP_BIN_RELATIVE = join("bin", "wp");
|
|
59
|
+
const WP_LAUNCHER_REQUIRED_RELATIVES = [
|
|
60
|
+
WP_BIN_RELATIVE,
|
|
61
|
+
join("bin", "_run.js"),
|
|
62
|
+
join("bin", "runtime-lanes.js"),
|
|
63
|
+
join("bin", "runtime-manifest.json"),
|
|
64
|
+
];
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the absolute path to webpresso's global `bin/wp` launcher on this
|
|
67
|
+
* machine. Probes the locations consumers use to install webpresso, in order
|
|
68
|
+
* of stability:
|
|
69
|
+
*
|
|
70
|
+
* 1. the stable global `wp` shim available on PATH
|
|
71
|
+
* 2. the currently executing `@webpresso/agent-kit` package
|
|
72
|
+
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
73
|
+
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
74
|
+
* Returns `null` when none of the candidates contain a usable `bin/wp`.
|
|
75
|
+
*/
|
|
76
|
+
export function findWebpressoMcpEntry(probe = {}) {
|
|
77
|
+
return resolveWebpressoMcpEntry(probe).entryPath;
|
|
78
|
+
}
|
|
79
|
+
function isUsableWebpressoMcpRoot(root) {
|
|
80
|
+
return WP_LAUNCHER_REQUIRED_RELATIVES.every((relativePath) => existsSync(join(root, relativePath)));
|
|
81
|
+
}
|
|
82
|
+
export function resolveWebpressoMcpEntry(probe = {}) {
|
|
83
|
+
const checked = [];
|
|
84
|
+
if (probe.candidates === undefined) {
|
|
85
|
+
const stableEntry = probe.stableEntry !== undefined
|
|
86
|
+
? probe.stableEntry()
|
|
87
|
+
: resolveExecutableOnPath("wp", process.env);
|
|
88
|
+
if (stableEntry) {
|
|
89
|
+
checked.push(stableEntry);
|
|
90
|
+
const packageWp = packageWpFromAdjacentNpmCmdShim(stableEntry);
|
|
91
|
+
if (packageWp !== null)
|
|
92
|
+
return { entryPath: packageWp, checked };
|
|
93
|
+
const verifierAllows = probe.stableEntryIsWebpresso?.(stableEntry) ?? true;
|
|
94
|
+
if (verifierAllows && isWebpressoWpEntry(stableEntry)) {
|
|
95
|
+
return { entryPath: stableEntry, checked };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const candidateGroups = probe.candidates !== undefined ? [probe.candidates] : [defaultFixedCandidates()];
|
|
100
|
+
for (const candidates of candidateGroups) {
|
|
101
|
+
for (const root of candidates) {
|
|
102
|
+
if (!root)
|
|
103
|
+
continue;
|
|
104
|
+
checked.push(root);
|
|
105
|
+
const wpBin = join(root, WP_BIN_RELATIVE);
|
|
106
|
+
if (isTrustedWebpressoPackageRoot(root))
|
|
107
|
+
return { entryPath: wpBin, checked };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { entryPath: null, checked };
|
|
111
|
+
}
|
|
112
|
+
function defaultFixedCandidates() {
|
|
113
|
+
const home = process.env.HOME || homedir();
|
|
114
|
+
const packageRoot = currentAgentKitPackageRoot();
|
|
115
|
+
const claudePlugin = join(home, ".claude", "plugins", "cache", "webpresso", "agent-kit");
|
|
116
|
+
const bunGlobal = join(home, ".bun", "install", "global", "node_modules", "@webpresso", "agent-kit");
|
|
117
|
+
return [packageRoot ?? "", claudePlugin, bunGlobal];
|
|
118
|
+
}
|
|
119
|
+
function currentAgentKitPackageRoot() {
|
|
120
|
+
let current = dirname(fileURLToPath(import.meta.url));
|
|
121
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
122
|
+
const packagePath = join(current, "package.json");
|
|
123
|
+
if (existsSync(packagePath)) {
|
|
124
|
+
try {
|
|
125
|
+
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
126
|
+
if (pkg.name === "@webpresso/agent-kit")
|
|
127
|
+
return current;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const parent = dirname(current);
|
|
134
|
+
if (parent === current)
|
|
135
|
+
break;
|
|
136
|
+
current = parent;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function isUsableWebpressoPackageRoot(packageRoot) {
|
|
141
|
+
try {
|
|
142
|
+
const pkg = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
143
|
+
return pkg.name === "@webpresso/agent-kit" && isUsableWebpressoMcpRoot(packageRoot);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function isPathInsideOrEqual(parent, candidate) {
|
|
150
|
+
const parentRoot = realpathSync(parent);
|
|
151
|
+
const candidateRoot = realpathSync(candidate);
|
|
152
|
+
const rel = relative(resolve(parentRoot), resolve(candidateRoot));
|
|
153
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
154
|
+
}
|
|
155
|
+
function isTrustedWebpressoPackageRoot(packageRoot) {
|
|
156
|
+
try {
|
|
157
|
+
if (!isUsableWebpressoPackageRoot(packageRoot))
|
|
158
|
+
return false;
|
|
159
|
+
const realPackageRoot = realpathSync(packageRoot);
|
|
160
|
+
const sourceRoot = currentAgentKitPackageRoot();
|
|
161
|
+
if (sourceRoot !== null && realPackageRoot === realpathSync(sourceRoot))
|
|
162
|
+
return true;
|
|
163
|
+
return trustedHomeInstallPackageRoots().some((anchor) => existsSync(anchor) && isPathInsideOrEqual(anchor, realPackageRoot));
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function trustedHomeInstallPackageRoots() {
|
|
170
|
+
const home = process.env.HOME || homedir();
|
|
171
|
+
return [
|
|
172
|
+
join(home, ".claude", "plugins", "cache", "webpresso", "agent-kit"),
|
|
173
|
+
join(home, ".bun", "install", "global", "node_modules", "@webpresso", "agent-kit"),
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
function packageWpFromAdjacentNpmCmdShim(entryPath) {
|
|
177
|
+
if (!entryPath.toLowerCase().endsWith(".cmd"))
|
|
178
|
+
return null;
|
|
179
|
+
const packageRoot = join(dirname(entryPath), "node_modules", "@webpresso", "agent-kit");
|
|
180
|
+
return isTrustedWebpressoPackageRoot(packageRoot) ? join(packageRoot, "bin", "wp") : null;
|
|
181
|
+
}
|
|
182
|
+
export function isWebpressoWpEntry(entryPath) {
|
|
183
|
+
try {
|
|
184
|
+
if (entryPath.toLowerCase().endsWith(".cmd"))
|
|
185
|
+
return false;
|
|
186
|
+
// Validate package ownership from the symlink target. Executing a binary
|
|
187
|
+
// and trusting its self-reported version lets any same-named PATH entry
|
|
188
|
+
// impersonate Webpresso.
|
|
189
|
+
const resolvedEntry = realpathSync(entryPath);
|
|
190
|
+
const packageRoot = dirname(dirname(resolvedEntry));
|
|
191
|
+
if (resolvedEntry !== join(packageRoot, WP_BIN_RELATIVE))
|
|
192
|
+
return false;
|
|
193
|
+
return isTrustedWebpressoPackageRoot(packageRoot);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const PROBE_SUPERVISOR = String.raw `
|
|
200
|
+
const { spawn } = require("node:child_process");
|
|
201
|
+
const input = JSON.parse(process.argv[1]);
|
|
202
|
+
const child = spawn(input.cmd, input.args, {
|
|
203
|
+
detached: process.platform !== "win32",
|
|
204
|
+
env: { ...process.env, WP_SKIP_UPDATE_CHECK: "1" },
|
|
205
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
206
|
+
windowsHide: true,
|
|
207
|
+
});
|
|
208
|
+
let output = "";
|
|
209
|
+
let timedOut = false;
|
|
210
|
+
let finished = false;
|
|
211
|
+
const signal = (name) => {
|
|
212
|
+
try {
|
|
213
|
+
if (process.platform !== "win32" && child.pid) process.kill(-child.pid, name);
|
|
214
|
+
else child.kill(name);
|
|
215
|
+
} catch {}
|
|
216
|
+
};
|
|
217
|
+
const finish = (value) => {
|
|
218
|
+
if (finished) return;
|
|
219
|
+
finished = true;
|
|
220
|
+
clearTimeout(deadline);
|
|
221
|
+
clearTimeout(forceKill);
|
|
222
|
+
process.stdout.write(JSON.stringify(value));
|
|
223
|
+
};
|
|
224
|
+
let forceKill;
|
|
225
|
+
const deadline = setTimeout(() => {
|
|
226
|
+
timedOut = true;
|
|
227
|
+
signal("SIGTERM");
|
|
228
|
+
forceKill = setTimeout(() => signal("SIGKILL"), input.killGraceMs);
|
|
229
|
+
}, input.timeoutMs);
|
|
230
|
+
child.stdout.setEncoding("utf8");
|
|
231
|
+
child.stdout.on("data", (chunk) => {
|
|
232
|
+
output += chunk;
|
|
233
|
+
if (Buffer.byteLength(output) > input.maxBytes) {
|
|
234
|
+
timedOut = true;
|
|
235
|
+
output = "";
|
|
236
|
+
child.stdout.destroy();
|
|
237
|
+
signal("SIGKILL");
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
child.on("error", () => finish(null));
|
|
241
|
+
child.on("exit", (code) => finish(!timedOut && code === 0 ? output.trim() || null : null));
|
|
242
|
+
`;
|
|
243
|
+
/** Run a discovery probe with bounded output and SIGKILL escalation. */
|
|
244
|
+
export function runQuiet(cmd, args, timeoutMs = 1_500) {
|
|
245
|
+
try {
|
|
246
|
+
const output = execFileSync(process.execPath, [
|
|
247
|
+
"-e",
|
|
248
|
+
PROBE_SUPERVISOR,
|
|
249
|
+
JSON.stringify({
|
|
250
|
+
cmd,
|
|
251
|
+
args: [...args],
|
|
252
|
+
timeoutMs,
|
|
253
|
+
killGraceMs: 100,
|
|
254
|
+
maxBytes: 64 * 1024,
|
|
255
|
+
}),
|
|
256
|
+
], {
|
|
257
|
+
encoding: "utf8",
|
|
258
|
+
env: { ...process.env, WP_SKIP_UPDATE_CHECK: "1" },
|
|
259
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
260
|
+
timeout: timeoutMs + 1_000,
|
|
261
|
+
// JSON escaping can expand the supervisor's already-bounded 64 KiB payload.
|
|
262
|
+
maxBuffer: 512 * 1024,
|
|
263
|
+
});
|
|
264
|
+
return JSON.parse(output);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/** Launch tuple for the webpresso MCP server given a resolved `wp` launcher. */
|
|
271
|
+
export function agentKitMcpLaunchCommand(entryPath) {
|
|
272
|
+
return { command: entryPath, args: [...WEBPRESSO_MCP_SPEC.args] };
|
|
273
|
+
}
|
|
@@ -7,7 +7,33 @@
|
|
|
7
7
|
* only.
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync, readdirSync } from "node:fs";
|
|
10
|
-
import { dirname, join } from "node:path";
|
|
10
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
11
|
+
import { convergeUnitFromTarget } from "./convergence.js";
|
|
12
|
+
import { resolveUntrackedCollision } from "./untracked-collision.js";
|
|
13
|
+
function guardUntrackedOverwrite(targetPath, incoming, opts) {
|
|
14
|
+
if (!opts.repoRoot)
|
|
15
|
+
return;
|
|
16
|
+
const repoRoot = resolve(opts.repoRoot);
|
|
17
|
+
const target = resolve(targetPath);
|
|
18
|
+
const repoRelative = relative(repoRoot, target);
|
|
19
|
+
if (repoRelative.length === 0 ||
|
|
20
|
+
repoRelative === ".." ||
|
|
21
|
+
repoRelative.startsWith(`..${sep}`) ||
|
|
22
|
+
isAbsolute(repoRelative)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const result = resolveUntrackedCollision({
|
|
26
|
+
unit: convergeUnitFromTarget(repoRoot, target, {
|
|
27
|
+
action: "modify",
|
|
28
|
+
scope: "repo-committed",
|
|
29
|
+
reason: "setup merge target",
|
|
30
|
+
}),
|
|
31
|
+
desiredContent: incoming,
|
|
32
|
+
force: opts.overwrite,
|
|
33
|
+
});
|
|
34
|
+
if (!result.ok)
|
|
35
|
+
throw new Error(result.error);
|
|
36
|
+
}
|
|
11
37
|
export function writeFileMerged(targetPath, incoming, opts = {}) {
|
|
12
38
|
const exists = existsSync(targetPath);
|
|
13
39
|
const existingContent = exists ? readFileSync(targetPath, "utf8") : null;
|
|
@@ -25,6 +51,7 @@ export function writeFileMerged(targetPath, incoming, opts = {}) {
|
|
|
25
51
|
if (shouldOverwrite) {
|
|
26
52
|
if (opts.dryRun)
|
|
27
53
|
return { targetPath, action: "skipped-dry" };
|
|
54
|
+
guardUntrackedOverwrite(targetPath, incoming, opts);
|
|
28
55
|
writeFileSync(targetPath, incoming);
|
|
29
56
|
return { targetPath, action: "overwritten" };
|
|
30
57
|
}
|
|
@@ -92,6 +119,8 @@ export function patchJsonFile(targetPath, patcher, opts = {}) {
|
|
|
92
119
|
if (opts.dryRun) {
|
|
93
120
|
return { targetPath, action: "skipped-dry" };
|
|
94
121
|
}
|
|
122
|
+
if (exists)
|
|
123
|
+
guardUntrackedOverwrite(targetPath, incoming, opts);
|
|
95
124
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
96
125
|
writeFileSync(targetPath, incoming);
|
|
97
126
|
return { targetPath, action: exists ? "overwritten" : "created" };
|
|
@@ -8,6 +8,13 @@ export interface ResolveAgentKitPackageRootOptions {
|
|
|
8
8
|
readonly pathExtEnv?: string;
|
|
9
9
|
readonly platform?: NodeJS.Platform;
|
|
10
10
|
readonly requireCatalog?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Optional cwd anchor used as a last-resort walk start when module/argv/PATH
|
|
13
|
+
* anchors cannot locate a root (virtual bunfs/vite moduleUrl, vitest entry).
|
|
14
|
+
* Not defaulted to process.cwd() so hermetic tests stay isolated from the
|
|
15
|
+
* monorepo checkout the test process runs in.
|
|
16
|
+
*/
|
|
17
|
+
readonly cwd?: string;
|
|
11
18
|
}
|
|
12
19
|
export declare function isAgentKitPackageRoot(dir: string, options?: {
|
|
13
20
|
readonly requireCatalog?: boolean;
|
|
@@ -84,13 +84,15 @@ export function isAgentKitPackageRoot(dir, options = {}) {
|
|
|
84
84
|
return false;
|
|
85
85
|
return hasStableAgentKitRootMarker(dir);
|
|
86
86
|
}
|
|
87
|
+
/** Max parent-walk hops from a start path. Deep pnpm/vitest/store layouts exceed 10. */
|
|
88
|
+
const PACKAGE_ROOT_WALK_MAX_DEPTH = 32;
|
|
87
89
|
export function findAgentKitPackageRoot(startPath, options = {}) {
|
|
88
90
|
if (!isRunnablePath(startPath))
|
|
89
91
|
return null;
|
|
90
92
|
const platform = options.platform ?? process.platform;
|
|
91
93
|
const pathModule = pathModuleForPlatform(platform);
|
|
92
94
|
let dir = pathModule.dirname(startPath);
|
|
93
|
-
for (let depth = 0; depth <
|
|
95
|
+
for (let depth = 0; depth < PACKAGE_ROOT_WALK_MAX_DEPTH; depth++) {
|
|
94
96
|
if (isAgentKitPackageRoot(dir, options))
|
|
95
97
|
return dir;
|
|
96
98
|
const parent = pathModule.dirname(dir);
|
|
@@ -113,7 +115,13 @@ export function resolveAgentKitPackageRoot(options = {}) {
|
|
|
113
115
|
platform,
|
|
114
116
|
});
|
|
115
117
|
const requireCatalog = options.requireCatalog;
|
|
116
|
-
|
|
118
|
+
// Opt-in cwd last: monorepo/test hosts often run from the package root when
|
|
119
|
+
// moduleUrl is virtual (bunfs/vite) or argv points outside the tree (vitest).
|
|
120
|
+
// Callers that want the fallback pass `cwd` explicitly (see hook launchers).
|
|
121
|
+
const cwdStart = typeof options.cwd === "string" && options.cwd.length > 0
|
|
122
|
+
? join(options.cwd, "package.json")
|
|
123
|
+
: undefined;
|
|
124
|
+
for (const startPath of [modulePath, argv1, execPath, pathResolvedBin, argv0, cwdStart]) {
|
|
117
125
|
const root = findAgentKitPackageRoot(startPath ?? undefined, { requireCatalog, platform });
|
|
118
126
|
if (root)
|
|
119
127
|
return root;
|
|
@@ -10,9 +10,6 @@ export declare const PLUGIN_CACHE_TARGETS: readonly [{
|
|
|
10
10
|
}, {
|
|
11
11
|
readonly host: "opencode";
|
|
12
12
|
readonly rootParts: readonly [".config", "opencode", "plugins", "cache"];
|
|
13
|
-
}, {
|
|
14
|
-
readonly host: "windsurf";
|
|
15
|
-
readonly rootParts: readonly [".windsurf", "plugins", "cache"];
|
|
16
13
|
}, {
|
|
17
14
|
readonly host: "agents";
|
|
18
15
|
readonly rootParts: readonly [".agents", "plugins", "cache"];
|
|
@@ -6,7 +6,6 @@ export const PLUGIN_CACHE_TARGETS = [
|
|
|
6
6
|
{ host: "codex", rootParts: [".codex", "plugins", "cache"] },
|
|
7
7
|
{ host: "opencode", rootParts: [".opencode", "plugins", "cache"] },
|
|
8
8
|
{ host: "opencode", rootParts: [".config", "opencode", "plugins", "cache"] },
|
|
9
|
-
{ host: "windsurf", rootParts: [".windsurf", "plugins", "cache"] },
|
|
10
9
|
{ host: "agents", rootParts: [".agents", "plugins", "cache"] },
|
|
11
10
|
{ host: "factory", rootParts: [".factory", "plugins", "cache"] },
|
|
12
11
|
];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentkitConfig } from "./config.js";
|
|
2
2
|
import type { ConsumerContext } from "./detect-consumer.js";
|
|
3
3
|
import { type MergeOptions, type MergeResult } from "./merge.js";
|
|
4
|
-
export declare const AGENTS_MD_MAX_BYTES =
|
|
4
|
+
export declare const AGENTS_MD_MAX_BYTES = 8180;
|
|
5
5
|
export declare function renderRepositoryMap(consumer: ConsumerContext): string;
|
|
6
6
|
export declare function renderTechStack(consumer: ConsumerContext): string;
|
|
7
7
|
export interface ScaffoldAgentsMdInput {
|
|
@@ -29,9 +29,15 @@ const TECH_STACK_RULES = [
|
|
|
29
29
|
{ dep: /^zod$/, label: "Zod" },
|
|
30
30
|
{ dep: /^typescript$/, label: "TypeScript" },
|
|
31
31
|
];
|
|
32
|
-
// Kept under 8 KB (8192
|
|
33
|
-
// `
|
|
34
|
-
|
|
32
|
+
// Kept under the 8 KB (8192-byte) hard ceiling. The rendered template embeds
|
|
33
|
+
// the full `native_tool_names` registry list, so this soft target tracks the
|
|
34
|
+
// tool count: adding an MCP tool grows the list by ~15-17 bytes. Bumped
|
|
35
|
+
// 8_100 -> 8_180 for the four-tool batch (wp_ci_preflight, wp_session_id,
|
|
36
|
+
// wp_session_info, wp_review_run), which renders ~8_160 — still 30+ bytes under
|
|
37
|
+
// 8_192. The 8_192 ceiling is the real guardrail; the next addition that would
|
|
38
|
+
// breach it should trigger a conscious restructure (or exclude the
|
|
39
|
+
// auto-generated tool list from the prose budget), not another reflexive bump.
|
|
40
|
+
export const AGENTS_MD_MAX_BYTES = 8_180;
|
|
35
41
|
export function renderRepositoryMap(consumer) {
|
|
36
42
|
const packages = consumer.workspacePackages;
|
|
37
43
|
if (packages.length === 0) {
|
|
@@ -14,6 +14,26 @@ interface PackageJsonLike {
|
|
|
14
14
|
[key: string]: unknown;
|
|
15
15
|
}
|
|
16
16
|
export declare function readSetupWpActionRef(metaUrl: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Idempotent, inject-by-content-absence repair for the managed `wp audit
|
|
19
|
+
* guardrails` CI step. On every `wp setup`, re-inserts the step into any
|
|
20
|
+
* wp-enabled quality workflow whose content lacks a guardrails invocation, so a
|
|
21
|
+
* consumer who deleted the step (with or without its comments) gets it back —
|
|
22
|
+
* and therefore keeps inheriting new guardrails (e.g. typescript-version) on
|
|
23
|
+
* their next agent-kit bump. Returns the content unchanged when the step is
|
|
24
|
+
* already present, the workflow is not a wp quality pipeline, no test step
|
|
25
|
+
* anchor exists, or `repoAlreadyWired` is true (guardrails already run in a
|
|
26
|
+
* sibling workflow of the same repo — see `migrateConsumerWorkflows`, and
|
|
27
|
+
* tech-debt h-017: without this check a consumer who deliberately hosts
|
|
28
|
+
* guardrails in a dedicated `guardrails.yml` got a duplicate step injected
|
|
29
|
+
* into `ci.yml` on every `wp setup`).
|
|
30
|
+
*
|
|
31
|
+
* `hasGuardrailsInvocation`/`findLiveTestRunAnchor` come from the shared
|
|
32
|
+
* `ci-guardrails-detection` module also used by `auditCiGuardrailsWiring`, so
|
|
33
|
+
* the audit and this injector can never disagree about what counts as a wired
|
|
34
|
+
* guardrails step or a live test-run anchor (tech-debt h-016).
|
|
35
|
+
*/
|
|
36
|
+
export declare function ensureGuardrailsCiStep(content: string, repoAlreadyWired?: boolean): string;
|
|
17
37
|
export declare function readAgentConfigVersion(metaUrl: string): string;
|
|
18
38
|
export declare function collectRuntimeContractGuidance(packageJson: PackageJsonLike | null | undefined): RuntimeContractGuidance;
|
|
19
39
|
export declare const BASE_KIT_QUALITY_TARGETS: string[];
|
|
@@ -3,6 +3,7 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
4
4
|
import { writeFileMerged } from "./merge.js";
|
|
5
5
|
import { resolveAgentKitPackageRoot } from "./package-root.js";
|
|
6
|
+
import { findLiveTestRunAnchor, hasGuardrailsInvocation } from "#audit/ci-guardrails-detection.js";
|
|
6
7
|
import { readPackageVersion } from "#cli/utils";
|
|
7
8
|
import { SETUP_WP_ACTION_REF } from "#build/release-action-ref.js";
|
|
8
9
|
const AUTHORING_TIME_DEPENDENCIES = [
|
|
@@ -162,16 +163,71 @@ function migrateWorkflowContent(content, actionRef, version) {
|
|
|
162
163
|
})
|
|
163
164
|
.join("\n");
|
|
164
165
|
}
|
|
166
|
+
// A workflow is a wp-enabled quality pipeline when it both installs the `wp`
|
|
167
|
+
// runtime and runs the default test suite. Gating on a wp-runtime anchor keeps
|
|
168
|
+
// injection off non-wp workflows (a reusable-workflow release.yml, or
|
|
169
|
+
// agent-kit's own source-built CI) that must never get a consumer step. Two
|
|
170
|
+
// install shapes count as the anchor: the `setup-wp` GitHub Action, and a
|
|
171
|
+
// global npm/pnpm/vp install of `@webpresso/agent-kit` — the documented
|
|
172
|
+
// third-party quick start for consumers that don't use the action (see
|
|
173
|
+
// `package-conventions.md`; e.g. ozby/edge-matte's ci.yml).
|
|
174
|
+
const SETUP_WP_MARKER = "setup-wp@";
|
|
175
|
+
const GLOBAL_AGENT_KIT_INSTALL = /^(?=.*\b(?:npm|pnpm|vp)\s+(?:install|i|add)\b)(?=.*(?:-g\b|--global\b))(?=.*@webpresso\/agent-kit\b).*$/imu;
|
|
176
|
+
function hasWpRuntimeAnchor(content) {
|
|
177
|
+
return content.includes(SETUP_WP_MARKER) || GLOBAL_AGENT_KIT_INSTALL.test(content);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Idempotent, inject-by-content-absence repair for the managed `wp audit
|
|
181
|
+
* guardrails` CI step. On every `wp setup`, re-inserts the step into any
|
|
182
|
+
* wp-enabled quality workflow whose content lacks a guardrails invocation, so a
|
|
183
|
+
* consumer who deleted the step (with or without its comments) gets it back —
|
|
184
|
+
* and therefore keeps inheriting new guardrails (e.g. typescript-version) on
|
|
185
|
+
* their next agent-kit bump. Returns the content unchanged when the step is
|
|
186
|
+
* already present, the workflow is not a wp quality pipeline, no test step
|
|
187
|
+
* anchor exists, or `repoAlreadyWired` is true (guardrails already run in a
|
|
188
|
+
* sibling workflow of the same repo — see `migrateConsumerWorkflows`, and
|
|
189
|
+
* tech-debt h-017: without this check a consumer who deliberately hosts
|
|
190
|
+
* guardrails in a dedicated `guardrails.yml` got a duplicate step injected
|
|
191
|
+
* into `ci.yml` on every `wp setup`).
|
|
192
|
+
*
|
|
193
|
+
* `hasGuardrailsInvocation`/`findLiveTestRunAnchor` come from the shared
|
|
194
|
+
* `ci-guardrails-detection` module also used by `auditCiGuardrailsWiring`, so
|
|
195
|
+
* the audit and this injector can never disagree about what counts as a wired
|
|
196
|
+
* guardrails step or a live test-run anchor (tech-debt h-016).
|
|
197
|
+
*/
|
|
198
|
+
export function ensureGuardrailsCiStep(content, repoAlreadyWired = false) {
|
|
199
|
+
if (hasGuardrailsInvocation(content))
|
|
200
|
+
return content;
|
|
201
|
+
if (repoAlreadyWired)
|
|
202
|
+
return content;
|
|
203
|
+
if (!hasWpRuntimeAnchor(content))
|
|
204
|
+
return content;
|
|
205
|
+
const anchorStepStart = findLiveTestRunAnchor(content);
|
|
206
|
+
if (anchorStepStart === -1)
|
|
207
|
+
return content;
|
|
208
|
+
const lines = content.split("\n");
|
|
209
|
+
// Safe: anchorStepStart is an index returned by findLiveTestRunAnchor over
|
|
210
|
+
// this same content.split("\n"), so it is always within lines' bounds here.
|
|
211
|
+
const indent = lines[anchorStepStart].match(/^(\s*)/u)?.[1] ?? "";
|
|
212
|
+
lines.splice(anchorStepStart, 0, `${indent}- name: Run wp audit guardrails`, `${indent} run: wp audit guardrails`);
|
|
213
|
+
return lines.join("\n");
|
|
214
|
+
}
|
|
165
215
|
function migrateConsumerWorkflows(repoRoot, actionRef, version, options) {
|
|
166
216
|
const workflowDir = join(repoRoot, ".github", "workflows");
|
|
167
217
|
if (!existsSync(workflowDir))
|
|
168
218
|
return [];
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
219
|
+
const names = readdirSync(workflowDir).filter((name) => name.endsWith(".yml") || name.endsWith(".yaml"));
|
|
220
|
+
// Read every workflow's original content once, up front, so per-file
|
|
221
|
+
// injection below can see the REPO-LEVEL wiring state (mirrors how
|
|
222
|
+
// `auditCiGuardrailsWiring` reasons across all workflows) instead of only
|
|
223
|
+
// the file it happens to be looking at. Without this, a consumer who
|
|
224
|
+
// deliberately hosts guardrails in a dedicated `guardrails.yml` gets a
|
|
225
|
+
// duplicate step injected into `ci.yml` on every `wp setup` (h-017).
|
|
226
|
+
const entries = names.map((name) => [name, readFileSync(join(workflowDir, name), "utf8")]);
|
|
227
|
+
const repoAlreadyWired = entries.some(([, content]) => hasGuardrailsInvocation(content));
|
|
228
|
+
return entries.map(([name, existing]) => {
|
|
172
229
|
const targetPath = join(workflowDir, name);
|
|
173
|
-
const
|
|
174
|
-
const migrated = migrateWorkflowContent(existing, actionRef, version);
|
|
230
|
+
const migrated = ensureGuardrailsCiStep(migrateWorkflowContent(existing, actionRef, version), repoAlreadyWired);
|
|
175
231
|
if (migrated === existing)
|
|
176
232
|
return { targetPath, action: "identical" };
|
|
177
233
|
if (options.dryRun)
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Grok Build native project hooks emitter.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Grok reads project hook configs from `.grok/hooks/*.json` — a near-clone of
|
|
5
|
+
* the Claude Code hook contract (stdin event JSON incl. hookEventName/cwd,
|
|
6
|
+
* regex matchers, exit code 2 = deny, JSON stdout for decisions). We write one
|
|
7
|
+
* managed file, `.grok/hooks/webpresso.json`, with commands labeled
|
|
8
|
+
* `WP_HOOK_HOST=grok`. Hooks are trust-gated: the user must run `/hooks-trust`
|
|
9
|
+
* once in Grok before they fire (fail-open on timeout).
|
|
10
|
+
*
|
|
11
|
+
* Managed events are the intersection of WP_HOOK_SPECS with Grok's documented
|
|
12
|
+
* event set — notably Grok has no PermissionRequest event (it has
|
|
13
|
+
* PermissionDenied instead), so that spec is skipped.
|
|
7
14
|
*/
|
|
8
|
-
export declare const
|
|
15
|
+
export declare const GROK_HOOKS_DIR_RELATIVE_PATH = ".grok/hooks";
|
|
16
|
+
export declare const GROK_HOOKS_RELATIVE_PATH = ".grok/hooks/webpresso.json";
|
|
9
17
|
export type GrokHooksDocument = {
|
|
10
|
-
readonly version: 1;
|
|
11
|
-
readonly host: "grok";
|
|
12
18
|
readonly hooks: Readonly<Record<string, readonly {
|
|
13
19
|
readonly matcher?: string;
|
|
14
20
|
readonly hooks: readonly {
|
|
@@ -19,8 +25,8 @@ export type GrokHooksDocument = {
|
|
|
19
25
|
}[]>>;
|
|
20
26
|
};
|
|
21
27
|
/**
|
|
22
|
-
* Build managed Grok hook
|
|
23
|
-
*
|
|
28
|
+
* Build the managed Grok hook document (Claude-contract wrapped shape:
|
|
29
|
+
* `{ "hooks": { Event: [ { matcher?, hooks: [...] } ] } }`).
|
|
24
30
|
*/
|
|
25
31
|
export declare function buildGrokHookDocument(input: {
|
|
26
32
|
readonly resolveBin: (name: string) => string;
|