@mirasim/computer-use 0.0.0-stage → 0.1.0-rc.3
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/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +154 -2
- package/THIRD_PARTY_NOTICES +488 -0
- package/bin/mirasim-cu.mjs +30 -0
- package/dist/entries/cli.d.ts +2 -0
- package/dist/entries/cli.js +32 -0
- package/dist/entries/commands/approvals.d.ts +1 -0
- package/dist/entries/commands/approvals.js +17 -0
- package/dist/entries/commands/bridge-host.d.ts +1 -0
- package/dist/entries/commands/bridge-host.js +7 -0
- package/dist/entries/commands/bridge.d.ts +1 -0
- package/dist/entries/commands/bridge.js +16 -0
- package/dist/entries/commands/browser-state.d.ts +1 -0
- package/dist/entries/commands/browser-state.js +8 -0
- package/dist/entries/commands/capture-server.d.ts +1 -0
- package/dist/entries/commands/capture-server.js +5 -0
- package/dist/entries/commands/help.d.ts +2 -0
- package/dist/entries/commands/help.js +1 -0
- package/dist/entries/commands/native-host-options.d.ts +32 -0
- package/dist/entries/commands/native-host-options.js +7 -0
- package/dist/entries/commands/setup-macos.d.ts +1 -0
- package/dist/entries/commands/setup-macos.js +4 -0
- package/dist/entries/commands/setup.d.ts +1 -0
- package/dist/entries/commands/setup.js +15 -0
- package/dist/entries/mcp.d.ts +1 -0
- package/dist/entries/mcp.js +6 -0
- package/dist/entries/version.d.ts +1 -0
- package/dist/entries/version.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -0
- package/dist/platform/browser/acquire.d.ts +15 -0
- package/dist/platform/browser/acquire.js +1 -0
- package/dist/platform/browser/bridge/acquire-bridge.d.ts +7 -0
- package/dist/platform/browser/bridge/acquire-bridge.js +3 -0
- package/dist/platform/browser/bridge/client.d.ts +69 -0
- package/dist/platform/browser/bridge/client.js +1 -0
- package/dist/platform/browser/bridge/extension-channel.d.ts +12 -0
- package/dist/platform/browser/bridge/extension-channel.js +1 -0
- package/dist/platform/browser/bridge/extension-id.d.ts +8 -0
- package/dist/platform/browser/bridge/extension-id.js +1 -0
- package/dist/platform/browser/bridge/extension-updates.d.ts +37 -0
- package/dist/platform/browser/bridge/extension-updates.js +1 -0
- package/dist/platform/browser/bridge/model-commands.d.ts +20 -0
- package/dist/platform/browser/bridge/model-commands.js +1 -0
- package/dist/platform/browser/bridge/model-core.d.ts +59 -0
- package/dist/platform/browser/bridge/model-core.js +1 -0
- package/dist/platform/browser/bridge/model.d.ts +4 -0
- package/dist/platform/browser/bridge/model.js +1 -0
- package/dist/platform/browser/bridge/native-frames.d.ts +9 -0
- package/dist/platform/browser/bridge/native-frames.js +1 -0
- package/dist/platform/browser/bridge/native-host.d.ts +24 -0
- package/dist/platform/browser/bridge/native-host.js +5 -0
- package/dist/platform/browser/bridge/runtime-contexts.d.ts +12 -0
- package/dist/platform/browser/bridge/runtime-contexts.js +1 -0
- package/dist/platform/browser/bridge/server-core.d.ts +66 -0
- package/dist/platform/browser/bridge/server-core.js +1 -0
- package/dist/platform/browser/bridge/server.d.ts +13 -0
- package/dist/platform/browser/bridge/server.js +1 -0
- package/dist/platform/browser/bridge-tabs.d.ts +22 -0
- package/dist/platform/browser/bridge-tabs.js +1 -0
- package/dist/platform/browser/cdp-connection.d.ts +3 -0
- package/dist/platform/browser/cdp-connection.js +1 -0
- package/dist/platform/browser/chrome-binary.d.ts +6 -0
- package/dist/platform/browser/chrome-binary.js +1 -0
- package/dist/platform/browser/config.d.ts +29 -0
- package/dist/platform/browser/config.js +1 -0
- package/dist/platform/browser/devtools-port.d.ts +3 -0
- package/dist/platform/browser/devtools-port.js +2 -0
- package/dist/platform/browser/downloads.d.ts +22 -0
- package/dist/platform/browser/downloads.js +1 -0
- package/dist/platform/browser/driver-connect.d.ts +13 -0
- package/dist/platform/browser/driver-connect.js +1 -0
- package/dist/platform/browser/driver-core.d.ts +50 -0
- package/dist/platform/browser/driver-core.js +1 -0
- package/dist/platform/browser/driver-tabs.d.ts +16 -0
- package/dist/platform/browser/driver-tabs.js +1 -0
- package/dist/platform/browser/driver-verbs.d.ts +13 -0
- package/dist/platform/browser/driver-verbs.js +2 -0
- package/dist/platform/browser/driver.d.ts +38 -0
- package/dist/platform/browser/driver.js +3 -0
- package/dist/platform/browser/focus-guard.d.ts +2 -0
- package/dist/platform/browser/focus-guard.js +1 -0
- package/dist/platform/browser/journal.d.ts +21 -0
- package/dist/platform/browser/journal.js +2 -0
- package/dist/platform/browser/keep-in-tab.d.ts +1 -0
- package/dist/platform/browser/keep-in-tab.js +1 -0
- package/dist/platform/browser/messages.d.ts +25 -0
- package/dist/platform/browser/messages.js +8 -0
- package/dist/platform/browser/navigate.d.ts +4 -0
- package/dist/platform/browser/navigate.js +2 -0
- package/dist/platform/browser/occupancy.d.ts +2 -0
- package/dist/platform/browser/occupancy.js +2 -0
- package/dist/platform/browser/overlay-guard.d.ts +3 -0
- package/dist/platform/browser/overlay-guard.js +1 -0
- package/dist/platform/browser/save-picker.d.ts +2 -0
- package/dist/platform/browser/save-picker.js +1 -0
- package/dist/platform/browser/session-files.d.ts +11 -0
- package/dist/platform/browser/session-files.js +1 -0
- package/dist/platform/browser/state.d.ts +25 -0
- package/dist/platform/browser/state.js +2 -0
- package/dist/platform/browser/tabs.d.ts +15 -0
- package/dist/platform/browser/tabs.js +2 -0
- package/dist/platform/browser/window-placement.d.ts +8 -0
- package/dist/platform/browser/window-placement.js +1 -0
- package/dist/platform/chromium/actions-value.d.ts +11 -0
- package/dist/platform/chromium/actions-value.js +5 -0
- package/dist/platform/chromium/actions.d.ts +20 -0
- package/dist/platform/chromium/actions.js +2 -0
- package/dist/platform/chromium/checkable-target.d.ts +1 -0
- package/dist/platform/chromium/checkable-target.js +1 -0
- package/dist/platform/chromium/collect-viewport.d.ts +1 -0
- package/dist/platform/chromium/collect-viewport.js +1 -0
- package/dist/platform/chromium/collect.d.ts +11 -0
- package/dist/platform/chromium/collect.js +1 -0
- package/dist/platform/chromium/coverer-label.d.ts +8 -0
- package/dist/platform/chromium/coverer-label.js +1 -0
- package/dist/platform/chromium/frames.d.ts +2 -0
- package/dist/platform/chromium/frames.js +1 -0
- package/dist/platform/chromium/headings.d.ts +1 -0
- package/dist/platform/chromium/headings.js +1 -0
- package/dist/platform/chromium/locate.d.ts +2 -0
- package/dist/platform/chromium/locate.js +1 -0
- package/dist/platform/chromium/page-acts.d.ts +9 -0
- package/dist/platform/chromium/page-acts.js +1 -0
- package/dist/platform/chromium/page-base.d.ts +33 -0
- package/dist/platform/chromium/page-base.js +1 -0
- package/dist/platform/chromium/page-driver.d.ts +18 -0
- package/dist/platform/chromium/page-driver.js +2 -0
- package/dist/platform/chromium/page-refs.d.ts +4 -0
- package/dist/platform/chromium/page-refs.js +1 -0
- package/dist/platform/chromium/page-text.d.ts +15 -0
- package/dist/platform/chromium/page-text.js +1 -0
- package/dist/platform/chromium/page-waits.d.ts +7 -0
- package/dist/platform/chromium/page-waits.js +1 -0
- package/dist/platform/chromium/preview-stream.d.ts +37 -0
- package/dist/platform/chromium/preview-stream.js +1 -0
- package/dist/platform/chromium/preview.d.ts +3 -0
- package/dist/platform/chromium/preview.js +1 -0
- package/dist/platform/chromium/read-page-script.d.ts +1 -0
- package/dist/platform/chromium/read-page-script.js +1 -0
- package/dist/platform/chromium/read-page.d.ts +11 -0
- package/dist/platform/chromium/read-page.js +6 -0
- package/dist/platform/chromium/run-js.d.ts +4 -0
- package/dist/platform/chromium/run-js.js +2 -0
- package/dist/platform/chromium/scroll-regions.d.ts +1 -0
- package/dist/platform/chromium/scroll-regions.js +1 -0
- package/dist/platform/chromium/scroll-scripts.d.ts +3 -0
- package/dist/platform/chromium/scroll-scripts.js +1 -0
- package/dist/platform/chromium/scroll.d.ts +18 -0
- package/dist/platform/chromium/scroll.js +5 -0
- package/dist/platform/chromium/select-text.d.ts +4 -0
- package/dist/platform/chromium/select-text.js +2 -0
- package/dist/platform/chromium/shot.d.ts +10 -0
- package/dist/platform/chromium/shot.js +2 -0
- package/dist/platform/chromium/unreached.d.ts +8 -0
- package/dist/platform/chromium/unreached.js +1 -0
- package/dist/platform/cli-command.d.ts +1 -0
- package/dist/platform/cli-command.js +1 -0
- package/dist/platform/driver-base.d.ts +83 -0
- package/dist/platform/driver-base.js +1 -0
- package/dist/platform/driver-diagnostics.d.ts +30 -0
- package/dist/platform/driver-diagnostics.js +4 -0
- package/dist/platform/driver-lines.d.ts +15 -0
- package/dist/platform/driver-lines.js +2 -0
- package/dist/platform/driver-narrate.d.ts +26 -0
- package/dist/platform/driver-narrate.js +3 -0
- package/dist/platform/driver-refs.d.ts +16 -0
- package/dist/platform/driver-refs.js +1 -0
- package/dist/platform/driver-render.d.ts +26 -0
- package/dist/platform/driver-render.js +4 -0
- package/dist/platform/driver-select.d.ts +31 -0
- package/dist/platform/driver-select.js +2 -0
- package/dist/platform/driver-settle.d.ts +22 -0
- package/dist/platform/driver-settle.js +4 -0
- package/dist/platform/driver-verdict.d.ts +11 -0
- package/dist/platform/driver-verdict.js +5 -0
- package/dist/platform/driver-wait.d.ts +9 -0
- package/dist/platform/driver-wait.js +1 -0
- package/dist/platform/driver-waits.d.ts +10 -0
- package/dist/platform/driver-waits.js +1 -0
- package/dist/platform/driver.d.ts +39 -0
- package/dist/platform/driver.js +15 -0
- package/dist/platform/electron/driver.d.ts +30 -0
- package/dist/platform/electron/driver.js +7 -0
- package/dist/platform/electron/preflight.d.ts +9 -0
- package/dist/platform/electron/preflight.js +1 -0
- package/dist/platform/electron/verbs.d.ts +3 -0
- package/dist/platform/electron/verbs.js +1 -0
- package/dist/platform/home.d.ts +2 -0
- package/dist/platform/home.js +1 -0
- package/dist/platform/macos/act-element.d.ts +27 -0
- package/dist/platform/macos/act-element.js +1 -0
- package/dist/platform/macos/app-names.d.ts +2 -0
- package/dist/platform/macos/app-names.js +2 -0
- package/dist/platform/macos/app-notes.d.ts +2 -0
- package/dist/platform/macos/app-notes.js +86 -0
- package/dist/platform/macos/approvals.d.ts +10 -0
- package/dist/platform/macos/approvals.js +2 -0
- package/dist/platform/macos/ax-client.d.ts +53 -0
- package/dist/platform/macos/ax-client.js +3 -0
- package/dist/platform/macos/ax-errors.d.ts +16 -0
- package/dist/platform/macos/ax-errors.js +1 -0
- package/dist/platform/macos/ax-shapes.d.ts +53 -0
- package/dist/platform/macos/ax-shapes.js +1 -0
- package/dist/platform/macos/capture-client.d.ts +11 -0
- package/dist/platform/macos/capture-client.js +2 -0
- package/dist/platform/macos/click-verb.d.ts +4 -0
- package/dist/platform/macos/click-verb.js +1 -0
- package/dist/platform/macos/driver-apps.d.ts +59 -0
- package/dist/platform/macos/driver-apps.js +2 -0
- package/dist/platform/macos/driver-read.d.ts +47 -0
- package/dist/platform/macos/driver-read.js +1 -0
- package/dist/platform/macos/driver-targets.d.ts +9 -0
- package/dist/platform/macos/driver-targets.js +1 -0
- package/dist/platform/macos/driver.d.ts +65 -0
- package/dist/platform/macos/driver.js +2 -0
- package/dist/platform/macos/element-lines.d.ts +12 -0
- package/dist/platform/macos/element-lines.js +1 -0
- package/dist/platform/macos/element-shapes.d.ts +54 -0
- package/dist/platform/macos/element-shapes.js +0 -0
- package/dist/platform/macos/element-text.d.ts +3 -0
- package/dist/platform/macos/element-text.js +2 -0
- package/dist/platform/macos/elements.d.ts +26 -0
- package/dist/platform/macos/elements.js +1 -0
- package/dist/platform/macos/extra-verbs.d.ts +2 -0
- package/dist/platform/macos/extra-verbs.js +1 -0
- package/dist/platform/macos/interaction-notes.d.ts +2 -0
- package/dist/platform/macos/interaction-notes.js +1 -0
- package/dist/platform/macos/interaction-policy.d.ts +5 -0
- package/dist/platform/macos/interaction-policy.js +1 -0
- package/dist/platform/macos/menu-commands.d.ts +22 -0
- package/dist/platform/macos/menu-commands.js +5 -0
- package/dist/platform/macos/mouse.d.ts +23 -0
- package/dist/platform/macos/mouse.js +1 -0
- package/dist/platform/macos/narrate.d.ts +20 -0
- package/dist/platform/macos/narrate.js +1 -0
- package/dist/platform/macos/permissions.d.ts +5 -0
- package/dist/platform/macos/permissions.js +1 -0
- package/dist/platform/macos/press-rungs.d.ts +49 -0
- package/dist/platform/macos/press-rungs.js +5 -0
- package/dist/platform/macos/preview-stream.d.ts +15 -0
- package/dist/platform/macos/preview-stream.js +1 -0
- package/dist/platform/macos/prompt-fragment.d.ts +1 -0
- package/dist/platform/macos/prompt-fragment.js +1 -0
- package/dist/platform/macos/scroll-pages.d.ts +1 -0
- package/dist/platform/macos/scroll-pages.js +1 -0
- package/dist/platform/macos/scroll-verb.d.ts +5 -0
- package/dist/platform/macos/scroll-verb.js +1 -0
- package/dist/platform/macos/select-text-verb.d.ts +8 -0
- package/dist/platform/macos/select-text-verb.js +1 -0
- package/dist/platform/macos/type-verb.d.ts +5 -0
- package/dist/platform/macos/type-verb.js +1 -0
- package/dist/platform/ownership.d.ts +20 -0
- package/dist/platform/ownership.js +1 -0
- package/dist/platform/platform-package.d.ts +1 -0
- package/dist/platform/platform-package.js +1 -0
- package/dist/platform/preview.d.ts +39 -0
- package/dist/platform/preview.js +1 -0
- package/dist/platform/profile.d.ts +20 -0
- package/dist/platform/profile.js +1 -0
- package/dist/platform/registry.d.ts +12 -0
- package/dist/platform/registry.js +1 -0
- package/dist/platform/tools/api-contract.d.ts +33 -0
- package/dist/platform/tools/api-contract.js +3 -0
- package/dist/platform/tools/api-expect.d.ts +3 -0
- package/dist/platform/tools/api-expect.js +1 -0
- package/dist/platform/tools/api-run.d.ts +6 -0
- package/dist/platform/tools/api-run.js +1 -0
- package/dist/platform/tools/api-target.d.ts +22 -0
- package/dist/platform/tools/api-target.js +1 -0
- package/dist/platform/tools/api-wait.d.ts +3 -0
- package/dist/platform/tools/api-wait.js +1 -0
- package/dist/platform/tools/api.d.ts +7 -0
- package/dist/platform/tools/api.js +1 -0
- package/dist/platform/tools/find-target.d.ts +54 -0
- package/dist/platform/tools/find-target.js +1 -0
- package/dist/platform/tools/index.d.ts +8 -0
- package/dist/platform/tools/index.js +1 -0
- package/dist/platform/tools/normalize.d.ts +2 -0
- package/dist/platform/tools/normalize.js +1 -0
- package/dist/platform/tools/repl-budget.d.ts +8 -0
- package/dist/platform/tools/repl-budget.js +4 -0
- package/dist/platform/tools/repl-code.d.ts +1 -0
- package/dist/platform/tools/repl-code.js +4 -0
- package/dist/platform/tools/repl-docs.d.ts +5 -0
- package/dist/platform/tools/repl-docs.js +4 -0
- package/dist/platform/tools/repl-state.d.ts +21 -0
- package/dist/platform/tools/repl-state.js +0 -0
- package/dist/platform/tools/repl.d.ts +8 -0
- package/dist/platform/tools/repl.js +19 -0
- package/dist/platform/tools/shot-file.d.ts +7 -0
- package/dist/platform/tools/shot-file.js +1 -0
- package/dist/platform/tools/validate.d.ts +2 -0
- package/dist/platform/tools/validate.js +1 -0
- package/dist/platform/types.d.ts +220 -0
- package/dist/platform/types.js +1 -0
- package/dist/platform/windows/app-gate.d.ts +24 -0
- package/dist/platform/windows/app-gate.js +2 -0
- package/dist/platform/windows/background-verb.d.ts +13 -0
- package/dist/platform/windows/background-verb.js +1 -0
- package/dist/platform/windows/dates.d.ts +2 -0
- package/dist/platform/windows/dates.js +1 -0
- package/dist/platform/windows/driver-apps.d.ts +9 -0
- package/dist/platform/windows/driver-apps.js +1 -0
- package/dist/platform/windows/driver-read.d.ts +12 -0
- package/dist/platform/windows/driver-read.js +3 -0
- package/dist/platform/windows/driver-targets.d.ts +58 -0
- package/dist/platform/windows/driver-targets.js +1 -0
- package/dist/platform/windows/driver-yield.d.ts +10 -0
- package/dist/platform/windows/driver-yield.js +1 -0
- package/dist/platform/windows/driver.d.ts +39 -0
- package/dist/platform/windows/driver.js +2 -0
- package/dist/platform/windows/elements.d.ts +66 -0
- package/dist/platform/windows/elements.js +2 -0
- package/dist/platform/windows/launch.d.ts +23 -0
- package/dist/platform/windows/launch.js +1 -0
- package/dist/platform/windows/menu-verb.d.ts +7 -0
- package/dist/platform/windows/menu-verb.js +6 -0
- package/dist/platform/windows/prompt-fragment.d.ts +2 -0
- package/dist/platform/windows/prompt-fragment.js +1 -0
- package/dist/platform/windows/text-verbs.d.ts +10 -0
- package/dist/platform/windows/text-verbs.js +5 -0
- package/dist/platform/windows/uia-client.d.ts +32 -0
- package/dist/platform/windows/uia-client.js +3 -0
- package/dist/platform/windows/verbs.d.ts +2 -0
- package/dist/platform/windows/verbs.js +1 -0
- package/extension/background.js +280 -0
- package/extension/connect.html +27 -0
- package/extension/connect.js +28 -0
- package/extension/group.js +283 -0
- package/extension/icons/icon-128.png +0 -0
- package/extension/icons/icon-16.png +0 -0
- package/extension/icons/icon-32.png +0 -0
- package/extension/icons/icon-48.png +0 -0
- package/extension/manifest.json +36 -0
- package/extension/relay.js +361 -0
- package/extension/runtime-info.js +9 -0
- package/extension/transport.js +81 -0
- package/package.json +76 -4
- package/scripts/extension.mjs +111 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import x from"node:http";import U from"node:net";import{chmodSync as A,existsSync as O,lstatSync as C,readFileSync as I,renameSync as R,unlinkSync as b,writeFileSync as j}from"node:fs";import{randomUUID as M,timingSafeEqual as J}from"node:crypto";import{AxHelperProcess as L}from"../../platform/macos/ax-client.js";import{AxRequestError as $}from"../../platform/macos/ax-errors.js";function u(r){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("Expected an object.");return r}function _(r){return Number.isSafeInteger(r)&&r>0}function T(r){const o=u(r);if(![o.x,o.y,o.width,o.height].every(n=>typeof n=="number"&&Number.isFinite(n))||!(o.width>0)||!(o.height>0))throw new Error("Invalid capture rectangle.")}function k(r){const o=u(r);if(!_(o.pid)||o.pid>2147483647||!_(o.window)||o.window>4294967295)throw new Error("Capture requires a valid PID and window ID.");return o}function F(r,o){if(r!=="shot"&&r!=="shotscoped")throw new Error("Only window screenshots are available here.");const n=k(o);if(Object.keys(n).some(c=>!["pid","window","expectedFrame","maxLongSide","region","mark"].includes(c)))throw new Error("Unsupported capture parameter; AX keys and input cannot cross this connection.");if(T(n.expectedFrame),!_(n.maxLongSide)||n.maxLongSide>4096)throw new Error("Invalid capture size.");if(r==="shotscoped")T(n.region);else if(n.region!==void 0)throw new Error("A full screenshot cannot carry a region.");if(n.mark!==void 0){const c=u(n.mark);if(![c.x,c.y].every(a=>typeof a=="number"&&Number.isFinite(a))||typeof c.down!="boolean")throw new Error("Invalid pointer annotation.")}return n}function E(r){return{ok:!1,error:r instanceof $?{code:r.code,message:r.message,...r.capture?{capture:r.capture}:{}}:{code:"capture_service_error",message:r instanceof Error?r.message:String(r)}}}async function K(){if(process.platform!=="darwin")throw new Error("Native capture is available only on macOS.");const r=process.env.COMPUTER_USE_MACOS_CAPTURE_SOCKET,o=process.env.COMPUTER_USE_MACOS_CAPTURE_TOKEN;if(!r||!o)throw new Error("Native capture must be started by its host.");const n=process.env.COMPUTER_USE_MACOS_CAPTURE_LEASE,c=Buffer.from(`Bearer ${o}`),a=new Map;let w=!1,l=0,g=0,N=Promise.resolve();const m=new L({captureLocal:!0,onStart:async t=>{n&&(j(`${n}.pending`,JSON.stringify({owner:process.pid,worker:t}),{mode:384}),R(`${n}.pending`,n))},env:{...process.env,COMPUTER_USE_PREVIEW_WORKER:"1"},onEvent:t=>{if(typeof t.streamId!="string")return;const e=a.get(t.streamId);e&&!e.destroyed&&e.writableLength<256*1024&&e.write(`${JSON.stringify(t)}
|
|
2
|
+
`)}});m.onReset=()=>{l++;const t=[...a.values()];a.clear();for(const e of t)e.end(`${JSON.stringify({event:"previewError",message:"The native capture worker stopped. Reopen the preview to reconnect."})}
|
|
3
|
+
`)};const v=t=>{if(w||g>=16)return Promise.reject(new Error("Native capture is stopping or busy; retry after current captures finish."));g++;const e=N.then(()=>{if(w)throw new Error("Native capture is stopping.");return t()});return N=e.catch(()=>{}),e.finally(()=>{g--})},h=(t,e,i)=>{t.destroyed||(t.writeHead(e,{"content-type":"application/json"}),t.end(JSON.stringify(i)))},d=x.createServer((t,e)=>{(async()=>{const i=Buffer.from(t.headers.authorization??"");if(t.headers.origin||i.length!==c.length||!J(i,c)){t.resume(),h(e,403,E(new Error("Native capture authentication failed.")));return}if(t.method!=="POST"||!["/capture","/preview"].includes(t.url??"")){t.resume(),h(e,404,E(new Error("Unknown native capture operation.")));return}let S="";for await(const f of t)if(S+=String(f),Buffer.byteLength(S)>16384)throw new Error("Native capture request is too large.");const y=u(JSON.parse(S));if(t.url==="/capture"){const f=F(y.op,y.params),p=await v(()=>m.request(y.op,f));h(e,200,{ok:!0,result:p})}else{const f=k(y);if(Object.keys(f).some(s=>s!=="pid"&&s!=="window"))throw new Error("Unsupported preview parameter.");if(a.size>=8)throw new Error("Too many native previews are already active.");const p=M(),P=l;a.set(p,e),e.writeHead(200,{"content-type":"application/x-ndjson"}),e.flushHeaders(),e.once("close",()=>{!a.delete(p)||w||l!==P||v(()=>l===P?m.request("previewstop",{streamId:p}):Promise.resolve({})).catch(()=>{})});try{const s=await v(async()=>e.destroyed?{}:m.request("previewstart",{pid:f.pid,window:f.window,streamId:p,maxLongSide:2560}));e.destroyed||e.write(`${JSON.stringify({event:"previewReady",...u(s)})}
|
|
4
|
+
`)}catch(s){e.destroyed||e.end(`${JSON.stringify({event:"previewError",...u(E(s)),message:s instanceof Error?s.message:String(s)})}
|
|
5
|
+
`)}}})().catch(i=>{e.headersSent?e.destroy():h(e,400,E(i))})});if(d.headersTimeout=5e3,d.requestTimeout=5e3,O(r)){if(!C(r).isSocket())throw new Error("The native capture socket path is occupied by a non-socket file.");if(await new Promise(e=>{const i=U.createConnection(r);i.once("connect",()=>{i.destroy(),e(!0)}),i.once("error",()=>e(!1)),i.setTimeout(500,()=>{i.destroy(),e(!0)})}))throw new Error("A native capture service is already listening on this socket.");b(r)}await new Promise((t,e)=>{d.once("error",e),d.listen(r,t)}),A(r,384),await new Promise(t=>{const e=()=>{w||(w=!0,t())};process.once("SIGTERM",e),process.once("SIGINT",e),process.stdin.resume(),process.stdin.once("end",e),process.stdin.once("error",e)}),process.stdin.pause(),d.close(),d.closeAllConnections(),await m.close(),n&&O(n)&&JSON.parse(I(n,"utf8")).owner===process.pid&&b(n),O(r)&&b(r)}export{K as runCaptureServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function r(o){const e=o[0];return e==="help"||e==="--help"||e==="-h"}function s(o,e){e&&(console.log(o),process.exit(0)),console.error(o),process.exit(2)}export{s as emitUsage,r as wantsHelp};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type NativeHostEntry } from "../../platform/browser/bridge/native-host.ts";
|
|
2
|
+
export declare const NATIVE_HOST_USAGE = " --host-name N native host name (default ai.mirasim.browser_bridge)\n --owner O whose record this is (default mirasim-cu); one record per owner\n --priority N lower is tried first when several programs are recorded (default 100;\n a negative one is written --priority=-1)\n --host-command C the program Chrome should run, absolute; repeat for an interpreter + script\n (default: the node and script running this command)\n --manifest-dir D one more NativeMessagingHosts folder (a browser on a custom --user-data-dir)";
|
|
3
|
+
export declare const NATIVE_HOST_OPTIONS: {
|
|
4
|
+
readonly "host-name": {
|
|
5
|
+
readonly type: "string";
|
|
6
|
+
};
|
|
7
|
+
readonly owner: {
|
|
8
|
+
readonly type: "string";
|
|
9
|
+
};
|
|
10
|
+
readonly priority: {
|
|
11
|
+
readonly type: "string";
|
|
12
|
+
};
|
|
13
|
+
readonly "host-command": {
|
|
14
|
+
readonly type: "string";
|
|
15
|
+
readonly multiple: true;
|
|
16
|
+
};
|
|
17
|
+
readonly "manifest-dir": {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
readonly multiple: true;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export interface NativeHostFlags {
|
|
23
|
+
"host-name"?: string;
|
|
24
|
+
owner?: string;
|
|
25
|
+
priority?: string;
|
|
26
|
+
"host-command"?: string[];
|
|
27
|
+
"manifest-dir"?: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function hostName(flags: NativeHostFlags): string;
|
|
30
|
+
export declare function hostOwner(flags: NativeHostFlags): string;
|
|
31
|
+
export declare function hostEntry(flags: NativeHostFlags, socket: string, extensionIds: string[]): NativeHostEntry;
|
|
32
|
+
export declare function recordedPath(path: string | undefined): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{defaultHostCommand as i,NATIVE_HOST_NAME as n}from"../../platform/browser/bridge/native-host.js";const p=` --host-name N native host name (default ${n})
|
|
2
|
+
--owner O whose record this is (default mirasim-cu); one record per owner
|
|
3
|
+
--priority N lower is tried first when several programs are recorded (default 100;
|
|
4
|
+
a negative one is written --priority=-1)
|
|
5
|
+
--host-command C the program Chrome should run, absolute; repeat for an interpreter + script
|
|
6
|
+
(default: the node and script running this command)
|
|
7
|
+
--manifest-dir D one more NativeMessagingHosts folder (a browser on a custom --user-data-dir)`,u={"host-name":{type:"string"},owner:{type:"string"},priority:{type:"string"},"host-command":{type:"string",multiple:!0},"manifest-dir":{type:"string",multiple:!0}};function d(r){return r["host-name"]??n}function s(r){return r.owner??"mirasim-cu"}function c(r,t,e){const o=r.priority===void 0?100:Number(r.priority);if(!Number.isFinite(o))throw new Error(`--priority must be a number: ${r.priority}`);return{owner:s(r),command:r["host-command"]?.length?r["host-command"]:i(),socket:t,priority:o,extensionIds:e,manifestDirs:r["manifest-dir"]??[],...process.platform==="win32"?{}:{path:m(process.env.PATH)}}}function m(r){const t=(r??"").split(":").filter(e=>e&&!/(^|\/)node_modules\/\.bin\/?$/.test(e));return t.length?t.join(":"):"/usr/bin:/bin"}export{u as NATIVE_HOST_OPTIONS,p as NATIVE_HOST_USAGE,c as hostEntry,d as hostName,s as hostOwner,m as recordedPath};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSetupMacos(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{execFile as a,execFileSync as l}from"node:child_process";import{parseArgs as u}from"node:util";import{AxHelperProcess as m}from"../../platform/macos/ax-client.js";const p=[{key:"accessibility",label:"Accessibility",why:"read and act in app windows",pane:"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility",request:'ObjC.bindFunction("AXIsProcessTrustedWithOptions", ["bool", ["id"]]); $.AXIsProcessTrustedWithOptions($({"AXTrustedCheckOptionPrompt": true}));'},{key:"screenRecording",label:"Screen Recording",why:"take screenshots",pane:"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture",request:'ObjC.bindFunction("CGRequestScreenCaptureAccess", ["bool", []]); $.CGRequestScreenCaptureAccess();'}];function d(){try{const c=new Map;for(const o of l("ps",["-axo","pid=,ppid=,comm="],{encoding:"utf8"}).split(`
|
|
2
|
+
`)){const t=/^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(o);t&&c.set(Number(t[1]),{ppid:Number(t[2]),comm:t[3]})}let n=null;for(let o=process.pid,t=0;o>1&&t<64;t++){const s=c.get(o);if(!s)break;const i=s.comm.indexOf(".app/");if(i>=0){const r=s.comm.slice(0,i+4);n={name:r.slice(r.lastIndexOf("/")+1,-4),path:r}}o=s.ppid}return n}catch{return null}}async function h(){const c=new m({captureLocal:!0,timeoutMs:18e4});try{const n=await c.request("capabilities");return{accessibility:n.accessibility===!0,screenRecording:n.screenRecording===!0}}finally{await c.close()}}const f=c=>new Promise(n=>a("osascript",["-l","JavaScript","-e",c],{timeout:1e4},()=>n()));async function w(c){const{values:n}=u({args:c,options:{open:{type:"boolean",default:!0},json:{type:"boolean",default:!1}},allowNegative:!0});process.platform!=="darwin"&&(console.error("setup macos: this machine is not a Mac"),process.exit(1));const o=d();let t;try{t=await h()}catch(e){console.error(`setup macos: could not start the macOS helper: ${e.message}`),process.exit(1)}const s=p.filter(e=>!t[e.key]);if(n.open)for(const e of s)await f(e.request),a("open",[e.pane],()=>{});n.json&&(console.log(JSON.stringify({app:o,...t,opened:n.open?s.map(e=>e.key):[]})),process.exit(s.length?1:0));const i=o?`${o.name} (${o.path})`:"the app that launched this command";console.log(`macOS grants these to ${i}, not to the helper:`);for(const e of p)console.log(` ${e.label.padEnd(16)} ${t[e.key]?"granted":`missing \u2014 needed to ${e.why}`}`);const r=o?.name??"that app";if(s.length){const e=s.length>1?"them":"it";console.log(n.open?`
|
|
3
|
+
Opened System Settings \u2192 Privacy & Security${s.length>1?" (one pane each)":""}: tick ${r} there, then run this again.`:`
|
|
4
|
+
Grant ${e} in System Settings \u2192 Privacy & Security: tick ${r}, then run this again.`),t.screenRecording||console.log(`If Screen Recording still reads missing after ticking it, quit and reopen ${r}.`)}console.log(`An MCP client that is a different app from ${r} needs the same grants on its own row.`),process.exit(s.length?1:0)}export{w as runSetupMacos};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSetupCommand(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import{parseArgs as a}from"node:util";import{findChrome as m,chromeMissingError as c}from"../../platform/browser/acquire.js";import{MIRASIM_EXTENSION_ID as l}from"../../platform/browser/bridge/extension-id.js";import{defaultBridgeSocket as f,installNativeHost as u,removeNativeHost as p}from"../../platform/browser/bridge/native-host.js";import{emitUsage as h,wantsHelp as n}from"./help.js";import{hostEntry as d,hostName as i,hostOwner as g,NATIVE_HOST_OPTIONS as b,NATIVE_HOST_USAGE as w}from"./native-host-options.js";function r(s){h(`Usage: mirasim-cu setup browser
|
|
2
|
+
mirasim-cu setup macos [--no-open] [--json]
|
|
3
|
+
mirasim-cu setup extension [--remove] [--socket P] [--json] [options]
|
|
4
|
+
|
|
5
|
+
browser check for a driveable Chrome; a miss names the fix (never auto-installs)
|
|
6
|
+
macos check Accessibility + Screen Recording for the app that launched this; a miss
|
|
7
|
+
opens its System Settings pane (--no-open: only report). Exit 1 while one is missing
|
|
8
|
+
extension let the browser extension start this computer-use's bridge: writes the
|
|
9
|
+
native-messaging manifest into every Chromium-family browser found
|
|
10
|
+
(--remove takes this computer-use's record back; the last one out
|
|
11
|
+
removes the manifests)
|
|
12
|
+
|
|
13
|
+
--socket P the socket \`bridge\` listens on (default <COMPUTER_USE_HOME>/bridge.sock)
|
|
14
|
+
--json print the result as JSON
|
|
15
|
+
${w}`,s)}async function N(s){const t=s[0];if(t==="browser"){const e=m();if(e){console.log(`browser ready: ${e}`);return}console.error(c().message),process.exit(1)}if(t==="macos"){n(s.slice(1))&&r(!0);const{runSetupMacos:e}=await import("./setup-macos.js");await e(s.slice(1));return}if(t==="extension"){n(s.slice(1))&&r(!0);const{values:e}=a({args:s.slice(1),options:{remove:{type:"boolean",default:!1},socket:{type:"string"},json:{type:"boolean",default:!1},...b}}),o=e.remove?p(g(e),i(e),e["manifest-dir"]??[]):u(d(e,e.socket??f(),[l]),i(e));if(e.json){console.log(JSON.stringify(o));return}if(e.remove){console.log(o.owners.length?`native host ${o.name}: record removed; manifests kept for ${o.owners.join(", ")}`:`native host ${o.name} removed${o.manifests.length?`: ${o.manifests.join(", ")}`:""}`);return}console.log(`native host ${o.name} installed`),console.log(` manifests: ${o.manifests.join(", ")||"(none \u2014 no Chromium-family browser folder found)"}`),console.log(` recorded: ${o.owners.join(", ")}`),console.log("Run `mirasim-cu bridge --native-host` to let the extension connect.");return}r(n(s))}export{N as runSetupCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function serveMcp(): Promise<void>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{appendFileSync as $,mkdirSync as A}from"node:fs";import{dirname as O}from"node:path";import{Server as P}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as N}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as G,ErrorCode as L,ListToolsRequestSchema as U,McpError as D}from"@modelcontextprotocol/sdk/types.js";import{resolveProfile as F}from"../platform/profile.js";import{SurfaceGoneError as b}from"../platform/types.js";import{ownVersion as R}from"./version.js";import{PreviewService as H}from"../platform/preview.js";function V(){const s=process.env.COMPUTER_USE_MCP_LOG?.trim();if(!s)return()=>{};try{A(O(s),{recursive:!0})}catch{}return a=>{try{$(s,JSON.stringify({ts:new Date().toISOString(),...a})+`
|
|
2
|
+
`)}catch{}}}const z="Copy literal values verbatim when filling forms. Never guess or invent URLs, ids, or names.";function j(s){return`${[...new Set(s.drivers.map(o=>o.promptFragment()))].join(`
|
|
3
|
+
|
|
4
|
+
`)}
|
|
5
|
+
|
|
6
|
+
${z}`}const B="notifications/mirasim-computer-use/revoke",g="mirasim-computer-use/preview",K=`${g}/watch`,W=4*1024*1024,X=15*6e4;function J(){let s=null;const a=[];return{consent:{available:()=>s?.getClientCapabilities()?.elicitation?.form!==void 0,ask:async(o,p)=>{const c=await s.elicitInput({mode:"form",message:o,requestedSchema:{type:"object",properties:{}},_meta:p},{timeout:X}),n=c._meta,m=n?.["mirasim-computer-use/reason"],l=n?.persist==="session"||n?.persist==="always"?n.persist:void 0;return{allowed:c.action==="accept",...l?{persist:l}:{},...typeof m=="string"&&m?{reason:m}:{}}},onRevoke:o=>{a.push(o)}},attach:o=>{s=o,o.fallbackNotificationHandler=async p=>{if(p.method!==B)return;const c=p.params?.ids;if(Array.isArray(c))for(const n of a)n(c.filter(m=>typeof m=="string"))}}}}async function se(){const s=J(),a=F({diagnostics:process.env.COMPUTER_USE_DIAGNOSTICS!=="0",consent:s.consent}),o=a.tools,p=V(),c=new Set,n=new P({name:"mirasim-cu",version:R()},{capabilities:{tools:{},experimental:{[g]:{version:1}}},instructions:j(a)});s.attach(n);const m=(e,t)=>{n.notification({method:`notifications/${g}/${e}`,params:t}).catch(()=>{})};let l=null;n.oninitialized=()=>{if(!n.getClientCapabilities()?.experimental?.[g])return;const e=new H({targets:t=>m("targets",{targets:t}),frame:(t,i)=>{process.stdout.writableLength<W&&m("frame",{...t,...i})},status:(t,i)=>m("status",{...t,...i})});for(const t of a.drivers)t.onPreview=(i,f)=>e.publish(i,f);s.consent.onRevoke(t=>e.revoke(t)),l=e},n.fallbackRequestHandler=async e=>{if(e.method!==K||!l)throw new D(L.MethodNotFound,`Method not found: ${e.method}`);const t=e.params??{},i=(Array.isArray(t.targets)?t.targets:[]).flatMap(f=>{const u=f;return(u.kind==="browser"||u.kind==="electron"||u.kind==="macos")&&typeof u.targetId=="string"?[{kind:u.kind,targetId:u.targetId}]:[]});return l.watch(i,typeof t.maxSize=="number"?t.maxSize:void 0),{}},n.setRequestHandler(U,async()=>({tools:o.map(e=>({name:e.name,description:e.description,inputSchema:e.parameters}))}));let _=!1;n.setRequestHandler(G,async e=>{const t=Date.now(),i=e.params.arguments??{};if(_)return{content:[{type:"text",text:"Turn cleanup is in progress; no new operation was started. Rebind after cleanup."}],isError:!0};const f=e.params._meta?.["mirasim-computer-use/previewTask"];if(e.params.name!=="turn_ended"&&l?.setTaskId(typeof f=="string"?f:null),e.params.name==="turn_ended"){const r=i,d=typeof r.session_id=="string"?r.session_id:"",w=typeof r.turn_id=="string"?r.turn_id:"",k=typeof r.hook_event_name=="string"?r.hook_event_name:"turn_ended",T=r.keep_browser_tabs===!0;if(!d||!w)return{content:[{type:"text",text:"turn_ended needs session_id and turn_id"}],isError:!0};const I=`${d}\0${w}`;if(c.has(I))return{content:[{type:"text",text:"turn_ended already applied"}]};const C=o.find(y=>y.name==="computer_repl_reset");_=!0;try{await C?.execute({waitForIdle:!0});for(const y of a.drivers)await y.turnEnded({sessionId:d,turnId:w,hookEventName:k,keepBrowserTabs:T}),await y.close();return c.add(I),c.size>512&&c.delete(c.values().next().value),p({type:"turn_ended",session_id:d,turn_id:w,hook_event_name:k,keep_browser_tabs:T}),{content:[{type:"text",text:`turn_ended applied (${k})`}]}}catch(y){return{content:[{type:"text",text:`turn_ended failed: ${y.message}`}],isError:!0}}finally{_=!1}}const u=e.params.name,v=o.find(r=>r.name===u);if(!v)return p({type:"call",tool:e.params.name,args:i,isError:!0,ms:0,details:{error:"unknown_tool"}}),{content:[{type:"text",text:`unknown tool: ${e.params.name}`}],isError:!0};try{const r=await v.execute(i);return p({type:"call",tool:v.name,args:i,isError:typeof r.details.error=="string",ms:Date.now()-t,details:r.details}),{content:r.content.map(d=>d.type==="image"?{type:"image",data:d.data,mimeType:d.mimeType}:{type:"text",text:d.text}),...typeof r.details.error=="string"?{isError:!0}:{}}}catch(r){p({type:"call",tool:v.name,args:i,isError:!0,ms:Date.now()-t,details:{error:r.message,...r instanceof b?{surfaceGone:!0}:{}}});const d=r instanceof b?" The surface is gone (window closed / device detached) \u2014 stop; do not retry or recreate it.":"";return{content:[{type:"text",text:`error: ${r.message}${d}`}],isError:!0}}});const M=new N;await n.connect(M);let x=null;const h=e=>{_=!0,x??=(async()=>{try{await o.find(t=>t.name==="computer_repl_reset")?.execute({waitForIdle:!0})}catch{}l?.close(),await Promise.all(a.drivers.map(t=>t.close().catch(()=>{})))})(),x.then(()=>process.exit(e))};process.on("SIGINT",()=>h(0)),process.on("SIGTERM",()=>h(0));const E=()=>h(0);n.onclose=E,process.stdin.on("end",E),process.stdin.on("close",E);const S=a.drivers.map(e=>e.platform).join(",");p({type:"server_start",version:R(),platforms:S,tools:o.map(e=>e.name)}),console.error(`mirasim-cu MCP server on stdio (platforms=${S})`)}export{se as serveMcp};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ownVersion(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as n}from"node:fs";function e(){try{const r=JSON.parse(n(new URL("../../package.json",import.meta.url),"utf8"));return String(r.version??"0.0.0")}catch{return"0.0.0"}}export{e as ownVersion};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { TOOL_NAMES, type ActResult, type Element, type ComputerUseToolSpec, type HeaderChanges, type ObservationCoverage, type OwnershipResource, type Snapshot, type SnapshotCapture, type TargetInfo, type TargetIdentity, type ToolResult, type VerbSpec, type Verdict, } from "./platform/types.ts";
|
|
2
|
+
export { ComputerUseDriver } from "./platform/driver.ts";
|
|
3
|
+
export { createComputerUseTools } from "./platform/tools/index.ts";
|
|
4
|
+
export { createReplTools } from "./platform/tools/repl.ts";
|
|
5
|
+
export { resolveProfile, type Profile, type ProfileOptions } from "./platform/profile.ts";
|
|
6
|
+
export type { OwnershipProvider } from "./platform/ownership.ts";
|
|
7
|
+
export type { BrowserConfig, BrowserConfigOptions } from "./platform/browser/config.ts";
|
|
8
|
+
export { BrowserDriver } from "./platform/browser/driver.ts";
|
|
9
|
+
export { BridgeServer, type BridgeServerOptions } from "./platform/browser/bridge/server.ts";
|
|
10
|
+
export { MIRASIM_EXTENSION_ID, extensionDir, extensionIdFromKey } from "./platform/browser/bridge/extension-id.ts";
|
|
11
|
+
export { MacosDriver } from "./platform/macos/driver.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{TOOL_NAMES as o}from"./platform/types.js";import{ComputerUseDriver as m}from"./platform/driver.js";import{createComputerUseTools as x}from"./platform/tools/index.js";import{createReplTools as s}from"./platform/tools/repl.js";import{resolveProfile as l}from"./platform/profile.js";import{BrowserDriver as D}from"./platform/browser/driver.js";import{BridgeServer as n}from"./platform/browser/bridge/server.js";import{MIRASIM_EXTENSION_ID as S,extensionDir as T,extensionIdFromKey as a}from"./platform/browser/bridge/extension-id.js";import{MacosDriver as E}from"./platform/macos/driver.js";export{n as BridgeServer,D as BrowserDriver,m as ComputerUseDriver,S as MIRASIM_EXTENSION_ID,E as MacosDriver,o as TOOL_NAMES,x as createComputerUseTools,s as createReplTools,T as extensionDir,a as extensionIdFromKey,l as resolveProfile};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Browser } from "playwright-core";
|
|
2
|
+
import { type BrowserConfig } from "./config.ts";
|
|
3
|
+
export { pingDevTools, readDevToolsPort } from "./devtools-port.ts";
|
|
4
|
+
export { chromeMissingError, findChrome, isAttachedProfile } from "./chrome-binary.ts";
|
|
5
|
+
export { actionsFileFor, endpointFileFor, publishTabIdentity, shotsDirFor } from "./session-files.ts";
|
|
6
|
+
import { browserPids, killByProfileDir } from "./occupancy.ts";
|
|
7
|
+
export declare function openBlankTab(cdpUrl: string): Promise<boolean>;
|
|
8
|
+
export { browserPids, killByProfileDir };
|
|
9
|
+
export { keepInBackground, revealFlagFor, userWantsVisible } from "./window-placement.ts";
|
|
10
|
+
export declare function openManagedBrowser(profileDir?: string, cfg?: BrowserConfig): Promise<void>;
|
|
11
|
+
export declare function acquireManagedBrowser(profileDir?: string, cfg?: BrowserConfig): Promise<{
|
|
12
|
+
browser: Browser;
|
|
13
|
+
cdpUrl: string;
|
|
14
|
+
profileDir: string;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawn as E}from"node:child_process";import{mkdirSync as v,rmSync as d}from"node:fs";import{join as w}from"node:path";import{connectBrowserCdp as x}from"./cdp-connection.js";import{browserConfigFromEnv as b}from"./config.js";import{pingDevTools as P,readDevToolsPort as A,waitForDevToolsPort as C}from"./devtools-port.js";import{pingDevTools as ft,readDevToolsPort as gt}from"./devtools-port.js";import{chromeMissingError as S,findChrome as I,needsNoSandbox as F,needsShmFallback as N}from"./chrome-binary.js";import{publishEndpoint as h}from"./session-files.js";import{chromeMissingError as yt,findChrome as bt,isAttachedProfile as Tt}from"./chrome-binary.js";import{actionsFileFor as Et,endpointFileFor as vt,publishTabIdentity as xt,shotsDirFor as Pt}from"./session-files.js";import{ensureBackgroundTab as _,newBackgroundPage as O}from"./tabs.js";import{browserPids as T,killByProfileDir as u}from"./occupancy.js";import{OFFSCREEN_POSITION as W,keepInBackground as $,parkWindowOffscreen as B,unparkWindow as M,userWantsVisible as j}from"./window-placement.js";import{msgAttachedDeadEnd as U,msgAttachedWhyHandshake as L,msgAttachedWhyNoPage as R,msgAttachedWhyNoPort as G,msgChromeBinaryUnrunnable as H,msgChromeExitedImmediately as K,msgChromeNoPort as V,msgChromeRefusedAttach as q,msgChromeStartFailed as z}from"./messages.js";const k=3e3,Z=5e3,J=15e3,Q="1440,900";async function X(t){try{const e=await fetch(`${t.replace(/\/$/,"")}/json/list`,{signal:AbortSignal.timeout(2e3)});if(!e.ok)return!1;const r=await e.json();return!Array.isArray(r)||r.some(a=>a.type==="page")?!1:(await fetch(`${t.replace(/\/$/,"")}/json/new?about:blank`,{method:"PUT",signal:AbortSignal.timeout(2e3)})).ok}catch{return!1}}async function Y(t){try{const e=await fetch(`${t.replace(/\/$/,"")}/json/list`);return e.ok?(await e.json()).some(o=>o.type==="page"&&!String(o.url??"").startsWith("devtools://")):!1}catch{return!1}}import{keepInBackground as Ct,revealFlagFor as St,userWantsVisible as It}from"./window-placement.js";async function mt(t,e=b()){t??=e.profileDir;const{browser:r}=await D(t,e);try{const o=r.contexts()[0]??await r.newContext(),a=o.pages().find(n=>!n.isClosed())??await O(o);if(j(t))return;await $(o,a,t,e)}finally{await r.close().catch(()=>{})}}async function l(t,e){try{return await x(t,e)}catch{return null}}async function D(t,e=b()){t??=e.profileDir;const r=e.attached;v(t,{recursive:!0});const o=A(t);if(o!==null&&await P(o)){const a=`http://127.0.0.1:${o}`;if(!await Y(a)){if(r){await X(a);const c=await l(a,k);if(c)return await h(t,o,null,e),{browser:c,cdpUrl:a,profileDir:t};throw f(t,R())}return await u(t),d(w(t,"DevToolsActivePort"),{force:!0}),await g(t,e)}const n=await l(a,k);if(n)return await h(t,o,null,e),{browser:n,cdpUrl:a,profileDir:t};if(r)throw f(t,L());await u(t),d(w(t,"DevToolsActivePort"),{force:!0})}try{return await g(t,e)}catch(a){if(!(await T(t)).length)throw a;if(r)throw f(t,G());return await u(t),d(w(t,"DevToolsActivePort"),{force:!0}),await g(t,e)}}function f(t,e){return new Error(U(t,e))}async function g(t,e){const r=I(e);if(!r)throw S();d(w(t,"DevToolsActivePort"),{force:!0});const o=e.window==="offscreen"&&!e.attached,a=[`--user-data-dir=${t}`,"--remote-debugging-port=0","--no-first-run","--no-default-browser-check",...F()?["--no-sandbox"]:[],...N()?["--disable-dev-shm-usage"]:[],...e.attached?[]:process.platform==="darwin"?["--use-mock-keychain"]:process.platform==="linux"?["--password-store=basic"]:[],`--window-size=${Q}`,...o?[`--window-position=${W}`]:[],"--silent-launch"],n=E(r,a,{stdio:"ignore",detached:!0});n.unref();let c=!1;const p={e:null};n.once("exit",()=>{c=!0}),n.once("error",s=>{p.e=s,c=!0});const m=await C(t,J,()=>c);if(m===null){try{n.kill("SIGKILL")}catch{}const s=p.e;throw s?new Error(s.code==="ENOENT"||s.code==="EACCES"?H(r,s.code):z(s.code??s.message)):new Error(c?K():V())}const y=`http://127.0.0.1:${m}`,i=await l(y,Z);if(!i){try{n.kill("SIGKILL")}catch{}throw new Error(q())}return await _(i),o?await B(i):await M(i),await h(t,m,n.pid??null,e),{browser:i,cdpUrl:y,profileDir:t}}export{D as acquireManagedBrowser,Et as actionsFileFor,T as browserPids,yt as chromeMissingError,vt as endpointFileFor,bt as findChrome,Tt as isAttachedProfile,Ct as keepInBackground,u as killByProfileDir,X as openBlankTab,mt as openManagedBrowser,ft as pingDevTools,xt as publishTabIdentity,gt as readDevToolsPort,St as revealFlagFor,Pt as shotsDirFor,It as userWantsVisible};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function acquireBridge(home: string): Promise<{
|
|
2
|
+
cdpUrl: string;
|
|
3
|
+
fresh: boolean;
|
|
4
|
+
}>;
|
|
5
|
+
export declare function extensionHeldElsewhere(home: string): Promise<string | null>;
|
|
6
|
+
export declare function waitForExtension(cdpUrl: string, ms: number, home?: string): Promise<boolean>;
|
|
7
|
+
export declare function bridgeJustStarted(home: string, ms: number): boolean;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{spawn as x}from"node:child_process";import s from"node:fs";import a from"node:path";import{defaultBridgeSocket as b,recordedBridges as T}from"./native-host.js";const S=3e4,U=6e4,E=35e3;function w(e){return a.join(e,"bridge.json")}function p(e){try{const n=JSON.parse(s.readFileSync(e,"utf8"));return typeof n.cdpUrl=="string"?n:null}catch{return null}}async function y(e){try{const n=await fetch(`${e}/status`,{signal:AbortSignal.timeout(1500)});return n.ok?{answering:!0,connected:(await n.json()).extensionConnected===!0}:{answering:!1,connected:!1}}catch{return{answering:!1,connected:!1}}}async function M(e){const n=w(e),o=async()=>{const r=p(n);return r&&(await y(r.cdpUrl)).answering?r.cdpUrl:null},i=await o();if(i)return{cdpUrl:i,fresh:!1};s.mkdirSync(e,{recursive:!0});const t=a.join(e,"bridge.lock");if(!h(t)){const r=Date.now()+S;for(;Date.now()<r&&s.existsSync(t);){await new Promise(d=>setTimeout(d,300));const c=await o();if(c)return{cdpUrl:c,fresh:!1}}if(!h(t))throw new Error(`another process is starting the browser bridge (${t}) and has not finished`)}try{const r=await o();if(r)return{cdpUrl:r,fresh:!1};const c=await O(e);return s.writeFileSync(n,`${JSON.stringify(c,null,2)}
|
|
2
|
+
`),s.rmSync(t,{force:!0}),await v(c.cdpUrl,E,e),{cdpUrl:c.cdpUrl,fresh:!0}}finally{s.rmSync(t,{force:!0})}}async function _(e){if(process.platform==="win32")return null;for(const{owner:n,socket:o}of T()){const i=a.dirname(o);if(a.resolve(i)===a.resolve(e))continue;const t=p(w(i));if(t&&(await y(t.cdpUrl)).connected)return n}return null}async function v(e,n,o){const i=Date.now()+n;for(;;){const{answering:t,connected:r}=await y(e);if(r||!t)return r||!t;if(Date.now()>=i||o&&await _(o))return!1;await new Promise(c=>setTimeout(c,500))}}function C(e,n){const o=p(w(e));return typeof o?.startedAt=="number"&&Date.now()-o.startedAt<n}function h(e){try{return s.closeSync(s.openSync(e,"wx")),!0}catch{try{if(Date.now()-s.statSync(e).mtimeMs>U)return s.rmSync(e,{force:!0}),s.closeSync(s.openSync(e,"wx")),!0}catch{}return!1}}async function O(e){const n=process.argv[1];if(!n)throw new Error("cannot start the browser bridge: this process was not started from the computer-use CLI");const o={...process.env,COMPUTER_USE_HOME:e},i=s.openSync(a.join(e,"bridge.log"),"a"),t=x(process.execPath,[...process.execArgv,n,"bridge","--json","--native-host"],{detached:!0,windowsHide:!0,stdio:["ignore","pipe",i],env:o});s.closeSync(i);try{const r=await new Promise((c,d)=>{let l="";const f=setTimeout(()=>d(new Error("no status line")),S);t.stdout.on("data",u=>{l+=u.toString();const g=l.indexOf(`
|
|
3
|
+
`);if(!(g<0)){clearTimeout(f);try{c(JSON.parse(l.slice(0,g)))}catch(m){d(m)}}}),t.once("error",u=>{clearTimeout(f),d(u)}),t.once("exit",u=>{clearTimeout(f),d(new Error(`exited ${u}`))})});return{cdpUrl:r.cdpUrl,extensionId:r.extensionId,extensionIds:r.extensionIds,pid:t.pid??0,socketPath:b(o),startedAt:Date.now()}}catch(r){try{t.kill()}catch{}throw new Error(`the browser bridge did not start (${r instanceof Error?r.message:String(r)}); see ${a.join(e,"bridge.log")}`)}finally{t.stdout?.destroy(),t.unref()}}export{M as acquireBridge,C as bridgeJustStarted,_ as extensionHeldElsewhere,v as waitForExtension};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type RuntimeDomain } from "./runtime-contexts.ts";
|
|
2
|
+
export interface BridgeTab {
|
|
3
|
+
id?: number;
|
|
4
|
+
url?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
discarded?: boolean;
|
|
7
|
+
status?: string;
|
|
8
|
+
windowId?: number;
|
|
9
|
+
splitViewId?: number;
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
active?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function tabIsUnloaded(tab: BridgeTab): boolean;
|
|
15
|
+
export interface TabAttachment {
|
|
16
|
+
tabId: number;
|
|
17
|
+
targetInfo: {
|
|
18
|
+
targetId: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
runtimes: Map<string, RuntimeDomain>;
|
|
22
|
+
}
|
|
23
|
+
export type CdpMessage = {
|
|
24
|
+
id?: number;
|
|
25
|
+
sessionId?: string;
|
|
26
|
+
method?: string;
|
|
27
|
+
params?: unknown;
|
|
28
|
+
result?: unknown;
|
|
29
|
+
error?: {
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare const STAND_IN_PREFIX = "mirasim-tab-";
|
|
34
|
+
export declare const FAKE_WINDOW: {
|
|
35
|
+
windowId: number;
|
|
36
|
+
bounds: {
|
|
37
|
+
left: number;
|
|
38
|
+
top: number;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
windowState: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare class BridgeClient {
|
|
45
|
+
private readonly sendMessage;
|
|
46
|
+
readonly id: number;
|
|
47
|
+
autoAttach: boolean;
|
|
48
|
+
readonly sessionByTabId: Map<number, string>;
|
|
49
|
+
readonly tabBySessionId: Map<string, number>;
|
|
50
|
+
readonly virtualSessions: Map<string, number>;
|
|
51
|
+
readonly browserSessions: Set<string>;
|
|
52
|
+
private nextSession;
|
|
53
|
+
private readonly runtimes;
|
|
54
|
+
private readonly initializedFrames;
|
|
55
|
+
private readonly frameReplies;
|
|
56
|
+
private readonly pendingFrames;
|
|
57
|
+
constructor(id: number, sendMessage: (message: CdpMessage) => void);
|
|
58
|
+
trackFrameTree(id: number, sessionId: string): void;
|
|
59
|
+
send(message: CdpMessage): void;
|
|
60
|
+
enableRuntime(sessionId: string): boolean;
|
|
61
|
+
disableRuntime(sessionId: string): void;
|
|
62
|
+
runtimeEvent(sessionId: string, method: string, params: unknown, replay?: boolean): void;
|
|
63
|
+
forgetSession(sessionId: string): void;
|
|
64
|
+
dispose(): void;
|
|
65
|
+
tabAlias(tabId: number): string;
|
|
66
|
+
virtualAlias(tabId: number): string;
|
|
67
|
+
browserAlias(): string;
|
|
68
|
+
dropTab(tabId: number): string | null;
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{RuntimeContexts as d}from"./runtime-contexts.js";function h(n){return n.discarded===!0||n.status==="unloaded"}const l="mirasim-tab-",u={windowId:1,bounds:{left:0,top:0,width:1440,height:900,windowState:"normal"}};class m{sendMessage;id;autoAttach=!1;sessionByTabId=new Map;tabBySessionId=new Map;virtualSessions=new Map;browserSessions=new Set;nextSession=0;runtimes=new Map;initializedFrames=new Set;frameReplies=new Map;pendingFrames=new Map;constructor(e,i){this.sendMessage=i,this.id=e}trackFrameTree(e,i){this.initializedFrames.has(i)||this.runtimes.has(i)||(this.frameReplies.set(e,i),this.pendingFrames.has(i)||this.pendingFrames.set(i,new d))}send(e){if(this.sendMessage(e),e.id===void 0)return;const i=this.frameReplies.get(e.id);if(i===void 0)return;this.frameReplies.delete(e.id);const t=this.pendingFrames.get(i);this.pendingFrames.delete(i),e.error||this.initializedFrames.add(i);for(const s of t?.values()??[])this.sendMessage({sessionId:i,method:"Runtime.executionContextCreated",params:s})}enableRuntime(e){return this.runtimes.has(e)?!1:(this.runtimes.set(e,new d),!0)}disableRuntime(e){this.runtimes.delete(e),this.pendingFrames.get(e)?.clear()}runtimeEvent(e,i,t,s=!1){const r=this.runtimes.get(e);if(!r||s&&r.has(t))return;r.update(i,t);const a=this.pendingFrames.get(e);a?.update(i,t),!(a&&i==="Runtime.executionContextCreated")&&this.send({sessionId:e,method:i,params:t})}forgetSession(e){this.disableRuntime(e),this.initializedFrames.delete(e),this.pendingFrames.delete(e);for(const[i,t]of this.frameReplies)t===e&&this.frameReplies.delete(i)}dispose(){this.runtimes.clear(),this.initializedFrames.clear(),this.pendingFrames.clear(),this.frameReplies.clear()}tabAlias(e){let i=this.sessionByTabId.get(e);return i||(i=`mir-c${this.id}-t${++this.nextSession}`,this.sessionByTabId.set(e,i),this.tabBySessionId.set(i,e)),i}virtualAlias(e){const i=`mir-c${this.id}-v${++this.nextSession}`;return this.virtualSessions.set(i,e),i}browserAlias(){const e=`mir-c${this.id}-b${++this.nextSession}`;return this.browserSessions.add(e),e}dropTab(e){const i=this.sessionByTabId.get(e)??null;i&&(this.forgetSession(i),this.sessionByTabId.delete(e),this.tabBySessionId.delete(i));for(const[t,s]of this.virtualSessions)s===e&&(this.forgetSession(t),this.virtualSessions.delete(t));return i}}export{m as BridgeClient,u as FAKE_WINDOW,l as STAND_IN_PREFIX,h as tabIsUnloaded};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Duplex } from "node:stream";
|
|
2
|
+
import { WebSocket } from "ws";
|
|
3
|
+
export interface ExtensionChannel {
|
|
4
|
+
readonly kind: "ws" | "native";
|
|
5
|
+
readonly isOpen: boolean;
|
|
6
|
+
send(text: string): void;
|
|
7
|
+
close(reason: string): void;
|
|
8
|
+
onMessage(cb: (text: string) => void): void;
|
|
9
|
+
onClose(cb: () => void): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function webSocketChannel(ws: WebSocket): ExtensionChannel;
|
|
12
|
+
export declare function socketChannel(socket: Duplex, onError: (e: Error) => void): ExtensionChannel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{WebSocket as d}from"ws";import{BROWSER_TO_HOST_MAX as c,encodeFrame as f,FrameDecoder as S,HOST_TO_BROWSER_MAX as u}from"./native-frames.js";function g(e){return{kind:"ws",get isOpen(){return e.readyState===d.OPEN},send:r=>e.send(r),close:r=>{e.readyState===d.OPEN&&e.close(1e3,r)},onMessage:r=>e.on("message",a=>r(a.toString())),onClose:r=>{e.on("close",r),e.on("error",r)}}}function p(e,r){const a=new S(c);let s=!0;const i=()=>{s=!1};return e.on("close",i),e.on("error",i),{kind:"native",get isOpen(){return s&&e.writable},send:n=>{try{e.write(f(n,u))}catch(o){r(o instanceof Error?o:new Error(String(o)))}},close:()=>{s=!1,e.destroy()},onMessage:n=>{e.on("data",o=>{let l;try{l=a.push(o)}catch(t){r(t instanceof Error?t:new Error(String(t))),e.destroy();return}for(const t of l)n(t)})},onClose:n=>{e.on("close",n),e.on("error",n)}}}export{p as socketChannel,g as webSocketChannel};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function extensionManifest(): {
|
|
2
|
+
key: string;
|
|
3
|
+
version: string;
|
|
4
|
+
version_name?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const MIRASIM_EXTENSION_ID: string;
|
|
7
|
+
export declare function extensionIdFromKey(manifestKeyBase64: string): string;
|
|
8
|
+
export declare function extensionDir(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as s}from"node:crypto";import{existsSync as a,readFileSync as f}from"node:fs";import{dirname as i,join as r}from"node:path";import{fileURLToPath as m}from"node:url";function c(){return JSON.parse(f(r(p(),"manifest.json"),"utf8"))}const b=d(c().key);function d(e){const t=Buffer.from(e,"base64");return[...s("sha256").update(t).digest().subarray(0,16)].map(n=>"abcdefghijklmnop"[n>>4]+"abcdefghijklmnop"[n&15]).join("")}function p(){let e=i(m(import.meta.url));for(let t=0;t<6;t++){const o=r(e,"extension");if(a(r(o,"manifest.json")))return o;e=i(e)}throw new Error("bridge extension directory not found beside the computer-use build (packaging bug)")}export{b as MIRASIM_EXTENSION_ID,p as extensionDir,d as extensionIdFromKey,c as extensionManifest};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ExtensionRuntimeInfo {
|
|
2
|
+
id: string;
|
|
3
|
+
version: string;
|
|
4
|
+
build: string | null;
|
|
5
|
+
protocol: number;
|
|
6
|
+
capabilities: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function parseExtensionRuntime(value: unknown): ExtensionRuntimeInfo | null;
|
|
9
|
+
export declare class ExtensionUpdates {
|
|
10
|
+
private readonly expected;
|
|
11
|
+
private readonly busy;
|
|
12
|
+
private readonly reload;
|
|
13
|
+
runtime: ExtensionRuntimeInfo | null;
|
|
14
|
+
updateVersion: string | null;
|
|
15
|
+
pending: boolean;
|
|
16
|
+
reloading: boolean;
|
|
17
|
+
error: string | null;
|
|
18
|
+
private timer;
|
|
19
|
+
private reconnectTimer;
|
|
20
|
+
private generation;
|
|
21
|
+
constructor(expected: {
|
|
22
|
+
version: string;
|
|
23
|
+
version_name?: string;
|
|
24
|
+
}, busy: () => boolean, reload: () => Promise<unknown>);
|
|
25
|
+
status(connected: boolean): {
|
|
26
|
+
version: string | null;
|
|
27
|
+
expectedVersion: string;
|
|
28
|
+
compatibility: string;
|
|
29
|
+
canReload: boolean;
|
|
30
|
+
updateVersion: string | null;
|
|
31
|
+
reloadPending: boolean;
|
|
32
|
+
error: string | null;
|
|
33
|
+
};
|
|
34
|
+
request(): void;
|
|
35
|
+
schedule(): void;
|
|
36
|
+
reset(): void;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function l(n){if(!n||typeof n!="object")return null;const i=n;return typeof i.id!="string"||!/^[a-p]{32}$/.test(i.id)||typeof i.version!="string"||!/^\d+(\.\d+){0,3}$/.test(i.version)||!Number.isInteger(i.protocol)||!Array.isArray(i.capabilities)?null:{id:i.id,version:i.version,build:typeof i.build=="string"?i.build:null,protocol:i.protocol,capabilities:i.capabilities.filter(e=>typeof e=="string")}}function o(n,i){const e=n.split(".").map(Number),r=i.split(".").map(Number);for(let t=0;t<4;t++)if((e[t]??0)!==(r[t]??0))return(e[t]??0)-(r[t]??0);return 0}class a{expected;busy;reload;runtime=null;updateVersion=null;pending=!1;reloading=!1;error=null;timer=null;reconnectTimer=null;generation=0;constructor(i,e,r){this.expected=i,this.busy=e,this.reload=r}status(i){const e=this.runtime,r=e?o(e.version,this.expected.version):0,t=i?e&&e.protocol>1?"app-update-required":r<0?"update-required":!e||e.protocol!==1||!["discarded-tabs","safe-reload"].every(s=>e.capabilities.includes(s))||r===0&&e.build&&this.expected.version_name&&e.build!==this.expected.version_name?"reload-required":"ready":"unknown";return{version:e?.version??null,expectedVersion:this.expected.version,compatibility:t,canReload:!!e?.capabilities.includes("safe-reload"),updateVersion:this.updateVersion,reloadPending:this.pending||this.reloading,error:this.error}}request(){if(!this.runtime?.capabilities.includes("safe-reload"))throw new Error("Reload the Mirasim extension from your browser\u2019s extensions page, then check its connection again.");this.pending=!0,this.error=null,this.schedule()}schedule(){!this.pending||this.reloading||this.timer||(this.timer=setTimeout(()=>{if(this.timer=null,this.busy()){this.schedule();return}this.reloading=!0,this.pending=!1;const i=this.generation;this.reload().then(()=>{i===this.generation&&(this.reconnectTimer=setTimeout(()=>{this.reloading=!1,this.error="The Mirasim extension did not reconnect after reloading. Check its extension page and that the browser bridge is running."},15e3),this.reconnectTimer.unref())}).catch(e=>{i===this.generation&&(this.reloading=!1,this.error=e instanceof Error?e.message:String(e))})},250),this.timer.unref())}reset(){this.generation+=1,this.timer&&clearTimeout(this.timer),this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.timer=null,this.runtime=null,this.updateVersion=null,this.pending=!1,this.reloading=!1,this.error=null}}export{a as ExtensionUpdates,l as parseExtensionRuntime};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BridgeClient } from "./client.ts";
|
|
2
|
+
import { BridgeModelCore } from "./model-core.ts";
|
|
3
|
+
export declare abstract class BridgeModelCommands extends BridgeModelCore {
|
|
4
|
+
private readonly restoringTabs;
|
|
5
|
+
handleCommand(client: BridgeClient, method: string, params: unknown, sessionId: string | undefined): Promise<unknown>;
|
|
6
|
+
private enableAutoAttach;
|
|
7
|
+
protected reconcileKnownTabs(): Promise<void>;
|
|
8
|
+
private assertBrowserSession;
|
|
9
|
+
private tabTarget;
|
|
10
|
+
private restoreTab;
|
|
11
|
+
createTarget(url: string | undefined): Promise<{
|
|
12
|
+
targetId: string;
|
|
13
|
+
}>;
|
|
14
|
+
recycleAgentTabs(): Promise<{
|
|
15
|
+
closed: number;
|
|
16
|
+
}>;
|
|
17
|
+
private closeTarget;
|
|
18
|
+
private attachToTarget;
|
|
19
|
+
private sendBrowserCommand;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{FAKE_WINDOW as b,tabIsUnloaded as w}from"./client.js";import{BridgeModelCore as g}from"./model-core.js";import{hostname as f}from"node:os";class p extends g{restoringTabs=new Map;async handleCommand(e,s,t,r){if(r&&e.browserSessions.has(r))return await this.handleCommand(e,s,t,void 0);const n=t??{};switch(s){case"Mirasim.tabs":return{tabs:await this.listTargets(),browserSession:this.browserSession};case"Mirasim.tabTarget":return{targetId:await this.tabTarget(Number(n.tabId),String(n.browserSession??""))};case"Mirasim.restoreTab":return await this.restoreTab(Number(n.tabId),String(n.targetId??""),String(n.browserSession??""));case"Browser.getVersion":return{protocolVersion:"1.3",product:"Chrome/mirasim-bridge",userAgent:"mirasim-bridge/1.0"};case"Browser.setDownloadBehavior":return{};case"Mirasim.downloads":{if(typeof n.since!="string"||!Number.isFinite(Date.parse(n.since)))throw new Error("Downloads require an ISO start time");if(n.until!==void 0&&(typeof n.until!="string"||!Number.isFinite(Date.parse(n.until))))throw new Error("Downloads require an ISO end time");const a=await this.sendToExtension("chrome.downloads.search",[{startedAfter:n.since,...n.until===void 0?{}:{startedBefore:n.until}}]);return{host:f(),items:a}}case"Browser.getWindowForTarget":return structuredClone(b);case"Browser.setWindowBounds":return{};case"Mirasim.attachRefusals":{const a=Date.now()-6e4;return{refusals:[...this.attachRefusals.values()].filter(o=>o.at>=a).map(({url:o,reason:h})=>({url:o,reason:h}))}}case"Browser.close":throw new Error("Browser.close is not available on the mirasim bridge \u2014 the browser is the user's own");case"Target.setAutoAttach":if(!r)return await this.enableAutoAttach(e),{};break;case"Target.createTarget":return await this.createTarget(typeof n.url=="string"?n.url:void 0);case"Target.closeTarget":return await this.closeTarget(typeof n.targetId=="string"?n.targetId:void 0);case"Target.attachToTarget":if(!r)return await this.attachToTarget(e,typeof n.targetId=="string"?n.targetId:void 0);break;case"Target.attachToBrowserTarget":if(!r)return{sessionId:e.browserAlias()};break;case"Runtime.enable":{if(!r)throw new Error("Runtime.enable requires a target session");const a=this.resolveSession(e,r),o=this.runtimeForSession(a.tabId,a.cdpSessionId),h=e.enableRuntime(r);try{const c=await o.enable(()=>this.sendToExtension("chrome.debugger.sendCommand",[{tabId:a.tabId,...a.cdpSessionId?{sessionId:a.cdpSessionId}:{}},s,...t===void 0?[]:[t]]));if(h)for(const i of o.values())e.runtimeEvent(r,"Runtime.executionContextCreated",i,!0);return c}catch(c){throw h&&e.disableRuntime(r),c}}case"Runtime.disable":if(!r)throw new Error("Runtime.disable requires a target session");return this.resolveSession(e,r),e.disableRuntime(r),{};case"Target.detachFromTarget":{const a=typeof n.sessionId=="string"?n.sessionId:void 0,o=a?e.virtualSessions.get(a):void 0;if(a&&o!==void 0)return e.virtualSessions.delete(a),e.forgetSession(a),this.releaseUnusedTab(o),{};if(a&&e.browserSessions.delete(a))return{};const h=a?this.childSessionOwner.get(a):void 0;if(a&&h===void 0)return{};if(a&&h!==void 0)return await this.sendToExtension("chrome.debugger.sendCommand",[{tabId:h},s,{sessionId:a}]);break}}if(!r)return await this.sendBrowserCommand(s,t);const d=this.resolveSession(e,r);return await this.sendToExtension("chrome.debugger.sendCommand",[{tabId:d.tabId,...d.cdpSessionId?{sessionId:d.cdpSessionId}:{}},s,...t===void 0?[]:[t]])}async enableAutoAttach(e){e.autoAttach=!0,await this.reconcileKnownTabs();const s=[...this.knownTabs].filter(([,t])=>!w(t)).map(([t])=>t);await Promise.all(s.map(t=>this.attachAndAnnounce(e,t).catch(r=>this.log("attach failed:",r))))}async reconcileKnownTabs(){let e;try{e=await this.sendToExtension("chrome.tabs.query",[{}])??[]}catch(t){this.log("tab reconcile failed:",t);return}const s=new Map(e.filter(t=>t.id!==void 0).map(t=>[t.id,t]));for(const t of[...this.knownTabs.keys()]){const r=s.get(t);if(!r)this.knownTabs.delete(t),this.agentTabs.delete(t),this.dropTab(t);else{const n=w(this.knownTabs.get(t));if(this.knownTabs.set(t,r),w(r)&&this.attachments.has(t))this.dropTab(t),this.sendToExtension("bridge.releaseTab",[t]).catch(d=>this.log("release unloaded tab failed:",d));else if(n&&!w(r))for(const d of this.clients)d.autoAttach&&this.attachAndAnnounce(d,t).catch(a=>this.log("restored tab attach failed:",a))}}}assertBrowserSession(e){if(!e||!this.browserSession)throw new Error("Reload the Mirasim extension before restoring tabs: this connection has no browser-session identity.");if(e!==this.browserSession)throw new Error("The browser restarted; list tabs and bind the intended target again.")}async tabTarget(e,s){if(this.assertBrowserSession(s),await this.reconcileKnownTabs(),!this.knownTabs.has(e))throw new Error(`Tab ${e} was closed; list tabs again.`);let t;try{t=await this.sendToExtension("chrome.debugger.getTargets",[])}catch(n){throw String(n).includes("Unknown method")?new Error("Reload the Mirasim extension to enable restoring unloaded tabs."):n}const r=t.find(n=>n.tabId===e);if(this.assertBrowserSession(s),!r?.id)throw new Error(`Chrome did not identify tab ${e}; refusing to restore an unknown target.`);return r.id}restoreTab(e,s,t){this.assertBrowserSession(t);const r=`${t}:${e}`,n=this.restoringTabs.get(r);if(n)return n.then(a=>{if(a.targetId!==s)throw new Error("Tab identity changed; list and bind it again before acting.");return a});const d=(async()=>{if(!s)throw new Error("Restoring a tab requires its claimed target identity.");if(await this.tabTarget(e,t)!==s)throw new Error(`Tab ${e} changed identity before restoration; no reload was sent.`);const a=this.knownTabs.get(e);if(!a)throw new Error(`Tab ${e} was closed; list tabs again.`);if(w(a)){try{await this.sendToExtension("chrome.tabs.reload",[e])}catch(u){const l=u instanceof Error?u.message:String(u);throw new Error(l.includes("Unknown method")?"Reload the Mirasim extension to enable restoring unloaded tabs.":`Could not restore tab ${e}: ${l}`)}const i=Date.now()+1e4;for(;w(this.knownTabs.get(e)??{discarded:!0});){if(Date.now()>=i)throw new Error(`Tab ${e} remained unloaded after restoration; no action was sent to its page.`);if(await new Promise(u=>setTimeout(u,50)),await this.reconcileKnownTabs(),!this.knownTabs.has(e))throw new Error(`Tab ${e} closed while restoring; no replacement tab was opened.`)}}const o=await this.ensureAttached(e);if(o.targetInfo.targetId!==s)throw new Error(`Tab ${e} changed identity while restoring; list and bind it again before acting.`);for(const i of this.clients)i.autoAttach&&this.announce(i,o);const h=[...this.knownTabs.values()].filter(i=>i.windowId===a.windowId&&i.splitViewId===a.splitViewId&&(i.width??0)>0&&(i.height??0)>0),c=h.find(i=>i.id===e)??h.find(i=>i.active)??h[0];return{targetId:o.targetInfo.targetId,...c?{viewport:{width:c.width,height:c.height}}:{}}})();return this.restoringTabs.set(r,d),d.finally(()=>this.restoringTabs.delete(r)).catch(()=>{}),d}async createTarget(e){const s=await this.sendToExtension("chrome.tabs.create",[{url:e||"about:blank",active:!1}]);if(s?.id===void 0)throw new Error("Failed to create tab");this.knownTabs.set(s.id,s),this.agentTabs.add(s.id);const t=await this.ensureAttached(s.id);for(const r of this.clients)r.autoAttach&&this.announce(r,t);return{targetId:t.targetInfo.targetId}}async recycleAgentTabs(){await this.reconcileKnownTabs();const e=[...this.agentTabs].filter(t=>this.knownTabs.has(t));let s=0;for(const t of e){try{await this.sendToExtension("chrome.tabs.remove",[t]),s+=1}catch(r){this.log("recycle failed for tab",t,r)}this.knownTabs.delete(t),this.agentTabs.delete(t),this.dropTab(t)}return{closed:s}}async closeTarget(e){const s=e?this.tabIdForTarget(e):void 0;return s===void 0?{success:!1}:(await this.sendToExtension("chrome.tabs.remove",[s]),{success:!0})}async attachToTarget(e,s){const t=s?this.tabIdForTarget(s):void 0;if(t===void 0)throw new Error(`No target with id: ${s}`);return await this.ensureAttached(t),{sessionId:e.virtualAlias(t)}}async sendBrowserCommand(e,s){const t=this.attachments.values().next().value,r=t?.tabId??[...this.knownTabs].find(([,n])=>!w(n))?.[0];if(r===void 0&&e==="Target.getTargetInfo")return{targetInfo:{targetId:"mirasim-browser",type:"browser",title:"",url:"",attached:!0}};if(r===void 0)throw new Error(`No tab to forward browser-level command: ${e}`);return t||await this.ensureAttached(r),await this.sendToExtension("chrome.debugger.sendCommand",[{tabId:r},e,...s===void 0?[]:[s]])}}export{p as BridgeModelCommands};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type SendToExtension = (method: string, params: unknown[]) => Promise<unknown>;
|
|
2
|
+
import { BridgeClient, type BridgeTab, type TabAttachment, type CdpMessage } from "./client.ts";
|
|
3
|
+
import { RuntimeDomain } from "./runtime-contexts.ts";
|
|
4
|
+
export { BridgeClient, type BridgeTab, type TabAttachment } from "./client.ts";
|
|
5
|
+
export declare abstract class BridgeModelCore {
|
|
6
|
+
protected readonly sendToExtension: SendToExtension;
|
|
7
|
+
protected readonly log: (...args: unknown[]) => void;
|
|
8
|
+
protected abstract reconcileKnownTabs(): Promise<void>;
|
|
9
|
+
protected knownTabs: Map<number, BridgeTab>;
|
|
10
|
+
protected agentTabs: Set<number>;
|
|
11
|
+
protected browserSession: string | null;
|
|
12
|
+
protected attachments: Map<number, TabAttachment>;
|
|
13
|
+
private attaching;
|
|
14
|
+
protected childSessionOwner: Map<string, number>;
|
|
15
|
+
protected attachRefusals: Map<number, {
|
|
16
|
+
url: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
at: number;
|
|
19
|
+
}>;
|
|
20
|
+
protected clients: Set<BridgeClient>;
|
|
21
|
+
private nextClientId;
|
|
22
|
+
constructor(sendToExtension: SendToExtension, log?: (...args: unknown[]) => void);
|
|
23
|
+
addClient(send: (message: CdpMessage) => void): BridgeClient;
|
|
24
|
+
removeClient(client: BridgeClient): void;
|
|
25
|
+
clientCount(): number;
|
|
26
|
+
onTabCreated(tab: BridgeTab, opener?: {
|
|
27
|
+
agent?: boolean;
|
|
28
|
+
}): void;
|
|
29
|
+
onTabRemoved(tabId: number): void;
|
|
30
|
+
onTabReplaced(addedTabId: number, removedTabId: number): void;
|
|
31
|
+
onDebuggerEvent(source: {
|
|
32
|
+
tabId?: number;
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
}, method: string, params: unknown): void;
|
|
35
|
+
onDebuggerDetach(source: {
|
|
36
|
+
tabId?: number;
|
|
37
|
+
}): void;
|
|
38
|
+
onExtensionDisconnected(): void;
|
|
39
|
+
onExtensionConnected(browserSession?: string): void;
|
|
40
|
+
listTargets(): Promise<Array<{
|
|
41
|
+
id: string;
|
|
42
|
+
tabId: number;
|
|
43
|
+
type: string;
|
|
44
|
+
url: string;
|
|
45
|
+
title: string;
|
|
46
|
+
unloaded: boolean;
|
|
47
|
+
}>>;
|
|
48
|
+
protected releaseUnusedTab(tabId: number): void;
|
|
49
|
+
protected runtimeForSession(tabId: number, sessionId?: string): RuntimeDomain;
|
|
50
|
+
protected resolveSession(client: BridgeClient, sessionId: string): {
|
|
51
|
+
tabId: number;
|
|
52
|
+
cdpSessionId?: string;
|
|
53
|
+
};
|
|
54
|
+
protected tabIdForTarget(targetId: string): number | undefined;
|
|
55
|
+
protected attachAndAnnounce(client: BridgeClient, tabId: number): Promise<void>;
|
|
56
|
+
protected announce(client: BridgeClient, attachment: TabAttachment): void;
|
|
57
|
+
protected ensureAttached(tabId: number): Promise<TabAttachment>;
|
|
58
|
+
protected dropTab(tabId: number): void;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BridgeClient as f,STAND_IN_PREFIX as h,tabIsUnloaded as c}from"./client.js";import{RuntimeDomain as u,isRuntimeContextEvent as g}from"./runtime-contexts.js";import{BridgeClient as S}from"./client.js";class m{sendToExtension;log;knownTabs=new Map;agentTabs=new Set;browserSession=null;attachments=new Map;attaching=new Map;childSessionOwner=new Map;attachRefusals=new Map;clients=new Set;nextClientId=0;constructor(t,e=()=>{}){this.sendToExtension=t,this.log=e}addClient(t){const e=new f(++this.nextClientId,t);return this.clients.add(e),e}removeClient(t){this.clients.delete(t),t.dispose();const e=new Set([...t.sessionByTabId.keys(),...t.virtualSessions.values()]);for(const s of e)this.releaseUnusedTab(s)}clientCount(){return this.clients.size}onTabCreated(t,e={}){if(t.id!==void 0){if(this.knownTabs.set(t.id,t),e.agent&&this.agentTabs.add(t.id),c(t)){this.attachments.has(t.id)&&(this.dropTab(t.id),this.sendToExtension("bridge.releaseTab",[t.id]).catch(s=>this.log("release unloaded tab failed:",s)));return}for(const s of this.clients)s.autoAttach&&this.attachAndAnnounce(s,t.id).catch(n=>this.log("auto-attach failed:",n))}}onTabRemoved(t){this.knownTabs.delete(t),this.agentTabs.delete(t),this.dropTab(t)}onTabReplaced(t,e){const s=this.agentTabs.has(e);this.onTabRemoved(e),s&&this.agentTabs.add(t)}onDebuggerEvent(t,e,s){const n=t.tabId;if(n===void 0||!this.attachments.has(n)||t.sessionId&&this.childSessionOwner.get(t.sessionId)!==n)return;const i=s?.sessionId;if(e==="Target.attachedToTarget"&&i)this.childSessionOwner.set(i,n);else if(e==="Target.detachedFromTarget"&&i){this.childSessionOwner.delete(i),this.attachments.get(n)?.runtimes.delete(i);for(const a of this.clients)a.forgetSession(i)}if(g(e)&&this.runtimeForSession(n,t.sessionId).update(e,s),t.sessionId){for(const a of this.clients)e.startsWith("Runtime.")?a.runtimeEvent(t.sessionId,e,s):a.send({sessionId:t.sessionId,method:e,params:s});return}for(const a of this.clients){const r=a.sessionByTabId.get(n);r&&(e.startsWith("Runtime.")?a.runtimeEvent(r,e,s):a.send({sessionId:r,method:e,params:s}));for(const[d,l]of a.virtualSessions)l===n&&(e.startsWith("Runtime.")?a.runtimeEvent(d,e,s):a.send({sessionId:d,method:e,params:s}))}}onDebuggerDetach(t){t.tabId!==void 0&&this.dropTab(t.tabId)}onExtensionDisconnected(){for(const t of[...this.attachments.keys()])this.dropTab(t);this.knownTabs.clear(),this.childSessionOwner.clear()}onExtensionConnected(t){const e=!!t&&t===this.browserSession;e||this.agentTabs.clear(),this.log(`extension connected: ${e?"same":"new"} browser session, kept ${this.agentTabs.size} agent tab mark(s)`),this.browserSession=t??null}async listTargets(){await this.reconcileKnownTabs();let t=[];try{t=await this.sendToExtension("chrome.tabs.query",[{}])??[]}catch(n){this.log("live tab query failed:",n)}const e=new Map(t.filter(n=>n.id!==void 0).map(n=>[n.id,n])),s=[];for(const n of this.knownTabs.keys()){const i=e.get(n),o=this.attachments.get(n)?.targetInfo;s.push({tabId:n,id:typeof o?.targetId=="string"?o.targetId:`${h}${n}`,type:"page",url:i?.url??(typeof o?.url=="string"?o.url:""),title:i?.title??(typeof o?.title=="string"?o.title:""),unloaded:c(i??this.knownTabs.get(n))})}return s}releaseUnusedTab(t){!this.attachments.has(t)||[...this.clients].some(e=>e.sessionByTabId.has(t)||[...e.virtualSessions.values()].includes(t))||(this.dropTab(t),this.sendToExtension("bridge.releaseTab",[t]).catch(e=>this.log("release failed:",e)))}runtimeForSession(t,e){const s=this.attachments.get(t);if(!s)throw new Error(`No debugger attachment for tab: ${t}`);const n=e??"";let i=s.runtimes.get(n);return i||(i=new u,s.runtimes.set(n,i)),i}resolveSession(t,e){const s=t.tabBySessionId.get(e);if(s!==void 0)return{tabId:s};const n=t.virtualSessions.get(e);if(n!==void 0)return{tabId:n};const i=this.childSessionOwner.get(e);if(i!==void 0)return{tabId:i,cdpSessionId:e};throw new Error(`No tab for sessionId: ${e}`)}tabIdForTarget(t){for(const s of this.attachments.values())if(s.targetInfo.targetId===t)return s.tabId;if(!t.startsWith(h))return;const e=Number(t.slice(h.length));return Number.isInteger(e)&&this.knownTabs.has(e)?e:void 0}async attachAndAnnounce(t,e){let s;try{s=await this.ensureAttached(e)}catch(n){this.attachRefusals.set(e,{url:this.knownTabs.get(e)?.url??"",reason:n instanceof Error?n.message:String(n),at:Date.now()});for(const i of this.attachRefusals.keys()){if(this.attachRefusals.size<=20)break;this.attachRefusals.delete(i)}throw n}this.attachRefusals.delete(e),this.announce(t,s)}announce(t,e){if(t.sessionByTabId.has(e.tabId))return;const s=t.tabAlias(e.tabId);t.send({method:"Target.attachedToTarget",params:{sessionId:s,targetInfo:{...e.targetInfo,attached:!0},waitingForDebugger:!1}})}ensureAttached(t){const e=this.knownTabs.get(t);if(!e)return Promise.reject(new Error(`Tab ${t} was closed; list tabs again.`));if(c(e))return Promise.reject(new Error(`Tab ${t} is unloaded by Chrome. Restore this tab before attaching its renderer.`));const s=this.attachments.get(t);if(s)return Promise.resolve(s);const n=this.attaching.get(t);if(n)return n;const i=(async()=>{await this.sendToExtension("chrome.debugger.attach",[{tabId:t},"1.3"]);const o=await this.sendToExtension("chrome.debugger.sendCommand",[{tabId:t},"Target.getTargetInfo"]);if(!o?.targetInfo?.targetId)throw new Error(`Tab ${t} reported no targetInfo`);const a={tabId:t,targetInfo:o.targetInfo,runtimes:new Map};return this.attachments.set(t,a),a})();return this.attaching.set(t,i),i.catch(()=>{}).finally(()=>this.attaching.delete(t)),i}dropTab(t){const e=this.attachments.get(t);this.attachments.delete(t);for(const[s,n]of this.childSessionOwner)if(n===t){this.childSessionOwner.delete(s);for(const i of this.clients)i.forgetSession(s)}for(const s of this.clients){const n=s.dropTab(t);n&&e&&s.send({method:"Target.detachedFromTarget",params:{sessionId:n,targetId:e.targetInfo.targetId}})}}}export{S as BridgeClient,m as BridgeModelCore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BridgeModelCommands as e}from"./model-commands.js";import{}from"./client.js";class d extends e{}export{d as BridgeModel};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const HOST_TO_BROWSER_MAX: number;
|
|
2
|
+
export declare const BROWSER_TO_HOST_MAX: number;
|
|
3
|
+
export declare function encodeFrame(text: string, max: number): Buffer;
|
|
4
|
+
export declare class FrameDecoder {
|
|
5
|
+
private readonly max;
|
|
6
|
+
private buffer;
|
|
7
|
+
constructor(max: number);
|
|
8
|
+
push(chunk: Buffer): string[];
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import n from"node:os";const i=1024*1024,h=64*1024*1024,s=n.endianness()==="LE";function u(f,r){const e=Buffer.from(f,"utf8");if(e.length>r)throw new Error(`native message of ${e.length} bytes exceeds the ${r}-byte limit`);const t=Buffer.allocUnsafe(4);return s?t.writeUInt32LE(e.length,0):t.writeUInt32BE(e.length,0),Buffer.concat([t,e])}class a{max;buffer=Buffer.alloc(0);constructor(r){this.max=r}push(r){this.buffer=this.buffer.length===0?r:Buffer.concat([this.buffer,r]);const e=[];for(;;){if(this.buffer.length<4)return e;const t=s?this.buffer.readUInt32LE(0):this.buffer.readUInt32BE(0);if(t>this.max)throw new Error(`native frame claims ${t} bytes, over the ${this.max}-byte limit`);if(this.buffer.length<4+t)return e;e.push(this.buffer.subarray(4,4+t).toString("utf8")),this.buffer=this.buffer.subarray(4+t)}}}export{h as BROWSER_TO_HOST_MAX,a as FrameDecoder,i as HOST_TO_BROWSER_MAX,u as encodeFrame};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const NATIVE_HOST_NAME = "ai.mirasim.browser_bridge";
|
|
2
|
+
export interface NativeHostEntry {
|
|
3
|
+
owner: string;
|
|
4
|
+
command: string[];
|
|
5
|
+
socket: string;
|
|
6
|
+
priority: number;
|
|
7
|
+
extensionIds: string[];
|
|
8
|
+
manifestDirs: string[];
|
|
9
|
+
path?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface NativeHostResult {
|
|
12
|
+
name: string;
|
|
13
|
+
wrapper: string;
|
|
14
|
+
manifests: string[];
|
|
15
|
+
owners: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function defaultBridgeSocket(env?: NodeJS.ProcessEnv): string;
|
|
18
|
+
export declare function defaultHostCommand(): string[];
|
|
19
|
+
export declare function installNativeHost(entry: NativeHostEntry, hostName?: string): NativeHostResult;
|
|
20
|
+
export declare function removeNativeHost(owner: string, hostName?: string, extraDirs?: string[]): NativeHostResult;
|
|
21
|
+
export declare function recordedBridges(hostName?: string): Array<{
|
|
22
|
+
owner: string;
|
|
23
|
+
socket: string;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{execFileSync as S}from"node:child_process";import n from"node:fs";import C from"node:os";import a from"node:path";import{computerUseHome as N,sharedHome as O}from"../../home.js";const l="ai.mirasim.browser_bridge",H={darwin:["Library/Application Support/Google/Chrome/NativeMessagingHosts","Library/Application Support/Google/Chrome Beta/NativeMessagingHosts","Library/Application Support/Google/Chrome for Testing/NativeMessagingHosts","Library/Application Support/Chromium/NativeMessagingHosts","Library/Application Support/Microsoft Edge/NativeMessagingHosts","Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts","Library/Application Support/Vivaldi/NativeMessagingHosts","Library/Application Support/com.operasoftware.Opera/NativeMessagingHosts","Library/Application Support/Arc/User Data/NativeMessagingHosts"],linux:[".config/google-chrome/NativeMessagingHosts",".config/google-chrome-beta/NativeMessagingHosts",".config/google-chrome-unstable/NativeMessagingHosts",".config/google-chrome-for-testing/NativeMessagingHosts",".config/chromium/NativeMessagingHosts",".config/microsoft-edge/NativeMessagingHosts",".config/BraveSoftware/Brave-Browser/NativeMessagingHosts",".config/vivaldi/NativeMessagingHosts",".config/opera/NativeMessagingHosts"]},M=["HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts","HKCU\\Software\\Microsoft\\Edge\\NativeMessagingHosts","HKCU\\Software\\BraveSoftware\\Brave-Browser\\NativeMessagingHosts","HKCU\\Software\\Chromium\\NativeMessagingHosts","HKCU\\Software\\Vivaldi\\NativeMessagingHosts","HKCU\\Software\\Opera Software\\Opera Stable\\NativeMessagingHosts"];function u(e=l){return a.join(O(),"native-host",e)}function U(e=process.env){return process.platform==="win32"?"\\\\.\\pipe\\mirasim-computer-use-bridge":a.join(N(e),"bridge.sock")}function W(){const e=process.argv[1];if(!e)throw new Error("cannot tell how this computer-use was started; pass --host-command");return[process.execPath,n.realpathSync(e)]}function F(e,r=l){if(E(r),k(e.owner),!e.command.length||e.command.some(i=>!a.isAbsolute(i)))throw new Error(`the host command must be absolute paths: ${JSON.stringify(e.command)}`);const o=[...new Set(e.extensionIds)];if(!o.length||o.some(i=>!/^[a-p]{32}$/.test(i)))throw new Error("Invalid Mirasim extension identity.");const t=`${JSON.stringify({...e,extensionIds:o},null,2)}
|
|
2
|
+
`;return d(a.join(u(r),"hosts",`${e.owner}.json`),t),b(r,w(r),[])}function K(e,r=l,o=[]){E(r),k(e);const t=a.join(u(r),"hosts",`${e}.json`),i=$(t);n.rmSync(t,{force:!0});const c=[...o,...i?.manifestDirs??[]],p=w(r);if(p.length)return b(r,p,c);const m=[];for(const s of v([...x(),...c])){const f=a.join(s,`${r}.json`);n.existsSync(f)&&m.push(f),n.rmSync(f,{force:!0})}if(n.rmSync(y(r),{force:!0}),process.platform==="win32"){n.rmSync(A(r),{force:!0});for(const s of M)try{S("reg",["delete",`${s}\\${r}`,"/f"],{stdio:"ignore",windowsHide:!0})}catch{}}return{name:r,wrapper:y(r),manifests:m,owners:[]}}function b(e,r,o){const t=y(e);d(t,process.platform==="win32"?_(r):I(r),448);const i=[...new Set(r.flatMap(s=>s.extensionIds))],c=`${JSON.stringify({name:e,description:"Mirasim browser bridge (computer-use)",path:t,type:"stdio",allowed_origins:i.map(s=>`chrome-extension://${s}/`)},null,2)}
|
|
3
|
+
`,p=[...new Set(r.flatMap(s=>s.manifestDirs))],m=[];if(process.platform==="win32"){const s=A(e);d(s,c),m.push(s),B(e,s)}else{const s=x();for(const f of v([...s,...p])){const g=a.join(f,`${e}.json`);try{n.mkdirSync(f,{recursive:!0}),d(g,c),m.push(g)}catch{}}for(const f of v(o.filter(g=>!p.includes(g)&&!s.includes(g))))n.rmSync(a.join(f,`${e}.json`),{force:!0})}return{name:e,wrapper:t,manifests:m,owners:r.map(s=>s.owner)}}function P(e=l){return w(e).map(r=>({owner:r.owner,socket:r.socket}))}function w(e){const r=a.join(u(e),"hosts");let o;try{o=n.readdirSync(r).filter(t=>t.endsWith(".json"))}catch{return[]}return o.map(t=>$(a.join(r,t))).filter(t=>t!==null).sort((t,i)=>t.priority-i.priority||t.owner.localeCompare(i.owner))}function $(e){try{const r=JSON.parse(n.readFileSync(e,"utf8"));return typeof r.owner!="string"||!Array.isArray(r.command)||typeof r.socket!="string"?null:{owner:r.owner,command:r.command.filter(o=>typeof o=="string"),socket:r.socket,priority:typeof r.priority=="number"?r.priority:100,extensionIds:Array.isArray(r.extensionIds)?r.extensionIds.filter(o=>typeof o=="string"):[],manifestDirs:Array.isArray(r.manifestDirs)?r.manifestDirs.filter(o=>typeof o=="string"):[],...typeof r.path=="string"?{path:r.path}:{}}}catch{return null}}function x(){const e=C.homedir(),r=process.platform==="darwin"?H.darwin:process.platform==="linux"?H.linux:[],o=process.env.XDG_CONFIG_HOME?.trim();return r.map(t=>process.platform==="linux"&&o&&t.startsWith(".config/")?a.join(o,t.slice(8)):a.join(e,t))}function v(e){return[...new Set(e)].filter(r=>{try{return n.statSync(a.dirname(r)).isDirectory()}catch{return!1}})}function y(e){return a.join(u(e),process.platform==="win32"?"chrome-native-host.bat":"chrome-native-host")}function A(e){return a.join(u(e),`${e}.json`)}function j(e,r){return e.map(o=>`--socket ${r(o.socket)}`).join(" ")}function I(e){const r=j(e,h),o=["#!/bin/sh","# Chrome native messaging host for the Mirasim browser extension (computer-use's bridge).","# Generated by mirasim-cu from the records next to this file \u2014 do not edit; every","# installer rewrites it.","#","# Each block is one installed computer-use, in priority order: the first whose program is","# still on disk runs the host, which dials every recorded bridge socket in the same order.","# CHROME starts this, with CHROME's environment, so each block brings the PATH its program","# was installed with."];for(const t of e){const i=t.command.map((c,p)=>`[ ${p===0?"-x":"-e"} ${h(c)} ]`).join(" && ");o.push(`# ${t.owner}`,`if ${i}; then`,...t.path?[` PATH=${h(t.path)}`," export PATH"]:[],` exec ${t.command.map(h).join(" ")} bridge-host ${r} "$@"`,"fi")}return o.push("exit 1",""),o.join(`
|
|
4
|
+
`)}function _(e){const r=i=>`"${i.replaceAll("%","%%")}"`,o=j(e,r),t=["@echo off","REM Chrome native messaging host for the Mirasim browser extension (computer-use's bridge).","REM Generated by mirasim-cu - do not edit; every installer rewrites it."];return e.forEach((i,c)=>{t.push(`REM ${i.owner}`);for(const p of i.command)t.push(`if not exist ${r(p)} goto next${c}`);t.push(`${i.command.map(r).join(" ")} bridge-host ${o} %*`,"exit /b",`:next${c}`)}),t.push("exit /b 1",""),t.join(`\r
|
|
5
|
+
`)}function B(e,r){for(const o of M)try{S("reg",["add",`${o}\\${e}`,"/ve","/t","REG_SZ","/d",r,"/f"],{stdio:"ignore",windowsHide:!0})}catch{}}function d(e,r,o){try{if(n.readFileSync(e,"utf8")===r)return}catch{}n.mkdirSync(a.dirname(e),{recursive:!0});const t=`${e}.${process.pid}.tmp`;n.writeFileSync(t,r),o!==void 0&&process.platform!=="win32"&&n.chmodSync(t,o),n.renameSync(t,e)}function h(e){return`'${e.replaceAll("'","'\\''")}'`}function E(e){if(!/^[a-z0-9_]+(\.[a-z0-9_]+)*$/.test(e))throw new Error(`invalid native host name: ${e}`)}function k(e){if(!/^[A-Za-z0-9._-]+$/.test(e)||e.startsWith("."))throw new Error(`invalid native host owner: ${e}`)}export{l as NATIVE_HOST_NAME,U as defaultBridgeSocket,W as defaultHostCommand,F as installNativeHost,P as recordedBridges,K as removeNativeHost};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class RuntimeContexts {
|
|
2
|
+
private readonly contexts;
|
|
3
|
+
has(params: unknown): boolean;
|
|
4
|
+
update(method: string, params: unknown): void;
|
|
5
|
+
values(): IterableIterator<unknown>;
|
|
6
|
+
clear(): void;
|
|
7
|
+
}
|
|
8
|
+
export declare class RuntimeDomain extends RuntimeContexts {
|
|
9
|
+
private enabling;
|
|
10
|
+
enable(send: () => Promise<unknown>): Promise<unknown>;
|
|
11
|
+
}
|
|
12
|
+
export declare function isRuntimeContextEvent(method: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class x{contexts=new Map;has(e){const t=e?.context?.id;return t!==void 0&&this.contexts.has(t)}update(e,t){const n=t;if(e==="Runtime.executionContextCreated"&&n?.context?.id!==void 0)this.contexts.set(n.context.id,t);else if(e==="Runtime.executionContextDestroyed"){if(n?.executionContextId!==void 0)this.contexts.delete(n.executionContextId);else if(n?.executionContextUniqueId)for(const[o,s]of this.contexts)s.context?.uniqueId===n.executionContextUniqueId&&this.contexts.delete(o)}else e==="Runtime.executionContextsCleared"&&this.clear()}values(){return this.contexts.values()}clear(){this.contexts.clear()}}class u extends x{enabling;enable(e){return this.enabling||(this.enabling=e().catch(t=>{throw this.enabling=void 0,t})),this.enabling}}function c(i){return i==="Runtime.executionContextCreated"||i==="Runtime.executionContextDestroyed"||i==="Runtime.executionContextsCleared"}export{x as RuntimeContexts,u as RuntimeDomain,c as isRuntimeContextEvent};
|