@engenty/wizards-runtime 0.0.0-stage → 0.7.6

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 (523) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +214 -2
  3. package/apps/runtime/dist/agents/architect.js +444 -0
  4. package/apps/runtime/dist/agents/studio-assistant.js +883 -0
  5. package/apps/runtime/dist/agents/subscription.js +207 -0
  6. package/apps/runtime/dist/agents/thought.js +21 -0
  7. package/apps/runtime/dist/agents/website.js +480 -0
  8. package/apps/runtime/dist/app.js +359 -0
  9. package/apps/runtime/dist/apple/wizards-apple +0 -0
  10. package/apps/runtime/dist/assistant/browser.js +26 -0
  11. package/apps/runtime/dist/assistant/docs.js +158 -0
  12. package/apps/runtime/dist/assistant/knows.js +353 -0
  13. package/apps/runtime/dist/assistant/primer.js +26 -0
  14. package/apps/runtime/dist/assistant/runs.js +24 -0
  15. package/apps/runtime/dist/auth/account.js +175 -0
  16. package/apps/runtime/dist/auth/device.js +112 -0
  17. package/apps/runtime/dist/auth/index.js +358 -0
  18. package/apps/runtime/dist/auth/keys.js +55 -0
  19. package/apps/runtime/dist/auth/local-ticket.js +26 -0
  20. package/apps/runtime/dist/authoring/example.js +74 -0
  21. package/apps/runtime/dist/authoring/guide.js +433 -0
  22. package/apps/runtime/dist/authoring/ops.js +117 -0
  23. package/apps/runtime/dist/browser/fast/action-space.js +160 -0
  24. package/apps/runtime/dist/browser/fast/classifier.js +91 -0
  25. package/apps/runtime/dist/browser/fast/decide.js +171 -0
  26. package/apps/runtime/dist/browser/fast/driver.js +141 -0
  27. package/apps/runtime/dist/browser/fast/instructions.js +33 -0
  28. package/apps/runtime/dist/browser/fast/run.js +249 -0
  29. package/apps/runtime/dist/browser/fast/span-picker.js +153 -0
  30. package/apps/runtime/dist/browser/fast/text-helper.js +178 -0
  31. package/apps/runtime/dist/browser/snapshot.js +335 -0
  32. package/apps/runtime/dist/cli/account.js +385 -0
  33. package/apps/runtime/dist/cli/autostart.js +182 -0
  34. package/apps/runtime/dist/cli/autoupdate.js +221 -0
  35. package/apps/runtime/dist/cli/clients.js +44 -0
  36. package/apps/runtime/dist/cli/connect.js +540 -0
  37. package/apps/runtime/dist/cli/environment.js +95 -0
  38. package/apps/runtime/dist/cli/exec.js +45 -0
  39. package/apps/runtime/dist/cli/features.js +50 -0
  40. package/apps/runtime/dist/cli/home.js +88 -0
  41. package/apps/runtime/dist/cli/install-env.js +33 -0
  42. package/apps/runtime/dist/cli/machine.js +107 -0
  43. package/apps/runtime/dist/cli/main.js +231 -0
  44. package/apps/runtime/dist/cli/mcp.js +136 -0
  45. package/apps/runtime/dist/cli/menu.js +202 -0
  46. package/apps/runtime/dist/cli/processes.js +72 -0
  47. package/apps/runtime/dist/cli/report.js +66 -0
  48. package/apps/runtime/dist/cli/sandbox.js +77 -0
  49. package/apps/runtime/dist/cli/setup.js +335 -0
  50. package/apps/runtime/dist/cli/start.js +276 -0
  51. package/apps/runtime/dist/cli/status.js +212 -0
  52. package/apps/runtime/dist/cli/ui.js +59 -0
  53. package/apps/runtime/dist/cli/uninstall-main.js +20 -0
  54. package/apps/runtime/dist/cli/uninstall.js +231 -0
  55. package/apps/runtime/dist/cli/update.js +86 -0
  56. package/apps/runtime/dist/cli/validate.js +75 -0
  57. package/apps/runtime/dist/cli/versions.js +123 -0
  58. package/apps/runtime/dist/connectors/builtin.js +86 -0
  59. package/apps/runtime/dist/connectors/external.js +409 -0
  60. package/apps/runtime/dist/connectors/gmail.js +107 -0
  61. package/apps/runtime/dist/connectors/imap.js +261 -0
  62. package/apps/runtime/dist/connectors/index.js +325 -0
  63. package/apps/runtime/dist/connectors/mail.js +72 -0
  64. package/apps/runtime/dist/connectors/outlook.js +90 -0
  65. package/apps/runtime/dist/connectors/plugin-connections.js +343 -0
  66. package/apps/runtime/dist/connectors/via-account.js +65 -0
  67. package/apps/runtime/dist/credits/credits.js +100 -0
  68. package/apps/runtime/dist/credits/estimate.js +152 -0
  69. package/apps/runtime/dist/db/adopt.js +149 -0
  70. package/apps/runtime/dist/db/client.js +173 -0
  71. package/apps/runtime/dist/db/control-schema.js +133 -0
  72. package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
  73. package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
  74. package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
  75. package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
  76. package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
  77. package/apps/runtime/dist/db/migrations/control/0005_chilly_oracle.sql +1 -0
  78. package/apps/runtime/dist/db/migrations/control/0006_sleepy_mojo.sql +1 -0
  79. package/apps/runtime/dist/db/migrations/control/0007_common_the_hand.sql +15 -0
  80. package/apps/runtime/dist/db/migrations/control/0008_runner.sql +8 -0
  81. package/apps/runtime/dist/db/migrations/control/0009_plugin_claim.sql +9 -0
  82. package/apps/runtime/dist/db/migrations/control/0010_tan_snowbird.sql +6 -0
  83. package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
  84. package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
  85. package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
  86. package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
  87. package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
  88. package/apps/runtime/dist/db/migrations/control/meta/0005_snapshot.json +358 -0
  89. package/apps/runtime/dist/db/migrations/control/meta/0006_snapshot.json +365 -0
  90. package/apps/runtime/dist/db/migrations/control/meta/0007_snapshot.json +460 -0
  91. package/apps/runtime/dist/db/migrations/control/meta/0008_snapshot.json +505 -0
  92. package/apps/runtime/dist/db/migrations/control/meta/0009_snapshot.json +561 -0
  93. package/apps/runtime/dist/db/migrations/control/meta/0010_snapshot.json +600 -0
  94. package/apps/runtime/dist/db/migrations/control/meta/_journal.json +83 -0
  95. package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
  96. package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
  97. package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
  98. package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
  99. package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
  100. package/apps/runtime/dist/db/migrations/tenant/0005_reflective_forgotten_one.sql +2 -0
  101. package/apps/runtime/dist/db/migrations/tenant/0006_hard_war_machine.sql +30 -0
  102. package/apps/runtime/dist/db/migrations/tenant/0007_space_data.sql +43 -0
  103. package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
  104. package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
  105. package/apps/runtime/dist/db/migrations/tenant/0010_plugin_connection.sql +15 -0
  106. package/apps/runtime/dist/db/migrations/tenant/0011_runners.sql +2 -0
  107. package/apps/runtime/dist/db/migrations/tenant/0012_assistant_chat.sql +40 -0
  108. package/apps/runtime/dist/db/migrations/tenant/0013_run_origin.sql +1 -0
  109. package/apps/runtime/dist/db/migrations/tenant/0014_run_answer.sql +2 -0
  110. package/apps/runtime/dist/db/migrations/tenant/0015_device_calls.sql +13 -0
  111. package/apps/runtime/dist/db/migrations/tenant/0016_even_trish_tilby.sql +12 -0
  112. package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
  113. package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
  114. package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
  115. package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
  116. package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
  117. package/apps/runtime/dist/db/migrations/tenant/meta/0005_snapshot.json +1659 -0
  118. package/apps/runtime/dist/db/migrations/tenant/meta/0006_snapshot.json +1696 -0
  119. package/apps/runtime/dist/db/migrations/tenant/meta/0007_snapshot.json +2012 -0
  120. package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
  121. package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
  122. package/apps/runtime/dist/db/migrations/tenant/meta/0010_snapshot.json +2942 -0
  123. package/apps/runtime/dist/db/migrations/tenant/meta/0011_snapshot.json +2956 -0
  124. package/apps/runtime/dist/db/migrations/tenant/meta/0012_snapshot.json +3132 -0
  125. package/apps/runtime/dist/db/migrations/tenant/meta/0013_snapshot.json +3139 -0
  126. package/apps/runtime/dist/db/migrations/tenant/meta/0014_snapshot.json +3154 -0
  127. package/apps/runtime/dist/db/migrations/tenant/meta/0015_snapshot.json +3243 -0
  128. package/apps/runtime/dist/db/migrations/tenant/meta/0016_snapshot.json +3326 -0
  129. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +125 -0
  130. package/apps/runtime/dist/db/schema.js +602 -0
  131. package/apps/runtime/dist/debug.js +197 -0
  132. package/apps/runtime/dist/docs/dev/index.md +41 -0
  133. package/apps/runtime/dist/docs/dev/meta.json +7 -0
  134. package/apps/runtime/dist/docs/dev/plugins/connections.md +74 -0
  135. package/apps/runtime/dist/docs/dev/plugins/events.md +89 -0
  136. package/apps/runtime/dist/docs/dev/plugins/examples.md +101 -0
  137. package/apps/runtime/dist/docs/dev/plugins/index.md +78 -0
  138. package/apps/runtime/dist/docs/dev/plugins/layout.md +90 -0
  139. package/apps/runtime/dist/docs/dev/plugins/meta.json +28 -0
  140. package/apps/runtime/dist/docs/dev/plugins/quick-start.md +94 -0
  141. package/apps/runtime/dist/docs/dev/plugins/reference.md +348 -0
  142. package/apps/runtime/dist/docs/dev/plugins/reloading.md +76 -0
  143. package/apps/runtime/dist/docs/dev/plugins/routes.md +185 -0
  144. package/apps/runtime/dist/docs/dev/plugins/runners.md +230 -0
  145. package/apps/runtime/dist/docs/dev/plugins/server.md +281 -0
  146. package/apps/runtime/dist/docs/dev/plugins/shipping.md +79 -0
  147. package/apps/runtime/dist/docs/dev/plugins/space.md +297 -0
  148. package/apps/runtime/dist/docs/dev/plugins/starters.md +70 -0
  149. package/apps/runtime/dist/docs/dev/plugins/studio.md +363 -0
  150. package/apps/runtime/dist/docs/dev/plugins/styling.md +129 -0
  151. package/apps/runtime/dist/docs/dev/plugins/tables.md +104 -0
  152. package/apps/runtime/dist/docs/dev/plugins/tools.md +139 -0
  153. package/apps/runtime/dist/docs/dev/wizard-format.md +125 -0
  154. package/apps/runtime/dist/docs/meta.json +3 -0
  155. package/apps/runtime/dist/docs/user/ai-apps.md +112 -0
  156. package/apps/runtime/dist/docs/user/assistant.md +77 -0
  157. package/apps/runtime/dist/docs/user/build-a-wizard.md +116 -0
  158. package/apps/runtime/dist/docs/user/command-line.md +86 -0
  159. package/apps/runtime/dist/docs/user/connectors.md +90 -0
  160. package/apps/runtime/dist/docs/user/create-account.md +52 -0
  161. package/apps/runtime/dist/docs/user/data.md +66 -0
  162. package/apps/runtime/dist/docs/user/first-start.md +60 -0
  163. package/apps/runtime/dist/docs/user/index.md +49 -0
  164. package/apps/runtime/dist/docs/user/install.md +123 -0
  165. package/apps/runtime/dist/docs/user/local-only.md +42 -0
  166. package/apps/runtime/dist/docs/user/meta.json +32 -0
  167. package/apps/runtime/dist/docs/user/models.md +156 -0
  168. package/apps/runtime/dist/docs/user/plugins.md +71 -0
  169. package/apps/runtime/dist/docs/user/run.md +98 -0
  170. package/apps/runtime/dist/docs/user/server.md +52 -0
  171. package/apps/runtime/dist/docs/user/space.md +126 -0
  172. package/apps/runtime/dist/docs/user/steps.md +220 -0
  173. package/apps/runtime/dist/docs/user/test-and-share.md +224 -0
  174. package/apps/runtime/dist/docs/user/troubleshooting.md +67 -0
  175. package/apps/runtime/dist/docs/user/wordpress.md +121 -0
  176. package/apps/runtime/dist/documents/parse.js +246 -0
  177. package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
  178. package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
  179. package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
  180. package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
  181. package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
  182. package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
  183. package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
  184. package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
  185. package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
  186. package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
  187. package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
  188. package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
  189. package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
  190. package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
  191. package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
  192. package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +381 -0
  193. package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
  194. package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
  195. package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
  196. package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
  197. package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
  198. package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
  199. package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
  200. package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
  201. package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
  202. package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +492 -0
  203. package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
  204. package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
  205. package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
  206. package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
  207. package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
  208. package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
  209. package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
  210. package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
  211. package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
  212. package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
  213. package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
  214. package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
  215. package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
  216. package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
  217. package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
  218. package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
  219. package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
  220. package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
  221. package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
  222. package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
  223. package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
  224. package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
  225. package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
  226. package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
  227. package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
  228. package/apps/runtime/dist/engenty/shims/web-ingest.js +19 -0
  229. package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
  230. package/apps/runtime/dist/engine/asks.js +82 -0
  231. package/apps/runtime/dist/engine/decide.js +82 -0
  232. package/apps/runtime/dist/engine/device.js +194 -0
  233. package/apps/runtime/dist/engine/events.js +128 -0
  234. package/apps/runtime/dist/engine/input.js +208 -0
  235. package/apps/runtime/dist/engine/owner.js +32 -0
  236. package/apps/runtime/dist/engine/prepare.js +90 -0
  237. package/apps/runtime/dist/engine/push.js +58 -0
  238. package/apps/runtime/dist/engine/requirements.js +355 -0
  239. package/apps/runtime/dist/engine/resources.js +198 -0
  240. package/apps/runtime/dist/engine/runner.js +970 -0
  241. package/apps/runtime/dist/engine/steps.js +1000 -0
  242. package/apps/runtime/dist/engine/surface.js +91 -0
  243. package/apps/runtime/dist/engine/template.js +240 -0
  244. package/apps/runtime/dist/engine/types.js +4 -0
  245. package/apps/runtime/dist/env.js +279 -0
  246. package/apps/runtime/dist/features.js +123 -0
  247. package/apps/runtime/dist/files/blobs.js +22 -0
  248. package/apps/runtime/dist/files/objects.js +86 -0
  249. package/apps/runtime/dist/files/storage.js +120 -0
  250. package/apps/runtime/dist/files/web-images.js +101 -0
  251. package/apps/runtime/dist/film/project.js +257 -0
  252. package/apps/runtime/dist/film/skills.js +91 -0
  253. package/apps/runtime/dist/film/sounds.js +122 -0
  254. package/apps/runtime/dist/film/step.js +289 -0
  255. package/apps/runtime/dist/film/tools.js +99 -0
  256. package/apps/runtime/dist/geocode.js +58 -0
  257. package/apps/runtime/dist/harness/antigravity.js +129 -0
  258. package/apps/runtime/dist/harness/apple.js +270 -0
  259. package/apps/runtime/dist/harness/claude.js +147 -0
  260. package/apps/runtime/dist/harness/codex.js +229 -0
  261. package/apps/runtime/dist/harness/cursor.js +93 -0
  262. package/apps/runtime/dist/harness/env.js +124 -0
  263. package/apps/runtime/dist/harness/index.js +95 -0
  264. package/apps/runtime/dist/harness/model.js +279 -0
  265. package/apps/runtime/dist/harness/prompt.js +121 -0
  266. package/apps/runtime/dist/harness/terminal.js +194 -0
  267. package/apps/runtime/dist/harness/types.js +7 -0
  268. package/apps/runtime/dist/index.js +113 -0
  269. package/apps/runtime/dist/limits.js +81 -0
  270. package/apps/runtime/dist/link-preview.js +60 -0
  271. package/apps/runtime/dist/log.js +106 -0
  272. package/apps/runtime/dist/manage.js +249 -0
  273. package/apps/runtime/dist/mcp/auth.js +161 -0
  274. package/apps/runtime/dist/mcp/bridge.js +59 -0
  275. package/apps/runtime/dist/mcp/flow-app.js +97 -0
  276. package/apps/runtime/dist/mcp/handler.js +54 -0
  277. package/apps/runtime/dist/mcp/scopes.js +14 -0
  278. package/apps/runtime/dist/mcp/seen.js +65 -0
  279. package/apps/runtime/dist/mcp/tools.js +572 -0
  280. package/apps/runtime/dist/media/conversation.js +167 -0
  281. package/apps/runtime/dist/media/ffmpeg.js +121 -0
  282. package/apps/runtime/dist/media/generate.js +120 -0
  283. package/apps/runtime/dist/media/marking.js +121 -0
  284. package/apps/runtime/dist/media/transcribe.js +198 -0
  285. package/apps/runtime/dist/model-errors.js +42 -0
  286. package/apps/runtime/dist/models.js +1164 -0
  287. package/apps/runtime/dist/plugin.js +61 -0
  288. package/apps/runtime/dist/plugins/channels.js +78 -0
  289. package/apps/runtime/dist/plugins/claims.js +56 -0
  290. package/apps/runtime/dist/plugins/discovery.js +155 -0
  291. package/apps/runtime/dist/plugins/events.js +63 -0
  292. package/apps/runtime/dist/plugins/jobs.js +64 -0
  293. package/apps/runtime/dist/plugins/loader.js +508 -0
  294. package/apps/runtime/dist/plugins/migrations.js +69 -0
  295. package/apps/runtime/dist/plugins/pro-keys.js +34 -0
  296. package/apps/runtime/dist/plugins/pro-state.js +83 -0
  297. package/apps/runtime/dist/plugins/pro.js +310 -0
  298. package/apps/runtime/dist/plugins/public.js +44 -0
  299. package/apps/runtime/dist/plugins/registry.js +122 -0
  300. package/apps/runtime/dist/plugins/runs.js +210 -0
  301. package/apps/runtime/dist/render/browser-path.js +54 -0
  302. package/apps/runtime/dist/render/chromium.js +98 -0
  303. package/apps/runtime/dist/render/convert.js +158 -0
  304. package/apps/runtime/dist/render/downloads.js +299 -0
  305. package/apps/runtime/dist/render/guard.js +25 -0
  306. package/apps/runtime/dist/render/shaped.js +137 -0
  307. package/apps/runtime/dist/routes/api.js +440 -0
  308. package/apps/runtime/dist/routes/debug.js +42 -0
  309. package/apps/runtime/dist/routes/delivery.js +90 -0
  310. package/apps/runtime/dist/routes/internal.js +81 -0
  311. package/apps/runtime/dist/routes/lang.js +25 -0
  312. package/apps/runtime/dist/routes/marketplace.js +43 -0
  313. package/apps/runtime/dist/routes/plugin-public.js +113 -0
  314. package/apps/runtime/dist/routes/plugins.js +212 -0
  315. package/apps/runtime/dist/routes/runs.js +1422 -0
  316. package/apps/runtime/dist/routes/studio.js +1629 -0
  317. package/apps/runtime/dist/routes/wizard-stream.js +30 -0
  318. package/apps/runtime/dist/running.js +39 -0
  319. package/apps/runtime/dist/sandbox/agentos-package.js +73 -0
  320. package/apps/runtime/dist/sandbox/agentos.js +162 -0
  321. package/apps/runtime/dist/sandbox/docker.js +45 -0
  322. package/apps/runtime/dist/sandbox/index.js +52 -0
  323. package/apps/runtime/dist/sandbox/install.js +122 -0
  324. package/apps/runtime/dist/sandbox/mastra.js +71 -0
  325. package/apps/runtime/dist/sandbox/types.js +1 -0
  326. package/apps/runtime/dist/secrets/crypto.js +28 -0
  327. package/apps/runtime/dist/secrets/signing.js +52 -0
  328. package/apps/runtime/dist/secrets/vault.js +59 -0
  329. package/apps/runtime/dist/services/access.js +88 -0
  330. package/apps/runtime/dist/services/api.js +248 -0
  331. package/apps/runtime/dist/services/architect.js +95 -0
  332. package/apps/runtime/dist/services/assistant-chats.js +311 -0
  333. package/apps/runtime/dist/services/brand.js +85 -0
  334. package/apps/runtime/dist/services/cloud.js +456 -0
  335. package/apps/runtime/dist/services/draft-events.js +27 -0
  336. package/apps/runtime/dist/services/engenty-shapes.js +71 -0
  337. package/apps/runtime/dist/services/errors.js +29 -0
  338. package/apps/runtime/dist/services/files.js +178 -0
  339. package/apps/runtime/dist/services/knowledge-model.js +559 -0
  340. package/apps/runtime/dist/services/knowledge.js +721 -0
  341. package/apps/runtime/dist/services/links.js +16 -0
  342. package/apps/runtime/dist/services/marketplace.js +492 -0
  343. package/apps/runtime/dist/services/onboarding.js +152 -0
  344. package/apps/runtime/dist/services/package-file.js +82 -0
  345. package/apps/runtime/dist/services/package.js +170 -0
  346. package/apps/runtime/dist/services/profile.js +51 -0
  347. package/apps/runtime/dist/services/project-files.js +439 -0
  348. package/apps/runtime/dist/services/project-index.js +707 -0
  349. package/apps/runtime/dist/services/projects.js +387 -0
  350. package/apps/runtime/dist/services/relevance.js +58 -0
  351. package/apps/runtime/dist/services/runners.js +178 -0
  352. package/apps/runtime/dist/services/runs.js +524 -0
  353. package/apps/runtime/dist/services/shares.js +130 -0
  354. package/apps/runtime/dist/services/site.js +270 -0
  355. package/apps/runtime/dist/services/space-categories.js +861 -0
  356. package/apps/runtime/dist/services/space-data.js +792 -0
  357. package/apps/runtime/dist/services/space-origin.js +207 -0
  358. package/apps/runtime/dist/services/spaces.js +657 -0
  359. package/apps/runtime/dist/services/translations.js +306 -0
  360. package/apps/runtime/dist/services/widgets.js +34 -0
  361. package/apps/runtime/dist/services/wizard-icon.js +157 -0
  362. package/apps/runtime/dist/services/wizards.js +420 -0
  363. package/apps/runtime/dist/settings.js +16 -0
  364. package/apps/runtime/dist/store/errors.js +4 -0
  365. package/apps/runtime/dist/store/index.js +299 -0
  366. package/apps/runtime/dist/store/shared-lists.js +123 -0
  367. package/apps/runtime/dist/tenants/control.js +238 -0
  368. package/apps/runtime/dist/tenants/tenant.js +26 -0
  369. package/apps/runtime/dist/texts.js +207 -0
  370. package/apps/runtime/dist/tools/browser.js +703 -0
  371. package/apps/runtime/dist/tools/connector.js +204 -0
  372. package/apps/runtime/dist/tools/index.js +291 -0
  373. package/apps/runtime/dist/tools/mail.js +104 -0
  374. package/apps/runtime/dist/tools/net-guard.js +170 -0
  375. package/apps/runtime/dist/tools/pages.js +81 -0
  376. package/apps/runtime/dist/tools/plugin.js +180 -0
  377. package/apps/runtime/dist/tools/project.js +154 -0
  378. package/apps/runtime/dist/tools/shared.js +69 -0
  379. package/apps/runtime/dist/tools/store.js +238 -0
  380. package/apps/runtime/dist/update.js +113 -0
  381. package/apps/runtime/dist/widgets/bundle.js +99 -0
  382. package/apps/runtime/dist/widgets/render.js +329 -0
  383. package/apps/runtime/dist/widgets/runtime.js +108 -0
  384. package/apps/runtime/dist/widgets/script.js +30 -0
  385. package/apps/runtime/dist/widgets/step.js +223 -0
  386. package/apps/web/dist/ai-labels/ai-black.svg +20 -0
  387. package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
  388. package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
  389. package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
  390. package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
  391. package/apps/web/dist/ai-labels/ai-white.svg +21 -0
  392. package/apps/web/dist/assets/AboutDialog-DYgXPagX.js +1 -0
  393. package/apps/web/dist/assets/ChangelogDialog-BXqBW8j3.js +1 -0
  394. package/apps/web/dist/assets/ChatView-CK2--tsE.js +10 -0
  395. package/apps/web/dist/assets/EditorPage-jvcwyXbU.js +3 -0
  396. package/apps/web/dist/assets/FlowPreview-CusP7ci9.js +1 -0
  397. package/apps/web/dist/assets/Harness-BrP-ENHg.css +1 -0
  398. package/apps/web/dist/assets/Harness-CV9uYzbv.js +16 -0
  399. package/apps/web/dist/assets/NewWizardChannels-BakW5q6s.js +1 -0
  400. package/apps/web/dist/assets/NewWizardPage-BoA-LJuW.js +7 -0
  401. package/apps/web/dist/assets/OnboardingPage-DaD1XnOe.js +1 -0
  402. package/apps/web/dist/assets/ProjectPage-BFgk1DEv.js +1 -0
  403. package/apps/web/dist/assets/PublicRunner-C9MwEvxy.js +1 -0
  404. package/apps/web/dist/assets/ReadOnly-DC2Kp7l8.js +1 -0
  405. package/apps/web/dist/assets/RunDrawer-CY6NZSrI.js +4 -0
  406. package/apps/web/dist/assets/RunnerView-BT26XgcY.js +1 -0
  407. package/apps/web/dist/assets/SettingsPage-AFt9IDLt.js +1 -0
  408. package/apps/web/dist/assets/SetupPage-DtFYAbwJ.js +1 -0
  409. package/apps/web/dist/assets/SharePage-t2xwNS61.js +1 -0
  410. package/apps/web/dist/assets/changelog-CATQFxCQ.js +1 -0
  411. package/apps/web/dist/assets/engenty-eXZ-EAwd.js +1 -0
  412. package/apps/web/dist/assets/esm-DXeMu8Lb.js +7 -0
  413. package/apps/web/dist/assets/fluffy-engenty-ClRou7yu.js +456 -0
  414. package/apps/web/dist/assets/index-AfUa8xKD.css +1 -0
  415. package/apps/web/dist/assets/index-Drw7FMTQ.js +14 -0
  416. package/apps/web/dist/assets/jsx-runtime-BNakU3Ej.js +1 -0
  417. package/apps/web/dist/assets/lock-R_CfU0Xo.js +1 -0
  418. package/apps/web/dist/assets/oss-credits-cZ9NUaLZ.js +1 -0
  419. package/apps/web/dist/assets/pdfmake-Cx9scTbD.js +228 -0
  420. package/apps/web/dist/assets/phone-CgrIS4_-.js +1 -0
  421. package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
  422. package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
  423. package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
  424. package/apps/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
  425. package/apps/web/dist/assets/settings-menu-2IMOOlLl.js +1 -0
  426. package/apps/web/dist/assets/ui-dzGvc3xk.js +137 -0
  427. package/apps/web/dist/assets/upload-BSuTilFF.js +1 -0
  428. package/apps/web/dist/assets/vfs_fonts-DllDSYt1.js +1 -0
  429. package/apps/web/dist/embed.js +266 -0
  430. package/apps/web/dist/favicon.svg +1 -0
  431. package/apps/web/dist/icons/apple-touch-icon.png +0 -0
  432. package/apps/web/dist/icons/icon-192.png +0 -0
  433. package/apps/web/dist/icons/icon-512.png +0 -0
  434. package/apps/web/dist/icons/icon-maskable-512.png +0 -0
  435. package/apps/web/dist/index.html +48 -0
  436. package/apps/web/dist/install.sh +577 -0
  437. package/apps/web/dist/manifest.webmanifest +21 -0
  438. package/apps/web/dist/mcp/flow.html +980 -0
  439. package/apps/web/dist/sw.js +15 -0
  440. package/bin/wizards.mjs +288 -0
  441. package/modules/README.md +15 -0
  442. package/node_modules/@engenty/wizards/dist/plugin/index.d.ts +1150 -0
  443. package/node_modules/@engenty/wizards/dist/plugin/index.js +4 -0
  444. package/node_modules/@engenty/wizards/dist/plugin/studio.d.ts +322 -0
  445. package/node_modules/@engenty/wizards/dist/plugin/studio.js +4 -0
  446. package/node_modules/@engenty/wizards/dist/plugin/thread.d.ts +174 -0
  447. package/node_modules/@engenty/wizards/dist/plugin/thread.js +821 -0
  448. package/node_modules/@engenty/wizards/package.json +11 -0
  449. package/node_modules/@engenty-wizards/shared/dist/assistant.d.ts +174 -0
  450. package/node_modules/@engenty-wizards/shared/dist/assistant.js +65 -0
  451. package/node_modules/@engenty-wizards/shared/dist/changes.d.ts +22 -0
  452. package/node_modules/@engenty-wizards/shared/dist/changes.js +61 -0
  453. package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
  454. package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
  455. package/node_modules/@engenty-wizards/shared/dist/decision.d.ts +76 -0
  456. package/node_modules/@engenty-wizards/shared/dist/decision.js +147 -0
  457. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +2922 -0
  458. package/node_modules/@engenty-wizards/shared/dist/definition.js +1920 -0
  459. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
  460. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
  461. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
  462. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
  463. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
  464. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +217 -0
  465. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
  466. package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
  467. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
  468. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
  469. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
  470. package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
  471. package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +78 -0
  472. package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +70 -0
  473. package/node_modules/@engenty-wizards/shared/dist/features.d.ts +41 -0
  474. package/node_modules/@engenty-wizards/shared/dist/features.js +89 -0
  475. package/node_modules/@engenty-wizards/shared/dist/fit.d.ts +71 -0
  476. package/node_modules/@engenty-wizards/shared/dist/fit.js +382 -0
  477. package/node_modules/@engenty-wizards/shared/dist/json-schema.d.ts +14 -0
  478. package/node_modules/@engenty-wizards/shared/dist/json-schema.js +66 -0
  479. package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
  480. package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
  481. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
  482. package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +107 -0
  483. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
  484. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +136 -0
  485. package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +227 -0
  486. package/node_modules/@engenty-wizards/shared/dist/marketplace.js +354 -0
  487. package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
  488. package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
  489. package/node_modules/@engenty-wizards/shared/dist/numbers.d.ts +24 -0
  490. package/node_modules/@engenty-wizards/shared/dist/numbers.js +54 -0
  491. package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +224 -0
  492. package/node_modules/@engenty-wizards/shared/dist/projects.js +319 -0
  493. package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +101 -0
  494. package/node_modules/@engenty-wizards/shared/dist/providers.js +390 -0
  495. package/node_modules/@engenty-wizards/shared/dist/run.d.ts +680 -0
  496. package/node_modules/@engenty-wizards/shared/dist/run.js +620 -0
  497. package/node_modules/@engenty-wizards/shared/dist/runner-texts.d.ts +546 -0
  498. package/node_modules/@engenty-wizards/shared/dist/runner-texts.js +523 -0
  499. package/node_modules/@engenty-wizards/shared/dist/runners.d.ts +93 -0
  500. package/node_modules/@engenty-wizards/shared/dist/runners.js +146 -0
  501. package/node_modules/@engenty-wizards/shared/dist/shape.d.ts +102 -0
  502. package/node_modules/@engenty-wizards/shared/dist/shape.js +318 -0
  503. package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +89 -0
  504. package/node_modules/@engenty-wizards/shared/dist/space-data.js +47 -0
  505. package/node_modules/@engenty-wizards/shared/dist/store.d.ts +117 -0
  506. package/node_modules/@engenty-wizards/shared/dist/store.js +81 -0
  507. package/node_modules/@engenty-wizards/shared/dist/surface.d.ts +115 -0
  508. package/node_modules/@engenty-wizards/shared/dist/surface.js +442 -0
  509. package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +45 -0
  510. package/node_modules/@engenty-wizards/shared/dist/texts.js +54 -0
  511. package/node_modules/@engenty-wizards/shared/dist/translation.d.ts +23 -0
  512. package/node_modules/@engenty-wizards/shared/dist/translation.js +154 -0
  513. package/node_modules/@engenty-wizards/shared/dist/wizard-package.d.ts +48 -0
  514. package/node_modules/@engenty-wizards/shared/dist/wizard-package.js +49 -0
  515. package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
  516. package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
  517. package/node_modules/@engenty-wizards/shared/package.json +10 -0
  518. package/package.json +77 -4
  519. package/plugin/.claude-plugin/plugin.json +9 -0
  520. package/plugin/.mcp.json +8 -0
  521. package/plugin/commands/wizard.md +8 -0
  522. package/plugin/skills/build-wizard/SKILL.md +27 -0
  523. package/plugin/skills/use-wizard/SKILL.md +18 -0
@@ -0,0 +1,107 @@
1
+ import { GOOGLE_OAUTH2, googleJson } from "../engenty/connections-google/shared.js";
2
+ import { htmlToMarkdown } from "../render/convert.js";
3
+ import { dayAfter, mailActions, snippetOf, } from "./mail.js";
4
+ const GMAIL_API = "https://gmail.googleapis.com/gmail/v1/users/me";
5
+ const SCOPE_READONLY = "https://www.googleapis.com/auth/gmail.readonly";
6
+ const header = (payload, name) => payload?.headers?.find((h) => h.name.toLowerCase() === name.toLowerCase())?.value ?? null;
7
+ function body(payload, mime) {
8
+ if (!payload) {
9
+ return null;
10
+ }
11
+ if (payload.mimeType === mime && payload.body?.data) {
12
+ return Buffer.from(payload.body.data, "base64url").toString("utf8");
13
+ }
14
+ for (const part of payload.parts ?? []) {
15
+ const found = body(part, mime);
16
+ if (found) {
17
+ return found;
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+ function attachments(payload, out = []) {
23
+ if (payload?.filename && payload.body?.attachmentId) {
24
+ out.push({
25
+ id: payload.body.attachmentId,
26
+ name: payload.filename,
27
+ mime: payload.mimeType ?? "application/octet-stream",
28
+ size: payload.body.size ?? null,
29
+ });
30
+ }
31
+ for (const part of payload?.parts ?? []) {
32
+ attachments(part, out);
33
+ }
34
+ return out;
35
+ }
36
+ function toMessage(raw) {
37
+ const html = body(raw.payload, "text/html");
38
+ const text = body(raw.payload, "text/plain") ?? (html ? htmlToMarkdown(html) : (raw.snippet ?? ""));
39
+ return {
40
+ id: raw.id,
41
+ date: raw.internalDate ? new Date(Number(raw.internalDate)).toISOString() : null,
42
+ from: header(raw.payload, "From"),
43
+ to: (header(raw.payload, "To") ?? "")
44
+ .split(",")
45
+ .map((s) => s.trim())
46
+ .filter(Boolean),
47
+ subject: header(raw.payload, "Subject"),
48
+ snippet: raw.snippet ?? snippetOf(text),
49
+ attachments: attachments(raw.payload),
50
+ text,
51
+ html,
52
+ };
53
+ }
54
+ /** Gmail's own search syntax: `{a b}` is "a OR b", dates are `after:`/`before:` days. */
55
+ function query(input) {
56
+ const quoted = (input.terms ?? []).map((t) => (/\s/.test(t) ? `"${t.replace(/"/g, "")}"` : t));
57
+ return [
58
+ quoted.length ? `{${quoted.join(" ")}}` : "",
59
+ input.from ? `from:${input.from}` : "",
60
+ input.since ? `after:${input.since.replace(/-/g, "/")}` : "",
61
+ input.until ? `before:${dayAfter(input.until).replace(/-/g, "/")}` : "",
62
+ input.has_attachment ? "has:attachment" : "",
63
+ ]
64
+ .filter(Boolean)
65
+ .join(" ");
66
+ }
67
+ const getMessage = (ctx, id) => googleJson(ctx, `${GMAIL_API}/messages/${encodeURIComponent(id)}?format=full`);
68
+ const backend = {
69
+ async search(input, ctx) {
70
+ const url = new URL(`${GMAIL_API}/messages`);
71
+ url.searchParams.set("q", query(input));
72
+ url.searchParams.set("maxResults", String(input.limit ?? 40));
73
+ const list = await googleJson(ctx, url.toString());
74
+ const out = [];
75
+ const ids = (list.messages ?? []).map((m) => m.id);
76
+ for (let i = 0; i < ids.length; i += 10) {
77
+ const batch = await Promise.all(ids.slice(i, i + 10).map((id) => getMessage(ctx, id)));
78
+ out.push(...batch.map(toMessage));
79
+ }
80
+ return out.map(({ text: _text, html: _html, to: _to, ...summary }) => summary);
81
+ },
82
+ async read(id, ctx) {
83
+ return toMessage(await getMessage(ctx, id));
84
+ },
85
+ async attachment(id, attachmentId, ctx) {
86
+ const info = attachments((await getMessage(ctx, id)).payload).find((a) => a.id === attachmentId);
87
+ const data = await googleJson(ctx, `${GMAIL_API}/messages/${encodeURIComponent(id)}/attachments/${encodeURIComponent(attachmentId)}`);
88
+ if (!data.data) {
89
+ throw new Error("gmail attachment has no data");
90
+ }
91
+ return {
92
+ name: info?.name ?? "attachment",
93
+ mime: info?.mime ?? "application/octet-stream",
94
+ data_base64: Buffer.from(data.data, "base64url").toString("base64"),
95
+ };
96
+ },
97
+ };
98
+ export const gmailConnector = {
99
+ id: "mail-gmail",
100
+ moduleId: "wizards-mail",
101
+ name: "Gmail",
102
+ description: "Read mail in a Gmail or Google Workspace account.",
103
+ icon: "logo:gmail",
104
+ toolPrefix: "mail",
105
+ auth: { kind: "oauth2", oauth2: GOOGLE_OAUTH2 },
106
+ actions: mailActions(backend, [SCOPE_READONLY]),
107
+ };
@@ -0,0 +1,261 @@
1
+ import { resolveMx } from "node:dns/promises";
2
+ import { ImapFlow } from "imapflow";
3
+ import { htmlToMarkdown } from "../render/convert.js";
4
+ import { assertPublicUrl } from "../tools/net-guard.js";
5
+ import { dayAfter, mailActions, snippetOf, } from "./mail.js";
6
+ const KNOWN_HOSTS = {
7
+ "gmail.com": "imap.gmail.com",
8
+ "googlemail.com": "imap.gmail.com",
9
+ "outlook.com": "outlook.office365.com",
10
+ "hotmail.com": "outlook.office365.com",
11
+ "live.com": "outlook.office365.com",
12
+ "icloud.com": "imap.mail.me.com",
13
+ "me.com": "imap.mail.me.com",
14
+ "yahoo.com": "imap.mail.yahoo.com",
15
+ "gmx.at": "imap.gmx.net",
16
+ "gmx.de": "imap.gmx.net",
17
+ "gmx.net": "imap.gmx.net",
18
+ "web.de": "imap.web.de",
19
+ "a1.net": "securemail.a1.net",
20
+ "fastmail.com": "imap.fastmail.com",
21
+ };
22
+ const ALLOW_PRIVATE = process.env.ALLOW_PRIVATE_FETCH === "1";
23
+ /** A mail server that does not answer within this long is reported, not waited for. */
24
+ const CONNECT_TIMEOUT_MS = 15_000;
25
+ /** Google Workspace on a company domain: the domain's mail is handled by Google. */
26
+ async function usesGoogleMail(domain) {
27
+ try {
28
+ const records = await Promise.race([
29
+ resolveMx(domain),
30
+ new Promise((_, reject) => setTimeout(() => reject(new Error("mx")), 4000)),
31
+ ]);
32
+ return records.some((r) => /(^|\.)(google|googlemail)\.com\.?$/i.test(r.exchange));
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ async function hostFor(credentials, domain) {
39
+ const typed = credentials.host?.trim();
40
+ if (typed) {
41
+ return typed;
42
+ }
43
+ if (KNOWN_HOSTS[domain]) {
44
+ return KNOWN_HOSTS[domain];
45
+ }
46
+ return (await usesGoogleMail(domain)) ? "imap.gmail.com" : `imap.${domain}`;
47
+ }
48
+ async function open(credentials) {
49
+ const email = credentials.email.trim();
50
+ const domain = email.split("@")[1]?.toLowerCase() ?? "";
51
+ const host = await hostFor(credentials, domain);
52
+ const port = Number(credentials.port) || 993;
53
+ if (!ALLOW_PRIVATE && port !== 993 && port !== 143) {
54
+ throw new Error("IMAP runs on port 993 (or 143).");
55
+ }
56
+ // The host is typed by the person: it must be a public mail server, never this server's network.
57
+ await assertPublicUrl(`https://${host}`);
58
+ const client = new ImapFlow({
59
+ host,
60
+ port,
61
+ secure: port === 993,
62
+ auth: { user: email, pass: credentials.password },
63
+ logger: false,
64
+ socketTimeout: 60_000,
65
+ connectionTimeout: CONNECT_TIMEOUT_MS,
66
+ greetingTimeout: CONNECT_TIMEOUT_MS,
67
+ });
68
+ // A dropped connection must not take the process down.
69
+ client.on("error", () => undefined);
70
+ let timer;
71
+ try {
72
+ await Promise.race([
73
+ client.connect(),
74
+ new Promise((_, reject) => {
75
+ timer = setTimeout(() => reject(Object.assign(new Error("timeout"), { code: "ETIMEDOUT" })), CONNECT_TIMEOUT_MS + 2000);
76
+ }),
77
+ ]);
78
+ }
79
+ catch (err) {
80
+ client.close();
81
+ // The message names the server that was tried, so a wrong guess is visible.
82
+ throw Object.assign(err instanceof Error ? err : new Error(String(err)), { imapHost: host });
83
+ }
84
+ finally {
85
+ clearTimeout(timer);
86
+ }
87
+ return client;
88
+ }
89
+ /** Runs `use` on the mailbox that holds everything ("All Mail" where the server has one). */
90
+ async function withMailbox(ctx, use) {
91
+ const client = await open(JSON.parse(ctx.accessToken));
92
+ try {
93
+ const boxes = await client.list();
94
+ const all = boxes.find((b) => b.specialUse === "\\All");
95
+ const lock = await client.getMailboxLock(all?.path ?? "INBOX", { readOnly: true });
96
+ try {
97
+ return await use(client);
98
+ }
99
+ finally {
100
+ lock.release();
101
+ }
102
+ }
103
+ finally {
104
+ await client.logout().catch(() => undefined);
105
+ }
106
+ }
107
+ function parts(node, out) {
108
+ if (!node) {
109
+ return out;
110
+ }
111
+ const name = node.dispositionParameters?.filename ?? node.parameters?.name;
112
+ const part = node.part ?? "1";
113
+ if (node.childNodes?.length) {
114
+ for (const child of node.childNodes) {
115
+ parts(child, out);
116
+ }
117
+ }
118
+ else if (node.disposition === "attachment" || (name && !node.type.startsWith("text/"))) {
119
+ out.attachments.push({
120
+ id: part,
121
+ name: name ?? `attachment-${part}`,
122
+ mime: node.type,
123
+ size: node.size ?? null,
124
+ });
125
+ }
126
+ else if (node.type === "text/plain" && !out.plain) {
127
+ out.plain = part;
128
+ }
129
+ else if (node.type === "text/html" && !out.html) {
130
+ out.html = part;
131
+ }
132
+ return out;
133
+ }
134
+ const emptyParts = () => ({ attachments: [], plain: null, html: null });
135
+ function sender(from) {
136
+ const f = from?.[0];
137
+ return f?.address ? (f.name ? `${f.name} <${f.address}>` : f.address) : null;
138
+ }
139
+ async function bytes(client, uid, part) {
140
+ const { content } = await client.download(uid, part, { uid: true });
141
+ if (!content) {
142
+ throw new Error("The mail is no longer there.");
143
+ }
144
+ const chunks = [];
145
+ for await (const chunk of content) {
146
+ chunks.push(Buffer.from(chunk));
147
+ }
148
+ return Buffer.concat(chunks);
149
+ }
150
+ const backend = {
151
+ search: (input, ctx) => withMailbox(ctx, async (client) => {
152
+ const query = {};
153
+ if (input.since) {
154
+ query.since = input.since;
155
+ }
156
+ if (input.until) {
157
+ query.before = dayAfter(input.until);
158
+ }
159
+ if (input.from) {
160
+ query.from = input.from;
161
+ }
162
+ const terms = input.terms ?? [];
163
+ if (terms.length === 1) {
164
+ query.text = terms[0];
165
+ }
166
+ else if (terms.length > 1) {
167
+ query.or = terms.map((text) => ({ text }));
168
+ }
169
+ if (!Object.keys(query).length) {
170
+ query.all = true;
171
+ }
172
+ const found = (await client.search(query, { uid: true })) || [];
173
+ const limit = input.limit ?? 40;
174
+ // Without the attachment filter the newest `limit` are enough; with it, look further back.
175
+ const uids = found.slice(-(input.has_attachment ? limit * 4 : limit));
176
+ if (!uids.length) {
177
+ return [];
178
+ }
179
+ const messages = await client.fetchAll(uids, { envelope: true, bodyStructure: true, internalDate: true }, { uid: true });
180
+ return messages
181
+ .map((m) => ({
182
+ id: String(m.uid),
183
+ date: m.internalDate ? new Date(m.internalDate).toISOString() : null,
184
+ from: sender(m.envelope?.from),
185
+ subject: m.envelope?.subject ?? null,
186
+ snippet: "",
187
+ attachments: parts(m.bodyStructure, emptyParts()).attachments,
188
+ }))
189
+ .filter((m) => !input.has_attachment || m.attachments.length > 0)
190
+ .reverse()
191
+ .slice(0, limit);
192
+ }),
193
+ read: (id, ctx) => withMailbox(ctx, async (client) => {
194
+ const m = await client.fetchOne(id, { envelope: true, bodyStructure: true, internalDate: true }, { uid: true });
195
+ if (!m) {
196
+ throw new Error("The mail is no longer there.");
197
+ }
198
+ const found = parts(m.bodyStructure, emptyParts());
199
+ const html = found.html ? (await bytes(client, id, found.html)).toString("utf8") : null;
200
+ const text = found.plain
201
+ ? (await bytes(client, id, found.plain)).toString("utf8")
202
+ : html
203
+ ? htmlToMarkdown(html)
204
+ : "";
205
+ return {
206
+ id,
207
+ date: m.internalDate ? new Date(m.internalDate).toISOString() : null,
208
+ from: sender(m.envelope?.from),
209
+ to: (m.envelope?.to ?? []).map((t) => t.address ?? "").filter(Boolean),
210
+ subject: m.envelope?.subject ?? null,
211
+ snippet: snippetOf(text),
212
+ attachments: found.attachments,
213
+ text,
214
+ html,
215
+ };
216
+ }),
217
+ attachment: (id, attachmentId, ctx) => withMailbox(ctx, async (client) => {
218
+ const m = await client.fetchOne(id, { bodyStructure: true }, { uid: true });
219
+ const info = m
220
+ ? parts(m.bodyStructure, emptyParts()).attachments.find((a) => a.id === attachmentId)
221
+ : undefined;
222
+ if (!info) {
223
+ throw new Error("The mail has no such attachment.");
224
+ }
225
+ return {
226
+ name: info.name,
227
+ mime: info.mime,
228
+ data_base64: (await bytes(client, id, attachmentId)).toString("base64"),
229
+ };
230
+ }),
231
+ };
232
+ export const imapConnector = {
233
+ id: "imap",
234
+ moduleId: "wizards-mail",
235
+ name: "IMAP",
236
+ description: "Read mail in any mailbox over IMAP (GMX, iCloud, your own domain …).",
237
+ icon: "mail",
238
+ toolPrefix: "mail",
239
+ auth: {
240
+ kind: "api_key",
241
+ apiKey: {
242
+ fields: [
243
+ { key: "email", label: "Email address", placeholder: "name@company.com" },
244
+ { key: "password", label: "Password or app password", secret: true },
245
+ {
246
+ key: "host",
247
+ label: "IMAP server",
248
+ placeholder: "leave empty for Gmail, GMX, iCloud …",
249
+ required: false,
250
+ },
251
+ { key: "port", label: "Port", placeholder: "993", required: false },
252
+ ],
253
+ verify: async (credentials) => {
254
+ const client = await open(credentials);
255
+ await client.logout().catch(() => undefined);
256
+ return { label: credentials.email.trim(), externalId: credentials.email.trim() };
257
+ },
258
+ },
259
+ },
260
+ actions: mailActions(backend, []),
261
+ };
@@ -0,0 +1,325 @@
1
+ import { isLang } from "@engenty-wizards/shared/definition";
2
+ import { note } from "@engenty-wizards/shared/run";
3
+ import { eq } from "drizzle-orm";
4
+ import { db, schema } from "../db/client.js";
5
+ import { buildAuthorizationUrl, createOAuth2Pkce, exchangeAuthorizationCode, refreshAccessToken, } from "../engenty/connections-sdk/oauth2.js";
6
+ import { scopesForGroups, } from "../engenty/connections-sdk/types.js";
7
+ import { env } from "../env.js";
8
+ import { NotedError } from "../model-errors.js";
9
+ import { seal, unseal } from "../secrets/crypto.js";
10
+ import { deleteSecret, getSecret, putSecret } from "../store/index.js";
11
+ import { serverText } from "../texts.js";
12
+ import { connectorFetch, MAIL_CONNECTORS, resolveEnv, usable, viaAccount } from "./builtin.js";
13
+ import { resolveConnector } from "./external.js";
14
+ import { AccountConnectError, redeemTicket, refreshThroughAccount, startThroughAccount, } from "./via-account.js";
15
+ /** The connectors a person can pick for each kind of connection. */
16
+ const CONNECTORS = { mail: MAIL_CONNECTORS };
17
+ const HINTS = { imap: "imapHint" };
18
+ /** The built-in connectors' fields in each language; their definitions say them in English. */
19
+ const FIELD_WORDS = {
20
+ de: {
21
+ imap: {
22
+ email: { label: "E-Mail-Adresse", placeholder: "name@firma.at" },
23
+ password: { label: "Passwort oder App-Passwort" },
24
+ host: { label: "IMAP-Server", placeholder: "leer lassen bei Gmail, GMX, iCloud …" },
25
+ },
26
+ },
27
+ };
28
+ /**
29
+ * What a connection asks the provider for: what reading needs, plus what each action the wizard
30
+ * may use needs. A wizard that only reads never asks for the right to send or delete.
31
+ */
32
+ function scopesFor(connection, connector) {
33
+ const scopes = new Set(scopesForGroups(connector, new Set(["read"])));
34
+ for (const action of connector.actions) {
35
+ if (connection.actions?.includes(action.id)) {
36
+ for (const scope of action.providerScopes ?? []) {
37
+ scopes.add(scope);
38
+ }
39
+ }
40
+ }
41
+ return [...scopes];
42
+ }
43
+ /** Where the provider sends the person back; must be registered with the OAuth client. */
44
+ export function connectRedirectUri() {
45
+ return env.connectRedirectUrl || `${env.appUrl}/api/connect/callback`;
46
+ }
47
+ const slot = (connectionId) => `connection:${connectionId}`;
48
+ /** A connector that needs no credential: there is nothing for the person to connect. */
49
+ const open = (connector) => connector.auth.kind === "api_key" && connector.auth.apiKey.fields.length === 0;
50
+ /** The connectors behind a connection: the built-in ones of its kind, or the one it names. */
51
+ async function candidates(connection, projectId) {
52
+ if (connection.connector) {
53
+ const found = await resolveConnector(projectId, connection.connector);
54
+ return found ? [found.connector] : [];
55
+ }
56
+ return connection.kind ? CONNECTORS[connection.kind] : [];
57
+ }
58
+ export async function connectorOptions(connection, projectId, lang = "en") {
59
+ const out = [];
60
+ for (const c of await candidates(connection, projectId)) {
61
+ if (!(await usable(c))) {
62
+ continue;
63
+ }
64
+ out.push(c.auth.kind === "api_key"
65
+ ? {
66
+ id: c.id,
67
+ name: c.name,
68
+ auth: "api_key",
69
+ fields: c.auth.apiKey.fields.map((f) => ({
70
+ ...f,
71
+ ...(lang === "en" ? undefined : FIELD_WORDS[lang]?.[c.id]?.[f.key]),
72
+ })),
73
+ hint: HINTS[c.id] && serverText(lang, HINTS[c.id]),
74
+ }
75
+ : { id: c.id, name: c.name, auth: "oauth2" });
76
+ }
77
+ return out;
78
+ }
79
+ async function connectorFor(connection, connectorId, projectId) {
80
+ const connector = (await candidates(connection, projectId)).find((c) => c.id === connectorId);
81
+ if (!connector) {
82
+ throw new Error(`Unknown connector "${connectorId}".`);
83
+ }
84
+ return connector;
85
+ }
86
+ export async function connectionViews(connections, scope, projectId,
87
+ /** The language the person reads the connectors' fields in. */
88
+ lang = "en") {
89
+ return Promise.all(connections.map(async (c) => {
90
+ const stored = await getSecret(scope, slot(c.id));
91
+ const only = c.connector ? (await candidates(c, projectId))[0] : undefined;
92
+ return {
93
+ id: c.id,
94
+ kind: c.kind ?? null,
95
+ connector: c.connector ?? null,
96
+ title: c.title ?? only?.name ?? null,
97
+ description: c.description ?? null,
98
+ account: stored
99
+ ? {
100
+ connector: stored.provider,
101
+ label: stored.label,
102
+ connectedAt: stored.createdAt.toISOString(),
103
+ }
104
+ : only && open(only)
105
+ ? { connector: only.id, label: only.name, connectedAt: new Date(0).toISOString() }
106
+ : null,
107
+ connectors: await connectorOptions(c, projectId, lang),
108
+ };
109
+ }));
110
+ }
111
+ export async function startOAuth(scope, projectId, runId, connection, connectorId, lang) {
112
+ const connector = await connectorFor(connection, connectorId, projectId);
113
+ if (connector.auth.kind !== "oauth2") {
114
+ throw new Error(`${connector.name} is not connected by signing in.`);
115
+ }
116
+ if (await viaAccount(connector)) {
117
+ // The Manage-App keeps the PKCE verifier; ours stays empty.
118
+ const state = {
119
+ scope,
120
+ projectId,
121
+ runId,
122
+ connectionId: connection.id,
123
+ connectorId,
124
+ verifier: "",
125
+ exp: Date.now() + 15 * 60_000,
126
+ lang,
127
+ };
128
+ try {
129
+ return await startThroughAccount(scopesFor(connection, connector), seal(state), connectRedirectUri());
130
+ }
131
+ catch (err) {
132
+ throw err instanceof AccountConnectError ? new ConnectError(err.message) : err;
133
+ }
134
+ }
135
+ // Servers that hand out OAuth clients on request (most MCP servers): get one on first use.
136
+ await connector.auth.oauth2.registerClient?.();
137
+ const pkce = createOAuth2Pkce();
138
+ const state = {
139
+ scope,
140
+ projectId,
141
+ runId,
142
+ connectionId: connection.id,
143
+ connectorId,
144
+ verifier: pkce.codeVerifier,
145
+ exp: Date.now() + 15 * 60_000,
146
+ lang,
147
+ };
148
+ return buildAuthorizationUrl({
149
+ connector,
150
+ pkce,
151
+ redirectUri: connectRedirectUri(),
152
+ scopes: scopesFor(connection, connector),
153
+ state: seal(state),
154
+ resolveEnv,
155
+ });
156
+ }
157
+ /** The language a sign-in was started in, a wizard's or a plugin's; null where it names none. */
158
+ export function oauthStateLang(rawState) {
159
+ const lang = unseal(rawState)?.lang;
160
+ return isLang(lang) ? lang : null;
161
+ }
162
+ /** The run an OAuth callback belongs to; its tenant is looked up before the state is used. */
163
+ export function oauthStateRun(rawState) {
164
+ return unseal(rawState)?.runId ?? null;
165
+ }
166
+ /**
167
+ * Google came back: with a code, or — connected through the account's Manage-App — with a
168
+ * ticket that holds the tokens.
169
+ */
170
+ export async function finishOAuth(answer, rawState) {
171
+ const state = unseal(rawState);
172
+ if (!state || state.exp < Date.now()) {
173
+ throw new Error("The sign-in has expired. Connect again.");
174
+ }
175
+ const run = await db.query.run.findFirst({ where: eq(schema.run.id, state.runId) });
176
+ const connection = run?.definition.connections?.find((c) => c.id === state.connectionId);
177
+ if (!connection) {
178
+ throw new Error("The run this sign-in belongs to is gone.");
179
+ }
180
+ const connector = await connectorFor(connection, state.connectorId, state.projectId);
181
+ if (connector.auth.kind !== "oauth2") {
182
+ throw new Error("not an oauth connector");
183
+ }
184
+ const tokens = "ticket" in answer
185
+ ? await redeemTicket(answer.ticket)
186
+ : await exchangeAuthorizationCode({
187
+ code: answer.code,
188
+ codeVerifier: state.verifier,
189
+ config: connector.auth.oauth2,
190
+ redirectUri: connectRedirectUri(),
191
+ resolveEnv,
192
+ });
193
+ // A provider that will not name the account still connected it.
194
+ const account = (await connector.auth.oauth2
195
+ .resolveAccount?.(tokens.accessToken, fetch)
196
+ .catch(() => null)) ?? { label: connector.name };
197
+ const stored = {
198
+ accessToken: tokens.accessToken,
199
+ refreshToken: tokens.refreshToken,
200
+ expiresAt: tokens.expiresAt?.toISOString() ?? null,
201
+ scopes: tokens.grantedScopes,
202
+ ...("ticket" in answer ? { via: "account" } : {}),
203
+ };
204
+ await putSecret(state.scope, slot(connection.id), connector.id, account.label, stored);
205
+ return state;
206
+ }
207
+ /** Connects an `api_key` connector with what the person typed; the connector checks it first. */
208
+ export async function connectWithCredentials(scope, projectId, connection, connectorId, values) {
209
+ const connector = await connectorFor(connection, connectorId, projectId);
210
+ if (connector.auth.kind !== "api_key") {
211
+ throw new Error(`${connector.name} is connected by signing in.`);
212
+ }
213
+ const credentials = {};
214
+ for (const field of connector.auth.apiKey.fields) {
215
+ const value = String(values[field.key] ?? "").trim();
216
+ if (!value && field.required !== false) {
217
+ throw new ConnectError(note("fieldMissing", { label: field.label }));
218
+ }
219
+ if (value) {
220
+ credentials[field.key] = value.slice(0, 500);
221
+ }
222
+ }
223
+ let account;
224
+ try {
225
+ account = await connector.auth.apiKey.verify(credentials, connectorFetch);
226
+ }
227
+ catch (err) {
228
+ throw new ConnectError(connectFailure(err));
229
+ }
230
+ const stored = {
231
+ accessToken: JSON.stringify(credentials),
232
+ refreshToken: null,
233
+ expiresAt: null,
234
+ scopes: [],
235
+ };
236
+ await putSecret(scope, slot(connection.id), connector.id, account.label, stored);
237
+ return account.label;
238
+ }
239
+ /** A connect attempt the person can fix (wrong password, unknown server). */
240
+ export class ConnectError extends NotedError {
241
+ }
242
+ function connectFailure(err) {
243
+ const e = err;
244
+ const host = e.imapHost ? ` (${e.imapHost})` : "";
245
+ if (e.authenticationFailed) {
246
+ const answer = e.responseText?.slice(0, 160);
247
+ return note("signInRefused", { host, answer: answer ? note("serverSaid", { answer }) : "" });
248
+ }
249
+ if (e.code === "ENOTFOUND") {
250
+ return note("mailServerNotExist", { host });
251
+ }
252
+ if (e.code === "ETIMEDOUT" || e.code === "ETIMEOUT" || e.code === "ECONNREFUSED") {
253
+ return note("mailServerNotResponding", { host });
254
+ }
255
+ const detail = String(e.message ?? err).slice(0, 200);
256
+ return note("connectingNotWork", { host, detail });
257
+ }
258
+ export function disconnect(scope, connectionId) {
259
+ return deleteSecret(scope, slot(connectionId));
260
+ }
261
+ // --- using ---------------------------------------------------------------------
262
+ /**
263
+ * The connector and the context its actions run with, for a connection the person has
264
+ * connected — with a fresh access token. `null` when nothing is connected.
265
+ */
266
+ export async function connectionContext(scope, connection, projectId) {
267
+ const stored = await getSecret(scope, slot(connection.id));
268
+ if (!stored) {
269
+ const only = connection.connector ? (await candidates(connection, projectId))[0] : undefined;
270
+ return only && open(only)
271
+ ? { connector: only, label: only.name, ctx: actionContext(scope, connection, only, "{}", []) }
272
+ : null;
273
+ }
274
+ const connector = await connectorFor(connection, stored.provider, projectId);
275
+ let data = stored.data;
276
+ const expires = data.expiresAt ? Date.parse(data.expiresAt) : null;
277
+ if (connector.auth.kind === "oauth2" &&
278
+ data.refreshToken &&
279
+ expires !== null &&
280
+ expires - Date.now() < 5 * 60_000) {
281
+ const tokens = data.via === "account"
282
+ ? await refreshThroughAccount(data.refreshToken)
283
+ : await refreshAccessToken({
284
+ config: connector.auth.oauth2,
285
+ refreshToken: data.refreshToken,
286
+ resolveEnv,
287
+ });
288
+ data = {
289
+ ...(data.via ? { via: data.via } : {}),
290
+ accessToken: tokens.accessToken,
291
+ refreshToken: tokens.refreshToken ?? data.refreshToken,
292
+ expiresAt: tokens.expiresAt?.toISOString() ?? null,
293
+ scopes: tokens.grantedScopes.length ? tokens.grantedScopes : data.scopes,
294
+ };
295
+ await putSecret(scope, slot(connection.id), connector.id, stored.label, data);
296
+ }
297
+ return {
298
+ connector,
299
+ label: stored.label,
300
+ ctx: actionContext(scope, connection, connector, data.accessToken, data.scopes, stored),
301
+ };
302
+ }
303
+ function actionContext(scope, connection, connector, accessToken, scopes, stored) {
304
+ return {
305
+ accessToken,
306
+ fetchImpl: connectorFetch,
307
+ log: () => undefined,
308
+ connection: {
309
+ id: connection.id,
310
+ connector_id: connector.id,
311
+ auth_kind: connector.auth.kind,
312
+ autonomous_mode: "read_only",
313
+ connected_by: null,
314
+ created_at: (stored?.createdAt ?? new Date()).toISOString(),
315
+ display_name: stored?.label ?? connector.name,
316
+ error_message: null,
317
+ external_account: stored?.label ?? null,
318
+ granted_scopes: scopes,
319
+ owner_user_id: null,
320
+ space_id: null,
321
+ status: "active",
322
+ tenant_id: scope.wizardId,
323
+ },
324
+ };
325
+ }