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,27 @@
1
+ import { EventEmitter } from "node:events";
2
+ const bus = new EventEmitter();
3
+ bus.setMaxListeners(0);
4
+ export function emitDraftChanged(change) {
5
+ bus.emit(change.wizardId, change);
6
+ }
7
+ export function subscribeDraft(wizardId, listener) {
8
+ bus.on(wizardId, listener);
9
+ return () => bus.off(wizardId, listener);
10
+ }
11
+ /** Steps that are new or differ in `after`. */
12
+ export function changedSteps(before, after) {
13
+ const old = new Map(before.steps.map((s) => [s.id, JSON.stringify(s)]));
14
+ return after.steps.filter((s) => old.get(s.id) !== JSON.stringify(s)).map((s) => s.id);
15
+ }
16
+ /** A workspace file was written or removed. Files carry no revision; the draft's is passed along. */
17
+ export function filesChanged(w, path) {
18
+ return {
19
+ wizardId: w.id,
20
+ kind: "files",
21
+ revision: w.revision,
22
+ source: "studio",
23
+ client: null,
24
+ note: null,
25
+ touched: [path],
26
+ };
27
+ }
@@ -0,0 +1,24 @@
1
+ const STATUS = {
2
+ not_found: 404,
3
+ invalid: 400,
4
+ has_issues: 400,
5
+ revision_conflict: 409,
6
+ no_credits: 402,
7
+ refused: 400,
8
+ };
9
+ export class ServiceError extends Error {
10
+ code;
11
+ data;
12
+ constructor(code, message, data = {}) {
13
+ super(message);
14
+ this.code = code;
15
+ this.data = data;
16
+ }
17
+ get status() {
18
+ return STATUS[this.code];
19
+ }
20
+ toJSON() {
21
+ return { error: this.message, code: this.code, ...this.data };
22
+ }
23
+ }
24
+ export const notFound = () => new ServiceError("not_found", "not found");
@@ -0,0 +1,129 @@
1
+ import { cleanPath, isTextMime, mimeForPath, WORKSPACE_LIMITS, } from "@engenty-wizards/shared/workspace";
2
+ import { and, asc, eq } from "drizzle-orm";
3
+ import { db, schema } from "../db/client.js";
4
+ import { getBlob, putBlob } from "../files/blobs.js";
5
+ import { emitDraftChanged, filesChanged } from "./draft-events.js";
6
+ import { notFound, ServiceError } from "./errors.js";
7
+ import { ownedWizard } from "./wizards.js";
8
+ /** The draft's workspace, sorted by path — the same shape publishing and runs snapshot. */
9
+ export async function draftFiles(wizardId) {
10
+ const rows = await db.query.wizardFile.findMany({
11
+ where: eq(schema.wizardFile.wizardId, wizardId),
12
+ orderBy: [asc(schema.wizardFile.path)],
13
+ });
14
+ return rows.map(({ path, hash, mime, size }) => ({ path, hash, mime, size }));
15
+ }
16
+ export async function listFiles(userId, wizardId) {
17
+ const w = await ownedWizard(userId, wizardId);
18
+ return draftFiles(w.id);
19
+ }
20
+ function requirePath(raw) {
21
+ const path = cleanPath(raw);
22
+ if (!path) {
23
+ throw new ServiceError("invalid", `"${raw}" is not a valid file path (letters, digits, - _ . and /, no "..").`);
24
+ }
25
+ return path;
26
+ }
27
+ export async function readFile(userId, wizardId, rawPath) {
28
+ const w = await ownedWizard(userId, wizardId);
29
+ const path = requirePath(rawPath);
30
+ const row = await db.query.wizardFile.findFirst({
31
+ where: and(eq(schema.wizardFile.wizardId, w.id), eq(schema.wizardFile.path, path)),
32
+ });
33
+ if (!row) {
34
+ throw notFound();
35
+ }
36
+ return { file: row, data: await getBlob(row.hash) };
37
+ }
38
+ /** Reads a file as text for a model; binary files are described, not dumped. */
39
+ export async function readFileText(userId, wizardId, rawPath) {
40
+ const { file, data } = await readFile(userId, wizardId, rawPath);
41
+ if (!isTextMime(file.mime)) {
42
+ return { path: file.path, mime: file.mime, size: file.size, text: null };
43
+ }
44
+ return { path: file.path, mime: file.mime, size: file.size, text: data.toString("utf8") };
45
+ }
46
+ export async function writeFile(userId, wizardId, rawPath, content, mime) {
47
+ const w = await ownedWizard(userId, wizardId);
48
+ const path = requirePath(rawPath);
49
+ const data = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
50
+ if (data.byteLength > WORKSPACE_LIMITS.fileBytes) {
51
+ throw new ServiceError("invalid", `${path} is larger than 5 MB.`);
52
+ }
53
+ const files = await draftFiles(w.id);
54
+ const others = files.filter((f) => f.path !== path);
55
+ if (others.length >= WORKSPACE_LIMITS.files) {
56
+ throw new ServiceError("invalid", "The workspace already holds 200 files.");
57
+ }
58
+ if (others.reduce((n, f) => n + f.size, 0) + data.byteLength > WORKSPACE_LIMITS.totalBytes) {
59
+ throw new ServiceError("invalid", "The workspace would be larger than 25 MB.");
60
+ }
61
+ const hash = await putBlob(data);
62
+ const file = {
63
+ path,
64
+ hash,
65
+ mime: mime && mime !== "application/octet-stream" ? mime : mimeForPath(path),
66
+ size: data.byteLength,
67
+ };
68
+ await db
69
+ .insert(schema.wizardFile)
70
+ .values({ wizardId: w.id, ...file })
71
+ .onConflictDoUpdate({
72
+ target: [schema.wizardFile.wizardId, schema.wizardFile.path],
73
+ set: { hash: file.hash, mime: file.mime, size: file.size, updatedAt: new Date() },
74
+ });
75
+ await touch(w.id);
76
+ emitDraftChanged(filesChanged(w, path));
77
+ return file;
78
+ }
79
+ export async function deleteFile(userId, wizardId, rawPath) {
80
+ const w = await ownedWizard(userId, wizardId);
81
+ const path = requirePath(rawPath);
82
+ const gone = await db
83
+ .delete(schema.wizardFile)
84
+ .where(and(eq(schema.wizardFile.wizardId, w.id), eq(schema.wizardFile.path, path)))
85
+ .returning({ path: schema.wizardFile.path });
86
+ if (!gone.length) {
87
+ throw notFound();
88
+ }
89
+ await touch(w.id);
90
+ emitDraftChanged(filesChanged(w, path));
91
+ }
92
+ /** Copies a workspace onto another wizard (duplicate). Blobs are shared, only rows are new. */
93
+ export async function copyFiles(fromWizardId, toWizardId) {
94
+ const files = await draftFiles(fromWizardId);
95
+ if (files.length) {
96
+ await db.insert(schema.wizardFile).values(files.map((f) => ({ wizardId: toWizardId, ...f })));
97
+ }
98
+ }
99
+ /** The files a new wizard starts with (a starter's widget, price list, reference text). */
100
+ export async function seedFiles(wizardId, files) {
101
+ const rows = [];
102
+ for (const [path, content] of Object.entries(files)) {
103
+ const data = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
104
+ rows.push({
105
+ wizardId,
106
+ path: requirePath(path),
107
+ hash: await putBlob(data),
108
+ mime: mimeForPath(path),
109
+ size: data.byteLength,
110
+ });
111
+ }
112
+ if (rows.length) {
113
+ await db.insert(schema.wizardFile).values(rows);
114
+ }
115
+ }
116
+ async function touch(wizardId) {
117
+ await db
118
+ .update(schema.wizard)
119
+ .set({ updatedAt: new Date() })
120
+ .where(eq(schema.wizard.id, wizardId));
121
+ }
122
+ /** The content of one file of a snapshot (a run's or a version's), by path. */
123
+ export async function snapshotFile(files, path) {
124
+ const file = files.find((f) => f.path === path);
125
+ return file ? { file, data: await getBlob(file.hash) } : null;
126
+ }
127
+ export function sameFiles(a, b) {
128
+ return a.length === b.length && a.every((f, i) => f.path === b[i].path && f.hash === b[i].hash);
129
+ }
@@ -0,0 +1,16 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { db, schema } from "../db/client.js";
3
+ import { dropLinks, dropRuns } from "../tenants/control.js";
4
+ /** Takes a wizard's public tokens and its runs out of the control database. */
5
+ export async function forgetWizardLinks(wizardId) {
6
+ const w = await db.query.wizard.findFirst({ where: eq(schema.wizard.id, wizardId) });
7
+ const runs = await db
8
+ .select({ id: schema.run.id, shareToken: schema.run.shareToken })
9
+ .from(schema.run)
10
+ .where(eq(schema.run.wizardId, wizardId));
11
+ await dropLinks([
12
+ ...(w ? [w.shareToken] : []),
13
+ ...runs.map((r) => r.shareToken).filter((t) => Boolean(t)),
14
+ ]);
15
+ await dropRuns(runs.map((r) => r.id));
16
+ }
@@ -0,0 +1,292 @@
1
+ import { DEFINITION_VERSION, readable, wizardSchema, } from "@engenty-wizards/shared/definition";
2
+ import { MARKETPLACE_LANGS, } from "@engenty-wizards/shared/marketplace";
3
+ import { wizardOutline } from "@engenty-wizards/shared/marketplace-entry";
4
+ import { searchEntries } from "@engenty-wizards/shared/marketplace-search";
5
+ import { and, eq, inArray, notInArray } from "drizzle-orm";
6
+ import { formulaEstimate } from "../credits/estimate.js";
7
+ import { control, controlDb, db, schema, withTenant } from "../db/client.js";
8
+ import { missingCapabilities } from "../engine/requirements.js";
9
+ import { env } from "../env.js";
10
+ import { managed } from "../manage.js";
11
+ import { classCatalog, imageCostUsd, tokenCostUsd, videoCostUsd, WEB_SEARCH_COST_USD, } from "../models.js";
12
+ import { readSetting, writeSetting } from "../settings.js";
13
+ import { LOCAL_TENANT } from "../tenants/tenant.js";
14
+ import { ServiceError } from "./errors.js";
15
+ /**
16
+ * The marketplace is an app of its own; this runtime is one of its clients
17
+ * (docs/marketplace-contract.md). It searches the marketplace live and starts wizards from its
18
+ * entries. Its starters and what people starred are kept in the control database, so the list
19
+ * and starting a wizard work without a connection too.
20
+ */
21
+ export const asLang = (raw) => MARKETPLACE_LANGS.includes(raw ?? "") ? raw : "de";
22
+ /** A search waits this long for the marketplace; then it searches what is kept here. */
23
+ const TIMEOUT_MS = 5000;
24
+ /** One call to the marketplace's API; null without an answer, or with an error. */
25
+ async function call(path, init) {
26
+ if (!env.marketplace.url) {
27
+ return null;
28
+ }
29
+ try {
30
+ const res = await fetch(`${env.marketplace.url}/api/v1${path}`, {
31
+ ...init,
32
+ signal: AbortSignal.timeout(TIMEOUT_MS),
33
+ });
34
+ if (!res.ok) {
35
+ return null;
36
+ }
37
+ return res.status === 204 ? {} : (await res.json());
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ // --- stars: a person's own, in the tenant's database ------------------------------------
44
+ async function starredIds() {
45
+ const rows = await db
46
+ .select({ id: schema.marketplaceStar.entryId })
47
+ .from(schema.marketplaceStar)
48
+ .orderBy(schema.marketplaceStar.createdAt);
49
+ return rows.map((r) => r.id);
50
+ }
51
+ /** Stars an entry or takes the star away; a starred entry is kept for offline use. */
52
+ export async function starEntry(tenantId, entryId, on) {
53
+ if (on) {
54
+ await db.insert(schema.marketplaceStar).values({ tenantId, entryId }).onConflictDoNothing();
55
+ }
56
+ else {
57
+ await db
58
+ .delete(schema.marketplaceStar)
59
+ .where(and(eq(schema.marketplaceStar.tenantId, tenantId), eq(schema.marketplaceStar.entryId, entryId)));
60
+ }
61
+ // What is kept follows at once, beside the request.
62
+ void syncMarketplace(true).catch(() => undefined);
63
+ }
64
+ // --- what is kept for offline use --------------------------------------------------------
65
+ async function kept(ids) {
66
+ const rows = await controlDb
67
+ .select({ entry: control.marketplaceCache.entry })
68
+ .from(control.marketplaceCache)
69
+ .where(ids ? inArray(control.marketplaceCache.id, ids) : undefined);
70
+ return rows.map((r) => r.entry);
71
+ }
72
+ /** The words of a kept entry in a language: a translation where it has one, else its own. */
73
+ function textIn(e, lang) {
74
+ return e.texts.find((t) => t.language === lang) ?? e.texts.find((t) => t.language === e.language);
75
+ }
76
+ function keptSummary(e, lang) {
77
+ const { texts: _texts, files: _files, ...summary } = e;
78
+ const text = textIn(e, lang);
79
+ return text
80
+ ? { ...summary, language: text.language, title: text.title, pitch: text.pitch }
81
+ : summary;
82
+ }
83
+ function keptItem(e, lang) {
84
+ const text = textIn(e, lang);
85
+ return text ? { ...keptSummary(e, lang), definition: text.definition, files: e.files } : null;
86
+ }
87
+ // --- searching -----------------------------------------------------------------------------
88
+ /** A summary as this app shows it: whether it can read and run it, and whether it is starred. */
89
+ function asEntry(summary, starred, unavailable) {
90
+ return {
91
+ ...summary,
92
+ credits: null,
93
+ usable: summary.version <= DEFINITION_VERSION,
94
+ starred: starred.has(summary.id),
95
+ missing: summary.capabilities.filter((c) => unavailable.has(c)),
96
+ };
97
+ }
98
+ /** Searches the marketplace; without an answer, what is kept here, scored the same way. */
99
+ export async function searchMarketplace(search) {
100
+ const { q = "", lang, starred: onlyStarred, limit = 60, offset = 0, ...filters } = search;
101
+ const stars = await starredIds();
102
+ const starred = new Set(stars);
103
+ const unavailable = await missingCapabilities();
104
+ const params = new URLSearchParams({ lang, limit: String(limit), offset: String(offset) });
105
+ if (onlyStarred) {
106
+ params.set("ids", stars.join(","));
107
+ }
108
+ else {
109
+ if (q.trim()) {
110
+ params.set("q", q.trim());
111
+ }
112
+ for (const [key, value] of Object.entries(filters)) {
113
+ if (value) {
114
+ params.set(key, value);
115
+ }
116
+ }
117
+ }
118
+ const remote = onlyStarred && !stars.length
119
+ ? { entries: [], total: 0, all: 0, facets: { useCase: {}, industry: {}, format: {} } }
120
+ : await call(`/entries?${params}`);
121
+ if (remote) {
122
+ return {
123
+ ...remote,
124
+ entries: remote.entries.map((e) => asEntry(e, starred, unavailable)),
125
+ offline: false,
126
+ unavailable: [...unavailable],
127
+ };
128
+ }
129
+ const local = (await kept(onlyStarred ? stars : undefined)).map((e) => keptSummary(e, lang));
130
+ const page = onlyStarred
131
+ ? searchEntries(local, "", {}, { limit, offset })
132
+ : searchEntries(local, q, filters, { limit, offset });
133
+ return {
134
+ ...page,
135
+ entries: page.entries.map((e) => asEntry(e, starred, unavailable)),
136
+ offline: true,
137
+ unavailable: [...unavailable],
138
+ };
139
+ }
140
+ // --- one entry -----------------------------------------------------------------------------
141
+ /** An entry with its wizard: from the marketplace, else from what is kept here. */
142
+ async function fetchItem(id, lang) {
143
+ const remote = await call(`/entries/${encodeURIComponent(id)}?lang=${encodeURIComponent(lang)}`);
144
+ if (remote) {
145
+ return remote;
146
+ }
147
+ const [local] = await kept([id]);
148
+ return local ? keptItem(local, lang) : null;
149
+ }
150
+ const CREDITS_PER_USD = 100;
151
+ /**
152
+ * Prices for a runtime that has no gateway to ask: what the models each class is bound to by
153
+ * default cost at their list price, in credits. An estimate needs a number even where a run is
154
+ * paid for another way.
155
+ */
156
+ function listPrices() {
157
+ const text = (ref) => ({
158
+ model: ref,
159
+ kind: "text",
160
+ inputCreditsPerMTok: tokenCostUsd(ref, { inputTokens: 1e6 }) * CREDITS_PER_USD,
161
+ outputCreditsPerMTok: tokenCostUsd(ref, { outputTokens: 1e6 }) * CREDITS_PER_USD,
162
+ });
163
+ const m = env.models;
164
+ return {
165
+ markup: 1,
166
+ webSearchCredits: WEB_SEARCH_COST_USD * CREDITS_PER_USD,
167
+ classes: {
168
+ classifier: text(m.classifier),
169
+ standard: text(m.standard),
170
+ high: text(m.high),
171
+ highest: text(m.highest),
172
+ image: {
173
+ model: m.image,
174
+ kind: "image",
175
+ creditsPerImage: imageCostUsd(m.image) * CREDITS_PER_USD,
176
+ },
177
+ video: {
178
+ model: m.video,
179
+ kind: "video",
180
+ creditsPerSecond: videoCostUsd(m.video, 1) * CREDITS_PER_USD,
181
+ },
182
+ },
183
+ };
184
+ }
185
+ /** What a run costs: at the gateway's prices where there is one, else at list prices. */
186
+ async function priced(definition) {
187
+ const catalog = await classCatalog().catch(() => null);
188
+ const price = formulaEstimate(definition, catalog ?? listPrices());
189
+ return { credits: Math.round(price.credits), high: price.high };
190
+ }
191
+ /** An entry in a language with its wizard read against this app; null where there is none. */
192
+ export async function marketplaceDetail(id, lang) {
193
+ const found = await fetchItem(id, lang);
194
+ if (!found) {
195
+ return null;
196
+ }
197
+ const { definition, files, ...summary } = found;
198
+ const entry = asEntry(summary, new Set(await starredIds()), await missingCapabilities());
199
+ const parsed = readable(definition) ? wizardSchema.parse(definition) : null;
200
+ if (!parsed) {
201
+ return {
202
+ ...entry,
203
+ usable: false,
204
+ description: "",
205
+ outline: [],
206
+ results: [],
207
+ files: Object.keys(files),
208
+ };
209
+ }
210
+ return {
211
+ ...entry,
212
+ credits: await priced(parsed),
213
+ ...wizardOutline(parsed, Object.keys(files), lang),
214
+ };
215
+ }
216
+ /** An entry's wizard and workspace in a language: what a wizard is made from. */
217
+ export async function marketplaceWizard(id, lang) {
218
+ const found = await fetchItem(id, lang);
219
+ if (!found) {
220
+ return null;
221
+ }
222
+ if (!readable(found.definition)) {
223
+ throw new ServiceError("refused", "Diese Vorlage braucht eine neuere Version der App. Bitte aktualisiere die App.");
224
+ }
225
+ return {
226
+ id: found.id,
227
+ revision: found.revision,
228
+ title: found.title,
229
+ language: found.language,
230
+ definition: wizardSchema.parse(found.definition),
231
+ files: Object.fromEntries(Object.entries(found.files).map(([path, data]) => [path, Buffer.from(data, "base64")])),
232
+ };
233
+ }
234
+ /** Tells the marketplace a wizard was made from an entry. */
235
+ export async function countInstall(id) {
236
+ await call(`/entries/${encodeURIComponent(id)}/installs`, { method: "POST" });
237
+ }
238
+ // --- keeping the starters and the starred ones ----------------------------------------------
239
+ // Not the key the copying into the database used before: the first look after an update is
240
+ // not held back.
241
+ const SYNCED = "marketplace:kept";
242
+ const SYNC_EVERY_MS = 3600_000;
243
+ let syncing = null;
244
+ /** The stars that count for what is kept: a runtime that runs alone has one person's. */
245
+ async function keptStars() {
246
+ return managed ? [] : withTenant(LOCAL_TENANT, starredIds);
247
+ }
248
+ async function takeOver() {
249
+ const list = await call(`/sync?ids=${encodeURIComponent((await keptStars()).join(","))}`);
250
+ if (!list?.items) {
251
+ return;
252
+ }
253
+ const have = await controlDb
254
+ .select({ id: control.marketplaceCache.id, hash: control.marketplaceCache.hash })
255
+ .from(control.marketplaceCache);
256
+ for (const item of list.items) {
257
+ if (have.some((h) => h.id === item.id && h.hash === item.hash)) {
258
+ continue;
259
+ }
260
+ const entry = await call(`/entries/${encodeURIComponent(item.id)}/export`);
261
+ if (!entry) {
262
+ continue;
263
+ }
264
+ const values = { id: entry.id, hash: entry.hash, entry, fetchedAt: new Date() };
265
+ await controlDb
266
+ .insert(control.marketplaceCache)
267
+ .values(values)
268
+ .onConflictDoUpdate({ target: control.marketplaceCache.id, set: values });
269
+ }
270
+ // What the marketplace no longer lists here is not kept either.
271
+ await controlDb.delete(control.marketplaceCache).where(notInArray(control.marketplaceCache.id, list.items.map((i) => i.id)));
272
+ await writeSetting(SYNCED, Date.now());
273
+ }
274
+ /**
275
+ * Keeps the marketplace's starters and the starred entries, by hash: an entry is fetched again
276
+ * only when it changed. At most once an hour unless forced.
277
+ */
278
+ export async function syncMarketplace(force = false) {
279
+ if (!env.marketplace.url) {
280
+ return;
281
+ }
282
+ const last = await readSetting(SYNCED);
283
+ if (!force && last && Date.now() - last < SYNC_EVERY_MS) {
284
+ return;
285
+ }
286
+ syncing ??= takeOver()
287
+ .catch((err) => console.error("[marketplace]", err.message))
288
+ .finally(() => {
289
+ syncing = null;
290
+ });
291
+ await syncing;
292
+ }