@webpresso/agent-kit 3.3.3 → 3.3.4
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/THIRD-PARTY-NOTICES.md +12 -10
- package/catalog/agent/rules/changeset-release.md +15 -4
- package/catalog/agent/rules/managed-tool-binaries.md +67 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +99 -1
- package/catalog/agent/rules/pre-implementation.md +36 -20
- package/catalog/agent/rules/rtk-routing.md +22 -16
- package/catalog/agent/skills/autopilot/SKILL.md +4 -3
- package/catalog/agent/skills/ultragoal/SKILL.md +11 -9
- package/dist/esm/audit/hook-surface.js +5 -1
- package/dist/esm/audit/repo-guardrails.d.ts +8 -0
- package/dist/esm/audit/repo-guardrails.js +71 -1
- package/dist/esm/blueprint/core/parser.js +38 -12
- package/dist/esm/blueprint/execution/artifacts.js +8 -4
- package/dist/esm/blueprint/execution/frontmatter-keys.d.ts +17 -0
- package/dist/esm/blueprint/execution/frontmatter-keys.js +24 -0
- package/dist/esm/blueprint/execution/metadata.js +8 -4
- package/dist/esm/blueprint/lifecycle/audit.d.ts +21 -0
- package/dist/esm/blueprint/lifecycle/audit.js +89 -3
- package/dist/esm/blueprint/lifecycle/review-provenance.js +63 -10
- package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +22 -0
- package/dist/esm/blueprint/lifecycle/rollout-anchor.js +37 -1
- package/dist/esm/blueprint/markdown/blocked-line.d.ts +49 -0
- package/dist/esm/blueprint/markdown/blocked-line.js +63 -0
- package/dist/esm/blueprint/markdown/helpers.js +10 -4
- package/dist/esm/blueprint/tracked-document/parser.js +3 -3
- package/dist/esm/blueprint/trust/gate-row.d.ts +55 -0
- package/dist/esm/blueprint/trust/gate-row.js +113 -0
- package/dist/esm/blueprint/trust/promotion.d.ts +17 -0
- package/dist/esm/blueprint/trust/promotion.js +19 -19
- package/dist/esm/build/atomic-file-copy.d.ts +32 -0
- package/dist/esm/build/atomic-file-copy.js +44 -0
- package/dist/esm/build/vendor-oxlint-plugins.d.ts +8 -0
- package/dist/esm/build/vendor-oxlint-plugins.js +53 -0
- package/dist/esm/cli/commands/blueprint/mutations.d.ts +15 -0
- package/dist/esm/cli/commands/blueprint/mutations.js +8 -2
- package/dist/esm/cli/commands/compile.d.ts +13 -0
- package/dist/esm/cli/commands/compile.js +182 -62
- package/dist/esm/cli/commands/format.js +17 -1
- package/dist/esm/cli/commands/gain/index.js +10 -3
- package/dist/esm/cli/commands/init/gitignore-patcher.js +6 -0
- package/dist/esm/cli/commands/init/index.js +29 -48
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +48 -13
- package/dist/esm/cli/commands/init/mcp-spec.js +86 -30
- package/dist/esm/cli/commands/init/merge.js +30 -10
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +56 -31
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +180 -43
- package/dist/esm/cli/commands/init/scaffolders/rtk/index.d.ts +17 -5
- package/dist/esm/cli/commands/init/scaffolders/rtk/index.js +56 -75
- package/dist/esm/cli/commands/init/scaffolders/runtime-check/index.js +7 -6
- package/dist/esm/cli/commands/init/untracked-collision.d.ts +12 -1
- package/dist/esm/cli/commands/init/untracked-collision.js +23 -1
- package/dist/esm/cli/commands/pr-help.js +1 -1
- package/dist/esm/cli/commands/pr.js +18 -4
- package/dist/esm/cli/commands/review.js +60 -6
- package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +24 -2
- package/dist/esm/cli/commands/worktree/router-dispatch.js +80 -48
- package/dist/esm/cli/commands/worktree/router.js +5 -2
- package/dist/esm/cli/direct-provider-launch.js +12 -4
- package/dist/esm/compiler/flatten.d.ts +10 -1
- package/dist/esm/compiler/flatten.js +14 -4
- package/dist/esm/compose/admin-blocks-registry-integrity.d.ts +22 -0
- package/dist/esm/compose/admin-blocks-registry-integrity.js +90 -0
- package/dist/esm/compose/compose.d.ts +8 -0
- package/dist/esm/compose/compose.js +115 -8
- package/dist/esm/compose/ops-report-schema.js +17 -3
- package/dist/esm/compose/registry-resolve.d.ts +17 -0
- package/dist/esm/compose/registry-resolve.js +78 -11
- package/dist/esm/config/oxlint/graphql-conventions.js +2 -5
- package/dist/esm/config/oxlint/import-hygiene.js +21 -8
- package/dist/esm/config/oxlint/oxlint-config.fixture.d.ts +1 -1
- package/dist/esm/config/oxlint/oxlint-config.fixture.js +2 -3
- package/dist/esm/config/oxlint/oxlintrc.d.ts +5 -7
- package/dist/esm/config/oxlint/oxlintrc.js +18 -21
- package/dist/esm/config/oxlint/path-roles.js +53 -0
- package/dist/esm/config/oxlint/query-patterns.js +2 -5
- package/dist/esm/daemon/domains/blueprint-exec-ledger.d.ts +86 -0
- package/dist/esm/daemon/domains/blueprint-exec-ledger.js +134 -0
- package/dist/esm/daemon/domains/blueprint-exec.d.ts +106 -0
- package/dist/esm/daemon/domains/blueprint-exec.js +161 -0
- package/dist/esm/daemon/domains/launch.d.ts +25 -0
- package/dist/esm/daemon/domains/launch.js +30 -1
- package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +12 -1
- package/dist/esm/daemon/handlers/blueprints-handlers.js +148 -6
- package/dist/esm/daemon/handlers/product.d.ts +10 -0
- package/dist/esm/daemon/handlers/product.js +10 -1
- package/dist/esm/daemon/methods.d.ts +21 -1
- package/dist/esm/daemon/methods.js +20 -0
- package/dist/esm/daemon/protocol/contract.d.ts +58 -0
- package/dist/esm/daemon/protocol/contract.js +38 -0
- package/dist/esm/daemon/server.js +7 -0
- package/dist/esm/docs-linter/blueprint-plan.js +2 -2
- package/dist/esm/errors/wp-error.js +21 -2
- package/dist/esm/hooks/doctor.d.ts +11 -0
- package/dist/esm/hooks/doctor.js +114 -45
- package/dist/esm/hooks/pretool-guard/dev-routing.js +1 -1
- package/dist/esm/hooks/pretool-guard/rtk-rewrite.d.ts +24 -0
- package/dist/esm/hooks/pretool-guard/rtk-rewrite.js +50 -0
- package/dist/esm/hooks/pretool-guard/runner.js +6 -0
- package/dist/esm/hooks/status/index.js +1 -1
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +39 -11
- package/dist/esm/mcp/blueprint/handlers/review-log.d.ts +14 -7
- package/dist/esm/mcp/blueprint/handlers/review-log.js +46 -22
- package/dist/esm/mcp/blueprint/registration.js +1 -1
- package/dist/esm/mcp/tools/_shared/redact.d.ts +22 -0
- package/dist/esm/mcp/tools/_shared/redact.js +114 -8
- package/dist/esm/mcp/tools/gain.js +28 -2
- package/dist/esm/mcp/tools/worktree.js +65 -3
- package/dist/esm/mcp/tools/wp-ui-compose.js +38 -4
- package/dist/esm/mcp/tools/wp-ui-preview.js +14 -7
- package/dist/esm/review/lifecycle-writers.d.ts +76 -0
- package/dist/esm/review/lifecycle-writers.js +330 -0
- package/dist/esm/review/subject.js +66 -32
- package/dist/esm/status/snapshot.d.ts +5 -0
- package/dist/esm/status/snapshot.js +27 -2
- package/dist/esm/test/shard-durations.json +0 -1
- package/dist/esm/test-helpers/global-setup.js +38 -3
- package/dist/esm/tool-runtime/managed-rtk.d.ts +44 -0
- package/dist/esm/tool-runtime/managed-rtk.js +275 -0
- package/dist/esm/tool-runtime/resolve-runner.js +18 -194
- package/dist/esm/utils/package-root.d.ts +32 -0
- package/dist/esm/utils/package-root.js +82 -0
- package/dist/esm/worktrees/git-metadata.d.ts +41 -0
- package/dist/esm/worktrees/git-metadata.js +48 -0
- package/package.json +16 -21
- package/dist/esm/config/oxlint/code-safety.d.ts +0 -18
- package/dist/esm/config/oxlint/foundation-purity.d.ts +0 -21
- package/dist/esm/config/oxlint/graphql-conventions.d.ts +0 -23
- package/dist/esm/config/oxlint/import-hygiene.d.ts +0 -34
- package/dist/esm/config/oxlint/index.d.ts +0 -22
- package/dist/esm/config/oxlint/index.js +0 -28
- package/dist/esm/config/oxlint/monorepo-paths.d.ts +0 -22
- package/dist/esm/config/oxlint/query-patterns.d.ts +0 -24
- package/dist/esm/config/oxlint/testing-quality.d.ts +0 -35
- package/dist/esm/config/oxlint/tier-boundaries.d.ts +0 -35
- package/dist/esm/output-transforms/rulesync.d.ts +0 -2
- package/dist/esm/output-transforms/rulesync.js +0 -79
|
@@ -1,35 +1,125 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { existsSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
4
|
import { dirname, join, resolve } from "node:path";
|
|
6
5
|
import { createRequire } from "node:module";
|
|
7
6
|
import { z } from "zod";
|
|
8
7
|
import { flattenAgentDir, writeFlattenedAssets } from "#compiler/flatten";
|
|
9
|
-
|
|
8
|
+
import { findPackageAsset } from "#utils/package-assets.js";
|
|
9
|
+
import { readPackageManifest, resolvePackageRoot, resolvePackageVersion, } from "#shared-utils/package-root.js";
|
|
10
10
|
const SUPPORTED_TARGETS = ["claude", "codex", "opencode"];
|
|
11
11
|
const DEFAULT_TARGETS = SUPPORTED_TARGETS.join(",");
|
|
12
12
|
const COMPILE_MANIFEST_VERSION = 1;
|
|
13
|
+
/**
|
|
14
|
+
* wp's target names are the stable CLI contract; rulesync's own ids differ for
|
|
15
|
+
* two of the three. rulesync does not reject an unknown target — it logs a skip
|
|
16
|
+
* and exits 0 — so passing wp's names straight through generated nothing for
|
|
17
|
+
* `claude` and `codex` while still reporting success.
|
|
18
|
+
*/
|
|
19
|
+
const RULESYNC_TARGET_IDS = {
|
|
20
|
+
claude: "claudecode",
|
|
21
|
+
codex: "codexcli",
|
|
22
|
+
opencode: "opencode",
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* rulesync defaults `--features` to `rules`, which agent-kit never emits — so
|
|
26
|
+
* omitting the flag guaranteed an empty generate. This is the set agent-kit
|
|
27
|
+
* actually flattens.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately not `*`: that also enables `rules`, whose output writes
|
|
30
|
+
* `AGENTS.md`/`CLAUDE.md` at the repo root and collides with the mergeAgentsMd
|
|
31
|
+
* step below, plus `ignore`/`mcp`/`hooks`/`permissions`, whose loaders print
|
|
32
|
+
* ENOENT lines straight to the user's terminal through the inherited stdio.
|
|
33
|
+
*/
|
|
34
|
+
const RULESYNC_FEATURES = "skills,commands,subagents";
|
|
35
|
+
const ASSET_KINDS = ["skills", "commands", "agents"];
|
|
36
|
+
/**
|
|
37
|
+
* Where rulesync writes each asset kind, per wp target.
|
|
38
|
+
*
|
|
39
|
+
* A kind omitted from a target's entry is one rulesync does not emit in project
|
|
40
|
+
* scope — notably codexcli commands, which it supports only under `--global`
|
|
41
|
+
* and otherwise skips with a warning. Omitting it keeps the check below honest
|
|
42
|
+
* rather than demanding a file rulesync was never going to write.
|
|
43
|
+
*/
|
|
44
|
+
const RULESYNC_OUTPUT_PATHS = {
|
|
45
|
+
claude: {
|
|
46
|
+
skills: (name) => join(".claude", "skills", name, "SKILL.md"),
|
|
47
|
+
commands: (name) => join(".claude", "commands", `${name}.md`),
|
|
48
|
+
agents: (name) => join(".claude", "agents", `${name}.md`),
|
|
49
|
+
},
|
|
50
|
+
codex: {
|
|
51
|
+
skills: (name) => join(".agents", "skills", name, "SKILL.md"),
|
|
52
|
+
// Codex subagents are TOML, not markdown — every other target emits .md.
|
|
53
|
+
agents: (name) => join(".codex", "agents", `${name}.toml`),
|
|
54
|
+
},
|
|
55
|
+
opencode: {
|
|
56
|
+
skills: (name) => join(".opencode", "skills", name, "SKILL.md"),
|
|
57
|
+
commands: (name) => join(".opencode", "commands", `${name}.md`),
|
|
58
|
+
agents: (name) => join(".opencode", "agents", `${name}.md`),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
/** Every output path a target is expected to produce for the given assets. */
|
|
62
|
+
function expectedOutputsForTarget(target, assets) {
|
|
63
|
+
const paths = RULESYNC_OUTPUT_PATHS[target];
|
|
64
|
+
const expected = [];
|
|
65
|
+
for (const kind of ASSET_KINDS) {
|
|
66
|
+
const toPath = paths[kind];
|
|
67
|
+
if (!toPath)
|
|
68
|
+
continue;
|
|
69
|
+
for (const name of Object.keys(assets[kind]))
|
|
70
|
+
expected.push(toPath(name));
|
|
71
|
+
}
|
|
72
|
+
return expected;
|
|
73
|
+
}
|
|
74
|
+
function expectedOutputs(targets, assets) {
|
|
75
|
+
return targets.flatMap((target) => expectedOutputsForTarget(target, assets));
|
|
76
|
+
}
|
|
13
77
|
// Resolve rulesync bin — checks consumer's node_modules first,
|
|
14
78
|
// then falls back to webpresso's own bundled rulesync.
|
|
79
|
+
// rulesync's `exports` map declares only ".", so its package.json is not
|
|
80
|
+
// resolvable by subpath — see #shared-utils/package-root for the full trap.
|
|
15
81
|
const _require = createRequire(import.meta.url);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Resolve rulesync relative to agent-kit's installed location rather than to
|
|
84
|
+
* this module's URL.
|
|
85
|
+
*
|
|
86
|
+
* In a bundled-Bun single-file binary `import.meta.url` is a `/$bunfs/root/...`
|
|
87
|
+
* virtual path, so a require anchored on it resolves nothing — and that is
|
|
88
|
+
* exactly the globally-installed case where the consumer has no local rulesync
|
|
89
|
+
* and this fallback is the only copy available.
|
|
90
|
+
*/
|
|
91
|
+
function agentKitAnchoredRequire() {
|
|
92
|
+
const manifestPath = findPackageAsset("package.json");
|
|
93
|
+
if (manifestPath === null)
|
|
94
|
+
return _require;
|
|
95
|
+
return createRequire(join(dirname(manifestPath), "noop.cjs"));
|
|
96
|
+
}
|
|
97
|
+
export function resolveRulesyncBinFromAgentKit(resolver = agentKitAnchoredRequire()) {
|
|
98
|
+
const root = resolvePackageRoot("rulesync", resolver);
|
|
99
|
+
if (!root)
|
|
31
100
|
return null;
|
|
32
|
-
|
|
101
|
+
const binField = readPackageManifest(root)?.bin;
|
|
102
|
+
const rel = typeof binField === "string"
|
|
103
|
+
? binField
|
|
104
|
+
: typeof binField === "object" && binField !== null && "rulesync" in binField
|
|
105
|
+
? String(binField["rulesync"])
|
|
106
|
+
: null;
|
|
107
|
+
if (!rel)
|
|
108
|
+
return null;
|
|
109
|
+
return join(root, rel);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The rulesync version agent-kit itself resolves — the only honest baseline to
|
|
113
|
+
* compare a consumer's install against.
|
|
114
|
+
*
|
|
115
|
+
* This used to be a hand-maintained `PINNED_RULESYNC_VERSION` literal, which
|
|
116
|
+
* drifted five majors behind the declared dependency (9.4.0 vs 14.0.1). The
|
|
117
|
+
* mismatch warning then fired on every single run, including inside agent-kit
|
|
118
|
+
* itself, which trains readers to ignore the one warning meant to catch a real
|
|
119
|
+
* mismatch. Deriving it from the resolved package makes that drift impossible.
|
|
120
|
+
*/
|
|
121
|
+
export function resolveBundledRulesyncVersion(resolver = agentKitAnchoredRequire()) {
|
|
122
|
+
return resolvePackageVersion("rulesync", resolver);
|
|
33
123
|
}
|
|
34
124
|
const CompileManifestSchema = z.object({
|
|
35
125
|
version: z.number(),
|
|
@@ -56,25 +146,6 @@ function readRulesyncVersion(cwd) {
|
|
|
56
146
|
return null;
|
|
57
147
|
}
|
|
58
148
|
}
|
|
59
|
-
function contentHash(assets) {
|
|
60
|
-
const entries = [
|
|
61
|
-
...Object.entries(assets.skills).map(([k, v]) => `s:${k}:${v}`),
|
|
62
|
-
...Object.entries(assets.commands).map(([k, v]) => `c:${k}:${v}`),
|
|
63
|
-
...Object.entries(assets.agents).map(([k, v]) => `a:${k}:${v}`),
|
|
64
|
-
];
|
|
65
|
-
entries.sort();
|
|
66
|
-
return entries.join("\0");
|
|
67
|
-
}
|
|
68
|
-
function readHashFile(p) {
|
|
69
|
-
if (!existsSync(p))
|
|
70
|
-
return null;
|
|
71
|
-
try {
|
|
72
|
-
return readFileSync(p, "utf-8").trim();
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
149
|
/** SHA-256 hash of all .md files under agentDir, recursively (content only). */
|
|
79
150
|
export function hashAgentDir(agentDir) {
|
|
80
151
|
const h = createHash("sha256");
|
|
@@ -144,20 +215,26 @@ export async function runCompile(options) {
|
|
|
144
215
|
}
|
|
145
216
|
const agentDir = join(cwd, ".agent");
|
|
146
217
|
const lockPath = join(agentDir, ".compile.lock");
|
|
147
|
-
const hashPath = join(agentDir, ".compile.hash");
|
|
148
218
|
const manifestPath = join(agentDir, ".compile-manifest.json");
|
|
149
219
|
const rulesyncBin = resolveRulesyncBin(cwd);
|
|
220
|
+
const expectedVersion = resolveBundledRulesyncVersion();
|
|
150
221
|
if (!rulesyncBin || !existsSync(rulesyncBin)) {
|
|
222
|
+
const installHint = expectedVersion ? `rulesync@${expectedVersion}` : "rulesync";
|
|
151
223
|
return {
|
|
152
224
|
ok: false,
|
|
153
225
|
targets: targetList,
|
|
154
226
|
noOp: false,
|
|
155
|
-
message:
|
|
227
|
+
message: `rulesync is not installed — run \`vp add -w ${installHint}\``,
|
|
156
228
|
};
|
|
157
229
|
}
|
|
158
230
|
const installedVersion = readRulesyncVersion(cwd);
|
|
159
|
-
|
|
160
|
-
|
|
231
|
+
// Only compare against a version we actually resolved: with no baseline there
|
|
232
|
+
// is nothing to assert, and a fabricated one is what produced the old
|
|
233
|
+
// permanently-firing warning.
|
|
234
|
+
if (expectedVersion !== null &&
|
|
235
|
+
installedVersion !== null &&
|
|
236
|
+
installedVersion !== expectedVersion) {
|
|
237
|
+
process.stderr.write(`wp compile: warning — installed rulesync@${installedVersion} does not match the rulesync@${expectedVersion} agent-kit resolves\n`);
|
|
161
238
|
}
|
|
162
239
|
// Atomic lock via O_EXCL — fails if another compile is running
|
|
163
240
|
try {
|
|
@@ -171,31 +248,48 @@ export async function runCompile(options) {
|
|
|
171
248
|
message: `wp compile: lock file exists at ${lockPath} — another compile is running`,
|
|
172
249
|
};
|
|
173
250
|
}
|
|
251
|
+
// Staging dir lives in cwd (see the rename below), so an interrupted compile
|
|
252
|
+
// would strand a `.rulesync.tmp-*` directory inside the user's repo that no
|
|
253
|
+
// later run reaps. Tracked here so the signal path clears it too.
|
|
254
|
+
let stagingDir = null;
|
|
174
255
|
const cleanup = () => {
|
|
175
256
|
try {
|
|
176
257
|
if (existsSync(lockPath))
|
|
177
258
|
unlinkSync(lockPath);
|
|
259
|
+
if (stagingDir !== null)
|
|
260
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
178
261
|
}
|
|
179
262
|
catch {
|
|
180
263
|
/* best-effort */
|
|
181
264
|
}
|
|
182
265
|
};
|
|
183
|
-
|
|
184
|
-
process
|
|
266
|
+
// Held as named refs so `finally` can detach them: runCompile is called
|
|
267
|
+
// repeatedly within one process (the test suites do exactly this), and
|
|
268
|
+
// anonymous handlers would stack up a MaxListenersExceededWarning plus N
|
|
269
|
+
// SIGINT handlers each racing to call process.exit.
|
|
270
|
+
const onSigint = () => {
|
|
185
271
|
cleanup();
|
|
186
272
|
process.exit(130);
|
|
187
|
-
}
|
|
188
|
-
|
|
273
|
+
};
|
|
274
|
+
const onSigterm = () => {
|
|
189
275
|
cleanup();
|
|
190
276
|
process.exit(143);
|
|
191
|
-
}
|
|
277
|
+
};
|
|
278
|
+
process.on("exit", cleanup);
|
|
279
|
+
process.on("SIGINT", onSigint);
|
|
280
|
+
process.on("SIGTERM", onSigterm);
|
|
192
281
|
try {
|
|
193
282
|
const assets = flattenAgentDir(agentDir);
|
|
194
|
-
const hash = contentHash(assets);
|
|
195
283
|
const sourceHash = hashAgentDir(agentDir);
|
|
196
|
-
//
|
|
284
|
+
// An unchanged source hash only proves the *input* is the same; it says
|
|
285
|
+
// nothing about whether the generated surfaces still exist. Deleting
|
|
286
|
+
// .claude/skills/ would otherwise leave compile reporting "no changes"
|
|
287
|
+
// forever while the files it exists to produce stay missing — the very
|
|
288
|
+
// silent-zero-output failure this command was repaired to eliminate.
|
|
289
|
+
const expected = expectedOutputs(targetList, assets);
|
|
290
|
+
const outputsPresent = expected.every((rel) => existsSync(join(cwd, rel)));
|
|
197
291
|
const existingManifest = readCompileManifest(manifestPath);
|
|
198
|
-
if (existingManifest !== null && existingManifest.sourceHash === sourceHash) {
|
|
292
|
+
if (outputsPresent && existingManifest !== null && existingManifest.sourceHash === sourceHash) {
|
|
199
293
|
return {
|
|
200
294
|
ok: true,
|
|
201
295
|
targets: targetList,
|
|
@@ -203,30 +297,35 @@ export async function runCompile(options) {
|
|
|
203
297
|
message: "No changes (manifest matches)",
|
|
204
298
|
};
|
|
205
299
|
}
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const tmpOut = mkdtempSync(join(tmpdir(), "wp-compile-"));
|
|
300
|
+
// Step 1+2: Stage the flattened assets, then atomically rename to .rulesync/.
|
|
301
|
+
//
|
|
302
|
+
// The staging dir must live inside `cwd`, not in os.tmpdir(): renameSync
|
|
303
|
+
// cannot cross filesystems, and on any host where /tmp is its own mount
|
|
304
|
+
// (tmpfs on most systemd Linux distros, Docker --tmpfs, many CI runners)
|
|
305
|
+
// the swap below would throw EXDEV and take the whole command down. The
|
|
306
|
+
// test suites cannot catch that on their own, because their cwd is itself
|
|
307
|
+
// under tmpdir() and so always lands on the same filesystem.
|
|
308
|
+
const tmpOut = mkdtempSync(join(cwd, ".rulesync.tmp-"));
|
|
309
|
+
stagingDir = tmpOut;
|
|
217
310
|
try {
|
|
218
311
|
await writeFlattenedAssets(assets, tmpOut);
|
|
219
312
|
const rulesyncInputDir = join(cwd, ".rulesync");
|
|
220
313
|
if (existsSync(rulesyncInputDir))
|
|
221
314
|
rmSync(rulesyncInputDir, { recursive: true, force: true });
|
|
222
315
|
renameSync(tmpOut, rulesyncInputDir);
|
|
316
|
+
// Renamed away: nothing left at the staging path for cleanup to remove.
|
|
317
|
+
stagingDir = null;
|
|
223
318
|
}
|
|
224
319
|
catch (err) {
|
|
225
320
|
rmSync(tmpOut, { recursive: true, force: true });
|
|
321
|
+
stagingDir = null;
|
|
226
322
|
throw err;
|
|
227
323
|
}
|
|
228
324
|
// Step 3: Run rulesync generate
|
|
229
|
-
const
|
|
325
|
+
const rulesyncTargets = targetList
|
|
326
|
+
.map((target) => RULESYNC_TARGET_IDS[target])
|
|
327
|
+
.join(",");
|
|
328
|
+
const result = spawnSync(rulesyncBin, ["generate", "--targets", rulesyncTargets, "--features", RULESYNC_FEATURES], {
|
|
230
329
|
cwd,
|
|
231
330
|
stdio: "inherit",
|
|
232
331
|
});
|
|
@@ -247,6 +346,21 @@ export async function runCompile(options) {
|
|
|
247
346
|
message: `wp compile: rulesync exited with code ${exitCode}`,
|
|
248
347
|
};
|
|
249
348
|
}
|
|
349
|
+
// rulesync exits 0 when it generates nothing at all ("All files are up to
|
|
350
|
+
// date"), so the exit code above cannot distinguish a real generate from a
|
|
351
|
+
// silent no-op caused by a target it skipped or input it could not see.
|
|
352
|
+
// The files consumers need are the contract, so assert they exist.
|
|
353
|
+
const missing = expected.filter((rel) => !existsSync(join(cwd, rel)));
|
|
354
|
+
if (missing.length > 0) {
|
|
355
|
+
const shown = missing.slice(0, 5).join(", ");
|
|
356
|
+
const rest = missing.length > 5 ? ` (and ${missing.length - 5} more)` : "";
|
|
357
|
+
return {
|
|
358
|
+
ok: false,
|
|
359
|
+
targets: targetList,
|
|
360
|
+
noOp: false,
|
|
361
|
+
message: `wp compile: rulesync exited 0 but ${missing.length} expected output(s) were not generated: ${shown}${rest}`,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
250
364
|
// Step 4: Run mergeAgentsMd to produce AGENTS.md at repo root
|
|
251
365
|
// (Plugin manifests are hand-maintained SSOT under packages/*-plugin/;
|
|
252
366
|
// wp compile no longer emits them — golden tests + version stamping own
|
|
@@ -270,6 +384,10 @@ export async function runCompile(options) {
|
|
|
270
384
|
const outputHashes = {
|
|
271
385
|
"AGENTS.md": hashFile(join(cwd, "AGENTS.md")),
|
|
272
386
|
};
|
|
387
|
+
// Every generated surface, not just AGENTS.md — this is what gives
|
|
388
|
+
// `wp audit compile-drift` something real to compare against.
|
|
389
|
+
for (const rel of expected)
|
|
390
|
+
outputHashes[rel] = hashFile(join(cwd, rel));
|
|
273
391
|
const compileManifest = {
|
|
274
392
|
version: COMPILE_MANIFEST_VERSION,
|
|
275
393
|
timestamp: new Date().toISOString(),
|
|
@@ -277,7 +395,6 @@ export async function runCompile(options) {
|
|
|
277
395
|
outputHashes,
|
|
278
396
|
};
|
|
279
397
|
writeCompileManifest(manifestPath, compileManifest);
|
|
280
|
-
writeFileSync(hashPath, hash);
|
|
281
398
|
return {
|
|
282
399
|
ok: true,
|
|
283
400
|
targets: targetList,
|
|
@@ -287,6 +404,9 @@ export async function runCompile(options) {
|
|
|
287
404
|
}
|
|
288
405
|
finally {
|
|
289
406
|
cleanup();
|
|
407
|
+
process.removeListener("exit", cleanup);
|
|
408
|
+
process.removeListener("SIGINT", onSigint);
|
|
409
|
+
process.removeListener("SIGTERM", onSigterm);
|
|
290
410
|
}
|
|
291
411
|
}
|
|
292
412
|
function collectAgentsLayers(agentDir) {
|
|
@@ -178,11 +178,27 @@ function formatterTargetFromCwd(file, cwd) {
|
|
|
178
178
|
return file;
|
|
179
179
|
return relativeTarget;
|
|
180
180
|
}
|
|
181
|
+
// The blueprint root is not always the top-level `blueprints/` directory: a
|
|
182
|
+
// consumer repo can resolve to `webpresso/blueprints/` (the webpresso-legacy
|
|
183
|
+
// fallback layout — see #utils/blueprint-root.js) or a `.webpressorc.json`
|
|
184
|
+
// override. A prefix anchored to one specific root silently fails to exclude
|
|
185
|
+
// review-artifact markdown under any other layout, so `wp format` reformats
|
|
186
|
+
// it. That mutates the artifact's bytes between when `wp review gate`
|
|
187
|
+
// records its sha256 into review-events.jsonl and when the file is
|
|
188
|
+
// committed, producing a false "Review artifact digest mismatch" at
|
|
189
|
+
// `wp_blueprint_finalize` time (src/review/authority.ts correctly detects
|
|
190
|
+
// the drift and fails closed). Match on the directory name alone — not
|
|
191
|
+
// anchored to any specific root prefix — so this stays correct across every
|
|
192
|
+
// current and future blueprint root layout without tracking
|
|
193
|
+
// resolveBlueprintRoot's precedence rules in a second place. This also keeps
|
|
194
|
+
// parity with the whole-repo formatter's own ignore layer
|
|
195
|
+
// (vite.config.ts#fmt.ignorePatterns), which uses the same unanchored
|
|
196
|
+
// `**/review-artifacts/**` glob for the same reason.
|
|
181
197
|
function filterFormatableFiles(files, cwd) {
|
|
182
198
|
return files.filter((file) => {
|
|
183
199
|
const extension = path.extname(file).toLowerCase();
|
|
184
200
|
const normalized = file.replaceAll("\\", "/");
|
|
185
|
-
const isReviewArtifact = normalized.
|
|
201
|
+
const isReviewArtifact = normalized.includes("/review-artifacts/");
|
|
186
202
|
return OXFMT_EXTENSIONS.has(extension) && !isReviewArtifact && existsSync(path.join(cwd, file));
|
|
187
203
|
});
|
|
188
204
|
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { SessionMemoryStore } from "#session-memory/store.js";
|
|
3
3
|
import { defaultIndexDbPath } from "#mcp/tools/session-restore.js";
|
|
4
|
+
import { resolveManagedRtkExecutable } from "#tool-runtime/managed-rtk.js";
|
|
4
5
|
export function runGain(options = {}) {
|
|
5
6
|
const dbPath = options.indexDbPath ?? defaultIndexDbPath(options.cwd);
|
|
6
7
|
const webpressoStats = readWebpressoGainStats(dbPath);
|
|
7
8
|
printWebpressoGain(webpressoStats, dbPath, { sessions: options.sessions === true });
|
|
8
9
|
console.log("\n── RTK Gain Totals ──────────────────────────────────────────");
|
|
9
|
-
const
|
|
10
|
+
const rtkBin = resolveManagedRtkExecutable();
|
|
11
|
+
if (!rtkBin) {
|
|
12
|
+
console.log(" Managed RTK not available.");
|
|
13
|
+
console.log(" Enable: wp setup --with rtk (or set WP_RTK_BIN to a capable rtk binary)");
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
const rtk = spawnSync(rtkBin, ["gain", "--format", "json"], { encoding: "utf8" });
|
|
10
17
|
if (rtk.error) {
|
|
11
18
|
const err = rtk.error;
|
|
12
19
|
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
13
|
-
console.log(" RTK
|
|
14
|
-
console.log(" Enable: wp setup --with rtk
|
|
20
|
+
console.log(" Managed RTK binary missing at resolved path.");
|
|
21
|
+
console.log(" Enable: wp setup --with rtk (or set WP_RTK_BIN)");
|
|
15
22
|
return 0;
|
|
16
23
|
}
|
|
17
24
|
throw err;
|
|
@@ -76,6 +76,12 @@ export const GENERATED_PATHS_BLOCK = {
|
|
|
76
76
|
".agent/.blueprints.lock",
|
|
77
77
|
".agent/.blueprints.snapshot.sql",
|
|
78
78
|
".agent/.tail-hint-history.jsonl",
|
|
79
|
+
"# `wp compile` derives .rulesync/ from the canonical agent sources and replaces",
|
|
80
|
+
"# it wholesale on every run, so it is a build artifact rather than the",
|
|
81
|
+
"# hand-authored source tree rulesync's own docs describe. The .tmp- dirs are",
|
|
82
|
+
"# its staging area, normally renamed away but left behind by an interrupt.",
|
|
83
|
+
".rulesync/",
|
|
84
|
+
".rulesync.tmp-*",
|
|
79
85
|
"# Stryker writes these mutation-test artifacts beside consumer source trees.",
|
|
80
86
|
".stryker-tmp/",
|
|
81
87
|
"reports/mutation/",
|
|
@@ -54,7 +54,7 @@ import { ensureClaudeCodeUserPlugin } from "./scaffolders/claude-plugin/index.js
|
|
|
54
54
|
import { ensureCodexUserPlugin } from "./scaffolders/codex-plugin/index.js";
|
|
55
55
|
import { scaffoldClaudeRules } from "./scaffolders/claude-rules/index.js";
|
|
56
56
|
import { ensureCodexCli } from "./scaffolders/codex-cli/index.js";
|
|
57
|
-
import { ensureClaudePlaywrightMcp, ensureCodexProjectMcpServers,
|
|
57
|
+
import { ensureClaudePlaywrightMcp, ensureCodexProjectMcpServers, pruneLegacyCodexWebpressoMcp, } from "./scaffolders/codex-mcp/index.js";
|
|
58
58
|
import { scaffoldExampleSkill } from "./scaffolders/example-skill/index.js";
|
|
59
59
|
import { scaffoldLoreCommits } from "./scaffolders/lore-commits/index.js";
|
|
60
60
|
import { ensureOpenCodeWebpressoPlugin } from "./scaffolders/opencode-plugin/index.js";
|
|
@@ -381,24 +381,7 @@ async function runUserOnlySetup(input) {
|
|
|
381
381
|
console.log(" playwright mcp: - skipped (the preset requires a project-owned .mcp.json; run setup inside the project repo)");
|
|
382
382
|
}
|
|
383
383
|
if (selectedHosts.includes("codex")) {
|
|
384
|
-
|
|
385
|
-
switch (webpressoMcpResult.kind) {
|
|
386
|
-
case "codex-webpresso-mcp-written":
|
|
387
|
-
console.log(` codex webpresso mcp: ✓ ${webpressoMcpResult.path} → ${webpressoMcpResult.entryPath}`);
|
|
388
|
-
break;
|
|
389
|
-
case "codex-webpresso-mcp-unchanged":
|
|
390
|
-
console.log(` codex webpresso mcp: already configured at ${webpressoMcpResult.path}`);
|
|
391
|
-
break;
|
|
392
|
-
case "codex-webpresso-mcp-ambiguous":
|
|
393
|
-
console.warn(` codex webpresso mcp: ⚠ ambiguous MCP config at ${webpressoMcpResult.path}; left unchanged`);
|
|
394
|
-
break;
|
|
395
|
-
case "codex-webpresso-mcp-skipped-dry-run":
|
|
396
|
-
console.log(" codex webpresso mcp: skipped (--dry-run)");
|
|
397
|
-
break;
|
|
398
|
-
case "codex-webpresso-mcp-not-installed":
|
|
399
|
-
console.log(` codex webpresso mcp: ⚠ no install root found (checked ${webpressoMcpResult.checked.length} paths). Install @webpresso/agent-kit globally (\`bun add -g @webpresso/agent-kit\`) or via the Claude plugin to wire up codex MCP.`);
|
|
400
|
-
break;
|
|
401
|
-
}
|
|
384
|
+
reportLegacyCodexWebpressoMcpPrune(pruneLegacyCodexWebpressoMcp({ options: userScopeOptions }));
|
|
402
385
|
console.log(" codex project mcp: - skipped (no project .mcp.json outside a repo)");
|
|
403
386
|
}
|
|
404
387
|
if (isCiEnvironment) {
|
|
@@ -696,6 +679,25 @@ function printCodexPluginResult(result) {
|
|
|
696
679
|
break;
|
|
697
680
|
}
|
|
698
681
|
}
|
|
682
|
+
function reportLegacyCodexWebpressoMcpPrune(result) {
|
|
683
|
+
switch (result.kind) {
|
|
684
|
+
case "codex-legacy-webpresso-mcp-removed":
|
|
685
|
+
console.log(` codex webpresso mcp: ✓ retired legacy [mcp_servers.webpresso] in ${result.path} (the bundled Codex plugin is the single delivery channel)`);
|
|
686
|
+
break;
|
|
687
|
+
case "codex-legacy-webpresso-mcp-absent":
|
|
688
|
+
console.log(" codex webpresso mcp: ✓ delivered by the bundled Codex plugin");
|
|
689
|
+
break;
|
|
690
|
+
case "codex-legacy-webpresso-mcp-preserved":
|
|
691
|
+
console.warn(` codex webpresso mcp: ⚠ ${result.path} declares a user-authored webpresso server (${result.command ?? "no command"}); left unchanged — remove it manually to use the bundled Codex plugin`);
|
|
692
|
+
break;
|
|
693
|
+
case "codex-legacy-webpresso-mcp-ambiguous":
|
|
694
|
+
console.warn(` codex webpresso mcp: ⚠ ambiguous MCP config at ${result.path}; left unchanged`);
|
|
695
|
+
break;
|
|
696
|
+
case "codex-legacy-webpresso-mcp-skipped-dry-run":
|
|
697
|
+
console.log(" codex webpresso mcp: skipped (--dry-run)");
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
699
701
|
function reconcileCodexProjectMcpServers(repoRoot, options) {
|
|
700
702
|
const result = ensureCodexProjectMcpServers({ repoRoot, options });
|
|
701
703
|
switch (result.kind) {
|
|
@@ -1625,29 +1627,14 @@ export async function runInit(flags, deps = {}) {
|
|
|
1625
1627
|
? { kind: "apply" }
|
|
1626
1628
|
: { kind: "skip", reason: skipGlobal ? "--skip-global" : "user-scope writes declined" });
|
|
1627
1629
|
}
|
|
1628
|
-
//
|
|
1629
|
-
//
|
|
1630
|
-
//
|
|
1631
|
-
// plugin / bun global / pnpm global / npm global) and write that.
|
|
1630
|
+
// Codex receives webpresso over ONE channel: the bundled Codex plugin's
|
|
1631
|
+
// `.mcp.json`. Setup retires the user-global `[mcp_servers.webpresso]`
|
|
1632
|
+
// block earlier versions wrote here rather than refreshing it.
|
|
1632
1633
|
if (selectedHosts.includes("codex")) {
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
recordUserScope("codex-config");
|
|
1638
|
-
break;
|
|
1639
|
-
case "codex-webpresso-mcp-unchanged":
|
|
1640
|
-
console.log(` codex webpresso mcp: already configured at ${webpressoMcpResult.path}`);
|
|
1641
|
-
break;
|
|
1642
|
-
case "codex-webpresso-mcp-ambiguous":
|
|
1643
|
-
console.warn(` codex webpresso mcp: ⚠ ambiguous MCP config at ${webpressoMcpResult.path}; left unchanged`);
|
|
1644
|
-
break;
|
|
1645
|
-
case "codex-webpresso-mcp-skipped-dry-run":
|
|
1646
|
-
console.log(" codex webpresso mcp: skipped (--dry-run)");
|
|
1647
|
-
break;
|
|
1648
|
-
case "codex-webpresso-mcp-not-installed":
|
|
1649
|
-
console.log(` codex webpresso mcp: ⚠ no install root found (checked ${webpressoMcpResult.checked.length} paths). Install @webpresso/agent-kit globally (\`bun add -g @webpresso/agent-kit\`) or via the Claude plugin to wire up codex MCP.`);
|
|
1650
|
-
break;
|
|
1634
|
+
const pruneResult = pruneLegacyCodexWebpressoMcp({ options: userScopeOptions });
|
|
1635
|
+
reportLegacyCodexWebpressoMcpPrune(pruneResult);
|
|
1636
|
+
if (pruneResult.kind === "codex-legacy-webpresso-mcp-removed") {
|
|
1637
|
+
recordUserScope("codex-config");
|
|
1651
1638
|
}
|
|
1652
1639
|
reconcileCodexProjectMcpServers(consumer.repoRoot, userScopeOptions);
|
|
1653
1640
|
}
|
|
@@ -1829,7 +1816,7 @@ export async function runInit(flags, deps = {}) {
|
|
|
1829
1816
|
const rtkResult = ensureRtk({ repoRoot: consumer.repoRoot, options: userScopeOptions });
|
|
1830
1817
|
switch (rtkResult.kind) {
|
|
1831
1818
|
case "rtk-ok":
|
|
1832
|
-
console.log(rtkResult.installed ? " rtk: ✓
|
|
1819
|
+
console.log(rtkResult.installed ? " rtk: ✓ managed binary installed" : " rtk: ✓");
|
|
1833
1820
|
recordUserScope("rtk-install");
|
|
1834
1821
|
break;
|
|
1835
1822
|
case "rtk-skipped-dry-run":
|
|
@@ -1839,10 +1826,6 @@ export async function runInit(flags, deps = {}) {
|
|
|
1839
1826
|
console.error(` rtk: ✗ ${rtkResult.hint}`);
|
|
1840
1827
|
rtkFailure = "not-found";
|
|
1841
1828
|
break;
|
|
1842
|
-
case "rtk-init-failed":
|
|
1843
|
-
console.error(` rtk: ✗ rtk init exited with ${rtkResult.exitCode}`);
|
|
1844
|
-
rtkFailure = "init-failed";
|
|
1845
|
-
break;
|
|
1846
1829
|
}
|
|
1847
1830
|
}
|
|
1848
1831
|
const all = [
|
|
@@ -2039,8 +2022,6 @@ export async function runInit(flags, deps = {}) {
|
|
|
2039
2022
|
console.log("\nwp init: setup phases finished.");
|
|
2040
2023
|
if (rtkFailure === "not-found")
|
|
2041
2024
|
return EXIT_SETUP_FAIL;
|
|
2042
|
-
if (rtkFailure === "init-failed")
|
|
2043
|
-
return EXIT_WRITE_FAIL;
|
|
2044
2025
|
if (isTelemetryEnabled(process.env)) {
|
|
2045
2026
|
const payload = {
|
|
2046
2027
|
event: "setup-complete",
|
|
@@ -30,7 +30,24 @@ export interface WebpressoInstallProbe {
|
|
|
30
30
|
stableEntry?: () => string | null;
|
|
31
31
|
/** Test seam — verify that a PATH entry is the Webpresso command. */
|
|
32
32
|
stableEntryIsWebpresso?: (entryPath: string) => boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Test seam — resolve the currently executing agent-kit package root.
|
|
35
|
+
*
|
|
36
|
+
* Without this seam the self-trust branch below is only reachable when the
|
|
37
|
+
* test file itself happens to live in a managed worktree, so the regression
|
|
38
|
+
* guard would silently skip in CI — where the checkout is a plain clone.
|
|
39
|
+
*/
|
|
40
|
+
sourceRoot?: () => string | null;
|
|
33
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* True when `entryPath` is the stable vite-plus multi-package `wp` shim that
|
|
44
|
+
* dispatches to `@webpresso/agent-kit` via `~/.vite-plus/bins/wp.json`.
|
|
45
|
+
*
|
|
46
|
+
* Unlike {@link isWebpressoWpEntry}, this does **not** require realpath to land
|
|
47
|
+
* inside a package `bin/wp` tree — vite-plus's `wp` is a symlink to the `vp`
|
|
48
|
+
* binary, so package-root ownership is proven via the bins metadata instead.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isVitePlusManagedWebpressoWp(entryPath: string): boolean;
|
|
34
51
|
/**
|
|
35
52
|
* Resolve the absolute path to webpresso's global `bin/wp` launcher on this
|
|
36
53
|
* machine. Probes the locations consumers use to install webpresso, in order
|
|
@@ -43,25 +60,43 @@ export interface WebpressoInstallProbe {
|
|
|
43
60
|
* 3. Claude plugin install — `~/.claude/plugins/cache/.../agent-kit/`
|
|
44
61
|
* 4. bun global — `~/.bun/install/global/node_modules/@webpresso/agent-kit/`
|
|
45
62
|
*
|
|
46
|
-
* Host MCP configs (Grok/
|
|
63
|
+
* Host MCP configs (Grok/OpenCode) must never be pinned to a versioned
|
|
47
64
|
* installId tree: the next `wp update` / `vp update -g` deletes that path and
|
|
48
|
-
* leaves every host with a dead launcher.
|
|
49
|
-
* candidates yield a durable `wp`.
|
|
65
|
+
* leaves every host with a dead launcher. `entryPath` is `null` when none of
|
|
66
|
+
* the candidates yield a durable `wp`.
|
|
50
67
|
*/
|
|
51
|
-
export declare function findWebpressoMcpEntry(probe?: WebpressoInstallProbe): string | null;
|
|
52
|
-
/**
|
|
53
|
-
* True when `entryPath` is the stable vite-plus multi-package `wp` shim that
|
|
54
|
-
* dispatches to `@webpresso/agent-kit` via `~/.vite-plus/bins/wp.json`.
|
|
55
|
-
*
|
|
56
|
-
* Unlike {@link isWebpressoWpEntry}, this does **not** require realpath to land
|
|
57
|
-
* inside a package `bin/wp` tree — vite-plus's `wp` is a symlink to the `vp`
|
|
58
|
-
* binary, so package-root ownership is proven via the bins metadata instead.
|
|
59
|
-
*/
|
|
60
|
-
export declare function isVitePlusManagedWebpressoWp(entryPath: string): boolean;
|
|
61
68
|
export declare function resolveWebpressoMcpEntry(probe?: WebpressoInstallProbe): {
|
|
62
69
|
entryPath: string | null;
|
|
63
70
|
checked: readonly string[];
|
|
64
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* Seams for classifying a persisted host-config `command` path as agent-kit's
|
|
74
|
+
* own. Kept separate from {@link WebpressoInstallProbe}: that probe answers
|
|
75
|
+
* "where should we WRITE a launcher", this one answers "did WE write this".
|
|
76
|
+
*/
|
|
77
|
+
export interface AgentKitOwnedCommandProbe {
|
|
78
|
+
/** Test seam — override `$HOME`. */
|
|
79
|
+
readonly home?: string;
|
|
80
|
+
/** Test seam — resolve the currently executing agent-kit package root. */
|
|
81
|
+
readonly sourceRoot?: () => string | null;
|
|
82
|
+
/** Test seam — filesystem existence check for the persisted command path. */
|
|
83
|
+
readonly exists?: (path: string) => boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Every root under which agent-kit itself installs (or checks out) a `bin/wp`.
|
|
87
|
+
* A `wp` launcher recorded inside one of these was written by agent-kit; a
|
|
88
|
+
* launcher anywhere else is an operator's deliberate choice.
|
|
89
|
+
*/
|
|
90
|
+
export declare function agentKitOwnedCommandRoots(probe?: AgentKitOwnedCommandProbe): readonly string[];
|
|
91
|
+
/**
|
|
92
|
+
* Ownership — not shape — decides whether setup may retire a persisted MCP
|
|
93
|
+
* entry. An entry is agent-kit's own when it launches `wp mcp` from an
|
|
94
|
+
* ABSOLUTE path AND either that path is gone (one we would have deleted) or
|
|
95
|
+
* it lives inside one
|
|
96
|
+
* of {@link agentKitOwnedCommandRoots}. A *live* `wp mcp` launcher outside
|
|
97
|
+
* those roots is an operator pointing Codex at a custom build: preserve it.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isAgentKitOwnedWpCommand(command: string, args: readonly string[], probe?: AgentKitOwnedCommandProbe): boolean;
|
|
65
100
|
export declare function isWebpressoWpEntry(entryPath: string): boolean;
|
|
66
101
|
/** Run a discovery probe with bounded output and SIGKILL escalation. */
|
|
67
102
|
export declare function runQuiet(cmd: string, args: readonly string[], timeoutMs?: number): string | null;
|