@metaphi-ai/hum 0.1.9 → 0.1.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/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) {
@@ -84642,11 +84668,15 @@ function attempt({ bin, args: args2 }, cwd2, { task, images, resume }) {
84642
84668
  settle(() => resolve(rec));
84643
84669
  return;
84644
84670
  }
84671
+ if (rec && rec.error) {
84672
+ settle(() => reject({ failed: rec.error }));
84673
+ return;
84674
+ }
84645
84675
  if (died && !rec) {
84646
84676
  settle(() => reject({ died: logPath }));
84647
84677
  return;
84648
84678
  }
84649
- if (Date.now() - t0 > 25e3) {
84679
+ if (Date.now() - t0 > 9e4) {
84650
84680
  settle(() => reject({ timeout: true }));
84651
84681
  return;
84652
84682
  }
@@ -84655,6 +84685,20 @@ function attempt({ bin, args: args2 }, cwd2, { task, images, resume }) {
84655
84685
  poll();
84656
84686
  });
84657
84687
  }
84688
+ function failureMessage(error) {
84689
+ return error.message + (error.hint ? `
84690
+ ${error.hint}` : "");
84691
+ }
84692
+ function diedMessage(logPath, text = null) {
84693
+ let tail2 = "";
84694
+ try {
84695
+ tail2 = (text ?? fs3.readFileSync(logPath, "utf8")).trim().split("\n").slice(-3).join("\n").trim();
84696
+ } catch {
84697
+ }
84698
+ return `the engine did not start${tail2 ? `:
84699
+ ${tail2}` : ""}
84700
+ (its log: ${logPath})`;
84701
+ }
84658
84702
  async function spawnEngine(cwd2, { task = null, images = [], resume = null, candidates = engineCandidates() } = {}) {
84659
84703
  const failures = [];
84660
84704
  for (const cand of candidates) {
@@ -84666,7 +84710,8 @@ async function spawnEngine(cwd2, { task = null, images = [], resume = null, cand
84666
84710
  failures.push({ ...cand, error: f.spawn });
84667
84711
  continue;
84668
84712
  }
84669
- if (f && f.died) throw new EngineError(`the engine did not start (see ${f.died})`);
84713
+ if (f && f.failed) throw new EngineError(failureMessage(f.failed));
84714
+ if (f && f.died) throw new EngineError(diedMessage(f.died));
84670
84715
  if (f && f.timeout) throw new EngineError("the engine did not start in time");
84671
84716
  throw f;
84672
84717
  }
@@ -84746,6 +84791,27 @@ var Engine = class {
84746
84791
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
84747
84792
  import fs4 from "node:fs";
84748
84793
  import path3 from "node:path";
84794
+ import { spawnSync as spawnSync2 } from "node:child_process";
84795
+ var ENGINE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "ps", "stop", "hooks", "engine"]);
84796
+ var argv0 = process.argv.slice(2);
84797
+ if (argv0[0] === "--version" || argv0[0] === "-V") {
84798
+ process.stdout.write(`hum ${true ? "0.1.11" : "0.0.0"}
84799
+ `);
84800
+ process.exit(0);
84801
+ }
84802
+ if (ENGINE_COMMANDS.has(argv0[0])) {
84803
+ const cmd = engineCommand(argv0);
84804
+ if (!cmd) {
84805
+ process.stderr.write(startFailure([]) + "\n");
84806
+ process.exit(1);
84807
+ }
84808
+ const r = spawnSync2(cmd.bin, cmd.args, { stdio: "inherit", windowsHide: true });
84809
+ if (r.error) {
84810
+ process.stderr.write(startFailure([{ bin: cmd.bin, error: r.error }]) + "\n");
84811
+ process.exit(1);
84812
+ }
84813
+ process.exit(r.status === null ? 1 : r.status);
84814
+ }
84749
84815
  function parseArgs(argv) {
84750
84816
  const a = { task: null, resume: null, cwd: process.cwd(), images: [] };
84751
84817
  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.11",
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
  }