wizards 0.1.9

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 (308) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +170 -0
  3. package/apps/runtime/dist/agents/architect.js +453 -0
  4. package/apps/runtime/dist/agents/project-assistant.js +354 -0
  5. package/apps/runtime/dist/agents/subscription.js +206 -0
  6. package/apps/runtime/dist/agents/thought.js +21 -0
  7. package/apps/runtime/dist/agents/website.js +197 -0
  8. package/apps/runtime/dist/app.js +153 -0
  9. package/apps/runtime/dist/auth/account.js +121 -0
  10. package/apps/runtime/dist/auth/index.js +329 -0
  11. package/apps/runtime/dist/auth/keys.js +55 -0
  12. package/apps/runtime/dist/auth/local-ticket.js +23 -0
  13. package/apps/runtime/dist/authoring/example.js +73 -0
  14. package/apps/runtime/dist/authoring/guide.js +259 -0
  15. package/apps/runtime/dist/authoring/ops.js +117 -0
  16. package/apps/runtime/dist/cli/autostart.js +134 -0
  17. package/apps/runtime/dist/cli/clients.js +44 -0
  18. package/apps/runtime/dist/cli/environment.js +81 -0
  19. package/apps/runtime/dist/cli/exec.js +45 -0
  20. package/apps/runtime/dist/cli/home.js +74 -0
  21. package/apps/runtime/dist/cli/machine.js +145 -0
  22. package/apps/runtime/dist/cli/main.js +125 -0
  23. package/apps/runtime/dist/cli/setup.js +273 -0
  24. package/apps/runtime/dist/cli/start.js +190 -0
  25. package/apps/runtime/dist/cli/status.js +120 -0
  26. package/apps/runtime/dist/cli/ui.js +12 -0
  27. package/apps/runtime/dist/cli/update.js +58 -0
  28. package/apps/runtime/dist/connectors/builtin.js +70 -0
  29. package/apps/runtime/dist/connectors/external.js +400 -0
  30. package/apps/runtime/dist/connectors/gmail.js +107 -0
  31. package/apps/runtime/dist/connectors/imap.js +217 -0
  32. package/apps/runtime/dist/connectors/index.js +266 -0
  33. package/apps/runtime/dist/connectors/mail.js +72 -0
  34. package/apps/runtime/dist/connectors/outlook.js +90 -0
  35. package/apps/runtime/dist/credits/credits.js +103 -0
  36. package/apps/runtime/dist/credits/estimate.js +132 -0
  37. package/apps/runtime/dist/db/adopt.js +149 -0
  38. package/apps/runtime/dist/db/client.js +146 -0
  39. package/apps/runtime/dist/db/control-schema.js +70 -0
  40. package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
  41. package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
  42. package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
  43. package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
  44. package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
  45. package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
  46. package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
  47. package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
  48. package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
  49. package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
  50. package/apps/runtime/dist/db/migrations/control/meta/_journal.json +41 -0
  51. package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
  52. package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
  53. package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
  54. package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
  55. package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
  56. package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
  57. package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
  58. package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
  59. package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
  60. package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
  61. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +41 -0
  62. package/apps/runtime/dist/db/schema.js +278 -0
  63. package/apps/runtime/dist/documents/parse.js +230 -0
  64. package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
  65. package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
  66. package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
  67. package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
  68. package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
  69. package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
  70. package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
  71. package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
  72. package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
  73. package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
  74. package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
  75. package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
  76. package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
  77. package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
  78. package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
  79. package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +359 -0
  80. package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
  81. package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
  82. package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
  83. package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
  84. package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
  85. package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
  86. package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
  87. package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
  88. package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
  89. package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +464 -0
  90. package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
  91. package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
  92. package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
  93. package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
  94. package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
  95. package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
  96. package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
  97. package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
  98. package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
  99. package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
  100. package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
  101. package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
  102. package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
  103. package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
  104. package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
  105. package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
  106. package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
  107. package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
  108. package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
  109. package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
  110. package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
  111. package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
  112. package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
  113. package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
  114. package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
  115. package/apps/runtime/dist/engenty/shims/web-ingest.js +3 -0
  116. package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
  117. package/apps/runtime/dist/engine/asks.js +60 -0
  118. package/apps/runtime/dist/engine/events.js +46 -0
  119. package/apps/runtime/dist/engine/input.js +170 -0
  120. package/apps/runtime/dist/engine/prepare.js +51 -0
  121. package/apps/runtime/dist/engine/requirements.js +124 -0
  122. package/apps/runtime/dist/engine/resources.js +89 -0
  123. package/apps/runtime/dist/engine/runner.js +560 -0
  124. package/apps/runtime/dist/engine/steps.js +598 -0
  125. package/apps/runtime/dist/engine/template.js +183 -0
  126. package/apps/runtime/dist/engine/types.js +3 -0
  127. package/apps/runtime/dist/env.js +224 -0
  128. package/apps/runtime/dist/files/blobs.js +22 -0
  129. package/apps/runtime/dist/files/objects.js +86 -0
  130. package/apps/runtime/dist/files/storage.js +95 -0
  131. package/apps/runtime/dist/geocode.js +58 -0
  132. package/apps/runtime/dist/harness/claude.js +138 -0
  133. package/apps/runtime/dist/harness/codex.js +228 -0
  134. package/apps/runtime/dist/harness/cursor.js +93 -0
  135. package/apps/runtime/dist/harness/env.js +124 -0
  136. package/apps/runtime/dist/harness/gemini.js +126 -0
  137. package/apps/runtime/dist/harness/index.js +99 -0
  138. package/apps/runtime/dist/harness/model.js +267 -0
  139. package/apps/runtime/dist/harness/prompt.js +121 -0
  140. package/apps/runtime/dist/harness/terminal.js +193 -0
  141. package/apps/runtime/dist/harness/types.js +7 -0
  142. package/apps/runtime/dist/index.js +76 -0
  143. package/apps/runtime/dist/limits.js +57 -0
  144. package/apps/runtime/dist/link-preview.js +59 -0
  145. package/apps/runtime/dist/manage.js +151 -0
  146. package/apps/runtime/dist/mcp/auth.js +102 -0
  147. package/apps/runtime/dist/mcp/bridge.js +59 -0
  148. package/apps/runtime/dist/mcp/handler.js +42 -0
  149. package/apps/runtime/dist/mcp/scopes.js +5 -0
  150. package/apps/runtime/dist/mcp/tools.js +401 -0
  151. package/apps/runtime/dist/media/ffmpeg.js +121 -0
  152. package/apps/runtime/dist/media/generate.js +120 -0
  153. package/apps/runtime/dist/media/marking.js +121 -0
  154. package/apps/runtime/dist/media/transcribe.js +30 -0
  155. package/apps/runtime/dist/model-errors.js +3 -0
  156. package/apps/runtime/dist/models.js +489 -0
  157. package/apps/runtime/dist/plugin.js +61 -0
  158. package/apps/runtime/dist/render/chromium.js +85 -0
  159. package/apps/runtime/dist/render/convert.js +161 -0
  160. package/apps/runtime/dist/render/downloads.js +277 -0
  161. package/apps/runtime/dist/render/guard.js +25 -0
  162. package/apps/runtime/dist/routes/api.js +74 -0
  163. package/apps/runtime/dist/routes/delivery.js +52 -0
  164. package/apps/runtime/dist/routes/internal.js +49 -0
  165. package/apps/runtime/dist/routes/marketplace.js +36 -0
  166. package/apps/runtime/dist/routes/runs.js +805 -0
  167. package/apps/runtime/dist/routes/studio.js +702 -0
  168. package/apps/runtime/dist/routes/wizard-stream.js +30 -0
  169. package/apps/runtime/dist/running.js +39 -0
  170. package/apps/runtime/dist/sandbox/agentos.js +191 -0
  171. package/apps/runtime/dist/sandbox/docker.js +77 -0
  172. package/apps/runtime/dist/sandbox/index.js +30 -0
  173. package/apps/runtime/dist/sandbox/types.js +1 -0
  174. package/apps/runtime/dist/secrets/crypto.js +28 -0
  175. package/apps/runtime/dist/secrets/signing.js +34 -0
  176. package/apps/runtime/dist/secrets/vault.js +59 -0
  177. package/apps/runtime/dist/services/architect.js +92 -0
  178. package/apps/runtime/dist/services/brand.js +20 -0
  179. package/apps/runtime/dist/services/cloud.js +52 -0
  180. package/apps/runtime/dist/services/draft-events.js +27 -0
  181. package/apps/runtime/dist/services/errors.js +24 -0
  182. package/apps/runtime/dist/services/files.js +129 -0
  183. package/apps/runtime/dist/services/links.js +16 -0
  184. package/apps/runtime/dist/services/marketplace.js +292 -0
  185. package/apps/runtime/dist/services/package.js +202 -0
  186. package/apps/runtime/dist/services/profile.js +23 -0
  187. package/apps/runtime/dist/services/project-files.js +266 -0
  188. package/apps/runtime/dist/services/project-index.js +109 -0
  189. package/apps/runtime/dist/services/projects.js +181 -0
  190. package/apps/runtime/dist/services/runs.js +224 -0
  191. package/apps/runtime/dist/services/shares.js +129 -0
  192. package/apps/runtime/dist/services/widgets.js +34 -0
  193. package/apps/runtime/dist/services/wizards.js +342 -0
  194. package/apps/runtime/dist/settings.js +16 -0
  195. package/apps/runtime/dist/store/index.js +279 -0
  196. package/apps/runtime/dist/tenants/control.js +106 -0
  197. package/apps/runtime/dist/tenants/tenant.js +26 -0
  198. package/apps/runtime/dist/tools/browser.js +380 -0
  199. package/apps/runtime/dist/tools/connector.js +204 -0
  200. package/apps/runtime/dist/tools/index.js +234 -0
  201. package/apps/runtime/dist/tools/mail.js +104 -0
  202. package/apps/runtime/dist/tools/net-guard.js +59 -0
  203. package/apps/runtime/dist/tools/project.js +53 -0
  204. package/apps/runtime/dist/tools/shared.js +42 -0
  205. package/apps/runtime/dist/tools/store.js +238 -0
  206. package/apps/runtime/dist/update.js +118 -0
  207. package/apps/runtime/dist/widgets/bundle.js +99 -0
  208. package/apps/runtime/dist/widgets/render.js +312 -0
  209. package/apps/runtime/dist/widgets/runtime.js +84 -0
  210. package/apps/runtime/dist/widgets/script.js +30 -0
  211. package/apps/runtime/dist/widgets/step.js +192 -0
  212. package/apps/web/dist/ai-labels/ai-black.svg +20 -0
  213. package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
  214. package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
  215. package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
  216. package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
  217. package/apps/web/dist/ai-labels/ai-white.svg +21 -0
  218. package/apps/web/dist/assets/ChangelogDialog-O00vEnbm.js +1 -0
  219. package/apps/web/dist/assets/ChatPanel-CH9ry0Hp.js +1 -0
  220. package/apps/web/dist/assets/CreditsDialog-DRzecwUw.js +1 -0
  221. package/apps/web/dist/assets/EditorPage-BRnBf02Q.js +2 -0
  222. package/apps/web/dist/assets/FlowPreview-DDOj8IAH.js +1 -0
  223. package/apps/web/dist/assets/HomePage-CAGTTG3N.js +1 -0
  224. package/apps/web/dist/assets/ImportWizard-0RRrAnX3.js +1 -0
  225. package/apps/web/dist/assets/LocalRuntime-BrP-ENHg.css +1 -0
  226. package/apps/web/dist/assets/LocalRuntime-C-TBYrzs.js +16 -0
  227. package/apps/web/dist/assets/NewWizardPage-kI90h3_9.js +2 -0
  228. package/apps/web/dist/assets/PublicRunner-CKRDeIVd.js +1 -0
  229. package/apps/web/dist/assets/RunnerView-Rc4H8wYH.js +2 -0
  230. package/apps/web/dist/assets/SettingsPage-CESMuZxq.js +2 -0
  231. package/apps/web/dist/assets/SetupPage-D1rrYU14.js +1 -0
  232. package/apps/web/dist/assets/SharePage-COTAmOgh.js +1 -0
  233. package/apps/web/dist/assets/api-BY28cjGY.js +10 -0
  234. package/apps/web/dist/assets/arrow-left-UpjOBfQp.js +1 -0
  235. package/apps/web/dist/assets/arrow-right-CucQycEy.js +1 -0
  236. package/apps/web/dist/assets/changelog-p3wsaDDS.js +1 -0
  237. package/apps/web/dist/assets/check-Bjx41xbB.js +1 -0
  238. package/apps/web/dist/assets/createLucideIcon-DBu2Ovxj.js +1 -0
  239. package/apps/web/dist/assets/definition-cy7uvY5L.js +55 -0
  240. package/apps/web/dist/assets/engenty-CWIFpgKq.js +1 -0
  241. package/apps/web/dist/assets/esm-D1OEhjTK.js +7 -0
  242. package/apps/web/dist/assets/external-link-CRg6DVdO.js +1 -0
  243. package/apps/web/dist/assets/fluffy-engenty-CJ3wCQgT.js +456 -0
  244. package/apps/web/dist/assets/index-CQ_q9iMO.css +1 -0
  245. package/apps/web/dist/assets/index-D0gxh90t.js +10 -0
  246. package/apps/web/dist/assets/jsx-runtime-Dk72oS4N.js +1 -0
  247. package/apps/web/dist/assets/meta-BbSdtTUa.js +1 -0
  248. package/apps/web/dist/assets/mic-CeqQ89Dj.js +1 -0
  249. package/apps/web/dist/assets/oss-credits-cPuZUFHD.js +1 -0
  250. package/apps/web/dist/assets/outputs-D6pxH6ve.js +69 -0
  251. package/apps/web/dist/assets/plus-HA210wXA.js +1 -0
  252. package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
  253. package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
  254. package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
  255. package/apps/web/dist/assets/type-BzYgVWKL.js +1 -0
  256. package/apps/web/dist/assets/ui-Ddwl35A6.js +1 -0
  257. package/apps/web/dist/assets/upload-DsgLfQ3U.js +1 -0
  258. package/apps/web/dist/assets/video-Dk1fuTDl.js +1 -0
  259. package/apps/web/dist/assets/wand-sparkles-Bf97fs8T.js +1 -0
  260. package/apps/web/dist/embed.js +102 -0
  261. package/apps/web/dist/favicon.svg +1 -0
  262. package/apps/web/dist/icons/apple-touch-icon.png +0 -0
  263. package/apps/web/dist/icons/icon-192.png +0 -0
  264. package/apps/web/dist/icons/icon-512.png +0 -0
  265. package/apps/web/dist/icons/icon-maskable-512.png +0 -0
  266. package/apps/web/dist/index.html +46 -0
  267. package/apps/web/dist/install.sh +532 -0
  268. package/apps/web/dist/manifest.webmanifest +20 -0
  269. package/apps/web/dist/sw.js +15 -0
  270. package/bin/wizards.mjs +13 -0
  271. package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
  272. package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
  273. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +1415 -0
  274. package/node_modules/@engenty-wizards/shared/dist/definition.js +762 -0
  275. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
  276. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
  277. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
  278. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
  279. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
  280. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +216 -0
  281. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
  282. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
  283. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
  284. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
  285. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
  286. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
  287. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
  288. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +86 -0
  289. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
  290. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +133 -0
  291. package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +298 -0
  292. package/node_modules/@engenty-wizards/shared/dist/marketplace.js +211 -0
  293. package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
  294. package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
  295. package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +74 -0
  296. package/node_modules/@engenty-wizards/shared/dist/projects.js +96 -0
  297. package/node_modules/@engenty-wizards/shared/dist/run.d.ts +219 -0
  298. package/node_modules/@engenty-wizards/shared/dist/run.js +1 -0
  299. package/node_modules/@engenty-wizards/shared/dist/store.d.ts +100 -0
  300. package/node_modules/@engenty-wizards/shared/dist/store.js +44 -0
  301. package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
  302. package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
  303. package/node_modules/@engenty-wizards/shared/package.json +10 -0
  304. package/package.json +62 -0
  305. package/plugin/.claude-plugin/plugin.json +9 -0
  306. package/plugin/.mcp.json +8 -0
  307. package/plugin/commands/wizard.md +8 -0
  308. package/plugin/skills/build-wizard/SKILL.md +27 -0
@@ -0,0 +1,181 @@
1
+ import { FACT_TYPES, PROJECT_LIMITS } from "@engenty-wizards/shared/projects";
2
+ import { and, count, eq } from "drizzle-orm";
3
+ import { nanoid } from "nanoid";
4
+ import { z } from "zod";
5
+ import { db, schema } from "../db/client.js";
6
+ import { env } from "../env.js";
7
+ import { managed, tenantInfo } from "../manage.js";
8
+ import { currentTenant } from "../tenants/tenant.js";
9
+ import { notFound, ServiceError } from "./errors.js";
10
+ import { forgetWizardLinks } from "./links.js";
11
+ import { removeProjectFiles } from "./project-files.js";
12
+ const MASK = "••••";
13
+ export const mcpServerSchema = z.object({
14
+ id: z.string().regex(/^[a-z][a-z0-9_]{0,30}$/),
15
+ name: z.string().min(1).max(60),
16
+ url: z.string().url(),
17
+ headers: z.record(z.string(), z.string()).optional(),
18
+ });
19
+ export const brandColorSchema = z.object({
20
+ name: z.string().max(120),
21
+ value: z.string().regex(/^#[0-9a-fA-F]{6}$/),
22
+ });
23
+ export const projectFactSchema = z.object({
24
+ key: z.string().regex(/^[a-z0-9_]{1,40}$/),
25
+ label: z.string().min(1).max(80),
26
+ value: z.string().max(4000),
27
+ type: z.enum(FACT_TYPES).optional(),
28
+ });
29
+ export const projectPatchSchema = z.object({
30
+ name: z.string().min(1).max(80).optional(),
31
+ brand: z
32
+ .object({
33
+ name: z.string().max(120).optional(),
34
+ about: z.string().max(8000).optional(),
35
+ colors: z.array(brandColorSchema).max(PROJECT_LIMITS.colors).optional(),
36
+ })
37
+ .optional(),
38
+ facts: z.array(projectFactSchema).max(PROJECT_LIMITS.facts).optional(),
39
+ mcpServers: z.array(mcpServerSchema).max(10).optional(),
40
+ });
41
+ /**
42
+ * How many projects the tenant works with: the number the Manage-App gives for it, else this
43
+ * runtime's (`LIMIT_PROJECTS`, one unless set). The studio shows a project switcher only above
44
+ * one. Projects beyond the number stay in the database and are not listed.
45
+ */
46
+ export async function projectLimit() {
47
+ if (managed) {
48
+ const info = await tenantInfo(currentTenant()).catch(() => null);
49
+ if (info?.limits.projects) {
50
+ return info.limits.projects;
51
+ }
52
+ }
53
+ return Math.max(1, env.limits.projects);
54
+ }
55
+ export async function ownedProject(_userId, projectId) {
56
+ const p = await db.query.project.findFirst({
57
+ where: and(eq(schema.project.id, projectId), eq(schema.project.tenantId, currentTenant())),
58
+ });
59
+ if (!p) {
60
+ throw notFound();
61
+ }
62
+ return p;
63
+ }
64
+ /** A tenant always has a project: the first one is made when its studio is first opened. */
65
+ async function ensureProject() {
66
+ const any = await db.query.project.findFirst({
67
+ where: eq(schema.project.tenantId, currentTenant()),
68
+ });
69
+ if (!any) {
70
+ await db
71
+ .insert(schema.project)
72
+ .values({ id: nanoid(12), tenantId: currentTenant(), name: "Meine Wizards" });
73
+ }
74
+ }
75
+ /** The project a wizard lands in when the caller names none: the oldest one. */
76
+ export async function defaultProject(_userId) {
77
+ await ensureProject();
78
+ const p = await db.query.project.findFirst({
79
+ where: eq(schema.project.tenantId, currentTenant()),
80
+ orderBy: [schema.project.createdAt],
81
+ });
82
+ if (!p) {
83
+ throw notFound();
84
+ }
85
+ return p;
86
+ }
87
+ export async function listProjects(_userId) {
88
+ await ensureProject();
89
+ // The oldest come first: with a limit of one, that is the project everything lands in.
90
+ const projects = await db.query.project.findMany({
91
+ where: eq(schema.project.tenantId, currentTenant()),
92
+ orderBy: [schema.project.createdAt],
93
+ limit: await projectLimit(),
94
+ });
95
+ const counts = await db
96
+ .select({ projectId: schema.wizard.projectId, n: count() })
97
+ .from(schema.wizard)
98
+ .where(eq(schema.wizard.tenantId, currentTenant()))
99
+ .groupBy(schema.wizard.projectId);
100
+ return projects.map((p) => ({
101
+ ...p,
102
+ wizardCount: counts.find((x) => x.projectId === p.id)?.n ?? 0,
103
+ }));
104
+ }
105
+ /** MCP server headers carry the admin's credentials: shown masked, kept when sent back masked. */
106
+ export function maskedServers(p) {
107
+ return p.mcpServers.map((s) => ({
108
+ ...s,
109
+ headers: s.headers
110
+ ? Object.fromEntries(Object.keys(s.headers).map((k) => [k, MASK]))
111
+ : undefined,
112
+ }));
113
+ }
114
+ export async function createProject(_userId, name) {
115
+ const [{ n }] = await db
116
+ .select({ n: count() })
117
+ .from(schema.project)
118
+ .where(eq(schema.project.tenantId, currentTenant()));
119
+ const limit = await projectLimit();
120
+ if (n >= limit) {
121
+ throw new ServiceError("refused", limit === 1 ? "Hier gibt es ein Projekt." : `Höchstens ${limit} Projekte.`);
122
+ }
123
+ const id = nanoid(12);
124
+ await db
125
+ .insert(schema.project)
126
+ .values({ id, tenantId: currentTenant(), name, brand: {}, mcpServers: [] });
127
+ return { id };
128
+ }
129
+ export async function updateProject(userId, projectId, patch) {
130
+ const p = await ownedProject(userId, projectId);
131
+ const mcpServers = patch.mcpServers?.map((s) => {
132
+ const before = p.mcpServers.find((x) => x.id === s.id);
133
+ const headers = s.headers
134
+ ? Object.fromEntries(Object.entries(s.headers).map(([k, v]) => [
135
+ k,
136
+ v === MASK ? (before?.headers?.[k] ?? "") : v,
137
+ ]))
138
+ : undefined;
139
+ return { ...s, headers };
140
+ });
141
+ if (patch.facts && new Set(patch.facts.map((f) => f.key)).size !== patch.facts.length) {
142
+ throw new ServiceError("invalid", "Zwei Einträge haben denselben Schlüssel.");
143
+ }
144
+ await db
145
+ .update(schema.project)
146
+ .set({
147
+ ...(patch.name ? { name: patch.name } : {}),
148
+ ...(patch.brand ? { brand: { ...p.brand, ...patch.brand } } : {}),
149
+ ...(patch.facts ? { facts: patch.facts } : {}),
150
+ ...(mcpServers ? { mcpServers } : {}),
151
+ updatedAt: new Date(),
152
+ })
153
+ .where(eq(schema.project.id, p.id));
154
+ }
155
+ export function projectProfile(p) {
156
+ return {
157
+ name: p.brand.name ?? "",
158
+ about: p.brand.about ?? "",
159
+ colors: p.brand.colors ?? [],
160
+ facts: p.facts.filter((f) => f.value.trim()),
161
+ };
162
+ }
163
+ export async function deleteProject(_userId, projectId) {
164
+ const all = await db.query.project.findMany({
165
+ where: eq(schema.project.tenantId, currentTenant()),
166
+ });
167
+ if (all.length <= 1) {
168
+ throw new ServiceError("refused", "Das letzte Projekt bleibt.");
169
+ }
170
+ const wizards = await db
171
+ .select({ id: schema.wizard.id })
172
+ .from(schema.wizard)
173
+ .where(eq(schema.wizard.projectId, projectId));
174
+ for (const w of wizards) {
175
+ await forgetWizardLinks(w.id);
176
+ }
177
+ await removeProjectFiles(projectId);
178
+ await db
179
+ .delete(schema.project)
180
+ .where(and(eq(schema.project.id, projectId), eq(schema.project.tenantId, currentTenant())));
181
+ }
@@ -0,0 +1,224 @@
1
+ import { formatsFor } from "@engenty-wizards/shared/definition";
2
+ import { and, count, desc, eq, inArray } from "drizzle-orm";
3
+ import { canSpend, MICROS_PER_CREDIT } from "../credits/credits.js";
4
+ import { db, schema } from "../db/client.js";
5
+ import { unattended } from "../engine/asks.js";
6
+ import { emitEvent, recentEvents, subscribe } from "../engine/events.js";
7
+ import { createRun, RunInputError, reviewStep, submitPage } from "../engine/runner.js";
8
+ import { ModelUnavailableError } from "../model-errors.js";
9
+ import { signedUrl } from "../secrets/signing.js";
10
+ import { currentTenant } from "../tenants/tenant.js";
11
+ import { notFound, ServiceError } from "./errors.js";
12
+ import { ownedWizard, requireClean, studioUrl } from "./wizards.js";
13
+ /** Test runs an MCP client started with answers: pages are filled and reviews accepted for it. */
14
+ const autopilots = new Set();
15
+ export async function startTestRun(userId, wizardId, autopilot) {
16
+ const w = await ownedWizard(userId, wizardId);
17
+ const { definition, files } = await requireClean(w);
18
+ if (!(await canSpend())) {
19
+ throw new ServiceError("no_credits", "Dein Guthaben ist aufgebraucht.");
20
+ }
21
+ const runId = await createRun({
22
+ wizardId: w.id,
23
+ definition,
24
+ files,
25
+ version: null,
26
+ mode: "test",
27
+ userId,
28
+ }).catch((err) => {
29
+ throw err instanceof ModelUnavailableError ? new ServiceError("refused", err.message) : err;
30
+ });
31
+ if (autopilot) {
32
+ fly(runId, autopilot.answers, autopilot.acceptReviews);
33
+ }
34
+ return { runId };
35
+ }
36
+ function fly(runId, answers, acceptReviews) {
37
+ autopilots.add(runId);
38
+ unattended.add(runId);
39
+ let busy = false;
40
+ let again = false;
41
+ const land = () => {
42
+ autopilots.delete(runId);
43
+ unattended.delete(runId);
44
+ unsubscribe();
45
+ clearTimeout(timeout);
46
+ };
47
+ const step = async () => {
48
+ if (busy) {
49
+ again = true;
50
+ return;
51
+ }
52
+ busy = true;
53
+ try {
54
+ do {
55
+ again = false;
56
+ const run = await db.query.run.findFirst({ where: eq(schema.run.id, runId) });
57
+ if (!run ||
58
+ run.status === "done" ||
59
+ run.status === "failed" ||
60
+ run.status === "cancelled") {
61
+ land();
62
+ return;
63
+ }
64
+ if (run.status !== "waiting_input") {
65
+ continue;
66
+ }
67
+ const current = run.definition.steps.find((s) => s.id === run.cursor);
68
+ if (current?.type === "page") {
69
+ const values = Object.fromEntries(current.fields.filter((f) => f.id in answers).map((f) => [f.id, answers[f.id]]));
70
+ await submitPage(runId, current.id, values);
71
+ }
72
+ else if (current?.type === "review" && acceptReviews) {
73
+ await reviewStep(runId, current.id, { type: "accept" });
74
+ }
75
+ else {
76
+ land();
77
+ return;
78
+ }
79
+ } while (again);
80
+ }
81
+ catch (err) {
82
+ const message = err instanceof RunInputError
83
+ ? `Antworten fehlen oder passen nicht: ${err.errors.map((e) => `${e.field} – ${e.message}`).join("; ")}`
84
+ : err.message;
85
+ await emitEvent(runId, null, "error", message).catch(() => undefined);
86
+ land();
87
+ }
88
+ finally {
89
+ busy = false;
90
+ }
91
+ };
92
+ const unsubscribe = subscribe(runId, () => {
93
+ void step();
94
+ });
95
+ const timeout = setTimeout(land, 30 * 60_000);
96
+ void step();
97
+ }
98
+ async function ownedTestRun(_userId, runId) {
99
+ const run = await db.query.run.findFirst({
100
+ where: and(eq(schema.run.id, runId), eq(schema.run.tenantId, currentTenant()), eq(schema.run.mode, "test")),
101
+ });
102
+ if (!run) {
103
+ throw notFound();
104
+ }
105
+ return run;
106
+ }
107
+ /** Still moving: running, or waiting on a page the autopilot is about to fill. */
108
+ function moving(run) {
109
+ return run.status === "running" || (run.status === "waiting_input" && autopilots.has(run.id));
110
+ }
111
+ async function waitWhileMoving(userId, runId, seconds) {
112
+ const deadline = Date.now() + seconds * 1000;
113
+ let run = await ownedTestRun(userId, runId);
114
+ while (moving(run) && Date.now() < deadline) {
115
+ await new Promise((resolve) => {
116
+ const unsubscribe = subscribe(runId, () => {
117
+ unsubscribe();
118
+ clearTimeout(timer);
119
+ resolve();
120
+ });
121
+ const timer = setTimeout(() => {
122
+ unsubscribe();
123
+ resolve();
124
+ }, deadline - Date.now());
125
+ });
126
+ run = await ownedTestRun(userId, runId);
127
+ }
128
+ return run;
129
+ }
130
+ function clip(text, max) {
131
+ return text.length > max
132
+ ? `${text.slice(0, max)} … [${text.length - max} more characters]`
133
+ : text;
134
+ }
135
+ function deliverableFormats(run, step) {
136
+ const possible = formatsFor(step);
137
+ const listed = run.definition.steps
138
+ .flatMap((s) => (s.type === "result" ? s.deliverables : []))
139
+ .find((d) => d.from === step.id);
140
+ return listed ? listed.formats.filter((f) => possible.includes(f)) : [];
141
+ }
142
+ /** What a test run did so far, for a client without the studio: outputs, links, cost, errors. */
143
+ export async function testRunReport(userId, runId, waitSeconds = 0) {
144
+ const run = await waitWhileMoving(userId, runId, waitSeconds);
145
+ const current = run.definition.steps.find((s) => s.id === run.cursor) ?? null;
146
+ const base = `/api/runs/${run.id}`;
147
+ const outputs = run.definition.steps.flatMap((step) => {
148
+ const output = run.state.outputs[step.id];
149
+ if (!output) {
150
+ return [];
151
+ }
152
+ return [
153
+ {
154
+ stepId: step.id,
155
+ title: step.title,
156
+ text: output.text ? clip(output.text, 1500) : undefined,
157
+ json: output.json === undefined ? undefined : clip(JSON.stringify(output.json), 1500),
158
+ assets: (output.assets ?? []).map((a) => ({
159
+ name: a.name,
160
+ mime: a.mime,
161
+ url: signedUrl(`${base}/assets/${a.id}`),
162
+ })),
163
+ downloads: Object.fromEntries(deliverableFormats(run, step).map((f) => [
164
+ f,
165
+ signedUrl(`${base}/steps/${step.id}/download?format=${f}`),
166
+ ])),
167
+ },
168
+ ];
169
+ });
170
+ const waitingFor = run.status === "waiting_input" && current?.type === "page"
171
+ ? {
172
+ page: current.id,
173
+ fields: current.fields.map((f) => ({
174
+ id: f.id,
175
+ label: f.label,
176
+ kind: f.kind,
177
+ required: Boolean(f.required),
178
+ options: f.options,
179
+ })),
180
+ }
181
+ : run.status === "waiting_input" && current?.type === "review"
182
+ ? { review: current.id, hint: "Accept or regenerate in the studio." }
183
+ : undefined;
184
+ return {
185
+ runId: run.id,
186
+ status: moving(run) ? "running" : run.status,
187
+ step: current ? { id: current.id, type: current.type, title: current.title } : null,
188
+ waitingFor,
189
+ error: run.error,
190
+ credits: Math.ceil(run.costMicros / MICROS_PER_CREDIT),
191
+ events: (await recentEvents(run.id, 0, 15)).map((e) => ({
192
+ step: e.stepId,
193
+ type: e.type,
194
+ message: e.message,
195
+ })),
196
+ outputs,
197
+ studioUrl: studioUrl(run.wizardId),
198
+ };
199
+ }
200
+ export async function listRuns(userId, wizardId) {
201
+ const w = await ownedWizard(userId, wizardId);
202
+ const rows = await db.query.run.findMany({
203
+ where: eq(schema.run.wizardId, w.id),
204
+ orderBy: [desc(schema.run.createdAt)],
205
+ limit: 100,
206
+ });
207
+ const assetCounts = rows.length
208
+ ? await db
209
+ .select({ runId: schema.asset.runId, n: count() })
210
+ .from(schema.asset)
211
+ .where(inArray(schema.asset.runId, rows.map((r) => r.id)))
212
+ .groupBy(schema.asset.runId)
213
+ : [];
214
+ return rows.map((r) => ({
215
+ id: r.id,
216
+ mode: r.mode,
217
+ status: r.status,
218
+ version: r.version,
219
+ createdAt: r.createdAt.toISOString(),
220
+ credits: Math.ceil(r.costMicros / MICROS_PER_CREDIT),
221
+ assets: assetCounts.find((a) => a.runId === r.id)?.n ?? 0,
222
+ stepTitle: r.definition.steps.find((s) => s.id === r.cursor)?.title ?? null,
223
+ }));
224
+ }
@@ -0,0 +1,129 @@
1
+ import { and, eq, isNotNull, lt } from "drizzle-orm";
2
+ import { nanoid } from "nanoid";
3
+ import { db, schema } from "../db/client.js";
4
+ import { availableFormats } from "../engine/runner.js";
5
+ import { env } from "../env.js";
6
+ import { inlineAssetRefs, loadAsset, loadAssetText, removeAssetFiles, saveAsset, } from "../files/storage.js";
7
+ import { htmlToPng } from "../render/convert.js";
8
+ import { dropLinks, dropRuns, putLink } from "../tenants/control.js";
9
+ import { brandView } from "./brand.js";
10
+ import { ServiceError } from "./errors.js";
11
+ export const shareUrlFor = (token) => `${env.appUrl}/s/${token}`;
12
+ /** Shares a finished run. Idempotent: the same run keeps the same link. */
13
+ export async function shareRun(run) {
14
+ if (run.status !== "done") {
15
+ throw new ServiceError("refused", "Nur fertige Ergebnisse lassen sich teilen.");
16
+ }
17
+ let token = run.shareToken;
18
+ if (!token) {
19
+ token = nanoid(16);
20
+ await db
21
+ .update(schema.run)
22
+ .set({ shareToken: token, sharedAt: new Date() })
23
+ .where(eq(schema.run.id, run.id));
24
+ await putLink(token, "result", run.id);
25
+ }
26
+ return { url: shareUrlFor(token), expiresAt: run.expiresAt?.toISOString() ?? null };
27
+ }
28
+ export async function unshareRun(run) {
29
+ if (run.shareToken) {
30
+ await dropLinks([run.shareToken]);
31
+ }
32
+ await db
33
+ .update(schema.run)
34
+ .set({ shareToken: null, sharedAt: null })
35
+ .where(eq(schema.run.id, run.id));
36
+ }
37
+ /** The shared run behind a token, unless the link was withdrawn or the run expired. */
38
+ export async function sharedRun(token) {
39
+ const run = await db.query.run.findFirst({ where: eq(schema.run.shareToken, token) });
40
+ if (run?.status !== "done" || (run.expiresAt && run.expiresAt < new Date())) {
41
+ return null;
42
+ }
43
+ return run;
44
+ }
45
+ export async function shareView(run) {
46
+ const def = run.definition;
47
+ const result = def.steps.find((s) => s.id === run.cursor && s.type === "result") ??
48
+ def.steps.findLast((s) => s.type === "result");
49
+ const deliverables = result?.type === "result" ? result.deliverables : [];
50
+ const shown = await Promise.all(deliverables.flatMap((d) => {
51
+ const step = def.steps.find((s) => s.id === d.from);
52
+ const output = run.state.outputs[d.from];
53
+ return step && output
54
+ ? [
55
+ (async () => ({
56
+ step,
57
+ output,
58
+ formats: await availableFormats(step, run, d.formats),
59
+ label: d.label ?? null,
60
+ }))(),
61
+ ]
62
+ : [];
63
+ }));
64
+ const w = await db.query.wizard.findFirst({ where: eq(schema.wizard.id, run.wizardId) });
65
+ return {
66
+ token: run.shareToken ?? "",
67
+ title: result?.title ?? def.title,
68
+ message: result?.type === "result" ? (result.message ?? null) : null,
69
+ wizard: { title: def.title, description: def.description, avatar: def.avatar },
70
+ brand: await brandView(w?.projectId ?? ""),
71
+ shown,
72
+ createdAt: run.createdAt.toISOString(),
73
+ expiresAt: run.expiresAt?.toISOString() ?? null,
74
+ wizardUrl: w?.shareEnabled && w.publishedVersion !== null ? `${env.appUrl}/w/${w.shareToken}` : null,
75
+ };
76
+ }
77
+ /**
78
+ * The picture link previews (X, LinkedIn, WhatsApp, Slack) show: the first image of the result,
79
+ * a widget's poster, or a document's first screen. Rendered once and kept.
80
+ */
81
+ export async function shareImage(run) {
82
+ const view = await shareView(run);
83
+ for (const { output } of view.shown) {
84
+ const assets = output?.assets ?? [];
85
+ const image = assets.find((a) => a.mime.startsWith("image/"));
86
+ if (image) {
87
+ const found = await loadAsset(image.id);
88
+ if (found) {
89
+ return { data: new Uint8Array(found.data), mime: found.row.mime };
90
+ }
91
+ }
92
+ const html = assets.find((a) => a.mime === "text/html");
93
+ if (html) {
94
+ const name = `${html.id}.og.png`;
95
+ const hit = await db.query.asset.findFirst({
96
+ where: and(eq(schema.asset.kind, "render"), eq(schema.asset.name, name)),
97
+ });
98
+ const cached = hit ? await loadAsset(hit.id) : null;
99
+ if (cached) {
100
+ return { data: new Uint8Array(cached.data), mime: "image/png" };
101
+ }
102
+ const page = await inlineAssetRefs(await loadAssetText(html.id));
103
+ const png = await htmlToPng(page, 1200, { height: 630, fullPage: false, scale: 1 });
104
+ await saveAsset({
105
+ runId: run.id,
106
+ kind: "render",
107
+ mime: "image/png",
108
+ name,
109
+ data: png,
110
+ });
111
+ return { data: png, mime: "image/png" };
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+ /** Deletes runs past their expiry with everything they made. Runs hourly. */
117
+ export async function purgeExpiredRuns() {
118
+ const expired = await db
119
+ .select({ id: schema.run.id, shareToken: schema.run.shareToken })
120
+ .from(schema.run)
121
+ .where(and(isNotNull(schema.run.expiresAt), lt(schema.run.expiresAt, new Date())));
122
+ for (const { id } of expired) {
123
+ await removeAssetFiles(id);
124
+ await db.delete(schema.run).where(eq(schema.run.id, id));
125
+ }
126
+ await dropLinks(expired.map((r) => r.shareToken).filter((t) => Boolean(t)));
127
+ await dropRuns(expired.map((r) => r.id));
128
+ return expired.length;
129
+ }
@@ -0,0 +1,34 @@
1
+ import { widgetSize } from "@engenty-wizards/shared/definition";
2
+ import { probeWidget } from "../widgets/render.js";
3
+ import { widgetPreviewHtml } from "../widgets/step.js";
4
+ import { notFound, ServiceError } from "./errors.js";
5
+ import { draftFiles } from "./files.js";
6
+ import { ownedProject } from "./projects.js";
7
+ import { ownedWizard } from "./wizards.js";
8
+ async function draftWidget(userId, wizardId, stepId) {
9
+ const w = await ownedWizard(userId, wizardId);
10
+ const step = w.draft.steps.find((s) => s.id === stepId);
11
+ if (!step) {
12
+ throw notFound();
13
+ }
14
+ if (step.type !== "widget") {
15
+ throw new ServiceError("invalid", `Step "${stepId}" is not a widget.`);
16
+ }
17
+ const files = await draftFiles(w.id);
18
+ if (!files.some((f) => f.path === step.entry)) {
19
+ throw new ServiceError("invalid", `The widget file ${step.entry} is not in the workspace yet.`);
20
+ }
21
+ return { step, files, project: await ownedProject(userId, w.projectId) };
22
+ }
23
+ /** The draft widget with its sample data, as one HTML file — the studio shows it before any run. */
24
+ export async function draftWidgetPreview(userId, wizardId, stepId, data) {
25
+ const { step, files, project } = await draftWidget(userId, wizardId, stepId);
26
+ return widgetPreviewHtml(step, files, project, data);
27
+ }
28
+ /** Loads the draft widget in Chromium: what broke, whether it animates, and how it looks. */
29
+ export async function checkDraftWidget(userId, wizardId, stepId, data) {
30
+ const { step, files, project } = await draftWidget(userId, wizardId, stepId);
31
+ const html = await widgetPreviewHtml(step, files, project, data);
32
+ const probe = await probeWidget(html, widgetSize(step));
33
+ return { ...probe, size: widgetSize(step), bytes: Buffer.byteLength(html) };
34
+ }