@duckmind/dm-windows-x64 0.62.3 → 0.63.0

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.
Files changed (93) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +43 -183
  3. package/extensions/dm-context/src/context.js +1 -2
  4. package/extensions/dm-context/src/index.js +1 -2
  5. package/extensions/{greedysearch-dm/bin/cdp.mjs → dm-cua/bin/browser-cdp.mjs} +3 -3
  6. package/extensions/dm-cua/bin/browser-cua.mjs +1 -1
  7. package/extensions/{greedysearch-dm/bin/launch.mjs → dm-cua/bin/browser-launch.mjs} +12 -11
  8. package/extensions/dm-cua/index.js +1 -1
  9. package/extensions/dm-cua/src/browser-cua-lib.mjs +17 -12
  10. package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/constants.mjs +11 -11
  11. package/extensions/{greedysearch-dm/src/utils → dm-cua/src/browser-helpers}/node-runtime.mjs +1 -1
  12. package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/port-pid.mjs +1 -1
  13. package/extensions/dm-ponytail/extensions/ponytail.mjs +186 -0
  14. package/extensions/dm-ponytail/hooks/claude-codex-hooks.json +41 -0
  15. package/extensions/dm-ponytail/hooks/copilot-hooks.json +21 -0
  16. package/extensions/dm-ponytail/hooks/ponytail-activate.js +59 -0
  17. package/extensions/dm-ponytail/hooks/ponytail-config.js +116 -0
  18. package/extensions/dm-ponytail/hooks/ponytail-instructions.js +81 -0
  19. package/extensions/dm-ponytail/hooks/ponytail-mode-tracker.js +96 -0
  20. package/extensions/dm-ponytail/hooks/ponytail-runtime.js +79 -0
  21. package/extensions/dm-ponytail/hooks/ponytail-statusline.ps1 +24 -0
  22. package/extensions/dm-ponytail/hooks/ponytail-statusline.sh +18 -0
  23. package/extensions/dm-ponytail/hooks/ponytail-subagent.js +50 -0
  24. package/extensions/dm-ponytail/hooks/qoder-hooks.json +26 -0
  25. package/extensions/dm-ponytail/package.json +19 -0
  26. package/extensions/dm-ponytail/pi-extension/index.js +186 -0
  27. package/extensions/dm-ponytail/pi-extension/package.json +8 -0
  28. package/extensions/dm-ponytail/skills/ponytail/SKILL.md +120 -0
  29. package/extensions/dm-ponytail/skills/ponytail-audit/SKILL.md +41 -0
  30. package/extensions/dm-ponytail/skills/ponytail-debt/SKILL.md +44 -0
  31. package/extensions/dm-ponytail/skills/ponytail-gain/SKILL.md +50 -0
  32. package/extensions/dm-ponytail/skills/ponytail-help/SKILL.md +71 -0
  33. package/extensions/dm-ponytail/skills/ponytail-review/SKILL.md +57 -0
  34. package/package.json +2 -6
  35. package/extensions/dm-caveman/extensions/caveman.js +0 -300
  36. package/extensions/dm-caveman/package.json +0 -20
  37. package/extensions/dm-goal/package.json +0 -23
  38. package/extensions/dm-goal/src/goal.js +0 -914
  39. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +0 -40
  40. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +0 -5
  41. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +0 -5
  42. package/extensions/greedysearch-dm/bin/gschrome.mjs +0 -30
  43. package/extensions/greedysearch-dm/bin/kill-visible.mjs +0 -7
  44. package/extensions/greedysearch-dm/bin/launch-visible.mjs +0 -13
  45. package/extensions/greedysearch-dm/bin/mcp.mjs +0 -400
  46. package/extensions/greedysearch-dm/bin/search.mjs +0 -635
  47. package/extensions/greedysearch-dm/bin/visible.mjs +0 -22
  48. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +0 -344
  49. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +0 -354
  50. package/extensions/greedysearch-dm/extractors/common.mjs +0 -794
  51. package/extensions/greedysearch-dm/extractors/consensus.mjs +0 -527
  52. package/extensions/greedysearch-dm/extractors/consent.mjs +0 -449
  53. package/extensions/greedysearch-dm/extractors/gemini.mjs +0 -291
  54. package/extensions/greedysearch-dm/extractors/google-ai.mjs +0 -86
  55. package/extensions/greedysearch-dm/extractors/logically.mjs +0 -589
  56. package/extensions/greedysearch-dm/extractors/perplexity.mjs +0 -370
  57. package/extensions/greedysearch-dm/extractors/selectors.mjs +0 -32
  58. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +0 -199
  59. package/extensions/greedysearch-dm/index.js +0 -123
  60. package/extensions/greedysearch-dm/package.json +0 -27
  61. package/extensions/greedysearch-dm/skills/greedy-search/skill.md +0 -18
  62. package/extensions/greedysearch-dm/src/fetcher.mjs +0 -577
  63. package/extensions/greedysearch-dm/src/formatters/results.js +0 -95
  64. package/extensions/greedysearch-dm/src/formatters/sources.js +0 -57
  65. package/extensions/greedysearch-dm/src/formatters/synthesis.js +0 -49
  66. package/extensions/greedysearch-dm/src/github.mjs +0 -228
  67. package/extensions/greedysearch-dm/src/reddit.mjs +0 -154
  68. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +0 -340
  69. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +0 -156
  70. package/extensions/greedysearch-dm/src/search/chrome.mjs +0 -510
  71. package/extensions/greedysearch-dm/src/search/defaults.mjs +0 -10
  72. package/extensions/greedysearch-dm/src/search/engines.mjs +0 -79
  73. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +0 -470
  74. package/extensions/greedysearch-dm/src/search/file-sources.mjs +0 -31
  75. package/extensions/greedysearch-dm/src/search/output.mjs +0 -51
  76. package/extensions/greedysearch-dm/src/search/paths.mjs +0 -48
  77. package/extensions/greedysearch-dm/src/search/pdf.mjs +0 -64
  78. package/extensions/greedysearch-dm/src/search/progress.mjs +0 -109
  79. package/extensions/greedysearch-dm/src/search/query.mjs +0 -21
  80. package/extensions/greedysearch-dm/src/search/recovery.mjs +0 -49
  81. package/extensions/greedysearch-dm/src/search/research.mjs +0 -2255
  82. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +0 -61
  83. package/extensions/greedysearch-dm/src/search/simple-research.mjs +0 -418
  84. package/extensions/greedysearch-dm/src/search/sources.mjs +0 -412
  85. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +0 -127
  86. package/extensions/greedysearch-dm/src/search/synthesis.mjs +0 -202
  87. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +0 -209
  88. package/extensions/greedysearch-dm/src/tools/shared.js +0 -226
  89. package/extensions/greedysearch-dm/src/types.js +0 -0
  90. package/extensions/greedysearch-dm/src/utils/content.mjs +0 -38
  91. package/extensions/greedysearch-dm/src/utils/helpers.js +0 -22
  92. /package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/minimize.mjs +0 -0
  93. /package/extensions/{greedysearch-dm/src/utils → dm-cua/src/browser-helpers}/system-cmds.mjs +0 -0
@@ -1,340 +0,0 @@
1
- import { execFileSync, execSync } from "node:child_process";
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readFileSync,
6
- unlinkSync,
7
- writeFileSync
8
- } from "node:fs";
9
- import { platform } from "node:os";
10
- import {
11
- CHROME_MODE_FILE,
12
- GREEDY_ACTIVITY_FILE,
13
- GREEDY_LAUNCH_LOCK_FILE,
14
- GREEDY_METADATA_FILE,
15
- GREEDY_PID_FILE,
16
- GREEDY_PORT,
17
- GREEDY_PROFILE_DIR
18
- } from "./constants.mjs";
19
- import { resolveSystemCmd } from "../utils/system-cmds.mjs";
20
- import { findListeningProcessPid } from "./port-pid.mjs";
21
- export const METADATA_FILE = GREEDY_METADATA_FILE;
22
- const LAUNCH_LOCK_FILE = GREEDY_LAUNCH_LOCK_FILE;
23
- const LOCK_STALE_MS = 15000;
24
- const LEGACY_PID_FILE = GREEDY_PID_FILE;
25
- const LEGACY_MODE_FILE = CHROME_MODE_FILE;
26
- const LEGACY_ACTIVITY_FILE = GREEDY_ACTIVITY_FILE;
27
- function processExists(pid) {
28
- if (!Number.isInteger(pid) || pid <= 0)
29
- return false;
30
- try {
31
- process.kill(pid, 0);
32
- return true;
33
- } catch {
34
- return false;
35
- }
36
- }
37
- function getProcessCommandLine(pid) {
38
- if (!processExists(pid))
39
- return null;
40
- try {
41
- if (platform() === "win32") {
42
- const output = execFileSync(resolveSystemCmd("powershell"), [
43
- "-NoProfile",
44
- "-NonInteractive",
45
- "-Command",
46
- `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").CommandLine`
47
- ], { encoding: "utf8", windowsHide: true, timeout: 5000 });
48
- return output.trim() || null;
49
- }
50
- const output = execFileSync(resolveSystemCmd("ps"), ["-p", String(pid), "-o", "command="], {
51
- encoding: "utf8",
52
- timeout: 5000
53
- });
54
- return output.trim() || null;
55
- } catch {
56
- return null;
57
- }
58
- }
59
- export function commandLineMatchesGreedyChrome(cmdLine, tempDir, debugPort = GREEDY_PORT) {
60
- if (!cmdLine)
61
- return false;
62
- const normalize = (value) => String(value || "").replaceAll("\\", "/").toLowerCase();
63
- const normalizedCmdLine = normalize(cmdLine);
64
- const normalizedTempDir = normalize(tempDir);
65
- return normalizedCmdLine.includes(normalizedTempDir) && normalizedCmdLine.includes(`--remote-debugging-port=${debugPort}`) && !normalizedCmdLine.includes("--type=");
66
- }
67
- export function verifyBrowserProcess(pid, tempDir, debugPort = GREEDY_PORT) {
68
- return commandLineMatchesGreedyChrome(getProcessCommandLine(pid), tempDir, debugPort);
69
- }
70
- function getPortPid(port = GREEDY_PORT) {
71
- return findListeningProcessPid(port);
72
- }
73
- function forceKillProcess(pid, expectedProfile = null, expectedPort = null) {
74
- if (expectedProfile && !verifyBrowserProcess(pid, expectedProfile, expectedPort))
75
- return false;
76
- try {
77
- if (platform() === "win32") {
78
- execSync(`${resolveSystemCmd("taskkill")} /F /T /PID ${pid}`, {
79
- stdio: "ignore"
80
- });
81
- } else {
82
- try {
83
- process.kill(-pid, "SIGKILL");
84
- } catch {}
85
- try {
86
- process.kill(pid, "SIGKILL");
87
- } catch {}
88
- }
89
- return true;
90
- } catch {
91
- return false;
92
- }
93
- }
94
- export function readMetadata() {
95
- try {
96
- if (existsSync(METADATA_FILE)) {
97
- const raw = readFileSync(METADATA_FILE, "utf8");
98
- const parsed = JSON.parse(raw);
99
- if (parsed && typeof parsed.tempDir === "string" && typeof parsed.debugPort === "number") {
100
- return {
101
- browserPid: Number.isInteger(parsed.browserPid) ? parsed.browserPid : undefined,
102
- debugPort: parsed.debugPort,
103
- tempDir: parsed.tempDir,
104
- clientPids: Array.isArray(parsed.clientPids) ? parsed.clientPids.filter((p) => Number.isInteger(p) && p > 0) : [],
105
- sessionMode: parsed.sessionMode === "visible" ? "visible" : "headless",
106
- lastActivity: Number.isFinite(parsed.lastActivity) ? parsed.lastActivity : 0,
107
- launchedAt: Number.isFinite(parsed.launchedAt) ? parsed.launchedAt : 0
108
- };
109
- }
110
- }
111
- } catch {}
112
- try {
113
- const browserPid = existsSync(LEGACY_PID_FILE) ? Number.parseInt(readFileSync(LEGACY_PID_FILE, "utf8").trim(), 10) || undefined : undefined;
114
- const sessionMode = existsSync(LEGACY_MODE_FILE) ? readFileSync(LEGACY_MODE_FILE, "utf8").trim() === "visible" ? "visible" : "headless" : "headless";
115
- const lastActivity = existsSync(LEGACY_ACTIVITY_FILE) ? Number.parseInt(readFileSync(LEGACY_ACTIVITY_FILE, "utf8").trim(), 10) || 0 : 0;
116
- return {
117
- browserPid,
118
- debugPort: GREEDY_PORT,
119
- tempDir: GREEDY_PROFILE_DIR,
120
- clientPids: browserPid ? [browserPid] : [],
121
- sessionMode,
122
- lastActivity,
123
- launchedAt: 0
124
- };
125
- } catch {
126
- return null;
127
- }
128
- }
129
- export function writeMetadata(metadata) {
130
- try {
131
- writeFileSync(METADATA_FILE, JSON.stringify({
132
- browserPid: metadata.browserPid,
133
- debugPort: metadata.debugPort,
134
- tempDir: metadata.tempDir,
135
- clientPids: [...new Set(metadata.clientPids.filter((p) => p > 0))],
136
- sessionMode: metadata.sessionMode,
137
- lastActivity: metadata.lastActivity,
138
- launchedAt: metadata.launchedAt
139
- }, null, 2), "utf8");
140
- } catch {}
141
- try {
142
- if (metadata.browserPid)
143
- writeFileSync(LEGACY_PID_FILE, String(metadata.browserPid), "utf8");
144
- } catch {}
145
- try {
146
- writeFileSync(LEGACY_MODE_FILE, metadata.sessionMode, "utf8");
147
- } catch {}
148
- try {
149
- writeFileSync(LEGACY_ACTIVITY_FILE, String(metadata.lastActivity), "utf8");
150
- } catch {}
151
- }
152
- export function clearMetadata() {
153
- try {
154
- unlinkSync(METADATA_FILE);
155
- } catch {}
156
- try {
157
- unlinkSync(LEGACY_PID_FILE);
158
- } catch {}
159
- try {
160
- unlinkSync(LEGACY_MODE_FILE);
161
- } catch {}
162
- try {
163
- unlinkSync(LEGACY_ACTIVITY_FILE);
164
- } catch {}
165
- }
166
- export function registerClient(metadata) {
167
- if (!metadata)
168
- return metadata;
169
- const updated = {
170
- ...metadata,
171
- clientPids: [
172
- ...new Set([...metadata.clientPids, process.pid].filter((p) => processExists(p) || p === process.pid))
173
- ]
174
- };
175
- writeMetadata(updated);
176
- return updated;
177
- }
178
- export function unregisterClient(metadata) {
179
- if (!metadata)
180
- return metadata;
181
- const updated = {
182
- ...metadata,
183
- clientPids: metadata.clientPids.filter((p) => p !== process.pid).filter((p) => processExists(p))
184
- };
185
- writeMetadata(updated);
186
- return updated;
187
- }
188
- export function touchActivity(metadata) {
189
- const ts = Date.now();
190
- try {
191
- if (metadata) {
192
- writeMetadata({ ...metadata, lastActivity: ts });
193
- } else {
194
- writeFileSync(LEGACY_ACTIVITY_FILE, String(ts), "utf8");
195
- }
196
- } catch {}
197
- }
198
- const IDLE_TIMEOUT_MINUTES = Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES || "5", 10) || 5;
199
- export function isIdleExpired(metadata) {
200
- if (IDLE_TIMEOUT_MINUTES <= 0)
201
- return false;
202
- if (!metadata || !metadata.lastActivity)
203
- return false;
204
- const idleMs = Date.now() - metadata.lastActivity;
205
- return idleMs / 60000 >= IDLE_TIMEOUT_MINUTES;
206
- }
207
- let _staleCleanupPerformed = false;
208
- export function cleanupStaleSessions() {
209
- if (process.env.GREEDY_SEARCH_RESEARCH_CHILD)
210
- return;
211
- if (_staleCleanupPerformed)
212
- return;
213
- _staleCleanupPerformed = true;
214
- const metadata = readMetadata();
215
- if (!metadata)
216
- return;
217
- if (metadata.browserPid) {
218
- const alive = processExists(metadata.browserPid);
219
- if (!alive) {
220
- clearMetadata();
221
- return;
222
- }
223
- const verified = verifyBrowserProcess(metadata.browserPid, metadata.tempDir, metadata.debugPort);
224
- if (!verified) {
225
- clearMetadata();
226
- } else {
227
- writeMetadata({
228
- ...metadata,
229
- clientPids: metadata.clientPids.filter((p) => processExists(p))
230
- });
231
- }
232
- }
233
- const portPid = getPortPid();
234
- if (portPid && portPid !== metadata.browserPid) {
235
- const verified = verifyBrowserProcess(portPid, GREEDY_PROFILE_DIR, GREEDY_PORT);
236
- if (verified) {
237
- writeMetadata({
238
- browserPid: portPid,
239
- debugPort: GREEDY_PORT,
240
- tempDir: GREEDY_PROFILE_DIR,
241
- clientPids: [portPid],
242
- sessionMode: metadata.sessionMode,
243
- lastActivity: Date.now(),
244
- launchedAt: Date.now()
245
- });
246
- } else {
247
- process.stderr.write(`[greedysearch] Refusing to kill unverified listener ${portPid} on port ${GREEDY_PORT}.
248
- `);
249
- }
250
- }
251
- }
252
- export function acquireLaunchLock() {
253
- mkdirSync(GREEDY_PROFILE_DIR, { recursive: true });
254
- try {
255
- const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
256
- writeFileSync(LAUNCH_LOCK_FILE, payload, { encoding: "utf8", flag: "wx" });
257
- return {
258
- acquired: true,
259
- release: () => {
260
- try {
261
- const raw = readFileSync(LAUNCH_LOCK_FILE, "utf8");
262
- const parsed = JSON.parse(raw);
263
- if (parsed.pid === process.pid) {
264
- unlinkSync(LAUNCH_LOCK_FILE);
265
- }
266
- } catch {}
267
- }
268
- };
269
- } catch (e) {
270
- if (e?.code !== "EEXIST") {
271
- return { acquired: false, release: () => {} };
272
- }
273
- }
274
- try {
275
- const raw = readFileSync(LAUNCH_LOCK_FILE, "utf8");
276
- const parsed = JSON.parse(raw);
277
- const lockAge = Date.now() - (parsed.ts || 0);
278
- const lockPidAlive = processExists(parsed.pid);
279
- if (!lockPidAlive || lockAge > LOCK_STALE_MS) {
280
- try {
281
- unlinkSync(LAUNCH_LOCK_FILE);
282
- } catch {}
283
- try {
284
- const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
285
- writeFileSync(LAUNCH_LOCK_FILE, payload, {
286
- encoding: "utf8",
287
- flag: "wx"
288
- });
289
- return {
290
- acquired: true,
291
- release: () => {
292
- try {
293
- unlinkSync(LAUNCH_LOCK_FILE);
294
- } catch {}
295
- }
296
- };
297
- } catch {
298
- return { acquired: false, release: () => {} };
299
- }
300
- }
301
- } catch {}
302
- return { acquired: false, release: () => {} };
303
- }
304
- export function checkRunning() {
305
- const metadata = readMetadata();
306
- if (!metadata || !metadata.browserPid) {
307
- const portPid = getPortPid();
308
- if (portPid && verifyBrowserProcess(portPid, GREEDY_PROFILE_DIR, GREEDY_PORT)) {
309
- return { running: true, pid: portPid, metadata };
310
- }
311
- return { running: false, pid: null, metadata: null };
312
- }
313
- const alive = processExists(metadata.browserPid);
314
- if (!alive) {
315
- return { running: false, pid: null, metadata };
316
- }
317
- const verified = verifyBrowserProcess(metadata.browserPid, metadata.tempDir, metadata.debugPort);
318
- if (!verified) {
319
- const portPid = getPortPid();
320
- if (portPid && verifyBrowserProcess(portPid, GREEDY_PROFILE_DIR, GREEDY_PORT)) {
321
- return { running: true, pid: portPid, metadata };
322
- }
323
- return { running: false, pid: null, metadata };
324
- }
325
- return { running: true, pid: metadata.browserPid, metadata };
326
- }
327
- export function killChrome() {
328
- const { running, pid, metadata } = checkRunning();
329
- if (!running || !pid) {
330
- clearMetadata();
331
- return false;
332
- }
333
- const killed = forceKillProcess(pid, metadata?.tempDir || GREEDY_PROFILE_DIR, metadata?.debugPort || GREEDY_PORT);
334
- clearMetadata();
335
- return killed;
336
- }
337
- export async function ensureCleanSession() {
338
- cleanupStaleSessions();
339
- return checkRunning();
340
- }
@@ -1,156 +0,0 @@
1
- import { cdp } from "../../extractors/common.mjs";
2
- const DEFAULT_TIMEOUT_MS = Number.parseInt(process.env.GREEDY_SEARCH_CHALLENGE_WAIT_MS || "300000", 10);
3
- const POLL_INTERVAL_MS = 3000;
4
- const ENGINE_SIGNALS = {
5
- chatgpt: {
6
- name: "chatgpt",
7
- isCleared: async (tab) => {
8
- const probe = await cdp([
9
- "eval",
10
- tab,
11
- `(() => {
12
- const title = document.title;
13
- const onChatGPT = location.hostname === "chatgpt.com";
14
- const hasProseMirror = !!document.querySelector("div.ProseMirror");
15
- const hasTurnstileInput =
16
- !!document.querySelector("input[name=\\"cf-turnstile-response\\"]") ||
17
- !!document.querySelector("iframe[id^=\\"cf-chl-widget-\\"]");
18
- // Body innerText is empty while on the Turnstile page.
19
- const bodyText = (document.body && document.body.innerText) || "";
20
- return JSON.stringify({
21
- title,
22
- url: location.href,
23
- hasProseMirror,
24
- hasTurnstileInput,
25
- bodyLen: bodyText.length,
26
- onChatGPT,
27
- });
28
- })()`
29
- ]).catch(() => null);
30
- if (!probe)
31
- return false;
32
- let info;
33
- try {
34
- info = JSON.parse(probe);
35
- } catch {
36
- return false;
37
- }
38
- if (!info.onChatGPT)
39
- return false;
40
- if (info.title && /περιμένετε|please wait|just a moment|verifying|checking/i.test(info.title)) {
41
- return false;
42
- }
43
- if (info.hasTurnstileInput)
44
- return false;
45
- return info.hasProseMirror || info.bodyLen > 50;
46
- }
47
- },
48
- bing: {
49
- name: "bing",
50
- isCleared: async (tab) => {
51
- const probe = await cdp([
52
- "eval",
53
- tab,
54
- `(() => {
55
- const url = location.href;
56
- const title = document.title;
57
- const onCopilot = /copilot\\.microsoft\\.com/.test(location.hostname);
58
- const onChallenge =
59
- /challenge|turnstile|cdn-cgi\\/challenge/i.test(url) ||
60
- /verify|human|robot/i.test(title);
61
- const hasTextarea =
62
- !!document.querySelector("textarea") ||
63
- !!document.querySelector("div[contenteditable=\\"true\\"]");
64
- const hasTurnstileInput =
65
- !!document.querySelector("iframe[id^=\\"cf-chl-widget-\\"]") ||
66
- !!document.querySelector("input[name=\\"cf-turnstile-response\\"]");
67
- const bodyText = (document.body && document.body.innerText) || "";
68
- return JSON.stringify({
69
- url,
70
- title,
71
- onCopilot,
72
- onChallenge,
73
- hasTextarea,
74
- hasTurnstileInput,
75
- bodyLen: bodyText.length,
76
- });
77
- })()`
78
- ]).catch(() => null);
79
- if (!probe)
80
- return false;
81
- let info;
82
- try {
83
- info = JSON.parse(probe);
84
- } catch {
85
- return false;
86
- }
87
- if (!info.onCopilot)
88
- return false;
89
- if (info.onChallenge)
90
- return false;
91
- if (info.hasTurnstileInput)
92
- return false;
93
- return info.hasTextarea || info.bodyLen > 50;
94
- }
95
- }
96
- };
97
- async function pollForCfClearanceCookie(tab) {
98
- const probe = await cdp([
99
- "eval",
100
- tab,
101
- `(() => {
102
- const cookies = document.cookie || "";
103
- return JSON.stringify({
104
- hasCfClearance: /(?:^|;\\s*)cf_clearance=/.test(cookies),
105
- hasCfBm: /(?:^|;\\s*)__cf_bm=/.test(cookies),
106
- cookiesLength: cookies.length,
107
- });
108
- })()`
109
- ]).catch(() => null);
110
- if (!probe)
111
- return false;
112
- try {
113
- const info = JSON.parse(probe);
114
- return info.hasCfClearance || info.hasCfBm;
115
- } catch {
116
- return false;
117
- }
118
- }
119
- export async function waitForChallengeCleared({
120
- tab,
121
- engine,
122
- timeoutMs = DEFAULT_TIMEOUT_MS,
123
- intervalMs = POLL_INTERVAL_MS,
124
- signal: externalSignal,
125
- log = () => {}
126
- }) {
127
- const def = ENGINE_SIGNALS[engine];
128
- const start = Date.now();
129
- let lastState = null;
130
- while (Date.now() - start < timeoutMs) {
131
- if (externalSignal?.aborted) {
132
- return { cleared: false, reason: "aborted" };
133
- }
134
- const elapsed = Math.floor((Date.now() - start) / 1000);
135
- let cleared = false;
136
- if (def) {
137
- cleared = await def.isCleared(tab).catch(() => false);
138
- } else {
139
- cleared = await pollForCfClearanceCookie(tab).catch(() => false);
140
- }
141
- if (cleared) {
142
- log(`[greedysearch] ✅ ${engine} challenge cleared after ${elapsed}s — auto-resuming extraction.`);
143
- return { cleared: true, signal: def ? "dom-marker" : "cookie" };
144
- }
145
- if (elapsed > 0 && elapsed % 30 === 0 && lastState !== elapsed) {
146
- lastState = elapsed;
147
- log(`[greedysearch] ⏳ Waiting for ${engine} challenge to clear (${elapsed}s/${Math.floor(timeoutMs / 1000)}s)...`);
148
- }
149
- await new Promise((r) => setTimeout(r, intervalMs));
150
- }
151
- return {
152
- cleared: false,
153
- reason: `Challenge not cleared within ${Math.floor(timeoutMs / 1000)}s`
154
- };
155
- }
156
- export const CHALLENGE_ENGINES = Object.keys(ENGINE_SIGNALS);