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,133 @@
1
+ import { scoreCatalogEntry, tokenizeCatalogText, } from "./engenty/search-index/catalog-lexical.js";
2
+ import { CAPABILITIES, INDUSTRIES, ITEM_FORMATS, USE_CASES, } from "./marketplace.js";
3
+ /**
4
+ * Searching the marketplace by words: BM25 with prefixes and inflections, the scoring engenty's
5
+ * catalogs use. The marketplace answers every search with it; an app that cannot reach the
6
+ * marketplace searches what it keeps the same way.
7
+ */
8
+ const WEIGHTS = [
9
+ ["title", 10],
10
+ ["summary", 6],
11
+ ["category", 5],
12
+ ["tags", 3],
13
+ ];
14
+ /** One search term of an entry, scored on its own. */
15
+ const TERM_WEIGHT = [["term", 7]];
16
+ /**
17
+ * Words a sentence is full of and no entry is found by — in the form the search reads words in,
18
+ * so "für" is left out as "fur".
19
+ */
20
+ const STOP = new Set(tokenizeCatalogText(`aber als also am an auch auf aus bei bin bitte brauche brauchen braucht das dass dem den der
21
+ des die dies diese dieser doch du ein eine einem einen einer eines er es etwas fuer für gerne
22
+ habe haben hat ich ihr im in ist kann können koennen mache machen mag mein meine meinem meinen
23
+ meiner mich mir mit möchte moechte nach nicht noch nur oder sich sie sind soll suche suchen
24
+ sucht um und uns unser unsere vom von vor was wie will wir wird wo wollen zu zum zur
25
+ a about an and are as at be can do for from have how i in is it like looking me my need of on
26
+ or our that the this to want we what which who with would you your`));
27
+ const fold = (text) => text.replace(/ß/g, "ss");
28
+ /** What a query is looked up by: its words, without the ones that say nothing. */
29
+ export function searchTerms(query) {
30
+ const words = tokenizeCatalogText(fold(query));
31
+ const kept = words.filter((w) => !STOP.has(w));
32
+ return kept.length ? kept : words;
33
+ }
34
+ /** From this many words on a query is a sentence: it shares some word with nearly every entry. */
35
+ export const SENTENCE_WORDS = 3;
36
+ /** Of a sentence's finds by words, those with at least this share of the best score are kept. */
37
+ const SENTENCE_SHARE = 0.4;
38
+ export const isSentence = (query) => query.trim().split(/\s+/).filter(Boolean).length >= SENTENCE_WORDS;
39
+ const labels = (all, ids) => ids.flatMap((id) => (all[id] ? [all[id].de, all[id].en] : []));
40
+ /** How well an entry answers the query by its words; 0 when it does not at all. */
41
+ export function scoreEntry(entry, query) {
42
+ const terms = searchTerms(query);
43
+ if (!terms.length) {
44
+ return 0;
45
+ }
46
+ const record = {
47
+ title: fold(entry.title),
48
+ summary: fold(entry.pitch),
49
+ category: labels(USE_CASES, entry.useCases),
50
+ tags: [
51
+ ...labels(INDUSTRIES, entry.industries),
52
+ ...labels(ITEM_FORMATS, entry.formats),
53
+ ...labels(CAPABILITIES, entry.capabilities),
54
+ ].map(fold),
55
+ };
56
+ let score = scoreCatalogEntry(record, terms.join(" "), WEIGHTS);
57
+ // An entry's own search terms: each word of the query counts once, by the term it fits best.
58
+ // Scored as one long text they would count for less the more of them an entry has.
59
+ const own = entry.terms.map((term) => ({ term: fold(term) }));
60
+ for (const word of terms) {
61
+ score += Math.max(0, ...own.map((t) => scoreCatalogEntry(t, word, TERM_WEIGHT)));
62
+ }
63
+ // German writes words together: "anzeige" is found inside "Videoanzeige" as well.
64
+ const text = tokenizeCatalogText(`${record.title} ${record.summary}`).join(" ");
65
+ const inside = terms.filter((term) => term.length >= 4 && text.includes(term)).length;
66
+ return score + inside * 2;
67
+ }
68
+ /** The entries a query finds by its words, best first. An empty query keeps the list as it is. */
69
+ export function rankEntries(entries, query) {
70
+ if (!query.trim()) {
71
+ return [...entries];
72
+ }
73
+ const rows = entries
74
+ .map((entry) => ({ entry, score: scoreEntry(entry, query) }))
75
+ .filter((row) => row.score > 0)
76
+ .sort((a, b) => b.score - a.score);
77
+ // A sentence shares some word with nearly every entry: only what comes close to the best counts.
78
+ const least = isSentence(query) ? (rows[0]?.score ?? 0) * SENTENCE_SHARE : 0;
79
+ return rows.filter((row) => row.score >= least).map((row) => row.entry);
80
+ }
81
+ /** Whether an entry passes the filters. An entry made for any industry passes every industry. */
82
+ export function matchesFilters(e, f) {
83
+ return ((!f.useCase || e.useCases.includes(f.useCase)) &&
84
+ (!f.industry ||
85
+ e.industries.includes(f.industry) ||
86
+ (f.industry !== "any" && e.industries.includes("any"))) &&
87
+ (!f.format || e.formats.includes(f.format)) &&
88
+ (!f.capability || e.capabilities.includes(f.capability)));
89
+ }
90
+ const FACETS = {
91
+ useCase: (e) => e.useCases,
92
+ industry: (e) => e.industries,
93
+ format: (e) => e.formats,
94
+ capability: (e) => e.capabilities,
95
+ };
96
+ /**
97
+ * Per option of each filter, the found entries it would leave with the other filters as they
98
+ * are. An option no entry has at all is left out.
99
+ */
100
+ function facetsOf(all, found, filters) {
101
+ const facets = {
102
+ useCase: {},
103
+ industry: {},
104
+ format: {},
105
+ capability: {},
106
+ };
107
+ for (const key of Object.keys(FACETS)) {
108
+ const options = new Set(all.flatMap(FACETS[key]));
109
+ const counts = facets[key];
110
+ for (const option of options) {
111
+ counts[option] = found.filter((e) => matchesFilters(e, {
112
+ ...filters,
113
+ [key]: option,
114
+ })).length;
115
+ }
116
+ }
117
+ return facets;
118
+ }
119
+ /**
120
+ * A search as the marketplace answers it: the entries the words find, best first (an empty
121
+ * query keeps the order given), narrowed by the filters, one page of them, and the counts.
122
+ */
123
+ export function searchEntries(entries, query, filters = {}, page = {}) {
124
+ const found = rankEntries(entries, query);
125
+ const shown = found.filter((e) => matchesFilters(e, filters));
126
+ const offset = Math.max(0, page.offset ?? 0);
127
+ return {
128
+ entries: shown.slice(offset, offset + Math.max(1, page.limit ?? 60)),
129
+ total: shown.length,
130
+ all: entries.length,
131
+ facets: facetsOf(entries, found, filters),
132
+ };
133
+ }
@@ -0,0 +1,298 @@
1
+ import type { WizardDefinition } from "./definition.js";
2
+ /**
3
+ * The marketplace: wizards anyone can start from. What an entry is sorted by — formats, industry,
4
+ * use case — and what follows from its definition: the AI capabilities it needs, how much a
5
+ * person has to fill in, and how expensive a run is.
6
+ */
7
+ export declare const MARKETPLACE_LANGS: readonly ["de", "en"];
8
+ export type MarketplaceLang = (typeof MARKETPLACE_LANGS)[number];
9
+ /** What comes out of a run. */
10
+ export declare const ITEM_FORMATS: {
11
+ text: {
12
+ de: string;
13
+ en: string;
14
+ };
15
+ document: {
16
+ de: string;
17
+ en: string;
18
+ };
19
+ table: {
20
+ de: string;
21
+ en: string;
22
+ };
23
+ image: {
24
+ de: string;
25
+ en: string;
26
+ };
27
+ video: {
28
+ de: string;
29
+ en: string;
30
+ };
31
+ audio: {
32
+ de: string;
33
+ en: string;
34
+ };
35
+ dashboard: {
36
+ de: string;
37
+ en: string;
38
+ };
39
+ };
40
+ export type ItemFormat = keyof typeof ITEM_FORMATS;
41
+ export declare const INDUSTRIES: {
42
+ any: {
43
+ de: string;
44
+ en: string;
45
+ };
46
+ trades: {
47
+ de: string;
48
+ en: string;
49
+ };
50
+ gastronomy: {
51
+ de: string;
52
+ en: string;
53
+ };
54
+ hospitality: {
55
+ de: string;
56
+ en: string;
57
+ };
58
+ realEstate: {
59
+ de: string;
60
+ en: string;
61
+ };
62
+ retail: {
63
+ de: string;
64
+ en: string;
65
+ };
66
+ health: {
67
+ de: string;
68
+ en: string;
69
+ };
70
+ professional: {
71
+ de: string;
72
+ en: string;
73
+ };
74
+ agency: {
75
+ de: string;
76
+ en: string;
77
+ };
78
+ events: {
79
+ de: string;
80
+ en: string;
81
+ };
82
+ publicSector: {
83
+ de: string;
84
+ en: string;
85
+ };
86
+ };
87
+ export type Industry = keyof typeof INDUSTRIES;
88
+ export declare const USE_CASES: {
89
+ marketing: {
90
+ de: string;
91
+ en: string;
92
+ };
93
+ sales: {
94
+ de: string;
95
+ en: string;
96
+ };
97
+ accounting: {
98
+ de: string;
99
+ en: string;
100
+ };
101
+ service: {
102
+ de: string;
103
+ en: string;
104
+ };
105
+ research: {
106
+ de: string;
107
+ en: string;
108
+ };
109
+ hr: {
110
+ de: string;
111
+ en: string;
112
+ };
113
+ operations: {
114
+ de: string;
115
+ en: string;
116
+ };
117
+ website: {
118
+ de: string;
119
+ en: string;
120
+ };
121
+ };
122
+ export type UseCase = keyof typeof USE_CASES;
123
+ /** What the models and tools behind a wizard must be able to do. */
124
+ export declare const CAPABILITIES: {
125
+ text: {
126
+ de: string;
127
+ en: string;
128
+ };
129
+ web: {
130
+ de: string;
131
+ en: string;
132
+ };
133
+ browser: {
134
+ de: string;
135
+ en: string;
136
+ };
137
+ documents: {
138
+ de: string;
139
+ en: string;
140
+ };
141
+ image: {
142
+ de: string;
143
+ en: string;
144
+ };
145
+ video: {
146
+ de: string;
147
+ en: string;
148
+ };
149
+ speech: {
150
+ de: string;
151
+ en: string;
152
+ };
153
+ listening: {
154
+ de: string;
155
+ en: string;
156
+ };
157
+ code: {
158
+ de: string;
159
+ en: string;
160
+ };
161
+ connectors: {
162
+ de: string;
163
+ en: string;
164
+ };
165
+ };
166
+ export type Capability = keyof typeof CAPABILITIES;
167
+ export declare const COST_TIERS: {
168
+ low: {
169
+ de: string;
170
+ en: string;
171
+ };
172
+ medium: {
173
+ de: string;
174
+ en: string;
175
+ };
176
+ high: {
177
+ de: string;
178
+ en: string;
179
+ };
180
+ };
181
+ export type CostTier = keyof typeof COST_TIERS;
182
+ export declare const ITEM_FORMAT_IDS: ("text" | "image" | "audio" | "video" | "document" | "dashboard" | "table")[];
183
+ export declare const INDUSTRY_IDS: ("any" | "trades" | "gastronomy" | "hospitality" | "realEstate" | "retail" | "health" | "professional" | "agency" | "events" | "publicSector")[];
184
+ export declare const USE_CASE_IDS: ("marketing" | "sales" | "accounting" | "service" | "research" | "hr" | "operations" | "website")[];
185
+ export declare const CAPABILITY_IDS: ("text" | "code" | "image" | "browser" | "video" | "speech" | "web" | "documents" | "listening" | "connectors")[];
186
+ /** The formats a run hands over, read from what the result step offers. */
187
+ export declare function formatsOf(def: WizardDefinition): ItemFormat[];
188
+ /** The capabilities a definition needs, read from its steps. */
189
+ export declare function capabilitiesOf(def: WizardDefinition): Capability[];
190
+ /** What a person does in a run, and about how long the whole run takes. */
191
+ export interface Effort {
192
+ /** Fields to fill in, the required ones of them. */
193
+ fields: number;
194
+ required: number;
195
+ /** Stops where the person looks at a result before it goes on. */
196
+ reviews: number;
197
+ /** Minutes from start to result: filling in, plus the time the steps work. */
198
+ minutes: number;
199
+ }
200
+ export declare function effortOf(def: WizardDefinition): Effort;
201
+ /** How expensive a run is, where no price in credits is known: by what it makes and uses. */
202
+ export declare function costTierOf(capabilities: Capability[]): CostTier;
203
+ /**
204
+ * The link that opens an entry in a local install at its default address — in the browser, or
205
+ * in the studio installed as a Chrome app.
206
+ */
207
+ export declare const entryLocalLink: (id: string) => string;
208
+ /** One entry as the marketplace lists it, in a language. */
209
+ export interface MarketplaceSummary {
210
+ id: string;
211
+ /** Goes up whenever the entry changes. */
212
+ revision: number;
213
+ /** Of everything the entry is made of, every language and file: changes with any of it. */
214
+ hash: string;
215
+ /** When the entry last changed, ISO 8601. */
216
+ updatedAt: string;
217
+ /** One of the entries an app keeps for offline use without being asked. */
218
+ starter: boolean;
219
+ /** The language of `title` and `pitch`; the entry's own where it is not translated. */
220
+ language: MarketplaceLang;
221
+ title: string;
222
+ pitch: string;
223
+ /** What people ask for when they mean this entry: searched, never shown. */
224
+ terms: string[];
225
+ avatar: string;
226
+ formats: ItemFormat[];
227
+ industries: Industry[];
228
+ useCases: UseCase[];
229
+ capabilities: Capability[];
230
+ effort: Effort;
231
+ costTier: CostTier;
232
+ steps: number;
233
+ /** The definition version the entry's wizard is written in (`DEFINITION_VERSION`). */
234
+ version: number;
235
+ }
236
+ /** What a search narrows by, besides its words. */
237
+ export interface MarketplaceFilters {
238
+ useCase?: UseCase;
239
+ industry?: Industry;
240
+ format?: ItemFormat;
241
+ capability?: Capability;
242
+ }
243
+ /** Per option of a filter: the entries it would leave, with the other filters as they are. */
244
+ export interface MarketplaceFacets {
245
+ useCase: Partial<Record<UseCase, number>>;
246
+ industry: Partial<Record<Industry, number>>;
247
+ format: Partial<Record<ItemFormat, number>>;
248
+ /** Optional: a marketplace older than this filter leaves it out. */
249
+ capability?: Partial<Record<Capability, number>>;
250
+ }
251
+ /** A page of a search: the entries, best first, how many there are, and the filters' counts. */
252
+ export interface MarketplacePage<T extends MarketplaceSummary = MarketplaceSummary> {
253
+ entries: T[];
254
+ total: number;
255
+ /** Every published entry, before words and filters. */
256
+ all: number;
257
+ facets: MarketplaceFacets;
258
+ }
259
+ /** One entry with its wizard in a language: what an app starts a wizard from. */
260
+ export interface MarketplaceItem extends MarketplaceSummary {
261
+ /** The wizard as written; an app reads it with its own schema. */
262
+ definition: unknown;
263
+ /** The workspace it starts with: path → base64. */
264
+ files: Record<string, string>;
265
+ }
266
+ /** Everything of an entry, every language: what an app keeps for offline use. */
267
+ export interface MarketplaceExport extends MarketplaceSummary {
268
+ texts: {
269
+ language: MarketplaceLang;
270
+ title: string;
271
+ pitch: string;
272
+ definition: unknown;
273
+ /** Written by a model, not by a person. */
274
+ machine: boolean;
275
+ }[];
276
+ /** path → base64 */
277
+ files: Record<string, string>;
278
+ }
279
+ /** What an app compares with what it keeps: an entry changed where its hash differs. */
280
+ export interface MarketplaceSyncItem {
281
+ id: string;
282
+ hash: string;
283
+ updatedAt: string;
284
+ }
285
+ /** One entry as the app shows it: the summary, read against this app. */
286
+ export interface MarketplaceEntry extends MarketplaceSummary {
287
+ /** A run's price in credits and what it rarely exceeds; null where it is not worked out. */
288
+ credits: {
289
+ credits: number;
290
+ high: number;
291
+ } | null;
292
+ /** False: this app is older than the entry and would read its wizard wrongly. */
293
+ usable: boolean;
294
+ /** The person keeps it for offline use. */
295
+ starred: boolean;
296
+ /** What it needs that this runtime has no model for: a wizard made from it would not start. */
297
+ missing: Capability[];
298
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The marketplace: wizards anyone can start from. What an entry is sorted by — formats, industry,
3
+ * use case — and what follows from its definition: the AI capabilities it needs, how much a
4
+ * person has to fill in, and how expensive a run is.
5
+ */
6
+ export const MARKETPLACE_LANGS = ["de", "en"];
7
+ /** What comes out of a run. */
8
+ export const ITEM_FORMATS = {
9
+ text: { de: "Text", en: "Text" },
10
+ document: { de: "Dokument (PDF, Word)", en: "Document (PDF, Word)" },
11
+ table: { de: "Tabelle", en: "Table" },
12
+ image: { de: "Bild", en: "Image" },
13
+ video: { de: "Video", en: "Video" },
14
+ audio: { de: "Audio", en: "Audio" },
15
+ dashboard: { de: "Dashboard", en: "Dashboard" },
16
+ };
17
+ export const INDUSTRIES = {
18
+ any: { de: "Jede Branche", en: "Any industry" },
19
+ trades: { de: "Handwerk", en: "Trades" },
20
+ gastronomy: { de: "Gastronomie", en: "Food service" },
21
+ hospitality: { de: "Hotel & Tourismus", en: "Hotels & tourism" },
22
+ realEstate: { de: "Immobilien", en: "Real estate" },
23
+ retail: { de: "Handel", en: "Retail" },
24
+ health: { de: "Gesundheit", en: "Health" },
25
+ professional: { de: "Kanzlei & Beratung", en: "Professional services" },
26
+ agency: { de: "Agentur & Marketing", en: "Agency & marketing" },
27
+ events: { de: "Veranstaltungen", en: "Events" },
28
+ publicSector: { de: "Vereine & Öffentliches", en: "Associations & public sector" },
29
+ };
30
+ export const USE_CASES = {
31
+ marketing: { de: "Marketing & Social Media", en: "Marketing & social media" },
32
+ sales: { de: "Angebote & Verkauf", en: "Offers & sales" },
33
+ accounting: { de: "Buchhaltung & Belege", en: "Accounting & receipts" },
34
+ service: { de: "Kundenservice", en: "Customer service" },
35
+ research: { de: "Recherche & Analyse", en: "Research & analysis" },
36
+ hr: { de: "Personal & Bewerbungen", en: "HR & applications" },
37
+ operations: { de: "Planung & Abläufe", en: "Planning & operations" },
38
+ website: { de: "Helfer für die Website", en: "Website helpers" },
39
+ };
40
+ /** What the models and tools behind a wizard must be able to do. */
41
+ export const CAPABILITIES = {
42
+ text: { de: "Text schreiben", en: "Writes text" },
43
+ web: { de: "Websuche", en: "Web search" },
44
+ browser: { de: "Browser bedienen", en: "Drives a browser" },
45
+ documents: { de: "Dokumente & Fotos lesen", en: "Reads documents & photos" },
46
+ image: { de: "Bilder erzeugen", en: "Makes images" },
47
+ video: { de: "Videos erzeugen", en: "Makes video" },
48
+ speech: { de: "Sprachausgabe", en: "Speech output" },
49
+ listening: { de: "Sprachnotizen verstehen", en: "Understands voice notes" },
50
+ code: { de: "Code ausführen", en: "Runs code" },
51
+ connectors: { de: "Verbundene Konten & Systeme", en: "Connected accounts & systems" },
52
+ };
53
+ export const COST_TIERS = {
54
+ low: { de: "günstig", en: "low cost" },
55
+ medium: { de: "mittel", en: "medium cost" },
56
+ high: { de: "teuer", en: "high cost" },
57
+ };
58
+ const keys = (o) => Object.keys(o);
59
+ export const ITEM_FORMAT_IDS = keys(ITEM_FORMATS);
60
+ export const INDUSTRY_IDS = keys(INDUSTRIES);
61
+ export const USE_CASE_IDS = keys(USE_CASES);
62
+ export const CAPABILITY_IDS = keys(CAPABILITIES);
63
+ const FORMAT_OF = {
64
+ pdf: "document",
65
+ docx: "document",
66
+ xlsx: "table",
67
+ csv: "table",
68
+ png: "image",
69
+ mp4: "video",
70
+ mp3: "audio",
71
+ md: "text",
72
+ txt: "text",
73
+ };
74
+ /** The formats a run hands over, read from what the result step offers. */
75
+ export function formatsOf(def) {
76
+ const found = new Set();
77
+ for (const step of def.steps) {
78
+ if (step.type === "generate" && step.asset === "dashboard") {
79
+ found.add("dashboard");
80
+ }
81
+ if (step.type === "result") {
82
+ for (const d of step.deliverables) {
83
+ const from = def.steps.find((s) => s.id === d.from);
84
+ for (const f of d.formats) {
85
+ const format = FORMAT_OF[f];
86
+ // A dashboard's PNG or PDF is still the dashboard.
87
+ if (format && !(from?.type === "generate" && from.asset === "dashboard")) {
88
+ found.add(format);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ if (!found.size) {
95
+ found.add("text");
96
+ }
97
+ return ITEM_FORMAT_IDS.filter((f) => found.has(f));
98
+ }
99
+ /** The capabilities a definition needs, read from its steps. */
100
+ export function capabilitiesOf(def) {
101
+ const found = new Set();
102
+ for (const step of def.steps) {
103
+ if (step.type === "page") {
104
+ for (const field of step.fields) {
105
+ if (field.kind === "image" || field.kind === "file") {
106
+ found.add("documents");
107
+ }
108
+ if (field.kind === "audio") {
109
+ found.add("listening");
110
+ }
111
+ }
112
+ }
113
+ else if (step.type === "agent") {
114
+ found.add("text");
115
+ for (const tool of step.tools) {
116
+ if (tool === "web_search" || tool === "web_fetch") {
117
+ found.add("web");
118
+ }
119
+ else if (tool === "browser") {
120
+ found.add("browser");
121
+ }
122
+ else if (tool === "sandbox") {
123
+ found.add("code");
124
+ }
125
+ else if (tool === "image") {
126
+ found.add("image");
127
+ }
128
+ else if (tool === "http") {
129
+ found.add("connectors");
130
+ }
131
+ }
132
+ if (step.mcp?.length || step.connections?.length) {
133
+ found.add("connectors");
134
+ }
135
+ }
136
+ else if (step.type === "generate") {
137
+ if (step.asset === "image") {
138
+ found.add("image");
139
+ }
140
+ else if (step.asset === "video") {
141
+ found.add("video");
142
+ }
143
+ else if (step.asset === "voice") {
144
+ found.add("speech");
145
+ }
146
+ else {
147
+ found.add("text");
148
+ }
149
+ }
150
+ }
151
+ if (def.connections?.length) {
152
+ found.add("connectors");
153
+ }
154
+ return CAPABILITY_IDS.filter((c) => found.has(c));
155
+ }
156
+ const WORK_SECONDS = { agent: 25, tools: 70, browser: 150, image: 30, video: 120, voice: 20 };
157
+ export function effortOf(def) {
158
+ let fields = 0;
159
+ let required = 0;
160
+ let reviews = 0;
161
+ let seconds = 0;
162
+ for (const step of def.steps) {
163
+ if (step.type === "page") {
164
+ fields += step.fields.length;
165
+ required += step.fields.filter((f) => f.required).length;
166
+ seconds += step.fields.length * 15;
167
+ }
168
+ else if (step.type === "review") {
169
+ reviews += 1;
170
+ seconds += 30;
171
+ }
172
+ else if (step.type === "agent") {
173
+ seconds += step.tools.includes("browser")
174
+ ? WORK_SECONDS.browser
175
+ : step.tools.length || step.mcp?.length || step.connections?.length
176
+ ? WORK_SECONDS.tools
177
+ : WORK_SECONDS.agent;
178
+ }
179
+ else if (step.type === "generate") {
180
+ // "each" makes one result per entry; three stands in for a number nobody knows yet.
181
+ const times = step.each ? 3 : 1;
182
+ seconds +=
183
+ times *
184
+ (step.asset === "image"
185
+ ? WORK_SECONDS.image
186
+ : step.asset === "video"
187
+ ? WORK_SECONDS.video
188
+ : step.asset === "voice"
189
+ ? WORK_SECONDS.voice
190
+ : WORK_SECONDS.agent);
191
+ }
192
+ else if (step.type === "widget" && step.video) {
193
+ seconds += 60;
194
+ }
195
+ }
196
+ return { fields, required, reviews, minutes: Math.max(1, Math.round(seconds / 60)) };
197
+ }
198
+ /** How expensive a run is, where no price in credits is known: by what it makes and uses. */
199
+ export function costTierOf(capabilities) {
200
+ if (capabilities.includes("video")) {
201
+ return "high";
202
+ }
203
+ return capabilities.some((c) => c === "image" || c === "browser" || c === "speech")
204
+ ? "medium"
205
+ : "low";
206
+ }
207
+ /**
208
+ * The link that opens an entry in a local install at its default address — in the browser, or
209
+ * in the studio installed as a Chrome app.
210
+ */
211
+ export const entryLocalLink = (id) => `http://localhost:24368/studio/new?starter=${encodeURIComponent(id)}`;
@@ -0,0 +1,7 @@
1
+ import type { WizardDefinition } from "./definition.js";
2
+ /**
3
+ * Three-way merge, step by step, of a draft edited in the studio (`local`) with one written
4
+ * elsewhere meanwhile (`remote`), both starting from `base`. What the studio changed, added or
5
+ * removed wins; everything else is taken from `remote`.
6
+ */
7
+ export declare function mergeDrafts(base: WizardDefinition, local: WizardDefinition, remote: WizardDefinition): WizardDefinition;
@@ -0,0 +1,40 @@
1
+ const META = ["title", "description", "avatar", "intro", "lists", "connections"];
2
+ const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
3
+ /**
4
+ * Three-way merge, step by step, of a draft edited in the studio (`local`) with one written
5
+ * elsewhere meanwhile (`remote`), both starting from `base`. What the studio changed, added or
6
+ * removed wins; everything else is taken from `remote`.
7
+ */
8
+ export function mergeDrafts(base, local, remote) {
9
+ const merged = { ...remote };
10
+ for (const key of META) {
11
+ if (!same(local[key], base[key])) {
12
+ Object.assign(merged, { [key]: local[key] });
13
+ }
14
+ }
15
+ const baseSteps = new Map(base.steps.map((s) => [s.id, s]));
16
+ const localIds = new Set(local.steps.map((s) => s.id));
17
+ // Removed in the studio: gone, unless the other side changed it meanwhile.
18
+ const steps = remote.steps.filter((s) => {
19
+ const before = baseSteps.get(s.id);
20
+ return localIds.has(s.id) || !before || !same(before, s);
21
+ });
22
+ local.steps.forEach((step, i) => {
23
+ const before = baseSteps.get(step.id);
24
+ if (before && same(before, step)) {
25
+ return;
26
+ }
27
+ const at = steps.findIndex((s) => s.id === step.id);
28
+ if (at !== -1) {
29
+ steps[at] = step;
30
+ return;
31
+ }
32
+ // New in the studio: after the step it follows there.
33
+ const prev = local.steps
34
+ .slice(0, i)
35
+ .reverse()
36
+ .find((p) => steps.some((s) => s.id === p.id));
37
+ steps.splice(prev ? steps.findIndex((s) => s.id === prev.id) + 1 : 0, 0, step);
38
+ });
39
+ return { ...merged, steps };
40
+ }