@ambitresearch/genie 1.3.1

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 (301) hide show
  1. package/README.md +15 -0
  2. package/dist/auth/bearer.d.ts +49 -0
  3. package/dist/auth/bearer.d.ts.map +1 -0
  4. package/dist/auth/bearer.js +159 -0
  5. package/dist/auth/bearer.js.map +1 -0
  6. package/dist/auth/oauth/authorize.d.ts +19 -0
  7. package/dist/auth/oauth/authorize.d.ts.map +1 -0
  8. package/dist/auth/oauth/authorize.js +111 -0
  9. package/dist/auth/oauth/authorize.js.map +1 -0
  10. package/dist/auth/oauth/config.d.ts +10 -0
  11. package/dist/auth/oauth/config.d.ts.map +1 -0
  12. package/dist/auth/oauth/config.js +16 -0
  13. package/dist/auth/oauth/config.js.map +1 -0
  14. package/dist/auth/oauth/dcr.d.ts +15 -0
  15. package/dist/auth/oauth/dcr.d.ts.map +1 -0
  16. package/dist/auth/oauth/dcr.js +38 -0
  17. package/dist/auth/oauth/dcr.js.map +1 -0
  18. package/dist/auth/oauth/jwt.d.ts +13 -0
  19. package/dist/auth/oauth/jwt.d.ts.map +1 -0
  20. package/dist/auth/oauth/jwt.js +46 -0
  21. package/dist/auth/oauth/jwt.js.map +1 -0
  22. package/dist/auth/oauth/metadata.d.ts +9 -0
  23. package/dist/auth/oauth/metadata.d.ts.map +1 -0
  24. package/dist/auth/oauth/metadata.js +19 -0
  25. package/dist/auth/oauth/metadata.js.map +1 -0
  26. package/dist/auth/oauth/router.d.ts +32 -0
  27. package/dist/auth/oauth/router.d.ts.map +1 -0
  28. package/dist/auth/oauth/router.js +159 -0
  29. package/dist/auth/oauth/router.js.map +1 -0
  30. package/dist/auth/oauth/store.d.ts +55 -0
  31. package/dist/auth/oauth/store.d.ts.map +1 -0
  32. package/dist/auth/oauth/store.js +63 -0
  33. package/dist/auth/oauth/store.js.map +1 -0
  34. package/dist/auth/oauth/token.d.ts +21 -0
  35. package/dist/auth/oauth/token.d.ts.map +1 -0
  36. package/dist/auth/oauth/token.js +77 -0
  37. package/dist/auth/oauth/token.js.map +1 -0
  38. package/dist/auth/oidc/group-policy.d.ts +43 -0
  39. package/dist/auth/oidc/group-policy.d.ts.map +1 -0
  40. package/dist/auth/oidc/group-policy.js +54 -0
  41. package/dist/auth/oidc/group-policy.js.map +1 -0
  42. package/dist/auth/oidc/verifier.d.ts +42 -0
  43. package/dist/auth/oidc/verifier.d.ts.map +1 -0
  44. package/dist/auth/oidc/verifier.js +145 -0
  45. package/dist/auth/oidc/verifier.js.map +1 -0
  46. package/dist/auth/token-cli.d.ts +9 -0
  47. package/dist/auth/token-cli.d.ts.map +1 -0
  48. package/dist/auth/token-cli.js +98 -0
  49. package/dist/auth/token-cli.js.map +1 -0
  50. package/dist/cli.d.ts +3 -0
  51. package/dist/cli.d.ts.map +1 -0
  52. package/dist/cli.js +149 -0
  53. package/dist/cli.js.map +1 -0
  54. package/dist/config/redact.d.ts +20 -0
  55. package/dist/config/redact.d.ts.map +1 -0
  56. package/dist/config/redact.js +77 -0
  57. package/dist/config/redact.js.map +1 -0
  58. package/dist/config/secrets.d.ts +100 -0
  59. package/dist/config/secrets.d.ts.map +1 -0
  60. package/dist/config/secrets.js +130 -0
  61. package/dist/config/secrets.js.map +1 -0
  62. package/dist/framework/html.d.ts +103 -0
  63. package/dist/framework/html.d.ts.map +1 -0
  64. package/dist/framework/html.js +271 -0
  65. package/dist/framework/html.js.map +1 -0
  66. package/dist/framework/interface.d.ts +130 -0
  67. package/dist/framework/interface.d.ts.map +1 -0
  68. package/dist/framework/interface.js +112 -0
  69. package/dist/framework/interface.js.map +1 -0
  70. package/dist/framework/react.d.ts +133 -0
  71. package/dist/framework/react.d.ts.map +1 -0
  72. package/dist/framework/react.js +243 -0
  73. package/dist/framework/react.js.map +1 -0
  74. package/dist/framework/vue.d.ts +99 -0
  75. package/dist/framework/vue.d.ts.map +1 -0
  76. package/dist/framework/vue.js +375 -0
  77. package/dist/framework/vue.js.map +1 -0
  78. package/dist/index.d.ts +3 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +3 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/llm/client.d.ts +81 -0
  83. package/dist/llm/client.d.ts.map +1 -0
  84. package/dist/llm/client.js +141 -0
  85. package/dist/llm/client.js.map +1 -0
  86. package/dist/llm/component-response.d.ts +111 -0
  87. package/dist/llm/component-response.d.ts.map +1 -0
  88. package/dist/llm/component-response.js +167 -0
  89. package/dist/llm/component-response.js.map +1 -0
  90. package/dist/llm/generated-files.d.ts +10 -0
  91. package/dist/llm/generated-files.d.ts.map +1 -0
  92. package/dist/llm/generated-files.js +26 -0
  93. package/dist/llm/generated-files.js.map +1 -0
  94. package/dist/llm/prompts/CHANGELOG.md +70 -0
  95. package/dist/llm/prompts/generate-component.system.md +99 -0
  96. package/dist/llm/prompts/refine-component.system.md +112 -0
  97. package/dist/llm/prompts.d.ts +66 -0
  98. package/dist/llm/prompts.d.ts.map +1 -0
  99. package/dist/llm/prompts.js +78 -0
  100. package/dist/llm/prompts.js.map +1 -0
  101. package/dist/llm/retry.d.ts +183 -0
  102. package/dist/llm/retry.d.ts.map +1 -0
  103. package/dist/llm/retry.js +475 -0
  104. package/dist/llm/retry.js.map +1 -0
  105. package/dist/llm/schema.d.ts +129 -0
  106. package/dist/llm/schema.d.ts.map +1 -0
  107. package/dist/llm/schema.js +147 -0
  108. package/dist/llm/schema.js.map +1 -0
  109. package/dist/llm/validate.d.ts +107 -0
  110. package/dist/llm/validate.d.ts.map +1 -0
  111. package/dist/llm/validate.js +174 -0
  112. package/dist/llm/validate.js.map +1 -0
  113. package/dist/manifest/compiler.d.ts +112 -0
  114. package/dist/manifest/compiler.d.ts.map +1 -0
  115. package/dist/manifest/compiler.js +306 -0
  116. package/dist/manifest/compiler.js.map +1 -0
  117. package/dist/manifest/ensure.d.ts +46 -0
  118. package/dist/manifest/ensure.d.ts.map +1 -0
  119. package/dist/manifest/ensure.js +49 -0
  120. package/dist/manifest/ensure.js.map +1 -0
  121. package/dist/manifest/index.d.ts +13 -0
  122. package/dist/manifest/index.d.ts.map +1 -0
  123. package/dist/manifest/index.js +13 -0
  124. package/dist/manifest/index.js.map +1 -0
  125. package/dist/middleware/plan-guard.d.ts +167 -0
  126. package/dist/middleware/plan-guard.d.ts.map +1 -0
  127. package/dist/middleware/plan-guard.js +190 -0
  128. package/dist/middleware/plan-guard.js.map +1 -0
  129. package/dist/plans/index.d.ts +71 -0
  130. package/dist/plans/index.d.ts.map +1 -0
  131. package/dist/plans/index.js +252 -0
  132. package/dist/plans/index.js.map +1 -0
  133. package/dist/schemas/component.schema.json +114 -0
  134. package/dist/server.d.ts +96 -0
  135. package/dist/server.d.ts.map +1 -0
  136. package/dist/server.js +258 -0
  137. package/dist/server.js.map +1 -0
  138. package/dist/store/empty-manifest.d.ts +58 -0
  139. package/dist/store/empty-manifest.d.ts.map +1 -0
  140. package/dist/store/empty-manifest.js +59 -0
  141. package/dist/store/empty-manifest.js.map +1 -0
  142. package/dist/store/git-host.d.ts +120 -0
  143. package/dist/store/git-host.d.ts.map +1 -0
  144. package/dist/store/git-host.js +796 -0
  145. package/dist/store/git-host.js.map +1 -0
  146. package/dist/store/index.d.ts +5 -0
  147. package/dist/store/index.d.ts.map +1 -0
  148. package/dist/store/index.js +4 -0
  149. package/dist/store/index.js.map +1 -0
  150. package/dist/store/interface.d.ts +322 -0
  151. package/dist/store/interface.d.ts.map +1 -0
  152. package/dist/store/interface.js +100 -0
  153. package/dist/store/interface.js.map +1 -0
  154. package/dist/store/kit-files.d.ts +88 -0
  155. package/dist/store/kit-files.d.ts.map +1 -0
  156. package/dist/store/kit-files.js +199 -0
  157. package/dist/store/kit-files.js.map +1 -0
  158. package/dist/store/local.d.ts +70 -0
  159. package/dist/store/local.d.ts.map +1 -0
  160. package/dist/store/local.js +651 -0
  161. package/dist/store/local.js.map +1 -0
  162. package/dist/store/manifest.d.ts +44 -0
  163. package/dist/store/manifest.d.ts.map +1 -0
  164. package/dist/store/manifest.js +116 -0
  165. package/dist/store/manifest.js.map +1 -0
  166. package/dist/store/viewer-assets.d.ts +20 -0
  167. package/dist/store/viewer-assets.d.ts.map +1 -0
  168. package/dist/store/viewer-assets.js +118 -0
  169. package/dist/store/viewer-assets.js.map +1 -0
  170. package/dist/sync/anchor.d.ts +125 -0
  171. package/dist/sync/anchor.d.ts.map +1 -0
  172. package/dist/sync/anchor.js +210 -0
  173. package/dist/sync/anchor.js.map +1 -0
  174. package/dist/sync/index.d.ts +15 -0
  175. package/dist/sync/index.d.ts.map +1 -0
  176. package/dist/sync/index.js +15 -0
  177. package/dist/sync/index.js.map +1 -0
  178. package/dist/sync/orchestrator.d.ts +160 -0
  179. package/dist/sync/orchestrator.d.ts.map +1 -0
  180. package/dist/sync/orchestrator.js +288 -0
  181. package/dist/sync/orchestrator.js.map +1 -0
  182. package/dist/tools/bind_kit.d.ts +29 -0
  183. package/dist/tools/bind_kit.d.ts.map +1 -0
  184. package/dist/tools/bind_kit.js +70 -0
  185. package/dist/tools/bind_kit.js.map +1 -0
  186. package/dist/tools/conjure.d.ts +141 -0
  187. package/dist/tools/conjure.d.ts.map +1 -0
  188. package/dist/tools/conjure.js +655 -0
  189. package/dist/tools/conjure.js.map +1 -0
  190. package/dist/tools/conjure_screen.d.ts +174 -0
  191. package/dist/tools/conjure_screen.d.ts.map +1 -0
  192. package/dist/tools/conjure_screen.js +458 -0
  193. package/dist/tools/conjure_screen.js.map +1 -0
  194. package/dist/tools/create_kit.d.ts +32 -0
  195. package/dist/tools/create_kit.d.ts.map +1 -0
  196. package/dist/tools/create_kit.js +131 -0
  197. package/dist/tools/create_kit.js.map +1 -0
  198. package/dist/tools/create_project.d.ts +267 -0
  199. package/dist/tools/create_project.d.ts.map +1 -0
  200. package/dist/tools/create_project.js +546 -0
  201. package/dist/tools/create_project.js.map +1 -0
  202. package/dist/tools/delete_files.d.ts +93 -0
  203. package/dist/tools/delete_files.d.ts.map +1 -0
  204. package/dist/tools/delete_files.js +276 -0
  205. package/dist/tools/delete_files.js.map +1 -0
  206. package/dist/tools/delete_project.d.ts +43 -0
  207. package/dist/tools/delete_project.d.ts.map +1 -0
  208. package/dist/tools/delete_project.js +118 -0
  209. package/dist/tools/delete_project.js.map +1 -0
  210. package/dist/tools/get_kit.d.ts +28 -0
  211. package/dist/tools/get_kit.d.ts.map +1 -0
  212. package/dist/tools/get_kit.js +95 -0
  213. package/dist/tools/get_kit.js.map +1 -0
  214. package/dist/tools/get_project.d.ts +37 -0
  215. package/dist/tools/get_project.d.ts.map +1 -0
  216. package/dist/tools/get_project.js +71 -0
  217. package/dist/tools/get_project.js.map +1 -0
  218. package/dist/tools/list_components.d.ts +42 -0
  219. package/dist/tools/list_components.d.ts.map +1 -0
  220. package/dist/tools/list_components.js +125 -0
  221. package/dist/tools/list_components.js.map +1 -0
  222. package/dist/tools/list_files.d.ts +32 -0
  223. package/dist/tools/list_files.d.ts.map +1 -0
  224. package/dist/tools/list_files.js +109 -0
  225. package/dist/tools/list_files.js.map +1 -0
  226. package/dist/tools/list_kits.d.ts +14 -0
  227. package/dist/tools/list_kits.d.ts.map +1 -0
  228. package/dist/tools/list_kits.js +41 -0
  229. package/dist/tools/list_kits.js.map +1 -0
  230. package/dist/tools/list_projects.d.ts +23 -0
  231. package/dist/tools/list_projects.d.ts.map +1 -0
  232. package/dist/tools/list_projects.js +66 -0
  233. package/dist/tools/list_projects.js.map +1 -0
  234. package/dist/tools/plan.d.ts +16 -0
  235. package/dist/tools/plan.d.ts.map +1 -0
  236. package/dist/tools/plan.js +146 -0
  237. package/dist/tools/plan.js.map +1 -0
  238. package/dist/tools/preview.d.ts +289 -0
  239. package/dist/tools/preview.d.ts.map +1 -0
  240. package/dist/tools/preview.js +672 -0
  241. package/dist/tools/preview.js.map +1 -0
  242. package/dist/tools/read_file.d.ts +40 -0
  243. package/dist/tools/read_file.d.ts.map +1 -0
  244. package/dist/tools/read_file.js +114 -0
  245. package/dist/tools/read_file.js.map +1 -0
  246. package/dist/tools/refine.d.ts +220 -0
  247. package/dist/tools/refine.d.ts.map +1 -0
  248. package/dist/tools/refine.js +501 -0
  249. package/dist/tools/refine.js.map +1 -0
  250. package/dist/tools/validate.d.ts +74 -0
  251. package/dist/tools/validate.d.ts.map +1 -0
  252. package/dist/tools/validate.js +224 -0
  253. package/dist/tools/validate.js.map +1 -0
  254. package/dist/tools/write_files.d.ts +158 -0
  255. package/dist/tools/write_files.d.ts.map +1 -0
  256. package/dist/tools/write_files.js +541 -0
  257. package/dist/tools/write_files.js.map +1 -0
  258. package/dist/transport.d.ts +77 -0
  259. package/dist/transport.d.ts.map +1 -0
  260. package/dist/transport.js +448 -0
  261. package/dist/transport.js.map +1 -0
  262. package/dist/ui/card-asset-broker.d.ts +42 -0
  263. package/dist/ui/card-asset-broker.d.ts.map +1 -0
  264. package/dist/ui/card-asset-broker.js +479 -0
  265. package/dist/ui/card-asset-broker.js.map +1 -0
  266. package/dist/ui/grid-resource.d.ts +252 -0
  267. package/dist/ui/grid-resource.d.ts.map +1 -0
  268. package/dist/ui/grid-resource.js +680 -0
  269. package/dist/ui/grid-resource.js.map +1 -0
  270. package/dist/ui/viewer-static/index.html +95 -0
  271. package/dist/ui/viewer-static/viewer.css +451 -0
  272. package/dist/ui/viewer-static/viewer.js +1405 -0
  273. package/dist/validate/full-scan.d.ts +87 -0
  274. package/dist/validate/full-scan.d.ts.map +1 -0
  275. package/dist/validate/full-scan.js +299 -0
  276. package/dist/validate/full-scan.js.map +1 -0
  277. package/dist/validate/index.d.ts +15 -0
  278. package/dist/validate/index.d.ts.map +1 -0
  279. package/dist/validate/index.js +18 -0
  280. package/dist/validate/index.js.map +1 -0
  281. package/dist/validate/marker.d.ts +89 -0
  282. package/dist/validate/marker.d.ts.map +1 -0
  283. package/dist/validate/marker.js +87 -0
  284. package/dist/validate/marker.js.map +1 -0
  285. package/dist/validate/phash.d.ts +135 -0
  286. package/dist/validate/phash.d.ts.map +1 -0
  287. package/dist/validate/phash.js +307 -0
  288. package/dist/validate/phash.js.map +1 -0
  289. package/dist/validate/render.d.ts +38 -0
  290. package/dist/validate/render.d.ts.map +1 -0
  291. package/dist/validate/render.js +155 -0
  292. package/dist/validate/render.js.map +1 -0
  293. package/dist/watch/index.d.ts +12 -0
  294. package/dist/watch/index.d.ts.map +1 -0
  295. package/dist/watch/index.js +12 -0
  296. package/dist/watch/index.js.map +1 -0
  297. package/dist/watch/watcher.d.ts +65 -0
  298. package/dist/watch/watcher.d.ts.map +1 -0
  299. package/dist/watch/watcher.js +238 -0
  300. package/dist/watch/watcher.js.map +1 -0
  301. package/package.json +70 -0
@@ -0,0 +1,147 @@
1
+ /**
2
+ * `COMPONENT_SCHEMA` (M2-02) — the JSON Schema `conjure`/`refine` (M2-03/M2-04)
3
+ * demand from the model via `response_format: { type: "json_schema",
4
+ * json_schema: COMPONENT_SCHEMA }`, and that M2-07's Ajv validation pass
5
+ * (`validateComponent`) compiles against.
6
+ *
7
+ * Draft 7 only (AC2): no `anyOf`/`oneOf` discriminator pattern, and the only
8
+ * `$ref` in the whole schema is a single level deep (`manifestEntry.viewport`
9
+ * → `#/definitions/Viewport`, mirroring the RFC §9.20 shared-`$defs` shape).
10
+ * LiteLLM's structured-output passthrough to Anthropic (via tool-use) is the
11
+ * reason to keep nesting shallow — a deep `$ref` chain is exactly the shape
12
+ * that passthrough has been observed not to handle reliably.
13
+ *
14
+ * `as const satisfies JSONSchema7` (AC1) does two jobs at once: `satisfies`
15
+ * runs the object through `@types/json-schema`'s `JSONSchema7` shape so a
16
+ * typo'd keyword (e.g. `additionalProperty` instead of `additionalProperties`)
17
+ * is a compile error, while `as const` preserves the literal types `FromSchema`
18
+ * (AC7) needs to actually infer `ValidatedComponent` below rather than widening
19
+ * every string field to `string`.
20
+ */
21
+ /**
22
+ * AC4 — every `files[].path` must land under `components/<group>/<Name>/`,
23
+ * matching the on-disk layout `write_files` (M1-08) ultimately writes to and
24
+ * the `@genie`-marker registration convention (D-A/D-B). `<group>` is
25
+ * `[a-z0-9-]+` (kebab-case, same shape as the top-level `group` field);
26
+ * `<Name>` is `[A-Z][A-Za-z0-9]+` (PascalCase, same shape as `componentName`);
27
+ * the file's own basename allows the broader `[A-Za-z0-9._-]+` (AC4's own
28
+ * pattern) since it must cover `<Name>.tsx`, `<Name>.d.ts`, `<Name>.prompt.md`,
29
+ * `<Name>.html`, and `meta.json` — five different suffix shapes — rather than
30
+ * repeating `<Name>` a second time in the basename segment.
31
+ */
32
+ const PATH_PATTERN = "^components/[a-z0-9-]+/[A-Z][A-Za-z0-9]+/[A-Za-z0-9._-]+$";
33
+ /**
34
+ * AC5 — at least one `files[]` entry must be a `<Name>.html` file (the
35
+ * `@genie`-marker carrier M3-01 later validates post-hoc). `contains` is the
36
+ * Draft-7 keyword for "at least one array item matches this sub-schema" — it
37
+ * does not require every item to match, unlike `items`. The pattern captures
38
+ * the directory's `<Name>` segment and backreferences it against the
39
+ * filename (`([A-Z][A-Za-z0-9]+)/\1\.html$`), so `Button/Button.html`
40
+ * matches but a mismatched `Button/Wrong.html` does not — enforcing the same
41
+ * `<Name>/<Name>.html` self-consistency the RFC's file-layout convention
42
+ * assumes throughout (§7.3/§7.4/§9.10). It deliberately does NOT also check
43
+ * the file's `content` for the literal `@genie` marker text — that
44
+ * cross-field, regex-on-a-sibling-field check is exactly what M2-07's
45
+ * `validateComponent` does as a second pass after schema validation (this
46
+ * issue's AC5 note: "validated post-hoc by M3-01, not by the schema").
47
+ */
48
+ const HTML_FILE_CONTAINS = {
49
+ type: "object",
50
+ properties: {
51
+ path: {
52
+ type: "string",
53
+ pattern: "^components/[a-z0-9-]+/([A-Z][A-Za-z0-9]{1,63})/\\1\\.html$",
54
+ },
55
+ },
56
+ };
57
+ export const COMPONENT_SCHEMA = {
58
+ $schema: "http://json-schema.org/draft-07/schema#",
59
+ $id: "https://genie.dev/schema/component.schema.json",
60
+ title: "GenieComponent",
61
+ description: "The file set + manifest metadata conjure/refine demand from the configured " +
62
+ "LLM endpoint via response_format.json_schema (M2-02).",
63
+ type: "object",
64
+ additionalProperties: false,
65
+ // AC3 — top-level shape: { componentName, group, files, manifestEntry }.
66
+ required: ["componentName", "group", "files", "manifestEntry"],
67
+ // The only $ref in this schema, one level deep (AC2) — mirrors the shared
68
+ // `Viewport` $def in RFC §9.20 rather than inlining width/height twice.
69
+ definitions: {
70
+ Viewport: {
71
+ type: "object",
72
+ additionalProperties: false,
73
+ required: ["width", "height"],
74
+ properties: {
75
+ width: { type: "integer", minimum: 1, maximum: 4096 },
76
+ height: { type: "integer", minimum: 1, maximum: 4096 },
77
+ },
78
+ },
79
+ },
80
+ properties: {
81
+ componentName: {
82
+ type: "string",
83
+ description: 'PascalCase component name, e.g. "Button".',
84
+ // Same shape as the equivalent `name` field in RFC §7.1/§7.5
85
+ // (manifest.json cards / the RFC's own COMPONENT_SCHEMA draft) — a
86
+ // 2-64 char PascalCase identifier. Minimum length is 2 (not 1) so a
87
+ // single-letter name like "B" cannot slip past `componentName` only to
88
+ // be trapped later by the `files[].path` pattern's `[A-Z][A-Za-z0-9]+`
89
+ // `<Name>` segment (which itself requires min length 2) — the two
90
+ // constraints move together.
91
+ pattern: "^[A-Z][A-Za-z0-9]{1,63}$",
92
+ },
93
+ group: {
94
+ type: "string",
95
+ description: 'Kebab-case UI-kit group/category, e.g. "actions".',
96
+ pattern: "^[a-z0-9-]{1,32}$",
97
+ },
98
+ files: {
99
+ type: "array",
100
+ description: "The component's file set (e.g. <Name>.jsx, <Name>.tsx, <Name>.d.ts, " +
101
+ "<Name>.prompt.md, <Name>.html, meta.json) — at least one must be a " +
102
+ "<Name>.html preview file (AC5).",
103
+ minItems: 1,
104
+ maxItems: 12,
105
+ contains: HTML_FILE_CONTAINS,
106
+ items: {
107
+ type: "object",
108
+ additionalProperties: false,
109
+ required: ["path", "content", "mimeType"],
110
+ properties: {
111
+ path: {
112
+ type: "string",
113
+ description: "Kit-relative path under components/<group>/<Name>/.",
114
+ pattern: PATH_PATTERN,
115
+ },
116
+ content: {
117
+ type: "string",
118
+ description: "Full file contents (AC5: an <Name>.html entry's content " +
119
+ "must begin with the @genie marker — checked post-hoc by M3-01/M2-07, " +
120
+ "not by this schema).",
121
+ minLength: 1,
122
+ maxLength: 65536,
123
+ },
124
+ mimeType: {
125
+ type: "string",
126
+ description: 'MIME type of `content`, e.g. "text/html".',
127
+ pattern: "^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$",
128
+ },
129
+ },
130
+ },
131
+ },
132
+ manifestEntry: {
133
+ type: "object",
134
+ description: "Metadata the manifest compiler (M3-03) needs to add this card to " +
135
+ ".genie/manifest.json without re-deriving it from the files themselves.",
136
+ additionalProperties: false,
137
+ // AC6 — viewport is required; subtitle/tags are optional.
138
+ required: ["viewport"],
139
+ properties: {
140
+ viewport: { $ref: "#/definitions/Viewport" },
141
+ subtitle: { type: "string", maxLength: 256 },
142
+ tags: { type: "array", items: { type: "string" }, maxItems: 16 },
143
+ },
144
+ },
145
+ },
146
+ };
147
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/llm/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * M2-07 — strict Ajv validation for the structured LLM output that conjure
3
+ * (M2-03) and refine (M2-04) receive from the configured OpenAI-compatible
4
+ * endpoint via `response_format: { type: "json_schema", ... }`.
5
+ *
6
+ * The single public entry point is {@link validateComponent}. It's called
7
+ * once per LLM completion, on the deserialised JSON payload the client got
8
+ * back. On success it returns the payload typed as {@link ValidatedComponent}
9
+ * (a compile-time re-typing — no reshape at runtime). On failure it throws
10
+ * {@link SchemaValidationError} carrying the full Ajv `errors: ErrorObject[]`
11
+ * so the retry path in M2-03/M2-04 can append the failure to the next prompt
12
+ * and give the model exactly one chance to self-correct.
13
+ *
14
+ * Two-pass design (AC3 + AC4):
15
+ * 1. Ajv strict-mode structural validation against `COMPONENT_SCHEMA`
16
+ * (M2-02). Catches missing fields, wrong types, bad path patterns, the
17
+ * "no <Name>.html preview" case, and the `manifestEntry.viewport`
18
+ * requirement.
19
+ * 2. `@genie` first-line marker cross-check on every `<Name>/<Name>.html`
20
+ * preview file the (now shape-valid) payload contains. This is
21
+ * intentionally *not* modelled in the JSON Schema itself — a regex-on-a-
22
+ * sibling-field is exactly the kind of cross-field constraint Draft 7
23
+ * can't express, and pushing it into JSON Schema would force the same
24
+ * shallow-`$ref` shape M2-02 was carefully written to avoid (see
25
+ * `schema.ts` AC2 note).
26
+ *
27
+ * The schema is compiled exactly once, at module load (AC5) — Ajv compilation
28
+ * is measurable per call and every LLM completion goes through this function,
29
+ * so caching pays for itself immediately.
30
+ */
31
+ import { type ErrorObject } from "ajv";
32
+ import { type ValidatedComponent } from "./schema.js";
33
+ export type { ValidatedComponent } from "./schema.js";
34
+ export type { ErrorObject } from "ajv";
35
+ /**
36
+ * AC4 — the canonical `@genie` first-line marker regex from
37
+ * Every generated `<Name>.html` preview
38
+ * must open with a comment matching this pattern so the manifest compiler
39
+ * (M3-03) and the validate tool (M3-04) can register / verify the card
40
+ * without re-parsing the component's JSX.
41
+ *
42
+ * M3-01 (DRO-257) landed the single source of truth for this pattern at
43
+ * `packages/server/src/validate/marker.ts`'s `MARKER_REGEX`, imported here
44
+ * via the `validate/index.ts` public barrel (Copilot review, PR #142) rather
45
+ * than reaching into `marker.js` directly, so this call site tracks the
46
+ * barrel's stable surface instead of the module's internal file layout.
47
+ * This is now a re-export alias, kept under its original M2-07 name for
48
+ * backwards compatibility with existing consumers (this module's own
49
+ * cross-check below, plus `packages/e2e/test/m2-generation.test.ts`) rather
50
+ * than forcing every call site to rename in the same change that removes
51
+ * the duplicate literal.
52
+ */
53
+ export declare const MARKER_REGEX_M2_07: RegExp;
54
+ /**
55
+ * Same selector as `COMPONENT_SCHEMA.properties.files.items.contains.pattern`
56
+ * — the `<group>/<Name>/<Name>.html` self-consistency shape ("preview file
57
+ * whose basename matches its containing directory"). Kept here as a compiled
58
+ * `RegExp` so the cross-check pass in {@link validateComponent} doesn't
59
+ * re-compile the pattern on every file iteration.
60
+ *
61
+ * The backreference `\1` locks the basename to the same PascalCase segment
62
+ * as the enclosing directory — this is what makes `Button/Wrong.html` fail
63
+ * schema-level AC5 but still lets `Button/Button.html` through. We reuse the
64
+ * exact shape here so the schema's `contains` guarantee (at least one file
65
+ * matches) and this cross-check (every matching file also has the `@genie`
66
+ * marker) can never disagree about which files are "preview files".
67
+ *
68
+ * Exported (Copilot review, PR #136) so consumers outside this module that
69
+ * need to identify "which files are actually preview files" — e.g.
70
+ * `m2-generation.test.ts`'s AC5 assertions — share this exact definition
71
+ * instead of re-deriving a looser one (`files[].path` also legally permits
72
+ * non-preview `.html` basenames like `dark-mode.html` per `schema.ts`'s
73
+ * `PATH_PATTERN`, which a naive `.endsWith(".html")` filter would wrongly
74
+ * subject to the marker rule).
75
+ */
76
+ export declare const NAMED_HTML_PATH: RegExp;
77
+ /**
78
+ * `Error` subclass thrown by {@link validateComponent} on structural or
79
+ * marker-cross-check failure. Callers in M2-03/M2-04 catch this narrowly and
80
+ * append `error.errors` to the next prompt — the retry loop is exactly one
81
+ * round-trip, per DRO-254's "Out of Scope: auto-repair" note.
82
+ *
83
+ * `name` is set explicitly so `error.name === "SchemaValidationError"` works
84
+ * even after ESM module boundaries strip the class identity (defensive
85
+ * against `instanceof` foot-guns in vitest / workers).
86
+ */
87
+ export declare class SchemaValidationError extends Error {
88
+ /** Ajv-style structured errors; always non-empty when this is thrown. */
89
+ readonly errors: ErrorObject[];
90
+ constructor(message: string, errors: ErrorObject[]);
91
+ }
92
+ /**
93
+ * AC1 — the module's sole export contract. Validates `output` against
94
+ * `COMPONENT_SCHEMA` (M2-02) and the `@genie` marker convention (AC4). On
95
+ * success returns `output` cast to {@link ValidatedComponent} — an assertion
96
+ * of type, not a copy: callers get the exact same object identity back so
97
+ * downstream `write_files` (M1-08) can pass it through without an extra
98
+ * allocation per completion.
99
+ *
100
+ * @throws {SchemaValidationError} on any structural or marker failure. The
101
+ * thrown error's `errors` array holds Ajv `ErrorObject`s (schema-level
102
+ * failures) and/or synthetic `ErrorObject`s with `keyword: "@genie-marker"`
103
+ * (marker-level failures). Both live in the same array so M2-03/M2-04's
104
+ * retry prompt can serialise them uniformly.
105
+ */
106
+ export declare function validateComponent(output: unknown): ValidatedComponent;
107
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/llm/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAO,KAAK,WAAW,EAAyB,MAAM,KAAK,CAAC;AAEnE,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGxE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,QAAe,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,QAAiE,CAAC;AAE9F;;;;;;;;;GASG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;CAKnD;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,kBAAkB,CAkErE"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * M2-07 — strict Ajv validation for the structured LLM output that conjure
3
+ * (M2-03) and refine (M2-04) receive from the configured OpenAI-compatible
4
+ * endpoint via `response_format: { type: "json_schema", ... }`.
5
+ *
6
+ * The single public entry point is {@link validateComponent}. It's called
7
+ * once per LLM completion, on the deserialised JSON payload the client got
8
+ * back. On success it returns the payload typed as {@link ValidatedComponent}
9
+ * (a compile-time re-typing — no reshape at runtime). On failure it throws
10
+ * {@link SchemaValidationError} carrying the full Ajv `errors: ErrorObject[]`
11
+ * so the retry path in M2-03/M2-04 can append the failure to the next prompt
12
+ * and give the model exactly one chance to self-correct.
13
+ *
14
+ * Two-pass design (AC3 + AC4):
15
+ * 1. Ajv strict-mode structural validation against `COMPONENT_SCHEMA`
16
+ * (M2-02). Catches missing fields, wrong types, bad path patterns, the
17
+ * "no <Name>.html preview" case, and the `manifestEntry.viewport`
18
+ * requirement.
19
+ * 2. `@genie` first-line marker cross-check on every `<Name>/<Name>.html`
20
+ * preview file the (now shape-valid) payload contains. This is
21
+ * intentionally *not* modelled in the JSON Schema itself — a regex-on-a-
22
+ * sibling-field is exactly the kind of cross-field constraint Draft 7
23
+ * can't express, and pushing it into JSON Schema would force the same
24
+ * shallow-`$ref` shape M2-02 was carefully written to avoid (see
25
+ * `schema.ts` AC2 note).
26
+ *
27
+ * The schema is compiled exactly once, at module load (AC5) — Ajv compilation
28
+ * is measurable per call and every LLM completion goes through this function,
29
+ * so caching pays for itself immediately.
30
+ */
31
+ import { Ajv } from "ajv";
32
+ import { COMPONENT_SCHEMA } from "./schema.js";
33
+ import { MARKER_REGEX } from "../validate/index.js";
34
+ /**
35
+ * AC4 — the canonical `@genie` first-line marker regex from
36
+ * Every generated `<Name>.html` preview
37
+ * must open with a comment matching this pattern so the manifest compiler
38
+ * (M3-03) and the validate tool (M3-04) can register / verify the card
39
+ * without re-parsing the component's JSX.
40
+ *
41
+ * M3-01 (DRO-257) landed the single source of truth for this pattern at
42
+ * `packages/server/src/validate/marker.ts`'s `MARKER_REGEX`, imported here
43
+ * via the `validate/index.ts` public barrel (Copilot review, PR #142) rather
44
+ * than reaching into `marker.js` directly, so this call site tracks the
45
+ * barrel's stable surface instead of the module's internal file layout.
46
+ * This is now a re-export alias, kept under its original M2-07 name for
47
+ * backwards compatibility with existing consumers (this module's own
48
+ * cross-check below, plus `packages/e2e/test/m2-generation.test.ts`) rather
49
+ * than forcing every call site to rename in the same change that removes
50
+ * the duplicate literal.
51
+ */
52
+ export const MARKER_REGEX_M2_07 = MARKER_REGEX;
53
+ /**
54
+ * Same selector as `COMPONENT_SCHEMA.properties.files.items.contains.pattern`
55
+ * — the `<group>/<Name>/<Name>.html` self-consistency shape ("preview file
56
+ * whose basename matches its containing directory"). Kept here as a compiled
57
+ * `RegExp` so the cross-check pass in {@link validateComponent} doesn't
58
+ * re-compile the pattern on every file iteration.
59
+ *
60
+ * The backreference `\1` locks the basename to the same PascalCase segment
61
+ * as the enclosing directory — this is what makes `Button/Wrong.html` fail
62
+ * schema-level AC5 but still lets `Button/Button.html` through. We reuse the
63
+ * exact shape here so the schema's `contains` guarantee (at least one file
64
+ * matches) and this cross-check (every matching file also has the `@genie`
65
+ * marker) can never disagree about which files are "preview files".
66
+ *
67
+ * Exported (Copilot review, PR #136) so consumers outside this module that
68
+ * need to identify "which files are actually preview files" — e.g.
69
+ * `m2-generation.test.ts`'s AC5 assertions — share this exact definition
70
+ * instead of re-deriving a looser one (`files[].path` also legally permits
71
+ * non-preview `.html` basenames like `dark-mode.html` per `schema.ts`'s
72
+ * `PATH_PATTERN`, which a naive `.endsWith(".html")` filter would wrongly
73
+ * subject to the marker rule).
74
+ */
75
+ export const NAMED_HTML_PATH = /^components\/[a-z0-9-]+\/([A-Z][A-Za-z0-9]{1,63})\/\1\.html$/;
76
+ /**
77
+ * `Error` subclass thrown by {@link validateComponent} on structural or
78
+ * marker-cross-check failure. Callers in M2-03/M2-04 catch this narrowly and
79
+ * append `error.errors` to the next prompt — the retry loop is exactly one
80
+ * round-trip, per DRO-254's "Out of Scope: auto-repair" note.
81
+ *
82
+ * `name` is set explicitly so `error.name === "SchemaValidationError"` works
83
+ * even after ESM module boundaries strip the class identity (defensive
84
+ * against `instanceof` foot-guns in vitest / workers).
85
+ */
86
+ export class SchemaValidationError extends Error {
87
+ /** Ajv-style structured errors; always non-empty when this is thrown. */
88
+ errors;
89
+ constructor(message, errors) {
90
+ super(message);
91
+ this.name = "SchemaValidationError";
92
+ this.errors = errors;
93
+ }
94
+ }
95
+ /**
96
+ * AC2 + AC5 — one Ajv instance, compiled once, at module load. The `strict:
97
+ * true` flag turns every unknown/ambiguous keyword into a *compile-time*
98
+ * throw, so if `schema.ts` ever grows a typo (e.g. `additionalProperty`
99
+ * instead of `additionalProperties`) the server refuses to boot rather than
100
+ * silently letting malformed output through at runtime. `allErrors: true`
101
+ * asks Ajv to keep validating past the first failure and return every
102
+ * problem — critical for the "append failures to the prompt" retry loop,
103
+ * which can only fix errors the model actually sees.
104
+ */
105
+ const ajv = new Ajv({ strict: true, allErrors: true });
106
+ const validate = ajv.compile(COMPONENT_SCHEMA);
107
+ /**
108
+ * AC1 — the module's sole export contract. Validates `output` against
109
+ * `COMPONENT_SCHEMA` (M2-02) and the `@genie` marker convention (AC4). On
110
+ * success returns `output` cast to {@link ValidatedComponent} — an assertion
111
+ * of type, not a copy: callers get the exact same object identity back so
112
+ * downstream `write_files` (M1-08) can pass it through without an extra
113
+ * allocation per completion.
114
+ *
115
+ * @throws {SchemaValidationError} on any structural or marker failure. The
116
+ * thrown error's `errors` array holds Ajv `ErrorObject`s (schema-level
117
+ * failures) and/or synthetic `ErrorObject`s with `keyword: "@genie-marker"`
118
+ * (marker-level failures). Both live in the same array so M2-03/M2-04's
119
+ * retry prompt can serialise them uniformly.
120
+ */
121
+ export function validateComponent(output) {
122
+ // Pass 1 — Ajv structural validation. `validate` mutates `.errors` on the
123
+ // ValidateFunction itself (Ajv's API quirk); snapshot into a local so a
124
+ // concurrent second call from another async caller can't clobber it before
125
+ // we've thrown.
126
+ if (!validate(output)) {
127
+ const errors = validate.errors ?? [];
128
+ throw new SchemaValidationError(`LLM output failed COMPONENT_SCHEMA validation (${errors.length} error${errors.length === 1 ? "" : "s"}).`,
129
+ // Defensive copy — a caller inspecting `.errors` shouldn't be able to
130
+ // mutate the ValidateFunction's internal buffer through this handle.
131
+ errors.map((e) => ({ ...e })));
132
+ }
133
+ // At this point Ajv has narrowed `output` to `ValidatedComponent` via the
134
+ // typed ValidateFunction type-guard return; `output` is the same object
135
+ // identity the caller passed in.
136
+ const component = output;
137
+ // Pass 2 — @genie marker cross-check (AC4). Ajv can't express "field A
138
+ // matches regex X on field B's first line", so this runs in plain code
139
+ // against the (now shape-valid) file set. Collect every failure so the
140
+ // retry prompt can name all of them at once, mirroring `allErrors: true`.
141
+ const markerErrors = [];
142
+ for (let i = 0; i < component.files.length; i++) {
143
+ const file = component.files[i];
144
+ if (!NAMED_HTML_PATH.test(file.path)) {
145
+ // Not a `<Name>/<Name>.html` preview — the schema's `contains`
146
+ // guarantees at least one file *does* match, but non-preview files
147
+ // (e.g. `Button.tsx`, `meta.json`) are exempt from the marker rule.
148
+ continue;
149
+ }
150
+ // First line only (`\n` split limit=1 style, but done via indexOf to
151
+ // avoid allocating the whole `split()` array on files that pass — the
152
+ // vast majority in the steady state).
153
+ const newlineAt = file.content.indexOf("\n");
154
+ const firstLine = newlineAt === -1 ? file.content : file.content.slice(0, newlineAt);
155
+ if (!MARKER_REGEX_M2_07.test(firstLine)) {
156
+ markerErrors.push({
157
+ keyword: "@genie-marker",
158
+ instancePath: `/files/${i}/content`,
159
+ schemaPath: "#/properties/files/items/content",
160
+ params: {
161
+ expected: MARKER_REGEX_M2_07.source,
162
+ path: file.path,
163
+ },
164
+ message: `first line of ${file.path} does not match the @genie marker ` +
165
+ `regex ${MARKER_REGEX_M2_07} (required for card registration)`,
166
+ });
167
+ }
168
+ }
169
+ if (markerErrors.length > 0) {
170
+ throw new SchemaValidationError(`LLM output has ${markerErrors.length} @genie marker error${markerErrors.length === 1 ? "" : "s"} (structural schema OK, marker cross-check failed).`, markerErrors);
171
+ }
172
+ return component;
173
+ }
174
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/llm/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * M3-03 (DRO-259) — the `.genie/manifest.json` writer (client-side compiler).
3
+ *
4
+ * This is genie's substitute for Anthropic's server-side manifest
5
+ * compilation (research report §6): a small, dependency-light walker that
6
+ * recompiles `<projectRoot>/.genie/manifest.json` from the `@genie` markers
7
+ * on disk whenever the M3-02 watcher fires (or on any direct call — this
8
+ * module has no opinion on WHEN it runs, only on producing a correct
9
+ * manifest for a given `projectRoot` snapshot).
10
+ *
11
+ * ── Schema reconciliation (recorded on DRO-259 before this file was written) ──
12
+ * This issue's own AC4 (and the RFC §6.8/§7.1 sketch, and the M4-03 viewer's
13
+ * `fetch` code) describe a root key `cards` with `viewport: {width,height}`
14
+ * as an object. But `../store/manifest.ts` — already merged, backing the
15
+ * shipped/tested M1-15 `list_components` tool, read by BOTH `LocalFsKitStore`
16
+ * and `GitHostKitStore` — has a zod schema that requires the root key
17
+ * `components`, with `viewport` as the raw marker STRING (e.g. `"400x200"`
18
+ * or `"desktop"`), plus `{name, group, path, hash, lastModified}`.
19
+ *
20
+ * Emitting `cards` would silently break `list_components` (a live, shipped
21
+ * P0 tool): its zod parse requires `components` and would throw
22
+ * `ManifestParseError` on a `cards`-shaped file. So this compiler emits
23
+ * `components` with a STRING `viewport`, matching the already-shipped reader
24
+ * contract. `../store/manifest.ts`'s schemas are `.passthrough()`, so the
25
+ * RFC's additional fields are layered on top without conflict: top-level
26
+ * `version: 1`, `generatedAt`, `name` (the kit/project's directory basename),
27
+ * `groups: string[]`; per-card `subtitle`/`tags` when a sibling `meta.json`
28
+ * supplies them. This is additive/forward-compatible per RFC §16.2 ("add a
29
+ * new output field — allowed in minor/patch").
30
+ *
31
+ * Pure-ish orchestration: the only side effects are reading the component
32
+ * tree + sibling `meta.json`/`_groups.json` files and the final atomic write.
33
+ * Marker PRESENCE validation and card sort order are delegated to
34
+ * already-shipped, independently-tested modules (M3-01's `validateMarker`,
35
+ * `store/manifest.ts`'s `compareComponents`); group/viewport extraction is
36
+ * a narrow regex read of the same already-validated marker line (see
37
+ * `extractGroup`/`extractViewportToken` below for why M3-01's own
38
+ * `extractViewport` isn't reused verbatim here).
39
+ */
40
+ /**
41
+ * One compiled card (AC2–AC5). Matches `../store/manifest.ts`'s
42
+ * `ComponentEntry` six required fields exactly, plus the two optional
43
+ * `meta.json`-sourced fields already defined by `llm/schema.ts`'s
44
+ * `manifestEntry` (`subtitle`, `tags`).
45
+ */
46
+ export interface ManifestCard {
47
+ name: string;
48
+ group: string;
49
+ path: string;
50
+ /** The raw marker token (e.g. "400x200" or "desktop") — AC5 note; not decomposed. */
51
+ viewport: string;
52
+ /** `sha256-<base64>` SRI hash of the HTML file's bytes (AC5). */
53
+ hash: string;
54
+ /** ISO-8601 mtime of the HTML file. */
55
+ lastModified: string;
56
+ subtitle?: string;
57
+ tags?: string[];
58
+ }
59
+ /** The full compiled manifest (AC4, reconciled — see module doc). */
60
+ export interface Manifest {
61
+ version: 1;
62
+ name: string;
63
+ generatedAt: string;
64
+ groups: string[];
65
+ components: ManifestCard[];
66
+ }
67
+ /**
68
+ * One skipped file the compiler declined to card — surfaced so a caller (the
69
+ * M3-02 watcher's `onChange`, or a future `validate` full-scan) can report
70
+ * `markerMissing` rather than the omission vanishing silently. Mirrors the
71
+ * RFC §6.8 failure mode: "the watcher silently skips it; `validate` surfaces
72
+ * the omission."
73
+ */
74
+ export interface ManifestSkip {
75
+ path: string;
76
+ reason: "MARKER_MISSING";
77
+ }
78
+ /** {@link compileManifest}'s full result: the manifest plus any skips. */
79
+ export interface CompileResult {
80
+ manifest: Manifest;
81
+ skipped: ManifestSkip[];
82
+ }
83
+ /**
84
+ * Recompile the manifest for `projectRoot` (AC1) purely from what's on disk
85
+ * right now — no incremental state, no cache. Safe to call as often as the
86
+ * watcher likes; a debounce (M3-02's own 100 ms window) is the caller's
87
+ * concern, not this function's.
88
+ *
89
+ * Steps (AC2/AC3):
90
+ * 1. Walk `${projectRoot}/components/**\/*.html`.
91
+ * 2. For each, validate the `@genie` first line (M3-01). A file that fails
92
+ * is SKIPPED (not carded) and reported in `skipped` — mirrors the RFC
93
+ * §6.8 failure mode ("the watcher silently skips it; validate surfaces
94
+ * the omission").
95
+ * 3. Extract `viewport` from the marker line; join a sibling `meta.json`
96
+ * for `subtitle`/`tags` when present (AC3).
97
+ * 4. Hash the HTML file's bytes as `sha256-<base64>` SRI (AC5, same format
98
+ * `list_files`/`.genie/sync.json` use — `store/kit-files.ts`'s
99
+ * `sriSha256`).
100
+ * 5. Sort groups alphabetically unless a root `_groups.json` sibling pins an
101
+ * explicit order (Impl Notes); sort cards alphabetically by `name`
102
+ * within a group, ties broken by `path` (the shared `compareComponents`
103
+ * from `store/manifest.ts` — AC6-equivalent ordering used everywhere
104
+ * else a component list is sorted in this codebase).
105
+ * 6. Atomically write `.genie/manifest.json` (AC6): stage under
106
+ * `${projectRoot}/.genie-tmp/`, then rename over the destination — same
107
+ * same-filesystem-rename pattern `sync/anchor.ts` and `store/local.ts`
108
+ * already use, so a crash mid-write leaves the PRIOR manifest (or none)
109
+ * intact, never a half-written one.
110
+ */
111
+ export declare function compileManifest(projectRoot: string): Promise<CompileResult>;
112
+ //# sourceMappingURL=compiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/manifest/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAWH;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,qEAAqE;AACrE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAqKD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA2DjF"}