@xopcai/xopc 0.0.160 → 0.0.162

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 (248) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/activity-store-hpcNv9MZ.js +1 -0
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_27aaZQ.js → agent-avatar-dicebear-Zf9UQEmQ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DfVkZlHc.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-BbzB57CJ.js → api-Dnatri09.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-DfmyWcyh.js → app-management-settings-panel-BBTR9wJP.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-B2v0c-K-.js → appearance-settings-C2zpLCHD.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-BMtAa4Ra.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-DL5Lnx0C.js → archive-plugin-9eR_ODY1.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-InuP-ZjQ.js → attachment-load-DPuWYUeX.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-CahGuh7B.js → automation-suggestion-card-Dw49OJRl.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-page-BiSAMYTr.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-CdOTGYVu.js → binary-plugins-BdkJpDFm.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-D6ShK1S-.js → block-editor-CAi7SXYU.js} +47 -47
  16. package/dist/gateway/static/root/assets/browser-settings-page-DHmaEJS2.js +8 -0
  17. package/dist/gateway/static/root/assets/browser-workflow-inputs-Dx6wkGz1.js +1 -0
  18. package/dist/gateway/static/root/assets/browser-workflows-page-Skertc-A.js +3 -0
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-B5wSgf4f.js +2 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BzoLm52Z.js → capability-presets-api-CNFl7dM3.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DyvFZwBj.js +2 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-DbgydMjl.js → channel-recipient-api-DYQyGDw4.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-BBKEqDZn.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-Drk110ve.js +1 -0
  25. package/dist/gateway/static/root/assets/check-DUBLcKHA.js +1 -0
  26. package/dist/gateway/static/root/assets/circle-alert-BEjgurr2.js +1 -0
  27. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
  28. package/dist/gateway/static/root/assets/{connector-logo-C3bJC9nt.js → connector-logo-Bng6kxYF.js} +1 -1
  29. package/dist/gateway/static/root/assets/connectors-page-HpgaUDQ1.js +2 -0
  30. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
  31. package/dist/gateway/static/root/assets/desktop-pet-Bpf6oegd.js +1 -0
  32. package/dist/gateway/static/root/assets/{desktop-pet-settings-BrHVvbBw.js → desktop-pet-settings-BVUyefSd.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-sprite-CFd1jGLJ.js → desktop-pet-sprite-DTqXSpqf.js} +1 -1
  34. package/dist/gateway/static/root/assets/{directory-picker-path-field-BPI969w-.js → directory-picker-path-field-DjSZAPz_.js} +1 -1
  35. package/dist/gateway/static/root/assets/{dreaming-settings-iw6QXD45.js → dreaming-settings-CAZk2AM4.js} +3 -3
  36. package/dist/gateway/static/root/assets/{extension-debug-page-rCHyhEr6.js → extension-debug-page-C2F6vTTd.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-C4gQsAPt.js → extension-page-AnIt4bn4.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-settings-page-DB_3eik7.js → extension-settings-page-CLSc6682.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-Cdt38iF2.js → gateway-config-api-DLFyZv33.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-settings-DM4BgyGw.js → gateway-settings-DnQAA-qq.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-ChRFNjj_.js → gateway-startup-retry-DbzLyJ3R.js} +1 -1
  42. package/dist/gateway/static/root/assets/goal-create-dialog-DrnKFC6M.js +1 -0
  43. package/dist/gateway/static/root/assets/goal-detail-page-Cw1hpJkZ.js +4 -0
  44. package/dist/gateway/static/root/assets/{goals-config-api-RvljeEm6.js → goals-config-api-REmr3QCr.js} +1 -1
  45. package/dist/gateway/static/root/assets/goals-page-BDGkTVma.js +2 -0
  46. package/dist/gateway/static/root/assets/{goals-settings-DMGV4S4L.js → goals-settings-Dz0F3uRO.js} +1 -1
  47. package/dist/gateway/static/root/assets/{heartbeat-settings-B8r5EXc5.js → heartbeat-settings-CQFY5gYs.js} +1 -1
  48. package/dist/gateway/static/root/assets/index-C8JkTS6d.js +199 -0
  49. package/dist/gateway/static/root/assets/index-hmrG55qg.css +1 -0
  50. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-1-LYibQ4.js → keyboard-shortcuts-settings-BnOQXU5k.js} +1 -1
  51. package/dist/gateway/static/root/assets/local-app-workbench-page-Bdef1b7F.js +2 -0
  52. package/dist/gateway/static/root/assets/{local-apps-page-CC4vtUUI.js → local-apps-page-KsOtWOyM.js} +1 -1
  53. package/dist/gateway/static/root/assets/{locale-store-CPbGB_6l.js → locale-store-0lpYdNDr.js} +1 -1
  54. package/dist/gateway/static/root/assets/{logs-page-Bn_taxBV.js → logs-page-CwLPgrWh.js} +3 -3
  55. package/dist/gateway/static/root/assets/{markdown-split-CprEIf8A.js → markdown-split-D5GRg10r.js} +1 -1
  56. package/dist/gateway/static/root/assets/{media-plugins-BXt_Sj2O.js → media-plugins-C1ryULGs.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-BwQ3WssU.js +5 -0
  58. package/dist/gateway/static/root/assets/{notes-page-Wf5-eyyM.js → notes-page-CIeZ1_DT.js} +1 -1
  59. package/dist/gateway/static/root/assets/notes-workbench-Cf06q19x.js +4 -0
  60. package/dist/gateway/static/root/assets/{page-tabs-dtpK_4Fs.js → page-tabs-Caj1-E_X.js} +1 -1
  61. package/dist/gateway/static/root/assets/{preview-open-alternatives-DijtEVxG.js → preview-open-alternatives-DKwEce-9.js} +1 -1
  62. package/dist/gateway/static/root/assets/product-delivery-BTRT9kCS.js +1 -0
  63. package/dist/gateway/static/root/assets/product-open-page-B90ZskkN.js +1 -0
  64. package/dist/gateway/static/root/assets/project-detail-page-SHTurM4t.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-BcC2qUAw.js +1 -0
  66. package/dist/gateway/static/root/assets/remote-access-hub-6vGefBHv.js +1 -0
  67. package/dist/gateway/static/root/assets/save-bar-controls-BDYt53uQ.js +1 -0
  68. package/dist/gateway/static/root/assets/{schedule-field-AhJ50NoT.js → schedule-field-Bcdni4Pj.js} +1 -1
  69. package/dist/gateway/static/root/assets/{schema-form-AuJg2CXU.js → schema-form-D7oCARF7.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-C5014a53.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-CDY3ZI1K.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-collapsible-section-D5ganr_X.js → settings-collapsible-section-6eNF8Jey.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-form-section-Db3cKRsg.js → settings-form-section-CARTHCxH.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-loading-skeleton-D05YKT2x.js → settings-loading-skeleton-DEwYqESe.js} +1 -1
  75. package/dist/gateway/static/root/assets/settings-page-B6vVdHeQ.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-page-layout-Cv_Cu4I5.js → settings-page-layout-D3srt5Bi.js} +1 -1
  77. package/dist/gateway/static/root/assets/setup-status-panel-z-rF0Hdg.js +1 -0
  78. package/dist/gateway/static/root/assets/{share-preview-page-CYkZVuse.js → share-preview-page-Ck9SxiXw.js} +1 -1
  79. package/dist/gateway/static/root/assets/shares-settings-CHZFXE_d.js +1 -0
  80. package/dist/gateway/static/root/assets/skill-reload-api-B7p2QNXt.js +1 -0
  81. package/dist/gateway/static/root/assets/skills-page-ncw3tX9P.js +2 -0
  82. package/dist/gateway/static/root/assets/{system-settings-panel-C1Ng5bXh.js → system-settings-panel-DLBUQSk2.js} +1 -1
  83. package/dist/gateway/static/root/assets/{theme-store-LMHIDR9n.js → theme-store-C1oaqeD2.js} +1 -1
  84. package/dist/gateway/static/root/assets/{typed-models-lib-Ch2Bdm_5.js → typed-models-lib-Divbg_C4.js} +1 -1
  85. package/dist/gateway/static/root/assets/{use-channel-catalog-CZnaMOeL.js → use-channel-catalog-CP9a_rAf.js} +1 -1
  86. package/dist/gateway/static/root/assets/user-context-page-iYfeSLKI.js +1 -0
  87. package/dist/gateway/static/root/assets/voice-api-key-field-CrwkicvT.js +1 -0
  88. package/dist/gateway/static/root/assets/work-discovery-page-BQWxyPg8.js +1 -0
  89. package/dist/gateway/static/root/assets/work-item-detail-page-50ZzGay5.js +1 -0
  90. package/dist/gateway/static/root/assets/work-page-DPqEahx7.js +1 -0
  91. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BFk8TvTw.js → workflow-run-setup-panel-DbDPYQwB.js} +2 -2
  92. package/dist/gateway/static/root/assets/workflows-page-C3eIC5HZ.js +11 -0
  93. package/dist/gateway/static/root/index.html +12 -10
  94. package/dist/package.js +1 -1
  95. package/dist/src/agent/agent-manager.d.ts +1 -0
  96. package/dist/src/agent/agent-manager.js +1 -0
  97. package/dist/src/agent/client-error-format.js +3 -3
  98. package/dist/src/agent/outcomes/task-evaluation.d.ts +20 -0
  99. package/dist/src/agent/outcomes/task-evaluation.js +48 -0
  100. package/dist/src/agent/outcomes/task-verifier.d.ts +29 -0
  101. package/dist/src/agent/outcomes/task-verifier.js +71 -0
  102. package/dist/src/agent/prompt/memory/index.js +1 -1
  103. package/dist/src/agent/prompt/service-prompt-builder.js +32 -1
  104. package/dist/src/agent/service.js +1 -0
  105. package/dist/src/agent/service.types.d.ts +1 -0
  106. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +1 -7
  107. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +2 -73
  108. package/dist/src/agent/tools/browser/tool/schemas.d.ts +1 -13
  109. package/dist/src/agent/tools/browser/tool/schemas.js +1 -9
  110. package/dist/src/agent/tools/browser-recipe-tool.d.ts +12 -0
  111. package/dist/src/agent/tools/browser-recipe-tool.js +113 -0
  112. package/dist/src/agent/tools/factory.d.ts +2 -0
  113. package/dist/src/agent/tools/factory.js +2 -0
  114. package/dist/src/agent/tools/index.d.ts +1 -0
  115. package/dist/src/agent/tools/index.js +2 -1
  116. package/dist/src/automations/domain/types.d.ts +13 -0
  117. package/dist/src/automations/domain/validation.d.ts +44 -24
  118. package/dist/src/automations/domain/validation.js +27 -18
  119. package/dist/src/automations/draft/automation-draft-validator.d.ts +6 -1
  120. package/dist/src/automations/draft/automation-draft-validator.js +1 -0
  121. package/dist/src/automations/service/action-executor.d.ts +1 -0
  122. package/dist/src/automations/service/action-executor.js +22 -0
  123. package/dist/src/browser/index.d.ts +0 -1
  124. package/dist/src/browser/index.js +1 -2
  125. package/dist/src/browser/pipeline/runner.d.ts +9 -2
  126. package/dist/src/browser/pipeline/runner.js +151 -105
  127. package/dist/src/browser/pipeline/schema.d.ts +21 -15
  128. package/dist/src/browser/pipeline/schema.js +93 -99
  129. package/dist/src/browser/recipes/index.d.ts +3 -0
  130. package/dist/src/browser/recipes/index.js +3 -0
  131. package/dist/src/browser/recipes/repository.d.ts +13 -0
  132. package/dist/src/browser/recipes/repository.js +81 -0
  133. package/dist/src/browser/recipes/runtime-service.d.ts +6 -0
  134. package/dist/src/browser/recipes/runtime-service.js +30 -0
  135. package/dist/src/browser/recipes/service.d.ts +36 -0
  136. package/dist/src/browser/recipes/service.js +186 -0
  137. package/dist/src/browser/recipes/types.d.ts +36 -0
  138. package/dist/src/browser/recipes/types.js +1 -0
  139. package/dist/src/cli/commands/browser-cli-helpers.js +6 -12
  140. package/dist/src/cli/commands/browser.js +4 -3
  141. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  142. package/dist/src/config/schema.d.ts +3 -3
  143. package/dist/src/config/schema.js +21 -21
  144. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
  145. package/dist/src/gateway/hono/routes/browser-workflows.d.ts +3 -0
  146. package/dist/src/gateway/hono/routes/browser-workflows.js +78 -0
  147. package/dist/src/gateway/hono/routes/home.js +1 -0
  148. package/dist/src/gateway/hono/routes/index.js +4 -0
  149. package/dist/src/gateway/hono/routes/interaction-state.d.ts +3 -0
  150. package/dist/src/gateway/hono/routes/interaction-state.js +45 -0
  151. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  152. package/dist/src/gateway/hono/routes/memory.js +33 -4
  153. package/dist/src/gateway/hono/routes/task-outcomes.d.ts +3 -0
  154. package/dist/src/gateway/hono/routes/task-outcomes.js +109 -0
  155. package/dist/src/gateway/hono/routes/you.d.ts +10 -2
  156. package/dist/src/gateway/hono/routes/you.js +184 -28
  157. package/dist/src/gateway/hono/sse.d.ts +2 -0
  158. package/dist/src/gateway/hono/sse.js +10 -3
  159. package/dist/src/gateway/run-loop.js +17 -7
  160. package/dist/src/gateway/server.d.ts +1 -0
  161. package/dist/src/gateway/server.js +9 -0
  162. package/dist/src/gateway/service/run-gateway-agent.js +84 -0
  163. package/dist/src/gateway/service.d.ts +3 -0
  164. package/dist/src/gateway/service.js +14 -0
  165. package/dist/src/local-apps/preview-runtime-bridge.d.ts +1 -1
  166. package/dist/src/local-apps/preview-runtime-bridge.js +14 -11
  167. package/dist/src/proactive/insight-repository.d.ts +2 -0
  168. package/dist/src/proactive/insight-repository.js +5 -2
  169. package/dist/src/proactive/run-processor.js +22 -1
  170. package/dist/src/proactive/types.d.ts +2 -0
  171. package/dist/src/proactive/value-score.d.ts +13 -0
  172. package/dist/src/proactive/value-score.js +30 -0
  173. package/dist/src/share/share-types.js +5 -5
  174. package/dist/src/share/site-share-types.d.ts +1 -1
  175. package/dist/src/share/site-share-types.js +5 -5
  176. package/dist/src/storage/sqlite/index.d.ts +3 -0
  177. package/dist/src/storage/sqlite/index.js +4 -1
  178. package/dist/src/storage/sqlite/interaction-state-repository.d.ts +17 -0
  179. package/dist/src/storage/sqlite/interaction-state-repository.js +60 -0
  180. package/dist/src/storage/sqlite/memory-records-repository.js +1 -1
  181. package/dist/src/storage/sqlite/migrations/053_browser_recipes.sql +45 -0
  182. package/dist/src/storage/sqlite/migrations/054_task_outcomes.sql +24 -0
  183. package/dist/src/storage/sqlite/migrations/055_relationship_settings.sql +14 -0
  184. package/dist/src/storage/sqlite/migrations/056_task_verification.sql +6 -0
  185. package/dist/src/storage/sqlite/migrations/057_interaction_states.sql +11 -0
  186. package/dist/src/storage/sqlite/migrations/058_proactive_value.sql +3 -0
  187. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  188. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  189. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  190. package/dist/src/storage/sqlite/relationship-settings-repository.d.ts +17 -0
  191. package/dist/src/storage/sqlite/relationship-settings-repository.js +64 -0
  192. package/dist/src/storage/sqlite/schema.js +1 -1
  193. package/dist/src/storage/sqlite/schema.sql +46 -0
  194. package/dist/src/storage/sqlite/task-outcome-repository.d.ts +90 -0
  195. package/dist/src/storage/sqlite/task-outcome-repository.js +138 -0
  196. package/dist/src/user-context/interaction-state.d.ts +13 -0
  197. package/dist/src/user-context/interaction-state.js +69 -0
  198. package/dist/src/user-context/memory-use-audit.d.ts +10 -0
  199. package/dist/src/user-context/memory-use-audit.js +25 -0
  200. package/dist/src/user-context/personal-playbook.d.ts +11 -0
  201. package/dist/src/user-context/personal-playbook.js +41 -0
  202. package/dist/src/user-context/projection.d.ts +4 -0
  203. package/dist/src/user-context/projection.js +5 -1
  204. package/dist/src/user-context/relationship-continuity.d.ts +14 -0
  205. package/dist/src/user-context/relationship-continuity.js +51 -0
  206. package/package.json +1 -1
  207. package/dist/gateway/static/root/assets/action-boundary-settings-panel-CY3sizqC.js +0 -1
  208. package/dist/gateway/static/root/assets/activity-store-3Cso_2qm.js +0 -1
  209. package/dist/gateway/static/root/assets/agents-B1l3iii6.js +0 -2
  210. package/dist/gateway/static/root/assets/apps-page-DaNFLsp0.js +0 -1
  211. package/dist/gateway/static/root/assets/automations-page-Cd0gMx6p.js +0 -6
  212. package/dist/gateway/static/root/assets/browser-settings-page-BmUYDL2Z.js +0 -8
  213. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CE7mrWtS.js +0 -2
  214. package/dist/gateway/static/root/assets/channels-settings-D1_gcAHK.js +0 -1
  215. package/dist/gateway/static/root/assets/channels-status-swr-Cqfqv59m.js +0 -1
  216. package/dist/gateway/static/root/assets/check-BODqo66o.js +0 -1
  217. package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +0 -1
  218. package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +0 -1
  219. package/dist/gateway/static/root/assets/connectors-page-CaLBi6Na.js +0 -2
  220. package/dist/gateway/static/root/assets/desktop-pet-wacrnJJ1.js +0 -1
  221. package/dist/gateway/static/root/assets/goal-create-dialog-BQamcEmF.js +0 -1
  222. package/dist/gateway/static/root/assets/goal-detail-page-DZUQ0Lf1.js +0 -4
  223. package/dist/gateway/static/root/assets/goals-page-BtxVD27C.js +0 -2
  224. package/dist/gateway/static/root/assets/index-CHKe7nwC.js +0 -197
  225. package/dist/gateway/static/root/assets/index-CXhfUIjh.css +0 -1
  226. package/dist/gateway/static/root/assets/local-app-workbench-page-CTTfyFe3.js +0 -2
  227. package/dist/gateway/static/root/assets/messages-DDsiqdJS.js +0 -5
  228. package/dist/gateway/static/root/assets/models-hub-panel-DJReXRP9.js +0 -2
  229. package/dist/gateway/static/root/assets/notes-workbench-BbdjzYzs.js +0 -4
  230. package/dist/gateway/static/root/assets/project-detail-page-BwG8SOzI.js +0 -1
  231. package/dist/gateway/static/root/assets/projects-page-nUlyUtxh.js +0 -1
  232. package/dist/gateway/static/root/assets/remote-access-hub-rf7bjije.js +0 -1
  233. package/dist/gateway/static/root/assets/save-bar-controls-qhDisdqY.js +0 -1
  234. package/dist/gateway/static/root/assets/sessions-page-CSoHUe38.js +0 -1
  235. package/dist/gateway/static/root/assets/settings-advanced-gate-Db976IEa.js +0 -1
  236. package/dist/gateway/static/root/assets/settings-page-DYfXmfTx.js +0 -1
  237. package/dist/gateway/static/root/assets/setup-status-panel-wBWOFpvw.js +0 -1
  238. package/dist/gateway/static/root/assets/shares-settings-BAMma1-P.js +0 -1
  239. package/dist/gateway/static/root/assets/skill-reload-api-TWxFFWxM.js +0 -1
  240. package/dist/gateway/static/root/assets/skills-page-Ca2RA29R.js +0 -2
  241. package/dist/gateway/static/root/assets/user-context-page-CTumZa0y.js +0 -1
  242. package/dist/gateway/static/root/assets/voice-api-key-field-DdlMxeqO.js +0 -1
  243. package/dist/gateway/static/root/assets/work-discovery-page-CcfZhdBi.js +0 -1
  244. package/dist/gateway/static/root/assets/work-item-detail-page--wxLw1p_.js +0 -1
  245. package/dist/gateway/static/root/assets/work-page-DyS0XBpV.js +0 -1
  246. package/dist/gateway/static/root/assets/workflows-page-CVVJd4gy.js +0 -11
  247. package/dist/src/browser/pipeline/source.d.ts +0 -9
  248. package/dist/src/browser/pipeline/source.js +0 -77
@@ -78,6 +78,8 @@ import { runBootstrapMigrationsSync } from "../migrations/runner.js";
78
78
  import { MobileNotificationService } from "../mobile/notification-service.js";
79
79
  import { LocalAppService } from "../local-apps/service.js";
80
80
  import "../local-apps/index.js";
81
+ import { createRuntimeBrowserRecipeService } from "../browser/recipes/runtime-service.js";
82
+ import "../browser/recipes/index.js";
81
83
  import { scheduleGatewayUpdateCheck } from "../infra/update-startup.js";
82
84
  import { resolveChannelConnectDeferSet } from "./resolve-channel-connect-defer.js";
83
85
  import { restartGatewayProcessWithFreshPid } from "./respawn.js";
@@ -108,6 +110,7 @@ var GatewayService = class {
108
110
  _agentService = null;
109
111
  channelManager;
110
112
  automationService;
113
+ browserRecipeService = null;
111
114
  notesService;
112
115
  extensionLoader = null;
113
116
  extensionMetadataSnapshot = null;
@@ -126,6 +129,13 @@ var GatewayService = class {
126
129
  getConfig() {
127
130
  return this.config;
128
131
  }
132
+ get browserRecipes() {
133
+ if (!this.browserRecipeService) this.browserRecipeService = createRuntimeBrowserRecipeService({
134
+ getConfig: () => this.config,
135
+ emit: (type, payload) => this.emit(type, payload)
136
+ });
137
+ return this.browserRecipeService;
138
+ }
129
139
  stopGatewayUpdateCheck = null;
130
140
  /** When set (e.g. by `GatewayServer`), `triggerGatewayProcessRestart` can stop HTTP then exit. */
131
141
  gatewayShutdownForRestart = null;
@@ -322,6 +332,7 @@ var GatewayService = class {
322
332
  },
323
333
  extensionRegistry: this.extensionLoader?.getRegistry(),
324
334
  getAutomationService: () => this.automationService,
335
+ getBrowserRecipeService: () => this.browserRecipes,
325
336
  getNotesService: () => this.notesService,
326
337
  getProjectService: () => this.projects,
327
338
  getWorkItemService: () => new WorkItemService(),
@@ -361,6 +372,7 @@ var GatewayService = class {
361
372
  getDefaultAgentId: () => getDefaultAgentId(this.config),
362
373
  getProjectWorkspaceRoot: (projectId) => this.projects.get(projectId)?.workspaceRoot,
363
374
  workflowRunService: this.createWorkflowRunService(),
375
+ browserRecipeService: this.browserRecipes,
364
376
  onRunCompleted: (run) => this.handleAutomationRunCompleted(run)
365
377
  });
366
378
  this._agentService.persistentGoals.setWebchatContinuationScheduler((sessionKey, message) => {
@@ -671,6 +683,7 @@ var GatewayService = class {
671
683
  agentService: this.agentService,
672
684
  getDefaultAgentId: () => getDefaultAgentId(this.config),
673
685
  workflowRunService: this.createWorkflowRunService(),
686
+ browserRecipeService: this.browserRecipes,
674
687
  onRunCompleted: (run) => this.handleAutomationRunCompleted(run)
675
688
  });
676
689
  this.startAutomationProductEventBridge();
@@ -822,6 +835,7 @@ var GatewayService = class {
822
835
  this.connectorMemorySyncCoordinator = null;
823
836
  this.connectedKnowledgeCoordinator?.stop();
824
837
  this.connectedKnowledgeCoordinator = null;
838
+ await this.browserRecipeService?.shutdown();
825
839
  if (this.browserExtensionRelease) {
826
840
  await this.browserExtensionRelease();
827
841
  this.browserExtensionRelease = null;
@@ -1,4 +1,4 @@
1
1
  import type { LocalAppAcceptanceConfig } from './acceptance.js';
2
- export declare const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = "(() => {\n let hostPort = null;\n const pending = [];\n const send = (type, detail) => {\n const message = { source: 'xopc-local-app-preview', version: 1, type, detail };\n if (hostPort) hostPort.postMessage(message);\n else pending.push(message);\n };\n const connect = (event) => {\n const message = event.data;\n if (event.source !== parent || message?.source !== 'xopc-local-app-host' || message?.version !== 1 || message?.type !== 'connect' || !event.ports[0]) return;\n event.stopImmediatePropagation();\n removeEventListener('message', connect, true);\n hostPort = event.ports[0];\n hostPort.start();\n for (const queued of pending.splice(0)) hostPort.postMessage(queued);\n };\n addEventListener('message', connect, true);\n const text = (value) => String(value ?? '').slice(0, 500);\n let runtimeFailure = '';\n const visible = (element) => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity) !== 0 && rect.width > 0 && rect.height > 0;\n };\n const accessibleName = (element) => {\n const labelledBy = text(element.getAttribute('aria-labelledby'));\n const labelledText = labelledBy.split(/\\s+/).map((id) => document.getElementById(id)?.textContent).filter(Boolean).join(' ');\n return text(element.getAttribute('aria-label') || labelledText || element.labels?.[0]?.textContent || element.textContent || element.getAttribute('alt') || element.getAttribute('title') || element.getAttribute('placeholder') || element.getAttribute('name')).trim();\n };\n const target = (id) => Array.from(document.querySelectorAll('[data-xopc-test-id]'))\n .find((element) => element.getAttribute('data-xopc-test-id') === id);\n const pause = () => new Promise((resolve) => setTimeout(resolve, 50));\n const readCriteria = () => {\n const encoded = document.querySelector('meta[name=\"xopc-local-app-acceptance\"]')?.content;\n if (!encoded) return { schemaVersion: 1, scenarios: [] };\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const bytes = Uint8Array.from(atob(padded), (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n };\n addEventListener('error', (event) => {\n runtimeFailure = text(event.message || 'A preview resource failed to load');\n send('error', {\n kind: 'script_error',\n message: runtimeFailure,\n filename: text(event.filename),\n line: Number(event.lineno) || undefined,\n column: Number(event.colno) || undefined,\n });\n }, true);\n addEventListener('unhandledrejection', (event) => {\n runtimeFailure = text(event.reason instanceof Error ? event.reason.message : event.reason);\n send('error', { kind: 'unhandled_rejection', message: runtimeFailure });\n });\n const runAcceptance = () => {\n const checks = [];\n const bodyReady = Boolean(document.body);\n checks.push({ id: 'document', status: bodyReady ? 'passed' : 'failed', message: bodyReady ? 'Preview document loaded' : 'Preview document has no body' });\n const contentNodes = bodyReady ? Array.from(document.body.querySelectorAll('*')).slice(0, 300) : [];\n const hasVisibleContent = contentNodes.some((element) => visible(element) && (text(element.textContent).trim() || /^(IMG|SVG|CANVAS|VIDEO)$/.test(element.tagName)));\n checks.push({ id: 'content', status: hasVisibleContent ? 'passed' : 'failed', message: hasVisibleContent ? 'Visible content rendered' : 'No visible content was rendered' });\n const controls = bodyReady ? Array.from(document.body.querySelectorAll('a[href], button, input, select, textarea, [role=\"button\"], [tabindex]')).filter((element) => visible(element) && !element.disabled && element.getAttribute('aria-disabled') !== 'true') : [];\n const unnamed = controls.filter((element) => !accessibleName(element));\n let interactionStatus = controls.length ? 'passed' : 'skipped';\n let interactionMessage = controls.length ? controls.length + ' interactive control(s) are discoverable' : 'No interactive controls to exercise';\n if (unnamed.length) {\n interactionStatus = 'failed';\n interactionMessage = unnamed.length + ' interactive control(s) need an accessible name';\n } else if (controls.length) {\n const previous = document.activeElement;\n controls[0].focus({ preventScroll: true });\n if (document.activeElement !== controls[0]) {\n interactionStatus = 'failed';\n interactionMessage = 'The first interactive control could not receive focus';\n }\n if (previous && typeof previous.focus === 'function') previous.focus({ preventScroll: true });\n else controls[0].blur();\n }\n checks.push({ id: 'interaction', status: interactionStatus, message: interactionMessage });\n send('acceptance', {\n status: checks.some((check) => check.status === 'failed') ? 'failed' : 'passed',\n checks,\n interactiveCount: controls.length,\n });\n };\n const runCriteria = async () => {\n const params = new URLSearchParams(location.search);\n if (params.get('xopcAcceptance') !== '1') return;\n let config;\n try {\n config = readCriteria();\n } catch (error) {\n send('criteria', { status: 'failed', scenarioCount: 0, scenarios: [{ id: 'config', name: 'Acceptance config', status: 'failed', message: text(error instanceof Error ? error.message : error) }] });\n return;\n }\n const requestedScenario = params.get('xopcScenario');\n const selectedScenarios = requestedScenario\n ? (config.scenarios || []).filter((scenario) => scenario.id === requestedScenario)\n : config.scenarios || [];\n if (requestedScenario && !selectedScenarios.length) {\n send('criteria', { status: 'failed', scenarioCount: 1, scenarios: [{ id: requestedScenario, name: requestedScenario, status: 'failed', message: 'Requested scenario was not found' }] });\n return;\n }\n const scenarios = [];\n for (const scenario of selectedScenarios) {\n let failure = '';\n for (let index = 0; index < scenario.steps.length; index += 1) {\n const step = scenario.steps[index];\n try {\n if (step.action === 'click') {\n const element = target(step.target);\n if (!(element instanceof HTMLElement)) throw new Error('Target \"' + step.target + '\" was not found');\n if ('disabled' in element && element.disabled || element.getAttribute('aria-disabled') === 'true') throw new Error('Target \"' + step.target + '\" is disabled');\n element.click();\n await pause();\n } else if (step.action === 'fill') {\n const element = target(step.target);\n if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) throw new Error('Target \"' + step.target + '\" cannot be filled');\n const prototype = element instanceof HTMLInputElement ? HTMLInputElement.prototype : element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLSelectElement.prototype;\n const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;\n if (setter) setter.call(element, step.value);\n else element.value = step.value;\n element.dispatchEvent(new Event('input', { bubbles: true }));\n element.dispatchEvent(new Event('change', { bubbles: true }));\n await pause();\n } else if (step.assert === 'text_visible') {\n const found = Array.from(document.body.querySelectorAll('*')).some((element) => visible(element) && text(element.textContent).includes(step.text));\n if (!found) throw new Error('Visible text was not found: \"' + step.text + '\"');\n } else if (step.assert === 'element_exists') {\n if (!target(step.target)) throw new Error('Target \"' + step.target + '\" was not found');\n } else if (step.assert === 'value_equals') {\n const element = target(step.target);\n if (!element || !('value' in element) || element.value !== step.value) throw new Error('Target \"' + step.target + '\" does not have the expected value');\n }\n if (runtimeFailure) throw new Error(runtimeFailure);\n } catch (error) {\n failure = 'Step ' + (index + 1) + ': ' + text(error instanceof Error ? error.message : error);\n break;\n }\n }\n scenarios.push({ id: scenario.id, name: scenario.name, status: failure ? 'failed' : 'passed', message: failure || 'Scenario passed' });\n }\n send('criteria', {\n status: scenarios.some((scenario) => scenario.status === 'failed') ? 'failed' : 'passed',\n scenarioCount: scenarios.length,\n scenarios,\n });\n };\n const loaded = () => {\n send('ready', { readyState: document.readyState });\n const run = () => { runAcceptance(); void runCriteria(); };\n if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => requestAnimationFrame(run));\n else setTimeout(run, 0);\n };\n if (document.readyState === 'complete') queueMicrotask(loaded);\n else addEventListener('load', loaded, { once: true });\n})();";
2
+ export declare const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = "(() => {\n let hostPort = null;\n const latest = new Map();\n const send = (type, detail) => {\n const message = { source: 'xopc-local-app-preview', version: 1, type, detail };\n latest.set(type, message);\n hostPort?.postMessage(message);\n };\n const connect = (event) => {\n const message = event.data;\n if (event.source !== parent || message?.source !== 'xopc-local-app-host' || message?.version !== 1 || message?.type !== 'connect' || !event.ports[0]) return;\n event.stopImmediatePropagation();\n hostPort?.close();\n hostPort = event.ports[0];\n hostPort.start();\n for (const message of latest.values()) hostPort.postMessage(message);\n };\n addEventListener('message', connect, true);\n const text = (value) => String(value ?? '').slice(0, 500);\n let runtimeFailure = '';\n const visible = (element) => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity) !== 0 && rect.width > 0 && rect.height > 0;\n };\n const accessibleName = (element) => {\n const labelledBy = text(element.getAttribute('aria-labelledby'));\n const labelledText = labelledBy.split(/\\s+/).map((id) => document.getElementById(id)?.textContent).filter(Boolean).join(' ');\n return text(element.getAttribute('aria-label') || labelledText || element.labels?.[0]?.textContent || element.textContent || element.getAttribute('alt') || element.getAttribute('title') || element.getAttribute('placeholder') || element.getAttribute('name')).trim();\n };\n const target = (id) => Array.from(document.querySelectorAll('[data-xopc-test-id]'))\n .find((element) => element.getAttribute('data-xopc-test-id') === id);\n const settle = async () => {\n await Promise.resolve();\n await Promise.resolve();\n };\n const readCriteria = () => {\n const encoded = document.querySelector('meta[name=\"xopc-local-app-acceptance\"]')?.content;\n if (!encoded) return { schemaVersion: 1, scenarios: [] };\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const bytes = Uint8Array.from(atob(padded), (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n };\n addEventListener('error', (event) => {\n runtimeFailure = text(event.message || 'A preview resource failed to load');\n send('error', {\n kind: 'script_error',\n message: runtimeFailure,\n filename: text(event.filename),\n line: Number(event.lineno) || undefined,\n column: Number(event.colno) || undefined,\n });\n }, true);\n addEventListener('unhandledrejection', (event) => {\n runtimeFailure = text(event.reason instanceof Error ? event.reason.message : event.reason);\n send('error', { kind: 'unhandled_rejection', message: runtimeFailure });\n });\n const runAcceptance = () => {\n const checks = [];\n const bodyReady = Boolean(document.body);\n checks.push({ id: 'document', status: bodyReady ? 'passed' : 'failed', message: bodyReady ? 'Preview document loaded' : 'Preview document has no body' });\n const contentNodes = bodyReady ? Array.from(document.body.querySelectorAll('*')).slice(0, 300) : [];\n const hasVisibleContent = contentNodes.some((element) => visible(element) && (text(element.textContent).trim() || /^(IMG|SVG|CANVAS|VIDEO)$/.test(element.tagName)));\n checks.push({ id: 'content', status: hasVisibleContent ? 'passed' : 'failed', message: hasVisibleContent ? 'Visible content rendered' : 'No visible content was rendered' });\n const controls = bodyReady ? Array.from(document.body.querySelectorAll('a[href], button, input, select, textarea, [role=\"button\"], [tabindex]')).filter((element) => visible(element) && !element.disabled && element.getAttribute('aria-disabled') !== 'true') : [];\n const unnamed = controls.filter((element) => !accessibleName(element));\n let interactionStatus = controls.length ? 'passed' : 'skipped';\n let interactionMessage = controls.length ? controls.length + ' interactive control(s) are discoverable' : 'No interactive controls to exercise';\n if (unnamed.length) {\n interactionStatus = 'failed';\n interactionMessage = unnamed.length + ' interactive control(s) need an accessible name';\n } else if (controls.length) {\n const previous = document.activeElement;\n controls[0].focus({ preventScroll: true });\n if (document.activeElement !== controls[0]) {\n interactionStatus = 'failed';\n interactionMessage = 'The first interactive control could not receive focus';\n }\n if (previous && typeof previous.focus === 'function') previous.focus({ preventScroll: true });\n else controls[0].blur();\n }\n checks.push({ id: 'interaction', status: interactionStatus, message: interactionMessage });\n send('acceptance', {\n status: checks.some((check) => check.status === 'failed') ? 'failed' : 'passed',\n checks,\n interactiveCount: controls.length,\n });\n };\n const runCriteria = async () => {\n const params = new URLSearchParams(location.search);\n if (params.get('xopcAcceptance') !== '1') return;\n let config;\n try {\n config = readCriteria();\n } catch (error) {\n send('criteria', { status: 'failed', scenarioCount: 0, scenarios: [{ id: 'config', name: 'Acceptance config', status: 'failed', message: text(error instanceof Error ? error.message : error) }] });\n return;\n }\n const requestedScenario = params.get('xopcScenario');\n const selectedScenarios = requestedScenario\n ? (config.scenarios || []).filter((scenario) => scenario.id === requestedScenario)\n : config.scenarios || [];\n if (requestedScenario && !selectedScenarios.length) {\n send('criteria', { status: 'failed', scenarioCount: 1, scenarios: [{ id: requestedScenario, name: requestedScenario, status: 'failed', message: 'Requested scenario was not found' }] });\n return;\n }\n const scenarios = [];\n for (const scenario of selectedScenarios) {\n let failure = '';\n for (let index = 0; index < scenario.steps.length; index += 1) {\n const step = scenario.steps[index];\n try {\n if (step.action === 'click') {\n const element = target(step.target);\n if (!(element instanceof HTMLElement)) throw new Error('Target \"' + step.target + '\" was not found');\n if ('disabled' in element && element.disabled || element.getAttribute('aria-disabled') === 'true') throw new Error('Target \"' + step.target + '\" is disabled');\n element.click();\n await settle();\n } else if (step.action === 'fill') {\n const element = target(step.target);\n if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) throw new Error('Target \"' + step.target + '\" cannot be filled');\n const prototype = element instanceof HTMLInputElement ? HTMLInputElement.prototype : element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLSelectElement.prototype;\n const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;\n if (setter) setter.call(element, step.value);\n else element.value = step.value;\n element.dispatchEvent(new Event('input', { bubbles: true }));\n element.dispatchEvent(new Event('change', { bubbles: true }));\n await settle();\n } else if (step.assert === 'text_visible') {\n const found = Array.from(document.body.querySelectorAll('*')).some((element) => visible(element) && text(element.textContent).includes(step.text));\n if (!found) throw new Error('Visible text was not found: \"' + step.text + '\"');\n } else if (step.assert === 'element_exists') {\n if (!target(step.target)) throw new Error('Target \"' + step.target + '\" was not found');\n } else if (step.assert === 'value_equals') {\n const element = target(step.target);\n if (!element || !('value' in element) || element.value !== step.value) throw new Error('Target \"' + step.target + '\" does not have the expected value');\n }\n if (runtimeFailure) throw new Error(runtimeFailure);\n } catch (error) {\n failure = 'Step ' + (index + 1) + ': ' + text(error instanceof Error ? error.message : error);\n break;\n }\n }\n scenarios.push({ id: scenario.id, name: scenario.name, status: failure ? 'failed' : 'passed', message: failure || 'Scenario passed' });\n }\n send('criteria', {\n status: scenarios.some((scenario) => scenario.status === 'failed') ? 'failed' : 'passed',\n scenarioCount: scenarios.length,\n scenarios,\n });\n };\n const loaded = () => {\n send('ready', { readyState: document.readyState });\n void runCriteria();\n if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => requestAnimationFrame(runAcceptance));\n else setTimeout(runAcceptance, 0);\n };\n if (document.readyState === 'complete') queueMicrotask(loaded);\n else addEventListener('load', loaded, { once: true });\n})();";
3
3
  export declare const LOCAL_APP_RUNTIME_BRIDGE_HASH: string;
4
4
  export declare function injectLocalAppRuntimeBridge(html: string, acceptance?: LocalAppAcceptanceConfig): string;
@@ -3,20 +3,20 @@ import { createHash } from "node:crypto";
3
3
  //#region src/local-apps/preview-runtime-bridge.ts
4
4
  const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = `(() => {
5
5
  let hostPort = null;
6
- const pending = [];
6
+ const latest = new Map();
7
7
  const send = (type, detail) => {
8
8
  const message = { source: 'xopc-local-app-preview', version: 1, type, detail };
9
- if (hostPort) hostPort.postMessage(message);
10
- else pending.push(message);
9
+ latest.set(type, message);
10
+ hostPort?.postMessage(message);
11
11
  };
12
12
  const connect = (event) => {
13
13
  const message = event.data;
14
14
  if (event.source !== parent || message?.source !== 'xopc-local-app-host' || message?.version !== 1 || message?.type !== 'connect' || !event.ports[0]) return;
15
15
  event.stopImmediatePropagation();
16
- removeEventListener('message', connect, true);
16
+ hostPort?.close();
17
17
  hostPort = event.ports[0];
18
18
  hostPort.start();
19
- for (const queued of pending.splice(0)) hostPort.postMessage(queued);
19
+ for (const message of latest.values()) hostPort.postMessage(message);
20
20
  };
21
21
  addEventListener('message', connect, true);
22
22
  const text = (value) => String(value ?? '').slice(0, 500);
@@ -33,7 +33,10 @@ const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = `(() => {
33
33
  };
34
34
  const target = (id) => Array.from(document.querySelectorAll('[data-xopc-test-id]'))
35
35
  .find((element) => element.getAttribute('data-xopc-test-id') === id);
36
- const pause = () => new Promise((resolve) => setTimeout(resolve, 50));
36
+ const settle = async () => {
37
+ await Promise.resolve();
38
+ await Promise.resolve();
39
+ };
37
40
  const readCriteria = () => {
38
41
  const encoded = document.querySelector('meta[name="xopc-local-app-acceptance"]')?.content;
39
42
  if (!encoded) return { schemaVersion: 1, scenarios: [] };
@@ -116,7 +119,7 @@ const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = `(() => {
116
119
  if (!(element instanceof HTMLElement)) throw new Error('Target "' + step.target + '" was not found');
117
120
  if ('disabled' in element && element.disabled || element.getAttribute('aria-disabled') === 'true') throw new Error('Target "' + step.target + '" is disabled');
118
121
  element.click();
119
- await pause();
122
+ await settle();
120
123
  } else if (step.action === 'fill') {
121
124
  const element = target(step.target);
122
125
  if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) throw new Error('Target "' + step.target + '" cannot be filled');
@@ -126,7 +129,7 @@ const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = `(() => {
126
129
  else element.value = step.value;
127
130
  element.dispatchEvent(new Event('input', { bubbles: true }));
128
131
  element.dispatchEvent(new Event('change', { bubbles: true }));
129
- await pause();
132
+ await settle();
130
133
  } else if (step.assert === 'text_visible') {
131
134
  const found = Array.from(document.body.querySelectorAll('*')).some((element) => visible(element) && text(element.textContent).includes(step.text));
132
135
  if (!found) throw new Error('Visible text was not found: "' + step.text + '"');
@@ -152,9 +155,9 @@ const LOCAL_APP_RUNTIME_BRIDGE_SCRIPT = `(() => {
152
155
  };
153
156
  const loaded = () => {
154
157
  send('ready', { readyState: document.readyState });
155
- const run = () => { runAcceptance(); void runCriteria(); };
156
- if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => requestAnimationFrame(run));
157
- else setTimeout(run, 0);
158
+ void runCriteria();
159
+ if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => requestAnimationFrame(runAcceptance));
160
+ else setTimeout(runAcceptance, 0);
158
161
  };
159
162
  if (document.readyState === 'complete') queueMicrotask(loaded);
160
163
  else addEventListener('load', loaded, { once: true });
@@ -13,6 +13,8 @@ export declare function createProactiveInsight(input: {
13
13
  whyItMatters: string;
14
14
  nextAction: string;
15
15
  evidence: ProactiveEvidence[];
16
+ valueScore: number;
17
+ valueReasons: string[];
16
18
  nowMs?: number;
17
19
  }): ProactiveInsight | null;
18
20
  export declare function setProactiveInsightStatus(id: string, status: ProactiveInsightStatus, nowMs?: number, expectedStatus?: ProactiveInsightStatus): ProactiveInsight | null;
@@ -14,6 +14,8 @@ function insightFromRow(row) {
14
14
  nextAction: row.next_action,
15
15
  evidence: JSON.parse(row.evidence_json),
16
16
  status: row.status,
17
+ valueScore: row.value_score,
18
+ valueReasons: JSON.parse(row.value_reasons_json),
17
19
  createdAt: row.created_at,
18
20
  updatedAt: row.updated_at
19
21
  };
@@ -58,8 +60,9 @@ function createProactiveInsight(input) {
58
60
  runSqliteWriteTransaction((db) => {
59
61
  created = db.prepare(`INSERT OR IGNORE INTO proactive_insights (
60
62
  insight_id, watch_id, run_id, kind, title, summary, why_it_matters,
61
- next_action, evidence_json, content_hash, status, created_at, updated_at
62
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unread', ?, ?)`).run(id, input.watchId, input.runId, input.kind, input.title, input.summary, input.whyItMatters, input.nextAction, JSON.stringify(input.evidence), contentHash, now, now).changes > 0;
63
+ next_action, evidence_json, content_hash, status, value_score,
64
+ value_reasons_json, created_at, updated_at
65
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unread', ?, ?, ?, ?)`).run(id, input.watchId, input.runId, input.kind, input.title, input.summary, input.whyItMatters, input.nextAction, JSON.stringify(input.evidence), contentHash, input.valueScore, JSON.stringify(input.valueReasons), now, now).changes > 0;
63
66
  });
64
67
  return created ? listProactiveInsights({ limit: 100 }).find((item) => item.id === id) ?? null : null;
65
68
  }
@@ -1,7 +1,10 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { getRelationshipSettings, isProactiveSupportAllowed } from "../storage/sqlite/relationship-settings-repository.js";
4
+ import "../storage/sqlite/index.js";
3
5
  import { getFocusWatchByAutomationId, recordFocusWatchRun } from "./watch-repository.js";
4
- import { createProactiveInsight } from "./insight-repository.js";
6
+ import { createProactiveInsight, listProactiveInsights } from "./insight-repository.js";
7
+ import { scoreProactiveValue } from "./value-score.js";
5
8
  //#region src/proactive/run-processor.ts
6
9
  init_logger();
7
10
  const log = createLogger("ProactiveRunProcessor");
@@ -105,6 +108,22 @@ function processFocusAutomationRun(run) {
105
108
  nowMs: run.endedAtMs
106
109
  })) return { handled: true };
107
110
  if (!result.meaningful) return { handled: true };
111
+ if (!isProactiveSupportAllowed(getRelationshipSettings(), {
112
+ now: new Date(run.endedAtMs),
113
+ topic: watch.kind
114
+ })) return { handled: true };
115
+ const history = listProactiveInsights({
116
+ status: ["approved", "dismissed"],
117
+ limit: 50
118
+ });
119
+ const value = scoreProactiveValue({
120
+ kind: watch.kind,
121
+ evidenceCount: result.evidence.length,
122
+ hasNextAction: Boolean(result.nextAction),
123
+ approvedCount: history.filter((item) => item.status === "approved").length,
124
+ dismissedCount: history.filter((item) => item.status === "dismissed").length
125
+ });
126
+ if (!value.shouldDeliver) return { handled: true };
108
127
  const insight = createProactiveInsight({
109
128
  watchId: watch.id,
110
129
  runId: run.id,
@@ -114,6 +133,8 @@ function processFocusAutomationRun(run) {
114
133
  whyItMatters: result.whyItMatters,
115
134
  nextAction: result.nextAction,
116
135
  evidence: result.evidence,
136
+ valueScore: value.score,
137
+ valueReasons: value.reasons,
117
138
  nowMs: run.endedAtMs
118
139
  });
119
140
  return insight ? {
@@ -49,6 +49,8 @@ export interface ProactiveInsight {
49
49
  whyItMatters: string;
50
50
  nextAction: string;
51
51
  evidence: ProactiveEvidence[];
52
+ valueScore: number;
53
+ valueReasons: string[];
52
54
  status: ProactiveInsightStatus;
53
55
  createdAt: number;
54
56
  updatedAt: number;
@@ -0,0 +1,13 @@
1
+ import type { FocusWatchKind } from './types.js';
2
+ export interface ProactiveValueScore {
3
+ score: number;
4
+ reasons: string[];
5
+ shouldDeliver: boolean;
6
+ }
7
+ export declare function scoreProactiveValue(input: {
8
+ kind: FocusWatchKind;
9
+ evidenceCount: number;
10
+ hasNextAction: boolean;
11
+ approvedCount: number;
12
+ dismissedCount: number;
13
+ }): ProactiveValueScore;
@@ -0,0 +1,30 @@
1
+ //#region src/proactive/value-score.ts
2
+ function scoreProactiveValue(input) {
3
+ const reasons = [];
4
+ let score = .15;
5
+ if (input.evidenceCount > 0) {
6
+ score += Math.min(.25, input.evidenceCount * .1);
7
+ reasons.push("evidence_backed");
8
+ }
9
+ if (input.hasNextAction) {
10
+ score += .25;
11
+ reasons.push("actionable");
12
+ }
13
+ const urgency = input.kind === "deadline" ? .25 : input.kind === "staleness" ? .2 : .15;
14
+ score += urgency;
15
+ reasons.push(input.kind === "deadline" ? "time_sensitive" : "focus_relevant");
16
+ const rated = input.approvedCount + input.dismissedCount;
17
+ if (rated > 0) {
18
+ const approvalRate = input.approvedCount / rated;
19
+ score += (approvalRate - .5) * .4;
20
+ reasons.push(approvalRate >= .5 ? "historically_useful" : "historically_dismissed");
21
+ }
22
+ score = Math.max(0, Math.min(1, score));
23
+ return {
24
+ score,
25
+ reasons,
26
+ shouldDeliver: score >= .65
27
+ };
28
+ }
29
+ //#endregion
30
+ export { scoreProactiveValue };
@@ -3,9 +3,9 @@
3
3
  const SHARE_CONFIG_DEFAULTS = {
4
4
  enabled: true,
5
5
  defaultTtlMs: 864e5,
6
- maxTtlMs: 6048e5,
7
- maxActiveShares: 100,
8
- maxFileSize: 104857600,
6
+ maxTtlMs: 2592e6,
7
+ maxActiveShares: 500,
8
+ maxFileSize: 524288e3,
9
9
  inlinePreviewMimes: [
10
10
  "image/png",
11
11
  "image/jpeg",
@@ -20,8 +20,8 @@ const SHARE_CONFIG_DEFAULTS = {
20
20
  ],
21
21
  directory: {
22
22
  enabled: true,
23
- maxFolderSize: 1073741824,
24
- maxFileCount: 1e3,
23
+ maxFolderSize: 2147483648,
24
+ maxFileCount: 1e4,
25
25
  maxDepth: 20,
26
26
  listingCacheMs: 6e4,
27
27
  zipConcurrency: 1
@@ -60,7 +60,7 @@ export interface CreateSiteShareParams {
60
60
  path?: string;
61
61
  /** Proxy: full upstream URL (must be loopback or whitelisted). */
62
62
  upstreamUrl?: string;
63
- /** Default 6h. */
63
+ /** Default 24h. */
64
64
  ttlMs?: number;
65
65
  /** Optional friendly description. */
66
66
  description?: string;
@@ -2,13 +2,13 @@
2
2
  const SITE_SHARE_CONFIG_DEFAULTS = {
3
3
  enabled: true,
4
4
  publicHostSuffix: "share.xopc.ai",
5
- defaultTtlMs: 216e5,
6
- maxTtlMs: 6048e5,
7
- maxActiveSites: 5,
5
+ defaultTtlMs: 864e5,
6
+ maxTtlMs: 2592e6,
7
+ maxActiveSites: 50,
8
8
  static: {
9
9
  enabled: true,
10
- maxRootDirSize: 524288e3,
11
- maxFileCount: 1e4,
10
+ maxRootDirSize: 1073741824,
11
+ maxFileCount: 2e4,
12
12
  rewriteEnabledByDefault: false
13
13
  },
14
14
  proxy: {
@@ -5,6 +5,9 @@ export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, } from './m
5
5
  export { discoverSqlMigrations, listRegisteredMigrationTargets } from './migrations/discover.js';
6
6
  export { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest, type OpenXopcDatabaseOptions, type XopcDatabase, } from './connection.js';
7
7
  export { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';
8
+ export { getInteractionState, setInteractionState, updateInteractionStateFromMessage, type InteractionState, } from './interaction-state-repository.js';
9
+ export { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings, type RelationshipSettings, type SupportMode, } from './relationship-settings-repository.js';
10
+ export { completeTaskOutcome, findTaskOutcomeForAssistant, getTaskOutcome, listTaskOutcomes, setTaskOutcomeFeedback, startTaskOutcome, summarizeTaskOutcomes, updateTaskOutcome, type TaskContract, type TaskEvidence, type TaskFeedbackOutcome, type TaskOutcome, type TaskOutcomeMetrics, type TaskOutcomeStatus, } from './task-outcome-repository.js';
8
11
  export { buildDefaultSessionMetadata, type SessionMetadataSeed, } from './session-metadata.js';
9
12
  export { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow, type SessionConfigRow, type SessionRow, type TranscriptEntryRow, } from './row-mappers.js';
10
13
  export { deleteSessionRecord, ensureSessionRecord, getCurrentSessionId, getGlobalSessionStats, findSessionKeyBySessionId, getSessionPersistedLevels, getSessionMetadata, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats, } from './session-repository.js';
@@ -6,6 +6,9 @@ import { XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, applyPendingMi
6
6
  import { ensureXopcDatabaseSchema } from "./schema.js";
7
7
  import { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest } from "./connection.js";
8
8
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
9
+ import { getInteractionState, setInteractionState, updateInteractionStateFromMessage } from "./interaction-state-repository.js";
10
+ import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
11
+ import { completeTaskOutcome, findTaskOutcomeForAssistant, getTaskOutcome, listTaskOutcomes, setTaskOutcomeFeedback, startTaskOutcome, summarizeTaskOutcomes, updateTaskOutcome } from "./task-outcome-repository.js";
9
12
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
10
13
  import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
11
14
  import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getCurrentSessionId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
@@ -21,4 +24,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
21
24
  import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
22
25
  import { consumeMemoryReferenceConsent, decideMemoryReferenceConsent, ensureMemoryReferenceConsentRequest, hasMemoryReferenceConsent, listMemoryReferenceConsents, revokeMemoryReferenceConsent } from "./memory-reference-consent-repository.js";
23
26
  import { getUserProfilePromptState, setUserProfilePromptState } from "./user-profile-setup-repository.js";
24
- export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, USER_UNDERSTANDING_REMEDIATION_POLICY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, buildDefaultSessionMetadata, buildGlobalSessionStats, captureCompactionCheckpoint, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, classifyStoredRow, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeConnectorApproval, consumeMemoryReferenceConsent, createConnectorApproval, createObjectLinkRecord, decideConnectorApproval, decideMemoryReferenceConsent, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, ensureMemoryReferenceConsentRequest, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findLatestMemoryInjectTrace, findSessionKeyBySessionId, finishKnowledgeSyncRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCompactionCheckpointDetail, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getCurrentSessionId, getGlobalSessionStats, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getNoteAgentContextRecord, getNoteRecord, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getUserProfilePromptState, getUserTrustPolicy, getXopcDatabase, hasMemoryReferenceConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, inspectSchemaMigrationStatus, isXopcDatabaseOpen, listActivityRecords, listCachedConnectorCatalogEntries, listCompactionCheckpoints, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemoryReferenceConsents, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, readSchemaVersion, readSchemaVersionForTest, recordActivityEvent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, revokeMemoryReferenceConsent, runSqliteWriteTransaction, searchMemoryIndex, searchMemoryRecords, sessionConfigRowToConfig, sessionRowToMetadata, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setLatestMemoryInjectFeedback, setMemoryProviderState, setMemoryTraceFeedback, setSessionConfig, setUserProfilePromptState, setUserTrustPolicy, startKnowledgeSyncRun, summarizeMemoryRecallFeedback, summarizeUserUnderstandingQuality, syncMemoryIndex, transcriptEntryRowToStoredRow, updateSessionConfig, updateSessionStats, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
27
+ export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, USER_UNDERSTANDING_REMEDIATION_POLICY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, captureCompactionCheckpoint, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, classifyStoredRow, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, completeTaskOutcome, consumeConnectorApproval, consumeMemoryReferenceConsent, createConnectorApproval, createObjectLinkRecord, decideConnectorApproval, decideMemoryReferenceConsent, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, ensureMemoryReferenceConsentRequest, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findLatestMemoryInjectTrace, findSessionKeyBySessionId, findTaskOutcomeForAssistant, finishKnowledgeSyncRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCompactionCheckpointDetail, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getCurrentSessionId, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getTaskOutcome, getUserProfilePromptState, getUserTrustPolicy, getXopcDatabase, hasMemoryReferenceConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, inspectSchemaMigrationStatus, isProactiveSupportAllowed, isXopcDatabaseOpen, listActivityRecords, listCachedConnectorCatalogEntries, listCompactionCheckpoints, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemoryReferenceConsents, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTaskOutcomes, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, readSchemaVersion, readSchemaVersionForTest, recordActivityEvent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, revokeMemoryReferenceConsent, runSqliteWriteTransaction, searchMemoryIndex, searchMemoryRecords, sessionConfigRowToConfig, sessionRowToMetadata, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setLatestMemoryInjectFeedback, setMemoryProviderState, setMemoryTraceFeedback, setSessionConfig, setTaskOutcomeFeedback, setUserProfilePromptState, setUserTrustPolicy, startKnowledgeSyncRun, startTaskOutcome, summarizeMemoryRecallFeedback, summarizeTaskOutcomes, summarizeUserUnderstandingQuality, syncMemoryIndex, transcriptEntryRowToStoredRow, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateTaskOutcome, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
@@ -0,0 +1,17 @@
1
+ import { type InteractionStateSignal } from '../../user-context/interaction-state.js';
2
+ export interface InteractionState extends InteractionStateSignal {
3
+ sessionKey: string;
4
+ expiresAt: number;
5
+ updatedAt: number;
6
+ }
7
+ export declare function getInteractionState(sessionKey: string, now?: number): InteractionState | undefined;
8
+ export declare function setInteractionState(input: {
9
+ sessionKey: string;
10
+ signal: InteractionStateSignal;
11
+ now?: number;
12
+ }): InteractionState;
13
+ export declare function updateInteractionStateFromMessage(input: {
14
+ sessionKey: string;
15
+ message: string;
16
+ now?: number;
17
+ }): InteractionState;
@@ -0,0 +1,60 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { inferInteractionState } from "../../user-context/interaction-state.js";
3
+ //#region src/storage/sqlite/interaction-state-repository.ts
4
+ const STATE_TTL_MS = 360 * 60 * 1e3;
5
+ function fromRow(row) {
6
+ return {
7
+ sessionKey: row.session_key,
8
+ supportNeed: row.support_need,
9
+ ...row.emotion_hypothesis ? { emotionHypothesis: row.emotion_hypothesis } : {},
10
+ confidence: row.confidence,
11
+ source: row.source,
12
+ repairStatus: row.repair_status,
13
+ ...row.repair_reason ? { repairReason: row.repair_reason } : {},
14
+ expiresAt: row.expires_at,
15
+ updatedAt: row.updated_at
16
+ };
17
+ }
18
+ function getInteractionState(sessionKey, now = Date.now()) {
19
+ const row = getSqliteDatabase().prepare(`SELECT session_key, support_need, emotion_hypothesis, confidence, source,
20
+ repair_status, repair_reason, expires_at, updated_at
21
+ FROM interaction_states WHERE session_key = ? AND expires_at > ?`).get(sessionKey, now);
22
+ return row ? fromRow(row) : void 0;
23
+ }
24
+ function setInteractionState(input) {
25
+ const now = input.now ?? Date.now();
26
+ const expiresAt = now + STATE_TTL_MS;
27
+ runSqliteWriteTransaction((db) => {
28
+ db.prepare(`INSERT INTO interaction_states (
29
+ session_key, support_need, emotion_hypothesis, confidence, source,
30
+ repair_status, repair_reason, expires_at, updated_at
31
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
32
+ ON CONFLICT(session_key) DO UPDATE SET
33
+ support_need = excluded.support_need,
34
+ emotion_hypothesis = excluded.emotion_hypothesis,
35
+ confidence = excluded.confidence,
36
+ source = excluded.source,
37
+ repair_status = excluded.repair_status,
38
+ repair_reason = excluded.repair_reason,
39
+ expires_at = excluded.expires_at,
40
+ updated_at = excluded.updated_at`).run(input.sessionKey, input.signal.supportNeed, input.signal.emotionHypothesis ?? null, input.signal.confidence, input.signal.source, input.signal.repairStatus, input.signal.repairReason ?? null, expiresAt, now);
41
+ });
42
+ return getInteractionState(input.sessionKey, now);
43
+ }
44
+ function updateInteractionStateFromMessage(input) {
45
+ const now = input.now ?? Date.now();
46
+ const previous = getInteractionState(input.sessionKey, now);
47
+ const inferred = inferInteractionState(input.message);
48
+ const signal = previous?.repairStatus === "needed" && inferred.repairStatus === "none" ? {
49
+ ...inferred,
50
+ repairStatus: "needed",
51
+ repairReason: previous.repairReason
52
+ } : inferred;
53
+ return setInteractionState({
54
+ sessionKey: input.sessionKey,
55
+ signal,
56
+ now
57
+ });
58
+ }
59
+ //#endregion
60
+ export { getInteractionState, setInteractionState, updateInteractionStateFromMessage };
@@ -1,6 +1,6 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
- import { buildFts5SearchQuery, fts5RankToScore, memoryLexicalSimilarity } from "./fts.js";
3
2
  import { LOCAL_USER_ID } from "../../user-context/owner.js";
3
+ import { buildFts5SearchQuery, fts5RankToScore, memoryLexicalSimilarity } from "./fts.js";
4
4
  import { randomUUID } from "node:crypto";
5
5
  //#region src/storage/sqlite/memory-records-repository.ts
6
6
  const USER_UNDERSTANDING_REMEDIATION_POLICY = {
@@ -0,0 +1,45 @@
1
+ CREATE TABLE IF NOT EXISTS browser_recipes (
2
+ recipe_id TEXT PRIMARY KEY,
3
+ revision INTEGER NOT NULL,
4
+ name TEXT NOT NULL,
5
+ description TEXT,
6
+ status TEXT NOT NULL CHECK (status IN ('published', 'disabled')),
7
+ yaml_source TEXT NOT NULL,
8
+ risk_level TEXT NOT NULL CHECK (risk_level IN ('read_only', 'account_write', 'sensitive')),
9
+ domains_json TEXT NOT NULL,
10
+ created_at_ms INTEGER NOT NULL,
11
+ updated_at_ms INTEGER NOT NULL
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS browser_recipe_runs (
15
+ run_id TEXT PRIMARY KEY,
16
+ recipe_id TEXT NOT NULL,
17
+ recipe_revision INTEGER NOT NULL,
18
+ recipe_yaml TEXT NOT NULL,
19
+ status TEXT NOT NULL CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
20
+ args_json TEXT NOT NULL,
21
+ result_json TEXT,
22
+ error TEXT,
23
+ created_at_ms INTEGER NOT NULL,
24
+ started_at_ms INTEGER,
25
+ ended_at_ms INTEGER,
26
+ duration_ms INTEGER,
27
+ FOREIGN KEY (recipe_id) REFERENCES browser_recipes(recipe_id) ON DELETE CASCADE
28
+ );
29
+
30
+ CREATE INDEX IF NOT EXISTS idx_browser_recipe_runs_recipe_created
31
+ ON browser_recipe_runs(recipe_id, created_at_ms DESC);
32
+
33
+ CREATE TABLE IF NOT EXISTS browser_recipe_run_events (
34
+ event_id TEXT PRIMARY KEY,
35
+ run_id TEXT NOT NULL,
36
+ seq INTEGER NOT NULL,
37
+ type TEXT NOT NULL,
38
+ data_json TEXT,
39
+ created_at_ms INTEGER NOT NULL,
40
+ UNIQUE(run_id, seq),
41
+ FOREIGN KEY (run_id) REFERENCES browser_recipe_runs(run_id) ON DELETE CASCADE
42
+ );
43
+
44
+ CREATE INDEX IF NOT EXISTS idx_browser_recipe_run_events_run_seq
45
+ ON browser_recipe_run_events(run_id, seq ASC);
@@ -0,0 +1,24 @@
1
+ CREATE TABLE task_outcomes (
2
+ run_id TEXT PRIMARY KEY,
3
+ session_key TEXT NOT NULL,
4
+ channel TEXT NOT NULL,
5
+ objective TEXT NOT NULL,
6
+ status TEXT NOT NULL CHECK (status IN ('running', 'succeeded', 'failed', 'cancelled')),
7
+ summary TEXT,
8
+ contract_json TEXT,
9
+ evidence_json TEXT NOT NULL DEFAULT '[]',
10
+ feedback_outcome TEXT CHECK (feedback_outcome IN ('helpful', 'not_helpful')),
11
+ feedback_reason TEXT,
12
+ needs_correction INTEGER CHECK (needs_correction IN (0, 1)),
13
+ support_fit INTEGER CHECK (support_fit IN (0, 1)),
14
+ started_at INTEGER NOT NULL,
15
+ completed_at INTEGER,
16
+ updated_at INTEGER NOT NULL,
17
+ FOREIGN KEY (session_key) REFERENCES sessions(session_key) ON DELETE CASCADE
18
+ );
19
+
20
+ CREATE INDEX idx_task_outcomes_session_started
21
+ ON task_outcomes(session_key, started_at DESC);
22
+
23
+ CREATE INDEX idx_task_outcomes_status_started
24
+ ON task_outcomes(status, started_at DESC);
@@ -0,0 +1,14 @@
1
+ CREATE TABLE relationship_settings (
2
+ owner_id TEXT PRIMARY KEY CHECK (owner_id = 'local-owner'),
3
+ support_mode TEXT NOT NULL CHECK (support_mode IN ('efficient', 'coach', 'companion', 'auto')),
4
+ proactive_enabled INTEGER NOT NULL CHECK (proactive_enabled IN (0, 1)),
5
+ quiet_start TEXT,
6
+ quiet_end TEXT,
7
+ allowed_topics_json TEXT NOT NULL,
8
+ blocked_topics_json TEXT NOT NULL,
9
+ updated_at INTEGER NOT NULL
10
+ );
11
+
12
+ INSERT INTO relationship_settings (
13
+ owner_id, support_mode, proactive_enabled, allowed_topics_json, blocked_topics_json, updated_at
14
+ ) VALUES ('local-owner', 'auto', 0, '[]', '[]', unixepoch() * 1000);
@@ -0,0 +1,6 @@
1
+ ALTER TABLE task_outcomes ADD COLUMN verification_status TEXT NOT NULL DEFAULT 'unverified'
2
+ CHECK (verification_status IN ('passed', 'failed', 'unverified'));
3
+ ALTER TABLE task_outcomes ADD COLUMN verification_json TEXT NOT NULL DEFAULT '{"checks":[]}';
4
+ ALTER TABLE task_outcomes ADD COLUMN failure_code TEXT;
5
+ ALTER TABLE task_outcomes ADD COLUMN failure_phase TEXT;
6
+ ALTER TABLE task_outcomes ADD COLUMN recovery_action TEXT;
@@ -0,0 +1,11 @@
1
+ CREATE TABLE interaction_states (
2
+ session_key TEXT PRIMARY KEY REFERENCES sessions(session_key) ON DELETE CASCADE,
3
+ support_need TEXT NOT NULL CHECK (support_need IN ('listen', 'clarify', 'advise', 'act', 'unknown')),
4
+ emotion_hypothesis TEXT,
5
+ confidence REAL NOT NULL CHECK (confidence >= 0 AND confidence <= 1),
6
+ source TEXT NOT NULL CHECK (source IN ('explicit', 'inferred')),
7
+ repair_status TEXT NOT NULL CHECK (repair_status IN ('none', 'needed', 'repaired')),
8
+ repair_reason TEXT,
9
+ expires_at INTEGER NOT NULL,
10
+ updated_at INTEGER NOT NULL
11
+ );
@@ -0,0 +1,3 @@
1
+ ALTER TABLE proactive_insights ADD COLUMN value_score REAL NOT NULL DEFAULT 0
2
+ CHECK (value_score >= 0 AND value_score <= 1);
3
+ ALTER TABLE proactive_insights ADD COLUMN value_reasons_json TEXT NOT NULL DEFAULT '[]';
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
4
  export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 52;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 58;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.