@webpresso/agent-kit 3.3.2 → 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.
Files changed (167) hide show
  1. package/THIRD-PARTY-NOTICES.md +12 -10
  2. package/catalog/AGENTS.md.tpl +3 -5
  3. package/catalog/agent/rules/changeset-release.md +15 -4
  4. package/catalog/agent/rules/managed-tool-binaries.md +67 -0
  5. package/catalog/agent/rules/parallel-orchestration-quota.md +99 -1
  6. package/catalog/agent/rules/pre-implementation.md +36 -20
  7. package/catalog/agent/rules/rtk-routing.md +22 -16
  8. package/catalog/agent/skills/autopilot/SKILL.md +4 -3
  9. package/catalog/agent/skills/ultragoal/SKILL.md +11 -9
  10. package/catalog/agent/skills/verify/SKILL.md +12 -12
  11. package/catalog/compose/admin-blocks-registry.json +659 -0
  12. package/dist/esm/audit/hook-surface.js +5 -1
  13. package/dist/esm/audit/repo-guardrails.d.ts +8 -0
  14. package/dist/esm/audit/repo-guardrails.js +71 -1
  15. package/dist/esm/blueprint/core/parser.js +40 -16
  16. package/dist/esm/blueprint/core/validation/criteria.js +2 -1
  17. package/dist/esm/blueprint/execution/artifacts.js +8 -4
  18. package/dist/esm/blueprint/execution/frontmatter-keys.d.ts +17 -0
  19. package/dist/esm/blueprint/execution/frontmatter-keys.js +24 -0
  20. package/dist/esm/blueprint/execution/metadata.js +8 -4
  21. package/dist/esm/blueprint/lifecycle/audit.d.ts +21 -0
  22. package/dist/esm/blueprint/lifecycle/audit.js +89 -3
  23. package/dist/esm/blueprint/lifecycle/review-provenance.js +148 -40
  24. package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +22 -0
  25. package/dist/esm/blueprint/lifecycle/rollout-anchor.js +37 -1
  26. package/dist/esm/blueprint/markdown/blocked-line.d.ts +49 -0
  27. package/dist/esm/blueprint/markdown/blocked-line.js +63 -0
  28. package/dist/esm/blueprint/markdown/helpers.js +10 -4
  29. package/dist/esm/blueprint/tracked-document/parser.js +3 -3
  30. package/dist/esm/blueprint/trust/gate-row.d.ts +55 -0
  31. package/dist/esm/blueprint/trust/gate-row.js +113 -0
  32. package/dist/esm/blueprint/trust/promotion.d.ts +17 -0
  33. package/dist/esm/blueprint/trust/promotion.js +19 -19
  34. package/dist/esm/build/atomic-file-copy.d.ts +32 -0
  35. package/dist/esm/build/atomic-file-copy.js +44 -0
  36. package/dist/esm/build/cli-mcp-parity.js +3 -2
  37. package/dist/esm/build/package-manifest.js +7 -2
  38. package/dist/esm/build/vendor-oxlint-plugins.d.ts +8 -0
  39. package/dist/esm/build/vendor-oxlint-plugins.js +53 -0
  40. package/dist/esm/cli/commands/audit-core.js +9 -1
  41. package/dist/esm/cli/commands/audit.js +16 -5
  42. package/dist/esm/cli/commands/blueprint/mutations.d.ts +15 -0
  43. package/dist/esm/cli/commands/blueprint/mutations.js +8 -2
  44. package/dist/esm/cli/commands/compile.d.ts +13 -0
  45. package/dist/esm/cli/commands/compile.js +182 -62
  46. package/dist/esm/cli/commands/format.js +17 -1
  47. package/dist/esm/cli/commands/gain/index.js +10 -3
  48. package/dist/esm/cli/commands/init/gitignore-patcher.js +6 -0
  49. package/dist/esm/cli/commands/init/index.js +29 -48
  50. package/dist/esm/cli/commands/init/mcp-spec.d.ts +54 -4
  51. package/dist/esm/cli/commands/init/mcp-spec.js +126 -22
  52. package/dist/esm/cli/commands/init/merge.js +30 -10
  53. package/dist/esm/cli/commands/init/scaffold-agents-md.js +5 -7
  54. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +56 -31
  55. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +180 -43
  56. package/dist/esm/cli/commands/init/scaffolders/rtk/index.d.ts +17 -5
  57. package/dist/esm/cli/commands/init/scaffolders/rtk/index.js +56 -75
  58. package/dist/esm/cli/commands/init/scaffolders/runtime-check/index.js +7 -6
  59. package/dist/esm/cli/commands/init/untracked-collision.d.ts +12 -1
  60. package/dist/esm/cli/commands/init/untracked-collision.js +23 -1
  61. package/dist/esm/cli/commands/package-manager.js +8 -2
  62. package/dist/esm/cli/commands/pr-help.js +1 -1
  63. package/dist/esm/cli/commands/pr.js +18 -4
  64. package/dist/esm/cli/commands/review.js +60 -6
  65. package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +24 -2
  66. package/dist/esm/cli/commands/worktree/router-dispatch.js +80 -48
  67. package/dist/esm/cli/commands/worktree/router.js +5 -2
  68. package/dist/esm/cli/direct-provider-launch.js +12 -4
  69. package/dist/esm/compiler/flatten.d.ts +10 -1
  70. package/dist/esm/compiler/flatten.js +14 -4
  71. package/dist/esm/compose/admin-blocks-registry-integrity.d.ts +22 -0
  72. package/dist/esm/compose/admin-blocks-registry-integrity.js +90 -0
  73. package/dist/esm/compose/compose.d.ts +46 -0
  74. package/dist/esm/compose/compose.js +250 -0
  75. package/dist/esm/compose/escape-html.d.ts +5 -0
  76. package/dist/esm/compose/escape-html.js +12 -0
  77. package/dist/esm/compose/ops-report-render.d.ts +5 -0
  78. package/dist/esm/compose/ops-report-render.js +71 -0
  79. package/dist/esm/compose/ops-report-schema.d.ts +42 -0
  80. package/dist/esm/compose/ops-report-schema.js +60 -0
  81. package/dist/esm/compose/preview.d.ts +14 -0
  82. package/dist/esm/compose/preview.js +32 -0
  83. package/dist/esm/compose/registry-resolve.d.ts +64 -0
  84. package/dist/esm/compose/registry-resolve.js +200 -0
  85. package/dist/esm/config/oxlint/graphql-conventions.js +2 -5
  86. package/dist/esm/config/oxlint/import-hygiene.js +21 -8
  87. package/dist/esm/config/oxlint/oxlint-config.fixture.d.ts +1 -1
  88. package/dist/esm/config/oxlint/oxlint-config.fixture.js +2 -3
  89. package/dist/esm/config/oxlint/oxlintrc.d.ts +5 -7
  90. package/dist/esm/config/oxlint/oxlintrc.js +18 -21
  91. package/dist/esm/config/oxlint/path-roles.js +53 -0
  92. package/dist/esm/config/oxlint/query-patterns.js +2 -5
  93. package/dist/esm/daemon/domains/blueprint-exec-ledger.d.ts +86 -0
  94. package/dist/esm/daemon/domains/blueprint-exec-ledger.js +134 -0
  95. package/dist/esm/daemon/domains/blueprint-exec.d.ts +106 -0
  96. package/dist/esm/daemon/domains/blueprint-exec.js +161 -0
  97. package/dist/esm/daemon/domains/launch.d.ts +25 -0
  98. package/dist/esm/daemon/domains/launch.js +30 -1
  99. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +12 -1
  100. package/dist/esm/daemon/handlers/blueprints-handlers.js +148 -6
  101. package/dist/esm/daemon/handlers/product.d.ts +10 -0
  102. package/dist/esm/daemon/handlers/product.js +10 -1
  103. package/dist/esm/daemon/methods.d.ts +21 -1
  104. package/dist/esm/daemon/methods.js +20 -0
  105. package/dist/esm/daemon/protocol/contract.d.ts +58 -0
  106. package/dist/esm/daemon/protocol/contract.js +38 -0
  107. package/dist/esm/daemon/server.js +7 -0
  108. package/dist/esm/docs-linter/blueprint-plan.js +2 -2
  109. package/dist/esm/errors/wp-error.js +21 -2
  110. package/dist/esm/git/changed-files.d.ts +20 -0
  111. package/dist/esm/git/changed-files.js +63 -0
  112. package/dist/esm/hooks/doctor.d.ts +11 -0
  113. package/dist/esm/hooks/doctor.js +114 -45
  114. package/dist/esm/hooks/pretool-guard/dev-routing.js +1 -1
  115. package/dist/esm/hooks/pretool-guard/rtk-rewrite.d.ts +24 -0
  116. package/dist/esm/hooks/pretool-guard/rtk-rewrite.js +50 -0
  117. package/dist/esm/hooks/pretool-guard/runner.js +6 -0
  118. package/dist/esm/hooks/status/index.js +1 -1
  119. package/dist/esm/hooks/stop/qa-changed-files.js +6 -1
  120. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +39 -11
  121. package/dist/esm/mcp/blueprint/handlers/review-log.d.ts +14 -7
  122. package/dist/esm/mcp/blueprint/handlers/review-log.js +46 -22
  123. package/dist/esm/mcp/blueprint/handlers/validate.js +6 -0
  124. package/dist/esm/mcp/blueprint/registration.js +1 -1
  125. package/dist/esm/mcp/tools/_names.d.ts +1 -1
  126. package/dist/esm/mcp/tools/_names.js +4 -0
  127. package/dist/esm/mcp/tools/_registry.js +8 -0
  128. package/dist/esm/mcp/tools/_shared/redact.d.ts +22 -0
  129. package/dist/esm/mcp/tools/_shared/redact.js +114 -8
  130. package/dist/esm/mcp/tools/gain.js +28 -2
  131. package/dist/esm/mcp/tools/release-progress.d.ts +9 -0
  132. package/dist/esm/mcp/tools/release-progress.js +110 -0
  133. package/dist/esm/mcp/tools/worktree.js +65 -3
  134. package/dist/esm/mcp/tools/wp-ui-blocks-list.d.ts +3 -0
  135. package/dist/esm/mcp/tools/wp-ui-blocks-list.js +43 -0
  136. package/dist/esm/mcp/tools/wp-ui-compose.d.ts +3 -0
  137. package/dist/esm/mcp/tools/wp-ui-compose.js +96 -0
  138. package/dist/esm/mcp/tools/wp-ui-preview.d.ts +3 -0
  139. package/dist/esm/mcp/tools/wp-ui-preview.js +59 -0
  140. package/dist/esm/package.json +2 -0
  141. package/dist/esm/review/lifecycle-writers.d.ts +76 -0
  142. package/dist/esm/review/lifecycle-writers.js +330 -0
  143. package/dist/esm/review/subject.js +66 -32
  144. package/dist/esm/status/snapshot.d.ts +5 -0
  145. package/dist/esm/status/snapshot.js +27 -2
  146. package/dist/esm/test/shard-durations.json +0 -1
  147. package/dist/esm/test-helpers/global-setup.js +38 -3
  148. package/dist/esm/tool-runtime/managed-rtk.d.ts +44 -0
  149. package/dist/esm/tool-runtime/managed-rtk.js +275 -0
  150. package/dist/esm/tool-runtime/resolve-runner.js +18 -194
  151. package/dist/esm/utils/package-root.d.ts +32 -0
  152. package/dist/esm/utils/package-root.js +82 -0
  153. package/dist/esm/worktrees/git-metadata.d.ts +41 -0
  154. package/dist/esm/worktrees/git-metadata.js +48 -0
  155. package/package.json +27 -21
  156. package/dist/esm/config/oxlint/code-safety.d.ts +0 -18
  157. package/dist/esm/config/oxlint/foundation-purity.d.ts +0 -21
  158. package/dist/esm/config/oxlint/graphql-conventions.d.ts +0 -23
  159. package/dist/esm/config/oxlint/import-hygiene.d.ts +0 -34
  160. package/dist/esm/config/oxlint/index.d.ts +0 -22
  161. package/dist/esm/config/oxlint/index.js +0 -28
  162. package/dist/esm/config/oxlint/monorepo-paths.d.ts +0 -22
  163. package/dist/esm/config/oxlint/query-patterns.d.ts +0 -24
  164. package/dist/esm/config/oxlint/testing-quality.d.ts +0 -35
  165. package/dist/esm/config/oxlint/tier-boundaries.d.ts +0 -35
  166. package/dist/esm/output-transforms/rulesync.d.ts +0 -2
  167. 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 = blockedMatch?.[1]?.trim() ?? "";
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
- let next = redactText(value) ?? value;
15
- let redacted = next !== value;
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) {
@@ -5,6 +5,26 @@ export interface ChangedFilesResult {
5
5
  readonly reason: ChangedFilesReason;
6
6
  }
7
7
  export declare function defaultBranchBaseRef(env?: NodeJS.ProcessEnv): string;
8
+ /**
9
+ * Latest fork point of `HEAD` from the base branch, given a caller-supplied base.
10
+ *
11
+ * CI passes `--base "$PR_BASE_SHA"` (`github.event.pull_request.base.sha`),
12
+ * which is pinned when the pull request is opened and does NOT advance as the
13
+ * base branch does. Once the branch is rebased onto a newer base — the
14
+ * documented recovery flow for a stale branch — that pinned SHA is no longer the
15
+ * fork point, so `<pinned>...HEAD` reports every commit merged into the base
16
+ * branch since the PR opened as if this branch had authored it. Scoped gates
17
+ * then fail a branch for unrelated, already-merged work.
18
+ *
19
+ * `git merge-base` against the LIVE base branch ref is recomputed from current
20
+ * history, so it tracks the rebase and yields the true fork point. Prefer it,
21
+ * but only when it is provably a descendant of the caller's base (never widen
22
+ * the range the caller asked for) and does not swallow `HEAD` (a base branch
23
+ * that already contains `HEAD` would otherwise empty the scope). Otherwise the
24
+ * caller's base is returned verbatim, so an unrelated or unresolvable live ref
25
+ * can never silently replace an explicit base.
26
+ */
27
+ export declare function resolveBranchDiffBase(cwd?: string, base?: string, liveBaseRef?: string): string;
8
28
  export declare function getGitTopLevel(cwd?: string): string | null;
9
29
  export declare function getStagedFiles(cwd?: string): ChangedFilesResult;
10
30
  export declare function getBranchChangedFiles(cwd?: string, base?: string): ChangedFilesResult;
@@ -5,6 +5,69 @@ export function defaultBranchBaseRef(env = process.env) {
5
5
  const githubBaseRef = env.GITHUB_BASE_REF?.trim();
6
6
  return `origin/${githubBaseRef && githubBaseRef.length > 0 ? githubBaseRef : "main"}`;
7
7
  }
8
+ /**
9
+ * Latest fork point of `HEAD` from the base branch, given a caller-supplied base.
10
+ *
11
+ * CI passes `--base "$PR_BASE_SHA"` (`github.event.pull_request.base.sha`),
12
+ * which is pinned when the pull request is opened and does NOT advance as the
13
+ * base branch does. Once the branch is rebased onto a newer base — the
14
+ * documented recovery flow for a stale branch — that pinned SHA is no longer the
15
+ * fork point, so `<pinned>...HEAD` reports every commit merged into the base
16
+ * branch since the PR opened as if this branch had authored it. Scoped gates
17
+ * then fail a branch for unrelated, already-merged work.
18
+ *
19
+ * `git merge-base` against the LIVE base branch ref is recomputed from current
20
+ * history, so it tracks the rebase and yields the true fork point. Prefer it,
21
+ * but only when it is provably a descendant of the caller's base (never widen
22
+ * the range the caller asked for) and does not swallow `HEAD` (a base branch
23
+ * that already contains `HEAD` would otherwise empty the scope). Otherwise the
24
+ * caller's base is returned verbatim, so an unrelated or unresolvable live ref
25
+ * can never silently replace an explicit base.
26
+ */
27
+ export function resolveBranchDiffBase(cwd = process.cwd(), base = defaultBranchBaseRef(), liveBaseRef = defaultBranchBaseRef()) {
28
+ const forkPoint = readMergeBase(cwd, liveBaseRef, "HEAD");
29
+ if (forkPoint === null || forkPoint === readCommit(cwd, "HEAD"))
30
+ return base;
31
+ return isAncestorCommit(cwd, base, forkPoint) ? forkPoint : base;
32
+ }
33
+ function readCommit(cwd, ref) {
34
+ try {
35
+ const output = execFileSync("git", ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], {
36
+ cwd,
37
+ encoding: "utf8",
38
+ stdio: ["ignore", "pipe", "ignore"],
39
+ }).trim();
40
+ return output.length > 0 ? output : null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function readMergeBase(cwd, left, right) {
47
+ try {
48
+ const output = execFileSync("git", ["merge-base", left, right], {
49
+ cwd,
50
+ encoding: "utf8",
51
+ stdio: ["ignore", "pipe", "ignore"],
52
+ }).trim();
53
+ return output.length > 0 ? output : null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ function isAncestorCommit(cwd, ancestor, descendant) {
60
+ try {
61
+ execFileSync("git", ["merge-base", "--is-ancestor", ancestor, descendant], {
62
+ cwd,
63
+ stdio: ["ignore", "ignore", "ignore"],
64
+ });
65
+ return true;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
8
71
  export function getGitTopLevel(cwd = process.cwd()) {
9
72
  try {
10
73
  const output = execFileSync("git", ["rev-parse", "--show-toplevel"], {
@@ -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;