@duckmind/dm-windows-x64 0.52.3 → 0.53.1
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/README.md +17 -0
- package/dm.exe +0 -0
- package/extensions/.dm-extensions.json +15 -8
- package/extensions/dm-cua/bin/browser-cua.mjs +6 -6
- package/extensions/dm-cua/index.js +5 -5
- package/extensions/dm-cua/src/browser-cua-lib.mjs +2 -2
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +8 -1
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +1 -1
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +1 -1
- package/extensions/greedysearch-dm/bin/cdp.mjs +29 -20
- package/extensions/greedysearch-dm/bin/gschrome.mjs +1 -10
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +1 -1
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +1 -4
- package/extensions/greedysearch-dm/bin/launch.mjs +9 -5
- package/extensions/greedysearch-dm/bin/mcp.mjs +375 -0
- package/extensions/greedysearch-dm/bin/search.mjs +310 -156
- package/extensions/greedysearch-dm/bin/visible.mjs +1 -1
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +205 -68
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +229 -140
- package/extensions/greedysearch-dm/extractors/common.mjs +160 -50
- package/extensions/greedysearch-dm/extractors/consensus.mjs +225 -92
- package/extensions/greedysearch-dm/extractors/consent.mjs +44 -17
- package/extensions/greedysearch-dm/extractors/gemini.mjs +275 -136
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +172 -64
- package/extensions/greedysearch-dm/extractors/logically.mjs +183 -69
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +331 -65
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +118 -41
- package/extensions/greedysearch-dm/index.js +20 -17
- package/extensions/greedysearch-dm/package.json +8 -3
- package/extensions/greedysearch-dm/skills/greedy-search/skill.md +8 -8
- package/extensions/greedysearch-dm/src/fetcher.mjs +2 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +8 -6
- package/extensions/greedysearch-dm/src/github.mjs +7 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +10 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +48 -0
- package/extensions/greedysearch-dm/src/search/chrome.mjs +129 -53
- package/extensions/greedysearch-dm/src/search/constants.mjs +8 -8
- package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +154 -77
- package/extensions/greedysearch-dm/src/search/minimize.mjs +1 -0
- package/extensions/greedysearch-dm/src/search/paths.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +1 -0
- package/extensions/greedysearch-dm/src/search/progress.mjs +2 -0
- package/extensions/greedysearch-dm/src/search/recovery.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +262 -167
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +11 -0
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +827 -0
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +11 -11
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +11 -11
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +23 -20
- package/extensions/greedysearch-dm/src/tools/shared.js +10 -9
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +1 -1
- package/package.json +1 -1
- package/extensions/greedysearch-dm/src/search/cdp-endpoint.mjs +0 -3
- package/extensions/greedysearch-dm/src/utils/browser-executable.mjs +0 -1
package/README.md
CHANGED
|
@@ -3,3 +3,20 @@
|
|
|
3
3
|
<strong>DuckMind (dm)</strong> is a <strong>minimal, fast AI coworker</strong> that runs in your terminal.
|
|
4
4
|
No UI overhead. Just plan, run, and get things done.
|
|
5
5
|
</p>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Windows Setup
|
|
9
|
+
|
|
10
|
+
DM requires a bash shell on Windows. It checks these locations in order:
|
|
11
|
+
|
|
12
|
+
1. `shellPath` in the global `~/.dm/agent/settings.json`
|
|
13
|
+
2. Git Bash at `C:\Program Files\Git\bin\bash.exe`
|
|
14
|
+
3. Every `bash.exe` found on `PATH` (for example Cygwin, MSYS2, or WSL)
|
|
15
|
+
|
|
16
|
+
For most users, Git for Windows is sufficient. To use a custom shell:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"shellPath": "C:\\cygwin64\\bin\\bash.exe"
|
|
21
|
+
}
|
|
22
|
+
```
|
package/dm.exe
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"status": "ok",
|
|
3
|
-
"prepared_at": "2026-07-
|
|
3
|
+
"prepared_at": "2026-07-23T06:36:46.219447+00:00",
|
|
4
4
|
"managed_entries": [
|
|
5
5
|
{
|
|
6
6
|
"id": "dm-context",
|
|
@@ -341,6 +341,8 @@
|
|
|
341
341
|
"drop-files"
|
|
342
342
|
],
|
|
343
343
|
"stripped_documentation": [
|
|
344
|
+
"docs/",
|
|
345
|
+
"CHANGELOG.md",
|
|
344
346
|
"LICENSE",
|
|
345
347
|
"README.md"
|
|
346
348
|
],
|
|
@@ -355,6 +357,7 @@
|
|
|
355
357
|
"bin/kill-visible.mjs",
|
|
356
358
|
"bin/launch-visible.mjs",
|
|
357
359
|
"bin/launch.mjs",
|
|
360
|
+
"bin/mcp.mjs",
|
|
358
361
|
"bin/search.mjs",
|
|
359
362
|
"bin/visible.mjs",
|
|
360
363
|
"extractors/bing-copilot.mjs",
|
|
@@ -376,34 +379,38 @@
|
|
|
376
379
|
"src/github.mjs",
|
|
377
380
|
"src/reddit.mjs",
|
|
378
381
|
"src/search/browser-lifecycle.mjs",
|
|
379
|
-
"src/search/
|
|
382
|
+
"src/search/challenge-detect.mjs",
|
|
380
383
|
"src/search/chrome.mjs",
|
|
381
384
|
"src/search/constants.mjs",
|
|
382
385
|
"src/search/defaults.mjs",
|
|
383
386
|
"src/search/engines.mjs",
|
|
384
387
|
"src/search/fetch-source.mjs",
|
|
385
388
|
"src/search/file-sources.mjs",
|
|
389
|
+
"src/search/minimize.mjs",
|
|
386
390
|
"src/search/output.mjs",
|
|
387
391
|
"src/search/paths.mjs",
|
|
388
392
|
"src/search/pdf.mjs",
|
|
393
|
+
"src/search/port-pid.mjs",
|
|
394
|
+
"src/search/progress.mjs",
|
|
389
395
|
"src/search/query.mjs",
|
|
390
396
|
"src/search/recovery.mjs",
|
|
391
397
|
"src/search/research.mjs",
|
|
398
|
+
"src/search/scale-aware.mjs",
|
|
399
|
+
"src/search/simple-research.mjs",
|
|
392
400
|
"src/search/sources.mjs",
|
|
393
401
|
"src/search/synthesis-runner.mjs",
|
|
394
402
|
"src/search/synthesis.mjs",
|
|
395
403
|
"src/tools/greedy-search-handler.js",
|
|
396
404
|
"src/tools/shared.js",
|
|
397
405
|
"src/types.js",
|
|
398
|
-
"src/utils/browser-executable.mjs",
|
|
399
406
|
"src/utils/content.mjs",
|
|
400
407
|
"src/utils/helpers.js",
|
|
401
408
|
"src/utils/node-runtime.mjs",
|
|
402
409
|
"src/utils/system-cmds.mjs"
|
|
403
410
|
],
|
|
404
|
-
"file_count":
|
|
405
|
-
"before_bytes":
|
|
406
|
-
"after_bytes":
|
|
411
|
+
"file_count": 58,
|
|
412
|
+
"before_bytes": 609953,
|
|
413
|
+
"after_bytes": 1166455,
|
|
407
414
|
"externals": [
|
|
408
415
|
"@duckmind/dm-agent-core",
|
|
409
416
|
"@duckmind/dm-ai",
|
|
@@ -628,8 +635,8 @@
|
|
|
628
635
|
"src/browser-cua-lib.mjs"
|
|
629
636
|
],
|
|
630
637
|
"file_count": 3,
|
|
631
|
-
"before_bytes":
|
|
632
|
-
"after_bytes":
|
|
638
|
+
"before_bytes": 22185,
|
|
639
|
+
"after_bytes": 32604,
|
|
633
640
|
"externals": [
|
|
634
641
|
"@duckmind/dm-agent-core",
|
|
635
642
|
"@duckmind/dm-ai",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createHash as
|
|
3
|
-
`)}case"navigate":return[`Navigated browser tab ${
|
|
4
|
-
`);case"snapshot":return[`Browser snapshot for ${
|
|
5
|
-
`);case"screenshot":return[`Saved browser screenshot for ${
|
|
6
|
-
`);case"click":return`Clicked selector ${JSON.stringify(
|
|
2
|
+
import{createHash as R}from"node:crypto";import{spawn as x}from"node:child_process";import{existsSync as W,mkdirSync as h,readFileSync as S}from"node:fs";import P from"node:http";import{homedir as g,platform as d,tmpdir as T}from"node:os";import{dirname as B,join as k,resolve as L}from"node:path";import{fileURLToPath as v}from"node:url";var y=B(v(import.meta.url)),K2=L(y,".."),u=9322,c=400,N=60000,p=/^(about:|https?:\/\/|file:|chrome-error:\/\/)/i,l={chrome:"Chrome",cloak:"CloakBrowser"};function I(J){let V=Number.parseInt(String(J??""),10);return Number.isInteger(V)&&V>1024&&V<65535?V:null}function n(J){return R("sha256").update(String(J||"default")).digest("hex")}function i(J){let V=String(J||"chrome").trim().toLowerCase();if(V==="cloakbrowser"||V==="cloak-browser")return"cloak";if(V==="chromium"||V==="google-chrome"||V==="chrome")return"chrome";return V.replace(/[^a-z0-9_.-]/g,"-")||"chrome"}function o(J,V){let $=J.DM_CUA_BROWSER_PATH||(V==="cloak"?J.DM_CUA_CLOAK_PATH||J.CLOAKBROWSER_BINARY_PATH:void 0)||J.CHROME_PATH;return $?L(String($)):void 0}function a(J=process.env,V=process.cwd()){let $=J.DM_CUA_SCOPE||J.DM_CODING_AGENT_DIR||J.PI_CODING_AGENT_DIR||V,Q=n(L(String($||"."))),Z=String(J.DM_CUA_INSTANCE_ID||Q.slice(0,12)).replace(/[^a-zA-Z0-9_.-]/g,"-"),X=i(J.DM_CUA_BROWSER||J.DM_BROWSER_CUA_BROWSER||J.DM_CUA_BROWSER_KIND),z=J.DM_CUA_BROWSER_DISPLAY_NAME||l[X]||X,A=o(J,X),H=I(J.DM_CUA_PORT)??I(J.GREEDY_SEARCH_PORT)??u+Number.parseInt(Q.slice(0,8),16)%c,j=X==="chrome"?"chrome":X,Y=L(J.DM_CUA_PROFILE_DIR||k(T(),`dm-cua-${j}-profile-${Z}`)),q=d()==="win32"?T():"/tmp";return{instanceId:Z,browserKind:X,browserDisplayName:z,browserExecutablePath:A,port:H,profileDir:Y,pidFile:k(Y,"chrome.pid"),modeFile:k(Y,"chrome-mode"),pagesCache:k(Y,"cdp-pages.json"),socketDir:k(q,`dm-cua-cdp-${Z}`)}}var M=a(),s=M.port,L2=M.profileDir;function D(){return{kind:M.browserKind,displayName:M.browserDisplayName,executablePath:M.browserExecutablePath,profileDir:M.profileDir,port:M.port}}function t(){if(M.browserKind==="cloak"&&!M.browserExecutablePath)throw Error(["CloakBrowser selected for browser CUA, but no executable path was provided.","Install/pre-download CloakBrowser yourself, then set DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH.","DM does not bundle the compiled CloakBrowser binary because its upstream license allows use but not redistribution."].join(" "));if(M.browserExecutablePath&&!W(M.browserExecutablePath))throw Error(`${M.browserDisplayName} executable not found: ${M.browserExecutablePath}`)}function C(){let V=[L(y,"..","greedysearch-dm"),L(y,"..","..","greedysearch-dm")].map(($)=>({launchScript:k($,"bin","launch.mjs"),cdpScript:k($,"bin","cdp.mjs")}));for(let $ of V)if(W($.launchScript)&&W($.cdpScript))return $;return V[0]}function r(J=M,V=process.env){let $=V.GREEDY_SEARCH_VISIBLE??V.DM_CUA_VISIBLE??V.DM_BROWSER_CUA_VISIBLE;return{...V,...J.browserExecutablePath?{CHROME_PATH:J.browserExecutablePath}:{},CDP_PROFILE_DIR:J.profileDir.replace(/\\/g,"/"),CDP_PAGES_CACHE:J.pagesCache.replace(/\\/g,"/"),CDP_SOCKET_DIR:J.socketDir.replace(/\\/g,"/"),GREEDY_SEARCH_BROWSER_LABEL:J.browserDisplayName,GREEDY_SEARCH_PORT:String(J.port),GREEDY_SEARCH_PROFILE_DIR:J.profileDir.replace(/\\/g,"/"),GREEDY_SEARCH_PID_FILE:J.pidFile.replace(/\\/g,"/"),GREEDY_SEARCH_MODE_FILE:J.modeFile.replace(/\\/g,"/"),GREEDY_SEARCH_ALLOW_PORT_CLEANUP:V.GREEDY_SEARCH_ALLOW_PORT_CLEANUP??"0",...$===void 0?{}:{GREEDY_SEARCH_VISIBLE:$}}}function w(){return r(M,process.env)}function e(J){return p.test(J)}function J2(J){return J.split(/\r?\n/).map((V)=>V.trimEnd()).filter(Boolean).map((V)=>{let $=V.trim().split(/\s{2,}/).filter(Boolean);if($.length===0)return null;let Q=$[0];if($.length===1)return{target:Q,title:"",url:""};if($.length===2&&e($[1]))return{target:Q,title:"",url:$[1]};let Z=$.at(-1)??"",X=$.slice(1,-1).join(" ");return{target:Q,title:X,url:Z}}).filter(Boolean)}function V2(){let J=process.env.DM_CODING_AGENT_DIR||process.env.PI_CODING_AGENT_DIR;return J?L(J):k(g(),".dm","agent")}function $2(){let J=k(V2(),"cua","screenshots");h(J,{recursive:!0});let V=new Date().toISOString().replace(/[:.]/g,"-");return k(J,`browser-${V}.png`)}function F(J,V,{env:$=process.env,timeoutMs:Q=N}={}){return new Promise((Z,X)=>{let z=x("node",[J,...V],{env:$,stdio:["ignore","pipe","pipe"]}),A="",H="",j=!1,Y=setTimeout(()=>{if(j)return;j=!0,z.kill("SIGTERM"),X(Error(`Timed out running ${J}`))},Q);z.stdout.on("data",(q)=>{A+=q.toString()}),z.stderr.on("data",(q)=>{H+=q.toString()}),z.on("error",(q)=>{if(j)return;j=!0,clearTimeout(Y),X(q)}),z.on("close",(q)=>{if(j)return;if(j=!0,clearTimeout(Y),q!==0){X(Error((H||A||`exit ${q}`).trim()));return}Z({stdout:A,stderr:H})})})}function j2(J,V){return new Promise(($,Q)=>{let Z=P.request({host:"127.0.0.1",port:s,path:V,method:J},(X)=>{let z="";X.on("data",(A)=>{z+=A.toString()}),X.on("end",()=>{if((X.statusCode??500)>=400){Q(Error(`Browser CDP HTTP ${X.statusCode}: ${z.trim()}`));return}try{$(z?JSON.parse(z):{})}catch(A){Q(A)}})});Z.on("error",Q),Z.end()})}async function Q2(J="about:blank"){return j2("PUT",`/json/new?${encodeURIComponent(J)}`)}async function K(J,V={}){let{cdpScript:$}=C();return F($,J,{env:w(),timeoutMs:V.timeoutMs??N})}async function G(){let J=await K(["list"]);return J2(J.stdout)}function b(J,V){if(!V)return J[0]??null;let $=V.toUpperCase();return J.find((Q)=>Q.target.toUpperCase().startsWith($))??null}async function _(){let{launchScript:J,cdpScript:V}=C();if(!W(J)||!W(V))throw Error("Bundled browser helpers are missing. Rebuild DM so dm-cua and greedysearch-dm are staged together.");return{launchScript:J,cdpScript:V}}async function E(){t();let{launchScript:J}=await _();await F(J,[],{env:w(),timeoutMs:N});let V=await G();if(V.length===0)await Q2("about:blank"),V=await G();return V}async function U(J){let V=await E(),$=b(V,J);if(!$){if(J)throw Error(`No browser tab matching prefix "${J}". Run browser_cua(list) first.`);throw Error("No browser tab available after browser bootstrap.")}return{tab:$.target,page:$,pages:V}}async function O({action:J,tab:V,url:$,selector:Q,x:Z,y:X,text:z,expression:A,outputPath:H}={}){switch(J){case"list":{let j=await E();return{status:"ok",action:J,browser:D(),pages:j}}case"navigate":{if(!$)throw Error("url is required for action=navigate");let j=await U(V),Y=await K(["nav",j.tab,$],{timeoutMs:90000}),q=await G(),f=b(q,j.tab)??j.page;return{status:"ok",action:J,browser:D(),tab:j.tab,url:f?.url||$,title:f?.title||"",message:Y.stdout.trim(),pages:q}}case"snapshot":{let j=await U(V),Y=await K(["snap",j.tab]);return{status:"ok",action:J,browser:D(),tab:j.tab,title:j.page?.title||"",url:j.page?.url||"",snapshot:Y.stdout.trim()}}case"screenshot":{let j=await U(V),Y=H?L(H):$2();h(B(Y),{recursive:!0});let q=await K(["shot",j.tab,Y],{timeoutMs:120000}),f=S(Y).toString("base64");return{status:"ok",action:J,browser:D(),tab:j.tab,title:j.page?.title||"",url:j.page?.url||"",imagePath:Y,imageBase64:f,mimeType:"image/png",message:q.stdout.trim()}}case"click":{if(!Q)throw Error("selector is required for action=click");let j=await U(V),Y=await K(["click",j.tab,Q]);return{status:"ok",action:J,browser:D(),tab:j.tab,selector:Q,message:Y.stdout.trim()}}case"click_xy":{if(typeof Z!=="number"||Number.isNaN(Z)||typeof X!=="number"||Number.isNaN(X))throw Error("x and y are required numbers for action=click_xy");let j=await U(V),Y=await K(["clickxy",j.tab,String(Z),String(X)]);return{status:"ok",action:J,browser:D(),tab:j.tab,x:Z,y:X,message:Y.stdout.trim()}}case"type":{if(z==null||z==="")throw Error("text is required for action=type");let j=await U(V),Y=await K(["type",j.tab,z]);return{status:"ok",action:J,browser:D(),tab:j.tab,textLength:z.length,message:Y.stdout.trim()}}case"evaluate":{if(!A)throw Error("expression is required for action=evaluate");let j=await U(V),Y=await K(["eval",j.tab,A]);return{status:"ok",action:J,browser:D(),tab:j.tab,value:Y.stdout.trim()}}case"stop":{let{launchScript:j}=await _();try{await K(["stop"])}catch{}let Y=await F(j,["--kill"],{env:w(),timeoutMs:30000});return{status:"ok",action:J,browser:D(),message:(Y.stdout||"Stopped browser CUA lane.").trim()}}default:throw Error(`Unsupported browser action: ${J}`)}}function m(J){switch(J.action){case"list":{if(!Array.isArray(J.pages)||J.pages.length===0)return"Browser CUA is ready, but no pages are open.";return["Open browser tabs:",...J.pages.map((V)=>V.url?`${V.target} ${V.title||"(untitled)"} ${V.url}`:`${V.target} ${V.title||"(untitled)"}`)].join(`
|
|
3
|
+
`)}case"navigate":return[`Navigated browser tab ${J.tab} to ${J.url||"(unknown URL)"}`,J.title?`Title: ${J.title}`:""].filter(Boolean).join(`
|
|
4
|
+
`);case"snapshot":return[`Browser snapshot for ${J.tab}`,J.snapshot||"(empty snapshot)"].join(`
|
|
5
|
+
`);case"screenshot":return[`Saved browser screenshot for ${J.tab} at ${J.imagePath}`,J.title?`Title: ${J.title}`:"",J.url?`URL: ${J.url}`:""].filter(Boolean).join(`
|
|
6
|
+
`);case"click":return`Clicked selector ${JSON.stringify(J.selector)} on browser tab ${J.tab}`;case"click_xy":return`Clicked browser tab ${J.tab} at CSS coordinates (${J.x}, ${J.y})`;case"type":return`Typed ${J.textLength} characters into browser tab ${J.tab}`;case"evaluate":return`Browser evaluate result for ${J.tab}: ${J.value}`;case"stop":return J.message||"Stopped browser CUA lane.";default:return JSON.stringify(J,null,2)}}function X2(){console.log(`dm-cua browser helper
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
node browser-cua.mjs list [--json]
|
|
@@ -21,4 +21,4 @@ Usage:
|
|
|
21
21
|
- Fresh dedicated browser profiles auto-bootstrap a blank tab.
|
|
22
22
|
- Default browser is Chrome/Chromium. To try CloakBrowser, set DM_CUA_BROWSER=cloak
|
|
23
23
|
and point DM_CUA_BROWSER_PATH or CLOAKBROWSER_BINARY_PATH at its Chromium binary.
|
|
24
|
-
- screenshot defaults to ~/.dm/agent/cua/screenshots when --output is omitted.`)}function
|
|
24
|
+
- screenshot defaults to ~/.dm/agent/cua/screenshots when --output is omitted.`)}function Y2(J){let V={},$=[];for(let Q=0;Q<J.length;Q+=1){let Z=J[Q];if(!Z.startsWith("--")){$.push(Z);continue}let X=Z.indexOf("="),z=X>2,A=z?Z.slice(2,X):Z.slice(2);if(A==="json"||A==="help"){V[A]=!0;continue}if(z){V[A]=Z.slice(X+1);continue}let H=J[Q+1];if(typeof H>"u"||H.startsWith("--"))throw Error(`Missing value for --${A}`);V[A]=H,Q+=1}return{options:V,positionals:$}}async function Z2(){let{options:J,positionals:V}=Y2(process.argv.slice(2));if(J.help||V.length===0){X2();return}let $=V[0],Q=await O({action:$,tab:J.tab,url:J.url,selector:J.selector,x:J.x==null?void 0:Number(J.x),y:J.y==null?void 0:Number(J.y),text:J.text,expression:J.expression,outputPath:J.output});if(J.json){console.log(JSON.stringify(Q,null,2));return}console.log(m(Q))}try{await Z2()}catch(J){let V=J instanceof Error?J.message:String(J),$=!1;try{$=process.argv.slice(2).includes("--json")}catch{}if($)console.log(JSON.stringify({status:"error",message:V},null,2));else console.error(V);process.exit(1)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`)}case"navigate":return[`Navigated browser tab ${
|
|
3
|
-
`);case"snapshot":return[`Browser snapshot for ${
|
|
4
|
-
`);case"screenshot":return[`Saved browser screenshot for ${
|
|
5
|
-
`);case"click":return`Clicked selector ${JSON.stringify(
|
|
1
|
+
import{existsSync as R}from"node:fs";import{Type as Z}from"@sinclair/typebox";import{createHash as d}from"node:crypto";import{spawn as g}from"node:child_process";import{existsSync as G,mkdirSync as C,readFileSync as x}from"node:fs";import P from"node:http";import{homedir as i,platform as c,tmpdir as B}from"node:os";import{dirname as m,join as U,resolve as f}from"node:path";import{fileURLToPath as p}from"node:url";var F=m(p(import.meta.url)),K4=f(F,".."),v=9322,a=400,N=60000,l=/^(about:|https?:\/\/|file:|chrome-error:\/\/)/i,u={chrome:"Chrome",cloak:"CloakBrowser"};function h(L){let $=Number.parseInt(String(L??""),10);return Number.isInteger($)&&$>1024&&$<65535?$:null}function o(L){return d("sha256").update(String(L||"default")).digest("hex")}function n(L){let $=String(L||"chrome").trim().toLowerCase();if($==="cloakbrowser"||$==="cloak-browser")return"cloak";if($==="chromium"||$==="google-chrome"||$==="chrome")return"chrome";return $.replace(/[^a-z0-9_.-]/g,"-")||"chrome"}function s(L,$){let J=L.DM_CUA_BROWSER_PATH||($==="cloak"?L.DM_CUA_CLOAK_PATH||L.CLOAKBROWSER_BINARY_PATH:void 0)||L.CHROME_PATH;return J?f(String(J)):void 0}function t(L=process.env,$=process.cwd()){let J=L.DM_CUA_SCOPE||L.DM_CODING_AGENT_DIR||L.PI_CODING_AGENT_DIR||$,V=o(f(String(J||"."))),z=String(L.DM_CUA_INSTANCE_ID||V.slice(0,12)).replace(/[^a-zA-Z0-9_.-]/g,"-"),Y=n(L.DM_CUA_BROWSER||L.DM_BROWSER_CUA_BROWSER||L.DM_CUA_BROWSER_KIND),k=L.DM_CUA_BROWSER_DISPLAY_NAME||u[Y]||Y,M=s(L,Y),K=h(L.DM_CUA_PORT)??h(L.GREEDY_SEARCH_PORT)??v+Number.parseInt(V.slice(0,8),16)%a,Q=Y==="chrome"?"chrome":Y,X=f(L.DM_CUA_PROFILE_DIR||U(B(),`dm-cua-${Q}-profile-${z}`)),q=c()==="win32"?B():"/tmp";return{instanceId:z,browserKind:Y,browserDisplayName:k,browserExecutablePath:M,port:K,profileDir:X,pidFile:U(X,"chrome.pid"),modeFile:U(X,"chrome-mode"),pagesCache:U(X,"cdp-pages.json"),socketDir:U(q,`dm-cua-cdp-${z}`)}}var A=t(),r=A.port,f4=A.profileDir;function D(){return{kind:A.browserKind,displayName:A.browserDisplayName,executablePath:A.browserExecutablePath,profileDir:A.profileDir,port:A.port}}function e(){if(A.browserKind==="cloak"&&!A.browserExecutablePath)throw Error(["CloakBrowser selected for browser CUA, but no executable path was provided.","Install/pre-download CloakBrowser yourself, then set DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH.","DM does not bundle the compiled CloakBrowser binary because its upstream license allows use but not redistribution."].join(" "));if(A.browserExecutablePath&&!G(A.browserExecutablePath))throw Error(`${A.browserDisplayName} executable not found: ${A.browserExecutablePath}`)}function T(){let $=[f(F,"..","greedysearch-dm"),f(F,"..","..","greedysearch-dm")].map((J)=>({launchScript:U(J,"bin","launch.mjs"),cdpScript:U(J,"bin","cdp.mjs")}));for(let J of $)if(G(J.launchScript)&&G(J.cdpScript))return J;return $[0]}function L4(L=A,$=process.env){let J=$.GREEDY_SEARCH_VISIBLE??$.DM_CUA_VISIBLE??$.DM_BROWSER_CUA_VISIBLE;return{...$,...L.browserExecutablePath?{CHROME_PATH:L.browserExecutablePath}:{},CDP_PROFILE_DIR:L.profileDir.replace(/\\/g,"/"),CDP_PAGES_CACHE:L.pagesCache.replace(/\\/g,"/"),CDP_SOCKET_DIR:L.socketDir.replace(/\\/g,"/"),GREEDY_SEARCH_BROWSER_LABEL:L.browserDisplayName,GREEDY_SEARCH_PORT:String(L.port),GREEDY_SEARCH_PROFILE_DIR:L.profileDir.replace(/\\/g,"/"),GREEDY_SEARCH_PID_FILE:L.pidFile.replace(/\\/g,"/"),GREEDY_SEARCH_MODE_FILE:L.modeFile.replace(/\\/g,"/"),GREEDY_SEARCH_ALLOW_PORT_CLEANUP:$.GREEDY_SEARCH_ALLOW_PORT_CLEANUP??"0",...J===void 0?{}:{GREEDY_SEARCH_VISIBLE:J}}}function j(){return L4(A,process.env)}function $4(L){return l.test(L)}function J4(L){return L.split(/\r?\n/).map(($)=>$.trimEnd()).filter(Boolean).map(($)=>{let J=$.trim().split(/\s{2,}/).filter(Boolean);if(J.length===0)return null;let V=J[0];if(J.length===1)return{target:V,title:"",url:""};if(J.length===2&&$4(J[1]))return{target:V,title:"",url:J[1]};let z=J.at(-1)??"",Y=J.slice(1,-1).join(" ");return{target:V,title:Y,url:z}}).filter(Boolean)}function Q4(){let L=process.env.DM_CODING_AGENT_DIR||process.env.PI_CODING_AGENT_DIR;return L?f(L):U(i(),".dm","agent")}function V4(){let L=U(Q4(),"cua","screenshots");C(L,{recursive:!0});let $=new Date().toISOString().replace(/[:.]/g,"-");return U(L,`browser-${$}.png`)}function w(L,$,{env:J=process.env,timeoutMs:V=N}={}){return new Promise((z,Y)=>{let k=g("node",[L,...$],{env:J,stdio:["ignore","pipe","pipe"]}),M="",K="",Q=!1,X=setTimeout(()=>{if(Q)return;Q=!0,k.kill("SIGTERM"),Y(Error(`Timed out running ${L}`))},V);k.stdout.on("data",(q)=>{M+=q.toString()}),k.stderr.on("data",(q)=>{K+=q.toString()}),k.on("error",(q)=>{if(Q)return;Q=!0,clearTimeout(X),Y(q)}),k.on("close",(q)=>{if(Q)return;if(Q=!0,clearTimeout(X),q!==0){Y(Error((K||M||`exit ${q}`).trim()));return}z({stdout:M,stderr:K})})})}function X4(L,$){return new Promise((J,V)=>{let z=P.request({host:"127.0.0.1",port:r,path:$,method:L},(Y)=>{let k="";Y.on("data",(M)=>{k+=M.toString()}),Y.on("end",()=>{if((Y.statusCode??500)>=400){V(Error(`Browser CDP HTTP ${Y.statusCode}: ${k.trim()}`));return}try{J(k?JSON.parse(k):{})}catch(M){V(M)}})});z.on("error",V),z.end()})}async function Z4(L="about:blank"){return X4("PUT",`/json/new?${encodeURIComponent(L)}`)}async function H(L,$={}){let{cdpScript:J}=T();return w(J,L,{env:j(),timeoutMs:$.timeoutMs??N})}async function I(){let L=await H(["list"]);return J4(L.stdout)}function _(L,$){if(!$)return L[0]??null;let J=$.toUpperCase();return L.find((V)=>V.target.toUpperCase().startsWith(J))??null}async function O(){let{launchScript:L,cdpScript:$}=T();if(!G(L)||!G($))throw Error("Bundled browser helpers are missing. Rebuild DM so dm-cua and greedysearch-dm are staged together.");return{launchScript:L,cdpScript:$}}async function b(){e();let{launchScript:L}=await O();await w(L,[],{env:j(),timeoutMs:N});let $=await I();if($.length===0)await Z4("about:blank"),$=await I();return $}async function y(L){let $=await b(),J=_($,L);if(!J){if(L)throw Error(`No browser tab matching prefix "${L}". Run browser_cua(list) first.`);throw Error("No browser tab available after browser bootstrap.")}return{tab:J.target,page:J,pages:$}}async function S({action:L,tab:$,url:J,selector:V,x:z,y:Y,text:k,expression:M,outputPath:K}={}){switch(L){case"list":{let Q=await b();return{status:"ok",action:L,browser:D(),pages:Q}}case"navigate":{if(!J)throw Error("url is required for action=navigate");let Q=await y($),X=await H(["nav",Q.tab,J],{timeoutMs:90000}),q=await I(),W=_(q,Q.tab)??Q.page;return{status:"ok",action:L,browser:D(),tab:Q.tab,url:W?.url||J,title:W?.title||"",message:X.stdout.trim(),pages:q}}case"snapshot":{let Q=await y($),X=await H(["snap",Q.tab]);return{status:"ok",action:L,browser:D(),tab:Q.tab,title:Q.page?.title||"",url:Q.page?.url||"",snapshot:X.stdout.trim()}}case"screenshot":{let Q=await y($),X=K?f(K):V4();C(m(X),{recursive:!0});let q=await H(["shot",Q.tab,X],{timeoutMs:120000}),W=x(X).toString("base64");return{status:"ok",action:L,browser:D(),tab:Q.tab,title:Q.page?.title||"",url:Q.page?.url||"",imagePath:X,imageBase64:W,mimeType:"image/png",message:q.stdout.trim()}}case"click":{if(!V)throw Error("selector is required for action=click");let Q=await y($),X=await H(["click",Q.tab,V]);return{status:"ok",action:L,browser:D(),tab:Q.tab,selector:V,message:X.stdout.trim()}}case"click_xy":{if(typeof z!=="number"||Number.isNaN(z)||typeof Y!=="number"||Number.isNaN(Y))throw Error("x and y are required numbers for action=click_xy");let Q=await y($),X=await H(["clickxy",Q.tab,String(z),String(Y)]);return{status:"ok",action:L,browser:D(),tab:Q.tab,x:z,y:Y,message:X.stdout.trim()}}case"type":{if(k==null||k==="")throw Error("text is required for action=type");let Q=await y($),X=await H(["type",Q.tab,k]);return{status:"ok",action:L,browser:D(),tab:Q.tab,textLength:k.length,message:X.stdout.trim()}}case"evaluate":{if(!M)throw Error("expression is required for action=evaluate");let Q=await y($),X=await H(["eval",Q.tab,M]);return{status:"ok",action:L,browser:D(),tab:Q.tab,value:X.stdout.trim()}}case"stop":{let{launchScript:Q}=await O();try{await H(["stop"])}catch{}let X=await w(Q,["--kill"],{env:j(),timeoutMs:30000});return{status:"ok",action:L,browser:D(),message:(X.stdout||"Stopped browser CUA lane.").trim()}}default:throw Error(`Unsupported browser action: ${L}`)}}function E(L){switch(L.action){case"list":{if(!Array.isArray(L.pages)||L.pages.length===0)return"Browser CUA is ready, but no pages are open.";return["Open browser tabs:",...L.pages.map(($)=>$.url?`${$.target} ${$.title||"(untitled)"} ${$.url}`:`${$.target} ${$.title||"(untitled)"}`)].join(`
|
|
2
|
+
`)}case"navigate":return[`Navigated browser tab ${L.tab} to ${L.url||"(unknown URL)"}`,L.title?`Title: ${L.title}`:""].filter(Boolean).join(`
|
|
3
|
+
`);case"snapshot":return[`Browser snapshot for ${L.tab}`,L.snapshot||"(empty snapshot)"].join(`
|
|
4
|
+
`);case"screenshot":return[`Saved browser screenshot for ${L.tab} at ${L.imagePath}`,L.title?`Title: ${L.title}`:"",L.url?`URL: ${L.url}`:""].filter(Boolean).join(`
|
|
5
|
+
`);case"click":return`Clicked selector ${JSON.stringify(L.selector)} on browser tab ${L.tab}`;case"click_xy":return`Clicked browser tab ${L.tab} at CSS coordinates (${L.x}, ${L.y})`;case"type":return`Typed ${L.textLength} characters into browser tab ${L.tab}`;case"evaluate":return`Browser evaluate result for ${L.tab}: ${L.value}`;case"stop":return L.message||"Stopped browser CUA lane.";default:return JSON.stringify(L,null,2)}}var z4=Z.Object({action:Z.Union([Z.Literal("list"),Z.Literal("navigate"),Z.Literal("snapshot"),Z.Literal("screenshot"),Z.Literal("click"),Z.Literal("click_xy"),Z.Literal("type"),Z.Literal("evaluate"),Z.Literal("stop")],{description:"Browser action. Start with list, snapshot, or screenshot before mutating actions on unfamiliar pages."}),tab:Z.Optional(Z.String({description:"Optional target tab prefix from browser_cua(list). If omitted, the first live page in the dedicated profile is used."})),url:Z.Optional(Z.String({description:"URL for action=navigate."})),selector:Z.Optional(Z.String({description:"CSS selector for action=click."})),x:Z.Optional(Z.Number({description:"CSS x coordinate for action=click_xy."})),y:Z.Optional(Z.Number({description:"CSS y coordinate for action=click_xy."})),text:Z.Optional(Z.String({description:"Text for action=type."})),expression:Z.Optional(Z.String({description:"JavaScript expression for action=evaluate."}))},{additionalProperties:!1});function Y4(L){L.on("session_start",async($,J)=>{let{launchScript:V,cdpScript:z}=T();if(!R(V)||!R(z))J.ui.notify("dm-cua: bundled browser helpers are missing. Rebuild DM so dm-cua and greedysearch-dm are staged together.","warning")}),L.registerTool({name:"browser_cua",label:"Browser CUA",description:"Drive a dedicated Chrome browser profile through DM's bundled browser CUA lane. Inspect first with list, snapshot, or screenshot. Fresh empty profiles auto-bootstrap a blank tab. Use navigate for deterministic URLs, click/click_xy/type for page interaction, evaluate for focused DOM reads, and stop to close the dedicated browser lane.",promptSnippet:"First-class browser CUA for Chrome. Inspect before acting. Screenshot complex pages before click/scroll loops.",parameters:z4,async execute($,J){try{let V=await S(J),z=[{type:"text",text:E(V)}];if(V.imageBase64&&V.mimeType)z.push({type:"image",data:V.imageBase64,mimeType:V.mimeType});return{content:z,details:V}}catch(V){let z=V instanceof Error?V.message:String(V);return{content:[{type:"text",text:`browser_cua failed: ${z}`}],details:{status:"error",action:J?.action??null,message:z}}}}})}export{Y4 as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
import{createHash as h}from"node:crypto";import{spawn as P}from"node:child_process";import{existsSync as W,mkdirSync as E,readFileSync as S}from"node:fs";import b from"node:http";import{homedir as m,platform as x,tmpdir as y}from"node:os";import{dirname as _,join as M,resolve as U}from"node:path";import{fileURLToPath as g}from"node:url";var j=_(g(import.meta.url)),KQ=U(j,".."),v=9322,d=400,I=60000,p=/^(about:|https?:\/\/|file:|chrome-error:\/\/)/i,u={chrome:"Chrome",cloak:"CloakBrowser"};function C(Q){let V=Number.parseInt(String(Q??""),10);return Number.isInteger(V)&&V>1024&&V<65535?V:null}function c(Q){return h("sha256").update(String(Q||"default")).digest("hex")}function l(Q){let V=String(Q||"chrome").trim().toLowerCase();if(V==="cloakbrowser"||V==="cloak-browser")return"cloak";if(V==="chromium"||V==="google-chrome"||V==="chrome")return"chrome";return V.replace(/[^a-z0-9_.-]/g,"-")||"chrome"}function i(Q,V){let X=Q.DM_CUA_BROWSER_PATH||(V==="cloak"?Q.DM_CUA_CLOAK_PATH||Q.CLOAKBROWSER_BINARY_PATH:void 0)||Q.CHROME_PATH;return X?U(String(X)):void 0}function a(Q=process.env,V=process.cwd()){let X=Q.DM_CUA_SCOPE||Q.DM_CODING_AGENT_DIR||Q.PI_CODING_AGENT_DIR||V,J=c(U(String(X||"."))),q=String(Q.DM_CUA_INSTANCE_ID||J.slice(0,12)).replace(/[^a-zA-Z0-9_.-]/g,"-"),z=l(Q.DM_CUA_BROWSER||Q.DM_BROWSER_CUA_BROWSER||Q.DM_CUA_BROWSER_KIND),Y=Q.DM_CUA_BROWSER_DISPLAY_NAME||u[z]||z,L=i(Q,z),k=C(Q.DM_CUA_PORT)??C(Q.GREEDY_SEARCH_PORT)??v+Number.parseInt(J.slice(0,8),16)%d,Z=z==="chrome"?"chrome":z,$=U(Q.DM_CUA_PROFILE_DIR||M(y(),`dm-cua-${Z}-profile-${q}`)),H=x()==="win32"?y():"/tmp";return{instanceId:q,browserKind:z,browserDisplayName:Y,browserExecutablePath:L,port:k,profileDir:$,pidFile:M($,"chrome.pid"),modeFile:M($,"chrome-mode"),pagesCache:M($,"cdp-pages.json"),socketDir:M(H,`dm-cua-cdp-${q}`)}}var K=a(),n=K.port,LQ=K.profileDir;function A(){return{kind:K.browserKind,displayName:K.browserDisplayName,executablePath:K.browserExecutablePath,profileDir:K.profileDir,port:K.port}}function o(){if(K.browserKind==="cloak"&&!K.browserExecutablePath)throw Error(["CloakBrowser selected for browser CUA, but no executable path was provided.","Install/pre-download CloakBrowser yourself, then set DM_CUA_BROWSER_PATH, DM_CUA_CLOAK_PATH, CLOAKBROWSER_BINARY_PATH, or CHROME_PATH.","DM does not bundle the compiled CloakBrowser binary because its upstream license allows use but not redistribution."].join(" "));if(K.browserExecutablePath&&!W(K.browserExecutablePath))throw Error(`${K.browserDisplayName} executable not found: ${K.browserExecutablePath}`)}function O(){let V=[U(j,"..","greedysearch-dm"),U(j,"..","..","greedysearch-dm")].map((X)=>({launchScript:M(X,"bin","launch.mjs"),cdpScript:M(X,"bin","cdp.mjs")}));for(let X of V)if(W(X.launchScript)&&W(X.cdpScript))return X;return V[0]}function s(Q=K,V=process.env){let X=V.GREEDY_SEARCH_VISIBLE??V.DM_CUA_VISIBLE??V.DM_BROWSER_CUA_VISIBLE;return{...V,...Q.browserExecutablePath?{CHROME_PATH:Q.browserExecutablePath}:{},CDP_PROFILE_DIR:Q.profileDir.replace(/\\/g,"/"),CDP_PAGES_CACHE:Q.pagesCache.replace(/\\/g,"/"),CDP_SOCKET_DIR:Q.socketDir.replace(/\\/g,"/"),GREEDY_SEARCH_BROWSER_LABEL:Q.browserDisplayName,GREEDY_SEARCH_PORT:String(Q.port),GREEDY_SEARCH_PROFILE_DIR:Q.profileDir.replace(/\\/g,"/"),GREEDY_SEARCH_PID_FILE:Q.pidFile.replace(/\\/g,"/"),GREEDY_SEARCH_MODE_FILE:Q.modeFile.replace(/\\/g,"/"),GREEDY_SEARCH_ALLOW_PORT_CLEANUP:V.GREEDY_SEARCH_ALLOW_PORT_CLEANUP??"0",...X===void 0?{}:{GREEDY_SEARCH_VISIBLE:X}}}function T(){return s(K,process.env)}function t(Q){return p.test(Q)}function r(Q){return Q.split(/\r?\n/).map((V)=>V.trimEnd()).filter(Boolean).map((V)=>{let X=V.trim().split(/\s{2,}/).filter(Boolean);if(X.length===0)return null;let J=X[0];if(X.length===1)return{target:J,title:"",url:""};if(X.length===2&&t(X[1]))return{target:J,title:"",url:X[1]};let q=X.at(-1)??"",z=X.slice(1,-1).join(" ");return{target:J,title:z,url:q}}).filter(Boolean)}function e(){let Q=process.env.DM_CODING_AGENT_DIR||process.env.PI_CODING_AGENT_DIR;return Q?U(Q):M(m(),".dm","agent")}function QQ(){let Q=M(e(),"cua","screenshots");E(Q,{recursive:!0});let V=new Date().toISOString().replace(/[:.]/g,"-");return M(Q,`browser-${V}.png`)}function B(Q,V,{env:X=process.env,timeoutMs:J=I}={}){return new Promise((q,z)=>{let Y=P("node",[Q,...V],{env:X,stdio:["ignore","pipe","pipe"]}),L="",k="",Z=!1,$=setTimeout(()=>{if(Z)return;Z=!0,Y.kill("SIGTERM"),z(Error(`Timed out running ${Q}`))},J);Y.stdout.on("data",(H)=>{L+=H.toString()}),Y.stderr.on("data",(H)=>{k+=H.toString()}),Y.on("error",(H)=>{if(Z)return;Z=!0,clearTimeout($),z(H)}),Y.on("close",(H)=>{if(Z)return;if(Z=!0,clearTimeout($),H!==0){z(Error((k||L||`exit ${H}`).trim()));return}q({stdout:L,stderr:k})})})}function VQ(Q,V){return new Promise((X,J)=>{let q=b.request({host:"127.0.0.1",port:n,path:V,method:Q},(z)=>{let Y="";z.on("data",(L)=>{Y+=L.toString()}),z.on("end",()=>{if((z.statusCode??500)>=400){J(Error(`Browser CDP HTTP ${z.statusCode}: ${Y.trim()}`));return}try{X(Y?JSON.parse(Y):{})}catch(L){J(L)}})});q.on("error",J),q.end()})}async function XQ(Q="about:blank"){return VQ("PUT",`/json/new?${encodeURIComponent(Q)}`)}async function D(Q,V={}){let{cdpScript:X}=O();return B(X,Q,{env:T(),timeoutMs:V.timeoutMs??I})}async function N(){let Q=await D(["list"]);return r(Q.stdout)}function w(Q,V){if(!V)return Q[0]??null;let X=V.toUpperCase();return Q.find((J)=>J.target.toUpperCase().startsWith(X))??null}async function R(){let{launchScript:Q,cdpScript:V}=O();if(!W(Q)||!W(V))throw Error("Bundled browser helpers are missing. Rebuild DM so dm-cua and greedysearch-dm are staged together.");return{launchScript:Q,cdpScript:V}}async function f(){o();let{launchScript:Q}=await R();await B(Q,[],{env:T(),timeoutMs:I});let V=await N();if(V.length===0)await XQ("about:blank"),V=await N();return V}async function G(Q){let V=await f(),X=w(V,Q);if(!X){if(Q)throw Error(`No browser tab matching prefix "${Q}". Run browser_cua(list) first.`);throw Error("No browser tab available after browser bootstrap.")}return{tab:X.target,page:X,pages:V}}async function MQ({action:Q,tab:V,url:X,selector:J,x:q,y:z,text:Y,expression:L,outputPath:k}={}){switch(Q){case"list":{let Z=await f();return{status:"ok",action:Q,browser:A(),pages:Z}}case"navigate":{if(!X)throw Error("url is required for action=navigate");let Z=await G(V),$=await D(["nav",Z.tab,X],{timeoutMs:90000}),H=await N(),F=w(H,Z.tab)??Z.page;return{status:"ok",action:Q,browser:A(),tab:Z.tab,url:F?.url||X,title:F?.title||"",message:$.stdout.trim(),pages:H}}case"snapshot":{let Z=await G(V),$=await D(["snap",Z.tab]);return{status:"ok",action:Q,browser:A(),tab:Z.tab,title:Z.page?.title||"",url:Z.page?.url||"",snapshot:$.stdout.trim()}}case"screenshot":{let Z=await G(V),$=k?U(k):QQ();E(_($),{recursive:!0});let H=await D(["shot",Z.tab,$],{timeoutMs:120000}),F=S($).toString("base64");return{status:"ok",action:Q,browser:A(),tab:Z.tab,title:Z.page?.title||"",url:Z.page?.url||"",imagePath:$,imageBase64:F,mimeType:"image/png",message:H.stdout.trim()}}case"click":{if(!J)throw Error("selector is required for action=click");let Z=await G(V),$=await D(["click",Z.tab,J]);return{status:"ok",action:Q,browser:A(),tab:Z.tab,selector:J,message:$.stdout.trim()}}case"click_xy":{if(typeof q!=="number"||Number.isNaN(q)||typeof z!=="number"||Number.isNaN(z))throw Error("x and y are required numbers for action=click_xy");let Z=await G(V),$=await D(["clickxy",Z.tab,String(q),String(z)]);return{status:"ok",action:Q,browser:A(),tab:Z.tab,x:q,y:z,message:$.stdout.trim()}}case"type":{if(Y==null||Y==="")throw Error("text is required for action=type");let Z=await G(V),$=await D(["type",Z.tab,Y]);return{status:"ok",action:Q,browser:A(),tab:Z.tab,textLength:Y.length,message:$.stdout.trim()}}case"evaluate":{if(!L)throw Error("expression is required for action=evaluate");let Z=await G(V),$=await D(["eval",Z.tab,L]);return{status:"ok",action:Q,browser:A(),tab:Z.tab,value:$.stdout.trim()}}case"stop":{let{launchScript:Z}=await R();try{await D(["stop"])}catch{}let $=await B(Z,["--kill"],{env:T(),timeoutMs:30000});return{status:"ok",action:Q,browser:A(),message:($.stdout||"Stopped browser CUA lane.").trim()}}default:throw Error(`Unsupported browser action: ${Q}`)}}function AQ(Q){switch(Q.action){case"list":{if(!Array.isArray(Q.pages)||Q.pages.length===0)return"Browser CUA is ready, but no pages are open.";return["Open browser tabs:",...Q.pages.map((V)=>V.url?`${V.target} ${V.title||"(untitled)"} ${V.url}`:`${V.target} ${V.title||"(untitled)"}`)].join(`
|
|
2
2
|
`)}case"navigate":return[`Navigated browser tab ${Q.tab} to ${Q.url||"(unknown URL)"}`,Q.title?`Title: ${Q.title}`:""].filter(Boolean).join(`
|
|
3
3
|
`);case"snapshot":return[`Browser snapshot for ${Q.tab}`,Q.snapshot||"(empty snapshot)"].join(`
|
|
4
4
|
`);case"screenshot":return[`Saved browser screenshot for ${Q.tab} at ${Q.imagePath}`,Q.title?`Title: ${Q.title}`:"",Q.url?`URL: ${Q.url}`:""].filter(Boolean).join(`
|
|
5
|
-
`);case"click":return`Clicked selector ${JSON.stringify(Q.selector)} on browser tab ${Q.tab}`;case"click_xy":return`Clicked browser tab ${Q.tab} at CSS coordinates (${Q.x}, ${Q.y})`;case"type":return`Typed ${Q.textLength} characters into browser tab ${Q.tab}`;case"evaluate":return`Browser evaluate result for ${Q.tab}: ${Q.value}`;case"stop":return Q.message||"Stopped browser CUA lane.";default:return JSON.stringify(Q,null,2)}}export{
|
|
5
|
+
`);case"click":return`Clicked selector ${JSON.stringify(Q.selector)} on browser tab ${Q.tab}`;case"click_xy":return`Clicked browser tab ${Q.tab} at CSS coordinates (${Q.x}, ${Q.y})`;case"type":return`Typed ${Q.textLength} characters into browser tab ${Q.tab}`;case"evaluate":return`Browser evaluate result for ${Q.tab}: ${Q.value}`;case"stop":return Q.message||"Stopped browser CUA lane.";default:return JSON.stringify(Q,null,2)}}export{MQ as runBrowserAction,a as resolveBrowserRuntimeConfig,s as resolveBrowserProcessEnv,O as resolveBrowserHelperPaths,AQ as renderBrowserActionText,r as parseListOutput,f as ensureBrowserReady,LQ as BROWSER_PROFILE_DIR};
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as N}from"node:child_process";import{basename as g}from"node:path";function j(J=process.env,K=process.execPath){let q=J.GREEDY_SEARCH_NODE||J.NODE_BINARY||J.NODE;if(q?.trim())return q.trim();let $=g(K||"").toLowerCase();if($==="node"||$==="node.exe")return K;return"node"}import{existsSync as B,mkdirSync as C,readFileSync as A,writeFileSync as f}from"node:fs";import{homedir as h}from"node:os";import{join as u}from"node:path";import{tmpdir as p}from"node:os";function T(J,K=9222){let q=Number.parseInt(String(J??""),10);return Number.isInteger(q)&&q>1024&&q<65535?q:K}var m=p().replaceAll("\\","/"),i=T(process.env.GREEDY_SEARCH_PORT),Q=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${m}/greedysearch-chrome-profile`).replaceAll("\\","/"),v=`${Q}/DevToolsActivePort`,r=process.env.GREEDY_SEARCH_PID_FILE||`${Q}/browser.pid`,s=process.env.CDP_PAGES_CACHE||`${Q}/cdp-pages.json`,x=process.env.GREEDY_SEARCH_MODE_FILE||`${Q}/browser-mode`,n=process.env.GREEDY_SEARCH_METADATA_FILE||`${Q}/browser-metadata.json`,o=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${Q}/browser-launch.lock`,I=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${Q}/browser-last-activity`,d=(process.env.CDP_SOCKET_DIR||`${Q}/cdp-sockets`).replaceAll("\\","/"),E=`${Q}/visible-recovery.jsonl`,w=u(h(),".dm"),W=u(w,"greedyconfig"),Z=["perplexity","google","chatgpt","gemini"],b="gemini";function P(){try{if(B(W)){let J=A(W,"utf8"),K=JSON.parse(J);if(Array.isArray(K.engines)&&K.engines.length>0&&K.engines.every((q)=>typeof q==="string")){let q=K.engines.filter((z)=>V[z]),$=K.engines.filter((z)=>!V[z]);if($.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${W}: ${$.join(", ")}
|
|
3
|
+
[greedysearch] Available engines: ${Object.keys(V).join(", ")}
|
|
4
|
+
`);if(q.length>0)return q;process.stderr.write(`[greedysearch] Warning: no valid engines in ${W}, falling back to defaults: ${Z.join(", ")}
|
|
5
|
+
`)}}}catch{}return Z}function l(){try{if(!B(w))C(w,{recursive:!0});if(!B(W))f(W,JSON.stringify({engines:Z,synthesizer:b},null,2)+`
|
|
6
|
+
`,"utf8")}catch{}}l();var U=["gemini","chatgpt"];function L(){try{if(B(W)){let J=A(W,"utf8"),K=JSON.parse(J);if(typeof K.synthesizer==="string"){let q=K.synthesizer.toLowerCase();if(U.includes(q))return q;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${K.synthesizer}" in ${W}
|
|
7
|
+
[greedysearch] Available synthesizers: ${U.join(", ")}
|
|
8
|
+
[greedysearch] Falling back to default: ${b}
|
|
9
|
+
`)}}}catch{}return b}var V={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},e=P();var qq=L(),Jq=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=Q;import{existsSync as Y,readFileSync as O}from"node:fs";var G=Q,M=v,y=x,k=process.argv.slice(2),X=null,H=k.indexOf("--mode");if(H!==-1)X=k[H+1]||null,k.splice(H,2);if(X&&!["visible","headless"].includes(X))console.error(`Invalid --mode ${X}. Use visible or headless.`),process.exit(2);if(!Y(M))console.error(`GreedySearch Chrome is not running (missing ${M}). Launch with bin/visible.mjs or bin/launch.mjs.`),process.exit(1);if(X){let J=Y(y)?O(y,"utf8").trim():"unknown";if(J!==X)console.error(`GreedySearch Chrome is ${J}, not ${X}. Refusing to attach.`),process.exit(1)}var t=new URL("./cdp.mjs",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1"),S=N(j(),[t,...k],{stdio:"inherit",env:{...process.env,CDP_PROFILE_DIR:G}});S.on("close",(J)=>process.exit(J??0));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as I}from"node:child_process";import{basename as H}from"node:path";function F(k=process.env,q=process.execPath){let z=k.GREEDY_SEARCH_NODE||k.NODE_BINARY||k.NODE;if(z?.trim())return z.trim();let E=H(q||"").toLowerCase();if(E==="node"||E==="node.exe")return q;return"node"}var J=new URL("./cdp-greedy.mjs",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1"),K=I(F(),[J,"--mode","headless",...process.argv.slice(2)],{stdio:"inherit"});K.on("close",(k)=>process.exit(k??0));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as I}from"node:child_process";import{basename as H}from"node:path";function F(k=process.env,q=process.execPath){let z=k.GREEDY_SEARCH_NODE||k.NODE_BINARY||k.NODE;if(z?.trim())return z.trim();let E=H(q||"").toLowerCase();if(E==="node"||E==="node.exe")return q;return"node"}var J=new URL("./cdp-greedy.mjs",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1"),K=I(F(),[J,"--mode","visible",...process.argv.slice(2)],{stdio:"inherit"});K.on("close",(k)=>process.exit(k??0));
|