@duckmind/dm-windows-x64 0.60.6 → 0.60.9
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.exe +0 -0
- package/extensions/.dm-extensions.json +70 -123
- package/extensions/dm-9router-ext/src/index.js +410 -5
- package/extensions/dm-caveman/extensions/caveman.js +283 -12
- package/extensions/dm-cliproxy/index.js +182 -2
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
- package/extensions/dm-cliproxy/src/apply.js +228 -1
- package/extensions/dm-cliproxy/src/cache.js +42 -1
- package/extensions/dm-cliproxy/src/commands.js +50 -2
- package/extensions/dm-cliproxy/src/compat.js +81 -1
- package/extensions/dm-cliproxy/src/config.js +192 -2
- package/extensions/dm-cliproxy/src/conflicts.js +46 -1
- package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
- package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
- package/extensions/dm-cliproxy/src/log.js +23 -1
- package/extensions/dm-cliproxy/src/status-quota.js +77 -1
- package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
- package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
- package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
- package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
- package/extensions/dm-context/src/context.js +144 -1
- package/extensions/dm-context/src/index.js +339 -7
- package/extensions/dm-context/src/utils.js +9 -1
- package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
- package/extensions/dm-cua/index.js +75 -6
- package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
- package/extensions/dm-cua/src/browser-install.mjs +331 -2
- package/extensions/dm-fff/src/index.js +688 -12
- package/extensions/dm-fff/src/query.js +60 -1
- package/extensions/dm-goal/src/goal.js +894 -23
- package/extensions/dm-image2/index.js +103 -9
- package/extensions/dm-image2/src/image-lib.mjs +1275 -8
- package/extensions/dm-subagents/install.mjs +62 -8
- package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
- package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
- package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
- package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
- package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
- package/extensions/dm-subagents/src/agents/agents.js +1139 -11
- package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
- package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
- package/extensions/dm-subagents/src/agents/identity.js +29 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
- package/extensions/dm-subagents/src/agents/skills.js +614 -6
- package/extensions/dm-subagents/src/extension/config.js +35 -2
- package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
- package/extensions/dm-subagents/src/extension/doctor.js +172 -15
- package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
- package/extensions/dm-subagents/src/extension/index.js +521 -359
- package/extensions/dm-subagents/src/extension/rpc.js +266 -7
- package/extensions/dm-subagents/src/extension/schemas.js +275 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
- package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
- package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
- package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
- package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
- package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
- package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
- package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
- package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
- package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
- package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
- package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
- package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
- package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
- package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
- package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
- package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
- package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
- package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
- package/extensions/dm-subagents/src/shared/formatters.js +98 -7
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
- package/extensions/dm-subagents/src/shared/model-info.js +62 -1
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
- package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
- package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
- package/extensions/dm-subagents/src/shared/settings.js +198 -11
- package/extensions/dm-subagents/src/shared/status-format.js +53 -1
- package/extensions/dm-subagents/src/shared/types.js +184 -6
- package/extensions/dm-subagents/src/shared/utils.js +462 -2
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
- package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
- package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
- package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
- package/extensions/dm-subagents/src/tui/render.js +1542 -4
- package/extensions/dm-usage/index.js +1294 -9
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
- package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
- package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
- package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
- package/extensions/greedysearch-dm/bin/search.mjs +620 -540
- package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
- package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
- package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
- package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
- package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
- package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
- package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
- package/extensions/greedysearch-dm/index.js +123 -23
- package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
- package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
- package/extensions/greedysearch-dm/src/github.mjs +222 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
- package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
- package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
- package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
- package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
- package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
- package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
- package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
- package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
- package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
- package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
- package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
- package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
- package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
- package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
- package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
- package/package.json +1 -1
|
@@ -1,375 +1,400 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`+G0(K.data,Q+1)}return W}var q1;var A0=U(()=>{q1={"user-agent":"GreedySearch/1.0 (Research Bot)",accept:"application/json"}});function b($,Q=8000){if(!$||$.length<=Q)return $;let X=`
|
|
39
|
-
|
|
40
|
-
[...content trimmed...]
|
|
41
|
-
|
|
42
|
-
`,W=Q-X.length,Z=Math.floor(W*0.75),K=W-Z,J=Z;while(J>Z-100&&$[J]!==`
|
|
43
|
-
`)J--;if(J<=Z-100)J=Z;let q=$.length-K;while(q<$.length-K+100&&$[q]!==`
|
|
44
|
-
`)q++;if(q>=$.length-K+100)q=$.length-K;let V=$.slice(0,J).trimEnd(),B=$.slice(q).trimStart();return`${V}${X}${B}`}import{spawn as B1}from"node:child_process";import{dirname as j1,join as H1}from"node:path";import{fileURLToPath as Y1}from"node:url";function A1($){if(!Array.isArray($)||$.length===0)throw Error("cdp: args must be a non-empty array");if($[0]==="test")return $.map((Q,X)=>M0(Q,X));if(!G1.has($[0]))throw Error(`cdp: unknown subcommand '${$[0]}'`);return $.map((Q,X)=>M0(Q,X))}function M0($,Q){if(typeof $!=="string")throw Error(`cdp: argv[${Q}] must be a string (got ${typeof $})`);if($.includes("\x00"))throw Error(`cdp: argv[${Q}] contains a null byte`);return $}function c($,Q=30000){return M1($,null,Q)}function M1($,Q=null,X=30000){let W=A1($);return new Promise((Z,K)=>{let J=B1(F(),[z1,...W],{stdio:[Q==null?"ignore":"pipe","pipe","pipe"]});if(Q!=null)J.stdin.write(Q),J.stdin.end();let q="",V="";J.stdout.on("data",(j)=>q+=j),J.stderr.on("data",(j)=>V+=j);let B=setTimeout(()=>{J.kill(),K(Error(`cdp timeout: ${$[0]}`))},X);J.on("close",(j)=>{if(clearTimeout(B),j===0)Z(q.trim());else K(Error(V.trim()||`cdp exit ${j}`))})})}async function i($){await c(["evalraw",$,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
|
|
45
|
-
(function() {
|
|
46
|
-
// ── Runtime.enable / CDP detection masking ──────────────
|
|
47
|
-
try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
|
|
48
|
-
try { delete window.__REBROWSER_DEVTOOLS; } catch(_) {}
|
|
49
|
-
try { delete window.__nightmare; } catch(_) {}
|
|
50
|
-
try { delete window.__phantom; } catch(_) {}
|
|
51
|
-
try { delete window.callPhantom; } catch(_) {}
|
|
52
|
-
try { delete window._phantom; } catch(_) {}
|
|
53
|
-
try { delete window.Buffer; } catch(_) {}
|
|
54
|
-
|
|
55
|
-
// Real Chrome without automation should not expose navigator.webdriver at all.
|
|
56
|
-
// A literal false or an own-property getter returning undefined is itself a
|
|
57
|
-
// common stealth tell; remove both instance and prototype properties when the
|
|
58
|
-
// descriptor is configurable (as it is with --disable-blink-features).
|
|
59
|
-
try { delete navigator.webdriver; } catch(_) {}
|
|
60
|
-
try { delete Navigator.prototype.webdriver; } catch(_) {}
|
|
61
|
-
Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
|
|
62
|
-
Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
|
|
63
|
-
Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
|
|
64
|
-
Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
|
|
65
|
-
Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
|
|
66
|
-
Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
|
|
67
|
-
var __greedyMimeTypes = null;
|
|
68
|
-
function __makeMimeTypes() {
|
|
69
|
-
var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
|
|
70
|
-
var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
|
|
71
|
-
try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
|
|
72
|
-
try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
|
|
73
|
-
var m = [pdf, textPdf];
|
|
74
|
-
try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
|
|
75
|
-
m.item = function item(i) { return this[i] || null; };
|
|
76
|
-
m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
|
|
77
|
-
return m;
|
|
78
|
-
}
|
|
79
|
-
Object.defineProperty(navigator, 'plugins', {
|
|
80
|
-
get: () => {
|
|
81
|
-
__greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
|
|
82
|
-
var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
|
|
83
|
-
var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
|
|
84
|
-
var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
|
|
85
|
-
try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
|
|
86
|
-
try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
|
|
87
|
-
try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
|
|
88
|
-
var p = [plugin0, plugin1, plugin2];
|
|
89
|
-
p.item = function item(i) { return this[i] || null; };
|
|
90
|
-
p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
|
|
91
|
-
p.refresh = function refresh() {};
|
|
92
|
-
try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
|
|
93
|
-
try {
|
|
94
|
-
__greedyMimeTypes[0].enabledPlugin = p[0];
|
|
95
|
-
__greedyMimeTypes[1].enabledPlugin = p[0];
|
|
96
|
-
} catch(_) {}
|
|
97
|
-
return p;
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { nodeRuntimeCommand } from "../src/utils/node-runtime.mjs";
|
|
3
|
+
import { createInterface } from "node:readline";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const SEARCH_BIN = join(__dirname, "search.mjs");
|
|
8
|
+
const PROTOCOL_VERSION = "2025-06-18";
|
|
9
|
+
const SERVER_INFO = { name: "greedysearch", version: "1.0.0" };
|
|
10
|
+
const DEFAULT_TIMEOUT_MS = 6 * 60 * 1000;
|
|
11
|
+
function log(...args) {
|
|
12
|
+
process.stderr.write(`[greedysearch-mcp] ${args.join(" ")}
|
|
13
|
+
`);
|
|
14
|
+
}
|
|
15
|
+
function send(message) {
|
|
16
|
+
process.stdout.write(`${JSON.stringify(message)}
|
|
17
|
+
`);
|
|
18
|
+
}
|
|
19
|
+
function sendResult(id, result) {
|
|
20
|
+
if (id === undefined || id === null)
|
|
21
|
+
return;
|
|
22
|
+
send({ jsonrpc: "2.0", id, result });
|
|
23
|
+
}
|
|
24
|
+
function sendError(id, code, message, data) {
|
|
25
|
+
if (id === undefined || id === null)
|
|
26
|
+
return;
|
|
27
|
+
send({ jsonrpc: "2.0", id, error: { code, message, ...data ? { data } : {} } });
|
|
28
|
+
}
|
|
29
|
+
const ENGINE_DESCRIPTION = 'Engine to use: "all" (default, fans out to configured engines and fetches top sources), ' + '"perplexity" (p), "google" (g), "chatgpt" (gpt), "gemini" (gem), "bing" (b). ' + 'Research engines: "semantic-scholar" (s2) and "logically" (log).';
|
|
30
|
+
const GREEDY_SEARCH_SCHEMA = {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
query: { type: "string", description: "The search query" },
|
|
34
|
+
engine: {
|
|
35
|
+
type: "string",
|
|
36
|
+
default: "all",
|
|
37
|
+
description: ENGINE_DESCRIPTION
|
|
98
38
|
},
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
__greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
|
|
104
|
-
return __greedyMimeTypes;
|
|
39
|
+
synthesize: {
|
|
40
|
+
type: "boolean",
|
|
41
|
+
default: false,
|
|
42
|
+
description: 'Only for engine="all": synthesize the multi-engine results and fetched sources.'
|
|
105
43
|
},
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
44
|
+
synthesizer: {
|
|
45
|
+
type: "string",
|
|
46
|
+
description: 'Synthesis engine for synthesize=true. Defaults to ~/.dm/greedyconfig synthesizer ("gemini" by default). Supported: "gemini", "chatgpt".'
|
|
47
|
+
},
|
|
48
|
+
depth: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: 'Use "research" for the iterative research workflow. Legacy values: "fast" skips source fetching; "standard"/"deep" alias synthesize=true.'
|
|
51
|
+
},
|
|
52
|
+
breadth: {
|
|
53
|
+
type: "number",
|
|
54
|
+
default: 3,
|
|
55
|
+
description: 'Only for depth="research": number of parallel research directions per round, 1-5.'
|
|
56
|
+
},
|
|
57
|
+
iterations: {
|
|
58
|
+
type: "number",
|
|
59
|
+
default: 2,
|
|
60
|
+
description: 'Only for depth="research": number of iterative research rounds, 1-3.'
|
|
61
|
+
},
|
|
62
|
+
maxSources: {
|
|
63
|
+
type: "number",
|
|
64
|
+
description: 'Only for depth="research": maximum fetched sources for the final report, 3-12.'
|
|
65
|
+
},
|
|
66
|
+
researchOutDir: {
|
|
67
|
+
type: "string",
|
|
68
|
+
description: 'Only for depth="research": optional directory for the structured research bundle.'
|
|
69
|
+
},
|
|
70
|
+
writeResearchBundle: {
|
|
71
|
+
type: "boolean",
|
|
72
|
+
default: true,
|
|
73
|
+
description: 'Only for depth="research": write the structured research bundle to disk.'
|
|
74
|
+
},
|
|
75
|
+
fullAnswer: {
|
|
76
|
+
type: "boolean",
|
|
77
|
+
default: false,
|
|
78
|
+
description: "When true, returns the complete answer instead of a truncated preview."
|
|
79
|
+
},
|
|
80
|
+
locale: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: 'Force results language (e.g. "en", "de", "fr"). Defaults to GREEDY_SEARCH_LOCALE or "en".'
|
|
83
|
+
},
|
|
84
|
+
visible: {
|
|
85
|
+
type: "boolean",
|
|
86
|
+
default: false,
|
|
87
|
+
description: "Set to true to always use visible Chrome for this search (e.g. to solve a login/captcha challenge)."
|
|
130
88
|
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
89
|
+
},
|
|
90
|
+
required: ["query"]
|
|
91
|
+
};
|
|
92
|
+
const GREEDY_FETCH_SCHEMA = {
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
url: { type: "string", description: "URL to fetch and extract content from" },
|
|
96
|
+
maxChars: {
|
|
97
|
+
type: "number",
|
|
98
|
+
default: 8000,
|
|
99
|
+
description: "Maximum characters of extracted content to return."
|
|
135
100
|
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
101
|
+
},
|
|
102
|
+
required: ["url"]
|
|
103
|
+
};
|
|
104
|
+
const TOOLS = [
|
|
105
|
+
{
|
|
106
|
+
name: "greedy_search",
|
|
107
|
+
description: "WEB/RESEARCH SEARCH ONLY — searches live web via Perplexity, Google AI, ChatGPT, and Gemini, " + "plus opt-in research through Semantic Scholar and Logically, using local headless Chrome automation " + '(no API keys needed). Research mode (depth: "research") plans follow-up actions, fetches sources, ' + "audits citations, and writes a structured research bundle on disk. Searches take roughly 1-5 minutes.",
|
|
108
|
+
inputSchema: GREEDY_SEARCH_SCHEMA
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "greedy_fetch",
|
|
112
|
+
description: "Fetch a single URL and extract its readable content (title, byline, markdown body). " + "Uses HTTP first, falling back to Chrome/browser rendering for JS-heavy or blocked pages.",
|
|
113
|
+
inputSchema: GREEDY_FETCH_SCHEMA
|
|
148
114
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
115
|
+
];
|
|
116
|
+
function buildSearchFlags(args) {
|
|
117
|
+
const engine = String(args.engine ?? "all").trim() || "all";
|
|
118
|
+
const depthRaw = String(args.depth ?? "").trim();
|
|
119
|
+
const researchMode = depthRaw === "research";
|
|
120
|
+
const legacyFast = depthRaw === "fast";
|
|
121
|
+
const legacySynthesisDepth = depthRaw === "standard" || depthRaw === "deep";
|
|
122
|
+
const synthesize = engine === "all" && !legacyFast && (args.synthesize === true || legacySynthesisDepth);
|
|
123
|
+
const effectiveEngine = researchMode ? "all" : engine;
|
|
124
|
+
const visible = args.visible === true || process.env.GREEDY_SEARCH_VISIBLE === "1";
|
|
125
|
+
const flags = [];
|
|
126
|
+
const fullAnswer = args.fullAnswer ?? effectiveEngine !== "all";
|
|
127
|
+
if (fullAnswer)
|
|
128
|
+
flags.push("--full");
|
|
129
|
+
if (researchMode) {
|
|
130
|
+
flags.push("--depth", "research");
|
|
131
|
+
if (typeof args.breadth === "number")
|
|
132
|
+
flags.push("--breadth", String(args.breadth));
|
|
133
|
+
if (typeof args.iterations === "number")
|
|
134
|
+
flags.push("--iterations", String(args.iterations));
|
|
135
|
+
if (typeof args.maxSources === "number")
|
|
136
|
+
flags.push("--max-sources", String(args.maxSources));
|
|
137
|
+
if (typeof args.researchOutDir === "string")
|
|
138
|
+
flags.push("--research-out-dir", args.researchOutDir);
|
|
139
|
+
if (args.writeResearchBundle === false)
|
|
140
|
+
flags.push("--no-research-bundle");
|
|
141
|
+
} else if (legacyFast) {
|
|
142
|
+
flags.push("--fast");
|
|
143
|
+
} else if (depthRaw === "deep") {
|
|
144
|
+
flags.push("--depth", "deep");
|
|
145
|
+
} else if (synthesize) {
|
|
146
|
+
flags.push("--synthesize");
|
|
158
147
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
148
|
+
if (synthesize && typeof args.synthesizer === "string") {
|
|
149
|
+
flags.push("--synthesizer", args.synthesizer);
|
|
150
|
+
}
|
|
151
|
+
if (typeof args.locale === "string" && args.locale) {
|
|
152
|
+
flags.push("--locale", args.locale);
|
|
153
|
+
}
|
|
154
|
+
if (visible)
|
|
155
|
+
flags.push("--always-visible");
|
|
156
|
+
else
|
|
157
|
+
flags.push("--headless");
|
|
158
|
+
return { engine: effectiveEngine, flags, visible };
|
|
159
|
+
}
|
|
160
|
+
function runSearch(query, args) {
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const { engine, flags, visible } = buildSearchFlags(args);
|
|
163
|
+
const procEnv = { ...process.env };
|
|
164
|
+
if (visible) {
|
|
165
|
+
procEnv.GREEDY_SEARCH_VISIBLE = "1";
|
|
166
|
+
procEnv.GREEDY_SEARCH_ALWAYS_VISIBLE = "1";
|
|
167
|
+
}
|
|
168
|
+
const proc = spawn(nodeRuntimeCommand(), [SEARCH_BIN, engine, "--inline", "--stdin", ...flags], { stdio: ["pipe", "pipe", "pipe"], env: procEnv });
|
|
169
|
+
proc.stdin.write(query);
|
|
170
|
+
proc.stdin.end();
|
|
171
|
+
let out = "";
|
|
172
|
+
let err = "";
|
|
173
|
+
const MAX_ERR = 50 * 1024;
|
|
174
|
+
let settled = false;
|
|
175
|
+
const parsedTimeout = parseInt(process.env.GREEDY_SEARCH_TIMEOUT_MS || "", 10);
|
|
176
|
+
const timeoutMs = Number.isNaN(parsedTimeout) ? DEFAULT_TIMEOUT_MS : parsedTimeout;
|
|
177
|
+
const timer = setTimeout(() => {
|
|
178
|
+
if (settled)
|
|
179
|
+
return;
|
|
180
|
+
settled = true;
|
|
181
|
+
if (process.platform === "win32")
|
|
182
|
+
proc.kill();
|
|
183
|
+
else
|
|
184
|
+
proc.kill("SIGTERM");
|
|
185
|
+
reject(new Error(`greedy_search timed out after ${timeoutMs}ms`));
|
|
186
|
+
}, timeoutMs);
|
|
187
|
+
timer.unref();
|
|
188
|
+
proc.stderr.on("data", (d) => {
|
|
189
|
+
err += d;
|
|
190
|
+
if (err.length > MAX_ERR)
|
|
191
|
+
err = err.slice(-MAX_ERR);
|
|
192
|
+
log(d.toString().trimEnd());
|
|
192
193
|
});
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
proc.stdout.on("data", (d) => out += d);
|
|
195
|
+
proc.on("error", (e) => {
|
|
196
|
+
if (settled)
|
|
197
|
+
return;
|
|
198
|
+
settled = true;
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
reject(e);
|
|
199
201
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// but varies between sessions.
|
|
209
|
-
var w = this.width, h = this.height;
|
|
210
|
-
if (w > 0 && h > 0) {
|
|
211
|
-
var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
|
|
212
|
-
if (imgData && imgData.data) {
|
|
213
|
-
for (var __i = 0; __i < imgData.data.length; __i += 4) {
|
|
214
|
-
imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
|
|
215
|
-
}
|
|
216
|
-
ctx.putImageData(imgData, 0, 0);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
202
|
+
proc.on("close", (code) => {
|
|
203
|
+
if (settled)
|
|
204
|
+
return;
|
|
205
|
+
settled = true;
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
if (code !== 0) {
|
|
208
|
+
reject(new Error(err.trim() || `search.mjs exited with code ${code}`));
|
|
209
|
+
return;
|
|
219
210
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// ── AudioContext fingerprint noise ────────────────────
|
|
225
|
-
// Headless Chrome's AudioContext produces slightly different output.
|
|
226
|
-
// Subtle noise breaks audio-based fingerprinting.
|
|
227
|
-
try {
|
|
228
|
-
var __audioSeed = ((Date.now() & 0x1F) | 1);
|
|
229
|
-
var origGetChannelData = AudioBuffer.prototype.getChannelData;
|
|
230
|
-
AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
|
|
231
|
-
var data = origGetChannelData.call(this, channel);
|
|
232
|
-
for (var __i = 0; __i < data.length; __i += 64) {
|
|
233
|
-
data[__i] *= 0.99999;
|
|
211
|
+
try {
|
|
212
|
+
resolve(JSON.parse(out.trim()));
|
|
213
|
+
} catch {
|
|
214
|
+
reject(new Error(`Invalid JSON from search.mjs: ${out.slice(0, 200)}`));
|
|
234
215
|
}
|
|
235
|
-
return data;
|
|
236
|
-
});
|
|
237
|
-
} catch(_) {}
|
|
238
|
-
|
|
239
|
-
// ── window outer dimensions ──────────────────────────
|
|
240
|
-
// outerWidth/Height = 0 in headless — a well-known bot signal.
|
|
241
|
-
// Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
|
|
242
|
-
try {
|
|
243
|
-
if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
|
|
244
|
-
if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
|
|
245
|
-
} catch(_) {}
|
|
246
|
-
|
|
247
|
-
// ── screen properties ─────────────────────────────────
|
|
248
|
-
// Headless Chrome often reports an 800x600 screen even when the viewport is
|
|
249
|
-
// 1920x1080. Keep screen metrics internally consistent with our launch flags.
|
|
250
|
-
try {
|
|
251
|
-
Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
|
|
252
|
-
Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
|
|
253
|
-
Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
|
|
254
|
-
Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
|
|
255
|
-
Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
|
|
256
|
-
Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
|
|
257
|
-
} catch(_) {}
|
|
258
|
-
|
|
259
|
-
// ── navigator.userAgentData (UA Client Hints) ─────────
|
|
260
|
-
// Derive version from the UA string already set by --user-agent flag so the
|
|
261
|
-
// two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
|
|
262
|
-
try {
|
|
263
|
-
var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
|
|
264
|
-
var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
|
|
265
|
-
var _brands = [
|
|
266
|
-
{ brand: 'Not)A;Brand', version: '99' },
|
|
267
|
-
{ brand: 'Google Chrome', version: _uaMajor },
|
|
268
|
-
{ brand: 'Chromium', version: _uaMajor },
|
|
269
|
-
];
|
|
270
|
-
Object.defineProperty(navigator, 'userAgentData', {
|
|
271
|
-
get: function() {
|
|
272
|
-
return {
|
|
273
|
-
brands: _brands, mobile: false, platform: 'Windows',
|
|
274
|
-
getHighEntropyValues: function() {
|
|
275
|
-
return Promise.resolve({
|
|
276
|
-
architecture: 'x86', bitness: '64',
|
|
277
|
-
brands: _brands,
|
|
278
|
-
fullVersionList: [
|
|
279
|
-
{ brand: 'Not)A;Brand', version: '99.0.0.0' },
|
|
280
|
-
{ brand: 'Google Chrome', version: _uaFull },
|
|
281
|
-
{ brand: 'Chromium', version: _uaFull },
|
|
282
|
-
],
|
|
283
|
-
mobile: false, model: '', platform: 'Windows',
|
|
284
|
-
platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
|
|
285
|
-
});
|
|
286
|
-
},
|
|
287
|
-
toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
|
|
288
|
-
};
|
|
289
|
-
},
|
|
290
|
-
configurable: true,
|
|
291
216
|
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function formatSummary(engine, data) {
|
|
220
|
+
const lines = [];
|
|
221
|
+
const needsHuman = data._needsHumanVerification;
|
|
222
|
+
if (needsHuman) {
|
|
223
|
+
lines.push("## Manual verification required");
|
|
224
|
+
lines.push(String(needsHuman.message || "Visible Chrome is open. Solve the verification challenge, then rerun the same search."));
|
|
225
|
+
}
|
|
226
|
+
const synthesis = data._synthesis;
|
|
227
|
+
if (synthesis?.answer) {
|
|
228
|
+
lines.push(String(synthesis.answer));
|
|
229
|
+
const sources = Array.isArray(data._sources) ? data._sources : [];
|
|
230
|
+
if (sources.length > 0) {
|
|
231
|
+
lines.push(`
|
|
232
|
+
Sources:`);
|
|
233
|
+
for (const s of sources.slice(0, 8)) {
|
|
234
|
+
lines.push(`- [${s.title || s.url}](${s.url})`);
|
|
306
235
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
var __nativeToString = Function.prototype.toString;
|
|
320
|
-
Function.prototype.toString = function toString() {
|
|
321
|
-
if (__greedyNativeFns.indexOf(this) !== -1) {
|
|
322
|
-
var name = this.name || '';
|
|
323
|
-
return 'function ' + name + '() { [native code] }';
|
|
236
|
+
}
|
|
237
|
+
return lines.join(`
|
|
238
|
+
`).trim();
|
|
239
|
+
}
|
|
240
|
+
if (typeof data.answer === "string") {
|
|
241
|
+
lines.push(data.answer);
|
|
242
|
+
const sources = Array.isArray(data.sources) ? data.sources : [];
|
|
243
|
+
if (sources.length > 0) {
|
|
244
|
+
lines.push(`
|
|
245
|
+
Sources:`);
|
|
246
|
+
for (const s of sources.slice(0, 8)) {
|
|
247
|
+
lines.push(`- [${s.title || s.url}](${s.url})`);
|
|
324
248
|
}
|
|
325
|
-
|
|
249
|
+
}
|
|
250
|
+
return lines.join(`
|
|
251
|
+
`).trim();
|
|
252
|
+
}
|
|
253
|
+
const engineKeys = Object.keys(data).filter((k) => !k.startsWith("_") && data[k] && typeof data[k] === "object");
|
|
254
|
+
for (const key of engineKeys) {
|
|
255
|
+
const eng = data[key];
|
|
256
|
+
if (engineKeys.length > 1) {
|
|
257
|
+
lines.push(`
|
|
258
|
+
## ${key}`);
|
|
259
|
+
}
|
|
260
|
+
if (eng.error) {
|
|
261
|
+
lines.push(`Error: ${eng.error}`);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (eng.answer)
|
|
265
|
+
lines.push(String(eng.answer));
|
|
266
|
+
const sources = Array.isArray(eng.sources) ? eng.sources : [];
|
|
267
|
+
if (sources.length > 0) {
|
|
268
|
+
lines.push(`
|
|
269
|
+
Sources:`);
|
|
270
|
+
for (const s of sources.slice(0, 5)) {
|
|
271
|
+
lines.push(`- [${s.title || s.url}](${s.url})`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return lines.join(`
|
|
276
|
+
`).trim() || "No results returned.";
|
|
277
|
+
}
|
|
278
|
+
async function callGreedySearch(args) {
|
|
279
|
+
if (!args || typeof args.query !== "string" || !args.query.trim()) {
|
|
280
|
+
throw new Error("query is required");
|
|
281
|
+
}
|
|
282
|
+
const data = await runSearch(args.query, args);
|
|
283
|
+
const summary = formatSummary(args.engine ?? "all", data);
|
|
284
|
+
return {
|
|
285
|
+
content: [
|
|
286
|
+
{ type: "text", text: summary || "No results returned." },
|
|
287
|
+
{ type: "text", text: JSON.stringify(data) }
|
|
288
|
+
]
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
let fetchSourceContentPromise;
|
|
292
|
+
function getFetchSourceContent() {
|
|
293
|
+
if (!fetchSourceContentPromise) {
|
|
294
|
+
fetchSourceContentPromise = import("../src/search/fetch-source.mjs").then((m) => m.fetchSourceContent);
|
|
295
|
+
}
|
|
296
|
+
return fetchSourceContentPromise;
|
|
297
|
+
}
|
|
298
|
+
async function callGreedyFetch(args) {
|
|
299
|
+
if (!args || typeof args.url !== "string" || !args.url.trim()) {
|
|
300
|
+
throw new Error("url is required");
|
|
301
|
+
}
|
|
302
|
+
const maxChars = typeof args.maxChars === "number" ? args.maxChars : 8000;
|
|
303
|
+
const fetchSourceContent = await getFetchSourceContent();
|
|
304
|
+
const result = await fetchSourceContent(args.url, maxChars);
|
|
305
|
+
if (result?.error && !result.content) {
|
|
306
|
+
return {
|
|
307
|
+
content: [{ type: "text", text: `Fetch failed: ${result.error}` }],
|
|
308
|
+
isError: true
|
|
326
309
|
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
`
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
`)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
310
|
+
}
|
|
311
|
+
const summary = [
|
|
312
|
+
`# ${result.title || args.url}`,
|
|
313
|
+
"",
|
|
314
|
+
result.byline ? `By ${result.byline}` : null,
|
|
315
|
+
result.siteName ? `Source: ${result.siteName}` : null,
|
|
316
|
+
"",
|
|
317
|
+
result.content || "(no content extracted)"
|
|
318
|
+
].filter((l) => l !== null).join(`
|
|
319
|
+
`);
|
|
320
|
+
return {
|
|
321
|
+
content: [
|
|
322
|
+
{ type: "text", text: summary },
|
|
323
|
+
{ type: "text", text: JSON.stringify(result) }
|
|
324
|
+
]
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
async function handleRequest(msg) {
|
|
328
|
+
const { id, method, params } = msg;
|
|
329
|
+
switch (method) {
|
|
330
|
+
case "initialize": {
|
|
331
|
+
const clientVersion = params?.protocolVersion;
|
|
332
|
+
sendResult(id, {
|
|
333
|
+
protocolVersion: typeof clientVersion === "string" ? clientVersion : PROTOCOL_VERSION,
|
|
334
|
+
capabilities: { tools: {} },
|
|
335
|
+
serverInfo: SERVER_INFO
|
|
336
|
+
});
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
case "notifications/initialized":
|
|
340
|
+
case "initialized":
|
|
341
|
+
return;
|
|
342
|
+
case "ping":
|
|
343
|
+
sendResult(id, {});
|
|
344
|
+
return;
|
|
345
|
+
case "tools/list":
|
|
346
|
+
sendResult(id, { tools: TOOLS });
|
|
347
|
+
return;
|
|
348
|
+
case "tools/call": {
|
|
349
|
+
const name = params?.name;
|
|
350
|
+
const toolArgs = params?.arguments ?? {};
|
|
351
|
+
try {
|
|
352
|
+
let result;
|
|
353
|
+
if (name === "greedy_search")
|
|
354
|
+
result = await callGreedySearch(toolArgs);
|
|
355
|
+
else if (name === "greedy_fetch")
|
|
356
|
+
result = await callGreedyFetch(toolArgs);
|
|
357
|
+
else {
|
|
358
|
+
sendError(id, -32602, `Unknown tool: ${name}`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
sendResult(id, result);
|
|
362
|
+
} catch (e) {
|
|
363
|
+
sendResult(id, {
|
|
364
|
+
content: [{ type: "text", text: `Error: ${e.message || String(e)}` }],
|
|
365
|
+
isError: true
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
default:
|
|
371
|
+
if (method && method.startsWith("notifications/"))
|
|
372
|
+
return;
|
|
373
|
+
sendError(id, -32601, `Method not found: ${method}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function main() {
|
|
377
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
378
|
+
rl.on("line", (line) => {
|
|
379
|
+
const trimmed = line.trim();
|
|
380
|
+
if (!trimmed)
|
|
381
|
+
return;
|
|
382
|
+
let msg;
|
|
383
|
+
try {
|
|
384
|
+
msg = JSON.parse(trimmed);
|
|
385
|
+
} catch {
|
|
386
|
+
sendError(null, -32700, "Parse error");
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
handleRequest(msg).catch((e) => {
|
|
390
|
+
log("Unhandled error:", e?.stack || String(e));
|
|
391
|
+
sendError(msg?.id, -32603, "Internal error", String(e?.message || e));
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
rl.on("close", () => process.exit(0));
|
|
395
|
+
process.on("uncaughtException", (e) => {
|
|
396
|
+
log("Uncaught exception:", e?.stack || String(e));
|
|
397
|
+
});
|
|
398
|
+
log(`GreedySearch MCP server ready (${SEARCH_BIN})`);
|
|
399
|
+
}
|
|
400
|
+
main();
|