@xopcai/xopc 0.0.225 → 0.0.228

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 (239) 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-CtTYnku4.js → activity-store-M0nAY5XB.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dizuqu_4.js → agent-avatar-dicebear-CjGZBs4C.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-B0NI4_NI.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-CLRMz2BT.js → api-BywYxpaS.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnk-DtQh.js → app-management-settings-panel--SjycrXk.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-wP0rogVI.js → appearance-settings-8G-TVUtg.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-2NiqD-YP.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-Cpzsm-DM.js → archive-plugin-7_DXaMTP.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Bd2OOoEK.js → attachment-load-Bx44zSpz.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-DNqhguyk.js → automations-page-CrKAHqc0.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-workspace-Q3g9cf0h.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-Dcma5HdI.js → binary-plugins-DjDwnHAQ.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-D-B8ThwK.js → block-editor-7aMOKoZM.js} +3 -3
  16. package/dist/gateway/static/root/assets/browser-settings-page-DTwPkmAC.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAPZIXrs.js → browser-workflow-inputs-8NC2qDRF.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-DHtaSKEh.js → browser-workflows-page-DVLrWKz_.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-YcP4FbN7.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-zsZQ7im3.js → capability-presets-api-o0y9WgAI.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-AcPjHHia.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-Cp8iaaXp.js → channel-recipient-api-C5ABr73b.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-Ca94Q1D-.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-Dr6Rq2ln.js → chat-terminal-dock-BR-_7KC0.js} +2 -2
  26. package/dist/gateway/static/root/assets/connectors-page-SGxfLTd6.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-BiXrpzmo.js → cron-expression-D8-c-Tkw.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-BPuRtwKt.js → date-picker-kV-Jyl9J.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-BNC_W7wI.js → dependency-picker-CwKcrfGj.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-DzOpt5nI.js → desktop-pet-D9rnchu3.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-BW0brCvH.js → desktop-pet-settings-CTs5WGzk.js} +1 -1
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-Baml0uTS.js → directory-picker-path-field-CCl0aaDm.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-CBXyKmfS.js → extension-debug-page-Cau40SvC.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-BBhcr_SZ.js → extension-page-BsJXdvIL.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-4rwWpN9_.js → extension-settings-page-qWqJyF7-.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-api-Dg-BlBe4.js → gateway-config-api-BI0SELXm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-Du0MvK9s.js → gateway-config-swr-BWGjnmDl.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-BOuYZOYe.js → gateway-settings-6ZdOIC7F.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-JbjcHCaN.js → gateway-startup-retry-B_zrtccP.js} +1 -1
  40. package/dist/gateway/static/root/assets/heartbeat-settings-KBwhXeFD.js +1 -0
  41. package/dist/gateway/static/root/assets/home-page-BA2M4CLi.js +1 -0
  42. package/dist/gateway/static/root/assets/{image-generation-api-G2tfPvKP.js → image-generation-api-YKP2me5Z.js} +1 -1
  43. package/dist/gateway/static/root/assets/index-BX0dz1JK.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-L1Vtxgp9.js → keyboard-shortcuts-settings-kHtpnyEm.js} +1 -1
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-D2nkn09R.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page--thlkBLS.js → local-apps-page-BCXa0oUa.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-DqJz-cOR.js → locale-store-CXhjfe4q.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-D3sNst0K.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-p55fR4XO.js → management-settings-tHnlfOAQ.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-DwMcRlBR.js → markdown-split-BMLqHHr5.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-O6H3GZn7.js → media-plugins-DybwqTgv.js} +1 -1
  55. package/dist/gateway/static/root/assets/messages-BMdD0LWk.js +3 -0
  56. package/dist/gateway/static/root/assets/{notes-api-CrjQbmk1.js → notes-api-BFsOGYkd.js} +1 -1
  57. package/dist/gateway/static/root/assets/{notes-page-miO9ig9C.js → notes-page-C24SfF6r.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-CTdZc3ov.js +4 -0
  59. package/dist/gateway/static/root/assets/{product-open-page-BOu07nXf.js → product-open-page-DBfCVlJq.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-COHaEpbA.js +1 -0
  61. package/dist/gateway/static/root/assets/projects-page-lMnST7D_.js +1 -0
  62. package/dist/gateway/static/root/assets/{registry-api-Bf_HDLUJ.js → registry-api-BFZrVYfy.js} +1 -1
  63. package/dist/gateway/static/root/assets/remote-access-hub-BIRKBvO_.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DthuRqUH.js → runtime-tools-settings-panel-BPEGTip5.js} +2 -2
  65. package/dist/gateway/static/root/assets/{schema-form-8W8PhXxa.js → schema-form-Dxlu60Td.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-CATO9G3y.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-Cco_W41x.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-CrsKGYiG.js → settings-form-section-ChXh3Bwk.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-WJtI0AAq.js → settings-loading-skeleton-BCAUqIe2.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-PCjwRF47.js → settings-page-D25W9Okr.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-D65CwlNC.js → setup-status-panel-DsN7Z4Fl.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-BGtvLLeZ.js → share-preview-page-CRFnUaNb.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-CAX0eNaP.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-Doy1gghe.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-C_npyryI.js → skills-page-Cl7jjTK7.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-C46Sd78k.js → skills-page.utils-BiCl4nb5.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-DomTLwki.js → system-settings-panel-BuESR7ZT.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-BRiy8NL3.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Ce7wq__X.js → theme-store-DOdCjyuw.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-Do9mCRcY.js → use-autosave-Dg1mgJ_l.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-context-page-CqoADNKu.js +1 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-Bc5p-0tX.js → voice-api-key-field-BDNexlVR.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-BieqsmT1.js → work-discovery-overlay-BHTfeaWL.js} +1 -1
  84. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DVj8iYvm.js → workflow-run-setup-panel-Cf_w-NZy.js} +2 -2
  85. package/dist/gateway/static/root/assets/workflows-page-j0P-uECz.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-manager.d.ts +3 -1
  92. package/dist/src/agent/agent-manager.js +22 -5
  93. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -0
  94. package/dist/src/agent/lifecycle/timeout-wrapper.js +7 -6
  95. package/dist/src/agent/mcp/mcp-transport-config.d.ts +1 -1
  96. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  97. package/dist/src/agent/memory/understanding/service.js +1 -0
  98. package/dist/src/agent/memory/understanding/types.d.ts +1 -0
  99. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -2
  100. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +4 -4
  101. package/dist/src/agent/service.d.ts +2 -0
  102. package/dist/src/agent/service.js +6 -0
  103. package/dist/src/agent/skills/index.d.ts +22 -2
  104. package/dist/src/agent/skills/index.js +74 -32
  105. package/dist/src/agent/skills/skill-sources.d.ts +0 -1
  106. package/dist/src/agent/skills/skill-sources.js +1 -11
  107. package/dist/src/agent/tools/create-share-tool.js +14 -1
  108. package/dist/src/agent/tools/exec-command.js +3 -3
  109. package/dist/src/agent/tools/execute-code-tool.js +1 -1
  110. package/dist/src/agent/tools/executor.js +2 -2
  111. package/dist/src/agent/tools/image-generate-tool.js +12 -0
  112. package/dist/src/agent/tools/send-media.js +11 -0
  113. package/dist/src/agent/tools/xopc-use-tool.js +1 -1
  114. package/dist/src/cli/command-loaders.js +1 -0
  115. package/dist/src/cli/command-manifest.js +4 -0
  116. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  117. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  118. package/dist/src/cli/commands/history.d.ts +1 -0
  119. package/dist/src/cli/commands/history.js +50 -0
  120. package/dist/src/config/agent-profile.js +1 -1
  121. package/dist/src/connectors/connected-source-understanding.js +1 -1
  122. package/dist/src/gateway/agents-admin.js +1 -1
  123. package/dist/src/gateway/chat-stream/protocol.d.ts +3 -2
  124. package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +16 -0
  125. package/dist/src/gateway/chat-stream/turn-outcome-collector.js +111 -0
  126. package/dist/src/gateway/heartbeat/service.js +1 -1
  127. package/dist/src/gateway/hono/lib/static-ui.js +7 -5
  128. package/dist/src/gateway/hono/routes/connectors.js +18 -16
  129. package/dist/src/gateway/hono/routes/index.js +2 -0
  130. package/dist/src/gateway/hono/routes/mobile.js +18 -40
  131. package/dist/src/gateway/hono/routes/notifications.d.ts +3 -0
  132. package/dist/src/gateway/hono/routes/notifications.js +45 -0
  133. package/dist/src/gateway/hono/routes/project-skills.js +30 -2
  134. package/dist/src/gateway/hono/routes/sessions.js +31 -0
  135. package/dist/src/gateway/hono/routes/tasks.js +1 -1
  136. package/dist/src/gateway/hono/routes/voice.js +1 -1
  137. package/dist/src/gateway/hono/routes/you.js +52 -0
  138. package/dist/src/gateway/service/agent-runner.js +6 -2
  139. package/dist/src/gateway/service/run-gateway-agent.js +53 -1
  140. package/dist/src/gateway/service/sessions-api.d.ts +6 -0
  141. package/dist/src/gateway/service/sessions-api.js +60 -3
  142. package/dist/src/gateway/service.d.ts +2 -2
  143. package/dist/src/gateway/service.js +8 -7
  144. package/dist/src/heartbeat/index.js +1 -1
  145. package/dist/src/history/ctx/exporter.d.ts +14 -0
  146. package/dist/src/history/ctx/exporter.js +99 -0
  147. package/dist/src/history/ctx/format.d.ts +25 -0
  148. package/dist/src/history/ctx/format.js +282 -0
  149. package/dist/src/infra/update-restart.js +1 -1
  150. package/dist/src/knowledge/connected-understanding-pipeline.js +12 -3
  151. package/dist/src/knowledge/index.d.ts +0 -1
  152. package/dist/src/knowledge/index.js +1 -2
  153. package/dist/src/media/session-references.d.ts +6 -0
  154. package/dist/src/media/session-references.js +24 -3
  155. package/dist/src/notifications/device-store.d.ts +16 -0
  156. package/dist/src/notifications/device-store.js +96 -0
  157. package/dist/src/notifications/planner.d.ts +6 -0
  158. package/dist/src/notifications/planner.js +156 -0
  159. package/dist/src/notifications/service.d.ts +18 -0
  160. package/dist/src/notifications/service.js +184 -0
  161. package/dist/src/notifications/store.d.ts +53 -0
  162. package/dist/src/notifications/store.js +184 -0
  163. package/dist/src/notifications/types.d.ts +29 -0
  164. package/dist/src/notifications/types.js +14 -0
  165. package/dist/src/projects/project-skill-service.d.ts +28 -6
  166. package/dist/src/projects/project-skill-service.js +76 -29
  167. package/dist/src/session/client-history.d.ts +3 -1
  168. package/dist/src/session/client-history.js +13 -0
  169. package/dist/src/session/index.d.ts +1 -1
  170. package/dist/src/session/manager.d.ts +1 -0
  171. package/dist/src/session/manager.js +6 -0
  172. package/dist/src/session/store.d.ts +15 -0
  173. package/dist/src/session/store.js +58 -0
  174. package/dist/src/storage/sqlite/index.d.ts +2 -1
  175. package/dist/src/storage/sqlite/index.js +3 -2
  176. package/dist/src/storage/sqlite/migrations/135_user_people.sql +59 -0
  177. package/dist/src/storage/sqlite/migrations/136_product_notifications.sql +79 -0
  178. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  179. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  180. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  181. package/dist/src/storage/sqlite/schema.js +1 -1
  182. package/dist/src/storage/sqlite/session-input-repository.d.ts +5 -0
  183. package/dist/src/storage/sqlite/session-input-repository.js +9 -1
  184. package/dist/src/storage/sqlite/user-people-repository.d.ts +32 -0
  185. package/dist/src/storage/sqlite/user-people-repository.js +246 -0
  186. package/dist/src/tasks/index.js +2 -2
  187. package/dist/src/tasks/task-application-service.js +42 -6
  188. package/dist/src/tasks/task-change-events.d.ts +9 -0
  189. package/dist/src/tasks/task-change-events.js +17 -1
  190. package/dist/src/tasks/task-outbox-dispatcher.js +5 -1
  191. package/dist/src/tasks/task-run-dispatcher.js +4 -2
  192. package/dist/src/tasks/task-run-repository.js +13 -0
  193. package/dist/src/user-context/relationships/indexer.d.ts +13 -0
  194. package/dist/src/user-context/relationships/indexer.js +185 -0
  195. package/dist/src/user-context/relationships/service.d.ts +22 -0
  196. package/dist/src/user-context/relationships/service.js +50 -0
  197. package/dist/src/user-context/relationships/types.d.ts +55 -0
  198. package/dist/src/user-context/relationships/types.js +10 -0
  199. package/dist/src/user-context/sources/repository.d.ts +1 -1
  200. package/dist/src/user-context/sources/repository.js +8 -2
  201. package/dist/src/work-discovery/service.js +1 -1
  202. package/package.json +2 -2
  203. package/dist/gateway/static/root/assets/agents-DeEEFZJ4.js +0 -68
  204. package/dist/gateway/static/root/assets/apps-page-Db5YNHVM.js +0 -1
  205. package/dist/gateway/static/root/assets/automations-workspace-CNT05YTb.js +0 -6
  206. package/dist/gateway/static/root/assets/browser-settings-page-UbDj3LIq.js +0 -8
  207. package/dist/gateway/static/root/assets/capabilities-settings-panel-CiO152QS.js +0 -7
  208. package/dist/gateway/static/root/assets/capability-presets-settings-panel-Bc_hRwfL.js +0 -3
  209. package/dist/gateway/static/root/assets/channels-settings-CFW7zBoT.js +0 -1
  210. package/dist/gateway/static/root/assets/channels-status-swr-5rNVq7iI.js +0 -1
  211. package/dist/gateway/static/root/assets/connectors-page-DLBr5nre.js +0 -2
  212. package/dist/gateway/static/root/assets/heartbeat-settings-Dq4YAlSx.js +0 -1
  213. package/dist/gateway/static/root/assets/home-page-BIXkO0Ck.js +0 -1
  214. package/dist/gateway/static/root/assets/index-Csccu8sa.js +0 -74
  215. package/dist/gateway/static/root/assets/index-D3_xSYKd.css +0 -2
  216. package/dist/gateway/static/root/assets/local-app-workbench-page-D-eacBcO.js +0 -2
  217. package/dist/gateway/static/root/assets/logs-page-BRCglHvd.js +0 -2
  218. package/dist/gateway/static/root/assets/markdown-view-CTB9u15e.js +0 -69
  219. package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +0 -134
  220. package/dist/gateway/static/root/assets/messages-CeydamsI.js +0 -3
  221. package/dist/gateway/static/root/assets/notes-workbench-_13lmvmF.js +0 -4
  222. package/dist/gateway/static/root/assets/project-detail-page-BStRkOQr.js +0 -1
  223. package/dist/gateway/static/root/assets/projects-page-CY03RxVr.js +0 -1
  224. package/dist/gateway/static/root/assets/remote-access-hub-B19llkld.js +0 -1
  225. package/dist/gateway/static/root/assets/sessions-page-BDA2qbTd.js +0 -1
  226. package/dist/gateway/static/root/assets/settings-advanced-gate-BONIDX4v.js +0 -1
  227. package/dist/gateway/static/root/assets/shares-settings-CdzVKrBl.js +0 -1
  228. package/dist/gateway/static/root/assets/skill-reload-api-CsRWid5h.js +0 -1
  229. package/dist/gateway/static/root/assets/task-detail-page-B6YFX7kK.js +0 -1
  230. package/dist/gateway/static/root/assets/user-context-page-CiCQA40E.js +0 -1
  231. package/dist/gateway/static/root/assets/workflows-page-AG04TTuH.js +0 -5
  232. package/dist/src/knowledge/people-graph.d.ts +0 -25
  233. package/dist/src/knowledge/people-graph.js +0 -92
  234. package/dist/src/mobile/notification-service.d.ts +0 -9
  235. package/dist/src/mobile/notification-service.js +0 -156
  236. package/dist/src/mobile/notification-store.d.ts +0 -28
  237. package/dist/src/mobile/notification-store.js +0 -132
  238. package/dist/src/mobile/notification-types.d.ts +0 -37
  239. package/dist/src/mobile/notification-types.js +0 -9
@@ -11,6 +11,7 @@ const REGISTRY_COMMAND_MODULES = {
11
11
  tui: () => import("./commands/tui.js"),
12
12
  resume: () => import("./commands/resume.js"),
13
13
  gateway: () => import("./commands/gateway.js"),
14
+ history: () => import("./commands/history.js"),
14
15
  session: () => import("./commands/session.js"),
15
16
  project: () => import("./commands/project.js"),
16
17
  config: () => import("./commands/config.js"),
@@ -67,6 +67,10 @@ const ROOT_HELP_COMMANDS = [
67
67
  name: "gateway [options]",
68
68
  description: "Start the xopc gateway server"
69
69
  },
70
+ {
71
+ name: "history",
72
+ description: "Export XOPC session history for external tools"
73
+ },
70
74
  {
71
75
  name: "session",
72
76
  description: "Session management commands"
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v134).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v136).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -1,8 +1,8 @@
1
1
  import { init_paths, resolveConfigPath } from "../../../config/paths.js";
2
2
  import { loadConfig } from "../../../config/loader.js";
3
3
  import "../../../config/index.js";
4
- import { resolveGatewayService } from "../../../daemon/service.js";
5
4
  import { isRestartEnabled } from "../../../config/commands.flags.js";
5
+ import { resolveGatewayService } from "../../../daemon/service.js";
6
6
  import { authorizeGatewaySigusr1Restart, writeGatewayRestartIntentSync } from "../../../infra/restart.js";
7
7
  import { findVerifiedGatewayListenerPidsOnPortSync, formatGatewayPidList, signalVerifiedGatewayPidSync } from "../../../infra/gateway-processes.js";
8
8
  import { runServiceRestart, runServiceStop } from "./lifecycle-core.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ import { requireXopcDatabase } from "../../storage/sqlite/connection.js";
2
+ import "../../storage/sqlite/index.js";
3
+ import { formatExamples, register } from "../registry.js";
4
+ import { exportCtxHistory } from "../../history/ctx/exporter.js";
5
+ import { Command } from "commander";
6
+ //#region src/cli/commands/history.ts
7
+ async function runCtxExport(options) {
8
+ try {
9
+ const { db } = requireXopcDatabase();
10
+ const result = await exportCtxHistory(db, { outputDir: options.outputDir });
11
+ const importCommand = `ctx import --history-source-manifest ${result.manifestPath}`;
12
+ if (options.json) {
13
+ console.log(JSON.stringify({
14
+ ...result,
15
+ importCommand
16
+ }, null, 2));
17
+ return;
18
+ }
19
+ const action = result.changed ? "Exported" : "Already up to date";
20
+ console.log(`${action}: ${result.sessionCount} sessions, ${result.eventCount} events`);
21
+ console.log(`History: ${result.historyPath}`);
22
+ console.log(`Manifest: ${result.manifestPath}`);
23
+ console.log(`\nRegister or refresh it in ctx:\n ${importCommand}`);
24
+ } catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ console.error(`Failed to export history for ctx: ${message}`);
27
+ process.exit(1);
28
+ }
29
+ }
30
+ function createHistoryCommand(_ctx) {
31
+ const command = new Command("history").description("Export XOPC session history for external tools").addHelpText("after", formatExamples([
32
+ "xopc history export ctx",
33
+ "xopc history export ctx --output-dir ./xopc-ctx-history",
34
+ "xopc history export ctx --json"
35
+ ]));
36
+ command.command("export").description("Export session history").command("ctx").description("Export a provider-owned ctx-history-jsonl-v2 source").option("--output-dir <path>", "Output directory (default: <xopc-state>/exports/ctx)").option("--json", "Output the result as JSON").action(runCtxExport);
37
+ return command;
38
+ }
39
+ register({
40
+ id: "history",
41
+ name: "history",
42
+ description: "Export XOPC session history for external tools",
43
+ factory: createHistoryCommand,
44
+ metadata: {
45
+ category: "utility",
46
+ examples: ["xopc history export ctx"]
47
+ }
48
+ });
49
+ //#endregion
50
+ export {};
@@ -1,6 +1,6 @@
1
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
1
2
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
3
  import "../agent-manifest/index.js";
3
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -1,9 +1,9 @@
1
1
  import { finishContextExtractionRun } from "../storage/sqlite/context-extraction-repository.js";
2
2
  import { listKnowledgeSourceItems } from "../storage/sqlite/knowledge-repository.js";
3
3
  import "../storage/sqlite/index.js";
4
+ import { focusLifecycle } from "../user-context/focus-lifecycle.js";
4
5
  import { upsertUserFocus } from "../user-context/sources/repository.js";
5
6
  import { claimRegisteredExtraction } from "../user-context/extraction/registry.js";
6
- import { focusLifecycle } from "../user-context/focus-lifecycle.js";
7
7
  import { allowsRemoteSourceProcessing } from "../user-context/sources/processing-policy.js";
8
8
  import { analyzeUnderstandingSources } from "../work-discovery/analyzer.js";
9
9
  import { createHash } from "node:crypto";
@@ -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";
@@ -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 };
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
4
- import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
5
4
  import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
6
5
  import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
6
+ import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
7
7
  import { createHeartbeatWake } from "../../heartbeat/wake.js";
8
8
  import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
9
9
  import { readFile } from "fs/promises";
@@ -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"
@@ -15,18 +15,17 @@ import { listUnderstandingSourceGrants, revokeUnderstandingSourceGrant } from ".
15
15
  import { recordConnectorHealthUsage } from "../../../connectors/usage.js";
16
16
  import { getConnectorInstance, getInstalledConnectorDefinition, listConnectorInstances } from "../../../connectors/instances.js";
17
17
  import { installConnector, installConnectorDefinition, uninstallConnector, updateConnectorConfig } from "../../../connectors/install.js";
18
+ import { ConfigPersistenceError, persistConfigMutation } from "../../../config/config-mutation.js";
18
19
  import { getMcpOAuthManager } from "../../../agent/mcp/oauth/mcp-oauth-manager.js";
19
20
  import { startConnectorAuthorization } from "../../../connectors/auth-provider-registry.js";
20
21
  import { composioLogoResponse } from "../../../connectors/composio-logo.js";
21
22
  import { inspectManagedComposioStatus } from "../../../connectors/composio-managed-client.js";
22
23
  import { appendComposioTriggerEvent, listComposioTriggerEvents } from "../../../connectors/composio-triggers.js";
23
- import { buildConnectedPeopleGraph } from "../../../knowledge/people-graph.js";
24
- import "../../../knowledge/index.js";
25
24
  import { ingestLocalFolderSource } from "../../../connectors/connected-source-ingestion.js";
26
25
  import { previewConnectorDefinition, testConnectorInstance } from "../../../connectors/health.js";
27
26
  import { setConnectorEnabled } from "../../../connectors/lifecycle.js";
28
27
  import { projectComposioConnectionStatus } from "../../../connectors/runtime-status.js";
29
- import { ConfigPersistenceError, persistConfigMutation } from "../../../config/config-mutation.js";
28
+ import { applySourceRevocationChoices, sourceRevocationImpact } from "./understanding-sources.js";
30
29
  //#region src/gateway/hono/routes/connectors.ts
31
30
  init_agent_scope();
32
31
  function errorMessage(error) {
@@ -196,7 +195,14 @@ function registerConnectorRoutes(authenticated, deps) {
196
195
  if (connectionId && !policy.scanEnabled) {
197
196
  service.setConnectorLearningPaused(connectionId, true);
198
197
  const grant = listUnderstandingSourceGrants().find((item) => item.sourceKey === `connector-account:${account.id}`);
199
- if (grant) revokeUnderstandingSourceGrant(grant.id);
198
+ if (grant) {
199
+ const impact = sourceRevocationImpact(grant.id);
200
+ revokeUnderstandingSourceGrant(grant.id);
201
+ if (impact) applySourceRevocationChoices(impact, {
202
+ derived: "retain",
203
+ raw: "retain"
204
+ });
205
+ }
200
206
  } else if (connectionId && previous?.scanEnabled === false) {
201
207
  if (service.setConnectorLearningPaused(connectionId, false) === 0) service.requestConnectorLearning(connectionId, {
202
208
  mode: "incremental",
@@ -288,7 +294,14 @@ function registerConnectorRoutes(authenticated, deps) {
288
294
  await revokeComposioConnection(connectionId);
289
295
  if (connection?.accountId) {
290
296
  const grant = listUnderstandingSourceGrants().find((item) => item.sourceKey === `connector-account:${connection.accountId}`);
291
- if (grant) revokeUnderstandingSourceGrant(grant.id);
297
+ if (grant) {
298
+ const impact = sourceRevocationImpact(grant.id);
299
+ revokeUnderstandingSourceGrant(grant.id);
300
+ if (impact) applySourceRevocationChoices(impact, {
301
+ derived: "retain",
302
+ raw: "retain"
303
+ });
304
+ }
292
305
  }
293
306
  return c.json({
294
307
  ok: true,
@@ -450,17 +463,6 @@ function registerConnectorRoutes(authenticated, deps) {
450
463
  }, 400);
451
464
  }
452
465
  });
453
- authenticated.get("/api/connectors/people", (c) => {
454
- const query = c.req.query("q") ?? "";
455
- const limit = Number(c.req.query("limit") ?? "100");
456
- return c.json({
457
- ok: true,
458
- payload: buildConnectedPeopleGraph({
459
- query,
460
- limit
461
- })
462
- });
463
- });
464
466
  authenticated.get("/api/connectors/:id", (c) => {
465
467
  const connectorId = c.req.param("id");
466
468
  const connector = getConnectorDefinition(connectorId);
@@ -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 };
@@ -5,6 +5,8 @@ function projectSkills(deps) {
5
5
  return new ProjectSkillService({
6
6
  projects: deps.service.projects,
7
7
  getConfig: () => deps.service.currentConfig,
8
+ getWorkspaceTrust: (workspaceRoot) => deps.service.agentService.getWorkspaceTrust(workspaceRoot),
9
+ setWorkspaceTrust: (workspaceRoot, trusted) => deps.service.agentService.setWorkspaceTrust(workspaceRoot, trusted),
8
10
  refreshSkills: () => deps.service.agentService.refreshSkillsAfterDiskChange()
9
11
  });
10
12
  }
@@ -31,11 +33,37 @@ function registerProjectSkillRoutes(authenticated, deps) {
31
33
  return errorResponse(c, error);
32
34
  }
33
35
  });
34
- authenticated.get("/api/projects/:projectId/skills/:skillId", (c) => {
36
+ authenticated.get("/api/projects/:projectId/workspace-trust", (c) => {
35
37
  try {
36
38
  return c.json({
37
39
  ok: true,
38
- skill: projectSkills(deps).getContent(c.req.param("projectId"), c.req.param("skillId"))
40
+ trust: projectSkills(deps).getWorkspaceTrust(c.req.param("projectId"))
41
+ });
42
+ } catch (error) {
43
+ return errorResponse(c, error);
44
+ }
45
+ });
46
+ authenticated.patch("/api/projects/:projectId/workspace-trust", async (c) => {
47
+ try {
48
+ const body = await c.req.json();
49
+ if (typeof body.trusted !== "boolean") return c.json({
50
+ ok: false,
51
+ error: "Expected { trusted: boolean }"
52
+ }, 400);
53
+ const trust = projectSkills(deps).setWorkspaceTrust(c.req.param("projectId"), body.trusted);
54
+ return c.json({
55
+ ok: true,
56
+ trust
57
+ });
58
+ } catch (error) {
59
+ return errorResponse(c, error);
60
+ }
61
+ });
62
+ authenticated.get("/api/projects/:projectId/skills/:skillKey", (c) => {
63
+ try {
64
+ return c.json({
65
+ ok: true,
66
+ skill: projectSkills(deps).getContent(c.req.param("projectId"), c.req.param("skillKey"))
39
67
  });
40
68
  } catch (error) {
41
69
  return errorResponse(c, error);