@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,224 @@
1
+ /**
2
+ * MCP tool: validate (D-A — one verb, two facets).
3
+ *
4
+ * genie's `validate` verb has two facets that share this single MCP tool
5
+ * (`00-decisions.md` D-A folds `report_validate` + `validate_design_system`
6
+ * into one verb):
7
+ *
8
+ * 1. **Counter-persistence facet (M1-12).** The caller already ran validation
9
+ * client-side and passes aggregate `counts`; this facet persists them to a
10
+ * timestamped report + emits Prometheus metrics. Read-side telemetry, no
11
+ * planId semantics.
12
+ * Input: { kitId, counts: { total, bad, thin, variantsIdentical, iterations } }
13
+ * Output: {}
14
+ *
15
+ * 2. **Full-scan facet (M3-04 · DRO-260).** The caller passes NO `counts`;
16
+ * this facet does the heavyweight walk itself — the `@genie` marker check,
17
+ * the "thin render" check, and the "variants identical" perceptual-hash
18
+ * check across every `.html` file in the kit — and returns structured
19
+ * findings the model can act on, THEN persists the derived counters via the
20
+ * exact same `persistReport`/`emitMetrics` path as facet 1 (AC8: one verb,
21
+ * one persistence path).
22
+ * Input: { kitId, planId? }
23
+ * Output: { markerMissing, thin, variantsIdentical, total, bad }
24
+ *
25
+ * The presence of `counts` in the input discriminates the two facets — the MCP
26
+ * verb has one input schema, so `counts` is optional and its presence selects
27
+ * the persist-only path; its absence selects the full scan.
28
+ */
29
+ import { writeFile, mkdir } from "node:fs/promises";
30
+ import { join } from "node:path";
31
+ import { z } from "zod";
32
+ import { Counter, Registry } from "prom-client";
33
+ import { fullScan, createDefaultRenderer, } from "../validate/index.js";
34
+ /** Input schema for validate (counter-persistence facet). */
35
+ const countsSchema = z.object({
36
+ total: z.number().int().nonnegative().describe("Total component count"),
37
+ bad: z.number().int().nonnegative().describe("Failed validation count"),
38
+ thin: z.number().int().nonnegative().describe("Thin component count"),
39
+ variantsIdentical: z.number().int().nonnegative().describe("Variants identical count"),
40
+ iterations: z.number().int().nonnegative().describe("Iteration count"),
41
+ });
42
+ const inputSchema = {
43
+ kitId: z.string().min(1).describe("UI kit identifier"),
44
+ // Facet 1 (counter-persistence, M1-12): when present, the caller supplies
45
+ // pre-computed counts and this verb only persists them. When ABSENT, facet 2
46
+ // (full-scan, M3-04) runs the checks itself. Optional so one MCP input schema
47
+ // serves both facets (D-A: one verb).
48
+ counts: countsSchema
49
+ .optional()
50
+ .describe("Pre-computed validation counts (counter-persistence facet). Omit to run " +
51
+ "the full-scan facet, which computes findings by scanning the kit."),
52
+ // Facet 2 (full-scan, M3-04 · AC2): optional planId, accepted per the verb's
53
+ // declared `validate({ kitId, planId? })` signature. Ignored by facet 1.
54
+ planId: z
55
+ .string()
56
+ .min(1)
57
+ .optional()
58
+ .describe("Optional plan id (full-scan facet); accepted per the verb signature."),
59
+ };
60
+ /**
61
+ * Prometheus metrics registry and counters.
62
+ * Exposed as a module singleton so M6-01 can register it with the HTTP endpoint.
63
+ */
64
+ export const metricsRegistry = new Registry();
65
+ const totalCounter = new Counter({
66
+ name: "genie_validate_total",
67
+ help: "Total components validated",
68
+ labelNames: ["kitId"],
69
+ registers: [metricsRegistry],
70
+ });
71
+ const badCounter = new Counter({
72
+ name: "genie_validate_bad",
73
+ help: "Components that failed validation",
74
+ labelNames: ["kitId"],
75
+ registers: [metricsRegistry],
76
+ });
77
+ const thinCounter = new Counter({
78
+ name: "genie_validate_thin",
79
+ help: "Thin components (minimal content)",
80
+ labelNames: ["kitId"],
81
+ registers: [metricsRegistry],
82
+ });
83
+ const variantsIdenticalCounter = new Counter({
84
+ name: "genie_validate_variantsIdentical",
85
+ help: "Components with identical variants",
86
+ labelNames: ["kitId"],
87
+ registers: [metricsRegistry],
88
+ });
89
+ const iterationsCounter = new Counter({
90
+ name: "genie_validate_iterations",
91
+ help: "Validation iterations performed",
92
+ labelNames: ["kitId"],
93
+ registers: [metricsRegistry],
94
+ });
95
+ /**
96
+ * Persist validation counts to a timestamped JSON report file.
97
+ *
98
+ * @param reportsDir - Directory where reports are stored (.genie/reports)
99
+ * @param kitId - Kit identifier
100
+ * @param counts - Validation counts to persist
101
+ * @returns The path to the created report file
102
+ */
103
+ export async function persistReport(reportsDir, kitId, counts) {
104
+ await mkdir(reportsDir, { recursive: true });
105
+ const timestamp = new Date().toISOString();
106
+ // Sanitize for Windows-safe filenames (`:` is forbidden) and append a
107
+ // random hex suffix so concurrent calls within the same millisecond never
108
+ // collide or overwrite each other.
109
+ const safeTimestamp = timestamp.replace(/:/g, "-");
110
+ const suffix = Math.random().toString(16).slice(2, 8);
111
+ const reportPath = join(reportsDir, `${safeTimestamp}-${suffix}.json`);
112
+ const report = {
113
+ timestamp,
114
+ kitId,
115
+ counts,
116
+ };
117
+ await writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
118
+ return reportPath;
119
+ }
120
+ /**
121
+ * Emit Prometheus metrics for the given validation counts.
122
+ *
123
+ * @param kitId - Kit identifier (used as metric label)
124
+ * @param counts - Validation counts to emit
125
+ */
126
+ export function emitMetrics(kitId, counts) {
127
+ totalCounter.inc({ kitId }, counts.total);
128
+ badCounter.inc({ kitId }, counts.bad);
129
+ thinCounter.inc({ kitId }, counts.thin);
130
+ variantsIdenticalCounter.inc({ kitId }, counts.variantsIdentical);
131
+ iterationsCounter.inc({ kitId }, counts.iterations);
132
+ }
133
+ /**
134
+ * Derive the M1-12 counter shape from a full-scan result (AC8: the full-scan
135
+ * facet persists its run via the SAME `persistReport`/`emitMetrics` path as the
136
+ * counter facet). `iterations` is 1 — a single scan pass — and the four
137
+ * validation dimensions come straight off the scan. `bad` is the scan's own
138
+ * literal sum (`markerMissing + thin + variantsIdentical`).
139
+ */
140
+ export function countsFromScan(result) {
141
+ return {
142
+ total: result.total,
143
+ bad: result.bad,
144
+ thin: result.thin.length,
145
+ variantsIdentical: result.variantsIdentical.length,
146
+ iterations: 1,
147
+ };
148
+ }
149
+ /**
150
+ * Register the `mcp__genie__validate` tool on the given MCP server (both
151
+ * facets — see the module header).
152
+ *
153
+ * Backward-compatible call shape: `registerValidate(server, reportsDir?)` still
154
+ * works (the M1-12 wiring), and `registerValidate(server, options)` opts into
155
+ * the full-scan facet by supplying a `kitStore`.
156
+ */
157
+ export function registerValidate(server, reportsDirOrOptions) {
158
+ const options = typeof reportsDirOrOptions === "string"
159
+ ? { reportsDir: reportsDirOrOptions }
160
+ : (reportsDirOrOptions ?? {});
161
+ const resolvedReportsDir = options.reportsDir ?? process.env.GENIE_REPORTS_DIR ?? join(process.cwd(), ".genie", "reports");
162
+ const createRenderer = options.createRenderer ?? createDefaultRenderer;
163
+ server.registerTool("mcp__genie__validate", {
164
+ title: "Validate",
165
+ description: "genie's validate verb (two facets, one tool). WITH `counts`: persists " +
166
+ "pre-computed validation counts for telemetry (no planId needed — read-" +
167
+ "side). WITHOUT `counts`: runs the full-scan facet — @genie marker check " +
168
+ "+ thin-render check + variants-identical perceptual-hash check across " +
169
+ "the kit — and returns { markerMissing, thin, variantsIdentical, total, " +
170
+ "bad }, persisting the derived counters via the same path. Reach for this as an " +
171
+ "advisory quality audit after conjure/refine + write_files — its findings are " +
172
+ "counts, not blocking errors.",
173
+ inputSchema,
174
+ }, async ({ kitId, counts, planId, }) => {
175
+ // ── Facet 1: counter-persistence (M1-12) ────────────────────────────────
176
+ // Explicit `counts` → persist-only, exactly as before.
177
+ if (counts) {
178
+ await persistReport(resolvedReportsDir, kitId, counts);
179
+ emitMetrics(kitId, counts);
180
+ return { content: [{ type: "text", text: JSON.stringify({}) }] };
181
+ }
182
+ // ── Facet 2: full-scan (M3-04 · DRO-260) ────────────────────────────────
183
+ // No `counts` → run the checks ourselves. Needs a kit store to read the
184
+ // tree; without one, the facet is not available in this deployment.
185
+ if (!options.kitStore) {
186
+ return {
187
+ isError: true,
188
+ content: [
189
+ {
190
+ type: "text",
191
+ text: JSON.stringify({
192
+ error: "ERR_FULLSCAN_UNAVAILABLE",
193
+ message: "The full-scan facet requires a kit store; this validate tool was " +
194
+ "registered without one. Pass pre-computed `counts` to use the " +
195
+ "counter-persistence facet instead.",
196
+ }),
197
+ },
198
+ ],
199
+ };
200
+ }
201
+ // One renderer per scan (AC7), created here and closed after — the
202
+ // orchestrator never closes a renderer it did not create. A `null`
203
+ // renderer (Playwright/Chromium unavailable) makes the scan degrade to
204
+ // marker-only rather than fail (same posture as `refine`'s region crop).
205
+ const renderer = await createRenderer();
206
+ let result;
207
+ try {
208
+ result = await fullScan({ kitStore: options.kitStore, renderer }, { kitId, planId });
209
+ }
210
+ finally {
211
+ if (renderer)
212
+ await renderer.close();
213
+ }
214
+ // AC8 — persist the derived counters through the SAME path as facet 1.
215
+ const derived = countsFromScan(result);
216
+ await persistReport(resolvedReportsDir, kitId, derived);
217
+ emitMetrics(kitId, derived);
218
+ // Return the structured findings (the heavyweight facet's whole point).
219
+ return {
220
+ content: [{ type: "text", text: JSON.stringify(result) }],
221
+ };
222
+ });
223
+ }
224
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { KitStore } from "../store/interface.js";
3
+ export declare const WRITE_FILES_TOOL_NAME = "mcp__genie__write_files";
4
+ /** M1-08 AC3 — hard ceiling on files per call. */
5
+ export declare const MAX_FILES_PER_CALL = 256;
6
+ /**
7
+ * Byte-cap for a single `write_files` call's total decoded payload.
8
+ *
9
+ * RFC §17.5 flags Anthropic's exact server-side cap as unconfirmed for their
10
+ * hosted endpoint; PRD §EC-029 sets genie's own default at 16 MiB with a
11
+ * configurable ceiling. `GENIE_WRITE_BYTE_CAP` overrides the default; values
12
+ * that are non-numeric or ≤ 0 fall back to it.
13
+ */
14
+ export declare const DEFAULT_WRITE_BYTE_CAP: number;
15
+ /** M1-08 AC3 — more than 256 files were supplied to `write_files` in one call. */
16
+ export declare class TooManyFilesError extends Error {
17
+ readonly count: number;
18
+ readonly max: number;
19
+ readonly code = "TooManyFilesError";
20
+ constructor(count: number, max: number);
21
+ }
22
+ /**
23
+ * Two or more files in the same call target the same `path` (Copilot review
24
+ * finding on PR #106). Without this check, `resolvedLocalPaths` — keyed by
25
+ * `file.path` — would silently drop all but the last entry's `localPath`
26
+ * (so an earlier duplicate would stage the WRONG file's bytes), and
27
+ * `writtenPaths` would list the same path twice as if two distinct files had
28
+ * been written, when in fact whichever entry committed last (an unspecified,
29
+ * input-order-dependent race between the two renames) is the only one that
30
+ * survives. Rejected up front, before any per-file validation, so partial
31
+ * ambiguity is never staged.
32
+ */
33
+ export declare class DuplicatePathError extends Error {
34
+ readonly path: string;
35
+ readonly code = "DuplicatePathError";
36
+ constructor(path: string);
37
+ }
38
+ /**
39
+ * M1-08 AC4 — a file's `path` is rejected by the plan boundary: either it
40
+ * doesn't match any glob in the plan's `writes` (`reason: "glob"`), or it
41
+ * resolves outside the plan's `localDir` even though a glob DID match
42
+ * (`reason: "escapesLocalDir"` — e.g. an absolute path under a permissive
43
+ * `**`; see the containment check in `writeFiles`). Both failure modes share
44
+ * one error class/code (`PathOutsidePlanError`) so callers can branch on a
45
+ * single `code`, but the message and `reason` field distinguish them —
46
+ * a Copilot review finding on PR #106 flagged the message as misleadingly
47
+ * glob-specific even when the actual cause was the containment check.
48
+ */
49
+ export declare class PathOutsidePlanError extends Error {
50
+ readonly path: string;
51
+ readonly reason: "glob" | "escapesLocalDir";
52
+ readonly code = "PathOutsidePlanError";
53
+ constructor(path: string, reason?: "glob" | "escapesLocalDir");
54
+ }
55
+ /** M1-08 AC6 — a file's `localPath` resolves outside the plan's `localDir`. */
56
+ export declare class LocalPathEscapeError extends Error {
57
+ readonly localPath: string;
58
+ readonly localDir: string;
59
+ readonly code = "LocalPathEscapeError";
60
+ constructor(localPath: string, localDir: string);
61
+ }
62
+ /** M1-08 AC7 — a file set neither `localPath` nor `data`, or set both. */
63
+ export declare class InvalidFileInputError extends Error {
64
+ readonly path: string;
65
+ readonly code = "InvalidFileInputError";
66
+ constructor(path: string, reason: "missing" | "both");
67
+ }
68
+ /** M1-08 AC7 — `data` was not valid base64 when `encoding: "base64"` was declared. */
69
+ export declare class InvalidEncodingError extends Error {
70
+ readonly path: string;
71
+ readonly code = "InvalidEncodingError";
72
+ constructor(path: string);
73
+ }
74
+ /** M1-08 AC9 — the call's total decoded byte size exceeds the configured cap. */
75
+ export declare class PayloadTooLargeError extends Error {
76
+ readonly totalBytes: number;
77
+ readonly maxBytes: number;
78
+ readonly retryMaxFiles: number;
79
+ readonly code = "PayloadTooLargeError";
80
+ constructor(totalBytes: number, maxBytes: number, retryMaxFiles: number);
81
+ }
82
+ /**
83
+ * AC10 write-failure taxonomy now lives in the store layer (`store/interface.ts`),
84
+ * because the store owns the atomic write transaction after the DRO-565 re-plumb.
85
+ * Re-exported here so existing importers of these names from `write_files.js`
86
+ * (tests, in-process callers) keep resolving them.
87
+ */
88
+ export { RollbackIncompleteError, WriteFailedError } from "../store/interface.js";
89
+ interface FileInput {
90
+ path: string;
91
+ localPath?: string;
92
+ data?: string;
93
+ encoding?: "utf-8" | "base64";
94
+ mimeType?: string;
95
+ }
96
+ interface WriteFilesArgs {
97
+ planId: string;
98
+ files: FileInput[];
99
+ }
100
+ /**
101
+ * Register the `mcp__genie__write_files` tool.
102
+ *
103
+ * @param server The MCP server to register against. `planId`/`writes` are
104
+ * validated against the shared M1-07 plan registry
105
+ * (`../plans/index.ts`) via the M1-13 plan-guard middleware
106
+ * (`../middleware/plan-guard.ts`) — the guard owns AC5's planId
107
+ * presence/existence/expiry checks and AC4's path-vs-`writes`-
108
+ * glob check; this file's own remaining validation covers
109
+ * per-file structural rules (duplicates, localPath containment,
110
+ * encoding, byte cap) that the guard is intentionally
111
+ * tool-agnostic about.
112
+ * @param kitStore The injected kit backend (M1-14a-1b / DRO-565). The physical
113
+ * write is `kitStore.writeFiles(plan.kitId, ops)` — the kit is
114
+ * the destination (same surface read_file/list_files see), and
115
+ * the atomic rename-transaction (LocalFs) / contents-API commit
116
+ * (GitHost) lives behind that primitive. Mirrors how
117
+ * `registerDeleteFilesTool(server, kitStore)` routes deletes.
118
+ */
119
+ export declare function registerWriteFilesTool(server: McpServer, kitStore: KitStore): void;
120
+ export interface WriteFilesResult extends Record<string, unknown> {
121
+ writtenPaths: string[];
122
+ }
123
+ /**
124
+ * Validate + execute a `write_files` call against a resolved plan, committing
125
+ * the batch into the plan's KIT via the injected store.
126
+ *
127
+ * Order of validation (fails fast, before any write) — keep this list in
128
+ * lockstep with the code below; downstream steps assume every prior step has
129
+ * passed (e.g. the `resolvedLocalPaths` map keyed by `file.path` assumes step 3
130
+ * rejected duplicates):
131
+ * 1. AC5 — planId exists + not expired (`getPlan`, from the M1-07
132
+ * plan registry — throws `PlanNotFoundError` for either
133
+ * failure mode).
134
+ * 2. AC3 — `files.length <= 256`.
135
+ * 3. Structural — no two `files[]` entries share the same destination
136
+ * `path` (`DuplicatePathError`; Copilot review finding
137
+ * on PR #106).
138
+ * 4. AC4 — every `path` matches a plan `writes` glob.
139
+ * 5. Security — every destination `path` is kit-relative and contained
140
+ * (no absolute path, no `..`/`.` segment). Destinations
141
+ * resolve against the KIT now (not `localDir`), so this is
142
+ * a lexical containment check (`PathOutsidePlanError` with
143
+ * `reason: "escapesLocalDir"`; RFC §10 T-13). The store
144
+ * re-checks via `safePath` as defense-in-depth.
145
+ * 6. AC7 — every file sets exactly one of `localPath` / `data`.
146
+ * 7. AC6 — every `localPath` resolves inside the plan's `localDir`
147
+ * (the SOURCE base — where uploads are read from).
148
+ * 8. AC9 — total decoded payload size <= the configured byte cap.
149
+ * Only once every file in the batch passes is the batch handed to
150
+ * `store.writeFiles(plan.kitId, ops)` for the atomic commit (AC10).
151
+ *
152
+ * @param store The injected kit backend. The destination is `plan.kitId`; the
153
+ * physical atomic write (rename transaction on LocalFs / contents-API commit
154
+ * on GitHost) lives behind `store.writeFiles`, so this function is now purely
155
+ * validation + WriteOp assembly.
156
+ */
157
+ export declare function writeFiles(store: KitStore, args: WriteFilesArgs, env?: Record<string, string | undefined>): Promise<WriteFilesResult>;
158
+ //# sourceMappingURL=write_files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write_files.d.ts","sourceRoot":"","sources":["../../src/tools/write_files.ts"],"names":[],"mappings":"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"}