@xopcai/xopc 0.0.113 → 0.0.115

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 (567) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  4. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  5. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  6. package/dist/extensions/telegram/src/plugin.js +1 -1
  7. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  8. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  9. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  10. package/dist/extensions/telegram/xopc.extension.json +1 -1
  11. package/dist/extensions/weixin/src/api/api.js +2 -2
  12. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  13. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  14. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  15. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  16. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  17. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  18. package/dist/extensions/weixin/src/plugin.js +1 -1
  19. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  20. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  21. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-DVnBfANm.js} +1 -1
  22. package/dist/gateway/static/root/assets/agent-browser-settings-page-DPXc4hz8.js +6 -0
  23. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CTJ0YnRQ.js +1 -0
  24. package/dist/gateway/static/root/assets/agents-zJXQfJ_W.js +71 -0
  25. package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-DzGbdr04.js} +1 -1
  26. package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-BQpPSTHD.js} +1 -1
  27. package/dist/gateway/static/root/assets/apps-page-CPjfyzSD.js +1 -0
  28. package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CXu-Csep.js} +1 -1
  29. package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BAjgOoGY.js} +1 -1
  30. package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-BSBgB2hO.js} +1 -1
  31. package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-BpXw9TTR.js} +3 -3
  32. package/dist/gateway/static/root/assets/channels-settings-BbPUpzWB.js +1 -0
  33. package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-NOoPiIYz.js} +1 -1
  34. package/dist/gateway/static/root/assets/connectors-settings-CAXYMOdp.js +2 -0
  35. package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-C9BOqAXd.js} +1 -1
  36. package/dist/gateway/static/root/assets/cron-page-DuUbBeKI.js +3 -0
  37. package/dist/gateway/static/root/assets/{dreaming-settings-6UZE1FSK.js → dreaming-settings-DQ4DtiK1.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-D9kgUHCc.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-CGyhXqzR.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-DL8Xquqd.js} +1 -1
  41. package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D0VXA932.js} +1 -1
  42. package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-Be8SmgUw.js} +1 -1
  43. package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-C-xjn__h.js} +1 -1
  44. package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-BMPwIjKI.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-DERUH61L.js} +1 -1
  46. package/dist/gateway/static/root/assets/goal-detail-page-BJsyjJnF.js +1 -0
  47. package/dist/gateway/static/root/assets/goals-config-api-BPmqWk90.js +1 -0
  48. package/dist/gateway/static/root/assets/goals-page-BerDgIhw.js +2 -0
  49. package/dist/gateway/static/root/assets/goals-settings-ByTjeAto.js +1 -0
  50. package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-Bfdzr8oV.js} +1 -1
  51. package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-TbHgcjTn.js} +1 -1
  52. package/dist/gateway/static/root/assets/index-AkTrf6Pb.js +122 -0
  53. package/dist/gateway/static/root/assets/index-fh5sXTj9.css +1 -0
  54. package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-utKbuCRY.js} +1 -1
  55. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-CjqS6c6V.js} +1 -1
  56. package/dist/gateway/static/root/assets/logs-page-DGXuPf5B.js +2 -0
  57. package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-DW8C47iB.js} +1 -1
  58. package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-D6HwDhDT.js} +1 -1
  59. package/dist/gateway/static/root/assets/messages-upgxw6Ub.js +3 -0
  60. package/dist/gateway/static/root/assets/models-hub-panel-Bot16nn7.js +2 -0
  61. package/dist/gateway/static/root/assets/note-detail-page-Brlyou8M.js +2 -0
  62. package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-pJM35Pz5.js} +1 -1
  63. package/dist/gateway/static/root/assets/notes-page-DvZ4pwc-.js +1 -0
  64. package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CVwHuyN6.js} +1 -1
  65. package/dist/gateway/static/root/assets/remote-access-hub-BZEDmxbZ.js +1 -0
  66. package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-Ba-UEk7x.js} +1 -1
  67. package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-CNN9595U.js} +1 -1
  68. package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DnNMmtD5.js} +1 -1
  69. package/dist/gateway/static/root/assets/sessions-page-DdGGlsfn.js +1 -0
  70. package/dist/gateway/static/root/assets/settings-advanced-gate-DlkEkPf9.js +1 -0
  71. package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CmOz80i5.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-BmK7JJOV.js} +1 -1
  73. package/dist/gateway/static/root/assets/settings-page-DFPTrsPF.js +1 -0
  74. package/dist/gateway/static/root/assets/setup-status-panel-CYCCfgh4.js +1 -0
  75. package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-Dp2qGrHC.js} +1 -1
  76. package/dist/gateway/static/root/assets/shares-settings-Bff1pGd0.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-CJGKpBur.js +1 -0
  78. package/dist/gateway/static/root/assets/skills-page-C6ocduTD.js +2 -0
  79. package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-5jrIEr5b.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-BuiXLIs5.js} +1 -1
  81. package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CHlO8J9G.js} +1 -1
  82. package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-CW5JORnl.js} +1 -1
  83. package/dist/gateway/static/root/assets/voice-api-key-field-DDoQyghO.js +1 -0
  84. package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DDDWYHvg.js} +1 -1
  85. package/dist/gateway/static/root/assets/workflow-page.utils-CKjeEGqx.js +1 -0
  86. package/dist/gateway/static/root/assets/workflows-page-B604ehHG.js +18 -0
  87. package/dist/gateway/static/root/index.html +5 -5
  88. package/dist/gateway/static/root/logo.svg +4 -3
  89. package/dist/package.js +1 -1
  90. package/dist/src/agent/agent-manager.d.ts +8 -0
  91. package/dist/src/agent/agent-manager.js +63 -28
  92. package/dist/src/agent/agent-manager.js.map +1 -1
  93. package/dist/src/agent/agent-scope.js +1 -1
  94. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  95. package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
  96. package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
  97. package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
  98. package/dist/src/agent/context/workspace-seed.js +2 -2
  99. package/dist/src/agent/context/workspace-state.js +1 -1
  100. package/dist/src/agent/context/workspace.js +1 -1
  101. package/dist/src/agent/embedded/session-tool-result-guard.js +8 -1
  102. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  103. package/dist/src/agent/goals/checklist-judge.d.ts +1 -0
  104. package/dist/src/agent/goals/checklist-judge.js +3 -2
  105. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  106. package/dist/src/agent/goals/evaluate-turn.d.ts +1 -1
  107. package/dist/src/agent/goals/evaluate-turn.js +1 -0
  108. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  109. package/dist/src/agent/goals/goal-locale.js +2 -2
  110. package/dist/src/agent/goals/persistent-goal-service.js +2 -4
  111. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  112. package/dist/src/agent/goals/post-turn.d.ts +6 -1
  113. package/dist/src/agent/goals/post-turn.js +15 -6
  114. package/dist/src/agent/goals/post-turn.js.map +1 -1
  115. package/dist/src/agent/image/load-image-media.js +2 -2
  116. package/dist/src/agent/inbound/inbound-loop.js +5 -1
  117. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  118. package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
  119. package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
  120. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  121. package/dist/src/agent/ipc/inbox.js +3 -3
  122. package/dist/src/agent/ipc/socket.js +1 -1
  123. package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
  124. package/dist/src/agent/mcp/bundle-mcp-materialize.js +50 -2
  125. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  126. package/dist/src/agent/mcp/bundle-mcp-runtime.js +79 -4
  127. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  128. package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
  129. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  130. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  131. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  132. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  133. package/dist/src/agent/memory/dreaming/events.js +1 -1
  134. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  135. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  136. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  137. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  138. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  139. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  140. package/dist/src/agent/memory/memory-flush.js +1 -1
  141. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  142. package/dist/src/agent/models/manager.js +1 -1
  143. package/dist/src/agent/prompt/memory/index.js +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/btw-query.js +11 -3
  149. package/dist/src/agent/service/btw-query.js.map +1 -1
  150. package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
  151. package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
  152. package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
  153. package/dist/src/agent/service/process-direct-one-shot.js +1 -1
  154. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  155. package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
  156. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  157. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  158. package/dist/src/agent/service.d.ts +1 -1
  159. package/dist/src/agent/service.js +13 -9
  160. package/dist/src/agent/service.js.map +1 -1
  161. package/dist/src/agent/service.types.d.ts +5 -0
  162. package/dist/src/agent/session/session-inspector.js +1 -1
  163. package/dist/src/agent/skills/config.js +2 -2
  164. package/dist/src/agent/skills/filesystem-watcher.js +5 -4
  165. package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
  166. package/dist/src/agent/skills/hub-hash.js +2 -2
  167. package/dist/src/agent/skills/hub-lock.js +1 -1
  168. package/dist/src/agent/skills/hub-pull.js +2 -2
  169. package/dist/src/agent/skills/index.js +4 -3
  170. package/dist/src/agent/skills/index.js.map +1 -1
  171. package/dist/src/agent/skills/installer.js +2 -2
  172. package/dist/src/agent/skills/managed-store.js +1 -1
  173. package/dist/src/agent/skills/skill-manage-ops.js +3 -2
  174. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  175. package/dist/src/agent/skills/skill-manager.js +1 -1
  176. package/dist/src/agent/skills/skill-view-path.js +1 -1
  177. package/dist/src/agent/skills/test-framework.js +1 -1
  178. package/dist/src/agent/skills/types.d.ts +1 -1
  179. package/dist/src/agent/skills/watcher.js +2 -5
  180. package/dist/src/agent/skills/watcher.js.map +1 -1
  181. package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
  182. package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
  183. package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
  184. package/dist/src/agent/starter-agents.js +1 -1
  185. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  186. package/dist/src/agent/tool-manuals/browser.js +62 -3
  187. package/dist/src/agent/tool-manuals/browser.js.map +1 -1
  188. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
  189. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
  190. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  191. package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
  192. package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
  193. package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
  194. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  195. package/dist/src/agent/tools/factory.js +1 -10
  196. package/dist/src/agent/tools/factory.js.map +1 -1
  197. package/dist/src/agent/tools/find.js +1 -1
  198. package/dist/src/agent/tools/grep.js +1 -1
  199. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  200. package/dist/src/agent/tools/skill-manage-tool.js +2 -2
  201. package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
  202. package/dist/src/agent/tools/workflow-tool.js +1 -1
  203. package/dist/src/agent/workflow/catalog.js +1 -1
  204. package/dist/src/agent/workflow/snapshot.d.ts +10 -0
  205. package/dist/src/agent/workflow/snapshot.js +136 -1
  206. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  207. package/dist/src/agent/workflow/subagent-runner.js +18 -1
  208. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  209. package/dist/src/ai-assist/text-assist.js +1 -1
  210. package/dist/src/auth/credentials.js +2 -2
  211. package/dist/src/auth/profiles/store.js +2 -2
  212. package/dist/src/auth/sync-provider-auth.js +1 -1
  213. package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
  214. package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
  215. package/dist/src/browser/actions/registry.js +383 -7
  216. package/dist/src/browser/actions/registry.js.map +1 -1
  217. package/dist/src/browser/actions/types.d.ts +11 -3
  218. package/dist/src/browser/cache-dir-policy.js +1 -1
  219. package/dist/src/browser/cdp-local-launcher.js +2 -2
  220. package/dist/src/browser/index.js +2 -2
  221. package/dist/src/browser/pipeline/output.d.ts +18 -16
  222. package/dist/src/browser/pipeline/output.js +28 -20
  223. package/dist/src/browser/pipeline/output.js.map +1 -1
  224. package/dist/src/browser/pipeline/runner.d.ts +7 -14
  225. package/dist/src/browser/pipeline/runner.js +349 -102
  226. package/dist/src/browser/pipeline/runner.js.map +1 -1
  227. package/dist/src/browser/pipeline/schema.d.ts +1 -0
  228. package/dist/src/browser/pipeline/schema.js +35 -58
  229. package/dist/src/browser/pipeline/schema.js.map +1 -1
  230. package/dist/src/browser/pipeline/source.d.ts +2 -0
  231. package/dist/src/browser/pipeline/source.js +10 -1
  232. package/dist/src/browser/pipeline/source.js.map +1 -1
  233. package/dist/src/browser/pipeline/template.d.ts +10 -2
  234. package/dist/src/browser/pipeline/template.js +50 -8
  235. package/dist/src/browser/pipeline/template.js.map +1 -1
  236. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  237. package/dist/src/browser/providers/cloakbrowser.js +5 -5
  238. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  239. package/dist/src/browser/stealth.js +1 -1
  240. package/dist/src/channels/catalog/channel-catalog-service.d.ts +2 -1
  241. package/dist/src/channels/catalog/channel-catalog-service.js +133 -16
  242. package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
  243. package/dist/src/channels/catalog/channel-catalog-types.d.ts +13 -0
  244. package/dist/src/channels/outbound/persist-store.js +1 -1
  245. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  246. package/dist/src/channels/pairing/pairing-store.js +2 -2
  247. package/dist/src/chat-commands/agent-edit.js +2 -2
  248. package/dist/src/chat-commands/builtins/config.js +5 -7
  249. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  250. package/dist/src/chat-commands/context.d.ts +5 -0
  251. package/dist/src/chat-commands/context.js +18 -9
  252. package/dist/src/chat-commands/context.js.map +1 -1
  253. package/dist/src/chat-commands/index.d.ts +1 -1
  254. package/dist/src/chat-commands/index.js +2 -2
  255. package/dist/src/chat-commands/index.js.map +1 -1
  256. package/dist/src/chat-commands/processor.js +22 -21
  257. package/dist/src/chat-commands/processor.js.map +1 -1
  258. package/dist/src/chat-commands/session-key.d.ts +3 -15
  259. package/dist/src/chat-commands/session-key.js +3 -49
  260. package/dist/src/chat-commands/session-key.js.map +1 -1
  261. package/dist/src/chat-commands/types.d.ts +4 -0
  262. package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
  263. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  264. package/dist/src/cli/commands/config.js +1 -1
  265. package/dist/src/cli/commands/doctor/checks/channel-config.js +14 -1
  266. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  267. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  268. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  269. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  270. package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
  271. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  272. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  273. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  274. package/dist/src/cli/commands/extension-create.js +1 -1
  275. package/dist/src/cli/commands/extension-dev.js +2 -2
  276. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  277. package/dist/src/cli/commands/extension-pack.js +2 -2
  278. package/dist/src/cli/commands/extension.js +3 -3
  279. package/dist/src/cli/commands/gateway/logs.js +1 -1
  280. package/dist/src/cli/commands/image.js +1 -1
  281. package/dist/src/cli/commands/init.js +2 -2
  282. package/dist/src/cli/commands/models.js +1 -1
  283. package/dist/src/cli/commands/skills-test.js +1 -1
  284. package/dist/src/cli/templates.js +1 -1
  285. package/dist/src/cli/utils/gateway-client.js +1 -1
  286. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  287. package/dist/src/config/agent-profile.js +1 -1
  288. package/dist/src/config/agent-typed-models.js +1 -1
  289. package/dist/src/config/gateway-bind.js +1 -1
  290. package/dist/src/config/index.js +7 -7
  291. package/dist/src/config/loader.js +4 -4
  292. package/dist/src/config/models-json.js +2 -2
  293. package/dist/src/config/paths-state.js +1 -1
  294. package/dist/src/config/paths.js +1 -1
  295. package/dist/src/config/profile.js +1 -1
  296. package/dist/src/config/reload.js +1 -1
  297. package/dist/src/config/rules.js +5 -0
  298. package/dist/src/config/rules.js.map +1 -1
  299. package/dist/src/config/schema.d.ts +8 -0
  300. package/dist/src/config/schema.js +7 -0
  301. package/dist/src/config/schema.js.map +1 -1
  302. package/dist/src/config/web-patch.d.ts +1 -0
  303. package/dist/src/config/web-patch.js +1 -0
  304. package/dist/src/config/web-patch.js.map +1 -1
  305. package/dist/src/config/workspace-path.js +1 -1
  306. package/dist/src/connectors/builtin-catalog.js +180 -1
  307. package/dist/src/connectors/builtin-catalog.js.map +1 -1
  308. package/dist/src/connectors/health.js +18 -9
  309. package/dist/src/connectors/health.js.map +1 -1
  310. package/dist/src/connectors/types.d.ts +19 -0
  311. package/dist/src/connectors/usage.js +12 -4
  312. package/dist/src/connectors/usage.js.map +1 -1
  313. package/dist/src/cron/executor.js +1 -1
  314. package/dist/src/cron/service.js +1 -1
  315. package/dist/src/daemon/constants.js +1 -1
  316. package/dist/src/daemon/install-plan.js +2 -2
  317. package/dist/src/daemon/launchd.js +2 -2
  318. package/dist/src/daemon/schtasks.js +2 -2
  319. package/dist/src/daemon/systemd.js +2 -2
  320. package/dist/src/extensions/bundle-mcp.js +1 -1
  321. package/dist/src/extensions/discover-extensions.js +2 -2
  322. package/dist/src/extensions/health.js +1 -1
  323. package/dist/src/extensions/install.js +2 -2
  324. package/dist/src/extensions/loader.js +2 -2
  325. package/dist/src/extensions/lockfile.js +3 -3
  326. package/dist/src/extensions/security.js +1 -1
  327. package/dist/src/extensions/types/tui.d.ts +2 -0
  328. package/dist/src/extensions/update.js +2 -2
  329. package/dist/src/gateway/agents-admin.js +2 -2
  330. package/dist/src/gateway/file-path-classifier.js +2 -2
  331. package/dist/src/gateway/heartbeat/service.js +13 -1
  332. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  333. package/dist/src/gateway/hono/app.js +18 -5
  334. package/dist/src/gateway/hono/app.js.map +1 -1
  335. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
  336. package/dist/src/gateway/hono/lib/config-payload.js +7 -4
  337. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  338. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  339. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  340. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  341. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +19 -5
  342. package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -1
  343. package/dist/src/gateway/hono/oauth-async.js +1 -1
  344. package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
  345. package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
  346. package/dist/src/gateway/hono/routes/agents.js +1 -1
  347. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  348. package/dist/src/gateway/hono/routes/channels.js +18 -14
  349. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  350. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
  351. package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
  352. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  353. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  354. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  355. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  356. package/dist/src/gateway/hono/routes/goals.js +16 -3
  357. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  358. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  359. package/dist/src/gateway/hono/routes/logs.js +1 -0
  360. package/dist/src/gateway/hono/routes/logs.js.map +1 -1
  361. package/dist/src/gateway/hono/routes/mcp.js +27 -8
  362. package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
  363. package/dist/src/gateway/hono/routes/models.js +1 -1
  364. package/dist/src/gateway/hono/routes/notes.js +14 -2
  365. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  366. package/dist/src/gateway/hono/routes/sessions.js +62 -4
  367. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  368. package/dist/src/gateway/hono/routes/shares.js +1 -1
  369. package/dist/src/gateway/hono/routes/workflows.js +1 -1
  370. package/dist/src/gateway/hono/routes/workspace.js +5 -68
  371. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  372. package/dist/src/gateway/hono/sse.d.ts +2 -2
  373. package/dist/src/gateway/hono/sse.js +7 -15
  374. package/dist/src/gateway/hono/sse.js.map +1 -1
  375. package/dist/src/gateway/lock.js +3 -3
  376. package/dist/src/gateway/ports.js +1 -1
  377. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  378. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  379. package/dist/src/gateway/rate-limit/buckets.js.map +1 -1
  380. package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
  381. package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
  382. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
  383. package/dist/src/gateway/service/agent-runner.d.ts +2 -3
  384. package/dist/src/gateway/service/agent-runner.js +9 -22
  385. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  386. package/dist/src/gateway/service/config-coordinator.js +1 -1
  387. package/dist/src/gateway/service/marketplace-service.js +2 -2
  388. package/dist/src/gateway/service/run-gateway-agent.js +9 -7
  389. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  390. package/dist/src/gateway/service/sessions-api.d.ts +9 -0
  391. package/dist/src/gateway/service/sessions-api.js +11 -0
  392. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  393. package/dist/src/gateway/service.d.ts +1 -1
  394. package/dist/src/gateway/service.js +23 -9
  395. package/dist/src/gateway/service.js.map +1 -1
  396. package/dist/src/gateway/workspace-file-search.d.ts +9 -0
  397. package/dist/src/gateway/workspace-file-search.js +76 -0
  398. package/dist/src/gateway/workspace-file-search.js.map +1 -0
  399. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  400. package/dist/src/goals/goal-notifications.d.ts +2 -0
  401. package/dist/src/goals/goal-notifications.js +16 -11
  402. package/dist/src/goals/goal-notifications.js.map +1 -1
  403. package/dist/src/goals/goal-service.js +1 -6
  404. package/dist/src/goals/goal-service.js.map +1 -1
  405. package/dist/src/goals/goal-workflow-judge.js +2 -2
  406. package/dist/src/i18n/goals-bundle.js +1 -1
  407. package/dist/src/i18n/index.js +1 -1
  408. package/dist/src/i18n/share-tool-bundle.js +2 -2
  409. package/dist/src/infra/brew.js +1 -1
  410. package/dist/src/infra/package-json.js +1 -1
  411. package/dist/src/infra/package-update-steps.js +1 -1
  412. package/dist/src/infra/path-env.js +2 -2
  413. package/dist/src/infra/restart.js +1 -1
  414. package/dist/src/infra/stable-node-path.js +1 -1
  415. package/dist/src/infra/update-check.js +1 -1
  416. package/dist/src/infra/update-global.js +1 -1
  417. package/dist/src/infra/update-lock.js +2 -2
  418. package/dist/src/infra/update-restart.js +1 -1
  419. package/dist/src/infra/update-runner.js +1 -1
  420. package/dist/src/infra/update-startup.js +1 -1
  421. package/dist/src/infra/write-file-atomic.js +2 -2
  422. package/dist/src/media/store.js +1 -1
  423. package/dist/src/notes/agent-context.js +1 -1
  424. package/dist/src/notes/service.js +1 -1
  425. package/dist/src/notes/store.js +2 -2
  426. package/dist/src/project-trust/trust-store.js +4 -2
  427. package/dist/src/project-trust/trust-store.js.map +1 -1
  428. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  429. package/dist/src/providers/index.js +1 -1
  430. package/dist/src/providers/model-registry.js +4 -4
  431. package/dist/src/session/index.d.ts +1 -1
  432. package/dist/src/session/index.js +2 -2
  433. package/dist/src/session/init-session-turn.js +7 -10
  434. package/dist/src/session/init-session-turn.js.map +1 -1
  435. package/dist/src/session/manager.d.ts +5 -1
  436. package/dist/src/session/manager.js +5 -2
  437. package/dist/src/session/manager.js.map +1 -1
  438. package/dist/src/session/reset-type.d.ts +0 -2
  439. package/dist/src/session/reset-type.js +3 -9
  440. package/dist/src/session/reset-type.js.map +1 -1
  441. package/dist/src/session/resolve-session.js +10 -21
  442. package/dist/src/session/resolve-session.js.map +1 -1
  443. package/dist/src/session/session-title.js +2 -2
  444. package/dist/src/session/store.d.ts +11 -3
  445. package/dist/src/session/store.js +30 -14
  446. package/dist/src/session/store.js.map +1 -1
  447. package/dist/src/session/types.d.ts +2 -4
  448. package/dist/src/session/types.js.map +1 -1
  449. package/dist/src/share/share-auto.js +2 -2
  450. package/dist/src/share/share-store.js +3 -3
  451. package/dist/src/share/share-thumbnail.js +2 -2
  452. package/dist/src/share/share-zip.js +1 -1
  453. package/dist/src/share/site-share-store.js +3 -3
  454. package/dist/src/share/site-static-serve.js +1 -1
  455. package/dist/src/storage/sqlite/connection.js +1 -1
  456. package/dist/src/storage/sqlite/index.d.ts +2 -2
  457. package/dist/src/storage/sqlite/index.js +3 -3
  458. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  459. package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
  460. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  461. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  462. package/dist/src/storage/sqlite/migrations/runner.js +5 -5
  463. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  464. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  465. package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
  466. package/dist/src/storage/sqlite/row-mappers.js +11 -14
  467. package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
  468. package/dist/src/storage/sqlite/schema.js +4 -4
  469. package/dist/src/storage/sqlite/schema.js.map +1 -1
  470. package/dist/src/storage/sqlite/schema.sql +37 -10
  471. package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
  472. package/dist/src/storage/sqlite/session-metadata.js +18 -72
  473. package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
  474. package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
  475. package/dist/src/storage/sqlite/session-repository.js +34 -40
  476. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  477. package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
  478. package/dist/src/storage/sqlite/transcript-repository.js +52 -52
  479. package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
  480. package/dist/src/tui/backends/embedded-backend.d.ts +18 -4
  481. package/dist/src/tui/backends/embedded-backend.js +100 -1
  482. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  483. package/dist/src/tui/backends/gateway-sse-backend.d.ts +5 -1
  484. package/dist/src/tui/backends/gateway-sse-backend.js +45 -2
  485. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  486. package/dist/src/tui/clipboard-image.js +3 -3
  487. package/dist/src/tui/components/chat-log.d.ts +2 -0
  488. package/dist/src/tui/components/chat-log.js +19 -0
  489. package/dist/src/tui/components/chat-log.js.map +1 -1
  490. package/dist/src/tui/extension-host/autocomplete.d.ts +3 -2
  491. package/dist/src/tui/extension-host/autocomplete.js +29 -12
  492. package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
  493. package/dist/src/tui/extension-host/load-extensions.js +1 -1
  494. package/dist/src/tui/extension-host/runtime.d.ts +12 -0
  495. package/dist/src/tui/extension-host/runtime.js +6 -4
  496. package/dist/src/tui/extension-host/runtime.js.map +1 -1
  497. package/dist/src/tui/theme-manager.js +1 -1
  498. package/dist/src/tui/tui-backend.d.ts +23 -0
  499. package/dist/src/tui/tui-command-formatters.js +4 -4
  500. package/dist/src/tui/tui-commands.d.ts +16 -3
  501. package/dist/src/tui/tui-commands.js +134 -27
  502. package/dist/src/tui/tui-commands.js.map +1 -1
  503. package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
  504. package/dist/src/tui/tui-file-autocomplete.js +26 -0
  505. package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
  506. package/dist/src/tui/tui-keybindings-file.js +1 -1
  507. package/dist/src/tui/tui-picker-overlay.js +1 -1
  508. package/dist/src/tui/tui-scoped-models.js +2 -2
  509. package/dist/src/tui/tui-settings.js +1 -1
  510. package/dist/src/tui/tui-startup-resources.js +1 -1
  511. package/dist/src/tui/tui-startup-text.js +1 -1
  512. package/dist/src/tui/tui-startup-text.js.map +1 -1
  513. package/dist/src/tui/tui.js +106 -17
  514. package/dist/src/tui/tui.js.map +1 -1
  515. package/dist/src/tunnel/frpc-binary.js +4 -4
  516. package/dist/src/tunnel/frpc-config.js +1 -1
  517. package/dist/src/tunnel/frpc-extract.js +1 -1
  518. package/dist/src/tunnel/tunnel-state.js +1 -1
  519. package/dist/src/utils/logger/audit.js +1 -1
  520. package/dist/src/utils/logger/context.d.ts +2 -2
  521. package/dist/src/utils/logger/context.js +2 -1
  522. package/dist/src/utils/logger/context.js.map +1 -1
  523. package/dist/src/utils/logger/log-store.js +2 -1
  524. package/dist/src/utils/logger/log-store.js.map +1 -1
  525. package/dist/src/utils/logger/pino-record.js +3 -0
  526. package/dist/src/utils/logger/pino-record.js.map +1 -1
  527. package/dist/src/utils/logger/rotation.js +1 -1
  528. package/dist/src/utils/logger/streams.js +1 -1
  529. package/dist/src/utils/logger/types.d.ts +5 -0
  530. package/dist/src/utils/logger/types.js.map +1 -1
  531. package/dist/src/voice/tts/audio.js +1 -1
  532. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  533. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  534. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  535. package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
  536. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  537. package/dist/src/workflows/store/event-store.js +1 -1
  538. package/dist/src/workflows/store/run-store.js +1 -1
  539. package/package.json +1 -1
  540. package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
  541. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
  542. package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
  543. package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
  544. package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
  545. package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
  546. package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
  547. package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
  548. package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
  549. package/dist/gateway/static/root/assets/goals-settings-ceEBjnfc.js +0 -1
  550. package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
  551. package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
  552. package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
  553. package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
  554. package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
  555. package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
  556. package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
  557. package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
  558. package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
  559. package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
  560. package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
  561. package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
  562. package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
  563. package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
  564. package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
  565. package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
  566. package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
  567. package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
@@ -2,8 +2,9 @@ import { init_paths, resolveSkillsDir } from "../../config/paths.js";
2
2
  import { parseFrontmatter } from "../../markdown/frontmatter.js";
3
3
  import { fuzzyFindText, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings } from "../tools/edit-diff.js";
4
4
  import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
5
- import { existsSync, realpathSync } from "fs";
5
+ import { resolveWorkspaceSkillsDir } from "./workspace-skills-dir.js";
6
6
  import { join, resolve, sep } from "path";
7
+ import { existsSync, realpathSync } from "fs";
7
8
  import { mkdir, writeFile } from "fs/promises";
8
9
  //#region src/agent/skills/skill-manage-ops.ts
9
10
  /**
@@ -97,7 +98,7 @@ function resolveGlobalSkillsRoot() {
97
98
  return resolveSkillsDir();
98
99
  }
99
100
  function resolveWorkspaceSkillsRoot(workspace) {
100
- return resolve(workspace, "skills");
101
+ return resolveWorkspaceSkillsDir(workspace);
101
102
  }
102
103
  function canWriteToPath(skillBaseDir, workspace, policy) {
103
104
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manage-ops.js","names":[],"sources":["../../../../src/agent/skills/skill-manage-ops.ts"],"sourcesContent":["/**\n * Shared logic for the skill_manage agent tool (create / edit / patch / delete / write_file / remove_file).\n */\n\nimport { existsSync, realpathSync } from 'fs';\nimport { join, resolve, sep } from 'path';\nimport { mkdir, writeFile } from 'fs/promises';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport type { Skill } from './types.js';\nimport type { SkillsConfig } from './types.js';\nimport { scanSkillDirectory, formatScanSummary } from './scanner.js';\n\nexport const SKILL_MANAGE_ALLOWED_SUBDIRS = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport const SKILL_MANAGE_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;\nexport const DEFAULT_MAX_SKILL_MD_CHARS = 100_000;\nexport const DEFAULT_MAX_SUPPORT_FILE_BYTES = 1_048_576;\n\nexport type AgentWritePolicy = 'global' | 'workspace' | 'both';\n\nexport function effectiveAgentWritePolicy(cfg?: SkillsConfig): AgentWritePolicy {\n const p = cfg?.agentWritePolicy;\n if (p === 'workspace' || p === 'both') return p;\n return 'global';\n}\n\nexport function maxSkillMdChars(_cfg?: SkillsConfig): number {\n return DEFAULT_MAX_SKILL_MD_CHARS;\n}\n\nexport function maxSupportFileBytes(cfg?: SkillsConfig): number {\n const n = cfg?.limits?.maxSkillFileBytes;\n if (typeof n === 'number' && n > 0) return n;\n return DEFAULT_MAX_SUPPORT_FILE_BYTES;\n}\n\nexport function validateSkillNameSegment(name: string, label: string): string | null {\n if (!name?.trim()) return `${label} is required.`;\n if (name.length > 64) return `${label} must be at most 64 characters.`;\n if (!SKILL_MANAGE_NAME_RE.test(name)) {\n return `${label} must match ${SKILL_MANAGE_NAME_RE}: lowercase letters, digits, ., _, -`;\n }\n return null;\n}\n\nexport function validateSkillMdContent(\n content: string,\n expectedName: string,\n maxChars: number,\n): { ok: true } | { ok: false; error: string } {\n if (!content.trim()) return { ok: false, error: 'Content cannot be empty.' };\n if (content.length > maxChars) {\n return { ok: false, error: `SKILL.md exceeds limit (${maxChars} characters).` };\n }\n if (!content.startsWith('---')) {\n return { ok: false, error: 'SKILL.md must start with YAML frontmatter (---).' };\n }\n const close = /\\r?\\n---\\s*\\r?\\n/.exec(content.slice(3));\n if (!close) {\n return { ok: false, error: 'Frontmatter must be closed with a line --- before the body.' };\n }\n const { frontmatter, content: body } = parseFrontmatter<Record<string, unknown>>(content);\n const name = frontmatter.name;\n const desc = frontmatter.description;\n if (typeof name !== 'string' || !name.trim()) {\n return { ok: false, error: 'Frontmatter must include a string name field.' };\n }\n if (typeof desc !== 'string' || !desc.trim()) {\n return { ok: false, error: 'Frontmatter must include a string description field.' };\n }\n if (name.trim() !== expectedName) {\n return {\n ok: false,\n error: `Frontmatter name \"${name.trim()}\" must match skill name \"${expectedName}\".`,\n };\n }\n if (!body?.trim()) {\n return { ok: false, error: 'SKILL.md must have a non-empty body after frontmatter.' };\n }\n return { ok: true };\n}\n\nfunction resolvedPathPrefix(dir: string): string {\n const r = resolve(dir);\n return r.endsWith(sep) ? r : r + sep;\n}\n\n/** Whether `filePath` is equal to `dir` or strictly inside it (resolved). */\nexport function isPathInsideDir(dir: string, filePath: string): boolean {\n try {\n const base = resolve(dir);\n const target = resolve(filePath);\n const baseReal = existsSync(base) ? realpathSync(base) : base;\n const targetReal = existsSync(target) ? realpathSync(target) : target;\n const prefix = resolvedPathPrefix(baseReal);\n return targetReal === baseReal || targetReal.startsWith(prefix);\n } catch {\n return false;\n }\n}\n\nexport function resolveGlobalSkillsRoot(): string {\n return resolveSkillsDir();\n}\n\nexport function resolveWorkspaceSkillsRoot(workspace: string): string {\n return resolve(workspace, 'skills');\n}\n\nexport function canWriteToPath(\n skillBaseDir: string,\n workspace: string,\n policy: AgentWritePolicy,\n): boolean {\n try {\n const baseResolved = existsSync(skillBaseDir) ? realpathSync(skillBaseDir) : resolve(skillBaseDir);\n const globalRoot = resolveGlobalSkillsRoot();\n const wsRoot = resolveWorkspaceSkillsRoot(workspace);\n const underGlobal = isPathInsideDir(globalRoot, baseResolved);\n const underWs = isPathInsideDir(wsRoot, baseResolved);\n if (policy === 'global') return underGlobal;\n if (policy === 'workspace') return underWs;\n return underGlobal || underWs;\n } catch {\n return false;\n }\n}\n\nexport function mutatableSkillOrNull(\n skill: Skill | undefined,\n workspace: string,\n policy: AgentWritePolicy,\n): Skill | null {\n if (!skill) return null;\n if (skill.source === 'builtin' || skill.source === 'extra') return null;\n if (!canWriteToPath(skill.baseDir, workspace, policy)) return null;\n return skill;\n}\n\nexport function validateSupportingRelativePath(filePath: string): string | null {\n if (!filePath?.trim()) return 'file_path is required.';\n const norm = filePath.replace(/\\\\/g, '/');\n if (norm.includes('..')) return \"Path traversal ('..') is not allowed.\";\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return 'file_path must be relative to the skill directory.';\n }\n const parts = norm.split('/').filter(Boolean);\n if (parts.length < 2) {\n return 'Provide a file path with a subdirectory, e.g. references/notes.md';\n }\n if (!SKILL_MANAGE_ALLOWED_SUBDIRS.has(parts[0]!)) {\n return `File must be under one of: ${[...SKILL_MANAGE_ALLOWED_SUBDIRS].join(', ')}.`;\n }\n return null;\n}\n\nexport async function atomicWriteUtf8(filePath: string, content: string): Promise<void> {\n const dir = resolve(filePath, '..');\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, 'utf-8');\n}\n\n/** Scan skill dir; returns error message if critical findings (caller rolls back). */\nexport async function scanSkillDirOrError(skillDir: string, skillName: string): Promise<string | null> {\n const summary = await scanSkillDirectory(skillDir);\n if (summary.critical > 0) {\n return `Security scan blocked this change:\\n${formatScanSummary(summary, skillName)}`;\n }\n return null;\n}\n\nexport function resolveCreateSkillDir(\n name: string,\n category: string | undefined,\n writeTarget: 'global' | 'workspace',\n workspace: string,\n policy: AgentWritePolicy,\n): { ok: true; dir: string } | { ok: false; error: string } {\n if (writeTarget === 'global' && policy === 'workspace') {\n return { ok: false, error: 'Creating under global skills is not allowed (skills.agentWritePolicy).' };\n }\n if (writeTarget === 'workspace' && policy === 'global') {\n return { ok: false, error: 'Creating under workspace skills is not allowed (skills.agentWritePolicy).' };\n }\n const root =\n writeTarget === 'global' ? resolveGlobalSkillsRoot() : resolveWorkspaceSkillsRoot(workspace);\n const dir = category?.trim() ? join(root, category.trim(), name) : join(root, name);\n return { ok: true, dir };\n}\n\nexport function ensureCategorySegment(category: string | undefined): string | null {\n if (category === undefined || category === null || category === '') return null;\n if (typeof category !== 'string') return 'category must be a string.';\n const c = category.trim();\n if (!c) return null;\n if (c.includes('/') || c.includes('\\\\')) return 'category must be a single path segment.';\n return validateSkillNameSegment(c, 'category');\n}\n\nimport { normalizeToLF, restoreLineEndings, fuzzyFindText, normalizeForFuzzyMatch } from '../tools/edit-diff.js';\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n\nexport function applyPatchToContent(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean,\n): { ok: true; next: string; replacements: number } | { ok: false; error: string } {\n if (!oldString) return { ok: false, error: 'old_string is required for patch.' };\n if (newString === undefined) {\n return { ok: false, error: 'new_string is required (use empty string to delete matched text).' };\n }\n\n const lineEnding = detectLineEnding(content);\n const normalized = normalizeToLF(content);\n const oldN = normalizeToLF(oldString);\n const newN = normalizeToLF(newString);\n\n if (replaceAll) {\n const parts = normalized.split(oldN);\n const count = parts.length - 1;\n if (count === 0) {\n return { ok: false, error: 'old_string not found for replace_all.' };\n }\n const merged = parts.join(newN);\n return { ok: true, next: restoreLineEndings(merged, lineEnding), replacements: count };\n }\n\n const match = fuzzyFindText(normalized, oldN);\n if (!match.found) {\n return { ok: false, error: 'old_string not found in file.' };\n }\n const base = match.contentForReplacement;\n const fuzzyContent = normalizeForFuzzyMatch(normalizeToLF(base));\n const fuzzyOld = normalizeForFuzzyMatch(oldN);\n const occurrences = fuzzyOld ? fuzzyContent.split(fuzzyOld).length - 1 : 0;\n if (occurrences > 1) {\n return { ok: false, error: `Found ${occurrences} matches; narrow old_string or use replace_all.` };\n }\n const next =\n base.slice(0, match.index) + newN + base.slice(match.index + match.matchLength);\n return { ok: true, next: restoreLineEndings(next, lineEnding), replacements: 1 };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skill-manage-ops.js","names":[],"sources":["../../../../src/agent/skills/skill-manage-ops.ts"],"sourcesContent":["/**\n * Shared logic for the skill_manage agent tool (create / edit / patch / delete / write_file / remove_file).\n */\n\nimport { existsSync, realpathSync } from 'fs';\nimport { join, resolve, sep } from 'path';\nimport { mkdir, writeFile } from 'fs/promises';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveSkillsDir } from '../../config/paths.js';\nimport type { Skill } from './types.js';\nimport type { SkillsConfig } from './types.js';\nimport { scanSkillDirectory, formatScanSummary } from './scanner.js';\nimport { resolveWorkspaceSkillsDir } from './workspace-skills-dir.js';\n\nexport const SKILL_MANAGE_ALLOWED_SUBDIRS = new Set(['references', 'templates', 'scripts', 'assets']);\n\nexport const SKILL_MANAGE_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;\nexport const DEFAULT_MAX_SKILL_MD_CHARS = 100_000;\nexport const DEFAULT_MAX_SUPPORT_FILE_BYTES = 1_048_576;\n\nexport type AgentWritePolicy = 'global' | 'workspace' | 'both';\n\nexport function effectiveAgentWritePolicy(cfg?: SkillsConfig): AgentWritePolicy {\n const p = cfg?.agentWritePolicy;\n if (p === 'workspace' || p === 'both') return p;\n return 'global';\n}\n\nexport function maxSkillMdChars(_cfg?: SkillsConfig): number {\n return DEFAULT_MAX_SKILL_MD_CHARS;\n}\n\nexport function maxSupportFileBytes(cfg?: SkillsConfig): number {\n const n = cfg?.limits?.maxSkillFileBytes;\n if (typeof n === 'number' && n > 0) return n;\n return DEFAULT_MAX_SUPPORT_FILE_BYTES;\n}\n\nexport function validateSkillNameSegment(name: string, label: string): string | null {\n if (!name?.trim()) return `${label} is required.`;\n if (name.length > 64) return `${label} must be at most 64 characters.`;\n if (!SKILL_MANAGE_NAME_RE.test(name)) {\n return `${label} must match ${SKILL_MANAGE_NAME_RE}: lowercase letters, digits, ., _, -`;\n }\n return null;\n}\n\nexport function validateSkillMdContent(\n content: string,\n expectedName: string,\n maxChars: number,\n): { ok: true } | { ok: false; error: string } {\n if (!content.trim()) return { ok: false, error: 'Content cannot be empty.' };\n if (content.length > maxChars) {\n return { ok: false, error: `SKILL.md exceeds limit (${maxChars} characters).` };\n }\n if (!content.startsWith('---')) {\n return { ok: false, error: 'SKILL.md must start with YAML frontmatter (---).' };\n }\n const close = /\\r?\\n---\\s*\\r?\\n/.exec(content.slice(3));\n if (!close) {\n return { ok: false, error: 'Frontmatter must be closed with a line --- before the body.' };\n }\n const { frontmatter, content: body } = parseFrontmatter<Record<string, unknown>>(content);\n const name = frontmatter.name;\n const desc = frontmatter.description;\n if (typeof name !== 'string' || !name.trim()) {\n return { ok: false, error: 'Frontmatter must include a string name field.' };\n }\n if (typeof desc !== 'string' || !desc.trim()) {\n return { ok: false, error: 'Frontmatter must include a string description field.' };\n }\n if (name.trim() !== expectedName) {\n return {\n ok: false,\n error: `Frontmatter name \"${name.trim()}\" must match skill name \"${expectedName}\".`,\n };\n }\n if (!body?.trim()) {\n return { ok: false, error: 'SKILL.md must have a non-empty body after frontmatter.' };\n }\n return { ok: true };\n}\n\nfunction resolvedPathPrefix(dir: string): string {\n const r = resolve(dir);\n return r.endsWith(sep) ? r : r + sep;\n}\n\n/** Whether `filePath` is equal to `dir` or strictly inside it (resolved). */\nexport function isPathInsideDir(dir: string, filePath: string): boolean {\n try {\n const base = resolve(dir);\n const target = resolve(filePath);\n const baseReal = existsSync(base) ? realpathSync(base) : base;\n const targetReal = existsSync(target) ? realpathSync(target) : target;\n const prefix = resolvedPathPrefix(baseReal);\n return targetReal === baseReal || targetReal.startsWith(prefix);\n } catch {\n return false;\n }\n}\n\nexport function resolveGlobalSkillsRoot(): string {\n return resolveSkillsDir();\n}\n\nexport function resolveWorkspaceSkillsRoot(workspace: string): string {\n return resolveWorkspaceSkillsDir(workspace);\n}\n\nexport function canWriteToPath(\n skillBaseDir: string,\n workspace: string,\n policy: AgentWritePolicy,\n): boolean {\n try {\n const baseResolved = existsSync(skillBaseDir) ? realpathSync(skillBaseDir) : resolve(skillBaseDir);\n const globalRoot = resolveGlobalSkillsRoot();\n const wsRoot = resolveWorkspaceSkillsRoot(workspace);\n const underGlobal = isPathInsideDir(globalRoot, baseResolved);\n const underWs = isPathInsideDir(wsRoot, baseResolved);\n if (policy === 'global') return underGlobal;\n if (policy === 'workspace') return underWs;\n return underGlobal || underWs;\n } catch {\n return false;\n }\n}\n\nexport function mutatableSkillOrNull(\n skill: Skill | undefined,\n workspace: string,\n policy: AgentWritePolicy,\n): Skill | null {\n if (!skill) return null;\n if (skill.source === 'builtin' || skill.source === 'extra') return null;\n if (!canWriteToPath(skill.baseDir, workspace, policy)) return null;\n return skill;\n}\n\nexport function validateSupportingRelativePath(filePath: string): string | null {\n if (!filePath?.trim()) return 'file_path is required.';\n const norm = filePath.replace(/\\\\/g, '/');\n if (norm.includes('..')) return \"Path traversal ('..') is not allowed.\";\n if (norm.startsWith('/') || /^[A-Za-z]:/.test(norm)) {\n return 'file_path must be relative to the skill directory.';\n }\n const parts = norm.split('/').filter(Boolean);\n if (parts.length < 2) {\n return 'Provide a file path with a subdirectory, e.g. references/notes.md';\n }\n if (!SKILL_MANAGE_ALLOWED_SUBDIRS.has(parts[0]!)) {\n return `File must be under one of: ${[...SKILL_MANAGE_ALLOWED_SUBDIRS].join(', ')}.`;\n }\n return null;\n}\n\nexport async function atomicWriteUtf8(filePath: string, content: string): Promise<void> {\n const dir = resolve(filePath, '..');\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, 'utf-8');\n}\n\n/** Scan skill dir; returns error message if critical findings (caller rolls back). */\nexport async function scanSkillDirOrError(skillDir: string, skillName: string): Promise<string | null> {\n const summary = await scanSkillDirectory(skillDir);\n if (summary.critical > 0) {\n return `Security scan blocked this change:\\n${formatScanSummary(summary, skillName)}`;\n }\n return null;\n}\n\nexport function resolveCreateSkillDir(\n name: string,\n category: string | undefined,\n writeTarget: 'global' | 'workspace',\n workspace: string,\n policy: AgentWritePolicy,\n): { ok: true; dir: string } | { ok: false; error: string } {\n if (writeTarget === 'global' && policy === 'workspace') {\n return { ok: false, error: 'Creating under global skills is not allowed (skills.agentWritePolicy).' };\n }\n if (writeTarget === 'workspace' && policy === 'global') {\n return { ok: false, error: 'Creating under workspace skills is not allowed (skills.agentWritePolicy).' };\n }\n const root =\n writeTarget === 'global' ? resolveGlobalSkillsRoot() : resolveWorkspaceSkillsRoot(workspace);\n const dir = category?.trim() ? join(root, category.trim(), name) : join(root, name);\n return { ok: true, dir };\n}\n\nexport function ensureCategorySegment(category: string | undefined): string | null {\n if (category === undefined || category === null || category === '') return null;\n if (typeof category !== 'string') return 'category must be a string.';\n const c = category.trim();\n if (!c) return null;\n if (c.includes('/') || c.includes('\\\\')) return 'category must be a single path segment.';\n return validateSkillNameSegment(c, 'category');\n}\n\nimport { normalizeToLF, restoreLineEndings, fuzzyFindText, normalizeForFuzzyMatch } from '../tools/edit-diff.js';\n\nfunction detectLineEnding(content: string): '\\r\\n' | '\\n' {\n const crlfIdx = content.indexOf('\\r\\n');\n const lfIdx = content.indexOf('\\n');\n if (lfIdx === -1) return '\\n';\n if (crlfIdx === -1) return '\\n';\n return crlfIdx < lfIdx ? '\\r\\n' : '\\n';\n}\n\nexport function applyPatchToContent(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean,\n): { ok: true; next: string; replacements: number } | { ok: false; error: string } {\n if (!oldString) return { ok: false, error: 'old_string is required for patch.' };\n if (newString === undefined) {\n return { ok: false, error: 'new_string is required (use empty string to delete matched text).' };\n }\n\n const lineEnding = detectLineEnding(content);\n const normalized = normalizeToLF(content);\n const oldN = normalizeToLF(oldString);\n const newN = normalizeToLF(newString);\n\n if (replaceAll) {\n const parts = normalized.split(oldN);\n const count = parts.length - 1;\n if (count === 0) {\n return { ok: false, error: 'old_string not found for replace_all.' };\n }\n const merged = parts.join(newN);\n return { ok: true, next: restoreLineEndings(merged, lineEnding), replacements: count };\n }\n\n const match = fuzzyFindText(normalized, oldN);\n if (!match.found) {\n return { ok: false, error: 'old_string not found in file.' };\n }\n const base = match.contentForReplacement;\n const fuzzyContent = normalizeForFuzzyMatch(normalizeToLF(base));\n const fuzzyOld = normalizeForFuzzyMatch(oldN);\n const occurrences = fuzzyOld ? fuzzyContent.split(fuzzyOld).length - 1 : 0;\n if (occurrences > 1) {\n return { ok: false, error: `Found ${occurrences} matches; narrow old_string or use replace_all.` };\n }\n const next =\n base.slice(0, match.index) + newN + base.slice(match.index + match.matchLength);\n return { ok: true, next: restoreLineEndings(next, lineEnding), replacements: 1 };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { resolveStateDir } from "../../config/paths-state.js";
2
- import { init_paths, resolveBundledSkillsDir } from "../../config/paths.js";
3
2
  import { createLogger } from "../../utils/logger/index.js";
4
3
  import { init_logger } from "../../utils/logger.js";
4
+ import { init_paths, resolveBundledSkillsDir } from "../../config/paths.js";
5
5
  import { createSkillConfigManager, isSkillEnabled } from "./config.js";
6
6
  import { formatSkillsForPrompt, selectSkillsVisibleInPrompt } from "./format-skills-prompt.js";
7
7
  import { createSkillLoader } from "./index.js";
@@ -1,5 +1,5 @@
1
- import { existsSync, realpathSync } from "fs";
2
1
  import { resolve, sep } from "path";
2
+ import { existsSync, realpathSync } from "fs";
3
3
  //#region src/agent/skills/skill-view-path.ts
4
4
  /**
5
5
  * Resolve safe paths for skill_view: only SKILL.md (default) or files under allowlisted subdirs.
@@ -4,8 +4,8 @@ import { parseFrontmatter } from "../../markdown/frontmatter.js";
4
4
  import { hasBinary } from "./installer.js";
5
5
  import { scanSkillDirectory } from "./scanner.js";
6
6
  import { parseSkillMetadata } from "./parse-skill-metadata.js";
7
- import { existsSync, readFileSync, readdirSync } from "fs";
8
7
  import { basename, join, relative } from "path";
8
+ import { existsSync, readFileSync, readdirSync } from "fs";
9
9
  //#region src/agent/skills/test-framework.ts
10
10
  /**
11
11
  * Skill Test Framework
@@ -114,7 +114,7 @@ export interface SkillsConfig {
114
114
  */
115
115
  toolGating?: boolean;
116
116
  /**
117
- * Where `skill_manage` may create or edit skills: global `~/.xopc/skills`, workspace `skills/`, or both.
117
+ * Where `skill_manage` may create or edit skills: global `~/.xopc/skills`, workspace `.xopc/skills/`, or both.
118
118
  * Default `global`.
119
119
  */
120
120
  agentWritePolicy?: 'global' | 'workspace' | 'both';
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { resolveWorkspaceSkillsDir } from "./workspace-skills-dir.js";
3
4
  import { watch } from "fs";
4
- import { join } from "path";
5
5
  //#region src/agent/skills/watcher.ts
6
6
  /**
7
7
  * Skill Watcher
@@ -102,10 +102,7 @@ function createSkillWatcher(loader, options) {
102
102
  */
103
103
  function createWatcherFromLoader(loader, options) {
104
104
  const watchDirs = [];
105
- if (options.workspaceDir) {
106
- const workspaceSkillsDir = join(options.workspaceDir, "skills");
107
- watchDirs.push(workspaceSkillsDir);
108
- }
105
+ if (options.workspaceDir) watchDirs.push(resolveWorkspaceSkillsDir(options.workspaceDir));
109
106
  if (options.builtinDir) watchDirs.push(options.builtinDir);
110
107
  if (options.globalDirs) watchDirs.push(...options.globalDirs);
111
108
  if (options.extraDirs) watchDirs.push(...options.extraDirs);
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.js","names":[],"sources":["../../../../src/agent/skills/watcher.ts"],"sourcesContent":["/**\n * Skill Watcher\n * \n * Watches skill directories for changes and triggers reloads.\n *\n */\n\nimport { watch } from 'fs';\nimport { join } from 'path';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillLoader } from './index.js';\n\nconst log = createLogger('SkillWatcher');\n\nexport interface SkillWatcherOptions {\n /** Debounce time in milliseconds */\n debounceMs?: number;\n /** Watch these directories */\n watchDirs: string[];\n}\n\nexport interface SkillWatcher {\n /** Start watching */\n start: () => void;\n /** Stop watching */\n stop: () => void;\n /** Check if watching is active */\n isWatching: () => boolean;\n /** Get last refresh time */\n getLastRefreshTime: () => number;\n}\n\n/**\n * Create a debounced reload function\n */\nfunction createDebouncedReload(\n loader: SkillLoader,\n debounceMs: number\n): () => void {\n let timeout: NodeJS.Timeout | null = null;\n let pendingReload = false;\n\n return () => {\n if (timeout) {\n pendingReload = true;\n return;\n }\n\n timeout = setTimeout(() => {\n timeout = null;\n \n if (pendingReload) {\n pendingReload = false;\n loader.reload();\n log.info('Skills reloaded after directory changes');\n }\n }, debounceMs);\n };\n}\n\n/**\n * Create a skill watcher\n */\nexport function createSkillWatcher(\n loader: SkillLoader,\n options: SkillWatcherOptions\n): SkillWatcher {\n const { watchDirs, debounceMs = 1000 } = options;\n \n const watchers: Array<{ watcher: ReturnType<typeof watch>; dir: string }> = [];\n const debouncedReload = createDebouncedReload(loader, debounceMs);\n let isWatching = false;\n let lastRefreshTime = Date.now();\n\n function watchDirectory(dir: string): void {\n try {\n const watcher = watch(dir, { recursive: true }, (eventType, filename) => {\n if (!filename) return;\n\n // Only care about SKILL.md files\n if (filename.toLowerCase() === 'skill.md') {\n log.debug({ eventType, filename, dir }, 'Skill file changed');\n lastRefreshTime = Date.now();\n debouncedReload();\n }\n\n // Also watch for new directories (potential new skills)\n if (eventType === 'rename') {\n log.debug({ eventType, filename, dir }, 'Directory changed, may be new skill');\n lastRefreshTime = Date.now();\n debouncedReload();\n }\n });\n\n watchers.push({ watcher, dir });\n log.info({ dir }, 'Watching skill directory');\n } catch (err) {\n log.warn({ dir, error: err }, 'Failed to watch skill directory');\n }\n }\n\n return {\n start: () => {\n if (isWatching) {\n log.warn('Watcher already started');\n return;\n }\n\n for (const dir of watchDirs) {\n watchDirectory(dir);\n }\n\n isWatching = true;\n log.info({ dirs: watchDirs }, 'Skill watcher started');\n },\n\n stop: () => {\n if (!isWatching) {\n return;\n }\n\n for (const { watcher } of watchers) {\n watcher.close();\n }\n\n watchers.length = 0;\n isWatching = false;\n log.info('Skill watcher stopped');\n },\n\n isWatching: () => isWatching,\n\n getLastRefreshTime: () => lastRefreshTime,\n };\n}\n\n/**\n * Create a skill watcher from loader configuration\n */\nexport function createWatcherFromLoader(\n loader: SkillLoader,\n options: {\n workspaceDir?: string;\n builtinDir?: string;\n globalDirs?: string[];\n extraDirs?: string[];\n debounceMs?: number;\n }\n): SkillWatcher | null {\n const watchDirs: string[] = [];\n\n // Add workspace skills directory\n if (options.workspaceDir) {\n const workspaceSkillsDir = join(options.workspaceDir, 'skills');\n watchDirs.push(workspaceSkillsDir);\n }\n\n // Add builtin directory\n if (options.builtinDir) {\n watchDirs.push(options.builtinDir);\n }\n\n // Add global directories\n if (options.globalDirs) {\n watchDirs.push(...options.globalDirs);\n }\n\n // Add extra directories\n if (options.extraDirs) {\n watchDirs.push(...options.extraDirs);\n }\n\n if (watchDirs.length === 0) {\n log.warn('No directories to watch');\n return null;\n }\n\n return createSkillWatcher(loader, {\n watchDirs,\n debounceMs: options.debounceMs ?? 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;aASqD;AAGrD,MAAM,MAAM,aAAa,eAAe;;;;AAuBxC,SAAS,sBACP,QACA,YACY;CACZ,IAAI,UAAiC;CACrC,IAAI,gBAAgB;AAEpB,cAAa;AACX,MAAI,SAAS;AACX,mBAAgB;AAChB;;AAGF,YAAU,iBAAiB;AACzB,aAAU;AAEV,OAAI,eAAe;AACjB,oBAAgB;AAChB,WAAO,QAAQ;AACf,QAAI,KAAK,0CAA0C;;KAEpD,WAAW;;;;;;AAOlB,SAAgB,mBACd,QACA,SACc;CACd,MAAM,EAAE,WAAW,aAAa,QAAS;CAEzC,MAAM,WAAsE,EAAE;CAC9E,MAAM,kBAAkB,sBAAsB,QAAQ,WAAW;CACjE,IAAI,aAAa;CACjB,IAAI,kBAAkB,KAAK,KAAK;CAEhC,SAAS,eAAe,KAAmB;AACzC,MAAI;GACF,MAAM,UAAU,MAAM,KAAK,EAAE,WAAW,MAAM,GAAG,WAAW,aAAa;AACvE,QAAI,CAAC,SAAU;AAGf,QAAI,SAAS,aAAa,KAAK,YAAY;AACzC,SAAI,MAAM;MAAE;MAAW;MAAU;MAAK,EAAE,qBAAqB;AAC7D,uBAAkB,KAAK,KAAK;AAC5B,sBAAiB;;AAInB,QAAI,cAAc,UAAU;AAC1B,SAAI,MAAM;MAAE;MAAW;MAAU;MAAK,EAAE,sCAAsC;AAC9E,uBAAkB,KAAK,KAAK;AAC5B,sBAAiB;;KAEnB;AAEF,YAAS,KAAK;IAAE;IAAS;IAAK,CAAC;AAC/B,OAAI,KAAK,EAAE,KAAK,EAAE,2BAA2B;WACtC,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,OAAO;IAAK,EAAE,kCAAkC;;;AAIpE,QAAO;EACL,aAAa;AACX,OAAI,YAAY;AACd,QAAI,KAAK,0BAA0B;AACnC;;AAGF,QAAK,MAAM,OAAO,UAChB,gBAAe,IAAI;AAGrB,gBAAa;AACb,OAAI,KAAK,EAAE,MAAM,WAAW,EAAE,wBAAwB;;EAGxD,YAAY;AACV,OAAI,CAAC,WACH;AAGF,QAAK,MAAM,EAAE,aAAa,SACxB,SAAQ,OAAO;AAGjB,YAAS,SAAS;AAClB,gBAAa;AACb,OAAI,KAAK,wBAAwB;;EAGnC,kBAAkB;EAElB,0BAA0B;EAC3B;;;;;AAMH,SAAgB,wBACd,QACA,SAOqB;CACrB,MAAM,YAAsB,EAAE;AAG9B,KAAI,QAAQ,cAAc;EACxB,MAAM,qBAAqB,KAAK,QAAQ,cAAc,SAAS;AAC/D,YAAU,KAAK,mBAAmB;;AAIpC,KAAI,QAAQ,WACV,WAAU,KAAK,QAAQ,WAAW;AAIpC,KAAI,QAAQ,WACV,WAAU,KAAK,GAAG,QAAQ,WAAW;AAIvC,KAAI,QAAQ,UACV,WAAU,KAAK,GAAG,QAAQ,UAAU;AAGtC,KAAI,UAAU,WAAW,GAAG;AAC1B,MAAI,KAAK,0BAA0B;AACnC,SAAO;;AAGT,QAAO,mBAAmB,QAAQ;EAChC;EACA,YAAY,QAAQ,cAAc;EACnC,CAAC"}
1
+ {"version":3,"file":"watcher.js","names":[],"sources":["../../../../src/agent/skills/watcher.ts"],"sourcesContent":["/**\n * Skill Watcher\n * \n * Watches skill directories for changes and triggers reloads.\n *\n */\n\nimport { watch } from 'fs';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillLoader } from './index.js';\nimport { resolveWorkspaceSkillsDir } from './workspace-skills-dir.js';\n\nconst log = createLogger('SkillWatcher');\n\nexport interface SkillWatcherOptions {\n /** Debounce time in milliseconds */\n debounceMs?: number;\n /** Watch these directories */\n watchDirs: string[];\n}\n\nexport interface SkillWatcher {\n /** Start watching */\n start: () => void;\n /** Stop watching */\n stop: () => void;\n /** Check if watching is active */\n isWatching: () => boolean;\n /** Get last refresh time */\n getLastRefreshTime: () => number;\n}\n\n/**\n * Create a debounced reload function\n */\nfunction createDebouncedReload(\n loader: SkillLoader,\n debounceMs: number\n): () => void {\n let timeout: NodeJS.Timeout | null = null;\n let pendingReload = false;\n\n return () => {\n if (timeout) {\n pendingReload = true;\n return;\n }\n\n timeout = setTimeout(() => {\n timeout = null;\n \n if (pendingReload) {\n pendingReload = false;\n loader.reload();\n log.info('Skills reloaded after directory changes');\n }\n }, debounceMs);\n };\n}\n\n/**\n * Create a skill watcher\n */\nexport function createSkillWatcher(\n loader: SkillLoader,\n options: SkillWatcherOptions\n): SkillWatcher {\n const { watchDirs, debounceMs = 1000 } = options;\n \n const watchers: Array<{ watcher: ReturnType<typeof watch>; dir: string }> = [];\n const debouncedReload = createDebouncedReload(loader, debounceMs);\n let isWatching = false;\n let lastRefreshTime = Date.now();\n\n function watchDirectory(dir: string): void {\n try {\n const watcher = watch(dir, { recursive: true }, (eventType, filename) => {\n if (!filename) return;\n\n // Only care about SKILL.md files\n if (filename.toLowerCase() === 'skill.md') {\n log.debug({ eventType, filename, dir }, 'Skill file changed');\n lastRefreshTime = Date.now();\n debouncedReload();\n }\n\n // Also watch for new directories (potential new skills)\n if (eventType === 'rename') {\n log.debug({ eventType, filename, dir }, 'Directory changed, may be new skill');\n lastRefreshTime = Date.now();\n debouncedReload();\n }\n });\n\n watchers.push({ watcher, dir });\n log.info({ dir }, 'Watching skill directory');\n } catch (err) {\n log.warn({ dir, error: err }, 'Failed to watch skill directory');\n }\n }\n\n return {\n start: () => {\n if (isWatching) {\n log.warn('Watcher already started');\n return;\n }\n\n for (const dir of watchDirs) {\n watchDirectory(dir);\n }\n\n isWatching = true;\n log.info({ dirs: watchDirs }, 'Skill watcher started');\n },\n\n stop: () => {\n if (!isWatching) {\n return;\n }\n\n for (const { watcher } of watchers) {\n watcher.close();\n }\n\n watchers.length = 0;\n isWatching = false;\n log.info('Skill watcher stopped');\n },\n\n isWatching: () => isWatching,\n\n getLastRefreshTime: () => lastRefreshTime,\n };\n}\n\n/**\n * Create a skill watcher from loader configuration\n */\nexport function createWatcherFromLoader(\n loader: SkillLoader,\n options: {\n workspaceDir?: string;\n builtinDir?: string;\n globalDirs?: string[];\n extraDirs?: string[];\n debounceMs?: number;\n }\n): SkillWatcher | null {\n const watchDirs: string[] = [];\n\n // Add project-local workspace skills directory\n if (options.workspaceDir) {\n watchDirs.push(resolveWorkspaceSkillsDir(options.workspaceDir));\n }\n\n // Add builtin directory\n if (options.builtinDir) {\n watchDirs.push(options.builtinDir);\n }\n\n // Add global directories\n if (options.globalDirs) {\n watchDirs.push(...options.globalDirs);\n }\n\n // Add extra directories\n if (options.extraDirs) {\n watchDirs.push(...options.extraDirs);\n }\n\n if (watchDirs.length === 0) {\n log.warn('No directories to watch');\n return null;\n }\n\n return createSkillWatcher(loader, {\n watchDirs,\n debounceMs: options.debounceMs ?? 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;aAQqD;AAIrD,MAAM,MAAM,aAAa,eAAe;;;;AAuBxC,SAAS,sBACP,QACA,YACY;CACZ,IAAI,UAAiC;CACrC,IAAI,gBAAgB;AAEpB,cAAa;AACX,MAAI,SAAS;AACX,mBAAgB;AAChB;;AAGF,YAAU,iBAAiB;AACzB,aAAU;AAEV,OAAI,eAAe;AACjB,oBAAgB;AAChB,WAAO,QAAQ;AACf,QAAI,KAAK,0CAA0C;;KAEpD,WAAW;;;;;;AAOlB,SAAgB,mBACd,QACA,SACc;CACd,MAAM,EAAE,WAAW,aAAa,QAAS;CAEzC,MAAM,WAAsE,EAAE;CAC9E,MAAM,kBAAkB,sBAAsB,QAAQ,WAAW;CACjE,IAAI,aAAa;CACjB,IAAI,kBAAkB,KAAK,KAAK;CAEhC,SAAS,eAAe,KAAmB;AACzC,MAAI;GACF,MAAM,UAAU,MAAM,KAAK,EAAE,WAAW,MAAM,GAAG,WAAW,aAAa;AACvE,QAAI,CAAC,SAAU;AAGf,QAAI,SAAS,aAAa,KAAK,YAAY;AACzC,SAAI,MAAM;MAAE;MAAW;MAAU;MAAK,EAAE,qBAAqB;AAC7D,uBAAkB,KAAK,KAAK;AAC5B,sBAAiB;;AAInB,QAAI,cAAc,UAAU;AAC1B,SAAI,MAAM;MAAE;MAAW;MAAU;MAAK,EAAE,sCAAsC;AAC9E,uBAAkB,KAAK,KAAK;AAC5B,sBAAiB;;KAEnB;AAEF,YAAS,KAAK;IAAE;IAAS;IAAK,CAAC;AAC/B,OAAI,KAAK,EAAE,KAAK,EAAE,2BAA2B;WACtC,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,OAAO;IAAK,EAAE,kCAAkC;;;AAIpE,QAAO;EACL,aAAa;AACX,OAAI,YAAY;AACd,QAAI,KAAK,0BAA0B;AACnC;;AAGF,QAAK,MAAM,OAAO,UAChB,gBAAe,IAAI;AAGrB,gBAAa;AACb,OAAI,KAAK,EAAE,MAAM,WAAW,EAAE,wBAAwB;;EAGxD,YAAY;AACV,OAAI,CAAC,WACH;AAGF,QAAK,MAAM,EAAE,aAAa,SACxB,SAAQ,OAAO;AAGjB,YAAS,SAAS;AAClB,gBAAa;AACb,OAAI,KAAK,wBAAwB;;EAGnC,kBAAkB;EAElB,0BAA0B;EAC3B;;;;;AAMH,SAAgB,wBACd,QACA,SAOqB;CACrB,MAAM,YAAsB,EAAE;AAG9B,KAAI,QAAQ,aACV,WAAU,KAAK,0BAA0B,QAAQ,aAAa,CAAC;AAIjE,KAAI,QAAQ,WACV,WAAU,KAAK,QAAQ,WAAW;AAIpC,KAAI,QAAQ,WACV,WAAU,KAAK,GAAG,QAAQ,WAAW;AAIvC,KAAI,QAAQ,UACV,WAAU,KAAK,GAAG,QAAQ,UAAU;AAGtC,KAAI,UAAU,WAAW,GAAG;AAC1B,MAAI,KAAK,0BAA0B;AACnC,SAAO;;AAGT,QAAO,mBAAmB,QAAQ;EAChC;EACA,YAAY,QAAQ,cAAc;EACnC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function resolveWorkspaceSkillsDir(workspaceDir: string): string;
@@ -0,0 +1,11 @@
1
+ import { join } from "node:path";
2
+ //#region src/agent/skills/workspace-skills-dir.ts
3
+ const PROJECT_XOPC_DIR = ".xopc";
4
+ const PROJECT_SKILLS_DIR = "skills";
5
+ function resolveWorkspaceSkillsDir(workspaceDir) {
6
+ return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_DIR);
7
+ }
8
+ //#endregion
9
+ export { resolveWorkspaceSkillsDir };
10
+
11
+ //# sourceMappingURL=workspace-skills-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-skills-dir.js","names":[],"sources":["../../../../src/agent/skills/workspace-skills-dir.ts"],"sourcesContent":["import { join } from 'node:path';\n\nconst PROJECT_XOPC_DIR = '.xopc';\nconst PROJECT_SKILLS_DIR = 'skills';\n\nexport function resolveWorkspaceSkillsDir(workspaceDir: string): string {\n return join(workspaceDir, PROJECT_XOPC_DIR, PROJECT_SKILLS_DIR);\n}\n"],"mappings":";;AAEA,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAE3B,SAAgB,0BAA0B,cAA8B;AACtE,QAAO,KAAK,cAAc,kBAAkB,mBAAmB"}
@@ -1,8 +1,8 @@
1
1
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentProfileDir, resolveAgentWorkspaceDir } from "./agent-scope.js";
2
2
  import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
3
3
  import { applyAgentConfig } from "../commands/agents.config.js";
4
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
4
  import { join } from "node:path";
5
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
6
6
  //#region src/agent/starter-agents.ts
7
7
  init_paths();
8
8
  init_agent_scope();
@@ -1 +1 @@
1
- export declare const browserUseManual = "# Browser Tool Manual\n\n## Overview\n\n`browser_use` is XOPC's unified browser tool. It supports four modes:\n\n| Mode | Purpose |\n|------|---------|\n| `command` | Run a single browser action |\n| `pipeline` | Run a multi-step YAML flow |\n| `inspect` | Read current page state |\n| `close` | Close the browser session |\n\n## When to use\n\n- Open pages, click controls, fill forms\n- Capture screenshots or page content\n- Run multi-step automation flows\n- Extract data from pages\n\n## Command mode\n\n### Basic shape\n\n```json\n{\n \"mode\": \"command\",\n \"command\": \"<action>\",\n \"args\": { ... }\n}\n```\n\n### Available commands\n\n| Command | Description | Key arguments |\n|---------|-------------|---------------|\n| `open` / `navigate` | Open a URL | `url`, `wait_until` |\n| `state` / `snapshot` | ARIA snapshot of the page | `selector`, `maxLength` |\n| `click` | Click an element | `selector` / `text` / `role` |\n| `type` / `input` | Type text | `selector` / `label`, `text`, `pressEnter` |\n| `scroll` | Scroll the page | `direction`, `amount` |\n| `screenshot` | Screenshot | `selector`, `full_page`, `path` |\n| `back` | Go back | `waitFor` |\n| `keys` / `press` | Keyboard input | `key` |\n| `console` / `eval` | Run JavaScript | `javascript` |\n| `images` | Collect images on the page | `selector`, `maxImages` |\n| `wait` | Wait for element/time | `selector` / `text` / `ms`, `timeout_ms` |\n| `dialog` | Handle dialogs | `action` (accept/dismiss) |\n| `close` | Close the current page | \u2014 |\n\n### Element targeting\n\nPrefer, in order:\n\n1. **ARIA role**: most stable, e.g. `\"role\": \"button:Submit\"`\n2. **Visible text**, e.g. `\"text\": \"Sign In\"`\n3. **CSS selector**, e.g. `\"selector\": \"#login-btn\"`\n\nGuidelines:\n\n- Use `inspect` or `state` first to get a snapshot\n- Pick locators from ARIA info in the snapshot\n- Avoid dynamic class names when possible\n\n## Inspect mode\n\nBefore acting, understand the current page:\n\n```json\n{ \"mode\": \"inspect\" }\n```\n\nReturns: current URL, title, ARIA snapshot.\n\n**Best practice**: after each navigation, inspect, then choose the next step.\n\n## Pipeline mode\n\nFor multi-step, reusable flows. Uses a brocli-style YAML DSL.\n\n### Run from file\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"path\": \"./browser-flow.yaml\",\n \"args\": { \"url\": \"https://example.com\" }\n }\n}\n```\n\n### Run inline YAML\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"name: quick-check\\npipeline:\\n - navigate:\\n url: https://example.com\\n - screenshot:\\n full_page: true\",\n \"dryRun\": false\n }\n}\n```\n\n### YAML layout\n\n```yaml\nname: pipeline-name\ndescription: What this flow does\nargs:\n url:\n type: string\n required: true\n query:\n type: string\n default: \"hello\"\npipeline:\n - navigate:\n url: ${{ args.url }}\n wait_until: domcontentloaded\n - wait:\n selector: input[name=\"q\"]\n - type:\n selector: input[name=\"q\"]\n text: ${{ args.query }}\n - press:\n key: Enter\n - wait:\n selector: body\n timeout_ms: 10000\n - screenshot:\n path: ./artifacts/result.png\n full_page: true\n - output:\n value:\n screenshot: ./artifacts/result.png\non_error:\n - screenshot:\n path: ./artifacts/error.png\n full_page: true\n```\n\n### Authoring rules\n\n1. One action per step\n2. Use `${{ args.xxx }}` for parameters\n3. Use `${{ data }}` or `${{ data | json }}` for the previous step's result\n4. Use `on_error` to collect diagnostics after failure\n\n### Validate without running\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"...\",\n \"dryRun\": true\n }\n}\n```\n\n## Recovery when something fails\n\n1. `inspect` to see current state\n2. Confirm the URL (redirects may have changed it)\n3. Use the snapshot to see if the page finished loading\n4. `screenshot` for visual debugging\n5. `wait` for elements, then retry\n\n## Safety\n\n- Do not put API keys or tokens in URLs\n- Do not target private IPs / localhost unless configuration allows it\n- Cloud metadata endpoints are always blocked\n- For destructive actions (submit forms, delete data), confirm intent with the user first\n";
1
+ export declare const browserUseManual = "# Browser Tool Manual\n\n## Overview\n\n`browser_use` is XOPC's unified browser tool. It supports four modes:\n\n| Mode | Purpose |\n|------|---------|\n| `command` | Run a single browser action |\n| `pipeline` | Run a multi-step YAML flow |\n| `inspect` | Read current page state |\n| `close` | Close the browser session |\n\n## When to use\n\n- Open pages, click controls, fill forms\n- Capture screenshots or page content\n- Run multi-step automation flows\n- Extract data from pages\n\n## Command mode\n\n### Basic shape\n\n```json\n{\n \"mode\": \"command\",\n \"command\": \"<action>\",\n \"args\": { ... }\n}\n```\n\n### Available commands\n\n| Command | Description | Key arguments |\n|---------|-------------|---------------|\n| `open` / `navigate` | Open a URL | `url`, `wait_until` |\n| `state` / `snapshot` | ARIA snapshot of the page | `selector`, `maxLength` |\n| `click` | Click an element | `selector` / `text` / `role` |\n| `type` / `input` | Type text | `selector` / `label`, `text`, `pressEnter` |\n| `scroll` | Scroll the page | `direction`, `amount` |\n| `screenshot` | Screenshot | `selector`, `full_page`, `path` |\n| `back` | Go back | `waitFor` |\n| `keys` / `press` | Keyboard input | `key` |\n| `console` / `eval` | Run JavaScript | `javascript` |\n| `images` | Collect images on the page | `selector`, `maxImages` |\n| `wait` | Wait for element/text/function/time | `selector` / `text` / `function` / `ms`, `state`, `timeout_ms` |\n| `wait_for_navigation` | Wait for page load state | `wait_until`, `timeout_ms` |\n| `wait_for_network_idle` | Wait until network is idle | `timeout_ms` |\n| `element_text` | Read element text | `selector` |\n| `element_attribute` | Read element attribute | `selector`, `attribute` |\n| `bounding_box` | Read element box | `selector` |\n| `network_start` / `network_events` / `network_stop` | Capture network events | `url_pattern`, `include_body` |\n| `dialog` | Handle dialogs | `action` (accept/dismiss) |\n| `close` | Close the current page | \u2014 |\n\n### Element targeting\n\nPrefer, in order:\n\n1. **ARIA role**: most stable, e.g. `\"role\": \"button:Submit\"`\n2. **Visible text**, e.g. `\"text\": \"Sign In\"`\n3. **CSS selector**, e.g. `\"selector\": \"#login-btn\"`\n\nGuidelines:\n\n- Use `inspect` or `state` first to get a snapshot\n- Pick locators from ARIA info in the snapshot\n- Avoid dynamic class names when possible\n\n## Inspect mode\n\nBefore acting, understand the current page:\n\n```json\n{ \"mode\": \"inspect\" }\n```\n\nReturns: current URL, title, ARIA snapshot.\n\n**Best practice**: after each navigation, inspect, then choose the next step.\n\n## Pipeline mode\n\nFor multi-step, reusable flows. Uses a brocli-style YAML DSL.\n\n### Run from file\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"path\": \"./browser-flow.yaml\",\n \"args\": { \"url\": \"https://example.com\" }\n }\n}\n```\n\n### Run inline YAML\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"name: quick-check\\npipeline:\\n - navigate:\\n url: https://example.com\\n - screenshot:\\n full_page: true\",\n \"dryRun\": false\n }\n}\n```\n\n### YAML layout\n\n```yaml\nname: pipeline-name\ndescription: What this flow does\ntimeoutSeconds: 60\ninclude:\n - ./shared-login.yaml\nargs:\n url:\n type: string\n required: true\n query:\n type: string\n default: \"hello\"\npipeline:\n - navigate:\n url: ${{ args.url }}\n wait_until: domcontentloaded\n - wait:\n selector: input[name=\"q\"]\n - type:\n selector: input[name=\"q\"]\n text: ${{ args.query }}\n - press:\n key: Enter\n - wait:\n selector: body\n timeout_ms: 10000\n - element_text:\n selector: h1\n - assert:\n contains: Results\n - screenshot:\n path: ./artifacts/result.png\n full_page: true\n - output:\n value:\n screenshot: ./artifacts/result.png\non_error:\n - screenshot:\n path: ./artifacts/error.png\n full_page: true\n```\n\n### Authoring rules\n\n1. One action per step\n2. Use `${{ args.xxx }}` for parameters\n3. Use `${{ last }}` or `${{ last | json }}` for the previous step result\n4. Use `${{ outputs.0 }}` for prior `output` values and `${{ vars.name }}` for values from `set_var`\n5. Use `include` for shared YAML fragments; relative includes resolve from the current pipeline file\n6. Use `on_error` to collect diagnostics after failure\n\n### Stable pipeline actions\n\n```yaml\npipeline:\n - network_start:\n url_pattern: /api/search\n include_body: true\n - click:\n text: Search\n - wait_for_network_idle:\n timeout_ms: 10000\n - collect: {}\n - filter:\n path: type\n equals: response\n - limit:\n count: 3\n - output:\n value: ${{ last }}\n```\n\nControl flow:\n\n```yaml\npipeline:\n - retry:\n times: 3\n delay_ms: 500\n pipeline:\n - wait:\n selector: button.submit\n timeout_ms: 3000\n - click:\n selector: button.submit\n - if:\n condition: ${{ last }}\n then:\n - output:\n value: clicked\n else:\n - output:\n value: missing\n```\n\n### Validate without running\n\n```json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"...\",\n \"dryRun\": true\n }\n}\n```\n\n## Recovery when something fails\n\n1. `inspect` to see current state\n2. Confirm the URL (redirects may have changed it)\n3. Use the snapshot to see if the page finished loading\n4. `screenshot` for visual debugging\n5. `wait` for elements, then retry\n\n## Safety\n\n- Do not put API keys or tokens in URLs\n- Do not target private IPs / localhost unless configuration allows it\n- Cloud metadata endpoints are always blocked\n- For destructive actions (submit forms, delete data), confirm intent with the user first\n";
@@ -45,7 +45,13 @@ const browserUseManual = `# Browser Tool Manual
45
45
  | \`keys\` / \`press\` | Keyboard input | \`key\` |
46
46
  | \`console\` / \`eval\` | Run JavaScript | \`javascript\` |
47
47
  | \`images\` | Collect images on the page | \`selector\`, \`maxImages\` |
48
- | \`wait\` | Wait for element/time | \`selector\` / \`text\` / \`ms\`, \`timeout_ms\` |
48
+ | \`wait\` | Wait for element/text/function/time | \`selector\` / \`text\` / \`function\` / \`ms\`, \`state\`, \`timeout_ms\` |
49
+ | \`wait_for_navigation\` | Wait for page load state | \`wait_until\`, \`timeout_ms\` |
50
+ | \`wait_for_network_idle\` | Wait until network is idle | \`timeout_ms\` |
51
+ | \`element_text\` | Read element text | \`selector\` |
52
+ | \`element_attribute\` | Read element attribute | \`selector\`, \`attribute\` |
53
+ | \`bounding_box\` | Read element box | \`selector\` |
54
+ | \`network_start\` / \`network_events\` / \`network_stop\` | Capture network events | \`url_pattern\`, \`include_body\` |
49
55
  | \`dialog\` | Handle dialogs | \`action\` (accept/dismiss) |
50
56
  | \`close\` | Close the current page | — |
51
57
 
@@ -108,6 +114,9 @@ For multi-step, reusable flows. Uses a brocli-style YAML DSL.
108
114
  \`\`\`yaml
109
115
  name: pipeline-name
110
116
  description: What this flow does
117
+ timeoutSeconds: 60
118
+ include:
119
+ - ./shared-login.yaml
111
120
  args:
112
121
  url:
113
122
  type: string
@@ -129,6 +138,10 @@ pipeline:
129
138
  - wait:
130
139
  selector: body
131
140
  timeout_ms: 10000
141
+ - element_text:
142
+ selector: h1
143
+ - assert:
144
+ contains: Results
132
145
  - screenshot:
133
146
  path: ./artifacts/result.png
134
147
  full_page: true
@@ -145,8 +158,54 @@ on_error:
145
158
 
146
159
  1. One action per step
147
160
  2. Use \`\${{ args.xxx }}\` for parameters
148
- 3. Use \`\${{ data }}\` or \`\${{ data | json }}\` for the previous step's result
149
- 4. Use \`on_error\` to collect diagnostics after failure
161
+ 3. Use \`\${{ last }}\` or \`\${{ last | json }}\` for the previous step result
162
+ 4. Use \`\${{ outputs.0 }}\` for prior \`output\` values and \`\${{ vars.name }}\` for values from \`set_var\`
163
+ 5. Use \`include\` for shared YAML fragments; relative includes resolve from the current pipeline file
164
+ 6. Use \`on_error\` to collect diagnostics after failure
165
+
166
+ ### Stable pipeline actions
167
+
168
+ \`\`\`yaml
169
+ pipeline:
170
+ - network_start:
171
+ url_pattern: /api/search
172
+ include_body: true
173
+ - click:
174
+ text: Search
175
+ - wait_for_network_idle:
176
+ timeout_ms: 10000
177
+ - collect: {}
178
+ - filter:
179
+ path: type
180
+ equals: response
181
+ - limit:
182
+ count: 3
183
+ - output:
184
+ value: \${{ last }}
185
+ \`\`\`
186
+
187
+ Control flow:
188
+
189
+ \`\`\`yaml
190
+ pipeline:
191
+ - retry:
192
+ times: 3
193
+ delay_ms: 500
194
+ pipeline:
195
+ - wait:
196
+ selector: button.submit
197
+ timeout_ms: 3000
198
+ - click:
199
+ selector: button.submit
200
+ - if:
201
+ condition: \${{ last }}
202
+ then:
203
+ - output:
204
+ value: clicked
205
+ else:
206
+ - output:
207
+ value: missing
208
+ \`\`\`
150
209
 
151
210
  ### Validate without running
152
211
 
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","names":[],"sources":["../../../../src/agent/tool-manuals/browser.ts"],"sourcesContent":["export const browserUseManual = `# Browser Tool Manual\n\n## Overview\n\n\\`browser_use\\` is XOPC's unified browser tool. It supports four modes:\n\n| Mode | Purpose |\n|------|---------|\n| \\`command\\` | Run a single browser action |\n| \\`pipeline\\` | Run a multi-step YAML flow |\n| \\`inspect\\` | Read current page state |\n| \\`close\\` | Close the browser session |\n\n## When to use\n\n- Open pages, click controls, fill forms\n- Capture screenshots or page content\n- Run multi-step automation flows\n- Extract data from pages\n\n## Command mode\n\n### Basic shape\n\n\\`\\`\\`json\n{\n \"mode\": \"command\",\n \"command\": \"<action>\",\n \"args\": { ... }\n}\n\\`\\`\\`\n\n### Available commands\n\n| Command | Description | Key arguments |\n|---------|-------------|---------------|\n| \\`open\\` / \\`navigate\\` | Open a URL | \\`url\\`, \\`wait_until\\` |\n| \\`state\\` / \\`snapshot\\` | ARIA snapshot of the page | \\`selector\\`, \\`maxLength\\` |\n| \\`click\\` | Click an element | \\`selector\\` / \\`text\\` / \\`role\\` |\n| \\`type\\` / \\`input\\` | Type text | \\`selector\\` / \\`label\\`, \\`text\\`, \\`pressEnter\\` |\n| \\`scroll\\` | Scroll the page | \\`direction\\`, \\`amount\\` |\n| \\`screenshot\\` | Screenshot | \\`selector\\`, \\`full_page\\`, \\`path\\` |\n| \\`back\\` | Go back | \\`waitFor\\` |\n| \\`keys\\` / \\`press\\` | Keyboard input | \\`key\\` |\n| \\`console\\` / \\`eval\\` | Run JavaScript | \\`javascript\\` |\n| \\`images\\` | Collect images on the page | \\`selector\\`, \\`maxImages\\` |\n| \\`wait\\` | Wait for element/time | \\`selector\\` / \\`text\\` / \\`ms\\`, \\`timeout_ms\\` |\n| \\`dialog\\` | Handle dialogs | \\`action\\` (accept/dismiss) |\n| \\`close\\` | Close the current page | — |\n\n### Element targeting\n\nPrefer, in order:\n\n1. **ARIA role**: most stable, e.g. \\`\"role\": \"button:Submit\"\\`\n2. **Visible text**, e.g. \\`\"text\": \"Sign In\"\\`\n3. **CSS selector**, e.g. \\`\"selector\": \"#login-btn\"\\`\n\nGuidelines:\n\n- Use \\`inspect\\` or \\`state\\` first to get a snapshot\n- Pick locators from ARIA info in the snapshot\n- Avoid dynamic class names when possible\n\n## Inspect mode\n\nBefore acting, understand the current page:\n\n\\`\\`\\`json\n{ \"mode\": \"inspect\" }\n\\`\\`\\`\n\nReturns: current URL, title, ARIA snapshot.\n\n**Best practice**: after each navigation, inspect, then choose the next step.\n\n## Pipeline mode\n\nFor multi-step, reusable flows. Uses a brocli-style YAML DSL.\n\n### Run from file\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"path\": \"./browser-flow.yaml\",\n \"args\": { \"url\": \"https://example.com\" }\n }\n}\n\\`\\`\\`\n\n### Run inline YAML\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"name: quick-check\\\\npipeline:\\\\n - navigate:\\\\n url: https://example.com\\\\n - screenshot:\\\\n full_page: true\",\n \"dryRun\": false\n }\n}\n\\`\\`\\`\n\n### YAML layout\n\n\\`\\`\\`yaml\nname: pipeline-name\ndescription: What this flow does\nargs:\n url:\n type: string\n required: true\n query:\n type: string\n default: \"hello\"\npipeline:\n - navigate:\n url: \\${{ args.url }}\n wait_until: domcontentloaded\n - wait:\n selector: input[name=\"q\"]\n - type:\n selector: input[name=\"q\"]\n text: \\${{ args.query }}\n - press:\n key: Enter\n - wait:\n selector: body\n timeout_ms: 10000\n - screenshot:\n path: ./artifacts/result.png\n full_page: true\n - output:\n value:\n screenshot: ./artifacts/result.png\non_error:\n - screenshot:\n path: ./artifacts/error.png\n full_page: true\n\\`\\`\\`\n\n### Authoring rules\n\n1. One action per step\n2. Use \\`\\${{ args.xxx }}\\` for parameters\n3. Use \\`\\${{ data }}\\` or \\`\\${{ data | json }}\\` for the previous step's result\n4. Use \\`on_error\\` to collect diagnostics after failure\n\n### Validate without running\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"...\",\n \"dryRun\": true\n }\n}\n\\`\\`\\`\n\n## Recovery when something fails\n\n1. \\`inspect\\` to see current state\n2. Confirm the URL (redirects may have changed it)\n3. Use the snapshot to see if the page finished loading\n4. \\`screenshot\\` for visual debugging\n5. \\`wait\\` for elements, then retry\n\n## Safety\n\n- Do not put API keys or tokens in URLs\n- Do not target private IPs / localhost unless configuration allows it\n- Cloud metadata endpoints are always blocked\n- For destructive actions (submit forms, delete data), confirm intent with the user first\n`;\n"],"mappings":";AAAA,MAAa,mBAAmB"}
1
+ {"version":3,"file":"browser.js","names":[],"sources":["../../../../src/agent/tool-manuals/browser.ts"],"sourcesContent":["export const browserUseManual = `# Browser Tool Manual\n\n## Overview\n\n\\`browser_use\\` is XOPC's unified browser tool. It supports four modes:\n\n| Mode | Purpose |\n|------|---------|\n| \\`command\\` | Run a single browser action |\n| \\`pipeline\\` | Run a multi-step YAML flow |\n| \\`inspect\\` | Read current page state |\n| \\`close\\` | Close the browser session |\n\n## When to use\n\n- Open pages, click controls, fill forms\n- Capture screenshots or page content\n- Run multi-step automation flows\n- Extract data from pages\n\n## Command mode\n\n### Basic shape\n\n\\`\\`\\`json\n{\n \"mode\": \"command\",\n \"command\": \"<action>\",\n \"args\": { ... }\n}\n\\`\\`\\`\n\n### Available commands\n\n| Command | Description | Key arguments |\n|---------|-------------|---------------|\n| \\`open\\` / \\`navigate\\` | Open a URL | \\`url\\`, \\`wait_until\\` |\n| \\`state\\` / \\`snapshot\\` | ARIA snapshot of the page | \\`selector\\`, \\`maxLength\\` |\n| \\`click\\` | Click an element | \\`selector\\` / \\`text\\` / \\`role\\` |\n| \\`type\\` / \\`input\\` | Type text | \\`selector\\` / \\`label\\`, \\`text\\`, \\`pressEnter\\` |\n| \\`scroll\\` | Scroll the page | \\`direction\\`, \\`amount\\` |\n| \\`screenshot\\` | Screenshot | \\`selector\\`, \\`full_page\\`, \\`path\\` |\n| \\`back\\` | Go back | \\`waitFor\\` |\n| \\`keys\\` / \\`press\\` | Keyboard input | \\`key\\` |\n| \\`console\\` / \\`eval\\` | Run JavaScript | \\`javascript\\` |\n| \\`images\\` | Collect images on the page | \\`selector\\`, \\`maxImages\\` |\n| \\`wait\\` | Wait for element/text/function/time | \\`selector\\` / \\`text\\` / \\`function\\` / \\`ms\\`, \\`state\\`, \\`timeout_ms\\` |\n| \\`wait_for_navigation\\` | Wait for page load state | \\`wait_until\\`, \\`timeout_ms\\` |\n| \\`wait_for_network_idle\\` | Wait until network is idle | \\`timeout_ms\\` |\n| \\`element_text\\` | Read element text | \\`selector\\` |\n| \\`element_attribute\\` | Read element attribute | \\`selector\\`, \\`attribute\\` |\n| \\`bounding_box\\` | Read element box | \\`selector\\` |\n| \\`network_start\\` / \\`network_events\\` / \\`network_stop\\` | Capture network events | \\`url_pattern\\`, \\`include_body\\` |\n| \\`dialog\\` | Handle dialogs | \\`action\\` (accept/dismiss) |\n| \\`close\\` | Close the current page | — |\n\n### Element targeting\n\nPrefer, in order:\n\n1. **ARIA role**: most stable, e.g. \\`\"role\": \"button:Submit\"\\`\n2. **Visible text**, e.g. \\`\"text\": \"Sign In\"\\`\n3. **CSS selector**, e.g. \\`\"selector\": \"#login-btn\"\\`\n\nGuidelines:\n\n- Use \\`inspect\\` or \\`state\\` first to get a snapshot\n- Pick locators from ARIA info in the snapshot\n- Avoid dynamic class names when possible\n\n## Inspect mode\n\nBefore acting, understand the current page:\n\n\\`\\`\\`json\n{ \"mode\": \"inspect\" }\n\\`\\`\\`\n\nReturns: current URL, title, ARIA snapshot.\n\n**Best practice**: after each navigation, inspect, then choose the next step.\n\n## Pipeline mode\n\nFor multi-step, reusable flows. Uses a brocli-style YAML DSL.\n\n### Run from file\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"path\": \"./browser-flow.yaml\",\n \"args\": { \"url\": \"https://example.com\" }\n }\n}\n\\`\\`\\`\n\n### Run inline YAML\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"name: quick-check\\\\npipeline:\\\\n - navigate:\\\\n url: https://example.com\\\\n - screenshot:\\\\n full_page: true\",\n \"dryRun\": false\n }\n}\n\\`\\`\\`\n\n### YAML layout\n\n\\`\\`\\`yaml\nname: pipeline-name\ndescription: What this flow does\ntimeoutSeconds: 60\ninclude:\n - ./shared-login.yaml\nargs:\n url:\n type: string\n required: true\n query:\n type: string\n default: \"hello\"\npipeline:\n - navigate:\n url: \\${{ args.url }}\n wait_until: domcontentloaded\n - wait:\n selector: input[name=\"q\"]\n - type:\n selector: input[name=\"q\"]\n text: \\${{ args.query }}\n - press:\n key: Enter\n - wait:\n selector: body\n timeout_ms: 10000\n - element_text:\n selector: h1\n - assert:\n contains: Results\n - screenshot:\n path: ./artifacts/result.png\n full_page: true\n - output:\n value:\n screenshot: ./artifacts/result.png\non_error:\n - screenshot:\n path: ./artifacts/error.png\n full_page: true\n\\`\\`\\`\n\n### Authoring rules\n\n1. One action per step\n2. Use \\`\\${{ args.xxx }}\\` for parameters\n3. Use \\`\\${{ last }}\\` or \\`\\${{ last | json }}\\` for the previous step result\n4. Use \\`\\${{ outputs.0 }}\\` for prior \\`output\\` values and \\`\\${{ vars.name }}\\` for values from \\`set_var\\`\n5. Use \\`include\\` for shared YAML fragments; relative includes resolve from the current pipeline file\n6. Use \\`on_error\\` to collect diagnostics after failure\n\n### Stable pipeline actions\n\n\\`\\`\\`yaml\npipeline:\n - network_start:\n url_pattern: /api/search\n include_body: true\n - click:\n text: Search\n - wait_for_network_idle:\n timeout_ms: 10000\n - collect: {}\n - filter:\n path: type\n equals: response\n - limit:\n count: 3\n - output:\n value: \\${{ last }}\n\\`\\`\\`\n\nControl flow:\n\n\\`\\`\\`yaml\npipeline:\n - retry:\n times: 3\n delay_ms: 500\n pipeline:\n - wait:\n selector: button.submit\n timeout_ms: 3000\n - click:\n selector: button.submit\n - if:\n condition: \\${{ last }}\n then:\n - output:\n value: clicked\n else:\n - output:\n value: missing\n\\`\\`\\`\n\n### Validate without running\n\n\\`\\`\\`json\n{\n \"mode\": \"pipeline\",\n \"pipeline\": {\n \"yaml\": \"...\",\n \"dryRun\": true\n }\n}\n\\`\\`\\`\n\n## Recovery when something fails\n\n1. \\`inspect\\` to see current state\n2. Confirm the URL (redirects may have changed it)\n3. Use the snapshot to see if the page finished loading\n4. \\`screenshot\\` for visual debugging\n5. \\`wait\\` for elements, then retry\n\n## Safety\n\n- Do not put API keys or tokens in URLs\n- Do not target private IPs / localhost unless configuration allows it\n- Cloud metadata endpoints are always blocked\n- For destructive actions (submit forms, delete data), confirm intent with the user first\n`;\n"],"mappings":";AAAA,MAAa,mBAAmB"}
@@ -25,6 +25,9 @@ export interface CreateBrowserUseToolDeps {
25
25
  */
26
26
  getReadiness?: () => Promise<BrowserNotReadyError | null>;
27
27
  /** Pipeline runner (injected to avoid circular deps; lazy-loaded if not provided). */
28
- runPipeline?: (yaml: string, args: Record<string, unknown>, ctx: BrowserActionContext, dryRun: boolean) => Promise<BrowserActionResult>;
28
+ runPipeline?: (yaml: string, args: Record<string, unknown>, ctx: BrowserActionContext, options: {
29
+ dryRun?: boolean;
30
+ sourceLocation?: string;
31
+ }) => Promise<BrowserActionResult>;
29
32
  }
30
33
  export declare function createBrowserUseTool(deps: CreateBrowserUseToolDeps): AgentTool<any, any>;
@@ -185,9 +185,12 @@ function createBrowserUseTool(deps) {
185
185
  mode: "pipeline"
186
186
  }
187
187
  };
188
- let yamlSource = pipelineParams.yaml ?? pipelineParams.script ?? "";
188
+ let yamlSource = pipelineParams.yaml ?? "";
189
+ let sourceLocation;
189
190
  if (!yamlSource && pipelineParams.path) try {
190
- yamlSource = (await loadBrowserPipelineSource(pipelineParams.path)).source;
191
+ const loaded = await loadBrowserPipelineSource(pipelineParams.path);
192
+ yamlSource = loaded.source;
193
+ sourceLocation = loaded.location;
191
194
  } catch (e) {
192
195
  const msg = e instanceof Error ? e.message : String(e);
193
196
  return {
@@ -215,10 +218,16 @@ function createBrowserUseTool(deps) {
215
218
  const pipelineArgs = pipelineParams.args ?? {};
216
219
  const dryRun = pipelineParams.dryRun === true;
217
220
  const ctx = buildContext(await deps.getPageForTask(), signal);
218
- if (deps.runPipeline) return formatResult(await deps.runPipeline(yamlSource, pipelineArgs, ctx, dryRun));
221
+ if (deps.runPipeline) return formatResult(await deps.runPipeline(yamlSource, pipelineArgs, ctx, {
222
+ dryRun,
223
+ sourceLocation
224
+ }));
219
225
  try {
220
226
  const { runBrowserPipeline } = await import("../../../../browser/pipeline/runner.js");
221
- return formatResult(await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, dryRun));
227
+ return formatResult(await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, {
228
+ dryRun,
229
+ sourceLocation
230
+ }));
222
231
  } catch (e) {
223
232
  const msg = e instanceof Error ? e.message : String(e);
224
233
  log.error({ err: e }, `Pipeline execution failed: ${msg}`);
@@ -1 +1 @@
1
- {"version":3,"file":"browser-use-tool.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/browser-use-tool.ts"],"sourcesContent":["/**\n * browser_use — unified browser AgentTool.\n *\n * Modes: command | pipeline | inspect | close.\n * Replaces the 14 fine-grained browser_* tools with a single entry point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport { createLogger } from '../../../../utils/logger.js';\nimport type { Config } from '../../../../config/schema.js';\nimport type { BrowserManager } from '../../../../browser/manager.js';\nimport type { CdpSupervisor } from '../../../../browser/cdp-supervisor.js';\nimport type { Page } from 'playwright-core';\n\nimport { BrowserUseSchema } from './schemas.js';\nimport { createBrowserActionRegistry } from '../../../../browser/actions/registry.js';\nimport type { BrowserActionContext, BrowserActionResult } from '../../../../browser/actions/types.js';\nimport { loadBrowserPipelineSource } from '../../../../browser/pipeline/source.js';\nimport type { BrowserNotReadyError, BrowserSetupHint } from '../../../../browser/readiness.js';\n\nconst log = createLogger('Agent:BrowserUse');\n\nexport interface CreateBrowserUseToolDeps {\n getManager: () => BrowserManager;\n getPageForTask: () => Promise<Page>;\n getTaskId: () => string;\n getConfig: () => Config | undefined;\n getSupervisor?: () => CdpSupervisor | undefined;\n notifyBrowserPageClosed?: (taskId: string) => void;\n /**\n * Preflight readiness check. Returns `null` when the configured backend is\n * usable, otherwise a structured hint the chat surface renders as a setup\n * card. Cache the result upstream (~30s) so back-to-back calls don't reprobe.\n */\n getReadiness?: () => Promise<BrowserNotReadyError | null>;\n /** Pipeline runner (injected to avoid circular deps; lazy-loaded if not provided). */\n runPipeline?: (yaml: string, args: Record<string, unknown>, ctx: BrowserActionContext, dryRun: boolean) => Promise<BrowserActionResult>;\n}\n\nexport function createBrowserUseTool(deps: CreateBrowserUseToolDeps): AgentTool<any, any> {\n const registry = createBrowserActionRegistry();\n\n function buildContext(page: Page, signal?: AbortSignal): BrowserActionContext {\n return {\n page,\n manager: deps.getManager(),\n config: deps.getConfig(),\n taskId: deps.getTaskId(),\n supervisor: deps.getSupervisor?.(),\n signal,\n };\n }\n\n /**\n * Render a {@link BrowserSetupHint} as a tool result. The text body is a\n * JSON envelope (`kind: 'browser_setup_required'`) so the chat surface can\n * detect it and render a Setup card; the embedded `message` keeps the\n * payload human-readable for the LLM so it stops the browser attempt and\n * tells the user to finish setup.\n */\n function formatNotReady(hint: BrowserSetupHint): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n const message =\n `⚠ Browser is not ready (backend=${hint.backend}, reason=${hint.reason}). ` +\n `Do NOT retry. Tell the user to open Settings → Browser to finish setup, ` +\n `then ask them to confirm before running any browser action again.`;\n const payload = {\n kind: 'browser_setup_required' as const,\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n detail: hint.detail,\n message,\n };\n return {\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n details: {\n ok: false,\n kind: 'browser_setup_required',\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n },\n };\n }\n\n function formatResult(result: BrowserActionResult): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n if (result.ok) {\n const parts: string[] = [];\n if (result.text) parts.push(result.text);\n if (result.data && !result.text) parts.push(JSON.stringify(result.data, null, 2));\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'OK' }],\n details: { ok: true, action: result.action, ...(result.artifacts?.length ? { artifacts: result.artifacts.length } : {}) },\n };\n }\n const parts: string[] = [];\n if (result.error) parts.push(`[${result.error.code}] ${result.error.message}`);\n if (result.diagnostics?.url) parts.push(`URL: ${result.diagnostics.url}`);\n if (result.diagnostics?.snapshot) parts.push(`Snapshot: ${result.diagnostics.snapshot.slice(0, 2000)}`);\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'Failed' }],\n details: { ok: false, action: result.action, error: result.error },\n };\n }\n\n const tool: any = {\n name: 'browser_use',\n label: '🌐 Browser',\n description:\n 'Use a persistent browser for web navigation, page inspection, interaction, screenshots, network capture, and scripted browser pipelines. For non-trivial browser tasks, load the built-in manual first with tool_manual({ tool: \"browser_use\" }).',\n parameters: BrowserUseSchema,\n\n async execute(_toolCallId, params: any, signal, _onUpdate) {\n const { mode, command, args: cmdArgs, pipeline: pipelineParams, options: _options } = params as {\n mode: string;\n command?: string;\n args?: Record<string, unknown>;\n pipeline?: { yaml?: string; script?: string; path?: string; args?: Record<string, unknown>; dryRun?: boolean };\n options?: { timeout?: number; headless?: boolean };\n };\n\n // ─── readiness preflight ────────────────────────────────────────────\n // Probes the configured backend (doctor + WS bridge / CDP / cloud key)\n // before any launch attempt. On failure we short-circuit with a setup\n // hint the chat renders as a card — the agent should stop and ask the\n // user to finish setup instead of looping on launch errors.\n if (deps.getReadiness) {\n try {\n const notReady = await deps.getReadiness();\n if (notReady) {\n return formatNotReady(notReady.hint);\n }\n } catch (e) {\n log.warn({ err: e }, 'Readiness preflight threw; continuing with launch attempt');\n }\n }\n\n // ─── inspect ────────────────────────────────────────────────────────\n if (mode === 'inspect') {\n const mgr = deps.getManager();\n await mgr.ensureConnected();\n const ext = mgr.getExtensionProvider();\n if (ext) {\n const timeout = deps.getConfig?.()?.agents?.defaults?.browser?.commandTimeout;\n const timeoutMs =\n typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0\n ? Math.floor(timeout * 1000)\n : 30_000;\n const urlRes = await ext.sendCommand('get_url', {}, { timeout: timeoutMs });\n const titleRes = await ext.sendCommand('get_title', {}, { timeout: timeoutMs });\n const snapRes = await ext.sendCommand('snapshot', {}, { timeout: timeoutMs });\n const url = urlRes.ok && urlRes.data ? String((urlRes.data as { url?: string }).url ?? '') : '';\n const title =\n titleRes.ok && titleRes.data ? String((titleRes.data as { title?: string }).title ?? '') : '';\n let snapText = '';\n if (snapRes.ok && snapRes.data) {\n const nodes = (snapRes.data as { nodes?: Array<{ role?: string; name?: string }> }).nodes ?? [];\n snapText = nodes.map((n) => `${n.role ?? '?'}: ${n.name ?? ''}`).join('\\n');\n if (snapText.length > 8000) snapText = `${snapText.slice(0, 8000)}\\n... (truncated)`;\n }\n const text = `URL: ${url}\\nTitle: ${title}\\n${snapText ? `--- Page Snapshot ---\\n${snapText}` : ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const result = await registry.execute('state', ctx, {});\n // Augment with URL / title\n const url = page.url();\n const title = await page.title().catch(() => '');\n const text = `URL: ${url}\\nTitle: ${title}\\n${result.text ?? ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n\n // ─── close ──────────────────────────────────────────────────────────\n if (mode === 'close') {\n const taskId = deps.getTaskId();\n await deps.getManager().ensureConnected();\n await deps.getManager().closePage(taskId);\n deps.notifyBrowserPageClosed?.(taskId);\n return {\n content: [{ type: 'text', text: 'Browser page closed.' }],\n details: { ok: true, mode: 'close' },\n };\n }\n\n // ─── command ────────────────────────────────────────────────────────\n if (mode === 'command') {\n if (!command) {\n return {\n content: [{ type: 'text', text: 'Missing `command` parameter for command mode.' }],\n details: { ok: false, mode: 'command' },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const args = cmdArgs ?? {};\n const result = await registry.execute(command, ctx, args);\n return formatResult(result);\n }\n\n // ─── pipeline ──────────────────────────────────────────────────────\n if (mode === 'pipeline') {\n if (!pipelineParams) {\n return {\n content: [{ type: 'text', text: 'Missing `pipeline` parameter for pipeline mode.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n // Resolve YAML source\n let yamlSource = pipelineParams.yaml ?? pipelineParams.script ?? '';\n\n if (!yamlSource && pipelineParams.path) {\n try {\n yamlSource = (await loadBrowserPipelineSource(pipelineParams.path)).source;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [{ type: 'text', text: `Failed to read pipeline source: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n if (!yamlSource) {\n return {\n content: [{ type: 'text', text: 'Pipeline mode requires `yaml`, `script`, or `path`.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n const pipelineArgs = (pipelineParams.args as Record<string, unknown>) ?? {};\n const dryRun = pipelineParams.dryRun === true;\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n\n // Use injected runner or lazy-load\n if (deps.runPipeline) {\n const result = await deps.runPipeline(yamlSource, pipelineArgs, ctx, dryRun);\n return formatResult(result);\n }\n\n // Lazy import pipeline runner\n try {\n const { runBrowserPipeline } = await import('../../../../browser/pipeline/runner.js');\n const result = await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, dryRun);\n return formatResult(result);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.error({ err: e }, `Pipeline execution failed: ${msg}`);\n return {\n content: [{ type: 'text', text: `Pipeline failed: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n return {\n content: [{ type: 'text', text: `Unknown mode: ${mode}` }],\n details: { ok: false },\n };\n },\n };\n return tool;\n}\n"],"mappings":";;;;;;aAS2D;AAY3D,MAAM,MAAM,aAAa,mBAAmB;AAmB5C,SAAgB,qBAAqB,MAAqD;CACxF,MAAM,WAAW,6BAA6B;CAE9C,SAAS,aAAa,MAAY,QAA4C;AAC5E,SAAO;GACL;GACA,SAAS,KAAK,YAAY;GAC1B,QAAQ,KAAK,WAAW;GACxB,QAAQ,KAAK,WAAW;GACxB,YAAY,KAAK,iBAAiB;GAClC;GACD;;;;;;;;;CAUH,SAAS,eAAe,MAAyG;EAC/H,MAAM,UACJ,mCAAmC,KAAK,QAAQ,WAAW,KAAK,OAAO;EAGzE,MAAM,UAAU;GACd,MAAM;GACN,SAAS,KAAK;GACd,QAAQ,KAAK;GACb,UAAU,KAAK;GACf,QAAQ,KAAK;GACb;GACD;AACD,SAAO;GACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,KAAK,UAAU,QAAQ;IAAE,CAAC;GAC1D,SAAS;IACP,IAAI;IACJ,MAAM;IACN,SAAS,KAAK;IACd,QAAQ,KAAK;IACb,UAAU,KAAK;IAChB;GACF;;CAGH,SAAS,aAAa,QAA8G;AAClI,MAAI,OAAO,IAAI;GACb,MAAM,QAAkB,EAAE;AAC1B,OAAI,OAAO,KAAM,OAAM,KAAK,OAAO,KAAK;AACxC,OAAI,OAAO,QAAQ,CAAC,OAAO,KAAM,OAAM,KAAK,KAAK,UAAU,OAAO,MAAM,MAAM,EAAE,CAAC;AACjF,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,MAAM,KAAK,KAAK,IAAI;KAAM,CAAC;IAC3D,SAAS;KAAE,IAAI;KAAM,QAAQ,OAAO;KAAQ,GAAI,OAAO,WAAW,SAAS,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,EAAE;KAAG;IAC1H;;EAEH,MAAM,QAAkB,EAAE;AAC1B,MAAI,OAAO,MAAO,OAAM,KAAK,IAAI,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,UAAU;AAC9E,MAAI,OAAO,aAAa,IAAK,OAAM,KAAK,QAAQ,OAAO,YAAY,MAAM;AACzE,MAAI,OAAO,aAAa,SAAU,OAAM,KAAK,aAAa,OAAO,YAAY,SAAS,MAAM,GAAG,IAAK,GAAG;AACvG,SAAO;GACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,MAAM,KAAK,KAAK,IAAI;IAAU,CAAC;GAC/D,SAAS;IAAE,IAAI;IAAO,QAAQ,OAAO;IAAQ,OAAO,OAAO;IAAO;GACnE;;AAuKH,QAAO;EAnKL,MAAM;EACN,OAAO;EACP,aACE;EACF,YAAY;EAEZ,MAAM,QAAQ,aAAa,QAAa,QAAQ,WAAW;GACzD,MAAM,EAAE,MAAM,SAAS,MAAM,SAAS,UAAU,gBAAgB,SAAS,aAAa;AAatF,OAAI,KAAK,aACP,KAAI;IACF,MAAM,WAAW,MAAM,KAAK,cAAc;AAC1C,QAAI,SACF,QAAO,eAAe,SAAS,KAAK;YAE/B,GAAG;AACV,QAAI,KAAK,EAAE,KAAK,GAAG,EAAE,4DAA4D;;AAKrF,OAAI,SAAS,WAAW;IACtB,MAAM,MAAM,KAAK,YAAY;AAC7B,UAAM,IAAI,iBAAiB;IAC3B,MAAM,MAAM,IAAI,sBAAsB;AACtC,QAAI,KAAK;KACP,MAAM,UAAU,KAAK,aAAa,EAAE,QAAQ,UAAU,SAAS;KAC/D,MAAM,YACJ,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,IAAI,UAAU,IACjE,KAAK,MAAM,UAAU,IAAK,GAC1B;KACN,MAAM,SAAS,MAAM,IAAI,YAAY,WAAW,EAAE,EAAE,EAAE,SAAS,WAAW,CAAC;KAC3E,MAAM,WAAW,MAAM,IAAI,YAAY,aAAa,EAAE,EAAE,EAAE,SAAS,WAAW,CAAC;KAC/E,MAAM,UAAU,MAAM,IAAI,YAAY,YAAY,EAAE,EAAE,EAAE,SAAS,WAAW,CAAC;KAC7E,MAAM,MAAM,OAAO,MAAM,OAAO,OAAO,OAAQ,OAAO,KAA0B,OAAO,GAAG,GAAG;KAC7F,MAAM,QACJ,SAAS,MAAM,SAAS,OAAO,OAAQ,SAAS,KAA4B,SAAS,GAAG,GAAG;KAC7F,IAAI,WAAW;AACf,SAAI,QAAQ,MAAM,QAAQ,MAAM;AAE9B,kBADe,QAAQ,KAA6D,SAAS,EAAE,EAC9E,KAAK,MAAM,GAAG,EAAE,QAAQ,IAAI,IAAI,EAAE,QAAQ,KAAK,CAAC,KAAK,KAAK;AAC3E,UAAI,SAAS,SAAS,IAAM,YAAW,GAAG,SAAS,MAAM,GAAG,IAAK,CAAC;;AAGpE,YAAO;MACL,SAAS,CAAC;OAAE,MAAM;OAAQ,MAAA,QAFP,IAAI,WAAW,MAAM,IAAI,WAAW,0BAA0B,aAAa;OAE9D,CAAC;MACjC,SAAS;OAAE,IAAI;OAAM,MAAM;OAAW;OAAK;OAAO;MACnD;;IAEH,MAAM,OAAO,MAAM,KAAK,gBAAgB;IACxC,MAAM,MAAM,aAAa,MAAM,OAAO;IACtC,MAAM,SAAS,MAAM,SAAS,QAAQ,SAAS,KAAK,EAAE,CAAC;IAEvD,MAAM,MAAM,KAAK,KAAK;IACtB,MAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG;AAEhD,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAA,QAFP,IAAI,WAAW,MAAM,IAAI,OAAO,QAAQ;MAE3B,CAAC;KACjC,SAAS;MAAE,IAAI;MAAM,MAAM;MAAW;MAAK;MAAO;KACnD;;AAIH,OAAI,SAAS,SAAS;IACpB,MAAM,SAAS,KAAK,WAAW;AAC/B,UAAM,KAAK,YAAY,CAAC,iBAAiB;AACzC,UAAM,KAAK,YAAY,CAAC,UAAU,OAAO;AACzC,SAAK,0BAA0B,OAAO;AACtC,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAwB,CAAC;KACzD,SAAS;MAAE,IAAI;MAAM,MAAM;MAAS;KACrC;;AAIH,OAAI,SAAS,WAAW;AACtB,QAAI,CAAC,QACH,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAiD,CAAC;KAClF,SAAS;MAAE,IAAI;MAAO,MAAM;MAAW;KACxC;IAGH,MAAM,MAAM,aAAa,MADN,KAAK,gBAAgB,EACT,OAAO;IACtC,MAAM,OAAO,WAAW,EAAE;AAE1B,WAAO,aAAa,MADC,SAAS,QAAQ,SAAS,KAAK,KAAK,CAC9B;;AAI7B,OAAI,SAAS,YAAY;AACvB,QAAI,CAAC,eACH,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAmD,CAAC;KACpF,SAAS;MAAE,IAAI;MAAO,MAAM;MAAY;KACzC;IAIH,IAAI,aAAa,eAAe,QAAQ,eAAe,UAAU;AAEjE,QAAI,CAAC,cAAc,eAAe,KAChC,KAAI;AACF,mBAAc,MAAM,0BAA0B,eAAe,KAAK,EAAE;aAC7D,GAAG;KACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,YAAO;MACL,SAAS,CAAC;OAAE,MAAM;OAAQ,MAAM,mCAAmC;OAAO,CAAC;MAC3E,SAAS;OAAE,IAAI;OAAO,MAAM;OAAY,OAAO;OAAK;MACrD;;AAIL,QAAI,CAAC,WACH,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAuD,CAAC;KACxF,SAAS;MAAE,IAAI;MAAO,MAAM;MAAY;KACzC;IAGH,MAAM,eAAgB,eAAe,QAAoC,EAAE;IAC3E,MAAM,SAAS,eAAe,WAAW;IAEzC,MAAM,MAAM,aAAa,MADN,KAAK,gBAAgB,EACT,OAAO;AAGtC,QAAI,KAAK,YAEP,QAAO,aAAa,MADC,KAAK,YAAY,YAAY,cAAc,KAAK,OAAO,CACjD;AAI7B,QAAI;KACF,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAE5C,YAAO,aAAa,MADC,mBAAmB,YAAY,cAAc,KAAK,UAAU,OAAO,CAC7D;aACpB,GAAG;KACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,SAAI,MAAM,EAAE,KAAK,GAAG,EAAE,8BAA8B,MAAM;AAC1D,YAAO;MACL,SAAS,CAAC;OAAE,MAAM;OAAQ,MAAM,oBAAoB;OAAO,CAAC;MAC5D,SAAS;OAAE,IAAI;OAAO,MAAM;OAAY,OAAO;OAAK;MACrD;;;AAIL,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,iBAAiB;KAAQ,CAAC;IAC1D,SAAS,EAAE,IAAI,OAAO;IACvB;;EAGM"}
1
+ {"version":3,"file":"browser-use-tool.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/browser-use-tool.ts"],"sourcesContent":["/**\n * browser_use — unified browser AgentTool.\n *\n * Modes: command | pipeline | inspect | close.\n * Replaces the 14 fine-grained browser_* tools with a single entry point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport { createLogger } from '../../../../utils/logger.js';\nimport type { Config } from '../../../../config/schema.js';\nimport type { BrowserManager } from '../../../../browser/manager.js';\nimport type { CdpSupervisor } from '../../../../browser/cdp-supervisor.js';\nimport type { Page } from 'playwright-core';\n\nimport { BrowserUseSchema } from './schemas.js';\nimport { createBrowserActionRegistry } from '../../../../browser/actions/registry.js';\nimport type { BrowserActionContext, BrowserActionResult } from '../../../../browser/actions/types.js';\nimport { loadBrowserPipelineSource } from '../../../../browser/pipeline/source.js';\nimport type { BrowserNotReadyError, BrowserSetupHint } from '../../../../browser/readiness.js';\n\nconst log = createLogger('Agent:BrowserUse');\n\nexport interface CreateBrowserUseToolDeps {\n getManager: () => BrowserManager;\n getPageForTask: () => Promise<Page>;\n getTaskId: () => string;\n getConfig: () => Config | undefined;\n getSupervisor?: () => CdpSupervisor | undefined;\n notifyBrowserPageClosed?: (taskId: string) => void;\n /**\n * Preflight readiness check. Returns `null` when the configured backend is\n * usable, otherwise a structured hint the chat surface renders as a setup\n * card. Cache the result upstream (~30s) so back-to-back calls don't reprobe.\n */\n getReadiness?: () => Promise<BrowserNotReadyError | null>;\n /** Pipeline runner (injected to avoid circular deps; lazy-loaded if not provided). */\n runPipeline?: (\n yaml: string,\n args: Record<string, unknown>,\n ctx: BrowserActionContext,\n options: { dryRun?: boolean; sourceLocation?: string },\n ) => Promise<BrowserActionResult>;\n}\n\nexport function createBrowserUseTool(deps: CreateBrowserUseToolDeps): AgentTool<any, any> {\n const registry = createBrowserActionRegistry();\n\n function buildContext(page: Page, signal?: AbortSignal): BrowserActionContext {\n return {\n page,\n manager: deps.getManager(),\n config: deps.getConfig(),\n taskId: deps.getTaskId(),\n supervisor: deps.getSupervisor?.(),\n signal,\n };\n }\n\n /**\n * Render a {@link BrowserSetupHint} as a tool result. The text body is a\n * JSON envelope (`kind: 'browser_setup_required'`) so the chat surface can\n * detect it and render a Setup card; the embedded `message` keeps the\n * payload human-readable for the LLM so it stops the browser attempt and\n * tells the user to finish setup.\n */\n function formatNotReady(hint: BrowserSetupHint): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n const message =\n `⚠ Browser is not ready (backend=${hint.backend}, reason=${hint.reason}). ` +\n `Do NOT retry. Tell the user to open Settings → Browser to finish setup, ` +\n `then ask them to confirm before running any browser action again.`;\n const payload = {\n kind: 'browser_setup_required' as const,\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n detail: hint.detail,\n message,\n };\n return {\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n details: {\n ok: false,\n kind: 'browser_setup_required',\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n },\n };\n }\n\n function formatResult(result: BrowserActionResult): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n if (result.ok) {\n const parts: string[] = [];\n if (result.text) parts.push(result.text);\n if (result.data && !result.text) parts.push(JSON.stringify(result.data, null, 2));\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'OK' }],\n details: { ok: true, action: result.action, ...(result.artifacts?.length ? { artifacts: result.artifacts.length } : {}) },\n };\n }\n const parts: string[] = [];\n if (result.error) parts.push(`[${result.error.code}] ${result.error.message}`);\n if (result.diagnostics?.url) parts.push(`URL: ${result.diagnostics.url}`);\n if (result.diagnostics?.snapshot) parts.push(`Snapshot: ${result.diagnostics.snapshot.slice(0, 2000)}`);\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'Failed' }],\n details: { ok: false, action: result.action, error: result.error },\n };\n }\n\n const tool: any = {\n name: 'browser_use',\n label: '🌐 Browser',\n description:\n 'Use a persistent browser for web navigation, page inspection, interaction, screenshots, network capture, and scripted browser pipelines. For non-trivial browser tasks, load the built-in manual first with tool_manual({ tool: \"browser_use\" }).',\n parameters: BrowserUseSchema,\n\n async execute(_toolCallId, params: any, signal, _onUpdate) {\n const { mode, command, args: cmdArgs, pipeline: pipelineParams, options: _options } = params as {\n mode: string;\n command?: string;\n args?: Record<string, unknown>;\n pipeline?: { yaml?: string; path?: string; args?: Record<string, unknown>; dryRun?: boolean };\n options?: { timeout?: number; headless?: boolean };\n };\n\n // ─── readiness preflight ────────────────────────────────────────────\n // Probes the configured backend (doctor + WS bridge / CDP / cloud key)\n // before any launch attempt. On failure we short-circuit with a setup\n // hint the chat renders as a card — the agent should stop and ask the\n // user to finish setup instead of looping on launch errors.\n if (deps.getReadiness) {\n try {\n const notReady = await deps.getReadiness();\n if (notReady) {\n return formatNotReady(notReady.hint);\n }\n } catch (e) {\n log.warn({ err: e }, 'Readiness preflight threw; continuing with launch attempt');\n }\n }\n\n // ─── inspect ────────────────────────────────────────────────────────\n if (mode === 'inspect') {\n const mgr = deps.getManager();\n await mgr.ensureConnected();\n const ext = mgr.getExtensionProvider();\n if (ext) {\n const timeout = deps.getConfig?.()?.agents?.defaults?.browser?.commandTimeout;\n const timeoutMs =\n typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0\n ? Math.floor(timeout * 1000)\n : 30_000;\n const urlRes = await ext.sendCommand('get_url', {}, { timeout: timeoutMs });\n const titleRes = await ext.sendCommand('get_title', {}, { timeout: timeoutMs });\n const snapRes = await ext.sendCommand('snapshot', {}, { timeout: timeoutMs });\n const url = urlRes.ok && urlRes.data ? String((urlRes.data as { url?: string }).url ?? '') : '';\n const title =\n titleRes.ok && titleRes.data ? String((titleRes.data as { title?: string }).title ?? '') : '';\n let snapText = '';\n if (snapRes.ok && snapRes.data) {\n const nodes = (snapRes.data as { nodes?: Array<{ role?: string; name?: string }> }).nodes ?? [];\n snapText = nodes.map((n) => `${n.role ?? '?'}: ${n.name ?? ''}`).join('\\n');\n if (snapText.length > 8000) snapText = `${snapText.slice(0, 8000)}\\n... (truncated)`;\n }\n const text = `URL: ${url}\\nTitle: ${title}\\n${snapText ? `--- Page Snapshot ---\\n${snapText}` : ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const result = await registry.execute('state', ctx, {});\n // Augment with URL / title\n const url = page.url();\n const title = await page.title().catch(() => '');\n const text = `URL: ${url}\\nTitle: ${title}\\n${result.text ?? ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n\n // ─── close ──────────────────────────────────────────────────────────\n if (mode === 'close') {\n const taskId = deps.getTaskId();\n await deps.getManager().ensureConnected();\n await deps.getManager().closePage(taskId);\n deps.notifyBrowserPageClosed?.(taskId);\n return {\n content: [{ type: 'text', text: 'Browser page closed.' }],\n details: { ok: true, mode: 'close' },\n };\n }\n\n // ─── command ────────────────────────────────────────────────────────\n if (mode === 'command') {\n if (!command) {\n return {\n content: [{ type: 'text', text: 'Missing `command` parameter for command mode.' }],\n details: { ok: false, mode: 'command' },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const args = cmdArgs ?? {};\n const result = await registry.execute(command, ctx, args);\n return formatResult(result);\n }\n\n // ─── pipeline ──────────────────────────────────────────────────────\n if (mode === 'pipeline') {\n if (!pipelineParams) {\n return {\n content: [{ type: 'text', text: 'Missing `pipeline` parameter for pipeline mode.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n let yamlSource = pipelineParams.yaml ?? '';\n let sourceLocation: string | undefined;\n\n if (!yamlSource && pipelineParams.path) {\n try {\n const loaded = await loadBrowserPipelineSource(pipelineParams.path);\n yamlSource = loaded.source;\n sourceLocation = loaded.location;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [{ type: 'text', text: `Failed to read pipeline source: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n if (!yamlSource) {\n return {\n content: [{ type: 'text', text: 'Pipeline mode requires `yaml`, `script`, or `path`.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n const pipelineArgs = (pipelineParams.args as Record<string, unknown>) ?? {};\n const dryRun = pipelineParams.dryRun === true;\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n\n // Use injected runner or lazy-load\n if (deps.runPipeline) {\n const result = await deps.runPipeline(yamlSource, pipelineArgs, ctx, { dryRun, sourceLocation });\n return formatResult(result);\n }\n\n // Lazy import pipeline runner\n try {\n const { runBrowserPipeline } = await import('../../../../browser/pipeline/runner.js');\n const result = await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, { dryRun, sourceLocation });\n return formatResult(result);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.error({ err: e }, `Pipeline execution failed: ${msg}`);\n return {\n content: [{ type: 'text', text: `Pipeline failed: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n return {\n content: [{ type: 'text', text: `Unknown mode: ${mode}` }],\n details: { ok: false },\n };\n },\n };\n return tool;\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@
3
3
  */
4
4
  export declare const BrowserUsePipelineSchema: import("@sinclair/typebox/build/cjs").TObject<{
5
5
  yaml: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
6
- script: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
7
6
  path: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
8
7
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
9
8
  dryRun: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TBoolean>;
@@ -18,7 +17,6 @@ export declare const BrowserUseSchema: import("@sinclair/typebox/build/cjs").TOb
18
17
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
19
18
  pipeline: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TObject<{
20
19
  yaml: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
21
- script: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
22
20
  path: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
23
21
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
24
22
  dryRun: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TBoolean>;
@@ -4,8 +4,7 @@ import { Type } from "@sinclair/typebox";
4
4
  * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.
5
5
  */
6
6
  const BrowserUsePipelineSchema = Type.Object({
7
- yaml: Type.Optional(Type.String({ description: "Inline YAML pipeline (brocli-style DSL)." })),
8
- script: Type.Optional(Type.String({ description: "Alias for `yaml` — inline brocli YAML script." })),
7
+ yaml: Type.Optional(Type.String({ description: "Inline YAML browser pipeline." })),
9
8
  path: Type.Optional(Type.String({ description: "Path or http(s) URL to a .yaml pipeline file." })),
10
9
  args: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Override pipeline arg defaults." })),
11
10
  dryRun: Type.Optional(Type.Boolean({ description: "Only parse & validate, do not execute." }))
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/schemas.ts"],"sourcesContent":["/**\n * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.\n */\n\nimport { Type } from '@sinclair/typebox';\n\nexport const BrowserUsePipelineSchema = Type.Object({\n yaml: Type.Optional(Type.String({ description: 'Inline YAML pipeline (brocli-style DSL).' })),\n script: Type.Optional(Type.String({ description: 'Alias for `yaml` — inline brocli YAML script.' })),\n path: Type.Optional(Type.String({ description: 'Path or http(s) URL to a .yaml pipeline file.' })),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Override pipeline arg defaults.' }),\n ),\n dryRun: Type.Optional(Type.Boolean({ description: 'Only parse & validate, do not execute.' })),\n});\n\nexport const BrowserUseOptionsSchema = Type.Object({\n timeout: Type.Optional(Type.Number({ description: 'Action timeout override (ms).' })),\n headless: Type.Optional(Type.Boolean({ description: 'Override headless mode for this call.' })),\n});\n\nexport const BrowserUseSchema = Type.Object({\n mode: Type.Union(\n [\n Type.Literal('command'),\n Type.Literal('pipeline'),\n Type.Literal('inspect'),\n Type.Literal('close'),\n ],\n { description: 'Execution mode.' },\n ),\n command: Type.Optional(\n Type.String({ description: 'Browser action name (command mode). E.g. open, click, type, screenshot.' }),\n ),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Action arguments (command mode).' }),\n ),\n pipeline: Type.Optional(BrowserUsePipelineSchema),\n options: Type.Optional(BrowserUseOptionsSchema),\n});\n"],"mappings":";;;;;AAMA,MAAa,2BAA2B,KAAK,OAAO;CAClD,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,4CAA4C,CAAC,CAAC;CAC7F,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CACpG,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CAClG,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,mCAAmC,CAAC,CAC/F;CACD,QAAQ,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,0CAA0C,CAAC,CAAC;CAC/F,CAAC;AAEF,MAAa,0BAA0B,KAAK,OAAO;CACjD,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CACrF,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,yCAAyC,CAAC,CAAC;CAChG,CAAC;AAEF,MAAa,mBAAmB,KAAK,OAAO;CAC1C,MAAM,KAAK,MACT;EACE,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,WAAW;EACxB,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,QAAQ;EACtB,EACD,EAAE,aAAa,mBAAmB,CACnC;CACD,SAAS,KAAK,SACZ,KAAK,OAAO,EAAE,aAAa,2EAA2E,CAAC,CACxG;CACD,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,oCAAoC,CAAC,CAChG;CACD,UAAU,KAAK,SAAS,yBAAyB;CACjD,SAAS,KAAK,SAAS,wBAAwB;CAChD,CAAC"}
1
+ {"version":3,"file":"schemas.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/schemas.ts"],"sourcesContent":["/**\n * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.\n */\n\nimport { Type } from '@sinclair/typebox';\n\nexport const BrowserUsePipelineSchema = Type.Object({\n yaml: Type.Optional(Type.String({ description: 'Inline YAML browser pipeline.' })),\n path: Type.Optional(Type.String({ description: 'Path or http(s) URL to a .yaml pipeline file.' })),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Override pipeline arg defaults.' }),\n ),\n dryRun: Type.Optional(Type.Boolean({ description: 'Only parse & validate, do not execute.' })),\n});\n\nexport const BrowserUseOptionsSchema = Type.Object({\n timeout: Type.Optional(Type.Number({ description: 'Action timeout override (ms).' })),\n headless: Type.Optional(Type.Boolean({ description: 'Override headless mode for this call.' })),\n});\n\nexport const BrowserUseSchema = Type.Object({\n mode: Type.Union(\n [\n Type.Literal('command'),\n Type.Literal('pipeline'),\n Type.Literal('inspect'),\n Type.Literal('close'),\n ],\n { description: 'Execution mode.' },\n ),\n command: Type.Optional(\n Type.String({ description: 'Browser action name (command mode). E.g. open, click, type, screenshot.' }),\n ),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Action arguments (command mode).' }),\n ),\n pipeline: Type.Optional(BrowserUsePipelineSchema),\n options: Type.Optional(BrowserUseOptionsSchema),\n});\n"],"mappings":";;;;;AAMA,MAAa,2BAA2B,KAAK,OAAO;CAClD,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CAClF,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CAClG,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,mCAAmC,CAAC,CAC/F;CACD,QAAQ,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,0CAA0C,CAAC,CAAC;CAC/F,CAAC;AAEF,MAAa,0BAA0B,KAAK,OAAO;CACjD,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CACrF,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,yCAAyC,CAAC,CAAC;CAChG,CAAC;AAEF,MAAa,mBAAmB,KAAK,OAAO;CAC1C,MAAM,KAAK,MACT;EACE,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,WAAW;EACxB,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,QAAQ;EACtB,EACD,EAAE,aAAa,mBAAmB,CACnC;CACD,SAAS,KAAK,SACZ,KAAK,OAAO,EAAE,aAAa,2EAA2E,CAAC,CACxG;CACD,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,oCAAoC,CAAC,CAChG;CACD,UAAU,KAAK,SAAS,yBAAyB;CACjD,SAAS,KAAK,SAAS,wBAAwB;CAChD,CAAC"}
@@ -3,8 +3,8 @@ import { init_logger } from "../../utils/logger.js";
3
3
  import { SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE } from "../memory/dreaming/constants.js";
4
4
  import { loadDreamingStore, saveDreamingStore } from "../memory/dreaming/short-term-store.js";
5
5
  import { resolveDreamingConfig } from "../memory/dreaming/config.js";
6
- import fs from "node:fs/promises";
7
6
  import path from "node:path";
7
+ import fs from "node:fs/promises";
8
8
  import { Type } from "@sinclair/typebox";
9
9
  //#region src/agent/tools/dreaming-tool.ts
10
10
  init_logger();
@@ -1,6 +1,5 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
4
3
  import { createReadFileTool } from "./read.js";
5
4
  import { createWriteFileTool } from "./write.js";
6
5
  import { createEditFileTool } from "./edit.js";
@@ -45,7 +44,6 @@ import { mergeTtsConfigFromAppConfig } from "../../voice/tts/merge-config.js";
45
44
  import { createTextToSpeechTool } from "./tts-tool.js";
46
45
  import { createGoalEvidenceRecorder } from "./goal-evidence-recorder.js";
47
46
  //#region src/agent/tools/factory.ts
48
- init_session_key();
49
47
  init_logger();
50
48
  const log = createLogger("AgentToolsFactory");
51
49
  /** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */
@@ -54,12 +52,6 @@ const CLARIFY_SUPPORTED_CHANNELS = new Set([
54
52
  "telegram",
55
53
  "cli"
56
54
  ]);
57
- function clarifyTransportSource(sessionKey) {
58
- const parsed = parseSessionKey(sessionKey);
59
- if (parsed) return parsed.source;
60
- const first = sessionKey.split(":").filter(Boolean)[0] ?? "";
61
- if (first === "cli" || first === "webchat") return first;
62
- }
63
55
  var AgentToolsFactory = class AgentToolsFactory {
64
56
  browserManager = null;
65
57
  /** One dialog/console supervisor per chat session (browser tab). */
@@ -195,8 +187,7 @@ var AgentToolsFactory = class AgentToolsFactory {
195
187
  if (!req) return null;
196
188
  const ctx = this.deps.getCurrentContext();
197
189
  if (!ctx?.sessionKey) return null;
198
- const source = clarifyTransportSource(ctx.sessionKey);
199
- if (!source || !CLARIFY_SUPPORTED_CHANNELS.has(source)) return null;
190
+ if (!CLARIFY_SUPPORTED_CHANNELS.has(ctx.channel)) return null;
200
191
  return (r) => req(ctx.sessionKey, r);
201
192
  } }),
202
193
  createTodoTool({ getSessionKey: () => this.deps.getCurrentContext()?.sessionKey }),