@elizaos/autonomous 2.0.0-alpha.10

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 (241) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +270 -0
  3. package/src/actions/emote.ts +101 -0
  4. package/src/actions/restart.ts +101 -0
  5. package/src/actions/send-message.ts +168 -0
  6. package/src/actions/stream-control.ts +439 -0
  7. package/src/actions/switch-stream-source.ts +126 -0
  8. package/src/actions/terminal.ts +186 -0
  9. package/src/api/agent-admin-routes.ts +178 -0
  10. package/src/api/agent-lifecycle-routes.ts +129 -0
  11. package/src/api/agent-model.ts +143 -0
  12. package/src/api/agent-transfer-routes.ts +211 -0
  13. package/src/api/apps-routes.ts +210 -0
  14. package/src/api/auth-routes.ts +90 -0
  15. package/src/api/bsc-trade.ts +736 -0
  16. package/src/api/bug-report-routes.ts +161 -0
  17. package/src/api/character-routes.ts +421 -0
  18. package/src/api/cloud-billing-routes.ts +598 -0
  19. package/src/api/cloud-compat-routes.ts +192 -0
  20. package/src/api/cloud-routes.ts +529 -0
  21. package/src/api/cloud-status-routes.ts +234 -0
  22. package/src/api/compat-utils.ts +154 -0
  23. package/src/api/connector-health.ts +135 -0
  24. package/src/api/coordinator-wiring.ts +179 -0
  25. package/src/api/credit-detection.ts +47 -0
  26. package/src/api/database.ts +1357 -0
  27. package/src/api/diagnostics-routes.ts +389 -0
  28. package/src/api/drop-service.ts +205 -0
  29. package/src/api/early-logs.ts +111 -0
  30. package/src/api/http-helpers.ts +252 -0
  31. package/src/api/index.ts +85 -0
  32. package/src/api/knowledge-routes.ts +1189 -0
  33. package/src/api/knowledge-service-loader.ts +92 -0
  34. package/src/api/memory-bounds.ts +121 -0
  35. package/src/api/memory-routes.ts +349 -0
  36. package/src/api/merkle-tree.ts +239 -0
  37. package/src/api/models-routes.ts +72 -0
  38. package/src/api/nfa-routes.ts +169 -0
  39. package/src/api/nft-verify.ts +188 -0
  40. package/src/api/og-tracker.ts +72 -0
  41. package/src/api/parse-action-block.ts +145 -0
  42. package/src/api/permissions-routes.ts +222 -0
  43. package/src/api/plugin-validation.ts +355 -0
  44. package/src/api/provider-switch-config.ts +455 -0
  45. package/src/api/registry-routes.ts +165 -0
  46. package/src/api/registry-service.ts +292 -0
  47. package/src/api/route-helpers.ts +21 -0
  48. package/src/api/sandbox-routes.ts +1480 -0
  49. package/src/api/server.ts +17674 -0
  50. package/src/api/signal-routes.ts +265 -0
  51. package/src/api/stream-persistence.ts +297 -0
  52. package/src/api/stream-route-state.ts +48 -0
  53. package/src/api/stream-routes.ts +1046 -0
  54. package/src/api/stream-voice-routes.ts +208 -0
  55. package/src/api/streaming-text.ts +129 -0
  56. package/src/api/streaming-types.ts +23 -0
  57. package/src/api/subscription-routes.ts +283 -0
  58. package/src/api/terminal-run-limits.ts +31 -0
  59. package/src/api/training-backend-check.ts +40 -0
  60. package/src/api/training-routes.ts +314 -0
  61. package/src/api/training-service-like.ts +46 -0
  62. package/src/api/trajectory-routes.ts +714 -0
  63. package/src/api/trigger-routes.ts +438 -0
  64. package/src/api/twitter-verify.ts +226 -0
  65. package/src/api/tx-service.ts +193 -0
  66. package/src/api/wallet-dex-prices.ts +206 -0
  67. package/src/api/wallet-evm-balance.ts +989 -0
  68. package/src/api/wallet-routes.ts +505 -0
  69. package/src/api/wallet-rpc.ts +523 -0
  70. package/src/api/wallet-trading-profile.ts +694 -0
  71. package/src/api/wallet.ts +745 -0
  72. package/src/api/whatsapp-routes.ts +282 -0
  73. package/src/api/zip-utils.ts +130 -0
  74. package/src/auth/anthropic.ts +63 -0
  75. package/src/auth/apply-stealth.ts +38 -0
  76. package/src/auth/claude-code-stealth.ts +141 -0
  77. package/src/auth/credentials.ts +226 -0
  78. package/src/auth/index.ts +18 -0
  79. package/src/auth/openai-codex.ts +94 -0
  80. package/src/auth/types.ts +24 -0
  81. package/src/awareness/registry.ts +220 -0
  82. package/src/bin.ts +10 -0
  83. package/src/cli/index.ts +36 -0
  84. package/src/cli/parse-duration.ts +43 -0
  85. package/src/cloud/auth.test.ts +370 -0
  86. package/src/cloud/auth.ts +176 -0
  87. package/src/cloud/backup.test.ts +150 -0
  88. package/src/cloud/backup.ts +50 -0
  89. package/src/cloud/base-url.ts +45 -0
  90. package/src/cloud/bridge-client.test.ts +481 -0
  91. package/src/cloud/bridge-client.ts +307 -0
  92. package/src/cloud/cloud-manager.test.ts +223 -0
  93. package/src/cloud/cloud-manager.ts +151 -0
  94. package/src/cloud/cloud-proxy.test.ts +122 -0
  95. package/src/cloud/cloud-proxy.ts +52 -0
  96. package/src/cloud/index.ts +23 -0
  97. package/src/cloud/reconnect.test.ts +178 -0
  98. package/src/cloud/reconnect.ts +108 -0
  99. package/src/cloud/validate-url.test.ts +147 -0
  100. package/src/cloud/validate-url.ts +176 -0
  101. package/src/config/character-schema.ts +44 -0
  102. package/src/config/config.ts +149 -0
  103. package/src/config/env-vars.ts +86 -0
  104. package/src/config/includes.ts +196 -0
  105. package/src/config/index.ts +15 -0
  106. package/src/config/object-utils.ts +10 -0
  107. package/src/config/paths.ts +92 -0
  108. package/src/config/plugin-auto-enable.ts +520 -0
  109. package/src/config/schema.ts +1342 -0
  110. package/src/config/telegram-custom-commands.ts +99 -0
  111. package/src/config/types.agent-defaults.ts +342 -0
  112. package/src/config/types.agents.ts +112 -0
  113. package/src/config/types.gateway.ts +243 -0
  114. package/src/config/types.hooks.ts +124 -0
  115. package/src/config/types.messages.ts +201 -0
  116. package/src/config/types.milady.ts +791 -0
  117. package/src/config/types.tools.ts +416 -0
  118. package/src/config/types.ts +7 -0
  119. package/src/config/zod-schema.agent-runtime.ts +777 -0
  120. package/src/config/zod-schema.core.ts +778 -0
  121. package/src/config/zod-schema.hooks.ts +139 -0
  122. package/src/config/zod-schema.providers-core.ts +1126 -0
  123. package/src/config/zod-schema.session.ts +98 -0
  124. package/src/config/zod-schema.ts +865 -0
  125. package/src/contracts/apps.ts +46 -0
  126. package/src/contracts/awareness.ts +56 -0
  127. package/src/contracts/config.ts +172 -0
  128. package/src/contracts/drop.ts +21 -0
  129. package/src/contracts/index.ts +8 -0
  130. package/src/contracts/onboarding.ts +592 -0
  131. package/src/contracts/permissions.ts +52 -0
  132. package/src/contracts/verification.ts +9 -0
  133. package/src/contracts/wallet.ts +503 -0
  134. package/src/diagnostics/integration-observability.ts +132 -0
  135. package/src/emotes/catalog.ts +655 -0
  136. package/src/external-modules.d.ts +7 -0
  137. package/src/hooks/discovery.test.ts +357 -0
  138. package/src/hooks/discovery.ts +231 -0
  139. package/src/hooks/eligibility.ts +146 -0
  140. package/src/hooks/hooks.test.ts +320 -0
  141. package/src/hooks/index.ts +8 -0
  142. package/src/hooks/loader.test.ts +418 -0
  143. package/src/hooks/loader.ts +256 -0
  144. package/src/hooks/registry.test.ts +168 -0
  145. package/src/hooks/registry.ts +74 -0
  146. package/src/hooks/types.ts +121 -0
  147. package/src/index.ts +19 -0
  148. package/src/onboarding-presets.ts +828 -0
  149. package/src/plugins/custom-rtmp/index.ts +40 -0
  150. package/src/providers/admin-trust.ts +76 -0
  151. package/src/providers/session-bridge.ts +143 -0
  152. package/src/providers/session-utils.ts +42 -0
  153. package/src/providers/simple-mode.ts +113 -0
  154. package/src/providers/ui-catalog.ts +135 -0
  155. package/src/providers/workspace-provider.ts +213 -0
  156. package/src/providers/workspace.ts +497 -0
  157. package/src/runtime/agent-event-service.ts +57 -0
  158. package/src/runtime/cloud-onboarding.test.ts +489 -0
  159. package/src/runtime/cloud-onboarding.ts +408 -0
  160. package/src/runtime/core-plugins.ts +53 -0
  161. package/src/runtime/custom-actions.ts +605 -0
  162. package/src/runtime/eliza.ts +4941 -0
  163. package/src/runtime/embedding-presets.ts +73 -0
  164. package/src/runtime/index.ts +8 -0
  165. package/src/runtime/milady-plugin.ts +180 -0
  166. package/src/runtime/onboarding-names.ts +76 -0
  167. package/src/runtime/release-plugin-policy.ts +119 -0
  168. package/src/runtime/restart.ts +59 -0
  169. package/src/runtime/trajectory-persistence.ts +2584 -0
  170. package/src/runtime/version.ts +6 -0
  171. package/src/security/audit-log.ts +222 -0
  172. package/src/security/network-policy.ts +91 -0
  173. package/src/server/index.ts +6 -0
  174. package/src/services/agent-export.ts +976 -0
  175. package/src/services/app-manager.ts +755 -0
  176. package/src/services/browser-capture.ts +215 -0
  177. package/src/services/coding-agent-context.ts +355 -0
  178. package/src/services/fallback-training-service.ts +196 -0
  179. package/src/services/index.ts +17 -0
  180. package/src/services/mcp-marketplace.ts +327 -0
  181. package/src/services/plugin-manager-types.ts +185 -0
  182. package/src/services/privy-wallets.ts +352 -0
  183. package/src/services/registry-client-app-meta.ts +201 -0
  184. package/src/services/registry-client-endpoints.ts +253 -0
  185. package/src/services/registry-client-local.ts +485 -0
  186. package/src/services/registry-client-network.ts +173 -0
  187. package/src/services/registry-client-queries.ts +176 -0
  188. package/src/services/registry-client-types.ts +104 -0
  189. package/src/services/registry-client.ts +366 -0
  190. package/src/services/remote-signing-service.ts +261 -0
  191. package/src/services/sandbox-engine.ts +753 -0
  192. package/src/services/sandbox-manager.ts +503 -0
  193. package/src/services/self-updater.ts +213 -0
  194. package/src/services/signal-pairing.ts +189 -0
  195. package/src/services/signing-policy.ts +230 -0
  196. package/src/services/skill-catalog-client.ts +195 -0
  197. package/src/services/skill-marketplace.ts +909 -0
  198. package/src/services/stream-manager.ts +707 -0
  199. package/src/services/tts-stream-bridge.ts +465 -0
  200. package/src/services/update-checker.ts +163 -0
  201. package/src/services/version-compat.ts +367 -0
  202. package/src/services/whatsapp-pairing.ts +279 -0
  203. package/src/shared/ui-catalog-prompt.ts +1158 -0
  204. package/src/test-support/process-helpers.ts +35 -0
  205. package/src/test-support/route-test-helpers.ts +113 -0
  206. package/src/test-support/test-helpers.ts +304 -0
  207. package/src/testing/index.ts +3 -0
  208. package/src/triggers/action.ts +342 -0
  209. package/src/triggers/runtime.ts +432 -0
  210. package/src/triggers/scheduling.ts +472 -0
  211. package/src/triggers/types.ts +133 -0
  212. package/src/types/app-hyperscape-routes-shim.d.ts +29 -0
  213. package/src/types/external-modules.d.ts +7 -0
  214. package/src/utils/exec-safety.ts +23 -0
  215. package/src/utils/number-parsing.ts +112 -0
  216. package/src/utils/spoken-text.ts +65 -0
  217. package/src/version-resolver.ts +60 -0
  218. package/test/api/agent-admin-routes.test.ts +160 -0
  219. package/test/api/agent-lifecycle-routes.test.ts +164 -0
  220. package/test/api/agent-transfer-routes.test.ts +136 -0
  221. package/test/api/apps-routes.test.ts +140 -0
  222. package/test/api/auth-routes.test.ts +160 -0
  223. package/test/api/bug-report-routes.test.ts +88 -0
  224. package/test/api/knowledge-routes.test.ts +73 -0
  225. package/test/api/lifecycle.test.ts +342 -0
  226. package/test/api/memory-routes.test.ts +74 -0
  227. package/test/api/models-routes.test.ts +112 -0
  228. package/test/api/nfa-routes.test.ts +78 -0
  229. package/test/api/permissions-routes.test.ts +185 -0
  230. package/test/api/registry-routes.test.ts +157 -0
  231. package/test/api/signal-routes.test.ts +113 -0
  232. package/test/api/subscription-routes.test.ts +90 -0
  233. package/test/api/trigger-routes.test.ts +87 -0
  234. package/test/api/wallet-routes.observability.test.ts +191 -0
  235. package/test/api/wallet-routes.test.ts +502 -0
  236. package/test/diagnostics/integration-observability.test.ts +135 -0
  237. package/test/security/audit-log.test.ts +229 -0
  238. package/test/security/network-policy.test.ts +143 -0
  239. package/test/services/version-compat.test.ts +127 -0
  240. package/tsconfig.build.json +21 -0
  241. package/tsconfig.json +19 -0
@@ -0,0 +1,1158 @@
1
+ /**
2
+ * ui-catalog-prompt.ts -- Generates a system prompt for LLMs describing
3
+ * all available UiSpec components so they can produce valid JSON specs.
4
+ *
5
+ * Exports:
6
+ * - COMPONENT_CATALOG — metadata for every supported component
7
+ * - generateCatalogPrompt(options?) — builds the system prompt string
8
+ * - getComponentNames() — returns the list of component type names
9
+ */
10
+
11
+ // ── Component metadata types ────────────────────────────────────────
12
+
13
+ interface PropMeta {
14
+ type: string;
15
+ description: string;
16
+ required?: boolean;
17
+ }
18
+
19
+ export interface ComponentMeta {
20
+ description: string;
21
+ props: Record<string, PropMeta>;
22
+ slots?: string[];
23
+ }
24
+
25
+ // ══════════════════════════════════════════════════════════════════════
26
+ // COMPONENT CATALOG
27
+ // ══════════════════════════════════════════════════════════════════════
28
+
29
+ export const COMPONENT_CATALOG: Record<string, ComponentMeta> = {
30
+ // ── Layout ──────────────────────────────────────────────────────────
31
+
32
+ Stack: {
33
+ description: "Flexbox container for vertical or horizontal layouts",
34
+ props: {
35
+ direction: {
36
+ type: '"vertical" | "horizontal"',
37
+ description: "Layout direction. Defaults to vertical.",
38
+ required: false,
39
+ },
40
+ gap: {
41
+ type: '"none" | "xs" | "sm" | "md" | "lg" | "xl"',
42
+ description: "Gap between children. Defaults to md.",
43
+ required: false,
44
+ },
45
+ align: {
46
+ type: '"start" | "center" | "end" | "stretch"',
47
+ description: "Cross-axis alignment. Defaults to stretch.",
48
+ required: false,
49
+ },
50
+ justify: {
51
+ type: '"start" | "center" | "end" | "between" | "around"',
52
+ description: "Main-axis alignment. Defaults to start.",
53
+ required: false,
54
+ },
55
+ },
56
+ slots: ["default"],
57
+ },
58
+
59
+ Grid: {
60
+ description: "CSS grid container with configurable columns",
61
+ props: {
62
+ columns: {
63
+ type: "number",
64
+ description: "Number of grid columns. Defaults to 2.",
65
+ required: false,
66
+ },
67
+ gap: {
68
+ type: '"none" | "xs" | "sm" | "md" | "lg" | "xl"',
69
+ description: "Gap between grid cells. Defaults to md.",
70
+ required: false,
71
+ },
72
+ },
73
+ slots: ["default"],
74
+ },
75
+
76
+ Card: {
77
+ description: "Bordered container with optional title and description",
78
+ props: {
79
+ title: {
80
+ type: "string",
81
+ description: "Card heading text",
82
+ required: false,
83
+ },
84
+ description: {
85
+ type: "string",
86
+ description: "Card subtitle / description text",
87
+ required: false,
88
+ },
89
+ maxWidth: {
90
+ type: '"full" | undefined',
91
+ description: 'Set to "full" for full-width card',
92
+ required: false,
93
+ },
94
+ },
95
+ slots: ["default"],
96
+ },
97
+
98
+ Separator: {
99
+ description: "Horizontal or vertical divider line",
100
+ props: {
101
+ orientation: {
102
+ type: '"horizontal" | "vertical"',
103
+ description: "Divider direction. Defaults to horizontal.",
104
+ required: false,
105
+ },
106
+ },
107
+ },
108
+
109
+ // ── Typography ──────────────────────────────────────────────────────
110
+
111
+ Heading: {
112
+ description: "Heading text with configurable level",
113
+ props: {
114
+ text: {
115
+ type: "string",
116
+ description: "Heading content",
117
+ required: true,
118
+ },
119
+ level: {
120
+ type: '"h1" | "h2" | "h3"',
121
+ description: "Heading level. Defaults to h2.",
122
+ required: false,
123
+ },
124
+ },
125
+ },
126
+
127
+ Text: {
128
+ description: "Body text with variant styling",
129
+ props: {
130
+ text: {
131
+ type: "string",
132
+ description: "Text content",
133
+ required: true,
134
+ },
135
+ variant: {
136
+ type: '"body" | "caption" | "muted" | "lead" | "code"',
137
+ description: "Text style variant. Defaults to body.",
138
+ required: false,
139
+ },
140
+ },
141
+ },
142
+
143
+ // ── Form ────────────────────────────────────────────────────────────
144
+
145
+ Input: {
146
+ description: "Single-line text input with label and state binding",
147
+ props: {
148
+ label: {
149
+ type: "string",
150
+ description: "Input label displayed above the field",
151
+ required: false,
152
+ },
153
+ type: {
154
+ type: '"text" | "email" | "password" | "number" | "url" | "tel"',
155
+ description: "HTML input type. Defaults to text.",
156
+ required: false,
157
+ },
158
+ name: {
159
+ type: "string",
160
+ description: "Form field name attribute",
161
+ required: false,
162
+ },
163
+ placeholder: {
164
+ type: "string",
165
+ description: "Placeholder text",
166
+ required: false,
167
+ },
168
+ statePath: {
169
+ type: "string",
170
+ description: "Dot-path into spec state for two-way binding",
171
+ required: false,
172
+ },
173
+ },
174
+ },
175
+
176
+ Textarea: {
177
+ description: "Multi-line text input with configurable rows",
178
+ props: {
179
+ label: {
180
+ type: "string",
181
+ description: "Textarea label",
182
+ required: false,
183
+ },
184
+ name: {
185
+ type: "string",
186
+ description: "Form field name attribute",
187
+ required: false,
188
+ },
189
+ placeholder: {
190
+ type: "string",
191
+ description: "Placeholder text",
192
+ required: false,
193
+ },
194
+ rows: {
195
+ type: "number",
196
+ description: "Number of visible rows. Defaults to 3.",
197
+ required: false,
198
+ },
199
+ statePath: {
200
+ type: "string",
201
+ description: "Dot-path into spec state for two-way binding",
202
+ required: false,
203
+ },
204
+ },
205
+ },
206
+
207
+ Select: {
208
+ description: "Dropdown select with options list",
209
+ props: {
210
+ label: {
211
+ type: "string",
212
+ description: "Select label",
213
+ required: false,
214
+ },
215
+ options: {
216
+ type: "Array<{ label: string; value: string }>",
217
+ description: "Array of selectable options",
218
+ required: true,
219
+ },
220
+ placeholder: {
221
+ type: "string",
222
+ description: "Placeholder option text",
223
+ required: false,
224
+ },
225
+ statePath: {
226
+ type: "string",
227
+ description: "Dot-path into spec state for two-way binding",
228
+ required: false,
229
+ },
230
+ },
231
+ },
232
+
233
+ Checkbox: {
234
+ description: "Single checkbox with label",
235
+ props: {
236
+ label: {
237
+ type: "string",
238
+ description: "Checkbox label text",
239
+ required: true,
240
+ },
241
+ statePath: {
242
+ type: "string",
243
+ description: "Dot-path into spec state for two-way binding (boolean)",
244
+ required: false,
245
+ },
246
+ },
247
+ },
248
+
249
+ Radio: {
250
+ description: "Radio button group",
251
+ props: {
252
+ label: {
253
+ type: "string",
254
+ description: "Group label text",
255
+ required: false,
256
+ },
257
+ name: {
258
+ type: "string",
259
+ description: "Radio group name for mutual exclusion",
260
+ required: true,
261
+ },
262
+ options: {
263
+ type: "Array<{ label: string; value: string }>",
264
+ description: "Array of radio options",
265
+ required: true,
266
+ },
267
+ statePath: {
268
+ type: "string",
269
+ description: "Dot-path into spec state for two-way binding",
270
+ required: false,
271
+ },
272
+ },
273
+ },
274
+
275
+ Switch: {
276
+ description: "Toggle switch for boolean values",
277
+ props: {
278
+ label: {
279
+ type: "string",
280
+ description: "Switch label text",
281
+ required: false,
282
+ },
283
+ statePath: {
284
+ type: "string",
285
+ description: "Dot-path into spec state for two-way binding (boolean)",
286
+ required: false,
287
+ },
288
+ },
289
+ },
290
+
291
+ Slider: {
292
+ description: "Range slider input",
293
+ props: {
294
+ label: {
295
+ type: "string",
296
+ description: "Slider label text",
297
+ required: false,
298
+ },
299
+ min: {
300
+ type: "number",
301
+ description: "Minimum value. Defaults to 0.",
302
+ required: false,
303
+ },
304
+ max: {
305
+ type: "number",
306
+ description: "Maximum value. Defaults to 100.",
307
+ required: false,
308
+ },
309
+ step: {
310
+ type: "number",
311
+ description: "Step increment. Defaults to 1.",
312
+ required: false,
313
+ },
314
+ statePath: {
315
+ type: "string",
316
+ description: "Dot-path into spec state for two-way binding (number)",
317
+ required: false,
318
+ },
319
+ },
320
+ },
321
+
322
+ Toggle: {
323
+ description: "Pressable toggle button with on/off state",
324
+ props: {
325
+ label: {
326
+ type: "string",
327
+ description: "Toggle button label. Defaults to 'Toggle'.",
328
+ required: false,
329
+ },
330
+ statePath: {
331
+ type: "string",
332
+ description: "Dot-path into spec state for two-way binding (boolean)",
333
+ required: false,
334
+ },
335
+ },
336
+ },
337
+
338
+ ToggleGroup: {
339
+ description: "Group of toggle buttons for single or multiple selection",
340
+ props: {
341
+ items: {
342
+ type: "Array<{ label: string; value: string }>",
343
+ description: "Selectable toggle items",
344
+ required: true,
345
+ },
346
+ type: {
347
+ type: '"single" | "multiple"',
348
+ description:
349
+ "Selection mode. Single selects one value, multiple allows many.",
350
+ required: false,
351
+ },
352
+ statePath: {
353
+ type: "string",
354
+ description:
355
+ "Dot-path into spec state. String for single, string[] for multiple.",
356
+ required: false,
357
+ },
358
+ },
359
+ },
360
+
361
+ ButtonGroup: {
362
+ description: "Row of mutually exclusive buttons (single selection)",
363
+ props: {
364
+ buttons: {
365
+ type: "Array<{ label: string; value: string }>",
366
+ description: "Button options",
367
+ required: true,
368
+ },
369
+ statePath: {
370
+ type: "string",
371
+ description: "Dot-path into spec state for the selected value",
372
+ required: false,
373
+ },
374
+ },
375
+ },
376
+
377
+ // ── Data Display ────────────────────────────────────────────────────
378
+
379
+ Table: {
380
+ description: "Data table with column headers and rows",
381
+ props: {
382
+ columns: {
383
+ type: "string[]",
384
+ description: "Array of column header names",
385
+ required: true,
386
+ },
387
+ rows: {
388
+ type: "string[][]",
389
+ description: "2D array of row cell values",
390
+ required: true,
391
+ },
392
+ caption: {
393
+ type: "string",
394
+ description: "Table caption displayed above",
395
+ required: false,
396
+ },
397
+ },
398
+ },
399
+
400
+ Carousel: {
401
+ description: "Paginated carousel that shows one item at a time",
402
+ props: {
403
+ items: {
404
+ type: "Array<{ title: string; description: string }>",
405
+ description: "Carousel slide items",
406
+ required: true,
407
+ },
408
+ },
409
+ },
410
+
411
+ Badge: {
412
+ description: "Small inline label / tag",
413
+ props: {
414
+ text: {
415
+ type: "string",
416
+ description: "Badge text content",
417
+ required: true,
418
+ },
419
+ variant: {
420
+ type: '"default" | "success" | "warning" | "error" | "info"',
421
+ description: "Color variant. Defaults to default.",
422
+ required: false,
423
+ },
424
+ },
425
+ },
426
+
427
+ Avatar: {
428
+ description: "Circular avatar showing initials derived from a name",
429
+ props: {
430
+ name: {
431
+ type: "string",
432
+ description: "Full name used to generate initials",
433
+ required: true,
434
+ },
435
+ size: {
436
+ type: '"sm" | "md" | "lg"',
437
+ description: "Avatar size. Defaults to md.",
438
+ required: false,
439
+ },
440
+ },
441
+ },
442
+
443
+ Image: {
444
+ description: "Image element with fallback placeholder",
445
+ props: {
446
+ src: {
447
+ type: "string",
448
+ description: "Image URL",
449
+ required: false,
450
+ },
451
+ alt: {
452
+ type: "string",
453
+ description: "Alt text for accessibility",
454
+ required: false,
455
+ },
456
+ width: {
457
+ type: "number",
458
+ description: "Width in pixels",
459
+ required: false,
460
+ },
461
+ height: {
462
+ type: "number",
463
+ description: "Height in pixels",
464
+ required: false,
465
+ },
466
+ },
467
+ },
468
+
469
+ // ── Feedback ────────────────────────────────────────────────────────
470
+
471
+ Alert: {
472
+ description: "Alert banner with type-based styling",
473
+ props: {
474
+ type: {
475
+ type: '"info" | "success" | "warning" | "error"',
476
+ description: "Alert severity. Defaults to info.",
477
+ required: false,
478
+ },
479
+ title: {
480
+ type: "string",
481
+ description: "Alert title",
482
+ required: false,
483
+ },
484
+ message: {
485
+ type: "string",
486
+ description: "Alert body text",
487
+ required: false,
488
+ },
489
+ },
490
+ },
491
+
492
+ Progress: {
493
+ description: "Horizontal progress bar",
494
+ props: {
495
+ value: {
496
+ type: "number",
497
+ description: "Current progress value",
498
+ required: true,
499
+ },
500
+ max: {
501
+ type: "number",
502
+ description: "Maximum value. Defaults to 100.",
503
+ required: false,
504
+ },
505
+ label: {
506
+ type: "string",
507
+ description: "Label displayed above the bar",
508
+ required: false,
509
+ },
510
+ },
511
+ },
512
+
513
+ Rating: {
514
+ description: "Star rating display",
515
+ props: {
516
+ value: {
517
+ type: "number",
518
+ description: "Number of filled stars",
519
+ required: true,
520
+ },
521
+ max: {
522
+ type: "number",
523
+ description: "Total number of stars. Defaults to 5.",
524
+ required: false,
525
+ },
526
+ label: {
527
+ type: "string",
528
+ description: "Label displayed above the stars",
529
+ required: false,
530
+ },
531
+ },
532
+ },
533
+
534
+ Skeleton: {
535
+ description: "Loading placeholder with pulse animation",
536
+ props: {
537
+ width: {
538
+ type: "string",
539
+ description: "CSS width value. Defaults to 100%.",
540
+ required: false,
541
+ },
542
+ height: {
543
+ type: "string",
544
+ description: "CSS height value. Defaults to 20px.",
545
+ required: false,
546
+ },
547
+ rounded: {
548
+ type: "boolean",
549
+ description: "Apply rounded corners",
550
+ required: false,
551
+ },
552
+ },
553
+ },
554
+
555
+ Spinner: {
556
+ description: "Spinning loading indicator",
557
+ props: {
558
+ size: {
559
+ type: '"sm" | "md" | "lg"',
560
+ description: "Spinner size. Defaults to md.",
561
+ required: false,
562
+ },
563
+ label: {
564
+ type: "string",
565
+ description: "Loading text displayed beside the spinner",
566
+ required: false,
567
+ },
568
+ },
569
+ },
570
+
571
+ // ── Navigation ──────────────────────────────────────────────────────
572
+
573
+ Button: {
574
+ description: "Clickable button with variant styling",
575
+ props: {
576
+ label: {
577
+ type: "string",
578
+ description: "Button text. Defaults to 'Button'.",
579
+ required: false,
580
+ },
581
+ variant: {
582
+ type: '"primary" | "secondary" | "danger" | "ghost"',
583
+ description: "Button style variant. Defaults to primary.",
584
+ required: false,
585
+ },
586
+ disabled: {
587
+ type: "boolean",
588
+ description: "Disable the button",
589
+ required: false,
590
+ },
591
+ },
592
+ },
593
+
594
+ Link: {
595
+ description: "Anchor link, optionally opening in a new tab",
596
+ props: {
597
+ label: {
598
+ type: "string",
599
+ description: "Link text",
600
+ required: false,
601
+ },
602
+ href: {
603
+ type: "string",
604
+ description: "URL target",
605
+ required: true,
606
+ },
607
+ external: {
608
+ type: "boolean",
609
+ description: "Open in new tab with noopener",
610
+ required: false,
611
+ },
612
+ },
613
+ },
614
+
615
+ DropdownMenu: {
616
+ description: "Button that reveals a dropdown list of actions",
617
+ props: {
618
+ label: {
619
+ type: "string",
620
+ description: "Trigger button text. Defaults to 'Menu'.",
621
+ required: false,
622
+ },
623
+ items: {
624
+ type: "Array<{ label: string; value: string }>",
625
+ description: "Menu items. Selection fires a 'menuSelect' action.",
626
+ required: true,
627
+ },
628
+ },
629
+ },
630
+
631
+ Tabs: {
632
+ description: "Tabbed navigation with inline text content per tab",
633
+ props: {
634
+ tabs: {
635
+ type: "Array<{ label: string; value: string; content: string }>",
636
+ description: "Tab definitions with labels and text content",
637
+ required: true,
638
+ },
639
+ defaultValue: {
640
+ type: "string",
641
+ description: "Initially active tab value",
642
+ required: false,
643
+ },
644
+ statePath: {
645
+ type: "string",
646
+ description: "Dot-path into spec state for the active tab value",
647
+ required: false,
648
+ },
649
+ },
650
+ },
651
+
652
+ Pagination: {
653
+ description: "Page navigation with numbered buttons",
654
+ props: {
655
+ totalPages: {
656
+ type: "number",
657
+ description: "Total number of pages",
658
+ required: true,
659
+ },
660
+ statePath: {
661
+ type: "string",
662
+ description: "Dot-path into spec state for the current page (number)",
663
+ required: false,
664
+ },
665
+ },
666
+ },
667
+
668
+ // ── Metric / KPI display ────────────────────────────────────────────
669
+
670
+ Metric: {
671
+ description:
672
+ "KPI / metric card showing a label, primary value, and optional change indicator. Ideal for wallet balances, prices, and stats.",
673
+ props: {
674
+ label: {
675
+ type: "string",
676
+ description: "Metric label (e.g. 'BNB Balance')",
677
+ required: true,
678
+ },
679
+ value: {
680
+ type: "string | number",
681
+ description:
682
+ 'Primary display value. Supports dynamic { "$path": "state.path" } reference.',
683
+ required: true,
684
+ },
685
+ unit: {
686
+ type: "string",
687
+ description: "Unit suffix after value (e.g. 'BNB', 'USD')",
688
+ required: false,
689
+ },
690
+ change: {
691
+ type: "string | number",
692
+ description: "Change delta shown below value (e.g. '+2.4%')",
693
+ required: false,
694
+ },
695
+ trend: {
696
+ type: '"up" | "down" | "neutral"',
697
+ description:
698
+ "Trend direction — colours change indicator green/red/grey",
699
+ required: false,
700
+ },
701
+ },
702
+ },
703
+
704
+ // ── Visualization ───────────────────────────────────────────────────
705
+
706
+ BarGraph: {
707
+ description: "Vertical bar chart",
708
+ props: {
709
+ data: {
710
+ type: "Array<{ label: string; value: number }>",
711
+ description: "Data points for the bars",
712
+ required: true,
713
+ },
714
+ title: {
715
+ type: "string",
716
+ description: "Chart title",
717
+ required: false,
718
+ },
719
+ },
720
+ },
721
+
722
+ LineGraph: {
723
+ description: "SVG line chart",
724
+ props: {
725
+ data: {
726
+ type: "Array<{ label: string; value: number }>",
727
+ description: "Data points for the line",
728
+ required: true,
729
+ },
730
+ title: {
731
+ type: "string",
732
+ description: "Chart title",
733
+ required: false,
734
+ },
735
+ },
736
+ },
737
+
738
+ // ── Interaction ─────────────────────────────────────────────────────
739
+
740
+ Tooltip: {
741
+ description: "Hover tooltip showing extra information",
742
+ props: {
743
+ text: {
744
+ type: "string",
745
+ description: "Trigger text that the user hovers. Defaults to 'Hover'.",
746
+ required: false,
747
+ },
748
+ content: {
749
+ type: "string",
750
+ description: "Tooltip popup content",
751
+ required: true,
752
+ },
753
+ },
754
+ },
755
+
756
+ Popover: {
757
+ description: "Click-triggered popup with content",
758
+ props: {
759
+ trigger: {
760
+ type: "string",
761
+ description: "Trigger text. Defaults to 'Click'.",
762
+ required: false,
763
+ },
764
+ content: {
765
+ type: "string",
766
+ description: "Popover body content",
767
+ required: true,
768
+ },
769
+ },
770
+ },
771
+
772
+ Collapsible: {
773
+ description: "Expandable/collapsible content section",
774
+ props: {
775
+ title: {
776
+ type: "string",
777
+ description: "Header text. Defaults to 'Collapsible'.",
778
+ required: false,
779
+ },
780
+ defaultOpen: {
781
+ type: "boolean",
782
+ description: "Start in open state",
783
+ required: false,
784
+ },
785
+ },
786
+ slots: ["default"],
787
+ },
788
+
789
+ Accordion: {
790
+ description: "Multi-section accordion with expand/collapse",
791
+ props: {
792
+ items: {
793
+ type: "Array<{ title: string; content: string }>",
794
+ description: "Accordion sections",
795
+ required: true,
796
+ },
797
+ type: {
798
+ type: '"single" | "multiple"',
799
+ description: "Whether only one section can be open at a time",
800
+ required: false,
801
+ },
802
+ },
803
+ },
804
+
805
+ Dialog: {
806
+ description: "Modal dialog controlled by a state path",
807
+ props: {
808
+ title: {
809
+ type: "string",
810
+ description: "Dialog title",
811
+ required: false,
812
+ },
813
+ description: {
814
+ type: "string",
815
+ description: "Dialog description text",
816
+ required: false,
817
+ },
818
+ openPath: {
819
+ type: "string",
820
+ description:
821
+ "Dot-path into spec state (boolean) that controls open/close",
822
+ required: true,
823
+ },
824
+ },
825
+ slots: ["default"],
826
+ },
827
+
828
+ Drawer: {
829
+ description: "Bottom drawer overlay controlled by a state path",
830
+ props: {
831
+ title: {
832
+ type: "string",
833
+ description: "Drawer title",
834
+ required: false,
835
+ },
836
+ description: {
837
+ type: "string",
838
+ description: "Drawer description text",
839
+ required: false,
840
+ },
841
+ openPath: {
842
+ type: "string",
843
+ description:
844
+ "Dot-path into spec state (boolean) that controls open/close",
845
+ required: true,
846
+ },
847
+ },
848
+ slots: ["default"],
849
+ },
850
+ };
851
+
852
+ // ══════════════════════════════════════════════════════════════════════
853
+ // UTILITIES
854
+ // ══════════════════════════════════════════════════════════════════════
855
+
856
+ /** Returns the list of all component type names in the catalog. */
857
+ export function getComponentNames(): string[] {
858
+ return Object.keys(COMPONENT_CATALOG);
859
+ }
860
+
861
+ // ══════════════════════════════════════════════════════════════════════
862
+ // PROMPT GENERATION
863
+ // ══════════════════════════════════════════════════════════════════════
864
+
865
+ export interface CatalogPromptOptions {
866
+ /** Extra rules appended to the end of the prompt. */
867
+ customRules?: string[];
868
+ /** Include a small example UiSpec at the end. */
869
+ includeExamples?: boolean;
870
+ /** Only include these component types (subset of catalog). */
871
+ componentFilter?: string[];
872
+ /**
873
+ * Output mode:
874
+ * "generate" (default) — AI outputs ONLY JSONL patches, no prose. Use for
875
+ * standalone UI builders and playgrounds.
876
+ * "chat" — AI responds conversationally first, then emits
877
+ * JSONL patches on their own lines when UI is needed.
878
+ * Text-only replies are allowed (greetings, questions).
879
+ * Use for conversational interfaces.
880
+ */
881
+ mode?: "generate" | "chat";
882
+ }
883
+
884
+ /**
885
+ * Builds a system prompt string describing the UiSpec JSON format and
886
+ * all available components so an LLM can generate valid specs.
887
+ *
888
+ * Two modes:
889
+ * "generate" (default) — AI outputs only JSONL patches, no prose.
890
+ * "chat" — AI can respond conversationally and embed JSONL
891
+ * patches inline when rich UI is appropriate.
892
+ */
893
+ export function generateCatalogPrompt(options?: CatalogPromptOptions): string {
894
+ const parts: string[] = [];
895
+ const mode = options?.mode ?? "generate";
896
+
897
+ // ── 1. Header ───────────────────────────────────────────────────────
898
+
899
+ if (mode === "chat") {
900
+ parts.push(
901
+ `You can generate interactive UI components inline in your responses using JSONL patches.
902
+
903
+ When the user's request calls for a form, chart, slider, metric display, wallet control, or any interactive element, respond conversationally first (one or two sentences), then emit the JSONL patches on their own lines immediately after. Each patch must be on its own line with no extra whitespace or code fences.
904
+
905
+ When no UI is needed (greetings, factual questions, clarifications) — reply with text only. Never emit patches unless they genuinely add value.`,
906
+ );
907
+ } else {
908
+ parts.push(
909
+ "You are generating UI specifications as JSONL patches. Output ONLY the patches — one JSON object per line, no prose, no markdown, no code fences.",
910
+ );
911
+ }
912
+
913
+ // ── 2. Patch format ─────────────────────────────────────────────────
914
+
915
+ parts.push(`
916
+ ## Output format — JSONL patches (RFC 6902)
917
+
918
+ Each line of UI output is a single JSON patch operation:
919
+
920
+ \`\`\`
921
+ {"op":"add","path":"/root","value":"card-1"}
922
+ {"op":"add","path":"/elements/card-1","value":{"type":"Card","props":{"title":"My Form"},"children":["input-1","btn-1"]}}
923
+ {"op":"add","path":"/elements/input-1","value":{"type":"Input","props":{"label":"Amount","type":"number","statePath":"amount"},"children":[]}}
924
+ {"op":"add","path":"/elements/btn-1","value":{"type":"Button","props":{"label":"Submit"},"children":[]}}
925
+ {"op":"add","path":"/state/amount","value":0}
926
+ \`\`\`
927
+
928
+ **Path conventions:**
929
+ - \`/root\` — set the root element ID (required, must be first)
930
+ - \`/elements/<id>\` — add/replace an element
931
+ - \`/state/<key>\` — set initial state value
932
+ - \`/state\` — set the entire state object at once
933
+
934
+ **Element schema:**
935
+ \`\`\`
936
+ {
937
+ "type": "<ComponentType>",
938
+ "props": { ... },
939
+ "children": ["child-id-1", "child-id-2"],
940
+ "on": { ... }, // optional event bindings
941
+ "visible": { ... }, // optional visibility condition
942
+ "validation": { ... }, // optional validation
943
+ "repeat": { ... } // optional list rendering
944
+ }
945
+ \`\`\`
946
+
947
+ Always emit \`/root\` first, then all \`/elements\` entries, then \`/state\` values.
948
+ Element IDs must be unique kebab-case strings (e.g. \`send-btn\`, \`amount-slider\`).`);
949
+
950
+ // ── 3. Available components ─────────────────────────────────────────
951
+
952
+ const filter = options?.componentFilter;
953
+ const entries = Object.entries(COMPONENT_CATALOG).filter(
954
+ ([name]) => !filter || filter.includes(name),
955
+ );
956
+
957
+ const componentLines: string[] = [];
958
+ for (const [name, meta] of entries) {
959
+ const propDescs: string[] = [];
960
+ for (const [prop, info] of Object.entries(meta.props)) {
961
+ const req = info.required ? " (required)" : "";
962
+ propDescs.push(
963
+ ` - ${prop}: ${info.type}${req} -- ${info.description}`,
964
+ );
965
+ }
966
+ const slotsLine = meta.slots
967
+ ? ` Slots: ${meta.slots.join(", ")} (accepts children)`
968
+ : " No children.";
969
+ componentLines.push(
970
+ `- **${name}**: ${meta.description}\n Props:\n${propDescs.join("\n")}\n${slotsLine}`,
971
+ );
972
+ }
973
+
974
+ parts.push(`
975
+ ## Available components (${entries.length})
976
+
977
+ ${componentLines.join("\n\n")}`);
978
+
979
+ // ── 4. Data binding ─────────────────────────────────────────────────
980
+
981
+ parts.push(`
982
+ ## Data binding
983
+
984
+ Reference state values dynamically in props using either syntax:
985
+
986
+ 1. **String prefix**: \`"$data.path.to.value"\` -- the value at that state path is resolved at render time.
987
+ 2. **Object syntax**: \`{ "$path": "path.to.value" }\` -- equivalent, useful when the value is not a string.
988
+
989
+ Inside a \`repeat\` block, reference the current item's fields with \`"$data.$item/fieldName"\` or \`{ "$path": "$item/fieldName" }\`.`);
990
+
991
+ // ── 5. State binding ────────────────────────────────────────────────
992
+
993
+ parts.push(`
994
+ ## State binding
995
+
996
+ Form elements accept a \`statePath\` prop (dot-delimited path into \`state\`). This creates two-way binding: the element reads its current value from the path and writes back on user input. Example: \`"statePath": "form.email"\` binds to \`state.form.email\`.`);
997
+
998
+ // ── 6. Visibility ───────────────────────────────────────────────────
999
+
1000
+ parts.push(`
1001
+ ## Visibility
1002
+
1003
+ Any element can have a \`visible\` condition. If it evaluates to false, the element is not rendered.
1004
+
1005
+ **Path-based condition:**
1006
+ \`\`\`
1007
+ { "path": "form.role", "operator": "eq", "value": "admin" }
1008
+ \`\`\`
1009
+ Operators: eq, ne, gt, gte, lt, lte.
1010
+
1011
+ **Auth-based condition:**
1012
+ \`\`\`
1013
+ { "auth": "signedIn" }
1014
+ \`\`\`
1015
+ Values: signedIn, signedOut, admin, or any custom role string.
1016
+
1017
+ **Logical combinators:**
1018
+ \`\`\`
1019
+ { "and": [ <condition>, <condition> ] }
1020
+ { "or": [ <condition>, <condition> ] }
1021
+ { "not": <condition> }
1022
+ \`\`\``);
1023
+
1024
+ // ── 7. Validation ───────────────────────────────────────────────────
1025
+
1026
+ parts.push(`
1027
+ ## Validation
1028
+
1029
+ Form elements can declare a \`validation\` object:
1030
+
1031
+ \`\`\`
1032
+ {
1033
+ "checks": [
1034
+ { "fn": "required", "message": "This field is required" },
1035
+ { "fn": "email", "message": "Enter a valid email" },
1036
+ { "fn": "minLength", "args": { "length": 3 }, "message": "At least 3 characters" }
1037
+ ],
1038
+ "validateOn": "blur"
1039
+ }
1040
+ \`\`\`
1041
+
1042
+ \`validateOn\`: "change" | "blur" | "submit" (defaults to submit).
1043
+
1044
+ Built-in validators:
1045
+ - **required** -- value must not be null or empty string
1046
+ - **email** -- must match email pattern
1047
+ - **minLength** -- args: { length: number }
1048
+ - **maxLength** -- args: { length: number }
1049
+ - **pattern** -- args: { pattern: string } (regex)
1050
+ - **min** -- args: { value: number }
1051
+ - **max** -- args: { value: number }`);
1052
+
1053
+ // ── 8. Events ───────────────────────────────────────────────────────
1054
+
1055
+ parts.push(`
1056
+ ## Events
1057
+
1058
+ Elements can have an \`on\` property mapping event names to actions:
1059
+
1060
+ \`\`\`
1061
+ {
1062
+ "on": {
1063
+ "press": {
1064
+ "action": "submitForm",
1065
+ "params": { "formId": "contactForm" },
1066
+ "confirm": {
1067
+ "title": "Confirm submission",
1068
+ "message": "Are you sure?",
1069
+ "confirmLabel": "Yes",
1070
+ "cancelLabel": "No"
1071
+ },
1072
+ "onSuccess": { "action": "showToast", "params": { "message": "Saved!" } },
1073
+ "onError": { "action": "showToast", "params": { "message": "Failed." } }
1074
+ }
1075
+ }
1076
+ }
1077
+ \`\`\`
1078
+
1079
+ Common event names: press, change. The \`action\` string identifies the handler. \`params\`, \`confirm\`, \`onSuccess\`, and \`onError\` are all optional.`);
1080
+
1081
+ // ── 9. Repeat / list rendering ──────────────────────────────────────
1082
+
1083
+ parts.push(`
1084
+ ## Repeat / list rendering
1085
+
1086
+ Render an element once per item in a state array:
1087
+
1088
+ \`\`\`
1089
+ {
1090
+ "type": "Card",
1091
+ "props": { "title": "$data.$item/name" },
1092
+ "children": [],
1093
+ "repeat": { "path": "users", "key": "id" }
1094
+ }
1095
+ \`\`\`
1096
+
1097
+ - \`path\`: dot-path to an array in state.
1098
+ - \`key\`: field name on each item used as the unique key.
1099
+ - Inside the repeated element and its children, use \`$data.$item/fieldName\` or \`{ "$path": "$item/fieldName" }\` to reference item fields.`);
1100
+
1101
+ // ── 10. Custom rules ────────────────────────────────────────────────
1102
+
1103
+ if (options?.customRules && options.customRules.length > 0) {
1104
+ parts.push(`
1105
+ ## Additional rules
1106
+
1107
+ ${options.customRules.map((r) => `- ${r}`).join("\n")}`);
1108
+ }
1109
+
1110
+ // ── 11. Example ─────────────────────────────────────────────────────
1111
+
1112
+ if (options?.includeExamples) {
1113
+ if (mode === "chat") {
1114
+ parts.push(`
1115
+ ## Example — chat mode
1116
+
1117
+ User: "Help me send some BNB to a friend"
1118
+
1119
+ Your response:
1120
+
1121
+ \`\`\`
1122
+ Sure! Here's a quick send form — enter the amount and recipient address:
1123
+
1124
+ {"op":"add","path":"/root","value":"send-card"}
1125
+ {"op":"add","path":"/elements/send-card","value":{"type":"Card","props":{"title":"Send BNB"},"children":["amount-slider","amount-display","addr-input","send-btn"]}}
1126
+ {"op":"add","path":"/elements/amount-slider","value":{"type":"Slider","props":{"label":"Amount (BNB)","min":0,"max":10,"step":0.01,"statePath":"amount"},"children":[]}}
1127
+ {"op":"add","path":"/elements/amount-display","value":{"type":"Metric","props":{"label":"Selected","value":{"$path":"amount"},"unit":"BNB"},"children":[]}}
1128
+ {"op":"add","path":"/elements/addr-input","value":{"type":"Input","props":{"label":"Recipient Address","placeholder":"0x...","statePath":"address"},"children":[],"validation":{"checks":[{"fn":"required","message":"Address is required"}],"validateOn":"blur"}}}
1129
+ {"op":"add","path":"/elements/send-btn","value":{"type":"Button","props":{"label":"Send BNB","variant":"primary"},"children":[],"on":{"press":{"action":"sendBnb","params":{"amount":{"$path":"amount"},"address":{"$path":"address"}},"confirm":{"title":"Confirm transfer","message":"Send BNB to this address?","confirmLabel":"Send","cancelLabel":"Cancel"}}}}}
1130
+ {"op":"add","path":"/state/amount","value":0.1}
1131
+ {"op":"add","path":"/state/address","value":""}
1132
+ \`\`\`
1133
+
1134
+ ---
1135
+
1136
+ User: "What does BNB stand for?"
1137
+
1138
+ Your response: BNB stands for Binance Coin — it's the native token of the BNB Chain (formerly Binance Smart Chain).
1139
+
1140
+ (text-only reply — no patches needed)`);
1141
+ } else {
1142
+ parts.push(`
1143
+ ## Example — generate mode
1144
+
1145
+ \`\`\`
1146
+ {"op":"add","path":"/root","value":"main"}
1147
+ {"op":"add","path":"/elements/main","value":{"type":"Card","props":{"title":"Contact Us"},"children":["heading","desc","email-input","submit-btn"]}}
1148
+ {"op":"add","path":"/elements/heading","value":{"type":"Heading","props":{"text":"Get in Touch","level":"h2"},"children":[]}}
1149
+ {"op":"add","path":"/elements/desc","value":{"type":"Text","props":{"text":"Fill out the form and we will respond within 24 hours.","variant":"muted"},"children":[]}}
1150
+ {"op":"add","path":"/elements/email-input","value":{"type":"Input","props":{"label":"Email","type":"email","placeholder":"you@example.com","statePath":"form.email"},"children":[],"validation":{"checks":[{"fn":"required","message":"Email is required"},{"fn":"email","message":"Enter a valid email"}],"validateOn":"blur"}}}
1151
+ {"op":"add","path":"/elements/submit-btn","value":{"type":"Button","props":{"label":"Send Message","variant":"primary"},"children":[],"on":{"press":{"action":"submitContact","params":{"email":{"$path":"form.email"}}}}}}
1152
+ {"op":"add","path":"/state/form","value":{"email":""}}
1153
+ \`\`\``);
1154
+ }
1155
+ }
1156
+
1157
+ return parts.join("\n");
1158
+ }