@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
|
@@ -5,11 +5,21 @@
|
|
|
5
5
|
* Domain implementations live in the sibling `*-handlers.ts` files; this
|
|
6
6
|
* module only aggregates them into the map `startDaemonServer` consumes.
|
|
7
7
|
*/
|
|
8
|
+
import type { BlueprintExecLedger } from "#daemon/domains/blueprint-exec-ledger.js";
|
|
9
|
+
import type { LaunchLedger } from "#daemon/domains/launch.js";
|
|
8
10
|
import type { MethodHandler } from "#daemon/rpc.js";
|
|
9
11
|
/**
|
|
10
12
|
* Build the default handler map. Callers may override individual methods via
|
|
11
13
|
* `startDaemonServer({ handlers })` — overrides win.
|
|
14
|
+
*
|
|
15
|
+
* `launchLedger` / `execLedger` are daemon-scoped (one per server, not one per
|
|
16
|
+
* connection): blueprint exec registers a job on the webview connection and
|
|
17
|
+
* binds the PTY session on the rust connection, so both peers must see the
|
|
18
|
+
* same ledger instances.
|
|
12
19
|
*/
|
|
13
20
|
export declare function createDefaultProductHandlers(options?: {
|
|
14
21
|
readonly repoRoot?: string;
|
|
22
|
+
readonly allowlistedRoots?: readonly string[];
|
|
23
|
+
readonly launchLedger?: LaunchLedger;
|
|
24
|
+
readonly execLedger?: BlueprintExecLedger;
|
|
15
25
|
}): Readonly<Partial<Record<string, MethodHandler>>>;
|
|
@@ -6,13 +6,22 @@ import { deployHandlers } from "./deploy-handlers.js";
|
|
|
6
6
|
/**
|
|
7
7
|
* Build the default handler map. Callers may override individual methods via
|
|
8
8
|
* `startDaemonServer({ handlers })` — overrides win.
|
|
9
|
+
*
|
|
10
|
+
* `launchLedger` / `execLedger` are daemon-scoped (one per server, not one per
|
|
11
|
+
* connection): blueprint exec registers a job on the webview connection and
|
|
12
|
+
* binds the PTY session on the rust connection, so both peers must see the
|
|
13
|
+
* same ledger instances.
|
|
9
14
|
*/
|
|
10
15
|
export function createDefaultProductHandlers(options) {
|
|
11
16
|
const repoRoot = options?.repoRoot ?? process.cwd();
|
|
12
17
|
return {
|
|
13
18
|
...gitHandlers,
|
|
14
19
|
...createFleetHandlers(repoRoot),
|
|
15
|
-
...createBlueprintsHandlers(repoRoot
|
|
20
|
+
...createBlueprintsHandlers(repoRoot, {
|
|
21
|
+
launchLedger: options?.launchLedger,
|
|
22
|
+
execLedger: options?.execLedger,
|
|
23
|
+
allowlistedRoots: options?.allowlistedRoots,
|
|
24
|
+
}),
|
|
16
25
|
...createSessionsHandlers(repoRoot),
|
|
17
26
|
...deployHandlers,
|
|
18
27
|
};
|
|
@@ -148,6 +148,26 @@ export declare const DAEMON_METHOD_REGISTRY: {
|
|
|
148
148
|
readonly requireHandshake: true;
|
|
149
149
|
readonly uiFacing: true;
|
|
150
150
|
};
|
|
151
|
+
/** Read-only exec attribution + executor-written progress. Never PTY-derived. */
|
|
152
|
+
readonly "blueprints.execStatus": {
|
|
153
|
+
readonly privileged: true;
|
|
154
|
+
readonly requiresConfirmation: false;
|
|
155
|
+
readonly mutates: false;
|
|
156
|
+
readonly requireHandshake: true;
|
|
157
|
+
readonly uiFacing: true;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Rust-only: binds the spawned PTY session id to an exec job. Not UI-facing —
|
|
161
|
+
* the webview must never be able to re-point a job at another session.
|
|
162
|
+
*/
|
|
163
|
+
readonly "blueprints.execBind": {
|
|
164
|
+
readonly privileged: true;
|
|
165
|
+
readonly requiresConfirmation: false;
|
|
166
|
+
readonly mutates: true;
|
|
167
|
+
readonly requireHandshake: true;
|
|
168
|
+
readonly allowedRoles: readonly ["rust"];
|
|
169
|
+
readonly uiFacing: false;
|
|
170
|
+
};
|
|
151
171
|
readonly "deploy.run": {
|
|
152
172
|
readonly privileged: true;
|
|
153
173
|
readonly requiresConfirmation: true;
|
|
@@ -171,7 +191,7 @@ export type UiRpcMethod = {
|
|
|
171
191
|
[M in DaemonRpcMethod]: (typeof DAEMON_METHOD_REGISTRY)[M]["uiFacing"] extends true ? M : never;
|
|
172
192
|
}[DaemonRpcMethod];
|
|
173
193
|
export declare const UI_RPC_METHODS: UiRpcMethod[];
|
|
174
|
-
export declare const DESTRUCTIVE_METHODS: ("auth.issueNonce" | "blueprints.exec" | "blueprints.list" | "daemon.envMap.push" | "deploy.run" | "fleet.status" | "git.commit" | "git.createPr" | "git.diff" | "handshake" | "launch.claim" | "launch.permissionState" | "launch.prepare" | "ping" | "sessions.list" | "sessions.search" | "worktrees.list")[];
|
|
194
|
+
export declare const DESTRUCTIVE_METHODS: ("auth.issueNonce" | "blueprints.exec" | "blueprints.execBind" | "blueprints.execStatus" | "blueprints.list" | "daemon.envMap.push" | "deploy.run" | "fleet.status" | "git.commit" | "git.createPr" | "git.diff" | "handshake" | "launch.claim" | "launch.permissionState" | "launch.prepare" | "ping" | "sessions.list" | "sessions.search" | "worktrees.list")[];
|
|
175
195
|
export declare function getMethodCapability(method: string): MethodCapability | null;
|
|
176
196
|
export declare function isDaemonRpcMethod(method: string): method is DaemonRpcMethod;
|
|
177
197
|
export declare function isUiRpcMethod(method: string): method is UiRpcMethod;
|
|
@@ -116,6 +116,26 @@ export const DAEMON_METHOD_REGISTRY = {
|
|
|
116
116
|
requireHandshake: true,
|
|
117
117
|
uiFacing: true,
|
|
118
118
|
},
|
|
119
|
+
/** Read-only exec attribution + executor-written progress. Never PTY-derived. */
|
|
120
|
+
"blueprints.execStatus": {
|
|
121
|
+
privileged: true,
|
|
122
|
+
requiresConfirmation: false,
|
|
123
|
+
mutates: false,
|
|
124
|
+
requireHandshake: true,
|
|
125
|
+
uiFacing: true,
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Rust-only: binds the spawned PTY session id to an exec job. Not UI-facing —
|
|
129
|
+
* the webview must never be able to re-point a job at another session.
|
|
130
|
+
*/
|
|
131
|
+
"blueprints.execBind": {
|
|
132
|
+
privileged: true,
|
|
133
|
+
requiresConfirmation: false,
|
|
134
|
+
mutates: true,
|
|
135
|
+
requireHandshake: true,
|
|
136
|
+
allowedRoles: ["rust"],
|
|
137
|
+
uiFacing: false,
|
|
138
|
+
},
|
|
119
139
|
"deploy.run": {
|
|
120
140
|
privileged: true,
|
|
121
141
|
requiresConfirmation: true,
|
|
@@ -79,6 +79,8 @@ export type HandshakeResult = z.infer<typeof handshakeResultSchema>;
|
|
|
79
79
|
export declare const daemonRpcMethodSchema: z.ZodEnum<{
|
|
80
80
|
"auth.issueNonce": "auth.issueNonce";
|
|
81
81
|
"blueprints.exec": "blueprints.exec";
|
|
82
|
+
"blueprints.execBind": "blueprints.execBind";
|
|
83
|
+
"blueprints.execStatus": "blueprints.execStatus";
|
|
82
84
|
"blueprints.list": "blueprints.list";
|
|
83
85
|
"daemon.envMap.push": "daemon.envMap.push";
|
|
84
86
|
"deploy.run": "deploy.run";
|
|
@@ -98,6 +100,7 @@ export declare const daemonRpcMethodSchema: z.ZodEnum<{
|
|
|
98
100
|
export declare const uiRpcMethodSchema: z.ZodEnum<{
|
|
99
101
|
"auth.issueNonce": "auth.issueNonce";
|
|
100
102
|
"blueprints.exec": "blueprints.exec";
|
|
103
|
+
"blueprints.execStatus": "blueprints.execStatus";
|
|
101
104
|
"blueprints.list": "blueprints.list";
|
|
102
105
|
"deploy.run": "deploy.run";
|
|
103
106
|
"fleet.status": "fleet.status";
|
|
@@ -303,11 +306,42 @@ export declare const blueprintsListResultSchema: z.ZodObject<{
|
|
|
303
306
|
}, z.core.$strict>;
|
|
304
307
|
export declare const blueprintsExecParamsSchema: z.ZodObject<{
|
|
305
308
|
slug: z.ZodString;
|
|
309
|
+
taskId: z.ZodOptional<z.ZodString>;
|
|
306
310
|
confirmationToken: z.ZodString;
|
|
307
311
|
}, z.core.$strict>;
|
|
312
|
+
/**
|
|
313
|
+
* Opaque only. `jobId` is the durable exec-attribution key; `handle` is the
|
|
314
|
+
* single-use launch handle the Rust peer claims. Deliberately carries no
|
|
315
|
+
* command, args, cwd, or env — those never cross to the webview.
|
|
316
|
+
*/
|
|
308
317
|
export declare const blueprintsExecResultSchema: z.ZodObject<{
|
|
318
|
+
jobId: z.ZodString;
|
|
309
319
|
handle: z.ZodString;
|
|
310
320
|
}, z.core.$strict>;
|
|
321
|
+
export declare const blueprintsExecStatusParamsSchema: z.ZodObject<{
|
|
322
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
323
|
+
}, z.core.$strict>;
|
|
324
|
+
/**
|
|
325
|
+
* Execution status is sourced from executor-written blueprint metadata, never
|
|
326
|
+
* from PTY output. The terminal stream is human-viewing only.
|
|
327
|
+
*/
|
|
328
|
+
export declare const blueprintsExecStatusResultSchema: z.ZodObject<{
|
|
329
|
+
jobs: z.ZodArray<z.ZodObject<{
|
|
330
|
+
jobId: z.ZodString;
|
|
331
|
+
slug: z.ZodString;
|
|
332
|
+
taskId: z.ZodNullable<z.ZodString>;
|
|
333
|
+
sessionId: z.ZodNullable<z.ZodNumber>;
|
|
334
|
+
state: z.ZodEnum<{
|
|
335
|
+
preparing: "preparing";
|
|
336
|
+
running: "running";
|
|
337
|
+
terminal: "terminal";
|
|
338
|
+
}>;
|
|
339
|
+
startedAt: z.ZodNumber;
|
|
340
|
+
executionId: z.ZodNullable<z.ZodString>;
|
|
341
|
+
executionStatus: z.ZodNullable<z.ZodString>;
|
|
342
|
+
executionUpdatedAt: z.ZodNullable<z.ZodString>;
|
|
343
|
+
}, z.core.$strict>>;
|
|
344
|
+
}, z.core.$strict>;
|
|
311
345
|
export declare const deployRunParamsSchema: z.ZodObject<{
|
|
312
346
|
cwd: z.ZodString;
|
|
313
347
|
lane: z.ZodString;
|
|
@@ -499,12 +533,36 @@ export declare const UI_METHOD_SCHEMAS: {
|
|
|
499
533
|
readonly "blueprints.exec": {
|
|
500
534
|
readonly params: z.ZodObject<{
|
|
501
535
|
slug: z.ZodString;
|
|
536
|
+
taskId: z.ZodOptional<z.ZodString>;
|
|
502
537
|
confirmationToken: z.ZodString;
|
|
503
538
|
}, z.core.$strict>;
|
|
504
539
|
readonly result: z.ZodObject<{
|
|
540
|
+
jobId: z.ZodString;
|
|
505
541
|
handle: z.ZodString;
|
|
506
542
|
}, z.core.$strict>;
|
|
507
543
|
};
|
|
544
|
+
readonly "blueprints.execStatus": {
|
|
545
|
+
readonly params: z.ZodObject<{
|
|
546
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
547
|
+
}, z.core.$strict>;
|
|
548
|
+
readonly result: z.ZodObject<{
|
|
549
|
+
jobs: z.ZodArray<z.ZodObject<{
|
|
550
|
+
jobId: z.ZodString;
|
|
551
|
+
slug: z.ZodString;
|
|
552
|
+
taskId: z.ZodNullable<z.ZodString>;
|
|
553
|
+
sessionId: z.ZodNullable<z.ZodNumber>;
|
|
554
|
+
state: z.ZodEnum<{
|
|
555
|
+
preparing: "preparing";
|
|
556
|
+
running: "running";
|
|
557
|
+
terminal: "terminal";
|
|
558
|
+
}>;
|
|
559
|
+
startedAt: z.ZodNumber;
|
|
560
|
+
executionId: z.ZodNullable<z.ZodString>;
|
|
561
|
+
executionStatus: z.ZodNullable<z.ZodString>;
|
|
562
|
+
executionUpdatedAt: z.ZodNullable<z.ZodString>;
|
|
563
|
+
}, z.core.$strict>>;
|
|
564
|
+
}, z.core.$strict>;
|
|
565
|
+
};
|
|
508
566
|
readonly "deploy.run": {
|
|
509
567
|
readonly params: z.ZodObject<{
|
|
510
568
|
cwd: z.ZodString;
|
|
@@ -301,14 +301,48 @@ export const blueprintsListResultSchema = z
|
|
|
301
301
|
export const blueprintsExecParamsSchema = z
|
|
302
302
|
.object({
|
|
303
303
|
slug: z.string().min(1),
|
|
304
|
+
/** Optional attribution only; never becomes part of the composed argv. */
|
|
305
|
+
taskId: z.string().min(1).optional(),
|
|
304
306
|
confirmationToken: z.string().min(1),
|
|
305
307
|
})
|
|
306
308
|
.strict();
|
|
309
|
+
/**
|
|
310
|
+
* Opaque only. `jobId` is the durable exec-attribution key; `handle` is the
|
|
311
|
+
* single-use launch handle the Rust peer claims. Deliberately carries no
|
|
312
|
+
* command, args, cwd, or env — those never cross to the webview.
|
|
313
|
+
*/
|
|
307
314
|
export const blueprintsExecResultSchema = z
|
|
308
315
|
.object({
|
|
316
|
+
jobId: z.string().min(1),
|
|
309
317
|
handle: opaqueHandleSchema,
|
|
310
318
|
})
|
|
311
319
|
.strict();
|
|
320
|
+
export const blueprintsExecStatusParamsSchema = z
|
|
321
|
+
.object({
|
|
322
|
+
slug: z.string().min(1).optional(),
|
|
323
|
+
})
|
|
324
|
+
.strict();
|
|
325
|
+
/**
|
|
326
|
+
* Execution status is sourced from executor-written blueprint metadata, never
|
|
327
|
+
* from PTY output. The terminal stream is human-viewing only.
|
|
328
|
+
*/
|
|
329
|
+
export const blueprintsExecStatusResultSchema = z
|
|
330
|
+
.object({
|
|
331
|
+
jobs: z.array(z
|
|
332
|
+
.object({
|
|
333
|
+
jobId: z.string().min(1),
|
|
334
|
+
slug: z.string().min(1),
|
|
335
|
+
taskId: z.string().nullable(),
|
|
336
|
+
sessionId: z.number().int().nonnegative().nullable(),
|
|
337
|
+
state: z.enum(["preparing", "running", "terminal"]),
|
|
338
|
+
startedAt: z.number().int().nonnegative(),
|
|
339
|
+
executionId: z.string().nullable(),
|
|
340
|
+
executionStatus: z.string().nullable(),
|
|
341
|
+
executionUpdatedAt: z.string().nullable(),
|
|
342
|
+
})
|
|
343
|
+
.strict()),
|
|
344
|
+
})
|
|
345
|
+
.strict();
|
|
312
346
|
export const deployRunParamsSchema = z
|
|
313
347
|
.object({
|
|
314
348
|
cwd: z.string().min(1),
|
|
@@ -344,6 +378,10 @@ export const UI_METHOD_SCHEMAS = {
|
|
|
344
378
|
"worktrees.list": { params: worktreesListParamsSchema, result: worktreesListResultSchema },
|
|
345
379
|
"blueprints.list": { params: blueprintsListParamsSchema, result: blueprintsListResultSchema },
|
|
346
380
|
"blueprints.exec": { params: blueprintsExecParamsSchema, result: blueprintsExecResultSchema },
|
|
381
|
+
"blueprints.execStatus": {
|
|
382
|
+
params: blueprintsExecStatusParamsSchema,
|
|
383
|
+
result: blueprintsExecStatusResultSchema,
|
|
384
|
+
},
|
|
347
385
|
"deploy.run": { params: deployRunParamsSchema, result: deployRunResultSchema },
|
|
348
386
|
};
|
|
349
387
|
// ---------------------------------------------------------------------------
|
|
@@ -10,6 +10,7 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, sta
|
|
|
10
10
|
import { createConnection, createServer } from "node:net";
|
|
11
11
|
import { dirname, join } from "node:path";
|
|
12
12
|
import { createDaemonAuthz } from "./authz.js";
|
|
13
|
+
import { createBlueprintExecLedger } from "./domains/blueprint-exec-ledger.js";
|
|
13
14
|
import { createLaunchLedger } from "./domains/launch.js";
|
|
14
15
|
import { createDefaultProductHandlers } from "./handlers/product.js";
|
|
15
16
|
import { getDefaultDaemonSocketPath } from "./paths.js";
|
|
@@ -104,6 +105,9 @@ export async function startDaemonServer(options = {}) {
|
|
|
104
105
|
const server = createServer();
|
|
105
106
|
const connections = new Set();
|
|
106
107
|
const launchLedger = createLaunchLedger();
|
|
108
|
+
// Daemon-scoped, not per-connection: the webview registers an exec job and
|
|
109
|
+
// the rust peer binds the PTY session from a different connection.
|
|
110
|
+
const execLedger = createBlueprintExecLedger();
|
|
107
111
|
server.on("connection", (socket) => {
|
|
108
112
|
connections.add(socket);
|
|
109
113
|
socket.on("close", () => connections.delete(socket));
|
|
@@ -137,6 +141,9 @@ export async function startDaemonServer(options = {}) {
|
|
|
137
141
|
handlers: {
|
|
138
142
|
...createDefaultProductHandlers({
|
|
139
143
|
repoRoot: options.allowlistedRoots?.[0] ?? process.cwd(),
|
|
144
|
+
allowlistedRoots: options.allowlistedRoots,
|
|
145
|
+
launchLedger,
|
|
146
|
+
execLedger,
|
|
140
147
|
}),
|
|
141
148
|
...options.handlers,
|
|
142
149
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { extractBlockedReason } from "#markdown/blocked-line";
|
|
1
2
|
/**
|
|
2
3
|
* Blueprint Plan Format Validator
|
|
3
4
|
*
|
|
@@ -394,7 +395,6 @@ function validateLifecycleContract(filePath, content) {
|
|
|
394
395
|
const taskBlocks = extractTaskBlocks(content);
|
|
395
396
|
for (const task of taskBlocks) {
|
|
396
397
|
const statusMatch = task.section.match(/\*\*Status:\*\*\s*(.+)/i);
|
|
397
|
-
const blockedMatch = task.section.match(/\*\*Blocked:\*\*\s*(.+)/i);
|
|
398
398
|
const checkboxMatches = Array.from(task.section.matchAll(/^- \[([ x])\]/gm));
|
|
399
399
|
const total = checkboxMatches.length;
|
|
400
400
|
const checked = checkboxMatches.filter((match) => match[1] === "x").length;
|
|
@@ -407,7 +407,7 @@ function validateLifecycleContract(filePath, content) {
|
|
|
407
407
|
errors.push(createTaskStatusInvalidError(filePath, task.id, taskStatus));
|
|
408
408
|
continue;
|
|
409
409
|
}
|
|
410
|
-
const blockedReason =
|
|
410
|
+
const blockedReason = extractBlockedReason(task.section) ?? "";
|
|
411
411
|
if (taskStatus === "blocked" && !blockedReason) {
|
|
412
412
|
errors.push(createBlockedReasonRequiredError(filePath, task.id));
|
|
413
413
|
}
|
|
@@ -11,8 +11,23 @@ export function validateWpErrorDocsUrl(value) {
|
|
|
11
11
|
return value;
|
|
12
12
|
}
|
|
13
13
|
function redactStringValue(value, explicitSecrets) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// Caller-declared secrets are masked FIRST, against the untouched original
|
|
15
|
+
// string, and always resolve to the full `[REDACTED]` form. The generic
|
|
16
|
+
// shared-redactor (`redactText`) runs SECOND, on whatever the explicit pass
|
|
17
|
+
// left behind.
|
|
18
|
+
//
|
|
19
|
+
// The order is load-bearing: `redactText`'s pattern set is broad (see
|
|
20
|
+
// `_shared/redact.ts`) and grows over time (h-010). A caller-supplied
|
|
21
|
+
// secret can incidentally match one of those generic shapes (e.g. a value
|
|
22
|
+
// adjacent to a `TOKEN=`/`SECRET:` key). Running the generic pass first
|
|
23
|
+
// would replace the literal with a *partial* mask (`CA***23`) before the
|
|
24
|
+
// explicit pass ever sees it, so `next.includes(secret)` fails silently and
|
|
25
|
+
// the caller's declared secret ends up under-redacted relative to what the
|
|
26
|
+
// caller explicitly asked to fully hide. A value the caller names as a
|
|
27
|
+
// secret is a stronger, more specific signal than a generic pattern match
|
|
28
|
+
// and must win.
|
|
29
|
+
let next = value;
|
|
30
|
+
let redacted = false;
|
|
16
31
|
for (const secret of [...explicitSecrets].sort((left, right) => right.length - left.length)) {
|
|
17
32
|
if (!secret)
|
|
18
33
|
continue;
|
|
@@ -21,6 +36,10 @@ function redactStringValue(value, explicitSecrets) {
|
|
|
21
36
|
redacted = true;
|
|
22
37
|
}
|
|
23
38
|
}
|
|
39
|
+
const generic = redactText(next) ?? next;
|
|
40
|
+
if (generic !== next)
|
|
41
|
+
redacted = true;
|
|
42
|
+
next = generic;
|
|
24
43
|
return { value: next, redacted };
|
|
25
44
|
}
|
|
26
45
|
function redactUnknownEvidence(value, explicitSecrets) {
|
|
@@ -57,6 +57,9 @@ export interface ResolvePackageRootForRuntimeOptions {
|
|
|
57
57
|
}
|
|
58
58
|
export declare function resolvePackageRootForRuntime(options?: ResolvePackageRootForRuntimeOptions): string | null;
|
|
59
59
|
export declare function findOwningPackageRoot(startDir: string): string | null;
|
|
60
|
+
export declare function checkFreestandingRtkSurface(cwd?: string): DoctorCheck | null;
|
|
61
|
+
/** Non-mutating warn for user-global freestanding RTK rewriters (rtk init -g). */
|
|
62
|
+
export declare function checkGlobalFreestandingRtkSurface(): DoctorCheck | null;
|
|
60
63
|
export declare function checkRtkOnPath(cwd?: string): Promise<DoctorCheck | null>;
|
|
61
64
|
export declare function checkRootLauncherContract(): DoctorCheck;
|
|
62
65
|
export declare function checkRuntimePluginCacheStaleSurfaceRepair(options?: {
|
|
@@ -66,6 +69,14 @@ export declare function checkRuntimePluginCacheStaleSurfaceRepair(options?: {
|
|
|
66
69
|
}): DoctorCheck;
|
|
67
70
|
export declare function checkNativePluginRuntime(): DoctorCheck;
|
|
68
71
|
export declare function checkPhase2RuntimeTypecheckParity(): DoctorCheck;
|
|
72
|
+
/**
|
|
73
|
+
* Codex must receive `webpresso` over exactly one channel — the bundled Codex
|
|
74
|
+
* plugin. Report the retired user-global `[mcp_servers.webpresso]` block that
|
|
75
|
+
* `wp setup` removes, and call out a double registration distinctly. A
|
|
76
|
+
* user-authored block (a live `wp` outside every agent-kit root) is never
|
|
77
|
+
* removed by setup, so it gets its own manual-action finding.
|
|
78
|
+
*/
|
|
79
|
+
export declare function classifyLegacyCodexWebpressoChannel(configPath?: string, homeDir?: string): string | null;
|
|
69
80
|
export declare function checkPackagedHostArtifacts(cwd?: string): DoctorCheck;
|
|
70
81
|
export declare function checkHostArtifactOwnership(cwd?: string): DoctorCheck;
|
|
71
82
|
export declare function checkHostLifecycleDepth(): DoctorCheck;
|
package/dist/esm/hooks/doctor.js
CHANGED
|
@@ -27,6 +27,8 @@ import { isAgentKitSourceRepo } from "#cli/commands/init/source-repo-hook-policy
|
|
|
27
27
|
import { findAgentKitPackageRoot, resolveAgentKitPackageRoot, } from "#cli/commands/init/package-root";
|
|
28
28
|
import { readInstalledHooksMap } from "#hooks/shared/installed-hooks.js";
|
|
29
29
|
import { auditCodexConfigPaths, checkCodexConfigPathIntegrity } from "#hooks/codex-config-paths.js";
|
|
30
|
+
import { findInstalledCodexPluginMcpManifests, pruneOwnedMcpServerBlock, } from "#cli/commands/init/scaffolders/codex-mcp/index.js";
|
|
31
|
+
import { isAgentKitOwnedWpCommand, WEBPRESSO_MCP_SERVER_NAME, } from "#cli/commands/init/mcp-spec.js";
|
|
30
32
|
import { parseProjectMcpServers, scanCodexConfigDrift } from "#hooks/host-config-contract.js";
|
|
31
33
|
import { defaultCodexConfigFilePath } from "#cli/commands/init/scaffolders/agent-hooks/codex-trust-sync.js";
|
|
32
34
|
import { expectedRootWpBinRelativePath, formatRootLauncherContractFailure, rootContractMode, validateRootLauncherContract, } from "#launcher/root-contract.js";
|
|
@@ -55,7 +57,10 @@ function createOwnedProbeSettler(child, timeoutMs, timeoutResult, resolve) {
|
|
|
55
57
|
return settle;
|
|
56
58
|
}
|
|
57
59
|
const RTK_REQUESTED_MARKER = join(".agent", ".rtk-requested");
|
|
58
|
-
const RTK_INSTALL_HINT = "rtk requested
|
|
60
|
+
const RTK_INSTALL_HINT = "rtk requested but managed binary missing; re-run wp setup (or set WP_RTK_BIN)";
|
|
61
|
+
const RTK_FREESTANDING_HOOK_REL = join(".claude", "hooks", "rtk-rewrite.sh");
|
|
62
|
+
const RTK_FREESTANDING_SETTINGS_REL = join(".claude", "settings.json");
|
|
63
|
+
const RTK_FREESTANDING_REPAIR = "stale freestanding rtk-rewrite surface; run wp setup (ensureRtk strips rtk-rewrite.sh — pretool-guard owns rewrite)";
|
|
59
64
|
const HOST_SMOKE_ENV = "WP_RUN_HOST_SMOKE";
|
|
60
65
|
const HOOK_PROBE_TIMEOUT_ENV = "WP_DOCTOR_HOOK_TIMEOUT_MS";
|
|
61
66
|
const WRAPPER_PROBE_ENV = "WP_DOCTOR_WRAPPER_PROBE";
|
|
@@ -347,6 +352,62 @@ function checkConsumerCodexHookPaths(cwd = process.cwd()) {
|
|
|
347
352
|
function wasRtkRequested(cwd = process.cwd()) {
|
|
348
353
|
return tryAccess(join(cwd, RTK_REQUESTED_MARKER));
|
|
349
354
|
}
|
|
355
|
+
export function checkFreestandingRtkSurface(cwd = process.cwd()) {
|
|
356
|
+
const hookPath = join(cwd, RTK_FREESTANDING_HOOK_REL);
|
|
357
|
+
const settingsPath = join(cwd, RTK_FREESTANDING_SETTINGS_REL);
|
|
358
|
+
const hookPresent = tryAccess(hookPath);
|
|
359
|
+
const markers = [];
|
|
360
|
+
if (hookPresent)
|
|
361
|
+
markers.push(RTK_FREESTANDING_HOOK_REL);
|
|
362
|
+
if (tryAccess(settingsPath)) {
|
|
363
|
+
try {
|
|
364
|
+
const settings = readFileSync(settingsPath, "utf8");
|
|
365
|
+
if (settings.includes("rtk-rewrite.sh")) {
|
|
366
|
+
markers.push(`${RTK_FREESTANDING_SETTINGS_REL} rtk-rewrite.sh`);
|
|
367
|
+
}
|
|
368
|
+
if (settings.includes("rtk hook claude")) {
|
|
369
|
+
markers.push(`${RTK_FREESTANDING_SETTINGS_REL} rtk hook claude`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
// ignore unreadable settings
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (markers.length === 0)
|
|
377
|
+
return null;
|
|
378
|
+
return {
|
|
379
|
+
name: "freestanding rtk PreToolUse retired",
|
|
380
|
+
ok: false,
|
|
381
|
+
detail: `${RTK_FREESTANDING_REPAIR} (found: ${markers.join(", ")})`,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/** Non-mutating warn for user-global freestanding RTK rewriters (rtk init -g). */
|
|
385
|
+
export function checkGlobalFreestandingRtkSurface() {
|
|
386
|
+
const globalSettings = join(homedir(), ".claude", "settings.json");
|
|
387
|
+
const globalHook = join(homedir(), ".claude", "hooks", "rtk-rewrite.sh");
|
|
388
|
+
const markers = [];
|
|
389
|
+
if (tryAccess(globalHook))
|
|
390
|
+
markers.push("~/.claude/hooks/rtk-rewrite.sh");
|
|
391
|
+
if (tryAccess(globalSettings)) {
|
|
392
|
+
try {
|
|
393
|
+
const settings = readFileSync(globalSettings, "utf8");
|
|
394
|
+
if (settings.includes("rtk-rewrite.sh"))
|
|
395
|
+
markers.push("~/.claude/settings.json rtk-rewrite.sh");
|
|
396
|
+
if (settings.includes("rtk hook claude"))
|
|
397
|
+
markers.push("~/.claude/settings.json rtk hook claude");
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
// ignore
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (markers.length === 0)
|
|
404
|
+
return null;
|
|
405
|
+
return {
|
|
406
|
+
name: "global freestanding rtk (warn)",
|
|
407
|
+
ok: true,
|
|
408
|
+
detail: `WARNING: global freestanding RTK PreToolUse still present (${markers.join(", ")}); remove manually or re-run rtk uninstall — project setup does not mutate ~/.claude. Dual rewriters may race updatedInput with wp-pretool-guard.`,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
350
411
|
function shouldRunHostChecks(mode) {
|
|
351
412
|
if (mode === "skip")
|
|
352
413
|
return false;
|
|
@@ -393,36 +454,13 @@ function resolveRequestedHosts(mode, hostNames) {
|
|
|
393
454
|
export function checkRtkOnPath(cwd) {
|
|
394
455
|
if (!wasRtkRequested(cwd))
|
|
395
456
|
return Promise.resolve(null);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
let stderr = "";
|
|
404
|
-
const settle = createOwnedProbeSettler(child, timeoutMs, () => ({
|
|
405
|
-
name: "rtk on PATH",
|
|
406
|
-
ok: false,
|
|
407
|
-
detail: `rtk probe timed out after ${timeoutMs}ms`,
|
|
408
|
-
}), resolve);
|
|
409
|
-
child.stdout.on("data", (chunk) => {
|
|
410
|
-
stdout += String(chunk);
|
|
411
|
-
});
|
|
412
|
-
child.stderr?.on("data", (chunk) => {
|
|
413
|
-
stderr += String(chunk);
|
|
414
|
-
});
|
|
415
|
-
child.on("error", () => {
|
|
416
|
-
settle({ name: "rtk on PATH", ok: false, detail: RTK_INSTALL_HINT });
|
|
417
|
-
});
|
|
418
|
-
child.on("close", (code) => {
|
|
419
|
-
if (code === 0) {
|
|
420
|
-
settle({ name: "rtk on PATH", ok: true, detail: stdout.trim() || "rtk present" });
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
const suffix = stderr.trim().length > 0 ? ` (${stderr.trim()})` : "";
|
|
424
|
-
settle({ name: "rtk on PATH", ok: false, detail: `${RTK_INSTALL_HINT}${suffix}` });
|
|
425
|
-
});
|
|
457
|
+
// Managed binary (Webpresso cache / WP_RTK_BIN), not bare PATH brew install.
|
|
458
|
+
return import("#tool-runtime/managed-rtk.js").then(({ isManagedRtkAvailable, resolveManagedRtkExecutable }) => {
|
|
459
|
+
const path = resolveManagedRtkExecutable();
|
|
460
|
+
if (path && isManagedRtkAvailable()) {
|
|
461
|
+
return { name: "rtk managed", ok: true, detail: path };
|
|
462
|
+
}
|
|
463
|
+
return { name: "rtk managed", ok: false, detail: RTK_INSTALL_HINT };
|
|
426
464
|
});
|
|
427
465
|
}
|
|
428
466
|
async function probeHookBin(wpCli, hookName, checkStdin) {
|
|
@@ -1184,19 +1222,44 @@ async function checkCodexHost() {
|
|
|
1184
1222
|
detail: `missing MCP entry (webpresso=${hasAgentKit})`,
|
|
1185
1223
|
};
|
|
1186
1224
|
}
|
|
1187
|
-
const
|
|
1188
|
-
if (
|
|
1189
|
-
|
|
1190
|
-
.map((finding) => `${finding.location}: ${finding.path} (${finding.reason === "missing" ? "path does not exist" : "volatile versioned path"})`)
|
|
1191
|
-
.join("; ");
|
|
1192
|
-
return {
|
|
1193
|
-
name: "Codex host integration",
|
|
1194
|
-
ok: false,
|
|
1195
|
-
detail: `webpresso MCP listed but launch paths are broken or rot-prone — ${detail}`,
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1225
|
+
const legacy = classifyLegacyCodexWebpressoChannel();
|
|
1226
|
+
if (legacy)
|
|
1227
|
+
return { name: "Codex host integration", ok: false, detail: legacy };
|
|
1198
1228
|
return { name: "Codex host integration", ok: true, detail: "webpresso MCP visible" };
|
|
1199
1229
|
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Codex must receive `webpresso` over exactly one channel — the bundled Codex
|
|
1232
|
+
* plugin. Report the retired user-global `[mcp_servers.webpresso]` block that
|
|
1233
|
+
* `wp setup` removes, and call out a double registration distinctly. A
|
|
1234
|
+
* user-authored block (a live `wp` outside every agent-kit root) is never
|
|
1235
|
+
* removed by setup, so it gets its own manual-action finding.
|
|
1236
|
+
*/
|
|
1237
|
+
export function classifyLegacyCodexWebpressoChannel(configPath = defaultCodexConfigFilePath(), homeDir = process.env.HOME || homedir()) {
|
|
1238
|
+
const outcome = classifyCodexConfigWebpressoBlock(configPath);
|
|
1239
|
+
if (outcome === null || outcome.kind === "absent")
|
|
1240
|
+
return null;
|
|
1241
|
+
if (outcome.kind === "ambiguous") {
|
|
1242
|
+
return `${configPath} declares webpresso in a TOML spelling wp setup cannot rewrite; remove the [mcp_servers.webpresso] definition by hand — the bundled Codex plugin is the single delivery channel`;
|
|
1243
|
+
}
|
|
1244
|
+
if (outcome.kind === "preserved") {
|
|
1245
|
+
return `${configPath} declares a user-authored webpresso MCP server (${outcome.command ?? "no command"}); wp setup preserves it. Remove it by hand to use the bundled Codex plugin as the single delivery channel`;
|
|
1246
|
+
}
|
|
1247
|
+
const dualChannel = findInstalledCodexPluginMcpManifests(homeDir).length > 0;
|
|
1248
|
+
const prefix = dualChannel
|
|
1249
|
+
? "webpresso is registered over BOTH delivery channels — the bundled Codex plugin AND a legacy"
|
|
1250
|
+
: "webpresso is still registered over the retired legacy";
|
|
1251
|
+
return `${prefix} [mcp_servers.webpresso] block in ${configPath} (command = ${outcome.command}); run \`wp setup\` — it removes the legacy block`;
|
|
1252
|
+
}
|
|
1253
|
+
function classifyCodexConfigWebpressoBlock(configPath) {
|
|
1254
|
+
try {
|
|
1255
|
+
if (!existsSync(configPath))
|
|
1256
|
+
return null;
|
|
1257
|
+
return pruneOwnedMcpServerBlock(readFileSync(configPath, "utf8"), WEBPRESSO_MCP_SERVER_NAME, isAgentKitOwnedWpCommand);
|
|
1258
|
+
}
|
|
1259
|
+
catch {
|
|
1260
|
+
return null;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1200
1263
|
async function checkOpenCodeHost(cwd = process.cwd()) {
|
|
1201
1264
|
const available = await runCommand("opencode", ["--version"]);
|
|
1202
1265
|
if (!available.ok) {
|
|
@@ -1430,9 +1493,8 @@ export function checkPackagedHostArtifacts(cwd = process.cwd()) {
|
|
|
1430
1493
|
const serverRecord = server && typeof server === "object" && !Array.isArray(server)
|
|
1431
1494
|
? server
|
|
1432
1495
|
: null;
|
|
1433
|
-
if (serverRecord?.command !== "
|
|
1434
|
-
|
|
1435
|
-
failures.push("Codex adapter MCP surface must expose direct webpresso server map launching ${PLUGIN_ROOT}/bin/wp mcp");
|
|
1496
|
+
if (serverRecord?.command !== "wp" || !stringArrayEquals(serverRecord.args, ["mcp"])) {
|
|
1497
|
+
failures.push("Codex adapter MCP surface must expose direct webpresso server map launching wp mcp");
|
|
1436
1498
|
}
|
|
1437
1499
|
}
|
|
1438
1500
|
if (codexHooks) {
|
|
@@ -2138,6 +2200,13 @@ export async function runHooksDoctor(opts = {}) {
|
|
|
2138
2200
|
const rtkCheck = await checkRtkOnPath(opts.cwd);
|
|
2139
2201
|
if (rtkCheck)
|
|
2140
2202
|
checks.push(rtkCheck);
|
|
2203
|
+
const freestandingRtk = checkFreestandingRtkSurface(opts.cwd);
|
|
2204
|
+
if (freestandingRtk)
|
|
2205
|
+
checks.push(freestandingRtk);
|
|
2206
|
+
// Non-mutating WARN only — never mutates ~/.claude; surfaces dual-rewriter risk.
|
|
2207
|
+
const globalFreestandingRtk = checkGlobalFreestandingRtkSurface();
|
|
2208
|
+
if (globalFreestandingRtk)
|
|
2209
|
+
checks.push(globalFreestandingRtk);
|
|
2141
2210
|
if (shouldRunHostChecks(hostMode)) {
|
|
2142
2211
|
for (const host of requestedHosts) {
|
|
2143
2212
|
if (host === "codex") {
|
|
@@ -23,7 +23,7 @@ function routeRawMutatingGitWorktree(command) {
|
|
|
23
23
|
return {
|
|
24
24
|
action: "deny",
|
|
25
25
|
tool: "wp_worktree",
|
|
26
|
-
guidance: "Use the `wp_worktree` MCP tool (or `wp worktree`
|
|
26
|
+
guidance: "Use the `wp_worktree` MCP tool (or `wp worktree prune --all` / `wp worktree remove <target>` when MCP is unavailable) instead — managed repositories may mutate linked worktrees only through agent-kit so owner bindings and the global registry stay consistent. Both prune paths also run `git worktree prune`, so a hand-deleted worktree directory still releases the branch it claimed.",
|
|
27
27
|
code: "GUARD_RAW_GIT_MUTATION",
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RTK rewrite inside path-stable pretool-guard (no freestanding consumer hook).
|
|
3
|
+
*
|
|
4
|
+
* v1: exact `git status` → `<managed-rtk> git status` when managed rtk is available.
|
|
5
|
+
*/
|
|
6
|
+
export type RtkRewriteDecision = {
|
|
7
|
+
readonly action: "rewrite";
|
|
8
|
+
readonly command: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly action: "noop";
|
|
11
|
+
readonly reason: string;
|
|
12
|
+
};
|
|
13
|
+
export type RtkPresenceProbe = () => boolean;
|
|
14
|
+
export type RtkExecutableResolver = () => string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Decide whether to rewrite a Bash command through managed rtk.
|
|
17
|
+
*/
|
|
18
|
+
export declare function decideRtkRewrite(command: string, isRtkPresent?: RtkPresenceProbe, resolveExecutable?: RtkExecutableResolver): RtkRewriteDecision;
|
|
19
|
+
/**
|
|
20
|
+
* POSIX single-quote wrap for absolute managed paths.
|
|
21
|
+
* Refuse NUL/newline/single-quote — those cannot be safely embedded in `'…'`.
|
|
22
|
+
* Double-quote wrapping is intentionally avoided ($ / ` / " injection).
|
|
23
|
+
*/
|
|
24
|
+
export declare function shellQuoteExecutable(path: string): string | null;
|