@metaphi-ai/hum 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -84571,18 +84571,44 @@ function enginePython(dirs = uvToolDirs()) {
84571
84571
  }
84572
84572
  return null;
84573
84573
  }
84574
+ function siblingEngine(execPath = process.execPath) {
84575
+ let dir;
84576
+ try {
84577
+ dir = path2.dirname(fs3.realpathSync(execPath));
84578
+ } catch {
84579
+ return null;
84580
+ }
84581
+ const p = path2.join(dir, "engine", win ? "hum-engine.exe" : "hum-engine");
84582
+ return exists(p) ? p : null;
84583
+ }
84584
+ function homeEngine(env3 = process.env) {
84585
+ const home = env3.HUM_HOME || path2.join(os4.homedir(), ".hum");
84586
+ const py = win ? path2.join(home, "engine", "Scripts", "python.exe") : path2.join(home, "engine", "bin", "python");
84587
+ return exists(py) ? py : null;
84588
+ }
84574
84589
  function engineCandidates(env3 = process.env) {
84575
84590
  const out = [];
84576
84591
  if (env3.HUM_ENGINE) {
84577
84592
  const [bin, ...args2] = env3.HUM_ENGINE.split(" ");
84578
84593
  out.push({ bin, args: args2, where: "HUM_ENGINE" });
84579
84594
  }
84595
+ const sib = siblingEngine();
84596
+ if (sib) out.push({ bin: sib, args: ["engine"], where: "beside hum" });
84597
+ const home = homeEngine(env3);
84598
+ if (home) out.push({ bin: home, args: ["-m", "hum.cli", "engine"], where: "HUM_HOME/engine" });
84580
84599
  const py = enginePython();
84581
84600
  if (py) out.push({ bin: py, args: ["-m", "hum.cli", "engine"], where: "the engine's interpreter" });
84582
84601
  out.push({ bin: "hum-engine", args: [], where: "PATH" });
84583
84602
  out.push({ bin: path2.join(os4.homedir(), ".local", "bin", win ? "hum-engine.exe" : "hum-engine"), args: [], where: "uv's bin dir" });
84584
84603
  return out;
84585
84604
  }
84605
+ function engineCommand(argv, candidates = engineCandidates()) {
84606
+ for (const c of candidates) {
84607
+ if (c.args[c.args.length - 1] !== "engine") continue;
84608
+ return { bin: c.bin, args: [...c.args.slice(0, -1), ...argv], where: c.where };
84609
+ }
84610
+ return null;
84611
+ }
84586
84612
  function startFailure(failures) {
84587
84613
  const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
84588
84614
  if (!refused) {
@@ -84746,6 +84772,27 @@ var Engine = class {
84746
84772
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
84747
84773
  import fs4 from "node:fs";
84748
84774
  import path3 from "node:path";
84775
+ import { spawnSync as spawnSync2 } from "node:child_process";
84776
+ var ENGINE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "ps", "stop", "hooks", "engine"]);
84777
+ var argv0 = process.argv.slice(2);
84778
+ if (argv0[0] === "--version" || argv0[0] === "-V") {
84779
+ process.stdout.write(`hum ${true ? "0.1.10" : "0.0.0"}
84780
+ `);
84781
+ process.exit(0);
84782
+ }
84783
+ if (ENGINE_COMMANDS.has(argv0[0])) {
84784
+ const cmd = engineCommand(argv0);
84785
+ if (!cmd) {
84786
+ process.stderr.write(startFailure([]) + "\n");
84787
+ process.exit(1);
84788
+ }
84789
+ const r = spawnSync2(cmd.bin, cmd.args, { stdio: "inherit", windowsHide: true });
84790
+ if (r.error) {
84791
+ process.stderr.write(startFailure([{ bin: cmd.bin, error: r.error }]) + "\n");
84792
+ process.exit(1);
84793
+ }
84794
+ process.exit(r.status === null ? 1 : r.status);
84795
+ }
84749
84796
  function parseArgs(argv) {
84750
84797
  const a = { task: null, resume: null, cwd: process.cwd(), images: [] };
84751
84798
  for (let i = 0; i < argv.length; i += 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Hum (हम): a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -1,23 +1,58 @@
1
- // Make sure the engine is installed: `hum-engine` on PATH (uv tool install hum-cli).
2
- // Quiet when it already is; installs uv first when it is missing; never fails the npm install.
3
- import { execSync, spawnSync } from 'node:child_process';
1
+ // The engine, installed beside the person's Hum data: ~/.hum/engine (HUM_HOME/engine), a plain
2
+ // Python environment holding hum-cli at this package's version. No launcher shims are written
3
+ // anywhere `hum` starts the engine through the environment's own interpreter — so nothing of
4
+ // ours lands in ~/.local/bin, and nothing there can shadow the `hum` npm installed.
5
+ // uv creates the environment (and fetches a Python if the machine has none); it is installed
6
+ // when missing. Quiet when the engine is already at this version; never fails the npm install.
7
+ import { execFileSync, spawnSync } from 'node:child_process';
8
+ import fs from 'node:fs';
4
9
  import os from 'node:os';
5
10
  import path from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
6
12
 
7
- const which = (cmd) => spawnSync(process.platform === 'win32' ? 'where' : 'which', [cmd], { stdio: 'ignore' }).status === 0;
8
- const local = path.join(os.homedir(), '.local', 'bin');
9
- const sh = (cmd) => { try { execSync(cmd, { stdio: 'inherit', env: { ...process.env, PATH: `${local}${path.delimiter}${process.env.PATH || ''}` } }); return true; } catch { return false; } };
13
+ const win = process.platform === 'win32';
14
+ const here = path.dirname(fileURLToPath(import.meta.url));
15
+ const version = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json'), 'utf8')).version;
16
+ const home = process.env.HUM_HOME || path.join(os.homedir(), '.hum');
17
+ const env = path.join(home, 'engine');
18
+ const python = win ? path.join(env, 'Scripts', 'python.exe') : path.join(env, 'bin', 'python');
19
+ const localBin = path.join(os.homedir(), '.local', 'bin');
20
+ const say = (m) => console.log(`hum: ${m}`);
10
21
 
11
- if (which('hum-engine') || spawnSync(path.join(local, 'hum-engine'), ['--help'], { stdio: 'ignore' }).status === 0) {
12
- process.exit(0);
13
- }
14
- console.log('hum: installing the engine (uv tool install hum-cli) …');
15
- if (!which('uv') && spawnSync(path.join(local, 'uv'), ['--version'], { stdio: 'ignore' }).status !== 0) {
16
- const ok = process.platform === 'win32'
17
- ? sh('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"')
18
- : sh('curl -LsSf https://astral.sh/uv/install.sh | sh');
19
- if (!ok) { console.log('hum: could not install uv; install it from https://astral.sh/uv then run: uv tool install hum-cli'); process.exit(0); }
20
- }
21
- if (!sh('uv tool install --quiet hum-cli')) {
22
- console.log('hum: engine install failed; run manually: uv tool install hum-cli');
22
+ const run = (cmd, args, opts = {}) => spawnSync(cmd, args, { encoding: 'utf8', windowsHide: true, ...opts });
23
+ const uvNames = ['uv', path.join(localBin, win ? 'uv.exe' : 'uv')];
24
+ const uv = () => uvNames.find((u) => run(u, ['--version']).status === 0);
25
+
26
+ const installed = () => {
27
+ const r = run(python, ['-c', 'import hum; print(hum.__version__)']);
28
+ return r.status === 0 ? r.stdout.trim() : null;
29
+ };
30
+
31
+ try {
32
+ if (installed() === version) process.exit(0);
33
+ let u = uv();
34
+ if (!u) {
35
+ say('installing uv (it creates the engine\'s Python environment) …');
36
+ const r = win
37
+ ? run('powershell', ['-ExecutionPolicy', 'ByPass', '-c', 'irm https://astral.sh/uv/install.ps1 | iex'], { stdio: 'inherit' })
38
+ : run('sh', ['-c', 'curl -LsSf https://astral.sh/uv/install.sh | sh'], { stdio: 'inherit' });
39
+ u = r.status === 0 ? uv() : null;
40
+ if (!u) { say('could not install uv; install it from https://astral.sh/uv and run: npm rebuild -g @metaphi-ai/hum'); process.exit(0); }
41
+ }
42
+ say(`installing the engine ${version} into ${env} …`);
43
+ fs.mkdirSync(home, { recursive: true });
44
+ if (run(u, ['venv', '--quiet', '--python', '3.12', env], { stdio: 'inherit' }).status !== 0) throw new Error('uv venv failed');
45
+ if (run(u, ['pip', 'install', '--quiet', '--python', python, `hum-cli==${version}`], { stdio: 'inherit' }).status !== 0) throw new Error('uv pip install failed');
46
+ if (installed() !== version) throw new Error('the engine did not import after install');
47
+
48
+ // An earlier version installed the engine with `uv tool install`, which wrote launcher shims
49
+ // (hum, hum-engine) into ~/.local/bin — where they shadow the `hum` npm installed, and where a
50
+ // managed Windows machine refuses them. That engine is redundant now; take it and its shims out.
51
+ const list = run(u, ['tool', 'list']);
52
+ if (list.status === 0 && /^hum-cli\b/m.test(list.stdout)) {
53
+ if (run(u, ['tool', 'uninstall', 'hum-cli']).status === 0) say(`removed the uv install of hum-cli and its shims in ${localBin}; the engine lives in ${env} now`);
54
+ }
55
+ say(`engine ${version} ready`);
56
+ } catch (e) {
57
+ say(`engine install failed (${e.message}); run: npm rebuild -g @metaphi-ai/hum`);
23
58
  }