@gaodefa/daocore 2026.5.29 → 2026.5.30
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.
- package/dist/abort-DI3P6TIb.js +277 -0
- package/dist/abort.runtime-B6Z7lDEa.js +2 -0
- package/dist/abort.runtime.js +1 -1
- package/dist/account-inspect-BFz7X0TX.js +173 -0
- package/dist/accounts-BoYYrY7x.js +107 -0
- package/dist/accounts-Busq29zW.js +107 -0
- package/dist/accounts-CuvH2tuN.js +119 -0
- package/dist/accounts-DkIcqvf7.js +2 -0
- package/dist/acp-runtime-BA8lzXzf.js +26 -0
- package/dist/acp-spawn-DPz2aX3A.js +2 -0
- package/dist/acp-spawn-DvVCsWYV.js +1275 -0
- package/dist/acp-stateful-target-driver-DcC76aZW.js +89 -0
- package/dist/action-kill-D-dVisIX.js +33 -0
- package/dist/action-runtime-BEiqwxDD.js +469 -0
- package/dist/action-runtime-api-1LzcGjcX.js +2 -0
- package/dist/action-send-c3CnDuPg.js +39 -0
- package/dist/action-spawn-Dj4kwpWs.js +47 -0
- package/dist/actions-qLccmQBc.js +161 -0
- package/dist/actions.runtime-B5vYAgNi.js +5 -0
- package/dist/agent-command-D6Ds198G.js +1367 -0
- package/dist/agent-components.runtime-xquK0B3L.js +10 -0
- package/dist/agent-components.runtime.js +1 -1
- package/dist/agent-harness-runtime-Dq1fCBOM.js +180 -0
- package/dist/agent-harness-task-runtime-DvSEqFkD.js +140 -0
- package/dist/agent-lm5ZYOFy.js +3 -0
- package/dist/agent-runner-execution-Dbh2pDhQ.js +1713 -0
- package/dist/agent-runner-utils-Di3r2T1T.js +266 -0
- package/dist/agent-runner.runtime-BW90EcGW.js +3455 -0
- package/dist/agent-runner.runtime.js +1 -1
- package/dist/agent-runtime-BgIT5Ytc.js +229 -0
- package/dist/agent-via-gateway-DMMS8-hK.js +463 -0
- package/dist/agent-ylolD8-V.js +2 -0
- package/dist/api-BB4vXLtW.js +2 -0
- package/dist/api-CUhM3KNB.js +134 -0
- package/dist/api-CewRHSbT.js +6 -0
- package/dist/api-CfKjNJlW.js +2 -0
- package/dist/api-Rsnqui1u.js +3 -0
- package/dist/api-k7AvxwHr.js +639 -0
- package/dist/apply-DQ4TQNMA.js +54 -0
- package/dist/apply-S_75Py4Y.js +41 -0
- package/dist/approval-handler.runtime-Cthxrstu.js +130 -0
- package/dist/assistant-Cp9pGaBw.js +291 -0
- package/dist/attachment-normalize-5R0bLLOj.js +225 -0
- package/dist/attempt-execution-DuyyZYsU.js +558 -0
- package/dist/attempt-execution.runtime-DF2GPgNh.js +3 -0
- package/dist/attempt-execution.runtime.js +1 -1
- package/dist/attempt-execution.shared-CwdukA3t.js +38 -0
- package/dist/attempt.prompt-helpers-CUqKtIa5.js +475 -0
- package/dist/attempt.tool-run-context-BbN4_BYO.js +2094 -0
- package/dist/binding-routing-C6Ex2Blu.js +113 -0
- package/dist/binding-targets-BqREncSL.js +121 -0
- package/dist/bot-DGMEkaIJ.js +7894 -0
- package/dist/bot-deps-BltYjeMX.js +2 -0
- package/dist/bot-deps-XvGCor9f.js +747 -0
- package/dist/bot-message-context.runtime-kK-xvLV7.js +7 -0
- package/dist/bot-message-context.runtime.js +1 -1
- package/dist/bot-message-context.session.runtime-DpOIJUae.js +12 -0
- package/dist/bot-message-context.session.runtime.js +1 -1
- package/dist/bot-native-commands.delivery.runtime-D49p5Lc1.js +4 -0
- package/dist/bot-native-commands.delivery.runtime.js +1 -1
- package/dist/bot-native-commands.runtime-8XBdSpkQ.js +13 -0
- package/dist/bot-native-commands.runtime.js +1 -1
- package/dist/bridge-server-y_XGduPx.js +113 -0
- package/dist/browser-cli-B2jmmTT3.js +230 -0
- package/dist/browser-cli-actions-input-JQt5ZQcn.js +473 -0
- package/dist/browser-cli-actions-observe-CrfKh6AX.js +81 -0
- package/dist/browser-cli-debug-DQACWlvC.js +137 -0
- package/dist/browser-cli-inspect-DDnxx0Xw.js +104 -0
- package/dist/browser-cli-lEuOnZzs.js +2 -0
- package/dist/browser-cli-manage-DogmwtYt.js +443 -0
- package/dist/browser-cli-resize-BHuV71VZ.js +26 -0
- package/dist/browser-cli-shared-CidShgoF.js +50 -0
- package/dist/browser-cli-state-i8cCGbiQ.js +337 -0
- package/dist/browser-control-auth-CKfXdXWj.js +2 -0
- package/dist/browser-profiles-ATBTvUGh.js +2 -0
- package/dist/browser-runtime-KmCT6FuL.js +384 -0
- package/dist/build-DOOT6f62.js +257 -0
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +2 -2
- package/dist/bundled/session-memory/handler.js +1 -1
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/capability-cli-DwvrwB-g.js +1782 -0
- package/dist/channel-B-wgK1bK.js +481 -0
- package/dist/channel-B1e_k1P0.js +867 -0
- package/dist/channel-BRDfa5tc.js +1777 -0
- package/dist/channel-BVEO1O4p.js +376 -0
- package/dist/channel-BYlO5l1d.js +508 -0
- package/dist/channel-Bl0sPoNx.js +653 -0
- package/dist/channel-C84xtDBy.js +1134 -0
- package/dist/channel-CLgKq4Ds.js +1556 -0
- package/dist/channel-CZT0qxLh.js +1249 -0
- package/dist/channel-CffBHWkb.js +955 -0
- package/dist/channel-D34ZJvVB.js +2126 -0
- package/dist/channel-DcdXLo_W.js +238 -0
- package/dist/channel-DnK5TrXV.js +362 -0
- package/dist/channel-Dzj4RHY2.js +740 -0
- package/dist/channel-OhZzLZCj.js +562 -0
- package/dist/channel-actions.runtime-Cdvhqc9s.js +265 -0
- package/dist/channel-actions.runtime.js +1 -1
- package/dist/channel-core-Dz9I_R4j.js +5 -0
- package/dist/channel-inbound-COGoV_aS.js +80 -0
- package/dist/channel-mP6HCIMr.js +1496 -0
- package/dist/channel-plugin-runtime-C0R46KeG.js +998 -0
- package/dist/channel-quGdgWel.js +808 -0
- package/dist/channel-runtime-FvPQoIF9.js +408 -0
- package/dist/channel.runtime-2vUz3gij.js +109 -0
- package/dist/channel.runtime-BZLDSNuQ.js +254 -0
- package/dist/channel.runtime-Bo5jO0Hj.js +4 -0
- package/dist/channel.runtime-CDgvrjM2.js +652 -0
- package/dist/channel.runtime-COf8SDFn.js +88 -0
- package/dist/channel.runtime-C_C1f8lu.js +733 -0
- package/dist/channel.runtime-CqPbsg8t.js +2528 -0
- package/dist/channel.runtime-DtV85Khx.js +1008 -0
- package/dist/channel.runtime-Spt1ukGW.js +21009 -0
- package/dist/channel.setup-Bc0LUQS1.js +1098 -0
- package/dist/channel.setup-ChTkj2hq.js +343 -0
- package/dist/channel.setup-CpMD9F8i.js +10 -0
- package/dist/chat-mUsjD5YN.js +2666 -0
- package/dist/chrome-u314zcbM.js +1503 -0
- package/dist/cli/run-main.js +5 -5
- package/dist/cli-CJMoqXrc.js +1341 -0
- package/dist/cli-compaction-qGYB7suI.js +347 -0
- package/dist/cli-metadata-BBJFpNU9.js +22 -0
- package/dist/cli-runner-C0kcts0I.js +540 -0
- package/dist/cli-runner-CTm8K6s8.js +2 -0
- package/dist/cli-runner.runtime-C8deL5FL.js +3 -0
- package/dist/cli-runner.runtime-DDAg1D0L.js +4 -0
- package/dist/cli-runner.runtime.js +1 -1
- package/dist/cli-startup-metadata.json +8 -8
- package/dist/client-CPxpgs4m.js +650 -0
- package/dist/client-adapter-CLlqOqfu.js +897 -0
- package/dist/client-factory-R7Rr2jwn.js +9 -0
- package/dist/command-auth-CkQP1buP.js +135 -0
- package/dist/command-handlers-CJEjFyMk.js +1609 -0
- package/dist/command-registry-BDgyOqDw.js +4 -0
- package/dist/command-registry-BVi5Jn1S.js +9 -0
- package/dist/command-registry-core-JCfsVRtz.js +110 -0
- package/dist/command-status.runtime-CM1JLzi6.js +90 -0
- package/dist/command-status.runtime.js +1 -1
- package/dist/commands-acp-C1-I78U6.js +74 -0
- package/dist/commands-compact.runtime-DOsNavwp.js +10 -0
- package/dist/commands-compact.runtime.js +1 -1
- package/dist/commands-handlers.runtime-BD1n2WGw.js +6154 -0
- package/dist/commands-handlers.runtime.js +1 -1
- package/dist/commands-status-DU_UTQz1.js +16 -0
- package/dist/commands-status-DejfTakp.js +3 -0
- package/dist/commands-status.runtime-DejfTakp.js +3 -0
- package/dist/commands-status.runtime.js +1 -1
- package/dist/commands-subagents-control.runtime-D7vo_2Y_.js +3 -0
- package/dist/commands-subagents-control.runtime-DGybTjJ6.js +2 -0
- package/dist/commands-subagents-control.runtime.js +1 -1
- package/dist/commands-system-prompt-BEBXAMea.js +2 -0
- package/dist/commands-system-prompt-gj3oQpQO.js +162 -0
- package/dist/commands.runtime-CgXX70IN.js +176 -0
- package/dist/commands.runtime.js +1 -1
- package/dist/commitments/runtime.js +1 -1
- package/dist/compact-C41XxMDt.js +480 -0
- package/dist/compact-DUVAF9EC.js +1141 -0
- package/dist/compact.runtime-COMRg6s3.js +12 -0
- package/dist/compact.runtime.js +1 -1
- package/dist/completion-cli-CmEYoB9a.js +315 -0
- package/dist/computer-use-BwJHu1QF.js +367 -0
- package/dist/config-ATBTvUGh.js +2 -0
- package/dist/config-DlNgjF8W.js +373 -0
- package/dist/config-mutations-tl_OqI6d.js +159 -0
- package/dist/context-engine-host-compat-BNPAIK9F.js +288 -0
- package/dist/context-engine-host-compat-C69CK7zS.js +2 -0
- package/dist/context-engine-lifecycle-iQ8f5a_-.js +1274 -0
- package/dist/control-auth-vVxyGKxY.js +114 -0
- package/dist/control-service-73nj79EW.js +145 -0
- package/dist/control-ui/assets/agents-DdWIz8Vk.js +1008 -0
- package/dist/control-ui/assets/channel-config-extras-C7ELhuDi.js +2 -0
- package/dist/control-ui/assets/channels-Bsoj-9BS.js +367 -0
- package/dist/control-ui/assets/cron-BRTEw1tT.js +1013 -0
- package/dist/control-ui/assets/debug-EKl_F8_L.js +97 -0
- package/dist/control-ui/assets/index-DSbSO7ys.js +7370 -0
- package/dist/control-ui/assets/instances-B1AoYwI5.js +57 -0
- package/dist/control-ui/assets/logs-BChOznzh.js +74 -0
- package/dist/control-ui/assets/nodes-5yebKh9k.js +436 -0
- package/dist/control-ui/assets/sessions-BlDYNThc.js +399 -0
- package/dist/control-ui/assets/skills-shared-CNFnf7KU.js +11 -0
- package/dist/control-ui/assets/skills-uxTDRmLx.js +314 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/sw.js +1 -1
- package/dist/conversation-binding-runtime-CmoTKcY1.js +4 -0
- package/dist/conversation-runtime-BxOHxuin.js +31 -0
- package/dist/core-D0Y2H55f.js +282 -0
- package/dist/core-api-BKlJUtDt.js +5 -0
- package/dist/core-api-_fiftUHn.js +2 -0
- package/dist/crestodian/crestodian.js +1 -1
- package/dist/crestodian/rescue-message.js +1 -1
- package/dist/crestodian-BJifoQiR.js +55 -0
- package/dist/daocore-tools-BMdF8RwK.js +11727 -0
- package/dist/delivery-e2ci_bcX.js +1002 -0
- package/dist/dialogue-BXayGhnz.js +37 -0
- package/dist/dir-fetch-tool-Cara5mZh.js +565 -0
- package/dist/dir-list-tool-CQ8Bo5Ez.js +100 -0
- package/dist/direct-dm-CPk6Qm9D.js +64 -0
- package/dist/directive-handling.fast-lane-BQ9aXqk8.js +68 -0
- package/dist/directive-handling.impl--a5AGurq.js +818 -0
- package/dist/directive-handling.impl-C4JqMwle.js +2 -0
- package/dist/directive-handling.model-selection-pyTYMIXn.js +122 -0
- package/dist/directive-handling.persist.runtime-B7vWT1r9.js +263 -0
- package/dist/directive-handling.persist.runtime.js +1 -1
- package/dist/dispatch-3Ru_eGq1.js +1640 -0
- package/dist/dispatch-acp-transcript.runtime-CYMP-5oE.js +40 -0
- package/dist/dispatch-acp-transcript.runtime.js +1 -1
- package/dist/dispatch-acp.runtime-BVCiklXk.js +18 -0
- package/dist/dispatch-acp.runtime.js +1 -1
- package/dist/doctor-B8mR3Sgr.js +2 -0
- package/dist/doctor-BJ6DuerV.js +6 -0
- package/dist/doctor-config-flow-BdOGs_zn.js +1741 -0
- package/dist/doctor-core-checks-CDf0stz-.js +2 -0
- package/dist/doctor-core-checks-Cpdnu2XI.js +573 -0
- package/dist/doctor-health-0qv_acBu.js +65 -0
- package/dist/doctor-health-contributions-Db1FQgFw.js +696 -0
- package/dist/doctor-lint-C1g4Llgl.js +94 -0
- package/dist/doctor-state-integrity-C8iXFLJ7.js +1231 -0
- package/dist/doctor-update-CsPu6p3d.js +58 -0
- package/dist/dynamic-tools-YQ0z0YKH.js +486 -0
- package/dist/embedded-backend-S0cahIZw.js +579 -0
- package/dist/embedded-gateway-stub.runtime-Cjw12ALm.js +12 -0
- package/dist/embedded-gateway-stub.runtime.js +1 -1
- package/dist/exec-approvals-ArHHjoE-.js +149 -0
- package/dist/extensionAPI.js +1 -1
- package/dist/extensions/active-memory/index.js +1 -1
- package/dist/extensions/admin-http-rpc/index.js +1 -1
- package/dist/extensions/browser/browser-bridge.js +1 -1
- package/dist/extensions/browser/browser-config.js +4 -4
- package/dist/extensions/browser/browser-control-auth.js +2 -2
- package/dist/extensions/browser/browser-doctor.js +2 -2
- package/dist/extensions/browser/browser-maintenance.js +1 -1
- package/dist/extensions/browser/browser-profiles.js +2 -2
- package/dist/extensions/browser/browser-runtime-api.js +11 -11
- package/dist/extensions/browser/cli-metadata.js +1 -1
- package/dist/extensions/browser/index.js +1 -1
- package/dist/extensions/browser/plugin-registration.js +1 -1
- package/dist/extensions/browser/register.runtime.js +4 -4
- package/dist/extensions/browser/runtime-api.js +13 -13
- package/dist/extensions/canvas/index.js +1 -1
- package/dist/extensions/clickclack/api.js +2 -2
- package/dist/extensions/clickclack/channel-plugin-api.js +1 -1
- package/dist/extensions/clickclack/runtime-api.js +2 -2
- package/dist/extensions/device-pair/api.js +1 -1
- package/dist/extensions/device-pair/pair-command-approve.js +1 -1
- package/dist/extensions/file-transfer/index.js +4 -4
- package/dist/extensions/imessage/api.js +2 -2
- package/dist/extensions/imessage/channel-plugin-api.js +1 -1
- package/dist/extensions/imessage/message-tool-api.d.ts +1 -1
- package/dist/extensions/imessage/runtime-api.js +3 -3
- package/dist/extensions/irc/api.js +2 -2
- package/dist/extensions/irc/channel-plugin-api.js +1 -1
- package/dist/extensions/llm-task/index.js +1 -1
- package/dist/extensions/mattermost/api.js +1 -1
- package/dist/extensions/mattermost/channel-plugin-api.js +1 -1
- package/dist/extensions/mattermost/channel-plugin-runtime.js +1 -1
- package/dist/extensions/mattermost/policy-api.js +1 -1
- package/dist/extensions/mattermost/runtime-api.js +2 -2
- package/dist/extensions/mattermost/slash-route-api.js +1 -1
- package/dist/extensions/memory-core/cli-metadata.js +1 -1
- package/dist/extensions/migrate-claude/apply.js +1 -1
- package/dist/extensions/migrate-claude/index.js +1 -1
- package/dist/extensions/migrate-claude/plan.js +1 -1
- package/dist/extensions/migrate-claude/provider.js +1 -1
- package/dist/extensions/migrate-claude/targets.js +1 -1
- package/dist/extensions/migrate-hermes/apply.js +1 -1
- package/dist/extensions/migrate-hermes/index.js +1 -1
- package/dist/extensions/migrate-hermes/model.js +1 -1
- package/dist/extensions/migrate-hermes/plan.js +1 -1
- package/dist/extensions/migrate-hermes/provider.js +1 -1
- package/dist/extensions/migrate-hermes/secrets.js +1 -1
- package/dist/extensions/migrate-hermes/targets.js +1 -1
- package/dist/extensions/policy/api.js +1 -1
- package/dist/extensions/policy/index.js +2 -2
- package/dist/extensions/signal/api.js +6 -6
- package/dist/extensions/signal/channel-plugin-api.js +1 -1
- package/dist/extensions/signal/reaction-runtime-api.js +1 -1
- package/dist/extensions/signal/runtime-api.js +7 -7
- package/dist/extensions/skill-workshop/api.js +1 -1
- package/dist/extensions/skill-workshop/index.js +2 -2
- package/dist/extensions/telegram/account-inspect-api.js +1 -1
- package/dist/extensions/telegram/api.js +11 -11
- package/dist/extensions/telegram/channel-plugin-api.js +2 -2
- package/dist/extensions/telegram/contract-api.js +3 -3
- package/dist/extensions/telegram/runtime-api.js +7 -7
- package/dist/extensions/telegram/security-audit-contract-api.js +1 -1
- package/dist/extensions/telegram/setup-plugin-api.js +1 -1
- package/dist/extensions/telegram/test-api.js +2 -2
- package/dist/extensions/webhooks/api.js +1 -1
- package/dist/extensions/webhooks/index.js +1 -1
- package/dist/extensions/xai/index.js +4 -4
- package/dist/extensions/xai/realtime-transcription-provider.js +1 -1
- package/dist/extensions/xai/speech-provider.js +1 -1
- package/dist/extensions/xai/test-api.js +1 -1
- package/dist/extensions/xai/tts.js +1 -1
- package/dist/extensions/xai/web-search.js +1 -1
- package/dist/extensions/xai/xai-oauth.js +1 -1
- package/dist/file-fetch-tool-DQpAtjX4.js +124 -0
- package/dist/file-write-tool-CkB0oYwe.js +127 -0
- package/dist/format-DUJUpMFQ.js +1145 -0
- package/dist/gateway-cli-CQo_E4Ka.js +435 -0
- package/dist/gateway-method-runtime-1QPgVJH7.js +21 -0
- package/dist/get-reply-DfUcsC-O.js +4689 -0
- package/dist/get-reply-from-config.runtime-C95MG73O.js +2 -0
- package/dist/get-reply-from-config.runtime.js +1 -1
- package/dist/graph-users-DPJe0fPs.js +1419 -0
- package/dist/group-access-DefaNJ6L.js +112 -0
- package/dist/handle-action.guild-admin-C1sy1kGJ.js +288 -0
- package/dist/harness-BgPRdmNK.js +61 -0
- package/dist/health-DFR9A1YV.js +4 -0
- package/dist/heartbeat-runner-BiYVPs25.js +5 -0
- package/dist/heartbeat-runner.runtime-Bmaq8WUA.js +4 -0
- package/dist/heartbeat-runner.runtime.js +1 -1
- package/dist/hooks-CNJDuJUm.js +534 -0
- package/dist/inbound-direct-dm-runtime-DFt58p71.js +2 -0
- package/dist/inbound-reply-dispatch-kgSDM8ax.js +148 -0
- package/dist/index.js +1 -1
- package/dist/init-B0zO_U4r.js +59 -0
- package/dist/inline-buttons-B6zgQW3J.js +40 -0
- package/dist/internal-events-C3Q5t6hg.js +90 -0
- package/dist/isolated-agent-CaSU5GCJ.js +2 -0
- package/dist/isolated-agent-CnsD2TmP.js +1118 -0
- package/dist/lifecycle-i3WZDaIn.js +571 -0
- package/dist/list.probe-g0rUiVXW.js +449 -0
- package/dist/list.status-command-DG3PrmeO.js +789 -0
- package/dist/llm-slug-generator-CHlf69FU.js +78 -0
- package/dist/llm-slug-generator.js +1 -1
- package/dist/local-dispatch.runtime-CDeHUp_A.js +9 -0
- package/dist/local-dispatch.runtime.js +1 -1
- package/dist/manager.runtime-BlLMPUTq.js +2714 -0
- package/dist/manager.runtime.js +1 -1
- package/dist/markdown-to-line-r_mBHMdy.js +811 -0
- package/dist/mcp-http-C5UPIJGR.js +555 -0
- package/dist/mcp-http-CTy9gpfA.js +2 -0
- package/dist/media-understanding-provider-BT6TOuVa.js +339 -0
- package/dist/message-actions-BdcjjwFt.js +145 -0
- package/dist/message-handler-B29Tj2p2.js +1715 -0
- package/dist/message-handler-BhHb1FHI.js +384 -0
- package/dist/message-handler.preflight-ouZ_-3o8.js +1125 -0
- package/dist/message-handler.process-CrYiBx_F.js +1484 -0
- package/dist/model-CLbtocQX.js +74 -0
- package/dist/model-selection-BG_vU9Kl.js +272 -0
- package/dist/models-4KERn3ya.js +104 -0
- package/dist/models-BCa-ipxi.js +2 -0
- package/dist/models-cli-DtpGXEsf.js +256 -0
- package/dist/monitor-B-egsvmI.js +1657 -0
- package/dist/monitor-BJX9Yv7k.js +2 -0
- package/dist/monitor-BPrIy3pV.js +715 -0
- package/dist/monitor-BWknZZ7N.js +4377 -0
- package/dist/monitor-C3y_PtI1.js +60 -0
- package/dist/monitor-DCzfdqE4.js +1370 -0
- package/dist/monitor-P24epSwE.js +2788 -0
- package/dist/monitor-auth-CEG_xldE.js +179 -0
- package/dist/monitor-jEePJbbS.js +834 -0
- package/dist/monitor-polling.runtime-BzlHK11u.js +883 -0
- package/dist/monitor-polling.runtime.js +1 -1
- package/dist/monitor-webhook.runtime-vFEhk_Zj.js +387 -0
- package/dist/monitor-webhook.runtime.js +1 -1
- package/dist/monitor.account-BUIfgWXg.js +5233 -0
- package/dist/monitor.runtime-Cp7W4fhb.js +2 -0
- package/dist/monitor.runtime.js +1 -1
- package/dist/monitor.webhook-DzrbeR4T.js +180 -0
- package/dist/node-cli-sessions-CLbI14UA.js +1228 -0
- package/dist/openai-http-BM9BIA_g.js +824 -0
- package/dist/openresponses-http-CNoW9kk8.js +1173 -0
- package/dist/operations-DT4bsxV6.js +805 -0
- package/dist/outbound-adapter-CZRUOgY0.js +543 -0
- package/dist/outbound-session-route-DneMsGNx.js +45 -0
- package/dist/outbound.runtime-CHuoKJJI.js +2 -0
- package/dist/outbound.runtime.js +1 -1
- package/dist/pi-embedded-1-rsueO_.js +3796 -0
- package/dist/pi-embedded-BRfDncVO.js +4 -0
- package/dist/pi-embedded.runtime-DEYoa6bW.js +4 -0
- package/dist/pi-embedded.runtime.js +1 -1
- package/dist/pi-tools-C0P3NgP5.js +2413 -0
- package/dist/plan-BQUkjBMY.js +81 -0
- package/dist/plan-CRO9_2_k.js +112 -0
- package/dist/plugin-BJCmWhnh.js +12396 -0
- package/dist/plugin-app-cache-key-CXAg0F7A.js +46 -0
- package/dist/plugin-enabled-D93Z9LSo.js +233 -0
- package/dist/plugin-registration-BBrTcZnf.js +88 -0
- package/dist/plugin-sdk/.boundary-entry-shims.stamp +1 -1
- package/dist/plugin-sdk/acp-runtime-backend.js +1 -1
- package/dist/plugin-sdk/acp-runtime.js +2 -2
- package/dist/plugin-sdk/agent-harness-runtime.js +6 -6
- package/dist/plugin-sdk/agent-harness-task-runtime.js +1 -1
- package/dist/plugin-sdk/agent-harness.js +7 -7
- package/dist/plugin-sdk/agent-runtime.js +2 -2
- package/dist/plugin-sdk/channel-core.js +2 -2
- package/dist/plugin-sdk/channel-inbound.js +2 -2
- package/dist/plugin-sdk/channel-test-helpers.js +1 -1
- package/dist/plugin-sdk/command-auth.js +1 -1
- package/dist/plugin-sdk/command-status-runtime.js +1 -1
- package/dist/plugin-sdk/compat.js +1 -1
- package/dist/plugin-sdk/conversation-binding-runtime.js +2 -2
- package/dist/plugin-sdk/conversation-runtime.js +3 -3
- package/dist/plugin-sdk/core.js +2 -2
- package/dist/plugin-sdk/direct-dm.js +1 -1
- package/dist/plugin-sdk/gateway-method-runtime.js +1 -1
- package/dist/plugin-sdk/health.js +2 -2
- package/dist/plugin-sdk/inbound-reply-dispatch.js +1 -1
- package/dist/plugin-sdk/index.js +1 -1
- package/dist/plugin-sdk/mattermost.js +1 -1
- package/dist/plugin-sdk/plugin-test-contracts.js +2 -2
- package/dist/plugin-sdk/provider-test-contracts.js +4 -4
- package/dist/plugin-sdk/reply-runtime.js +4 -4
- package/dist/plugin-sdk/testing.js +2 -2
- package/dist/plugin-sdk/zalouser.js +1 -1
- package/dist/plugin-service-DnZEPBEA.js +1229 -0
- package/dist/plugins/runtime/index.js +4 -4
- package/dist/policy-CMv5QMPG.js +138 -0
- package/dist/policy-CeoP4t9J.js +680 -0
- package/dist/prepare.runtime-DZ55JiTt.js +732 -0
- package/dist/prepare.runtime.js +1 -1
- package/dist/preview-warnings-O08PZRxu.js +392 -0
- package/dist/probe-C6w3bP8X.js +682 -0
- package/dist/probe-Cs1_X1NA.js +47 -0
- package/dist/probe-Cuee_jyM.js +2204 -0
- package/dist/probe-DZxCnDzn.js +2 -0
- package/dist/program-C2dT8VHB.js +131 -0
- package/dist/provider-C2_vSzYh.js +32 -0
- package/dist/provider-DSfTDQbj.js +152 -0
- package/dist/provider-U8hrm9h-.js +32 -0
- package/dist/provider-_v910H8y.js +8735 -0
- package/dist/provider-dispatcher-C3kmmIEC.js +22 -0
- package/dist/provider-dispatcher.runtime.js +1 -1
- package/dist/provider-session.runtime-Mg0fx5hH.js +9 -0
- package/dist/provider-session.runtime.js +1 -1
- package/dist/provider.runtime-pSTXuHrq.js +2 -0
- package/dist/provider.runtime.js +1 -1
- package/dist/public-surface-loader-09t4TTue.js +114 -0
- package/dist/pw-ai-DjNqHV3_.js +3029 -0
- package/dist/pw-role-snapshot-DoGefdv7.js +333 -0
- package/dist/reaction-level-C8Mqxizo.js +19 -0
- package/dist/reaction-runtime-api-DOP6xOsm.js +116 -0
- package/dist/realtime-transcription-provider-BTGEXXna.js +205 -0
- package/dist/register-CbZPpqI3.js +2178 -0
- package/dist/register.agent-DrBFuPKh.js +156 -0
- package/dist/register.crestodian-DwTbmaK8.js +24 -0
- package/dist/register.maintenance-BIeoYBub.js +83 -0
- package/dist/register.runtime-B5V9_Dwz.js +54 -0
- package/dist/register.subclis-CJE9ISZY.js +31 -0
- package/dist/register.subclis-YQsKas8N.js +3 -0
- package/dist/register.subclis-core-CjwdGeGU.js +273 -0
- package/dist/repair-sequencing-C0jrL5pw.js +640 -0
- package/dist/reply-delivery-B28mTIpb.js +196 -0
- package/dist/reply-runtime-BqQX7HHw.js +11 -0
- package/dist/reply.runtime-C95MG73O.js +2 -0
- package/dist/reply.runtime.js +1 -1
- package/dist/request-BqoMvXxH.js +54 -0
- package/dist/resolve-allowlist-hbKKd_kq.js +220 -0
- package/dist/result-fallback-classifier-BrORPoxj.js +79 -0
- package/dist/route-HHRgSzVy.js +469 -0
- package/dist/route-resolution-C7bafjVc.js +274 -0
- package/dist/routes-86XGeo7a.js +2 -0
- package/dist/routes-BhVGr9ie.js +3602 -0
- package/dist/run-Bb5QP5JV.js +1162 -0
- package/dist/run-attempt-CLi0wV7j.js +7704 -0
- package/dist/run-command-Be6GAxiW.js +2 -0
- package/dist/run-command-Ds4hr3iU.js +23 -0
- package/dist/run-embedded.runtime-wX9ORojX.js +4 -0
- package/dist/run-embedded.runtime.js +1 -1
- package/dist/run-execution-cli.runtime-BmNZVB2N.js +4 -0
- package/dist/run-execution-cli.runtime.js +1 -1
- package/dist/run-executor.runtime.js +1 -1
- package/dist/run-subagent-registry.runtime-Uq5sjftu.js +2 -0
- package/dist/run-subagent-registry.runtime.js +1 -1
- package/dist/runtime-BktLQ75j.js +1287 -0
- package/dist/runtime-C9XdR62_.js +438 -0
- package/dist/runtime-CTvWDPx9.js +6179 -0
- package/dist/runtime-api-BojB3MUw.js +21 -0
- package/dist/runtime-api-C92MlAwp.js +13 -0
- package/dist/runtime-api-CFNZE9Xt.js +13 -0
- package/dist/runtime-api-Cimpgm5_.js +3 -0
- package/dist/runtime-api-D8qG_lUm.js +17 -0
- package/dist/runtime-api-DMDMnQEG.js +4 -0
- package/dist/runtime-api-DupQdIlE.js +24 -0
- package/dist/runtime-api.actions-B8i3elqu.js +3 -0
- package/dist/runtime-api.monitor-BntFzf_M.js +6 -0
- package/dist/runtime-api.send-CPlmi1jc.js +4 -0
- package/dist/runtime-api.threads-D-H_r_Nl.js +2 -0
- package/dist/runtime-channel-BGhTxnXZ.js +150 -0
- package/dist/runtime-channel-CPFxNapZ.js +2 -0
- package/dist/runtime-embedded-pi.runtime-BjnMTurB.js +2 -0
- package/dist/runtime-embedded-pi.runtime.js +1 -1
- package/dist/sanitize-outbound-BMUv1NeS.js +127 -0
- package/dist/sdk-setup-tools-Do3DkQi_.js +8 -0
- package/dist/secrets-B8YVPHhk.js +113 -0
- package/dist/security-audit-7Gg_nL4o.js +122 -0
- package/dist/security-audit-Bk3CREj-.js +118 -0
- package/dist/security-audit.runtime-BmSJrdeq.js +2 -0
- package/dist/security-audit.runtime.js +1 -1
- package/dist/selection-BFGde9-_.js +3 -0
- package/dist/selection-DrLFlbgG.js +16157 -0
- package/dist/send-4dLa-BQo.js +1631 -0
- package/dist/send-CV6gCwYP.js +192 -0
- package/dist/send-aGiK3Efu.js +143 -0
- package/dist/send-dB3CehAN.js +2 -0
- package/dist/send.components-BcG9BlkC.js +2 -0
- package/dist/send.components-rLjDlfYU.js +500 -0
- package/dist/send.runtime-D20k2MSr.js +2 -0
- package/dist/send.runtime.js +1 -1
- package/dist/server-BTRx_U1s.js +73 -0
- package/dist/server-CY0ymhBg.js +24 -0
- package/dist/server-close.runtime.js +1 -1
- package/dist/server-context-BxGT8wbK.js +955 -0
- package/dist/server-context-DYlbhAaT.js +2 -0
- package/dist/server-cron-BB_15lcP.js +2 -0
- package/dist/server-cron-CfyJX_a4.js +2989 -0
- package/dist/server-methods-Ck2ab6TC.js +16494 -0
- package/dist/server-node-events-BdRizF-5.js +596 -0
- package/dist/server-plugin-bootstrap-CPUr8NFE.js +70 -0
- package/dist/server-plugins-__5AxjzH.js +432 -0
- package/dist/server-reload-handlers-BMl9Fx9b.js +714 -0
- package/dist/server-restart-sentinel-D11M_ZsH.js +747 -0
- package/dist/server-restart-sentinel-DGptQ27c.js +2 -0
- package/dist/server-runtime-services-BwtLs-8I.js +2 -0
- package/dist/server-runtime-services-aJydixRu.js +267 -0
- package/dist/server-startup-plugins-m_P3gY4m.js +113 -0
- package/dist/server-startup-post-attach-DuXQ1AXL.js +716 -0
- package/dist/server-ws-runtime-mXmxB1W8.js +349 -0
- package/dist/server.impl-fuV8aKSP.js +2586 -0
- package/dist/service-a8cTFka4.js +1446 -0
- package/dist/session-binding-BIycxo9u.js +2 -0
- package/dist/session-binding-xHwQr9vM.js +219 -0
- package/dist/session-kill-http-DiUZhcoN.js +121 -0
- package/dist/session-reset-service-DkepDoob.js +625 -0
- package/dist/session-route-Ba5u7ecb.js +93 -0
- package/dist/session-status.runtime-Cb1X69Rl.js +2 -0
- package/dist/session-status.runtime.js +1 -1
- package/dist/session-subagent-reactivation.runtime-rbqmto4G.js +2 -0
- package/dist/session-subagent-reactivation.runtime.js +1 -1
- package/dist/session-tab-registry-DSKOoJta.js +521 -0
- package/dist/sessions-history-http-CWP88I_C.js +430 -0
- package/dist/sessions.runtime-1q1OwLn3.js +2 -0
- package/dist/sessions.runtime.js +1 -1
- package/dist/setup-api-DtrOOYeP.js +29 -0
- package/dist/setup-core-DMrJS6LP.js +174 -0
- package/dist/setup-surface-BFPNu1qA.js +405 -0
- package/dist/setup-surface-CedShqhO.js +288 -0
- package/dist/setup-surface-DLOBH1Vf.js +320 -0
- package/dist/setup-surface-MhCeEWSj.js +221 -0
- package/dist/shared-DamL-e8D.js +121 -0
- package/dist/shared-client-B48JoAsz.js +2 -0
- package/dist/shared-client-BoSiDnUo.js +629 -0
- package/dist/side-question-DQoQ_ETb.js +683 -0
- package/dist/skill-tool-dispatch.runtime-CWLloYA8.js +143 -0
- package/dist/skill-tool-dispatch.runtime.js +1 -1
- package/dist/slash-state-DrrWJQfv.js +2166 -0
- package/dist/speech-provider-8Hx1uw41.js +184 -0
- package/dist/src-BbUYOPwU.js +4256 -0
- package/dist/startup-context-opAJAamX.js +313 -0
- package/dist/status-subagents.runtime-DSo7ZK_Z.js +18 -0
- package/dist/status-subagents.runtime.js +1 -1
- package/dist/status-text-AyPuDzrO.js +296 -0
- package/dist/sticker-cache-91Tp8mLP.js +206 -0
- package/dist/sticker-vision.runtime-DjleFXi5.js +17 -0
- package/dist/sticker-vision.runtime.js +1 -1
- package/dist/subagent-announce-delivery-DS_2W9oZ.js +958 -0
- package/dist/subagent-announce-hatA_PZ2.js +354 -0
- package/dist/subagent-control-IyFIvc7T.js +508 -0
- package/dist/subagent-hooks-BCj5eB0Z.js +2 -0
- package/dist/subagent-hooks-BWjTBkox.js +146 -0
- package/dist/subagent-hooks-CdGLK9_3.js +230 -0
- package/dist/subagent-hooks-EH0tBkw9.js +2 -0
- package/dist/subagent-hooks-api-BhYaXQJV.js +23 -0
- package/dist/subagent-hooks-api-uGsV8Xn5.js +22 -0
- package/dist/subagent-hooks-api-wfJFKIPx.js +23 -0
- package/dist/subagent-hooks-l8Xd94dt.js +2 -0
- package/dist/subagent-hooks-m2eHUO_d.js +116 -0
- package/dist/subagent-orphan-recovery-Bq9zvX3L.js +352 -0
- package/dist/subagent-registry-Bcb3zy6b.js +3 -0
- package/dist/subagent-registry-CoZNTFx-.js +2351 -0
- package/dist/subagent-registry.runtime.js +1 -1
- package/dist/subagent-session-cleanup--00EjDLe.js +525 -0
- package/dist/subagent-spawn-ClJJkz3D.js +1164 -0
- package/dist/target-id-BsZLiF3x.js +107 -0
- package/dist/targets-CQMe4AZP.js +44 -0
- package/dist/targets-SmL1AU-H.js +19 -0
- package/dist/targets-Y-roiA47.js +19 -0
- package/dist/task-registry-control.runtime.js +1 -1
- package/dist/telegram/token.js +1 -1
- package/dist/testing-B5hNJDuF.js +267 -0
- package/dist/thread-bindings-BD3eE0kK.js +232 -0
- package/dist/thread-bindings-C9NNiv8K.js +571 -0
- package/dist/thread-bindings-Dl4PN1vZ.js +228 -0
- package/dist/thread-bindings-uK1LLAwy.js +8 -0
- package/dist/thread-bindings.discord-api-BHNEUbnk.js +187 -0
- package/dist/thread-bindings.manager-B0LXiH3F.js +2 -0
- package/dist/thread-bindings.manager-BTlH4XMG.js +536 -0
- package/dist/thread-lifecycle-DG8uyPHd.js +1614 -0
- package/dist/token-BbGCANnE.js +134 -0
- package/dist/tool-actions.runtime-oUUrD8HB.js +534 -0
- package/dist/tool-actions.runtime.js +1 -1
- package/dist/tool-bqg-_vYv.js +139 -0
- package/dist/tool-resolution-CSZsa3kP.js +149 -0
- package/dist/tools-effective-inventory-0CqFp-vq.js +204 -0
- package/dist/tools-invoke-http-DhYHY0Yh.js +67 -0
- package/dist/tools-invoke-shared-CbVJJUj7.js +200 -0
- package/dist/tts-C2qD-ad6.js +66 -0
- package/dist/tui-CzGY254f.js +4709 -0
- package/dist/tui-backend-fzoeoSN0.js +256 -0
- package/dist/tui-cli-B2RWb2gM.js +37 -0
- package/dist/tui-dgS8hdXU.js +2 -0
- package/dist/update-cli-BmiBDf3c.js +3664 -0
- package/dist/update-runner-CM7QVX6u.js +2379 -0
- package/dist/vision-tools-BzoBZnIc.js +1409 -0
- package/dist/web-search-DmfOd66S.js +62 -0
- package/dist/web-search-provider.runtime-3C5-pODD.js +328 -0
- package/dist/web-search-provider.runtime-Doh-Z9We.js +2 -0
- package/dist/web-search-provider.runtime.js +1 -1
- package/dist/xai-oauth-BLvQ43hx.js +479 -0
- package/dist/xai-user-agent-BdMQ_0_O.js +32 -0
- package/package.json +1 -1
- package/dist/abort-DeEb_wKd.js +0 -277
- package/dist/abort.runtime-CoYXQGPK.js +0 -2
- package/dist/account-inspect-D_06-CYS.js +0 -173
- package/dist/accounts-BCTqtj4Y.js +0 -107
- package/dist/accounts-BudLl8P2.js +0 -107
- package/dist/accounts-CUReBDA0.js +0 -2
- package/dist/accounts-PCioSzzr.js +0 -119
- package/dist/acp-runtime-B2t9_BHD.js +0 -26
- package/dist/acp-spawn-0x4Iiu1o.js +0 -2
- package/dist/acp-spawn-B2Ghe0jJ.js +0 -1275
- package/dist/acp-stateful-target-driver-C4VgcSyz.js +0 -89
- package/dist/action-kill-ClYsXEz7.js +0 -33
- package/dist/action-runtime-DrLPkNvU.js +0 -469
- package/dist/action-runtime-api-BqSflr9q.js +0 -2
- package/dist/action-send-CIy9cziD.js +0 -39
- package/dist/action-spawn-BjV6lFnX.js +0 -47
- package/dist/actions-D-QH7wq5.js +0 -161
- package/dist/actions.runtime-hzDtXQGU.js +0 -5
- package/dist/agent-Bb1DTBgv.js +0 -3
- package/dist/agent-Cnqj258q.js +0 -2
- package/dist/agent-command-BRx6ZNgJ.js +0 -1367
- package/dist/agent-components.runtime-D-g6xXJ0.js +0 -10
- package/dist/agent-harness-runtime-dKUQFuOc.js +0 -180
- package/dist/agent-harness-task-runtime-v2crUm3i.js +0 -140
- package/dist/agent-runner-execution-AOzdxvWR.js +0 -1713
- package/dist/agent-runner-utils-Byv50B4Z.js +0 -266
- package/dist/agent-runner.runtime-hhgRE0Z-.js +0 -3455
- package/dist/agent-runtime-BHmh3i0o.js +0 -229
- package/dist/agent-via-gateway-DnCqaK4a.js +0 -463
- package/dist/api-Bzyb8sFU.js +0 -3
- package/dist/api-CIEDFXZs.js +0 -2
- package/dist/api-D_dTQAu8.js +0 -2
- package/dist/api-DilBjZ9Q.js +0 -6
- package/dist/api-E5zoQMmh.js +0 -134
- package/dist/api-OJZug8gQ.js +0 -639
- package/dist/apply-C0eV5T0O.js +0 -41
- package/dist/apply-alsYvxLE.js +0 -54
- package/dist/approval-handler.runtime-C6jqZXSN.js +0 -130
- package/dist/assistant-DDXnAAB5.js +0 -291
- package/dist/attachment-normalize-Cv-_4DWU.js +0 -225
- package/dist/attempt-execution-DECEU59r.js +0 -558
- package/dist/attempt-execution.runtime-kasMxuER.js +0 -3
- package/dist/attempt-execution.shared-ClUxk52p.js +0 -38
- package/dist/attempt.prompt-helpers-Bxlv9VSu.js +0 -475
- package/dist/attempt.tool-run-context-CplQWX6g.js +0 -2094
- package/dist/binding-routing-0Obpp-Ij.js +0 -113
- package/dist/binding-targets-CZHQaZL4.js +0 -121
- package/dist/bot-BPbQ0840.js +0 -7894
- package/dist/bot-deps-Cs1M9USs.js +0 -2
- package/dist/bot-deps-xAcaOtTZ.js +0 -747
- package/dist/bot-message-context.runtime-Bji78Cbn.js +0 -7
- package/dist/bot-message-context.session.runtime-C3dyOIYH.js +0 -12
- package/dist/bot-native-commands.delivery.runtime-WshH99fy.js +0 -4
- package/dist/bot-native-commands.runtime-C1L364gU.js +0 -13
- package/dist/bridge-server-DPlM8_Lk.js +0 -113
- package/dist/browser-cli-DFNQE98N.js +0 -230
- package/dist/browser-cli-Drb5E5--.js +0 -2
- package/dist/browser-cli-actions-input-Dx-1OXmE.js +0 -473
- package/dist/browser-cli-actions-observe-BMDfE7xU.js +0 -81
- package/dist/browser-cli-debug-nu7Ih09g.js +0 -137
- package/dist/browser-cli-inspect-D5X2wohg.js +0 -104
- package/dist/browser-cli-manage-DkzYwph4.js +0 -443
- package/dist/browser-cli-resize-B30Avedl.js +0 -26
- package/dist/browser-cli-shared-cMgQoQzF.js +0 -50
- package/dist/browser-cli-state-CQLDvDy7.js +0 -337
- package/dist/browser-control-auth-D7ArmHUt.js +0 -2
- package/dist/browser-profiles-B39SIZNb.js +0 -2
- package/dist/browser-runtime-DUbSAOOS.js +0 -384
- package/dist/build-D25KqC92.js +0 -257
- package/dist/capability-cli-CuyXrlAB.js +0 -1782
- package/dist/channel-0N3YGMGg.js +0 -1496
- package/dist/channel-1UyKoLyp.js +0 -481
- package/dist/channel-BG87pSEW.js +0 -740
- package/dist/channel-BPGSaZW7.js +0 -1249
- package/dist/channel-BQMPh1J_.js +0 -376
- package/dist/channel-Bd_8V6zn.js +0 -1134
- package/dist/channel-BtBjh_ij.js +0 -362
- package/dist/channel-CpFBlVH6.js +0 -562
- package/dist/channel-CwuTrIrF.js +0 -508
- package/dist/channel-Cxl4sJA-.js +0 -1777
- package/dist/channel-D-VfU4Z2.js +0 -2126
- package/dist/channel-D9q8aYrN.js +0 -867
- package/dist/channel-DKSvVvZh.js +0 -238
- package/dist/channel-DvoFfWLx.js +0 -808
- package/dist/channel-GktTcGHm.js +0 -955
- package/dist/channel-actions.runtime-CKcRA0GW.js +0 -265
- package/dist/channel-core-nm8s1qFZ.js +0 -5
- package/dist/channel-d3t2ESlE.js +0 -653
- package/dist/channel-inbound-DKz40dq-.js +0 -80
- package/dist/channel-plugin-runtime-DKIGZWfW.js +0 -998
- package/dist/channel-runtime-Bh8_GY12.js +0 -408
- package/dist/channel-yQ8jCOb9.js +0 -1556
- package/dist/channel.runtime-BG4mM5cQ.js +0 -652
- package/dist/channel.runtime-BS6PyFFa.js +0 -1008
- package/dist/channel.runtime-CE_xECqN.js +0 -88
- package/dist/channel.runtime-Cd1Sw8U4.js +0 -254
- package/dist/channel.runtime-DIq3XOEe.js +0 -733
- package/dist/channel.runtime-Dy1cx35I.js +0 -21009
- package/dist/channel.runtime-NyIMjLnP.js +0 -109
- package/dist/channel.runtime-Zx5mfE2V.js +0 -4
- package/dist/channel.runtime-rJRibGfN.js +0 -2528
- package/dist/channel.setup--4ACadmF.js +0 -10
- package/dist/channel.setup-DzwqIlo3.js +0 -1098
- package/dist/channel.setup-FKYSJwXR.js +0 -343
- package/dist/chat-CKxSm7r1.js +0 -2666
- package/dist/chrome-rMubJwRG.js +0 -1503
- package/dist/cli-CbTod55I.js +0 -1341
- package/dist/cli-compaction-BbHgjJyW.js +0 -347
- package/dist/cli-metadata-DkOWLC_p.js +0 -22
- package/dist/cli-runner-Cwzv_RKf.js +0 -540
- package/dist/cli-runner-DdnUsgPl.js +0 -2
- package/dist/cli-runner.runtime-BlrSgbEW.js +0 -3
- package/dist/cli-runner.runtime-D8kVfvFH.js +0 -4
- package/dist/client-ClvxsWgL.js +0 -650
- package/dist/client-adapter-CsrIIjK1.js +0 -897
- package/dist/client-factory-DAYClhwm.js +0 -9
- package/dist/command-auth-CCha2ofd.js +0 -135
- package/dist/command-handlers-DCWJzHyB.js +0 -1609
- package/dist/command-registry-BIf61QNz.js +0 -9
- package/dist/command-registry-DJROBy4h.js +0 -4
- package/dist/command-registry-core-BQOWqi6S.js +0 -110
- package/dist/command-status.runtime-D88CUglL.js +0 -90
- package/dist/commands-acp-B-8dHX4Z.js +0 -74
- package/dist/commands-compact.runtime-ComX5mUk.js +0 -10
- package/dist/commands-handlers.runtime-DR3wjXHX.js +0 -6154
- package/dist/commands-status-CDyGrwsI.js +0 -3
- package/dist/commands-status-DV-i_ZIK.js +0 -16
- package/dist/commands-status.runtime-CDyGrwsI.js +0 -3
- package/dist/commands-subagents-control.runtime-B029cXAS.js +0 -3
- package/dist/commands-subagents-control.runtime-DR8Qspe0.js +0 -2
- package/dist/commands-system-prompt-C10ctsG3.js +0 -162
- package/dist/commands-system-prompt-DQlRWwnk.js +0 -2
- package/dist/commands.runtime-BYmIAuN0.js +0 -176
- package/dist/compact-14Ljaaeu.js +0 -480
- package/dist/compact-B--ovdkx.js +0 -1141
- package/dist/compact.runtime-E0Idf2Dq.js +0 -12
- package/dist/completion-cli-DMvvQGSk.js +0 -315
- package/dist/computer-use-CcLwX5SR.js +0 -367
- package/dist/config-B39SIZNb.js +0 -2
- package/dist/config-D4rsGOyV.js +0 -373
- package/dist/config-mutations-CsI3YJu7.js +0 -159
- package/dist/context-engine-host-compat-BZpDFiMJ.js +0 -2
- package/dist/context-engine-host-compat-runUdES5.js +0 -288
- package/dist/context-engine-lifecycle-D6odtNrn.js +0 -1274
- package/dist/control-auth-BPGpPtfz.js +0 -114
- package/dist/control-service-C-OmdPCe.js +0 -145
- package/dist/control-ui/assets/agents-GeyOHPuW.js +0 -1008
- package/dist/control-ui/assets/channel-config-extras-D7en6iUg.js +0 -2
- package/dist/control-ui/assets/channels-DkEyr1w5.js +0 -367
- package/dist/control-ui/assets/cron-C-wThQ1Q.js +0 -1013
- package/dist/control-ui/assets/debug-83AFRtIX.js +0 -97
- package/dist/control-ui/assets/index-CiGEhMOA.js +0 -7370
- package/dist/control-ui/assets/instances-CVl0t-1h.js +0 -57
- package/dist/control-ui/assets/logs-eybVEXxg.js +0 -74
- package/dist/control-ui/assets/nodes-C_A7eoU2.js +0 -436
- package/dist/control-ui/assets/sessions-Cq4Nc69u.js +0 -399
- package/dist/control-ui/assets/skills-ZN6hroIh.js +0 -314
- package/dist/control-ui/assets/skills-shared-DIWGwmdC.js +0 -11
- package/dist/conversation-binding-runtime-C2U1JElL.js +0 -4
- package/dist/conversation-runtime-NmIUd3Zu.js +0 -31
- package/dist/core-DGKJP1dm.js +0 -282
- package/dist/core-api-1fA4sNeC.js +0 -5
- package/dist/core-api-BY822Quq.js +0 -2
- package/dist/crestodian-Bp-NXiBC.js +0 -55
- package/dist/daocore-tools-Defpam0j.js +0 -11727
- package/dist/delivery-CEdVAUGB.js +0 -1002
- package/dist/dialogue-CZ69INPq.js +0 -37
- package/dist/dir-fetch-tool-BCicHhQE.js +0 -565
- package/dist/dir-list-tool-Cv_WktsJ.js +0 -100
- package/dist/direct-dm-Bz89rM8x.js +0 -64
- package/dist/directive-handling.fast-lane-DDnbcc5S.js +0 -68
- package/dist/directive-handling.impl-B0H52Ymr.js +0 -818
- package/dist/directive-handling.impl-CgKpwEW-.js +0 -2
- package/dist/directive-handling.model-selection-_cXAr0vt.js +0 -122
- package/dist/directive-handling.persist.runtime-Dw0mfzXT.js +0 -263
- package/dist/dispatch-C3AeYvyP.js +0 -1640
- package/dist/dispatch-acp-transcript.runtime-CP8pqBwS.js +0 -40
- package/dist/dispatch-acp.runtime-Cdap-AZI.js +0 -18
- package/dist/doctor-BZwVH97p.js +0 -2
- package/dist/doctor-BfkGBii1.js +0 -6
- package/dist/doctor-config-flow-D3JASGDt.js +0 -1741
- package/dist/doctor-core-checks-DH5AIT0Q.js +0 -573
- package/dist/doctor-core-checks-DiNu7VSh.js +0 -2
- package/dist/doctor-health-BDIJ-Nro.js +0 -65
- package/dist/doctor-health-contributions-BgmF7w8X.js +0 -696
- package/dist/doctor-lint-uIxkMUSO.js +0 -94
- package/dist/doctor-state-integrity-ws1b_BGk.js +0 -1231
- package/dist/doctor-update-Cx4CqxaX.js +0 -58
- package/dist/dynamic-tools-DiqOxhJh.js +0 -486
- package/dist/embedded-backend-C634irMl.js +0 -579
- package/dist/embedded-gateway-stub.runtime-CCfrTOeN.js +0 -12
- package/dist/exec-approvals-D85KThSg.js +0 -149
- package/dist/file-fetch-tool-BERaGYCT.js +0 -124
- package/dist/file-write-tool-BjHrMyfe.js +0 -127
- package/dist/format-DE9PuPg1.js +0 -1145
- package/dist/gateway-cli-B5hjhbUy.js +0 -435
- package/dist/gateway-method-runtime-Bu0E9Eki.js +0 -21
- package/dist/get-reply-6PtPz9hv.js +0 -4689
- package/dist/get-reply-from-config.runtime-CwprvhoR.js +0 -2
- package/dist/graph-users-DUp1kgnS.js +0 -1419
- package/dist/group-access-D5GBQ3w6.js +0 -112
- package/dist/handle-action.guild-admin-CA0Y-buD.js +0 -288
- package/dist/harness-B5nOFVfm.js +0 -61
- package/dist/health-D5heIDj3.js +0 -4
- package/dist/heartbeat-runner-BzFkIFHh.js +0 -5
- package/dist/heartbeat-runner.runtime-p6H1_xMV.js +0 -4
- package/dist/hooks-BvTyQ14X.js +0 -534
- package/dist/inbound-direct-dm-runtime-DwiDXi8L.js +0 -2
- package/dist/inbound-reply-dispatch-YoDUOC6C.js +0 -148
- package/dist/init-CPtcV5Xu.js +0 -59
- package/dist/inline-buttons-DeD5d42c.js +0 -40
- package/dist/internal-events-DEb50Sw3.js +0 -90
- package/dist/isolated-agent-CcxFFZ-Z.js +0 -1118
- package/dist/isolated-agent-CpHzq5qr.js +0 -2
- package/dist/lifecycle-DNel-oMe.js +0 -571
- package/dist/list.probe-DCa3N25d.js +0 -449
- package/dist/list.status-command-CyeAJmZW.js +0 -789
- package/dist/llm-slug-generator-CyqTY37Z.js +0 -78
- package/dist/local-dispatch.runtime-nE39kFIP.js +0 -9
- package/dist/manager.runtime-CpAPB8D5.js +0 -2714
- package/dist/markdown-to-line-Ci6TRmoZ.js +0 -811
- package/dist/mcp-http-BR0vmxFL.js +0 -2
- package/dist/mcp-http-C0oniA8h.js +0 -555
- package/dist/media-understanding-provider-BwA0XqC3.js +0 -339
- package/dist/message-actions-C9C_Ngkd.js +0 -145
- package/dist/message-handler-CUUKPC5n.js +0 -384
- package/dist/message-handler-xRTfIXWV.js +0 -1715
- package/dist/message-handler.preflight-Ch2Q7V3M.js +0 -1125
- package/dist/message-handler.process-HM3mK93q.js +0 -1484
- package/dist/model-CB8Ex5xS.js +0 -74
- package/dist/model-selection-2s0Dinux.js +0 -272
- package/dist/models-Cn-6DJ41.js +0 -2
- package/dist/models-CzszJD__.js +0 -104
- package/dist/models-cli-CbhElnA5.js +0 -256
- package/dist/monitor-7aprTsMV.js +0 -715
- package/dist/monitor-BuVhqwDS.js +0 -1370
- package/dist/monitor-C4H_YkgY.js +0 -2
- package/dist/monitor-CPQsMxgv.js +0 -1657
- package/dist/monitor-Ce0V1PiR.js +0 -4377
- package/dist/monitor-D0bcGJWI.js +0 -60
- package/dist/monitor-DEjlJqzh.js +0 -834
- package/dist/monitor-auth-DjJZsjgV.js +0 -179
- package/dist/monitor-ikSYagv3.js +0 -2788
- package/dist/monitor-polling.runtime-D7yEflMM.js +0 -883
- package/dist/monitor-webhook.runtime-CIZt-biI.js +0 -387
- package/dist/monitor.account-C2sMOBCS.js +0 -5233
- package/dist/monitor.runtime-BAi6zmcn.js +0 -2
- package/dist/monitor.webhook-BcjpfRCX.js +0 -180
- package/dist/node-cli-sessions-CIhkJRU4.js +0 -1228
- package/dist/openai-http-Dj21RwSj.js +0 -824
- package/dist/openresponses-http-COnnr1ox.js +0 -1173
- package/dist/operations-H3vUh0lM.js +0 -805
- package/dist/outbound-adapter-WLtWE7wv.js +0 -543
- package/dist/outbound-session-route-CZtd64EH.js +0 -45
- package/dist/outbound.runtime-D98P0sN1.js +0 -2
- package/dist/pi-embedded-BWJzd4mK.js +0 -4
- package/dist/pi-embedded-DeNsSqQQ.js +0 -3796
- package/dist/pi-embedded.runtime-CZnNwFpc.js +0 -4
- package/dist/pi-tools-CNHSpjBa.js +0 -2413
- package/dist/plan-B0reFFlM.js +0 -81
- package/dist/plan-CrfF-TH8.js +0 -112
- package/dist/plugin-DI_8eYOe.js +0 -12396
- package/dist/plugin-app-cache-key-WaTUD3e-.js +0 -46
- package/dist/plugin-enabled-aWLXgGGi.js +0 -233
- package/dist/plugin-registration-ByjRIVJm.js +0 -88
- package/dist/plugin-service-VQm_241d.js +0 -1229
- package/dist/policy-BmJH-swe.js +0 -680
- package/dist/policy-DE-bO1zn.js +0 -138
- package/dist/prepare.runtime-bSj3-res.js +0 -732
- package/dist/preview-warnings-CbuGYsF9.js +0 -392
- package/dist/probe-C_rWg7_m.js +0 -682
- package/dist/probe-CagOFfx6.js +0 -2
- package/dist/probe-thX1HqOh.js +0 -2204
- package/dist/probe-zU6B6gFt.js +0 -47
- package/dist/program-BtVdH743.js +0 -131
- package/dist/provider-CDoD7tO0.js +0 -8735
- package/dist/provider-CK1gMdJ2.js +0 -32
- package/dist/provider-DJqr9djy.js +0 -32
- package/dist/provider-DsOJp5bK.js +0 -152
- package/dist/provider-dispatcher-UNQ-LSx9.js +0 -22
- package/dist/provider-session.runtime-DMrkMb4x.js +0 -9
- package/dist/provider.runtime-C2-t3zm8.js +0 -2
- package/dist/public-surface-loader-hTeyyHcd.js +0 -114
- package/dist/pw-ai-BaL3eVYx.js +0 -3029
- package/dist/pw-role-snapshot-DKeBqhN1.js +0 -333
- package/dist/reaction-level-BV2potsD.js +0 -19
- package/dist/reaction-runtime-api-CCBxgM10.js +0 -116
- package/dist/realtime-transcription-provider-CHYtIXZm.js +0 -205
- package/dist/register-BJf28G9B.js +0 -2178
- package/dist/register.agent-oXAHwNQv.js +0 -156
- package/dist/register.crestodian-CQ0sqdV2.js +0 -24
- package/dist/register.maintenance-CylVRs5M.js +0 -83
- package/dist/register.runtime-CcDgwy0X.js +0 -54
- package/dist/register.subclis-CpBYNw2X.js +0 -3
- package/dist/register.subclis-N2CvieOL.js +0 -31
- package/dist/register.subclis-core-BHaGvbzg.js +0 -273
- package/dist/repair-sequencing-EBBnBdIB.js +0 -640
- package/dist/reply-delivery-BLoPALlI.js +0 -196
- package/dist/reply-runtime-D4asNTSa.js +0 -11
- package/dist/reply.runtime-CwprvhoR.js +0 -2
- package/dist/request-DlWPRUDt.js +0 -54
- package/dist/resolve-allowlist-BukQf58x.js +0 -220
- package/dist/result-fallback-classifier-DyHFnqfV.js +0 -79
- package/dist/route-BMf4keN5.js +0 -469
- package/dist/route-resolution-DWNi1QAu.js +0 -274
- package/dist/routes-C20LC8c4.js +0 -3602
- package/dist/routes-CkK7Vv_m.js +0 -2
- package/dist/run-KDF_AEza.js +0 -1162
- package/dist/run-attempt-JHYCfonU.js +0 -7704
- package/dist/run-command-3PVihYIy.js +0 -2
- package/dist/run-command-QHAXnyKY.js +0 -23
- package/dist/run-embedded.runtime-BJw-2vss.js +0 -4
- package/dist/run-execution-cli.runtime-GHClMn2g.js +0 -4
- package/dist/run-subagent-registry.runtime-BLLMrhtE.js +0 -2
- package/dist/runtime-C2u-dC1r.js +0 -1287
- package/dist/runtime-ClyfkDWT.js +0 -6179
- package/dist/runtime-WXCarlPc.js +0 -438
- package/dist/runtime-api-3QhGLpZf.js +0 -13
- package/dist/runtime-api-DRAu3mjv.js +0 -4
- package/dist/runtime-api-JE07pOem.js +0 -13
- package/dist/runtime-api-JuKylHvw.js +0 -24
- package/dist/runtime-api-bcbk4yax.js +0 -21
- package/dist/runtime-api-dDe9U2_V.js +0 -17
- package/dist/runtime-api-uMexLqGS.js +0 -3
- package/dist/runtime-api.actions-Bo7TLDFl.js +0 -3
- package/dist/runtime-api.monitor-7q78L1Em.js +0 -6
- package/dist/runtime-api.send-Bf9RR4nV.js +0 -4
- package/dist/runtime-api.threads-Dj2QuhHj.js +0 -2
- package/dist/runtime-channel-k1C0Satl.js +0 -2
- package/dist/runtime-channel-qt9t0J-J.js +0 -150
- package/dist/runtime-embedded-pi.runtime-BPB9NlTS.js +0 -2
- package/dist/sanitize-outbound-BLH_SQvg.js +0 -127
- package/dist/sdk-setup-tools-BshlBPau.js +0 -8
- package/dist/secrets-CsHXv7d3.js +0 -113
- package/dist/security-audit-CUXBQXNX.js +0 -122
- package/dist/security-audit-CzdXbRma.js +0 -118
- package/dist/security-audit.runtime-Ca0FMFJG.js +0 -2
- package/dist/selection-BmvQJlSD.js +0 -3
- package/dist/selection-BplDXc9w.js +0 -16157
- package/dist/send--qFg8a9v.js +0 -1631
- package/dist/send-BPdryPPA.js +0 -192
- package/dist/send-Bl4YaRkS.js +0 -143
- package/dist/send-Ccm7RMXC.js +0 -2
- package/dist/send.components-c3OUPSmR.js +0 -2
- package/dist/send.components-rhQJYoXs.js +0 -500
- package/dist/send.runtime-dfUkAp5d.js +0 -2
- package/dist/server-DRhyTMLe.js +0 -73
- package/dist/server-Dv4BzjGn.js +0 -24
- package/dist/server-context-4HRJy2vp.js +0 -955
- package/dist/server-context-DlxYb1G5.js +0 -2
- package/dist/server-cron-Bt8Pkc3i.js +0 -2989
- package/dist/server-cron-CtNWsa4Z.js +0 -2
- package/dist/server-methods-rye_okUW.js +0 -16494
- package/dist/server-node-events-C1yZ5a1u.js +0 -596
- package/dist/server-plugin-bootstrap-DUMyVtlP.js +0 -70
- package/dist/server-plugins-B5ZWWkRE.js +0 -432
- package/dist/server-reload-handlers-CTnMXNjT.js +0 -714
- package/dist/server-restart-sentinel-CAYxtwmY.js +0 -747
- package/dist/server-restart-sentinel-DqrtSIvy.js +0 -2
- package/dist/server-runtime-services-CuptQTe5.js +0 -2
- package/dist/server-runtime-services-aaS2IiW3.js +0 -267
- package/dist/server-startup-plugins-D0ymJgQT.js +0 -113
- package/dist/server-startup-post-attach-DlrN2uyt.js +0 -716
- package/dist/server-ws-runtime-CdpLbv4o.js +0 -349
- package/dist/server.impl-Cb4qcMTg.js +0 -2586
- package/dist/service-qxvDlMQE.js +0 -1446
- package/dist/session-binding-6bLobLHL.js +0 -219
- package/dist/session-binding-Bm6fCpoY.js +0 -2
- package/dist/session-kill-http-B6WjVo8V.js +0 -121
- package/dist/session-reset-service-GUVIhxp4.js +0 -625
- package/dist/session-route-BcRDnvzG.js +0 -93
- package/dist/session-status.runtime-BcjOunV4.js +0 -2
- package/dist/session-subagent-reactivation.runtime-BSmk_KYn.js +0 -2
- package/dist/session-tab-registry-BBYzbSOu.js +0 -521
- package/dist/sessions-history-http-bLJJfgLm.js +0 -430
- package/dist/sessions.runtime-DNRtQzCk.js +0 -2
- package/dist/setup-api-CcolVVJs.js +0 -29
- package/dist/setup-core-eJD18F3B.js +0 -174
- package/dist/setup-surface-B75C2Qtz.js +0 -221
- package/dist/setup-surface-CFuPfVHp.js +0 -405
- package/dist/setup-surface-Dyy-Mzyz.js +0 -288
- package/dist/setup-surface-ZsVF_g8W.js +0 -320
- package/dist/shared-BkCNrcLX.js +0 -121
- package/dist/shared-client-B7zqC9p2.js +0 -2
- package/dist/shared-client-yXjKgZBz.js +0 -629
- package/dist/side-question-DU3gESCb.js +0 -683
- package/dist/skill-tool-dispatch.runtime-CPBuqyvk.js +0 -143
- package/dist/slash-state-Do3bAahA.js +0 -2166
- package/dist/speech-provider-Bg9los3C.js +0 -184
- package/dist/src-D7LzUctH.js +0 -4256
- package/dist/startup-context-CCF2gIOl.js +0 -313
- package/dist/status-subagents.runtime-DX5FTymp.js +0 -18
- package/dist/status-text-B-1u5dSV.js +0 -296
- package/dist/sticker-cache-DwpU_9RJ.js +0 -206
- package/dist/sticker-vision.runtime-Bbldi_YL.js +0 -17
- package/dist/subagent-announce-BCo0VHVL.js +0 -354
- package/dist/subagent-announce-delivery-JcnuDN_N.js +0 -958
- package/dist/subagent-control-BzbA3Suz.js +0 -508
- package/dist/subagent-hooks-BIGZQWrG.js +0 -2
- package/dist/subagent-hooks-Bj4qYZfv.js +0 -230
- package/dist/subagent-hooks-C-rvhVBv.js +0 -2
- package/dist/subagent-hooks-P01_AFl5.js +0 -116
- package/dist/subagent-hooks-VEfak8nl.js +0 -2
- package/dist/subagent-hooks-api-BPnSxxN4.js +0 -23
- package/dist/subagent-hooks-api-DwIAvMoS.js +0 -22
- package/dist/subagent-hooks-api-kgyR9FOb.js +0 -23
- package/dist/subagent-hooks-oED56wqq.js +0 -146
- package/dist/subagent-orphan-recovery-D79ZzwKN.js +0 -352
- package/dist/subagent-registry-D0soBT5j.js +0 -2351
- package/dist/subagent-registry-DRJDkmty.js +0 -3
- package/dist/subagent-session-cleanup-9eAO1aJe.js +0 -525
- package/dist/subagent-spawn-D80vbogm.js +0 -1164
- package/dist/target-id-COLv5LsJ.js +0 -107
- package/dist/targets-CDW5IQ6a.js +0 -44
- package/dist/targets-Ci6O1ZdP.js +0 -19
- package/dist/targets-CsaWFBg1.js +0 -19
- package/dist/testing-BoJit-h1.js +0 -267
- package/dist/thread-bindings-CGCvw0KT.js +0 -571
- package/dist/thread-bindings-ClCTNacX.js +0 -228
- package/dist/thread-bindings-DRb7BMZ6.js +0 -8
- package/dist/thread-bindings-Xc6smav0.js +0 -232
- package/dist/thread-bindings.discord-api-DC467oeF.js +0 -187
- package/dist/thread-bindings.manager-C_mpTDIZ.js +0 -536
- package/dist/thread-bindings.manager-DkCRs612.js +0 -2
- package/dist/thread-lifecycle-DpqCXlx9.js +0 -1614
- package/dist/token-CI6HjbTA.js +0 -134
- package/dist/tool-BMe7hjBK.js +0 -139
- package/dist/tool-actions.runtime-D-h5PI_m.js +0 -534
- package/dist/tool-resolution-CnLx0CHe.js +0 -149
- package/dist/tools-effective-inventory-BR6MUMtE.js +0 -204
- package/dist/tools-invoke-http-CTTs2yMT.js +0 -67
- package/dist/tools-invoke-shared-9B1EjXWf.js +0 -200
- package/dist/tts-eGOviZ5c.js +0 -66
- package/dist/tui-Bw0HqKd7.js +0 -4709
- package/dist/tui-CIZJnPzj.js +0 -2
- package/dist/tui-backend-BJ_r7tcF.js +0 -256
- package/dist/tui-cli-BaSMBpuA.js +0 -37
- package/dist/update-cli-zuCybGNR.js +0 -3664
- package/dist/update-runner-Dek2BHmQ.js +0 -2379
- package/dist/vision-tools-1ps0BEE5.js +0 -1409
- package/dist/web-search-B7EziZXE.js +0 -62
- package/dist/web-search-provider.runtime-DGTCvGch.js +0 -328
- package/dist/web-search-provider.runtime-DWL5t39M.js +0 -2
- package/dist/xai-oauth-CRtsj2Gs.js +0 -479
- package/dist/xai-user-agent-Dndwzw2S.js +0 -32
- /package/dist/{acp-runtime-backend-DSDBcyh9.js → acp-runtime-backend-Cxo7eBHf.js} +0 -0
- /package/dist/{channel-actions-FV66JqtI.js → channel-actions-UDeVjgGz.js} +0 -0
- /package/dist/{command-status-runtime-BRWKSoG7.js → command-status-runtime-CoHd4Fws.js} +0 -0
- /package/dist/{delegate-DGqKhwB4.js → delegate-B-2xZ77o.js} +0 -0
- /package/dist/{dispatch-acp-Ceoxja_Z.js → dispatch-acp-DLPkmK7K.js} +0 -0
- /package/dist/{heartbeat-runner-CJHvr5pG.js → heartbeat-runner-D2j6JwOI.js} +0 -0
- /package/dist/{library-Bq3aDek_.js → library-DBT0cIPP.js} +0 -0
- /package/dist/{run-executor.runtime-DNJhGPbA.js → run-executor.runtime-DE4J7f4M.js} +0 -0
- /package/dist/{shared-CYxmRpq1.js → shared-xeo8Yh5n.js} +0 -0
package/dist/routes-C20LC8c4.js
DELETED
|
@@ -1,3602 +0,0 @@
|
|
|
1
|
-
import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString$4 } from "./string-coerce-DyL154ka.js";
|
|
2
|
-
import { i as formatErrorMessage } from "./errors-D_oyTIw2.js";
|
|
3
|
-
import { f as pathScope } from "./fs-safe-BFN3ftAo.js";
|
|
4
|
-
import { p as resolveUserPath } from "./utils-CNnMhEDp.js";
|
|
5
|
-
import { i as getRuntimeConfig } from "./io-Ct2JqgbR.js";
|
|
6
|
-
import { c as getImageMetadata, o as buildImageResizeSideGrid, p as resizeToJpeg, r as IMAGE_REDUCE_QUALITY_STEPS, u as isImageProcessorUnavailableError } from "./media-services-C8kJ1LwP.js";
|
|
7
|
-
import { a as ensureMediaDir, u as saveMediaBuffer } from "./store-53qCOCD8.js";
|
|
8
|
-
import "./string-coerce-runtime-DcopKqDR.js";
|
|
9
|
-
import { C as BrowserTabNotFoundError, E as toBrowserErrorResponse, L as DEFAULT_AI_SNAPSHOT_EFFICIENT_MAX_CHARS, R as DEFAULT_AI_SNAPSHOT_MAX_CHARS, T as BrowserValidationError, W as DEFAULT_BROWSER_SCREENSHOT_TIMEOUT_MS, _ as BrowserConflictError, b as BrowserProfileUnavailableError, d as parseBrowserHttpUrl, f as redactCdpUrl, n as assertCdpEndpointAllowed, p as withCdpSocket, v as BrowserError, w as BrowserTargetAmbiguousError, y as BrowserProfileNotFoundError } from "./cdp.helpers-Dc4Aa7R9.js";
|
|
10
|
-
import { a as DEFAULT_DOWNLOAD_DIR, i as resolveProfile, o as DEFAULT_TRACE_DIR, r as resolveManagedBrowserHeadlessMode, s as DEFAULT_UPLOAD_DIR } from "./config-D4rsGOyV.js";
|
|
11
|
-
import "./config-B39SIZNb.js";
|
|
12
|
-
import "./errors-CdV5A9eu.js";
|
|
13
|
-
import { i as isValidProfileName, n as deleteBrowserProfileConfig, t as createBrowserProfileConfig } from "./config-mutations-CsI3YJu7.js";
|
|
14
|
-
import { r as resolveBrowserExecutableForPlatform } from "./chrome.executables-CeF4Du_1.js";
|
|
15
|
-
import { t as movePathToTrash } from "./trash-CBCzn4Yn.js";
|
|
16
|
-
import { n as normalizeString } from "./record-shared-DnJBzWLH.js";
|
|
17
|
-
import "./sdk-setup-tools-BshlBPau.js";
|
|
18
|
-
import { E as uploadChromeMcpFile, T as takeChromeMcpSnapshot, _ as navigateChromeMcpPage, a as closeChromeMcpTab, c as evaluateChromeMcpScript, f as getChromeMcpPid, l as fillChromeMcpElement, m as hoverChromeMcpElement, n as clickChromeMcpCoords, o as dragChromeMcpElement, r as clickChromeMcpElement, u as fillChromeMcpForm, w as takeChromeMcpScreenshot, x as resizeChromeMcpPage, y as pressChromeMcpKey } from "./chrome-mcp-5e65bt26.js";
|
|
19
|
-
import { E as withBrowserNavigationPolicy, S as assertBrowserNavigationAllowed, _ as INTERACTIVE_ROLES, a as resolveDaoCoreUserDataDir, b as resolveBrowserNavigationProxyMode, g as CONTENT_ROLES, h as snapshotRoleViaCdp, m as snapshotAria, t as getChromeWebSocketUrl, u as captureScreenshot, v as STRUCTURAL_ROLES, w as assertBrowserNavigationResultAllowed, y as ensureOutputDirectory } from "./chrome-rMubJwRG.js";
|
|
20
|
-
import { a as shouldUsePlaywrightForAriaSnapshot, i as resolveDefaultSnapshotFormat, n as getPwAiModule$1, o as shouldUsePlaywrightForScreenshot, r as getBrowserProfileCapabilities, t as resolveTargetIdFromTabs } from "./target-id-COLv5LsJ.js";
|
|
21
|
-
import { c as ACT_MAX_CLICK_DELAY_MS, l as ACT_MAX_WAIT_TIME_MS, o as normalizeBrowserFormField, p as matchBrowserUrlPattern, r as getRoleSnapshotStats, u as normalizeActBoundedNonNegativeMs } from "./pw-role-snapshot-DKeBqhN1.js";
|
|
22
|
-
import fs from "node:fs";
|
|
23
|
-
import path from "node:path";
|
|
24
|
-
import crypto from "node:crypto";
|
|
25
|
-
//#region extensions/browser/src/browser/routes/utils.ts
|
|
26
|
-
function normalizeOptionalString$3(value) {
|
|
27
|
-
return value.trim() || void 0;
|
|
28
|
-
}
|
|
29
|
-
function asyncBrowserRoute(handler) {
|
|
30
|
-
return (req, res) => handler(req, res);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Extract profile name from query string or body and get profile context.
|
|
34
|
-
* Query string takes precedence over body for consistency with GET routes.
|
|
35
|
-
*/
|
|
36
|
-
function getProfileContext(req, ctx) {
|
|
37
|
-
let profileName;
|
|
38
|
-
if (typeof req.query.profile === "string") profileName = normalizeOptionalString$3(req.query.profile);
|
|
39
|
-
if (!profileName && req.body && typeof req.body === "object") {
|
|
40
|
-
const body = req.body;
|
|
41
|
-
if (typeof body.profile === "string") profileName = normalizeOptionalString$3(body.profile);
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
return ctx.forProfile(profileName);
|
|
45
|
-
} catch (err) {
|
|
46
|
-
return {
|
|
47
|
-
error: String(err),
|
|
48
|
-
status: 404
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function jsonError(res, status, message) {
|
|
53
|
-
res.status(status).json({ error: message });
|
|
54
|
-
}
|
|
55
|
-
function toStringOrEmpty(value) {
|
|
56
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return normalizeOptionalString$3(String(value)) ?? "";
|
|
57
|
-
return "";
|
|
58
|
-
}
|
|
59
|
-
function toNumber(value) {
|
|
60
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
61
|
-
const normalized = typeof value === "string" ? normalizeOptionalString$3(value) : void 0;
|
|
62
|
-
if (normalized) {
|
|
63
|
-
const parsed = Number(normalized);
|
|
64
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function toBoolean(value) {
|
|
68
|
-
if (typeof value === "boolean") return value;
|
|
69
|
-
if (typeof value !== "string" && typeof value !== "number") return;
|
|
70
|
-
const normalized = String(value).trim().toLowerCase();
|
|
71
|
-
if (normalized === "true" || normalized === "1" || normalized === "yes") return true;
|
|
72
|
-
if (normalized === "false" || normalized === "0" || normalized === "no") return false;
|
|
73
|
-
}
|
|
74
|
-
function toStringArray(value) {
|
|
75
|
-
if (!Array.isArray(value)) return;
|
|
76
|
-
const strings = value.map((v) => toStringOrEmpty(v)).filter(Boolean);
|
|
77
|
-
return strings.length ? strings : void 0;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region extensions/browser/src/browser/routes/agent.shared.ts
|
|
81
|
-
function normalizeOptionalString$2(value) {
|
|
82
|
-
return typeof value === "string" ? value.trim() || void 0 : void 0;
|
|
83
|
-
}
|
|
84
|
-
const SELECTOR_UNSUPPORTED_MESSAGE = [
|
|
85
|
-
"Error: 'selector' is not supported. Use 'ref' from snapshot instead.",
|
|
86
|
-
"",
|
|
87
|
-
"Example workflow:",
|
|
88
|
-
"1. snapshot action to get page state with refs",
|
|
89
|
-
"2. act with ref: \"e123\" to interact with element",
|
|
90
|
-
"",
|
|
91
|
-
"This is more reliable for modern SPAs."
|
|
92
|
-
].join("\n");
|
|
93
|
-
function readBody(req) {
|
|
94
|
-
const body = req.body;
|
|
95
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
96
|
-
return body;
|
|
97
|
-
}
|
|
98
|
-
function resolveTargetIdFromBody(body) {
|
|
99
|
-
return (normalizeOptionalString$2(body.targetId) ?? "") || void 0;
|
|
100
|
-
}
|
|
101
|
-
function resolveTargetIdFromQuery(query) {
|
|
102
|
-
return (normalizeOptionalString$2(query.targetId) ?? "") || void 0;
|
|
103
|
-
}
|
|
104
|
-
function handleRouteError(ctx, res, err) {
|
|
105
|
-
const mapped = ctx.mapTabError(err);
|
|
106
|
-
if (mapped) return jsonError(res, mapped.status, mapped.message);
|
|
107
|
-
const browserMapped = toBrowserErrorResponse(err);
|
|
108
|
-
if (browserMapped) return jsonError(res, browserMapped.status, browserMapped.message);
|
|
109
|
-
jsonError(res, 500, String(err));
|
|
110
|
-
}
|
|
111
|
-
function resolveProfileContext(req, res, ctx) {
|
|
112
|
-
const profileCtx = getProfileContext(req, ctx);
|
|
113
|
-
if ("error" in profileCtx) {
|
|
114
|
-
jsonError(res, profileCtx.status, profileCtx.error);
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return profileCtx;
|
|
118
|
-
}
|
|
119
|
-
async function getPwAiModule() {
|
|
120
|
-
return await getPwAiModule$1({ mode: "soft" });
|
|
121
|
-
}
|
|
122
|
-
async function requirePwAi(res, feature) {
|
|
123
|
-
const mod = await getPwAiModule();
|
|
124
|
-
if (mod) return mod;
|
|
125
|
-
jsonError(res, 501, [
|
|
126
|
-
`Playwright is not available in this gateway build; '${feature}' is unsupported.`,
|
|
127
|
-
"Reinstall or update DaoCore so the core browser runtime dependency is present, then restart the gateway. In Docker, also install Chromium with the bundled playwright-core CLI.",
|
|
128
|
-
"Docs: /tools/browser#playwright-requirement"
|
|
129
|
-
].join("\n"));
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
async function withRouteTabContext(params) {
|
|
133
|
-
const profileCtx = resolveProfileContext(params.req, params.res, params.ctx);
|
|
134
|
-
if (!profileCtx) return;
|
|
135
|
-
try {
|
|
136
|
-
const tab = await profileCtx.ensureTabAvailable(params.targetId);
|
|
137
|
-
if (params.enforceCurrentUrlAllowed) await assertBrowserNavigationResultAllowed({
|
|
138
|
-
url: tab.url,
|
|
139
|
-
...withBrowserNavigationPolicy(params.ctx.state().resolved.ssrfPolicy, { browserProxyMode: resolveBrowserNavigationProxyMode({
|
|
140
|
-
resolved: params.ctx.state().resolved,
|
|
141
|
-
profile: profileCtx.profile
|
|
142
|
-
}) })
|
|
143
|
-
});
|
|
144
|
-
return await params.run({
|
|
145
|
-
profileCtx,
|
|
146
|
-
tab,
|
|
147
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
148
|
-
resolveTabUrl: (fallbackUrl) => resolveSafeRouteTabUrl({
|
|
149
|
-
ctx: params.ctx,
|
|
150
|
-
profileCtx,
|
|
151
|
-
targetId: tab.targetId,
|
|
152
|
-
fallbackUrl
|
|
153
|
-
})
|
|
154
|
-
});
|
|
155
|
-
} catch (err) {
|
|
156
|
-
handleRouteError(params.ctx, params.res, err);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Response-only URL redaction. This swallows policy failures and must not be used as
|
|
162
|
-
* an execution gate; use enforceCurrentUrlAllowed on the route helper instead.
|
|
163
|
-
*/
|
|
164
|
-
async function resolveSafeRouteTabUrl(params) {
|
|
165
|
-
const candidateUrl = (await params.profileCtx.listTabs().catch(() => [])).find((tab) => tab.targetId === params.targetId)?.url ?? params.fallbackUrl;
|
|
166
|
-
if (!candidateUrl) return;
|
|
167
|
-
try {
|
|
168
|
-
await assertBrowserNavigationResultAllowed({
|
|
169
|
-
url: candidateUrl,
|
|
170
|
-
...withBrowserNavigationPolicy(params.ctx.state().resolved.ssrfPolicy, { browserProxyMode: resolveBrowserNavigationProxyMode({
|
|
171
|
-
resolved: params.ctx.state().resolved,
|
|
172
|
-
profile: params.profileCtx.profile
|
|
173
|
-
}) })
|
|
174
|
-
});
|
|
175
|
-
return candidateUrl;
|
|
176
|
-
} catch {
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
async function withPlaywrightRouteContext(params) {
|
|
181
|
-
return await withRouteTabContext({
|
|
182
|
-
req: params.req,
|
|
183
|
-
res: params.res,
|
|
184
|
-
ctx: params.ctx,
|
|
185
|
-
targetId: params.targetId,
|
|
186
|
-
enforceCurrentUrlAllowed: params.enforceCurrentUrlAllowed,
|
|
187
|
-
run: async ({ profileCtx, tab, cdpUrl, resolveTabUrl }) => {
|
|
188
|
-
const pw = await requirePwAi(params.res, params.feature);
|
|
189
|
-
if (!pw) return;
|
|
190
|
-
return await params.run({
|
|
191
|
-
profileCtx,
|
|
192
|
-
tab,
|
|
193
|
-
cdpUrl,
|
|
194
|
-
resolveTabUrl,
|
|
195
|
-
pw
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region extensions/browser/src/browser/routes/existing-session-limits.ts
|
|
202
|
-
const EXISTING_SESSION_LIMITS = {
|
|
203
|
-
act: {
|
|
204
|
-
clickSelector: "existing-session click does not support selector targeting yet; use ref.",
|
|
205
|
-
clickButtonOrModifiers: "existing-session click currently supports left-click only (no button overrides/modifiers).",
|
|
206
|
-
typeSelector: "existing-session type does not support selector targeting yet; use ref.",
|
|
207
|
-
typeSlowly: "existing-session type does not support slowly=true; use fill/press instead.",
|
|
208
|
-
typeTimeout: "existing-session type does not support timeoutMs overrides.",
|
|
209
|
-
pressDelay: "existing-session press does not support delayMs.",
|
|
210
|
-
hoverSelector: "existing-session hover does not support selector targeting yet; use ref.",
|
|
211
|
-
hoverTimeout: "existing-session hover does not support timeoutMs overrides.",
|
|
212
|
-
scrollSelector: "existing-session scrollIntoView does not support selector targeting yet; use ref.",
|
|
213
|
-
scrollTimeout: "existing-session scrollIntoView does not support timeoutMs overrides.",
|
|
214
|
-
dragSelector: "existing-session drag does not support selector targeting yet; use startRef/endRef.",
|
|
215
|
-
dragTimeout: "existing-session drag does not support timeoutMs overrides.",
|
|
216
|
-
selectSelector: "existing-session select does not support selector targeting yet; use ref.",
|
|
217
|
-
selectSingleValue: "existing-session select currently supports a single value only.",
|
|
218
|
-
selectTimeout: "existing-session select does not support timeoutMs overrides.",
|
|
219
|
-
fillTimeout: "existing-session fill does not support timeoutMs overrides.",
|
|
220
|
-
waitNetworkIdle: "existing-session wait does not support loadState=networkidle yet.",
|
|
221
|
-
evaluateTimeout: "existing-session evaluate does not support timeoutMs overrides.",
|
|
222
|
-
batch: "existing-session batch is not supported yet; send actions individually."
|
|
223
|
-
},
|
|
224
|
-
hooks: {
|
|
225
|
-
uploadElement: "existing-session file uploads do not support element selectors; use ref/inputRef.",
|
|
226
|
-
uploadSingleFile: "existing-session file uploads currently support one file at a time.",
|
|
227
|
-
uploadRefRequired: "existing-session file uploads require ref or inputRef.",
|
|
228
|
-
dialogId: "existing-session dialog handling does not support dialogId.",
|
|
229
|
-
dialogTimeout: "existing-session dialog handling does not support timeoutMs."
|
|
230
|
-
},
|
|
231
|
-
download: {
|
|
232
|
-
waitUnsupported: "download waiting is not supported for existing-session profiles yet.",
|
|
233
|
-
downloadUnsupported: "downloads are not supported for existing-session profiles yet."
|
|
234
|
-
},
|
|
235
|
-
snapshot: {
|
|
236
|
-
pdfUnsupported: "pdf is not supported for existing-session profiles yet; use screenshot/snapshot instead.",
|
|
237
|
-
screenshotElement: "element screenshots are not supported for existing-session profiles; use ref from snapshot.",
|
|
238
|
-
snapshotSelector: "selector/frame snapshots are not supported for existing-session profiles; snapshot the whole page and use refs."
|
|
239
|
-
},
|
|
240
|
-
responseBody: "response body is not supported for existing-session profiles yet."
|
|
241
|
-
};
|
|
242
|
-
//#endregion
|
|
243
|
-
//#region extensions/browser/src/browser/routes/output-paths.ts
|
|
244
|
-
async function ensureOutputRootDir(rootDir) {
|
|
245
|
-
await ensureOutputDirectory(rootDir);
|
|
246
|
-
}
|
|
247
|
-
async function resolveWritableOutputPathOrRespond(params) {
|
|
248
|
-
if (params.ensureRootDir) await ensureOutputRootDir(params.rootDir);
|
|
249
|
-
const pathResult = await pathScope(params.rootDir, { label: params.scopeLabel }).writable(params.requestedPath, { defaultName: params.defaultFileName });
|
|
250
|
-
if (!pathResult.ok) {
|
|
251
|
-
params.res.status(400).json({ error: pathResult.error });
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
254
|
-
return pathResult.path;
|
|
255
|
-
}
|
|
256
|
-
//#endregion
|
|
257
|
-
//#region extensions/browser/src/browser/routes/agent.act.download.ts
|
|
258
|
-
function buildDownloadRequestBase(cdpUrl, targetId, timeoutMs) {
|
|
259
|
-
return {
|
|
260
|
-
cdpUrl,
|
|
261
|
-
targetId,
|
|
262
|
-
timeoutMs: timeoutMs ?? void 0
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
function registerBrowserAgentActDownloadRoutes(app, ctx) {
|
|
266
|
-
app.post("/wait/download", asyncBrowserRoute(async (req, res) => {
|
|
267
|
-
const body = readBody(req);
|
|
268
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
269
|
-
const out = toStringOrEmpty(body.path) || "";
|
|
270
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
271
|
-
await withRouteTabContext({
|
|
272
|
-
req,
|
|
273
|
-
res,
|
|
274
|
-
ctx,
|
|
275
|
-
targetId,
|
|
276
|
-
run: async ({ profileCtx, cdpUrl, tab }) => {
|
|
277
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) return jsonError(res, 501, EXISTING_SESSION_LIMITS.download.waitUnsupported);
|
|
278
|
-
const pw = await requirePwAi(res, "wait for download");
|
|
279
|
-
if (!pw) return;
|
|
280
|
-
await ensureOutputRootDir(DEFAULT_DOWNLOAD_DIR);
|
|
281
|
-
let downloadPath;
|
|
282
|
-
if (out.trim()) {
|
|
283
|
-
const resolvedDownloadPath = await resolveWritableOutputPathOrRespond({
|
|
284
|
-
res,
|
|
285
|
-
rootDir: DEFAULT_DOWNLOAD_DIR,
|
|
286
|
-
requestedPath: out,
|
|
287
|
-
scopeLabel: "downloads directory"
|
|
288
|
-
});
|
|
289
|
-
if (!resolvedDownloadPath) return;
|
|
290
|
-
downloadPath = resolvedDownloadPath;
|
|
291
|
-
}
|
|
292
|
-
const requestBase = buildDownloadRequestBase(cdpUrl, tab.targetId, timeoutMs);
|
|
293
|
-
const result = await pw.waitForDownloadViaPlaywright({
|
|
294
|
-
...requestBase,
|
|
295
|
-
path: downloadPath,
|
|
296
|
-
rootDir: DEFAULT_DOWNLOAD_DIR
|
|
297
|
-
});
|
|
298
|
-
res.json({
|
|
299
|
-
ok: true,
|
|
300
|
-
targetId: tab.targetId,
|
|
301
|
-
download: result
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
}));
|
|
306
|
-
app.post("/download", asyncBrowserRoute(async (req, res) => {
|
|
307
|
-
const body = readBody(req);
|
|
308
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
309
|
-
const ref = toStringOrEmpty(body.ref);
|
|
310
|
-
const out = toStringOrEmpty(body.path);
|
|
311
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
312
|
-
if (!ref) return jsonError(res, 400, "ref is required");
|
|
313
|
-
if (!out) return jsonError(res, 400, "path is required");
|
|
314
|
-
await withRouteTabContext({
|
|
315
|
-
req,
|
|
316
|
-
res,
|
|
317
|
-
ctx,
|
|
318
|
-
targetId,
|
|
319
|
-
run: async ({ profileCtx, cdpUrl, tab }) => {
|
|
320
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) return jsonError(res, 501, EXISTING_SESSION_LIMITS.download.downloadUnsupported);
|
|
321
|
-
const pw = await requirePwAi(res, "download");
|
|
322
|
-
if (!pw) return;
|
|
323
|
-
await ensureOutputRootDir(DEFAULT_DOWNLOAD_DIR);
|
|
324
|
-
const downloadPath = await resolveWritableOutputPathOrRespond({
|
|
325
|
-
res,
|
|
326
|
-
rootDir: DEFAULT_DOWNLOAD_DIR,
|
|
327
|
-
requestedPath: out,
|
|
328
|
-
scopeLabel: "downloads directory"
|
|
329
|
-
});
|
|
330
|
-
if (!downloadPath) return;
|
|
331
|
-
const requestBase = buildDownloadRequestBase(cdpUrl, tab.targetId, timeoutMs);
|
|
332
|
-
const result = await pw.downloadViaPlaywright({
|
|
333
|
-
...requestBase,
|
|
334
|
-
ref,
|
|
335
|
-
path: downloadPath,
|
|
336
|
-
rootDir: DEFAULT_DOWNLOAD_DIR
|
|
337
|
-
});
|
|
338
|
-
res.json({
|
|
339
|
-
ok: true,
|
|
340
|
-
targetId: tab.targetId,
|
|
341
|
-
download: result
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
}));
|
|
346
|
-
}
|
|
347
|
-
//#endregion
|
|
348
|
-
//#region extensions/browser/src/browser/routes/agent.act.errors.ts
|
|
349
|
-
const ACT_ERROR_CODES = {
|
|
350
|
-
kindRequired: "ACT_KIND_REQUIRED",
|
|
351
|
-
invalidRequest: "ACT_INVALID_REQUEST",
|
|
352
|
-
selectorUnsupported: "ACT_SELECTOR_UNSUPPORTED",
|
|
353
|
-
evaluateDisabled: "ACT_EVALUATE_DISABLED",
|
|
354
|
-
unsupportedForExistingSession: "ACT_EXISTING_SESSION_UNSUPPORTED",
|
|
355
|
-
targetIdMismatch: "ACT_TARGET_ID_MISMATCH"
|
|
356
|
-
};
|
|
357
|
-
function jsonActError(res, status, code, message) {
|
|
358
|
-
res.status(status).json({
|
|
359
|
-
error: message,
|
|
360
|
-
code
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
function browserEvaluateDisabledMessage(action) {
|
|
364
|
-
return [action === "wait" ? "wait --fn is disabled by config (browser.evaluateEnabled=false)." : "act:evaluate is disabled by config (browser.evaluateEnabled=false).", "Docs: /gateway/configuration#browser-daocore-managed-browser"].join("\n");
|
|
365
|
-
}
|
|
366
|
-
//#endregion
|
|
367
|
-
//#region extensions/browser/src/browser/routes/agent.act.hooks.ts
|
|
368
|
-
function registerBrowserAgentActHookRoutes(app, ctx) {
|
|
369
|
-
app.post("/hooks/file-chooser", asyncBrowserRoute(async (req, res) => {
|
|
370
|
-
const body = readBody(req);
|
|
371
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
372
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
373
|
-
const inputRef = toStringOrEmpty(body.inputRef) || void 0;
|
|
374
|
-
const element = toStringOrEmpty(body.element) || void 0;
|
|
375
|
-
const paths = toStringArray(body.paths) ?? [];
|
|
376
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
377
|
-
if (!paths.length) return jsonError(res, 400, "paths are required");
|
|
378
|
-
await withRouteTabContext({
|
|
379
|
-
req,
|
|
380
|
-
res,
|
|
381
|
-
ctx,
|
|
382
|
-
targetId,
|
|
383
|
-
run: async ({ profileCtx, cdpUrl, tab }) => {
|
|
384
|
-
const uploadPathsResult = await pathScope(DEFAULT_UPLOAD_DIR, { label: `uploads directory (${DEFAULT_UPLOAD_DIR})` }).existing(paths);
|
|
385
|
-
if (!uploadPathsResult.ok) {
|
|
386
|
-
res.status(400).json({ error: uploadPathsResult.error });
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
const resolvedPaths = uploadPathsResult.paths;
|
|
390
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) {
|
|
391
|
-
if (element) return jsonError(res, 501, EXISTING_SESSION_LIMITS.hooks.uploadElement);
|
|
392
|
-
if (resolvedPaths.length !== 1) return jsonError(res, 501, EXISTING_SESSION_LIMITS.hooks.uploadSingleFile);
|
|
393
|
-
const uid = inputRef || ref;
|
|
394
|
-
if (!uid) return jsonError(res, 501, EXISTING_SESSION_LIMITS.hooks.uploadRefRequired);
|
|
395
|
-
await uploadChromeMcpFile({
|
|
396
|
-
profileName: profileCtx.profile.name,
|
|
397
|
-
profile: profileCtx.profile,
|
|
398
|
-
targetId: tab.targetId,
|
|
399
|
-
uid,
|
|
400
|
-
filePath: resolvedPaths[0] ?? ""
|
|
401
|
-
});
|
|
402
|
-
return res.json({ ok: true });
|
|
403
|
-
}
|
|
404
|
-
const pw = await requirePwAi(res, "file chooser hook");
|
|
405
|
-
if (!pw) return;
|
|
406
|
-
if (inputRef || element) {
|
|
407
|
-
if (ref) return jsonError(res, 400, "ref cannot be combined with inputRef/element");
|
|
408
|
-
await pw.setInputFilesViaPlaywright({
|
|
409
|
-
cdpUrl,
|
|
410
|
-
targetId: tab.targetId,
|
|
411
|
-
inputRef,
|
|
412
|
-
element,
|
|
413
|
-
paths: resolvedPaths
|
|
414
|
-
});
|
|
415
|
-
} else {
|
|
416
|
-
await pw.armFileUploadViaPlaywright({
|
|
417
|
-
cdpUrl,
|
|
418
|
-
targetId: tab.targetId,
|
|
419
|
-
paths: resolvedPaths,
|
|
420
|
-
timeoutMs: timeoutMs ?? void 0
|
|
421
|
-
});
|
|
422
|
-
if (ref) await pw.clickViaPlaywright({
|
|
423
|
-
cdpUrl,
|
|
424
|
-
targetId: tab.targetId,
|
|
425
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy,
|
|
426
|
-
ref
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
res.json({ ok: true });
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
}));
|
|
433
|
-
app.post("/hooks/dialog", asyncBrowserRoute(async (req, res) => {
|
|
434
|
-
const body = readBody(req);
|
|
435
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
436
|
-
const accept = toBoolean(body.accept);
|
|
437
|
-
const promptText = toStringOrEmpty(body.promptText) || void 0;
|
|
438
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
439
|
-
const dialogId = toStringOrEmpty(body.dialogId) || void 0;
|
|
440
|
-
if (accept === void 0) return jsonError(res, 400, "accept is required");
|
|
441
|
-
await withRouteTabContext({
|
|
442
|
-
req,
|
|
443
|
-
res,
|
|
444
|
-
ctx,
|
|
445
|
-
targetId,
|
|
446
|
-
run: async ({ profileCtx, cdpUrl, tab }) => {
|
|
447
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) {
|
|
448
|
-
if (dialogId) return jsonError(res, 501, EXISTING_SESSION_LIMITS.hooks.dialogId);
|
|
449
|
-
if (timeoutMs) return jsonError(res, 501, EXISTING_SESSION_LIMITS.hooks.dialogTimeout);
|
|
450
|
-
await evaluateChromeMcpScript({
|
|
451
|
-
profileName: profileCtx.profile.name,
|
|
452
|
-
profile: profileCtx.profile,
|
|
453
|
-
targetId: tab.targetId,
|
|
454
|
-
fn: `() => {
|
|
455
|
-
const state = (window.__daocoreDialogHook ??= {});
|
|
456
|
-
if (!state.originals) {
|
|
457
|
-
state.originals = {
|
|
458
|
-
alert: window.alert.bind(window),
|
|
459
|
-
confirm: window.confirm.bind(window),
|
|
460
|
-
prompt: window.prompt.bind(window),
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
const originals = state.originals;
|
|
464
|
-
const restore = () => {
|
|
465
|
-
window.alert = originals.alert;
|
|
466
|
-
window.confirm = originals.confirm;
|
|
467
|
-
window.prompt = originals.prompt;
|
|
468
|
-
delete window.__daocoreDialogHook;
|
|
469
|
-
};
|
|
470
|
-
window.alert = (...args) => {
|
|
471
|
-
try {
|
|
472
|
-
return undefined;
|
|
473
|
-
} finally {
|
|
474
|
-
restore();
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
window.confirm = (...args) => {
|
|
478
|
-
try {
|
|
479
|
-
return ${accept ? "true" : "false"};
|
|
480
|
-
} finally {
|
|
481
|
-
restore();
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
window.prompt = (...args) => {
|
|
485
|
-
try {
|
|
486
|
-
return ${accept ? JSON.stringify(promptText ?? "") : "null"};
|
|
487
|
-
} finally {
|
|
488
|
-
restore();
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
return true;
|
|
492
|
-
}`
|
|
493
|
-
});
|
|
494
|
-
return res.json({ ok: true });
|
|
495
|
-
}
|
|
496
|
-
const pw = await requirePwAi(res, "dialog hook");
|
|
497
|
-
if (!pw) return;
|
|
498
|
-
await pw.armDialogViaPlaywright({
|
|
499
|
-
cdpUrl,
|
|
500
|
-
targetId: tab.targetId,
|
|
501
|
-
dialogId,
|
|
502
|
-
accept,
|
|
503
|
-
promptText,
|
|
504
|
-
timeoutMs: timeoutMs ?? void 0
|
|
505
|
-
});
|
|
506
|
-
res.json({ ok: true });
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
}));
|
|
510
|
-
}
|
|
511
|
-
//#endregion
|
|
512
|
-
//#region extensions/browser/src/browser/routes/agent.act.shared.ts
|
|
513
|
-
const ACT_KINDS = [
|
|
514
|
-
"batch",
|
|
515
|
-
"click",
|
|
516
|
-
"clickCoords",
|
|
517
|
-
"close",
|
|
518
|
-
"drag",
|
|
519
|
-
"evaluate",
|
|
520
|
-
"fill",
|
|
521
|
-
"hover",
|
|
522
|
-
"scrollIntoView",
|
|
523
|
-
"press",
|
|
524
|
-
"resize",
|
|
525
|
-
"select",
|
|
526
|
-
"type",
|
|
527
|
-
"wait"
|
|
528
|
-
];
|
|
529
|
-
function isActKind(value) {
|
|
530
|
-
if (typeof value !== "string") return false;
|
|
531
|
-
return ACT_KINDS.includes(value);
|
|
532
|
-
}
|
|
533
|
-
const ALLOWED_CLICK_MODIFIERS = new Set([
|
|
534
|
-
"Alt",
|
|
535
|
-
"Control",
|
|
536
|
-
"ControlOrMeta",
|
|
537
|
-
"Meta",
|
|
538
|
-
"Shift"
|
|
539
|
-
]);
|
|
540
|
-
function parseClickButton(raw) {
|
|
541
|
-
if (raw === "left" || raw === "right" || raw === "middle") return raw;
|
|
542
|
-
}
|
|
543
|
-
function parseClickModifiers(raw) {
|
|
544
|
-
if (raw.filter((m) => !ALLOWED_CLICK_MODIFIERS.has(m)).length) return { error: "modifiers must be Alt|Control|ControlOrMeta|Meta|Shift" };
|
|
545
|
-
return { modifiers: raw.length ? raw : void 0 };
|
|
546
|
-
}
|
|
547
|
-
//#endregion
|
|
548
|
-
//#region extensions/browser/src/browser/routes/agent.act.normalize.ts
|
|
549
|
-
function normalizeActKind(raw) {
|
|
550
|
-
const kind = toStringOrEmpty(raw);
|
|
551
|
-
if (!isActKind(kind)) throw new Error("kind is required");
|
|
552
|
-
return kind;
|
|
553
|
-
}
|
|
554
|
-
function countBatchActions(actions) {
|
|
555
|
-
let count = 0;
|
|
556
|
-
for (const action of actions) {
|
|
557
|
-
count += 1;
|
|
558
|
-
if (action.kind === "batch") count += countBatchActions(action.actions);
|
|
559
|
-
}
|
|
560
|
-
return count;
|
|
561
|
-
}
|
|
562
|
-
function validateBatchTargetIds(actions, targetId) {
|
|
563
|
-
for (const action of actions) {
|
|
564
|
-
if (action.targetId && action.targetId !== targetId) return "batched action targetId must match request targetId";
|
|
565
|
-
if (action.kind === "batch") {
|
|
566
|
-
const nestedError = validateBatchTargetIds(action.actions, targetId);
|
|
567
|
-
if (nestedError) return nestedError;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
return null;
|
|
571
|
-
}
|
|
572
|
-
function normalizeFields(rawFields) {
|
|
573
|
-
return (Array.isArray(rawFields) ? rawFields : []).map((field) => {
|
|
574
|
-
if (!field || typeof field !== "object") return null;
|
|
575
|
-
return normalizeBrowserFormField(field);
|
|
576
|
-
}).filter((field) => field !== null);
|
|
577
|
-
}
|
|
578
|
-
function normalizeBatchAction(value) {
|
|
579
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("batch actions must be objects");
|
|
580
|
-
return normalizeActRequest(value, { source: "batch" });
|
|
581
|
-
}
|
|
582
|
-
function normalizeActRequest(body, options) {
|
|
583
|
-
const source = options?.source ?? "request";
|
|
584
|
-
const kind = normalizeActKind(body.kind);
|
|
585
|
-
switch (kind) {
|
|
586
|
-
case "click": {
|
|
587
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
588
|
-
const selector = toStringOrEmpty(body.selector) || void 0;
|
|
589
|
-
if (!ref && !selector) throw new Error("click requires ref or selector");
|
|
590
|
-
const buttonRaw = toStringOrEmpty(body.button);
|
|
591
|
-
const button = buttonRaw ? parseClickButton(buttonRaw) : void 0;
|
|
592
|
-
if (buttonRaw && !button) throw new Error("click button must be left|right|middle");
|
|
593
|
-
const parsedModifiers = parseClickModifiers(toStringArray(body.modifiers) ?? []);
|
|
594
|
-
if (parsedModifiers.error) throw new Error(parsedModifiers.error);
|
|
595
|
-
const doubleClick = toBoolean(body.doubleClick);
|
|
596
|
-
const delayMs = normalizeActBoundedNonNegativeMs(toNumber(body.delayMs), "click delayMs", ACT_MAX_CLICK_DELAY_MS);
|
|
597
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
598
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
599
|
-
return {
|
|
600
|
-
kind,
|
|
601
|
-
...ref ? { ref } : {},
|
|
602
|
-
...selector ? { selector } : {},
|
|
603
|
-
...targetId ? { targetId } : {},
|
|
604
|
-
...doubleClick !== void 0 ? { doubleClick } : {},
|
|
605
|
-
...button ? { button } : {},
|
|
606
|
-
...parsedModifiers.modifiers ? { modifiers: parsedModifiers.modifiers } : {},
|
|
607
|
-
...delayMs !== void 0 ? { delayMs } : {},
|
|
608
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
case "clickCoords": {
|
|
612
|
-
const x = toNumber(body.x);
|
|
613
|
-
const y = toNumber(body.y);
|
|
614
|
-
if (x === void 0 || y === void 0 || x < 0 || y < 0) throw new Error("clickCoords requires non-negative x and y");
|
|
615
|
-
const buttonRaw = toStringOrEmpty(body.button);
|
|
616
|
-
const button = buttonRaw ? parseClickButton(buttonRaw) : void 0;
|
|
617
|
-
if (buttonRaw && !button) throw new Error("clickCoords button must be left|right|middle");
|
|
618
|
-
const doubleClick = toBoolean(body.doubleClick);
|
|
619
|
-
const delayMs = normalizeActBoundedNonNegativeMs(toNumber(body.delayMs), "clickCoords delayMs", ACT_MAX_CLICK_DELAY_MS);
|
|
620
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
621
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
622
|
-
return {
|
|
623
|
-
kind,
|
|
624
|
-
x,
|
|
625
|
-
y,
|
|
626
|
-
...targetId ? { targetId } : {},
|
|
627
|
-
...doubleClick !== void 0 ? { doubleClick } : {},
|
|
628
|
-
...button ? { button } : {},
|
|
629
|
-
...delayMs !== void 0 ? { delayMs } : {},
|
|
630
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
case "type": {
|
|
634
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
635
|
-
const selector = toStringOrEmpty(body.selector) || void 0;
|
|
636
|
-
const text = body.text;
|
|
637
|
-
if (!ref && !selector) throw new Error("type requires ref or selector");
|
|
638
|
-
if (typeof text !== "string") throw new Error("type requires text");
|
|
639
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
640
|
-
const submit = toBoolean(body.submit);
|
|
641
|
-
const slowly = toBoolean(body.slowly);
|
|
642
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
643
|
-
return {
|
|
644
|
-
kind,
|
|
645
|
-
...ref ? { ref } : {},
|
|
646
|
-
...selector ? { selector } : {},
|
|
647
|
-
text,
|
|
648
|
-
...targetId ? { targetId } : {},
|
|
649
|
-
...submit !== void 0 ? { submit } : {},
|
|
650
|
-
...slowly !== void 0 ? { slowly } : {},
|
|
651
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
case "press": {
|
|
655
|
-
const key = toStringOrEmpty(body.key);
|
|
656
|
-
if (!key) throw new Error("press requires key");
|
|
657
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
658
|
-
const delayMs = toNumber(body.delayMs);
|
|
659
|
-
return {
|
|
660
|
-
kind,
|
|
661
|
-
key,
|
|
662
|
-
...targetId ? { targetId } : {},
|
|
663
|
-
...delayMs !== void 0 ? { delayMs } : {}
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
case "hover":
|
|
667
|
-
case "scrollIntoView": {
|
|
668
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
669
|
-
const selector = toStringOrEmpty(body.selector) || void 0;
|
|
670
|
-
if (!ref && !selector) throw new Error(`${kind} requires ref or selector`);
|
|
671
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
672
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
673
|
-
return {
|
|
674
|
-
kind,
|
|
675
|
-
...ref ? { ref } : {},
|
|
676
|
-
...selector ? { selector } : {},
|
|
677
|
-
...targetId ? { targetId } : {},
|
|
678
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
case "drag": {
|
|
682
|
-
const startRef = toStringOrEmpty(body.startRef) || void 0;
|
|
683
|
-
const startSelector = toStringOrEmpty(body.startSelector) || void 0;
|
|
684
|
-
const endRef = toStringOrEmpty(body.endRef) || void 0;
|
|
685
|
-
const endSelector = toStringOrEmpty(body.endSelector) || void 0;
|
|
686
|
-
if (!startRef && !startSelector) throw new Error("drag requires startRef or startSelector");
|
|
687
|
-
if (!endRef && !endSelector) throw new Error("drag requires endRef or endSelector");
|
|
688
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
689
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
690
|
-
return {
|
|
691
|
-
kind,
|
|
692
|
-
...startRef ? { startRef } : {},
|
|
693
|
-
...startSelector ? { startSelector } : {},
|
|
694
|
-
...endRef ? { endRef } : {},
|
|
695
|
-
...endSelector ? { endSelector } : {},
|
|
696
|
-
...targetId ? { targetId } : {},
|
|
697
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
case "select": {
|
|
701
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
702
|
-
const selector = toStringOrEmpty(body.selector) || void 0;
|
|
703
|
-
const values = toStringArray(body.values);
|
|
704
|
-
if (!ref && !selector || !values?.length) throw new Error("select requires ref/selector and values");
|
|
705
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
706
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
707
|
-
return {
|
|
708
|
-
kind,
|
|
709
|
-
...ref ? { ref } : {},
|
|
710
|
-
...selector ? { selector } : {},
|
|
711
|
-
values,
|
|
712
|
-
...targetId ? { targetId } : {},
|
|
713
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
case "fill": {
|
|
717
|
-
const fields = normalizeFields(body.fields);
|
|
718
|
-
if (!fields.length) throw new Error("fill requires fields");
|
|
719
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
720
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
721
|
-
return {
|
|
722
|
-
kind,
|
|
723
|
-
fields,
|
|
724
|
-
...targetId ? { targetId } : {},
|
|
725
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
case "resize": {
|
|
729
|
-
const width = toNumber(body.width);
|
|
730
|
-
const height = toNumber(body.height);
|
|
731
|
-
if (width === void 0 || height === void 0 || width <= 0 || height <= 0) throw new Error("resize requires positive width and height");
|
|
732
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
733
|
-
return {
|
|
734
|
-
kind,
|
|
735
|
-
width,
|
|
736
|
-
height,
|
|
737
|
-
...targetId ? { targetId } : {}
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
case "wait": {
|
|
741
|
-
const loadStateRaw = toStringOrEmpty(body.loadState);
|
|
742
|
-
const loadState = loadStateRaw === "load" || loadStateRaw === "domcontentloaded" || loadStateRaw === "networkidle" ? loadStateRaw : void 0;
|
|
743
|
-
const timeMs = normalizeActBoundedNonNegativeMs(toNumber(body.timeMs), "wait timeMs", ACT_MAX_WAIT_TIME_MS);
|
|
744
|
-
const text = toStringOrEmpty(body.text) || void 0;
|
|
745
|
-
const textGone = toStringOrEmpty(body.textGone) || void 0;
|
|
746
|
-
const selector = toStringOrEmpty(body.selector) || void 0;
|
|
747
|
-
const url = toStringOrEmpty(body.url) || void 0;
|
|
748
|
-
const fn = toStringOrEmpty(body.fn) || void 0;
|
|
749
|
-
if (timeMs === void 0 && !text && !textGone && !selector && !url && !loadState && !fn) throw new Error("wait requires at least one of: timeMs, text, textGone, selector, url, loadState, fn");
|
|
750
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
751
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
752
|
-
return {
|
|
753
|
-
kind,
|
|
754
|
-
...timeMs !== void 0 ? { timeMs } : {},
|
|
755
|
-
...text ? { text } : {},
|
|
756
|
-
...textGone ? { textGone } : {},
|
|
757
|
-
...selector ? { selector } : {},
|
|
758
|
-
...url ? { url } : {},
|
|
759
|
-
...loadState ? { loadState } : {},
|
|
760
|
-
...fn ? { fn } : {},
|
|
761
|
-
...targetId ? { targetId } : {},
|
|
762
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
case "evaluate": {
|
|
766
|
-
const fn = toStringOrEmpty(body.fn);
|
|
767
|
-
if (!fn) throw new Error("evaluate requires fn");
|
|
768
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
769
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
770
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
771
|
-
return {
|
|
772
|
-
kind,
|
|
773
|
-
fn,
|
|
774
|
-
...ref ? { ref } : {},
|
|
775
|
-
...targetId ? { targetId } : {},
|
|
776
|
-
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
case "close": {
|
|
780
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
781
|
-
return {
|
|
782
|
-
kind,
|
|
783
|
-
...targetId ? { targetId } : {}
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
case "batch": {
|
|
787
|
-
const actions = Array.isArray(body.actions) ? body.actions.map(normalizeBatchAction) : [];
|
|
788
|
-
if (!actions.length) throw new Error(source === "batch" ? "batch requires actions" : "actions are required");
|
|
789
|
-
if (countBatchActions(actions) > 100) throw new Error(`batch exceeds maximum of 100 actions`);
|
|
790
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
791
|
-
const stopOnError = toBoolean(body.stopOnError);
|
|
792
|
-
return {
|
|
793
|
-
kind,
|
|
794
|
-
actions,
|
|
795
|
-
...targetId ? { targetId } : {},
|
|
796
|
-
...stopOnError !== void 0 ? { stopOnError } : {}
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
throw new Error("Unsupported browser act kind");
|
|
801
|
-
}
|
|
802
|
-
//#endregion
|
|
803
|
-
//#region extensions/browser/src/browser/routes/agent.snapshot-target.ts
|
|
804
|
-
/** Resolve the correct targetId after a navigation that may trigger a renderer swap. */
|
|
805
|
-
async function resolveTargetIdAfterNavigate(opts) {
|
|
806
|
-
let currentTargetId = opts.oldTargetId;
|
|
807
|
-
try {
|
|
808
|
-
const pickReplacement = (tabs, options) => {
|
|
809
|
-
if (tabs.some((tab) => tab.targetId === opts.oldTargetId)) return {
|
|
810
|
-
targetId: opts.oldTargetId,
|
|
811
|
-
shouldRetry: false
|
|
812
|
-
};
|
|
813
|
-
const byUrl = tabs.filter((tab) => tab.url === opts.navigatedUrl);
|
|
814
|
-
if (byUrl.length === 1) return {
|
|
815
|
-
targetId: byUrl[0]?.targetId ?? opts.oldTargetId,
|
|
816
|
-
shouldRetry: false
|
|
817
|
-
};
|
|
818
|
-
const uniqueReplacement = byUrl.filter((tab) => tab.targetId !== opts.oldTargetId);
|
|
819
|
-
if (uniqueReplacement.length === 1) return {
|
|
820
|
-
targetId: uniqueReplacement[0]?.targetId ?? opts.oldTargetId,
|
|
821
|
-
shouldRetry: false
|
|
822
|
-
};
|
|
823
|
-
if (options?.allowSingleTabFallback && tabs.length === 1) return {
|
|
824
|
-
targetId: tabs[0]?.targetId ?? opts.oldTargetId,
|
|
825
|
-
shouldRetry: false
|
|
826
|
-
};
|
|
827
|
-
return {
|
|
828
|
-
targetId: opts.oldTargetId,
|
|
829
|
-
shouldRetry: true
|
|
830
|
-
};
|
|
831
|
-
};
|
|
832
|
-
const first = pickReplacement(await opts.listTabs());
|
|
833
|
-
currentTargetId = first.targetId;
|
|
834
|
-
if (first.shouldRetry) {
|
|
835
|
-
await new Promise((r) => setTimeout(r, opts.retryDelayMs ?? 800));
|
|
836
|
-
currentTargetId = pickReplacement(await opts.listTabs(), { allowSingleTabFallback: true }).targetId;
|
|
837
|
-
}
|
|
838
|
-
} catch {}
|
|
839
|
-
return currentTargetId;
|
|
840
|
-
}
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region extensions/browser/src/browser/routes/agent.act.ts
|
|
843
|
-
function sleep(ms) {
|
|
844
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
845
|
-
}
|
|
846
|
-
const EXISTING_SESSION_INTERACTION_NAVIGATION_RECHECK_DELAYS_MS = [
|
|
847
|
-
0,
|
|
848
|
-
250,
|
|
849
|
-
500
|
|
850
|
-
];
|
|
851
|
-
async function readExistingSessionLocationHref(params) {
|
|
852
|
-
const currentUrl = await evaluateChromeMcpScript({
|
|
853
|
-
profileName: params.profileName,
|
|
854
|
-
profile: params.profile,
|
|
855
|
-
userDataDir: params.userDataDir,
|
|
856
|
-
targetId: params.targetId,
|
|
857
|
-
fn: "() => window.location.href"
|
|
858
|
-
});
|
|
859
|
-
if (typeof currentUrl !== "string") throw new Error("Location probe returned a non-string result");
|
|
860
|
-
const normalizedUrl = currentUrl.trim();
|
|
861
|
-
if (!normalizedUrl) throw new Error("Location probe returned an empty URL");
|
|
862
|
-
return normalizedUrl;
|
|
863
|
-
}
|
|
864
|
-
async function assertExistingSessionPostInteractionNavigationAllowed(params) {
|
|
865
|
-
const ssrfPolicyOpts = withBrowserNavigationPolicy(params.ssrfPolicy);
|
|
866
|
-
if (!ssrfPolicyOpts.ssrfPolicy) return;
|
|
867
|
-
const listTabs = params.listTabs;
|
|
868
|
-
const initialTabTargetIds = params.initialTabTargetIds;
|
|
869
|
-
const assertNewTabsAllowed = async () => {
|
|
870
|
-
const tabs = await listTabs();
|
|
871
|
-
for (const tab of tabs) {
|
|
872
|
-
if (initialTabTargetIds.has(tab.targetId)) continue;
|
|
873
|
-
await assertBrowserNavigationResultAllowed({
|
|
874
|
-
url: tab.url,
|
|
875
|
-
...ssrfPolicyOpts
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
let lastObservedUrl;
|
|
880
|
-
let sawStableAllowedUrl = false;
|
|
881
|
-
for (const delayMs of EXISTING_SESSION_INTERACTION_NAVIGATION_RECHECK_DELAYS_MS) {
|
|
882
|
-
if (delayMs > 0) await sleep(delayMs);
|
|
883
|
-
let currentUrl;
|
|
884
|
-
try {
|
|
885
|
-
currentUrl = await readExistingSessionLocationHref(params);
|
|
886
|
-
} catch {
|
|
887
|
-
sawStableAllowedUrl = false;
|
|
888
|
-
continue;
|
|
889
|
-
}
|
|
890
|
-
await assertBrowserNavigationResultAllowed({
|
|
891
|
-
url: currentUrl,
|
|
892
|
-
...ssrfPolicyOpts
|
|
893
|
-
});
|
|
894
|
-
if (currentUrl === lastObservedUrl) sawStableAllowedUrl = true;
|
|
895
|
-
else sawStableAllowedUrl = false;
|
|
896
|
-
lastObservedUrl = currentUrl;
|
|
897
|
-
}
|
|
898
|
-
if (sawStableAllowedUrl) {
|
|
899
|
-
await assertNewTabsAllowed();
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
if (lastObservedUrl) {
|
|
903
|
-
const lastDelay = EXISTING_SESSION_INTERACTION_NAVIGATION_RECHECK_DELAYS_MS[EXISTING_SESSION_INTERACTION_NAVIGATION_RECHECK_DELAYS_MS.length - 1];
|
|
904
|
-
await sleep(lastDelay);
|
|
905
|
-
try {
|
|
906
|
-
const followUpUrl = await readExistingSessionLocationHref(params);
|
|
907
|
-
await assertBrowserNavigationResultAllowed({
|
|
908
|
-
url: followUpUrl,
|
|
909
|
-
...ssrfPolicyOpts
|
|
910
|
-
});
|
|
911
|
-
if (followUpUrl === lastObservedUrl) {
|
|
912
|
-
await assertNewTabsAllowed();
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
915
|
-
} catch {}
|
|
916
|
-
}
|
|
917
|
-
throw new Error("Unable to verify stable post-interaction navigation");
|
|
918
|
-
}
|
|
919
|
-
async function runExistingSessionActionWithNavigationGuard(params) {
|
|
920
|
-
let actionError;
|
|
921
|
-
let result;
|
|
922
|
-
try {
|
|
923
|
-
result = await params.execute();
|
|
924
|
-
} catch (error) {
|
|
925
|
-
actionError = error;
|
|
926
|
-
}
|
|
927
|
-
if (params.guard) await assertExistingSessionPostInteractionNavigationAllowed(params.guard);
|
|
928
|
-
if (actionError) throw actionError;
|
|
929
|
-
return result;
|
|
930
|
-
}
|
|
931
|
-
function buildExistingSessionWaitPredicate(params) {
|
|
932
|
-
const checks = [];
|
|
933
|
-
if (params.text) checks.push(`Boolean(document.body?.innerText?.includes(${JSON.stringify(params.text)}))`);
|
|
934
|
-
if (params.textGone) checks.push(`!document.body?.innerText?.includes(${JSON.stringify(params.textGone)})`);
|
|
935
|
-
if (params.selector) checks.push(`Boolean(document.querySelector(${JSON.stringify(params.selector)}))`);
|
|
936
|
-
if (params.loadState === "domcontentloaded") checks.push(`document.readyState === "interactive" || document.readyState === "complete"`);
|
|
937
|
-
else if (params.loadState === "load") checks.push(`document.readyState === "complete"`);
|
|
938
|
-
if (params.fn) checks.push(`Boolean(await (${params.fn})())`);
|
|
939
|
-
if (checks.length === 0) return null;
|
|
940
|
-
return checks.length === 1 ? checks[0] : checks.map((check) => `(${check})`).join(" && ");
|
|
941
|
-
}
|
|
942
|
-
async function waitForExistingSessionCondition(params) {
|
|
943
|
-
if (params.timeMs && params.timeMs > 0) await sleep(params.timeMs);
|
|
944
|
-
const predicate = buildExistingSessionWaitPredicate(params);
|
|
945
|
-
if (!predicate && !params.url) return;
|
|
946
|
-
const timeoutMs = Math.max(250, params.timeoutMs ?? 1e4);
|
|
947
|
-
const deadline = Date.now() + timeoutMs;
|
|
948
|
-
while (Date.now() < deadline) {
|
|
949
|
-
let ready = true;
|
|
950
|
-
if (predicate) ready = Boolean(await evaluateChromeMcpScript({
|
|
951
|
-
profileName: params.profileName,
|
|
952
|
-
profile: params.profile,
|
|
953
|
-
userDataDir: params.userDataDir,
|
|
954
|
-
targetId: params.targetId,
|
|
955
|
-
fn: `async () => ${predicate}`
|
|
956
|
-
}));
|
|
957
|
-
if (ready && params.url) {
|
|
958
|
-
const currentUrl = await evaluateChromeMcpScript({
|
|
959
|
-
profileName: params.profileName,
|
|
960
|
-
profile: params.profile,
|
|
961
|
-
userDataDir: params.userDataDir,
|
|
962
|
-
targetId: params.targetId,
|
|
963
|
-
fn: "() => window.location.href"
|
|
964
|
-
});
|
|
965
|
-
ready = typeof currentUrl === "string" && matchBrowserUrlPattern(params.url, currentUrl);
|
|
966
|
-
}
|
|
967
|
-
if (ready) return;
|
|
968
|
-
await sleep(250);
|
|
969
|
-
}
|
|
970
|
-
throw new Error("Timed out waiting for condition");
|
|
971
|
-
}
|
|
972
|
-
const SELECTOR_ALLOWED_KINDS = new Set([
|
|
973
|
-
"batch",
|
|
974
|
-
"click",
|
|
975
|
-
"drag",
|
|
976
|
-
"hover",
|
|
977
|
-
"scrollIntoView",
|
|
978
|
-
"select",
|
|
979
|
-
"type",
|
|
980
|
-
"wait"
|
|
981
|
-
]);
|
|
982
|
-
function shouldEnforceCurrentUrlForAct(action) {
|
|
983
|
-
return action.kind !== "resize" && action.kind !== "close";
|
|
984
|
-
}
|
|
985
|
-
function getExistingSessionUnsupportedMessage(action) {
|
|
986
|
-
switch (action.kind) {
|
|
987
|
-
case "click":
|
|
988
|
-
if (action.selector) return EXISTING_SESSION_LIMITS.act.clickSelector;
|
|
989
|
-
if (action.button && action.button !== "left" || Array.isArray(action.modifiers) && action.modifiers.length > 0) return EXISTING_SESSION_LIMITS.act.clickButtonOrModifiers;
|
|
990
|
-
return null;
|
|
991
|
-
case "clickCoords": return null;
|
|
992
|
-
case "type":
|
|
993
|
-
if (action.selector) return EXISTING_SESSION_LIMITS.act.typeSelector;
|
|
994
|
-
if (action.slowly) return EXISTING_SESSION_LIMITS.act.typeSlowly;
|
|
995
|
-
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.typeTimeout : null;
|
|
996
|
-
case "press": return action.delayMs ? EXISTING_SESSION_LIMITS.act.pressDelay : null;
|
|
997
|
-
case "hover":
|
|
998
|
-
if (action.selector) return EXISTING_SESSION_LIMITS.act.hoverSelector;
|
|
999
|
-
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.hoverTimeout : null;
|
|
1000
|
-
case "scrollIntoView":
|
|
1001
|
-
if (action.selector) return EXISTING_SESSION_LIMITS.act.scrollSelector;
|
|
1002
|
-
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.scrollTimeout : null;
|
|
1003
|
-
case "drag":
|
|
1004
|
-
if (action.startSelector || action.endSelector) return EXISTING_SESSION_LIMITS.act.dragSelector;
|
|
1005
|
-
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.dragTimeout : null;
|
|
1006
|
-
case "select":
|
|
1007
|
-
if (action.selector) return EXISTING_SESSION_LIMITS.act.selectSelector;
|
|
1008
|
-
if (action.values.length !== 1) return EXISTING_SESSION_LIMITS.act.selectSingleValue;
|
|
1009
|
-
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.selectTimeout : null;
|
|
1010
|
-
case "fill": return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.fillTimeout : null;
|
|
1011
|
-
case "wait": return action.loadState === "networkidle" ? EXISTING_SESSION_LIMITS.act.waitNetworkIdle : null;
|
|
1012
|
-
case "evaluate": return action.timeoutMs !== void 0 ? EXISTING_SESSION_LIMITS.act.evaluateTimeout : null;
|
|
1013
|
-
case "batch": return EXISTING_SESSION_LIMITS.act.batch;
|
|
1014
|
-
case "resize":
|
|
1015
|
-
case "close": return null;
|
|
1016
|
-
}
|
|
1017
|
-
throw new Error("Unsupported browser act kind");
|
|
1018
|
-
}
|
|
1019
|
-
function registerBrowserAgentActRoutes(app, ctx) {
|
|
1020
|
-
app.post("/act", asyncBrowserRoute(async (req, res) => {
|
|
1021
|
-
const body = readBody(req);
|
|
1022
|
-
const kindRaw = toStringOrEmpty(body.kind);
|
|
1023
|
-
if (!isActKind(kindRaw)) return jsonActError(res, 400, ACT_ERROR_CODES.kindRequired, "kind is required");
|
|
1024
|
-
const kind = kindRaw;
|
|
1025
|
-
let action;
|
|
1026
|
-
try {
|
|
1027
|
-
action = normalizeActRequest(body);
|
|
1028
|
-
} catch (err) {
|
|
1029
|
-
return jsonActError(res, 400, ACT_ERROR_CODES.invalidRequest, formatErrorMessage(err));
|
|
1030
|
-
}
|
|
1031
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
1032
|
-
if (Object.hasOwn(body, "selector") && !SELECTOR_ALLOWED_KINDS.has(kind)) return jsonActError(res, 400, ACT_ERROR_CODES.selectorUnsupported, SELECTOR_UNSUPPORTED_MESSAGE);
|
|
1033
|
-
const earlyFn = action.kind === "wait" || action.kind === "evaluate" ? action.fn : "";
|
|
1034
|
-
if ((action.kind === "evaluate" || action.kind === "wait" && earlyFn) && !ctx.state().resolved.evaluateEnabled) return jsonActError(res, 403, ACT_ERROR_CODES.evaluateDisabled, browserEvaluateDisabledMessage(action.kind === "evaluate" ? "evaluate" : "wait"));
|
|
1035
|
-
await withRouteTabContext({
|
|
1036
|
-
req,
|
|
1037
|
-
res,
|
|
1038
|
-
ctx,
|
|
1039
|
-
targetId,
|
|
1040
|
-
enforceCurrentUrlAllowed: shouldEnforceCurrentUrlForAct(action),
|
|
1041
|
-
run: async ({ profileCtx, cdpUrl, tab, resolveTabUrl }) => {
|
|
1042
|
-
const evaluateEnabled = ctx.state().resolved.evaluateEnabled;
|
|
1043
|
-
const ssrfPolicy = ctx.state().resolved.ssrfPolicy;
|
|
1044
|
-
const isExistingSession = getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp;
|
|
1045
|
-
const hasNavigationResultPolicy = Boolean(withBrowserNavigationPolicy(ssrfPolicy).ssrfPolicy);
|
|
1046
|
-
const jsonOk = async (extra, options) => {
|
|
1047
|
-
const responseTargetId = options?.resolveCurrentTarget && (!isExistingSession || hasNavigationResultPolicy) ? await resolveTargetIdAfterNavigate({
|
|
1048
|
-
oldTargetId: tab.targetId,
|
|
1049
|
-
navigatedUrl: tab.url,
|
|
1050
|
-
listTabs: () => profileCtx.listTabs()
|
|
1051
|
-
}) : tab.targetId;
|
|
1052
|
-
const url = responseTargetId === tab.targetId ? await resolveTabUrl(tab.url) : await resolveSafeRouteTabUrl({
|
|
1053
|
-
ctx,
|
|
1054
|
-
profileCtx,
|
|
1055
|
-
targetId: responseTargetId,
|
|
1056
|
-
fallbackUrl: tab.url
|
|
1057
|
-
});
|
|
1058
|
-
return res.json({
|
|
1059
|
-
ok: true,
|
|
1060
|
-
targetId: responseTargetId,
|
|
1061
|
-
...url ? { url } : {},
|
|
1062
|
-
...extra
|
|
1063
|
-
});
|
|
1064
|
-
};
|
|
1065
|
-
if (action.targetId && action.targetId !== tab.targetId) return jsonActError(res, 403, ACT_ERROR_CODES.targetIdMismatch, "action targetId must match request targetId");
|
|
1066
|
-
const profileName = profileCtx.profile.name;
|
|
1067
|
-
if (isExistingSession) {
|
|
1068
|
-
const initialTabTargetIds = hasNavigationResultPolicy ? new Set((await profileCtx.listTabs()).map((currentTab) => currentTab.targetId)) : /* @__PURE__ */ new Set();
|
|
1069
|
-
const existingSessionNavigationGuard = {
|
|
1070
|
-
profileName,
|
|
1071
|
-
profile: profileCtx.profile,
|
|
1072
|
-
targetId: tab.targetId,
|
|
1073
|
-
ssrfPolicy,
|
|
1074
|
-
listTabs: () => profileCtx.listTabs(),
|
|
1075
|
-
initialTabTargetIds
|
|
1076
|
-
};
|
|
1077
|
-
const unsupportedMessage = getExistingSessionUnsupportedMessage(action);
|
|
1078
|
-
if (unsupportedMessage) return jsonActError(res, 501, ACT_ERROR_CODES.unsupportedForExistingSession, unsupportedMessage);
|
|
1079
|
-
switch (action.kind) {
|
|
1080
|
-
case "click":
|
|
1081
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1082
|
-
execute: () => clickChromeMcpElement({
|
|
1083
|
-
profileName,
|
|
1084
|
-
profile: profileCtx.profile,
|
|
1085
|
-
targetId: tab.targetId,
|
|
1086
|
-
uid: action.ref,
|
|
1087
|
-
doubleClick: action.doubleClick ?? false,
|
|
1088
|
-
timeoutMs: action.timeoutMs,
|
|
1089
|
-
signal: req.signal
|
|
1090
|
-
}),
|
|
1091
|
-
guard: existingSessionNavigationGuard
|
|
1092
|
-
});
|
|
1093
|
-
return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1094
|
-
case "clickCoords":
|
|
1095
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1096
|
-
execute: () => clickChromeMcpCoords({
|
|
1097
|
-
profileName,
|
|
1098
|
-
profile: profileCtx.profile,
|
|
1099
|
-
targetId: tab.targetId,
|
|
1100
|
-
x: action.x,
|
|
1101
|
-
y: action.y,
|
|
1102
|
-
doubleClick: action.doubleClick ?? false,
|
|
1103
|
-
button: action.button,
|
|
1104
|
-
delayMs: action.delayMs
|
|
1105
|
-
}),
|
|
1106
|
-
guard: existingSessionNavigationGuard
|
|
1107
|
-
});
|
|
1108
|
-
return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1109
|
-
case "type":
|
|
1110
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1111
|
-
execute: async () => {
|
|
1112
|
-
await fillChromeMcpElement({
|
|
1113
|
-
profileName,
|
|
1114
|
-
profile: profileCtx.profile,
|
|
1115
|
-
targetId: tab.targetId,
|
|
1116
|
-
uid: action.ref,
|
|
1117
|
-
value: action.text
|
|
1118
|
-
});
|
|
1119
|
-
if (action.submit) await pressChromeMcpKey({
|
|
1120
|
-
profileName,
|
|
1121
|
-
profile: profileCtx.profile,
|
|
1122
|
-
targetId: tab.targetId,
|
|
1123
|
-
key: "Enter"
|
|
1124
|
-
});
|
|
1125
|
-
},
|
|
1126
|
-
guard: existingSessionNavigationGuard
|
|
1127
|
-
});
|
|
1128
|
-
return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1129
|
-
case "press":
|
|
1130
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1131
|
-
execute: () => pressChromeMcpKey({
|
|
1132
|
-
profileName,
|
|
1133
|
-
profile: profileCtx.profile,
|
|
1134
|
-
targetId: tab.targetId,
|
|
1135
|
-
key: action.key
|
|
1136
|
-
}),
|
|
1137
|
-
guard: existingSessionNavigationGuard
|
|
1138
|
-
});
|
|
1139
|
-
return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1140
|
-
case "hover":
|
|
1141
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1142
|
-
execute: () => hoverChromeMcpElement({
|
|
1143
|
-
profileName,
|
|
1144
|
-
profile: profileCtx.profile,
|
|
1145
|
-
targetId: tab.targetId,
|
|
1146
|
-
uid: action.ref
|
|
1147
|
-
}),
|
|
1148
|
-
guard: existingSessionNavigationGuard
|
|
1149
|
-
});
|
|
1150
|
-
return await jsonOk();
|
|
1151
|
-
case "scrollIntoView":
|
|
1152
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1153
|
-
execute: () => evaluateChromeMcpScript({
|
|
1154
|
-
profileName,
|
|
1155
|
-
profile: profileCtx.profile,
|
|
1156
|
-
targetId: tab.targetId,
|
|
1157
|
-
fn: `(el) => { el.scrollIntoView({ block: "center", inline: "center" }); return true; }`,
|
|
1158
|
-
args: [action.ref]
|
|
1159
|
-
}),
|
|
1160
|
-
guard: existingSessionNavigationGuard
|
|
1161
|
-
});
|
|
1162
|
-
return await jsonOk();
|
|
1163
|
-
case "drag":
|
|
1164
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1165
|
-
execute: () => dragChromeMcpElement({
|
|
1166
|
-
profileName,
|
|
1167
|
-
profile: profileCtx.profile,
|
|
1168
|
-
targetId: tab.targetId,
|
|
1169
|
-
fromUid: action.startRef,
|
|
1170
|
-
toUid: action.endRef
|
|
1171
|
-
}),
|
|
1172
|
-
guard: existingSessionNavigationGuard
|
|
1173
|
-
});
|
|
1174
|
-
return await jsonOk();
|
|
1175
|
-
case "select":
|
|
1176
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1177
|
-
execute: () => fillChromeMcpElement({
|
|
1178
|
-
profileName,
|
|
1179
|
-
profile: profileCtx.profile,
|
|
1180
|
-
targetId: tab.targetId,
|
|
1181
|
-
uid: action.ref,
|
|
1182
|
-
value: action.values[0] ?? ""
|
|
1183
|
-
}),
|
|
1184
|
-
guard: existingSessionNavigationGuard
|
|
1185
|
-
});
|
|
1186
|
-
return await jsonOk();
|
|
1187
|
-
case "fill":
|
|
1188
|
-
await runExistingSessionActionWithNavigationGuard({
|
|
1189
|
-
execute: () => fillChromeMcpForm({
|
|
1190
|
-
profileName,
|
|
1191
|
-
profile: profileCtx.profile,
|
|
1192
|
-
targetId: tab.targetId,
|
|
1193
|
-
elements: action.fields.map((field) => ({
|
|
1194
|
-
uid: field.ref,
|
|
1195
|
-
value: String(field.value ?? "")
|
|
1196
|
-
}))
|
|
1197
|
-
}),
|
|
1198
|
-
guard: existingSessionNavigationGuard
|
|
1199
|
-
});
|
|
1200
|
-
return await jsonOk();
|
|
1201
|
-
case "resize":
|
|
1202
|
-
await resizeChromeMcpPage({
|
|
1203
|
-
profileName,
|
|
1204
|
-
profile: profileCtx.profile,
|
|
1205
|
-
targetId: tab.targetId,
|
|
1206
|
-
width: action.width,
|
|
1207
|
-
height: action.height
|
|
1208
|
-
});
|
|
1209
|
-
return await jsonOk();
|
|
1210
|
-
case "wait":
|
|
1211
|
-
await waitForExistingSessionCondition({
|
|
1212
|
-
profileName,
|
|
1213
|
-
profile: profileCtx.profile,
|
|
1214
|
-
targetId: tab.targetId,
|
|
1215
|
-
timeMs: action.timeMs,
|
|
1216
|
-
text: action.text,
|
|
1217
|
-
textGone: action.textGone,
|
|
1218
|
-
selector: action.selector,
|
|
1219
|
-
url: action.url,
|
|
1220
|
-
loadState: action.loadState,
|
|
1221
|
-
fn: action.fn,
|
|
1222
|
-
timeoutMs: action.timeoutMs
|
|
1223
|
-
});
|
|
1224
|
-
return await jsonOk();
|
|
1225
|
-
case "evaluate": return await jsonOk({ result: await runExistingSessionActionWithNavigationGuard({
|
|
1226
|
-
execute: () => evaluateChromeMcpScript({
|
|
1227
|
-
profileName,
|
|
1228
|
-
profile: profileCtx.profile,
|
|
1229
|
-
targetId: tab.targetId,
|
|
1230
|
-
fn: action.fn,
|
|
1231
|
-
args: action.ref ? [action.ref] : void 0
|
|
1232
|
-
}),
|
|
1233
|
-
guard: existingSessionNavigationGuard
|
|
1234
|
-
}) });
|
|
1235
|
-
case "close":
|
|
1236
|
-
await closeChromeMcpTab(profileName, tab.targetId, profileCtx.profile);
|
|
1237
|
-
return await jsonOk();
|
|
1238
|
-
case "batch": return jsonActError(res, 501, ACT_ERROR_CODES.unsupportedForExistingSession, EXISTING_SESSION_LIMITS.act.batch);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
const pw = await requirePwAi(res, `act:${kind}`);
|
|
1242
|
-
if (!pw) return;
|
|
1243
|
-
if (action.kind === "batch") {
|
|
1244
|
-
const targetIdError = validateBatchTargetIds(action.actions, tab.targetId);
|
|
1245
|
-
if (targetIdError) return jsonActError(res, 403, ACT_ERROR_CODES.targetIdMismatch, targetIdError);
|
|
1246
|
-
}
|
|
1247
|
-
const result = await pw.executeActViaPlaywright({
|
|
1248
|
-
cdpUrl,
|
|
1249
|
-
action,
|
|
1250
|
-
targetId: tab.targetId,
|
|
1251
|
-
evaluateEnabled,
|
|
1252
|
-
ssrfPolicy,
|
|
1253
|
-
signal: req.signal
|
|
1254
|
-
});
|
|
1255
|
-
if (result.blockedByDialog) return await jsonOk({
|
|
1256
|
-
blockedByDialog: true,
|
|
1257
|
-
browserState: result.browserState
|
|
1258
|
-
});
|
|
1259
|
-
switch (action.kind) {
|
|
1260
|
-
case "batch": return await jsonOk({ results: result.results ?? [] }, { resolveCurrentTarget: true });
|
|
1261
|
-
case "evaluate": return await jsonOk({ result: result.result }, { resolveCurrentTarget: true });
|
|
1262
|
-
case "click":
|
|
1263
|
-
case "clickCoords": return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1264
|
-
case "resize": return await jsonOk();
|
|
1265
|
-
default: return await jsonOk(void 0, { resolveCurrentTarget: true });
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
});
|
|
1269
|
-
}));
|
|
1270
|
-
registerBrowserAgentActHookRoutes(app, ctx);
|
|
1271
|
-
registerBrowserAgentActDownloadRoutes(app, ctx);
|
|
1272
|
-
app.post("/response/body", asyncBrowserRoute(async (req, res) => {
|
|
1273
|
-
const body = readBody(req);
|
|
1274
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
1275
|
-
const url = toStringOrEmpty(body.url);
|
|
1276
|
-
const timeoutMs = toNumber(body.timeoutMs);
|
|
1277
|
-
const maxChars = toNumber(body.maxChars);
|
|
1278
|
-
if (!url) return jsonError(res, 400, "url is required");
|
|
1279
|
-
await withRouteTabContext({
|
|
1280
|
-
req,
|
|
1281
|
-
res,
|
|
1282
|
-
ctx,
|
|
1283
|
-
targetId,
|
|
1284
|
-
enforceCurrentUrlAllowed: true,
|
|
1285
|
-
run: async ({ profileCtx, cdpUrl, tab, resolveTabUrl }) => {
|
|
1286
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) return jsonError(res, 501, EXISTING_SESSION_LIMITS.responseBody);
|
|
1287
|
-
const pw = await requirePwAi(res, "response body");
|
|
1288
|
-
if (!pw) return;
|
|
1289
|
-
const result = await pw.responseBodyViaPlaywright({
|
|
1290
|
-
cdpUrl,
|
|
1291
|
-
targetId: tab.targetId,
|
|
1292
|
-
url,
|
|
1293
|
-
timeoutMs: timeoutMs ?? void 0,
|
|
1294
|
-
maxChars: maxChars ?? void 0
|
|
1295
|
-
});
|
|
1296
|
-
const currentUrl = await resolveTabUrl(tab.url);
|
|
1297
|
-
res.json({
|
|
1298
|
-
ok: true,
|
|
1299
|
-
targetId: tab.targetId,
|
|
1300
|
-
...currentUrl ? { url: currentUrl } : {},
|
|
1301
|
-
response: result
|
|
1302
|
-
});
|
|
1303
|
-
}
|
|
1304
|
-
});
|
|
1305
|
-
}));
|
|
1306
|
-
app.post("/highlight", asyncBrowserRoute(async (req, res) => {
|
|
1307
|
-
const body = readBody(req);
|
|
1308
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
1309
|
-
const ref = toStringOrEmpty(body.ref);
|
|
1310
|
-
if (!ref) return jsonError(res, 400, "ref is required");
|
|
1311
|
-
await withRouteTabContext({
|
|
1312
|
-
req,
|
|
1313
|
-
res,
|
|
1314
|
-
ctx,
|
|
1315
|
-
targetId,
|
|
1316
|
-
enforceCurrentUrlAllowed: true,
|
|
1317
|
-
run: async ({ profileCtx, cdpUrl, tab, resolveTabUrl }) => {
|
|
1318
|
-
const jsonOk = async () => {
|
|
1319
|
-
const currentUrl = await resolveTabUrl(tab.url);
|
|
1320
|
-
return res.json({
|
|
1321
|
-
ok: true,
|
|
1322
|
-
targetId: tab.targetId,
|
|
1323
|
-
...currentUrl ? { url: currentUrl } : {}
|
|
1324
|
-
});
|
|
1325
|
-
};
|
|
1326
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) {
|
|
1327
|
-
await evaluateChromeMcpScript({
|
|
1328
|
-
profileName: profileCtx.profile.name,
|
|
1329
|
-
profile: profileCtx.profile,
|
|
1330
|
-
targetId: tab.targetId,
|
|
1331
|
-
args: [ref],
|
|
1332
|
-
fn: `(el) => {
|
|
1333
|
-
if (!(el instanceof Element)) {
|
|
1334
|
-
return false;
|
|
1335
|
-
}
|
|
1336
|
-
el.scrollIntoView({ block: "center", inline: "center" });
|
|
1337
|
-
const previousOutline = el.style.outline;
|
|
1338
|
-
const previousOffset = el.style.outlineOffset;
|
|
1339
|
-
el.style.outline = "3px solid #FF4500";
|
|
1340
|
-
el.style.outlineOffset = "2px";
|
|
1341
|
-
setTimeout(() => {
|
|
1342
|
-
el.style.outline = previousOutline;
|
|
1343
|
-
el.style.outlineOffset = previousOffset;
|
|
1344
|
-
}, 2000);
|
|
1345
|
-
return true;
|
|
1346
|
-
}`
|
|
1347
|
-
});
|
|
1348
|
-
return await jsonOk();
|
|
1349
|
-
}
|
|
1350
|
-
const pw = await requirePwAi(res, "highlight");
|
|
1351
|
-
if (!pw) return;
|
|
1352
|
-
await pw.highlightViaPlaywright({
|
|
1353
|
-
cdpUrl,
|
|
1354
|
-
targetId: tab.targetId,
|
|
1355
|
-
ref
|
|
1356
|
-
});
|
|
1357
|
-
await jsonOk();
|
|
1358
|
-
}
|
|
1359
|
-
});
|
|
1360
|
-
}));
|
|
1361
|
-
}
|
|
1362
|
-
//#endregion
|
|
1363
|
-
//#region extensions/browser/src/browser/routes/agent.debug.ts
|
|
1364
|
-
function registerBrowserAgentDebugRoutes(app, ctx) {
|
|
1365
|
-
app.get("/console", asyncBrowserRoute(async (req, res) => {
|
|
1366
|
-
const targetId = resolveTargetIdFromQuery(req.query);
|
|
1367
|
-
const level = typeof req.query.level === "string" ? req.query.level : "";
|
|
1368
|
-
await withPlaywrightRouteContext({
|
|
1369
|
-
req,
|
|
1370
|
-
res,
|
|
1371
|
-
ctx,
|
|
1372
|
-
targetId,
|
|
1373
|
-
feature: "console messages",
|
|
1374
|
-
enforceCurrentUrlAllowed: true,
|
|
1375
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1376
|
-
const messages = await pw.getConsoleMessagesViaPlaywright({
|
|
1377
|
-
cdpUrl,
|
|
1378
|
-
targetId: tab.targetId,
|
|
1379
|
-
level: normalizeOptionalString$4(level)
|
|
1380
|
-
});
|
|
1381
|
-
const url = await resolveTabUrl(tab.url);
|
|
1382
|
-
res.json({
|
|
1383
|
-
ok: true,
|
|
1384
|
-
messages,
|
|
1385
|
-
targetId: tab.targetId,
|
|
1386
|
-
...url ? { url } : {}
|
|
1387
|
-
});
|
|
1388
|
-
}
|
|
1389
|
-
});
|
|
1390
|
-
}));
|
|
1391
|
-
app.get("/errors", asyncBrowserRoute(async (req, res) => {
|
|
1392
|
-
const targetId = resolveTargetIdFromQuery(req.query);
|
|
1393
|
-
const clear = toBoolean(req.query.clear) ?? false;
|
|
1394
|
-
await withPlaywrightRouteContext({
|
|
1395
|
-
req,
|
|
1396
|
-
res,
|
|
1397
|
-
ctx,
|
|
1398
|
-
targetId,
|
|
1399
|
-
feature: "page errors",
|
|
1400
|
-
enforceCurrentUrlAllowed: true,
|
|
1401
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1402
|
-
const result = await pw.getPageErrorsViaPlaywright({
|
|
1403
|
-
cdpUrl,
|
|
1404
|
-
targetId: tab.targetId,
|
|
1405
|
-
clear
|
|
1406
|
-
});
|
|
1407
|
-
const url = await resolveTabUrl(tab.url);
|
|
1408
|
-
res.json({
|
|
1409
|
-
ok: true,
|
|
1410
|
-
targetId: tab.targetId,
|
|
1411
|
-
...url ? { url } : {},
|
|
1412
|
-
...result
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
});
|
|
1416
|
-
}));
|
|
1417
|
-
app.get("/requests", asyncBrowserRoute(async (req, res) => {
|
|
1418
|
-
const targetId = resolveTargetIdFromQuery(req.query);
|
|
1419
|
-
const filter = typeof req.query.filter === "string" ? req.query.filter : "";
|
|
1420
|
-
const clear = toBoolean(req.query.clear) ?? false;
|
|
1421
|
-
await withPlaywrightRouteContext({
|
|
1422
|
-
req,
|
|
1423
|
-
res,
|
|
1424
|
-
ctx,
|
|
1425
|
-
targetId,
|
|
1426
|
-
feature: "network requests",
|
|
1427
|
-
enforceCurrentUrlAllowed: true,
|
|
1428
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1429
|
-
const result = await pw.getNetworkRequestsViaPlaywright({
|
|
1430
|
-
cdpUrl,
|
|
1431
|
-
targetId: tab.targetId,
|
|
1432
|
-
filter: normalizeOptionalString$4(filter),
|
|
1433
|
-
clear
|
|
1434
|
-
});
|
|
1435
|
-
const url = await resolveTabUrl(tab.url);
|
|
1436
|
-
res.json({
|
|
1437
|
-
ok: true,
|
|
1438
|
-
targetId: tab.targetId,
|
|
1439
|
-
...url ? { url } : {},
|
|
1440
|
-
...result
|
|
1441
|
-
});
|
|
1442
|
-
}
|
|
1443
|
-
});
|
|
1444
|
-
}));
|
|
1445
|
-
app.get("/dialogs", asyncBrowserRoute(async (req, res) => {
|
|
1446
|
-
await withPlaywrightRouteContext({
|
|
1447
|
-
req,
|
|
1448
|
-
res,
|
|
1449
|
-
ctx,
|
|
1450
|
-
targetId: resolveTargetIdFromQuery(req.query),
|
|
1451
|
-
feature: "dialog state",
|
|
1452
|
-
enforceCurrentUrlAllowed: true,
|
|
1453
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1454
|
-
const browserState = await pw.getObservedBrowserStateViaPlaywright({
|
|
1455
|
-
cdpUrl,
|
|
1456
|
-
targetId: tab.targetId,
|
|
1457
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
1458
|
-
});
|
|
1459
|
-
const url = await resolveTabUrl(tab.url);
|
|
1460
|
-
res.json({
|
|
1461
|
-
ok: true,
|
|
1462
|
-
targetId: tab.targetId,
|
|
1463
|
-
...url ? { url } : {},
|
|
1464
|
-
browserState
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
});
|
|
1468
|
-
}));
|
|
1469
|
-
app.post("/trace/start", asyncBrowserRoute(async (req, res) => {
|
|
1470
|
-
const body = readBody(req);
|
|
1471
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
1472
|
-
const screenshots = toBoolean(body.screenshots) ?? void 0;
|
|
1473
|
-
const snapshots = toBoolean(body.snapshots) ?? void 0;
|
|
1474
|
-
const sources = toBoolean(body.sources) ?? void 0;
|
|
1475
|
-
await withPlaywrightRouteContext({
|
|
1476
|
-
req,
|
|
1477
|
-
res,
|
|
1478
|
-
ctx,
|
|
1479
|
-
targetId,
|
|
1480
|
-
feature: "trace start",
|
|
1481
|
-
enforceCurrentUrlAllowed: true,
|
|
1482
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1483
|
-
await pw.traceStartViaPlaywright({
|
|
1484
|
-
cdpUrl,
|
|
1485
|
-
targetId: tab.targetId,
|
|
1486
|
-
screenshots,
|
|
1487
|
-
snapshots,
|
|
1488
|
-
sources
|
|
1489
|
-
});
|
|
1490
|
-
const url = await resolveTabUrl(tab.url);
|
|
1491
|
-
res.json({
|
|
1492
|
-
ok: true,
|
|
1493
|
-
targetId: tab.targetId,
|
|
1494
|
-
...url ? { url } : {}
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
});
|
|
1498
|
-
}));
|
|
1499
|
-
app.post("/trace/stop", asyncBrowserRoute(async (req, res) => {
|
|
1500
|
-
const body = readBody(req);
|
|
1501
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
1502
|
-
const out = toStringOrEmpty(body.path) || "";
|
|
1503
|
-
await withPlaywrightRouteContext({
|
|
1504
|
-
req,
|
|
1505
|
-
res,
|
|
1506
|
-
ctx,
|
|
1507
|
-
targetId,
|
|
1508
|
-
feature: "trace stop",
|
|
1509
|
-
enforceCurrentUrlAllowed: true,
|
|
1510
|
-
run: async ({ cdpUrl, tab, pw, resolveTabUrl }) => {
|
|
1511
|
-
const tracePath = await resolveWritableOutputPathOrRespond({
|
|
1512
|
-
res,
|
|
1513
|
-
rootDir: DEFAULT_TRACE_DIR,
|
|
1514
|
-
requestedPath: out,
|
|
1515
|
-
scopeLabel: "trace directory",
|
|
1516
|
-
defaultFileName: `browser-trace-${crypto.randomUUID()}.zip`,
|
|
1517
|
-
ensureRootDir: true
|
|
1518
|
-
});
|
|
1519
|
-
if (!tracePath) return;
|
|
1520
|
-
await pw.traceStopViaPlaywright({
|
|
1521
|
-
cdpUrl,
|
|
1522
|
-
targetId: tab.targetId,
|
|
1523
|
-
path: tracePath
|
|
1524
|
-
});
|
|
1525
|
-
const url = await resolveTabUrl(tab.url);
|
|
1526
|
-
res.json({
|
|
1527
|
-
ok: true,
|
|
1528
|
-
targetId: tab.targetId,
|
|
1529
|
-
...url ? { url } : {},
|
|
1530
|
-
path: path.resolve(tracePath)
|
|
1531
|
-
});
|
|
1532
|
-
}
|
|
1533
|
-
});
|
|
1534
|
-
}));
|
|
1535
|
-
}
|
|
1536
|
-
//#endregion
|
|
1537
|
-
//#region extensions/browser/src/browser/chrome-mcp.snapshot.ts
|
|
1538
|
-
function normalizeRole(node) {
|
|
1539
|
-
return normalizeLowercaseStringOrEmpty(node.role) || "generic";
|
|
1540
|
-
}
|
|
1541
|
-
function escapeQuoted(value) {
|
|
1542
|
-
return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
|
|
1543
|
-
}
|
|
1544
|
-
function shouldIncludeNode(params) {
|
|
1545
|
-
if (params.options?.interactive && !INTERACTIVE_ROLES.has(params.role)) return false;
|
|
1546
|
-
if (params.options?.compact && STRUCTURAL_ROLES.has(params.role) && !params.name) return false;
|
|
1547
|
-
return true;
|
|
1548
|
-
}
|
|
1549
|
-
function shouldCreateRef(role, name) {
|
|
1550
|
-
return INTERACTIVE_ROLES.has(role) || CONTENT_ROLES.has(role) && Boolean(name);
|
|
1551
|
-
}
|
|
1552
|
-
function createDuplicateTracker() {
|
|
1553
|
-
return {
|
|
1554
|
-
counts: /* @__PURE__ */ new Map(),
|
|
1555
|
-
keysByRef: /* @__PURE__ */ new Map(),
|
|
1556
|
-
duplicates: /* @__PURE__ */ new Set()
|
|
1557
|
-
};
|
|
1558
|
-
}
|
|
1559
|
-
function registerRef(tracker, ref, role, name) {
|
|
1560
|
-
const key = `${role}:${name ?? ""}`;
|
|
1561
|
-
const count = tracker.counts.get(key) ?? 0;
|
|
1562
|
-
tracker.counts.set(key, count + 1);
|
|
1563
|
-
tracker.keysByRef.set(ref, key);
|
|
1564
|
-
if (count > 0) {
|
|
1565
|
-
tracker.duplicates.add(key);
|
|
1566
|
-
return count;
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
function flattenChromeMcpSnapshotToAriaNodes(root, limit = 500) {
|
|
1570
|
-
const boundedLimit = Math.max(1, Math.min(2e3, Math.floor(limit)));
|
|
1571
|
-
const out = [];
|
|
1572
|
-
const visit = (node, depth) => {
|
|
1573
|
-
if (out.length >= boundedLimit) return;
|
|
1574
|
-
const ref = normalizeString(node.id);
|
|
1575
|
-
if (ref) out.push({
|
|
1576
|
-
ref,
|
|
1577
|
-
role: normalizeRole(node),
|
|
1578
|
-
name: normalizeString(node.name) ?? "",
|
|
1579
|
-
value: normalizeString(node.value),
|
|
1580
|
-
description: normalizeString(node.description),
|
|
1581
|
-
depth
|
|
1582
|
-
});
|
|
1583
|
-
for (const child of node.children ?? []) {
|
|
1584
|
-
visit(child, depth + 1);
|
|
1585
|
-
if (out.length >= boundedLimit) return;
|
|
1586
|
-
}
|
|
1587
|
-
};
|
|
1588
|
-
visit(root, 0);
|
|
1589
|
-
return out;
|
|
1590
|
-
}
|
|
1591
|
-
function buildAiSnapshotFromChromeMcpSnapshot(params) {
|
|
1592
|
-
const refs = {};
|
|
1593
|
-
const tracker = createDuplicateTracker();
|
|
1594
|
-
const lines = [];
|
|
1595
|
-
const visit = (node, depth) => {
|
|
1596
|
-
const role = normalizeRole(node);
|
|
1597
|
-
const name = normalizeString(node.name);
|
|
1598
|
-
const value = normalizeString(node.value);
|
|
1599
|
-
const description = normalizeString(node.description);
|
|
1600
|
-
const maxDepth = params.options?.maxDepth;
|
|
1601
|
-
if (maxDepth !== void 0 && depth > maxDepth) return;
|
|
1602
|
-
if (shouldIncludeNode({
|
|
1603
|
-
role,
|
|
1604
|
-
name,
|
|
1605
|
-
options: params.options
|
|
1606
|
-
})) {
|
|
1607
|
-
let line = `${" ".repeat(depth)}- ${role}`;
|
|
1608
|
-
if (name) line += ` "${escapeQuoted(name)}"`;
|
|
1609
|
-
const ref = normalizeString(node.id);
|
|
1610
|
-
if (ref && shouldCreateRef(role, name)) {
|
|
1611
|
-
const nth = registerRef(tracker, ref, role, name);
|
|
1612
|
-
refs[ref] = nth === void 0 ? {
|
|
1613
|
-
role,
|
|
1614
|
-
name
|
|
1615
|
-
} : {
|
|
1616
|
-
role,
|
|
1617
|
-
name,
|
|
1618
|
-
nth
|
|
1619
|
-
};
|
|
1620
|
-
line += ` [ref=${ref}]`;
|
|
1621
|
-
}
|
|
1622
|
-
if (value) line += ` value="${escapeQuoted(value)}"`;
|
|
1623
|
-
if (description) line += ` description="${escapeQuoted(description)}"`;
|
|
1624
|
-
lines.push(line);
|
|
1625
|
-
}
|
|
1626
|
-
for (const child of node.children ?? []) visit(child, depth + 1);
|
|
1627
|
-
};
|
|
1628
|
-
visit(params.root, 0);
|
|
1629
|
-
for (const [ref, data] of Object.entries(refs)) {
|
|
1630
|
-
const key = tracker.keysByRef.get(ref);
|
|
1631
|
-
if (key && !tracker.duplicates.has(key)) delete data.nth;
|
|
1632
|
-
}
|
|
1633
|
-
let snapshot = lines.join("\n");
|
|
1634
|
-
let truncated = false;
|
|
1635
|
-
const maxChars = typeof params.maxChars === "number" && Number.isFinite(params.maxChars) && params.maxChars > 0 ? Math.floor(params.maxChars) : void 0;
|
|
1636
|
-
if (maxChars && snapshot.length > maxChars) {
|
|
1637
|
-
snapshot = `${snapshot.slice(0, maxChars)}\n\n[...TRUNCATED - page too large]`;
|
|
1638
|
-
truncated = true;
|
|
1639
|
-
}
|
|
1640
|
-
const stats = getRoleSnapshotStats(snapshot, refs);
|
|
1641
|
-
return truncated ? {
|
|
1642
|
-
snapshot,
|
|
1643
|
-
truncated,
|
|
1644
|
-
refs,
|
|
1645
|
-
stats
|
|
1646
|
-
} : {
|
|
1647
|
-
snapshot,
|
|
1648
|
-
refs,
|
|
1649
|
-
stats
|
|
1650
|
-
};
|
|
1651
|
-
}
|
|
1652
|
-
//#endregion
|
|
1653
|
-
//#region extensions/browser/src/browser/screenshot.ts
|
|
1654
|
-
const DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE = 2e3;
|
|
1655
|
-
const DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
|
|
1656
|
-
async function normalizeBrowserScreenshot(buffer, opts) {
|
|
1657
|
-
const maxSide = Math.max(1, Math.round(opts?.maxSide ?? 2e3));
|
|
1658
|
-
const maxBytes = Math.max(1, Math.round(opts?.maxBytes ?? 5242880));
|
|
1659
|
-
const meta = await getImageMetadata(buffer);
|
|
1660
|
-
const width = meta?.width ?? 0;
|
|
1661
|
-
const height = meta?.height ?? 0;
|
|
1662
|
-
const maxDim = Math.max(width, height);
|
|
1663
|
-
if (buffer.byteLength <= maxBytes && (maxDim === 0 || width <= maxSide && height <= maxSide)) return { buffer };
|
|
1664
|
-
const sideGrid = buildImageResizeSideGrid(maxSide, maxDim > 0 ? Math.min(maxSide, maxDim) : maxSide);
|
|
1665
|
-
let smallest = null;
|
|
1666
|
-
let processorUnavailableError;
|
|
1667
|
-
for (const side of sideGrid) {
|
|
1668
|
-
for (const quality of IMAGE_REDUCE_QUALITY_STEPS) {
|
|
1669
|
-
let out;
|
|
1670
|
-
try {
|
|
1671
|
-
out = await resizeToJpeg({
|
|
1672
|
-
buffer,
|
|
1673
|
-
maxSide: side,
|
|
1674
|
-
quality,
|
|
1675
|
-
withoutEnlargement: true
|
|
1676
|
-
});
|
|
1677
|
-
} catch (err) {
|
|
1678
|
-
if (isImageProcessorUnavailableError(err)) {
|
|
1679
|
-
processorUnavailableError = err;
|
|
1680
|
-
break;
|
|
1681
|
-
}
|
|
1682
|
-
throw err;
|
|
1683
|
-
}
|
|
1684
|
-
if (!smallest || out.byteLength < smallest.size) smallest = {
|
|
1685
|
-
buffer: out,
|
|
1686
|
-
size: out.byteLength
|
|
1687
|
-
};
|
|
1688
|
-
if (out.byteLength <= maxBytes) return {
|
|
1689
|
-
buffer: out,
|
|
1690
|
-
contentType: "image/jpeg"
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
if (processorUnavailableError) break;
|
|
1694
|
-
}
|
|
1695
|
-
if (processorUnavailableError) throw processorUnavailableError;
|
|
1696
|
-
const best = smallest?.buffer ?? buffer;
|
|
1697
|
-
throw new Error(`Browser screenshot could not be reduced below ${(maxBytes / (1024 * 1024)).toFixed(0)}MB (got ${(best.byteLength / (1024 * 1024)).toFixed(2)}MB)`);
|
|
1698
|
-
}
|
|
1699
|
-
//#endregion
|
|
1700
|
-
//#region extensions/browser/src/browser/routes/agent.snapshot.plan.ts
|
|
1701
|
-
function readStringValue$1(value) {
|
|
1702
|
-
return typeof value === "string" ? value : void 0;
|
|
1703
|
-
}
|
|
1704
|
-
function normalizeOptionalString$1(value) {
|
|
1705
|
-
return readStringValue$1(value)?.trim() || void 0;
|
|
1706
|
-
}
|
|
1707
|
-
function resolveSnapshotPlan(params) {
|
|
1708
|
-
const mode = params.query.mode === "efficient" ? "efficient" : void 0;
|
|
1709
|
-
const labels = toBoolean(params.query.labels) ?? void 0;
|
|
1710
|
-
const urls = toBoolean(params.query.urls) ?? void 0;
|
|
1711
|
-
const explicitFormat = params.query.format === "aria" ? "aria" : params.query.format === "ai" ? "ai" : void 0;
|
|
1712
|
-
const format = resolveDefaultSnapshotFormat({
|
|
1713
|
-
profile: params.profile,
|
|
1714
|
-
hasPlaywright: params.hasPlaywright,
|
|
1715
|
-
explicitFormat,
|
|
1716
|
-
mode
|
|
1717
|
-
});
|
|
1718
|
-
const limitRaw = readStringValue$1(params.query.limit);
|
|
1719
|
-
const hasMaxChars = Object.hasOwn(params.query, "maxChars");
|
|
1720
|
-
const maxCharsRaw = readStringValue$1(params.query.maxChars);
|
|
1721
|
-
const limit = Number.isFinite(Number(limitRaw)) ? Number(limitRaw) : void 0;
|
|
1722
|
-
const maxChars = Number.isFinite(Number(maxCharsRaw)) && Number(maxCharsRaw) > 0 ? Math.floor(Number(maxCharsRaw)) : void 0;
|
|
1723
|
-
const resolvedMaxChars = format === "ai" ? hasMaxChars ? maxChars : mode === "efficient" ? DEFAULT_AI_SNAPSHOT_EFFICIENT_MAX_CHARS : DEFAULT_AI_SNAPSHOT_MAX_CHARS : void 0;
|
|
1724
|
-
const interactiveRaw = toBoolean(params.query.interactive);
|
|
1725
|
-
const compactRaw = toBoolean(params.query.compact);
|
|
1726
|
-
const depthRaw = toNumber(params.query.depth);
|
|
1727
|
-
const refsModeRaw = toStringOrEmpty(params.query.refs).trim();
|
|
1728
|
-
const refsMode = refsModeRaw === "aria" ? "aria" : refsModeRaw === "role" ? "role" : void 0;
|
|
1729
|
-
const interactive = interactiveRaw ?? (mode === "efficient" ? true : void 0);
|
|
1730
|
-
const compact = compactRaw ?? (mode === "efficient" ? true : void 0);
|
|
1731
|
-
const depth = depthRaw ?? (mode === "efficient" ? 6 : void 0);
|
|
1732
|
-
const selectorValue = normalizeOptionalString$1(toStringOrEmpty(params.query.selector));
|
|
1733
|
-
const frameSelectorValue = normalizeOptionalString$1(toStringOrEmpty(params.query.frame));
|
|
1734
|
-
return {
|
|
1735
|
-
format,
|
|
1736
|
-
mode,
|
|
1737
|
-
labels,
|
|
1738
|
-
urls,
|
|
1739
|
-
limit,
|
|
1740
|
-
resolvedMaxChars,
|
|
1741
|
-
interactive,
|
|
1742
|
-
compact,
|
|
1743
|
-
depth,
|
|
1744
|
-
refsMode,
|
|
1745
|
-
selectorValue,
|
|
1746
|
-
frameSelectorValue,
|
|
1747
|
-
wantsRoleSnapshot: labels === true || urls === true || mode === "efficient" || interactive === true || compact === true || depth !== void 0 || Boolean(selectorValue) || Boolean(frameSelectorValue)
|
|
1748
|
-
};
|
|
1749
|
-
}
|
|
1750
|
-
//#endregion
|
|
1751
|
-
//#region extensions/browser/src/browser/routes/agent.snapshot.ts
|
|
1752
|
-
const CHROME_MCP_OVERLAY_ATTR = "data-daocore-mcp-overlay";
|
|
1753
|
-
function browserNavigationPolicyForProfile$1(ctx, profileCtx) {
|
|
1754
|
-
return withBrowserNavigationPolicy(ctx.state().resolved.ssrfPolicy, { browserProxyMode: resolveBrowserNavigationProxyMode({
|
|
1755
|
-
resolved: ctx.state().resolved,
|
|
1756
|
-
profile: profileCtx.profile
|
|
1757
|
-
}) });
|
|
1758
|
-
}
|
|
1759
|
-
async function collectChromeMcpSnapshotUrls(params) {
|
|
1760
|
-
const result = await evaluateChromeMcpScript({
|
|
1761
|
-
profileName: params.profileName,
|
|
1762
|
-
profile: params.profile,
|
|
1763
|
-
userDataDir: params.userDataDir,
|
|
1764
|
-
targetId: params.targetId,
|
|
1765
|
-
fn: `() => {
|
|
1766
|
-
const seen = new Set();
|
|
1767
|
-
const out = [];
|
|
1768
|
-
for (const anchor of Array.from(document.querySelectorAll("a[href]"))) {
|
|
1769
|
-
const href = anchor.href || "";
|
|
1770
|
-
if (!href || seen.has(href)) continue;
|
|
1771
|
-
const text = (anchor.innerText || anchor.textContent || anchor.getAttribute("aria-label") || "")
|
|
1772
|
-
.replace(/\\s+/g, " ")
|
|
1773
|
-
.trim()
|
|
1774
|
-
.slice(0, 120) || href;
|
|
1775
|
-
seen.add(href);
|
|
1776
|
-
out.push({ text, url: href });
|
|
1777
|
-
if (out.length >= 100) break;
|
|
1778
|
-
}
|
|
1779
|
-
return out;
|
|
1780
|
-
}`
|
|
1781
|
-
}).catch(() => []);
|
|
1782
|
-
return Array.isArray(result) ? result.filter((entry) => entry && typeof entry === "object" && typeof entry.text === "string" && typeof entry.url === "string") : [];
|
|
1783
|
-
}
|
|
1784
|
-
function appendSnapshotUrls(snapshot, urls) {
|
|
1785
|
-
if (urls.length === 0) return snapshot;
|
|
1786
|
-
return `${snapshot}\n\nLinks:\n${urls.map((entry, index) => `${index + 1}. ${entry.text} -> ${entry.url}`).join("\n")}`;
|
|
1787
|
-
}
|
|
1788
|
-
async function clearChromeMcpOverlay(params) {
|
|
1789
|
-
await evaluateChromeMcpScript({
|
|
1790
|
-
profileName: params.profileName,
|
|
1791
|
-
profile: params.profile,
|
|
1792
|
-
userDataDir: params.userDataDir,
|
|
1793
|
-
targetId: params.targetId,
|
|
1794
|
-
fn: `() => {
|
|
1795
|
-
document.querySelectorAll("[${CHROME_MCP_OVERLAY_ATTR}]").forEach((node) => node.remove());
|
|
1796
|
-
return true;
|
|
1797
|
-
}`
|
|
1798
|
-
}).catch(() => {});
|
|
1799
|
-
}
|
|
1800
|
-
async function renderChromeMcpLabels(params) {
|
|
1801
|
-
const refList = JSON.stringify(params.refs);
|
|
1802
|
-
const result = await evaluateChromeMcpScript({
|
|
1803
|
-
profileName: params.profileName,
|
|
1804
|
-
profile: params.profile,
|
|
1805
|
-
userDataDir: params.userDataDir,
|
|
1806
|
-
targetId: params.targetId,
|
|
1807
|
-
args: params.refs,
|
|
1808
|
-
fn: `(...elements) => {
|
|
1809
|
-
const refs = ${refList};
|
|
1810
|
-
document.querySelectorAll("[${CHROME_MCP_OVERLAY_ATTR}]").forEach((node) => node.remove());
|
|
1811
|
-
const root = document.createElement("div");
|
|
1812
|
-
root.setAttribute("${CHROME_MCP_OVERLAY_ATTR}", "labels");
|
|
1813
|
-
root.style.position = "fixed";
|
|
1814
|
-
root.style.inset = "0";
|
|
1815
|
-
root.style.pointerEvents = "none";
|
|
1816
|
-
root.style.zIndex = "2147483647";
|
|
1817
|
-
let labels = 0;
|
|
1818
|
-
let skipped = 0;
|
|
1819
|
-
elements.forEach((el, index) => {
|
|
1820
|
-
if (!(el instanceof Element)) {
|
|
1821
|
-
skipped += 1;
|
|
1822
|
-
return;
|
|
1823
|
-
}
|
|
1824
|
-
const rect = el.getBoundingClientRect();
|
|
1825
|
-
if (rect.width <= 0 && rect.height <= 0) {
|
|
1826
|
-
skipped += 1;
|
|
1827
|
-
return;
|
|
1828
|
-
}
|
|
1829
|
-
labels += 1;
|
|
1830
|
-
const badge = document.createElement("div");
|
|
1831
|
-
badge.setAttribute("${CHROME_MCP_OVERLAY_ATTR}", "label");
|
|
1832
|
-
badge.textContent = refs[index] || String(labels);
|
|
1833
|
-
badge.style.position = "fixed";
|
|
1834
|
-
badge.style.left = \`\${Math.max(0, rect.left)}px\`;
|
|
1835
|
-
badge.style.top = \`\${Math.max(0, rect.top)}px\`;
|
|
1836
|
-
badge.style.transform = "translateY(-100%)";
|
|
1837
|
-
badge.style.padding = "2px 6px";
|
|
1838
|
-
badge.style.borderRadius = "999px";
|
|
1839
|
-
badge.style.background = "#FF4500";
|
|
1840
|
-
badge.style.color = "#fff";
|
|
1841
|
-
badge.style.font = "600 12px ui-monospace, SFMono-Regular, Menlo, monospace";
|
|
1842
|
-
badge.style.boxShadow = "0 2px 6px rgba(0,0,0,0.35)";
|
|
1843
|
-
badge.style.whiteSpace = "nowrap";
|
|
1844
|
-
root.appendChild(badge);
|
|
1845
|
-
});
|
|
1846
|
-
document.documentElement.appendChild(root);
|
|
1847
|
-
return { labels, skipped };
|
|
1848
|
-
}`
|
|
1849
|
-
});
|
|
1850
|
-
return {
|
|
1851
|
-
labels: result && typeof result === "object" && typeof result.labels === "number" ? result.labels : 0,
|
|
1852
|
-
skipped: result && typeof result === "object" && typeof result.skipped === "number" ? result.skipped : 0
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
async function saveNormalizedScreenshotResponse(params) {
|
|
1856
|
-
const normalized = await normalizeBrowserScreenshot(params.buffer, {
|
|
1857
|
-
maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
|
|
1858
|
-
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES
|
|
1859
|
-
});
|
|
1860
|
-
await saveBrowserMediaResponse({
|
|
1861
|
-
res: params.res,
|
|
1862
|
-
buffer: normalized.buffer,
|
|
1863
|
-
contentType: normalized.contentType ?? `image/${params.type}`,
|
|
1864
|
-
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES,
|
|
1865
|
-
targetId: params.targetId,
|
|
1866
|
-
url: params.url,
|
|
1867
|
-
labels: params.labels,
|
|
1868
|
-
labelsCount: params.labelsCount,
|
|
1869
|
-
labelsSkipped: params.labelsSkipped
|
|
1870
|
-
});
|
|
1871
|
-
}
|
|
1872
|
-
async function saveBrowserMediaResponse(params) {
|
|
1873
|
-
await ensureMediaDir();
|
|
1874
|
-
const saved = await saveMediaBuffer(params.buffer, params.contentType, "browser", params.maxBytes);
|
|
1875
|
-
params.res.json({
|
|
1876
|
-
ok: true,
|
|
1877
|
-
path: path.resolve(saved.path),
|
|
1878
|
-
targetId: params.targetId,
|
|
1879
|
-
url: params.url,
|
|
1880
|
-
...params.labels ? { labels: true } : {},
|
|
1881
|
-
...typeof params.labelsCount === "number" ? { labelsCount: params.labelsCount } : {},
|
|
1882
|
-
...typeof params.labelsSkipped === "number" ? { labelsSkipped: params.labelsSkipped } : {}
|
|
1883
|
-
});
|
|
1884
|
-
}
|
|
1885
|
-
function hasObservableBrowserState(state) {
|
|
1886
|
-
if (!state || typeof state !== "object") return false;
|
|
1887
|
-
const dialogs = state.dialogs;
|
|
1888
|
-
return Boolean(dialogs?.pending?.length || dialogs?.recent?.length);
|
|
1889
|
-
}
|
|
1890
|
-
function hasPendingDialogs(state) {
|
|
1891
|
-
if (!state || typeof state !== "object") return false;
|
|
1892
|
-
const dialogs = state.dialogs;
|
|
1893
|
-
return Boolean(dialogs?.pending?.length);
|
|
1894
|
-
}
|
|
1895
|
-
function browserStateResponseFields(state) {
|
|
1896
|
-
return hasObservableBrowserState(state) ? { browserState: state } : {};
|
|
1897
|
-
}
|
|
1898
|
-
function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
1899
|
-
app.post("/navigate", asyncBrowserRoute(async (req, res) => {
|
|
1900
|
-
const body = readBody(req);
|
|
1901
|
-
const url = toStringOrEmpty(body.url);
|
|
1902
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
1903
|
-
if (!url) return jsonError(res, 400, "url is required");
|
|
1904
|
-
await withRouteTabContext({
|
|
1905
|
-
req,
|
|
1906
|
-
res,
|
|
1907
|
-
ctx,
|
|
1908
|
-
targetId,
|
|
1909
|
-
run: async ({ profileCtx, tab, cdpUrl }) => {
|
|
1910
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) {
|
|
1911
|
-
const ssrfPolicyOpts = browserNavigationPolicyForProfile$1(ctx, profileCtx);
|
|
1912
|
-
await assertBrowserNavigationAllowed({
|
|
1913
|
-
url,
|
|
1914
|
-
...ssrfPolicyOpts
|
|
1915
|
-
});
|
|
1916
|
-
const result = await navigateChromeMcpPage({
|
|
1917
|
-
profileName: profileCtx.profile.name,
|
|
1918
|
-
profile: profileCtx.profile,
|
|
1919
|
-
targetId: tab.targetId,
|
|
1920
|
-
url
|
|
1921
|
-
});
|
|
1922
|
-
await assertBrowserNavigationResultAllowed({
|
|
1923
|
-
url: result.url,
|
|
1924
|
-
...ssrfPolicyOpts
|
|
1925
|
-
});
|
|
1926
|
-
return res.json({
|
|
1927
|
-
ok: true,
|
|
1928
|
-
targetId: tab.targetId,
|
|
1929
|
-
...result
|
|
1930
|
-
});
|
|
1931
|
-
}
|
|
1932
|
-
const pw = await requirePwAi(res, "navigate");
|
|
1933
|
-
if (!pw) return;
|
|
1934
|
-
const result = await pw.navigateViaPlaywright({
|
|
1935
|
-
cdpUrl,
|
|
1936
|
-
targetId: tab.targetId,
|
|
1937
|
-
url,
|
|
1938
|
-
...browserNavigationPolicyForProfile$1(ctx, profileCtx)
|
|
1939
|
-
});
|
|
1940
|
-
const currentTargetId = await resolveTargetIdAfterNavigate({
|
|
1941
|
-
oldTargetId: tab.targetId,
|
|
1942
|
-
navigatedUrl: result.url,
|
|
1943
|
-
listTabs: () => profileCtx.listTabs()
|
|
1944
|
-
});
|
|
1945
|
-
res.json({
|
|
1946
|
-
ok: true,
|
|
1947
|
-
targetId: currentTargetId,
|
|
1948
|
-
...result
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
});
|
|
1952
|
-
}));
|
|
1953
|
-
app.post("/pdf", asyncBrowserRoute(async (req, res) => {
|
|
1954
|
-
const targetId = toStringOrEmpty(readBody(req).targetId) || void 0;
|
|
1955
|
-
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
1956
|
-
if (!profileCtx) return;
|
|
1957
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) return jsonError(res, 501, EXISTING_SESSION_LIMITS.snapshot.pdfUnsupported);
|
|
1958
|
-
await withPlaywrightRouteContext({
|
|
1959
|
-
req,
|
|
1960
|
-
res,
|
|
1961
|
-
ctx,
|
|
1962
|
-
targetId,
|
|
1963
|
-
feature: "pdf",
|
|
1964
|
-
enforceCurrentUrlAllowed: true,
|
|
1965
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
1966
|
-
const pdf = await pw.pdfViaPlaywright({
|
|
1967
|
-
cdpUrl,
|
|
1968
|
-
targetId: tab.targetId
|
|
1969
|
-
});
|
|
1970
|
-
await saveBrowserMediaResponse({
|
|
1971
|
-
res,
|
|
1972
|
-
buffer: pdf.buffer,
|
|
1973
|
-
contentType: "application/pdf",
|
|
1974
|
-
maxBytes: pdf.buffer.byteLength,
|
|
1975
|
-
targetId: tab.targetId,
|
|
1976
|
-
url: tab.url
|
|
1977
|
-
});
|
|
1978
|
-
}
|
|
1979
|
-
});
|
|
1980
|
-
}));
|
|
1981
|
-
app.post("/screenshot", asyncBrowserRoute(async (req, res) => {
|
|
1982
|
-
const body = readBody(req);
|
|
1983
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
1984
|
-
const fullPage = toBoolean(body.fullPage) ?? false;
|
|
1985
|
-
const ref = toStringOrEmpty(body.ref) || void 0;
|
|
1986
|
-
const element = toStringOrEmpty(body.element) || void 0;
|
|
1987
|
-
const labels = toBoolean(body.labels) ?? false;
|
|
1988
|
-
const type = body.type === "jpeg" ? "jpeg" : "png";
|
|
1989
|
-
const timeoutMsRaw = toNumber(body.timeoutMs);
|
|
1990
|
-
const timeoutMs = timeoutMsRaw !== void 0 ? Math.max(1, Math.floor(timeoutMsRaw)) : DEFAULT_BROWSER_SCREENSHOT_TIMEOUT_MS;
|
|
1991
|
-
if (fullPage && (ref || element)) return jsonError(res, 400, "fullPage is not supported for element screenshots");
|
|
1992
|
-
await withRouteTabContext({
|
|
1993
|
-
req,
|
|
1994
|
-
res,
|
|
1995
|
-
ctx,
|
|
1996
|
-
targetId,
|
|
1997
|
-
enforceCurrentUrlAllowed: true,
|
|
1998
|
-
run: async ({ profileCtx, tab, cdpUrl }) => {
|
|
1999
|
-
if (getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp) {
|
|
2000
|
-
const ssrfPolicyOpts = browserNavigationPolicyForProfile$1(ctx, profileCtx);
|
|
2001
|
-
if (ssrfPolicyOpts.ssrfPolicy) await assertBrowserNavigationResultAllowed({
|
|
2002
|
-
url: tab.url,
|
|
2003
|
-
...ssrfPolicyOpts
|
|
2004
|
-
});
|
|
2005
|
-
if (element) return jsonError(res, 400, EXISTING_SESSION_LIMITS.snapshot.screenshotElement);
|
|
2006
|
-
if (labels) {
|
|
2007
|
-
const built = buildAiSnapshotFromChromeMcpSnapshot({ root: await takeChromeMcpSnapshot({
|
|
2008
|
-
profileName: profileCtx.profile.name,
|
|
2009
|
-
profile: profileCtx.profile,
|
|
2010
|
-
targetId: tab.targetId
|
|
2011
|
-
}) });
|
|
2012
|
-
const labelResult = await renderChromeMcpLabels({
|
|
2013
|
-
profileName: profileCtx.profile.name,
|
|
2014
|
-
profile: profileCtx.profile,
|
|
2015
|
-
targetId: tab.targetId,
|
|
2016
|
-
refs: Object.keys(built.refs)
|
|
2017
|
-
});
|
|
2018
|
-
try {
|
|
2019
|
-
await saveNormalizedScreenshotResponse({
|
|
2020
|
-
res,
|
|
2021
|
-
buffer: await takeChromeMcpScreenshot({
|
|
2022
|
-
profileName: profileCtx.profile.name,
|
|
2023
|
-
profile: profileCtx.profile,
|
|
2024
|
-
targetId: tab.targetId,
|
|
2025
|
-
fullPage,
|
|
2026
|
-
format: type,
|
|
2027
|
-
timeoutMs
|
|
2028
|
-
}),
|
|
2029
|
-
type,
|
|
2030
|
-
targetId: tab.targetId,
|
|
2031
|
-
url: tab.url,
|
|
2032
|
-
labels: true,
|
|
2033
|
-
labelsCount: labelResult.labels,
|
|
2034
|
-
labelsSkipped: labelResult.skipped
|
|
2035
|
-
});
|
|
2036
|
-
} finally {
|
|
2037
|
-
await clearChromeMcpOverlay({
|
|
2038
|
-
profileName: profileCtx.profile.name,
|
|
2039
|
-
profile: profileCtx.profile,
|
|
2040
|
-
targetId: tab.targetId
|
|
2041
|
-
});
|
|
2042
|
-
}
|
|
2043
|
-
return;
|
|
2044
|
-
}
|
|
2045
|
-
await saveNormalizedScreenshotResponse({
|
|
2046
|
-
res,
|
|
2047
|
-
buffer: await takeChromeMcpScreenshot({
|
|
2048
|
-
profileName: profileCtx.profile.name,
|
|
2049
|
-
profile: profileCtx.profile,
|
|
2050
|
-
targetId: tab.targetId,
|
|
2051
|
-
uid: ref,
|
|
2052
|
-
fullPage,
|
|
2053
|
-
format: type,
|
|
2054
|
-
timeoutMs
|
|
2055
|
-
}),
|
|
2056
|
-
type,
|
|
2057
|
-
targetId: tab.targetId,
|
|
2058
|
-
url: tab.url
|
|
2059
|
-
});
|
|
2060
|
-
return;
|
|
2061
|
-
}
|
|
2062
|
-
let buffer;
|
|
2063
|
-
if (labels || shouldUsePlaywrightForScreenshot({
|
|
2064
|
-
profile: profileCtx.profile,
|
|
2065
|
-
wsUrl: tab.wsUrl,
|
|
2066
|
-
ref,
|
|
2067
|
-
element
|
|
2068
|
-
})) {
|
|
2069
|
-
const pw = await requirePwAi(res, "screenshot");
|
|
2070
|
-
if (!pw) return;
|
|
2071
|
-
if (labels) {
|
|
2072
|
-
const snap = await pw.snapshotRoleViaPlaywright({
|
|
2073
|
-
cdpUrl,
|
|
2074
|
-
targetId: tab.targetId,
|
|
2075
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
2076
|
-
});
|
|
2077
|
-
const labeled = await pw.screenshotWithLabelsViaPlaywright({
|
|
2078
|
-
cdpUrl,
|
|
2079
|
-
targetId: tab.targetId,
|
|
2080
|
-
refs: snap.refs,
|
|
2081
|
-
type,
|
|
2082
|
-
timeoutMs
|
|
2083
|
-
});
|
|
2084
|
-
await saveNormalizedScreenshotResponse({
|
|
2085
|
-
res,
|
|
2086
|
-
buffer: labeled.buffer,
|
|
2087
|
-
type,
|
|
2088
|
-
targetId: tab.targetId,
|
|
2089
|
-
url: tab.url,
|
|
2090
|
-
labels: true,
|
|
2091
|
-
labelsCount: labeled.labels,
|
|
2092
|
-
labelsSkipped: labeled.skipped
|
|
2093
|
-
});
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
buffer = (await pw.takeScreenshotViaPlaywright({
|
|
2097
|
-
cdpUrl,
|
|
2098
|
-
targetId: tab.targetId,
|
|
2099
|
-
ref,
|
|
2100
|
-
element,
|
|
2101
|
-
fullPage,
|
|
2102
|
-
type,
|
|
2103
|
-
timeoutMs
|
|
2104
|
-
})).buffer;
|
|
2105
|
-
} else buffer = await captureScreenshot({
|
|
2106
|
-
wsUrl: tab.wsUrl ?? "",
|
|
2107
|
-
fullPage,
|
|
2108
|
-
format: type,
|
|
2109
|
-
quality: type === "jpeg" ? 85 : void 0,
|
|
2110
|
-
timeoutMs
|
|
2111
|
-
});
|
|
2112
|
-
await saveNormalizedScreenshotResponse({
|
|
2113
|
-
res,
|
|
2114
|
-
buffer,
|
|
2115
|
-
type,
|
|
2116
|
-
targetId: tab.targetId,
|
|
2117
|
-
url: tab.url
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
});
|
|
2121
|
-
}));
|
|
2122
|
-
app.get("/snapshot", asyncBrowserRoute(async (req, res) => {
|
|
2123
|
-
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
2124
|
-
if (!profileCtx) return;
|
|
2125
|
-
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
|
|
2126
|
-
const pwModule = await getPwAiModule();
|
|
2127
|
-
const hasPlaywright = Boolean(pwModule);
|
|
2128
|
-
const plan = resolveSnapshotPlan({
|
|
2129
|
-
profile: profileCtx.profile,
|
|
2130
|
-
query: req.query,
|
|
2131
|
-
hasPlaywright
|
|
2132
|
-
});
|
|
2133
|
-
try {
|
|
2134
|
-
const tab = await profileCtx.ensureTabAvailable(targetId || void 0);
|
|
2135
|
-
const usesChromeMcp = getBrowserProfileCapabilities(profileCtx.profile).usesChromeMcp;
|
|
2136
|
-
const ssrfPolicyOpts = browserNavigationPolicyForProfile$1(ctx, profileCtx);
|
|
2137
|
-
let observedBrowserState;
|
|
2138
|
-
if (!usesChromeMcp && pwModule) {
|
|
2139
|
-
await assertBrowserNavigationResultAllowed({
|
|
2140
|
-
url: tab.url,
|
|
2141
|
-
...ssrfPolicyOpts
|
|
2142
|
-
});
|
|
2143
|
-
observedBrowserState = await pwModule.getObservedBrowserStateViaPlaywright({
|
|
2144
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2145
|
-
targetId: tab.targetId,
|
|
2146
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
2147
|
-
}).catch(() => void 0);
|
|
2148
|
-
}
|
|
2149
|
-
if ((plan.labels || plan.mode === "efficient") && plan.format === "aria") return jsonError(res, 400, "labels/mode=efficient require format=ai");
|
|
2150
|
-
if (usesChromeMcp) {
|
|
2151
|
-
if (plan.selectorValue || plan.frameSelectorValue) return jsonError(res, 400, EXISTING_SESSION_LIMITS.snapshot.snapshotSelector);
|
|
2152
|
-
if (ssrfPolicyOpts.ssrfPolicy) await assertBrowserNavigationResultAllowed({
|
|
2153
|
-
url: tab.url,
|
|
2154
|
-
...ssrfPolicyOpts
|
|
2155
|
-
});
|
|
2156
|
-
const snapshot = await takeChromeMcpSnapshot({
|
|
2157
|
-
profileName: profileCtx.profile.name,
|
|
2158
|
-
profile: profileCtx.profile,
|
|
2159
|
-
targetId: tab.targetId
|
|
2160
|
-
});
|
|
2161
|
-
if (plan.format === "aria") return res.json({
|
|
2162
|
-
ok: true,
|
|
2163
|
-
format: "aria",
|
|
2164
|
-
targetId: tab.targetId,
|
|
2165
|
-
url: tab.url,
|
|
2166
|
-
nodes: flattenChromeMcpSnapshotToAriaNodes(snapshot, plan.limit)
|
|
2167
|
-
});
|
|
2168
|
-
const built = buildAiSnapshotFromChromeMcpSnapshot({
|
|
2169
|
-
root: snapshot,
|
|
2170
|
-
options: {
|
|
2171
|
-
interactive: plan.interactive ?? void 0,
|
|
2172
|
-
compact: plan.compact ?? void 0,
|
|
2173
|
-
maxDepth: plan.depth ?? void 0
|
|
2174
|
-
},
|
|
2175
|
-
maxChars: plan.resolvedMaxChars
|
|
2176
|
-
});
|
|
2177
|
-
const builtWithUrls = plan.urls ? {
|
|
2178
|
-
...built,
|
|
2179
|
-
snapshot: appendSnapshotUrls(built.snapshot, await collectChromeMcpSnapshotUrls({
|
|
2180
|
-
profileName: profileCtx.profile.name,
|
|
2181
|
-
profile: profileCtx.profile,
|
|
2182
|
-
targetId: tab.targetId
|
|
2183
|
-
}))
|
|
2184
|
-
} : built;
|
|
2185
|
-
if (plan.labels) {
|
|
2186
|
-
const refs = Object.keys(builtWithUrls.refs);
|
|
2187
|
-
const labelResult = await renderChromeMcpLabels({
|
|
2188
|
-
profileName: profileCtx.profile.name,
|
|
2189
|
-
profile: profileCtx.profile,
|
|
2190
|
-
targetId: tab.targetId,
|
|
2191
|
-
refs
|
|
2192
|
-
});
|
|
2193
|
-
try {
|
|
2194
|
-
const normalized = await normalizeBrowserScreenshot(await takeChromeMcpScreenshot({
|
|
2195
|
-
profileName: profileCtx.profile.name,
|
|
2196
|
-
profile: profileCtx.profile,
|
|
2197
|
-
targetId: tab.targetId,
|
|
2198
|
-
format: "png"
|
|
2199
|
-
}), {
|
|
2200
|
-
maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
|
|
2201
|
-
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES
|
|
2202
|
-
});
|
|
2203
|
-
await ensureMediaDir();
|
|
2204
|
-
const saved = await saveMediaBuffer(normalized.buffer, normalized.contentType ?? "image/png", "browser", DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES);
|
|
2205
|
-
return res.json({
|
|
2206
|
-
ok: true,
|
|
2207
|
-
format: "ai",
|
|
2208
|
-
targetId: tab.targetId,
|
|
2209
|
-
url: tab.url,
|
|
2210
|
-
labels: true,
|
|
2211
|
-
labelsCount: labelResult.labels,
|
|
2212
|
-
labelsSkipped: labelResult.skipped,
|
|
2213
|
-
imagePath: path.resolve(saved.path),
|
|
2214
|
-
imageType: normalized.contentType?.includes("jpeg") ? "jpeg" : "png",
|
|
2215
|
-
...builtWithUrls
|
|
2216
|
-
});
|
|
2217
|
-
} finally {
|
|
2218
|
-
await clearChromeMcpOverlay({
|
|
2219
|
-
profileName: profileCtx.profile.name,
|
|
2220
|
-
profile: profileCtx.profile,
|
|
2221
|
-
targetId: tab.targetId
|
|
2222
|
-
});
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
return res.json({
|
|
2226
|
-
ok: true,
|
|
2227
|
-
format: "ai",
|
|
2228
|
-
targetId: tab.targetId,
|
|
2229
|
-
url: tab.url,
|
|
2230
|
-
...builtWithUrls
|
|
2231
|
-
});
|
|
2232
|
-
}
|
|
2233
|
-
if (hasPendingDialogs(observedBrowserState)) return res.json({
|
|
2234
|
-
ok: true,
|
|
2235
|
-
format: plan.format,
|
|
2236
|
-
targetId: tab.targetId,
|
|
2237
|
-
url: tab.url,
|
|
2238
|
-
blockedByDialog: true,
|
|
2239
|
-
...browserStateResponseFields(observedBrowserState),
|
|
2240
|
-
...plan.format === "aria" ? { nodes: [] } : {
|
|
2241
|
-
snapshot: "",
|
|
2242
|
-
refs: {}
|
|
2243
|
-
}
|
|
2244
|
-
});
|
|
2245
|
-
if (plan.format === "ai") {
|
|
2246
|
-
const roleSnapshotArgs = {
|
|
2247
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2248
|
-
targetId: tab.targetId,
|
|
2249
|
-
selector: plan.selectorValue,
|
|
2250
|
-
frameSelector: plan.frameSelectorValue,
|
|
2251
|
-
refsMode: plan.refsMode,
|
|
2252
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy,
|
|
2253
|
-
urls: plan.urls,
|
|
2254
|
-
options: {
|
|
2255
|
-
interactive: plan.interactive ?? void 0,
|
|
2256
|
-
compact: plan.compact ?? void 0,
|
|
2257
|
-
maxDepth: plan.depth ?? void 0
|
|
2258
|
-
}
|
|
2259
|
-
};
|
|
2260
|
-
const cdpRoleSnapshot = async () => {
|
|
2261
|
-
if (!tab.wsUrl) return null;
|
|
2262
|
-
if (plan.selectorValue || plan.frameSelectorValue) return null;
|
|
2263
|
-
return await snapshotRoleViaCdp({
|
|
2264
|
-
wsUrl: tab.wsUrl,
|
|
2265
|
-
urls: plan.urls,
|
|
2266
|
-
options: {
|
|
2267
|
-
interactive: plan.interactive ?? void 0,
|
|
2268
|
-
compact: plan.compact ?? void 0,
|
|
2269
|
-
maxDepth: plan.depth ?? void 0
|
|
2270
|
-
}
|
|
2271
|
-
});
|
|
2272
|
-
};
|
|
2273
|
-
const pw = await getPwAiModule();
|
|
2274
|
-
const snap = plan.wantsRoleSnapshot ? pw ? await pw.snapshotRoleViaPlaywright(roleSnapshotArgs).catch(async (err) => {
|
|
2275
|
-
const fallback = await cdpRoleSnapshot();
|
|
2276
|
-
if (fallback) return fallback;
|
|
2277
|
-
throw err;
|
|
2278
|
-
}) : await cdpRoleSnapshot() : pw ? await pw.snapshotAiViaPlaywright({
|
|
2279
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2280
|
-
targetId: tab.targetId,
|
|
2281
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy,
|
|
2282
|
-
urls: plan.urls,
|
|
2283
|
-
...typeof plan.resolvedMaxChars === "number" ? { maxChars: plan.resolvedMaxChars } : {}
|
|
2284
|
-
}) : await cdpRoleSnapshot();
|
|
2285
|
-
if (!snap) {
|
|
2286
|
-
await requirePwAi(res, "ai snapshot");
|
|
2287
|
-
return;
|
|
2288
|
-
}
|
|
2289
|
-
if (plan.labels) {
|
|
2290
|
-
if (!pw) return jsonError(res, 501, "Snapshot labels require Playwright.");
|
|
2291
|
-
const labeled = await pw.screenshotWithLabelsViaPlaywright({
|
|
2292
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2293
|
-
targetId: tab.targetId,
|
|
2294
|
-
refs: "refs" in snap ? snap.refs : {},
|
|
2295
|
-
type: "png"
|
|
2296
|
-
});
|
|
2297
|
-
const normalized = await normalizeBrowserScreenshot(labeled.buffer, {
|
|
2298
|
-
maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
|
|
2299
|
-
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES
|
|
2300
|
-
});
|
|
2301
|
-
await ensureMediaDir();
|
|
2302
|
-
const saved = await saveMediaBuffer(normalized.buffer, normalized.contentType ?? "image/png", "browser", DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES);
|
|
2303
|
-
const imageType = normalized.contentType?.includes("jpeg") ? "jpeg" : "png";
|
|
2304
|
-
return res.json({
|
|
2305
|
-
ok: true,
|
|
2306
|
-
format: plan.format,
|
|
2307
|
-
targetId: tab.targetId,
|
|
2308
|
-
url: tab.url,
|
|
2309
|
-
...browserStateResponseFields(observedBrowserState),
|
|
2310
|
-
labels: true,
|
|
2311
|
-
labelsCount: labeled.labels,
|
|
2312
|
-
labelsSkipped: labeled.skipped,
|
|
2313
|
-
imagePath: path.resolve(saved.path),
|
|
2314
|
-
imageType,
|
|
2315
|
-
...snap
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
return res.json({
|
|
2319
|
-
ok: true,
|
|
2320
|
-
format: plan.format,
|
|
2321
|
-
targetId: tab.targetId,
|
|
2322
|
-
url: tab.url,
|
|
2323
|
-
...browserStateResponseFields(observedBrowserState),
|
|
2324
|
-
...snap
|
|
2325
|
-
});
|
|
2326
|
-
}
|
|
2327
|
-
const usePlaywrightAriaSnapshot = shouldUsePlaywrightForAriaSnapshot({
|
|
2328
|
-
profile: profileCtx.profile,
|
|
2329
|
-
wsUrl: tab.wsUrl
|
|
2330
|
-
});
|
|
2331
|
-
const snap = usePlaywrightAriaSnapshot ? requirePwAi(res, "aria snapshot").then(async (pw) => {
|
|
2332
|
-
if (!pw) return null;
|
|
2333
|
-
return await pw.snapshotAriaViaPlaywright({
|
|
2334
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2335
|
-
targetId: tab.targetId,
|
|
2336
|
-
limit: plan.limit,
|
|
2337
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
2338
|
-
});
|
|
2339
|
-
}) : snapshotAria({
|
|
2340
|
-
wsUrl: tab.wsUrl ?? "",
|
|
2341
|
-
limit: plan.limit
|
|
2342
|
-
});
|
|
2343
|
-
const resolved = await Promise.resolve(snap);
|
|
2344
|
-
if (!resolved) return;
|
|
2345
|
-
if (!usePlaywrightAriaSnapshot) await pwModule?.storeAriaSnapshotRefsViaPlaywright?.({
|
|
2346
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
2347
|
-
targetId: tab.targetId,
|
|
2348
|
-
nodes: resolved.nodes
|
|
2349
|
-
});
|
|
2350
|
-
return res.json({
|
|
2351
|
-
ok: true,
|
|
2352
|
-
format: plan.format,
|
|
2353
|
-
targetId: tab.targetId,
|
|
2354
|
-
url: tab.url,
|
|
2355
|
-
...browserStateResponseFields(observedBrowserState),
|
|
2356
|
-
...resolved
|
|
2357
|
-
});
|
|
2358
|
-
} catch (err) {
|
|
2359
|
-
handleRouteError(ctx, res, err);
|
|
2360
|
-
}
|
|
2361
|
-
}));
|
|
2362
|
-
}
|
|
2363
|
-
//#endregion
|
|
2364
|
-
//#region extensions/browser/src/browser/routes/agent.storage.ts
|
|
2365
|
-
function readStringValue(value) {
|
|
2366
|
-
return typeof value === "string" ? value : void 0;
|
|
2367
|
-
}
|
|
2368
|
-
function normalizeOptionalString(value) {
|
|
2369
|
-
return readStringValue(value)?.trim() || void 0;
|
|
2370
|
-
}
|
|
2371
|
-
function parseStorageKind(raw) {
|
|
2372
|
-
if (raw === "local" || raw === "session") return raw;
|
|
2373
|
-
return null;
|
|
2374
|
-
}
|
|
2375
|
-
function parseStorageMutationRequest(kindParam, body) {
|
|
2376
|
-
return {
|
|
2377
|
-
kind: parseStorageKind(toStringOrEmpty(kindParam)),
|
|
2378
|
-
targetId: resolveTargetIdFromBody(body)
|
|
2379
|
-
};
|
|
2380
|
-
}
|
|
2381
|
-
function parseRequiredStorageMutationRequest(kindParam, body) {
|
|
2382
|
-
const parsed = parseStorageMutationRequest(kindParam, body);
|
|
2383
|
-
if (!parsed.kind) return null;
|
|
2384
|
-
return {
|
|
2385
|
-
kind: parsed.kind,
|
|
2386
|
-
targetId: parsed.targetId
|
|
2387
|
-
};
|
|
2388
|
-
}
|
|
2389
|
-
function parseStorageMutationOrRespond(res, kindParam, body) {
|
|
2390
|
-
const parsed = parseRequiredStorageMutationRequest(kindParam, body);
|
|
2391
|
-
if (!parsed) {
|
|
2392
|
-
jsonError(res, 400, "kind must be local|session");
|
|
2393
|
-
return null;
|
|
2394
|
-
}
|
|
2395
|
-
return parsed;
|
|
2396
|
-
}
|
|
2397
|
-
function parseStorageMutationFromRequest(req, res) {
|
|
2398
|
-
const body = readBody(req);
|
|
2399
|
-
const parsed = parseStorageMutationOrRespond(res, req.params.kind, body);
|
|
2400
|
-
if (!parsed) return null;
|
|
2401
|
-
return {
|
|
2402
|
-
body,
|
|
2403
|
-
parsed
|
|
2404
|
-
};
|
|
2405
|
-
}
|
|
2406
|
-
function registerBrowserAgentStorageRoutes(app, ctx) {
|
|
2407
|
-
app.get("/cookies", asyncBrowserRoute(async (req, res) => {
|
|
2408
|
-
await withPlaywrightRouteContext({
|
|
2409
|
-
req,
|
|
2410
|
-
res,
|
|
2411
|
-
ctx,
|
|
2412
|
-
targetId: resolveTargetIdFromQuery(req.query),
|
|
2413
|
-
feature: "cookies",
|
|
2414
|
-
enforceCurrentUrlAllowed: true,
|
|
2415
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2416
|
-
const result = await pw.cookiesGetViaPlaywright({
|
|
2417
|
-
cdpUrl,
|
|
2418
|
-
targetId: tab.targetId
|
|
2419
|
-
});
|
|
2420
|
-
res.json({
|
|
2421
|
-
ok: true,
|
|
2422
|
-
targetId: tab.targetId,
|
|
2423
|
-
...result
|
|
2424
|
-
});
|
|
2425
|
-
}
|
|
2426
|
-
});
|
|
2427
|
-
}));
|
|
2428
|
-
app.post("/cookies/set", asyncBrowserRoute(async (req, res) => {
|
|
2429
|
-
const body = readBody(req);
|
|
2430
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2431
|
-
const cookie = body.cookie && typeof body.cookie === "object" && !Array.isArray(body.cookie) ? body.cookie : null;
|
|
2432
|
-
if (!cookie) return jsonError(res, 400, "cookie is required");
|
|
2433
|
-
await withPlaywrightRouteContext({
|
|
2434
|
-
req,
|
|
2435
|
-
res,
|
|
2436
|
-
ctx,
|
|
2437
|
-
targetId,
|
|
2438
|
-
feature: "cookies set",
|
|
2439
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2440
|
-
await pw.cookiesSetViaPlaywright({
|
|
2441
|
-
cdpUrl,
|
|
2442
|
-
targetId: tab.targetId,
|
|
2443
|
-
cookie: {
|
|
2444
|
-
name: toStringOrEmpty(cookie.name),
|
|
2445
|
-
value: toStringOrEmpty(cookie.value),
|
|
2446
|
-
url: toStringOrEmpty(cookie.url) || void 0,
|
|
2447
|
-
domain: toStringOrEmpty(cookie.domain) || void 0,
|
|
2448
|
-
path: toStringOrEmpty(cookie.path) || void 0,
|
|
2449
|
-
expires: toNumber(cookie.expires) ?? void 0,
|
|
2450
|
-
httpOnly: toBoolean(cookie.httpOnly) ?? void 0,
|
|
2451
|
-
secure: toBoolean(cookie.secure) ?? void 0,
|
|
2452
|
-
sameSite: cookie.sameSite === "Lax" || cookie.sameSite === "None" || cookie.sameSite === "Strict" ? cookie.sameSite : void 0
|
|
2453
|
-
}
|
|
2454
|
-
});
|
|
2455
|
-
res.json({
|
|
2456
|
-
ok: true,
|
|
2457
|
-
targetId: tab.targetId
|
|
2458
|
-
});
|
|
2459
|
-
}
|
|
2460
|
-
});
|
|
2461
|
-
}));
|
|
2462
|
-
app.post("/cookies/clear", asyncBrowserRoute(async (req, res) => {
|
|
2463
|
-
await withPlaywrightRouteContext({
|
|
2464
|
-
req,
|
|
2465
|
-
res,
|
|
2466
|
-
ctx,
|
|
2467
|
-
targetId: resolveTargetIdFromBody(readBody(req)),
|
|
2468
|
-
feature: "cookies clear",
|
|
2469
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2470
|
-
await pw.cookiesClearViaPlaywright({
|
|
2471
|
-
cdpUrl,
|
|
2472
|
-
targetId: tab.targetId
|
|
2473
|
-
});
|
|
2474
|
-
res.json({
|
|
2475
|
-
ok: true,
|
|
2476
|
-
targetId: tab.targetId
|
|
2477
|
-
});
|
|
2478
|
-
}
|
|
2479
|
-
});
|
|
2480
|
-
}));
|
|
2481
|
-
app.get("/storage/:kind", asyncBrowserRoute(async (req, res) => {
|
|
2482
|
-
const kind = parseStorageKind(toStringOrEmpty(req.params.kind));
|
|
2483
|
-
if (!kind) return jsonError(res, 400, "kind must be local|session");
|
|
2484
|
-
const targetId = resolveTargetIdFromQuery(req.query);
|
|
2485
|
-
const key = toStringOrEmpty(req.query.key);
|
|
2486
|
-
await withPlaywrightRouteContext({
|
|
2487
|
-
req,
|
|
2488
|
-
res,
|
|
2489
|
-
ctx,
|
|
2490
|
-
targetId,
|
|
2491
|
-
feature: "storage get",
|
|
2492
|
-
enforceCurrentUrlAllowed: true,
|
|
2493
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2494
|
-
const result = await pw.storageGetViaPlaywright({
|
|
2495
|
-
cdpUrl,
|
|
2496
|
-
targetId: tab.targetId,
|
|
2497
|
-
kind,
|
|
2498
|
-
key: normalizeOptionalString(key)
|
|
2499
|
-
});
|
|
2500
|
-
res.json({
|
|
2501
|
-
ok: true,
|
|
2502
|
-
targetId: tab.targetId,
|
|
2503
|
-
...result
|
|
2504
|
-
});
|
|
2505
|
-
}
|
|
2506
|
-
});
|
|
2507
|
-
}));
|
|
2508
|
-
app.post("/storage/:kind/set", asyncBrowserRoute(async (req, res) => {
|
|
2509
|
-
const mutation = parseStorageMutationFromRequest(req, res);
|
|
2510
|
-
if (!mutation) return;
|
|
2511
|
-
const key = toStringOrEmpty(mutation.body.key);
|
|
2512
|
-
if (!key) return jsonError(res, 400, "key is required");
|
|
2513
|
-
const value = typeof mutation.body.value === "string" ? mutation.body.value : "";
|
|
2514
|
-
await withPlaywrightRouteContext({
|
|
2515
|
-
req,
|
|
2516
|
-
res,
|
|
2517
|
-
ctx,
|
|
2518
|
-
targetId: mutation.parsed.targetId,
|
|
2519
|
-
feature: "storage set",
|
|
2520
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2521
|
-
await pw.storageSetViaPlaywright({
|
|
2522
|
-
cdpUrl,
|
|
2523
|
-
targetId: tab.targetId,
|
|
2524
|
-
kind: mutation.parsed.kind,
|
|
2525
|
-
key,
|
|
2526
|
-
value
|
|
2527
|
-
});
|
|
2528
|
-
res.json({
|
|
2529
|
-
ok: true,
|
|
2530
|
-
targetId: tab.targetId
|
|
2531
|
-
});
|
|
2532
|
-
}
|
|
2533
|
-
});
|
|
2534
|
-
}));
|
|
2535
|
-
app.post("/storage/:kind/clear", asyncBrowserRoute(async (req, res) => {
|
|
2536
|
-
const mutation = parseStorageMutationFromRequest(req, res);
|
|
2537
|
-
if (!mutation) return;
|
|
2538
|
-
await withPlaywrightRouteContext({
|
|
2539
|
-
req,
|
|
2540
|
-
res,
|
|
2541
|
-
ctx,
|
|
2542
|
-
targetId: mutation.parsed.targetId,
|
|
2543
|
-
feature: "storage clear",
|
|
2544
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2545
|
-
await pw.storageClearViaPlaywright({
|
|
2546
|
-
cdpUrl,
|
|
2547
|
-
targetId: tab.targetId,
|
|
2548
|
-
kind: mutation.parsed.kind
|
|
2549
|
-
});
|
|
2550
|
-
res.json({
|
|
2551
|
-
ok: true,
|
|
2552
|
-
targetId: tab.targetId
|
|
2553
|
-
});
|
|
2554
|
-
}
|
|
2555
|
-
});
|
|
2556
|
-
}));
|
|
2557
|
-
app.post("/set/offline", asyncBrowserRoute(async (req, res) => {
|
|
2558
|
-
const body = readBody(req);
|
|
2559
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2560
|
-
const offline = toBoolean(body.offline);
|
|
2561
|
-
if (offline === void 0) return jsonError(res, 400, "offline is required");
|
|
2562
|
-
await withPlaywrightRouteContext({
|
|
2563
|
-
req,
|
|
2564
|
-
res,
|
|
2565
|
-
ctx,
|
|
2566
|
-
targetId,
|
|
2567
|
-
feature: "offline",
|
|
2568
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2569
|
-
await pw.setOfflineViaPlaywright({
|
|
2570
|
-
cdpUrl,
|
|
2571
|
-
targetId: tab.targetId,
|
|
2572
|
-
offline
|
|
2573
|
-
});
|
|
2574
|
-
res.json({
|
|
2575
|
-
ok: true,
|
|
2576
|
-
targetId: tab.targetId
|
|
2577
|
-
});
|
|
2578
|
-
}
|
|
2579
|
-
});
|
|
2580
|
-
}));
|
|
2581
|
-
app.post("/set/headers", asyncBrowserRoute(async (req, res) => {
|
|
2582
|
-
const body = readBody(req);
|
|
2583
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2584
|
-
const headers = body.headers && typeof body.headers === "object" && !Array.isArray(body.headers) ? body.headers : null;
|
|
2585
|
-
if (!headers) return jsonError(res, 400, "headers is required");
|
|
2586
|
-
const parsed = {};
|
|
2587
|
-
for (const [k, v] of Object.entries(headers)) if (typeof v === "string") parsed[k] = v;
|
|
2588
|
-
await withPlaywrightRouteContext({
|
|
2589
|
-
req,
|
|
2590
|
-
res,
|
|
2591
|
-
ctx,
|
|
2592
|
-
targetId,
|
|
2593
|
-
feature: "headers",
|
|
2594
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2595
|
-
await pw.setExtraHTTPHeadersViaPlaywright({
|
|
2596
|
-
cdpUrl,
|
|
2597
|
-
targetId: tab.targetId,
|
|
2598
|
-
headers: parsed
|
|
2599
|
-
});
|
|
2600
|
-
res.json({
|
|
2601
|
-
ok: true,
|
|
2602
|
-
targetId: tab.targetId
|
|
2603
|
-
});
|
|
2604
|
-
}
|
|
2605
|
-
});
|
|
2606
|
-
}));
|
|
2607
|
-
app.post("/set/credentials", asyncBrowserRoute(async (req, res) => {
|
|
2608
|
-
const body = readBody(req);
|
|
2609
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2610
|
-
const clear = toBoolean(body.clear) ?? false;
|
|
2611
|
-
const username = toStringOrEmpty(body.username) || void 0;
|
|
2612
|
-
const password = readStringValue(body.password);
|
|
2613
|
-
await withPlaywrightRouteContext({
|
|
2614
|
-
req,
|
|
2615
|
-
res,
|
|
2616
|
-
ctx,
|
|
2617
|
-
targetId,
|
|
2618
|
-
feature: "http credentials",
|
|
2619
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2620
|
-
await pw.setHttpCredentialsViaPlaywright({
|
|
2621
|
-
cdpUrl,
|
|
2622
|
-
targetId: tab.targetId,
|
|
2623
|
-
username,
|
|
2624
|
-
password,
|
|
2625
|
-
clear
|
|
2626
|
-
});
|
|
2627
|
-
res.json({
|
|
2628
|
-
ok: true,
|
|
2629
|
-
targetId: tab.targetId
|
|
2630
|
-
});
|
|
2631
|
-
}
|
|
2632
|
-
});
|
|
2633
|
-
}));
|
|
2634
|
-
app.post("/set/geolocation", asyncBrowserRoute(async (req, res) => {
|
|
2635
|
-
const body = readBody(req);
|
|
2636
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2637
|
-
const clear = toBoolean(body.clear) ?? false;
|
|
2638
|
-
const latitude = toNumber(body.latitude);
|
|
2639
|
-
const longitude = toNumber(body.longitude);
|
|
2640
|
-
const accuracy = toNumber(body.accuracy) ?? void 0;
|
|
2641
|
-
const origin = toStringOrEmpty(body.origin) || void 0;
|
|
2642
|
-
await withPlaywrightRouteContext({
|
|
2643
|
-
req,
|
|
2644
|
-
res,
|
|
2645
|
-
ctx,
|
|
2646
|
-
targetId,
|
|
2647
|
-
feature: "geolocation",
|
|
2648
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2649
|
-
await pw.setGeolocationViaPlaywright({
|
|
2650
|
-
cdpUrl,
|
|
2651
|
-
targetId: tab.targetId,
|
|
2652
|
-
latitude,
|
|
2653
|
-
longitude,
|
|
2654
|
-
accuracy,
|
|
2655
|
-
origin,
|
|
2656
|
-
clear
|
|
2657
|
-
});
|
|
2658
|
-
res.json({
|
|
2659
|
-
ok: true,
|
|
2660
|
-
targetId: tab.targetId
|
|
2661
|
-
});
|
|
2662
|
-
}
|
|
2663
|
-
});
|
|
2664
|
-
}));
|
|
2665
|
-
app.post("/set/media", asyncBrowserRoute(async (req, res) => {
|
|
2666
|
-
const body = readBody(req);
|
|
2667
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2668
|
-
const schemeRaw = toStringOrEmpty(body.colorScheme);
|
|
2669
|
-
const colorScheme = schemeRaw === "dark" || schemeRaw === "light" || schemeRaw === "no-preference" ? schemeRaw : schemeRaw === "none" ? null : void 0;
|
|
2670
|
-
if (colorScheme === void 0) return jsonError(res, 400, "colorScheme must be dark|light|no-preference|none");
|
|
2671
|
-
await withPlaywrightRouteContext({
|
|
2672
|
-
req,
|
|
2673
|
-
res,
|
|
2674
|
-
ctx,
|
|
2675
|
-
targetId,
|
|
2676
|
-
feature: "media emulation",
|
|
2677
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2678
|
-
await pw.emulateMediaViaPlaywright({
|
|
2679
|
-
cdpUrl,
|
|
2680
|
-
targetId: tab.targetId,
|
|
2681
|
-
colorScheme
|
|
2682
|
-
});
|
|
2683
|
-
res.json({
|
|
2684
|
-
ok: true,
|
|
2685
|
-
targetId: tab.targetId
|
|
2686
|
-
});
|
|
2687
|
-
}
|
|
2688
|
-
});
|
|
2689
|
-
}));
|
|
2690
|
-
app.post("/set/timezone", asyncBrowserRoute(async (req, res) => {
|
|
2691
|
-
const body = readBody(req);
|
|
2692
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2693
|
-
const timezoneId = toStringOrEmpty(body.timezoneId);
|
|
2694
|
-
if (!timezoneId) return jsonError(res, 400, "timezoneId is required");
|
|
2695
|
-
await withPlaywrightRouteContext({
|
|
2696
|
-
req,
|
|
2697
|
-
res,
|
|
2698
|
-
ctx,
|
|
2699
|
-
targetId,
|
|
2700
|
-
feature: "timezone",
|
|
2701
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2702
|
-
await pw.setTimezoneViaPlaywright({
|
|
2703
|
-
cdpUrl,
|
|
2704
|
-
targetId: tab.targetId,
|
|
2705
|
-
timezoneId
|
|
2706
|
-
});
|
|
2707
|
-
res.json({
|
|
2708
|
-
ok: true,
|
|
2709
|
-
targetId: tab.targetId
|
|
2710
|
-
});
|
|
2711
|
-
}
|
|
2712
|
-
});
|
|
2713
|
-
}));
|
|
2714
|
-
app.post("/set/locale", asyncBrowserRoute(async (req, res) => {
|
|
2715
|
-
const body = readBody(req);
|
|
2716
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2717
|
-
const locale = toStringOrEmpty(body.locale);
|
|
2718
|
-
if (!locale) return jsonError(res, 400, "locale is required");
|
|
2719
|
-
await withPlaywrightRouteContext({
|
|
2720
|
-
req,
|
|
2721
|
-
res,
|
|
2722
|
-
ctx,
|
|
2723
|
-
targetId,
|
|
2724
|
-
feature: "locale",
|
|
2725
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2726
|
-
await pw.setLocaleViaPlaywright({
|
|
2727
|
-
cdpUrl,
|
|
2728
|
-
targetId: tab.targetId,
|
|
2729
|
-
locale
|
|
2730
|
-
});
|
|
2731
|
-
res.json({
|
|
2732
|
-
ok: true,
|
|
2733
|
-
targetId: tab.targetId
|
|
2734
|
-
});
|
|
2735
|
-
}
|
|
2736
|
-
});
|
|
2737
|
-
}));
|
|
2738
|
-
app.post("/set/device", asyncBrowserRoute(async (req, res) => {
|
|
2739
|
-
const body = readBody(req);
|
|
2740
|
-
const targetId = resolveTargetIdFromBody(body);
|
|
2741
|
-
const name = toStringOrEmpty(body.name);
|
|
2742
|
-
if (!name) return jsonError(res, 400, "name is required");
|
|
2743
|
-
await withPlaywrightRouteContext({
|
|
2744
|
-
req,
|
|
2745
|
-
res,
|
|
2746
|
-
ctx,
|
|
2747
|
-
targetId,
|
|
2748
|
-
feature: "device emulation",
|
|
2749
|
-
run: async ({ cdpUrl, tab, pw }) => {
|
|
2750
|
-
await pw.setDeviceViaPlaywright({
|
|
2751
|
-
cdpUrl,
|
|
2752
|
-
targetId: tab.targetId,
|
|
2753
|
-
name
|
|
2754
|
-
});
|
|
2755
|
-
res.json({
|
|
2756
|
-
ok: true,
|
|
2757
|
-
targetId: tab.targetId
|
|
2758
|
-
});
|
|
2759
|
-
}
|
|
2760
|
-
});
|
|
2761
|
-
}));
|
|
2762
|
-
}
|
|
2763
|
-
//#endregion
|
|
2764
|
-
//#region extensions/browser/src/browser/routes/agent.ts
|
|
2765
|
-
function registerBrowserAgentRoutes(app, ctx) {
|
|
2766
|
-
registerBrowserAgentSnapshotRoutes(app, ctx);
|
|
2767
|
-
registerBrowserAgentActRoutes(app, ctx);
|
|
2768
|
-
registerBrowserAgentDebugRoutes(app, ctx);
|
|
2769
|
-
registerBrowserAgentStorageRoutes(app, ctx);
|
|
2770
|
-
}
|
|
2771
|
-
//#endregion
|
|
2772
|
-
//#region extensions/browser/src/browser/doctor.ts
|
|
2773
|
-
function buildBrowserDoctorReport(params) {
|
|
2774
|
-
const status = params.status;
|
|
2775
|
-
const checks = [];
|
|
2776
|
-
const transport = status.transport === "chrome-mcp" ? "chrome-mcp" : "cdp";
|
|
2777
|
-
checks.push({
|
|
2778
|
-
id: "plugin-enabled",
|
|
2779
|
-
label: "Browser plugin",
|
|
2780
|
-
status: status.enabled ? "pass" : "fail",
|
|
2781
|
-
summary: status.enabled ? "enabled" : "disabled",
|
|
2782
|
-
...status.enabled ? {} : { fixHint: "Enable the browser plugin and restart the Gateway." }
|
|
2783
|
-
});
|
|
2784
|
-
checks.push({
|
|
2785
|
-
id: "profile",
|
|
2786
|
-
label: "Profile",
|
|
2787
|
-
status: "pass",
|
|
2788
|
-
summary: `${status.profile ?? "daocore"} via ${transport}`
|
|
2789
|
-
});
|
|
2790
|
-
if (transport === "chrome-mcp") checks.push({
|
|
2791
|
-
id: "attach-target",
|
|
2792
|
-
label: "Existing browser attach",
|
|
2793
|
-
status: status.running ? "pass" : "fail",
|
|
2794
|
-
summary: status.running ? "Chrome MCP target is reachable" : "Chrome MCP target is not reachable",
|
|
2795
|
-
...status.running ? {} : { fixHint: "Keep the matching Chromium browser running, enable remote debugging in chrome://inspect, and accept the attach prompt." }
|
|
2796
|
-
});
|
|
2797
|
-
else {
|
|
2798
|
-
checks.push({
|
|
2799
|
-
id: "managed-executable",
|
|
2800
|
-
label: "Chromium executable",
|
|
2801
|
-
status: status.detectError ? "fail" : status.detectedExecutablePath ? "pass" : "warn",
|
|
2802
|
-
summary: status.detectError ? status.detectError : status.detectedExecutablePath ? `${status.detectedBrowser ?? "chromium"} at ${status.detectedExecutablePath}` : "No Chromium executable detected",
|
|
2803
|
-
...status.detectedExecutablePath || status.detectError ? {} : { fixHint: "Install Chrome/Chromium/Brave/Edge or set browser.executablePath." }
|
|
2804
|
-
});
|
|
2805
|
-
const platform = params.platform ?? process.platform;
|
|
2806
|
-
const env = params.env ?? process.env;
|
|
2807
|
-
const uid = params.uid ?? process.getuid?.();
|
|
2808
|
-
const missingDisplay = platform === "linux" && !status.headless && !env.DISPLAY && !env.WAYLAND_DISPLAY;
|
|
2809
|
-
if (status.headlessSource === "linux-display-fallback") checks.push({
|
|
2810
|
-
id: "headless-mode",
|
|
2811
|
-
label: "Headless mode",
|
|
2812
|
-
status: "pass",
|
|
2813
|
-
summary: "Linux no-display fallback selected headless mode"
|
|
2814
|
-
});
|
|
2815
|
-
if (missingDisplay) checks.push({
|
|
2816
|
-
id: "display",
|
|
2817
|
-
label: "Display",
|
|
2818
|
-
status: "warn",
|
|
2819
|
-
summary: `No DISPLAY or WAYLAND_DISPLAY is set while headed mode is selected (${status.headlessSource ?? "unknown"})`,
|
|
2820
|
-
fixHint: "Use a desktop session, Xvfb, set DAOCORE_BROWSER_HEADLESS=1, or remove the headed override."
|
|
2821
|
-
});
|
|
2822
|
-
if (platform === "linux" && uid === 0 && !status.noSandbox) checks.push({
|
|
2823
|
-
id: "linux-sandbox",
|
|
2824
|
-
label: "Linux sandbox",
|
|
2825
|
-
status: "warn",
|
|
2826
|
-
summary: "Gateway is running as root while browser.noSandbox is false",
|
|
2827
|
-
fixHint: "Set browser.noSandbox: true for container/root Chromium runtimes."
|
|
2828
|
-
});
|
|
2829
|
-
checks.push({
|
|
2830
|
-
id: "cdp-http",
|
|
2831
|
-
label: "CDP HTTP",
|
|
2832
|
-
status: status.cdpHttp ? "pass" : status.running ? "fail" : "info",
|
|
2833
|
-
summary: status.cdpHttp ? "CDP HTTP endpoint is reachable" : status.running ? "CDP HTTP endpoint is not reachable" : "Browser is not currently running",
|
|
2834
|
-
...status.cdpHttp || !status.running ? {} : { fixHint: "Run daocore browser start or inspect browser.cdpUrl/CDP port reachability." }
|
|
2835
|
-
});
|
|
2836
|
-
checks.push({
|
|
2837
|
-
id: "cdp-websocket",
|
|
2838
|
-
label: "CDP WebSocket",
|
|
2839
|
-
status: status.cdpReady ? "pass" : status.running ? "fail" : "info",
|
|
2840
|
-
summary: status.cdpReady ? "CDP WebSocket is reachable" : status.running ? "CDP WebSocket is not reachable" : "Browser is launchable but not running",
|
|
2841
|
-
...status.cdpReady || !status.running ? {} : { fixHint: "Check Chrome launch logs, stale locks, proxy env, and port conflicts." }
|
|
2842
|
-
});
|
|
2843
|
-
}
|
|
2844
|
-
return {
|
|
2845
|
-
ok: checks.every((check) => check.status !== "fail"),
|
|
2846
|
-
profile: status.profile ?? "daocore",
|
|
2847
|
-
transport,
|
|
2848
|
-
checks,
|
|
2849
|
-
status
|
|
2850
|
-
};
|
|
2851
|
-
}
|
|
2852
|
-
//#endregion
|
|
2853
|
-
//#region extensions/browser/src/browser/profiles-service.ts
|
|
2854
|
-
const HEX_COLOR_RE = /^#[0-9A-Fa-f]{6}$/;
|
|
2855
|
-
function createBrowserProfilesService(ctx) {
|
|
2856
|
-
const listProfiles = async () => {
|
|
2857
|
-
return await ctx.listProfiles();
|
|
2858
|
-
};
|
|
2859
|
-
const createProfile = async (params) => {
|
|
2860
|
-
const name = params.name.trim();
|
|
2861
|
-
const rawCdpUrl = normalizeOptionalString$4(params.cdpUrl);
|
|
2862
|
-
const rawUserDataDir = normalizeOptionalString$4(params.userDataDir);
|
|
2863
|
-
const normalizedUserDataDir = rawUserDataDir ? resolveUserPath(rawUserDataDir) : void 0;
|
|
2864
|
-
const driver = params.driver === "existing-session" ? "existing-session" : void 0;
|
|
2865
|
-
if (!isValidProfileName(name)) throw new BrowserValidationError("invalid profile name: use lowercase letters, numbers, and hyphens only");
|
|
2866
|
-
const state = ctx.state();
|
|
2867
|
-
if (name in state.resolved.profiles) throw new BrowserConflictError(`profile "${name}" already exists`);
|
|
2868
|
-
if (name in (getRuntimeConfig().browser?.profiles ?? {})) throw new BrowserConflictError(`profile "${name}" already exists`);
|
|
2869
|
-
const explicitProfileColor = params.color && HEX_COLOR_RE.test(params.color) ? params.color : void 0;
|
|
2870
|
-
let parsedCdpUrl;
|
|
2871
|
-
if (normalizedUserDataDir && driver !== "existing-session") throw new BrowserValidationError("driver=existing-session is required when userDataDir is provided");
|
|
2872
|
-
if (normalizedUserDataDir && !fs.existsSync(normalizedUserDataDir)) throw new BrowserValidationError(`browser user data directory not found: ${normalizedUserDataDir}`);
|
|
2873
|
-
if (rawCdpUrl) {
|
|
2874
|
-
if (driver === "existing-session") throw new BrowserValidationError("driver=existing-session does not accept cdpUrl; it attaches via the Chrome MCP auto-connect flow");
|
|
2875
|
-
let parsed;
|
|
2876
|
-
try {
|
|
2877
|
-
parsed = parseBrowserHttpUrl(rawCdpUrl, "browser.profiles.cdpUrl");
|
|
2878
|
-
await assertCdpEndpointAllowed(parsed.normalized, state.resolved.ssrfPolicy);
|
|
2879
|
-
} catch (err) {
|
|
2880
|
-
throw new BrowserValidationError(formatErrorMessage(err));
|
|
2881
|
-
}
|
|
2882
|
-
parsedCdpUrl = parsed.normalized;
|
|
2883
|
-
}
|
|
2884
|
-
const profileConfig = await createBrowserProfileConfig({
|
|
2885
|
-
name,
|
|
2886
|
-
resolved: state.resolved,
|
|
2887
|
-
...explicitProfileColor ? { color: explicitProfileColor } : {},
|
|
2888
|
-
...parsedCdpUrl ? { parsedCdpUrl } : {},
|
|
2889
|
-
...normalizedUserDataDir ? { userDataDir: normalizedUserDataDir } : {},
|
|
2890
|
-
...driver ? { driver } : {}
|
|
2891
|
-
});
|
|
2892
|
-
if (!profileConfig) throw new BrowserProfileNotFoundError(`profile "${name}" not found after creation`);
|
|
2893
|
-
state.resolved.profiles[name] = profileConfig;
|
|
2894
|
-
const resolved = resolveProfile(state.resolved, name);
|
|
2895
|
-
if (!resolved) throw new BrowserProfileNotFoundError(`profile "${name}" not found after creation`);
|
|
2896
|
-
const capabilities = getBrowserProfileCapabilities(resolved);
|
|
2897
|
-
return {
|
|
2898
|
-
ok: true,
|
|
2899
|
-
profile: name,
|
|
2900
|
-
transport: capabilities.usesChromeMcp ? "chrome-mcp" : "cdp",
|
|
2901
|
-
cdpPort: capabilities.usesChromeMcp ? null : resolved.cdpPort,
|
|
2902
|
-
cdpUrl: capabilities.usesChromeMcp ? null : resolved.cdpUrl,
|
|
2903
|
-
userDataDir: resolved.userDataDir ?? null,
|
|
2904
|
-
color: resolved.color,
|
|
2905
|
-
isRemote: !resolved.cdpIsLoopback
|
|
2906
|
-
};
|
|
2907
|
-
};
|
|
2908
|
-
const deleteProfile = async (nameRaw) => {
|
|
2909
|
-
const name = nameRaw.trim();
|
|
2910
|
-
if (!name) throw new BrowserValidationError("profile name is required");
|
|
2911
|
-
if (!isValidProfileName(name)) throw new BrowserValidationError("invalid profile name");
|
|
2912
|
-
const state = ctx.state();
|
|
2913
|
-
const cfg = getRuntimeConfig();
|
|
2914
|
-
const profiles = cfg.browser?.profiles ?? {};
|
|
2915
|
-
if (name === (cfg.browser?.defaultProfile ?? state.resolved.defaultProfile)) throw new BrowserValidationError(`cannot delete the default profile "${name}"; change browser.defaultProfile first`);
|
|
2916
|
-
if (!(name in profiles)) throw new BrowserProfileNotFoundError(`profile "${name}" not found`);
|
|
2917
|
-
let deleted = false;
|
|
2918
|
-
const resolved = resolveProfile(state.resolved, name);
|
|
2919
|
-
if (resolved?.cdpIsLoopback && resolved.driver === "daocore") {
|
|
2920
|
-
try {
|
|
2921
|
-
await ctx.forProfile(name).stopRunningBrowser();
|
|
2922
|
-
} catch {}
|
|
2923
|
-
const userDataDir = resolveDaoCoreUserDataDir(name);
|
|
2924
|
-
const profileDir = path.dirname(userDataDir);
|
|
2925
|
-
if (fs.existsSync(profileDir)) {
|
|
2926
|
-
await movePathToTrash(profileDir);
|
|
2927
|
-
deleted = true;
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
await deleteBrowserProfileConfig(name);
|
|
2931
|
-
delete state.resolved.profiles[name];
|
|
2932
|
-
state.profiles.delete(name);
|
|
2933
|
-
return {
|
|
2934
|
-
ok: true,
|
|
2935
|
-
profile: name,
|
|
2936
|
-
deleted
|
|
2937
|
-
};
|
|
2938
|
-
};
|
|
2939
|
-
return {
|
|
2940
|
-
listProfiles,
|
|
2941
|
-
createProfile,
|
|
2942
|
-
deleteProfile
|
|
2943
|
-
};
|
|
2944
|
-
}
|
|
2945
|
-
//#endregion
|
|
2946
|
-
//#region extensions/browser/src/browser/routes/basic.ts
|
|
2947
|
-
const STATUS_CDP_HTTP_TIMEOUT_MS = 300;
|
|
2948
|
-
const STATUS_CDP_TRANSPORT_TIMEOUT_MS = 600;
|
|
2949
|
-
const STATUS_CHROME_MCP_TOTAL_TIMEOUT_MS = 7e3;
|
|
2950
|
-
const STATUS_CHROME_MCP_TRANSPORT_TIMEOUT_MS = 5e3;
|
|
2951
|
-
function remainingChromeMcpStatusTimeoutMs(startedAtMs) {
|
|
2952
|
-
return Math.max(1, STATUS_CHROME_MCP_TOTAL_TIMEOUT_MS - (Date.now() - startedAtMs));
|
|
2953
|
-
}
|
|
2954
|
-
async function probeChromeMcpPageReady(profileCtx, timeoutMs) {
|
|
2955
|
-
const abort = new AbortController();
|
|
2956
|
-
const timer = setTimeout(() => {
|
|
2957
|
-
abort.abort(/* @__PURE__ */ new Error(`Chrome MCP page-readiness probe timed out after ${timeoutMs}ms.`));
|
|
2958
|
-
}, timeoutMs);
|
|
2959
|
-
try {
|
|
2960
|
-
return await profileCtx.isReachable(timeoutMs, {
|
|
2961
|
-
ephemeral: true,
|
|
2962
|
-
signal: abort.signal
|
|
2963
|
-
});
|
|
2964
|
-
} catch {
|
|
2965
|
-
return false;
|
|
2966
|
-
} finally {
|
|
2967
|
-
clearTimeout(timer);
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
function handleBrowserRouteError(res, err) {
|
|
2971
|
-
const mapped = toBrowserErrorResponse(err);
|
|
2972
|
-
if (mapped) return jsonError(res, mapped.status, mapped.message);
|
|
2973
|
-
jsonError(res, 500, String(err));
|
|
2974
|
-
}
|
|
2975
|
-
async function withBasicProfileRoute(params) {
|
|
2976
|
-
const profileCtx = resolveProfileContext(params.req, params.res, params.ctx);
|
|
2977
|
-
if (!profileCtx) return;
|
|
2978
|
-
try {
|
|
2979
|
-
await params.run(profileCtx);
|
|
2980
|
-
} catch (err) {
|
|
2981
|
-
return handleBrowserRouteError(params.res, err);
|
|
2982
|
-
}
|
|
2983
|
-
}
|
|
2984
|
-
async function withProfilesServiceMutation(params) {
|
|
2985
|
-
try {
|
|
2986
|
-
const service = createBrowserProfilesService(params.ctx);
|
|
2987
|
-
const result = await params.run(service);
|
|
2988
|
-
params.res.json(result);
|
|
2989
|
-
} catch (err) {
|
|
2990
|
-
return handleBrowserRouteError(params.res, err);
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2993
|
-
async function buildBrowserStatus(req, ctx) {
|
|
2994
|
-
let current;
|
|
2995
|
-
try {
|
|
2996
|
-
current = ctx.state();
|
|
2997
|
-
} catch {
|
|
2998
|
-
throw new BrowserError("browser server not started", 503);
|
|
2999
|
-
}
|
|
3000
|
-
const profileCtx = getProfileContext(req, ctx);
|
|
3001
|
-
if ("error" in profileCtx) throw new BrowserError(profileCtx.error, profileCtx.status);
|
|
3002
|
-
const capabilities = getBrowserProfileCapabilities(profileCtx.profile);
|
|
3003
|
-
const [cdpHttp, cdpReady, pageReady] = capabilities.usesChromeMcp ? await (async () => {
|
|
3004
|
-
const statusStartedAtMs = Date.now();
|
|
3005
|
-
const transportReady = await profileCtx.isTransportAvailable(STATUS_CHROME_MCP_TRANSPORT_TIMEOUT_MS);
|
|
3006
|
-
if (!transportReady) return [
|
|
3007
|
-
false,
|
|
3008
|
-
false,
|
|
3009
|
-
false
|
|
3010
|
-
];
|
|
3011
|
-
return [
|
|
3012
|
-
transportReady,
|
|
3013
|
-
transportReady,
|
|
3014
|
-
await probeChromeMcpPageReady(profileCtx, remainingChromeMcpStatusTimeoutMs(statusStartedAtMs))
|
|
3015
|
-
];
|
|
3016
|
-
})() : await (async () => {
|
|
3017
|
-
const [http, ready] = await Promise.all([profileCtx.isHttpReachable(STATUS_CDP_HTTP_TIMEOUT_MS), profileCtx.isTransportAvailable(STATUS_CDP_TRANSPORT_TIMEOUT_MS)]);
|
|
3018
|
-
return [
|
|
3019
|
-
http,
|
|
3020
|
-
ready,
|
|
3021
|
-
ready
|
|
3022
|
-
];
|
|
3023
|
-
})();
|
|
3024
|
-
const profileState = current.profiles.get(profileCtx.profile.name);
|
|
3025
|
-
let detectedBrowser = null;
|
|
3026
|
-
let detectedExecutablePath = null;
|
|
3027
|
-
let detectError = null;
|
|
3028
|
-
try {
|
|
3029
|
-
const detected = resolveBrowserExecutableForPlatform(current.resolved, process.platform);
|
|
3030
|
-
if (detected) {
|
|
3031
|
-
detectedBrowser = detected.kind;
|
|
3032
|
-
detectedExecutablePath = detected.path;
|
|
3033
|
-
}
|
|
3034
|
-
} catch (err) {
|
|
3035
|
-
detectError = String(err);
|
|
3036
|
-
}
|
|
3037
|
-
const configuredHeadlessMode = resolveManagedBrowserHeadlessMode(current.resolved, profileCtx.profile);
|
|
3038
|
-
const headlessMode = typeof profileState?.running?.headless === "boolean" ? {
|
|
3039
|
-
headless: profileState.running.headless,
|
|
3040
|
-
source: profileState.running.headlessSource ?? configuredHeadlessMode.source
|
|
3041
|
-
} : configuredHeadlessMode;
|
|
3042
|
-
return {
|
|
3043
|
-
enabled: current.resolved.enabled,
|
|
3044
|
-
profile: profileCtx.profile.name,
|
|
3045
|
-
driver: profileCtx.profile.driver,
|
|
3046
|
-
transport: capabilities.usesChromeMcp ? "chrome-mcp" : "cdp",
|
|
3047
|
-
running: cdpReady,
|
|
3048
|
-
cdpReady,
|
|
3049
|
-
cdpHttp,
|
|
3050
|
-
pageReady,
|
|
3051
|
-
pid: capabilities.usesChromeMcp ? getChromeMcpPid(profileCtx.profile.name) : profileState?.running?.pid ?? null,
|
|
3052
|
-
cdpPort: capabilities.usesChromeMcp ? null : profileCtx.profile.cdpPort,
|
|
3053
|
-
cdpUrl: capabilities.usesChromeMcp ? null : redactCdpUrl(profileCtx.profile.cdpUrl) ?? null,
|
|
3054
|
-
chosenBrowser: profileState?.running?.exe.kind ?? null,
|
|
3055
|
-
detectedBrowser,
|
|
3056
|
-
detectedExecutablePath,
|
|
3057
|
-
detectError,
|
|
3058
|
-
userDataDir: profileState?.running?.userDataDir ?? profileCtx.profile.userDataDir ?? null,
|
|
3059
|
-
color: profileCtx.profile.color,
|
|
3060
|
-
headless: headlessMode.headless,
|
|
3061
|
-
headlessSource: headlessMode.source,
|
|
3062
|
-
noSandbox: current.resolved.noSandbox,
|
|
3063
|
-
executablePath: profileCtx.profile.executablePath ?? null,
|
|
3064
|
-
attachOnly: profileCtx.profile.attachOnly
|
|
3065
|
-
};
|
|
3066
|
-
}
|
|
3067
|
-
async function runBrowserLiveProbe(req, ctx) {
|
|
3068
|
-
const profileCtx = getProfileContext(req, ctx);
|
|
3069
|
-
if ("error" in profileCtx) return {
|
|
3070
|
-
id: "live-snapshot",
|
|
3071
|
-
label: "Live snapshot",
|
|
3072
|
-
status: "fail",
|
|
3073
|
-
summary: profileCtx.error
|
|
3074
|
-
};
|
|
3075
|
-
const capabilities = getBrowserProfileCapabilities(profileCtx.profile);
|
|
3076
|
-
try {
|
|
3077
|
-
const tab = await profileCtx.ensureTabAvailable();
|
|
3078
|
-
if (capabilities.usesChromeMcp) {
|
|
3079
|
-
const { takeChromeMcpSnapshot } = await import("./chrome-mcp-t4jCw9ZG.js");
|
|
3080
|
-
await takeChromeMcpSnapshot({
|
|
3081
|
-
profileName: profileCtx.profile.name,
|
|
3082
|
-
profile: profileCtx.profile,
|
|
3083
|
-
targetId: tab.targetId
|
|
3084
|
-
});
|
|
3085
|
-
return {
|
|
3086
|
-
id: "live-snapshot",
|
|
3087
|
-
label: "Live snapshot",
|
|
3088
|
-
status: "pass",
|
|
3089
|
-
summary: `Chrome MCP snapshot succeeded on ${tab.suggestedTargetId ?? tab.targetId}`
|
|
3090
|
-
};
|
|
3091
|
-
}
|
|
3092
|
-
if (!tab.wsUrl) return {
|
|
3093
|
-
id: "live-snapshot",
|
|
3094
|
-
label: "Live snapshot",
|
|
3095
|
-
status: "warn",
|
|
3096
|
-
summary: "No per-tab CDP WebSocket available for the lightweight live snapshot probe"
|
|
3097
|
-
};
|
|
3098
|
-
const snap = await snapshotAria({
|
|
3099
|
-
wsUrl: tab.wsUrl,
|
|
3100
|
-
limit: 25
|
|
3101
|
-
});
|
|
3102
|
-
return {
|
|
3103
|
-
id: "live-snapshot",
|
|
3104
|
-
label: "Live snapshot",
|
|
3105
|
-
status: snap.nodes.length > 0 ? "pass" : "warn",
|
|
3106
|
-
summary: snap.nodes.length > 0 ? `CDP accessibility snapshot returned ${snap.nodes.length} nodes on ${tab.suggestedTargetId ?? tab.targetId}` : `CDP accessibility snapshot returned no nodes on ${tab.suggestedTargetId ?? tab.targetId}`
|
|
3107
|
-
};
|
|
3108
|
-
} catch (err) {
|
|
3109
|
-
return {
|
|
3110
|
-
id: "live-snapshot",
|
|
3111
|
-
label: "Live snapshot",
|
|
3112
|
-
status: "fail",
|
|
3113
|
-
summary: String(err),
|
|
3114
|
-
fixHint: "Run daocore browser start, then retry with daocore browser doctor --deep."
|
|
3115
|
-
};
|
|
3116
|
-
}
|
|
3117
|
-
}
|
|
3118
|
-
function hasQueryKey(query, key) {
|
|
3119
|
-
return Object.prototype.hasOwnProperty.call(query ?? {}, key);
|
|
3120
|
-
}
|
|
3121
|
-
function parseHeadlessStartOverride(params) {
|
|
3122
|
-
if (!hasQueryKey(params.req.query, "headless")) return { ok: true };
|
|
3123
|
-
const headless = toBoolean(params.req.query.headless);
|
|
3124
|
-
if (typeof headless !== "boolean") {
|
|
3125
|
-
jsonError(params.res, 400, "Invalid headless value. Use \"true\" or \"false\".");
|
|
3126
|
-
return { ok: false };
|
|
3127
|
-
}
|
|
3128
|
-
const capabilities = getBrowserProfileCapabilities(params.profileCtx.profile);
|
|
3129
|
-
if (params.profileCtx.profile.driver !== "daocore" || params.profileCtx.profile.attachOnly || capabilities.isRemote) {
|
|
3130
|
-
jsonError(params.res, 400, `Headless start override is only supported for locally launched daocore profiles. Profile "${params.profileCtx.profile.name}" is attach-only, remote, or existing-session.`);
|
|
3131
|
-
return { ok: false };
|
|
3132
|
-
}
|
|
3133
|
-
return {
|
|
3134
|
-
ok: true,
|
|
3135
|
-
headless
|
|
3136
|
-
};
|
|
3137
|
-
}
|
|
3138
|
-
function registerBrowserBasicRoutes(app, ctx) {
|
|
3139
|
-
app.get("/profiles", asyncBrowserRoute(async (_req, res) => {
|
|
3140
|
-
try {
|
|
3141
|
-
const profiles = await createBrowserProfilesService(ctx).listProfiles();
|
|
3142
|
-
res.json({ profiles });
|
|
3143
|
-
} catch (err) {
|
|
3144
|
-
jsonError(res, 500, String(err));
|
|
3145
|
-
}
|
|
3146
|
-
}));
|
|
3147
|
-
app.get("/", asyncBrowserRoute(async (req, res) => {
|
|
3148
|
-
try {
|
|
3149
|
-
res.json(await buildBrowserStatus(req, ctx));
|
|
3150
|
-
} catch (err) {
|
|
3151
|
-
const mapped = toBrowserErrorResponse(err);
|
|
3152
|
-
if (mapped) return jsonError(res, mapped.status, mapped.message);
|
|
3153
|
-
jsonError(res, 500, String(err));
|
|
3154
|
-
}
|
|
3155
|
-
}));
|
|
3156
|
-
app.get("/doctor", asyncBrowserRoute(async (req, res) => {
|
|
3157
|
-
try {
|
|
3158
|
-
const report = buildBrowserDoctorReport({ status: await buildBrowserStatus(req, ctx) });
|
|
3159
|
-
if (toBoolean(req.query.deep) === true || toBoolean(req.query.live) === true) {
|
|
3160
|
-
report.checks.push(await runBrowserLiveProbe(req, ctx));
|
|
3161
|
-
report.ok = report.checks.every((check) => check.status !== "fail");
|
|
3162
|
-
}
|
|
3163
|
-
res.json(report);
|
|
3164
|
-
} catch (err) {
|
|
3165
|
-
const mapped = toBrowserErrorResponse(err);
|
|
3166
|
-
if (mapped) return jsonError(res, mapped.status, mapped.message);
|
|
3167
|
-
jsonError(res, 500, String(err));
|
|
3168
|
-
}
|
|
3169
|
-
}));
|
|
3170
|
-
app.post("/start", asyncBrowserRoute(async (req, res) => {
|
|
3171
|
-
await withBasicProfileRoute({
|
|
3172
|
-
req,
|
|
3173
|
-
res,
|
|
3174
|
-
ctx,
|
|
3175
|
-
run: async (profileCtx) => {
|
|
3176
|
-
const headlessOverride = parseHeadlessStartOverride({
|
|
3177
|
-
req,
|
|
3178
|
-
res,
|
|
3179
|
-
profileCtx
|
|
3180
|
-
});
|
|
3181
|
-
if (!headlessOverride.ok) return;
|
|
3182
|
-
await profileCtx.ensureBrowserAvailable({ headless: headlessOverride.headless });
|
|
3183
|
-
res.json({
|
|
3184
|
-
ok: true,
|
|
3185
|
-
profile: profileCtx.profile.name
|
|
3186
|
-
});
|
|
3187
|
-
}
|
|
3188
|
-
});
|
|
3189
|
-
}));
|
|
3190
|
-
app.post("/stop", asyncBrowserRoute(async (req, res) => {
|
|
3191
|
-
await withBasicProfileRoute({
|
|
3192
|
-
req,
|
|
3193
|
-
res,
|
|
3194
|
-
ctx,
|
|
3195
|
-
run: async (profileCtx) => {
|
|
3196
|
-
const result = await profileCtx.stopRunningBrowser();
|
|
3197
|
-
res.json({
|
|
3198
|
-
ok: true,
|
|
3199
|
-
stopped: result.stopped,
|
|
3200
|
-
profile: profileCtx.profile.name
|
|
3201
|
-
});
|
|
3202
|
-
}
|
|
3203
|
-
});
|
|
3204
|
-
}));
|
|
3205
|
-
app.post("/reset-profile", asyncBrowserRoute(async (req, res) => {
|
|
3206
|
-
await withBasicProfileRoute({
|
|
3207
|
-
req,
|
|
3208
|
-
res,
|
|
3209
|
-
ctx,
|
|
3210
|
-
run: async (profileCtx) => {
|
|
3211
|
-
const result = await profileCtx.resetProfile();
|
|
3212
|
-
res.json({
|
|
3213
|
-
ok: true,
|
|
3214
|
-
profile: profileCtx.profile.name,
|
|
3215
|
-
...result
|
|
3216
|
-
});
|
|
3217
|
-
}
|
|
3218
|
-
});
|
|
3219
|
-
}));
|
|
3220
|
-
app.post("/profiles/create", asyncBrowserRoute(async (req, res) => {
|
|
3221
|
-
const name = toStringOrEmpty(req.body?.name);
|
|
3222
|
-
const color = toStringOrEmpty(req.body?.color);
|
|
3223
|
-
const cdpUrl = toStringOrEmpty(req.body?.cdpUrl);
|
|
3224
|
-
const userDataDir = toStringOrEmpty(req.body?.userDataDir);
|
|
3225
|
-
const driver = toStringOrEmpty(req.body?.driver);
|
|
3226
|
-
if (!name) return jsonError(res, 400, "name is required");
|
|
3227
|
-
if (driver && driver !== "daocore" && driver !== "clawd" && driver !== "existing-session") return jsonError(res, 400, `unsupported profile driver "${driver}"; use "daocore", "clawd", or "existing-session"`);
|
|
3228
|
-
await withProfilesServiceMutation({
|
|
3229
|
-
res,
|
|
3230
|
-
ctx,
|
|
3231
|
-
run: async (service) => await service.createProfile({
|
|
3232
|
-
name,
|
|
3233
|
-
color: color || void 0,
|
|
3234
|
-
cdpUrl: cdpUrl || void 0,
|
|
3235
|
-
userDataDir: userDataDir || void 0,
|
|
3236
|
-
driver: driver === "existing-session" ? "existing-session" : driver === "daocore" || driver === "clawd" ? "daocore" : void 0
|
|
3237
|
-
})
|
|
3238
|
-
});
|
|
3239
|
-
}));
|
|
3240
|
-
app.delete("/profiles/:name", asyncBrowserRoute(async (req, res) => {
|
|
3241
|
-
const name = toStringOrEmpty(req.params.name);
|
|
3242
|
-
if (!name) return jsonError(res, 400, "profile name is required");
|
|
3243
|
-
await withProfilesServiceMutation({
|
|
3244
|
-
res,
|
|
3245
|
-
ctx,
|
|
3246
|
-
run: async (service) => await service.deleteProfile(name)
|
|
3247
|
-
});
|
|
3248
|
-
}));
|
|
3249
|
-
}
|
|
3250
|
-
//#endregion
|
|
3251
|
-
//#region extensions/browser/src/browser/routes/permissions.ts
|
|
3252
|
-
const permissionRouteDeps = { getPwAiModule: getPwAiModule$1 };
|
|
3253
|
-
function readOrigin(raw) {
|
|
3254
|
-
const value = toStringOrEmpty(raw);
|
|
3255
|
-
if (!value) return null;
|
|
3256
|
-
try {
|
|
3257
|
-
const parsed = new URL(value);
|
|
3258
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
3259
|
-
return parsed.origin;
|
|
3260
|
-
} catch {
|
|
3261
|
-
return null;
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
function readPermissions(raw) {
|
|
3265
|
-
if (!Array.isArray(raw)) return null;
|
|
3266
|
-
const permissions = raw.map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
3267
|
-
if (permissions.length !== raw.length) return null;
|
|
3268
|
-
return [...new Set(permissions)];
|
|
3269
|
-
}
|
|
3270
|
-
async function grantPermissions(params) {
|
|
3271
|
-
const allPermissions = [...new Set([...params.requiredPermissions, ...params.optionalPermissions])];
|
|
3272
|
-
const playwrightRequiredPermissions = params.requiredPermissions.map(toPlaywrightPermission);
|
|
3273
|
-
if (playwrightRequiredPermissions.every((value) => Boolean(value)) && params.requiredPermissions.length > 0) {
|
|
3274
|
-
const pw = await permissionRouteDeps.getPwAiModule({ mode: "soft" });
|
|
3275
|
-
if (pw) try {
|
|
3276
|
-
await (await pw.getPageForTargetId({
|
|
3277
|
-
cdpUrl: params.profileCtx.profile.cdpUrl,
|
|
3278
|
-
targetId: params.targetId,
|
|
3279
|
-
ssrfPolicy: params.ssrfPolicy
|
|
3280
|
-
})).context().grantPermissions(playwrightRequiredPermissions, { origin: params.origin });
|
|
3281
|
-
return {
|
|
3282
|
-
grantedPermissions: params.requiredPermissions,
|
|
3283
|
-
unsupportedPermissions: params.optionalPermissions,
|
|
3284
|
-
grantMethod: "playwright"
|
|
3285
|
-
};
|
|
3286
|
-
} catch {}
|
|
3287
|
-
}
|
|
3288
|
-
let unsupportedPermissions = [];
|
|
3289
|
-
await withCdpSocket(params.wsUrl, async (send) => {
|
|
3290
|
-
try {
|
|
3291
|
-
await send("Browser.grantPermissions", {
|
|
3292
|
-
origin: params.origin,
|
|
3293
|
-
permissions: allPermissions
|
|
3294
|
-
});
|
|
3295
|
-
return;
|
|
3296
|
-
} catch (error) {
|
|
3297
|
-
if (params.optionalPermissions.length === 0) throw error;
|
|
3298
|
-
}
|
|
3299
|
-
await send("Browser.grantPermissions", {
|
|
3300
|
-
origin: params.origin,
|
|
3301
|
-
permissions: params.requiredPermissions
|
|
3302
|
-
});
|
|
3303
|
-
unsupportedPermissions = params.optionalPermissions;
|
|
3304
|
-
}, { commandTimeoutMs: params.timeoutMs });
|
|
3305
|
-
return {
|
|
3306
|
-
grantedPermissions: allPermissions.filter((value) => !unsupportedPermissions.includes(value)),
|
|
3307
|
-
unsupportedPermissions,
|
|
3308
|
-
grantMethod: "cdp"
|
|
3309
|
-
};
|
|
3310
|
-
}
|
|
3311
|
-
function toPlaywrightPermission(permission) {
|
|
3312
|
-
switch (permission) {
|
|
3313
|
-
case "audioCapture": return "microphone";
|
|
3314
|
-
case "videoCapture": return "camera";
|
|
3315
|
-
default: return;
|
|
3316
|
-
}
|
|
3317
|
-
}
|
|
3318
|
-
function registerBrowserPermissionRoutes(app, ctx) {
|
|
3319
|
-
app.post("/permissions/grant", asyncBrowserRoute(async (req, res) => {
|
|
3320
|
-
const profileCtx = getProfileContext(req, ctx);
|
|
3321
|
-
if ("error" in profileCtx) return jsonError(res, profileCtx.status, profileCtx.error);
|
|
3322
|
-
const body = req.body ?? {};
|
|
3323
|
-
const origin = readOrigin(body.origin);
|
|
3324
|
-
if (!origin) return jsonError(res, 400, "origin must be an http(s) origin");
|
|
3325
|
-
const requiredPermissions = readPermissions(body.permissions);
|
|
3326
|
-
if (!requiredPermissions || requiredPermissions.length === 0) return jsonError(res, 400, "permissions must be a non-empty string array");
|
|
3327
|
-
const optionalPermissions = readPermissions(body.optionalPermissions ?? []) ?? [];
|
|
3328
|
-
const targetId = toStringOrEmpty(body.targetId) || void 0;
|
|
3329
|
-
const timeoutMs = Math.max(1e3, toNumber(body.timeoutMs) ?? 5e3);
|
|
3330
|
-
try {
|
|
3331
|
-
await profileCtx.ensureBrowserAvailable();
|
|
3332
|
-
const wsUrl = await getChromeWebSocketUrl(profileCtx.profile.cdpUrl, timeoutMs, ctx.state().resolved.ssrfPolicy);
|
|
3333
|
-
if (!wsUrl) return jsonError(res, 409, "browser CDP WebSocket unavailable");
|
|
3334
|
-
const granted = await grantPermissions({
|
|
3335
|
-
profileCtx,
|
|
3336
|
-
targetId,
|
|
3337
|
-
wsUrl,
|
|
3338
|
-
origin,
|
|
3339
|
-
requiredPermissions,
|
|
3340
|
-
optionalPermissions,
|
|
3341
|
-
timeoutMs,
|
|
3342
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
3343
|
-
});
|
|
3344
|
-
return res.json({
|
|
3345
|
-
ok: true,
|
|
3346
|
-
origin,
|
|
3347
|
-
...granted
|
|
3348
|
-
});
|
|
3349
|
-
} catch (error) {
|
|
3350
|
-
return jsonError(res, 500, error instanceof Error ? error.message : String(error));
|
|
3351
|
-
}
|
|
3352
|
-
}));
|
|
3353
|
-
}
|
|
3354
|
-
//#endregion
|
|
3355
|
-
//#region extensions/browser/src/browser/routes/tabs.ts
|
|
3356
|
-
function resolveTabsProfileContext(req, res, ctx) {
|
|
3357
|
-
const profileCtx = getProfileContext(req, ctx);
|
|
3358
|
-
if ("error" in profileCtx) {
|
|
3359
|
-
jsonError(res, profileCtx.status, profileCtx.error);
|
|
3360
|
-
return null;
|
|
3361
|
-
}
|
|
3362
|
-
return profileCtx;
|
|
3363
|
-
}
|
|
3364
|
-
function browserNavigationPolicyForProfile(ctx, profileCtx) {
|
|
3365
|
-
return withBrowserNavigationPolicy(ctx.state().resolved.ssrfPolicy, { browserProxyMode: resolveBrowserNavigationProxyMode({
|
|
3366
|
-
resolved: ctx.state().resolved,
|
|
3367
|
-
profile: profileCtx.profile
|
|
3368
|
-
}) });
|
|
3369
|
-
}
|
|
3370
|
-
function handleTabsRouteError(ctx, res, err, opts) {
|
|
3371
|
-
if (opts?.mapTabError) {
|
|
3372
|
-
const mapped = ctx.mapTabError(err);
|
|
3373
|
-
if (mapped) return jsonError(res, mapped.status, mapped.message);
|
|
3374
|
-
}
|
|
3375
|
-
return jsonError(res, 500, String(err));
|
|
3376
|
-
}
|
|
3377
|
-
async function withTabsProfileRoute(params) {
|
|
3378
|
-
const profileCtx = resolveTabsProfileContext(params.req, params.res, params.ctx);
|
|
3379
|
-
if (!profileCtx) return;
|
|
3380
|
-
try {
|
|
3381
|
-
await params.run(profileCtx);
|
|
3382
|
-
} catch (err) {
|
|
3383
|
-
handleTabsRouteError(params.ctx, params.res, err, { mapTabError: params.mapTabError });
|
|
3384
|
-
}
|
|
3385
|
-
}
|
|
3386
|
-
async function ensureBrowserRunning(profileCtx, res) {
|
|
3387
|
-
if (!await profileCtx.isReachable(300)) {
|
|
3388
|
-
jsonError(res, new BrowserProfileUnavailableError("browser not running").status, "browser not running");
|
|
3389
|
-
return false;
|
|
3390
|
-
}
|
|
3391
|
-
return true;
|
|
3392
|
-
}
|
|
3393
|
-
async function redactBlockedTabUrls(params) {
|
|
3394
|
-
const ssrfPolicyOpts = withBrowserNavigationPolicy(params.ssrfPolicy);
|
|
3395
|
-
if (!ssrfPolicyOpts.ssrfPolicy) return params.tabs;
|
|
3396
|
-
const redactedTabs = [];
|
|
3397
|
-
for (const tab of params.tabs) try {
|
|
3398
|
-
await assertBrowserNavigationResultAllowed({
|
|
3399
|
-
url: tab.url,
|
|
3400
|
-
...ssrfPolicyOpts
|
|
3401
|
-
});
|
|
3402
|
-
redactedTabs.push(tab);
|
|
3403
|
-
} catch {
|
|
3404
|
-
redactedTabs.push({
|
|
3405
|
-
...tab,
|
|
3406
|
-
url: ""
|
|
3407
|
-
});
|
|
3408
|
-
}
|
|
3409
|
-
return redactedTabs;
|
|
3410
|
-
}
|
|
3411
|
-
function resolveIndexedTab(tabs, index) {
|
|
3412
|
-
return typeof index === "number" ? tabs[index] : tabs.at(0);
|
|
3413
|
-
}
|
|
3414
|
-
function parseRequiredTargetId(res, rawTargetId) {
|
|
3415
|
-
const targetId = toStringOrEmpty(rawTargetId);
|
|
3416
|
-
if (!targetId) {
|
|
3417
|
-
jsonError(res, 400, "targetId is required");
|
|
3418
|
-
return null;
|
|
3419
|
-
}
|
|
3420
|
-
return targetId;
|
|
3421
|
-
}
|
|
3422
|
-
function readOptionalTabLabel(body) {
|
|
3423
|
-
return toStringOrEmpty(body?.label) || void 0;
|
|
3424
|
-
}
|
|
3425
|
-
async function runTabTargetMutation(params) {
|
|
3426
|
-
await withTabsProfileRoute({
|
|
3427
|
-
req: params.req,
|
|
3428
|
-
res: params.res,
|
|
3429
|
-
ctx: params.ctx,
|
|
3430
|
-
mapTabError: true,
|
|
3431
|
-
run: async (profileCtx) => {
|
|
3432
|
-
if (!await ensureBrowserRunning(profileCtx, params.res)) return;
|
|
3433
|
-
await params.mutate(profileCtx, params.targetId);
|
|
3434
|
-
params.res.json({ ok: true });
|
|
3435
|
-
}
|
|
3436
|
-
});
|
|
3437
|
-
}
|
|
3438
|
-
function registerBrowserTabRoutes(app, ctx) {
|
|
3439
|
-
app.get("/tabs", asyncBrowserRoute(async (req, res) => {
|
|
3440
|
-
await withTabsProfileRoute({
|
|
3441
|
-
req,
|
|
3442
|
-
res,
|
|
3443
|
-
ctx,
|
|
3444
|
-
run: async (profileCtx) => {
|
|
3445
|
-
if (!await profileCtx.isReachable(300)) return res.json({
|
|
3446
|
-
running: false,
|
|
3447
|
-
tabs: []
|
|
3448
|
-
});
|
|
3449
|
-
const tabs = await redactBlockedTabUrls({
|
|
3450
|
-
tabs: await profileCtx.listTabs(),
|
|
3451
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
3452
|
-
});
|
|
3453
|
-
res.json({
|
|
3454
|
-
running: true,
|
|
3455
|
-
tabs
|
|
3456
|
-
});
|
|
3457
|
-
}
|
|
3458
|
-
});
|
|
3459
|
-
}));
|
|
3460
|
-
app.post("/tabs/open", asyncBrowserRoute(async (req, res) => {
|
|
3461
|
-
const url = toStringOrEmpty(req.body?.url);
|
|
3462
|
-
const label = readOptionalTabLabel(req.body);
|
|
3463
|
-
if (!url) return jsonError(res, 400, "url is required");
|
|
3464
|
-
await withTabsProfileRoute({
|
|
3465
|
-
req,
|
|
3466
|
-
res,
|
|
3467
|
-
ctx,
|
|
3468
|
-
mapTabError: true,
|
|
3469
|
-
run: async (profileCtx) => {
|
|
3470
|
-
await assertBrowserNavigationAllowed({
|
|
3471
|
-
url,
|
|
3472
|
-
...browserNavigationPolicyForProfile(ctx, profileCtx)
|
|
3473
|
-
});
|
|
3474
|
-
await profileCtx.ensureBrowserAvailable();
|
|
3475
|
-
const tab = await profileCtx.openTab(url, { label });
|
|
3476
|
-
res.json(tab);
|
|
3477
|
-
}
|
|
3478
|
-
});
|
|
3479
|
-
}));
|
|
3480
|
-
app.post("/tabs/focus", asyncBrowserRoute(async (req, res) => {
|
|
3481
|
-
const targetId = parseRequiredTargetId(res, req.body?.targetId);
|
|
3482
|
-
if (!targetId) return;
|
|
3483
|
-
await runTabTargetMutation({
|
|
3484
|
-
req,
|
|
3485
|
-
res,
|
|
3486
|
-
ctx,
|
|
3487
|
-
targetId,
|
|
3488
|
-
mutate: async (profileCtx, id) => {
|
|
3489
|
-
const tabs = await profileCtx.listTabs();
|
|
3490
|
-
const resolved = resolveTargetIdFromTabs(id, tabs);
|
|
3491
|
-
if (!resolved.ok) {
|
|
3492
|
-
if (resolved.reason === "ambiguous") throw new BrowserTargetAmbiguousError();
|
|
3493
|
-
throw new BrowserTabNotFoundError({ input: id });
|
|
3494
|
-
}
|
|
3495
|
-
const tab = tabs.find((currentTab) => currentTab.targetId === resolved.targetId);
|
|
3496
|
-
if (!tab) throw new BrowserTabNotFoundError({ input: id });
|
|
3497
|
-
const ssrfPolicyOpts = browserNavigationPolicyForProfile(ctx, profileCtx);
|
|
3498
|
-
if (ssrfPolicyOpts.ssrfPolicy) await assertBrowserNavigationResultAllowed({
|
|
3499
|
-
url: tab.url,
|
|
3500
|
-
...ssrfPolicyOpts
|
|
3501
|
-
});
|
|
3502
|
-
await profileCtx.focusTab(resolved.targetId);
|
|
3503
|
-
}
|
|
3504
|
-
});
|
|
3505
|
-
}));
|
|
3506
|
-
app.delete("/tabs/:targetId", asyncBrowserRoute(async (req, res) => {
|
|
3507
|
-
const targetId = parseRequiredTargetId(res, req.params.targetId);
|
|
3508
|
-
if (!targetId) return;
|
|
3509
|
-
await runTabTargetMutation({
|
|
3510
|
-
req,
|
|
3511
|
-
res,
|
|
3512
|
-
ctx,
|
|
3513
|
-
targetId,
|
|
3514
|
-
mutate: async (profileCtx, id) => {
|
|
3515
|
-
await profileCtx.closeTab(id);
|
|
3516
|
-
}
|
|
3517
|
-
});
|
|
3518
|
-
}));
|
|
3519
|
-
app.post("/tabs/action", asyncBrowserRoute(async (req, res) => {
|
|
3520
|
-
const action = toStringOrEmpty(req.body?.action);
|
|
3521
|
-
const index = toNumber(req.body?.index);
|
|
3522
|
-
await withTabsProfileRoute({
|
|
3523
|
-
req,
|
|
3524
|
-
res,
|
|
3525
|
-
ctx,
|
|
3526
|
-
mapTabError: true,
|
|
3527
|
-
run: async (profileCtx) => {
|
|
3528
|
-
if (action === "list") {
|
|
3529
|
-
if (!await profileCtx.isReachable(300)) return res.json({
|
|
3530
|
-
ok: true,
|
|
3531
|
-
tabs: []
|
|
3532
|
-
});
|
|
3533
|
-
const tabs = await redactBlockedTabUrls({
|
|
3534
|
-
tabs: await profileCtx.listTabs(),
|
|
3535
|
-
ssrfPolicy: ctx.state().resolved.ssrfPolicy
|
|
3536
|
-
});
|
|
3537
|
-
return res.json({
|
|
3538
|
-
ok: true,
|
|
3539
|
-
tabs
|
|
3540
|
-
});
|
|
3541
|
-
}
|
|
3542
|
-
if (action === "new") {
|
|
3543
|
-
await profileCtx.ensureBrowserAvailable();
|
|
3544
|
-
const tab = await profileCtx.openTab("about:blank", { label: readOptionalTabLabel(req.body) });
|
|
3545
|
-
return res.json({
|
|
3546
|
-
ok: true,
|
|
3547
|
-
tab
|
|
3548
|
-
});
|
|
3549
|
-
}
|
|
3550
|
-
if (action === "label") {
|
|
3551
|
-
if (!await ensureBrowserRunning(profileCtx, res)) return;
|
|
3552
|
-
const targetId = parseRequiredTargetId(res, req.body?.targetId);
|
|
3553
|
-
if (!targetId) return;
|
|
3554
|
-
const label = readOptionalTabLabel(req.body);
|
|
3555
|
-
if (!label) return jsonError(res, 400, "label is required");
|
|
3556
|
-
const tab = await profileCtx.labelTab(targetId, label);
|
|
3557
|
-
return res.json({
|
|
3558
|
-
ok: true,
|
|
3559
|
-
tab
|
|
3560
|
-
});
|
|
3561
|
-
}
|
|
3562
|
-
if (action === "close") {
|
|
3563
|
-
if (!await ensureBrowserRunning(profileCtx, res)) return;
|
|
3564
|
-
const target = resolveIndexedTab(await profileCtx.listTabs(), index);
|
|
3565
|
-
if (!target) throw new BrowserTabNotFoundError();
|
|
3566
|
-
await profileCtx.closeTab(target.targetId);
|
|
3567
|
-
return res.json({
|
|
3568
|
-
ok: true,
|
|
3569
|
-
targetId: target.targetId
|
|
3570
|
-
});
|
|
3571
|
-
}
|
|
3572
|
-
if (action === "select") {
|
|
3573
|
-
if (typeof index !== "number") return jsonError(res, 400, "index is required");
|
|
3574
|
-
if (!await ensureBrowserRunning(profileCtx, res)) return;
|
|
3575
|
-
const target = (await profileCtx.listTabs())[index];
|
|
3576
|
-
if (!target) throw new BrowserTabNotFoundError();
|
|
3577
|
-
const ssrfPolicyOpts = browserNavigationPolicyForProfile(ctx, profileCtx);
|
|
3578
|
-
if (ssrfPolicyOpts.ssrfPolicy) await assertBrowserNavigationResultAllowed({
|
|
3579
|
-
url: target.url,
|
|
3580
|
-
...ssrfPolicyOpts
|
|
3581
|
-
});
|
|
3582
|
-
await profileCtx.focusTab(target.targetId);
|
|
3583
|
-
return res.json({
|
|
3584
|
-
ok: true,
|
|
3585
|
-
targetId: target.targetId
|
|
3586
|
-
});
|
|
3587
|
-
}
|
|
3588
|
-
return jsonError(res, 400, "unknown tab action");
|
|
3589
|
-
}
|
|
3590
|
-
});
|
|
3591
|
-
}));
|
|
3592
|
-
}
|
|
3593
|
-
//#endregion
|
|
3594
|
-
//#region extensions/browser/src/browser/routes/index.ts
|
|
3595
|
-
function registerBrowserRoutes(app, ctx) {
|
|
3596
|
-
registerBrowserBasicRoutes(app, ctx);
|
|
3597
|
-
registerBrowserTabRoutes(app, ctx);
|
|
3598
|
-
registerBrowserPermissionRoutes(app, ctx);
|
|
3599
|
-
registerBrowserAgentRoutes(app, ctx);
|
|
3600
|
-
}
|
|
3601
|
-
//#endregion
|
|
3602
|
-
export { registerBrowserRoutes as t };
|