@metaphi-ai/hum 0.2.9 → 0.2.11
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 +207 -82
- package/dist/install.mjs +167 -25
- 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,9 +88502,9 @@ 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);
|
|
@@ -88504,20 +88512,20 @@ function installCore(version, { env: env3 = process.env, say = (m) => console.lo
|
|
|
88504
88512
|
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--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,118 @@ 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() } = {}) {
|
|
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
|
+
if (!fs3.existsSync(entryFile(env3, version))) {
|
|
88608
|
+
const p = installPackage(version, { env: env3, say, runImpl });
|
|
88609
|
+
if (!p.ok) return p;
|
|
88610
|
+
}
|
|
88611
|
+
if (installedVersion(env3, version, runImpl) !== version) {
|
|
88612
|
+
const c = installCore(version, { env: env3, say, runImpl, now });
|
|
88613
|
+
if (!c.ok) return { ok: false, error: c.error };
|
|
88614
|
+
}
|
|
88615
|
+
fs3.writeFileSync(readyFile(env3, version), `${version}
|
|
88616
|
+
`);
|
|
88617
|
+
say(`hum ${version} is ready; the next hum you start is ${version}`);
|
|
88618
|
+
prune(env3, { say });
|
|
88619
|
+
return { ok: true, error: null };
|
|
88620
|
+
} catch (e) {
|
|
88621
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
88622
|
+
}
|
|
88623
|
+
}
|
|
88624
|
+
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;
|
|
88534
88625
|
var init_install = __esm({
|
|
88535
88626
|
"src/install.js"() {
|
|
88536
88627
|
win = process.platform === "win32";
|
|
88628
|
+
MINE = true ? "0.2.11" : "";
|
|
88537
88629
|
npmFix = (version = "") => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
|
|
88538
88630
|
NPM_FIX = npmFix("latest");
|
|
88539
88631
|
humHome = (env3 = process.env) => env3.HUM_HOME || path.join(os3.homedir(), ".hum");
|
|
88540
|
-
|
|
88541
|
-
|
|
88542
|
-
|
|
88632
|
+
versionsDir = (env3 = process.env) => path.join(humHome(env3), "versions");
|
|
88633
|
+
versionDir = (env3 = process.env, version = MINE) => path.join(versionsDir(env3), version);
|
|
88634
|
+
pkgDir = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "pkg");
|
|
88635
|
+
coreDir = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "core");
|
|
88636
|
+
corePython = (env3 = process.env, version = MINE) => win ? path.join(coreDir(env3, version), "Scripts", "python.exe") : path.join(coreDir(env3, version), "bin", "python");
|
|
88637
|
+
readyFile = (env3 = process.env, version = MINE) => path.join(versionDir(env3, version), "ready");
|
|
88638
|
+
entryFile = (env3 = process.env, version = MINE) => path.join(pkgDir(env3, version), "dist", "cli.mjs");
|
|
88639
|
+
stampPath = (env3, version) => path.join(coreDir(env3, version), "version");
|
|
88543
88640
|
statePath = (env3) => path.join(humHome(env3), "core-install.json");
|
|
88641
|
+
isVersion = (v) => /^\d+\.\d+\.\d+$/.test(v);
|
|
88642
|
+
newer = (a, b) => {
|
|
88643
|
+
const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
|
|
88644
|
+
for (let i = 0; i < 3; i += 1) {
|
|
88645
|
+
if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
|
|
88646
|
+
}
|
|
88647
|
+
return false;
|
|
88648
|
+
};
|
|
88544
88649
|
run = (cmd, args2, opts = {}) => spawnSync(cmd, args2, { encoding: "utf8", windowsHide: true, ...opts });
|
|
88545
88650
|
ASK_VERSION = ["-I", "-c", "import hum; print(hum.__version__)"];
|
|
88546
88651
|
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)}`;
|
|
88652
|
+
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
88653
|
readInstallState = (env3 = process.env) => {
|
|
88549
88654
|
try {
|
|
88550
88655
|
return JSON.parse(fs3.readFileSync(statePath(env3), "utf8"));
|
|
@@ -88559,6 +88664,24 @@ var init_install = __esm({
|
|
|
88559
88664
|
} catch {
|
|
88560
88665
|
}
|
|
88561
88666
|
};
|
|
88667
|
+
if (process.argv[1] && /install\.mjs$/.test(process.argv[1]) && process.argv[2] === "install") {
|
|
88668
|
+
const log = path.join(humHome(), "update.log");
|
|
88669
|
+
const say = (m) => {
|
|
88670
|
+
try {
|
|
88671
|
+
fs3.appendFileSync(log, `${(/* @__PURE__ */ new Date()).toISOString()} ${m}
|
|
88672
|
+
`);
|
|
88673
|
+
} catch {
|
|
88674
|
+
}
|
|
88675
|
+
};
|
|
88676
|
+
const runLogged = (cmd, args2, opts = {}) => {
|
|
88677
|
+
const r2 = run(cmd, args2, { ...opts, stdio: "pipe" });
|
|
88678
|
+
if (r2 && r2.status !== 0 && (r2.stderr || r2.stdout)) say(String(r2.stderr || r2.stdout).trim().split(/\r?\n/).slice(-5).join("\n"));
|
|
88679
|
+
return r2;
|
|
88680
|
+
};
|
|
88681
|
+
const r = installVersion(process.argv[3] || "", { say, runImpl: runLogged });
|
|
88682
|
+
if (!r.ok) say(`hum ${process.argv[3]} did not install: ${r.error}`);
|
|
88683
|
+
process.exit(r.ok ? 0 : 1);
|
|
88684
|
+
}
|
|
88562
88685
|
}
|
|
88563
88686
|
});
|
|
88564
88687
|
|
|
@@ -88566,6 +88689,7 @@ var init_install = __esm({
|
|
|
88566
88689
|
import fs4 from "node:fs";
|
|
88567
88690
|
import os4 from "node:os";
|
|
88568
88691
|
import path2 from "node:path";
|
|
88692
|
+
import { fileURLToPath } from "node:url";
|
|
88569
88693
|
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
88570
88694
|
async function latestVersion(fetchImpl = globalThis.fetch, env3 = process.env) {
|
|
88571
88695
|
if (env3.HUM_NO_UPDATE_CHECK || typeof fetchImpl !== "function") return "";
|
|
@@ -88588,20 +88712,9 @@ function installLayout(execPath = process.execPath, env3 = process.env) {
|
|
|
88588
88712
|
}
|
|
88589
88713
|
return { kind: "native", exe, dir: path2.dirname(real), base: path2.dirname(path2.dirname(real)) };
|
|
88590
88714
|
}
|
|
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 = "") {
|
|
88715
|
+
function installerArgv(version, platform2 = process.platform, layout2 = { kind: "native" }, log = "", node = process.execPath) {
|
|
88600
88716
|
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
|
-
}
|
|
88717
|
+
if (layout2.kind === "npm") return [node, [installerScript(), "install", version], {}];
|
|
88605
88718
|
if (platform2 === "win32") {
|
|
88606
88719
|
const cmd = `irm ${base}/install.ps1 | iex`;
|
|
88607
88720
|
return ["powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", log ? `& { ${cmd} } *>> '${log}'` : cmd], {}];
|
|
@@ -88613,6 +88726,7 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
|
|
|
88613
88726
|
const s = readState(env3);
|
|
88614
88727
|
if (s.version === version && now - (s.started || 0) < 30 * 60 * 1e3) return false;
|
|
88615
88728
|
const hidden = platform2 === "win32";
|
|
88729
|
+
const ownLog = layout2.kind === "npm";
|
|
88616
88730
|
const log = path2.join(humHome2(env3), "update.log");
|
|
88617
88731
|
let out = "ignore";
|
|
88618
88732
|
let logged = false;
|
|
@@ -88620,15 +88734,15 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
|
|
|
88620
88734
|
fs4.mkdirSync(humHome2(env3), { recursive: true });
|
|
88621
88735
|
out = fs4.openSync(log, "w");
|
|
88622
88736
|
logged = true;
|
|
88623
|
-
if (hidden) {
|
|
88737
|
+
if (hidden || ownLog) {
|
|
88624
88738
|
fs4.closeSync(out);
|
|
88625
88739
|
out = "ignore";
|
|
88626
88740
|
}
|
|
88627
88741
|
} catch {
|
|
88628
88742
|
out = "ignore";
|
|
88629
88743
|
}
|
|
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 };
|
|
88744
|
+
const [bin, args2, extra] = installerArgv(version, platform2, layout2, hidden && logged && !ownLog ? log : "");
|
|
88745
|
+
const io = hidden ? { stdio: "ignore", windowsHide: true } : { detached: true, stdio: ownLog ? "ignore" : ["ignore", out, out], windowsHide: true };
|
|
88632
88746
|
try {
|
|
88633
88747
|
const child = spawnImpl(bin, args2, { ...io, ...extra, env: { ...env3, HUM_VERSION: version, HUM_DIST: dist(env3) } });
|
|
88634
88748
|
child.unref();
|
|
@@ -88651,7 +88765,7 @@ function updateNotice(mine, { running = "", latest = "", env: env3 = process.env
|
|
|
88651
88765
|
if (drift) return drift;
|
|
88652
88766
|
if (env3.HUM_NO_UPDATE_CHECK || !mine || !latest || !newer(latest, mine)) return "";
|
|
88653
88767
|
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`;
|
|
88768
|
+
if (readyVersion(layout2, latest, env3)) return `hum ${latest} is ready \xB7 restart hum to use it`;
|
|
88655
88769
|
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
88770
|
if (readState(env3).version === latest) return `hum ${latest} is still installing in the background (${path2.join(humHome2(env3), "update.log")} has the details)`;
|
|
88657
88771
|
return "";
|
|
@@ -88673,45 +88787,54 @@ function watchReady(mine, latest, onReady, { env: env3 = process.env, layout: la
|
|
|
88673
88787
|
if (t.unref) t.unref();
|
|
88674
88788
|
return () => clearInterval(t);
|
|
88675
88789
|
}
|
|
88676
|
-
function updateNow(layout2 = installLayout()) {
|
|
88790
|
+
async function updateNow(layout2 = installLayout(), { mine = MINE, latest = latestVersion, install = installVersion, write = (m) => process.stdout.write(m) } = {}) {
|
|
88677
88791
|
if (layout2.kind === "native") {
|
|
88678
88792
|
const [bin, args2] = installerArgv();
|
|
88679
88793
|
return spawnSync2(bin, args2, { stdio: "inherit", env: { ...process.env, HUM_DIST: dist() } }).status ?? 1;
|
|
88680
88794
|
}
|
|
88681
88795
|
if (layout2.kind === "python") {
|
|
88682
88796
|
const r2 = spawnSync2(win2() ? "uv.exe" : "uv", ["tool", "upgrade", "hum-cli"], { stdio: "inherit", windowsHide: true });
|
|
88683
|
-
if (r2.error || r2.status !== 0)
|
|
88797
|
+
if (r2.error || r2.status !== 0) write(`update with your package manager: ${updateCommand(layout2)}
|
|
88684
88798
|
`);
|
|
88685
88799
|
return r2.error ? 1 : r2.status ?? 1;
|
|
88686
88800
|
}
|
|
88687
|
-
const
|
|
88688
|
-
|
|
88801
|
+
const v = await latest();
|
|
88802
|
+
if (!v) {
|
|
88803
|
+
write(`could not read the latest release from ${dist()}
|
|
88804
|
+
`);
|
|
88805
|
+
return 1;
|
|
88806
|
+
}
|
|
88807
|
+
if (mine && !newer(v, mine)) {
|
|
88808
|
+
write(`hum ${mine} is the latest
|
|
88809
|
+
`);
|
|
88810
|
+
return 0;
|
|
88811
|
+
}
|
|
88812
|
+
const r = install(v, { say: (m) => write(`hum: ${m}
|
|
88813
|
+
`) });
|
|
88814
|
+
if (!r.ok) write(`hum: ${r.error}
|
|
88815
|
+
`);
|
|
88816
|
+
return r.ok ? 0 : 1;
|
|
88689
88817
|
}
|
|
88690
|
-
var dist, humHome2, win2,
|
|
88818
|
+
var dist, humHome2, win2, updateCommand, readyVersion, installerScript, stateFile, readState, writeState;
|
|
88691
88819
|
var init_update = __esm({
|
|
88692
88820
|
"src/update.js"() {
|
|
88821
|
+
init_install();
|
|
88693
88822
|
init_install();
|
|
88694
88823
|
dist = (env3 = process.env) => (env3.HUM_DIST || "https://humboldt.metaphi.ai").replace(/\/+$/, "");
|
|
88695
88824
|
humHome2 = (env3 = process.env) => env3.HUM_HOME || path2.join(os4.homedir(), ".hum");
|
|
88696
88825
|
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
88826
|
updateCommand = (layout2 = installLayout(), platform2 = process.platform) => {
|
|
88705
88827
|
if (layout2.kind === "native") return platform2 === "win32" ? `irm ${dist()}/install.ps1 | iex` : `curl -fsSL ${dist()}/install.sh | sh`;
|
|
88706
88828
|
if (layout2.kind === "python") return "uv tool upgrade hum-cli (or: pip install -U hum-cli)";
|
|
88707
88829
|
return "npm i -g @metaphi-ai/hum@latest";
|
|
88708
88830
|
};
|
|
88709
|
-
readyVersion = (layout2, version,
|
|
88831
|
+
readyVersion = (layout2, version, env3 = process.env) => {
|
|
88710
88832
|
if (!version) return "";
|
|
88711
88833
|
if (layout2.kind === "native") return fs4.existsSync(path2.join(layout2.base, version, layout2.exe)) ? version : "";
|
|
88712
|
-
if (layout2.kind === "npm") return
|
|
88834
|
+
if (layout2.kind === "npm") return fs4.existsSync(readyFile(env3, version)) ? version : "";
|
|
88713
88835
|
return "";
|
|
88714
88836
|
};
|
|
88837
|
+
installerScript = () => fileURLToPath(new URL("./install.mjs", import.meta.url));
|
|
88715
88838
|
stateFile = (env3 = process.env) => path2.join(humHome2(env3), "update.json");
|
|
88716
88839
|
readState = (env3 = process.env) => {
|
|
88717
88840
|
try {
|
|
@@ -88774,12 +88897,12 @@ function siblingCore(execPath = process.execPath) {
|
|
|
88774
88897
|
const p = path3.join(dir, "core", win3 ? "hum-core.exe" : "hum-core");
|
|
88775
88898
|
return exists(p) ? p : null;
|
|
88776
88899
|
}
|
|
88777
|
-
function homeCore(env3 = process.env) {
|
|
88778
|
-
|
|
88779
|
-
const py =
|
|
88900
|
+
function homeCore(env3 = process.env, version = MINE) {
|
|
88901
|
+
if (!version) return null;
|
|
88902
|
+
const py = corePython(env3, version);
|
|
88780
88903
|
return exists(py) ? py : null;
|
|
88781
88904
|
}
|
|
88782
|
-
function coreCandidates(env3 = process.env) {
|
|
88905
|
+
function coreCandidates(env3 = process.env, version = MINE) {
|
|
88783
88906
|
const out = [];
|
|
88784
88907
|
if (env3.HUM_CORE) {
|
|
88785
88908
|
const [bin, ...args2] = env3.HUM_CORE.split(" ");
|
|
@@ -88787,8 +88910,8 @@ function coreCandidates(env3 = process.env) {
|
|
|
88787
88910
|
}
|
|
88788
88911
|
const sib = siblingCore();
|
|
88789
88912
|
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/
|
|
88913
|
+
const home = homeCore(env3, version);
|
|
88914
|
+
if (home) out.push({ bin: home, args: ["-m", "hum.cli", "core"], where: "HUM_HOME/versions" });
|
|
88792
88915
|
const py = corePython2();
|
|
88793
88916
|
if (py) out.push({ bin: py, args: ["-m", "hum.cli", "core"], where: "the interpreter beside it" });
|
|
88794
88917
|
out.push({ bin: "hum-core", args: [], where: "PATH" });
|
|
@@ -88805,9 +88928,9 @@ function coreCommand(argv, candidates = coreCandidates()) {
|
|
|
88805
88928
|
}
|
|
88806
88929
|
return null;
|
|
88807
88930
|
}
|
|
88808
|
-
function candidateVersion(c, { env: env3 = process.env, runImpl = spawnSync3 } = {}) {
|
|
88931
|
+
function candidateVersion(c, { env: env3 = process.env, runImpl = spawnSync3, version = MINE } = {}) {
|
|
88809
88932
|
if (!c || !c.bin) return null;
|
|
88810
|
-
if (c.where === "HUM_HOME/
|
|
88933
|
+
if (c.where === "HUM_HOME/versions") return installedVersion(env3, version);
|
|
88811
88934
|
const interp = c.args.length >= 3 && c.args[c.args.length - 3] === "-m" && c.args[c.args.length - 2] === "hum.cli";
|
|
88812
88935
|
let r;
|
|
88813
88936
|
try {
|
|
@@ -88832,10 +88955,10 @@ function clientEnv() {
|
|
|
88832
88955
|
platform: process.platform,
|
|
88833
88956
|
arch: process.arch,
|
|
88834
88957
|
terminal: process.env.TERM_PROGRAM || (process.env.WT_SESSION ? "Windows Terminal" : process.env.TERM || ""),
|
|
88835
|
-
tui: true ? "0.2.
|
|
88958
|
+
tui: true ? "0.2.11" : ""
|
|
88836
88959
|
};
|
|
88837
88960
|
}
|
|
88838
|
-
function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.
|
|
88961
|
+
function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.11" : "" } = {}) {
|
|
88839
88962
|
const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
|
|
88840
88963
|
const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
|
|
88841
88964
|
if (!refused) {
|
|
@@ -89658,10 +89781,12 @@ async function diagnose({
|
|
|
89658
89781
|
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
89782
|
if (layout2.kind === "npm") {
|
|
89660
89783
|
const st = readInstallState(env3);
|
|
89661
|
-
const stamp = installedVersion(env3, runImpl);
|
|
89784
|
+
const stamp = installedVersion(env3, mine, runImpl);
|
|
89662
89785
|
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)));
|
|
89786
|
+
else if (!stamp) checks.push(check2("fail", `nothing installed under ${coreDir(env3, mine)}`, npmFix2(mine)));
|
|
89787
|
+
else checks.push(check2(stamp === mine ? "ok" : "warn", `${coreDir(env3, mine)} holds ${stamp}`, stamp === mine ? "" : npmFix2(mine)));
|
|
89788
|
+
const ready = readyVersions(env3);
|
|
89789
|
+
if (ready.length) checks.push(check2("ok", `installed here: ${ready.join(", ")} (the newest starts next)`));
|
|
89665
89790
|
}
|
|
89666
89791
|
if (layout2.kind === "native") {
|
|
89667
89792
|
const sib = path6.join(layout2.dir, "core", isWin(platform2) ? "hum-core.exe" : "hum-core");
|
|
@@ -89686,7 +89811,7 @@ async function diagnose({
|
|
|
89686
89811
|
else if (latest) checks.push(check2("ok", `${mine} is the latest release`));
|
|
89687
89812
|
sections.push({ key: "updates", title: "Updates", checks });
|
|
89688
89813
|
}
|
|
89689
|
-
const interp = running && running.args.length >= 3 && running.args[running.args.length - 2] === "hum.cli" ? running.bin : exists2(corePython(env3)) ? corePython(env3) : null;
|
|
89814
|
+
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
89815
|
let toolServers = null;
|
|
89691
89816
|
{
|
|
89692
89817
|
const checks = [];
|
|
@@ -90291,7 +90416,7 @@ var input_default = MultilineInput;
|
|
|
90291
90416
|
|
|
90292
90417
|
// src/app.jsx
|
|
90293
90418
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
90294
|
-
var
|
|
90419
|
+
var MINE2 = true ? "0.2.11" : "";
|
|
90295
90420
|
var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
|
|
90296
90421
|
var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
|
|
90297
90422
|
var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
|
|
@@ -90679,7 +90804,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
|
|
|
90679
90804
|
(ev.questions || []).forEach(addAsk);
|
|
90680
90805
|
if (ev.fresh) append({ kind: "wordmark" });
|
|
90681
90806
|
setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
|
|
90682
|
-
append({ kind: "banner", lines: bannerLines(ev, homeRel,
|
|
90807
|
+
append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE2), instruction: ev.session ? ev.instruction : null });
|
|
90683
90808
|
if (ev.note) append({ kind: "warn", text: ev.note });
|
|
90684
90809
|
setGoal(ev.goal_state && ev.goal_state.text ? ev.goal_state : ev.goal ? { text: ev.goal, status: "active", exchanges: 0 } : null);
|
|
90685
90810
|
if (ev.goal_state && ev.goal_state.text) append({ kind: "info", text: goalLine(ev.goal_state) });
|
|
@@ -91053,7 +91178,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
|
|
|
91053
91178
|
const noticedRef = (0, import_react36.useRef)("");
|
|
91054
91179
|
(0, import_react36.useEffect)(() => {
|
|
91055
91180
|
if (!latest) return void 0;
|
|
91056
|
-
const mine =
|
|
91181
|
+
const mine = MINE2 || latest.version || "0.0.0";
|
|
91057
91182
|
const want = latest.latest_version || "";
|
|
91058
91183
|
const line = update(mine, { running: latest.version || "", latest: want });
|
|
91059
91184
|
if (line && noticedRef.current !== line) {
|
|
@@ -92116,33 +92241,33 @@ init_update();
|
|
|
92116
92241
|
init_install();
|
|
92117
92242
|
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
92118
92243
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
92119
|
-
var
|
|
92244
|
+
var MINE3 = true ? "0.2.11" : "0.0.0";
|
|
92120
92245
|
var layout = installLayout();
|
|
92121
92246
|
function completeInstall() {
|
|
92122
|
-
if (layout.kind !== "npm" || !needsInstall(
|
|
92247
|
+
if (layout.kind !== "npm" || !needsInstall(MINE3)) return;
|
|
92123
92248
|
const say = (m) => process.stderr.write(`hum: ${m}
|
|
92124
92249
|
`);
|
|
92125
|
-
say(`updating to ${
|
|
92126
|
-
const r = installCore(
|
|
92127
|
-
if (!r.ok) say(`the update did not finish: ${r.error} \xB7 ${npmFix(
|
|
92250
|
+
say(`updating to ${MINE3} \u2026`);
|
|
92251
|
+
const r = installCore(MINE3, { say });
|
|
92252
|
+
if (!r.ok) say(`the update did not finish: ${r.error} \xB7 ${npmFix(MINE3)}`);
|
|
92128
92253
|
}
|
|
92129
92254
|
var CORE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "persona", "ps", "stop", "hooks", "core"]);
|
|
92130
92255
|
var argv0 = process.argv.slice(2);
|
|
92131
92256
|
if (argv0[0] === "--version" || argv0[0] === "-V") {
|
|
92132
|
-
process.stdout.write(`hum ${
|
|
92257
|
+
process.stdout.write(`hum ${MINE3}
|
|
92133
92258
|
`);
|
|
92134
92259
|
if (layout.kind === "npm") {
|
|
92135
92260
|
const r = runningVersion();
|
|
92136
|
-
const drift = mismatchLine(
|
|
92261
|
+
const drift = mismatchLine(MINE3, r ? r.version : "", { layout });
|
|
92137
92262
|
if (drift) process.stdout.write(`${drift}
|
|
92138
92263
|
`);
|
|
92139
92264
|
}
|
|
92140
92265
|
process.exit(0);
|
|
92141
92266
|
}
|
|
92142
|
-
if (argv0[0] === "update") process.exit(updateNow());
|
|
92267
|
+
if (argv0[0] === "update") process.exit(await updateNow());
|
|
92143
92268
|
if (argv0[0] === "doctor") {
|
|
92144
92269
|
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
92145
|
-
process.exit(await doctor2({ json: argv0.includes("--json"), mine:
|
|
92270
|
+
process.exit(await doctor2({ json: argv0.includes("--json"), mine: MINE3, layout }));
|
|
92146
92271
|
}
|
|
92147
92272
|
if (CORE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--json") || wantsPlain(argv0)) {
|
|
92148
92273
|
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,9 +120,9 @@ 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);
|
|
@@ -101,20 +130,20 @@ function installCore(version, { env = process.env, say = (m) => console.log(`hum
|
|
|
101
130
|
const pipIn = () => (runImpl(u, ["pip", "install", "--quiet", "--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,133 @@ 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
|
+
function installVersion(version, { env = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now() } = {}) {
|
|
218
|
+
if (!isVersion(version)) return { ok: false, error: `not a version: ${version}` };
|
|
219
|
+
try {
|
|
220
|
+
fs.mkdirSync(versionDir(env, version), { recursive: true });
|
|
221
|
+
try {
|
|
222
|
+
fs.unlinkSync(readyFile(env, version));
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
if (!fs.existsSync(entryFile(env, version))) {
|
|
226
|
+
const p = installPackage(version, { env, say, runImpl });
|
|
227
|
+
if (!p.ok) return p;
|
|
228
|
+
}
|
|
229
|
+
if (installedVersion(env, version, runImpl) !== version) {
|
|
230
|
+
const c = installCore(version, { env, say, runImpl, now });
|
|
231
|
+
if (!c.ok) return { ok: false, error: c.error };
|
|
232
|
+
}
|
|
233
|
+
fs.writeFileSync(readyFile(env, version), `${version}
|
|
234
|
+
`);
|
|
235
|
+
say(`hum ${version} is ready; the next hum you start is ${version}`);
|
|
236
|
+
prune(env, { say });
|
|
237
|
+
return { ok: true, error: null };
|
|
238
|
+
} catch (e) {
|
|
239
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (process.argv[1] && /install\.mjs$/.test(process.argv[1]) && process.argv[2] === "install") {
|
|
243
|
+
const log = path.join(humHome(), "update.log");
|
|
244
|
+
const say = (m) => {
|
|
245
|
+
try {
|
|
246
|
+
fs.appendFileSync(log, `${(/* @__PURE__ */ new Date()).toISOString()} ${m}
|
|
247
|
+
`);
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const runLogged = (cmd, args, opts = {}) => {
|
|
252
|
+
const r2 = run(cmd, args, { ...opts, stdio: "pipe" });
|
|
253
|
+
if (r2 && r2.status !== 0 && (r2.stderr || r2.stdout)) say(String(r2.stderr || r2.stdout).trim().split(/\r?\n/).slice(-5).join("\n"));
|
|
254
|
+
return r2;
|
|
255
|
+
};
|
|
256
|
+
const r = installVersion(process.argv[3] || "", { say, runImpl: runLogged });
|
|
257
|
+
if (!r.ok) say(`hum ${process.argv[3]} did not install: ${r.error}`);
|
|
258
|
+
process.exit(r.ok ? 0 : 1);
|
|
259
|
+
}
|
|
130
260
|
export {
|
|
131
261
|
ASK_SSL,
|
|
132
262
|
ASK_VERSION,
|
|
263
|
+
MINE,
|
|
133
264
|
NPM_FIX,
|
|
265
|
+
chosenEntry,
|
|
134
266
|
coreDir,
|
|
135
267
|
corePython,
|
|
268
|
+
entryFile,
|
|
136
269
|
humHome,
|
|
137
270
|
importedVersion,
|
|
138
271
|
installCore,
|
|
272
|
+
installPackage,
|
|
273
|
+
installVersion,
|
|
139
274
|
installedVersion,
|
|
140
275
|
needsInstall,
|
|
276
|
+
newer,
|
|
141
277
|
npmFix,
|
|
278
|
+
pkgDir,
|
|
279
|
+
prune,
|
|
142
280
|
readInstallState,
|
|
281
|
+
readyFile,
|
|
282
|
+
readyVersions,
|
|
143
283
|
sslAdvice,
|
|
144
284
|
sslBlocked,
|
|
145
|
-
trustedPython
|
|
285
|
+
trustedPython,
|
|
286
|
+
versionDir,
|
|
287
|
+
versionsDir
|
|
146
288
|
};
|
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
|
}
|