@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 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/config/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,gFAAgF;AAChF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;EAKrB,CAAC;AAEX,wDAAwD;AACxD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AAEnE,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAIpC;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAClB,QAAQ,EAAE,SAAS,MAAM,EAAE;gBAA3B,QAAQ,EAAE,SAAS,MAAM,EAAE;CAIxD;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAazE;AAID,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,SAAS,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,yEAAyE;IACzE,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,YAAY,EAAE,CA8C5E;AAID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAA2C,GACnE,IAAI,CAON"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Secret loading (M5-03 / DRO-275) — no plaintext secrets at rest.
3
+ *
4
+ * Every secret genie uses is read only from env vars or, when
5
+ * `--secrets-from <path>` is passed (e.g. a mounted Docker/Kubernetes
6
+ * secret), from an owner-only `KEY=VALUE`-per-line file at that path (AC6).
7
+ * Files with group/other permission bits are rejected before reading. Nothing
8
+ * secret is ever hardcoded, and this module never writes a secret value to
9
+ * disk, argv, or a log line.
10
+ *
11
+ * Bootstrap contract (AC2): `loadSecrets()` throws `SecretValidationError`
12
+ * with one message per problem when any *required* secret is:
13
+ * - missing (unset, and absent from a `--secrets-from` file if provided);
14
+ * - shorter than its required minimum length;
15
+ * - present verbatim anywhere in `process.argv` (a value passed as a CLI
16
+ * flag is visible to `ps`/shell history on every other local user, so a
17
+ * secret leaking into argv is treated as fatal, not just discouraged).
18
+ *
19
+ * AC3: `auditLoadedSecrets` logs which secret *names* were loaded (never
20
+ * values) as a single structured line on process.stderr, mirroring the
21
+ * stdout-is-JSON-RPC convention documented in `llm/client.ts`.
22
+ */
23
+ import { readFileSync, statSync } from "node:fs";
24
+ // ─── Known secrets ───────────────────────────────────────────────────────────
25
+ /** Every secret env var genie recognises, and whether it's required to boot. */
26
+ export const SECRET_DEFINITIONS = [
27
+ { key: "GENIE_LLM_API_KEY", required: true, minLength: 16 },
28
+ { key: "OAUTH_HS256_KEY", required: true, minLength: 32 },
29
+ { key: "GENIE_GIT_TOKEN", required: false, minLength: 0 },
30
+ { key: "OAUTH_CLIENT_SECRET", required: false, minLength: 0 },
31
+ ];
32
+ /** Minimum acceptable length for a required secret value (AC2). */
33
+ export const MIN_SECRET_LENGTH = 16;
34
+ // ─── Errors ──────────────────────────────────────────────────────────────────
35
+ /**
36
+ * Thrown by `loadSecrets` when bootstrap validation fails. Aggregates every
37
+ * problem found (not just the first) so a misconfigured deployment gets the
38
+ * full picture in one failure rather than fixing issues one at a time.
39
+ */
40
+ export class SecretValidationError extends Error {
41
+ problems;
42
+ constructor(problems) {
43
+ super(`Secret validation failed:\n - ${problems.join("\n - ")}`);
44
+ this.problems = problems;
45
+ this.name = "SecretValidationError";
46
+ }
47
+ }
48
+ // ─── Secrets-from-file parsing ───────────────────────────────────────────────
49
+ /**
50
+ * Parse a `KEY=VALUE`-per-line secrets file (AC6), e.g. a mounted secret
51
+ * mounted at `/run/secrets/genie`. Blank lines and `#`-prefixed comments are
52
+ * skipped. Values are not trimmed of surrounding quotes — the file is
53
+ * expected to hold raw values, matching Docker/Kubernetes secret conventions
54
+ * (unlike a shell-sourced `.env`, no quoting/escaping is applied).
55
+ */
56
+ export function parseSecretsFile(contents) {
57
+ const out = {};
58
+ for (const rawLine of contents.split("\n")) {
59
+ const line = rawLine.trim();
60
+ if (line === "" || line.startsWith("#"))
61
+ continue;
62
+ const eq = line.indexOf("=");
63
+ if (eq === -1)
64
+ continue;
65
+ const key = line.slice(0, eq).trim();
66
+ const value = line.slice(eq + 1);
67
+ if (key === "")
68
+ continue;
69
+ out[key] = value;
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * Load and validate every known secret (AC1/AC2). Reads from env only,
75
+ * optionally overlaid by a `--secrets-from` file (AC6). Throws
76
+ * `SecretValidationError` if any *required* secret is missing, too short, or
77
+ * leaked into argv verbatim.
78
+ *
79
+ * Returns only the secrets that were actually present (optional secrets are
80
+ * omitted when unset) so callers can distinguish "not configured" from "".
81
+ */
82
+ export function loadSecrets(options = {}) {
83
+ const env = options.env ?? process.env;
84
+ const argv = options.argv ?? process.argv;
85
+ const readFile = options.readFile ?? ((path) => readFileSync(path, "utf8"));
86
+ const statFile = options.statFile ?? statSync;
87
+ let fileValues = {};
88
+ if (options.secretsFromPath) {
89
+ const mode = statFile(options.secretsFromPath).mode & 0o777;
90
+ if ((mode & 0o077) !== 0) {
91
+ throw new SecretValidationError([
92
+ `Secrets file ${options.secretsFromPath} must not be readable or writable by group or other users (mode ${mode.toString(8).padStart(3, "0")}).`,
93
+ ]);
94
+ }
95
+ fileValues = parseSecretsFile(readFile(options.secretsFromPath));
96
+ }
97
+ const problems = [];
98
+ const loaded = [];
99
+ for (const def of SECRET_DEFINITIONS) {
100
+ const value = fileValues[def.key] ?? env[def.key];
101
+ if (value === undefined || value === "") {
102
+ if (def.required)
103
+ problems.push(`${def.key} is required but not set.`);
104
+ continue;
105
+ }
106
+ if (def.required && value.length < def.minLength) {
107
+ problems.push(`${def.key} must be at least ${def.minLength} characters (got ${value.length}).`);
108
+ }
109
+ if (argv.some((arg) => arg.includes(value))) {
110
+ problems.push(`${def.key}'s value was found in process.argv — secrets must never be passed as CLI flags.`);
111
+ }
112
+ loaded.push({ key: def.key, value });
113
+ }
114
+ if (problems.length > 0)
115
+ throw new SecretValidationError(problems);
116
+ return loaded;
117
+ }
118
+ // ─── Startup audit (AC3) ─────────────────────────────────────────────────────
119
+ /**
120
+ * Log which secrets were loaded — key names only, never values — as a single
121
+ * structured line on stderr (stdout is the JSON-RPC stream on the stdio
122
+ * transport; see `llm/client.ts` for the same convention).
123
+ */
124
+ export function auditLoadedSecrets(loaded, write = (line) => process.stderr.write(line)) {
125
+ write(JSON.stringify({
126
+ event: "secrets.loaded",
127
+ keys: loaded.map((s) => s.key),
128
+ }) + "\n");
129
+ }
130
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/config/secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * `HtmlAdapter` (M2-08 stub → **v2 · DRO-617**) — the vanilla-HTML framework adapter.
3
+ *
4
+ * Lowers a neutral {@link RenderInput} (a self-contained `.html` document /
5
+ * template) into the three target artefacts, mirroring {@link ReactAdapter} /
6
+ * {@link VueAdapter} method-for-method so `conjure` treats every framework the
7
+ * same:
8
+ * - {@link HtmlAdapter.renderSource} → `<Name>.html` (the canonical source)
9
+ * - {@link HtmlAdapter.renderPreview} → `<Name>.preview.js` — a browser-ready
10
+ * **IIFE** exposing the component on `globalThis.GenieComponent` for the M4
11
+ * iframe grid to mount, exactly like the React/Vue previews
12
+ * - {@link HtmlAdapter.extractDts} → `<Name>.d.ts` — a minimal custom-element
13
+ * typing surface (an `HTMLElementTagNameMap` augmentation for any
14
+ * `customElements.define(...)` the source registers), or a valid empty module
15
+ *
16
+ * ── Why vanilla HTML still emits a `.preview.js` IIFE ─────────────────────────
17
+ * The HTML *is* already browser-ready — but the M4-03 iframe grid mounts **every**
18
+ * framework through the identical `window.{@link PREVIEW_GLOBAL_NAME}` handle
19
+ * (`{ default, <Name> }`), so React and Vue cards mount the same way (react.ts /
20
+ * vue.ts). Emitting an HTML card as a raw document instead would fork the grid's
21
+ * mount path per framework. Instead this adapter wraps the markup in the same
22
+ * preview-global contract: the IIFE exposes a descriptor whose `mount(container)`
23
+ * writes the component's markup into the card and *re-executes* any inline
24
+ * `<script>` (browsers do not run scripts inserted via `innerHTML`), so an
25
+ * interactive vanilla-HTML component behaves the same mounted as it would opened
26
+ * directly. This is the issue's "mostly a pass-through + optional JS/CSS inlining":
27
+ * no bundler, no compile — the markup flows through verbatim, only *wrapped* for a
28
+ * uniform mount.
29
+ *
30
+ * ── No preview host globals ───────────────────────────────────────────────────
31
+ * Unlike React (`window.React`) and Vue (`window.Vue`), a vanilla-HTML preview has
32
+ * **no** framework runtime to resolve from a host global — the browser is the
33
+ * runtime. So there is no host-global contract and no esbuild rewrite plugin here;
34
+ * the preview is fully self-contained and evaluates in any window.
35
+ *
36
+ * ── Import-time safety ────────────────────────────────────────────────────────
37
+ * Nothing heavy is imported here at all — the preview is assembled from plain
38
+ * string templating and `extractDts` scans the source with a regex — so resolving
39
+ * an `HtmlAdapter` (which the registry does on first `getAdapter("html")`) is
40
+ * free, and `conjure` can read its `promptDirective` / `defaultViewport` on the
41
+ * generation hot path with zero cost. The React/Vue adapters lazy-`import` esbuild
42
+ * / ts-morph / the SFC compiler for the same "keep resolving cheap" reason; the
43
+ * HTML adapter simply needs none of them.
44
+ */
45
+ import { type AdapterFile, type FrameworkAdapter, type Framework, type RenderInput, type Viewport } from "./interface.js";
46
+ /**
47
+ * v2 tracking issue this adapter was implemented under (kept exported for
48
+ * provenance and referenced by the conformance suite's URL-shape assertion).
49
+ * Retained now that HTML is no longer a stub so historical links still resolve.
50
+ */
51
+ export declare const HTML_TRACKING_ISSUE = "https://github.com/ambitresearch/genie/issues/130";
52
+ /**
53
+ * The property name the preview descriptor carries the component's raw markup
54
+ * under. Exported so a test (or the M4 grid) can read the pass-through markup off
55
+ * `window.GenieComponent.default.html` without re-deriving the key.
56
+ */
57
+ export declare const PREVIEW_HTML_KEY = "html";
58
+ export declare class HtmlAdapter implements FrameworkAdapter {
59
+ readonly framework: Framework;
60
+ /**
61
+ * A comfortable default card for a vanilla-HTML component when the caller has no
62
+ * better viewport. Matches the React/Vue adapters (and the RFC's default preview
63
+ * grid cell, §7.5) so a framework switch never resizes a card by default.
64
+ */
65
+ readonly defaultViewport: Viewport;
66
+ /**
67
+ * The framework directive `conjure` injects into the generation prompt (AC4):
68
+ * name the target framework and the self-contained vanilla-HTML shape the model
69
+ * should emit. Kept aligned with the original stub's directive so a prompt built
70
+ * before this adapter graduated still reads identically.
71
+ */
72
+ readonly promptDirective: string;
73
+ /**
74
+ * The canonical source file: `<Name>.html`, carrying the model-authored markup
75
+ * verbatim. `text/html` matches the MIME the kit-file classifier maps `.html` to
76
+ * (`mime-types` resolves `.html` → `text/html`), so an adapter-emitted source and
77
+ * a store-read source report the same type.
78
+ */
79
+ renderSource(input: RenderInput): AdapterFile;
80
+ /**
81
+ * Wrap the component markup in the browser-ready **IIFE** exposing it on
82
+ * `globalThis.${PREVIEW_GLOBAL_NAME}` (`{ default, <Name> }`), so the M4 grid
83
+ * mounts an HTML card through the identical `window.GenieComponent` handle it
84
+ * uses for React/Vue — see {@link previewIife} for the descriptor + `mount`
85
+ * contract. The markup passes through verbatim (no bundler, no compile); this is
86
+ * `async` only to satisfy the {@link FrameworkAdapter} contract (React/Vue are
87
+ * async because they lazy-load esbuild) — HTML needs no async work, so it
88
+ * resolves immediately.
89
+ */
90
+ renderPreview(input: RenderInput): Promise<AdapterFile>;
91
+ /**
92
+ * Emit a `.d.ts` typing surface (parity with React/Vue). A vanilla-HTML
93
+ * component exports no component type, so the useful typing is the **custom
94
+ * elements** it registers: {@link customElementTags} scans the source for
95
+ * `customElements.define("x-y", …)` and {@link dtsForCustomElements} augments
96
+ * `HTMLElementTagNameMap` for each. A component that registers none falls back to
97
+ * a valid empty module (`export {};`) — never an empty file — exactly as the
98
+ * React/Vue adapters do for a source with no exported declarations. `async` only
99
+ * to match the contract; the work is synchronous.
100
+ */
101
+ extractDts(input: RenderInput): Promise<AdapterFile>;
102
+ }
103
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/framework/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAQxB;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,sDAAsD,CAAC;AAoBvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAgIvC,qBAAa,WAAY,YAAW,gBAAgB;IAClD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAU;IAEvC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAA+B;IAEjE;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAInB;IAEb;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAQ7C;;;;;;;;;OASG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAQvD;;;;;;;;;OASG;IACH,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAQrD"}
@@ -0,0 +1,271 @@
1
+ /**
2
+ * `HtmlAdapter` (M2-08 stub → **v2 · DRO-617**) — the vanilla-HTML framework adapter.
3
+ *
4
+ * Lowers a neutral {@link RenderInput} (a self-contained `.html` document /
5
+ * template) into the three target artefacts, mirroring {@link ReactAdapter} /
6
+ * {@link VueAdapter} method-for-method so `conjure` treats every framework the
7
+ * same:
8
+ * - {@link HtmlAdapter.renderSource} → `<Name>.html` (the canonical source)
9
+ * - {@link HtmlAdapter.renderPreview} → `<Name>.preview.js` — a browser-ready
10
+ * **IIFE** exposing the component on `globalThis.GenieComponent` for the M4
11
+ * iframe grid to mount, exactly like the React/Vue previews
12
+ * - {@link HtmlAdapter.extractDts} → `<Name>.d.ts` — a minimal custom-element
13
+ * typing surface (an `HTMLElementTagNameMap` augmentation for any
14
+ * `customElements.define(...)` the source registers), or a valid empty module
15
+ *
16
+ * ── Why vanilla HTML still emits a `.preview.js` IIFE ─────────────────────────
17
+ * The HTML *is* already browser-ready — but the M4-03 iframe grid mounts **every**
18
+ * framework through the identical `window.{@link PREVIEW_GLOBAL_NAME}` handle
19
+ * (`{ default, <Name> }`), so React and Vue cards mount the same way (react.ts /
20
+ * vue.ts). Emitting an HTML card as a raw document instead would fork the grid's
21
+ * mount path per framework. Instead this adapter wraps the markup in the same
22
+ * preview-global contract: the IIFE exposes a descriptor whose `mount(container)`
23
+ * writes the component's markup into the card and *re-executes* any inline
24
+ * `<script>` (browsers do not run scripts inserted via `innerHTML`), so an
25
+ * interactive vanilla-HTML component behaves the same mounted as it would opened
26
+ * directly. This is the issue's "mostly a pass-through + optional JS/CSS inlining":
27
+ * no bundler, no compile — the markup flows through verbatim, only *wrapped* for a
28
+ * uniform mount.
29
+ *
30
+ * ── No preview host globals ───────────────────────────────────────────────────
31
+ * Unlike React (`window.React`) and Vue (`window.Vue`), a vanilla-HTML preview has
32
+ * **no** framework runtime to resolve from a host global — the browser is the
33
+ * runtime. So there is no host-global contract and no esbuild rewrite plugin here;
34
+ * the preview is fully self-contained and evaluates in any window.
35
+ *
36
+ * ── Import-time safety ────────────────────────────────────────────────────────
37
+ * Nothing heavy is imported here at all — the preview is assembled from plain
38
+ * string templating and `extractDts` scans the source with a regex — so resolving
39
+ * an `HtmlAdapter` (which the registry does on first `getAdapter("html")`) is
40
+ * free, and `conjure` can read its `promptDirective` / `defaultViewport` on the
41
+ * generation hot path with zero cost. The React/Vue adapters lazy-`import` esbuild
42
+ * / ts-morph / the SFC compiler for the same "keep resolving cheap" reason; the
43
+ * HTML adapter simply needs none of them.
44
+ */
45
+ import { componentPath, } from "./interface.js";
46
+ // The M4 grid's preview-global name is a cross-framework contract; import the
47
+ // single source of truth from the React adapter rather than redeclaring it, so
48
+ // HTML, Vue and React cards are all mounted through the identical
49
+ // `window.GenieComponent` handle. (react.js has no heavy top-level imports —
50
+ // only `import type` — so this stays free and pulls no esbuild/ts-morph.)
51
+ import { PREVIEW_GLOBAL_NAME } from "./react.js";
52
+ /**
53
+ * v2 tracking issue this adapter was implemented under (kept exported for
54
+ * provenance and referenced by the conformance suite's URL-shape assertion).
55
+ * Retained now that HTML is no longer a stub so historical links still resolve.
56
+ */
57
+ export const HTML_TRACKING_ISSUE = "https://github.com/ambitresearch/genie/issues/130";
58
+ /**
59
+ * Matches a `customElements.define("tag-name", …)` registration in the source,
60
+ * capturing the custom-element tag (which must contain a hyphen per the HTML
61
+ * spec). Used by {@link HtmlAdapter.extractDts} to surface a typed element map.
62
+ * Tolerant of single/double/back quotes and arbitrary whitespace around `(`.
63
+ *
64
+ * **Case-sensitive by design** (only the `g` flag — no `i`): `customElements.define`
65
+ * is a case-sensitive JS API, so a mixed-case token like `CustomElements.Define` is
66
+ * not a real registration and must not match. More importantly, a valid custom-element
67
+ * name is lowercase per the HTML spec — `define("X-Counter", …)` throws `SyntaxError`
68
+ * at runtime — so an `i` flag would let the tag group accept uppercase names and type
69
+ * an element in `HTMLElementTagNameMap` that can never actually be registered. The
70
+ * literal `customElements`/`define` and every valid tag name are already lowercase,
71
+ * so dropping `i` costs nothing and rejects exactly the tags that can never exist.
72
+ */
73
+ const CUSTOM_ELEMENT_DEFINE = /customElements\s*\.\s*define\s*\(\s*["'`]([a-z][a-z0-9]*-[a-z0-9-]*)["'`]/g;
74
+ /**
75
+ * The property name the preview descriptor carries the component's raw markup
76
+ * under. Exported so a test (or the M4 grid) can read the pass-through markup off
77
+ * `window.GenieComponent.default.html` without re-deriving the key.
78
+ */
79
+ export const PREVIEW_HTML_KEY = "html";
80
+ /**
81
+ * Serialize a string into a JS string literal that is also safe to embed inside
82
+ * an HTML `<script>` block. `JSON.stringify` handles quotes/newlines/control
83
+ * chars, and replacing every `<` with the `<` escape means the literal can
84
+ * never contain a `</script>` (or `<script>`, or `<!--`) token an HTML parser
85
+ * would act on. `"<"` evaluates back to `"<"` at JS runtime, so the value
86
+ * the descriptor carries is byte-identical to the source markup.
87
+ */
88
+ function jsStringForHtmlEmbedding(value) {
89
+ return JSON.stringify(value).replace(/</g, "\\u003c");
90
+ }
91
+ /**
92
+ * Build the browser-ready preview IIFE body for a vanilla-HTML component. The
93
+ * emitted script assigns `window.GenieComponent = { default: descriptor, <Name>:
94
+ * descriptor }` (the same `{ default, <Name> }` shape React/Vue expose), where the
95
+ * descriptor is:
96
+ *
97
+ * {
98
+ * framework: "html",
99
+ * html: "<the component markup, verbatim>",
100
+ * mount: function (container) { … }
101
+ * }
102
+ *
103
+ * `mount` writes the markup into the target element and then re-executes any
104
+ * inline `<script>` the markup carried — because setting `innerHTML` produces
105
+ * inert `<script>` nodes the browser will not run. Re-creating each `<script>`
106
+ * (copying its attributes + text) makes an interactive vanilla-HTML component work
107
+ * mounted exactly as it would opened directly (the "optional JS … inlining" the
108
+ * issue calls for). It is defensive about a missing DOM (returns without throwing)
109
+ * so evaluating the bundle for static analysis never crashes.
110
+ *
111
+ * The markup is embedded via `JSON.stringify` so any quotes / newlines in the
112
+ * source are safely escaped into a single JS string literal. `JSON.stringify`
113
+ * does **not** escape `<` (or `/`), so a literal `</script>` in the markup would
114
+ * survive verbatim — harmless in a standalone `.js` file, but a script-breakout
115
+ * hazard the instant this preview is inlined into an HTML `<script>` block (which
116
+ * an iframe host page may do). Escaping every `<` to its `<` unicode form
117
+ * closes that hole: `"<"` evaluates back to `<` at runtime (so the mounted
118
+ * markup is byte-identical to the source), yet no HTML parser ever sees a
119
+ * `<script` / `</script` token in the emitted preview. The standard safe-embed
120
+ * technique used by JSON-in-HTML serializers.
121
+ */
122
+ function previewIife(input) {
123
+ const markup = jsStringForHtmlEmbedding(input.source);
124
+ const componentExport = JSON.stringify(input.componentName);
125
+ return [
126
+ `(function () {`,
127
+ ` "use strict";`,
128
+ ` var descriptor = {`,
129
+ ` framework: "html",`,
130
+ ` ${PREVIEW_HTML_KEY}: ${markup},`,
131
+ ` mount: function (container) {`,
132
+ ` if (!container || typeof document === "undefined") return;`,
133
+ ` container.innerHTML = descriptor.${PREVIEW_HTML_KEY};`,
134
+ ` // Scripts inserted via innerHTML are inert; re-create each so the`,
135
+ ` // browser executes it — this is what makes interactivity work mounted.`,
136
+ ` var inert = container.querySelectorAll("script");`,
137
+ ` for (var i = 0; i < inert.length; i++) {`,
138
+ ` var old = inert[i];`,
139
+ ` var next = document.createElement("script");`,
140
+ ` for (var a = 0; a < old.attributes.length; a++) {`,
141
+ ` var attr = old.attributes[a];`,
142
+ ` next.setAttribute(attr.name, attr.value);`,
143
+ ` }`,
144
+ ` next.textContent = old.textContent;`,
145
+ ` old.parentNode.replaceChild(next, old);`,
146
+ ` }`,
147
+ ` return container;`,
148
+ ` },`,
149
+ ` };`,
150
+ ` var GC = { default: descriptor };`,
151
+ ` GC[${componentExport}] = descriptor;`,
152
+ ` if (typeof window !== "undefined") {`,
153
+ ` window.${PREVIEW_GLOBAL_NAME} = GC;`,
154
+ ` } else if (typeof globalThis !== "undefined") {`,
155
+ ` globalThis.${PREVIEW_GLOBAL_NAME} = GC;`,
156
+ ` }`,
157
+ `})();`,
158
+ ].join("\n");
159
+ }
160
+ /**
161
+ * Collect the distinct custom-element tag names the source registers via
162
+ * `customElements.define("x-y", …)`, in first-seen order. Empty when the markup
163
+ * defines no custom elements (the common case for a plain HTML component).
164
+ */
165
+ function customElementTags(source) {
166
+ const tags = [];
167
+ const seen = new Set();
168
+ // `matchAll` needs the /g flag (present on CUSTOM_ELEMENT_DEFINE); re-run from a
169
+ // fresh matcher each call so the shared regex's lastIndex never leaks state.
170
+ for (const match of source.matchAll(CUSTOM_ELEMENT_DEFINE)) {
171
+ const tag = match[1];
172
+ if (tag && !seen.has(tag)) {
173
+ seen.add(tag);
174
+ tags.push(tag);
175
+ }
176
+ }
177
+ return tags;
178
+ }
179
+ /**
180
+ * Build the `.d.ts` typing surface for an HTML component. Vanilla HTML has no
181
+ * exported component type the way a `.tsx`/`.vue` source does, so the only stable
182
+ * typing worth surfacing is the **custom elements** the markup registers: each
183
+ * `customElements.define("x-y", …)` is declared as an `HTMLElement` and mapped in
184
+ * `HTMLElementTagNameMap`, so a consuming TypeScript project's
185
+ * `document.createElement("x-y")` / `querySelector("x-y")` are typed. When the
186
+ * source registers none, fall back to a valid empty module (never an empty file),
187
+ * mirroring the React/Vue `export {};` fallback.
188
+ */
189
+ function dtsForCustomElements(tags) {
190
+ if (tags.length === 0)
191
+ return `export {};\n`;
192
+ const lines = [
193
+ "// Custom elements this HTML component registers via customElements.define().",
194
+ "declare global {",
195
+ " interface HTMLElementTagNameMap {",
196
+ ];
197
+ for (const tag of tags) {
198
+ lines.push(` ${JSON.stringify(tag)}: HTMLElement;`);
199
+ }
200
+ lines.push(" }", "}", "export {};", "");
201
+ return lines.join("\n");
202
+ }
203
+ export class HtmlAdapter {
204
+ framework = "html";
205
+ /**
206
+ * A comfortable default card for a vanilla-HTML component when the caller has no
207
+ * better viewport. Matches the React/Vue adapters (and the RFC's default preview
208
+ * grid cell, §7.5) so a framework switch never resizes a card by default.
209
+ */
210
+ defaultViewport = { width: 400, height: 300 };
211
+ /**
212
+ * The framework directive `conjure` injects into the generation prompt (AC4):
213
+ * name the target framework and the self-contained vanilla-HTML shape the model
214
+ * should emit. Kept aligned with the original stub's directive so a prompt built
215
+ * before this adapter graduated still reads identically.
216
+ */
217
+ promptDirective = [
218
+ "Target framework: html",
219
+ "Emit a self-contained vanilla HTML component: semantic markup with inline " +
220
+ "<style>, and vanilla JS in a <script> only if interactivity is required.",
221
+ ].join("\n");
222
+ /**
223
+ * The canonical source file: `<Name>.html`, carrying the model-authored markup
224
+ * verbatim. `text/html` matches the MIME the kit-file classifier maps `.html` to
225
+ * (`mime-types` resolves `.html` → `text/html`), so an adapter-emitted source and
226
+ * a store-read source report the same type.
227
+ */
228
+ renderSource(input) {
229
+ return {
230
+ path: componentPath(input, `${input.componentName}.html`),
231
+ content: input.source,
232
+ mimeType: "text/html",
233
+ };
234
+ }
235
+ /**
236
+ * Wrap the component markup in the browser-ready **IIFE** exposing it on
237
+ * `globalThis.${PREVIEW_GLOBAL_NAME}` (`{ default, <Name> }`), so the M4 grid
238
+ * mounts an HTML card through the identical `window.GenieComponent` handle it
239
+ * uses for React/Vue — see {@link previewIife} for the descriptor + `mount`
240
+ * contract. The markup passes through verbatim (no bundler, no compile); this is
241
+ * `async` only to satisfy the {@link FrameworkAdapter} contract (React/Vue are
242
+ * async because they lazy-load esbuild) — HTML needs no async work, so it
243
+ * resolves immediately.
244
+ */
245
+ renderPreview(input) {
246
+ return Promise.resolve({
247
+ path: componentPath(input, `${input.componentName}.preview.js`),
248
+ content: previewIife(input),
249
+ mimeType: "text/javascript",
250
+ });
251
+ }
252
+ /**
253
+ * Emit a `.d.ts` typing surface (parity with React/Vue). A vanilla-HTML
254
+ * component exports no component type, so the useful typing is the **custom
255
+ * elements** it registers: {@link customElementTags} scans the source for
256
+ * `customElements.define("x-y", …)` and {@link dtsForCustomElements} augments
257
+ * `HTMLElementTagNameMap` for each. A component that registers none falls back to
258
+ * a valid empty module (`export {};`) — never an empty file — exactly as the
259
+ * React/Vue adapters do for a source with no exported declarations. `async` only
260
+ * to match the contract; the work is synchronous.
261
+ */
262
+ extractDts(input) {
263
+ const tags = customElementTags(input.source);
264
+ return Promise.resolve({
265
+ path: componentPath(input, `${input.componentName}.d.ts`),
266
+ content: dtsForCustomElements(tags),
267
+ mimeType: "text/plain",
268
+ });
269
+ }
270
+ }
271
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/framework/html.ts"],"names":[],"mappings":"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"}