@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,199 @@
1
+ /**
2
+ * Shared kit-file helpers — MIME classification, SRI hashing, and the
3
+ * default/`.genieignore` exclusion matcher.
4
+ *
5
+ * These were previously split across `tools/read_file.ts` (MIME + binary
6
+ * detection) and `tools/list_files.ts` (SHA-256 SRI hashing, ignore matching).
7
+ * DRO-540 re-plumbs those verbs onto the `KitStore` interface, so the pure
8
+ * logic moves here to be shared by BOTH the `LocalFsKitStore` and
9
+ * `GitHostKitStore` implementations of `readFile`/`listFiles` — a `read_file`
10
+ * or `list_files` result is then byte-identical whichever adapter backs it.
11
+ *
12
+ * Nothing here touches the filesystem or the network; it operates on paths and
13
+ * bytes the adapters supply.
14
+ */
15
+ import { createHash } from "node:crypto";
16
+ import { extname } from "node:path";
17
+ import { lookup } from "mime-types";
18
+ // ─── MIME resolution + text/binary classification ────────────────────────────
19
+ /**
20
+ * Extensions that `mime-types` either misidentifies (e.g. `.ts` → `video/mp2t`)
21
+ * or doesn't know at all (`.tsx`, `.mts`, `.cts`). All are source-code text.
22
+ */
23
+ const TEXT_EXT_OVERRIDES = {
24
+ ".ts": "text/typescript",
25
+ ".tsx": "text/tsx",
26
+ ".mts": "text/typescript",
27
+ ".cts": "text/typescript",
28
+ ".svelte": "text/x-svelte",
29
+ ".vue": "text/x-vue",
30
+ ".mdx": "text/mdx",
31
+ };
32
+ /**
33
+ * MIME types (beyond the `text/*` family) that are textual and should be
34
+ * returned as utf-8 rather than base64. `mime-types` labels several source
35
+ * formats with an `application/*` type (e.g. `.cjs` → `application/node`,
36
+ * `.toml` → `application/toml`), so we treat a curated allow-list as text.
37
+ */
38
+ const TEXT_APPLICATION_MIMES = new Set([
39
+ "application/json",
40
+ "application/xml",
41
+ "application/javascript",
42
+ "application/ecmascript",
43
+ "application/node",
44
+ "application/toml",
45
+ "application/yaml",
46
+ "application/x-yaml",
47
+ "application/graphql",
48
+ "application/x-sh",
49
+ "application/x-httpd-php",
50
+ "application/sql",
51
+ "application/manifest+json",
52
+ ]);
53
+ /**
54
+ * Resolve the MIME type for a file path.
55
+ * Prefers our overrides for extensions that `mime-types` misidentifies.
56
+ */
57
+ export function resolveMime(filePath) {
58
+ const ext = extname(filePath).toLowerCase();
59
+ return TEXT_EXT_OVERRIDES[ext] ?? (lookup(filePath) || "application/octet-stream");
60
+ }
61
+ /**
62
+ * True when a MIME type is textual (returned as utf-8); everything else is
63
+ * returned as base64. Any MIME parameters (e.g. a `; charset=utf-8` suffix)
64
+ * are stripped before matching.
65
+ */
66
+ export function isTextMime(mime) {
67
+ const base = mime.split(";")[0]?.trim().toLowerCase() ?? "";
68
+ if (base.startsWith("text/"))
69
+ return true;
70
+ if (base.endsWith("+json"))
71
+ return true;
72
+ if (base.endsWith("+xml"))
73
+ return true;
74
+ if (base.endsWith("+yaml"))
75
+ return true;
76
+ return TEXT_APPLICATION_MIMES.has(base);
77
+ }
78
+ /** Strict base64 validation shared by tool-boundary and generated-file checks. */
79
+ export function isValidBase64Content(data) {
80
+ if (data.length === 0)
81
+ return true;
82
+ return /^[A-Za-z0-9+/]*={0,2}$/.test(data) && data.length % 4 === 0;
83
+ }
84
+ /**
85
+ * Classify raw file bytes into the `{ content, encoding, mimeType }` shape
86
+ * `KitStore.readFile` returns. Text files (by MIME) are decoded to utf-8;
87
+ * everything else is base64-encoded. The MIME type is derived from `path`.
88
+ */
89
+ export function classifyFileContent(path, bytes) {
90
+ const mimeType = resolveMime(path);
91
+ if (isTextMime(mimeType)) {
92
+ return { content: bytes.toString("utf-8"), encoding: "utf-8", mimeType };
93
+ }
94
+ return { content: bytes.toString("base64"), encoding: "base64", mimeType };
95
+ }
96
+ // ─── SRI hashing ─────────────────────────────────────────────────────────────
97
+ /**
98
+ * Compute a Subresource-Integrity hash (`sha256-<base64>`) over `bytes` — the
99
+ * exact form `list_files` reports and the M4 viewer's CSP references.
100
+ */
101
+ export function sriSha256(bytes) {
102
+ return `sha256-${createHash("sha256").update(bytes).digest("base64")}`;
103
+ }
104
+ // ─── kitId traversal safety ──────────────────────────────────────────────────
105
+ /**
106
+ * The ONE kitId-safety rule shared by the `list_files` and `read_file` tools
107
+ * AND both `KitStore` adapters, so their traversal defenses cannot silently
108
+ * drift apart (DRO-509 / DRO-581 unification). Lives here — not in a tool
109
+ * module — because the store layer (post-#114) also needs it, and `store/*`
110
+ * must not import from `tools/*`.
111
+ *
112
+ * A `kitId` names a single directory (LocalFs) or repo (git host) directly
113
+ * under the store's kits root. `isSafeKitId` returns false for exactly the ids
114
+ * that would let a caller escape that single-kit namespace:
115
+ *
116
+ * - the empty string — `join(kitsRoot, "")` is the kits ROOT itself, so an
117
+ * empty kitId plus a crafted `path` (e.g. `other-kit/secret.txt`) would
118
+ * read across sibling kits; it names no kit and is rejected;
119
+ * - `.` or `..` exactly — the traversal aliases for "this dir" / "the parent",
120
+ * which also resolve to the root or above it;
121
+ * - any id containing a path separator (`/` or `\`), which could introduce a
122
+ * nested or absolute path.
123
+ *
124
+ * Ids that merely EMBED dots (`my..kit`, `..kit`, `kit..`) stay a literal child
125
+ * of the root and are allowed — they simply resolve to a not-found kit if
126
+ * absent. This is deliberately looser than the pre-unification `read_file`
127
+ * guard (`kitId.includes("..")`), which over-rejected `my..kit` yet — crucially
128
+ * — MISSED both `""` and `.` (neither contains `..`), the exact holes that
129
+ * enabled the cross-kit read this rule closes.
130
+ *
131
+ * A predicate (not a throwing helper) on purpose: each caller raises its own
132
+ * error type/code (`ListFilesError` / `McpError` / `NotFoundError`) — only the
133
+ * RULE is centralised here, not the error shape.
134
+ */
135
+ export function isSafeKitId(kitId) {
136
+ if (kitId.length === 0)
137
+ return false;
138
+ if (kitId === "." || kitId === "..")
139
+ return false;
140
+ if (kitId.includes("/") || kitId.includes("\\"))
141
+ return false;
142
+ return true;
143
+ }
144
+ /**
145
+ * Directories genie always hides from a kit listing regardless of
146
+ * `.genieignore`. `.genie-tmp` is `write_files`' atomic-rename scratch space —
147
+ * excluded so a listing taken mid-write (or after a crash that orphaned a
148
+ * subdir) never surfaces genie's own bookkeeping as kit content.
149
+ */
150
+ const DEFAULT_IGNORED_SEGMENTS = ["node_modules", ".git", "dist", ".genie-tmp"];
151
+ /**
152
+ * Build a matcher that returns true for any path that should be excluded from a
153
+ * kit listing: the default-ignored dirs plus every `.genieignore` pattern.
154
+ */
155
+ export function buildIgnoreMatcher(patterns) {
156
+ const matchers = [
157
+ ...DEFAULT_IGNORED_SEGMENTS.map(segmentMatcher),
158
+ ...patterns.map(patternMatcher),
159
+ ];
160
+ return (path) => matchers.some((matcher) => matcher(path));
161
+ }
162
+ /**
163
+ * Parse a `.genieignore` file body into its active pattern lines (trimmed,
164
+ * blank + `#`-comment lines dropped). Kept here so both adapters read the same
165
+ * ignore semantics from whatever source (a file on disk, a git-host blob).
166
+ */
167
+ export function parseGenieignore(raw) {
168
+ return raw
169
+ .split(/\r?\n/)
170
+ .map((line) => line.trim())
171
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
172
+ }
173
+ function segmentMatcher(segment) {
174
+ return (path) => path.split("/").includes(segment);
175
+ }
176
+ function patternMatcher(rawPattern) {
177
+ const pattern = rawPattern.replace(/^\/+/, "");
178
+ if (pattern.endsWith("/")) {
179
+ const dir = pattern.replace(/\/+$/, "");
180
+ return (path) => path === dir || path.startsWith(`${dir}/`);
181
+ }
182
+ if (!pattern.includes("*")) {
183
+ return (path) => path === pattern || path.startsWith(`${pattern}/`);
184
+ }
185
+ const regex = globPatternToRegex(pattern);
186
+ return (path) => regex.test(path);
187
+ }
188
+ function globPatternToRegex(pattern) {
189
+ const escaped = pattern
190
+ .split("")
191
+ .map((char) => {
192
+ if (char === "*")
193
+ return "[^/]*";
194
+ return /[\\^$+?.()|[\]{}]/.test(char) ? `\\${char}` : char;
195
+ })
196
+ .join("");
197
+ return new RegExp(`^${escaped}$`);
198
+ }
199
+ //# sourceMappingURL=kit-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit-files.js","sourceRoot":"","sources":["../../src/store/kit-files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * LocalFsStore — solo-dev adapter.
3
+ *
4
+ * AC3: Stores kits under `${GENIE_HOME ?? ~/.genie}/kits/<kitId>/`
5
+ * and projects under `${GENIE_HOME ?? ~/.genie}/projects/<projectId>/`.
6
+ * Each plan is a temp staging directory.
7
+ */
8
+ import type { ComponentEntry, FileOp, KitFileContent, KitFileEntry, KitId, KitMeta, KitStore, PlanId, ProjectId, ProjectMeta, ProjectStore, WriteOp } from "./interface.js";
9
+ export declare class LocalFsKitStore implements KitStore {
10
+ private readonly baseDir;
11
+ private readonly plansDir;
12
+ constructor(baseDir?: string);
13
+ private kitDir;
14
+ /**
15
+ * Resolve a kitId to its on-disk directory for the READ verbs
16
+ * (`listFiles`/`readFile`), rejecting unsafe ids BEFORE the join (AC-SEC,
17
+ * DRO-581). This is the store-layer half of the shared `isSafeKitId` rule and
18
+ * the defense-in-depth guard behind each tool's own kitId check: a
19
+ * programmatic caller that bypasses the tool must not be able to pass `""`
20
+ * (whose `join(baseDir, "")` is the kits ROOT — letting a crafted `path` like
21
+ * `other-kit/secret.txt` read a SIBLING kit), `.`/`..`, or a separator.
22
+ *
23
+ * An unsafe id names no valid kit, so it surfaces as the SAME `NotFoundError`
24
+ * a genuinely-missing kit would — this never leaks a sibling's bytes and adds
25
+ * no new error type to the `KitStore` contract (AC4). The write/plan verbs
26
+ * (`createKit`/`deleteFile`/`openPlan`) keep using `kitDir` directly: their
27
+ * ids are server-minted or already plan-gated, and their behavior is
28
+ * unchanged.
29
+ */
30
+ private safeKitDir;
31
+ private kitMetaPath;
32
+ private planDir;
33
+ listKits(): Promise<KitMeta[]>;
34
+ getKit(kitId: KitId): Promise<KitMeta>;
35
+ listFiles(kitId: KitId): Promise<KitFileEntry[]>;
36
+ /**
37
+ * Read the kit's `.genieignore` (if any) into active pattern lines. Absent
38
+ * file → no extra patterns (the default-dir exclusion still applies).
39
+ */
40
+ private readIgnorePatterns;
41
+ listComponents(params: {
42
+ kitId: KitId;
43
+ group?: string;
44
+ }): Promise<ComponentEntry[]>;
45
+ readFile(kitId: KitId, path: string): Promise<KitFileContent>;
46
+ deleteFile(kitId: KitId, path: string): Promise<{
47
+ existed: boolean;
48
+ }>;
49
+ writeFiles(kitId: KitId, ops: WriteOp[]): Promise<{
50
+ writtenPaths: string[];
51
+ }>;
52
+ createKit(name: string, kitId?: string): Promise<KitMeta>;
53
+ openPlan(kitId: KitId, ops: FileOp[]): Promise<PlanId>;
54
+ commitPlan(kitId: KitId, planId: PlanId, ops: FileOp[]): Promise<void>;
55
+ closePlan(kitId: KitId, planId: PlanId): Promise<void>;
56
+ private applyOps;
57
+ }
58
+ export declare class LocalFsProjectStore implements ProjectStore {
59
+ private readonly baseDir;
60
+ constructor(baseDir?: string);
61
+ private projectDir;
62
+ private metaPath;
63
+ listProjects(): Promise<ProjectMeta[]>;
64
+ getProject(projectId: ProjectId): Promise<ProjectMeta>;
65
+ createProject(name: string): Promise<ProjectMeta>;
66
+ deleteProject(projectId: ProjectId): Promise<void>;
67
+ bindKit(projectId: ProjectId, kitId: KitId): Promise<void>;
68
+ recordScreen(projectId: ProjectId, screenRef: string): Promise<void>;
69
+ }
70
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/store/local.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmBH,OAAO,KAAK,EACV,cAAc,EACd,MAAM,EACN,cAAc,EACd,YAAY,EACZ,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,WAAW,EACX,YAAY,EACZ,OAAO,EACR,MAAM,gBAAgB,CAAC;AAwXxB,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,CAAC,EAAE,MAAM;IAK5B,OAAO,CAAC,MAAM;IAId;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,OAAO;IAIT,QAAQ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAmB9B,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtC,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAYtD;;;OAGG;YACW,kBAAkB;IAU1B,cAAc,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA+BnF,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgC7D,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAerE,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAY7E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+DzD,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAWtD,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9C,QAAQ;CAWvB;AAID,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,CAAC,EAAE,MAAM;IAI5B,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,QAAQ;IAIV,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAmBtC,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAWtD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAcjD,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAM3E"}