@metaphi-ai/hum 0.2.10 → 0.2.12
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/hum.js +15 -4
- package/dist/cli.mjs +223 -83
- package/dist/install.mjs +183 -26
- package/package.json +1 -1
- package/scripts/postinstall.js +1 -1
package/bin/hum.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// `hum` from npm: the
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// `hum` from npm: the launcher. It starts the newest release installed under ~/.hum/versions
|
|
3
|
+
// (a session installs a newer one there in the background while it runs) and, when none is newer
|
|
4
|
+
// than this package, this package's own front-end, which starts Hum's core (Python) and talks to
|
|
5
|
+
// it over localhost. Everything the person sees is there; everything the session records is in
|
|
6
|
+
// the core. This file is what npm put on PATH and it changes only when npm reinstalls it: keep
|
|
7
|
+
// it small, and keep it running whatever the versions directory holds.
|
|
8
|
+
import fs from 'node:fs';
|
|
5
9
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
10
|
import path from 'node:path';
|
|
7
11
|
|
|
@@ -15,4 +19,11 @@ if (Number(process.versions.node.split('.')[0]) < NODE_FLOOR) {
|
|
|
15
19
|
|
|
16
20
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
17
21
|
// a URL, not a path: on Windows `C:\…` is not something the ESM loader will import
|
|
18
|
-
|
|
22
|
+
const asUrl = (p) => pathToFileURL(p).href;
|
|
23
|
+
let entry = path.join(here, '..', 'dist', 'cli.mjs');
|
|
24
|
+
try {
|
|
25
|
+
const own = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json'), 'utf8')).version;
|
|
26
|
+
const { chosenEntry } = await import(asUrl(path.join(here, '..', 'dist', 'install.mjs')));
|
|
27
|
+
entry = chosenEntry(own) || entry;
|
|
28
|
+
} catch { /* this package's own */ }
|
|
29
|
+
await import(asUrl(entry));
|
package/dist/cli.mjs
CHANGED
|
@@ -88432,20 +88432,29 @@ import { spawnSync } from "node:child_process";
|
|
|
88432
88432
|
import fs3 from "node:fs";
|
|
88433
88433
|
import os3 from "node:os";
|
|
88434
88434
|
import path from "node:path";
|
|
88435
|
-
function
|
|
88436
|
-
|
|
88435
|
+
function readyVersions(env3 = process.env) {
|
|
88436
|
+
let names = [];
|
|
88437
|
+
try {
|
|
88438
|
+
names = fs3.readdirSync(versionsDir(env3));
|
|
88439
|
+
} catch {
|
|
88440
|
+
return [];
|
|
88441
|
+
}
|
|
88442
|
+
return names.filter((v) => isVersion(v) && fs3.existsSync(readyFile(env3, v))).sort((a, b) => newer(a, b) ? -1 : newer(b, a) ? 1 : 0);
|
|
88443
|
+
}
|
|
88444
|
+
function importedVersion(env3 = process.env, version = MINE, runImpl = run) {
|
|
88445
|
+
const r = runImpl(corePython(env3, version), ASK_VERSION);
|
|
88437
88446
|
return r && r.status === 0 ? String(r.stdout).trim() : null;
|
|
88438
88447
|
}
|
|
88439
|
-
function installedVersion(env3 = process.env, runImpl = run) {
|
|
88448
|
+
function installedVersion(env3 = process.env, version = MINE, runImpl = run) {
|
|
88440
88449
|
try {
|
|
88441
|
-
return fs3.readFileSync(stampPath(env3), "utf8").trim() || null;
|
|
88450
|
+
return fs3.readFileSync(stampPath(env3, version), "utf8").trim() || null;
|
|
88442
88451
|
} catch {
|
|
88443
88452
|
}
|
|
88444
|
-
if (!fs3.existsSync(corePython(env3))) return null;
|
|
88445
|
-
const v = importedVersion(env3, runImpl);
|
|
88453
|
+
if (!fs3.existsSync(corePython(env3, version))) return null;
|
|
88454
|
+
const v = importedVersion(env3, version, runImpl);
|
|
88446
88455
|
if (v) {
|
|
88447
88456
|
try {
|
|
88448
|
-
fs3.writeFileSync(stampPath(env3), `${v}
|
|
88457
|
+
fs3.writeFileSync(stampPath(env3, version), `${v}
|
|
88449
88458
|
`);
|
|
88450
88459
|
} catch {
|
|
88451
88460
|
}
|
|
@@ -88458,22 +88467,21 @@ function trustedPython(env3 = process.env, runImpl = run) {
|
|
|
88458
88467
|
const p = r && r.status === 0 ? String(r.stdout).trim().split(/\r?\n/).pop() : "";
|
|
88459
88468
|
return /^[a-z]:\\.+\\python(w)?\.exe$/i.test(p) ? p : null;
|
|
88460
88469
|
}
|
|
88461
|
-
function sslBlocked(env3 = process.env, runImpl = run) {
|
|
88462
|
-
const r = runImpl(corePython(env3), ASK_SSL);
|
|
88470
|
+
function sslBlocked(env3 = process.env, version = MINE, runImpl = run) {
|
|
88471
|
+
const r = runImpl(corePython(env3, version), ASK_SSL);
|
|
88463
88472
|
if (r && r.status === 0) return null;
|
|
88464
88473
|
const text = String(r && (r.stderr || r.stdout) || "ssl did not import").trim().split(/\r?\n/).filter(Boolean).pop() || "ssl did not import";
|
|
88465
88474
|
return text;
|
|
88466
88475
|
}
|
|
88467
|
-
function needsInstall(version, { env: env3 = process.env, installed = () => installedVersion(env3), now = Date.now(), state = readInstallState(env3) } = {}) {
|
|
88476
|
+
function needsInstall(version, { env: env3 = process.env, installed = () => installedVersion(env3, version), now = Date.now(), state = readInstallState(env3) } = {}) {
|
|
88468
88477
|
if (!version || env3.HUM_CORE || env3.HUM_CORE_PORT) return false;
|
|
88469
88478
|
if (installed() === version) return false;
|
|
88470
88479
|
if (state && !state.ok && state.version === version && now - (state.at || 0) < 10 * 60 * 1e3) return false;
|
|
88471
88480
|
return true;
|
|
88472
88481
|
}
|
|
88473
88482
|
function installCore(version, { env: env3 = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now() } = {}) {
|
|
88474
|
-
const
|
|
88475
|
-
const
|
|
88476
|
-
const python = corePython(env3);
|
|
88483
|
+
const dir = coreDir(env3, version);
|
|
88484
|
+
const python = corePython(env3, version);
|
|
88477
88485
|
const localBin = path.join(os3.homedir(), ".local", "bin");
|
|
88478
88486
|
const uvNames = ["uv", path.join(localBin, win ? "uv.exe" : "uv")];
|
|
88479
88487
|
const uv = () => uvNames.find((u) => {
|
|
@@ -88494,30 +88502,30 @@ function installCore(version, { env: env3 = process.env, say = (m) => console.lo
|
|
|
88494
88502
|
if (!u) return outcome(false, `could not install uv; install it from https://astral.sh/uv and run: ${npmFix(version)}`);
|
|
88495
88503
|
}
|
|
88496
88504
|
say(`installing ${env3.HUM_CORE_SPEC ? spec : `hum ${version}`} into ${dir} \u2026`);
|
|
88497
|
-
fs3.mkdirSync(
|
|
88505
|
+
fs3.mkdirSync(path.dirname(dir), { recursive: true });
|
|
88498
88506
|
try {
|
|
88499
|
-
fs3.unlinkSync(stampPath(env3));
|
|
88507
|
+
fs3.unlinkSync(stampPath(env3, version));
|
|
88500
88508
|
} catch {
|
|
88501
88509
|
}
|
|
88502
88510
|
const trusted = trustedPython(env3, runImpl);
|
|
88503
88511
|
const makeVenv = (clear) => (runImpl(u, ["venv", "--quiet", "--python", trusted || "3.12", ...clear ? ["--clear"] : [], dir], { stdio: "inherit" }) || {}).status === 0;
|
|
88504
|
-
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--python", python, spec], { stdio: "inherit" }) || {}).status === 0;
|
|
88512
|
+
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--refresh-package", "hum-cli", "--python", python, spec], { stdio: "inherit" }) || {}).status === 0;
|
|
88505
88513
|
if (!fs3.existsSync(python) && !makeVenv(fs3.existsSync(dir))) return outcome(false, "uv venv failed");
|
|
88506
88514
|
if (!pipIn()) return outcome(false, `uv pip install ${spec} failed`);
|
|
88507
|
-
let got = importedVersion(env3, runImpl);
|
|
88515
|
+
let got = importedVersion(env3, version, runImpl);
|
|
88508
88516
|
if (!got) return outcome(false, "hum did not import after the install");
|
|
88509
88517
|
if (got !== version && !env3.HUM_CORE_SPEC) return outcome(false, `installed ${got}, wanted ${version}`, got);
|
|
88510
|
-
let blocked = sslBlocked(env3, runImpl);
|
|
88518
|
+
let blocked = sslBlocked(env3, version, runImpl);
|
|
88511
88519
|
if (blocked && trusted) {
|
|
88512
88520
|
say(`the policy here refuses the environment's OpenSSL (${blocked}); rebuilding it on ${trusted} \u2026`);
|
|
88513
88521
|
if (makeVenv(true) && pipIn()) {
|
|
88514
|
-
got = importedVersion(env3, runImpl) || got;
|
|
88515
|
-
blocked = sslBlocked(env3, runImpl);
|
|
88522
|
+
got = importedVersion(env3, version, runImpl) || got;
|
|
88523
|
+
blocked = sslBlocked(env3, version, runImpl);
|
|
88516
88524
|
}
|
|
88517
88525
|
}
|
|
88518
88526
|
if (blocked) return outcome(false, sslAdvice(env3, version));
|
|
88519
88527
|
fs3.mkdirSync(dir, { recursive: true });
|
|
88520
|
-
fs3.writeFileSync(stampPath(env3), `${got}
|
|
88528
|
+
fs3.writeFileSync(stampPath(env3, version), `${got}
|
|
88521
88529
|
`);
|
|
88522
88530
|
const list2 = runImpl(u, ["tool", "list"]);
|
|
88523
88531
|
if (list2 && list2.status === 0 && /^hum-cli\b/m.test(list2.stdout)) {
|
|
@@ -88530,21 +88538,127 @@ function installCore(version, { env: env3 = process.env, say = (m) => console.lo
|
|
|
88530
88538
|
return outcome(false, e && e.message ? e.message : String(e));
|
|
88531
88539
|
}
|
|
88532
88540
|
}
|
|
88533
|
-
|
|
88541
|
+
function installPackage(version, { env: env3 = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run } = {}) {
|
|
88542
|
+
const dest = pkgDir(env3, version);
|
|
88543
|
+
const stage = path.join(versionDir(env3, version), "npm");
|
|
88544
|
+
say(`fetching hum ${version} \u2026`);
|
|
88545
|
+
fs3.rmSync(stage, { recursive: true, force: true });
|
|
88546
|
+
fs3.mkdirSync(stage, { recursive: true });
|
|
88547
|
+
const r = runImpl(win ? "npm.cmd" : "npm", [
|
|
88548
|
+
"install",
|
|
88549
|
+
"--prefix",
|
|
88550
|
+
stage,
|
|
88551
|
+
"--ignore-scripts",
|
|
88552
|
+
"--no-audit",
|
|
88553
|
+
"--no-fund",
|
|
88554
|
+
"--no-package-lock",
|
|
88555
|
+
"--loglevel=error",
|
|
88556
|
+
`@metaphi-ai/hum@${version}`
|
|
88557
|
+
], { shell: win, env: { ...env3, npm_config_update_notifier: "false" } });
|
|
88558
|
+
const got = path.join(stage, "node_modules", "@metaphi-ai", "hum");
|
|
88559
|
+
if (!r || r.status !== 0 || !fs3.existsSync(path.join(got, "dist", "cli.mjs"))) {
|
|
88560
|
+
const why = String(r && (r.stderr || r.stdout) || "").trim().split(/\r?\n/).filter(Boolean).pop() || `npm exited ${r ? r.status : "without running"}`;
|
|
88561
|
+
fs3.rmSync(stage, { recursive: true, force: true });
|
|
88562
|
+
return { ok: false, error: `npm could not fetch @metaphi-ai/hum@${version}: ${why}` };
|
|
88563
|
+
}
|
|
88564
|
+
fs3.rmSync(dest, { recursive: true, force: true });
|
|
88565
|
+
fs3.renameSync(got, dest);
|
|
88566
|
+
fs3.rmSync(stage, { recursive: true, force: true });
|
|
88567
|
+
return { ok: true, error: null };
|
|
88568
|
+
}
|
|
88569
|
+
function prune(env3 = process.env, { keep = MINE, say = () => {
|
|
88570
|
+
}, now = Date.now() } = {}) {
|
|
88571
|
+
let names = [];
|
|
88572
|
+
try {
|
|
88573
|
+
names = fs3.readdirSync(versionsDir(env3)).filter(isVersion);
|
|
88574
|
+
} catch {
|
|
88575
|
+
return [];
|
|
88576
|
+
}
|
|
88577
|
+
const ready = readyVersions(env3);
|
|
88578
|
+
const stay = /* @__PURE__ */ new Set([keep, ...ready.slice(0, 3)]);
|
|
88579
|
+
const gone = [];
|
|
88580
|
+
for (const v of names) {
|
|
88581
|
+
if (stay.has(v)) continue;
|
|
88582
|
+
if (!ready.includes(v)) {
|
|
88583
|
+
let at = 0;
|
|
88584
|
+
try {
|
|
88585
|
+
at = fs3.statSync(versionDir(env3, v)).mtimeMs;
|
|
88586
|
+
} catch {
|
|
88587
|
+
}
|
|
88588
|
+
if (now - at < 30 * 60 * 1e3) continue;
|
|
88589
|
+
}
|
|
88590
|
+
try {
|
|
88591
|
+
fs3.rmSync(versionDir(env3, v), { recursive: true, force: true });
|
|
88592
|
+
gone.push(v);
|
|
88593
|
+
say(`removed hum ${v}`);
|
|
88594
|
+
} catch {
|
|
88595
|
+
}
|
|
88596
|
+
}
|
|
88597
|
+
return gone.sort((a, b) => newer(a, b) ? -1 : newer(b, a) ? 1 : 0);
|
|
88598
|
+
}
|
|
88599
|
+
function installVersion(version, { env: env3 = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now(), retries = 0, every = 90 * 1e3, wait = pause } = {}) {
|
|
88600
|
+
if (!isVersion(version)) return { ok: false, error: `not a version: ${version}` };
|
|
88601
|
+
try {
|
|
88602
|
+
fs3.mkdirSync(versionDir(env3, version), { recursive: true });
|
|
88603
|
+
try {
|
|
88604
|
+
fs3.unlinkSync(readyFile(env3, version));
|
|
88605
|
+
} catch {
|
|
88606
|
+
}
|
|
88607
|
+
const attempt2 = (what, step) => {
|
|
88608
|
+
let r = step();
|
|
88609
|
+
for (let i = 0; !r.ok && i < retries; i += 1) {
|
|
88610
|
+
say(`${what} is not there yet (${r.error}); trying again in ${Math.round(every / 1e3)} s`);
|
|
88611
|
+
wait(every);
|
|
88612
|
+
r = step();
|
|
88613
|
+
}
|
|
88614
|
+
return r;
|
|
88615
|
+
};
|
|
88616
|
+
if (!fs3.existsSync(entryFile(env3, version))) {
|
|
88617
|
+
const p = attempt2("the package", () => installPackage(version, { env: env3, say, runImpl }));
|
|
88618
|
+
if (!p.ok) return p;
|
|
88619
|
+
}
|
|
88620
|
+
if (installedVersion(env3, version, runImpl) !== version) {
|
|
88621
|
+
const c = attempt2("the part of hum that does the work", () => installCore(version, { env: env3, say, runImpl, now }));
|
|
88622
|
+
if (!c.ok) return { ok: false, error: c.error };
|
|
88623
|
+
}
|
|
88624
|
+
fs3.writeFileSync(readyFile(env3, version), `${version}
|
|
88625
|
+
`);
|
|
88626
|
+
say(`hum ${version} is ready; the next hum you start is ${version}`);
|
|
88627
|
+
prune(env3, { say });
|
|
88628
|
+
return { ok: true, error: null };
|
|
88629
|
+
} catch (e) {
|
|
88630
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
88631
|
+
}
|
|
88632
|
+
}
|
|
88633
|
+
var win, MINE, npmFix, NPM_FIX, humHome, versionsDir, versionDir, pkgDir, coreDir, corePython, readyFile, entryFile, stampPath, statePath, isVersion, newer, run, ASK_VERSION, ASK_SSL, sslAdvice, readInstallState, writeInstallState, pause;
|
|
88534
88634
|
var init_install = __esm({
|
|
88535
88635
|
"src/install.js"() {
|
|
88536
88636
|
win = process.platform === "win32";
|
|
88637
|
+
MINE = true ? "0.2.12" : "";
|
|
88537
88638
|
npmFix = (version = "") => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
|
|
88538
88639
|
NPM_FIX = npmFix("latest");
|
|
88539
88640
|
humHome = (env3 = process.env) => env3.HUM_HOME || path.join(os3.homedir(), ".hum");
|
|
88540
|
-
|
|
88541
|
-
|
|
88542
|
-
|
|
88641
|
+
versionsDir = (env3 = process.env) => path.join(humHome(env3), "versions");
|
|
88642
|
+
versionDir = (env3 = process.env, version = MINE) => path.join(versionsDir(env3), version);
|
|
88643
|
+
pkgDir = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "pkg");
|
|
88644
|
+
coreDir = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "core");
|
|
88645
|
+
corePython = (env3 = process.env, version = MINE) => win ? path.join(coreDir(env3, version), "Scripts", "python.exe") : path.join(coreDir(env3, version), "bin", "python");
|
|
88646
|
+
readyFile = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "ready");
|
|
88647
|
+
entryFile = (env3 = process.env, version = MINE) => path.join(pkgDir(env3, version), "dist", "cli.mjs");
|
|
88648
|
+
stampPath = (env3, version) => path.join(coreDir(env3, version), "version");
|
|
88543
88649
|
statePath = (env3) => path.join(humHome(env3), "core-install.json");
|
|
88650
|
+
isVersion = (v) => /^\d+\.\d+\.\d+$/.test(v);
|
|
88651
|
+
newer = (a, b) => {
|
|
88652
|
+
const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
|
|
88653
|
+
for (let i = 0; i < 3; i += 1) {
|
|
88654
|
+
if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
|
|
88655
|
+
}
|
|
88656
|
+
return false;
|
|
88657
|
+
};
|
|
88544
88658
|
run = (cmd, args2, opts = {}) => spawnSync(cmd, args2, { encoding: "utf8", windowsHide: true, ...opts });
|
|
88545
88659
|
ASK_VERSION = ["-I", "-c", "import hum; print(hum.__version__)"];
|
|
88546
88660
|
ASK_SSL = ["-I", "-c", "import ssl"];
|
|
88547
|
-
sslAdvice = (env3, version) => `the machine's application control blocked Python's OpenSSL DLL in ${coreDir(env3)}; install Python 3.12 from python.org (Microsoft signs it), then run ${npmFix(version)}`;
|
|
88661
|
+
sslAdvice = (env3, version) => `the machine's application control blocked Python's OpenSSL DLL in ${coreDir(env3, version)}; install Python 3.12 from python.org (Microsoft signs it), then run ${npmFix(version)}`;
|
|
88548
88662
|
readInstallState = (env3 = process.env) => {
|
|
88549
88663
|
try {
|
|
88550
88664
|
return JSON.parse(fs3.readFileSync(statePath(env3), "utf8"));
|
|
@@ -88559,6 +88673,30 @@ var init_install = __esm({
|
|
|
88559
88673
|
} catch {
|
|
88560
88674
|
}
|
|
88561
88675
|
};
|
|
88676
|
+
pause = (ms) => {
|
|
88677
|
+
try {
|
|
88678
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
88679
|
+
} catch {
|
|
88680
|
+
}
|
|
88681
|
+
};
|
|
88682
|
+
if (process.argv[1] && /install\.mjs$/.test(process.argv[1]) && process.argv[2] === "install") {
|
|
88683
|
+
const log = path.join(humHome(), "update.log");
|
|
88684
|
+
const say = (m) => {
|
|
88685
|
+
try {
|
|
88686
|
+
fs3.appendFileSync(log, `${(/* @__PURE__ */ new Date()).toISOString()} ${m}
|
|
88687
|
+
`);
|
|
88688
|
+
} catch {
|
|
88689
|
+
}
|
|
88690
|
+
};
|
|
88691
|
+
const runLogged = (cmd, args2, opts = {}) => {
|
|
88692
|
+
const r2 = run(cmd, args2, { ...opts, stdio: "pipe" });
|
|
88693
|
+
if (r2 && r2.status !== 0 && (r2.stderr || r2.stdout)) say(String(r2.stderr || r2.stdout).trim().split(/\r?\n/).slice(-5).join("\n"));
|
|
88694
|
+
return r2;
|
|
88695
|
+
};
|
|
88696
|
+
const r = installVersion(process.argv[3] || "", { say, runImpl: runLogged, retries: 3 });
|
|
88697
|
+
if (!r.ok) say(`hum ${process.argv[3]} did not install: ${r.error}`);
|
|
88698
|
+
process.exit(r.ok ? 0 : 1);
|
|
88699
|
+
}
|
|
88562
88700
|
}
|
|
88563
88701
|
});
|
|
88564
88702
|
|
|
@@ -88566,6 +88704,7 @@ var init_install = __esm({
|
|
|
88566
88704
|
import fs4 from "node:fs";
|
|
88567
88705
|
import os4 from "node:os";
|
|
88568
88706
|
import path2 from "node:path";
|
|
88707
|
+
import { fileURLToPath } from "node:url";
|
|
88569
88708
|
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
88570
88709
|
async function latestVersion(fetchImpl = globalThis.fetch, env3 = process.env) {
|
|
88571
88710
|
if (env3.HUM_NO_UPDATE_CHECK || typeof fetchImpl !== "function") return "";
|
|
@@ -88588,20 +88727,9 @@ function installLayout(execPath = process.execPath, env3 = process.env) {
|
|
|
88588
88727
|
}
|
|
88589
88728
|
return { kind: "native", exe, dir: path2.dirname(real), base: path2.dirname(path2.dirname(real)) };
|
|
88590
88729
|
}
|
|
88591
|
-
function
|
|
88592
|
-
try {
|
|
88593
|
-
const dir = path2.dirname(fs4.realpathSync(entry));
|
|
88594
|
-
return JSON.parse(fs4.readFileSync(path2.join(dir, "..", "package.json"), "utf8")).version || "";
|
|
88595
|
-
} catch {
|
|
88596
|
-
return "";
|
|
88597
|
-
}
|
|
88598
|
-
}
|
|
88599
|
-
function installerArgv(version, platform2 = process.platform, layout2 = { kind: "native" }, log = "") {
|
|
88730
|
+
function installerArgv(version, platform2 = process.platform, layout2 = { kind: "native" }, log = "", node = process.execPath) {
|
|
88600
88731
|
const base = dist();
|
|
88601
|
-
if (layout2.kind === "npm") {
|
|
88602
|
-
const cmd = `npm i -g --ignore-scripts @metaphi-ai/hum@${version || "latest"}`;
|
|
88603
|
-
return platform2 === "win32" ? ["cmd.exe", ["/d", "/s", "/c", `"${cmd}${log ? ` >> "${log}" 2>&1` : ""}"`], { windowsVerbatimArguments: true }] : ["/bin/sh", ["-c", cmd], {}];
|
|
88604
|
-
}
|
|
88732
|
+
if (layout2.kind === "npm") return [node, [installerScript(), "install", version], {}];
|
|
88605
88733
|
if (platform2 === "win32") {
|
|
88606
88734
|
const cmd = `irm ${base}/install.ps1 | iex`;
|
|
88607
88735
|
return ["powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", log ? `& { ${cmd} } *>> '${log}'` : cmd], {}];
|
|
@@ -88613,6 +88741,7 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
|
|
|
88613
88741
|
const s = readState(env3);
|
|
88614
88742
|
if (s.version === version && now - (s.started || 0) < 30 * 60 * 1e3) return false;
|
|
88615
88743
|
const hidden = platform2 === "win32";
|
|
88744
|
+
const ownLog = layout2.kind === "npm";
|
|
88616
88745
|
const log = path2.join(humHome2(env3), "update.log");
|
|
88617
88746
|
let out = "ignore";
|
|
88618
88747
|
let logged = false;
|
|
@@ -88620,15 +88749,15 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
|
|
|
88620
88749
|
fs4.mkdirSync(humHome2(env3), { recursive: true });
|
|
88621
88750
|
out = fs4.openSync(log, "w");
|
|
88622
88751
|
logged = true;
|
|
88623
|
-
if (hidden) {
|
|
88752
|
+
if (hidden || ownLog) {
|
|
88624
88753
|
fs4.closeSync(out);
|
|
88625
88754
|
out = "ignore";
|
|
88626
88755
|
}
|
|
88627
88756
|
} catch {
|
|
88628
88757
|
out = "ignore";
|
|
88629
88758
|
}
|
|
88630
|
-
const [bin, args2, extra] = installerArgv(version, platform2, layout2, hidden && logged ? log : "");
|
|
88631
|
-
const io = hidden ? { stdio: "ignore", windowsHide: true } : { detached: true, stdio: ["ignore", out, out], windowsHide: true };
|
|
88759
|
+
const [bin, args2, extra] = installerArgv(version, platform2, layout2, hidden && logged && !ownLog ? log : "");
|
|
88760
|
+
const io = hidden ? { stdio: "ignore", windowsHide: true } : { detached: true, stdio: ownLog ? "ignore" : ["ignore", out, out], windowsHide: true };
|
|
88632
88761
|
try {
|
|
88633
88762
|
const child = spawnImpl(bin, args2, { ...io, ...extra, env: { ...env3, HUM_VERSION: version, HUM_DIST: dist(env3) } });
|
|
88634
88763
|
child.unref();
|
|
@@ -88651,7 +88780,7 @@ function updateNotice(mine, { running = "", latest = "", env: env3 = process.env
|
|
|
88651
88780
|
if (drift) return drift;
|
|
88652
88781
|
if (env3.HUM_NO_UPDATE_CHECK || !mine || !latest || !newer(latest, mine)) return "";
|
|
88653
88782
|
if (env3.HUM_NO_AUTO_UPDATE || layout2.kind === "python") return `hum ${latest} is out \xB7 ${updateCommand(layout2)}`;
|
|
88654
|
-
if (readyVersion(layout2, latest)) return `hum ${latest} is ready \xB7 restart hum to use it`;
|
|
88783
|
+
if (readyVersion(layout2, latest, env3)) return `hum ${latest} is ready \xB7 restart hum to use it`;
|
|
88655
88784
|
if (startBackgroundUpdate(latest, { env: env3, spawnImpl, layout: layout2, now, platform: platform2 })) return `hum ${latest} is installing in the background \xB7 it takes effect the next time you start hum`;
|
|
88656
88785
|
if (readState(env3).version === latest) return `hum ${latest} is still installing in the background (${path2.join(humHome2(env3), "update.log")} has the details)`;
|
|
88657
88786
|
return "";
|
|
@@ -88673,45 +88802,54 @@ function watchReady(mine, latest, onReady, { env: env3 = process.env, layout: la
|
|
|
88673
88802
|
if (t.unref) t.unref();
|
|
88674
88803
|
return () => clearInterval(t);
|
|
88675
88804
|
}
|
|
88676
|
-
function updateNow(layout2 = installLayout()) {
|
|
88805
|
+
async function updateNow(layout2 = installLayout(), { mine = MINE, latest = latestVersion, install = installVersion, write = (m) => process.stdout.write(m) } = {}) {
|
|
88677
88806
|
if (layout2.kind === "native") {
|
|
88678
88807
|
const [bin, args2] = installerArgv();
|
|
88679
88808
|
return spawnSync2(bin, args2, { stdio: "inherit", env: { ...process.env, HUM_DIST: dist() } }).status ?? 1;
|
|
88680
88809
|
}
|
|
88681
88810
|
if (layout2.kind === "python") {
|
|
88682
88811
|
const r2 = spawnSync2(win2() ? "uv.exe" : "uv", ["tool", "upgrade", "hum-cli"], { stdio: "inherit", windowsHide: true });
|
|
88683
|
-
if (r2.error || r2.status !== 0)
|
|
88812
|
+
if (r2.error || r2.status !== 0) write(`update with your package manager: ${updateCommand(layout2)}
|
|
88684
88813
|
`);
|
|
88685
88814
|
return r2.error ? 1 : r2.status ?? 1;
|
|
88686
88815
|
}
|
|
88687
|
-
const
|
|
88688
|
-
|
|
88816
|
+
const v = await latest();
|
|
88817
|
+
if (!v) {
|
|
88818
|
+
write(`could not read the latest release from ${dist()}
|
|
88819
|
+
`);
|
|
88820
|
+
return 1;
|
|
88821
|
+
}
|
|
88822
|
+
if (mine && !newer(v, mine)) {
|
|
88823
|
+
write(`hum ${mine} is the latest
|
|
88824
|
+
`);
|
|
88825
|
+
return 0;
|
|
88826
|
+
}
|
|
88827
|
+
const r = install(v, { say: (m) => write(`hum: ${m}
|
|
88828
|
+
`) });
|
|
88829
|
+
if (!r.ok) write(`hum: ${r.error}
|
|
88830
|
+
`);
|
|
88831
|
+
return r.ok ? 0 : 1;
|
|
88689
88832
|
}
|
|
88690
|
-
var dist, humHome2, win2,
|
|
88833
|
+
var dist, humHome2, win2, updateCommand, readyVersion, installerScript, stateFile, readState, writeState;
|
|
88691
88834
|
var init_update = __esm({
|
|
88692
88835
|
"src/update.js"() {
|
|
88836
|
+
init_install();
|
|
88693
88837
|
init_install();
|
|
88694
88838
|
dist = (env3 = process.env) => (env3.HUM_DIST || "https://humboldt.metaphi.ai").replace(/\/+$/, "");
|
|
88695
88839
|
humHome2 = (env3 = process.env) => env3.HUM_HOME || path2.join(os4.homedir(), ".hum");
|
|
88696
88840
|
win2 = () => process.platform === "win32";
|
|
88697
|
-
newer = (a, b) => {
|
|
88698
|
-
const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
|
|
88699
|
-
for (let i = 0; i < 3; i += 1) {
|
|
88700
|
-
if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
|
|
88701
|
-
}
|
|
88702
|
-
return false;
|
|
88703
|
-
};
|
|
88704
88841
|
updateCommand = (layout2 = installLayout(), platform2 = process.platform) => {
|
|
88705
88842
|
if (layout2.kind === "native") return platform2 === "win32" ? `irm ${dist()}/install.ps1 | iex` : `curl -fsSL ${dist()}/install.sh | sh`;
|
|
88706
88843
|
if (layout2.kind === "python") return "uv tool upgrade hum-cli (or: pip install -U hum-cli)";
|
|
88707
88844
|
return "npm i -g @metaphi-ai/hum@latest";
|
|
88708
88845
|
};
|
|
88709
|
-
readyVersion = (layout2, version,
|
|
88846
|
+
readyVersion = (layout2, version, env3 = process.env) => {
|
|
88710
88847
|
if (!version) return "";
|
|
88711
88848
|
if (layout2.kind === "native") return fs4.existsSync(path2.join(layout2.base, version, layout2.exe)) ? version : "";
|
|
88712
|
-
if (layout2.kind === "npm") return
|
|
88849
|
+
if (layout2.kind === "npm") return fs4.existsSync(readyFile(env3, version)) ? version : "";
|
|
88713
88850
|
return "";
|
|
88714
88851
|
};
|
|
88852
|
+
installerScript = () => fileURLToPath(new URL("./install.mjs", import.meta.url));
|
|
88715
88853
|
stateFile = (env3 = process.env) => path2.join(humHome2(env3), "update.json");
|
|
88716
88854
|
readState = (env3 = process.env) => {
|
|
88717
88855
|
try {
|
|
@@ -88774,12 +88912,12 @@ function siblingCore(execPath = process.execPath) {
|
|
|
88774
88912
|
const p = path3.join(dir, "core", win3 ? "hum-core.exe" : "hum-core");
|
|
88775
88913
|
return exists(p) ? p : null;
|
|
88776
88914
|
}
|
|
88777
|
-
function homeCore(env3 = process.env) {
|
|
88778
|
-
|
|
88779
|
-
const py =
|
|
88915
|
+
function homeCore(env3 = process.env, version = MINE) {
|
|
88916
|
+
if (!version) return null;
|
|
88917
|
+
const py = corePython(env3, version);
|
|
88780
88918
|
return exists(py) ? py : null;
|
|
88781
88919
|
}
|
|
88782
|
-
function coreCandidates(env3 = process.env) {
|
|
88920
|
+
function coreCandidates(env3 = process.env, version = MINE) {
|
|
88783
88921
|
const out = [];
|
|
88784
88922
|
if (env3.HUM_CORE) {
|
|
88785
88923
|
const [bin, ...args2] = env3.HUM_CORE.split(" ");
|
|
@@ -88787,8 +88925,8 @@ function coreCandidates(env3 = process.env) {
|
|
|
88787
88925
|
}
|
|
88788
88926
|
const sib = siblingCore();
|
|
88789
88927
|
if (sib) out.push({ bin: sib, args: ["core"], where: "beside hum" });
|
|
88790
|
-
const home = homeCore(env3);
|
|
88791
|
-
if (home) out.push({ bin: home, args: ["-m", "hum.cli", "core"], where: "HUM_HOME/
|
|
88928
|
+
const home = homeCore(env3, version);
|
|
88929
|
+
if (home) out.push({ bin: home, args: ["-m", "hum.cli", "core"], where: "HUM_HOME/versions" });
|
|
88792
88930
|
const py = corePython2();
|
|
88793
88931
|
if (py) out.push({ bin: py, args: ["-m", "hum.cli", "core"], where: "the interpreter beside it" });
|
|
88794
88932
|
out.push({ bin: "hum-core", args: [], where: "PATH" });
|
|
@@ -88805,9 +88943,9 @@ function coreCommand(argv, candidates = coreCandidates()) {
|
|
|
88805
88943
|
}
|
|
88806
88944
|
return null;
|
|
88807
88945
|
}
|
|
88808
|
-
function candidateVersion(c, { env: env3 = process.env, runImpl = spawnSync3 } = {}) {
|
|
88946
|
+
function candidateVersion(c, { env: env3 = process.env, runImpl = spawnSync3, version = MINE } = {}) {
|
|
88809
88947
|
if (!c || !c.bin) return null;
|
|
88810
|
-
if (c.where === "HUM_HOME/
|
|
88948
|
+
if (c.where === "HUM_HOME/versions") return installedVersion(env3, version);
|
|
88811
88949
|
const interp = c.args.length >= 3 && c.args[c.args.length - 3] === "-m" && c.args[c.args.length - 2] === "hum.cli";
|
|
88812
88950
|
let r;
|
|
88813
88951
|
try {
|
|
@@ -88832,10 +88970,10 @@ function clientEnv() {
|
|
|
88832
88970
|
platform: process.platform,
|
|
88833
88971
|
arch: process.arch,
|
|
88834
88972
|
terminal: process.env.TERM_PROGRAM || (process.env.WT_SESSION ? "Windows Terminal" : process.env.TERM || ""),
|
|
88835
|
-
tui: true ? "0.2.
|
|
88973
|
+
tui: true ? "0.2.12" : ""
|
|
88836
88974
|
};
|
|
88837
88975
|
}
|
|
88838
|
-
function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.
|
|
88976
|
+
function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.12" : "" } = {}) {
|
|
88839
88977
|
const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
|
|
88840
88978
|
const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
|
|
88841
88979
|
if (!refused) {
|
|
@@ -89658,10 +89796,12 @@ async function diagnose({
|
|
|
89658
89796
|
if (env3.HUM_CORE && running && running.version === mine) checks.push(check2("warn", `HUM_CORE is set (${env3.HUM_CORE}): it decides what runs, ahead of any install`, "unset HUM_CORE"));
|
|
89659
89797
|
if (layout2.kind === "npm") {
|
|
89660
89798
|
const st = readInstallState(env3);
|
|
89661
|
-
const stamp = installedVersion(env3, runImpl);
|
|
89799
|
+
const stamp = installedVersion(env3, mine, runImpl);
|
|
89662
89800
|
if (st && !st.ok) checks.push(check2(stamp === mine ? "warn" : "fail", `the last install attempt (wanted ${st.wanted || st.version}) did not finish: ${st.error}`, npmFix2(mine)));
|
|
89663
|
-
else if (!stamp) checks.push(check2("fail", `nothing installed under ${coreDir(env3)}`, npmFix2(mine)));
|
|
89664
|
-
else checks.push(check2(stamp === mine ? "ok" : "warn", `${coreDir(env3)} holds ${stamp}`, stamp === mine ? "" : npmFix2(mine)));
|
|
89801
|
+
else if (!stamp) checks.push(check2("fail", `nothing installed under ${coreDir(env3, mine)}`, npmFix2(mine)));
|
|
89802
|
+
else checks.push(check2(stamp === mine ? "ok" : "warn", `${coreDir(env3, mine)} holds ${stamp}`, stamp === mine ? "" : npmFix2(mine)));
|
|
89803
|
+
const ready = readyVersions(env3);
|
|
89804
|
+
if (ready.length) checks.push(check2("ok", `installed here: ${ready.join(", ")} (the newest starts next)`));
|
|
89665
89805
|
}
|
|
89666
89806
|
if (layout2.kind === "native") {
|
|
89667
89807
|
const sib = path6.join(layout2.dir, "core", isWin(platform2) ? "hum-core.exe" : "hum-core");
|
|
@@ -89686,7 +89826,7 @@ async function diagnose({
|
|
|
89686
89826
|
else if (latest) checks.push(check2("ok", `${mine} is the latest release`));
|
|
89687
89827
|
sections.push({ key: "updates", title: "Updates", checks });
|
|
89688
89828
|
}
|
|
89689
|
-
const interp = running && running.args.length >= 3 && running.args[running.args.length - 2] === "hum.cli" ? running.bin : exists2(corePython(env3)) ? corePython(env3) : null;
|
|
89829
|
+
const interp = running && running.args.length >= 3 && running.args[running.args.length - 2] === "hum.cli" ? running.bin : exists2(corePython(env3, mine)) ? corePython(env3, mine) : null;
|
|
89690
89830
|
let toolServers = null;
|
|
89691
89831
|
{
|
|
89692
89832
|
const checks = [];
|
|
@@ -90291,7 +90431,7 @@ var input_default = MultilineInput;
|
|
|
90291
90431
|
|
|
90292
90432
|
// src/app.jsx
|
|
90293
90433
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
90294
|
-
var
|
|
90434
|
+
var MINE2 = true ? "0.2.12" : "";
|
|
90295
90435
|
var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
|
|
90296
90436
|
var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
|
|
90297
90437
|
var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
|
|
@@ -90679,7 +90819,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
|
|
|
90679
90819
|
(ev.questions || []).forEach(addAsk);
|
|
90680
90820
|
if (ev.fresh) append({ kind: "wordmark" });
|
|
90681
90821
|
setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
|
|
90682
|
-
append({ kind: "banner", lines: bannerLines(ev, homeRel,
|
|
90822
|
+
append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE2), instruction: ev.session ? ev.instruction : null });
|
|
90683
90823
|
if (ev.note) append({ kind: "warn", text: ev.note });
|
|
90684
90824
|
setGoal(ev.goal_state && ev.goal_state.text ? ev.goal_state : ev.goal ? { text: ev.goal, status: "active", exchanges: 0 } : null);
|
|
90685
90825
|
if (ev.goal_state && ev.goal_state.text) append({ kind: "info", text: goalLine(ev.goal_state) });
|
|
@@ -91053,7 +91193,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
|
|
|
91053
91193
|
const noticedRef = (0, import_react36.useRef)("");
|
|
91054
91194
|
(0, import_react36.useEffect)(() => {
|
|
91055
91195
|
if (!latest) return void 0;
|
|
91056
|
-
const mine =
|
|
91196
|
+
const mine = MINE2 || latest.version || "0.0.0";
|
|
91057
91197
|
const want = latest.latest_version || "";
|
|
91058
91198
|
const line = update(mine, { running: latest.version || "", latest: want });
|
|
91059
91199
|
if (line && noticedRef.current !== line) {
|
|
@@ -92116,33 +92256,33 @@ init_update();
|
|
|
92116
92256
|
init_install();
|
|
92117
92257
|
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
92118
92258
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
92119
|
-
var
|
|
92259
|
+
var MINE3 = true ? "0.2.12" : "0.0.0";
|
|
92120
92260
|
var layout = installLayout();
|
|
92121
92261
|
function completeInstall() {
|
|
92122
|
-
if (layout.kind !== "npm" || !needsInstall(
|
|
92262
|
+
if (layout.kind !== "npm" || !needsInstall(MINE3)) return;
|
|
92123
92263
|
const say = (m) => process.stderr.write(`hum: ${m}
|
|
92124
92264
|
`);
|
|
92125
|
-
say(`updating to ${
|
|
92126
|
-
const r = installCore(
|
|
92127
|
-
if (!r.ok) say(`the update did not finish: ${r.error} \xB7 ${npmFix(
|
|
92265
|
+
say(`updating to ${MINE3} \u2026`);
|
|
92266
|
+
const r = installCore(MINE3, { say });
|
|
92267
|
+
if (!r.ok) say(`the update did not finish: ${r.error} \xB7 ${npmFix(MINE3)}`);
|
|
92128
92268
|
}
|
|
92129
92269
|
var CORE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "persona", "ps", "stop", "hooks", "core"]);
|
|
92130
92270
|
var argv0 = process.argv.slice(2);
|
|
92131
92271
|
if (argv0[0] === "--version" || argv0[0] === "-V") {
|
|
92132
|
-
process.stdout.write(`hum ${
|
|
92272
|
+
process.stdout.write(`hum ${MINE3}
|
|
92133
92273
|
`);
|
|
92134
92274
|
if (layout.kind === "npm") {
|
|
92135
92275
|
const r = runningVersion();
|
|
92136
|
-
const drift = mismatchLine(
|
|
92276
|
+
const drift = mismatchLine(MINE3, r ? r.version : "", { layout });
|
|
92137
92277
|
if (drift) process.stdout.write(`${drift}
|
|
92138
92278
|
`);
|
|
92139
92279
|
}
|
|
92140
92280
|
process.exit(0);
|
|
92141
92281
|
}
|
|
92142
|
-
if (argv0[0] === "update") process.exit(updateNow());
|
|
92282
|
+
if (argv0[0] === "update") process.exit(await updateNow());
|
|
92143
92283
|
if (argv0[0] === "doctor") {
|
|
92144
92284
|
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
92145
|
-
process.exit(await doctor2({ json: argv0.includes("--json"), mine:
|
|
92285
|
+
process.exit(await doctor2({ json: argv0.includes("--json"), mine: MINE3, layout }));
|
|
92146
92286
|
}
|
|
92147
92287
|
if (CORE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--json") || wantsPlain(argv0)) {
|
|
92148
92288
|
completeInstall();
|
package/dist/install.mjs
CHANGED
|
@@ -4,29 +4,59 @@ import fs from "node:fs";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
var win = process.platform === "win32";
|
|
7
|
+
var MINE = typeof HUM_VERSION === "string" ? HUM_VERSION : "";
|
|
7
8
|
var npmFix = (version = "") => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
|
|
8
9
|
var NPM_FIX = npmFix("latest");
|
|
9
10
|
var humHome = (env = process.env) => env.HUM_HOME || path.join(os.homedir(), ".hum");
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
11
|
+
var versionsDir = (env = process.env) => path.join(humHome(env), "versions");
|
|
12
|
+
var versionDir = (env = process.env, version = MINE) => path.join(versionsDir(env), version);
|
|
13
|
+
var pkgDir = (env = process.env, version = MINE) => path.join(versionDir(env, version), "pkg");
|
|
14
|
+
var coreDir = (env = process.env, version = MINE) => path.join(versionDir(env, version), "core");
|
|
15
|
+
var corePython = (env = process.env, version = MINE) => win ? path.join(coreDir(env, version), "Scripts", "python.exe") : path.join(coreDir(env, version), "bin", "python");
|
|
16
|
+
var readyFile = (env = process.env, version = MINE) => path.join(versionDir(env, version), "ready");
|
|
17
|
+
var entryFile = (env = process.env, version = MINE) => path.join(pkgDir(env, version), "dist", "cli.mjs");
|
|
18
|
+
var stampPath = (env, version) => path.join(coreDir(env, version), "version");
|
|
13
19
|
var statePath = (env) => path.join(humHome(env), "core-install.json");
|
|
20
|
+
var isVersion = (v) => /^\d+\.\d+\.\d+$/.test(v);
|
|
21
|
+
var newer = (a, b) => {
|
|
22
|
+
const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
|
|
23
|
+
for (let i = 0; i < 3; i += 1) {
|
|
24
|
+
if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
};
|
|
28
|
+
function readyVersions(env = process.env) {
|
|
29
|
+
let names = [];
|
|
30
|
+
try {
|
|
31
|
+
names = fs.readdirSync(versionsDir(env));
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
return names.filter((v) => isVersion(v) && fs.existsSync(readyFile(env, v))).sort((a, b) => newer(a, b) ? -1 : newer(b, a) ? 1 : 0);
|
|
36
|
+
}
|
|
37
|
+
function chosenEntry(own, env = process.env) {
|
|
38
|
+
for (const v of readyVersions(env)) {
|
|
39
|
+
if (own && !newer(v, own)) break;
|
|
40
|
+
if (fs.existsSync(entryFile(env, v)) && fs.existsSync(corePython(env, v))) return entryFile(env, v);
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
14
44
|
var run = (cmd, args, opts = {}) => spawnSync(cmd, args, { encoding: "utf8", windowsHide: true, ...opts });
|
|
15
45
|
var ASK_VERSION = ["-I", "-c", "import hum; print(hum.__version__)"];
|
|
16
|
-
function importedVersion(env = process.env, runImpl = run) {
|
|
17
|
-
const r = runImpl(corePython(env), ASK_VERSION);
|
|
46
|
+
function importedVersion(env = process.env, version = MINE, runImpl = run) {
|
|
47
|
+
const r = runImpl(corePython(env, version), ASK_VERSION);
|
|
18
48
|
return r && r.status === 0 ? String(r.stdout).trim() : null;
|
|
19
49
|
}
|
|
20
|
-
function installedVersion(env = process.env, runImpl = run) {
|
|
50
|
+
function installedVersion(env = process.env, version = MINE, runImpl = run) {
|
|
21
51
|
try {
|
|
22
|
-
return fs.readFileSync(stampPath(env), "utf8").trim() || null;
|
|
52
|
+
return fs.readFileSync(stampPath(env, version), "utf8").trim() || null;
|
|
23
53
|
} catch {
|
|
24
54
|
}
|
|
25
|
-
if (!fs.existsSync(corePython(env))) return null;
|
|
26
|
-
const v = importedVersion(env, runImpl);
|
|
55
|
+
if (!fs.existsSync(corePython(env, version))) return null;
|
|
56
|
+
const v = importedVersion(env, version, runImpl);
|
|
27
57
|
if (v) {
|
|
28
58
|
try {
|
|
29
|
-
fs.writeFileSync(stampPath(env), `${v}
|
|
59
|
+
fs.writeFileSync(stampPath(env, version), `${v}
|
|
30
60
|
`);
|
|
31
61
|
} catch {
|
|
32
62
|
}
|
|
@@ -40,13 +70,13 @@ function trustedPython(env = process.env, runImpl = run) {
|
|
|
40
70
|
return /^[a-z]:\\.+\\python(w)?\.exe$/i.test(p) ? p : null;
|
|
41
71
|
}
|
|
42
72
|
var ASK_SSL = ["-I", "-c", "import ssl"];
|
|
43
|
-
function sslBlocked(env = process.env, runImpl = run) {
|
|
44
|
-
const r = runImpl(corePython(env), ASK_SSL);
|
|
73
|
+
function sslBlocked(env = process.env, version = MINE, runImpl = run) {
|
|
74
|
+
const r = runImpl(corePython(env, version), ASK_SSL);
|
|
45
75
|
if (r && r.status === 0) return null;
|
|
46
76
|
const text = String(r && (r.stderr || r.stdout) || "ssl did not import").trim().split(/\r?\n/).filter(Boolean).pop() || "ssl did not import";
|
|
47
77
|
return text;
|
|
48
78
|
}
|
|
49
|
-
var sslAdvice = (env, version) => `the machine's application control blocked Python's OpenSSL DLL in ${coreDir(env)}; install Python 3.12 from python.org (Microsoft signs it), then run ${npmFix(version)}`;
|
|
79
|
+
var sslAdvice = (env, version) => `the machine's application control blocked Python's OpenSSL DLL in ${coreDir(env, version)}; install Python 3.12 from python.org (Microsoft signs it), then run ${npmFix(version)}`;
|
|
50
80
|
var readInstallState = (env = process.env) => {
|
|
51
81
|
try {
|
|
52
82
|
return JSON.parse(fs.readFileSync(statePath(env), "utf8"));
|
|
@@ -61,16 +91,15 @@ var writeInstallState = (s, env) => {
|
|
|
61
91
|
} catch {
|
|
62
92
|
}
|
|
63
93
|
};
|
|
64
|
-
function needsInstall(version, { env = process.env, installed = () => installedVersion(env), now = Date.now(), state = readInstallState(env) } = {}) {
|
|
94
|
+
function needsInstall(version, { env = process.env, installed = () => installedVersion(env, version), now = Date.now(), state = readInstallState(env) } = {}) {
|
|
65
95
|
if (!version || env.HUM_CORE || env.HUM_CORE_PORT) return false;
|
|
66
96
|
if (installed() === version) return false;
|
|
67
97
|
if (state && !state.ok && state.version === version && now - (state.at || 0) < 10 * 60 * 1e3) return false;
|
|
68
98
|
return true;
|
|
69
99
|
}
|
|
70
100
|
function installCore(version, { env = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now() } = {}) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const python = corePython(env);
|
|
101
|
+
const dir = coreDir(env, version);
|
|
102
|
+
const python = corePython(env, version);
|
|
74
103
|
const localBin = path.join(os.homedir(), ".local", "bin");
|
|
75
104
|
const uvNames = ["uv", path.join(localBin, win ? "uv.exe" : "uv")];
|
|
76
105
|
const uv = () => uvNames.find((u) => {
|
|
@@ -91,30 +120,30 @@ function installCore(version, { env = process.env, say = (m) => console.log(`hum
|
|
|
91
120
|
if (!u) return outcome(false, `could not install uv; install it from https://astral.sh/uv and run: ${npmFix(version)}`);
|
|
92
121
|
}
|
|
93
122
|
say(`installing ${env.HUM_CORE_SPEC ? spec : `hum ${version}`} into ${dir} \u2026`);
|
|
94
|
-
fs.mkdirSync(
|
|
123
|
+
fs.mkdirSync(path.dirname(dir), { recursive: true });
|
|
95
124
|
try {
|
|
96
|
-
fs.unlinkSync(stampPath(env));
|
|
125
|
+
fs.unlinkSync(stampPath(env, version));
|
|
97
126
|
} catch {
|
|
98
127
|
}
|
|
99
128
|
const trusted = trustedPython(env, runImpl);
|
|
100
129
|
const makeVenv = (clear) => (runImpl(u, ["venv", "--quiet", "--python", trusted || "3.12", ...clear ? ["--clear"] : [], dir], { stdio: "inherit" }) || {}).status === 0;
|
|
101
|
-
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--python", python, spec], { stdio: "inherit" }) || {}).status === 0;
|
|
130
|
+
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--refresh-package", "hum-cli", "--python", python, spec], { stdio: "inherit" }) || {}).status === 0;
|
|
102
131
|
if (!fs.existsSync(python) && !makeVenv(fs.existsSync(dir))) return outcome(false, "uv venv failed");
|
|
103
132
|
if (!pipIn()) return outcome(false, `uv pip install ${spec} failed`);
|
|
104
|
-
let got = importedVersion(env, runImpl);
|
|
133
|
+
let got = importedVersion(env, version, runImpl);
|
|
105
134
|
if (!got) return outcome(false, "hum did not import after the install");
|
|
106
135
|
if (got !== version && !env.HUM_CORE_SPEC) return outcome(false, `installed ${got}, wanted ${version}`, got);
|
|
107
|
-
let blocked = sslBlocked(env, runImpl);
|
|
136
|
+
let blocked = sslBlocked(env, version, runImpl);
|
|
108
137
|
if (blocked && trusted) {
|
|
109
138
|
say(`the policy here refuses the environment's OpenSSL (${blocked}); rebuilding it on ${trusted} \u2026`);
|
|
110
139
|
if (makeVenv(true) && pipIn()) {
|
|
111
|
-
got = importedVersion(env, runImpl) || got;
|
|
112
|
-
blocked = sslBlocked(env, runImpl);
|
|
140
|
+
got = importedVersion(env, version, runImpl) || got;
|
|
141
|
+
blocked = sslBlocked(env, version, runImpl);
|
|
113
142
|
}
|
|
114
143
|
}
|
|
115
144
|
if (blocked) return outcome(false, sslAdvice(env, version));
|
|
116
145
|
fs.mkdirSync(dir, { recursive: true });
|
|
117
|
-
fs.writeFileSync(stampPath(env), `${got}
|
|
146
|
+
fs.writeFileSync(stampPath(env, version), `${got}
|
|
118
147
|
`);
|
|
119
148
|
const list = runImpl(u, ["tool", "list"]);
|
|
120
149
|
if (list && list.status === 0 && /^hum-cli\b/m.test(list.stdout)) {
|
|
@@ -127,20 +156,148 @@ function installCore(version, { env = process.env, say = (m) => console.log(`hum
|
|
|
127
156
|
return outcome(false, e && e.message ? e.message : String(e));
|
|
128
157
|
}
|
|
129
158
|
}
|
|
159
|
+
function installPackage(version, { env = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run } = {}) {
|
|
160
|
+
const dest = pkgDir(env, version);
|
|
161
|
+
const stage = path.join(versionDir(env, version), "npm");
|
|
162
|
+
say(`fetching hum ${version} \u2026`);
|
|
163
|
+
fs.rmSync(stage, { recursive: true, force: true });
|
|
164
|
+
fs.mkdirSync(stage, { recursive: true });
|
|
165
|
+
const r = runImpl(win ? "npm.cmd" : "npm", [
|
|
166
|
+
"install",
|
|
167
|
+
"--prefix",
|
|
168
|
+
stage,
|
|
169
|
+
"--ignore-scripts",
|
|
170
|
+
"--no-audit",
|
|
171
|
+
"--no-fund",
|
|
172
|
+
"--no-package-lock",
|
|
173
|
+
"--loglevel=error",
|
|
174
|
+
`@metaphi-ai/hum@${version}`
|
|
175
|
+
], { shell: win, env: { ...env, npm_config_update_notifier: "false" } });
|
|
176
|
+
const got = path.join(stage, "node_modules", "@metaphi-ai", "hum");
|
|
177
|
+
if (!r || r.status !== 0 || !fs.existsSync(path.join(got, "dist", "cli.mjs"))) {
|
|
178
|
+
const why = String(r && (r.stderr || r.stdout) || "").trim().split(/\r?\n/).filter(Boolean).pop() || `npm exited ${r ? r.status : "without running"}`;
|
|
179
|
+
fs.rmSync(stage, { recursive: true, force: true });
|
|
180
|
+
return { ok: false, error: `npm could not fetch @metaphi-ai/hum@${version}: ${why}` };
|
|
181
|
+
}
|
|
182
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
183
|
+
fs.renameSync(got, dest);
|
|
184
|
+
fs.rmSync(stage, { recursive: true, force: true });
|
|
185
|
+
return { ok: true, error: null };
|
|
186
|
+
}
|
|
187
|
+
function prune(env = process.env, { keep = MINE, say = () => {
|
|
188
|
+
}, now = Date.now() } = {}) {
|
|
189
|
+
let names = [];
|
|
190
|
+
try {
|
|
191
|
+
names = fs.readdirSync(versionsDir(env)).filter(isVersion);
|
|
192
|
+
} catch {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
const ready = readyVersions(env);
|
|
196
|
+
const stay = /* @__PURE__ */ new Set([keep, ...ready.slice(0, 3)]);
|
|
197
|
+
const gone = [];
|
|
198
|
+
for (const v of names) {
|
|
199
|
+
if (stay.has(v)) continue;
|
|
200
|
+
if (!ready.includes(v)) {
|
|
201
|
+
let at = 0;
|
|
202
|
+
try {
|
|
203
|
+
at = fs.statSync(versionDir(env, v)).mtimeMs;
|
|
204
|
+
} catch {
|
|
205
|
+
}
|
|
206
|
+
if (now - at < 30 * 60 * 1e3) continue;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
fs.rmSync(versionDir(env, v), { recursive: true, force: true });
|
|
210
|
+
gone.push(v);
|
|
211
|
+
say(`removed hum ${v}`);
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return gone.sort((a, b) => newer(a, b) ? -1 : newer(b, a) ? 1 : 0);
|
|
216
|
+
}
|
|
217
|
+
var pause = (ms) => {
|
|
218
|
+
try {
|
|
219
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
function installVersion(version, { env = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now(), retries = 0, every = 90 * 1e3, wait = pause } = {}) {
|
|
224
|
+
if (!isVersion(version)) return { ok: false, error: `not a version: ${version}` };
|
|
225
|
+
try {
|
|
226
|
+
fs.mkdirSync(versionDir(env, version), { recursive: true });
|
|
227
|
+
try {
|
|
228
|
+
fs.unlinkSync(readyFile(env, version));
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
231
|
+
const attempt = (what, step) => {
|
|
232
|
+
let r = step();
|
|
233
|
+
for (let i = 0; !r.ok && i < retries; i += 1) {
|
|
234
|
+
say(`${what} is not there yet (${r.error}); trying again in ${Math.round(every / 1e3)} s`);
|
|
235
|
+
wait(every);
|
|
236
|
+
r = step();
|
|
237
|
+
}
|
|
238
|
+
return r;
|
|
239
|
+
};
|
|
240
|
+
if (!fs.existsSync(entryFile(env, version))) {
|
|
241
|
+
const p = attempt("the package", () => installPackage(version, { env, say, runImpl }));
|
|
242
|
+
if (!p.ok) return p;
|
|
243
|
+
}
|
|
244
|
+
if (installedVersion(env, version, runImpl) !== version) {
|
|
245
|
+
const c = attempt("the part of hum that does the work", () => installCore(version, { env, say, runImpl, now }));
|
|
246
|
+
if (!c.ok) return { ok: false, error: c.error };
|
|
247
|
+
}
|
|
248
|
+
fs.writeFileSync(readyFile(env, version), `${version}
|
|
249
|
+
`);
|
|
250
|
+
say(`hum ${version} is ready; the next hum you start is ${version}`);
|
|
251
|
+
prune(env, { say });
|
|
252
|
+
return { ok: true, error: null };
|
|
253
|
+
} catch (e) {
|
|
254
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (process.argv[1] && /install\.mjs$/.test(process.argv[1]) && process.argv[2] === "install") {
|
|
258
|
+
const log = path.join(humHome(), "update.log");
|
|
259
|
+
const say = (m) => {
|
|
260
|
+
try {
|
|
261
|
+
fs.appendFileSync(log, `${(/* @__PURE__ */ new Date()).toISOString()} ${m}
|
|
262
|
+
`);
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
const runLogged = (cmd, args, opts = {}) => {
|
|
267
|
+
const r2 = run(cmd, args, { ...opts, stdio: "pipe" });
|
|
268
|
+
if (r2 && r2.status !== 0 && (r2.stderr || r2.stdout)) say(String(r2.stderr || r2.stdout).trim().split(/\r?\n/).slice(-5).join("\n"));
|
|
269
|
+
return r2;
|
|
270
|
+
};
|
|
271
|
+
const r = installVersion(process.argv[3] || "", { say, runImpl: runLogged, retries: 3 });
|
|
272
|
+
if (!r.ok) say(`hum ${process.argv[3]} did not install: ${r.error}`);
|
|
273
|
+
process.exit(r.ok ? 0 : 1);
|
|
274
|
+
}
|
|
130
275
|
export {
|
|
131
276
|
ASK_SSL,
|
|
132
277
|
ASK_VERSION,
|
|
278
|
+
MINE,
|
|
133
279
|
NPM_FIX,
|
|
280
|
+
chosenEntry,
|
|
134
281
|
coreDir,
|
|
135
282
|
corePython,
|
|
283
|
+
entryFile,
|
|
136
284
|
humHome,
|
|
137
285
|
importedVersion,
|
|
138
286
|
installCore,
|
|
287
|
+
installPackage,
|
|
288
|
+
installVersion,
|
|
139
289
|
installedVersion,
|
|
140
290
|
needsInstall,
|
|
291
|
+
newer,
|
|
141
292
|
npmFix,
|
|
293
|
+
pkgDir,
|
|
294
|
+
prune,
|
|
142
295
|
readInstallState,
|
|
296
|
+
readyFile,
|
|
297
|
+
readyVersions,
|
|
143
298
|
sslAdvice,
|
|
144
299
|
sslBlocked,
|
|
145
|
-
trustedPython
|
|
300
|
+
trustedPython,
|
|
301
|
+
versionDir,
|
|
302
|
+
versionsDir
|
|
146
303
|
};
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -11,7 +11,7 @@ const version = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json')
|
|
|
11
11
|
// a URL, not a path: on Windows `C:\…` is not something the ESM loader will import
|
|
12
12
|
const { installedVersion, installCore, npmFix } = await import(pathToFileURL(path.join(here, '..', 'dist', 'install.mjs')).href);
|
|
13
13
|
|
|
14
|
-
if (installedVersion() !== version) {
|
|
14
|
+
if (installedVersion(process.env, version) !== version) {
|
|
15
15
|
const r = installCore(version);
|
|
16
16
|
if (!r.ok) console.log(`hum: the install did not finish (${r.error}); run: ${npmFix(version)}`);
|
|
17
17
|
}
|