@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,349 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
|
|
30
|
-
var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
|
|
31
|
-
try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
|
|
32
|
-
try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
|
|
33
|
-
var m = [pdf, textPdf];
|
|
34
|
-
try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
|
|
35
|
-
m.item = function item(i) { return this[i] || null; };
|
|
36
|
-
m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
|
|
37
|
-
return m;
|
|
38
|
-
}
|
|
39
|
-
Object.defineProperty(navigator, 'plugins', {
|
|
40
|
-
get: () => {
|
|
41
|
-
__greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
|
|
42
|
-
var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
|
|
43
|
-
var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
|
|
44
|
-
var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
|
|
45
|
-
try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
|
|
46
|
-
try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
|
|
47
|
-
try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
|
|
48
|
-
var p = [plugin0, plugin1, plugin2];
|
|
49
|
-
p.item = function item(i) { return this[i] || null; };
|
|
50
|
-
p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
|
|
51
|
-
p.refresh = function refresh() {};
|
|
52
|
-
try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
|
|
53
|
-
try {
|
|
54
|
-
__greedyMimeTypes[0].enabledPlugin = p[0];
|
|
55
|
-
__greedyMimeTypes[1].enabledPlugin = p[0];
|
|
56
|
-
} catch(_) {}
|
|
57
|
-
return p;
|
|
58
|
-
},
|
|
59
|
-
configurable: true,
|
|
60
|
-
});
|
|
61
|
-
Object.defineProperty(navigator, 'mimeTypes', {
|
|
62
|
-
get: () => {
|
|
63
|
-
__greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
|
|
64
|
-
return __greedyMimeTypes;
|
|
65
|
-
},
|
|
66
|
-
configurable: true,
|
|
67
|
-
});
|
|
68
|
-
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
|
|
69
|
-
try {
|
|
70
|
-
Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
|
|
71
|
-
} catch(_) {}
|
|
72
|
-
if (!navigator.mediaDevices) {
|
|
73
|
-
Object.defineProperty(navigator, 'mediaDevices', {
|
|
74
|
-
get: () => ({
|
|
75
|
-
enumerateDevices: () => Promise.resolve([
|
|
76
|
-
{ deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
|
|
77
|
-
{ deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
|
|
78
|
-
{ deviceId: '', kind: 'videoinput', label: '', groupId: '' },
|
|
79
|
-
]),
|
|
80
|
-
getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
|
|
81
|
-
getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
|
|
82
|
-
}),
|
|
83
|
-
configurable: true,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
// ── Missing platform APIs (headless often lacks these) ─
|
|
87
|
-
try {
|
|
88
|
-
if (!navigator.share) {
|
|
89
|
-
navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
|
|
90
|
-
}
|
|
91
|
-
} catch(_) {}
|
|
92
|
-
try {
|
|
93
|
-
if (!navigator.contentIndex) {
|
|
94
|
-
Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
|
|
95
|
-
}
|
|
96
|
-
} catch(_) {}
|
|
97
|
-
|
|
98
|
-
if (!window.chrome) {
|
|
99
|
-
window.chrome = {
|
|
100
|
-
app: { isInstalled: false, InstallState: {}, RunningState: {} },
|
|
101
|
-
runtime: {
|
|
102
|
-
OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
|
|
103
|
-
connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
|
|
104
|
-
},
|
|
105
|
-
loadTimes: function() { return { requestTime: 0, startLoadTime: Date.now() - 5000, commitLoadTime: Date.now() - 3000, finishDocumentLoadTime: Date.now() - 2000, finishLoadTime: Date.now() - 1000, firstPaintTime: Date.now() - 800, navigationType: 'Other', wasFetchedViaSpdy: true, wasNpnNegotiated: true, npnNegotiatedProtocol: 'h2', wasAlternateProtocolAvailable: false, connectionInfo: 'http/2' }; },
|
|
106
|
-
csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
var __greedyNativeFns = [];
|
|
110
|
-
function __markNative(fn) { try { __greedyNativeFns.push(fn); } catch(_) {} return fn; }
|
|
111
|
-
|
|
112
|
-
var origQuery = navigator.permissions?.query;
|
|
113
|
-
if (origQuery) {
|
|
114
|
-
navigator.permissions.query = __markNative(function query(params) {
|
|
115
|
-
if (params && params.name === 'notifications') return Promise.resolve({ state: Notification.permission || 'default', onchange: null });
|
|
116
|
-
return origQuery.apply(this, arguments);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
try {
|
|
120
|
-
var getParam = WebGLRenderingContext.prototype.getParameter;
|
|
121
|
-
WebGLRenderingContext.prototype.getParameter = __markNative(function getParameter(p) {
|
|
122
|
-
if (p === 37445) return 'Intel Inc.';
|
|
123
|
-
if (p === 37446) return 'Intel Iris OpenGL Engine';
|
|
124
|
-
return getParam.call(this, p);
|
|
125
|
-
});
|
|
126
|
-
} catch(_) {}
|
|
127
|
-
// ── WebGL readPixels noise ──────────────────────────
|
|
128
|
-
// CreepJS and other fingerprinters draw content with WebGL and read back the
|
|
129
|
-
// rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
|
|
130
|
-
try {
|
|
131
|
-
var origReadPixels = WebGLRenderingContext.prototype.readPixels;
|
|
132
|
-
WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
|
|
133
|
-
var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
|
|
134
|
-
if (pixels && pixels.length > 0) {
|
|
135
|
-
pixels[0] ^= 1;
|
|
136
|
-
}
|
|
137
|
-
return result;
|
|
138
|
-
});
|
|
139
|
-
} catch(_) {}
|
|
140
|
-
Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
|
|
141
|
-
Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
|
|
142
|
-
|
|
143
|
-
// ── Canvas fingerprint noise ─────────────────────────
|
|
144
|
-
// Headless rendering engines produce slightly different canvas output
|
|
145
|
-
// than headed Chrome. Subtle noise breaks hash-based fingerprinting.
|
|
146
|
-
try {
|
|
147
|
-
var __canvasNoise = ((Date.now() & 0xFF) | 1);
|
|
148
|
-
var origFill = CanvasRenderingContext2D.prototype.fillText;
|
|
149
|
-
CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
|
|
150
|
-
this.globalAlpha = 0.9995;
|
|
151
|
-
return origFill.apply(this, arguments);
|
|
152
|
-
});
|
|
153
|
-
} catch(_) {}
|
|
154
|
-
try {
|
|
155
|
-
var origStroke = CanvasRenderingContext2D.prototype.strokeText;
|
|
156
|
-
CanvasRenderingContext2D.prototype.strokeText = __markNative(function strokeText() {
|
|
157
|
-
this.globalAlpha = 0.9995;
|
|
158
|
-
return origStroke.apply(this, arguments);
|
|
159
|
-
});
|
|
160
|
-
} catch(_) {}
|
|
161
|
-
try {
|
|
162
|
-
var origToDataURL = HTMLCanvasElement.prototype.toDataURL;
|
|
163
|
-
HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
|
|
164
|
-
var ctx = this.getContext('2d');
|
|
165
|
-
if (ctx) {
|
|
166
|
-
// Spread noise across canvas to break hash-based fingerprinting.
|
|
167
|
-
// Uses a deterministic pattern so it's consistent per page load
|
|
168
|
-
// but varies between sessions.
|
|
169
|
-
var w = this.width, h = this.height;
|
|
170
|
-
if (w > 0 && h > 0) {
|
|
171
|
-
var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
|
|
172
|
-
if (imgData && imgData.data) {
|
|
173
|
-
for (var __i = 0; __i < imgData.data.length; __i += 4) {
|
|
174
|
-
imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
|
|
175
|
-
}
|
|
176
|
-
ctx.putImageData(imgData, 0, 0);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return origToDataURL.apply(this, arguments);
|
|
181
|
-
});
|
|
182
|
-
} catch(_) {}
|
|
183
|
-
|
|
184
|
-
// ── AudioContext fingerprint noise ────────────────────
|
|
185
|
-
// Headless Chrome's AudioContext produces slightly different output.
|
|
186
|
-
// Subtle noise breaks audio-based fingerprinting.
|
|
187
|
-
try {
|
|
188
|
-
var __audioSeed = ((Date.now() & 0x1F) | 1);
|
|
189
|
-
var origGetChannelData = AudioBuffer.prototype.getChannelData;
|
|
190
|
-
AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
|
|
191
|
-
var data = origGetChannelData.call(this, channel);
|
|
192
|
-
for (var __i = 0; __i < data.length; __i += 64) {
|
|
193
|
-
data[__i] *= 0.99999;
|
|
194
|
-
}
|
|
195
|
-
return data;
|
|
196
|
-
});
|
|
197
|
-
} catch(_) {}
|
|
198
|
-
|
|
199
|
-
// ── window outer dimensions ──────────────────────────
|
|
200
|
-
// outerWidth/Height = 0 in headless — a well-known bot signal.
|
|
201
|
-
// Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
|
|
202
|
-
try {
|
|
203
|
-
if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
|
|
204
|
-
if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
|
|
205
|
-
} catch(_) {}
|
|
206
|
-
|
|
207
|
-
// ── screen properties ─────────────────────────────────
|
|
208
|
-
// Headless Chrome often reports an 800x600 screen even when the viewport is
|
|
209
|
-
// 1920x1080. Keep screen metrics internally consistent with our launch flags.
|
|
210
|
-
try {
|
|
211
|
-
Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
|
|
212
|
-
Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
|
|
213
|
-
Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
|
|
214
|
-
Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
|
|
215
|
-
Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
|
|
216
|
-
Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
|
|
217
|
-
} catch(_) {}
|
|
218
|
-
|
|
219
|
-
// ── navigator.userAgentData (UA Client Hints) ─────────
|
|
220
|
-
// Derive version from the UA string already set by --user-agent flag so the
|
|
221
|
-
// two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
|
|
222
|
-
try {
|
|
223
|
-
var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
|
|
224
|
-
var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
|
|
225
|
-
var _brands = [
|
|
226
|
-
{ brand: 'Not)A;Brand', version: '99' },
|
|
227
|
-
{ brand: 'Google Chrome', version: _uaMajor },
|
|
228
|
-
{ brand: 'Chromium', version: _uaMajor },
|
|
229
|
-
];
|
|
230
|
-
Object.defineProperty(navigator, 'userAgentData', {
|
|
231
|
-
get: function() {
|
|
232
|
-
return {
|
|
233
|
-
brands: _brands, mobile: false, platform: 'Windows',
|
|
234
|
-
getHighEntropyValues: function() {
|
|
235
|
-
return Promise.resolve({
|
|
236
|
-
architecture: 'x86', bitness: '64',
|
|
237
|
-
brands: _brands,
|
|
238
|
-
fullVersionList: [
|
|
239
|
-
{ brand: 'Not)A;Brand', version: '99.0.0.0' },
|
|
240
|
-
{ brand: 'Google Chrome', version: _uaFull },
|
|
241
|
-
{ brand: 'Chromium', version: _uaFull },
|
|
242
|
-
],
|
|
243
|
-
mobile: false, model: '', platform: 'Windows',
|
|
244
|
-
platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
|
|
245
|
-
});
|
|
246
|
-
},
|
|
247
|
-
toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
|
|
248
|
-
};
|
|
249
|
-
},
|
|
250
|
-
configurable: true,
|
|
251
|
-
});
|
|
252
|
-
} catch(_) {}
|
|
253
|
-
|
|
254
|
-
// ── CDP Runtime serialization guard ──────────────────
|
|
255
|
-
// Sites detect CDP by putting a getter on Error.prototype.stack
|
|
256
|
-
// and checking if console.log triggers it (only happens when
|
|
257
|
-
// Runtime domain is enabled). We monkey-patch console methods to
|
|
258
|
-
// strip custom getters from arguments before they reach CDP.
|
|
259
|
-
try {
|
|
260
|
-
var _origLog = console.log, _origError = console.error,
|
|
261
|
-
_origWarn = console.warn, _origDebug = console.debug,
|
|
262
|
-
_origInfo = console.info;
|
|
263
|
-
var _safeArg = function(a) {
|
|
264
|
-
if (a instanceof Error) {
|
|
265
|
-
try { return new Error(a.message); } catch(_) { return a; }
|
|
266
|
-
}
|
|
267
|
-
return a;
|
|
268
|
-
};
|
|
269
|
-
console.log = __markNative(function log() { return _origLog.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
|
|
270
|
-
console.error = __markNative(function error() { return _origError.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
|
|
271
|
-
console.warn = __markNative(function warn() { return _origWarn.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
|
|
272
|
-
console.debug = __markNative(function debug() { return _origDebug.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
|
|
273
|
-
console.info = __markNative(function info() { return _origInfo.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
|
|
274
|
-
} catch(_) {}
|
|
275
|
-
|
|
276
|
-
// ── Native function masking ──────────────────────────
|
|
277
|
-
// Patched APIs should not stringify as user-defined stealth code.
|
|
278
|
-
try {
|
|
279
|
-
var __nativeToString = Function.prototype.toString;
|
|
280
|
-
Function.prototype.toString = function toString() {
|
|
281
|
-
if (__greedyNativeFns.indexOf(this) !== -1) {
|
|
282
|
-
var name = this.name || '';
|
|
283
|
-
return 'function ' + name + '() { [native code] }';
|
|
284
|
-
}
|
|
285
|
-
return __nativeToString.call(this);
|
|
286
|
-
};
|
|
287
|
-
} catch(_) {}
|
|
288
|
-
})();
|
|
289
|
-
`})])}var rn={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};function q(n){let t=n*0.2,e=rt(-Math.floor(t),Math.floor(t)+1);return Math.max(50,Math.round(n+e))}async function B(n,t,e=15000,i=500){let r=String.raw`
|
|
290
|
-
new Promise((resolve) => {
|
|
291
|
-
const _deadline = Date.now() + ${e};
|
|
292
|
-
const _baseInterval = ${i};
|
|
293
|
-
|
|
294
|
-
function _jitter(ms) {
|
|
295
|
-
return Math.max(50, ms + (Math.random() * ms * 0.4 - ms * 0.2));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function _poll() {
|
|
299
|
-
try {
|
|
300
|
-
if (document.querySelector('${t}')) { resolve(true); return; }
|
|
301
|
-
if (Date.now() < _deadline) { setTimeout(_poll, _jitter(_baseInterval)); }
|
|
302
|
-
else { resolve(false); }
|
|
303
|
-
} catch(_) { resolve(false); }
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
_poll();
|
|
307
|
-
})
|
|
308
|
-
`;return await a(["eval",n,r],e+5000)==="true"}async function Wn(n){let t=n.indexOf("--stdin");if(t===-1)return n;let e=await new Promise((r)=>{let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(u)=>o+=u),process.stdin.on("end",()=>r(o.trim()))}),i=[...n];return i[t]=e,i}function xn(n){let t=n.includes("--short"),e=n.filter((l)=>l!=="--short"),i=e.indexOf("--tab"),r=i===-1?null:e[i+1];if(i!==-1)e=e.filter((l,g)=>g!==i&&g!==i+1);let o=e.indexOf("--locale"),u=o===-1?null:e[o+1];if(o!==-1)e=e.filter((l,g)=>g!==o&&g!==o+1);return{query:e.join(" "),tabPrefix:r,short:t,locale:u}}function jn(n,t){if(!n.length||n[0]==="--help")process.stderr.write(t),process.exit(1)}function Jn(n,t,e=300){if(!t||n.length<=e)return n;let i=n.slice(0,e),r=i.lastIndexOf(" ");return r>0?`${i.slice(0,r)}…`:`${i}…`}function Nn(n){process.stdout.write(`${JSON.stringify(n,null,2)}
|
|
309
|
-
`)}function y(n,t,e=null){if(!n||typeof n!=="object")return;let i=e?` (+${Date.now()-e}ms)`:"";if(n.lastStage=t,!Array.isArray(n.stages))n.stages=[];n.stages.push({stage:t,at:Date.now()});let r=n.engine||"extractor";console.error(`[${r}] stage: ${t}${i}`)}function on({engine:n,mode:t="headless",clipboardEmpty:e=null,fallbackUsed:i=null,blockedBy:r=null,verificationResult:o=null,inputReady:u=null,durationMs:l=null,lastStage:g=null,stages:f=null}={}){return{engine:n,mode:t,clipboardEmpty:e,fallbackUsed:i,blockedBy:r,verificationResult:o,inputReady:u,durationMs:l,lastStage:g,stages:f}}function Zn(n,t=null){if(t){let e=JSON.stringify({_envelope:t,error:n.message});process.stdout.write(`${e}
|
|
310
|
-
`)}process.stderr.write(`Error: ${n.message}
|
|
311
|
-
`),process.exit(1)}import{spawn as Pt,execFileSync as hn,execSync as de}from"node:child_process";import{basename as pt}from"node:path";function Xn(n=process.env,t=process.execPath){let e=n.GREEDY_SEARCH_NODE||n.NODE_BINARY||n.NODE;if(e?.trim())return e.trim();let i=pt(t||"").toLowerCase();if(i==="node"||i==="node.exe")return t;return"node"}import{existsSync as Sn,readFileSync as cn,renameSync as Kt,unlinkSync as $,writeFileSync as E}from"node:fs";import pn from"node:http";import{platform as Ln}from"node:os";import{existsSync as qn}from"node:fs";import{platform as wt}from"node:os";import{join as x}from"node:path";function _(n){let t=wt()==="win32",e=process.env.SystemRoot||"C:\\Windows",i={win32:{powershell:x(e,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:x(e,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:x(e,"System32","netstat.exe"),taskkill:x(e,"System32","taskkill.exe"),tasklist:x(e,"System32","tasklist.exe"),cmd:x(e,"System32","cmd.exe")},unix:{ps:"/usr/bin/ps",lsof:"/usr/bin/lsof",ss:"/usr/sbin/ss",grep:"/usr/bin/grep",kill:"/usr/bin/kill"}},r=t?i.win32:i.unix,o=n.toLowerCase();if(r[o]&&qn(r[o]))return r[o];if(t&&o==="netstat"){let u=x(e,"Sysnative","netstat.exe");if(qn(u))return u}return n}import{execFileSync as yt}from"node:child_process";import{platform as vt}from"node:os";function _t(n,t){return yt(_(n),t,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5000})}function mt(n){let t=String(n||"").match(/\b(\d+)\b/);return t?Number.parseInt(t[1],10):null}function $t(n){return mt(n)}function bt(n,t){for(let e of String(n||"").split(/\r?\n/)){if(!/\bLISTEN\b/i.test(e))continue;if(!e.trim().split(/\s+/).slice(0,6).some((o)=>o.endsWith(`:${t}`)))continue;let r=e.match(/\bpid=(\d+)\b/);if(r)return Number.parseInt(r[1],10)}return null}function Wt(n,t){for(let e of String(n||"").split(/\r?\n/)){let i=e.trim().split(/\s+/);if(i.length<5||i[0].toUpperCase()!=="TCP")continue;if(!i.at(-2)?.toUpperCase().startsWith("LISTEN"))continue;if(!i[1].endsWith(`:${t}`))continue;let r=Number.parseInt(i.at(-1),10);if(Number.isInteger(r)&&r>0)return r}return null}function un(n,t,e){try{return n(t,e)}catch{return null}}function P(n,{platformName:t=vt(),run:e=_t}={}){if(t==="win32")return Wt(un(e,"netstat",["-ano","-p","TCP"]),n);let i=un(e,"lsof",["-nP",`-iTCP:${n}`,"-sTCP:LISTEN","-t"]),r=$t(i);if(r)return r;if(t!=="linux")return null;return bt(un(e,"ss",["-ltnp"]),n)}import{existsSync as Bn}from"node:fs";import{dirname as xt,join as Q}from"node:path";import{fileURLToPath as jt}from"node:url";function Qn(n){return jt(new URL(".",n)).replace(/^\/([A-Z]:)/,"$1")}function Jt(n,t=Bn){let e=new Set;for(let i of n.filter(Boolean)){if(e.has(i))continue;if(e.add(i),t(i))return i}return n.filter(Boolean).at(-1)}function kn({moduleDir:n,entrypoint:t=process.argv[1],env:e=process.env,exists:i=Bn}={}){let r=t?xt(t):null,o=e.GREEDY_SEARCH_EXTENSION_DIR?.trim()||null;return Jt([n?Q(n,"..","..","bin","launch.mjs"):null,n?Q(n,"launch.mjs"):null,o?Q(o,"bin","launch.mjs"):null,r?Q(r,"launch.mjs"):null,r?Q(r,"..","bin","launch.mjs"):null],i)}import{existsSync as K,mkdirSync as Nt,readFileSync as Vn,writeFileSync as Zt}from"node:fs";import{homedir as Xt}from"node:os";import{join as Un}from"node:path";import{tmpdir as qt}from"node:os";function Bt(n,t=9222){let e=Number.parseInt(String(n??""),10);return Number.isInteger(e)&&e>1024&&e<65535?e:t}var Qt=qt().replaceAll("\\","/"),h=Bt(process.env.GREEDY_SEARCH_PORT),c=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${Qt}/greedysearch-chrome-profile`).replaceAll("\\","/"),k=`${c}/DevToolsActivePort`,C=process.env.GREEDY_SEARCH_PID_FILE||`${c}/browser.pid`,kt=process.env.CDP_PAGES_CACHE||`${c}/cdp-pages.json`,W=process.env.GREEDY_SEARCH_MODE_FILE||`${c}/browser-mode`,zn=process.env.GREEDY_SEARCH_METADATA_FILE||`${c}/browser-metadata.json`,An=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${c}/browser-launch.lock`,Y=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${c}/browser-last-activity`,ze=(process.env.CDP_SOCKET_DIR||`${c}/cdp-sockets`).replaceAll("\\","/"),Ae=`${c}/visible-recovery.jsonl`,fn=Un(Xt(),".dm"),m=Un(fn,"greedyconfig"),an=["perplexity","google","chatgpt","gemini"],gn="gemini";function Ht(){try{if(K(m)){let n=Vn(m,"utf8"),t=JSON.parse(n);if(Array.isArray(t.engines)&&t.engines.length>0&&t.engines.every((e)=>typeof e==="string")){let e=t.engines.filter((r)=>ln[r]),i=t.engines.filter((r)=>!ln[r]);if(i.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${m}: ${i.join(", ")}
|
|
312
|
-
[greedysearch] Available engines: ${Object.keys(ln).join(", ")}
|
|
313
|
-
`);if(e.length>0)return e;process.stderr.write(`[greedysearch] Warning: no valid engines in ${m}, falling back to defaults: ${an.join(", ")}
|
|
314
|
-
`)}}}catch{}return an}function Vt(){try{if(!K(fn))Nt(fn,{recursive:!0});if(!K(m))Zt(m,JSON.stringify({engines:an,synthesizer:gn},null,2)+`
|
|
315
|
-
`,"utf8")}catch{}}Vt();var Hn=["gemini","chatgpt"];function Ut(){try{if(K(m)){let n=Vn(m,"utf8"),t=JSON.parse(n);if(typeof t.synthesizer==="string"){let e=t.synthesizer.toLowerCase();if(Hn.includes(e))return e;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${m}
|
|
316
|
-
[greedysearch] Available synthesizers: ${Hn.join(", ")}
|
|
317
|
-
[greedysearch] Falling back to default: ${gn}
|
|
318
|
-
`)}}}catch{}return gn}var ln={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},Me=Ht();var Oe=Ut(),De=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=c;import{execFileSync as Mn,execSync as Ke}from"node:child_process";import{existsSync as G,mkdirSync as zt,readFileSync as X,unlinkSync as J,writeFileSync as N}from"node:fs";import{platform as At}from"node:os";var S=zn,j=An,Mt=15000,L=C,F=W,H=Y;function V(n){if(!Number.isInteger(n)||n<=0)return!1;try{return process.kill(n,0),!0}catch{return!1}}function Ot(n){if(!V(n))return null;try{if(At()==="win32")return Mn(_("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${n}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return Mn(_("ps"),["-p",String(n),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Dt(n,t,e=h){if(!n)return!1;let i=(u)=>String(u||"").replaceAll("\\","/").toLowerCase(),r=i(n),o=i(t);return r.includes(o)&&r.includes(`--remote-debugging-port=${e}`)&&!r.includes("--type=")}function On(n,t,e=h){return Dt(Ot(n),t,e)}function Tt(n=h){return P(n)}function U(){try{if(G(S)){let n=X(S,"utf8"),t=JSON.parse(n);if(t&&typeof t.tempDir==="string"&&typeof t.debugPort==="number")return{browserPid:Number.isInteger(t.browserPid)?t.browserPid:void 0,debugPort:t.debugPort,tempDir:t.tempDir,clientPids:Array.isArray(t.clientPids)?t.clientPids.filter((e)=>Number.isInteger(e)&&e>0):[],sessionMode:t.sessionMode==="visible"?"visible":"headless",lastActivity:Number.isFinite(t.lastActivity)?t.lastActivity:0,launchedAt:Number.isFinite(t.launchedAt)?t.launchedAt:0}}}catch{}try{let n=G(L)?Number.parseInt(X(L,"utf8").trim(),10)||void 0:void 0,t=G(F)?X(F,"utf8").trim()==="visible"?"visible":"headless":"headless",e=G(H)?Number.parseInt(X(H,"utf8").trim(),10)||0:0;return{browserPid:n,debugPort:h,tempDir:c,clientPids:n?[n]:[],sessionMode:t,lastActivity:e,launchedAt:0}}catch{return null}}function R(n){try{N(S,JSON.stringify({browserPid:n.browserPid,debugPort:n.debugPort,tempDir:n.tempDir,clientPids:[...new Set(n.clientPids.filter((t)=>t>0))],sessionMode:n.sessionMode,lastActivity:n.lastActivity,launchedAt:n.launchedAt},null,2),"utf8")}catch{}try{if(n.browserPid)N(L,String(n.browserPid),"utf8")}catch{}try{N(F,n.sessionMode,"utf8")}catch{}try{N(H,String(n.lastActivity),"utf8")}catch{}}function Dn(){try{J(S)}catch{}try{J(L)}catch{}try{J(F)}catch{}try{J(H)}catch{}}function sn(n){if(!n)return n;let t={...n,clientPids:[...new Set([...n.clientPids,process.pid].filter((e)=>V(e)||e===process.pid))]};return R(t),t}function I(n){let t=Date.now();try{if(n)R({...n,lastActivity:t});else N(H,String(t),"utf8")}catch{}}var Fe=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Tn=!1;function Pn(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD)return;if(Tn)return;Tn=!0;let n=U();if(!n)return;if(n.browserPid){if(!V(n.browserPid)){Dn();return}if(!On(n.browserPid,n.tempDir,n.debugPort))Dn();else R({...n,clientPids:n.clientPids.filter((r)=>V(r))})}let t=Tt();if(t&&t!==n.browserPid)if(On(t,c,h))R({browserPid:t,debugPort:h,tempDir:c,clientPids:[t],sessionMode:n.sessionMode,lastActivity:Date.now(),launchedAt:Date.now()});else process.stderr.write(`[greedysearch] Refusing to kill unverified listener ${t} on port ${h}.
|
|
319
|
-
`)}function Kn(){zt(c,{recursive:!0});try{let n=JSON.stringify({pid:process.pid,ts:Date.now()});return N(j,n,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{let t=X(j,"utf8");if(JSON.parse(t).pid===process.pid)J(j)}catch{}}}}catch(n){if(n?.code!=="EEXIST")return{acquired:!1,release:()=>{}}}try{let n=X(j,"utf8"),t=JSON.parse(n),e=Date.now()-(t.ts||0);if(!V(t.pid)||e>Mt){try{J(j)}catch{}try{let r=JSON.stringify({pid:process.pid,ts:Date.now()});return N(j,r,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{J(j)}catch{}}}}catch{return{acquired:!1,release:()=>{}}}}}catch{}return{acquired:!1,release:()=>{}}}var Ct=Qn(import.meta.url),Cn=C,z=Y,Yt=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,Gt=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;function St(n,t=h){let e=String(n||"").toLowerCase();if(!e.includes(`--remote-debugging-port=${t}`)||e.includes("--type="))return null;return e.includes("--headless")}function Fn(){try{let n=tn(),t=n?Rn(n):null,e=St(t);if(e!==null){try{E(W,e?"headless":"visible","utf8")}catch{}return e}}catch{}try{if(!Sn(W))return!0;return cn(W,"utf8").trim()==="headless"}catch{return!0}}function Lt(){try{E(z,String(Date.now()),"utf8")}catch{}try{let n=U();if(n)I(n)}catch{}}function Rn(n){try{if(Ln()==="win32")return hn(_("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${n}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return hn(_("ps"),["-p",String(n),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Ft(n){let t=String(n||"").replaceAll("\\","/"),e=c.replaceAll("\\","/");return t.includes(`--remote-debugging-port=${h}`)&&t.includes(`--user-data-dir=${e}`)&&!t.includes("--type=")}function tn(){return P(h)}function nn(){let n=tn();return n&&Ft(Rn(n))?n:null}async function Rt(n=1500){let t=nn();if(!t)return process.stderr.write(`[greedysearch] Refusing to close an unverified listener.
|
|
320
|
-
`),!1;try{let i=await new Promise((o,u)=>{let l=pn.get(`http://localhost:${h}/json/version`,(g)=>{let f="";g.on("data",(s)=>f+=s),g.on("end",()=>{try{o(JSON.parse(f))}catch{u(Error("bad JSON"))}})});l.on("error",u),l.setTimeout(1000,()=>{l.destroy(),u(Error("timeout"))})}),r=new globalThis.WebSocket(i.webSocketDebuggerUrl);await new Promise((o)=>{r.onopen=()=>{if(nn()!==t){r.close(),o();return}r.send(JSON.stringify({id:1,method:"Browser.close"})),setTimeout(()=>{r.close(),o()},200)},r.onerror=()=>o(),setTimeout(o,1000)})}catch{}let e=Date.now()+n;while(Date.now()<e){let i=tn();if(!i)return!0;if(i!==t)return!1;await new Promise((r)=>setTimeout(r,150))}return It(t)}function It(n=null){try{let t=nn();if(!t||n&&t!==n)return!1;if(Ln()==="win32")hn(_("taskkill"),["/F","/PID",String(t)],{stdio:"ignore",windowsHide:!0});else process.kill(t,"SIGKILL");return!0}catch{return!1}}async function In(){if(!nn()){if(tn())process.stderr.write(`[greedysearch] Refusing to kill an unverified listener.
|
|
321
|
-
`);return!1}if(!await b(500)){try{$(Cn)}catch{}try{$(z)}catch{}try{$(W)}catch{}return!1}let t=await Rt(1500);try{$(Cn)}catch{}try{$(z)}catch{}try{$(W)}catch{}if(t)process.stderr.write(`[greedysearch] Killed Chrome on port ${h}.
|
|
322
|
-
`);return t}var Yn=In;async function dt(){let t=Fn()?Yt:Gt;if(t<=0)return!1;if(!Sn(z))return Lt(),!1;try{let e=Number.parseInt(cn(z,"utf8").trim(),10);if(!e)return!1;if((Date.now()-e)/60000>=t)return In()}catch{}return!1}function b(n=3000){return new Promise((t)=>{let e=pn.get(`http://localhost:${h}/json/version`,(i)=>{i.resume(),t(i.statusCode===200)});e.on("error",()=>t(!1)),e.setTimeout(n,()=>{e.destroy(),t(!1)})})}async function Gn(n=3000,t=200){let e=Date.now()+n;while(Date.now()<e){if(!await b(300))return!0;await new Promise((i)=>setTimeout(i,t))}return!await b(300)}async function d(){let n=`${k}.lock`,t=`${k}.tmp`,e=5000,i=1000,r=await new Promise((o)=>{let u=Date.now(),l=()=>{try{let g=JSON.stringify({pid:process.pid,ts:Date.now()});E(n,g,{encoding:"utf8",flag:"wx"}),o(!0)}catch(g){if(g?.code!=="EEXIST"){if(Date.now()-u<1000)setTimeout(l,50);else o(!1);return}try{let f=cn(n,"utf8").trim(),s=f.startsWith("{")?JSON.parse(f):{ts:Number(f)},v=Number(s?.ts)||0;if(v>0&&Date.now()-v>5000)try{$(n)}catch{}if(Date.now()-u<1000)setTimeout(l,50);else o(!1)}catch{if(Date.now()-u<1000)setTimeout(l,50);else o(!1)}}};l()});try{let o=await new Promise((g,f)=>{let s=pn.get(`http://localhost:${h}/json/version`,(v)=>{let A="";v.on("data",(M)=>A+=M),v.on("end",()=>g(A))});s.on("error",f),s.setTimeout(3000,()=>{s.destroy(),f(Error("timeout"))})}),{webSocketDebuggerUrl:u}=JSON.parse(o),l=new URL(u).pathname;if(r){E(t,`${h}
|
|
323
|
-
${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}async function dn(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD&&await b()){await d();try{let o=U();if(o)I(o),sn(o)}catch{}return}Pn();let n=await dt(),t=n?!1:await b();if(!t&&!n)await new Promise((o)=>setTimeout(o,500)),t=await b();let e=!1;if(t){let o=Fn(),u=process.env.GREEDY_SEARCH_VISIBLE==="1";if(!u&&!o)process.stderr.write(`[greedysearch] Visible Chrome detected — switching to headless mode...
|
|
324
|
-
`),await Yn(),await Gn(),e=!0;else if(u&&o)process.stderr.write(`[greedysearch] Headless Chrome detected — switching to visible mode...
|
|
325
|
-
`),await Yn(),await Gn(),e=!0}if(e?!1:await b()){await d();try{let o=U();if(o)I(o),sn(o)}catch{}return}let r=Kn();if(!r.acquired){let o=Date.now()+12000,u=!1;while(Date.now()<o){if(u=await b(500),u)break;await new Promise((l)=>setTimeout(l,250))}if(u){await d();return}}try{if(await b(1000)){await d();return}process.stderr.write(`GreedySearch Chrome not running on port ${h} — auto-launching...
|
|
326
|
-
`);let l=[kn({moduleDir:Ct,entrypoint:process.argv[1],env:process.env})];if(process.env.GREEDY_SEARCH_VISIBLE!=="1")l.push("--headless");await new Promise((g,f)=>{Pt(Xn(),l,{stdio:["ignore",process.stderr,process.stderr]}).on("close",(v)=>v===0?g():f(Error("launch.mjs failed")))})}finally{r.release()}}var Et=`
|
|
327
|
-
(function() {
|
|
328
|
-
// Google consent page (consent.google.com)
|
|
329
|
-
var g = document.querySelector('#L2AGLb, button[jsname="b3VHJd"], .tHlp8d');
|
|
330
|
-
if (g) { g.click(); return 'google'; }
|
|
331
|
-
|
|
332
|
-
// OneTrust (used by many sites including Stack Overflow)
|
|
333
|
-
var ot = document.querySelector('#onetrust-accept-btn-handler, .onetrust-accept-btn-handler');
|
|
334
|
-
if (ot) { ot.click(); return 'onetrust'; }
|
|
335
|
-
|
|
336
|
-
// Generic "accept all" / "agree" buttons
|
|
337
|
-
var btns = Array.from(document.querySelectorAll('button, a[role=button]'));
|
|
338
|
-
var accept = btns.find(b => /^(accept all|accept cookies|agree|i agree|got it|allow all|allow cookies)$/i.test(b.innerText?.trim()));
|
|
339
|
-
if (accept) { accept.click(); return 'generic:' + accept.innerText.trim(); }
|
|
340
|
-
|
|
341
|
-
return null;
|
|
342
|
-
})()
|
|
343
|
-
`;async function wn(n,t){let e=await t(["eval",n,Et]).catch(()=>null);if(e&&e!=="null")await new Promise((i)=>setTimeout(i,1500))}var w={input:'textarea[name="newMessage"]',submitButton:'button[aria-label="Submit search"]',answerContainer:'div[class*="prose"]',paperCard:'a[data-testid="search-result"]',exportButton:'button[aria-label="Export"]'};async function ne(n){return await a(["eval",n,`(() => {
|
|
1
|
+
import {
|
|
2
|
+
buildEnvelope,
|
|
3
|
+
cdp,
|
|
4
|
+
cdpWithInput,
|
|
5
|
+
formatAnswer,
|
|
6
|
+
getOrOpenTab,
|
|
7
|
+
handleError,
|
|
8
|
+
jitter,
|
|
9
|
+
logStage,
|
|
10
|
+
outputJson,
|
|
11
|
+
parseArgs,
|
|
12
|
+
prepareArgs,
|
|
13
|
+
TIMING,
|
|
14
|
+
validateQuery,
|
|
15
|
+
verifyInputText,
|
|
16
|
+
waitForSelector
|
|
17
|
+
} from "./common.mjs";
|
|
18
|
+
import { ensureChrome } from "../src/search/chrome.mjs";
|
|
19
|
+
import { dismissConsent } from "./consent.mjs";
|
|
20
|
+
const SELECTORS = {
|
|
21
|
+
input: 'textarea[name="newMessage"]',
|
|
22
|
+
submitButton: 'button[aria-label="Submit search"]',
|
|
23
|
+
answerContainer: 'div[class*="prose"]',
|
|
24
|
+
paperCard: 'a[data-testid="search-result"]',
|
|
25
|
+
exportButton: 'button[aria-label="Export"]'
|
|
26
|
+
};
|
|
27
|
+
async function detectSignUpWall(tab) {
|
|
28
|
+
const code = `(() => {
|
|
344
29
|
const url = document.location.href || '';
|
|
345
30
|
return url.indexOf('/sign-up/') !== -1 || url.indexOf('redirect_url=') !== -1;
|
|
346
|
-
})()
|
|
31
|
+
})()`;
|
|
32
|
+
const result = await cdp(["eval", tab, code]).catch(() => "false");
|
|
33
|
+
return result === "true";
|
|
34
|
+
}
|
|
35
|
+
async function detectStaleClerkSession(tab) {
|
|
36
|
+
const code = `(() => {
|
|
347
37
|
const url = document.location.href || '';
|
|
348
38
|
const title = document.title || '';
|
|
349
39
|
const text = document.body?.innerText || '';
|
|
@@ -354,14 +44,91 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
354
44
|
text.includes('refresh_request_origin_azp_mismatch') ||
|
|
355
45
|
(text.includes('HTTP ERROR 405') && text.includes('This page isn'));
|
|
356
46
|
return JSON.stringify({ stale, url, title, text: text.slice(0, 500) });
|
|
357
|
-
})()
|
|
358
|
-
|
|
47
|
+
})()`;
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(await cdp(["eval", tab, code], 5000));
|
|
50
|
+
} catch {
|
|
51
|
+
return { stale: false, url: "", title: "", text: "" };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function clearConsensusAuthStorage(tab) {
|
|
55
|
+
for (const origin of [
|
|
56
|
+
"https://consensus.app",
|
|
57
|
+
"https://clerk.consensus.app"
|
|
58
|
+
]) {
|
|
59
|
+
await cdp([
|
|
60
|
+
"evalraw",
|
|
61
|
+
tab,
|
|
62
|
+
"Storage.clearDataForOrigin",
|
|
63
|
+
JSON.stringify({ origin, storageTypes: "all" })
|
|
64
|
+
]).catch((e) => {
|
|
65
|
+
console.error(`[consensus] Warning: failed to clear stale auth storage for ${origin}: ${e.message}`);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function recoverStaleClerkSession(tab, env, startTime) {
|
|
70
|
+
const before = await detectStaleClerkSession(tab);
|
|
71
|
+
if (!before.stale)
|
|
72
|
+
return false;
|
|
73
|
+
logStage(env, "auth-storage-reset", startTime);
|
|
74
|
+
console.error(`[consensus] Detected stale Clerk/Consensus auth state (${before.title || before.url}) — clearing per-origin storage and retrying navigation`);
|
|
75
|
+
env.fallbackUsed = "clear-stale-consensus-auth";
|
|
76
|
+
await clearConsensusAuthStorage(tab);
|
|
77
|
+
await cdp(["nav", tab, "https://consensus.app/"], 20000);
|
|
78
|
+
await new Promise((r) => setTimeout(r, 900));
|
|
79
|
+
const after = await detectStaleClerkSession(tab);
|
|
80
|
+
if (after.stale) {
|
|
81
|
+
env.blockedBy = "signin";
|
|
82
|
+
env.verificationResult = "needs-human";
|
|
83
|
+
throw new Error("Consensus auth session is stale — visible Chrome is open. Please sign in again, then rerun the search.");
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
async function typeIntoConsensus(tab, text) {
|
|
88
|
+
await cdp(["click", tab, SELECTORS.input]);
|
|
89
|
+
await new Promise((r) => setTimeout(r, jitter(200)));
|
|
90
|
+
const type = async () => {
|
|
91
|
+
await cdpWithInput(["type", tab, "--stdin"], text);
|
|
92
|
+
await new Promise((r) => setTimeout(r, jitter(300)));
|
|
93
|
+
};
|
|
94
|
+
const readInput = async () => {
|
|
95
|
+
const raw = await cdp([
|
|
96
|
+
"eval",
|
|
97
|
+
tab,
|
|
98
|
+
`JSON.stringify(document.querySelector('${SELECTORS.input}')?.value || '')`
|
|
99
|
+
]);
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(raw);
|
|
102
|
+
} catch {
|
|
103
|
+
return raw;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const verify = async () => verifyInputText(await readInput(), text);
|
|
107
|
+
const clear = async () => {
|
|
108
|
+
await cdp([
|
|
109
|
+
"eval",
|
|
110
|
+
tab,
|
|
111
|
+
`(() => {
|
|
112
|
+
const el = document.querySelector('${SELECTORS.input}');
|
|
359
113
|
if (!el) return false;
|
|
360
114
|
el.focus();
|
|
361
115
|
el.select();
|
|
362
116
|
document.execCommand('delete');
|
|
363
117
|
return true;
|
|
364
|
-
})()`
|
|
118
|
+
})()`
|
|
119
|
+
]);
|
|
120
|
+
};
|
|
121
|
+
await type();
|
|
122
|
+
if (await verify())
|
|
123
|
+
return;
|
|
124
|
+
await clear();
|
|
125
|
+
await type();
|
|
126
|
+
if (!await verify()) {
|
|
127
|
+
throw new Error("Consensus input did not accept text — input verification failed");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function installPapersDetailsInterceptor(tab) {
|
|
131
|
+
const code = `(() => {
|
|
365
132
|
if (window.__pdiInstalled) return 'already';
|
|
366
133
|
window.__pdiInstalled = true;
|
|
367
134
|
const _origOpen = XMLHttpRequest.prototype.open;
|
|
@@ -402,9 +169,14 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
402
169
|
return _origSend.apply(this, arguments);
|
|
403
170
|
};
|
|
404
171
|
return 'installed';
|
|
405
|
-
})()
|
|
406
|
-
|
|
407
|
-
|
|
172
|
+
})()`;
|
|
173
|
+
const r = await cdp(["eval", tab, code]);
|
|
174
|
+
return r === "installed" || r === "already";
|
|
175
|
+
}
|
|
176
|
+
async function fetchPapersDetailsResponse(tab, timeoutMs = 1e4, afterTs = 0) {
|
|
177
|
+
const code = `new Promise((resolve) => {
|
|
178
|
+
const _deadline = Date.now() + ${timeoutMs};
|
|
179
|
+
const _after = ${afterTs};
|
|
408
180
|
function _check() {
|
|
409
181
|
const store = window.__papersDetailsResps;
|
|
410
182
|
const latest = store && store.latest;
|
|
@@ -424,10 +196,24 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
424
196
|
}
|
|
425
197
|
}
|
|
426
198
|
_check();
|
|
427
|
-
})
|
|
199
|
+
})`;
|
|
200
|
+
const result = await cdp(["eval", tab, code], timeoutMs + 5000);
|
|
201
|
+
try {
|
|
202
|
+
return JSON.parse(result);
|
|
203
|
+
} catch {
|
|
204
|
+
return { ok: false, reason: "invalid-json" };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function expandReferences(tab, maxClicks = 8) {
|
|
208
|
+
const ready = await waitForSelector(tab, SELECTORS.paperCard, 20000, 500).catch(() => false);
|
|
209
|
+
if (!ready) {
|
|
210
|
+
console.error("[consensus] Warning: no paper cards appeared within 20s — Load More will be skipped");
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
const code = String.raw`
|
|
428
214
|
new Promise((resolve) => {
|
|
429
|
-
const _paperSel = '${
|
|
430
|
-
const _maxClicks = ${
|
|
215
|
+
const _paperSel = '${SELECTORS.paperCard}';
|
|
216
|
+
const _maxClicks = ${maxClicks};
|
|
431
217
|
function _findLoadMore() {
|
|
432
218
|
const btns = Array.from(document.querySelectorAll('button'));
|
|
433
219
|
return btns.find(b => {
|
|
@@ -460,10 +246,23 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
460
246
|
}
|
|
461
247
|
_loop();
|
|
462
248
|
})
|
|
463
|
-
|
|
249
|
+
`;
|
|
250
|
+
const result = await cdp(["eval", tab, code], maxClicks * 5000 + 5000).catch(() => null);
|
|
251
|
+
if (!result)
|
|
252
|
+
return 0;
|
|
253
|
+
try {
|
|
254
|
+
const { clicks, cards } = JSON.parse(result);
|
|
255
|
+
console.error(`[consensus] expandReferences: ${clicks} click(s), ${cards} card(s)`);
|
|
256
|
+
return clicks;
|
|
257
|
+
} catch {
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function waitForCardsStable(tab, maxMs = 1200) {
|
|
262
|
+
const code = String.raw`
|
|
464
263
|
new Promise((resolve) => {
|
|
465
|
-
const _sel = '${
|
|
466
|
-
const _deadline = Date.now() + ${
|
|
264
|
+
const _sel = '${SELECTORS.paperCard}';
|
|
265
|
+
const _deadline = Date.now() + ${maxMs};
|
|
467
266
|
let _last = document.querySelectorAll(_sel).length;
|
|
468
267
|
function _poll() {
|
|
469
268
|
const cur = document.querySelectorAll(_sel).length;
|
|
@@ -474,20 +273,93 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
474
273
|
}
|
|
475
274
|
setTimeout(_poll, 300);
|
|
476
275
|
})
|
|
477
|
-
`;
|
|
478
|
-
|
|
276
|
+
`;
|
|
277
|
+
await cdp(["eval", tab, code], maxMs + 3000).catch(() => null);
|
|
278
|
+
}
|
|
279
|
+
async function clickExportCsv(tab) {
|
|
280
|
+
await cdp([
|
|
281
|
+
"eval",
|
|
282
|
+
tab,
|
|
283
|
+
`(() => {
|
|
284
|
+
const btn = document.querySelector('${SELECTORS.exportButton}');
|
|
479
285
|
if (!btn) return 'no-export';
|
|
480
286
|
btn.scrollIntoView({ block: 'center' });
|
|
481
287
|
btn.click();
|
|
482
288
|
return 'opened';
|
|
483
|
-
})()`
|
|
289
|
+
})()`
|
|
290
|
+
]);
|
|
291
|
+
await new Promise((r) => setTimeout(r, 600));
|
|
292
|
+
const clicked = await cdp([
|
|
293
|
+
"eval",
|
|
294
|
+
tab,
|
|
295
|
+
`(() => {
|
|
484
296
|
const btn = Array.from(document.querySelectorAll('button'))
|
|
485
297
|
.find(b => /\\.CSV/.test((b.innerText || '').trim()));
|
|
486
298
|
if (!btn) return 'no-csv';
|
|
487
299
|
btn.click();
|
|
488
300
|
return 'clicked';
|
|
489
|
-
})()`
|
|
490
|
-
|
|
301
|
+
})()`
|
|
302
|
+
]);
|
|
303
|
+
return clicked;
|
|
304
|
+
}
|
|
305
|
+
function buildSourcesFromApi(respData) {
|
|
306
|
+
const map = respData?.paperDetailsListByPaperId || {};
|
|
307
|
+
const ids = Object.keys(map);
|
|
308
|
+
const sources = [];
|
|
309
|
+
for (let i = 0;i < ids.length; i++) {
|
|
310
|
+
const p = map[ids[i]] || {};
|
|
311
|
+
const urlSlug = p.url_slug || "";
|
|
312
|
+
const paperId = p.paper_id || p.hash_paper_id || ids[i];
|
|
313
|
+
let url;
|
|
314
|
+
if (urlSlug) {
|
|
315
|
+
url = `https://consensus.app/papers/${urlSlug}/${paperId}/`;
|
|
316
|
+
} else if (p.provider_url) {
|
|
317
|
+
url = p.provider_url;
|
|
318
|
+
} else if (p.doi) {
|
|
319
|
+
url = `https://doi.org/${p.doi}`;
|
|
320
|
+
} else {
|
|
321
|
+
url = `https://consensus.app/paper/${paperId}`;
|
|
322
|
+
}
|
|
323
|
+
const tags = [];
|
|
324
|
+
const badges = p.badges || {};
|
|
325
|
+
if (badges.study_type === "rct")
|
|
326
|
+
tags.push("RCT");
|
|
327
|
+
else if (badges.study_type === "meta_analysis")
|
|
328
|
+
tags.push("META-ANALYSIS");
|
|
329
|
+
else if (badges.study_type === "systematic_review")
|
|
330
|
+
tags.push("SYSTEMATIC REVIEW");
|
|
331
|
+
else if (badges.study_type)
|
|
332
|
+
tags.push(badges.study_type.toUpperCase());
|
|
333
|
+
if (badges.rigorous_journal)
|
|
334
|
+
tags.push("RIGOROUS JOURNAL");
|
|
335
|
+
if (badges.very_rigorous_journal)
|
|
336
|
+
tags.push("VERY RIGOROUS JOURNAL");
|
|
337
|
+
if (badges.highly_cited_paper)
|
|
338
|
+
tags.push("HIGHLY CITED");
|
|
339
|
+
if (badges.large_human_trial)
|
|
340
|
+
tags.push("LARGE HUMAN TRIAL");
|
|
341
|
+
if (p.is_retracted)
|
|
342
|
+
tags.push("RETRACTED");
|
|
343
|
+
if (p.open_access_pdf_url)
|
|
344
|
+
tags.push("OPEN ACCESS");
|
|
345
|
+
sources.push({
|
|
346
|
+
title: p.title || "",
|
|
347
|
+
url,
|
|
348
|
+
rank: i + 1,
|
|
349
|
+
authors: Array.isArray(p.authors) ? p.authors : [],
|
|
350
|
+
year: p.year || null,
|
|
351
|
+
journal: p.journal || p.publisher_name || null,
|
|
352
|
+
doi: p.doi || null,
|
|
353
|
+
citation_count: p.citation_count || 0,
|
|
354
|
+
snippet: p.abstract_takeaway || "",
|
|
355
|
+
tags
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
return sources;
|
|
359
|
+
}
|
|
360
|
+
async function extractSourcesFromDom(tab) {
|
|
361
|
+
const code = `(() => {
|
|
362
|
+
const cards = Array.from(document.querySelectorAll('${SELECTORS.paperCard}'));
|
|
491
363
|
const sources = [];
|
|
492
364
|
const seen = new Set();
|
|
493
365
|
for (const card of cards) {
|
|
@@ -509,8 +381,147 @@ ${l}`,"utf8");try{$(k)}catch{}Kt(t,k)}}catch{}finally{if(r)try{$(n)}catch{}}}asy
|
|
|
509
381
|
sources.push({ title, url, rank, snippet, tags });
|
|
510
382
|
}
|
|
511
383
|
return JSON.stringify(sources);
|
|
512
|
-
})()
|
|
513
|
-
|
|
384
|
+
})()`;
|
|
385
|
+
const result = await cdp(["eval", tab, code], 1e4);
|
|
386
|
+
try {
|
|
387
|
+
return JSON.parse(result);
|
|
388
|
+
} catch {
|
|
389
|
+
return [];
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async function extractAnswer(tab) {
|
|
393
|
+
const code = `(() => {
|
|
394
|
+
const prose = document.querySelector('${SELECTORS.answerContainer}');
|
|
514
395
|
return prose?.innerText?.trim() || '';
|
|
515
|
-
})()`;
|
|
516
|
-
|
|
396
|
+
})()`;
|
|
397
|
+
return await cdp(["eval", tab, code], 1e4) || "";
|
|
398
|
+
}
|
|
399
|
+
const USAGE = `Usage: node extractors/consensus.mjs "<query>" [--tab <prefix>]
|
|
400
|
+
`;
|
|
401
|
+
async function main() {
|
|
402
|
+
const args = await prepareArgs(process.argv.slice(2));
|
|
403
|
+
validateQuery(args, USAGE);
|
|
404
|
+
const { query, tabPrefix, short } = parseArgs(args);
|
|
405
|
+
const startTime = Date.now();
|
|
406
|
+
const mode = process.env.GREEDY_SEARCH_VISIBLE === "1" ? "visible" : "headless";
|
|
407
|
+
const env = {
|
|
408
|
+
engine: "consensus",
|
|
409
|
+
mode,
|
|
410
|
+
clipboardEmpty: null,
|
|
411
|
+
fallbackUsed: null,
|
|
412
|
+
blockedBy: null,
|
|
413
|
+
verificationResult: null,
|
|
414
|
+
inputReady: null
|
|
415
|
+
};
|
|
416
|
+
try {
|
|
417
|
+
if (process.env.GREEDY_SEARCH_VISIBLE !== "1" && process.env.GREEDY_SEARCH_ALWAYS_VISIBLE !== "1") {
|
|
418
|
+
process.env.GREEDY_SEARCH_HEADLESS = "1";
|
|
419
|
+
}
|
|
420
|
+
await ensureChrome();
|
|
421
|
+
if (!tabPrefix)
|
|
422
|
+
await cdp(["list"]);
|
|
423
|
+
const tab = await getOrOpenTab(tabPrefix);
|
|
424
|
+
const currentUrl = await cdp(["eval", tab, "document.location.href"]).catch(() => "");
|
|
425
|
+
let onConsensus = false;
|
|
426
|
+
try {
|
|
427
|
+
const host = new URL(currentUrl).hostname.toLowerCase();
|
|
428
|
+
onConsensus = host === "consensus.app" || host.endsWith(".consensus.app");
|
|
429
|
+
} catch {}
|
|
430
|
+
if (!onConsensus) {
|
|
431
|
+
logStage(env, "nav", startTime);
|
|
432
|
+
await cdp(["nav", tab, "https://consensus.app/"], 20000);
|
|
433
|
+
await new Promise((r) => setTimeout(r, 600));
|
|
434
|
+
}
|
|
435
|
+
await recoverStaleClerkSession(tab, env, startTime);
|
|
436
|
+
await dismissConsent(tab, cdp);
|
|
437
|
+
logStage(env, "input-wait", startTime);
|
|
438
|
+
const inputReady = await waitForSelector(tab, SELECTORS.input, 15000, 400);
|
|
439
|
+
env.inputReady = inputReady;
|
|
440
|
+
if (!inputReady) {
|
|
441
|
+
const recovered = await recoverStaleClerkSession(tab, env, startTime);
|
|
442
|
+
if (recovered) {
|
|
443
|
+
const retryInputReady = await waitForSelector(tab, SELECTORS.input, 15000, 400);
|
|
444
|
+
env.inputReady = retryInputReady;
|
|
445
|
+
if (retryInputReady) {
|
|
446
|
+
await dismissConsent(tab, cdp);
|
|
447
|
+
} else {
|
|
448
|
+
throw new Error("Consensus input not found after stale auth recovery — page may not have loaded or is in unexpected state");
|
|
449
|
+
}
|
|
450
|
+
} else {
|
|
451
|
+
throw new Error("Consensus input not found — page may not have loaded or is in unexpected state");
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
await new Promise((r) => setTimeout(r, jitter(TIMING.postClick)));
|
|
455
|
+
logStage(env, "type-and-submit", startTime);
|
|
456
|
+
await typeIntoConsensus(tab, query);
|
|
457
|
+
await new Promise((r) => setTimeout(r, jitter(TIMING.postType)));
|
|
458
|
+
await cdp([
|
|
459
|
+
"eval",
|
|
460
|
+
tab,
|
|
461
|
+
`document.querySelector('${SELECTORS.submitButton}')?.click()`
|
|
462
|
+
]);
|
|
463
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
464
|
+
if (await detectSignUpWall(tab)) {
|
|
465
|
+
env.blockedBy = "signin";
|
|
466
|
+
throw new Error("Consensus requires sign-in — please sign in or create a free account in the visible browser window. Once signed in, cookies persist for future runs.");
|
|
467
|
+
}
|
|
468
|
+
logStage(env, "answer-wait", startTime);
|
|
469
|
+
await waitForSelector(tab, SELECTORS.answerContainer, 30000, 500);
|
|
470
|
+
await installPapersDetailsInterceptor(tab);
|
|
471
|
+
logStage(env, "expand-refs", startTime);
|
|
472
|
+
const clicks = await expandReferences(tab, 8);
|
|
473
|
+
if (clicks === 0) {
|
|
474
|
+
console.error("[consensus] Note: 'Load more results' button not present (initial page has all references)");
|
|
475
|
+
} else {
|
|
476
|
+
console.error(`[consensus] Clicked 'Load more results' ${clicks} time(s) to expand references`);
|
|
477
|
+
}
|
|
478
|
+
await waitForCardsStable(tab, 1200);
|
|
479
|
+
logStage(env, "csv-click", startTime);
|
|
480
|
+
const preClickTs = Number(await cdp(["eval", tab, "Date.now()"]).catch(() => "0") || 0);
|
|
481
|
+
const csvResult = await clickExportCsv(tab);
|
|
482
|
+
if (csvResult !== "clicked") {
|
|
483
|
+
console.error(`[consensus] Export → .CSV click did not register (${csvResult}) — falling back to DOM`);
|
|
484
|
+
}
|
|
485
|
+
logStage(env, "wait-csv-resp", startTime);
|
|
486
|
+
const csvResp = await fetchPapersDetailsResponse(tab, 12000, preClickTs);
|
|
487
|
+
let sources = [];
|
|
488
|
+
let sourcePath = "dom";
|
|
489
|
+
if (csvResp.ok) {
|
|
490
|
+
sources = buildSourcesFromApi(csvResp.data);
|
|
491
|
+
sourcePath = "api-intercept";
|
|
492
|
+
console.error(`[consensus] Captured /api/papers/details/ response with ${csvResp.count} paper(s)`);
|
|
493
|
+
} else {
|
|
494
|
+
console.error(`[consensus] /api/papers/details/ response not captured (${csvResp.reason}) — falling back to DOM cards`);
|
|
495
|
+
}
|
|
496
|
+
logStage(env, "extract", startTime);
|
|
497
|
+
const answer = await extractAnswer(tab);
|
|
498
|
+
if (!answer) {
|
|
499
|
+
throw new Error("No answer extracted — Consensus may not have responded");
|
|
500
|
+
}
|
|
501
|
+
if (sources.length === 0) {
|
|
502
|
+
sources = await extractSourcesFromDom(tab);
|
|
503
|
+
} else {
|
|
504
|
+
const domSources = await extractSourcesFromDom(tab);
|
|
505
|
+
const apiUrls = new Set(sources.map((s) => s.url));
|
|
506
|
+
for (const ds of domSources) {
|
|
507
|
+
if (!apiUrls.has(ds.url))
|
|
508
|
+
sources.push(ds);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const finalUrl = await cdp(["eval", tab, "document.location.href"]).catch(() => "");
|
|
512
|
+
env.durationMs = Date.now() - startTime;
|
|
513
|
+
env.sourcePath = sourcePath;
|
|
514
|
+
logStage(env, "done", startTime);
|
|
515
|
+
outputJson({
|
|
516
|
+
query,
|
|
517
|
+
url: finalUrl,
|
|
518
|
+
answer: formatAnswer(answer, short),
|
|
519
|
+
sources,
|
|
520
|
+
_envelope: buildEnvelope(env)
|
|
521
|
+
});
|
|
522
|
+
} catch (e) {
|
|
523
|
+
env.durationMs = Date.now() - startTime;
|
|
524
|
+
handleError(e, buildEnvelope(env));
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
main();
|