@xopcai/xopc 0.0.86 → 0.0.88

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 (658) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +3 -3
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
  7. package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
  8. package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
  9. package/dist/extensions/telegram/src/plugin.js +1 -1
  10. package/dist/extensions/telegram/src/routing-integration.js +3 -2
  11. package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
  12. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  13. package/dist/extensions/telegram/xopc.extension.json +1 -1
  14. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
  15. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
  16. package/dist/extensions/weixin/src/api/api.js +3 -3
  17. package/dist/extensions/weixin/src/api/api.js.map +1 -1
  18. package/dist/extensions/weixin/src/auth/accounts.js +12 -12
  19. package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
  20. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  21. package/dist/extensions/weixin/src/delivery-to.js +2 -2
  22. package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
  23. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  24. package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
  25. package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
  26. package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
  27. package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
  28. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  29. package/dist/extensions/weixin/src/plugin.js +1 -1
  30. package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
  31. package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
  32. package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
  33. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  34. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
  35. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +222 -0
  36. package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-wKWf3l57.js} +1 -1
  37. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +1 -0
  38. package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-DIsl75Y3.js} +1 -1
  39. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +1 -0
  40. package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-N9hvuRrn.js} +1 -1
  41. package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-tlNGNxhP.js} +1 -1
  42. package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-CJwfHYvT.js} +1 -1
  43. package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-BVJohZoZ.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BT2tmElC.js} +1 -1
  45. package/dist/gateway/static/root/assets/extension-settings-page-BSS47c2j.js +1 -0
  46. package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-BaFNUtkE.js} +1 -1
  47. package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-QwYEq6Hz.js} +1 -1
  48. package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-BVSidEDJ.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +1 -0
  50. package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-qNrVJp-y.js} +97 -95
  51. package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-DDonPVLn.js} +1 -1
  52. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +1 -0
  53. package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-B8N3A3Zo.js} +1 -1
  54. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +3 -0
  55. package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-Q7KqkO-u.js} +1 -1
  56. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +2 -0
  57. package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-BbRc5ugR.js} +1 -1
  58. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +7 -0
  59. package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CxDGduqK.js} +1 -1
  60. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +1 -0
  61. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +27 -0
  62. package/dist/gateway/static/root/index.html +6 -5
  63. package/dist/package.js +1 -1
  64. package/dist/src/agent/agent-manager.js +7 -7
  65. package/dist/src/agent/agent-scope.d.ts +4 -0
  66. package/dist/src/agent/agent-scope.js +53 -10
  67. package/dist/src/agent/agent-scope.js.map +1 -1
  68. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
  69. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  70. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  71. package/dist/src/agent/child-agent-factory.d.ts +15 -0
  72. package/dist/src/agent/child-agent-factory.js +35 -2
  73. package/dist/src/agent/child-agent-factory.js.map +1 -1
  74. package/dist/src/agent/client-error-format.d.ts +20 -0
  75. package/dist/src/agent/client-error-format.js +97 -0
  76. package/dist/src/agent/client-error-format.js.map +1 -0
  77. package/dist/src/agent/context/workspace-seed.js +2 -2
  78. package/dist/src/agent/embedded/run-turn.js +23 -4
  79. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  80. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
  81. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  82. package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
  83. package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
  84. package/dist/src/agent/fallback/candidates.js +2 -2
  85. package/dist/src/agent/fallback/candidates.js.map +1 -1
  86. package/dist/src/agent/goals/goal-locale.d.ts +1 -1
  87. package/dist/src/agent/goals/goal-run-store.js +4 -4
  88. package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
  89. package/dist/src/agent/goals/persistent-goal-service.js +1 -2
  90. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  91. package/dist/src/agent/goals/post-turn.js +2 -2
  92. package/dist/src/agent/image/generation/normalization.js +2 -12
  93. package/dist/src/agent/image/generation/normalization.js.map +1 -1
  94. package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
  95. package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
  96. package/dist/src/agent/image/generation/runtime.d.ts +2 -2
  97. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  98. package/dist/src/agent/image/generation/types.d.ts +0 -18
  99. package/dist/src/agent/image/image-helpers.js +6 -1
  100. package/dist/src/agent/image/image-helpers.js.map +1 -1
  101. package/dist/src/agent/image/index.d.ts +1 -1
  102. package/dist/src/agent/image/load-image-media.js +2 -2
  103. package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
  104. package/dist/src/agent/inbound/inbound-loop.js +41 -10
  105. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  106. package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
  107. package/dist/src/agent/inbound/turn-dispatcher.js +7 -5
  108. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  109. package/dist/src/agent/ipc/bus.js +1 -1
  110. package/dist/src/agent/ipc/inbox.js +2 -2
  111. package/dist/src/agent/ipc/socket.js +1 -1
  112. package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
  113. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  114. package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
  115. package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
  116. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
  117. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  118. package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
  119. package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
  120. package/dist/src/agent/mcp/mcp-transport.js +2 -1
  121. package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
  122. package/dist/src/agent/media-generation/runtime-shared.js +2 -9
  123. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  124. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  125. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  126. package/dist/src/agent/memory/dreaming/events.js +1 -1
  127. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  128. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  129. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  130. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  131. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  132. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  133. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  134. package/dist/src/agent/messaging/command-handler.d.ts +6 -0
  135. package/dist/src/agent/messaging/command-handler.js +5 -0
  136. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  137. package/dist/src/agent/models/manager.js +1 -1
  138. package/dist/src/agent/orchestration/llm-turn-retry.d.ts +2 -0
  139. package/dist/src/agent/orchestration/llm-turn-retry.js +9 -1
  140. package/dist/src/agent/orchestration/llm-turn-retry.js.map +1 -1
  141. package/dist/src/agent/prompt/safety.d.ts +0 -7
  142. package/dist/src/agent/prompt/safety.js +1 -20
  143. package/dist/src/agent/prompt/safety.js.map +1 -1
  144. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  145. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  146. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  147. package/dist/src/agent/sandbox/path-policy.js +2 -2
  148. package/dist/src/agent/service/build-direct-message-content.js +2 -2
  149. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  150. package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
  151. package/dist/src/agent/service/direct-turn-helpers.js +6 -1
  152. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  153. package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
  154. package/dist/src/agent/service/process-direct-one-shot.js +15 -2
  155. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  156. package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
  157. package/dist/src/agent/service/process-direct-streaming.js +53 -7
  158. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  159. package/dist/src/agent/service/webchat-tts.d.ts +1 -2
  160. package/dist/src/agent/service/webchat-tts.js +2 -2
  161. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  162. package/dist/src/agent/service.d.ts +8 -0
  163. package/dist/src/agent/service.js +25 -5
  164. package/dist/src/agent/service.js.map +1 -1
  165. package/dist/src/agent/session/session-inspector.js +1 -1
  166. package/dist/src/agent/skills/config.js +1 -1
  167. package/dist/src/agent/skills/hub-hash.js +2 -2
  168. package/dist/src/agent/skills/hub-lock.js +1 -1
  169. package/dist/src/agent/skills/hub-pull.js +2 -2
  170. package/dist/src/agent/skills/index.js +1 -1
  171. package/dist/src/agent/skills/managed-store.js +1 -1
  172. package/dist/src/agent/skills/scanner.js +1 -1
  173. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  174. package/dist/src/agent/skills/skill-manager.js +1 -1
  175. package/dist/src/agent/tools/create-share-tool.js +27 -20
  176. package/dist/src/agent/tools/create-share-tool.js.map +1 -1
  177. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  178. package/dist/src/agent/tools/factory.js +2 -2
  179. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  180. package/dist/src/agent/tools/index.d.ts +0 -1
  181. package/dist/src/agent/tools/index.js +4 -5
  182. package/dist/src/agent/tools/send-media.js +1 -1
  183. package/dist/src/agent/tools/shell.js +0 -13
  184. package/dist/src/agent/tools/shell.js.map +1 -1
  185. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  186. package/dist/src/agent/tools/workflow-tool.js +70 -16
  187. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  188. package/dist/src/agent/tools/write.js +1 -1
  189. package/dist/src/agent/workflow/agent-progress.d.ts +5 -0
  190. package/dist/src/agent/workflow/agent-progress.js +65 -0
  191. package/dist/src/agent/workflow/agent-progress.js.map +1 -0
  192. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  193. package/dist/src/agent/workflow/builtins/audit-repo.js +14 -0
  194. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  195. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  196. package/dist/src/agent/workflow/builtins/debug-incident.js +14 -0
  197. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  198. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +12 -0
  199. package/dist/src/agent/workflow/builtins/implementation-plan.js +175 -0
  200. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -0
  201. package/dist/src/agent/workflow/builtins/index.d.ts +3 -1
  202. package/dist/src/agent/workflow/builtins/index.js +11 -1
  203. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  204. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  205. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +14 -0
  206. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  207. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  208. package/dist/src/agent/workflow/builtins/pr-review.js +14 -0
  209. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  210. package/dist/src/agent/workflow/builtins/release-check.d.ts +11 -0
  211. package/dist/src/agent/workflow/builtins/release-check.js +165 -0
  212. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -0
  213. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  214. package/dist/src/agent/workflow/builtins/research.js +14 -0
  215. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  216. package/dist/src/agent/workflow/catalog.js +1 -1
  217. package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
  218. package/dist/src/agent/workflow/index.d.ts +2 -1
  219. package/dist/src/agent/workflow/index.js +3 -2
  220. package/dist/src/agent/workflow/lint.d.ts +38 -0
  221. package/dist/src/agent/workflow/lint.js +74 -0
  222. package/dist/src/agent/workflow/lint.js.map +1 -0
  223. package/dist/src/agent/workflow/meta-locale.d.ts +12 -0
  224. package/dist/src/agent/workflow/meta-locale.js +62 -0
  225. package/dist/src/agent/workflow/meta-locale.js.map +1 -0
  226. package/dist/src/agent/workflow/parser.js +7 -1
  227. package/dist/src/agent/workflow/parser.js.map +1 -1
  228. package/dist/src/agent/workflow/runtime.d.ts +4 -1
  229. package/dist/src/agent/workflow/runtime.js +88 -8
  230. package/dist/src/agent/workflow/runtime.js.map +1 -1
  231. package/dist/src/agent/workflow/snapshot.js +2 -12
  232. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  233. package/dist/src/agent/workflow/step-labels.d.ts +8 -0
  234. package/dist/src/agent/workflow/step-labels.js +48 -0
  235. package/dist/src/agent/workflow/step-labels.js.map +1 -0
  236. package/dist/src/agent/workflow/subagent-runner.js +46 -1
  237. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  238. package/dist/src/agent/workflow/types.d.ts +76 -1
  239. package/dist/src/auth/credentials.d.ts +5 -0
  240. package/dist/src/auth/credentials.js +12 -3
  241. package/dist/src/auth/credentials.js.map +1 -1
  242. package/dist/src/auth/profiles/store.js +1 -1
  243. package/dist/src/auth/sync-provider-auth.js +1 -1
  244. package/dist/src/browser/cache-dir-policy.js +1 -1
  245. package/dist/src/browser/cdp-local-launcher.js +2 -2
  246. package/dist/src/browser/index.js +4 -4
  247. package/dist/src/browser/manager.d.ts +1 -3
  248. package/dist/src/browser/manager.js +0 -6
  249. package/dist/src/browser/manager.js.map +1 -1
  250. package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
  251. package/dist/src/browser/providers/browser-ext-install.js +41 -88
  252. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  253. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
  254. package/dist/src/browser/providers/cloakbrowser.js +6 -59
  255. package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
  256. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  257. package/dist/src/browser/stealth.js +1 -1
  258. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  259. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  260. package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
  261. package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
  262. package/dist/src/channels/outbound/persist-store.js +1 -1
  263. package/dist/src/channels/pairing/allow-from-file.js +9 -9
  264. package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
  265. package/dist/src/channels/pairing/pairing-store.js +7 -7
  266. package/dist/src/channels/pairing/pairing-store.js.map +1 -1
  267. package/dist/src/chat-commands/builtins/config.js +2 -2
  268. package/dist/src/chat-commands/builtins/session.js +1 -1
  269. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  270. package/dist/src/chat-commands/builtins/tts.js +2 -2
  271. package/dist/src/chat-commands/builtins/tts.js.map +1 -1
  272. package/dist/src/chat-commands/context.d.ts +3 -0
  273. package/dist/src/chat-commands/context.js +22 -4
  274. package/dist/src/chat-commands/context.js.map +1 -1
  275. package/dist/src/chat-commands/session-key.d.ts +4 -37
  276. package/dist/src/chat-commands/session-key.js +49 -85
  277. package/dist/src/chat-commands/session-key.js.map +1 -1
  278. package/dist/src/chat-commands/types.d.ts +2 -0
  279. package/dist/src/cli/commands/agent/interactive.js +2 -2
  280. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  281. package/dist/src/cli/commands/agent/sessions.js +2 -2
  282. package/dist/src/cli/commands/agent/sessions.js.map +1 -1
  283. package/dist/src/cli/commands/agent.js +4 -5
  284. package/dist/src/cli/commands/agent.js.map +1 -1
  285. package/dist/src/cli/commands/channels.js +1 -5
  286. package/dist/src/cli/commands/channels.js.map +1 -1
  287. package/dist/src/cli/commands/config.js +1 -1
  288. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  289. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  290. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  291. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  292. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  293. package/dist/src/cli/commands/extension-dev.js +1 -1
  294. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  295. package/dist/src/cli/commands/extension-pack.js +1 -1
  296. package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
  297. package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
  298. package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
  299. package/dist/src/cli/commands/gateway/logs.js +50 -17
  300. package/dist/src/cli/commands/gateway/logs.js.map +1 -1
  301. package/dist/src/cli/commands/image.js +23 -22
  302. package/dist/src/cli/commands/image.js.map +1 -1
  303. package/dist/src/cli/commands/init.js +4 -4
  304. package/dist/src/cli/commands/onboard.js +1 -1
  305. package/dist/src/cli/commands/session/utils.js +2 -2
  306. package/dist/src/cli/commands/session/utils.js.map +1 -1
  307. package/dist/src/cli/commands/update.js +26 -46
  308. package/dist/src/cli/commands/update.js.map +1 -1
  309. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  310. package/dist/src/cli/utils/session.d.ts +0 -5
  311. package/dist/src/cli/utils/session.js +1 -6
  312. package/dist/src/cli/utils/session.js.map +1 -1
  313. package/dist/src/commands/agents.config.js +1 -1
  314. package/dist/src/commands/agents.config.js.map +1 -1
  315. package/dist/src/config/agent-profile.js +6 -28
  316. package/dist/src/config/agent-profile.js.map +1 -1
  317. package/dist/src/config/agent-typed-models.d.ts +18 -0
  318. package/dist/src/config/agent-typed-models.js +53 -0
  319. package/dist/src/config/agent-typed-models.js.map +1 -0
  320. package/dist/src/config/gateway-bind.js +1 -1
  321. package/dist/src/config/index.js +6 -6
  322. package/dist/src/config/loader.js +2 -2
  323. package/dist/src/config/model-input.js +2 -5
  324. package/dist/src/config/model-input.js.map +1 -1
  325. package/dist/src/config/models-json.js +2 -2
  326. package/dist/src/config/paths-state.js +1 -1
  327. package/dist/src/config/profile.js +2 -2
  328. package/dist/src/config/schema.d.ts +253 -217
  329. package/dist/src/config/schema.js +91 -40
  330. package/dist/src/config/schema.js.map +1 -1
  331. package/dist/src/config/voice.d.ts +3 -28
  332. package/dist/src/config/voice.js +27 -261
  333. package/dist/src/config/voice.js.map +1 -1
  334. package/dist/src/config/workspace-path-helpers.d.ts +1 -2
  335. package/dist/src/config/workspace-path-helpers.js.map +1 -1
  336. package/dist/src/config/workspace-path.js +1 -1
  337. package/dist/src/cron/executor.js +2 -2
  338. package/dist/src/cron/persistence.js +1 -1
  339. package/dist/src/cron/run-log-store.js +1 -1
  340. package/dist/src/daemon/constants.js +1 -1
  341. package/dist/src/daemon/install-plan.js +27 -3
  342. package/dist/src/daemon/install-plan.js.map +1 -1
  343. package/dist/src/daemon/launchd.d.ts +8 -0
  344. package/dist/src/daemon/launchd.js +7 -14
  345. package/dist/src/daemon/launchd.js.map +1 -1
  346. package/dist/src/daemon/schtasks.d.ts +25 -0
  347. package/dist/src/daemon/schtasks.js +168 -48
  348. package/dist/src/daemon/schtasks.js.map +1 -1
  349. package/dist/src/daemon/service.js +5 -4
  350. package/dist/src/daemon/service.js.map +1 -1
  351. package/dist/src/daemon/systemd.d.ts +6 -0
  352. package/dist/src/daemon/systemd.js +20 -5
  353. package/dist/src/daemon/systemd.js.map +1 -1
  354. package/dist/src/extensions/activation-context.js +0 -1
  355. package/dist/src/extensions/activation-context.js.map +1 -1
  356. package/dist/src/extensions/bundle-mcp.js +1 -1
  357. package/dist/src/extensions/discover-extensions.js +1 -1
  358. package/dist/src/extensions/health.js +1 -1
  359. package/dist/src/extensions/loader.js +1 -1
  360. package/dist/src/extensions/lockfile.js +2 -2
  361. package/dist/src/extensions/normalize-manifest.js +0 -1
  362. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  363. package/dist/src/extensions/types/manifest.d.ts +0 -2
  364. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  365. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  366. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  367. package/dist/src/gateway/agents-admin.d.ts +9 -0
  368. package/dist/src/gateway/agents-admin.js +28 -4
  369. package/dist/src/gateway/agents-admin.js.map +1 -1
  370. package/dist/src/gateway/config-tools-web.js +3 -2
  371. package/dist/src/gateway/config-tools-web.js.map +1 -1
  372. package/dist/src/gateway/file-path-classifier.js +2 -2
  373. package/dist/src/gateway/heartbeat/service.js +2 -2
  374. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  375. package/dist/src/gateway/hono/app.js +1 -1
  376. package/dist/src/gateway/hono/lib/agent-model.d.ts +25 -10
  377. package/dist/src/gateway/hono/lib/agent-model.js +60 -36
  378. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  379. package/dist/src/gateway/hono/lib/config-payload.js +29 -6
  380. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  381. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  382. package/dist/src/gateway/hono/lib/mask-secret-length.d.ts +6 -0
  383. package/dist/src/gateway/hono/lib/mask-secret-length.js +16 -0
  384. package/dist/src/gateway/hono/lib/mask-secret-length.js.map +1 -0
  385. package/dist/src/gateway/hono/lib/safe-providers-config.d.ts +1 -1
  386. package/dist/src/gateway/hono/lib/safe-providers-config.js +2 -1
  387. package/dist/src/gateway/hono/lib/safe-providers-config.js.map +1 -1
  388. package/dist/src/gateway/hono/lib/safe-voice-config.js +16 -54
  389. package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
  390. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  391. package/dist/src/gateway/hono/oauth.js +1 -1
  392. package/dist/src/gateway/hono/routes/agents.js +2 -2
  393. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  394. package/dist/src/gateway/hono/routes/config-patch/agents.js +25 -7
  395. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  396. package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
  397. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
  398. package/dist/src/gateway/hono/routes/config-patch/gateway.js +3 -2
  399. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  400. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -3
  401. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  402. package/dist/src/gateway/hono/routes/config.js +59 -0
  403. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  404. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  405. package/dist/src/gateway/hono/routes/goals.js +1 -1
  406. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  407. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  408. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  409. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  410. package/dist/src/gateway/hono/routes/models.js +75 -12
  411. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  412. package/dist/src/gateway/hono/routes/sessions.js +28 -7
  413. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  414. package/dist/src/gateway/hono/routes/shares.js +15 -13
  415. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  416. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  417. package/dist/src/gateway/hono/routes/update.js +4 -2
  418. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  419. package/dist/src/gateway/hono/routes/voice.js +75 -0
  420. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  421. package/dist/src/gateway/hono/routes/workflows.d.ts +3 -0
  422. package/dist/src/gateway/hono/routes/workflows.js +347 -0
  423. package/dist/src/gateway/hono/routes/workflows.js.map +1 -0
  424. package/dist/src/gateway/hono/routes/workspace.js +4 -4
  425. package/dist/src/gateway/hono/sse.js +16 -33
  426. package/dist/src/gateway/hono/sse.js.map +1 -1
  427. package/dist/src/gateway/lock.js +11 -11
  428. package/dist/src/gateway/lock.js.map +1 -1
  429. package/dist/src/gateway/ports.js +6 -6
  430. package/dist/src/gateway/ports.js.map +1 -1
  431. package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
  432. package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
  433. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
  434. package/dist/src/gateway/service/agent-runner.js +2 -2
  435. package/dist/src/gateway/service/marketplace-service.js +2 -2
  436. package/dist/src/gateway/service/run-gateway-agent.js +9 -11
  437. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  438. package/dist/src/gateway/service/sessions-api.d.ts +3 -0
  439. package/dist/src/gateway/service/sessions-api.js +8 -0
  440. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  441. package/dist/src/gateway/service.d.ts +3 -2
  442. package/dist/src/gateway/service.js +9 -8
  443. package/dist/src/gateway/service.js.map +1 -1
  444. package/dist/src/gateway/session-reset-service.d.ts +20 -0
  445. package/dist/src/gateway/session-reset-service.js +54 -0
  446. package/dist/src/gateway/session-reset-service.js.map +1 -0
  447. package/dist/src/gateway/startup-readiness.d.ts +1 -1
  448. package/dist/src/gateway/startup-readiness.js +1 -0
  449. package/dist/src/gateway/startup-readiness.js.map +1 -1
  450. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  451. package/dist/src/heartbeat/index.js +1 -1
  452. package/dist/src/infra/gateway-processes.js +2 -2
  453. package/dist/src/infra/gateway-processes.js.map +1 -1
  454. package/dist/src/infra/restart.js +2 -2
  455. package/dist/src/infra/run-command.d.ts +16 -0
  456. package/dist/src/infra/run-command.js +67 -0
  457. package/dist/src/infra/run-command.js.map +1 -0
  458. package/dist/src/infra/update-check.js +1 -1
  459. package/dist/src/infra/update-global.d.ts +45 -0
  460. package/dist/src/infra/update-global.js +224 -0
  461. package/dist/src/infra/update-global.js.map +1 -0
  462. package/dist/src/infra/update-lock.js +3 -3
  463. package/dist/src/infra/update-runner.js +1 -1
  464. package/dist/src/infra/update-startup.js +2 -2
  465. package/dist/src/infra/write-file-atomic.js +2 -2
  466. package/dist/src/mcp/channel-shared.js +2 -1
  467. package/dist/src/mcp/channel-shared.js.map +1 -1
  468. package/dist/src/providers/auth-runtime/auth-profile-store.js +2 -2
  469. package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
  470. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
  471. package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
  472. package/dist/src/providers/auth-runtime/types.d.ts +6 -12
  473. package/dist/src/providers/index.js +2 -2
  474. package/dist/src/providers/model-registry.js +1 -1
  475. package/dist/src/routing/agent-session-key.d.ts +58 -0
  476. package/dist/src/routing/agent-session-key.js +164 -0
  477. package/dist/src/routing/agent-session-key.js.map +1 -0
  478. package/dist/src/routing/index.d.ts +1 -1
  479. package/dist/src/routing/index.js +4 -2
  480. package/dist/src/routing/index.js.map +1 -1
  481. package/dist/src/routing/resolve-route.d.ts +15 -0
  482. package/dist/src/routing/resolve-route.js +41 -20
  483. package/dist/src/routing/resolve-route.js.map +1 -1
  484. package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
  485. package/dist/src/routing/resolve-tui-session-key.js +54 -0
  486. package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
  487. package/dist/src/routing/session-key-utils.d.ts +24 -0
  488. package/dist/src/routing/session-key-utils.js +92 -0
  489. package/dist/src/routing/session-key-utils.js.map +1 -0
  490. package/dist/src/routing/session-key.d.ts +19 -49
  491. package/dist/src/routing/session-key.js +143 -116
  492. package/dist/src/routing/session-key.js.map +1 -1
  493. package/dist/src/session/config-store.js +2 -2
  494. package/dist/src/session/index.d.ts +6 -0
  495. package/dist/src/session/index.js +7 -1
  496. package/dist/src/session/init-session-turn.d.ts +30 -0
  497. package/dist/src/session/init-session-turn.js +102 -0
  498. package/dist/src/session/init-session-turn.js.map +1 -0
  499. package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
  500. package/dist/src/session/lifecycle-timestamps.js +16 -0
  501. package/dist/src/session/lifecycle-timestamps.js.map +1 -0
  502. package/dist/src/session/manager.d.ts +7 -1
  503. package/dist/src/session/manager.js +8 -1
  504. package/dist/src/session/manager.js.map +1 -1
  505. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  506. package/dist/src/session/parity/sessions-json-file.js +1 -1
  507. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  508. package/dist/src/session/parity/transcript-paths.js +2 -2
  509. package/dist/src/session/parity/transcript-paths.js.map +1 -1
  510. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
  511. package/dist/src/session/reset-policy.d.ts +32 -0
  512. package/dist/src/session/reset-policy.js +65 -0
  513. package/dist/src/session/reset-policy.js.map +1 -0
  514. package/dist/src/session/reset-triggers.d.ts +20 -0
  515. package/dist/src/session/reset-triggers.js +63 -0
  516. package/dist/src/session/reset-triggers.js.map +1 -0
  517. package/dist/src/session/reset-type.d.ts +12 -0
  518. package/dist/src/session/reset-type.js +25 -0
  519. package/dist/src/session/reset-type.js.map +1 -0
  520. package/dist/src/session/resolve-session.d.ts +30 -0
  521. package/dist/src/session/resolve-session.js +93 -0
  522. package/dist/src/session/resolve-session.js.map +1 -0
  523. package/dist/src/session/search-index-cache.js +1 -1
  524. package/dist/src/session/search-index.js +1 -1
  525. package/dist/src/session/session-title.js +3 -2
  526. package/dist/src/session/session-title.js.map +1 -1
  527. package/dist/src/session/store.d.ts +11 -4
  528. package/dist/src/session/store.js +62 -11
  529. package/dist/src/session/store.js.map +1 -1
  530. package/dist/src/session/transcript-events.js +2 -1
  531. package/dist/src/session/transcript-events.js.map +1 -1
  532. package/dist/src/share/share-auto.js +2 -2
  533. package/dist/src/share/share-store.js +3 -3
  534. package/dist/src/share/share-thumbnail.js +2 -2
  535. package/dist/src/share/share-url.d.ts +33 -0
  536. package/dist/src/share/share-url.js +56 -14
  537. package/dist/src/share/share-url.js.map +1 -1
  538. package/dist/src/share/share-zip.js +1 -1
  539. package/dist/src/share/site-share-store.js +3 -3
  540. package/dist/src/share/site-static-serve.js +1 -1
  541. package/dist/src/tui/backends/embedded-backend.js +4 -9
  542. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  543. package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
  544. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  545. package/dist/src/tui/clipboard-image.js +3 -3
  546. package/dist/src/tui/components/chat-log.js +3 -3
  547. package/dist/src/tui/components/chat-log.js.map +1 -1
  548. package/dist/src/tui/theme-manager.js +1 -1
  549. package/dist/src/tui/theme.d.ts +0 -2
  550. package/dist/src/tui/theme.js +1 -3
  551. package/dist/src/tui/theme.js.map +1 -1
  552. package/dist/src/tui/tui-agent-events.js +2 -1
  553. package/dist/src/tui/tui-agent-events.js.map +1 -1
  554. package/dist/src/tui/tui-commands.d.ts +3 -0
  555. package/dist/src/tui/tui-commands.js +45 -10
  556. package/dist/src/tui/tui-commands.js.map +1 -1
  557. package/dist/src/tui/tui-keybindings-file.js +2 -22
  558. package/dist/src/tui/tui-keybindings-file.js.map +1 -1
  559. package/dist/src/tui/tui-scoped-models.js +2 -2
  560. package/dist/src/tui/tui-session-actions.d.ts +28 -0
  561. package/dist/src/tui/tui-session-actions.js +88 -0
  562. package/dist/src/tui/tui-session-actions.js.map +1 -0
  563. package/dist/src/tui/tui-settings.js +1 -1
  564. package/dist/src/tui/tui.js +54 -49
  565. package/dist/src/tui/tui.js.map +1 -1
  566. package/dist/src/tunnel/frpc-binary.js +3 -3
  567. package/dist/src/tunnel/frpc-config.js +1 -1
  568. package/dist/src/tunnel/frpc-extract.js +1 -1
  569. package/dist/src/tunnel/tunnel-state.js +1 -1
  570. package/dist/src/utils/logger/audit.js +1 -1
  571. package/dist/src/utils/logger/log-store.js +1 -1
  572. package/dist/src/utils/logger/rotation.js +1 -1
  573. package/dist/src/utils/string-coerce.d.ts +2 -0
  574. package/dist/src/utils/string-coerce.js +10 -1
  575. package/dist/src/utils/string-coerce.js.map +1 -1
  576. package/dist/src/voice/metadata/builtin.d.ts +2 -0
  577. package/dist/src/voice/metadata/builtin.js +420 -0
  578. package/dist/src/voice/metadata/builtin.js.map +1 -0
  579. package/dist/src/voice/metadata/index.d.ts +4 -0
  580. package/dist/src/voice/metadata/index.js +3 -0
  581. package/dist/src/voice/metadata/registry.d.ts +5 -0
  582. package/dist/src/voice/metadata/registry.js +34 -0
  583. package/dist/src/voice/metadata/registry.js.map +1 -0
  584. package/dist/src/voice/metadata/types.d.ts +41 -0
  585. package/dist/src/voice/metadata/types.js +1 -0
  586. package/dist/src/voice/stt/config-slice.d.ts +2 -5
  587. package/dist/src/voice/stt/config-slice.js +5 -26
  588. package/dist/src/voice/stt/config-slice.js.map +1 -1
  589. package/dist/src/voice/stt/list-providers.d.ts +3 -3
  590. package/dist/src/voice/stt/list-providers.js +41 -6
  591. package/dist/src/voice/stt/list-providers.js.map +1 -1
  592. package/dist/src/voice/stt/types.d.ts +1 -18
  593. package/dist/src/voice/stt/types.js +4 -2
  594. package/dist/src/voice/stt/types.js.map +1 -1
  595. package/dist/src/voice/tts/audio.js +1 -1
  596. package/dist/src/voice/tts/config-slice.d.ts +3 -7
  597. package/dist/src/voice/tts/config-slice.js +7 -38
  598. package/dist/src/voice/tts/config-slice.js.map +1 -1
  599. package/dist/src/voice/tts/list-providers.d.ts +3 -3
  600. package/dist/src/voice/tts/list-providers.js +41 -6
  601. package/dist/src/voice/tts/list-providers.js.map +1 -1
  602. package/dist/src/voice/tts/merge-config.js +2 -48
  603. package/dist/src/voice/tts/merge-config.js.map +1 -1
  604. package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
  605. package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
  606. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  607. package/dist/src/voice/tts/types.d.ts +1 -29
  608. package/dist/src/voice/tts/types.js +19 -17
  609. package/dist/src/voice/tts/types.js.map +1 -1
  610. package/dist/src/workflows/domain/command.d.ts +18 -0
  611. package/dist/src/workflows/domain/command.js +1 -0
  612. package/dist/src/workflows/domain/definition.d.ts +62 -0
  613. package/dist/src/workflows/domain/definition.js +1 -0
  614. package/dist/src/workflows/domain/event.d.ts +67 -0
  615. package/dist/src/workflows/domain/event.js +1 -0
  616. package/dist/src/workflows/domain/index.d.ts +5 -0
  617. package/dist/src/workflows/domain/index.js +2 -0
  618. package/dist/src/workflows/domain/result.d.ts +65 -0
  619. package/dist/src/workflows/domain/result.js +1 -0
  620. package/dist/src/workflows/domain/run.d.ts +120 -0
  621. package/dist/src/workflows/domain/run.js +14 -0
  622. package/dist/src/workflows/domain/run.js.map +1 -0
  623. package/dist/src/workflows/engine/index.d.ts +2 -0
  624. package/dist/src/workflows/engine/index.js +3 -0
  625. package/dist/src/workflows/engine/projector.d.ts +3 -0
  626. package/dist/src/workflows/engine/projector.js +205 -0
  627. package/dist/src/workflows/engine/projector.js.map +1 -0
  628. package/dist/src/workflows/engine/workflow-engine.d.ts +31 -0
  629. package/dist/src/workflows/engine/workflow-engine.js +188 -0
  630. package/dist/src/workflows/engine/workflow-engine.js.map +1 -0
  631. package/dist/src/workflows/index.d.ts +6 -0
  632. package/dist/src/workflows/index.js +11 -0
  633. package/dist/src/workflows/runtime/index.d.ts +1 -0
  634. package/dist/src/workflows/runtime/index.js +4 -0
  635. package/dist/src/workflows/runtime/script-runtime.d.ts +3 -0
  636. package/dist/src/workflows/runtime/script-runtime.js +3 -0
  637. package/dist/src/workflows/store/event-store.d.ts +17 -0
  638. package/dist/src/workflows/store/event-store.js +83 -0
  639. package/dist/src/workflows/store/event-store.js.map +1 -0
  640. package/dist/src/workflows/store/paths.d.ts +7 -0
  641. package/dist/src/workflows/store/paths.js +26 -0
  642. package/dist/src/workflows/store/paths.js.map +1 -0
  643. package/dist/src/workflows/store/run-store.d.ts +13 -0
  644. package/dist/src/workflows/store/run-store.js +68 -0
  645. package/dist/src/workflows/store/run-store.js.map +1 -0
  646. package/package.json +5 -8
  647. package/dist/gateway/static/root/assets/agents-mS3_HpRI.js +0 -222
  648. package/dist/gateway/static/root/assets/channels-settings-BG6b9KrW.js +0 -1
  649. package/dist/gateway/static/root/assets/extension-settings-page-B-W4x2xP.js +0 -1
  650. package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
  651. package/dist/gateway/static/root/assets/sessions-page-FaG_Vlkb.js +0 -1
  652. package/dist/gateway/static/root/assets/settings-page-Bet1OerL.js +0 -3
  653. package/dist/gateway/static/root/assets/skills-page-DhUO235y.js +0 -2
  654. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
  655. package/dist/gateway/static/root/assets/voice-api-key-field-CGEydndO.js +0 -1
  656. package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
  657. package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
  658. package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"inbound-loop.js","names":[],"sources":["../../../../src/agent/inbound/inbound-loop.ts"],"sourcesContent":["/**\n * InboundLoop — owns the bus-driven inbound pipeline.\n *\n * Replaces the previous `AgentService.start()` while-loop, `handleInboundMessage`,\n * and `handleSystemMessage` methods. Everything that \"a message arrives, run the\n * agent turn, publish the reply\" needs is concentrated here; the parent\n * `AgentService` now just constructs the loop with collaborators and forwards\n * start/stop to it.\n *\n * The constructor takes a fairly wide config because handling a single inbound\n * message touches almost every subsystem (router, command handler, lifecycle\n * manager, agent orchestrator, outbound coordinator, session state, etc.). All\n * dependencies are injected so this class is unit-testable and the inbound\n * pipeline can evolve without touching `AgentService`.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { MessageBus, InboundMessage } from '../../infra/bus/index.js';\nimport { MessageBusShutdownError } from '../../infra/bus/index.js';\nimport type { Config } from '../../config/schema.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport { runWithLogContext, updateAsyncLogContext } from '../../utils/logger.js';\nimport type { ContextualLogger } from '../../utils/logger/types.js';\n\nimport type { AgentManager } from '../agent-manager.js';\nimport type { AgentOrchestrator } from '../orchestration/index.js';\nimport type { CommandHandler, OutboundCoordinator, StreamManager } from '../messaging/index.js';\nimport type { MessageRouter } from '../messaging/message-router.js';\nimport type { ModelManager } from '../models/index.js';\nimport type {\n SessionContext,\n SessionContextManager,\n SessionHydrator,\n SessionLifecycleManager,\n SessionStateBag,\n} from '../session/index.js';\nimport type { FeedbackCoordinator } from '../feedback/index.js';\nimport type { HookHandler } from '../lifecycle/hook-handler.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { StreamHandle } from '../service.types.js';\nimport { runEmbeddedTurnForSession } from '../embedded/run-for-session.js';\nimport { inboundMessageLogRequestId } from '../service-inbound-utils.js';\n\n/** Initial back-off when bus consume fails. Doubles each consecutive failure. */\nconst INBOUND_CONSUME_BASE_BACKOFF_MS = 1_000;\n/** Hard cap on back-off so a long bus outage settles at one retry per 30s. */\nconst INBOUND_CONSUME_MAX_BACKOFF_MS = 30_000;\n\nexport interface InboundLoopConfig {\n log: ContextualLogger;\n agentId: string;\n bus: MessageBus;\n hookHandler: HookHandler;\n messageRouter: MessageRouter;\n commandHandler: CommandHandler;\n sessionContextManager: SessionContextManager;\n feedbackCoordinator: FeedbackCoordinator;\n agentManager: AgentManager;\n sessionLifecycleManager: SessionLifecycleManager;\n agentOrchestrator: AgentOrchestrator;\n outboundCoordinator: OutboundCoordinator;\n streamManager: StreamManager;\n sessionState: SessionStateBag;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n\n /** Register a per-session agent-event subscription (idempotent). */\n setupSessionEventHandling: (sessionKey: string) => void;\n /** Per-session config hydration (workspace + model override) before a turn runs. */\n sessionHydrator: SessionHydrator;\n /** Returns the visible last assistant text used for outbound + persistent-goal hook. */\n getLastAssistantPlainText: (sessionKey: string) => string;\n /** Pre-turn auto-compaction (only used by system messages). */\n checkAndCompact: (sessionKey: string, messages: AgentMessage[]) => Promise<void>;\n /** Fire-and-forget auto-title (no-ops for cron/heartbeat keys). */\n enqueueMaybeAutoTitleAfterPersist: (sessionKey: string) => void;\n /** Effective merged config snapshot. */\n getConfig: () => Config | undefined;\n /** Connect a channel stream handle for partial assistant text rendering. */\n setStreamHandle: (handle: StreamHandle) => void;\n}\n\nexport class InboundLoop {\n private readonly cfg: InboundLoopConfig;\n private readonly log: ContextualLogger;\n private running = false;\n private channelManagerRef: ChannelManager | null = null;\n\n constructor(cfg: InboundLoopConfig) {\n this.cfg = cfg;\n this.log = cfg.log;\n }\n\n setChannelManager(channelManager: ChannelManager | null): void {\n this.channelManagerRef = channelManager;\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n /** Begin consuming inbound messages from the bus until {@link stop} or shutdown. */\n async start(): Promise<void> {\n this.running = true;\n await this.cfg.hookHandler.trigger('session_start', { sessionId: this.cfg.agentId });\n\n // Errors fall into two buckets:\n // 1. `bus.consumeInbound()` itself threw → infrastructure problem; back off\n // exponentially so a flapping bus does not pin the CPU at 100%.\n // 2. `handleInboundMessage(msg)` threw → per-message handler bug. The\n // message is already lost; do NOT sleep, just log and move on so\n // legitimate traffic is not held hostage.\n // Shutdown (`MessageBusShutdownError`) is the only signal that breaks the loop.\n let consecutiveConsumeFailures = 0;\n\n while (this.running) {\n let msg: InboundMessage;\n try {\n msg = await this.cfg.bus.consumeInbound();\n consecutiveConsumeFailures = 0;\n } catch (error) {\n if (error instanceof MessageBusShutdownError) {\n break;\n }\n consecutiveConsumeFailures += 1;\n const delayMs = Math.min(\n INBOUND_CONSUME_MAX_BACKOFF_MS,\n INBOUND_CONSUME_BASE_BACKOFF_MS * 2 ** (consecutiveConsumeFailures - 1),\n );\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'inbound_consume',\n consecutiveFailures: consecutiveConsumeFailures,\n backoffMs: delayMs,\n },\n `Bus consume failed (backing off ${delayMs}ms): ${em}`,\n );\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n continue;\n }\n\n try {\n await this.handleInboundMessage(msg);\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'inbound_handle',\n channel: msg.channel,\n chatId: msg.chat_id,\n },\n `Inbound message handler failed: ${em}`,\n );\n // Per-message failure: keep consuming. The next message is independent.\n }\n }\n\n await this.cfg.hookHandler.trigger('session_end', {\n sessionId: this.cfg.agentId,\n messageCount: 0,\n });\n }\n\n /** Cooperatively stop the loop; the current message (if any) is allowed to finish. */\n stop(): void {\n this.running = false;\n }\n\n private async handleInboundMessage(msg: InboundMessage): Promise<void> {\n const requestId = inboundMessageLogRequestId(msg);\n\n await runWithLogContext({ requestId }, async () => {\n const routing = await this.cfg.messageRouter.routeMessage(msg);\n const { context, isCommand, command, commandArgs } = routing;\n\n const sessionContext: SessionContext = {\n sessionKey: context.sessionKey,\n channel: context.channel,\n chatId: context.chatId,\n senderId: context.senderId || '',\n isGroup: context.isGroup || false,\n metadata: {\n transcribedVoice: msg.metadata?.transcribedVoice === true,\n },\n };\n\n updateAsyncLogContext({ sessionId: sessionContext.sessionKey });\n\n await this.cfg.sessionContextManager.runWith(sessionContext, async () => {\n this.cfg.feedbackCoordinator.setContext(sessionContext);\n\n // `subscribeToSession` requires an Agent instance; without this the first inbound never\n // registers `message_update` streaming (second turn behaved differently).\n this.cfg.agentManager.getOrCreateAgent(sessionContext.sessionKey);\n this.cfg.setupSessionEventHandling(sessionContext.sessionKey);\n\n await this.cfg.sessionLifecycleManager.startSession(sessionContext);\n\n let typingController: ReturnType<OutboundCoordinator['createTypingControllerForInbound']> = null;\n let inboundTurnArmed = false;\n let busProcessFailed: string | undefined;\n\n try {\n if (msg.channel === 'system') {\n await this.handleSystemMessage(msg, sessionContext);\n return;\n }\n\n if (this.channelManagerRef && msg.channel !== 'cli') {\n await this.channelManagerRef.dispatchInboundMessageAction(msg);\n }\n\n if (isCommand && command) {\n const handled = await this.cfg.commandHandler.executeCommand(command, commandArgs || '', {\n sessionKey: sessionContext.sessionKey,\n channel: sessionContext.channel,\n chatId: sessionContext.chatId,\n senderId: sessionContext.senderId,\n isGroup: sessionContext.isGroup,\n inboundMetadata: msg.metadata,\n });\n if (handled) {\n return;\n }\n }\n\n // Continuous typing indicator (renews every 5 seconds); stopped only AFTER outbound.\n typingController = this.cfg.outboundCoordinator.createTypingControllerForInbound(msg);\n typingController?.start();\n\n if (this.channelManagerRef && msg.channel !== 'cli') {\n const meta = msg.metadata as Record<string, unknown> | undefined;\n const streamHandle = this.channelManagerRef.startStream(\n msg.channel,\n msg.chat_id,\n meta?.accountId as string | undefined,\n {\n threadId: meta?.threadId as string | undefined,\n replyToMessageId: meta?.messageId as string | undefined,\n },\n );\n if (streamHandle) {\n this.cfg.setStreamHandle(streamHandle as StreamHandle);\n }\n }\n\n this.cfg.sessionState.beginInboundTurn(sessionContext.sessionKey);\n inboundTurnArmed = true;\n try {\n await this.cfg.agentOrchestrator.process(msg, sessionContext);\n } catch (procErr) {\n busProcessFailed = procErr instanceof Error ? procErr.message : String(procErr);\n throw procErr;\n }\n } finally {\n await this.cfg.sessionLifecycleManager.endSession(sessionContext);\n await this.cfg.streamManager.end();\n try {\n await this.cfg.outboundCoordinator.sendFinalResponse(msg, sessionContext);\n } finally {\n // Clear typing AFTER outbound (incl. TTS); otherwise Weixin shows typing_off before the message.\n await typingController?.stop();\n }\n if (inboundTurnArmed) {\n const meta = msg.metadata as Record<string, unknown> | undefined;\n const assistantPlainText = this.cfg.getLastAssistantPlainText(sessionContext.sessionKey) ?? '';\n try {\n await this.cfg.outboundCoordinator.emitSessionTurnComplete({\n sessionKey: sessionContext.sessionKey,\n channel: sessionContext.channel,\n chatId: sessionContext.chatId,\n inboundUserText: msg.content,\n assistantPlainText,\n aborted: false,\n ...(busProcessFailed !== undefined ? { streamError: busProcessFailed } : {}),\n skipPersistentGoalPostTurn: false,\n outboundMetadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n },\n });\n } catch (turnErr) {\n const em = turnErr instanceof Error ? turnErr.message : String(turnErr);\n this.log.warn(\n { err: turnErr, sessionKey: sessionContext.sessionKey },\n `Session turn complete failed: ${em}`,\n );\n }\n this.cfg.sessionState.endInboundTurn(sessionContext.sessionKey);\n }\n this.cfg.feedbackCoordinator.endTask();\n this.cfg.feedbackCoordinator.clearContext();\n }\n });\n });\n }\n\n private async handleSystemMessage(msg: InboundMessage, context: SessionContext): Promise<void> {\n this.log.debug({ sessionKey: context.sessionKey }, 'Processing system message');\n\n await this.cfg.sessionHydrator.workspace(context.sessionKey);\n await this.cfg.sessionHydrator.model(context.sessionKey);\n\n const messages = await this.cfg.sessionStore.load(context.sessionKey);\n await this.cfg.checkAndCompact(context.sessionKey, messages);\n\n const systemMessage: AgentMessage = {\n role: 'user',\n content: [{ type: 'text', text: `[System: ${msg.sender_id}] ${msg.content}` }],\n timestamp: Date.now(),\n };\n\n try {\n const result = await runEmbeddedTurnForSession({\n sessionKey: context.sessionKey,\n userMessage: systemMessage,\n sessionStore: this.cfg.sessionStore,\n agentManager: this.cfg.agentManager,\n modelManager: this.cfg.modelManager,\n getConfig: this.cfg.getConfig,\n });\n\n const finalContent = result.lastAssistantText ?? this.cfg.getLastAssistantPlainText(context.sessionKey);\n if (finalContent) {\n this.cfg.sessionState.setLastAssistantText(context.sessionKey, finalContent);\n const hookResult = await this.cfg.hookHandler.runMessageSending(\n context.chatId,\n finalContent,\n context.channel,\n );\n if (hookResult.send) {\n await this.cfg.bus.publishOutbound({\n channel: context.channel,\n chat_id: context.chatId,\n content: hookResult.content || finalContent,\n type: 'message',\n });\n }\n }\n this.cfg.enqueueMaybeAutoTitleAfterPersist(context.sessionKey);\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n sessionKey: context.sessionKey,\n channel: context.channel,\n chatId: context.chatId,\n senderId: msg.sender_id,\n },\n `System message handling failed: ${em}`,\n );\n await this.cfg.bus.publishOutbound({\n channel: context.channel,\n chat_id: context.chatId,\n content: '❌ An error occurred while processing the system message.',\n type: 'message',\n });\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inbound-loop.js","names":[],"sources":["../../../../src/agent/inbound/inbound-loop.ts"],"sourcesContent":["/**\n * InboundLoop — owns the bus-driven inbound pipeline.\n *\n * Replaces the previous `AgentService.start()` while-loop, `handleInboundMessage`,\n * and `handleSystemMessage` methods. Everything that \"a message arrives, run the\n * agent turn, publish the reply\" needs is concentrated here; the parent\n * `AgentService` now just constructs the loop with collaborators and forwards\n * start/stop to it.\n *\n * The constructor takes a fairly wide config because handling a single inbound\n * message touches almost every subsystem (router, command handler, lifecycle\n * manager, agent orchestrator, outbound coordinator, session state, etc.). All\n * dependencies are injected so this class is unit-testable and the inbound\n * pipeline can evolve without touching `AgentService`.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { MessageBus, InboundMessage } from '../../infra/bus/index.js';\nimport { MessageBusShutdownError } from '../../infra/bus/index.js';\nimport type { Config } from '../../config/schema.js';\nimport type { ChannelManager } from '../../channels/manager.js';\nimport { runWithLogContext, updateAsyncLogContext } from '../../utils/logger.js';\nimport type { ContextualLogger } from '../../utils/logger/types.js';\n\nimport type { AgentManager } from '../agent-manager.js';\nimport type { AgentOrchestrator } from '../orchestration/index.js';\nimport type { CommandHandler, OutboundCoordinator, StreamManager } from '../messaging/index.js';\nimport type { MessageRouter } from '../messaging/message-router.js';\nimport type { ModelManager } from '../models/index.js';\nimport type {\n SessionContext,\n SessionContextManager,\n SessionHydrator,\n SessionLifecycleManager,\n SessionStateBag,\n} from '../session/index.js';\nimport type { FeedbackCoordinator } from '../feedback/index.js';\nimport type { HookHandler } from '../lifecycle/hook-handler.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { initSessionTurn } from '../../session/init-session-turn.js';\nimport { shouldSkipResetOverlapCommand } from '../../session/reset-triggers.js';\nimport type { StreamHandle } from '../service.types.js';\nimport { runEmbeddedTurnForSession } from '../embedded/run-for-session.js';\nimport { inboundMessageLogRequestId } from '../service-inbound-utils.js';\n\n/** Initial back-off when bus consume fails. Doubles each consecutive failure. */\nconst INBOUND_CONSUME_BASE_BACKOFF_MS = 1_000;\n/** Hard cap on back-off so a long bus outage settles at one retry per 30s. */\nconst INBOUND_CONSUME_MAX_BACKOFF_MS = 30_000;\n\nexport interface InboundLoopConfig {\n log: ContextualLogger;\n agentId: string;\n bus: MessageBus;\n hookHandler: HookHandler;\n messageRouter: MessageRouter;\n commandHandler: CommandHandler;\n sessionContextManager: SessionContextManager;\n feedbackCoordinator: FeedbackCoordinator;\n agentManager: AgentManager;\n sessionLifecycleManager: SessionLifecycleManager;\n agentOrchestrator: AgentOrchestrator;\n outboundCoordinator: OutboundCoordinator;\n streamManager: StreamManager;\n sessionState: SessionStateBag;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n\n /** Register a per-session agent-event subscription (idempotent). */\n setupSessionEventHandling: (sessionKey: string) => void;\n /** Per-session config hydration (workspace + model override) before a turn runs. */\n sessionHydrator: SessionHydrator;\n /** Returns the visible last assistant text used for outbound + persistent-goal hook. */\n getLastAssistantPlainText: (sessionKey: string) => string;\n /** Pre-turn auto-compaction (only used by system messages). */\n checkAndCompact: (sessionKey: string, messages: AgentMessage[]) => Promise<void>;\n /** Fire-and-forget auto-title (no-ops for cron/heartbeat keys). */\n enqueueMaybeAutoTitleAfterPersist: (sessionKey: string) => void;\n /** Effective merged config snapshot. */\n getConfig: () => Config | undefined;\n /** Archive transcript + new session id (freshness / reset trigger rollover). */\n resetSession: (sessionKey: string) => Promise<{ sessionId: string; previousSessionId: string } | null>;\n /** Connect a channel stream handle for partial assistant text rendering. */\n setStreamHandle: (handle: StreamHandle) => void;\n}\n\nexport class InboundLoop {\n private readonly cfg: InboundLoopConfig;\n private readonly log: ContextualLogger;\n private running = false;\n private channelManagerRef: ChannelManager | null = null;\n\n constructor(cfg: InboundLoopConfig) {\n this.cfg = cfg;\n this.log = cfg.log;\n }\n\n setChannelManager(channelManager: ChannelManager | null): void {\n this.channelManagerRef = channelManager;\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n /** Begin consuming inbound messages from the bus until {@link stop} or shutdown. */\n async start(): Promise<void> {\n this.running = true;\n await this.cfg.hookHandler.trigger('session_start', { sessionId: this.cfg.agentId });\n\n // Errors fall into two buckets:\n // 1. `bus.consumeInbound()` itself threw → infrastructure problem; back off\n // exponentially so a flapping bus does not pin the CPU at 100%.\n // 2. `handleInboundMessage(msg)` threw → per-message handler bug. The\n // message is already lost; do NOT sleep, just log and move on so\n // legitimate traffic is not held hostage.\n // Shutdown (`MessageBusShutdownError`) is the only signal that breaks the loop.\n let consecutiveConsumeFailures = 0;\n\n while (this.running) {\n let msg: InboundMessage;\n try {\n msg = await this.cfg.bus.consumeInbound();\n consecutiveConsumeFailures = 0;\n } catch (error) {\n if (error instanceof MessageBusShutdownError) {\n break;\n }\n consecutiveConsumeFailures += 1;\n const delayMs = Math.min(\n INBOUND_CONSUME_MAX_BACKOFF_MS,\n INBOUND_CONSUME_BASE_BACKOFF_MS * 2 ** (consecutiveConsumeFailures - 1),\n );\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'inbound_consume',\n consecutiveFailures: consecutiveConsumeFailures,\n backoffMs: delayMs,\n },\n `Bus consume failed (backing off ${delayMs}ms): ${em}`,\n );\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n continue;\n }\n\n try {\n await this.handleInboundMessage(msg);\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'inbound_handle',\n channel: msg.channel,\n chatId: msg.chat_id,\n },\n `Inbound message handler failed: ${em}`,\n );\n // Per-message failure: keep consuming. The next message is independent.\n }\n }\n\n await this.cfg.hookHandler.trigger('session_end', {\n sessionId: this.cfg.agentId,\n messageCount: 0,\n });\n }\n\n /** Cooperatively stop the loop; the current message (if any) is allowed to finish. */\n stop(): void {\n this.running = false;\n }\n\n private async handleInboundMessage(msg: InboundMessage): Promise<void> {\n const requestId = inboundMessageLogRequestId(msg);\n\n await runWithLogContext({ requestId }, async () => {\n const routing = await this.cfg.messageRouter.routeMessage(msg);\n const { context, isCommand, command, commandArgs } = routing;\n\n const sessionContext: SessionContext = {\n sessionKey: context.sessionKey,\n channel: context.channel,\n chatId: context.chatId,\n senderId: context.senderId || '',\n isGroup: context.isGroup || false,\n metadata: {\n transcribedVoice: msg.metadata?.transcribedVoice === true,\n },\n };\n\n updateAsyncLogContext({ sessionId: sessionContext.sessionKey });\n\n await this.cfg.sessionContextManager.runWith(sessionContext, async () => {\n this.cfg.feedbackCoordinator.setContext(sessionContext);\n\n // `subscribeToSession` requires an Agent instance; without this the first inbound never\n // registers `message_update` streaming (second turn behaved differently).\n this.cfg.agentManager.getOrCreateAgent(sessionContext.sessionKey);\n this.cfg.setupSessionEventHandling(sessionContext.sessionKey);\n\n await this.cfg.sessionLifecycleManager.startSession(sessionContext);\n\n let typingController: ReturnType<OutboundCoordinator['createTypingControllerForInbound']> = null;\n let inboundTurnArmed = false;\n let busProcessFailed: string | undefined;\n let inboundMsg = msg;\n\n try {\n if (msg.channel === 'system') {\n await this.handleSystemMessage(msg, sessionContext);\n return;\n }\n\n if (this.channelManagerRef && msg.channel !== 'cli') {\n await this.channelManagerRef.dispatchInboundMessageAction(msg);\n }\n\n const cfg = this.cfg.getConfig();\n let effectiveContent = msg.content;\n let resetTriggeredAtInit = false;\n\n if (cfg && typeof msg.content === 'string') {\n const turn = await initSessionTurn({\n cfg,\n sessionKey: sessionContext.sessionKey,\n body: msg.content,\n resetSession: (sk) => this.cfg.resetSession(sk),\n });\n resetTriggeredAtInit = turn.resetTriggered;\n\n if (turn.bareReset && turn.ackMessage) {\n await this.cfg.bus.publishOutbound({\n channel: sessionContext.channel,\n chat_id: sessionContext.chatId,\n content: turn.ackMessage,\n type: 'message',\n });\n return;\n }\n\n effectiveContent = turn.bodyStripped;\n }\n\n if (isCommand && command) {\n if (!shouldSkipResetOverlapCommand(command, resetTriggeredAtInit)) {\n const handled = await this.cfg.commandHandler.executeCommand(command, commandArgs || '', {\n sessionKey: sessionContext.sessionKey,\n channel: sessionContext.channel,\n chatId: sessionContext.chatId,\n senderId: sessionContext.senderId,\n isGroup: sessionContext.isGroup,\n inboundMetadata: msg.metadata,\n });\n if (handled) {\n return;\n }\n }\n }\n\n inboundMsg =\n effectiveContent !== msg.content ? { ...msg, content: effectiveContent } : msg;\n\n // Continuous typing indicator (renews every 5 seconds); stopped only AFTER outbound.\n typingController = this.cfg.outboundCoordinator.createTypingControllerForInbound(msg);\n typingController?.start();\n\n if (this.channelManagerRef && msg.channel !== 'cli') {\n const meta = msg.metadata as Record<string, unknown> | undefined;\n const streamHandle = this.channelManagerRef.startStream(\n msg.channel,\n msg.chat_id,\n meta?.accountId as string | undefined,\n {\n threadId: meta?.threadId as string | undefined,\n replyToMessageId: meta?.messageId as string | undefined,\n },\n );\n if (streamHandle) {\n this.cfg.setStreamHandle(streamHandle as StreamHandle);\n }\n }\n\n this.cfg.sessionState.beginInboundTurn(sessionContext.sessionKey);\n inboundTurnArmed = true;\n try {\n await this.cfg.agentOrchestrator.process(inboundMsg, sessionContext);\n } catch (procErr) {\n busProcessFailed = procErr instanceof Error ? procErr.message : String(procErr);\n throw procErr;\n }\n } finally {\n await this.cfg.sessionLifecycleManager.endSession(sessionContext);\n await this.cfg.streamManager.end();\n try {\n await this.cfg.outboundCoordinator.sendFinalResponse(msg, sessionContext);\n } finally {\n // Clear typing AFTER outbound (incl. TTS); otherwise Weixin shows typing_off before the message.\n await typingController?.stop();\n }\n if (inboundTurnArmed) {\n const meta = msg.metadata as Record<string, unknown> | undefined;\n const assistantPlainText = this.cfg.getLastAssistantPlainText(sessionContext.sessionKey) ?? '';\n try {\n await this.cfg.outboundCoordinator.emitSessionTurnComplete({\n sessionKey: sessionContext.sessionKey,\n channel: sessionContext.channel,\n chatId: sessionContext.chatId,\n inboundUserText: inboundMsg.content,\n assistantPlainText,\n aborted: false,\n ...(busProcessFailed !== undefined ? { streamError: busProcessFailed } : {}),\n skipPersistentGoalPostTurn: false,\n outboundMetadata: {\n accountId: meta?.accountId,\n threadId: meta?.threadId,\n },\n });\n } catch (turnErr) {\n const em = turnErr instanceof Error ? turnErr.message : String(turnErr);\n this.log.warn(\n { err: turnErr, sessionKey: sessionContext.sessionKey },\n `Session turn complete failed: ${em}`,\n );\n }\n this.cfg.sessionState.endInboundTurn(sessionContext.sessionKey);\n }\n this.cfg.feedbackCoordinator.endTask();\n this.cfg.feedbackCoordinator.clearContext();\n }\n });\n });\n }\n\n private async handleSystemMessage(msg: InboundMessage, context: SessionContext): Promise<void> {\n this.log.debug({ sessionKey: context.sessionKey }, 'Processing system message');\n\n await this.cfg.sessionHydrator.workspace(context.sessionKey);\n await this.cfg.sessionHydrator.model(context.sessionKey);\n\n const messages = await this.cfg.sessionStore.load(context.sessionKey);\n await this.cfg.checkAndCompact(context.sessionKey, messages);\n\n const systemMessage: AgentMessage = {\n role: 'user',\n content: [{ type: 'text', text: `[System: ${msg.sender_id}] ${msg.content}` }],\n timestamp: Date.now(),\n };\n\n try {\n const result = await runEmbeddedTurnForSession({\n sessionKey: context.sessionKey,\n userMessage: systemMessage,\n sessionStore: this.cfg.sessionStore,\n agentManager: this.cfg.agentManager,\n modelManager: this.cfg.modelManager,\n getConfig: this.cfg.getConfig,\n });\n\n const finalContent = result.lastAssistantText ?? this.cfg.getLastAssistantPlainText(context.sessionKey);\n if (finalContent) {\n this.cfg.sessionState.setLastAssistantText(context.sessionKey, finalContent);\n const hookResult = await this.cfg.hookHandler.runMessageSending(\n context.chatId,\n finalContent,\n context.channel,\n );\n if (hookResult.send) {\n await this.cfg.bus.publishOutbound({\n channel: context.channel,\n chat_id: context.chatId,\n content: hookResult.content || finalContent,\n type: 'message',\n });\n }\n }\n this.cfg.enqueueMaybeAutoTitleAfterPersist(context.sessionKey);\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n this.log.error(\n {\n err: error,\n errorMessage: em,\n sessionKey: context.sessionKey,\n channel: context.channel,\n chatId: context.chatId,\n senderId: msg.sender_id,\n },\n `System message handling failed: ${em}`,\n );\n await this.cfg.bus.publishOutbound({\n channel: context.channel,\n chat_id: context.chatId,\n content: '❌ An error occurred while processing the system message.',\n type: 'message',\n });\n }\n }\n}\n"],"mappings":"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"}
@@ -50,6 +50,10 @@ export interface TurnDispatcherConfig {
50
50
  endDirectRequestContext: () => void;
51
51
  /** Gateway hook fired after assistant text lands on disk (UI refetch). */
52
52
  onSessionTranscriptUpdated?: (sessionKey: string) => void;
53
+ resetSession: (sessionKey: string) => Promise<{
54
+ sessionId: string;
55
+ previousSessionId: string;
56
+ } | null>;
53
57
  }
54
58
  export type DirectAttachment = DirectInboundAttachment;
55
59
  export declare class TurnDispatcher {
@@ -12,7 +12,7 @@ var TurnDispatcher = class {
12
12
  this.log = cfg.log;
13
13
  }
14
14
  /** One-shot direct turn (CLI / embedded TUI). */
15
- processDirect(content, sessionKey = "cli:direct", attachments, thinking) {
15
+ processDirect(content, sessionKey = "agent:main:main", attachments, thinking) {
16
16
  return runProcessDirect(this.buildOneShotDeps(), {
17
17
  content,
18
18
  sessionKey,
@@ -21,7 +21,7 @@ var TurnDispatcher = class {
21
21
  });
22
22
  }
23
23
  /** Streaming direct turn (webchat SSE / CLI streaming). */
24
- async *processDirectStreaming(content, sessionKey = "cli:direct", attachments, thinking, options) {
24
+ async *processDirectStreaming(content, sessionKey = "agent:main:main", attachments, thinking, options) {
25
25
  yield* runProcessDirectStreaming(this.buildStreamingDeps(), {
26
26
  content,
27
27
  sessionKey,
@@ -99,11 +99,12 @@ var TurnDispatcher = class {
99
99
  },
100
100
  maybeEmitWebchatTts: (sk, hadVoice) => maybeEmitWebchatTts({
101
101
  config: c.getConfig(),
102
- agentManager: c.agentManager,
103
102
  sessionStore: c.sessionStore,
103
+ getLastAssistantPlainText: (sessionKey) => c.sessionState.getLastAssistantText(sessionKey) ?? c.agentManager.getLastAssistantContent(sessionKey) ?? "",
104
104
  log: this.log
105
105
  }, sk, hadVoice),
106
- endDirectRequestContext: c.endDirectRequestContext
106
+ endDirectRequestContext: c.endDirectRequestContext,
107
+ resetSession: c.resetSession
107
108
  };
108
109
  }
109
110
  buildOneShotDeps() {
@@ -128,7 +129,8 @@ var TurnDispatcher = class {
128
129
  if (text) c.sessionState.setLastAssistantText(sk, text);
129
130
  c.enqueueMaybeAutoTitleAfterPersist(sk);
130
131
  },
131
- endDirectRequestContext: c.endDirectRequestContext
132
+ endDirectRequestContext: c.endDirectRequestContext,
133
+ resetSession: c.resetSession
132
134
  };
133
135
  }
134
136
  };
@@ -1 +1 @@
1
- {"version":3,"file":"turn-dispatcher.js","names":[],"sources":["../../../../src/agent/inbound/turn-dispatcher.ts"],"sourcesContent":["/**\n * TurnDispatcher — single entry point for direct (non-bus) agent turns.\n *\n * Wraps the two existing direct-turn runners (one-shot and streaming) so the\n * parent `AgentService` no longer carries a pair of huge `createXxxDeps()`\n * factories. The public surface — `processDirect`, `processDirectStreaming`,\n * `steerWebchatSession`, `enqueueWebchatSseEvent`,\n * `notifyWebchatTranscriptAppend` — matches what `AgentService` exposed\n * previously, so callers (gateway, CLI) are unchanged.\n *\n * Like `OutboundCoordinator` and `InboundLoop`, this class accepts a wide\n * dependency bag in its constructor (the direct-turn pipeline touches almost\n * every other subsystem). The win is that AgentService becomes the only place\n * that wires those dependencies together; individual responsibilities now live\n * in their own classes and are unit-testable.\n */\n\nimport type { Config } from '../../config/schema.js';\nimport type { ContextualLogger } from '../../utils/logger/types.js';\n\nimport type { AgentManager } from '../agent-manager.js';\nimport type { CommandHandler } from '../messaging/command-handler.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionConfigStore } from '../../session/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type {\n SessionContext,\n SessionHydrator,\n SessionStateBag,\n} from '../session/index.js';\nimport { queueEmbeddedSteer } from '../embedded/runs.js';\nimport type { InternalAttachmentRoots } from '../../channels/attachments/inbound-persist.js';\nimport {\n buildDirectUserMessageContent,\n type DirectInboundAttachment,\n} from '../service/build-direct-message-content.js';\nimport {\n runProcessDirectStreaming,\n type ProcessDirectStreamingDeps,\n type ProcessDirectStreamingSseEvent,\n} from '../service/process-direct-streaming.js';\nimport {\n runProcessDirect,\n type RunProcessDirectDeps,\n} from '../service/process-direct-one-shot.js';\nimport { maybeEmitWebchatTts } from '../service/webchat-tts.js';\n\nexport interface TurnDispatcherConfig {\n log: ContextualLogger;\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionConfigStore: SessionConfigStore;\n sessionState: SessionStateBag;\n commandHandler: CommandHandler;\n getConfig: () => Config | undefined;\n /** Strict accessor — required for direct-turn paths that must have a config. */\n requireConfig: () => Config;\n parseSessionKey: (sessionKey: string) => { channel: string; chatId: string };\n /** Establish per-session context (also creates the Agent + subscribes to events). */\n initSessionContext: (sessionKey: string, channel: string, chatId: string) => SessionContext;\n /** Per-session config hydration: workspace, model, thinking. */\n sessionHydrator: SessionHydrator;\n attachmentRootsForSession: (sessionKey: string) => InternalAttachmentRoots;\n prepareInboundAttachments: (\n sessionKey: string,\n attachments?: DirectInboundAttachment[],\n ) => Promise<DirectInboundAttachment[] | undefined>;\n enqueueMaybeAutoTitleAfterPersist: (sessionKey: string) => void;\n endDirectRequestContext: () => void;\n /** Gateway hook fired after assistant text lands on disk (UI refetch). */\n onSessionTranscriptUpdated?: (sessionKey: string) => void;\n}\n\nexport type DirectAttachment = DirectInboundAttachment;\n\nexport class TurnDispatcher {\n private readonly cfg: TurnDispatcherConfig;\n private readonly log: ContextualLogger;\n\n constructor(cfg: TurnDispatcherConfig) {\n this.cfg = cfg;\n this.log = cfg.log;\n }\n\n /** One-shot direct turn (CLI / embedded TUI). */\n processDirect(\n content: string,\n sessionKey = 'cli:direct',\n attachments?: DirectAttachment[],\n thinking?: string,\n ): Promise<string> {\n return runProcessDirect(this.buildOneShotDeps(), {\n content,\n sessionKey,\n attachments,\n thinking,\n });\n }\n\n /** Streaming direct turn (webchat SSE / CLI streaming). */\n async *processDirectStreaming(\n content: string,\n sessionKey = 'cli:direct',\n attachments?: DirectAttachment[],\n thinking?: string,\n options?: { signal?: AbortSignal },\n ): AsyncGenerator<ProcessDirectStreamingSseEvent, void, unknown> {\n yield* runProcessDirectStreaming(this.buildStreamingDeps(), {\n content,\n sessionKey,\n attachments,\n thinking,\n signal: options?.signal,\n });\n }\n\n /** Push an out-of-band event into the live webchat stream for a session. */\n enqueueWebchatSseEvent(\n sessionKey: string,\n event: { type: string; [key: string]: unknown },\n ): void {\n const pub = this.cfg.sessionState.getWebchatPublisher(sessionKey);\n if (pub) {\n pub(event);\n }\n }\n\n /** Stream assistant text to live webchat session + notify transcript listeners. */\n notifyWebchatTranscriptAppend(sessionKey: string, assistantText: string): void {\n const trimmed = assistantText.trim();\n if (trimmed) {\n this.enqueueWebchatSseEvent(sessionKey, { type: 'token', content: trimmed });\n }\n this.cfg.onSessionTranscriptUpdated?.(sessionKey);\n }\n\n /**\n * Queue a steering user message into pi-agent's in-flight run (delivered\n * after current tool work, before the next LLM call). See `Agent.steer`\n * in `@earendil-works/pi-agent-core`.\n */\n async steerWebchatSession(sessionKey: string, text: string): Promise<boolean> {\n const trimmed = text.trim();\n if (!trimmed) return false;\n try {\n return await queueEmbeddedSteer(sessionKey, trimmed);\n } catch (err) {\n this.log.warn({ err, sessionKey }, 'steerWebchatSession failed');\n return false;\n }\n }\n\n private buildStreamingDeps(): ProcessDirectStreamingDeps {\n const c = this.cfg;\n return {\n log: this.log,\n parseSessionKey: c.parseSessionKey,\n initDirectStreamingSession: c.initSessionContext,\n registerWebchatSsePublisher: (sk, publisher) =>\n c.sessionState.registerWebchatPublisher(sk, publisher),\n unregisterWebchatSsePublisher: (sk) => c.sessionState.unregisterWebchatPublisher(sk),\n agentManager: c.agentManager,\n hydrateSessionWorkspaceFromStore: (sk) => c.sessionHydrator.workspace(sk),\n hydrateSessionModelFromStore: (sk) => c.sessionHydrator.model(sk),\n sessionStore: c.sessionStore,\n modelManager: c.modelManager,\n applyResolvedThinkingLevel: (sk, t) => c.sessionHydrator.thinking(sk, t),\n getConfig: c.getConfig,\n sessionConfigStore: c.sessionConfigStore,\n attachmentRootsForSession: c.attachmentRootsForSession,\n commandHandler: c.commandHandler,\n prepareInboundAttachments: c.prepareInboundAttachments,\n buildMessageContent: (text, prepared, sk) =>\n buildDirectUserMessageContent({\n content: text,\n attachments: prepared,\n sessionKey: sk,\n config: c.requireConfig(),\n agentManager: c.agentManager,\n modelManager: c.modelManager,\n }),\n recordPersistentGoalStreamOutcome: (sk, o) =>\n c.sessionState.recordPersistentGoalStreamOutcome(sk, o),\n onTurnComplete: (sk, text) => {\n if (text) {\n c.sessionState.setLastAssistantText(sk, text);\n }\n c.enqueueMaybeAutoTitleAfterPersist(sk);\n },\n reloadWebchatTranscript: (sk) => {\n c.onSessionTranscriptUpdated?.(sk);\n },\n maybeEmitWebchatTts: (sk, hadVoice) =>\n maybeEmitWebchatTts(\n {\n config: c.getConfig(),\n agentManager: c.agentManager,\n sessionStore: c.sessionStore,\n log: this.log,\n },\n sk,\n hadVoice,\n ),\n endDirectRequestContext: c.endDirectRequestContext,\n };\n }\n\n private buildOneShotDeps(): RunProcessDirectDeps {\n const c = this.cfg;\n const cfg = c.requireConfig();\n return {\n log: this.log,\n config: cfg,\n parseSessionKey: c.parseSessionKey,\n initSessionContext: (sk, channel, chatId) => {\n void c.initSessionContext(sk, channel, chatId);\n },\n hydrateSessionWorkspaceFromStore: (sk) => c.sessionHydrator.workspace(sk),\n hydrateSessionModelFromStore: (sk) => c.sessionHydrator.model(sk),\n agentManager: c.agentManager,\n sessionStore: c.sessionStore,\n modelManager: c.modelManager,\n applyResolvedThinkingLevel: (sk, t) => c.sessionHydrator.thinking(sk, t),\n prepareInboundAttachments: c.prepareInboundAttachments,\n commandHandler: c.commandHandler,\n onTurnComplete: (sk, text) => {\n if (text) {\n c.sessionState.setLastAssistantText(sk, text);\n }\n c.enqueueMaybeAutoTitleAfterPersist(sk);\n },\n endDirectRequestContext: c.endDirectRequestContext,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"turn-dispatcher.js","names":[],"sources":["../../../../src/agent/inbound/turn-dispatcher.ts"],"sourcesContent":["/**\n * TurnDispatcher — single entry point for direct (non-bus) agent turns.\n *\n * Wraps the two existing direct-turn runners (one-shot and streaming) so the\n * parent `AgentService` no longer carries a pair of huge `createXxxDeps()`\n * factories. The public surface — `processDirect`, `processDirectStreaming`,\n * `steerWebchatSession`, `enqueueWebchatSseEvent`,\n * `notifyWebchatTranscriptAppend` — matches what `AgentService` exposed\n * previously, so callers (gateway, CLI) are unchanged.\n *\n * Like `OutboundCoordinator` and `InboundLoop`, this class accepts a wide\n * dependency bag in its constructor (the direct-turn pipeline touches almost\n * every other subsystem). The win is that AgentService becomes the only place\n * that wires those dependencies together; individual responsibilities now live\n * in their own classes and are unit-testable.\n */\n\nimport type { Config } from '../../config/schema.js';\nimport type { ContextualLogger } from '../../utils/logger/types.js';\n\nimport type { AgentManager } from '../agent-manager.js';\nimport type { CommandHandler } from '../messaging/command-handler.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionConfigStore } from '../../session/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type {\n SessionContext,\n SessionHydrator,\n SessionStateBag,\n} from '../session/index.js';\nimport { queueEmbeddedSteer } from '../embedded/runs.js';\nimport type { InternalAttachmentRoots } from '../../channels/attachments/inbound-persist.js';\nimport {\n buildDirectUserMessageContent,\n type DirectInboundAttachment,\n} from '../service/build-direct-message-content.js';\nimport {\n runProcessDirectStreaming,\n type ProcessDirectStreamingDeps,\n type ProcessDirectStreamingSseEvent,\n} from '../service/process-direct-streaming.js';\nimport {\n runProcessDirect,\n type RunProcessDirectDeps,\n} from '../service/process-direct-one-shot.js';\nimport { maybeEmitWebchatTts } from '../service/webchat-tts.js';\n\nexport interface TurnDispatcherConfig {\n log: ContextualLogger;\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionConfigStore: SessionConfigStore;\n sessionState: SessionStateBag;\n commandHandler: CommandHandler;\n getConfig: () => Config | undefined;\n /** Strict accessor — required for direct-turn paths that must have a config. */\n requireConfig: () => Config;\n parseSessionKey: (sessionKey: string) => { channel: string; chatId: string };\n /** Establish per-session context (also creates the Agent + subscribes to events). */\n initSessionContext: (sessionKey: string, channel: string, chatId: string) => SessionContext;\n /** Per-session config hydration: workspace, model, thinking. */\n sessionHydrator: SessionHydrator;\n attachmentRootsForSession: (sessionKey: string) => InternalAttachmentRoots;\n prepareInboundAttachments: (\n sessionKey: string,\n attachments?: DirectInboundAttachment[],\n ) => Promise<DirectInboundAttachment[] | undefined>;\n enqueueMaybeAutoTitleAfterPersist: (sessionKey: string) => void;\n endDirectRequestContext: () => void;\n /** Gateway hook fired after assistant text lands on disk (UI refetch). */\n onSessionTranscriptUpdated?: (sessionKey: string) => void;\n resetSession: (sessionKey: string) => Promise<{ sessionId: string; previousSessionId: string } | null>;\n}\n\nexport type DirectAttachment = DirectInboundAttachment;\n\nexport class TurnDispatcher {\n private readonly cfg: TurnDispatcherConfig;\n private readonly log: ContextualLogger;\n\n constructor(cfg: TurnDispatcherConfig) {\n this.cfg = cfg;\n this.log = cfg.log;\n }\n\n /** One-shot direct turn (CLI / embedded TUI). */\n processDirect(\n content: string,\n sessionKey = 'agent:main:main',\n attachments?: DirectAttachment[],\n thinking?: string,\n ): Promise<string> {\n return runProcessDirect(this.buildOneShotDeps(), {\n content,\n sessionKey,\n attachments,\n thinking,\n });\n }\n\n /** Streaming direct turn (webchat SSE / CLI streaming). */\n async *processDirectStreaming(\n content: string,\n sessionKey = 'agent:main:main',\n attachments?: DirectAttachment[],\n thinking?: string,\n options?: { signal?: AbortSignal },\n ): AsyncGenerator<ProcessDirectStreamingSseEvent, void, unknown> {\n yield* runProcessDirectStreaming(this.buildStreamingDeps(), {\n content,\n sessionKey,\n attachments,\n thinking,\n signal: options?.signal,\n });\n }\n\n /** Push an out-of-band event into the live webchat stream for a session. */\n enqueueWebchatSseEvent(\n sessionKey: string,\n event: { type: string; [key: string]: unknown },\n ): void {\n const pub = this.cfg.sessionState.getWebchatPublisher(sessionKey);\n if (pub) {\n pub(event);\n }\n }\n\n /** Stream assistant text to live webchat session + notify transcript listeners. */\n notifyWebchatTranscriptAppend(sessionKey: string, assistantText: string): void {\n const trimmed = assistantText.trim();\n if (trimmed) {\n this.enqueueWebchatSseEvent(sessionKey, { type: 'token', content: trimmed });\n }\n this.cfg.onSessionTranscriptUpdated?.(sessionKey);\n }\n\n /**\n * Queue a steering user message into pi-agent's in-flight run (delivered\n * after current tool work, before the next LLM call). See `Agent.steer`\n * in `@earendil-works/pi-agent-core`.\n */\n async steerWebchatSession(sessionKey: string, text: string): Promise<boolean> {\n const trimmed = text.trim();\n if (!trimmed) return false;\n try {\n return await queueEmbeddedSteer(sessionKey, trimmed);\n } catch (err) {\n this.log.warn({ err, sessionKey }, 'steerWebchatSession failed');\n return false;\n }\n }\n\n private buildStreamingDeps(): ProcessDirectStreamingDeps {\n const c = this.cfg;\n return {\n log: this.log,\n parseSessionKey: c.parseSessionKey,\n initDirectStreamingSession: c.initSessionContext,\n registerWebchatSsePublisher: (sk, publisher) =>\n c.sessionState.registerWebchatPublisher(sk, publisher),\n unregisterWebchatSsePublisher: (sk) => c.sessionState.unregisterWebchatPublisher(sk),\n agentManager: c.agentManager,\n hydrateSessionWorkspaceFromStore: (sk) => c.sessionHydrator.workspace(sk),\n hydrateSessionModelFromStore: (sk) => c.sessionHydrator.model(sk),\n sessionStore: c.sessionStore,\n modelManager: c.modelManager,\n applyResolvedThinkingLevel: (sk, t) => c.sessionHydrator.thinking(sk, t),\n getConfig: c.getConfig,\n sessionConfigStore: c.sessionConfigStore,\n attachmentRootsForSession: c.attachmentRootsForSession,\n commandHandler: c.commandHandler,\n prepareInboundAttachments: c.prepareInboundAttachments,\n buildMessageContent: (text, prepared, sk) =>\n buildDirectUserMessageContent({\n content: text,\n attachments: prepared,\n sessionKey: sk,\n config: c.requireConfig(),\n agentManager: c.agentManager,\n modelManager: c.modelManager,\n }),\n recordPersistentGoalStreamOutcome: (sk, o) =>\n c.sessionState.recordPersistentGoalStreamOutcome(sk, o),\n onTurnComplete: (sk, text) => {\n if (text) {\n c.sessionState.setLastAssistantText(sk, text);\n }\n c.enqueueMaybeAutoTitleAfterPersist(sk);\n },\n reloadWebchatTranscript: (sk) => {\n c.onSessionTranscriptUpdated?.(sk);\n },\n maybeEmitWebchatTts: (sk, hadVoice) =>\n maybeEmitWebchatTts(\n {\n config: c.getConfig(),\n sessionStore: c.sessionStore,\n getLastAssistantPlainText: (sessionKey) =>\n c.sessionState.getLastAssistantText(sessionKey) ??\n c.agentManager.getLastAssistantContent(sessionKey) ??\n '',\n log: this.log,\n },\n sk,\n hadVoice,\n ),\n endDirectRequestContext: c.endDirectRequestContext,\n resetSession: c.resetSession,\n };\n }\n\n private buildOneShotDeps(): RunProcessDirectDeps {\n const c = this.cfg;\n const cfg = c.requireConfig();\n return {\n log: this.log,\n config: cfg,\n parseSessionKey: c.parseSessionKey,\n initSessionContext: (sk, channel, chatId) => {\n void c.initSessionContext(sk, channel, chatId);\n },\n hydrateSessionWorkspaceFromStore: (sk) => c.sessionHydrator.workspace(sk),\n hydrateSessionModelFromStore: (sk) => c.sessionHydrator.model(sk),\n agentManager: c.agentManager,\n sessionStore: c.sessionStore,\n modelManager: c.modelManager,\n applyResolvedThinkingLevel: (sk, t) => c.sessionHydrator.thinking(sk, t),\n prepareInboundAttachments: c.prepareInboundAttachments,\n commandHandler: c.commandHandler,\n onTurnComplete: (sk, text) => {\n if (text) {\n c.sessionState.setLastAssistantText(sk, text);\n }\n c.enqueueMaybeAutoTitleAfterPersist(sk);\n },\n endDirectRequestContext: c.endDirectRequestContext,\n resetSession: c.resetSession,\n };\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
4
4
  import { createResponseMessage, createSignalMessage, createTaskMessage } from "./types.js";
5
5
  import { AgentInbox } from "./inbox.js";
6
6
  //#region src/agent/ipc/bus.ts
@@ -1,10 +1,10 @@
1
+ import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
1
2
  import { createLogger } from "../../utils/logger/index.js";
2
3
  import { init_logger } from "../../utils/logger.js";
3
4
  import { init_paths, resolveAgentDir } from "../../config/paths.js";
4
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
5
+ import { mkdir, readFile, readdir, rename } from "fs/promises";
5
6
  import { join } from "path";
6
7
  import { existsSync, watch } from "fs";
7
- import { mkdir, readFile, readdir, rename } from "fs/promises";
8
8
  //#region src/agent/ipc/inbox.ts
9
9
  init_write_file_atomic();
10
10
  init_logger();
@@ -2,8 +2,8 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { init_paths, resolveSocketPath } from "../../config/paths.js";
4
4
  import { isValidIPCMessage } from "./types.js";
5
- import { dirname } from "path";
6
5
  import { mkdir } from "fs/promises";
6
+ import { dirname } from "path";
7
7
  import { Socket, createServer } from "net";
8
8
  //#region src/agent/ipc/socket.ts
9
9
  init_logger();
@@ -1,11 +1,12 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
3
+ import { init_string_coerce, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
4
4
  import { buildSafeToolName, normalizeReservedToolNames } from "./bundle-mcp-names.js";
5
5
  import { setPluginToolMeta } from "./mcp-tool-meta.js";
6
6
  import crypto from "node:crypto";
7
7
  //#region src/agent/mcp/bundle-mcp-materialize.ts
8
8
  init_logger();
9
+ init_string_coerce();
9
10
  const log = createLogger("BundleMcp");
10
11
  function readMaterializedToolDescription(tool) {
11
12
  const raw = tool;
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-mcp-materialize.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-materialize.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport type { AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { AgentTool as AnyAgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Config } from \"../../config/schema.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { setPluginToolMeta } from \"./mcp-tool-meta.js\";\nimport {\n normalizeLowercaseStringOrEmpty,\n normalizeOptionalString,\n} from \"../../utils/string-coerce.js\";\nimport {\n buildSafeToolName,\n normalizeReservedToolNames,\n TOOL_NAME_SEPARATOR,\n} from \"./bundle-mcp-names.js\";\nimport type { BundleMcpToolRuntime, SessionMcpRuntime } from \"./bundle-mcp-types.js\";\n\nexport type McpGatewayToolEntry = {\n name: string;\n shortName: string;\n description: string;\n};\n\nfunction readMaterializedToolDescription(tool: AnyAgentTool): string {\n const raw = tool as { description?: unknown; label?: unknown };\n return (\n normalizeOptionalString(raw.description) ??\n normalizeOptionalString(raw.label) ??\n tool.name\n );\n}\n\nexport function mapBundleMcpToolsForGateway(\n tools: AnyAgentTool[],\n serverId: string,\n): McpGatewayToolEntry[] {\n const prefix = `${serverId.trim()}${TOOL_NAME_SEPARATOR}`;\n return tools\n .filter((tool) => tool.name.startsWith(prefix))\n .map((tool) => ({\n name: tool.name,\n shortName: tool.name.slice(prefix.length),\n description: readMaterializedToolDescription(tool),\n }));\n}\n\nexport async function listBundleMcpServerToolsForGateway(params: {\n workspaceDir: string;\n cfg?: Config;\n serverId: string;\n}): Promise<McpGatewayToolEntry[]> {\n const runtime = await createBundleMcpToolRuntime({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n try {\n return mapBundleMcpToolsForGateway(runtime.tools, params.serverId);\n } finally {\n await runtime.dispose();\n }\n}\n\nfunction toAgentToolResult(params: {\n serverName: string;\n toolName: string;\n result: CallToolResult;\n}): AgentToolResult<unknown> {\n const content = Array.isArray(params.result.content)\n ? (params.result.content as AgentToolResult<unknown>[\"content\"])\n : [];\n const normalizedContent: AgentToolResult<unknown>[\"content\"] =\n content.length > 0\n ? content\n : params.result.structuredContent !== undefined\n ? [\n {\n type: \"text\",\n text: JSON.stringify(params.result.structuredContent, null, 2),\n },\n ]\n : ([\n {\n type: \"text\",\n text: JSON.stringify(\n {\n status: params.result.isError === true ? \"error\" : \"ok\",\n server: params.serverName,\n tool: params.toolName,\n },\n null,\n 2,\n ),\n },\n ] as AgentToolResult<unknown>[\"content\"]);\n const details: Record<string, unknown> = {\n mcpServer: params.serverName,\n mcpTool: params.toolName,\n };\n if (params.result.structuredContent !== undefined) {\n details.structuredContent = params.result.structuredContent;\n }\n if (params.result.isError === true) {\n details.status = \"error\";\n }\n return {\n content: normalizedContent,\n details,\n };\n}\n\nexport async function materializeBundleMcpToolsForRun(params: {\n runtime: SessionMcpRuntime;\n reservedToolNames?: Iterable<string>;\n disposeRuntime?: () => Promise<void>;\n}): Promise<BundleMcpToolRuntime> {\n let disposed = false;\n const releaseLease = params.runtime.acquireLease?.();\n params.runtime.markUsed();\n let catalog;\n try {\n catalog = await params.runtime.getCatalog();\n } catch (error) {\n releaseLease?.();\n throw error;\n }\n const reservedNames = normalizeReservedToolNames(params.reservedToolNames);\n const tools: BundleMcpToolRuntime[\"tools\"] = [];\n const sortedCatalogTools = [...catalog.tools].toSorted((a, b) => {\n const serverOrder = a.safeServerName.localeCompare(b.safeServerName);\n if (serverOrder !== 0) {\n return serverOrder;\n }\n const toolOrder = a.toolName.localeCompare(b.toolName);\n if (toolOrder !== 0) {\n return toolOrder;\n }\n return a.serverName.localeCompare(b.serverName);\n });\n\n for (const tool of sortedCatalogTools) {\n const originalName = tool.toolName.trim();\n if (!originalName) {\n continue;\n }\n const safeToolName = buildSafeToolName({\n serverName: tool.safeServerName,\n toolName: originalName,\n reservedNames,\n });\n if (safeToolName !== `${tool.safeServerName}${TOOL_NAME_SEPARATOR}${originalName}`) {\n log.warn(\n `bundle-mcp: tool \"${tool.toolName}\" from server \"${tool.serverName}\" registered as \"${safeToolName}\" to keep the tool name provider-safe.`,\n );\n }\n reservedNames.add(normalizeLowercaseStringOrEmpty(safeToolName));\n const agentTool = {\n name: safeToolName,\n label: tool.title ?? tool.toolName,\n description: tool.description || tool.title || tool.fallbackDescription,\n parameters: tool.inputSchema,\n execute: async (_toolCallId: string, input: unknown) => {\n params.runtime.markUsed();\n const result = await params.runtime.callTool(tool.serverName, tool.toolName, input);\n return toAgentToolResult({\n serverName: tool.serverName,\n toolName: tool.toolName,\n result,\n });\n },\n } as unknown as AnyAgentTool;\n setPluginToolMeta(agentTool, {\n pluginId: \"bundle-mcp\",\n optional: false,\n });\n tools.push(agentTool);\n }\n\n // Sort tools deterministically by name so the tools block in API requests is stable across\n // turns (defensive — listTools() order is usually stable but not guaranteed).\n // Cannot fix name collisions: collision suffixes above are order-dependent.\n tools.sort((a, b) => a.name.localeCompare(b.name));\n\n return {\n tools,\n dispose: async () => {\n if (disposed) {\n return;\n }\n disposed = true;\n releaseLease?.();\n await params.disposeRuntime?.();\n },\n };\n}\n\nexport async function createBundleMcpToolRuntime(params: {\n workspaceDir: string;\n cfg?: Config;\n reservedToolNames?: Iterable<string>;\n createRuntime?: (params: {\n sessionId: string;\n workspaceDir: string;\n cfg?: Config;\n }) => SessionMcpRuntime;\n}): Promise<BundleMcpToolRuntime> {\n const createRuntime =\n params.createRuntime ?? (await import(\"./bundle-mcp-runtime.js\")).createSessionMcpRuntime;\n const runtime = createRuntime({\n sessionId: `bundle-mcp:${crypto.randomUUID()}`,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n const materialized = await materializeBundleMcpToolsForRun({\n runtime,\n reservedToolNames: params.reservedToolNames,\n disposeRuntime: async () => {\n await runtime.dispose();\n },\n });\n return materialized;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bundle-mcp-materialize.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-materialize.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport type { AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { AgentTool as AnyAgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Config } from \"../../config/schema.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { setPluginToolMeta } from \"./mcp-tool-meta.js\";\nimport {\n normalizeLowercaseStringOrEmpty,\n normalizeOptionalString,\n} from \"../../utils/string-coerce.js\";\nimport {\n buildSafeToolName,\n normalizeReservedToolNames,\n TOOL_NAME_SEPARATOR,\n} from \"./bundle-mcp-names.js\";\nimport type { BundleMcpToolRuntime, SessionMcpRuntime } from \"./bundle-mcp-types.js\";\n\nexport type McpGatewayToolEntry = {\n name: string;\n shortName: string;\n description: string;\n};\n\nfunction readMaterializedToolDescription(tool: AnyAgentTool): string {\n const raw = tool as { description?: unknown; label?: unknown };\n return (\n normalizeOptionalString(raw.description) ??\n normalizeOptionalString(raw.label) ??\n tool.name\n );\n}\n\nexport function mapBundleMcpToolsForGateway(\n tools: AnyAgentTool[],\n serverId: string,\n): McpGatewayToolEntry[] {\n const prefix = `${serverId.trim()}${TOOL_NAME_SEPARATOR}`;\n return tools\n .filter((tool) => tool.name.startsWith(prefix))\n .map((tool) => ({\n name: tool.name,\n shortName: tool.name.slice(prefix.length),\n description: readMaterializedToolDescription(tool),\n }));\n}\n\nexport async function listBundleMcpServerToolsForGateway(params: {\n workspaceDir: string;\n cfg?: Config;\n serverId: string;\n}): Promise<McpGatewayToolEntry[]> {\n const runtime = await createBundleMcpToolRuntime({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n try {\n return mapBundleMcpToolsForGateway(runtime.tools, params.serverId);\n } finally {\n await runtime.dispose();\n }\n}\n\nfunction toAgentToolResult(params: {\n serverName: string;\n toolName: string;\n result: CallToolResult;\n}): AgentToolResult<unknown> {\n const content = Array.isArray(params.result.content)\n ? (params.result.content as AgentToolResult<unknown>[\"content\"])\n : [];\n const normalizedContent: AgentToolResult<unknown>[\"content\"] =\n content.length > 0\n ? content\n : params.result.structuredContent !== undefined\n ? [\n {\n type: \"text\",\n text: JSON.stringify(params.result.structuredContent, null, 2),\n },\n ]\n : ([\n {\n type: \"text\",\n text: JSON.stringify(\n {\n status: params.result.isError === true ? \"error\" : \"ok\",\n server: params.serverName,\n tool: params.toolName,\n },\n null,\n 2,\n ),\n },\n ] as AgentToolResult<unknown>[\"content\"]);\n const details: Record<string, unknown> = {\n mcpServer: params.serverName,\n mcpTool: params.toolName,\n };\n if (params.result.structuredContent !== undefined) {\n details.structuredContent = params.result.structuredContent;\n }\n if (params.result.isError === true) {\n details.status = \"error\";\n }\n return {\n content: normalizedContent,\n details,\n };\n}\n\nexport async function materializeBundleMcpToolsForRun(params: {\n runtime: SessionMcpRuntime;\n reservedToolNames?: Iterable<string>;\n disposeRuntime?: () => Promise<void>;\n}): Promise<BundleMcpToolRuntime> {\n let disposed = false;\n const releaseLease = params.runtime.acquireLease?.();\n params.runtime.markUsed();\n let catalog;\n try {\n catalog = await params.runtime.getCatalog();\n } catch (error) {\n releaseLease?.();\n throw error;\n }\n const reservedNames = normalizeReservedToolNames(params.reservedToolNames);\n const tools: BundleMcpToolRuntime[\"tools\"] = [];\n const sortedCatalogTools = [...catalog.tools].toSorted((a, b) => {\n const serverOrder = a.safeServerName.localeCompare(b.safeServerName);\n if (serverOrder !== 0) {\n return serverOrder;\n }\n const toolOrder = a.toolName.localeCompare(b.toolName);\n if (toolOrder !== 0) {\n return toolOrder;\n }\n return a.serverName.localeCompare(b.serverName);\n });\n\n for (const tool of sortedCatalogTools) {\n const originalName = tool.toolName.trim();\n if (!originalName) {\n continue;\n }\n const safeToolName = buildSafeToolName({\n serverName: tool.safeServerName,\n toolName: originalName,\n reservedNames,\n });\n if (safeToolName !== `${tool.safeServerName}${TOOL_NAME_SEPARATOR}${originalName}`) {\n log.warn(\n `bundle-mcp: tool \"${tool.toolName}\" from server \"${tool.serverName}\" registered as \"${safeToolName}\" to keep the tool name provider-safe.`,\n );\n }\n reservedNames.add(normalizeLowercaseStringOrEmpty(safeToolName));\n const agentTool = {\n name: safeToolName,\n label: tool.title ?? tool.toolName,\n description: tool.description || tool.title || tool.fallbackDescription,\n parameters: tool.inputSchema,\n execute: async (_toolCallId: string, input: unknown) => {\n params.runtime.markUsed();\n const result = await params.runtime.callTool(tool.serverName, tool.toolName, input);\n return toAgentToolResult({\n serverName: tool.serverName,\n toolName: tool.toolName,\n result,\n });\n },\n } as unknown as AnyAgentTool;\n setPluginToolMeta(agentTool, {\n pluginId: \"bundle-mcp\",\n optional: false,\n });\n tools.push(agentTool);\n }\n\n // Sort tools deterministically by name so the tools block in API requests is stable across\n // turns (defensive — listTools() order is usually stable but not guaranteed).\n // Cannot fix name collisions: collision suffixes above are order-dependent.\n tools.sort((a, b) => a.name.localeCompare(b.name));\n\n return {\n tools,\n dispose: async () => {\n if (disposed) {\n return;\n }\n disposed = true;\n releaseLease?.();\n await params.disposeRuntime?.();\n },\n };\n}\n\nexport async function createBundleMcpToolRuntime(params: {\n workspaceDir: string;\n cfg?: Config;\n reservedToolNames?: Iterable<string>;\n createRuntime?: (params: {\n sessionId: string;\n workspaceDir: string;\n cfg?: Config;\n }) => SessionMcpRuntime;\n}): Promise<BundleMcpToolRuntime> {\n const createRuntime =\n params.createRuntime ?? (await import(\"./bundle-mcp-runtime.js\")).createSessionMcpRuntime;\n const runtime = createRuntime({\n sessionId: `bundle-mcp:${crypto.randomUUID()}`,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n const materialized = await materializeBundleMcpToolsForRun({\n runtime,\n reservedToolNames: params.reservedToolNames,\n disposeRuntime: async () => {\n await runtime.dispose();\n },\n });\n return materialized;\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
1
+ import { init_string_coerce, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
2
2
  //#region src/agent/mcp/bundle-mcp-names.ts
3
+ init_string_coerce();
3
4
  function normalizeOptionalLowercaseString(value) {
4
5
  const s = normalizeOptionalString(value);
5
6
  return s ? s.toLowerCase() : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-mcp-names.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-names.ts"],"sourcesContent":["import {\n normalizeLowercaseStringOrEmpty,\n normalizeOptionalString,\n} from '../../utils/string-coerce.js';\n\nfunction normalizeOptionalLowercaseString(value: unknown): string | undefined {\n const s = normalizeOptionalString(value);\n return s ? s.toLowerCase() : undefined;\n}\n\nconst TOOL_NAME_SAFE_RE = /[^A-Za-z0-9_-]/g;\nexport const TOOL_NAME_SEPARATOR = \"__\";\nconst TOOL_NAME_MAX_PREFIX = 30;\nconst TOOL_NAME_MAX_TOTAL = 64;\n\nfunction sanitizeToolFragment(raw: string, fallback: string, maxChars?: number): string {\n const cleaned = raw.trim().replace(TOOL_NAME_SAFE_RE, \"-\");\n const normalized = cleaned || fallback;\n if (!maxChars) {\n return normalized;\n }\n return normalized.length > maxChars ? normalized.slice(0, maxChars) : normalized;\n}\n\nexport function sanitizeServerName(raw: string, usedNames: Set<string>): string {\n const base = sanitizeToolFragment(raw, \"mcp\", TOOL_NAME_MAX_PREFIX);\n let candidate = base;\n let n = 2;\n while (usedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {\n const suffix = `-${n}`;\n candidate = `${base.slice(0, Math.max(1, TOOL_NAME_MAX_PREFIX - suffix.length))}${suffix}`;\n n += 1;\n }\n usedNames.add(normalizeLowercaseStringOrEmpty(candidate));\n return candidate;\n}\n\nexport function sanitizeToolName(raw: string): string {\n return sanitizeToolFragment(raw, \"tool\");\n}\n\nexport function normalizeReservedToolNames(names?: Iterable<string>): Set<string> {\n return new Set(\n Array.from(names ?? [], (name) => normalizeOptionalLowercaseString(name)).filter(\n (name): name is string => Boolean(name),\n ),\n );\n}\n\nexport function buildSafeToolName(params: {\n serverName: string;\n toolName: string;\n reservedNames: Set<string>;\n}): string {\n const cleanedToolName = sanitizeToolName(params.toolName);\n const maxToolChars = Math.max(\n 1,\n TOOL_NAME_MAX_TOTAL - params.serverName.length - TOOL_NAME_SEPARATOR.length,\n );\n const truncatedToolName = cleanedToolName.slice(0, maxToolChars);\n let candidateToolName = truncatedToolName || \"tool\";\n let candidate = `${params.serverName}${TOOL_NAME_SEPARATOR}${candidateToolName}`;\n let n = 2;\n while (params.reservedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {\n const suffix = `-${n}`;\n candidateToolName = `${(truncatedToolName || \"tool\").slice(0, Math.max(1, maxToolChars - suffix.length))}${suffix}`;\n candidate = `${params.serverName}${TOOL_NAME_SEPARATOR}${candidateToolName}`;\n n += 1;\n }\n return candidate;\n}\n"],"mappings":";;AAKA,SAAS,iCAAiC,OAAoC;CAC5E,MAAM,IAAI,wBAAwB,MAAM;AACxC,QAAO,IAAI,EAAE,aAAa,GAAG,KAAA;;AAG/B,MAAM,oBAAoB;AAC1B,MAAa,sBAAsB;AACnC,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAE5B,SAAS,qBAAqB,KAAa,UAAkB,UAA2B;CAEtF,MAAM,aADU,IAAI,MAAM,CAAC,QAAQ,mBAAmB,IAC5B,IAAI;AAC9B,KAAI,CAAC,SACH,QAAO;AAET,QAAO,WAAW,SAAS,WAAW,WAAW,MAAM,GAAG,SAAS,GAAG;;AAGxE,SAAgB,mBAAmB,KAAa,WAAgC;CAC9E,MAAM,OAAO,qBAAqB,KAAK,OAAO,qBAAqB;CACnE,IAAI,YAAY;CAChB,IAAI,IAAI;AACR,QAAO,UAAU,IAAI,gCAAgC,UAAU,CAAC,EAAE;EAChE,MAAM,SAAS,IAAI;AACnB,cAAY,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,uBAAuB,OAAO,OAAO,CAAC,GAAG;AAClF,OAAK;;AAEP,WAAU,IAAI,gCAAgC,UAAU,CAAC;AACzD,QAAO;;AAGT,SAAgB,iBAAiB,KAAqB;AACpD,QAAO,qBAAqB,KAAK,OAAO;;AAG1C,SAAgB,2BAA2B,OAAuC;AAChF,QAAO,IAAI,IACT,MAAM,KAAK,SAAS,EAAE,GAAG,SAAS,iCAAiC,KAAK,CAAC,CAAC,QACvE,SAAyB,QAAQ,KAAK,CACxC,CACF;;AAGH,SAAgB,kBAAkB,QAIvB;CACT,MAAM,kBAAkB,iBAAiB,OAAO,SAAS;CACzD,MAAM,eAAe,KAAK,IACxB,GACA,sBAAsB,OAAO,WAAW,SAAS,EAClD;CACD,MAAM,oBAAoB,gBAAgB,MAAM,GAAG,aAAa;CAChE,IAAI,oBAAoB,qBAAqB;CAC7C,IAAI,YAAY,GAAG,OAAO,eAAmC;CAC7D,IAAI,IAAI;AACR,QAAO,OAAO,cAAc,IAAI,gCAAgC,UAAU,CAAC,EAAE;EAC3E,MAAM,SAAS,IAAI;AACnB,sBAAoB,IAAI,qBAAqB,QAAQ,MAAM,GAAG,KAAK,IAAI,GAAG,eAAe,OAAO,OAAO,CAAC,GAAG;AAC3G,cAAY,GAAG,OAAO,eAAmC;AACzD,OAAK;;AAEP,QAAO"}
1
+ {"version":3,"file":"bundle-mcp-names.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-names.ts"],"sourcesContent":["import {\n normalizeLowercaseStringOrEmpty,\n normalizeOptionalString,\n} from '../../utils/string-coerce.js';\n\nfunction normalizeOptionalLowercaseString(value: unknown): string | undefined {\n const s = normalizeOptionalString(value);\n return s ? s.toLowerCase() : undefined;\n}\n\nconst TOOL_NAME_SAFE_RE = /[^A-Za-z0-9_-]/g;\nexport const TOOL_NAME_SEPARATOR = \"__\";\nconst TOOL_NAME_MAX_PREFIX = 30;\nconst TOOL_NAME_MAX_TOTAL = 64;\n\nfunction sanitizeToolFragment(raw: string, fallback: string, maxChars?: number): string {\n const cleaned = raw.trim().replace(TOOL_NAME_SAFE_RE, \"-\");\n const normalized = cleaned || fallback;\n if (!maxChars) {\n return normalized;\n }\n return normalized.length > maxChars ? normalized.slice(0, maxChars) : normalized;\n}\n\nexport function sanitizeServerName(raw: string, usedNames: Set<string>): string {\n const base = sanitizeToolFragment(raw, \"mcp\", TOOL_NAME_MAX_PREFIX);\n let candidate = base;\n let n = 2;\n while (usedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {\n const suffix = `-${n}`;\n candidate = `${base.slice(0, Math.max(1, TOOL_NAME_MAX_PREFIX - suffix.length))}${suffix}`;\n n += 1;\n }\n usedNames.add(normalizeLowercaseStringOrEmpty(candidate));\n return candidate;\n}\n\nexport function sanitizeToolName(raw: string): string {\n return sanitizeToolFragment(raw, \"tool\");\n}\n\nexport function normalizeReservedToolNames(names?: Iterable<string>): Set<string> {\n return new Set(\n Array.from(names ?? [], (name) => normalizeOptionalLowercaseString(name)).filter(\n (name): name is string => Boolean(name),\n ),\n );\n}\n\nexport function buildSafeToolName(params: {\n serverName: string;\n toolName: string;\n reservedNames: Set<string>;\n}): string {\n const cleanedToolName = sanitizeToolName(params.toolName);\n const maxToolChars = Math.max(\n 1,\n TOOL_NAME_MAX_TOTAL - params.serverName.length - TOOL_NAME_SEPARATOR.length,\n );\n const truncatedToolName = cleanedToolName.slice(0, maxToolChars);\n let candidateToolName = truncatedToolName || \"tool\";\n let candidate = `${params.serverName}${TOOL_NAME_SEPARATOR}${candidateToolName}`;\n let n = 2;\n while (params.reservedNames.has(normalizeLowercaseStringOrEmpty(candidate))) {\n const suffix = `-${n}`;\n candidateToolName = `${(truncatedToolName || \"tool\").slice(0, Math.max(1, maxToolChars - suffix.length))}${suffix}`;\n candidate = `${params.serverName}${TOOL_NAME_SEPARATOR}${candidateToolName}`;\n n += 1;\n }\n return candidate;\n}\n"],"mappings":";;oBAGsC;AAEtC,SAAS,iCAAiC,OAAoC;CAC5E,MAAM,IAAI,wBAAwB,MAAM;AACxC,QAAO,IAAI,EAAE,aAAa,GAAG,KAAA;;AAG/B,MAAM,oBAAoB;AAC1B,MAAa,sBAAsB;AACnC,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAE5B,SAAS,qBAAqB,KAAa,UAAkB,UAA2B;CAEtF,MAAM,aADU,IAAI,MAAM,CAAC,QAAQ,mBAAmB,IAC5B,IAAI;AAC9B,KAAI,CAAC,SACH,QAAO;AAET,QAAO,WAAW,SAAS,WAAW,WAAW,MAAM,GAAG,SAAS,GAAG;;AAGxE,SAAgB,mBAAmB,KAAa,WAAgC;CAC9E,MAAM,OAAO,qBAAqB,KAAK,OAAO,qBAAqB;CACnE,IAAI,YAAY;CAChB,IAAI,IAAI;AACR,QAAO,UAAU,IAAI,gCAAgC,UAAU,CAAC,EAAE;EAChE,MAAM,SAAS,IAAI;AACnB,cAAY,GAAG,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,uBAAuB,OAAO,OAAO,CAAC,GAAG;AAClF,OAAK;;AAEP,WAAU,IAAI,gCAAgC,UAAU,CAAC;AACzD,QAAO;;AAGT,SAAgB,iBAAiB,KAAqB;AACpD,QAAO,qBAAqB,KAAK,OAAO;;AAG1C,SAAgB,2BAA2B,OAAuC;AAChF,QAAO,IAAI,IACT,MAAM,KAAK,SAAS,EAAE,GAAG,SAAS,iCAAiC,KAAK,CAAC,CAAC,QACvE,SAAyB,QAAQ,KAAK,CACxC,CACF;;AAGH,SAAgB,kBAAkB,QAIvB;CACT,MAAM,kBAAkB,iBAAiB,OAAO,SAAS;CACzD,MAAM,eAAe,KAAK,IACxB,GACA,sBAAsB,OAAO,WAAW,SAAS,EAClD;CACD,MAAM,oBAAoB,gBAAgB,MAAM,GAAG,aAAa;CAChE,IAAI,oBAAoB,qBAAqB;CAC7C,IAAI,YAAY,GAAG,OAAO,eAAmC;CAC7D,IAAI,IAAI;AACR,QAAO,OAAO,cAAc,IAAI,gCAAgC,UAAU,CAAC,EAAE;EAC3E,MAAM,SAAS,IAAI;AACnB,sBAAoB,IAAI,qBAAqB,QAAQ,MAAM,GAAG,KAAK,IAAI,GAAG,eAAe,OAAO,OAAO,CAAC,GAAG;AAC3G,cAAY,GAAG,OAAO,eAAmC;AACzD,OAAK;;AAEP,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { normalizeOptionalString } from "../../utils/string-coerce.js";
3
+ import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
4
4
  import { sanitizeServerName } from "./bundle-mcp-names.js";
5
5
  import { resolveGlobalSingleton } from "../../utils/global-singleton.js";
6
6
  import { redactSensitiveUrlLikeString } from "../../utils/redact-sensitive-url.js";
@@ -13,6 +13,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
13
13
  import { AjvJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/ajv-provider.js";
14
14
  //#region src/agent/mcp/bundle-mcp-runtime.ts
15
15
  init_logger();
16
+ init_string_coerce();
16
17
  const log = createLogger("BundleMcp");
17
18
  const require = createRequire(import.meta.url);
18
19
  const SESSION_MCP_RUNTIME_MANAGER_KEY = Symbol.for("xopc.sessionMcpRuntimeManager");
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-mcp-runtime.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-runtime.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { AjvJsonSchemaValidator } from \"@modelcontextprotocol/sdk/validation/ajv-provider.js\";\nimport type {\n JsonSchemaType,\n JsonSchemaValidator,\n jsonSchemaValidator,\n} from \"@modelcontextprotocol/sdk/validation/types.js\";\nimport type { ErrorObject, ValidateFunction } from \"ajv\";\nimport type { Config } from \"../../config/schema.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { resolveGlobalSingleton } from \"../../utils/global-singleton.js\";\nimport { redactSensitiveUrlLikeString } from \"../../utils/redact-sensitive-url.js\";\nimport { normalizeOptionalString } from \"../../utils/string-coerce.js\";\nimport { loadEmbeddedMcpConfig } from \"./embedded-mcp.js\";\nimport { isMcpConfigRecord } from \"./mcp-config-shared.js\";\nimport { resolveMcpTransport } from \"./mcp-transport.js\";\nimport { sanitizeServerName } from \"./bundle-mcp-names.js\";\nimport type {\n McpCatalogTool,\n McpServerCatalog,\n McpToolCatalog,\n SessionMcpRuntime,\n SessionMcpRuntimeManager,\n} from \"./bundle-mcp-types.js\";\n\ntype BundleMcpSession = {\n serverName: string;\n client: Client;\n transport: Transport;\n transportType: \"stdio\" | \"sse\" | \"streamable-http\";\n detachStderr?: () => void;\n};\n\ntype LoadedMcpConfig = ReturnType<typeof loadEmbeddedMcpConfig>;\ntype ListedTool = Awaited<ReturnType<Client[\"listTools\"]>>[\"tools\"][number];\ntype CreateSessionMcpRuntime = (\n params: Parameters<typeof createSessionMcpRuntime>[0] & { configFingerprint?: string },\n) => SessionMcpRuntime;\n\nconst require = createRequire(import.meta.url);\nconst SESSION_MCP_RUNTIME_MANAGER_KEY = Symbol.for(\"xopc.sessionMcpRuntimeManager\");\nconst DRAFT_2020_12_SCHEMA = \"https://json-schema.org/draft/2020-12/schema\";\nconst DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS = 10 * 60 * 1000;\nconst SESSION_MCP_RUNTIME_SWEEP_INTERVAL_MS = 60 * 1000;\n\ntype Ajv2020Like = {\n compile: (schema: JsonSchemaType) => ValidateFunction;\n errorsText: (errors?: ErrorObject[] | null) => string;\n};\n\nfunction isDraft202012Schema(schema: JsonSchemaType): boolean {\n return (schema as { $schema?: unknown }).$schema === DRAFT_2020_12_SCHEMA;\n}\n\nexport function createBundleMcpJsonSchemaValidator(): jsonSchemaValidator {\n const defaultValidator = new AjvJsonSchemaValidator();\n const Ajv2020Ctor = require(\"ajv/dist/2020\") as new (opts?: object) => Ajv2020Like;\n const ajv2020 = new Ajv2020Ctor({\n strict: false,\n validateFormats: false,\n validateSchema: false,\n allErrors: true,\n });\n\n return {\n getValidator<T>(schema: JsonSchemaType): JsonSchemaValidator<T> {\n if (!isDraft202012Schema(schema)) {\n return defaultValidator.getValidator<T>(schema);\n }\n const ajvValidator = ajv2020.compile(schema);\n return (input: unknown) => {\n const valid = ajvValidator(input);\n if (valid) {\n return {\n valid: true,\n data: input as T,\n errorMessage: undefined,\n };\n }\n return {\n valid: false,\n data: undefined,\n errorMessage: ajv2020.errorsText(ajvValidator.errors),\n };\n };\n },\n };\n}\n\nfunction connectWithTimeout(\n client: Client,\n transport: Transport,\n timeoutMs: number,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`MCP server connection timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n client.connect(transport).then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\nfunction redactErrorUrls(error: unknown): string {\n return redactSensitiveUrlLikeString(String(error));\n}\n\nasync function listAllTools(client: Client) {\n const tools: ListedTool[] = [];\n let cursor: string | undefined;\n do {\n const page = await client.listTools(cursor ? { cursor } : undefined);\n tools.push(...page.tools);\n cursor = page.nextCursor;\n } while (cursor);\n return tools;\n}\n\nasync function disposeSession(session: BundleMcpSession) {\n session.detachStderr?.();\n if (session.transportType === \"streamable-http\") {\n await (session.transport as StreamableHTTPClientTransport).terminateSession().catch(() => {});\n }\n await session.transport.close().catch(() => {});\n await session.client.close().catch(() => {});\n}\n\nfunction createCatalogFingerprint(servers: Record<string, unknown>): string {\n return crypto.createHash(\"sha1\").update(JSON.stringify(servers)).digest(\"hex\");\n}\n\nfunction loadSessionMcpConfig(params: {\n workspaceDir: string;\n cfg?: Config;\n logDiagnostics?: boolean;\n}): {\n loaded: LoadedMcpConfig;\n fingerprint: string;\n} {\n const loaded = loadEmbeddedMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n if (params.logDiagnostics !== false) {\n for (const diagnostic of loaded.diagnostics) {\n log.warn(`bundle-mcp: ${diagnostic.extensionId}: ${diagnostic.message}`);\n }\n }\n return {\n loaded,\n fingerprint: createCatalogFingerprint(loaded.mcpServers),\n };\n}\n\nfunction createDisposedError(sessionId: string): Error {\n return new Error(`bundle-mcp runtime disposed for session ${sessionId}`);\n}\n\nfunction resolveSessionMcpRuntimeIdleTtlMs(cfg?: Config): number {\n const raw = cfg?.mcp?.sessionIdleTtlMs;\n if (typeof raw === \"number\" && Number.isFinite(raw) && raw >= 0) {\n return Math.floor(raw);\n }\n return DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS;\n}\n\nexport function createSessionMcpRuntime(params: {\n sessionId: string;\n sessionKey?: string;\n workspaceDir: string;\n cfg?: Config;\n}): SessionMcpRuntime {\n const { loaded, fingerprint: configFingerprint } = loadSessionMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n logDiagnostics: true,\n });\n const createdAt = Date.now();\n let lastUsedAt = createdAt;\n let activeLeases = 0;\n let disposed = false;\n let catalog: McpToolCatalog | null = null;\n let catalogInFlight: Promise<McpToolCatalog> | undefined;\n const sessions = new Map<string, BundleMcpSession>();\n const failIfDisposed = () => {\n if (disposed) {\n throw createDisposedError(params.sessionId);\n }\n };\n\n const getCatalog = async (): Promise<McpToolCatalog> => {\n failIfDisposed();\n if (catalog) {\n return catalog;\n }\n if (catalogInFlight) {\n return catalogInFlight;\n }\n catalogInFlight = (async () => {\n if (Object.keys(loaded.mcpServers).length === 0) {\n return {\n version: 1,\n generatedAt: Date.now(),\n servers: {},\n tools: [],\n };\n }\n\n const servers: Record<string, McpServerCatalog> = {};\n const tools: McpCatalogTool[] = [];\n const usedServerNames = new Set<string>();\n\n try {\n for (const [serverName, rawServer] of Object.entries(loaded.mcpServers)) {\n failIfDisposed();\n const resolved = resolveMcpTransport(serverName, rawServer);\n if (!resolved) {\n continue;\n }\n const safeServerName = sanitizeServerName(serverName, usedServerNames);\n if (safeServerName !== serverName) {\n log.warn(\n `bundle-mcp: server key \"${serverName}\" registered as \"${safeServerName}\" for provider-safe tool names.`,\n );\n }\n\n const client = new Client(\n {\n name: \"xopc-bundle-mcp\",\n version: \"0.0.0\",\n },\n {\n jsonSchemaValidator: createBundleMcpJsonSchemaValidator(),\n },\n );\n const session: BundleMcpSession = {\n serverName,\n client,\n transport: resolved.transport,\n transportType: resolved.transportType,\n detachStderr: resolved.detachStderr,\n };\n sessions.set(serverName, session);\n\n try {\n failIfDisposed();\n await connectWithTimeout(client, resolved.transport, resolved.connectionTimeoutMs);\n failIfDisposed();\n const listedTools = await listAllTools(client);\n failIfDisposed();\n servers[serverName] = {\n serverName,\n launchSummary: resolved.description,\n toolCount: listedTools.length,\n };\n for (const tool of listedTools) {\n const toolName = tool.name.trim();\n if (!toolName) {\n continue;\n }\n tools.push({\n serverName,\n safeServerName,\n toolName,\n title: tool.title,\n description:\n normalizeOptionalString(tool.description) ?? normalizeOptionalString(tool.title),\n inputSchema: tool.inputSchema,\n fallbackDescription: `Provided by bundle MCP server \"${serverName}\" (${resolved.description}).`,\n });\n }\n } catch (error) {\n if (!disposed) {\n log.warn(\n `bundle-mcp: failed to start server \"${serverName}\" (${resolved.description}): ${redactErrorUrls(error)}`,\n );\n }\n await disposeSession(session);\n sessions.delete(serverName);\n failIfDisposed();\n }\n }\n\n failIfDisposed();\n return {\n version: 1,\n generatedAt: Date.now(),\n servers,\n tools,\n };\n } catch (error) {\n await Promise.allSettled(\n Array.from(sessions.values(), (session) => disposeSession(session)),\n );\n sessions.clear();\n throw error;\n }\n })();\n\n try {\n const nextCatalog = await catalogInFlight;\n failIfDisposed();\n catalog = nextCatalog;\n return nextCatalog;\n } finally {\n catalogInFlight = undefined;\n }\n };\n\n return {\n sessionId: params.sessionId,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n configFingerprint,\n createdAt,\n get lastUsedAt() {\n return lastUsedAt;\n },\n get activeLeases() {\n return activeLeases;\n },\n acquireLease() {\n activeLeases += 1;\n let released = false;\n return () => {\n if (released) {\n return;\n }\n released = true;\n activeLeases = Math.max(0, activeLeases - 1);\n lastUsedAt = Date.now();\n };\n },\n getCatalog,\n markUsed() {\n lastUsedAt = Date.now();\n },\n async callTool(serverName, toolName, input) {\n failIfDisposed();\n await getCatalog();\n const session = sessions.get(serverName);\n if (!session) {\n throw new Error(`bundle-mcp server \"${serverName}\" is not connected`);\n }\n return (await session.client.callTool({\n name: toolName,\n arguments: isMcpConfigRecord(input) ? input : {},\n })) as CallToolResult;\n },\n async dispose() {\n if (disposed) {\n return;\n }\n disposed = true;\n catalog = null;\n catalogInFlight = undefined;\n const sessionsToClose = Array.from(sessions.values());\n sessions.clear();\n await Promise.allSettled(sessionsToClose.map((session) => disposeSession(session)));\n },\n };\n}\n\nfunction createSessionMcpRuntimeManager(\n opts: {\n createRuntime?: CreateSessionMcpRuntime;\n now?: () => number;\n enableIdleSweepTimer?: boolean;\n idleSweepIntervalMs?: number;\n } = {},\n): SessionMcpRuntimeManager {\n const runtimesBySessionId = new Map<string, SessionMcpRuntime>();\n const sessionIdBySessionKey = new Map<string, string>();\n const idleTtlMsBySessionId = new Map<string, number>();\n const createRuntime = opts.createRuntime ?? createSessionMcpRuntime;\n const now = opts.now ?? Date.now;\n const createInFlight = new Map<\n string,\n {\n promise: Promise<SessionMcpRuntime>;\n workspaceDir: string;\n configFingerprint: string;\n }\n >();\n const idleSweepIntervalMs = opts.idleSweepIntervalMs ?? SESSION_MCP_RUNTIME_SWEEP_INTERVAL_MS;\n let idleSweepTimer: ReturnType<typeof setInterval> | undefined;\n let idleSweepInFlight: Promise<void> | undefined;\n\n const forgetSessionKeysForSessionId = (sessionId: string) => {\n for (const [sessionKey, mappedSessionId] of sessionIdBySessionKey.entries()) {\n if (mappedSessionId === sessionId) {\n sessionIdBySessionKey.delete(sessionKey);\n }\n }\n };\n\n const sweepIdleRuntimes = async (): Promise<number> => {\n const nowMs = now();\n const expired: SessionMcpRuntime[] = [];\n for (const [sessionId, runtime] of runtimesBySessionId.entries()) {\n const idleTtlMs =\n idleTtlMsBySessionId.get(sessionId) ?? DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS;\n if (idleTtlMs <= 0 || (runtime.activeLeases ?? 0) > 0) {\n continue;\n }\n if (nowMs - runtime.lastUsedAt < idleTtlMs) {\n continue;\n }\n runtimesBySessionId.delete(sessionId);\n idleTtlMsBySessionId.delete(sessionId);\n forgetSessionKeysForSessionId(sessionId);\n expired.push(runtime);\n }\n await Promise.allSettled(expired.map((runtime) => runtime.dispose()));\n return expired.length;\n };\n\n const queueIdleSweep = () => {\n if (idleSweepInFlight) {\n return;\n }\n idleSweepInFlight = sweepIdleRuntimes()\n .then(() => undefined)\n .catch((error: unknown) => {\n log.warn(`bundle-mcp: idle runtime sweep failed: ${String(error)}`);\n })\n .finally(() => {\n idleSweepInFlight = undefined;\n });\n };\n\n const ensureIdleSweepTimer = () => {\n if (opts.enableIdleSweepTimer === false || idleSweepIntervalMs <= 0 || idleSweepTimer) {\n return;\n }\n idleSweepTimer = setInterval(queueIdleSweep, idleSweepIntervalMs);\n idleSweepTimer.unref?.();\n };\n\n const clearIdleSweepTimer = () => {\n if (!idleSweepTimer) {\n return;\n }\n clearInterval(idleSweepTimer);\n idleSweepTimer = undefined;\n };\n\n return {\n async getOrCreate(params) {\n const idleTtlMs = resolveSessionMcpRuntimeIdleTtlMs(params.cfg);\n if (runtimesBySessionId.has(params.sessionId)) {\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n }\n await sweepIdleRuntimes();\n if (idleTtlMs > 0) {\n ensureIdleSweepTimer();\n }\n if (params.sessionKey) {\n sessionIdBySessionKey.set(params.sessionKey, params.sessionId);\n }\n const { fingerprint: nextFingerprint } = loadSessionMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n logDiagnostics: false,\n });\n const existing = runtimesBySessionId.get(params.sessionId);\n if (existing) {\n if (\n existing.workspaceDir !== params.workspaceDir ||\n existing.configFingerprint !== nextFingerprint\n ) {\n runtimesBySessionId.delete(params.sessionId);\n await existing.dispose();\n } else {\n existing.markUsed();\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n return existing;\n }\n }\n const inFlight = createInFlight.get(params.sessionId);\n if (inFlight) {\n if (\n inFlight.workspaceDir === params.workspaceDir &&\n inFlight.configFingerprint === nextFingerprint\n ) {\n return inFlight.promise;\n }\n createInFlight.delete(params.sessionId);\n const staleRuntime = await inFlight.promise.catch(() => undefined);\n runtimesBySessionId.delete(params.sessionId);\n idleTtlMsBySessionId.delete(params.sessionId);\n await staleRuntime?.dispose();\n }\n const created = Promise.resolve(\n createRuntime({\n sessionId: params.sessionId,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n }),\n ).then((runtime) => {\n runtime.markUsed();\n runtimesBySessionId.set(params.sessionId, runtime);\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n return runtime;\n });\n createInFlight.set(params.sessionId, {\n promise: created,\n workspaceDir: params.workspaceDir,\n configFingerprint: nextFingerprint,\n });\n try {\n return await created;\n } finally {\n createInFlight.delete(params.sessionId);\n }\n },\n bindSessionKey(sessionKey, sessionId) {\n sessionIdBySessionKey.set(sessionKey, sessionId);\n },\n resolveSessionId(sessionKey) {\n return sessionIdBySessionKey.get(sessionKey);\n },\n async disposeSession(sessionId) {\n const inFlight = createInFlight.get(sessionId);\n createInFlight.delete(sessionId);\n let runtime = runtimesBySessionId.get(sessionId);\n if (!runtime && inFlight) {\n runtime = await inFlight.promise.catch(() => undefined);\n }\n runtimesBySessionId.delete(sessionId);\n idleTtlMsBySessionId.delete(sessionId);\n if (!runtime) {\n forgetSessionKeysForSessionId(sessionId);\n return;\n }\n forgetSessionKeysForSessionId(sessionId);\n await runtime.dispose();\n },\n async disposeAll() {\n clearIdleSweepTimer();\n const inFlightRuntimes = Array.from(createInFlight.values());\n createInFlight.clear();\n const runtimes = Array.from(runtimesBySessionId.values());\n runtimesBySessionId.clear();\n sessionIdBySessionKey.clear();\n idleTtlMsBySessionId.clear();\n const lateRuntimes = await Promise.all(\n inFlightRuntimes.map(async ({ promise }) => await promise.catch(() => undefined)),\n );\n const allRuntimes = new Set<SessionMcpRuntime>(runtimes);\n for (const runtime of lateRuntimes) {\n if (runtime) {\n allRuntimes.add(runtime);\n }\n }\n await Promise.allSettled(Array.from(allRuntimes, (runtime) => runtime.dispose()));\n },\n sweepIdleRuntimes,\n listSessionIds() {\n return Array.from(runtimesBySessionId.keys());\n },\n };\n}\n\nexport function getSessionMcpRuntimeManager(): SessionMcpRuntimeManager {\n return resolveGlobalSingleton(SESSION_MCP_RUNTIME_MANAGER_KEY, createSessionMcpRuntimeManager);\n}\n\nexport async function getOrCreateSessionMcpRuntime(params: {\n sessionId: string;\n sessionKey?: string;\n workspaceDir: string;\n cfg?: Config;\n}): Promise<SessionMcpRuntime> {\n return await getSessionMcpRuntimeManager().getOrCreate(params);\n}\n\nexport async function disposeSessionMcpRuntime(sessionId: string): Promise<void> {\n await getSessionMcpRuntimeManager().disposeSession(sessionId);\n}\n\nexport async function retireSessionMcpRuntime(params: {\n sessionId?: string | null;\n reason: string;\n onError?: (error: unknown, sessionId: string, reason: string) => void;\n}): Promise<boolean> {\n const sessionId = normalizeOptionalString(params.sessionId);\n if (!sessionId) {\n return false;\n }\n try {\n await disposeSessionMcpRuntime(sessionId);\n return true;\n } catch (error) {\n params.onError?.(error, sessionId, params.reason);\n return false;\n }\n}\n\nexport async function retireSessionMcpRuntimeForSessionKey(params: {\n sessionKey?: string | null;\n reason: string;\n onError?: (error: unknown, sessionId: string, reason: string) => void;\n}): Promise<boolean> {\n const sessionKey = normalizeOptionalString(params.sessionKey);\n if (!sessionKey) {\n return false;\n }\n const sessionId = getSessionMcpRuntimeManager().resolveSessionId(sessionKey);\n return await retireSessionMcpRuntime({\n sessionId,\n reason: params.reason,\n onError: params.onError,\n });\n}\n\nexport async function disposeAllSessionMcpRuntimes(): Promise<void> {\n await getSessionMcpRuntimeManager().disposeAll();\n}\n\nexport const __testing = {\n createSessionMcpRuntimeManager,\n async resetSessionMcpRuntimeManager() {\n await disposeAllSessionMcpRuntimes();\n },\n getCachedSessionIds() {\n return getSessionMcpRuntimeManager().listSessionIds();\n },\n resolveSessionMcpRuntimeIdleTtlMs,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"bundle-mcp-runtime.js","names":[],"sources":["../../../../src/agent/mcp/bundle-mcp-runtime.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { AjvJsonSchemaValidator } from \"@modelcontextprotocol/sdk/validation/ajv-provider.js\";\nimport type {\n JsonSchemaType,\n JsonSchemaValidator,\n jsonSchemaValidator,\n} from \"@modelcontextprotocol/sdk/validation/types.js\";\nimport type { ErrorObject, ValidateFunction } from \"ajv\";\nimport type { Config } from \"../../config/schema.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { resolveGlobalSingleton } from \"../../utils/global-singleton.js\";\nimport { redactSensitiveUrlLikeString } from \"../../utils/redact-sensitive-url.js\";\nimport { normalizeOptionalString } from \"../../utils/string-coerce.js\";\nimport { loadEmbeddedMcpConfig } from \"./embedded-mcp.js\";\nimport { isMcpConfigRecord } from \"./mcp-config-shared.js\";\nimport { resolveMcpTransport } from \"./mcp-transport.js\";\nimport { sanitizeServerName } from \"./bundle-mcp-names.js\";\nimport type {\n McpCatalogTool,\n McpServerCatalog,\n McpToolCatalog,\n SessionMcpRuntime,\n SessionMcpRuntimeManager,\n} from \"./bundle-mcp-types.js\";\n\ntype BundleMcpSession = {\n serverName: string;\n client: Client;\n transport: Transport;\n transportType: \"stdio\" | \"sse\" | \"streamable-http\";\n detachStderr?: () => void;\n};\n\ntype LoadedMcpConfig = ReturnType<typeof loadEmbeddedMcpConfig>;\ntype ListedTool = Awaited<ReturnType<Client[\"listTools\"]>>[\"tools\"][number];\ntype CreateSessionMcpRuntime = (\n params: Parameters<typeof createSessionMcpRuntime>[0] & { configFingerprint?: string },\n) => SessionMcpRuntime;\n\nconst require = createRequire(import.meta.url);\nconst SESSION_MCP_RUNTIME_MANAGER_KEY = Symbol.for(\"xopc.sessionMcpRuntimeManager\");\nconst DRAFT_2020_12_SCHEMA = \"https://json-schema.org/draft/2020-12/schema\";\nconst DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS = 10 * 60 * 1000;\nconst SESSION_MCP_RUNTIME_SWEEP_INTERVAL_MS = 60 * 1000;\n\ntype Ajv2020Like = {\n compile: (schema: JsonSchemaType) => ValidateFunction;\n errorsText: (errors?: ErrorObject[] | null) => string;\n};\n\nfunction isDraft202012Schema(schema: JsonSchemaType): boolean {\n return (schema as { $schema?: unknown }).$schema === DRAFT_2020_12_SCHEMA;\n}\n\nexport function createBundleMcpJsonSchemaValidator(): jsonSchemaValidator {\n const defaultValidator = new AjvJsonSchemaValidator();\n const Ajv2020Ctor = require(\"ajv/dist/2020\") as new (opts?: object) => Ajv2020Like;\n const ajv2020 = new Ajv2020Ctor({\n strict: false,\n validateFormats: false,\n validateSchema: false,\n allErrors: true,\n });\n\n return {\n getValidator<T>(schema: JsonSchemaType): JsonSchemaValidator<T> {\n if (!isDraft202012Schema(schema)) {\n return defaultValidator.getValidator<T>(schema);\n }\n const ajvValidator = ajv2020.compile(schema);\n return (input: unknown) => {\n const valid = ajvValidator(input);\n if (valid) {\n return {\n valid: true,\n data: input as T,\n errorMessage: undefined,\n };\n }\n return {\n valid: false,\n data: undefined,\n errorMessage: ajv2020.errorsText(ajvValidator.errors),\n };\n };\n },\n };\n}\n\nfunction connectWithTimeout(\n client: Client,\n transport: Transport,\n timeoutMs: number,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(`MCP server connection timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n client.connect(transport).then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\nfunction redactErrorUrls(error: unknown): string {\n return redactSensitiveUrlLikeString(String(error));\n}\n\nasync function listAllTools(client: Client) {\n const tools: ListedTool[] = [];\n let cursor: string | undefined;\n do {\n const page = await client.listTools(cursor ? { cursor } : undefined);\n tools.push(...page.tools);\n cursor = page.nextCursor;\n } while (cursor);\n return tools;\n}\n\nasync function disposeSession(session: BundleMcpSession) {\n session.detachStderr?.();\n if (session.transportType === \"streamable-http\") {\n await (session.transport as StreamableHTTPClientTransport).terminateSession().catch(() => {});\n }\n await session.transport.close().catch(() => {});\n await session.client.close().catch(() => {});\n}\n\nfunction createCatalogFingerprint(servers: Record<string, unknown>): string {\n return crypto.createHash(\"sha1\").update(JSON.stringify(servers)).digest(\"hex\");\n}\n\nfunction loadSessionMcpConfig(params: {\n workspaceDir: string;\n cfg?: Config;\n logDiagnostics?: boolean;\n}): {\n loaded: LoadedMcpConfig;\n fingerprint: string;\n} {\n const loaded = loadEmbeddedMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n if (params.logDiagnostics !== false) {\n for (const diagnostic of loaded.diagnostics) {\n log.warn(`bundle-mcp: ${diagnostic.extensionId}: ${diagnostic.message}`);\n }\n }\n return {\n loaded,\n fingerprint: createCatalogFingerprint(loaded.mcpServers),\n };\n}\n\nfunction createDisposedError(sessionId: string): Error {\n return new Error(`bundle-mcp runtime disposed for session ${sessionId}`);\n}\n\nfunction resolveSessionMcpRuntimeIdleTtlMs(cfg?: Config): number {\n const raw = cfg?.mcp?.sessionIdleTtlMs;\n if (typeof raw === \"number\" && Number.isFinite(raw) && raw >= 0) {\n return Math.floor(raw);\n }\n return DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS;\n}\n\nexport function createSessionMcpRuntime(params: {\n sessionId: string;\n sessionKey?: string;\n workspaceDir: string;\n cfg?: Config;\n}): SessionMcpRuntime {\n const { loaded, fingerprint: configFingerprint } = loadSessionMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n logDiagnostics: true,\n });\n const createdAt = Date.now();\n let lastUsedAt = createdAt;\n let activeLeases = 0;\n let disposed = false;\n let catalog: McpToolCatalog | null = null;\n let catalogInFlight: Promise<McpToolCatalog> | undefined;\n const sessions = new Map<string, BundleMcpSession>();\n const failIfDisposed = () => {\n if (disposed) {\n throw createDisposedError(params.sessionId);\n }\n };\n\n const getCatalog = async (): Promise<McpToolCatalog> => {\n failIfDisposed();\n if (catalog) {\n return catalog;\n }\n if (catalogInFlight) {\n return catalogInFlight;\n }\n catalogInFlight = (async () => {\n if (Object.keys(loaded.mcpServers).length === 0) {\n return {\n version: 1,\n generatedAt: Date.now(),\n servers: {},\n tools: [],\n };\n }\n\n const servers: Record<string, McpServerCatalog> = {};\n const tools: McpCatalogTool[] = [];\n const usedServerNames = new Set<string>();\n\n try {\n for (const [serverName, rawServer] of Object.entries(loaded.mcpServers)) {\n failIfDisposed();\n const resolved = resolveMcpTransport(serverName, rawServer);\n if (!resolved) {\n continue;\n }\n const safeServerName = sanitizeServerName(serverName, usedServerNames);\n if (safeServerName !== serverName) {\n log.warn(\n `bundle-mcp: server key \"${serverName}\" registered as \"${safeServerName}\" for provider-safe tool names.`,\n );\n }\n\n const client = new Client(\n {\n name: \"xopc-bundle-mcp\",\n version: \"0.0.0\",\n },\n {\n jsonSchemaValidator: createBundleMcpJsonSchemaValidator(),\n },\n );\n const session: BundleMcpSession = {\n serverName,\n client,\n transport: resolved.transport,\n transportType: resolved.transportType,\n detachStderr: resolved.detachStderr,\n };\n sessions.set(serverName, session);\n\n try {\n failIfDisposed();\n await connectWithTimeout(client, resolved.transport, resolved.connectionTimeoutMs);\n failIfDisposed();\n const listedTools = await listAllTools(client);\n failIfDisposed();\n servers[serverName] = {\n serverName,\n launchSummary: resolved.description,\n toolCount: listedTools.length,\n };\n for (const tool of listedTools) {\n const toolName = tool.name.trim();\n if (!toolName) {\n continue;\n }\n tools.push({\n serverName,\n safeServerName,\n toolName,\n title: tool.title,\n description:\n normalizeOptionalString(tool.description) ?? normalizeOptionalString(tool.title),\n inputSchema: tool.inputSchema,\n fallbackDescription: `Provided by bundle MCP server \"${serverName}\" (${resolved.description}).`,\n });\n }\n } catch (error) {\n if (!disposed) {\n log.warn(\n `bundle-mcp: failed to start server \"${serverName}\" (${resolved.description}): ${redactErrorUrls(error)}`,\n );\n }\n await disposeSession(session);\n sessions.delete(serverName);\n failIfDisposed();\n }\n }\n\n failIfDisposed();\n return {\n version: 1,\n generatedAt: Date.now(),\n servers,\n tools,\n };\n } catch (error) {\n await Promise.allSettled(\n Array.from(sessions.values(), (session) => disposeSession(session)),\n );\n sessions.clear();\n throw error;\n }\n })();\n\n try {\n const nextCatalog = await catalogInFlight;\n failIfDisposed();\n catalog = nextCatalog;\n return nextCatalog;\n } finally {\n catalogInFlight = undefined;\n }\n };\n\n return {\n sessionId: params.sessionId,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n configFingerprint,\n createdAt,\n get lastUsedAt() {\n return lastUsedAt;\n },\n get activeLeases() {\n return activeLeases;\n },\n acquireLease() {\n activeLeases += 1;\n let released = false;\n return () => {\n if (released) {\n return;\n }\n released = true;\n activeLeases = Math.max(0, activeLeases - 1);\n lastUsedAt = Date.now();\n };\n },\n getCatalog,\n markUsed() {\n lastUsedAt = Date.now();\n },\n async callTool(serverName, toolName, input) {\n failIfDisposed();\n await getCatalog();\n const session = sessions.get(serverName);\n if (!session) {\n throw new Error(`bundle-mcp server \"${serverName}\" is not connected`);\n }\n return (await session.client.callTool({\n name: toolName,\n arguments: isMcpConfigRecord(input) ? input : {},\n })) as CallToolResult;\n },\n async dispose() {\n if (disposed) {\n return;\n }\n disposed = true;\n catalog = null;\n catalogInFlight = undefined;\n const sessionsToClose = Array.from(sessions.values());\n sessions.clear();\n await Promise.allSettled(sessionsToClose.map((session) => disposeSession(session)));\n },\n };\n}\n\nfunction createSessionMcpRuntimeManager(\n opts: {\n createRuntime?: CreateSessionMcpRuntime;\n now?: () => number;\n enableIdleSweepTimer?: boolean;\n idleSweepIntervalMs?: number;\n } = {},\n): SessionMcpRuntimeManager {\n const runtimesBySessionId = new Map<string, SessionMcpRuntime>();\n const sessionIdBySessionKey = new Map<string, string>();\n const idleTtlMsBySessionId = new Map<string, number>();\n const createRuntime = opts.createRuntime ?? createSessionMcpRuntime;\n const now = opts.now ?? Date.now;\n const createInFlight = new Map<\n string,\n {\n promise: Promise<SessionMcpRuntime>;\n workspaceDir: string;\n configFingerprint: string;\n }\n >();\n const idleSweepIntervalMs = opts.idleSweepIntervalMs ?? SESSION_MCP_RUNTIME_SWEEP_INTERVAL_MS;\n let idleSweepTimer: ReturnType<typeof setInterval> | undefined;\n let idleSweepInFlight: Promise<void> | undefined;\n\n const forgetSessionKeysForSessionId = (sessionId: string) => {\n for (const [sessionKey, mappedSessionId] of sessionIdBySessionKey.entries()) {\n if (mappedSessionId === sessionId) {\n sessionIdBySessionKey.delete(sessionKey);\n }\n }\n };\n\n const sweepIdleRuntimes = async (): Promise<number> => {\n const nowMs = now();\n const expired: SessionMcpRuntime[] = [];\n for (const [sessionId, runtime] of runtimesBySessionId.entries()) {\n const idleTtlMs =\n idleTtlMsBySessionId.get(sessionId) ?? DEFAULT_SESSION_MCP_RUNTIME_IDLE_TTL_MS;\n if (idleTtlMs <= 0 || (runtime.activeLeases ?? 0) > 0) {\n continue;\n }\n if (nowMs - runtime.lastUsedAt < idleTtlMs) {\n continue;\n }\n runtimesBySessionId.delete(sessionId);\n idleTtlMsBySessionId.delete(sessionId);\n forgetSessionKeysForSessionId(sessionId);\n expired.push(runtime);\n }\n await Promise.allSettled(expired.map((runtime) => runtime.dispose()));\n return expired.length;\n };\n\n const queueIdleSweep = () => {\n if (idleSweepInFlight) {\n return;\n }\n idleSweepInFlight = sweepIdleRuntimes()\n .then(() => undefined)\n .catch((error: unknown) => {\n log.warn(`bundle-mcp: idle runtime sweep failed: ${String(error)}`);\n })\n .finally(() => {\n idleSweepInFlight = undefined;\n });\n };\n\n const ensureIdleSweepTimer = () => {\n if (opts.enableIdleSweepTimer === false || idleSweepIntervalMs <= 0 || idleSweepTimer) {\n return;\n }\n idleSweepTimer = setInterval(queueIdleSweep, idleSweepIntervalMs);\n idleSweepTimer.unref?.();\n };\n\n const clearIdleSweepTimer = () => {\n if (!idleSweepTimer) {\n return;\n }\n clearInterval(idleSweepTimer);\n idleSweepTimer = undefined;\n };\n\n return {\n async getOrCreate(params) {\n const idleTtlMs = resolveSessionMcpRuntimeIdleTtlMs(params.cfg);\n if (runtimesBySessionId.has(params.sessionId)) {\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n }\n await sweepIdleRuntimes();\n if (idleTtlMs > 0) {\n ensureIdleSweepTimer();\n }\n if (params.sessionKey) {\n sessionIdBySessionKey.set(params.sessionKey, params.sessionId);\n }\n const { fingerprint: nextFingerprint } = loadSessionMcpConfig({\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n logDiagnostics: false,\n });\n const existing = runtimesBySessionId.get(params.sessionId);\n if (existing) {\n if (\n existing.workspaceDir !== params.workspaceDir ||\n existing.configFingerprint !== nextFingerprint\n ) {\n runtimesBySessionId.delete(params.sessionId);\n await existing.dispose();\n } else {\n existing.markUsed();\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n return existing;\n }\n }\n const inFlight = createInFlight.get(params.sessionId);\n if (inFlight) {\n if (\n inFlight.workspaceDir === params.workspaceDir &&\n inFlight.configFingerprint === nextFingerprint\n ) {\n return inFlight.promise;\n }\n createInFlight.delete(params.sessionId);\n const staleRuntime = await inFlight.promise.catch(() => undefined);\n runtimesBySessionId.delete(params.sessionId);\n idleTtlMsBySessionId.delete(params.sessionId);\n await staleRuntime?.dispose();\n }\n const created = Promise.resolve(\n createRuntime({\n sessionId: params.sessionId,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n }),\n ).then((runtime) => {\n runtime.markUsed();\n runtimesBySessionId.set(params.sessionId, runtime);\n idleTtlMsBySessionId.set(params.sessionId, idleTtlMs);\n return runtime;\n });\n createInFlight.set(params.sessionId, {\n promise: created,\n workspaceDir: params.workspaceDir,\n configFingerprint: nextFingerprint,\n });\n try {\n return await created;\n } finally {\n createInFlight.delete(params.sessionId);\n }\n },\n bindSessionKey(sessionKey, sessionId) {\n sessionIdBySessionKey.set(sessionKey, sessionId);\n },\n resolveSessionId(sessionKey) {\n return sessionIdBySessionKey.get(sessionKey);\n },\n async disposeSession(sessionId) {\n const inFlight = createInFlight.get(sessionId);\n createInFlight.delete(sessionId);\n let runtime = runtimesBySessionId.get(sessionId);\n if (!runtime && inFlight) {\n runtime = await inFlight.promise.catch(() => undefined);\n }\n runtimesBySessionId.delete(sessionId);\n idleTtlMsBySessionId.delete(sessionId);\n if (!runtime) {\n forgetSessionKeysForSessionId(sessionId);\n return;\n }\n forgetSessionKeysForSessionId(sessionId);\n await runtime.dispose();\n },\n async disposeAll() {\n clearIdleSweepTimer();\n const inFlightRuntimes = Array.from(createInFlight.values());\n createInFlight.clear();\n const runtimes = Array.from(runtimesBySessionId.values());\n runtimesBySessionId.clear();\n sessionIdBySessionKey.clear();\n idleTtlMsBySessionId.clear();\n const lateRuntimes = await Promise.all(\n inFlightRuntimes.map(async ({ promise }) => await promise.catch(() => undefined)),\n );\n const allRuntimes = new Set<SessionMcpRuntime>(runtimes);\n for (const runtime of lateRuntimes) {\n if (runtime) {\n allRuntimes.add(runtime);\n }\n }\n await Promise.allSettled(Array.from(allRuntimes, (runtime) => runtime.dispose()));\n },\n sweepIdleRuntimes,\n listSessionIds() {\n return Array.from(runtimesBySessionId.keys());\n },\n };\n}\n\nexport function getSessionMcpRuntimeManager(): SessionMcpRuntimeManager {\n return resolveGlobalSingleton(SESSION_MCP_RUNTIME_MANAGER_KEY, createSessionMcpRuntimeManager);\n}\n\nexport async function getOrCreateSessionMcpRuntime(params: {\n sessionId: string;\n sessionKey?: string;\n workspaceDir: string;\n cfg?: Config;\n}): Promise<SessionMcpRuntime> {\n return await getSessionMcpRuntimeManager().getOrCreate(params);\n}\n\nexport async function disposeSessionMcpRuntime(sessionId: string): Promise<void> {\n await getSessionMcpRuntimeManager().disposeSession(sessionId);\n}\n\nexport async function retireSessionMcpRuntime(params: {\n sessionId?: string | null;\n reason: string;\n onError?: (error: unknown, sessionId: string, reason: string) => void;\n}): Promise<boolean> {\n const sessionId = normalizeOptionalString(params.sessionId);\n if (!sessionId) {\n return false;\n }\n try {\n await disposeSessionMcpRuntime(sessionId);\n return true;\n } catch (error) {\n params.onError?.(error, sessionId, params.reason);\n return false;\n }\n}\n\nexport async function retireSessionMcpRuntimeForSessionKey(params: {\n sessionKey?: string | null;\n reason: string;\n onError?: (error: unknown, sessionId: string, reason: string) => void;\n}): Promise<boolean> {\n const sessionKey = normalizeOptionalString(params.sessionKey);\n if (!sessionKey) {\n return false;\n }\n const sessionId = getSessionMcpRuntimeManager().resolveSessionId(sessionKey);\n return await retireSessionMcpRuntime({\n sessionId,\n reason: params.reason,\n onError: params.onError,\n });\n}\n\nexport async function disposeAllSessionMcpRuntimes(): Promise<void> {\n await getSessionMcpRuntimeManager().disposeAll();\n}\n\nexport const __testing = {\n createSessionMcpRuntimeManager,\n async resetSessionMcpRuntimeManager() {\n await disposeAllSessionMcpRuntimes();\n },\n getCachedSessionIds() {\n return getSessionMcpRuntimeManager().listSessionIds();\n },\n resolveSessionMcpRuntimeIdleTtlMs,\n};\n"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { normalizeLowercaseStringOrEmpty } from "../../utils/string-coerce.js";
3
+ import { init_string_coerce, normalizeLowercaseStringOrEmpty } from "../../utils/string-coerce.js";
4
4
  import { resolveXopcMcpTransportAlias } from "../../config/mcp-config-normalize.js";
5
5
  import { sanitizeForLog } from "../../utils/sanitize-log.js";
6
6
  import { describeHttpMcpServerLaunchConfig, resolveHttpMcpServerLaunchConfig } from "./mcp-http.js";
7
7
  import { describeStdioMcpServerLaunchConfig, resolveStdioMcpServerLaunchConfig } from "./mcp-stdio.js";
8
8
  //#region src/agent/mcp/mcp-transport-config.ts
9
9
  init_logger();
10
+ init_string_coerce();
10
11
  const log = createLogger("BundleMcp");
11
12
  const DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
12
13
  function getConnectionTimeoutMs(rawServer) {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-transport-config.js","names":[],"sources":["../../../../src/agent/mcp/mcp-transport-config.ts"],"sourcesContent":["import { resolveXopcMcpTransportAlias } from \"../../config/mcp-config-normalize.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { normalizeLowercaseStringOrEmpty } from \"../../utils/string-coerce.js\";\nimport { sanitizeForLog } from \"../../utils/sanitize-log.js\";\nimport {\n describeHttpMcpServerLaunchConfig,\n resolveHttpMcpServerLaunchConfig,\n type HttpMcpTransportType,\n} from \"./mcp-http.js\";\nimport {\n describeStdioMcpServerLaunchConfig,\n resolveStdioMcpServerLaunchConfig,\n} from \"./mcp-stdio.js\";\n\ntype ResolvedBaseMcpTransportConfig = {\n description: string;\n connectionTimeoutMs: number;\n};\n\nexport type ResolvedStdioMcpTransportConfig = ResolvedBaseMcpTransportConfig & {\n kind: \"stdio\";\n transportType: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n};\n\nexport type ResolvedHttpMcpTransportConfig = ResolvedBaseMcpTransportConfig & {\n kind: \"http\";\n transportType: HttpMcpTransportType;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type ResolvedMcpTransportConfig =\n | ResolvedStdioMcpTransportConfig\n | ResolvedHttpMcpTransportConfig;\n\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 30_000;\n\nfunction getConnectionTimeoutMs(rawServer: unknown): number {\n if (\n rawServer &&\n typeof rawServer === \"object\" &&\n typeof (rawServer as { connectionTimeoutMs?: unknown }).connectionTimeoutMs === \"number\" &&\n (rawServer as { connectionTimeoutMs: number }).connectionTimeoutMs > 0\n ) {\n return (rawServer as { connectionTimeoutMs: number }).connectionTimeoutMs;\n }\n return DEFAULT_CONNECTION_TIMEOUT_MS;\n}\n\nfunction getRequestedTransport(rawServer: unknown): string {\n if (\n !rawServer ||\n typeof rawServer !== \"object\" ||\n typeof (rawServer as { transport?: unknown }).transport !== \"string\"\n ) {\n return \"\";\n }\n return normalizeLowercaseStringOrEmpty((rawServer as { transport?: string }).transport);\n}\n\nfunction getRequestedTransportAlias(rawServer: unknown): HttpMcpTransportType | \"\" {\n if (\n !rawServer ||\n typeof rawServer !== \"object\" ||\n typeof (rawServer as { type?: unknown }).type !== \"string\"\n ) {\n return \"\";\n }\n return resolveXopcMcpTransportAlias((rawServer as { type?: string }).type) ?? \"\";\n}\n\nfunction resolveHttpTransportConfig(\n serverName: string,\n rawServer: unknown,\n transportType: HttpMcpTransportType,\n): ResolvedHttpMcpTransportConfig | null {\n const launch = resolveHttpMcpServerLaunchConfig(rawServer, {\n transportType,\n onDroppedHeader: (key) => {\n log.warn(\n `bundle-mcp: server \"${serverName}\": header \"${key}\" has an unsupported value type and was ignored.`,\n );\n },\n onMalformedHeaders: () => {\n log.warn(\n `bundle-mcp: server \"${serverName}\": \"headers\" must be a JSON object; the value was ignored.`,\n );\n },\n });\n if (!launch.ok) {\n return null;\n }\n return {\n kind: \"http\",\n transportType: launch.config.transportType,\n url: launch.config.url,\n headers: launch.config.headers,\n description: describeHttpMcpServerLaunchConfig(launch.config),\n connectionTimeoutMs: getConnectionTimeoutMs(rawServer),\n };\n}\n\nexport function resolveMcpTransportConfig(\n serverName: string,\n rawServer: unknown,\n): ResolvedMcpTransportConfig | null {\n const logServerName = sanitizeForLog(serverName);\n const requestedTransport = getRequestedTransport(rawServer);\n const requestedTransportAlias = requestedTransport ? \"\" : getRequestedTransportAlias(rawServer);\n const effectiveTransport = requestedTransport || requestedTransportAlias;\n const stdioLaunch = resolveStdioMcpServerLaunchConfig(rawServer, {\n onDroppedEnv: (key) => {\n log.warn(\n `bundle-mcp: server \"${logServerName}\": env \"${sanitizeForLog(key)}\" is blocked for stdio startup safety and was ignored.`,\n );\n },\n });\n if (stdioLaunch.ok) {\n return {\n kind: \"stdio\",\n transportType: \"stdio\",\n command: stdioLaunch.config.command,\n args: stdioLaunch.config.args,\n env: stdioLaunch.config.env,\n cwd: stdioLaunch.config.cwd,\n description: describeStdioMcpServerLaunchConfig(stdioLaunch.config),\n connectionTimeoutMs: getConnectionTimeoutMs(rawServer),\n };\n }\n\n if (\n effectiveTransport &&\n effectiveTransport !== \"sse\" &&\n effectiveTransport !== \"streamable-http\"\n ) {\n log.warn(\n `bundle-mcp: skipped server \"${logServerName}\" because transport \"${sanitizeForLog(effectiveTransport)}\" is not supported.`,\n );\n return null;\n }\n\n if (effectiveTransport === \"streamable-http\") {\n const httpTransport = resolveHttpTransportConfig(serverName, rawServer, \"streamable-http\");\n if (httpTransport) {\n return httpTransport;\n }\n }\n\n const sseTransport = resolveHttpTransportConfig(serverName, rawServer, \"sse\");\n if (sseTransport) {\n return sseTransport;\n }\n\n const stdioReason =\n stdioLaunch.ok === false ? stdioLaunch.reason : 'not a stdio server';\n const httpLaunch = resolveHttpMcpServerLaunchConfig(rawServer);\n const httpReason =\n httpLaunch.ok === false ? httpLaunch.reason : 'not an HTTP MCP server';\n log.warn(\n `bundle-mcp: skipped server \"${logServerName}\" because ${stdioReason} and ${httpReason}.`,\n );\n return null;\n}\n"],"mappings":";;;;;;;;aACqD;AACrD,MAAM,MAAM,aAAa,YAAY;AAsCrC,MAAM,gCAAgC;AAEtC,SAAS,uBAAuB,WAA4B;AAC1D,KACE,aACA,OAAO,cAAc,YACrB,OAAQ,UAAgD,wBAAwB,YAC/E,UAA8C,sBAAsB,EAErE,QAAQ,UAA8C;AAExD,QAAO;;AAGT,SAAS,sBAAsB,WAA4B;AACzD,KACE,CAAC,aACD,OAAO,cAAc,YACrB,OAAQ,UAAsC,cAAc,SAE5D,QAAO;AAET,QAAO,gCAAiC,UAAqC,UAAU;;AAGzF,SAAS,2BAA2B,WAA+C;AACjF,KACE,CAAC,aACD,OAAO,cAAc,YACrB,OAAQ,UAAiC,SAAS,SAElD,QAAO;AAET,QAAO,6BAA8B,UAAgC,KAAK,IAAI;;AAGhF,SAAS,2BACP,YACA,WACA,eACuC;CACvC,MAAM,SAAS,iCAAiC,WAAW;EACzD;EACA,kBAAkB,QAAQ;AACxB,OAAI,KACF,uBAAuB,WAAW,aAAa,IAAI,kDACpD;;EAEH,0BAA0B;AACxB,OAAI,KACF,uBAAuB,WAAW,4DACnC;;EAEJ,CAAC;AACF,KAAI,CAAC,OAAO,GACV,QAAO;AAET,QAAO;EACL,MAAM;EACN,eAAe,OAAO,OAAO;EAC7B,KAAK,OAAO,OAAO;EACnB,SAAS,OAAO,OAAO;EACvB,aAAa,kCAAkC,OAAO,OAAO;EAC7D,qBAAqB,uBAAuB,UAAU;EACvD;;AAGH,SAAgB,0BACd,YACA,WACmC;CACnC,MAAM,gBAAgB,eAAe,WAAW;CAChD,MAAM,qBAAqB,sBAAsB,UAAU;CAC3D,MAAM,0BAA0B,qBAAqB,KAAK,2BAA2B,UAAU;CAC/F,MAAM,qBAAqB,sBAAsB;CACjD,MAAM,cAAc,kCAAkC,WAAW,EAC/D,eAAe,QAAQ;AACrB,MAAI,KACF,uBAAuB,cAAc,UAAU,eAAe,IAAI,CAAC,wDACpE;IAEJ,CAAC;AACF,KAAI,YAAY,GACd,QAAO;EACL,MAAM;EACN,eAAe;EACf,SAAS,YAAY,OAAO;EAC5B,MAAM,YAAY,OAAO;EACzB,KAAK,YAAY,OAAO;EACxB,KAAK,YAAY,OAAO;EACxB,aAAa,mCAAmC,YAAY,OAAO;EACnE,qBAAqB,uBAAuB,UAAU;EACvD;AAGH,KACE,sBACA,uBAAuB,SACvB,uBAAuB,mBACvB;AACA,MAAI,KACF,+BAA+B,cAAc,uBAAuB,eAAe,mBAAmB,CAAC,qBACxG;AACD,SAAO;;AAGT,KAAI,uBAAuB,mBAAmB;EAC5C,MAAM,gBAAgB,2BAA2B,YAAY,WAAW,kBAAkB;AAC1F,MAAI,cACF,QAAO;;CAIX,MAAM,eAAe,2BAA2B,YAAY,WAAW,MAAM;AAC7E,KAAI,aACF,QAAO;CAGT,MAAM,cACJ,YAAY,OAAO,QAAQ,YAAY,SAAS;CAClD,MAAM,aAAa,iCAAiC,UAAU;CAC9D,MAAM,aACJ,WAAW,OAAO,QAAQ,WAAW,SAAS;AAChD,KAAI,KACF,+BAA+B,cAAc,YAAY,YAAY,OAAO,WAAW,GACxF;AACD,QAAO"}
1
+ {"version":3,"file":"mcp-transport-config.js","names":[],"sources":["../../../../src/agent/mcp/mcp-transport-config.ts"],"sourcesContent":["import { resolveXopcMcpTransportAlias } from \"../../config/mcp-config-normalize.js\";\nimport { createLogger } from \"../../utils/logger.js\";\nconst log = createLogger(\"BundleMcp\");\nimport { normalizeLowercaseStringOrEmpty } from \"../../utils/string-coerce.js\";\nimport { sanitizeForLog } from \"../../utils/sanitize-log.js\";\nimport {\n describeHttpMcpServerLaunchConfig,\n resolveHttpMcpServerLaunchConfig,\n type HttpMcpTransportType,\n} from \"./mcp-http.js\";\nimport {\n describeStdioMcpServerLaunchConfig,\n resolveStdioMcpServerLaunchConfig,\n} from \"./mcp-stdio.js\";\n\ntype ResolvedBaseMcpTransportConfig = {\n description: string;\n connectionTimeoutMs: number;\n};\n\nexport type ResolvedStdioMcpTransportConfig = ResolvedBaseMcpTransportConfig & {\n kind: \"stdio\";\n transportType: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n};\n\nexport type ResolvedHttpMcpTransportConfig = ResolvedBaseMcpTransportConfig & {\n kind: \"http\";\n transportType: HttpMcpTransportType;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type ResolvedMcpTransportConfig =\n | ResolvedStdioMcpTransportConfig\n | ResolvedHttpMcpTransportConfig;\n\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 30_000;\n\nfunction getConnectionTimeoutMs(rawServer: unknown): number {\n if (\n rawServer &&\n typeof rawServer === \"object\" &&\n typeof (rawServer as { connectionTimeoutMs?: unknown }).connectionTimeoutMs === \"number\" &&\n (rawServer as { connectionTimeoutMs: number }).connectionTimeoutMs > 0\n ) {\n return (rawServer as { connectionTimeoutMs: number }).connectionTimeoutMs;\n }\n return DEFAULT_CONNECTION_TIMEOUT_MS;\n}\n\nfunction getRequestedTransport(rawServer: unknown): string {\n if (\n !rawServer ||\n typeof rawServer !== \"object\" ||\n typeof (rawServer as { transport?: unknown }).transport !== \"string\"\n ) {\n return \"\";\n }\n return normalizeLowercaseStringOrEmpty((rawServer as { transport?: string }).transport);\n}\n\nfunction getRequestedTransportAlias(rawServer: unknown): HttpMcpTransportType | \"\" {\n if (\n !rawServer ||\n typeof rawServer !== \"object\" ||\n typeof (rawServer as { type?: unknown }).type !== \"string\"\n ) {\n return \"\";\n }\n return resolveXopcMcpTransportAlias((rawServer as { type?: string }).type) ?? \"\";\n}\n\nfunction resolveHttpTransportConfig(\n serverName: string,\n rawServer: unknown,\n transportType: HttpMcpTransportType,\n): ResolvedHttpMcpTransportConfig | null {\n const launch = resolveHttpMcpServerLaunchConfig(rawServer, {\n transportType,\n onDroppedHeader: (key) => {\n log.warn(\n `bundle-mcp: server \"${serverName}\": header \"${key}\" has an unsupported value type and was ignored.`,\n );\n },\n onMalformedHeaders: () => {\n log.warn(\n `bundle-mcp: server \"${serverName}\": \"headers\" must be a JSON object; the value was ignored.`,\n );\n },\n });\n if (!launch.ok) {\n return null;\n }\n return {\n kind: \"http\",\n transportType: launch.config.transportType,\n url: launch.config.url,\n headers: launch.config.headers,\n description: describeHttpMcpServerLaunchConfig(launch.config),\n connectionTimeoutMs: getConnectionTimeoutMs(rawServer),\n };\n}\n\nexport function resolveMcpTransportConfig(\n serverName: string,\n rawServer: unknown,\n): ResolvedMcpTransportConfig | null {\n const logServerName = sanitizeForLog(serverName);\n const requestedTransport = getRequestedTransport(rawServer);\n const requestedTransportAlias = requestedTransport ? \"\" : getRequestedTransportAlias(rawServer);\n const effectiveTransport = requestedTransport || requestedTransportAlias;\n const stdioLaunch = resolveStdioMcpServerLaunchConfig(rawServer, {\n onDroppedEnv: (key) => {\n log.warn(\n `bundle-mcp: server \"${logServerName}\": env \"${sanitizeForLog(key)}\" is blocked for stdio startup safety and was ignored.`,\n );\n },\n });\n if (stdioLaunch.ok) {\n return {\n kind: \"stdio\",\n transportType: \"stdio\",\n command: stdioLaunch.config.command,\n args: stdioLaunch.config.args,\n env: stdioLaunch.config.env,\n cwd: stdioLaunch.config.cwd,\n description: describeStdioMcpServerLaunchConfig(stdioLaunch.config),\n connectionTimeoutMs: getConnectionTimeoutMs(rawServer),\n };\n }\n\n if (\n effectiveTransport &&\n effectiveTransport !== \"sse\" &&\n effectiveTransport !== \"streamable-http\"\n ) {\n log.warn(\n `bundle-mcp: skipped server \"${logServerName}\" because transport \"${sanitizeForLog(effectiveTransport)}\" is not supported.`,\n );\n return null;\n }\n\n if (effectiveTransport === \"streamable-http\") {\n const httpTransport = resolveHttpTransportConfig(serverName, rawServer, \"streamable-http\");\n if (httpTransport) {\n return httpTransport;\n }\n }\n\n const sseTransport = resolveHttpTransportConfig(serverName, rawServer, \"sse\");\n if (sseTransport) {\n return sseTransport;\n }\n\n const stdioReason =\n stdioLaunch.ok === false ? stdioLaunch.reason : 'not a stdio server';\n const httpLaunch = resolveHttpMcpServerLaunchConfig(rawServer);\n const httpReason =\n httpLaunch.ok === false ? httpLaunch.reason : 'not an HTTP MCP server';\n log.warn(\n `bundle-mcp: skipped server \"${logServerName}\" because ${stdioReason} and ${httpReason}.`,\n );\n return null;\n}\n"],"mappings":";;;;;;;;aACqD;oBAE0B;AAD/E,MAAM,MAAM,aAAa,YAAY;AAsCrC,MAAM,gCAAgC;AAEtC,SAAS,uBAAuB,WAA4B;AAC1D,KACE,aACA,OAAO,cAAc,YACrB,OAAQ,UAAgD,wBAAwB,YAC/E,UAA8C,sBAAsB,EAErE,QAAQ,UAA8C;AAExD,QAAO;;AAGT,SAAS,sBAAsB,WAA4B;AACzD,KACE,CAAC,aACD,OAAO,cAAc,YACrB,OAAQ,UAAsC,cAAc,SAE5D,QAAO;AAET,QAAO,gCAAiC,UAAqC,UAAU;;AAGzF,SAAS,2BAA2B,WAA+C;AACjF,KACE,CAAC,aACD,OAAO,cAAc,YACrB,OAAQ,UAAiC,SAAS,SAElD,QAAO;AAET,QAAO,6BAA8B,UAAgC,KAAK,IAAI;;AAGhF,SAAS,2BACP,YACA,WACA,eACuC;CACvC,MAAM,SAAS,iCAAiC,WAAW;EACzD;EACA,kBAAkB,QAAQ;AACxB,OAAI,KACF,uBAAuB,WAAW,aAAa,IAAI,kDACpD;;EAEH,0BAA0B;AACxB,OAAI,KACF,uBAAuB,WAAW,4DACnC;;EAEJ,CAAC;AACF,KAAI,CAAC,OAAO,GACV,QAAO;AAET,QAAO;EACL,MAAM;EACN,eAAe,OAAO,OAAO;EAC7B,KAAK,OAAO,OAAO;EACnB,SAAS,OAAO,OAAO;EACvB,aAAa,kCAAkC,OAAO,OAAO;EAC7D,qBAAqB,uBAAuB,UAAU;EACvD;;AAGH,SAAgB,0BACd,YACA,WACmC;CACnC,MAAM,gBAAgB,eAAe,WAAW;CAChD,MAAM,qBAAqB,sBAAsB,UAAU;CAC3D,MAAM,0BAA0B,qBAAqB,KAAK,2BAA2B,UAAU;CAC/F,MAAM,qBAAqB,sBAAsB;CACjD,MAAM,cAAc,kCAAkC,WAAW,EAC/D,eAAe,QAAQ;AACrB,MAAI,KACF,uBAAuB,cAAc,UAAU,eAAe,IAAI,CAAC,wDACpE;IAEJ,CAAC;AACF,KAAI,YAAY,GACd,QAAO;EACL,MAAM;EACN,eAAe;EACf,SAAS,YAAY,OAAO;EAC5B,MAAM,YAAY,OAAO;EACzB,KAAK,YAAY,OAAO;EACxB,KAAK,YAAY,OAAO;EACxB,aAAa,mCAAmC,YAAY,OAAO;EACnE,qBAAqB,uBAAuB,UAAU;EACvD;AAGH,KACE,sBACA,uBAAuB,SACvB,uBAAuB,mBACvB;AACA,MAAI,KACF,+BAA+B,cAAc,uBAAuB,eAAe,mBAAmB,CAAC,qBACxG;AACD,SAAO;;AAGT,KAAI,uBAAuB,mBAAmB;EAC5C,MAAM,gBAAgB,2BAA2B,YAAY,WAAW,kBAAkB;AAC1F,MAAI,cACF,QAAO;;CAIX,MAAM,eAAe,2BAA2B,YAAY,WAAW,MAAM;AAC7E,KAAI,aACF,QAAO;CAGT,MAAM,cACJ,YAAY,OAAO,QAAQ,YAAY,SAAS;CAClD,MAAM,aAAa,iCAAiC,UAAU;CAC9D,MAAM,aACJ,WAAW,OAAO,QAAQ,WAAW,SAAS;AAChD,KAAI,KACF,+BAA+B,cAAc,YAAY,YAAY,OAAO,WAAW,GACxF;AACD,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { normalizeOptionalString } from "../../utils/string-coerce.js";
3
+ import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
4
4
  import { XopcStdioClientTransport } from "./mcp-stdio-transport.js";
5
5
  import { resolveMcpTransportConfig } from "./mcp-transport-config.js";
6
6
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -8,6 +8,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
8
8
  import { fetch } from "undici";
9
9
  //#region src/agent/mcp/mcp-transport.ts
10
10
  init_logger();
11
+ init_string_coerce();
11
12
  const log = createLogger("McpTransport");
12
13
  function attachStderrLogging(serverName, transport) {
13
14
  const stderr = transport.stderr;