@metaphi-ai/hum 0.2.26 → 0.2.28

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 +232 -135
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -89037,7 +89037,7 @@ var win, MINE, npmFix, NPM_FIX, humHome, versionsDir, versionDir, pkgDir, coreDi
89037
89037
  var init_install = __esm({
89038
89038
  "src/install.js"() {
89039
89039
  win = process.platform === "win32";
89040
- MINE = true ? "0.2.26" : "";
89040
+ MINE = true ? "0.2.28" : "";
89041
89041
  npmFix = (version = "") => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
89042
89042
  NPM_FIX = npmFix("latest");
89043
89043
  humHome = (env3 = process.env) => env3.HUM_HOME || path.join(os3.homedir(), ".hum");
@@ -89382,10 +89382,10 @@ function clientEnv() {
89382
89382
  platform: process.platform,
89383
89383
  arch: process.arch,
89384
89384
  terminal: process.env.TERM_PROGRAM || (process.env.WT_SESSION ? "Windows Terminal" : process.env.TERM || ""),
89385
- tui: true ? "0.2.26" : ""
89385
+ tui: true ? "0.2.28" : ""
89386
89386
  };
89387
89387
  }
89388
- function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.26" : "" } = {}) {
89388
+ function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.2.28" : "" } = {}) {
89389
89389
  const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
89390
89390
  const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
89391
89391
  if (!refused) {
@@ -90490,18 +90490,24 @@ init_wrap_ansi2();
90490
90490
  await init_markdown();
90491
90491
  var optionRows = (step, options2, width, picks, cursor) => {
90492
90492
  const digits = String(options2.length).length;
90493
- return options2.flatMap((o, i) => {
90494
- const lead = `${i === cursor ? "\u203A " : " "}${String(i + 1).padStart(digits)}. ${step.multi ? `[${picks.includes(o.label) ? "x" : " "}] ` : ""}`;
90493
+ const lines = [];
90494
+ let at = [0, 0];
90495
+ options2.forEach((o, i) => {
90496
+ const lead = `${i === cursor ? "\u203A " : " "}${String(i + 1).padStart(digits)}. ${step.multi && !o.own ? `[${picks.includes(o.label) ? "x" : " "}] ` : ""}`;
90495
90497
  const said = String(o.description || "");
90496
90498
  const desc = /[\x60*_]/.test(said) ? renderMarkdown(said, 1e3).trim() : said;
90497
90499
  const body = `${source_default.bold(o.label)}${step.default === o.label ? " (default)" : ""}${desc ? source_default.dim(` \u2014 ${desc}`) : ""}`;
90498
- return wrapAnsi2(body, Math.max(8, width - lead.length), { hard: true, trim: true }).split("\n").map((line, j) => (j ? " ".repeat(lead.length) : i === cursor ? source_default.hex(ACCENT)(lead) : lead) + line);
90500
+ const from = lines.length;
90501
+ lines.push(...wrapAnsi2(body, Math.max(8, width - lead.length), { hard: true, trim: true }).split("\n").map((line, j) => (j ? " ".repeat(lead.length) : i === cursor ? source_default.hex(ACCENT)(lead) : lead) + line));
90502
+ if (i === cursor) at = [from, lines.length];
90499
90503
  });
90504
+ return { lines, at };
90500
90505
  };
90506
+ var OWN_ANSWER = { label: "Something else", description: "type your own answer", own: true };
90501
90507
  var cell = (s) => String(s || "").replaceAll("\\", "\\\\").replaceAll("|", "\\|").replace(/\r?\n/g, " ");
90502
90508
  function consultBody(question, step, width, picks = [], cursor = 0) {
90503
90509
  const parts = [];
90504
- let choices = [];
90510
+ let choices = { lines: [], at: [0, 0] };
90505
90511
  if (question.kind === "constraints") {
90506
90512
  const rows = (question.questions || []).filter((q) => q.id !== "missed");
90507
90513
  if (width >= 60) {
@@ -90520,24 +90526,37 @@ ${q.question}`).join("\n\n"));
90520
90526
  if (step.header) parts.push(`**${step.header}**`);
90521
90527
  parts.push(step.question);
90522
90528
  const options2 = (step.options || []).map((o) => typeof o === "string" ? { label: o } : o);
90523
- if (question.kind === "decision" && options2.length && width >= 60 && !options2.some((o) => /\n/.test(o.description || ""))) {
90524
- parts.push([
90525
- "| # | Choice | Consequences |",
90526
- "| --- | --- | --- |",
90527
- ...options2.map((o, i) => `| ${i + 1} | ${cell(o.label)} | ${cell(o.description)} |`)
90528
- ].join("\n"));
90529
- } else if (options2.length) {
90530
- choices = optionRows(step, options2, width, picks, cursor);
90531
- }
90529
+ if (options2.length) choices = optionRows(step, [...options2, OWN_ANSWER], width, picks, cursor);
90532
90530
  }
90533
- const read = (md) => md.length ? wrapAnsi2(
90534
- renderMarkdown(md.filter(Boolean).join("\n\n"), width),
90535
- width,
90536
- { hard: true, trim: false }
90537
- ).split("\n") : [];
90538
90531
  const evidence = question.evidence?.length ? ["**Evidence**\n\n" + question.evidence.join("\n\n")] : [];
90539
- if (!choices.length) return read([...parts, ...evidence]);
90540
- return [...read(parts), "", ...choices, ...evidence.length ? ["", ...read(evidence)] : []];
90532
+ const md = [...parts, ...evidence].filter(Boolean);
90533
+ const text = md.length ? wrapAnsi2(renderMarkdown(md.join("\n\n"), width), width, { hard: true, trim: false }).split("\n") : [];
90534
+ return { text, rows: choices.lines, at: choices.at };
90535
+ }
90536
+ function consultWindow({ text, rows, at }, height, top) {
90537
+ const rowsHeight = Math.min(rows.length, height - (text.length ? 1 : 0));
90538
+ const textHeight = Math.min(text.length, height - rowsHeight);
90539
+ const textStart = Math.max(0, Math.min(top, text.length - textHeight));
90540
+ const rowsStart = at[1] <= rowsHeight ? 0 : Math.min(at[0], rows.length - rowsHeight);
90541
+ return {
90542
+ textHeight,
90543
+ textStart,
90544
+ shownText: text.slice(textStart, textStart + textHeight),
90545
+ shownRows: rows.slice(rowsStart, rowsStart + rowsHeight)
90546
+ };
90547
+ }
90548
+ function pickOf(step, said) {
90549
+ const word = String(said ?? "").trim();
90550
+ const labels = (step.options || []).map((o) => typeof o === "string" ? o : o.label);
90551
+ const nth = (t) => /^\d+$/.test(t) && Number(t) >= 1 && Number(t) <= labels.length ? labels[Number(t) - 1] : null;
90552
+ if (!word || !labels.length) return { pick: null, why: word };
90553
+ if (step.multi && word.includes(",")) {
90554
+ const each = word.split(",").map((t) => nth(t.trim()));
90555
+ return each.every(Boolean) ? { pick: each.join(", "), why: "" } : { pick: null, why: word };
90556
+ }
90557
+ const head = step.graded ? word.split(/\s+/)[0] : word;
90558
+ const named = nth(head) || labels.find((l) => l.toLowerCase() === word.toLowerCase()) || null;
90559
+ return named ? { pick: named, why: nth(head) ? word.slice(head.length).trim() : "" } : { pick: null, why: word };
90541
90560
  }
90542
90561
 
90543
90562
  // src/wordmark.js
@@ -90868,10 +90887,11 @@ var after = (ms, fn) => {
90868
90887
 
90869
90888
  // src/app.jsx
90870
90889
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
90871
- var MINE2 = true ? "0.2.26" : "";
90890
+ var MINE2 = true ? "0.2.28" : "";
90872
90891
  var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
90873
90892
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
90874
90893
  var shortSession = (name) => (name || "").replace(/\.jsonl$/, "");
90894
+ var PLAN_GLYPH = { completed: "\u2714", in_progress: "\u25A1", pending: "\u25A1" };
90875
90895
  var HYPOTHESIS_GLYPH = { candidate: "\u25FB", testing: "\u25B8", supported: "\u25FC", refuted: "\u2717", superseded: "\u21B7", blocked: "\u2016" };
90876
90896
  var PICKER_ROWS = 8;
90877
90897
  var sessionRows = (p, here) => {
@@ -90977,6 +90997,7 @@ var readPaste = (n) => {
90977
90997
  var DRAFT_TAIL_LINES = 14;
90978
90998
  var LIVE_MIN_ROWS = 3;
90979
90999
  var DEFAULT_ROWS = 24;
91000
+ var ELAPSED_TICK_MS = 1e3;
90980
91001
  var liveTail = (text, width, rows) => {
90981
91002
  const l = wrapAnsi2(text, Math.max(20, width), { hard: true, trim: false }).split("\n");
90982
91003
  return l.length <= rows ? l.join("\n") : "\u2026\n" + l.slice(-(rows - 1)).join("\n");
@@ -91043,7 +91064,6 @@ var REWIND_CHOICES = [
91043
91064
  ];
91044
91065
  var ERR_TAIL_LINES = 5;
91045
91066
  var PEEK_LINES = 12;
91046
- var THOUGHT_TAIL_LINES = 3;
91047
91067
  var FILE_DEPTH = 3;
91048
91068
  var FILE_CAP = 200;
91049
91069
  var FILE_ROWS = 8;
@@ -91093,6 +91113,15 @@ var ToolRow = ({ text, tail: tail2 }) => /* @__PURE__ */ (0, import_jsx_runtime3
91093
91113
  tail2 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: tail2 }) : null
91094
91114
  ] })
91095
91115
  ] });
91116
+ var CONTINUES = /* @__PURE__ */ new Set(["tool_result", "diff", "errtail", "spool", "agent_end", "thought"]);
91117
+ var continuesBlock = (item) => !!item.agent || CONTINUES.has(item.kind);
91118
+ var blockGap = (item) => continuesBlock(item) ? 0 : 1;
91119
+ var rowStands = (call) => !!call && (call.lines != null || !!call.diff);
91120
+ var callLabel = (ev) => ev.lines != null ? `${ev.desc || ev.name} (${ev.lines} lines)` : ev.desc || ev.name;
91121
+ var Hang = ({ lead, children }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { children: [
91122
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { width: lead.length, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: lead }) }),
91123
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children })
91124
+ ] });
91096
91125
  var tickTail = (t0) => {
91097
91126
  const s = Math.floor((Date.now() - t0) / 1e3);
91098
91127
  return s >= 1 ? ` \xB7 ${fmtDur(s)}` : "";
@@ -91132,6 +91161,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
91132
91161
  const [transcriptEpoch, setTranscriptEpoch] = (0, import_react38.useState)(0);
91133
91162
  const [phase, setPhase] = (0, import_react38.useState)("connecting");
91134
91163
  const [status, setStatus] = (0, import_react38.useState)("");
91164
+ const [statusOf, setStatusOf] = (0, import_react38.useState)("");
91135
91165
  const [hello, setHello] = (0, import_react38.useState)(null);
91136
91166
  const [latest, setLatest] = (0, import_react38.useState)(null);
91137
91167
  const [ready, setReady] = (0, import_react38.useState)("");
@@ -91144,7 +91174,7 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
91144
91174
  const [looking, setLooking] = (0, import_react38.useState)(null);
91145
91175
  const lookRef = (0, import_react38.useRef)(null);
91146
91176
  const [draft, setDraft] = (0, import_react38.useState)("");
91147
- const [thinking, setThinking] = (0, import_react38.useState)("");
91177
+ const [planSteps, setPlanSteps] = (0, import_react38.useState)([]);
91148
91178
  const [value, setValue] = (0, import_react38.useState)("");
91149
91179
  const [menuIndex, setMenuIndex] = (0, import_react38.useState)(0);
91150
91180
  const [atShut, setAtShut] = (0, import_react38.useState)("");
@@ -91180,9 +91210,12 @@ function App2({ core: core2, task, resume, images = [], peek = peekSession, upda
91180
91210
  const turnT0 = (0, import_react38.useRef)(null);
91181
91211
  const thinkT0 = (0, import_react38.useRef)(null);
91182
91212
  const thinkChars = (0, import_react38.useRef)(0);
91213
+ const thinkText = (0, import_react38.useRef)("");
91183
91214
  const draftRef = (0, import_react38.useRef)("");
91184
91215
  const thoughtRef = (0, import_react38.useRef)(null);
91216
+ const ledRef = (0, import_react38.useRef)(null);
91185
91217
  const toolsRef = (0, import_react38.useRef)({});
91218
+ const proposedRef = (0, import_react38.useRef)(/* @__PURE__ */ new Set());
91186
91219
  const historyRef = (0, import_react38.useRef)(loadHistory());
91187
91220
  const modelRef = (0, import_react38.useRef)("");
91188
91221
  const heldRef = (0, import_react38.useRef)({ reads: [], calls: [] });
@@ -91258,7 +91291,7 @@ ${r.content}`).join("\n\n") };
91258
91291
  return true;
91259
91292
  }
91260
91293
  printHeld(rest);
91261
- push(rowOf2(keepOut(ev.name, ev.content)));
91294
+ if (rowOf2) push(rowOf2(keepOut(ev.name, ev.content)));
91262
91295
  return false;
91263
91296
  };
91264
91297
  const setAsks = (next) => {
@@ -91283,6 +91316,16 @@ ${r.content}`).join("\n\n") };
91283
91316
  summary: ev.summary || "",
91284
91317
  evidence: ev.evidence || []
91285
91318
  });
91319
+ const ASK_TITLES = { decision: "Decision", review: "Review", constraints: "Constraints" };
91320
+ const answeredItem = (ask, ev) => {
91321
+ const qs = ask ? ask.questions && ask.questions.length ? ask.questions : [{ id: ask.id, question: ask.question, options: ask.options, default: ask.default }] : [];
91322
+ const given = ev.answers || {};
91323
+ const entries = qs.filter((q) => given[q.id]).map((q) => ({ question: q.question, ...pickOf(q, given[q.id]) }));
91324
+ const whole = entries.length ? [] : [{ question: "", pick: null, why: String(given.reply ?? ev.answer ?? "") }];
91325
+ const count = qs.length > 1 && entries.length ? `${entries.length}/${qs.length} ` : "";
91326
+ const via = ev.via ? ` \xB7 from ${ev.via[0].toUpperCase()}${ev.via.slice(1)}` : "";
91327
+ return { kind: "answered", title: `\u2726 ${ASK_TITLES[ask?.kind] || "Clarification"} \xB7 ${count}answered${via}`, entries: [...entries, ...whole] };
91328
+ };
91286
91329
  const addAsk = (ev) => {
91287
91330
  if (asksRef.current.some((q) => q.id === ev.id)) return;
91288
91331
  const shown = asksRef.current.length > 0;
@@ -91300,26 +91343,30 @@ ${r.content}`).join("\n\n") };
91300
91343
  const stepLabels = stepOptions.map((o) => o.label);
91301
91344
  const listAsk = !!(question && question.kind === "constraints" && question.questions && question.questions.length);
91302
91345
  const listRows = listAsk ? question.questions.filter((q) => q.id !== "missed") : [];
91303
- const typedRow = /^[1-9]$/.test(value.trim()) && Number(value.trim()) <= stepLabels.length ? Number(value.trim()) - 1 : null;
91304
- const choiceRow = step && !step.multi && !listAsk && question.kind !== "decision" ? typedRow ?? qChoice ?? stepLabels.indexOf(step.default) : -1;
91305
- const consultLines = (0, import_react38.useMemo)(
91306
- () => question && step ? consultBody(question, step, Math.max(20, width - 4), qPicks, step.multi ? qCursor : choiceRow) : [],
91346
+ const typedHead = step && step.graded ? value.trim().split(/\s+/)[0] : value.trim();
91347
+ const typedRow = /^[1-9]$/.test(typedHead) && Number(typedHead) <= stepLabels.length ? Number(typedHead) - 1 : null;
91348
+ const choiceRow = step && !step.multi && !listAsk ? typedRow ?? qChoice ?? stepLabels.indexOf(step.default) : -1;
91349
+ const ownRow = stepLabels.length;
91350
+ const ownMarked = !!(step && ownRow && !listAsk && typedRow === null && (step.multi ? qCursor : qChoice) === ownRow);
91351
+ const markedPick = step && step.graded && !step.multi && !listAsk && qChoice !== null && qChoice < ownRow ? qChoice + 1 : 0;
91352
+ const consult = (0, import_react38.useMemo)(
91353
+ () => question && step ? consultBody(question, step, Math.max(20, width - 4), qPicks, step.multi ? qCursor : choiceRow) : { text: [], rows: [], at: [0, 0] },
91307
91354
  [question, step, width, qPicks, qCursor, choiceRow]
91308
91355
  );
91309
- const choosing = !!(step && stepLabels.length && !listAsk && question.kind !== "decision");
91356
+ const choosing = !!(step && stepLabels.length && !listAsk);
91310
91357
  const askHint = step && !listAsk ? fitStatus([
91311
91358
  choosing && { text: step.multi ? "a number ticks" : step.graded ? "\u2191\u2193 or a number marks" : "\u2191\u2193 or a number chooses on Enter" },
91312
91359
  choosing && step.multi && { text: "space ticks the one marked", drop: 3 },
91313
91360
  choosing && !step.multi && step.graded && { text: "words after it if you like", drop: 3 },
91314
91361
  !step.graded && { text: "type or paste your answer", drop: 2 },
91315
91362
  !step.graded && { text: "Alt+Enter adds a line", drop: 1 },
91316
- !step.multi && qChoice !== null ? { text: "enter takes the one marked" } : step.default && { text: "enter takes the default" },
91363
+ ownMarked ? null : !step.multi && qChoice !== null ? { text: "enter takes the one marked" } : step.default && { text: "enter takes the default" },
91317
91364
  !step.default && step.optional && (step.multi || qChoice === null) && { text: "enter says nothing" },
91318
91365
  step.multi && stepLabels.length && { text: "enter takes what is ticked" },
91319
91366
  step.secret && { text: "it is not shown and not recorded" }
91320
91367
  ], width - 4) : "";
91321
91368
  const consultHeight = Math.max(4, Math.min(18, Math.floor((stdout?.rows || DEFAULT_ROWS) / 2)));
91322
- const consultStart = Math.min(consultTop, Math.max(0, consultLines.length - consultHeight));
91369
+ const consultView = consultWindow(consult, consultHeight, consultTop);
91323
91370
  const menu = !question && value.trimStart().startsWith("/") && !value.includes(" ") ? COMMANDS.filter((c) => c.name.startsWith(value.trim())) : [];
91324
91371
  const atTyped = !question && !menu.length && !search ? (value.match(AT_TAIL) || [])[1] || "" : "";
91325
91372
  const atWord = atTyped === atShut ? "" : atTyped;
@@ -91339,15 +91386,23 @@ ${r.content}`).join("\n\n") };
91339
91386
  if (phase !== "busy" && phase !== "connecting") return void 0;
91340
91387
  const started = Date.now();
91341
91388
  setElapsed(0);
91342
- const t = setInterval(() => setElapsed(Math.floor((Date.now() - started) / 1e3)), 1e3);
91343
- return () => clearInterval(t);
91389
+ let ticks = 0;
91390
+ let off = () => {
91391
+ };
91392
+ const tick = () => {
91393
+ ticks += 1;
91394
+ setElapsed(Math.max(ticks, Math.floor((Date.now() - started) / ELAPSED_TICK_MS)));
91395
+ off = after2(ELAPSED_TICK_MS, tick);
91396
+ };
91397
+ off = after2(ELAPSED_TICK_MS, tick);
91398
+ return () => off();
91344
91399
  }, [phase]);
91345
91400
  const foldThinking = () => {
91346
91401
  if (thinkChars.current > 0) {
91347
91402
  const secs = thinkT0.current ? (Date.now() - thinkT0.current) / 1e3 : 0;
91348
- thoughtRef.current = { kind: "thought", text: `thought for ${fmtDur(secs)}` };
91403
+ thoughtRef.current = { kind: "thought", text: `thought for ${fmtDur(secs)}`, whole: thinkText.current };
91349
91404
  }
91350
- setThinking("");
91405
+ thinkText.current = "";
91351
91406
  thinkChars.current = 0;
91352
91407
  thinkT0.current = null;
91353
91408
  };
@@ -91363,8 +91418,10 @@ ${r.content}`).join("\n\n") };
91363
91418
  setDraft("");
91364
91419
  draftRef.current = "";
91365
91420
  thoughtRef.current = null;
91366
- setThinking("");
91421
+ ledRef.current = null;
91422
+ thinkText.current = "";
91367
91423
  thinkChars.current = 0;
91424
+ setPlanSteps([]);
91368
91425
  setProposal(null);
91369
91426
  setAsks([]);
91370
91427
  pendingAsk.current = null;
@@ -91412,14 +91469,14 @@ ${r.content}`).join("\n\n") };
91412
91469
  append({ kind: "warn", text: `could not look at ${row.name}: ${e.message}` });
91413
91470
  }
91414
91471
  };
91472
+ const thoughtRow = (text, whole) => ({ kind: "thought", text: whole ? `${text} (ctrl+o expands \xB7 #${keepOut("thought", whole)})` : text });
91415
91473
  const flushDraft = () => {
91416
91474
  const d = draftRef.current.trim();
91417
91475
  draftRef.current = "";
91418
91476
  if (d) append({ kind: "hum", text: d });
91419
- if (thoughtRef.current) {
91420
- append(thoughtRef.current);
91421
- thoughtRef.current = null;
91422
- }
91477
+ if (d && ledRef.current) append(thoughtRow(ledRef.current.text, ledRef.current.whole));
91478
+ ledRef.current = null;
91479
+ thoughtRef.current = null;
91423
91480
  setDraft("");
91424
91481
  };
91425
91482
  const handle = (ev) => {
@@ -91436,6 +91493,7 @@ ${r.content}`).join("\n\n") };
91436
91493
  case "busy":
91437
91494
  setPhaseBoth("busy");
91438
91495
  setStatus(ev.phase || "");
91496
+ setStatusOf(ev.of || "");
91439
91497
  return;
91440
91498
  case "plan":
91441
91499
  case "hypotheses":
@@ -91487,6 +91545,7 @@ ${r.content}`).join("\n\n") };
91487
91545
  if (ev.busy) {
91488
91546
  setPhaseBoth("busy");
91489
91547
  setStatus(ev.phase || "");
91548
+ setStatusOf("");
91490
91549
  } else {
91491
91550
  foldThinking();
91492
91551
  flushDraft();
@@ -91516,6 +91575,7 @@ ${r.content}`).join("\n\n") };
91516
91575
  if (ev.busy) {
91517
91576
  setPhaseBoth("busy");
91518
91577
  setStatus(ev.phase || "");
91578
+ setStatusOf("");
91519
91579
  turnT0.current = Date.now();
91520
91580
  } else setPhaseBoth("idle");
91521
91581
  }
@@ -91543,25 +91603,34 @@ ${r.content}`).join("\n\n") };
91543
91603
  break;
91544
91604
  }
91545
91605
  const ordered = [];
91606
+ let thought = null;
91546
91607
  for (const it of ev.items || []) {
91547
- const prev = ordered[ordered.length - 1];
91548
- if (it.type === "text" && prev && prev.type === "thought") ordered.splice(ordered.length - 1, 0, it);
91549
- else ordered.push(it);
91608
+ if (it.type === "thought") {
91609
+ thought = it;
91610
+ continue;
91611
+ }
91612
+ ordered.push(it);
91613
+ if (it.type === "text" && thought) ordered.push(thought);
91614
+ thought = null;
91550
91615
  }
91551
91616
  for (const it of ordered) {
91552
91617
  switch (it.type) {
91553
91618
  case "you":
91554
91619
  append({ kind: "you", text: it.text, images: it.images || [] });
91555
91620
  break;
91621
+ case "question_closed":
91622
+ append(answeredItem(it.ask ? askOf(it.ask) : null, it));
91623
+ break;
91624
+ // the block it left live
91556
91625
  case "text":
91557
91626
  append({ kind: "hum", text: it.text });
91558
91627
  break;
91559
91628
  case "thought":
91560
- append({ kind: "thought", text: `thought for ${fmtDur(it.secs || 0)}` });
91629
+ append(thoughtRow(`thought for ${fmtDur(it.secs || 0)}`, it.text));
91561
91630
  break;
91562
91631
  case "tool_call": {
91563
91632
  toolsRef.current[it.id] = it;
91564
- const row = { kind: "tool", text: it.name === "write_file" && it.lines != null ? `${it.desc || it.name} (${it.lines} lines)` : it.desc || it.name, name: it.name, args: it.args, agent: it.agent };
91633
+ const row = { kind: "tool", text: callLabel(it), name: it.name, args: it.args, agent: it.agent };
91565
91634
  if (it.agent || it.diff) append(row);
91566
91635
  else holdCall(it, row);
91567
91636
  if (it.diff) {
@@ -91574,14 +91643,13 @@ ${r.content}`).join("\n\n") };
91574
91643
  const more = (n) => (it.lines || 0) > 1 ? ` (+${it.lines - 1} lines${n ? ` \xB7 #${n}` : ""})` : "";
91575
91644
  const rowOf2 = (n) => ({ kind: "tool_result", text: `${it.summary || "(no output)"}${more(n)}`, isError: !it.ok, agent: it.agent });
91576
91645
  if (it.agent) append(rowOf2(0));
91577
- else landResult(it, rowOf2);
91646
+ else landResult(it, it.ok && rowStands(toolsRef.current[it.id]) ? null : rowOf2);
91578
91647
  break;
91579
91648
  }
91580
- case "plan": {
91581
- const glyph = { completed: "\u25FC", in_progress: "\u25B8", pending: "\u25FB" };
91582
- append({ kind: "plan", steps: (it.steps || []).map((st) => ({ ...st, glyph: glyph[st.status] || "\u25FB" })), explanation: it.explanation });
91649
+ case "plan":
91650
+ if (!it.agent) setPlanSteps(it.steps || []);
91651
+ append({ kind: "plan", steps: (it.steps || []).map((st) => ({ ...st, glyph: PLAN_GLYPH[st.status] || PLAN_GLYPH.pending })), explanation: it.explanation });
91583
91652
  break;
91584
- }
91585
91653
  case "hypotheses":
91586
91654
  append({ kind: "hypotheses", hypotheses: (it.hypotheses || []).map((h) => ({ ...h, glyph: HYPOTHESIS_GLYPH[h.status] || "\u25FB" })), explanation: it.explanation });
91587
91655
  break;
@@ -91662,6 +91730,7 @@ ${r.content}`).join("\n\n") };
91662
91730
  case "busy":
91663
91731
  setPhaseBoth("busy");
91664
91732
  setStatus(ev.phase || "");
91733
+ setStatusOf(ev.of || "");
91665
91734
  break;
91666
91735
  case "idle":
91667
91736
  setPhaseBoth("idle");
@@ -91671,22 +91740,25 @@ ${r.content}`).join("\n\n") };
91671
91740
  case "reasoning_delta":
91672
91741
  if (!thinkT0.current) thinkT0.current = Date.now();
91673
91742
  thinkChars.current += ev.text.length;
91674
- setThinking((t) => t + ev.text);
91743
+ thinkText.current += ev.text;
91675
91744
  break;
91676
91745
  case "text_delta":
91677
- if (thinkChars.current > 0) foldThinking();
91746
+ if (thinkChars.current > 0) {
91747
+ foldThinking();
91748
+ ledRef.current = thoughtRef.current;
91749
+ }
91678
91750
  draftRef.current += ev.text;
91679
91751
  setDraft((d) => d + ev.text);
91680
91752
  break;
91681
91753
  case "tool_pending":
91682
91754
  break;
91683
- // the status line already shows it; the call itself lands as a transcript line
91755
+ // the call itself lands as a transcript line
91684
91756
  case "tool_call": {
91685
91757
  foldThinking();
91686
91758
  flushDraft();
91687
91759
  toolsRef.current[ev.id] = ev;
91688
- const label = ev.name === "write_file" && ev.lines != null ? `${ev.desc || ev.name} (${ev.lines} lines)` : ev.desc || ev.name;
91689
- const row = { kind: "tool", text: label, name: ev.name, args: ev.args };
91760
+ if (proposedRef.current.delete(ev.id)) break;
91761
+ const row = { kind: "tool", text: callLabel(ev), name: ev.name, args: ev.args };
91690
91762
  if (ev.diff) append(row);
91691
91763
  else holdCall(ev, row);
91692
91764
  if (ev.diff) {
@@ -91698,7 +91770,8 @@ ${r.content}`).join("\n\n") };
91698
91770
  case "tool_result": {
91699
91771
  if (ev.ok && (ev.name === "write_file" || ev.name === "edit_file")) wroteRef.current = true;
91700
91772
  const more = (n) => (ev.lines || 0) > 1 ? ` (+${ev.lines - 1} lines \xB7 ctrl+o expands \xB7 #${n})` : "";
91701
- if (landResult(ev, (n) => ({ kind: "tool_result", text: `${ev.summary || "(no output)"}${more(n)}`, isError: !ev.ok }))) break;
91773
+ const rowOf2 = (n) => ({ kind: "tool_result", text: `${ev.summary || "(no output)"}${more(n)}`, isError: !ev.ok });
91774
+ if (landResult(ev, ev.ok && rowStands(toolsRef.current[ev.id]) ? null : rowOf2)) break;
91702
91775
  if (!ev.ok && ev.diagnostics && ev.diagnostics.length) {
91703
91776
  push({ kind: "errtail", lines: ev.diagnostics.map(diagLine) });
91704
91777
  } else if (!ev.ok && ev.content) {
@@ -91711,8 +91784,8 @@ ${r.content}`).join("\n\n") };
91711
91784
  case "plan": {
91712
91785
  foldThinking();
91713
91786
  flushDraft();
91714
- const glyph = { completed: "\u25FC", in_progress: "\u25B8", pending: "\u25FB" };
91715
- append({ kind: "plan", steps: (ev.steps || []).map((st) => ({ ...st, glyph: glyph[st.status] || "\u25FB" })), explanation: ev.explanation });
91787
+ setPlanSteps(ev.steps || []);
91788
+ append({ kind: "plan", steps: (ev.steps || []).map((st) => ({ ...st, glyph: PLAN_GLYPH[st.status] || PLAN_GLYPH.pending })), explanation: ev.explanation });
91716
91789
  break;
91717
91790
  }
91718
91791
  case "hypotheses": {
@@ -91725,34 +91798,41 @@ ${r.content}`).join("\n\n") };
91725
91798
  foldThinking();
91726
91799
  flushDraft();
91727
91800
  (ev.calls || []).forEach((c) => {
91728
- if (c.diff) append({ kind: "output", name: `${c.desc} \xB7 the whole change`, lines: c.diff.split("\n"), diff: true });
91801
+ if (!c.diff || proposedRef.current.has(c.id)) return;
91802
+ proposedRef.current.add(c.id);
91803
+ append({ kind: "tool", text: callLabel(c), name: c.name, args: c.args });
91804
+ append({ kind: "diff", lines: c.diff.split("\n"), more: 0 });
91729
91805
  });
91730
91806
  setProposal({ content: ev.content || "", calls: ev.calls || [], remember: ev.remember || [], remember_text: ev.remember_text || "", agent: ev.agent || null });
91731
91807
  setStatus("waiting for your decision");
91808
+ setStatusOf("");
91732
91809
  break;
91733
91810
  case "question":
91734
91811
  foldThinking();
91735
91812
  flushDraft();
91736
91813
  addAsk(ev);
91737
91814
  break;
91738
- case "question_closed":
91815
+ case "question_closed": {
91739
91816
  if (pendingAsk.current?.id === ev.id) {
91740
- append({ kind: "you", text: pendingAsk.current.display });
91741
91817
  pendingAsk.current = null;
91742
91818
  setSendingAsk(null);
91743
91819
  setValue("");
91744
91820
  }
91821
+ const closing = asksRef.current.find((q) => q.id === ev.id);
91822
+ if (closing) append(answeredItem(closing, ev));
91745
91823
  dropAsk(ev.id);
91746
- append({ kind: "info", text: `answered: ${ev.answer}` });
91747
91824
  break;
91825
+ }
91748
91826
  case "mcp":
91749
91827
  append({ kind: "mcp", servers: ev.servers || [] });
91750
91828
  break;
91751
91829
  case "memory": {
91752
91830
  const items2 = ev.items || [];
91753
- append({ kind: "info", text: `memory: ${ev.dir}${items2.some((i) => i.source === "repo") ? ` \xB7 shared: ${ev.repo_dir}` : ""}` });
91754
- if (!items2.length) append({ kind: "info", text: "nothing remembered yet; the model writes here with remember, and you may edit the files by hand" });
91755
- for (const it of items2) append({ kind: "info", text: ` ${it.name} (${it.type}${it.source === "repo" ? ", shared" : ""}): ${it.description}` });
91831
+ append({ kind: "info", text: [
91832
+ `memory: ${ev.dir}${items2.some((i) => i.source === "repo") ? ` \xB7 shared: ${ev.repo_dir}` : ""}`,
91833
+ ...items2.length ? [] : ["nothing remembered yet; the model writes here with remember, and you may edit the files by hand"],
91834
+ ...items2.map((it) => ` ${it.name} (${it.type}${it.source === "repo" ? ", shared" : ""}): ${it.description}`)
91835
+ ].join("\n") });
91756
91836
  break;
91757
91837
  }
91758
91838
  case "reflection":
@@ -91816,8 +91896,10 @@ ${r.content}`).join("\n\n") };
91816
91896
  case "rewind": {
91817
91897
  setConfirm(null);
91818
91898
  const did = [ev.files ? "the files" : null, ev.conversation ? "the conversation" : null].filter(Boolean).join(" and ");
91819
- append({ kind: "info", text: `back to \u201C${(ev.said || "").slice(0, 60)}\u201D \xB7 ${did} restored` });
91820
- if (ev.stat) append({ kind: "info", text: ` ${String(ev.stat).split("\n").filter((l) => l.trim()).join("\n ")}` });
91899
+ append({ kind: "info", text: [
91900
+ `back to \u201C${(ev.said || "").slice(0, 60)}\u201D \xB7 ${did} restored`,
91901
+ ...String(ev.stat || "").split("\n").filter((l) => l.trim()).map((l) => ` ${l}`)
91902
+ ].join("\n") });
91821
91903
  break;
91822
91904
  }
91823
91905
  case "goal":
@@ -91960,6 +92042,8 @@ ${r.content}`).join("\n\n") };
91960
92042
  exit();
91961
92043
  }, 2500);
91962
92044
  };
92045
+ const answering = !!(proposal || question || picker || confirm || trust || looking || reflection || search);
92046
+ const escOwned = answering || files.length > 0 || panelIndex >= 0;
91963
92047
  use_input_default((input, key) => {
91964
92048
  hereNow();
91965
92049
  if (key.ctrl && input === "c") {
@@ -92108,28 +92192,34 @@ ${r.content}`).join("\n\n") };
92108
92192
  if (question && step && !picker) {
92109
92193
  if (key.pageDown || key.pageUp) {
92110
92194
  setConsultTop(Math.max(0, Math.min(
92111
- consultLines.length - consultHeight,
92112
- consultStart + (key.pageDown ? consultHeight : -consultHeight)
92195
+ consult.text.length - consultView.textHeight,
92196
+ consultView.textStart + (key.pageDown ? consultView.textHeight : -consultView.textHeight)
92113
92197
  )));
92114
92198
  return;
92115
92199
  }
92116
92200
  if (key.escape || sendingAsk) return;
92117
- if (!listAsk && question.kind !== "decision") {
92201
+ if (!listAsk) {
92118
92202
  const n = stepLabels.length;
92203
+ const rows2 = n ? n + 1 : 0;
92119
92204
  if (step.multi && n && !value.trim()) {
92120
92205
  if (key.upArrow) {
92121
- setQCursor((c) => (c + n - 1) % n);
92206
+ setQCursor((c) => (c + rows2 - 1) % rows2);
92122
92207
  return;
92123
92208
  }
92124
92209
  if (key.downArrow || key.tab) {
92125
- setQCursor((c) => (c + 1) % n);
92210
+ setQCursor((c) => (c + 1) % rows2);
92126
92211
  return;
92127
92212
  }
92128
92213
  if (input === " " && !value.trim()) {
92129
- togglePick(stepLabels[Math.min(qCursor, n - 1)]);
92214
+ if (qCursor < n) togglePick(stepLabels[qCursor]);
92130
92215
  return;
92131
92216
  }
92132
92217
  }
92218
+ if (n && !value.trim() && input === String(rows2)) {
92219
+ if (step.multi) setQCursor(n);
92220
+ else setQChoice(n);
92221
+ return;
92222
+ }
92133
92223
  if (step.multi && !value.trim() && /^[1-9]$/.test(input) && Number(input) <= n) {
92134
92224
  const label = stepLabels[Number(input) - 1];
92135
92225
  setQCursor(Number(input) - 1);
@@ -92138,15 +92228,16 @@ ${r.content}`).join("\n\n") };
92138
92228
  }
92139
92229
  if (!step.multi && n && !value.trim()) {
92140
92230
  if (key.upArrow) {
92141
- setQChoice(choiceRow < 0 ? n - 1 : (choiceRow + n - 1) % n);
92231
+ setQChoice(choiceRow < 0 ? rows2 - 1 : (choiceRow + rows2 - 1) % rows2);
92142
92232
  return;
92143
92233
  }
92144
92234
  if (key.downArrow) {
92145
- setQChoice((choiceRow + 1) % n);
92235
+ setQChoice((choiceRow + 1) % rows2);
92146
92236
  return;
92147
92237
  }
92148
92238
  }
92149
92239
  if (key.return && !key.meta && !key.shift && !value.trim()) {
92240
+ if (ownMarked) return;
92150
92241
  if (!step.multi && qChoice !== null) {
92151
92242
  answerStep(String(qChoice + 1));
92152
92243
  return;
@@ -92229,7 +92320,6 @@ ${r.content}`).join("\n\n") };
92229
92320
  else if (key.tab) setValue(menu[Math.min(menuIndex, menu.length - 1)].name + " ");
92230
92321
  return;
92231
92322
  }
92232
- const answering = !!(proposal || question || picker || confirm || trust || looking || reflection || search);
92233
92323
  if (key.tab && phaseRef.current === "busy" && !answering && value.trim() && !/^[/!]/.test(value.trim())) {
92234
92324
  const raw = value.trim();
92235
92325
  remember(raw);
@@ -92292,9 +92382,9 @@ ${r.content}`).join("\n\n") };
92292
92382
  setValue("");
92293
92383
  setQPicks((ps) => ps.includes(label) ? ps.filter((x) => x !== label) : [...ps, label]);
92294
92384
  };
92295
- const submitAsk = (payload, display) => {
92385
+ const submitAsk = (payload) => {
92296
92386
  if (!question || pendingAsk.current) return;
92297
- pendingAsk.current = { id: question.id, display };
92387
+ pendingAsk.current = { id: question.id };
92298
92388
  setSendingAsk(question.id);
92299
92389
  if (core2.send({ cmd: "answer", id: question.id, ...payload }) === false) {
92300
92390
  pendingAsk.current = null;
@@ -92305,22 +92395,20 @@ ${r.content}`).join("\n\n") };
92305
92395
  const holdAll = () => {
92306
92396
  if (!listAsk) return;
92307
92397
  const answers = Object.fromEntries(question.questions.map((q) => [q.id, q.id === "missed" ? "" : "holds"]));
92308
- submitAsk({ answers }, `held all ${listRows.length} as stated`);
92398
+ submitAsk({ answers });
92309
92399
  };
92310
92400
  const answerWhole = (text) => {
92311
92401
  if (!text.trim() || /^\d+$/.test(text.trim())) {
92312
92402
  append({ kind: "warn", text: "say what the number means, or type /hold to confirm every constraint" });
92313
92403
  return;
92314
92404
  }
92315
- submitAsk({ text }, text);
92405
+ submitAsk({ text });
92316
92406
  };
92317
92407
  const answerStep = (text) => {
92318
92408
  if (!question || !step) return;
92319
- const display = step.secret ? "(kept to yourself)" : text || (step.default ? `(the default: ${step.default})` : "(nothing)");
92320
92409
  const answers = { ...qAnswers, [step.id]: text };
92321
92410
  if (qStep + 1 < steps.length) {
92322
92411
  setValue("");
92323
- append({ kind: "you", text: display });
92324
92412
  setQAnswers(answers);
92325
92413
  setQStep(qStep + 1);
92326
92414
  setConsultTop(0);
@@ -92329,7 +92417,7 @@ ${r.content}`).join("\n\n") };
92329
92417
  setQChoice(null);
92330
92418
  return;
92331
92419
  }
92332
- submitAsk({ answers }, display);
92420
+ submitAsk({ answers });
92333
92421
  };
92334
92422
  const vote = (polarity, why2 = "") => {
92335
92423
  core2.send({ cmd: polarity > 0 ? "accept" : "reject", ...why2 ? { why: why2 } : {} });
@@ -92549,7 +92637,7 @@ ${r.content}`).join("\n\n") };
92549
92637
  if (question && step && !/^\/(quit|exit|stop)\b/.test(raw)) {
92550
92638
  if (listAsk && text === "/hold") holdAll();
92551
92639
  else if (listAsk) answerWhole(text);
92552
- else answerStep(text);
92640
+ else answerStep(markedPick && text.trim() && typedRow === null ? `${markedPick} ${text.trim()}` : text);
92553
92641
  return;
92554
92642
  }
92555
92643
  if (reflection) closeReflection(reflection.id, "dismiss");
@@ -92580,13 +92668,18 @@ ${r.content}`).join("\n\n") };
92580
92668
  !ctrlc && question && step && !step.secret && { text: "ctrl+g editor", drop: 2 },
92581
92669
  ctrlc ? { text: "ctrl+c again to quit" } : { text: "/ for commands", drop: 1 }
92582
92670
  ], width);
92583
- const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${status || "working"}${elapsed >= 2 ? ` \xB7 ${fmtDur(elapsed)}` : ""}` + (thinkChars.current > 4e3 ? ` \xB7 ${(thinkChars.current / 1e3).toFixed(0)}k thinking` : "");
92671
+ const stepAt = planSteps.findIndex((st) => st.status === "in_progress");
92672
+ const phaseWord = statusOf === "tool" ? "" : status;
92673
+ const doing = [stepAt >= 0 ? `${stepAt + 1}/${planSteps.length} \xB7 ${planSteps[stepAt].step}` : "", phaseWord].filter(Boolean).join(" \xB7 ") || "working";
92674
+ const beside = [elapsed >= 1 ? fmtDur(elapsed) : "", escOwned ? "" : "esc to interrupt"].filter(Boolean).join(" \xB7 ");
92675
+ const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${doing}${beside ? ` (${beside})` : ""}`;
92676
+ const spinnerRows = wrapAnsi2(spinnerLabel, Math.max(1, width - 1), { hard: true, trim: false }).split("\n").length;
92584
92677
  const rows = stdout?.rows || DEFAULT_ROWS;
92585
92678
  const heldRows = [...foldRows(held.reads), ...held.calls.map((c) => c.item)];
92586
- const chrome = 1 + 2 + heldRows.length + 4 + (value.split("\n").length - 1) + 1 + (menu.length ? menu.length : 0) + files.length + (!menu.length && !files.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 ? 9 + Math.min(consultHeight, consultLines.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) + (trust ? 4 + trust.starts.length : 0) + (picker ? 14 : 0);
92679
+ const chrome = 1 + 1 + spinnerRows + heldRows.reduce((n, r) => n + 1 + blockGap(r), 0) + 4 + (value.split("\n").length - 1) + 1 + (menu.length ? menu.length : 0) + files.length + (!menu.length && !files.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 ? 9 + Math.min(consultHeight, consult.text.length + consult.rows.length) + (consult.rows.length ? 1 : 0) : 0) + (proposal ? 4 + proposal.calls.length : 0) + (reflection ? 8 + reflection.details.split("\n").length : 0) + (confirm ? 4 + Math.min(8, String(confirm.stat || "").split("\n").length) : 0) + (trust ? 4 + trust.starts.length : 0) + (picker ? 14 : 0);
92587
92680
  const liveBudget = Math.max(LIVE_MIN_ROWS, Math.min(DRAFT_TAIL_LINES, rows - 1 - chrome));
92588
92681
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92589
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Static, { items, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", marginBottom: ["hum", "you", "banner", "turn"].includes(item.kind) ? 1 : 0, children: [
92682
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Static, { items, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", marginTop: blockGap(item), children: [
92590
92683
  item.kind === "wordmark" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { flexDirection: "column", paddingLeft: 1, children: WORDMARK.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, bold: true, children: row }, i)) }),
92591
92684
  item.kind === "banner" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 1, children: [
92592
92685
  MASCOT.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { children: [
@@ -92622,6 +92715,15 @@ ${r.content}`).join("\n\n") };
92622
92715
  ] }, i))
92623
92716
  ] })
92624
92717
  ] }),
92718
+ item.kind === "answered" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92719
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, bold: true, children: item.title }),
92720
+ item.entries.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92721
+ e.question ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " \u2022 ", children: e.question }) : null,
92722
+ e.pick ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " pick: ", children: e.pick }) : null,
92723
+ e.pick && e.why ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " why: ", children: e.why }) : null,
92724
+ !e.pick ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " answer: ", children: e.why || "(nothing)" }) : null
92725
+ ] }, i))
92726
+ ] }),
92625
92727
  item.kind === "agent" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { color: "magenta", children: [
92626
92728
  " \u25B8 ",
92627
92729
  item.text
@@ -92634,22 +92736,25 @@ ${r.content}`).join("\n\n") };
92634
92736
  " \xB7 ",
92635
92737
  item.text
92636
92738
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRow, { text: item.text })),
92637
- item.kind === "plan" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 2, children: [
92638
- item.explanation ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: item.explanation }) : null,
92639
- item.steps.map((st, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
92640
- Text2,
92641
- {
92642
- dimColor: st.status === "completed",
92643
- bold: st.status === "in_progress",
92644
- color: st.status === "in_progress" ? ACCENT : void 0,
92645
- children: [
92646
- st.glyph,
92647
- " ",
92648
- st.step
92649
- ]
92650
- },
92651
- i
92652
- ))
92739
+ item.kind === "plan" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92740
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRow, { text: "updated the plan" }),
92741
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 2, children: [
92742
+ item.explanation ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, italic: true, children: item.explanation }) : null,
92743
+ item.steps.map((st, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
92744
+ Text2,
92745
+ {
92746
+ dimColor: st.status !== "in_progress",
92747
+ bold: st.status === "in_progress",
92748
+ color: st.status === "in_progress" ? ACCENT : void 0,
92749
+ children: [
92750
+ st.glyph,
92751
+ " ",
92752
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { strikethrough: st.status === "completed", children: st.step })
92753
+ ]
92754
+ },
92755
+ i
92756
+ ))
92757
+ ] })
92653
92758
  ] }),
92654
92759
  item.kind === "hypotheses" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 2, children: [
92655
92760
  item.explanation ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: item.explanation }) : null,
@@ -92702,7 +92807,7 @@ ${r.content}`).join("\n\n") };
92702
92807
  item.kind === "errtail" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { flexDirection: "column", paddingLeft: 6, children: item.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: "red", dimColor: true, children: l }, i)) }),
92703
92808
  item.kind === "output" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 4, children: [
92704
92809
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: `full output \xB7 ${item.name}` }),
92705
- item.lines.map((l, i) => item.diff ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: l.startsWith("+") ? "green" : l.startsWith("-") ? "red" : void 0, dimColor: !l.startsWith("+") && !l.startsWith("-"), children: l || " " }, i) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: l || " " }, i))
92810
+ item.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: l || " " }, i))
92706
92811
  ] }),
92707
92812
  item.kind === "turn" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { children: [
92708
92813
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, children: "\u273B " }),
@@ -92754,17 +92859,17 @@ ${r.content}`).join("\n\n") };
92754
92859
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: "red", children: item.text })
92755
92860
  ] })
92756
92861
  ] }, item.id) }, transcriptEpoch),
92757
- heldRows.map((item, i) => item.kind === "tool" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRow, { text: item.text, tail: i === heldRows.length - 1 && held.calls.length && phase === "busy" ? tickTail(held.calls[held.calls.length - 1].t0) : "" }, i) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { dimColor: true, children: [
92758
- " \u23BF ",
92759
- item.text
92760
- ] }, i)),
92862
+ heldRows.map((item, i) => (
92863
+ // a held row stands where it will print: the same gap above it here as on the transcript
92864
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { flexDirection: "column", marginTop: blockGap(item), children: item.kind === "tool" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRow, { text: item.text, tail: i === heldRows.length - 1 && held.calls.length && phase === "busy" ? tickTail(held.calls[held.calls.length - 1].t0) : "" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { dimColor: true, children: [
92865
+ " \u23BF ",
92866
+ item.text
92867
+ ] }) }, i)
92868
+ )),
92761
92869
  draft.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { marginTop: 1, children: [
92762
92870
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { width: 2, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, dimColor: true, children: "\u25CF" }) }),
92763
92871
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: liveTail(renderMarkdown(draft, width - 2), width - 2, liveBudget) })
92764
92872
  ] }),
92765
- thinking.length > 0 && // the thought as it streams: its newest lines, dim, so a long think is never a blank screen.
92766
- // It folds into one line under the reply the moment the reply starts
92767
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box2, { flexDirection: "column", marginTop: 1, paddingLeft: 2, width, children: thinking.slice(-600).split("\n").filter((l) => l.trim()).slice(-Math.min(THOUGHT_TAIL_LINES, liveBudget)).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, italic: true, wrap: "truncate-start", children: l }, i)) }),
92768
92873
  (phase === "busy" || phase === "connecting") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { marginTop: 1, children: [
92769
92874
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(build_default, { type: "dots" }) }),
92770
92875
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: spinnerLabel })
@@ -92775,11 +92880,11 @@ ${r.content}`).join("\n\n") };
92775
92880
  listAsk ? `\u2726 Constraints Hum discovered ${listRows.length} \xB7 say what you know about each` : question.kind === "decision" ? "\u2726 Review a decision" : question.kind === "review" ? "\u2726 Hum asks for your review" : "\u2726 Clarification",
92776
92881
  !listAsk && steps.length > 1 ? ` (${qStep + 1} of ${steps.length})` : ""
92777
92882
  ] }),
92778
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: consultLines.slice(consultStart, consultStart + consultHeight).join("\n") }),
92779
- consultLines.length > consultHeight ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: `lines ${consultStart + 1}\u2013${Math.min(consultLines.length, consultStart + consultHeight)} of ${consultLines.length} \xB7 PgUp/PgDn to read` }) : null,
92883
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: consultView.shownText.join("\n") }),
92884
+ consult.text.length > consultView.textHeight ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: `lines ${consultView.textStart + 1}\u2013${consultView.textStart + consultView.textHeight} of ${consult.text.length} \xB7 PgUp/PgDn to read` }) : null,
92885
+ consultView.shownRows.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: ["", ...consultView.shownRows].join("\n") }) : null,
92780
92886
  listAsk ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: "your words are the answer \xB7 add what was missed \xB7 /hold confirms all \xB7 Alt+Enter adds a line \xB7 Esc leaves unanswered" }) : null,
92781
92887
  question.kind === "review" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: "Share solution insights, test inputs and expected results, constraints, or a hypothesis and how to test it." }) : null,
92782
- question.kind === "decision" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: "Type a choice and your reasoning, or another approach \xB7 Alt+Enter adds a line \xB7 Enter sends" }) : null,
92783
92888
  sendingAsk === question.id ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, children: "Sending answer\u2026" }) : null,
92784
92889
  !listAsk ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, wrap: "truncate-end", children: " " + askHint }) : null
92785
92890
  ] }),
@@ -92837,7 +92942,11 @@ ${r.content}`).join("\n\n") };
92837
92942
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { children: [
92838
92943
  " \xB7 ",
92839
92944
  c.desc,
92840
- c.lines != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: ` (${c.lines} lines)` }) : null
92945
+ c.lines != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: ` (${c.lines} lines)` }) : null,
92946
+ c.diff ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { children: [
92947
+ " ",
92948
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DiffStat, { lines: c.diff.split("\n") })
92949
+ ] }) : null
92841
92950
  ] }),
92842
92951
  (c.name === "bash" || c.name === "powershell") && c.desc !== `$ ${String(c.args?.command || "")}` ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { color: "cyan", children: [
92843
92952
  " $ ",
@@ -92846,20 +92955,7 @@ ${r.content}`).join("\n\n") };
92846
92955
  c.escape ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { color: "yellow", children: [
92847
92956
  " outside the sandbox \u2014 ",
92848
92957
  String(c.reason || "").slice(0, Math.max(20, width - 32))
92849
- ] }) : null,
92850
- c.diff ? c.diff.split("\n").slice(0, DIFF_TAIL_LINES).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
92851
- Text2,
92852
- {
92853
- color: l.startsWith("+") ? "green" : l.startsWith("-") ? "red" : void 0,
92854
- dimColor: !l.startsWith("+") && !l.startsWith("-"),
92855
- children: [
92856
- " ",
92857
- l || " "
92858
- ]
92859
- },
92860
- i
92861
- )) : null,
92862
- c.diff && c.diff.split("\n").length > DIFF_TAIL_LINES ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: ` the whole change (${c.diff.split("\n").length} lines) is above` }) : null
92958
+ ] }) : null
92863
92959
  ] }, c.id))
92864
92960
  ] }),
92865
92961
  looking && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, marginTop: 1, children: [
@@ -93100,12 +93196,13 @@ ${r.content}`).join("\n\n") };
93100
93196
  if (reflection && why !== reflection.id && (input === "1" || input === "2")) return true;
93101
93197
  if (proposal && (input === "a" || input === "p") && (proposal.remember || []).length) return true;
93102
93198
  if (!question || !step) return false;
93103
- if (listAsk || question.kind === "decision") return false;
93199
+ if (listAsk) return false;
93200
+ if (stepLabels.length && input === String(stepLabels.length + 1)) return true;
93104
93201
  if (step.multi && /^[1-9]$/.test(input) && Number(input) <= stepLabels.length) return true;
93105
93202
  if (stepLabels.length && (key.upArrow || key.downArrow)) return true;
93106
93203
  return !!(step.multi && stepLabels.length && input === " ");
93107
93204
  },
93108
- placeholder: why && reflection && why === reflection.id ? "what did it get wrong? (enter alone: just the no)" : listAsk ? "your words on the list, by number or as one reply" : question && step ? stepLabels.length ? "a number, or your answer" : "your answer" : proposal ? (proposal.remember || []).length ? "enter approves \xB7 a / p allow this shape \xB7 or type why not" : "enter to approve \xB7 or type why not" : paused ? "paused \xB7 say what to do, or /continue" : phase === "busy" ? "type to steer \xB7 esc to stop \xB7 !cmd runs a command" : session ? "what next?" : "what are we doing?"
93205
+ placeholder: why && reflection && why === reflection.id ? "what did it get wrong? (enter alone: just the no)" : listAsk ? "your words on the list, by number or as one reply" : question && step ? ownMarked ? "type your own answer" : markedPick ? "why? \xB7 enter sends \xB7 enter on an empty line sends the pick alone" : stepLabels.length ? "a number, or your answer" : "your answer" : proposal ? (proposal.remember || []).length ? "enter approves \xB7 a / p allow this shape \xB7 or type why not" : "enter to approve \xB7 or type why not" : paused ? "paused \xB7 say what to do, or /continue" : phase === "busy" ? "type to steer \xB7 esc to stop \xB7 !cmd runs a command" : session ? "what next?" : "what are we doing?"
93109
93206
  }
93110
93207
  )
93111
93208
  ] }),
@@ -93172,7 +93269,7 @@ init_install();
93172
93269
  await init_theme();
93173
93270
  var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
93174
93271
  import { spawnSync as spawnSync6 } from "node:child_process";
93175
- var MINE3 = true ? "0.2.26" : "0.0.0";
93272
+ var MINE3 = true ? "0.2.28" : "0.0.0";
93176
93273
  var layout = installLayout();
93177
93274
  function completeInstall() {
93178
93275
  if (layout.kind !== "npm" || !needsInstall(MINE3)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaphi-ai/hum",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "Hum: a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",