@withbuddi/buddi 0.1.0-pre.42 → 0.1.0-pre.44

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 (647) hide show
  1. package/examples/agents/agent-father/agent.md +12 -5
  2. package/examples/agents/concierge/agent.md +11 -3
  3. package/extension/icons/128.png +0 -0
  4. package/extension/icons/16.png +0 -0
  5. package/extension/icons/32.png +0 -0
  6. package/extension/icons/48.png +0 -0
  7. package/extension/manifest.json +7 -3
  8. package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
  9. package/node_modules/@buddi/cli/dist/access-cmd.d.ts +2 -1
  10. package/node_modules/@buddi/cli/dist/access-cmd.d.ts.map +1 -1
  11. package/node_modules/@buddi/cli/dist/access-cmd.js +40 -7
  12. package/node_modules/@buddi/cli/dist/access-cmd.js.map +1 -1
  13. package/node_modules/@buddi/cli/dist/args.d.ts +2 -1
  14. package/node_modules/@buddi/cli/dist/args.d.ts.map +1 -1
  15. package/node_modules/@buddi/cli/dist/args.js +7 -3
  16. package/node_modules/@buddi/cli/dist/args.js.map +1 -1
  17. package/node_modules/@buddi/cli/dist/commands.d.ts.map +1 -1
  18. package/node_modules/@buddi/cli/dist/commands.js +3 -2
  19. package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
  20. package/node_modules/@buddi/cli/dist/doctor-probes.d.ts.map +1 -1
  21. package/node_modules/@buddi/cli/dist/doctor-probes.js +10 -1
  22. package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
  23. package/node_modules/@buddi/cli/dist/doctor.d.ts +9 -0
  24. package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
  25. package/node_modules/@buddi/cli/dist/doctor.js +21 -3
  26. package/node_modules/@buddi/cli/dist/doctor.js.map +1 -1
  27. package/node_modules/@buddi/cli/dist/main.js +1 -1
  28. package/node_modules/@buddi/cli/dist/main.js.map +1 -1
  29. package/node_modules/@buddi/cli/dist/mcp/server.js +1 -1
  30. package/node_modules/@buddi/cli/dist/mcp/server.js.map +1 -1
  31. package/node_modules/@buddi/cli/dist/mcp/tools.d.ts.map +1 -1
  32. package/node_modules/@buddi/cli/dist/mcp/tools.js +60 -0
  33. package/node_modules/@buddi/cli/dist/mcp/tools.js.map +1 -1
  34. package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
  35. package/node_modules/@buddi/core/dist/agents/catalog.js +1 -1
  36. package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
  37. package/node_modules/@buddi/core/dist/lock.d.ts +15 -1
  38. package/node_modules/@buddi/core/dist/lock.d.ts.map +1 -1
  39. package/node_modules/@buddi/core/dist/lock.js +15 -1
  40. package/node_modules/@buddi/core/dist/lock.js.map +1 -1
  41. package/node_modules/@buddi/core/dist/pages.d.ts +75 -0
  42. package/node_modules/@buddi/core/dist/pages.d.ts.map +1 -1
  43. package/node_modules/@buddi/core/dist/pages.js +14 -0
  44. package/node_modules/@buddi/core/dist/pages.js.map +1 -1
  45. package/node_modules/@buddi/core/dist/plugin/index.d.ts +2 -2
  46. package/node_modules/@buddi/core/dist/plugin/index.d.ts.map +1 -1
  47. package/node_modules/@buddi/core/dist/plugin/index.js.map +1 -1
  48. package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
  49. package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
  50. package/node_modules/@buddi/core/dist/provider-accounts.d.ts +32 -0
  51. package/node_modules/@buddi/core/dist/provider-accounts.d.ts.map +1 -1
  52. package/node_modules/@buddi/core/dist/provider-accounts.js +22 -0
  53. package/node_modules/@buddi/core/dist/provider-accounts.js.map +1 -1
  54. package/node_modules/@buddi/core/dist/testing/database-url.d.ts +13 -0
  55. package/node_modules/@buddi/core/dist/testing/database-url.d.ts.map +1 -1
  56. package/node_modules/@buddi/core/dist/testing/database-url.js +34 -0
  57. package/node_modules/@buddi/core/dist/testing/database-url.js.map +1 -1
  58. package/node_modules/@buddi/core/dist/testing/isolated-global-setup.d.ts +2 -0
  59. package/node_modules/@buddi/core/dist/testing/isolated-global-setup.d.ts.map +1 -0
  60. package/node_modules/@buddi/core/dist/testing/isolated-global-setup.js +20 -0
  61. package/node_modules/@buddi/core/dist/testing/isolated-global-setup.js.map +1 -0
  62. package/node_modules/@buddi/core/migrations/077_lock_background_portrait.sql +5 -0
  63. package/node_modules/@buddi/core/package.json +4 -0
  64. package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
  65. package/node_modules/@buddi/gateway/dist/agents/owner-tools.d.ts +21 -8
  66. package/node_modules/@buddi/gateway/dist/agents/owner-tools.d.ts.map +1 -1
  67. package/node_modules/@buddi/gateway/dist/agents/owner-tools.js +201 -36
  68. package/node_modules/@buddi/gateway/dist/agents/owner-tools.js.map +1 -1
  69. package/node_modules/@buddi/gateway/dist/agents/platform.d.ts +8 -0
  70. package/node_modules/@buddi/gateway/dist/agents/platform.d.ts.map +1 -1
  71. package/node_modules/@buddi/gateway/dist/agents/platform.js +48 -22
  72. package/node_modules/@buddi/gateway/dist/agents/platform.js.map +1 -1
  73. package/node_modules/@buddi/gateway/dist/evals/golden.d.ts +5 -0
  74. package/node_modules/@buddi/gateway/dist/evals/golden.d.ts.map +1 -1
  75. package/node_modules/@buddi/gateway/dist/evals/golden.js +48 -0
  76. package/node_modules/@buddi/gateway/dist/evals/golden.js.map +1 -1
  77. package/node_modules/@buddi/gateway/dist/mcp/requests.d.ts +8 -2
  78. package/node_modules/@buddi/gateway/dist/mcp/requests.d.ts.map +1 -1
  79. package/node_modules/@buddi/gateway/dist/mcp/requests.js +74 -1
  80. package/node_modules/@buddi/gateway/dist/mcp/requests.js.map +1 -1
  81. package/node_modules/@buddi/gateway/dist/owner-profile-edit.d.ts +160 -0
  82. package/node_modules/@buddi/gateway/dist/owner-profile-edit.d.ts.map +1 -0
  83. package/node_modules/@buddi/gateway/dist/owner-profile-edit.js +296 -0
  84. package/node_modules/@buddi/gateway/dist/owner-profile-edit.js.map +1 -0
  85. package/node_modules/@buddi/gateway/dist/plugins/index.d.ts +1 -0
  86. package/node_modules/@buddi/gateway/dist/plugins/index.d.ts.map +1 -1
  87. package/node_modules/@buddi/gateway/dist/plugins/index.js +1 -0
  88. package/node_modules/@buddi/gateway/dist/plugins/index.js.map +1 -1
  89. package/node_modules/@buddi/gateway/dist/plugins/pages-state.d.ts +37 -0
  90. package/node_modules/@buddi/gateway/dist/plugins/pages-state.d.ts.map +1 -0
  91. package/node_modules/@buddi/gateway/dist/plugins/pages-state.js +98 -0
  92. package/node_modules/@buddi/gateway/dist/plugins/pages-state.js.map +1 -0
  93. package/node_modules/@buddi/gateway/dist/provider-accounts.d.ts +33 -4
  94. package/node_modules/@buddi/gateway/dist/provider-accounts.d.ts.map +1 -1
  95. package/node_modules/@buddi/gateway/dist/provider-accounts.js +82 -18
  96. package/node_modules/@buddi/gateway/dist/provider-accounts.js.map +1 -1
  97. package/node_modules/@buddi/gateway/dist/provider-diagnostics.d.ts +5 -0
  98. package/node_modules/@buddi/gateway/dist/provider-diagnostics.d.ts.map +1 -1
  99. package/node_modules/@buddi/gateway/dist/provider-diagnostics.js +6 -1
  100. package/node_modules/@buddi/gateway/dist/provider-diagnostics.js.map +1 -1
  101. package/node_modules/@buddi/gateway/dist/serve.d.ts.map +1 -1
  102. package/node_modules/@buddi/gateway/dist/serve.js +5 -2
  103. package/node_modules/@buddi/gateway/dist/serve.js.map +1 -1
  104. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-connector.d.ts +63 -0
  105. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-connector.d.ts.map +1 -0
  106. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-connector.js +87 -0
  107. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-connector.js.map +1 -0
  108. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts +39 -4
  109. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -1
  110. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js +99 -11
  111. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js.map +1 -1
  112. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js +1 -1
  113. package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js.map +1 -1
  114. package/node_modules/@buddi/gateway/dist/web/access/index.d.ts +1 -0
  115. package/node_modules/@buddi/gateway/dist/web/access/index.d.ts.map +1 -1
  116. package/node_modules/@buddi/gateway/dist/web/access/index.js +1 -0
  117. package/node_modules/@buddi/gateway/dist/web/access/index.js.map +1 -1
  118. package/node_modules/@buddi/gateway/dist/web/agent-offers.d.ts +6 -0
  119. package/node_modules/@buddi/gateway/dist/web/agent-offers.d.ts.map +1 -1
  120. package/node_modules/@buddi/gateway/dist/web/agent-offers.js +6 -0
  121. package/node_modules/@buddi/gateway/dist/web/agent-offers.js.map +1 -1
  122. package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
  123. package/node_modules/@buddi/gateway/dist/web/api-routes.js +24 -3
  124. package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
  125. package/node_modules/@buddi/gateway/dist/web/attention.d.ts +11 -1
  126. package/node_modules/@buddi/gateway/dist/web/attention.d.ts.map +1 -1
  127. package/node_modules/@buddi/gateway/dist/web/attention.js +22 -2
  128. package/node_modules/@buddi/gateway/dist/web/attention.js.map +1 -1
  129. package/node_modules/@buddi/gateway/dist/web/chat.d.ts +0 -2
  130. package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
  131. package/node_modules/@buddi/gateway/dist/web/chat.js +15 -4
  132. package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
  133. package/node_modules/@buddi/gateway/dist/web/lock-backgrounds.d.ts +9 -0
  134. package/node_modules/@buddi/gateway/dist/web/lock-backgrounds.d.ts.map +1 -0
  135. package/node_modules/@buddi/gateway/dist/web/lock-backgrounds.js +60 -0
  136. package/node_modules/@buddi/gateway/dist/web/lock-backgrounds.js.map +1 -0
  137. package/node_modules/@buddi/gateway/dist/web/lock.d.ts +22 -1
  138. package/node_modules/@buddi/gateway/dist/web/lock.d.ts.map +1 -1
  139. package/node_modules/@buddi/gateway/dist/web/lock.js +87 -24
  140. package/node_modules/@buddi/gateway/dist/web/lock.js.map +1 -1
  141. package/node_modules/@buddi/gateway/dist/web/places.d.ts +5 -0
  142. package/node_modules/@buddi/gateway/dist/web/places.d.ts.map +1 -1
  143. package/node_modules/@buddi/gateway/dist/web/places.js +11 -4
  144. package/node_modules/@buddi/gateway/dist/web/places.js.map +1 -1
  145. package/node_modules/@buddi/gateway/dist/web/plugins.d.ts.map +1 -1
  146. package/node_modules/@buddi/gateway/dist/web/plugins.js +4 -0
  147. package/node_modules/@buddi/gateway/dist/web/plugins.js.map +1 -1
  148. package/node_modules/@buddi/gateway/dist/web/server.d.ts +3 -0
  149. package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
  150. package/node_modules/@buddi/gateway/dist/web/server.js +48 -49
  151. package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
  152. package/node_modules/@buddi/gateway/dist/web/take-on.d.ts +3 -1
  153. package/node_modules/@buddi/gateway/dist/web/take-on.d.ts.map +1 -1
  154. package/node_modules/@buddi/gateway/dist/web/take-on.js +14 -3
  155. package/node_modules/@buddi/gateway/dist/web/take-on.js.map +1 -1
  156. package/node_modules/@buddi/gateway/dist/web/telegram.d.ts.map +1 -1
  157. package/node_modules/@buddi/gateway/dist/web/telegram.js +4 -2
  158. package/node_modules/@buddi/gateway/dist/web/telegram.js.map +1 -1
  159. package/node_modules/@buddi/gateway/dist/web/version.d.ts +10 -0
  160. package/node_modules/@buddi/gateway/dist/web/version.d.ts.map +1 -1
  161. package/node_modules/@buddi/gateway/dist/web/version.js +12 -0
  162. package/node_modules/@buddi/gateway/dist/web/version.js.map +1 -1
  163. package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
  164. package/node_modules/@buddi/install/dist/backup.d.ts +12 -0
  165. package/node_modules/@buddi/install/dist/backup.d.ts.map +1 -1
  166. package/node_modules/@buddi/install/dist/backup.js +26 -8
  167. package/node_modules/@buddi/install/dist/backup.js.map +1 -1
  168. package/node_modules/@buddi/install/dist/cloudflared.d.ts +121 -0
  169. package/node_modules/@buddi/install/dist/cloudflared.d.ts.map +1 -0
  170. package/node_modules/@buddi/install/dist/cloudflared.js +451 -0
  171. package/node_modules/@buddi/install/dist/cloudflared.js.map +1 -0
  172. package/node_modules/@buddi/install/dist/index.d.ts +1 -0
  173. package/node_modules/@buddi/install/dist/index.d.ts.map +1 -1
  174. package/node_modules/@buddi/install/dist/index.js +1 -0
  175. package/node_modules/@buddi/install/dist/index.js.map +1 -1
  176. package/node_modules/@buddi/install/dist/supervisor.d.ts +6 -1
  177. package/node_modules/@buddi/install/dist/supervisor.d.ts.map +1 -1
  178. package/node_modules/@buddi/install/dist/supervisor.js +51 -5
  179. package/node_modules/@buddi/install/dist/supervisor.js.map +1 -1
  180. package/node_modules/@buddi/install/dist/upgrade.d.ts +2 -0
  181. package/node_modules/@buddi/install/dist/upgrade.d.ts.map +1 -1
  182. package/node_modules/@buddi/install/dist/upgrade.js +3 -2
  183. package/node_modules/@buddi/install/dist/upgrade.js.map +1 -1
  184. package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
  185. package/node_modules/@buddi/runtime/dist/codex-direct.d.ts +12 -1
  186. package/node_modules/@buddi/runtime/dist/codex-direct.d.ts.map +1 -1
  187. package/node_modules/@buddi/runtime/dist/codex-direct.js +15 -6
  188. package/node_modules/@buddi/runtime/dist/codex-direct.js.map +1 -1
  189. package/node_modules/@buddi/runtime/dist/groups.d.ts +5 -4
  190. package/node_modules/@buddi/runtime/dist/groups.d.ts.map +1 -1
  191. package/node_modules/@buddi/runtime/dist/groups.js +7 -6
  192. package/node_modules/@buddi/runtime/dist/groups.js.map +1 -1
  193. package/node_modules/@buddi/runtime/dist/provider-models.d.ts +4 -0
  194. package/node_modules/@buddi/runtime/dist/provider-models.d.ts.map +1 -1
  195. package/node_modules/@buddi/runtime/dist/provider-models.js.map +1 -1
  196. package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
  197. package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
  198. package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
  199. package/node_modules/@buddi/tool-email/dist/html.d.ts +16 -0
  200. package/node_modules/@buddi/tool-email/dist/html.d.ts.map +1 -0
  201. package/node_modules/@buddi/tool-email/dist/html.js +273 -0
  202. package/node_modules/@buddi/tool-email/dist/html.js.map +1 -0
  203. package/node_modules/@buddi/tool-email/dist/imap/imapflow-client.d.ts +7 -0
  204. package/node_modules/@buddi/tool-email/dist/imap/imapflow-client.d.ts.map +1 -1
  205. package/node_modules/@buddi/tool-email/dist/imap/imapflow-client.js +53 -0
  206. package/node_modules/@buddi/tool-email/dist/imap/imapflow-client.js.map +1 -1
  207. package/node_modules/@buddi/tool-email/dist/mail.d.ts.map +1 -1
  208. package/node_modules/@buddi/tool-email/dist/mail.js +4 -0
  209. package/node_modules/@buddi/tool-email/dist/mail.js.map +1 -1
  210. package/node_modules/@buddi/tool-email/dist/pages/descriptors.d.ts.map +1 -1
  211. package/node_modules/@buddi/tool-email/dist/pages/descriptors.js +250 -176
  212. package/node_modules/@buddi/tool-email/dist/pages/descriptors.js.map +1 -1
  213. package/node_modules/@buddi/tool-email/dist/pages/index.d.ts +1 -0
  214. package/node_modules/@buddi/tool-email/dist/pages/index.d.ts.map +1 -1
  215. package/node_modules/@buddi/tool-email/dist/pages/index.js +3 -0
  216. package/node_modules/@buddi/tool-email/dist/pages/index.js.map +1 -1
  217. package/node_modules/@buddi/tool-email/dist/pages/queries.d.ts +28 -1
  218. package/node_modules/@buddi/tool-email/dist/pages/queries.d.ts.map +1 -1
  219. package/node_modules/@buddi/tool-email/dist/pages/queries.js +362 -66
  220. package/node_modules/@buddi/tool-email/dist/pages/queries.js.map +1 -1
  221. package/node_modules/@buddi/tool-email/dist/pages/thread-tools.d.ts +25 -0
  222. package/node_modules/@buddi/tool-email/dist/pages/thread-tools.d.ts.map +1 -0
  223. package/node_modules/@buddi/tool-email/dist/pages/thread-tools.js +33 -0
  224. package/node_modules/@buddi/tool-email/dist/pages/thread-tools.js.map +1 -0
  225. package/node_modules/@buddi/tool-email/dist/ports.d.ts +10 -0
  226. package/node_modules/@buddi/tool-email/dist/ports.d.ts.map +1 -1
  227. package/node_modules/@buddi/tool-email/dist/ports.js.map +1 -1
  228. package/node_modules/@buddi/tool-email/dist/retention.d.ts.map +1 -1
  229. package/node_modules/@buddi/tool-email/dist/retention.js +1 -0
  230. package/node_modules/@buddi/tool-email/dist/retention.js.map +1 -1
  231. package/node_modules/@buddi/tool-email/dist/sources/inbox-poll.d.ts.map +1 -1
  232. package/node_modules/@buddi/tool-email/dist/sources/inbox-poll.js +9 -2
  233. package/node_modules/@buddi/tool-email/dist/sources/inbox-poll.js.map +1 -1
  234. package/node_modules/@buddi/tool-email/migrations/027_first_contact.sql +13 -0
  235. package/node_modules/@buddi/tool-email/migrations/028_reading.sql +20 -0
  236. package/node_modules/@buddi/tool-email/package.json +1 -0
  237. package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
  238. package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
  239. package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
  240. package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
  241. package/node_modules/entities/LICENSE +11 -0
  242. package/node_modules/entities/decode.d.ts +1 -0
  243. package/node_modules/entities/decode.js +3 -0
  244. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts +19 -0
  245. package/node_modules/entities/dist/commonjs/decode-codepoint.d.ts.map +1 -0
  246. package/node_modules/entities/dist/commonjs/decode-codepoint.js +77 -0
  247. package/node_modules/entities/dist/commonjs/decode-codepoint.js.map +1 -0
  248. package/node_modules/entities/dist/commonjs/decode.d.ts +209 -0
  249. package/node_modules/entities/dist/commonjs/decode.d.ts.map +1 -0
  250. package/node_modules/entities/dist/commonjs/decode.js +511 -0
  251. package/node_modules/entities/dist/commonjs/decode.js.map +1 -0
  252. package/node_modules/entities/dist/commonjs/encode.d.ts +22 -0
  253. package/node_modules/entities/dist/commonjs/encode.d.ts.map +1 -0
  254. package/node_modules/entities/dist/commonjs/encode.js +73 -0
  255. package/node_modules/entities/dist/commonjs/encode.js.map +1 -0
  256. package/node_modules/entities/dist/commonjs/escape.d.ts +43 -0
  257. package/node_modules/entities/dist/commonjs/escape.d.ts.map +1 -0
  258. package/node_modules/entities/dist/commonjs/escape.js +121 -0
  259. package/node_modules/entities/dist/commonjs/escape.js.map +1 -0
  260. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts +2 -0
  261. package/node_modules/entities/dist/commonjs/generated/decode-data-html.d.ts.map +1 -0
  262. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js +10 -0
  263. package/node_modules/entities/dist/commonjs/generated/decode-data-html.js.map +1 -0
  264. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts +2 -0
  265. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.d.ts.map +1 -0
  266. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js +10 -0
  267. package/node_modules/entities/dist/commonjs/generated/decode-data-xml.js.map +1 -0
  268. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts +8 -0
  269. package/node_modules/entities/dist/commonjs/generated/encode-html.d.ts.map +1 -0
  270. package/node_modules/entities/dist/commonjs/generated/encode-html.js +13 -0
  271. package/node_modules/entities/dist/commonjs/generated/encode-html.js.map +1 -0
  272. package/node_modules/entities/dist/commonjs/index.d.ts +96 -0
  273. package/node_modules/entities/dist/commonjs/index.d.ts.map +1 -0
  274. package/node_modules/entities/dist/commonjs/index.js +131 -0
  275. package/node_modules/entities/dist/commonjs/index.js.map +1 -0
  276. package/node_modules/entities/dist/commonjs/package.json +3 -0
  277. package/node_modules/entities/dist/esm/decode-codepoint.d.ts +19 -0
  278. package/node_modules/entities/dist/esm/decode-codepoint.d.ts.map +1 -0
  279. package/node_modules/entities/dist/esm/decode-codepoint.js +72 -0
  280. package/node_modules/entities/dist/esm/decode-codepoint.js.map +1 -0
  281. package/node_modules/entities/dist/esm/decode.d.ts +209 -0
  282. package/node_modules/entities/dist/esm/decode.d.ts.map +1 -0
  283. package/node_modules/entities/dist/esm/decode.js +497 -0
  284. package/node_modules/entities/dist/esm/decode.js.map +1 -0
  285. package/node_modules/entities/dist/esm/encode.d.ts +22 -0
  286. package/node_modules/entities/dist/esm/encode.d.ts.map +1 -0
  287. package/node_modules/entities/dist/esm/encode.js +69 -0
  288. package/node_modules/entities/dist/esm/encode.js.map +1 -0
  289. package/node_modules/entities/dist/esm/escape.d.ts +43 -0
  290. package/node_modules/entities/dist/esm/escape.d.ts.map +1 -0
  291. package/node_modules/entities/dist/esm/escape.js +117 -0
  292. package/node_modules/entities/dist/esm/escape.js.map +1 -0
  293. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts +2 -0
  294. package/node_modules/entities/dist/esm/generated/decode-data-html.d.ts.map +1 -0
  295. package/node_modules/entities/dist/esm/generated/decode-data-html.js +7 -0
  296. package/node_modules/entities/dist/esm/generated/decode-data-html.js.map +1 -0
  297. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts +2 -0
  298. package/node_modules/entities/dist/esm/generated/decode-data-xml.d.ts.map +1 -0
  299. package/node_modules/entities/dist/esm/generated/decode-data-xml.js +7 -0
  300. package/node_modules/entities/dist/esm/generated/decode-data-xml.js.map +1 -0
  301. package/node_modules/entities/dist/esm/generated/encode-html.d.ts +8 -0
  302. package/node_modules/entities/dist/esm/generated/encode-html.d.ts.map +1 -0
  303. package/node_modules/entities/dist/esm/generated/encode-html.js +10 -0
  304. package/node_modules/entities/dist/esm/generated/encode-html.js.map +1 -0
  305. package/node_modules/entities/dist/esm/index.d.ts +96 -0
  306. package/node_modules/entities/dist/esm/index.d.ts.map +1 -0
  307. package/node_modules/entities/dist/esm/index.js +107 -0
  308. package/node_modules/entities/dist/esm/index.js.map +1 -0
  309. package/node_modules/entities/dist/esm/package.json +3 -0
  310. package/node_modules/entities/escape.d.ts +1 -0
  311. package/node_modules/entities/escape.js +3 -0
  312. package/node_modules/entities/package.json +118 -0
  313. package/node_modules/entities/readme.md +122 -0
  314. package/node_modules/entities/src/decode-codepoint.ts +81 -0
  315. package/node_modules/entities/src/decode.spec.ts +320 -0
  316. package/node_modules/entities/src/decode.ts +620 -0
  317. package/node_modules/entities/src/encode.spec.ts +78 -0
  318. package/node_modules/entities/src/encode.ts +77 -0
  319. package/node_modules/entities/src/escape.spec.ts +14 -0
  320. package/node_modules/entities/src/escape.ts +148 -0
  321. package/node_modules/entities/src/generated/.eslintrc.json +10 -0
  322. package/node_modules/entities/src/generated/decode-data-html.ts +8 -0
  323. package/node_modules/entities/src/generated/decode-data-xml.ts +8 -0
  324. package/node_modules/entities/src/generated/encode-html.ts +17 -0
  325. package/node_modules/entities/src/index.spec.ts +125 -0
  326. package/node_modules/entities/src/index.ts +188 -0
  327. package/node_modules/parse5/LICENSE +19 -0
  328. package/node_modules/parse5/README.md +38 -0
  329. package/node_modules/parse5/dist/cjs/common/doctype.d.ts +4 -0
  330. package/node_modules/parse5/dist/cjs/common/doctype.js +118 -0
  331. package/node_modules/parse5/dist/cjs/common/error-codes.d.ts +67 -0
  332. package/node_modules/parse5/dist/cjs/common/error-codes.js +66 -0
  333. package/node_modules/parse5/dist/cjs/common/foreign-content.d.ts +9 -0
  334. package/node_modules/parse5/dist/cjs/common/foreign-content.js +237 -0
  335. package/node_modules/parse5/dist/cjs/common/html.d.ts +289 -0
  336. package/node_modules/parse5/dist/cjs/common/html.js +528 -0
  337. package/node_modules/parse5/dist/cjs/common/token.d.ts +84 -0
  338. package/node_modules/parse5/dist/cjs/common/token.js +24 -0
  339. package/node_modules/parse5/dist/cjs/common/unicode.d.ts +42 -0
  340. package/node_modules/parse5/dist/cjs/common/unicode.js +70 -0
  341. package/node_modules/parse5/dist/cjs/index.d.ts +71 -0
  342. package/node_modules/parse5/dist/cjs/index.js +54 -0
  343. package/node_modules/parse5/dist/cjs/package.json +1 -0
  344. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.d.ts +36 -0
  345. package/node_modules/parse5/dist/cjs/parser/formatting-element-list.js +114 -0
  346. package/node_modules/parse5/dist/cjs/parser/index.d.ts +221 -0
  347. package/node_modules/parse5/dist/cjs/parser/index.js +3240 -0
  348. package/node_modules/parse5/dist/cjs/parser/open-element-stack.d.ts +53 -0
  349. package/node_modules/parse5/dist/cjs/parser/open-element-stack.js +328 -0
  350. package/node_modules/parse5/dist/cjs/serializer/index.d.ts +60 -0
  351. package/node_modules/parse5/dist/cjs/serializer/index.js +172 -0
  352. package/node_modules/parse5/dist/cjs/tokenizer/index.d.ts +247 -0
  353. package/node_modules/parse5/dist/cjs/tokenizer/index.js +2714 -0
  354. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.d.ts +36 -0
  355. package/node_modules/parse5/dist/cjs/tokenizer/preprocessor.js +200 -0
  356. package/node_modules/parse5/dist/cjs/tree-adapters/default.d.ts +84 -0
  357. package/node_modules/parse5/dist/cjs/tree-adapters/default.js +176 -0
  358. package/node_modules/parse5/dist/cjs/tree-adapters/interface.d.ts +255 -0
  359. package/node_modules/parse5/dist/cjs/tree-adapters/interface.js +2 -0
  360. package/node_modules/parse5/dist/common/doctype.d.ts +4 -0
  361. package/node_modules/parse5/dist/common/doctype.js +114 -0
  362. package/node_modules/parse5/dist/common/error-codes.d.ts +67 -0
  363. package/node_modules/parse5/dist/common/error-codes.js +63 -0
  364. package/node_modules/parse5/dist/common/foreign-content.d.ts +9 -0
  365. package/node_modules/parse5/dist/common/foreign-content.js +228 -0
  366. package/node_modules/parse5/dist/common/html.d.ts +289 -0
  367. package/node_modules/parse5/dist/common/html.js +523 -0
  368. package/node_modules/parse5/dist/common/token.d.ts +84 -0
  369. package/node_modules/parse5/dist/common/token.js +20 -0
  370. package/node_modules/parse5/dist/common/unicode.d.ts +42 -0
  371. package/node_modules/parse5/dist/common/unicode.js +62 -0
  372. package/node_modules/parse5/dist/index.d.ts +71 -0
  373. package/node_modules/parse5/dist/index.js +42 -0
  374. package/node_modules/parse5/dist/parser/formatting-element-list.d.ts +36 -0
  375. package/node_modules/parse5/dist/parser/formatting-element-list.js +110 -0
  376. package/node_modules/parse5/dist/parser/index.d.ts +221 -0
  377. package/node_modules/parse5/dist/parser/index.js +3245 -0
  378. package/node_modules/parse5/dist/parser/open-element-stack.d.ts +53 -0
  379. package/node_modules/parse5/dist/parser/open-element-stack.js +324 -0
  380. package/node_modules/parse5/dist/serializer/index.d.ts +60 -0
  381. package/node_modules/parse5/dist/serializer/index.js +168 -0
  382. package/node_modules/parse5/dist/tokenizer/index.d.ts +247 -0
  383. package/node_modules/parse5/dist/tokenizer/index.js +2710 -0
  384. package/node_modules/parse5/dist/tokenizer/preprocessor.d.ts +36 -0
  385. package/node_modules/parse5/dist/tokenizer/preprocessor.js +196 -0
  386. package/node_modules/parse5/dist/tree-adapters/default.d.ts +84 -0
  387. package/node_modules/parse5/dist/tree-adapters/default.js +173 -0
  388. package/node_modules/parse5/dist/tree-adapters/interface.d.ts +255 -0
  389. package/node_modules/parse5/dist/tree-adapters/interface.js +1 -0
  390. package/node_modules/parse5/package.json +50 -0
  391. package/package.json +2 -2
  392. package/packages/cli/dist/.tsbuildinfo +1 -1
  393. package/packages/cli/dist/access-cmd.d.ts +2 -1
  394. package/packages/cli/dist/access-cmd.d.ts.map +1 -1
  395. package/packages/cli/dist/access-cmd.js +40 -7
  396. package/packages/cli/dist/access-cmd.js.map +1 -1
  397. package/packages/cli/dist/args.d.ts +2 -1
  398. package/packages/cli/dist/args.d.ts.map +1 -1
  399. package/packages/cli/dist/args.js +7 -3
  400. package/packages/cli/dist/args.js.map +1 -1
  401. package/packages/cli/dist/commands.d.ts.map +1 -1
  402. package/packages/cli/dist/commands.js +3 -2
  403. package/packages/cli/dist/commands.js.map +1 -1
  404. package/packages/cli/dist/doctor-probes.d.ts.map +1 -1
  405. package/packages/cli/dist/doctor-probes.js +10 -1
  406. package/packages/cli/dist/doctor-probes.js.map +1 -1
  407. package/packages/cli/dist/doctor.d.ts +9 -0
  408. package/packages/cli/dist/doctor.d.ts.map +1 -1
  409. package/packages/cli/dist/doctor.js +21 -3
  410. package/packages/cli/dist/doctor.js.map +1 -1
  411. package/packages/cli/dist/main.js +1 -1
  412. package/packages/cli/dist/main.js.map +1 -1
  413. package/packages/cli/dist/mcp/server.js +1 -1
  414. package/packages/cli/dist/mcp/server.js.map +1 -1
  415. package/packages/cli/dist/mcp/tools.d.ts.map +1 -1
  416. package/packages/cli/dist/mcp/tools.js +60 -0
  417. package/packages/cli/dist/mcp/tools.js.map +1 -1
  418. package/packages/core/dist/.tsbuildinfo +1 -1
  419. package/packages/core/dist/agents/catalog.js +1 -1
  420. package/packages/core/dist/agents/catalog.js.map +1 -1
  421. package/packages/core/dist/lock.d.ts +15 -1
  422. package/packages/core/dist/lock.d.ts.map +1 -1
  423. package/packages/core/dist/lock.js +15 -1
  424. package/packages/core/dist/lock.js.map +1 -1
  425. package/packages/core/dist/pages.d.ts +75 -0
  426. package/packages/core/dist/pages.d.ts.map +1 -1
  427. package/packages/core/dist/pages.js +14 -0
  428. package/packages/core/dist/pages.js.map +1 -1
  429. package/packages/core/dist/plugin/index.d.ts +2 -2
  430. package/packages/core/dist/plugin/index.d.ts.map +1 -1
  431. package/packages/core/dist/plugin/index.js.map +1 -1
  432. package/packages/core/dist/plugin/version.d.ts +1 -1
  433. package/packages/core/dist/plugin/version.js +1 -1
  434. package/packages/core/dist/provider-accounts.d.ts +32 -0
  435. package/packages/core/dist/provider-accounts.d.ts.map +1 -1
  436. package/packages/core/dist/provider-accounts.js +22 -0
  437. package/packages/core/dist/provider-accounts.js.map +1 -1
  438. package/packages/core/dist/testing/database-url.d.ts +13 -0
  439. package/packages/core/dist/testing/database-url.d.ts.map +1 -1
  440. package/packages/core/dist/testing/database-url.js +34 -0
  441. package/packages/core/dist/testing/database-url.js.map +1 -1
  442. package/packages/core/dist/testing/isolated-global-setup.d.ts +2 -0
  443. package/packages/core/dist/testing/isolated-global-setup.d.ts.map +1 -0
  444. package/packages/core/dist/testing/isolated-global-setup.js +20 -0
  445. package/packages/core/dist/testing/isolated-global-setup.js.map +1 -0
  446. package/packages/core/migrations/077_lock_background_portrait.sql +5 -0
  447. package/packages/core/package.json +4 -0
  448. package/packages/gateway/dist/.tsbuildinfo +1 -1
  449. package/packages/gateway/dist/agents/owner-tools.d.ts +21 -8
  450. package/packages/gateway/dist/agents/owner-tools.d.ts.map +1 -1
  451. package/packages/gateway/dist/agents/owner-tools.js +201 -36
  452. package/packages/gateway/dist/agents/owner-tools.js.map +1 -1
  453. package/packages/gateway/dist/agents/platform.d.ts +8 -0
  454. package/packages/gateway/dist/agents/platform.d.ts.map +1 -1
  455. package/packages/gateway/dist/agents/platform.js +48 -22
  456. package/packages/gateway/dist/agents/platform.js.map +1 -1
  457. package/packages/gateway/dist/evals/golden.d.ts +5 -0
  458. package/packages/gateway/dist/evals/golden.d.ts.map +1 -1
  459. package/packages/gateway/dist/evals/golden.js +48 -0
  460. package/packages/gateway/dist/evals/golden.js.map +1 -1
  461. package/packages/gateway/dist/mcp/requests.d.ts +8 -2
  462. package/packages/gateway/dist/mcp/requests.d.ts.map +1 -1
  463. package/packages/gateway/dist/mcp/requests.js +74 -1
  464. package/packages/gateway/dist/mcp/requests.js.map +1 -1
  465. package/packages/gateway/dist/owner-profile-edit.d.ts +160 -0
  466. package/packages/gateway/dist/owner-profile-edit.d.ts.map +1 -0
  467. package/packages/gateway/dist/owner-profile-edit.js +296 -0
  468. package/packages/gateway/dist/owner-profile-edit.js.map +1 -0
  469. package/packages/gateway/dist/plugins/index.d.ts +1 -0
  470. package/packages/gateway/dist/plugins/index.d.ts.map +1 -1
  471. package/packages/gateway/dist/plugins/index.js +1 -0
  472. package/packages/gateway/dist/plugins/index.js.map +1 -1
  473. package/packages/gateway/dist/plugins/pages-state.d.ts +37 -0
  474. package/packages/gateway/dist/plugins/pages-state.d.ts.map +1 -0
  475. package/packages/gateway/dist/plugins/pages-state.js +98 -0
  476. package/packages/gateway/dist/plugins/pages-state.js.map +1 -0
  477. package/packages/gateway/dist/provider-accounts.d.ts +33 -4
  478. package/packages/gateway/dist/provider-accounts.d.ts.map +1 -1
  479. package/packages/gateway/dist/provider-accounts.js +82 -18
  480. package/packages/gateway/dist/provider-accounts.js.map +1 -1
  481. package/packages/gateway/dist/provider-diagnostics.d.ts +5 -0
  482. package/packages/gateway/dist/provider-diagnostics.d.ts.map +1 -1
  483. package/packages/gateway/dist/provider-diagnostics.js +6 -1
  484. package/packages/gateway/dist/provider-diagnostics.js.map +1 -1
  485. package/packages/gateway/dist/serve.d.ts.map +1 -1
  486. package/packages/gateway/dist/serve.js +5 -2
  487. package/packages/gateway/dist/serve.js.map +1 -1
  488. package/packages/gateway/dist/web/access/cloudflare-connector.d.ts +63 -0
  489. package/packages/gateway/dist/web/access/cloudflare-connector.d.ts.map +1 -0
  490. package/packages/gateway/dist/web/access/cloudflare-connector.js +87 -0
  491. package/packages/gateway/dist/web/access/cloudflare-connector.js.map +1 -0
  492. package/packages/gateway/dist/web/access/cloudflare-setup.d.ts +39 -4
  493. package/packages/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -1
  494. package/packages/gateway/dist/web/access/cloudflare-setup.js +99 -11
  495. package/packages/gateway/dist/web/access/cloudflare-setup.js.map +1 -1
  496. package/packages/gateway/dist/web/access/cloudflare-token.js +1 -1
  497. package/packages/gateway/dist/web/access/cloudflare-token.js.map +1 -1
  498. package/packages/gateway/dist/web/access/index.d.ts +1 -0
  499. package/packages/gateway/dist/web/access/index.d.ts.map +1 -1
  500. package/packages/gateway/dist/web/access/index.js +1 -0
  501. package/packages/gateway/dist/web/access/index.js.map +1 -1
  502. package/packages/gateway/dist/web/agent-offers.d.ts +6 -0
  503. package/packages/gateway/dist/web/agent-offers.d.ts.map +1 -1
  504. package/packages/gateway/dist/web/agent-offers.js +6 -0
  505. package/packages/gateway/dist/web/agent-offers.js.map +1 -1
  506. package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
  507. package/packages/gateway/dist/web/api-routes.js +24 -3
  508. package/packages/gateway/dist/web/api-routes.js.map +1 -1
  509. package/packages/gateway/dist/web/attention.d.ts +11 -1
  510. package/packages/gateway/dist/web/attention.d.ts.map +1 -1
  511. package/packages/gateway/dist/web/attention.js +22 -2
  512. package/packages/gateway/dist/web/attention.js.map +1 -1
  513. package/packages/gateway/dist/web/chat.d.ts +0 -2
  514. package/packages/gateway/dist/web/chat.d.ts.map +1 -1
  515. package/packages/gateway/dist/web/chat.js +15 -4
  516. package/packages/gateway/dist/web/chat.js.map +1 -1
  517. package/packages/gateway/dist/web/lock-backgrounds.d.ts +9 -0
  518. package/packages/gateway/dist/web/lock-backgrounds.d.ts.map +1 -0
  519. package/packages/gateway/dist/web/lock-backgrounds.js +60 -0
  520. package/packages/gateway/dist/web/lock-backgrounds.js.map +1 -0
  521. package/packages/gateway/dist/web/lock.d.ts +22 -1
  522. package/packages/gateway/dist/web/lock.d.ts.map +1 -1
  523. package/packages/gateway/dist/web/lock.js +87 -24
  524. package/packages/gateway/dist/web/lock.js.map +1 -1
  525. package/packages/gateway/dist/web/places.d.ts +5 -0
  526. package/packages/gateway/dist/web/places.d.ts.map +1 -1
  527. package/packages/gateway/dist/web/places.js +11 -4
  528. package/packages/gateway/dist/web/places.js.map +1 -1
  529. package/packages/gateway/dist/web/plugins.d.ts.map +1 -1
  530. package/packages/gateway/dist/web/plugins.js +4 -0
  531. package/packages/gateway/dist/web/plugins.js.map +1 -1
  532. package/packages/gateway/dist/web/server.d.ts +3 -0
  533. package/packages/gateway/dist/web/server.d.ts.map +1 -1
  534. package/packages/gateway/dist/web/server.js +48 -49
  535. package/packages/gateway/dist/web/server.js.map +1 -1
  536. package/packages/gateway/dist/web/take-on.d.ts +3 -1
  537. package/packages/gateway/dist/web/take-on.d.ts.map +1 -1
  538. package/packages/gateway/dist/web/take-on.js +14 -3
  539. package/packages/gateway/dist/web/take-on.js.map +1 -1
  540. package/packages/gateway/dist/web/telegram.d.ts.map +1 -1
  541. package/packages/gateway/dist/web/telegram.js +4 -2
  542. package/packages/gateway/dist/web/telegram.js.map +1 -1
  543. package/packages/gateway/dist/web/version.d.ts +10 -0
  544. package/packages/gateway/dist/web/version.d.ts.map +1 -1
  545. package/packages/gateway/dist/web/version.js +12 -0
  546. package/packages/gateway/dist/web/version.js.map +1 -1
  547. package/packages/install/dist/.tsbuildinfo +1 -1
  548. package/packages/install/dist/backup.d.ts +12 -0
  549. package/packages/install/dist/backup.d.ts.map +1 -1
  550. package/packages/install/dist/backup.js +26 -8
  551. package/packages/install/dist/backup.js.map +1 -1
  552. package/packages/install/dist/cloudflared.d.ts +121 -0
  553. package/packages/install/dist/cloudflared.d.ts.map +1 -0
  554. package/packages/install/dist/cloudflared.js +451 -0
  555. package/packages/install/dist/cloudflared.js.map +1 -0
  556. package/packages/install/dist/index.d.ts +1 -0
  557. package/packages/install/dist/index.d.ts.map +1 -1
  558. package/packages/install/dist/index.js +1 -0
  559. package/packages/install/dist/index.js.map +1 -1
  560. package/packages/install/dist/supervisor.d.ts +6 -1
  561. package/packages/install/dist/supervisor.d.ts.map +1 -1
  562. package/packages/install/dist/supervisor.js +51 -5
  563. package/packages/install/dist/supervisor.js.map +1 -1
  564. package/packages/install/dist/upgrade.d.ts +2 -0
  565. package/packages/install/dist/upgrade.d.ts.map +1 -1
  566. package/packages/install/dist/upgrade.js +3 -2
  567. package/packages/install/dist/upgrade.js.map +1 -1
  568. package/packages/runtime/dist/.tsbuildinfo +1 -1
  569. package/packages/runtime/dist/codex-direct.d.ts +12 -1
  570. package/packages/runtime/dist/codex-direct.d.ts.map +1 -1
  571. package/packages/runtime/dist/codex-direct.js +15 -6
  572. package/packages/runtime/dist/codex-direct.js.map +1 -1
  573. package/packages/runtime/dist/groups.d.ts +5 -4
  574. package/packages/runtime/dist/groups.d.ts.map +1 -1
  575. package/packages/runtime/dist/groups.js +7 -6
  576. package/packages/runtime/dist/groups.js.map +1 -1
  577. package/packages/runtime/dist/provider-models.d.ts +4 -0
  578. package/packages/runtime/dist/provider-models.d.ts.map +1 -1
  579. package/packages/runtime/dist/provider-models.js.map +1 -1
  580. package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
  581. package/packages/tools/browser/dist/.tsbuildinfo +1 -1
  582. package/packages/tools/email/dist/.tsbuildinfo +1 -1
  583. package/packages/tools/email/dist/html.d.ts +16 -0
  584. package/packages/tools/email/dist/html.d.ts.map +1 -0
  585. package/packages/tools/email/dist/html.js +273 -0
  586. package/packages/tools/email/dist/html.js.map +1 -0
  587. package/packages/tools/email/dist/imap/imapflow-client.d.ts +7 -0
  588. package/packages/tools/email/dist/imap/imapflow-client.d.ts.map +1 -1
  589. package/packages/tools/email/dist/imap/imapflow-client.js +53 -0
  590. package/packages/tools/email/dist/imap/imapflow-client.js.map +1 -1
  591. package/packages/tools/email/dist/mail.d.ts.map +1 -1
  592. package/packages/tools/email/dist/mail.js +4 -0
  593. package/packages/tools/email/dist/mail.js.map +1 -1
  594. package/packages/tools/email/dist/pages/descriptors.d.ts.map +1 -1
  595. package/packages/tools/email/dist/pages/descriptors.js +250 -176
  596. package/packages/tools/email/dist/pages/descriptors.js.map +1 -1
  597. package/packages/tools/email/dist/pages/index.d.ts +1 -0
  598. package/packages/tools/email/dist/pages/index.d.ts.map +1 -1
  599. package/packages/tools/email/dist/pages/index.js +3 -0
  600. package/packages/tools/email/dist/pages/index.js.map +1 -1
  601. package/packages/tools/email/dist/pages/queries.d.ts +28 -1
  602. package/packages/tools/email/dist/pages/queries.d.ts.map +1 -1
  603. package/packages/tools/email/dist/pages/queries.js +362 -66
  604. package/packages/tools/email/dist/pages/queries.js.map +1 -1
  605. package/packages/tools/email/dist/pages/thread-tools.d.ts +25 -0
  606. package/packages/tools/email/dist/pages/thread-tools.d.ts.map +1 -0
  607. package/packages/tools/email/dist/pages/thread-tools.js +33 -0
  608. package/packages/tools/email/dist/pages/thread-tools.js.map +1 -0
  609. package/packages/tools/email/dist/ports.d.ts +10 -0
  610. package/packages/tools/email/dist/ports.d.ts.map +1 -1
  611. package/packages/tools/email/dist/ports.js.map +1 -1
  612. package/packages/tools/email/dist/retention.d.ts.map +1 -1
  613. package/packages/tools/email/dist/retention.js +1 -0
  614. package/packages/tools/email/dist/retention.js.map +1 -1
  615. package/packages/tools/email/dist/sources/inbox-poll.d.ts.map +1 -1
  616. package/packages/tools/email/dist/sources/inbox-poll.js +9 -2
  617. package/packages/tools/email/dist/sources/inbox-poll.js.map +1 -1
  618. package/packages/tools/email/migrations/027_first_contact.sql +13 -0
  619. package/packages/tools/email/migrations/028_reading.sql +20 -0
  620. package/packages/tools/email/package.json +1 -0
  621. package/packages/tools/host/dist/.tsbuildinfo +1 -1
  622. package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
  623. package/packages/tools/memory/dist/.tsbuildinfo +1 -1
  624. package/packages/tools/web/dist/.tsbuildinfo +1 -1
  625. package/packages/web/dist/apple-touch-icon.png +0 -0
  626. package/packages/web/dist/assets/index-C1sRt7zd.js +149 -0
  627. package/packages/web/dist/assets/index-CdZpSJ4_.css +1 -0
  628. package/packages/web/dist/assets/{lottie_light-CQmEj1as.js → lottie_light-DnYl9yaP.js} +1 -1
  629. package/packages/web/dist/backgrounds/golden-streak-portrait.jpg +0 -0
  630. package/packages/web/dist/backgrounds/golden-streak-thumb.jpg +0 -0
  631. package/packages/web/dist/backgrounds/manifest.json +18 -0
  632. package/packages/web/dist/backgrounds/peoria-autumn-waterfront-thumb.jpg +0 -0
  633. package/packages/web/dist/backgrounds/peoria-autumn-waterfront.jpg +0 -0
  634. package/packages/web/dist/build.json +1 -1
  635. package/packages/web/dist/favicon-16.png +0 -0
  636. package/packages/web/dist/favicon-32.png +0 -0
  637. package/packages/web/dist/favicon.ico +0 -0
  638. package/packages/web/dist/icon-192.png +0 -0
  639. package/packages/web/dist/icon-512.png +0 -0
  640. package/packages/web/dist/index.html +6 -3
  641. package/packages/web/dist/manifest.webmanifest +1 -1
  642. package/packages/web/dist/maskable-512.png +0 -0
  643. package/packages/web/dist/precache.json +7 -5
  644. package/packages/web/dist/assets/index-BrA8nWN-.css +0 -1
  645. package/packages/web/dist/assets/index-lmUTDd2T.js +0 -146
  646. package/packages/web/dist/favicon.png +0 -0
  647. package/packages/web/dist/icon-maskable-512.png +0 -0
@@ -23,7 +23,7 @@ import { QueryRefusal } from '@buddi/core/plugin';
23
23
  import { POLL_EVERY_SECONDS, TRIAGE_AGENT_ID } from '../sources/inbox-poll.js';
24
24
  import { idleLive } from '../sources/idle.js';
25
25
  import { booleanFilter, buildSearch, narrows, toSearchRow, validateFilters, windowNote, } from '../search.js';
26
- import { lastSyncByAccount, listAccounts } from '../config.js';
26
+ import { lastSyncedByAccount, listAccounts } from '../config.js';
27
27
  import { ACCOUNT_KIND } from '../credentials.js';
28
28
  import { attentionReasons, findThread, listThreadRows, threadMessages } from '../threads.js';
29
29
  import { attentionLine, reasonOf, viewOf } from '../needs-you.js';
@@ -34,6 +34,7 @@ import { loadWatcherSettings, DEFAULT_WATCHER_SETTINGS } from '../watchers.js';
34
34
  import { draftStatusLine, isoOf, policyLine, relative } from './format.js';
35
35
  import { describeUndo, movedSince, plural, recentActions, undoRefusal, verbOf } from '../mailbox/actions.js';
36
36
  import { learnedRules } from '../policies/auto.js';
37
+ import { ACTION_COLUMNS, SEEN, toAction } from '../mailbox/actions.js';
37
38
  /** How many conversations the list shows before the owner narrows it. */
38
39
  export const THREAD_LIST_LIMIT = 30;
39
40
  /** How many messages of a conversation the page draws. The newest ones. */
@@ -80,6 +81,11 @@ export function attachmentRows(messageId, raw) {
80
81
  line: `${filename} — ${detail}`,
81
82
  artifactId: a.artifactId ?? null,
82
83
  held: a.artifactId ? 'in your files' : 'not fetched',
84
+ // The `message` component's own words for the same file (host API 1.30).
85
+ name: filename,
86
+ size: Number.isFinite(size) ? size : 0,
87
+ mime: a.mime ?? 'application/octet-stream',
88
+ contentId: typeof a.contentId === 'string' && a.contentId !== '' ? a.contentId : null,
83
89
  };
84
90
  });
85
91
  }
@@ -109,8 +115,14 @@ export function formatBytes(bytes) {
109
115
  export const MAX_BODY_BYTES = 512 * 1024;
110
116
  /** The sentence a cut body ends with. Said once, so a test can name it. */
111
117
  export const TRUNCATED_NOTE = '… this message is too long to show in full; the rest is in your mailbox.';
112
- export function truncateBody(text) {
113
- if (Buffer.byteLength(text, 'utf8') <= MAX_BODY_BYTES)
118
+ /**
119
+ * How much of the plain text rides along when there is an HTML body too: the
120
+ * text is then only the fallback, and the answer must stay under the
121
+ * engine's megabyte with both in it.
122
+ */
123
+ export const TEXT_WITH_HTML_BYTES = 64 * 1024;
124
+ export function truncateBody(text, max = MAX_BODY_BYTES) {
125
+ if (Buffer.byteLength(text, 'utf8') <= max)
114
126
  return text;
115
127
  /*
116
128
  * Cut on a character boundary: slicing bytes can land in the middle of a
@@ -118,12 +130,12 @@ export function truncateBody(text) {
118
130
  * end of every long message. Decoding the slice leaves that partial
119
131
  * character as U+FFFD, which is exactly what is trimmed off here.
120
132
  */
121
- const bytes = Buffer.from(text, 'utf8').subarray(0, MAX_BODY_BYTES);
133
+ const bytes = Buffer.from(text, 'utf8').subarray(0, max);
122
134
  const whole = new TextDecoder('utf-8').decode(bytes).replace(/\uFFFD+$/, '');
123
135
  return `${whole}\n\n${TRUNCATED_NOTE}`;
124
136
  }
125
137
  /** A draft as the editor and the draft list read it. Never a patch: all of it. */
126
- function draftRow(draft, now) {
138
+ function draftRow(draft, now, fromAddress) {
127
139
  const live = LIVE_DRAFT_STATUSES.includes(draft.status) && draft.sentActionId === null;
128
140
  // Dispatched, never confirmed: the one state where nothing may be done to it
129
141
  // until somebody has looked in the mailbox.
@@ -153,6 +165,17 @@ function draftRow(draft, now) {
153
165
  notLiveLine: `This draft is ${draft.status} and cannot be edited or sent. It is kept so you can read what was proposed.`,
154
166
  unresolvedLine: unresolvedLine(draft.sendError),
155
167
  sendError: draft.sendError,
168
+ /*
169
+ * The reply as the reading pane shows it before anyone edits it: drawn
170
+ * the way a message is (host API 1.30), from the mailbox it will leave.
171
+ */
172
+ preview: {
173
+ from: { name: 'Your reply', address: fromAddress ?? draft.to[0] ?? 'you' },
174
+ to: draft.to.map((address) => ({ address })),
175
+ cc: draft.cc.map((address) => ({ address })),
176
+ at: draft.updatedAt,
177
+ text: draft.bodyText,
178
+ },
156
179
  };
157
180
  }
158
181
  /** What a dispatch that never came back says, with the server's own words. */
@@ -199,6 +222,7 @@ export function threadsQuery() {
199
222
  const { rows } = await ctx.buddi.db.query(`select distinct thread_id from email.drafts
200
223
  where thread_id = any($1::uuid[]) and status = any($2::text[])`, [threads.map((t) => t.id), [...LIVE_DRAFT_STATUSES]]);
201
224
  const withDraft = new Set(rows.map((r) => String(r.thread_id)));
225
+ const reading = await listReading(ctx.buddi.db, threads.map((t) => t.id));
202
226
  /*
203
227
  * Who the conversation is *with*: the first participant who is not one
204
228
  * of the owner's own addresses. The owner is on every thread, so the
@@ -206,34 +230,159 @@ export function threadsQuery() {
206
230
  */
207
231
  const own = new Set(accounts.flatMap((account) => [account.address, ...account.aliases]).map((address) => address.toLowerCase()));
208
232
  return {
209
- threads: threads.map((thread) => ({
210
- id: thread.id,
211
- subject: thread.subject === '' ? '(no subject)' : thread.subject,
212
- sender: thread.participants.find((address) => !own.has(address.toLowerCase())) ??
233
+ threads: threads.map((thread) => {
234
+ const sender = thread.participants.find((address) => !own.has(address.toLowerCase())) ??
213
235
  thread.participants[0] ??
214
- '(nobody)',
215
- participants: thread.participants.join(', '),
216
- state: thread.state,
217
- /*
218
- * The state as the owner reads it (`needs-you.ts`): "Waiting on you"
219
- * only when the one rule says so. A notification and a message
220
- * nobody expects an answer to carry no pill at all — a word on every
221
- * row is how forty "Waiting on you" pills came to mean nothing.
222
- */
223
- attention: viewOf(reasons.get(thread.id) ?? reasonOf(null, thread.state)),
224
- pill: listPillOf(viewOf(reasons.get(thread.id) ?? reasonOf(null, thread.state))),
225
- // The "draft" pill sits *beside* the state, never in place of it: a
226
- // conversation that is waiting on the owner and has a reply written
227
- // for it is two facts, and the old page showed both.
228
- draftPill: withDraft.has(thread.id) ? 'draft' : '',
229
- when: relative(thread.lastAt, now),
230
- messageCount: thread.messageCount,
231
- })),
236
+ '(nobody)';
237
+ const read = reading.get(thread.id);
238
+ return {
239
+ id: thread.id,
240
+ subject: thread.subject === '' ? '(no subject)' : thread.subject,
241
+ sender,
242
+ /*
243
+ * The person, not the address: the display name on their latest
244
+ * message when they gave one (host API 1.30's reading pane), the
245
+ * address otherwise.
246
+ */
247
+ senderName: read?.senderName && read.senderAddress?.toLowerCase() === sender.toLowerCase() ? read.senderName : sender,
248
+ // What the conversation last said, on one line; the owner's own words say so.
249
+ preview: read ? (read.lastOut ? `You: ${read.snippet}` : read.snippet) : '',
250
+ unread: read?.unread ?? false,
251
+ // Mail Triage's word for the latest message, as a chip: "Bill", "Receipt".
252
+ tag: read?.category && read.category !== 'other' ? tagLabel(read.category) : '',
253
+ participants: thread.participants.join(', '),
254
+ state: thread.state,
255
+ /*
256
+ * The state as the owner reads it (`needs-you.ts`): "Waiting on you"
257
+ * only when the one rule says so. A notification and a message
258
+ * nobody expects an answer to carry no pill at all — a word on every
259
+ * row is how forty "Waiting on you" pills came to mean nothing.
260
+ */
261
+ attention: viewOf(reasons.get(thread.id) ?? reasonOf(null, thread.state)),
262
+ pill: listPillOf(viewOf(reasons.get(thread.id) ?? reasonOf(null, thread.state))),
263
+ // The "draft" pill sits *beside* the state, never in place of it: a
264
+ // conversation that is waiting on the owner and has a reply written
265
+ // for it is two facts, and the old page showed both.
266
+ draftPill: withDraft.has(thread.id) ? 'draft' : '',
267
+ when: relative(thread.lastAt, now),
268
+ messageCount: thread.messageCount,
269
+ };
270
+ }),
232
271
  ...hits,
233
272
  };
234
273
  },
235
274
  };
236
275
  }
276
+ /** Triage's categories as a chip says them. Anything else reads as itself, capitalised. */
277
+ const TAG_WORDS = {
278
+ 'reply-needed': 'Reply needed',
279
+ 'payment-failed': 'Payment failed',
280
+ 'bank-notice': 'Bank',
281
+ 'service-notice': 'Service',
282
+ promo: 'Promotion',
283
+ };
284
+ export function tagLabel(category) {
285
+ const known = TAG_WORDS[category];
286
+ if (known)
287
+ return known;
288
+ const words = category.replace(/-/g, ' ').trim();
289
+ return words === '' ? '' : words[0].toUpperCase() + words.slice(1);
290
+ }
291
+ /**
292
+ * What the list draws beside each conversation, in one read: how its last
293
+ * message opens, the name on the latest message they sent, whether anything
294
+ * they sent is still unread on the server (no `\Seen`, as the flag sync last
295
+ * saw it), and Mail Triage's latest category.
296
+ */
297
+ async function listReading(db, ids) {
298
+ const out = new Map();
299
+ if (ids.length === 0)
300
+ return out;
301
+ const { rows } = await db.query(`select t.id,
302
+ lm.snippet, lm.direction as last_direction,
303
+ li.from_name, li.from_addr,
304
+ exists (select 1 from email.messages u
305
+ where u.thread_id = t.id and u.direction = 'in'
306
+ and not (coalesce(u.flags, '[]'::jsonb) ? $2)) as unread,
307
+ (select tr.category from email.triage tr
308
+ where tr.message_id = li.id
309
+ order by tr.decided_at desc, tr.processing_version desc limit 1) as category
310
+ from email.threads t
311
+ left join email.messages lm on lm.id = t.last_message_id
312
+ left join lateral (
313
+ select m.id, m.from_name, m.from_addr from email.messages m
314
+ where m.thread_id = t.id and m.direction = 'in'
315
+ order by coalesce(m.internal_date, m.fetched_at) desc, m.id desc limit 1
316
+ ) li on true
317
+ where t.id = any($1::uuid[])`, [ids, SEEN]);
318
+ for (const row of rows) {
319
+ out.set(String(row.id), {
320
+ snippet: String(row.snippet ?? ''),
321
+ lastOut: row.last_direction === 'out',
322
+ senderName: typeof row.from_name === 'string' && row.from_name.trim() !== '' ? row.from_name.trim() : null,
323
+ senderAddress: typeof row.from_addr === 'string' ? row.from_addr : null,
324
+ unread: row.unread === true,
325
+ category: typeof row.category === 'string' ? row.category : null,
326
+ });
327
+ }
328
+ return out;
329
+ }
330
+ /** One address as the `message` component reads it. */
331
+ function addressRow(address, name) {
332
+ return name ? { address, name } : { address };
333
+ }
334
+ /**
335
+ * The parts of a conversation's reading pane that are buddi's rather than the
336
+ * mail's: Mail Triage's verdict on the latest message they sent, and what
337
+ * buddi changed in the mailbox about this conversation, newest first, with
338
+ * Undo where it still applies (the same rows and words as Recent changes).
339
+ */
340
+ async function threadLayer(db, threadId, accountAddress, now) {
341
+ const verdict = await db.query(`select tr.category, tr.urgency, tr.summary, tr.action_needed, tr.decided_at
342
+ from email.triage tr
343
+ join lateral (
344
+ select m.id from email.messages m
345
+ where m.thread_id = $1::uuid and m.direction = 'in'
346
+ order by coalesce(m.internal_date, m.fetched_at) desc, m.id desc limit 1
347
+ ) li on li.id = tr.message_id
348
+ order by tr.decided_at desc, tr.processing_version desc limit 1`, [threadId]);
349
+ const v = verdict.rows[0];
350
+ const triage = v
351
+ ? {
352
+ category: String(v.category),
353
+ tag: tagLabel(String(v.category)),
354
+ urgency: String(v.urgency),
355
+ // "Bill · normal — The October invoice from Studio North, €1,240. To do: pay by 14 Oct."
356
+ line: [
357
+ `${tagLabel(String(v.category))} · ${v.urgency === 'urgent' ? 'urgent' : v.urgency === 'low' ? 'low' : 'this week'}`,
358
+ '—',
359
+ String(v.summary ?? '').trim(),
360
+ v.action_needed ? `To do: ${String(v.action_needed).trim()}` : '',
361
+ ]
362
+ .filter((part) => part !== '')
363
+ .join(' '),
364
+ when: relative(isoOf(v.decided_at), now),
365
+ }
366
+ : null;
367
+ const { rows } = await db.query(`select ${ACTION_COLUMNS_SQL} from email.mailbox_actions a
368
+ where a.message_ids && (select coalesce(array_agg(m.id), '{}') from email.messages m where m.thread_id = $1::uuid)
369
+ order by a.created_at desc, a.seq desc limit $2`, [threadId, THREAD_CHANGES]);
370
+ const changes = [];
371
+ for (const c of rows.map(toAction)) {
372
+ const undoable = undoRefusal(c) === null;
373
+ const moved = undoable ? await movedSince(db, c) : 0;
374
+ const who = c.origin === 'policy' ? `by ${c.actor}` : c.origin === 'owner' ? 'by you' : c.actor === TRIAGE_AGENT_ID ? 'by Mail Triage' : `by @${c.actor}`;
375
+ changes.push({
376
+ id: c.id,
377
+ // The words Recent changes uses: "Mark as read · by Mail Triage · yesterday".
378
+ line: [verbOf(c.kind, c.destination), who, relative(c.createdAt, now), c.note ?? ''].filter((p) => p !== '').join(' · '),
379
+ state: changeState(c),
380
+ undoable,
381
+ undoLine: describeUndo(c, accountAddress, moved),
382
+ });
383
+ }
384
+ return { triage, changes };
385
+ }
237
386
  /**
238
387
  * The list's pill for a conversation: the views that are worth a word.
239
388
  * A notification and "they wrote" are the inbox's ordinary weather and say
@@ -302,6 +451,26 @@ async function searchHits(ctx, input, ids) {
302
451
  ...(built.windowed && built.windowFrom ? { window: windowNote(built.windowFrom) } : {}),
303
452
  };
304
453
  }
454
+ /** How many of buddi's changes a reading pane lists for one conversation. */
455
+ export const THREAD_CHANGES = 3;
456
+ const ACTION_COLUMNS_SQL = ACTION_COLUMNS.split(',').map((c) => `a.${c.trim()}`).join(', ');
457
+ /** The display name, the server's own arrival time and the read mark of each message, by id. */
458
+ async function messageExtras(db, ids) {
459
+ const out = new Map();
460
+ if (ids.length === 0)
461
+ return out;
462
+ const { rows } = await db.query(`select id, from_name, coalesce(internal_date, fetched_at) as at, direction,
463
+ coalesce(flags, '[]'::jsonb) ? $2 as seen
464
+ from email.messages where id = any($1::uuid[])`, [ids, SEEN]);
465
+ for (const row of rows) {
466
+ out.set(String(row.id), {
467
+ fromName: typeof row.from_name === 'string' && row.from_name.trim() !== '' ? row.from_name.trim() : null,
468
+ at: isoOf(row.at),
469
+ unread: row.direction === 'in' && row.seen !== true,
470
+ });
471
+ }
472
+ return out;
473
+ }
305
474
  /**
306
475
  * One conversation: its messages' snippets, then the drafts under them.
307
476
  *
@@ -327,8 +496,23 @@ export function threadQuery() {
327
496
  const live = drafts.filter((d) => LIVE_DRAFT_STATUSES.includes(d.status));
328
497
  const older = drafts.filter((d) => !LIVE_DRAFT_STATUSES.includes(d.status));
329
498
  const latest = messages[messages.length - 1] ?? null;
499
+ const accounts = await listAccounts(ctx.buddi.db, { enabledOnly: false });
500
+ const account = accounts.find((a) => a.id === thread.accountId);
501
+ const layer = await threadLayer(ctx.buddi.db, thread.id, account?.address ?? 'your mailbox', now);
502
+ const extra = await messageExtras(ctx.buddi.db, messages.map((m) => m.id));
503
+ const view = viewOf(reason);
330
504
  return {
331
505
  id: thread.id,
506
+ /*
507
+ * buddi's layer above the thread (host API 1.30's reading pane): the
508
+ * verdict, what was changed and Undo, and "Needs a reply" with Done.
509
+ */
510
+ hasTriage: layer.triage !== null,
511
+ triage: layer.triage,
512
+ triageLine: layer.triage ? String(layer.triage.line) : '',
513
+ changes: layer.changes,
514
+ hasChanges: layer.changes.length > 0,
515
+ needsReply: view === 'needs-you',
332
516
  subject: thread.subject === '' ? '(no subject)' : thread.subject,
333
517
  state: thread.state,
334
518
  attention: viewOf(reason),
@@ -337,32 +521,41 @@ export function threadQuery() {
337
521
  participants: thread.participants.join(', '),
338
522
  lastAt: thread.lastAt,
339
523
  messageCount: thread.messageCount,
340
- messages: messages.map((message) => ({
341
- id: message.id,
342
- from: message.from,
343
- snippet: message.snippet,
344
- who: message.direction === 'out' ? 'you wrote' : 'they wrote',
345
- when: relative(message.date, now),
346
- // Where it is now when that is not the inbox: archived, in Trash,
347
- // in a label, or no longer in the inbox (moved in another app).
348
- place: message.place,
349
- // One line, because a repeated component draws text and formats
350
- // nothing: who wrote it, when, where it is now, and what it opens with.
351
- summary: [
352
- message.from,
353
- message.direction === 'out' ? 'you wrote' : 'they wrote',
354
- relative(message.date, now),
355
- message.place,
356
- ]
357
- .filter((part) => part !== '')
358
- .join(' · ') + (message.snippet ? ` — ${message.snippet}` : ''),
359
- })),
524
+ messages: messages.map((message, index) => {
525
+ const more = extra.get(message.id);
526
+ return {
527
+ id: message.id,
528
+ // The header the reading pane draws before the body arrives (`message`).
529
+ from: addressRow(message.from, more?.fromName),
530
+ to: message.to.map((address) => addressRow(address)),
531
+ at: more?.at ?? message.date,
532
+ // Every message but the newest is one line until it is opened, unless the owner has not read it.
533
+ folded: index < messages.length - 1 && !(more?.unread ?? false),
534
+ fromAddress: message.from,
535
+ snippet: message.snippet,
536
+ who: message.direction === 'out' ? 'you wrote' : 'they wrote',
537
+ when: relative(message.date, now),
538
+ // Where it is now when that is not the inbox: archived, in Trash,
539
+ // in a label, or no longer in the inbox (moved in another app).
540
+ place: message.place,
541
+ // One line, because a repeated component draws text and formats
542
+ // nothing: who wrote it, when, where it is now, and what it opens with.
543
+ summary: [
544
+ message.from,
545
+ message.direction === 'out' ? 'you wrote' : 'they wrote',
546
+ relative(message.date, now),
547
+ message.place,
548
+ ]
549
+ .filter((part) => part !== '')
550
+ .join(' · ') + (message.snippet ? ` — ${message.snippet}` : ''),
551
+ };
552
+ }),
360
553
  latestMessageId: latest?.id ?? null,
361
554
  hasMessages: messages.length > 0,
362
555
  hasDraft: live.length > 0,
363
556
  // Every live draft: the page draws an editor per row, so each row is
364
557
  // the whole envelope rather than a line about one.
365
- drafts: live.map((draft) => draftRow(draft, now)),
558
+ drafts: live.map((draft) => draftRow(draft, now, account?.address)),
366
559
  hasOlder: older.length > 0,
367
560
  older: older.map((draft) => ({
368
561
  id: draft.id,
@@ -401,8 +594,9 @@ export function messageQuery() {
401
594
  params: byId,
402
595
  async produce(params, ctx) {
403
596
  const { id } = params;
404
- const { rows } = await ctx.buddi.db.query(`select m.id, m.from_addr, m.to_addrs, m.cc, m.subject, m.date, m.direction,
405
- m.body_text, m.body_purged_at, m.attachments
597
+ const { rows } = await ctx.buddi.db.query(`select m.id, m.from_addr, m.from_name, m.to_addrs, m.cc, m.subject, m.date, m.direction,
598
+ m.body_text, m.body_html, m.body_purged_at, m.attachments, m.snippet,
599
+ coalesce(m.internal_date, m.fetched_at) as at
406
600
  from email.messages m
407
601
  join email.accounts a on a.id = m.account_id
408
602
  where m.id = $1::uuid`, [id]);
@@ -411,20 +605,35 @@ export function messageQuery() {
411
605
  throw new QueryRefusal('No message here has that id.');
412
606
  const messageId = String(row.id);
413
607
  const purged = row.body_purged_at !== null;
414
- const body = purged
415
- ? 'The body of this message has been purged under your retention setting. Its headers are kept.'
416
- : truncateBody(String(row.body_text ?? ''));
608
+ const purgedNote = 'The body of this message has been purged under your retention setting. Its headers are kept.';
609
+ const html = !purged && typeof row.body_html === 'string' && row.body_html !== '' ? row.body_html : null;
610
+ const text = purged ? '' : truncateBody(String(row.body_text ?? ''), html ? TEXT_WITH_HTML_BYTES : MAX_BODY_BYTES);
611
+ const toList = Array.isArray(row.to_addrs) ? row.to_addrs : [];
612
+ const ccList = Array.isArray(row.cc) ? row.cc : [];
417
613
  return {
418
614
  id: messageId,
419
- from: row.from_addr,
420
- to: (Array.isArray(row.to_addrs) ? row.to_addrs : []).join(', '),
421
- cc: (Array.isArray(row.cc) ? row.cc : []).join(', '),
615
+ /*
616
+ * The `message` component's shape (host API 1.30): who, to whom,
617
+ * when (the server's arrival time, as the thread orders by), the
618
+ * stored HTML — sanitised at ingest, and again by the dashboard — and
619
+ * the text it falls back to. Never anything fetched now.
620
+ */
621
+ from: addressRow(String(row.from_addr), typeof row.from_name === 'string' ? row.from_name : null),
622
+ to: toList.map((address) => addressRow(address)),
623
+ cc: ccList.map((address) => addressRow(address)),
624
+ at: isoOf(row.at) ?? isoOf(row.date),
625
+ html,
626
+ text: purged ? null : text,
627
+ snippet: row.snippet ?? '',
628
+ note: purged ? purgedNote : null,
629
+ toText: toList.join(', '),
630
+ ccText: ccList.join(', '),
422
631
  subject: row.subject ?? '',
423
632
  date: isoOf(row.date),
424
633
  who: row.direction === 'out' ? 'you wrote' : 'they wrote',
425
- // Null once retention has purged it: the headers stay, the body does
426
- // not, and the page says so rather than drawing an empty message.
427
- bodyText: body,
634
+ // The body rides once, as `text` (null once retention purged it, with
635
+ // `note` saying so): a second copy would put a long message over the
636
+ // gateway's megabyte per answer.
428
637
  purged,
429
638
  attachments: attachmentRows(messageId, row.attachments),
430
639
  };
@@ -483,10 +692,18 @@ export function accountsQuery() {
483
692
  async produce(_params, ctx) {
484
693
  const now = ctx.buddi.clock.now();
485
694
  const accounts = await listAccounts(ctx.buddi.db, { enabledOnly: false });
486
- const synced = await lastSyncByAccount(ctx.buddi.db);
695
+ // When each mailbox last *finished* a poll: "connected, synced 3 min
696
+ // ago" is true of a quiet mailbox too, where "when mail last landed"
697
+ // read "no mail has arrived yet" on the day it was connected.
698
+ const synced = await lastSyncedByAccount(ctx.buddi.db);
487
699
  const waiting = await triageWaitingByAccount(ctx.buddi.db);
488
700
  const needed = await passwordsNeeded(accounts, ctx);
701
+ const { rows: storedRows } = await ctx.buddi.db.query(`select a.id from email.accounts a where exists (select 1 from email.messages m where m.account_id = a.id)`);
702
+ const stored = new Set(storedRows.map((row) => String(row.id)));
489
703
  return {
704
+ // A connected mailbox with nothing stored yet: the Mail page's "Read
705
+ // the last 7 days" lands here, and the note it lands on reads this.
706
+ anyFresh: accounts.some((account) => account.enabled && !stored.has(account.id)),
490
707
  /*
491
708
  * Whether new mail has anybody to triage it. `needs-agent` is what
492
709
  * the page's offer line is drawn against: a mailbox, and no agent
@@ -522,9 +739,11 @@ export function accountsQuery() {
522
739
  : idleLive(account.id)
523
740
  ? 'Instant'
524
741
  : `Checking every ${Math.round(POLL_EVERY_SECONDS / 60)} min`,
525
- lastSync: synced.get(account.id)
526
- ? relative(synced.get(account.id) ?? null, now)
527
- : 'no mail has arrived yet',
742
+ lastSync: !account.enabled
743
+ ? '—'
744
+ : synced.get(account.id)
745
+ ? relative(synced.get(account.id).toISOString(), now)
746
+ : 'not yet',
528
747
  /*
529
748
  * Facts about a mailbox, not one sentence to be parsed: whether
530
749
  * buddi is reading it, and whether it is a mailbox `.env` used to
@@ -534,9 +753,13 @@ export function accountsQuery() {
534
753
  * carry the tone.
535
754
  */
536
755
  state: [
537
- account.enabled
538
- ? { value: 'on', tone: 'neutral' }
539
- : { value: 'off', tone: 'warning' },
756
+ // Connected once a poll has finished with the password it has;
757
+ // until the first one, "connecting".
758
+ !account.enabled
759
+ ? { value: 'off', tone: 'warning' }
760
+ : synced.get(account.id) && !needed.has(account.id)
761
+ ? { value: 'connected', tone: 'neutral' }
762
+ : { value: needed.has(account.id) ? 'on' : 'connecting', tone: 'neutral' },
540
763
  // A mailbox `.env` used to name that could not be adopted is a
541
764
  // password nobody can read here: Set password brings it back.
542
765
  ...(account.addedVia === 'env' ? [{ value: 'password needed', tone: 'neutral' }] : []),
@@ -548,6 +771,78 @@ export function accountsQuery() {
548
771
  },
549
772
  };
550
773
  }
774
+ /**
775
+ * The Mail page's own read: which mailboxes are connected, and which of them
776
+ * are fresh — connected, a first poll finished, and nothing stored yet. A
777
+ * fresh mailbox gets a first state instead of an empty list ("Connected to
778
+ * you@example.com. Reading new mail from now on; 412 older messages left
779
+ * alone."), because "No conversations here" on the day you connect reads as a
780
+ * fault. Until that first poll has finished nothing is known about what was
781
+ * left alone, so the page says "Connecting to you@example.com…" instead.
782
+ */
783
+ export function mailStatusQuery() {
784
+ return {
785
+ name: 'mail_status',
786
+ params: noParams,
787
+ async produce(_params, ctx) {
788
+ const accounts = await listAccounts(ctx.buddi.db, { enabledOnly: true });
789
+ // The conversation list reads every mailbox, a disabled one's retained
790
+ // conversations included; whether there is mail to list asks the same.
791
+ const everyId = (await listAccounts(ctx.buddi.db, { enabledOnly: false })).map((account) => account.id);
792
+ const { rows } = await ctx.buddi.db.query(`select a.id,
793
+ exists (select 1 from email.messages m where m.account_id = a.id) as stored,
794
+ (a.last_synced_at is not null
795
+ or exists (select 1 from email.folders f
796
+ where f.account_id = a.id and f.first_contact_at is not null)) as polled,
797
+ (select f.left_alone from email.folders f
798
+ where f.account_id = a.id and f.kind = 'inbox' order by f.first_contact_at nulls last limit 1) as left_alone
799
+ from email.accounts a where a.enabled`);
800
+ const facts = new Map(rows.map((row) => [String(row.id), row]));
801
+ const empty = accounts.filter((account) => facts.get(account.id)?.stored !== true);
802
+ const fresh = empty.filter((account) => facts.get(account.id)?.polled === true);
803
+ const connecting = empty.filter((account) => facts.get(account.id)?.polled !== true);
804
+ const mail = everyId.length === 0
805
+ ? { rows: [] }
806
+ : await ctx.buddi.db.query(`select exists (select 1 from email.messages where account_id = any($1::uuid[])) as has_mail`, [everyId]);
807
+ const hasMail = mail.rows[0]?.has_mail === true;
808
+ return {
809
+ connected: accounts.length
810
+ ? `Connected: ${accounts.map((account) => account.address).join(' · ')}`
811
+ : '',
812
+ hasAccounts: accounts.length > 0,
813
+ anyFresh: fresh.length > 0,
814
+ anyConnecting: connecting.length > 0,
815
+ connecting: connecting.length > 0 ? connectingLine(connecting.map((account) => account.address)) : '',
816
+ hasMail,
817
+ // The list is drawn when there is mail to list, or nothing connected
818
+ // at all (its empty sentence is then the honest one).
819
+ showList: hasMail || accounts.length === 0,
820
+ fresh: fresh.map((account) => ({
821
+ id: account.id,
822
+ address: account.address,
823
+ line: freshLine(account.address, facts.get(account.id)?.left_alone),
824
+ })),
825
+ };
826
+ },
827
+ };
828
+ }
829
+ /** What the page says while a mailbox's first poll has not finished. */
830
+ export function connectingLine(addresses) {
831
+ const list = addresses.length <= 1
832
+ ? (addresses[0] ?? '')
833
+ : `${addresses.slice(0, -1).join(', ')} and ${addresses[addresses.length - 1]}`;
834
+ return `Connecting to ${list}…`;
835
+ }
836
+ /** The first-state sentence for one fresh mailbox. */
837
+ export function freshLine(address, leftAlone) {
838
+ const older = leftAlone === null || leftAlone === undefined ? null : Number(leftAlone);
839
+ const head = `Connected to ${address}. Reading new mail from now on`;
840
+ if (older === null || !Number.isFinite(older))
841
+ return `${head}; older messages left alone.`;
842
+ if (older === 0)
843
+ return `${head}.`;
844
+ return `${head}; ${older.toLocaleString('en-US')} older ${older === 1 ? 'message' : 'messages'} left alone.`;
845
+ }
551
846
  /**
552
847
  * How many of this plugin's rules wait on Settings → Proposals. Zero on an
553
848
  * installation whose core has no proposals table yet.
@@ -846,6 +1141,7 @@ export function emailPageQueries() {
846
1141
  draftQuery(),
847
1142
  messageQuery(),
848
1143
  accountsQuery(),
1144
+ mailStatusQuery(),
849
1145
  policiesQuery(),
850
1146
  ruleThreadsQuery(),
851
1147
  watcherSettingsQuery(),