@engenty/wizards-runtime 0.0.0-stage → 0.7.5

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 (518) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +214 -2
  3. package/apps/runtime/dist/agents/architect.js +444 -0
  4. package/apps/runtime/dist/agents/studio-assistant.js +883 -0
  5. package/apps/runtime/dist/agents/subscription.js +207 -0
  6. package/apps/runtime/dist/agents/thought.js +21 -0
  7. package/apps/runtime/dist/agents/website.js +480 -0
  8. package/apps/runtime/dist/app.js +359 -0
  9. package/apps/runtime/dist/apple/wizards-apple +0 -0
  10. package/apps/runtime/dist/assistant/browser.js +26 -0
  11. package/apps/runtime/dist/assistant/docs.js +158 -0
  12. package/apps/runtime/dist/assistant/knows.js +353 -0
  13. package/apps/runtime/dist/assistant/primer.js +26 -0
  14. package/apps/runtime/dist/assistant/runs.js +24 -0
  15. package/apps/runtime/dist/auth/account.js +175 -0
  16. package/apps/runtime/dist/auth/device.js +112 -0
  17. package/apps/runtime/dist/auth/index.js +358 -0
  18. package/apps/runtime/dist/auth/keys.js +55 -0
  19. package/apps/runtime/dist/auth/local-ticket.js +26 -0
  20. package/apps/runtime/dist/authoring/example.js +74 -0
  21. package/apps/runtime/dist/authoring/guide.js +433 -0
  22. package/apps/runtime/dist/authoring/ops.js +117 -0
  23. package/apps/runtime/dist/browser/fast/action-space.js +160 -0
  24. package/apps/runtime/dist/browser/fast/classifier.js +91 -0
  25. package/apps/runtime/dist/browser/fast/decide.js +171 -0
  26. package/apps/runtime/dist/browser/fast/driver.js +141 -0
  27. package/apps/runtime/dist/browser/fast/instructions.js +33 -0
  28. package/apps/runtime/dist/browser/fast/run.js +249 -0
  29. package/apps/runtime/dist/browser/fast/span-picker.js +153 -0
  30. package/apps/runtime/dist/browser/fast/text-helper.js +178 -0
  31. package/apps/runtime/dist/browser/snapshot.js +335 -0
  32. package/apps/runtime/dist/cli/account.js +385 -0
  33. package/apps/runtime/dist/cli/autostart.js +182 -0
  34. package/apps/runtime/dist/cli/autoupdate.js +221 -0
  35. package/apps/runtime/dist/cli/clients.js +44 -0
  36. package/apps/runtime/dist/cli/connect.js +540 -0
  37. package/apps/runtime/dist/cli/environment.js +93 -0
  38. package/apps/runtime/dist/cli/exec.js +45 -0
  39. package/apps/runtime/dist/cli/features.js +50 -0
  40. package/apps/runtime/dist/cli/home.js +88 -0
  41. package/apps/runtime/dist/cli/install-env.js +33 -0
  42. package/apps/runtime/dist/cli/machine.js +107 -0
  43. package/apps/runtime/dist/cli/main.js +222 -0
  44. package/apps/runtime/dist/cli/mcp.js +136 -0
  45. package/apps/runtime/dist/cli/menu.js +202 -0
  46. package/apps/runtime/dist/cli/processes.js +72 -0
  47. package/apps/runtime/dist/cli/report.js +66 -0
  48. package/apps/runtime/dist/cli/setup.js +335 -0
  49. package/apps/runtime/dist/cli/start.js +276 -0
  50. package/apps/runtime/dist/cli/status.js +203 -0
  51. package/apps/runtime/dist/cli/ui.js +59 -0
  52. package/apps/runtime/dist/cli/uninstall-main.js +20 -0
  53. package/apps/runtime/dist/cli/uninstall.js +231 -0
  54. package/apps/runtime/dist/cli/update.js +86 -0
  55. package/apps/runtime/dist/cli/validate.js +75 -0
  56. package/apps/runtime/dist/cli/versions.js +123 -0
  57. package/apps/runtime/dist/connectors/builtin.js +86 -0
  58. package/apps/runtime/dist/connectors/external.js +409 -0
  59. package/apps/runtime/dist/connectors/gmail.js +107 -0
  60. package/apps/runtime/dist/connectors/imap.js +261 -0
  61. package/apps/runtime/dist/connectors/index.js +325 -0
  62. package/apps/runtime/dist/connectors/mail.js +72 -0
  63. package/apps/runtime/dist/connectors/outlook.js +90 -0
  64. package/apps/runtime/dist/connectors/plugin-connections.js +343 -0
  65. package/apps/runtime/dist/connectors/via-account.js +65 -0
  66. package/apps/runtime/dist/credits/credits.js +100 -0
  67. package/apps/runtime/dist/credits/estimate.js +152 -0
  68. package/apps/runtime/dist/db/adopt.js +149 -0
  69. package/apps/runtime/dist/db/client.js +173 -0
  70. package/apps/runtime/dist/db/control-schema.js +133 -0
  71. package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
  72. package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
  73. package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
  74. package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
  75. package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
  76. package/apps/runtime/dist/db/migrations/control/0005_chilly_oracle.sql +1 -0
  77. package/apps/runtime/dist/db/migrations/control/0006_sleepy_mojo.sql +1 -0
  78. package/apps/runtime/dist/db/migrations/control/0007_common_the_hand.sql +15 -0
  79. package/apps/runtime/dist/db/migrations/control/0008_runner.sql +8 -0
  80. package/apps/runtime/dist/db/migrations/control/0009_plugin_claim.sql +9 -0
  81. package/apps/runtime/dist/db/migrations/control/0010_tan_snowbird.sql +6 -0
  82. package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
  83. package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
  84. package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
  85. package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
  86. package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
  87. package/apps/runtime/dist/db/migrations/control/meta/0005_snapshot.json +358 -0
  88. package/apps/runtime/dist/db/migrations/control/meta/0006_snapshot.json +365 -0
  89. package/apps/runtime/dist/db/migrations/control/meta/0007_snapshot.json +460 -0
  90. package/apps/runtime/dist/db/migrations/control/meta/0008_snapshot.json +505 -0
  91. package/apps/runtime/dist/db/migrations/control/meta/0009_snapshot.json +561 -0
  92. package/apps/runtime/dist/db/migrations/control/meta/0010_snapshot.json +600 -0
  93. package/apps/runtime/dist/db/migrations/control/meta/_journal.json +83 -0
  94. package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
  95. package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
  96. package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
  97. package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
  98. package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
  99. package/apps/runtime/dist/db/migrations/tenant/0005_reflective_forgotten_one.sql +2 -0
  100. package/apps/runtime/dist/db/migrations/tenant/0006_hard_war_machine.sql +30 -0
  101. package/apps/runtime/dist/db/migrations/tenant/0007_space_data.sql +43 -0
  102. package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
  103. package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
  104. package/apps/runtime/dist/db/migrations/tenant/0010_plugin_connection.sql +15 -0
  105. package/apps/runtime/dist/db/migrations/tenant/0011_runners.sql +2 -0
  106. package/apps/runtime/dist/db/migrations/tenant/0012_assistant_chat.sql +40 -0
  107. package/apps/runtime/dist/db/migrations/tenant/0013_run_origin.sql +1 -0
  108. package/apps/runtime/dist/db/migrations/tenant/0014_run_answer.sql +2 -0
  109. package/apps/runtime/dist/db/migrations/tenant/0015_device_calls.sql +13 -0
  110. package/apps/runtime/dist/db/migrations/tenant/0016_even_trish_tilby.sql +12 -0
  111. package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
  112. package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
  113. package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
  114. package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
  115. package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
  116. package/apps/runtime/dist/db/migrations/tenant/meta/0005_snapshot.json +1659 -0
  117. package/apps/runtime/dist/db/migrations/tenant/meta/0006_snapshot.json +1696 -0
  118. package/apps/runtime/dist/db/migrations/tenant/meta/0007_snapshot.json +2012 -0
  119. package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
  120. package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
  121. package/apps/runtime/dist/db/migrations/tenant/meta/0010_snapshot.json +2942 -0
  122. package/apps/runtime/dist/db/migrations/tenant/meta/0011_snapshot.json +2956 -0
  123. package/apps/runtime/dist/db/migrations/tenant/meta/0012_snapshot.json +3132 -0
  124. package/apps/runtime/dist/db/migrations/tenant/meta/0013_snapshot.json +3139 -0
  125. package/apps/runtime/dist/db/migrations/tenant/meta/0014_snapshot.json +3154 -0
  126. package/apps/runtime/dist/db/migrations/tenant/meta/0015_snapshot.json +3243 -0
  127. package/apps/runtime/dist/db/migrations/tenant/meta/0016_snapshot.json +3326 -0
  128. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +125 -0
  129. package/apps/runtime/dist/db/schema.js +602 -0
  130. package/apps/runtime/dist/debug.js +196 -0
  131. package/apps/runtime/dist/docs/dev/index.md +41 -0
  132. package/apps/runtime/dist/docs/dev/meta.json +7 -0
  133. package/apps/runtime/dist/docs/dev/plugins/connections.md +74 -0
  134. package/apps/runtime/dist/docs/dev/plugins/events.md +89 -0
  135. package/apps/runtime/dist/docs/dev/plugins/examples.md +101 -0
  136. package/apps/runtime/dist/docs/dev/plugins/index.md +78 -0
  137. package/apps/runtime/dist/docs/dev/plugins/layout.md +90 -0
  138. package/apps/runtime/dist/docs/dev/plugins/meta.json +28 -0
  139. package/apps/runtime/dist/docs/dev/plugins/quick-start.md +94 -0
  140. package/apps/runtime/dist/docs/dev/plugins/reference.md +348 -0
  141. package/apps/runtime/dist/docs/dev/plugins/reloading.md +76 -0
  142. package/apps/runtime/dist/docs/dev/plugins/routes.md +185 -0
  143. package/apps/runtime/dist/docs/dev/plugins/runners.md +230 -0
  144. package/apps/runtime/dist/docs/dev/plugins/server.md +281 -0
  145. package/apps/runtime/dist/docs/dev/plugins/shipping.md +79 -0
  146. package/apps/runtime/dist/docs/dev/plugins/space.md +297 -0
  147. package/apps/runtime/dist/docs/dev/plugins/starters.md +70 -0
  148. package/apps/runtime/dist/docs/dev/plugins/studio.md +363 -0
  149. package/apps/runtime/dist/docs/dev/plugins/styling.md +129 -0
  150. package/apps/runtime/dist/docs/dev/plugins/tables.md +104 -0
  151. package/apps/runtime/dist/docs/dev/plugins/tools.md +139 -0
  152. package/apps/runtime/dist/docs/dev/wizard-format.md +125 -0
  153. package/apps/runtime/dist/docs/meta.json +3 -0
  154. package/apps/runtime/dist/docs/user/ai-apps.md +112 -0
  155. package/apps/runtime/dist/docs/user/assistant.md +77 -0
  156. package/apps/runtime/dist/docs/user/build-a-wizard.md +116 -0
  157. package/apps/runtime/dist/docs/user/command-line.md +83 -0
  158. package/apps/runtime/dist/docs/user/connectors.md +90 -0
  159. package/apps/runtime/dist/docs/user/create-account.md +52 -0
  160. package/apps/runtime/dist/docs/user/data.md +66 -0
  161. package/apps/runtime/dist/docs/user/first-start.md +60 -0
  162. package/apps/runtime/dist/docs/user/index.md +49 -0
  163. package/apps/runtime/dist/docs/user/install.md +123 -0
  164. package/apps/runtime/dist/docs/user/local-only.md +42 -0
  165. package/apps/runtime/dist/docs/user/meta.json +32 -0
  166. package/apps/runtime/dist/docs/user/models.md +156 -0
  167. package/apps/runtime/dist/docs/user/plugins.md +71 -0
  168. package/apps/runtime/dist/docs/user/run.md +98 -0
  169. package/apps/runtime/dist/docs/user/server.md +52 -0
  170. package/apps/runtime/dist/docs/user/space.md +126 -0
  171. package/apps/runtime/dist/docs/user/steps.md +220 -0
  172. package/apps/runtime/dist/docs/user/test-and-share.md +224 -0
  173. package/apps/runtime/dist/docs/user/troubleshooting.md +67 -0
  174. package/apps/runtime/dist/docs/user/wordpress.md +121 -0
  175. package/apps/runtime/dist/documents/parse.js +246 -0
  176. package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
  177. package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
  178. package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
  179. package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
  180. package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
  181. package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
  182. package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
  183. package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
  184. package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
  185. package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
  186. package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
  187. package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
  188. package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
  189. package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
  190. package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
  191. package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +381 -0
  192. package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
  193. package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
  194. package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
  195. package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
  196. package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
  197. package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
  198. package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
  199. package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
  200. package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
  201. package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +492 -0
  202. package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
  203. package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
  204. package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
  205. package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
  206. package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
  207. package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
  208. package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
  209. package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
  210. package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
  211. package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
  212. package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
  213. package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
  214. package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
  215. package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
  216. package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
  217. package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
  218. package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
  219. package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
  220. package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
  221. package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
  222. package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
  223. package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
  224. package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
  225. package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
  226. package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
  227. package/apps/runtime/dist/engenty/shims/web-ingest.js +19 -0
  228. package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
  229. package/apps/runtime/dist/engine/asks.js +82 -0
  230. package/apps/runtime/dist/engine/decide.js +82 -0
  231. package/apps/runtime/dist/engine/device.js +194 -0
  232. package/apps/runtime/dist/engine/events.js +128 -0
  233. package/apps/runtime/dist/engine/input.js +208 -0
  234. package/apps/runtime/dist/engine/owner.js +32 -0
  235. package/apps/runtime/dist/engine/prepare.js +90 -0
  236. package/apps/runtime/dist/engine/push.js +58 -0
  237. package/apps/runtime/dist/engine/requirements.js +355 -0
  238. package/apps/runtime/dist/engine/resources.js +198 -0
  239. package/apps/runtime/dist/engine/runner.js +970 -0
  240. package/apps/runtime/dist/engine/steps.js +1000 -0
  241. package/apps/runtime/dist/engine/surface.js +91 -0
  242. package/apps/runtime/dist/engine/template.js +240 -0
  243. package/apps/runtime/dist/engine/types.js +4 -0
  244. package/apps/runtime/dist/env.js +295 -0
  245. package/apps/runtime/dist/features.js +123 -0
  246. package/apps/runtime/dist/files/blobs.js +22 -0
  247. package/apps/runtime/dist/files/objects.js +86 -0
  248. package/apps/runtime/dist/files/storage.js +120 -0
  249. package/apps/runtime/dist/files/web-images.js +101 -0
  250. package/apps/runtime/dist/film/project.js +257 -0
  251. package/apps/runtime/dist/film/skills.js +91 -0
  252. package/apps/runtime/dist/film/sounds.js +122 -0
  253. package/apps/runtime/dist/film/step.js +289 -0
  254. package/apps/runtime/dist/film/tools.js +99 -0
  255. package/apps/runtime/dist/geocode.js +58 -0
  256. package/apps/runtime/dist/harness/antigravity.js +129 -0
  257. package/apps/runtime/dist/harness/apple.js +270 -0
  258. package/apps/runtime/dist/harness/claude.js +147 -0
  259. package/apps/runtime/dist/harness/codex.js +229 -0
  260. package/apps/runtime/dist/harness/cursor.js +93 -0
  261. package/apps/runtime/dist/harness/env.js +124 -0
  262. package/apps/runtime/dist/harness/index.js +95 -0
  263. package/apps/runtime/dist/harness/model.js +279 -0
  264. package/apps/runtime/dist/harness/prompt.js +121 -0
  265. package/apps/runtime/dist/harness/terminal.js +194 -0
  266. package/apps/runtime/dist/harness/types.js +7 -0
  267. package/apps/runtime/dist/index.js +113 -0
  268. package/apps/runtime/dist/limits.js +81 -0
  269. package/apps/runtime/dist/link-preview.js +60 -0
  270. package/apps/runtime/dist/log.js +106 -0
  271. package/apps/runtime/dist/manage.js +249 -0
  272. package/apps/runtime/dist/mcp/auth.js +161 -0
  273. package/apps/runtime/dist/mcp/bridge.js +59 -0
  274. package/apps/runtime/dist/mcp/flow-app.js +97 -0
  275. package/apps/runtime/dist/mcp/handler.js +54 -0
  276. package/apps/runtime/dist/mcp/scopes.js +14 -0
  277. package/apps/runtime/dist/mcp/seen.js +65 -0
  278. package/apps/runtime/dist/mcp/tools.js +572 -0
  279. package/apps/runtime/dist/media/conversation.js +167 -0
  280. package/apps/runtime/dist/media/ffmpeg.js +121 -0
  281. package/apps/runtime/dist/media/generate.js +120 -0
  282. package/apps/runtime/dist/media/marking.js +121 -0
  283. package/apps/runtime/dist/media/transcribe.js +198 -0
  284. package/apps/runtime/dist/model-errors.js +42 -0
  285. package/apps/runtime/dist/models.js +1164 -0
  286. package/apps/runtime/dist/plugin.js +61 -0
  287. package/apps/runtime/dist/plugins/channels.js +78 -0
  288. package/apps/runtime/dist/plugins/claims.js +56 -0
  289. package/apps/runtime/dist/plugins/discovery.js +155 -0
  290. package/apps/runtime/dist/plugins/events.js +63 -0
  291. package/apps/runtime/dist/plugins/jobs.js +64 -0
  292. package/apps/runtime/dist/plugins/loader.js +508 -0
  293. package/apps/runtime/dist/plugins/migrations.js +69 -0
  294. package/apps/runtime/dist/plugins/pro-keys.js +34 -0
  295. package/apps/runtime/dist/plugins/pro-state.js +83 -0
  296. package/apps/runtime/dist/plugins/pro.js +310 -0
  297. package/apps/runtime/dist/plugins/public.js +44 -0
  298. package/apps/runtime/dist/plugins/registry.js +122 -0
  299. package/apps/runtime/dist/plugins/runs.js +210 -0
  300. package/apps/runtime/dist/render/browser-path.js +54 -0
  301. package/apps/runtime/dist/render/chromium.js +98 -0
  302. package/apps/runtime/dist/render/convert.js +158 -0
  303. package/apps/runtime/dist/render/downloads.js +299 -0
  304. package/apps/runtime/dist/render/guard.js +25 -0
  305. package/apps/runtime/dist/render/shaped.js +137 -0
  306. package/apps/runtime/dist/routes/api.js +440 -0
  307. package/apps/runtime/dist/routes/debug.js +42 -0
  308. package/apps/runtime/dist/routes/delivery.js +90 -0
  309. package/apps/runtime/dist/routes/internal.js +81 -0
  310. package/apps/runtime/dist/routes/lang.js +25 -0
  311. package/apps/runtime/dist/routes/marketplace.js +43 -0
  312. package/apps/runtime/dist/routes/plugin-public.js +113 -0
  313. package/apps/runtime/dist/routes/plugins.js +212 -0
  314. package/apps/runtime/dist/routes/runs.js +1422 -0
  315. package/apps/runtime/dist/routes/studio.js +1629 -0
  316. package/apps/runtime/dist/routes/wizard-stream.js +30 -0
  317. package/apps/runtime/dist/running.js +39 -0
  318. package/apps/runtime/dist/sandbox/docker.js +75 -0
  319. package/apps/runtime/dist/sandbox/index.js +23 -0
  320. package/apps/runtime/dist/sandbox/types.js +1 -0
  321. package/apps/runtime/dist/secrets/crypto.js +28 -0
  322. package/apps/runtime/dist/secrets/signing.js +52 -0
  323. package/apps/runtime/dist/secrets/vault.js +59 -0
  324. package/apps/runtime/dist/services/access.js +88 -0
  325. package/apps/runtime/dist/services/api.js +248 -0
  326. package/apps/runtime/dist/services/architect.js +95 -0
  327. package/apps/runtime/dist/services/assistant-chats.js +311 -0
  328. package/apps/runtime/dist/services/brand.js +85 -0
  329. package/apps/runtime/dist/services/cloud.js +456 -0
  330. package/apps/runtime/dist/services/draft-events.js +27 -0
  331. package/apps/runtime/dist/services/engenty-shapes.js +71 -0
  332. package/apps/runtime/dist/services/errors.js +29 -0
  333. package/apps/runtime/dist/services/files.js +178 -0
  334. package/apps/runtime/dist/services/knowledge-model.js +559 -0
  335. package/apps/runtime/dist/services/knowledge.js +721 -0
  336. package/apps/runtime/dist/services/links.js +16 -0
  337. package/apps/runtime/dist/services/marketplace.js +492 -0
  338. package/apps/runtime/dist/services/onboarding.js +152 -0
  339. package/apps/runtime/dist/services/package-file.js +82 -0
  340. package/apps/runtime/dist/services/package.js +170 -0
  341. package/apps/runtime/dist/services/profile.js +51 -0
  342. package/apps/runtime/dist/services/project-files.js +439 -0
  343. package/apps/runtime/dist/services/project-index.js +707 -0
  344. package/apps/runtime/dist/services/projects.js +387 -0
  345. package/apps/runtime/dist/services/relevance.js +58 -0
  346. package/apps/runtime/dist/services/runners.js +178 -0
  347. package/apps/runtime/dist/services/runs.js +524 -0
  348. package/apps/runtime/dist/services/shares.js +130 -0
  349. package/apps/runtime/dist/services/site.js +270 -0
  350. package/apps/runtime/dist/services/space-categories.js +861 -0
  351. package/apps/runtime/dist/services/space-data.js +792 -0
  352. package/apps/runtime/dist/services/space-origin.js +207 -0
  353. package/apps/runtime/dist/services/spaces.js +656 -0
  354. package/apps/runtime/dist/services/translations.js +306 -0
  355. package/apps/runtime/dist/services/widgets.js +34 -0
  356. package/apps/runtime/dist/services/wizard-icon.js +157 -0
  357. package/apps/runtime/dist/services/wizards.js +420 -0
  358. package/apps/runtime/dist/settings.js +16 -0
  359. package/apps/runtime/dist/store/errors.js +4 -0
  360. package/apps/runtime/dist/store/index.js +299 -0
  361. package/apps/runtime/dist/store/shared-lists.js +123 -0
  362. package/apps/runtime/dist/tenants/control.js +238 -0
  363. package/apps/runtime/dist/tenants/tenant.js +26 -0
  364. package/apps/runtime/dist/texts.js +207 -0
  365. package/apps/runtime/dist/tools/browser.js +703 -0
  366. package/apps/runtime/dist/tools/connector.js +204 -0
  367. package/apps/runtime/dist/tools/index.js +291 -0
  368. package/apps/runtime/dist/tools/mail.js +104 -0
  369. package/apps/runtime/dist/tools/net-guard.js +170 -0
  370. package/apps/runtime/dist/tools/pages.js +81 -0
  371. package/apps/runtime/dist/tools/plugin.js +180 -0
  372. package/apps/runtime/dist/tools/project.js +154 -0
  373. package/apps/runtime/dist/tools/shared.js +69 -0
  374. package/apps/runtime/dist/tools/store.js +238 -0
  375. package/apps/runtime/dist/update.js +113 -0
  376. package/apps/runtime/dist/widgets/bundle.js +99 -0
  377. package/apps/runtime/dist/widgets/render.js +329 -0
  378. package/apps/runtime/dist/widgets/runtime.js +108 -0
  379. package/apps/runtime/dist/widgets/script.js +30 -0
  380. package/apps/runtime/dist/widgets/step.js +223 -0
  381. package/apps/web/dist/ai-labels/ai-black.svg +20 -0
  382. package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
  383. package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
  384. package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
  385. package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
  386. package/apps/web/dist/ai-labels/ai-white.svg +21 -0
  387. package/apps/web/dist/assets/AboutDialog-D4mvc-zu.js +1 -0
  388. package/apps/web/dist/assets/ChangelogDialog-DLqpJsF6.js +1 -0
  389. package/apps/web/dist/assets/ChatView-3laypRcE.js +10 -0
  390. package/apps/web/dist/assets/EditorPage-BalA5U2Y.js +3 -0
  391. package/apps/web/dist/assets/FlowPreview-CusP7ci9.js +1 -0
  392. package/apps/web/dist/assets/Harness-BrP-ENHg.css +1 -0
  393. package/apps/web/dist/assets/Harness-iYLtOLaK.js +16 -0
  394. package/apps/web/dist/assets/NewWizardChannels-CbwJ9A56.js +1 -0
  395. package/apps/web/dist/assets/NewWizardPage-BOBYiB9i.js +7 -0
  396. package/apps/web/dist/assets/OnboardingPage-CUwCiVIr.js +1 -0
  397. package/apps/web/dist/assets/ProjectPage-Bb16MdYG.js +1 -0
  398. package/apps/web/dist/assets/PublicRunner-BCt7Q6C-.js +1 -0
  399. package/apps/web/dist/assets/ReadOnly-kIHX2TEy.js +1 -0
  400. package/apps/web/dist/assets/RunDrawer-hZ9oeSXu.js +4 -0
  401. package/apps/web/dist/assets/RunnerView-DUS9fPmx.js +1 -0
  402. package/apps/web/dist/assets/SettingsPage-BzwR50fi.js +1 -0
  403. package/apps/web/dist/assets/SetupPage-gAp7rPxp.js +1 -0
  404. package/apps/web/dist/assets/SharePage-DqZWHva_.js +1 -0
  405. package/apps/web/dist/assets/changelog-DugmCNSf.js +1 -0
  406. package/apps/web/dist/assets/engenty-eXZ-EAwd.js +1 -0
  407. package/apps/web/dist/assets/esm-DXeMu8Lb.js +7 -0
  408. package/apps/web/dist/assets/fluffy-engenty-ClRou7yu.js +456 -0
  409. package/apps/web/dist/assets/index-AfUa8xKD.css +1 -0
  410. package/apps/web/dist/assets/index-C5Sm7tTR.js +14 -0
  411. package/apps/web/dist/assets/jsx-runtime-BNakU3Ej.js +1 -0
  412. package/apps/web/dist/assets/lock-R_CfU0Xo.js +1 -0
  413. package/apps/web/dist/assets/oss-credits-cZ9NUaLZ.js +1 -0
  414. package/apps/web/dist/assets/pdfmake-Cx9scTbD.js +228 -0
  415. package/apps/web/dist/assets/phone-CgrIS4_-.js +1 -0
  416. package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
  417. package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
  418. package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
  419. package/apps/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
  420. package/apps/web/dist/assets/settings-menu-2IMOOlLl.js +1 -0
  421. package/apps/web/dist/assets/ui-dzGvc3xk.js +137 -0
  422. package/apps/web/dist/assets/upload-BSuTilFF.js +1 -0
  423. package/apps/web/dist/assets/vfs_fonts-DllDSYt1.js +1 -0
  424. package/apps/web/dist/embed.js +266 -0
  425. package/apps/web/dist/favicon.svg +1 -0
  426. package/apps/web/dist/icons/apple-touch-icon.png +0 -0
  427. package/apps/web/dist/icons/icon-192.png +0 -0
  428. package/apps/web/dist/icons/icon-512.png +0 -0
  429. package/apps/web/dist/icons/icon-maskable-512.png +0 -0
  430. package/apps/web/dist/index.html +48 -0
  431. package/apps/web/dist/install.sh +577 -0
  432. package/apps/web/dist/manifest.webmanifest +21 -0
  433. package/apps/web/dist/mcp/flow.html +980 -0
  434. package/apps/web/dist/sw.js +15 -0
  435. package/bin/wizards.mjs +288 -0
  436. package/modules/README.md +15 -0
  437. package/node_modules/@engenty/wizards/dist/plugin/index.d.ts +1150 -0
  438. package/node_modules/@engenty/wizards/dist/plugin/index.js +4 -0
  439. package/node_modules/@engenty/wizards/dist/plugin/studio.d.ts +322 -0
  440. package/node_modules/@engenty/wizards/dist/plugin/studio.js +4 -0
  441. package/node_modules/@engenty/wizards/dist/plugin/thread.d.ts +174 -0
  442. package/node_modules/@engenty/wizards/dist/plugin/thread.js +821 -0
  443. package/node_modules/@engenty/wizards/package.json +11 -0
  444. package/node_modules/@engenty-wizards/shared/dist/assistant.d.ts +174 -0
  445. package/node_modules/@engenty-wizards/shared/dist/assistant.js +65 -0
  446. package/node_modules/@engenty-wizards/shared/dist/changes.d.ts +22 -0
  447. package/node_modules/@engenty-wizards/shared/dist/changes.js +61 -0
  448. package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
  449. package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
  450. package/node_modules/@engenty-wizards/shared/dist/decision.d.ts +76 -0
  451. package/node_modules/@engenty-wizards/shared/dist/decision.js +147 -0
  452. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +2922 -0
  453. package/node_modules/@engenty-wizards/shared/dist/definition.js +1920 -0
  454. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
  455. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
  456. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
  457. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
  458. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
  459. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +217 -0
  460. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
  461. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
  462. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
  463. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
  464. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
  465. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
  466. package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +78 -0
  467. package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +70 -0
  468. package/node_modules/@engenty-wizards/shared/dist/features.d.ts +41 -0
  469. package/node_modules/@engenty-wizards/shared/dist/features.js +89 -0
  470. package/node_modules/@engenty-wizards/shared/dist/fit.d.ts +71 -0
  471. package/node_modules/@engenty-wizards/shared/dist/fit.js +382 -0
  472. package/node_modules/@engenty-wizards/shared/dist/json-schema.d.ts +14 -0
  473. package/node_modules/@engenty-wizards/shared/dist/json-schema.js +66 -0
  474. package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
  475. package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
  476. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
  477. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +107 -0
  478. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
  479. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +136 -0
  480. package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +227 -0
  481. package/node_modules/@engenty-wizards/shared/dist/marketplace.js +354 -0
  482. package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
  483. package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
  484. package/node_modules/@engenty-wizards/shared/dist/numbers.d.ts +24 -0
  485. package/node_modules/@engenty-wizards/shared/dist/numbers.js +54 -0
  486. package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +224 -0
  487. package/node_modules/@engenty-wizards/shared/dist/projects.js +319 -0
  488. package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +101 -0
  489. package/node_modules/@engenty-wizards/shared/dist/providers.js +390 -0
  490. package/node_modules/@engenty-wizards/shared/dist/run.d.ts +680 -0
  491. package/node_modules/@engenty-wizards/shared/dist/run.js +620 -0
  492. package/node_modules/@engenty-wizards/shared/dist/runner-texts.d.ts +546 -0
  493. package/node_modules/@engenty-wizards/shared/dist/runner-texts.js +523 -0
  494. package/node_modules/@engenty-wizards/shared/dist/runners.d.ts +93 -0
  495. package/node_modules/@engenty-wizards/shared/dist/runners.js +146 -0
  496. package/node_modules/@engenty-wizards/shared/dist/shape.d.ts +102 -0
  497. package/node_modules/@engenty-wizards/shared/dist/shape.js +318 -0
  498. package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +89 -0
  499. package/node_modules/@engenty-wizards/shared/dist/space-data.js +47 -0
  500. package/node_modules/@engenty-wizards/shared/dist/store.d.ts +117 -0
  501. package/node_modules/@engenty-wizards/shared/dist/store.js +81 -0
  502. package/node_modules/@engenty-wizards/shared/dist/surface.d.ts +115 -0
  503. package/node_modules/@engenty-wizards/shared/dist/surface.js +442 -0
  504. package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +45 -0
  505. package/node_modules/@engenty-wizards/shared/dist/texts.js +54 -0
  506. package/node_modules/@engenty-wizards/shared/dist/translation.d.ts +23 -0
  507. package/node_modules/@engenty-wizards/shared/dist/translation.js +154 -0
  508. package/node_modules/@engenty-wizards/shared/dist/wizard-package.d.ts +48 -0
  509. package/node_modules/@engenty-wizards/shared/dist/wizard-package.js +49 -0
  510. package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
  511. package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
  512. package/node_modules/@engenty-wizards/shared/package.json +10 -0
  513. package/package.json +77 -4
  514. package/plugin/.claude-plugin/plugin.json +9 -0
  515. package/plugin/.mcp.json +8 -0
  516. package/plugin/commands/wizard.md +8 -0
  517. package/plugin/skills/build-wizard/SKILL.md +27 -0
  518. package/plugin/skills/use-wizard/SKILL.md +18 -0
@@ -0,0 +1,281 @@
1
+ ---
2
+ title: The server half
3
+ description: The function a plugin exports, what it is handed, and the rules it runs under.
4
+ version: 0.5.0
5
+ ---
6
+
7
+ The server half is a file whose default export is a function. The runtime calls it once when the
8
+ plugin loads and hands it `wizards`. The function registers what the plugin adds.
9
+
10
+ ```ts
11
+ import { definePlugin } from "@engenty/wizards/plugin";
12
+
13
+ export default definePlugin((wizards) => {
14
+ const { server } = wizards;
15
+
16
+ server.registerMigrations("migrations");
17
+ server.registerHttpRoute({ method: "GET", path: "/", handler: async () => ({ ok: true }) });
18
+ server.registerTool({ /* … */ });
19
+ server.on("run.done", async (event) => { /* … */ });
20
+ });
21
+ ```
22
+
23
+ `definePlugin` only types the function. The function may be `async`.
24
+
25
+ ## What it is handed
26
+
27
+ | | |
28
+ |---|---|
29
+ | `wizards.server` | Registers tools, routes, tables and listeners. See the table below |
30
+ | `wizards.plugin` | The manifest: `id`, `name`, `version` and whatever else it holds |
31
+ | `wizards.config.get(key)` | A setting of the install: a line of its `.env`. Empty and missing are both `undefined` |
32
+ | `wizards.features.has(name)`, `.all()` | The feature switches of the tenant at hand. See [Feature switches](#feature-switches) |
33
+ | `wizards.log.info`, `.warn`, `.error` | A log line with the plugin’s name in front |
34
+ | `wizards.resolvePath(relative)` | A file of the plugin as an absolute path |
35
+
36
+ | `wizards.server.` | Does | Page |
37
+ |---|---|---|
38
+ | `registerTool(tool)` | A tool for AI steps | [Tools](./tools.md) |
39
+ | `registerSpaceContext(context)` | A block and tools for every AI step of a space | [The space](./space.md) |
40
+ | `registerAssistantTool(tool)` | A tool of the space assistant | [The space](./space.md#tools-of-the-space-assistant) |
41
+ | `registerAssistantContext(context)` | What the space assistant is told on the plugin’s own page | [The space](./space.md#the-assistant-on-the-plugins-own-page) |
42
+ | `spaceData.putPage(input)`, `putTable`, `putFile`, `putDocument`, `putCategories`, … | Knowledge of a space: pages, tables, files and categories | [The space](./space.md#knowledge-a-plugin-writes) |
43
+ | `spaces.brand(space)` | The space’s look: its title, colours and fonts | [The space](./space.md#the-spaces-brand) |
44
+ | `index.put(entry)`, `index.remove(space, key?)` | Texts in the space’s search index | [The space](./space.md#the-search-index) |
45
+ | `registerHttpRoute(route)` | A route below `/api/studio/plugins/<id>` | [Routes](./routes.md) |
46
+ | `registerPublicRoute(route)`, `publicUrl(path)` | A route anyone may call, and its address | [Routes](./routes.md#public-routes) |
47
+ | `registerSharedRoute(route)`, `sharedUrl(path)`, `publicRef()` | One route for every tenant, and the ref that names one | [Routes](./routes.md#shared-routes) |
48
+ | `channels.get()`, `request`, `withdraw`, `book` | The numbers the Manage-App gives the tenant | below |
49
+ | `claims.take(key)`, `put`, `drop`, `holder`, `mine` | Keys held across tenants, one tenant each | below |
50
+ | `registerRunner(runner)` | A door a wizard runs through, beside the page and the chat | [Runners](./runners.md) |
51
+ | `runs.start(…)`, `report`, `answerPage`, … | Drives runs from the plugin’s own door | [Runners](./runners.md#drive-a-run) |
52
+ | `speech.conversation()` | The tenant’s realtime speech model, for a call | [Runners](./runners.md#a-call) |
53
+ | `registerMigrations(folder)` | `.sql` files with the plugin’s tables | [Tables](./tables.md) |
54
+ | `on(event, listener)` | Called when a run ends or a space changes | [Events](./events.md) |
55
+ | `connections.available(…)`, `start`, `connect`, `list`, `call`, … | Accounts of a space, through the built-in connectors | [Accounts](./connections.md) |
56
+ | `registerStarter(starter)` | A wizard the plugin brings as a template | [Starters](./starters.md) |
57
+ | `every(name, everyMs, handler)` | A job, again and again | below |
58
+ | `web.fetch(url, init?)`, `web.read(url)` | Requests to the web, guarded | below |
59
+ | `documents.parse(file)` | A file as Markdown | below |
60
+ | `secrets.seal(value)`, `secrets.unseal(sealed)` | Keys of the plugin’s own, sealed for a table | below |
61
+ | `getTenantDb()` | The database of the tenant the current request, step or event belongs to | [Tables](./tables.md) |
62
+ | `generate(request)` | Asks a model of the current tenant | below |
63
+ | `onUnload(fn)` | Something to undo when the plugin unloads | below |
64
+
65
+ ## Settings
66
+
67
+ Name a plugin’s settings after the plugin and read them when the plugin loads:
68
+
69
+ ```ts
70
+ const url = wizards.config.get("NOTIFY_URL");
71
+ if (!url) {
72
+ wizards.log.warn("NOTIFY_URL is not set: nothing will be sent.");
73
+ return;
74
+ }
75
+ ```
76
+
77
+ The person sets them in the install’s `.env` and restarts engenty wizards. A plugin doesn’t get
78
+ a settings page for free: a plugin that wants one adds a [settings section](./studio.md) and
79
+ keeps the values in a [table](./tables.md).
80
+
81
+ ## Feature switches
82
+
83
+ A plugin declares its own switches in its manifest under `features`
84
+ ([Files and manifest](./layout.md#the-manifest)). Everywhere else each one is known as
85
+ `<plugin id>.<name>`: in `wizards features`, in the install’s `.features` file and in the
86
+ `FEATURES` setting.
87
+
88
+ ```ts
89
+ if (await wizards.features.has("leadScoring")) {
90
+ server.registerTool(scoreLead);
91
+ }
92
+ ```
93
+
94
+ - `has(name)` with a short name asks for the plugin’s own switch (`contacts.leadScoring`); a
95
+ full name asks for any switch, the runtime’s own included.
96
+ - `all()` gives every switch of the tenant at hand, by its full name.
97
+ - A switch is off unless something turned it on.
98
+
99
+ ## Tenants
100
+
101
+ A runtime serves one tenant on a person’s computer and many on engenty.ai. Either way, a plugin
102
+ never names a tenant:
103
+
104
+ - A route, a tool and a listener each run inside one tenant.
105
+ - `server.getTenantDb()` is that tenant’s database. Call it where you use it, not once at load
106
+ time: at load time there is no tenant.
107
+ - State kept in a variable of the module is shared by all tenants. Keep per-tenant state in a
108
+ table.
109
+
110
+ ## Numbers of the Manage-App
111
+
112
+ On engenty.ai a team gets its number for texts and calls from engenty: it asks for one, an
113
+ admin assigns it. `server.channels` reads it for the current tenant and books what it carries;
114
+ the prices are the Manage-App’s ([manage contract](https://github.com/engenty/wizards/blob/main/docs/manage-contract.md#numbers-of-a-tenant)).
115
+
116
+ ```ts
117
+ const channels = await server.channels.get();
118
+ // { number: { number: "+43…", country: "AT", kinds: ["sms", "call"], providerRef: "PN…" } | null,
119
+ // request: { id, country, wish, createdAt } | null,
120
+ // shared: [{ number, country, kinds }],
121
+ // allowed: true } // false: the plan has no number of its own (Free)
122
+
123
+ await server.channels.request({ userId: request.user.id, country: "AT", lang: "de" });
124
+ await server.channels.book({ kind: "sms", quantity: segments, key: messageSid, runId });
125
+ ```
126
+
127
+ - `get` is kept for a minute; `request` and `withdraw` forget it.
128
+ - `request` throws `403` / `plan` on a plan without a number and `409` / `has_number` when
129
+ the team has one. Asking again gives the open request.
130
+ - `book`: `sms` by segment, sent or received, `call` by started minute, `whatsapp` by
131
+ message sent. The same `key` books once.
132
+ - A runtime without a Manage-App has no numbers: `get` gives `null`, `request` and `withdraw`
133
+ throw `404` / `not_managed`, `book` books nothing.
134
+
135
+ ## Keys across tenants
136
+
137
+ What a [shared route](./routes.md#shared-routes) needs to find its tenant: a keyword on a number
138
+ every tenant shares, who last wrote to it, a number a tenant connected. `server.claims` holds
139
+ such keys, each for one tenant at a time, in the runtime’s own database:
140
+
141
+ ```ts
142
+ // In the tenant: the keyword is this tenant's, unless another one has it.
143
+ if (!(await server.claims.take(`kw:${keyword.toLowerCase()}`))) {
144
+ throw Object.assign(new Error("Taken."), { status: 409, code: "keyword_taken" });
145
+ }
146
+ await server.claims.put(`sender:${waId}`); // the last tenant they wrote to has them
147
+
148
+ // In the shared route: whose is it?
149
+ const ref = await server.claims.holder(`kw:${text.toLowerCase()}`);
150
+ if (ref) {
151
+ await inTenant(ref, () => handle(message));
152
+ }
153
+ ```
154
+
155
+ | | |
156
+ |---|---|
157
+ | `take(key)` | The current tenant takes the key; `false` when another tenant holds it |
158
+ | `put(key)` | The current tenant gets the key, whoever held it |
159
+ | `drop(key)` | The current tenant gives the key up; a key another tenant holds stays |
160
+ | `holder(key)` | The ref of the tenant that holds the key, for `inTenant`; `null` for none. Also outside a tenant |
161
+ | `mine(key)` | Whether the current tenant holds the key |
162
+
163
+ Keys are 1 to 200 characters and the plugin’s own: another plugin’s key of the same name is
164
+ another key. They stay when a tenant loses the plugin; `inTenant` then answers `404`.
165
+
166
+ ## Asking a model
167
+
168
+ `server.generate` asks one of the tenant’s models, the same ones its wizards run on, and is paid
169
+ like any other of its calls. With a `schema` the answer is an object of that shape:
170
+
171
+ ```ts
172
+ const { object } = await server.generate({
173
+ model: "classifier",
174
+ system: "You sort support mails.",
175
+ prompt: `Which team does this mail go to?\n\n${mail}`,
176
+ schema: z.object({ team: z.enum(["sales", "support", "billing"]) }),
177
+ });
178
+ ```
179
+
180
+ | Field | | Default |
181
+ |---|---|---|
182
+ | `prompt` | What the model is asked | required |
183
+ | `system` | How it should answer | |
184
+ | `schema` | A zod schema: `object` is the answer in that shape | text only |
185
+ | `model` | `classifier` (fast, cheap), `standard`, `high`, `highest` | `standard` |
186
+ | `maxOutputTokens` | A limit on the answer | the model’s |
187
+ | `signal` | Aborts the call | two minutes |
188
+ | `files` | Pictures (PNG, JPEG, WebP, GIF) and PDFs the model looks at with the prompt: `{ data, mediaType, name? }[]`, `data` a `Uint8Array` | none |
189
+
190
+ It answers `{ text, object }`. Without a model set up it throws an error with the status `503`
191
+ and the code `no_model`: a route that lets it through answers just that, and the studio half
192
+ says it in the person’s language.
193
+
194
+ ## Jobs
195
+
196
+ ```ts
197
+ server.every("refresh", 60 * 60_000, async ({ tenantId, lastRun, signal }) => {
198
+ for (const source of await dueSources()) {
199
+ await refresh(source, signal);
200
+ }
201
+ });
202
+ ```
203
+
204
+ - The handler runs for every tenant that has the plugin, inside that tenant, at most once per
205
+ `everyMs`. The shortest interval is a minute.
206
+ - A job’s name is lower case, digits and `_`, once per plugin.
207
+ - The runtime keeps when a job ran, so a restart does not start the count again. A runtime that
208
+ was off runs a due job once when it starts, not once per turn it missed. On a person’s computer,
209
+ jobs run while engenty wizards runs.
210
+ - One turn per tenant at a time. A turn that throws is logged and counts as run.
211
+ - `lastRun` is when the turn before started; `null` the first time. `signal` is aborted
212
+ when the plugin unloads.
213
+ - `PLUGIN_JOBS=0` keeps a runtime from running jobs, for one whose jobs another process runs.
214
+
215
+ ## The web
216
+
217
+ ```ts
218
+ const page = await server.web.read("https://example.com/preise");
219
+ // { url, status, etag, lastModified, title, description, text, links, jsonld }
220
+
221
+ const res = await server.web.fetch(`${origin}/sitemap.xml`, {
222
+ headers: { "if-none-match": source.etag ?? "" },
223
+ });
224
+ ```
225
+
226
+ - Both refuse addresses of the computer the runtime runs on and of its local network, after a
227
+ redirect too, as the runtime’s own requests do.
228
+ - `read` gives the page’s text as Markdown and its links, absolute and each once (up to
229
+ 2,000). A page with hardly any text without its scripts is drawn in a browser first. `etag`
230
+ and `lastModified` are what the server sent, for asking later whether the page changed. `jsonld`
231
+ is the page’s structured data (its `application/ld+json` blocks, parsed): a shop’s product
232
+ page says title, price, availability and image there exactly, without a model.
233
+ - `fetch` is `fetch` behind the guard: for a sitemap, `robots.txt`, a question with
234
+ `if-none-match`.
235
+
236
+ ## Keys of the plugin’s own
237
+
238
+ A plugin that talks to a shop or a service with keys the person typed keeps them sealed, as the
239
+ runtime seals a connection’s tokens:
240
+
241
+ ```ts
242
+ await db().update(store).set({ credentials: server.secrets.seal({ token }) });
243
+ const keys = server.secrets.unseal<{ token: string }>(row.credentials);
244
+ ```
245
+
246
+ `unseal` answers null for a value sealed on another install: ask for the keys again.
247
+
248
+ ## Documents
249
+
250
+ ```ts
251
+ const { markdown, pages } = await server.documents.parse({ data, name: "preise.pdf", mime });
252
+ ```
253
+
254
+ PDF and Word files are read by their own text, scans and photos by a vision model, and
255
+ spreadsheets and CSV files as tables. What was read is kept by content, so the same bytes are
256
+ read, and paid for, only once.
257
+
258
+ ## Undo on unload
259
+
260
+ A plugin can load again while the runtime runs. What it registered through `wizards.server` is
261
+ taken back for it. Anything else it started, it undoes itself:
262
+
263
+ ```ts
264
+ const timer = setInterval(sync, 60_000);
265
+ server.onUnload(() => clearInterval(timer));
266
+ ```
267
+
268
+ The functions run last-first when the plugin unloads or loads again.
269
+
270
+ ## When loading fails
271
+
272
+ A plugin whose function throws keeps nothing of what it registered before the error, so there
273
+ are no half-loaded plugins. Settings → Plugins shows the error, and the plugin’s routes answer
274
+ `404` until you fix its file.
275
+
276
+ ## Imports
277
+
278
+ `@engenty/wizards/plugin` (and `@engenty/wizards/plugin/thread`), `zod`, `drizzle-orm` and
279
+ `drizzle-orm/sqlite-core` come from the runtime’s own copies, so a schema or a table a plugin
280
+ makes is one the runtime understands. See [Files and manifest](./layout.md#dependencies) for
281
+ everything else.
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: Shipping
3
+ description: Hand a plugin to someone else, put it into a server's image, and decide which tenant has it.
4
+ version: 0.5.0
5
+ ---
6
+
7
+ ## To someone’s install
8
+
9
+ A plugin is a file or a folder. Whoever installs it puts it into their plugins folder, which is
10
+ `~/.engenty/wizards/plugins` for an installed app.
11
+
12
+ Give them:
13
+
14
+ | | |
15
+ |---|---|
16
+ | One file | `notify.ts` |
17
+ | A folder | The manifest, `src/`, `migrations/`, and the built `dist/`. Not `ui/`: it is the source of `dist/` |
18
+ | Dependencies | A `node_modules` beside the plugin, if it imports anything but the SDK, `zod` and `drizzle-orm` |
19
+ | Settings | The names of the `.env` lines it reads, in its description |
20
+
21
+ Say what the plugin does with data. A plugin runs with the app’s full rights, and the person who
22
+ installs it trusts you with them.
23
+
24
+ ## As a package
25
+
26
+ Packages installed into a plugins folder count as plugins when they carry a manifest:
27
+
28
+ ```bash
29
+ cd ~/.engenty/wizards/plugins
30
+ npm install @acme/wizards-contacts
31
+ ```
32
+
33
+ The runtime finds `node_modules/@acme/wizards-contacts/engenty.plugin.json` at its next start,
34
+ or with “Look again” in Settings → Plugins. Put the manifest, the server half and the built
35
+ `dist/` into the package’s `files`.
36
+
37
+ ## Into a server
38
+
39
+ With Docker, mount a folder and name it:
40
+
41
+ ```yaml
42
+ services:
43
+ wizards:
44
+ environment:
45
+ PLUGINS_DIR: /plugins
46
+ volumes:
47
+ - ./plugins:/plugins
48
+ ```
49
+
50
+ Or copy the plugins into an image of your own, built on the runtime’s.
51
+
52
+ ## With engenty wizards itself
53
+
54
+ Plugins in the repository’s `modules/` folder ship with every runtime: in a checkout, in the
55
+ npm package and installed app, and in the Docker image. A module there is part of the open
56
+ product.
57
+
58
+ - Its server half imports only what the runtime hands every plugin, and its own files. It has no
59
+ `node_modules` of its own where it is installed.
60
+ - A module with a studio half is a workspace package whose `build` script is
61
+ `node ../../scripts/build-plugin.mjs .`, so the product’s build builds its `dist/`.
62
+ `apps/runtime/Dockerfile` copies each workspace package’s `package.json` before it installs:
63
+ add the module’s there.
64
+
65
+ A plugin that is not part of the open product stays out of `modules/` and goes into a folder of
66
+ `PLUGINS_DIR`.
67
+
68
+ ## Which tenant has a plugin
69
+
70
+ On an install of your own, on your computer or your own server, every tenant has every plugin
71
+ the runtime loaded. On engenty.ai the service installs the plugins and switches them on per
72
+ account. A person cannot install a plugin there.
73
+
74
+ ## Versions
75
+
76
+ - The settings show `version` from the manifest. The runtime doesn’t compare versions.
77
+ - A plugin’s `.sql` files only ever grow: an update adds files and never changes one that ran.
78
+ - A wizard that uses a plugin’s tool names it by its id. Renaming a tool or the plugin breaks
79
+ those wizards, so keep ids for good.
@@ -0,0 +1,297 @@
1
+ ---
2
+ title: The space
3
+ description: Knowledge a plugin writes, a block and tools for every AI step of a space, texts in its search index, tools and cards of its assistant.
4
+ version: 0.5.0
5
+ ---
6
+
7
+ A space holds what all its wizards share: a name, its brand (logos, colours, fonts), facts, and
8
+ Knowledge – pages, tables and files with their categories. A plugin can write Knowledge and add to
9
+ what the space’s AI steps know, to what its search finds and to what its assistant can do. The
10
+ runtime’s own tables call a space a project: `wizard.projectId` in a [run event](./events.md) is
11
+ a space’s id.
12
+
13
+ ## Knowledge a plugin writes
14
+
15
+ `server.spaceData` writes pages, tables and files into a space’s Knowledge under keys of the
16
+ plugin’s own, with their categories. Every write is indexed: `project_search` finds it a moment
17
+ later, filtered by its categories and checked like everything else in Knowledge. `space` is the
18
+ space’s id.
19
+
20
+ ```ts
21
+ // The source's categories, once. `proposed: true` shows them to the person to confirm first.
22
+ await server.spaceData.putCategories({
23
+ space,
24
+ categories: [
25
+ { name: "Team", type: "choice", hint: "folder name" },
26
+ { name: "Meeting date", type: "date" },
27
+ { name: "Duration", type: "number", unit: "h" },
28
+ ],
29
+ });
30
+
31
+ // Then an item per entry. The same key again rewrites it, never doubles it.
32
+ await server.spaceData.putPage({
33
+ space,
34
+ key: `${source.id}:2026-03-14`,
35
+ label: "Meeting notes",
36
+ title: "Weekly meeting, 14 March 2026",
37
+ markdown,
38
+ categories: { Team: "Sales", "Meeting date": "2026-03-14", Duration: 1.5 },
39
+ fill: true, // a model fills the categories the entry did not bring
40
+ });
41
+
42
+ // A file is read as an upload is: a page, sub-pages, a table per sheet, or a file.
43
+ const doc = await server.spaceData.putDocument({ space, key, label, name, mime, data, fill: true });
44
+ ```
45
+
46
+ | `server.spaceData.` | Does |
47
+ |---|---|
48
+ | `putCategories({ space, categories, proposed? })` | Adds categories, or values to known ones. Types: `choice` (with `values`, `multiple`, `ordered`), `date`, `number` (with `unit`), `text`, `boolean`. `column: { table, column }` takes a category’s values from a column of a table the plugin wrote |
49
+ | `putPage(input)` | A page: `title`, `markdown`, `parent` (the key of a page to stand under), `original` (the file it was read from), `categories`, `fill`, `review` (why a person should look) |
50
+ | `putTable(input)` | A table: typed `columns`, `rows` (cells by column id, they replace the rows the key had), `format: "faq"` |
51
+ | `putFile(input)` | A file that is not a page. It is found by its name, `description` and categories; `text` is what a step reads of it |
52
+ | `putDocument(input)` | A file, read the way an upload is. Returns what it became: `items` (pages, tables), and `review` when it was hard to read or could not be read |
53
+ | `readPages(space, { parent? })` | The space’s own pages, whoever wrote them, with their Markdown: `{ id, title, path, parentId, markdown, origin, originKey, updatedAt }` |
54
+ | `files(space, kind?)`, `readFile(space, id)` | The space’s files of a kind (`document`, `logo`, `asset`, `pattern`; `document` when none is named), newest first, and one file with its bytes, such as a price list someone dropped into Knowledge |
55
+ | `list(space)` | Everything the plugin wrote, by key, with its path and `state` |
56
+ | `remove(space, key?)` | Takes out one key, or everything the plugin wrote in the space. Returns how many items it removed |
57
+ | `summarize(space, category?, value?)` | Writes the “Overview” of one value, or of every value with three items or more. Each costs a model call. Returns how many it wrote |
58
+
59
+ - `label` is what the person knows the source as. Knowledge shows it beside the item.
60
+ - When a person changes an item, it is theirs: the plugin’s next write returns `state: "kept"`
61
+ and changes nothing, and `remove` leaves it.
62
+ - What a step reads of an item is its path: `pages/…`, `tables/…`, `files/…`.
63
+
64
+ ## A block for every AI step
65
+
66
+ ```ts
67
+ server.registerSpaceContext({
68
+ block: async (space) => {
69
+ const titles = await pageTitles(space.id);
70
+ return titles.length
71
+ ? `# THE SPACE'S WIKI\nPages, read one with wiki_page: ${titles.join(" · ")}`
72
+ : null;
73
+ },
74
+ tools: [
75
+ {
76
+ name: "page",
77
+ description: "Reads a page of the space's wiki by its title.",
78
+ inputSchema: z.object({ title: z.string() }),
79
+ execute: async ({ title }, step) => pageOf(step.space.id, title),
80
+ },
81
+ ],
82
+ });
83
+ ```
84
+
85
+ - Every agent step of the space’s wizards gets the block in its instructions, after what the
86
+ space says about itself and its documents, and gets the tools with it. No step lists them.
87
+ - `block` is called once per step. If it returns `null` or an empty text, the step gets neither
88
+ the block nor the tools.
89
+ - A block is cut at 8,000 characters. A block that throws is logged, and the step runs without
90
+ it.
91
+ - The tools are [tools](./tools.md) like the ones a step lists; the model sees
92
+ `<plugin>_<name>`. Their names and the names of the plugin’s other tools are one list.
93
+ - A model on the device calls no tools. That is Apple Intelligence on a Mac, or on the phone a
94
+ run is followed on, which answers only steps that list no tools themselves. Such a step gets
95
+ the block without the tools.
96
+ - `steps` says which steps get the block: `["agent"]` when left out. `"html"` stands for the
97
+ steps that write a document or a dashboard as HTML. They get the block without the tools,
98
+ after the space’s brand – a good place to say how the brand’s elements look.
99
+
100
+ ## The space’s brand
101
+
102
+ `server.spaces.brand(space)` reads what Info & brand holds of the space’s look, for a block, a
103
+ page or a model call in it:
104
+
105
+ ```ts
106
+ const brand = await server.spaces.brand(space.id);
107
+ // { name: "Mira Kaffee", colors: [{ name: "Primary", value: "#7a3e1d" }, …],
108
+ // fonts: [{ family: "Fraunces", role: "Headings", weights: [600] }, …] }
109
+ ```
110
+
111
+ - The first colour is the accent. A font’s `role` is what it is for, in the person’s words.
112
+ - It returns `null` for a space the tenant does not have. The studio half gets the same from
113
+ `studio.useSpace().brand`.
114
+
115
+ ## The search index
116
+
117
+ Every agent step can search the space with `project_search`. It finds Knowledge, written by
118
+ people and by `server.spaceData`, and the texts plugins put in themselves, outside Knowledge:
119
+
120
+ ```ts
121
+ await server.index.put({
122
+ space: space.id,
123
+ key: `page:${page.id}`,
124
+ title: page.title,
125
+ text: page.markdown,
126
+ link: "/space/knowledge#wiki",
127
+ });
128
+
129
+ await server.index.remove(space.id, `page:${page.id}`);
130
+ await server.index.remove(space.id); // every text of the plugin in the space
131
+ ```
132
+
133
+ - Putting a key again replaces what it held.
134
+ - A text is cut into passages. Its title is searched with it, and a hit is named by it. The test
135
+ search under Knowledge (“Try a search…”) shows hits as a step gets them.
136
+ - The index searches by words and by trigrams (codes, parts of compounds). With an embedding
137
+ model set up, it also searches by meaning. A classifier then judges each candidate.
138
+ - Such a text has no categories, so a search with a filter leaves it out. Write Knowledge with
139
+ `server.spaceData` when it should be filtered.
140
+ - A step gets `project_search` as soon as the space has Knowledge or a plugin’s text.
141
+ - A tenant without the plugin does not find its texts. They are deleted with the space.
142
+
143
+ ## Tools of the space assistant
144
+
145
+ The studio’s assistant, Goose, stands on every page of the studio except the editor. Where a
146
+ space is open and the person may change it, the assistant fills the space in from what the person
147
+ says, a website or files. A plugin gives it tools:
148
+
149
+ > Goose is still being tried out and doesn’t show in every studio yet. Where it doesn’t, nobody
150
+ > sees the tools, cards and page hooks below.
151
+
152
+ ```ts
153
+ server.registerAssistantTool({
154
+ name: "draft_page",
155
+ description: "Drafts a page of the space's wiki on a topic the person names.",
156
+ inputSchema: z.object({ topic: z.string() }),
157
+ card: true,
158
+ execute: async ({ topic }, turn) => {
159
+ turn.emit("Writing the draft …");
160
+ const draft = await draftPage(turn.space.id, topic, turn.signal);
161
+ return { title: draft.title, words: draft.words };
162
+ },
163
+ });
164
+ ```
165
+
166
+ | `turn.` | |
167
+ |---|---|
168
+ | `space` | `{ id, name }`: the space the person is filling in |
169
+ | `tenantId`, `userId` | The tenant and the person |
170
+ | `signal` | Aborted when the person leaves or stops the answer |
171
+ | `emit(message)` | The line the chat shows while the assistant works |
172
+ | `changed()` | The tool changed what the space page shows: the page draws it again |
173
+
174
+ - The model sees the tool as `<plugin>_<name>`, beside the assistant’s own tools.
175
+ - The assistant doesn’t keep a tool’s result from one message to the next. Keep what a later
176
+ message needs in the plugin’s tables.
177
+
178
+ ### A card in the chat
179
+
180
+ With `card: true` the result also goes to the chat. The studio half draws it:
181
+
182
+ ```tsx
183
+ studio.registerAssistantCard({
184
+ tool: "draft_page",
185
+ component: ({ data, send }) => (
186
+ <Card className="flex items-center gap-3 p-4">
187
+ <span className="flex-1 text-[0.875rem]">
188
+ {data.title}: {data.words} words
189
+ </span>
190
+ <Button size="sm" onClick={() => send("Publish it")}>
191
+ Publish it
192
+ </Button>
193
+ </Card>
194
+ ),
195
+ });
196
+ ```
197
+
198
+ - `tool` is the name the server half registered, without the plugin’s prefix.
199
+ - The card stands below the assistant’s answer. Without a card for the tool, nothing shows.
200
+ - `data` is what `execute` returned, sent as it is: keep it small.
201
+ - `send(message)` sends a message to the assistant as if the person typed it.
202
+
203
+ ## Events of a space
204
+
205
+ `space.created`, `space.updated`, `space.deleted`, `space.file.ready` and `space.file.removed`
206
+ say what changed. See [Events](./events.md).
207
+
208
+ ## The assistant on the plugin’s own page
209
+
210
+ The assistant stands on the plugin’s pages too, as on every page of the studio. A page tells it
211
+ what to say there, and what it shows; the assistant is told what the page holds and uses the
212
+ plugin’s assistant tools first.
213
+
214
+ ```tsx
215
+ const Assistant = studio.Assistant;
216
+
217
+ <Assistant
218
+ title="Ask about your contacts"
219
+ hello="I find people who ran a wizard and tidy the list."
220
+ placeholder="e.g. “Who ran the quote wizard last week?” …"
221
+ suggestions={[
222
+ { label: "Who came back more than once?" },
223
+ { label: "Remove the contacts of …", fill: true },
224
+ ]}
225
+ onChanged={() => queryClient.invalidateQueries({ queryKey: ["contacts"] })}
226
+ />
227
+ ```
228
+
229
+ ```ts
230
+ server.registerAssistantContext({
231
+ block: async (space) => `THE CONTACTS ON THIS PAGE: ${await contactsText(space.id)} …`,
232
+ });
233
+ ```
234
+
235
+ - `studio.Assistant` draws nothing: place it once, anywhere in the page. `title` and `hello`
236
+ greet the person before the first message, and up to three `suggestions` stand under them. A
237
+ click sends a suggestion at once (its `message`, or the label). With `fill: true` it goes into
238
+ the field instead, for the person to finish.
239
+ - `block` is called once per message, and only when the person writes from the plugin’s page. A
240
+ block is cut at 8,000 characters. One that throws is logged and left out.
241
+ - Where the person may not change the space, the assistant gets neither the space’s tools nor
242
+ the plugins’. That is a space published from engenty wizards on a computer, or a person who
243
+ may not build here.
244
+
245
+ ### What the page shows
246
+
247
+ `studio.useAssistantPage` tells the assistant what the person sees: an open item, a selection,
248
+ a line on what the page holds, its fields. It is sent with every message, beside the page’s
249
+ address and the trail of the top bar.
250
+
251
+ ```tsx
252
+ studio.useAssistantPage({
253
+ open: person ? { kind: "contact", id: String(person.id), label: person.email } : undefined,
254
+ selection: picked.map(String),
255
+ summary: `${contacts.length} contacts · ${withoutName} without a name`,
256
+ // A page of full-height tables keeps the assistant small, at the lower right.
257
+ compact: true,
258
+ });
259
+ ```
260
+
261
+ - `open` is `{ kind, id?, label }`, `selection` holds the ids of what the person picked, and
262
+ `fields` is `{ id, label, value }[]`.
263
+ - It takes the words of `studio.Assistant` too (`title`, `hello`, `placeholder`, `suggestions`,
264
+ `onChanged`): one call can do both.
265
+ - The data may change on every render; it is read when the person sends.
266
+
267
+ ### Tools in the page
268
+
269
+ `studio.useAssistantTool` gives the assistant a tool that runs in the browser while the page is
270
+ shown: it filters a list, opens an item, picks a tab. The model sees it as `<plugin>_<name>`
271
+ (a `-` in the plugin’s id becomes `_`). `run` gets the arguments and returns what the assistant
272
+ learns. Such a tool changes what the page shows and never saves: saving stays with the server
273
+ half’s tools.
274
+
275
+ ```tsx
276
+ studio.useAssistantTool(
277
+ "filter_contacts",
278
+ {
279
+ description: "Shows only the contacts that match: of a wizard, by words.",
280
+ parameters: {
281
+ type: "object",
282
+ properties: {
283
+ wizard: { type: "string" },
284
+ query: { type: "string" },
285
+ },
286
+ },
287
+ },
288
+ ({ wizard, query }) => {
289
+ setFilter({ wizard: wizard as string | undefined, query: query as string | undefined });
290
+ return { shown: count };
291
+ },
292
+ );
293
+ ```
294
+
295
+ Besides a page’s tools, the assistant can open a studio page, point at an element, read what is
296
+ on the screen, fill a field and scroll. It finds elements by their headings, labels and
297
+ buttons. `data-assist="<id>"` on an element names it for the assistant.