@metaphi-ai/hum 0.2.26 → 0.2.27

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 +219 -118
  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.27" : "";
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.27" : ""
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.27" : "" } = {}) {
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.27" : "";
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,8 +91210,10 @@ 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)({});
91186
91218
  const historyRef = (0, import_react38.useRef)(loadHistory());
91187
91219
  const modelRef = (0, import_react38.useRef)("");
@@ -91258,7 +91290,7 @@ ${r.content}`).join("\n\n") };
91258
91290
  return true;
91259
91291
  }
91260
91292
  printHeld(rest);
91261
- push(rowOf2(keepOut(ev.name, ev.content)));
91293
+ if (rowOf2) push(rowOf2(keepOut(ev.name, ev.content)));
91262
91294
  return false;
91263
91295
  };
91264
91296
  const setAsks = (next) => {
@@ -91283,6 +91315,16 @@ ${r.content}`).join("\n\n") };
91283
91315
  summary: ev.summary || "",
91284
91316
  evidence: ev.evidence || []
91285
91317
  });
91318
+ const ASK_TITLES = { decision: "Decision", review: "Review", constraints: "Constraints" };
91319
+ const answeredItem = (ask, ev) => {
91320
+ const qs = ask ? ask.questions && ask.questions.length ? ask.questions : [{ id: ask.id, question: ask.question, options: ask.options, default: ask.default }] : [];
91321
+ const given = ev.answers || {};
91322
+ const entries = qs.filter((q) => given[q.id]).map((q) => ({ question: q.question, ...pickOf(q, given[q.id]) }));
91323
+ const whole = entries.length ? [] : [{ question: "", pick: null, why: String(given.reply ?? ev.answer ?? "") }];
91324
+ const count = qs.length > 1 && entries.length ? `${entries.length}/${qs.length} ` : "";
91325
+ const via = ev.via ? ` \xB7 from ${ev.via[0].toUpperCase()}${ev.via.slice(1)}` : "";
91326
+ return { kind: "answered", title: `\u2726 ${ASK_TITLES[ask?.kind] || "Clarification"} \xB7 ${count}answered${via}`, entries: [...entries, ...whole] };
91327
+ };
91286
91328
  const addAsk = (ev) => {
91287
91329
  if (asksRef.current.some((q) => q.id === ev.id)) return;
91288
91330
  const shown = asksRef.current.length > 0;
@@ -91300,26 +91342,30 @@ ${r.content}`).join("\n\n") };
91300
91342
  const stepLabels = stepOptions.map((o) => o.label);
91301
91343
  const listAsk = !!(question && question.kind === "constraints" && question.questions && question.questions.length);
91302
91344
  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) : [],
91345
+ const typedHead = step && step.graded ? value.trim().split(/\s+/)[0] : value.trim();
91346
+ const typedRow = /^[1-9]$/.test(typedHead) && Number(typedHead) <= stepLabels.length ? Number(typedHead) - 1 : null;
91347
+ const choiceRow = step && !step.multi && !listAsk ? typedRow ?? qChoice ?? stepLabels.indexOf(step.default) : -1;
91348
+ const ownRow = stepLabels.length;
91349
+ const ownMarked = !!(step && ownRow && !listAsk && typedRow === null && (step.multi ? qCursor : qChoice) === ownRow);
91350
+ const markedPick = step && step.graded && !step.multi && !listAsk && qChoice !== null && qChoice < ownRow ? qChoice + 1 : 0;
91351
+ const consult = (0, import_react38.useMemo)(
91352
+ () => question && step ? consultBody(question, step, Math.max(20, width - 4), qPicks, step.multi ? qCursor : choiceRow) : { text: [], rows: [], at: [0, 0] },
91307
91353
  [question, step, width, qPicks, qCursor, choiceRow]
91308
91354
  );
91309
- const choosing = !!(step && stepLabels.length && !listAsk && question.kind !== "decision");
91355
+ const choosing = !!(step && stepLabels.length && !listAsk);
91310
91356
  const askHint = step && !listAsk ? fitStatus([
91311
91357
  choosing && { text: step.multi ? "a number ticks" : step.graded ? "\u2191\u2193 or a number marks" : "\u2191\u2193 or a number chooses on Enter" },
91312
91358
  choosing && step.multi && { text: "space ticks the one marked", drop: 3 },
91313
91359
  choosing && !step.multi && step.graded && { text: "words after it if you like", drop: 3 },
91314
91360
  !step.graded && { text: "type or paste your answer", drop: 2 },
91315
91361
  !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" },
91362
+ ownMarked ? null : !step.multi && qChoice !== null ? { text: "enter takes the one marked" } : step.default && { text: "enter takes the default" },
91317
91363
  !step.default && step.optional && (step.multi || qChoice === null) && { text: "enter says nothing" },
91318
91364
  step.multi && stepLabels.length && { text: "enter takes what is ticked" },
91319
91365
  step.secret && { text: "it is not shown and not recorded" }
91320
91366
  ], width - 4) : "";
91321
91367
  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));
91368
+ const consultView = consultWindow(consult, consultHeight, consultTop);
91323
91369
  const menu = !question && value.trimStart().startsWith("/") && !value.includes(" ") ? COMMANDS.filter((c) => c.name.startsWith(value.trim())) : [];
91324
91370
  const atTyped = !question && !menu.length && !search ? (value.match(AT_TAIL) || [])[1] || "" : "";
91325
91371
  const atWord = atTyped === atShut ? "" : atTyped;
@@ -91339,15 +91385,23 @@ ${r.content}`).join("\n\n") };
91339
91385
  if (phase !== "busy" && phase !== "connecting") return void 0;
91340
91386
  const started = Date.now();
91341
91387
  setElapsed(0);
91342
- const t = setInterval(() => setElapsed(Math.floor((Date.now() - started) / 1e3)), 1e3);
91343
- return () => clearInterval(t);
91388
+ let ticks = 0;
91389
+ let off = () => {
91390
+ };
91391
+ const tick = () => {
91392
+ ticks += 1;
91393
+ setElapsed(Math.max(ticks, Math.floor((Date.now() - started) / ELAPSED_TICK_MS)));
91394
+ off = after2(ELAPSED_TICK_MS, tick);
91395
+ };
91396
+ off = after2(ELAPSED_TICK_MS, tick);
91397
+ return () => off();
91344
91398
  }, [phase]);
91345
91399
  const foldThinking = () => {
91346
91400
  if (thinkChars.current > 0) {
91347
91401
  const secs = thinkT0.current ? (Date.now() - thinkT0.current) / 1e3 : 0;
91348
- thoughtRef.current = { kind: "thought", text: `thought for ${fmtDur(secs)}` };
91402
+ thoughtRef.current = { kind: "thought", text: `thought for ${fmtDur(secs)}`, whole: thinkText.current };
91349
91403
  }
91350
- setThinking("");
91404
+ thinkText.current = "";
91351
91405
  thinkChars.current = 0;
91352
91406
  thinkT0.current = null;
91353
91407
  };
@@ -91363,8 +91417,10 @@ ${r.content}`).join("\n\n") };
91363
91417
  setDraft("");
91364
91418
  draftRef.current = "";
91365
91419
  thoughtRef.current = null;
91366
- setThinking("");
91420
+ ledRef.current = null;
91421
+ thinkText.current = "";
91367
91422
  thinkChars.current = 0;
91423
+ setPlanSteps([]);
91368
91424
  setProposal(null);
91369
91425
  setAsks([]);
91370
91426
  pendingAsk.current = null;
@@ -91412,14 +91468,14 @@ ${r.content}`).join("\n\n") };
91412
91468
  append({ kind: "warn", text: `could not look at ${row.name}: ${e.message}` });
91413
91469
  }
91414
91470
  };
91471
+ const thoughtRow = (text, whole) => ({ kind: "thought", text: whole ? `${text} (ctrl+o expands \xB7 #${keepOut("thought", whole)})` : text });
91415
91472
  const flushDraft = () => {
91416
91473
  const d = draftRef.current.trim();
91417
91474
  draftRef.current = "";
91418
91475
  if (d) append({ kind: "hum", text: d });
91419
- if (thoughtRef.current) {
91420
- append(thoughtRef.current);
91421
- thoughtRef.current = null;
91422
- }
91476
+ if (d && ledRef.current) append(thoughtRow(ledRef.current.text, ledRef.current.whole));
91477
+ ledRef.current = null;
91478
+ thoughtRef.current = null;
91423
91479
  setDraft("");
91424
91480
  };
91425
91481
  const handle = (ev) => {
@@ -91436,6 +91492,7 @@ ${r.content}`).join("\n\n") };
91436
91492
  case "busy":
91437
91493
  setPhaseBoth("busy");
91438
91494
  setStatus(ev.phase || "");
91495
+ setStatusOf(ev.of || "");
91439
91496
  return;
91440
91497
  case "plan":
91441
91498
  case "hypotheses":
@@ -91487,6 +91544,7 @@ ${r.content}`).join("\n\n") };
91487
91544
  if (ev.busy) {
91488
91545
  setPhaseBoth("busy");
91489
91546
  setStatus(ev.phase || "");
91547
+ setStatusOf("");
91490
91548
  } else {
91491
91549
  foldThinking();
91492
91550
  flushDraft();
@@ -91516,6 +91574,7 @@ ${r.content}`).join("\n\n") };
91516
91574
  if (ev.busy) {
91517
91575
  setPhaseBoth("busy");
91518
91576
  setStatus(ev.phase || "");
91577
+ setStatusOf("");
91519
91578
  turnT0.current = Date.now();
91520
91579
  } else setPhaseBoth("idle");
91521
91580
  }
@@ -91543,25 +91602,34 @@ ${r.content}`).join("\n\n") };
91543
91602
  break;
91544
91603
  }
91545
91604
  const ordered = [];
91605
+ let thought = null;
91546
91606
  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);
91607
+ if (it.type === "thought") {
91608
+ thought = it;
91609
+ continue;
91610
+ }
91611
+ ordered.push(it);
91612
+ if (it.type === "text" && thought) ordered.push(thought);
91613
+ thought = null;
91550
91614
  }
91551
91615
  for (const it of ordered) {
91552
91616
  switch (it.type) {
91553
91617
  case "you":
91554
91618
  append({ kind: "you", text: it.text, images: it.images || [] });
91555
91619
  break;
91620
+ case "question_closed":
91621
+ append(answeredItem(it.ask ? askOf(it.ask) : null, it));
91622
+ break;
91623
+ // the block it left live
91556
91624
  case "text":
91557
91625
  append({ kind: "hum", text: it.text });
91558
91626
  break;
91559
91627
  case "thought":
91560
- append({ kind: "thought", text: `thought for ${fmtDur(it.secs || 0)}` });
91628
+ append(thoughtRow(`thought for ${fmtDur(it.secs || 0)}`, it.text));
91561
91629
  break;
91562
91630
  case "tool_call": {
91563
91631
  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 };
91632
+ const row = { kind: "tool", text: callLabel(it), name: it.name, args: it.args, agent: it.agent };
91565
91633
  if (it.agent || it.diff) append(row);
91566
91634
  else holdCall(it, row);
91567
91635
  if (it.diff) {
@@ -91574,14 +91642,13 @@ ${r.content}`).join("\n\n") };
91574
91642
  const more = (n) => (it.lines || 0) > 1 ? ` (+${it.lines - 1} lines${n ? ` \xB7 #${n}` : ""})` : "";
91575
91643
  const rowOf2 = (n) => ({ kind: "tool_result", text: `${it.summary || "(no output)"}${more(n)}`, isError: !it.ok, agent: it.agent });
91576
91644
  if (it.agent) append(rowOf2(0));
91577
- else landResult(it, rowOf2);
91645
+ else landResult(it, it.ok && rowStands(toolsRef.current[it.id]) ? null : rowOf2);
91578
91646
  break;
91579
91647
  }
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 });
91648
+ case "plan":
91649
+ if (!it.agent) setPlanSteps(it.steps || []);
91650
+ append({ kind: "plan", steps: (it.steps || []).map((st) => ({ ...st, glyph: PLAN_GLYPH[st.status] || PLAN_GLYPH.pending })), explanation: it.explanation });
91583
91651
  break;
91584
- }
91585
91652
  case "hypotheses":
91586
91653
  append({ kind: "hypotheses", hypotheses: (it.hypotheses || []).map((h) => ({ ...h, glyph: HYPOTHESIS_GLYPH[h.status] || "\u25FB" })), explanation: it.explanation });
91587
91654
  break;
@@ -91662,6 +91729,7 @@ ${r.content}`).join("\n\n") };
91662
91729
  case "busy":
91663
91730
  setPhaseBoth("busy");
91664
91731
  setStatus(ev.phase || "");
91732
+ setStatusOf(ev.of || "");
91665
91733
  break;
91666
91734
  case "idle":
91667
91735
  setPhaseBoth("idle");
@@ -91671,22 +91739,24 @@ ${r.content}`).join("\n\n") };
91671
91739
  case "reasoning_delta":
91672
91740
  if (!thinkT0.current) thinkT0.current = Date.now();
91673
91741
  thinkChars.current += ev.text.length;
91674
- setThinking((t) => t + ev.text);
91742
+ thinkText.current += ev.text;
91675
91743
  break;
91676
91744
  case "text_delta":
91677
- if (thinkChars.current > 0) foldThinking();
91745
+ if (thinkChars.current > 0) {
91746
+ foldThinking();
91747
+ ledRef.current = thoughtRef.current;
91748
+ }
91678
91749
  draftRef.current += ev.text;
91679
91750
  setDraft((d) => d + ev.text);
91680
91751
  break;
91681
91752
  case "tool_pending":
91682
91753
  break;
91683
- // the status line already shows it; the call itself lands as a transcript line
91754
+ // the call itself lands as a transcript line
91684
91755
  case "tool_call": {
91685
91756
  foldThinking();
91686
91757
  flushDraft();
91687
91758
  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 };
91759
+ const row = { kind: "tool", text: callLabel(ev), name: ev.name, args: ev.args };
91690
91760
  if (ev.diff) append(row);
91691
91761
  else holdCall(ev, row);
91692
91762
  if (ev.diff) {
@@ -91698,7 +91768,8 @@ ${r.content}`).join("\n\n") };
91698
91768
  case "tool_result": {
91699
91769
  if (ev.ok && (ev.name === "write_file" || ev.name === "edit_file")) wroteRef.current = true;
91700
91770
  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;
91771
+ const rowOf2 = (n) => ({ kind: "tool_result", text: `${ev.summary || "(no output)"}${more(n)}`, isError: !ev.ok });
91772
+ if (landResult(ev, ev.ok && rowStands(toolsRef.current[ev.id]) ? null : rowOf2)) break;
91702
91773
  if (!ev.ok && ev.diagnostics && ev.diagnostics.length) {
91703
91774
  push({ kind: "errtail", lines: ev.diagnostics.map(diagLine) });
91704
91775
  } else if (!ev.ok && ev.content) {
@@ -91711,8 +91782,8 @@ ${r.content}`).join("\n\n") };
91711
91782
  case "plan": {
91712
91783
  foldThinking();
91713
91784
  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 });
91785
+ setPlanSteps(ev.steps || []);
91786
+ append({ kind: "plan", steps: (ev.steps || []).map((st) => ({ ...st, glyph: PLAN_GLYPH[st.status] || PLAN_GLYPH.pending })), explanation: ev.explanation });
91716
91787
  break;
91717
91788
  }
91718
91789
  case "hypotheses": {
@@ -91729,30 +91800,34 @@ ${r.content}`).join("\n\n") };
91729
91800
  });
91730
91801
  setProposal({ content: ev.content || "", calls: ev.calls || [], remember: ev.remember || [], remember_text: ev.remember_text || "", agent: ev.agent || null });
91731
91802
  setStatus("waiting for your decision");
91803
+ setStatusOf("");
91732
91804
  break;
91733
91805
  case "question":
91734
91806
  foldThinking();
91735
91807
  flushDraft();
91736
91808
  addAsk(ev);
91737
91809
  break;
91738
- case "question_closed":
91810
+ case "question_closed": {
91739
91811
  if (pendingAsk.current?.id === ev.id) {
91740
- append({ kind: "you", text: pendingAsk.current.display });
91741
91812
  pendingAsk.current = null;
91742
91813
  setSendingAsk(null);
91743
91814
  setValue("");
91744
91815
  }
91816
+ const closing = asksRef.current.find((q) => q.id === ev.id);
91817
+ if (closing) append(answeredItem(closing, ev));
91745
91818
  dropAsk(ev.id);
91746
- append({ kind: "info", text: `answered: ${ev.answer}` });
91747
91819
  break;
91820
+ }
91748
91821
  case "mcp":
91749
91822
  append({ kind: "mcp", servers: ev.servers || [] });
91750
91823
  break;
91751
91824
  case "memory": {
91752
91825
  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}` });
91826
+ append({ kind: "info", text: [
91827
+ `memory: ${ev.dir}${items2.some((i) => i.source === "repo") ? ` \xB7 shared: ${ev.repo_dir}` : ""}`,
91828
+ ...items2.length ? [] : ["nothing remembered yet; the model writes here with remember, and you may edit the files by hand"],
91829
+ ...items2.map((it) => ` ${it.name} (${it.type}${it.source === "repo" ? ", shared" : ""}): ${it.description}`)
91830
+ ].join("\n") });
91756
91831
  break;
91757
91832
  }
91758
91833
  case "reflection":
@@ -91816,8 +91891,10 @@ ${r.content}`).join("\n\n") };
91816
91891
  case "rewind": {
91817
91892
  setConfirm(null);
91818
91893
  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 ")}` });
91894
+ append({ kind: "info", text: [
91895
+ `back to \u201C${(ev.said || "").slice(0, 60)}\u201D \xB7 ${did} restored`,
91896
+ ...String(ev.stat || "").split("\n").filter((l) => l.trim()).map((l) => ` ${l}`)
91897
+ ].join("\n") });
91821
91898
  break;
91822
91899
  }
91823
91900
  case "goal":
@@ -91960,6 +92037,8 @@ ${r.content}`).join("\n\n") };
91960
92037
  exit();
91961
92038
  }, 2500);
91962
92039
  };
92040
+ const answering = !!(proposal || question || picker || confirm || trust || looking || reflection || search);
92041
+ const escOwned = answering || files.length > 0 || panelIndex >= 0;
91963
92042
  use_input_default((input, key) => {
91964
92043
  hereNow();
91965
92044
  if (key.ctrl && input === "c") {
@@ -92108,28 +92187,34 @@ ${r.content}`).join("\n\n") };
92108
92187
  if (question && step && !picker) {
92109
92188
  if (key.pageDown || key.pageUp) {
92110
92189
  setConsultTop(Math.max(0, Math.min(
92111
- consultLines.length - consultHeight,
92112
- consultStart + (key.pageDown ? consultHeight : -consultHeight)
92190
+ consult.text.length - consultView.textHeight,
92191
+ consultView.textStart + (key.pageDown ? consultView.textHeight : -consultView.textHeight)
92113
92192
  )));
92114
92193
  return;
92115
92194
  }
92116
92195
  if (key.escape || sendingAsk) return;
92117
- if (!listAsk && question.kind !== "decision") {
92196
+ if (!listAsk) {
92118
92197
  const n = stepLabels.length;
92198
+ const rows2 = n ? n + 1 : 0;
92119
92199
  if (step.multi && n && !value.trim()) {
92120
92200
  if (key.upArrow) {
92121
- setQCursor((c) => (c + n - 1) % n);
92201
+ setQCursor((c) => (c + rows2 - 1) % rows2);
92122
92202
  return;
92123
92203
  }
92124
92204
  if (key.downArrow || key.tab) {
92125
- setQCursor((c) => (c + 1) % n);
92205
+ setQCursor((c) => (c + 1) % rows2);
92126
92206
  return;
92127
92207
  }
92128
92208
  if (input === " " && !value.trim()) {
92129
- togglePick(stepLabels[Math.min(qCursor, n - 1)]);
92209
+ if (qCursor < n) togglePick(stepLabels[qCursor]);
92130
92210
  return;
92131
92211
  }
92132
92212
  }
92213
+ if (n && !value.trim() && input === String(rows2)) {
92214
+ if (step.multi) setQCursor(n);
92215
+ else setQChoice(n);
92216
+ return;
92217
+ }
92133
92218
  if (step.multi && !value.trim() && /^[1-9]$/.test(input) && Number(input) <= n) {
92134
92219
  const label = stepLabels[Number(input) - 1];
92135
92220
  setQCursor(Number(input) - 1);
@@ -92138,15 +92223,16 @@ ${r.content}`).join("\n\n") };
92138
92223
  }
92139
92224
  if (!step.multi && n && !value.trim()) {
92140
92225
  if (key.upArrow) {
92141
- setQChoice(choiceRow < 0 ? n - 1 : (choiceRow + n - 1) % n);
92226
+ setQChoice(choiceRow < 0 ? rows2 - 1 : (choiceRow + rows2 - 1) % rows2);
92142
92227
  return;
92143
92228
  }
92144
92229
  if (key.downArrow) {
92145
- setQChoice((choiceRow + 1) % n);
92230
+ setQChoice((choiceRow + 1) % rows2);
92146
92231
  return;
92147
92232
  }
92148
92233
  }
92149
92234
  if (key.return && !key.meta && !key.shift && !value.trim()) {
92235
+ if (ownMarked) return;
92150
92236
  if (!step.multi && qChoice !== null) {
92151
92237
  answerStep(String(qChoice + 1));
92152
92238
  return;
@@ -92229,7 +92315,6 @@ ${r.content}`).join("\n\n") };
92229
92315
  else if (key.tab) setValue(menu[Math.min(menuIndex, menu.length - 1)].name + " ");
92230
92316
  return;
92231
92317
  }
92232
- const answering = !!(proposal || question || picker || confirm || trust || looking || reflection || search);
92233
92318
  if (key.tab && phaseRef.current === "busy" && !answering && value.trim() && !/^[/!]/.test(value.trim())) {
92234
92319
  const raw = value.trim();
92235
92320
  remember(raw);
@@ -92292,9 +92377,9 @@ ${r.content}`).join("\n\n") };
92292
92377
  setValue("");
92293
92378
  setQPicks((ps) => ps.includes(label) ? ps.filter((x) => x !== label) : [...ps, label]);
92294
92379
  };
92295
- const submitAsk = (payload, display) => {
92380
+ const submitAsk = (payload) => {
92296
92381
  if (!question || pendingAsk.current) return;
92297
- pendingAsk.current = { id: question.id, display };
92382
+ pendingAsk.current = { id: question.id };
92298
92383
  setSendingAsk(question.id);
92299
92384
  if (core2.send({ cmd: "answer", id: question.id, ...payload }) === false) {
92300
92385
  pendingAsk.current = null;
@@ -92305,22 +92390,20 @@ ${r.content}`).join("\n\n") };
92305
92390
  const holdAll = () => {
92306
92391
  if (!listAsk) return;
92307
92392
  const answers = Object.fromEntries(question.questions.map((q) => [q.id, q.id === "missed" ? "" : "holds"]));
92308
- submitAsk({ answers }, `held all ${listRows.length} as stated`);
92393
+ submitAsk({ answers });
92309
92394
  };
92310
92395
  const answerWhole = (text) => {
92311
92396
  if (!text.trim() || /^\d+$/.test(text.trim())) {
92312
92397
  append({ kind: "warn", text: "say what the number means, or type /hold to confirm every constraint" });
92313
92398
  return;
92314
92399
  }
92315
- submitAsk({ text }, text);
92400
+ submitAsk({ text });
92316
92401
  };
92317
92402
  const answerStep = (text) => {
92318
92403
  if (!question || !step) return;
92319
- const display = step.secret ? "(kept to yourself)" : text || (step.default ? `(the default: ${step.default})` : "(nothing)");
92320
92404
  const answers = { ...qAnswers, [step.id]: text };
92321
92405
  if (qStep + 1 < steps.length) {
92322
92406
  setValue("");
92323
- append({ kind: "you", text: display });
92324
92407
  setQAnswers(answers);
92325
92408
  setQStep(qStep + 1);
92326
92409
  setConsultTop(0);
@@ -92329,7 +92412,7 @@ ${r.content}`).join("\n\n") };
92329
92412
  setQChoice(null);
92330
92413
  return;
92331
92414
  }
92332
- submitAsk({ answers }, display);
92415
+ submitAsk({ answers });
92333
92416
  };
92334
92417
  const vote = (polarity, why2 = "") => {
92335
92418
  core2.send({ cmd: polarity > 0 ? "accept" : "reject", ...why2 ? { why: why2 } : {} });
@@ -92549,7 +92632,7 @@ ${r.content}`).join("\n\n") };
92549
92632
  if (question && step && !/^\/(quit|exit|stop)\b/.test(raw)) {
92550
92633
  if (listAsk && text === "/hold") holdAll();
92551
92634
  else if (listAsk) answerWhole(text);
92552
- else answerStep(text);
92635
+ else answerStep(markedPick && text.trim() && typedRow === null ? `${markedPick} ${text.trim()}` : text);
92553
92636
  return;
92554
92637
  }
92555
92638
  if (reflection) closeReflection(reflection.id, "dismiss");
@@ -92580,13 +92663,18 @@ ${r.content}`).join("\n\n") };
92580
92663
  !ctrlc && question && step && !step.secret && { text: "ctrl+g editor", drop: 2 },
92581
92664
  ctrlc ? { text: "ctrl+c again to quit" } : { text: "/ for commands", drop: 1 }
92582
92665
  ], 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` : "");
92666
+ const stepAt = planSteps.findIndex((st) => st.status === "in_progress");
92667
+ const phaseWord = statusOf === "tool" ? "" : status;
92668
+ const doing = [stepAt >= 0 ? `${stepAt + 1}/${planSteps.length} \xB7 ${planSteps[stepAt].step}` : "", phaseWord].filter(Boolean).join(" \xB7 ") || "working";
92669
+ const beside = [elapsed >= 1 ? fmtDur(elapsed) : "", escOwned ? "" : "esc to interrupt"].filter(Boolean).join(" \xB7 ");
92670
+ const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${doing}${beside ? ` (${beside})` : ""}`;
92671
+ const spinnerRows = wrapAnsi2(spinnerLabel, Math.max(1, width - 1), { hard: true, trim: false }).split("\n").length;
92584
92672
  const rows = stdout?.rows || DEFAULT_ROWS;
92585
92673
  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);
92674
+ 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 * (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);
92587
92675
  const liveBudget = Math.max(LIVE_MIN_ROWS, Math.min(DRAFT_TAIL_LINES, rows - 1 - chrome));
92588
92676
  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: [
92677
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Static, { items, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", marginTop: blockGap(item), children: [
92590
92678
  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
92679
  item.kind === "banner" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 1, children: [
92592
92680
  MASCOT.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { children: [
@@ -92622,6 +92710,15 @@ ${r.content}`).join("\n\n") };
92622
92710
  ] }, i))
92623
92711
  ] })
92624
92712
  ] }),
92713
+ item.kind === "answered" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92714
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, bold: true, children: item.title }),
92715
+ item.entries.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92716
+ e.question ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " \u2022 ", children: e.question }) : null,
92717
+ e.pick ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " pick: ", children: e.pick }) : null,
92718
+ e.pick && e.why ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " why: ", children: e.why }) : null,
92719
+ !e.pick ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hang, { lead: " answer: ", children: e.why || "(nothing)" }) : null
92720
+ ] }, i))
92721
+ ] }),
92625
92722
  item.kind === "agent" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text2, { color: "magenta", children: [
92626
92723
  " \u25B8 ",
92627
92724
  item.text
@@ -92634,22 +92731,25 @@ ${r.content}`).join("\n\n") };
92634
92731
  " \xB7 ",
92635
92732
  item.text
92636
92733
  ] }) : /* @__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
- ))
92734
+ item.kind === "plan" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", children: [
92735
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolRow, { text: "updated the plan" }),
92736
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 2, children: [
92737
+ item.explanation ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, italic: true, children: item.explanation }) : null,
92738
+ item.steps.map((st, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
92739
+ Text2,
92740
+ {
92741
+ dimColor: st.status !== "in_progress",
92742
+ bold: st.status === "in_progress",
92743
+ color: st.status === "in_progress" ? ACCENT : void 0,
92744
+ children: [
92745
+ st.glyph,
92746
+ " ",
92747
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { strikethrough: st.status === "completed", children: st.step })
92748
+ ]
92749
+ },
92750
+ i
92751
+ ))
92752
+ ] })
92653
92753
  ] }),
92654
92754
  item.kind === "hypotheses" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { flexDirection: "column", paddingLeft: 2, children: [
92655
92755
  item.explanation ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: item.explanation }) : null,
@@ -92754,17 +92854,17 @@ ${r.content}`).join("\n\n") };
92754
92854
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: "red", children: item.text })
92755
92855
  ] })
92756
92856
  ] }, 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)),
92857
+ heldRows.map((item, i) => (
92858
+ // a held row stands where it will print: the same gap above it here as on the transcript
92859
+ /* @__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: [
92860
+ " \u23BF ",
92861
+ item.text
92862
+ ] }) }, i)
92863
+ )),
92761
92864
  draft.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { marginTop: 1, children: [
92762
92865
  /* @__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
92866
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: liveTail(renderMarkdown(draft, width - 2), width - 2, liveBudget) })
92764
92867
  ] }),
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
92868
  (phase === "busy" || phase === "connecting") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box2, { marginTop: 1, children: [
92769
92869
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(build_default, { type: "dots" }) }),
92770
92870
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, children: spinnerLabel })
@@ -92775,11 +92875,11 @@ ${r.content}`).join("\n\n") };
92775
92875
  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
92876
  !listAsk && steps.length > 1 ? ` (${qStep + 1} of ${steps.length})` : ""
92777
92877
  ] }),
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,
92878
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: consultView.shownText.join("\n") }),
92879
+ 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,
92880
+ consultView.shownRows.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { children: ["", ...consultView.shownRows].join("\n") }) : null,
92780
92881
  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
92882
  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
92883
  sendingAsk === question.id ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { color: ACCENT, children: "Sending answer\u2026" }) : null,
92784
92884
  !listAsk ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text2, { dimColor: true, wrap: "truncate-end", children: " " + askHint }) : null
92785
92885
  ] }),
@@ -93100,12 +93200,13 @@ ${r.content}`).join("\n\n") };
93100
93200
  if (reflection && why !== reflection.id && (input === "1" || input === "2")) return true;
93101
93201
  if (proposal && (input === "a" || input === "p") && (proposal.remember || []).length) return true;
93102
93202
  if (!question || !step) return false;
93103
- if (listAsk || question.kind === "decision") return false;
93203
+ if (listAsk) return false;
93204
+ if (stepLabels.length && input === String(stepLabels.length + 1)) return true;
93104
93205
  if (step.multi && /^[1-9]$/.test(input) && Number(input) <= stepLabels.length) return true;
93105
93206
  if (stepLabels.length && (key.upArrow || key.downArrow)) return true;
93106
93207
  return !!(step.multi && stepLabels.length && input === " ");
93107
93208
  },
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?"
93209
+ 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
93210
  }
93110
93211
  )
93111
93212
  ] }),
@@ -93172,7 +93273,7 @@ init_install();
93172
93273
  await init_theme();
93173
93274
  var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
93174
93275
  import { spawnSync as spawnSync6 } from "node:child_process";
93175
- var MINE3 = true ? "0.2.26" : "0.0.0";
93276
+ var MINE3 = true ? "0.2.27" : "0.0.0";
93176
93277
  var layout = installLayout();
93177
93278
  function completeInstall() {
93178
93279
  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.27",
4
4
  "description": "Hum: a self-improving coding agent for your terminal.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",