@metaphi-ai/hum 0.1.68 → 0.1.70

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 +244 -64
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -83589,7 +83589,7 @@ function runningVersion(candidates = engineCandidates(), opts = {}) {
83589
83589
  }
83590
83590
  return null;
83591
83591
  }
83592
- function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.68" : "" } = {}) {
83592
+ function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.70" : "" } = {}) {
83593
83593
  const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
83594
83594
  const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
83595
83595
  if (!refused) {
@@ -83811,6 +83811,7 @@ var agents_exports = {};
83811
83811
  __export(agents_exports, {
83812
83812
  alive: () => alive,
83813
83813
  fmtCost: () => fmtCost,
83814
+ grouped: () => grouped,
83814
83815
  liveRows: () => liveRows,
83815
83816
  needCount: () => needCount,
83816
83817
  peekSession: () => peekSession,
@@ -83844,6 +83845,8 @@ function rowOf(rec) {
83844
83845
  steps: Number(rec.steps || 0),
83845
83846
  spent_usd: Number(rec.spent_usd || 0),
83846
83847
  summary: rec.summary || "",
83848
+ agents: Number(rec.agents || 0),
83849
+ // the sub-agents it runs right now, from its own run file
83847
83850
  cwd: rec.cwd || "",
83848
83851
  port: rec.port || 0,
83849
83852
  updated: Number(rec.updated || 0)
@@ -83871,6 +83874,35 @@ function liveRows() {
83871
83874
  rows.sort((a, b) => rank(a) - rank(b) || b.updated - a.updated);
83872
83875
  return rows;
83873
83876
  }
83877
+ function grouped(rows) {
83878
+ const teams = /* @__PURE__ */ new Map();
83879
+ const loose = [];
83880
+ for (const r of rows) {
83881
+ if (!r.team) {
83882
+ loose.push(r);
83883
+ continue;
83884
+ }
83885
+ const g = teams.get(r.team) || { lead: null, workers: [] };
83886
+ if (r.role === "lead" && !g.lead) g.lead = r;
83887
+ else g.workers.push(r);
83888
+ teams.set(r.team, g);
83889
+ }
83890
+ const groups = [...teams.values()];
83891
+ for (const g of groups) {
83892
+ g.workers.sort((a, b) => rank(a) - rank(b) || b.updated - a.updated);
83893
+ const all = [g.lead, ...g.workers].filter(Boolean);
83894
+ g.best = Math.min(...all.map(rank));
83895
+ g.at = Math.max(...all.map((r) => r.updated));
83896
+ }
83897
+ groups.sort((a, b) => a.best - b.best || b.at - a.at);
83898
+ const out = [];
83899
+ for (const g of groups) {
83900
+ if (g.lead) out.push({ ...g.lead, depth: 0 });
83901
+ for (const w of g.workers) out.push({ ...w, depth: g.lead ? 1 : 0 });
83902
+ }
83903
+ for (const r of loose) out.push({ ...r, depth: 0 });
83904
+ return { rows: out, teams: groups.length };
83905
+ }
83874
83906
  function stopSession(row, done = () => {
83875
83907
  }) {
83876
83908
  const token2 = (readRun(row.run_id) || {}).token || "";
@@ -83929,7 +83961,7 @@ async function peekSession(row, ready, make = (port2, token2) => new Engine(port
83929
83961
  if (ev.type === "replay") {
83930
83962
  replay = ev.items || [];
83931
83963
  timer = setTimeout(() => settle(null), PEEK_SETTLE_MS);
83932
- } else if (ev.type === "question") settle(ev);
83964
+ } else if (ev.type === "question") settle(asked(ev));
83933
83965
  else if (ev.type === "bye") settle(null);
83934
83966
  });
83935
83967
  await engine2.connect();
@@ -83941,7 +83973,7 @@ async function peekSession(row, ready, make = (port2, token2) => new Engine(port
83941
83973
  }
83942
83974
  };
83943
83975
  }
83944
- var firstLine, rank, needCount, stateText, fmtCost, PEEK_SETTLE_MS;
83976
+ var firstLine, rank, needCount, stateText, fmtCost, PEEK_SETTLE_MS, asked;
83945
83977
  var init_agents = __esm({
83946
83978
  "src/agents.js"() {
83947
83979
  init_engine();
@@ -83951,6 +83983,11 @@ var init_agents = __esm({
83951
83983
  stateText = (r) => r.needs ? "needs you" : r.state === "busy" ? "working" : r.state;
83952
83984
  fmtCost = (c) => c >= 0.01 ? `$${c.toFixed(2)}` : c > 0 ? `$${c.toFixed(4)}` : "$0";
83953
83985
  PEEK_SETTLE_MS = 300;
83986
+ asked = (ev) => {
83987
+ const first = ev.questions && ev.questions[0] || ev;
83988
+ const options2 = (first.options || []).map((o) => typeof o === "string" ? { label: o } : o);
83989
+ return { ...ev, question: first.question || ev.question || "", options: options2, default: first.default ?? ev.default ?? null };
83990
+ };
83954
83991
  }
83955
83992
  });
83956
83993
 
@@ -85170,7 +85207,7 @@ __export(agents_exports2, {
85170
85207
  default: () => Agents
85171
85208
  });
85172
85209
  function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop = stopSession, everyMs = EVERY_MS }) {
85173
- const [rows, setRows] = (0, import_react25.useState)(() => read());
85210
+ const [rows, setRows] = (0, import_react25.useState)(() => grouped(read()).rows);
85174
85211
  const [index, setIndex] = (0, import_react25.useState)(0);
85175
85212
  const [open, setOpen] = (0, import_react25.useState)(null);
85176
85213
  const [value, setValue] = (0, import_react25.useState)("");
@@ -85178,7 +85215,7 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85178
85215
  const { stdout } = use_stdout_default();
85179
85216
  const width = stdout && stdout.columns || 100;
85180
85217
  (0, import_react25.useEffect)(() => {
85181
- const t = setInterval(() => setRows(read()), everyMs);
85218
+ const t = setInterval(() => setRows(grouped(read()).rows), everyMs);
85182
85219
  return () => clearInterval(t);
85183
85220
  }, [read, everyMs]);
85184
85221
  const row = rows[Math.min(index, Math.max(0, rows.length - 1))];
@@ -85240,7 +85277,7 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85240
85277
  setNote(`stopping ${row.name} \u2026`);
85241
85278
  stop(row, (ok) => {
85242
85279
  setNote(ok ? `stopped ${row.name}` : `could not stop ${row.name}`);
85243
- setRows(read());
85280
+ setRows(grouped(read()).rows);
85244
85281
  });
85245
85282
  } else if (input === "q") onQuit();
85246
85283
  });
@@ -85267,7 +85304,7 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85267
85304
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { borderStyle: "round", borderColor: "gray", paddingX: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: value || /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: q.default ? `enter takes the default: ${q.default}` : "your answer" }) }) }),
85268
85305
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: "enter answers and leaves \xB7 esc leaves it open" })
85269
85306
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
85270
- open.lines.length ? open.lines.slice(-PEEK_LINES).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: l.slice(0, width - 4) }, i)) : open.waiting ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: "nothing on its transcript yet" }),
85307
+ open.lines.length ? open.lines.slice(-PEEK_LINES2).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: l.slice(0, width - 4) }, i)) : open.waiting ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: "nothing on its transcript yet" }),
85271
85308
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
85272
85309
  "\n",
85273
85310
  "esc goes back"
@@ -85275,17 +85312,20 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85275
85312
  ] })
85276
85313
  ] });
85277
85314
  }
85278
- const nameW = 14;
85315
+ const nameW = 18;
85279
85316
  const roleW = 9;
85280
85317
  const stateW = 10;
85281
85318
  const needsW = 9;
85282
85319
  const stepsW = 6;
85283
85320
  const spentW = 8;
85321
+ const teams = new Set(rows.filter((r) => r.team).map((r) => r.team)).size;
85322
+ const count = `${rows.length} on this machine${teams ? ` \xB7 ${teams} team${teams === 1 ? "" : "s"}` : ""}`;
85323
+ const nameOf = (r) => `${" ".repeat(r.depth || 0)}${r.name}${r.agents ? ` +${r.agents}` : ""}`;
85284
85324
  const taskW = Math.max(12, width - 2 - (2 + nameW + roleW + stateW + needsW + stepsW + spentW + 6));
85285
85325
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
85286
85326
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: ACCENT, bold: true, children: [
85287
85327
  "Agents ",
85288
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: `(${rows.length} on this machine)` })
85328
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: `(${count})` })
85289
85329
  ] }),
85290
85330
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
85291
85331
  " ",
@@ -85306,7 +85346,7 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85306
85346
  rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", children: [
85307
85347
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { children: [
85308
85348
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { width: 2, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: ACCENT, children: i === index ? "\u276F" : "" }) }),
85309
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: i === index, children: pad(r.name, nameW) }),
85349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: i === index, children: pad(nameOf(r), nameW) }),
85310
85350
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
85311
85351
  " ",
85312
85352
  pad(r.role, roleW)
@@ -85342,7 +85382,7 @@ function Agents({ onAttach, onQuit, read = liveRows, peek = peekSession, stop =
85342
85382
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: FOOTER }) })
85343
85383
  ] });
85344
85384
  }
85345
- var import_react25, import_jsx_runtime3, EVERY_MS, PEEK_LINES, pad, padLeft, FOOTER;
85385
+ var import_react25, import_jsx_runtime3, EVERY_MS, PEEK_LINES2, pad, padLeft, FOOTER;
85346
85386
  var init_agents2 = __esm({
85347
85387
  async "src/agents.jsx"() {
85348
85388
  import_react25 = __toESM(require_react(), 1);
@@ -85351,7 +85391,7 @@ var init_agents2 = __esm({
85351
85391
  init_agents();
85352
85392
  import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
85353
85393
  EVERY_MS = 2e3;
85354
- PEEK_LINES = 20;
85394
+ PEEK_LINES2 = 20;
85355
85395
  pad = (s, n) => String(s || "").slice(0, n).padEnd(n);
85356
85396
  padLeft = (s, n) => String(s || "").slice(0, n).padStart(n);
85357
85397
  FOOTER = "\u2191\u2193 move \xB7 enter attach \xB7 space peek \xB7 s stop \xB7 q quit";
@@ -85568,7 +85608,7 @@ var input_default = MultilineInput;
85568
85608
 
85569
85609
  // src/app.jsx
85570
85610
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
85571
- var MINE = true ? "0.1.68" : "";
85611
+ var MINE = true ? "0.1.70" : "";
85572
85612
  var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
85573
85613
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
85574
85614
  var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
@@ -85675,6 +85715,7 @@ var REWIND_CHOICES = [
85675
85715
  { key: "both", label: "both", desc: "" }
85676
85716
  ];
85677
85717
  var ERR_TAIL_LINES = 5;
85718
+ var PEEK_LINES = 12;
85678
85719
  var THOUGHT_TAIL_LINES = 3;
85679
85720
  var diagLine = (d) => `${d.file ? `${d.file}${d.line != null ? `:${d.line}` : ""}: ` : ""}${d.severity || "error"}: ${d.message || ""}`;
85680
85721
  var toolLine = (text) => {
@@ -85691,7 +85732,7 @@ var tallyLine = (tally) => Object.entries(tally).map(([name, t]) => {
85691
85732
  const parts = [t.ok ? `${t.ok} ok` : null, t.failed ? `${t.failed} failed` : null, t.error ? `${t.error} error` : null].filter(Boolean);
85692
85733
  return `${short} ${parts.join(" \xB7 ")}`;
85693
85734
  }).join(" ");
85694
- function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2 = null }) {
85735
+ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2 = null, peek = peekSession }) {
85695
85736
  const { exit } = use_app_default();
85696
85737
  const { stdout } = use_stdout_default();
85697
85738
  const width = (stdout?.columns || 80) - 2;
@@ -85705,6 +85746,9 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85705
85746
  const [session, setSession] = (0, import_react24.useState)(null);
85706
85747
  const [spend, setSpend] = (0, import_react24.useState)(0);
85707
85748
  const [agents, setAgents] = (0, import_react24.useState)([]);
85749
+ const [panelIndex, setPanelIndex] = (0, import_react24.useState)(-1);
85750
+ const [looking, setLooking] = (0, import_react24.useState)(null);
85751
+ const lookRef = (0, import_react24.useRef)(null);
85708
85752
  const [draft, setDraft] = (0, import_react24.useState)("");
85709
85753
  const [thinking, setThinking] = (0, import_react24.useState)("");
85710
85754
  const [value, setValue] = (0, import_react24.useState)("");
@@ -85713,7 +85757,8 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85713
85757
  const [ctrlc, setCtrlc] = (0, import_react24.useState)(0);
85714
85758
  const [picker, setPicker] = (0, import_react24.useState)(null);
85715
85759
  const [proposal, setProposal] = (0, import_react24.useState)(null);
85716
- const [question, setQuestion] = (0, import_react24.useState)(null);
85760
+ const [questions, setQuestions] = (0, import_react24.useState)([]);
85761
+ const question = questions.length ? questions[0] : null;
85717
85762
  const [qStep, setQStep] = (0, import_react24.useState)(0);
85718
85763
  const [qAnswers, setQAnswers] = (0, import_react24.useState)({});
85719
85764
  const [qPicks, setQPicks] = (0, import_react24.useState)([]);
@@ -85739,6 +85784,7 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85739
85784
  const modelRef = (0, import_react24.useRef)("");
85740
85785
  const lastOutRef = (0, import_react24.useRef)(null);
85741
85786
  const helloRef = (0, import_react24.useRef)(false);
85787
+ const asksRef = (0, import_react24.useRef)([]);
85742
85788
  const startedRef = (0, import_react24.useRef)(false);
85743
85789
  const escRef = (0, import_react24.useRef)(0);
85744
85790
  const rewindRef = (0, import_react24.useRef)({ files: true, conversation: true });
@@ -85751,6 +85797,37 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85751
85797
  setPhase(p);
85752
85798
  };
85753
85799
  const append = (item) => setItems((prev) => [...prev, { id: nextId.current++, ...item }]);
85800
+ const setAsks = (next) => {
85801
+ asksRef.current = next;
85802
+ setQuestions(next);
85803
+ };
85804
+ const restartAsk = () => {
85805
+ setQStep(0);
85806
+ setQAnswers({});
85807
+ setQPicks([]);
85808
+ setQCursor(0);
85809
+ };
85810
+ const askOf = (ev) => ({
85811
+ id: ev.id,
85812
+ question: ev.question || "",
85813
+ options: ev.options || [],
85814
+ default: ev.default || null,
85815
+ questions: ev.questions || null,
85816
+ kind: ev.kind || null,
85817
+ summary: ev.summary || "",
85818
+ evidence: ev.evidence || []
85819
+ });
85820
+ const addAsk = (ev) => {
85821
+ if (asksRef.current.some((q) => q.id === ev.id)) return;
85822
+ const shown = asksRef.current.length > 0;
85823
+ setAsks([...asksRef.current, askOf(ev)]);
85824
+ if (!shown) restartAsk();
85825
+ };
85826
+ const dropAsk = (id) => {
85827
+ const wasShown = asksRef.current.length > 0 && asksRef.current[0].id === id;
85828
+ setAsks(asksRef.current.filter((q) => q.id !== id));
85829
+ if (wasShown) restartAsk();
85830
+ };
85754
85831
  const steps = question ? question.questions && question.questions.length ? question.questions : [{ id: question.id, question: question.question, options: (question.options || []).map((o) => ({ label: o })), default: question.default }] : [];
85755
85832
  const step = steps.length ? steps[Math.min(qStep, steps.length - 1)] : null;
85756
85833
  const stepOptions = step ? (step.options || []).map((o) => typeof o === "string" ? { label: o } : o) : [];
@@ -85775,6 +85852,8 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85775
85852
  };
85776
85853
  const resetForSession = () => {
85777
85854
  setAgents([]);
85855
+ setPanelIndex(-1);
85856
+ closeLook();
85778
85857
  setItems([]);
85779
85858
  setDraft("");
85780
85859
  draftRef.current = "";
@@ -85782,11 +85861,8 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85782
85861
  setThinking("");
85783
85862
  thinkChars.current = 0;
85784
85863
  setProposal(null);
85785
- setQuestion(null);
85786
- setQStep(0);
85787
- setQAnswers({});
85788
- setQPicks([]);
85789
- setQCursor(0);
85864
+ setAsks([]);
85865
+ restartAsk();
85790
85866
  setPaused(false);
85791
85867
  setPicker(null);
85792
85868
  setConfirm(null);
@@ -85802,6 +85878,30 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85802
85878
  wroteRef.current = false;
85803
85879
  setMeter((m) => ({ ...m, tokens: 0, input: 0, output: 0 }));
85804
85880
  };
85881
+ const closeLook = () => {
85882
+ if (lookRef.current && lookRef.current.handle) lookRef.current.handle.close();
85883
+ lookRef.current = null;
85884
+ setLooking(null);
85885
+ };
85886
+ const showLook = (v) => {
85887
+ lookRef.current = v;
85888
+ setLooking(v);
85889
+ };
85890
+ const openLook = async (a) => {
85891
+ const row = { run_id: String(a.n), name: a.name || String(a.n), port: (readRun(String(a.n)) || {}).port || 0, task: a.desc || "" };
85892
+ showLook({ row, question: null, lines: [], waiting: true, handle: null });
85893
+ const here = () => lookRef.current && lookRef.current.row.run_id === row.run_id;
85894
+ try {
85895
+ const handle2 = await peek(row, ({ question: question2, lines }) => {
85896
+ if (here()) showLook({ ...lookRef.current, question: question2, lines, waiting: false });
85897
+ });
85898
+ if (here()) showLook({ ...lookRef.current, handle: handle2 });
85899
+ else handle2.close();
85900
+ } catch (e) {
85901
+ showLook(null);
85902
+ append({ kind: "warn", text: `could not look at ${row.name}: ${e.message}` });
85903
+ }
85904
+ };
85805
85905
  const flushDraft = () => {
85806
85906
  const d = draftRef.current.trim();
85807
85907
  draftRef.current = "";
@@ -85840,9 +85940,12 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85840
85940
  }
85841
85941
  }
85842
85942
  switch (ev.type) {
85843
- case "agents":
85844
- setAgents(ev.items || []);
85943
+ case "agents": {
85944
+ const items2 = ev.items || [];
85945
+ setAgents(items2);
85946
+ setPanelIndex((i) => i >= items2.length ? items2.length - 1 : i);
85845
85947
  break;
85948
+ }
85846
85949
  case "agent_start":
85847
85950
  foldThinking();
85848
85951
  flushDraft();
@@ -85866,6 +85969,7 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
85866
85969
  setMeter((m) => ({ ...m, tokens: 0, cap: ev.compact_at || 0 }));
85867
85970
  setGate(ev.gate === "approve" ? "approve" : "off");
85868
85971
  if (ev.session) setSession(ev.session);
85972
+ (ev.questions || []).forEach(addAsk);
85869
85973
  if (ev.fresh) append({ kind: "wordmark" });
85870
85974
  setLatest({ version: ev.version || "", latest_version: ev.latest_version || "", release_notes_url: ev.release_notes_url || "" });
85871
85975
  append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE), instruction: ev.session ? ev.instruction : null });
@@ -86076,27 +86180,10 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86076
86180
  case "question":
86077
86181
  foldThinking();
86078
86182
  flushDraft();
86079
- setQuestion({
86080
- id: ev.id,
86081
- question: ev.question || "",
86082
- options: ev.options || [],
86083
- default: ev.default || null,
86084
- questions: ev.questions || null,
86085
- kind: ev.kind || null,
86086
- summary: ev.summary || "",
86087
- evidence: ev.evidence || []
86088
- });
86089
- setQStep(0);
86090
- setQAnswers({});
86091
- setQPicks([]);
86092
- setQCursor(0);
86183
+ addAsk(ev);
86093
86184
  break;
86094
86185
  case "question_closed":
86095
- setQuestion(null);
86096
- setQStep(0);
86097
- setQAnswers({});
86098
- setQPicks([]);
86099
- setQCursor(0);
86186
+ dropAsk(ev.id);
86100
86187
  append({ kind: "info", text: `answered: ${ev.answer}` });
86101
86188
  break;
86102
86189
  case "mcp":
@@ -86322,6 +86409,38 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86322
86409
  }
86323
86410
  return;
86324
86411
  }
86412
+ if (looking) {
86413
+ if (key.escape || key.return && !looking.question) {
86414
+ closeLook();
86415
+ return;
86416
+ }
86417
+ return;
86418
+ }
86419
+ const panelOpen = agents.length > 0 && !value && !picker && !confirm && !proposal && !question && !reflection;
86420
+ if (panelOpen && panelIndex < 0 && key.downArrow) {
86421
+ setPanelIndex(0);
86422
+ return;
86423
+ }
86424
+ if (panelOpen && panelIndex >= 0) {
86425
+ if (key.downArrow) {
86426
+ setPanelIndex((i) => Math.min(i + 1, agents.length - 1));
86427
+ return;
86428
+ }
86429
+ if (key.upArrow) {
86430
+ setPanelIndex((i) => i - 1);
86431
+ return;
86432
+ }
86433
+ if (key.escape) {
86434
+ setPanelIndex(-1);
86435
+ return;
86436
+ }
86437
+ if (key.return) {
86438
+ const a = agents[panelIndex];
86439
+ if (a && a.worker) openLook(a);
86440
+ return;
86441
+ }
86442
+ if (input && !key.ctrl && !key.meta && input >= " ") setPanelIndex(-1);
86443
+ }
86325
86444
  if (confirm && !picker) {
86326
86445
  if (key.return) {
86327
86446
  setConfirm(null);
@@ -86561,11 +86680,7 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86561
86680
  setQCursor(0);
86562
86681
  return;
86563
86682
  }
86564
- setQuestion(null);
86565
- setQStep(0);
86566
- setQAnswers({});
86567
- setQPicks([]);
86568
- setQCursor(0);
86683
+ dropAsk(question.id);
86569
86684
  engine2.send({ cmd: "answer", id: question.id, answers });
86570
86685
  };
86571
86686
  const vote = (polarity, why2 = "") => {
@@ -86680,6 +86795,15 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86680
86795
  closeReflection(reflection.id, "down", text);
86681
86796
  return;
86682
86797
  }
86798
+ if (looking) {
86799
+ const l = looking;
86800
+ if (l.question && l.handle) {
86801
+ l.handle.answer(l.question.id, text);
86802
+ append({ kind: "info", text: `answered ${l.row.name}${text ? `: ${text}` : ""}` });
86803
+ }
86804
+ closeLook();
86805
+ return;
86806
+ }
86683
86807
  if (!text && attached.length === 0) return;
86684
86808
  if (!text && proposal) return;
86685
86809
  const hist = historyRef.current;
@@ -86716,10 +86840,10 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86716
86840
  setPhaseBoth("busy");
86717
86841
  }
86718
86842
  };
86719
- 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");
86843
+ 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" : "") + (agents.length && panelIndex < 0 && !looking ? " \xB7 \u2193 agents" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
86720
86844
  const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${status || "working"}${elapsed >= 2 ? ` \xB7 ${fmtDur(elapsed)}` : ""}` + (thinkChars.current > 4e3 ? ` \xB7 ${(thinkChars.current / 1e3).toFixed(0)}k thinking` : "");
86721
86845
  const rows = stdout?.rows || DEFAULT_ROWS;
86722
- 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);
86846
+ const chrome = 1 + 2 + 4 + (value.split("\n").length - 1) + 1 + (menu.length ? menu.length : 0) + (!menu.length && agents.length ? agents.length + 1 : 0) + (looking ? 4 + (looking.question ? (looking.question.options || []).length + 2 : Math.min(PEEK_LINES, looking.lines.length) + 1) : 0) + (question && step ? 6 + stepOptions.length + (questions.length > 1 ? 1 : 0) + (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);
86723
86847
  const liveBudget = Math.max(LIVE_MIN_ROWS, Math.min(DRAFT_TAIL_LINES, rows - 1 - chrome));
86724
86848
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
86725
86849
  /* @__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: [
@@ -86885,6 +87009,7 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86885
87009
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: spinnerLabel })
86886
87010
  ] }),
86887
87011
  question && step && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: ACCENT, paddingX: 1, marginTop: 1, children: [
87012
+ questions.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: ` 1 of ${questions.length} open asks \xB7 the oldest first` }) : null,
86888
87013
  (question.kind === "feedback" || question.kind === "decision") && qStep === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", marginBottom: 1, children: [
86889
87014
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: question.kind === "decision" ? "\u2726 Decision Review" : "\u2726 hum asks for your judgment" }) }),
86890
87015
  question.summary.split("\n").map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: ` ${l}` }, `s${i}`)),
@@ -86999,6 +87124,38 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
86999
87124
  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
87000
87125
  ] }, c.id))
87001
87126
  ] }),
87127
+ looking && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, marginTop: 1, children: [
87128
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87129
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", bold: true, children: looking.row.name }),
87130
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87131
+ " ",
87132
+ looking.row.task.slice(0, width - 20)
87133
+ ] })
87134
+ ] }),
87135
+ looking.waiting ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "looking \u2026" }) : null,
87136
+ looking.question ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
87137
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87138
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: "? " }),
87139
+ looking.question.question
87140
+ ] }),
87141
+ (looking.question.options || []).map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87142
+ " ",
87143
+ i + 1,
87144
+ ". ",
87145
+ typeof o === "string" ? o : o.label,
87146
+ o && o.description ? ` \xB7 ${o.description}` : ""
87147
+ ] }, i)),
87148
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87149
+ " ",
87150
+ "type the answer \xB7 enter answers and leaves",
87151
+ looking.question.default ? ` (empty takes the default: ${looking.question.default})` : "",
87152
+ " \xB7 esc leaves it open"
87153
+ ] })
87154
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
87155
+ looking.lines.length ? looking.lines.slice(-PEEK_LINES).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: l.slice(0, width - 4) }, i)) : looking.waiting ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "nothing on its transcript yet" }),
87156
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "esc goes back" })
87157
+ ] })
87158
+ ] }),
87002
87159
  picker && picker.kind === "update" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
87003
87160
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87004
87161
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "yellow", children: "\u2728 " }),
@@ -87190,7 +87347,7 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
87190
87347
  onChange: setValue,
87191
87348
  onSubmit,
87192
87349
  focus: phase !== "dead" && !picker && !confirm,
87193
- navActive: menu.length === 0,
87350
+ navActive: menu.length === 0 && panelIndex < 0 && !looking,
87194
87351
  history: historyRef.current,
87195
87352
  mask: !!(step && step.secret),
87196
87353
  swallow: (input, key) => {
@@ -87215,24 +87372,47 @@ function App2({ engine: engine2, task, resume, images = [], onUpdate: onUpdate2
87215
87372
  ] }, c.name)),
87216
87373
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "tab to complete \xB7 enter to run" })
87217
87374
  ] }),
87218
- !menu.length && agents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
87375
+ !menu.length && agents.length > 0 && // one flat list: ○ a sub-agent of this process, ◇ a worker session of the team (its state, what it needs,
87376
+ // +N sub-agents of its own); the engine puts what wants a person first. ↓ moves a highlight in from the box
87377
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
87219
87378
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
87379
+ " ",
87220
87380
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", children: "\u25CF" }),
87221
87381
  " main"
87222
87382
  ] }),
87223
- agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
87224
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", children: "\u25CB " }),
87225
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: String(a.kind).padEnd(10) }),
87226
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: a.desc }),
87227
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87228
- " ",
87229
- fmtDur(a.elapsed_s || 0),
87230
- " \xB7 ",
87231
- plural(a.steps || 0, "step"),
87232
- " \xB7 ",
87233
- fmtTokens(a.tokens),
87234
- " \xB7 ",
87235
- fmtCost2(a.cost_usd || 0)
87383
+ agents.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
87384
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === panelIndex ? "\u276F " : " " }),
87385
+ a.worker ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
87386
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", children: "\u25C7 " }),
87387
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: i === panelIndex, children: `${a.kind} worker`.padEnd(16) }),
87388
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: a.desc }),
87389
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: a.needs ? "yellow" : void 0, dimColor: !a.needs, children: [
87390
+ " \xB7 ",
87391
+ a.needs ? `needs ${a.needs}` : a.state
87392
+ ] }),
87393
+ a.agents ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", children: ` +${a.agents}` }) : null,
87394
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87395
+ " ",
87396
+ fmtDur(a.elapsed_s || 0),
87397
+ " \xB7 ",
87398
+ plural(a.steps || 0, "step"),
87399
+ " \xB7 ",
87400
+ fmtCost2(a.cost_usd || 0)
87401
+ ] })
87402
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
87403
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "magenta", children: "\u25CB " }),
87404
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: i === panelIndex, children: String(a.kind).padEnd(10) }),
87405
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: a.desc }),
87406
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
87407
+ " ",
87408
+ fmtDur(a.elapsed_s || 0),
87409
+ " \xB7 ",
87410
+ plural(a.steps || 0, "step"),
87411
+ " \xB7 ",
87412
+ fmtTokens(a.tokens),
87413
+ " \xB7 ",
87414
+ fmtCost2(a.cost_usd || 0)
87415
+ ] })
87236
87416
  ] })
87237
87417
  ] }, a.n))
87238
87418
  ] }),
@@ -87246,7 +87426,7 @@ init_update();
87246
87426
  init_install();
87247
87427
  var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
87248
87428
  import { spawnSync as spawnSync5 } from "node:child_process";
87249
- var MINE2 = true ? "0.1.68" : "0.0.0";
87429
+ var MINE2 = true ? "0.1.70" : "0.0.0";
87250
87430
  var layout = installLayout();
87251
87431
  function completeInstall() {
87252
87432
  if (layout.kind !== "npm" || !needsInstall(MINE2)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.1.68",
3
+ "version": "0.1.70",
4
4
  "description": "Hum: a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",