@xopcai/xopc 0.0.159 → 0.0.160

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 (195) 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-CY3sizqC.js} +1 -1
  4. package/dist/gateway/static/root/assets/{activity-store-C-57rvkX.js → activity-store-3Cso_2qm.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BeVf03hx.js → agent-avatar-dicebear-B_27aaZQ.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-B1l3iii6.js +2 -0
  7. package/dist/gateway/static/root/assets/{api-BjcBIV2O.js → api-BbzB57CJ.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-BG2ulMYw.js → app-management-settings-panel-DfmyWcyh.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-0Kjenr2T.js → appearance-settings-B2v0c-K-.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-DaNFLsp0.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-ChiNnH1e.js → archive-plugin-DL5Lnx0C.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-pbBlQR-g.js → attachment-load-InuP-ZjQ.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automation-suggestion-card-CTZDOyDy.js → automation-suggestion-card-CahGuh7B.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-Cd0gMx6p.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-BeZGzpGF.js → binary-plugins-CdOTGYVu.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BnDmhN5Z.js → block-editor-D6ShK1S-.js} +3 -3
  17. package/dist/gateway/static/root/assets/browser-settings-page-BmUYDL2Z.js +8 -0
  18. package/dist/gateway/static/root/assets/{capability-presets-api-Ii36j_7v.js → capability-presets-api-BzoLm52Z.js} +1 -1
  19. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-Cl3dw4yh.js → capability-presets-settings-panel-CE7mrWtS.js} +2 -2
  20. package/dist/gateway/static/root/assets/{channel-recipient-api-CFqrSi5K.js → channel-recipient-api-DbgydMjl.js} +1 -1
  21. package/dist/gateway/static/root/assets/channels-settings-D1_gcAHK.js +1 -0
  22. package/dist/gateway/static/root/assets/channels-status-swr-Cqfqv59m.js +1 -0
  23. package/dist/gateway/static/root/assets/{connector-logo-CiLxuZ8S.js → connector-logo-C3bJC9nt.js} +1 -1
  24. package/dist/gateway/static/root/assets/connectors-page-CaLBi6Na.js +2 -0
  25. package/dist/gateway/static/root/assets/desktop-pet-settings-BrHVvbBw.js +1 -0
  26. package/dist/gateway/static/root/assets/desktop-pet-sprite-CFd1jGLJ.js +1 -0
  27. package/dist/gateway/static/root/assets/desktop-pet-wacrnJJ1.js +1 -0
  28. package/dist/gateway/static/root/assets/{directory-picker-path-field-CC2VL5Mc.js → directory-picker-path-field-BPI969w-.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dreaming-settings-KY7ZfVsy.js → dreaming-settings-iw6QXD45.js} +3 -3
  30. package/dist/gateway/static/root/assets/{extension-debug-page-C8KBeucs.js → extension-debug-page-rCHyhEr6.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-CV-5Kcyk.js → extension-page-C4gQsAPt.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-DvUtDrAu.js → extension-settings-page-DB_3eik7.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-config-api-DXfVeJLc.js → gateway-config-api-Cdt38iF2.js} +1 -1
  34. package/dist/gateway/static/root/assets/gateway-settings-DM4BgyGw.js +1 -0
  35. package/dist/gateway/static/root/assets/{gateway-startup-retry-cxQ94qMm.js → gateway-startup-retry-ChRFNjj_.js} +1 -1
  36. package/dist/gateway/static/root/assets/goal-create-dialog-BQamcEmF.js +1 -0
  37. package/dist/gateway/static/root/assets/goal-detail-page-DZUQ0Lf1.js +4 -0
  38. package/dist/gateway/static/root/assets/{goals-config-api-P8VhLqYF.js → goals-config-api-RvljeEm6.js} +1 -1
  39. package/dist/gateway/static/root/assets/goals-page-BtxVD27C.js +2 -0
  40. package/dist/gateway/static/root/assets/{goals-settings-DHXyaH_O.js → goals-settings-DMGV4S4L.js} +1 -1
  41. package/dist/gateway/static/root/assets/{heartbeat-settings-CNckP_Dv.js → heartbeat-settings-B8r5EXc5.js} +1 -1
  42. package/dist/gateway/static/root/assets/index-CHKe7nwC.js +197 -0
  43. package/dist/gateway/static/root/assets/index-CXhfUIjh.css +1 -0
  44. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-jXmv1RVX.js → keyboard-shortcuts-settings-1-LYibQ4.js} +1 -1
  45. package/dist/gateway/static/root/assets/local-app-workbench-page-CTTfyFe3.js +2 -0
  46. package/dist/gateway/static/root/assets/{local-apps-page-Cs5LKjtc.js → local-apps-page-CC4vtUUI.js} +1 -1
  47. package/dist/gateway/static/root/assets/{locale-store-C_M71MK9.js → locale-store-CPbGB_6l.js} +1 -1
  48. package/dist/gateway/static/root/assets/logs-page-Bn_taxBV.js +7 -0
  49. package/dist/gateway/static/root/assets/{markdown-split-BFqeSNte.js → markdown-split-CprEIf8A.js} +1 -1
  50. package/dist/gateway/static/root/assets/{media-plugins-Cc8379gq.js → media-plugins-BXt_Sj2O.js} +1 -1
  51. package/dist/gateway/static/root/assets/{messages-BuT0SR1R.js → messages-DDsiqdJS.js} +4 -4
  52. package/dist/gateway/static/root/assets/models-hub-panel-DJReXRP9.js +2 -0
  53. package/dist/gateway/static/root/assets/{notes-page-DlGU4ipo.js → notes-page-Wf5-eyyM.js} +1 -1
  54. package/dist/gateway/static/root/assets/notes-workbench-BbdjzYzs.js +4 -0
  55. package/dist/gateway/static/root/assets/{page-tabs-kFOswGlG.js → page-tabs-dtpK_4Fs.js} +1 -1
  56. package/dist/gateway/static/root/assets/{preview-open-alternatives-CvjuvABg.js → preview-open-alternatives-DijtEVxG.js} +1 -1
  57. package/dist/gateway/static/root/assets/project-detail-page-BwG8SOzI.js +1 -0
  58. package/dist/gateway/static/root/assets/projects-page-nUlyUtxh.js +1 -0
  59. package/dist/gateway/static/root/assets/remote-access-hub-rf7bjije.js +1 -0
  60. package/dist/gateway/static/root/assets/{save-bar-controls-DwrD7ODx.js → save-bar-controls-qhDisdqY.js} +1 -1
  61. package/dist/gateway/static/root/assets/{schedule-field-Ba4WzTmE.js → schedule-field-AhJ50NoT.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-DvydL8eF.js → schema-form-AuJg2CXU.js} +1 -1
  63. package/dist/gateway/static/root/assets/sessions-page-CSoHUe38.js +1 -0
  64. package/dist/gateway/static/root/assets/settings-advanced-gate-Db976IEa.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-collapsible-section-LaQqGGej.js → settings-collapsible-section-D5ganr_X.js} +1 -1
  66. package/dist/gateway/static/root/assets/{settings-form-section-DruI__qO.js → settings-form-section-Db3cKRsg.js} +1 -1
  67. package/dist/gateway/static/root/assets/{settings-loading-skeleton-UvA-eDhF.js → settings-loading-skeleton-D05YKT2x.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-page-5oCGSebm.js → settings-page-DYfXmfTx.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-layout-DG-XMIPu.js → settings-page-layout-Cv_Cu4I5.js} +1 -1
  70. package/dist/gateway/static/root/assets/setup-status-panel-wBWOFpvw.js +1 -0
  71. package/dist/gateway/static/root/assets/{share-preview-page-FLVeTrRt.js → share-preview-page-CYkZVuse.js} +1 -1
  72. package/dist/gateway/static/root/assets/shares-settings-BAMma1-P.js +1 -0
  73. package/dist/gateway/static/root/assets/skill-reload-api-TWxFFWxM.js +1 -0
  74. package/dist/gateway/static/root/assets/skills-page-Ca2RA29R.js +2 -0
  75. package/dist/gateway/static/root/assets/{system-settings-panel-CeK93xVi.js → system-settings-panel-C1Ng5bXh.js} +1 -1
  76. package/dist/gateway/static/root/assets/{theme-store-C8ohIHhw.js → theme-store-LMHIDR9n.js} +1 -1
  77. package/dist/gateway/static/root/assets/{typed-models-lib-D1Lr2gG0.js → typed-models-lib-Ch2Bdm_5.js} +1 -1
  78. package/dist/gateway/static/root/assets/{use-channel-catalog-BWzou5ar.js → use-channel-catalog-CZnaMOeL.js} +1 -1
  79. package/dist/gateway/static/root/assets/user-context-page-CTumZa0y.js +1 -0
  80. package/dist/gateway/static/root/assets/voice-api-key-field-DdlMxeqO.js +1 -0
  81. package/dist/gateway/static/root/assets/work-discovery-page-CcfZhdBi.js +1 -0
  82. package/dist/gateway/static/root/assets/work-item-detail-page--wxLw1p_.js +1 -0
  83. package/dist/gateway/static/root/assets/work-page-DyS0XBpV.js +1 -0
  84. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Bynqe4kV.js → workflow-run-setup-panel-BFk8TvTw.js} +2 -2
  85. package/dist/gateway/static/root/assets/workflows-page-CVVJd4gy.js +11 -0
  86. package/dist/gateway/static/root/index.html +7 -7
  87. package/dist/package.js +1 -1
  88. package/dist/src/automations/service/action-executor.js +1 -1
  89. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  90. package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
  91. package/dist/src/gateway/chat-stream/mapper.js +43 -7
  92. package/dist/src/gateway/hono/routes/home.js +15 -2
  93. package/dist/src/gateway/hono/routes/work-discovery.js +451 -0
  94. package/dist/src/gateway/service.d.ts +2 -0
  95. package/dist/src/gateway/service.js +27 -2
  96. package/dist/src/mobile/notification-service.js +1 -0
  97. package/dist/src/pets/factory.js +23 -26
  98. package/dist/src/pets/manifest.d.ts +2 -1
  99. package/dist/src/pets/manifest.js +15 -8
  100. package/dist/src/pets/validator.js +8 -3
  101. package/dist/src/proactive/calendar-signals.d.ts +4 -0
  102. package/dist/src/proactive/calendar-signals.js +120 -0
  103. package/dist/src/proactive/focus-service.d.ts +62 -0
  104. package/dist/src/proactive/focus-service.js +173 -0
  105. package/dist/src/proactive/index.d.ts +7 -0
  106. package/dist/src/proactive/index.js +7 -0
  107. package/dist/src/proactive/insight-repository.d.ts +19 -0
  108. package/dist/src/proactive/insight-repository.js +106 -0
  109. package/dist/src/proactive/run-processor.d.ts +19 -0
  110. package/dist/src/proactive/run-processor.js +125 -0
  111. package/dist/src/proactive/trial-expiry-reconciler.d.ts +5 -0
  112. package/dist/src/proactive/trial-expiry-reconciler.js +30 -0
  113. package/dist/src/proactive/types.d.ts +64 -0
  114. package/dist/src/proactive/types.js +1 -0
  115. package/dist/src/proactive/watch-repository.d.ts +28 -0
  116. package/dist/src/proactive/watch-repository.js +129 -0
  117. package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
  118. package/dist/src/storage/sqlite/knowledge-repository.js +4 -0
  119. package/dist/src/storage/sqlite/migrations/047_work_discovery_sources.sql +16 -0
  120. package/dist/src/storage/sqlite/migrations/048_work_understanding_investigations.sql +40 -0
  121. package/dist/src/storage/sqlite/migrations/049_work_understanding_threads.sql +52 -0
  122. package/dist/src/storage/sqlite/migrations/050_work_discovery_source_refreshes.sql +15 -0
  123. package/dist/src/storage/sqlite/migrations/051_focus_watches.sql +26 -0
  124. package/dist/src/storage/sqlite/migrations/052_proactive_insights.sql +25 -0
  125. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  126. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  127. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  128. package/dist/src/storage/sqlite/schema.js +1 -1
  129. package/dist/src/work-discovery/analyzer.d.ts +12 -1
  130. package/dist/src/work-discovery/analyzer.js +126 -7
  131. package/dist/src/work-discovery/candidate-discovery.d.ts +17 -0
  132. package/dist/src/work-discovery/candidate-discovery.js +279 -0
  133. package/dist/src/work-discovery/evaluation.d.ts +11 -0
  134. package/dist/src/work-discovery/evaluation.js +17 -0
  135. package/dist/src/work-discovery/governance.d.ts +25 -0
  136. package/dist/src/work-discovery/governance.js +96 -0
  137. package/dist/src/work-discovery/incremental-repository.d.ts +13 -0
  138. package/dist/src/work-discovery/incremental-repository.js +55 -0
  139. package/dist/src/work-discovery/incremental.d.ts +2 -0
  140. package/dist/src/work-discovery/incremental.js +7 -0
  141. package/dist/src/work-discovery/index.d.ts +10 -0
  142. package/dist/src/work-discovery/index.js +13 -3
  143. package/dist/src/work-discovery/investigation-repository.d.ts +16 -0
  144. package/dist/src/work-discovery/investigation-repository.js +122 -0
  145. package/dist/src/work-discovery/investigator.d.ts +55 -0
  146. package/dist/src/work-discovery/investigator.js +358 -0
  147. package/dist/src/work-discovery/probe.d.ts +22 -0
  148. package/dist/src/work-discovery/probe.js +88 -1
  149. package/dist/src/work-discovery/service.d.ts +110 -1
  150. package/dist/src/work-discovery/service.js +578 -8
  151. package/dist/src/work-discovery/source-repository.d.ts +13 -0
  152. package/dist/src/work-discovery/source-repository.js +72 -0
  153. package/dist/src/work-discovery/thread-repository.d.ts +34 -0
  154. package/dist/src/work-discovery/thread-repository.js +112 -0
  155. package/dist/src/work-discovery/thread-service.d.ts +8 -0
  156. package/dist/src/work-discovery/thread-service.js +104 -0
  157. package/dist/src/work-discovery/types.d.ts +145 -0
  158. package/package.json +1 -1
  159. package/skills/creative/hatch-pet/SKILL.md +2 -2
  160. package/dist/gateway/static/root/assets/agents-P05C4A-3.js +0 -2
  161. package/dist/gateway/static/root/assets/apps-page-DANGrBpN.js +0 -1
  162. package/dist/gateway/static/root/assets/automations-page-BXfGL_cm.js +0 -6
  163. package/dist/gateway/static/root/assets/browser-settings-page-534luV0B.js +0 -8
  164. package/dist/gateway/static/root/assets/channels-settings-M91zFJVi.js +0 -1
  165. package/dist/gateway/static/root/assets/channels-status-swr-vooEF4lG.js +0 -1
  166. package/dist/gateway/static/root/assets/connectors-page-CV5UulW6.js +0 -2
  167. package/dist/gateway/static/root/assets/desktop-pet-Cil2eSpW.js +0 -1
  168. package/dist/gateway/static/root/assets/desktop-pet-settings-DwsC6l5F.js +0 -1
  169. package/dist/gateway/static/root/assets/desktop-pet-sprite-DqZ6fbIj.js +0 -1
  170. package/dist/gateway/static/root/assets/gateway-settings-BpJ0v56l.js +0 -1
  171. package/dist/gateway/static/root/assets/goal-create-dialog-lMHD-2CX.js +0 -1
  172. package/dist/gateway/static/root/assets/goal-detail-page-yPmF-G7b.js +0 -4
  173. package/dist/gateway/static/root/assets/goals-page-BHTCKobG.js +0 -2
  174. package/dist/gateway/static/root/assets/index-BgZhEOkN.css +0 -1
  175. package/dist/gateway/static/root/assets/index-BuqGh2SW.js +0 -193
  176. package/dist/gateway/static/root/assets/local-app-workbench-page-zpp_wciE.js +0 -2
  177. package/dist/gateway/static/root/assets/logs-page-B4CRYqYR.js +0 -7
  178. package/dist/gateway/static/root/assets/models-hub-panel-1hdoAoB_.js +0 -2
  179. package/dist/gateway/static/root/assets/notes-workbench-DQEAZTA5.js +0 -4
  180. package/dist/gateway/static/root/assets/project-detail-page-Bp9bC7A6.js +0 -1
  181. package/dist/gateway/static/root/assets/projects-page-RNorFXTw.js +0 -1
  182. package/dist/gateway/static/root/assets/remote-access-hub-BqRTcM_6.js +0 -1
  183. package/dist/gateway/static/root/assets/sessions-page-B2EfW1cm.js +0 -1
  184. package/dist/gateway/static/root/assets/settings-advanced-gate-CklL85T4.js +0 -1
  185. package/dist/gateway/static/root/assets/setup-status-panel-D3my1HgB.js +0 -1
  186. package/dist/gateway/static/root/assets/shares-settings-DVxgjrsP.js +0 -1
  187. package/dist/gateway/static/root/assets/skill-reload-api-Bcu58ZaF.js +0 -1
  188. package/dist/gateway/static/root/assets/skills-page-CDd-84FE.js +0 -2
  189. package/dist/gateway/static/root/assets/sliding-segmented-uWmrxE3P.js +0 -1
  190. package/dist/gateway/static/root/assets/user-context-page-1OyJnTyR.js +0 -1
  191. package/dist/gateway/static/root/assets/voice-api-key-field-B2ncRwHS.js +0 -1
  192. package/dist/gateway/static/root/assets/work-discovery-page-BZlY4PZL.js +0 -1
  193. package/dist/gateway/static/root/assets/work-item-detail-page-DPXMrneY.js +0 -1
  194. package/dist/gateway/static/root/assets/work-page-CTERoqyv.js +0 -1
  195. package/dist/gateway/static/root/assets/workflows-page-CLgsnqFQ.js +0 -11
@@ -75,23 +75,26 @@ function esc(value) {
75
75
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
76
76
  }
77
77
  function desktopPetActionFrameCount(action) {
78
- if (action === "idle") return 6;
79
- if (action === "success" || action === "error") return 8;
78
+ if (action === "idle" || action === "sleep") return 6;
79
+ if (action === "success" || action === "concern") return 8;
80
80
  return 10;
81
81
  }
82
82
  function desktopPetActionFps(action) {
83
- if (action === "idle") return 6;
84
- if (action === "success" || action === "error") return 12;
83
+ if (action === "idle" || action === "sleep") return 6;
84
+ if (action === "success" || action === "concern") return 12;
85
85
  return 10;
86
86
  }
87
87
  function desktopPetActionLoops(action) {
88
- return action !== "success" && action !== "error";
88
+ return action === "idle" || action === "sleep" || action === "research" || action === "read" || action === "create" || action === "execute" || action === "wait";
89
89
  }
90
90
  function renderAccessory(action, frame, style) {
91
91
  const t = frame / Math.max(1, desktopPetActionFrameCount(action) - 1);
92
92
  const bob = Math.sin(t * Math.PI * 2) * 2;
93
93
  const { palette } = style;
94
- if (action === "typing") {
94
+ if (action === "sleep") return `<g fill="${palette.screen}" font-family="Arial, sans-serif" font-weight="800"><text x="70" y="28" font-size="13" opacity="${frame % 2 ? .45 : .9}">z</text><text x="80" y="17" font-size="10" opacity="${frame % 2 ? .9 : .45}">z</text></g>`;
95
+ if (action === "greet" || action === "wake" || action === "pet") return `<path d="M76 23c-7-9-19 1-7 13l7 7 7-7c12-12 0-22-7-13z" fill="${palette.cheek}" stroke="#101827" stroke-width="2"/>`;
96
+ if (action === "wait") return `<g fill="${palette.screen}" transform="translate(62 18)"><circle cx="0" cy="0" r="3" opacity="${frame % 3 === 0 ? 1 : .35}"/><circle cx="10" cy="0" r="3" opacity="${frame % 3 === 1 ? 1 : .35}"/><circle cx="20" cy="0" r="3" opacity="${frame % 3 === 2 ? 1 : .35}"/></g>`;
97
+ if (action === "create") {
95
98
  const glow = frame % 2 === 0 ? 1 : .45;
96
99
  return `
97
100
  <g transform="translate(55 ${59 + bob})">
@@ -103,7 +106,7 @@ function renderAccessory(action, frame, style) {
103
106
  <rect x="29" y="28" width="5" height="2" rx="1" fill="#e0f2fe" opacity="${glow}"/>
104
107
  </g>`;
105
108
  }
106
- if (action === "toolbox") {
109
+ if (action === "prepare") {
107
110
  const open = frame % 2 === 0 ? -11 : -3;
108
111
  return `
109
112
  <g transform="translate(6 ${61 + bob})">
@@ -114,38 +117,30 @@ function renderAccessory(action, frame, style) {
114
117
  <rect x="29" y="${8 + open / 2}" width="5" height="17" rx="2" fill="#e5e7eb" stroke="#101827" stroke-width="2" transform="rotate(25 31 24)"/>
115
118
  </g>`;
116
119
  }
117
- if (action === "search") return `
120
+ if (action === "research") return `
118
121
  <g transform="translate(58 ${58 + bob}) rotate(${frame % 2 === 0 ? -7 : 4} 18 18)">
119
122
  <circle cx="15" cy="14" r="11" fill="#e0f2fe" stroke="${palette.accent}" stroke-width="5"/>
120
123
  <rect x="24" y="24" width="17" height="7" rx="3" fill="${palette.accent}" stroke="#101827" stroke-width="3" transform="rotate(43 24 24)"/>
121
124
  </g>`;
122
- if (action === "file") return `
125
+ if (action === "read") return `
123
126
  <g transform="translate(59 ${55 + bob}) rotate(${frame % 2 === 0 ? -5 : 5} 16 20)">
124
127
  <path d="M5 1h22l9 9v31H5z" fill="#eff6ff" stroke="#101827" stroke-width="3" stroke-linejoin="round"/>
125
128
  <path d="M27 1v10h9" fill="${palette.accent}" stroke="#101827" stroke-width="3" stroke-linejoin="round"/>
126
129
  <rect x="12" y="20" width="16" height="3" rx="1.5" fill="${palette.body}"/>
127
130
  <rect x="12" y="28" width="12" height="3" rx="1.5" fill="${palette.body}"/>
128
131
  </g>`;
129
- if (action === "terminal") return `
132
+ if (action === "execute") return `
130
133
  <g transform="translate(55 ${61 + bob})">
131
134
  <rect x="0" y="0" width="39" height="29" rx="7" fill="#111827" stroke="#101827" stroke-width="3"/>
132
135
  <path d="M10 10l6 5-6 5" fill="none" stroke="#86efac" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" opacity="${frame % 2 === 0 ? 1 : .4}"/>
133
136
  <path d="M20 20h9" stroke="#86efac" stroke-width="3" stroke-linecap="round"/>
134
- </g>`;
135
- if (action === "browser") return `
136
- <g transform="translate(55 ${58 + bob})">
137
- <rect x="0" y="0" width="40" height="31" rx="7" fill="#e0f2fe" stroke="#101827" stroke-width="3"/>
138
- <path d="M1 11h38" stroke="${palette.accent}" stroke-width="8"/>
139
- <circle cx="10" cy="10" r="2" fill="#101827"/>
140
- <circle cx="17" cy="10" r="2" fill="#101827"/>
141
- <rect x="11" y="21" width="20" height="4" rx="2" fill="${palette.body}"/>
142
137
  </g>`;
143
138
  if (action === "success") return `
144
139
  <g fill="#facc15" transform="translate(61 ${12 + bob})">
145
140
  <path d="M12 0l3 8 8 3-8 3-3 8-3-8-8-3 8-3z"/>
146
141
  <path d="M-12 18l2 5 5 2-5 2-2 5-2-5-5-2 5-2z" opacity="0.78"/>
147
142
  </g>`;
148
- if (action === "error") return `
143
+ if (action === "concern") return `
149
144
  <g transform="translate(61 ${56 + bob})">
150
145
  <path d="M18 0l18 32H0z" fill="#facc15" stroke="#101827" stroke-width="3" stroke-linejoin="round"/>
151
146
  <text x="18" y="26" text-anchor="middle" font-family="Arial, sans-serif" font-size="22" font-weight="900" fill="#101827">!</text>
@@ -170,14 +165,14 @@ function renderHead(style) {
170
165
  }
171
166
  function renderFrame(style, action, frame) {
172
167
  const t = frame / Math.max(1, desktopPetActionFrameCount(action) - 1);
173
- const bob = Math.sin(t * Math.PI * 2) * (action === "idle" ? 2.5 : 1.5);
174
- const tilt = action === "toolbox" ? Math.sin(t * Math.PI * 2) * 2.5 : 0;
168
+ const bob = action === "sleep" ? 7 : action === "pickedUp" ? -6 : action === "released" ? 4 : Math.sin(t * Math.PI * 2) * (action === "idle" ? 2.5 : 1.5);
169
+ const tilt = action === "prepare" ? Math.sin(t * Math.PI * 2) * 2.5 : action === "pet" ? Math.sin(t * Math.PI) * 5 : 0;
175
170
  const { palette } = style;
176
- const face = action === "error" ? "#3f0f18" : palette.face;
177
- const eye = action === "error" ? "#fca5a5" : palette.screen;
178
- const mouth = action === "success" ? "M39 45q5 5 10 0" : "M42 46h9";
179
- const leftArm = action === "typing" ? 23 + frame % 2 * 13 : action === "toolbox" ? 39 + frame % 2 * 10 : 9;
180
- const rightArm = action === "typing" ? -23 - frame % 2 * 13 : action === "toolbox" ? -39 - frame % 2 * 10 : -9;
171
+ const face = action === "concern" ? "#3f0f18" : palette.face;
172
+ const eye = action === "concern" ? "#fca5a5" : palette.screen;
173
+ const mouth = action === "success" || action === "greet" || action === "pet" ? "M39 45q5 5 10 0" : "M42 46h9";
174
+ const leftArm = action === "create" || action === "execute" ? 23 + frame % 2 * 13 : action === "prepare" || action === "read" ? 39 + frame % 2 * 10 : action === "pickedUp" ? 58 : 9;
175
+ const rightArm = action === "create" || action === "execute" ? -23 - frame % 2 * 13 : action === "prepare" || action === "read" ? -39 - frame % 2 * 10 : action === "greet" || action === "wake" ? -48 - frame % 2 * 12 : action === "pickedUp" ? -58 : -9;
181
176
  return `
182
177
  <g transform="translate(0 ${bob}) rotate(${tilt} 48 76)">
183
178
  ${renderHead(style)}
@@ -287,6 +282,7 @@ async function createDesktopPetPackage(input) {
287
282
  await mkdir(targetRoot, { recursive: true });
288
283
  const { id, dir } = await resolvePackageDir(targetRoot, (input.id?.trim() ? normalizePackageId(input.id) : null) || slugify(input.name?.trim() || titleFromPrompt(prompt), `pet-${hashString(prompt).toString(36)}`), input.overwrite === true);
289
284
  const existingManifest = input.overwrite === true ? await readExistingManifest(dir) : null;
285
+ if (existingManifest && existingManifest.schemaVersion !== 2) throw new Error(`Existing pet package must use schemaVersion 2`);
290
286
  const existingName = typeof existingManifest?.name === "string" ? existingManifest.name.trim() : "";
291
287
  const persona = normalizePersona(input.persona ?? existingManifest?.persona);
292
288
  const baseName = clampText(input.name?.trim() || existingName || titleFromPrompt(prompt), 36);
@@ -296,6 +292,7 @@ async function createDesktopPetPackage(input) {
296
292
  const thumbnailPath = join(tempDir, "thumbnail.svg");
297
293
  const manifestPath = join(tempDir, "manifest.json");
298
294
  const manifest = {
295
+ schemaVersion: 2,
299
296
  id,
300
297
  name: baseName,
301
298
  description,
@@ -1,2 +1,3 @@
1
- export declare const DESKTOP_PET_ACTIONS: readonly ["idle", "typing", "toolbox", "search", "file", "terminal", "browser", "success", "error"];
1
+ export declare const DESKTOP_PET_SCHEMA_VERSION: 2;
2
+ export declare const DESKTOP_PET_ACTIONS: readonly ["idle", "sleep", "wake", "greet", "prepare", "research", "read", "create", "execute", "wait", "success", "concern", "pet", "pickedUp", "released"];
2
3
  export type DesktopPetPackageAction = (typeof DESKTOP_PET_ACTIONS)[number];
@@ -1,14 +1,21 @@
1
1
  //#region src/pets/manifest.ts
2
+ const DESKTOP_PET_SCHEMA_VERSION = 2;
2
3
  const DESKTOP_PET_ACTIONS = [
3
4
  "idle",
4
- "typing",
5
- "toolbox",
6
- "search",
7
- "file",
8
- "terminal",
9
- "browser",
5
+ "sleep",
6
+ "wake",
7
+ "greet",
8
+ "prepare",
9
+ "research",
10
+ "read",
11
+ "create",
12
+ "execute",
13
+ "wait",
10
14
  "success",
11
- "error"
15
+ "concern",
16
+ "pet",
17
+ "pickedUp",
18
+ "released"
12
19
  ];
13
20
  //#endregion
14
- export { DESKTOP_PET_ACTIONS };
21
+ export { DESKTOP_PET_ACTIONS, DESKTOP_PET_SCHEMA_VERSION };
@@ -135,6 +135,7 @@ async function validateDesktopPetPackage(dir) {
135
135
  };
136
136
  }
137
137
  if (typeof manifest.id !== "string" || !manifest.id.trim()) details.push("id is required");
138
+ if (manifest.schemaVersion !== 2) details.push(`schemaVersion must be 2`);
138
139
  if (typeof manifest.name !== "string" || !manifest.name.trim()) details.push("name is required");
139
140
  if (typeof manifest.description !== "string" || !manifest.description.trim()) details.push("description is required");
140
141
  if (positiveNumber(manifest.canvasWidth) === null || positiveNumber(manifest.canvasHeight) === null) details.push("canvasWidth and canvasHeight must be positive numbers");
@@ -143,9 +144,13 @@ async function validateDesktopPetPackage(dir) {
143
144
  const rawAnimations = manifest.animations && typeof manifest.animations === "object" ? manifest.animations : null;
144
145
  if (!rawAnimations) details.push("animations is required");
145
146
  const animations = [];
146
- if (rawAnimations) for (const action of DESKTOP_PET_ACTIONS) {
147
- const animation = parseAnimation(action, rawAnimations[action], details);
148
- if (animation) animations.push(animation);
147
+ if (rawAnimations) {
148
+ const supportedActions = new Set(DESKTOP_PET_ACTIONS);
149
+ for (const action of Object.keys(rawAnimations)) if (!supportedActions.has(action)) details.push(`${action}: unsupported animation action`);
150
+ for (const action of DESKTOP_PET_ACTIONS) {
151
+ const animation = parseAnimation(action, rawAnimations[action], details);
152
+ if (animation) animations.push(animation);
153
+ }
149
154
  }
150
155
  for (const animation of animations) {
151
156
  const sourcePath = safeResolve(dir, animation.src);
@@ -0,0 +1,4 @@
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[];
@@ -0,0 +1,120 @@
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 };
@@ -0,0 +1,62 @@
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 {};
@@ -0,0 +1,173 @@
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 };
@@ -0,0 +1,7 @@
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';
@@ -0,0 +1,7 @@
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 };
@@ -0,0 +1,19 @@
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
+ nowMs?: number;
17
+ }): ProactiveInsight | null;
18
+ export declare function setProactiveInsightStatus(id: string, status: ProactiveInsightStatus, nowMs?: number, expectedStatus?: ProactiveInsightStatus): ProactiveInsight | null;
19
+ export declare function claimProactiveInsightApproval(id: string, nowMs?: number): ProactiveInsight | null;