@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.
- package/dm.exe +0 -0
- package/extensions/.dm-extensions.json +43 -183
- package/extensions/dm-context/src/context.js +1 -2
- package/extensions/dm-context/src/index.js +1 -2
- package/extensions/{greedysearch-dm/bin/cdp.mjs → dm-cua/bin/browser-cdp.mjs} +3 -3
- package/extensions/dm-cua/bin/browser-cua.mjs +1 -1
- package/extensions/{greedysearch-dm/bin/launch.mjs → dm-cua/bin/browser-launch.mjs} +12 -11
- package/extensions/dm-cua/index.js +1 -1
- package/extensions/dm-cua/src/browser-cua-lib.mjs +17 -12
- package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/constants.mjs +11 -11
- package/extensions/{greedysearch-dm/src/utils → dm-cua/src/browser-helpers}/node-runtime.mjs +1 -1
- package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/port-pid.mjs +1 -1
- package/extensions/dm-ponytail/extensions/ponytail.mjs +186 -0
- package/extensions/dm-ponytail/hooks/claude-codex-hooks.json +41 -0
- package/extensions/dm-ponytail/hooks/copilot-hooks.json +21 -0
- package/extensions/dm-ponytail/hooks/ponytail-activate.js +59 -0
- package/extensions/dm-ponytail/hooks/ponytail-config.js +116 -0
- package/extensions/dm-ponytail/hooks/ponytail-instructions.js +81 -0
- package/extensions/dm-ponytail/hooks/ponytail-mode-tracker.js +96 -0
- package/extensions/dm-ponytail/hooks/ponytail-runtime.js +79 -0
- package/extensions/dm-ponytail/hooks/ponytail-statusline.ps1 +24 -0
- package/extensions/dm-ponytail/hooks/ponytail-statusline.sh +18 -0
- package/extensions/dm-ponytail/hooks/ponytail-subagent.js +50 -0
- package/extensions/dm-ponytail/hooks/qoder-hooks.json +26 -0
- package/extensions/dm-ponytail/package.json +19 -0
- package/extensions/dm-ponytail/pi-extension/index.js +186 -0
- package/extensions/dm-ponytail/pi-extension/package.json +8 -0
- package/extensions/dm-ponytail/skills/ponytail/SKILL.md +120 -0
- package/extensions/dm-ponytail/skills/ponytail-audit/SKILL.md +41 -0
- package/extensions/dm-ponytail/skills/ponytail-debt/SKILL.md +44 -0
- package/extensions/dm-ponytail/skills/ponytail-gain/SKILL.md +50 -0
- package/extensions/dm-ponytail/skills/ponytail-help/SKILL.md +71 -0
- package/extensions/dm-ponytail/skills/ponytail-review/SKILL.md +57 -0
- package/package.json +2 -6
- package/extensions/dm-caveman/extensions/caveman.js +0 -300
- package/extensions/dm-caveman/package.json +0 -20
- package/extensions/dm-goal/package.json +0 -23
- package/extensions/dm-goal/src/goal.js +0 -914
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +0 -40
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +0 -5
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +0 -5
- package/extensions/greedysearch-dm/bin/gschrome.mjs +0 -30
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +0 -7
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +0 -13
- package/extensions/greedysearch-dm/bin/mcp.mjs +0 -400
- package/extensions/greedysearch-dm/bin/search.mjs +0 -635
- package/extensions/greedysearch-dm/bin/visible.mjs +0 -22
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +0 -344
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +0 -354
- package/extensions/greedysearch-dm/extractors/common.mjs +0 -794
- package/extensions/greedysearch-dm/extractors/consensus.mjs +0 -527
- package/extensions/greedysearch-dm/extractors/consent.mjs +0 -449
- package/extensions/greedysearch-dm/extractors/gemini.mjs +0 -291
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +0 -86
- package/extensions/greedysearch-dm/extractors/logically.mjs +0 -589
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +0 -370
- package/extensions/greedysearch-dm/extractors/selectors.mjs +0 -32
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +0 -199
- package/extensions/greedysearch-dm/index.js +0 -123
- package/extensions/greedysearch-dm/package.json +0 -27
- package/extensions/greedysearch-dm/skills/greedy-search/skill.md +0 -18
- package/extensions/greedysearch-dm/src/fetcher.mjs +0 -577
- package/extensions/greedysearch-dm/src/formatters/results.js +0 -95
- package/extensions/greedysearch-dm/src/formatters/sources.js +0 -57
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +0 -49
- package/extensions/greedysearch-dm/src/github.mjs +0 -228
- package/extensions/greedysearch-dm/src/reddit.mjs +0 -154
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +0 -340
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +0 -156
- package/extensions/greedysearch-dm/src/search/chrome.mjs +0 -510
- package/extensions/greedysearch-dm/src/search/defaults.mjs +0 -10
- package/extensions/greedysearch-dm/src/search/engines.mjs +0 -79
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +0 -470
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +0 -31
- package/extensions/greedysearch-dm/src/search/output.mjs +0 -51
- package/extensions/greedysearch-dm/src/search/paths.mjs +0 -48
- package/extensions/greedysearch-dm/src/search/pdf.mjs +0 -64
- package/extensions/greedysearch-dm/src/search/progress.mjs +0 -109
- package/extensions/greedysearch-dm/src/search/query.mjs +0 -21
- package/extensions/greedysearch-dm/src/search/recovery.mjs +0 -49
- package/extensions/greedysearch-dm/src/search/research.mjs +0 -2255
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +0 -61
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +0 -418
- package/extensions/greedysearch-dm/src/search/sources.mjs +0 -412
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +0 -127
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +0 -202
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +0 -209
- package/extensions/greedysearch-dm/src/tools/shared.js +0 -226
- package/extensions/greedysearch-dm/src/types.js +0 -0
- package/extensions/greedysearch-dm/src/utils/content.mjs +0 -38
- package/extensions/greedysearch-dm/src/utils/helpers.js +0 -22
- /package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/minimize.mjs +0 -0
- /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);
|