@ulearning/ai-generative-frame 0.0.0-stage → 1.0.0-next.0

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 +21 -0
  2. package/README.md +233 -2
  3. package/dist/assistant-ui/entry.d.ts +34 -0
  4. package/dist/assistant-ui/entry.d.ts.map +1 -0
  5. package/dist/assistant-ui/entry.js +50 -0
  6. package/dist/assistant-ui/entry.js.map +1 -0
  7. package/dist/assistant-ui/extension.d.ts +18 -0
  8. package/dist/assistant-ui/extension.d.ts.map +1 -0
  9. package/dist/assistant-ui/extension.js +0 -0
  10. package/dist/assistant-ui/history.d.ts +15 -0
  11. package/dist/assistant-ui/history.d.ts.map +1 -0
  12. package/dist/assistant-ui/history.js +39 -0
  13. package/dist/assistant-ui/history.js.map +1 -0
  14. package/dist/assistant-ui/modelContext.d.ts +45 -0
  15. package/dist/assistant-ui/modelContext.d.ts.map +1 -0
  16. package/dist/assistant-ui/modelContext.js +88 -0
  17. package/dist/assistant-ui/modelContext.js.map +1 -0
  18. package/dist/assistant-ui/snapshotSaver.d.ts +11 -0
  19. package/dist/assistant-ui/snapshotSaver.d.ts.map +1 -0
  20. package/dist/assistant-ui/snapshotSaver.js +83 -0
  21. package/dist/assistant-ui/snapshotSaver.js.map +1 -0
  22. package/dist/assistant-ui/tool-calls.d.ts +21 -0
  23. package/dist/assistant-ui/tool-calls.d.ts.map +1 -0
  24. package/dist/assistant-ui/tool-calls.js +65 -0
  25. package/dist/assistant-ui/tool-calls.js.map +1 -0
  26. package/dist/assistant-ui/toolkit.d.ts +96 -0
  27. package/dist/assistant-ui/toolkit.d.ts.map +1 -0
  28. package/dist/assistant-ui/toolkit.js +456 -0
  29. package/dist/assistant-ui/toolkit.js.map +1 -0
  30. package/dist/assistant-ui/useSharedContext.d.ts +14 -0
  31. package/dist/assistant-ui/useSharedContext.d.ts.map +1 -0
  32. package/dist/assistant-ui/useSharedContext.js +27 -0
  33. package/dist/assistant-ui/useSharedContext.js.map +1 -0
  34. package/dist/assistant-ui.d.ts +3 -0
  35. package/dist/assistant-ui.d.ts.map +1 -0
  36. package/dist/assistant-ui.js +1 -0
  37. package/dist/bootstrap.d.ts +23 -0
  38. package/dist/bootstrap.d.ts.map +1 -0
  39. package/dist/bootstrap.js +78 -0
  40. package/dist/bootstrap.js.map +1 -0
  41. package/dist/csp.d.ts +25 -0
  42. package/dist/csp.d.ts.map +1 -0
  43. package/dist/csp.js +78 -0
  44. package/dist/csp.js.map +1 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +5 -0
  48. package/dist/json-schema.d.ts +70 -0
  49. package/dist/json-schema.d.ts.map +1 -0
  50. package/dist/json-schema.js +163 -0
  51. package/dist/json-schema.js.map +1 -0
  52. package/dist/preview.d.ts +30 -0
  53. package/dist/preview.d.ts.map +1 -0
  54. package/dist/preview.js +60 -0
  55. package/dist/preview.js.map +1 -0
  56. package/dist/prompts/guidance.d.ts +41 -0
  57. package/dist/prompts/guidance.d.ts.map +1 -0
  58. package/dist/prompts/guidance.js +268 -0
  59. package/dist/prompts/guidance.js.map +1 -0
  60. package/dist/prompts.d.ts +2 -0
  61. package/dist/prompts.d.ts.map +1 -0
  62. package/dist/prompts.js +1 -0
  63. package/dist/protocol.d.ts +114 -0
  64. package/dist/protocol.d.ts.map +1 -0
  65. package/dist/protocol.js +49 -0
  66. package/dist/protocol.js.map +1 -0
  67. package/dist/repair/repair.d.ts +72 -0
  68. package/dist/repair/repair.d.ts.map +1 -0
  69. package/dist/repair/repair.js +103 -0
  70. package/dist/repair/repair.js.map +1 -0
  71. package/dist/repair.d.ts +2 -0
  72. package/dist/repair.d.ts.map +1 -0
  73. package/dist/repair.js +1 -0
  74. package/dist/rpc.d.ts +60 -0
  75. package/dist/rpc.d.ts.map +1 -0
  76. package/dist/rpc.js +127 -0
  77. package/dist/rpc.js.map +1 -0
  78. package/dist/runtime/diagnostics.d.ts +17 -0
  79. package/dist/runtime/diagnostics.d.ts.map +1 -0
  80. package/dist/runtime/diagnostics.js +128 -0
  81. package/dist/runtime/diagnostics.js.map +1 -0
  82. package/dist/runtime/generated.d.ts +2 -0
  83. package/dist/runtime/generated.d.ts.map +1 -0
  84. package/dist/runtime/generated.js +5 -0
  85. package/dist/runtime/generated.js.map +1 -0
  86. package/dist/runtime/index.d.ts +7 -0
  87. package/dist/runtime/index.d.ts.map +1 -0
  88. package/dist/runtime/index.js +264 -0
  89. package/dist/runtime/index.js.map +1 -0
  90. package/dist/runtime/morph.d.ts +51 -0
  91. package/dist/runtime/morph.d.ts.map +1 -0
  92. package/dist/runtime/morph.js +251 -0
  93. package/dist/runtime/morph.js.map +1 -0
  94. package/dist/runtime/screenshot.d.ts +23 -0
  95. package/dist/runtime/screenshot.d.ts.map +1 -0
  96. package/dist/runtime/screenshot.js +188 -0
  97. package/dist/runtime/screenshot.js.map +1 -0
  98. package/dist/runtime/size.d.ts +10 -0
  99. package/dist/runtime/size.d.ts.map +1 -0
  100. package/dist/runtime/size.js +21 -0
  101. package/dist/runtime/size.js.map +1 -0
  102. package/dist/runtime/storage.d.ts +4 -0
  103. package/dist/runtime/storage.d.ts.map +1 -0
  104. package/dist/runtime/storage.js +38 -0
  105. package/dist/runtime/storage.js.map +1 -0
  106. package/dist/spec/actions.d.ts +40 -0
  107. package/dist/spec/actions.d.ts.map +1 -0
  108. package/dist/spec/actions.js +53 -0
  109. package/dist/spec/actions.js.map +1 -0
  110. package/dist/spec/assistant-ui/thread.d.ts +66 -0
  111. package/dist/spec/assistant-ui/thread.d.ts.map +1 -0
  112. package/dist/spec/assistant-ui/thread.js +252 -0
  113. package/dist/spec/assistant-ui/thread.js.map +1 -0
  114. package/dist/spec/assistant-ui/toolkit.d.ts +33 -0
  115. package/dist/spec/assistant-ui/toolkit.d.ts.map +1 -0
  116. package/dist/spec/assistant-ui/toolkit.js +142 -0
  117. package/dist/spec/assistant-ui/toolkit.js.map +1 -0
  118. package/dist/spec/assistant-ui/web.d.ts +6 -0
  119. package/dist/spec/assistant-ui/web.d.ts.map +1 -0
  120. package/dist/spec/assistant-ui/web.js +48 -0
  121. package/dist/spec/assistant-ui/web.js.map +1 -0
  122. package/dist/spec/assistant-ui.d.ts +3 -0
  123. package/dist/spec/assistant-ui.d.ts.map +1 -0
  124. package/dist/spec/assistant-ui.js +1 -0
  125. package/dist/spec/calc.d.ts +8 -0
  126. package/dist/spec/calc.d.ts.map +1 -0
  127. package/dist/spec/calc.js +498 -0
  128. package/dist/spec/calc.js.map +1 -0
  129. package/dist/spec/catalog.d.ts +52 -0
  130. package/dist/spec/catalog.d.ts.map +1 -0
  131. package/dist/spec/catalog.js +104 -0
  132. package/dist/spec/catalog.js.map +1 -0
  133. package/dist/spec/expressions.d.ts +45 -0
  134. package/dist/spec/expressions.d.ts.map +1 -0
  135. package/dist/spec/expressions.js +199 -0
  136. package/dist/spec/expressions.js.map +1 -0
  137. package/dist/spec/patch.d.ts +20 -0
  138. package/dist/spec/patch.d.ts.map +1 -0
  139. package/dist/spec/patch.js +77 -0
  140. package/dist/spec/patch.js.map +1 -0
  141. package/dist/spec/pending.d.ts +15 -0
  142. package/dist/spec/pending.d.ts.map +1 -0
  143. package/dist/spec/pending.js +33 -0
  144. package/dist/spec/pending.js.map +1 -0
  145. package/dist/spec/pointer.d.ts +17 -0
  146. package/dist/spec/pointer.d.ts.map +1 -0
  147. package/dist/spec/pointer.js +88 -0
  148. package/dist/spec/pointer.js.map +1 -0
  149. package/dist/spec/prompt.d.ts +29 -0
  150. package/dist/spec/prompt.d.ts.map +1 -0
  151. package/dist/spec/prompt.js +145 -0
  152. package/dist/spec/prompt.js.map +1 -0
  153. package/dist/spec/render-spec.d.ts +50 -0
  154. package/dist/spec/render-spec.d.ts.map +1 -0
  155. package/dist/spec/render-spec.js +104 -0
  156. package/dist/spec/render-spec.js.map +1 -0
  157. package/dist/spec/resolve.d.ts +39 -0
  158. package/dist/spec/resolve.d.ts.map +1 -0
  159. package/dist/spec/resolve.js +51 -0
  160. package/dist/spec/resolve.js.map +1 -0
  161. package/dist/spec/resolved.d.ts +3 -0
  162. package/dist/spec/resolved.d.ts.map +1 -0
  163. package/dist/spec/resolved.js +36 -0
  164. package/dist/spec/resolved.js.map +1 -0
  165. package/dist/spec/state.d.ts +34 -0
  166. package/dist/spec/state.d.ts.map +1 -0
  167. package/dist/spec/state.js +111 -0
  168. package/dist/spec/state.js.map +1 -0
  169. package/dist/spec/stream.d.ts +50 -0
  170. package/dist/spec/stream.d.ts.map +1 -0
  171. package/dist/spec/stream.js +168 -0
  172. package/dist/spec/stream.js.map +1 -0
  173. package/dist/spec/tools.d.ts +3 -0
  174. package/dist/spec/tools.d.ts.map +1 -0
  175. package/dist/spec/tools.js +3 -0
  176. package/dist/spec/tree.d.ts +21 -0
  177. package/dist/spec/tree.d.ts.map +1 -0
  178. package/dist/spec/tree.js +27 -0
  179. package/dist/spec/tree.js.map +1 -0
  180. package/dist/spec/types.d.ts +66 -0
  181. package/dist/spec/types.d.ts.map +1 -0
  182. package/dist/spec/types.js +9 -0
  183. package/dist/spec/types.js.map +1 -0
  184. package/dist/spec/validate.d.ts +32 -0
  185. package/dist/spec/validate.d.ts.map +1 -0
  186. package/dist/spec/validate.js +264 -0
  187. package/dist/spec/validate.js.map +1 -0
  188. package/dist/spec/vue/SpecRenderer.d.ts +43 -0
  189. package/dist/spec/vue/SpecRenderer.d.ts.map +1 -0
  190. package/dist/spec/vue/SpecRenderer.js +357 -0
  191. package/dist/spec/vue/SpecRenderer.js.map +1 -0
  192. package/dist/spec/vue/useSpecStream.d.ts +19 -0
  193. package/dist/spec/vue/useSpecStream.d.ts.map +1 -0
  194. package/dist/spec/vue/useSpecStream.js +115 -0
  195. package/dist/spec/vue/useSpecStream.js.map +1 -0
  196. package/dist/spec/vue.d.ts +3 -0
  197. package/dist/spec/vue.d.ts.map +1 -0
  198. package/dist/spec/vue.js +3 -0
  199. package/dist/spec.d.ts +12 -0
  200. package/dist/spec.d.ts.map +1 -0
  201. package/dist/spec.js +8 -0
  202. package/dist/theme.d.ts +38 -0
  203. package/dist/theme.d.ts.map +1 -0
  204. package/dist/theme.js +370 -0
  205. package/dist/theme.js.map +1 -0
  206. package/dist/tools/define.d.ts +43 -0
  207. package/dist/tools/define.d.ts.map +1 -0
  208. package/dist/tools/define.js +31 -0
  209. package/dist/tools/define.js.map +1 -0
  210. package/dist/tools/edits.d.ts +19 -0
  211. package/dist/tools/edits.d.ts.map +1 -0
  212. package/dist/tools/edits.js +55 -0
  213. package/dist/tools/edits.js.map +1 -0
  214. package/dist/tools/registry.d.ts +19 -0
  215. package/dist/tools/registry.d.ts.map +1 -0
  216. package/dist/tools/registry.js +33 -0
  217. package/dist/tools/registry.js.map +1 -0
  218. package/dist/tools/tools.d.ts +88 -0
  219. package/dist/tools/tools.d.ts.map +1 -0
  220. package/dist/tools/tools.js +235 -0
  221. package/dist/tools/tools.js.map +1 -0
  222. package/dist/tools.d.ts +5 -0
  223. package/dist/tools.d.ts.map +1 -0
  224. package/dist/tools.js +5 -0
  225. package/dist/version.d.ts +2 -0
  226. package/dist/version.d.ts.map +1 -0
  227. package/dist/version.js +5 -0
  228. package/dist/version.js.map +1 -0
  229. package/dist/vue/Widget.d.ts +16 -0
  230. package/dist/vue/Widget.d.ts.map +1 -0
  231. package/dist/vue/Widget.js +58 -0
  232. package/dist/vue/Widget.js.map +1 -0
  233. package/dist/vue/sync.d.ts +19 -0
  234. package/dist/vue/sync.d.ts.map +1 -0
  235. package/dist/vue/sync.js +31 -0
  236. package/dist/vue/sync.js.map +1 -0
  237. package/dist/vue/themeStore.d.ts +23 -0
  238. package/dist/vue/themeStore.d.ts.map +1 -0
  239. package/dist/vue/themeStore.js +115 -0
  240. package/dist/vue/themeStore.js.map +1 -0
  241. package/dist/vue/useThemeTokens.d.ts +6 -0
  242. package/dist/vue/useThemeTokens.d.ts.map +1 -0
  243. package/dist/vue/useThemeTokens.js +49 -0
  244. package/dist/vue/useThemeTokens.js.map +1 -0
  245. package/dist/vue/useWidget.d.ts +10 -0
  246. package/dist/vue/useWidget.d.ts.map +1 -0
  247. package/dist/vue/useWidget.js +81 -0
  248. package/dist/vue/useWidget.js.map +1 -0
  249. package/dist/vue.d.ts +5 -0
  250. package/dist/vue.d.ts.map +1 -0
  251. package/dist/vue.js +4 -0
  252. package/dist/widget.d.ts +129 -0
  253. package/dist/widget.d.ts.map +1 -0
  254. package/dist/widget.js +655 -0
  255. package/dist/widget.js.map +1 -0
  256. package/package.json +125 -3
  257. package/src/assistant-ui/entry.ts +124 -0
  258. package/src/assistant-ui/extension.ts +19 -0
  259. package/src/assistant-ui/history.ts +63 -0
  260. package/src/assistant-ui/modelContext.ts +162 -0
  261. package/src/assistant-ui/snapshotSaver.ts +116 -0
  262. package/src/assistant-ui/tool-calls.ts +115 -0
  263. package/src/assistant-ui/toolkit.tsx +747 -0
  264. package/src/assistant-ui/useSharedContext.ts +40 -0
  265. package/src/assistant-ui.ts +14 -0
  266. package/src/bootstrap.ts +112 -0
  267. package/src/csp.ts +96 -0
  268. package/src/index.ts +44 -0
  269. package/src/json-schema.ts +353 -0
  270. package/src/preview.ts +120 -0
  271. package/src/prompts/guidance.ts +369 -0
  272. package/src/prompts.ts +8 -0
  273. package/src/protocol.ts +141 -0
  274. package/src/repair/repair.ts +202 -0
  275. package/src/repair.ts +11 -0
  276. package/src/rpc.ts +228 -0
  277. package/src/runtime/diagnostics.ts +165 -0
  278. package/src/runtime/generated.ts +2 -0
  279. package/src/runtime/index.ts +343 -0
  280. package/src/runtime/morph.ts +352 -0
  281. package/src/runtime/screenshot.ts +288 -0
  282. package/src/runtime/size.ts +17 -0
  283. package/src/runtime/storage.ts +49 -0
  284. package/src/spec/actions.ts +111 -0
  285. package/src/spec/assistant-ui/thread.ts +381 -0
  286. package/src/spec/assistant-ui/toolkit.tsx +295 -0
  287. package/src/spec/assistant-ui/web.tsx +63 -0
  288. package/src/spec/assistant-ui.ts +2 -0
  289. package/src/spec/calc.ts +598 -0
  290. package/src/spec/catalog.ts +196 -0
  291. package/src/spec/expressions.ts +301 -0
  292. package/src/spec/patch.ts +112 -0
  293. package/src/spec/pending.ts +36 -0
  294. package/src/spec/pointer.ts +170 -0
  295. package/src/spec/prompt.ts +243 -0
  296. package/src/spec/render-spec.ts +144 -0
  297. package/src/spec/resolve.ts +123 -0
  298. package/src/spec/resolved.ts +53 -0
  299. package/src/spec/state.ts +193 -0
  300. package/src/spec/stream.ts +230 -0
  301. package/src/spec/tools.ts +17 -0
  302. package/src/spec/tree.ts +37 -0
  303. package/src/spec/types.ts +51 -0
  304. package/src/spec/validate.ts +429 -0
  305. package/src/spec/vue/SpecRenderer.tsx +544 -0
  306. package/src/spec/vue/__tests__/harness.ts +50 -0
  307. package/src/spec/vue/useSpecStream.ts +162 -0
  308. package/src/spec/vue.ts +13 -0
  309. package/src/spec.ts +55 -0
  310. package/src/theme.ts +423 -0
  311. package/src/tools/define.ts +65 -0
  312. package/src/tools/edits.ts +73 -0
  313. package/src/tools/registry.ts +44 -0
  314. package/src/tools/tools.ts +361 -0
  315. package/src/tools.ts +32 -0
  316. package/src/version.ts +4 -0
  317. package/src/vue/Widget.tsx +74 -0
  318. package/src/vue/sync.ts +36 -0
  319. package/src/vue/themeStore.ts +157 -0
  320. package/src/vue/useThemeTokens.ts +71 -0
  321. package/src/vue/useWidget.ts +117 -0
  322. package/src/vue.ts +8 -0
  323. package/src/widget.ts +1080 -0
@@ -0,0 +1,3 @@
1
+ import type { PropsSchema } from "./catalog.js";
2
+ export declare function rejectedPropType(schema: PropsSchema | undefined, props: Record<string, unknown>): string | undefined;
3
+ //# sourceMappingURL=resolved.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved.d.ts","mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAW;AAoC5C,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,SAAS","names":[],"ignoreList":[],"sources":["../../src/spec/resolved.ts"],"sourcesContent":[null]}
@@ -0,0 +1,36 @@
1
+ import { toJsonSchema } from "../json-schema.js";
2
+ // src/spec/resolved.ts
3
+ const primitiveTypes = /* @__PURE__ */ new Set([
4
+ "string",
5
+ "number",
6
+ "integer",
7
+ "boolean",
8
+ "null"
9
+ ]);
10
+ const listedValues = "one of the listed values";
11
+ function expectedPrimitive(schema) {
12
+ if (schema.type !== void 0) {
13
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type];
14
+ return types.length > 0 && types.every((type) => primitiveTypes.has(type)) ? [...new Set(types)].join(" or ") : void 0;
15
+ }
16
+ const alternatives = schema.anyOf ?? schema.oneOf;
17
+ if (alternatives !== void 0) {
18
+ if (alternatives.length === 0) return void 0;
19
+ const expected = alternatives.map(expectedPrimitive);
20
+ return expected.every((type) => type !== void 0) ? [...new Set(expected)].join(" or ") : void 0;
21
+ }
22
+ if (schema.enum?.length) return schema.enum.every((value) => value === null || typeof value !== "object") ? listedValues : void 0;
23
+ }
24
+ function rejectedPropType(schema, props) {
25
+ const properties = toJsonSchema(schema)?.properties;
26
+ if (!properties) return void 0;
27
+ for (const [name, property] of Object.entries(properties)) {
28
+ const value = props[name];
29
+ if (value === null || typeof value !== "object") continue;
30
+ const expected = expectedPrimitive(property);
31
+ if (expected) return `${name} expected ${expected}, got ${Array.isArray(value) ? "array" : "object"}`;
32
+ }
33
+ }
34
+ export { rejectedPropType };
35
+
36
+ //# sourceMappingURL=resolved.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved.js","names":[],"sources":["../../src/spec/resolved.ts"],"sourcesContent":["import { toJsonSchema, type JsonSchema } from \"../json-schema\";\nimport type { PropsSchema } from \"./catalog\";\n\nconst primitiveTypes = new Set([\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\",\n]);\nconst listedValues = \"one of the listed values\";\n\nfunction expectedPrimitive(schema: JsonSchema): string | undefined {\n if (schema.type !== undefined) {\n const types = Array.isArray(schema.type) ? schema.type : [schema.type];\n return types.length > 0 && types.every((type) => primitiveTypes.has(type))\n ? [...new Set(types)].join(\" or \")\n : undefined;\n }\n const alternatives = schema.anyOf ?? schema.oneOf;\n if (alternatives !== undefined) {\n if (alternatives.length === 0) return undefined;\n const expected = alternatives.map(expectedPrimitive);\n return expected.every((type): type is string => type !== undefined)\n ? [...new Set(expected)].join(\" or \")\n : undefined;\n }\n if (schema.enum?.length) {\n return schema.enum.every(\n (value) => value === null || typeof value !== \"object\",\n )\n ? listedValues\n : undefined;\n }\n return undefined;\n}\n\nexport function rejectedPropType(\n schema: PropsSchema | undefined,\n props: Record<string, unknown>,\n): string | undefined {\n const properties = toJsonSchema(schema)?.properties;\n if (!properties) return undefined;\n for (const [name, property] of Object.entries(properties)) {\n const value = props[name];\n if (value === null || typeof value !== \"object\") continue;\n const expected = expectedPrimitive(property);\n if (expected) {\n return `${name} expected ${expected}, got ${Array.isArray(value) ? \"array\" : \"object\"}`;\n }\n }\n return undefined;\n}\n"],"mappings":";;AAGA,MAAM,iCAAiB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,eAAe;AAErB,SAAS,kBAAkB,QAAwC;CACjE,IAAI,OAAO,SAAS,KAAA,GAAW;EAC7B,MAAM,QAAQ,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,OAAO,CAAC,OAAO,IAAI;EACrE,OAAO,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,eAAe,IAAI,IAAI,CAAC,IACrE,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,IAC/B,KAAA;CACN;CACA,MAAM,eAAe,OAAO,SAAS,OAAO;CAC5C,IAAI,iBAAiB,KAAA,GAAW;EAC9B,IAAI,aAAa,WAAW,GAAG,OAAO,KAAA;EACtC,MAAM,WAAW,aAAa,IAAI,iBAAiB;EACnD,OAAO,SAAS,OAAO,SAAyB,SAAS,KAAA,CAAS,IAC9D,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,IAClC,KAAA;CACN;CACA,IAAI,OAAO,MAAM,QACf,OAAO,OAAO,KAAK,OAChB,UAAU,UAAU,QAAQ,OAAO,UAAU,QAChD,IACI,eACA,KAAA;AAGR;AAEA,SAAgB,iBACd,QACA,OACoB;CACpB,MAAM,aAAa,aAAa,MAAM,CAAC,EAAE;CACzC,IAAI,CAAC,YAAY,OAAO,KAAA;CACxB,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,UAAU,GAAG;EACzD,MAAM,QAAQ,MAAM;EACpB,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;EACjD,MAAM,WAAW,kBAAkB,QAAQ;EAC3C,IAAI,UACF,OAAO,GAAG,KAAK,YAAY,SAAS,QAAQ,MAAM,QAAQ,KAAK,IAAI,UAAU;CAEjF;AAEF"}
@@ -0,0 +1,34 @@
1
+ export type StateListener = (state: Record<string, unknown>) => void;
2
+ /** A value written at a JSON Pointer with `set`: an optional mode marks a replacement, and optional array-parent paths keep the shape of arrays the write went through. */
3
+ export type SpecStateWrite = readonly [
4
+ path: string,
5
+ value: unknown,
6
+ mode?: "add" | "replace",
7
+ arrayParents?: readonly string[]
8
+ ];
9
+ /** A small state container for spec expressions and `setState` actions. */
10
+ export type SpecStateStore = {
11
+ getState(): Record<string, unknown>;
12
+ /** The value at a JSON Pointer, or undefined. */
13
+ get(path: string): unknown;
14
+ /** Writes at a JSON Pointer, creating missing parent objects. Defaults to add (inserting at array indices); replace updates an existing array item. */
15
+ set(path: string, value: unknown, mode?: "add" | "replace"): void;
16
+ /**
17
+ * Replaces the base state, typically the spec's `state` as it streams in,
18
+ * and re-applies every `set` made so far on top of it, so model updates
19
+ * never discard what the user already changed.
20
+ */
21
+ seed(state: Record<string, unknown>): void;
22
+ subscribe(listener: StateListener): () => void;
23
+ };
24
+ export type StateStoreOptions = {
25
+ /** Writes to apply over the initial state and keep, such as changes saved from an earlier session. One that no longer applies is dropped. */
26
+ writes?: readonly SpecStateWrite[];
27
+ };
28
+ export declare function createStateStore(initial?: Record<string, unknown>, options?: StateStoreOptions): SpecStateStore & {
29
+ /**
30
+ * The writes `seed` re-applies, oldest first, as `[path, value]`, `[path, value, "replace"]`, or, for a write that went through an array, `[path, value, mode, arrayParents]`, whose array-parent paths recreate those arrays when the write is replayed without them: what to save to restore the user's changes later. A write that replaces a value drops earlier writes at its path and below it, except those made before an insert at an index of an array on its path, which may have moved them to another item; one that inserts into an array, at an index or at `-`, keeps them, so replaying the list in order gives the same state. The array is replaced, never mutated, when it changes.
31
+ */
32
+ writes(): readonly SpecStateWrite[];
33
+ };
34
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","mappings":"AAOA,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;AAEpE;AACA,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,IAAI,CAAC,EAAE,KAAK,GAAG,SAAS;IACxB,YAAY,CAAC,EAAE,SAAS,MAAM;CAC/B;AAED;AACA,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnC;IACA,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAC1B;IACA,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;IACjE;;;;;IAKA,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAC1C,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;CAC/C;AAKD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;IACA,MAAM,CAAC,EAAE,SAAS,cAAc,EAAE;CACnC;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,OAAO,GAAE,iBAAsB,GAC9B,cAAc,GAAG;IAClB;;;IAGA,MAAM,IAAI,SAAS,cAAc,EAAE;CACpC","names":[],"ignoreList":[],"sources":["../../src/spec/state.ts"],"sourcesContent":[null]}
@@ -0,0 +1,111 @@
1
+ import { getAtPointer, joinPointer, parsePointer, writeAtPointer } from "./pointer.js";
2
+ // src/spec/state.ts
3
+ const normalize = (path) => path === "" || path.startsWith("/") ? path : `/${path}`;
4
+ function createStateStore(initial = {}, options = {}) {
5
+ let base = initial;
6
+ let state = initial;
7
+ let writes = [];
8
+ const shifting = /* @__PURE__ */ new WeakSet();
9
+ const listeners = /* @__PURE__ */ new Set();
10
+ const arrayParentsAt = (target, path) => {
11
+ const tokens = parsePointer(path);
12
+ return tokens.flatMap((_, index) => {
13
+ const parent = joinPointer(tokens.slice(0, index));
14
+ return Array.isArray(getAtPointer(target, parent)) ? [parent] : [];
15
+ });
16
+ };
17
+ const parentOf = (path) => path.slice(0, path.lastIndexOf("/"));
18
+ const apply = (target, path, value, mode, savedArrayParents = []) => {
19
+ const arrayParents = [.../* @__PURE__ */ new Set([...savedArrayParents, ...arrayParentsAt(target, path)])];
20
+ const parent = path === "" ? void 0 : getAtPointer(target, parentOf(path));
21
+ const inserted = mode === "add" && path !== "" && (Array.isArray(parent) || parent === void 0 && arrayParents.includes(parentOf(path)));
22
+ return {
23
+ next: writeAtPointer(target, parsePointer(path), mode, value, { createMissing: true }, arrayParents),
24
+ inserted,
25
+ arrayParents
26
+ };
27
+ };
28
+ const entryFor = (path, value, mode, arrayParents) => {
29
+ if (arrayParents.length > 0) return [
30
+ path,
31
+ value,
32
+ mode,
33
+ arrayParents
34
+ ];
35
+ return mode === "replace" ? [
36
+ path,
37
+ value,
38
+ mode
39
+ ] : [path, value];
40
+ };
41
+ const record = (entry, inserted) => {
42
+ const path = entry[0];
43
+ if (inserted) {
44
+ if (!path.endsWith("/-")) shifting.add(entry);
45
+ writes = [...writes, entry];
46
+ return;
47
+ }
48
+ const moved = writes.findLastIndex((write) => shifting.has(write) && path.startsWith(`${parentOf(write[0])}/`));
49
+ writes = [...writes.filter(([written], index) => index <= moved || written !== path && !written.startsWith(`${path}/`)), entry];
50
+ };
51
+ const modeOf = (saved) => saved === "replace" ? "replace" : "add";
52
+ const emit = () => {
53
+ for (const listener of [...listeners]) listener(state);
54
+ };
55
+ for (const [rawPath, value, saved, savedArrayParents] of options.writes ?? []) {
56
+ const path = normalize(rawPath);
57
+ const mode = modeOf(saved);
58
+ try {
59
+ const result = apply(state, path, value, mode, savedArrayParents?.map(normalize));
60
+ state = result.next;
61
+ record(entryFor(path, value, mode, result.arrayParents), result.inserted);
62
+ } catch {}
63
+ }
64
+ return {
65
+ getState: () => state,
66
+ get: (path) => getAtPointer(state, normalize(path)),
67
+ set(rawPath, value, mode = "add") {
68
+ const path = normalize(rawPath);
69
+ const result = apply(state, path, value, mode);
70
+ record(entryFor(path, value, mode, result.arrayParents), result.inserted);
71
+ state = result.next;
72
+ emit();
73
+ },
74
+ writes: () => writes,
75
+ seed(next) {
76
+ if (next === base) return;
77
+ base = next;
78
+ let merged = next;
79
+ let changed = false;
80
+ const applied = [];
81
+ for (const write of writes) {
82
+ const [path, value, saved, savedArrayParents] = write;
83
+ const mode = modeOf(saved);
84
+ try {
85
+ const result = apply(merged, path, value, mode, savedArrayParents);
86
+ merged = result.next;
87
+ if (result.arrayParents.length === (savedArrayParents?.length ?? 0)) {
88
+ applied.push(write);
89
+ continue;
90
+ }
91
+ const entry = entryFor(path, value, mode, result.arrayParents);
92
+ if (shifting.has(write)) shifting.add(entry);
93
+ applied.push(entry);
94
+ changed = true;
95
+ } catch {
96
+ changed = true;
97
+ }
98
+ }
99
+ if (changed) writes = applied;
100
+ state = merged;
101
+ emit();
102
+ },
103
+ subscribe(listener) {
104
+ listeners.add(listener);
105
+ return () => listeners.delete(listener);
106
+ }
107
+ };
108
+ }
109
+ export { createStateStore };
110
+
111
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","names":[],"sources":["../../src/spec/state.ts"],"sourcesContent":["import {\n getAtPointer,\n joinPointer,\n parsePointer,\n writeAtPointer,\n} from \"./pointer\";\n\nexport type StateListener = (state: Record<string, unknown>) => void;\n\n/** A value written at a JSON Pointer with `set`: an optional mode marks a replacement, and optional array-parent paths keep the shape of arrays the write went through. */\nexport type SpecStateWrite = readonly [\n path: string,\n value: unknown,\n mode?: \"add\" | \"replace\",\n arrayParents?: readonly string[],\n];\n\n/** A small state container for spec expressions and `setState` actions. */\nexport type SpecStateStore = {\n getState(): Record<string, unknown>;\n /** The value at a JSON Pointer, or undefined. */\n get(path: string): unknown;\n /** Writes at a JSON Pointer, creating missing parent objects. Defaults to add (inserting at array indices); replace updates an existing array item. */\n set(path: string, value: unknown, mode?: \"add\" | \"replace\"): void;\n /**\n * Replaces the base state, typically the spec's `state` as it streams in,\n * and re-applies every `set` made so far on top of it, so model updates\n * never discard what the user already changed.\n */\n seed(state: Record<string, unknown>): void;\n subscribe(listener: StateListener): () => void;\n};\n\nconst normalize = (path: string) =>\n path === \"\" || path.startsWith(\"/\") ? path : `/${path}`;\n\nexport type StateStoreOptions = {\n /** Writes to apply over the initial state and keep, such as changes saved from an earlier session. One that no longer applies is dropped. */\n writes?: readonly SpecStateWrite[];\n};\n\nexport function createStateStore(\n initial: Record<string, unknown> = {},\n options: StateStoreOptions = {},\n): SpecStateStore & {\n /**\n * The writes `seed` re-applies, oldest first, as `[path, value]`, `[path, value, \"replace\"]`, or, for a write that went through an array, `[path, value, mode, arrayParents]`, whose array-parent paths recreate those arrays when the write is replayed without them: what to save to restore the user's changes later. A write that replaces a value drops earlier writes at its path and below it, except those made before an insert at an index of an array on its path, which may have moved them to another item; one that inserts into an array, at an index or at `-`, keeps them, so replaying the list in order gives the same state. The array is replaced, never mutated, when it changes.\n */\n writes(): readonly SpecStateWrite[];\n} {\n let base = initial;\n let state = initial;\n let writes: readonly SpecStateWrite[] = [];\n const shifting = new WeakSet<SpecStateWrite>();\n const listeners = new Set<StateListener>();\n\n const arrayParentsAt = (target: Record<string, unknown>, path: string) => {\n const tokens = parsePointer(path);\n return tokens.flatMap((_, index) => {\n const parent = joinPointer(tokens.slice(0, index));\n return Array.isArray(getAtPointer(target, parent)) ? [parent] : [];\n });\n };\n\n const parentOf = (path: string) => path.slice(0, path.lastIndexOf(\"/\"));\n\n const apply = (\n target: Record<string, unknown>,\n path: string,\n value: unknown,\n mode: \"add\" | \"replace\",\n savedArrayParents: readonly string[] = [],\n ) => {\n const arrayParents = [\n ...new Set([...savedArrayParents, ...arrayParentsAt(target, path)]),\n ];\n const parent =\n path === \"\" ? undefined : getAtPointer(target, parentOf(path));\n const inserted =\n mode === \"add\" &&\n path !== \"\" &&\n (Array.isArray(parent) ||\n (parent === undefined && arrayParents.includes(parentOf(path))));\n const next = writeAtPointer(\n target,\n parsePointer(path),\n mode,\n value,\n { createMissing: true },\n arrayParents,\n ) as Record<string, unknown>;\n return { next, inserted, arrayParents };\n };\n\n const entryFor = (\n path: string,\n value: unknown,\n mode: \"add\" | \"replace\",\n arrayParents: readonly string[],\n ): SpecStateWrite => {\n if (arrayParents.length > 0) return [path, value, mode, arrayParents];\n return mode === \"replace\" ? [path, value, mode] : [path, value];\n };\n\n const record = (entry: SpecStateWrite, inserted: boolean) => {\n const path = entry[0];\n if (inserted) {\n if (!path.endsWith(\"/-\")) shifting.add(entry);\n writes = [...writes, entry];\n return;\n }\n const moved = writes.findLastIndex(\n (write) =>\n shifting.has(write) && path.startsWith(`${parentOf(write[0])}/`),\n );\n writes = [\n ...writes.filter(\n ([written], index) =>\n index <= moved ||\n (written !== path && !written.startsWith(`${path}/`)),\n ),\n entry,\n ];\n };\n\n const modeOf = (saved: unknown) => (saved === \"replace\" ? \"replace\" : \"add\");\n\n const emit = () => {\n for (const listener of [...listeners]) listener(state);\n };\n\n for (const [rawPath, value, saved, savedArrayParents] of options.writes ??\n []) {\n const path = normalize(rawPath);\n const mode = modeOf(saved);\n try {\n const result = apply(\n state,\n path,\n value,\n mode,\n savedArrayParents?.map(normalize),\n );\n state = result.next;\n record(entryFor(path, value, mode, result.arrayParents), result.inserted);\n } catch {}\n }\n\n return {\n getState: () => state,\n get: (path) => getAtPointer(state, normalize(path)),\n set(rawPath, value, mode = \"add\") {\n const path = normalize(rawPath);\n const result = apply(state, path, value, mode);\n record(entryFor(path, value, mode, result.arrayParents), result.inserted);\n state = result.next;\n emit();\n },\n writes: () => writes,\n seed(next) {\n if (next === base) return;\n base = next;\n let merged = next;\n let changed = false;\n const applied: SpecStateWrite[] = [];\n for (const write of writes) {\n const [path, value, saved, savedArrayParents] = write;\n const mode = modeOf(saved);\n try {\n const result = apply(merged, path, value, mode, savedArrayParents);\n merged = result.next;\n if (result.arrayParents.length === (savedArrayParents?.length ?? 0)) {\n applied.push(write);\n continue;\n }\n const entry = entryFor(path, value, mode, result.arrayParents);\n if (shifting.has(write)) shifting.add(entry);\n applied.push(entry);\n changed = true;\n } catch {\n changed = true;\n }\n }\n if (changed) writes = applied;\n state = merged;\n emit();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { type PatchOperation, type Spec } from "./types.js";
2
+ /**
3
+ * `jsonl`: every non-empty line is a patch operation (what `render_spec`
4
+ * receives). `inline`: prose and patches interleave, as in a chat reply;
5
+ * patch lines sit in a ```spec fence or start with `{"op"`, everything else
6
+ * is text.
7
+ */
8
+ export type SpecStreamMode = "jsonl" | "inline";
9
+ export type SpecStreamError = {
10
+ line: number;
11
+ message: string;
12
+ text: string;
13
+ };
14
+ export type SpecStreamUpdate = {
15
+ /** The spec after every patch so far. A new object only when it changed. */
16
+ spec: Spec;
17
+ /** Operations applied by this push. */
18
+ patches: PatchOperation[];
19
+ /** Prose added by this push (inline mode). */
20
+ text: string;
21
+ /** Errors from lines completed by this push. */
22
+ errors: SpecStreamError[];
23
+ };
24
+ export type SpecStreamResult = {
25
+ spec: Spec;
26
+ patches: PatchOperation[];
27
+ text: string;
28
+ errors: SpecStreamError[];
29
+ };
30
+ export type SpecStream = {
31
+ /** Feeds raw model output; partial lines wait for their newline. */
32
+ push(chunk: string): SpecStreamUpdate;
33
+ /** Processes a trailing line without a newline and returns everything so far. */
34
+ result(): SpecStreamResult;
35
+ readonly spec: Spec;
36
+ };
37
+ export type CreateSpecStreamOptions = {
38
+ mode?: SpecStreamMode;
39
+ /** Spec to apply patches onto. Defaults to an empty spec. */
40
+ initial?: Spec;
41
+ };
42
+ /**
43
+ * Turns a stream of JSONL patch lines (optionally interleaved with prose)
44
+ * into a progressively built spec. Bad lines are reported and skipped, so
45
+ * one malformed patch does not stop the rest of the UI from rendering.
46
+ */
47
+ export declare function createSpecStream(options?: CreateSpecStreamOptions): SpecStream;
48
+ /** Parses complete JSONL or inline output in one go. */
49
+ export declare function parseSpecStream(source: string, options?: CreateSpecStreamOptions): SpecStreamResult;
50
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","mappings":"AACA,OAAO,EAAa,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,YAAS;AAEnE;;;;;;AAMA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ;AAE/C,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM;IAAE,OAAO,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;CAAE;AAE7E,MAAM,MAAM,gBAAgB,GAAG;IAC7B;IACA,IAAI,EAAE,IAAI;IACV;IACA,OAAO,EAAE,cAAc,EAAE;IACzB;IACA,IAAI,EAAE,MAAM;IACZ;IACA,MAAM,EAAE,eAAe,EAAE;CAC1B;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,cAAc,EAAE;IACzB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,eAAe,EAAE;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG;IACvB;IACA,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACrC;IACA,MAAM,IAAI,gBAAgB;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI;CACpB;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,EAAE,cAAc;IACrB;IACA,OAAO,CAAC,EAAE,IAAI;CACf;AAiBD;;;;;AAKA,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,uBAA4B,GACpC,UAAU;AA0Jb;AACA,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,uBAA4B,GACpC,gBAAgB","names":[],"ignoreList":[],"sources":["../../src/spec/stream.ts"],"sourcesContent":[null]}
@@ -0,0 +1,168 @@
1
+ import { emptySpec } from "./types.js";
2
+ import { applyPatchOperation, checkPatchOperation } from "./patch.js";
3
+ // src/spec/stream.ts
4
+ const FENCE = /^\s*(`{3,}|~{3,})\s*([\w-]*)\s*$/;
5
+ const SPEC_FENCES = /* @__PURE__ */ new Set([
6
+ "spec",
7
+ "jsonl",
8
+ "json-patch",
9
+ "spec-jsonl"
10
+ ]);
11
+ const LOOKS_LIKE_PATCH = /^\s*\{\s*"op"\s*:/;
12
+ /** A partial line that can no longer turn into a patch or a fence. */
13
+ const PROSE_START = /^\s*[^\s{`~]/;
14
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
15
+ const isSpecShape = (value) => isRecord(value) && typeof value["root"] === "string" && isRecord(value["elements"]) && (value["state"] === void 0 || isRecord(value["state"]));
16
+ /**
17
+ * Turns a stream of JSONL patch lines (optionally interleaved with prose)
18
+ * into a progressively built spec. Bad lines are reported and skipped, so
19
+ * one malformed patch does not stop the rest of the UI from rendering.
20
+ */
21
+ function createSpecStream(options = {}) {
22
+ const mode = options.mode ?? "jsonl";
23
+ let spec = options.initial ?? emptySpec();
24
+ let buffer = "";
25
+ let lineNumber = 0;
26
+ let fence;
27
+ let fenceIsSpec = false;
28
+ let finished = false;
29
+ /** Characters of the current, unfinished line already emitted as prose. */
30
+ let proseEmitted = 0;
31
+ const allPatches = [];
32
+ const allErrors = [];
33
+ let allText = "";
34
+ const applyLine = (raw, update, terminated) => {
35
+ lineNumber++;
36
+ const line = raw.replace(/\r$/, "");
37
+ const emitted = proseEmitted;
38
+ proseEmitted = 0;
39
+ const prose = () => {
40
+ const text = (terminated ? `${line}\n` : line).slice(emitted);
41
+ update.text += text;
42
+ allText += text;
43
+ };
44
+ if (mode === "inline") {
45
+ const fenceMatch = FENCE.exec(line);
46
+ if (fenceMatch) {
47
+ if (fence === void 0) {
48
+ fence = fenceMatch[1];
49
+ fenceIsSpec = SPEC_FENCES.has(fenceMatch[2].toLowerCase());
50
+ if (!fenceIsSpec) prose();
51
+ return;
52
+ }
53
+ if (fenceMatch[1].startsWith(fence) && !fenceMatch[2]) {
54
+ if (!fenceIsSpec) prose();
55
+ fence = void 0;
56
+ fenceIsSpec = false;
57
+ return;
58
+ }
59
+ }
60
+ if (!(fence !== void 0 && fenceIsSpec || fence === void 0 && LOOKS_LIKE_PATCH.test(line))) {
61
+ prose();
62
+ return;
63
+ }
64
+ }
65
+ const trimmed = line.trim();
66
+ if (!trimmed) return;
67
+ const fail = (message) => {
68
+ const error = {
69
+ line: lineNumber,
70
+ message,
71
+ text: trimmed.slice(0, 200)
72
+ };
73
+ update.errors.push(error);
74
+ allErrors.push(error);
75
+ };
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(trimmed);
79
+ } catch {
80
+ fail("not valid JSON");
81
+ return;
82
+ }
83
+ if (isSpecShape(parsed)) {
84
+ spec = {
85
+ state: {},
86
+ ...parsed
87
+ };
88
+ return;
89
+ }
90
+ const operations = Array.isArray(parsed) ? parsed : [parsed];
91
+ for (const candidate of operations) {
92
+ const checked = checkPatchOperation(candidate);
93
+ if (!checked.ok) {
94
+ fail(checked.error);
95
+ continue;
96
+ }
97
+ try {
98
+ const next = applyPatchOperation(spec, checked.op, { createMissing: true });
99
+ if (!isSpecShape(next)) throw new Error("A spec needs a string root, an elements object, and optional state object");
100
+ spec = next;
101
+ update.patches.push(checked.op);
102
+ allPatches.push(checked.op);
103
+ } catch (error) {
104
+ fail(error instanceof Error ? error.message : String(error));
105
+ }
106
+ }
107
+ };
108
+ const push = (chunk) => {
109
+ if (finished) throw new Error("The spec stream already finished");
110
+ const update = {
111
+ patches: [],
112
+ text: "",
113
+ errors: []
114
+ };
115
+ buffer += chunk;
116
+ let newline = buffer.indexOf("\n");
117
+ while (newline !== -1) {
118
+ const line = buffer.slice(0, newline);
119
+ buffer = buffer.slice(newline + 1);
120
+ applyLine(line, update, true);
121
+ newline = buffer.indexOf("\n");
122
+ }
123
+ if (mode === "inline" && fence === void 0 && buffer.length > proseEmitted && PROSE_START.test(buffer)) {
124
+ const end = buffer.endsWith("\r") ? buffer.length - 1 : buffer.length;
125
+ const text = buffer.slice(proseEmitted, end);
126
+ proseEmitted = end;
127
+ update.text += text;
128
+ allText += text;
129
+ }
130
+ return {
131
+ spec,
132
+ ...update
133
+ };
134
+ };
135
+ return {
136
+ push,
137
+ result() {
138
+ if (!finished && buffer) {
139
+ const rest = buffer;
140
+ buffer = "";
141
+ applyLine(rest, {
142
+ patches: [],
143
+ text: "",
144
+ errors: []
145
+ }, false);
146
+ }
147
+ finished = true;
148
+ return {
149
+ spec,
150
+ patches: [...allPatches],
151
+ text: allText,
152
+ errors: [...allErrors]
153
+ };
154
+ },
155
+ get spec() {
156
+ return spec;
157
+ }
158
+ };
159
+ }
160
+ /** Parses complete JSONL or inline output in one go. */
161
+ function parseSpecStream(source, options = {}) {
162
+ const stream = createSpecStream(options);
163
+ stream.push(source);
164
+ return stream.result();
165
+ }
166
+ export { createSpecStream, parseSpecStream };
167
+
168
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","names":[],"sources":["../../src/spec/stream.ts"],"sourcesContent":["import { applyPatchOperation, checkPatchOperation } from \"./patch\";\nimport { emptySpec, type PatchOperation, type Spec } from \"./types\";\n\n/**\n * `jsonl`: every non-empty line is a patch operation (what `render_spec`\n * receives). `inline`: prose and patches interleave, as in a chat reply;\n * patch lines sit in a ```spec fence or start with `{\"op\"`, everything else\n * is text.\n */\nexport type SpecStreamMode = \"jsonl\" | \"inline\";\n\nexport type SpecStreamError = { line: number; message: string; text: string };\n\nexport type SpecStreamUpdate = {\n /** The spec after every patch so far. A new object only when it changed. */\n spec: Spec;\n /** Operations applied by this push. */\n patches: PatchOperation[];\n /** Prose added by this push (inline mode). */\n text: string;\n /** Errors from lines completed by this push. */\n errors: SpecStreamError[];\n};\n\nexport type SpecStreamResult = {\n spec: Spec;\n patches: PatchOperation[];\n text: string;\n errors: SpecStreamError[];\n};\n\nexport type SpecStream = {\n /** Feeds raw model output; partial lines wait for their newline. */\n push(chunk: string): SpecStreamUpdate;\n /** Processes a trailing line without a newline and returns everything so far. */\n result(): SpecStreamResult;\n readonly spec: Spec;\n};\n\nexport type CreateSpecStreamOptions = {\n mode?: SpecStreamMode;\n /** Spec to apply patches onto. Defaults to an empty spec. */\n initial?: Spec;\n};\n\nconst FENCE = /^\\s*(`{3,}|~{3,})\\s*([\\w-]*)\\s*$/;\nconst SPEC_FENCES = new Set([\"spec\", \"jsonl\", \"json-patch\", \"spec-jsonl\"]);\nconst LOOKS_LIKE_PATCH = /^\\s*\\{\\s*\"op\"\\s*:/;\n/** A partial line that can no longer turn into a patch or a fence. */\nconst PROSE_START = /^\\s*[^\\s{`~]/;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isSpecShape = (value: unknown): value is Spec =>\n isRecord(value) &&\n typeof value[\"root\"] === \"string\" &&\n isRecord(value[\"elements\"]) &&\n (value[\"state\"] === undefined || isRecord(value[\"state\"]));\n\n/**\n * Turns a stream of JSONL patch lines (optionally interleaved with prose)\n * into a progressively built spec. Bad lines are reported and skipped, so\n * one malformed patch does not stop the rest of the UI from rendering.\n */\nexport function createSpecStream(\n options: CreateSpecStreamOptions = {},\n): SpecStream {\n const mode = options.mode ?? \"jsonl\";\n let spec: Spec = options.initial ?? emptySpec();\n let buffer = \"\";\n let lineNumber = 0;\n let fence: string | undefined;\n let fenceIsSpec = false;\n let finished = false;\n /** Characters of the current, unfinished line already emitted as prose. */\n let proseEmitted = 0;\n const allPatches: PatchOperation[] = [];\n const allErrors: SpecStreamError[] = [];\n let allText = \"\";\n\n const applyLine = (\n raw: string,\n update: {\n patches: PatchOperation[];\n text: string;\n errors: SpecStreamError[];\n },\n terminated: boolean,\n ) => {\n lineNumber++;\n const line = raw.replace(/\\r$/, \"\");\n const emitted = proseEmitted;\n proseEmitted = 0;\n const prose = () => {\n const text = (terminated ? `${line}\\n` : line).slice(emitted);\n update.text += text;\n allText += text;\n };\n\n if (mode === \"inline\") {\n const fenceMatch = FENCE.exec(line);\n if (fenceMatch) {\n if (fence === undefined) {\n fence = fenceMatch[1]!;\n fenceIsSpec = SPEC_FENCES.has(fenceMatch[2]!.toLowerCase());\n if (!fenceIsSpec) prose();\n return;\n }\n if (fenceMatch[1]!.startsWith(fence) && !fenceMatch[2]) {\n if (!fenceIsSpec) prose();\n fence = undefined;\n fenceIsSpec = false;\n return;\n }\n }\n const isPatchLine =\n (fence !== undefined && fenceIsSpec) ||\n (fence === undefined && LOOKS_LIKE_PATCH.test(line));\n if (!isPatchLine) {\n prose();\n return;\n }\n }\n\n const trimmed = line.trim();\n if (!trimmed) return;\n const fail = (message: string) => {\n const error = { line: lineNumber, message, text: trimmed.slice(0, 200) };\n update.errors.push(error);\n allErrors.push(error);\n };\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n fail(\"not valid JSON\");\n return;\n }\n\n if (isSpecShape(parsed)) {\n spec = { state: {}, ...parsed };\n return;\n }\n const operations = Array.isArray(parsed) ? parsed : [parsed];\n for (const candidate of operations) {\n const checked = checkPatchOperation(candidate);\n if (!checked.ok) {\n fail(checked.error);\n continue;\n }\n try {\n const next = applyPatchOperation(spec, checked.op, {\n createMissing: true,\n });\n if (!isSpecShape(next)) {\n throw new Error(\n \"A spec needs a string root, an elements object, and optional state object\",\n );\n }\n spec = next;\n update.patches.push(checked.op);\n allPatches.push(checked.op);\n } catch (error) {\n fail(error instanceof Error ? error.message : String(error));\n }\n }\n };\n\n const push = (chunk: string): SpecStreamUpdate => {\n if (finished) throw new Error(\"The spec stream already finished\");\n const update = { patches: [], text: \"\", errors: [] } as Omit<\n SpecStreamUpdate,\n \"spec\"\n >;\n buffer += chunk;\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n const line = buffer.slice(0, newline);\n buffer = buffer.slice(newline + 1);\n applyLine(line, update, true);\n newline = buffer.indexOf(\"\\n\");\n }\n if (\n mode === \"inline\" &&\n fence === undefined &&\n buffer.length > proseEmitted &&\n PROSE_START.test(buffer)\n ) {\n const end = buffer.endsWith(\"\\r\") ? buffer.length - 1 : buffer.length;\n const text = buffer.slice(proseEmitted, end);\n proseEmitted = end;\n update.text += text;\n allText += text;\n }\n return { spec, ...update };\n };\n\n return {\n push,\n result() {\n if (!finished && buffer) {\n const rest = buffer;\n buffer = \"\";\n applyLine(rest, { patches: [], text: \"\", errors: [] }, false);\n }\n finished = true;\n return {\n spec,\n patches: [...allPatches],\n text: allText,\n errors: [...allErrors],\n };\n },\n get spec() {\n return spec;\n },\n };\n}\n\n/** Parses complete JSONL or inline output in one go. */\nexport function parseSpecStream(\n source: string,\n options: CreateSpecStreamOptions = {},\n): SpecStreamResult {\n const stream = createSpecStream(options);\n stream.push(source);\n return stream.result();\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createSpecTools, SPEC_TOOL_RESULTS_RULE, specGuidanceModule, type CreateSpecToolsOptions, type RenderSpecInput, type RenderSpecResult, type RenderSpecTool, type SpecTools, } from "./render-spec.js";
2
+ export { getToolDeclarations, toAISDKTools, type GuidanceModule, type JsonSchema, type ToolDefinition, } from "../tools/define.js";
3
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","mappings":"AAAA,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,kBAAe;AACtB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,oBAAiB","names":[],"ignoreList":[],"sources":["../../src/spec/tools.ts"],"sourcesContent":[null]}
@@ -0,0 +1,3 @@
1
+ import { SPEC_TOOL_RESULTS_RULE, createSpecTools, specGuidanceModule } from "./render-spec.js";
2
+ import { getToolDeclarations, toAISDKTools } from "../tools/define.js";
3
+ export { SPEC_TOOL_RESULTS_RULE, createSpecTools, getToolDeclarations, specGuidanceModule, toAISDKTools };
@@ -0,0 +1,21 @@
1
+ import { type ExpressionContext } from "./expressions.js";
2
+ import type { SpecElement } from "./types.js";
3
+ /** What the children of a `repeat` read about their item. */
4
+ export type RepeatScope = Pick<ExpressionContext, "item" | "index" | "itemPath">;
5
+ /** The element ids in a slot, where `default` is `children`. */
6
+ export declare const childIdsOf: (element: SpecElement, slot: string) => string[];
7
+ /** A JSON Pointer for a state path written with or without its leading slash. */
8
+ export declare const safePointer: (path: string) => string;
9
+ /**
10
+ * The items a `repeat` renders its children for, each with its key (the
11
+ * item's `key` field, else its index) and the scope its children read, or
12
+ * `undefined` when the state at `path` is not an array.
13
+ */
14
+ export declare function repeatItems(repeat: {
15
+ path: string;
16
+ key?: string;
17
+ }, state: unknown): {
18
+ key: string;
19
+ scope: RepeatScope;
20
+ }[] | undefined;
21
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","mappings":"AAAA,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,kBAAe;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAS;AAE1C;AACA,MAAM,MAAM,WAAW,GAAG,IAAI,CAC5B,iBAAiB,EACjB,MAAM,GAAG,OAAO,GAAG,UAAU,CAC9B;AAED;AACA,eAAO,MAAM,UAAU,GAAI,SAAS,WAAW,EAAE,MAAM,MAAM,aACU;AAEvE;AACA,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WACiB;AAEzD;;;;;AAKA,wBAAgB,WAAW,CACzB,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM;IAAE,GAAG,CAAC,EAAE,MAAM;CAAE,EACtC,KAAK,EAAE,OAAO,GACb;IAAE,GAAG,EAAE,MAAM;IAAE,KAAK,EAAE,WAAW;CAAE,EAAE,GAAG,SAAS","names":[],"ignoreList":[],"sources":["../../src/spec/tree.ts"],"sourcesContent":[null]}
@@ -0,0 +1,27 @@
1
+ import { getAtPointer } from "./pointer.js";
2
+ import { itemPointer } from "./expressions.js";
3
+ // src/spec/tree.ts
4
+ /** The element ids in a slot, where `default` is `children`. */
5
+ const childIdsOf = (element, slot) => (slot === "default" ? element.children : element.slots?.[slot]) ?? [];
6
+ /** A JSON Pointer for a state path written with or without its leading slash. */
7
+ const safePointer = (path) => path.startsWith("/") || path === "" ? path : `/${path}`;
8
+ /**
9
+ * The items a `repeat` renders its children for, each with its key (the
10
+ * item's `key` field, else its index) and the scope its children read, or
11
+ * `undefined` when the state at `path` is not an array.
12
+ */
13
+ function repeatItems(repeat, state) {
14
+ const items = getAtPointer(state, safePointer(repeat.path));
15
+ if (!Array.isArray(items)) return void 0;
16
+ return items.map((item, index) => ({
17
+ key: repeat.key && item && typeof item === "object" ? String(item[repeat.key] ?? index) : String(index),
18
+ scope: {
19
+ item,
20
+ index,
21
+ itemPath: itemPointer(repeat.path, index)
22
+ }
23
+ }));
24
+ }
25
+ export { childIdsOf, repeatItems, safePointer };
26
+
27
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","names":[],"sources":["../../src/spec/tree.ts"],"sourcesContent":["import { itemPointer, type ExpressionContext } from \"./expressions\";\nimport { getAtPointer } from \"./pointer\";\nimport type { SpecElement } from \"./types\";\n\n/** What the children of a `repeat` read about their item. */\nexport type RepeatScope = Pick<\n ExpressionContext,\n \"item\" | \"index\" | \"itemPath\"\n>;\n\n/** The element ids in a slot, where `default` is `children`. */\nexport const childIdsOf = (element: SpecElement, slot: string) =>\n (slot === \"default\" ? element.children : element.slots?.[slot]) ?? [];\n\n/** A JSON Pointer for a state path written with or without its leading slash. */\nexport const safePointer = (path: string) =>\n path.startsWith(\"/\") || path === \"\" ? path : `/${path}`;\n\n/**\n * The items a `repeat` renders its children for, each with its key (the\n * item's `key` field, else its index) and the scope its children read, or\n * `undefined` when the state at `path` is not an array.\n */\nexport function repeatItems(\n repeat: { path: string; key?: string },\n state: unknown,\n): { key: string; scope: RepeatScope }[] | undefined {\n const items = getAtPointer(state, safePointer(repeat.path));\n if (!Array.isArray(items)) return undefined;\n return items.map((item: unknown, index) => ({\n key:\n repeat.key && item && typeof item === \"object\"\n ? String((item as Record<string, unknown>)[repeat.key] ?? index)\n : String(index),\n scope: { item, index, itemPath: itemPointer(repeat.path, index) },\n }));\n}\n"],"mappings":";;;;AAWA,MAAa,cAAc,SAAsB,UAC9C,SAAS,YAAY,QAAQ,WAAW,QAAQ,QAAQ,UAAU,CAAC;;AAGtE,MAAa,eAAe,SAC1B,KAAK,WAAW,GAAG,KAAK,SAAS,KAAK,OAAO,IAAI;;;;;;AAOnD,SAAgB,YACd,QACA,OACmD;CACnD,MAAM,QAAQ,aAAa,OAAO,YAAY,OAAO,IAAI,CAAC;CAC1D,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;CAClC,OAAO,MAAM,KAAK,MAAe,WAAW;EAC1C,KACE,OAAO,OAAO,QAAQ,OAAO,SAAS,WAClC,OAAQ,KAAiC,OAAO,QAAQ,KAAK,IAC7D,OAAO,KAAK;EAClB,OAAO;GAAE;GAAM;GAAO,UAAU,YAAY,OAAO,MAAM,KAAK;EAAE;CAClE,EAAE;AACJ"}
@@ -0,0 +1,66 @@
1
+ /** Runs a catalog action, or the built-in `setState`, when an element emits an event. */
2
+ export type ActionBinding = {
3
+ action: string;
4
+ params?: Record<string, unknown>;
5
+ };
6
+ /**
7
+ * A visibility condition: a boolean, a value expression (truthy test), a
8
+ * comparison (`{ $state: "/x", gt: 3 }`), `{ not: condition }`,
9
+ * `{ $and: [...] }`, `{ $or: [...] }`, or an array (all must hold).
10
+ */
11
+ export type Condition = boolean | readonly Condition[] | {
12
+ readonly [key: string]: unknown;
13
+ };
14
+ /** One node of a spec. Children are referenced by element id. */
15
+ export type SpecElement = {
16
+ type: string;
17
+ props?: Record<string, unknown>;
18
+ /** Ids of the elements in the component's default slot. */
19
+ children?: string[];
20
+ /** Ids per named slot, for components that declare more than `default`. */
21
+ slots?: Record<string, string[]>;
22
+ /** Renders the element only while the condition holds. */
23
+ visible?: Condition;
24
+ /** Renders the children once per item of the array at `path` in state. */
25
+ repeat?: {
26
+ path: string;
27
+ key?: string;
28
+ };
29
+ /** Actions to run when the component emits an event, keyed by event name. */
30
+ on?: Record<string, ActionBinding | ActionBinding[]>;
31
+ /** Actions to run when the state value at a path changes, keyed by JSON Pointer. */
32
+ watch?: Record<string, ActionBinding | ActionBinding[]>;
33
+ };
34
+ /** A flat spec: the root element id, every element by id, and initial state. */
35
+ export type Spec = {
36
+ root: string;
37
+ elements: Record<string, SpecElement>;
38
+ state?: Record<string, unknown>;
39
+ };
40
+ /** One RFC 6902 operation. Paths are JSON Pointers into the spec. */
41
+ export type PatchOperation = {
42
+ op: "add";
43
+ path: string;
44
+ value: unknown;
45
+ } | {
46
+ op: "replace";
47
+ path: string;
48
+ value: unknown;
49
+ } | {
50
+ op: "remove";
51
+ path: string;
52
+ } | {
53
+ op: "move";
54
+ from: string;
55
+ path: string;
56
+ } | {
57
+ op: "copy";
58
+ from: string;
59
+ path: string;
60
+ } | {
61
+ op: "test";
62
+ path: string;
63
+ value: unknown;
64
+ };
65
+ export declare const emptySpec: () => Spec;
66
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","mappings":"AAAA;AACA,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACjC;AAED;;;;;AAKA,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,SAAS,SAAS,EAAE,GACpB;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAAE;AAEvC;AACA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/B;IACA,QAAQ,CAAC,EAAE,MAAM,EAAE;IACnB;IACA,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAChC;IACA,OAAO,CAAC,EAAE,SAAS;IACnB;IACA,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM;QAAE,GAAG,CAAC,EAAE,MAAM;KAAE;IACvC;IACA,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,CAAC;IACpD;IACA,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,CAAC;CACxD;AAED;AACA,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAChC;AAED;AACA,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,KAAK;IAAE,IAAI,EAAE,MAAM;IAAE,KAAK,EAAE,OAAO;CAAE,GAC3C;IAAE,EAAE,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM;IAAE,KAAK,EAAE,OAAO;CAAE,GAC/C;IAAE,EAAE,EAAE,QAAQ;IAAE,IAAI,EAAE,MAAM;CAAE,GAC9B;IAAE,EAAE,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;CAAE,GAC1C;IAAE,EAAE,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;CAAE,GAC1C;IAAE,EAAE,EAAE,MAAM;IAAE,IAAI,EAAE,MAAM;IAAE,KAAK,EAAE,OAAO;CAAE;AAEhD,eAAO,MAAM,SAAS,QAAO,IAA+C","names":[],"ignoreList":[],"sources":["../../src/spec/types.ts"],"sourcesContent":[null]}
@@ -0,0 +1,9 @@
1
+ // src/spec/types.ts
2
+ const emptySpec = () => ({
3
+ root: "",
4
+ elements: {},
5
+ state: {}
6
+ });
7
+ export { emptySpec };
8
+
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/spec/types.ts"],"sourcesContent":["/** Runs a catalog action, or the built-in `setState`, when an element emits an event. */\nexport type ActionBinding = {\n action: string;\n params?: Record<string, unknown>;\n};\n\n/**\n * A visibility condition: a boolean, a value expression (truthy test), a\n * comparison (`{ $state: \"/x\", gt: 3 }`), `{ not: condition }`,\n * `{ $and: [...] }`, `{ $or: [...] }`, or an array (all must hold).\n */\nexport type Condition =\n | boolean\n | readonly Condition[]\n | { readonly [key: string]: unknown };\n\n/** One node of a spec. Children are referenced by element id. */\nexport type SpecElement = {\n type: string;\n props?: Record<string, unknown>;\n /** Ids of the elements in the component's default slot. */\n children?: string[];\n /** Ids per named slot, for components that declare more than `default`. */\n slots?: Record<string, string[]>;\n /** Renders the element only while the condition holds. */\n visible?: Condition;\n /** Renders the children once per item of the array at `path` in state. */\n repeat?: { path: string; key?: string };\n /** Actions to run when the component emits an event, keyed by event name. */\n on?: Record<string, ActionBinding | ActionBinding[]>;\n /** Actions to run when the state value at a path changes, keyed by JSON Pointer. */\n watch?: Record<string, ActionBinding | ActionBinding[]>;\n};\n\n/** A flat spec: the root element id, every element by id, and initial state. */\nexport type Spec = {\n root: string;\n elements: Record<string, SpecElement>;\n state?: Record<string, unknown>;\n};\n\n/** One RFC 6902 operation. Paths are JSON Pointers into the spec. */\nexport type PatchOperation =\n | { op: \"add\"; path: string; value: unknown }\n | { op: \"replace\"; path: string; value: unknown }\n | { op: \"remove\"; path: string }\n | { op: \"move\"; from: string; path: string }\n | { op: \"copy\"; from: string; path: string }\n | { op: \"test\"; path: string; value: unknown };\n\nexport const emptySpec = (): Spec => ({ root: \"\", elements: {}, state: {} });\n"],"mappings":";AAkDA,MAAa,mBAAyB;CAAE,MAAM;CAAI,UAAU,CAAC;CAAG,OAAO,CAAC;AAAE"}