@metaphi-ai/hum 0.1.57 → 0.1.59

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 +171 -60
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -83350,13 +83350,24 @@ function installLayout(execPath = process.execPath, env3 = process.env) {
83350
83350
  }
83351
83351
  return { kind: "native", exe, dir: path2.dirname(real), base: path2.dirname(path2.dirname(real)) };
83352
83352
  }
83353
- function installerArgv(version, platform2 = process.platform) {
83353
+ function packageVersion(entry = process.argv[1]) {
83354
+ try {
83355
+ const dir = path2.dirname(fs3.realpathSync(entry));
83356
+ return JSON.parse(fs3.readFileSync(path2.join(dir, "..", "package.json"), "utf8")).version || "";
83357
+ } catch {
83358
+ return "";
83359
+ }
83360
+ }
83361
+ function installerArgv(version, platform2 = process.platform, layout2 = { kind: "native" }) {
83354
83362
  const base = dist();
83363
+ if (layout2.kind === "npm") {
83364
+ return platform2 === "win32" ? ["cmd.exe", ["/d", "/s", "/c", `npm i -g --ignore-scripts @metaphi-ai/hum@${version || "latest"}`]] : ["/bin/sh", ["-c", `npm i -g --ignore-scripts @metaphi-ai/hum@${version || "latest"}`]];
83365
+ }
83355
83366
  if (platform2 === "win32") return ["powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", `irm ${base}/install.ps1 | iex`]];
83356
83367
  return ["/bin/sh", ["-c", `curl -fsSL "${base}/install.sh" | sh`]];
83357
83368
  }
83358
- function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.now(), spawnImpl = spawn } = {}) {
83359
- if (env3.HUM_NO_AUTO_UPDATE) return false;
83369
+ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.now(), spawnImpl = spawn, layout: layout2 = installLayout(process.execPath, env3), platform: platform2 = process.platform } = {}) {
83370
+ if (env3.HUM_NO_AUTO_UPDATE || layout2.kind === "python") return false;
83360
83371
  const s = readState(env3);
83361
83372
  if (s.version === version && now - (s.started || 0) < 30 * 60 * 1e3) return false;
83362
83373
  const log = path2.join(humHome2(env3), "update.log");
@@ -83366,7 +83377,7 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
83366
83377
  out = fs3.openSync(log, "w");
83367
83378
  } catch {
83368
83379
  }
83369
- const [bin, args2] = installerArgv(version);
83380
+ const [bin, args2] = installerArgv(version, platform2, layout2);
83370
83381
  try {
83371
83382
  const child = spawnImpl(bin, args2, {
83372
83383
  detached: true,
@@ -83375,7 +83386,7 @@ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.no
83375
83386
  env: { ...env3, HUM_VERSION: version, HUM_DIST: dist(env3) }
83376
83387
  });
83377
83388
  child.unref();
83378
- writeState({ version, started: now }, env3);
83389
+ writeState({ ...s, version, started: now }, env3);
83379
83390
  return true;
83380
83391
  } catch {
83381
83392
  return false;
@@ -83390,33 +83401,49 @@ function mismatchLine(mine, running, { env: env3 = process.env, layout: layout2
83390
83401
  return `${head} \xB7 ${fix}`;
83391
83402
  }
83392
83403
  function updateBox(mine, latest, notes = "", { env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3) } = {}) {
83393
- if (env3.HUM_NO_UPDATE_CHECK || !mine || !latest || !newer(latest, mine)) return null;
83394
- return { head: `Update available! ${mine} -> ${latest}`, command: updateCommand(layout2), notes: notes || "" };
83404
+ if (env3.HUM_NO_UPDATE_CHECK || !mine || !latest || !newer(latest, mine) || skipped(latest, env3)) return null;
83405
+ const choices = UPDATE_CHOICES.map((c) => c.key === "later" && (env3.HUM_NO_AUTO_UPDATE || layout2.kind === "python") ? { ...c, desc: "keeps going on this version" } : c);
83406
+ return { head: `Update available! ${mine} -> ${latest}`, latest, command: updateCommand(layout2), notes: notes || "", choices };
83395
83407
  }
83396
- async function updateNotice(mine, { running = "", latest = "", env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3), spawnImpl = spawn } = {}) {
83408
+ async function updateNotice(mine, { running = "", latest = "", env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3) } = {}) {
83397
83409
  const drift = mismatchLine(mine, running, { env: env3, layout: layout2 });
83398
83410
  if (drift) return drift;
83399
- if (env3.HUM_NO_UPDATE_CHECK || !latest || !newer(latest, mine) || layout2.kind !== "native") return "";
83411
+ if (env3.HUM_NO_UPDATE_CHECK || !latest || !newer(latest, mine) || layout2.kind === "python") return "";
83400
83412
  if (readyVersion(layout2, latest)) return `hum ${latest} is ready \xB7 restart hum to use it`;
83401
- if (startBackgroundUpdate(latest, { env: env3, spawnImpl })) return `hum ${latest} is downloading in the background \xB7 it takes effect the next time you start hum`;
83402
83413
  const s = readState(env3);
83403
83414
  if (s.version === latest && !env3.HUM_NO_AUTO_UPDATE) return `hum ${latest} is still installing in the background (${path2.join(humHome2(env3), "update.log")} has the details)`;
83404
83415
  return "";
83405
83416
  }
83417
+ function updateDue(latest, { env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3), now = Date.now() } = {}) {
83418
+ if (!latest || layout2.kind === "python") return !!latest;
83419
+ if (readyVersion(layout2, latest)) return false;
83420
+ const s = readState(env3);
83421
+ return !(s.version === latest && !env3.HUM_NO_AUTO_UPDATE && now - (s.started || 0) < 30 * 60 * 1e3);
83422
+ }
83423
+ function laterNotice(latest, { env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3), spawnImpl = spawn } = {}) {
83424
+ if (startBackgroundUpdate(latest, { env: env3, spawnImpl, layout: layout2 })) return `hum ${latest} is downloading in the background \xB7 it takes effect the next time you start hum`;
83425
+ return "";
83426
+ }
83406
83427
  function updateNow(layout2 = installLayout()) {
83407
83428
  if (layout2.kind === "native") {
83408
83429
  const [bin, args2] = installerArgv();
83409
83430
  return spawnSync2(bin, args2, { stdio: "inherit", env: { ...process.env, HUM_DIST: dist() } }).status ?? 1;
83410
83431
  }
83411
83432
  if (layout2.kind === "python") {
83412
- process.stdout.write(`update with your package manager: ${updateCommand(layout2)}
83433
+ const r2 = spawnSync2(win2() ? "uv.exe" : "uv", ["tool", "upgrade", "hum-cli"], { stdio: "inherit", windowsHide: true });
83434
+ if (r2.error || r2.status !== 0) process.stdout.write(`update with your package manager: ${updateCommand(layout2)}
83413
83435
  `);
83414
- return 0;
83436
+ return r2.error ? 1 : r2.status ?? 1;
83415
83437
  }
83416
83438
  const r = spawnSync2(win2() ? "npm.cmd" : "npm", ["i", "-g", "@metaphi-ai/hum@latest"], { stdio: "inherit", shell: win2() });
83417
83439
  return r.status ?? 1;
83418
83440
  }
83419
- var dist, humHome2, win2, newer, updateCommand, readyVersion, stateFile, readState, writeState;
83441
+ function restart(argv = process.argv.slice(2), platform2 = process.platform) {
83442
+ const w = platform2 === "win32";
83443
+ const r = spawnSync2(w ? "hum.cmd" : "hum", argv, { stdio: "inherit", shell: w, windowsHide: true });
83444
+ return r.error ? 1 : r.status ?? 1;
83445
+ }
83446
+ var dist, humHome2, win2, newer, updateCommand, readyVersion, stateFile, readState, writeState, skipVersion, skipped, UPDATE_CHOICES;
83420
83447
  var init_update = __esm({
83421
83448
  "src/update.js"() {
83422
83449
  init_install();
@@ -83435,7 +83462,12 @@ var init_update = __esm({
83435
83462
  if (layout2.kind === "python") return "uv tool upgrade hum-cli (or: pip install -U hum-cli)";
83436
83463
  return "npm i -g @metaphi-ai/hum@latest";
83437
83464
  };
83438
- readyVersion = (layout2, version) => layout2.kind === "native" && version && fs3.existsSync(path2.join(layout2.base, version, layout2.exe)) ? version : "";
83465
+ readyVersion = (layout2, version, pkg = packageVersion) => {
83466
+ if (!version) return "";
83467
+ if (layout2.kind === "native") return fs3.existsSync(path2.join(layout2.base, version, layout2.exe)) ? version : "";
83468
+ if (layout2.kind === "npm") return pkg() === version ? version : "";
83469
+ return "";
83470
+ };
83439
83471
  stateFile = (env3 = process.env) => path2.join(humHome2(env3), "update.json");
83440
83472
  readState = (env3 = process.env) => {
83441
83473
  try {
@@ -83451,6 +83483,13 @@ var init_update = __esm({
83451
83483
  } catch {
83452
83484
  }
83453
83485
  };
83486
+ skipVersion = (version, env3 = process.env) => writeState({ ...readState(env3), skipped: version }, env3);
83487
+ skipped = (version, env3 = process.env) => !!version && readState(env3).skipped === version;
83488
+ UPDATE_CHOICES = [
83489
+ { key: "now", label: "Update now", desc: "installs and starts hum again on the new version" },
83490
+ { key: "later", label: "Not now", desc: "keeps going \xB7 the new version installs in the background for next time" },
83491
+ { key: "skip", label: "Skip this version", desc: "not offered again until the one after it" }
83492
+ ];
83454
83493
  }
83455
83494
  });
83456
83495
 
@@ -83519,6 +83558,9 @@ function engineCandidates(env3 = process.env) {
83519
83558
  out.push({ bin: path3.join(os5.homedir(), ".local", "bin", win3 ? "hum-engine.exe" : "hum-engine"), args: [], where: "uv's bin dir" });
83520
83559
  return out;
83521
83560
  }
83561
+ function wantsPlain(argv, env3 = process.env) {
83562
+ return argv.includes("--plain") || !!env3.HUM_PLAIN;
83563
+ }
83522
83564
  function engineCommand(argv, candidates = engineCandidates()) {
83523
83565
  for (const c of candidates) {
83524
83566
  if (c.args[c.args.length - 1] !== "engine") continue;
@@ -83547,7 +83589,7 @@ function runningVersion(candidates = engineCandidates(), opts = {}) {
83547
83589
  }
83548
83590
  return null;
83549
83591
  }
83550
- function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.57" : "" } = {}) {
83592
+ function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.59" : "" } = {}) {
83551
83593
  const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
83552
83594
  const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
83553
83595
  if (!refused) {
@@ -85526,7 +85568,7 @@ var input_default = MultilineInput;
85526
85568
 
85527
85569
  // src/app.jsx
85528
85570
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
85529
- var MINE = true ? "0.1.57" : "";
85571
+ var MINE = true ? "0.1.59" : "";
85530
85572
  var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
85531
85573
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
85532
85574
  var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
@@ -85567,6 +85609,11 @@ var handEdit = (stat) => {
85567
85609
  ${lines.join("\n ")}`;
85568
85610
  };
85569
85611
  var fmtCost2 = (c) => c >= 0.01 ? `$${c.toFixed(2)}` : c > 0 ? `$${c.toFixed(4)}` : "$0";
85612
+ var goalLine = (g) => {
85613
+ if (!g || !g.text) return "no goal set";
85614
+ const n = g.exchanges || 0;
85615
+ return `goal ${g.status || "active"}: ${g.text}${n ? ` \xB7 ${plural(n, "exchange")}` : ""}`;
85616
+ };
85570
85617
  var fmtTokens = (t) => t >= 1e3 ? `${(t / 1e3).toFixed(1)}k tokens` : `${t || 0} tokens`;
85571
85618
  var HISTORY_PATH = path5.join(os6.homedir(), ".hum", "history.json");
85572
85619
  var HISTORY_MAX = 300;
@@ -85605,7 +85652,7 @@ var COMMANDS = [
85605
85652
  { name: "/usage-credits", desc: "your credits on our models, and the page that adds more (a code from Metaphi, or a purchase)" },
85606
85653
  { name: "/approve", desc: "approvals on|off \u2014 whether every change and command waits for you first (leaving the sandbox always asks)" },
85607
85654
  { name: "/continue", desc: "after a pause: let the agent carry on" },
85608
- { name: "/goal", desc: "what must hold before the work is done (/goal <condition>; /goal clear) \u2014 it outlives compaction and resume, and is checked against the workspace before every stop" },
85655
+ { name: "/goal", desc: "the goal the session keeps working toward on its own, exchange after exchange, until the model marks it complete or blocked (/goal <objective>; /goal pause \xB7 resume \xB7 clear; /goal alone shows where it stands)" },
85609
85656
  { name: "/image", desc: "attach an image file to your next message (/image <path>); ctrl+v pastes a screenshot" },
85610
85657
  { name: "/mcp", desc: "the MCP servers in this session \u2014 what each mounted, and any that did not" },
85611
85658
  { name: "/tools", desc: "the tools the model has, and the sandbox they run in" },
@@ -85634,7 +85681,7 @@ var tallyLine = (tally) => Object.entries(tally).map(([name, t]) => {
85634
85681
  const parts = [t.ok ? `${t.ok} ok` : null, t.failed ? `${t.failed} failed` : null, t.error ? `${t.error} error` : null].filter(Boolean);
85635
85682
  return `${short} ${parts.join(" \xB7 ")}`;
85636
85683
  }).join(" ");
85637
- function App2({ engine: engine2, task, resume, images = [] }) {
85684
+ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2 = null }) {
85638
85685
  const { exit } = use_app_default();
85639
85686
  const { stdout } = use_stdout_default();
85640
85687
  const width = (stdout?.columns || 80) - 2;
@@ -85642,6 +85689,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85642
85689
  const [phase, setPhase] = (0, import_react24.useState)("connecting");
85643
85690
  const [status, setStatus] = (0, import_react24.useState)("");
85644
85691
  const [hello, setHello] = (0, import_react24.useState)(null);
85692
+ const [latest, setLatest] = (0, import_react24.useState)(null);
85645
85693
  const [needYou, setNeedYou] = (0, import_react24.useState)(0);
85646
85694
  const [goal, setGoal] = (0, import_react24.useState)(null);
85647
85695
  const [session, setSession] = (0, import_react24.useState)(null);
@@ -85795,6 +85843,12 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85795
85843
  append({ kind: "agent_end", text: `agent ${ev.n} done \xB7 ${plural(ev.steps, "step")} \xB7 ${fmtCost2(ev.cost_usd)}${ev.reason !== "done" ? ` \xB7 ${ev.reason}` : ""}` });
85796
85844
  setAgents((a) => a.filter((x) => x.n !== ev.n));
85797
85845
  break;
85846
+ case "tools":
85847
+ setHello((h) => h ? { ...h, tools: ev.tools || h.tools, mcp: ev.mcp || h.mcp, mounting: [] } : h);
85848
+ break;
85849
+ case "update":
85850
+ setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
85851
+ break;
85798
85852
  case "hello": {
85799
85853
  if (helloRef.current) resetForSession();
85800
85854
  setHello(ev);
@@ -85803,15 +85857,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85803
85857
  setMeter((m) => ({ ...m, tokens: 0, cap: ev.compact_at || 0 }));
85804
85858
  setGate(ev.gate === "approve" ? "approve" : "off");
85805
85859
  if (ev.session) setSession(ev.session);
85806
- if (ev.fresh) {
85807
- const box = updateBox(MINE || ev.version || "", ev.latest_version || "", ev.release_notes_url || "");
85808
- if (box) append({ kind: "update", ...box });
85809
- append({ kind: "wordmark" });
85810
- }
85860
+ if (ev.fresh) append({ kind: "wordmark" });
85861
+ setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
85811
85862
  append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE), instruction: ev.session ? ev.instruction : null });
85812
85863
  if (ev.note) append({ kind: "warn", text: ev.note });
85813
- setGoal(ev.goal || null);
85814
- if (ev.goal) append({ kind: "info", text: `goal: ${ev.goal}` });
85864
+ setGoal(ev.goal_state && ev.goal_state.text ? ev.goal_state : ev.goal ? { text: ev.goal, status: "active", exchanges: 0 } : null);
85865
+ if (ev.goal_state && ev.goal_state.text) append({ kind: "info", text: goalLine(ev.goal_state) });
85866
+ else if (ev.goal) append({ kind: "info", text: `goal: ${ev.goal}` });
85815
85867
  preHello.current.forEach((it) => append(it));
85816
85868
  preHello.current = [];
85817
85869
  if (ev.session) {
@@ -86101,8 +86153,8 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86101
86153
  break;
86102
86154
  }
86103
86155
  case "goal":
86104
- setGoal(ev.text || null);
86105
- append({ kind: "info", text: ev.text ? `goal: ${ev.text}` : "goal cleared" });
86156
+ setGoal(ev.text ? ev : null);
86157
+ append({ kind: ev.status === "blocked" || ev.status === "usage_limited" ? "warn" : "info", text: ev.summary || goalLine(ev) });
86106
86158
  break;
86107
86159
  case "gate":
86108
86160
  setGate(ev.mode);
@@ -86183,17 +86235,45 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86183
86235
  const t = setInterval(count, NEEDS_EVERY_MS);
86184
86236
  return () => clearInterval(t);
86185
86237
  }, [hello && hello.run_id]);
86238
+ const offeredRef = (0, import_react24.useRef)("");
86186
86239
  (0, import_react24.useEffect)(() => {
86187
- if (!hello) return void 0;
86240
+ if (!latest) return void 0;
86188
86241
  let live = true;
86189
- updateNotice(MINE || hello.version || "0.0.0", { running: hello.version || "", latest: hello.latest_version || "" }).then((line) => {
86242
+ const mine = MINE || latest.version || "0.0.0";
86243
+ updateNotice(mine, { running: latest.version || "", latest: latest.latest_version || "" }).then((line) => {
86190
86244
  if (live && line) append({ kind: "info", text: line });
86191
86245
  }).catch(() => {
86192
86246
  });
86247
+ const box = updateBox(mine, latest.latest_version || "", latest.release_notes_url || "");
86248
+ if (box && offeredRef.current !== box.latest && updateDue(box.latest)) {
86249
+ offeredRef.current = box.latest;
86250
+ setPicker((p) => p ? p : { kind: "update", index: 0, box });
86251
+ }
86193
86252
  return () => {
86194
86253
  live = false;
86195
86254
  };
86196
- }, [hello]);
86255
+ }, [latest]);
86256
+ const chooseUpdate = (choice, box) => {
86257
+ if (choice === "now") {
86258
+ if (!onUpdate2) {
86259
+ append({ kind: "info", text: `run ${box.command} to update` });
86260
+ return;
86261
+ }
86262
+ append({ kind: "info", text: `updating hum to ${box.latest} \u2026` });
86263
+ onUpdate2(box.latest);
86264
+ engine2.send({ cmd: session ? "quit" : "stop" });
86265
+ setPhaseBoth("dead");
86266
+ setTimeout(() => exit(), 400);
86267
+ return;
86268
+ }
86269
+ if (choice === "skip") {
86270
+ skipVersion(box.latest);
86271
+ append({ kind: "info", text: `skipping ${box.latest} \xB7 \`hum update\` brings it any time` });
86272
+ return;
86273
+ }
86274
+ const line = laterNotice(box.latest);
86275
+ if (line) append({ kind: "info", text: line });
86276
+ };
86197
86277
  const quit = () => {
86198
86278
  if (phaseRef.current === "dead") return;
86199
86279
  const busy = phaseRef.current === "busy";
@@ -86368,6 +86448,20 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86368
86448
  else if (input === "s" && !value.trim()) pick(false);
86369
86449
  return;
86370
86450
  }
86451
+ if (picker && picker.kind === "update") {
86452
+ const n = picker.box.choices.length;
86453
+ const choose = (i) => {
86454
+ const c = picker.box.choices[i];
86455
+ setPicker(null);
86456
+ if (c) chooseUpdate(c.key, picker.box);
86457
+ };
86458
+ if (key.upArrow) setPicker((p) => ({ ...p, index: (p.index + n - 1) % n }));
86459
+ else if (key.downArrow || key.tab) setPicker((p) => ({ ...p, index: (p.index + 1) % n }));
86460
+ else if (key.escape) choose(1);
86461
+ else if (key.return) choose(picker.index);
86462
+ else if (/^[1-9]$/.test(input) && Number(input) <= n) choose(Number(input) - 1);
86463
+ return;
86464
+ }
86371
86465
  if (picker && picker.kind === "model") {
86372
86466
  const it = picker.items[picker.index];
86373
86467
  const pick = () => {
@@ -86554,8 +86648,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86554
86648
  engine2.send({ cmd: "continue" });
86555
86649
  break;
86556
86650
  case "/goal":
86557
- if (!arg) append({ kind: "info", text: goal ? `goal: ${goal}` : "no goal set \u2014 /goal <what must hold before the work is done>; /goal clear removes it" });
86558
- else engine2.send({ cmd: "goal", text: arg });
86651
+ engine2.send(arg ? { cmd: "goal", text: arg } : { cmd: "goal" });
86559
86652
  break;
86560
86653
  case "/approve": {
86561
86654
  const mode = arg === "on" ? "approve" : arg === "off" ? "off" : gate === "approve" ? "off" : "approve";
@@ -86625,30 +86718,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86625
86718
  setPhaseBoth("busy");
86626
86719
  }
86627
86720
  };
86628
- const statusLine = phase === "connecting" ? "starting \u2026" : `${modelRef.current || ""} \xB7 ${fmtCost2(spend)}` + (ctxPct >= 10 ? ` \xB7 ctx ${ctxPct}%` : "") + (gate === "approve" ? " \xB7 approvals on" : "") + (needYou ? ` \xB7 ${needYou} need you` : "") + (offer ? " \xB7 /accept \xB7 /reject" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
86721
+ const statusLine = phase === "connecting" ? "starting \u2026" : `${modelRef.current || ""} \xB7 ${fmtCost2(spend)}` + (ctxPct >= 10 ? ` \xB7 ctx ${ctxPct}%` : "") + (gate === "approve" ? " \xB7 approvals on" : "") + (hello && hello.mounting && hello.mounting.length ? ` \xB7 mounting ${hello.mounting.join(", ")}` : "") + (goal && goal.text ? ` \xB7 \u25CE goal ${goal.status || "active"}` : "") + (needYou ? ` \xB7 ${needYou} need you` : "") + (offer ? " \xB7 /accept \xB7 /reject" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
86629
86722
  const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${status || "working"}${elapsed >= 2 ? ` \xB7 ${fmtDur(elapsed)}` : ""}` + (thinkChars.current > 4e3 ? ` \xB7 ${(thinkChars.current / 1e3).toFixed(0)}k thinking` : "");
86630
86723
  const rows = stdout?.rows || DEFAULT_ROWS;
86631
86724
  const chrome = 1 + 2 + 4 + (value.split("\n").length - 1) + 1 + (menu.length ? menu.length : 0) + (!menu.length && agents.length ? agents.length + 1 : 0) + (question && step ? 6 + stepOptions.length + (question.summary ? question.summary.split("\n").length : 0) + (question.evidence || []).length : 0) + (proposal ? 4 + proposal.calls.length * (1 + Math.min(DIFF_TAIL_LINES, 8)) : 0) + (reflection ? 8 + reflection.details.split("\n").length : 0) + (confirm ? 4 + Math.min(8, String(confirm.stat || "").split("\n").length) : 0) + (picker ? 14 : 0);
86632
86725
  const liveBudget = Math.max(LIVE_MIN_ROWS, Math.min(DRAFT_TAIL_LINES, rows - 1 - chrome));
86633
86726
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
86634
86727
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Static, { items, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", marginBottom: ["hum", "you", "banner", "turn"].includes(item.kind) ? 1 : 0, children: [
86635
- item.kind === "update" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, marginLeft: 1, alignSelf: "flex-start", children: [
86636
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
86637
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "yellow", children: "\u2728 " }),
86638
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: true, children: item.head })
86639
- ] }),
86640
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
86641
- "Run ",
86642
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: item.command }),
86643
- " to update."
86644
- ] }),
86645
- item.notes ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
86646
- "\n",
86647
- "See full release notes:",
86648
- "\n",
86649
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, underline: true, children: item.notes })
86650
- ] }) : null
86651
- ] }),
86652
86728
  item.kind === "wordmark" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexDirection: "column", paddingLeft: 1, children: WORDMARK.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: row }, i)) }),
86653
86729
  item.kind === "banner" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
86654
86730
  MASCOT.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
@@ -86925,6 +87001,30 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86925
87001
  c.diff && c.diff.split("\n").length > DIFF_TAIL_LINES ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: ` the whole change (${c.diff.split("\n").length} lines) is above` }) : null
86926
87002
  ] }, c.id))
86927
87003
  ] }),
87004
+ picker && picker.kind === "update" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
87005
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87006
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "yellow", children: "\u2728 " }),
87007
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: true, children: picker.box.head })
87008
+ ] }),
87009
+ picker.box.notes ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87010
+ "release notes: ",
87011
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { underline: true, children: picker.box.notes })
87012
+ ] }) : null,
87013
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
87014
+ picker.box.choices.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
87015
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === picker.index ? "\u276F " : " " }),
87016
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: i === picker.index, children: `${i + 1}. ${c.label}`.padEnd(22) }),
87017
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: i !== picker.index, children: [
87018
+ " ",
87019
+ c.desc
87020
+ ] })
87021
+ ] }, c.key)),
87022
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
87023
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87024
+ "Enter to choose \xB7 Esc to keep going \xB7 by hand: ",
87025
+ picker.box.command
87026
+ ] })
87027
+ ] }),
86928
87028
  picker && picker.kind === "model" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
86929
87029
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: "Select model" }),
86930
87030
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Switch models. Served via Metaphi AI." }),
@@ -87148,7 +87248,7 @@ init_update();
87148
87248
  init_install();
87149
87249
  var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
87150
87250
  import { spawnSync as spawnSync5 } from "node:child_process";
87151
- var MINE2 = true ? "0.1.57" : "0.0.0";
87251
+ var MINE2 = true ? "0.1.59" : "0.0.0";
87152
87252
  var layout = installLayout();
87153
87253
  function completeInstall() {
87154
87254
  if (layout.kind !== "npm" || !needsInstall(MINE2)) return;
@@ -87176,7 +87276,7 @@ if (argv0[0] === "doctor") {
87176
87276
  const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
87177
87277
  process.exit(await doctor2({ json: argv0.includes("--json"), mine: MINE2, layout }));
87178
87278
  }
87179
- if (ENGINE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--json")) {
87279
+ if (ENGINE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--json") || wantsPlain(argv0)) {
87180
87280
  completeInstall();
87181
87281
  const cmd = engineCommand(argv0);
87182
87282
  if (!cmd) {
@@ -87190,6 +87290,21 @@ if (ENGINE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--
87190
87290
  }
87191
87291
  process.exit(r.status === null ? 1 : r.status);
87192
87292
  }
87293
+ var wantUpdate = "";
87294
+ var onUpdate = (version) => {
87295
+ wantUpdate = version;
87296
+ };
87297
+ function leave(engine2) {
87298
+ engine2.close();
87299
+ if (!wantUpdate) process.exit(0);
87300
+ const rc = updateNow(layout);
87301
+ if (rc !== 0) {
87302
+ process.stderr.write(`the update did not finish \xB7 ${updateCommand(layout)}
87303
+ `);
87304
+ process.exit(rc);
87305
+ }
87306
+ process.exit(restart());
87307
+ }
87193
87308
  if (argv0[0] === "agents") {
87194
87309
  const { liveRows: liveRows2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
87195
87310
  const rows = liveRows2();
@@ -87216,10 +87331,9 @@ if (argv0[0] === "agents") {
87216
87331
  process.stderr.write(exc.message + "\n");
87217
87332
  process.exit(1);
87218
87333
  }
87219
- const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine: engine2, task: null, resume: null, images: [] }), { exitOnCtrlC: false });
87334
+ const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine: engine2, task: null, resume: null, images: [], onUpdate }), { exitOnCtrlC: false });
87220
87335
  await app.waitUntilExit();
87221
- engine2.close();
87222
- process.exit(0);
87336
+ leave(engine2);
87223
87337
  }
87224
87338
  function parseArgs(argv) {
87225
87339
  const a = { task: null, resume: null, cwd: process.cwd(), images: [] };
@@ -87270,11 +87384,8 @@ try {
87270
87384
  process.stderr.write(exc.message + "\n");
87271
87385
  process.exit(1);
87272
87386
  }
87273
- var { waitUntilExit } = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine, task: startedHere ? null : args.task, resume: args.resume === "pick" || !startedHere ? args.resume : null, images: startedHere ? [] : args.images }), { exitOnCtrlC: false });
87274
- waitUntilExit().then(() => {
87275
- engine.close();
87276
- process.exit(0);
87277
- });
87387
+ var { waitUntilExit } = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine, task: startedHere ? null : args.task, resume: args.resume === "pick" || !startedHere ? args.resume : null, images: startedHere ? [] : args.images, onUpdate }), { exitOnCtrlC: false });
87388
+ waitUntilExit().then(() => leave(engine));
87278
87389
  /*! Bundled license information:
87279
87390
 
87280
87391
  react/cjs/react.production.min.js:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "Hum: a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",