@xopcai/xopc 0.0.117 → 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 (590) hide show
  1. package/README.md +26 -24
  2. package/README.zh-CN.md +46 -42
  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-BBLhJ2C6.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-DdDx0V4z.js → apps-page-DU0dz9Zo.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-DZsVqMhU.js → archive-plugin-BkVIgZzA.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CIol6JWX.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-B3UauMfp.js → binary-plugins-B4TO_bsn.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-2HJoFchH.js → block-editor-DJRWwWNI.js} +6 -6
  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-DX5WRE_t.js → extension-debug-page-DYh402XV.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-Buah7Bw-.js → extension-page-Cr_TizrN.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-DuroLVnf.js → extension-settings-page-BU1KoKRj.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-B5zdl27C.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-gT4ZhE7h.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-B3kL8KGY.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-AR-fVh0P.js → goals-config-api-DqxVi0p5.js} +1 -1
  35. package/dist/gateway/static/root/assets/{goals-page-Cpb21ezg.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-DefCgF4o.js → logs-page-DLXPcksQ.js} +2 -2
  42. package/dist/gateway/static/root/assets/{markdown-split-ChbR9LGO.js → markdown-split-CpHxbtWJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-B82oP80n.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-CDknITM3.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-DV3xQsWB.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-BODCXnvY.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-qtfEI6QM.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-BHZKjVcS.js → settings-collapsible-section-BouO6JTi.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-form-section-5i35D-J1.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-B0H63tDv.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-BCjP_VHb.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-CeEevm7z.js +1 -0
  71. package/dist/gateway/static/root/assets/{voice-player-store-BlF9V05n.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 +6 -9
  78. package/dist/src/agent/agent-manager.js.map +1 -1
  79. package/dist/src/agent/agent-scope.js +0 -2
  80. package/dist/src/agent/agent-scope.js.map +1 -1
  81. package/dist/src/agent/background-review/prompts.d.ts +2 -2
  82. package/dist/src/agent/background-review/prompts.js +2 -2
  83. package/dist/src/agent/background-review/prompts.js.map +1 -1
  84. package/dist/src/agent/background-review/settings.d.ts +1 -1
  85. package/dist/src/agent/background-review/settings.js +7 -8
  86. package/dist/src/agent/background-review/settings.js.map +1 -1
  87. package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
  88. package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
  89. package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
  90. package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
  91. package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
  92. package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
  93. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
  94. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  95. package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
  96. package/dist/src/agent/bootstrap/load-bootstrap-files.js +17 -16
  97. package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
  98. package/dist/src/agent/bootstrap/types.d.ts +1 -1
  99. package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
  100. package/dist/src/agent/context/workspace.d.ts +4 -2
  101. package/dist/src/agent/context/workspace.js +5 -4
  102. package/dist/src/agent/context/workspace.js.map +1 -1
  103. package/dist/src/agent/embedded/run-for-session.js +106 -15
  104. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  105. package/dist/src/agent/fallback/candidates.d.ts +0 -8
  106. package/dist/src/agent/fallback/candidates.js +10 -11
  107. package/dist/src/agent/fallback/candidates.js.map +1 -1
  108. package/dist/src/agent/index.js +1 -1
  109. package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
  110. package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
  111. package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
  112. package/dist/src/agent/lifecycle/progress.d.ts +0 -1
  113. package/dist/src/agent/lifecycle/progress.js +1 -6
  114. package/dist/src/agent/lifecycle/progress.js.map +1 -1
  115. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
  116. package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
  117. package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
  118. package/dist/src/agent/memory/builtin-memory-store.d.ts +4 -2
  119. package/dist/src/agent/memory/builtin-memory-store.js +11 -6
  120. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  121. package/dist/src/agent/memory/builtin-provider.js +36 -7
  122. package/dist/src/agent/memory/builtin-provider.js.map +1 -1
  123. package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
  124. package/dist/src/agent/memory/candidate-extractor.js +60 -0
  125. package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
  126. package/dist/src/agent/memory/manager.d.ts +2 -1
  127. package/dist/src/agent/memory/manager.js +27 -3
  128. package/dist/src/agent/memory/manager.js.map +1 -1
  129. package/dist/src/agent/memory/memory-config.js +3 -0
  130. package/dist/src/agent/memory/memory-config.js.map +1 -1
  131. package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
  132. package/dist/src/agent/memory/types.d.ts +27 -4
  133. package/dist/src/agent/middleware/self-verify.d.ts +0 -1
  134. package/dist/src/agent/middleware/self-verify.js +0 -2
  135. package/dist/src/agent/middleware/self-verify.js.map +1 -1
  136. package/dist/src/agent/models/index.d.ts +1 -1
  137. package/dist/src/agent/models/manager.d.ts +4 -20
  138. package/dist/src/agent/models/manager.js +9 -126
  139. package/dist/src/agent/models/manager.js.map +1 -1
  140. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
  141. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
  142. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  143. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  144. package/dist/src/agent/prompt/memory/index.js +18 -12
  145. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  146. package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
  147. package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
  148. package/dist/src/agent/prompt/sections/tooling.js +2 -2
  149. package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
  150. package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
  151. package/dist/src/agent/prompt/service-prompt-builder.js +4 -31
  152. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  153. package/dist/src/agent/prompt/subagent-context.js +1 -1
  154. package/dist/src/agent/prompt/subagent-context.js.map +1 -1
  155. package/dist/src/agent/prompt/types.d.ts +1 -1
  156. package/dist/src/agent/reply/post-compaction-context.js +1 -3
  157. package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
  158. package/dist/src/agent/reply/startup-context.js +1 -5
  159. package/dist/src/agent/reply/startup-context.js.map +1 -1
  160. package/dist/src/agent/service.d.ts +4 -12
  161. package/dist/src/agent/service.js +10 -48
  162. package/dist/src/agent/service.js.map +1 -1
  163. package/dist/src/agent/service.types.d.ts +2 -2
  164. package/dist/src/agent/session/session-config-service.d.ts +11 -11
  165. package/dist/src/agent/session/session-config-service.js +14 -14
  166. package/dist/src/agent/session/session-config-service.js.map +1 -1
  167. package/dist/src/agent/session/session-inspector.js +3 -2
  168. package/dist/src/agent/session/session-inspector.js.map +1 -1
  169. package/dist/src/agent/starter-agents.js +12 -12
  170. package/dist/src/agent/starter-agents.js.map +1 -1
  171. package/dist/src/agent/tools/automation-tool.d.ts +14 -0
  172. package/dist/src/agent/tools/automation-tool.js +102 -0
  173. package/dist/src/agent/tools/automation-tool.js.map +1 -0
  174. package/dist/src/agent/tools/curated-memory-tool.js +57 -2
  175. package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
  176. package/dist/src/agent/tools/delegate-tool.js +1 -1
  177. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  178. package/dist/src/agent/tools/factory.d.ts +3 -3
  179. package/dist/src/agent/tools/factory.js +2 -2
  180. package/dist/src/agent/tools/factory.js.map +1 -1
  181. package/dist/src/agent/tools/index.d.ts +1 -1
  182. package/dist/src/agent/tools/index.js +2 -2
  183. package/dist/src/agent/tools/web-extract.js +6 -8
  184. package/dist/src/agent/tools/web-extract.js.map +1 -1
  185. package/dist/src/agent-manifest/index.js +2 -2
  186. package/dist/src/agent-manifest/resolver.d.ts +4 -2
  187. package/dist/src/agent-manifest/resolver.js +6 -3
  188. package/dist/src/agent-manifest/resolver.js.map +1 -1
  189. package/dist/src/agent-manifest/schema.d.ts +238 -0
  190. package/dist/src/agent-manifest/schema.js +16 -5
  191. package/dist/src/agent-manifest/schema.js.map +1 -1
  192. package/dist/src/agent-manifest/validator.d.ts +3 -2
  193. package/dist/src/agent-manifest/validator.js +2 -1
  194. package/dist/src/agent-manifest/validator.js.map +1 -1
  195. package/dist/src/ai-assist/text-assist.d.ts +1 -1
  196. package/dist/src/ai-assist/text-assist.js +56 -0
  197. package/dist/src/ai-assist/text-assist.js.map +1 -1
  198. package/dist/src/auth/profiles/store.js.map +1 -1
  199. package/dist/src/automations/api/routes.d.ts +3 -0
  200. package/dist/src/automations/api/routes.js +193 -0
  201. package/dist/src/automations/api/routes.js.map +1 -0
  202. package/dist/src/automations/domain/index.d.ts +3 -0
  203. package/dist/src/automations/domain/index.js +3 -0
  204. package/dist/src/automations/domain/schedule.d.ts +4 -0
  205. package/dist/src/automations/domain/schedule.js +37 -0
  206. package/dist/src/automations/domain/schedule.js.map +1 -0
  207. package/dist/src/automations/domain/types.d.ts +160 -0
  208. package/dist/src/automations/domain/validation.d.ts +370 -0
  209. package/dist/src/automations/domain/validation.js +149 -0
  210. package/dist/src/automations/domain/validation.js.map +1 -0
  211. package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
  212. package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
  213. package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
  214. package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
  215. package/dist/src/automations/draft/automation-draft-service.js +135 -0
  216. package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
  217. package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
  218. package/dist/src/automations/draft/automation-draft-validator.js +105 -0
  219. package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
  220. package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
  221. package/dist/src/automations/draft/index.d.ts +3 -0
  222. package/dist/src/automations/draft/index.js +3 -0
  223. package/dist/src/automations/index.d.ts +3 -0
  224. package/dist/src/automations/index.js +8 -0
  225. package/dist/src/automations/product-events.d.ts +5 -0
  226. package/dist/src/automations/product-events.js +21 -0
  227. package/dist/src/automations/product-events.js.map +1 -0
  228. package/dist/src/automations/service/action-executor.d.ts +9 -0
  229. package/dist/src/automations/service/action-executor.js +157 -0
  230. package/dist/src/automations/service/action-executor.js.map +1 -0
  231. package/dist/src/automations/service/automation-service.d.ts +54 -0
  232. package/dist/src/automations/service/automation-service.js +404 -0
  233. package/dist/src/automations/service/automation-service.js.map +1 -0
  234. package/dist/src/automations/service/index.d.ts +2 -0
  235. package/dist/src/automations/service/index.js +3 -0
  236. package/dist/src/automations/storage/automation-repository.d.ts +6 -0
  237. package/dist/src/automations/storage/automation-repository.js +61 -0
  238. package/dist/src/automations/storage/automation-repository.js.map +1 -0
  239. package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
  240. package/dist/src/automations/storage/automation-run-repository.js +130 -0
  241. package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
  242. package/dist/src/automations/storage/index.d.ts +2 -0
  243. package/dist/src/automations/storage/index.js +3 -0
  244. package/dist/src/channels/pipeline.d.ts +1 -1
  245. package/dist/src/channels/pipeline.js.map +1 -1
  246. package/dist/src/channels/plugin-types.d.ts +3 -0
  247. package/dist/src/chat-commands/agent-edit.js +0 -1
  248. package/dist/src/chat-commands/agent-edit.js.map +1 -1
  249. package/dist/src/chat-commands/builtins/model.js +2 -2
  250. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  251. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  252. package/dist/src/cli/command-catalog.js +0 -39
  253. package/dist/src/cli/command-catalog.js.map +1 -1
  254. package/dist/src/cli/command-loaders.js +0 -1
  255. package/dist/src/cli/command-loaders.js.map +1 -1
  256. package/dist/src/cli/command-manifest.d.ts +1 -1
  257. package/dist/src/cli/command-manifest.js +1 -5
  258. package/dist/src/cli/command-manifest.js.map +1 -1
  259. package/dist/src/cli/commands/agents.js +7 -6
  260. package/dist/src/cli/commands/agents.js.map +1 -1
  261. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  262. package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
  263. package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
  264. package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
  265. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -0
  266. package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
  267. package/dist/src/cli/commands/doctor/checks/workspace-status.js +0 -1
  268. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
  269. package/dist/src/cli/commands/doctor/flow.js +2 -2
  270. package/dist/src/cli/commands/doctor/flow.js.map +1 -1
  271. package/dist/src/cli/commands/gateway/call.js +2 -2
  272. package/dist/src/cli/commands/gateway/call.js.map +1 -1
  273. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  274. package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
  275. package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
  276. package/dist/src/cli/commands/init.js +33 -14
  277. package/dist/src/cli/commands/init.js.map +1 -1
  278. package/dist/src/cli/commands/models.js +13 -31
  279. package/dist/src/cli/commands/models.js.map +1 -1
  280. package/dist/src/cli/commands/onboard/model.js +17 -10
  281. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  282. package/dist/src/cli/commands/onboard.js +2 -2
  283. package/dist/src/cli/commands/onboard.js.map +1 -1
  284. package/dist/src/cli/commands/tui.js +26 -4
  285. package/dist/src/cli/commands/tui.js.map +1 -1
  286. package/dist/src/cli/index.d.ts +1 -0
  287. package/dist/src/cli/index.js +10 -5
  288. package/dist/src/cli/index.js.map +1 -1
  289. package/dist/src/cli/registry.js +1 -1
  290. package/dist/src/cli/registry.js.map +1 -1
  291. package/dist/src/cli/templates.d.ts +1 -1
  292. package/dist/src/cli/templates.js +1 -11
  293. package/dist/src/cli/templates.js.map +1 -1
  294. package/dist/src/cli/utils/init-workspace-core.js +2 -0
  295. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  296. package/dist/src/commands/agents.config.d.ts +9 -0
  297. package/dist/src/commands/agents.config.js +42 -12
  298. package/dist/src/commands/agents.config.js.map +1 -1
  299. package/dist/src/config/agent-profile.js +5 -3
  300. package/dist/src/config/agent-profile.js.map +1 -1
  301. package/dist/src/config/agent-typed-models.js +3 -5
  302. package/dist/src/config/agent-typed-models.js.map +1 -1
  303. package/dist/src/config/config-surface.d.ts +3 -0
  304. package/dist/src/config/index.d.ts +0 -1
  305. package/dist/src/config/index.js +3 -3
  306. package/dist/src/config/index.js.map +1 -1
  307. package/dist/src/config/paths.d.ts +8 -10
  308. package/dist/src/config/paths.js +16 -16
  309. package/dist/src/config/paths.js.map +1 -1
  310. package/dist/src/config/profile.js +0 -1
  311. package/dist/src/config/profile.js.map +1 -1
  312. package/dist/src/config/rules.js +0 -5
  313. package/dist/src/config/rules.js.map +1 -1
  314. package/dist/src/config/schema.d.ts +45 -44
  315. package/dist/src/config/schema.js +68 -52
  316. package/dist/src/config/schema.js.map +1 -1
  317. package/dist/src/config/web-patch.d.ts +0 -12
  318. package/dist/src/config/web-patch.js +2 -29
  319. package/dist/src/config/web-patch.js.map +1 -1
  320. package/dist/src/extensions/api.d.ts +2 -0
  321. package/dist/src/extensions/api.js +10 -0
  322. package/dist/src/extensions/api.js.map +1 -1
  323. package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
  324. package/dist/src/extensions/extension-registry-impl.js +8 -0
  325. package/dist/src/extensions/extension-registry-impl.js.map +1 -1
  326. package/dist/src/extensions/loader.d.ts +3 -3
  327. package/dist/src/extensions/loader.js +3 -3
  328. package/dist/src/extensions/loader.js.map +1 -1
  329. package/dist/src/extensions/sdk/testing.d.ts +2 -0
  330. package/dist/src/extensions/sdk/testing.js +7 -0
  331. package/dist/src/extensions/sdk/testing.js.map +1 -1
  332. package/dist/src/extensions/types/core.d.ts +10 -1
  333. package/dist/src/extensions/types/index.d.ts +1 -1
  334. package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
  335. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  336. package/dist/src/gateway/agent-builtin-tools.js +1 -1
  337. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  338. package/dist/src/gateway/agents-admin.d.ts +8 -0
  339. package/dist/src/gateway/agents-admin.js +63 -34
  340. package/dist/src/gateway/agents-admin.js.map +1 -1
  341. package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
  342. package/dist/src/gateway/capability-presets-admin.js +19 -10
  343. package/dist/src/gateway/capability-presets-admin.js.map +1 -1
  344. package/dist/src/gateway/chat-stream/mapper.js +9 -2
  345. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  346. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
  347. package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
  348. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
  349. package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
  350. package/dist/src/gateway/global-defaults-admin.js +146 -0
  351. package/dist/src/gateway/global-defaults-admin.js.map +1 -0
  352. package/dist/src/gateway/heartbeat/service.d.ts +0 -2
  353. package/dist/src/gateway/heartbeat/service.js +0 -7
  354. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  355. package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
  356. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  357. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  358. package/dist/src/gateway/hono/routes/agents.js +33 -1
  359. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  360. package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
  361. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  362. package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
  363. package/dist/src/gateway/hono/routes/config-patch/misc.js +12 -6
  364. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  365. package/dist/src/gateway/hono/routes/dreaming.js +27 -37
  366. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  367. package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
  368. package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
  369. package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
  370. package/dist/src/gateway/hono/routes/home.d.ts +2 -2
  371. package/dist/src/gateway/hono/routes/home.js +34 -25
  372. package/dist/src/gateway/hono/routes/home.js.map +1 -1
  373. package/dist/src/gateway/hono/routes/lazy-bundles.js +21 -9
  374. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  375. package/dist/src/gateway/hono/routes/memory.js +75 -4
  376. package/dist/src/gateway/hono/routes/memory.js.map +1 -1
  377. package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
  378. package/dist/src/gateway/hono/routes/migrations.js +35 -0
  379. package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
  380. package/dist/src/gateway/hono/routes/models.js +1 -1
  381. package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
  382. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  383. package/dist/src/gateway/hono/routes/sessions.js +14 -0
  384. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  385. package/dist/src/gateway/run-loop.js +2 -0
  386. package/dist/src/gateway/run-loop.js.map +1 -1
  387. package/dist/src/gateway/security/operator-scopes.js +5 -1
  388. package/dist/src/gateway/security/operator-scopes.js.map +1 -1
  389. package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
  390. package/dist/src/gateway/service/config-coordinator.js +14 -8
  391. package/dist/src/gateway/service/config-coordinator.js.map +1 -1
  392. package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
  393. package/dist/src/gateway/service/marketplace-service.js +11 -7
  394. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  395. package/dist/src/gateway/service/sessions-api.d.ts +2 -1
  396. package/dist/src/gateway/service/sessions-api.js +6 -1
  397. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  398. package/dist/src/gateway/service.d.ts +7 -3
  399. package/dist/src/gateway/service.js +61 -27
  400. package/dist/src/gateway/service.js.map +1 -1
  401. package/dist/src/goals/goal-service.js +45 -4
  402. package/dist/src/goals/goal-service.js.map +1 -1
  403. package/dist/src/infra/update-restart.js +1 -1
  404. package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
  405. package/dist/src/migrations/config/default-capability-preset.js +135 -0
  406. package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
  407. package/dist/src/migrations/index.d.ts +4 -0
  408. package/dist/src/migrations/index.js +4 -0
  409. package/dist/src/migrations/registry.d.ts +8 -0
  410. package/dist/src/migrations/registry.js +18 -0
  411. package/dist/src/migrations/registry.js.map +1 -0
  412. package/dist/src/migrations/runner.d.ts +17 -0
  413. package/dist/src/migrations/runner.js +191 -0
  414. package/dist/src/migrations/runner.js.map +1 -0
  415. package/dist/src/migrations/types.d.ts +34 -0
  416. package/dist/src/notes/service.js +27 -2
  417. package/dist/src/notes/service.js.map +1 -1
  418. package/dist/src/providers/index.d.ts +4 -5
  419. package/dist/src/providers/index.js +16 -16
  420. package/dist/src/providers/index.js.map +1 -1
  421. package/dist/src/providers/model-registry.d.ts +0 -1
  422. package/dist/src/providers/model-registry.js +0 -3
  423. package/dist/src/providers/model-registry.js.map +1 -1
  424. package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
  425. package/dist/src/routing/resolve-tui-session-key.js +14 -3
  426. package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
  427. package/dist/src/session/session-workspace.js +2 -7
  428. package/dist/src/session/session-workspace.js.map +1 -1
  429. package/dist/src/session/store.js +0 -5
  430. package/dist/src/session/store.js.map +1 -1
  431. package/dist/src/session/transcript-outline.d.ts +47 -0
  432. package/dist/src/session/transcript-outline.js +481 -0
  433. package/dist/src/session/transcript-outline.js.map +1 -0
  434. package/dist/src/storage/sqlite/index.d.ts +1 -3
  435. package/dist/src/storage/sqlite/index.js +2 -4
  436. package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
  437. package/dist/src/storage/sqlite/memory-index-repository.js +15 -14
  438. package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
  439. package/dist/src/storage/sqlite/memory-records-repository.d.ts +44 -1
  440. package/dist/src/storage/sqlite/memory-records-repository.js +164 -20
  441. package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
  442. package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
  443. package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
  444. package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
  445. package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
  446. package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -0
  447. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  448. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  449. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  450. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  451. package/dist/src/storage/sqlite/schema.js +1 -1
  452. package/dist/src/storage/sqlite/schema.sql +56 -46
  453. package/dist/src/tui/backends/embedded-backend.d.ts +9 -0
  454. package/dist/src/tui/backends/embedded-backend.js +55 -27
  455. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  456. package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -0
  457. package/dist/src/tui/backends/gateway-sse-backend.js +30 -3
  458. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  459. package/dist/src/tui/components/tui-header.d.ts +0 -1
  460. package/dist/src/tui/components/tui-header.js +3 -8
  461. package/dist/src/tui/components/tui-header.js.map +1 -1
  462. package/dist/src/tui/tui-backend.d.ts +4 -0
  463. package/dist/src/tui/tui-commands.d.ts +5 -0
  464. package/dist/src/tui/tui-commands.js +43 -0
  465. package/dist/src/tui/tui-commands.js.map +1 -1
  466. package/dist/src/tui/tui-startup-resources.js +2 -1
  467. package/dist/src/tui/tui-startup-resources.js.map +1 -1
  468. package/dist/src/tui/tui-startup-text.js +12 -12
  469. package/dist/src/tui/tui-startup-text.js.map +1 -1
  470. package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
  471. package/dist/src/tui/tui-transcript-tree.js +17 -257
  472. package/dist/src/tui/tui-transcript-tree.js.map +1 -1
  473. package/dist/src/tui/tui-types.d.ts +2 -0
  474. package/dist/src/tui/tui-types.js.map +1 -1
  475. package/dist/src/tui/tui.js +11 -3
  476. package/dist/src/tui/tui.js.map +1 -1
  477. package/dist/src/workflows/domain/index.js +1 -1
  478. package/dist/src/workflows/domain/run.d.ts +7 -7
  479. package/dist/src/workflows/domain/run.js.map +1 -1
  480. package/dist/src/workflows/index.js +2 -2
  481. package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
  482. package/dist/src/workflows/service/workflow-run-service.js +31 -9
  483. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  484. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
  485. package/package.json +4 -2
  486. package/dist/gateway/static/root/assets/agents-C6xgagZd.js +0 -71
  487. package/dist/gateway/static/root/assets/app-management-settings-panel-CBpLONvG.js +0 -1
  488. package/dist/gateway/static/root/assets/appearance-settings-CGcc54yj.js +0 -1
  489. package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +0 -8
  490. package/dist/gateway/static/root/assets/capability-presets-api-XQoMTI0A.js +0 -1
  491. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +0 -1
  492. package/dist/gateway/static/root/assets/channels-settings-BYyRzsex.js +0 -1
  493. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
  494. package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +0 -2
  495. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
  496. package/dist/gateway/static/root/assets/cron-api-R41aQCX9.js +0 -1
  497. package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
  498. package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +0 -3
  499. package/dist/gateway/static/root/assets/dreaming-settings-Bceaw1PG.js +0 -1
  500. package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
  501. package/dist/gateway/static/root/assets/format-interval-label-Dn_QKIqb.js +0 -1
  502. package/dist/gateway/static/root/assets/gateway-settings-iISWAZRm.js +0 -1
  503. package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +0 -1
  504. package/dist/gateway/static/root/assets/goals-settings-CPAuFwoD.js +0 -1
  505. package/dist/gateway/static/root/assets/heartbeat-config-api-D7bKFEeO.js +0 -1
  506. package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +0 -1
  507. package/dist/gateway/static/root/assets/index-CwhK8qCh.js +0 -122
  508. package/dist/gateway/static/root/assets/index-CyfhARL-.css +0 -1
  509. package/dist/gateway/static/root/assets/interval-presets-0DtsnxE0.js +0 -1
  510. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BPREtN8B.js +0 -1
  511. package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +0 -3
  512. package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +0 -2
  513. package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +0 -2
  514. package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +0 -1
  515. package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +0 -1
  516. package/dist/gateway/static/root/assets/schedule-field-CgJSCD3B.js +0 -1
  517. package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +0 -1
  518. package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +0 -1
  519. package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +0 -1
  520. package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +0 -1
  521. package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +0 -1
  522. package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +0 -1
  523. package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +0 -2
  524. package/dist/gateway/static/root/assets/system-settings-panel-DXs2VmBt.js +0 -1
  525. package/dist/gateway/static/root/assets/typed-models-lib-4gPuydz_.js +0 -1
  526. package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +0 -1
  527. package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +0 -18
  528. package/dist/src/agent/context/workspace-templates/USER.md +0 -24
  529. package/dist/src/agent/fallback/error.d.ts +0 -22
  530. package/dist/src/agent/fallback/error.js +0 -32
  531. package/dist/src/agent/fallback/error.js.map +0 -1
  532. package/dist/src/agent/fallback/index.d.ts +0 -5
  533. package/dist/src/agent/fallback/index.js +0 -9
  534. package/dist/src/agent/fallback/index.js.map +0 -1
  535. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
  536. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
  537. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
  538. package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
  539. package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
  540. package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
  541. package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
  542. package/dist/src/agent/tools/cronjob-tool.js +0 -274
  543. package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
  544. package/dist/src/cli/commands/cron-cli.d.ts +0 -2
  545. package/dist/src/cli/commands/cron-cli.js +0 -15
  546. package/dist/src/cli/commands/cron-cli.js.map +0 -1
  547. package/dist/src/cli/commands/cron.d.ts +0 -4
  548. package/dist/src/cli/commands/cron.js +0 -188
  549. package/dist/src/cli/commands/cron.js.map +0 -1
  550. package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
  551. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
  552. package/dist/src/cron/execution-types.d.ts +0 -42
  553. package/dist/src/cron/executor.d.ts +0 -67
  554. package/dist/src/cron/executor.js +0 -669
  555. package/dist/src/cron/executor.js.map +0 -1
  556. package/dist/src/cron/index.d.ts +0 -7
  557. package/dist/src/cron/index.js +0 -7
  558. package/dist/src/cron/job-content.d.ts +0 -5
  559. package/dist/src/cron/job-content.js +0 -15
  560. package/dist/src/cron/job-content.js.map +0 -1
  561. package/dist/src/cron/run-log-store.d.ts +0 -12
  562. package/dist/src/cron/run-log-store.js +0 -58
  563. package/dist/src/cron/run-log-store.js.map +0 -1
  564. package/dist/src/cron/schedule.d.ts +0 -10
  565. package/dist/src/cron/schedule.js +0 -85
  566. package/dist/src/cron/schedule.js.map +0 -1
  567. package/dist/src/cron/service.d.ts +0 -58
  568. package/dist/src/cron/service.js +0 -419
  569. package/dist/src/cron/service.js.map +0 -1
  570. package/dist/src/cron/types.d.ts +0 -183
  571. package/dist/src/cron/validation.d.ts +0 -500
  572. package/dist/src/cron/validation.js +0 -192
  573. package/dist/src/cron/validation.js.map +0 -1
  574. package/dist/src/cron/workflow-run-completion.d.ts +0 -23
  575. package/dist/src/cron/workflow-run-completion.js +0 -72
  576. package/dist/src/cron/workflow-run-completion.js.map +0 -1
  577. package/dist/src/extensions/types/phase4.js +0 -1
  578. package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
  579. package/dist/src/gateway/hono/routes/cron.js +0 -109
  580. package/dist/src/gateway/hono/routes/cron.js.map +0 -1
  581. package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
  582. package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
  583. package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
  584. package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
  585. package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
  586. package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
  587. /package/dist/src/{cron → automations/domain}/types.js +0 -0
  588. /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
  589. /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
  590. /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { SessionMetadataSeed } from '../../../storage/sqlite/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteError } from '../lib/route-logger.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport type { SessionType } from '../../../session/types.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { deleteMediaUrisNoLongerReferenced } from '../../../media/session-references.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\nimport { evictEmbeddedSessionRunner } from '../../../agent/embedded/session-runner.js';\n\nconst log = createGatewayRouteLogger('Sessions');\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nconst SESSION_TYPES = new Set<SessionType>(['chat', 'workflow-run', 'workflow-subagent', 'cron', 'heartbeat']);\n\nfunction isSessionType(value: string): value is SessionType {\n return SESSION_TYPES.has(value as SessionType);\n}\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nfunction buildDirectSessionMetadata(params: {\n agentId: string;\n source: string;\n accountId: string;\n peerId: string;\n}): SessionMetadataSeed {\n return {\n sourceChannel: params.source,\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n routing: {\n agentId: params.agentId,\n source: params.source,\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n };\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: body.chat_id,\n }),\n });\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n // Look for existing empty sessions to reuse\n const existingSessions = await service.sessions.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n return s.routing?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.sessions.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: chatId,\n }),\n });\n\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const sessionTypes = query.types\n ?.split(',')\n .map((value) => value.trim())\n .filter(isSessionType);\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n sessionTypes: sessionTypes?.length ? sessionTypes : undefined,\n includeHidden: query.includeHidden === 'true',\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/resolve?sessionId=... - Resolve OpenClaw-style session id to canonical key.\n authenticated.get('/api/sessions/resolve', async (c) => {\n const result = await service.sessions.resolveSession({\n sessionId: c.req.query('sessionId'),\n sessionKey: c.req.query('sessionKey') ?? c.req.query('key'),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // POST /api/sessions/resolve - Resolve by JSON body (`sessionId`, `sessionKey`, or `key`).\n authenticated.post('/api/sessions/resolve', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.resolveSession({\n sessionId: typeof body.sessionId === 'string' ? body.sessionId : undefined,\n sessionKey: typeof body.sessionKey === 'string' ? body.sessionKey : undefined,\n key: typeof body.key === 'string' ? body.key : undefined,\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/label — append label change for a transcript entry.\n authenticated.post('/api/sessions/:key/transcript/label', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const targetId = typeof body.targetId === 'string' ? body.targetId.trim() : '';\n if (!targetId) {\n return c.json({ ok: false, error: 'targetId is required' }, 400);\n }\n const label = typeof body.label === 'string' && body.label.trim() ? body.label.trim() : undefined;\n await service.sessionIndexInstance.appendTranscriptLabelEntry(key, { targetId, label });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom — append extension state for TUI replay.\n authenticated.post('/api/sessions/:key/transcript/custom', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptCustomEntry(key, {\n customType,\n data: body.data,\n });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom-message — append visible extension custom message.\n authenticated.post('/api/sessions/:key/transcript/custom-message', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n const content =\n typeof body.content === 'string' || Array.isArray(body.content) ? body.content : '';\n await service.sessionIndexInstance.appendTranscriptCustomMessageEntry(key, {\n customType,\n content,\n display: typeof body.display === 'boolean' ? body.display : undefined,\n details: body.details,\n });\n evictEmbeddedSessionRunner(key, 'gateway_custom_message_appended');\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/bash — append local TUI shell execution.\n authenticated.post('/api/sessions/:key/transcript/bash', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const command = typeof body.command === 'string' ? body.command.trim() : '';\n if (!command) {\n return c.json({ ok: false, error: 'command is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptBashExecutionEntry(key, {\n command,\n output: typeof body.output === 'string' ? body.output : '',\n exitCode: typeof body.exitCode === 'number' ? body.exitCode : body.exitCode === null ? null : undefined,\n signal: typeof body.signal === 'string' ? body.signal : body.signal === null ? null : undefined,\n excludeFromContext: body.excludeFromContext === true,\n truncated: body.truncated === true,\n fullOutputPath: typeof body.fullOutputPath === 'string' ? body.fullOutputPath : undefined,\n });\n evictEmbeddedSessionRunner(key, 'gateway_bash_execution_appended');\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n logRouteError(log, c, err, 'gateway.route.sessions', { operation: 'restoreCheckpoint', sessionKey: key });\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/import', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const content = typeof body.content === 'string' ? body.content : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!content.trim()) {\n return c.json({ ok: false, error: 'content is required' }, 400);\n }\n try {\n const result = await service.sessions.importExport(targetKey, content);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/btw', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const question = typeof body.question === 'string' ? body.question : '';\n const result = await service.sessions.btwQuery(key, question);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/:key/fork', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n try {\n const result = await service.sessions.fork(key, targetKey);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/fork-row', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const throughRow = typeof body.throughRow === 'number' ? Math.trunc(body.throughRow) : NaN;\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!Number.isFinite(throughRow) || throughRow < 1) {\n return c.json({ ok: false, error: 'throughRow must be a positive integer' }, 400);\n }\n try {\n const result = await service.sessions.forkRows(key, targetKey, { throughRow });\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const removed = loaded.slice(startIndex, startIndex + deleteCount);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n await deleteMediaUrisNoLongerReferenced({ removed, remaining: next });\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { SessionMetadataSeed } from '../../../storage/sqlite/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteError } from '../lib/route-logger.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport type { SessionType } from '../../../session/types.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { deleteMediaUrisNoLongerReferenced } from '../../../media/session-references.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\nimport { evictEmbeddedSessionRunner } from '../../../agent/embedded/session-runner.js';\n\nconst log = createGatewayRouteLogger('Sessions');\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nconst SESSION_TYPES = new Set<SessionType>(['chat', 'workflow-run', 'workflow-subagent', 'cron', 'heartbeat']);\n\nfunction isSessionType(value: string): value is SessionType {\n return SESSION_TYPES.has(value as SessionType);\n}\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nfunction buildDirectSessionMetadata(params: {\n agentId: string;\n source: string;\n accountId: string;\n peerId: string;\n}): SessionMetadataSeed {\n return {\n sourceChannel: params.source,\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n routing: {\n agentId: params.agentId,\n source: params.source,\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n };\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: body.chat_id,\n }),\n });\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n // Look for existing empty sessions to reuse\n const existingSessions = await service.sessions.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n return s.routing?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.sessions.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: chatId,\n }),\n });\n\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const sessionTypes = query.types\n ?.split(',')\n .map((value) => value.trim())\n .filter(isSessionType);\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n sessionTypes: sessionTypes?.length ? sessionTypes : undefined,\n includeHidden: query.includeHidden === 'true',\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/resolve?sessionId=... - Resolve OpenClaw-style session id to canonical key.\n authenticated.get('/api/sessions/resolve', async (c) => {\n const result = await service.sessions.resolveSession({\n sessionId: c.req.query('sessionId'),\n sessionKey: c.req.query('sessionKey') ?? c.req.query('key'),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // POST /api/sessions/resolve - Resolve by JSON body (`sessionId`, `sessionKey`, or `key`).\n authenticated.post('/api/sessions/resolve', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.resolveSession({\n sessionId: typeof body.sessionId === 'string' ? body.sessionId : undefined,\n sessionKey: typeof body.sessionKey === 'string' ? body.sessionKey : undefined,\n key: typeof body.key === 'string' ? body.key : undefined,\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // GET /api/sessions/:key/timeline — row-backed conversation outline for Web / TUI navigation.\n authenticated.get('/api/sessions/:key/timeline', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const items = await service.sessions.getTimeline(key);\n if (!items) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, items });\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/label — append label change for a transcript entry.\n authenticated.post('/api/sessions/:key/transcript/label', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const targetId = typeof body.targetId === 'string' ? body.targetId.trim() : '';\n if (!targetId) {\n return c.json({ ok: false, error: 'targetId is required' }, 400);\n }\n const label = typeof body.label === 'string' && body.label.trim() ? body.label.trim() : undefined;\n await service.sessionIndexInstance.appendTranscriptLabelEntry(key, { targetId, label });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom — append extension state for TUI replay.\n authenticated.post('/api/sessions/:key/transcript/custom', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptCustomEntry(key, {\n customType,\n data: body.data,\n });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom-message — append visible extension custom message.\n authenticated.post('/api/sessions/:key/transcript/custom-message', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n const content =\n typeof body.content === 'string' || Array.isArray(body.content) ? body.content : '';\n await service.sessionIndexInstance.appendTranscriptCustomMessageEntry(key, {\n customType,\n content,\n display: typeof body.display === 'boolean' ? body.display : undefined,\n details: body.details,\n });\n evictEmbeddedSessionRunner(key, 'gateway_custom_message_appended');\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/bash — append local TUI shell execution.\n authenticated.post('/api/sessions/:key/transcript/bash', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const command = typeof body.command === 'string' ? body.command.trim() : '';\n if (!command) {\n return c.json({ ok: false, error: 'command is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptBashExecutionEntry(key, {\n command,\n output: typeof body.output === 'string' ? body.output : '',\n exitCode: typeof body.exitCode === 'number' ? body.exitCode : body.exitCode === null ? null : undefined,\n signal: typeof body.signal === 'string' ? body.signal : body.signal === null ? null : undefined,\n excludeFromContext: body.excludeFromContext === true,\n truncated: body.truncated === true,\n fullOutputPath: typeof body.fullOutputPath === 'string' ? body.fullOutputPath : undefined,\n });\n evictEmbeddedSessionRunner(key, 'gateway_bash_execution_appended');\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n logRouteError(log, c, err, 'gateway.route.sessions', { operation: 'restoreCheckpoint', sessionKey: key });\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/import', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const content = typeof body.content === 'string' ? body.content : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!content.trim()) {\n return c.json({ ok: false, error: 'content is required' }, 400);\n }\n try {\n const result = await service.sessions.importExport(targetKey, content);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/btw', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const question = typeof body.question === 'string' ? body.question : '';\n const result = await service.sessions.btwQuery(key, question);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/:key/fork', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n try {\n const result = await service.sessions.fork(key, targetKey);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/fork-row', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const throughRow = typeof body.throughRow === 'number' ? Math.trunc(body.throughRow) : NaN;\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!Number.isFinite(throughRow) || throughRow < 1) {\n return c.json({ ok: false, error: 'throughRow must be a positive integer' }, 400);\n }\n try {\n const result = await service.sessions.forkRows(key, targetKey, { throughRow });\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const removed = loaded.slice(startIndex, startIndex + deleteCount);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n await deleteMediaUrisNoLongerReferenced({ removed, remaining: next });\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
2
  import "../config/index.js";
3
3
  import { isRestartEnabled } from "../config/commands.flags.js";
4
+ import { runBootstrapMigrationsSync } from "../migrations/runner.js";
4
5
  import { restartGatewayProcessWithFreshPid } from "./respawn.js";
5
6
  import { acquireGatewayLock } from "./lock.js";
6
7
  import { consumeGatewayRestartIntentSync, consumeGatewaySigusr1RestartAuthorization, isGatewaySigusr1RestartExternallyAllowed, resetGatewayRestartStateForInProcessRestart, scheduleGatewaySigusr1Restart, setGatewaySigusr1RestartPolicy } from "../infra/restart.js";
@@ -9,6 +10,7 @@ import { consumeGatewayRestartIntentSync, consumeGatewaySigusr1RestartAuthorizat
9
10
  * Gateway Run Loop - Core run loop for gateway process management
10
11
  */
11
12
  async function runGatewayLoop(opts) {
13
+ runBootstrapMigrationsSync(opts.configPath);
12
14
  setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(loadConfig(opts.configPath)) });
13
15
  let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });
14
16
  let server = null;
@@ -1 +1 @@
1
- {"version":3,"file":"run-loop.js","names":[],"sources":["../../../src/gateway/run-loop.ts"],"sourcesContent":["/**\n * Gateway Run Loop - Core run loop for gateway process management\n */\n\nimport { isRestartEnabled } from '../config/commands.flags.js';\nimport { loadConfig } from '../config/index.js';\nimport type { GatewayServer } from './server.js';\nimport { acquireGatewayLock } from './lock.js';\nimport { restartGatewayProcessWithFreshPid } from './respawn.js';\nimport {\n consumeGatewayRestartIntentSync,\n consumeGatewaySigusr1RestartAuthorization,\n isGatewaySigusr1RestartExternallyAllowed,\n resetGatewayRestartStateForInProcessRestart,\n scheduleGatewaySigusr1Restart,\n setGatewaySigusr1RestartPolicy,\n} from '../infra/restart.js';\n\ntype GatewayRunSignalAction = 'stop' | 'restart';\n\nexport type RunGatewayLoopOptions = {\n start: () => Promise<GatewayServer>;\n configPath: string;\n port: number;\n};\n\nexport async function runGatewayLoop(opts: RunGatewayLoopOptions): Promise<void> {\n const config = loadConfig(opts.configPath);\n setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(config) });\n\n let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });\n let server: GatewayServer | null = null;\n let shuttingDown = false;\n let restartResolver: (() => void) | null = null;\n\n const cleanupSignals = () => {\n process.removeListener('SIGTERM', onSigterm);\n process.removeListener('SIGINT', onSigint);\n process.removeListener('SIGUSR1', onSigusr1);\n };\n\n const exitProcess = (code: number) => {\n cleanupSignals();\n process.exit(code);\n };\n\n const releaseLock = async (): Promise<void> => {\n if (lock) {\n await lock.release();\n lock = null;\n }\n };\n\n const handleRestartAfterClose = async () => {\n await releaseLock();\n\n const respawn = restartGatewayProcessWithFreshPid();\n\n if (respawn.mode === 'spawned' || respawn.mode === 'supervised') {\n const modeLabel = respawn.mode === 'spawned'\n ? `spawned pid ${respawn.pid ?? 'unknown'}`\n : 'supervisor restart';\n console.log(`[GatewayRunLoop] Restart mode: full process restart (${modeLabel})`);\n exitProcess(0);\n return;\n }\n\n if (respawn.mode === 'failed') {\n console.warn(`[GatewayRunLoop] Full process restart failed: ${respawn.detail ?? 'unknown error'}`);\n } else {\n console.log('[GatewayRunLoop] Restart mode: in-process restart (XOPC_NO_RESPAWN)');\n }\n\n resetGatewayRestartStateForInProcessRestart();\n\n try {\n lock = await acquireGatewayLock(opts.configPath, { port: opts.port });\n } catch (err) {\n console.error(`[GatewayRunLoop] Failed to reacquire lock: ${String(err)}`);\n exitProcess(1);\n return;\n }\n\n shuttingDown = false;\n restartResolver?.();\n };\n\n const handleStopAfterClose = async () => {\n await releaseLock();\n exitProcess(0);\n };\n\n const DRAIN_TIMEOUT_MS = 30_000;\n const SHUTDOWN_TIMEOUT_MS = 15_000;\n\n const requestShutdown = (action: GatewayRunSignalAction, signal: string) => {\n if (shuttingDown) {\n return;\n }\n\n shuttingDown = true;\n const isRestart = action === 'restart';\n console.log(`[GatewayRunLoop] Received ${signal}; ${isRestart ? 'restarting' : 'shutting down'}`);\n\n cleanupSignals();\n\n const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;\n const forceExitTimer = setTimeout(() => {\n console.error('[GatewayRunLoop] Shutdown timed out; force exiting');\n exitProcess(0);\n }, forceExitMs);\n\n void (async () => {\n try {\n if (isRestart) {\n console.log('[GatewayRunLoop] Draining active tasks before restart...');\n }\n\n await server?.close?.({\n reason: isRestart ? 'gateway restarting' : 'gateway stopping',\n restartExpectedMs: isRestart ? 1500 : null,\n });\n } catch (err) {\n console.error(`[GatewayRunLoop] Shutdown error: ${String(err)}`);\n } finally {\n clearTimeout(forceExitTimer);\n server = null;\n\n if (isRestart) {\n await handleRestartAfterClose();\n } else {\n await handleStopAfterClose();\n }\n }\n })();\n };\n\n const onSigterm = () => {\n console.log('[GatewayRunLoop] SIGTERM received');\n const isRestart = consumeGatewayRestartIntentSync();\n requestShutdown(isRestart ? 'restart' : 'stop', 'SIGTERM');\n };\n\n const onSigint = () => {\n console.log('[GatewayRunLoop] SIGINT received');\n requestShutdown('stop', 'SIGINT');\n };\n\n const onSigusr1 = () => {\n console.log('[GatewayRunLoop] SIGUSR1 received');\n const authorized = consumeGatewaySigusr1RestartAuthorization();\n if (!authorized) {\n if (!isGatewaySigusr1RestartExternallyAllowed()) {\n console.warn(\n '[GatewayRunLoop] SIGUSR1 restart ignored (commands.restart=false or unauthorized).',\n );\n return;\n }\n if (shuttingDown) {\n console.log('[GatewayRunLoop] Received SIGUSR1 during shutdown; ignoring');\n return;\n }\n scheduleGatewaySigusr1Restart({\n delayMs: 0,\n reason: 'SIGUSR1',\n onRestart: () => requestShutdown('restart', 'SIGUSR1'),\n });\n return;\n }\n requestShutdown('restart', 'SIGUSR1');\n };\n\n process.on('SIGTERM', onSigterm);\n process.on('SIGINT', onSigint);\n process.on('SIGUSR1', onSigusr1);\n\n try {\n while (true) {\n console.log('[GatewayRunLoop] Starting gateway server...');\n try {\n server = await opts.start();\n } catch (err) {\n console.error('[GatewayRunLoop] Failed to start gateway server:', err);\n await releaseLock();\n exitProcess(1);\n return;\n }\n\n await new Promise<void>((resolve) => {\n restartResolver = resolve;\n });\n\n console.log('[GatewayRunLoop] Restart signal received, restarting gateway...');\n }\n } finally {\n await releaseLock();\n cleanupSignals();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-loop.js","names":[],"sources":["../../../src/gateway/run-loop.ts"],"sourcesContent":["/**\n * Gateway Run Loop - Core run loop for gateway process management\n */\n\nimport { isRestartEnabled } from '../config/commands.flags.js';\nimport { loadConfig } from '../config/index.js';\nimport { runBootstrapMigrationsSync } from '../migrations/runner.js';\nimport type { GatewayServer } from './server.js';\nimport { acquireGatewayLock } from './lock.js';\nimport { restartGatewayProcessWithFreshPid } from './respawn.js';\nimport {\n consumeGatewayRestartIntentSync,\n consumeGatewaySigusr1RestartAuthorization,\n isGatewaySigusr1RestartExternallyAllowed,\n resetGatewayRestartStateForInProcessRestart,\n scheduleGatewaySigusr1Restart,\n setGatewaySigusr1RestartPolicy,\n} from '../infra/restart.js';\n\ntype GatewayRunSignalAction = 'stop' | 'restart';\n\nexport type RunGatewayLoopOptions = {\n start: () => Promise<GatewayServer>;\n configPath: string;\n port: number;\n};\n\nexport async function runGatewayLoop(opts: RunGatewayLoopOptions): Promise<void> {\n runBootstrapMigrationsSync(opts.configPath);\n const config = loadConfig(opts.configPath);\n setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(config) });\n\n let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });\n let server: GatewayServer | null = null;\n let shuttingDown = false;\n let restartResolver: (() => void) | null = null;\n\n const cleanupSignals = () => {\n process.removeListener('SIGTERM', onSigterm);\n process.removeListener('SIGINT', onSigint);\n process.removeListener('SIGUSR1', onSigusr1);\n };\n\n const exitProcess = (code: number) => {\n cleanupSignals();\n process.exit(code);\n };\n\n const releaseLock = async (): Promise<void> => {\n if (lock) {\n await lock.release();\n lock = null;\n }\n };\n\n const handleRestartAfterClose = async () => {\n await releaseLock();\n\n const respawn = restartGatewayProcessWithFreshPid();\n\n if (respawn.mode === 'spawned' || respawn.mode === 'supervised') {\n const modeLabel = respawn.mode === 'spawned'\n ? `spawned pid ${respawn.pid ?? 'unknown'}`\n : 'supervisor restart';\n console.log(`[GatewayRunLoop] Restart mode: full process restart (${modeLabel})`);\n exitProcess(0);\n return;\n }\n\n if (respawn.mode === 'failed') {\n console.warn(`[GatewayRunLoop] Full process restart failed: ${respawn.detail ?? 'unknown error'}`);\n } else {\n console.log('[GatewayRunLoop] Restart mode: in-process restart (XOPC_NO_RESPAWN)');\n }\n\n resetGatewayRestartStateForInProcessRestart();\n\n try {\n lock = await acquireGatewayLock(opts.configPath, { port: opts.port });\n } catch (err) {\n console.error(`[GatewayRunLoop] Failed to reacquire lock: ${String(err)}`);\n exitProcess(1);\n return;\n }\n\n shuttingDown = false;\n restartResolver?.();\n };\n\n const handleStopAfterClose = async () => {\n await releaseLock();\n exitProcess(0);\n };\n\n const DRAIN_TIMEOUT_MS = 30_000;\n const SHUTDOWN_TIMEOUT_MS = 15_000;\n\n const requestShutdown = (action: GatewayRunSignalAction, signal: string) => {\n if (shuttingDown) {\n return;\n }\n\n shuttingDown = true;\n const isRestart = action === 'restart';\n console.log(`[GatewayRunLoop] Received ${signal}; ${isRestart ? 'restarting' : 'shutting down'}`);\n\n cleanupSignals();\n\n const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;\n const forceExitTimer = setTimeout(() => {\n console.error('[GatewayRunLoop] Shutdown timed out; force exiting');\n exitProcess(0);\n }, forceExitMs);\n\n void (async () => {\n try {\n if (isRestart) {\n console.log('[GatewayRunLoop] Draining active tasks before restart...');\n }\n\n await server?.close?.({\n reason: isRestart ? 'gateway restarting' : 'gateway stopping',\n restartExpectedMs: isRestart ? 1500 : null,\n });\n } catch (err) {\n console.error(`[GatewayRunLoop] Shutdown error: ${String(err)}`);\n } finally {\n clearTimeout(forceExitTimer);\n server = null;\n\n if (isRestart) {\n await handleRestartAfterClose();\n } else {\n await handleStopAfterClose();\n }\n }\n })();\n };\n\n const onSigterm = () => {\n console.log('[GatewayRunLoop] SIGTERM received');\n const isRestart = consumeGatewayRestartIntentSync();\n requestShutdown(isRestart ? 'restart' : 'stop', 'SIGTERM');\n };\n\n const onSigint = () => {\n console.log('[GatewayRunLoop] SIGINT received');\n requestShutdown('stop', 'SIGINT');\n };\n\n const onSigusr1 = () => {\n console.log('[GatewayRunLoop] SIGUSR1 received');\n const authorized = consumeGatewaySigusr1RestartAuthorization();\n if (!authorized) {\n if (!isGatewaySigusr1RestartExternallyAllowed()) {\n console.warn(\n '[GatewayRunLoop] SIGUSR1 restart ignored (commands.restart=false or unauthorized).',\n );\n return;\n }\n if (shuttingDown) {\n console.log('[GatewayRunLoop] Received SIGUSR1 during shutdown; ignoring');\n return;\n }\n scheduleGatewaySigusr1Restart({\n delayMs: 0,\n reason: 'SIGUSR1',\n onRestart: () => requestShutdown('restart', 'SIGUSR1'),\n });\n return;\n }\n requestShutdown('restart', 'SIGUSR1');\n };\n\n process.on('SIGTERM', onSigterm);\n process.on('SIGINT', onSigint);\n process.on('SIGUSR1', onSigusr1);\n\n try {\n while (true) {\n console.log('[GatewayRunLoop] Starting gateway server...');\n try {\n server = await opts.start();\n } catch (err) {\n console.error('[GatewayRunLoop] Failed to start gateway server:', err);\n await releaseLock();\n exitProcess(1);\n return;\n }\n\n await new Promise<void>((resolve) => {\n restartResolver = resolve;\n });\n\n console.log('[GatewayRunLoop] Restart signal received, restarting gateway...');\n }\n } finally {\n await releaseLock();\n cleanupSignals();\n }\n}\n"],"mappings":"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"}
@@ -49,7 +49,11 @@ const ROUTE_SCOPE_REQUIREMENTS = [
49
49
  scope: WRITE_SCOPE
50
50
  },
51
51
  {
52
- prefix: "/api/cron",
52
+ prefix: "/api/automations",
53
+ scope: WRITE_SCOPE
54
+ },
55
+ {
56
+ prefix: "/api/automation-runs",
53
57
  scope: WRITE_SCOPE
54
58
  },
55
59
  {
@@ -1 +1 @@
1
- {"version":3,"file":"operator-scopes.js","names":[],"sources":["../../../../src/gateway/security/operator-scopes.ts"],"sourcesContent":["/**\n * Operator scope system for fine-grained gateway API authorization.\n *\n * Each gateway API method maps to one or more required scopes.\n * Clients declare their scopes at connection time; the gateway enforces\n * that the declared scopes cover the method being invoked.\n */\n\nexport const ADMIN_SCOPE = 'operator.admin' as const;\nexport const READ_SCOPE = 'operator.read' as const;\nexport const WRITE_SCOPE = 'operator.write' as const;\n\nexport type OperatorScope =\n | typeof ADMIN_SCOPE\n | typeof READ_SCOPE\n | typeof WRITE_SCOPE;\n\nconst KNOWN_OPERATOR_SCOPE_VALUES: readonly OperatorScope[] = [\n ADMIN_SCOPE,\n READ_SCOPE,\n WRITE_SCOPE,\n];\n\nexport const KNOWN_OPERATOR_SCOPES: ReadonlySet<OperatorScope> = new Set(\n KNOWN_OPERATOR_SCOPE_VALUES,\n);\n\nexport function isOperatorScope(value: unknown): value is OperatorScope {\n return typeof value === 'string' && KNOWN_OPERATOR_SCOPES.has(value as OperatorScope);\n}\n\n/** Default scopes granted to authenticated CLI / direct connections. */\nexport const DEFAULT_OPERATOR_SCOPES: OperatorScope[] = [\n ADMIN_SCOPE,\n READ_SCOPE,\n WRITE_SCOPE,\n];\n\n/**\n * Route-level scope requirements.\n * Maps HTTP route path prefixes to required minimum scope.\n */\nconst ROUTE_SCOPE_REQUIREMENTS: ReadonlyArray<{ prefix: string; scope: OperatorScope }> = [\n // Admin routes\n { prefix: '/api/config', scope: ADMIN_SCOPE },\n { prefix: '/api/update', scope: ADMIN_SCOPE },\n { prefix: '/api/extensions/registry', scope: ADMIN_SCOPE },\n\n // Write routes\n { prefix: '/api/agent', scope: WRITE_SCOPE },\n { prefix: '/api/sessions', scope: WRITE_SCOPE },\n { prefix: '/api/cron', scope: WRITE_SCOPE },\n { prefix: '/api/channels', scope: WRITE_SCOPE },\n { prefix: '/api/agents', scope: WRITE_SCOPE },\n { prefix: '/api/workspace', scope: WRITE_SCOPE },\n { prefix: '/api/skills', scope: WRITE_SCOPE },\n { prefix: '/api/marketplace/install', scope: ADMIN_SCOPE },\n { prefix: '/api/marketplace/uninstall', scope: ADMIN_SCOPE },\n { prefix: '/api/commands', scope: WRITE_SCOPE },\n { prefix: '/api/host-fs', scope: WRITE_SCOPE },\n\n // Read routes\n { prefix: '/api/status', scope: READ_SCOPE },\n { prefix: '/api/models', scope: READ_SCOPE },\n { prefix: '/api/logs', scope: READ_SCOPE },\n { prefix: '/api/doctor', scope: READ_SCOPE },\n { prefix: '/api/events', scope: READ_SCOPE },\n];\n\n/** Scope hierarchy: admin > write > read. */\nconst SCOPE_HIERARCHY: Record<OperatorScope, number> = {\n [ADMIN_SCOPE]: 3,\n [WRITE_SCOPE]: 2,\n [READ_SCOPE]: 1,\n};\n\nfunction scopeSatisfies(granted: OperatorScope, required: OperatorScope): boolean {\n return SCOPE_HIERARCHY[granted] >= SCOPE_HIERARCHY[required];\n}\n\n/**\n * Check whether a set of granted scopes satisfies the required scope for a route.\n */\nexport function authorizeRouteScope(\n routePath: string,\n grantedScopes: readonly OperatorScope[],\n): { allowed: true } | { allowed: false; requiredScope: OperatorScope } {\n const routeRequirement = ROUTE_SCOPE_REQUIREMENTS.find(\n (entry) => routePath.startsWith(entry.prefix),\n );\n\n if (!routeRequirement) {\n // Routes without explicit scope requirements default to read\n return authorizeScope(READ_SCOPE, grantedScopes);\n }\n\n return authorizeScope(routeRequirement.scope, grantedScopes);\n}\n\n/**\n * Check whether any of the granted scopes satisfies the required scope.\n */\nexport function authorizeScope(\n requiredScope: OperatorScope,\n grantedScopes: readonly OperatorScope[],\n): { allowed: true } | { allowed: false; requiredScope: OperatorScope } {\n const hasSufficientScope = grantedScopes.some(\n (granted) => scopeSatisfies(granted, requiredScope),\n );\n\n if (hasSufficientScope) {\n return { allowed: true };\n }\n return { allowed: false, requiredScope };\n}\n\n/**\n * Parse scopes from a comma-separated header value.\n */\nexport function parseScopesHeader(headerValue: string | undefined): OperatorScope[] {\n if (!headerValue?.trim()) {\n return [...DEFAULT_OPERATOR_SCOPES];\n }\n return headerValue\n .split(',')\n .map((scope) => scope.trim())\n .filter(isOperatorScope);\n}\n"],"mappings":";;;;;;;;AAQA,MAAa,cAAc;AAC3B,MAAa,aAAa;AAC1B,MAAa,cAAc;AAa3B,MAAa,wBAAoD,IAAI,IACnE;CANA;CACA;CACA;CAIA,CACD;AAED,SAAgB,gBAAgB,OAAwC;AACtE,QAAO,OAAO,UAAU,YAAY,sBAAsB,IAAI,MAAuB;;;AAIvF,MAAa,0BAA2C;CACtD;CACA;CACA;CACD;;;;;AAMD,MAAM,2BAAoF;CAExF;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAA4B,OAAO;EAAa;CAG1D;EAAE,QAAQ;EAAc,OAAO;EAAa;CAC5C;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAa,OAAO;EAAa;CAC3C;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAAkB,OAAO;EAAa;CAChD;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAA4B,OAAO;EAAa;CAC1D;EAAE,QAAQ;EAA8B,OAAO;EAAa;CAC5D;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAgB,OAAO;EAAa;CAG9C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAa,OAAO;EAAY;CAC1C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC7C;;AAGD,MAAM,kBAAiD;EACpD,cAAc;EACd,cAAc;EACd,aAAa;CACf;AAED,SAAS,eAAe,SAAwB,UAAkC;AAChF,QAAO,gBAAgB,YAAY,gBAAgB;;;;;AAMrD,SAAgB,oBACd,WACA,eACsE;CACtE,MAAM,mBAAmB,yBAAyB,MAC/C,UAAU,UAAU,WAAW,MAAM,OAAO,CAC9C;AAED,KAAI,CAAC,iBAEH,QAAO,eAAe,YAAY,cAAc;AAGlD,QAAO,eAAe,iBAAiB,OAAO,cAAc;;;;;AAM9D,SAAgB,eACd,eACA,eACsE;AAKtE,KAJ2B,cAAc,MACtC,YAAY,eAAe,SAAS,cAAc,CAG/B,CACpB,QAAO,EAAE,SAAS,MAAM;AAE1B,QAAO;EAAE,SAAS;EAAO;EAAe;;;;;AAM1C,SAAgB,kBAAkB,aAAkD;AAClF,KAAI,CAAC,aAAa,MAAM,CACtB,QAAO,CAAC,GAAG,wBAAwB;AAErC,QAAO,YACJ,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,OAAO,gBAAgB"}
1
+ {"version":3,"file":"operator-scopes.js","names":[],"sources":["../../../../src/gateway/security/operator-scopes.ts"],"sourcesContent":["/**\n * Operator scope system for fine-grained gateway API authorization.\n *\n * Each gateway API method maps to one or more required scopes.\n * Clients declare their scopes at connection time; the gateway enforces\n * that the declared scopes cover the method being invoked.\n */\n\nexport const ADMIN_SCOPE = 'operator.admin' as const;\nexport const READ_SCOPE = 'operator.read' as const;\nexport const WRITE_SCOPE = 'operator.write' as const;\n\nexport type OperatorScope =\n | typeof ADMIN_SCOPE\n | typeof READ_SCOPE\n | typeof WRITE_SCOPE;\n\nconst KNOWN_OPERATOR_SCOPE_VALUES: readonly OperatorScope[] = [\n ADMIN_SCOPE,\n READ_SCOPE,\n WRITE_SCOPE,\n];\n\nexport const KNOWN_OPERATOR_SCOPES: ReadonlySet<OperatorScope> = new Set(\n KNOWN_OPERATOR_SCOPE_VALUES,\n);\n\nexport function isOperatorScope(value: unknown): value is OperatorScope {\n return typeof value === 'string' && KNOWN_OPERATOR_SCOPES.has(value as OperatorScope);\n}\n\n/** Default scopes granted to authenticated CLI / direct connections. */\nexport const DEFAULT_OPERATOR_SCOPES: OperatorScope[] = [\n ADMIN_SCOPE,\n READ_SCOPE,\n WRITE_SCOPE,\n];\n\n/**\n * Route-level scope requirements.\n * Maps HTTP route path prefixes to required minimum scope.\n */\nconst ROUTE_SCOPE_REQUIREMENTS: ReadonlyArray<{ prefix: string; scope: OperatorScope }> = [\n // Admin routes\n { prefix: '/api/config', scope: ADMIN_SCOPE },\n { prefix: '/api/update', scope: ADMIN_SCOPE },\n { prefix: '/api/extensions/registry', scope: ADMIN_SCOPE },\n\n // Write routes\n { prefix: '/api/agent', scope: WRITE_SCOPE },\n { prefix: '/api/sessions', scope: WRITE_SCOPE },\n { prefix: '/api/automations', scope: WRITE_SCOPE },\n { prefix: '/api/automation-runs', scope: WRITE_SCOPE },\n { prefix: '/api/channels', scope: WRITE_SCOPE },\n { prefix: '/api/agents', scope: WRITE_SCOPE },\n { prefix: '/api/workspace', scope: WRITE_SCOPE },\n { prefix: '/api/skills', scope: WRITE_SCOPE },\n { prefix: '/api/marketplace/install', scope: ADMIN_SCOPE },\n { prefix: '/api/marketplace/uninstall', scope: ADMIN_SCOPE },\n { prefix: '/api/commands', scope: WRITE_SCOPE },\n { prefix: '/api/host-fs', scope: WRITE_SCOPE },\n\n // Read routes\n { prefix: '/api/status', scope: READ_SCOPE },\n { prefix: '/api/models', scope: READ_SCOPE },\n { prefix: '/api/logs', scope: READ_SCOPE },\n { prefix: '/api/doctor', scope: READ_SCOPE },\n { prefix: '/api/events', scope: READ_SCOPE },\n];\n\n/** Scope hierarchy: admin > write > read. */\nconst SCOPE_HIERARCHY: Record<OperatorScope, number> = {\n [ADMIN_SCOPE]: 3,\n [WRITE_SCOPE]: 2,\n [READ_SCOPE]: 1,\n};\n\nfunction scopeSatisfies(granted: OperatorScope, required: OperatorScope): boolean {\n return SCOPE_HIERARCHY[granted] >= SCOPE_HIERARCHY[required];\n}\n\n/**\n * Check whether a set of granted scopes satisfies the required scope for a route.\n */\nexport function authorizeRouteScope(\n routePath: string,\n grantedScopes: readonly OperatorScope[],\n): { allowed: true } | { allowed: false; requiredScope: OperatorScope } {\n const routeRequirement = ROUTE_SCOPE_REQUIREMENTS.find(\n (entry) => routePath.startsWith(entry.prefix),\n );\n\n if (!routeRequirement) {\n // Routes without explicit scope requirements default to read\n return authorizeScope(READ_SCOPE, grantedScopes);\n }\n\n return authorizeScope(routeRequirement.scope, grantedScopes);\n}\n\n/**\n * Check whether any of the granted scopes satisfies the required scope.\n */\nexport function authorizeScope(\n requiredScope: OperatorScope,\n grantedScopes: readonly OperatorScope[],\n): { allowed: true } | { allowed: false; requiredScope: OperatorScope } {\n const hasSufficientScope = grantedScopes.some(\n (granted) => scopeSatisfies(granted, requiredScope),\n );\n\n if (hasSufficientScope) {\n return { allowed: true };\n }\n return { allowed: false, requiredScope };\n}\n\n/**\n * Parse scopes from a comma-separated header value.\n */\nexport function parseScopesHeader(headerValue: string | undefined): OperatorScope[] {\n if (!headerValue?.trim()) {\n return [...DEFAULT_OPERATOR_SCOPES];\n }\n return headerValue\n .split(',')\n .map((scope) => scope.trim())\n .filter(isOperatorScope);\n}\n"],"mappings":";;;;;;;;AAQA,MAAa,cAAc;AAC3B,MAAa,aAAa;AAC1B,MAAa,cAAc;AAa3B,MAAa,wBAAoD,IAAI,IACnE;CANA;CACA;CACA;CAIA,CACD;AAED,SAAgB,gBAAgB,OAAwC;AACtE,QAAO,OAAO,UAAU,YAAY,sBAAsB,IAAI,MAAuB;;;AAIvF,MAAa,0BAA2C;CACtD;CACA;CACA;CACD;;;;;AAMD,MAAM,2BAAoF;CAExF;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAA4B,OAAO;EAAa;CAG1D;EAAE,QAAQ;EAAc,OAAO;EAAa;CAC5C;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAoB,OAAO;EAAa;CAClD;EAAE,QAAQ;EAAwB,OAAO;EAAa;CACtD;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAAkB,OAAO;EAAa;CAChD;EAAE,QAAQ;EAAe,OAAO;EAAa;CAC7C;EAAE,QAAQ;EAA4B,OAAO;EAAa;CAC1D;EAAE,QAAQ;EAA8B,OAAO;EAAa;CAC5D;EAAE,QAAQ;EAAiB,OAAO;EAAa;CAC/C;EAAE,QAAQ;EAAgB,OAAO;EAAa;CAG9C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAa,OAAO;EAAY;CAC1C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC5C;EAAE,QAAQ;EAAe,OAAO;EAAY;CAC7C;;AAGD,MAAM,kBAAiD;EACpD,cAAc;EACd,cAAc;EACd,aAAa;CACf;AAED,SAAS,eAAe,SAAwB,UAAkC;AAChF,QAAO,gBAAgB,YAAY,gBAAgB;;;;;AAMrD,SAAgB,oBACd,WACA,eACsE;CACtE,MAAM,mBAAmB,yBAAyB,MAC/C,UAAU,UAAU,WAAW,MAAM,OAAO,CAC9C;AAED,KAAI,CAAC,iBAEH,QAAO,eAAe,YAAY,cAAc;AAGlD,QAAO,eAAe,iBAAiB,OAAO,cAAc;;;;;AAM9D,SAAgB,eACd,eACA,eACsE;AAKtE,KAJ2B,cAAc,MACtC,YAAY,eAAe,SAAS,cAAc,CAG/B,CACpB,QAAO,EAAE,SAAS,MAAM;AAE1B,QAAO;EAAE,SAAS;EAAO;EAAe;;;;;AAM1C,SAAgB,kBAAkB,aAAkD;AAClF,KAAI,CAAC,aAAa,MAAM,CACtB,QAAO,CAAC,GAAG,wBAAwB;AAErC,QAAO,YACJ,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,OAAO,gBAAgB"}
@@ -9,7 +9,7 @@
9
9
  * - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`
10
10
  * (QR-login follow-ups that bypass the watcher)
11
11
  * - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)
12
- * - Eight section reload handlers (models / agents / channels / cron /
12
+ * - Section reload handlers (models / agents / channels /
13
13
  * heartbeat / tools / mcp / extensions)
14
14
  * - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so
15
15
  * Telegram/Weixin do not stop/start repeatedly)
@@ -26,7 +26,6 @@
26
26
  import type { Config } from '../../config/schema.js';
27
27
  import type { AgentService } from '../../agent/service.js';
28
28
  import type { ChannelManager } from '../../channels/manager.js';
29
- import type { CronService } from '../../cron/index.js';
30
29
  import type { HeartbeatService } from '../heartbeat/index.js';
31
30
  import type { ExtensionLoader } from '../../extensions/loader.js';
32
31
  import type { MessageBus } from '../../infra/bus/index.js';
@@ -40,11 +39,12 @@ export interface GatewayConfigCoordinatorOptions {
40
39
  setConfig: (next: Config) => void;
41
40
  getAgentService: () => AgentService;
42
41
  getChannelManager: () => ChannelManager;
43
- getCronService: () => CronService;
44
42
  getHeartbeatService: () => HeartbeatService | null;
45
43
  getExtensionLoader: () => ExtensionLoader | null;
46
44
  /** Re-evaluate browser-extension server attachment after agent defaults change. */
47
45
  reconcileBrowserExtensionServer: () => Promise<void>;
46
+ /** Sync built-in dreaming automations after memory.dreaming changes. */
47
+ reconcileDreamingAutomations: () => Promise<void>;
48
48
  /** Latest channel status snapshot for the `channels.status` SSE event. */
49
49
  getChannelsStatus: () => unknown;
50
50
  /** SSE emit (used for `config.reload` + `channels.status`). */
@@ -104,7 +104,7 @@ export declare class GatewayConfigCoordinator {
104
104
  * follow-up saves until the first flush settles.
105
105
  */
106
106
  private scheduleChannelPluginsAfterPersist;
107
- private handleCronReload;
107
+ private handleAutomationReload;
108
108
  private handleHeartbeatReload;
109
109
  private handleToolsReload;
110
110
  private handleMcpReload;
@@ -28,7 +28,7 @@ var GatewayConfigCoordinator = class {
28
28
  onModelsReload: (newConfig) => this.handleModelsReload(newConfig),
29
29
  onAgentDefaultsReload: (newConfig) => this.handleAgentDefaultsReload(newConfig),
30
30
  onChannelsReload: (newConfig) => this.handleChannelsReload(newConfig),
31
- onCronReload: (newConfig) => this.handleCronReload(newConfig),
31
+ onCronReload: (newConfig) => this.handleAutomationReload(newConfig),
32
32
  onHeartbeatReload: (newConfig) => this.handleHeartbeatReload(newConfig),
33
33
  onToolsReload: (newConfig) => this.handleToolsReload(newConfig),
34
34
  onMcpReload: (newConfig) => this.handleMcpReload(newConfig),
@@ -222,6 +222,13 @@ var GatewayConfigCoordinator = class {
222
222
  this.opts.setConfig(newConfig);
223
223
  this.opts.getAgentService().applyAgentDefaultsFromConfig(newConfig);
224
224
  this.opts.reconcileBrowserExtensionServer();
225
+ this.opts.reconcileDreamingAutomations().catch((err) => {
226
+ const em = err instanceof Error ? err.message : String(err);
227
+ log.warn({
228
+ err,
229
+ errorMessage: em
230
+ }, `Dreaming automation refresh failed: ${em}`);
231
+ });
225
232
  this.opts.emit("config.reload", { section: "agents" });
226
233
  log.debug("Agent defaults reloaded");
227
234
  }
@@ -251,12 +258,11 @@ var GatewayConfigCoordinator = class {
251
258
  }
252
259
  })();
253
260
  }
254
- handleCronReload(newConfig) {
255
- log.debug("Reloading cron config...");
261
+ handleAutomationReload(newConfig) {
262
+ log.debug("Reloading automation-related config...");
256
263
  this.opts.setConfig(newConfig);
257
- this.opts.getCronService().updateConfig(newConfig);
258
- this.opts.emit("config.reload", { section: "cron" });
259
- log.debug("Cron config reloaded");
264
+ this.opts.emit("config.reload", { section: "automations" });
265
+ log.debug("Automation-related config reloaded");
260
266
  }
261
267
  handleHeartbeatReload(newConfig) {
262
268
  log.debug("Reloading heartbeat config...");
@@ -343,12 +349,12 @@ var GatewayConfigCoordinator = class {
343
349
  if (sanitizeTunnelConfig(reloaded)) await saveConfig(reloaded, this.opts.configPath);
344
350
  this.opts.getAgentService().applyAgentDefaultsFromConfig(reloaded);
345
351
  await this.opts.reconcileBrowserExtensionServer();
346
- await this.opts.getAgentService().reconcileDreamingNow().catch((err) => {
352
+ await this.opts.reconcileDreamingAutomations().catch((err) => {
347
353
  const em = err instanceof Error ? err.message : String(err);
348
354
  log.warn({
349
355
  err,
350
356
  errorMessage: em
351
- }, `Dreaming cron reconcile after save failed: ${em}`);
357
+ }, `Dreaming automation refresh after save failed: ${em}`);
352
358
  });
353
359
  this.configReloader?.syncCurrentConfig(reloaded);
354
360
  }
@@ -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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"}
@@ -61,15 +61,15 @@ export declare class GatewayMarketplaceService {
61
61
  overwrite?: boolean;
62
62
  provider?: string;
63
63
  }): Promise<SkillInstallResultPayload>;
64
- getSkillsProvider(): {
64
+ getSkillsProvider(): Promise<{
65
65
  provider: string;
66
66
  displayName: string;
67
- };
67
+ }>;
68
68
  /** All registered marketplace providers (built-in + extension-contributed). */
69
- getSkillsProviders(): Array<{
69
+ getSkillsProviders(): Promise<Array<{
70
70
  id: string;
71
71
  displayName: string;
72
- }>;
72
+ }>>;
73
73
  private getDefaultAgentId;
74
74
  private getInstallAvailability;
75
75
  /** xopc-store extension package preview (type must be `extension`). */