@metaphi-ai/hum 0.1.20 → 0.1.22

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 +142 -110
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -22744,10 +22744,10 @@ var require_react_reconciler_development = __commonJS({
22744
22744
  var setErrorHandler = null;
22745
22745
  var setSuspenseHandler = null;
22746
22746
  {
22747
- var copyWithDeleteImpl = function(obj, path5, index2) {
22748
- var key = path5[index2];
22747
+ var copyWithDeleteImpl = function(obj, path4, index2) {
22748
+ var key = path4[index2];
22749
22749
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
22750
- if (index2 + 1 === path5.length) {
22750
+ if (index2 + 1 === path4.length) {
22751
22751
  if (isArray(updated)) {
22752
22752
  updated.splice(key, 1);
22753
22753
  } else {
@@ -22755,11 +22755,11 @@ var require_react_reconciler_development = __commonJS({
22755
22755
  }
22756
22756
  return updated;
22757
22757
  }
22758
- updated[key] = copyWithDeleteImpl(obj[key], path5, index2 + 1);
22758
+ updated[key] = copyWithDeleteImpl(obj[key], path4, index2 + 1);
22759
22759
  return updated;
22760
22760
  };
22761
- var copyWithDelete = function(obj, path5) {
22762
- return copyWithDeleteImpl(obj, path5, 0);
22761
+ var copyWithDelete = function(obj, path4) {
22762
+ return copyWithDeleteImpl(obj, path4, 0);
22763
22763
  };
22764
22764
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
22765
22765
  var oldKey = oldPath[index2];
@@ -22797,17 +22797,17 @@ var require_react_reconciler_development = __commonJS({
22797
22797
  }
22798
22798
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
22799
22799
  };
22800
- var copyWithSetImpl = function(obj, path5, index2, value) {
22801
- if (index2 >= path5.length) {
22800
+ var copyWithSetImpl = function(obj, path4, index2, value) {
22801
+ if (index2 >= path4.length) {
22802
22802
  return value;
22803
22803
  }
22804
- var key = path5[index2];
22804
+ var key = path4[index2];
22805
22805
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
22806
- updated[key] = copyWithSetImpl(obj[key], path5, index2 + 1, value);
22806
+ updated[key] = copyWithSetImpl(obj[key], path4, index2 + 1, value);
22807
22807
  return updated;
22808
22808
  };
22809
- var copyWithSet = function(obj, path5, value) {
22810
- return copyWithSetImpl(obj, path5, 0, value);
22809
+ var copyWithSet = function(obj, path4, value) {
22810
+ return copyWithSetImpl(obj, path4, 0, value);
22811
22811
  };
22812
22812
  var findHook = function(fiber, id) {
22813
22813
  var currentHook2 = fiber.memoizedState;
@@ -22817,10 +22817,10 @@ var require_react_reconciler_development = __commonJS({
22817
22817
  }
22818
22818
  return currentHook2;
22819
22819
  };
22820
- overrideHookState = function(fiber, id, path5, value) {
22820
+ overrideHookState = function(fiber, id, path4, value) {
22821
22821
  var hook = findHook(fiber, id);
22822
22822
  if (hook !== null) {
22823
- var newState = copyWithSet(hook.memoizedState, path5, value);
22823
+ var newState = copyWithSet(hook.memoizedState, path4, value);
22824
22824
  hook.memoizedState = newState;
22825
22825
  hook.baseState = newState;
22826
22826
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -22830,10 +22830,10 @@ var require_react_reconciler_development = __commonJS({
22830
22830
  }
22831
22831
  }
22832
22832
  };
22833
- overrideHookStateDeletePath = function(fiber, id, path5) {
22833
+ overrideHookStateDeletePath = function(fiber, id, path4) {
22834
22834
  var hook = findHook(fiber, id);
22835
22835
  if (hook !== null) {
22836
- var newState = copyWithDelete(hook.memoizedState, path5);
22836
+ var newState = copyWithDelete(hook.memoizedState, path4);
22837
22837
  hook.memoizedState = newState;
22838
22838
  hook.baseState = newState;
22839
22839
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -22856,8 +22856,8 @@ var require_react_reconciler_development = __commonJS({
22856
22856
  }
22857
22857
  }
22858
22858
  };
22859
- overrideProps = function(fiber, path5, value) {
22860
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path5, value);
22859
+ overrideProps = function(fiber, path4, value) {
22860
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path4, value);
22861
22861
  if (fiber.alternate) {
22862
22862
  fiber.alternate.pendingProps = fiber.pendingProps;
22863
22863
  }
@@ -22866,8 +22866,8 @@ var require_react_reconciler_development = __commonJS({
22866
22866
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
22867
22867
  }
22868
22868
  };
22869
- overridePropsDeletePath = function(fiber, path5) {
22870
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path5);
22869
+ overridePropsDeletePath = function(fiber, path4) {
22870
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path4);
22871
22871
  if (fiber.alternate) {
22872
22872
  fiber.alternate.pendingProps = fiber.pendingProps;
22873
22873
  }
@@ -73569,15 +73569,15 @@ var require_route = __commonJS({
73569
73569
  };
73570
73570
  }
73571
73571
  function wrapConversion(toModel, graph) {
73572
- const path5 = [graph[toModel].parent, toModel];
73572
+ const path4 = [graph[toModel].parent, toModel];
73573
73573
  let fn = conversions[graph[toModel].parent][toModel];
73574
73574
  let cur = graph[toModel].parent;
73575
73575
  while (graph[cur].parent) {
73576
- path5.unshift(graph[cur].parent);
73576
+ path4.unshift(graph[cur].parent);
73577
73577
  fn = link3(conversions[graph[cur].parent][cur], fn);
73578
73578
  cur = graph[cur].parent;
73579
73579
  }
73580
- fn.conversion = path5;
73580
+ fn.conversion = path4;
73581
73581
  return fn;
73582
73582
  }
73583
73583
  module.exports = function(fromModel) {
@@ -80406,8 +80406,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
80406
80406
  }
80407
80407
 
80408
80408
  // node_modules/ink/build/components/ErrorOverview.js
80409
- var cleanupPath = (path5) => {
80410
- return path5?.replace(`file://${cwd()}/`, "");
80409
+ var cleanupPath = (path4) => {
80410
+ return path4?.replace(`file://${cwd()}/`, "");
80411
80411
  };
80412
80412
  var stackUtils = new import_stack_utils.default({
80413
80413
  cwd: cwd(),
@@ -83844,6 +83844,23 @@ var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s
83844
83844
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
83845
83845
  var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
83846
83846
  var shortSession = (name) => (name || "").replace(/\.jsonl$/, "");
83847
+ var PICKER_ROWS = 8;
83848
+ var sessionRows = (p, here) => {
83849
+ const q = p.query.trim().toLowerCase();
83850
+ const all = p.all.map((it) => ({ ...it, dir: it.cwd ? path2.basename(it.cwd) : "" }));
83851
+ const inHere = all.filter((it) => it.cwd && here && it.cwd === here);
83852
+ const scope = p.scope === "here" && inHere.length ? "here" : "all";
83853
+ let rows = all;
83854
+ if (scope === "here") rows = inHere;
83855
+ else {
83856
+ const order = [];
83857
+ for (const it of all) if (!order.includes(it.cwd || "")) order.push(it.cwd || "");
83858
+ if (here && order.includes(here)) order.splice(0, 0, ...order.splice(order.indexOf(here), 1));
83859
+ rows = [...all].sort((a, b) => order.indexOf(a.cwd || "") - order.indexOf(b.cwd || ""));
83860
+ }
83861
+ if (q) rows = rows.filter((it) => [it.instruction, it.dir, it.name, it.model].some((v) => (v || "").toLowerCase().includes(q)));
83862
+ return { rows, scope };
83863
+ };
83847
83864
  var homeRel = (p) => {
83848
83865
  const h = os4.homedir();
83849
83866
  return p && h && p.startsWith(h) ? "~" + p.slice(h.length) : p;
@@ -83881,7 +83898,7 @@ var tail = (s, n) => {
83881
83898
  var COMMANDS = [
83882
83899
  { name: "/resume", desc: "pick a past session to continue (this machine or any other)" },
83883
83900
  { name: "/compact", desc: "summarise and restart the context now" },
83884
- { name: "/model", desc: "pick the model \u2014 enter makes it the default, s for this session only; /model <name> switches here" },
83901
+ { name: "/model", desc: "switch between the models you can use; /model <name> switches straight away" },
83885
83902
  { name: "/cost", desc: "tokens and cost so far" },
83886
83903
  { name: "/approve", desc: "approvals on|off \u2014 whether every change and command waits for you first (leaving the sandbox always asks)" },
83887
83904
  { name: "/continue", desc: "after a pause: let the agent carry on" },
@@ -83891,10 +83908,10 @@ var COMMANDS = [
83891
83908
  { name: "/tools", desc: "the tools the model has, and the sandbox they run in" },
83892
83909
  { name: "/hooks", desc: "the lifecycle hooks in scope (~/.hum/hooks.json, <repo>/.hum/hooks.json; Claude Code and Codex hook files too)" },
83893
83910
  { name: "/help", desc: "keys and commands" },
83894
- { name: "/quit", desc: "leave; the session keeps running (hum brings you back)" },
83911
+ { name: "/quit", desc: "leave; the session keeps running (hum resume brings you back)" },
83895
83912
  { name: "/stop", desc: "end this session's engine (the record is saved)" }
83896
83913
  ];
83897
- var HELP = "!cmd runs a command as you \xB7 esc interrupts the model (what it had is kept) \xB7 type while it works to steer \xB7 edit files in your editor any time (recorded as your turn) \xB7 ctrl+o shows the full output of the last tool result \xB7 ctrl+v pastes a screenshot from the clipboard \xB7 @path.png or /image <path> attaches an image file \xB7 commands run in a sandbox (writes in the working directory, no network); leaving it asks you first (enter approves, a typed reason rejects) \xB7 /approve makes every change and command wait for you \xB7 /mcp lists the tool servers \xB7 /resume picks a past session (a running one attaches) \xB7 /compact restarts the context from a summary \xB7 ctrl+c twice leaves and the session keeps running (`hum` brings you back) \xB7 /stop ends it";
83914
+ var HELP = "!cmd runs a command as you \xB7 esc interrupts the model (what it had is kept) \xB7 type while it works to steer \xB7 edit files in your editor any time (recorded as your turn) \xB7 ctrl+o shows the full output of the last tool result \xB7 ctrl+v pastes a screenshot from the clipboard \xB7 @path.png or /image <path> attaches an image file \xB7 commands run in a sandbox (writes in the working directory, no network); leaving it asks you first (enter approves, a typed reason rejects) \xB7 /approve makes every change and command wait for you \xB7 /mcp lists the tool servers \xB7 /resume picks a past session (a running one attaches) \xB7 /compact restarts the context from a summary \xB7 ctrl+c twice leaves and the session keeps running (`hum resume` brings you back) \xB7 /stop ends it";
83898
83915
  var DIFF_TAIL_LINES = 20;
83899
83916
  var OUTPUT_MAX_LINES = 200;
83900
83917
  var ERR_TAIL_LINES = 5;
@@ -84027,7 +84044,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84027
84044
  } else setPhaseBoth("idle");
84028
84045
  if (resume === "pick") engine2.send({ cmd: "sessions" });
84029
84046
  } else if (task) {
84030
- if (images.length && !ev.images) append({ kind: "warn", text: "this engine does not take images; update hum" });
84047
+ if (images.length && !ev.images) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
84031
84048
  engine2.send({ cmd: "start", task, images: ev.images ? images : [] });
84032
84049
  } else if (resume === "pick") {
84033
84050
  setPhaseBoth("idle");
@@ -84036,7 +84053,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84036
84053
  else {
84037
84054
  setPhaseBoth("idle");
84038
84055
  if (ev.images) images.forEach((p) => engine2.send({ cmd: "attach", path: p }));
84039
- else if (images.length) append({ kind: "warn", text: "this engine does not take images; update hum" });
84056
+ else if (images.length) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
84040
84057
  }
84041
84058
  break;
84042
84059
  }
@@ -84122,7 +84139,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84122
84139
  append({ kind: "info", text: "no sessions yet" });
84123
84140
  break;
84124
84141
  }
84125
- setPicker({ kind: "session", items: ev.items.slice(0, 12), index: 0 });
84142
+ setPicker({ kind: "session", all: ev.items, index: 0, top: 0, query: "", scope: "here" });
84126
84143
  break;
84127
84144
  case "models": {
84128
84145
  if (!ev.items || ev.items.length === 0) {
@@ -84285,7 +84302,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84285
84302
  setStatus("");
84286
84303
  break;
84287
84304
  case "bye":
84288
- if (ev.gone && phaseRef.current !== "dead") append({ kind: "error", text: "engine went away" });
84305
+ if (ev.gone && phaseRef.current !== "dead") append({ kind: "error", text: "the session's process went away \xB7 `hum resume` brings it back" });
84289
84306
  setPhaseBoth("dead");
84290
84307
  exit();
84291
84308
  break;
@@ -84299,7 +84316,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84299
84316
  (0, import_react24.useEffect)(() => {
84300
84317
  if (!hello) return void 0;
84301
84318
  let live = true;
84302
- updateNotice(true ? "0.1.20" : hello.version || "0.0.0").then((line) => {
84319
+ updateNotice(true ? "0.1.22" : hello.version || "0.0.0").then((line) => {
84303
84320
  if (live && line) append({ kind: "info", text: line });
84304
84321
  }).catch(() => {
84305
84322
  });
@@ -84310,12 +84327,10 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84310
84327
  const quit = () => {
84311
84328
  if (phaseRef.current === "dead") return;
84312
84329
  const busy = phaseRef.current === "busy";
84313
- append({ kind: "info", text: !session ? "bye" : busy ? "still working \xB7 `hum` brings you back" : `saved \xB7 \`hum\` brings you back` });
84330
+ append({ kind: "info", text: !session ? "bye" : busy ? "still working \xB7 `hum resume` brings you back" : `saved \xB7 \`hum resume\` brings you back` });
84314
84331
  engine2.send({ cmd: "quit" });
84315
- setTimeout(() => {
84316
- setPhaseBoth("dead");
84317
- exit();
84318
- }, 400);
84332
+ setPhaseBoth("dead");
84333
+ setTimeout(() => exit(), 400);
84319
84334
  };
84320
84335
  const stop = () => {
84321
84336
  if (phaseRef.current === "dead") return;
@@ -84366,28 +84381,43 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84366
84381
  return;
84367
84382
  }
84368
84383
  }
84369
- if (picker) {
84384
+ if (picker && picker.kind === "model") {
84385
+ const it = picker.items[picker.index];
84386
+ const pick = () => {
84387
+ setPicker(null);
84388
+ if (it.current) return;
84389
+ modelRef.current = it.name;
84390
+ engine2.send({ cmd: "model", name: it.name });
84391
+ };
84370
84392
  if (key.upArrow) setPicker((p) => ({ ...p, index: (p.index + p.items.length - 1) % p.items.length }));
84371
84393
  else if (key.downArrow || key.tab) setPicker((p) => ({ ...p, index: (p.index + 1) % p.items.length }));
84372
84394
  else if (key.escape) setPicker(null);
84373
- else if (picker.kind === "model") {
84374
- const it = picker.items[picker.index];
84375
- const pick = (isDefault) => {
84376
- setPicker(null);
84377
- if (it.current && !isDefault) return;
84378
- modelRef.current = it.name;
84379
- engine2.send({ cmd: "model", name: it.name, default: isDefault });
84380
- };
84381
- if (key.return) pick(true);
84382
- else if (input === "s") pick(false);
84383
- else if (/^[1-9]$/.test(input) && Number(input) <= picker.items.length) setPicker((p) => ({ ...p, index: Number(input) - 1 }));
84384
- } else if (key.return) {
84385
- const it = picker.items[picker.index];
84395
+ else if (key.return) pick();
84396
+ else if (/^[1-9]$/.test(input) && Number(input) <= picker.items.length) setPicker((p) => ({ ...p, index: Number(input) - 1 }));
84397
+ return;
84398
+ }
84399
+ if (picker && picker.kind === "session") {
84400
+ const { rows } = sessionRows(picker, hello?.cwd);
84401
+ const move = (d) => setPicker((p) => {
84402
+ const n = rows.length;
84403
+ if (!n) return p;
84404
+ const index = (p.index + d + n) % n;
84405
+ const top = index < p.top ? index : index >= p.top + PICKER_ROWS ? index - PICKER_ROWS + 1 : p.top;
84406
+ return { ...p, index, top };
84407
+ });
84408
+ if (key.upArrow) move(-1);
84409
+ else if (key.downArrow || key.tab) move(1);
84410
+ else if (key.escape) setPicker(null);
84411
+ else if (key.return) {
84412
+ const it = rows[picker.index];
84413
+ if (!it) return;
84386
84414
  setPicker(null);
84387
84415
  if (it.live && it.live.here) {
84388
84416
  } else if (it.live && it.live.port) attachTo(it.live.port);
84389
84417
  else engine2.send({ cmd: "resume", name: it.name });
84390
- }
84418
+ } else if (key.ctrl && input === "a") setPicker((p) => ({ ...p, scope: p.scope === "here" ? "all" : "here", index: 0, top: 0 }));
84419
+ else if (key.backspace || key.delete) setPicker((p) => ({ ...p, query: p.query.slice(0, -1), index: 0, top: 0 }));
84420
+ else if (input && !key.ctrl && !key.meta && input >= " ") setPicker((p) => ({ ...p, query: p.query + input, index: 0, top: 0 }));
84391
84421
  return;
84392
84422
  }
84393
84423
  if (menu.length > 0) {
@@ -84462,7 +84492,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84462
84492
  break;
84463
84493
  }
84464
84494
  case "/image":
84465
- if (!hello?.images) append({ kind: "warn", text: "this engine does not take images; update hum" });
84495
+ if (!hello?.images) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
84466
84496
  else if (!arg) append({ kind: "info", text: "/image <path> attaches the file to your next message \xB7 ctrl+v pastes a screenshot \xB7 @path.png in a message works too" });
84467
84497
  else engine2.send({ cmd: "attach", path: arg });
84468
84498
  break;
@@ -84538,7 +84568,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84538
84568
  setPhaseBoth("busy");
84539
84569
  }
84540
84570
  };
84541
- const statusLine = phase === "connecting" ? "starting the engine \u2026" : `${modelRef.current || ""} \xB7 ${fmtCost(spend)}` + (ctxPct >= 10 ? ` \xB7 ctx ${ctxPct}%` : "") + (gate === "approve" ? " \xB7 approvals on" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
84571
+ const statusLine = phase === "connecting" ? "starting \u2026" : `${modelRef.current || ""} \xB7 ${fmtCost(spend)}` + (ctxPct >= 10 ? ` \xB7 ctx ${ctxPct}%` : "") + (gate === "approve" ? " \xB7 approvals on" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
84542
84572
  const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${status || "working"}${elapsed >= 2 ? ` \xB7 ${fmtDur(elapsed)}` : ""}` + (thinkChars.current > 4e3 ? ` \xB7 ${(thinkChars.current / 1e3).toFixed(0)}k thinking` : "");
84543
84573
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
84544
84574
  /* @__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: [
@@ -84727,13 +84757,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84727
84757
  ] }),
84728
84758
  picker && picker.kind === "model" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
84729
84759
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: "Select model" }),
84730
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `Your pick becomes the default for new sessions.${picker.via ? ` Served via ${picker.via}.` : ""}${picker.byo.length ? ` Your own keys: ${picker.byo.join(", ")} \u2014 /model <provider>/<model> uses one.` : ""}` }),
84760
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `Switch between open source models. Served via Metaphi AI.${picker.byo.length ? ` Your own keys: ${picker.byo.join(", ")} \u2014 /model <provider>/<model> uses one.` : ""}` }),
84731
84761
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
84732
84762
  (() => {
84733
84763
  const nameW = Math.max(...picker.items.map((m) => m.name.length + (m.current ? 2 : 0)));
84734
84764
  return picker.items.map((m, i) => {
84735
84765
  const price = m.price_per_m && m.price_per_m.length === 2 && (m.price_per_m[0] || m.price_per_m[1]) ? `$${m.price_per_m[0]}/$${m.price_per_m[1]} per M` : "";
84736
- const about = [m.note, price].filter(Boolean).join(" \xB7 ") + (m.default ? (m.note || price ? " \xB7 " : "") + "default" : "");
84766
+ const about = [m.note, price].filter(Boolean).join(" \xB7 ");
84737
84767
  const label = `${i + 1}. ${m.name}${m.current ? " \u2713" : ""}`.padEnd(nameW + 4);
84738
84768
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
84739
84769
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === picker.index ? "\u276F " : " " }),
@@ -84746,35 +84776,66 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84746
84776
  });
84747
84777
  })(),
84748
84778
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
84749
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to set as default \xB7 s to use this session only \xB7 Esc to cancel" })
84779
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to switch \xB7 Esc to cancel" })
84750
84780
  ] }),
84751
- picker && picker.kind === "session" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
84752
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
84753
- "pick a session to continue ",
84754
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "\xB7 enter continues \xB7 esc cancels" })
84755
- ] }),
84756
- picker.items.map((it, i) => {
84757
- const live = it.live ? it.live.here ? " \xB7 here" : ` \xB7 ${it.live.state || "running"}` : "";
84758
- const tail2 = (it.steps != null ? ` \xB7 ${plural(it.steps, "step")}` : " \xB7 on the server") + (it.cost_usd ? ` \xB7 ${fmtCost(it.cost_usd)}` : "") + (it.cwd ? ` \xB7 ${path2.basename(it.cwd)}` : "") + live;
84759
- const room = Math.max(16, width - 13 - tail2.length - 1);
84760
- const what = (it.instruction || "(untitled)").replace(/\s+/g, " ");
84761
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
84762
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "cyan", inverse: i === picker.index, children: (i === picker.index ? "\u276F " : " ") + (it.when || "").padEnd(9) }),
84763
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: i !== picker.index, color: it.live && !it.live.here ? "magenta" : void 0, children: [
84781
+ picker && picker.kind === "session" && (() => {
84782
+ const { rows, scope } = sessionRows(picker, hello?.cwd);
84783
+ const top = Math.min(picker.top, Math.max(0, rows.length - PICKER_ROWS));
84784
+ const shown = rows.slice(top, top + PICKER_ROWS);
84785
+ const out = [];
84786
+ let lastDir = null;
84787
+ shown.forEach((it, j) => {
84788
+ const i = top + j;
84789
+ if (it.dir !== lastDir) {
84790
+ out.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
84764
84791
  " ",
84765
- what.length > room ? what.slice(0, room - 1) + "\u2026" : what,
84766
- tail2
84767
- ] })
84768
- ] }, it.name);
84769
- })
84770
- ] }),
84792
+ it.dir || "(no directory)"
84793
+ ] }, `dir${i}`));
84794
+ lastDir = it.dir;
84795
+ }
84796
+ const sel = i === picker.index;
84797
+ const state = it.live ? it.live.here ? "this window" : it.live.state || "running" : null;
84798
+ const what = (it.instruction || "(untitled)").replace(/\s+/g, " ");
84799
+ const room = Math.max(16, width - 6 - (state ? state.length + 4 : 0));
84800
+ const meta = [it.when, it.steps != null ? plural(it.steps, "step") : "on the server", it.cost_usd ? fmtCost(it.cost_usd) : null, it.model].filter(Boolean).join(" \xB7 ");
84801
+ out.push(
84802
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", marginBottom: 1, children: [
84803
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
84804
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: sel ? "\u276F " : " " }),
84805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: sel, color: sel ? ACCENT : void 0, children: what.length > room ? what.slice(0, room - 1) + "\u2026" : what }),
84806
+ state ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "magenta", children: [
84807
+ " \xB7 ",
84808
+ state
84809
+ ] }) : null
84810
+ ] }),
84811
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
84812
+ " ",
84813
+ meta
84814
+ ] })
84815
+ ] }, it.name)
84816
+ );
84817
+ });
84818
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
84819
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: ACCENT, bold: true, children: [
84820
+ "Resume session ",
84821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `(${rows.length ? picker.index + 1 : 0} of ${rows.length})` })
84822
+ ] }),
84823
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { borderStyle: "round", borderColor: "gray", paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
84824
+ "\u2315 ",
84825
+ picker.query ? picker.query : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Search\u2026" })
84826
+ ] }) }),
84827
+ rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: " nothing matches" }) : out,
84828
+ top + PICKER_ROWS < rows.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `\u2193 ${rows.length - top - PICKER_ROWS} more` }) : null,
84829
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `Enter to continue \xB7 Ctrl+A to show ${scope === "here" ? "all directories" : "only this directory"} \xB7 Type to search \xB7 Esc to cancel` })
84830
+ ] });
84831
+ })(),
84771
84832
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, paddingX: 1, marginTop: 1, children: [
84772
84833
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "cyan", children: "\u276F " }),
84773
84834
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
84774
84835
  input_default,
84775
84836
  {
84776
84837
  ref: inputRef,
84777
- onPasteImage: () => hello?.images ? engine2.send({ cmd: "paste_image" }) : append({ kind: "warn", text: "this engine does not take images; update hum" }),
84838
+ onPasteImage: () => hello?.images ? engine2.send({ cmd: "paste_image" }) : append({ kind: "warn", text: "this version of hum does not take images; update hum" }),
84778
84839
  value,
84779
84840
  onChange: setValue,
84780
84841
  onSubmit,
@@ -85070,13 +85131,11 @@ var Engine = class {
85070
85131
 
85071
85132
  // src/cli.jsx
85072
85133
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
85073
- import fs5 from "node:fs";
85074
- import path4 from "node:path";
85075
85134
  import { spawnSync as spawnSync3 } from "node:child_process";
85076
85135
  var ENGINE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "ps", "stop", "hooks", "engine"]);
85077
85136
  var argv0 = process.argv.slice(2);
85078
85137
  if (argv0[0] === "--version" || argv0[0] === "-V") {
85079
- process.stdout.write(`hum ${true ? "0.1.20" : "0.0.0"}
85138
+ process.stdout.write(`hum ${true ? "0.1.22" : "0.0.0"}
85080
85139
  `);
85081
85140
  process.exit(0);
85082
85141
  }
@@ -85118,39 +85177,12 @@ if (!process.stdin.isTTY) {
85118
85177
  process.stderr.write('hum needs an interactive terminal; use `hum run "task"` when piping.\n');
85119
85178
  process.exit(1);
85120
85179
  }
85121
- var liveRuns = () => {
85122
- let out = [];
85123
- try {
85124
- for (const f of fs5.readdirSync(runDir())) {
85125
- if (!f.endsWith(".json")) continue;
85126
- try {
85127
- const r = JSON.parse(fs5.readFileSync(path4.join(runDir(), f), "utf8"));
85128
- if (r.port && r.session) out.push(r);
85129
- } catch {
85130
- }
85131
- }
85132
- } catch {
85133
- }
85134
- out.sort((a, b) => (b.updated || 0) - (a.updated || 0));
85135
- for (const r of out) {
85136
- try {
85137
- process.kill(r.pid, 0);
85138
- } catch {
85139
- r.dead = true;
85140
- }
85141
- }
85142
- return out.filter((r) => !r.dead);
85143
- };
85144
85180
  var port = Number(process.env.HUM_ENGINE_PORT || 0);
85145
85181
  var startedHere = false;
85146
85182
  try {
85147
85183
  if (!port) {
85148
- let rec = null;
85149
- if (!args.task && !args.resume && args.images.length === 0) rec = liveRuns()[0] || null;
85150
- if (!rec) {
85151
- rec = await spawnEngine(args.cwd, { task: args.task, images: args.images, resume: args.resume && args.resume !== "pick" ? args.resume : null });
85152
- startedHere = true;
85153
- }
85184
+ const rec = await spawnEngine(args.cwd, { task: args.task, images: args.images, resume: args.resume && args.resume !== "pick" ? args.resume : null });
85185
+ startedHere = true;
85154
85186
  port = rec.port;
85155
85187
  }
85156
85188
  } catch (exc) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Hum (हम): a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",