@melaya/runner 1.0.31 → 1.0.33
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/dist/pythonEnv.js +37 -2
- package/package.json +1 -1
package/dist/pythonEnv.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { spawn } from "child_process";
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
14
|
+
import { createHash } from "crypto";
|
|
14
15
|
import { join } from "path";
|
|
15
16
|
import { homedir, platform } from "os";
|
|
16
17
|
import chalk from "chalk";
|
|
@@ -70,12 +71,35 @@ const PIP_DEPS = [
|
|
|
70
71
|
"python-docx",
|
|
71
72
|
"python-pptx",
|
|
72
73
|
"ddgs", // duckduckgo search rebrand — shared.tools.core imports DDGS
|
|
74
|
+
// Scrapling — full-text article fetcher used by shared.tools.core.
|
|
75
|
+
// Without it, web_search emits the "Snippets only (Scrapling
|
|
76
|
+
// unavailable)" fallback, agents get 1-line DDG titles instead of
|
|
77
|
+
// article bodies, and small models hallucinate to fill the gap.
|
|
78
|
+
// [fetchers] extra brings curl_cffi for the TLS-impersonating
|
|
79
|
+
// AsyncFetcher (no browser needed) AND playwright for the optional
|
|
80
|
+
// StealthyFetcher rescue path. The stealth path also needs
|
|
81
|
+
// `scrapling install` to download Chromium — best-effort run below
|
|
82
|
+
// (failure non-fatal: AsyncFetcher fast-path still works without it).
|
|
83
|
+
"scrapling[fetchers]",
|
|
73
84
|
];
|
|
74
85
|
export function venvPython() {
|
|
75
86
|
return platform() === "win32"
|
|
76
87
|
? join(VENV_DIR, "Scripts", "python.exe")
|
|
77
88
|
: join(VENV_DIR, "bin", "python");
|
|
78
89
|
}
|
|
90
|
+
// The marker is keyed on sharedVersion + a hash of PIP_DEPS so changes
|
|
91
|
+
// to either invalidate the venv. Without the PIP_DEPS half, a runner
|
|
92
|
+
// update that adds a dep (e.g. scrapling[fetchers] in 1.0.32) would
|
|
93
|
+
// silently skip the reinstall on any box whose sharedVersion hadn't
|
|
94
|
+
// also changed — operators would update the runner but never see the
|
|
95
|
+
// new deps. Hashing the full deps list catches additions, removals,
|
|
96
|
+
// AND version-pin changes within deps.
|
|
97
|
+
function _pipDepsHash() {
|
|
98
|
+
return createHash("sha256").update(JSON.stringify(PIP_DEPS)).digest("hex").slice(0, 12);
|
|
99
|
+
}
|
|
100
|
+
function venvMarkerValue(expectedVersion) {
|
|
101
|
+
return `${expectedVersion}::${_pipDepsHash()}`;
|
|
102
|
+
}
|
|
79
103
|
function venvIsValid(expectedVersion) {
|
|
80
104
|
if (!existsSync(venvPython()))
|
|
81
105
|
return false;
|
|
@@ -83,7 +107,7 @@ function venvIsValid(expectedVersion) {
|
|
|
83
107
|
return false;
|
|
84
108
|
try {
|
|
85
109
|
const cached = readFileSync(VENV_MARK, "utf-8").trim();
|
|
86
|
-
return cached === expectedVersion;
|
|
110
|
+
return cached === venvMarkerValue(expectedVersion);
|
|
87
111
|
}
|
|
88
112
|
catch {
|
|
89
113
|
return false;
|
|
@@ -149,7 +173,18 @@ export async function ensurePythonEnv(systemPython, expectedVersion, onProgress
|
|
|
149
173
|
reason: `pip install failed (exit ${acode}). Check the lines above for the actual pip error.`,
|
|
150
174
|
};
|
|
151
175
|
}
|
|
152
|
-
|
|
176
|
+
// Scrapling browser binaries — best-effort. The fast-path AsyncFetcher
|
|
177
|
+
// (curl_cffi TLS impersonation) works without this; only StealthyFetcher
|
|
178
|
+
// (Cloudflare-bypass rescue path) needs Chromium. If `scrapling install`
|
|
179
|
+
// fails (offline, network blip, browser-download mirror down) we don't
|
|
180
|
+
// fail the venv — the search just stays on the fast path. Logs are
|
|
181
|
+
// surfaced so the operator sees what happened.
|
|
182
|
+
onProgress("installing scrapling browsers (best-effort, for stealth rescue path)");
|
|
183
|
+
const scrCode = await runProc(venvPython(), ["-m", "scrapling", "install"], onProgress);
|
|
184
|
+
if (scrCode !== 0) {
|
|
185
|
+
onProgress(`(scrapling install exited ${scrCode} — fast-path fetcher still works; stealth-rescue disabled)`);
|
|
186
|
+
}
|
|
187
|
+
writeFileSync(VENV_MARK, venvMarkerValue(expectedVersion), "utf-8");
|
|
153
188
|
// sanity: confirm shortuuid + agentscope (via PYTHONPATH) resolve now.
|
|
154
189
|
// Probe must mirror the spawn env so PYTHONPATH=CACHE_DIR points at
|
|
155
190
|
// the cached agentscope source — without this the probe ImportError's
|