@gorlitzer-labs/seldon 0.1.4 → 0.1.6

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/bin/seldon.js CHANGED
@@ -55,6 +55,30 @@ function run(cmd, args, opts = {}) {
55
55
  // Is a command on PATH? (used to pick the fastest package manager)
56
56
  const has = (bin) => { try { execSync(`command -v ${bin}`, { stdio: "ignore" }); return true; } catch { return false; } };
57
57
 
58
+ // A usable uv, for Python modules. Prefer one on PATH; else a prior isolated
59
+ // copy; else bootstrap uv into ~/.seldon/bin with NO shell/profile changes.
60
+ // uv can fetch a standalone CPython (e.g. 3.12) itself, so the user's own
61
+ // Python is never touched — which is the whole point for demerzel. null = give up.
62
+ function ensureUv() {
63
+ if (has("uv")) return "uv";
64
+ const dir = path.join(process.env.HOME, ".seldon", "bin");
65
+ const local = path.join(dir, "uv");
66
+ if (fs.existsSync(local)) return local;
67
+ console.log(C.dim(" installing uv (isolated → ~/.seldon/bin, no shell changes)"));
68
+ fs.mkdirSync(dir, { recursive: true });
69
+ const ok = run("bash", ["-c",
70
+ `curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR='${dir}' UV_NO_MODIFY_PATH=1 sh`]);
71
+ return ok && fs.existsSync(local) ? local : null;
72
+ }
73
+
74
+ // Fallback interpreter when uv is unavailable: an exact minor already on PATH
75
+ // (python3.12 → 3.11 → 3.10). Used only to seed an isolated venv, never modified.
76
+ function pickPython(ver) {
77
+ const [maj, min] = ver.split(".").map(Number);
78
+ for (let m = min; m >= 10; m--) { const b = `python${maj}.${m}`; if (has(b)) return b; }
79
+ return null;
80
+ }
81
+
58
82
  // pnpm can only `add -g` when a global bin dir is configured (else ERR_PNPM_NO_GLOBAL_BIN_DIR).
59
83
  const pnpmGlobalReady = () => {
60
84
  if (process.env.PNPM_HOME) return true;
@@ -64,13 +88,13 @@ const pnpmGlobalReady = () => {
64
88
  } catch { return false; }
65
89
  };
66
90
 
67
- // Pick the node package manager: --pm=<x> override, else the fastest that can
68
- // actually global-install; npm is the universal fallback.
91
+ // Pick the node package manager: --pm=<x> override (pnpm|bun|npm), else pnpm
92
+ // when it can global-install, else npm (the universal fallback). bun is not
93
+ // auto-preferred — opt in with --pm=bun.
69
94
  function nodePM() {
70
95
  const ov = (process.argv.find((a) => a.startsWith("--pm=")) || "").split("=")[1];
71
96
  if (ov) return ov;
72
97
  if (has("pnpm") && pnpmGlobalReady()) return "pnpm";
73
- if (has("bun")) return "bun";
74
98
  return "npm";
75
99
  }
76
100
 
@@ -127,12 +151,23 @@ function installPython(m, dev) {
127
151
  // venv+pip is the isolated fallback. No `--system`, no active-env writes.
128
152
  const venv = path.join(dest, ".venv");
129
153
  const req = path.join(dest, "requirements.txt");
154
+ fs.rmSync(venv, { recursive: true, force: true }); // never reuse a venv built on the wrong Python
130
155
  let ok;
131
- if (has("uv")) {
132
- if (!run("uv", ["venv", venv])) return false;
133
- ok = run("uv", ["pip", "install", "--python", path.join(venv, "bin", "python"), "-r", req]);
156
+ const uv = ensureUv();
157
+ if (uv) {
158
+ const venvArgs = ["venv", venv];
159
+ if (m.pyVersion) venvArgs.push("--python", m.pyVersion); // uv fetches a standalone CPython
160
+ if (!run(uv, venvArgs)) return false;
161
+ ok = run(uv, ["pip", "install", "--python", path.join(venv, "bin", "python"), "-r", req]);
134
162
  } else {
135
- run("python3", ["-m", "venv", venv]);
163
+ // No uv (and couldn't bootstrap it). Fall back to a matching system python.
164
+ const py = m.pyVersion ? pickPython(m.pyVersion) : "python3";
165
+ if (!py) {
166
+ console.log(C.red(` ${m.id} needs Python ${m.pyVersion} but uv is unavailable and no python${m.pyVersion} is on PATH.`));
167
+ console.log(C.dim(` install uv (fetches Python ${m.pyVersion} in isolation): https://astral.sh/uv`));
168
+ return false;
169
+ }
170
+ run(py, ["-m", "venv", venv]);
136
171
  ok = run(path.join(venv, "bin", "pip"), ["install", "-r", req]);
137
172
  }
138
173
  if (ok) console.log(C.dim(` run it: ${path.join(dest, m.bin)} (isolated venv at ${venv})`));
@@ -236,7 +271,7 @@ ${C.bold("seldon")} — install the Seldon stack, pick what you use.
236
271
 
237
272
  ${C.dim("node tools install via pnpm/bun if present (faster), else npm.")}
238
273
  ${C.dim("python (demerzel) installs into its own isolated venv — never your system Python;")}
239
- ${C.dim("uses uv if present, else python3 -m venv + pip.")}
274
+ ${C.dim("uses uv (auto-installed to ~/.seldon/bin if missing) to fetch a standalone CPython 3.12.")}
240
275
 
241
276
  modules: ${MODULES.map((m) => m.id).join(", ")}
242
277
  `);
package/modules.mjs CHANGED
@@ -76,6 +76,9 @@ export const MODULES = [
76
76
  bin: "demerzel",
77
77
  needs: ["python3"],
78
78
  requires: [],
79
+ // kokoro==0.9.4 caps Python at <3.13; the venv is pinned to 3.12 and uv
80
+ // fetches a standalone CPython 3.12 in isolation (never the system Python).
81
+ pyVersion: "3.12",
79
82
  platforms: { platform: "darwin", arch: "arm64" }, // macOS + Apple silicon only
80
83
  },
81
84
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gorlitzer-labs/seldon",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Install the Seldon stack — pick your tools from a checklist; each installs via its native method.",
5
5
  "type": "module",
6
6
  "bin": {