@xopcai/xopc 0.0.118 → 0.0.119

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 (468) hide show
  1. package/README.md +2 -1
  2. package/README.zh-CN.md +2 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dzUrQoeZ.js → agent-avatar-dicebear-CU8J6zou.js} +1 -1
  6. package/dist/gateway/static/root/assets/agents-B0hkpLhP.js +2 -0
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-B9vfYoEr.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-ClOzIO24.js +1 -0
  9. package/dist/gateway/static/root/assets/{apps-page--wMEL00f.js → apps-page-DU0dz9Zo.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-Cki4SfU2.js → archive-plugin-BkVIgZzA.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-D-KnS2Do.js → attachment-load-CaCMWh1D.js} +1 -1
  12. package/dist/gateway/static/root/assets/automation-suggestion-card-DhGDpKP3.js +1 -0
  13. package/dist/gateway/static/root/assets/automations-page-CTedroVo.js +1 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-D2sgvJja.js → binary-plugins-B4TO_bsn.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-DIq-4Gvb.js → block-editor-DJRWwWNI.js} +28 -28
  16. package/dist/gateway/static/root/assets/browser-settings-page-FCDwOOBK.js +8 -0
  17. package/dist/gateway/static/root/assets/capability-presets-api-Befi89CL.js +1 -0
  18. package/dist/gateway/static/root/assets/capability-presets-settings-panel-_G8eb2vJ.js +1 -0
  19. package/dist/gateway/static/root/assets/channel-recipient-api-BNSuJb5f.js +1 -0
  20. package/dist/gateway/static/root/assets/channels-settings-C3d5JBJX.js +1 -0
  21. package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +1 -0
  22. package/dist/gateway/static/root/assets/connectors-page-yaUNvt5u.js +2 -0
  23. package/dist/gateway/static/root/assets/cron-expression-B3B1eqnr.js +2 -0
  24. package/dist/gateway/static/root/assets/dreaming-settings-DNrdg1Ve.js +1 -0
  25. package/dist/gateway/static/root/assets/{extension-debug-page-DYu1KaFQ.js → extension-debug-page-DYh402XV.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B3W6QwlZ.js → extension-page-Cr_TizrN.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-D7VQ-cxE.js → extension-settings-page-BU1KoKRj.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-B7xDPu-R.js → fetch-Y7AEX4H3.js} +1 -1
  29. package/dist/gateway/static/root/assets/format-cron-label-arqgGlVV.js +1 -0
  30. package/dist/gateway/static/root/assets/{gateway-config-api-BTBLSeUu.js → gateway-config-api-RbMmAOpX.js} +1 -1
  31. package/dist/gateway/static/root/assets/gateway-settings-C79wkXef.js +1 -0
  32. package/dist/gateway/static/root/assets/{gateway-startup-retry-CYj9FWCp.js → gateway-startup-retry-DiD_Tx4N.js} +1 -1
  33. package/dist/gateway/static/root/assets/goal-detail-page-9paXuHdo.js +1 -0
  34. package/dist/gateway/static/root/assets/{goals-config-api-CQQgzPr3.js → goals-config-api-DqxVi0p5.js} +1 -1
  35. package/dist/gateway/static/root/assets/{goals-page-BHitvJAv.js → goals-page-CS0R-Af2.js} +2 -2
  36. package/dist/gateway/static/root/assets/goals-settings-CSuzZ8Ae.js +1 -0
  37. package/dist/gateway/static/root/assets/heartbeat-settings-DXPaYJm3.js +1 -0
  38. package/dist/gateway/static/root/assets/index-BoKafJIZ.js +191 -0
  39. package/dist/gateway/static/root/assets/index-CArhCcYn.css +1 -0
  40. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-Dvg53qnd.js +1 -0
  41. package/dist/gateway/static/root/assets/{logs-page-C2Uqvae9.js → logs-page-DLXPcksQ.js} +2 -2
  42. package/dist/gateway/static/root/assets/{markdown-split-BwOFrJ2E.js → markdown-split-CpHxbtWJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-Cnz6Q5G6.js → media-plugins-SFPQRSxq.js} +1 -1
  44. package/dist/gateway/static/root/assets/messages-CrDHEbss.js +3 -0
  45. package/dist/gateway/static/root/assets/models-hub-panel-BDF2iyRk.js +2 -0
  46. package/dist/gateway/static/root/assets/note-detail-page-CSb_hwig.js +2 -0
  47. package/dist/gateway/static/root/assets/{note-image-lightbox-B-Svpmza.js → note-image-lightbox-BUYURRgn.js} +1 -1
  48. package/dist/gateway/static/root/assets/notes-page-BsIBSFyZ.js +1 -0
  49. package/dist/gateway/static/root/assets/{preview-open-alternatives-Bss4TiwP.js → preview-open-alternatives-BHz9iWYA.js} +1 -1
  50. package/dist/gateway/static/root/assets/remote-access-hub-CwzSovcS.js +1 -0
  51. package/dist/gateway/static/root/assets/{save-bar-controls-BRNjdgKq.js → save-bar-controls-CefkOlRg.js} +1 -1
  52. package/dist/gateway/static/root/assets/schedule-field-CmTRoOcE.js +1 -0
  53. package/dist/gateway/static/root/assets/{schema-form-Dub9sy8r.js → schema-form-FMKv1vGu.js} +1 -1
  54. package/dist/gateway/static/root/assets/sessions-page-PHmX-NmA.js +1 -0
  55. package/dist/gateway/static/root/assets/settings-advanced-gate-BRAeKJN4.js +1 -0
  56. package/dist/gateway/static/root/assets/{settings-collapsible-section-BeFLavGi.js → settings-collapsible-section-BouO6JTi.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-form-section-dmyaPOTG.js → settings-form-section-D-4lBl6X.js} +1 -1
  58. package/dist/gateway/static/root/assets/settings-page-KKrbFjy8.js +1 -0
  59. package/dist/gateway/static/root/assets/settings-page-layout-BJ4Gsef5.js +1 -0
  60. package/dist/gateway/static/root/assets/setup-status-panel-CrUjHPQo.js +1 -0
  61. package/dist/gateway/static/root/assets/{share-preview-page-C8glrdqe.js → share-preview-page-BDy2btRN.js} +1 -1
  62. package/dist/gateway/static/root/assets/shares-settings-B18OBmH5.js +1 -0
  63. package/dist/gateway/static/root/assets/skill-reload-api-C28-2uKQ.js +1 -0
  64. package/dist/gateway/static/root/assets/skills-page-Bm2ebkwl.js +2 -0
  65. package/dist/gateway/static/root/assets/system-settings-panel-CRngrlnZ.js +1 -0
  66. package/dist/gateway/static/root/assets/typed-models-lib-BltBc0b-.js +1 -0
  67. package/dist/gateway/static/root/assets/{use-channel-catalog-DqlWTsDb.js → use-channel-catalog-CjN-51e6.js} +1 -1
  68. package/dist/gateway/static/root/assets/user-profile-settings-panel-DJ1dKwZy.js +1 -0
  69. package/dist/gateway/static/root/assets/utils-B5M5-YvK.js +1 -0
  70. package/dist/gateway/static/root/assets/{voice-api-key-field-C73IVZeC.js → voice-api-key-field-CeEevm7z.js} +1 -1
  71. package/dist/gateway/static/root/assets/{voice-player-store-C_ArLJPM.js → voice-player-store-B7ykUlHM.js} +1 -1
  72. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C4PzUQjB.js +3 -0
  73. package/dist/gateway/static/root/assets/workflows-page-BL84_-Ky.js +18 -0
  74. package/dist/gateway/static/root/index.html +6 -7
  75. package/dist/package.js +1 -1
  76. package/dist/src/agent/agent-manager.d.ts +4 -5
  77. package/dist/src/agent/agent-manager.js +4 -8
  78. package/dist/src/agent/agent-manager.js.map +1 -1
  79. package/dist/src/agent/embedded/run-for-session.js +102 -14
  80. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  81. package/dist/src/agent/fallback/candidates.d.ts +0 -8
  82. package/dist/src/agent/fallback/candidates.js.map +1 -1
  83. package/dist/src/agent/index.js +1 -1
  84. package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
  85. package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
  86. package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
  87. package/dist/src/agent/lifecycle/progress.d.ts +0 -1
  88. package/dist/src/agent/lifecycle/progress.js +1 -6
  89. package/dist/src/agent/lifecycle/progress.js.map +1 -1
  90. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
  91. package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
  92. package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
  93. package/dist/src/agent/middleware/self-verify.d.ts +0 -1
  94. package/dist/src/agent/middleware/self-verify.js +0 -2
  95. package/dist/src/agent/middleware/self-verify.js.map +1 -1
  96. package/dist/src/agent/models/index.d.ts +1 -1
  97. package/dist/src/agent/models/manager.d.ts +4 -20
  98. package/dist/src/agent/models/manager.js +9 -126
  99. package/dist/src/agent/models/manager.js.map +1 -1
  100. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
  101. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
  102. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  103. package/dist/src/agent/prompt/sections/tooling.js +2 -2
  104. package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
  105. package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
  106. package/dist/src/agent/prompt/service-prompt-builder.js +0 -12
  107. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  108. package/dist/src/agent/prompt/subagent-context.js +1 -1
  109. package/dist/src/agent/prompt/subagent-context.js.map +1 -1
  110. package/dist/src/agent/prompt/types.d.ts +1 -1
  111. package/dist/src/agent/service.d.ts +1 -9
  112. package/dist/src/agent/service.js +3 -40
  113. package/dist/src/agent/service.js.map +1 -1
  114. package/dist/src/agent/service.types.d.ts +2 -2
  115. package/dist/src/agent/session/session-config-service.d.ts +11 -11
  116. package/dist/src/agent/session/session-config-service.js +14 -14
  117. package/dist/src/agent/session/session-config-service.js.map +1 -1
  118. package/dist/src/agent/session/session-inspector.js +3 -2
  119. package/dist/src/agent/session/session-inspector.js.map +1 -1
  120. package/dist/src/agent/starter-agents.js +12 -12
  121. package/dist/src/agent/starter-agents.js.map +1 -1
  122. package/dist/src/agent/tools/automation-tool.d.ts +14 -0
  123. package/dist/src/agent/tools/automation-tool.js +102 -0
  124. package/dist/src/agent/tools/automation-tool.js.map +1 -0
  125. package/dist/src/agent/tools/delegate-tool.js +1 -1
  126. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  127. package/dist/src/agent/tools/factory.d.ts +3 -3
  128. package/dist/src/agent/tools/factory.js +2 -2
  129. package/dist/src/agent/tools/factory.js.map +1 -1
  130. package/dist/src/agent/tools/index.d.ts +1 -1
  131. package/dist/src/agent/tools/index.js +2 -2
  132. package/dist/src/agent-manifest/resolver.d.ts +1 -0
  133. package/dist/src/agent-manifest/resolver.js +1 -0
  134. package/dist/src/agent-manifest/resolver.js.map +1 -1
  135. package/dist/src/agent-manifest/schema.d.ts +6 -0
  136. package/dist/src/agent-manifest/schema.js +12 -3
  137. package/dist/src/agent-manifest/schema.js.map +1 -1
  138. package/dist/src/ai-assist/text-assist.d.ts +1 -1
  139. package/dist/src/ai-assist/text-assist.js +56 -0
  140. package/dist/src/ai-assist/text-assist.js.map +1 -1
  141. package/dist/src/auth/profiles/store.js.map +1 -1
  142. package/dist/src/automations/api/routes.d.ts +3 -0
  143. package/dist/src/automations/api/routes.js +193 -0
  144. package/dist/src/automations/api/routes.js.map +1 -0
  145. package/dist/src/automations/domain/index.d.ts +3 -0
  146. package/dist/src/automations/domain/index.js +3 -0
  147. package/dist/src/automations/domain/schedule.d.ts +4 -0
  148. package/dist/src/automations/domain/schedule.js +37 -0
  149. package/dist/src/automations/domain/schedule.js.map +1 -0
  150. package/dist/src/automations/domain/types.d.ts +160 -0
  151. package/dist/src/automations/domain/validation.d.ts +370 -0
  152. package/dist/src/automations/domain/validation.js +149 -0
  153. package/dist/src/automations/domain/validation.js.map +1 -0
  154. package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
  155. package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
  156. package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
  157. package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
  158. package/dist/src/automations/draft/automation-draft-service.js +135 -0
  159. package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
  160. package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
  161. package/dist/src/automations/draft/automation-draft-validator.js +105 -0
  162. package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
  163. package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
  164. package/dist/src/automations/draft/index.d.ts +3 -0
  165. package/dist/src/automations/draft/index.js +3 -0
  166. package/dist/src/automations/index.d.ts +3 -0
  167. package/dist/src/automations/index.js +8 -0
  168. package/dist/src/automations/product-events.d.ts +5 -0
  169. package/dist/src/automations/product-events.js +21 -0
  170. package/dist/src/automations/product-events.js.map +1 -0
  171. package/dist/src/automations/service/action-executor.d.ts +9 -0
  172. package/dist/src/automations/service/action-executor.js +157 -0
  173. package/dist/src/automations/service/action-executor.js.map +1 -0
  174. package/dist/src/automations/service/automation-service.d.ts +54 -0
  175. package/dist/src/automations/service/automation-service.js +404 -0
  176. package/dist/src/automations/service/automation-service.js.map +1 -0
  177. package/dist/src/automations/service/index.d.ts +2 -0
  178. package/dist/src/automations/service/index.js +3 -0
  179. package/dist/src/automations/storage/automation-repository.d.ts +6 -0
  180. package/dist/src/automations/storage/automation-repository.js +61 -0
  181. package/dist/src/automations/storage/automation-repository.js.map +1 -0
  182. package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
  183. package/dist/src/automations/storage/automation-run-repository.js +130 -0
  184. package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
  185. package/dist/src/automations/storage/index.d.ts +2 -0
  186. package/dist/src/automations/storage/index.js +3 -0
  187. package/dist/src/channels/plugin-types.d.ts +3 -0
  188. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  189. package/dist/src/cli/command-catalog.js +0 -39
  190. package/dist/src/cli/command-catalog.js.map +1 -1
  191. package/dist/src/cli/command-loaders.js +0 -1
  192. package/dist/src/cli/command-loaders.js.map +1 -1
  193. package/dist/src/cli/command-manifest.js +0 -4
  194. package/dist/src/cli/command-manifest.js.map +1 -1
  195. package/dist/src/cli/commands/agents.js +7 -6
  196. package/dist/src/cli/commands/agents.js.map +1 -1
  197. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  198. package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
  199. package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
  200. package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
  201. package/dist/src/cli/commands/doctor/flow.js +2 -2
  202. package/dist/src/cli/commands/doctor/flow.js.map +1 -1
  203. package/dist/src/cli/commands/gateway/call.js +2 -2
  204. package/dist/src/cli/commands/gateway/call.js.map +1 -1
  205. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  206. package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
  207. package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
  208. package/dist/src/cli/commands/init.js +26 -8
  209. package/dist/src/cli/commands/init.js.map +1 -1
  210. package/dist/src/cli/commands/tui.js +24 -2
  211. package/dist/src/cli/commands/tui.js.map +1 -1
  212. package/dist/src/cli/utils/init-workspace-core.js +2 -0
  213. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  214. package/dist/src/commands/agents.config.d.ts +9 -0
  215. package/dist/src/commands/agents.config.js +40 -2
  216. package/dist/src/commands/agents.config.js.map +1 -1
  217. package/dist/src/config/agent-profile.js +4 -3
  218. package/dist/src/config/agent-profile.js.map +1 -1
  219. package/dist/src/config/agent-typed-models.js.map +1 -1
  220. package/dist/src/config/config-surface.d.ts +3 -0
  221. package/dist/src/config/index.d.ts +0 -1
  222. package/dist/src/config/index.js +3 -3
  223. package/dist/src/config/index.js.map +1 -1
  224. package/dist/src/config/paths.d.ts +0 -9
  225. package/dist/src/config/paths.js +1 -14
  226. package/dist/src/config/paths.js.map +1 -1
  227. package/dist/src/config/profile.js +0 -1
  228. package/dist/src/config/profile.js.map +1 -1
  229. package/dist/src/config/rules.js +0 -5
  230. package/dist/src/config/rules.js.map +1 -1
  231. package/dist/src/config/schema.d.ts +13 -12
  232. package/dist/src/config/schema.js +22 -26
  233. package/dist/src/config/schema.js.map +1 -1
  234. package/dist/src/config/web-patch.d.ts +0 -12
  235. package/dist/src/config/web-patch.js +2 -29
  236. package/dist/src/config/web-patch.js.map +1 -1
  237. package/dist/src/extensions/api.d.ts +2 -0
  238. package/dist/src/extensions/api.js +10 -0
  239. package/dist/src/extensions/api.js.map +1 -1
  240. package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
  241. package/dist/src/extensions/extension-registry-impl.js +8 -0
  242. package/dist/src/extensions/extension-registry-impl.js.map +1 -1
  243. package/dist/src/extensions/loader.d.ts +3 -3
  244. package/dist/src/extensions/loader.js +3 -3
  245. package/dist/src/extensions/loader.js.map +1 -1
  246. package/dist/src/extensions/sdk/testing.d.ts +2 -0
  247. package/dist/src/extensions/sdk/testing.js +7 -0
  248. package/dist/src/extensions/sdk/testing.js.map +1 -1
  249. package/dist/src/extensions/types/core.d.ts +10 -1
  250. package/dist/src/extensions/types/index.d.ts +1 -1
  251. package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
  252. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  253. package/dist/src/gateway/agent-builtin-tools.js +1 -1
  254. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  255. package/dist/src/gateway/agents-admin.d.ts +1 -0
  256. package/dist/src/gateway/agents-admin.js +13 -15
  257. package/dist/src/gateway/agents-admin.js.map +1 -1
  258. package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
  259. package/dist/src/gateway/capability-presets-admin.js +19 -10
  260. package/dist/src/gateway/capability-presets-admin.js.map +1 -1
  261. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
  262. package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
  263. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
  264. package/dist/src/gateway/heartbeat/service.d.ts +0 -2
  265. package/dist/src/gateway/heartbeat/service.js +0 -7
  266. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  267. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
  268. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  269. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  270. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  271. package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
  272. package/dist/src/gateway/hono/routes/config-patch/misc.js +12 -6
  273. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  274. package/dist/src/gateway/hono/routes/dreaming.js +27 -37
  275. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  276. package/dist/src/gateway/hono/routes/home.d.ts +2 -2
  277. package/dist/src/gateway/hono/routes/home.js +34 -25
  278. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  279. package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -6
  280. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  281. package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
  282. package/dist/src/gateway/hono/routes/migrations.js +35 -0
  283. package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
  284. package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
  285. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  286. package/dist/src/gateway/hono/routes/sessions.js +14 -0
  287. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  288. package/dist/src/gateway/run-loop.js +2 -0
  289. package/dist/src/gateway/run-loop.js.map +1 -1
  290. package/dist/src/gateway/security/operator-scopes.js +5 -1
  291. package/dist/src/gateway/security/operator-scopes.js.map +1 -1
  292. package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
  293. package/dist/src/gateway/service/config-coordinator.js +14 -8
  294. package/dist/src/gateway/service/config-coordinator.js.map +1 -1
  295. package/dist/src/gateway/service/sessions-api.d.ts +2 -1
  296. package/dist/src/gateway/service/sessions-api.js +6 -1
  297. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  298. package/dist/src/gateway/service.d.ts +7 -3
  299. package/dist/src/gateway/service.js +61 -27
  300. package/dist/src/gateway/service.js.map +1 -1
  301. package/dist/src/goals/goal-service.js +45 -4
  302. package/dist/src/goals/goal-service.js.map +1 -1
  303. package/dist/src/infra/update-restart.js +1 -1
  304. package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
  305. package/dist/src/migrations/config/default-capability-preset.js +135 -0
  306. package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
  307. package/dist/src/migrations/index.d.ts +4 -0
  308. package/dist/src/migrations/index.js +4 -0
  309. package/dist/src/migrations/registry.d.ts +8 -0
  310. package/dist/src/migrations/registry.js +18 -0
  311. package/dist/src/migrations/registry.js.map +1 -0
  312. package/dist/src/migrations/runner.d.ts +17 -0
  313. package/dist/src/migrations/runner.js +191 -0
  314. package/dist/src/migrations/runner.js.map +1 -0
  315. package/dist/src/migrations/types.d.ts +34 -0
  316. package/dist/src/notes/service.js +24 -1
  317. package/dist/src/notes/service.js.map +1 -1
  318. package/dist/src/providers/model-registry.d.ts +0 -1
  319. package/dist/src/providers/model-registry.js +0 -3
  320. package/dist/src/providers/model-registry.js.map +1 -1
  321. package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
  322. package/dist/src/routing/resolve-tui-session-key.js +14 -3
  323. package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
  324. package/dist/src/session/transcript-outline.d.ts +47 -0
  325. package/dist/src/session/transcript-outline.js +481 -0
  326. package/dist/src/session/transcript-outline.js.map +1 -0
  327. package/dist/src/storage/sqlite/index.d.ts +0 -2
  328. package/dist/src/storage/sqlite/index.js +1 -3
  329. package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
  330. package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
  331. package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -0
  332. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  333. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  334. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  335. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  336. package/dist/src/storage/sqlite/schema.js +1 -1
  337. package/dist/src/storage/sqlite/schema.sql +56 -46
  338. package/dist/src/tui/backends/embedded-backend.d.ts +6 -0
  339. package/dist/src/tui/backends/embedded-backend.js +18 -7
  340. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  341. package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -0
  342. package/dist/src/tui/backends/gateway-sse-backend.js +14 -0
  343. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  344. package/dist/src/tui/tui-backend.d.ts +4 -0
  345. package/dist/src/tui/tui-commands.d.ts +5 -0
  346. package/dist/src/tui/tui-commands.js +43 -0
  347. package/dist/src/tui/tui-commands.js.map +1 -1
  348. package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
  349. package/dist/src/tui/tui-transcript-tree.js +17 -257
  350. package/dist/src/tui/tui-transcript-tree.js.map +1 -1
  351. package/dist/src/tui/tui-types.d.ts +2 -0
  352. package/dist/src/tui/tui-types.js.map +1 -1
  353. package/dist/src/tui/tui.js +7 -2
  354. package/dist/src/tui/tui.js.map +1 -1
  355. package/dist/src/workflows/domain/index.js +1 -1
  356. package/dist/src/workflows/domain/run.d.ts +7 -7
  357. package/dist/src/workflows/domain/run.js.map +1 -1
  358. package/dist/src/workflows/index.js +2 -2
  359. package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
  360. package/dist/src/workflows/service/workflow-run-service.js +31 -9
  361. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  362. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
  363. package/package.json +4 -2
  364. package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +0 -2
  365. package/dist/gateway/static/root/assets/app-management-settings-panel-bxYJVJpx.js +0 -1
  366. package/dist/gateway/static/root/assets/appearance-settings-BCIykXlI.js +0 -1
  367. package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +0 -8
  368. package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +0 -1
  369. package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +0 -1
  370. package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +0 -1
  371. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
  372. package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +0 -2
  373. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
  374. package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +0 -1
  375. package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
  376. package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +0 -3
  377. package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +0 -1
  378. package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
  379. package/dist/gateway/static/root/assets/format-interval-label-BzxafKxR.js +0 -1
  380. package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +0 -1
  381. package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +0 -1
  382. package/dist/gateway/static/root/assets/goals-settings-CYVY4NGp.js +0 -1
  383. package/dist/gateway/static/root/assets/heartbeat-config-api-DriO_CN9.js +0 -1
  384. package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +0 -1
  385. package/dist/gateway/static/root/assets/index-C17Tsd_b.css +0 -1
  386. package/dist/gateway/static/root/assets/index-Cc41r16l.js +0 -191
  387. package/dist/gateway/static/root/assets/interval-presets-DFPCKW_W.js +0 -1
  388. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CcVcqstx.js +0 -1
  389. package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +0 -3
  390. package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +0 -2
  391. package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +0 -2
  392. package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +0 -1
  393. package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +0 -1
  394. package/dist/gateway/static/root/assets/schedule-field-CUCKODde.js +0 -1
  395. package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +0 -1
  396. package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +0 -1
  397. package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +0 -1
  398. package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +0 -1
  399. package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +0 -1
  400. package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +0 -1
  401. package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +0 -2
  402. package/dist/gateway/static/root/assets/system-settings-panel-DI-LN_8G.js +0 -1
  403. package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +0 -1
  404. package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +0 -1
  405. package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +0 -1
  406. package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +0 -18
  407. package/dist/src/agent/fallback/error.d.ts +0 -22
  408. package/dist/src/agent/fallback/error.js +0 -32
  409. package/dist/src/agent/fallback/error.js.map +0 -1
  410. package/dist/src/agent/fallback/index.d.ts +0 -5
  411. package/dist/src/agent/fallback/index.js +0 -9
  412. package/dist/src/agent/fallback/index.js.map +0 -1
  413. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
  414. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
  415. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
  416. package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
  417. package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
  418. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
  419. package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
  420. package/dist/src/agent/tools/cronjob-tool.js +0 -274
  421. package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
  422. package/dist/src/cli/commands/cron-cli.d.ts +0 -2
  423. package/dist/src/cli/commands/cron-cli.js +0 -15
  424. package/dist/src/cli/commands/cron-cli.js.map +0 -1
  425. package/dist/src/cli/commands/cron.d.ts +0 -4
  426. package/dist/src/cli/commands/cron.js +0 -188
  427. package/dist/src/cli/commands/cron.js.map +0 -1
  428. package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
  429. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
  430. package/dist/src/cron/execution-types.d.ts +0 -42
  431. package/dist/src/cron/executor.d.ts +0 -67
  432. package/dist/src/cron/executor.js +0 -669
  433. package/dist/src/cron/executor.js.map +0 -1
  434. package/dist/src/cron/index.d.ts +0 -7
  435. package/dist/src/cron/index.js +0 -7
  436. package/dist/src/cron/job-content.d.ts +0 -5
  437. package/dist/src/cron/job-content.js +0 -15
  438. package/dist/src/cron/job-content.js.map +0 -1
  439. package/dist/src/cron/run-log-store.d.ts +0 -12
  440. package/dist/src/cron/run-log-store.js +0 -58
  441. package/dist/src/cron/run-log-store.js.map +0 -1
  442. package/dist/src/cron/schedule.d.ts +0 -10
  443. package/dist/src/cron/schedule.js +0 -85
  444. package/dist/src/cron/schedule.js.map +0 -1
  445. package/dist/src/cron/service.d.ts +0 -58
  446. package/dist/src/cron/service.js +0 -419
  447. package/dist/src/cron/service.js.map +0 -1
  448. package/dist/src/cron/types.d.ts +0 -183
  449. package/dist/src/cron/validation.d.ts +0 -500
  450. package/dist/src/cron/validation.js +0 -192
  451. package/dist/src/cron/validation.js.map +0 -1
  452. package/dist/src/cron/workflow-run-completion.d.ts +0 -23
  453. package/dist/src/cron/workflow-run-completion.js +0 -72
  454. package/dist/src/cron/workflow-run-completion.js.map +0 -1
  455. package/dist/src/extensions/types/phase4.js +0 -1
  456. package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
  457. package/dist/src/gateway/hono/routes/cron.js +0 -109
  458. package/dist/src/gateway/hono/routes/cron.js.map +0 -1
  459. package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
  460. package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
  461. package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
  462. package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
  463. package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
  464. package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
  465. /package/dist/src/{cron → automations/domain}/types.js +0 -0
  466. /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
  467. /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
  468. /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"config-coordinator.js","names":["writeConfigToDisk"],"sources":["../../../../src/gateway/service/config-coordinator.ts"],"sourcesContent":["/**\n * GatewayConfigCoordinator — owns config persistence, hot-reload, and the\n * per-section reload handlers.\n *\n * Was 350 lines of `GatewayService` covering nine concerns:\n * - manual `reloadConfig()` (CLI/UI trigger)\n * - `saveConfig()` / `updateConfig()` (PATCH /api/config)\n * - `setBundledExtensionActivationTarget` (extension store install)\n * - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`\n * (QR-login follow-ups that bypass the watcher)\n * - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)\n * - Eight section reload handlers (models / agents / channels / cron /\n * heartbeat / tools / mcp / extensions)\n * - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so\n * Telegram/Weixin do not stop/start repeatedly)\n *\n * Pulled out so the gateway composition root stays focused on lifecycle, and\n * each handler is reachable from one place when adding a new config section.\n *\n * **Config state ownership.** `GatewayService.config` is still the single\n * source of truth — this coordinator reads it via `getConfig()` and writes it\n * back via `setConfig()` after every reload / persist. We pass through rather\n * than holding our own copy so other coordinators (sessions, marketplace,\n * agent runner) see the latest config the moment a reload commits.\n */\nimport type { Config } from '../../config/schema.js';\nimport type { Config as SurfaceConfig } from '../../config/config-surface.js';\nimport type { AgentService } from '../../agent/service.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport type { CronService } from '../../cron/index.js';\nimport type { HeartbeatService } from '../heartbeat/index.js';\nimport type { ExtensionLoader } from '../../extensions/loader.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { ConfigHotReloader } from '../../config/reload.js';\nimport { loadConfig, saveConfig as writeConfigToDisk } from '../../config/index.js';\nimport { sanitizeTunnelConfig } from '../../tunnel/tunnel-config.js';\nimport { getModelRegistry } from '../../providers/index.js';\nimport { disposeAllSessionMcpRuntimes } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { computeBundledExtensionExtensionsPatch } from '../../extensions/bundled-extension-activation.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('GatewayConfigCoordinator');\n\nexport interface GatewayConfigCoordinatorOptions {\n configPath: string;\n bus: MessageBus;\n /** Hot reload (fs.watch) — disabled in tests / certain CLI modes. */\n enableHotReload: boolean;\n getConfig: () => Config;\n /** Writes the new config back into `GatewayService.config`. */\n setConfig: (next: Config) => void;\n getAgentService: () => AgentService;\n getChannelManager: () => ChannelManager;\n getCronService: () => CronService;\n getHeartbeatService: () => HeartbeatService | null;\n getExtensionLoader: () => ExtensionLoader | null;\n /** Re-evaluate browser-extension server attachment after agent defaults change. */\n reconcileBrowserExtensionServer: () => Promise<void>;\n /** Latest channel status snapshot for the `channels.status` SSE event. */\n getChannelsStatus: () => unknown;\n /** SSE emit (used for `config.reload` + `channels.status`). */\n emit: (type: string, payload: unknown) => void;\n}\n\nexport class GatewayConfigCoordinator {\n private readonly opts: GatewayConfigCoordinatorOptions;\n private configReloader: ConfigHotReloader | null = null;\n private channelReloadFlushPromise: Promise<void> | null = null;\n private channelReloadPending = false;\n\n constructor(opts: GatewayConfigCoordinatorOptions) {\n this.opts = opts;\n }\n\n // ── Lifecycle ──────────────────────────────────────────────────────────\n\n /** Start the fs.watch-based reloader (idempotent — only starts once). */\n startHotReloader(): void {\n if (this.configReloader) return;\n this.configReloader = new ConfigHotReloader(\n this.opts.configPath,\n this.opts.getConfig(),\n {\n onModelsReload: (newConfig) => this.handleModelsReload(newConfig),\n onAgentDefaultsReload: (newConfig) => this.handleAgentDefaultsReload(newConfig),\n onChannelsReload: (newConfig) => this.handleChannelsReload(newConfig),\n onCronReload: (newConfig) => this.handleCronReload(newConfig),\n onHeartbeatReload: (newConfig) => this.handleHeartbeatReload(newConfig),\n onToolsReload: (newConfig) => this.handleToolsReload(newConfig),\n onMcpReload: (newConfig) => this.handleMcpReload(newConfig),\n onExtensionsReload: async (newConfig, changedPaths) => {\n await this.handleExtensionsReload(newConfig, changedPaths);\n },\n onFullRestart: (newConfig) => {\n log.warn(\n { requiresProcessRestart: true, hint: 'Restart the gateway process (hot reload cannot apply this change).' },\n 'Config reload: full gateway restart required — see prior \"restartPaths\" info log',\n );\n this.opts.setConfig(newConfig);\n this.opts.emit('config.reload', { section: 'full', requiresRestart: true });\n },\n },\n {\n debounceMs: 300,\n enabled: this.opts.enableHotReload,\n }\n );\n this.configReloader.start();\n }\n\n async stopHotReloader(): Promise<void> {\n if (this.configReloader) {\n await this.configReloader.stop();\n this.configReloader = null;\n }\n }\n\n // ── Manual reload (UI trigger) ─────────────────────────────────────────\n\n async reloadConfig(): Promise<{ reloaded: boolean; error?: string }> {\n if (!this.configReloader) {\n return { reloaded: false, error: 'Config reloader not initialized' };\n }\n const result = await this.configReloader.triggerReload();\n return { reloaded: result.success, error: result.error };\n }\n\n // ── Persist (PATCH /api/config, marketplace install, etc.) ─────────────\n\n async saveConfig(config: Config): Promise<{ saved: boolean; error?: string }> {\n try {\n await this.writeConfigAndReloadFromDisk(config);\n this.scheduleChannelPluginsAfterPersist();\n return { saved: true };\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em, phase: 'infra.config' }, `Failed to save config: ${em}`);\n return { saved: false, error: em };\n }\n }\n\n /** Merge partial updates into `currentConfig` and persist. */\n async updateConfig(updates: Partial<Config>): Promise<{ updated: boolean; error?: string }> {\n try {\n log.debug('Updating configuration...');\n const merged = { ...this.opts.getConfig(), ...updates };\n this.opts.setConfig(merged);\n await this.writeConfigAndReloadFromDisk(merged);\n this.scheduleChannelPluginsAfterPersist();\n log.debug('Configuration updated successfully');\n return { updated: true };\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em, phase: 'infra.config' }, `Failed to update config: ${em}`);\n return { updated: false, error: em };\n }\n }\n\n /**\n * App store (phase 1): persist `extensions.enabled` / `extensions.disabled`\n * for a bundled extension. Marketplace-only extensions hot-load on enable;\n * disable still needs a gateway restart to unload.\n */\n async setBundledExtensionActivationTarget(\n extensionId: string,\n wanted: boolean,\n ): Promise<{ ok: boolean; error?: string; requiresGatewayRestart: boolean }> {\n const loader = this.opts.getExtensionLoader();\n if (!loader) {\n return { ok: false, error: 'Extension loader unavailable', requiresGatewayRestart: false };\n }\n const id = extensionId.trim();\n if (!id) {\n return { ok: false, error: 'Invalid extension id', requiresGatewayRestart: false };\n }\n const patch = computeBundledExtensionExtensionsPatch(loader, this.opts.getConfig(), id, wanted);\n if (patch.ok === false) {\n return { ok: false, error: patch.error, requiresGatewayRestart: false };\n }\n const newConfig = { ...this.opts.getConfig(), extensions: patch.extensions } as Config;\n const saved = await this.saveConfig(newConfig);\n if (!saved.saved) {\n return { ok: false, error: saved.error ?? 'Failed to save config', requiresGatewayRestart: false };\n }\n loader.setConfig(this.opts.getConfig() as unknown as SurfaceConfig);\n\n let requiresGatewayRestart = true;\n if (wanted) {\n try {\n loader.invalidateManifestCache();\n await loader.loadByActivationPlan();\n requiresGatewayRestart = false;\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, extensionId: id, errorMessage: em },\n `Extension hot-load after bundled activation failed: ${em}`,\n );\n requiresGatewayRestart = true;\n }\n }\n\n this.opts.emit('config.reload', { section: 'extensions', source: 'bundled-activation' });\n return { ok: true, requiresGatewayRestart };\n }\n\n // ── QR-login follow-ups (bypass fs watcher) ────────────────────────────\n\n async afterWeixinCredentialsPersisted(): Promise<void> {\n const next = loadConfig(this.opts.configPath);\n this.opts.setConfig(next);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(next);\n this.configReloader?.syncCurrentConfig(next);\n await this.handleChannelsReload(next);\n const { weixinPlugin } = await import('../../channels/weixin/index.js');\n await weixinPlugin.reloadMonitorsWithConfig(this.opts.getConfig(), this.opts.bus);\n log.info('Weixin monitors restarted after credential login');\n }\n\n async afterFeishuCredentialsPersisted(): Promise<void> {\n const next = loadConfig(this.opts.configPath);\n this.opts.setConfig(next);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(next);\n this.configReloader?.syncCurrentConfig(next);\n await this.handleChannelsReload(next);\n log.info('Feishu config applied after QR setup');\n }\n\n // ── Section reload handlers (also used by manual triggers) ─────────────\n\n /**\n * Apply `latest.channels` to every registered channel plugin (Telegram,\n * Weixin, extensions). Single runtime path for: file watcher hot reload, API\n * saves, and Weixin QR follow-up.\n */\n async handleChannelsReload(newConfig: Config): Promise<void> {\n log.debug('Reloading channels config...');\n this.opts.setConfig(newConfig);\n await this.opts.getChannelManager().updateConfig(newConfig);\n this.opts.emit('config.reload', { section: 'channels' });\n this.opts.emit('channels.status', { channels: this.opts.getChannelsStatus() });\n log.debug('Channels config reloaded');\n }\n\n /**\n * Apply `gateway.heartbeat` from current config after PATCH /api/config (and\n * when hot reload is off). File watcher uses `handleHeartbeatReload` with\n * the same effect when paths match.\n */\n reloadHeartbeatFromCurrentConfig(): void {\n this.handleHeartbeatReload(this.opts.getConfig());\n }\n\n // ── Internals ──────────────────────────────────────────────────────────\n\n private handleModelsReload(newConfig: Config): void {\n log.debug('Reloading models config...');\n this.opts.setConfig(newConfig);\n getModelRegistry().refresh();\n this.opts.emit('config.reload', { section: 'models' });\n log.debug('Models config reloaded');\n }\n\n private handleAgentDefaultsReload(newConfig: Config): void {\n log.debug('Reloading agent defaults...');\n this.opts.setConfig(newConfig);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(newConfig);\n void this.opts.reconcileBrowserExtensionServer();\n this.opts.emit('config.reload', { section: 'agents' });\n log.debug('Agent defaults reloaded');\n }\n\n /**\n * Coalesces rapid saves so Telegram/Weixin do not stop/start repeatedly.\n * The persist path schedules the channel apply; the same coalescer absorbs\n * follow-up saves until the first flush settles.\n */\n private scheduleChannelPluginsAfterPersist(): void {\n this.channelReloadPending = true;\n if (this.channelReloadFlushPromise) return;\n this.channelReloadFlushPromise = (async () => {\n try {\n while (this.channelReloadPending) {\n this.channelReloadPending = false;\n await this.handleChannelsReload(this.opts.getConfig());\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em }, `Channel reload after persist failed: ${em}`);\n } finally {\n this.channelReloadFlushPromise = null;\n if (this.channelReloadPending) {\n this.scheduleChannelPluginsAfterPersist();\n }\n }\n })();\n }\n\n private handleCronReload(newConfig: Config): void {\n log.debug('Reloading cron config...');\n this.opts.setConfig(newConfig);\n this.opts.getCronService().updateConfig(newConfig);\n this.opts.emit('config.reload', { section: 'cron' });\n log.debug('Cron config reloaded');\n }\n\n private handleHeartbeatReload(newConfig: Config): void {\n log.debug('Reloading heartbeat config...');\n this.opts.setConfig(newConfig);\n this.opts.getHeartbeatService()?.updateConfig(newConfig);\n this.opts.emit('config.reload', { section: 'heartbeat' });\n log.debug('Heartbeat config reloaded');\n }\n\n private handleToolsReload(newConfig: Config): void {\n log.debug('Reloading tools config...');\n this.opts.setConfig(newConfig);\n this.opts.emit('config.reload', { section: 'tools' });\n log.debug('Tools config reloaded');\n }\n\n private handleMcpReload(newConfig: Config): void {\n log.debug('Reloading MCP config...');\n this.opts.setConfig(newConfig);\n void disposeAllSessionMcpRuntimes().catch((err) => {\n log.warn({ err }, 'MCP runtime dispose on config reload failed');\n });\n this.opts.emit('config.reload', { section: 'mcp' });\n log.debug('MCP config reloaded');\n }\n\n /** Dispatch config hot reload to extensions that registered `registerReload`. */\n private async handleExtensionsReload(\n newConfig: Config,\n changedPaths: string[],\n ): Promise<void> {\n this.opts.setConfig(newConfig);\n const loader = this.opts.getExtensionLoader();\n loader?.setConfig(newConfig as unknown as SurfaceConfig);\n\n if (!loader) {\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n return;\n }\n\n const registry = loader.getRegistry();\n const matchingRegs = registry.getMatchingReloadRegistrations(changedPaths);\n\n if (matchingRegs.length === 0) {\n log.debug({ changedPaths }, 'No extension reload handlers matched');\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n return;\n }\n\n for (const reg of matchingRegs) {\n const relevantPaths = changedPaths.filter(\n (p) =>\n reg.configPrefixes.length === 0 ||\n reg.configPrefixes.some(\n (prefix) => p === prefix || p.startsWith(`${prefix}.`),\n ),\n );\n\n log.info(\n { extensionId: reg.extensionId, relevantPaths },\n 'Calling extension reload handler',\n );\n\n try {\n const result = await reg.handler(newConfig, relevantPaths);\n if (result.success) {\n log.info({ extensionId: reg.extensionId }, 'Extension reload succeeded');\n } else {\n log.warn(\n { extensionId: reg.extensionId, error: result.error },\n `Extension reload reported failure: ${result.error ?? 'unknown'}`,\n );\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.error(\n { err, extensionId: reg.extensionId, errorMessage },\n `Extension reload handler threw: ${errorMessage}`,\n );\n }\n }\n\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n }\n\n /**\n * Persist and replace `currentConfig` with the validated file contents so\n * runtime matches disk (PATCH merge objects can drift from Zod-normalized\n * output).\n */\n private async writeConfigAndReloadFromDisk(configToWrite: Config): Promise<void> {\n await writeConfigToDisk(configToWrite, this.opts.configPath);\n const reloaded = loadConfig(this.opts.configPath);\n this.opts.setConfig(reloaded);\n if (sanitizeTunnelConfig(reloaded)) {\n await writeConfigToDisk(reloaded, this.opts.configPath);\n }\n this.opts.getAgentService().applyAgentDefaultsFromConfig(reloaded);\n await this.opts.reconcileBrowserExtensionServer();\n // Hot-apply: reconcile managed dreaming cron jobs immediately after config persists.\n await this.opts.getAgentService().reconcileDreamingNow().catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em }, `Dreaming cron reconcile after save failed: ${em}`);\n });\n // Align watcher baseline before channel hooks run so fs `change` does not\n // re-apply the same diff concurrently.\n this.configReloader?.syncCurrentConfig(reloaded);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-coordinator.js","names":["writeConfigToDisk"],"sources":["../../../../src/gateway/service/config-coordinator.ts"],"sourcesContent":["/**\n * GatewayConfigCoordinator — owns config persistence, hot-reload, and the\n * per-section reload handlers.\n *\n * Was 350 lines of `GatewayService` covering nine concerns:\n * - manual `reloadConfig()` (CLI/UI trigger)\n * - `saveConfig()` / `updateConfig()` (PATCH /api/config)\n * - `setBundledExtensionActivationTarget` (extension store install)\n * - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`\n * (QR-login follow-ups that bypass the watcher)\n * - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)\n * - Section reload handlers (models / agents / channels /\n * heartbeat / tools / mcp / extensions)\n * - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so\n * Telegram/Weixin do not stop/start repeatedly)\n *\n * Pulled out so the gateway composition root stays focused on lifecycle, and\n * each handler is reachable from one place when adding a new config section.\n *\n * **Config state ownership.** `GatewayService.config` is still the single\n * source of truth — this coordinator reads it via `getConfig()` and writes it\n * back via `setConfig()` after every reload / persist. We pass through rather\n * than holding our own copy so other coordinators (sessions, marketplace,\n * agent runner) see the latest config the moment a reload commits.\n */\nimport type { Config } from '../../config/schema.js';\nimport type { Config as SurfaceConfig } from '../../config/config-surface.js';\nimport type { AgentService } from '../../agent/service.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport type { HeartbeatService } from '../heartbeat/index.js';\nimport type { ExtensionLoader } from '../../extensions/loader.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { ConfigHotReloader } from '../../config/reload.js';\nimport { loadConfig, saveConfig as writeConfigToDisk } from '../../config/index.js';\nimport { sanitizeTunnelConfig } from '../../tunnel/tunnel-config.js';\nimport { getModelRegistry } from '../../providers/index.js';\nimport { disposeAllSessionMcpRuntimes } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { computeBundledExtensionExtensionsPatch } from '../../extensions/bundled-extension-activation.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('GatewayConfigCoordinator');\n\nexport interface GatewayConfigCoordinatorOptions {\n configPath: string;\n bus: MessageBus;\n /** Hot reload (fs.watch) — disabled in tests / certain CLI modes. */\n enableHotReload: boolean;\n getConfig: () => Config;\n /** Writes the new config back into `GatewayService.config`. */\n setConfig: (next: Config) => void;\n getAgentService: () => AgentService;\n getChannelManager: () => ChannelManager;\n getHeartbeatService: () => HeartbeatService | null;\n getExtensionLoader: () => ExtensionLoader | null;\n /** Re-evaluate browser-extension server attachment after agent defaults change. */\n reconcileBrowserExtensionServer: () => Promise<void>;\n /** Sync built-in dreaming automations after memory.dreaming changes. */\n reconcileDreamingAutomations: () => Promise<void>;\n /** Latest channel status snapshot for the `channels.status` SSE event. */\n getChannelsStatus: () => unknown;\n /** SSE emit (used for `config.reload` + `channels.status`). */\n emit: (type: string, payload: unknown) => void;\n}\n\nexport class GatewayConfigCoordinator {\n private readonly opts: GatewayConfigCoordinatorOptions;\n private configReloader: ConfigHotReloader | null = null;\n private channelReloadFlushPromise: Promise<void> | null = null;\n private channelReloadPending = false;\n\n constructor(opts: GatewayConfigCoordinatorOptions) {\n this.opts = opts;\n }\n\n // ── Lifecycle ──────────────────────────────────────────────────────────\n\n /** Start the fs.watch-based reloader (idempotent — only starts once). */\n startHotReloader(): void {\n if (this.configReloader) return;\n this.configReloader = new ConfigHotReloader(\n this.opts.configPath,\n this.opts.getConfig(),\n {\n onModelsReload: (newConfig) => this.handleModelsReload(newConfig),\n onAgentDefaultsReload: (newConfig) => this.handleAgentDefaultsReload(newConfig),\n onChannelsReload: (newConfig) => this.handleChannelsReload(newConfig),\n onCronReload: (newConfig) => this.handleAutomationReload(newConfig),\n onHeartbeatReload: (newConfig) => this.handleHeartbeatReload(newConfig),\n onToolsReload: (newConfig) => this.handleToolsReload(newConfig),\n onMcpReload: (newConfig) => this.handleMcpReload(newConfig),\n onExtensionsReload: async (newConfig, changedPaths) => {\n await this.handleExtensionsReload(newConfig, changedPaths);\n },\n onFullRestart: (newConfig) => {\n log.warn(\n { requiresProcessRestart: true, hint: 'Restart the gateway process (hot reload cannot apply this change).' },\n 'Config reload: full gateway restart required — see prior \"restartPaths\" info log',\n );\n this.opts.setConfig(newConfig);\n this.opts.emit('config.reload', { section: 'full', requiresRestart: true });\n },\n },\n {\n debounceMs: 300,\n enabled: this.opts.enableHotReload,\n }\n );\n this.configReloader.start();\n }\n\n async stopHotReloader(): Promise<void> {\n if (this.configReloader) {\n await this.configReloader.stop();\n this.configReloader = null;\n }\n }\n\n // ── Manual reload (UI trigger) ─────────────────────────────────────────\n\n async reloadConfig(): Promise<{ reloaded: boolean; error?: string }> {\n if (!this.configReloader) {\n return { reloaded: false, error: 'Config reloader not initialized' };\n }\n const result = await this.configReloader.triggerReload();\n return { reloaded: result.success, error: result.error };\n }\n\n // ── Persist (PATCH /api/config, marketplace install, etc.) ─────────────\n\n async saveConfig(config: Config): Promise<{ saved: boolean; error?: string }> {\n try {\n await this.writeConfigAndReloadFromDisk(config);\n this.scheduleChannelPluginsAfterPersist();\n return { saved: true };\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em, phase: 'infra.config' }, `Failed to save config: ${em}`);\n return { saved: false, error: em };\n }\n }\n\n /** Merge partial updates into `currentConfig` and persist. */\n async updateConfig(updates: Partial<Config>): Promise<{ updated: boolean; error?: string }> {\n try {\n log.debug('Updating configuration...');\n const merged = { ...this.opts.getConfig(), ...updates };\n this.opts.setConfig(merged);\n await this.writeConfigAndReloadFromDisk(merged);\n this.scheduleChannelPluginsAfterPersist();\n log.debug('Configuration updated successfully');\n return { updated: true };\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em, phase: 'infra.config' }, `Failed to update config: ${em}`);\n return { updated: false, error: em };\n }\n }\n\n /**\n * App store (phase 1): persist `extensions.enabled` / `extensions.disabled`\n * for a bundled extension. Marketplace-only extensions hot-load on enable;\n * disable still needs a gateway restart to unload.\n */\n async setBundledExtensionActivationTarget(\n extensionId: string,\n wanted: boolean,\n ): Promise<{ ok: boolean; error?: string; requiresGatewayRestart: boolean }> {\n const loader = this.opts.getExtensionLoader();\n if (!loader) {\n return { ok: false, error: 'Extension loader unavailable', requiresGatewayRestart: false };\n }\n const id = extensionId.trim();\n if (!id) {\n return { ok: false, error: 'Invalid extension id', requiresGatewayRestart: false };\n }\n const patch = computeBundledExtensionExtensionsPatch(loader, this.opts.getConfig(), id, wanted);\n if (patch.ok === false) {\n return { ok: false, error: patch.error, requiresGatewayRestart: false };\n }\n const newConfig = { ...this.opts.getConfig(), extensions: patch.extensions } as Config;\n const saved = await this.saveConfig(newConfig);\n if (!saved.saved) {\n return { ok: false, error: saved.error ?? 'Failed to save config', requiresGatewayRestart: false };\n }\n loader.setConfig(this.opts.getConfig() as unknown as SurfaceConfig);\n\n let requiresGatewayRestart = true;\n if (wanted) {\n try {\n loader.invalidateManifestCache();\n await loader.loadByActivationPlan();\n requiresGatewayRestart = false;\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, extensionId: id, errorMessage: em },\n `Extension hot-load after bundled activation failed: ${em}`,\n );\n requiresGatewayRestart = true;\n }\n }\n\n this.opts.emit('config.reload', { section: 'extensions', source: 'bundled-activation' });\n return { ok: true, requiresGatewayRestart };\n }\n\n // ── QR-login follow-ups (bypass fs watcher) ────────────────────────────\n\n async afterWeixinCredentialsPersisted(): Promise<void> {\n const next = loadConfig(this.opts.configPath);\n this.opts.setConfig(next);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(next);\n this.configReloader?.syncCurrentConfig(next);\n await this.handleChannelsReload(next);\n const { weixinPlugin } = await import('../../channels/weixin/index.js');\n await weixinPlugin.reloadMonitorsWithConfig(this.opts.getConfig(), this.opts.bus);\n log.info('Weixin monitors restarted after credential login');\n }\n\n async afterFeishuCredentialsPersisted(): Promise<void> {\n const next = loadConfig(this.opts.configPath);\n this.opts.setConfig(next);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(next);\n this.configReloader?.syncCurrentConfig(next);\n await this.handleChannelsReload(next);\n log.info('Feishu config applied after QR setup');\n }\n\n // ── Section reload handlers (also used by manual triggers) ─────────────\n\n /**\n * Apply `latest.channels` to every registered channel plugin (Telegram,\n * Weixin, extensions). Single runtime path for: file watcher hot reload, API\n * saves, and Weixin QR follow-up.\n */\n async handleChannelsReload(newConfig: Config): Promise<void> {\n log.debug('Reloading channels config...');\n this.opts.setConfig(newConfig);\n await this.opts.getChannelManager().updateConfig(newConfig);\n this.opts.emit('config.reload', { section: 'channels' });\n this.opts.emit('channels.status', { channels: this.opts.getChannelsStatus() });\n log.debug('Channels config reloaded');\n }\n\n /**\n * Apply `gateway.heartbeat` from current config after PATCH /api/config (and\n * when hot reload is off). File watcher uses `handleHeartbeatReload` with\n * the same effect when paths match.\n */\n reloadHeartbeatFromCurrentConfig(): void {\n this.handleHeartbeatReload(this.opts.getConfig());\n }\n\n // ── Internals ──────────────────────────────────────────────────────────\n\n private handleModelsReload(newConfig: Config): void {\n log.debug('Reloading models config...');\n this.opts.setConfig(newConfig);\n getModelRegistry().refresh();\n this.opts.emit('config.reload', { section: 'models' });\n log.debug('Models config reloaded');\n }\n\n private handleAgentDefaultsReload(newConfig: Config): void {\n log.debug('Reloading agent defaults...');\n this.opts.setConfig(newConfig);\n this.opts.getAgentService().applyAgentDefaultsFromConfig(newConfig);\n void this.opts.reconcileBrowserExtensionServer();\n void this.opts.reconcileDreamingAutomations().catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em }, `Dreaming automation refresh failed: ${em}`);\n });\n this.opts.emit('config.reload', { section: 'agents' });\n log.debug('Agent defaults reloaded');\n }\n\n /**\n * Coalesces rapid saves so Telegram/Weixin do not stop/start repeatedly.\n * The persist path schedules the channel apply; the same coalescer absorbs\n * follow-up saves until the first flush settles.\n */\n private scheduleChannelPluginsAfterPersist(): void {\n this.channelReloadPending = true;\n if (this.channelReloadFlushPromise) return;\n this.channelReloadFlushPromise = (async () => {\n try {\n while (this.channelReloadPending) {\n this.channelReloadPending = false;\n await this.handleChannelsReload(this.opts.getConfig());\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, errorMessage: em }, `Channel reload after persist failed: ${em}`);\n } finally {\n this.channelReloadFlushPromise = null;\n if (this.channelReloadPending) {\n this.scheduleChannelPluginsAfterPersist();\n }\n }\n })();\n }\n\n private handleAutomationReload(newConfig: Config): void {\n log.debug('Reloading automation-related config...');\n this.opts.setConfig(newConfig);\n this.opts.emit('config.reload', { section: 'automations' });\n log.debug('Automation-related config reloaded');\n }\n\n private handleHeartbeatReload(newConfig: Config): void {\n log.debug('Reloading heartbeat config...');\n this.opts.setConfig(newConfig);\n this.opts.getHeartbeatService()?.updateConfig(newConfig);\n this.opts.emit('config.reload', { section: 'heartbeat' });\n log.debug('Heartbeat config reloaded');\n }\n\n private handleToolsReload(newConfig: Config): void {\n log.debug('Reloading tools config...');\n this.opts.setConfig(newConfig);\n this.opts.emit('config.reload', { section: 'tools' });\n log.debug('Tools config reloaded');\n }\n\n private handleMcpReload(newConfig: Config): void {\n log.debug('Reloading MCP config...');\n this.opts.setConfig(newConfig);\n void disposeAllSessionMcpRuntimes().catch((err) => {\n log.warn({ err }, 'MCP runtime dispose on config reload failed');\n });\n this.opts.emit('config.reload', { section: 'mcp' });\n log.debug('MCP config reloaded');\n }\n\n /** Dispatch config hot reload to extensions that registered `registerReload`. */\n private async handleExtensionsReload(\n newConfig: Config,\n changedPaths: string[],\n ): Promise<void> {\n this.opts.setConfig(newConfig);\n const loader = this.opts.getExtensionLoader();\n loader?.setConfig(newConfig as unknown as SurfaceConfig);\n\n if (!loader) {\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n return;\n }\n\n const registry = loader.getRegistry();\n const matchingRegs = registry.getMatchingReloadRegistrations(changedPaths);\n\n if (matchingRegs.length === 0) {\n log.debug({ changedPaths }, 'No extension reload handlers matched');\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n return;\n }\n\n for (const reg of matchingRegs) {\n const relevantPaths = changedPaths.filter(\n (p) =>\n reg.configPrefixes.length === 0 ||\n reg.configPrefixes.some(\n (prefix) => p === prefix || p.startsWith(`${prefix}.`),\n ),\n );\n\n log.info(\n { extensionId: reg.extensionId, relevantPaths },\n 'Calling extension reload handler',\n );\n\n try {\n const result = await reg.handler(newConfig, relevantPaths);\n if (result.success) {\n log.info({ extensionId: reg.extensionId }, 'Extension reload succeeded');\n } else {\n log.warn(\n { extensionId: reg.extensionId, error: result.error },\n `Extension reload reported failure: ${result.error ?? 'unknown'}`,\n );\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.error(\n { err, extensionId: reg.extensionId, errorMessage },\n `Extension reload handler threw: ${errorMessage}`,\n );\n }\n }\n\n this.opts.emit('config.reload', {\n section: 'extensions',\n source: 'extension-reload',\n changedPaths,\n });\n }\n\n /**\n * Persist and replace `currentConfig` with the validated file contents so\n * runtime matches disk (PATCH merge objects can drift from Zod-normalized\n * output).\n */\n private async writeConfigAndReloadFromDisk(configToWrite: Config): Promise<void> {\n await writeConfigToDisk(configToWrite, this.opts.configPath);\n const reloaded = loadConfig(this.opts.configPath);\n this.opts.setConfig(reloaded);\n if (sanitizeTunnelConfig(reloaded)) {\n await writeConfigToDisk(reloaded, this.opts.configPath);\n }\n this.opts.getAgentService().applyAgentDefaultsFromConfig(reloaded);\n await this.opts.reconcileBrowserExtensionServer();\n // Keep built-in dreaming automations aligned with memory.dreaming.\n await this.opts.reconcileDreamingAutomations().catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em }, `Dreaming automation refresh after save failed: ${em}`);\n });\n // Align watcher baseline before channel hooks run so fs `change` does not\n // re-apply the same diff concurrently.\n this.configReloader?.syncCurrentConfig(reloaded);\n }\n}\n"],"mappings":"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"}
@@ -64,6 +64,7 @@ export declare class GatewaySessionsApi {
64
64
  nextBeforeCursor?: string;
65
65
  };
66
66
  }>;
67
+ getTimeline(key: string): Promise<import("../../session/transcript-outline.js").SessionTimelineItem[]>;
67
68
  patch(key: string, body: SessionPatchBody): Promise<{
68
69
  ok: true;
69
70
  } | {
@@ -142,7 +143,7 @@ export declare class GatewaySessionsApi {
142
143
  }>;
143
144
  stats(): Promise<import("../../session/types.js").GlobalSessionStats>;
144
145
  /**
145
- * Distinct chat-id pairs from sessions, grouped by channel. Used by cron job
146
+ * Distinct chat-id pairs from sessions, grouped by channel. Used by automation
146
147
  * configuration UI to seed the "send to existing chat" picker.
147
148
  */
148
149
  chatIds(channel?: string): Promise<Array<{
@@ -1,5 +1,6 @@
1
1
  import { retireSessionMcpRuntimeForSessionKey } from "../../agent/mcp/bundle-mcp-runtime.js";
2
2
  import "../../agent/mcp/bundle-mcp-tools.js";
3
+ import { buildSessionTimeline } from "../../session/transcript-outline.js";
3
4
  import { collectMediaUrisFromMessages, deleteMediaUris } from "../../media/session-references.js";
4
5
  import { getDistinctSessionChatIds } from "./session-chat-ids.js";
5
6
  import { performSessionReset } from "../session-reset-service.js";
@@ -44,6 +45,10 @@ var GatewaySessionsApi = class {
44
45
  getMessagePage(key, options) {
45
46
  return this.opts.sessionIndex.getSessionMessagePage(key, options);
46
47
  }
48
+ async getTimeline(key) {
49
+ if (!await this.opts.sessionIndex.getSessionMetadata(key)) return null;
50
+ return buildSessionTimeline(await this.opts.sessionIndex.getStore().loadTranscriptRows(key));
51
+ }
47
52
  patch(key, body) {
48
53
  return this.opts.sessionIndex.patchSession(key, body);
49
54
  }
@@ -156,7 +161,7 @@ var GatewaySessionsApi = class {
156
161
  return this.opts.sessionIndex.getStats();
157
162
  }
158
163
  /**
159
- * Distinct chat-id pairs from sessions, grouped by channel. Used by cron job
164
+ * Distinct chat-id pairs from sessions, grouped by channel. Used by automation
160
165
  * configuration UI to seed the "send to existing chat" picker.
161
166
  */
162
167
  chatIds(channel) {
@@ -1 +1 @@
1
- {"version":3,"file":"sessions-api.js","names":[],"sources":["../../../../src/gateway/service/sessions-api.ts"],"sourcesContent":["/**\n * GatewaySessionsApi — session CRUD, search, compaction, tag/pin/archive,\n * stats, and chat-id grouping for the gateway REST surface.\n *\n * Twenty-four methods, previously sitting on `GatewayService` as a mix of\n * one-line `sessionIndex.*` delegations and small composite operations (e.g.\n * `restoreCheckpoint` also evicts the in-memory agent, `runCompaction` also\n * appends a transcript context entry). Centralising them here lets routes\n * depend on the narrow `GatewaySessionsApi` surface instead of the full\n * `GatewayService`, and keeps the gateway composition root focused on\n * lifecycle + wiring.\n */\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { CompactionResult } from '../../agent/memory/compaction.js';\nimport { retireSessionMcpRuntimeForSessionKey } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { SessionIndex } from '../../session/index.js';\nimport type { ExportFormat, SessionListQuery } from '../../session/types.js';\nimport type { SessionPatchBody } from '../../session/patch-metadata.js';\nimport { collectMediaUrisFromMessages, deleteMediaUris } from '../../media/session-references.js';\nimport { getDistinctSessionChatIds } from './session-chat-ids.js';\nimport { performSessionReset, type SessionResetResult } from '../session-reset-service.js';\n\nexport interface GatewaySessionsApiOptions {\n sessionIndex: SessionIndex;\n /** Resolves the live agent service (created lazily; throws if gateway is starting). */\n getAgentService: () => AgentService;\n /** Read-only view of in-flight webchat runs (per session key → run id). */\n getActiveWebchatRunId: (sessionKey: string) => string | undefined;\n}\n\nexport class GatewaySessionsApi {\n private readonly opts: GatewaySessionsApiOptions;\n\n constructor(opts: GatewaySessionsApiOptions) {\n this.opts = opts;\n }\n\n // ── List / get ─────────────────────────────────────────────────────────\n\n listSessions(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSessions(query);\n }\n\n /** Subagent sessions have keys starting with `subagent:`. */\n listSubagents(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSubagents(query);\n }\n\n getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ) {\n return this.opts.sessionIndex.getSession(key, options);\n }\n\n async resolveSession(input: {\n key?: string;\n sessionKey?: string;\n sessionId?: string;\n }): Promise<\n | {\n sessionKey: string;\n sessionId: string;\n session: Awaited<ReturnType<GatewaySessionsApi['getSession']>>;\n }\n | null\n > {\n const explicitKey = input.sessionKey?.trim() || input.key?.trim();\n const resolvedKey =\n explicitKey ||\n (input.sessionId?.trim()\n ? await this.opts.sessionIndex.resolveSessionKeyBySessionId(input.sessionId.trim())\n : null);\n if (!resolvedKey) {\n return null;\n }\n const session = await this.getSession(resolvedKey);\n if (!session?.sessionId) {\n return null;\n }\n return { sessionKey: resolvedKey, sessionId: session.sessionId, session };\n }\n\n /** Read-only: in-flight webchat agent run for this session key, if any. */\n getActiveRun(sessionKey: string): { active: boolean; runId?: string } {\n const key = sessionKey.trim();\n if (!key) return { active: false };\n const runId = this.opts.getActiveWebchatRunId(key)?.trim();\n if (!runId) return { active: false };\n return { active: true, runId };\n }\n\n getMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ) {\n return this.opts.sessionIndex.getSessionMessagePage(key, options);\n }\n\n // ── Metadata patches ──────────────────────────────────────────────────\n\n patch(key: string, body: SessionPatchBody): Promise<{ ok: true } | { ok: false; error: string }> {\n return this.opts.sessionIndex.patchSession(key, body);\n }\n\n async getAgentConfig(sessionKey: string) {\n return this.opts.getAgentService().sessionInspector.agentConfig(sessionKey);\n }\n\n /** Resolved markdown workspace for a session (after hydration / mkdir). */\n getEffectiveWorkspacePath(sessionKey: string): Promise<string> {\n return this.opts.getAgentService().getEffectiveWorkspacePathForSession(sessionKey);\n }\n\n patchAgentConfig(\n sessionKey: string,\n body: {\n thinkingLevel?: string;\n model?: string | null;\n reasoningLevel?: string;\n verboseLevel?: string;\n workingDirectory?: string;\n },\n ) {\n return this.opts.getAgentService().sessionConfig.patch(sessionKey, body);\n }\n\n // ── Compaction checkpoints ────────────────────────────────────────────\n\n listCompactionCheckpoints(key: string) {\n return this.opts.sessionIndex.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpoint(key: string, checkpointId: string) {\n return this.opts.sessionIndex.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n await this.opts.sessionIndex.restoreCompactionCheckpoint(key, checkpointId);\n this.opts.getAgentService().evictSessionAgent(key);\n }\n\n async runCompaction(\n key: string,\n options?: { instructions?: string; force?: boolean },\n ): Promise<CompactionResult> {\n const result = await this.opts.getAgentService().sessionInspector.compact(key, options);\n if (result.compacted) {\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(key, {\n text: 'Session transcript compacted',\n data: {\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summaryPreview: result.summary.slice(0, 500),\n },\n })\n .catch(() => {});\n }\n return result;\n }\n\n // ── Lifecycle (delete / rename / tag / pin / archive) ─────────────────\n\n async delete(key: string): Promise<{ deleted: boolean }> {\n const messages = await this.opts.sessionIndex.loadMessages(key).catch(() => []);\n const result = await this.opts.sessionIndex.deleteSession(key);\n if (result) {\n await deleteMediaUris(collectMediaUrisFromMessages(messages));\n this.opts.getAgentService().evictSessionAgent(key);\n await retireSessionMcpRuntimeForSessionKey({ sessionKey: key, reason: 'session-delete' });\n }\n return { deleted: result };\n }\n\n /** Reset transcript in place (archive + new session id); preserves session key and overrides. */\n reset(key: string): Promise<SessionResetResult> {\n return performSessionReset(key, {\n sessionIndex: this.opts.sessionIndex,\n getAgentService: this.opts.getAgentService,\n });\n }\n\n deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n return this.opts.sessionIndex.deleteSessions(keys);\n }\n\n async rename(key: string, name: string): Promise<{ renamed: boolean }> {\n await this.opts.sessionIndex.renameSession(key, name);\n return { renamed: true };\n }\n\n async tag(key: string, tags: string[]): Promise<{ tagged: boolean }> {\n await this.opts.sessionIndex.tagSession(key, tags);\n return { tagged: true };\n }\n\n async untag(key: string, tags: string[]): Promise<{ untagged: boolean }> {\n await this.opts.sessionIndex.untagSession(key, tags);\n return { untagged: true };\n }\n\n async archive(key: string): Promise<{ archived: boolean }> {\n await this.opts.sessionIndex.archiveSession(key);\n return { archived: true };\n }\n\n async unarchive(key: string): Promise<{ unarchived: boolean }> {\n await this.opts.sessionIndex.unarchiveSession(key);\n return { unarchived: true };\n }\n\n async pin(key: string): Promise<{ pinned: boolean }> {\n await this.opts.sessionIndex.pinSession(key);\n return { pinned: true };\n }\n\n async unpin(key: string): Promise<{ unpinned: boolean }> {\n await this.opts.sessionIndex.unpinSession(key);\n return { unpinned: true };\n }\n\n // ── Search + export + stats ───────────────────────────────────────────\n\n search(query: string) {\n return this.opts.sessionIndex.searchSessions(query);\n }\n\n searchIn(key: string, keyword: string) {\n return this.opts.sessionIndex.searchInSession(key, keyword);\n }\n\n async export(key: string, format: ExportFormat): Promise<{ content: string }> {\n const content = await this.opts.sessionIndex.exportSession(key, format);\n return { content };\n }\n\n importExport(\n targetKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.importSessionExport(targetKey, jsonContent);\n }\n\n fork(\n key: string,\n targetKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSession(key, targetKey);\n }\n\n forkRows(\n key: string,\n targetKey: string,\n options: { throughRow?: number } = {},\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSessionRows(key, targetKey, options);\n }\n\n btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n return this.opts.getAgentService().sessionInspector.btwQuery(sessionKey, question);\n }\n\n stats() {\n return this.opts.sessionIndex.getStats();\n }\n\n /**\n * Distinct chat-id pairs from sessions, grouped by channel. Used by cron job\n * configuration UI to seed the \"send to existing chat\" picker.\n */\n chatIds(channel?: string): Promise<\n Array<{\n channel: string;\n chatId: string;\n lastActive: string;\n accountId?: string;\n peerKind?: string;\n peerId?: string;\n }>\n > {\n return getDistinctSessionChatIds(this.opts.sessionIndex, channel);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sessions-api.js","names":[],"sources":["../../../../src/gateway/service/sessions-api.ts"],"sourcesContent":["/**\n * GatewaySessionsApi — session CRUD, search, compaction, tag/pin/archive,\n * stats, and chat-id grouping for the gateway REST surface.\n *\n * Twenty-four methods, previously sitting on `GatewayService` as a mix of\n * one-line `sessionIndex.*` delegations and small composite operations (e.g.\n * `restoreCheckpoint` also evicts the in-memory agent, `runCompaction` also\n * appends a transcript context entry). Centralising them here lets routes\n * depend on the narrow `GatewaySessionsApi` surface instead of the full\n * `GatewayService`, and keeps the gateway composition root focused on\n * lifecycle + wiring.\n */\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { CompactionResult } from '../../agent/memory/compaction.js';\nimport { retireSessionMcpRuntimeForSessionKey } from '../../agent/mcp/bundle-mcp-tools.js';\nimport { SessionIndex } from '../../session/index.js';\nimport type { ExportFormat, SessionListQuery } from '../../session/types.js';\nimport { buildSessionTimeline } from '../../session/transcript-outline.js';\nimport type { SessionPatchBody } from '../../session/patch-metadata.js';\nimport { collectMediaUrisFromMessages, deleteMediaUris } from '../../media/session-references.js';\nimport { getDistinctSessionChatIds } from './session-chat-ids.js';\nimport { performSessionReset, type SessionResetResult } from '../session-reset-service.js';\n\nexport interface GatewaySessionsApiOptions {\n sessionIndex: SessionIndex;\n /** Resolves the live agent service (created lazily; throws if gateway is starting). */\n getAgentService: () => AgentService;\n /** Read-only view of in-flight webchat runs (per session key → run id). */\n getActiveWebchatRunId: (sessionKey: string) => string | undefined;\n}\n\nexport class GatewaySessionsApi {\n private readonly opts: GatewaySessionsApiOptions;\n\n constructor(opts: GatewaySessionsApiOptions) {\n this.opts = opts;\n }\n\n // ── List / get ─────────────────────────────────────────────────────────\n\n listSessions(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSessions(query);\n }\n\n /** Subagent sessions have keys starting with `subagent:`. */\n listSubagents(query?: SessionListQuery) {\n return this.opts.sessionIndex.listSubagents(query);\n }\n\n getSession(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ) {\n return this.opts.sessionIndex.getSession(key, options);\n }\n\n async resolveSession(input: {\n key?: string;\n sessionKey?: string;\n sessionId?: string;\n }): Promise<\n | {\n sessionKey: string;\n sessionId: string;\n session: Awaited<ReturnType<GatewaySessionsApi['getSession']>>;\n }\n | null\n > {\n const explicitKey = input.sessionKey?.trim() || input.key?.trim();\n const resolvedKey =\n explicitKey ||\n (input.sessionId?.trim()\n ? await this.opts.sessionIndex.resolveSessionKeyBySessionId(input.sessionId.trim())\n : null);\n if (!resolvedKey) {\n return null;\n }\n const session = await this.getSession(resolvedKey);\n if (!session?.sessionId) {\n return null;\n }\n return { sessionKey: resolvedKey, sessionId: session.sessionId, session };\n }\n\n /** Read-only: in-flight webchat agent run for this session key, if any. */\n getActiveRun(sessionKey: string): { active: boolean; runId?: string } {\n const key = sessionKey.trim();\n if (!key) return { active: false };\n const runId = this.opts.getActiveWebchatRunId(key)?.trim();\n if (!runId) return { active: false };\n return { active: true, runId };\n }\n\n getMessagePage(\n key: string,\n options?: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n },\n ) {\n return this.opts.sessionIndex.getSessionMessagePage(key, options);\n }\n\n async getTimeline(key: string) {\n const metadata = await this.opts.sessionIndex.getSessionMetadata(key);\n if (!metadata) return null;\n const rows = await this.opts.sessionIndex.getStore().loadTranscriptRows(key);\n return buildSessionTimeline(rows);\n }\n\n // ── Metadata patches ──────────────────────────────────────────────────\n\n patch(key: string, body: SessionPatchBody): Promise<{ ok: true } | { ok: false; error: string }> {\n return this.opts.sessionIndex.patchSession(key, body);\n }\n\n async getAgentConfig(sessionKey: string) {\n return this.opts.getAgentService().sessionInspector.agentConfig(sessionKey);\n }\n\n /** Resolved markdown workspace for a session (after hydration / mkdir). */\n getEffectiveWorkspacePath(sessionKey: string): Promise<string> {\n return this.opts.getAgentService().getEffectiveWorkspacePathForSession(sessionKey);\n }\n\n patchAgentConfig(\n sessionKey: string,\n body: {\n thinkingLevel?: string;\n model?: string | null;\n reasoningLevel?: string;\n verboseLevel?: string;\n workingDirectory?: string;\n },\n ) {\n return this.opts.getAgentService().sessionConfig.patch(sessionKey, body);\n }\n\n // ── Compaction checkpoints ────────────────────────────────────────────\n\n listCompactionCheckpoints(key: string) {\n return this.opts.sessionIndex.listCompactionCheckpoints(key);\n }\n\n getCompactionCheckpoint(key: string, checkpointId: string) {\n return this.opts.sessionIndex.getCompactionCheckpointDetail(key, checkpointId);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n await this.opts.sessionIndex.restoreCompactionCheckpoint(key, checkpointId);\n this.opts.getAgentService().evictSessionAgent(key);\n }\n\n async runCompaction(\n key: string,\n options?: { instructions?: string; force?: boolean },\n ): Promise<CompactionResult> {\n const result = await this.opts.getAgentService().sessionInspector.compact(key, options);\n if (result.compacted) {\n void this.opts.sessionIndex\n .appendTranscriptContextEntry(key, {\n text: 'Session transcript compacted',\n data: {\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summaryPreview: result.summary.slice(0, 500),\n },\n })\n .catch(() => {});\n }\n return result;\n }\n\n // ── Lifecycle (delete / rename / tag / pin / archive) ─────────────────\n\n async delete(key: string): Promise<{ deleted: boolean }> {\n const messages = await this.opts.sessionIndex.loadMessages(key).catch(() => []);\n const result = await this.opts.sessionIndex.deleteSession(key);\n if (result) {\n await deleteMediaUris(collectMediaUrisFromMessages(messages));\n this.opts.getAgentService().evictSessionAgent(key);\n await retireSessionMcpRuntimeForSessionKey({ sessionKey: key, reason: 'session-delete' });\n }\n return { deleted: result };\n }\n\n /** Reset transcript in place (archive + new session id); preserves session key and overrides. */\n reset(key: string): Promise<SessionResetResult> {\n return performSessionReset(key, {\n sessionIndex: this.opts.sessionIndex,\n getAgentService: this.opts.getAgentService,\n });\n }\n\n deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n return this.opts.sessionIndex.deleteSessions(keys);\n }\n\n async rename(key: string, name: string): Promise<{ renamed: boolean }> {\n await this.opts.sessionIndex.renameSession(key, name);\n return { renamed: true };\n }\n\n async tag(key: string, tags: string[]): Promise<{ tagged: boolean }> {\n await this.opts.sessionIndex.tagSession(key, tags);\n return { tagged: true };\n }\n\n async untag(key: string, tags: string[]): Promise<{ untagged: boolean }> {\n await this.opts.sessionIndex.untagSession(key, tags);\n return { untagged: true };\n }\n\n async archive(key: string): Promise<{ archived: boolean }> {\n await this.opts.sessionIndex.archiveSession(key);\n return { archived: true };\n }\n\n async unarchive(key: string): Promise<{ unarchived: boolean }> {\n await this.opts.sessionIndex.unarchiveSession(key);\n return { unarchived: true };\n }\n\n async pin(key: string): Promise<{ pinned: boolean }> {\n await this.opts.sessionIndex.pinSession(key);\n return { pinned: true };\n }\n\n async unpin(key: string): Promise<{ unpinned: boolean }> {\n await this.opts.sessionIndex.unpinSession(key);\n return { unpinned: true };\n }\n\n // ── Search + export + stats ───────────────────────────────────────────\n\n search(query: string) {\n return this.opts.sessionIndex.searchSessions(query);\n }\n\n searchIn(key: string, keyword: string) {\n return this.opts.sessionIndex.searchInSession(key, keyword);\n }\n\n async export(key: string, format: ExportFormat): Promise<{ content: string }> {\n const content = await this.opts.sessionIndex.exportSession(key, format);\n return { content };\n }\n\n importExport(\n targetKey: string,\n jsonContent: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.importSessionExport(targetKey, jsonContent);\n }\n\n fork(\n key: string,\n targetKey: string,\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSession(key, targetKey);\n }\n\n forkRows(\n key: string,\n targetKey: string,\n options: { throughRow?: number } = {},\n ): Promise<{ sessionKey: string; rowCount: number }> {\n return this.opts.sessionIndex.forkSessionRows(key, targetKey, options);\n }\n\n btwQuery(sessionKey: string, question: string): Promise<{ text: string; error?: string }> {\n return this.opts.getAgentService().sessionInspector.btwQuery(sessionKey, question);\n }\n\n stats() {\n return this.opts.sessionIndex.getStats();\n }\n\n /**\n * Distinct chat-id pairs from sessions, grouped by channel. Used by automation\n * configuration UI to seed the \"send to existing chat\" picker.\n */\n chatIds(channel?: string): Promise<\n Array<{\n channel: string;\n chatId: string;\n lastActive: string;\n accountId?: string;\n peerKind?: string;\n peerId?: string;\n }>\n > {\n return getDistinctSessionChatIds(this.opts.sessionIndex, channel);\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { AgentService } from '../agent/service.js';
2
2
  import { MessageBus } from '../infra/bus/index.js';
3
- import { CronService } from '../cron/index.js';
3
+ import { AutomationService } from '../automations/index.js';
4
4
  import { NotesService } from '../notes/index.js';
5
5
  import { WorkflowRunService } from '../workflows/service/workflow-run-service.js';
6
6
  import { ExtensionLoader } from '../extensions/index.js';
@@ -22,7 +22,7 @@ export declare class GatewayService {
22
22
  private configPath;
23
23
  private _agentService;
24
24
  private channelManager;
25
- private cronService;
25
+ private automationService;
26
26
  private notesService;
27
27
  private extensionLoader;
28
28
  private extensionMetadataSnapshot;
@@ -53,6 +53,8 @@ export declare class GatewayService {
53
53
  private goalRunner;
54
54
  private goalNotifications;
55
55
  private connectorSupervisor;
56
+ private stopAutomationProductEventBridge;
57
+ private stopSessionTranscriptAutomationEvents;
56
58
  /**
57
59
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
58
60
  * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
@@ -233,7 +235,8 @@ export declare class GatewayService {
233
235
  get messageBusInstance(): MessageBus;
234
236
  /** Effective HTTP listen port (CLI `--port` override or config default). */
235
237
  getEffectiveListenPort(): number;
236
- get cronServiceInstance(): CronService;
238
+ get automationServiceInstance(): AutomationService;
239
+ private reconcileDreamingAutomations;
237
240
  get notesServiceInstance(): NotesService;
238
241
  get sessionIndexInstance(): SessionIndex;
239
242
  /** Shared workflow run orchestrator + session bridge (one instance per gateway). */
@@ -244,6 +247,7 @@ export declare class GatewayService {
244
247
  processDirect(content: string, sessionKey?: string): Promise<string>;
245
248
  subscribe(sessionId: string, listener: (event: ServiceEvent) => Promise<void> | void): () => void;
246
249
  emit(type: string, payload: unknown): void;
250
+ private startAutomationProductEventBridge;
247
251
  /** Replay events since `lastEventId` for SSE reconnection. */
248
252
  getEventsSince(sessionId: string, lastEventId: string): ServiceEvent[];
249
253
  /**
@@ -16,6 +16,8 @@ import { loadConfig, saveConfig } from "../config/loader.js";
16
16
  import { prewarmModelRegistry } from "../providers/model-registry.js";
17
17
  import { init_providers, providers_exports } from "../providers/index.js";
18
18
  import { resolveEffectiveGatewayPort } from "./host.js";
19
+ import { onSessionTranscriptUpdate } from "../session/transcript-events.js";
20
+ import { onAutomationProductEvent, publishAutomationProductEvent } from "../automations/product-events.js";
19
21
  import { closeXopcDatabase, openXopcDatabase } from "../storage/sqlite/connection.js";
20
22
  import { GoalRunner } from "../goals/goal-runner.js";
21
23
  import { GoalNotificationService } from "../goals/goal-notifications.js";
@@ -31,15 +33,16 @@ import { MessageBus, MessageBusShutdownError } from "../infra/bus/queue.js";
31
33
  import "../infra/bus/index.js";
32
34
  import { AgentService } from "../agent/service.js";
33
35
  import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
36
+ import { AutomationService } from "../automations/service/automation-service.js";
37
+ import "../automations/index.js";
34
38
  import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
35
39
  import { registerClarifyBridge } from "./clarify-runtime.js";
36
40
  import { ChannelManager } from "../channels/manager.js";
37
41
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
38
42
  import "../config/index.js";
39
43
  import { startConnectorSupervisor } from "../connectors/supervisor.js";
40
- import { CronService } from "../cron/service.js";
41
- import "../cron/index.js";
42
44
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
45
+ import { reconcileDreamingAutomations } from "./dreaming-automation-reconciler.js";
43
46
  import { NotesStore } from "../notes/store.js";
44
47
  import { buildNoteAgentContext } from "../notes/agent-context.js";
45
48
  import { NotesService } from "../notes/service.js";
@@ -59,6 +62,7 @@ import { isGatewayStrictSecurityEnabled } from "./rate-limit/env-flags.js";
59
62
  import "./rate-limit/index.js";
60
63
  import { assertGatewayRuntimeConfig } from "./runtime-config.js";
61
64
  import { auditGatewayConfig } from "./security/audit.js";
65
+ import { runBootstrapMigrationsSync } from "../migrations/runner.js";
62
66
  import { scheduleGatewayUpdateCheck } from "../infra/update-startup.js";
63
67
  import { resolveChannelConnectDeferSet } from "./resolve-channel-connect-defer.js";
64
68
  import { restartGatewayProcessWithFreshPid } from "./respawn.js";
@@ -87,7 +91,7 @@ var GatewayService = class {
87
91
  configPath;
88
92
  _agentService = null;
89
93
  channelManager;
90
- cronService;
94
+ automationService;
91
95
  notesService;
92
96
  extensionLoader = null;
93
97
  extensionMetadataSnapshot = null;
@@ -120,6 +124,8 @@ var GatewayService = class {
120
124
  goalRunner = null;
121
125
  goalNotifications = null;
122
126
  connectorSupervisor = null;
127
+ stopAutomationProductEventBridge = null;
128
+ stopSessionTranscriptAutomationEvents = null;
123
129
  /**
124
130
  * Webchat agent invocation surface (`runAgent`, `abortAgentRun`, `steer*`,
125
131
  * `submitClarifyResponse`, clarify-bridge dispatch). Owns the
@@ -145,6 +151,7 @@ var GatewayService = class {
145
151
  this.serviceConfig = serviceConfig;
146
152
  this.bus = new MessageBus();
147
153
  this.configPath = serviceConfig.configPath || resolveConfigPath();
154
+ runBootstrapMigrationsSync(this.configPath);
148
155
  this.config = loadConfig(this.configPath);
149
156
  const starterResult = ensureStarterAgentsInitialized(this.config);
150
157
  if (starterResult.changed) {
@@ -204,7 +211,7 @@ var GatewayService = class {
204
211
  this.workspacePath = getWorkspacePath(this.config) || "./workspace";
205
212
  this.initializeExtensionLoader();
206
213
  this.sessionIndex = new SessionIndex({ config: this.config });
207
- this.cronService = new CronService({ maxConcurrentJobs: this.config.cron?.maxConcurrentJobs });
214
+ this.automationService = new AutomationService();
208
215
  this.notesService = new NotesService(new NotesStore());
209
216
  this.agentRunner = new GatewayAgentRunner({
210
217
  bus: this.bus,
@@ -237,10 +244,10 @@ var GatewayService = class {
237
244
  },
238
245
  getAgentService: () => this.ensureAgentService(),
239
246
  getChannelManager: () => this.channelManager,
240
- getCronService: () => this.cronService,
241
247
  getHeartbeatService: () => this.heartbeatService,
242
248
  getExtensionLoader: () => this.extensionLoader,
243
249
  reconcileBrowserExtensionServer: () => this.reconcileBrowserExtensionServer(),
250
+ reconcileDreamingAutomations: () => this.reconcileDreamingAutomations(),
244
251
  getChannelsStatus: () => this.getChannelsStatus(),
245
252
  emit: (type, payload) => this.emit(type, payload)
246
253
  });
@@ -251,7 +258,6 @@ var GatewayService = class {
251
258
  }
252
259
  ensureAgentService() {
253
260
  if (this._agentService) return this._agentService;
254
- const cronRef = { service: this.cronService };
255
261
  this._agentService = new AgentService(this.bus, {
256
262
  workspace: this.workspacePath,
257
263
  model: getAgentDefaultModelRef(this.config),
@@ -280,7 +286,7 @@ var GatewayService = class {
280
286
  });
281
287
  },
282
288
  extensionRegistry: this.extensionLoader?.getRegistry(),
283
- getCronService: () => cronRef.service,
289
+ getAutomationService: () => this.automationService,
284
290
  getWorkflowRunService: () => this.createWorkflowRunService(),
285
291
  sourceContextResolver: async (binding) => {
286
292
  if (binding.kind !== "note") return null;
@@ -305,16 +311,11 @@ var GatewayService = class {
305
311
  getModelForSession: (sk) => this._agentService.getModelForSession(sk),
306
312
  switchModelForSession: (sk, id) => this._agentService.switchModelForSession(sk, id)
307
313
  });
308
- this.cronService.setDeps({
314
+ this.automationService.setDeps({
309
315
  agentService: this._agentService,
310
- messageBus: this.bus,
311
- heartbeatService: this.ensureHeartbeatService(),
312
- sessionStore: this.sessionIndex.getStore(),
313
- getDefaultCronAgentId: () => getDefaultAgentId(this.config),
314
- workflowRunService: this.createWorkflowRunService(),
315
- goalRunner: this.createGoalRunner()
316
+ getDefaultAgentId: () => getDefaultAgentId(this.config),
317
+ workflowRunService: this.createWorkflowRunService()
316
318
  });
317
- cronRef.service = this.cronService;
318
319
  this._agentService.persistentGoals.setWebchatContinuationScheduler((sessionKey, message) => {
319
320
  const scheduleWhenIdle = () => {
320
321
  if (this._agentService.getInboundTurnDepth(sessionKey) > 0) {
@@ -336,7 +337,6 @@ var GatewayService = class {
336
337
  this.heartbeatService = new HeartbeatService({
337
338
  agentService: this.ensureAgentService(),
338
339
  messageBus: this.bus,
339
- cronService: this.cronService,
340
340
  sessionStore: this.sessionIndex.getStore(),
341
341
  getConfig: () => this.config
342
342
  });
@@ -614,15 +614,12 @@ var GatewayService = class {
614
614
  }, "Gateway channel startup phase-1 complete");
615
615
  await trace.measure("sessions.initialize", () => this.sessionIndex.initialize());
616
616
  log.debug("Session manager initialized");
617
- this.cronService.setDeps({
617
+ this.automationService.setDeps({
618
618
  agentService: this.agentService,
619
- messageBus: this.bus,
620
- heartbeatService: this.ensureHeartbeatService(),
621
- sessionStore: this.sessionIndex.getStore(),
622
- getDefaultCronAgentId: () => getDefaultAgentId(this.config),
623
- workflowRunService: this.createWorkflowRunService(),
624
- goalRunner: this.createGoalRunner()
619
+ getDefaultAgentId: () => getDefaultAgentId(this.config),
620
+ workflowRunService: this.createWorkflowRunService()
625
621
  });
622
+ this.startAutomationProductEventBridge();
626
623
  await trace.measure("workflows.reconcile", () => this.reconcileInterruptedWorkflowRuns());
627
624
  this.sessionIndex.on("sessionUpdated", (data) => {
628
625
  this.emit("session.updated", {
@@ -631,7 +628,8 @@ var GatewayService = class {
631
628
  tags: data.tags
632
629
  });
633
630
  });
634
- if (this.config.cron?.enabled !== false) await trace.measure("cron.initialize", () => this.cronService.initialize());
631
+ await trace.measure("automations.initialize", () => this.automationService.initialize());
632
+ await trace.measure("dreaming.reconcile", () => this.reconcileDreamingAutomations());
635
633
  await this.notesService.initialize();
636
634
  this.ensureHeartbeatService().start(heartbeatRunnerConfigFromConfig(this.config));
637
635
  this.connectorSupervisor = startConnectorSupervisor({
@@ -775,7 +773,11 @@ var GatewayService = class {
775
773
  this.lastChannelConnectDeferMode = "auto";
776
774
  this.lastChannelConnectDeferSource = "off";
777
775
  await this.channelManager.stop();
778
- await this.cronService.stop();
776
+ await this.automationService.stop();
777
+ this.stopAutomationProductEventBridge?.();
778
+ this.stopAutomationProductEventBridge = null;
779
+ this.stopSessionTranscriptAutomationEvents?.();
780
+ this.stopSessionTranscriptAutomationEvents = null;
779
781
  await this.notesService.flush();
780
782
  buckets.destroyAll();
781
783
  closeXopcDatabase();
@@ -1074,8 +1076,14 @@ var GatewayService = class {
1074
1076
  getEffectiveListenPort() {
1075
1077
  return resolveEffectiveGatewayPort(this.config, this.serviceConfig.listenPort);
1076
1078
  }
1077
- get cronServiceInstance() {
1078
- return this.cronService;
1079
+ get automationServiceInstance() {
1080
+ return this.automationService;
1081
+ }
1082
+ async reconcileDreamingAutomations() {
1083
+ await reconcileDreamingAutomations({
1084
+ config: this.config,
1085
+ automationService: this.automationService
1086
+ });
1079
1087
  }
1080
1088
  get notesServiceInstance() {
1081
1089
  return this.notesService;
@@ -1134,6 +1142,32 @@ var GatewayService = class {
1134
1142
  this.sse.emit(type, payload);
1135
1143
  this.createGoalNotificationService().handleGatewayEvent(type, payload);
1136
1144
  }
1145
+ startAutomationProductEventBridge() {
1146
+ this.stopAutomationProductEventBridge?.();
1147
+ this.stopSessionTranscriptAutomationEvents?.();
1148
+ this.stopAutomationProductEventBridge = onAutomationProductEvent((event) => {
1149
+ this.automationService.triggerEvent(event).catch((err) => {
1150
+ const em = err instanceof Error ? err.message : String(err);
1151
+ log.warn({
1152
+ err,
1153
+ eventType: event.type,
1154
+ source: event.source
1155
+ }, `Automation product event failed: ${em}`);
1156
+ });
1157
+ });
1158
+ this.stopSessionTranscriptAutomationEvents = onSessionTranscriptUpdate((update) => {
1159
+ if (!update.sessionKey || update.sessionKey.includes(":automation:")) return;
1160
+ publishAutomationProductEvent({
1161
+ type: "session.transcript.updated",
1162
+ source: "sessions",
1163
+ payload: {
1164
+ sessionKey: update.sessionKey,
1165
+ messageId: update.messageId,
1166
+ hasMessage: update.message !== void 0
1167
+ }
1168
+ });
1169
+ });
1170
+ }
1137
1171
  /** Replay events since `lastEventId` for SSE reconnection. */
1138
1172
  getEventsSince(sessionId, lastEventId) {
1139
1173
  return this.sse.getEventsSince(sessionId, lastEventId);