@plune-ai/cairn 0.2.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 (323) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +181 -0
  3. package/dist/agent/graph.d.ts +538 -0
  4. package/dist/agent/graph.d.ts.map +1 -0
  5. package/dist/agent/graph.js +0 -0
  6. package/dist/agent/graph.js.map +1 -0
  7. package/dist/agent/index.d.ts +83 -0
  8. package/dist/agent/index.d.ts.map +1 -0
  9. package/dist/agent/index.js +407 -0
  10. package/dist/agent/index.js.map +1 -0
  11. package/dist/analyze/index.d.ts +22 -0
  12. package/dist/analyze/index.d.ts.map +1 -0
  13. package/dist/analyze/index.js +39 -0
  14. package/dist/analyze/index.js.map +1 -0
  15. package/dist/artifacts/index.d.ts +29 -0
  16. package/dist/artifacts/index.d.ts.map +1 -0
  17. package/dist/artifacts/index.js +68 -0
  18. package/dist/artifacts/index.js.map +1 -0
  19. package/dist/artifacts/report.d.ts +21 -0
  20. package/dist/artifacts/report.d.ts.map +1 -0
  21. package/dist/artifacts/report.js +56 -0
  22. package/dist/artifacts/report.js.map +1 -0
  23. package/dist/artifacts/testcase-md.d.ts +37 -0
  24. package/dist/artifacts/testcase-md.d.ts.map +1 -0
  25. package/dist/artifacts/testcase-md.js +91 -0
  26. package/dist/artifacts/testcase-md.js.map +1 -0
  27. package/dist/browser/backends/playwright-cli.d.ts +23 -0
  28. package/dist/browser/backends/playwright-cli.d.ts.map +1 -0
  29. package/dist/browser/backends/playwright-cli.js +85 -0
  30. package/dist/browser/backends/playwright-cli.js.map +1 -0
  31. package/dist/browser/backends/playwright-lib.d.ts +32 -0
  32. package/dist/browser/backends/playwright-lib.d.ts.map +1 -0
  33. package/dist/browser/backends/playwright-lib.js +157 -0
  34. package/dist/browser/backends/playwright-lib.js.map +1 -0
  35. package/dist/browser/gateway.d.ts +33 -0
  36. package/dist/browser/gateway.d.ts.map +1 -0
  37. package/dist/browser/gateway.js +2 -0
  38. package/dist/browser/gateway.js.map +1 -0
  39. package/dist/browser/index.d.ts +15 -0
  40. package/dist/browser/index.d.ts.map +1 -0
  41. package/dist/browser/index.js +59 -0
  42. package/dist/browser/index.js.map +1 -0
  43. package/dist/browser/types.d.ts +99 -0
  44. package/dist/browser/types.d.ts.map +1 -0
  45. package/dist/browser/types.js +6 -0
  46. package/dist/browser/types.js.map +1 -0
  47. package/dist/checklist/index.d.ts +24 -0
  48. package/dist/checklist/index.d.ts.map +1 -0
  49. package/dist/checklist/index.js +65 -0
  50. package/dist/checklist/index.js.map +1 -0
  51. package/dist/cli/branding.d.ts +14 -0
  52. package/dist/cli/branding.d.ts.map +1 -0
  53. package/dist/cli/branding.js +14 -0
  54. package/dist/cli/branding.js.map +1 -0
  55. package/dist/cli/index.d.ts +12 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +322 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/lex-bot.d.ts +3 -0
  60. package/dist/cli/lex-bot.d.ts.map +1 -0
  61. package/dist/cli/lex-bot.js +11 -0
  62. package/dist/cli/lex-bot.js.map +1 -0
  63. package/dist/codegen/index.d.ts +36 -0
  64. package/dist/codegen/index.d.ts.map +1 -0
  65. package/dist/codegen/index.js +63 -0
  66. package/dist/codegen/index.js.map +1 -0
  67. package/dist/codegen/schema.d.ts +14 -0
  68. package/dist/codegen/schema.d.ts.map +1 -0
  69. package/dist/codegen/schema.js +9 -0
  70. package/dist/codegen/schema.js.map +1 -0
  71. package/dist/config/env.d.ts +18 -0
  72. package/dist/config/env.d.ts.map +1 -0
  73. package/dist/config/env.js +42 -0
  74. package/dist/config/env.js.map +1 -0
  75. package/dist/config/index.d.ts +11 -0
  76. package/dist/config/index.d.ts.map +1 -0
  77. package/dist/config/index.js +74 -0
  78. package/dist/config/index.js.map +1 -0
  79. package/dist/config/profiles.d.ts +7 -0
  80. package/dist/config/profiles.d.ts.map +1 -0
  81. package/dist/config/profiles.js +28 -0
  82. package/dist/config/profiles.js.map +1 -0
  83. package/dist/config/schema.d.ts +91 -0
  84. package/dist/config/schema.d.ts.map +1 -0
  85. package/dist/config/schema.js +20 -0
  86. package/dist/config/schema.js.map +1 -0
  87. package/dist/design/index.d.ts +36 -0
  88. package/dist/design/index.d.ts.map +1 -0
  89. package/dist/design/index.js +35 -0
  90. package/dist/design/index.js.map +1 -0
  91. package/dist/design/schema.d.ts +109 -0
  92. package/dist/design/schema.d.ts.map +1 -0
  93. package/dist/design/schema.js +35 -0
  94. package/dist/design/schema.js.map +1 -0
  95. package/dist/eval/collect.d.ts +18 -0
  96. package/dist/eval/collect.d.ts.map +1 -0
  97. package/dist/eval/collect.js +53 -0
  98. package/dist/eval/collect.js.map +1 -0
  99. package/dist/eval/experiment.d.ts +49 -0
  100. package/dist/eval/experiment.d.ts.map +1 -0
  101. package/dist/eval/experiment.js +66 -0
  102. package/dist/eval/experiment.js.map +1 -0
  103. package/dist/eval/judge.d.ts +30 -0
  104. package/dist/eval/judge.d.ts.map +1 -0
  105. package/dist/eval/judge.js +47 -0
  106. package/dist/eval/judge.js.map +1 -0
  107. package/dist/eval/pilot.d.ts +21 -0
  108. package/dist/eval/pilot.d.ts.map +1 -0
  109. package/dist/eval/pilot.js +24 -0
  110. package/dist/eval/pilot.js.map +1 -0
  111. package/dist/eval/scorers.d.ts +23 -0
  112. package/dist/eval/scorers.d.ts.map +1 -0
  113. package/dist/eval/scorers.js +38 -0
  114. package/dist/eval/scorers.js.map +1 -0
  115. package/dist/index.d.ts +21 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +13 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/knowledge/index.d.ts +7 -0
  120. package/dist/knowledge/index.d.ts.map +1 -0
  121. package/dist/knowledge/index.js +39 -0
  122. package/dist/knowledge/index.js.map +1 -0
  123. package/dist/llm/factory.d.ts +31 -0
  124. package/dist/llm/factory.d.ts.map +1 -0
  125. package/dist/llm/factory.js +48 -0
  126. package/dist/llm/factory.js.map +1 -0
  127. package/dist/llm/index.d.ts +5 -0
  128. package/dist/llm/index.d.ts.map +1 -0
  129. package/dist/llm/index.js +3 -0
  130. package/dist/llm/index.js.map +1 -0
  131. package/dist/llm/structured.d.ts +30 -0
  132. package/dist/llm/structured.d.ts.map +1 -0
  133. package/dist/llm/structured.js +58 -0
  134. package/dist/llm/structured.js.map +1 -0
  135. package/dist/llm/vision.d.ts +16 -0
  136. package/dist/llm/vision.d.ts.map +1 -0
  137. package/dist/llm/vision.js +4 -0
  138. package/dist/llm/vision.js.map +1 -0
  139. package/dist/observe/index.d.ts +21 -0
  140. package/dist/observe/index.d.ts.map +1 -0
  141. package/dist/observe/index.js +18 -0
  142. package/dist/observe/index.js.map +1 -0
  143. package/dist/observe/parse-aria.d.ts +8 -0
  144. package/dist/observe/parse-aria.d.ts.map +1 -0
  145. package/dist/observe/parse-aria.js +71 -0
  146. package/dist/observe/parse-aria.js.map +1 -0
  147. package/dist/probe/index.d.ts +19 -0
  148. package/dist/probe/index.d.ts.map +1 -0
  149. package/dist/probe/index.js +38 -0
  150. package/dist/probe/index.js.map +1 -0
  151. package/dist/promote/index.d.ts +6 -0
  152. package/dist/promote/index.d.ts.map +1 -0
  153. package/dist/promote/index.js +4 -0
  154. package/dist/promote/index.js.map +1 -0
  155. package/dist/promote/promote-case.d.ts +12 -0
  156. package/dist/promote/promote-case.d.ts.map +1 -0
  157. package/dist/promote/promote-case.js +103 -0
  158. package/dist/promote/promote-case.js.map +1 -0
  159. package/dist/promote/selectors.d.ts +29 -0
  160. package/dist/promote/selectors.d.ts.map +1 -0
  161. package/dist/promote/selectors.js +58 -0
  162. package/dist/promote/selectors.js.map +1 -0
  163. package/dist/prompts/index.d.ts +32 -0
  164. package/dist/prompts/index.d.ts.map +1 -0
  165. package/dist/prompts/index.js +55 -0
  166. package/dist/prompts/index.js.map +1 -0
  167. package/dist/prompts/local/identify-elements.d.ts +6 -0
  168. package/dist/prompts/local/identify-elements.d.ts.map +1 -0
  169. package/dist/prompts/local/identify-elements.js +21 -0
  170. package/dist/prompts/local/identify-elements.js.map +1 -0
  171. package/dist/prompts/local/index.d.ts +3 -0
  172. package/dist/prompts/local/index.d.ts.map +1 -0
  173. package/dist/prompts/local/index.js +18 -0
  174. package/dist/prompts/local/index.js.map +1 -0
  175. package/dist/prompts/local/judge-checklist-coverage.d.ts +3 -0
  176. package/dist/prompts/local/judge-checklist-coverage.d.ts.map +1 -0
  177. package/dist/prompts/local/judge-checklist-coverage.js +11 -0
  178. package/dist/prompts/local/judge-checklist-coverage.js.map +1 -0
  179. package/dist/prompts/local/judge-test-cases.d.ts +3 -0
  180. package/dist/prompts/local/judge-test-cases.d.ts.map +1 -0
  181. package/dist/prompts/local/judge-test-cases.js +11 -0
  182. package/dist/prompts/local/judge-test-cases.js.map +1 -0
  183. package/dist/prompts/local/pilot-review.d.ts +3 -0
  184. package/dist/prompts/local/pilot-review.d.ts.map +1 -0
  185. package/dist/prompts/local/pilot-review.js +13 -0
  186. package/dist/prompts/local/pilot-review.js.map +1 -0
  187. package/dist/prompts/local/qa-manual-test-designer.d.ts +7 -0
  188. package/dist/prompts/local/qa-manual-test-designer.d.ts.map +1 -0
  189. package/dist/prompts/local/qa-manual-test-designer.js +13 -0
  190. package/dist/prompts/local/qa-manual-test-designer.js.map +1 -0
  191. package/dist/prompts/local/qa-playwright-ts-writer.d.ts +6 -0
  192. package/dist/prompts/local/qa-playwright-ts-writer.d.ts.map +1 -0
  193. package/dist/prompts/local/qa-playwright-ts-writer.js +40 -0
  194. package/dist/prompts/local/qa-playwright-ts-writer.js.map +1 -0
  195. package/dist/prompts/local/qa-testcase-from-ui.d.ts +6 -0
  196. package/dist/prompts/local/qa-testcase-from-ui.d.ts.map +1 -0
  197. package/dist/prompts/local/qa-testcase-from-ui.js +52 -0
  198. package/dist/prompts/local/qa-testcase-from-ui.js.map +1 -0
  199. package/dist/session/index.d.ts +27 -0
  200. package/dist/session/index.d.ts.map +1 -0
  201. package/dist/session/index.js +74 -0
  202. package/dist/session/index.js.map +1 -0
  203. package/dist/telemetry/index.d.ts +21 -0
  204. package/dist/telemetry/index.d.ts.map +1 -0
  205. package/dist/telemetry/index.js +26 -0
  206. package/dist/telemetry/index.js.map +1 -0
  207. package/dist/tui/App.d.ts +6 -0
  208. package/dist/tui/App.d.ts.map +1 -0
  209. package/dist/tui/App.js +61 -0
  210. package/dist/tui/App.js.map +1 -0
  211. package/dist/tui/components/error-boundary.d.ts +17 -0
  212. package/dist/tui/components/error-boundary.d.ts.map +1 -0
  213. package/dist/tui/components/error-boundary.js +20 -0
  214. package/dist/tui/components/error-boundary.js.map +1 -0
  215. package/dist/tui/components/field.d.ts +10 -0
  216. package/dist/tui/components/field.d.ts.map +1 -0
  217. package/dist/tui/components/field.js +8 -0
  218. package/dist/tui/components/field.js.map +1 -0
  219. package/dist/tui/components/help.d.ts +5 -0
  220. package/dist/tui/components/help.d.ts.map +1 -0
  221. package/dist/tui/components/help.js +7 -0
  222. package/dist/tui/components/help.js.map +1 -0
  223. package/dist/tui/components/log-pane.d.ts +6 -0
  224. package/dist/tui/components/log-pane.d.ts.map +1 -0
  225. package/dist/tui/components/log-pane.js +10 -0
  226. package/dist/tui/components/log-pane.js.map +1 -0
  227. package/dist/tui/components/node-checklist.d.ts +6 -0
  228. package/dist/tui/components/node-checklist.d.ts.map +1 -0
  229. package/dist/tui/components/node-checklist.js +9 -0
  230. package/dist/tui/components/node-checklist.js.map +1 -0
  231. package/dist/tui/components/pilot-badge.d.ts +6 -0
  232. package/dist/tui/components/pilot-badge.d.ts.map +1 -0
  233. package/dist/tui/components/pilot-badge.js +12 -0
  234. package/dist/tui/components/pilot-badge.js.map +1 -0
  235. package/dist/tui/components/scores-table.d.ts +6 -0
  236. package/dist/tui/components/scores-table.d.ts.map +1 -0
  237. package/dist/tui/components/scores-table.js +9 -0
  238. package/dist/tui/components/scores-table.js.map +1 -0
  239. package/dist/tui/components/scrollable-text.d.ts +6 -0
  240. package/dist/tui/components/scrollable-text.d.ts.map +1 -0
  241. package/dist/tui/components/scrollable-text.js +22 -0
  242. package/dist/tui/components/scrollable-text.js.map +1 -0
  243. package/dist/tui/components/session-picker.d.ts +5 -0
  244. package/dist/tui/components/session-picker.d.ts.map +1 -0
  245. package/dist/tui/components/session-picker.js +16 -0
  246. package/dist/tui/components/session-picker.js.map +1 -0
  247. package/dist/tui/components/test-case-list.d.ts +7 -0
  248. package/dist/tui/components/test-case-list.d.ts.map +1 -0
  249. package/dist/tui/components/test-case-list.js +10 -0
  250. package/dist/tui/components/test-case-list.js.map +1 -0
  251. package/dist/tui/hooks/use-run-artifacts.d.ts +14 -0
  252. package/dist/tui/hooks/use-run-artifacts.d.ts.map +1 -0
  253. package/dist/tui/hooks/use-run-artifacts.js +37 -0
  254. package/dist/tui/hooks/use-run-artifacts.js.map +1 -0
  255. package/dist/tui/hooks/use-runner.d.ts +25 -0
  256. package/dist/tui/hooks/use-runner.d.ts.map +1 -0
  257. package/dist/tui/hooks/use-runner.js +116 -0
  258. package/dist/tui/hooks/use-runner.js.map +1 -0
  259. package/dist/tui/hooks/use-runs.d.ts +14 -0
  260. package/dist/tui/hooks/use-runs.d.ts.map +1 -0
  261. package/dist/tui/hooks/use-runs.js +57 -0
  262. package/dist/tui/hooks/use-runs.js.map +1 -0
  263. package/dist/tui/hooks/use-sessions.d.ts +10 -0
  264. package/dist/tui/hooks/use-sessions.d.ts.map +1 -0
  265. package/dist/tui/hooks/use-sessions.js +32 -0
  266. package/dist/tui/hooks/use-sessions.js.map +1 -0
  267. package/dist/tui/hooks/use-stdout-dimensions.d.ts +3 -0
  268. package/dist/tui/hooks/use-stdout-dimensions.d.ts.map +1 -0
  269. package/dist/tui/hooks/use-stdout-dimensions.js +18 -0
  270. package/dist/tui/hooks/use-stdout-dimensions.js.map +1 -0
  271. package/dist/tui/index.d.ts +7 -0
  272. package/dist/tui/index.d.ts.map +1 -0
  273. package/dist/tui/index.js +13 -0
  274. package/dist/tui/index.js.map +1 -0
  275. package/dist/tui/router-context.d.ts +12 -0
  276. package/dist/tui/router-context.d.ts.map +1 -0
  277. package/dist/tui/router-context.js +14 -0
  278. package/dist/tui/router-context.js.map +1 -0
  279. package/dist/tui/router.d.ts +44 -0
  280. package/dist/tui/router.d.ts.map +1 -0
  281. package/dist/tui/router.js +22 -0
  282. package/dist/tui/router.js.map +1 -0
  283. package/dist/tui/screens/form-screen.d.ts +7 -0
  284. package/dist/tui/screens/form-screen.d.ts.map +1 -0
  285. package/dist/tui/screens/form-screen.js +104 -0
  286. package/dist/tui/screens/form-screen.js.map +1 -0
  287. package/dist/tui/screens/launcher-screen.d.ts +2 -0
  288. package/dist/tui/screens/launcher-screen.d.ts.map +1 -0
  289. package/dist/tui/screens/launcher-screen.js +28 -0
  290. package/dist/tui/screens/launcher-screen.js.map +1 -0
  291. package/dist/tui/screens/run-dashboard-screen.d.ts +7 -0
  292. package/dist/tui/screens/run-dashboard-screen.d.ts.map +1 -0
  293. package/dist/tui/screens/run-dashboard-screen.js +32 -0
  294. package/dist/tui/screens/run-dashboard-screen.js.map +1 -0
  295. package/dist/tui/screens/run-detail-screen.d.ts +5 -0
  296. package/dist/tui/screens/run-detail-screen.d.ts.map +1 -0
  297. package/dist/tui/screens/run-detail-screen.js +67 -0
  298. package/dist/tui/screens/run-detail-screen.js.map +1 -0
  299. package/dist/tui/screens/runs-list-screen.d.ts +2 -0
  300. package/dist/tui/screens/runs-list-screen.d.ts.map +1 -0
  301. package/dist/tui/screens/runs-list-screen.js +22 -0
  302. package/dist/tui/screens/runs-list-screen.js.map +1 -0
  303. package/dist/tui/screens/summary-screen.d.ts +6 -0
  304. package/dist/tui/screens/summary-screen.d.ts.map +1 -0
  305. package/dist/tui/screens/summary-screen.js +53 -0
  306. package/dist/tui/screens/summary-screen.js.map +1 -0
  307. package/dist/tui/theme.d.ts +31 -0
  308. package/dist/tui/theme.d.ts.map +1 -0
  309. package/dist/tui/theme.js +70 -0
  310. package/dist/tui/theme.js.map +1 -0
  311. package/dist/tui/types.d.ts +38 -0
  312. package/dist/tui/types.d.ts.map +1 -0
  313. package/dist/tui/types.js +2 -0
  314. package/dist/tui/types.js.map +1 -0
  315. package/dist/validate/index.d.ts +30 -0
  316. package/dist/validate/index.d.ts.map +1 -0
  317. package/dist/validate/index.js +39 -0
  318. package/dist/validate/index.js.map +1 -0
  319. package/dist/validate/runner.d.ts +15 -0
  320. package/dist/validate/runner.d.ts.map +1 -0
  321. package/dist/validate/runner.js +74 -0
  322. package/dist/validate/runner.js.map +1 -0
  323. package/package.json +97 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.d.ts","sourceRoot":"","sources":["../../src/llm/vision.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAE3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAc,GAAG,UAAU,CAE/E"}
@@ -0,0 +1,4 @@
1
+ export function imageBlock(dataB64, mediaType = "image/png") {
2
+ return { type: "image_url", image_url: { url: `data:${mediaType};base64,${dataB64}` } };
3
+ }
4
+ //# sourceMappingURL=vision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.js","sourceRoot":"","sources":["../../src/llm/vision.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,SAAS,GAAG,WAAW;IACjE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,SAAS,WAAW,OAAO,EAAE,EAAE,EAAE,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { BrowserGateway } from "../browser/gateway.js";
2
+ import type { BackendKind, ElementRef } from "../browser/types.js";
3
+ export { parseAriaSnapshot } from "./parse-aria.js";
4
+ /** Model-ready normalized page observation. */
5
+ export interface PageStudy {
6
+ url: string;
7
+ screenshotB64: string;
8
+ ariaYaml: string;
9
+ elements: ElementRef[];
10
+ capturedBy: BackendKind;
11
+ /** Page JS errors (console.error + uncaught), if the backend captures them. */
12
+ consoleErrors?: string[];
13
+ }
14
+ /**
15
+ * Explore the page through the gateway and normalize it into a `PageStudy`
16
+ * (the same shape regardless of the backend — ADR-0003).
17
+ */
18
+ export declare function capture(gateway: BrowserGateway, url: string, opts?: {
19
+ fullPage?: boolean;
20
+ }): Promise<PageStudy>;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observe/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,WAAW,CAAC;IACxB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAChC,OAAO,CAAC,SAAS,CAAC,CAUpB"}
@@ -0,0 +1,18 @@
1
+ import { parseAriaSnapshot } from "./parse-aria.js";
2
+ export { parseAriaSnapshot } from "./parse-aria.js";
3
+ /**
4
+ * Explore the page through the gateway and normalize it into a `PageStudy`
5
+ * (the same shape regardless of the backend — ADR-0003).
6
+ */
7
+ export async function capture(gateway, url, opts = {}) {
8
+ const obs = await gateway.observe({ url, fullPage: opts.fullPage });
9
+ return {
10
+ url: obs.url,
11
+ screenshotB64: obs.screenshotB64,
12
+ ariaYaml: obs.ariaSnapshot,
13
+ elements: parseAriaSnapshot(obs.ariaSnapshot),
14
+ capturedBy: obs.capturedBy,
15
+ consoleErrors: obs.consoleErrors,
16
+ };
17
+ }
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/observe/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAapD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAuB,EACvB,GAAW,EACX,OAA+B,EAAE;IAEjC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpE,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,QAAQ,EAAE,GAAG,CAAC,YAAY;QAC1B,QAAQ,EAAE,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC;QAC7C,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,aAAa,EAAE,GAAG,CAAC,aAAa;KACjC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ElementRef } from "../browser/types.js";
2
+ /**
3
+ * Parses the Playwright `ariaSnapshot()` output (YAML-like) into ranked `ElementRef[]`
4
+ * in document order. Skips property lines (`/url`, `/checked`…) and text nodes (`text:`).
5
+ * A pure function — fully testable without a browser.
6
+ */
7
+ export declare function parseAriaSnapshot(aria: string): ElementRef[];
8
+ //# sourceMappingURL=parse-aria.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-aria.d.ts","sourceRoot":"","sources":["../../src/observe/parse-aria.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA6CtD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAuB5D"}
@@ -0,0 +1,71 @@
1
+ /** Roles the user interacts with (priority for test cases). */
2
+ const INTERACTIVE = new Set([
3
+ "button",
4
+ "link",
5
+ "textbox",
6
+ "checkbox",
7
+ "radio",
8
+ "combobox",
9
+ "listbox",
10
+ "option",
11
+ "switch",
12
+ "slider",
13
+ "searchbox",
14
+ "spinbutton",
15
+ "menuitem",
16
+ "menuitemcheckbox",
17
+ "menuitemradio",
18
+ "tab",
19
+ "gridcell",
20
+ "treeitem",
21
+ ]);
22
+ /** Semantic containers — low but non-zero priority. */
23
+ const LANDMARK = new Set([
24
+ "main",
25
+ "navigation",
26
+ "banner",
27
+ "complementary",
28
+ "contentinfo",
29
+ "region",
30
+ "form",
31
+ "search",
32
+ "article",
33
+ "dialog",
34
+ ]);
35
+ function rankFor(role, interactive) {
36
+ if (interactive)
37
+ return 3;
38
+ if (role === "heading")
39
+ return 2;
40
+ if (LANDMARK.has(role))
41
+ return 1;
42
+ return 0;
43
+ }
44
+ /**
45
+ * Parses the Playwright `ariaSnapshot()` output (YAML-like) into ranked `ElementRef[]`
46
+ * in document order. Skips property lines (`/url`, `/checked`…) and text nodes (`text:`).
47
+ * A pure function — fully testable without a browser.
48
+ */
49
+ export function parseAriaSnapshot(aria) {
50
+ const out = [];
51
+ let n = 0;
52
+ for (const raw of aria.split(/\r?\n/)) {
53
+ const line = raw.trimStart();
54
+ if (!line.startsWith("- "))
55
+ continue;
56
+ const content = line.slice(2).trim();
57
+ if (content.startsWith("/"))
58
+ continue; // property: /url, /checked, /disabled…
59
+ const role = content.match(/^([a-zA-Z][\w-]*)/)?.[1];
60
+ if (!role || role === "text")
61
+ continue; // text node or unparseable
62
+ const name = content.match(/"([^"]*)"/)?.[1];
63
+ // A native ref from the cli/MCP snapshot (`[ref=e15]`) takes priority over a synthesized one.
64
+ const nativeRef = content.match(/\[ref=([^\]\s]+)\]/)?.[1];
65
+ const interactive = INTERACTIVE.has(role);
66
+ n += 1;
67
+ out.push({ ref: nativeRef ?? `e${n}`, role, name, interactive, rank: rankFor(role, interactive) });
68
+ }
69
+ return out;
70
+ }
71
+ //# sourceMappingURL=parse-aria.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-aria.js","sourceRoot":"","sources":["../../src/observe/parse-aria.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,QAAQ;IACR,MAAM;IACN,SAAS;IACT,UAAU;IACV,OAAO;IACP,UAAU;IACV,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,WAAW;IACX,YAAY;IACZ,UAAU;IACV,kBAAkB;IAClB,eAAe;IACf,KAAK;IACL,UAAU;IACV,UAAU;CACX,CAAC,CAAC;AAEH,uDAAuD;AACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;IACvB,MAAM;IACN,YAAY;IACZ,QAAQ;IACR,eAAe;IACf,aAAa;IACb,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,SAAS;IACT,QAAQ;CACT,CAAC,CAAC;AAEH,SAAS,OAAO,CAAC,IAAY,EAAE,WAAoB;IACjD,IAAI,WAAW;QAAE,OAAO,CAAC,CAAC;IAC1B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACjC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAErC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,uCAAuC;QAE9E,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,MAAM;YAAE,SAAS,CAAC,2BAA2B;QAEnE,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,8FAA8F;QAC9F,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC,IAAI,CAAC,CAAC;QACP,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IACrG,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { BrowserGateway } from "../browser/index.js";
2
+ import type { ElementRef, ElementState } from "../browser/types.js";
3
+ /** An observed state transition after a safe action (act→observe). */
4
+ export interface Transition {
5
+ ref: string;
6
+ role: string;
7
+ name?: string;
8
+ before: ElementState;
9
+ after: ElementState;
10
+ }
11
+ /** Convert transitions into text for the prompt (designer/codegen ground assertions on them). */
12
+ export declare function formatTransitions(transitions: Transition[]): string;
13
+ /**
14
+ * Stage B grounding: for safe (reversible) elements, perform a click, OBSERVE the state transition,
15
+ * and revert it. Does NOT touch buttons (submit/delete), links (navigation), or file inputs.
16
+ * Gives the designer real transitions instead of guessed ones → grounds state-transition assertions.
17
+ */
18
+ export declare function probeTransitions(gateway: BrowserGateway, elements: ElementRef[]): Promise<Transition[]>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/probe/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;CACrB;AAKD,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAWnE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,UAAU,EAAE,GACrB,OAAO,CAAC,UAAU,EAAE,CAAC,CAevB"}
@@ -0,0 +1,38 @@
1
+ /** Reversible roles that are safe to click (restored by a reverse click). */
2
+ const SAFE_ROLES = new Set(["switch", "checkbox", "radio"]);
3
+ /** Convert transitions into text for the prompt (designer/codegen ground assertions on them). */
4
+ export function formatTransitions(transitions) {
5
+ if (transitions.length === 0)
6
+ return "(no observed transitions — assertions on the static state only)";
7
+ return transitions
8
+ .map((t) => {
9
+ const change = t.before.checked !== undefined && t.after.checked !== undefined
10
+ ? `checked ${t.before.checked}→${t.after.checked}`
11
+ : `enabled ${t.before.enabled}→${t.after.enabled}`;
12
+ return `- click ${t.ref} (${t.role}${t.name ? ` "${t.name}"` : ""}): ${change}`;
13
+ })
14
+ .join("\n");
15
+ }
16
+ /**
17
+ * Stage B grounding: for safe (reversible) elements, perform a click, OBSERVE the state transition,
18
+ * and revert it. Does NOT touch buttons (submit/delete), links (navigation), or file inputs.
19
+ * Gives the designer real transitions instead of guessed ones → grounds state-transition assertions.
20
+ */
21
+ export async function probeTransitions(gateway, elements) {
22
+ const out = [];
23
+ for (const el of elements) {
24
+ if (!SAFE_ROLES.has(el.role))
25
+ continue;
26
+ const before = await gateway.getState(el);
27
+ if (!before.visible || !before.enabled)
28
+ continue; // don't touch hidden/disabled
29
+ const clicked = await gateway.act({ kind: "click", ref: el.ref });
30
+ if (!clicked.ok)
31
+ continue;
32
+ const after = await gateway.getState(el);
33
+ await gateway.act({ kind: "click", ref: el.ref }).catch(() => undefined); // revert (reversibility)
34
+ out.push({ ref: el.ref, role: el.role, name: el.name, before, after });
35
+ }
36
+ return out;
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/probe/index.ts"],"names":[],"mappings":"AAYA,6EAA6E;AAC7E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5D,iGAAiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,WAAyB;IACzD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,iEAAiE,CAAC;IACvG,OAAO,WAAW;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,MAAM,GACV,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS;YAC7D,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE;YAClD,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACvD,OAAO,WAAW,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IAClF,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAuB,EACvB,QAAsB;IAEtB,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;YAAE,SAAS;QACvC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,SAAS,CAAC,8BAA8B;QAEhF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,SAAS;QAC1B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB;QAEnG,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { promoteCase } from "./promote-case.js";
2
+ export type { PromoteResult } from "./promote-case.js";
3
+ export { collectSelectors } from "./selectors.js";
4
+ export type { PromoteDeps, CollectedSelectors } from "./selectors.js";
5
+ export { locatorFor } from "../artifacts/report.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/promote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { promoteCase } from "./promote-case.js";
2
+ export { collectSelectors } from "./selectors.js";
3
+ export { locatorFor } from "../artifacts/report.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/promote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type PromoteDeps } from "./selectors.js";
2
+ export interface PromoteResult {
3
+ oldId: string;
4
+ newId: string;
5
+ oldFile: string;
6
+ newFile: string;
7
+ selectorsFilled: number;
8
+ missingRefs: string[];
9
+ warning?: string;
10
+ }
11
+ export declare function promoteCase(runDir: string, caseId: string, deps?: PromoteDeps): Promise<PromoteResult>;
12
+ //# sourceMappingURL=promote-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote-case.d.ts","sourceRoot":"","sources":["../../src/promote/promote-case.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,aAAa,CAAC,CAyCxB"}
@@ -0,0 +1,103 @@
1
+ import { readFile, writeFile, readdir, unlink } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { parseTestCaseMd } from "../artifacts/testcase-md.js";
4
+ import { collectSelectors } from "./selectors.js";
5
+ /** MTC-<SUITE>-NNN → <SUITE> (suite may contain dashes; strip leading kind + trailing number). */
6
+ function suiteOf(id) {
7
+ const m = id.match(/^(?:MTC|ATC)-(.+)-(\d+)$/);
8
+ return m?.[1] ?? "";
9
+ }
10
+ function escapeRe(s) {
11
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12
+ }
13
+ /** Next free ATC number for a suite, scanning testcases/ filenames. */
14
+ async function nextAtcNumber(tcDir, suite) {
15
+ const files = await readdir(tcDir);
16
+ const re = new RegExp(`^ATC-${escapeRe(suite)}-(\\d+)\\.md$`);
17
+ let max = 0;
18
+ for (const f of files) {
19
+ const m = f.match(re);
20
+ if (m?.[1] != null)
21
+ max = Math.max(max, Number(m[1]));
22
+ }
23
+ return max + 1;
24
+ }
25
+ /** Replace (or insert) a key in the leading `---` frontmatter block. */
26
+ function setFrontmatter(md, key, value) {
27
+ const fmEnd = md.indexOf("\n---\n");
28
+ if (fmEnd === -1)
29
+ return md; // no frontmatter — bail
30
+ const fm = md.slice(0, fmEnd);
31
+ const rest = md.slice(fmEnd);
32
+ const re = new RegExp(`^(${escapeRe(key)}:).*$`, "m");
33
+ if (re.test(fm))
34
+ return fm.replace(re, `$1 ${value}`) + rest;
35
+ return `${fm}\n${key}: ${value}${rest}`;
36
+ }
37
+ /** Recover elementRefs by matching the case title against report.json. */
38
+ async function elementRefsForTitle(runDir, title) {
39
+ try {
40
+ const rep = JSON.parse(await readFile(join(runDir, "report.json"), "utf8"));
41
+ const hit = (rep.testCases ?? []).find((t) => t.title === title);
42
+ return hit?.elementRefs ?? [];
43
+ }
44
+ catch {
45
+ return [];
46
+ }
47
+ }
48
+ /** Insert a `## Selectors` table after the body (if absent). */
49
+ function injectSelectors(md, selectors) {
50
+ if (selectors.length === 0 || md.includes("## Selectors"))
51
+ return md;
52
+ const rows = selectors.map((s) => `| ${s.label} | \`${s.locator}\` |`).join("\n");
53
+ const block = `\n## Selectors (recorded during promote)\n\n| Element | Locator |\n| --- | --- |\n${rows}\n`;
54
+ return md.trimEnd() + "\n" + block;
55
+ }
56
+ /** Append a "Promoted from" row to the ## Traceability section (create it if absent). */
57
+ function appendTraceability(md, oldId) {
58
+ const row = `| Promoted from | ${oldId} |`;
59
+ const m = md.match(/## Traceability\b[\s\S]*?(?=\n## |\n*$)/);
60
+ if (m) {
61
+ const section = m[0].trimEnd();
62
+ return md.replace(m[0], () => `${section}\n${row}`);
63
+ }
64
+ return `${md.trimEnd()}\n\n## Traceability\n\n| Source | Reference |\n| --- | --- |\n${row}\n`;
65
+ }
66
+ export async function promoteCase(runDir, caseId, deps = {}) {
67
+ if (!caseId.startsWith("MTC")) {
68
+ throw new Error(`Cannot promote ${caseId}: only MTC-* (manual) cases can be promoted.`);
69
+ }
70
+ const tcDir = join(runDir, "testcases");
71
+ const oldFile = join(tcDir, `${caseId}.md`);
72
+ const md = await readFile(oldFile, "utf8");
73
+ const parsed = parseTestCaseMd(md);
74
+ const suite = suiteOf(caseId);
75
+ const num = await nextAtcNumber(tcDir, suite);
76
+ const newId = `ATC-${suite}-${String(num).padStart(3, "0")}`;
77
+ const newFile = join(tcDir, `${newId}.md`);
78
+ let selectorsFilled = 0;
79
+ let missingRefs = [];
80
+ let updated = md;
81
+ if (parsed.selectors.length === 0) {
82
+ const refs = await elementRefsForTitle(runDir, parsed.title);
83
+ const { selectors, missing } = await collectSelectors(runDir, refs, deps);
84
+ selectorsFilled = selectors.length;
85
+ missingRefs = missing;
86
+ updated = injectSelectors(updated, selectors);
87
+ }
88
+ const automation = `tests/ui/${suite.toLowerCase()}/${newId.toLowerCase()}.spec.ts`;
89
+ updated = setFrontmatter(updated, "id", newId);
90
+ updated = setFrontmatter(updated, "execution", "auto");
91
+ updated = setFrontmatter(updated, "status", "❌ Not implemented");
92
+ updated = setFrontmatter(updated, "automation", automation);
93
+ updated = updated.replace(/^(#\s+)(?:MTC|ATC)-[A-Za-z0-9-]+-\d+(:)/m, `$1${newId}$2`);
94
+ updated = appendTraceability(updated, caseId);
95
+ await writeFile(newFile, updated, "utf8");
96
+ if (newFile !== oldFile)
97
+ await unlink(oldFile); // in-place rename
98
+ const warning = missingRefs.length > 0
99
+ ? `${missingRefs.length} ref(s) without a selector — generated code will be incomplete.`
100
+ : undefined;
101
+ return { oldId: caseId, newId, oldFile, newFile, selectorsFilled, missingRefs, warning };
102
+ }
103
+ //# sourceMappingURL=promote-case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote-case.js","sourceRoot":"","sources":["../../src/promote/promote-case.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface PromoteDeps {
2
+ /**
3
+ * Live browser fallback for refs missing from study.json. Omit → offline-only.
4
+ *
5
+ * Returns a `Map<ref, locator>` only — element names are not available in the
6
+ * live path, so any selector produced here will be labeled by its ref string
7
+ * (e.g. `"e99"`) rather than a human-readable name.
8
+ */
9
+ collectLive?: (url: string, refs: string[]) => Promise<Map<string, string>>;
10
+ }
11
+ export interface CollectedSelectors {
12
+ selectors: {
13
+ label: string;
14
+ locator: string;
15
+ }[];
16
+ missing: string[];
17
+ }
18
+ /**
19
+ * Build selectors for the given elementRefs.
20
+ *
21
+ * Resolution order: study.json (offline) → optional live browser fallback.
22
+ *
23
+ * **Label convention:**
24
+ * - Elements found in study.json → `label` is `name ?? role` (human-readable).
25
+ * - Elements found only via `collectLive` → `label` is the ref string (e.g. `"e99"`),
26
+ * because the live path returns locators only and does not expose element names.
27
+ */
28
+ export declare function collectSelectors(runDir: string, elementRefs: string[], deps?: PromoteDeps): Promise<CollectedSelectors>;
29
+ //# sourceMappingURL=selectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/promote/selectors.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EAAE,EACrB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA0C7B"}
@@ -0,0 +1,58 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { locatorFor } from "../artifacts/report.js";
4
+ /**
5
+ * Build selectors for the given elementRefs.
6
+ *
7
+ * Resolution order: study.json (offline) → optional live browser fallback.
8
+ *
9
+ * **Label convention:**
10
+ * - Elements found in study.json → `label` is `name ?? role` (human-readable).
11
+ * - Elements found only via `collectLive` → `label` is the ref string (e.g. `"e99"`),
12
+ * because the live path returns locators only and does not expose element names.
13
+ */
14
+ export async function collectSelectors(runDir, elementRefs, deps = {}) {
15
+ let elements = [];
16
+ try {
17
+ const study = JSON.parse(await readFile(join(runDir, "study.json"), "utf8"));
18
+ elements = study.elements ?? [];
19
+ }
20
+ catch {
21
+ // no study.json — every ref is missing (live fallback may still fill them)
22
+ }
23
+ const byRef = new Map(elements.map((e) => [e.ref, e]));
24
+ const selectors = [];
25
+ const missing = [];
26
+ for (const ref of elementRefs) {
27
+ const el = byRef.get(ref);
28
+ if (el)
29
+ selectors.push({ label: el.name ?? el.role, locator: locatorFor(el) });
30
+ else
31
+ missing.push(ref);
32
+ }
33
+ if (missing.length === 0 || !deps.collectLive)
34
+ return { selectors, missing };
35
+ let url = "";
36
+ try {
37
+ const rep = JSON.parse(await readFile(join(runDir, "report.json"), "utf8"));
38
+ url = rep.url ?? "";
39
+ }
40
+ catch {
41
+ // no report.json → cannot navigate
42
+ }
43
+ if (!url) {
44
+ // collectLive provided but no url available → cannot navigate; leave refs in missing
45
+ return { selectors, missing };
46
+ }
47
+ const live = await deps.collectLive(url, missing);
48
+ const stillMissing = [];
49
+ for (const ref of missing) {
50
+ const loc = live.get(ref);
51
+ if (loc)
52
+ selectors.push({ label: ref, locator: loc });
53
+ else
54
+ stillMissing.push(ref);
55
+ }
56
+ return { selectors, missing: stillMissing };
57
+ }
58
+ //# sourceMappingURL=selectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.js","sourceRoot":"","sources":["../../src/promote/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAmBpD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,WAAqB,EACrB,OAAoB,EAAE;IAEtB,IAAI,QAAQ,GAAiB,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAE1E,CAAC;QACF,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;IAC7E,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,MAAM,SAAS,GAAyC,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,EAAE;YAAE,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;YAC1E,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IAE7E,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAqB,CAAC;QAChG,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IACD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,qFAAqF;QACrF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,GAAG;YAAE,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;;YACjD,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,32 @@
1
+ export { LOCAL_PROMPTS } from "./local/index.js";
2
+ export interface CompiledPrompt {
3
+ name: string;
4
+ text: string;
5
+ version: number | "local";
6
+ isFallback: boolean;
7
+ }
8
+ /** Source of versioned prompts (e.g. Langfuse). Returns null if the prompt is absent. */
9
+ export interface PromptFetcher {
10
+ fetch(name: string): Promise<{
11
+ text: string;
12
+ version: number;
13
+ } | null>;
14
+ }
15
+ export interface PromptRegistryOptions {
16
+ fetcher?: PromptFetcher;
17
+ local?: Record<string, string>;
18
+ /** Directory of .md overrides (default ./prompts): edit a prompt without rebuilding. `<name>.md` > local constant. */
19
+ overridesDir?: string;
20
+ }
21
+ /**
22
+ * Prompt registry (ADR-0004): Langfuse first (if a fetcher is injected), otherwise the local fallback.
23
+ * `{{var}}` is interpolated; a missing variable → empty. The bot works offline on local prompts.
24
+ */
25
+ export declare class PromptRegistry {
26
+ private readonly opts;
27
+ private readonly local;
28
+ private readonly overridesDir;
29
+ constructor(opts?: PromptRegistryOptions);
30
+ getPrompt(name: string, vars?: Record<string, string>): Promise<CompiledPrompt>;
31
+ }
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sHAAsH;IACtH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD;;;GAGG;AACH,qBAAa,cAAc;IAGb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBACT,IAAI,GAAE,qBAA0B;IAKvD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAmC1F"}
@@ -0,0 +1,55 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { LOCAL_PROMPTS } from "./local/index.js";
4
+ export { LOCAL_PROMPTS } from "./local/index.js";
5
+ function interpolate(tpl, vars) {
6
+ return tpl.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, key) => vars[key] ?? "");
7
+ }
8
+ /**
9
+ * Prompt registry (ADR-0004): Langfuse first (if a fetcher is injected), otherwise the local fallback.
10
+ * `{{var}}` is interpolated; a missing variable → empty. The bot works offline on local prompts.
11
+ */
12
+ export class PromptRegistry {
13
+ opts;
14
+ local;
15
+ overridesDir;
16
+ constructor(opts = {}) {
17
+ this.opts = opts;
18
+ this.local = opts.local ?? LOCAL_PROMPTS;
19
+ this.overridesDir = opts.overridesDir ?? "prompts";
20
+ }
21
+ async getPrompt(name, vars = {}) {
22
+ let raw;
23
+ let version = "local";
24
+ let isFallback = true;
25
+ if (this.opts.fetcher) {
26
+ try {
27
+ const remote = await this.opts.fetcher.fetch(name);
28
+ if (remote) {
29
+ raw = remote.text;
30
+ version = remote.version;
31
+ isFallback = false;
32
+ }
33
+ }
34
+ catch {
35
+ // Langfuse unavailable → local fallback.
36
+ }
37
+ }
38
+ if (raw === undefined) {
39
+ try {
40
+ raw = await readFile(join(this.overridesDir, `${name}.md`), "utf8");
41
+ }
42
+ catch {
43
+ // no .md override → local constant
44
+ }
45
+ }
46
+ if (raw === undefined) {
47
+ raw = this.local[name];
48
+ if (raw === undefined) {
49
+ throw new Error(`Prompt '${name}' not found (neither in Langfuse nor locally).`);
50
+ }
51
+ }
52
+ return { name, text: interpolate(raw, vars), version, isFallback };
53
+ }
54
+ }
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqBjD,SAAS,WAAW,CAAC,GAAW,EAAE,IAA4B;IAC5D,OAAO,GAAG,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,cAAc;IAGI;IAFZ,KAAK,CAAyB;IAC9B,YAAY,CAAS;IACtC,YAA6B,OAA8B,EAAE;QAAhC,SAAI,GAAJ,IAAI,CAA4B;QAC3D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC;QACzC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAA+B,EAAE;QAC7D,IAAI,GAAuB,CAAC;QAC5B,IAAI,OAAO,GAAqB,OAAO,CAAC;QACxC,IAAI,UAAU,GAAG,IAAI,CAAC;QAEtB,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,MAAM,EAAE,CAAC;oBACX,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC;oBAClB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;oBACzB,UAAU,GAAG,KAAK,CAAC;gBACrB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;QACH,CAAC;QAED,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YACtE,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;QACH,CAAC;QAED,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,gDAAgD,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACrE,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Page analysis prompt (identifyElements). New (not from qa-skills).
3
+ * The vision image is passed as a separate content block; this is the text part.
4
+ */
5
+ export declare const IDENTIFY_ELEMENTS = "You are an experienced QA engineer. Analyze the web page.\n\nARIA snapshot:\n{{ariaYaml}}\n\nDetected elements (ref \u00B7 role \u00B7 name):\n{{elements}}\n\nTasks:\n1. pageSemantics \u2014 briefly (1\u20132 sentences) describe what this screen is and its main purpose.\n2. primaryRefs \u2014 pick the refs of the most test-worthy elements. Use ONLY refs from the provided\n list \u2014 do not invent new ones or change them.\n3. viewSwitchers \u2014 refs of view switchers: tabs, wizard steps, filter/mode toggles, form switchers \u2014\n whose click OPENS DIFFERENT content (rather than performing an action). Only from the provided list; empty if none.\n\nReturn structured output.";
6
+ //# sourceMappingURL=identify-elements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identify-elements.d.ts","sourceRoot":"","sources":["../../../src/prompts/local/identify-elements.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,srBAeJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Page analysis prompt (identifyElements). New (not from qa-skills).
3
+ * The vision image is passed as a separate content block; this is the text part.
4
+ */
5
+ export const IDENTIFY_ELEMENTS = `You are an experienced QA engineer. Analyze the web page.
6
+
7
+ ARIA snapshot:
8
+ {{ariaYaml}}
9
+
10
+ Detected elements (ref · role · name):
11
+ {{elements}}
12
+
13
+ Tasks:
14
+ 1. pageSemantics — briefly (1–2 sentences) describe what this screen is and its main purpose.
15
+ 2. primaryRefs — pick the refs of the most test-worthy elements. Use ONLY refs from the provided
16
+ list — do not invent new ones or change them.
17
+ 3. viewSwitchers — refs of view switchers: tabs, wizard steps, filter/mode toggles, form switchers —
18
+ whose click OPENS DIFFERENT content (rather than performing an action). Only from the provided list; empty if none.
19
+
20
+ Return structured output.`;
21
+ //# sourceMappingURL=identify-elements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identify-elements.js","sourceRoot":"","sources":["../../../src/prompts/local/identify-elements.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;0BAeP,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Local prompts (fallback, ADR-0004). Names match the Langfuse prompt names. */
2
+ export declare const LOCAL_PROMPTS: Record<string, string>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/prompts/local/index.ts"],"names":[],"mappings":"AAQA,iFAAiF;AACjF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQhD,CAAC"}