@metaphi-ai/hum 0.1.57 → 0.1.58

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 +167 -59
  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
 
@@ -83547,7 +83586,7 @@ function runningVersion(candidates = engineCandidates(), opts = {}) {
83547
83586
  }
83548
83587
  return null;
83549
83588
  }
83550
- function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.57" : "" } = {}) {
83589
+ function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.58" : "" } = {}) {
83551
83590
  const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
83552
83591
  const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
83553
83592
  if (!refused) {
@@ -85526,7 +85565,7 @@ var input_default = MultilineInput;
85526
85565
 
85527
85566
  // src/app.jsx
85528
85567
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
85529
- var MINE = true ? "0.1.57" : "";
85568
+ var MINE = true ? "0.1.58" : "";
85530
85569
  var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
85531
85570
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
85532
85571
  var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
@@ -85567,6 +85606,11 @@ var handEdit = (stat) => {
85567
85606
  ${lines.join("\n ")}`;
85568
85607
  };
85569
85608
  var fmtCost2 = (c) => c >= 0.01 ? `$${c.toFixed(2)}` : c > 0 ? `$${c.toFixed(4)}` : "$0";
85609
+ var goalLine = (g) => {
85610
+ if (!g || !g.text) return "no goal set";
85611
+ const n = g.exchanges || 0;
85612
+ return `goal ${g.status || "active"}: ${g.text}${n ? ` \xB7 ${plural(n, "exchange")}` : ""}`;
85613
+ };
85570
85614
  var fmtTokens = (t) => t >= 1e3 ? `${(t / 1e3).toFixed(1)}k tokens` : `${t || 0} tokens`;
85571
85615
  var HISTORY_PATH = path5.join(os6.homedir(), ".hum", "history.json");
85572
85616
  var HISTORY_MAX = 300;
@@ -85605,7 +85649,7 @@ var COMMANDS = [
85605
85649
  { name: "/usage-credits", desc: "your credits on our models, and the page that adds more (a code from Metaphi, or a purchase)" },
85606
85650
  { name: "/approve", desc: "approvals on|off \u2014 whether every change and command waits for you first (leaving the sandbox always asks)" },
85607
85651
  { 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" },
85652
+ { 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
85653
  { name: "/image", desc: "attach an image file to your next message (/image <path>); ctrl+v pastes a screenshot" },
85610
85654
  { name: "/mcp", desc: "the MCP servers in this session \u2014 what each mounted, and any that did not" },
85611
85655
  { name: "/tools", desc: "the tools the model has, and the sandbox they run in" },
@@ -85634,7 +85678,7 @@ var tallyLine = (tally) => Object.entries(tally).map(([name, t]) => {
85634
85678
  const parts = [t.ok ? `${t.ok} ok` : null, t.failed ? `${t.failed} failed` : null, t.error ? `${t.error} error` : null].filter(Boolean);
85635
85679
  return `${short} ${parts.join(" \xB7 ")}`;
85636
85680
  }).join(" ");
85637
- function App2({ engine: engine2, task, resume, images = [] }) {
85681
+ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2 = null }) {
85638
85682
  const { exit } = use_app_default();
85639
85683
  const { stdout } = use_stdout_default();
85640
85684
  const width = (stdout?.columns || 80) - 2;
@@ -85642,6 +85686,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85642
85686
  const [phase, setPhase] = (0, import_react24.useState)("connecting");
85643
85687
  const [status, setStatus] = (0, import_react24.useState)("");
85644
85688
  const [hello, setHello] = (0, import_react24.useState)(null);
85689
+ const [latest, setLatest] = (0, import_react24.useState)(null);
85645
85690
  const [needYou, setNeedYou] = (0, import_react24.useState)(0);
85646
85691
  const [goal, setGoal] = (0, import_react24.useState)(null);
85647
85692
  const [session, setSession] = (0, import_react24.useState)(null);
@@ -85795,6 +85840,12 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85795
85840
  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
85841
  setAgents((a) => a.filter((x) => x.n !== ev.n));
85797
85842
  break;
85843
+ case "tools":
85844
+ setHello((h) => h ? { ...h, tools: ev.tools || h.tools, mcp: ev.mcp || h.mcp, mounting: [] } : h);
85845
+ break;
85846
+ case "update":
85847
+ setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
85848
+ break;
85798
85849
  case "hello": {
85799
85850
  if (helloRef.current) resetForSession();
85800
85851
  setHello(ev);
@@ -85803,15 +85854,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
85803
85854
  setMeter((m) => ({ ...m, tokens: 0, cap: ev.compact_at || 0 }));
85804
85855
  setGate(ev.gate === "approve" ? "approve" : "off");
85805
85856
  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
- }
85857
+ if (ev.fresh) append({ kind: "wordmark" });
85858
+ setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
85811
85859
  append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE), instruction: ev.session ? ev.instruction : null });
85812
85860
  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}` });
85861
+ setGoal(ev.goal_state && ev.goal_state.text ? ev.goal_state : ev.goal ? { text: ev.goal, status: "active", exchanges: 0 } : null);
85862
+ if (ev.goal_state && ev.goal_state.text) append({ kind: "info", text: goalLine(ev.goal_state) });
85863
+ else if (ev.goal) append({ kind: "info", text: `goal: ${ev.goal}` });
85815
85864
  preHello.current.forEach((it) => append(it));
85816
85865
  preHello.current = [];
85817
85866
  if (ev.session) {
@@ -86101,8 +86150,8 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86101
86150
  break;
86102
86151
  }
86103
86152
  case "goal":
86104
- setGoal(ev.text || null);
86105
- append({ kind: "info", text: ev.text ? `goal: ${ev.text}` : "goal cleared" });
86153
+ setGoal(ev.text ? ev : null);
86154
+ append({ kind: ev.status === "blocked" || ev.status === "usage_limited" ? "warn" : "info", text: ev.summary || goalLine(ev) });
86106
86155
  break;
86107
86156
  case "gate":
86108
86157
  setGate(ev.mode);
@@ -86183,17 +86232,45 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86183
86232
  const t = setInterval(count, NEEDS_EVERY_MS);
86184
86233
  return () => clearInterval(t);
86185
86234
  }, [hello && hello.run_id]);
86235
+ const offeredRef = (0, import_react24.useRef)("");
86186
86236
  (0, import_react24.useEffect)(() => {
86187
- if (!hello) return void 0;
86237
+ if (!latest) return void 0;
86188
86238
  let live = true;
86189
- updateNotice(MINE || hello.version || "0.0.0", { running: hello.version || "", latest: hello.latest_version || "" }).then((line) => {
86239
+ const mine = MINE || latest.version || "0.0.0";
86240
+ updateNotice(mine, { running: latest.version || "", latest: latest.latest_version || "" }).then((line) => {
86190
86241
  if (live && line) append({ kind: "info", text: line });
86191
86242
  }).catch(() => {
86192
86243
  });
86244
+ const box = updateBox(mine, latest.latest_version || "", latest.release_notes_url || "");
86245
+ if (box && offeredRef.current !== box.latest && updateDue(box.latest)) {
86246
+ offeredRef.current = box.latest;
86247
+ setPicker((p) => p ? p : { kind: "update", index: 0, box });
86248
+ }
86193
86249
  return () => {
86194
86250
  live = false;
86195
86251
  };
86196
- }, [hello]);
86252
+ }, [latest]);
86253
+ const chooseUpdate = (choice, box) => {
86254
+ if (choice === "now") {
86255
+ if (!onUpdate2) {
86256
+ append({ kind: "info", text: `run ${box.command} to update` });
86257
+ return;
86258
+ }
86259
+ append({ kind: "info", text: `updating hum to ${box.latest} \u2026` });
86260
+ onUpdate2(box.latest);
86261
+ engine2.send({ cmd: session ? "quit" : "stop" });
86262
+ setPhaseBoth("dead");
86263
+ setTimeout(() => exit(), 400);
86264
+ return;
86265
+ }
86266
+ if (choice === "skip") {
86267
+ skipVersion(box.latest);
86268
+ append({ kind: "info", text: `skipping ${box.latest} \xB7 \`hum update\` brings it any time` });
86269
+ return;
86270
+ }
86271
+ const line = laterNotice(box.latest);
86272
+ if (line) append({ kind: "info", text: line });
86273
+ };
86197
86274
  const quit = () => {
86198
86275
  if (phaseRef.current === "dead") return;
86199
86276
  const busy = phaseRef.current === "busy";
@@ -86368,6 +86445,20 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86368
86445
  else if (input === "s" && !value.trim()) pick(false);
86369
86446
  return;
86370
86447
  }
86448
+ if (picker && picker.kind === "update") {
86449
+ const n = picker.box.choices.length;
86450
+ const choose = (i) => {
86451
+ const c = picker.box.choices[i];
86452
+ setPicker(null);
86453
+ if (c) chooseUpdate(c.key, picker.box);
86454
+ };
86455
+ if (key.upArrow) setPicker((p) => ({ ...p, index: (p.index + n - 1) % n }));
86456
+ else if (key.downArrow || key.tab) setPicker((p) => ({ ...p, index: (p.index + 1) % n }));
86457
+ else if (key.escape) choose(1);
86458
+ else if (key.return) choose(picker.index);
86459
+ else if (/^[1-9]$/.test(input) && Number(input) <= n) choose(Number(input) - 1);
86460
+ return;
86461
+ }
86371
86462
  if (picker && picker.kind === "model") {
86372
86463
  const it = picker.items[picker.index];
86373
86464
  const pick = () => {
@@ -86554,8 +86645,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86554
86645
  engine2.send({ cmd: "continue" });
86555
86646
  break;
86556
86647
  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 });
86648
+ engine2.send(arg ? { cmd: "goal", text: arg } : { cmd: "goal" });
86559
86649
  break;
86560
86650
  case "/approve": {
86561
86651
  const mode = arg === "on" ? "approve" : arg === "off" ? "off" : gate === "approve" ? "off" : "approve";
@@ -86625,30 +86715,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86625
86715
  setPhaseBoth("busy");
86626
86716
  }
86627
86717
  };
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");
86718
+ 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
86719
  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
86720
  const rows = stdout?.rows || DEFAULT_ROWS;
86631
86721
  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
86722
  const liveBudget = Math.max(LIVE_MIN_ROWS, Math.min(DRAFT_TAIL_LINES, rows - 1 - chrome));
86633
86723
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
86634
86724
  /* @__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
86725
  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
86726
  item.kind === "banner" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
86654
86727
  MASCOT.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
@@ -86925,6 +86998,30 @@ function App2({ engine: engine2, task, resume, images = [] }) {
86925
86998
  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
86999
  ] }, c.id))
86927
87000
  ] }),
87001
+ picker && picker.kind === "update" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
87002
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87003
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "yellow", children: "\u2728 " }),
87004
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: true, children: picker.box.head })
87005
+ ] }),
87006
+ picker.box.notes ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87007
+ "release notes: ",
87008
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { underline: true, children: picker.box.notes })
87009
+ ] }) : null,
87010
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
87011
+ picker.box.choices.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
87012
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === picker.index ? "\u276F " : " " }),
87013
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: i === picker.index, children: `${i + 1}. ${c.label}`.padEnd(22) }),
87014
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: i !== picker.index, children: [
87015
+ " ",
87016
+ c.desc
87017
+ ] })
87018
+ ] }, c.key)),
87019
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
87020
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87021
+ "Enter to choose \xB7 Esc to keep going \xB7 by hand: ",
87022
+ picker.box.command
87023
+ ] })
87024
+ ] }),
86928
87025
  picker && picker.kind === "model" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
86929
87026
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: "Select model" }),
86930
87027
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Switch models. Served via Metaphi AI." }),
@@ -87148,7 +87245,7 @@ init_update();
87148
87245
  init_install();
87149
87246
  var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
87150
87247
  import { spawnSync as spawnSync5 } from "node:child_process";
87151
- var MINE2 = true ? "0.1.57" : "0.0.0";
87248
+ var MINE2 = true ? "0.1.58" : "0.0.0";
87152
87249
  var layout = installLayout();
87153
87250
  function completeInstall() {
87154
87251
  if (layout.kind !== "npm" || !needsInstall(MINE2)) return;
@@ -87190,6 +87287,21 @@ if (ENGINE_COMMANDS.has(argv0[0]) || argv0[0] === "agents" && argv0.includes("--
87190
87287
  }
87191
87288
  process.exit(r.status === null ? 1 : r.status);
87192
87289
  }
87290
+ var wantUpdate = "";
87291
+ var onUpdate = (version) => {
87292
+ wantUpdate = version;
87293
+ };
87294
+ function leave(engine2) {
87295
+ engine2.close();
87296
+ if (!wantUpdate) process.exit(0);
87297
+ const rc = updateNow(layout);
87298
+ if (rc !== 0) {
87299
+ process.stderr.write(`the update did not finish \xB7 ${updateCommand(layout)}
87300
+ `);
87301
+ process.exit(rc);
87302
+ }
87303
+ process.exit(restart());
87304
+ }
87193
87305
  if (argv0[0] === "agents") {
87194
87306
  const { liveRows: liveRows2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
87195
87307
  const rows = liveRows2();
@@ -87216,10 +87328,9 @@ if (argv0[0] === "agents") {
87216
87328
  process.stderr.write(exc.message + "\n");
87217
87329
  process.exit(1);
87218
87330
  }
87219
- const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine: engine2, task: null, resume: null, images: [] }), { exitOnCtrlC: false });
87331
+ const app = render_default(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(App2, { engine: engine2, task: null, resume: null, images: [], onUpdate }), { exitOnCtrlC: false });
87220
87332
  await app.waitUntilExit();
87221
- engine2.close();
87222
- process.exit(0);
87333
+ leave(engine2);
87223
87334
  }
87224
87335
  function parseArgs(argv) {
87225
87336
  const a = { task: null, resume: null, cwd: process.cwd(), images: [] };
@@ -87270,11 +87381,8 @@ try {
87270
87381
  process.stderr.write(exc.message + "\n");
87271
87382
  process.exit(1);
87272
87383
  }
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
- });
87384
+ 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 });
87385
+ waitUntilExit().then(() => leave(engine));
87278
87386
  /*! Bundled license information:
87279
87387
 
87280
87388
  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.58",
4
4
  "description": "Hum: a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",