@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":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner } from './types.js';\n\nconst log = createLogger('workflow-subagent-runner');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n };\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary } = await handle.run();\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner, SubagentProgressEvent } from './types.js';\n\nconst log = createLogger('workflow-subagent-runner');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n const streamMode = resolveSubagentStreamMode(this.deps.getConfig);\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n progressHooks:\n opts.onProgress && streamMode !== 'off'\n ? {\n mode: streamMode === 'full' ? 'full' : 'steps',\n onProgress: (event) => {\n opts.onProgress?.(mapChildProgressEvent(event));\n },\n }\n : undefined,\n };\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary } = await handle.run();\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n\nfunction resolveSubagentStreamMode(\n getConfig: () => Config | undefined,\n): 'off' | 'steps' | 'full' {\n const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;\n if (mode === 'off' || mode === 'steps' || mode === 'full') return mode;\n return 'steps';\n}\n\nfunction mapChildProgressEvent(event: {\n type: 'tool_start' | 'tool_end' | 'iteration' | 'text_delta' | 'thinking_delta';\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n isError?: boolean;\n count?: number;\n max?: number;\n delta?: string;\n}): SubagentProgressEvent {\n switch (event.type) {\n case 'tool_start':\n return {\n type: 'tool_start',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n args: event.args ?? {},\n };\n case 'tool_end':\n return {\n type: 'tool_end',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n isError: Boolean(event.isError),\n };\n case 'iteration':\n return {\n type: 'iteration',\n count: event.count ?? 0,\n max: event.max ?? 0,\n };\n case 'text_delta':\n return { type: 'text_delta', delta: event.delta ?? '' };\n case 'thinking_delta':\n return { type: 'thinking_delta', delta: event.delta ?? '' };\n default:\n return { type: 'text_delta', delta: '' };\n }\n}\n"],"mappings":"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"}
@@ -22,12 +22,24 @@ export interface JsonSchema {
22
22
  export interface WorkflowMetaPhase {
23
23
  title: string;
24
24
  detail?: string;
25
+ /** Default model for this phase: `provider/model` or configured typed id. */
25
26
  model?: string;
26
27
  }
27
28
  export interface WorkflowMetaEstimatedAgents {
28
29
  min: number;
29
30
  max: number;
30
31
  }
32
+ /** One-click starter text in the gateway start dialog; `field` is `goal` or an `args` key. */
33
+ export interface WorkflowMetaExamplePrompt {
34
+ field: string;
35
+ text: string;
36
+ }
37
+ /** Locale-specific copy overrides; top-level `description` / `whenToUse` / `examplePrompts` are English defaults. */
38
+ export interface WorkflowMetaLocale {
39
+ description?: string;
40
+ whenToUse?: string;
41
+ examplePrompts?: WorkflowMetaExamplePrompt[];
42
+ }
31
43
  export interface WorkflowMeta {
32
44
  name: string;
33
45
  description: string;
@@ -37,8 +49,24 @@ export interface WorkflowMeta {
37
49
  tags?: string[];
38
50
  /** Rough subagent count range for UX / cost hints. */
39
51
  estimatedAgents?: WorkflowMetaEstimatedAgents;
52
+ /** English-default example prompts for the gateway start dialog. */
53
+ examplePrompts?: WorkflowMetaExamplePrompt[];
54
+ /** Non-English locale bundles keyed by BCP-47 language tag (e.g. `zh`). */
55
+ i18n?: Record<string, WorkflowMetaLocale>;
40
56
  }
41
57
  export type WorkflowAgentStatus = 'queued' | 'running' | 'done' | 'error' | 'skipped';
58
+ export type WorkflowAgentStepStatus = 'running' | 'done' | 'error';
59
+ export interface WorkflowAgentStep {
60
+ id: string;
61
+ kind: 'tool' | 'llm' | 'thinking';
62
+ /** Original tool name when `kind === 'tool'` (for chat UI reuse). */
63
+ toolName?: string;
64
+ label: string;
65
+ detail?: string;
66
+ status: WorkflowAgentStepStatus;
67
+ startedAtMs?: number;
68
+ durationMs?: number;
69
+ }
42
70
  export interface WorkflowAgentSnapshot {
43
71
  id: number;
44
72
  label: string;
@@ -47,6 +75,15 @@ export interface WorkflowAgentSnapshot {
47
75
  status: WorkflowAgentStatus;
48
76
  resultPreview?: string;
49
77
  error?: string;
78
+ startedAtMs?: number;
79
+ durationMs?: number;
80
+ steps?: WorkflowAgentStep[];
81
+ /** One-line summary for inline agent rows. */
82
+ currentStep?: string;
83
+ iteration?: number;
84
+ maxIterations?: number;
85
+ /** Accumulated assistant/thinking text when subagentStream is `full`. */
86
+ streamText?: string;
50
87
  }
51
88
  export interface WorkflowSnapshot {
52
89
  name: string;
@@ -79,12 +116,35 @@ export interface SubagentRunOptions<T = unknown> {
79
116
  rethrow?: boolean;
80
117
  /** Hint about which phase this agent belongs to (passed through for logging). */
81
118
  phase?: string;
119
+ /** Live progress from the child agent loop (workflow tool binds per agent id). */
120
+ onProgress?: (event: SubagentProgressEvent) => void;
82
121
  /** Pre-bound capture for structured output (internal: created by the adapter when schema present). */
83
122
  __capture?: {
84
123
  called: boolean;
85
124
  value?: T;
86
125
  };
87
126
  }
127
+ export type SubagentProgressEvent = {
128
+ type: 'tool_start';
129
+ toolCallId: string;
130
+ toolName: string;
131
+ args: Record<string, unknown>;
132
+ } | {
133
+ type: 'tool_end';
134
+ toolCallId: string;
135
+ toolName: string;
136
+ isError: boolean;
137
+ } | {
138
+ type: 'iteration';
139
+ count: number;
140
+ max: number;
141
+ } | {
142
+ type: 'text_delta';
143
+ delta: string;
144
+ } | {
145
+ type: 'thinking_delta';
146
+ delta: string;
147
+ };
88
148
  /**
89
149
  * Spawns a single fresh subagent and returns its result.
90
150
  *
@@ -102,7 +162,9 @@ export interface AgentScriptOptions {
102
162
  label?: string;
103
163
  phase?: string;
104
164
  schema?: JsonSchema;
105
- /** Model id; currently passed as text guidance, runner may resolve in future. */
165
+ /**
166
+ * Model ref: `provider/model` or a configured typed id (e.g. `small`, `@large`).
167
+ */
106
168
  model?: string;
107
169
  /** Subagent tool allowlist override (forwarded to the runner). */
108
170
  toolset?: string[];
@@ -121,6 +183,12 @@ export interface WorkflowRunOptions {
121
183
  maxSubagents?: number;
122
184
  onLog?: (message: string) => void;
123
185
  onPhase?: (title: string) => void;
186
+ onAgentQueued?: (event: {
187
+ id: number;
188
+ label: string;
189
+ phase?: string;
190
+ prompt: string;
191
+ }) => void;
124
192
  onAgentStart?: (event: {
125
193
  id: number;
126
194
  label: string;
@@ -134,6 +202,13 @@ export interface WorkflowRunOptions {
134
202
  result: unknown;
135
203
  status: WorkflowAgentStatus;
136
204
  }) => void;
205
+ /** Merge extra subagent run options (e.g. progress callbacks) per agent id. */
206
+ enhanceSubagentRun?: (ctx: {
207
+ id: number;
208
+ label: string;
209
+ phase?: string;
210
+ prompt: string;
211
+ }) => Partial<SubagentRunOptions<unknown>>;
137
212
  }
138
213
  export interface WorkflowRunResult<T = unknown> {
139
214
  meta: WorkflowMeta;
@@ -54,6 +54,11 @@ export declare class CredentialResolver {
54
54
  id: string;
55
55
  source: 'agent' | 'global';
56
56
  }>>;
57
+ /**
58
+ * Plaintext API key from global auth profiles only (no env/oauth fallback).
59
+ * Used by the gateway console reveal endpoint.
60
+ */
61
+ revealGatewayStoredApiKey(provider: string): Promise<string | null>;
57
62
  /**
58
63
  * Save an API key profile
59
64
  */
@@ -1,11 +1,11 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
+ import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
2
3
  import { createLogger } from "../utils/logger/index.js";
3
4
  import { init_logger } from "../utils/logger.js";
4
- import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveCredentialsDir, resolveOAuthPath } from "../config/paths.js";
5
- import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
6
5
  import { getApiKeyFromEnv, init_env_keys } from "../providers/env-keys.js";
7
- import { dirname, join } from "path";
6
+ import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveCredentialsDir, resolveOAuthPath } from "../config/paths.js";
8
7
  import { mkdir, readFile } from "fs/promises";
8
+ import { dirname, join } from "path";
9
9
  //#region src/auth/credentials.ts
10
10
  function getCredentialResolver(options) {
11
11
  return new CredentialResolver(options);
@@ -117,6 +117,15 @@ var init_credentials = __esmMin((() => {
117
117
  return profiles;
118
118
  }
119
119
  /**
120
+ * Plaintext API key from global auth profiles only (no env/oauth fallback).
121
+ * Used by the gateway console reveal endpoint.
122
+ */
123
+ async revealGatewayStoredApiKey(provider) {
124
+ const normalizedProvider = provider.toLowerCase();
125
+ const profiles = await this.loadAuthProfilesFile();
126
+ return this.findProfileForProvider(profiles, normalizedProvider)?.key?.trim() || null;
127
+ }
128
+ /**
120
129
  * Save an API key profile
121
130
  */
122
131
  async saveApiKey(provider, key, options = {}) {
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","names":[],"sources":["../../../src/auth/credentials.ts"],"sourcesContent":["import { readFile, mkdir } from 'fs/promises';\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { join, dirname } from 'path';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from '../providers/env-keys.js';\nimport {\n resolveCredentialsDir,\n resolveAuthProfilesPath,\n resolveAgentAuthProfilesPath,\n resolveOAuthPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('Credentials');\n\n// ============================================\n// Types\n// ============================================\n\nexport type CredentialType = 'api_key' | 'oauth';\n\nexport interface ApiKeyProfile {\n type: 'api_key';\n provider: string;\n profileName?: string;\n envVar?: string | null;\n key: string | null;\n}\n\nexport interface OAuthToken {\n type: 'oauth';\n provider: string;\n access: string;\n refresh?: string;\n expiresAt?: number;\n scope?: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport type CredentialProfile = ApiKeyProfile;\n\nexport interface AuthProfilesFile {\n version: number;\n profiles: Record<string, ApiKeyProfile>;\n}\n\n// ============================================\n// Credential Resolver\n// ============================================\n\nexport interface CredentialResolverOptions {\n stateDir?: string;\n /** When set, per-agent auth profiles are read from `resolveAgentAuthProfilesPath(appConfig, agentId)`. */\n agentId?: string;\n /** Required when `agentId` is set. */\n appConfig?: Config;\n}\n\nexport class CredentialResolver {\n private readonly credentialsDir: string;\n private readonly agentId?: string;\n private readonly appConfig?: Config;\n\n constructor(options: CredentialResolverOptions = {}) {\n this.credentialsDir = options.stateDir\n ? join(options.stateDir, 'credentials')\n : resolveCredentialsDir();\n this.agentId = options.agentId;\n this.appConfig = options.appConfig;\n if (this.agentId && !this.appConfig) {\n throw new Error('CredentialResolver: appConfig is required when agentId is set');\n }\n }\n\n /**\n * Resolve API key for a provider\n * Priority: Agent private > Global > OAuth > Environment\n */\n async resolveApiKey(provider: string): Promise<string | null> {\n const normalizedProvider = provider.toLowerCase();\n\n // 1. Try agent private credentials\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) {\n log.debug({ provider, source: 'agent' }, 'Resolved API key from agent credentials');\n return agentKey;\n }\n }\n\n // 2. Try global credentials\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) {\n log.debug({ provider, source: 'global' }, 'Resolved API key from global credentials');\n return globalKey;\n }\n\n // 3. Try OAuth token (convert to Bearer)\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) {\n log.debug({ provider, source: 'oauth' }, 'Resolved API key from OAuth token');\n return oauthToken.access;\n }\n\n // 4. Environment variables (see `src/providers/env-keys.ts`)\n const envKey = getApiKeyFromEnv(normalizedProvider);\n if (envKey) {\n log.debug({ provider, source: 'env' }, 'Resolved API key from environment');\n return envKey;\n }\n\n log.debug({ provider }, 'No API key found');\n return null;\n }\n\n /**\n * Check if a provider has credentials configured\n */\n async hasCredentials(provider: string): Promise<boolean> {\n const key = await this.resolveApiKey(provider);\n return key !== null;\n }\n\n /**\n * Which step in {@link resolveApiKey} would supply the key (no secret material).\n */\n async resolveApiKeySource(\n provider: string,\n ): Promise<'agent' | 'global' | 'oauth' | 'env' | null> {\n const normalizedProvider = provider.toLowerCase();\n\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) return 'agent';\n }\n\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) return 'global';\n\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) return 'oauth';\n\n if (getApiKeyFromEnv(normalizedProvider)) return 'env';\n\n return null;\n }\n\n /**\n * List all available credential profiles\n */\n async listProfiles(): Promise<Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }>> {\n const profiles: Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }> = [];\n\n // Global profiles\n const globalProfiles = await this.loadAuthProfilesFile();\n for (const [id, profile] of Object.entries(globalProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'global' });\n }\n\n // Agent private profiles\n if (this.agentId) {\n const agentProfiles = await this.loadAgentAuthProfilesFile();\n for (const [id, profile] of Object.entries(agentProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'agent' });\n }\n }\n\n return profiles;\n }\n\n /**\n * Save an API key profile\n */\n async saveApiKey(\n provider: string,\n key: string,\n options: {\n profileName?: string;\n envVar?: string | null;\n agentPrivate?: boolean;\n } = {}\n ): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const profileId = options.profileName\n ? `${normalizedProvider}:${options.profileName}`\n : `${normalizedProvider}:default`;\n\n const profile: ApiKeyProfile = {\n type: 'api_key',\n provider: normalizedProvider,\n profileName: options.profileName,\n envVar: options.envVar ?? null,\n key,\n };\n\n if (options.agentPrivate && this.agentId) {\n await this.saveAgentAuthProfile(profileId, profile);\n } else {\n await this.saveGlobalAuthProfile(profileId, profile);\n }\n\n log.info({ provider, profileId, agentPrivate: options.agentPrivate }, 'Saved API key');\n }\n\n /**\n * Delete a credential profile\n */\n async deleteProfile(profileId: string, options: { agentPrivate?: boolean } = {}): Promise<void> {\n if (options.agentPrivate && this.agentId) {\n await this.deleteAgentAuthProfile(profileId);\n } else {\n await this.deleteGlobalAuthProfile(profileId);\n }\n\n log.info({ profileId, agentPrivate: options.agentPrivate }, 'Deleted credential profile');\n }\n\n /**\n * Load OAuth token for a provider\n */\n async loadOAuthToken(provider: string): Promise<OAuthToken | null> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n try {\n const content = await readFile(oauthPath, 'utf-8');\n const token = JSON.parse(content) as OAuthToken;\n\n // Check if token is expired\n if (token.expiresAt && token.expiresAt < Date.now()) {\n log.warn({ provider, expiresAt: token.expiresAt }, 'OAuth token is expired');\n // TODO: Implement token refresh\n return null;\n }\n\n return token;\n } catch {\n return null;\n }\n }\n\n /**\n * Save OAuth token for a provider\n */\n async saveOAuthToken(provider: string, token: Omit<OAuthToken, 'type' | 'provider' | 'updatedAt'>): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n await mkdir(dirname(oauthPath), { recursive: true });\n\n const fullToken: OAuthToken = {\n ...token,\n type: 'oauth',\n provider: normalizedProvider,\n updatedAt: new Date().toISOString(),\n };\n\n await writeTextAtomic(oauthPath, JSON.stringify(fullToken, null, 2));\n log.info({ provider }, 'Saved OAuth token');\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private async loadFromAgentCredentials(provider: string): Promise<string | null> {\n if (!this.agentId) return null;\n\n const profiles = await this.loadAgentAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private async loadFromGlobalCredentials(provider: string): Promise<string | null> {\n const profiles = await this.loadAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private loadFromEnv(envVarName: string): string | null {\n return process.env[envVarName] || null;\n }\n\n private findProfileForProvider(\n file: AuthProfilesFile,\n provider: string\n ): ApiKeyProfile | null {\n const normalizedProvider = provider.toLowerCase();\n\n // Look for exact match first\n for (const [, profile] of Object.entries(file.profiles)) {\n if (profile.provider === normalizedProvider) {\n return profile;\n }\n }\n\n return null;\n }\n\n private async loadAuthProfilesFile(): Promise<AuthProfilesFile> {\n const path = resolveAuthProfilesPath();\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async loadAgentAuthProfilesFile(): Promise<AuthProfilesFile> {\n if (!this.agentId || !this.appConfig) return { version: 2, profiles: {} };\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async saveGlobalAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n const path = resolveAuthProfilesPath();\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async saveAgentAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAgentAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteGlobalAuthProfile(profileId: string): Promise<void> {\n const path = resolveAuthProfilesPath();\n const file = await this.loadAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteAgentAuthProfile(profileId: string): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n const file = await this.loadAgentAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\nlet defaultResolver: CredentialResolver | null = null;\n\nexport function getCredentialResolver(options?: CredentialResolverOptions): CredentialResolver {\n if (!defaultResolver || options) {\n return new CredentialResolver(options);\n }\n return defaultResolver;\n}\n\nexport async function resolveApiKey(provider: string, options?: CredentialResolverOptions): Promise<string | null> {\n const resolver = getCredentialResolver(options);\n return resolver.resolveApiKey(provider);\n}\n\nexport async function hasCredentials(provider: string, options?: CredentialResolverOptions): Promise<boolean> {\n const resolver = getCredentialResolver(options);\n return resolver.hasCredentials(provider);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"credentials.js","names":[],"sources":["../../../src/auth/credentials.ts"],"sourcesContent":["import { readFile, mkdir } from 'fs/promises';\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { join, dirname } from 'path';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from '../providers/env-keys.js';\nimport {\n resolveCredentialsDir,\n resolveAuthProfilesPath,\n resolveAgentAuthProfilesPath,\n resolveOAuthPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/schema.js';\n\nconst log = createLogger('Credentials');\n\n// ============================================\n// Types\n// ============================================\n\nexport type CredentialType = 'api_key' | 'oauth';\n\nexport interface ApiKeyProfile {\n type: 'api_key';\n provider: string;\n profileName?: string;\n envVar?: string | null;\n key: string | null;\n}\n\nexport interface OAuthToken {\n type: 'oauth';\n provider: string;\n access: string;\n refresh?: string;\n expiresAt?: number;\n scope?: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport type CredentialProfile = ApiKeyProfile;\n\nexport interface AuthProfilesFile {\n version: number;\n profiles: Record<string, ApiKeyProfile>;\n}\n\n// ============================================\n// Credential Resolver\n// ============================================\n\nexport interface CredentialResolverOptions {\n stateDir?: string;\n /** When set, per-agent auth profiles are read from `resolveAgentAuthProfilesPath(appConfig, agentId)`. */\n agentId?: string;\n /** Required when `agentId` is set. */\n appConfig?: Config;\n}\n\nexport class CredentialResolver {\n private readonly credentialsDir: string;\n private readonly agentId?: string;\n private readonly appConfig?: Config;\n\n constructor(options: CredentialResolverOptions = {}) {\n this.credentialsDir = options.stateDir\n ? join(options.stateDir, 'credentials')\n : resolveCredentialsDir();\n this.agentId = options.agentId;\n this.appConfig = options.appConfig;\n if (this.agentId && !this.appConfig) {\n throw new Error('CredentialResolver: appConfig is required when agentId is set');\n }\n }\n\n /**\n * Resolve API key for a provider\n * Priority: Agent private > Global > OAuth > Environment\n */\n async resolveApiKey(provider: string): Promise<string | null> {\n const normalizedProvider = provider.toLowerCase();\n\n // 1. Try agent private credentials\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) {\n log.debug({ provider, source: 'agent' }, 'Resolved API key from agent credentials');\n return agentKey;\n }\n }\n\n // 2. Try global credentials\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) {\n log.debug({ provider, source: 'global' }, 'Resolved API key from global credentials');\n return globalKey;\n }\n\n // 3. Try OAuth token (convert to Bearer)\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) {\n log.debug({ provider, source: 'oauth' }, 'Resolved API key from OAuth token');\n return oauthToken.access;\n }\n\n // 4. Environment variables (see `src/providers/env-keys.ts`)\n const envKey = getApiKeyFromEnv(normalizedProvider);\n if (envKey) {\n log.debug({ provider, source: 'env' }, 'Resolved API key from environment');\n return envKey;\n }\n\n log.debug({ provider }, 'No API key found');\n return null;\n }\n\n /**\n * Check if a provider has credentials configured\n */\n async hasCredentials(provider: string): Promise<boolean> {\n const key = await this.resolveApiKey(provider);\n return key !== null;\n }\n\n /**\n * Which step in {@link resolveApiKey} would supply the key (no secret material).\n */\n async resolveApiKeySource(\n provider: string,\n ): Promise<'agent' | 'global' | 'oauth' | 'env' | null> {\n const normalizedProvider = provider.toLowerCase();\n\n if (this.agentId) {\n const agentKey = await this.loadFromAgentCredentials(normalizedProvider);\n if (agentKey) return 'agent';\n }\n\n const globalKey = await this.loadFromGlobalCredentials(normalizedProvider);\n if (globalKey) return 'global';\n\n const oauthToken = await this.loadOAuthToken(normalizedProvider);\n if (oauthToken) return 'oauth';\n\n if (getApiKeyFromEnv(normalizedProvider)) return 'env';\n\n return null;\n }\n\n /**\n * List all available credential profiles\n */\n async listProfiles(): Promise<Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }>> {\n const profiles: Array<ApiKeyProfile & { id: string; source: 'agent' | 'global' }> = [];\n\n // Global profiles\n const globalProfiles = await this.loadAuthProfilesFile();\n for (const [id, profile] of Object.entries(globalProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'global' });\n }\n\n // Agent private profiles\n if (this.agentId) {\n const agentProfiles = await this.loadAgentAuthProfilesFile();\n for (const [id, profile] of Object.entries(agentProfiles.profiles)) {\n profiles.push({ ...profile, id, source: 'agent' });\n }\n }\n\n return profiles;\n }\n\n /**\n * Plaintext API key from global auth profiles only (no env/oauth fallback).\n * Used by the gateway console reveal endpoint.\n */\n async revealGatewayStoredApiKey(provider: string): Promise<string | null> {\n const normalizedProvider = provider.toLowerCase();\n const profiles = await this.loadAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, normalizedProvider);\n const key = profile?.key?.trim();\n return key || null;\n }\n\n /**\n * Save an API key profile\n */\n async saveApiKey(\n provider: string,\n key: string,\n options: {\n profileName?: string;\n envVar?: string | null;\n agentPrivate?: boolean;\n } = {}\n ): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const profileId = options.profileName\n ? `${normalizedProvider}:${options.profileName}`\n : `${normalizedProvider}:default`;\n\n const profile: ApiKeyProfile = {\n type: 'api_key',\n provider: normalizedProvider,\n profileName: options.profileName,\n envVar: options.envVar ?? null,\n key,\n };\n\n if (options.agentPrivate && this.agentId) {\n await this.saveAgentAuthProfile(profileId, profile);\n } else {\n await this.saveGlobalAuthProfile(profileId, profile);\n }\n\n log.info({ provider, profileId, agentPrivate: options.agentPrivate }, 'Saved API key');\n }\n\n /**\n * Delete a credential profile\n */\n async deleteProfile(profileId: string, options: { agentPrivate?: boolean } = {}): Promise<void> {\n if (options.agentPrivate && this.agentId) {\n await this.deleteAgentAuthProfile(profileId);\n } else {\n await this.deleteGlobalAuthProfile(profileId);\n }\n\n log.info({ profileId, agentPrivate: options.agentPrivate }, 'Deleted credential profile');\n }\n\n /**\n * Load OAuth token for a provider\n */\n async loadOAuthToken(provider: string): Promise<OAuthToken | null> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n try {\n const content = await readFile(oauthPath, 'utf-8');\n const token = JSON.parse(content) as OAuthToken;\n\n // Check if token is expired\n if (token.expiresAt && token.expiresAt < Date.now()) {\n log.warn({ provider, expiresAt: token.expiresAt }, 'OAuth token is expired');\n // TODO: Implement token refresh\n return null;\n }\n\n return token;\n } catch {\n return null;\n }\n }\n\n /**\n * Save OAuth token for a provider\n */\n async saveOAuthToken(provider: string, token: Omit<OAuthToken, 'type' | 'provider' | 'updatedAt'>): Promise<void> {\n const normalizedProvider = provider.toLowerCase();\n const oauthPath = resolveOAuthPath(normalizedProvider);\n\n await mkdir(dirname(oauthPath), { recursive: true });\n\n const fullToken: OAuthToken = {\n ...token,\n type: 'oauth',\n provider: normalizedProvider,\n updatedAt: new Date().toISOString(),\n };\n\n await writeTextAtomic(oauthPath, JSON.stringify(fullToken, null, 2));\n log.info({ provider }, 'Saved OAuth token');\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private async loadFromAgentCredentials(provider: string): Promise<string | null> {\n if (!this.agentId) return null;\n\n const profiles = await this.loadAgentAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private async loadFromGlobalCredentials(provider: string): Promise<string | null> {\n const profiles = await this.loadAuthProfilesFile();\n const profile = this.findProfileForProvider(profiles, provider);\n\n if (!profile) return null;\n if (profile.envVar) return this.loadFromEnv(profile.envVar) ?? profile.key;\n return profile.key;\n }\n\n private loadFromEnv(envVarName: string): string | null {\n return process.env[envVarName] || null;\n }\n\n private findProfileForProvider(\n file: AuthProfilesFile,\n provider: string\n ): ApiKeyProfile | null {\n const normalizedProvider = provider.toLowerCase();\n\n // Look for exact match first\n for (const [, profile] of Object.entries(file.profiles)) {\n if (profile.provider === normalizedProvider) {\n return profile;\n }\n }\n\n return null;\n }\n\n private async loadAuthProfilesFile(): Promise<AuthProfilesFile> {\n const path = resolveAuthProfilesPath();\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async loadAgentAuthProfilesFile(): Promise<AuthProfilesFile> {\n if (!this.agentId || !this.appConfig) return { version: 2, profiles: {} };\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n version: data.version || 1,\n profiles: data.profiles || {},\n };\n } catch {\n return { version: 2, profiles: {} };\n }\n }\n\n private async saveGlobalAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n const path = resolveAuthProfilesPath();\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async saveAgentAuthProfile(profileId: string, profile: ApiKeyProfile): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n await mkdir(dirname(path), { recursive: true });\n\n const file = await this.loadAgentAuthProfilesFile();\n file.profiles[profileId] = profile;\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteGlobalAuthProfile(profileId: string): Promise<void> {\n const path = resolveAuthProfilesPath();\n const file = await this.loadAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n\n private async deleteAgentAuthProfile(profileId: string): Promise<void> {\n if (!this.agentId || !this.appConfig) throw new Error('Agent ID and appConfig required for agent-private profiles');\n\n const path = resolveAgentAuthProfilesPath(this.appConfig, this.agentId);\n const file = await this.loadAgentAuthProfilesFile();\n\n delete file.profiles[profileId];\n\n await writeTextAtomic(path, JSON.stringify(file, null, 2));\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\nlet defaultResolver: CredentialResolver | null = null;\n\nexport function getCredentialResolver(options?: CredentialResolverOptions): CredentialResolver {\n if (!defaultResolver || options) {\n return new CredentialResolver(options);\n }\n return defaultResolver;\n}\n\nexport async function resolveApiKey(provider: string, options?: CredentialResolverOptions): Promise<string | null> {\n const resolver = getCredentialResolver(options);\n return resolver.resolveApiKey(provider);\n}\n\nexport async function hasCredentials(provider: string, options?: CredentialResolverOptions): Promise<boolean> {\n const resolver = getCredentialResolver(options);\n return resolver.hasCredentials(provider);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
2
- import path from "node:path";
3
2
  import { chmodSync, existsSync, mkdirSync, readFileSync } from "node:fs";
3
+ import path from "node:path";
4
4
  import { homedir } from "os";
5
5
  //#region src/auth/profiles/store.ts
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
- import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
3
2
  import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveOAuthPath } from "../config/paths.js";
4
3
  import { init_loader, loadConfig } from "../config/loader.js";
4
+ import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  //#region src/auth/sync-provider-auth.ts
7
7
  /**
@@ -1,6 +1,6 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
- import { homedir } from "node:os";
3
2
  import { isAbsolute, relative, resolve, sep } from "node:path";
3
+ import { homedir } from "node:os";
4
4
  //#region src/browser/cache-dir-policy.ts
5
5
  function expandHome(input) {
6
6
  if (input === "~") return homedir();
@@ -2,10 +2,10 @@ import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { loadPlaywrightCoreModule } from "./providers/playwright-doctor.js";
4
4
  import { pickFreePort } from "./free-port.js";
5
- import { homedir, platform } from "node:os";
6
- import { join } from "node:path";
7
5
  import { existsSync } from "node:fs";
8
6
  import { mkdir, rm } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import { homedir, platform } from "node:os";
9
9
  import { spawn } from "node:child_process";
10
10
  //#region src/browser/cdp-local-launcher.ts
11
11
  /**
@@ -1,12 +1,12 @@
1
- import { resolveBrowserCommandTimeoutMs } from "./browser-command-timeout.js";
2
- import { BrowserBackSchema, BrowserCdpSchema, BrowserClickSchema, BrowserCloseSchema, BrowserConsoleSchema, BrowserDialogSchema, BrowserGetImagesSchema, BrowserNavigateSchema, BrowserPressSchema, BrowserScreenshotSchema, BrowserScrollSchema, BrowserSnapshotSchema, BrowserTypeSchema, BrowserVisionSchema } from "./schemas.js";
3
- import { assertBrowserUrlAllowed, checkPostRedirectUrl, containsApiKeyPattern, isAlwaysBlockedUrl } from "./url-policy.js";
4
- import { snapshotSummaryHeader, truncateSnapshotAtBoundary } from "./snapshot-helpers.js";
5
1
  import { BrowserManager } from "./manager.js";
6
2
  import { resolveBrowserBackendFromConfig } from "./backend-from-config.js";
3
+ import { resolveBrowserCommandTimeoutMs } from "./browser-command-timeout.js";
7
4
  import { BrowserNotReadyError, buildBrowserSetupDeepLink, checkBrowserReadiness } from "./readiness.js";
5
+ import { assertBrowserUrlAllowed, checkPostRedirectUrl, containsApiKeyPattern, isAlwaysBlockedUrl } from "./url-policy.js";
8
6
  import { CdpSupervisor } from "./cdp-supervisor.js";
7
+ import { snapshotSummaryHeader, truncateSnapshotAtBoundary } from "./snapshot-helpers.js";
9
8
  import { checkBotDetection, cleanupOrphanProcesses, startTracing, stopTracing } from "./session-lifecycle.js";
9
+ import { BrowserBackSchema, BrowserCdpSchema, BrowserClickSchema, BrowserCloseSchema, BrowserConsoleSchema, BrowserDialogSchema, BrowserGetImagesSchema, BrowserNavigateSchema, BrowserPressSchema, BrowserScreenshotSchema, BrowserScrollSchema, BrowserSnapshotSchema, BrowserTypeSchema, BrowserVisionSchema } from "./schemas.js";
10
10
  import { generateMousePath, generateScrollPlan, generateTypingPlan, humanizedClick, humanizedFill, humanizedPress, humanizedScroll, resolveHumanConfig } from "./humanize.js";
11
11
  import { WEBDRIVER_OVERRIDE_SCRIPT, buildLocalStealthArgs, buildStealthArgs, generateFingerprintSeed, makeExecutable, removeQuarantineAttr } from "./stealth.js";
12
12
  import { createBrowserActionRegistry } from "./actions/registry.js";
@@ -1,4 +1,4 @@
1
- import type { BrowserContext, Page } from 'playwright-core';
1
+ import type { Page } from 'playwright-core';
2
2
  import type { BrowserBackend } from './providers/types.js';
3
3
  import type { ExtensionBrowserProvider } from './providers/extension.js';
4
4
  export interface BrowserManagerOptions {
@@ -37,8 +37,6 @@ export declare class BrowserManager {
37
37
  * Extension mode does not create a Playwright {@link BrowserContext}.
38
38
  */
39
39
  ensureConnected(): Promise<void>;
40
- /** @deprecated Use {@link ensureConnected}. */
41
- ensureBrowser(): Promise<BrowserContext>;
42
40
  private _launchLocal;
43
41
  private _connectViaCdp;
44
42
  private _connectViaCloud;
@@ -118,12 +118,6 @@ var BrowserManager = class {
118
118
  this.activeBackendMode = backend.mode;
119
119
  if (this.browser) this._wireBrowserLifecycle(this.browser);
120
120
  }
121
- /** @deprecated Use {@link ensureConnected}. */
122
- async ensureBrowser() {
123
- await this.ensureConnected();
124
- if (!this.context) throw new Error("ensureBrowser: no Playwright context (extension backend uses ensureConnected + registry bridge)");
125
- return this.context;
126
- }
127
121
  async _launchLocal(headless) {
128
122
  const pw = await loadPlaywrightCoreModule();
129
123
  const chromium = pw.chromium ?? pw.default?.chromium;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","names":[],"sources":["../../../src/browser/manager.ts"],"sourcesContent":["import type { Browser, BrowserContext, Page } from 'playwright-core';\n\nimport { createLogger } from '../utils/logger.js';\n\nimport { loadPlaywrightCoreModule } from './providers/playwright-doctor.js';\nimport type { BrowserBackend, CloudBrowserProvider, CloudBrowserProviderConfig, ExtensionConnectionConfig } from './providers/types.js';\nimport type { ExtensionBrowserProvider } from './providers/extension.js';\n\nconst log = createLogger('browser-manager');\n\nconst MAX_PAGES = 3;\nconst PAGE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface BrowserManagerOptions {\n getHeadless: () => boolean;\n /** Backend connection mode. Default: local Playwright. */\n getBackend?: () => BrowserBackend;\n}\n\n/**\n * Multi-backend browser manager — supports local Playwright, direct CDP, and cloud providers.\n *\n * One browser context shared by all sessions; one {@link Page} per task/session key (max {@link MAX_PAGES}).\n * Backend is selected at first connection based on {@link BrowserManagerOptions.getBackend}.\n */\nexport class BrowserManager {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private cloudProvider: CloudBrowserProvider | null = null;\n private extensionProvider: ExtensionBrowserProvider | null = null;\n private extensionRelease: (() => Promise<void>) | null = null;\n private cloakChildProcess: import('node:child_process').ChildProcess | null = null;\n private cloakTempProfileDir: string | null = null;\n private pages = new Map<string, { page: Page; lastUsed: number }>();\n private readonly options: BrowserManagerOptions;\n private activeBackendMode: BrowserBackend['mode'] | null = null;\n\n constructor(options: BrowserManagerOptions) {\n this.options = options;\n }\n\n /** Current backend mode (null if not yet connected). */\n get backendMode(): string | null {\n return this.activeBackendMode;\n }\n\n private evictIdlePages(): void {\n const now = Date.now();\n for (const [id, entry] of this.pages) {\n if (entry.page.isClosed() || now - entry.lastUsed > PAGE_IDLE_TIMEOUT_MS) {\n void entry.page.close().catch(() => {});\n this.pages.delete(id);\n log.debug({ taskId: id }, 'Evicted idle or closed browser page');\n }\n }\n }\n\n private _isPlaywrightConnectionAlive(): boolean {\n if (!this.browser || !this.context) return false;\n try {\n if (typeof this.browser.isConnected === 'function' && !this.browser.isConnected()) {\n return false;\n }\n return true;\n } catch {\n return false;\n }\n }\n\n private _wireBrowserLifecycle(browser: Browser): void {\n browser.on('disconnected', () => {\n log.warn({ mode: this.activeBackendMode }, 'Browser disconnected — clearing stale session');\n this._clearPlaywrightSessionRefs();\n });\n }\n\n /** Drop Playwright handles without tearing down extension bridge. */\n private _clearPlaywrightSessionRefs(): void {\n this.pages.clear();\n this.context = null;\n this.browser = null;\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n if (this.cloudProvider) {\n void this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n }\n\n private async _resetStalePlaywrightSession(): Promise<void> {\n for (const [, entry] of this.pages) {\n await entry.page.close().catch(() => {});\n }\n this.pages.clear();\n\n if (this.cloudProvider) {\n await this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n\n if (this.cloakChildProcess || this.cloakTempProfileDir) {\n const { cleanupCloakBrowser } = await import('./providers/cloakbrowser.js');\n await cleanupCloakBrowser(this.cloakChildProcess, this.cloakTempProfileDir).catch(() => {});\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n }\n\n await this.context?.close().catch(() => {});\n await this.browser?.close().catch(() => {});\n this.context = null;\n this.browser = null;\n }\n\n /**\n * Ensure Playwright context or Chrome Extension provider is ready.\n * Extension mode does not create a Playwright {@link BrowserContext}.\n */\n async ensureConnected(): Promise<void> {\n if (this.extensionProvider) return;\n\n if (this.context && this._isPlaywrightConnectionAlive()) {\n return;\n }\n\n if (this.context || this.browser) {\n log.warn({ mode: this.activeBackendMode }, 'Browser session unavailable — reconnecting');\n await this._resetStalePlaywrightSession();\n }\n\n const backend = this.options.getBackend?.() ?? { mode: 'local' as const, headless: false };\n\n switch (backend.mode) {\n case 'cdp':\n await this._connectViaCdp(backend.config.wsEndpoint);\n break;\n case 'cloud':\n await this._connectViaCloud(backend.config);\n break;\n case 'extension':\n await this._connectViaExtension(backend.config);\n break;\n case 'cloakbrowser':\n await this._connectViaCloakBrowser(backend.config);\n break;\n case 'local':\n default:\n await this._launchLocal(backend.mode === 'local' ? backend.headless : this.options.getHeadless() === true);\n break;\n }\n\n this.activeBackendMode = backend.mode;\n if (this.browser) {\n this._wireBrowserLifecycle(this.browser);\n }\n }\n\n /** @deprecated Use {@link ensureConnected}. */\n async ensureBrowser(): Promise<BrowserContext> {\n await this.ensureConnected();\n if (!this.context) {\n throw new Error('ensureBrowser: no Playwright context (extension backend uses ensureConnected + registry bridge)');\n }\n return this.context;\n }\n\n private async _launchLocal(headless: boolean): Promise<void> {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.launch) {\n throw new Error(\n 'playwright-core did not expose chromium (try reinstall: pnpm install playwright-core; install browser: npx playwright install chromium)',\n );\n }\n this.browser = await chromium.launch({\n headless,\n ...(headless ? { channel: 'chromium' } : {}),\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n this.context = await this.browser.newContext({\n viewport: { width: 1280, height: 720 },\n userAgent:\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n });\n log.info({ headless, mode: 'local' }, 'Browser launched (local)');\n }\n\n private async _connectViaCdp(wsEndpoint: string): Promise<void> {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) {\n throw new Error('playwright-core does not support connectOverCDP');\n }\n this.browser = await chromium.connectOverCDP(wsEndpoint);\n const contexts = this.browser.contexts();\n this.context = contexts.length > 0 ? contexts[0] : await this.browser.newContext();\n log.info({ mode: 'cdp', wsEndpoint }, 'Browser connected (CDP)');\n }\n\n private async _connectViaCloud(config: CloudBrowserProviderConfig): Promise<void> {\n const { BrowserbaseProvider } = await import('./providers/browserbase.js');\n const { BrowserUseProvider } = await import('./providers/browser-use.js');\n\n const provider = config.type === 'browserbase'\n ? new BrowserbaseProvider(config)\n : new BrowserUseProvider(config);\n\n const { browser, context } = await provider.connect();\n this.browser = browser;\n this.context = context;\n this.cloudProvider = provider;\n log.info({ mode: 'cloud', provider: config.type }, `Browser connected (${config.type})`);\n }\n\n private async _connectViaExtension(config?: ExtensionConnectionConfig): Promise<void> {\n const { acquireExtensionBrowserServer } = await import('./providers/extension-ws-acquire.js');\n const { provider, release } = await acquireExtensionBrowserServer(config);\n this.extensionProvider = provider;\n this.extensionRelease = release;\n log.info({ port: config?.port ?? 19820 }, 'Extension WS server ready, waiting for Chrome Extension...');\n await provider.waitForConnection();\n // Extension mode does not use Playwright — context stays null.\n // The action registry dispatches directly via extensionProvider.sendCommand().\n log.info({ mode: 'extension' }, 'Browser connected (Chrome Extension)');\n }\n\n private async _connectViaCloakBrowser(config?: import('./providers/types.js').CloakBrowserConfig): Promise<void> {\n const { launchCloakBrowser } = await import('./providers/cloakbrowser.js');\n const result = await launchCloakBrowser(config);\n if (!result.browser || !result.context) {\n throw new Error('BrowserManager: CloakBrowser launch did not return a Playwright connection');\n }\n this.browser = result.browser;\n this.context = result.context;\n this.cloakChildProcess = result.childProcess;\n this.cloakTempProfileDir = result.temporaryProfileDir;\n log.info({ mode: 'cloakbrowser' }, 'Browser connected (CloakBrowser)');\n }\n\n async getPage(taskId: string): Promise<Page> {\n if (this.extensionProvider) {\n throw new Error('BrowserManager.getPage is not used in Chrome Extension backend mode');\n }\n\n this.evictIdlePages();\n await this.ensureConnected();\n\n const existing = this.pages.get(taskId);\n if (existing && !existing.page.isClosed()) {\n existing.lastUsed = Date.now();\n return existing.page;\n }\n if (existing) {\n this.pages.delete(taskId);\n }\n\n if (this.pages.size >= MAX_PAGES) {\n const oldest = [...this.pages.entries()].sort((a, b) => a[1].lastUsed - b[1].lastUsed)[0];\n if (oldest) {\n await oldest[1].page.close().catch(() => {});\n this.pages.delete(oldest[0]);\n }\n }\n\n const ctx = this.context;\n if (!ctx) {\n throw new Error('BrowserManager: Playwright context missing after ensureConnected');\n }\n const page = await ctx.newPage();\n this.pages.set(taskId, { page, lastUsed: Date.now() });\n return page;\n }\n\n async closePage(taskId: string): Promise<void> {\n if (this.extensionProvider) {\n return;\n }\n const entry = this.pages.get(taskId);\n if (entry) {\n await entry.page.close().catch(() => {});\n this.pages.delete(taskId);\n }\n }\n\n /** Get the extension provider (only available in extension mode). */\n getExtensionProvider(): ExtensionBrowserProvider | null {\n return this.extensionProvider;\n }\n\n async shutdown(): Promise<void> {\n for (const [, entry] of this.pages) {\n await entry.page.close().catch(() => {});\n }\n this.pages.clear();\n\n if (this.cloudProvider) {\n await this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n\n if (this.extensionRelease) {\n await this.extensionRelease().catch(() => {});\n this.extensionRelease = null;\n }\n this.extensionProvider = null;\n\n // CloakBrowser cleanup — kill child process and remove temp profile\n if (this.cloakChildProcess || this.cloakTempProfileDir) {\n const { cleanupCloakBrowser } = await import('./providers/cloakbrowser.js');\n await cleanupCloakBrowser(this.cloakChildProcess, this.cloakTempProfileDir).catch(() => {});\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n }\n\n await this.context?.close().catch(() => {});\n await this.browser?.close().catch(() => {});\n this.context = null;\n this.browser = null;\n this.activeBackendMode = null;\n log.info('Browser shut down');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","names":[],"sources":["../../../src/browser/manager.ts"],"sourcesContent":["import type { Browser, BrowserContext, Page } from 'playwright-core';\n\nimport { createLogger } from '../utils/logger.js';\n\nimport { loadPlaywrightCoreModule } from './providers/playwright-doctor.js';\nimport type { BrowserBackend, CloudBrowserProvider, CloudBrowserProviderConfig, ExtensionConnectionConfig } from './providers/types.js';\nimport type { ExtensionBrowserProvider } from './providers/extension.js';\n\nconst log = createLogger('browser-manager');\n\nconst MAX_PAGES = 3;\nconst PAGE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface BrowserManagerOptions {\n getHeadless: () => boolean;\n /** Backend connection mode. Default: local Playwright. */\n getBackend?: () => BrowserBackend;\n}\n\n/**\n * Multi-backend browser manager — supports local Playwright, direct CDP, and cloud providers.\n *\n * One browser context shared by all sessions; one {@link Page} per task/session key (max {@link MAX_PAGES}).\n * Backend is selected at first connection based on {@link BrowserManagerOptions.getBackend}.\n */\nexport class BrowserManager {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private cloudProvider: CloudBrowserProvider | null = null;\n private extensionProvider: ExtensionBrowserProvider | null = null;\n private extensionRelease: (() => Promise<void>) | null = null;\n private cloakChildProcess: import('node:child_process').ChildProcess | null = null;\n private cloakTempProfileDir: string | null = null;\n private pages = new Map<string, { page: Page; lastUsed: number }>();\n private readonly options: BrowserManagerOptions;\n private activeBackendMode: BrowserBackend['mode'] | null = null;\n\n constructor(options: BrowserManagerOptions) {\n this.options = options;\n }\n\n /** Current backend mode (null if not yet connected). */\n get backendMode(): string | null {\n return this.activeBackendMode;\n }\n\n private evictIdlePages(): void {\n const now = Date.now();\n for (const [id, entry] of this.pages) {\n if (entry.page.isClosed() || now - entry.lastUsed > PAGE_IDLE_TIMEOUT_MS) {\n void entry.page.close().catch(() => {});\n this.pages.delete(id);\n log.debug({ taskId: id }, 'Evicted idle or closed browser page');\n }\n }\n }\n\n private _isPlaywrightConnectionAlive(): boolean {\n if (!this.browser || !this.context) return false;\n try {\n if (typeof this.browser.isConnected === 'function' && !this.browser.isConnected()) {\n return false;\n }\n return true;\n } catch {\n return false;\n }\n }\n\n private _wireBrowserLifecycle(browser: Browser): void {\n browser.on('disconnected', () => {\n log.warn({ mode: this.activeBackendMode }, 'Browser disconnected — clearing stale session');\n this._clearPlaywrightSessionRefs();\n });\n }\n\n /** Drop Playwright handles without tearing down extension bridge. */\n private _clearPlaywrightSessionRefs(): void {\n this.pages.clear();\n this.context = null;\n this.browser = null;\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n if (this.cloudProvider) {\n void this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n }\n\n private async _resetStalePlaywrightSession(): Promise<void> {\n for (const [, entry] of this.pages) {\n await entry.page.close().catch(() => {});\n }\n this.pages.clear();\n\n if (this.cloudProvider) {\n await this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n\n if (this.cloakChildProcess || this.cloakTempProfileDir) {\n const { cleanupCloakBrowser } = await import('./providers/cloakbrowser.js');\n await cleanupCloakBrowser(this.cloakChildProcess, this.cloakTempProfileDir).catch(() => {});\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n }\n\n await this.context?.close().catch(() => {});\n await this.browser?.close().catch(() => {});\n this.context = null;\n this.browser = null;\n }\n\n /**\n * Ensure Playwright context or Chrome Extension provider is ready.\n * Extension mode does not create a Playwright {@link BrowserContext}.\n */\n async ensureConnected(): Promise<void> {\n if (this.extensionProvider) return;\n\n if (this.context && this._isPlaywrightConnectionAlive()) {\n return;\n }\n\n if (this.context || this.browser) {\n log.warn({ mode: this.activeBackendMode }, 'Browser session unavailable — reconnecting');\n await this._resetStalePlaywrightSession();\n }\n\n const backend = this.options.getBackend?.() ?? { mode: 'local' as const, headless: false };\n\n switch (backend.mode) {\n case 'cdp':\n await this._connectViaCdp(backend.config.wsEndpoint);\n break;\n case 'cloud':\n await this._connectViaCloud(backend.config);\n break;\n case 'extension':\n await this._connectViaExtension(backend.config);\n break;\n case 'cloakbrowser':\n await this._connectViaCloakBrowser(backend.config);\n break;\n case 'local':\n default:\n await this._launchLocal(backend.mode === 'local' ? backend.headless : this.options.getHeadless() === true);\n break;\n }\n\n this.activeBackendMode = backend.mode;\n if (this.browser) {\n this._wireBrowserLifecycle(this.browser);\n }\n }\n\n private async _launchLocal(headless: boolean): Promise<void> {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.launch) {\n throw new Error(\n 'playwright-core did not expose chromium (try reinstall: pnpm install playwright-core; install browser: npx playwright install chromium)',\n );\n }\n this.browser = await chromium.launch({\n headless,\n ...(headless ? { channel: 'chromium' } : {}),\n args: ['--no-sandbox', '--disable-setuid-sandbox'],\n });\n this.context = await this.browser.newContext({\n viewport: { width: 1280, height: 720 },\n userAgent:\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n });\n log.info({ headless, mode: 'local' }, 'Browser launched (local)');\n }\n\n private async _connectViaCdp(wsEndpoint: string): Promise<void> {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) {\n throw new Error('playwright-core does not support connectOverCDP');\n }\n this.browser = await chromium.connectOverCDP(wsEndpoint);\n const contexts = this.browser.contexts();\n this.context = contexts.length > 0 ? contexts[0] : await this.browser.newContext();\n log.info({ mode: 'cdp', wsEndpoint }, 'Browser connected (CDP)');\n }\n\n private async _connectViaCloud(config: CloudBrowserProviderConfig): Promise<void> {\n const { BrowserbaseProvider } = await import('./providers/browserbase.js');\n const { BrowserUseProvider } = await import('./providers/browser-use.js');\n\n const provider = config.type === 'browserbase'\n ? new BrowserbaseProvider(config)\n : new BrowserUseProvider(config);\n\n const { browser, context } = await provider.connect();\n this.browser = browser;\n this.context = context;\n this.cloudProvider = provider;\n log.info({ mode: 'cloud', provider: config.type }, `Browser connected (${config.type})`);\n }\n\n private async _connectViaExtension(config?: ExtensionConnectionConfig): Promise<void> {\n const { acquireExtensionBrowserServer } = await import('./providers/extension-ws-acquire.js');\n const { provider, release } = await acquireExtensionBrowserServer(config);\n this.extensionProvider = provider;\n this.extensionRelease = release;\n log.info({ port: config?.port ?? 19820 }, 'Extension WS server ready, waiting for Chrome Extension...');\n await provider.waitForConnection();\n // Extension mode does not use Playwright — context stays null.\n // The action registry dispatches directly via extensionProvider.sendCommand().\n log.info({ mode: 'extension' }, 'Browser connected (Chrome Extension)');\n }\n\n private async _connectViaCloakBrowser(config?: import('./providers/types.js').CloakBrowserConfig): Promise<void> {\n const { launchCloakBrowser } = await import('./providers/cloakbrowser.js');\n const result = await launchCloakBrowser(config);\n if (!result.browser || !result.context) {\n throw new Error('BrowserManager: CloakBrowser launch did not return a Playwright connection');\n }\n this.browser = result.browser;\n this.context = result.context;\n this.cloakChildProcess = result.childProcess;\n this.cloakTempProfileDir = result.temporaryProfileDir;\n log.info({ mode: 'cloakbrowser' }, 'Browser connected (CloakBrowser)');\n }\n\n async getPage(taskId: string): Promise<Page> {\n if (this.extensionProvider) {\n throw new Error('BrowserManager.getPage is not used in Chrome Extension backend mode');\n }\n\n this.evictIdlePages();\n await this.ensureConnected();\n\n const existing = this.pages.get(taskId);\n if (existing && !existing.page.isClosed()) {\n existing.lastUsed = Date.now();\n return existing.page;\n }\n if (existing) {\n this.pages.delete(taskId);\n }\n\n if (this.pages.size >= MAX_PAGES) {\n const oldest = [...this.pages.entries()].sort((a, b) => a[1].lastUsed - b[1].lastUsed)[0];\n if (oldest) {\n await oldest[1].page.close().catch(() => {});\n this.pages.delete(oldest[0]);\n }\n }\n\n const ctx = this.context;\n if (!ctx) {\n throw new Error('BrowserManager: Playwright context missing after ensureConnected');\n }\n const page = await ctx.newPage();\n this.pages.set(taskId, { page, lastUsed: Date.now() });\n return page;\n }\n\n async closePage(taskId: string): Promise<void> {\n if (this.extensionProvider) {\n return;\n }\n const entry = this.pages.get(taskId);\n if (entry) {\n await entry.page.close().catch(() => {});\n this.pages.delete(taskId);\n }\n }\n\n /** Get the extension provider (only available in extension mode). */\n getExtensionProvider(): ExtensionBrowserProvider | null {\n return this.extensionProvider;\n }\n\n async shutdown(): Promise<void> {\n for (const [, entry] of this.pages) {\n await entry.page.close().catch(() => {});\n }\n this.pages.clear();\n\n if (this.cloudProvider) {\n await this.cloudProvider.disconnect().catch(() => {});\n this.cloudProvider = null;\n }\n\n if (this.extensionRelease) {\n await this.extensionRelease().catch(() => {});\n this.extensionRelease = null;\n }\n this.extensionProvider = null;\n\n // CloakBrowser cleanup — kill child process and remove temp profile\n if (this.cloakChildProcess || this.cloakTempProfileDir) {\n const { cleanupCloakBrowser } = await import('./providers/cloakbrowser.js');\n await cleanupCloakBrowser(this.cloakChildProcess, this.cloakTempProfileDir).catch(() => {});\n this.cloakChildProcess = null;\n this.cloakTempProfileDir = null;\n }\n\n await this.context?.close().catch(() => {});\n await this.browser?.close().catch(() => {});\n this.context = null;\n this.browser = null;\n this.activeBackendMode = null;\n log.info('Browser shut down');\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/{version}/.
3
- * Single version directory per install direct overwrite, no `current` symlink.
2
+ * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.
3
+ * Fixed path gateway upgrades overwrite in place so Chrome sideload paths stay stable.
4
4
  */
5
5
  export declare const BROWSER_EXT_REQUIRED_FILES: readonly ["manifest.json", "popup.html", "dist/background.js", "dist/content.js", "dist/popup.js"];
6
6
  export type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';
@@ -32,8 +32,8 @@ export interface EnsureBrowserExtResult {
32
32
  }
33
33
  /** Validate a directory contains a loadable extension tree. */
34
34
  export declare function validateBrowserExtLayout(dir: string): boolean;
35
- /** Resolve the installed extension directory (version folder, not a symlink). */
36
- export declare function resolveInstalledExtensionPath(cacheDir: string, meta: BrowserExtInstallMeta | null): string | null;
35
+ /** Resolve the installed extension directory (fixed `browser-ext/` root). */
36
+ export declare function resolveInstalledExtensionPath(cacheDir: string, _meta: BrowserExtInstallMeta | null): string | null;
37
37
  /**
38
38
  * Resolve the bundled extension source directory (read-only).
39
39
  */