@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
@@ -0,0 +1,200 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, isAbsolute, join, resolve } from "node:path";
4
+ import { resolvePackageAssetPreferred } from "#utils/package-assets.js";
5
+ import { z } from "zod";
6
+ const REGISTRY_RELATIVE = join("generated", "frontend", "blocks", "registry.json");
7
+ const MAX_WALK = 48;
8
+ /**
9
+ * Local reader capability floor for project registries (agent-kit consumer).
10
+ * Bump in the same PR as catalog/compose/admin-blocks-registry.json major/minor
11
+ * advances. Does not import @webpresso/schema (SEA / nondeterminism lock).
12
+ */
13
+ export const READER_REGISTRY_VERSION = "1.0.0";
14
+ /** Stop climbing past these markers (mirrors project-root clamps elsewhere). */
15
+ function isProjectBoundary(dir) {
16
+ return existsSync(join(dir, ".git")) || existsSync(join(dir, ".webpressorc.json"));
17
+ }
18
+ /**
19
+ * `~/.webpresso` is the managed-worktree host, never a product project root.
20
+ * Matching it would mis-label every uninitialized checkout under $HOME.
21
+ */
22
+ function isManagedHostWebpresso(candidate) {
23
+ return resolve(candidate) === resolve(join(homedir(), ".webpresso"));
24
+ }
25
+ const blockDefinitionSchema = z
26
+ .object({
27
+ name: z.string(),
28
+ view: z.enum(["list", "detail", "form"]),
29
+ description: z.string().optional(),
30
+ props: z.array(z.unknown()).optional(),
31
+ variants: z.array(z.string()).optional(),
32
+ slots: z.array(z.unknown()).optional(),
33
+ permissions: z.array(z.unknown()).optional(),
34
+ deprecated: z.boolean().optional(),
35
+ })
36
+ .passthrough();
37
+ export const blockRegistrySchema = z.object({
38
+ $schema: z.string().optional(),
39
+ version: z.string(),
40
+ minVersion: z.string().optional(),
41
+ blocks: z.array(blockDefinitionSchema).min(1),
42
+ });
43
+ /**
44
+ * Walk up for nearest project `.webpresso` directory (not a file).
45
+ * Clamped at the enclosing project boundary (`.git` / `.webpressorc.json`)
46
+ * and never treats `~/.webpresso` (managed worktree host) as a project root.
47
+ */
48
+ function walkUpForWebpressoDir(startDir) {
49
+ let dir = resolve(startDir);
50
+ for (let i = 0; i < MAX_WALK; i++) {
51
+ const candidate = join(dir, ".webpresso");
52
+ if (existsSync(candidate)) {
53
+ try {
54
+ if (statSync(candidate).isDirectory() && !isManagedHostWebpresso(candidate)) {
55
+ return candidate;
56
+ }
57
+ }
58
+ catch {
59
+ // ignore unreadable markers
60
+ }
61
+ }
62
+ // Do not climb past the repo / consumer root into $HOME tooling dirs.
63
+ if (isProjectBoundary(dir))
64
+ return null;
65
+ const parent = dirname(dir);
66
+ if (parent === dir)
67
+ return null;
68
+ dir = parent;
69
+ }
70
+ return null;
71
+ }
72
+ export function defaultSnapshotPath() {
73
+ // Portable across src/ and dist/esm/ via package-root walk (no fixed-depth joins).
74
+ const assetPath = resolvePackageAssetPreferred(["catalog/compose/admin-blocks-registry.json"]);
75
+ if (!existsSync(assetPath)) {
76
+ throw new Error(`admin-blocks-registry.json snapshot not found at package asset path: ${assetPath}`);
77
+ }
78
+ return assetPath;
79
+ }
80
+ function loadRegistryFile(path) {
81
+ try {
82
+ const raw = readFileSync(path, "utf8");
83
+ const parsed = JSON.parse(raw);
84
+ return blockRegistrySchema.parse(parsed);
85
+ }
86
+ catch (error) {
87
+ const detail = error instanceof Error ? error.message : String(error);
88
+ throw new Error(`Failed to load block registry at ${path}: ${detail}`, { cause: error });
89
+ }
90
+ }
91
+ function parseSemver(version) {
92
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
93
+ if (!match)
94
+ return null;
95
+ return {
96
+ major: Number(match[1]),
97
+ minor: Number(match[2]),
98
+ patch: Number(match[3]),
99
+ };
100
+ }
101
+ /**
102
+ * Whether a loaded project registry is readable by this agent-kit consumer.
103
+ * - registry.version major must match the reader major
104
+ * - if registry.minVersion is set, reader must be >= that floor (semver order)
105
+ */
106
+ export function isProjectRegistryCompatibleWithReader(registry, readerVersion = READER_REGISTRY_VERSION) {
107
+ const reader = parseSemver(readerVersion);
108
+ if (!reader) {
109
+ return { ok: false, reason: `reader version "${readerVersion}" is not semver` };
110
+ }
111
+ const produced = parseSemver(registry.version);
112
+ if (!produced) {
113
+ return { ok: false, reason: `registry version "${registry.version}" is not semver` };
114
+ }
115
+ if (produced.major !== reader.major) {
116
+ return {
117
+ ok: false,
118
+ reason: `registry major ${produced.major} incompatible with reader major ${reader.major} (${readerVersion})`,
119
+ };
120
+ }
121
+ if (registry.minVersion !== undefined) {
122
+ const min = parseSemver(registry.minVersion);
123
+ if (!min) {
124
+ return { ok: false, reason: `registry minVersion "${registry.minVersion}" is not semver` };
125
+ }
126
+ const belowMin = reader.major < min.major ||
127
+ (reader.major === min.major && reader.minor < min.minor) ||
128
+ (reader.major === min.major && reader.minor === min.minor && reader.patch < min.patch);
129
+ if (belowMin) {
130
+ return {
131
+ ok: false,
132
+ reason: `reader ${readerVersion} is below registry minVersion ${registry.minVersion}`,
133
+ };
134
+ }
135
+ }
136
+ return { ok: true };
137
+ }
138
+ /**
139
+ * Two-tier registry resolution (v0):
140
+ * 1. Nearest project `.webpresso/` (within git/webpressorc boundary) — if it has
141
+ * generated blocks registry, use it
142
+ * 2. Else catalog snapshot (with warning when that project `.webpresso/` lacks registry)
143
+ *
144
+ * Never dynamically imports @webpresso/schema.
145
+ * Never climbs past the project boundary into `~/.webpresso` (managed worktree host)
146
+ * or other ancestor projects (avoids silent wrong-project catalog).
147
+ */
148
+ export function resolveBlockRegistry(options = {}) {
149
+ const start = options.cwd
150
+ ? isAbsolute(options.cwd)
151
+ ? options.cwd
152
+ : resolve(process.cwd(), options.cwd)
153
+ : process.cwd();
154
+ const webpressoRoot = walkUpForWebpressoDir(start);
155
+ const warnings = [];
156
+ if (webpressoRoot) {
157
+ const projectPath = join(webpressoRoot, REGISTRY_RELATIVE);
158
+ if (existsSync(projectPath)) {
159
+ try {
160
+ const registry = loadRegistryFile(projectPath);
161
+ const compat = isProjectRegistryCompatibleWithReader(registry);
162
+ if (!compat.ok) {
163
+ warnings.push(`Project registry at ${projectPath} incompatible with reader ${READER_REGISTRY_VERSION} (${compat.reason}); using catalog snapshot.`);
164
+ }
165
+ else {
166
+ return {
167
+ registry,
168
+ source: "project",
169
+ registryVersion: registry.version,
170
+ path: projectPath,
171
+ warnings,
172
+ webpressoPresentWithoutRegistry: false,
173
+ };
174
+ }
175
+ }
176
+ catch (error) {
177
+ // Producer codegen can advance ahead of this consumer's schema; prefer
178
+ // snapshot over hard-failing MCP tools on version skew.
179
+ const detail = error instanceof Error ? error.message : String(error);
180
+ warnings.push(`Project registry at ${projectPath} failed validation (${detail}); using catalog snapshot. Regenerate or align registry schema.`);
181
+ }
182
+ }
183
+ }
184
+ const snapshotPath = options.snapshotPath ?? defaultSnapshotPath();
185
+ const registry = loadRegistryFile(snapshotPath);
186
+ if (webpressoRoot && warnings.length === 0) {
187
+ warnings.push(`Project has .webpresso/ at ${webpressoRoot} but no ${join(".webpresso", REGISTRY_RELATIVE)}; using catalog snapshot ${registry.version}. Run schema frontend codegen / converge to materialize a project registry.`);
188
+ }
189
+ return {
190
+ registry,
191
+ source: "snapshot",
192
+ registryVersion: registry.version,
193
+ path: snapshotPath,
194
+ warnings,
195
+ webpressoPresentWithoutRegistry: webpressoRoot !== null && !existsSync(join(webpressoRoot, REGISTRY_RELATIVE)),
196
+ };
197
+ }
198
+ export function blockNamesForView(registry, view) {
199
+ return new Set(registry.blocks.filter((block) => block.view === view).map((block) => block.name));
200
+ }
@@ -7,6 +7,7 @@
7
7
  // causes runtime errors: "field 'user' not found in type: 'query_root'"
8
8
  //
9
9
  // This rule scans template literals and string literals for known singular patterns and reports them.
10
+ import { isWebAppSurface, normalizeFilename } from "./path-roles.js";
10
11
  // Mapping of singular table patterns to their correct plural/actual GraphQL field names.
11
12
  // Format: [singular, correct, description]
12
13
  const SINGULAR_TABLE_RULES = [
@@ -76,9 +77,6 @@ const INLINE_GRAPHQL_EXEMPT_PATH_SEGMENTS = [
76
77
  "/packages/sdk/schema-engine/src/emitters/",
77
78
  "/packages/feature/app-core/src/daemon/",
78
79
  ];
79
- function normalizeFilename(filename) {
80
- return typeof filename === "string" ? filename.replaceAll("\\", "/") : "";
81
- }
82
80
  function getFilename(context) {
83
81
  if (typeof context.getFilename === "function") {
84
82
  return normalizeFilename(context.getFilename());
@@ -92,9 +90,8 @@ function isClientQuerySurface(filename) {
92
90
  if (INLINE_GRAPHQL_EXEMPT_PATH_SEGMENTS.some((segment) => normalized.includes(segment))) {
93
91
  return false;
94
92
  }
95
- const isWebAppSurface = normalized.includes("/apps/web/") && normalized.includes("/app/");
96
93
  const isFeatureSurface = normalized.includes("/packages/feature/") && normalized.includes("/src/");
97
- return isWebAppSurface || isFeatureSurface;
94
+ return isWebAppSurface(normalized) || isFeatureSurface;
98
95
  }
99
96
  function getNodeStart(node) {
100
97
  if (Array.isArray(node?.range) && typeof node.range[0] === "number") {
@@ -4,6 +4,8 @@
4
4
  // - no-src-path-imports
5
5
  // - no-relative-mock-paths
6
6
  // - no-forbidden-package-imports
7
+ import { isAgentKitSeaTreeFile, isPlatformAppFile, isSdkPackageFile, normalizeFilename, } from "./path-roles.js";
8
+ export { isAgentKitSeaTreeFile, isPlatformAppFile, isSdkPackageFile, normalizeFilename, } from "./path-roles.js";
7
9
  const CROSS_PACKAGE_SEGMENT = /(?:^|\/)(packages|apps|tooling|infra|webpresso)\//;
8
10
  function isRelativeParentPath(source) {
9
11
  return typeof source === "string" && source.includes("../");
@@ -32,9 +34,6 @@ function reportCrossPackageImport(context, node) {
32
34
  message: "Do not reach into another package/app with a relative filesystem import. Add a proper package export and import it via the package name.",
33
35
  });
34
36
  }
35
- function normalizeFilename(filename) {
36
- return typeof filename === "string" ? filename.replaceAll("\\", "/") : "";
37
- }
38
37
  function getFilename(context) {
39
38
  if (typeof context.getFilename === "function") {
40
39
  return normalizeFilename(context.getFilename());
@@ -46,12 +45,16 @@ function checkStaticModuleSource(node, callback) {
46
45
  return;
47
46
  callback(node.source.value, node.source);
48
47
  }
49
- function isPlatformAppFile(filename) {
50
- return filename.includes("/apps/workers/") || filename.includes("/apps/web/");
51
- }
52
- function isSdkPackageFile(filename) {
53
- return filename.includes("/packages/sdk/");
48
+ /** Package imports forbidden in agent-kit SEA surfaces (schema + ui paint kits). */
49
+ export function isSeaForbiddenPackageImport(source) {
50
+ if (typeof source !== "string")
51
+ return false;
52
+ return (source === "@webpresso/schema" ||
53
+ source.startsWith("@webpresso/schema/") ||
54
+ source === "@webpresso/ui" ||
55
+ source.startsWith("@webpresso/ui/"));
54
56
  }
57
+ export const SEA_FORBIDDEN_IMPORT_MESSAGE = "Agent-kit SEA surfaces (compose / wp_ui_*) must not import `@webpresso/schema` or `@webpresso/ui`. Use the two-tier block registry snapshot/project file and local Zod/HTML paint instead (offline / nondeterminism lock).";
55
58
  function isSchemaEngineImport(source) {
56
59
  return typeof source === "string" && source.startsWith("@webpresso/schema/engine/");
57
60
  }
@@ -147,6 +150,16 @@ const noForbiddenPackageImports = {
147
150
  function checkImport(source, node) {
148
151
  if (typeof source !== "string")
149
152
  return;
153
+ // Agent-kit SEA / offline compose — ban before monorepo platform allow rules.
154
+ // Consumers still get this rule via shipped oxlintrc; monorepo apps do not match
155
+ // isAgentKitSeaTreeFile so public schema imports remain allowed there.
156
+ if (isAgentKitSeaTreeFile(filename) && isSeaForbiddenPackageImport(source)) {
157
+ context.report({
158
+ node,
159
+ message: SEA_FORBIDDEN_IMPORT_MESSAGE,
160
+ });
161
+ return;
162
+ }
150
163
  if (isPlatformAppFile(filename) &&
151
164
  isSchemaEngineImport(source) &&
152
165
  source !== "@webpresso/schema/engine/api") {
@@ -1,2 +1,2 @@
1
- import { config } from "./index.js";
1
+ import { config } from "@webpresso/agent-config/oxlint";
2
2
  export default config;
@@ -1,4 +1,3 @@
1
- import { config } from "./index.js";
2
- // Consumer repos can use the same shape from the public subpath:
3
- // import { config } from 'webpresso/oxlint'
1
+ import { config } from "@webpresso/agent-config/oxlint";
2
+ // Shape parity for folded config consumers (agent-config is the SSOT).
4
3
  export default config;
@@ -1,16 +1,13 @@
1
1
  /**
2
2
  * Compiled plugin module basenames shipped next to the generated oxlintrc.json.
3
- * Kept in lockstep with the plugin set in `index.ts` (guarded by the parity
4
- * test in `oxlintrc.test.ts`, which asserts one entry per registered plugin).
3
+ * Must match agent-config policy plugins (guarded by vendor + parity tests).
5
4
  */
6
5
  export declare const OXLINT_PLUGIN_BASENAMES: readonly ["code-safety", "foundation-purity", "graphql-conventions", "import-hygiene", "monorepo-paths", "query-patterns", "testing-quality", "tier-boundaries"];
7
6
  /** jsPlugins specifiers, sibling-relative to the shipped oxlintrc.json. */
8
7
  export declare const OXLINT_JS_PLUGIN_FILES: readonly string[];
9
8
  /**
10
9
  * Standard ignore patterns for every webpresso consumer: build output, vendored
11
- * deps, generated reports, and the regenerated agent-surface directories. These
12
- * are project-relative. Truly repo-specific extras belong in a consumer-local
13
- * `.oxlintignore`, never here.
10
+ * deps, generated reports, and the regenerated agent-surface directories.
14
11
  */
15
12
  export declare const STANDARD_IGNORE_PATTERNS: readonly string[];
16
13
  export interface ResolvedOxlintRc {
@@ -18,9 +15,10 @@ export interface ResolvedOxlintRc {
18
15
  readonly rules: Readonly<Record<string, "error">>;
19
16
  readonly ignorePatterns: readonly string[];
20
17
  }
18
+ /** Rule map from agent-config SSOT (error severity for inject). */
19
+ export declare const rules: Readonly<Record<string, "error">>;
21
20
  /**
22
21
  * Build the resolved oxlint config object that ships as `oxlintrc.json`. Pure:
23
- * the build-time generator serializes this return value verbatim, and the
24
- * parity test asserts it against the live `rules`/`plugins` exports.
22
+ * the build-time generator serializes this return value verbatim.
25
23
  */
26
24
  export declare function buildOxlintrc(): ResolvedOxlintRc;
@@ -1,26 +1,24 @@
1
1
  /**
2
2
  * Resolved, consumer-ready oxlint configuration (Tier-1 DRY model).
3
3
  *
4
- * agent-kit ships ONE resolved `.oxlintrc.json` — generated from this builder
5
- * at build time into `dist/esm/config/oxlint/oxlintrc.json` — and `wp lint`
6
- * points oxlint at it via `--config`. Consumers therefore carry no
7
- * `oxlint.config.ts` and no `oxlint` dependency; the linter version, plugins,
8
- * rules, and standard ignores are all gated to @webpresso/agent-kit.
4
+ * agent-kit ships ONE resolved `.oxlintrc.json` — generated at build time into
5
+ * `dist/esm/config/oxlint/oxlintrc.json` — and `wp lint` points oxlint at it via
6
+ * `--config` for consumers without a local oxlint config.
9
7
  *
10
- * Two oxlint resolution facts (verified against oxlint 1.67) make this work:
11
- * - `jsPlugins` are resolved relative to the CONFIG FILE's directory, so the
12
- * specifiers below are sibling-relative (`./<plugin>.js`) to the shipped JSON
13
- * zero package-resolution machinery, no dependency on @webpresso/agent-kit
14
- * being resolvable from the config's location.
15
- * - `ignorePatterns` are applied relative to the LINTED project (cwd), not the
16
- * config-file directory, so `dist`/`node_modules`/etc. ignore the consumer's
17
- * tree even though the config lives inside node_modules.
8
+ * Plugin *bodies* are authored in `@webpresso/agent-config/oxlint/*` (consumer
9
+ * SSOT). Build vendors compiled sibling `.js` next to oxlintrc.json so inject
10
+ * needs no runtime agent-config dependency. Monorepos with their own lint
11
+ * config load `@webpresso/agent-config/oxlint/*` package names directly.
12
+ *
13
+ * Two oxlint resolution facts (verified against oxlint 1.67) make inject work:
14
+ * - `jsPlugins` are resolved relative to the CONFIG FILE's directory
15
+ * (`./<plugin>.js` siblings of the shipped JSON).
16
+ * - `ignorePatterns` apply relative to the LINTED project (cwd).
18
17
  */
19
- import { rules } from "./index.js";
18
+ import { rules as agentConfigRules } from "@webpresso/agent-config/oxlint";
20
19
  /**
21
20
  * Compiled plugin module basenames shipped next to the generated oxlintrc.json.
22
- * Kept in lockstep with the plugin set in `index.ts` (guarded by the parity
23
- * test in `oxlintrc.test.ts`, which asserts one entry per registered plugin).
21
+ * Must match agent-config policy plugins (guarded by vendor + parity tests).
24
22
  */
25
23
  export const OXLINT_PLUGIN_BASENAMES = [
26
24
  "code-safety",
@@ -36,9 +34,7 @@ export const OXLINT_PLUGIN_BASENAMES = [
36
34
  export const OXLINT_JS_PLUGIN_FILES = OXLINT_PLUGIN_BASENAMES.map((name) => `./${name}.js`);
37
35
  /**
38
36
  * Standard ignore patterns for every webpresso consumer: build output, vendored
39
- * deps, generated reports, and the regenerated agent-surface directories. These
40
- * are project-relative. Truly repo-specific extras belong in a consumer-local
41
- * `.oxlintignore`, never here.
37
+ * deps, generated reports, and the regenerated agent-surface directories.
42
38
  */
43
39
  export const STANDARD_IGNORE_PATTERNS = [
44
40
  "dist",
@@ -53,10 +49,11 @@ export const STANDARD_IGNORE_PATTERNS = [
53
49
  ".opencode",
54
50
  ".runtime",
55
51
  ];
52
+ /** Rule map from agent-config SSOT (error severity for inject). */
53
+ export const rules = agentConfigRules;
56
54
  /**
57
55
  * Build the resolved oxlint config object that ships as `oxlintrc.json`. Pure:
58
- * the build-time generator serializes this return value verbatim, and the
59
- * parity test asserts it against the live `rules`/`plugins` exports.
56
+ * the build-time generator serializes this return value verbatim.
60
57
  */
61
58
  export function buildOxlintrc() {
62
59
  return {
@@ -0,0 +1,53 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * Shared path classifiers for webpresso oxlint policy plugins.
4
+ * Pure functions only — no AST. Consumers resolve plugins from
5
+ * `@webpresso/agent-config/oxlint/*`; these markers must match real trees.
6
+ */
7
+ /** Normalize Windows paths for substring role checks. */
8
+ export function normalizeFilename(filename) {
9
+ return typeof filename === "string" ? filename.replaceAll("\\", "/") : "";
10
+ }
11
+ /**
12
+ * Offline / SEA-shaped agent-kit surfaces (compose + UI MCP tools).
13
+ * Monorepo apps never use these path segments.
14
+ */
15
+ export function isAgentKitSeaTreeFile(filename) {
16
+ const n = normalizeFilename(filename);
17
+ if (n.includes("/node_modules/"))
18
+ return false;
19
+ return n.includes("/src/compose/") || n.includes("/src/mcp/tools/wp-ui-");
20
+ }
21
+ /** Platform web apps: real monorepo layout + legacy `/apps/web/`. */
22
+ export function isPlatformWebFile(filename) {
23
+ const n = normalizeFilename(filename);
24
+ if (n.includes("/node_modules/"))
25
+ return false;
26
+ return n.includes("/apps/platform/web/") || n.includes("/apps/web/");
27
+ }
28
+ /** Platform workers: real monorepo layout + legacy `/apps/workers/`. */
29
+ export function isPlatformWorkerFile(filename) {
30
+ const n = normalizeFilename(filename);
31
+ if (n.includes("/node_modules/"))
32
+ return false;
33
+ return n.includes("/apps/platform/workers/") || n.includes("/apps/workers/");
34
+ }
35
+ /** Platform apps (web or worker) for import-hygiene schema-surface rules. */
36
+ export function isPlatformAppFile(filename) {
37
+ return isPlatformWebFile(filename) || isPlatformWorkerFile(filename);
38
+ }
39
+ /**
40
+ * Client UI surfaces for GraphQL/query-pattern rules.
41
+ * Real monorepo: apps/platform/web/.../app/; legacy apps/web/.../app/.
42
+ */
43
+ export function isWebAppSurface(filename) {
44
+ const n = normalizeFilename(filename);
45
+ if (n.includes("/node_modules/"))
46
+ return false;
47
+ if (!n.includes("/app/"))
48
+ return false;
49
+ return n.includes("/apps/platform/web/") || n.includes("/apps/web/");
50
+ }
51
+ export function isSdkPackageFile(filename) {
52
+ return normalizeFilename(filename).includes("/packages/sdk/");
53
+ }
@@ -1,8 +1,6 @@
1
1
  // @ts-nocheck
2
+ import { isWebAppSurface, normalizeFilename } from "./path-roles.js";
2
3
  const QUERY_HOOK_NAMES = new Set(["useQuery", "useSuspenseQuery", "useInfiniteQuery"]);
3
- function normalizeFilename(filename) {
4
- return typeof filename === "string" ? filename.replaceAll("\\", "/") : "";
5
- }
6
4
  function getFilename(context) {
7
5
  if (typeof context.getFilename === "function") {
8
6
  return normalizeFilename(context.getFilename());
@@ -15,9 +13,8 @@ function isClientQuerySurface(filename) {
15
13
  return false;
16
14
  if (normalized.includes("/.webpresso/generated/"))
17
15
  return false;
18
- const isWebAppSurface = normalized.includes("/apps/web/") && normalized.includes("/app/");
19
16
  const isFeatureSurface = normalized.includes("/packages/feature/") && normalized.includes("/src/");
20
- return isWebAppSurface || isFeatureSurface;
17
+ return isWebAppSurface(normalized) || isFeatureSurface;
21
18
  }
22
19
  function getCalleeName(callee) {
23
20
  if (!callee)
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Blueprint exec run ledger: durable job ↔ PTY session ↔ blueprint attribution.
3
+ *
4
+ * Why this exists separately from the launch ledger: a launch handle is
5
+ * single-use and is consumed the moment Rust claims it, and the PTY reaper
6
+ * reports that *a* session ended but not which blueprint it belonged to.
7
+ * Neither can answer "what is this terminal running?" after a UI restart. A
8
+ * job id that outlives both can.
9
+ *
10
+ * Rows are deliberately env-free and argv-free: this ledger is readable by the
11
+ * webview, so it must never carry launch material.
12
+ */
13
+ export declare const BLUEPRINT_EXEC_JOB_STATES: readonly ["preparing", "running", "terminal"];
14
+ export type BlueprintExecJobState = (typeof BLUEPRINT_EXEC_JOB_STATES)[number];
15
+ export type BlueprintExecJob = {
16
+ readonly jobId: string;
17
+ readonly slug: string;
18
+ readonly taskId: string | null;
19
+ /** Opaque single-use launch handle; never the composed argv or env. */
20
+ readonly launchHandle: string;
21
+ readonly sessionId: number | null;
22
+ readonly startedAt: number;
23
+ readonly state: BlueprintExecJobState;
24
+ };
25
+ export type RegisterBlueprintExecJobInput = {
26
+ readonly slug: string;
27
+ readonly taskId: string | null;
28
+ readonly launchHandle: string;
29
+ };
30
+ /**
31
+ * Bounded, insertion-ordered job store.
32
+ *
33
+ * Complexity: `register`, `bindSession`, `markTerminal`, and `get` are all
34
+ * Map-keyed O(1). Eviction is O(1) too — terminal job ids are appended to a
35
+ * FIFO queue as they terminate, so making room pops the front instead of
36
+ * rescanning the map. `list` is O(#jobs) over a capped map.
37
+ */
38
+ /**
39
+ * Construction options. Shared by the class and {@link createBlueprintExecLedger}
40
+ * so the factory's public surface cannot drift away from what the constructor
41
+ * actually accepts.
42
+ */
43
+ export type BlueprintExecLedgerOptions = {
44
+ readonly maxJobs?: number;
45
+ readonly staleUnboundMs?: number;
46
+ /** Injectable clock (tests). */
47
+ readonly now?: () => number;
48
+ };
49
+ export declare class BlueprintExecLedger {
50
+ private readonly byJobId;
51
+ /** FIFO of job ids that reached `terminal`, oldest first. */
52
+ private readonly terminalOrder;
53
+ private readonly maxJobs;
54
+ private readonly staleUnboundMs;
55
+ private readonly now;
56
+ constructor(options?: BlueprintExecLedgerOptions);
57
+ /** Evict the oldest terminal job. O(1) amortized via the FIFO queue. */
58
+ private evictOneTerminal;
59
+ /**
60
+ * Last-resort reclaim: the oldest job that never bound a session and whose
61
+ * launch handle can no longer be claimed.
62
+ *
63
+ * Without this, a daemon that only ever prepared launches which were never
64
+ * claimed (a crashing Rust peer) would wedge at the cap forever, because
65
+ * nothing would ever transition those jobs to terminal.
66
+ *
67
+ * O(#jobs) and only on the eviction path when the terminal queue is empty.
68
+ */
69
+ private evictOneStaleUnbound;
70
+ register(input: RegisterBlueprintExecJobInput): {
71
+ readonly jobId: string;
72
+ };
73
+ /**
74
+ * Bind the spawned PTY session to a job. Rust-only caller.
75
+ *
76
+ * Single-assignment: a second bind for the same job is rejected so a
77
+ * compromised or buggy peer cannot re-point an existing job at another
78
+ * session.
79
+ */
80
+ bindSession(jobId: string, sessionId: number): BlueprintExecJob;
81
+ markTerminal(jobId: string): BlueprintExecJob | null;
82
+ get(jobId: string): BlueprintExecJob | undefined;
83
+ list(): readonly BlueprintExecJob[];
84
+ size(): number;
85
+ }
86
+ export declare function createBlueprintExecLedger(options?: BlueprintExecLedgerOptions): BlueprintExecLedger;