@xopcai/xopc 0.0.227 → 0.0.229

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 (249) 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-BevwE16n.js → activity-store-M0nAY5XB.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BggVQrEZ.js → agent-avatar-dicebear-CsFAJTIN.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DA4b6_0C.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-Bx_BpIt8.js → api-BywYxpaS.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-BtKP9n2r.js → app-management-settings-panel-7KcMWuah.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-BoH2NAUX.js → appearance-settings-Cqlw7Fif.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-CsnhdGZ2.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-DnceUyxm.js → archive-plugin-7_DXaMTP.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Bh8_9gkr.js → attachment-load-q4pDpqkF.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-ZKeAAVxD.js → automations-page-BuTqjKGX.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-workspace-CD0E2ThS.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-Cy9er6w-.js → binary-plugins-DUce1Bsc.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-Cc0wWvNX.js → block-editor-D8Ejp-QR.js} +3 -3
  16. package/dist/gateway/static/root/assets/browser-settings-page-CY1k3MMd.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BS7rpLLl.js → browser-workflow-inputs-8NC2qDRF.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-BdBVUZXm.js → browser-workflows-page-BDvZbR9v.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-D1VfotHQ.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-D1Lqz0Tt.js → capability-presets-api-o0y9WgAI.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DXHqRLpU.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-CGuEl-l2.js → channel-recipient-api-C5ABr73b.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-DrFL57M_.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-38FsOnR0.js +1 -0
  25. package/dist/gateway/static/root/assets/{chat-terminal-dock-CdX_7aQh.js → chat-terminal-dock-h1CKexNz.js} +2 -2
  26. package/dist/gateway/static/root/assets/connectors-page-DUAyfFCF.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-BnSQc4Ek.js → cron-expression-DlaQQOId.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-BbuG7zQ_.js → date-picker-8R1sXJKb.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-snZeqOmG.js → dependency-picker-CWur0821.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-DJQ8JoR1.js → desktop-pet-Knl-zNDU.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-B9txsRtv.js → desktop-pet-settings-CAQMLVtd.js} +1 -1
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-D7WKWkNB.js → directory-picker-path-field-Caaz4Rw5.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-D_7cOCj2.js → extension-debug-page-B965Mc15.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-Bwu47iUb.js → extension-page-C0UnkBi5.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-Dwg4dSZM.js → extension-settings-page-BUSIAZCR.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-api-jURUSte_.js → gateway-config-api-DkH0eEgy.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-6SQXF1yR.js → gateway-config-swr-BWGjnmDl.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-UklJOMLX.js → gateway-settings-BBgLDm6I.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-DqWaxyvZ.js → gateway-startup-retry-B_zrtccP.js} +1 -1
  40. package/dist/gateway/static/root/assets/{heartbeat-settings-Djs_nduD.js → heartbeat-settings-BtEHVXWD.js} +1 -1
  41. package/dist/gateway/static/root/assets/home-page-5SU2TNJj.js +1 -0
  42. package/dist/gateway/static/root/assets/{image-generation-api-Bxmt6LEr.js → image-generation-api-YKP2me5Z.js} +1 -1
  43. package/dist/gateway/static/root/assets/index-BNWhgmjs.js +70 -0
  44. package/dist/gateway/static/root/assets/index-D_hrEKXM.css +2 -0
  45. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-ByVsCH3d.js → keyboard-shortcuts-settings-CsRz8NrS.js} +1 -1
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-DYPEUgpP.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page-D19R-xsz.js → local-apps-page-CTBNUG4a.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-Ci1Qi0Q-.js → locale-store-CXhjfe4q.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-B0P7rG2B.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-G0y7zmfY.js → management-settings-YqUAEwQo.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-B69d2HWt.js → markdown-split-dxpSCXb8.js} +1 -1
  52. package/dist/gateway/static/root/assets/{markdown-view-DD_PgVue.css → markdown-view-CLzTdVLW.css} +1 -1
  53. package/dist/gateway/static/root/assets/markdown-view-DvM5PWEH.js +201 -0
  54. package/dist/gateway/static/root/assets/{media-plugins-6TWEQgN_.js → media-plugins-CJ00i1Lg.js} +1 -1
  55. package/dist/gateway/static/root/assets/messages-BMdD0LWk.js +3 -0
  56. package/dist/gateway/static/root/assets/{notes-api-DLsnnZCS.js → notes-api-BFsOGYkd.js} +1 -1
  57. package/dist/gateway/static/root/assets/{notes-page-CkRJJKDm.js → notes-page-DEnbnkIt.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-DmVYu_Oc.js +4 -0
  59. package/dist/gateway/static/root/assets/{product-open-page-HxArIvoN.js → product-open-page-BHxo9U95.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-DV2nGmsq.js +1 -0
  61. package/dist/gateway/static/root/assets/projects-page-BNIFwFfc.js +1 -0
  62. package/dist/gateway/static/root/assets/{registry-api-lEar5FOV.js → registry-api-BFZrVYfy.js} +1 -1
  63. package/dist/gateway/static/root/assets/remote-access-hub-DLXqKiA_.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bf03UNGD.js → runtime-tools-settings-panel-BpQ2GI-0.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-CIXMBgx5.js → schema-form-HE1G26Lx.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-DWaXf_25.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-JFCbnCL2.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-DgdB26mE.js → settings-form-section-CXAn0Xhy.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-efk5W6lG.js → settings-loading-skeleton-DsFu7Bcv.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-BHVf4gEP.js → settings-page-C4iib9nO.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-WK0dGNMv.js → setup-status-panel-BA83Wr1d.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-Cod-w2qm.js → share-preview-page-BOGl3s6M.js} +1 -1
  73. package/dist/gateway/static/root/assets/{shares-settings-CUqQ31gt.js → shares-settings-Q2MdGaBi.js} +1 -1
  74. package/dist/gateway/static/root/assets/skill-reload-api-cFtfVeFU.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-DwCcipqK.js → skills-page-CdaFtNw9.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-3WSbtl3S.js → skills-page.utils-DYaAddUL.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-C5VxqC_s.js → system-settings-panel-Co7gilRd.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-5B1pswu8.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Dd89g_ki.js → theme-store-DOdCjyuw.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-CeV8VJh2.js → use-autosave-DnnZtMpA.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-context-page-Dr1FKjXv.js +1 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-EmJ-8aZu.js → voice-api-key-field-wetUpi3i.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-zsk6E3Mi.js → work-discovery-overlay-tbTWASJJ.js} +1 -1
  84. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Dy0fDs8w.js +3 -0
  85. package/dist/gateway/static/root/assets/workflows-page-IVP3GSkI.js +5 -0
  86. package/dist/gateway/static/root/index.html +12 -12
  87. package/dist/gateway/static/root/notification-sw.js +1 -1
  88. package/dist/package.js +1 -1
  89. package/dist/packages/gateway-contract/src/notifications.js +56 -0
  90. package/dist/packages/gateway-contract/src/turn-outcome.js +114 -0
  91. package/dist/src/agent/agent-instance-gateway.d.ts +1 -1
  92. package/dist/src/agent/agent-manager.d.ts +1 -1
  93. package/dist/src/agent/agent-manager.js +18 -3
  94. package/dist/src/agent/background-review/prompts.d.ts +8 -2
  95. package/dist/src/agent/background-review/prompts.js +25 -12
  96. package/dist/src/agent/background-review/run-background-review.d.ts +7 -2
  97. package/dist/src/agent/background-review/run-background-review.js +175 -160
  98. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -0
  99. package/dist/src/agent/lifecycle/timeout-wrapper.js +7 -6
  100. package/dist/src/agent/mcp/mcp-transport-config.d.ts +1 -1
  101. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  102. package/dist/src/agent/memory/index.d.ts +1 -1
  103. package/dist/src/agent/memory/index.js +2 -2
  104. package/dist/src/agent/memory/manager.d.ts +1 -11
  105. package/dist/src/agent/memory/manager.js +0 -16
  106. package/dist/src/agent/memory/understanding/service.d.ts +0 -11
  107. package/dist/src/agent/memory/understanding/service.js +7 -173
  108. package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -3
  109. package/dist/src/agent/memory/user-context-coordinator.js +3 -66
  110. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  111. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -2
  112. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +4 -4
  113. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  114. package/dist/src/agent/tools/create-share-tool.js +14 -1
  115. package/dist/src/agent/tools/exec-command.js +3 -3
  116. package/dist/src/agent/tools/execute-code-tool.js +1 -1
  117. package/dist/src/agent/tools/executor.js +2 -2
  118. package/dist/src/agent/tools/image-generate-tool.js +12 -0
  119. package/dist/src/agent/tools/send-media.js +11 -0
  120. package/dist/src/agent/tools/xopc-use-tool.js +1 -1
  121. package/dist/src/cli/command-loaders.js +1 -0
  122. package/dist/src/cli/command-manifest.js +4 -0
  123. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  124. package/dist/src/cli/commands/history.d.ts +1 -0
  125. package/dist/src/cli/commands/history.js +50 -0
  126. package/dist/src/config/agent-profile.js +1 -1
  127. package/dist/src/config/schema.d.ts +4 -0
  128. package/dist/src/config/schema.js +1 -0
  129. package/dist/src/connectors/connected-source-understanding.js +35 -21
  130. package/dist/src/connectors/learning-coordinator.js +1 -42
  131. package/dist/src/gateway/agents-admin.js +1 -1
  132. package/dist/src/gateway/chat-stream/mapper.d.ts +2 -0
  133. package/dist/src/gateway/chat-stream/mapper.js +5 -0
  134. package/dist/src/gateway/chat-stream/protocol.d.ts +3 -2
  135. package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +16 -0
  136. package/dist/src/gateway/chat-stream/turn-outcome-collector.js +111 -0
  137. package/dist/src/gateway/hono/lib/static-ui.js +7 -5
  138. package/dist/src/gateway/hono/routes/index.js +2 -0
  139. package/dist/src/gateway/hono/routes/mobile.js +18 -40
  140. package/dist/src/gateway/hono/routes/notifications.d.ts +3 -0
  141. package/dist/src/gateway/hono/routes/notifications.js +45 -0
  142. package/dist/src/gateway/hono/routes/sessions.js +31 -0
  143. package/dist/src/gateway/hono/routes/tasks.js +1 -1
  144. package/dist/src/gateway/hono/routes/understanding-sources.js +4 -1
  145. package/dist/src/gateway/hono/routes/you.js +29 -11
  146. package/dist/src/gateway/service/agent-runner.js +6 -2
  147. package/dist/src/gateway/service/run-gateway-agent.js +58 -2
  148. package/dist/src/gateway/service/sessions-api.d.ts +6 -0
  149. package/dist/src/gateway/service/sessions-api.js +60 -3
  150. package/dist/src/gateway/service.d.ts +2 -2
  151. package/dist/src/gateway/service.js +8 -7
  152. package/dist/src/history/ctx/exporter.d.ts +14 -0
  153. package/dist/src/history/ctx/exporter.js +99 -0
  154. package/dist/src/history/ctx/format.d.ts +25 -0
  155. package/dist/src/history/ctx/format.js +282 -0
  156. package/dist/src/knowledge/index.d.ts +0 -1
  157. package/dist/src/knowledge/index.js +1 -2
  158. package/dist/src/media/session-references.d.ts +6 -0
  159. package/dist/src/media/session-references.js +24 -3
  160. package/dist/src/notifications/device-store.d.ts +16 -0
  161. package/dist/src/notifications/device-store.js +96 -0
  162. package/dist/src/notifications/planner.d.ts +6 -0
  163. package/dist/src/notifications/planner.js +160 -0
  164. package/dist/src/notifications/service.d.ts +18 -0
  165. package/dist/src/notifications/service.js +184 -0
  166. package/dist/src/notifications/store.d.ts +53 -0
  167. package/dist/src/notifications/store.js +184 -0
  168. package/dist/src/notifications/types.d.ts +29 -0
  169. package/dist/src/notifications/types.js +14 -0
  170. package/dist/src/session/client-history.d.ts +3 -1
  171. package/dist/src/session/client-history.js +13 -0
  172. package/dist/src/session/index.d.ts +1 -1
  173. package/dist/src/session/manager.d.ts +1 -0
  174. package/dist/src/session/manager.js +6 -0
  175. package/dist/src/session/store.d.ts +15 -0
  176. package/dist/src/session/store.js +58 -0
  177. package/dist/src/storage/sqlite/index.d.ts +2 -2
  178. package/dist/src/storage/sqlite/index.js +3 -3
  179. package/dist/src/storage/sqlite/migrations/136_product_notifications.sql +79 -0
  180. package/dist/src/storage/sqlite/migrations/137_understanding_status_audit.sql +71 -0
  181. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  182. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  183. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  184. package/dist/src/storage/sqlite/schema.js +1 -1
  185. package/dist/src/storage/sqlite/session-input-repository.d.ts +5 -0
  186. package/dist/src/storage/sqlite/session-input-repository.js +9 -1
  187. package/dist/src/storage/sqlite/user-context-repository.d.ts +16 -4
  188. package/dist/src/storage/sqlite/user-context-repository.js +56 -12
  189. package/dist/src/tasks/index.js +2 -2
  190. package/dist/src/tasks/task-application-service.js +42 -6
  191. package/dist/src/tasks/task-change-events.d.ts +9 -0
  192. package/dist/src/tasks/task-change-events.js +17 -1
  193. package/dist/src/tasks/task-outbox-dispatcher.js +5 -1
  194. package/dist/src/tasks/task-run-dispatcher.js +4 -2
  195. package/dist/src/tasks/task-run-repository.js +13 -0
  196. package/dist/src/user-context/config.d.ts +8 -0
  197. package/dist/src/user-context/config.js +3 -0
  198. package/dist/src/user-context/consolidation.js +16 -4
  199. package/dist/src/user-context/extraction/executor.d.ts +22 -0
  200. package/dist/src/user-context/extraction/executor.js +142 -0
  201. package/dist/src/user-context/extraction/registry.d.ts +1 -1
  202. package/dist/src/user-context/extraction/registry.js +5 -34
  203. package/dist/src/user-context/extraction/repair.js +4 -1
  204. package/dist/src/user-context/extraction/semantic.d.ts +18 -0
  205. package/dist/src/user-context/extraction/semantic.js +148 -0
  206. package/dist/src/user-context/understandingQuality.js +4 -0
  207. package/dist/src/work-discovery/analyzer.js +9 -4
  208. package/dist/src/work-discovery/service.d.ts +1 -0
  209. package/dist/src/work-discovery/service.js +5 -4
  210. package/dist/src/work-discovery/types.d.ts +1 -0
  211. package/package.json +14 -8
  212. package/dist/gateway/static/root/assets/agents-TJpjRHnr.js +0 -68
  213. package/dist/gateway/static/root/assets/apps-page-CZ4Da51l.js +0 -1
  214. package/dist/gateway/static/root/assets/automations-workspace-2Y00PvJU.js +0 -6
  215. package/dist/gateway/static/root/assets/browser-settings-page-CbJD27_j.js +0 -8
  216. package/dist/gateway/static/root/assets/capabilities-settings-panel-Dv8y6OuP.js +0 -7
  217. package/dist/gateway/static/root/assets/capability-presets-settings-panel-TZmjzWzt.js +0 -3
  218. package/dist/gateway/static/root/assets/channels-settings-g-68dutA.js +0 -1
  219. package/dist/gateway/static/root/assets/channels-status-swr-D7KsAeWh.js +0 -1
  220. package/dist/gateway/static/root/assets/connectors-page-DXA0rAvQ.js +0 -2
  221. package/dist/gateway/static/root/assets/home-page-i6bXCHdo.js +0 -1
  222. package/dist/gateway/static/root/assets/index-BBBE89vm.css +0 -2
  223. package/dist/gateway/static/root/assets/index-BsD5wygl.js +0 -74
  224. package/dist/gateway/static/root/assets/local-app-workbench-page-BCKEDMlP.js +0 -2
  225. package/dist/gateway/static/root/assets/logs-page-Cy9YQK7j.js +0 -2
  226. package/dist/gateway/static/root/assets/markdown-view-CBM-v2ph.js +0 -69
  227. package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +0 -134
  228. package/dist/gateway/static/root/assets/messages-CtOJwGW3.js +0 -3
  229. package/dist/gateway/static/root/assets/notes-workbench-B10T3hGX.js +0 -4
  230. package/dist/gateway/static/root/assets/project-detail-page-DsqRlgsy.js +0 -1
  231. package/dist/gateway/static/root/assets/projects-page-Bu2PN8OK.js +0 -1
  232. package/dist/gateway/static/root/assets/remote-access-hub-CXACdJ2f.js +0 -1
  233. package/dist/gateway/static/root/assets/sessions-page-CS2knWDT.js +0 -1
  234. package/dist/gateway/static/root/assets/settings-advanced-gate-ByFGk0q_.js +0 -1
  235. package/dist/gateway/static/root/assets/skill-reload-api-DweAPjI8.js +0 -1
  236. package/dist/gateway/static/root/assets/task-detail-page-DEj-BFMP.js +0 -1
  237. package/dist/gateway/static/root/assets/user-context-page-f7yh7aD5.js +0 -1
  238. package/dist/gateway/static/root/assets/workflow-run-setup-panel-CBAYvm3G.js +0 -3
  239. package/dist/gateway/static/root/assets/workflows-page-BN0JmHrG.js +0 -5
  240. package/dist/src/agent/memory/understanding/correction.d.ts +0 -3
  241. package/dist/src/agent/memory/understanding/correction.js +0 -39
  242. package/dist/src/knowledge/connected-understanding-pipeline.d.ts +0 -17
  243. package/dist/src/knowledge/connected-understanding-pipeline.js +0 -278
  244. package/dist/src/mobile/notification-service.d.ts +0 -9
  245. package/dist/src/mobile/notification-service.js +0 -156
  246. package/dist/src/mobile/notification-store.d.ts +0 -28
  247. package/dist/src/mobile/notification-store.js +0 -132
  248. package/dist/src/mobile/notification-types.d.ts +0 -37
  249. package/dist/src/mobile/notification-types.js +0 -9
@@ -6,7 +6,6 @@ import { upsertUserFocus } from "../user-context/sources/repository.js";
6
6
  import { claimRegisteredExtraction } from "../user-context/extraction/registry.js";
7
7
  import { allowsRemoteSourceProcessing } from "../user-context/sources/processing-policy.js";
8
8
  import { analyzeUnderstandingSources } from "../work-discovery/analyzer.js";
9
- import { createHash } from "node:crypto";
10
9
  //#region src/connectors/connected-source-understanding.ts
11
10
  const MAX_CONNECTED_ITEMS = 150;
12
11
  function normalizedValue(item) {
@@ -60,17 +59,14 @@ function connectedItemsForUnderstanding(items) {
60
59
  }];
61
60
  });
62
61
  }
63
- function understandingKind(category) {
64
- if (category === "preference") return "preference";
65
- if (category === "routine") return "routine";
66
- return "project_context";
62
+ function isConnectedPortraitCandidate(candidate) {
63
+ return candidate.category === "preference" || candidate.category === "routine";
67
64
  }
68
65
  function understandingCandidate(candidate) {
69
- const normalized = candidate.statement.toLocaleLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
70
66
  return {
71
- kind: understandingKind(candidate.category),
67
+ kind: candidate.category,
72
68
  content: candidate.statement,
73
- canonicalKey: `connected-semantic:${candidate.category}:${createHash("sha256").update(normalized).digest("hex").slice(0, 20)}`,
69
+ canonicalKey: `understanding:${candidate.category}:${candidate.factKey}`,
74
70
  confidence: candidate.confidence === "high" ? .9 : candidate.confidence === "medium" ? .72 : .55,
75
71
  importance: .68,
76
72
  explicitness: "inferred",
@@ -84,6 +80,18 @@ function hasLongVerbatimOverlap(value, sourceTexts, minimumLength = 32) {
84
80
  if (normalized.length < minimumLength) return false;
85
81
  return sourceTexts.some((source) => source.replace(/\s+/g, " ").includes(normalized));
86
82
  }
83
+ function evidenceDate(item) {
84
+ const timestamp = item.occurredAt ?? item.modifiedAt;
85
+ return timestamp == null ? void 0 : new Date(timestamp).toISOString().slice(0, 10);
86
+ }
87
+ function durableConnectedEvidence(candidate, itemsByRef) {
88
+ if (candidate.confidence !== "high") return [];
89
+ const items = [...new Set(candidate.evidenceRefs ?? [])].flatMap((ref) => itemsByRef.get(ref) ?? []);
90
+ if (items.some((item) => item.ownerAttribution !== "user")) return [];
91
+ const required = candidate.category === "routine" ? 3 : 2;
92
+ const dates = new Set(items.map(evidenceDate).filter((value) => Boolean(value)));
93
+ return items.length >= required && dates.size >= required ? items : [];
94
+ }
87
95
  async function deriveConnectedSourceUnderstanding(input) {
88
96
  const knowledgeItems = listKnowledgeSourceItems({
89
97
  agentId: input.agentId,
@@ -115,22 +123,28 @@ async function deriveConnectedSourceUnderstanding(input) {
115
123
  items
116
124
  });
117
125
  const rawTexts = items.flatMap((item) => item.text ? [item.text] : []);
118
- const profileCandidates = analysis.profileCandidates.filter((candidate) => !hasLongVerbatimOverlap(candidate.statement, rawTexts));
119
- const sourceItemIds = [...new Set([...profileCandidates.flatMap((candidate) => candidate.evidenceRefs ?? []), ...analysis.workThreadCandidates.flatMap((candidate) => candidate.evidenceRefs)].map((ref) => ref.startsWith("knowledge-source://") ? ref.slice(19) : ""))].filter(Boolean).slice(0, 20);
120
- const reviewed = profileCandidates.length ? await input.memoryManager.applyUnderstandingCandidates(profileCandidates.map(understandingCandidate), {
121
- agentId: input.agentId,
122
- sourceItemIds,
123
- sourceText: "Bounded semantic synthesis from explicitly connected work sources.",
124
- source: {
125
- provider: "connected-sources",
126
- sourceInstanceId: input.sourceInstanceId
127
- },
128
- reviewSource: "background",
129
- extractionRunId: extraction.run.id
130
- }) : {
126
+ const itemsByRef = new Map(items.map((item) => [item.evidenceRef, item]));
127
+ const profileCandidates = analysis.profileCandidates.filter(isConnectedPortraitCandidate).filter((candidate) => !hasLongVerbatimOverlap(candidate.statement, rawTexts) && durableConnectedEvidence(candidate, itemsByRef).length > 0);
128
+ const reviewed = {
131
129
  created: 0,
132
130
  writeOutputs: []
133
131
  };
132
+ for (const candidate of profileCandidates) {
133
+ const evidenceItems = durableConnectedEvidence(candidate, itemsByRef);
134
+ const applied = await input.memoryManager.applyUnderstandingCandidates([understandingCandidate(candidate)], {
135
+ agentId: input.agentId,
136
+ sourceItemIds: evidenceItems.map((item) => item.id).slice(0, 20),
137
+ sourceText: "Bounded semantic synthesis from explicitly connected work sources.",
138
+ source: {
139
+ provider: "connected-sources",
140
+ sourceInstanceId: input.sourceInstanceId
141
+ },
142
+ reviewSource: "background",
143
+ extractionRunId: extraction.run.id
144
+ });
145
+ reviewed.created += applied.created;
146
+ reviewed.writeOutputs.push(...applied.writeOutputs ?? []);
147
+ }
134
148
  const focuses = analysis.workThreadCandidates.filter((candidate) => !hasLongVerbatimOverlap(candidate.title, rawTexts) && !hasLongVerbatimOverlap(candidate.summary, rawTexts)).map((candidate) => upsertUserFocus({
135
149
  canonicalKey: `connected-focus:${candidate.topicKey}`,
136
150
  title: candidate.title,
@@ -1,6 +1,5 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
- import { finishContextExtractionRun } from "../storage/sqlite/context-extraction-repository.js";
4
3
  import { claimNextConnectorLearningJob, enqueueConnectorLearningJob, listConnectorLearningJobs, recoverStaleConnectorLearningJobs, setConnectorLearningPaused, updateConnectorLearningJob } from "../storage/sqlite/connector-learning-repository.js";
5
4
  import { getConnectorInstallation, listConnectorConnections, upsertConnectorConnection } from "../storage/sqlite/connector-repository.js";
6
5
  import { getConnectorAccount, reconcileConnectorAccount } from "../storage/sqlite/connector-account-repository.js";
@@ -11,10 +10,8 @@ import { ComposioSessionsAdapter } from "./composio-sessions.js";
11
10
  import { buildConnectorLearningArguments, getConnectorLearningPlan } from "./learning-recipes.js";
12
11
  import { getConnectorDefinition } from "./catalog.js";
13
12
  import { createUnderstandingSourceRun, getUnderstandingSourceGrant, listUnderstandingSourceRuns, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceRun, upsertUnderstandingSourceGrant } from "../user-context/sources/repository.js";
14
- import { claimRegisteredExtraction } from "../user-context/extraction/registry.js";
15
13
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
16
14
  import { ConnectedKnowledgePipeline } from "../knowledge/connected-knowledge-pipeline.js";
17
- import { ConnectedUnderstandingPipeline } from "../knowledge/connected-understanding-pipeline.js";
18
15
  import "../knowledge/index.js";
19
16
  import { ingestComposioConnectedSource } from "./connected-source-ingestion.js";
20
17
  import { deriveConnectedSourceUnderstanding } from "./connected-source-understanding.js";
@@ -210,44 +207,6 @@ function startConnectorLearningCoordinator(options) {
210
207
  itemsIndexed
211
208
  }));
212
209
  publish(updateConnectorLearningJob(job.id, { phase: "deriving" }));
213
- const structuralExtraction = claimRegisteredExtraction({
214
- extractorId: "connector-structural",
215
- sourceRef: `understanding-source-run:${sourceRun.id}`,
216
- contentForHash: `${job.sourceInstanceId}:${itemsSeen}:${itemsIndexed}`,
217
- processingPolicy: "local_only",
218
- destination: "deterministic"
219
- });
220
- let understanding = {
221
- proposed: 0,
222
- created: 0,
223
- deduplicated: 0,
224
- rejected: 0,
225
- createdRecords: [],
226
- writeOutputs: []
227
- };
228
- if (structuralExtraction.shouldExecute) try {
229
- understanding = await new ConnectedUnderstandingPipeline(options.getMemoryManager()).process(job.agentId, structuralExtraction.run.id);
230
- finishContextExtractionRun({
231
- runId: structuralExtraction.run.id,
232
- status: "completed",
233
- outputs: (understanding.writeOutputs ?? []).map((output) => ({
234
- candidateKey: output.candidateKey,
235
- ...output.objectId ? {
236
- objectType: "understanding",
237
- objectId: output.objectId
238
- } : {},
239
- ...output.versionId ? { versionId: output.versionId } : {},
240
- outcome: output.outcome
241
- }))
242
- });
243
- } catch (error) {
244
- finishContextExtractionRun({
245
- runId: structuralExtraction.run.id,
246
- status: "failed",
247
- errorCode: "extractor_failed"
248
- });
249
- throw error;
250
- }
251
210
  let semantic = {
252
211
  created: 0,
253
212
  focusCount: 0,
@@ -276,7 +235,7 @@ function startConnectorLearningCoordinator(options) {
276
235
  connectorId: job.connectorId
277
236
  }, `Connected source semantic analysis failed: ${errorMessage}`);
278
237
  }
279
- const candidatesCreated = understanding.created + semantic.created + semantic.focusCount;
238
+ const candidatesCreated = semantic.created + semantic.focusCount;
280
239
  const incomplete = enrichmentErrors.length > 0 || semantic.status !== "completed";
281
240
  const completed = updateConnectorLearningJob(job.id, {
282
241
  status: "completed",
@@ -1,5 +1,5 @@
1
- import { resolveCapabilityPresetLayer, resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
+ import { resolveCapabilityPresetLayer, resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
@@ -15,6 +15,7 @@ export declare class ChatStreamMapper {
15
15
  private currentAssistantMessageId;
16
16
  private lastAssistantMessageId;
17
17
  private currentAssistantText;
18
+ private lastAssistantText;
18
19
  private currentAssistantReviewEmitted;
19
20
  private toolCallToMessageId;
20
21
  private turnDiffs;
@@ -28,6 +29,7 @@ export declare class ChatStreamMapper {
28
29
  start(): ChatStreamEvent[];
29
30
  end(status: ChatStreamStatus, summary?: string): ChatStreamEvent[];
30
31
  error(message: string, code?: string): ChatStreamEvent[];
32
+ getLastAssistantText(): string;
31
33
  private mapMessageStart;
32
34
  private mapMessageUpdate;
33
35
  private mapAssistantSnapshot;
@@ -14,6 +14,7 @@ var ChatStreamMapper = class {
14
14
  currentAssistantMessageId;
15
15
  lastAssistantMessageId;
16
16
  currentAssistantText = "";
17
+ lastAssistantText = "";
17
18
  currentAssistantReviewEmitted = false;
18
19
  toolCallToMessageId = /* @__PURE__ */ new Map();
19
20
  turnDiffs = [];
@@ -154,6 +155,9 @@ var ChatStreamMapper = class {
154
155
  petFeedback: createPetFeedback("error", { recoverable: false })
155
156
  })];
156
157
  }
158
+ getLastAssistantText() {
159
+ return this.currentAssistantText || this.lastAssistantText;
160
+ }
157
161
  mapMessageStart(raw) {
158
162
  if (raw?.role !== "assistant") return [];
159
163
  const messageId = this.nextAssistantMessageId();
@@ -260,6 +264,7 @@ var ChatStreamMapper = class {
260
264
  presentation: hasToolCall(message) ? "narration" : "answer",
261
265
  usage: extractUsage(message)
262
266
  }));
267
+ if (this.currentAssistantText) this.lastAssistantText = this.currentAssistantText;
263
268
  this.lastAssistantMessageId = messageId;
264
269
  this.currentAssistantMessageId = void 0;
265
270
  this.currentAssistantText = "";
@@ -1,4 +1,4 @@
1
- import type { ToolActivity } from '@xopcai/gateway-contract';
1
+ import type { ToolActivity, TurnOutcome } from '@xopcai/gateway-contract';
2
2
  export type ChatStreamStatus = 'success' | 'error' | 'cancelled';
3
3
  export type PetFeedbackTaskState = 'working' | 'waiting' | 'success' | 'error';
4
4
  export type PetFeedbackSensitivity = 'public' | 'private';
@@ -142,6 +142,7 @@ export type TurnDiffEvent = ChatStreamEnvelope<'turn_diff', {
142
142
  added: number;
143
143
  removed: number;
144
144
  }>;
145
+ export type TurnOutcomeEvent = ChatStreamEnvelope<'turn_outcome', TurnOutcome>;
145
146
  export type ReviewStartEvent = ChatStreamEnvelope<'review_start', {
146
147
  messageId: string;
147
148
  reviewId: string;
@@ -237,4 +238,4 @@ export type StreamErrorEvent = ChatStreamEnvelope<'error', {
237
238
  recoverable?: boolean;
238
239
  petFeedback: PetFeedback;
239
240
  }>;
240
- export type ChatStreamEvent = RunStartEvent | UserMessageEvent | UserTranscriptEvent | AssistantMessageStartEvent | AssistantDeltaEvent | ThinkingDeltaEvent | ThinkingEndEvent | ToolStartEvent | ToolUpdateEvent | ToolEndEvent | CommandStartedEvent | CommandOutputDeltaEvent | CommandCompletedEvent | PatchAppliedEvent | TurnPlanUpdatedEvent | TaskPlanUpdatedEvent | TurnDiffEvent | ReviewStartEvent | ReviewDeltaEvent | ReviewEndEvent | ReviewEvent | AssistantMessageEndEvent | ProgressEvent | CompactionEvent | TtsAudioEvent | ClarifyRequestEvent | MemoryConsentRequiredEvent | MemoryCapturedEvent | MemoryCandidateEvent | RunEndEvent | StreamErrorEvent;
241
+ export type ChatStreamEvent = RunStartEvent | UserMessageEvent | UserTranscriptEvent | AssistantMessageStartEvent | AssistantDeltaEvent | ThinkingDeltaEvent | ThinkingEndEvent | ToolStartEvent | ToolUpdateEvent | ToolEndEvent | CommandStartedEvent | CommandOutputDeltaEvent | CommandCompletedEvent | PatchAppliedEvent | TurnPlanUpdatedEvent | TaskPlanUpdatedEvent | TurnDiffEvent | TurnOutcomeEvent | ReviewStartEvent | ReviewDeltaEvent | ReviewEndEvent | ReviewEvent | AssistantMessageEndEvent | ProgressEvent | CompactionEvent | TtsAudioEvent | ClarifyRequestEvent | MemoryConsentRequiredEvent | MemoryCapturedEvent | MemoryCandidateEvent | RunEndEvent | StreamErrorEvent;
@@ -0,0 +1,16 @@
1
+ import type { AgentStreamRunStatus, TurnOutcome } from '@xopcai/gateway-contract';
2
+ import type { ChatStreamEvent } from './protocol.js';
3
+ export declare class TurnOutcomeCollector {
4
+ private readonly runId;
5
+ private readonly environment;
6
+ private readonly deliverables;
7
+ private readonly evidence;
8
+ private readonly files;
9
+ private readonly diffs;
10
+ private added;
11
+ private removed;
12
+ private failedToolCount;
13
+ constructor(runId: string, environment?: 'workspace' | 'worktree' | 'remote_runtime');
14
+ capture(event: ChatStreamEvent): void;
15
+ finalize(status: AgentStreamRunStatus, summary?: string): TurnOutcome;
16
+ }
@@ -0,0 +1,111 @@
1
+ import { TurnOutcomeDeliverableSchema } from "../../../packages/gateway-contract/src/turn-outcome.js";
2
+ //#region src/gateway/chat-stream/turn-outcome-collector.ts
3
+ const VERIFICATION_COMMAND = /(^|[\s:/_-])(test|vitest|jest|pytest|lint|typecheck|type-check|build)([\s:/_-]|$)/i;
4
+ const MAX_OUTCOME_DIFF_CHARS = 2e5;
5
+ function asRecord(value) {
6
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7
+ }
8
+ function optionalString(value) {
9
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
10
+ }
11
+ function fileStatus(kind) {
12
+ if (kind === "add") return "added";
13
+ if (kind === "delete") return "deleted";
14
+ if (kind === "move") return "renamed";
15
+ if (kind === "update") return "modified";
16
+ }
17
+ function changedFiles(changes) {
18
+ return changes.flatMap((value) => {
19
+ const row = asRecord(value);
20
+ const path = optionalString(row?.moveTo) ?? optionalString(row?.path);
21
+ if (!path) return [];
22
+ return [{
23
+ path,
24
+ ...fileStatus(row?.kind) ? { status: fileStatus(row?.kind) } : {},
25
+ ...typeof row?.added === "number" ? { added: Math.max(0, row.added) } : {},
26
+ ...typeof row?.removed === "number" ? { removed: Math.max(0, row.removed) } : {}
27
+ }];
28
+ });
29
+ }
30
+ function structuredDeliverables(details) {
31
+ if (!Array.isArray(details.artifacts)) return [];
32
+ return details.artifacts.flatMap((value) => {
33
+ const parsed = TurnOutcomeDeliverableSchema.safeParse(value);
34
+ return parsed.success ? [parsed.data] : [];
35
+ });
36
+ }
37
+ var TurnOutcomeCollector = class {
38
+ deliverables = /* @__PURE__ */ new Map();
39
+ evidence = /* @__PURE__ */ new Map();
40
+ files = /* @__PURE__ */ new Map();
41
+ diffs = [];
42
+ added = 0;
43
+ removed = 0;
44
+ failedToolCount = 0;
45
+ constructor(runId, environment = "workspace") {
46
+ this.runId = runId;
47
+ this.environment = environment;
48
+ }
49
+ capture(event) {
50
+ if (event.type === "tool_end") {
51
+ if (event.payload.status !== "success") {
52
+ this.failedToolCount += 1;
53
+ return;
54
+ }
55
+ const details = asRecord(event.payload.result?.details);
56
+ if (!details) return;
57
+ for (const artifact of structuredDeliverables(details)) this.deliverables.set(artifact.artifactId, artifact);
58
+ return;
59
+ }
60
+ if (event.type === "patch_applied") {
61
+ for (const file of changedFiles(event.payload.changes)) this.files.set(file.path, file);
62
+ return;
63
+ }
64
+ if (event.type === "turn_diff") {
65
+ for (const path of event.payload.files) if (!this.files.has(path)) this.files.set(path, { path });
66
+ if (event.payload.diff.trim()) this.diffs.push(event.payload.diff);
67
+ this.added += Math.max(0, event.payload.added);
68
+ this.removed += Math.max(0, event.payload.removed);
69
+ return;
70
+ }
71
+ if (event.type === "command_completed" && VERIFICATION_COMMAND.test(event.payload.command)) {
72
+ const status = event.payload.exitCode === 0 && !event.payload.timedOut ? "passed" : "failed";
73
+ this.evidence.set(event.payload.toolCallId, {
74
+ evidenceId: `${this.runId}:${event.payload.toolCallId}:check`,
75
+ kind: "check",
76
+ label: event.payload.command,
77
+ status,
78
+ command: event.payload.command,
79
+ ...event.payload.durationMs !== void 0 ? { durationMs: event.payload.durationMs } : {}
80
+ });
81
+ }
82
+ }
83
+ finalize(status, summary) {
84
+ const evidence = [...this.evidence.values()];
85
+ const partial = this.failedToolCount > 0 || evidence.some((item) => item.status === "failed");
86
+ const fullDiff = this.diffs.join("\n");
87
+ const diffTruncated = fullDiff.length > MAX_OUTCOME_DIFF_CHARS;
88
+ return {
89
+ version: 1,
90
+ outcomeId: `${this.runId}:outcome`,
91
+ runId: this.runId,
92
+ turnId: this.runId,
93
+ status: status === "error" ? "failed" : status === "cancelled" || partial ? "partial" : "succeeded",
94
+ ...summary?.trim() ? { summary: summary.trim() } : {},
95
+ deliverables: [...this.deliverables.values()],
96
+ ...this.files.size > 0 || this.diffs.length > 0 ? { changeSet: {
97
+ changeSetId: `${this.runId}:changes`,
98
+ files: [...this.files.values()],
99
+ added: this.added,
100
+ removed: this.removed,
101
+ diff: diffTruncated ? fullDiff.slice(0, MAX_OUTCOME_DIFF_CHARS) : fullDiff,
102
+ ...diffTruncated ? { diffTruncated: true } : {},
103
+ environment: this.environment
104
+ } } : {},
105
+ evidence,
106
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
107
+ };
108
+ }
109
+ };
110
+ //#endregion
111
+ export { TurnOutcomeCollector };
@@ -52,7 +52,7 @@ function resolveCacheControl(relativePath) {
52
52
  function resolveContentType(relativePath) {
53
53
  return MIME_TYPES[relativePath.split(".").pop()?.toLowerCase() || ""] || "application/octet-stream";
54
54
  }
55
- function loadIntoCache(relativePath) {
55
+ function readStaticFile(relativePath, cache) {
56
56
  const filePath = resolve(UI_STATIC_ROOT, relativePath);
57
57
  try {
58
58
  const content = readFileSync(filePath);
@@ -62,8 +62,10 @@ function loadIntoCache(relativePath) {
62
62
  etag: computeEtag(content),
63
63
  cacheControl: resolveCacheControl(relativePath)
64
64
  };
65
- fileCache.set(relativePath, cached);
66
- stats.entries = fileCache.size;
65
+ if (cache) {
66
+ fileCache.set(relativePath, cached);
67
+ stats.entries = fileCache.size;
68
+ }
67
69
  stats.misses += 1;
68
70
  return cached;
69
71
  } catch {
@@ -71,12 +73,13 @@ function loadIntoCache(relativePath) {
71
73
  }
72
74
  }
73
75
  function getCachedFile(relativePath) {
76
+ if (relativePath === "index.html") return readStaticFile(relativePath, false);
74
77
  const cached = fileCache.get(relativePath);
75
78
  if (cached) {
76
79
  stats.hits += 1;
77
80
  return cached;
78
81
  }
79
- return loadIntoCache(relativePath);
82
+ return readStaticFile(relativePath, true);
80
83
  }
81
84
  function getStaticUiCacheStats() {
82
85
  return { ...stats };
@@ -92,7 +95,6 @@ function resolveStaticUiRootForTests() {
92
95
  return UI_STATIC_ROOT;
93
96
  }
94
97
  const DEFAULT_PREWARM_PATHS = [
95
- "index.html",
96
98
  "favicon.ico",
97
99
  "logo.svg",
98
100
  "logo-dark.svg"
@@ -8,6 +8,7 @@ import { registerProjectsRoutes } from "./projects.js";
8
8
  import { registerProjectSkillRoutes } from "./project-skills.js";
9
9
  import { registerSearchRoutes } from "./search.js";
10
10
  import { registerMobileRoutes } from "./mobile.js";
11
+ import { registerNotificationRoutes } from "./notifications.js";
11
12
  import { registerInteractionStateRoutes } from "./interaction-state.js";
12
13
  import { registerComposerHistoryRoutes } from "./composer-history.js";
13
14
  import { registerEndpointToolRoutes } from "./endpoint-tools.js";
@@ -35,6 +36,7 @@ function registerCoreAuthenticatedRoutes(authenticated, deps) {
35
36
  registerProactiveRoutes(authenticated, deps);
36
37
  registerSearchRoutes(authenticated, deps);
37
38
  registerMobileRoutes(authenticated, deps);
39
+ registerNotificationRoutes(authenticated, deps);
38
40
  registerInteractionStateRoutes(authenticated, deps);
39
41
  registerComposerHistoryRoutes(authenticated, deps);
40
42
  registerEndpointToolRoutes(authenticated, deps);
@@ -1,4 +1,4 @@
1
- import { acknowledgeMobileActivityEvent, listMobileActivityEvents, registerMobileDevice, removeMobileDevice, updateMobileDevicePreferences } from "../../../mobile/notification-store.js";
1
+ import { registerNotificationDevice, removeNotificationDevice, updateNotificationDevicePreferences } from "../../../notifications/device-store.js";
2
2
  //#region src/gateway/hono/routes/mobile.ts
3
3
  function stringField(value, maxLength) {
4
4
  return typeof value === "string" && value.trim().length > 0 && value.trim().length <= maxLength ? value.trim() : null;
@@ -9,10 +9,15 @@ function parsePreferences(value) {
9
9
  const source = value;
10
10
  const result = {};
11
11
  for (const key of [
12
- "needsInput",
13
- "failed",
14
- "completed",
15
- "automationFailed"
12
+ "chatCompleted",
13
+ "chatFailed",
14
+ "taskNeedsInput",
15
+ "taskBlocked",
16
+ "taskFailed",
17
+ "taskCompleted",
18
+ "automationCompleted",
19
+ "automationFailed",
20
+ "proactiveInsight"
16
21
  ]) {
17
22
  if (source[key] === void 0) continue;
18
23
  if (typeof source[key] !== "boolean") return null;
@@ -26,15 +31,8 @@ function parsePlatform(value) {
26
31
  function parsePermission(value) {
27
32
  return value === "granted" || value === "denied" || value === "unknown" ? value : null;
28
33
  }
29
- function parseCursor(value) {
30
- if (!value) return void 0;
31
- const parsed = Number.parseInt(value, 10);
32
- return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
33
- }
34
- function parseLimit(value) {
35
- if (!value) return void 0;
36
- const parsed = Number.parseInt(value, 10);
37
- return Number.isFinite(parsed) ? Math.max(1, Math.min(100, parsed)) : void 0;
34
+ function parseLocale(value) {
35
+ return value === "en" || value === "zh" ? value : null;
38
36
  }
39
37
  function registerMobileRoutes(authenticated, _deps) {
40
38
  authenticated.post("/api/mobile/devices/register", async (c) => {
@@ -44,17 +42,19 @@ function registerMobileRoutes(authenticated, _deps) {
44
42
  const platform = parsePlatform(body?.platform);
45
43
  const permissions = parsePermission(body?.permissions);
46
44
  const preferences = parsePreferences(body?.preferences);
45
+ const locale = parseLocale(body?.locale);
47
46
  const appVersion = body?.appVersion === void 0 ? void 0 : stringField(body.appVersion, 128);
48
- if (!id || !pushToken || !platform || !permissions || preferences === null || appVersion === null) return c.json({
47
+ if (!id || !pushToken || !platform || !permissions || !locale || preferences === null || appVersion === null) return c.json({
49
48
  ok: false,
50
49
  error: "Invalid mobile device registration"
51
50
  }, 400);
52
- const device = registerMobileDevice({
51
+ const device = registerNotificationDevice({
53
52
  id,
54
53
  pushToken,
55
54
  platform,
56
55
  permissions,
57
56
  preferences,
57
+ locale,
58
58
  appVersion
59
59
  });
60
60
  return c.json({
@@ -68,7 +68,7 @@ function registerMobileRoutes(authenticated, _deps) {
68
68
  ok: false,
69
69
  error: "Invalid notification preferences"
70
70
  }, 400);
71
- const device = updateMobileDevicePreferences(c.req.param("id"), preferences);
71
+ const device = updateNotificationDevicePreferences(c.req.param("id"), preferences);
72
72
  if (!device) return c.json({
73
73
  ok: false,
74
74
  error: "Mobile device not found"
@@ -81,31 +81,9 @@ function registerMobileRoutes(authenticated, _deps) {
81
81
  authenticated.delete("/api/mobile/devices/:id", (c) => {
82
82
  return c.json({
83
83
  ok: true,
84
- removed: removeMobileDevice(c.req.param("id"))
85
- });
86
- });
87
- authenticated.get("/api/mobile/activity", (c) => {
88
- const result = listMobileActivityEvents({
89
- cursor: parseCursor(c.req.query("cursor")),
90
- limit: parseLimit(c.req.query("limit"))
91
- });
92
- return c.json({
93
- ok: true,
94
- ...result
84
+ removed: removeNotificationDevice(c.req.param("id"))
95
85
  });
96
86
  });
97
- authenticated.post("/api/mobile/activity/:id/ack", async (c) => {
98
- const deviceId = stringField((await c.req.json().catch(() => null))?.deviceId, 160);
99
- if (!deviceId) return c.json({
100
- ok: false,
101
- error: "deviceId is required"
102
- }, 400);
103
- if (!acknowledgeMobileActivityEvent(c.req.param("id"), deviceId)) return c.json({
104
- ok: false,
105
- error: "Activity event or mobile device not found"
106
- }, 404);
107
- return c.json({ ok: true });
108
- });
109
87
  }
110
88
  //#endregion
111
89
  export { registerMobileRoutes };
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerNotificationRoutes(authenticated: Hono, _deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,45 @@
1
+ import { acknowledgeNotification, listNotificationEvents, notificationDeliveryMetrics } from "../../../notifications/store.js";
2
+ //#region src/gateway/hono/routes/notifications.ts
3
+ function integerQuery(value, min, max) {
4
+ if (!value) return void 0;
5
+ const parsed = Number.parseInt(value, 10);
6
+ return Number.isFinite(parsed) ? Math.max(min, Math.min(max, parsed)) : void 0;
7
+ }
8
+ function stringField(value, maxLength) {
9
+ return typeof value === "string" && value.trim().length > 0 && value.trim().length <= maxLength ? value.trim() : null;
10
+ }
11
+ function registerNotificationRoutes(authenticated, _deps) {
12
+ authenticated.get("/api/notifications", (c) => {
13
+ const result = listNotificationEvents({
14
+ afterId: c.req.query("after")?.trim() || void 0,
15
+ since: integerQuery(c.req.query("since"), 0, Number.MAX_SAFE_INTEGER),
16
+ limit: integerQuery(c.req.query("limit"), 1, 100)
17
+ });
18
+ return c.json({
19
+ ok: true,
20
+ ...result
21
+ });
22
+ });
23
+ authenticated.post("/api/notifications/:id/ack", async (c) => {
24
+ const body = await c.req.json().catch(() => null);
25
+ const consumerId = stringField(body?.consumerId, 160);
26
+ const surface = body?.surface;
27
+ if (!consumerId || surface !== "web" && surface !== "electron" && surface !== "mobile") return c.json({
28
+ ok: false,
29
+ error: "Invalid notification acknowledgement"
30
+ }, 400);
31
+ if (!acknowledgeNotification(c.req.param("id"), consumerId, surface)) return c.json({
32
+ ok: false,
33
+ error: "Notification not found"
34
+ }, 404);
35
+ return c.json({ ok: true });
36
+ });
37
+ authenticated.get("/api/notifications/metrics", (c) => {
38
+ return c.json({
39
+ ok: true,
40
+ deliveries: notificationDeliveryMetrics()
41
+ });
42
+ });
43
+ }
44
+ //#endregion
45
+ export { registerNotificationRoutes };
@@ -60,6 +60,14 @@ function buildDirectSessionMetadata(params) {
60
60
  }
61
61
  function registerSessionsRoutes(authenticated, deps) {
62
62
  const { service } = deps;
63
+ authenticated.get("/api/session-runs", (c) => {
64
+ const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
65
+ if (blocked) return blocked;
66
+ return c.json({
67
+ ok: true,
68
+ payload: { runs: service.sessions.listActiveRuns() }
69
+ });
70
+ });
63
71
  authenticated.get("/api/sidebar/chat-list", async (c) => {
64
72
  const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
65
73
  if (blocked) return blocked;
@@ -648,6 +656,29 @@ function registerSessionsRoutes(authenticated, deps) {
648
656
  }, 400);
649
657
  }
650
658
  });
659
+ authenticated.post("/api/sessions/:key/fork-at-turn", async (c) => {
660
+ const key = c.req.param("key");
661
+ const body = await c.req.json().catch(() => ({}));
662
+ const lastTurnId = typeof body.lastTurnId === "string" ? body.lastTurnId.trim() : "";
663
+ if (!lastTurnId) return c.json({
664
+ ok: false,
665
+ error: "lastTurnId is required"
666
+ }, 400);
667
+ try {
668
+ const result = await service.sessions.forkAtTurn(key, lastTurnId);
669
+ return c.json({
670
+ ok: true,
671
+ ...result
672
+ }, 201);
673
+ } catch (err) {
674
+ const errorMessage = err instanceof Error ? err.message : String(err);
675
+ const status = errorMessage.startsWith("Session not found:") ? 404 : 409;
676
+ return c.json({
677
+ ok: false,
678
+ error: errorMessage
679
+ }, status);
680
+ }
681
+ });
651
682
  authenticated.post("/api/sessions/:key/fork-row", async (c) => {
652
683
  const key = c.req.param("key");
653
684
  const body = await c.req.json().catch(() => ({}));
@@ -1,6 +1,7 @@
1
1
  import { runSqliteWriteTransaction } from "../../../storage/sqlite/transaction.js";
2
2
  import { TaskRepository } from "../../../tasks/task-repository.js";
3
3
  import { TaskConversationRepository } from "../../../tasks/task-conversation-repository.js";
4
+ import { enqueueTaskChangedEvent } from "../../../tasks/task-change-events.js";
4
5
  import { TaskRunRepository } from "../../../tasks/task-run-repository.js";
5
6
  import { TaskReadModelProjector } from "../../../tasks/task-read-model-projector.js";
6
7
  import { TaskPhaseSchema } from "../../../../packages/gateway-contract/src/task-lifecycle.js";
@@ -8,7 +9,6 @@ import { TaskBoardPositionRequestSchema, TaskCommandRequestSchema, TaskContextIn
8
9
  import { ProjectMonitoringUpdateSchema } from "../../../../packages/gateway-contract/src/project-monitoring.js";
9
10
  import { resolveProjectAgentId } from "../../../projects/project-agent.js";
10
11
  import { TaskContextRepository } from "../../../tasks/task-context-repository.js";
11
- import { enqueueTaskChangedEvent } from "../../../tasks/task-change-events.js";
12
12
  import { TaskDependencyError, TaskDependencyService } from "../../../tasks/task-dependency-service.js";
13
13
  import { TaskApplicationService } from "../../../tasks/task-application-service.js";
14
14
  import { ProjectMonitoringService } from "../../../tasks/project-monitoring-service.js";
@@ -67,7 +67,10 @@ function applySourceRevocationChoices(impact, options) {
67
67
  } else updateUserFocus(id, { status: "paused" });
68
68
  for (const id of impact.understandingIds) if (options.derived === "delete") {
69
69
  if (deleteUnderstanding(id)) derivedDeleted += 1;
70
- } else setUnderstandingStatus(id, "needs_review");
70
+ } else setUnderstandingStatus(id, "needs_review", {
71
+ actorType: "runtime",
72
+ source: "understanding-source-revoked"
73
+ });
71
74
  if (options.derived === "delete" && impact.sourceInstanceId) derivedDeleted += deleteMemoryRecordsBySourceInstanceId(impact.sourceInstanceId);
72
75
  const rawDeleted = options.raw === "delete" && impact.sourceInstanceId ? deleteKnowledgeSourceItems(impact.sourceInstanceId) : 0;
73
76
  return {