@xopcai/xopc 0.0.172 → 0.0.174

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 (223) 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-C3Y-bESI.js → activity-store-CyEDJeIt.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CPyev9P7.js → agent-avatar-dicebear-DF7Bol6I.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-BVxEFPQ5.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-B7qEr_Rw.js → api-DYunqroX.js} +1 -1
  7. package/dist/gateway/static/root/assets/api-DwyUxpgY.js +1 -0
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-Br_9-7fs.js → app-management-settings-panel-B4xJyvDu.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-uyLcRPai.js → appearance-settings-B2PQxRiu.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-BtIgd82S.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-B19REnR5.js → archive-plugin-DWhBmmjD.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-DLWCC4Yi.js → attachment-load-BOpZfa_I.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automation-suggestion-card-ky5S5lly.js → automation-suggestion-card-Byu3I7Rs.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-CG_SCH5b.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-CtPEzLlo.js → binary-plugins-6AG1qatz.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-CQVR4Xij.js → block-editor-CJhrn98_.js} +5 -5
  17. package/dist/gateway/static/root/assets/browser-settings-page-CfLqPWZC.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CimCGbhq.js → browser-workflow-inputs-CBVb4mt9.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-DewuCw3p.js → browser-workflows-page-Cq4XUKbu.js} +2 -2
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-DCJmm6cR.js +7 -0
  21. package/dist/gateway/static/root/assets/{capability-presets-api-B5RTs-Az.js → capability-presets-api-hbW4NAKO.js} +1 -1
  22. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CnkAYvWI.js +1 -0
  23. package/dist/gateway/static/root/assets/{channel-recipient-api-Czu0YzIZ.js → channel-recipient-api-CzMjHb17.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-settings-DtqqFpDn.js +1 -0
  25. package/dist/gateway/static/root/assets/channels-status-swr-C-5yHbc0.js +1 -0
  26. package/dist/gateway/static/root/assets/{connector-logo-Di3gnR_D.js → connector-logo-B9Au6gMZ.js} +1 -1
  27. package/dist/gateway/static/root/assets/connectors-page-CaHfs8YF.js +2 -0
  28. package/dist/gateway/static/root/assets/copy-VueTIC2x.js +1 -0
  29. package/dist/gateway/static/root/assets/desktop-pet-CvFMKYdb.js +1 -0
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-C3L6AI8_.js → desktop-pet-settings-CNff5TFb.js} +1 -1
  31. package/dist/gateway/static/root/assets/{directory-picker-path-field-Dvq4iG6P.js → directory-picker-path-field-Bf956uo-.js} +1 -1
  32. package/dist/gateway/static/root/assets/dreaming-settings-CHM8FE1g.js +3 -0
  33. package/dist/gateway/static/root/assets/{extension-debug-page-BecQjU0J.js → extension-debug-page-ZqM_0eUs.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-BeVkPSm-.js → extension-page-D4hvXOMM.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-DMoo2mKx.js → extension-settings-page-GsqxaJjA.js} +1 -1
  36. package/dist/gateway/static/root/assets/focus-detail-page-CE6uwrl1.js +1 -0
  37. package/dist/gateway/static/root/assets/{gateway-config-api-Bthb3_6v.js → gateway-config-api-B4THmgnS.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-Bh8nPvJQ.js → gateway-settings-CPv-MxGE.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-D3USVm9D.js → gateway-startup-retry-MP3K71pP.js} +1 -1
  40. package/dist/gateway/static/root/assets/goal-create-dialog-DAeb82xP.js +1 -0
  41. package/dist/gateway/static/root/assets/goal-detail-page-CwLSp01r.js +4 -0
  42. package/dist/gateway/static/root/assets/{goals-config-api-C_2QWBtb.js → goals-config-api-DCcDuIjG.js} +1 -1
  43. package/dist/gateway/static/root/assets/goals-page-DvJQ6_4M.js +2 -0
  44. package/dist/gateway/static/root/assets/{goals-settings-DhL643tc.js → goals-settings-o9QMXvNq.js} +1 -1
  45. package/dist/gateway/static/root/assets/{heartbeat-settings-COVFwp7C.js → heartbeat-settings-DixwpXnH.js} +1 -1
  46. package/dist/gateway/static/root/assets/{image-generation-api-BNQlnwpU.js → image-generation-api-BOGH9FGi.js} +1 -1
  47. package/dist/gateway/static/root/assets/index-CfXiRNN5.css +1 -0
  48. package/dist/gateway/static/root/assets/index-eyttVNS_.js +212 -0
  49. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DfdJRJVy.js → keyboard-shortcuts-settings-D4o4ZPF6.js} +1 -1
  50. package/dist/gateway/static/root/assets/local-app-workbench-page-CPcfqn_A.js +2 -0
  51. package/dist/gateway/static/root/assets/{local-apps-page-BvCPOgoi.js → local-apps-page-GzMmpO7G.js} +1 -1
  52. package/dist/gateway/static/root/assets/{locale-store-BP0vD37A.js → locale-store-CAuhEGCn.js} +1 -1
  53. package/dist/gateway/static/root/assets/logs-page-DXABWCZp.js +7 -0
  54. package/dist/gateway/static/root/assets/{markdown-split-YO1rDk9m.js → markdown-split-CIX8D1pv.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-CU_RRf-q.js → media-plugins-Bp3eIA45.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-BiBdO1-O.js +3 -0
  57. package/dist/gateway/static/root/assets/{notes-page-CeFiOK3S.js → notes-page-RVFiYAoO.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-DgJzZRX3.js +4 -0
  59. package/dist/gateway/static/root/assets/{page-tabs-tiHmRJUA.js → page-tabs-BGAYH3Ef.js} +1 -1
  60. package/dist/gateway/static/root/assets/{preview-open-alternatives-CU6XgaCz.js → preview-open-alternatives-BM6pDkHp.js} +1 -1
  61. package/dist/gateway/static/root/assets/{product-open-page-Dn4_qor4.js → product-open-page-BiMetEmn.js} +1 -1
  62. package/dist/gateway/static/root/assets/project-detail-page-DF7F70Vg.js +1 -0
  63. package/dist/gateway/static/root/assets/projects-page-Cw3jyi5s.js +1 -0
  64. package/dist/gateway/static/root/assets/remote-access-hub-ChAJsaNY.js +1 -0
  65. package/dist/gateway/static/root/assets/{save-bar-controls-edDUIbXo.js → save-bar-controls-BdjV8MK5.js} +1 -1
  66. package/dist/gateway/static/root/assets/{schedule-field-DqJO_5Yb.js → schedule-field-ChlqXU46.js} +1 -1
  67. package/dist/gateway/static/root/assets/{schema-form-CMh0jzy5.js → schema-form-DDKf5ZSH.js} +1 -1
  68. package/dist/gateway/static/root/assets/sessions-page-BxZIxt7z.js +1 -0
  69. package/dist/gateway/static/root/assets/settings-advanced-gate-DcDLS0xV.js +1 -0
  70. package/dist/gateway/static/root/assets/{settings-form-section-Bb0Bc3nJ.js → settings-form-section-CPG0KGVs.js} +1 -1
  71. package/dist/gateway/static/root/assets/{settings-loading-skeleton-DQhADvz1.js → settings-loading-skeleton-DRSDHucM.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-page-b0M5HukN.js → settings-page-CeB7_xD0.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-page-layout-hvjtIjvh.js → settings-page-layout-BENrkwd0.js} +1 -1
  74. package/dist/gateway/static/root/assets/setup-status-panel-4Xa9NA7v.js +1 -0
  75. package/dist/gateway/static/root/assets/{share-preview-page-rbeaOpTg.js → share-preview-page-DIzczJkG.js} +1 -1
  76. package/dist/gateway/static/root/assets/shares-settings-BpN0o5Cf.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-DvF2UAaL.js +1 -0
  78. package/dist/gateway/static/root/assets/skills-page-CGKXpNfy.js +2 -0
  79. package/dist/gateway/static/root/assets/{system-settings-panel-BHo_hgnL.js → system-settings-panel-Dp4d5Q1B.js} +1 -1
  80. package/dist/gateway/static/root/assets/{theme-store-C3KnnjcU.js → theme-store-CbGc1laW.js} +1 -1
  81. package/dist/gateway/static/root/assets/{time-picker-D-G-uwVJ.js → time-picker-BhgCeDuO.js} +1 -1
  82. package/dist/gateway/static/root/assets/{typed-models-lib-DtRnG-YI.js → typed-models-lib-DwPk3OPL.js} +1 -1
  83. package/dist/gateway/static/root/assets/{use-channel-catalog-CWWItX2g.js → use-channel-catalog-CXrEu2dw.js} +1 -1
  84. package/dist/gateway/static/root/assets/user-context-page-Dy_fKAK_.js +1 -0
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-BTnltQHZ.js → voice-api-key-field-DFoA79LB.js} +1 -1
  86. package/dist/gateway/static/root/assets/work-discovery-page-BWkjb1NK.js +1 -0
  87. package/dist/gateway/static/root/assets/work-item-detail-page-DLBNFse5.js +1 -0
  88. package/dist/gateway/static/root/assets/work-page-Bn5RXMIE.js +1 -0
  89. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D7vKChFZ.js → workflow-run-setup-panel-BuniGPO0.js} +2 -2
  90. package/dist/gateway/static/root/assets/workflows-page-_vFhRrAl.js +11 -0
  91. package/dist/gateway/static/root/index.html +7 -7
  92. package/dist/package.js +1 -1
  93. package/dist/src/agent/agent-manager.d.ts +3 -1
  94. package/dist/src/agent/agent-manager.js +4 -3
  95. package/dist/src/agent/capabilities/definitions.d.ts +2 -1
  96. package/dist/src/agent/capabilities/definitions.js +3 -1
  97. package/dist/src/agent/prompt/sections/tooling.js +4 -0
  98. package/dist/src/agent/service.d.ts +2 -1
  99. package/dist/src/agent/service.js +26 -0
  100. package/dist/src/agent/skills/hub-pull.js +1 -1
  101. package/dist/src/agent/skills/index.js +1 -1
  102. package/dist/src/agent/skills/install-target.js +1 -1
  103. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.d.ts +64 -0
  104. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +27 -18
  105. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +1 -1
  106. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +1 -1
  107. package/dist/src/agent/skills/marketplace/search.d.ts +46 -0
  108. package/dist/src/agent/skills/marketplace/search.js +193 -0
  109. package/dist/src/agent/skills/skill-tool-gating.js +2 -1
  110. package/dist/src/agent/tools/delegate-tool.js +2 -0
  111. package/dist/src/agent/tools/factory.d.ts +4 -2
  112. package/dist/src/agent/tools/factory.js +11 -5
  113. package/dist/src/agent/tools/index.d.ts +2 -1
  114. package/dist/src/agent/tools/index.js +2 -1
  115. package/dist/src/agent/tools/skill-install-tool.d.ts +17 -0
  116. package/dist/src/agent/tools/skill-install-tool.js +76 -8
  117. package/dist/src/agent/tools/skills-marketplace-search-tool.d.ts +17 -0
  118. package/dist/src/agent/tools/skills-marketplace-search-tool.js +77 -0
  119. package/dist/src/browser/providers/cloakbrowser.js +1 -1
  120. package/dist/src/capabilities/store-connector.js +1 -1
  121. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  122. package/dist/src/config/agent-profile.js +1 -1
  123. package/dist/src/extensions/api.js +1 -1
  124. package/dist/src/extensions/install.js +1 -1
  125. package/dist/src/focuses/candidate-repository.d.ts +15 -0
  126. package/dist/src/focuses/candidate-repository.js +91 -0
  127. package/dist/src/focuses/index.d.ts +7 -0
  128. package/dist/src/focuses/index.js +7 -0
  129. package/dist/src/focuses/insight-repository.d.ts +22 -0
  130. package/dist/src/focuses/insight-repository.js +77 -0
  131. package/dist/src/focuses/prompts.d.ts +2 -0
  132. package/dist/src/focuses/prompts.js +18 -0
  133. package/dist/src/focuses/reconciler.d.ts +5 -0
  134. package/dist/src/focuses/reconciler.js +26 -0
  135. package/dist/src/focuses/repository.d.ts +61 -0
  136. package/dist/src/focuses/repository.js +214 -0
  137. package/dist/src/focuses/run-processor.d.ts +18 -0
  138. package/dist/src/focuses/run-processor.js +162 -0
  139. package/dist/src/focuses/service.d.ts +42 -0
  140. package/dist/src/focuses/service.js +241 -0
  141. package/dist/src/focuses/types.d.ts +89 -0
  142. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  143. package/dist/src/gateway/agent-builtin-tools.js +2 -0
  144. package/dist/src/gateway/agents-admin.js +1 -1
  145. package/dist/src/gateway/hono/routes/commands-skills.js +2 -2
  146. package/dist/src/gateway/hono/routes/focuses.d.ts +3 -0
  147. package/dist/src/gateway/hono/routes/focuses.js +319 -0
  148. package/dist/src/gateway/hono/routes/home.js +15 -17
  149. package/dist/src/gateway/hono/routes/index.js +2 -0
  150. package/dist/src/gateway/hono/routes/projects.js +2 -103
  151. package/dist/src/gateway/hono/routes/work-discovery.js +0 -239
  152. package/dist/src/gateway/service/marketplace-service.js +1 -1
  153. package/dist/src/gateway/service.d.ts +1 -1
  154. package/dist/src/gateway/service.js +15 -11
  155. package/dist/src/storage/sqlite/migrations/066_first_class_focuses.sql +126 -0
  156. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  157. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  158. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  159. package/dist/src/storage/sqlite/schema.js +1 -1
  160. package/dist/src/work-discovery/index.d.ts +0 -2
  161. package/dist/src/work-discovery/index.js +1 -3
  162. package/dist/src/work-discovery/service.d.ts +0 -30
  163. package/dist/src/work-discovery/service.js +1 -35
  164. package/dist/src/work-discovery/thread-service.d.ts +5 -0
  165. package/dist/src/work-discovery/thread-service.js +36 -88
  166. package/package.json +1 -1
  167. package/skills/tools/find-skills/SKILL.md +18 -428
  168. package/dist/gateway/static/root/assets/agents-Bf_kK2Ay.js +0 -2
  169. package/dist/gateway/static/root/assets/apps-page-DXFCP5-1.js +0 -1
  170. package/dist/gateway/static/root/assets/automations-page-D8pT1o2O.js +0 -6
  171. package/dist/gateway/static/root/assets/browser-settings-page-Bav_skKN.js +0 -8
  172. package/dist/gateway/static/root/assets/capabilities-settings-panel-BHaYYo9E.js +0 -7
  173. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BgchTh81.js +0 -1
  174. package/dist/gateway/static/root/assets/channels-settings-BP0e62wt.js +0 -1
  175. package/dist/gateway/static/root/assets/channels-status-swr-DBWKfeGe.js +0 -1
  176. package/dist/gateway/static/root/assets/connectors-page-CC5kh0de.js +0 -2
  177. package/dist/gateway/static/root/assets/desktop-pet-D-ZUNHhn.js +0 -1
  178. package/dist/gateway/static/root/assets/dreaming-settings-D9i54kWO.js +0 -3
  179. package/dist/gateway/static/root/assets/goal-create-dialog-Dp0AyDHI.js +0 -1
  180. package/dist/gateway/static/root/assets/goal-detail-page-CNt7nrdS.js +0 -4
  181. package/dist/gateway/static/root/assets/goals-page-Bm_NZFiZ.js +0 -2
  182. package/dist/gateway/static/root/assets/index-C_XSKOH6.css +0 -1
  183. package/dist/gateway/static/root/assets/index-DUasAutC.js +0 -212
  184. package/dist/gateway/static/root/assets/local-app-workbench-page-DZwkD1co.js +0 -2
  185. package/dist/gateway/static/root/assets/logs-page-dNL0Y1dA.js +0 -7
  186. package/dist/gateway/static/root/assets/messages-BWtP5TFz.js +0 -3
  187. package/dist/gateway/static/root/assets/notes-workbench-B8MKxpZb.js +0 -4
  188. package/dist/gateway/static/root/assets/project-detail-page-CWBuuX-S.js +0 -1
  189. package/dist/gateway/static/root/assets/projects-page-BJSsLsXH.js +0 -1
  190. package/dist/gateway/static/root/assets/remote-access-hub-DXJDb8vB.js +0 -1
  191. package/dist/gateway/static/root/assets/sessions-page-DeHpWgxM.js +0 -1
  192. package/dist/gateway/static/root/assets/settings-advanced-gate-Cf-TEYUd.js +0 -1
  193. package/dist/gateway/static/root/assets/setup-status-panel-BFyfed_g.js +0 -1
  194. package/dist/gateway/static/root/assets/shares-settings-CYnH9sTt.js +0 -1
  195. package/dist/gateway/static/root/assets/skill-reload-api-Cr8_m-jS.js +0 -1
  196. package/dist/gateway/static/root/assets/skills-page-Chtc1xDO.js +0 -2
  197. package/dist/gateway/static/root/assets/user-context-page-D7qMR26X.js +0 -1
  198. package/dist/gateway/static/root/assets/work-discovery-page-CpqFZze9.js +0 -1
  199. package/dist/gateway/static/root/assets/work-item-detail-page-t4dXpGC0.js +0 -1
  200. package/dist/gateway/static/root/assets/work-page-BXwDKiMZ.js +0 -1
  201. package/dist/gateway/static/root/assets/workflows-page-Bos9HyqT.js +0 -11
  202. package/dist/src/proactive/calendar-signals.d.ts +0 -4
  203. package/dist/src/proactive/calendar-signals.js +0 -120
  204. package/dist/src/proactive/focus-service.d.ts +0 -62
  205. package/dist/src/proactive/focus-service.js +0 -173
  206. package/dist/src/proactive/index.d.ts +0 -7
  207. package/dist/src/proactive/index.js +0 -7
  208. package/dist/src/proactive/insight-repository.d.ts +0 -21
  209. package/dist/src/proactive/insight-repository.js +0 -109
  210. package/dist/src/proactive/run-processor.d.ts +0 -19
  211. package/dist/src/proactive/run-processor.js +0 -146
  212. package/dist/src/proactive/trial-expiry-reconciler.d.ts +0 -5
  213. package/dist/src/proactive/trial-expiry-reconciler.js +0 -30
  214. package/dist/src/proactive/types.d.ts +0 -66
  215. package/dist/src/proactive/value-score.d.ts +0 -13
  216. package/dist/src/proactive/value-score.js +0 -30
  217. package/dist/src/proactive/watch-repository.d.ts +0 -28
  218. package/dist/src/proactive/watch-repository.js +0 -129
  219. package/dist/src/work-discovery/governance.d.ts +0 -25
  220. package/dist/src/work-discovery/governance.js +0 -96
  221. package/dist/src/work-discovery/thread-repository.d.ts +0 -34
  222. package/dist/src/work-discovery/thread-repository.js +0 -112
  223. /package/dist/src/{proactive → focuses}/types.js +0 -0
@@ -1,4 +0,0 @@
1
- import type { KnowledgeSourceItem } from '../knowledge/types.js';
2
- import type { FocusCalendarSignal, FocusView } from './types.js';
3
- export declare function buildFocusCalendarSignals(items: KnowledgeSourceItem[], focuses: FocusView[], nowMs?: number): FocusCalendarSignal[];
4
- export declare function listFocusCalendarSignals(focuses: FocusView[], nowMs?: number): FocusCalendarSignal[];
@@ -1,120 +0,0 @@
1
- import { listKnowledgeSourceItems } from "../storage/sqlite/knowledge-repository.js";
2
- //#region src/proactive/calendar-signals.ts
3
- const LOOKAHEAD_MS = 7 * 864e5;
4
- const FIELD_LIMIT = 8;
5
- const TITLE_KEYS = new Set([
6
- "summary",
7
- "title",
8
- "name",
9
- "subject"
10
- ]);
11
- const DESCRIPTION_KEYS = new Set([
12
- "description",
13
- "notes",
14
- "body",
15
- "agenda"
16
- ]);
17
- const START_KEYS = new Set([
18
- "start",
19
- "starttime",
20
- "start_time",
21
- "startat",
22
- "start_at",
23
- "datetime"
24
- ]);
25
- const END_KEYS = new Set([
26
- "end",
27
- "endtime",
28
- "end_time",
29
- "endat",
30
- "end_at"
31
- ]);
32
- const STOP_WORDS = new Set([
33
- "about",
34
- "after",
35
- "before",
36
- "from",
37
- "have",
38
- "meeting",
39
- "project",
40
- "review",
41
- "the",
42
- "this",
43
- "with"
44
- ]);
45
- function parsePayload(item) {
46
- if (!item.normalizedText) return null;
47
- try {
48
- return JSON.parse(item.normalizedText);
49
- } catch {
50
- return null;
51
- }
52
- }
53
- function findStrings(value, keys, depth = 0) {
54
- if (depth > 6 || value == null) return [];
55
- if (Array.isArray(value)) return value.flatMap((item) => findStrings(item, keys, depth + 1)).slice(0, FIELD_LIMIT);
56
- if (typeof value !== "object") return [];
57
- const record = value;
58
- const direct = Object.entries(record).flatMap(([key, nested]) => {
59
- if (!keys.has(key.toLowerCase().replaceAll("-", "_"))) return [];
60
- if (typeof nested === "string") return [nested];
61
- return findStrings(nested, new Set([
62
- "datetime",
63
- "date",
64
- "value"
65
- ]), depth + 1);
66
- });
67
- if (direct.length > 0) return direct.slice(0, FIELD_LIMIT);
68
- return Object.values(record).flatMap((nested) => findStrings(nested, keys, depth + 1)).slice(0, FIELD_LIMIT);
69
- }
70
- function firstDate(payload, keys) {
71
- for (const value of findStrings(payload, keys)) {
72
- const parsed = Date.parse(value);
73
- if (Number.isFinite(parsed)) return parsed;
74
- }
75
- }
76
- function terms(value) {
77
- const normalized = value.toLocaleLowerCase();
78
- const result = new Set(normalized.match(/[a-z0-9][a-z0-9_-]{2,}/g)?.filter((word) => !STOP_WORDS.has(word)) ?? []);
79
- for (const sequence of normalized.match(/[\p{Script=Han}]{2,}/gu) ?? []) for (let index = 0; index < sequence.length - 1; index += 1) result.add(sequence.slice(index, index + 2));
80
- return result;
81
- }
82
- function relatedFocus(focuses, text) {
83
- const eventTerms = terms(text);
84
- if (eventTerms.size === 0) return void 0;
85
- return focuses.map((focus) => ({
86
- focus,
87
- score: [...terms(`${focus.title} ${focus.summary}`)].filter((term) => eventTerms.has(term)).length
88
- })).filter((candidate) => candidate.score >= 2).toSorted((left, right) => right.score - left.score || right.focus.focusScore - left.focus.focusScore)[0]?.focus;
89
- }
90
- function buildFocusCalendarSignals(items, focuses, nowMs = Date.now()) {
91
- const end = nowMs + LOOKAHEAD_MS;
92
- const signals = items.flatMap((item) => {
93
- if (item.itemType !== "calendar_event") return [];
94
- const payload = parsePayload(item);
95
- const title = findStrings(payload, TITLE_KEYS)[0]?.trim();
96
- const startsAt = firstDate(payload, START_KEYS);
97
- if (!title || startsAt == null || startsAt < nowMs || startsAt > end) return [];
98
- const focus = relatedFocus(focuses, `${title} ${findStrings(payload, DESCRIPTION_KEYS).join(" ")}`);
99
- if (!focus) return [];
100
- const endsAt = firstDate(payload, END_KEYS);
101
- return [{
102
- id: item.id,
103
- focusId: focus.id,
104
- focusTitle: focus.title,
105
- title,
106
- startsAt,
107
- ...endsAt != null ? { endsAt } : {},
108
- sourceInstanceId: item.sourceInstanceId
109
- }];
110
- }).toSorted((left, right) => left.startsAt - right.startsAt);
111
- return signals.filter((signal, index) => signals.findIndex((candidate) => candidate.focusId === signal.focusId && candidate.startsAt === signal.startsAt && candidate.title.toLocaleLowerCase() === signal.title.toLocaleLowerCase()) === index).slice(0, 20);
112
- }
113
- function listFocusCalendarSignals(focuses, nowMs = Date.now()) {
114
- return buildFocusCalendarSignals(listKnowledgeSourceItems({
115
- itemType: "calendar_event",
116
- limit: 500
117
- }), focuses, nowMs);
118
- }
119
- //#endregion
120
- export { buildFocusCalendarSignals, listFocusCalendarSignals };
@@ -1,62 +0,0 @@
1
- import type { Automation, AutomationRun } from '../automations/index.js';
2
- import type { FocusView, FocusWatch, FocusWatchKind } from './types.js';
3
- interface AutomationPort {
4
- create(input: {
5
- name: string;
6
- description: string;
7
- projectId?: string;
8
- trigger: {
9
- kind: 'schedule';
10
- schedule: {
11
- kind: 'interval';
12
- everyMs: number;
13
- };
14
- };
15
- action: {
16
- kind: 'agent';
17
- instruction: string;
18
- timeoutSeconds: number;
19
- };
20
- safety: {
21
- mode: 'suggest_only';
22
- };
23
- afterRun: {
24
- kind: 'none';
25
- };
26
- reliability: {
27
- timeoutSeconds: number;
28
- disableAfterConsecutiveFailures: number;
29
- };
30
- }): Promise<Automation>;
31
- pause(id: string): Promise<Automation | null>;
32
- resume(id: string): Promise<Automation | null>;
33
- update(id: string, patch: {
34
- action: {
35
- kind: 'agent';
36
- instruction: string;
37
- timeoutSeconds: number;
38
- };
39
- }): Promise<Automation | null>;
40
- runNow(id: string): Promise<AutomationRun>;
41
- }
42
- export declare class FocusService {
43
- private readonly automations;
44
- private readonly goals;
45
- constructor(automations: AutomationPort);
46
- list(options?: {
47
- includeUnreviewed?: boolean;
48
- }): FocusView[];
49
- confirm(id: string): FocusView | null;
50
- activateTrial(input: {
51
- threadId: string;
52
- kind?: FocusWatchKind;
53
- eventContext?: string;
54
- }): Promise<{
55
- focus: FocusView;
56
- watch: FocusWatch;
57
- }>;
58
- pauseWatch(id: string): Promise<FocusWatch | null>;
59
- reconcileExpiredTrials(nowMs?: number): Promise<number>;
60
- recordInsightFeedback(watchId: string, useful: boolean): Promise<FocusWatch | null>;
61
- }
62
- export {};
@@ -1,173 +0,0 @@
1
- import { createLogger } from "../utils/logger/index.js";
2
- import { init_logger } from "../utils/logger.js";
3
- import { GoalService } from "../goals/goal-service.js";
4
- import "../goals/index.js";
5
- import { addWorkUnderstandingThreadFeedback, getWorkUnderstandingThread, listWorkUnderstandingThreads } from "../work-discovery/thread-repository.js";
6
- import { createFocusWatch, getFocusWatchByThreadAndKind, listFocusWatches, recordFocusWatchFeedback, restartFocusWatchTrial, setFocusWatchStatus } from "./watch-repository.js";
7
- //#region src/proactive/focus-service.ts
8
- init_logger();
9
- const TRIAL_DURATION_MS = 7 * 864e5;
10
- const DAILY_INTERVAL_MS = 1440 * 60 * 1e3;
11
- const log = createLogger("FocusService");
12
- function instructionForFocus(title, summary, kind, eventContext) {
13
- const intent = kind === "progress" ? "Look for meaningful progress, blockers, and the most useful next step." : kind === "staleness" ? "Check whether this focus has stalled and identify the smallest credible unblock." : kind === "deadline" ? "Check upcoming deadlines or meetings and prepare only the material that is needed next." : "Search for external changes published since the previous daily check. Use primary sources when possible, include the publication date and canonical URL, reject generic background news, and explain the concrete impact on this focus.";
14
- return [
15
- "Maintain this user-confirmed focus in suggest-only mode.",
16
- `Focus: ${title}`,
17
- `Context: ${summary}`,
18
- ...eventContext ? [`Upcoming event selected by the user: ${eventContext}`] : [],
19
- intent,
20
- "Inspect only evidence that changed since the previous daily check; use timestamps, history, status, or source revisions to establish the delta.",
21
- "Use evidence available to the agent. Do not modify files, send messages, publish content, or claim progress without evidence.",
22
- "Return JSON only, with no markdown.",
23
- "If nothing materially changed: {\"meaningful\":false}.",
24
- "Otherwise return {\"meaningful\":true,\"title\":\"short title\",\"summary\":\"what changed\",\"whyItMatters\":\"concrete impact\",\"nextAction\":\"one next action\",\"evidence\":[{\"label\":\"specific observed evidence\",\"source\":\"file, event, or canonical URL\",\"publishedAt\":\"ISO date when this is external news\"}]}.",
25
- "A meaningful result requires at least one specific evidence item. Never invent evidence. Keep the entire JSON response under 2,000 characters."
26
- ].join("\n");
27
- }
28
- var FocusService = class {
29
- goals = new GoalService();
30
- constructor(automations) {
31
- this.automations = automations;
32
- }
33
- list(options = {}) {
34
- const threads = listWorkUnderstandingThreads({ limit: 200 }).filter((thread) => options.includeUnreviewed || thread.userStatus === "confirmed" || thread.userStatus === "corrected");
35
- const watches = listFocusWatches();
36
- const goals = this.goals.list({
37
- status: [
38
- "active",
39
- "blocked",
40
- "needs_input",
41
- "paused"
42
- ],
43
- limit: 200
44
- });
45
- return threads.map((thread) => {
46
- const goal = goals.find((candidate) => candidate.projectId && thread.projectIds.includes(candidate.projectId));
47
- return {
48
- id: thread.id,
49
- title: thread.title,
50
- summary: thread.summary,
51
- status: thread.status,
52
- horizon: thread.horizon,
53
- confidence: thread.confidence,
54
- focusScore: thread.focusScore,
55
- userStatus: thread.userStatus,
56
- projectIds: thread.projectIds,
57
- ...goal ? {
58
- goalId: goal.id,
59
- nextAction: goal.nextAction,
60
- blockedReason: goal.blockedReason
61
- } : {},
62
- watches: watches.filter((watch) => watch.threadId === thread.id),
63
- lastObservedAt: thread.lastObservedAt
64
- };
65
- });
66
- }
67
- confirm(id) {
68
- const thread = addWorkUnderstandingThreadFeedback({
69
- threadId: id,
70
- decision: "confirmed"
71
- });
72
- return thread ? this.list({ includeUnreviewed: true }).find((focus) => focus.id === thread.id) ?? null : null;
73
- }
74
- async activateTrial(input) {
75
- const kind = input.kind ?? "progress";
76
- let thread = getWorkUnderstandingThread(input.threadId);
77
- if (!thread || thread.userStatus === "rejected") throw new Error("Focus not found");
78
- if (thread.userStatus === "unreviewed") thread = addWorkUnderstandingThreadFeedback({
79
- threadId: thread.id,
80
- decision: "confirmed"
81
- });
82
- if (!thread) throw new Error("Focus not found");
83
- const existing = getFocusWatchByThreadAndKind(thread.id, kind);
84
- if (existing) {
85
- if (input.eventContext) await this.automations.update(existing.automationId, { action: {
86
- kind: "agent",
87
- instruction: instructionForFocus(thread.title, thread.summary, kind, input.eventContext),
88
- timeoutSeconds: 300
89
- } });
90
- if (existing.status === "paused") {
91
- await this.automations.resume(existing.automationId);
92
- restartFocusWatchTrial(existing.id, Date.now() + TRIAL_DURATION_MS);
93
- }
94
- if (input.eventContext) this.automations.runNow(existing.automationId).catch((err) => {
95
- log.warn({
96
- err,
97
- automationId: existing.automationId,
98
- watchId: existing.id
99
- }, "Focus event preparation run failed");
100
- });
101
- return {
102
- focus: this.list({ includeUnreviewed: true }).find((item) => item.id === thread.id),
103
- watch: getFocusWatchByThreadAndKind(thread.id, kind)
104
- };
105
- }
106
- const automation = await this.automations.create({
107
- name: `Keep moving: ${thread.title}`.slice(0, 200),
108
- description: `Seven-day ${kind} watch for a user-confirmed focus.`,
109
- ...thread.projectIds[0] ? { projectId: thread.projectIds[0] } : {},
110
- trigger: {
111
- kind: "schedule",
112
- schedule: {
113
- kind: "interval",
114
- everyMs: DAILY_INTERVAL_MS
115
- }
116
- },
117
- action: {
118
- kind: "agent",
119
- instruction: instructionForFocus(thread.title, thread.summary, kind, input.eventContext),
120
- timeoutSeconds: 300
121
- },
122
- safety: { mode: "suggest_only" },
123
- afterRun: { kind: "none" },
124
- reliability: {
125
- timeoutSeconds: 300,
126
- disableAfterConsecutiveFailures: 3
127
- }
128
- });
129
- const watch = createFocusWatch({
130
- threadId: thread.id,
131
- automationId: automation.id,
132
- kind,
133
- config: {
134
- cadence: "daily",
135
- notifyOnlyWhenMeaningful: true
136
- },
137
- trialEndsAt: Date.now() + TRIAL_DURATION_MS
138
- });
139
- this.automations.runNow(automation.id).catch((err) => {
140
- log.warn({
141
- err,
142
- automationId: automation.id,
143
- watchId: watch.id
144
- }, "Initial focus watch run failed");
145
- });
146
- return {
147
- focus: this.list({ includeUnreviewed: true }).find((item) => item.id === thread.id),
148
- watch
149
- };
150
- }
151
- async pauseWatch(id) {
152
- const watch = listFocusWatches().find((item) => item.id === id);
153
- if (!watch) return null;
154
- await this.automations.pause(watch.automationId);
155
- return setFocusWatchStatus(id, "paused");
156
- }
157
- async reconcileExpiredTrials(nowMs = Date.now()) {
158
- const expired = listFocusWatches({ status: "active" }).filter((watch) => watch.trialEndsAt != null && watch.trialEndsAt <= nowMs);
159
- for (const watch of expired) {
160
- await this.automations.pause(watch.automationId);
161
- setFocusWatchStatus(watch.id, "paused", nowMs);
162
- }
163
- return expired.length;
164
- }
165
- async recordInsightFeedback(watchId, useful) {
166
- const result = recordFocusWatchFeedback(watchId, useful);
167
- if (!result) return null;
168
- if (!useful && result.consecutiveDismissed >= 3) return this.pauseWatch(watchId);
169
- return result.watch;
170
- }
171
- };
172
- //#endregion
173
- export { FocusService };
@@ -1,7 +0,0 @@
1
- export * from './types.js';
2
- export * from './calendar-signals.js';
3
- export * from './focus-service.js';
4
- export * from './insight-repository.js';
5
- export * from './run-processor.js';
6
- export * from './trial-expiry-reconciler.js';
7
- export * from './watch-repository.js';
@@ -1,7 +0,0 @@
1
- import { buildFocusCalendarSignals, listFocusCalendarSignals } from "./calendar-signals.js";
2
- import { createFocusWatch, getFocusWatchByAutomationId, getFocusWatchByThreadAndKind, listFocusWatches, recordFocusWatchFeedback, recordFocusWatchRun, restartFocusWatchTrial, setFocusWatchStatus } from "./watch-repository.js";
3
- import { FocusService } from "./focus-service.js";
4
- import { claimProactiveInsightApproval, createProactiveInsight, getProactiveInsight, listProactiveInsights, setProactiveInsightStatus } from "./insight-repository.js";
5
- import { hasValidIntelligenceEvidence, parseFocusRunResult, processFocusAutomationRun } from "./run-processor.js";
6
- import { startTrialExpiryReconciler } from "./trial-expiry-reconciler.js";
7
- export { FocusService, buildFocusCalendarSignals, claimProactiveInsightApproval, createFocusWatch, createProactiveInsight, getFocusWatchByAutomationId, getFocusWatchByThreadAndKind, getProactiveInsight, hasValidIntelligenceEvidence, listFocusCalendarSignals, listFocusWatches, listProactiveInsights, parseFocusRunResult, processFocusAutomationRun, recordFocusWatchFeedback, recordFocusWatchRun, restartFocusWatchTrial, setFocusWatchStatus, setProactiveInsightStatus, startTrialExpiryReconciler };
@@ -1,21 +0,0 @@
1
- import type { FocusWatchKind, ProactiveEvidence, ProactiveInsight, ProactiveInsightStatus } from './types.js';
2
- export declare function getProactiveInsight(id: string): ProactiveInsight | null;
3
- export declare function listProactiveInsights(options?: {
4
- status?: ProactiveInsightStatus[];
5
- limit?: number;
6
- }): ProactiveInsight[];
7
- export declare function createProactiveInsight(input: {
8
- watchId: string;
9
- runId: string;
10
- kind: FocusWatchKind;
11
- title: string;
12
- summary: string;
13
- whyItMatters: string;
14
- nextAction: string;
15
- evidence: ProactiveEvidence[];
16
- valueScore: number;
17
- valueReasons: string[];
18
- nowMs?: number;
19
- }): ProactiveInsight | null;
20
- export declare function setProactiveInsightStatus(id: string, status: ProactiveInsightStatus, nowMs?: number, expectedStatus?: ProactiveInsightStatus): ProactiveInsight | null;
21
- export declare function claimProactiveInsightApproval(id: string, nowMs?: number): ProactiveInsight | null;
@@ -1,109 +0,0 @@
1
- import { requireXopcDatabase } from "../storage/sqlite/connection.js";
2
- import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
3
- import { createHash, randomUUID } from "node:crypto";
4
- //#region src/proactive/insight-repository.ts
5
- function insightFromRow(row) {
6
- return {
7
- id: row.insight_id,
8
- watchId: row.watch_id,
9
- runId: row.run_id,
10
- kind: row.kind,
11
- title: row.title,
12
- summary: row.summary,
13
- whyItMatters: row.why_it_matters,
14
- nextAction: row.next_action,
15
- evidence: JSON.parse(row.evidence_json),
16
- status: row.status,
17
- valueScore: row.value_score,
18
- valueReasons: JSON.parse(row.value_reasons_json),
19
- createdAt: row.created_at,
20
- updatedAt: row.updated_at
21
- };
22
- }
23
- function getProactiveInsight(id) {
24
- const { db } = requireXopcDatabase();
25
- const row = db.prepare("SELECT * FROM proactive_insights WHERE insight_id = ?").get(id);
26
- return row ? insightFromRow(row) : null;
27
- }
28
- function listProactiveInsights(options = {}) {
29
- const statuses = options.status ?? ["unread", "read"];
30
- if (statuses.length === 0) return [];
31
- const limit = Math.max(1, Math.min(100, options.limit ?? 20));
32
- const { db } = requireXopcDatabase();
33
- return db.prepare(`SELECT * FROM proactive_insights
34
- WHERE status IN (${statuses.map(() => "?").join(", ")})
35
- ORDER BY created_at DESC LIMIT ?`).all(...statuses, limit).map(insightFromRow);
36
- }
37
- function createProactiveInsight(input) {
38
- const id = randomUUID();
39
- const now = input.nowMs ?? Date.now();
40
- const intelligenceUpdates = input.evidence.map((item) => [
41
- canonicalSource(item.source),
42
- canonicalPublishedAt(item.publishedAt),
43
- normalizeIdentityText(item.label)
44
- ]).filter(([source]) => Boolean(source)).toSorted((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
45
- const fingerprint = input.kind === "intelligence" && intelligenceUpdates.length > 0 ? JSON.stringify({
46
- kind: input.kind,
47
- updates: intelligenceUpdates
48
- }) : JSON.stringify({
49
- kind: input.kind,
50
- title: input.title.toLocaleLowerCase().trim(),
51
- summary: input.summary.toLocaleLowerCase().trim(),
52
- evidence: input.evidence.map((item) => [
53
- item.label.toLocaleLowerCase().trim(),
54
- canonicalSource(item.source),
55
- item.publishedAt ?? ""
56
- ])
57
- });
58
- const contentHash = createHash("sha256").update(fingerprint).digest("hex");
59
- let created = false;
60
- runSqliteWriteTransaction((db) => {
61
- created = db.prepare(`INSERT OR IGNORE INTO proactive_insights (
62
- insight_id, watch_id, run_id, kind, title, summary, why_it_matters,
63
- next_action, evidence_json, content_hash, status, value_score,
64
- value_reasons_json, created_at, updated_at
65
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unread', ?, ?, ?, ?)`).run(id, input.watchId, input.runId, input.kind, input.title, input.summary, input.whyItMatters, input.nextAction, JSON.stringify(input.evidence), contentHash, input.valueScore, JSON.stringify(input.valueReasons), now, now).changes > 0;
66
- });
67
- return created ? listProactiveInsights({ limit: 100 }).find((item) => item.id === id) ?? null : null;
68
- }
69
- function canonicalPublishedAt(value) {
70
- if (!value) return "";
71
- const timestamp = Date.parse(value);
72
- return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : value.trim();
73
- }
74
- function normalizeIdentityText(value) {
75
- return value.trim().toLocaleLowerCase().replace(/\s+/g, " ");
76
- }
77
- function canonicalSource(source) {
78
- const value = source?.trim();
79
- if (!value) return "";
80
- try {
81
- const url = new URL(value);
82
- url.hash = "";
83
- for (const key of [...url.searchParams.keys()]) if (key.toLowerCase().startsWith("utm_") || key === "ref" || key === "source") url.searchParams.delete(key);
84
- url.pathname = url.pathname.replace(/\/$/, "");
85
- return url.toString().toLocaleLowerCase();
86
- } catch {
87
- return value.toLocaleLowerCase();
88
- }
89
- }
90
- function setProactiveInsightStatus(id, status, nowMs = Date.now(), expectedStatus) {
91
- let changed = false;
92
- runSqliteWriteTransaction((db) => {
93
- changed = db.prepare(`UPDATE proactive_insights SET status = ?, updated_at = ? WHERE insight_id = ?
94
- ${expectedStatus ? "AND status = ?" : ""}`).run(status, nowMs, id, ...expectedStatus ? [expectedStatus] : []).changes > 0;
95
- });
96
- if (!changed) return null;
97
- const { db } = requireXopcDatabase();
98
- return insightFromRow(db.prepare("SELECT * FROM proactive_insights WHERE insight_id = ?").get(id));
99
- }
100
- function claimProactiveInsightApproval(id, nowMs = Date.now()) {
101
- let claimed = false;
102
- runSqliteWriteTransaction((db) => {
103
- claimed = db.prepare(`UPDATE proactive_insights SET status = 'approved', updated_at = ?
104
- WHERE insight_id = ? AND status = 'unread'`).run(nowMs, id).changes > 0;
105
- });
106
- return claimed ? getProactiveInsight(id) : null;
107
- }
108
- //#endregion
109
- export { claimProactiveInsightApproval, createProactiveInsight, getProactiveInsight, listProactiveInsights, setProactiveInsightStatus };
@@ -1,19 +0,0 @@
1
- import type { AutomationRun } from '../automations/index.js';
2
- import type { ProactiveEvidence, ProactiveInsight } from './types.js';
3
- interface MeaningfulResult {
4
- meaningful: true;
5
- title: string;
6
- summary: string;
7
- whyItMatters: string;
8
- nextAction: string;
9
- evidence: ProactiveEvidence[];
10
- }
11
- export declare function parseFocusRunResult(summary: string): MeaningfulResult | {
12
- meaningful: false;
13
- } | null;
14
- export declare function hasValidIntelligenceEvidence(evidence: ProactiveEvidence[]): boolean;
15
- export declare function processFocusAutomationRun(run: AutomationRun): {
16
- handled: boolean;
17
- insight?: ProactiveInsight;
18
- };
19
- export {};
@@ -1,146 +0,0 @@
1
- import { createLogger } from "../utils/logger/index.js";
2
- import { init_logger } from "../utils/logger.js";
3
- import { getRelationshipSettings, isProactiveSupportAllowed } from "../storage/sqlite/relationship-settings-repository.js";
4
- import "../storage/sqlite/index.js";
5
- import { getFocusWatchByAutomationId, recordFocusWatchRun } from "./watch-repository.js";
6
- import { createProactiveInsight, listProactiveInsights } from "./insight-repository.js";
7
- import { scoreProactiveValue } from "./value-score.js";
8
- //#region src/proactive/run-processor.ts
9
- init_logger();
10
- const log = createLogger("ProactiveRunProcessor");
11
- function nonEmptyString(value) {
12
- return typeof value === "string" && value.trim() ? value.trim() : null;
13
- }
14
- function parseFocusRunResult(summary) {
15
- const start = summary.indexOf("{");
16
- const end = summary.lastIndexOf("}");
17
- if (start < 0 || end <= start) return null;
18
- let value;
19
- try {
20
- value = JSON.parse(summary.slice(start, end + 1));
21
- } catch {
22
- return null;
23
- }
24
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
25
- const result = value;
26
- if (result.meaningful === false) return { meaningful: false };
27
- if (result.meaningful !== true) return null;
28
- const title = nonEmptyString(result.title);
29
- const resultSummary = nonEmptyString(result.summary);
30
- const whyItMatters = nonEmptyString(result.whyItMatters);
31
- const nextAction = nonEmptyString(result.nextAction);
32
- const evidence = Array.isArray(result.evidence) ? result.evidence.flatMap((item) => {
33
- if (!item || typeof item !== "object" || Array.isArray(item)) return [];
34
- const label = nonEmptyString(item.label);
35
- const source = nonEmptyString(item.source);
36
- const publishedAtValue = nonEmptyString(item.publishedAt);
37
- const publishedAt = publishedAtValue && Number.isFinite(Date.parse(publishedAtValue)) ? new Date(publishedAtValue).toISOString() : null;
38
- return label ? [{
39
- label,
40
- ...source ? { source } : {},
41
- ...publishedAt ? { publishedAt } : {}
42
- }] : [];
43
- }).slice(0, 8) : [];
44
- if (!title || !resultSummary || !whyItMatters || !nextAction || evidence.length === 0) return null;
45
- return {
46
- meaningful: true,
47
- title,
48
- summary: resultSummary,
49
- whyItMatters,
50
- nextAction,
51
- evidence
52
- };
53
- }
54
- function hasValidIntelligenceEvidence(evidence) {
55
- return evidence.some((item) => {
56
- if (!item.source || !item.publishedAt) return false;
57
- try {
58
- const url = new URL(item.source);
59
- return (url.protocol === "https:" || url.protocol === "http:") && Number.isFinite(Date.parse(item.publishedAt));
60
- } catch {
61
- return false;
62
- }
63
- });
64
- }
65
- function processFocusAutomationRun(run) {
66
- const watch = getFocusWatchByAutomationId(run.automationId);
67
- if (!watch) return { handled: false };
68
- if (run.status !== "succeeded" || !run.summary) {
69
- recordFocusWatchRun({
70
- id: watch.id,
71
- runId: run.id,
72
- outcome: "failed",
73
- nowMs: run.endedAtMs
74
- });
75
- return { handled: true };
76
- }
77
- const result = parseFocusRunResult(run.summary);
78
- if (!result) {
79
- recordFocusWatchRun({
80
- id: watch.id,
81
- runId: run.id,
82
- outcome: "failed",
83
- nowMs: run.endedAtMs
84
- });
85
- log.warn({
86
- automationId: run.automationId,
87
- runId: run.id
88
- }, "Focus watch returned an invalid result");
89
- return { handled: true };
90
- }
91
- if (result.meaningful && watch.kind === "intelligence" && !hasValidIntelligenceEvidence(result.evidence)) {
92
- recordFocusWatchRun({
93
- id: watch.id,
94
- runId: run.id,
95
- outcome: "failed",
96
- nowMs: run.endedAtMs
97
- });
98
- log.warn({
99
- automationId: run.automationId,
100
- runId: run.id
101
- }, "Intelligence watch result lacked dated web evidence");
102
- return { handled: true };
103
- }
104
- if (!recordFocusWatchRun({
105
- id: watch.id,
106
- runId: run.id,
107
- outcome: result.meaningful ? "meaningful" : "empty",
108
- nowMs: run.endedAtMs
109
- })) return { handled: true };
110
- if (!result.meaningful) return { handled: true };
111
- if (!isProactiveSupportAllowed(getRelationshipSettings(), {
112
- now: new Date(run.endedAtMs),
113
- topic: watch.kind
114
- })) return { handled: true };
115
- const history = listProactiveInsights({
116
- status: ["approved", "dismissed"],
117
- limit: 50
118
- });
119
- const value = scoreProactiveValue({
120
- kind: watch.kind,
121
- evidenceCount: result.evidence.length,
122
- hasNextAction: Boolean(result.nextAction),
123
- approvedCount: history.filter((item) => item.status === "approved").length,
124
- dismissedCount: history.filter((item) => item.status === "dismissed").length
125
- });
126
- if (!value.shouldDeliver) return { handled: true };
127
- const insight = createProactiveInsight({
128
- watchId: watch.id,
129
- runId: run.id,
130
- kind: watch.kind,
131
- title: result.title,
132
- summary: result.summary,
133
- whyItMatters: result.whyItMatters,
134
- nextAction: result.nextAction,
135
- evidence: result.evidence,
136
- valueScore: value.score,
137
- valueReasons: value.reasons,
138
- nowMs: run.endedAtMs
139
- });
140
- return insight ? {
141
- handled: true,
142
- insight
143
- } : { handled: true };
144
- }
145
- //#endregion
146
- export { hasValidIntelligenceEvidence, parseFocusRunResult, processFocusAutomationRun };
@@ -1,5 +0,0 @@
1
- interface TrialExpiryService {
2
- reconcileExpiredTrials(): Promise<number>;
3
- }
4
- export declare function startTrialExpiryReconciler(service: TrialExpiryService, intervalMs?: number): () => Promise<void>;
5
- export {};