@metaphi-ai/hum 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +129 -59
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -84524,7 +84524,7 @@ import net from "node:net";
84524
84524
  import os4 from "node:os";
84525
84525
  import path2 from "node:path";
84526
84526
  import crypto from "node:crypto";
84527
- import { spawn } from "node:child_process";
84527
+ import { spawn, spawnSync } from "node:child_process";
84528
84528
  var runDir = () => path2.join(process.env.HUM_HOME || path2.join(os4.homedir(), ".hum"), "run");
84529
84529
  var readRun = (id) => {
84530
84530
  try {
@@ -84535,74 +84535,144 @@ var readRun = (id) => {
84535
84535
  };
84536
84536
  var EngineError = class extends Error {
84537
84537
  };
84538
- var ENGINE_CANDIDATES = [
84539
- process.env.HUM_ENGINE,
84540
- // explicit: a command to run (e.g. `python -m hum.cli engine`)
84541
- "hum-engine",
84542
- // uv tool install hum-cli
84543
- path2.join(os4.homedir(), ".local", "bin", process.platform === "win32" ? "hum-engine.exe" : "hum-engine")
84544
- // uv's bin dir, off PATH
84545
- ];
84546
- function spawnEngine(cwd2, { task = null, images = [], resume = null } = {}) {
84538
+ var win = process.platform === "win32";
84539
+ var exists = (p) => {
84540
+ try {
84541
+ fs3.accessSync(p);
84542
+ return true;
84543
+ } catch {
84544
+ return false;
84545
+ }
84546
+ };
84547
+ function uvToolDirs() {
84548
+ const dirs = [];
84549
+ if (process.env.UV_TOOL_DIR) dirs.push(process.env.UV_TOOL_DIR);
84550
+ if (win) {
84551
+ for (const base of [process.env.APPDATA, process.env.LOCALAPPDATA]) if (base) dirs.push(path2.join(base, "uv", "tools"));
84552
+ } else dirs.push(path2.join(process.env.XDG_DATA_HOME || path2.join(os4.homedir(), ".local", "share"), "uv", "tools"));
84553
+ if (!dirs.some(exists)) {
84554
+ for (const uv of ["uv", path2.join(os4.homedir(), ".local", "bin", win ? "uv.exe" : "uv")]) {
84555
+ try {
84556
+ const r = spawnSync(uv, ["tool", "dir"], { encoding: "utf8", windowsHide: true });
84557
+ if (r.status === 0 && r.stdout.trim()) {
84558
+ dirs.push(r.stdout.trim());
84559
+ break;
84560
+ }
84561
+ } catch {
84562
+ }
84563
+ }
84564
+ }
84565
+ return dirs;
84566
+ }
84567
+ function enginePython(dirs = uvToolDirs()) {
84568
+ for (const dir of dirs) for (const name of ["hum-cli", "hum"]) {
84569
+ const py = win ? path2.join(dir, name, "Scripts", "python.exe") : path2.join(dir, name, "bin", "python");
84570
+ if (exists(py)) return py;
84571
+ }
84572
+ return null;
84573
+ }
84574
+ function engineCandidates(env3 = process.env) {
84575
+ const out = [];
84576
+ if (env3.HUM_ENGINE) {
84577
+ const [bin, ...args2] = env3.HUM_ENGINE.split(" ");
84578
+ out.push({ bin, args: args2, where: "HUM_ENGINE" });
84579
+ }
84580
+ const py = enginePython();
84581
+ if (py) out.push({ bin: py, args: ["-m", "hum.cli", "engine"], where: "the engine's interpreter" });
84582
+ out.push({ bin: "hum-engine", args: [], where: "PATH" });
84583
+ out.push({ bin: path2.join(os4.homedir(), ".local", "bin", win ? "hum-engine.exe" : "hum-engine"), args: [], where: "uv's bin dir" });
84584
+ return out;
84585
+ }
84586
+ function startFailure(failures) {
84587
+ const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
84588
+ if (!refused) {
84589
+ return "Hum's engine is not installed. Run: uv tool install hum-cli (or set HUM_ENGINE to the command that starts it)";
84590
+ }
84591
+ const what = refused.error.code || refused.error.message;
84592
+ const lines = [
84593
+ `Hum's engine is installed (${refused.bin}) but this machine would not start it: ${what}.`
84594
+ ];
84595
+ if (win) {
84596
+ lines.push("On a managed Windows machine that is usually Device Guard / WDAC refusing an executable it does not know.");
84597
+ lines.push(`To see the policy's own message, run: "${refused.bin}" --help`);
84598
+ const dir = uvToolDirs()[0];
84599
+ lines.push(`If uv's environment is elsewhere, point Hum at its interpreter: set HUM_ENGINE=${path2.join(dir || "<uv tool dir>", "hum-cli", "Scripts", "python.exe")} -m hum.cli engine`);
84600
+ } else {
84601
+ lines.push('Set HUM_ENGINE to a command that starts it, e.g. HUM_ENGINE="python -m hum.cli engine"');
84602
+ }
84603
+ return lines.join("\n");
84604
+ }
84605
+ function attempt({ bin, args: args2 }, cwd2, { task, images, resume }) {
84547
84606
  return new Promise((resolve, reject) => {
84548
- const tryNext = (i) => {
84549
- const cmd = ENGINE_CANDIDATES[i];
84550
- if (cmd === void 0) {
84551
- reject(new EngineError(
84552
- "Hum's engine is not installed. Run: uv tool install hum-cli (or set HUM_ENGINE to the command that starts it)"
84553
- ));
84607
+ const runId = crypto.randomBytes(6).toString("hex");
84608
+ fs3.mkdirSync(runDir(), { recursive: true });
84609
+ const logPath = path2.join(runDir(), `${runId}.log`);
84610
+ const log = fs3.openSync(logPath, "a");
84611
+ const argv = [...args2, "-C", cwd2, "--run-id", runId];
84612
+ if (task) argv.push("--task", task);
84613
+ for (const p of images) argv.push("--image", p);
84614
+ if (resume) argv.push("--resume", resume);
84615
+ let settled = false;
84616
+ const settle = (fn) => {
84617
+ if (!settled) {
84618
+ settled = true;
84619
+ fn();
84620
+ }
84621
+ };
84622
+ let child;
84623
+ try {
84624
+ child = spawn(bin, argv, { stdio: ["ignore", log, log], detached: true, windowsHide: true });
84625
+ } catch (e) {
84626
+ fs3.closeSync(log);
84627
+ reject({ spawn: e });
84628
+ return;
84629
+ }
84630
+ fs3.closeSync(log);
84631
+ let died = false;
84632
+ child.on("error", (e) => settle(() => reject({ spawn: e })));
84633
+ child.on("exit", () => {
84634
+ died = true;
84635
+ });
84636
+ const t0 = Date.now();
84637
+ const poll = () => {
84638
+ if (settled) return;
84639
+ const rec = readRun(runId);
84640
+ if (rec && rec.port) {
84641
+ child.unref();
84642
+ settle(() => resolve(rec));
84554
84643
  return;
84555
84644
  }
84556
- if (!cmd) {
84557
- tryNext(i + 1);
84645
+ if (died && !rec) {
84646
+ settle(() => reject({ died: logPath }));
84558
84647
  return;
84559
84648
  }
84560
- const runId = crypto.randomBytes(6).toString("hex");
84561
- fs3.mkdirSync(runDir(), { recursive: true });
84562
- const log = fs3.openSync(path2.join(runDir(), `${runId}.log`), "a");
84563
- const [bin, ...rest] = cmd.split(" ");
84564
- const args2 = [...rest, "-C", cwd2, "--run-id", runId];
84565
- if (task) args2.push("--task", task);
84566
- for (const p of images) args2.push("--image", p);
84567
- if (resume) args2.push("--resume", resume);
84568
- let child;
84569
- try {
84570
- child = spawn(bin, args2, { stdio: ["ignore", log, log], detached: true, windowsHide: true });
84571
- } catch {
84572
- tryNext(i + 1);
84649
+ if (Date.now() - t0 > 25e3) {
84650
+ settle(() => reject({ timeout: true }));
84573
84651
  return;
84574
84652
  }
84575
- let failed = false;
84576
- child.on("error", () => {
84577
- failed = true;
84578
- tryNext(i + 1);
84579
- });
84580
- child.on("exit", () => {
84581
- failed = true;
84582
- });
84583
- const t0 = Date.now();
84584
- const poll = () => {
84585
- const rec = readRun(runId);
84586
- if (rec && rec.port) {
84587
- child.unref();
84588
- resolve(rec);
84589
- return;
84590
- }
84591
- if (failed && !rec) {
84592
- reject(new EngineError(`the engine did not start (see ${path2.join(runDir(), `${runId}.log`)})`));
84593
- return;
84594
- }
84595
- if (Date.now() - t0 > 25e3) {
84596
- reject(new EngineError("the engine did not start in time"));
84597
- return;
84598
- }
84599
- setTimeout(poll, 50);
84600
- };
84601
- poll();
84653
+ setTimeout(poll, 50);
84602
84654
  };
84603
- tryNext(0);
84655
+ poll();
84604
84656
  });
84605
84657
  }
84658
+ async function spawnEngine(cwd2, { task = null, images = [], resume = null, candidates = engineCandidates() } = {}) {
84659
+ const failures = [];
84660
+ for (const cand of candidates) {
84661
+ if (!cand.bin) continue;
84662
+ try {
84663
+ return await attempt(cand, cwd2, { task, images, resume });
84664
+ } catch (f) {
84665
+ if (f && f.spawn) {
84666
+ failures.push({ ...cand, error: f.spawn });
84667
+ continue;
84668
+ }
84669
+ if (f && f.died) throw new EngineError(`the engine did not start (see ${f.died})`);
84670
+ if (f && f.timeout) throw new EngineError("the engine did not start in time");
84671
+ throw f;
84672
+ }
84673
+ }
84674
+ throw new EngineError(startFailure(failures));
84675
+ }
84606
84676
  var Engine = class {
84607
84677
  constructor(port2) {
84608
84678
  this.port = port2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Hum (हम): a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",