@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.
Potentially problematic release.
This version of @webpresso/agent-kit might be problematic. Click here for more details.
- 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
|
@@ -18,15 +18,17 @@
|
|
|
18
18
|
* provisioned, exact-version binaries with environment-variable names
|
|
19
19
|
* forwarded through Codex's stdio `env_vars` allow-list.
|
|
20
20
|
*/
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
21
|
+
import { spawnSync } from "node:child_process";
|
|
22
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
23
23
|
import { homedir } from "node:os";
|
|
24
24
|
import { dirname, join } from "node:path";
|
|
25
|
-
import {
|
|
26
|
-
|
|
25
|
+
import { agentKitMcpLaunchCommand, findWebpressoMcpEntry, resolveExecutableOnPath, resolveWebpressoMcpEntry, WEBPRESSO_MCP_SERVER_NAME, WEBPRESSO_MCP_SPEC, } from "#cli/commands/init/mcp-spec.js";
|
|
26
|
+
// Re-exported so existing importers (tests) keep a stable path; the canonical
|
|
27
|
+
// implementation now lives in `mcp-spec.ts`.
|
|
28
|
+
export { findWebpressoMcpEntry, WEBPRESSO_MCP_SERVER_NAME };
|
|
29
|
+
import { updateScaffolderTextFile } from "#cli/commands/init/scaffolders/file-transaction.js";
|
|
27
30
|
import { isJsonRecord, isUnsafeRuntimeLauncher, parseJson, parseProjectMcpServers, parseTomlString, } from "#hooks/host-config-contract.js";
|
|
28
31
|
import { appendGlobalCapableVpArgs, resolveGlobalCapableVpCommand, } from "#cli/global-vp.js";
|
|
29
|
-
import { pathCandidates } from "#runtime/command-exists.js";
|
|
30
32
|
import { writeFileAtomic } from "#shared-utils/write-json-file.js";
|
|
31
33
|
export const PLAYWRIGHT_MCP_SERVER_NAME = "playwright";
|
|
32
34
|
export const PLAYWRIGHT_MCP_VERSION = "0.0.78";
|
|
@@ -42,56 +44,8 @@ const PLAYWRIGHT_STDIO_MCP_DEFINITION = {
|
|
|
42
44
|
command: "vp",
|
|
43
45
|
args: ["dlx", PLAYWRIGHT_MCP_PACKAGE, ...PLAYWRIGHT_MCP_ARGS],
|
|
44
46
|
};
|
|
45
|
-
const CODEX_CONFIG_LOCK_TIMEOUT_MS = 5_000;
|
|
46
|
-
const CODEX_CONFIG_LOCK_POLL_MS = 25;
|
|
47
|
-
const CODEX_CONFIG_LOCK_STALE_MS = 30_000;
|
|
48
|
-
function sleepSync(ms) {
|
|
49
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
50
|
-
}
|
|
51
|
-
function acquireCodexConfigLock(configPath) {
|
|
52
|
-
mkdirSync(dirname(configPath), { recursive: true });
|
|
53
|
-
const startedAt = Date.now();
|
|
54
|
-
while (true) {
|
|
55
|
-
try {
|
|
56
|
-
return lockfile.lockSync(configPath, {
|
|
57
|
-
realpath: false,
|
|
58
|
-
stale: CODEX_CONFIG_LOCK_STALE_MS,
|
|
59
|
-
update: CODEX_CONFIG_LOCK_STALE_MS / 2,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
if (error.code !== "ELOCKED")
|
|
64
|
-
throw error;
|
|
65
|
-
if (Date.now() - startedAt >= CODEX_CONFIG_LOCK_TIMEOUT_MS) {
|
|
66
|
-
throw new Error(`Timed out waiting for Codex config lock: ${configPath}`, {
|
|
67
|
-
cause: error,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
sleepSync(CODEX_CONFIG_LOCK_POLL_MS);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function withCodexConfigLock(configPath, action) {
|
|
75
|
-
const release = acquireCodexConfigLock(configPath);
|
|
76
|
-
try {
|
|
77
|
-
return action();
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
release();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function readCodexConfig(configPath) {
|
|
84
|
-
return existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
85
|
-
}
|
|
86
47
|
function updateCodexConfig(configPath, transform) {
|
|
87
|
-
return
|
|
88
|
-
const existing = readCodexConfig(configPath);
|
|
89
|
-
const next = transform(existing);
|
|
90
|
-
if (next === existing)
|
|
91
|
-
return "unchanged";
|
|
92
|
-
writeFileAtomic(configPath, next, "utf8");
|
|
93
|
-
return "written";
|
|
94
|
-
});
|
|
48
|
+
return updateScaffolderTextFile(configPath, transform);
|
|
95
49
|
}
|
|
96
50
|
function tomlString(value) {
|
|
97
51
|
return JSON.stringify(value);
|
|
@@ -118,15 +72,254 @@ export function commandMcpCodexBlock(definition) {
|
|
|
118
72
|
if (definition.codexEnvVars && definition.codexEnvVars.length > 0) {
|
|
119
73
|
lines.push(`env_vars = ${tomlStringArray(definition.codexEnvVars)}`);
|
|
120
74
|
}
|
|
75
|
+
if (definition.codexEnv && Object.keys(definition.codexEnv).length > 0) {
|
|
76
|
+
const pairs = Object.entries(definition.codexEnv).map(([key, value]) => `${key} = ${tomlString(value)}`);
|
|
77
|
+
lines.push(`env = { ${pairs.join(", ")} }`);
|
|
78
|
+
}
|
|
121
79
|
lines.push("enabled = true");
|
|
122
80
|
for (const [key, value] of Object.entries(definition.codexFields ?? {})) {
|
|
123
81
|
lines.push(`${key} = ${tomlValue(value)}`);
|
|
124
82
|
}
|
|
125
83
|
return `${lines.join("\n")}\n`;
|
|
126
84
|
}
|
|
85
|
+
function parseTomlTableHeader(line) {
|
|
86
|
+
const match = line.match(/^\s*\[\s*([\s\S]*?)\s*\]\s*(?:#.*)?$/u);
|
|
87
|
+
if (!match || line.trimStart().startsWith("[["))
|
|
88
|
+
return null;
|
|
89
|
+
return parseTomlDottedKey(match[1] ?? "");
|
|
90
|
+
}
|
|
91
|
+
function parseTomlArrayTableHeader(line) {
|
|
92
|
+
const match = line.match(/^\s*\[\[\s*([\s\S]*?)\s*\]\]\s*(?:#.*)?$/u);
|
|
93
|
+
if (!match)
|
|
94
|
+
return null;
|
|
95
|
+
return parseTomlDottedKey(match[1] ?? "");
|
|
96
|
+
}
|
|
97
|
+
function parseTomlDottedKey(raw) {
|
|
98
|
+
const segments = [];
|
|
99
|
+
let i = 0;
|
|
100
|
+
const skipSpace = () => {
|
|
101
|
+
while (/\s/u.test(raw[i] ?? ""))
|
|
102
|
+
i += 1;
|
|
103
|
+
};
|
|
104
|
+
while (i < raw.length) {
|
|
105
|
+
skipSpace();
|
|
106
|
+
const segment = parseTomlKeySegment(raw, i);
|
|
107
|
+
if (!segment)
|
|
108
|
+
return null;
|
|
109
|
+
segments.push(segment.value);
|
|
110
|
+
i = segment.next;
|
|
111
|
+
skipSpace();
|
|
112
|
+
if (i >= raw.length)
|
|
113
|
+
break;
|
|
114
|
+
if (raw[i] !== ".")
|
|
115
|
+
return null;
|
|
116
|
+
i += 1;
|
|
117
|
+
}
|
|
118
|
+
return segments.length > 0 ? segments : null;
|
|
119
|
+
}
|
|
120
|
+
function parseTomlKeySegment(raw, start) {
|
|
121
|
+
const first = raw[start];
|
|
122
|
+
if (first === "'") {
|
|
123
|
+
const end = raw.indexOf("'", start + 1);
|
|
124
|
+
if (end === -1)
|
|
125
|
+
return null;
|
|
126
|
+
return { value: raw.slice(start + 1, end), next: end + 1 };
|
|
127
|
+
}
|
|
128
|
+
if (first === '"') {
|
|
129
|
+
return parseBasicTomlKeySegment(raw, start);
|
|
130
|
+
}
|
|
131
|
+
let end = start;
|
|
132
|
+
while (/[A-Za-z0-9_-]/u.test(raw[end] ?? ""))
|
|
133
|
+
end += 1;
|
|
134
|
+
if (end === start)
|
|
135
|
+
return null;
|
|
136
|
+
return { value: raw.slice(start, end), next: end };
|
|
137
|
+
}
|
|
138
|
+
function parseBasicTomlKeySegment(raw, start) {
|
|
139
|
+
let value = "";
|
|
140
|
+
for (let i = start + 1; i < raw.length; i += 1) {
|
|
141
|
+
const ch = raw[i];
|
|
142
|
+
if (ch === '"')
|
|
143
|
+
return { value, next: i + 1 };
|
|
144
|
+
if (ch !== "\\") {
|
|
145
|
+
value += ch;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const escaped = raw[i + 1];
|
|
149
|
+
if (escaped === undefined)
|
|
150
|
+
return null;
|
|
151
|
+
const simple = {
|
|
152
|
+
b: "\b",
|
|
153
|
+
t: "\t",
|
|
154
|
+
n: "\n",
|
|
155
|
+
f: "\f",
|
|
156
|
+
r: "\r",
|
|
157
|
+
'"': '"',
|
|
158
|
+
"\\": "\\",
|
|
159
|
+
};
|
|
160
|
+
if (escaped in simple) {
|
|
161
|
+
value += simple[escaped];
|
|
162
|
+
i += 1;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (escaped === "u" || escaped === "U") {
|
|
166
|
+
const width = escaped === "u" ? 4 : 8;
|
|
167
|
+
const hex = raw.slice(i + 2, i + 2 + width);
|
|
168
|
+
if (!new RegExp(`^[0-9A-Fa-f]{${width}}$`, "u").test(hex))
|
|
169
|
+
return null;
|
|
170
|
+
value += String.fromCodePoint(Number.parseInt(hex, 16));
|
|
171
|
+
i += 1 + width;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
function isServerTableHeader(line, serverId) {
|
|
179
|
+
const segments = parseTomlTableHeader(line);
|
|
180
|
+
return segments?.length === 2 && segments[0] === "mcp_servers" && segments[1] === serverId;
|
|
181
|
+
}
|
|
127
182
|
function isOwnedSubTableHeader(line, serverId) {
|
|
128
|
-
const
|
|
129
|
-
return
|
|
183
|
+
const segments = parseTomlTableHeader(line);
|
|
184
|
+
return (segments !== null &&
|
|
185
|
+
segments.length > 2 &&
|
|
186
|
+
segments[0] === "mcp_servers" &&
|
|
187
|
+
segments[1] === serverId);
|
|
188
|
+
}
|
|
189
|
+
function isOwnedServerOrDescendantTableHeader(line, serverId) {
|
|
190
|
+
const segments = parseTomlArrayTableHeader(line) ?? parseTomlTableHeader(line);
|
|
191
|
+
return (segments !== null &&
|
|
192
|
+
segments.length >= 2 &&
|
|
193
|
+
segments[0] === "mcp_servers" &&
|
|
194
|
+
segments[1] === serverId);
|
|
195
|
+
}
|
|
196
|
+
function tomlLinesStartingInsideMultilineString(lines) {
|
|
197
|
+
const insideAtStart = [];
|
|
198
|
+
let delimiter = null;
|
|
199
|
+
for (const line of lines) {
|
|
200
|
+
insideAtStart.push(delimiter !== null);
|
|
201
|
+
for (let i = 0; i < line.length; i += 1) {
|
|
202
|
+
if (delimiter !== null) {
|
|
203
|
+
const end = findTomlMultilineStringEnd(line, i, delimiter);
|
|
204
|
+
if (end === -1)
|
|
205
|
+
break;
|
|
206
|
+
i = end + delimiter.length - 1;
|
|
207
|
+
delimiter = null;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const ch = line[i];
|
|
211
|
+
if (ch === "#")
|
|
212
|
+
break;
|
|
213
|
+
if (line.startsWith('"""', i) || line.startsWith("'''", i)) {
|
|
214
|
+
delimiter = line.startsWith('"""', i) ? '"""' : "'''";
|
|
215
|
+
i += delimiter.length - 1;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (ch === '"') {
|
|
219
|
+
i += 1;
|
|
220
|
+
while (i < line.length) {
|
|
221
|
+
const inner = line[i];
|
|
222
|
+
if (inner === "\\") {
|
|
223
|
+
i += 2;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (inner === '"')
|
|
227
|
+
break;
|
|
228
|
+
i += 1;
|
|
229
|
+
}
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (ch === "'") {
|
|
233
|
+
const end = line.indexOf("'", i + 1);
|
|
234
|
+
if (end === -1)
|
|
235
|
+
break;
|
|
236
|
+
i = end;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return insideAtStart;
|
|
241
|
+
}
|
|
242
|
+
function findTomlMultilineStringEnd(line, start, delimiter) {
|
|
243
|
+
if (delimiter === "'''")
|
|
244
|
+
return line.indexOf(delimiter, start);
|
|
245
|
+
for (let i = start; i < line.length; i += 1) {
|
|
246
|
+
if (!line.startsWith(delimiter, i))
|
|
247
|
+
continue;
|
|
248
|
+
let backslashes = 0;
|
|
249
|
+
for (let j = i - 1; j >= 0 && line[j] === "\\"; j -= 1)
|
|
250
|
+
backslashes += 1;
|
|
251
|
+
if (backslashes % 2 === 0)
|
|
252
|
+
return i;
|
|
253
|
+
}
|
|
254
|
+
return -1;
|
|
255
|
+
}
|
|
256
|
+
function tomlAssignmentKey(line) {
|
|
257
|
+
let quote = null;
|
|
258
|
+
let escaped = false;
|
|
259
|
+
for (let i = 0; i < line.length; i += 1) {
|
|
260
|
+
const ch = line[i];
|
|
261
|
+
if (quote !== null) {
|
|
262
|
+
if (quote === '"' && escaped) {
|
|
263
|
+
escaped = false;
|
|
264
|
+
}
|
|
265
|
+
else if (quote === '"' && ch === "\\") {
|
|
266
|
+
escaped = true;
|
|
267
|
+
}
|
|
268
|
+
else if (ch === quote) {
|
|
269
|
+
quote = null;
|
|
270
|
+
}
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (ch === '"' || ch === "'") {
|
|
274
|
+
quote = ch;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (ch === "#")
|
|
278
|
+
return null;
|
|
279
|
+
if (ch === "=")
|
|
280
|
+
return parseTomlDottedKey(line.slice(0, i).trim());
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
function hasDottedServerDefinition(lines, startsInsideMultiline, serverId) {
|
|
285
|
+
let currentTable = null;
|
|
286
|
+
return lines.some((line, index) => {
|
|
287
|
+
if (startsInsideMultiline[index])
|
|
288
|
+
return false;
|
|
289
|
+
const arrayTable = parseTomlArrayTableHeader(line);
|
|
290
|
+
if (arrayTable !== null &&
|
|
291
|
+
arrayTable.length >= 2 &&
|
|
292
|
+
arrayTable[0] === "mcp_servers" &&
|
|
293
|
+
arrayTable[1] === serverId) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
const table = parseTomlTableHeader(line);
|
|
297
|
+
if (table !== null) {
|
|
298
|
+
currentTable = table;
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const segments = tomlAssignmentKey(line);
|
|
302
|
+
return (segments !== null &&
|
|
303
|
+
((segments.length >= 2 && segments[0] === "mcp_servers" && segments[1] === serverId) ||
|
|
304
|
+
(currentTable?.length === 1 &&
|
|
305
|
+
currentTable[0] === "mcp_servers" &&
|
|
306
|
+
segments[0] === serverId)));
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
export function hasAmbiguousMcpServerDottedDefinition(raw, serverId) {
|
|
310
|
+
const lines = raw.trimEnd().split(/\r?\n/);
|
|
311
|
+
const startsInsideMultiline = tomlLinesStartingInsideMultilineString(lines);
|
|
312
|
+
const start = lines.findIndex((line, index) => !startsInsideMultiline[index] && isServerTableHeader(line, serverId));
|
|
313
|
+
return start === -1 && hasDottedServerDefinition(lines, startsInsideMultiline, serverId);
|
|
314
|
+
}
|
|
315
|
+
export function hasManagedMcpServerTableConflict(raw, serverId) {
|
|
316
|
+
const lines = raw.trimEnd().split(/\r?\n/);
|
|
317
|
+
const startsInsideMultiline = tomlLinesStartingInsideMultilineString(lines);
|
|
318
|
+
const start = lines.findIndex((line, index) => !startsInsideMultiline[index] && isServerTableHeader(line, serverId));
|
|
319
|
+
if (start === -1)
|
|
320
|
+
return hasDottedServerDefinition(lines, startsInsideMultiline, serverId);
|
|
321
|
+
const end = managedSectionEnd(lines, startsInsideMultiline, start, serverId);
|
|
322
|
+
return hasOwnedServerTableOutsideManagedSection(lines, startsInsideMultiline, start, end, serverId);
|
|
130
323
|
}
|
|
131
324
|
/**
|
|
132
325
|
* Find the exclusive end index of the managed section region: the parent block
|
|
@@ -136,9 +329,11 @@ function isOwnedSubTableHeader(line, serverId) {
|
|
|
136
329
|
* sub-tables under foreign or absent parents are never touched (they remain
|
|
137
330
|
* doctor-report-only territory).
|
|
138
331
|
*/
|
|
139
|
-
function managedSectionEnd(lines, start, serverId) {
|
|
332
|
+
function managedSectionEnd(lines, startsInsideMultiline, start, serverId) {
|
|
140
333
|
let end = lines.length;
|
|
141
334
|
for (let i = start + 1; i < lines.length; i += 1) {
|
|
335
|
+
if (startsInsideMultiline[i])
|
|
336
|
+
continue;
|
|
142
337
|
if (!lines[i].trim().startsWith("["))
|
|
143
338
|
continue;
|
|
144
339
|
if (isOwnedSubTableHeader(lines[i], serverId))
|
|
@@ -146,20 +341,43 @@ function managedSectionEnd(lines, start, serverId) {
|
|
|
146
341
|
end = i;
|
|
147
342
|
break;
|
|
148
343
|
}
|
|
344
|
+
// Trailing comment/blank lines between the managed block and the next table
|
|
345
|
+
// belong to the surrounding document (often annotating the *next* section) —
|
|
346
|
+
// leave them in place rather than swallowing them into the regenerated block.
|
|
347
|
+
while (end > start + 1) {
|
|
348
|
+
const previous = lines[end - 1].trim();
|
|
349
|
+
if (previous.length === 0 || previous.startsWith("#")) {
|
|
350
|
+
end -= 1;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
149
355
|
return end;
|
|
150
356
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
357
|
+
function hasOwnedServerTableOutsideManagedSection(lines, startsInsideMultiline, start, end, serverId) {
|
|
358
|
+
return lines.some((line, index) => !startsInsideMultiline[index] &&
|
|
359
|
+
(index < start || index >= end) &&
|
|
360
|
+
isOwnedServerOrDescendantTableHeader(line, serverId));
|
|
361
|
+
}
|
|
362
|
+
export function upsertMcpServerBlock(raw, serverId, block) {
|
|
153
363
|
const lines = raw.trimEnd().split(/\r?\n/);
|
|
154
364
|
const hasContent = raw.trim().length > 0;
|
|
155
|
-
const
|
|
365
|
+
const startsInsideMultiline = tomlLinesStartingInsideMultilineString(lines);
|
|
366
|
+
const start = lines.findIndex((line, index) => !startsInsideMultiline[index] && isServerTableHeader(line, serverId));
|
|
156
367
|
if (start === -1) {
|
|
368
|
+
if (hasDottedServerDefinition(lines, startsInsideMultiline, serverId))
|
|
369
|
+
return raw;
|
|
157
370
|
const prefix = hasContent ? `${raw.trimEnd()}\n\n` : "";
|
|
158
371
|
return `${prefix}${block}`;
|
|
159
372
|
}
|
|
160
|
-
const end = managedSectionEnd(lines, start, serverId);
|
|
373
|
+
const end = managedSectionEnd(lines, startsInsideMultiline, start, serverId);
|
|
374
|
+
if (hasOwnedServerTableOutsideManagedSection(lines, startsInsideMultiline, start, end, serverId)) {
|
|
375
|
+
return raw;
|
|
376
|
+
}
|
|
161
377
|
const replacement = block.trimEnd().split("\n");
|
|
162
|
-
|
|
378
|
+
// Separate the block from a preserved tail — unless the tail already starts
|
|
379
|
+
// with its own blank line (kept by the trailing-comment walk-back).
|
|
380
|
+
if (end < lines.length && lines[end].trim().length !== 0)
|
|
163
381
|
replacement.push("");
|
|
164
382
|
return [...lines.slice(0, start), ...replacement, ...lines.slice(end)].join("\n") + "\n";
|
|
165
383
|
}
|
|
@@ -176,31 +394,11 @@ export function commandMcpClaudeServer(definition) {
|
|
|
176
394
|
}
|
|
177
395
|
return server;
|
|
178
396
|
}
|
|
179
|
-
export const WEBPRESSO_MCP_SERVER_NAME = "webpresso";
|
|
180
397
|
export const WEBPRESSO_MCP_HEADER = `[mcp_servers.${WEBPRESSO_MCP_SERVER_NAME}]`;
|
|
181
398
|
function defaultConfigPath() {
|
|
182
399
|
const codexHome = process.env.CODEX_HOME || join(process.env.HOME || homedir(), ".codex");
|
|
183
400
|
return join(codexHome, "config.toml");
|
|
184
401
|
}
|
|
185
|
-
function resolvePinnedMcpExecutable(binary, env) {
|
|
186
|
-
for (const candidate of pathCandidates(binary, {
|
|
187
|
-
pathEnv: env.PATH,
|
|
188
|
-
pathExtEnv: env.PATHEXT,
|
|
189
|
-
})) {
|
|
190
|
-
try {
|
|
191
|
-
if (!statSync(candidate).isFile())
|
|
192
|
-
continue;
|
|
193
|
-
if (process.platform !== "win32")
|
|
194
|
-
accessSync(candidate, constants.X_OK);
|
|
195
|
-
return candidate;
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
// Continue scanning PATH. Returning the candidate, not its realpath, keeps
|
|
199
|
-
// the generated config anchored to Vite+'s stable global-bin symlink.
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
402
|
function installedGlobalPackageMetadata(vpCommand, packageName, spawn) {
|
|
205
403
|
const listCommand = appendGlobalCapableVpArgs(vpCommand, [
|
|
206
404
|
"list",
|
|
@@ -250,7 +448,7 @@ function selectPackageBinary(definition, metadata) {
|
|
|
250
448
|
function provisionPinnedCodexMcp(input, definition) {
|
|
251
449
|
const env = input.env ?? process.env;
|
|
252
450
|
const spawn = input.spawn ?? spawnSync;
|
|
253
|
-
const resolveExecutable = input.resolveExecutable ?? ((binary) =>
|
|
451
|
+
const resolveExecutable = input.resolveExecutable ?? ((binary) => resolveExecutableOnPath(binary, env));
|
|
254
452
|
const vpCommand = input.resolveVpCommand !== undefined
|
|
255
453
|
? input.resolveVpCommand()
|
|
256
454
|
: resolveGlobalCapableVpCommand(env.PATH ?? "", process.platform, env);
|
|
@@ -462,130 +660,13 @@ export function ensureClaudePlaywrightMcp(input) {
|
|
|
462
660
|
// ────────────────────────────────────────────────────────────────────────────
|
|
463
661
|
// Agent-kit MCP server registration
|
|
464
662
|
// ────────────────────────────────────────────────────────────────────────────
|
|
465
|
-
const WP_BIN_RELATIVE = join("bin", process.platform === "win32" ? "wp.cmd" : "wp");
|
|
466
|
-
const WP_LAUNCHER_REQUIRED_RELATIVES = [
|
|
467
|
-
WP_BIN_RELATIVE,
|
|
468
|
-
join("bin", "_run.js"),
|
|
469
|
-
join("bin", "runtime-lanes.js"),
|
|
470
|
-
join("bin", "runtime-manifest.json"),
|
|
471
|
-
];
|
|
472
|
-
/**
|
|
473
|
-
* Resolve the absolute path to webpresso's global `bin/wp` launcher on this machine. Probes
|
|
474
|
-
* the locations consumers use to install webpresso, in order of stability:
|
|
475
|
-
*
|
|
476
|
-
* 1. the stable global `wp` shim available on PATH
|
|
477
|
-
* 2. the currently executing `@webpresso/agent-kit` package
|
|
478
|
-
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
479
|
-
* (path-stable; updated by Claude Code's plugin manager)
|
|
480
|
-
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
481
|
-
* 5. pnpm global — `$(pnpm root -g)/@webpresso/agent-kit/`
|
|
482
|
-
* 6. npm global — `$(npm root -g)/@webpresso/agent-kit/`
|
|
483
|
-
*
|
|
484
|
-
* Returns `null` when none of the candidates contain `bin/wp`. The caller
|
|
485
|
-
* surfaces a clear error rather than writing a broken codex config.
|
|
486
|
-
*/
|
|
487
|
-
export function findWebpressoMcpEntry(probe = {}) {
|
|
488
|
-
return resolveWebpressoMcpEntry(probe).entryPath;
|
|
489
|
-
}
|
|
490
|
-
function isUsableWebpressoMcpRoot(root) {
|
|
491
|
-
return WP_LAUNCHER_REQUIRED_RELATIVES.every((relativePath) => existsSync(join(root, relativePath)));
|
|
492
|
-
}
|
|
493
|
-
function resolveWebpressoMcpEntry(probe = {}) {
|
|
494
|
-
const checked = [];
|
|
495
|
-
if (probe.candidates === undefined) {
|
|
496
|
-
const stableEntry = probe.stableEntry !== undefined
|
|
497
|
-
? probe.stableEntry()
|
|
498
|
-
: resolvePinnedMcpExecutable("wp", process.env);
|
|
499
|
-
if (stableEntry)
|
|
500
|
-
return { entryPath: stableEntry, checked: [stableEntry] };
|
|
501
|
-
}
|
|
502
|
-
const candidateGroups = probe.candidates !== undefined ? [probe.candidates] : [defaultFixedCandidates()];
|
|
503
|
-
for (const candidates of candidateGroups) {
|
|
504
|
-
for (const root of candidates) {
|
|
505
|
-
if (!root)
|
|
506
|
-
continue;
|
|
507
|
-
checked.push(root);
|
|
508
|
-
const wpBin = join(root, WP_BIN_RELATIVE);
|
|
509
|
-
if (isUsableWebpressoMcpRoot(root))
|
|
510
|
-
return { entryPath: wpBin, checked };
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (probe.candidates === undefined) {
|
|
514
|
-
for (const root of defaultPackageManagerCandidates(probe)) {
|
|
515
|
-
if (!root)
|
|
516
|
-
continue;
|
|
517
|
-
checked.push(root);
|
|
518
|
-
const wpBin = join(root, WP_BIN_RELATIVE);
|
|
519
|
-
if (isUsableWebpressoMcpRoot(root))
|
|
520
|
-
return { entryPath: wpBin, checked };
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
return { entryPath: null, checked };
|
|
524
|
-
}
|
|
525
|
-
function defaultFixedCandidates() {
|
|
526
|
-
const home = process.env.HOME || homedir();
|
|
527
|
-
const packageRoot = currentAgentKitPackageRoot();
|
|
528
|
-
const claudePlugin = join(home, ".claude", "plugins", "cache", "webpresso", "agent-kit");
|
|
529
|
-
const bunGlobal = join(home, ".bun", "install", "global", "node_modules", "@webpresso", "agent-kit");
|
|
530
|
-
return [packageRoot ?? "", claudePlugin, bunGlobal];
|
|
531
|
-
}
|
|
532
|
-
function defaultPackageManagerCandidates(probe) {
|
|
533
|
-
const pnpmRoot = (probe.pnpmGlobalRoot ?? probePnpmGlobalRoot)();
|
|
534
|
-
const npmRoot = (probe.npmGlobalRoot ?? probeNpmGlobalRoot)();
|
|
535
|
-
return [
|
|
536
|
-
pnpmRoot ? join(pnpmRoot, "@webpresso", "agent-kit") : "",
|
|
537
|
-
npmRoot ? join(npmRoot, "@webpresso", "agent-kit") : "",
|
|
538
|
-
];
|
|
539
|
-
}
|
|
540
|
-
function currentAgentKitPackageRoot() {
|
|
541
|
-
let current = dirname(fileURLToPath(import.meta.url));
|
|
542
|
-
for (let depth = 0; depth < 12; depth += 1) {
|
|
543
|
-
const packagePath = join(current, "package.json");
|
|
544
|
-
if (existsSync(packagePath)) {
|
|
545
|
-
try {
|
|
546
|
-
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
547
|
-
if (pkg.name === "@webpresso/agent-kit")
|
|
548
|
-
return current;
|
|
549
|
-
}
|
|
550
|
-
catch {
|
|
551
|
-
return null;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
const parent = dirname(current);
|
|
555
|
-
if (parent === current)
|
|
556
|
-
break;
|
|
557
|
-
current = parent;
|
|
558
|
-
}
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
function probePnpmGlobalRoot() {
|
|
562
|
-
return runQuiet("pnpm", ["root", "-g"]);
|
|
563
|
-
}
|
|
564
|
-
function probeNpmGlobalRoot() {
|
|
565
|
-
return runQuiet("npm", ["root", "-g"]);
|
|
566
|
-
}
|
|
567
|
-
function runQuiet(cmd, args) {
|
|
568
|
-
try {
|
|
569
|
-
const output = execFileSync(cmd, [...args], {
|
|
570
|
-
encoding: "utf8",
|
|
571
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
572
|
-
});
|
|
573
|
-
const trimmed = output.trim();
|
|
574
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
575
|
-
}
|
|
576
|
-
catch {
|
|
577
|
-
return null;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
export function agentKitMcpLaunchCommand(entryPath) {
|
|
581
|
-
return { command: entryPath, args: ["mcp"] };
|
|
582
|
-
}
|
|
583
663
|
export function agentKitMcpBlock(entryPath) {
|
|
584
664
|
const launch = agentKitMcpLaunchCommand(entryPath);
|
|
585
665
|
return commandMcpCodexBlock({
|
|
586
666
|
id: WEBPRESSO_MCP_SERVER_NAME,
|
|
587
667
|
command: launch.command,
|
|
588
668
|
args: launch.args,
|
|
669
|
+
codexEnv: WEBPRESSO_MCP_SPEC.env,
|
|
589
670
|
});
|
|
590
671
|
}
|
|
591
672
|
export function upsertWebpressoMcpServer(raw, entryPath) {
|
|
@@ -602,7 +683,12 @@ export function ensureCodexWebpressoMcp(input) {
|
|
|
602
683
|
const checked = resolution?.checked ?? [];
|
|
603
684
|
return { kind: "codex-webpresso-mcp-not-installed", path: configPath, checked };
|
|
604
685
|
}
|
|
605
|
-
const
|
|
686
|
+
const existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
687
|
+
if (hasAmbiguousMcpServerDottedDefinition(existing, WEBPRESSO_MCP_SERVER_NAME) ||
|
|
688
|
+
hasManagedMcpServerTableConflict(existing, WEBPRESSO_MCP_SERVER_NAME)) {
|
|
689
|
+
return { kind: "codex-webpresso-mcp-ambiguous", path: configPath, entryPath };
|
|
690
|
+
}
|
|
691
|
+
const result = updateCodexConfig(configPath, (raw) => upsertWebpressoMcpServer(raw, entryPath));
|
|
606
692
|
if (result === "unchanged") {
|
|
607
693
|
return { kind: "codex-webpresso-mcp-unchanged", path: configPath, entryPath };
|
|
608
694
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-only seams following the `claimInstallLock` options precedent. `isAlive`
|
|
3
|
+
* and `now` make liveness/age deterministic; `onBeforeReclaimDelete` fires while
|
|
4
|
+
* the reaper is held, just before a stale lock is removed, so a test can prove
|
|
5
|
+
* reclaim is serialized. Never supplied in production.
|
|
6
|
+
*/
|
|
7
|
+
export interface ScaffolderLockSeams {
|
|
8
|
+
readonly isAlive?: (pid: number) => boolean;
|
|
9
|
+
readonly now?: () => number;
|
|
10
|
+
readonly onBeforeReclaimDelete?: () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Serialize a complete read/modify/write transaction for a host config file.
|
|
14
|
+
* These are local single-machine home-config locks (`~/.codex`, `~/.grok`), so
|
|
15
|
+
* owner-pid liveness is meaningful; this is not a shared-filesystem lock.
|
|
16
|
+
*/
|
|
17
|
+
export declare function withScaffolderFileLock<T>(path: string, action: () => T, seams?: ScaffolderLockSeams): T;
|
|
18
|
+
/**
|
|
19
|
+
* Serialize a text-file read/modify/write and install the replacement strictly
|
|
20
|
+
* atomically without weakening an existing file's permissions.
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateScaffolderTextFile(path: string, transform: (existing: string) => string): "written" | "unchanged";
|