@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,162 @@
1
+ import {
2
+ computed,
3
+ onScopeDispose,
4
+ shallowRef,
5
+ toValue,
6
+ watch,
7
+ type MaybeRefOrGetter,
8
+ type ShallowRef,
9
+ } from "vue";
10
+ import {
11
+ createSpecStream,
12
+ parseSpecStream,
13
+ type SpecStream,
14
+ type SpecStreamError,
15
+ type SpecStreamMode,
16
+ } from "../stream";
17
+ import { emptySpec, type Spec } from "../types";
18
+ export type UseSpecStreamOptions = {
19
+ source?: string;
20
+ complete?: boolean;
21
+ mode?: SpecStreamMode;
22
+ initial?: Spec;
23
+ };
24
+ export type UseSpecStreamResult = {
25
+ spec: Readonly<ShallowRef<Spec>>;
26
+ text: Readonly<ShallowRef<string>>;
27
+ errors: Readonly<ShallowRef<SpecStreamError[]>>;
28
+ push(chunk: string): void;
29
+ end(): void;
30
+ reset(): void;
31
+ };
32
+ type Snapshot = { spec: Spec; text: string; errors: SpecStreamError[] };
33
+ type Follower = {
34
+ stream: SpecStream;
35
+ consumed: string;
36
+ mode: SpecStreamMode;
37
+ generation: number;
38
+ text: string;
39
+ errors: SpecStreamError[];
40
+ };
41
+ export function useSpecStream(
42
+ options: MaybeRefOrGetter<UseSpecStreamOptions> = {},
43
+ ): UseSpecStreamResult {
44
+ const generation = shallowRef(0);
45
+ const snapshot = shallowRef<Snapshot>({
46
+ spec: toValue(options).initial ?? emptySpec(),
47
+ text: "",
48
+ errors: [],
49
+ });
50
+ const followed = shallowRef<Snapshot | null>(null);
51
+ let follower: Follower | null = null;
52
+ let imperative: SpecStream | null = null;
53
+ let disposed = false;
54
+ const start = () => {
55
+ const { initial, mode = "jsonl" } = toValue(options);
56
+ return createSpecStream({ mode, ...(initial ? { initial } : {}) });
57
+ };
58
+ watch(
59
+ () =>
60
+ [
61
+ toValue(options).source,
62
+ toValue(options).complete ?? false,
63
+ toValue(options).mode ?? "jsonl",
64
+ generation.value,
65
+ ] as const,
66
+ ([source, complete, mode, currentGeneration]) => {
67
+ if (source === undefined) {
68
+ followed.value = null;
69
+ return;
70
+ }
71
+ const initial = toValue(options).initial;
72
+ if (complete) {
73
+ const result = parseSpecStream(source, {
74
+ mode,
75
+ ...(initial ? { initial } : {}),
76
+ });
77
+ follower = null;
78
+ followed.value = {
79
+ spec: result.spec,
80
+ text: result.text,
81
+ errors: result.errors,
82
+ };
83
+ return;
84
+ }
85
+ if (
86
+ !follower ||
87
+ follower.mode !== mode ||
88
+ follower.generation !== currentGeneration ||
89
+ !source.startsWith(follower.consumed)
90
+ ) {
91
+ follower = {
92
+ stream: start(),
93
+ consumed: "",
94
+ mode,
95
+ generation: currentGeneration,
96
+ text: "",
97
+ errors: [],
98
+ };
99
+ }
100
+ if (source.length > follower.consumed.length) {
101
+ const update = follower.stream.push(
102
+ source.slice(follower.consumed.length),
103
+ );
104
+ follower.consumed = source;
105
+ if (update.text) follower.text += update.text;
106
+ if (update.errors.length)
107
+ follower.errors = [...follower.errors, ...update.errors];
108
+ }
109
+ followed.value = {
110
+ spec: follower.stream.spec,
111
+ text: follower.text,
112
+ errors: follower.errors,
113
+ };
114
+ },
115
+ { immediate: true, flush: "pre" },
116
+ );
117
+ onScopeDispose(() => {
118
+ disposed = true;
119
+ follower = null;
120
+ imperative = null;
121
+ });
122
+ const current = computed(() => followed.value ?? snapshot.value);
123
+ return {
124
+ spec: computed(() => current.value.spec),
125
+ text: computed(() => current.value.text),
126
+ errors: computed(() => current.value.errors),
127
+ push(chunk) {
128
+ if (disposed) return;
129
+ imperative ??= start();
130
+ const update = imperative.push(chunk);
131
+ const previous = snapshot.value;
132
+ if (update.spec !== previous.spec || update.text || update.errors.length)
133
+ snapshot.value = {
134
+ spec: update.spec,
135
+ text: previous.text + update.text,
136
+ errors: update.errors.length
137
+ ? [...previous.errors, ...update.errors]
138
+ : previous.errors,
139
+ };
140
+ },
141
+ end() {
142
+ if (disposed || !imperative) return;
143
+ const result = imperative.result();
144
+ imperative = null;
145
+ snapshot.value = {
146
+ spec: result.spec,
147
+ text: result.text,
148
+ errors: result.errors,
149
+ };
150
+ },
151
+ reset() {
152
+ if (disposed) return;
153
+ imperative = null;
154
+ generation.value++;
155
+ snapshot.value = {
156
+ spec: toValue(options).initial ?? emptySpec(),
157
+ text: "",
158
+ errors: [],
159
+ };
160
+ },
161
+ };
162
+ }
@@ -0,0 +1,13 @@
1
+ export {
2
+ SpecRenderer,
3
+ SpecPlaceholder,
4
+ type SpecComponentProps,
5
+ type SpecComponents,
6
+ type SpecPlaceholderProps,
7
+ type SpecRendererProps,
8
+ } from "./vue/SpecRenderer";
9
+ export {
10
+ useSpecStream,
11
+ type UseSpecStreamOptions,
12
+ type UseSpecStreamResult,
13
+ } from "./vue/useSpecStream";
package/src/spec.ts ADDED
@@ -0,0 +1,55 @@
1
+ export type {
2
+ ActionBinding,
3
+ Condition,
4
+ PatchOperation,
5
+ Spec,
6
+ SpecElement,
7
+ } from "./spec/types";
8
+ export { emptySpec } from "./spec/types";
9
+ export {
10
+ defineCatalog,
11
+ type ActionDefinition,
12
+ type Catalog,
13
+ type CatalogDefinition,
14
+ type ComponentDefinition,
15
+ type PropsSchema,
16
+ } from "./spec/catalog";
17
+ export type { SpecPromptOptions } from "./spec/prompt";
18
+ export {
19
+ createSpecStream,
20
+ parseSpecStream,
21
+ type CreateSpecStreamOptions,
22
+ type SpecStream,
23
+ type SpecStreamError,
24
+ type SpecStreamMode,
25
+ type SpecStreamResult,
26
+ type SpecStreamUpdate,
27
+ } from "./spec/stream";
28
+ export { applyPatch } from "./spec/patch";
29
+ export {
30
+ formatSpecIssues,
31
+ validateSpec,
32
+ type SpecIssue,
33
+ type SpecIssueCode,
34
+ type SpecValidation,
35
+ type ValidateSpecOptions,
36
+ } from "./spec/validate";
37
+ export {
38
+ createStateStore,
39
+ type SpecStateStore,
40
+ type SpecStateWrite,
41
+ type StateListener,
42
+ type StateStoreOptions,
43
+ } from "./spec/state";
44
+ export {
45
+ resolveSpec,
46
+ type ResolveSpecOptions,
47
+ type ResolvedAction,
48
+ type ResolvedElement,
49
+ } from "./spec/resolve";
50
+ export type { ActionHandler, ActionSource } from "./spec/actions";
51
+ export type {
52
+ JsonSchema,
53
+ JsonSchemaType,
54
+ StandardSchemaLike,
55
+ } from "./json-schema";
package/src/theme.ts ADDED
@@ -0,0 +1,423 @@
1
+ import type { ColorScheme } from "./protocol";
2
+
3
+ /** Theme values sent into a widget frame, keyed by CSS custom property name. */
4
+ export type ThemeTokens = {
5
+ colorScheme: ColorScheme;
6
+ variables: Record<string, string>;
7
+ };
8
+
9
+ export type ThemeTokenName =
10
+ | "--color-background"
11
+ | "--color-surface"
12
+ | "--color-surface-muted"
13
+ | "--color-text"
14
+ | "--color-text-muted"
15
+ | "--color-text-subtle"
16
+ | "--color-border"
17
+ | "--color-border-strong"
18
+ | "--color-accent"
19
+ | "--color-accent-text"
20
+ | "--color-danger"
21
+ | "--color-success"
22
+ | "--color-warning"
23
+ | "--color-info"
24
+ | "--chart-1"
25
+ | "--chart-2"
26
+ | "--chart-3"
27
+ | "--chart-4"
28
+ | "--chart-5"
29
+ | "--chart-6"
30
+ | "--font-sans"
31
+ | "--font-mono"
32
+ | "--radius-sm"
33
+ | "--radius-md"
34
+ | "--radius-lg";
35
+
36
+ export type ThemeTokenInfo = {
37
+ name: ThemeTokenName;
38
+ group:
39
+ | "surface"
40
+ | "text"
41
+ | "border"
42
+ | "accent"
43
+ | "status"
44
+ | "chart"
45
+ | "type"
46
+ | "shape";
47
+ usage: string;
48
+ };
49
+
50
+ /** The canonical tokens every frame defines, in prompt order. */
51
+ export const THEME_TOKENS: readonly ThemeTokenInfo[] = [
52
+ {
53
+ name: "--color-background",
54
+ group: "surface",
55
+ usage:
56
+ "the host page behind the widget; for knockouts only, the widget itself stays transparent",
57
+ },
58
+ {
59
+ name: "--color-surface",
60
+ group: "surface",
61
+ usage: "cards, panels, popovers",
62
+ },
63
+ {
64
+ name: "--color-surface-muted",
65
+ group: "surface",
66
+ usage: "wells, table stripes, hover fills, code blocks",
67
+ },
68
+ {
69
+ name: "--color-text",
70
+ group: "text",
71
+ usage: "body text, headings, primary values",
72
+ },
73
+ {
74
+ name: "--color-text-muted",
75
+ group: "text",
76
+ usage: "labels, secondary text, axis titles",
77
+ },
78
+ {
79
+ name: "--color-text-subtle",
80
+ group: "text",
81
+ usage: "captions, tick labels, placeholders, disabled",
82
+ },
83
+ {
84
+ name: "--color-border",
85
+ group: "border",
86
+ usage: "hairlines, dividers, card outlines, gridlines",
87
+ },
88
+ {
89
+ name: "--color-border-strong",
90
+ group: "border",
91
+ usage: "inputs, emphasized outlines, focus-adjacent edges",
92
+ },
93
+ {
94
+ name: "--color-accent",
95
+ group: "accent",
96
+ usage: "primary actions, selection, the one highlighted series",
97
+ },
98
+ {
99
+ name: "--color-accent-text",
100
+ group: "accent",
101
+ usage: "text and icons placed on --color-accent",
102
+ },
103
+ {
104
+ name: "--color-danger",
105
+ group: "status",
106
+ usage: "errors, destructive actions, negative deltas",
107
+ },
108
+ {
109
+ name: "--color-success",
110
+ group: "status",
111
+ usage: "success, positive deltas",
112
+ },
113
+ {
114
+ name: "--color-warning",
115
+ group: "status",
116
+ usage: "warnings, pending states",
117
+ },
118
+ {
119
+ name: "--color-info",
120
+ group: "status",
121
+ usage: "neutral notices, links inside callouts",
122
+ },
123
+ { name: "--chart-1", group: "chart", usage: "first categorical series" },
124
+ { name: "--chart-2", group: "chart", usage: "second categorical series" },
125
+ { name: "--chart-3", group: "chart", usage: "third categorical series" },
126
+ { name: "--chart-4", group: "chart", usage: "fourth categorical series" },
127
+ { name: "--chart-5", group: "chart", usage: "fifth categorical series" },
128
+ { name: "--chart-6", group: "chart", usage: "sixth categorical series" },
129
+ { name: "--font-sans", group: "type", usage: "all UI text" },
130
+ { name: "--font-mono", group: "type", usage: "code, tabular identifiers" },
131
+ {
132
+ name: "--radius-sm",
133
+ group: "shape",
134
+ usage: "chips, inputs, small buttons",
135
+ },
136
+ { name: "--radius-md", group: "shape", usage: "buttons, cards" },
137
+ { name: "--radius-lg", group: "shape", usage: "large panels, dialogs" },
138
+ ];
139
+
140
+ const SHARED: Partial<Record<ThemeTokenName, string>> = {
141
+ "--font-sans":
142
+ 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
143
+ "--font-mono":
144
+ 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
145
+ "--radius-sm": "6px",
146
+ "--radius-md": "8px",
147
+ "--radius-lg": "12px",
148
+ };
149
+
150
+ export const DEFAULT_LIGHT_TOKENS: ThemeTokens = {
151
+ colorScheme: "light",
152
+ variables: {
153
+ ...SHARED,
154
+ "--color-background": "#ffffff",
155
+ "--color-surface": "#ffffff",
156
+ "--color-surface-muted": "#f4f4f5",
157
+ "--color-text": "#18181b",
158
+ "--color-text-muted": "#52525b",
159
+ "--color-text-subtle": "#71717a",
160
+ "--color-border": "#e4e4e7",
161
+ "--color-border-strong": "#d4d4d8",
162
+ "--color-accent": "#2563eb",
163
+ "--color-accent-text": "#ffffff",
164
+ "--color-danger": "#dc2626",
165
+ "--color-success": "#16a34a",
166
+ "--color-warning": "#d97706",
167
+ "--color-info": "#0284c7",
168
+ "--chart-1": "#2563eb",
169
+ "--chart-2": "#0d9488",
170
+ "--chart-3": "#d97706",
171
+ "--chart-4": "#db2777",
172
+ "--chart-5": "#7c3aed",
173
+ "--chart-6": "#65a30d",
174
+ } as Record<string, string>,
175
+ };
176
+
177
+ export const DEFAULT_DARK_TOKENS: ThemeTokens = {
178
+ colorScheme: "dark",
179
+ variables: {
180
+ ...SHARED,
181
+ "--color-background": "#09090b",
182
+ "--color-surface": "#18181b",
183
+ "--color-surface-muted": "#27272a",
184
+ "--color-text": "#fafafa",
185
+ "--color-text-muted": "#a1a1aa",
186
+ "--color-text-subtle": "#71717a",
187
+ "--color-border": "#27272a",
188
+ "--color-border-strong": "#3f3f46",
189
+ "--color-accent": "#3b82f6",
190
+ "--color-accent-text": "#ffffff",
191
+ "--color-danger": "#f87171",
192
+ "--color-success": "#4ade80",
193
+ "--color-warning": "#fbbf24",
194
+ "--color-info": "#38bdf8",
195
+ "--chart-1": "#60a5fa",
196
+ "--chart-2": "#2dd4bf",
197
+ "--chart-3": "#fbbf24",
198
+ "--chart-4": "#f472b6",
199
+ "--chart-5": "#a78bfa",
200
+ "--chart-6": "#a3e635",
201
+ } as Record<string, string>,
202
+ };
203
+
204
+ export const defaultThemeTokens = (scheme: ColorScheme): ThemeTokens =>
205
+ scheme === "dark" ? DEFAULT_DARK_TOKENS : DEFAULT_LIGHT_TOKENS;
206
+
207
+ /**
208
+ * Where `readThemeTokens` looks for each canonical token, first match wins.
209
+ * The defaults read the canonical name, then the shadcn/ui variable.
210
+ */
211
+ export type ThemeTokenSources = Partial<
212
+ Record<ThemeTokenName, string | readonly string[]>
213
+ >;
214
+
215
+ export const DEFAULT_TOKEN_SOURCES: Record<ThemeTokenName, readonly string[]> =
216
+ {
217
+ "--color-background": ["--color-background", "--background"],
218
+ "--color-surface": ["--color-surface", "--card", "--background"],
219
+ "--color-surface-muted": [
220
+ "--color-surface-muted",
221
+ "--muted",
222
+ "--secondary",
223
+ ],
224
+ "--color-text": ["--color-text", "--foreground"],
225
+ "--color-text-muted": ["--color-text-muted", "--muted-foreground"],
226
+ "--color-text-subtle": ["--color-text-subtle", "--muted-foreground"],
227
+ "--color-border": ["--color-border", "--border"],
228
+ "--color-border-strong": ["--color-border-strong", "--input", "--ring"],
229
+ "--color-accent": ["--color-accent", "--primary"],
230
+ "--color-accent-text": ["--color-accent-text", "--primary-foreground"],
231
+ "--color-danger": ["--color-danger", "--destructive"],
232
+ "--color-success": ["--color-success"],
233
+ "--color-warning": ["--color-warning"],
234
+ "--color-info": ["--color-info"],
235
+ "--chart-1": ["--chart-1"],
236
+ "--chart-2": ["--chart-2"],
237
+ "--chart-3": ["--chart-3"],
238
+ "--chart-4": ["--chart-4"],
239
+ "--chart-5": ["--chart-5"],
240
+ "--chart-6": ["--chart-6"],
241
+ "--font-sans": ["--font-sans"],
242
+ "--font-mono": ["--font-mono"],
243
+ "--radius-sm": ["--radius-sm"],
244
+ "--radius-md": ["--radius-md", "--radius"],
245
+ "--radius-lg": ["--radius-lg"],
246
+ };
247
+
248
+ /** shadcn/ui before Tailwind v4 stored colors as bare HSL channels, e.g. `222 47% 11%`. */
249
+ const HSL_CHANNELS =
250
+ /^-?[\d.]+(?:deg)?\s+[\d.]+%\s+[\d.]+%(?:\s*\/\s*[\d.]+%?)?$/;
251
+
252
+ const RGB =
253
+ /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:[\s,/]+([\d.]+))?/i;
254
+
255
+ const schemeFromColor = (color: string): ColorScheme | undefined => {
256
+ const match = RGB.exec(color);
257
+ if (!match || match[4] === "0") return undefined;
258
+ const [r, g, b] = [match[1], match[2], match[3]].map(Number) as [
259
+ number,
260
+ number,
261
+ number,
262
+ ];
263
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b < 128 ? "dark" : "light";
264
+ };
265
+
266
+ /** Infers the color scheme an element renders in. */
267
+ export function detectColorScheme(element: Element): ColorScheme {
268
+ if (element.closest('.dark, [data-theme="dark"], [data-mode="dark"]')) {
269
+ return "dark";
270
+ }
271
+ if (element.closest('.light, [data-theme="light"], [data-mode="light"]')) {
272
+ return "light";
273
+ }
274
+ const view = element.ownerDocument.defaultView;
275
+ const style = view?.getComputedStyle(element);
276
+ const declared = style?.colorScheme.trim();
277
+ if (declared === "dark" || declared === "light") return declared;
278
+ const fromBackground = style && schemeFromColor(style.backgroundColor);
279
+ if (fromBackground) return fromBackground;
280
+ return view?.matchMedia?.("(prefers-color-scheme: dark)").matches
281
+ ? "dark"
282
+ : "light";
283
+ }
284
+
285
+ /**
286
+ * Reads the host page's theme into canonical tokens. Tokens the page does not
287
+ * define fall back to the built-in palette for the detected color scheme.
288
+ */
289
+ export function readThemeTokens(
290
+ element: Element = document.documentElement,
291
+ sources: ThemeTokenSources = {},
292
+ ): ThemeTokens {
293
+ const colorScheme = detectColorScheme(element);
294
+ const style = element.ownerDocument.defaultView?.getComputedStyle(element);
295
+ const defaults = defaultThemeTokens(colorScheme).variables;
296
+ const variables: Record<string, string> = { ...defaults };
297
+ if (!style) return { colorScheme, variables };
298
+
299
+ const declared = new Set<ThemeTokenName>();
300
+ for (const info of THEME_TOKENS) {
301
+ const override = sources[info.name];
302
+ const candidates =
303
+ override === undefined
304
+ ? DEFAULT_TOKEN_SOURCES[info.name]
305
+ : typeof override === "string"
306
+ ? [override]
307
+ : override;
308
+ for (const candidate of candidates) {
309
+ const value = style.getPropertyValue(candidate).trim();
310
+ if (value) {
311
+ declared.add(info.name);
312
+ variables[info.name] = HSL_CHANNELS.test(value)
313
+ ? `hsl(${value})`
314
+ : value;
315
+ break;
316
+ }
317
+ }
318
+ }
319
+
320
+ const radius = style.getPropertyValue("--radius").trim();
321
+ if (radius && !style.getPropertyValue("--radius-sm").trim()) {
322
+ variables["--radius-sm"] = `calc(${radius} - 2px)`;
323
+ }
324
+ if (radius && !style.getPropertyValue("--radius-lg").trim()) {
325
+ variables["--radius-lg"] = `calc(${radius} + 4px)`;
326
+ }
327
+ const doc = element.ownerDocument;
328
+ const font = declared.has("--font-sans")
329
+ ? variables["--font-sans"]
330
+ : doc.defaultView?.getComputedStyle(
331
+ element === doc.documentElement && doc.body ? doc.body : element,
332
+ ).fontFamily;
333
+ // The page's web fonts do not load inside the frame, so the default stacks follow them.
334
+ if (font) variables["--font-sans"] = `${font}, ${SHARED["--font-sans"]}`;
335
+ if (declared.has("--font-mono")) {
336
+ variables["--font-mono"] =
337
+ `${variables["--font-mono"]}, ${SHARED["--font-mono"]}`;
338
+ }
339
+
340
+ return { colorScheme, variables };
341
+ }
342
+
343
+ const tint = (color: string | undefined, percent: number) =>
344
+ color ? `color-mix(in srgb, ${color} ${percent}%, transparent)` : undefined;
345
+
346
+ /**
347
+ * Maps canonical tokens onto the MCP Apps standard style variables, so
348
+ * widgets written for MCP Apps hosts pick up the host theme too.
349
+ */
350
+ export function toMcpAppsVariables(
351
+ tokens: ThemeTokens,
352
+ ): Record<string, string> {
353
+ const v = tokens.variables;
354
+ const entries: [string, string | undefined][] = [
355
+ ["--color-background-primary", v["--color-background"]],
356
+ ["--color-background-secondary", v["--color-surface"]],
357
+ ["--color-background-tertiary", v["--color-surface-muted"]],
358
+ ["--color-background-inverse", v["--color-text"]],
359
+ ["--color-background-ghost", "transparent"],
360
+ ["--color-background-info", tint(v["--color-info"], 12)],
361
+ ["--color-background-danger", tint(v["--color-danger"], 12)],
362
+ ["--color-background-success", tint(v["--color-success"], 12)],
363
+ ["--color-background-warning", tint(v["--color-warning"], 12)],
364
+ ["--color-background-disabled", v["--color-surface-muted"]],
365
+ ["--color-text-primary", v["--color-text"]],
366
+ ["--color-text-secondary", v["--color-text-muted"]],
367
+ ["--color-text-tertiary", v["--color-text-subtle"]],
368
+ ["--color-text-inverse", v["--color-background"]],
369
+ ["--color-text-ghost", v["--color-text-subtle"]],
370
+ ["--color-text-info", v["--color-info"]],
371
+ ["--color-text-danger", v["--color-danger"]],
372
+ ["--color-text-success", v["--color-success"]],
373
+ ["--color-text-warning", v["--color-warning"]],
374
+ ["--color-text-disabled", v["--color-text-subtle"]],
375
+ ["--color-border-primary", v["--color-border"]],
376
+ ["--color-border-secondary", v["--color-border-strong"]],
377
+ ["--color-border-tertiary", v["--color-border"]],
378
+ ["--color-border-inverse", v["--color-text"]],
379
+ ["--color-border-ghost", "transparent"],
380
+ ["--color-border-info", v["--color-info"]],
381
+ ["--color-border-danger", v["--color-danger"]],
382
+ ["--color-border-success", v["--color-success"]],
383
+ ["--color-border-warning", v["--color-warning"]],
384
+ ["--color-border-disabled", v["--color-border"]],
385
+ ["--color-ring-primary", v["--color-accent"]],
386
+ ["--color-ring-secondary", v["--color-border-strong"]],
387
+ ["--color-ring-inverse", v["--color-background"]],
388
+ ["--color-ring-info", v["--color-info"]],
389
+ ["--color-ring-danger", v["--color-danger"]],
390
+ ["--color-ring-success", v["--color-success"]],
391
+ ["--color-ring-warning", v["--color-warning"]],
392
+ ["--font-sans", v["--font-sans"]],
393
+ ["--font-mono", v["--font-mono"]],
394
+ ["--font-weight-normal", "400"],
395
+ ["--font-weight-medium", "500"],
396
+ ["--font-weight-semibold", "600"],
397
+ ["--font-weight-bold", "700"],
398
+ ["--font-text-xs-size", "12px"],
399
+ ["--font-text-sm-size", "14px"],
400
+ ["--font-text-md-size", "16px"],
401
+ ["--font-text-lg-size", "18px"],
402
+ ["--font-heading-sm-size", "18px"],
403
+ ["--font-heading-md-size", "22px"],
404
+ ["--font-heading-lg-size", "28px"],
405
+ ["--border-radius-xs", v["--radius-sm"]],
406
+ ["--border-radius-sm", v["--radius-sm"]],
407
+ ["--border-radius-md", v["--radius-md"]],
408
+ ["--border-radius-lg", v["--radius-lg"]],
409
+ ["--border-radius-xl", v["--radius-lg"]],
410
+ ["--border-radius-full", "9999px"],
411
+ ["--border-width-regular", "1px"],
412
+ ];
413
+ const result: Record<string, string> = {};
414
+ for (const [name, value] of entries) {
415
+ if (value !== undefined) result[name] = value;
416
+ }
417
+ return result;
418
+ }
419
+
420
+ /** Every variable a frame receives: canonical tokens plus their MCP Apps aliases. */
421
+ export function themeVariables(tokens: ThemeTokens): Record<string, string> {
422
+ return { ...toMcpAppsVariables(tokens), ...tokens.variables };
423
+ }