@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,555 +1,635 @@
|
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
__greedyMimeTypes[1].enabledPlugin = p[0];
|
|
54
|
-
} catch(_) {}
|
|
55
|
-
return p;
|
|
56
|
-
},
|
|
57
|
-
configurable: true,
|
|
58
|
-
});
|
|
59
|
-
Object.defineProperty(navigator, 'mimeTypes', {
|
|
60
|
-
get: () => {
|
|
61
|
-
__greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
|
|
62
|
-
return __greedyMimeTypes;
|
|
63
|
-
},
|
|
64
|
-
configurable: true,
|
|
65
|
-
});
|
|
66
|
-
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
|
|
67
|
-
try {
|
|
68
|
-
Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
|
|
69
|
-
} catch(_) {}
|
|
70
|
-
if (!navigator.mediaDevices) {
|
|
71
|
-
Object.defineProperty(navigator, 'mediaDevices', {
|
|
72
|
-
get: () => ({
|
|
73
|
-
enumerateDevices: () => Promise.resolve([
|
|
74
|
-
{ deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
|
|
75
|
-
{ deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
|
|
76
|
-
{ deviceId: '', kind: 'videoinput', label: '', groupId: '' },
|
|
77
|
-
]),
|
|
78
|
-
getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
|
|
79
|
-
getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
|
|
80
|
-
}),
|
|
81
|
-
configurable: true,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
// ── Missing platform APIs (headless often lacks these) ─
|
|
1
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
cdp,
|
|
6
|
+
closeTab,
|
|
7
|
+
closeTabs,
|
|
8
|
+
ensureChrome,
|
|
9
|
+
killHeadlessChrome,
|
|
10
|
+
openNewTab,
|
|
11
|
+
touchActivity
|
|
12
|
+
} from "../src/search/chrome.mjs";
|
|
13
|
+
import {
|
|
14
|
+
ALL_ENGINES,
|
|
15
|
+
ENGINES,
|
|
16
|
+
SYNTHESIZER,
|
|
17
|
+
VISIBLE_RECOVERY_LOG,
|
|
18
|
+
GREEDY_PORT
|
|
19
|
+
} from "../src/search/constants.mjs";
|
|
20
|
+
import { runExtractor } from "../src/search/engines.mjs";
|
|
21
|
+
import {
|
|
22
|
+
fetchMultipleSources,
|
|
23
|
+
fetchTopSource
|
|
24
|
+
} from "../src/search/fetch-source.mjs";
|
|
25
|
+
import { waitForChallengeCleared } from "../src/search/challenge-detect.mjs";
|
|
26
|
+
import { writeSourcesToFiles } from "../src/search/file-sources.mjs";
|
|
27
|
+
import { writeOutput } from "../src/search/output.mjs";
|
|
28
|
+
import {
|
|
29
|
+
findHeadlessBlockedEngines,
|
|
30
|
+
isHeadlessBlockedResult,
|
|
31
|
+
isManualVerificationError
|
|
32
|
+
} from "../src/search/recovery.mjs";
|
|
33
|
+
import {
|
|
34
|
+
buildSourceRegistry,
|
|
35
|
+
mergeFetchDataIntoSources
|
|
36
|
+
} from "../src/search/sources.mjs";
|
|
37
|
+
import { buildConfidence } from "../src/search/synthesis.mjs";
|
|
38
|
+
import {
|
|
39
|
+
getSynthesisStartUrl,
|
|
40
|
+
normalizeSynthesizer,
|
|
41
|
+
synthesizeResults
|
|
42
|
+
} from "../src/search/synthesis-runner.mjs";
|
|
43
|
+
import { normalizeQuery } from "../src/search/query.mjs";
|
|
44
|
+
import { runResearchMode } from "../src/search/research.mjs";
|
|
45
|
+
import { minimizeViaCDP } from "../src/search/minimize.mjs";
|
|
46
|
+
import {
|
|
47
|
+
moduleDirectory,
|
|
48
|
+
resolveGreedySearchExtractorScript
|
|
49
|
+
} from "../src/search/paths.mjs";
|
|
50
|
+
const CONFIG_DIR = join(homedir(), ".config", "greedysearch");
|
|
51
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
52
|
+
function loadUserConfig() {
|
|
85
53
|
try {
|
|
86
|
-
if (
|
|
87
|
-
|
|
54
|
+
if (existsSync(CONFIG_FILE)) {
|
|
55
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
|
|
88
56
|
}
|
|
89
|
-
} catch
|
|
57
|
+
} catch {}
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
function logVisibleRecovery(event) {
|
|
90
61
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
62
|
+
appendFileSync(VISIBLE_RECOVERY_LOG, `${JSON.stringify({ at: new Date().toISOString(), ...event })}
|
|
63
|
+
`, "utf8");
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
async function readStdin() {
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
let data = "";
|
|
69
|
+
process.stdin.setEncoding("utf8");
|
|
70
|
+
process.stdin.on("data", (chunk) => data += chunk);
|
|
71
|
+
process.stdin.on("end", () => resolve(data.trim()));
|
|
72
|
+
if (process.stdin.isTTY)
|
|
73
|
+
resolve("");
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function main() {
|
|
77
|
+
const args = process.argv.slice(2);
|
|
78
|
+
if (args[0] === "--dm-print-helper-paths") {
|
|
79
|
+
const binDir = moduleDirectory(import.meta.url);
|
|
80
|
+
console.log(JSON.stringify({
|
|
81
|
+
launchScript: join(binDir, "launch.mjs"),
|
|
82
|
+
searchScript: join(binDir, "search.mjs"),
|
|
83
|
+
perplexityExtractor: resolveGreedySearchExtractorScript("perplexity.mjs", { moduleDir: binDir })
|
|
84
|
+
}));
|
|
85
|
+
return;
|
|
106
86
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
87
|
+
if (args.length < 2 || args[0] === "--help") {
|
|
88
|
+
process.stderr.write(`${[
|
|
89
|
+
'Usage: node search.mjs <engine> "<query>"',
|
|
90
|
+
"",
|
|
91
|
+
"Engines: all, perplexity (p), google (g), chatgpt (gpt), gemini (gem), semantic-scholar (s2), logically (log), bing (b)",
|
|
92
|
+
"",
|
|
93
|
+
"Flags:",
|
|
94
|
+
" --synthesize For engine=all: synthesize fetched sources",
|
|
95
|
+
" --synthesizer <engine> Synthesis engine (default from ~/.dm/greedyconfig)",
|
|
96
|
+
" --fast Legacy quick mode: no source fetching or synthesis",
|
|
97
|
+
" --depth <mode> Legacy: fast|standard|deep aliases, or research",
|
|
98
|
+
" --deep-research Deprecated alias for --research",
|
|
99
|
+
" --research Iterative query/learnings loop (alias: --depth research)",
|
|
100
|
+
" --breadth <n> Research mode query breadth, 1-5 (default: 3)",
|
|
101
|
+
" --iterations <n> Research mode rounds, 1-3 (default: 2)",
|
|
102
|
+
" --max-sources <n> Research mode fetched source cap, 3-12",
|
|
103
|
+
" --research-out-dir <dir> Write research bundle to a specific directory",
|
|
104
|
+
" --no-research-bundle Disable the default .dm/greedysearch-research bundle",
|
|
105
|
+
" --fetch-top-source Fetch content from top source",
|
|
106
|
+
" --inline Output JSON to stdout (for piping)",
|
|
107
|
+
" --locale <lang> Force results language (en, de, fr, etc.)",
|
|
108
|
+
" --visible Always use visible Chrome for this search",
|
|
109
|
+
" --always-visible Alias for --visible",
|
|
110
|
+
" --stdin Read query from stdin (avoids command-line leakage)",
|
|
111
|
+
"",
|
|
112
|
+
"Environment:",
|
|
113
|
+
" GREEDY_SEARCH_VISIBLE Set to 1 to show Chrome window (disables headless)",
|
|
114
|
+
" GREEDY_SEARCH_ALWAYS_VISIBLE Set to 1 to force visible mode for all runs",
|
|
115
|
+
" GREEDY_SEARCH_LOCALE Default locale (default: en)",
|
|
116
|
+
"",
|
|
117
|
+
"Examples:",
|
|
118
|
+
' node search.mjs all "Node.js streams" # Grounded: engines + fetched sources',
|
|
119
|
+
' node search.mjs all "Node.js streams" --synthesize # Add Gemini synthesis',
|
|
120
|
+
' node search.mjs all "quick check" --fast # Legacy fast: no sources/synthesis',
|
|
121
|
+
' node search.mjs all "browser automation" --research --breadth 3 --iterations 2',
|
|
122
|
+
' node search.mjs p "what is memoization" # Single engine search'
|
|
123
|
+
].join(`
|
|
124
|
+
`)}
|
|
125
|
+
`);
|
|
126
|
+
process.exit(1);
|
|
116
127
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
128
|
+
const alwaysVisible = args.includes("--visible") || args.includes("--always-visible") || process.env.GREEDY_SEARCH_ALWAYS_VISIBLE === "1";
|
|
129
|
+
if (alwaysVisible) {
|
|
130
|
+
process.env.GREEDY_SEARCH_VISIBLE = "1";
|
|
131
|
+
process.env.GREEDY_SEARCH_ALWAYS_VISIBLE = "1";
|
|
132
|
+
delete process.env.GREEDY_SEARCH_HEADLESS;
|
|
133
|
+
} else if (process.env.GREEDY_SEARCH_VISIBLE !== "1") {
|
|
134
|
+
process.env.GREEDY_SEARCH_HEADLESS = "1";
|
|
135
|
+
}
|
|
136
|
+
await ensureChrome();
|
|
137
|
+
touchActivity();
|
|
138
|
+
const depthIdx = args.indexOf("--depth");
|
|
139
|
+
const legacyDepth = depthIdx !== -1 && args[depthIdx + 1] ? args[depthIdx + 1].toLowerCase() : null;
|
|
140
|
+
const engineArg = args.find((a) => !a.startsWith("--"))?.toLowerCase();
|
|
141
|
+
const researchMode = args.includes("--research") || args.includes("--deep-research") || legacyDepth === "research";
|
|
142
|
+
const legacyFast = args.includes("--fast") || legacyDepth === "fast";
|
|
143
|
+
const legacySynthesisDepth = legacyDepth === "standard" || legacyDepth === "deep" || args.includes("--deep");
|
|
144
|
+
const shouldFetchSources = engineArg === "all" && !legacyFast;
|
|
145
|
+
const shouldSynthesize = engineArg === "all" && !legacyFast && (args.includes("--synthesize") || legacySynthesisDepth);
|
|
146
|
+
const groundedSynthesis = legacyDepth === "deep" || args.includes("--deep");
|
|
147
|
+
if (args.includes("--deep-research")) {
|
|
148
|
+
process.stderr.write(`[greedysearch] --deep-research is deprecated; use --research or --depth research
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
151
|
+
if (legacySynthesisDepth) {
|
|
152
|
+
process.stderr.write(`[greedysearch] depth fast|standard|deep is deprecated; use default grounded search plus --synthesize when needed
|
|
153
|
+
`);
|
|
154
|
+
}
|
|
155
|
+
const synthesizerIdx = args.indexOf("--synthesizer");
|
|
156
|
+
const synthesizer = normalizeSynthesizer(synthesizerIdx === -1 ? SYNTHESIZER : args[synthesizerIdx + 1]);
|
|
157
|
+
const full = args.includes("--full");
|
|
158
|
+
const short = !full;
|
|
159
|
+
const fetchSource = args.includes("--fetch-top-source");
|
|
160
|
+
const inline = args.includes("--inline");
|
|
161
|
+
const breadthIdx = args.indexOf("--breadth");
|
|
162
|
+
const iterationsIdx = args.indexOf("--iterations");
|
|
163
|
+
const maxSourcesIdx = args.indexOf("--max-sources");
|
|
164
|
+
const researchBreadth = breadthIdx === -1 ? undefined : args[breadthIdx + 1];
|
|
165
|
+
const researchIterations = iterationsIdx === -1 ? undefined : args[iterationsIdx + 1];
|
|
166
|
+
const researchMaxSources = maxSourcesIdx === -1 ? undefined : args[maxSourcesIdx + 1];
|
|
167
|
+
const researchOutDirIdx = args.indexOf("--research-out-dir");
|
|
168
|
+
const researchOutDir = researchOutDirIdx === -1 ? undefined : args[researchOutDirIdx + 1];
|
|
169
|
+
const writeResearchBundle = !args.includes("--no-research-bundle");
|
|
170
|
+
const outIdx = args.indexOf("--out");
|
|
171
|
+
const outFile = outIdx === -1 ? null : args[outIdx + 1];
|
|
172
|
+
const localeIdx = args.indexOf("--locale");
|
|
173
|
+
const envLocale = process.env.GREEDY_SEARCH_LOCALE;
|
|
174
|
+
const userConfig = loadUserConfig();
|
|
175
|
+
let locale = "en";
|
|
176
|
+
if (localeIdx !== -1 && args[localeIdx + 1]) {
|
|
177
|
+
locale = args[localeIdx + 1];
|
|
178
|
+
} else if (envLocale) {
|
|
179
|
+
locale = envLocale;
|
|
180
|
+
} else if (userConfig.locale) {
|
|
181
|
+
locale = userConfig.locale;
|
|
182
|
+
}
|
|
183
|
+
const rest = args.filter((a, i) => a !== "--full" && a !== "--short" && a !== "--fast" && a !== "--fetch-top-source" && a !== "--synthesize" && a !== "--deep-research" && a !== "--deep" && a !== "--research" && a !== "--inline" && a !== "--stdin" && a !== "--headless" && a !== "--visible" && a !== "--always-visible" && a !== "--depth" && a !== "--synthesizer" && a !== "--out" && a !== "--locale" && a !== "--breadth" && a !== "--iterations" && a !== "--max-sources" && a !== "--research-out-dir" && a !== "--no-research-bundle" && a !== "--help" && (depthIdx === -1 || i !== depthIdx + 1) && (synthesizerIdx === -1 || i !== synthesizerIdx + 1) && (outIdx === -1 || i !== outIdx + 1) && (localeIdx === -1 || i !== localeIdx + 1) && (breadthIdx === -1 || i !== breadthIdx + 1) && (iterationsIdx === -1 || i !== iterationsIdx + 1) && (maxSourcesIdx === -1 || i !== maxSourcesIdx + 1) && (researchOutDirIdx === -1 || i !== researchOutDirIdx + 1));
|
|
184
|
+
const engine = rest[0]?.toLowerCase();
|
|
185
|
+
const useStdin = args.includes("--stdin");
|
|
186
|
+
let query;
|
|
187
|
+
if (useStdin) {
|
|
188
|
+
query = await readStdin();
|
|
189
|
+
} else {
|
|
190
|
+
query = rest.slice(1).join(" ");
|
|
191
|
+
}
|
|
192
|
+
if (researchMode) {
|
|
193
|
+
if (engine !== "all") {
|
|
194
|
+
process.stderr.write(`[greedysearch] Research mode uses all engines; ignoring engine "${engine}".
|
|
195
|
+
`);
|
|
196
|
+
}
|
|
197
|
+
const out = await runResearchMode({
|
|
198
|
+
query: normalizeQuery(query),
|
|
199
|
+
breadth: researchBreadth,
|
|
200
|
+
iterations: researchIterations,
|
|
201
|
+
maxSources: researchMaxSources,
|
|
202
|
+
locale,
|
|
203
|
+
short,
|
|
204
|
+
writeBundle: writeResearchBundle,
|
|
205
|
+
researchOutDir
|
|
150
206
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.globalAlpha = 0.9995;
|
|
156
|
-
return origStroke.apply(this, arguments);
|
|
207
|
+
writeOutput(out, outFile, {
|
|
208
|
+
inline,
|
|
209
|
+
synthesize: true,
|
|
210
|
+
query
|
|
157
211
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (engine === "all") {
|
|
215
|
+
await cdp(["list"]);
|
|
216
|
+
const ENGINE_START_URLS = {
|
|
217
|
+
perplexity: "https://www.perplexity.ai/",
|
|
218
|
+
google: "https://www.google.com/",
|
|
219
|
+
chatgpt: "https://chatgpt.com/",
|
|
220
|
+
gemini: "https://gemini.google.com/app",
|
|
221
|
+
"semantic-scholar": "https://www.semanticscholar.org/",
|
|
222
|
+
semanticscholar: "https://www.semanticscholar.org/",
|
|
223
|
+
s2: "https://www.semanticscholar.org/",
|
|
224
|
+
logically: "https://logically.app/research-assistant/"
|
|
225
|
+
};
|
|
226
|
+
const engineTabs = await Promise.all(ALL_ENGINES.map((e) => openNewTab(ENGINE_START_URLS[e])));
|
|
227
|
+
await cdp(["list"]);
|
|
228
|
+
const engineTimeoutFor = (engineName) => {
|
|
229
|
+
if (!legacyFast)
|
|
230
|
+
return 70000;
|
|
231
|
+
return engineName === "chatgpt" ? 60000 : 35000;
|
|
232
|
+
};
|
|
233
|
+
try {
|
|
234
|
+
const results = await Promise.allSettled(ALL_ENGINES.map((e, i) => runExtractor(ENGINES[e], normalizeQuery(query), engineTabs[i], short, engineTimeoutFor(e), locale).then((r) => {
|
|
235
|
+
process.stderr.write(`PROGRESS:${e}:done
|
|
236
|
+
`);
|
|
237
|
+
return { engine: e, ...r };
|
|
238
|
+
}).catch((err) => {
|
|
239
|
+
throw err;
|
|
240
|
+
})));
|
|
241
|
+
const out = {};
|
|
242
|
+
for (let i = 0;i < results.length; i++) {
|
|
243
|
+
const r = results[i];
|
|
244
|
+
if (r.status === "fulfilled") {
|
|
245
|
+
out[r.value.engine] = r.value;
|
|
246
|
+
} else {
|
|
247
|
+
const err = r.reason;
|
|
248
|
+
const msg = err?.message || "unknown error";
|
|
249
|
+
out[ALL_ENGINES[i]] = { error: msg };
|
|
250
|
+
if (err?.lastStage) {
|
|
251
|
+
process.stderr.write(`[greedysearch] ${ALL_ENGINES[i]} failed at stage '${err.lastStage}': ${msg}
|
|
252
|
+
`);
|
|
253
|
+
}
|
|
254
|
+
if (err?.partialErr) {
|
|
255
|
+
process.stderr.write(`[greedysearch] ${ALL_ENGINES[i]} tail stderr:
|
|
256
|
+
${err.partialErr}
|
|
257
|
+
`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const recoveryCandidates = findHeadlessBlockedEngines(out);
|
|
262
|
+
if (recoveryCandidates.length > 0 && process.env.GREEDY_SEARCH_VISIBLE !== "1") {
|
|
263
|
+
logVisibleRecovery({
|
|
264
|
+
scope: "all",
|
|
265
|
+
phase: "start",
|
|
266
|
+
engines: recoveryCandidates,
|
|
267
|
+
reasons: Object.fromEntries(recoveryCandidates.map((engineName) => [
|
|
268
|
+
engineName,
|
|
269
|
+
{
|
|
270
|
+
error: out[engineName]?.error || null,
|
|
271
|
+
envelope: out[engineName]?._envelope || null
|
|
272
|
+
}
|
|
273
|
+
]))
|
|
274
|
+
});
|
|
275
|
+
process.stderr.write(`[greedysearch] \uD83D\uDD13 Headless ${recoveryCandidates.join(", ")} search hit timeout/verification/antibot signals — retrying visible to establish cookies...
|
|
276
|
+
`);
|
|
277
|
+
for (const blockedEngine of recoveryCandidates) {
|
|
278
|
+
process.stderr.write(`[greedysearch] ${blockedEngine} recovery starting in visible mode...
|
|
279
|
+
`);
|
|
280
|
+
}
|
|
281
|
+
await closeTabs(engineTabs);
|
|
282
|
+
await killHeadlessChrome();
|
|
283
|
+
process.env.GREEDY_SEARCH_VISIBLE = "1";
|
|
284
|
+
delete process.env.GREEDY_SEARCH_HEADLESS;
|
|
285
|
+
await ensureChrome();
|
|
286
|
+
await cdp(["list"]);
|
|
287
|
+
const retryTabs = [];
|
|
288
|
+
let keepVisibleForHuman = false;
|
|
289
|
+
let recovered = 0;
|
|
290
|
+
for (let i = 0;i < recoveryCandidates.length; i++) {
|
|
291
|
+
const tab = await openNewTab();
|
|
292
|
+
retryTabs.push(tab);
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
const retries = await Promise.allSettled(recoveryCandidates.map((e, i) => runExtractor(ENGINES[e], query, retryTabs[i], short, null, locale).then((r) => ({ engine: e, ...r })).catch((err) => ({ engine: e, error: err.message }))));
|
|
296
|
+
const stillBlocked = [];
|
|
297
|
+
const manualVerification = [];
|
|
298
|
+
for (const r of retries) {
|
|
299
|
+
if (r.status === "fulfilled" && !r.value.error) {
|
|
300
|
+
out[r.value.engine] = r.value;
|
|
301
|
+
recovered++;
|
|
302
|
+
process.stderr.write(`PROGRESS:${r.value.engine}:done
|
|
303
|
+
`);
|
|
304
|
+
} else if (r.status === "fulfilled") {
|
|
305
|
+
out[r.value.engine] = r.value;
|
|
306
|
+
stillBlocked.push(r.value.engine);
|
|
307
|
+
if (isManualVerificationError(r.value.error)) {
|
|
308
|
+
manualVerification.push(r.value.engine);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (recovered > 0) {
|
|
313
|
+
process.stderr.write(`[greedysearch] ✅ ${recovered}/${recoveryCandidates.length} engine(s) recovered — cookies cached for future headless runs.
|
|
314
|
+
`);
|
|
315
|
+
} else {
|
|
316
|
+
process.stderr.write(`[greedysearch] ⚠️ Recovery attempt did not extract an answer — ${recoveryCandidates.join(", ")} may still need manual verification or a DOM fallback.
|
|
317
|
+
`);
|
|
318
|
+
}
|
|
319
|
+
if (stillBlocked.length > 0) {
|
|
320
|
+
process.stderr.write(`[greedysearch] Second visible retry for ${stillBlocked.join(", ")} — Turnstile may have resolved on first attempt...
|
|
321
|
+
`);
|
|
322
|
+
const secondRetries = await Promise.allSettled(stillBlocked.map((e) => {
|
|
323
|
+
const idx = recoveryCandidates.indexOf(e);
|
|
324
|
+
return runExtractor(ENGINES[e], query, retryTabs[idx], short, null, locale).then((r) => ({ engine: e, ...r })).catch((err) => ({ engine: e, error: err.message }));
|
|
325
|
+
}));
|
|
326
|
+
const secondStillBlocked = [];
|
|
327
|
+
for (const r of secondRetries) {
|
|
328
|
+
if (r.status === "fulfilled" && !r.value.error) {
|
|
329
|
+
out[r.value.engine] = r.value;
|
|
330
|
+
recovered++;
|
|
331
|
+
process.stderr.write(`PROGRESS:${r.value.engine}:done
|
|
332
|
+
`);
|
|
333
|
+
process.stderr.write(`[greedysearch] ✅ ${r.value.engine} recovered on second visible retry.
|
|
334
|
+
`);
|
|
335
|
+
} else {
|
|
336
|
+
secondStillBlocked.push(r.value?.engine || "unknown");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
stillBlocked.length = 0;
|
|
340
|
+
stillBlocked.push(...secondStillBlocked);
|
|
341
|
+
}
|
|
342
|
+
logVisibleRecovery({
|
|
343
|
+
scope: "all",
|
|
344
|
+
phase: stillBlocked.length > 0 ? "needs-human" : "success",
|
|
345
|
+
engines: recoveryCandidates,
|
|
346
|
+
results: Object.fromEntries(recoveryCandidates.map((engineName) => [
|
|
347
|
+
engineName,
|
|
348
|
+
{
|
|
349
|
+
mode: out[engineName]?._envelope?.mode || null,
|
|
350
|
+
durationMs: out[engineName]?._envelope?.durationMs || null,
|
|
351
|
+
lastStage: out[engineName]?._envelope?.lastStage || null,
|
|
352
|
+
error: out[engineName]?.error || null
|
|
353
|
+
}
|
|
354
|
+
]))
|
|
355
|
+
});
|
|
356
|
+
if (stillBlocked.length > 0) {
|
|
357
|
+
for (const blockedEngine of stillBlocked) {
|
|
358
|
+
process.stderr.write(`PROGRESS:${blockedEngine}:needs-human
|
|
359
|
+
`);
|
|
360
|
+
}
|
|
361
|
+
const allPollResults = await Promise.all(stillBlocked.map(async (blockedEngine) => {
|
|
362
|
+
const tab = retryTabs[recoveryCandidates.indexOf(blockedEngine)];
|
|
363
|
+
const result = await waitForChallengeCleared({
|
|
364
|
+
tab,
|
|
365
|
+
engine: blockedEngine
|
|
366
|
+
}).catch((pollErr) => ({
|
|
367
|
+
cleared: false,
|
|
368
|
+
reason: pollErr.message || String(pollErr)
|
|
369
|
+
}));
|
|
370
|
+
return { engine: blockedEngine, tab, ...result };
|
|
371
|
+
}));
|
|
372
|
+
const clearedEngines = allPollResults.filter((p) => p.cleared);
|
|
373
|
+
if (clearedEngines.length > 0) {
|
|
374
|
+
process.stderr.write(`[greedysearch] \uD83D\uDD04 Auto-resuming ${clearedEngines.map((p) => p.engine).join(", ")} on cleared tabs...
|
|
375
|
+
`);
|
|
376
|
+
await Promise.allSettled(clearedEngines.map(async (p) => {
|
|
377
|
+
const script = ENGINES[p.engine];
|
|
378
|
+
try {
|
|
379
|
+
const result = await runExtractor(script, query, p.tab, short, null, locale);
|
|
380
|
+
out[p.engine] = result;
|
|
381
|
+
process.stderr.write(`PROGRESS:${p.engine}:done
|
|
382
|
+
`);
|
|
383
|
+
} catch (resumeErr) {
|
|
384
|
+
process.stderr.write(`[greedysearch] ⚠️ Resume extraction failed for ${p.engine}: ${resumeErr.message}
|
|
385
|
+
`);
|
|
386
|
+
}
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
const stillStillBlocked = stillBlocked.filter((e) => !clearedEngines.find((p) => p.engine === e));
|
|
390
|
+
if (stillStillBlocked.length === 0) {
|
|
391
|
+
keepVisibleForHuman = false;
|
|
392
|
+
} else {
|
|
393
|
+
keepVisibleForHuman = true;
|
|
394
|
+
out._needsHumanVerification = {
|
|
395
|
+
engines: stillStillBlocked,
|
|
396
|
+
message: "Visible Chrome is open with the engine page loaded. Solve the Turnstile checkbox or other challenge in the visible window to store cookies. Cookies persist for future runs."
|
|
397
|
+
};
|
|
398
|
+
process.stderr.write(`[greedysearch] \uD83D\uDD13 ${stillStillBlocked.join(", ")} still blocked — keeping visible Chrome open. Solve the challenge in the window to store cookies, then rerun.
|
|
399
|
+
`);
|
|
173
400
|
}
|
|
174
|
-
|
|
401
|
+
}
|
|
402
|
+
} finally {
|
|
403
|
+
if (keepVisibleForHuman) {
|
|
404
|
+
minimizeChrome().catch(() => {});
|
|
405
|
+
} else {
|
|
406
|
+
await closeTabs(retryTabs);
|
|
407
|
+
process.stderr.write(`[greedysearch] Switching back to headless Chrome...
|
|
408
|
+
`);
|
|
409
|
+
await killHeadlessChrome();
|
|
410
|
+
delete process.env.GREEDY_SEARCH_VISIBLE;
|
|
411
|
+
process.env.GREEDY_SEARCH_HEADLESS = "1";
|
|
412
|
+
await ensureChrome();
|
|
413
|
+
await cdp(["list"]);
|
|
175
414
|
}
|
|
176
415
|
}
|
|
416
|
+
engineTabs.length = 0;
|
|
177
417
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
for (var __i = 0; __i < data.length; __i += 64) {
|
|
191
|
-
data[__i] *= 0.99999;
|
|
418
|
+
for (const engineName of ALL_ENGINES) {
|
|
419
|
+
if (!out[engineName]?.error)
|
|
420
|
+
continue;
|
|
421
|
+
if (recoveryCandidates.includes(engineName)) {
|
|
422
|
+
if (process.env.GREEDY_SEARCH_VISIBLE === "1") {
|
|
423
|
+
process.stderr.write(`PROGRESS:${engineName}:${isManualVerificationError(out[engineName].error) ? "needs-human" : "error"}
|
|
424
|
+
`);
|
|
425
|
+
}
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
process.stderr.write(`PROGRESS:${engineName}:error
|
|
429
|
+
`);
|
|
192
430
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
|
|
203
|
-
} catch(_) {}
|
|
204
|
-
|
|
205
|
-
// ── screen properties ─────────────────────────────────
|
|
206
|
-
// Headless Chrome often reports an 800x600 screen even when the viewport is
|
|
207
|
-
// 1920x1080. Keep screen metrics internally consistent with our launch flags.
|
|
208
|
-
try {
|
|
209
|
-
Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
|
|
210
|
-
Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
|
|
211
|
-
Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
|
|
212
|
-
Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
|
|
213
|
-
Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
|
|
214
|
-
Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
|
|
215
|
-
} catch(_) {}
|
|
216
|
-
|
|
217
|
-
// ── navigator.userAgentData (UA Client Hints) ─────────
|
|
218
|
-
// Derive version from the UA string already set by --user-agent flag so the
|
|
219
|
-
// two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
|
|
220
|
-
try {
|
|
221
|
-
var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
|
|
222
|
-
var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
|
|
223
|
-
var _brands = [
|
|
224
|
-
{ brand: 'Not)A;Brand', version: '99' },
|
|
225
|
-
{ brand: 'Google Chrome', version: _uaMajor },
|
|
226
|
-
{ brand: 'Chromium', version: _uaMajor },
|
|
227
|
-
];
|
|
228
|
-
Object.defineProperty(navigator, 'userAgentData', {
|
|
229
|
-
get: function() {
|
|
230
|
-
return {
|
|
231
|
-
brands: _brands, mobile: false, platform: 'Windows',
|
|
232
|
-
getHighEntropyValues: function() {
|
|
233
|
-
return Promise.resolve({
|
|
234
|
-
architecture: 'x86', bitness: '64',
|
|
235
|
-
brands: _brands,
|
|
236
|
-
fullVersionList: [
|
|
237
|
-
{ brand: 'Not)A;Brand', version: '99.0.0.0' },
|
|
238
|
-
{ brand: 'Google Chrome', version: _uaFull },
|
|
239
|
-
{ brand: 'Chromium', version: _uaFull },
|
|
240
|
-
],
|
|
241
|
-
mobile: false, model: '', platform: 'Windows',
|
|
242
|
-
platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
|
|
243
|
-
});
|
|
244
|
-
},
|
|
245
|
-
toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
|
|
246
|
-
};
|
|
247
|
-
},
|
|
248
|
-
configurable: true,
|
|
249
|
-
});
|
|
250
|
-
} catch(_) {}
|
|
251
|
-
|
|
252
|
-
// ── CDP Runtime serialization guard ──────────────────
|
|
253
|
-
// Sites detect CDP by putting a getter on Error.prototype.stack
|
|
254
|
-
// and checking if console.log triggers it (only happens when
|
|
255
|
-
// Runtime domain is enabled). We monkey-patch console methods to
|
|
256
|
-
// strip custom getters from arguments before they reach CDP.
|
|
257
|
-
try {
|
|
258
|
-
var _origLog = console.log, _origError = console.error,
|
|
259
|
-
_origWarn = console.warn, _origDebug = console.debug,
|
|
260
|
-
_origInfo = console.info;
|
|
261
|
-
var _safeArg = function(a) {
|
|
262
|
-
if (a instanceof Error) {
|
|
263
|
-
try { return new Error(a.message); } catch(_) { return a; }
|
|
431
|
+
out._sources = buildSourceRegistry(out, query);
|
|
432
|
+
if (shouldFetchSources && out._sources.length > 0) {
|
|
433
|
+
process.stderr.write(`PROGRESS:source-fetch:start
|
|
434
|
+
`);
|
|
435
|
+
const fetchedSources = await fetchMultipleSources(out._sources, 5, 8000);
|
|
436
|
+
out._sources = mergeFetchDataIntoSources(out._sources, fetchedSources);
|
|
437
|
+
out._fetchedSources = writeSourcesToFiles(fetchedSources);
|
|
438
|
+
process.stderr.write(`PROGRESS:source-fetch:done
|
|
439
|
+
`);
|
|
264
440
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
441
|
+
if (shouldSynthesize) {
|
|
442
|
+
process.stderr.write(`PROGRESS:synthesis:start
|
|
443
|
+
`);
|
|
444
|
+
process.stderr.write(`[greedysearch] Synthesizing results with ${synthesizer}...
|
|
445
|
+
`);
|
|
446
|
+
let synthesisTab = null;
|
|
447
|
+
try {
|
|
448
|
+
synthesisTab = await openNewTab(getSynthesisStartUrl(synthesizer));
|
|
449
|
+
const synthesis = await synthesizeResults(query, out, {
|
|
450
|
+
grounded: groundedSynthesis,
|
|
451
|
+
tabPrefix: synthesisTab,
|
|
452
|
+
visible: process.env.GREEDY_SEARCH_VISIBLE === "1",
|
|
453
|
+
synthesizer
|
|
454
|
+
});
|
|
455
|
+
out._synthesis = {
|
|
456
|
+
...synthesis,
|
|
457
|
+
synthesized: true
|
|
458
|
+
};
|
|
459
|
+
process.stderr.write(`PROGRESS:synthesis:done
|
|
460
|
+
`);
|
|
461
|
+
} catch (e) {
|
|
462
|
+
process.stderr.write(`[greedysearch] Synthesis failed: ${e.message}
|
|
463
|
+
`);
|
|
464
|
+
out._synthesis = {
|
|
465
|
+
error: e.message,
|
|
466
|
+
synthesized: false,
|
|
467
|
+
synthesizedBy: synthesizer
|
|
468
|
+
};
|
|
469
|
+
} finally {
|
|
470
|
+
if (synthesisTab)
|
|
471
|
+
await closeTab(synthesisTab);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (fetchSource) {
|
|
475
|
+
const top = pickTopSource(out);
|
|
476
|
+
if (top)
|
|
477
|
+
out._topSource = await fetchTopSource(top.canonicalUrl || top.url);
|
|
478
|
+
}
|
|
479
|
+
if (!legacyFast)
|
|
480
|
+
out._confidence = buildConfidence(out);
|
|
481
|
+
writeOutput(out, outFile, {
|
|
482
|
+
inline,
|
|
483
|
+
synthesize: shouldSynthesize,
|
|
484
|
+
query
|
|
485
|
+
});
|
|
486
|
+
return;
|
|
487
|
+
} finally {
|
|
488
|
+
await closeTabs(engineTabs);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const script = ENGINES[engine];
|
|
492
|
+
if (!script) {
|
|
493
|
+
process.stderr.write(`Unknown engine: "${engine}"
|
|
494
|
+
Available: ${Object.keys(ENGINES).join(", ")}
|
|
495
|
+
`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
276
498
|
try {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
499
|
+
const result = await runExtractor(script, normalizeQuery(query), null, short, null, locale);
|
|
500
|
+
if (fetchSource && result.sources?.length > 0) {
|
|
501
|
+
result.topSource = await fetchTopSource(result.sources[0].url);
|
|
502
|
+
}
|
|
503
|
+
writeOutput(result, outFile, { inline, synthesize: false, query });
|
|
504
|
+
} catch (e) {
|
|
505
|
+
const recoveryEngine = script.includes("bing") ? "bing" : script.includes("perplexity") ? "perplexity" : script.includes("chatgpt") ? "chatgpt" : script.includes("semantic-scholar") ? "semantic-scholar" : script.includes("logically") ? "logically" : null;
|
|
506
|
+
const canRetryVisible = recoveryEngine && process.env.GREEDY_SEARCH_VISIBLE !== "1" && isHeadlessBlockedResult(e);
|
|
507
|
+
if (canRetryVisible) {
|
|
508
|
+
logVisibleRecovery({
|
|
509
|
+
scope: "single",
|
|
510
|
+
phase: "start",
|
|
511
|
+
engines: [recoveryEngine],
|
|
512
|
+
reasons: {
|
|
513
|
+
[recoveryEngine]: {
|
|
514
|
+
error: e.message || null,
|
|
515
|
+
envelope: e.envelope || null,
|
|
516
|
+
lastStage: e.lastStage || null
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
process.stderr.write(`[greedysearch] \uD83D\uDD13 ${recoveryEngine} blocked in headless — retrying visible to establish cookies...
|
|
521
|
+
`);
|
|
522
|
+
await killHeadlessChrome();
|
|
523
|
+
process.env.GREEDY_SEARCH_VISIBLE = "1";
|
|
524
|
+
delete process.env.GREEDY_SEARCH_HEADLESS;
|
|
525
|
+
await ensureChrome();
|
|
526
|
+
await cdp(["list"]);
|
|
527
|
+
const retryTab = await openNewTab();
|
|
528
|
+
let keepVisibleForHuman = false;
|
|
529
|
+
try {
|
|
530
|
+
const result = await runExtractor(script, query, retryTab, short, null, locale);
|
|
531
|
+
logVisibleRecovery({
|
|
532
|
+
scope: "single",
|
|
533
|
+
phase: "success",
|
|
534
|
+
engines: [recoveryEngine],
|
|
535
|
+
result: {
|
|
536
|
+
engine: recoveryEngine,
|
|
537
|
+
mode: result._envelope?.mode || null,
|
|
538
|
+
durationMs: result._envelope?.durationMs || null,
|
|
539
|
+
lastStage: result._envelope?.lastStage || null
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
if (fetchSource && result.sources?.length > 0) {
|
|
543
|
+
result.topSource = await fetchTopSource(result.sources[0].url);
|
|
544
|
+
}
|
|
545
|
+
writeOutput(result, outFile, { inline, synthesize: false, query });
|
|
546
|
+
return;
|
|
547
|
+
} catch (retryErr) {
|
|
548
|
+
logVisibleRecovery({
|
|
549
|
+
scope: "single",
|
|
550
|
+
phase: "needs-human",
|
|
551
|
+
engines: [recoveryEngine],
|
|
552
|
+
result: {
|
|
553
|
+
engine: recoveryEngine,
|
|
554
|
+
error: retryErr.message || String(retryErr),
|
|
555
|
+
envelope: retryErr.envelope || null
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
const pollResult = await waitForChallengeCleared({
|
|
559
|
+
tab: retryTab,
|
|
560
|
+
engine: recoveryEngine
|
|
561
|
+
}).catch((pollErr) => ({
|
|
562
|
+
cleared: false,
|
|
563
|
+
reason: pollErr.message || String(pollErr)
|
|
564
|
+
}));
|
|
565
|
+
if (pollResult.cleared) {
|
|
566
|
+
process.stderr.write(`[greedysearch] \uD83D\uDD04 Auto-resuming ${recoveryEngine} extraction on the now-cleared tab...
|
|
567
|
+
`);
|
|
568
|
+
try {
|
|
569
|
+
const result = await runExtractor(script, query, retryTab, short, null, locale);
|
|
570
|
+
logVisibleRecovery({
|
|
571
|
+
scope: "single",
|
|
572
|
+
phase: "success-after-poll",
|
|
573
|
+
engines: [recoveryEngine],
|
|
574
|
+
result: {
|
|
575
|
+
engine: recoveryEngine,
|
|
576
|
+
mode: result._envelope?.mode || null,
|
|
577
|
+
durationMs: result._envelope?.durationMs || null,
|
|
578
|
+
lastStage: result._envelope?.lastStage || null
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
if (fetchSource && result.sources?.length > 0) {
|
|
582
|
+
result.topSource = await fetchTopSource(result.sources[0].url);
|
|
583
|
+
}
|
|
584
|
+
writeOutput(result, outFile, { inline, synthesize: false, query });
|
|
585
|
+
return;
|
|
586
|
+
} catch (resumeErr) {
|
|
587
|
+
process.stderr.write(`[greedysearch] ⚠️ Resume extraction failed: ${resumeErr.message}
|
|
588
|
+
`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
keepVisibleForHuman = true;
|
|
592
|
+
writeOutput({
|
|
593
|
+
query,
|
|
594
|
+
error: retryErr.message,
|
|
595
|
+
_needsHumanVerification: {
|
|
596
|
+
engines: [recoveryEngine],
|
|
597
|
+
message: "Visible Chrome is open with the engine page loaded. Solve the Turnstile checkbox or other challenge to store cookies. Cookies persist for future runs."
|
|
598
|
+
}
|
|
599
|
+
}, outFile, { inline, synthesize: false, query });
|
|
600
|
+
return;
|
|
601
|
+
} finally {
|
|
602
|
+
if (!keepVisibleForHuman) {
|
|
603
|
+
await closeTab(retryTab);
|
|
604
|
+
await killHeadlessChrome();
|
|
605
|
+
delete process.env.GREEDY_SEARCH_VISIBLE;
|
|
606
|
+
process.env.GREEDY_SEARCH_HEADLESS = "1";
|
|
607
|
+
} else {
|
|
608
|
+
minimizeChrome().catch(() => {});
|
|
609
|
+
}
|
|
282
610
|
}
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
`;if(H)M+=H.slice(0,6000);else M+=`[No README found]
|
|
310
|
-
|
|
311
|
-
Files:
|
|
312
|
-
${B.map((D)=>` ${D.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${D.path}`).join(`
|
|
313
|
-
`)}`;return{ok:!0,title:`${X}/${J}`,content:M,tree:B.slice(0,30)}}if(W==="blob"&&V){let j;if(!K||K==="HEAD")try{j=(await N0(`/repos/${X}/${J}`)).default_branch}catch{j=void 0}let Y=await C6(X,J,K,V,1e4,j);if(Y===null)return{ok:!1,error:`File not found: ${V}`};return{ok:!0,title:`${X}/${J}: ${V}`,content:Y}}if(W==="tree"&&V){let j;if(!K||K==="HEAD")try{j=(await N0(`/repos/${X}/${J}`)).default_branch}catch{j=void 0}let Y=await C2(X,J,K||"HEAD",V,j),Q=Y.map((H)=>` ${H.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${H.path}`).join(`
|
|
314
|
-
`);return{ok:!0,title:`${X}/${J}/${V}`,content:`[Directory: ${V}]
|
|
315
|
-
|
|
316
|
-
Files:
|
|
317
|
-
${Q}`,tree:Y}}return{ok:!1,error:"Unsupported GitHub URL type"}}catch(j){return{ok:!1,error:j.message}}}var R2;var z$=X0(()=>{R2={"user-agent":"GreedySearch/1.0",accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});function E2($){try{let Z=new URL($),X=Z.hostname.toLowerCase();if(!(X==="reddit.com"||X.endsWith(".reddit.com")))return null;let J=Z.pathname;if(J.match(/^\/(u|user)\/[^/]+\/?$/i))return{type:"user",cleanUrl:I2($)};if(J.match(/^\/r\/[^/]+\/comments\/[^/]+/i))return{type:"post",cleanUrl:I2($)};return null}catch{return null}}function I2($){try{let Z=new URL($);return`${Z.protocol}//${Z.hostname}${Z.pathname}`}catch{return $}}async function q2($,Z=8000){let X=Date.now();try{let J=$.replace(/\/+$/,"")+".json",W=new AbortController,K=setTimeout(()=>W.abort(),15000),V=await fetch(J,{headers:R6,signal:W.signal});if(clearTimeout(K),!V.ok)throw Error(`Reddit API ${V.status}`);let j=await V.json();if(!Array.isArray(j)||j.length<1)throw Error("Invalid Reddit API response structure");let Y=j[0],Q=j[1],H=Y?.data?.children?.[0]?.data;if(!H)throw Error("No post data in Reddit response");let B=v6(H,Q,Z);return{ok:!0,url:$,finalUrl:$,status:200,contentType:"text/markdown",lastModified:"",title:H.title||"Reddit Post",byline:`u/${H.author}`,siteName:`r/${H.subreddit}`,lang:"en",publishedTime:new Date(H.created_utc*1000).toISOString(),excerpt:H.selftext?.slice(0,300).replace(/\n/g," ")||"",markdown:B,contentLength:B.length,needsBrowser:!1,duration:Date.now()-X}}catch(J){return{ok:!1,url:$,finalUrl:$,status:0,error:`Reddit fetch failed: ${J.message}`,needsBrowser:!1,duration:Date.now()-X}}}function v6($,Z,X){let J="";if(J+=`# ${$.title}
|
|
318
|
-
|
|
319
|
-
`,J+=`**Subreddit:** r/${$.subreddit} | **Author:** u/${$.author} | **Score:** ${$.score}
|
|
320
|
-
|
|
321
|
-
`,$.selftext)J+=$.selftext,J+=`
|
|
322
|
-
|
|
323
|
-
`;else if($.url)try{let W=new URL($.url).hostname.toLowerCase();if(W!=="reddit.com"&&!W.endsWith(".reddit.com"))J+=`**Link:** ${$.url}
|
|
324
|
-
|
|
325
|
-
`}catch{J+=`**Link:** ${$.url}
|
|
326
|
-
|
|
327
|
-
`}if(Z?.data?.children?.length>0){J+=`---
|
|
328
|
-
|
|
329
|
-
## Comments
|
|
330
|
-
|
|
331
|
-
`;let W=Z.data.children.filter((K)=>K.kind==="t1").slice(0,10);for(let K of W)J+=f2(K.data,0),J+=`
|
|
332
|
-
`}if(J.length>X)J=J.slice(0,X).trim()+`
|
|
333
|
-
|
|
334
|
-
... (truncated)`;return J}function f2($,Z){if(!$||$.body==="[deleted]"||$.body==="[removed]")return"";let X="> ".repeat(Z),J="";if(J+=`${X}**u/${$.author}** (${$.score} pts)
|
|
335
|
-
`,J+=`${X}${$.body.replaceAll(`
|
|
336
|
-
`,`
|
|
337
|
-
`+X)}
|
|
338
|
-
`,Z<3&&$.replies?.data?.children){let W=$.replies.data.children.filter((K)=>K.kind==="t1");for(let K of W.slice(0,5))J+=`
|
|
339
|
-
`+f2(K.data,Z+1)}return J}var R6;var b2=X0(()=>{R6={"user-agent":"GreedySearch/1.0 (Research Bot)",accept:"application/json"}});function u0($,Z=8000){if(!$||$.length<=Z)return $;let X=`
|
|
340
|
-
|
|
341
|
-
[...content trimmed...]
|
|
342
|
-
|
|
343
|
-
`,J=Z-X.length,W=Math.floor(J*0.75),K=J-W,V=W;while(V>W-100&&$[V]!==`
|
|
344
|
-
`)V--;if(V<=W-100)V=W;let j=$.length-K;while(j<$.length-K+100&&$[j]!==`
|
|
345
|
-
`)j++;if(j>=$.length-K+100)j=$.length-K;let Y=$.slice(0,V).trimEnd(),Q=$.slice(j).trimStart();return`${Y}${X}${Q}`}function I6(){if(typeof globalThis.DOMMatrix>"u")globalThis.DOMMatrix=class{constructor(Z=void 0){}multiplySelf(){return this}preMultiplySelf(){return this}translateSelf(){return this}scaleSelf(){return this}rotateSelf(){return this}};if(typeof globalThis.ImageData>"u")globalThis.ImageData=class{constructor(Z=void 0,X=0,J=0){this.data=Z,this.width=X,this.height=J}};if(typeof globalThis.Path2D>"u")globalThis.Path2D=class{constructor(Z=void 0){}}}async function E6(){I6();let $=await import("pdf-parse"),Z=$.PDFParse??$.default;if(!Z)throw Error("pdf-parse did not export PDFParse");return Z}async function x2($,Z){try{let J=new(await E6())({data:new Uint8Array($)});await J.load();let W=await J.getText(),K=W.text?.trim();if(!K)return null;return{title:new URL(Z).pathname.split("/").pop()||"Document.pdf",content:`## PDF Content (${W.total} pages)
|
|
346
|
-
|
|
347
|
-
${K}`,pages:W.total}}catch(X){return{error:X.message||String(X)}}}function R($="",Z=240){let X=String($).replaceAll(/\s+/g," ").trim();if(X.length<=Z)return X;let J=X.slice(0,Z),W=J.lastIndexOf(" ");return W>0?`${J.slice(0,W)}...`:`${J}...`}function F$($=""){let Z=R($,180);if(!Z)return"";if(/^https?:\/\//i.test(Z))return"";let X=Z.split(/\s+/).filter(Boolean).length,J=/[A-Z]/.test(Z),W=/\d/.test(Z);return Z===Z.toLowerCase()&&X<=4&&!J&&!W?"":Z}function w$($="",Z=""){let X=F$($),J=F$(Z);if(!J)return X;if(!X)return J;let W=/^https?:\/\//i.test(X),K=/^https?:\/\//i.test(J);if(W&&!K)return J;if(!W&&K)return X;return J.length>X.length?J:X}function e($){if(!$)return null;try{let Z=new URL($);if(!["http:","https:"].includes(Z.protocol))return null;if(Z.hash="",Z.hostname=Z.hostname.toLowerCase(),Z.protocol==="https:"&&Z.port==="443"||Z.protocol==="http:"&&Z.port==="80")Z.port="";for(let W of[...Z.searchParams.keys()]){let K=W.toLowerCase();if(q6.includes(K)||K.startsWith("utm_"))Z.searchParams.delete(W)}Z.searchParams.sort();let X=Z.pathname.replace(/\/{1,10}$/,"")||"/";Z.pathname=X;let J=Z.toString();return X==="/"?J.replace(/\/$/,""):J}catch{return null}}function x6($){try{return new URL($).hostname.toLowerCase().replace(/^www\./,"")}catch{return""}}function O1($,Z){return Z.some((X)=>$===X||$.endsWith(`.${X}`))}function P$($,Z="",X=""){let J=Z.toLowerCase(),W=X.toLowerCase();if($==="github.com"||$==="gitlab.com")return"repo";if($==="arxiv.org"||$==="doi.org"||$==="semanticscholar.org"||$.endsWith(".semanticscholar.org")||W.includes("/paper/")||W.includes("/pdf/"))return"academic";if(O1($,g2))return"social";if(O1($,f6))return"community";if(O1($,b6))return"news";if($.startsWith("docs.")||$.startsWith("developer.")||$.startsWith("developers.")||$.startsWith("api.")||J.includes("documentation")||J.includes("docs")||J.includes("reference")||W.includes("/docs/")||W.includes("/reference/")||W.includes("/api/"))return"official-docs";if($.startsWith("blog.")||W.includes("/blog/"))return"maintainer-blog";return"website"}function S6($){switch($){case"official-docs":return 5;case"repo":return 4;case"academic":return 4;case"maintainer-blog":return 3;case"website":return 2;case"community":return 1;case"news":return 0;case"social":return-6;default:return 0}}function g6($){let Z=Object.values($.perEngine||{}).map((X)=>X?.rank||99);return Z.length?Math.min(...Z):99}function c0($){return $.smartScore*3+$.engineCount*5+S6($.sourceType)*2+Math.max(0,7-g6($))}function h6($){let Z=$.toLowerCase(),X=[];if(Z.includes("openai")||Z.includes("gpt")||Z.includes("chatgpt"))X.push("openai.com","platform.openai.com","help.openai.com");if(Z.includes("anthropic")||Z.includes("claude"))X.push("anthropic.com","docs.anthropic.com");if(Z.includes("bun"))X.push("bun.sh","bun.com");if(Z.includes("next.js")||Z.includes("nextjs"))X.push("nextjs.org","vercel.com");if(Z.includes("playwright"))X.push("playwright.dev");if(Z.includes("supabase"))X.push("supabase.com","supabase.io");if(Z.includes("prisma"))X.push("prisma.io");if(Z.includes("tailwind"))X.push("tailwindcss.com");if(Z.includes("vite"))X.push("vitejs.dev","vite.dev");if(Z.includes("astro"))X.push("astro.build");if(Z.includes("svelte"))X.push("svelte.dev");if(Z.includes("solid"))X.push("solidjs.com");if(Z.includes("vue")||Z.includes("nuxt"))X.push("vuejs.org","nuxt.com");if(Z.includes("react")||Z.includes("react native"))X.push("react.dev","reactnative.dev");if(Z.includes("angular"))X.push("angular.io","angular.dev");if(Z.includes("node.js")||Z.includes("nodejs"))X.push("nodejs.org","nodejs.dev","npmjs.com");if(/\bgo\b/.test(Z)||Z.includes("golang"))X.push("go.dev","golang.org","pkg.go.dev");if(Z.includes("deno"))X.push("deno.land","deno.com");if(Z.includes("fresh"))X.push("fresh.deno.dev");if(Z.includes("typescript")||Z.includes("ts"))X.push("typescriptlang.org");if(Z.includes("python"))X.push("python.org","docs.python.org");if(Z.includes("rust"))X.push("rust-lang.org","docs.rs","crates.io");if(Z.includes("zig"))X.push("ziglang.org");if(Z.includes("docker"))X.push("docker.com","docs.docker.com","hub.docker.com");if(Z.includes("kubernetes")||Z.includes("k8s"))X.push("kubernetes.io","k8s.io");if(Z.includes("postgres")||Z.includes("postgresql"))X.push("postgresql.org","neon.tech","supabase.com");if(Z.includes("redis"))X.push("redis.io");if(Z.includes("sqlite"))X.push("sqlite.org");if(Z.includes("cloudflare"))X.push("developers.cloudflare.com","cloudflare.com");if(Z.includes("vercel"))X.push("vercel.com","nextjs.org");if(Z.includes("netlify"))X.push("netlify.com","docs.netlify.com");if(Z.includes("stripe"))X.push("stripe.com","docs.stripe.com");if(Z.includes("github"))X.push("github.com","docs.github.com");if(Z.includes("gitlab"))X.push("gitlab.com","docs.gitlab.com");if(Z.includes("aws"))X.push("aws.amazon.com","docs.aws.amazon.com");if(Z.includes("azure"))X.push("azure.microsoft.com","learn.microsoft.com");if(Z.includes("gcp")||Z.includes("google cloud"))X.push("cloud.google.com","developers.google.com");if(Z.includes("gemini")||Z.includes("google ai"))X.push("ai.google.dev","developers.google.com");for(let J of g2){let W=J.replace(/\.com$/,"");if(Z.includes(W))X.push(J)}return[...new Set(X)]}function S2($,Z){return $===Z||$.endsWith(`.${Z}`)}function f0($,Z=""){let X=new Map,J=Object.keys($||{}).filter((Q)=>!Q.startsWith("_")),W=h6(Z);for(let Q of J){let H=$[Q];if(!H?.sources)continue;for(let B=0;B<H.sources.length;B++){let N=H.sources[B],G=e(N.url);if(!G||G.length<10)continue;let O=F$(N.title||""),M=x6(G),D=P$(M,O,G),z=0;if(W.some((g)=>S2(M,g)))z+=10;if(D==="official-docs")z+=3;let F=G.toLowerCase();if(/\/docs\/|\/documentation\/|\.dev\/|\/api\/|\/reference\//.test(F))z+=2;let P=W.some((g)=>S2(M,g));if(D==="social"&&!P)z-=20;if(W.length>0){if(O1(M,y6))z-=3;else if(D==="community"&&!O1(M,["stackoverflow.com","stackexchange.com"]))z-=1}let w=X.get(G)||{id:"",canonicalUrl:G,displayUrl:N.url||G,domain:M,title:"",engines:[],engineCount:0,perEngine:{},sourceType:D,isOfficial:D==="official-docs",smartScore:0};if(w.title=w$(w.title,O),w.displayUrl=w.displayUrl||N.url||G,w.sourceType=w.sourceType||D,w.isOfficial=w.isOfficial||D==="official-docs",w.smartScore=Math.max(w.smartScore,z),!w.engines.includes(Q))w.engines.push(Q);w.perEngine[Q]={rank:B+1,title:w$(w.perEngine[Q]?.title||"",O)},X.set(G,w)}}let K=Array.from(X.values()).map((Q)=>({...Q,engineCount:Q.engines.length})),V=K.filter((Q)=>Q.sourceType!=="social"),j=K.filter((Q)=>Q.sourceType==="social");return V.sort((Q,H)=>{let B=c0(H)-c0(Q);if(B!==0)return B;return Q.domain.localeCompare(H.domain)}),j.sort((Q,H)=>{let B=c0(H)-c0(Q);if(B!==0)return B;return Q.domain.localeCompare(H.domain)}),[...V,...j].slice(0,12).map((Q,H)=>({...Q,id:`S${H+1}`,title:Q.title||Q.domain||Q.canonicalUrl}))}function r0($,Z){let X=new Map(Z.map((J)=>[J.id,J]));return $.map((J)=>{let W=X.get(J.id);if(!W)return J;let K=w$(J.title,W.title||"");return{...J,title:K||J.title,fetch:{attempted:!0,ok:!W.error&&W.contentChars>100,status:W.status||null,finalUrl:W.finalUrl||W.url||J.canonicalUrl,contentType:W.contentType||"",lastModified:W.lastModified||"",publishedTime:W.publishedTime||"",byline:W.byline||"",siteName:W.siteName||"",lang:W.lang||"",title:W.title||"",snippet:W.snippet||"",contentChars:W.contentChars||0,source:W.source||"unknown",duration:W.duration||0,error:W.error||""}}})}var q6,f6,b6,g2,y6;var b0=X0(()=>{q6=["fbclid","gclid","ref","ref_src","ref_url","source","utm_campaign","utm_content","utm_medium","utm_source","utm_term"],f6=["dev.to","hashnode.com","medium.com","reddit.com","stackoverflow.com","stackexchange.com","substack.com"],b6=["arstechnica.com","techcrunch.com","theverge.com","venturebeat.com","wired.com","zdnet.com"],g2=["facebook.com","instagram.com","linkedin.com","pinterest.com","tiktok.com","twitter.com","x.com"];y6=["reddit.com","news.ycombinator.com","lobste.rs"]});var _$={};r1(_$,{fetchTopSource:()=>e0,fetchSourceContent:()=>h2,fetchMultipleSources:()=>M1});async function p6($,Z,X=8000){let J=Date.now();try{let K=(await y(["evalraw",$,"Page.getFrameTree","{}"]).then((O)=>JSON.parse(O)).catch(()=>null))?.frameTree?.frame?.id||void 0,V=await y(["evalraw",$,"Network.loadNetworkResource",JSON.stringify({frameId:K,url:Z,options:{disableCache:!0,includeCredentials:!1}})],20000),Y=JSON.parse(V).resource;if(!Y?.success||!Y.httpStatusCode)return{url:Z,error:Y?.netErrorName||Y?.netError||"loadNetworkResource failed",source:"chrome",duration:Date.now()-J,needsFallback:!0};let Q="";if(Y.stream)try{let O=await y(["evalraw",$,"IO.read",JSON.stringify({handle:Y.stream})],1e4);Q=JSON.parse(O).data||"",await y(["evalraw",$,"IO.close",JSON.stringify({handle:Y.stream})]).catch(()=>{})}catch{}if(!Q||Q.length<100)return{url:Z,error:"Empty response body from Network.loadNetworkResource",source:"chrome",duration:Date.now()-J,needsFallback:!0};let H=N$(Y.httpStatusCode,Q,Z,Z);if(H.blocked)return{url:Z,status:Y.httpStatusCode,error:`Blocked: ${H.reason}`,source:"chrome",duration:Date.now()-J,needsBrowser:!0};let B=await O$(Q,Z),N=M$(B);if(!N.ok)return{url:Z,status:Y.httpStatusCode,error:`Low quality: ${N.reason}`,source:"chrome",duration:Date.now()-J,needsBrowser:!0};let G=u0(B.markdown,X);return{url:Z,finalUrl:Z,status:Y.httpStatusCode,contentType:"text/markdown",lastModified:"",publishedTime:B.publishedTime||"",byline:B.byline||"",siteName:B.siteName||"",lang:B.lang||"",title:B.title||Z,snippet:B.excerpt,content:G,contentChars:G.length,source:"chrome",duration:Date.now()-J}}catch(W){return{url:Z,error:W.message,source:"chrome",duration:Date.now()-J,needsFallback:!0}}}function y2($){try{return new URL($).pathname.toLowerCase().endsWith(".pdf")}catch{return!1}}async function m6($,Z=8000){let X=p1($);if(X.blocked)return{url:$,finalUrl:$,status:403,error:`Blocked: ${X.reason}`,source:"pdf-http"};let J=new AbortController,W=setTimeout(()=>J.abort(),20000),K=Date.now();try{let V=await fetch($,{method:"GET",redirect:"follow",signal:J.signal,headers:L2({accept:"application/pdf,application/octet-stream;q=0.9,*/*;q=0.5"})});clearTimeout(W);let j=V.headers.get("content-type")||"",Y=V.url||$,Q=Number.parseInt(V.headers.get("content-length")||"0",10);if(V.status>=400)return{url:$,finalUrl:Y,status:V.status,error:`HTTP ${V.status}`,source:"pdf-http",duration:Date.now()-K};if(!j.toLowerCase().includes("application/pdf")&&!y2(Y))return null;if(Q>31457280)return{url:$,finalUrl:Y,status:V.status,error:`PDF too large: ${Q} bytes`,source:"pdf-http",duration:Date.now()-K};let H=Buffer.from(await V.arrayBuffer()),B=await x2(H,Y);if(!B||B.error)return{url:$,finalUrl:Y,status:V.status,error:B?.error||"PDF text extraction failed",source:"pdf-http",duration:Date.now()-K};let N=u0(B.content,Z);return{url:$,finalUrl:Y,status:V.status,contentType:"application/pdf",lastModified:V.headers.get("last-modified")||"",title:B.title,snippet:R(N,320),content:N,contentChars:N.length,pages:B.pages,source:"pdf-http",duration:Date.now()-K}}catch(V){return clearTimeout(W),{url:$,finalUrl:$,error:V.message||String(V),source:"pdf-http",duration:Date.now()-K}}}async function h2($,Z=8000){let X=Date.now();if(y2($)){let K=await m6($,Z);if(K?.content||K?.status===403)return K}if(N1($)){let K=N1($);if(K&&(K.type==="root"||K.type==="tree"||K.type==="blob"&&!K.path?.includes("."))){let V=await D$($);if(V.ok){let j=u0(V.content,Z);return{url:$,finalUrl:$,status:200,contentType:"text/markdown",lastModified:"",title:V.title,snippet:j.slice(0,320),content:j,contentChars:j.length,source:"github-api",...V.tree&&{tree:V.tree},duration:Date.now()-X}}process.stderr.write(`[greedysearch] GitHub API fetch failed, trying HTTP: ${V.error}
|
|
348
|
-
`)}}if(E2($)?.type==="post"){process.stderr.write(`[greedysearch] Using Reddit JSON API for: ${$.slice(0,60)}...
|
|
349
|
-
`);let K=await q2($,Z);if(K.ok){let V=u0(K.markdown,Z);return{url:$,finalUrl:K.finalUrl,status:K.status,contentType:"text/markdown",lastModified:K.lastModified||"",publishedTime:K.publishedTime||"",byline:K.byline||"",siteName:K.siteName||"",lang:K.lang||"",title:K.title,snippet:K.excerpt,content:V,contentChars:V.length,source:"reddit-api",duration:Date.now()-X}}process.stderr.write(`[greedysearch] Reddit API fetch failed, falling back to HTTP: ${K.error}
|
|
350
|
-
`)}let W=await A2($,{timeoutMs:1e4});if(W.ok){let K=u0(W.markdown,Z);return{url:$,finalUrl:W.finalUrl,status:W.status,contentType:"text/markdown",lastModified:W.lastModified||"",publishedTime:W.publishedTime||"",byline:W.byline||"",siteName:W.siteName||"",lang:W.lang||"",title:W.title,snippet:W.excerpt,content:K,contentChars:K.length,source:"http",duration:Date.now()-X}}if(W.needsBrowser)try{let K=await C0();try{let V=await p6(K,$,Z);if(V.content&&V.content.length>100)return V}finally{await E0(K)}}catch{}return process.stderr.write(`[greedysearch] HTTP failed for ${$.slice(0,60)}, trying browser...
|
|
351
|
-
`),await d6($,Z)}async function p2($,Z=4000,X=200){let J=Date.now()+Z;while(Date.now()<J){try{if((await y(["eval",$,'document.readyState === "complete" && !!document.body && document.body.innerText.length > 500'])).trim()==="true")return}catch{}await new Promise((W)=>setTimeout(W,X))}}async function d6($,Z=8000){let X=Date.now(),J;try{J=await C0()}catch(W){return{url:$,title:"",content:null,snippet:"",contentChars:0,error:`openNewTab failed: ${W.message}`,source:"browser",duration:Date.now()-X}}try{await y(["nav",J,$],30000),await p2(J);let W=await y(["eval",J,String.raw`
|
|
352
|
-
(function(){
|
|
353
|
-
var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
|
|
354
|
-
var text = (el || document.body).innerText;
|
|
355
|
-
return JSON.stringify({
|
|
356
|
-
title: document.title,
|
|
357
|
-
content: text.replace(/\s+/g, ' ').trim(),
|
|
358
|
-
url: location.href
|
|
359
|
-
});
|
|
360
|
-
})()
|
|
361
|
-
`]),K=JSON.parse(W),V=u0(K.content,Z);return{url:$,finalUrl:K.url||$,status:200,contentType:"text/plain",lastModified:"",title:K.title,snippet:R(V,320),content:V,contentChars:V.length,source:"browser",duration:Date.now()-X}}catch(W){return{url:$,title:"",content:null,snippet:"",contentChars:0,error:W.message,source:"browser",duration:Date.now()-X}}finally{await E0(J)}}async function M1($,Z=5,X=8000,J=j$){let W=$.slice(0,Z);if(W.length===0)return[];let K=Math.min(W.length,Math.max(1,Number.parseInt(String(J),10)||j$));process.stderr.write(`[greedysearch] Fetching content from ${W.length} sources via HTTP (concurrency ${K})...
|
|
362
|
-
`);let V=Array(W.length),j=0,Y=0;async function Q(){while(!0){let G=j++;if(G>=W.length)return;let O=W[G],M=O.canonicalUrl||O.url;process.stderr.write(`[greedysearch] [${G+1}/${W.length}] Fetching: ${M.slice(0,60)}...
|
|
363
|
-
`);let D=await h2(M,X).catch((z)=>({url:M,title:"",content:null,snippet:"",contentChars:0,error:z.message,source:"error",duration:0}));if(V[G]={id:O.id,...D},D.content&&D.content.length>100)process.stderr.write(`[greedysearch] ✓ ${D.source}: ${D.content.length} chars
|
|
364
|
-
`);else if(D.error)process.stderr.write(`[greedysearch] ✗ ${D.error.slice(0,80)}
|
|
365
|
-
`);Y+=1,process.stderr.write(`PROGRESS:fetch:${Y}/${W.length}
|
|
366
|
-
`)}}await Promise.all(Array.from({length:K},()=>Q()));let H=V.filter((G)=>G.content&&G.content.length>100),B=V.filter((G)=>G.source==="http").length,N=V.filter((G)=>G.source==="browser").length;return process.stderr.write(`[greedysearch] Fetched ${H.length}/${V.length} sources (HTTP: ${B}, Browser: ${N})
|
|
367
|
-
`),V}async function e0($){let Z=await C0();try{await y(["nav",Z,$],30000),await p2(Z);let X=await y(["eval",Z,String.raw`
|
|
368
|
-
(function(){
|
|
369
|
-
var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
|
|
370
|
-
var text = (el || document.body).innerText;
|
|
371
|
-
return text.replace(/\s+/g, ' ').trim();
|
|
372
|
-
})()
|
|
373
|
-
`]);return{url:$,content:X}}catch(X){return{url:$,content:null,error:X.message}}finally{await E0(Z)}}var D1=X0(()=>{T2();z$();b2();G$();M0();b0()});var l2={};r1(l2,{writeSourcesToFiles:()=>$1});import{mkdirSync as n6,writeFileSync as i6}from"node:fs";import{join as d2}from"node:path";function $1($,Z=a6){return n6(Z,{recursive:!0}),$.map((X)=>{if(!X.content||X.content.length<10)return X;let J=String(X.id||"unknown").replace(/[^a-zA-Z0-9_-]/g,""),W=(X.canonicalUrl||X.url||"").replace(/^https?:\/\//,"").replace(/[^a-zA-Z0-9]/g,"-").slice(0,40),K=`${J}-${W}.md`,V=d2(Z,K),j=`---
|
|
374
|
-
url: ${X.finalUrl||X.url}
|
|
375
|
-
title: ${X.title||""}
|
|
376
|
-
source: ${X.source||"unknown"}
|
|
377
|
-
status: ${X.status||""}
|
|
378
|
-
chars: ${X.contentChars||X.content.length}
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
`;i6(V,j+X.content,"utf8");let{content:Y,...Q}=X;return{...Q,contentPath:V,contentChars:X.contentChars||Y.length}})}var a6;var m1=X0(()=>{a6=d2(process.cwd(),".dm","greedysearch-sources")});G$();M0();import{appendFileSync as z9,existsSync as U9,readFileSync as F9}from"node:fs";import{homedir as w9}from"node:os";import{join as a1}from"node:path";g0();M0();W1();import{spawn as G6}from"node:child_process";var N6=v0(import.meta.url);function q0($,Z,X=null,J=!1,W=null,K=null){if(W===null)W=$.includes("logically")?120000:$.includes("chatgpt")?80000:$.includes("gemini")?70000:60000;let V=[...X?["--tab",X]:[],...J?["--short"]:[],...K?["--locale",K]:[]];return new Promise((j,Y)=>{let Q=s0($,{moduleDir:N6}),H=G6(Q0(),[Q,"--stdin",...V],{stdio:["pipe","pipe","pipe"],env:{...process.env,CDP_PROFILE_DIR:u}});H.stdin.write(Z),H.stdin.end();let B="",N="";H.stdout.on("data",(O)=>B+=O),H.stderr.on("data",(O)=>{if(N+=O,process.env.GREEDY_SEARCH_CHILD_STDERR!=="0")process.stderr.write(O)});let G=setTimeout(()=>{H.kill();let O=(z,F=20)=>String(z??"").split(/\r?\n/).filter(Boolean).slice(-F).join(`
|
|
382
|
-
`),M=null;try{let z=JSON.parse(B.trim());if(z._envelope)M=z._envelope}catch{}let D=Error(`${$} timed out after ${W/1000}s`+(M?.lastStage?` (last stage: ${M.lastStage})`:""));D.engineScript=$,D.lastStage=M?.lastStage||null,D.partialErr=O(N),D.partialOut=O(B),Y(D)},W);H.on("close",(O)=>{if(clearTimeout(G),O===0)try{j(JSON.parse(B.trim()))}catch{Y(Error(`bad JSON from ${$}: ${B.slice(0,100)}`))}else{let M=null;try{let F=JSON.parse(B.trim());if(F._envelope)M=F._envelope}catch{}let D=N.trim()||`extractor exit ${O}`,z=Error(D);if(M)z.envelope=M;Y(z)}})})}D1();$$();var l6=Number.parseInt(process.env.GREEDY_SEARCH_CHALLENGE_WAIT_MS||"300000",10),u6=3000,m2={chatgpt:{name:"chatgpt",isCleared:async($)=>{let Z=await y0(["eval",$,`(() => {
|
|
383
|
-
const title = document.title;
|
|
384
|
-
const onChatGPT = location.hostname === "chatgpt.com";
|
|
385
|
-
const hasProseMirror = !!document.querySelector("div.ProseMirror");
|
|
386
|
-
const hasTurnstileInput =
|
|
387
|
-
!!document.querySelector("input[name=\\"cf-turnstile-response\\"]") ||
|
|
388
|
-
!!document.querySelector("iframe[id^=\\"cf-chl-widget-\\"]");
|
|
389
|
-
// Body innerText is empty while on the Turnstile page.
|
|
390
|
-
const bodyText = (document.body && document.body.innerText) || "";
|
|
391
|
-
return JSON.stringify({
|
|
392
|
-
title,
|
|
393
|
-
url: location.href,
|
|
394
|
-
hasProseMirror,
|
|
395
|
-
hasTurnstileInput,
|
|
396
|
-
bodyLen: bodyText.length,
|
|
397
|
-
onChatGPT,
|
|
398
|
-
});
|
|
399
|
-
})()`]).catch(()=>null);if(!Z)return!1;let X;try{X=JSON.parse(Z)}catch{return!1}if(!X.onChatGPT)return!1;if(X.title&&/περιμένετε|please wait|just a moment|verifying|checking/i.test(X.title))return!1;if(X.hasTurnstileInput)return!1;return X.hasProseMirror||X.bodyLen>50}},bing:{name:"bing",isCleared:async($)=>{let Z=await y0(["eval",$,`(() => {
|
|
400
|
-
const url = location.href;
|
|
401
|
-
const title = document.title;
|
|
402
|
-
const onCopilot = /copilot\\.microsoft\\.com/.test(location.hostname);
|
|
403
|
-
const onChallenge =
|
|
404
|
-
/challenge|turnstile|cdn-cgi\\/challenge/i.test(url) ||
|
|
405
|
-
/verify|human|robot/i.test(title);
|
|
406
|
-
const hasTextarea =
|
|
407
|
-
!!document.querySelector("textarea") ||
|
|
408
|
-
!!document.querySelector("div[contenteditable=\\"true\\"]");
|
|
409
|
-
const hasTurnstileInput =
|
|
410
|
-
!!document.querySelector("iframe[id^=\\"cf-chl-widget-\\"]") ||
|
|
411
|
-
!!document.querySelector("input[name=\\"cf-turnstile-response\\"]");
|
|
412
|
-
const bodyText = (document.body && document.body.innerText) || "";
|
|
413
|
-
return JSON.stringify({
|
|
414
|
-
url,
|
|
415
|
-
title,
|
|
416
|
-
onCopilot,
|
|
417
|
-
onChallenge,
|
|
418
|
-
hasTextarea,
|
|
419
|
-
hasTurnstileInput,
|
|
420
|
-
bodyLen: bodyText.length,
|
|
421
|
-
});
|
|
422
|
-
})()`]).catch(()=>null);if(!Z)return!1;let X;try{X=JSON.parse(Z)}catch{return!1}if(!X.onCopilot)return!1;if(X.onChallenge)return!1;if(X.hasTurnstileInput)return!1;return X.hasTextarea||X.bodyLen>50}}};async function c6($){let Z=await y0(["eval",$,`(() => {
|
|
423
|
-
const cookies = document.cookie || "";
|
|
424
|
-
return JSON.stringify({
|
|
425
|
-
hasCfClearance: /(?:^|;\\s*)cf_clearance=/.test(cookies),
|
|
426
|
-
hasCfBm: /(?:^|;\\s*)__cf_bm=/.test(cookies),
|
|
427
|
-
cookiesLength: cookies.length,
|
|
428
|
-
});
|
|
429
|
-
})()`]).catch(()=>null);if(!Z)return!1;try{let X=JSON.parse(Z);return X.hasCfClearance||X.hasCfBm}catch{return!1}}async function k$({tab:$,engine:Z,timeoutMs:X=l6,intervalMs:J=u6,signal:W,log:K=()=>{}}){let V=m2[Z],j=Date.now(),Y=null;while(Date.now()-j<X){if(W?.aborted)return{cleared:!1,reason:"aborted"};let Q=Math.floor((Date.now()-j)/1000),H=!1;if(V)H=await V.isCleared($).catch(()=>!1);else H=await c6($).catch(()=>!1);if(H)return K(`[greedysearch] ✅ ${Z} challenge cleared after ${Q}s — auto-resuming extraction.`),{cleared:!0,signal:V?"dom-marker":"cookie"};if(Q>0&&Q%30===0&&Y!==Q)Y=Q,K(`[greedysearch] ⏳ Waiting for ${Z} challenge to clear (${Q}s/${Math.floor(X/1000)}s)...`);await new Promise((B)=>setTimeout(B,J))}return{cleared:!1,reason:`Challenge not cleared within ${Math.floor(X/1000)}s`}}var d4=Object.keys(m2);m1();import{mkdirSync as o6,readdirSync as s6,rmSync as t6,statSync as r6,writeFileSync as L$}from"node:fs";import{join as d1}from"node:path";var e6=import.meta.dirname||new URL(".",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1");function $7($){return $.toLowerCase().replaceAll(/[^a-z0-9]+/g,"-").replaceAll(/^-|-$/g,"").slice(0,60)}var Z7=604800000,X7=10;function J7($){try{let Z=s6($).filter((J)=>J.endsWith(".json")||J.endsWith(".md")).map((J)=>({f:J,mtime:r6(d1($,J)).mtimeMs})).sort((J,W)=>W.mtime-J.mtime),X=Date.now()-Z7;for(let J=X7;J<Z.length;J++)if(Z[J].mtime<X)t6(d1($,Z[J].f),{force:!0})}catch{}}function W7(){let $=d1(e6,"..","..","results");return o6($,{recursive:!0}),J7($),$}function n0($,Z,{inline:X=!1,synthesize:J=!1,query:W=""}={}){let K=`${JSON.stringify($,null,2)}
|
|
430
|
-
`;if(Z){L$(Z,K,"utf8"),process.stderr.write(`Results written to ${Z}
|
|
431
|
-
`);return}if(X){process.stdout.write(K);return}let V=new Date().toISOString().replaceAll("T","_").replaceAll(/[:.]/g,"-").slice(0,19),j=$7(W),Y=d1(W7(),`${V}_${j}`);if(L$(`${Y}.json`,K,"utf8"),J&&$._synthesis?.answer)L$(`${Y}-synthesis.md`,$._synthesis.answer,"utf8"),process.stdout.write(`${Y}-synthesis.md
|
|
432
|
-
`);else process.stdout.write(`${Y}.json
|
|
433
|
-
`)}var K7=["perplexity","bing","chatgpt","semantic-scholar","logically"],u2=new Set(["rate-limit"]),V7=/timed out|timeout|verification|captcha|cloudflare|turnstile|input not found|ask-input|copy button hidden|sign.in|login required/i,j7=/needs-human|verification required|please solve|captcha|cloudflare|turnstile|could not be completed automatically|manual intervention|sign.in|login required/i;function c2($){return V7.test(String($||""))}function A$($){return j7.test(String($||""))}function n2($){return K7.filter((Z)=>{let X=$?.[Z];if(!X)return!1;let J=X._envelope?.blockedBy;if(J){if(u2.has(J))return!1;return!0}if(X._envelope?.verificationResult==="needs-human")return!0;let W=X.error;return W&&c2(W)})}function i2($){if(!$)return!1;let Z=$.envelope;if(Z?.blockedBy){if(u2.has(Z.blockedBy))return!1;return!0}if(Z?.verificationResult==="needs-human")return!0;return c2($.message)}b0();M0();b0();function Y7($){let Z="",X=!1,J=!1;for(let W of String($)){if(J){Z+=W,J=!1;continue}if(W==="\\"){Z+=W,J=!0;continue}if(W==='"'){X=!X,Z+=W;continue}if(X&&W===`
|
|
434
|
-
`)Z+="\\n";else if(X&&W==="\r")Z+="\\r";else if(X&&W==="\t")Z+="\\t";else Z+=W}return Z}function D0($){if(!$)return null;let Z=String($).trim(),X=Z.indexOf("BEGIN_JSON"),J=Z.indexOf("END_JSON");if(X!==-1&&J!==-1&&X<J)Z=Z.slice(X+10,J).trim();else{let j=Z.indexOf("{");if(j>0)Z=Z.slice(j)}let W=[Z,Z.replace(/^```json\s*/i,"").replace(/^```\s*/i,"").replace(/```$/i,"").trim()],K=Z.indexOf("{"),V=Z.lastIndexOf("}");if(K!==-1&&V!==-1&&K<V)W.push(Z.slice(K,V+1));for(let j of[...W]){let Y=Y7(j);if(Y!==j)W.push(Y)}for(let j of W)try{return JSON.parse(j)}catch{}return null}function a2($,Z,X=""){let J=new Set(Z.map((Y)=>Y.id)),W=["high","medium","low","mixed","conflicting"].includes($?.agreement?.level)?$.agreement.level:"mixed",K=Array.isArray($?.claims)?$.claims.map((Y)=>({claim:R(Y?.claim||"",260),support:["strong","moderate","weak","conflicting"].includes(Y?.support)?Y.support:"moderate",sourceIds:Array.isArray(Y?.sourceIds)?Y.sourceIds.filter((Q)=>J.has(Q)):[]})).filter((Y)=>Y.claim):[],V=Array.isArray($?.recommendedSources)?$.recommendedSources.filter((Y)=>J.has(Y)).slice(0,6):[],j="";if(X){let Y=X.indexOf("{"),Q=X.lastIndexOf("}");if(Y!==-1&&Q!==-1&&Y<Q)j=X.slice(Y,Q+1);else j=X}return{answer:R($?.answer||j||X,4000),agreement:{level:W,summary:R($?.agreement?.summary||"",280)},differences:Array.isArray($?.differences)?$.differences.map((Y)=>R(Y,220)).filter(Boolean).slice(0,5):[],caveats:Array.isArray($?.caveats)?$.caveats.map((Y)=>R(Y,220)).filter(Boolean).slice(0,5):[],claims:K,recommendedSources:V}}function o2($,Z,X,{grounded:J=!1}={}){let W={};for(let j of["perplexity","bing","google"]){let Y=Z[j];if(!Y)continue;if(Y.error){W[j]={status:"error",error:String(Y.error)};continue}W[j]={status:"ok",answer:R(Y.answer||"",J?4500:2200),sourceIds:X.filter((Q)=>Q.engines.includes(j)).sort((Q,H)=>(Q.perEngine[j]?.rank||99)-(H.perEngine[j]?.rank||99)).map((Q)=>Q.id).slice(0,6)}}let K=J?700:300,V=X.slice(0,J?10:8).map((j)=>({id:j.id,title:j.title,domain:j.domain,canonicalUrl:j.canonicalUrl,sourceType:j.sourceType,isOfficial:j.isOfficial,engines:j.engines,engineCount:j.engineCount,fetch:j.fetch?.attempted?{ok:j.fetch.ok,publishedTime:j.fetch.publishedTime||"",byline:j.fetch.byline||"",snippet:R(j.fetch.snippet||"",K)}:void 0}));return["You are a research synthesizer. Combine these search engine results into a single authoritative answer.","",`Query: ${$}`,"",`Engine summaries:
|
|
435
|
-
${JSON.stringify(W,null,2)}`,"",`Source registry:
|
|
436
|
-
${JSON.stringify(V,null,2)}`,"","Instructions:","- Write a clear, direct answer in markdown (use headers/bullets where they help readability)","- Cite sources inline as [S1], [S2] etc. when making specific claims","- Prefer sources with content (fetch.ok=true and non-empty snippet) for citations","- Note where the engines agree or meaningfully disagree","- List any important caveats or limitations","- recommendedSources: the 2-4 source IDs most worth reading for this query","","Respond ONLY with a JSON object wrapped in BEGIN_JSON / END_JSON markers:","","BEGIN_JSON",JSON.stringify({answer:"<your markdown answer here>",agreement:{level:"high|medium|mixed|conflicting",summary:"<one sentence>"},differences:["<notable difference between engines, if any>"],caveats:["<important caveat or limitation>"],recommendedSources:["S1","S2"]},null,2),"END_JSON"].join(`
|
|
437
|
-
`)}function s2($){let Z=Array.isArray($._sources)?$._sources:[],X=Z.length>0?Z[0]?.engineCount||0:0,J=Z.filter((Q)=>Q.isOfficial).length,W=Z.filter((Q)=>Q.isOfficial||Q.sourceType==="maintainer-blog").length,K=Z.filter((Q)=>Q.fetch?.attempted).length,V=Z.filter((Q)=>Q.fetch?.ok).length,j=Z.reduce((Q,H)=>{return Q[H.sourceType]=(Q[H.sourceType]||0)+1,Q},{}),Y=$._synthesis?.agreement?.level;return{sourcesCount:Z.length,topSourceConsensus:X,agreementLevel:Y||(X>=3?"high":X>=2?"medium":"low"),enginesResponded:r.filter((Q)=>$[Q]?.answer&&!$[Q]?.error),enginesFailed:r.filter((Q)=>$[Q]?.error),officialSourceCount:J,firstPartySourceCount:W,fetchedSourceSuccessRate:K>0?Number((V/K).toFixed(2)):0,sourceTypeBreakdown:j}}g0();M0();W1();import{spawn as Q7}from"node:child_process";b0();var H7=v0(import.meta.url),B7={gemini:"gemini.mjs",chatgpt:"chatgpt.mjs"},G7={gemini:"https://gemini.google.com/app",chatgpt:"https://chatgpt.com/"};function z1($="gemini"){let Z=String($||"gemini").toLowerCase();if(Z==="gem")return"gemini";if(Z==="gpt")return"chatgpt";return Z}function t2($="gemini"){return G7[z1($)]||"about:blank"}async function r2($,Z,{tabPrefix:X=null,timeoutMs:J=180000,visible:W=null}={}){let K=z1($),V=B7[K];if(!V||!K1.includes(K))throw Error(`Unsupported synthesizer "${$}". Supported: ${K1.join(", ")}`);return new Promise((j,Y)=>{let Q=s0(V,{moduleDir:H7}),H=X?["--tab",String(X)]:[],B={...process.env,CDP_PROFILE_DIR:u};if(W!==!0)delete B.GREEDY_SEARCH_VISIBLE,delete B.GREEDY_SEARCH_ALWAYS_VISIBLE;else B.GREEDY_SEARCH_VISIBLE="1",B.GREEDY_SEARCH_ALWAYS_VISIBLE="1";let N=Q7(Q0(),[Q,"--stdin",...H],{stdio:["pipe","pipe","pipe"],env:B});N.stdin.write(Z),N.stdin.end();let G="",O="";N.stdout.on("data",(D)=>G+=D),N.stderr.on("data",(D)=>O+=D);let M=setTimeout(()=>{N.kill(),Y(Error(`${K} prompt timed out after ${J/1000}s`))},J);N.on("close",(D)=>{if(clearTimeout(M),D!==0){Y(Error(O.trim()||`${K} extractor failed`));return}try{j(JSON.parse(G.trim()))}catch{Y(Error(`bad JSON from ${K}: ${G.slice(0,100)}`))}})})}async function H0($,Z={}){return r2("gemini",$,Z)}async function e2($,Z,{grounded:X=!1,tabPrefix:J=null,visible:W=null,synthesizer:K="gemini"}={}){let V=z1(K),j=Array.isArray(Z._sources)?Z._sources:f0(Z),Y=o2($,Z,j,{grounded:X}),Q=await r2(V,Y,{tabPrefix:J,timeoutMs:180000,visible:W}),H=D0(Q.answer||""),N=H&&["answer","agreement","claims","differences","caveats"].some((O)=>(O in H));if(H&&["perplexity","bing","google","chatgpt","gemini"].some((O)=>(O in H))&&!N)H=null;return{...a2(H,j,Q.answer||""),rawAnswer:Q.answer||"",synthesizedBy:V,synthesizerSources:Q.sources||[],geminiSources:V==="gemini"?Q.sources||[]:[]}}var N7=/^(can you |could you |please |would you mind |i need to (know|understand) |i want to (know|understand) |i('m| am) (looking for|wondering about|curious about) |i need (information|info) (about|on) |tell me )?(about |explain |describe |give me |help me understand |search for |look up |find |research )?(about |regarding |on |for )?(it|this|the following)?\s*/i,O7=/\b(latest|newest|current|recent|up-to-date|up to date)\b/i,M7=/\b\d+\.\d+|\bv\d+\b|\b20(2[0-9]|[3-9]\d)\b/i;function D7($){let Z=$.trim().replace(N7,"").trim();return Z.length>4?Z:$.trim()}function z7($,Z=new Date().getFullYear()){if(!O7.test($))return $;if(M7.test($))return $;return`${$.trimEnd()} ${Z}`}function l1($){if(!$?.trim())return $;let Z=D7($);return Z=z7(Z),Z||$}g0();b0();import{spawn as b7}from"node:child_process";import{mkdirSync as f$,writeFileSync as V0}from"node:fs";import{join as m}from"node:path";import{fileURLToPath as x7}from"node:url";M0();b0();var U7=30000;function $8($,Z,X,J){let W=Number.parseInt(String($??""),10);if(!Number.isFinite(W))return J;return Math.min(X,Math.max(Z,W))}async function Z8($){let Z=["You are a research complexity classifier.","Classify the following query by research complexity.","","- simple: A narrow factual question (what is X, define X, how does X work)."," Answerable with 1-3 search queries and a short synthesis. No sub-questions.","- moderate: A focused comparison, recent change, or best-practice lookup."," Needs 2-4 angles but stays within one domain.","- complex: Multi-faceted survey, landscape analysis, or cross-domain investigation."," Benefits from parallel research directions and iterative deepening.","","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({complexity:"simple",reasoning:"narrow factual question",suggestedBreadth:1,suggestedIterations:1,needsAcademicSources:!1},null,2),"END_JSON","","Query: "+$].join(`
|
|
438
|
-
`);try{let X=await H0(Z,{timeoutMs:U7}),J=D0(X?.answer||"")||{},W=["simple","moderate","complex"].includes(J.complexity)?J.complexity:"moderate";return{complexity:W,reasoning:R(J.reasoning||"",200),suggestedBreadth:$8(J.suggestedBreadth,1,5,W==="simple"?1:3),suggestedIterations:$8(J.suggestedIterations,1,3,W==="simple"?1:2),needsAcademicSources:J.needsAcademicSources===!0}}catch(X){return process.stderr.write(`[greedysearch] Complexity classification failed, defaulting to moderate: ${X.message}
|
|
439
|
-
`),{complexity:"moderate",reasoning:"classification failed",suggestedBreadth:3,suggestedIterations:2,needsAcademicSources:!1}}}M0();b0();m1();D1();function F7($){if($<1000)return"0s";let Z=Math.round($/1000);if(Z<60)return`${Z}s`;let X=Math.floor(Z/60),J=Z%60;return`${X}m ${J}s`}function w7($,Z=20){let X=Math.round($*Z),J=Z-X;return"["+"█".repeat(X)+"░".repeat(J)+"]"}function u1({totalActions:$=0,totalRounds:Z=0,totalFetches:X=0,silent:J=!1}={}){let W=Date.now(),K=0,V=0,j=0,Y=[],Q=null,H=null,B=0,N=500;function G(z){if(Y.push(z),Y.length>5)Y.shift()}function O(){if(Y.length===0)return null;return Y.reduce((z,F)=>z+F,0)/Y.length}function M(z){let F=Date.now()-W,P=$+X+Z,w=K+j+V,g=P>0?Math.min(1,w/P):0,d=w7(g),f=O(),x=Math.max(0,P-w),i=f?f*x:null,B0=i?F7(i):"—",o=H?` ${H}`:"";return`${d} ${w}/${P} (${z}${o}, ETA ${B0})`}function D(z){if(J)return;let F=Date.now();if(F-B<N&&z!=="done")return;B=F,process.stderr.write(`[greedysearch] ${M(z)}
|
|
440
|
-
`)}return{startRound(z){V=z-1},endRound(){V++,D("round")},startAction(z,F){Q=Date.now(),H=`${z}:${(F||"").slice(0,40)}`,D(z)},endAction(){if(Q)G(Date.now()-Q),Q=null;K++,D("action")},startFetch(z){Q=Date.now(),H=`fetch:${(z||"").slice(0,40)}`,D("fetch")},endFetch(z=!0){if(Q)G(Date.now()-Q),Q=null;j++,D(z?"fetch":"fetch-failed")},print(){D("progress")},finish(){D("done")},getElapsedMs(){return Date.now()-W}}}g0();import{spawn as P7}from"node:child_process";import{join as _7}from"node:path";import{fileURLToPath as k7}from"node:url";var L7=k7(new URL(".",import.meta.url)).replace(/^\/([A-Z]:)/,"$1"),A7=_7(L7,"..","..","bin","search.mjs");function X8($,Z=1/0){let X=new Set,J=[];for(let W of $||[]){let K=R(String(W||""),1000);if(!K||X.has(K))continue;if(X.add(K),J.push(K),J.length>=Z)break}return J}function T7($){let Z=String($||"").trim();if(!Z)return[];return[`${Z} — definition and overview`,`${Z} — how it works, mechanism, or key details`,`${Z} — current usage, comparison, or best practices`]}function C7($,Z){let X=new Map;for(let J of $||[]){let W=J?.canonicalUrl||J?.finalUrl||J?.url;if(W)X.set(W,J)}for(let J of Z||[]){let W=J?.canonicalUrl||J?.finalUrl||J?.url;if(!W)continue;if(X.has(W)){let K={...X.get(W),angles:[...X.get(W).angles||[X.get(W).query||""],J.query||""]};X.set(W,K)}else X.set(W,J)}return Array.from(X.values())}var R7=r.join("|"),v7=new RegExp(`^\\[(${R7})\\]`);function I7($){return/^PROGRESS:/.test($)||/^\[greedysearch\]/.test($)||v7.test($)||/^GreedySearch Chrome/.test($)||/^Launching GreedySearch Chrome/.test($)||/^Headless mode/.test($)||/^Ready\.?$/.test($)}async function E7($,{locale:Z=null,short:X=!0}={}){let J=[A7,"all","--inline","--stdin","--fast"];if(!X)J.push("--full");if(Z)J.push("--locale",Z);return new Promise((W,K)=>{let V=P7(Q0(),J,{stdio:["pipe","pipe","pipe"],env:{...process.env,GREEDY_SEARCH_RESEARCH_CHILD:"1"}});V.stdin.write($),V.stdin.end();let j="",Y="",Q="";V.stdout.on("data",(B)=>j+=B),V.stderr.on("data",(B)=>{Y+=B,Q+=B.toString();let N=Q.split(`
|
|
441
|
-
`);Q=N.pop()||"";for(let G of N)if(I7(G))process.stderr.write(`${G}
|
|
442
|
-
`)});let H=setTimeout(()=>{V.kill(),K(Error(`research child search timed out for: ${$}`))},140000);V.on("close",(B)=>{if(clearTimeout(H),B!==0){K(Error(Y.trim()||`search child exited with code ${B}`));return}try{W(JSON.parse(j.trim()))}catch{K(Error(`Invalid JSON from research child: ${j.slice(0,200)}`))}})})}function q7($,Z){let X=new Map;for(let J of Z||[]){let W=e(J?.canonicalUrl||J?.finalUrl||J?.url);if(W&&J?.id)X.set(W,J.id)}return($||[]).map((J,W)=>{let K=e(J?.finalUrl||J?.canonicalUrl||J?.url);return{...J,id:J?.id||X.get(K)||`F${W+1}`}})}function f7($){let Z=$.length,X=$.filter((J)=>J.status==="closed").length;return{total:Z,closed:X,open:Math.max(0,Z-X)}}async function J8({query:$,locale:Z=null,maxSources:X=5,qualityThreshold:J=8.5,writeBundle:W=process.env.GREEDY_RESEARCH_BUNDLE!=="0",researchOutDir:K=null}={}){let V=new Date().toISOString(),j=Date.now(),Y=I$($),Q=new Set;process.stderr.write(`[greedysearch] Simple research mode: single-pass for "${R($,80)}"
|
|
443
|
-
`);let N=u1({totalActions:6,totalRounds:1,totalFetches:1,silent:process.env.GREEDY_RESEARCH_QUIET==="1"});N.startRound(1);let G=[],O=[],M=T7($),D=[];N.startAction("search",`${M.length} angles in parallel`);let z=await Promise.allSettled(M.map((T)=>E7(T,{locale:Z,short:!0})));for(let T=0;T<M.length;T++){let $0=M[T],c=z[T];if(N.endAction(),c.status==="fulfilled"){let s=c.value;D.push({angle:$0,result:s});let E=f0(s,$0);G=C7(G,E)}else process.stderr.write(`[greedysearch] Simple search angle "${$0}" failed: ${c.reason.message}
|
|
444
|
-
`)}if(process.stderr.write(`PROGRESS:research:simple:fetching
|
|
445
|
-
`),G.length>0)try{N.startFetch(`top ${Math.min(X,G.length)} sources`),O=await M1(G,Math.min(X,G.length),8000,Math.min(3,X)),N.endFetch(!0),G=r0(G,O)}catch(T){N.endFetch(!1),process.stderr.write(`[greedysearch] Source fetching failed: ${T.message}
|
|
446
|
-
`)}O=q7(O,G),process.stderr.write(`PROGRESS:research:simple:evidence
|
|
447
|
-
`);let F=[];try{let T=await W8({query:$,questions:Y,fetchedSources:O,extractedSourceKeys:Q});F=T.evidence||[];for(let $0 of T.evidence){let c=Array.isArray($0.answers)?$0.answers:[];for(let E of c){let U0=E?.id||E?.question;if(U0){let b=Y.find((W0)=>W0.id===U0);if(b){if(b.status="closed",b.closedRound=1,E.evidence)b.evidence=X8([...b.evidence||[],E.evidence],4)}}}let s=Array.isArray($0.newQuestions)?$0.newQuestions:[];for(let E of s){let U0=R(String(E),320);if(U0&&!Y.some((b)=>b.question===U0))Y.push({id:`Q${Y.length+1}`,question:U0,status:"open",reason:"Discovered gap/follow-up",createdRound:1,evidence:[],sourceIds:[]})}}}catch(T){process.stderr.write(`[greedysearch] Evidence extraction failed: ${T.message}
|
|
448
|
-
`)}process.stderr.write(`PROGRESS:research:simple:synthesizing
|
|
449
|
-
`);let P={answer:"",agreement:{level:"mixed",summary:"Single-pass synthesis."},differences:[],caveats:[],claims:[],recommendedSources:G.slice(0,4).map((T)=>T.id),synthesized:!1};if(F.length>0)try{N.startAction("synth-evidence","from evidence");let T=await H0(C$($,G,Y,F),{timeoutMs:120000});N.endAction(),P={...P,...D0(T?.answer||"")||{}},P.synthesized=Array.isArray(P.claims)&&P.claims.length>0}catch(T){process.stderr.write(`[greedysearch] Evidence synthesis failed: ${T.message}
|
|
450
|
-
`)}if(!P.synthesized&&G.length>0)try{N.startAction("synth-final","fallback report");let T=await H0(T$($,[{round:1,learnings:[],gaps:[],actions:[]}],G,Y,F),{timeoutMs:120000});N.endAction(),P={...P,...D0(T?.answer||"")||{}},P.synthesized=Array.isArray(P.claims)&&P.claims.length>0}catch(T){process.stderr.write(`[greedysearch] Final synthesis failed: ${T.message}
|
|
451
|
-
`)}process.stderr.write(`PROGRESS:research:simple:audit
|
|
452
|
-
`);let w=R$(P.answer||"",G),g=await v$(G,w);E$(Y,P,w);let d=X8(P.caveats||[]),f=c1({sources:G,fetchedSources:O,synthesis:P,citationAudit:w,gaps:d,questions:Y,rounds:[{round:1,actions:[],learnings:[],gaps:d}],qualityScore:P.synthesized?8:5,qualityThreshold:J,maxSources:X}),x=new Date().toISOString(),i=Date.now()-j,B0={startedAt:V,finishedAt:x,durationMs:i,rounds:1,terminationReason:"simple_single_pass"},o=null,J0;if(W){process.stderr.write(`PROGRESS:research:simple:bundle
|
|
453
|
-
`);try{o=await q$({query:$,rounds:[{round:1,actions:[],learnings:[],gaps:d,evidence:F}],sources:G,fetchedSources:O,evidenceItems:F,synthesis:P,citationAudit:w,citationUrls:g,floor:f,manifest:{...B0,engines:j1,synthesizer:"gemini",actionsRun:1,searches:1,fetches:O.length,sourcesFetched:O.filter((T)=>T?.contentChars>100).length,engineFailures:[],floorMet:f.floorMet},allGaps:d,questions:Y,outDir:K}),J0=o.sourceFiles,delete o.sourceFiles}catch(T){process.stderr.write(`[greedysearch] Research bundle write failed: ${T.message}
|
|
454
|
-
`),o={error:T.message||String(T)},J0=await $1(O)}}else J0=await $1(O);return process.stderr.write(`PROGRESS:research:done
|
|
455
|
-
`),N.endRound(),N.finish(),{query:$,_research:{mode:"simple",breadth:1,iterations:1,maxSources:X,rounds:[{round:1,actions:[],learnings:[],gaps:d,evidence:F}],learnings:[],gaps:d,evidence:F,questions:Y,questionProgress:f7(Y),qualityHistory:[P.synthesized?8:5],terminationReason:"simple_single_pass",qualityThreshold:J,floor:f,bundle:o,manifest:B0},_citationAudit:w,_citationUrls:g,_sources:G,_fetchedSources:J0,_synthesis:P,_confidence:{sourcesCount:G.length,fetchedSourceSuccessRate:O.length>0?O.filter((T)=>T.contentChars>100).length/O.length:0,agreementLevel:P.agreement?.level||"mixed",floorMet:f.floorMet}}}var S7=x7(new URL(".",import.meta.url)).replace(/^\/([A-Z]:)/,"$1"),g7=m(S7,"..","..","bin","search.mjs"),y7=m(process.cwd(),".pi","greedysearch-research"),h7=28000;function p7($){return String($||"research").toLowerCase().replaceAll(/[^a-z0-9]+/g,"-").replaceAll(/^-|-$/g,"").slice(0,60)||"research"}function R0($,Z=1/0){let X=new Set,J=[];for(let W of $||[]){let K=R(String(W||""),1000);if(!K||X.has(K))continue;if(X.add(K),J.push(K),J.length>=Z)break}return J}async function m7(...$){let{fetchMultipleSources:Z}=await Promise.resolve().then(() => (D1(),_$));return Z(...$)}async function y$(...$){let{writeSourcesToFiles:Z}=await Promise.resolve().then(() => (m1(),l2));return Z(...$)}function d7({breadth:$=3,iterations:Z=2,maxSources:X}){let J=b$($,1,5,3),W=b$(Z,1,3,2),K=b$(X??Math.max(5,J*W*2),3,12,8);return{breadth:J,iterations:W,maxSources:K}}function b$($,Z,X,J){let W=Number.parseInt(String($??""),10);if(!Number.isFinite(W))return J;return Math.min(X,Math.max(Z,W))}function l7($,Z,X,{expand:J=!0,includeOriginal:W=!0,exclude:K=[]}={}){let V=Array.isArray($?.queries)?$.queries:[],j=[],Y=new Set([...K].map((Q)=>z0(Q).toLowerCase()));for(let Q of V){let H=typeof Q==="string"?Q:Q?.query,B=typeof Q==="string"?"":Q?.researchGoal||"";x$(j,H,B,{exclude:Y})}if(W)x$(j,Z,"Original user query",{prepend:!0,exclude:Y});if(J){let Q=[{query:`${Z} official docs GitHub`,researchGoal:"Find primary project docs, repository details, and maintainer claims."},{query:`${Z} benchmarks limitations compatibility`,researchGoal:"Validate performance claims and uncover unsupported APIs or caveats."},{query:`${Z} alternatives comparison production use cases`,researchGoal:"Compare against conventional headless browsers and identify when to choose it."},{query:`${Z} anti bot detection Cloudflare screenshots visual rendering`,researchGoal:"Check automation risks, rendering gaps, screenshots, and bot-detection behavior."}];for(let H of Q){if(j.length>=X)break;x$(j,H.query,H.researchGoal,{exclude:Y})}}return j.slice(0,X)}function x$($,Z,X="",{prepend:J=!1,exclude:W=new Set}={}){if(!Z||typeof Z!=="string")return;let K=z0(Z);if(!K||W.has(K.toLowerCase())||$.some((j)=>j.query.toLowerCase()===K.toLowerCase()))return;let V={query:K,researchGoal:R(X,320)};if(J)$.unshift(V);else $.push(V)}function z0($){return c7(u7(String($)))}function u7($){let Z="",X=0;while(X<$.length){let J=$.indexOf("[",X);if(J===-1){Z+=$.slice(X);break}let W=$.indexOf("]",J+1);if(W===-1||$[W+1]!=="("||W===J+1){Z+=$.slice(X,J+1),X=J+1;continue}let K=$.indexOf(")",W+2);if(K===-1){Z+=$.slice(X,J+1),X=J+1;continue}let V=$.slice(W+2,K).trimStart();if(!V.startsWith("http://")&&!V.startsWith("https://")){Z+=$.slice(X,J+1),X=J+1;continue}Z+=$.slice(X,J),Z+=$.slice(J+1,W),X=K+1}return Z}function c7($){let Z="",X=!1;for(let J of $)if(J===" "||J==="\t"||J===`
|
|
456
|
-
`||J==="\r"){if(!X)Z+=" ";X=!0}else Z+=J,X=!1;return Z.trim()}function h$($){return new Set(String($).toLowerCase().normalize("NFD").replaceAll(/[\u0300-\u036f]/g,"").split(/[^\w]+/).filter((Z)=>Z.length>1))}function m$($,Z){let X=h$($),J=h$(Z),W=new Set([...X,...J]).size;if(W===0)return 1;let K=0;for(let V of X)if(J.has(V))K++;return K/W}function j8($,Z,{threshold:X=0.75,roundIndex:J=0,originalQuery:W=null}={}){let K=z0($).toLowerCase();if(Z.has(K))return!0;if(W&&J>0&&K===z0(W).toLowerCase())return!0;for(let V of Z)if(m$(K,V)>=X)return!0;return!1}function n7($,Z,X,J){let W=Z.map((K)=>({queries:K.queries?.map((V)=>V.query||"")||[],learnings:K.learnings||[],gaps:K.gaps||[]}));return["You are evaluating the quality of an iterative research run.","Assess coverage across: official sources, limitations/risks, benchmarks/performance, production usage, and counter-evidence.","Score each dimension 0-10. Overall score 0-10.","Identify remaining knowledge gaps.","Propose targeted next actions (search queries or direct URL fetches) that would most improve the research.","Decide whether to continue or stop.","terminationReason must be one of: quality_threshold | max_rounds | no_novel_actions | insufficient_evidence.","",`Original research question: ${$}`,`Rounds completed: ${JSON.stringify(W,null,2)}`,`Accumulated learnings: ${JSON.stringify(X.slice(0,12),null,2)}`,`Known gaps: ${JSON.stringify(J.slice(0,8),null,2)}`,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({score:7.5,coverage:{officialSources:8,limitations:5,benchmarks:7,productionUseCases:6,counterEvidence:4},knowledgeGaps:["specific gap or missing evidence"],shouldContinue:!0,terminationReason:"quality_threshold",nextActions:[{type:"search",query:"targeted search query"},{type:"fetchUrl",url:"https://example.com/primary-doc"}]},null,2),"END_JSON"].join(`
|
|
457
|
-
`)}function i7($,Z,X,J,W){let K=[],V=[{template:(j)=>`${j} official documentation`,label:"official docs"},{template:(j)=>`${j} GitHub issues discussions`,label:"community signals"},{template:(j)=>`${j} benchmarks performance comparison`,label:"benchmarks"},{template:(j)=>`${j} limitations risks caveats`,label:"limitations"},{template:(j)=>`${j} production deployment experience`,label:"production usage"},{template:(j)=>`${Z} ${j} counter evidence`,label:"counter-evidence"}];for(let j=0;j<$.length&&K.length<J;j++){let Y=$[j],Q=V[j%V.length],H=Q.template(Y);if(!j8(H,X,{roundIndex:W}))K.push({query:H,researchGoal:`Gap-driven: ${Y} (${Q.label})`})}return K}async function a7($,Z,X,J,W){try{let K=await H0(n7($,Z,X,J),{timeoutMs:120000}),V=U1(K,{}),j=typeof V.score==="number"?Math.min(10,Math.max(0,V.score)):W.length>0?W[W.length-1]:5,Y=Array.isArray(V.knowledgeGaps)?V.knowledgeGaps.map((N)=>String(N)).filter(Boolean).slice(0,6):[],Q=Array.isArray(V.nextActions)?V.nextActions.slice(0,5):[],H=typeof V.shouldContinue==="boolean"?V.shouldContinue:j<8,B=V.terminationReason||null;return{score:j,coverage:V.coverage||{},knowledgeGaps:Y,shouldContinue:H,nextActions:Q,terminationReason:B||(j>=8.5?"quality_threshold":null),evaluationError:""}}catch(K){return process.stderr.write(`[greedysearch] Quality evaluation failed: ${K.message}
|
|
458
|
-
`),{score:W.length>0?W[W.length-1]:5,coverage:{},knowledgeGaps:[],shouldContinue:!0,nextActions:[],terminationReason:null,evaluationError:K.message}}}function o7($){let Z={};for(let X of Object.keys($||{}).filter((J)=>!J.startsWith("_"))){let J=$?.[X];if(!J)continue;Z[X]=J.error?{status:"error",error:String(J.error)}:{status:"ok",answer:R(J.answer||"",1400),sources:Array.isArray(J.sources)?J.sources.slice(0,5).map((W)=>({title:R(W.title||"",160),url:W.url||""})):[]}}return Z}function s7($,Z,X=[],J=[],W=[]){let K=J.length>0?`
|
|
459
|
-
Known knowledge gaps to target:
|
|
460
|
-
${J.map((j)=>`- ${j}`).join(`
|
|
461
|
-
`)}`:"",V=W.length>0?`
|
|
462
|
-
Already fetched URLs (do not re-fetch):
|
|
463
|
-
${W.map((j)=>`- ${j}`).join(`
|
|
464
|
-
`)}`:"";return["You are planning web research actions for a multi-engine search agent.","You can plan two types of actions:",' - "search": run a multi-engine SERP search query',' - "fetchUrl": directly fetch a specific URL (docs page, GitHub repo, specification, etc.)','Prefer "fetchUrl" when a specific primary source URL is known or obvious.','Use "search" for broad discovery or when specific URLs are unknown.',`Return at most ${Z} actions.`,"Avoid near-duplicate search queries and already-fetched URLs.","",`User topic: ${$}`,X.length?`
|
|
465
|
-
Prior learnings to build on:
|
|
466
|
-
${X.map((j)=>`- ${j}`).join(`
|
|
467
|
-
`)}`:"",K,V,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({actions:[{type:"search",query:"specific search query",researchGoal:"what this action should clarify"},{type:"fetchUrl",url:"https://example.com/docs/relevant-page",researchGoal:"extract specific information from this page"}]},null,2),"END_JSON"].join(`
|
|
468
|
-
`)}function Y8($){if(!$||typeof $!=="object")return null;let Z=$.type,X=R($.researchGoal||"",320);if(Z==="search"){if($.query==null)return null;let J=z0($.query);return J?{type:"search",query:J,researchGoal:X}:null}if(Z==="fetchUrl"){if($.url==null)return null;let J=e($.url);return J?{type:"fetchUrl",url:J,researchGoal:X}:null}return null}async function t7($,{locale:Z=null,short:X=!0,usedQueries:J,usedUrls:W,maxChars:K=8000}={}){if($.type==="search"){let V=z0($.query).toLowerCase();J.add(V);try{let j=await V9($.query,{locale:Z,short:X}),Y=f0(j,$.query);return{ok:!0,action:$,result:j,sources:Y}}catch(j){return{ok:!1,action:$,error:j.message,sources:[]}}}if($.type==="fetchUrl"){let V=e($.url);if(W.has(V))return{ok:!1,action:$,error:`URL already fetched: ${V}`,sources:[]};try{let j=await r7(V,K);W.add(V);let Y=e7(V),Q={id:"",canonicalUrl:j.finalUrl||V,displayUrl:j.url||V,domain:Y,title:j.title||V,engines:["fetch"],engineCount:1,perEngine:{},sourceType:P$(Y,j.title||"",j.finalUrl||V),isOfficial:!1,smartScore:0,fetch:{attempted:!0,ok:!j.error&&(j.contentChars||0)>100,status:j.status||null,finalUrl:j.finalUrl||V,content:j.content||"",contentChars:j.contentChars||0,snippet:j.snippet||"",error:j.error||""}};return{ok:!0,action:$,result:null,sources:[Q],fetchResult:{id:Q.id,url:V,finalUrl:j.finalUrl||V,title:j.title||"",content:j.content||"",contentChars:j.contentChars||0,snippet:j.snippet||"",status:j.status||null,error:j.error||"",source:j.source||"http",duration:j.duration||0}}}catch(j){return{ok:!1,action:$,error:j.message,sources:[]}}}return{ok:!1,action:$,error:`Unknown action type: ${$.type}`,sources:[]}}async function r7($,Z){let{fetchSourceContent:X}=await Promise.resolve().then(() => (D1(),_$));return await X($,Z)}function e7($){try{return new URL($).hostname.toLowerCase().replace(/^www\./,"")}catch{return""}}async function $9($,Z){let X=[],{parseGitHubUrl:J}=await Promise.resolve().then(() => (z$(),v2));for(let W of $){if(W.type!=="fetchUrl"){X.push(W);continue}let K=J(W.url);if(!K||K.type!=="root"){X.push(W);continue}let{owner:V,repo:j}=K,Y=`https://github.com/${V}/${j}`;if(Z.has(Y))continue;let Q=[Y],H=[`${Y}/blob/main/CONTRIBUTING.md`,`${Y}/blob/master/CONTRIBUTING.md`,`${Y}/blob/main/CHANGELOG.md`,`${Y}/blob/master/CHANGELOG.md`,`${Y}/blob/main/docs/README.md`];for(let B of H){if(Q.length>=3)break;if(!Z.has(B))Q.push(B)}for(let B of Q)X.push({type:"fetchUrl",url:B,researchGoal:W.researchGoal||`Fetch GitHub content for ${V}/${j}`})}return X}function Z9($,Z){let X=D0($?.answer||"")||{},J=Array.isArray(X?.actions)?X.actions:[],W=[];for(let K of J){let V=Y8(K);if(V&&W.length<Z)W.push(V)}return W}function X9($){return($||[]).map((Z)=>({type:"search",query:typeof Z==="string"?Z:Z.query,researchGoal:typeof Z==="string"?"":Z.researchGoal||""})).filter((Z)=>Z.query)}function Z1($){return e($?.finalUrl||$?.canonicalUrl||$?.url||"")||$?.id||""}function Q8($,Z){let X=Array.isArray($?.extractions)?$.extractions:[],J=new Map,W=new Map;for(let K of Z||[]){if(K?.id)W.set(String(K.id),K);let V=Z1(K);if(V)J.set(V,K)}return X.map((K)=>{let V=W.get(String(K?.sourceId||""))||J.get(e(K?.url||"")||""),j=String(K?.sourceId||V?.id||""),Y=e(K?.url||V?.finalUrl||V?.url||""),Q=Array.isArray(K?.answers)?K.answers.map((H)=>({id:String(H?.id||""),evidence:R(H?.evidence||"",500),sourceIds:[j].filter(Boolean)})).filter((H)=>H.id):[];return{sourceId:j,url:Y,title:V?.title||K?.title||"",rational:R(K?.rational||"",700),evidence:R(K?.evidence||"",1600),summary:R(K?.summary||"",700),answers:Q,newQuestions:R0(K?.newQuestions||[],6)}}).filter((K)=>K.sourceId||K.url||K.summary||K.evidence)}function J9($,Z,X,J=new Set){let W=(Z||[]).filter((V)=>V.status!=="closed").slice(0,12).map((V)=>({id:V.id,question:V.question})),K=(X||[]).filter((V)=>V?.content||V?.snippet).filter((V)=>!J.has(Z1(V))).slice(0,6).map((V,j)=>({id:V.id||`F${j+1}`,title:V.title||"",url:V.finalUrl||V.url||V.canonicalUrl||"",content:R(V.content||V.snippet||"",5000)}));return["You are doing goal-based evidence extraction for an iterative research run.","For each source, extract only information that helps answer the open questions.","Use original wording/details where useful. Do not invent answers; leave questions open if evidence is insufficient.","If a source answers one or more tracked questions, identify those question IDs explicitly.","Also propose genuinely new sub-questions discovered from the evidence.","",`Original research question: ${$}`,`Open question ledger: ${JSON.stringify(W,null,2)}`,`Fetched sources: ${JSON.stringify(K,null,2)}`,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({extractions:[{sourceId:"S1",url:"https://example.com/source",rational:"why this source matters for the goal",evidence:"specific quoted/paraphrased evidence with numbers, dates, caveats",summary:"concise contribution to the research question",answers:[{id:"Q1",evidence:"brief evidence that closes the question"}],newQuestions:["new sub-question raised by this source"]}]},null,2),"END_JSON"].join(`
|
|
469
|
-
`)}async function W8({query:$,questions:Z,fetchedSources:X,extractedSourceKeys:J}){let W=(X||[]).filter((K)=>(K?.content||K?.snippet)&&!J.has(Z1(K)));if(W.length===0)return{evidence:[],error:""};try{let K=await H0(J9($,Z,W,J),{timeoutMs:120000}),V=U1(K,{extractions:[]}),j=Q8(V,W);for(let Y of W){let Q=Z1(Y);if(Q)J.add(Q)}return{evidence:j,error:""}}catch(K){return{evidence:[],error:K.message||String(K)}}}function W9($,Z,X,J,W,K,V=[]){let j=(Z||[]).filter((F)=>F.status!=="closed").slice(0,12).map((F)=>({id:F.id,question:F.question})),Y=(W||[]).filter((F)=>F?.content||F?.snippet),Q=(K||[]).filter((F)=>F?.content||F?.snippet),H=({extractionCount:F,extractionLimit:P,learningCount:w,learningLimit:g})=>{let d=Y.slice(0,F).map((x,i)=>({id:x.id||`F${i+1}`,title:x.title||"",url:x.finalUrl||x.url||x.canonicalUrl||"",content:R(x.content||x.snippet||"",P)})),f=Q.slice(0,w).map((x,i)=>({id:`F${i+1}`,title:x.title||"",url:x.finalUrl||x.url||"",snippet:R(x.content||x.snippet||"",g)}));return["You are doing two combined research tasks for one round of an iterative research run. Perform BOTH tasks and return a single combined JSON object.","","TASK A — Goal-based evidence extraction:","For each source under 'Sources for evidence extraction', extract only information that helps answer the open questions.","Use original wording/details where useful. Do not invent answers; leave questions open if evidence is insufficient.","If a source answers one or more tracked questions, identify those question IDs explicitly.","Also propose genuinely new sub-questions discovered from the evidence.","","TASK B — Compact research-state learning extraction:","Using the round queries, question ledger, extracted source evidence, engine summaries, and fetched source snippets below, create dense, non-overlapping learnings with exact names, numbers, dates, limitations, and caveats where available.","Also propose follow-up search queries that would most improve confidence or fill gaps.","",`Original research question: ${$}`,`Open question ledger: ${JSON.stringify(j)}`,`Round queries: ${JSON.stringify(X)}`,`Question ledger: ${JSON.stringify(Z)}`,`Extracted source evidence so far: ${JSON.stringify(V.slice(-12))}`,`Engine summaries: ${JSON.stringify(J)}`,`Sources for evidence extraction (Task A): ${JSON.stringify(d)}`,`Fetched source snippets (Task B context): ${JSON.stringify(f)}`,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers, combining both tasks into one object:","BEGIN_JSON",JSON.stringify({extractions:[{sourceId:"S1",url:"https://example.com/source",rational:"why this source matters for the goal",evidence:"specific quoted/paraphrased evidence with numbers, dates, caveats",summary:"concise contribution to the research question",answers:[{id:"Q1",evidence:"brief evidence that closes the question"}],newQuestions:["new sub-question raised by this source"]}],learnings:["concise, information-dense learning"],answeredQuestions:[{id:"Q1",evidence:"brief evidence that closes this question",sourceIds:["S1"]}],newQuestions:["new sub-question discovered from the evidence"],followUpQueries:["specific next search query"],gaps:["important uncertainty or missing evidence"]},null,2),"END_JSON"].join(`
|
|
470
|
-
`)},B=Math.min(4,Y.length),N=3000,G=Math.min(6,Q.length),O=2000,M=H({extractionCount:B,extractionLimit:N,learningCount:G,learningLimit:O}),D=!1,z=600;while(M.length>h7){if(N>z||O>z)N=Math.max(z,Math.floor(N/2)),O=Math.max(z,Math.floor(O/2));else if(G>1)G-=1;else if(B>1)B-=1;else if(N>1||O>1)N=Math.max(1,Math.floor(N/2)),O=Math.max(1,Math.floor(O/2));else throw Error(`[greedysearch] evidence/learning prompt exceeds Gemini input cap after source trimming: ${M.length} chars`);D=!0,M=H({extractionCount:B,extractionLimit:N,learningCount:G,learningLimit:O})}if(D)console.error(`[greedysearch] evidence/learning prompt trimmed to fit Gemini input cap: ${M.length} chars`);return M}async function K9({query:$,questions:Z,fetchedSources:X,extractedSourceKeys:J,roundQueries:W,searchSummaries:K,evidenceItems:V=[]}){let j=(X||[]).filter((N)=>(N?.content||N?.snippet)&&!J.has(Z1(N))),Y=[],Q="",H={learnings:[],followUpQueries:[],gaps:[]},B="";try{let N=await H0(W9($,Z,W,K,j,X,V),{timeoutMs:180000}),G=U1(N,{});Y=Q8(G,j);for(let O of j){let M=Z1(O);if(M)J.add(M)}H={...H,...G}}catch(N){let G=N.message||String(N);Q=G,B=G}return{evidence:Y,evidenceError:Q,learningPayload:H,learningError:B}}function T$($,Z,X,J=[],W=[]){let K=Z.flatMap((Y)=>Y.learnings||[]),V=Z.flatMap((Y)=>Y.gaps||[]),j=X.slice(0,12).map((Y)=>({id:Y.id,title:Y.title,domain:Y.domain,url:Y.canonicalUrl,type:Y.sourceType,engines:Y.engines,fetch:Y.fetch?.attempted?{ok:Y.fetch.ok,snippet:R(Y.fetch.snippet||"",1200),publishedTime:Y.fetch.publishedTime||""}:void 0}));return["You are writing the final research report for an iterative deep-research run.","Produce a thorough markdown report organized into clear sections.","","Use the learnings and source registry below. Every substantive claim MUST be backed by an [S1] citation.",'Where engines disagree, surface the conflicting claims explicitly in the "differences" array.','Include a "Key Claims" structure that maps each distinct claim to its supporting source IDs.',"","Report structure:","1. ## Summary — A 2-4 sentence executive summary of findings","2. ## Key Findings — The main findings, organized by theme or question, each with inline citations","3. ## Areas of Disagreement — Where engines or sources conflict (if any)","4. ## Limitations & Caveats — Important qualifiers, gaps, or uncertainties","",`Original research question: ${$}`,`Learnings: ${JSON.stringify(K,null,2)}`,`Known gaps/caveats: ${JSON.stringify(V,null,2)}`,`Question ledger: ${JSON.stringify(J,null,2)}`,`Goal-based extracted evidence: ${JSON.stringify(W.slice(-20),null,2)}`,`Source registry: ${JSON.stringify(j,null,2)}`,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({answer:"markdown report with sections and inline [S1] citations",agreement:{level:"high|medium|low|mixed|conflicting",summary:"one-sentence confidence summary"},differences:["notable disagreement or conflict between sources"],caveats:["important caveat or qualification"],claims:[{claim:"specific factual statement from the research",support:"strong|moderate|weak|conflicting",sourceIds:["S1","S2"]}],recommendedSources:["S1","S2"]},null,2),"END_JSON"].join(`
|
|
471
|
-
`)}function C$($,Z=[],X=[],J=[]){let W=Z.slice(0,12).map((Y)=>({id:Y.id,title:Y.title,domain:Y.domain,url:Y.canonicalUrl,type:Y.sourceType,engines:Y.engines})),K=J.slice(-20),V=new Set;for(let Y of K)for(let Q of Y.answers||[])if(Q?.id)V.add(Q.id);let j=(X||[]).filter((Y)=>Y.status!=="closed").map((Y)=>({id:Y.id,question:Y.question}));return["You are writing the final research report from goal-based extracted evidence.","Per-round learnings were not produced, but the per-source evidence extraction step succeeded.","Synthesize a thorough markdown report using ONLY the evidence below. Every substantive claim MUST be backed by an [S1] citation.","","Report structure:","1. ## Summary — A 2-4 sentence executive summary of findings","2. ## Key Findings — The main findings, organized by theme or question, each with inline citations","3. ## Limitations & Caveats — Important qualifiers, gaps, or uncertainties","",`Original research question: ${$}`,`Per-source extracted evidence: ${JSON.stringify(K,null,2)}`,`Source registry: ${JSON.stringify(W,null,2)}`,`Questions already answered by the evidence: ${JSON.stringify(Array.from(V))}`,`Questions still open after this evidence: ${JSON.stringify(j)}`,"","Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:","BEGIN_JSON",JSON.stringify({answer:"markdown report with sections and inline [S1] citations",agreement:{level:"high|medium|low|mixed|conflicting",summary:"one-sentence confidence summary"},differences:["notable disagreement or conflict between sources"],caveats:["important caveat or qualification"],claims:[{claim:"specific factual statement supported by the evidence",support:"strong|moderate|weak|conflicting",sourceIds:["S1","S2"]}],recommendedSources:["S1","S2"]},null,2),"END_JSON"].join(`
|
|
472
|
-
`)}async function V9($,{locale:Z=null,short:X=!0}={}){let J=[g7,"all","--inline","--stdin","--fast"];if(!X)J.push("--full");if(Z)J.push("--locale",Z);return new Promise((W,K)=>{let V=b7(Q0(),J,{stdio:["pipe","pipe","pipe"],env:{...process.env,GREEDY_SEARCH_RESEARCH_CHILD:"1"}});V.stdin.write($),V.stdin.end();let j="",Y="",Q="";V.stdout.on("data",(B)=>j+=B),V.stderr.on("data",(B)=>{Y+=B,Q+=B.toString();let N=Q.split(`
|
|
473
|
-
`);Q=N.pop()||"";for(let G of N)if(H9(G))process.stderr.write(`${G}
|
|
474
|
-
`)});let H=setTimeout(()=>{V.kill(),K(Error(`research child search timed out for: ${$}`))},140000);V.on("close",(B)=>{if(clearTimeout(H),B!==0){K(Error(Y.trim()||`search child exited with code ${B}`));return}try{W(JSON.parse(j.trim()))}catch{K(Error(`Invalid JSON from research child: ${j.slice(0,200)}`))}})})}function j9($){let Z=new Map;for(let X of $.flat()){let J=e(X.canonicalUrl||X.url);if(!J)continue;let W=Z.get(J);if(!W){Z.set(J,{...X,canonicalUrl:J});continue}W.engines=[...new Set([...W.engines||[],...X.engines||[]])],W.engineCount=W.engines.length,W.smartScore=Math.max(W.smartScore||0,X.smartScore||0)}return Array.from(Z.values()).sort((X,J)=>{let W=c0(J)-c0(X);if(W!==0)return W;return(X.domain||"").localeCompare(J.domain||"")}).slice(0,12).map((X,J)=>({...X,id:`S${J+1}`}))}var Y9=r.join("|"),Q9=new RegExp(`^\\[(${Y9})\\]`);function H9($){return/^PROGRESS:/.test($)||/^\[greedysearch\]/.test($)||Q9.test($)||/^GreedySearch Chrome/.test($)||/^Launching GreedySearch Chrome/.test($)||/^Headless mode/.test($)||/^Ready\.?$/.test($)}function U1($,Z={}){return D0($?.answer||"")||Z}function R$($,Z){if(!$||!Array.isArray(Z))return{cited:[],missing:[],unfetched:[],ok:!0};let X=/\b[SF](\d+)\b/g,J=new Set,W;while((W=X.exec($))!==null)J.add(`S${W[1]}`),J.add(`F${W[1]}`);let K=new Map;for(let Q of Z){let H=Q?.id;if(H)K.set(H,Q)}let V=Array.from(J),j=[],Y=[];for(let Q of V){let H=K.get(Q);if(!H){let B=Q.match(/^(S|F)(\d+)$/);if(B){let N=parseInt(B[2],10)-1;if(N>=0&&N<Z.length){let G=Z[N];if(G){if(!(G.fetch?.ok||G.content&&G.content.length>100||G.contentChars&&G.contentChars>100))Y.push(Q);continue}}}j.push(Q)}else if(!(H.fetch?.ok||H.content&&H.content.length>100||H.contentChars&&H.contentChars>100))Y.push(Q)}return{cited:V,missing:j,unfetched:Y,ok:j.length===0}}async function B9($,{timeoutMs:Z=6000,concurrency:X=4}={}){let J=Math.max(1,Math.floor(X||1)),W=($||[]).filter((N)=>N?.id&&(N?.canonicalUrl||N?.finalUrl||N?.url));if(W.length===0)return{reachable:[],dead:[],skipped:[],ok:!0};let K=[],V=[],j=[],Y=Array(W.length),Q=0;async function H(){while(!0){let N=Q++;if(N>=W.length)return;let G=W[N];try{let O=G.fetch?.finalUrl||G.canonicalUrl||G.finalUrl||G.url;if(!O){Y[N]={id:G.id,url:"",status:"skipped"};continue}try{let M=new URL(O);if(M.protocol!=="http:"&&M.protocol!=="https:"){Y[N]={id:G.id,url:O,status:"skipped"};continue}}catch{Y[N]={id:G.id,url:O,status:"skipped"};continue}try{let M=new AbortController,D=setTimeout(()=>M.abort(),Z);try{let z=await fetch(O,{method:"HEAD",redirect:"follow",signal:M.signal,headers:{"User-Agent":"Mozilla/5.0 (compatible; GreedySearch/2.0; +https://github.com/apmantza/greedysearch-dm)"}});clearTimeout(D);let F=z.status>=200&&z.status<400,P=[401,403,405,429].includes(z.status),w="dead";if(F)w="reachable";else if(P)w="skipped";Y[N]={id:G.id,url:O,status:w,httpStatus:z.status,reason:P?"bot-protected-or-head-disallowed":void 0}}catch(z){clearTimeout(D),Y[N]={id:G.id,url:O,status:"dead",error:z.name==="AbortError"?"timeout":z.message}}}catch(M){Y[N]={id:G.id,url:O,status:"dead",error:M.message}}}catch(O){Y[N]={id:"?",url:"",status:"dead",error:O?.message||"unknown"}}}}let B=Math.min(W.length,J);await Promise.all(Array.from({length:B},()=>H()));for(let N of Y)if(N.status==="reachable")K.push(N);else if(N.status==="dead")V.push(N);else j.push(N);return{reachable:K,dead:V,skipped:j,ok:V.length===0}}async function v$($,Z=null){process.stderr.write(`PROGRESS:research:check-urls
|
|
475
|
-
`);try{let X=new Set(Z?.cited||[]),J=X.size?($||[]).filter((K)=>X.has(K?.id)):$,W=await B9(J,{timeoutMs:6000,concurrency:4});if(!W.ok)process.stderr.write(`[greedysearch] ${W.dead.length} dead citation URL(s) detected
|
|
476
|
-
`);return W}catch(X){return process.stderr.write(`[greedysearch] URL reachability check failed: ${X.message}
|
|
477
|
-
`),null}}function c1({sources:$=[],fetchedSources:Z=[],synthesis:X={},citationAudit:J=null,gaps:W=[],questions:K=[],rounds:V=[],qualityScore:j=0,qualityThreshold:Y=8.5,maxSources:Q=8,requireCitations:H=!0,requireQuestions:B=!0}={}){let N=Z.filter((f)=>f?.fetch?.ok||(f?.contentChars||0)>100||String(f?.content||"").length>100),G=$.filter((f)=>["official-docs","repo","maintainer-blog","academic"].includes(String(f?.sourceType||""))),O=Array.isArray(X?.claims)?X.claims:[],M=J?J.cited?.length||0:0,D=p$(K),z=(K||[]).filter((f)=>!f.createdRound||f.reason==="Original research question"),F=p$(z),P=(V||[]).length,w=Math.min(4,Math.max(2,Number(Q)||8)),g=P<=1?Math.min(2,w):w,d={roundsRun:V.length>=1,fetchedSources:N.length>=g,primarySources:G.length>=1,qualityScore:j>=Math.min(Y,8)||H&&O.length>0&&M>0,claimsExtracted:!H||O.length>0,citationsPresent:!H||M>0,citationsValid:!H||J?.ok===!0,unfetchedCitations:!H||(J?.unfetched||[]).length===0,requiredQuestionsClosed:!B||F.open===0};return{floorMet:Object.values(d).every(Boolean),checks:d,metrics:{fetchedOk:N.length,primarySources:G.length,claims:O.length,cited:M,gaps:W.length,openQuestions:D.open,closedQuestions:D.closed,totalQuestions:D.total,openRequiredQuestions:F.open,closedRequiredQuestions:F.closed,totalRequiredQuestions:F.total,qualityScore:j,minFetched:g}}}function K8($,Z){let X=new Map;for(let J of Z||[]){let W=e(J?.canonicalUrl||J?.finalUrl||J?.url);if(W&&J?.id)X.set(W,J.id)}return($||[]).map((J,W)=>{let K=e(J?.finalUrl||J?.canonicalUrl||J?.url);return{...J,id:J?.id||X.get(K)||`F${W+1}`}})}function I$($){return[{id:"Q1",question:R(z0($),320),status:"open",reason:"Original research question",evidence:[],sourceIds:[]}]}function G9($){let Z=0;for(let X of $||[]){let J=Number.parseInt(String(X.id||"").replace(/^Q/i,""),10);if(Number.isFinite(J))Z=Math.max(Z,J)}return`Q${Z+1}`}function H8($,Z){let X=z0(Z).toLowerCase();return($||[]).find((J)=>J.question?.toLowerCase()===X||m$(J.question||"",X)>=0.82)}function S$($,Z,{reason:X="",round:J=null}={}){let W=R(z0(Z),320);if(!W)return null;let K=H8($,W);if(K)return K;let V={id:G9($),question:W,status:"open",reason:R(X,240),createdRound:J,evidence:[],sourceIds:[]};return $.push(V),V}function i1($,Z,{evidence:X="",sourceIds:J=[],round:W=null}={}){let K=$.find((V)=>V.id===Z)||H8($,Z);if(!K)return null;if(K.status="closed",K.closedRound=K.closedRound||W,X)K.evidence=R0([...K.evidence||[],X],4);if(Array.isArray(J))K.sourceIds=R0([...K.sourceIds||[],...J],8);return K}function p$($){let Z=$.length,X=$.filter((J)=>J.status==="closed").length;return{total:Z,closed:X,open:Math.max(0,Z-X)}}function n1($,{roundNumber:Z,actions:X=[],learningPayload:J={}}={}){for(let Y of X){let Q=Y?.action||Y,H=Q?.researchGoal&&Q.researchGoal!=="Original user query"?Q.researchGoal:Q?.query||Q?.url||"";if(H)S$($,H,{reason:"Planned research action",round:Z})}let W=5,K=$.filter((Y)=>Y.status==="open"&&Y.reason==="Discovered gap/follow-up");if(K.length>W){let Y=K.sort((Q,H)=>(Q.createdRound||0)-(H.createdRound||0)).slice(0,K.length-W);for(let Q of Y)Q.status="resolved",Q.closedRound=Z,Q.evidence=R0([...Q.evidence||[],"Auto-resolved to cap open-question ledger"],4)}let V=Array.isArray(J.answeredQuestions)?J.answeredQuestions:[];for(let Y of V){if(typeof Y==="string"){i1($,Y,{round:Z});continue}let Q=Y?.id||Y?.question;if(!Q&&Y?.question){let H=S$($,Y.question,{reason:"Answered during learning extraction",round:Z});if(H)i1($,H.id,{round:Z});continue}i1($,Q,{evidence:Y?.evidence||Y?.answer||"",sourceIds:Array.isArray(Y?.sourceIds)?Y.sourceIds:[],round:Z})}let j=Array.isArray(J.newQuestions)?J.newQuestions:[];for(let Y of j)S$($,Y,{reason:"Discovered gap/follow-up",round:Z});return $}function N9($,Z){if(!Array.isArray($)||$.length===0)return[];let X=["arxiv.org","semanticscholar.org","doi.org"],J=new Set,W=[];for(let K of $){let V=K?.canonicalUrl||K?.finalUrl||K?.url||"";if(!V)continue;let j="";try{j=new URL(V).hostname.toLowerCase().replace(/^www\./,"")}catch{continue}if(!X.some((Q)=>j===Q||j.endsWith(`.${Q}`)))continue;if(Z.has(V)||J.has(V))continue;J.add(V);let Y=V.includes("/pdf/")?V.replace(/\/pdf\//,"/html/").replace(/\.pdf$/i,""):V;W.push({url:Y,label:K?.title||K?.id||j})}return W.slice(0,2)}function E$($,Z,X){if(!Z?.answer||X?.ok!==!0)return $;let J=Array.isArray(Z.claims)?Z.claims:[],W=Array.isArray(X.cited)?X.cited:[];if(J.length===0||W.length===0)return $;for(let K of $){if(K.status==="closed")continue;let V=null,j=0;for(let Y of J){let Q=m$(K.question||"",Y.claim||"");if(Q>j)j=Q,V=Y}if(K.id==="Q1"||j>=0.18)i1($,K.id,{evidence:V?.claim||"Answered in final cited synthesis",sourceIds:Array.isArray(V?.sourceIds)?V.sourceIds:W.slice(0,4)})}return $}function O9($){if(!$.length)return"No tracked questions.";return $.map((Z)=>{let X=Z.sourceIds?.length?` (${Z.sourceIds.join(", ")})`:"";return`- [${Z.status==="closed"?"x":" "}] ${Z.id}: ${Z.question}${X}`}).join(`
|
|
478
|
-
`)}function g$($,Z="None recorded."){let X=R0($);return X.length?X.map((J)=>`- ${J}`).join(`
|
|
479
|
-
`):Z}function M9($,{query:Z,rounds:X,sources:J,fetchedSources:W,citationAudit:K,citationUrls:V,floor:j,manifest:Y}){let Q=(W||[]).filter((M)=>M?.contentChars>100||M?.fetch?.ok),H=(J||[]).filter((M)=>["official-docs","repo","maintainer-blog","academic"].includes(String(M?.sourceType||""))),B=new Set(K?.cited||[]),N=(J||[]).filter((M)=>B.has(M?.id)),G=[`# Provenance: ${Z}`,"",`- **Date:** ${Y?.startedAt||new Date().toISOString()}`,`- **Duration:** ${Y?.durationMs?`${(Y.durationMs/1000).toFixed(1)}s`:"unknown"}`,`- **Mode:** ${Y?.terminationReason==="simple_single_pass"?"simple (single-pass)":"iterative"}`,`- **Rounds:** ${Y?.rounds||X?.length||1}`,"","## Sources","",`- **Consulted:** ${J?.length||0}`,`- **Fetched successfully:** ${Q.length}`,`- **Primary sources:** ${H.length}`,`- **Cited in report:** ${N.length}`,""];if(N.length>0){G.push("### Cited sources","");for(let M of N){let D=M.canonicalUrl||M.finalUrl||M.url||"",z=M.fetch?.ok?"✓":"✗";G.push(`- **${M.id}:** [${M.title||D}](${D}) (${M.sourceType||"unknown"}, fetched: ${z})`)}G.push("")}if(V&&(V.reachable.length>0||V.dead.length>0)){if(G.push("## URL reachability",""),V.dead.length>0){G.push(""),G.push("**Dead links:**");for(let M of V.dead)G.push(`- ${M.id}: ${M.url} (${M.httpStatus||M.error||"unknown"})`)}if(V.reachable.length>0)G.push(""),G.push(`**Reachable:** ${V.reachable.length}/${V.reachable.length+V.dead.length}`);G.push("")}let O=!K?"NOT CHECKED":K.ok&&(V?.ok??!0)?"PASS":K.ok===!1?"FAIL (missing citations)":"FAIL (dead links)";if(G.push("## Verification","",`- **Citations:** ${K?.ok?"PASS":`FAIL — missing: ${(K?.missing||[]).join(", ")}`}`,`- **URL reachability:** ${V?V.ok?"PASS":`FAIL — ${V.dead.length} dead`:"SKIPPED"}`,`- **Floor:** ${j?.floorMet?"PASS":"PARTIAL"}`,`- **Overall:** ${O}`,""),j?.checks){G.push("## Floor checks","");for(let[M,D]of Object.entries(j.checks))G.push(`- [${D?"x":" "}] ${M}`);G.push("")}V0(m($,"provenance.md"),G.join(`
|
|
480
|
-
`),"utf8")}async function q$({query:$,rounds:Z,sources:X,fetchedSources:J,evidenceItems:W=[],synthesis:K,citationAudit:V,floor:j,manifest:Y,allGaps:Q=[],questions:H=[],citationUrls:B=null,outDir:N=null}){let G=new Date().toISOString().replaceAll(/[:.]/g,"-").slice(0,19),O=N||m(y7,`${G}_${p7($)}`),M=m(O,"reports"),D=m(O,"sources"),z=m(O,"data");f$(M,{recursive:!0}),f$(D,{recursive:!0}),f$(z,{recursive:!0});let F=await y$(J,D),P=R0([...Q,...Z.flatMap((w)=>w.gaps||[])]);V0(m(O,"STATUS.md"),[j.floorMet?"STATUS: DONE":"STATUS: PARTIAL","",`Query: ${$}`,`Stop reason: ${Y.terminationReason||"max_rounds"}`,"","## Deterministic floor checks",...Object.entries(j.checks).map(([w,g])=>`- [${g?"x":" "}] ${w}`),"","## Questions",O9(H),"","## Open gaps",g$(P),""].join(`
|
|
481
|
-
`),"utf8"),V0(m(O,"OUTLINE.md"),["# Research bundle outline","","- `reports/SUMMARY.md` — final cited report","- `reports/CLAIMS.md` — extracted claims with support/source IDs","- `reports/EVIDENCE.md` — goal-based source evidence","- `reports/GAPS.md` — remaining caveats and uncertainties","- `provenance.md` — human-readable run metadata and verification","- `sources/` — fetched source markdown files","- `data/manifest.json` — machine-readable run metadata","- `data/rounds.json` — per-round actions/learnings/gaps","- `data/sources.json` — ranked source registry","- `data/questions.json` — open/closed question ledger",""].join(`
|
|
482
|
-
`),"utf8"),V0(m(M,"SUMMARY.md"),String(K.answer||""),"utf8"),V0(m(M,"CLAIMS.md"),["# Key claims","",...Array.isArray(K.claims)&&K.claims.length?K.claims.map((w)=>{let g=Array.isArray(w.sourceIds)?w.sourceIds.join(", "):"";return`- ${w.claim||""} (${w.support||"support unknown"}${g?`; ${g}`:""})`}):["No structured claims were extracted."],""].join(`
|
|
483
|
-
`),"utf8"),V0(m(M,"EVIDENCE.md"),["# Extracted evidence","",...W.length?W.map((w)=>[`## ${w.sourceId||w.url||"Source"}`,w.url?`<${w.url}>`:"",w.rational?`**Rational:** ${w.rational}`:"",w.evidence?`**Evidence:** ${w.evidence}`:"",w.summary?`**Summary:** ${w.summary}`:"",""].filter(Boolean).join(`
|
|
484
|
-
`)):["No goal-based evidence was extracted."],""].join(`
|
|
485
|
-
`),"utf8"),V0(m(M,"GAPS.md"),["# Gaps and caveats","","## Caveats",g$(K.caveats||[]),"","## Research gaps",g$(P),""].join(`
|
|
486
|
-
`),"utf8"),V0(m(z,"manifest.json"),JSON.stringify({...Y,floor:j,citationAudit:V},null,2),"utf8"),V0(m(z,"rounds.json"),JSON.stringify(Z,null,2),"utf8"),V0(m(z,"sources.json"),JSON.stringify(X,null,2),"utf8"),V0(m(z,"questions.json"),JSON.stringify(H,null,2),"utf8"),V0(m(z,"evidence.json"),JSON.stringify(W,null,2),"utf8"),V0(m(D,"index.md"),["# Source index","",...F.map((w)=>{let g=w.title||w.url,d=w.finalUrl||w.url,f=w.contentPath?` — ${w.contentPath}`:"";return`- ${w.id||"?"}: [${g}](${d})${f}`}),""].join(`
|
|
487
|
-
`),"utf8");try{M9(O,{query:$,rounds:Z,sources:X,fetchedSources:J,citationAudit:V,citationUrls:B,floor:j,manifest:Y})}catch(w){process.stderr.write(`[greedysearch] Provenance sidecar write failed (non-critical): ${w.message}
|
|
488
|
-
`)}return{dir:O,statusPath:m(O,"STATUS.md"),summaryPath:m(M,"SUMMARY.md"),manifestPath:m(z,"manifest.json"),provenancePath:m(O,"provenance.md"),sourceCount:F.length,sourceFiles:F}}async function B8({query:$,breadth:Z,iterations:X,maxSources:J,locale:W=null,short:K=!1,qualityThreshold:V=8.5,writeBundle:j=process.env.GREEDY_RESEARCH_BUNDLE!=="0",researchOutDir:Y=null}={}){let Q=d7({breadth:Z,iterations:X,maxSources:J}),H=Z!==void 0&&Z!==null,B=X!==void 0&&X!==null;if(!H&&!B)try{let _=await Z8($);if(process.stderr.write(`[greedysearch] Complexity: ${_.complexity} (${_.reasoning})
|
|
489
|
-
`),_.complexity==="simple")return process.stderr.write(`[greedysearch] Simple query detected — using fast single-pass path
|
|
490
|
-
`),J8({query:$,locale:W,maxSources:Math.min(J??5,5),qualityThreshold:V,writeBundle:j,researchOutDir:Y});if(!H)Q.breadth=_.suggestedBreadth;if(!B)Q.iterations=_.suggestedIterations}catch(_){process.stderr.write(`[greedysearch] Scale classification failed, using defaults: ${_.message}
|
|
491
|
-
`)}let G=[],O=[],M=[],D=I$($),z=null,F=[],P=[],w=[],g=new Set,d=new Set,f=new Set,x=[],i="max_rounds",B0=new Date().toISOString(),o=Date.now(),J0=0,T=0,$0=0,c=[],s=u1({totalActions:Q.iterations*Q.breadth,totalRounds:Q.iterations,totalFetches:Q.iterations,silent:process.env.GREEDY_RESEARCH_QUIET==="1"});s.startRound(1),process.stderr.write(`[greedysearch] Research mode: breadth ${Q.breadth}, iterations ${Q.iterations}, qualityThreshold ${V}, engines ${j1.join(",")}, synthesizer gemini
|
|
492
|
-
`);for(let _=0;_<Q.iterations;_++){let A=_+1,h=Math.max(1,Math.ceil(Q.breadth/2**_));if(process.stderr.write(`PROGRESS:research:round-${A}:planning
|
|
493
|
-
`),!z)try{let U=await H0(s7($,h,O,M,[...f]),{timeoutMs:120000}),q=Z9(U,h);if(_===0)q.unshift({type:"search",query:$,researchGoal:"Original user query"});q=await $9(q,f),z=q}catch(U){process.stderr.write(`[greedysearch] Action planning failed, using fallback queries: ${U.message}
|
|
494
|
-
`);let q=l7(null,$,h,{includeOriginal:_===0,exclude:d});z=X9(q)}let j0=(z||[]).filter((U)=>{if(U.type==="search"){let q=!j8(U.query,d,{roundIndex:_,originalQuery:$});if(!q)process.stderr.write(`[greedysearch] Novelty gate rejected search: ${U.query}
|
|
495
|
-
`);return q}if(U.type==="fetchUrl"){let q=!f.has(U.url);if(!q)process.stderr.write(`[greedysearch] Novelty gate rejected fetch: ${U.url}
|
|
496
|
-
`);return q}return!1}).slice(0,h),S=N9(F,f);if(!j0.some((U)=>U.type==="fetchUrl")&&S.length>0){let U=S[0];j0.push({type:"fetchUrl",url:U.url,researchGoal:`Direct fetch of known academic source: ${U.label||U.url}`}),process.stderr.write(`[greedysearch] Forced fetchUrl for academic source: ${U.url}
|
|
497
|
-
`)}let p=Array(j0.length),l=Math.min(3,j0.length),Y0=0;async function x0(){while(!0){let U=Y0++;if(U>=j0.length)return;let q=j0[U];process.stderr.write(`PROGRESS:research:round-${A}:action-${U+1}/${j0.length}
|
|
498
|
-
`),process.stderr.write(`[greedysearch] Action ${U+1}/${j0.length} [${q.type}]: ${(q.query||q.url).slice(0,80)}
|
|
499
|
-
`),s.startAction(q.type,(q.query||q.url||"").slice(0,60));let t=await t7(q,{locale:W,short:K,usedQueries:d,usedUrls:f,maxChars:8000});s.endAction(),p[U]=t}}await Promise.all(Array.from({length:l},()=>x0()));let F0=[];for(let U=0;U<j0.length;U++){let q=j0[U],t=p[U];if(F0.push(t),J0++,q.type==="search")T++;if(q.type==="fetchUrl")$0++,s.endFetch(t.ok);if(!t.ok)c.push({round:A,type:q.type,target:q.query||q.url,error:t.error}),process.stderr.write(`[greedysearch] Action failed: ${t.error}
|
|
500
|
-
`)}let l$=F0.filter((U)=>U.action.type==="search"),u$=F0.filter((U)=>U.action.type==="fetchUrl");n1(D,{roundNumber:A,actions:F0}),F=j9([F,l$.flatMap((U)=>U.sources||[]),u$.flatMap((U)=>U.sources||[])]);for(let U of u$)if(U.fetchResult)P.push(U.fetchResult);P=V8(P);let o1=Math.max(0,Q.maxSources-P.filter((U)=>U?.content||U?.contentChars>100).length);if(o1>0&&F.length>0){process.stderr.write(`PROGRESS:research:round-${A}:fetching
|
|
501
|
-
`);let U=new Set,q=(P0)=>{try{return e(P0||"")}catch{return""}};for(let P0 of P)for(let w1 of[P0?.url,P0?.finalUrl,P0?.canonicalUrl]){let o0=q(w1);if(o0)U.add(o0)}let t=F.filter((P0)=>{let w1=[P0?.canonicalUrl,P0?.finalUrl,P0?.url].map((o0)=>q(o0)).filter(Boolean);return w1.length>0&&w1.every((o0)=>!U.has(o0))}),D8=await m7(t,Math.min(o1,t.length),8000,Math.min(3,o1||1));P=V8([...P,...D8]),F=r0(F,P)}P=K8(P,F);let M8=F0.map((U)=>({query:U.action.query||U.action.url||"",researchGoal:U.action.researchGoal||""}));process.stderr.write(`PROGRESS:research:round-${A}:evidence
|
|
502
|
-
`),process.stderr.write(`PROGRESS:research:round-${A}:learning
|
|
503
|
-
`);let F1=await K9({query:$,questions:D,fetchedSources:P,extractedSourceKeys:g,roundQueries:M8,searchSummaries:l$.map((U)=>({query:U.action.query,researchGoal:U.action.researchGoal,error:U.error||"",engines:o7(U.result)})),evidenceItems:w}),i0={evidence:F1.evidence,error:F1.evidenceError};if(i0.error)process.stderr.write(`[greedysearch] Evidence extraction failed: ${i0.error}
|
|
504
|
-
`);w=[...w,...i0.evidence];for(let U of i0.evidence)n1(D,{roundNumber:A,learningPayload:{answeredQuestions:U.answers||[],newQuestions:U.newQuestions||[]}});let{learningPayload:a0,learningError:s1}=F1;if(s1)process.stderr.write(`[greedysearch] Learning extraction failed: ${s1}
|
|
505
|
-
`);let c$=Array.isArray(a0.learnings)?a0.learnings.map((U)=>String(U)).filter(Boolean).slice(0,8):[],t1=Array.isArray(a0.gaps)?a0.gaps.map((U)=>String(U)).filter(Boolean).slice(0,6):[];if(O=R0([...O,...c$]),M=R0([...M,...t1]),n1(D,{roundNumber:A,actions:[],learningPayload:a0,gaps:t1}),G.push({round:A,actions:F0.map((U)=>({type:U.action.type,query:U.action.query||"",url:U.action.url||"",researchGoal:U.action.researchGoal||"",error:U.error||"",sourceCount:U.sources?.length||0})),learnings:c$,gaps:t1,evidence:i0.evidence,evidenceError:i0.error,learningError:s1}),process.stderr.write(`PROGRESS:research:round-${A}:evaluating
|
|
506
|
-
`),s.endRound(),A<Q.iterations)s.startRound(A+1);let K0=A===Q.iterations?{score:x.length>0?x[x.length-1]:5,coverage:{},knowledgeGaps:[],shouldContinue:!1,nextActions:[],terminationReason:null,evaluationError:""}:await a7($,G,O,M,x);x.push(K0.score),M=R0([...M,...K0.knowledgeGaps||[]]),n1(D,{roundNumber:A,gaps:K0.knowledgeGaps||[]});let n$=c1({sources:F,fetchedSources:P,gaps:M,questions:D,rounds:G,qualityScore:K0.score,qualityThreshold:V,maxSources:Q.maxSources,requireCitations:!1,requireQuestions:!1});if(process.stderr.write(`[greedysearch] Quality score round ${A}: ${K0.score.toFixed(1)} (shouldContinue: ${K0.shouldContinue}, floor: ${n$.floorMet})
|
|
507
|
-
`),K0.score>=V&&n$.floorMet&&(!K0.shouldContinue||K0.terminationReason==="quality_threshold")){i=K0.terminationReason||"quality_threshold",process.stderr.write(`[greedysearch] Research floor reached (score: ${K0.score.toFixed(1)}). Terminating early.
|
|
508
|
-
`);break}let S0=Math.max(1,Math.ceil(h/2)),w0=(a0.followUpQueries||[]).map((U)=>({type:"search",query:z0(String(U)),researchGoal:"Follow-up from learning extraction"})).filter((U)=>U.query&&U.query.toLowerCase()!==$.toLowerCase()).slice(0,S0);if(w0.length<S0&&K0.nextActions.length>0){let U=K0.nextActions.map((t)=>Y8(t)).filter(Boolean);w0=[...w0,...U].slice(0,S0)}if(w0.length<S0&&M.length>0){let U=i7(M,$,d,S0-w0.length,_+1),q=U.map((t)=>({type:"search",query:t.query,researchGoal:t.researchGoal}));if(w0=[...w0,...q].slice(0,S0),U.length>0)process.stderr.write(`[greedysearch] Generated ${U.length} gap-driven fallback actions.
|
|
509
|
-
`)}z=w0.length>=S0?w0:null}process.stderr.write(`PROGRESS:research:final-report
|
|
510
|
-
`);let E={answer:O.length?O.map((_)=>`- ${_}`).join(`
|
|
511
|
-
`):"Research completed, but no structured learnings were extracted.",agreement:{level:"mixed",summary:"Research synthesis fallback."},differences:[],caveats:[],claims:[],recommendedSources:F.slice(0,4).map((_)=>_.id),synthesized:!1};try{let _=await H0(T$($,G,F,D,w),{timeoutMs:180000}),A=U1(_,{}),h=Array.isArray(A?.claims)&&A.claims.length>0;E={...E,...A,rawAnswer:_.answer||"",geminiSources:_.sources||[],synthesized:h}}catch(_){process.stderr.write(`[greedysearch] Final report failed: ${_.message}
|
|
512
|
-
`),E.error=_.message}if(!(E.synthesized===!0&&Array.isArray(E.claims)&&E.claims.length>0)&&w.length>0){process.stderr.write(`[greedysearch] Falling back to evidence-based synthesis (no per-round learnings).
|
|
513
|
-
`);try{let _=C$($,F,D,w),A=await H0(_,{timeoutMs:180000}),h=U1(A,{});E={...E,...h,rawAnswer:A.answer||E.answer||"",geminiSources:A.sources||E.geminiSources||[],synthesized:!0,synthesisMode:"evidence_fallback"}}catch(_){process.stderr.write(`[greedysearch] Evidence-based synthesis failed: ${_.message}
|
|
514
|
-
`),E.evidenceFallbackError=_.message}}let b=new Date().toISOString(),W0=Date.now()-o,k=x.at(-1)||0;P=K8(P,F),process.stderr.write(`PROGRESS:research:audit-citations
|
|
515
|
-
`);let v=R$(E.answer||"",F),J1=await v$(F,v);E$(D,E,v);let a=c1({sources:F,fetchedSources:P,synthesis:E,citationAudit:v,gaps:M,questions:D,rounds:G,qualityScore:k,qualityThreshold:V,maxSources:Q.maxSources});if(a.floorMet&&i==="max_rounds")i="done_floor_met";else if(!a.floorMet&&i==="quality_threshold")i="max_rounds_floor_unmet";let C={startedAt:B0,finishedAt:b,durationMs:W0,engines:j1,synthesizer:"gemini",rounds:G.length,actionsRun:J0,searches:T,fetches:$0,sourcesFetched:P.filter((_)=>_?.contentChars>100).length,engineFailures:c,terminationReason:i,floorMet:a.floorMet},I=null,L;if(j){process.stderr.write(`PROGRESS:research:bundle
|
|
516
|
-
`);try{I=await q$({query:$,rounds:G,sources:F,fetchedSources:P,evidenceItems:w,synthesis:E,citationAudit:v,citationUrls:J1,floor:a,manifest:C,allGaps:M,questions:D,outDir:Y}),L=I.sourceFiles,delete I.sourceFiles}catch(_){I={error:_.message||String(_)},L=await y$(P)}}else L=await y$(P);return process.stderr.write(`PROGRESS:research:done
|
|
517
|
-
`),s.finish(),{query:$,_research:{mode:"iterative",breadth:Q.breadth,iterations:Q.iterations,maxSources:Q.maxSources,rounds:G,learnings:O,gaps:M,evidence:w,questions:D,questionProgress:p$(D),qualityHistory:x,terminationReason:i,qualityThreshold:V,floor:a,bundle:I,manifest:C},_citationAudit:v,_citationUrls:J1,_sources:F,_fetchedSources:L,_synthesis:E,_confidence:{sourcesCount:F.length,fetchedSourceSuccessRate:P.length>0?Number((P.filter((_)=>_.contentChars>100).length/P.length).toFixed(2)):0,agreementLevel:E.agreement?.level||"mixed",floorMet:a.floorMet}}}function V8($){let Z=new Map;for(let V of $){let j=V?.id||e(V?.finalUrl||V?.url||"");if(!j)continue;let Y=Z.get(j);if(!Y||(V.contentChars||0)>(Y.contentChars||0))Z.set(j,V)}let X=new Map;function J(V){let j=X.get(V);if(!j){let Y=String(V.content||V.snippet||"");j={length:Y.length,tokens:h$(Y.slice(0,4000))},X.set(V,j)}return j}function W(V,j){let Y=0,Q=V.size<=j.size?V:j,H=V.size<=j.size?j:V;for(let N of Q)if(H.has(N))Y++;let B=V.size+j.size-Y;if(B===0)return 1;return Y/B}let K=[];for(let V of Z.values()){let j=J(V),Y=K.findIndex((Q)=>{let H=X.get(Q);if(j.length<400||H.length<400)return!1;return W(j.tokens,H.tokens)>=0.9});if(Y===-1){K.push(V);continue}if((V.contentChars||0)>(K[Y].contentChars||0))K[Y]=V}return K}import D9 from"node:http";function G8($,Z=1000){return new Promise((X)=>{let J=D9.get($,(W)=>{let K="";W.on("data",(V)=>K+=V),W.on("end",()=>X({ok:W.statusCode===200,body:K}))});J.on("error",()=>X({ok:!1})),J.setTimeout(Z,()=>{J.destroy(),X({ok:!1})})})}async function N8($){try{let Z=await G8(`http://localhost:${$}/json/version`);if(!Z.ok)return;let X=JSON.parse(Z.body),J=await G8(`http://localhost:${$}/json/list`);if(!J.ok)return;let K=JSON.parse(J.body).find((Q)=>Q.type==="page")?.id;if(!K)return;let V=X.webSocketDebuggerUrl;if(typeof V!=="string")return;let j=new URL(V);if(j.hostname!=="localhost"&&j.hostname!=="127.0.0.1")return;if(!/^ws:\/\/localhost:\d+/.test(`ws://${j.host}`))return;let Y=new WebSocket(`ws://localhost:${$}${j.pathname}`);await new Promise((Q)=>{let H=!1,B=setTimeout(()=>N(),5000),N=()=>{if(H)return;H=!0,clearTimeout(B);try{Y.close()}catch{}Q()};Y.onopen=()=>{try{Y.send(JSON.stringify({id:1,method:"Browser.getWindowForTarget",params:{targetId:K}}))}catch{N()}},Y.onmessage=(G)=>{try{let O=JSON.parse(G.data);if(O.id===1&&O.result?.windowId)Y.send(JSON.stringify({id:2,method:"Browser.setWindowBounds",params:{windowId:O.result.windowId,bounds:{windowState:"minimized"}}}));else if(O.id===2)N();else if(O.id===1)N()}catch{N()}},Y.onerror=N})}catch{}}W1();var P9=a1(w9(),".config","greedysearch"),O8=a1(P9,"config.json");function _9(){try{if(U9(O8))return JSON.parse(F9(O8,"utf8"))}catch{}return{}}function X1($){try{z9(X2,`${JSON.stringify({at:new Date().toISOString(),...$})}
|
|
518
|
-
`,"utf8")}catch{}}async function k9(){return new Promise(($)=>{let Z="";if(process.stdin.setEncoding("utf8"),process.stdin.on("data",(X)=>Z+=X),process.stdin.on("end",()=>$(Z.trim())),process.stdin.isTTY)$("")})}async function L9(){let $=process.argv.slice(2);if($[0]==="--dm-print-helper-paths"){let k=v0(import.meta.url);console.log(JSON.stringify({launchScript:a1(k,"launch.mjs"),searchScript:a1(k,"search.mjs"),perplexityExtractor:s0("perplexity.mjs",{moduleDir:k})}));return}if($.length<2||$[0]==="--help")process.stderr.write(`${['Usage: node search.mjs <engine> "<query>"',"","Engines: all, perplexity (p), google (g), chatgpt (gpt), gemini (gem), semantic-scholar (s2), logically (log), bing (b)","","Flags:"," --synthesize For engine=all: synthesize fetched sources"," --synthesizer <engine> Synthesis engine (default from ~/.dm/greedyconfig)"," --fast Legacy quick mode: no source fetching or synthesis"," --depth <mode> Legacy: fast|standard|deep aliases, or research"," --deep-research Deprecated alias for --research"," --research Iterative query/learnings loop (alias: --depth research)"," --breadth <n> Research mode query breadth, 1-5 (default: 3)"," --iterations <n> Research mode rounds, 1-3 (default: 2)"," --max-sources <n> Research mode fetched source cap, 3-12"," --research-out-dir <dir> Write research bundle to a specific directory"," --no-research-bundle Disable the default .dm/greedysearch-research bundle"," --fetch-top-source Fetch content from top source"," --inline Output JSON to stdout (for piping)"," --locale <lang> Force results language (en, de, fr, etc.)"," --visible Always use visible Chrome for this search"," --always-visible Alias for --visible"," --stdin Read query from stdin (avoids command-line leakage)","","Environment:"," GREEDY_SEARCH_VISIBLE Set to 1 to show Chrome window (disables headless)"," GREEDY_SEARCH_ALWAYS_VISIBLE Set to 1 to force visible mode for all runs"," GREEDY_SEARCH_LOCALE Default locale (default: en)","","Examples:",' node search.mjs all "Node.js streams" # Grounded: engines + fetched sources',' node search.mjs all "Node.js streams" --synthesize # Add Gemini synthesis',' node search.mjs all "quick check" --fast # Legacy fast: no sources/synthesis',' node search.mjs all "browser automation" --research --breadth 3 --iterations 2',' node search.mjs p "what is memoization" # Single engine search'].join(`
|
|
519
|
-
`)}
|
|
520
|
-
`),process.exit(1);if($.includes("--visible")||$.includes("--always-visible")||process.env.GREEDY_SEARCH_ALWAYS_VISIBLE==="1")process.env.GREEDY_SEARCH_VISIBLE="1",process.env.GREEDY_SEARCH_ALWAYS_VISIBLE="1",delete process.env.GREEDY_SEARCH_HEADLESS;else if(process.env.GREEDY_SEARCH_VISIBLE!=="1")process.env.GREEDY_SEARCH_HEADLESS="1";await G1(),S1();let X=$.indexOf("--depth"),J=X!==-1&&$[X+1]?$[X+1].toLowerCase():null,W=$.find((k)=>!k.startsWith("--"))?.toLowerCase(),K=$.includes("--research")||$.includes("--deep-research")||J==="research",V=$.includes("--fast")||J==="fast",j=J==="standard"||J==="deep"||$.includes("--deep"),Y=W==="all"&&!V,Q=W==="all"&&!V&&($.includes("--synthesize")||j),H=J==="deep"||$.includes("--deep");if($.includes("--deep-research"))process.stderr.write(`[greedysearch] --deep-research is deprecated; use --research or --depth research
|
|
521
|
-
`);if(j)process.stderr.write(`[greedysearch] depth fast|standard|deep is deprecated; use default grounded search plus --synthesize when needed
|
|
522
|
-
`);let B=$.indexOf("--synthesizer"),N=z1(B===-1?J2:$[B+1]),O=!$.includes("--full"),M=$.includes("--fetch-top-source"),D=$.includes("--inline"),z=$.indexOf("--breadth"),F=$.indexOf("--iterations"),P=$.indexOf("--max-sources"),w=z===-1?void 0:$[z+1],g=F===-1?void 0:$[F+1],d=P===-1?void 0:$[P+1],f=$.indexOf("--research-out-dir"),x=f===-1?void 0:$[f+1],i=!$.includes("--no-research-bundle"),B0=$.indexOf("--out"),o=B0===-1?null:$[B0+1],J0=$.indexOf("--locale"),T=process.env.GREEDY_SEARCH_LOCALE,$0=_9(),c="en";if(J0!==-1&&$[J0+1])c=$[J0+1];else if(T)c=T;else if($0.locale)c=$0.locale;let s=$.filter((k,v)=>k!=="--full"&&k!=="--short"&&k!=="--fast"&&k!=="--fetch-top-source"&&k!=="--synthesize"&&k!=="--deep-research"&&k!=="--deep"&&k!=="--research"&&k!=="--inline"&&k!=="--stdin"&&k!=="--headless"&&k!=="--visible"&&k!=="--always-visible"&&k!=="--depth"&&k!=="--synthesizer"&&k!=="--out"&&k!=="--locale"&&k!=="--breadth"&&k!=="--iterations"&&k!=="--max-sources"&&k!=="--research-out-dir"&&k!=="--no-research-bundle"&&k!=="--help"&&(X===-1||v!==X+1)&&(B===-1||v!==B+1)&&(B0===-1||v!==B0+1)&&(J0===-1||v!==J0+1)&&(z===-1||v!==z+1)&&(F===-1||v!==F+1)&&(P===-1||v!==P+1)&&(f===-1||v!==f+1)),E=s[0]?.toLowerCase(),U0=$.includes("--stdin"),b;if(U0)b=await k9();else b=s.slice(1).join(" ");if(K){if(E!=="all")process.stderr.write(`[greedysearch] Research mode uses all engines; ignoring engine "${E}".
|
|
523
|
-
`);let k=await B8({query:l1(b),breadth:w,iterations:g,maxSources:d,locale:c,short:O,writeBundle:i,researchOutDir:x});n0(k,o,{inline:D,synthesize:!0,query:b});return}if(E==="all"){await y(["list"]);let k={perplexity:"https://www.perplexity.ai/",google:"https://www.google.com/",chatgpt:"https://chatgpt.com/",gemini:"https://gemini.google.com/app","semantic-scholar":"https://www.semanticscholar.org/",semanticscholar:"https://www.semanticscholar.org/",s2:"https://www.semanticscholar.org/",logically:"https://logically.app/research-assistant/"},v=await Promise.all(r.map((a)=>C0(k[a])));await y(["list"]);let J1=(a)=>{if(!V)return 70000;return a==="chatgpt"?60000:35000};try{let a=await Promise.allSettled(r.map((L,_)=>q0(G0[L],l1(b),v[_],O,J1(L),c).then((A)=>{return process.stderr.write(`PROGRESS:${L}:done
|
|
524
|
-
`),{engine:L,...A}}).catch((A)=>{throw A}))),C={};for(let L=0;L<a.length;L++){let _=a[L];if(_.status==="fulfilled")C[_.value.engine]=_.value;else{let A=_.reason,h=A?.message||"unknown error";if(C[r[L]]={error:h},A?.lastStage)process.stderr.write(`[greedysearch] ${r[L]} failed at stage '${A.lastStage}': ${h}
|
|
525
|
-
`);if(A?.partialErr)process.stderr.write(`[greedysearch] ${r[L]} tail stderr:
|
|
526
|
-
${A.partialErr}
|
|
527
|
-
`)}}let I=n2(C);if(I.length>0&&process.env.GREEDY_SEARCH_VISIBLE!=="1"){X1({scope:"all",phase:"start",engines:I,reasons:Object.fromEntries(I.map((h)=>[h,{error:C[h]?.error||null,envelope:C[h]?._envelope||null}]))}),process.stderr.write(`[greedysearch] \uD83D\uDD13 Headless ${I.join(", ")} search hit timeout/verification/antibot signals — retrying visible to establish cookies...
|
|
528
|
-
`);for(let h of I)process.stderr.write(`[greedysearch] ${h} recovery starting in visible mode...
|
|
529
|
-
`);await y1(v),await l0(),process.env.GREEDY_SEARCH_VISIBLE="1",delete process.env.GREEDY_SEARCH_HEADLESS,await G1(),await y(["list"]);let L=[],_=!1,A=0;for(let h=0;h<I.length;h++){let Z0=await C0();L.push(Z0)}try{let h=await Promise.allSettled(I.map((S,O0)=>q0(G0[S],b,L[O0],O,null,c).then((p)=>({engine:S,...p})).catch((p)=>({engine:S,error:p.message})))),Z0=[],j0=[];for(let S of h)if(S.status==="fulfilled"&&!S.value.error)C[S.value.engine]=S.value,A++,process.stderr.write(`PROGRESS:${S.value.engine}:done
|
|
530
|
-
`);else if(S.status==="fulfilled"){if(C[S.value.engine]=S.value,Z0.push(S.value.engine),A$(S.value.error))j0.push(S.value.engine)}if(A>0)process.stderr.write(`[greedysearch] ✅ ${A}/${I.length} engine(s) recovered — cookies cached for future headless runs.
|
|
531
|
-
`);else process.stderr.write(`[greedysearch] ⚠️ Recovery attempt did not extract an answer — ${I.join(", ")} may still need manual verification or a DOM fallback.
|
|
532
|
-
`);if(Z0.length>0){process.stderr.write(`[greedysearch] Second visible retry for ${Z0.join(", ")} — Turnstile may have resolved on first attempt...
|
|
533
|
-
`);let S=await Promise.allSettled(Z0.map((p)=>{let l=I.indexOf(p);return q0(G0[p],b,L[l],O,null,c).then((Y0)=>({engine:p,...Y0})).catch((Y0)=>({engine:p,error:Y0.message}))})),O0=[];for(let p of S)if(p.status==="fulfilled"&&!p.value.error)C[p.value.engine]=p.value,A++,process.stderr.write(`PROGRESS:${p.value.engine}:done
|
|
534
|
-
`),process.stderr.write(`[greedysearch] ✅ ${p.value.engine} recovered on second visible retry.
|
|
535
|
-
`);else O0.push(p.value?.engine||"unknown");Z0.length=0,Z0.push(...O0)}if(X1({scope:"all",phase:Z0.length>0?"needs-human":"success",engines:I,results:Object.fromEntries(I.map((S)=>[S,{mode:C[S]?._envelope?.mode||null,durationMs:C[S]?._envelope?.durationMs||null,lastStage:C[S]?._envelope?.lastStage||null,error:C[S]?.error||null}]))}),Z0.length>0){for(let l of Z0)process.stderr.write(`PROGRESS:${l}:needs-human
|
|
536
|
-
`);let O0=(await Promise.all(Z0.map(async(l)=>{let Y0=L[I.indexOf(l)],x0=await k$({tab:Y0,engine:l}).catch((F0)=>({cleared:!1,reason:F0.message||String(F0)}));return{engine:l,tab:Y0,...x0}}))).filter((l)=>l.cleared);if(O0.length>0)process.stderr.write(`[greedysearch] \uD83D\uDD04 Auto-resuming ${O0.map((l)=>l.engine).join(", ")} on cleared tabs...
|
|
537
|
-
`),await Promise.allSettled(O0.map(async(l)=>{let Y0=G0[l.engine];try{let x0=await q0(Y0,b,l.tab,O,null,c);C[l.engine]=x0,process.stderr.write(`PROGRESS:${l.engine}:done
|
|
538
|
-
`)}catch(x0){process.stderr.write(`[greedysearch] ⚠️ Resume extraction failed for ${l.engine}: ${x0.message}
|
|
539
|
-
`)}}));let p=Z0.filter((l)=>!O0.find((Y0)=>Y0.engine===l));if(p.length===0)_=!1;else _=!0,C._needsHumanVerification={engines:p,message:"Visible Chrome is open with the engine page loaded. Solve the Turnstile checkbox or other challenge in the visible window to store cookies. Cookies persist for future runs."},process.stderr.write(`[greedysearch] \uD83D\uDD13 ${p.join(", ")} still blocked — keeping visible Chrome open. Solve the challenge in the window to store cookies, then rerun.
|
|
540
|
-
`)}}finally{if(_)d$().catch(()=>{});else await y1(L),process.stderr.write(`[greedysearch] Switching back to headless Chrome...
|
|
541
|
-
`),await l0(),delete process.env.GREEDY_SEARCH_VISIBLE,process.env.GREEDY_SEARCH_HEADLESS="1",await G1(),await y(["list"])}v.length=0}for(let L of r){if(!C[L]?.error)continue;if(I.includes(L)){if(process.env.GREEDY_SEARCH_VISIBLE==="1")process.stderr.write(`PROGRESS:${L}:${A$(C[L].error)?"needs-human":"error"}
|
|
542
|
-
`);continue}process.stderr.write(`PROGRESS:${L}:error
|
|
543
|
-
`)}if(C._sources=f0(C,b),Y&&C._sources.length>0){process.stderr.write(`PROGRESS:source-fetch:start
|
|
544
|
-
`);let L=await M1(C._sources,5,8000);C._sources=r0(C._sources,L),C._fetchedSources=$1(L),process.stderr.write(`PROGRESS:source-fetch:done
|
|
545
|
-
`)}if(Q){process.stderr.write(`PROGRESS:synthesis:start
|
|
546
|
-
`),process.stderr.write(`[greedysearch] Synthesizing results with ${N}...
|
|
547
|
-
`);let L=null;try{L=await C0(t2(N));let _=await e2(b,C,{grounded:H,tabPrefix:L,visible:process.env.GREEDY_SEARCH_VISIBLE==="1",synthesizer:N});C._synthesis={..._,synthesized:!0},process.stderr.write(`PROGRESS:synthesis:done
|
|
548
|
-
`)}catch(_){process.stderr.write(`[greedysearch] Synthesis failed: ${_.message}
|
|
549
|
-
`),C._synthesis={error:_.message,synthesized:!1,synthesizedBy:N}}finally{if(L)await E0(L)}}if(M){let L=A9(C);if(L)C._topSource=await e0(L.canonicalUrl||L.url)}if(!V)C._confidence=s2(C);n0(C,o,{inline:D,synthesize:Q,query:b});return}finally{await y1(v)}}let W0=G0[E];if(!W0)process.stderr.write(`Unknown engine: "${E}"
|
|
550
|
-
Available: ${Object.keys(G0).join(", ")}
|
|
551
|
-
`),process.exit(1);try{let k=await q0(W0,l1(b),null,O,null,c);if(M&&k.sources?.length>0)k.topSource=await e0(k.sources[0].url);n0(k,o,{inline:D,synthesize:!1,query:b})}catch(k){let v=W0.includes("bing")?"bing":W0.includes("perplexity")?"perplexity":W0.includes("chatgpt")?"chatgpt":W0.includes("semantic-scholar")?"semantic-scholar":W0.includes("logically")?"logically":null;if(v&&process.env.GREEDY_SEARCH_VISIBLE!=="1"&&i2(k)){X1({scope:"single",phase:"start",engines:[v],reasons:{[v]:{error:k.message||null,envelope:k.envelope||null,lastStage:k.lastStage||null}}}),process.stderr.write(`[greedysearch] \uD83D\uDD13 ${v} blocked in headless — retrying visible to establish cookies...
|
|
552
|
-
`),await l0(),process.env.GREEDY_SEARCH_VISIBLE="1",delete process.env.GREEDY_SEARCH_HEADLESS,await G1(),await y(["list"]);let a=await C0(),C=!1;try{let I=await q0(W0,b,a,O,null,c);if(X1({scope:"single",phase:"success",engines:[v],result:{engine:v,mode:I._envelope?.mode||null,durationMs:I._envelope?.durationMs||null,lastStage:I._envelope?.lastStage||null}}),M&&I.sources?.length>0)I.topSource=await e0(I.sources[0].url);n0(I,o,{inline:D,synthesize:!1,query:b});return}catch(I){if(X1({scope:"single",phase:"needs-human",engines:[v],result:{engine:v,error:I.message||String(I),envelope:I.envelope||null}}),(await k$({tab:a,engine:v}).catch((_)=>({cleared:!1,reason:_.message||String(_)}))).cleared){process.stderr.write(`[greedysearch] \uD83D\uDD04 Auto-resuming ${v} extraction on the now-cleared tab...
|
|
553
|
-
`);try{let _=await q0(W0,b,a,O,null,c);if(X1({scope:"single",phase:"success-after-poll",engines:[v],result:{engine:v,mode:_._envelope?.mode||null,durationMs:_._envelope?.durationMs||null,lastStage:_._envelope?.lastStage||null}}),M&&_.sources?.length>0)_.topSource=await e0(_.sources[0].url);n0(_,o,{inline:D,synthesize:!1,query:b});return}catch(_){process.stderr.write(`[greedysearch] ⚠️ Resume extraction failed: ${_.message}
|
|
554
|
-
`)}}C=!0,n0({query:b,error:I.message,_needsHumanVerification:{engines:[v],message:"Visible Chrome is open with the engine page loaded. Solve the Turnstile checkbox or other challenge to store cookies. Cookies persist for future runs."}},o,{inline:D,synthesize:!1,query:b});return}finally{if(!C)await E0(a),await l0(),delete process.env.GREEDY_SEARCH_VISIBLE,process.env.GREEDY_SEARCH_HEADLESS="1";else d$().catch(()=>{})}}process.stderr.write(`Error: ${k.message}
|
|
555
|
-
`),process.exit(1)}}function A9($){if(Array.isArray($._sources)&&$._sources.length>0)return $._sources[0];for(let Z of["perplexity","google","bing"]){let X=$[Z];if(X?.sources?.length>0)return X.sources[0]}return null}async function d$(){if(process.env.GREEDY_SEARCH_HEADLESS==="1")return;await N8(n)}L9().finally(async()=>{S1(),d$().catch(()=>{})});
|
|
611
|
+
}
|
|
612
|
+
process.stderr.write(`Error: ${e.message}
|
|
613
|
+
`);
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function pickTopSource(out) {
|
|
618
|
+
if (Array.isArray(out._sources) && out._sources.length > 0)
|
|
619
|
+
return out._sources[0];
|
|
620
|
+
for (const engine of ["perplexity", "google", "bing"]) {
|
|
621
|
+
const r = out[engine];
|
|
622
|
+
if (r?.sources?.length > 0)
|
|
623
|
+
return r.sources[0];
|
|
624
|
+
}
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
async function minimizeChrome() {
|
|
628
|
+
if (process.env.GREEDY_SEARCH_HEADLESS === "1")
|
|
629
|
+
return;
|
|
630
|
+
await minimizeViaCDP(GREEDY_PORT);
|
|
631
|
+
}
|
|
632
|
+
main().finally(async () => {
|
|
633
|
+
touchActivity();
|
|
634
|
+
minimizeChrome().catch(() => {});
|
|
635
|
+
});
|