@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,13 +1,26 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { getMemoryRecord, upsertMemoryRecord } from "../storage/sqlite/memory-records-repository.js";
4
+ import { upsertKnowledgeSourceItems } from "../storage/sqlite/knowledge-repository.js";
5
+ import "../storage/sqlite/index.js";
3
6
  import { ActivityService } from "../activity/service.js";
4
7
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
5
8
  import { buildSessionKey, init_session_key } from "../routing/session-key.js";
6
9
  import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
10
+ import { nextMemoryReviewAt } from "../agent/memory/lifecycle.js";
11
+ import { addWorkUnderstandingThreadFeedback, attachWorkUnderstandingThreadEvidence, getWorkUnderstandingThread, listWorkUnderstandingThreads } from "./thread-repository.js";
7
12
  import { previewWorkDiscoveryRoot, probeWorkDiscoveryRoot, summarizeWorkContextSnapshot } from "./probe.js";
8
- import { analyzeWorkContext, workDiscoveryResultMarkdown } from "./analyzer.js";
13
+ import { analyzePersonalContext, analyzeWorkContext, workDiscoveryResultMarkdown } from "./analyzer.js";
14
+ import { discoverWorkCandidates } from "./candidate-discovery.js";
15
+ import { deleteWorkUnderstandingDerivedData, getWorkUnderstandingMetrics, getWorkUnderstandingSourceLineage } from "./governance.js";
16
+ import { workDiscoveryFingerprintsEqual } from "./incremental.js";
17
+ import { findActiveWorkDiscoverySourceRefresh, recordWorkDiscoverySourceRefresh, updateWorkDiscoverySourceRefreshForRun } from "./incremental-repository.js";
18
+ import { appendWorkUnderstandingEvidence, getWorkUnderstandingInvestigationForRun, listWorkUnderstandingEvidence } from "./investigation-repository.js";
19
+ import { investigateWorkContext } from "./investigator.js";
20
+ import { persistWorkThreadsFromDiscovery } from "./thread-service.js";
9
21
  import { createWorkDiscoveryRun, getWorkDiscoveryOnboardingState, getWorkDiscoveryRun, getWorkDiscoveryRunByIdempotencyKey, setWorkDiscoveryFeedback, setWorkDiscoveryOnboardingState, updateWorkDiscoveryRun } from "./repository.js";
10
- import { randomUUID } from "node:crypto";
22
+ import { getWorkDiscoveryDirectorySource, listWorkDiscoveryDirectorySources, revokeWorkDiscoveryDirectorySource, upsertWorkDiscoveryDirectorySource } from "./source-repository.js";
23
+ import { createHash, randomUUID } from "node:crypto";
11
24
  //#region src/work-discovery/service.ts
12
25
  init_schema();
13
26
  init_session_key();
@@ -47,8 +60,19 @@ function errorCode(error) {
47
60
  if (message.includes("timeout")) return "analysis_timeout";
48
61
  return "internal_error";
49
62
  }
63
+ function hasLongVerbatimOverlap(value, sources, minimumLength = 32) {
64
+ const normalized = value.replace(/\s+/g, " ").trim();
65
+ if (normalized.length < minimumLength) return false;
66
+ const sourceText = sources.map((source) => source.replace(/\s+/g, " "));
67
+ for (let index = 0; index <= normalized.length - minimumLength; index += Math.max(1, Math.floor(minimumLength / 2))) {
68
+ const fragment = normalized.slice(index, index + minimumLength);
69
+ if (sourceText.some((source) => source.includes(fragment))) return true;
70
+ }
71
+ return false;
72
+ }
50
73
  var WorkDiscoveryService = class {
51
74
  abortControllers = /* @__PURE__ */ new Map();
75
+ candidateContexts = /* @__PURE__ */ new Map();
52
76
  activity = new ActivityService();
53
77
  constructor(options) {
54
78
  this.options = options;
@@ -68,6 +92,339 @@ var WorkDiscoveryService = class {
68
92
  getRun(id) {
69
93
  return getWorkDiscoveryRun(id);
70
94
  }
95
+ getInvestigation(runId) {
96
+ const investigation = getWorkUnderstandingInvestigationForRun(runId);
97
+ return investigation ? {
98
+ investigation,
99
+ evidence: listWorkUnderstandingEvidence(investigation.id)
100
+ } : null;
101
+ }
102
+ listWorkThreads(options = {}) {
103
+ return listWorkUnderstandingThreads(options);
104
+ }
105
+ getWorkThread(id) {
106
+ return getWorkUnderstandingThread(id);
107
+ }
108
+ getSourceLineage(sourceId) {
109
+ return getWorkUnderstandingSourceLineage(sourceId);
110
+ }
111
+ deleteSourceDerivedData(sourceId) {
112
+ return deleteWorkUnderstandingDerivedData(sourceId);
113
+ }
114
+ getUnderstandingMetrics() {
115
+ return getWorkUnderstandingMetrics();
116
+ }
117
+ updateWorkThread(input) {
118
+ return addWorkUnderstandingThreadFeedback({
119
+ threadId: input.id,
120
+ decision: input.decision,
121
+ correctedTitle: input.correctedTitle,
122
+ correctedSummary: input.correctedSummary
123
+ });
124
+ }
125
+ async discoverCandidates(signal) {
126
+ return discoverWorkCandidates({
127
+ existingProjects: this.options.projects.list({
128
+ status: "active",
129
+ limit: 500
130
+ }).items.map((project) => ({
131
+ id: project.id,
132
+ workspaceRoot: project.workspaceRoot
133
+ })),
134
+ approvedDirectories: listWorkDiscoveryDirectorySources().map((source) => ({
135
+ id: source.id,
136
+ rootPath: source.rootPath
137
+ })),
138
+ signal
139
+ });
140
+ }
141
+ listDirectorySources() {
142
+ return listWorkDiscoveryDirectorySources();
143
+ }
144
+ async grantDirectorySource(rootPath) {
145
+ const preview = await previewWorkDiscoveryRoot(rootPath);
146
+ return upsertWorkDiscoveryDirectorySource({
147
+ rootPath: preview.canonicalRootPath,
148
+ displayName: preview.displayName,
149
+ fingerprint: preview.fingerprint
150
+ });
151
+ }
152
+ async checkDirectorySources() {
153
+ const checks = [];
154
+ for (const source of listWorkDiscoveryDirectorySources()) try {
155
+ const preview = await previewWorkDiscoveryRoot(source.rootPath);
156
+ checks.push(recordWorkDiscoverySourceRefresh({
157
+ sourceId: source.id,
158
+ changed: !workDiscoveryFingerprintsEqual(source.fingerprint, preview.fingerprint),
159
+ previousFingerprint: source.fingerprint,
160
+ currentFingerprint: preview.fingerprint
161
+ }));
162
+ } catch (error) {
163
+ log.warn({
164
+ err: error,
165
+ sourceId: source.id,
166
+ path: source.rootPath
167
+ }, "Work source change check failed");
168
+ }
169
+ return checks;
170
+ }
171
+ async refreshDirectorySourceIfChanged(input) {
172
+ const source = getWorkDiscoveryDirectorySource(input.id);
173
+ if (!source || source.status !== "active") throw new Error("Approved work folder not found");
174
+ const preview = await previewWorkDiscoveryRoot(source.rootPath);
175
+ if (!!workDiscoveryFingerprintsEqual(source.fingerprint, preview.fingerprint)) return {
176
+ changed: false,
177
+ refresh: recordWorkDiscoverySourceRefresh({
178
+ sourceId: source.id,
179
+ changed: false,
180
+ previousFingerprint: source.fingerprint,
181
+ currentFingerprint: preview.fingerprint
182
+ })
183
+ };
184
+ const activeRefresh = findActiveWorkDiscoverySourceRefresh(source.id, preview.fingerprint);
185
+ const activeRun = activeRefresh?.discoveryRunId ? getWorkDiscoveryRun(activeRefresh.discoveryRunId) : null;
186
+ if (activeRefresh && activeRun) return {
187
+ changed: true,
188
+ reused: true,
189
+ refresh: activeRefresh,
190
+ run: activeRun
191
+ };
192
+ const run = await this.startRun({
193
+ rootPath: preview.canonicalRootPath,
194
+ source: "manual_selected_directory",
195
+ idempotencyKey: input.idempotencyKey
196
+ });
197
+ return {
198
+ changed: true,
199
+ run,
200
+ refresh: recordWorkDiscoverySourceRefresh({
201
+ sourceId: source.id,
202
+ changed: true,
203
+ previousFingerprint: source.fingerprint,
204
+ currentFingerprint: preview.fingerprint,
205
+ status: "queued",
206
+ discoveryRunId: run.id
207
+ })
208
+ };
209
+ }
210
+ revokeDirectorySource(id) {
211
+ return revokeWorkDiscoveryDirectorySource(id);
212
+ }
213
+ async importPersonalContext(rawItems, signal, runId) {
214
+ let remaining = 3e5;
215
+ const allowedSources = new Set([
216
+ "apple_notes",
217
+ "calendar",
218
+ "reminders"
219
+ ]);
220
+ const items = rawItems.flatMap((value) => {
221
+ if (!value || typeof value !== "object" || remaining <= 0) return [];
222
+ const raw = value;
223
+ const id = typeof raw.id === "string" ? raw.id.trim().slice(0, 500) : "";
224
+ const title = typeof raw.title === "string" ? raw.title.trim().slice(0, 300) : "";
225
+ const source = typeof raw.source === "string" && allowedSources.has(raw.source) ? raw.source : null;
226
+ if (!id || !title || !source) return [];
227
+ const content = typeof raw.content === "string" ? raw.content.trim().slice(0, Math.min(12e3, remaining)) : "";
228
+ remaining -= content.length;
229
+ const timestamp = (key) => {
230
+ const value = raw[key];
231
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
232
+ return Number.isFinite(new Date(value).getTime()) ? value : void 0;
233
+ };
234
+ return [{
235
+ id,
236
+ source,
237
+ title,
238
+ ...typeof raw.group === "string" && raw.group.trim() ? { group: raw.group.trim().slice(0, 200) } : {},
239
+ content,
240
+ ...timestamp("createdAt") ? { createdAt: timestamp("createdAt") } : {},
241
+ ...timestamp("modifiedAt") ? { modifiedAt: timestamp("modifiedAt") } : {},
242
+ ...timestamp("startsAt") ? { startsAt: timestamp("startsAt") } : {},
243
+ ...timestamp("endsAt") ? { endsAt: timestamp("endsAt") } : {}
244
+ }];
245
+ }).slice(0, 150);
246
+ if (!items.length) throw new Error("No readable personal context was provided");
247
+ const linkedRun = runId ? getWorkDiscoveryRun(runId) : null;
248
+ const analysis = await analyzePersonalContext({
249
+ config: this.options.getConfig(),
250
+ items,
251
+ ...linkedRun?.result ? { workContext: {
252
+ projectSummary: linkedRun.result.projectSummary,
253
+ currentState: linkedRun.result.currentState,
254
+ uncertainties: linkedRun.result.uncertainties,
255
+ workThreads: linkedRun.result.workThreads
256
+ } } : {},
257
+ signal
258
+ });
259
+ const calendarItems = items.filter((item) => item.source === "calendar" && item.startsAt != null);
260
+ if (calendarItems.length > 0) upsertKnowledgeSourceItems(calendarItems.map((item) => {
261
+ const normalizedText = JSON.stringify({
262
+ title: item.title,
263
+ description: item.content,
264
+ start: new Date(item.startsAt).toISOString(),
265
+ ...item.endsAt != null ? { end: new Date(item.endsAt).toISOString() } : {},
266
+ ...item.group ? { calendar: item.group } : {}
267
+ });
268
+ return {
269
+ sourceInstanceId: "desktop:calendar",
270
+ externalId: item.id,
271
+ itemType: "calendar_event",
272
+ authorRole: "unknown",
273
+ occurredAt: new Date(item.startsAt).toISOString(),
274
+ ...item.modifiedAt != null ? { sourceUpdatedAt: new Date(item.modifiedAt).toISOString() } : {},
275
+ contentHash: createHash("sha256").update(normalizedText).digest("hex"),
276
+ normalizedText,
277
+ metadata: {
278
+ provider: "desktop-calendar",
279
+ calendar: item.group ?? ""
280
+ },
281
+ sensitivity: "personal",
282
+ retentionClass: "bounded",
283
+ synthesisPipeline: "user_understanding",
284
+ synthesisStatus: "ignored"
285
+ };
286
+ }));
287
+ const rawContents = items.flatMap((item) => item.content ? [item.content] : []);
288
+ const safeProfileCandidates = analysis.profileCandidates.filter((candidate) => !hasLongVerbatimOverlap(candidate.statement, rawContents));
289
+ const safeWorkThreadCandidates = analysis.workThreadCandidates.filter((candidate) => !hasLongVerbatimOverlap(candidate.title, rawContents) && !hasLongVerbatimOverlap(candidate.summary, rawContents));
290
+ const agentId = getDefaultAgentId(this.options.getConfig());
291
+ const profileCandidates = safeProfileCandidates.map((candidate) => {
292
+ const autoRemember = candidate.confidence === "high" && candidate.category !== "focus" && candidate.evidence.length >= 2;
293
+ const record = upsertMemoryRecord({
294
+ providerId: "local",
295
+ kind: candidate.category === "preference" ? "preference" : candidate.category === "workflow" ? "routine" : "derived_insight",
296
+ sourceAgentId: agentId,
297
+ content: candidate.statement,
298
+ source: {
299
+ provider: "personal-context",
300
+ path: "personal-context://onboarding"
301
+ },
302
+ confidence: candidate.confidence === "high" ? .9 : candidate.confidence === "medium" ? .72 : .58,
303
+ tags: [
304
+ "user-understanding",
305
+ "personal-context",
306
+ `work-discovery:${candidate.category}`
307
+ ],
308
+ status: autoRemember ? "active" : "candidate",
309
+ sensitivity: "normal",
310
+ explicitness: "inferred",
311
+ durability: candidate.category === "focus" ? "ephemeral" : candidate.category === "workflow" ? "recurring" : "durable",
312
+ importance: candidate.category === "focus" ? .75 : .65,
313
+ disclosurePolicy: "referenceable"
314
+ });
315
+ return {
316
+ ...candidate,
317
+ status: autoRemember ? "accepted" : "pending",
318
+ memoryRecordId: record.id
319
+ };
320
+ });
321
+ const investigation = linkedRun ? getWorkUnderstandingInvestigationForRun(linkedRun.id) : null;
322
+ const contextEvidence = investigation ? safeWorkThreadCandidates.map((candidate) => {
323
+ const topicHash = createHash("sha256").update(candidate.topicKey).digest("hex").slice(0, 16);
324
+ return appendWorkUnderstandingEvidence({
325
+ investigationId: investigation.id,
326
+ projectId: linkedRun.projectId,
327
+ sourceType: "personal_context",
328
+ sourceRef: `personal-context://thread/${topicHash}`,
329
+ observation: candidate.summary,
330
+ contentHash: createHash("sha256").update(JSON.stringify(candidate.evidenceRefs)).digest("hex"),
331
+ sensitivity: "normal"
332
+ });
333
+ }) : [];
334
+ const workThreads = linkedRun && contextEvidence.length ? persistWorkThreadsFromDiscovery({
335
+ projectId: linkedRun.projectId,
336
+ result: {
337
+ projectSummary: "Personal work context",
338
+ currentState: "Work streams inferred from explicitly connected personal sources.",
339
+ uncertainties: [],
340
+ suggestions: [],
341
+ workThreadCandidates: safeWorkThreadCandidates.map((candidate, index) => ({
342
+ ...candidate,
343
+ evidenceRefs: contextEvidence[index] ? [contextEvidence[index].sourceRef] : []
344
+ }))
345
+ },
346
+ snapshot: {
347
+ root: {
348
+ displayName: "Personal Context",
349
+ projectKind: "general",
350
+ markerReasons: ["explicitly_connected_personal_context"]
351
+ },
352
+ structure: {
353
+ sampledPaths: [],
354
+ metadataOnlyFiles: [],
355
+ omittedPathCount: 0
356
+ },
357
+ documents: [],
358
+ limits: {
359
+ policyVersion: 1,
360
+ fileCount: 0,
361
+ contentBytes: 0,
362
+ truncated: false
363
+ }
364
+ },
365
+ evidence: contextEvidence
366
+ }) : [];
367
+ log.info({
368
+ runId,
369
+ itemCount: items.length,
370
+ candidateCount: profileCandidates.length,
371
+ workThreadCount: workThreads.length
372
+ }, "Personal context analyzed");
373
+ return {
374
+ profileCandidates,
375
+ workThreads,
376
+ autoRemembered: profileCandidates.filter((candidate) => candidate.status === "accepted")
377
+ };
378
+ }
379
+ updatePersonalContextProfile(input) {
380
+ return input.decisions.flatMap((decision) => {
381
+ const record = getMemoryRecord(decision.memoryRecordId);
382
+ if (!record || record.source.provider !== "personal-context") return [];
383
+ const statement = decision.status === "edited" ? decision.statement?.trim().slice(0, 500) : void 0;
384
+ if (decision.status === "edited" && !statement) return [];
385
+ const updated = this.preserveMemoryRecord(record, {
386
+ providerId: "local",
387
+ status: decision.status === "rejected" ? "rejected" : "active",
388
+ ...statement ? {
389
+ content: statement,
390
+ explicitness: "explicit",
391
+ confidence: 1
392
+ } : {},
393
+ ...decision.status !== "rejected" ? { reviewAfter: nextMemoryReviewAt(record) } : {}
394
+ });
395
+ return [{
396
+ memoryRecordId: updated.id,
397
+ status: decision.status,
398
+ statement: updated.content
399
+ }];
400
+ });
401
+ }
402
+ async rescanDirectorySource(input) {
403
+ const source = getWorkDiscoveryDirectorySource(input.id);
404
+ if (!source || source.status !== "active") throw new Error("Approved work folder not found");
405
+ const preview = await previewWorkDiscoveryRoot(source.rootPath);
406
+ upsertWorkDiscoveryDirectorySource({
407
+ rootPath: preview.canonicalRootPath,
408
+ displayName: preview.displayName,
409
+ fingerprint: preview.fingerprint
410
+ });
411
+ return this.startRun({
412
+ rootPath: preview.canonicalRootPath,
413
+ source: "manual_selected_directory",
414
+ idempotencyKey: input.idempotencyKey
415
+ });
416
+ }
417
+ async startQuickRun(input) {
418
+ const candidates = await this.discoverCandidates();
419
+ const primary = candidates[0];
420
+ if (!primary) throw new Error("No accessible work projects were found");
421
+ return this.startRun({
422
+ rootPath: primary.rootPath,
423
+ source: "onboarding_selected_directory",
424
+ idempotencyKey: input.idempotencyKey,
425
+ candidateContext: candidates
426
+ });
427
+ }
71
428
  async startRun(input) {
72
429
  const existing = getWorkDiscoveryRunByIdempotencyKey(input.idempotencyKey);
73
430
  if (existing) return existing;
@@ -154,6 +511,7 @@ var WorkDiscoveryService = class {
154
511
  });
155
512
  const controller = new AbortController();
156
513
  this.abortControllers.set(run.id, controller);
514
+ if (input.candidateContext?.length) this.candidateContexts.set(run.id, input.candidateContext.slice(0, 8));
157
515
  this.execute(run, controller.signal);
158
516
  return run;
159
517
  }
@@ -185,11 +543,81 @@ var WorkDiscoveryService = class {
185
543
  snapshot: summarizeWorkContextSnapshot(snapshot)
186
544
  });
187
545
  this.publish(current);
188
- const analysis = await analyzeWorkContext({
546
+ const approvedSource = listWorkDiscoveryDirectorySources().find((source) => source.rootPath === run.rootPath);
547
+ const investigation = await investigateWorkContext({
189
548
  config: this.options.getConfig(),
190
549
  snapshot,
550
+ rootPath: run.rootPath,
551
+ discoveryRunId: run.id,
552
+ projectId: run.projectId,
553
+ ...approvedSource ? { sourceGrantId: approvedSource.id } : {},
191
554
  signal
192
555
  });
556
+ const investigatedSnapshot = {
557
+ ...snapshot,
558
+ documents: investigation.documents,
559
+ limits: {
560
+ ...snapshot.limits,
561
+ contentBytes: investigation.documents.reduce((sum, document) => sum + document.excerpt.length, 0),
562
+ truncated: snapshot.limits.truncated || investigation.degraded
563
+ }
564
+ };
565
+ const candidateContext = this.candidateContexts.get(run.id) ?? (run.source === "onboarding_selected_directory" ? await this.discoverCandidates(signal) : void 0);
566
+ const unifiedEvidence = [...investigation.evidence];
567
+ for (const candidate of candidateContext ?? []) {
568
+ if (candidate.rootPath === run.rootPath) continue;
569
+ const sourceRef = candidate.projectId ? `project://${candidate.projectId}` : `project-candidate://${createHash("sha256").update(candidate.rootPath).digest("hex").slice(0, 16)}`;
570
+ unifiedEvidence.push(appendWorkUnderstandingEvidence({
571
+ investigationId: investigation.investigation.id,
572
+ ...candidate.projectId ? { projectId: candidate.projectId } : {},
573
+ sourceType: "project_metadata",
574
+ sourceRef,
575
+ observation: `${candidate.displayName} is a related work area with ${candidate.changedFileCount} changed files and activity score ${candidate.score}.`,
576
+ contentHash: createHash("sha256").update(JSON.stringify({
577
+ score: candidate.score,
578
+ branch: candidate.branch,
579
+ changedFileCount: candidate.changedFileCount
580
+ })).digest("hex"),
581
+ ...candidate.lastActiveAt ? { observedAt: candidate.lastActiveAt } : {},
582
+ sensitivity: "normal"
583
+ }));
584
+ }
585
+ const analysis = await analyzeWorkContext({
586
+ config: this.options.getConfig(),
587
+ snapshot: investigatedSnapshot,
588
+ ...candidateContext?.length ? { candidateContext } : {},
589
+ signal
590
+ });
591
+ const discoveredProjects = candidateContext?.map((candidate) => ({
592
+ rootPath: candidate.rootPath,
593
+ displayName: candidate.displayName,
594
+ score: candidate.score,
595
+ projectKind: candidate.projectKind,
596
+ ...candidate.lastActiveAt ? { lastActiveAt: candidate.lastActiveAt } : {},
597
+ evidence: candidate.evidence
598
+ }));
599
+ const baseResult = {
600
+ ...analysis.result,
601
+ investigation: {
602
+ id: investigation.investigation.id,
603
+ hypotheses: investigation.investigation.plan.hypotheses,
604
+ questions: investigation.investigation.plan.questions,
605
+ toolCallCount: investigation.investigation.toolCallCount,
606
+ contentCharsRead: investigation.investigation.contentCharsRead,
607
+ degraded: investigation.degraded
608
+ },
609
+ ...discoveredProjects?.length ? { discoveredProjects } : {}
610
+ };
611
+ const workThreads = persistWorkThreadsFromDiscovery({
612
+ projectId: run.projectId,
613
+ result: baseResult,
614
+ snapshot: investigatedSnapshot,
615
+ evidence: unifiedEvidence
616
+ });
617
+ const result = this.persistProfileCandidates(run, {
618
+ ...baseResult,
619
+ ...workThreads.length ? { workThreads } : {}
620
+ });
193
621
  current = updateWorkDiscoveryRun(run.id, {
194
622
  status: "analyzing",
195
623
  stage: "next_steps"
@@ -197,11 +625,11 @@ var WorkDiscoveryService = class {
197
625
  this.publish(current);
198
626
  await this.options.sessions.appendTranscriptCustomMessageEntry(run.sessionKey, {
199
627
  customType: "work-discovery-result",
200
- content: workDiscoveryResultMarkdown(analysis.result),
628
+ content: workDiscoveryResultMarkdown(result),
201
629
  display: true,
202
630
  details: {
203
631
  runId: run.id,
204
- result: analysis.result
632
+ result
205
633
  }
206
634
  });
207
635
  const project = this.options.projects.get(run.projectId);
@@ -209,12 +637,28 @@ var WorkDiscoveryService = class {
209
637
  name: project ? `Continue work on ${project.name}` : "Continue recent work",
210
638
  hiddenFromSessionList: false
211
639
  });
640
+ if (approvedSource) try {
641
+ const preview = await previewWorkDiscoveryRoot(run.rootPath);
642
+ upsertWorkDiscoveryDirectorySource({
643
+ rootPath: preview.canonicalRootPath,
644
+ displayName: preview.displayName,
645
+ fingerprint: preview.fingerprint,
646
+ scanned: true
647
+ });
648
+ } catch (error) {
649
+ log.debug({
650
+ err: error,
651
+ runId: run.id,
652
+ phase: "source_fingerprint"
653
+ }, "Work source fingerprint update failed");
654
+ }
212
655
  current = updateWorkDiscoveryRun(run.id, {
213
656
  status: "completed",
214
657
  stage: "next_steps",
215
- result: analysis.result,
658
+ result,
216
659
  completedAt: Date.now()
217
660
  });
661
+ updateWorkDiscoverySourceRefreshForRun(run.id, "completed");
218
662
  this.activity.record({
219
663
  type: "work_discovery.completed",
220
664
  primaryObject: {
@@ -237,8 +681,8 @@ var WorkDiscoveryService = class {
237
681
  },
238
682
  payload: {
239
683
  policyVersion: run.scanPolicyVersion,
240
- suggestionCount: analysis.result.suggestions.length,
241
- lowConfidence: analysis.result.lowConfidence === true
684
+ suggestionCount: result.suggestions.length,
685
+ lowConfidence: result.lowConfidence === true
242
686
  },
243
687
  scopes: [{
244
688
  scopeKind: "project",
@@ -268,6 +712,7 @@ var WorkDiscoveryService = class {
268
712
  errorMessage: message,
269
713
  ...canceled ? { canceledAt: Date.now() } : { completedAt: Date.now() }
270
714
  });
715
+ updateWorkDiscoverySourceRefreshForRun(run.id, "failed");
271
716
  if (current) this.publish(current);
272
717
  this.activity.record({
273
718
  type: canceled ? "work_discovery.canceled" : "work_discovery.failed",
@@ -305,8 +750,110 @@ var WorkDiscoveryService = class {
305
750
  }, `Work discovery failed: ${message}`);
306
751
  } finally {
307
752
  this.abortControllers.delete(run.id);
753
+ this.candidateContexts.delete(run.id);
308
754
  }
309
755
  }
756
+ persistProfileCandidates(run, result) {
757
+ if (!result.profileCandidates?.length) return result;
758
+ const profileCandidates = result.profileCandidates.map((candidate) => {
759
+ const kind = candidate.category === "preference" ? "preference" : candidate.category === "workflow" ? "routine" : "derived_insight";
760
+ const confidence = candidate.confidence === "high" ? .9 : candidate.confidence === "medium" ? .72 : .58;
761
+ const durability = candidate.category === "focus" ? "ephemeral" : candidate.category === "workflow" ? "recurring" : "durable";
762
+ const record = upsertMemoryRecord({
763
+ providerId: "local",
764
+ kind,
765
+ sourceAgentId: run.agentId,
766
+ sessionKey: run.sessionKey,
767
+ projectId: run.projectId,
768
+ content: candidate.statement,
769
+ source: {
770
+ provider: "work-discovery",
771
+ path: `work-discovery://${run.id}`
772
+ },
773
+ confidence,
774
+ tags: [
775
+ "user-understanding",
776
+ "work-discovery",
777
+ `work-discovery:${candidate.category}`
778
+ ],
779
+ status: "candidate",
780
+ sensitivity: "normal",
781
+ explicitness: "inferred",
782
+ durability,
783
+ importance: candidate.category === "focus" ? .75 : .65,
784
+ disclosurePolicy: "referenceable"
785
+ });
786
+ return {
787
+ ...candidate,
788
+ memoryRecordId: record.id
789
+ };
790
+ });
791
+ return {
792
+ ...result,
793
+ profileCandidates
794
+ };
795
+ }
796
+ updateProfileCandidates(input) {
797
+ const run = getWorkDiscoveryRun(input.runId);
798
+ if (!run?.result?.profileCandidates?.length) return null;
799
+ const decisions = new Map(input.decisions.map((decision) => [decision.id, decision]));
800
+ const profileCandidates = run.result.profileCandidates.map((candidate) => {
801
+ const decision = decisions.get(candidate.id);
802
+ if (!decision || !candidate.memoryRecordId) return candidate;
803
+ const record = getMemoryRecord(candidate.memoryRecordId);
804
+ if (!record) return candidate;
805
+ const statement = decision.status === "edited" ? decision.statement?.trim().slice(0, 500) : void 0;
806
+ if (decision.status === "edited" && !statement) return candidate;
807
+ this.preserveMemoryRecord(record, {
808
+ status: decision.status === "rejected" ? "rejected" : "active",
809
+ ...statement ? {
810
+ content: statement,
811
+ explicitness: "explicit",
812
+ confidence: 1
813
+ } : {},
814
+ ...decision.status !== "rejected" ? { reviewAfter: nextMemoryReviewAt(record) } : {}
815
+ });
816
+ return {
817
+ ...candidate,
818
+ ...statement ? { statement } : {},
819
+ status: decision.status
820
+ };
821
+ });
822
+ return updateWorkDiscoveryRun(run.id, { result: {
823
+ ...run.result,
824
+ profileCandidates
825
+ } });
826
+ }
827
+ preserveMemoryRecord(record, patch) {
828
+ return upsertMemoryRecord({
829
+ id: record.id,
830
+ providerId: "local",
831
+ kind: record.kind,
832
+ sourceAgentId: record.provenance.sourceAgentId,
833
+ workspaceId: record.scope.workspaceId,
834
+ sessionKey: record.scope.sessionKey,
835
+ projectId: record.scope.projectId,
836
+ content: record.content,
837
+ source: record.source,
838
+ confidence: record.confidence,
839
+ tags: record.tags,
840
+ status: record.status,
841
+ sensitivity: record.sensitivity,
842
+ canonicalKey: record.canonicalKey,
843
+ explicitness: record.explicitness,
844
+ durability: record.durability,
845
+ importance: record.importance,
846
+ disclosurePolicy: record.disclosurePolicy,
847
+ evidence: record.evidence,
848
+ reviewAfter: record.reviewAfter,
849
+ expiresAt: record.expiresAt,
850
+ validFrom: record.validFrom,
851
+ validTo: record.validTo,
852
+ supersedesRecordId: record.supersedesRecordId,
853
+ conflictGroupId: record.conflictGroupId,
854
+ ...patch
855
+ });
856
+ }
310
857
  cancelRun(id) {
311
858
  const run = getWorkDiscoveryRun(id);
312
859
  if (!run) return null;
@@ -352,6 +899,29 @@ var WorkDiscoveryService = class {
352
899
  recognitionDecision: input.decision,
353
900
  ...correctedIntent ? { correctedIntent } : {}
354
901
  });
902
+ const investigation = getWorkUnderstandingInvestigationForRun(run.id);
903
+ if (investigation && input.decision !== "dismissed") {
904
+ const observation = correctedIntent ? `The user explicitly stated their current intent: ${correctedIntent}` : "The user explicitly confirmed the inferred current work understanding.";
905
+ const evidence = appendWorkUnderstandingEvidence({
906
+ investigationId: investigation.id,
907
+ projectId: run.projectId,
908
+ sourceType: "user_statement",
909
+ sourceRef: `session://${createHash("sha256").update(run.sessionKey).digest("hex").slice(0, 16)}/recognition`,
910
+ observation,
911
+ contentHash: createHash("sha256").update(observation).digest("hex"),
912
+ observedAt: Date.now(),
913
+ sensitivity: "normal"
914
+ });
915
+ const currentThreads = listWorkUnderstandingThreads({
916
+ projectId: run.projectId,
917
+ limit: 50
918
+ }).filter((thread) => thread.horizon === "current").slice(0, 3);
919
+ for (const thread of currentThreads) attachWorkUnderstandingThreadEvidence({
920
+ threadId: thread.id,
921
+ evidenceId: evidence.id,
922
+ projectId: run.projectId
923
+ });
924
+ }
355
925
  if (run.source === "onboarding_selected_directory") setWorkDiscoveryOnboardingState({
356
926
  status: input.decision === "dismissed" ? "dismissed" : "completed",
357
927
  activeRunId: input.decision === "dismissed" ? null : run.id
@@ -0,0 +1,13 @@
1
+ import type { WorkDiscoveryDirectorySource, WorkDiscoveryPreview } from './types.js';
2
+ export declare function listWorkDiscoveryDirectorySources(options?: {
3
+ includeRevoked?: boolean;
4
+ }): WorkDiscoveryDirectorySource[];
5
+ export declare function getWorkDiscoveryDirectorySource(id: string): WorkDiscoveryDirectorySource | null;
6
+ export declare function upsertWorkDiscoveryDirectorySource(input: {
7
+ rootPath: string;
8
+ displayName: string;
9
+ fingerprint?: WorkDiscoveryPreview['fingerprint'];
10
+ scanned?: boolean;
11
+ nowMs?: number;
12
+ }): WorkDiscoveryDirectorySource;
13
+ export declare function revokeWorkDiscoveryDirectorySource(id: string, nowMs?: number): WorkDiscoveryDirectorySource | null;