@duckmind/dm-darwin-x64 0.43.0 → 0.43.2
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/dm +0 -0
- package/extensions/.dm-extensions.json +5 -4
- package/extensions/greedysearch-dm/README.md +20 -17
- package/extensions/greedysearch-dm/bin/gschrome.mjs +3 -3
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +4 -4
- package/extensions/greedysearch-dm/bin/launch.mjs +4 -4
- package/extensions/greedysearch-dm/src/utils/browser-executable.mjs +1 -0
- package/package.json +1 -1
package/dm
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"status": "ok",
|
|
3
|
-
"prepared_at": "2026-07-
|
|
3
|
+
"prepared_at": "2026-07-07T16:00:55.489219+00:00",
|
|
4
4
|
"managed_entries": [
|
|
5
5
|
{
|
|
6
6
|
"id": "dm-context",
|
|
@@ -405,13 +405,14 @@
|
|
|
405
405
|
"src/search/sources.mjs",
|
|
406
406
|
"src/search/synthesis-runner.mjs",
|
|
407
407
|
"src/search/synthesis.mjs",
|
|
408
|
+
"src/utils/browser-executable.mjs",
|
|
408
409
|
"src/utils/content.mjs",
|
|
409
410
|
"src/utils/node-runtime.mjs",
|
|
410
411
|
"src/utils/system-cmds.mjs"
|
|
411
412
|
],
|
|
412
|
-
"file_count":
|
|
413
|
-
"before_bytes":
|
|
414
|
-
"after_bytes":
|
|
413
|
+
"file_count": 44,
|
|
414
|
+
"before_bytes": 475440,
|
|
415
|
+
"after_bytes": 758895,
|
|
415
416
|
"externals": [
|
|
416
417
|
"@duckmind/dm-agent-core",
|
|
417
418
|
"@duckmind/dm-ai",
|
|
@@ -8,7 +8,7 @@ Multi-engine AI web search for DM via browser automation.
|
|
|
8
8
|
- Real browser results from configurable engines: Perplexity, Google AI, ChatGPT, Gemini, plus opt-in Semantic Scholar and Logically research engines
|
|
9
9
|
- Research mode as the centerpiece: iterative planning, source fetching, citation audit, and structured bundles
|
|
10
10
|
- Optional configurable synthesis with source grounding (Gemini by default)
|
|
11
|
-
- Chrome runs headless by default — no window, purely background
|
|
11
|
+
- CloakBrowser/Chrome runs headless by default — no window, purely background
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -40,7 +40,7 @@ greedy_search({
|
|
|
40
40
|
maxSources: 8,
|
|
41
41
|
});
|
|
42
42
|
// Research mode writes a dataroom-style bundle under .dm/greedysearch-research/ by default.
|
|
43
|
-
// Headless is the default — no window. To force visible
|
|
43
|
+
// Headless is the default — no window. To force visible browser:
|
|
44
44
|
greedy_search({ query: "Visible browser setup", engine: "perplexity", visible: true });
|
|
45
45
|
```
|
|
46
46
|
|
|
@@ -50,8 +50,8 @@ greedy_search({ query: "Visible browser setup", engine: "perplexity", visible: t
|
|
|
50
50
|
|
|
51
51
|
- `query` (required)
|
|
52
52
|
- `fullAnswer`: return full single-engine output instead of preview
|
|
53
|
-
- `headless`: set to `false` to show
|
|
54
|
-
- `visible` / `alwaysVisible`: set to `true` to always use visible
|
|
53
|
+
- `headless`: set to `false` to show a browser window (default: `true`)
|
|
54
|
+
- `visible` / `alwaysVisible`: set to `true` to always use a visible browser for this search
|
|
55
55
|
|
|
56
56
|
### Normal search
|
|
57
57
|
|
|
@@ -75,11 +75,14 @@ Deep research uses the configured `~/.dm/greedyconfig.engines` list for child se
|
|
|
75
75
|
|
|
76
76
|
| Variable | Default | Description |
|
|
77
77
|
| ------------------------------------ | ------------- | ------------------------------------------------------------- |
|
|
78
|
-
| `GREEDY_SEARCH_VISIBLE` | (unset) | Set to `1` to show
|
|
79
|
-
| `GREEDY_SEARCH_ALWAYS_VISIBLE` | (unset) | Set to `1` to force visible
|
|
80
|
-
| `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES` | `5` | Minutes of inactivity before auto-killing GreedySearch
|
|
78
|
+
| `GREEDY_SEARCH_VISIBLE` | (unset) | Set to `1` to show a browser window instead of headless |
|
|
79
|
+
| `GREEDY_SEARCH_ALWAYS_VISIBLE` | (unset) | Set to `1` to force visible browser for all GreedySearch runs |
|
|
80
|
+
| `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES` | `5` | Minutes of inactivity before auto-killing GreedySearch browser |
|
|
81
81
|
| `GREEDY_SEARCH_LOCALE` | `en` | Default result language (en, de, fr, es, ja, etc.) |
|
|
82
|
-
| `
|
|
82
|
+
| `GREEDY_SEARCH_BROWSER` / `DM_CUA_BROWSER` | `auto` | `auto`, `cloak`, or `chrome`; auto prefers CloakBrowser when installed |
|
|
83
|
+
| `GREEDY_SEARCH_BROWSER_PATH` / `DM_CUA_BROWSER_PATH` | (unset) | Explicit browser executable override |
|
|
84
|
+
| `DM_CUA_CLOAK_PATH` / `CLOAKBROWSER_BINARY_PATH` | (unset) | Explicit CloakBrowser executable; DM does not bundle the binary |
|
|
85
|
+
| `CHROME_PATH` | auto-detected | Path to Chrome/Chromium executable fallback |
|
|
83
86
|
|
|
84
87
|
## Search modes
|
|
85
88
|
|
|
@@ -133,9 +136,9 @@ node bin/search.mjs all "topic" --depth research --no-research-bundle
|
|
|
133
136
|
Inside DM, prefer the extension commands (no package path needed):
|
|
134
137
|
|
|
135
138
|
```text
|
|
136
|
-
/greedy-visible # launch visible
|
|
137
|
-
/greedy-status # show GreedySearch
|
|
138
|
-
/greedy-kill # stop GreedySearch
|
|
139
|
+
/greedy-visible # launch visible browser for captcha/login/cookie setup
|
|
140
|
+
/greedy-status # show GreedySearch browser status
|
|
141
|
+
/greedy-kill # stop GreedySearch browser
|
|
139
142
|
/set-greedy-locale # set default result language (de, fr, es, ja, etc.)
|
|
140
143
|
```
|
|
141
144
|
|
|
@@ -147,9 +150,9 @@ node "$GS/bin/launch.mjs" --status
|
|
|
147
150
|
node "$GS/bin/visible.mjs" # visible mode
|
|
148
151
|
node "$GS/bin/visible.mjs" --kill # strong visible/port cleanup
|
|
149
152
|
node "$GS/bin/kill-visible.mjs" # same as visible.mjs --kill
|
|
150
|
-
node "$GS/bin/cdp-visible.mjs" list # safe CDP: GreedySearch visible
|
|
151
|
-
node "$GS/bin/cdp-headless.mjs" list # safe CDP: GreedySearch headless
|
|
152
|
-
node "$GS/bin/cdp-greedy.mjs" list # safe CDP: any GreedySearch
|
|
153
|
+
node "$GS/bin/cdp-visible.mjs" list # safe CDP: GreedySearch visible browser only
|
|
154
|
+
node "$GS/bin/cdp-headless.mjs" list # safe CDP: GreedySearch headless browser only
|
|
155
|
+
node "$GS/bin/cdp-greedy.mjs" list # safe CDP: any GreedySearch browser mode
|
|
153
156
|
```
|
|
154
157
|
|
|
155
158
|
npm global install path:
|
|
@@ -165,13 +168,13 @@ node "$GS/bin/cdp-headless.mjs" list
|
|
|
165
168
|
node "$GS/bin/cdp-greedy.mjs" list
|
|
166
169
|
```
|
|
167
170
|
|
|
168
|
-
|
|
171
|
+
GreedySearch browser is auto-cleaned after 5 min idle. Override with `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES=10` or disable with `0`.
|
|
169
172
|
|
|
170
|
-
**CDP safety:** use `cdp-visible.mjs`, `cdp-headless.mjs`, or `cdp-greedy.mjs` for debugging. They always set `CDP_PROFILE_DIR` to the dedicated GreedySearch
|
|
173
|
+
**CDP safety:** use `cdp-visible.mjs`, `cdp-headless.mjs`, or `cdp-greedy.mjs` for debugging. They always set `CDP_PROFILE_DIR` to the dedicated GreedySearch browser profile and never fall back to your main browser session. Avoid calling raw `bin/cdp.mjs` manually unless you explicitly set `CDP_PROFILE_DIR`.
|
|
171
174
|
|
|
172
175
|
## Requirements
|
|
173
176
|
|
|
174
|
-
- Chrome
|
|
177
|
+
- CloakBrowser or Chrome/Chromium
|
|
175
178
|
- Node.js 20.11.0+
|
|
176
179
|
|
|
177
180
|
## Source fetching
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
3
|
-
`)[0]):null}catch{return null}}function
|
|
4
|
-
${
|
|
2
|
+
import{execSync as s,spawn as e}from"node:child_process";import{existsSync as R,mkdirSync as N,readFileSync as m,unlinkSync as z,writeFileSync as H}from"node:fs";import J from"node:http";import{platform as f,tmpdir as x}from"node:os";import{join as Q}from"node:path";import{existsSync as w}from"node:fs";import{platform as W}from"node:os";function M(o=W()){if(o==="win32")return{cloak:["C:/Program Files/CloakBrowser/CloakBrowser.exe","C:/Program Files (x86)/CloakBrowser/CloakBrowser.exe"],chrome:["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]};if(o==="darwin")return{cloak:["/Applications/CloakBrowser.app/Contents/MacOS/CloakBrowser","/Applications/Cloak Browser.app/Contents/MacOS/CloakBrowser"],chrome:["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]};return{cloak:["/usr/bin/cloakbrowser","/usr/local/bin/cloakbrowser","/opt/CloakBrowser/CloakBrowser"],chrome:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium-browser","/usr/bin/chromium","/snap/bin/chromium"]}}function c(o,r=w){return o.find((C)=>C&&r(C))||null}function T(o,r){for(let C of r){let a=o[C]?.trim();if(a)return{key:C,path:a}}return null}function b(o,r){if(o==="chrome"||r==="CHROME_PATH")return"Chrome";if(o==="cloak"||r==="DM_CUA_CLOAK_PATH"||r==="CLOAKBROWSER_BINARY_PATH")return"CloakBrowser";return"browser"}function G({env:o=process.env,platformName:r=W(),exists:C=w}={}){let a=(o.GREEDY_SEARCH_BROWSER||o.DM_CUA_BROWSER||"auto").toLowerCase(),h=T(o,a==="chrome"?["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","CHROME_PATH"]:["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","DM_CUA_CLOAK_PATH","CLOAKBROWSER_BINARY_PATH","CHROME_PATH"]);if(h)return{path:h.path,label:b(a,h.key)};let n=M(r);if(a==="cloak")return{path:c(n.cloak,C),label:"CloakBrowser"};if(a==="chrome")return{path:c(n.chrome,C),label:"Chrome"};let l=c(n.cloak,C);return{path:l||c(n.chrome,C),label:l?"CloakBrowser":"Chrome"}}var Y=x().replaceAll("\\","/"),i=9222,_=Q(x(),"greedysearch-chrome-profile"),u=`${Y}/greedysearch-chrome.pid`,t=`${Y}/greedysearch-chrome-mode`;function B(){return new Promise((o)=>{let r=J.get(`http://localhost:${i}/json/version`,(C)=>{let a="";C.on("data",(A)=>a+=A),C.on("end",()=>o({ok:!0,body:a}))});r.on("error",()=>o({ok:!1})),r.setTimeout(2000,()=>{r.destroy(),o({ok:!1})})})}function U(o){try{if(f()==="win32"){let C=s("netstat -ano -p TCP 2>nul",{encoding:"utf8"}),a=new RegExp(String.raw`TCP\s+\S+:${o}\s+\S+:0\s+LISTENING\s+(\d+)`,"i");return(C.match(a)||[])[1]?parseInt(C.match(a)[1]):null}let r=s(`lsof -i :${o} -t 2>/dev/null || ss -tlnp 2>/dev/null | grep :${o} | grep -oP 'pid=\\K\\d+'`,{encoding:"utf8"}).trim();return r?parseInt(r.split(`
|
|
3
|
+
`)[0]):null}catch{return null}}function K(){let o=U(i);if(!o)return!1;try{if(f()==="win32")s(`taskkill /F /PID ${o}`,{stdio:"ignore"});else process.kill(o,"SIGKILL");return!0}catch{return!1}}function p(){for(let o of[u,t])try{z(o)}catch{}}async function S(){let{ok:o,body:r}=await B();if(!o){console.log("Not running.");return}let C=R(t)?m(t,"utf8").trim():"unknown",a=R(u)?m(u,"utf8").trim():"none",A=U(i)||"unknown",{Browser:h}=JSON.parse(r);console.log(`Running: ${h}`),console.log(` Mode: ${C}`),console.log(` Port: ${i}`),console.log(` PID file: ${a}`),console.log(` PID actual:${A}`)}async function V(){let{ok:o}=await B();if(!o){console.log("Not running — nothing to kill."),p();return}console.log("Killing browser on port 9222..."),K(),p(),await new Promise((C)=>setTimeout(C,1500));let{ok:r}=await B();console.log(r?"FAILED — still running.":"Killed.")}async function g(o){let{ok:r}=await B();if(r){let n=R(t)?m(t,"utf8").trim():"unknown";if(n===o){console.log(`Already running in ${o} mode.`);return}console.log(`${n} browser running — killing to switch to ${o}...`),K(),p(),await new Promise((l)=>setTimeout(l,1500))}let C=G();if(!C.path)console.error("CloakBrowser/Chrome not found. Set GREEDY_SEARCH_BROWSER_PATH, DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH."),process.exit(1);let a=o==="headless",A=[`--remote-debugging-port=${i}`,"--disable-features=DevToolsPrivacyUI","--no-first-run","--no-default-browser-check","--disable-default-apps","--disable-blink-features=AutomationControlled","--window-size=1920,1080",`--user-data-dir=${_}`,"--profile-directory=Default"];if(a){if(A.push("--headless=new","--disable-gpu","--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"),f()==="win32")A.push("--disable-software-rasterizer")}A.push("about:blank"),N(_,{recursive:!0}),console.log(`Launching ${o} ${C.label} on port ${i}...`);let h=e(C.path,A,{detached:!0,stdio:"ignore"});h.unref(),H(u,String(h.pid)),H(t,o);for(let n=0;n<30;n++){await new Promise((k)=>setTimeout(k,500));let{ok:l}=await B();if(l){try{let{body:k}=await B(),{webSocketDebuggerUrl:O}=JSON.parse(k),E=new URL(O).pathname;H(`${_}/DevToolsActivePort`,`${i}
|
|
4
|
+
${E}`)}catch{}console.log("Ready.");return}}console.error("Timeout — Chrome did not become ready."),process.exit(1)}var X=process.argv[2];switch(X){case"launch-headless":await g("headless");break;case"launch-visible":await g("visible");break;case"kill":await V();break;case"status":await S();break;default:console.log(`Usage: node bin/gschrome.mjs <command>
|
|
5
5
|
|
|
6
6
|
Commands:
|
|
7
7
|
launch-headless Start headless Chrome on port 9222
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
3
|
-
${
|
|
4
|
-
`}function
|
|
5
|
-
${
|
|
2
|
+
import{execSync as c,spawn as YC}from"node:child_process";import{existsSync as EC,mkdirSync as GC,readFileSync as u,unlinkSync as L,writeFileSync as f}from"node:fs";import MC from"node:http";import{platform as p,tmpdir as N}from"node:os";import{join as J}from"node:path";import{existsSync as V,mkdirSync as l,readFileSync as Q,renameSync as a,unlinkSync as v,writeFileSync as h}from"node:fs";import o from"node:http";import{platform as S}from"node:os";import{dirname as n}from"node:path";var q=[9222,9223],r=/^(0|false|no|off)$/i;function i(C){return[...new Set(C.filter(Boolean))]}function m(C,A="localhost"){let _=String(C||"").trim().split(/\r?\n/).map((O)=>O.trim()).filter(Boolean);if(_.length===0)throw Error("empty DevToolsActivePort");let[R,B=""]=_;if(/^wss?:\/\//i.test(R))return R;if(R.includes(":"))return`ws://${R}${B}`;return`ws://${A}:${R}${B}`}function b(C,A="explicit"){let _=new URL(C),R=_.protocol==="wss:"?"wss:":"ws:",B=_.port?Number.parseInt(_.port,10):R==="wss:"?443:80;return{source:A,wsUrl:`${R}//${_.host}${_.pathname}${_.search}`,host:_.hostname,port:B,path:`${_.pathname}${_.search}`,httpUrl:`http://${_.hostname}:${B}`}}function U(C=process.env){return![C.GREEDY_SEARCH_REUSE_EXISTING_BROWSER,C.DM_CUA_REUSE_EXISTING_BROWSER].some((A)=>A!==void 0&&r.test(String(A)))}function X(C){let A=Number.parseInt(String(C??""),10);return Number.isInteger(A)&&A>0&&A<65536?A:null}function s(C){if(!C)return null;let A=String(C).trim();if(!A)return null;let _=new URL(A.includes("://")?A:`http://${A}`),R=X(_.port)||(_.protocol==="https:"?443:80);return{host:_.hostname,port:R,source:`env:${A}`}}function d(C){if(!C)return[];return String(C).split(/[,\s]+/).map(X).filter(Boolean)}function t({env:C=process.env,platformName:A=S(),procVersionText:_=null}={}){if(A!=="linux")return!1;if(C.WSL_DISTRO_NAME||C.WSL_INTEROP)return!0;let R=_??(()=>{try{return Q("/proc/version","utf8")}catch{return""}})();return/microsoft|wsl/i.test(R)}function e({env:C=process.env,platformName:A=S(),procVersionText:_=null,resolvConfText:R=null}={}){let B=["localhost","127.0.0.1"];if(t({env:C,platformName:A,procVersionText:_})){let W=(R??(()=>{try{return Q("/etc/resolv.conf","utf8")}catch{return""}})()).match(/^\s*nameserver\s+([^\s#]+)/m);if(W)B.push(W[1]);B.push("host.docker.internal")}return i(B)}function CC({env:C=process.env,hosts:A=e({env:C}),autoPorts:_=q,excludePorts:R=[]}={}){let B=[];for(let H of["GREEDY_SEARCH_CDP_WS_URL","DM_CUA_CDP_WS_URL","CDP_WS_URL"])if(C[H])B.push({wsUrl:C[H],source:`env:${H}`});for(let H of["GREEDY_SEARCH_CDP_URL","DM_CUA_CDP_URL","CDP_URL"])try{let Y=s(C[H]);if(Y)B.push(Y)}catch{}for(let H of["GREEDY_SEARCH_EXISTING_CDP_PORT","DM_CUA_EXISTING_CDP_PORT","GREEDY_SEARCH_CDP_PORT","DM_CUA_CDP_PORT"]){let Y=X(C[H]);if(!Y)continue;for(let M of A)B.push({host:M,port:Y,source:`env:${H}`})}let O=d(C.GREEDY_SEARCH_EXISTING_CDP_PORTS);for(let H of O)for(let Y of A)B.push({host:Y,port:H,source:"env:GREEDY_SEARCH_EXISTING_CDP_PORTS"});let W=new Set(R.filter(Boolean));if(U(C))for(let H of _){if(W.has(H))continue;for(let Y of A)B.push({host:Y,port:H,source:"auto"})}let K=new Set;return B.filter((H)=>{let Y=H.wsUrl||`${H.host}:${H.port}`;if(K.has(Y))return!1;return K.add(Y),!0})}async function AC(C,{timeoutMs:A=700}={}){if(C.wsUrl)return b(C.wsUrl,C.source);let _=C.host||"localhost",R=C.port;if(!R)return null;let B=await new Promise((O)=>{let W=o.get({host:_,port:R,path:"/json/version",timeout:A},(K)=>{let H="";K.setEncoding("utf8"),K.on("data",(Y)=>H+=Y),K.on("end",()=>O(K.statusCode===200?H:null))});W.on("error",()=>O(null)),W.setTimeout(A,()=>{W.destroy(),O(null)})});if(!B)return null;try{let O=JSON.parse(B);if(!O.webSocketDebuggerUrl)return null;let W=b(O.webSocketDebuggerUrl,C.source),K=W.path||new URL(O.webSocketDebuggerUrl).pathname;return{...W,host:_,port:R,httpUrl:`http://${_}:${R}`,wsUrl:`ws://${_}:${R}${K}`,path:K}}catch{return null}}async function _C(C={}){for(let A of CC(C)){let _=await AC(A,C);if(_)return _}return null}function RC(C){if(!C)throw Error("missing CDP endpoint");let A=new URL(C.wsUrl);return`${A.host}
|
|
3
|
+
${A.pathname}${A.search}
|
|
4
|
+
`}function BC(C,A){l(n(C),{recursive:!0});let _=`${C}.tmp-${process.pid}`;h(_,RC(A),"utf8");try{v(C)}catch{}a(_,C)}async function x({activePortFile:C,modeFile:A,env:_=process.env,excludePorts:R=[],autoPorts:B=q}={}){if(!U(_))return null;let O=await _C({env:_,excludePorts:R,autoPorts:B});if(!O)return null;if(BC(C,O),A)h(A,"existing","utf8");return O}function OC(C){return String(C||"").trim()==="existing"}function Z(C,A){if(!A||!V(A))return!1;if(!OC(Q(A,"utf8")))return!1;return!!C&&V(C)}import{existsSync as w}from"node:fs";import{platform as y}from"node:os";function HC(C=y()){if(C==="win32")return{cloak:["C:/Program Files/CloakBrowser/CloakBrowser.exe","C:/Program Files (x86)/CloakBrowser/CloakBrowser.exe"],chrome:["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]};if(C==="darwin")return{cloak:["/Applications/CloakBrowser.app/Contents/MacOS/CloakBrowser","/Applications/Cloak Browser.app/Contents/MacOS/CloakBrowser"],chrome:["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]};return{cloak:["/usr/bin/cloakbrowser","/usr/local/bin/cloakbrowser","/opt/CloakBrowser/CloakBrowser"],chrome:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium-browser","/usr/bin/chromium","/snap/bin/chromium"]}}function j(C,A=w){return C.find((_)=>_&&A(_))||null}function KC(C,A){for(let _ of A){let R=C[_]?.trim();if(R)return{key:_,path:R}}return null}function WC(C,A){if(C==="chrome"||A==="CHROME_PATH")return"Chrome";if(C==="cloak"||A==="DM_CUA_CLOAK_PATH"||A==="CLOAKBROWSER_BINARY_PATH")return"CloakBrowser";return"browser"}function P({env:C=process.env,platformName:A=y(),exists:_=w}={}){let R=(C.GREEDY_SEARCH_BROWSER||C.DM_CUA_BROWSER||"auto").toLowerCase(),O=KC(C,R==="chrome"?["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","CHROME_PATH"]:["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","DM_CUA_CLOAK_PATH","CLOAKBROWSER_BINARY_PATH","CHROME_PATH"]);if(O)return{path:O.path,label:WC(R,O.key)};let W=HC(A);if(R==="cloak")return{path:j(W.cloak,_),label:"CloakBrowser"};if(R==="chrome")return{path:j(W.chrome,_),label:"Chrome"};let K=j(W.cloak,_);return{path:K||j(W.chrome,_),label:K?"CloakBrowser":"Chrome"}}var E=9222,k=J(N(),"greedysearch-chrome-profile"),G=J(k,"DevToolsActivePort"),I=J(N(),"greedysearch-chrome.pid"),D=J(N(),"greedysearch-chrome-mode");function z(){if(!EC(I))return!1;let C=Number.parseInt(u(I,"utf8").trim(),10);if(!C)return!1;try{return process.kill(C,0),C}catch{return!1}}function T(C){try{if(p()==="win32"){let _=c("netstat -ano -p TCP 2>nul",{encoding:"utf8"}),R=new RegExp(String.raw`TCP\s+[^\s]*:${C}\s+[^\s]*:0\s+LISTENING\s+(\d+)`,"i"),B=_.match(R);return B?Number.parseInt(B[1],10):null}}catch{return null}}function $(C){try{if(p()==="win32")c(`taskkill /F /PID ${C} /T`,{stdio:"ignore"});else process.kill(C,"SIGKILL");return!0}catch{return!1}}function g(C,A=1000){return new Promise((_)=>{let R=MC.get(C,(B)=>{let O="";B.on("data",(W)=>O+=W),B.on("end",()=>_({ok:B.statusCode===200,body:O}))});R.on("error",()=>_({ok:!1})),R.setTimeout(A,()=>{R.destroy(),_({ok:!1})})})}async function DC(C){try{let A=await g(`http://localhost:${C}/json/version`).then((H)=>JSON.parse(H.body)),R=(await g(`http://localhost:${C}/json/list`).then((H)=>JSON.parse(H.body))).find((H)=>H.type==="page")?.id;if(!R)return;let B=A.webSocketDebuggerUrl;if(typeof B!=="string")return;let O=new URL(B);if(O.hostname!=="localhost"&&O.hostname!=="127.0.0.1")return;if(!/^ws:\/\/localhost:\d+/.test(`ws://${O.host}`))return;let W=O.pathname,K=new WebSocket(`ws://localhost:${C}${W}`);await new Promise((H)=>{K.onopen=()=>K.send(JSON.stringify({id:1,method:"Browser.getWindowForTarget",params:{targetId:R}})),K.onmessage=(Y)=>{let M=JSON.parse(Y.data);if(M.id===1&&M.result?.windowId)K.send(JSON.stringify({id:2,method:"Browser.setWindowBounds",params:{windowId:M.result.windowId,bounds:{windowState:"minimized"}}}));else if(M.id===2)K.close(),H()},K.onerror=()=>{K.close(),H()},setTimeout(()=>{try{K.close()}catch{}H()},5000)})}catch{}}async function LC(C=15000){let A=Date.now()+C;while(Date.now()<A){let{ok:_,body:R}=await g(`http://localhost:${E}/json/version`,1500);if(_)try{let{webSocketDebuggerUrl:B}=JSON.parse(R),O=new URL(B),W=`${O.pathname}${O.search}`;return f(G,`localhost:${E}
|
|
5
|
+
${W}`,"utf8"),!0}catch{}await new Promise((B)=>setTimeout(B,400))}return!1}function F(){let C=z();if(C)$(C);let A=T(E);if(A&&A!==C)$(A);try{L(I)}catch{}try{L(G)}catch{}try{L(D)}catch{}return new Promise((_)=>{let R=Date.now(),B=()=>{let O=T(E);if(!O)return _(!0);if(Date.now()-R>5000)return _(!1);$(O),setTimeout(B,500)};B()})}async function jC(){let C=process.argv[2];if(C==="--kill"){if(Z(G,D)){try{L(G)}catch{}try{L(D)}catch{}console.log("Detached from existing browser CDP endpoint; no browser process was killed.");return}await F(),console.log("Browser stopped.");return}if(C==="--status"){if(Z(G,D)){try{let H=m(u(G,"utf8"));console.log(`Reusing existing browser — ${H}`)}catch{console.log("Reusing existing browser.")}return}let K=z()||T(E);if(K)console.log(`Running — pid ${K}, port ${E}`);else console.log("Not running.");return}let A=await x({activePortFile:G,modeFile:D,excludePorts:z()?[E]:[],autoPorts:z()?[9223]:[E,9223]});if(A){console.log(`Reusing existing browser CDP endpoint ${A.httpUrl} (${A.source}).`);return}console.log("Stopping any existing browser on port 9222..."),await F();let _=P();if(!_.path)console.error("CloakBrowser/Chrome not found. Set GREEDY_SEARCH_BROWSER_PATH, DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH."),process.exit(1);GC(k,{recursive:!0});let R=[`--remote-debugging-port=${E}`,"--disable-features=DevToolsPrivacyUI","--no-first-run","--no-default-browser-check","--disable-default-apps",`--user-data-dir=${k}`,"--profile-directory=Default","--new-window","about:blank"];console.log(`Launching visible ${_.label}...`);let B=YC(_.path,R,{detached:!0,stdio:"ignore"});B.unref();let O=B.pid;if(f(I,String(O)),f(D,"visible","utf8"),console.log(`${_.label} PID: ${O}`),!await LC())console.error(`${_.label} did not become ready within 15s.`),process.exit(1);await DC(E),console.log(`Visible ${_.label} ready on port 9222.`),console.log(`Keep this terminal open to keep ${_.label} alive.`)}jC();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as R,spawn as Lz}from"node:child_process";import{existsSync as b,mkdirSync as l,readdirSync as Nz,readFileSync as S,unlinkSync as A,writeFileSync as T}from"node:fs";import
|
|
2
|
+
import{execSync as R,spawn as Lz}from"node:child_process";import{existsSync as b,mkdirSync as l,readdirSync as Nz,readFileSync as S,unlinkSync as A,writeFileSync as T}from"node:fs";import d from"node:http";import{platform as I,tmpdir as f}from"node:os";import{join as D}from"node:path";import{existsSync as g,mkdirSync as r,readFileSync as q,renameSync as i,unlinkSync as o,writeFileSync as k}from"node:fs";import t from"node:http";import{platform as F}from"node:os";import{dirname as e}from"node:path";var w=[9222,9223],zz=/^(0|false|no|off)$/i;function Jz(z){return[...new Set(z.filter(Boolean))]}function h(z,J="localhost"){let K=String(z||"").trim().split(/\r?\n/).map((Y)=>Y.trim()).filter(Boolean);if(K.length===0)throw Error("empty DevToolsActivePort");let[Q,X=""]=K;if(/^wss?:\/\//i.test(Q))return Q;if(Q.includes(":"))return`ws://${Q}${X}`;return`ws://${J}:${Q}${X}`}function y(z,J="explicit"){let K=new URL(z),Q=K.protocol==="wss:"?"wss:":"ws:",X=K.port?Number.parseInt(K.port,10):Q==="wss:"?443:80;return{source:J,wsUrl:`${Q}//${K.host}${K.pathname}${K.search}`,host:K.hostname,port:X,path:`${K.pathname}${K.search}`,httpUrl:`http://${K.hostname}:${X}`}}function P(z=process.env){return![z.GREEDY_SEARCH_REUSE_EXISTING_BROWSER,z.DM_CUA_REUSE_EXISTING_BROWSER].some((J)=>J!==void 0&&zz.test(String(J)))}function U(z){let J=Number.parseInt(String(z??""),10);return Number.isInteger(J)&&J>0&&J<65536?J:null}function Kz(z){if(!z)return null;let J=String(z).trim();if(!J)return null;let K=new URL(J.includes("://")?J:`http://${J}`),Q=U(K.port)||(K.protocol==="https:"?443:80);return{host:K.hostname,port:Q,source:`env:${J}`}}function Qz(z){if(!z)return[];return String(z).split(/[,\s]+/).map(U).filter(Boolean)}function Xz({env:z=process.env,platformName:J=F(),procVersionText:K=null}={}){if(J!=="linux")return!1;if(z.WSL_DISTRO_NAME||z.WSL_INTEROP)return!0;let Q=K??(()=>{try{return q("/proc/version","utf8")}catch{return""}})();return/microsoft|wsl/i.test(Q)}function Yz({env:z=process.env,platformName:J=F(),procVersionText:K=null,resolvConfText:Q=null}={}){let X=["localhost","127.0.0.1"];if(Xz({env:z,platformName:J,procVersionText:K})){let G=(Q??(()=>{try{return q("/etc/resolv.conf","utf8")}catch{return""}})()).match(/^\s*nameserver\s+([^\s#]+)/m);if(G)X.push(G[1]);X.push("host.docker.internal")}return Jz(X)}function Zz({env:z=process.env,hosts:J=Yz({env:z}),autoPorts:K=w,excludePorts:Q=[]}={}){let X=[];for(let $ of["GREEDY_SEARCH_CDP_WS_URL","DM_CUA_CDP_WS_URL","CDP_WS_URL"])if(z[$])X.push({wsUrl:z[$],source:`env:${$}`});for(let $ of["GREEDY_SEARCH_CDP_URL","DM_CUA_CDP_URL","CDP_URL"])try{let O=Kz(z[$]);if(O)X.push(O)}catch{}for(let $ of["GREEDY_SEARCH_EXISTING_CDP_PORT","DM_CUA_EXISTING_CDP_PORT","GREEDY_SEARCH_CDP_PORT","DM_CUA_CDP_PORT"]){let O=U(z[$]);if(!O)continue;for(let W of J)X.push({host:W,port:O,source:`env:${$}`})}let Y=Qz(z.GREEDY_SEARCH_EXISTING_CDP_PORTS);for(let $ of Y)for(let O of J)X.push({host:O,port:$,source:"env:GREEDY_SEARCH_EXISTING_CDP_PORTS"});let G=new Set(Q.filter(Boolean));if(P(z))for(let $ of K){if(G.has($))continue;for(let O of J)X.push({host:O,port:$,source:"auto"})}let Z=new Set;return X.filter(($)=>{let O=$.wsUrl||`${$.host}:${$.port}`;if(Z.has(O))return!1;return Z.add(O),!0})}async function $z(z,{timeoutMs:J=700}={}){if(z.wsUrl)return y(z.wsUrl,z.source);let K=z.host||"localhost",Q=z.port;if(!Q)return null;let X=await new Promise((Y)=>{let G=t.get({host:K,port:Q,path:"/json/version",timeout:J},(Z)=>{let $="";Z.setEncoding("utf8"),Z.on("data",(O)=>$+=O),Z.on("end",()=>Y(Z.statusCode===200?$:null))});G.on("error",()=>Y(null)),G.setTimeout(J,()=>{G.destroy(),Y(null)})});if(!X)return null;try{let Y=JSON.parse(X);if(!Y.webSocketDebuggerUrl)return null;let G=y(Y.webSocketDebuggerUrl,z.source),Z=G.path||new URL(Y.webSocketDebuggerUrl).pathname;return{...G,host:K,port:Q,httpUrl:`http://${K}:${Q}`,wsUrl:`ws://${K}:${Q}${Z}`,path:Z}}catch{return null}}async function Gz(z={}){for(let J of Zz(z)){let K=await $z(J,z);if(K)return K}return null}function Oz(z){if(!z)throw Error("missing CDP endpoint");let J=new URL(z.wsUrl);return`${J.host}
|
|
3
3
|
${J.pathname}${J.search}
|
|
4
|
-
`}function jz(z,J){
|
|
5
|
-
`)[0],10):null}catch{return null}}function E(z){try{if(I()==="win32")R(`taskkill /F /T /PID ${z}`,{stdio:"ignore"});else process.kill(z,"SIGTERM");return!0}catch{return!1}}function p(){let z=
|
|
6
|
-
${G}`,"utf8"),!0}catch{}await new Promise((X)=>setTimeout(X,400))}return!1}async function Uz(){let z=process.argv[2];if(z==="--kill"){if(C(N,L)){try{A(N)}catch{}try{A(L)}catch{}console.log("Detached from existing browser CDP endpoint; no browser process was killed.");return}p();let Z=_()||
|
|
4
|
+
`}function jz(z,J){r(e(z),{recursive:!0});let K=`${z}.tmp-${process.pid}`;k(K,Oz(J),"utf8");try{o(z)}catch{}i(K,z)}async function m({activePortFile:z,modeFile:J,env:K=process.env,excludePorts:Q=[],autoPorts:X=w}={}){if(!P(K))return null;let Y=await Gz({env:K,excludePorts:Q,autoPorts:X});if(!Y)return null;if(jz(z,Y),J)k(J,"existing","utf8");return Y}function Az(z){return String(z||"").trim()==="existing"}function C(z,J){if(!J||!g(J))return!1;if(!Az(q(J,"utf8")))return!1;return!!z&&g(z)}function Vz(z,J){let K=Number.parseInt(String(z??""),10);return Number.isInteger(K)&&K>1024&&K<65535?K:J}var j=Vz(process.env.GREEDY_SEARCH_PORT,9222),H=process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||D(f(),"greedysearch-chrome-profile"),N=D(H,"DevToolsActivePort"),V=process.env.GREEDY_SEARCH_PID_FILE||D(f(),"greedysearch-chrome.pid"),L=process.env.GREEDY_SEARCH_MODE_FILE||D(f(),"greedysearch-chrome-mode"),Wz=/^(1|true|yes|on)$/i.test(process.env.GREEDY_SEARCH_ALLOW_PORT_CLEANUP??"1");function a(z){return z.find((J)=>J&&b(J))||null}function v(){let z=I();return a(z==="win32"?["C:/Program Files/CloakBrowser/CloakBrowser.exe","C:/Program Files (x86)/CloakBrowser/CloakBrowser.exe"]:z==="darwin"?["/Applications/CloakBrowser.app/Contents/MacOS/CloakBrowser","/Applications/Cloak Browser.app/Contents/MacOS/CloakBrowser"]:["/usr/bin/cloakbrowser","/usr/local/bin/cloakbrowser","/opt/CloakBrowser/CloakBrowser"])}function u(){let z=I();return a(z==="win32"?["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]:z==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium-browser","/usr/bin/chromium","/snap/bin/chromium"])}function _z(){let z=(process.env.GREEDY_SEARCH_BROWSER||process.env.DM_CUA_BROWSER||"auto").toLowerCase(),J=process.env.GREEDY_SEARCH_BROWSER_PATH||process.env.DM_CUA_BROWSER_PATH||process.env.DM_CUA_CLOAK_PATH||process.env.CLOAKBROWSER_BINARY_PATH||process.env.CHROME_PATH;if(J){let Q=J===process.env.DM_CUA_CLOAK_PATH||J===process.env.CLOAKBROWSER_BINARY_PATH,X=J===process.env.CHROME_PATH;return{path:J,label:z==="chrome"||X?"Chrome":z==="cloak"||Q?"CloakBrowser":"browser"}}if(z==="cloak")return{path:v(),label:"CloakBrowser"};if(z==="chrome")return{path:u(),label:"Chrome"};let K=v();return{path:K||u(),label:K?"CloakBrowser":"Chrome"}}var B=()=>process.env.GREEDY_SEARCH_VISIBLE!=="1",Bz=[`--remote-debugging-port=${j}`,"--disable-features=DevToolsPrivacyUI","--no-first-run","--no-default-browser-check","--disable-default-apps","--disable-blink-features=AutomationControlled",`--user-data-dir=${H}`,"--profile-directory=Default","--window-size=1920,1080","--lang=en-US","--force-color-profile=srgb","--disable-background-timer-throttling","--disable-renderer-backgrounding","--disable-backgrounding-occluded-windows"];function Dz(z){try{let J=D(z,".."),Q=Nz(J).find((X)=>/^\d{1,10}\.\d{1,10}\.\d{1,10}\.\d{1,10}$/.test(X));if(Q)return Q.split(".")[0]}catch{}try{let K=R(`"${z}" --version`,{encoding:"utf8",timeout:5000}).trim().match(/(\d{1,10})\.\d{1,10}\.\d{1,10}/);if(K)return K[1]}catch{}return null}function Rz(z){let J=[...Bz];if(B()){J.push("--headless=new");let K=Dz(z)||"136";J.push(`--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${K}.0.0.0 Safari/537.36`)}return J.push("about:blank"),J}var Iz=()=>process.env.GREEDY_SEARCH_VISIBLE==="1";function Hz(){try{if(!b(L))return!0;return S(L,"utf8").trim()==="headless"}catch{return!0}}async function Mz(){if(B())return;try{let z=await new Promise((G,Z)=>{d.get(`http://localhost:${j}/json/version`,($)=>{let O="";$.on("data",(W)=>O+=W),$.on("end",()=>G(JSON.parse(O)))}).on("error",Z)}),J=new URL(z.webSocketDebuggerUrl).pathname,K=globalThis.WebSocket;if(!K)return;let Q=new K(`ws://localhost:${j}${J}`),X=0,Y=new Map;Q.onopen=()=>{let G=++X;Y.set(G,{resolve:(Z)=>{let O=(Z.targetInfos||[]).find((M)=>M.type==="page");if(!O){Q.close();return}let W=++X;Y.set(W,{resolve:(M)=>{let s=M.windowId,x=++X;Y.set(x,{resolve:()=>{},reject:()=>{}}),Q.send(JSON.stringify({id:x,method:"Browser.setWindowBounds",params:{windowId:s,bounds:{windowState:"minimized"}}})),setTimeout(()=>Q.close(),500)},reject:()=>Q.close()}),Q.send(JSON.stringify({id:W,method:"Browser.getWindowForTarget",params:{targetId:O.targetId}}))},reject:()=>Q.close()}),Q.send(JSON.stringify({id:G,method:"Target.getTargets",params:{}}))},Q.onmessage=(G)=>{let Z=JSON.parse(G.data);if(Z.id&&Y.has(Z.id)){let{resolve:$,reject:O}=Y.get(Z.id);if(Y.delete(Z.id),Z.error)O?.(Z.error);else $?.(Z.result)}},setTimeout(()=>Q.close(),5000)}catch{}}function _(){if(!b(V))return!1;let z=Number.parseInt(S(V,"utf8").trim(),10);if(!z)return!1;try{return process.kill(z,0),z}catch{return!1}}function n(z){try{if(I()==="win32"){let Q=R("netstat -ano -p TCP 2>nul",{encoding:"utf8"}),X=new RegExp(String.raw`TCP\s+[^\s]*:${z}\s+[^\s]*:0\s+LISTENING\s+(\d+)`,"i"),Y=Q.match(X);return Y?Number.parseInt(Y[1],10):null}let K=R(String.raw`lsof -i :${z} -t 2>/dev/null || ss -tlnp 2>/dev/null | grep :${z} | grep -oP 'pid=\K\d+'`,{encoding:"utf8"}).trim();return K?Number.parseInt(K.split(`
|
|
5
|
+
`)[0],10):null}catch{return null}}function E(z){try{if(I()==="win32")R(`taskkill /F /T /PID ${z}`,{stdio:"ignore"});else process.kill(z,"SIGTERM");return!0}catch{return!1}}function p(){let z=n(j);if(!z)return;let J=_();if(J&&z===J)return;if(!Wz)console.error(`Browser/CDP port ${j} is already owned by untracked pid ${z}; refusing to kill it. Set GREEDY_SEARCH_PORT or DM_CUA_PORT to a free port.`),process.exit(1);console.log(`Ghost browser on port ${j} (pid ${z}) — cleaning up...`),E(z);try{A(V)}catch{}try{A(N)}catch{}try{A(L)}catch{}}function qz(z,J=1000){return new Promise((K)=>{let Q=d.get(z,(X)=>{let Y="";X.on("data",(G)=>Y+=G),X.on("end",()=>K({ok:X.statusCode===200,body:Y}))});Q.on("error",()=>K({ok:!1})),Q.setTimeout(J,()=>{Q.destroy(),K({ok:!1})})})}async function c(z=15000){let J=Date.now()+z;while(Date.now()<J){let{ok:K,body:Q}=await qz(`http://localhost:${j}/json/version`,1500);if(K)try{let{webSocketDebuggerUrl:X}=JSON.parse(Q),Y=new URL(X),G=`${Y.pathname}${Y.search}`;return l(H,{recursive:!0}),T(N,`localhost:${j}
|
|
6
|
+
${G}`,"utf8"),!0}catch{}await new Promise((X)=>setTimeout(X,400))}return!1}async function Uz(){let z=process.argv[2];if(z==="--kill"){if(C(N,L)){try{A(N)}catch{}try{A(L)}catch{}console.log("Detached from existing browser CDP endpoint; no browser process was killed.");return}p();let Z=_()||n(j);if(Z){let $=E(Z);console.log($?`Stopped browser (pid ${Z}).`:`Failed to stop pid ${Z}.`)}else console.log("GreedySearch browser is not running.");try{A(V)}catch{}try{A(N)}catch{}try{A(L)}catch{}return}if(z==="--status"){if(C(N,L)){try{let $=h(S(N,"utf8"));console.log(`Reusing existing browser — ${$}`)}catch{console.log("Reusing existing browser.")}return}let Z=_();if(Z)console.log(`Running — pid ${Z}, port ${j}`);else console.log("Not running.");return}let J=_(),K=await m({activePortFile:N,modeFile:L,excludePorts:J?[j]:[],autoPorts:J?[9223]:[j,9223]});if(K){console.log(`Reusing existing browser CDP endpoint ${K.httpUrl} (${K.source}).`);return}p();let Q=_();if(Q)if(process.env.GREEDY_SEARCH_VISIBLE==="1"&&!process.argv.includes("--headless")&&Hz()){console.log(`Headless browser running (pid ${Q}) but visible requested — killing...`),E(Q);try{A(V)}catch{}try{A(L)}catch{}}else{if(await c(5000)){console.log(`GreedySearch browser already running (pid ${Q}).`);return}console.log(`Stale PID ${Q} — launching fresh.`);try{A(V)}catch{}}let X=_z();if(!X.path)console.error("CloakBrowser/Chrome not found. Set GREEDY_SEARCH_BROWSER_PATH, DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH."),process.exit(1);if(l(H,{recursive:!0}),console.log(`Launching GreedySearch ${X.label} on port ${j}...`),B())console.log("Headless mode — no window will be shown");else if(!Iz())console.log("Window will be minimized");let Y=Lz(X.path,Rz(X.path),{detached:!0,stdio:"ignore"});if(Y.unref(),T(V,String(Y.pid)),T(L,B()?"headless":"visible","utf8"),!await c())console.error(`${X.label} did not become ready within 15s.`),process.exit(1);if(B())console.log("Ready (headless).");else await Mz(),console.log("Ready.")}Uz();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as c}from"node:fs";import{platform as s}from"node:os";function C(o=s()){if(o==="win32")return{cloak:["C:/Program Files/CloakBrowser/CloakBrowser.exe","C:/Program Files (x86)/CloakBrowser/CloakBrowser.exe"],chrome:["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]};if(o==="darwin")return{cloak:["/Applications/CloakBrowser.app/Contents/MacOS/CloakBrowser","/Applications/Cloak Browser.app/Contents/MacOS/CloakBrowser"],chrome:["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]};return{cloak:["/usr/bin/cloakbrowser","/usr/local/bin/cloakbrowser","/opt/CloakBrowser/CloakBrowser"],chrome:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/usr/bin/chromium-browser","/usr/bin/chromium","/snap/bin/chromium"]}}function l(o,e=c){return o.find((r)=>r&&e(r))||null}function p(o,e){for(let r of e){let a=o[r]?.trim();if(a)return{key:r,path:a}}return null}function m(o,e){if(o==="chrome"||e==="CHROME_PATH")return"Chrome";if(o==="cloak"||e==="DM_CUA_CLOAK_PATH"||e==="CLOAKBROWSER_BINARY_PATH")return"CloakBrowser";return"browser"}function _({env:o=process.env,platformName:e=s(),exists:r=c}={}){let a=(o.GREEDY_SEARCH_BROWSER||o.DM_CUA_BROWSER||"auto").toLowerCase(),n=p(o,a==="chrome"?["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","CHROME_PATH"]:["GREEDY_SEARCH_BROWSER_PATH","DM_CUA_BROWSER_PATH","DM_CUA_CLOAK_PATH","CLOAKBROWSER_BINARY_PATH","CHROME_PATH"]);if(n)return{path:n.path,label:m(a,n.key)};let t=C(e);if(a==="cloak")return{path:l(t.cloak,r),label:"CloakBrowser"};if(a==="chrome")return{path:l(t.chrome,r),label:"Chrome"};let i=l(t.cloak,r);return{path:i||l(t.chrome,r),label:i?"CloakBrowser":"Chrome"}}export{_ as resolveBrowser,l as firstExisting,C as browserCandidates};
|