@xopcai/xopc 0.0.196 → 0.0.199

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 (258) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-BwmdJ5pv.js → activity-store-DYVN1hRp.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B1oxPli_.js → agent-avatar-dicebear-Bt70bZjv.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-D19uNmJf.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-BM1hNzjw.js → api-B8mzbAle.js} +1 -1
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-B4x7JfL8.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-Dwdagf-Q.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-DkTiesxe.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-BdE4Mati.js → archive-plugin-Cv0VXKLm.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CTzaQcLV.js → attachment-load-CgidKrXn.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-BR6qMOVr.js +6 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-B25zTNxl.js → binary-plugins-DN3CQgIq.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-Cdrf2awF.js → block-editor-BwkSl1F_.js} +46 -46
  15. package/dist/gateway/static/root/assets/browser-settings-page-CDFQWAxI.js +8 -0
  16. package/dist/gateway/static/root/assets/browser-workflow-inputs-_ndaecsf.js +1 -0
  17. package/dist/gateway/static/root/assets/{browser-workflows-page-Wx9FrbK-.js → browser-workflows-page-C_I31wLm.js} +2 -2
  18. package/dist/gateway/static/root/assets/button-CSEbl4zT.js +1 -0
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-D41mssOq.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BoOzFotX.js → capability-presets-api-Dy1jZJKs.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BXgCyuu2.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-_8IiTxRB.js → channel-recipient-api-D-9qiuio.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-DV5BhAeu.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-B4Rbh3bM.js +1 -0
  25. package/dist/gateway/static/root/assets/connectors-api-5FEBYguL.js +1 -0
  26. package/dist/gateway/static/root/assets/connectors-page-C_qkEN0T.js +2 -0
  27. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  28. package/dist/gateway/static/root/assets/cron-expression-SEFx5rnr.js +2 -0
  29. package/dist/gateway/static/root/assets/date-picker-D4zCUQJL.js +1 -0
  30. package/dist/gateway/static/root/assets/dependency-picker-DpQAxS2k.js +1 -0
  31. package/dist/gateway/static/root/assets/{desktop-pet-BOb8sEhN.js → desktop-pet-B_5G3lQl.js} +1 -1
  32. package/dist/gateway/static/root/assets/desktop-pet-settings-ClEyoUJe.js +1 -0
  33. package/dist/gateway/static/root/assets/directory-picker-path-field-AsFWmOjG.js +1 -0
  34. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +1 -0
  35. package/dist/gateway/static/root/assets/dist-DY4Af0fY.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-p83TmZFd.js → extension-debug-page-C22Y2o5l.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DMQ3ovxA.js → extension-page-C61Ikawk.js} +1 -1
  38. package/dist/gateway/static/root/assets/extension-settings-page-WlWWcDFr.js +1 -0
  39. package/dist/gateway/static/root/assets/external-link-DjqjBmc3.js +1 -0
  40. package/dist/gateway/static/root/assets/form-field-width-DJw_jULe.js +1 -0
  41. package/dist/gateway/static/root/assets/gateway-config-api-ByIOMQdc.js +1 -0
  42. package/dist/gateway/static/root/assets/gateway-config-swr-jB0hAhWO.js +1 -0
  43. package/dist/gateway/static/root/assets/gateway-settings-CzzS9A17.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry--2njcDpC.js → gateway-startup-retry-C-fRlHCL.js} +1 -1
  45. package/dist/gateway/static/root/assets/globe-DSSGFWFn.js +1 -0
  46. package/dist/gateway/static/root/assets/heartbeat-settings-B4A_CXUL.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-FVGYYPWo.js +3 -0
  48. package/dist/gateway/static/root/assets/index-CGbKTCST.js +152 -0
  49. package/dist/gateway/static/root/assets/index-CR233S0Q.css +1 -0
  50. package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQb06_jl.js → keyboard-shortcuts-settings-BD_TFz0_.js} +1 -1
  52. package/dist/gateway/static/root/assets/loader-circle-CifKLtgG.js +1 -0
  53. package/dist/gateway/static/root/assets/local-app-workbench-page-BNpkigNb.js +2 -0
  54. package/dist/gateway/static/root/assets/local-apps-page-BwbUeLfm.js +1 -0
  55. package/dist/gateway/static/root/assets/{locale-store-Bjvw7jtg.js → locale-store-xULEcFVs.js} +1 -1
  56. package/dist/gateway/static/root/assets/logs-page-DXP9OQQt.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-CW2VpqtT.js +1 -0
  58. package/dist/gateway/static/root/assets/{markdown-split-Db-KrpOQ.js → markdown-split-B1M9KO16.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-CHN66qs0.js → media-plugins-B_QlNdqZ.js} +1 -1
  60. package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
  61. package/dist/gateway/static/root/assets/{notes-page-CJtKZM0P.js → notes-page-BTbD4GmH.js} +1 -1
  62. package/dist/gateway/static/root/assets/notes-workbench-JRiq7QDW.js +4 -0
  63. package/dist/gateway/static/root/assets/page-tabs-BaEQMYm_.js +1 -0
  64. package/dist/gateway/static/root/assets/popover-select-BzdnTy3h.js +1 -0
  65. package/dist/gateway/static/root/assets/preview-open-alternatives-CeqtArlZ.js +1 -0
  66. package/dist/gateway/static/root/assets/{product-open-page--RnCc9bb.js → product-open-page-DnalBZZs.js} +1 -1
  67. package/dist/gateway/static/root/assets/project-detail-page-CjWA13aE.js +1 -0
  68. package/dist/gateway/static/root/assets/projects-page-jsCkScbG.js +1 -0
  69. package/dist/gateway/static/root/assets/remote-access-hub-CGPJTEkM.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bg1W2__k.js → runtime-tools-settings-panel-cGkBEfg4.js} +4 -4
  71. package/dist/gateway/static/root/assets/schema-form-CmsrLlxu.js +1 -0
  72. package/dist/gateway/static/root/assets/sessions-page-BBHzziMd.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-advanced-gate-2cGg8-9h.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-form-draft-Dy10ldo8.js +1 -0
  75. package/dist/gateway/static/root/assets/settings-form-section-DUWCbaMJ.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BS36Mjzz.js → settings-loading-skeleton-Bvy5rdMY.js} +1 -1
  77. package/dist/gateway/static/root/assets/{settings-page-BDSd7F9Y.js → settings-page-cZSAwsRR.js} +1 -1
  78. package/dist/gateway/static/root/assets/settings-page-layout-BRQNel6r.js +1 -0
  79. package/dist/gateway/static/root/assets/settings-shell-dialog-layer-BU3UuiJr.js +1 -0
  80. package/dist/gateway/static/root/assets/setup-status-panel-Cf06b66-.js +1 -0
  81. package/dist/gateway/static/root/assets/share-preview-page-BzA2NCAH.js +2 -0
  82. package/dist/gateway/static/root/assets/shares-settings-xlNKydYY.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-C5Xu93c_.js +1 -0
  84. package/dist/gateway/static/root/assets/skills-page-Bvde7_i5.js +2 -0
  85. package/dist/gateway/static/root/assets/{skills-page.utils-CnbJncdL.js → skills-page.utils-vXSqHR7g.js} +1 -1
  86. package/dist/gateway/static/root/assets/system-settings-panel-9cQGOGCK.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-Bkno4tTe.js +1 -0
  88. package/dist/gateway/static/root/assets/{theme-store-DtxpMC5S.js → theme-store-CHQRiuCF.js} +1 -1
  89. package/dist/gateway/static/root/assets/tool-activity-R8V9l6nk.js +1 -0
  90. package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +1 -0
  91. package/dist/gateway/static/root/assets/use-autosave-7XfKULPI.js +1 -0
  92. package/dist/gateway/static/root/assets/user-context-page-CZ9m9aC_.js +1 -0
  93. package/dist/gateway/static/root/assets/voice-api-key-field-DXr21v-3.js +1 -0
  94. package/dist/gateway/static/root/assets/work-discovery-overlay-CeG7g_DZ.js +1 -0
  95. package/dist/gateway/static/root/assets/work-discovery-page-CQWZD03N.js +1 -0
  96. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BEmugHfL.js → workflow-run-setup-panel-DSQQZP9T.js} +2 -2
  97. package/dist/gateway/static/root/assets/workflows-page-Cs-MXFJ1.js +5 -0
  98. package/dist/gateway/static/root/assets/working-directory-picker-modal-D-IgcHPp.js +1 -0
  99. package/dist/gateway/static/root/index.html +23 -8
  100. package/dist/package.js +1 -1
  101. package/dist/packages/gateway-contract/src/tasks.js +54 -2
  102. package/dist/src/agent/agent-manager.d.ts +1 -0
  103. package/dist/src/agent/agent-manager.js +1 -0
  104. package/dist/src/agent/embedded/execution-context.d.ts +2 -0
  105. package/dist/src/agent/embedded/execution-context.js +11 -0
  106. package/dist/src/agent/embedded/index.d.ts +3 -1
  107. package/dist/src/agent/embedded/index.js +5 -3
  108. package/dist/src/agent/embedded/run-turn.js +15 -9
  109. package/dist/src/agent/embedded/session-runner.d.ts +6 -11
  110. package/dist/src/agent/embedded/session-runner.js +25 -36
  111. package/dist/src/agent/embedded/transcript-runtime.d.ts +35 -0
  112. package/dist/src/agent/embedded/transcript-runtime.js +66 -0
  113. package/dist/src/agent/embedded/types.d.ts +3 -1
  114. package/dist/src/agent/service.d.ts +15 -0
  115. package/dist/src/agent/service.js +31 -0
  116. package/dist/src/agent/service.types.d.ts +1 -0
  117. package/dist/src/agent/tools/factory.d.ts +2 -0
  118. package/dist/src/agent/tools/factory.js +2 -1
  119. package/dist/src/agent/tools/xopc-use-tool.d.ts +1 -0
  120. package/dist/src/agent/tools/xopc-use-tool.js +56 -6
  121. package/dist/src/automations/domain/validation.d.ts +40 -0
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -1
  123. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  124. package/dist/src/config/agent-profile.js +1 -1
  125. package/dist/src/config/rules.js +2 -2
  126. package/dist/src/gateway/agents-admin.js +1 -1
  127. package/dist/src/gateway/hono/app.d.ts +2 -0
  128. package/dist/src/gateway/hono/app.js +10 -3
  129. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  130. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
  131. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -1
  132. package/dist/src/gateway/hono/routes/config.js +9 -0
  133. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  134. package/dist/src/gateway/hono/routes/home.d.ts +1 -1
  135. package/dist/src/gateway/hono/routes/home.js +2 -2
  136. package/dist/src/gateway/hono/routes/index.js +2 -0
  137. package/dist/src/gateway/hono/routes/projects.js +67 -1
  138. package/dist/src/gateway/hono/routes/side-chats.d.ts +3 -0
  139. package/dist/src/gateway/hono/routes/side-chats.js +173 -0
  140. package/dist/src/gateway/hono/routes/tasks.js +112 -19
  141. package/dist/src/gateway/host.d.ts +9 -1
  142. package/dist/src/gateway/host.js +22 -5
  143. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  144. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  145. package/dist/src/gateway/runtime-config.js +6 -5
  146. package/dist/src/gateway/security/audit.js +0 -7
  147. package/dist/src/gateway/server.js +4 -1
  148. package/dist/src/gateway/service/agent-runner.d.ts +4 -0
  149. package/dist/src/gateway/service/agent-runner.js +15 -1
  150. package/dist/src/gateway/service/run-gateway-agent.js +1 -1
  151. package/dist/src/gateway/service.d.ts +5 -0
  152. package/dist/src/gateway/service.js +38 -8
  153. package/dist/src/gateway/side-chat/context-snapshot.d.ts +11 -0
  154. package/dist/src/gateway/side-chat/context-snapshot.js +108 -0
  155. package/dist/src/gateway/side-chat/index.d.ts +5 -0
  156. package/dist/src/gateway/side-chat/index.js +4 -0
  157. package/dist/src/gateway/side-chat/manager.d.ts +45 -0
  158. package/dist/src/gateway/side-chat/manager.js +198 -0
  159. package/dist/src/gateway/side-chat/run-service.d.ts +22 -0
  160. package/dist/src/gateway/side-chat/run-service.js +110 -0
  161. package/dist/src/gateway/side-chat/types.d.ts +61 -0
  162. package/dist/src/gateway/side-chat/types.js +1 -0
  163. package/dist/src/proactive/actions/service.d.ts +2 -0
  164. package/dist/src/proactive/actions/service.js +80 -0
  165. package/dist/src/proactive/execution/insight.js +20 -0
  166. package/dist/src/proactive/execution/repository.js +8 -2
  167. package/dist/src/proactive/execution/types.d.ts +14 -0
  168. package/dist/src/proactive/inbox/repository.js +59 -9
  169. package/dist/src/proactive/inbox/service.d.ts +2 -2
  170. package/dist/src/proactive/inbox/service.js +7 -2
  171. package/dist/src/proactive/inbox/types.d.ts +14 -0
  172. package/dist/src/proactive/inbox/worker.js +2 -0
  173. package/dist/src/proactive/scenarios/prompt-composer.js +2 -2
  174. package/dist/src/routing/session-key-utils.d.ts +0 -1
  175. package/dist/src/routing/session-key-utils.js +1 -6
  176. package/dist/src/routing/session-key.js +2 -2
  177. package/dist/src/storage/sqlite/migrations/118_task_board_rank.sql +6 -0
  178. package/dist/src/storage/sqlite/migrations/119_proactive_disposition.sql +13 -0
  179. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  180. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  181. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  182. package/dist/src/storage/sqlite/schema.js +1 -1
  183. package/dist/src/tasks/home-query-service.d.ts +29 -0
  184. package/dist/src/tasks/home-query-service.js +291 -7
  185. package/dist/src/tasks/index.d.ts +1 -0
  186. package/dist/src/tasks/index.js +5 -4
  187. package/dist/src/tasks/project-monitoring-service.d.ts +9 -0
  188. package/dist/src/tasks/project-monitoring-service.js +41 -3
  189. package/dist/src/tasks/project-operating-view-service.d.ts +2 -2
  190. package/dist/src/tasks/project-operating-view-service.js +47 -21
  191. package/dist/src/tasks/task-application-service.js +99 -6
  192. package/dist/src/tasks/task-change-events.d.ts +13 -0
  193. package/dist/src/tasks/task-change-events.js +29 -0
  194. package/dist/src/tasks/task-read-model-projector.js +2 -1
  195. package/dist/src/tasks/task-repository.d.ts +7 -0
  196. package/dist/src/tasks/task-repository.js +29 -6
  197. package/dist/src/tunnel/enable-lan-pairing.js +15 -26
  198. package/dist/src/tunnel/pair-context.js +1 -1
  199. package/dist/src/tunnel/pair-url.js +1 -1
  200. package/dist/src/tunnel/tunnel-qr.d.ts +0 -7
  201. package/dist/src/tunnel/tunnel-qr.js +2 -19
  202. package/package.json +4 -2
  203. package/dist/gateway/static/root/assets/agents-VoFNMGL3.js +0 -68
  204. package/dist/gateway/static/root/assets/app-management-settings-panel-vmuJ_Z6i.js +0 -1
  205. package/dist/gateway/static/root/assets/appearance-settings-BMlEoe-G.js +0 -1
  206. package/dist/gateway/static/root/assets/apps-page-CsNB6mv_.js +0 -1
  207. package/dist/gateway/static/root/assets/automations-page-CW1YWgiX.js +0 -6
  208. package/dist/gateway/static/root/assets/browser-settings-page-BMTmGMM6.js +0 -8
  209. package/dist/gateway/static/root/assets/browser-workflow-inputs-BsmHy0ks.js +0 -1
  210. package/dist/gateway/static/root/assets/capabilities-settings-panel-C5l85__e.js +0 -7
  211. package/dist/gateway/static/root/assets/capability-presets-settings-panel-9T2KXAs1.js +0 -3
  212. package/dist/gateway/static/root/assets/channels-settings-DquD4BPQ.js +0 -1
  213. package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
  214. package/dist/gateway/static/root/assets/connectors-api-BC-4ftOM.js +0 -1
  215. package/dist/gateway/static/root/assets/connectors-page-7zUxVHQg.js +0 -2
  216. package/dist/gateway/static/root/assets/cron-expression-BycQlU8Q.js +0 -2
  217. package/dist/gateway/static/root/assets/dependency-picker-BvYqHRz0.js +0 -1
  218. package/dist/gateway/static/root/assets/desktop-pet-settings-DStgPb82.js +0 -1
  219. package/dist/gateway/static/root/assets/directory-picker-path-field-DUUr9sq0.js +0 -1
  220. package/dist/gateway/static/root/assets/extension-settings-page-BcSKEU8s.js +0 -1
  221. package/dist/gateway/static/root/assets/gateway-config-api-C-MmtCc7.js +0 -1
  222. package/dist/gateway/static/root/assets/gateway-settings-CuaRDWbg.js +0 -1
  223. package/dist/gateway/static/root/assets/heartbeat-settings-Dm8TrfGa.js +0 -1
  224. package/dist/gateway/static/root/assets/home-page-BYhDbUvI.js +0 -3
  225. package/dist/gateway/static/root/assets/index-BzPwnXho.js +0 -150
  226. package/dist/gateway/static/root/assets/index-CFFYvilx.css +0 -1
  227. package/dist/gateway/static/root/assets/local-app-workbench-page-CHk4x0kR.js +0 -2
  228. package/dist/gateway/static/root/assets/local-apps-page-DQtsxjGs.js +0 -1
  229. package/dist/gateway/static/root/assets/logs-page-CDqIY72S.js +0 -2
  230. package/dist/gateway/static/root/assets/management-settings-D7itDEHl.js +0 -1
  231. package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
  232. package/dist/gateway/static/root/assets/notes-workbench-epHGeKd5.js +0 -4
  233. package/dist/gateway/static/root/assets/page-tabs-HXweXqYE.js +0 -1
  234. package/dist/gateway/static/root/assets/preview-open-alternatives-Dob6Oe2l.js +0 -1
  235. package/dist/gateway/static/root/assets/project-detail-page-BxOD5-zj.js +0 -1
  236. package/dist/gateway/static/root/assets/projects-page-D-9AhrH5.js +0 -1
  237. package/dist/gateway/static/root/assets/remote-access-hub-CSUNXLKM.js +0 -1
  238. package/dist/gateway/static/root/assets/schema-form-BI4rVt3u.js +0 -1
  239. package/dist/gateway/static/root/assets/sessions-page-BxOUBMca.js +0 -1
  240. package/dist/gateway/static/root/assets/settings-advanced-gate-DAvTIbgw.js +0 -1
  241. package/dist/gateway/static/root/assets/settings-form-section-C7rzhi7x.js +0 -1
  242. package/dist/gateway/static/root/assets/settings-page-layout-CTMmZcwj.js +0 -1
  243. package/dist/gateway/static/root/assets/setup-status-panel-D1v-2Ci-.js +0 -1
  244. package/dist/gateway/static/root/assets/share-preview-page-BeCxg6eb.js +0 -2
  245. package/dist/gateway/static/root/assets/shares-settings-CXL1EldF.js +0 -1
  246. package/dist/gateway/static/root/assets/skill-reload-api-BxwkKgVw.js +0 -1
  247. package/dist/gateway/static/root/assets/skills-page-CyfjEM4D.js +0 -2
  248. package/dist/gateway/static/root/assets/system-settings-panel-CAv0Yk0Y.js +0 -1
  249. package/dist/gateway/static/root/assets/task-detail-page-DGTVJs_N.js +0 -1
  250. package/dist/gateway/static/root/assets/typed-models-lib-DomX3Szl.js +0 -1
  251. package/dist/gateway/static/root/assets/use-autosave-BLc4gfG0.js +0 -1
  252. package/dist/gateway/static/root/assets/user-context-page-C2kQENTK.js +0 -1
  253. package/dist/gateway/static/root/assets/voice-api-key-field-BijmpPjb.js +0 -1
  254. package/dist/gateway/static/root/assets/work-discovery-overlay-D7w2JFFq.js +0 -1
  255. package/dist/gateway/static/root/assets/work-discovery-page-XtoPgPUS.js +0 -1
  256. package/dist/gateway/static/root/assets/workflows-page-D_K2xOWq.js +0 -5
  257. package/dist/src/gateway/ensure-network-cors.d.ts +0 -3
  258. package/dist/src/gateway/ensure-network-cors.js +0 -23
@@ -0,0 +1,173 @@
1
+ import { validateWebchatContent } from "../../chat-limits.js";
2
+ import { validateSideChatSelections } from "../../side-chat/context-snapshot.js";
3
+ import { SideChatError, parseThinkingLevel } from "../../side-chat/manager.js";
4
+ import "../../side-chat/index.js";
5
+ import { createGatewayRouteLogger, logRouteError } from "../lib/route-logger.js";
6
+ //#region src/gateway/hono/routes/side-chats.ts
7
+ const CLIENT_HEADER = "x-xopc-client-instance-id";
8
+ const log = createGatewayRouteLogger("SideChats");
9
+ function registerSideChatRoutes(authenticated, deps) {
10
+ const { service } = deps;
11
+ authenticated.post("/api/sessions/:parentSessionKey/side-chats", deps.chatRateLimitMiddleware, async (c) => {
12
+ try {
13
+ const body = await c.req.json().catch(() => ({}));
14
+ const clientInstanceId = readClientInstanceId(c, body.clientInstanceId);
15
+ if (body.modelRef !== void 0 && typeof body.modelRef !== "string") throw new SideChatError("modelRef must be a string", "INVALID_REQUEST");
16
+ const modelRef = typeof body.modelRef === "string" ? body.modelRef : void 0;
17
+ let selections;
18
+ try {
19
+ selections = validateSideChatSelections(body.selections);
20
+ } catch (error) {
21
+ throw new SideChatError(error instanceof Error ? error.message : "Invalid selections", "INVALID_REQUEST");
22
+ }
23
+ const sideChat = await service.sideChats.create({
24
+ parentSessionKey: c.req.param("parentSessionKey"),
25
+ clientInstanceId,
26
+ selections,
27
+ config: {
28
+ modelRef,
29
+ thinkingLevel: parseThinkingLevel(body.thinkingLevel)
30
+ }
31
+ });
32
+ return c.json({
33
+ ok: true,
34
+ sideChat
35
+ }, 201);
36
+ } catch (error) {
37
+ return respondSideChatError(c, error);
38
+ }
39
+ });
40
+ authenticated.get("/api/side-chats/:sideChatId", (c) => {
41
+ try {
42
+ const sideChat = service.sideChats.get(c.req.param("sideChatId"), readClientInstanceId(c));
43
+ return c.json({
44
+ ok: true,
45
+ sideChat
46
+ });
47
+ } catch (error) {
48
+ return respondSideChatError(c, error);
49
+ }
50
+ });
51
+ authenticated.get("/api/side-chats/:sideChatId/messages", (c) => {
52
+ try {
53
+ const messages = service.sideChats.getMessages(c.req.param("sideChatId"), readClientInstanceId(c));
54
+ return c.json({
55
+ ok: true,
56
+ messages
57
+ });
58
+ } catch (error) {
59
+ return respondSideChatError(c, error);
60
+ }
61
+ });
62
+ authenticated.patch("/api/side-chats/:sideChatId/config", async (c) => {
63
+ try {
64
+ const body = await c.req.json().catch(() => ({}));
65
+ if (body.modelRef !== void 0 && typeof body.modelRef !== "string") throw new SideChatError("modelRef must be a string", "INVALID_REQUEST");
66
+ const modelRef = typeof body.modelRef === "string" ? body.modelRef : void 0;
67
+ const sideChat = service.sideChats.updateConfig(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), {
68
+ modelRef,
69
+ thinkingLevel: parseThinkingLevel(body.thinkingLevel)
70
+ });
71
+ return c.json({
72
+ ok: true,
73
+ sideChat
74
+ });
75
+ } catch (error) {
76
+ return respondSideChatError(c, error);
77
+ }
78
+ });
79
+ authenticated.post("/api/side-chats/:sideChatId/heartbeat", (c) => {
80
+ try {
81
+ const sideChat = service.sideChats.heartbeat(c.req.param("sideChatId"), readClientInstanceId(c));
82
+ return c.json({
83
+ ok: true,
84
+ sideChat
85
+ });
86
+ } catch (error) {
87
+ return respondSideChatError(c, error);
88
+ }
89
+ });
90
+ authenticated.post("/api/side-chats/:sideChatId/inputs", deps.chatRateLimitMiddleware, async (c) => {
91
+ try {
92
+ const body = await c.req.json().catch(() => ({}));
93
+ const content = typeof body.content === "string" ? body.content : "";
94
+ const contentError = validateWebchatContent(content);
95
+ if (contentError) throw new SideChatError(contentError, "INVALID_REQUEST");
96
+ const result = service.sideChatRuns.submit(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), content);
97
+ return c.json({
98
+ ok: true,
99
+ payload: result
100
+ }, 202);
101
+ } catch (error) {
102
+ return respondSideChatError(c, error);
103
+ }
104
+ });
105
+ authenticated.post("/api/side-chats/:sideChatId/abort", deps.chatRateLimitMiddleware, async (c) => {
106
+ try {
107
+ const body = await c.req.json().catch(() => ({}));
108
+ const aborted = await service.sideChatRuns.abort(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), typeof body.runId === "string" ? body.runId : void 0);
109
+ return c.json({
110
+ ok: true,
111
+ payload: { aborted }
112
+ });
113
+ } catch (error) {
114
+ return respondSideChatError(c, error);
115
+ }
116
+ });
117
+ authenticated.post("/api/side-chats/:sideChatId/clarify/:requestId", deps.chatRateLimitMiddleware, async (c) => {
118
+ try {
119
+ const body = await c.req.json().catch(() => ({}));
120
+ const answer = body.skip === true ? "" : typeof body.answer === "string" ? body.answer.trim() : "";
121
+ if (body.skip !== true && !answer) throw new SideChatError("answer is required", "INVALID_REQUEST");
122
+ if (!service.sideChatRuns.submitClarification(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), c.req.param("requestId"), answer)) throw new SideChatError("Clarification request not found", "NOT_FOUND");
123
+ return c.json({ ok: true });
124
+ } catch (error) {
125
+ return respondSideChatError(c, error);
126
+ }
127
+ });
128
+ authenticated.delete("/api/side-chats/:sideChatId", async (c) => {
129
+ try {
130
+ return await service.sideChatRuns.dispose(c.req.param("sideChatId"), readClientInstanceId(c)) ? c.json({ ok: true }) : c.json({
131
+ ok: false,
132
+ error: "Side chat not found",
133
+ code: "NOT_FOUND"
134
+ }, 404);
135
+ } catch (error) {
136
+ return respondSideChatError(c, error);
137
+ }
138
+ });
139
+ authenticated.delete("/api/side-chats", async (c) => {
140
+ try {
141
+ const removed = await service.sideChats.disposeClient(readClientInstanceId(c, c.req.query("clientInstanceId")));
142
+ return c.json({
143
+ ok: true,
144
+ removed
145
+ });
146
+ } catch (error) {
147
+ return respondSideChatError(c, error);
148
+ }
149
+ });
150
+ }
151
+ function readClientInstanceId(c, fallback) {
152
+ const value = c.req.header(CLIENT_HEADER) || (typeof fallback === "string" ? fallback : "");
153
+ if (!value.trim()) throw new SideChatError("clientInstanceId is required", "INVALID_REQUEST");
154
+ return value.trim();
155
+ }
156
+ function respondSideChatError(c, error) {
157
+ if (!(error instanceof SideChatError)) {
158
+ logRouteError(log, c, error, "Side chat request failed");
159
+ return c.json({
160
+ ok: false,
161
+ error: "Side chat request failed",
162
+ code: "INTERNAL_ERROR"
163
+ }, 500);
164
+ }
165
+ const status = error.code === "NOT_FOUND" ? 404 : error.code === "CONFLICT" ? 409 : error.code === "LIMIT_REACHED" ? 429 : 400;
166
+ return c.json({
167
+ ok: false,
168
+ error: error.message,
169
+ code: error.code
170
+ }, status);
171
+ }
172
+ //#endregion
173
+ export { registerSideChatRoutes };
@@ -1,10 +1,12 @@
1
+ import { runSqliteWriteTransaction } from "../../../storage/sqlite/transaction.js";
1
2
  import { TaskRepository } from "../../../tasks/task-repository.js";
2
3
  import { TaskRunRepository } from "../../../tasks/task-run-repository.js";
3
4
  import { TaskReadModelProjector } from "../../../tasks/task-read-model-projector.js";
4
5
  import { TaskPhaseSchema } from "../../../../packages/gateway-contract/src/task-lifecycle.js";
5
- import { TaskCommandRequestSchema, TaskContextInputSchema, TaskCreateRequestSchema, TaskDependencyUpdateRequestSchema, TaskPatchRequestSchema } from "../../../../packages/gateway-contract/src/tasks.js";
6
+ import { TaskBoardPositionRequestSchema, TaskCommandRequestSchema, TaskContextInputSchema, TaskCreateRequestSchema, TaskDependencyUpdateRequestSchema, TaskPatchRequestSchema } from "../../../../packages/gateway-contract/src/tasks.js";
6
7
  import { ProjectMonitoringUpdateSchema } from "../../../../packages/gateway-contract/src/project-monitoring.js";
7
8
  import { TaskContextRepository } from "../../../tasks/task-context-repository.js";
9
+ import { enqueueTaskChangedEvent } from "../../../tasks/task-change-events.js";
8
10
  import { TaskDependencyError, TaskDependencyService } from "../../../tasks/task-dependency-service.js";
9
11
  import { TaskApplicationService } from "../../../tasks/task-application-service.js";
10
12
  import { ProjectMonitoringService } from "../../../tasks/project-monitoring-service.js";
@@ -13,6 +15,7 @@ import { TaskValueMetricsService } from "../../../tasks/task-value-metrics-servi
13
15
  import { TaskSignalService } from "../../../tasks/task-signal-service.js";
14
16
  //#region src/gateway/hono/routes/tasks.ts
15
17
  function registerTaskRoutes(authenticated, deps) {
18
+ const taskRateLimit = deps.taskRateLimitMiddleware ?? deps.strictRateLimitMiddleware;
16
19
  const application = new TaskApplicationService();
17
20
  const operatingViews = new ProjectOperatingViewService(deps.service.projects);
18
21
  const monitoring = new ProjectMonitoringService();
@@ -42,7 +45,7 @@ function registerTaskRoutes(authenticated, deps) {
42
45
  })
43
46
  });
44
47
  });
45
- authenticated.post("/api/tasks", deps.strictRateLimitMiddleware, async (c) => {
48
+ authenticated.post("/api/tasks", taskRateLimit, async (c) => {
46
49
  const body = await c.req.json().catch(() => ({}));
47
50
  const parsed = TaskCreateRequestSchema.safeParse(body);
48
51
  if (!parsed.success) return c.json({
@@ -57,6 +60,7 @@ function registerTaskRoutes(authenticated, deps) {
57
60
  error: created.reason
58
61
  }, 409);
59
62
  if (created.runId) deps.service.dispatchTaskRuns();
63
+ else deps.service.dispatchTaskEvents();
60
64
  return c.json({
61
65
  ok: true,
62
66
  task: created.model.task,
@@ -97,33 +101,57 @@ function registerTaskRoutes(authenticated, deps) {
97
101
  allowedCommands: model.allowedCommands
98
102
  });
99
103
  });
100
- authenticated.patch("/api/tasks/:id", deps.strictRateLimitMiddleware, async (c) => {
104
+ authenticated.patch("/api/tasks/:id", taskRateLimit, async (c) => {
101
105
  const parsed = TaskPatchRequestSchema.safeParse(await c.req.json().catch(() => ({})));
102
106
  if (!parsed.success) return c.json({
103
107
  ok: false,
104
108
  error: "Invalid task patch"
105
109
  }, 400);
106
- const updated = tasks.update(c.req.param("id"), parsed.data);
110
+ const updated = runSqliteWriteTransaction((db) => {
111
+ const task = tasks.update(c.req.param("id"), parsed.data);
112
+ if (!task) return void 0;
113
+ const changedFields = Object.keys(parsed.data).filter((field) => field !== "expectedVersion");
114
+ enqueueTaskChangedEvent(db, {
115
+ taskId: task.id,
116
+ projectId: task.projectId,
117
+ version: task.version,
118
+ changedFields,
119
+ actor: { kind: "user" }
120
+ });
121
+ return task;
122
+ });
107
123
  if (!updated) return c.json({
108
124
  ok: false,
109
125
  error: "Task changed or was not found"
110
126
  }, 409);
127
+ deps.service.dispatchTaskEvents();
111
128
  return c.json({
112
129
  ok: true,
113
130
  task: updated
114
131
  });
115
132
  });
116
- authenticated.put("/api/tasks/:id/dependencies", deps.strictRateLimitMiddleware, async (c) => {
133
+ authenticated.put("/api/tasks/:id/dependencies", taskRateLimit, async (c) => {
117
134
  const parsed = TaskDependencyUpdateRequestSchema.safeParse(await c.req.json().catch(() => ({})));
118
135
  if (!parsed.success) return c.json({
119
136
  ok: false,
120
137
  error: "Invalid task dependencies"
121
138
  }, 400);
122
139
  try {
123
- const task = dependencies.replace({
124
- taskId: c.req.param("id"),
125
- ...parsed.data
140
+ const task = runSqliteWriteTransaction((db) => {
141
+ const changed = dependencies.replace({
142
+ taskId: c.req.param("id"),
143
+ ...parsed.data
144
+ });
145
+ enqueueTaskChangedEvent(db, {
146
+ taskId: changed.id,
147
+ projectId: changed.projectId,
148
+ version: changed.version,
149
+ changedFields: ["dependencies"],
150
+ actor: { kind: "user" }
151
+ });
152
+ return changed;
126
153
  });
154
+ deps.service.dispatchTaskEvents();
127
155
  return c.json({
128
156
  ok: true,
129
157
  task,
@@ -140,7 +168,45 @@ function registerTaskRoutes(authenticated, deps) {
140
168
  }, status);
141
169
  }
142
170
  });
143
- authenticated.post("/api/tasks/:id/commands", deps.strictRateLimitMiddleware, async (c) => {
171
+ authenticated.put("/api/tasks/:id/board-position", taskRateLimit, async (c) => {
172
+ const parsed = TaskBoardPositionRequestSchema.safeParse(await c.req.json().catch(() => ({})));
173
+ if (!parsed.success) return c.json({
174
+ ok: false,
175
+ error: "Invalid task board position"
176
+ }, 400);
177
+ try {
178
+ const task = runSqliteWriteTransaction((db) => {
179
+ const reordered = tasks.reorder({
180
+ taskId: c.req.param("id"),
181
+ ...parsed.data
182
+ });
183
+ if (!reordered) return void 0;
184
+ enqueueTaskChangedEvent(db, {
185
+ taskId: reordered.id,
186
+ projectId: reordered.projectId,
187
+ version: reordered.version,
188
+ changedFields: ["boardRank"],
189
+ actor: { kind: "user" }
190
+ });
191
+ return reordered;
192
+ });
193
+ if (!task) return c.json({
194
+ ok: false,
195
+ error: "Task changed or was not found"
196
+ }, 409);
197
+ deps.service.dispatchTaskEvents();
198
+ return c.json({
199
+ ok: true,
200
+ task
201
+ });
202
+ } catch (error) {
203
+ return c.json({
204
+ ok: false,
205
+ error: error instanceof Error ? error.message : String(error)
206
+ }, 400);
207
+ }
208
+ });
209
+ authenticated.post("/api/tasks/:id/commands", taskRateLimit, async (c) => {
144
210
  const parsed = TaskCommandRequestSchema.safeParse(await c.req.json().catch(() => ({})));
145
211
  if (!parsed.success) return c.json({
146
212
  ok: false,
@@ -165,6 +231,7 @@ function registerTaskRoutes(authenticated, deps) {
165
231
  }, 409);
166
232
  }
167
233
  if (result.runId || parsed.data.command?.type === "resolve_wait") deps.service.dispatchTaskRuns();
234
+ else deps.service.dispatchTaskEvents();
168
235
  if (parsed.data.command?.type === "close" && parsed.data.command.resolution === "done") signals.dependencyClosed(c.req.param("id"));
169
236
  return c.json({
170
237
  ok: true,
@@ -172,7 +239,7 @@ function registerTaskRoutes(authenticated, deps) {
172
239
  ...result.runId ? { run: runs.get(result.runId) } : {}
173
240
  });
174
241
  });
175
- authenticated.post("/api/tasks/:id/context", deps.strictRateLimitMiddleware, async (c) => {
242
+ authenticated.post("/api/tasks/:id/context", taskRateLimit, async (c) => {
176
243
  const task = tasks.get(c.req.param("id"));
177
244
  if (!task) return c.json({
178
245
  ok: false,
@@ -183,17 +250,42 @@ function registerTaskRoutes(authenticated, deps) {
183
250
  ok: false,
184
251
  error: "Invalid task context edge"
185
252
  }, 400);
186
- return c.json({
187
- ok: true,
188
- edge: context.add({
253
+ const edge = runSqliteWriteTransaction((db) => {
254
+ const created = context.add({
189
255
  taskId: task.id,
190
256
  ...parsed.data,
191
257
  createdBy: { kind: "user" }
192
- })
258
+ });
259
+ enqueueTaskChangedEvent(db, {
260
+ taskId: task.id,
261
+ projectId: task.projectId,
262
+ version: task.version,
263
+ changedFields: ["context"],
264
+ actor: { kind: "user" }
265
+ });
266
+ return created;
267
+ });
268
+ deps.service.dispatchTaskEvents();
269
+ return c.json({
270
+ ok: true,
271
+ edge
193
272
  }, 201);
194
273
  });
195
- authenticated.delete("/api/tasks/:id/context/:edgeId", deps.strictRateLimitMiddleware, (c) => {
196
- return context.remove(c.req.param("id"), c.req.param("edgeId")) ? c.json({ ok: true }) : c.json({
274
+ authenticated.delete("/api/tasks/:id/context/:edgeId", taskRateLimit, (c) => {
275
+ const task = tasks.get(c.req.param("id"));
276
+ const removed = task ? runSqliteWriteTransaction((db) => {
277
+ const didRemove = context.remove(task.id, c.req.param("edgeId"));
278
+ if (didRemove) enqueueTaskChangedEvent(db, {
279
+ taskId: task.id,
280
+ projectId: task.projectId,
281
+ version: task.version,
282
+ changedFields: ["context"],
283
+ actor: { kind: "user" }
284
+ });
285
+ return didRemove;
286
+ }) : false;
287
+ if (removed) deps.service.dispatchTaskEvents();
288
+ return removed ? c.json({ ok: true }) : c.json({
197
289
  ok: false,
198
290
  error: "Task context edge not found"
199
291
  }, 404);
@@ -219,7 +311,7 @@ function registerTaskRoutes(authenticated, deps) {
219
311
  error: "TaskRun not found"
220
312
  }, 404);
221
313
  });
222
- authenticated.post("/api/task-runs/:runId/cancel", deps.strictRateLimitMiddleware, async (c) => {
314
+ authenticated.post("/api/task-runs/:runId/cancel", taskRateLimit, async (c) => {
223
315
  const body = await c.req.json().catch(() => ({}));
224
316
  const run = runs.get(c.req.param("runId"));
225
317
  if (!run) return c.json({
@@ -256,13 +348,14 @@ function registerTaskRoutes(authenticated, deps) {
256
348
  ok: false,
257
349
  error: result.reason
258
350
  }, 409);
351
+ deps.service.dispatchTaskEvents();
259
352
  return c.json({
260
353
  ok: true,
261
354
  run: runs.get(run.id),
262
355
  receipt: runs.getReceipt(run.id)
263
356
  });
264
357
  });
265
- authenticated.post("/api/task-runs/:runId/feedback", deps.strictRateLimitMiddleware, async (c) => {
358
+ authenticated.post("/api/task-runs/:runId/feedback", taskRateLimit, async (c) => {
266
359
  const body = await c.req.json().catch(() => ({}));
267
360
  if (body.rating !== "helpful" && body.rating !== "not_helpful") return c.json({
268
361
  ok: false,
@@ -306,7 +399,7 @@ function registerTaskRoutes(authenticated, deps) {
306
399
  policy: monitoring.get(projectId)
307
400
  });
308
401
  });
309
- authenticated.patch("/api/projects/:projectId/monitoring", deps.strictRateLimitMiddleware, async (c) => {
402
+ authenticated.patch("/api/projects/:projectId/monitoring", taskRateLimit, async (c) => {
310
403
  const projectId = c.req.param("projectId");
311
404
  if (!deps.service.projects.get(projectId)) return c.json({
312
405
  ok: false,
@@ -6,6 +6,13 @@ export declare function isAllInterfacesHost(host: string | undefined): boolean;
6
6
  export declare const GATEWAY_DEV_CONSOLE_ORIGINS: readonly ["http://localhost:3000", "http://127.0.0.1:3000"];
7
7
  /** Expo / React Native web dev server (Metro defaults to port 8081). */
8
8
  export declare const GATEWAY_EXPO_DEV_ORIGINS: readonly ["http://localhost:8081", "http://127.0.0.1:8081"];
9
+ export type LanGatewayCandidate = {
10
+ url: string;
11
+ address: string;
12
+ interfaceName: string;
13
+ };
14
+ /** Non-internal IPv4 addresses that can serve this gateway on the local network. */
15
+ export declare function enumerateLanGatewayCandidates(port: number): LanGatewayCandidate[];
9
16
  /** Effective HTTP listen port: CLI `--port` override wins over config (default 18790). */
10
17
  export declare function resolveEffectiveGatewayPort(config: {
11
18
  gateway?: {
@@ -27,7 +34,8 @@ export declare function buildDefaultCorsOrigins(params: {
27
34
  }): string[];
28
35
  /**
29
36
  * Effective browser origins for CORS and CSRF checks.
30
- * Custom `gateway.corsOrigins` (e.g. after LAN pairing) still merge loopback Vite dev origins.
37
+ * Configured origins extend the gateway's own browser origins instead of replacing them.
38
+ * This keeps the bundled console reachable while allowing explicit external frontends.
31
39
  */
32
40
  export declare function resolveGatewayCorsOrigins(params: {
33
41
  configuredOrigins?: string[];
@@ -1,4 +1,5 @@
1
1
  import "../daemon/constants.js";
2
+ import { networkInterfaces } from "node:os";
2
3
  //#region src/gateway/host.ts
3
4
  /** True when the bind address is local-only (127.x, localhost, ::1). */
4
5
  function isLoopbackHost(host) {
@@ -17,6 +18,21 @@ const GATEWAY_DEV_CONSOLE_ORIGINS = ["http://localhost:3000", "http://127.0.0.1:
17
18
  /** Expo / React Native web dev server (Metro defaults to port 8081). */
18
19
  const GATEWAY_EXPO_DEV_ORIGINS = ["http://localhost:8081", "http://127.0.0.1:8081"];
19
20
  const GATEWAY_LOOPBACK_DEV_ORIGINS = [...GATEWAY_DEV_CONSOLE_ORIGINS, ...GATEWAY_EXPO_DEV_ORIGINS];
21
+ /** Non-internal IPv4 addresses that can serve this gateway on the local network. */
22
+ function enumerateLanGatewayCandidates(port) {
23
+ const seen = /* @__PURE__ */ new Set();
24
+ const candidates = [];
25
+ for (const [interfaceName, addresses] of Object.entries(networkInterfaces())) for (const address of addresses ?? []) {
26
+ if (address.family !== "IPv4" || address.internal || seen.has(address.address)) continue;
27
+ seen.add(address.address);
28
+ candidates.push({
29
+ address: address.address,
30
+ interfaceName,
31
+ url: `http://${address.address}:${port}`
32
+ });
33
+ }
34
+ return candidates;
35
+ }
20
36
  /** Effective HTTP listen port: CLI `--port` override wins over config (default 18790). */
21
37
  function resolveEffectiveGatewayPort(config, listenPortOverride) {
22
38
  if (typeof listenPortOverride === "number" && Number.isFinite(listenPortOverride)) return listenPortOverride;
@@ -35,19 +51,20 @@ function buildDefaultCorsOrigins(params) {
35
51
  ]);
36
52
  const bindHost = params.bindHost?.trim();
37
53
  if (bindHost && !isLoopbackHost(bindHost) && !isAllInterfacesHost(bindHost)) origins.add(`http://${bindHost}:${params.port}`);
54
+ if (isAllInterfacesHost(bindHost)) for (const candidate of enumerateLanGatewayCandidates(params.port)) origins.add(candidate.url);
38
55
  return [...origins];
39
56
  }
40
57
  /**
41
58
  * Effective browser origins for CORS and CSRF checks.
42
- * Custom `gateway.corsOrigins` (e.g. after LAN pairing) still merge loopback Vite dev origins.
59
+ * Configured origins extend the gateway's own browser origins instead of replacing them.
60
+ * This keeps the bundled console reachable while allowing explicit external frontends.
43
61
  */
44
62
  function resolveGatewayCorsOrigins(params) {
45
63
  const configured = (params.configuredOrigins ?? []).map((origin) => origin.trim()).filter(Boolean);
46
- if (configured.length === 0) return buildDefaultCorsOrigins({
64
+ return [...new Set([...configured, ...buildDefaultCorsOrigins({
47
65
  port: params.port,
48
66
  bindHost: params.bindHost
49
- });
50
- return [...new Set([...configured, ...GATEWAY_LOOPBACK_DEV_ORIGINS])];
67
+ })])];
51
68
  }
52
69
  /** Browser origin (`https://host`) from a gateway public/tunnel root URL. */
53
70
  function originFromGatewayPublicUrl(publicUrl) {
@@ -73,4 +90,4 @@ function resolveAllowedBrowserOrigins(params) {
73
90
  return origins;
74
91
  }
75
92
  //#endregion
76
- export { GATEWAY_DEV_CONSOLE_ORIGINS, GATEWAY_EXPO_DEV_ORIGINS, buildDefaultCorsOrigins, isAllInterfacesHost, isLoopbackHost, originFromGatewayPublicUrl, resolveAllowedBrowserOrigins, resolveEffectiveGatewayPort, resolveGatewayCorsOrigins, resolveGatewayServiceListenPort };
93
+ export { GATEWAY_DEV_CONSOLE_ORIGINS, GATEWAY_EXPO_DEV_ORIGINS, buildDefaultCorsOrigins, enumerateLanGatewayCandidates, isAllInterfacesHost, isLoopbackHost, originFromGatewayPublicUrl, resolveAllowedBrowserOrigins, resolveEffectiveGatewayPort, resolveGatewayCorsOrigins, resolveGatewayServiceListenPort };
@@ -36,6 +36,7 @@ declare class BucketRegistry {
36
36
  private authFailureSignature?;
37
37
  private strictApiLimiter?;
38
38
  private chatApiLimiter?;
39
+ private taskApiLimiter?;
39
40
  private xopcCloudPollLimiter?;
40
41
  private channelApiLimiter?;
41
42
  private tunnelMutateLimiter?;
@@ -52,6 +53,8 @@ declare class BucketRegistry {
52
53
  strictApi(): RateLimiter;
53
54
  /** Interactive chat actions — 180 req / 60 s per client IP. */
54
55
  chatApi(): RateLimiter;
56
+ /** Interactive task and board mutations — 300 req / 60 s per client IP. */
57
+ taskApi(): RateLimiter;
55
58
  /** XOPC Cloud authorization polling — 60 req / 60 s per client IP. */
56
59
  xopcCloudPoll(): RateLimiter;
57
60
  /** Channel mutation/action endpoints — 20 req / 60 s per client IP. */
@@ -48,6 +48,7 @@ var BucketRegistry = class {
48
48
  authFailureSignature;
49
49
  strictApiLimiter;
50
50
  chatApiLimiter;
51
+ taskApiLimiter;
51
52
  xopcCloudPollLimiter;
52
53
  channelApiLimiter;
53
54
  tunnelMutateLimiter;
@@ -89,6 +90,14 @@ var BucketRegistry = class {
89
90
  });
90
91
  return this.chatApiLimiter;
91
92
  }
93
+ /** Interactive task and board mutations — 300 req / 60 s per client IP. */
94
+ taskApi() {
95
+ if (!this.taskApiLimiter) this.taskApiLimiter = new RateLimiter({
96
+ maxRequests: 300,
97
+ windowMs: 6e4
98
+ });
99
+ return this.taskApiLimiter;
100
+ }
92
101
  /** XOPC Cloud authorization polling — 60 req / 60 s per client IP. */
93
102
  xopcCloudPoll() {
94
103
  if (!this.xopcCloudPollLimiter) this.xopcCloudPollLimiter = new RateLimiter({
@@ -142,6 +151,7 @@ var BucketRegistry = class {
142
151
  this.authFailureLimiter?.destroy();
143
152
  this.strictApiLimiter?.destroy();
144
153
  this.chatApiLimiter?.destroy();
154
+ this.taskApiLimiter?.destroy();
145
155
  this.xopcCloudPollLimiter?.destroy();
146
156
  this.channelApiLimiter?.destroy();
147
157
  this.tunnelMutateLimiter?.destroy();
@@ -151,6 +161,7 @@ var BucketRegistry = class {
151
161
  this.authFailureLimiter = void 0;
152
162
  this.strictApiLimiter = void 0;
153
163
  this.chatApiLimiter = void 0;
164
+ this.taskApiLimiter = void 0;
154
165
  this.xopcCloudPollLimiter = void 0;
155
166
  this.channelApiLimiter = void 0;
156
167
  this.tunnelMutateLimiter = void 0;
@@ -164,6 +175,7 @@ var BucketRegistry = class {
164
175
  this.authFailureLimiter?.resetForTests();
165
176
  this.strictApiLimiter?.resetForTests();
166
177
  this.chatApiLimiter?.resetForTests();
178
+ this.taskApiLimiter?.resetForTests();
167
179
  this.xopcCloudPollLimiter?.resetForTests();
168
180
  this.channelApiLimiter?.resetForTests();
169
181
  this.tunnelMutateLimiter?.resetForTests();
@@ -1,12 +1,9 @@
1
- import { isAllInterfacesHost, isLoopbackHost } from "./host.js";
1
+ import { isAllInterfacesHost, isLoopbackHost, resolveGatewayCorsOrigins } from "./host.js";
2
2
  import { isAuthRateLimitGloballyDisabled, isGatewayStrictSecurityEnabled } from "./rate-limit/env-flags.js";
3
3
  import "./rate-limit/index.js";
4
4
  import { resolveGatewayListenPlan } from "./listen.js";
5
5
  import { assertTailscaleExposureCompatible } from "./tailscale-lifecycle.js";
6
6
  //#region src/gateway/runtime-config.ts
7
- function normalizeCorsOrigins(cfg) {
8
- return (cfg.gateway?.corsOrigins ?? []).map((value) => value.trim()).filter(Boolean);
9
- }
10
7
  function hasSharedSecret(auth) {
11
8
  if (auth.mode === "trusted-proxy") return true;
12
9
  if (auth.mode === "token") return typeof auth.token === "string" && auth.token.trim().length > 0;
@@ -23,7 +20,11 @@ function assertGatewayRuntimeConfig(params) {
23
20
  bindOverride: params.bindOverride
24
21
  });
25
22
  const loopback = isLoopbackHost(bindHost);
26
- const corsOrigins = normalizeCorsOrigins(params.cfg);
23
+ const corsOrigins = resolveGatewayCorsOrigins({
24
+ configuredOrigins: params.cfg.gateway?.corsOrigins,
25
+ port: params.port,
26
+ bindHost
27
+ });
27
28
  const dangerouslyAllowHostHeaderOriginFallback = params.cfg.gateway?.dangerouslyAllowHostHeaderOriginFallback === true;
28
29
  if (bindMode === "loopback" && !loopback) throw new Error(`gateway bind=loopback resolved to non-loopback host ${bindHost}; refusing fallback to a network bind`);
29
30
  if (bindMode === "custom") {
@@ -110,13 +110,6 @@ function collectGatewayConfigFindings(params) {
110
110
  title: "Large number of CORS origins configured",
111
111
  detail: `${params.corsOrigins.length} CORS origins configured. Review whether all are necessary.`
112
112
  });
113
- if (!loopback && (!params.corsOrigins || params.corsOrigins.length === 0) && params.dangerouslyAllowHostHeaderOriginFallback !== true) findings.push({
114
- checkId: "gateway.cors.no_explicit_origins",
115
- severity: "info",
116
- title: "No custom CORS origins — loopback browsers only",
117
- detail: "Gateway listens on a network address with empty gateway.corsOrigins. localhost and 127.0.0.1 on the gateway port are allowed by default; LAN or remote browser URLs must be added explicitly.",
118
- remediation: "Add gateway.corsOrigins entries (e.g. http://192.168.x.x:<port>) for non-loopback browser access, or enable gateway.dangerouslyAllowHostHeaderOriginFallback only if you understand the CSRF risk."
119
- });
120
113
  if (!loopback && params.auth.mode !== "none" && params.auth.mode !== "trusted-proxy" && params.rateLimitEnabled === false) findings.push({
121
114
  checkId: "gateway.auth.no_rate_limit",
122
115
  severity: "warn",
@@ -51,7 +51,10 @@ var GatewayServer = class {
51
51
  });
52
52
  const { configureTunnelFromGatewayConfig } = await import("../tunnel/gateway-lifecycle.js");
53
53
  await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });
54
- const app = createHonoApp({ service: this.service });
54
+ const app = createHonoApp({
55
+ service: this.service,
56
+ listenHost: bindHost
57
+ });
55
58
  const primaryHost = listenHosts[0] ?? bindHost;
56
59
  const attachUpgrade = (server) => {
57
60
  server.on("upgrade", (req, socket, head) => {
@@ -49,6 +49,7 @@ export declare class GatewayAgentRunner {
49
49
  private readonly clarifyBridge;
50
50
  /** Maps webchat session key → active `runId` for `clarify` tool routing. */
51
51
  private readonly activeWebchatRunBySession;
52
+ private readonly externalStreamBySession;
52
53
  readonly inputs: SessionInputCoordinator;
53
54
  constructor(opts: GatewayAgentRunnerOptions);
54
55
  /** True when a webchat agent run is currently in-flight for `sessionKey`. */
@@ -57,6 +58,9 @@ export declare class GatewayAgentRunner {
57
58
  getClarifyBridge(): ClarifyBridge;
58
59
  /** Called from `GatewayService.stop()` so the bridge gets cleaned up. */
59
60
  disposeClarifyBridge(): void;
61
+ registerExternalWebchatRun(sessionKey: string, runId: string, publish: (event: ClarifyStreamEvent) => void): void;
62
+ unregisterExternalWebchatRun(sessionKey: string, runId: string): void;
63
+ cancelClarificationForRun(runId: string): void;
60
64
  runAgent(message: string, channel: string, chatId: string, origin: TurnOrigin, attachments?: UserTurnAttachment[], thinking?: string, runOptions?: {
61
65
  signal?: AbortSignal;
62
66
  runId?: string;