@webpresso/agent-kit 3.3.3 → 3.3.5

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 (156) hide show
  1. package/THIRD-PARTY-NOTICES.md +12 -10
  2. package/catalog/agent/rules/changeset-release.md +15 -4
  3. package/catalog/agent/rules/managed-tool-binaries.md +67 -0
  4. package/catalog/agent/rules/parallel-orchestration-quota.md +99 -1
  5. package/catalog/agent/rules/pre-implementation.md +36 -20
  6. package/catalog/agent/rules/rtk-routing.md +22 -16
  7. package/catalog/agent/skills/autopilot/SKILL.md +4 -3
  8. package/catalog/agent/skills/ultragoal/SKILL.md +11 -9
  9. package/dist/esm/audit/agents.js +126 -26
  10. package/dist/esm/audit/hook-surface.js +5 -1
  11. package/dist/esm/audit/repo-guardrails.d.ts +8 -0
  12. package/dist/esm/audit/repo-guardrails.js +71 -1
  13. package/dist/esm/blueprint/core/parser.js +38 -12
  14. package/dist/esm/blueprint/execution/artifacts.js +8 -4
  15. package/dist/esm/blueprint/execution/frontmatter-keys.d.ts +17 -0
  16. package/dist/esm/blueprint/execution/frontmatter-keys.js +24 -0
  17. package/dist/esm/blueprint/execution/metadata.js +8 -4
  18. package/dist/esm/blueprint/lifecycle/audit.d.ts +21 -0
  19. package/dist/esm/blueprint/lifecycle/audit.js +89 -3
  20. package/dist/esm/blueprint/lifecycle/review-provenance.js +63 -10
  21. package/dist/esm/blueprint/lifecycle/rollout-anchor.d.ts +22 -0
  22. package/dist/esm/blueprint/lifecycle/rollout-anchor.js +37 -1
  23. package/dist/esm/blueprint/markdown/blocked-line.d.ts +49 -0
  24. package/dist/esm/blueprint/markdown/blocked-line.js +63 -0
  25. package/dist/esm/blueprint/markdown/helpers.js +10 -4
  26. package/dist/esm/blueprint/tracked-document/parser.js +3 -3
  27. package/dist/esm/blueprint/trust/dossier.js +41 -1
  28. package/dist/esm/blueprint/trust/gate-row.d.ts +55 -0
  29. package/dist/esm/blueprint/trust/gate-row.js +113 -0
  30. package/dist/esm/blueprint/trust/promotion.d.ts +17 -0
  31. package/dist/esm/blueprint/trust/promotion.js +19 -19
  32. package/dist/esm/build/atomic-file-copy.d.ts +32 -0
  33. package/dist/esm/build/atomic-file-copy.js +44 -0
  34. package/dist/esm/build/vendor-oxlint-plugins.d.ts +11 -0
  35. package/dist/esm/build/vendor-oxlint-plugins.js +48 -0
  36. package/dist/esm/cli/commands/blueprint/mutations.d.ts +15 -0
  37. package/dist/esm/cli/commands/blueprint/mutations.js +8 -2
  38. package/dist/esm/cli/commands/compile.d.ts +13 -0
  39. package/dist/esm/cli/commands/compile.js +182 -62
  40. package/dist/esm/cli/commands/format.js +17 -1
  41. package/dist/esm/cli/commands/gain/index.js +10 -3
  42. package/dist/esm/cli/commands/init/gitignore-patcher.js +6 -0
  43. package/dist/esm/cli/commands/init/index.js +32 -52
  44. package/dist/esm/cli/commands/init/mcp-spec.d.ts +48 -13
  45. package/dist/esm/cli/commands/init/mcp-spec.js +86 -30
  46. package/dist/esm/cli/commands/init/merge.js +30 -10
  47. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +56 -31
  48. package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +180 -43
  49. package/dist/esm/cli/commands/init/scaffolders/rtk/index.d.ts +17 -5
  50. package/dist/esm/cli/commands/init/scaffolders/rtk/index.js +56 -75
  51. package/dist/esm/cli/commands/init/scaffolders/runtime-check/index.js +7 -6
  52. package/dist/esm/cli/commands/init/untracked-collision.d.ts +12 -1
  53. package/dist/esm/cli/commands/init/untracked-collision.js +23 -1
  54. package/dist/esm/cli/commands/pr-help.js +1 -1
  55. package/dist/esm/cli/commands/pr.js +18 -4
  56. package/dist/esm/cli/commands/review.d.ts +1 -0
  57. package/dist/esm/cli/commands/review.js +137 -7
  58. package/dist/esm/cli/commands/sync.d.ts +8 -6
  59. package/dist/esm/cli/commands/sync.js +11 -9
  60. package/dist/esm/cli/commands/worktree/router-dispatch.d.ts +24 -2
  61. package/dist/esm/cli/commands/worktree/router-dispatch.js +80 -48
  62. package/dist/esm/cli/commands/worktree/router.js +5 -2
  63. package/dist/esm/cli/direct-provider-launch.js +12 -4
  64. package/dist/esm/compiler/flatten.d.ts +10 -1
  65. package/dist/esm/compiler/flatten.js +14 -4
  66. package/dist/esm/compose/admin-blocks-registry-integrity.d.ts +22 -0
  67. package/dist/esm/compose/admin-blocks-registry-integrity.js +90 -0
  68. package/dist/esm/compose/compose.d.ts +8 -0
  69. package/dist/esm/compose/compose.js +115 -8
  70. package/dist/esm/compose/ops-report-schema.js +17 -3
  71. package/dist/esm/compose/registry-resolve.d.ts +17 -0
  72. package/dist/esm/compose/registry-resolve.js +78 -11
  73. package/dist/esm/config/oxlint/graphql-conventions.js +2 -5
  74. package/dist/esm/config/oxlint/import-hygiene.js +21 -8
  75. package/dist/esm/config/oxlint/oxlint-config.fixture.d.ts +1 -1
  76. package/dist/esm/config/oxlint/oxlint-config.fixture.js +2 -3
  77. package/dist/esm/config/oxlint/oxlintrc.d.ts +5 -7
  78. package/dist/esm/config/oxlint/oxlintrc.js +19 -31
  79. package/dist/esm/config/oxlint/path-roles.js +53 -0
  80. package/dist/esm/config/oxlint/query-patterns.js +2 -5
  81. package/dist/esm/content/dispatch.js +4 -0
  82. package/dist/esm/content/loader.d.ts +1 -1
  83. package/dist/esm/content/loader.js +10 -6
  84. package/dist/esm/content/skill-policy.d.ts +11 -0
  85. package/dist/esm/content/skill-policy.js +33 -0
  86. package/dist/esm/daemon/domains/blueprint-exec-ledger.d.ts +86 -0
  87. package/dist/esm/daemon/domains/blueprint-exec-ledger.js +134 -0
  88. package/dist/esm/daemon/domains/blueprint-exec.d.ts +106 -0
  89. package/dist/esm/daemon/domains/blueprint-exec.js +161 -0
  90. package/dist/esm/daemon/domains/launch.d.ts +25 -0
  91. package/dist/esm/daemon/domains/launch.js +30 -1
  92. package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +12 -1
  93. package/dist/esm/daemon/handlers/blueprints-handlers.js +148 -6
  94. package/dist/esm/daemon/handlers/product.d.ts +10 -0
  95. package/dist/esm/daemon/handlers/product.js +10 -1
  96. package/dist/esm/daemon/methods.d.ts +21 -1
  97. package/dist/esm/daemon/methods.js +20 -0
  98. package/dist/esm/daemon/protocol/contract.d.ts +58 -0
  99. package/dist/esm/daemon/protocol/contract.js +38 -0
  100. package/dist/esm/daemon/server.js +7 -0
  101. package/dist/esm/docs-linter/blueprint-plan.js +2 -2
  102. package/dist/esm/errors/wp-error.js +21 -2
  103. package/dist/esm/hooks/doctor.d.ts +11 -0
  104. package/dist/esm/hooks/doctor.js +114 -45
  105. package/dist/esm/hooks/pretool-guard/dev-routing.js +68 -5
  106. package/dist/esm/hooks/pretool-guard/rtk-rewrite.d.ts +24 -0
  107. package/dist/esm/hooks/pretool-guard/rtk-rewrite.js +50 -0
  108. package/dist/esm/hooks/pretool-guard/runner.js +6 -0
  109. package/dist/esm/hooks/pretool-guard/validators/worktree-discipline.js +62 -3
  110. package/dist/esm/hooks/status/index.js +1 -1
  111. package/dist/esm/mcp/blueprint/_shared/lifecycle.js +39 -11
  112. package/dist/esm/mcp/blueprint/handlers/review-log.d.ts +14 -7
  113. package/dist/esm/mcp/blueprint/handlers/review-log.js +46 -22
  114. package/dist/esm/mcp/blueprint/registration.js +1 -1
  115. package/dist/esm/mcp/tools/_shared/redact.d.ts +22 -0
  116. package/dist/esm/mcp/tools/_shared/redact.js +114 -8
  117. package/dist/esm/mcp/tools/gain.js +28 -2
  118. package/dist/esm/mcp/tools/worktree.js +65 -3
  119. package/dist/esm/mcp/tools/wp-ui-compose.js +38 -4
  120. package/dist/esm/mcp/tools/wp-ui-preview.js +14 -7
  121. package/dist/esm/review/authority.js +56 -1
  122. package/dist/esm/review/delivery-verifier.d.ts +4 -0
  123. package/dist/esm/review/delivery-verifier.js +9 -1
  124. package/dist/esm/review/lifecycle-writers.d.ts +76 -0
  125. package/dist/esm/review/lifecycle-writers.js +330 -0
  126. package/dist/esm/review/subject.js +66 -32
  127. package/dist/esm/status/snapshot.d.ts +5 -0
  128. package/dist/esm/status/snapshot.js +27 -2
  129. package/dist/esm/symlinker/consumers.d.ts +3 -1
  130. package/dist/esm/symlinker/consumers.js +7 -1
  131. package/dist/esm/symlinker/unified-sync.d.ts +3 -3
  132. package/dist/esm/symlinker/unified-sync.js +88 -11
  133. package/dist/esm/test/shard-durations.json +0 -2
  134. package/dist/esm/test-helpers/global-setup.js +38 -3
  135. package/dist/esm/tool-runtime/managed-rtk.d.ts +44 -0
  136. package/dist/esm/tool-runtime/managed-rtk.js +275 -0
  137. package/dist/esm/tool-runtime/resolve-runner.js +18 -194
  138. package/dist/esm/utils/package-root.d.ts +32 -0
  139. package/dist/esm/utils/package-root.js +82 -0
  140. package/dist/esm/worktrees/git-metadata.d.ts +41 -0
  141. package/dist/esm/worktrees/git-metadata.js +48 -0
  142. package/package.json +16 -21
  143. package/dist/esm/cli/commands/init/scaffolders/subagents/index.d.ts +0 -6
  144. package/dist/esm/cli/commands/init/scaffolders/subagents/index.js +0 -77
  145. package/dist/esm/config/oxlint/code-safety.d.ts +0 -18
  146. package/dist/esm/config/oxlint/foundation-purity.d.ts +0 -21
  147. package/dist/esm/config/oxlint/graphql-conventions.d.ts +0 -23
  148. package/dist/esm/config/oxlint/import-hygiene.d.ts +0 -34
  149. package/dist/esm/config/oxlint/index.d.ts +0 -22
  150. package/dist/esm/config/oxlint/index.js +0 -28
  151. package/dist/esm/config/oxlint/monorepo-paths.d.ts +0 -22
  152. package/dist/esm/config/oxlint/query-patterns.d.ts +0 -24
  153. package/dist/esm/config/oxlint/testing-quality.d.ts +0 -35
  154. package/dist/esm/config/oxlint/tier-boundaries.d.ts +0 -35
  155. package/dist/esm/output-transforms/rulesync.d.ts +0 -2
  156. package/dist/esm/output-transforms/rulesync.js +0 -79
@@ -1,10 +1,22 @@
1
1
  /**
2
- * Blueprint-domain product handlers: `blueprints.list` is a real
3
- * implementation over the `blueprints/<status>/` directories; `blueprints.exec`
4
- * is not implemented (exec remains CLI-owned).
2
+ * Blueprint-domain product handlers.
3
+ *
4
+ * - `blueprints.list` enumerates the `blueprints/<status>/` directories.
5
+ * - `blueprints.exec` composes an executor launch spec and prepares it as an
6
+ * opaque, single-use launch handle. It returns **only** identifiers: no
7
+ * command, no argv, no cwd, no env ever crosses to the webview, and this
8
+ * module never spawns anything (spawning is Rust-only, through the PTY
9
+ * manager, after a rust-credentialed `launch.claim`).
10
+ * - `blueprints.execBind` is rust-role-only and records the spawned PTY
11
+ * session against the job so attribution survives a UI restart.
12
+ * - `blueprints.execStatus` joins ledger rows with executor-written blueprint
13
+ * frontmatter metadata. Status is never parsed out of PTY output — the
14
+ * terminal stream is human-viewing only.
5
15
  */
6
16
  import { readdirSync, existsSync, statSync } from "node:fs";
7
17
  import { join } from "node:path";
18
+ import { composeBlueprintExecSpec, readBlueprintExecProgress, } from "#daemon/domains/blueprint-exec.js";
19
+ import { asRecord, requireString } from "./shared.js";
8
20
  function listBlueprintRows(repoRoot) {
9
21
  const statuses = ["completed", "in-progress", "planned", "parked", "draft", "archived"];
10
22
  const rows = [];
@@ -21,16 +33,146 @@ function listBlueprintRows(repoRoot) {
21
33
  rows.sort((a, b) => a.slug.localeCompare(b.slug));
22
34
  return rows;
23
35
  }
36
+ /**
37
+ * Executor statuses that mean the run is over. Mirrors `executionStatusSchema`
38
+ * terminal values; a job in one of these retires from the ledger.
39
+ */
40
+ const TERMINAL_EXECUTION_STATUSES = new Set([
41
+ "completed",
42
+ "failed",
43
+ "stopped",
44
+ ]);
45
+ function optionalString(record, key) {
46
+ const value = record[key];
47
+ if (value === undefined || value === null || value === "")
48
+ return null;
49
+ if (typeof value !== "string") {
50
+ throw new Error(`param ${key} must be a string when present`);
51
+ }
52
+ return value;
53
+ }
54
+ /**
55
+ * Params `blueprints.exec` accepts. `requestNonce`/`confirmationToken` belong
56
+ * to the auth envelope and may still be present on the domain record.
57
+ *
58
+ * The protocol contract's strict Zod schema is a declarative helper and is not
59
+ * applied on the dispatch path, so unknown keys would otherwise be silently
60
+ * ignored rather than refused. Ignoring is already fail-safe here (the handler
61
+ * reads only known keys), but refusing is what makes "exec params are data,
62
+ * not command" an enforced boundary instead of an aspirational one — and it
63
+ * stops a future edit that naively spreads params from becoming an injection.
64
+ */
65
+ const EXEC_ALLOWED_PARAM_KEYS = new Set([
66
+ "slug",
67
+ "taskId",
68
+ "confirmationToken",
69
+ "requestNonce",
70
+ ]);
71
+ /** O(#keys) on a bounded record. Never echoes caller-controlled key text. */
72
+ function assertNoSmuggledExecParams(record) {
73
+ for (const key of Object.keys(record)) {
74
+ if (!EXEC_ALLOWED_PARAM_KEYS.has(key)) {
75
+ throw new Error("unexpected param for blueprints.exec: only slug and taskId are accepted " +
76
+ "(command, args, cwd, and env are composed by the daemon)");
77
+ }
78
+ }
79
+ }
80
+ function requireSessionId(record) {
81
+ const value = record["sessionId"];
82
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
83
+ throw new Error("missing or invalid param: sessionId");
84
+ }
85
+ return value;
86
+ }
87
+ function requireExecDeps(deps) {
88
+ const { launchLedger, execLedger } = deps;
89
+ if (launchLedger === undefined || execLedger === undefined) {
90
+ throw new Error("blueprints exec is unavailable: daemon ledgers are not wired");
91
+ }
92
+ return { launchLedger, execLedger };
93
+ }
24
94
  /**
25
95
  * Build blueprint-domain handlers scoped to `repoRoot`.
96
+ *
97
+ * The ledgers are created once per daemon (not per connection) and passed in,
98
+ * because the webview peer registers the job while the rust peer binds the
99
+ * session — two different connections must observe the same ledger.
26
100
  */
27
- export function createBlueprintsHandlers(repoRoot) {
101
+ export function createBlueprintsHandlers(repoRoot, deps = {}) {
102
+ const allowlistedRoots = deps.allowlistedRoots !== undefined && deps.allowlistedRoots.length > 0
103
+ ? deps.allowlistedRoots
104
+ : [repoRoot];
28
105
  return {
29
106
  "blueprints.list": () => ({
30
107
  blueprints: listBlueprintRows(repoRoot),
31
108
  }),
32
- "blueprints.exec": () => {
33
- throw new Error("blueprints.exec is not implemented (exec remains CLI-owned)");
109
+ "blueprints.exec": (_session, params) => {
110
+ const { launchLedger, execLedger } = requireExecDeps(deps);
111
+ const record = asRecord(params);
112
+ assertNoSmuggledExecParams(record);
113
+ const slug = requireString(record, "slug");
114
+ const taskId = optionalString(record, "taskId");
115
+ // Validation, path confinement, and daemon-side argv composition.
116
+ const spec = composeBlueprintExecSpec({
117
+ slug,
118
+ taskId,
119
+ repoRoot,
120
+ allowlistedRoots,
121
+ });
122
+ const { handle } = launchLedger.prepareComposed({
123
+ command: spec.command,
124
+ args: spec.args,
125
+ cwd: spec.cwd,
126
+ env: spec.env,
127
+ });
128
+ const { jobId } = execLedger.register({
129
+ slug: spec.slug,
130
+ taskId: spec.taskId,
131
+ launchHandle: handle,
132
+ });
133
+ // Opaque only: the rust-role claim is what yields command/args/env.
134
+ return { jobId, handle };
135
+ },
136
+ "blueprints.execBind": (_session, params) => {
137
+ const { execLedger } = requireExecDeps(deps);
138
+ const record = asRecord(params);
139
+ const jobId = requireString(record, "jobId");
140
+ const sessionId = requireSessionId(record);
141
+ const job = execLedger.bindSession(jobId, sessionId);
142
+ return { jobId: job.jobId, sessionId: job.sessionId, state: job.state };
143
+ },
144
+ "blueprints.execStatus": (_session, params) => {
145
+ const { execLedger } = requireExecDeps(deps);
146
+ const record = asRecord(params);
147
+ const slugFilter = optionalString(record, "slug");
148
+ const jobs = execLedger
149
+ .list()
150
+ .filter((job) => slugFilter === null || job.slug === slugFilter)
151
+ .map((job) => {
152
+ // Executor-written frontmatter metadata — never PTY bytes.
153
+ const progress = readBlueprintExecProgress(repoRoot, job.slug);
154
+ // Drive the terminal transition from the executor's own status.
155
+ // This is what keeps `markTerminal` (and therefore ledger eviction)
156
+ // live in production without inventing a push transport: the daemon
157
+ // has no server-push seam, so the pull that reports status is also
158
+ // the pull that retires the job.
159
+ const settled = progress !== null && TERMINAL_EXECUTION_STATUSES.has(progress.status)
160
+ ? execLedger.markTerminal(job.jobId)
161
+ : null;
162
+ const state = settled?.state ?? job.state;
163
+ return {
164
+ jobId: job.jobId,
165
+ slug: job.slug,
166
+ taskId: job.taskId,
167
+ sessionId: job.sessionId,
168
+ state,
169
+ startedAt: job.startedAt,
170
+ executionId: progress?.executionId ?? null,
171
+ executionStatus: progress?.status ?? null,
172
+ executionUpdatedAt: progress?.updatedAt ?? null,
173
+ };
174
+ });
175
+ return { jobs };
34
176
  },
35
177
  };
36
178
  }
@@ -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) {
@@ -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;