@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.
Files changed (2) hide show
  1. package/dist/pythonEnv.js +37 -2
  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
- writeFileSync(VENV_MARK, expectedVersion, "utf-8");
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melaya/runner",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
4
4
  "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,