@xopcai/xopc 0.0.268 → 0.0.270

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 (240) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-Bhyy6ENz.js → activity-store-D_0FmdRj.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B9WObxjr.js → agent-avatar-dicebear-IZvEXak_.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +1 -0
  6. package/dist/gateway/static/root/assets/{agents-BJuTIRPD.js → agents-DzG2qw-c.js} +1 -1
  7. package/dist/gateway/static/root/assets/{api-B2y7ZjZk.js → api-O3TTQ4qN.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-Bbn9mDfL.js → app-management-settings-panel-Cqqsbzri.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-Deo5EsIc.js → appearance-settings-DaJyf32s.js} +1 -1
  10. package/dist/gateway/static/root/assets/{apps-page-Cz4d7ErX.js → apps-page-B4lX6yoT.js} +1 -1
  11. package/dist/gateway/static/root/assets/{archive-plugin-CxJTU8MU.js → archive-plugin-kDPnDTJI.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-C71Cukgp.js → attachment-load-CJ3VceKS.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-_J7UZ55Q.js → automations-page-JwMtU8XB.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-CX8fC8Zt.js → binary-plugins-DzyZXLBX.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-Ci9fjoQL.js → block-editor-kTt3gYIJ.js} +3 -3
  17. package/dist/gateway/static/root/assets/{browser-automation-inputs-s5I78Iko.js → browser-automation-inputs-BKohPYR4.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-automations-page-rDSx0ozx.js → browser-automations-page-ktQfFPk-.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-settings-page-B9RA6x4x.js → browser-settings-page-Dgdt5uVL.js} +3 -3
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +7 -0
  21. package/dist/gateway/static/root/assets/{channels-settings-CEhVLJNa.js → channels-settings-DU4EQnR0.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-status-swr-_OsWr_vS.js → channels-status-swr-DrqzYmDr.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-DMSl8KxS.js → chat-terminal-dock-CIFGGLGa.js} +2 -2
  24. package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +2 -0
  25. package/dist/gateway/static/root/assets/{cron-expression-BByq6Uh8.js → cron-expression-BNwbnrEb.js} +1 -1
  26. package/dist/gateway/static/root/assets/{date-picker-m6JZCUEW.js → date-picker-DKyirU4K.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-CwCAjbaJ.js → dependency-picker-D3vNIjRI.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-DSmeEREd.js → desktop-pet-fQwRb_3p.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-MfKceMoe.js → desktop-pet-settings-DfOJ-GvT.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-CwvWy26h.js → extension-debug-page-Cn53jB5-.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-DLrbVBHM.js → extension-page-IDpLCxpC.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-BI6C4PM-.js → extension-settings-page-B1dds2bP.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-config-swr-OObCK8jM.js → gateway-config-swr-B7dcmP7Q.js} +1 -1
  34. package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +1 -0
  35. package/dist/gateway/static/root/assets/{gateway-startup-retry-D_TxKN_A.js → gateway-startup-retry-JGhGMhVZ.js} +1 -1
  36. package/dist/gateway/static/root/assets/{heartbeat-settings-CUl832Tb.js → heartbeat-settings-B8_zTyev.js} +1 -1
  37. package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +1 -0
  38. package/dist/gateway/static/root/assets/{image-generation-api-fPU9yGsw.js → image-generation-api-BJLX7Qrh.js} +1 -1
  39. package/dist/gateway/static/root/assets/index-1zRt56Zt.css +2 -0
  40. package/dist/gateway/static/root/assets/{index-wKE8Q2FX.js → index-OMnem2nr.js} +47 -47
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-r4DCS19O.js → keyboard-shortcuts-settings-CBvMTFFx.js} +1 -1
  42. package/dist/gateway/static/root/assets/{local-app-workbench-page-qwLuir8A.js → local-app-workbench-page-bj75v2ZE.js} +2 -2
  43. package/dist/gateway/static/root/assets/{local-apps-page-DkfCRLUh.js → local-apps-page-APCMNDvU.js} +1 -1
  44. package/dist/gateway/static/root/assets/{locale-store-DFQX9kTl.js → locale-store-BThkG0W5.js} +1 -1
  45. package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +2 -0
  46. package/dist/gateway/static/root/assets/{management-settings-Cfx4ATTa.js → management-settings-CM62j8ZX.js} +1 -1
  47. package/dist/gateway/static/root/assets/{markdown-view-D-5jHRWg.js → markdown-view-BwjpJVPs.js} +1 -1
  48. package/dist/gateway/static/root/assets/{media-plugins-DOLjWd3y.js → media-plugins-C10byeaa.js} +1 -1
  49. package/dist/gateway/static/root/assets/{messages-Dj8QuS6e.js → messages-D0V_bgRP.js} +2 -2
  50. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-BGW9joAb.js → mobile-pairing-wizard-BCWfwVx3.js} +1 -1
  51. package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +5 -0
  52. package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +8 -0
  53. package/dist/gateway/static/root/assets/{page-tabs-_SGXMT2O.js → page-tabs-qQ36zncF.js} +1 -1
  54. package/dist/gateway/static/root/assets/{preview-open-alternatives-lVetfCWk.js → preview-open-alternatives-BiAJvvCo.js} +1 -1
  55. package/dist/gateway/static/root/assets/proactive-card-CcNBqHoH.js +1 -0
  56. package/dist/gateway/static/root/assets/proactive-page-C3K61jve.js +1 -0
  57. package/dist/gateway/static/root/assets/{product-open-page-CIGLPFm7.js → product-open-page-CunnDP4w.js} +1 -1
  58. package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +1 -0
  59. package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +1 -0
  60. package/dist/gateway/static/root/assets/{registry-api-CsZLatKo.js → registry-api-0JSegbNl.js} +1 -1
  61. package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +1 -0
  62. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BDqVrUEj.js → runtime-tools-settings-panel-bu_mwBTr.js} +1 -1
  63. package/dist/gateway/static/root/assets/{schema-form-8RQgFJJO.js → schema-form-BE0sgZyz.js} +1 -1
  64. package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +1 -0
  65. package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +1 -0
  66. package/dist/gateway/static/root/assets/{settings-form-section-j4UjGM-f.js → settings-form-section-CBo517lV.js} +1 -1
  67. package/dist/gateway/static/root/assets/{settings-page-lMi50B_s.js → settings-page-DBPimx93.js} +1 -1
  68. package/dist/gateway/static/root/assets/{setup-status-panel-Dx4Fy3rU.js → setup-status-panel-J3AnooPW.js} +1 -1
  69. package/dist/gateway/static/root/assets/{share-preview-page-aSyKRH5y.js → share-preview-page-DdV75VTe.js} +1 -1
  70. package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +1 -0
  71. package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +1 -0
  72. package/dist/gateway/static/root/assets/{skills-page-C2_CAvxW.js → skills-page-Cn_-nvRo.js} +1 -1
  73. package/dist/gateway/static/root/assets/{skills-page.utils-B00e4Q30.js → skills-page.utils-CfVAc_lu.js} +1 -1
  74. package/dist/gateway/static/root/assets/{system-settings-panel-CulAkrsV.js → system-settings-panel-B-pzalp-.js} +1 -1
  75. package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +1 -0
  76. package/dist/gateway/static/root/assets/{theme-store-zRT6vaZc.js → theme-store-1wryLgBQ.js} +1 -1
  77. package/dist/gateway/static/root/assets/{tunnel-api-C01xgCWR.js → tunnel-api-Cgpnm2fL.js} +1 -1
  78. package/dist/gateway/static/root/assets/{use-autosave-DfSJ3c2p.js → use-autosave-N_lm4FdD.js} +1 -1
  79. package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +2 -0
  80. package/dist/gateway/static/root/assets/{voice-api-key-field-9v-miN8o.js → voice-api-key-field-DMsyVfri.js} +1 -1
  81. package/dist/gateway/static/root/assets/{voice-config-api-DpJEu2RQ.js → voice-config-api-QWVmiAp3.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-CREYgh-1.js → work-discovery-overlay-BC0vAxp1.js} +1 -1
  83. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Cz9jQIlP.js +3 -0
  84. package/dist/gateway/static/root/assets/workflows-page-DA6OOK6X.js +6 -0
  85. package/dist/gateway/static/root/index.html +10 -10
  86. package/dist/gateway/static/root/notification-sw.js +15 -0
  87. package/dist/package.js +1 -1
  88. package/dist/packages/gateway-contract/src/notifications.js +15 -1
  89. package/dist/packages/gateway-contract/src/proactive.js +120 -0
  90. package/dist/packages/realtime-protocol/src/voice.js +2 -1
  91. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  92. package/dist/src/agent/tool-manuals/xopc-use.js +19 -1
  93. package/dist/src/agent/tools/factory.js +1 -0
  94. package/dist/src/agent/tools/xopc-use-tool.d.ts +3 -2
  95. package/dist/src/agent/tools/xopc-use-tool.js +48 -4
  96. package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
  97. package/dist/src/agent/workflow/subagent-runner.js +2 -2
  98. package/dist/src/browser/automations/schema.d.ts +1 -1
  99. package/dist/src/browser/automations/service.d.ts +1 -1
  100. package/dist/src/cli/bin.js +2 -2
  101. package/dist/src/cli/commands/agent.js +2 -2
  102. package/dist/src/cli/commands/auth.js +1 -1
  103. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  104. package/dist/src/cli/commands/extension-dev.js +1 -1
  105. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  106. package/dist/src/cli/commands/extension.js +1 -1
  107. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  108. package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
  109. package/dist/src/cli/commands/models.js +2 -2
  110. package/dist/src/cli/commands/onboard.js +1 -1
  111. package/dist/src/cli/commands/platform.js +1 -1
  112. package/dist/src/cli/commands/profile.js +1 -1
  113. package/dist/src/cli/commands/tunnel.js +1 -1
  114. package/dist/src/cli/commands/update.js +1 -1
  115. package/dist/src/cli/extension-cli-register.js +1 -1
  116. package/dist/src/config/index.js +1 -1
  117. package/dist/src/connectors/connected-source-normalizers.js +3 -0
  118. package/dist/src/gateway/hono/routes/index.js +0 -2
  119. package/dist/src/gateway/hono/routes/lazy-bundles.js +12 -0
  120. package/dist/src/gateway/hono/routes/proactive-control.d.ts +3 -0
  121. package/dist/src/gateway/hono/routes/proactive-control.js +168 -0
  122. package/dist/src/gateway/hono/routes/proactive.d.ts +1 -1
  123. package/dist/src/gateway/hono/routes/proactive.js +12 -5
  124. package/dist/src/gateway/hono/routes/voice.js +1 -1
  125. package/dist/src/gateway/run-loop.js +1 -1
  126. package/dist/src/gateway/security/gateway-scopes.js +5 -0
  127. package/dist/src/gateway/server.js +1 -1
  128. package/dist/src/gateway/service.d.ts +0 -1
  129. package/dist/src/gateway/service.js +21 -23
  130. package/dist/src/notifications/planner.js +4 -3
  131. package/dist/src/notifications/proactive-channel.d.ts +8 -0
  132. package/dist/src/notifications/proactive-channel.js +57 -0
  133. package/dist/src/notifications/proactive-policy.d.ts +3 -0
  134. package/dist/src/notifications/proactive-policy.js +32 -0
  135. package/dist/src/notifications/service.d.ts +78 -0
  136. package/dist/src/notifications/service.js +71 -13
  137. package/dist/src/notifications/store.d.ts +2 -0
  138. package/dist/src/notifications/store.js +8 -1
  139. package/dist/src/notifications/web-push.d.ts +19 -0
  140. package/dist/src/notifications/web-push.js +182 -0
  141. package/dist/src/proactive/actions/service.js +12 -2
  142. package/dist/src/proactive/execution/agent-executor.d.ts +5 -0
  143. package/dist/src/proactive/execution/agent-executor.js +21 -0
  144. package/dist/src/proactive/execution/authorization.d.ts +5 -0
  145. package/dist/src/proactive/execution/authorization.js +61 -0
  146. package/dist/src/proactive/execution/context.d.ts +4 -0
  147. package/dist/src/proactive/execution/context.js +51 -14
  148. package/dist/src/proactive/execution/insight.d.ts +7 -0
  149. package/dist/src/proactive/execution/insight.js +36 -3
  150. package/dist/src/proactive/execution/repository.d.ts +2 -0
  151. package/dist/src/proactive/execution/repository.js +53 -9
  152. package/dist/src/proactive/execution/types.d.ts +7 -0
  153. package/dist/src/proactive/execution/worker.js +43 -7
  154. package/dist/src/proactive/experience.d.ts +69 -0
  155. package/dist/src/proactive/experience.js +90 -0
  156. package/dist/src/proactive/follow-ups.d.ts +123 -0
  157. package/dist/src/proactive/follow-ups.js +169 -0
  158. package/dist/src/proactive/inbox/cards.d.ts +21 -0
  159. package/dist/src/proactive/inbox/cards.js +266 -0
  160. package/dist/src/proactive/inbox/delivery.d.ts +6 -0
  161. package/dist/src/proactive/inbox/delivery.js +54 -0
  162. package/dist/src/proactive/inbox/digest.d.ts +8 -0
  163. package/dist/src/proactive/inbox/digest.js +112 -0
  164. package/dist/src/proactive/inbox/lifecycle.d.ts +4 -0
  165. package/dist/src/proactive/inbox/lifecycle.js +61 -0
  166. package/dist/src/proactive/inbox/notification-policy.d.ts +1 -0
  167. package/dist/src/proactive/inbox/notification-policy.js +22 -0
  168. package/dist/src/proactive/inbox/repository.d.ts +1 -0
  169. package/dist/src/proactive/inbox/repository.js +75 -12
  170. package/dist/src/proactive/inbox/types.d.ts +11 -1
  171. package/dist/src/proactive/inbox/worker.js +9 -3
  172. package/dist/src/proactive/index.js +2 -2
  173. package/dist/src/proactive/mail-thread.d.ts +13 -0
  174. package/dist/src/proactive/mail-thread.js +54 -0
  175. package/dist/src/proactive/maintenance.js +7 -0
  176. package/dist/src/proactive/metrics.d.ts +10 -0
  177. package/dist/src/proactive/metrics.js +27 -0
  178. package/dist/src/proactive/policy/presence.d.ts +2 -0
  179. package/dist/src/proactive/policy/presence.js +27 -0
  180. package/dist/src/proactive/policy/service.d.ts +51 -0
  181. package/dist/src/proactive/policy/service.js +120 -0
  182. package/dist/src/proactive/routing/matcher.js +3 -2
  183. package/dist/src/proactive/scenarios/control.d.ts +87 -0
  184. package/dist/src/proactive/scenarios/control.js +108 -0
  185. package/dist/src/proactive/scenarios/preview.d.ts +13 -0
  186. package/dist/src/proactive/scenarios/preview.js +81 -0
  187. package/dist/src/proactive/scenarios/prompt-composer.js +4 -2
  188. package/dist/src/proactive/scenarios/repository.js +5 -1
  189. package/dist/src/proactive/service.js +1 -1
  190. package/dist/src/proactive/temporal/schedule.d.ts +3 -0
  191. package/dist/src/proactive/temporal/schedule.js +67 -0
  192. package/dist/src/proactive/temporal/worker.d.ts +1 -0
  193. package/dist/src/proactive/temporal/worker.js +24 -6
  194. package/dist/src/storage/sqlite/migrations/159_proactive_controls.sql +68 -0
  195. package/dist/src/storage/sqlite/migrations/160_proactive_web_push.sql +27 -0
  196. package/dist/src/storage/sqlite/migrations/161_proactive_delivery_and_lifecycle.sql +51 -0
  197. package/dist/src/storage/sqlite/migrations/162_proactive_product.sql +7 -0
  198. package/dist/src/storage/sqlite/migrations/163_proactive_follow_ups.sql +29 -0
  199. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  200. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  201. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  202. package/dist/src/storage/sqlite/schema.js +1 -1
  203. package/dist/src/tasks/home-query-service.js +1 -1
  204. package/dist/src/tasks/index.js +4 -4
  205. package/dist/src/voice/dashscope/streaming-stt-session.js +1 -0
  206. package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +1 -0
  207. package/dist/src/voice/dashscope/streaming-tts-stream.js +8 -0
  208. package/dist/src/voice/realtime/agentBroker.js +1 -1
  209. package/dist/src/voice/realtime/agentEngine.js +1 -1
  210. package/dist/src/voice/realtime/pcm-output-gain.d.ts +2 -0
  211. package/dist/src/voice/realtime/pcm-output-gain.js +16 -0
  212. package/dist/src/voice/realtime/runtime.d.ts +2 -1
  213. package/dist/src/voice/realtime/runtime.js +25 -7
  214. package/dist/src/workflows/domain/run.d.ts +1 -0
  215. package/dist/src/workflows/index.js +2 -2
  216. package/dist/src/workflows/service/workflow-run-service.d.ts +3 -0
  217. package/dist/src/workflows/service/workflow-run-service.js +27 -6
  218. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
  219. package/package.json +7 -5
  220. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-J1YFNG26.js +0 -1
  221. package/dist/gateway/static/root/assets/automations-workspace-Bn8nwUOL.js +0 -6
  222. package/dist/gateway/static/root/assets/capabilities-settings-panel-C1GUih8m.js +0 -7
  223. package/dist/gateway/static/root/assets/connectors-page-IQAQDSmO.js +0 -2
  224. package/dist/gateway/static/root/assets/gateway-settings-B3H7Vfbh.js +0 -1
  225. package/dist/gateway/static/root/assets/home-page-CT4JL2jm.js +0 -1
  226. package/dist/gateway/static/root/assets/index-CRJrO4GI.css +0 -2
  227. package/dist/gateway/static/root/assets/logs-page-DrNaaPWc.js +0 -2
  228. package/dist/gateway/static/root/assets/note-detail-panel-Dbj5OvXE.js +0 -5
  229. package/dist/gateway/static/root/assets/notes-page-5hRB3WXc.js +0 -8
  230. package/dist/gateway/static/root/assets/project-detail-page-CblWLA8k.js +0 -1
  231. package/dist/gateway/static/root/assets/projects-page-CGk-kzqs.js +0 -1
  232. package/dist/gateway/static/root/assets/remote-access-hub-Du8PweyU.js +0 -1
  233. package/dist/gateway/static/root/assets/sessions-page-BFm94dJC.js +0 -1
  234. package/dist/gateway/static/root/assets/settings-advanced-gate-C0H-cToA.js +0 -1
  235. package/dist/gateway/static/root/assets/shares-settings-CqF9s0pl.js +0 -1
  236. package/dist/gateway/static/root/assets/skill-reload-api-BBL_ZUSC.js +0 -1
  237. package/dist/gateway/static/root/assets/task-detail-page-D1FmRFIn.js +0 -1
  238. package/dist/gateway/static/root/assets/user-model-page-BGC_5baJ.js +0 -2
  239. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BfCWdw8F.js +0 -3
  240. package/dist/gateway/static/root/assets/workflows-page-CvmKQkD0.js +0 -6
@@ -4,9 +4,9 @@ import { ExtensionLoader } from "../extensions/loader.js";
4
4
  import "../extensions/index.js";
5
5
  import { MessageBus } from "../infra/bus/queue.js";
6
6
  import "../infra/bus/index.js";
7
- import { createDefaultContext } from "./registry.js";
8
7
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
9
8
  import "../config/index.js";
9
+ import { createDefaultContext } from "./registry.js";
10
10
  import { registerExtensionCliProgram } from "../extensions/sdk/channel-helpers.js";
11
11
  import { join } from "path";
12
12
  //#region src/cli/extension-cli-register.ts
@@ -13,10 +13,10 @@ import { clearConfigValueCache, getAllowedCommands, getCacheStats, init_resolve_
13
13
  import { CustomModelSchema, ImageGenerationCapabilitiesSchema, ImageGenerationModelSchema, ImageGenerationProviderSchema, ModelOverrideSchema, ModelsJsonSchema, OpenAICompatSchema, OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema, OpenRouterRoutingSchema, ProviderConfigSchema, VercelGatewayRoutingSchema, getDefaultModelValues, init_models_json, loadModelsJson, modelsJsonExists, saveModelsJson, validateModelsConfig } from "./models-json.js";
14
14
  import { canonicalizeConfiguredMcpServer, isKnownCliMcpTypeAlias, normalizeConfiguredMcpServers, resolveXopcMcpTransportAlias } from "./mcp-config-normalize.js";
15
15
  import { formatThinkingLevels, listThinkingLevels, normalizeElevatedMode, normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel, thinkLevelToNumber } from "../agent/transcript/thinking-types.js";
16
+ import { diffConfigPaths } from "./diff.js";
16
17
  import { getWorkspacePath } from "./workspace-path-helpers.js";
17
18
  import { listAgentProfileMarkdownDirs, listAgentWorkspaceDirs } from "./workspace-dirs.js";
18
19
  import { ProfileManager, createProfile, deleteProfile, getCurrentProfile, getProfileManager, getProfileNameFromDir, getSwitchCommand, listProfiles, resolveProfileStateDir } from "./profile.js";
19
- import { diffConfigPaths } from "./diff.js";
20
20
  import { BASE_RELOAD_RULES, buildReloadPlan, matchReloadRule } from "./rules.js";
21
21
  import { ConfigHotReloader } from "./reload.js";
22
22
  //#region src/config/index.ts
@@ -122,6 +122,9 @@ function normalizeCalendar(result) {
122
122
  value: compact({
123
123
  id: externalId,
124
124
  title: text(event, "summary", "title", "name"),
125
+ description: text(event, "description"),
126
+ location: text(event, "location"),
127
+ allDay: Boolean(event.start && typeof event.start === "object" && "date" in event.start),
125
128
  start: occurredAt,
126
129
  end: time(event.end ?? event.endTime ?? event.end_time),
127
130
  organizer: event.organizer,
@@ -20,7 +20,6 @@ import { registerLocalAppsRoutes } from "./local-apps.js";
20
20
  import { registerWorkDiscoveryRoutes } from "./work-discovery.js";
21
21
  import { registerContextSourceRoutes } from "./context-sources.js";
22
22
  import { registerTaskRoutes } from "./tasks.js";
23
- import { registerProactiveRoutes } from "./proactive.js";
24
23
  import { registerMobilePrivacyRoutes } from "./mobile-privacy.js";
25
24
  import { mountAppLazyRoutePrefixes, registerAuthenticatedLazyRouteFallback } from "./lazy-fallback.js";
26
25
  //#region src/gateway/hono/routes/index.ts
@@ -40,7 +39,6 @@ function registerCoreAuthenticatedRoutes(authenticated, deps) {
40
39
  registerWorkDiscoveryRoutes(authenticated, deps);
41
40
  registerContextSourceRoutes(authenticated, deps);
42
41
  registerTaskRoutes(authenticated, deps);
43
- registerProactiveRoutes(authenticated, deps);
44
42
  registerSearchRoutes(authenticated, deps);
45
43
  registerDevicePushRoutes(authenticated);
46
44
  registerNotificationRoutes(authenticated, deps);
@@ -3,6 +3,18 @@ function startsWithAny(path, prefixes) {
3
3
  return prefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
4
4
  }
5
5
  const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
6
+ {
7
+ id: "proactive",
8
+ match: (path) => startsWithAny(path, [
9
+ "/api/proactive",
10
+ "/api/inbox/judgments",
11
+ "/api/internal/proactive"
12
+ ]),
13
+ load: async () => {
14
+ const { registerProactiveRoutes } = await import("./proactive.js");
15
+ return { register: registerProactiveRoutes };
16
+ }
17
+ },
6
18
  {
7
19
  id: "runtime-tools",
8
20
  match: (path) => startsWithAny(path, ["/api/runtime-tools"]),
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerProactiveControlRoutes(app: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,168 @@
1
+ import { getSqliteDatabase } from "../../../storage/sqlite/transaction.js";
2
+ import { ProactiveConflict, proactivePreferences, updateProactivePreferences } from "../../../proactive/policy/service.js";
3
+ import { controlledSubscriptions, createControlledSubscription, requireSubscription, templateCatalog, updateControlledSubscription } from "../../../proactive/scenarios/control.js";
4
+ import { listMailFollowUps, mailFollowUpSources, startMailFollowUp, updateMailFollowUp } from "../../../proactive/follow-ups.js";
5
+ import { cardChanges, getCard, listCards, performCardAction } from "../../../proactive/inbox/cards.js";
6
+ import { checkDelegation, delegationOverview, startDelegation } from "../../../proactive/experience.js";
7
+ import { recordProactivePresence } from "../../../proactive/policy/presence.js";
8
+ import { digestCards } from "../../../proactive/inbox/digest.js";
9
+ import { acknowledgeBrowserProbe, listBrowserProbes, prepareBrowserPush, registerBrowserPush, testBrowserPush, unregisterBrowserPush } from "../../../notifications/web-push.js";
10
+ import { ReadonlyProactiveAgentExecutor } from "../../../proactive/execution/agent-executor.js";
11
+ import { proactiveMetrics } from "../../../proactive/metrics.js";
12
+ import { previewSubscription } from "../../../proactive/scenarios/preview.js";
13
+ import { ZodError } from "zod";
14
+ //#region src/gateway/hono/routes/proactive-control.ts
15
+ function registerProactiveControlRoutes(app, deps) {
16
+ app.onError((error, c) => c.json({
17
+ ok: false,
18
+ error: error instanceof ZodError ? "Invalid request" : error.message
19
+ }, error instanceof ProactiveConflict ? 409 : 400));
20
+ const workspace = () => deps.service.currentWorkspacePath;
21
+ app.get("/api/proactive/follow-ups/sources", (c) => c.json({
22
+ ok: true,
23
+ sources: mailFollowUpSources(workspace())
24
+ }));
25
+ app.get("/api/proactive/follow-ups", (c) => c.json({
26
+ ok: true,
27
+ followUps: listMailFollowUps(workspace())
28
+ }));
29
+ app.post("/api/proactive/follow-ups", deps.strictRateLimitMiddleware, async (c) => c.json({
30
+ ok: true,
31
+ followUp: startMailFollowUp(workspace(), await c.req.json())
32
+ }, 201));
33
+ app.patch("/api/proactive/follow-ups/:id", deps.strictRateLimitMiddleware, async (c) => c.json({
34
+ ok: true,
35
+ followUp: updateMailFollowUp(workspace(), c.req.param("id"), await c.req.json())
36
+ }));
37
+ app.get("/api/proactive/overview", (c) => c.json({
38
+ ok: true,
39
+ ...delegationOverview(workspace())
40
+ }));
41
+ app.post("/api/proactive/delegations", deps.strictRateLimitMiddleware, async (c) => c.json({
42
+ ok: true,
43
+ subscription: startDelegation(workspace(), await c.req.json())
44
+ }, 201));
45
+ app.post("/api/proactive/subscriptions/:id/check", deps.strictRateLimitMiddleware, (c) => c.json({
46
+ ok: true,
47
+ ...checkDelegation(workspace(), c.req.param("id"))
48
+ }, 202));
49
+ for (const path of ["/api/proactive/*", "/api/inbox/judgments/*"]) app.use(path, async (c, next) => {
50
+ try {
51
+ const id = c.req.path.match(/^\/api\/inbox\/judgments\/([^/]+)/)?.[1];
52
+ if (id && id !== "changes") getCard(decodeURIComponent(id), workspace());
53
+ await next();
54
+ } catch (error) {
55
+ return c.json({
56
+ ok: false,
57
+ error: error instanceof ZodError ? "Invalid request" : error instanceof Error ? error.message : "Request failed"
58
+ }, error instanceof ProactiveConflict ? 409 : 400);
59
+ }
60
+ });
61
+ app.get("/api/proactive/web-push/probes", (c) => c.json({
62
+ ok: true,
63
+ probes: listBrowserProbes(workspace())
64
+ }));
65
+ app.post("/api/proactive/web-push/subscriptions/:id/test", deps.strictRateLimitMiddleware, async (c) => c.json({
66
+ ok: true,
67
+ ...await testBrowserPush(workspace(), c.req.param("id"))
68
+ }));
69
+ app.post("/api/proactive/web-push/probes/:id/opened", deps.strictRateLimitMiddleware, (c) => {
70
+ acknowledgeBrowserProbe(workspace(), c.req.param("id"));
71
+ return c.json({ ok: true });
72
+ });
73
+ app.post("/api/proactive/web-push/prepare", deps.strictRateLimitMiddleware, (c) => c.json({
74
+ ok: true,
75
+ ...prepareBrowserPush()
76
+ }));
77
+ app.post("/api/proactive/web-push/subscriptions", deps.strictRateLimitMiddleware, async (c) => c.json({
78
+ ok: true,
79
+ ...registerBrowserPush(workspace(), await c.req.json())
80
+ }, 201));
81
+ app.delete("/api/proactive/web-push/subscriptions/:id", deps.strictRateLimitMiddleware, (c) => {
82
+ unregisterBrowserPush(workspace(), c.req.param("id"));
83
+ return c.json({ ok: true });
84
+ });
85
+ app.post("/api/proactive/presence", deps.strictRateLimitMiddleware, async (c) => {
86
+ recordProactivePresence(workspace(), await c.req.json());
87
+ return c.json({ ok: true });
88
+ });
89
+ app.get("/api/proactive/metrics", (c) => c.json({
90
+ ok: true,
91
+ metrics: proactiveMetrics(workspace())
92
+ }));
93
+ app.get("/api/proactive/digests/:id", (c) => c.json({
94
+ ok: true,
95
+ cards: digestCards(c.req.param("id"), workspace())
96
+ }));
97
+ app.post("/api/proactive/subscriptions/:id/preview", deps.strictRateLimitMiddleware, async (c) => c.json({
98
+ ok: true,
99
+ ...await previewSubscription(workspace(), c.req.param("id"), new ReadonlyProactiveAgentExecutor(() => deps.service.getConfig()), c.req.raw.signal)
100
+ }));
101
+ app.get("/api/proactive/templates", (c) => c.json({
102
+ ok: true,
103
+ templates: templateCatalog(workspace())
104
+ }));
105
+ app.get("/api/proactive/preferences", (c) => c.json({
106
+ ok: true,
107
+ preferences: proactivePreferences(workspace())
108
+ }));
109
+ app.patch("/api/proactive/preferences", deps.strictRateLimitMiddleware, async (c) => c.json({
110
+ ok: true,
111
+ preferences: updateProactivePreferences(workspace(), await c.req.json())
112
+ }));
113
+ app.get("/api/proactive/subscriptions", (c) => c.json({
114
+ ok: true,
115
+ subscriptions: controlledSubscriptions(workspace())
116
+ }));
117
+ app.post("/api/proactive/subscriptions", deps.strictRateLimitMiddleware, async (c) => c.json({
118
+ ok: true,
119
+ subscription: createControlledSubscription(workspace(), await c.req.json())
120
+ }, 201));
121
+ app.patch("/api/proactive/subscriptions/:id", deps.strictRateLimitMiddleware, async (c) => c.json({
122
+ ok: true,
123
+ subscription: updateControlledSubscription(workspace(), c.req.param("id"), await c.req.json())
124
+ }));
125
+ app.get("/api/proactive/subscriptions/:id/runs", (c) => {
126
+ requireSubscription(c.req.param("id"), workspace());
127
+ return c.json({
128
+ ok: true,
129
+ runs: getSqliteDatabase().prepare(`SELECT run_id AS id, status, outcome_reason AS reason,
130
+ started_at AS startedAt, completed_at AS completedAt, error_message AS error FROM proactive_runs WHERE subscription_id = ? ORDER BY started_at DESC LIMIT 30`).all(c.req.param("id"))
131
+ });
132
+ });
133
+ app.get("/api/proactive/cards", (c) => c.json({
134
+ ok: true,
135
+ ...listCards(workspace(), {
136
+ status: c.req.query("status"),
137
+ before: c.req.query("before")
138
+ })
139
+ }));
140
+ app.get("/api/inbox/judgments/changes", (c) => {
141
+ const cursor = Number(c.req.query("cursor") ?? 0);
142
+ if (!Number.isSafeInteger(cursor) || cursor < 0) return c.json({
143
+ ok: false,
144
+ error: "Invalid cursor"
145
+ }, 400);
146
+ return c.json({
147
+ ok: true,
148
+ ...cardChanges(workspace(), cursor)
149
+ });
150
+ });
151
+ app.get("/api/inbox/judgments/:itemId", (c) => c.json({
152
+ ok: true,
153
+ card: getCard(c.req.param("itemId"), workspace())
154
+ }));
155
+ app.post("/api/inbox/judgments/:itemId/actions", deps.strictRateLimitMiddleware, async (c) => {
156
+ const card = performCardAction(c.req.param("itemId"), workspace(), await c.req.json());
157
+ deps.service.emit("proactive.card.changed", {
158
+ cardId: card.id,
159
+ revision: card.revision
160
+ });
161
+ return c.json({
162
+ ok: true,
163
+ card
164
+ });
165
+ });
166
+ }
167
+ //#endregion
168
+ export { registerProactiveControlRoutes };
@@ -1,4 +1,4 @@
1
1
  import type { Hono } from 'hono';
2
2
  import type { AuthenticatedRouteDeps } from './deps.js';
3
- /** User-facing judgment inbox plus internal diagnostics. There is intentionally no proactive control-panel API. */
3
+ /** Proactive controls, cards and internal diagnostics. */
4
4
  export declare function registerProactiveRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
@@ -1,10 +1,14 @@
1
+ import { getInboxItem } from "../../../proactive/inbox/repository.js";
2
+ import { listCards } from "../../../proactive/inbox/cards.js";
3
+ import { registerProactiveControlRoutes } from "./proactive-control.js";
1
4
  //#region src/gateway/hono/routes/proactive.ts
2
5
  function positiveInt(value, fallback) {
3
6
  const parsed = Number(value);
4
7
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
5
8
  }
6
- /** User-facing judgment inbox plus internal diagnostics. There is intentionally no proactive control-panel API. */
9
+ /** Proactive controls, cards and internal diagnostics. */
7
10
  function registerProactiveRoutes(authenticated, deps) {
11
+ registerProactiveControlRoutes(authenticated, deps);
8
12
  authenticated.get("/api/inbox/judgments", (c) => {
9
13
  const status = c.req.query("status");
10
14
  if (status && ![
@@ -16,12 +20,15 @@ function registerProactiveRoutes(authenticated, deps) {
16
20
  ok: false,
17
21
  error: "Invalid inbox status"
18
22
  }, 400);
23
+ const page = listCards(deps.service.currentWorkspacePath, {
24
+ status,
25
+ limit: positiveInt(c.req.query("limit"), 50),
26
+ before: c.req.query("before")
27
+ });
19
28
  return c.json({
20
29
  ok: true,
21
- items: deps.service.proactiveInbox.list({
22
- ...status ? { status } : {},
23
- limit: positiveInt(c.req.query("limit"), 50)
24
- })
30
+ ...page,
31
+ items: page.cards.map((card) => getInboxItem(card.id))
25
32
  });
26
33
  });
27
34
  authenticated.post("/api/inbox/judgments/:itemId/transition", deps.strictRateLimitMiddleware, async (c) => {
@@ -256,7 +256,7 @@ function registerVoiceRoutes(authenticated, deps) {
256
256
  }
257
257
  }, 400);
258
258
  const principal = getGatewayPrincipal(c);
259
- service.voiceRealtime.cancelSession(parsed.data.sessionId, parsed.data.ticket, principal.principalId);
259
+ await service.voiceRealtime.cancelSession(parsed.data.sessionId, parsed.data.ticket, principal.principalId);
260
260
  return c.json({ ok: true });
261
261
  });
262
262
  authenticated.post("/api/voice/language", strictRateLimitMiddleware, async (c) => {
@@ -1,6 +1,6 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
- import "../config/index.js";
3
2
  import { isRestartEnabled } from "../config/commands.flags.js";
3
+ import "../config/index.js";
4
4
  import { runBootstrapMigrationsSync } from "../migrations/runner.js";
5
5
  import { restartGatewayProcessWithFreshPid } from "./respawn.js";
6
6
  import { acquireGatewayLock } from "./lock.js";
@@ -63,6 +63,11 @@ function requiredGatewayScope(method, path) {
63
63
  if (path.startsWith("/api/agents") || path.startsWith("/api/models")) return methodScope(method, "agents.read", "gateway.admin");
64
64
  if (path.startsWith("/api/sessions") || path.startsWith("/api/side-chats")) return methodScope(method, "sessions.read", "sessions.write");
65
65
  if (path.startsWith("/api/tasks")) return methodScope(method, "tasks.read", "tasks.write");
66
+ if (method === "POST" && /^\/api\/proactive\/subscriptions\/[^/]+\/preview$/.test(path)) return "agents.run";
67
+ if (/^\/api\/inbox\/judgments\/[^/]+\/workflow$/.test(path)) return methodScope(method, "automations.read", "automations.write");
68
+ if (method === "POST" && /^\/api\/inbox\/judgments\/[^/]+\/prepare$/.test(path)) return "automations.write";
69
+ if (path.startsWith("/api/proactive/web-push")) return "notifications.self";
70
+ if (path === "/api/proactive" || path.startsWith("/api/proactive/")) return methodScope(method, "tasks.read", "tasks.write");
66
71
  if (path.startsWith("/api/home") || path.startsWith("/api/inbox")) return methodScope(method, "tasks.read", "tasks.write");
67
72
  if (path.startsWith("/api/automations") || path.startsWith("/api/automation-runs")) return methodScope(method, "automations.read", "automations.write");
68
73
  if (path.startsWith("/api/workflows")) return methodScope(method, "automations.read", "automations.write");
@@ -1,6 +1,6 @@
1
1
  import { resolveGatewayBindHost, resolveGatewayListenHosts } from "../config/gateway-bind.js";
2
- import { ensureXopcCliOnPath } from "../infra/path-env.js";
3
2
  import { resolveGatewayListenPlan } from "./listen.js";
3
+ import { ensureXopcCliOnPath } from "../infra/path-env.js";
4
4
  import { GatewayService } from "./service.js";
5
5
  import { handleSiteShareUpgrade } from "../share/site-share-router.js";
6
6
  import { createHonoApp } from "./hono/app.js";
@@ -179,7 +179,6 @@ export declare class GatewayService {
179
179
  private schedulePostReadySidecars;
180
180
  private runPostReadySidecars;
181
181
  start(): Promise<void>;
182
- private ensureDefaultProactiveScenarioSubscriptions;
183
182
  /** Called when the HTTP listener is bound (before deferred channel work). */
184
183
  markHttpListening(): void;
185
184
  isGatewayReady(): boolean;
@@ -31,11 +31,13 @@ import { resolveProjectAgentId } from "../projects/project-agent.js";
31
31
  import "../projects/index.js";
32
32
  import { resolveEffectiveGatewayPort } from "./host.js";
33
33
  import { onSessionTranscriptUpdate } from "../session/transcript-events.js";
34
+ import { ProactiveScenarioService } from "../proactive/scenarios/service.js";
35
+ import { ProactiveEventService } from "../proactive/service.js";
36
+ import { TaskApplicationService } from "../tasks/task-application-service.js";
37
+ import { ProactiveInboxService } from "../proactive/inbox/service.js";
34
38
  import { AutomationService } from "../automations/service/automation-service.js";
35
39
  import { onAutomationProductEvent, publishAutomationProductEvent } from "../automations/product-events.js";
36
40
  import "../automations/index.js";
37
- import { TaskApplicationService } from "../tasks/task-application-service.js";
38
- import { ProactiveScenarioService } from "../proactive/scenarios/service.js";
39
41
  import { TaskOutboxDispatcher } from "../tasks/task-outbox-dispatcher.js";
40
42
  import { TaskRunDispatcher } from "../tasks/task-run-dispatcher.js";
41
43
  import { TaskSignalService } from "../tasks/task-signal-service.js";
@@ -72,6 +74,7 @@ import "../endpoint-tools/index.js";
72
74
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
73
75
  import { prepareAutomationAgentSession } from "./automation-agent-session.js";
74
76
  import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
77
+ import { deliverProactiveCard } from "../proactive/inbox/delivery.js";
75
78
  import { buildVoiceMemoryContext } from "../voice/realtime/memory-context.js";
76
79
  import { buildVoicePersonaContext } from "../voice/realtime/persona-context.js";
77
80
  import { voiceMemoryBudget, voicePersonaBudget } from "../voice/realtime/conversation-context.js";
@@ -106,12 +109,10 @@ import "../local-apps/index.js";
106
109
  import { createRuntimeBrowserAutomationService } from "../browser/automations/runtime-service.js";
107
110
  import "../browser/automations/index.js";
108
111
  import { mapProductEventToProactive } from "../proactive/events/product-event-bridge.js";
109
- import { ProactiveEventService } from "../proactive/service.js";
110
112
  import { ReadonlyProactiveAgentExecutor } from "../proactive/execution/agent-executor.js";
111
113
  import { listInsights } from "../proactive/execution/repository.js";
112
114
  import { ProactiveWorker } from "../proactive/execution/worker.js";
113
115
  import { ProactiveTemporalWorker } from "../proactive/temporal/worker.js";
114
- import { ProactiveInboxService } from "../proactive/inbox/service.js";
115
116
  import { ProactiveInboxWorker } from "../proactive/inbox/worker.js";
116
117
  import "../proactive/index.js";
117
118
  import { scheduleGatewayUpdateCheck } from "../infra/update-startup.js";
@@ -317,7 +318,7 @@ var GatewayService = class {
317
318
  this.proactiveWorker = new ProactiveWorker(new ReadonlyProactiveAgentExecutor(() => this.config));
318
319
  this.proactiveTemporalWorker = new ProactiveTemporalWorker(this.proactive);
319
320
  this.proactiveInboxWorker = new ProactiveInboxWorker({ deliver: async ({ inboxItem }) => {
320
- this.emit("proactive.inbox.created", inboxItem);
321
+ return deliverProactiveCard(inboxItem, this.createNotificationService(), (type, payload) => this.realtime.broker.publish("gateway", type, payload));
321
322
  } });
322
323
  let bootstrapConfigChanged = initializeVoiceDefaults(this.config, inferProductLanguageFromEnvironment());
323
324
  const starterResult = ensureStarterAgentsInitialized(this.config);
@@ -680,7 +681,21 @@ var GatewayService = class {
680
681
  return this.taskRunDispatcher;
681
682
  }
682
683
  createNotificationService() {
683
- if (!this.notificationService) this.notificationService = new NotificationService({ publish: (type, payload) => this.realtime.broker.publish("gateway", type, payload) });
684
+ if (!this.notificationService) this.notificationService = new NotificationService({
685
+ publish: (type, payload) => this.realtime.broker.publish("gateway", type, payload),
686
+ sendChannel: async (target, text) => {
687
+ const outbound = this.channelManager.getPlugin("telegram")?.outbound;
688
+ if (!outbound?.sendText || !this.channelManager.getRunningChannels().includes("telegram")) throw new Error("Telegram is not connected");
689
+ const result = await outbound.sendText({
690
+ cfg: this.config,
691
+ to: target.chatId,
692
+ accountId: target.accountId,
693
+ text
694
+ });
695
+ if (!result.success) throw new Error("Telegram delivery failed");
696
+ return { messageId: result.messageId };
697
+ }
698
+ });
684
699
  return this.notificationService;
685
700
  }
686
701
  dispatchTaskRuns() {
@@ -921,7 +936,6 @@ var GatewayService = class {
921
936
  this.running = true;
922
937
  this.taskRunDispatchTimer = setInterval(() => this.dispatchTaskRuns(), 1e3);
923
938
  this.taskRunDispatchTimer.unref?.();
924
- this.ensureDefaultProactiveScenarioSubscriptions();
925
939
  this.proactiveWorker.start();
926
940
  this.proactiveTemporalWorker.start();
927
941
  this.proactiveInboxWorker.start();
@@ -1115,22 +1129,6 @@ var GatewayService = class {
1115
1129
  else trace.mark("service.started-awaiting-http");
1116
1130
  log.debug("Gateway service started");
1117
1131
  }
1118
- ensureDefaultProactiveScenarioSubscriptions() {
1119
- for (const scenarioKey of [
1120
- "automation_failure_impact",
1121
- "meeting_preparation",
1122
- "discussion_follow_up"
1123
- ]) {
1124
- if (this.proactiveScenarios.subscriptions(scenarioKey).some((subscription) => subscription.workspaceId === this.currentWorkspacePath)) continue;
1125
- this.proactiveScenarios.subscribe({
1126
- scenarioKey,
1127
- workspaceId: this.currentWorkspacePath,
1128
- scopeKind: "workspace",
1129
- scopeId: this.currentWorkspacePath,
1130
- enabled: true
1131
- });
1132
- }
1133
- }
1134
1132
  /** Called when the HTTP listener is bound (before deferred channel work). */
1135
1133
  markHttpListening() {
1136
1134
  this.readiness.markHttpListening();
@@ -122,7 +122,7 @@ function automationPlan(payload) {
122
122
  function proactivePlan(payload) {
123
123
  if (!payload || typeof payload !== "object") return null;
124
124
  const item = payload;
125
- if (typeof item.id !== "string" || typeof item.insightId !== "string" || typeof item.insight.title !== "string") return null;
125
+ if (typeof item.id !== "string" || typeof item.insightId !== "string" || typeof item.insight?.title !== "string") return null;
126
126
  const requiresDecision = item.insight.attentionKind === "decision";
127
127
  const highUrgency = item.insight.urgency === "high" || item.insight.urgency === "critical";
128
128
  if (item.insight.attentionKind === "receipt") return null;
@@ -130,7 +130,7 @@ function proactivePlan(payload) {
130
130
  const title = item.insight.title.trim().slice(0, 120);
131
131
  const summary = typeof item.insight.summary === "string" ? item.insight.summary.trim().slice(0, 180) : "";
132
132
  return {
133
- dedupeKey: `proactive.insight:${item.id}`,
133
+ dedupeKey: `proactive.insight:${item.id}${item.notificationRevision && item.notificationRevision > 1 ? `:${item.notificationRevision}` : ""}`,
134
134
  notification: {
135
135
  type: "proactive.insight",
136
136
  target: {
@@ -148,7 +148,8 @@ function proactivePlan(payload) {
148
148
  } } : {},
149
149
  payload: {
150
150
  inboxItemId: item.id,
151
- insightId: item.insightId
151
+ insightId: item.insightId,
152
+ notificationRevision: item.notificationRevision ?? 1
152
153
  }
153
154
  }
154
155
  };
@@ -0,0 +1,8 @@
1
+ import type { ProductNotification, ProactivePreferences } from '@xopcai/gateway-contract';
2
+ type Target = NonNullable<ProactivePreferences['telegram']>;
3
+ export type ProactiveChannelSender = (target: Target, text: string) => Promise<{
4
+ messageId: string;
5
+ }>;
6
+ export declare function enqueueChannelNotification(notification: ProductNotification, workspace: string): void;
7
+ export declare function drainChannelNotifications(send: ProactiveChannelSender): Promise<void>;
8
+ export {};
@@ -0,0 +1,57 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
+ import { notificationTargetRoute } from "../../packages/gateway-contract/src/notifications.js";
3
+ import { proactivePreferences } from "../proactive/policy/service.js";
4
+ import { recheckNotificationDelivery } from "./proactive-policy.js";
5
+ import { getNotificationEvent } from "./store.js";
6
+ //#region src/notifications/proactive-channel.ts
7
+ function enqueueChannelNotification(notification, workspace) {
8
+ const target = proactivePreferences(workspace).telegram;
9
+ if (!target) throw new Error("Configure a Telegram destination before selecting it");
10
+ getSqliteDatabase().prepare("INSERT OR IGNORE INTO proactive_channel_deliveries(notification_id, workspace_id, target_json, next_attempt_at) VALUES (?, ?, ?, ?)").run(notification.id, workspace, JSON.stringify(target), Date.now());
11
+ }
12
+ async function drainChannelNotifications(send) {
13
+ const db = getSqliteDatabase();
14
+ const claim = runSqliteWriteTransaction((tx) => {
15
+ tx.prepare("UPDATE proactive_channel_deliveries SET status = 'failed', last_error = 'Lease exhausted' WHERE status = 'sending' AND lease_until <= ? AND attempt >= 5").run(Date.now());
16
+ const row = tx.prepare(`SELECT * FROM proactive_channel_deliveries WHERE (status = 'pending' AND next_attempt_at <= ?) OR (status = 'sending' AND lease_until <= ?) ORDER BY next_attempt_at LIMIT 1`).get(Date.now(), Date.now());
17
+ if (!row) return null;
18
+ tx.prepare("UPDATE proactive_channel_deliveries SET status = 'sending', attempt = attempt + 1, lease_until = ? WHERE notification_id = ?").run(Date.now() + 12e4, row.notification_id);
19
+ return {
20
+ ...row,
21
+ attempt: row.attempt + 1
22
+ };
23
+ });
24
+ if (!claim) return;
25
+ const finish = (status, nextAt, messageId = null, error = null) => {
26
+ db.prepare(`UPDATE proactive_channel_deliveries SET status = ?, next_attempt_at = ?, provider_message_id = ?, last_error = ?, lease_until = NULL
27
+ WHERE notification_id = ? AND status = 'sending' AND attempt = ?`).run(status, nextAt, messageId, error, claim.notification_id, claim.attempt);
28
+ };
29
+ try {
30
+ const notification = getNotificationEvent(claim.notification_id);
31
+ const current = proactivePreferences(claim.workspace_id);
32
+ if (!notification || current.preferredChannel !== "telegram" || JSON.stringify(current.telegram) !== claim.target_json) {
33
+ finish("cancelled", Date.now());
34
+ return;
35
+ }
36
+ const policy = recheckNotificationDelivery(notification, "telegram");
37
+ if (policy === "cancel") {
38
+ finish("cancelled", Date.now());
39
+ return;
40
+ }
41
+ if (policy instanceof Date) {
42
+ finish("pending", policy.getTime());
43
+ db.prepare("UPDATE proactive_channel_deliveries SET attempt = attempt - 1 WHERE notification_id = ? AND attempt = ?").run(claim.notification_id, claim.attempt);
44
+ return;
45
+ }
46
+ const target = JSON.parse(claim.target_json);
47
+ const url = new URL(target.publicUrl);
48
+ url.hash = notificationTargetRoute(notification.target, "web");
49
+ const result = await send(target, `${notification.target.kind === "proactive_digest" ? "你的工作摘要已就绪 / Your work digest is ready." : "有一项工作需要查看 / A work update is ready."}\n${url.toString()}`);
50
+ if (!result.messageId) throw new Error("No delivery receipt");
51
+ finish("sent", Date.now(), result.messageId);
52
+ } catch {
53
+ finish(claim.attempt >= 5 ? "failed" : "pending", Date.now() + Math.min(36e5, 3e4 * 2 ** claim.attempt), null, "Telegram delivery failed");
54
+ }
55
+ }
56
+ //#endregion
57
+ export { drainChannelNotifications, enqueueChannelNotification };
@@ -0,0 +1,3 @@
1
+ import type { ProductNotification } from '@xopcai/gateway-contract';
2
+ export declare function proactiveNotificationWorkspace(notification: Pick<ProductNotification, 'target'>): string | null;
3
+ export declare function recheckNotificationDelivery(notification: ProductNotification, channel: 'browser' | 'mobile' | 'telegram', now?: Date): 'send' | 'cancel' | Date;
@@ -0,0 +1,32 @@
1
+ import { getSqliteDatabase } from "../storage/sqlite/transaction.js";
2
+ import { proactivePreferences, quietHoursEnd } from "../proactive/policy/service.js";
3
+ import { viewingProactiveCards } from "../proactive/policy/presence.js";
4
+ import { digestCards } from "../proactive/inbox/digest.js";
5
+ import { recheckProactiveNotification } from "../proactive/inbox/notification-policy.js";
6
+ //#region src/notifications/proactive-policy.ts
7
+ function proactiveNotificationWorkspace(notification) {
8
+ const target = notification.target;
9
+ const db = getSqliteDatabase();
10
+ return (target.kind === "insight" ? db.prepare(`SELECT s.workspace_id FROM proactive_inbox_items i JOIN proactive_insights x USING(insight_id) JOIN proactive_scenario_subscriptions s USING(subscription_id) WHERE i.inbox_item_id = ?`).get(target.inboxItemId) : target.kind === "proactive_digest" ? db.prepare("SELECT workspace_id FROM proactive_digests WHERE digest_id = ?").get(target.digestId) : null)?.workspace_id ?? null;
11
+ }
12
+ function recheckNotificationDelivery(notification, channel, now = /* @__PURE__ */ new Date()) {
13
+ if (notification.type !== "proactive.insight") return "send";
14
+ const workspace = proactiveNotificationWorkspace(notification);
15
+ if (!workspace) return "cancel";
16
+ const preferences = proactivePreferences(workspace);
17
+ if (![
18
+ "all",
19
+ "auto",
20
+ channel
21
+ ].includes(preferences.preferredChannel)) return "cancel";
22
+ if (preferences.level === "off" || preferences.pausedUntil && Date.parse(preferences.pausedUntil) > now.getTime()) return "cancel";
23
+ if (preferences.suppressWhileViewing && viewingProactiveCards(workspace, now.getTime())) return "cancel";
24
+ if (notification.target.kind === "insight") return recheckProactiveNotification(notification.target.inboxItemId, now, notification.payload.notificationRevision);
25
+ if (notification.target.kind === "proactive_digest") {
26
+ if (!digestCards(notification.target.digestId, workspace).length) return "cancel";
27
+ return quietHoursEnd(preferences, now) ?? "send";
28
+ }
29
+ return "cancel";
30
+ }
31
+ //#endregion
32
+ export { proactiveNotificationWorkspace, recheckNotificationDelivery };