@xopcai/xopc 0.0.159 → 0.0.161

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 (215) 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/{action-boundary-settings-panel-CaRK2vIy.js → action-boundary-settings-panel-BIVBUiNT.js} +1 -1
  4. package/dist/gateway/static/root/assets/activity-store-o7GRljfD.js +1 -0
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BeVf03hx.js → agent-avatar-dicebear-9R3szLMc.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-_qbUaYbs.js +2 -0
  7. package/dist/gateway/static/root/assets/{api-BjcBIV2O.js → api-jSTqFMq9.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-BG2ulMYw.js → app-management-settings-panel-D81cyE76.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-0Kjenr2T.js → appearance-settings-Ct6bZQCV.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-0sPqD0FK.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-ChiNnH1e.js → archive-plugin-CfD7AZKn.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-pbBlQR-g.js → attachment-load-CP_Gaxt3.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automation-suggestion-card-CTZDOyDy.js → automation-suggestion-card-BGKM_NDZ.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-BxWBuBsE.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-BeZGzpGF.js → binary-plugins-IPr2EVnS.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BnDmhN5Z.js → block-editor-B6aHEGA6.js} +3 -3
  17. package/dist/gateway/static/root/assets/browser-settings-page-C499b9AH.js +8 -0
  18. package/dist/gateway/static/root/assets/{capability-presets-api-Ii36j_7v.js → capability-presets-api-CCX9-LjU.js} +1 -1
  19. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-Cl3dw4yh.js → capability-presets-settings-panel-Dva9SiPK.js} +2 -2
  20. package/dist/gateway/static/root/assets/{channel-recipient-api-CFqrSi5K.js → channel-recipient-api-MmLMLDWf.js} +1 -1
  21. package/dist/gateway/static/root/assets/channels-settings-DNAU7u9o.js +1 -0
  22. package/dist/gateway/static/root/assets/channels-status-swr-CIOH7tgn.js +1 -0
  23. package/dist/gateway/static/root/assets/check-DUBLcKHA.js +1 -0
  24. package/dist/gateway/static/root/assets/circle-alert-BEjgurr2.js +1 -0
  25. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
  26. package/dist/gateway/static/root/assets/{connector-logo-CiLxuZ8S.js → connector-logo-BbjzIs87.js} +1 -1
  27. package/dist/gateway/static/root/assets/connectors-page-TwiBp8vY.js +2 -0
  28. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
  29. package/dist/gateway/static/root/assets/desktop-pet-CYH5ZSXy.js +1 -0
  30. package/dist/gateway/static/root/assets/desktop-pet-settings-DQLqGLc0.js +1 -0
  31. package/dist/gateway/static/root/assets/desktop-pet-sprite-DTqXSpqf.js +1 -0
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-CC2VL5Mc.js → directory-picker-path-field-ClsiXhmz.js} +1 -1
  33. package/dist/gateway/static/root/assets/{dreaming-settings-KY7ZfVsy.js → dreaming-settings-CjMPPdzg.js} +3 -3
  34. package/dist/gateway/static/root/assets/{extension-debug-page-C8KBeucs.js → extension-debug-page-57eizjhB.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-CV-5Kcyk.js → extension-page-CsbSb3u1.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-DvUtDrAu.js → extension-settings-page-DKA9-lyP.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-api-DXfVeJLc.js → gateway-config-api-DIPJuzBZ.js} +1 -1
  38. package/dist/gateway/static/root/assets/gateway-settings-CDLqAQY7.js +1 -0
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-cxQ94qMm.js → gateway-startup-retry-DrfSJtvT.js} +1 -1
  40. package/dist/gateway/static/root/assets/goal-create-dialog-Q3B0E-0s.js +1 -0
  41. package/dist/gateway/static/root/assets/goal-detail-page-C5VAK04G.js +4 -0
  42. package/dist/gateway/static/root/assets/{goals-config-api-P8VhLqYF.js → goals-config-api-lGC10UkU.js} +1 -1
  43. package/dist/gateway/static/root/assets/goals-page-BJb-5IYw.js +2 -0
  44. package/dist/gateway/static/root/assets/{goals-settings-DHXyaH_O.js → goals-settings-BWq0pdrA.js} +1 -1
  45. package/dist/gateway/static/root/assets/{heartbeat-settings-CNckP_Dv.js → heartbeat-settings-D4o8BJVv.js} +1 -1
  46. package/dist/gateway/static/root/assets/index-CkUHH170.css +1 -0
  47. package/dist/gateway/static/root/assets/index-vq_cJZJC.js +199 -0
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-jXmv1RVX.js → keyboard-shortcuts-settings-6T2QYehS.js} +1 -1
  49. package/dist/gateway/static/root/assets/local-app-workbench-page-euH17Kvb.js +2 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-Cs5LKjtc.js → local-apps-page-DCjg2K9f.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-C_M71MK9.js → locale-store-Dar-xqQr.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-CyYCBqym.js +7 -0
  53. package/dist/gateway/static/root/assets/{markdown-split-BFqeSNte.js → markdown-split-rt1XO43g.js} +1 -1
  54. package/dist/gateway/static/root/assets/{media-plugins-Cc8379gq.js → media-plugins-Bwo8CJuh.js} +1 -1
  55. package/dist/gateway/static/root/assets/messages-CxySDn9d.js +5 -0
  56. package/dist/gateway/static/root/assets/models-hub-panel-DObxxjc9.js +2 -0
  57. package/dist/gateway/static/root/assets/{notes-page-DlGU4ipo.js → notes-page-Dp-pkX7d.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-CCb4RXcZ.js +4 -0
  59. package/dist/gateway/static/root/assets/{page-tabs-kFOswGlG.js → page-tabs-CzZ4iKOb.js} +1 -1
  60. package/dist/gateway/static/root/assets/{preview-open-alternatives-CvjuvABg.js → preview-open-alternatives-3E_Qa-58.js} +1 -1
  61. package/dist/gateway/static/root/assets/product-delivery-BTRT9kCS.js +1 -0
  62. package/dist/gateway/static/root/assets/product-open-page-B2T48Sbt.js +1 -0
  63. package/dist/gateway/static/root/assets/project-detail-page-BvEcriRC.js +1 -0
  64. package/dist/gateway/static/root/assets/projects-page-B_e79MRJ.js +1 -0
  65. package/dist/gateway/static/root/assets/remote-access-hub-DGcqnYfR.js +1 -0
  66. package/dist/gateway/static/root/assets/{save-bar-controls-DwrD7ODx.js → save-bar-controls-CkeKasGm.js} +1 -1
  67. package/dist/gateway/static/root/assets/{schedule-field-Ba4WzTmE.js → schedule-field-TkqUL3wm.js} +1 -1
  68. package/dist/gateway/static/root/assets/{schema-form-DvydL8eF.js → schema-form-DC-iU5IG.js} +1 -1
  69. package/dist/gateway/static/root/assets/sessions-page-DQZhrDJ8.js +1 -0
  70. package/dist/gateway/static/root/assets/settings-advanced-gate-BkdeN99Y.js +1 -0
  71. package/dist/gateway/static/root/assets/{settings-collapsible-section-LaQqGGej.js → settings-collapsible-section-Dpqth3oA.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-form-section-DruI__qO.js → settings-form-section-CNqF6IwY.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-loading-skeleton-UvA-eDhF.js → settings-loading-skeleton-DkvwitK_.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-page-layout-DG-XMIPu.js → settings-page-layout-DWvNgISx.js} +1 -1
  75. package/dist/gateway/static/root/assets/{settings-page-5oCGSebm.js → settings-page-qPG7I2zd.js} +1 -1
  76. package/dist/gateway/static/root/assets/setup-status-panel-lwRAh9aw.js +1 -0
  77. package/dist/gateway/static/root/assets/{share-preview-page-FLVeTrRt.js → share-preview-page-DGpSPW-n.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-BGj9IVUr.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-B2UBAs5U.js +1 -0
  80. package/dist/gateway/static/root/assets/skills-page-DdjzFZ8I.js +2 -0
  81. package/dist/gateway/static/root/assets/{system-settings-panel-CeK93xVi.js → system-settings-panel-8TxxSbUw.js} +1 -1
  82. package/dist/gateway/static/root/assets/{theme-store-C8ohIHhw.js → theme-store-B5FzMWOx.js} +1 -1
  83. package/dist/gateway/static/root/assets/{typed-models-lib-D1Lr2gG0.js → typed-models-lib-DEGtSA5h.js} +1 -1
  84. package/dist/gateway/static/root/assets/{use-channel-catalog-BWzou5ar.js → use-channel-catalog-BDU6FneG.js} +1 -1
  85. package/dist/gateway/static/root/assets/user-context-page-BTTZpAGV.js +1 -0
  86. package/dist/gateway/static/root/assets/voice-api-key-field-DuDQd-WU.js +1 -0
  87. package/dist/gateway/static/root/assets/work-discovery-page-BUVkVCsW.js +1 -0
  88. package/dist/gateway/static/root/assets/work-item-detail-page-DeEPPu4n.js +1 -0
  89. package/dist/gateway/static/root/assets/work-page-DQNUyTUq.js +1 -0
  90. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Bynqe4kV.js → workflow-run-setup-panel-Cwi8Pz7n.js} +2 -2
  91. package/dist/gateway/static/root/assets/workflows-page-BIy4wrzO.js +11 -0
  92. package/dist/gateway/static/root/index.html +12 -10
  93. package/dist/package.js +1 -1
  94. package/dist/src/automations/service/action-executor.js +1 -1
  95. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  96. package/dist/src/config/agent-profile.js +1 -1
  97. package/dist/src/gateway/agents-admin.js +1 -1
  98. package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
  99. package/dist/src/gateway/chat-stream/mapper.js +43 -7
  100. package/dist/src/gateway/hono/routes/home.js +15 -2
  101. package/dist/src/gateway/hono/routes/work-discovery.js +451 -0
  102. package/dist/src/gateway/hono/sse.d.ts +2 -0
  103. package/dist/src/gateway/hono/sse.js +10 -3
  104. package/dist/src/gateway/run-loop.js +17 -7
  105. package/dist/src/gateway/server.d.ts +1 -0
  106. package/dist/src/gateway/server.js +9 -0
  107. package/dist/src/gateway/service.d.ts +2 -0
  108. package/dist/src/gateway/service.js +27 -2
  109. package/dist/src/local-apps/preview-runtime-bridge.d.ts +1 -1
  110. package/dist/src/local-apps/preview-runtime-bridge.js +14 -11
  111. package/dist/src/mobile/notification-service.js +1 -0
  112. package/dist/src/pets/factory.js +23 -26
  113. package/dist/src/pets/manifest.d.ts +2 -1
  114. package/dist/src/pets/manifest.js +15 -8
  115. package/dist/src/pets/validator.js +8 -3
  116. package/dist/src/proactive/calendar-signals.d.ts +4 -0
  117. package/dist/src/proactive/calendar-signals.js +120 -0
  118. package/dist/src/proactive/focus-service.d.ts +62 -0
  119. package/dist/src/proactive/focus-service.js +173 -0
  120. package/dist/src/proactive/index.d.ts +7 -0
  121. package/dist/src/proactive/index.js +7 -0
  122. package/dist/src/proactive/insight-repository.d.ts +19 -0
  123. package/dist/src/proactive/insight-repository.js +106 -0
  124. package/dist/src/proactive/run-processor.d.ts +19 -0
  125. package/dist/src/proactive/run-processor.js +125 -0
  126. package/dist/src/proactive/trial-expiry-reconciler.d.ts +5 -0
  127. package/dist/src/proactive/trial-expiry-reconciler.js +30 -0
  128. package/dist/src/proactive/types.d.ts +64 -0
  129. package/dist/src/proactive/types.js +1 -0
  130. package/dist/src/proactive/watch-repository.d.ts +28 -0
  131. package/dist/src/proactive/watch-repository.js +129 -0
  132. package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
  133. package/dist/src/storage/sqlite/knowledge-repository.js +4 -0
  134. package/dist/src/storage/sqlite/migrations/047_work_discovery_sources.sql +16 -0
  135. package/dist/src/storage/sqlite/migrations/048_work_understanding_investigations.sql +40 -0
  136. package/dist/src/storage/sqlite/migrations/049_work_understanding_threads.sql +52 -0
  137. package/dist/src/storage/sqlite/migrations/050_work_discovery_source_refreshes.sql +15 -0
  138. package/dist/src/storage/sqlite/migrations/051_focus_watches.sql +26 -0
  139. package/dist/src/storage/sqlite/migrations/052_proactive_insights.sql +25 -0
  140. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  141. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  142. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  143. package/dist/src/storage/sqlite/schema.js +1 -1
  144. package/dist/src/work-discovery/analyzer.d.ts +12 -1
  145. package/dist/src/work-discovery/analyzer.js +126 -7
  146. package/dist/src/work-discovery/candidate-discovery.d.ts +17 -0
  147. package/dist/src/work-discovery/candidate-discovery.js +279 -0
  148. package/dist/src/work-discovery/evaluation.d.ts +11 -0
  149. package/dist/src/work-discovery/evaluation.js +17 -0
  150. package/dist/src/work-discovery/governance.d.ts +25 -0
  151. package/dist/src/work-discovery/governance.js +96 -0
  152. package/dist/src/work-discovery/incremental-repository.d.ts +13 -0
  153. package/dist/src/work-discovery/incremental-repository.js +55 -0
  154. package/dist/src/work-discovery/incremental.d.ts +2 -0
  155. package/dist/src/work-discovery/incremental.js +7 -0
  156. package/dist/src/work-discovery/index.d.ts +10 -0
  157. package/dist/src/work-discovery/index.js +13 -3
  158. package/dist/src/work-discovery/investigation-repository.d.ts +16 -0
  159. package/dist/src/work-discovery/investigation-repository.js +122 -0
  160. package/dist/src/work-discovery/investigator.d.ts +55 -0
  161. package/dist/src/work-discovery/investigator.js +358 -0
  162. package/dist/src/work-discovery/probe.d.ts +22 -0
  163. package/dist/src/work-discovery/probe.js +88 -1
  164. package/dist/src/work-discovery/service.d.ts +110 -1
  165. package/dist/src/work-discovery/service.js +578 -8
  166. package/dist/src/work-discovery/source-repository.d.ts +13 -0
  167. package/dist/src/work-discovery/source-repository.js +72 -0
  168. package/dist/src/work-discovery/thread-repository.d.ts +34 -0
  169. package/dist/src/work-discovery/thread-repository.js +112 -0
  170. package/dist/src/work-discovery/thread-service.d.ts +8 -0
  171. package/dist/src/work-discovery/thread-service.js +104 -0
  172. package/dist/src/work-discovery/types.d.ts +145 -0
  173. package/package.json +1 -1
  174. package/skills/creative/hatch-pet/SKILL.md +2 -2
  175. package/dist/gateway/static/root/assets/activity-store-C-57rvkX.js +0 -1
  176. package/dist/gateway/static/root/assets/agents-P05C4A-3.js +0 -2
  177. package/dist/gateway/static/root/assets/apps-page-DANGrBpN.js +0 -1
  178. package/dist/gateway/static/root/assets/automations-page-BXfGL_cm.js +0 -6
  179. package/dist/gateway/static/root/assets/browser-settings-page-534luV0B.js +0 -8
  180. package/dist/gateway/static/root/assets/channels-settings-M91zFJVi.js +0 -1
  181. package/dist/gateway/static/root/assets/channels-status-swr-vooEF4lG.js +0 -1
  182. package/dist/gateway/static/root/assets/check-BODqo66o.js +0 -1
  183. package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +0 -1
  184. package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +0 -1
  185. package/dist/gateway/static/root/assets/connectors-page-CV5UulW6.js +0 -2
  186. package/dist/gateway/static/root/assets/desktop-pet-Cil2eSpW.js +0 -1
  187. package/dist/gateway/static/root/assets/desktop-pet-settings-DwsC6l5F.js +0 -1
  188. package/dist/gateway/static/root/assets/desktop-pet-sprite-DqZ6fbIj.js +0 -1
  189. package/dist/gateway/static/root/assets/gateway-settings-BpJ0v56l.js +0 -1
  190. package/dist/gateway/static/root/assets/goal-create-dialog-lMHD-2CX.js +0 -1
  191. package/dist/gateway/static/root/assets/goal-detail-page-yPmF-G7b.js +0 -4
  192. package/dist/gateway/static/root/assets/goals-page-BHTCKobG.js +0 -2
  193. package/dist/gateway/static/root/assets/index-BgZhEOkN.css +0 -1
  194. package/dist/gateway/static/root/assets/index-BuqGh2SW.js +0 -193
  195. package/dist/gateway/static/root/assets/local-app-workbench-page-zpp_wciE.js +0 -2
  196. package/dist/gateway/static/root/assets/logs-page-B4CRYqYR.js +0 -7
  197. package/dist/gateway/static/root/assets/messages-BuT0SR1R.js +0 -5
  198. package/dist/gateway/static/root/assets/models-hub-panel-1hdoAoB_.js +0 -2
  199. package/dist/gateway/static/root/assets/notes-workbench-DQEAZTA5.js +0 -4
  200. package/dist/gateway/static/root/assets/project-detail-page-Bp9bC7A6.js +0 -1
  201. package/dist/gateway/static/root/assets/projects-page-RNorFXTw.js +0 -1
  202. package/dist/gateway/static/root/assets/remote-access-hub-BqRTcM_6.js +0 -1
  203. package/dist/gateway/static/root/assets/sessions-page-B2EfW1cm.js +0 -1
  204. package/dist/gateway/static/root/assets/settings-advanced-gate-CklL85T4.js +0 -1
  205. package/dist/gateway/static/root/assets/setup-status-panel-D3my1HgB.js +0 -1
  206. package/dist/gateway/static/root/assets/shares-settings-DVxgjrsP.js +0 -1
  207. package/dist/gateway/static/root/assets/skill-reload-api-Bcu58ZaF.js +0 -1
  208. package/dist/gateway/static/root/assets/skills-page-CDd-84FE.js +0 -2
  209. package/dist/gateway/static/root/assets/sliding-segmented-uWmrxE3P.js +0 -1
  210. package/dist/gateway/static/root/assets/user-context-page-1OyJnTyR.js +0 -1
  211. package/dist/gateway/static/root/assets/voice-api-key-field-B2ncRwHS.js +0 -1
  212. package/dist/gateway/static/root/assets/work-discovery-page-BZlY4PZL.js +0 -1
  213. package/dist/gateway/static/root/assets/work-item-detail-page-DPXMrneY.js +0 -1
  214. package/dist/gateway/static/root/assets/work-page-CTERoqyv.js +0 -1
  215. package/dist/gateway/static/root/assets/workflows-page-CLgsnqFQ.js +0 -11
@@ -1,6 +1,10 @@
1
1
  import { getAgentDefaultModelRef, init_schema } from "../../../config/schema.js";
2
2
  import { init_providers, resolveModel } from "../../../providers/index.js";
3
3
  import { isLocalModelBaseUrl } from "../../../providers/model-call.js";
4
+ import { listFocusCalendarSignals } from "../../../proactive/calendar-signals.js";
5
+ import { FocusService } from "../../../proactive/focus-service.js";
6
+ import { claimProactiveInsightApproval, getProactiveInsight, setProactiveInsightStatus } from "../../../proactive/insight-repository.js";
7
+ import "../../../proactive/index.js";
4
8
  import { previewWorkDiscoveryRoot } from "../../../work-discovery/probe.js";
5
9
  import { WorkDiscoveryService } from "../../../work-discovery/service.js";
6
10
  //#region src/gateway/hono/routes/work-discovery.ts
@@ -26,6 +30,7 @@ function stringField(body, field) {
26
30
  }
27
31
  function registerWorkDiscoveryRoutes(authenticated, deps) {
28
32
  const service = workDiscoveryService(deps);
33
+ const focuses = new FocusService(deps.service.automationServiceInstance);
29
34
  const limited = deps.strictRateLimitMiddleware;
30
35
  authenticated.get("/api/onboarding/work-discovery", (c) => c.json({
31
36
  enabled: service.isEnabled(),
@@ -77,6 +82,178 @@ function registerWorkDiscoveryRoutes(authenticated, deps) {
77
82
  }, 400);
78
83
  }
79
84
  });
85
+ authenticated.post("/api/work-discovery/candidates", limited, async (c) => {
86
+ if (!service.isEnabled()) return c.json({
87
+ ok: false,
88
+ error: "Work discovery is disabled"
89
+ }, 404);
90
+ try {
91
+ const candidates = await service.discoverCandidates(c.req.raw.signal);
92
+ return c.json({
93
+ ok: true,
94
+ candidates
95
+ });
96
+ } catch (error) {
97
+ return c.json({
98
+ ok: false,
99
+ error: error instanceof Error ? error.message : String(error)
100
+ }, 500);
101
+ }
102
+ });
103
+ authenticated.get("/api/work-discovery/sources/directories", (c) => c.json({
104
+ ok: true,
105
+ sources: service.listDirectorySources()
106
+ }));
107
+ authenticated.post("/api/work-discovery/sources/directories", limited, async (c) => {
108
+ const rootPath = stringField(await c.req.json().catch(() => null), "rootPath");
109
+ if (!rootPath) return c.json({
110
+ ok: false,
111
+ error: "Missing rootPath"
112
+ }, 400);
113
+ try {
114
+ const source = await service.grantDirectorySource(rootPath);
115
+ return c.json({
116
+ ok: true,
117
+ source
118
+ }, 201);
119
+ } catch (error) {
120
+ return c.json({
121
+ ok: false,
122
+ error: error instanceof Error ? error.message : String(error)
123
+ }, 400);
124
+ }
125
+ });
126
+ authenticated.delete("/api/work-discovery/sources/directories/:sourceId", limited, (c) => {
127
+ const source = service.revokeDirectorySource(c.req.param("sourceId"));
128
+ return source ? c.json({
129
+ ok: true,
130
+ source
131
+ }) : c.json({
132
+ ok: false,
133
+ error: "Source not found"
134
+ }, 404);
135
+ });
136
+ authenticated.post("/api/work-discovery/sources/directories/:sourceId/runs", limited, async (c) => {
137
+ const idempotencyKey = stringField(await c.req.json().catch(() => null), "idempotencyKey");
138
+ if (!idempotencyKey) return c.json({
139
+ ok: false,
140
+ error: "Missing idempotencyKey"
141
+ }, 400);
142
+ try {
143
+ const run = await service.rescanDirectorySource({
144
+ id: c.req.param("sourceId"),
145
+ idempotencyKey
146
+ });
147
+ return c.json({
148
+ ok: true,
149
+ run
150
+ }, 202);
151
+ } catch (error) {
152
+ return c.json({
153
+ ok: false,
154
+ error: error instanceof Error ? error.message : String(error)
155
+ }, 400);
156
+ }
157
+ });
158
+ authenticated.post("/api/work-discovery/sources/directories/check", limited, async (c) => {
159
+ return c.json({
160
+ ok: true,
161
+ checks: await service.checkDirectorySources()
162
+ });
163
+ });
164
+ authenticated.post("/api/work-discovery/sources/directories/:sourceId/refresh-if-changed", limited, async (c) => {
165
+ const idempotencyKey = stringField(await c.req.json().catch(() => null), "idempotencyKey");
166
+ if (!idempotencyKey) return c.json({
167
+ ok: false,
168
+ error: "Missing idempotencyKey"
169
+ }, 400);
170
+ try {
171
+ const result = await service.refreshDirectorySourceIfChanged({
172
+ id: c.req.param("sourceId"),
173
+ idempotencyKey
174
+ });
175
+ return c.json({
176
+ ok: true,
177
+ ...result
178
+ }, result.changed ? 202 : 200);
179
+ } catch (error) {
180
+ return c.json({
181
+ ok: false,
182
+ error: error instanceof Error ? error.message : String(error)
183
+ }, 400);
184
+ }
185
+ });
186
+ authenticated.post("/api/work-discovery/personal-context/import", limited, async (c) => {
187
+ if (!service.isEnabled()) return c.json({
188
+ ok: false,
189
+ error: "Work discovery is disabled"
190
+ }, 404);
191
+ const body = await c.req.json().catch(() => null);
192
+ const items = body && typeof body === "object" && Array.isArray(body.items) ? body.items.slice(0, 150) : [];
193
+ const runId = stringField(body, "runId");
194
+ if (!items.length) return c.json({
195
+ ok: false,
196
+ error: "No personal context was provided"
197
+ }, 400);
198
+ try {
199
+ const result = await service.importPersonalContext(items, c.req.raw.signal, runId || void 0);
200
+ return c.json({
201
+ ok: true,
202
+ ...result
203
+ }, 201);
204
+ } catch (error) {
205
+ return c.json({
206
+ ok: false,
207
+ error: error instanceof Error ? error.message : String(error)
208
+ }, 400);
209
+ }
210
+ });
211
+ authenticated.post("/api/work-discovery/personal-context/profile", limited, async (c) => {
212
+ const body = await c.req.json().catch(() => null);
213
+ const decisions = (body && typeof body === "object" && Array.isArray(body.decisions) ? body.decisions : []).flatMap((value) => {
214
+ if (!value || typeof value !== "object") return [];
215
+ const item = value;
216
+ const memoryRecordId = typeof item.memoryRecordId === "string" ? item.memoryRecordId.trim() : "";
217
+ const status = item.status === "accepted" || item.status === "edited" || item.status === "rejected" ? item.status : void 0;
218
+ if (!memoryRecordId || !status) return [];
219
+ return [{
220
+ memoryRecordId,
221
+ status,
222
+ ...typeof item.statement === "string" ? { statement: item.statement } : {}
223
+ }];
224
+ }).slice(0, 10);
225
+ if (!decisions.length) return c.json({
226
+ ok: false,
227
+ error: "At least one valid decision is required"
228
+ }, 400);
229
+ return c.json({
230
+ ok: true,
231
+ decisions: service.updatePersonalContextProfile({ decisions })
232
+ });
233
+ });
234
+ authenticated.post("/api/work-discovery/quick-runs", limited, async (c) => {
235
+ if (!service.isEnabled()) return c.json({
236
+ ok: false,
237
+ error: "Work discovery is disabled"
238
+ }, 404);
239
+ const idempotencyKey = stringField(await c.req.json().catch(() => null), "idempotencyKey");
240
+ if (!idempotencyKey) return c.json({
241
+ ok: false,
242
+ error: "Missing idempotencyKey"
243
+ }, 400);
244
+ try {
245
+ const run = await service.startQuickRun({ idempotencyKey });
246
+ return c.json({
247
+ ok: true,
248
+ run
249
+ }, 202);
250
+ } catch (error) {
251
+ return c.json({
252
+ ok: false,
253
+ error: error instanceof Error ? error.message : String(error)
254
+ }, 400);
255
+ }
256
+ });
80
257
  authenticated.post("/api/work-discovery/runs", limited, async (c) => {
81
258
  if (!service.isEnabled()) return c.json({
82
259
  ok: false,
@@ -117,6 +294,250 @@ function registerWorkDiscoveryRoutes(authenticated, deps) {
117
294
  error: "Run not found"
118
295
  }, 404);
119
296
  });
297
+ authenticated.get("/api/work-discovery/runs/:runId/investigation", (c) => {
298
+ const result = service.getInvestigation(c.req.param("runId"));
299
+ return result ? c.json({
300
+ ok: true,
301
+ ...result
302
+ }) : c.json({
303
+ ok: false,
304
+ error: "Investigation not found"
305
+ }, 404);
306
+ });
307
+ authenticated.get("/api/work-understanding/threads", (c) => {
308
+ const projectId = c.req.query("projectId")?.trim();
309
+ const limit = Number(c.req.query("limit"));
310
+ return c.json({
311
+ ok: true,
312
+ threads: service.listWorkThreads({
313
+ ...projectId ? { projectId } : {},
314
+ ...Number.isFinite(limit) ? { limit } : {}
315
+ })
316
+ });
317
+ });
318
+ authenticated.get("/api/work-understanding/metrics", (c) => c.json({
319
+ ok: true,
320
+ metrics: service.getUnderstandingMetrics()
321
+ }));
322
+ authenticated.get("/api/work-understanding/sources/:sourceId/lineage", (c) => {
323
+ const lineage = service.getSourceLineage(c.req.param("sourceId"));
324
+ return lineage ? c.json({
325
+ ok: true,
326
+ lineage
327
+ }) : c.json({
328
+ ok: false,
329
+ error: "Source not found"
330
+ }, 404);
331
+ });
332
+ authenticated.delete("/api/work-understanding/sources/:sourceId/derived-data", limited, (c) => {
333
+ const deleted = service.deleteSourceDerivedData(c.req.param("sourceId"));
334
+ return deleted ? c.json({
335
+ ok: true,
336
+ deleted
337
+ }) : c.json({
338
+ ok: false,
339
+ error: "Source not found"
340
+ }, 404);
341
+ });
342
+ authenticated.get("/api/work-understanding/threads/:threadId", (c) => {
343
+ const thread = service.getWorkThread(c.req.param("threadId"));
344
+ return thread ? c.json({
345
+ ok: true,
346
+ thread
347
+ }) : c.json({
348
+ ok: false,
349
+ error: "Work thread not found"
350
+ }, 404);
351
+ });
352
+ authenticated.patch("/api/work-understanding/threads/:threadId", limited, async (c) => {
353
+ const body = await c.req.json().catch(() => null);
354
+ const decision = stringField(body, "decision");
355
+ if (![
356
+ "confirmed",
357
+ "corrected",
358
+ "rejected",
359
+ "paused",
360
+ "completed"
361
+ ].includes(decision)) return c.json({
362
+ ok: false,
363
+ error: "Invalid work thread decision"
364
+ }, 400);
365
+ const thread = service.updateWorkThread({
366
+ id: c.req.param("threadId"),
367
+ decision,
368
+ ...stringField(body, "correctedTitle") ? { correctedTitle: stringField(body, "correctedTitle") } : {},
369
+ ...stringField(body, "correctedSummary") ? { correctedSummary: stringField(body, "correctedSummary") } : {}
370
+ });
371
+ return thread ? c.json({
372
+ ok: true,
373
+ thread
374
+ }) : c.json({
375
+ ok: false,
376
+ error: "Work thread not found"
377
+ }, 404);
378
+ });
379
+ authenticated.get("/api/focuses", (c) => {
380
+ return c.json({
381
+ ok: true,
382
+ focuses: focuses.list({ includeUnreviewed: c.req.query("includeUnreviewed") === "true" })
383
+ });
384
+ });
385
+ authenticated.post("/api/focuses/:focusId/confirm", limited, (c) => {
386
+ const focus = focuses.confirm(c.req.param("focusId"));
387
+ return focus ? c.json({
388
+ ok: true,
389
+ focus
390
+ }) : c.json({
391
+ ok: false,
392
+ error: "Focus not found"
393
+ }, 404);
394
+ });
395
+ authenticated.post("/api/focuses/:focusId/watches/trial", limited, async (c) => {
396
+ const requestedKind = stringField(await c.req.json().catch(() => null), "kind");
397
+ const kind = [
398
+ "progress",
399
+ "staleness",
400
+ "deadline",
401
+ "intelligence"
402
+ ].includes(requestedKind) ? requestedKind : void 0;
403
+ try {
404
+ const result = await focuses.activateTrial({
405
+ threadId: c.req.param("focusId"),
406
+ ...kind ? { kind } : {}
407
+ });
408
+ return c.json({
409
+ ok: true,
410
+ ...result
411
+ }, 201);
412
+ } catch (error) {
413
+ return c.json({
414
+ ok: false,
415
+ error: error instanceof Error ? error.message : String(error)
416
+ }, 400);
417
+ }
418
+ });
419
+ authenticated.post("/api/focuses/:focusId/watches/:watchId/pause", limited, async (c) => {
420
+ const watch = focuses.list({ includeUnreviewed: true }).find((item) => item.id === c.req.param("focusId"))?.watches.find((item) => item.id === c.req.param("watchId"));
421
+ if (!watch) return c.json({
422
+ ok: false,
423
+ error: "Watch not found"
424
+ }, 404);
425
+ const paused = await focuses.pauseWatch(watch.id);
426
+ return c.json({
427
+ ok: true,
428
+ watch: paused
429
+ });
430
+ });
431
+ authenticated.patch("/api/proactive/insights/:insightId", limited, async (c) => {
432
+ const requested = stringField(await c.req.json().catch(() => null), "status");
433
+ const status = requested === "read" || requested === "dismissed" ? requested : void 0;
434
+ if (!status) return c.json({
435
+ ok: false,
436
+ error: "Status must be read or dismissed"
437
+ }, 400);
438
+ const insight = setProactiveInsightStatus(c.req.param("insightId"), status, Date.now(), "unread");
439
+ if (!insight) return c.json({
440
+ ok: false,
441
+ error: "Insight was already handled or not found"
442
+ }, 409);
443
+ if (status === "dismissed") await focuses.recordInsightFeedback(insight.watchId, false);
444
+ return c.json({
445
+ ok: true,
446
+ insight
447
+ });
448
+ });
449
+ authenticated.post("/api/proactive/insights/:insightId/approve", limited, async (c) => {
450
+ const insight = getProactiveInsight(c.req.param("insightId"));
451
+ if (!insight) return c.json({
452
+ ok: false,
453
+ error: "Insight not found"
454
+ }, 404);
455
+ if (insight.status !== "unread") return c.json({
456
+ ok: false,
457
+ error: `Insight is ${insight.status}`
458
+ }, 409);
459
+ const focus = focuses.list({ includeUnreviewed: true }).find((item) => item.watches.some((watch) => watch.id === insight.watchId));
460
+ if (!focus) return c.json({
461
+ ok: false,
462
+ error: "Focus not found"
463
+ }, 404);
464
+ if (!claimProactiveInsightApproval(insight.id)) return c.json({
465
+ ok: false,
466
+ error: "Insight was already handled"
467
+ }, 409);
468
+ let automationId;
469
+ try {
470
+ const automation = await deps.service.automationServiceInstance.create({
471
+ name: `Investigate: ${insight.title}`.slice(0, 200),
472
+ description: `User-approved read-only proposal from proactive insight ${insight.id}.`,
473
+ ...focus.projectIds[0] ? { projectId: focus.projectIds[0] } : {},
474
+ trigger: { kind: "manual" },
475
+ action: {
476
+ kind: "agent",
477
+ instruction: [
478
+ "The user approved this evidence-backed proposal for read-only investigation and preparation.",
479
+ `Focus: ${focus.title}`,
480
+ `Observed change: ${insight.summary}`,
481
+ `Why it matters: ${insight.whyItMatters}`,
482
+ `Approved next step: ${insight.nextAction}`,
483
+ `Evidence: ${JSON.stringify(insight.evidence)}`,
484
+ "Investigate or prepare the requested material. Return a concise result with evidence. Do not modify files or external systems."
485
+ ].join("\n"),
486
+ timeoutSeconds: 300
487
+ },
488
+ safety: { mode: "suggest_only" },
489
+ afterRun: { kind: "none" },
490
+ reliability: {
491
+ timeoutSeconds: 300,
492
+ disableAfterConsecutiveFailures: 1
493
+ }
494
+ });
495
+ automationId = automation.id;
496
+ const run = await deps.service.automationServiceInstance.runNow(automation.id);
497
+ await focuses.recordInsightFeedback(insight.watchId, true);
498
+ return c.json({
499
+ ok: true,
500
+ automationId: automation.id,
501
+ runId: run.id
502
+ }, 202);
503
+ } catch (error) {
504
+ if (automationId) await deps.service.automationServiceInstance.remove(automationId);
505
+ setProactiveInsightStatus(insight.id, "unread", Date.now(), "approved");
506
+ return c.json({
507
+ ok: false,
508
+ error: error instanceof Error ? error.message : String(error)
509
+ }, 500);
510
+ }
511
+ });
512
+ authenticated.post("/api/focuses/:focusId/calendar/:signalId/prepare", limited, async (c) => {
513
+ const focus = focuses.list().find((item) => item.id === c.req.param("focusId"));
514
+ if (!focus) return c.json({
515
+ ok: false,
516
+ error: "Focus not found"
517
+ }, 404);
518
+ const signal = listFocusCalendarSignals([focus]).find((item) => item.id === c.req.param("signalId"));
519
+ if (!signal) return c.json({
520
+ ok: false,
521
+ error: "Calendar event not found"
522
+ }, 404);
523
+ const eventContext = `${signal.title} at ${new Date(signal.startsAt).toISOString()}`;
524
+ try {
525
+ const result = await focuses.activateTrial({
526
+ threadId: focus.id,
527
+ kind: "deadline",
528
+ eventContext
529
+ });
530
+ return c.json({
531
+ ok: true,
532
+ ...result
533
+ });
534
+ } catch (error) {
535
+ return c.json({
536
+ ok: false,
537
+ error: error instanceof Error ? error.message : String(error)
538
+ }, 500);
539
+ }
540
+ });
120
541
  authenticated.post("/api/work-discovery/runs/:runId/cancel", (c) => {
121
542
  const run = service.cancelRun(c.req.param("runId"));
122
543
  return run ? c.json({
@@ -169,6 +590,36 @@ function registerWorkDiscoveryRoutes(authenticated, deps) {
169
590
  }, 400);
170
591
  }
171
592
  });
593
+ authenticated.post("/api/work-discovery/runs/:runId/profile", limited, async (c) => {
594
+ const body = await c.req.json().catch(() => null);
595
+ const decisions = (body && typeof body === "object" && Array.isArray(body.decisions) ? body.decisions : []).flatMap((value) => {
596
+ if (!value || typeof value !== "object") return [];
597
+ const item = value;
598
+ const id = typeof item.id === "string" ? item.id.trim() : "";
599
+ const status = item.status === "accepted" || item.status === "edited" || item.status === "rejected" ? item.status : void 0;
600
+ if (!id || !status) return [];
601
+ return [{
602
+ id,
603
+ status,
604
+ ...typeof item.statement === "string" ? { statement: item.statement } : {}
605
+ }];
606
+ }).slice(0, 10);
607
+ if (!decisions.length) return c.json({
608
+ ok: false,
609
+ error: "At least one valid decision is required"
610
+ }, 400);
611
+ const run = service.updateProfileCandidates({
612
+ runId: c.req.param("runId"),
613
+ decisions
614
+ });
615
+ return run ? c.json({
616
+ ok: true,
617
+ run
618
+ }) : c.json({
619
+ ok: false,
620
+ error: "Profile candidates not found"
621
+ }, 404);
622
+ });
172
623
  authenticated.post("/api/work-discovery/runs/:runId/suggestions/:suggestionId/select", (c) => {
173
624
  return service.selectSuggestion(c.req.param("runId"), c.req.param("suggestionId")) ? c.json({ ok: true }) : c.json({
174
625
  ok: false,
@@ -1,5 +1,7 @@
1
1
  import type { Context } from 'hono';
2
2
  import type { GatewayService } from '../service.js';
3
+ /** Close long-lived gateway event streams before the HTTP server starts draining. */
4
+ export declare function closeAllEventStreams(): void;
3
5
  export interface SSEHandlerConfig {
4
6
  service: GatewayService;
5
7
  maxSseConnections?: number;
@@ -9,6 +9,10 @@ import { streamSSE } from "hono/streaming";
9
9
  init_logger();
10
10
  const log = createLogger("Gateway:SSE");
11
11
  const activeConnections = /* @__PURE__ */ new Map();
12
+ /** Close long-lived gateway event streams before the HTTP server starts draining. */
13
+ function closeAllEventStreams() {
14
+ for (const controller of activeConnections.values()) controller.abort();
15
+ }
12
16
  function isValidAgentRequest(body) {
13
17
  if (!body || typeof body !== "object") return false;
14
18
  const b = body;
@@ -341,17 +345,20 @@ function createEventsSSEHandler(config) {
341
345
  }
342
346
  }, 3e4);
343
347
  await new Promise((resolve) => {
344
- stream.onAbort(() => {
348
+ const finish = () => {
345
349
  aborted = true;
346
350
  clearInterval(keepAlive);
347
351
  cleanup();
348
352
  activeConnections.delete(sessionId);
349
353
  log.debug({ sessionId }, "Event stream disconnected");
350
354
  resolve();
351
- });
355
+ };
356
+ stream.onAbort(finish);
357
+ abortController.signal.addEventListener("abort", () => stream.abort(), { once: true });
358
+ if (abortController.signal.aborted) stream.abort();
352
359
  });
353
360
  });
354
361
  };
355
362
  }
356
363
  //#endregion
357
- export { createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
364
+ export { closeAllEventStreams, createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
@@ -15,7 +15,8 @@ async function runGatewayLoop(opts) {
15
15
  let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });
16
16
  let server = null;
17
17
  let shuttingDown = false;
18
- let restartResolver = null;
18
+ let forceCloseRequested = false;
19
+ let loopResolver = null;
19
20
  const cleanupSignals = () => {
20
21
  process.removeListener("SIGTERM", onSigterm);
21
22
  process.removeListener("SIGINT", onSigint);
@@ -51,20 +52,27 @@ async function runGatewayLoop(opts) {
51
52
  return;
52
53
  }
53
54
  shuttingDown = false;
54
- restartResolver?.();
55
+ forceCloseRequested = false;
56
+ loopResolver?.("restart");
55
57
  };
56
58
  const handleStopAfterClose = async () => {
57
59
  await releaseLock();
58
- exitProcess(0);
60
+ loopResolver?.("stop");
59
61
  };
60
62
  const DRAIN_TIMEOUT_MS = 3e4;
61
63
  const SHUTDOWN_TIMEOUT_MS = 15e3;
62
64
  const requestShutdown = (action, signal) => {
63
- if (shuttingDown) return;
65
+ if (shuttingDown) {
66
+ if (!forceCloseRequested && (signal === "SIGINT" || signal === "SIGTERM")) {
67
+ forceCloseRequested = true;
68
+ console.warn(`[GatewayRunLoop] Received ${signal} again; force closing connections`);
69
+ server?.forceCloseConnections();
70
+ }
71
+ return;
72
+ }
64
73
  shuttingDown = true;
65
74
  const isRestart = action === "restart";
66
75
  console.log(`[GatewayRunLoop] Received ${signal}; ${isRestart ? "restarting" : "shutting down"}`);
67
- cleanupSignals();
68
76
  const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;
69
77
  const forceExitTimer = setTimeout(() => {
70
78
  console.error("[GatewayRunLoop] Shutdown timed out; force exiting");
@@ -129,9 +137,11 @@ async function runGatewayLoop(opts) {
129
137
  exitProcess(1);
130
138
  return;
131
139
  }
132
- await new Promise((resolve) => {
133
- restartResolver = resolve;
140
+ const action = await new Promise((resolve) => {
141
+ loopResolver = resolve;
134
142
  });
143
+ loopResolver = null;
144
+ if (action === "stop") return;
135
145
  console.log("[GatewayRunLoop] Restart signal received, restarting gateway...");
136
146
  }
137
147
  } finally {
@@ -23,6 +23,7 @@ export declare class GatewayServer {
23
23
  restartExpectedMs?: number | null;
24
24
  }): Promise<void>;
25
25
  stop(): Promise<void>;
26
+ forceCloseConnections(): void;
26
27
  get isRunning(): boolean;
27
28
  get serviceInstance(): GatewayService;
28
29
  }
@@ -2,6 +2,7 @@ import { resolveGatewayBindHost, resolveGatewayListenHosts } from "../config/gat
2
2
  import { ensureXopcCliOnPath } from "../infra/path-env.js";
3
3
  import { resolveGatewayListenPlan } from "./listen.js";
4
4
  import { GatewayService } from "./service.js";
5
+ import { closeAllEventStreams } from "./hono/sse.js";
5
6
  import { handleSiteShareUpgrade } from "../share/site-share-router.js";
6
7
  import { createHonoApp } from "./hono/app.js";
7
8
  import { serve } from "@hono/node-server";
@@ -94,6 +95,7 @@ var GatewayServer = class {
94
95
  }
95
96
  async stop() {
96
97
  console.log("[GatewayServer] Stopping gateway server...");
98
+ closeAllEventStreams();
97
99
  const closeServer = async (server) => {
98
100
  if (!server) return;
99
101
  const forceClose = setTimeout(() => {
@@ -113,6 +115,13 @@ var GatewayServer = class {
113
115
  await this.service.stop();
114
116
  console.log("[GatewayServer] Gateway server stopped");
115
117
  }
118
+ forceCloseConnections() {
119
+ const close = (server) => {
120
+ server?.closeAllConnections?.();
121
+ };
122
+ close(this.server);
123
+ for (const extra of this.extraServers) close(extra);
124
+ }
116
125
  get isRunning() {
117
126
  return this.server !== void 0;
118
127
  }
@@ -61,6 +61,7 @@ export declare class GatewayService {
61
61
  private connectedKnowledgeCoordinator;
62
62
  private stopAutomationProductEventBridge;
63
63
  private stopSessionTranscriptAutomationEvents;
64
+ private stopFocusTrialExpiryReconciler;
64
65
  /**
65
66
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
66
67
  * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
@@ -267,6 +268,7 @@ export declare class GatewayService {
267
268
  processDirect(content: string, sessionKey?: string): Promise<string>;
268
269
  subscribe(sessionId: string, listener: (event: ServiceEvent) => Promise<void> | void): () => void;
269
270
  emit(type: string, payload: unknown): void;
271
+ private handleAutomationRunCompleted;
270
272
  private startAutomationProductEventBridge;
271
273
  /** Replay events since `lastEventId` for SSE reconnection. */
272
274
  getEventsSince(sessionId: string, lastEventId: string): ServiceEvent[];