@xopcai/xopc 0.0.113 → 0.0.114

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 (327) 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/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-Fp-p7bP1.js} +1 -1
  4. package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +6 -0
  5. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-DJWG26Si.js +71 -0
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-v24i25Oj.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-ycbdJRuZ.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CJzSADJo.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BTAB4zGS.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-DXR1-mct.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-CzQri9h2.js} +44 -44
  14. package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +1 -0
  15. package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-DRqjEvAx.js} +1 -1
  16. package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +2 -0
  17. package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-BXaZXv1o.js} +1 -1
  18. package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +3 -0
  19. package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +1 -0
  20. package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-DSkqMYo7.js} +1 -1
  21. package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-h2dGDbMN.js} +1 -1
  22. package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-hN99RhOi.js} +1 -1
  23. package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D9QqUtzZ.js} +1 -1
  24. package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-D6E687rG.js} +1 -1
  25. package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-CLt_SKTC.js} +1 -1
  26. package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-1PDi4lI0.js} +1 -1
  27. package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-N7Z_sz7p.js} +1 -1
  28. package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +1 -0
  29. package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +2 -0
  30. package/dist/gateway/static/root/assets/{goals-settings-ceEBjnfc.js → goals-settings-LFlwtIKE.js} +1 -1
  31. package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-DGPadTw-.js} +1 -1
  32. package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-BHHAs8ZX.js} +1 -1
  33. package/dist/gateway/static/root/assets/index-DefIdW9q.js +122 -0
  34. package/dist/gateway/static/root/assets/index-DzmWBkq-.css +1 -0
  35. package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-CEklPQ_r.js} +1 -1
  36. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-Ce_aQ8Iv.js} +1 -1
  37. package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +2 -0
  38. package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-BMz3xPXO.js} +1 -1
  39. package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-BalOSoz9.js} +1 -1
  40. package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +3 -0
  41. package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +2 -0
  42. package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +2 -0
  43. package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-C5D1Q5mY.js} +1 -1
  44. package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +1 -0
  45. package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CYFR5U9l.js} +1 -1
  46. package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +1 -0
  47. package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-BQ79Z5IP.js} +1 -1
  48. package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-Bgk6Emue.js} +1 -1
  49. package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DzS36TMa.js} +1 -1
  50. package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +1 -0
  51. package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +1 -0
  52. package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CdjFnSAy.js} +1 -1
  53. package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-DZLy_exu.js} +1 -1
  54. package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +1 -0
  55. package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +1 -0
  56. package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-_qRDr4g_.js} +1 -1
  57. package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +1 -0
  58. package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +1 -0
  59. package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +2 -0
  60. package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-hqaBF5aG.js} +1 -1
  61. package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-zbVIQLOA.js} +1 -1
  62. package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CbXq97rT.js} +1 -1
  63. package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-DwS3drWK.js} +1 -1
  64. package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +1 -0
  65. package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DSuOd9zy.js} +1 -1
  66. package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +1 -0
  67. package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.js +18 -0
  68. package/dist/gateway/static/root/index.html +5 -5
  69. package/dist/package.js +1 -1
  70. package/dist/src/agent/agent-manager.d.ts +8 -0
  71. package/dist/src/agent/agent-manager.js +57 -22
  72. package/dist/src/agent/agent-manager.js.map +1 -1
  73. package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
  74. package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
  75. package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
  76. package/dist/src/agent/goals/persistent-goal-service.js +2 -4
  77. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  78. package/dist/src/agent/inbound/inbound-loop.js +5 -1
  79. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  80. package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
  81. package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
  82. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  83. package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
  84. package/dist/src/agent/mcp/bundle-mcp-materialize.js +49 -1
  85. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  86. package/dist/src/agent/mcp/bundle-mcp-runtime.js +78 -3
  87. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  88. package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
  89. package/dist/src/agent/service/btw-query.js +11 -3
  90. package/dist/src/agent/service/btw-query.js.map +1 -1
  91. package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
  92. package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
  93. package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
  94. package/dist/src/agent/service/process-direct-one-shot.js +1 -1
  95. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  96. package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
  97. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  98. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  99. package/dist/src/agent/service.d.ts +1 -1
  100. package/dist/src/agent/service.js +9 -5
  101. package/dist/src/agent/service.js.map +1 -1
  102. package/dist/src/agent/service.types.d.ts +5 -0
  103. package/dist/src/agent/skills/filesystem-watcher.js +4 -3
  104. package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
  105. package/dist/src/agent/skills/index.js +2 -1
  106. package/dist/src/agent/skills/index.js.map +1 -1
  107. package/dist/src/agent/skills/skill-manage-ops.js +2 -1
  108. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  109. package/dist/src/agent/skills/types.d.ts +1 -1
  110. package/dist/src/agent/skills/watcher.js +2 -5
  111. package/dist/src/agent/skills/watcher.js.map +1 -1
  112. package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
  113. package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
  114. package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
  115. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  116. package/dist/src/agent/tool-manuals/browser.js +62 -3
  117. package/dist/src/agent/tool-manuals/browser.js.map +1 -1
  118. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
  119. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
  120. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  121. package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
  122. package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
  123. package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
  124. package/dist/src/agent/tools/factory.js +1 -10
  125. package/dist/src/agent/tools/factory.js.map +1 -1
  126. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  127. package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
  128. package/dist/src/agent/workflow/subagent-runner.js +18 -1
  129. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  130. package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
  131. package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
  132. package/dist/src/browser/actions/registry.js +383 -7
  133. package/dist/src/browser/actions/registry.js.map +1 -1
  134. package/dist/src/browser/actions/types.d.ts +11 -3
  135. package/dist/src/browser/index.js +2 -2
  136. package/dist/src/browser/pipeline/output.d.ts +18 -16
  137. package/dist/src/browser/pipeline/output.js +28 -20
  138. package/dist/src/browser/pipeline/output.js.map +1 -1
  139. package/dist/src/browser/pipeline/runner.d.ts +7 -14
  140. package/dist/src/browser/pipeline/runner.js +349 -102
  141. package/dist/src/browser/pipeline/runner.js.map +1 -1
  142. package/dist/src/browser/pipeline/schema.d.ts +1 -0
  143. package/dist/src/browser/pipeline/schema.js +35 -58
  144. package/dist/src/browser/pipeline/schema.js.map +1 -1
  145. package/dist/src/browser/pipeline/source.d.ts +2 -0
  146. package/dist/src/browser/pipeline/source.js +10 -1
  147. package/dist/src/browser/pipeline/source.js.map +1 -1
  148. package/dist/src/browser/pipeline/template.d.ts +10 -2
  149. package/dist/src/browser/pipeline/template.js +50 -8
  150. package/dist/src/browser/pipeline/template.js.map +1 -1
  151. package/dist/src/chat-commands/builtins/config.js +3 -5
  152. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  153. package/dist/src/chat-commands/context.d.ts +5 -0
  154. package/dist/src/chat-commands/context.js +18 -9
  155. package/dist/src/chat-commands/context.js.map +1 -1
  156. package/dist/src/chat-commands/index.d.ts +1 -1
  157. package/dist/src/chat-commands/index.js +2 -2
  158. package/dist/src/chat-commands/index.js.map +1 -1
  159. package/dist/src/chat-commands/processor.js +22 -21
  160. package/dist/src/chat-commands/processor.js.map +1 -1
  161. package/dist/src/chat-commands/session-key.d.ts +3 -15
  162. package/dist/src/chat-commands/session-key.js +3 -49
  163. package/dist/src/chat-commands/session-key.js.map +1 -1
  164. package/dist/src/chat-commands/types.d.ts +4 -0
  165. package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
  166. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  167. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  168. package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
  169. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  170. package/dist/src/config/rules.js +5 -0
  171. package/dist/src/config/rules.js.map +1 -1
  172. package/dist/src/connectors/builtin-catalog.js +180 -1
  173. package/dist/src/connectors/builtin-catalog.js.map +1 -1
  174. package/dist/src/connectors/health.js +18 -9
  175. package/dist/src/connectors/health.js.map +1 -1
  176. package/dist/src/connectors/types.d.ts +19 -0
  177. package/dist/src/connectors/usage.js +12 -4
  178. package/dist/src/connectors/usage.js.map +1 -1
  179. package/dist/src/extensions/types/tui.d.ts +2 -0
  180. package/dist/src/gateway/heartbeat/service.js +13 -1
  181. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  182. package/dist/src/gateway/hono/app.js +13 -4
  183. package/dist/src/gateway/hono/app.js.map +1 -1
  184. package/dist/src/gateway/hono/oauth-async.js +1 -1
  185. package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
  186. package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
  187. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
  188. package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
  189. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  190. package/dist/src/gateway/hono/routes/goals.js +16 -3
  191. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  192. package/dist/src/gateway/hono/routes/logs.js +1 -0
  193. package/dist/src/gateway/hono/routes/logs.js.map +1 -1
  194. package/dist/src/gateway/hono/routes/mcp.js +27 -8
  195. package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
  196. package/dist/src/gateway/hono/routes/notes.js +14 -2
  197. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  198. package/dist/src/gateway/hono/routes/sessions.js +62 -4
  199. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  200. package/dist/src/gateway/hono/routes/workspace.js +3 -66
  201. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  202. package/dist/src/gateway/hono/sse.d.ts +2 -2
  203. package/dist/src/gateway/hono/sse.js +7 -15
  204. package/dist/src/gateway/hono/sse.js.map +1 -1
  205. package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
  206. package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
  207. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
  208. package/dist/src/gateway/service/agent-runner.d.ts +2 -3
  209. package/dist/src/gateway/service/agent-runner.js +9 -22
  210. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  211. package/dist/src/gateway/service/run-gateway-agent.js +9 -7
  212. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  213. package/dist/src/gateway/service/sessions-api.d.ts +9 -0
  214. package/dist/src/gateway/service/sessions-api.js +11 -0
  215. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  216. package/dist/src/gateway/service.d.ts +1 -1
  217. package/dist/src/gateway/service.js +19 -5
  218. package/dist/src/gateway/service.js.map +1 -1
  219. package/dist/src/gateway/workspace-file-search.d.ts +9 -0
  220. package/dist/src/gateway/workspace-file-search.js +76 -0
  221. package/dist/src/gateway/workspace-file-search.js.map +1 -0
  222. package/dist/src/goals/goal-notifications.d.ts +2 -0
  223. package/dist/src/goals/goal-notifications.js +16 -11
  224. package/dist/src/goals/goal-notifications.js.map +1 -1
  225. package/dist/src/goals/goal-service.js +1 -6
  226. package/dist/src/goals/goal-service.js.map +1 -1
  227. package/dist/src/project-trust/trust-store.js +2 -0
  228. package/dist/src/project-trust/trust-store.js.map +1 -1
  229. package/dist/src/session/index.d.ts +1 -1
  230. package/dist/src/session/index.js +2 -2
  231. package/dist/src/session/init-session-turn.js +6 -9
  232. package/dist/src/session/init-session-turn.js.map +1 -1
  233. package/dist/src/session/manager.d.ts +5 -1
  234. package/dist/src/session/manager.js +5 -2
  235. package/dist/src/session/manager.js.map +1 -1
  236. package/dist/src/session/reset-type.d.ts +0 -2
  237. package/dist/src/session/reset-type.js +3 -9
  238. package/dist/src/session/reset-type.js.map +1 -1
  239. package/dist/src/session/resolve-session.js +9 -20
  240. package/dist/src/session/resolve-session.js.map +1 -1
  241. package/dist/src/session/store.d.ts +11 -3
  242. package/dist/src/session/store.js +29 -13
  243. package/dist/src/session/store.js.map +1 -1
  244. package/dist/src/session/types.d.ts +2 -4
  245. package/dist/src/session/types.js.map +1 -1
  246. package/dist/src/storage/sqlite/index.d.ts +2 -2
  247. package/dist/src/storage/sqlite/index.js +3 -3
  248. package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
  249. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  250. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  251. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  252. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  253. package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
  254. package/dist/src/storage/sqlite/row-mappers.js +11 -14
  255. package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
  256. package/dist/src/storage/sqlite/schema.js +3 -3
  257. package/dist/src/storage/sqlite/schema.js.map +1 -1
  258. package/dist/src/storage/sqlite/schema.sql +37 -10
  259. package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
  260. package/dist/src/storage/sqlite/session-metadata.js +18 -72
  261. package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
  262. package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
  263. package/dist/src/storage/sqlite/session-repository.js +34 -40
  264. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  265. package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
  266. package/dist/src/storage/sqlite/transcript-repository.js +52 -52
  267. package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
  268. package/dist/src/tui/backends/embedded-backend.d.ts +11 -4
  269. package/dist/src/tui/backends/embedded-backend.js +27 -1
  270. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  271. package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -1
  272. package/dist/src/tui/backends/gateway-sse-backend.js +21 -2
  273. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  274. package/dist/src/tui/extension-host/autocomplete.js +13 -10
  275. package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
  276. package/dist/src/tui/extension-host/runtime.d.ts +7 -0
  277. package/dist/src/tui/extension-host/runtime.js +6 -4
  278. package/dist/src/tui/extension-host/runtime.js.map +1 -1
  279. package/dist/src/tui/tui-backend.d.ts +9 -0
  280. package/dist/src/tui/tui-commands.js +85 -6
  281. package/dist/src/tui/tui-commands.js.map +1 -1
  282. package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
  283. package/dist/src/tui/tui-file-autocomplete.js +26 -0
  284. package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
  285. package/dist/src/tui/tui-picker-overlay.js +1 -1
  286. package/dist/src/tui/tui.js +29 -11
  287. package/dist/src/tui/tui.js.map +1 -1
  288. package/dist/src/utils/logger/context.d.ts +2 -2
  289. package/dist/src/utils/logger/context.js +2 -1
  290. package/dist/src/utils/logger/context.js.map +1 -1
  291. package/dist/src/utils/logger/log-store.js +1 -0
  292. package/dist/src/utils/logger/log-store.js.map +1 -1
  293. package/dist/src/utils/logger/pino-record.js +3 -0
  294. package/dist/src/utils/logger/pino-record.js.map +1 -1
  295. package/dist/src/utils/logger/types.d.ts +5 -0
  296. package/dist/src/utils/logger/types.js.map +1 -1
  297. package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
  298. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  299. package/package.json +1 -1
  300. package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
  301. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
  302. package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
  303. package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
  304. package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
  305. package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
  306. package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
  307. package/dist/gateway/static/root/assets/dreaming-settings-6UZE1FSK.js +0 -1
  308. package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
  309. package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
  310. package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
  311. package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
  312. package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
  313. package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
  314. package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
  315. package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
  316. package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
  317. package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
  318. package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
  319. package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
  320. package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
  321. package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
  322. package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
  323. package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
  324. package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
  325. package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
  326. package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
  327. package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
@@ -33,6 +33,7 @@ function parseBrowserPipeline(yamlSource) {
33
33
  const description = typeof doc.description === "string" ? doc.description : void 0;
34
34
  const provider = typeof doc.provider === "string" ? doc.provider : void 0;
35
35
  const include = Array.isArray(doc.include) ? doc.include.filter((x) => typeof x === "string") : void 0;
36
+ const timeoutSeconds = typeof doc.timeoutSeconds === "number" ? doc.timeoutSeconds : void 0;
36
37
  const argsRaw = doc.args && typeof doc.args === "object" && !Array.isArray(doc.args) ? doc.args : {};
37
38
  const args = {};
38
39
  for (const [k, v] of Object.entries(argsRaw)) if (v && typeof v === "object" && !Array.isArray(v)) {
@@ -48,81 +49,56 @@ function parseBrowserPipeline(yamlSource) {
48
49
  type: "string",
49
50
  default: v
50
51
  };
51
- const pipelineRaw = doc.pipeline;
52
- if (!Array.isArray(pipelineRaw)) {
53
- errors.push({
54
- path: "pipeline",
55
- message: "`pipeline` must be an array of steps."
56
- });
57
- return {
58
- ok: false,
59
- errors
60
- };
61
- }
62
- const pipeline = [];
63
- for (let i = 0; i < pipelineRaw.length; i++) {
64
- const step = pipelineRaw[i];
65
- if (!step || typeof step !== "object" || Array.isArray(step)) {
66
- errors.push({
67
- path: `pipeline[${i}]`,
68
- message: "Each step must be a YAML mapping."
52
+ function parseSteps(rawSteps, path, required) {
53
+ if (!Array.isArray(rawSteps)) {
54
+ if (required) errors.push({
55
+ path,
56
+ message: `\`${path}\` must be an array of steps.`
69
57
  });
70
- continue;
58
+ return [];
71
59
  }
72
- const stepObj = step;
73
- const actionKeys = Object.keys(stepObj);
74
- if (actionKeys.length !== 1) {
75
- errors.push({
76
- path: `pipeline[${i}]`,
77
- message: `Each step must have exactly one action key, found ${actionKeys.length}: [${actionKeys.join(", ")}].`
78
- });
79
- continue;
80
- }
81
- const action = actionKeys[0];
82
- const actionArgs = stepObj[action];
83
- if (typeof actionArgs === "string") pipeline.push({
84
- action,
85
- args: actionArgs
86
- });
87
- else if (actionArgs && typeof actionArgs === "object" && !Array.isArray(actionArgs)) pipeline.push({
88
- action,
89
- args: actionArgs
90
- });
91
- else if (actionArgs === null || actionArgs === void 0) pipeline.push({
92
- action,
93
- args: {}
94
- });
95
- else pipeline.push({
96
- action,
97
- args: { value: actionArgs }
98
- });
99
- }
100
- const onErrorRaw = doc.on_error;
101
- let onError;
102
- if (Array.isArray(onErrorRaw)) {
103
- onError = [];
104
- for (let i = 0; i < onErrorRaw.length; i++) {
105
- const step = onErrorRaw[i];
106
- if (!step || typeof step !== "object" || Array.isArray(step)) continue;
60
+ const pipeline = [];
61
+ for (let i = 0; i < rawSteps.length; i++) {
62
+ const step = rawSteps[i];
63
+ if (!step || typeof step !== "object" || Array.isArray(step)) {
64
+ errors.push({
65
+ path: `${path}[${i}]`,
66
+ message: "Each step must be a YAML mapping."
67
+ });
68
+ continue;
69
+ }
107
70
  const stepObj = step;
108
71
  const actionKeys = Object.keys(stepObj);
109
- if (actionKeys.length !== 1) continue;
72
+ if (actionKeys.length !== 1) {
73
+ errors.push({
74
+ path: `${path}[${i}]`,
75
+ message: `Each step must have exactly one action key, found ${actionKeys.length}: [${actionKeys.join(", ")}].`
76
+ });
77
+ continue;
78
+ }
110
79
  const action = actionKeys[0];
111
80
  const actionArgs = stepObj[action];
112
- if (typeof actionArgs === "string") onError.push({
81
+ if (typeof actionArgs === "string") pipeline.push({
113
82
  action,
114
83
  args: actionArgs
115
84
  });
116
- else if (actionArgs && typeof actionArgs === "object" && !Array.isArray(actionArgs)) onError.push({
85
+ else if (actionArgs && typeof actionArgs === "object" && !Array.isArray(actionArgs)) pipeline.push({
117
86
  action,
118
87
  args: actionArgs
119
88
  });
120
- else onError.push({
89
+ else if (actionArgs === null || actionArgs === void 0) pipeline.push({
121
90
  action,
122
91
  args: {}
123
92
  });
93
+ else pipeline.push({
94
+ action,
95
+ args: { value: actionArgs }
96
+ });
124
97
  }
98
+ return pipeline;
125
99
  }
100
+ const pipeline = parseSteps(doc.pipeline, "pipeline", true);
101
+ const onError = doc.on_error === void 0 ? void 0 : parseSteps(doc.on_error, "on_error", false);
126
102
  if (errors.length > 0) return {
127
103
  ok: false,
128
104
  errors
@@ -134,6 +110,7 @@ function parseBrowserPipeline(yamlSource) {
134
110
  description,
135
111
  provider,
136
112
  include,
113
+ timeoutSeconds,
137
114
  args,
138
115
  pipeline,
139
116
  onError
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../../../src/browser/pipeline/schema.ts"],"sourcesContent":["/**\n * Pipeline YAML schema — parse and validate brocli-style browser pipeline documents.\n */\n\nimport yaml from 'js-yaml';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface PipelineArgDef {\n type: string;\n required?: boolean;\n default?: unknown;\n description?: string;\n choices?: unknown[];\n}\n\nexport interface PipelineStep {\n /** The single action name (key of the step object). */\n action: string;\n /** Action arguments (value of that key), or raw string for shorthand like `evaluate: |`. */\n args: Record<string, unknown> | string;\n}\n\nexport interface PipelineDocument {\n name: string;\n description?: string;\n provider?: string;\n include?: string[];\n args: Record<string, PipelineArgDef>;\n pipeline: PipelineStep[];\n onError?: PipelineStep[];\n}\n\nexport interface PipelineValidationError {\n path: string;\n message: string;\n}\n\nexport interface PipelineParseResult {\n ok: boolean;\n document?: PipelineDocument;\n errors: PipelineValidationError[];\n}\n\n// ─── Parse ──────────────────────────────────────────────────────────────────\n\nexport function parseBrowserPipeline(yamlSource: string): PipelineParseResult {\n const errors: PipelineValidationError[] = [];\n\n let raw: unknown;\n try {\n raw = yaml.load(yamlSource);\n } catch (e) {\n return { ok: false, errors: [{ path: '', message: `YAML parse error: ${e instanceof Error ? e.message : String(e)}` }] };\n }\n\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return { ok: false, errors: [{ path: '', message: 'Pipeline must be a YAML mapping (object).' }] };\n }\n\n const doc = raw as Record<string, unknown>;\n\n // name\n const name = typeof doc.name === 'string' ? doc.name.trim() : '';\n if (!name) errors.push({ path: 'name', message: '`name` is required.' });\n\n // description\n const description = typeof doc.description === 'string' ? doc.description : undefined;\n\n // provider\n const provider = typeof doc.provider === 'string' ? doc.provider : undefined;\n\n // include\n const include = Array.isArray(doc.include)\n ? doc.include.filter((x): x is string => typeof x === 'string')\n : undefined;\n\n // args\n const argsRaw = (doc.args && typeof doc.args === 'object' && !Array.isArray(doc.args)) ? doc.args as Record<string, unknown> : {};\n const args: Record<string, PipelineArgDef> = {};\n for (const [k, v] of Object.entries(argsRaw)) {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n const def = v as Record<string, unknown>;\n args[k] = {\n type: typeof def.type === 'string' ? def.type : 'string',\n required: def.required === true,\n default: def.default,\n description: typeof def.description === 'string' ? def.description : undefined,\n choices: Array.isArray(def.choices) ? def.choices : undefined,\n };\n } else {\n args[k] = { type: 'string', default: v };\n }\n }\n\n // pipeline\n const pipelineRaw = doc.pipeline;\n if (!Array.isArray(pipelineRaw)) {\n errors.push({ path: 'pipeline', message: '`pipeline` must be an array of steps.' });\n return { ok: false, errors };\n }\n\n const pipeline: PipelineStep[] = [];\n for (let i = 0; i < pipelineRaw.length; i++) {\n const step = pipelineRaw[i];\n if (!step || typeof step !== 'object' || Array.isArray(step)) {\n errors.push({ path: `pipeline[${i}]`, message: 'Each step must be a YAML mapping.' });\n continue;\n }\n const stepObj = step as Record<string, unknown>;\n const actionKeys = Object.keys(stepObj);\n if (actionKeys.length !== 1) {\n errors.push({ path: `pipeline[${i}]`, message: `Each step must have exactly one action key, found ${actionKeys.length}: [${actionKeys.join(', ')}].` });\n continue;\n }\n const action = actionKeys[0];\n const actionArgs = stepObj[action];\n if (typeof actionArgs === 'string') {\n pipeline.push({ action, args: actionArgs });\n } else if (actionArgs && typeof actionArgs === 'object' && !Array.isArray(actionArgs)) {\n pipeline.push({ action, args: actionArgs as Record<string, unknown> });\n } else if (actionArgs === null || actionArgs === undefined) {\n pipeline.push({ action, args: {} });\n } else {\n pipeline.push({ action, args: { value: actionArgs } });\n }\n }\n\n // on_error\n const onErrorRaw = doc.on_error;\n let onError: PipelineStep[] | undefined;\n if (Array.isArray(onErrorRaw)) {\n onError = [];\n for (let i = 0; i < onErrorRaw.length; i++) {\n const step = onErrorRaw[i];\n if (!step || typeof step !== 'object' || Array.isArray(step)) continue;\n const stepObj = step as Record<string, unknown>;\n const actionKeys = Object.keys(stepObj);\n if (actionKeys.length !== 1) continue;\n const action = actionKeys[0];\n const actionArgs = stepObj[action];\n if (typeof actionArgs === 'string') {\n onError.push({ action, args: actionArgs });\n } else if (actionArgs && typeof actionArgs === 'object' && !Array.isArray(actionArgs)) {\n onError.push({ action, args: actionArgs as Record<string, unknown> });\n } else {\n onError.push({ action, args: {} });\n }\n }\n }\n\n if (errors.length > 0) {\n return { ok: false, errors };\n }\n\n return {\n ok: true,\n document: { name, description, provider, include, args, pipeline, onError },\n errors: [],\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../../src/browser/pipeline/schema.ts"],"sourcesContent":["/**\n * Pipeline YAML schema — parse and validate brocli-style browser pipeline documents.\n */\n\nimport yaml from 'js-yaml';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface PipelineArgDef {\n type: string;\n required?: boolean;\n default?: unknown;\n description?: string;\n choices?: unknown[];\n}\n\nexport interface PipelineStep {\n /** The single action name (key of the step object). */\n action: string;\n /** Action arguments (value of that key), or raw string for shorthand like `evaluate: |`. */\n args: Record<string, unknown> | string;\n}\n\nexport interface PipelineDocument {\n name: string;\n description?: string;\n provider?: string;\n include?: string[];\n timeoutSeconds?: number;\n args: Record<string, PipelineArgDef>;\n pipeline: PipelineStep[];\n onError?: PipelineStep[];\n}\n\nexport interface PipelineValidationError {\n path: string;\n message: string;\n}\n\nexport interface PipelineParseResult {\n ok: boolean;\n document?: PipelineDocument;\n errors: PipelineValidationError[];\n}\n\n// ─── Parse ──────────────────────────────────────────────────────────────────\n\nexport function parseBrowserPipeline(yamlSource: string): PipelineParseResult {\n const errors: PipelineValidationError[] = [];\n\n let raw: unknown;\n try {\n raw = yaml.load(yamlSource);\n } catch (e) {\n return { ok: false, errors: [{ path: '', message: `YAML parse error: ${e instanceof Error ? e.message : String(e)}` }] };\n }\n\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return { ok: false, errors: [{ path: '', message: 'Pipeline must be a YAML mapping (object).' }] };\n }\n\n const doc = raw as Record<string, unknown>;\n\n // name\n const name = typeof doc.name === 'string' ? doc.name.trim() : '';\n if (!name) errors.push({ path: 'name', message: '`name` is required.' });\n\n // description\n const description = typeof doc.description === 'string' ? doc.description : undefined;\n\n // provider\n const provider = typeof doc.provider === 'string' ? doc.provider : undefined;\n\n // include\n const include = Array.isArray(doc.include)\n ? doc.include.filter((x): x is string => typeof x === 'string')\n : undefined;\n\n const timeoutSeconds = typeof doc.timeoutSeconds === 'number' ? doc.timeoutSeconds : undefined;\n\n // args\n const argsRaw = (doc.args && typeof doc.args === 'object' && !Array.isArray(doc.args)) ? doc.args as Record<string, unknown> : {};\n const args: Record<string, PipelineArgDef> = {};\n for (const [k, v] of Object.entries(argsRaw)) {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n const def = v as Record<string, unknown>;\n args[k] = {\n type: typeof def.type === 'string' ? def.type : 'string',\n required: def.required === true,\n default: def.default,\n description: typeof def.description === 'string' ? def.description : undefined,\n choices: Array.isArray(def.choices) ? def.choices : undefined,\n };\n } else {\n args[k] = { type: 'string', default: v };\n }\n }\n\n function parseSteps(rawSteps: unknown, path: string, required: boolean): PipelineStep[] {\n if (!Array.isArray(rawSteps)) {\n if (required) errors.push({ path, message: `\\`${path}\\` must be an array of steps.` });\n return [];\n }\n const pipeline: PipelineStep[] = [];\n for (let i = 0; i < rawSteps.length; i++) {\n const step = rawSteps[i];\n if (!step || typeof step !== 'object' || Array.isArray(step)) {\n errors.push({ path: `${path}[${i}]`, message: 'Each step must be a YAML mapping.' });\n continue;\n }\n const stepObj = step as Record<string, unknown>;\n const actionKeys = Object.keys(stepObj);\n if (actionKeys.length !== 1) {\n errors.push({ path: `${path}[${i}]`, message: `Each step must have exactly one action key, found ${actionKeys.length}: [${actionKeys.join(', ')}].` });\n continue;\n }\n const action = actionKeys[0];\n const actionArgs = stepObj[action];\n if (typeof actionArgs === 'string') {\n pipeline.push({ action, args: actionArgs });\n } else if (actionArgs && typeof actionArgs === 'object' && !Array.isArray(actionArgs)) {\n pipeline.push({ action, args: actionArgs as Record<string, unknown> });\n } else if (actionArgs === null || actionArgs === undefined) {\n pipeline.push({ action, args: {} });\n } else {\n pipeline.push({ action, args: { value: actionArgs } });\n }\n }\n return pipeline;\n }\n\n const pipeline = parseSteps(doc.pipeline, 'pipeline', true);\n const onError = doc.on_error === undefined ? undefined : parseSteps(doc.on_error, 'on_error', false);\n\n if (errors.length > 0) {\n return { ok: false, errors };\n }\n\n return {\n ok: true,\n document: { name, description, provider, include, timeoutSeconds, args, pipeline, onError },\n errors: [],\n };\n}\n"],"mappings":"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"}
@@ -4,4 +4,6 @@ export interface BrowserPipelineSource {
4
4
  location: string;
5
5
  }
6
6
  export declare function isRemotePipelineSource(location: string): boolean;
7
+ export declare function fetchPipelineSource(url: string): Promise<string>;
7
8
  export declare function loadBrowserPipelineSource(location: string): Promise<BrowserPipelineSource>;
9
+ export declare function resolvePipelineIncludeLocation(includePath: string, parentLocation: string | undefined): string;
@@ -1,4 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
2
3
  //#region src/browser/pipeline/source.ts
3
4
  const DEFAULT_PIPELINE_SOURCE_TIMEOUT_MS = 3e4;
4
5
  const MAX_PIPELINE_SOURCE_BYTES = 1024 * 1024;
@@ -64,7 +65,15 @@ async function loadBrowserPipelineSource(location) {
64
65
  location: normalizedLocation
65
66
  };
66
67
  }
68
+ function resolvePipelineIncludeLocation(includePath, parentLocation) {
69
+ const normalized = includePath.trim();
70
+ if (!normalized) throw new Error("Pipeline include path is empty");
71
+ if (isRemotePipelineSource(normalized)) return normalized;
72
+ if (!parentLocation) return resolve(normalized);
73
+ if (isRemotePipelineSource(parentLocation)) return new URL(normalized, parentLocation).toString();
74
+ return resolve(dirname(parentLocation), normalized);
75
+ }
67
76
  //#endregion
68
- export { isRemotePipelineSource, loadBrowserPipelineSource };
77
+ export { fetchPipelineSource, isRemotePipelineSource, loadBrowserPipelineSource, resolvePipelineIncludeLocation };
69
78
 
70
79
  //# sourceMappingURL=source.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"source.js","names":[],"sources":["../../../../src/browser/pipeline/source.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\nconst DEFAULT_PIPELINE_SOURCE_TIMEOUT_MS = 30_000;\nconst MAX_PIPELINE_SOURCE_BYTES = 1024 * 1024;\n\nexport interface BrowserPipelineSource {\n source: string;\n origin: 'file' | 'url';\n location: string;\n}\n\nexport function isRemotePipelineSource(location: string): boolean {\n try {\n const url = new URL(location);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nasync function readLimitedResponseText(response: Response, url: string): Promise<string> {\n const contentLength = response.headers.get('content-length');\n if (contentLength) {\n const expectedBytes = Number.parseInt(contentLength, 10);\n if (Number.isFinite(expectedBytes) && expectedBytes > MAX_PIPELINE_SOURCE_BYTES) {\n throw new Error(`Pipeline URL is too large: ${expectedBytes} bytes`);\n }\n }\n\n if (!response.body) {\n return await response.text();\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let totalBytes = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (!value) {\n continue;\n }\n totalBytes += value.byteLength;\n if (totalBytes > MAX_PIPELINE_SOURCE_BYTES) {\n await reader.cancel().catch(() => {});\n throw new Error(`Pipeline URL is too large: ${url}`);\n }\n chunks.push(value);\n }\n\n const payload = new Uint8Array(totalBytes);\n let offset = 0;\n for (const chunk of chunks) {\n payload.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new TextDecoder().decode(payload);\n}\n\nasync function fetchPipelineSource(url: string): Promise<string> {\n const response = await fetch(url, {\n headers: {\n accept: 'application/yaml, text/yaml, text/plain, */*',\n },\n signal: AbortSignal.timeout(DEFAULT_PIPELINE_SOURCE_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : '';\n throw new Error(`Pipeline URL returned HTTP ${response.status}${statusText}`);\n }\n\n return await readLimitedResponseText(response, url);\n}\n\nexport async function loadBrowserPipelineSource(location: string): Promise<BrowserPipelineSource> {\n const normalizedLocation = location.trim();\n if (!normalizedLocation) {\n throw new Error('Pipeline path is empty');\n }\n\n if (isRemotePipelineSource(normalizedLocation)) {\n return {\n source: await fetchPipelineSource(normalizedLocation),\n origin: 'url',\n location: normalizedLocation,\n };\n }\n\n return {\n source: await readFile(normalizedLocation, 'utf-8'),\n origin: 'file',\n location: normalizedLocation,\n };\n}\n"],"mappings":";;AAEA,MAAM,qCAAqC;AAC3C,MAAM,4BAA4B,OAAO;AAQzC,SAAgB,uBAAuB,UAA2B;AAChE,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,SAAO,IAAI,aAAa,WAAW,IAAI,aAAa;SAC9C;AACN,SAAO;;;AAIX,eAAe,wBAAwB,UAAoB,KAA8B;CACvF,MAAM,gBAAgB,SAAS,QAAQ,IAAI,iBAAiB;AAC5D,KAAI,eAAe;EACjB,MAAM,gBAAgB,OAAO,SAAS,eAAe,GAAG;AACxD,MAAI,OAAO,SAAS,cAAc,IAAI,gBAAgB,0BACpD,OAAM,IAAI,MAAM,8BAA8B,cAAc,QAAQ;;AAIxE,KAAI,CAAC,SAAS,KACZ,QAAO,MAAM,SAAS,MAAM;CAG9B,MAAM,SAAS,SAAS,KAAK,WAAW;CACxC,MAAM,SAAuB,EAAE;CAC/B,IAAI,aAAa;AAEjB,QAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,KACF;AAEF,MAAI,CAAC,MACH;AAEF,gBAAc,MAAM;AACpB,MAAI,aAAa,2BAA2B;AAC1C,SAAM,OAAO,QAAQ,CAAC,YAAY,GAAG;AACrC,SAAM,IAAI,MAAM,8BAA8B,MAAM;;AAEtD,SAAO,KAAK,MAAM;;CAGpB,MAAM,UAAU,IAAI,WAAW,WAAW;CAC1C,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,UAAQ,IAAI,OAAO,OAAO;AAC1B,YAAU,MAAM;;AAGlB,QAAO,IAAI,aAAa,CAAC,OAAO,QAAQ;;AAG1C,eAAe,oBAAoB,KAA8B;CAC/D,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,SAAS,EACP,QAAQ,gDACT;EACD,QAAQ,YAAY,QAAQ,mCAAmC;EAChE,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,aAAa,SAAS,aAAa,IAAI,SAAS,eAAe;AACrE,QAAM,IAAI,MAAM,8BAA8B,SAAS,SAAS,aAAa;;AAG/E,QAAO,MAAM,wBAAwB,UAAU,IAAI;;AAGrD,eAAsB,0BAA0B,UAAkD;CAChG,MAAM,qBAAqB,SAAS,MAAM;AAC1C,KAAI,CAAC,mBACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,KAAI,uBAAuB,mBAAmB,CAC5C,QAAO;EACL,QAAQ,MAAM,oBAAoB,mBAAmB;EACrD,QAAQ;EACR,UAAU;EACX;AAGH,QAAO;EACL,QAAQ,MAAM,SAAS,oBAAoB,QAAQ;EACnD,QAAQ;EACR,UAAU;EACX"}
1
+ {"version":3,"file":"source.js","names":[],"sources":["../../../../src/browser/pipeline/source.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\n\nconst DEFAULT_PIPELINE_SOURCE_TIMEOUT_MS = 30_000;\nconst MAX_PIPELINE_SOURCE_BYTES = 1024 * 1024;\n\nexport interface BrowserPipelineSource {\n source: string;\n origin: 'file' | 'url';\n location: string;\n}\n\nexport function isRemotePipelineSource(location: string): boolean {\n try {\n const url = new URL(location);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\nasync function readLimitedResponseText(response: Response, url: string): Promise<string> {\n const contentLength = response.headers.get('content-length');\n if (contentLength) {\n const expectedBytes = Number.parseInt(contentLength, 10);\n if (Number.isFinite(expectedBytes) && expectedBytes > MAX_PIPELINE_SOURCE_BYTES) {\n throw new Error(`Pipeline URL is too large: ${expectedBytes} bytes`);\n }\n }\n\n if (!response.body) {\n return await response.text();\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let totalBytes = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (!value) {\n continue;\n }\n totalBytes += value.byteLength;\n if (totalBytes > MAX_PIPELINE_SOURCE_BYTES) {\n await reader.cancel().catch(() => {});\n throw new Error(`Pipeline URL is too large: ${url}`);\n }\n chunks.push(value);\n }\n\n const payload = new Uint8Array(totalBytes);\n let offset = 0;\n for (const chunk of chunks) {\n payload.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new TextDecoder().decode(payload);\n}\n\nexport async function fetchPipelineSource(url: string): Promise<string> {\n const response = await fetch(url, {\n headers: {\n accept: 'application/yaml, text/yaml, text/plain, */*',\n },\n signal: AbortSignal.timeout(DEFAULT_PIPELINE_SOURCE_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : '';\n throw new Error(`Pipeline URL returned HTTP ${response.status}${statusText}`);\n }\n\n return await readLimitedResponseText(response, url);\n}\n\nexport async function loadBrowserPipelineSource(location: string): Promise<BrowserPipelineSource> {\n const normalizedLocation = location.trim();\n if (!normalizedLocation) {\n throw new Error('Pipeline path is empty');\n }\n\n if (isRemotePipelineSource(normalizedLocation)) {\n return {\n source: await fetchPipelineSource(normalizedLocation),\n origin: 'url',\n location: normalizedLocation,\n };\n }\n\n return {\n source: await readFile(normalizedLocation, 'utf-8'),\n origin: 'file',\n location: normalizedLocation,\n };\n}\n\nexport function resolvePipelineIncludeLocation(includePath: string, parentLocation: string | undefined): string {\n const normalized = includePath.trim();\n if (!normalized) {\n throw new Error('Pipeline include path is empty');\n }\n if (isRemotePipelineSource(normalized)) {\n return normalized;\n }\n if (!parentLocation) {\n return resolve(normalized);\n }\n if (isRemotePipelineSource(parentLocation)) {\n return new URL(normalized, parentLocation).toString();\n }\n return resolve(dirname(parentLocation), normalized);\n}\n"],"mappings":";;;AAGA,MAAM,qCAAqC;AAC3C,MAAM,4BAA4B,OAAO;AAQzC,SAAgB,uBAAuB,UAA2B;AAChE,KAAI;EACF,MAAM,MAAM,IAAI,IAAI,SAAS;AAC7B,SAAO,IAAI,aAAa,WAAW,IAAI,aAAa;SAC9C;AACN,SAAO;;;AAIX,eAAe,wBAAwB,UAAoB,KAA8B;CACvF,MAAM,gBAAgB,SAAS,QAAQ,IAAI,iBAAiB;AAC5D,KAAI,eAAe;EACjB,MAAM,gBAAgB,OAAO,SAAS,eAAe,GAAG;AACxD,MAAI,OAAO,SAAS,cAAc,IAAI,gBAAgB,0BACpD,OAAM,IAAI,MAAM,8BAA8B,cAAc,QAAQ;;AAIxE,KAAI,CAAC,SAAS,KACZ,QAAO,MAAM,SAAS,MAAM;CAG9B,MAAM,SAAS,SAAS,KAAK,WAAW;CACxC,MAAM,SAAuB,EAAE;CAC/B,IAAI,aAAa;AAEjB,QAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,KACF;AAEF,MAAI,CAAC,MACH;AAEF,gBAAc,MAAM;AACpB,MAAI,aAAa,2BAA2B;AAC1C,SAAM,OAAO,QAAQ,CAAC,YAAY,GAAG;AACrC,SAAM,IAAI,MAAM,8BAA8B,MAAM;;AAEtD,SAAO,KAAK,MAAM;;CAGpB,MAAM,UAAU,IAAI,WAAW,WAAW;CAC1C,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,UAAQ,IAAI,OAAO,OAAO;AAC1B,YAAU,MAAM;;AAGlB,QAAO,IAAI,aAAa,CAAC,OAAO,QAAQ;;AAG1C,eAAsB,oBAAoB,KAA8B;CACtE,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,SAAS,EACP,QAAQ,gDACT;EACD,QAAQ,YAAY,QAAQ,mCAAmC;EAChE,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,aAAa,SAAS,aAAa,IAAI,SAAS,eAAe;AACrE,QAAM,IAAI,MAAM,8BAA8B,SAAS,SAAS,aAAa;;AAG/E,QAAO,MAAM,wBAAwB,UAAU,IAAI;;AAGrD,eAAsB,0BAA0B,UAAkD;CAChG,MAAM,qBAAqB,SAAS,MAAM;AAC1C,KAAI,CAAC,mBACH,OAAM,IAAI,MAAM,yBAAyB;AAG3C,KAAI,uBAAuB,mBAAmB,CAC5C,QAAO;EACL,QAAQ,MAAM,oBAAoB,mBAAmB;EACrD,QAAQ;EACR,UAAU;EACX;AAGH,QAAO;EACL,QAAQ,MAAM,SAAS,oBAAoB,QAAQ;EACnD,QAAQ;EACR,UAAU;EACX;;AAGH,SAAgB,+BAA+B,aAAqB,gBAA4C;CAC9G,MAAM,aAAa,YAAY,MAAM;AACrC,KAAI,CAAC,WACH,OAAM,IAAI,MAAM,iCAAiC;AAEnD,KAAI,uBAAuB,WAAW,CACpC,QAAO;AAET,KAAI,CAAC,eACH,QAAO,QAAQ,WAAW;AAE5B,KAAI,uBAAuB,eAAe,CACxC,QAAO,IAAI,IAAI,YAAY,eAAe,CAAC,UAAU;AAEvD,QAAO,QAAQ,QAAQ,eAAe,EAAE,WAAW"}
@@ -1,21 +1,29 @@
1
1
  /**
2
2
  * Pipeline template expression engine.
3
3
  *
4
- * Supports: ${{ args.xxx }}, ${{ data }}, ${{ data | json }}, ${{ error.message }}
4
+ * Supports: ${{ args.xxx }}, ${{ last }}, ${{ outputs.0 }}, ${{ vars.name }},
5
+ * ${{ error.message }} and simple pipe filters.
5
6
  * Does NOT execute arbitrary JavaScript — only whitelisted expressions.
6
7
  */
7
8
  export interface TemplateContext {
8
9
  args: Record<string, unknown>;
9
- data: unknown;
10
+ last: unknown;
11
+ outputs: unknown[];
12
+ vars: Record<string, unknown>;
10
13
  error?: {
11
14
  code?: string;
12
15
  message?: string;
13
16
  };
14
17
  }
18
+ export declare function resolvePath(obj: unknown, path: string): unknown;
19
+ export declare function isTruthyValue(value: unknown): boolean;
20
+ export declare function valueContains(actual: unknown, expected: unknown): boolean;
21
+ export declare function evaluateRawExpression(expr: string, ctx: TemplateContext): unknown;
15
22
  /**
16
23
  * Resolve all `${{ ... }}` expressions in a string.
17
24
  */
18
25
  export declare function resolveTemplate(template: string, ctx: TemplateContext): string;
26
+ export declare function resolveTemplateValue(value: string, ctx: TemplateContext): unknown;
19
27
  /**
20
28
  * Deep-resolve templates in an object/array/string value.
21
29
  */
@@ -2,16 +2,24 @@
2
2
  /**
3
3
  * Pipeline template expression engine.
4
4
  *
5
- * Supports: ${{ args.xxx }}, ${{ data }}, ${{ data | json }}, ${{ error.message }}
5
+ * Supports: ${{ args.xxx }}, ${{ last }}, ${{ outputs.0 }}, ${{ vars.name }},
6
+ * ${{ error.message }} and simple pipe filters.
6
7
  * Does NOT execute arbitrary JavaScript — only whitelisted expressions.
7
8
  */
8
9
  const TEMPLATE_RE = /\$\{\{\s*(.+?)\s*\}\}/g;
10
+ function parsePath(path) {
11
+ return path.replace(/\[(\d+)\]/g, ".$1").split(".").map((part) => part.trim()).filter(Boolean);
12
+ }
9
13
  function resolvePath(obj, path) {
10
- const parts = path.split(".");
14
+ const parts = parsePath(path);
11
15
  let current = obj;
12
16
  for (const part of parts) {
13
17
  if (current === null || current === void 0) return void 0;
14
- if (typeof current === "object") current = current[part];
18
+ if (Array.isArray(current)) {
19
+ const index = Number(part);
20
+ if (!Number.isInteger(index)) return void 0;
21
+ current = current[index];
22
+ } else if (typeof current === "object") current = current[part];
15
23
  else return;
16
24
  }
17
25
  return current;
@@ -22,10 +30,24 @@ function applyFilter(value, filter) {
22
30
  case "string": return String(value ?? "");
23
31
  case "number": return String(Number(value));
24
32
  case "boolean": return String(Boolean(value));
33
+ case "urlencode": return encodeURIComponent(String(value ?? ""));
25
34
  default: return String(value ?? "");
26
35
  }
27
36
  }
28
- function evaluateExpression(expr, ctx) {
37
+ function isTruthyValue(value) {
38
+ if (value === null || value === void 0 || value === false) return false;
39
+ if (typeof value === "number") return Number.isFinite(value) && value !== 0;
40
+ if (typeof value === "string") return value.length > 0 && value !== "false" && value !== "0";
41
+ if (Array.isArray(value)) return value.length > 0;
42
+ return true;
43
+ }
44
+ function valueContains(actual, expected) {
45
+ if (typeof actual === "string") return actual.includes(String(expected));
46
+ if (Array.isArray(actual)) return actual.some((item) => JSON.stringify(item) === JSON.stringify(expected));
47
+ if (actual && typeof actual === "object") return JSON.stringify(actual).includes(String(expected));
48
+ return String(actual ?? "").includes(String(expected));
49
+ }
50
+ function evaluateRawExpression(expr, ctx) {
29
51
  const pipeIdx = expr.indexOf("|");
30
52
  let path = expr;
31
53
  let filter;
@@ -34,17 +56,31 @@ function evaluateExpression(expr, ctx) {
34
56
  filter = expr.slice(pipeIdx + 1).trim();
35
57
  }
36
58
  let value;
37
- if (path === "data") value = ctx.data;
59
+ if (path === "last") value = ctx.last;
60
+ else if (path.startsWith("last.")) value = resolvePath(ctx.last, path.slice(5));
38
61
  else if (path.startsWith("args.")) value = resolvePath(ctx.args, path.slice(5));
62
+ else if (path === "outputs") value = ctx.outputs;
63
+ else if (path.startsWith("outputs.")) value = resolvePath(ctx.outputs, path.slice(8));
64
+ else if (path === "vars") value = ctx.vars;
65
+ else if (path.startsWith("vars.")) value = resolvePath(ctx.vars, path.slice(5));
39
66
  else if (path.startsWith("error.")) value = resolvePath(ctx.error, path.slice(6));
40
67
  else if (path === "error") value = ctx.error?.message ?? "";
41
- else value = resolvePath(ctx.args, path) ?? `\${{ ${expr} }}`;
68
+ else {
69
+ value = resolvePath(ctx.args, path);
70
+ if (value === void 0) return `\${{ ${expr} }}`;
71
+ }
42
72
  if (filter) return applyFilter(value, filter);
73
+ return value;
74
+ }
75
+ function stringifyTemplateValue(value) {
43
76
  if (value === void 0 || value === null) return "";
44
77
  if (typeof value === "string") return value;
45
78
  if (typeof value === "number" || typeof value === "boolean") return String(value);
46
79
  return JSON.stringify(value);
47
80
  }
81
+ function evaluateExpression(expr, ctx) {
82
+ return stringifyTemplateValue(evaluateRawExpression(expr, ctx));
83
+ }
48
84
  /**
49
85
  * Resolve all `${{ ... }}` expressions in a string.
50
86
  */
@@ -53,11 +89,17 @@ function resolveTemplate(template, ctx) {
53
89
  return evaluateExpression(expr.trim(), ctx);
54
90
  });
55
91
  }
92
+ function resolveTemplateValue(value, ctx) {
93
+ const trimmed = value.trim();
94
+ const match = /^\$\{\{\s*(.+?)\s*\}\}$/.exec(trimmed);
95
+ if (!match) return resolveTemplate(value, ctx);
96
+ return evaluateRawExpression(match[1].trim(), ctx);
97
+ }
56
98
  /**
57
99
  * Deep-resolve templates in an object/array/string value.
58
100
  */
59
101
  function resolveTemplateDeep(value, ctx) {
60
- if (typeof value === "string") return resolveTemplate(value, ctx);
102
+ if (typeof value === "string") return resolveTemplateValue(value, ctx);
61
103
  if (Array.isArray(value)) return value.map((item) => resolveTemplateDeep(item, ctx));
62
104
  if (value && typeof value === "object") {
63
105
  const result = {};
@@ -67,6 +109,6 @@ function resolveTemplateDeep(value, ctx) {
67
109
  return value;
68
110
  }
69
111
  //#endregion
70
- export { resolveTemplate, resolveTemplateDeep };
112
+ export { evaluateRawExpression, isTruthyValue, resolvePath, resolveTemplate, resolveTemplateDeep, resolveTemplateValue, valueContains };
71
113
 
72
114
  //# sourceMappingURL=template.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","names":[],"sources":["../../../../src/browser/pipeline/template.ts"],"sourcesContent":["/**\n * Pipeline template expression engine.\n *\n * Supports: ${{ args.xxx }}, ${{ data }}, ${{ data | json }}, ${{ error.message }}\n * Does NOT execute arbitrary JavaScript — only whitelisted expressions.\n */\n\nconst TEMPLATE_RE = /\\$\\{\\{\\s*(.+?)\\s*\\}\\}/g;\n\nexport interface TemplateContext {\n args: Record<string, unknown>;\n data: unknown;\n error?: { code?: string; message?: string };\n}\n\nfunction resolvePath(obj: unknown, path: string): unknown {\n const parts = path.split('.');\n let current: unknown = obj;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current === 'object') {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\nfunction applyFilter(value: unknown, filter: string): string {\n switch (filter.trim()) {\n case 'json':\n return JSON.stringify(value, null, 2) ?? 'null';\n case 'string':\n return String(value ?? '');\n case 'number':\n return String(Number(value));\n case 'boolean':\n return String(Boolean(value));\n default:\n return String(value ?? '');\n }\n}\n\nfunction evaluateExpression(expr: string, ctx: TemplateContext): string {\n // Check for pipe filter: `data | json`\n const pipeIdx = expr.indexOf('|');\n let path = expr;\n let filter: string | undefined;\n if (pipeIdx > 0) {\n path = expr.slice(0, pipeIdx).trim();\n filter = expr.slice(pipeIdx + 1).trim();\n }\n\n let value: unknown;\n\n if (path === 'data') {\n value = ctx.data;\n } else if (path.startsWith('args.')) {\n value = resolvePath(ctx.args, path.slice(5));\n } else if (path.startsWith('error.')) {\n value = resolvePath(ctx.error, path.slice(6));\n } else if (path === 'error') {\n value = ctx.error?.message ?? '';\n } else {\n // Try resolving from args as fallback\n value = resolvePath(ctx.args, path) ?? `\\${{ ${expr} }}`;\n }\n\n if (filter) {\n return applyFilter(value, filter);\n }\n\n if (value === undefined || value === null) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\n/**\n * Resolve all `${{ ... }}` expressions in a string.\n */\nexport function resolveTemplate(template: string, ctx: TemplateContext): string {\n return template.replace(TEMPLATE_RE, (_match, expr: string) => {\n return evaluateExpression(expr.trim(), ctx);\n });\n}\n\n/**\n * Deep-resolve templates in an object/array/string value.\n */\nexport function resolveTemplateDeep(value: unknown, ctx: TemplateContext): unknown {\n if (typeof value === 'string') {\n return resolveTemplate(value, ctx);\n }\n if (Array.isArray(value)) {\n return value.map((item) => resolveTemplateDeep(item, ctx));\n }\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[resolveTemplate(k, ctx)] = resolveTemplateDeep(v, ctx);\n }\n return result;\n }\n return value;\n}\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc;AAQpB,SAAS,YAAY,KAAc,MAAuB;CACxD,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,UAAmB;AACvB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,YAAY,QAAQ,YAAY,KAAA,EAAW,QAAO,KAAA;AACtD,MAAI,OAAO,YAAY,SACrB,WAAW,QAAoC;MAE/C;;AAGJ,QAAO;;AAGT,SAAS,YAAY,OAAgB,QAAwB;AAC3D,SAAQ,OAAO,MAAM,EAArB;EACE,KAAK,OACH,QAAO,KAAK,UAAU,OAAO,MAAM,EAAE,IAAI;EAC3C,KAAK,SACH,QAAO,OAAO,SAAS,GAAG;EAC5B,KAAK,SACH,QAAO,OAAO,OAAO,MAAM,CAAC;EAC9B,KAAK,UACH,QAAO,OAAO,QAAQ,MAAM,CAAC;EAC/B,QACE,QAAO,OAAO,SAAS,GAAG;;;AAIhC,SAAS,mBAAmB,MAAc,KAA8B;CAEtE,MAAM,UAAU,KAAK,QAAQ,IAAI;CACjC,IAAI,OAAO;CACX,IAAI;AACJ,KAAI,UAAU,GAAG;AACf,SAAO,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM;AACpC,WAAS,KAAK,MAAM,UAAU,EAAE,CAAC,MAAM;;CAGzC,IAAI;AAEJ,KAAI,SAAS,OACX,SAAQ,IAAI;UACH,KAAK,WAAW,QAAQ,CACjC,SAAQ,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;UACnC,KAAK,WAAW,SAAS,CAClC,SAAQ,YAAY,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;UACpC,SAAS,QAClB,SAAQ,IAAI,OAAO,WAAW;KAG9B,SAAQ,YAAY,IAAI,MAAM,KAAK,IAAI,QAAQ,KAAK;AAGtD,KAAI,OACF,QAAO,YAAY,OAAO,OAAO;AAGnC,KAAI,UAAU,KAAA,KAAa,UAAU,KAAM,QAAO;AAClD,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,MAAM;AACjF,QAAO,KAAK,UAAU,MAAM;;;;;AAM9B,SAAgB,gBAAgB,UAAkB,KAA8B;AAC9E,QAAO,SAAS,QAAQ,cAAc,QAAQ,SAAiB;AAC7D,SAAO,mBAAmB,KAAK,MAAM,EAAE,IAAI;GAC3C;;;;;AAMJ,SAAgB,oBAAoB,OAAgB,KAA+B;AACjF,KAAI,OAAO,UAAU,SACnB,QAAO,gBAAgB,OAAO,IAAI;AAEpC,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MAAM,KAAK,SAAS,oBAAoB,MAAM,IAAI,CAAC;AAE5D,KAAI,SAAS,OAAO,UAAU,UAAU;EACtC,MAAM,SAAkC,EAAE;AAC1C,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CACxC,QAAO,gBAAgB,GAAG,IAAI,IAAI,oBAAoB,GAAG,IAAI;AAE/D,SAAO;;AAET,QAAO"}
1
+ {"version":3,"file":"template.js","names":[],"sources":["../../../../src/browser/pipeline/template.ts"],"sourcesContent":["/**\n * Pipeline template expression engine.\n *\n * Supports: ${{ args.xxx }}, ${{ last }}, ${{ outputs.0 }}, ${{ vars.name }},\n * ${{ error.message }} and simple pipe filters.\n * Does NOT execute arbitrary JavaScript — only whitelisted expressions.\n */\n\nconst TEMPLATE_RE = /\\$\\{\\{\\s*(.+?)\\s*\\}\\}/g;\n\nexport interface TemplateContext {\n args: Record<string, unknown>;\n last: unknown;\n outputs: unknown[];\n vars: Record<string, unknown>;\n error?: { code?: string; message?: string };\n}\n\nfunction parsePath(path: string): string[] {\n return path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nexport function resolvePath(obj: unknown, path: string): unknown {\n const parts = parsePath(path);\n let current: unknown = obj;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (Array.isArray(current)) {\n const index = Number(part);\n if (!Number.isInteger(index)) return undefined;\n current = current[index];\n } else if (typeof current === 'object') {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\nfunction applyFilter(value: unknown, filter: string): string {\n switch (filter.trim()) {\n case 'json':\n return JSON.stringify(value, null, 2) ?? 'null';\n case 'string':\n return String(value ?? '');\n case 'number':\n return String(Number(value));\n case 'boolean':\n return String(Boolean(value));\n case 'urlencode':\n return encodeURIComponent(String(value ?? ''));\n default:\n return String(value ?? '');\n }\n}\n\nexport function isTruthyValue(value: unknown): boolean {\n if (value === null || value === undefined || value === false) return false;\n if (typeof value === 'number') return Number.isFinite(value) && value !== 0;\n if (typeof value === 'string') return value.length > 0 && value !== 'false' && value !== '0';\n if (Array.isArray(value)) return value.length > 0;\n return true;\n}\n\nexport function valueContains(actual: unknown, expected: unknown): boolean {\n if (typeof actual === 'string') return actual.includes(String(expected));\n if (Array.isArray(actual)) return actual.some((item) => JSON.stringify(item) === JSON.stringify(expected));\n if (actual && typeof actual === 'object') return JSON.stringify(actual).includes(String(expected));\n return String(actual ?? '').includes(String(expected));\n}\n\nexport function evaluateRawExpression(expr: string, ctx: TemplateContext): unknown {\n // Check for pipe filter: `last | json`\n const pipeIdx = expr.indexOf('|');\n let path = expr;\n let filter: string | undefined;\n if (pipeIdx > 0) {\n path = expr.slice(0, pipeIdx).trim();\n filter = expr.slice(pipeIdx + 1).trim();\n }\n\n let value: unknown;\n\n if (path === 'last') {\n value = ctx.last;\n } else if (path.startsWith('last.')) {\n value = resolvePath(ctx.last, path.slice(5));\n } else if (path.startsWith('args.')) {\n value = resolvePath(ctx.args, path.slice(5));\n } else if (path === 'outputs') {\n value = ctx.outputs;\n } else if (path.startsWith('outputs.')) {\n value = resolvePath(ctx.outputs, path.slice(8));\n } else if (path === 'vars') {\n value = ctx.vars;\n } else if (path.startsWith('vars.')) {\n value = resolvePath(ctx.vars, path.slice(5));\n } else if (path.startsWith('error.')) {\n value = resolvePath(ctx.error, path.slice(6));\n } else if (path === 'error') {\n value = ctx.error?.message ?? '';\n } else {\n value = resolvePath(ctx.args, path);\n if (value === undefined) return `\\${{ ${expr} }}`;\n }\n\n if (filter) {\n return applyFilter(value, filter);\n }\n\n return value;\n}\n\nfunction stringifyTemplateValue(value: unknown): string {\n if (value === undefined || value === null) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\nfunction evaluateExpression(expr: string, ctx: TemplateContext): string {\n return stringifyTemplateValue(evaluateRawExpression(expr, ctx));\n}\n\n/**\n * Resolve all `${{ ... }}` expressions in a string.\n */\nexport function resolveTemplate(template: string, ctx: TemplateContext): string {\n return template.replace(TEMPLATE_RE, (_match, expr: string) => {\n return evaluateExpression(expr.trim(), ctx);\n });\n}\n\nexport function resolveTemplateValue(value: string, ctx: TemplateContext): unknown {\n const trimmed = value.trim();\n const match = /^\\$\\{\\{\\s*(.+?)\\s*\\}\\}$/.exec(trimmed);\n if (!match) return resolveTemplate(value, ctx);\n return evaluateRawExpression(match[1].trim(), ctx);\n}\n\n/**\n * Deep-resolve templates in an object/array/string value.\n */\nexport function resolveTemplateDeep(value: unknown, ctx: TemplateContext): unknown {\n if (typeof value === 'string') {\n return resolveTemplateValue(value, ctx);\n }\n if (Array.isArray(value)) {\n return value.map((item) => resolveTemplateDeep(item, ctx));\n }\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[resolveTemplate(k, ctx)] = resolveTemplateDeep(v, ctx);\n }\n return result;\n }\n return value;\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ import { createLogger } from "../../utils/logger/index.js";
3
3
  import { init_logger } from "../../utils/logger.js";
4
4
  import { ConfigSchema, init_schema } from "../../config/schema.js";
5
5
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
6
- import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
7
6
  import { commandRegistry } from "../registry.js";
8
7
  import { parseConfigValue } from "../config-value.js";
9
8
  import { getConfigValueAtPath, parseConfigPath, setConfigValueAtPath, unsetConfigValueAtPath } from "../config-paths.js";
@@ -13,7 +12,6 @@ init_schema();
13
12
  init_loader();
14
13
  init_paths();
15
14
  init_logger();
16
- init_session_key();
17
15
  const log = createLogger("ConfigCommand");
18
16
  const BLOCKED_WRITE_PATHS = new Set(["gateway.auth.token", "providers"]);
19
17
  function isBlockedPath(path) {
@@ -29,13 +27,13 @@ function redactConfigForDisplay(plain) {
29
27
  if (plain.providers !== void 0) plain.providers = "[redacted]";
30
28
  }
31
29
  function senderMayWritePersistentConfig(ctx) {
32
- const { source, senderId, isGroup, sessionKey } = ctx;
30
+ const { source, senderId, isGroup } = ctx;
33
31
  if (source !== "telegram" && source !== "weixin") return true;
34
32
  const cfg = ctx.getConfig?.() ?? ctx.config;
35
33
  if (source === "weixin") {
36
34
  const wx = cfg.channels?.weixin;
37
35
  if (!wx?.enabled) return false;
38
- const accountId = parseSessionKey(sessionKey)?.accountId ?? "default";
36
+ const accountId = ctx.accountId ?? "default";
39
37
  let allowFrom = [];
40
38
  if (wx.accounts && Object.keys(wx.accounts).length > 0) {
41
39
  const acc = wx.accounts[accountId] ?? wx.accounts["default"];
@@ -50,7 +48,7 @@ function senderMayWritePersistentConfig(ctx) {
50
48
  }
51
49
  const tg = cfg.channels?.telegram;
52
50
  if (!tg?.enabled) return false;
53
- const accountId = parseSessionKey(sessionKey)?.accountId ?? "default";
51
+ const accountId = ctx.accountId ?? "default";
54
52
  const acc = tg.accounts?.[accountId] ?? tg.accounts?.["default"];
55
53
  if (!acc || acc.enabled === false) return false;
56
54
  const allowFrom = [...acc.allowFrom ?? []];
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../../../../src/chat-commands/builtins/config.ts"],"sourcesContent":["/**\n * /config — read and write persistent config (~/.xopc/xopc.json) from chat.\n */\n\nimport type { CommandDefinition, CommandContext } from '../types.js';\nimport { commandRegistry } from '../registry.js';\nimport { parseConfigValue } from '../config-value.js';\nimport {\n parseConfigPath,\n getConfigValueAtPath,\n setConfigValueAtPath,\n unsetConfigValueAtPath,\n} from '../config-paths.js';\nimport { ConfigSchema, type TelegramConfig, type WeixinConfig } from '../../config/schema.js';\nimport { loadConfig, saveConfig } from '../../config/loader.js';\nimport { resolveConfigPath } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { parseSessionKey } from '../../routing/session-key.js';\nimport { resolveAllowlistMatchSimple } from '../../channels/security.js';\n\nconst log = createLogger('ConfigCommand');\n\nconst BLOCKED_WRITE_PATHS = new Set(['gateway.auth.token', 'providers']);\n\nfunction isBlockedPath(path: string[]): boolean {\n const joined = path.join('.');\n for (const blocked of BLOCKED_WRITE_PATHS) {\n if (joined === blocked || joined.startsWith(`${blocked}.`)) return true;\n }\n return false;\n}\n\nfunction redactConfigForDisplay(plain: Record<string, unknown>): void {\n if (plain.gateway && typeof plain.gateway === 'object') {\n const gw = plain.gateway as Record<string, unknown>;\n if (gw.auth && typeof gw.auth === 'object') {\n (gw.auth as Record<string, unknown>).token = '[redacted]';\n }\n }\n if (plain.providers !== undefined) plain.providers = '[redacted]';\n}\n\nfunction senderMayWritePersistentConfig(ctx: CommandContext): boolean {\n const { source, senderId, isGroup, sessionKey } = ctx;\n if (source !== 'telegram' && source !== 'weixin') {\n return true;\n }\n\n const cfg = ctx.getConfig?.() ?? ctx.config;\n\n if (source === 'weixin') {\n const wx = cfg.channels?.weixin as WeixinConfig | undefined;\n if (!wx?.enabled) return false;\n const parsed = parseSessionKey(sessionKey);\n const accountId = parsed?.accountId ?? 'default';\n let allowFrom: Array<string | number> = [];\n if (wx.accounts && Object.keys(wx.accounts).length > 0) {\n const acc = wx.accounts[accountId] ?? wx.accounts['default'];\n if (!acc || acc.enabled === false) return false;\n allowFrom = [...(acc.allowFrom ?? [])];\n } else {\n allowFrom = [...(wx.allowFrom ?? [])];\n }\n if (allowFrom.length === 0) return false;\n return resolveAllowlistMatchSimple({ allowFrom, senderId }).allowed;\n }\n\n const tg = cfg.channels?.telegram as TelegramConfig | undefined;\n if (!tg?.enabled) return false;\n const parsed = parseSessionKey(sessionKey);\n const accountId = parsed?.accountId ?? 'default';\n const acc = tg.accounts?.[accountId] ?? tg.accounts?.['default'];\n if (!acc || acc.enabled === false) return false;\n const allowFrom = [...(acc.allowFrom ?? [])];\n const groupAllowFrom = [...(acc.groupAllowFrom ?? [])];\n const list = isGroup && groupAllowFrom.length > 0 ? groupAllowFrom : allowFrom;\n if (list.length === 0) return false;\n return resolveAllowlistMatchSimple({ allowFrom: list, senderId }).allowed;\n}\n\nconst configCommand: CommandDefinition = {\n id: 'system.config',\n name: 'config',\n aliases: ['cfg'],\n description:\n 'Show or update configuration. Usage: /config show [path] | /config set path=value | /config unset path',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: [\n '/config show',\n '/config show agents.defaults.models.chat',\n '/config set agents.defaults.models.chat.primary=anthropic/claude-opus-4-5',\n '/config set agents.defaults.temperature=0.5',\n '/config unset tts',\n ],\n handler: async (ctx: CommandContext, args: string) => {\n const parts = args.trim().split(/\\s+/);\n const action = parts[0]?.toLowerCase();\n const rest = parts.slice(1).join(' ').trim();\n\n if (!action || action === 'show' || action === 'get') {\n const config = ctx.getConfig?.() ?? loadConfig(resolveConfigPath());\n const plain = JSON.parse(JSON.stringify(config)) as Record<string, unknown>;\n redactConfigForDisplay(plain);\n\n if (rest) {\n const parsed = parseConfigPath(rest);\n if (!parsed.ok || !parsed.path) {\n return { content: `⚠️ ${parsed.error ?? 'Invalid path.'}`, success: false };\n }\n const value = getConfigValueAtPath(plain, parsed.path);\n const rendered = JSON.stringify(value ?? null, null, 2);\n return { content: `⚙️ \\`${rest}\\`:\\n\\`\\`\\`json\\n${rendered}\\n\\`\\`\\`` };\n }\n\n const json = JSON.stringify(plain, null, 2);\n return { content: `⚙️ Current config:\\n\\`\\`\\`json\\n${json}\\n\\`\\`\\`` };\n }\n\n if (action === 'set') {\n if (!senderMayWritePersistentConfig(ctx)) {\n return {\n content: '⚠️ You are not allowed to change config from this chat surface.',\n success: false,\n };\n }\n const eqIndex = rest.indexOf('=');\n if (eqIndex <= 0) {\n return { content: '⚠️ Usage: /config set path=value', success: false };\n }\n const pathRaw = rest.slice(0, eqIndex).trim();\n const valueRaw = rest.slice(eqIndex + 1);\n\n const parsedPath = parseConfigPath(pathRaw);\n if (!parsedPath.ok || !parsedPath.path) {\n return { content: `⚠️ ${parsedPath.error}`, success: false };\n }\n if (isBlockedPath(parsedPath.path)) {\n return {\n content: `⚠️ Path \\`${pathRaw}\\` cannot be modified via chat for security reasons.`,\n success: false,\n };\n }\n\n const parsedValue = parseConfigValue(valueRaw);\n if (parsedValue.ok === false) {\n return { content: `⚠️ ${parsedValue.error}`, success: false };\n }\n\n const configPath = resolveConfigPath();\n const currentConfig = loadConfig(configPath) as Record<string, unknown>;\n setConfigValueAtPath(currentConfig, parsedPath.path, parsedValue.value);\n\n const validated = ConfigSchema.safeParse(currentConfig);\n if (!validated.success) {\n const firstIssue = validated.error.issues[0];\n const fieldPath = firstIssue.path.join('.');\n return {\n content: `⚠️ Config invalid after set (${fieldPath}: ${firstIssue.message}). Change not saved.`,\n success: false,\n };\n }\n\n await saveConfig(validated.data);\n log.info({ path: pathRaw, value: parsedValue.value }, 'Config updated via /config set');\n\n const valueLabel =\n typeof parsedValue.value === 'string'\n ? `\"${parsedValue.value}\"`\n : JSON.stringify(parsedValue.value);\n return { content: `⚙️ Config updated: \\`${pathRaw}\\` = ${valueLabel}` };\n }\n\n if (action === 'unset') {\n if (!senderMayWritePersistentConfig(ctx)) {\n return {\n content: '⚠️ You are not allowed to change config from this chat surface.',\n success: false,\n };\n }\n if (!rest) {\n return { content: '⚠️ Usage: /config unset path', success: false };\n }\n const parsedPath = parseConfigPath(rest);\n if (!parsedPath.ok || !parsedPath.path) {\n return { content: `⚠️ ${parsedPath.error}`, success: false };\n }\n if (isBlockedPath(parsedPath.path)) {\n return {\n content: `⚠️ Path \\`${rest}\\` cannot be modified via chat for security reasons.`,\n success: false,\n };\n }\n\n const configPath = resolveConfigPath();\n const currentConfig = loadConfig(configPath) as Record<string, unknown>;\n const removed = unsetConfigValueAtPath(currentConfig, parsedPath.path);\n if (!removed) {\n return { content: `⚙️ No config value found at \\`${rest}\\`.`, success: false };\n }\n\n const validated = ConfigSchema.safeParse(currentConfig);\n if (!validated.success) {\n const firstIssue = validated.error.issues[0];\n const fieldPath = firstIssue.path.join('.');\n return {\n content: `⚠️ Config invalid after unset (${fieldPath}: ${firstIssue.message}). Change not saved.`,\n success: false,\n };\n }\n\n await saveConfig(validated.data);\n log.info({ path: rest }, 'Config key removed via /config unset');\n return { content: `⚙️ Config updated: \\`${rest}\\` removed.` };\n }\n\n return {\n content:\n '⚙️ *Config Command*\\n\\n' +\n '`/config show [path]` — view config (or a specific path)\\n' +\n '`/config set path=value` — update a config value\\n' +\n '`/config unset path` — remove a config key\\n\\n' +\n 'Examples:\\n' +\n '`/config show agents.defaults.models.chat`\\n' +\n '`/config set agents.defaults.temperature=0.5`\\n' +\n '`/config set agents.defaults.thinkingDefault=medium`\\n' +\n '`/config unset tts`',\n };\n },\n};\n\nexport function registerConfigCommand(): void {\n commandRegistry.register(configCommand);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../../../src/chat-commands/builtins/config.ts"],"sourcesContent":["/**\n * /config — read and write persistent config (~/.xopc/xopc.json) from chat.\n */\n\nimport type { CommandDefinition, CommandContext } from '../types.js';\nimport { commandRegistry } from '../registry.js';\nimport { parseConfigValue } from '../config-value.js';\nimport {\n parseConfigPath,\n getConfigValueAtPath,\n setConfigValueAtPath,\n unsetConfigValueAtPath,\n} from '../config-paths.js';\nimport { ConfigSchema, type TelegramConfig, type WeixinConfig } from '../../config/schema.js';\nimport { loadConfig, saveConfig } from '../../config/loader.js';\nimport { resolveConfigPath } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveAllowlistMatchSimple } from '../../channels/security.js';\n\nconst log = createLogger('ConfigCommand');\n\nconst BLOCKED_WRITE_PATHS = new Set(['gateway.auth.token', 'providers']);\n\nfunction isBlockedPath(path: string[]): boolean {\n const joined = path.join('.');\n for (const blocked of BLOCKED_WRITE_PATHS) {\n if (joined === blocked || joined.startsWith(`${blocked}.`)) return true;\n }\n return false;\n}\n\nfunction redactConfigForDisplay(plain: Record<string, unknown>): void {\n if (plain.gateway && typeof plain.gateway === 'object') {\n const gw = plain.gateway as Record<string, unknown>;\n if (gw.auth && typeof gw.auth === 'object') {\n (gw.auth as Record<string, unknown>).token = '[redacted]';\n }\n }\n if (plain.providers !== undefined) plain.providers = '[redacted]';\n}\n\nfunction senderMayWritePersistentConfig(ctx: CommandContext): boolean {\n const { source, senderId, isGroup } = ctx;\n if (source !== 'telegram' && source !== 'weixin') {\n return true;\n }\n\n const cfg = ctx.getConfig?.() ?? ctx.config;\n\n if (source === 'weixin') {\n const wx = cfg.channels?.weixin as WeixinConfig | undefined;\n if (!wx?.enabled) return false;\n const accountId = ctx.accountId ?? 'default';\n let allowFrom: Array<string | number> = [];\n if (wx.accounts && Object.keys(wx.accounts).length > 0) {\n const acc = wx.accounts[accountId] ?? wx.accounts['default'];\n if (!acc || acc.enabled === false) return false;\n allowFrom = [...(acc.allowFrom ?? [])];\n } else {\n allowFrom = [...(wx.allowFrom ?? [])];\n }\n if (allowFrom.length === 0) return false;\n return resolveAllowlistMatchSimple({ allowFrom, senderId }).allowed;\n }\n\n const tg = cfg.channels?.telegram as TelegramConfig | undefined;\n if (!tg?.enabled) return false;\n const accountId = ctx.accountId ?? 'default';\n const acc = tg.accounts?.[accountId] ?? tg.accounts?.['default'];\n if (!acc || acc.enabled === false) return false;\n const allowFrom = [...(acc.allowFrom ?? [])];\n const groupAllowFrom = [...(acc.groupAllowFrom ?? [])];\n const list = isGroup && groupAllowFrom.length > 0 ? groupAllowFrom : allowFrom;\n if (list.length === 0) return false;\n return resolveAllowlistMatchSimple({ allowFrom: list, senderId }).allowed;\n}\n\nconst configCommand: CommandDefinition = {\n id: 'system.config',\n name: 'config',\n aliases: ['cfg'],\n description:\n 'Show or update configuration. Usage: /config show [path] | /config set path=value | /config unset path',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: [\n '/config show',\n '/config show agents.defaults.models.chat',\n '/config set agents.defaults.models.chat.primary=anthropic/claude-opus-4-5',\n '/config set agents.defaults.temperature=0.5',\n '/config unset tts',\n ],\n handler: async (ctx: CommandContext, args: string) => {\n const parts = args.trim().split(/\\s+/);\n const action = parts[0]?.toLowerCase();\n const rest = parts.slice(1).join(' ').trim();\n\n if (!action || action === 'show' || action === 'get') {\n const config = ctx.getConfig?.() ?? loadConfig(resolveConfigPath());\n const plain = JSON.parse(JSON.stringify(config)) as Record<string, unknown>;\n redactConfigForDisplay(plain);\n\n if (rest) {\n const parsed = parseConfigPath(rest);\n if (!parsed.ok || !parsed.path) {\n return { content: `⚠️ ${parsed.error ?? 'Invalid path.'}`, success: false };\n }\n const value = getConfigValueAtPath(plain, parsed.path);\n const rendered = JSON.stringify(value ?? null, null, 2);\n return { content: `⚙️ \\`${rest}\\`:\\n\\`\\`\\`json\\n${rendered}\\n\\`\\`\\`` };\n }\n\n const json = JSON.stringify(plain, null, 2);\n return { content: `⚙️ Current config:\\n\\`\\`\\`json\\n${json}\\n\\`\\`\\`` };\n }\n\n if (action === 'set') {\n if (!senderMayWritePersistentConfig(ctx)) {\n return {\n content: '⚠️ You are not allowed to change config from this chat surface.',\n success: false,\n };\n }\n const eqIndex = rest.indexOf('=');\n if (eqIndex <= 0) {\n return { content: '⚠️ Usage: /config set path=value', success: false };\n }\n const pathRaw = rest.slice(0, eqIndex).trim();\n const valueRaw = rest.slice(eqIndex + 1);\n\n const parsedPath = parseConfigPath(pathRaw);\n if (!parsedPath.ok || !parsedPath.path) {\n return { content: `⚠️ ${parsedPath.error}`, success: false };\n }\n if (isBlockedPath(parsedPath.path)) {\n return {\n content: `⚠️ Path \\`${pathRaw}\\` cannot be modified via chat for security reasons.`,\n success: false,\n };\n }\n\n const parsedValue = parseConfigValue(valueRaw);\n if (parsedValue.ok === false) {\n return { content: `⚠️ ${parsedValue.error}`, success: false };\n }\n\n const configPath = resolveConfigPath();\n const currentConfig = loadConfig(configPath) as Record<string, unknown>;\n setConfigValueAtPath(currentConfig, parsedPath.path, parsedValue.value);\n\n const validated = ConfigSchema.safeParse(currentConfig);\n if (!validated.success) {\n const firstIssue = validated.error.issues[0];\n const fieldPath = firstIssue.path.join('.');\n return {\n content: `⚠️ Config invalid after set (${fieldPath}: ${firstIssue.message}). Change not saved.`,\n success: false,\n };\n }\n\n await saveConfig(validated.data);\n log.info({ path: pathRaw, value: parsedValue.value }, 'Config updated via /config set');\n\n const valueLabel =\n typeof parsedValue.value === 'string'\n ? `\"${parsedValue.value}\"`\n : JSON.stringify(parsedValue.value);\n return { content: `⚙️ Config updated: \\`${pathRaw}\\` = ${valueLabel}` };\n }\n\n if (action === 'unset') {\n if (!senderMayWritePersistentConfig(ctx)) {\n return {\n content: '⚠️ You are not allowed to change config from this chat surface.',\n success: false,\n };\n }\n if (!rest) {\n return { content: '⚠️ Usage: /config unset path', success: false };\n }\n const parsedPath = parseConfigPath(rest);\n if (!parsedPath.ok || !parsedPath.path) {\n return { content: `⚠️ ${parsedPath.error}`, success: false };\n }\n if (isBlockedPath(parsedPath.path)) {\n return {\n content: `⚠️ Path \\`${rest}\\` cannot be modified via chat for security reasons.`,\n success: false,\n };\n }\n\n const configPath = resolveConfigPath();\n const currentConfig = loadConfig(configPath) as Record<string, unknown>;\n const removed = unsetConfigValueAtPath(currentConfig, parsedPath.path);\n if (!removed) {\n return { content: `⚙️ No config value found at \\`${rest}\\`.`, success: false };\n }\n\n const validated = ConfigSchema.safeParse(currentConfig);\n if (!validated.success) {\n const firstIssue = validated.error.issues[0];\n const fieldPath = firstIssue.path.join('.');\n return {\n content: `⚠️ Config invalid after unset (${fieldPath}: ${firstIssue.message}). Change not saved.`,\n success: false,\n };\n }\n\n await saveConfig(validated.data);\n log.info({ path: rest }, 'Config key removed via /config unset');\n return { content: `⚙️ Config updated: \\`${rest}\\` removed.` };\n }\n\n return {\n content:\n '⚙️ *Config Command*\\n\\n' +\n '`/config show [path]` — view config (or a specific path)\\n' +\n '`/config set path=value` — update a config value\\n' +\n '`/config unset path` — remove a config key\\n\\n' +\n 'Examples:\\n' +\n '`/config show agents.defaults.models.chat`\\n' +\n '`/config set agents.defaults.temperature=0.5`\\n' +\n '`/config set agents.defaults.thinkingDefault=medium`\\n' +\n '`/config unset tts`',\n };\n },\n};\n\nexport function registerConfigCommand(): void {\n commandRegistry.register(configCommand);\n}\n"],"mappings":"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"}
@@ -20,6 +20,8 @@ export interface CommandContextDeps {
20
20
  chatId: string;
21
21
  senderId: string;
22
22
  isGroup: boolean;
23
+ accountId?: string;
24
+ threadId?: string;
23
25
  config: Config;
24
26
  bus: MessageBus;
25
27
  sessionStore: SessionStore;
@@ -61,6 +63,8 @@ export declare class CommandContextImpl implements CommandContext {
61
63
  readonly chatId: string;
62
64
  readonly senderId: string;
63
65
  readonly isGroup: boolean;
66
+ readonly accountId?: string;
67
+ readonly threadId?: string;
64
68
  readonly config: Config;
65
69
  readonly abortCurrentTurn?: () => Promise<void>;
66
70
  readonly reloadSkills?: () => Promise<void>;
@@ -68,6 +72,7 @@ export declare class CommandContextImpl implements CommandContext {
68
72
  readonly workflowRunApis?: CommandContext['workflowRunApis'];
69
73
  private deps;
70
74
  constructor(deps: CommandContextDeps);
75
+ private outboundMetadata;
71
76
  reply(text: string, options?: ReplyOptions): Promise<void>;
72
77
  replyComponent(component: UIComponent): Promise<void>;
73
78
  setTyping(typing: boolean): Promise<void>;
@@ -2,7 +2,7 @@ import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { init_loader, saveConfig } from "../config/loader.js";
4
4
  import { effectiveWorkspacePathForSession } from "../session/session-workspace.js";
5
- import { getRoutingInfo, getSessionDisplayName } from "./session-key.js";
5
+ import { getSessionDisplayName } from "./session-key.js";
6
6
  import { wrapMarkdownExportAsHtml } from "../session/chat-export.js";
7
7
  import { join } from "path";
8
8
  import { mkdir, writeFile } from "fs/promises";
@@ -17,6 +17,8 @@ var CommandContextImpl = class {
17
17
  chatId;
18
18
  senderId;
19
19
  isGroup;
20
+ accountId;
21
+ threadId;
20
22
  config;
21
23
  abortCurrentTurn;
22
24
  reloadSkills;
@@ -30,6 +32,8 @@ var CommandContextImpl = class {
30
32
  this.chatId = deps.chatId;
31
33
  this.senderId = deps.senderId;
32
34
  this.isGroup = deps.isGroup;
35
+ this.accountId = deps.accountId;
36
+ this.threadId = deps.threadId;
33
37
  this.config = deps.config;
34
38
  this.deps = deps;
35
39
  if (deps.abortCurrentTurn) {
@@ -50,6 +54,13 @@ var CommandContextImpl = class {
50
54
  startWorkflowRun: (params) => deps.workflowRunService.startWorkflowRun(params)
51
55
  };
52
56
  }
57
+ outboundMetadata(extra) {
58
+ return {
59
+ accountId: this.deps.accountId,
60
+ threadId: this.deps.threadId,
61
+ ...extra
62
+ };
63
+ }
53
64
  async reply(text, options) {
54
65
  await this.deps.replyHandler(text, options);
55
66
  }
@@ -72,13 +83,12 @@ var CommandContextImpl = class {
72
83
  await this.clearSession();
73
84
  return;
74
85
  }
75
- const routing = getRoutingInfo(this.sessionKey);
76
86
  await this.deps.bus.publishOutbound({
77
- channel: routing.channel,
78
- chat_id: routing.chatId,
87
+ channel: this.source,
88
+ chat_id: this.chatId,
79
89
  content: "✅ New session started. Previous transcript archived; model and session overrides kept.",
80
90
  type: "message",
81
- metadata: { threadId: routing.threadId }
91
+ metadata: this.outboundMetadata()
82
92
  });
83
93
  log.info({ sessionKey: this.sessionKey }, "Session reset");
84
94
  }
@@ -93,13 +103,12 @@ var CommandContextImpl = class {
93
103
  }
94
104
  await this.deps.sessionStore.deleteSession(this.sessionKey);
95
105
  this.deps.invalidateAgentSession?.(this.sessionKey);
96
- const routing = getRoutingInfo(this.sessionKey);
97
106
  await this.deps.bus.publishOutbound({
98
- channel: routing.channel,
99
- chat_id: routing.chatId,
107
+ channel: this.source,
108
+ chat_id: this.chatId,
100
109
  content: "✅ Session cleared.",
101
110
  type: "message",
102
- metadata: { threadId: routing.threadId }
111
+ metadata: this.outboundMetadata()
103
112
  });
104
113
  log.info({ sessionKey: this.sessionKey }, "Session cleared");
105
114
  }