@buildaharness/aielia 0.3.4 → 0.3.5

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 (97) hide show
  1. package/README.md +63 -20
  2. package/dist/PlanGraphPane.d.ts +19 -0
  3. package/dist/_memory-core-generated.d.ts +1764 -0
  4. package/dist/agent-loop.d.ts +23 -8
  5. package/dist/ambiguity-guard-flag.d.ts +12 -0
  6. package/dist/ambiguity-guard.d.ts +20 -0
  7. package/dist/answer-claim.d.ts +13 -1
  8. package/dist/ask-clarification-service.d.ts +12 -1
  9. package/dist/ask-response-format.d.ts +6 -0
  10. package/dist/assistant-session.d.ts +12 -1
  11. package/dist/assistant-source.d.ts +7 -0
  12. package/dist/assistant-types.d.ts +17 -1
  13. package/dist/assistant.d.ts +128 -6
  14. package/dist/benchmark-injected-failure.d.ts +6 -0
  15. package/dist/bin-CjKpxDxl.js +4836 -0
  16. package/dist/bin-CjKpxDxl.js.map +1 -0
  17. package/dist/cli-session.d.ts +14 -1
  18. package/dist/cli.d.ts +17 -2
  19. package/dist/cli.js +1 -1
  20. package/dist/code-plan-templates.d.ts +21 -0
  21. package/dist/config.d.ts +29 -0
  22. package/dist/constraint-check.d.ts +35 -0
  23. package/dist/contradiction-checker.d.ts +7 -0
  24. package/dist/decomposed-answer.d.ts +13 -0
  25. package/dist/decomposition-classifier.d.ts +2 -0
  26. package/dist/doctor-checks.d.ts +3 -0
  27. package/dist/episodic-digest.d.ts +89 -0
  28. package/dist/fact-extraction.d.ts +39 -0
  29. package/dist/file-tools-mcp-server.mjs +138 -12
  30. package/dist/file-tools.d.ts +4 -0
  31. package/dist/first-run.d.ts +0 -2
  32. package/dist/goal-graph-store.d.ts +18 -18
  33. package/dist/grounding-check.d.ts +33 -0
  34. package/dist/harness-bridge.d.ts +75 -2
  35. package/dist/harness-token-budget.d.ts +9 -0
  36. package/dist/index.d.ts +20 -1
  37. package/dist/index.js +165 -94
  38. package/dist/index.js.map +1 -1
  39. package/dist/layer-policy-flag.d.ts +13 -0
  40. package/dist/layer-policy-wiring.d.ts +77 -0
  41. package/dist/layer-settings.d.ts +49 -0
  42. package/dist/layer-telemetry.d.ts +2 -0
  43. package/dist/lexical/lexical-mode.d.ts +29 -0
  44. package/dist/memory-consolidation.d.ts +80 -0
  45. package/dist/memory-governance.d.ts +30 -0
  46. package/dist/memory-reviewer.d.ts +114 -0
  47. package/dist/memory-service.d.ts +348 -9
  48. package/dist/model-json.d.ts +17 -0
  49. package/dist/next-step-context.d.ts +51 -0
  50. package/dist/next-step-proposer.d.ts +3 -2
  51. package/dist/plan-graph-flag.d.ts +20 -0
  52. package/dist/plan-question.d.ts +60 -0
  53. package/dist/plan-service.d.ts +6 -2
  54. package/dist/plan-step-prompt.d.ts +15 -0
  55. package/dist/plan-store.d.ts +7 -1
  56. package/dist/plan-viz/normalize.d.ts +14 -0
  57. package/dist/plan-viz/plan-detail-lines.d.ts +3 -0
  58. package/dist/plan-viz/plan-layout.d.ts +48 -0
  59. package/dist/plan-viz/plan-nav.d.ts +29 -0
  60. package/dist/plan-viz/plan-raster.d.ts +36 -0
  61. package/dist/plan-viz/plan-routes.d.ts +6 -0
  62. package/dist/plan-viz/plan-snapshot.d.ts +73 -0
  63. package/dist/plan-viz/plan-viewport.d.ts +29 -0
  64. package/dist/plan-viz/plan-width.d.ts +15 -0
  65. package/dist/plan-viz/testkit/display-width.d.ts +12 -0
  66. package/dist/plan-viz/testkit/generators.d.ts +61 -0
  67. package/dist/plan-viz/testkit/grid-oracles.d.ts +38 -0
  68. package/dist/plan-viz/testkit/nav-oracles.d.ts +79 -0
  69. package/dist/plan-viz/testkit/types.d.ts +8 -0
  70. package/dist/plan-viz/types.d.ts +34 -0
  71. package/dist/{provider-setup-CPbB5y_V.js → provider-setup-LFsaTkpf.js} +9308 -5510
  72. package/dist/provider-setup-LFsaTkpf.js.map +1 -0
  73. package/dist/recall-tool.d.ts +43 -0
  74. package/dist/recovery-note.d.ts +22 -0
  75. package/dist/response-service.d.ts +11 -1
  76. package/dist/review-checker.d.ts +10 -4
  77. package/dist/reviewer-revision.d.ts +23 -0
  78. package/dist/risk-classifier.d.ts +7 -0
  79. package/dist/scripted-llm-client.d.ts +26 -1
  80. package/dist/semantic-compaction.d.ts +15 -0
  81. package/dist/semantic-hypotheses.d.ts +40 -0
  82. package/dist/source-reliability.d.ts +71 -0
  83. package/dist/task-completion-check.d.ts +24 -0
  84. package/dist/tool-control-plane.d.ts +33 -1
  85. package/dist/tool-effect-class.d.ts +9 -0
  86. package/dist/transcript-compaction.d.ts +9 -0
  87. package/dist/{tui-app-DeyZ4Pr9.js → tui-app-BLR-PRFp.js} +321 -7
  88. package/dist/tui-app-BLR-PRFp.js.map +1 -0
  89. package/dist/tui-app.d.ts +38 -0
  90. package/dist/turn-intent-classifier.d.ts +75 -16
  91. package/dist/turn-interpreter.d.ts +25 -3
  92. package/dist/version.d.ts +1 -1
  93. package/package.json +6 -6
  94. package/dist/bin-CdVTAe7j.js +0 -2209
  95. package/dist/bin-CdVTAe7j.js.map +0 -1
  96. package/dist/provider-setup-CPbB5y_V.js.map +0 -1
  97. package/dist/tui-app-DeyZ4Pr9.js.map +0 -1
@@ -3,11 +3,11 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { jsxs, jsx } from "react/jsx-runtime";
5
5
  import { Readable, Writable } from "node:stream";
6
- import { useState, useRef, useCallback, useSyncExternalStore, useEffect } from "react";
6
+ import { useState, useRef, useMemo, useCallback, useSyncExternalStore, useEffect } from "react";
7
7
  import { useWindowSize, usePaste, useInput, Box, Text, render, Static } from "ink";
8
- import { r as runCli, P as PLAN_LINE_PREFIX, I as ICONS } from "./bin-CdVTAe7j.js";
8
+ import { r as renderPlan, t as toLines, a as runCli, P as PLAN_LINE_PREFIX, I as ICONS } from "./bin-CjKpxDxl.js";
9
9
  import { format } from "node:util";
10
- import { j as DIFF_INDENT } from "./provider-setup-CPbB5y_V.js";
10
+ import { n as DIFF_INDENT } from "./provider-setup-LFsaTkpf.js";
11
11
  function classify(raw, stream) {
12
12
  if (raw.startsWith("\r")) {
13
13
  return { type: "progress", text: raw.replace(/\r/g, "").trimEnd() };
@@ -244,6 +244,189 @@ function SelectPrompt(props) {
244
244
  ] }, option.key)) })
245
245
  ] });
246
246
  }
247
+ function navModelFrom(nodes, boxes) {
248
+ const byId = new Map(boxes.map((b) => [b.id, b]));
249
+ const ids = nodes.map((n) => n.id).filter((id) => byId.has(id));
250
+ const dependents = Object.fromEntries(ids.map((id) => [id, []]));
251
+ for (const n of nodes) if (byId.has(n.id)) {
252
+ for (const d of n.deps) if (dependents[d]) dependents[d].push(n.id);
253
+ }
254
+ return {
255
+ ids,
256
+ taskOrder: ids,
257
+ x: Object.fromEntries(ids.map((id) => [id, byId.get(id).x + byId.get(id).w / 2])),
258
+ y: Object.fromEntries(ids.map((id) => [id, byId.get(id).y])),
259
+ deps: Object.fromEntries(nodes.map((n) => [n.id, n.deps.filter((d) => byId.has(d))])),
260
+ dependents
261
+ };
262
+ }
263
+ const cmp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
264
+ const byX = (m, ids) => [...ids].sort((a, b) => m.x[a] - m.x[b] || cmp(a, b));
265
+ const planNavigator = {
266
+ start: (_m, id) => ({ cur: id, k: 0 }),
267
+ press(m, st, key) {
268
+ if (key === "tab" || key === "shiftTab") {
269
+ const n = m.taskOrder.length;
270
+ if (!n) return st;
271
+ const i2 = m.taskOrder.indexOf(st.cur);
272
+ return { cur: m.taskOrder[(i2 + (key === "tab" ? 1 : -1) + n) % n], k: 0 };
273
+ }
274
+ if (key === "up" || key === "down") {
275
+ const origin = st.lastKey === key && st.lastFrom !== void 0 ? st.lastFrom : st.cur;
276
+ const cands = byX(m, (key === "up" ? m.deps[origin] : m.dependents[origin]) ?? []);
277
+ if (!cands.length) return st;
278
+ const nearest = [...cands].sort((a, b) => Math.abs(m.x[a] - m.x[origin]) - Math.abs(m.x[b] - m.x[origin]) || cmp(a, b))[0];
279
+ const k = st.lastKey === key ? (st.k + 1) % cands.length : 0;
280
+ return { cur: cands[(cands.indexOf(nearest) + k) % cands.length], lastKey: key, lastFrom: origin, k };
281
+ }
282
+ const rank = byX(m, m.ids.filter((id) => m.y[id] === m.y[st.cur]));
283
+ const i = rank.indexOf(st.cur);
284
+ if (i < 0) return st;
285
+ return { cur: rank[(i + (key === "left" ? -1 : 1) + rank.length) % rank.length], lastKey: key, k: 0 };
286
+ }
287
+ };
288
+ function followSelection(prev, box, grid, term) {
289
+ const width = Math.min(term.cols, grid.width);
290
+ const height = Math.min(term.rows, grid.height);
291
+ const fit = (start, size, bStart, bSize, total) => {
292
+ let s = start;
293
+ if (bStart < s) s = bStart;
294
+ if (bStart + bSize > s + size) s = bStart + bSize - size;
295
+ return Math.max(0, Math.min(s, total - size));
296
+ };
297
+ return { width, height, left: fit(prev.left, width, box.x, box.w, grid.width), top: fit(prev.top, height, box.y, box.h, grid.height) };
298
+ }
299
+ function scrollIndicators(v, grid) {
300
+ return { up: v.top > 0, down: v.top + v.height < grid.height, left: v.left > 0, right: v.left + v.width < grid.width };
301
+ }
302
+ const STATUS_WORD = {
303
+ pending: "pending",
304
+ ready: "ready to run",
305
+ running: "running",
306
+ done: "done",
307
+ failed: "failed",
308
+ awaiting_user: "waiting for you",
309
+ awaiting_input: "blocked, waiting for input",
310
+ cancelled: "cancelled"
311
+ };
312
+ function wrap(text, width) {
313
+ const out = [];
314
+ let line = "";
315
+ for (const word of text.split(/\s+/).filter(Boolean)) {
316
+ let w = word;
317
+ while (w.length > width) {
318
+ if (line) {
319
+ out.push(line);
320
+ line = "";
321
+ }
322
+ out.push(w.slice(0, width));
323
+ w = w.slice(width);
324
+ }
325
+ if (!line) line = w;
326
+ else if (line.length + 1 + w.length <= width) line += ` ${w}`;
327
+ else {
328
+ out.push(line);
329
+ line = w;
330
+ }
331
+ }
332
+ if (line) out.push(line);
333
+ return out;
334
+ }
335
+ function planDetailLines(nodes, id, width) {
336
+ const node = nodes.find((n) => n.id === id);
337
+ if (!node) return ["No task selected."];
338
+ const w = Math.max(10, width);
339
+ const name = (i) => {
340
+ var _a;
341
+ return ((_a = nodes.find((n) => n.id === i)) == null ? void 0 : _a.id) ?? i;
342
+ };
343
+ const dependents = nodes.filter((n) => n.deps.includes(node.id)).map((n) => n.id);
344
+ return [
345
+ ...wrap(node.id, w),
346
+ "",
347
+ ...wrap(node.label, w),
348
+ "",
349
+ `Status: ${STATUS_WORD[node.status] ?? node.status}`,
350
+ ...wrap(`Depends on: ${node.deps.length ? node.deps.map(name).join(", ") : "nothing"}`, w),
351
+ ...wrap(`Needed by: ${dependents.length ? dependents.join(", ") : "nothing"}`, w)
352
+ ];
353
+ }
354
+ const DRAWER_DOCK_COLUMNS = 120;
355
+ const DRAWER_WIDTH = 36;
356
+ function PlanGraphPane({ nodes, columns, rows, active = true, color = true, ascii = false, onClose }) {
357
+ const docked = columns >= DRAWER_DOCK_COLUMNS;
358
+ const [drawerOpen, setDrawerOpen] = useState(false);
359
+ const showDrawer = docked || drawerOpen;
360
+ const graphCols = showDrawer ? Math.max(20, columns - DRAWER_WIDTH - 1) : columns;
361
+ const graphRows = Math.max(3, rows - 2);
362
+ const [nav, setNav] = useState(void 0);
363
+ const lastIndex = useRef(0);
364
+ const viewport = useRef({ left: 0, top: 0, width: 0, height: 0 });
365
+ const base = useMemo(() => renderPlan(nodes, { maxCols: graphCols, ascii, color: false }), [nodes, graphCols, ascii]);
366
+ const model = useMemo(() => base.ok ? navModelFrom(nodes, base.boxes) : void 0, [nodes, base]);
367
+ let selectedId;
368
+ if (model && model.ids.length) {
369
+ if (nav && model.ids.includes(nav.cur)) selectedId = nav.cur;
370
+ else selectedId = model.taskOrder[Math.min(lastIndex.current, model.taskOrder.length - 1)];
371
+ }
372
+ if (model && selectedId) lastIndex.current = model.taskOrder.indexOf(selectedId);
373
+ const detail = useMemo(() => planDetailLines(nodes, selectedId, DRAWER_WIDTH - 2), [nodes, selectedId]);
374
+ const [scroll, setScroll] = useState({ id: void 0, offset: 0 });
375
+ const drawerRows = graphRows;
376
+ const maxScroll = Math.max(0, detail.length - drawerRows);
377
+ const drawerOffset = scroll.id === selectedId ? Math.min(scroll.offset, maxScroll) : 0;
378
+ const scrollDrawer = (delta) => setScroll({ id: selectedId, offset: Math.max(0, Math.min(maxScroll, drawerOffset + delta)) });
379
+ useInput(
380
+ (input, key) => {
381
+ if (key.escape || input === "q") return onClose();
382
+ if (key.return || input === "d") return setDrawerOpen((open) => !open);
383
+ if (showDrawer) {
384
+ if (input === "j") return scrollDrawer(1);
385
+ if (input === "k") return scrollDrawer(-1);
386
+ if (key.pageDown) return scrollDrawer(drawerRows);
387
+ if (key.pageUp) return scrollDrawer(-drawerRows);
388
+ }
389
+ if (!model || !selectedId) return;
390
+ const k = key.upArrow || input === "[" ? "up" : key.downArrow || input === "]" ? "down" : key.leftArrow ? "left" : key.rightArrow ? "right" : key.tab ? key.shift ? "shiftTab" : "tab" : void 0;
391
+ if (!k) return;
392
+ const from = nav && nav.cur === selectedId ? nav : planNavigator.start(model, selectedId);
393
+ setNav(planNavigator.press(model, from, k));
394
+ },
395
+ { isActive: active }
396
+ );
397
+ if (!base.ok || !model) {
398
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, children: [
399
+ /* @__PURE__ */ jsxs(Text, { children: [
400
+ "Plan graph unavailable: ",
401
+ base.ok ? "nothing to draw" : base.message
402
+ ] }),
403
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "q / Esc closes" })
404
+ ] });
405
+ }
406
+ const r = renderPlan(nodes, { maxCols: graphCols, ascii, color, selectedId });
407
+ if (!r.ok) return /* @__PURE__ */ jsxs(Text, { children: [
408
+ "Plan graph unavailable: ",
409
+ r.message
410
+ ] });
411
+ const box = r.boxes.find((b) => b.id === selectedId);
412
+ const vp = box ? followSelection(viewport.current, box, r, { cols: graphCols, rows: graphRows }) : { left: 0, top: 0, width: Math.min(graphCols, r.width), height: Math.min(graphRows, r.height) };
413
+ viewport.current = vp;
414
+ const lines = toLines(r.cells, r.styles, [vp.top, vp.top + vp.height], [vp.left, vp.left + vp.width]);
415
+ const more = scrollIndicators(vp, r);
416
+ const arrows = `${more.up ? "↑" : " "}${more.down ? "↓" : " "}${more.left ? "←" : " "}${more.right ? "→" : " "}`;
417
+ const done = nodes.filter((n) => n.status === "done").length;
418
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, children: [
419
+ /* @__PURE__ */ jsxs(Text, { bold: true, children: [
420
+ `Plan graph — ${done}/${nodes.length} done `,
421
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: arrows })
422
+ ] }),
423
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [
424
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: graphCols, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: line.length ? line : " " }, i)) }),
425
+ showDrawer && /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: DRAWER_WIDTH + 1, paddingLeft: 1, borderStyle: "single", borderTop: false, borderBottom: false, borderRight: false, children: detail.slice(drawerOffset, drawerOffset + drawerRows).map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: line.length ? line : " " }, i)) })
426
+ ] }),
427
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: docked ? "↑↓←→ move · Tab next · j/k PgUp/PgDn scroll details · q close" : "↑↓←→ move · Tab next · Enter details · q close" })
428
+ ] });
429
+ }
247
430
  const HEADER_RE = /^(#{1,6})\s+(.*)$/;
248
431
  const CHECKBOX_RE = /^(\s*[-*]\s)\[([ xX])\]\s+(.*)$/;
249
432
  const DIFF_LINE_RE = /^(\s*\d+) ([+\- ])(.*)$/;
@@ -463,6 +646,107 @@ class StatusBridge {
463
646
  for (const listener of this.listeners) listener();
464
647
  }
465
648
  }
649
+ const ALT_SCREEN_ON = "\x1B[?1049h";
650
+ const ALT_SCREEN_OFF = "\x1B[?1049l";
651
+ const ALT_SCREEN_SETTLE_MS = 80;
652
+ const PLAN_GRAPH_MIN_RENDER_MS = 100;
653
+ class PlanGraphBridge {
654
+ constructor(writeRaw, settleMs = ALT_SCREEN_SETTLE_MS, minRenderMs = PLAN_GRAPH_MIN_RENDER_MS) {
655
+ __publicField(this, "view", { mode: "chat", nodes: [] });
656
+ __publicField(this, "listeners", /* @__PURE__ */ new Set());
657
+ __publicField(this, "timer");
658
+ __publicField(this, "pendingNodes");
659
+ __publicField(this, "transition", Promise.resolve());
660
+ __publicField(this, "subscribe", (listener) => {
661
+ this.listeners.add(listener);
662
+ return () => {
663
+ this.listeners.delete(listener);
664
+ };
665
+ });
666
+ __publicField(this, "getSnapshot", () => this.view);
667
+ this.writeRaw = writeRaw;
668
+ this.settleMs = settleMs;
669
+ this.minRenderMs = minRenderMs;
670
+ }
671
+ isOpen() {
672
+ return this.view.mode !== "chat";
673
+ }
674
+ set(view) {
675
+ this.view = view;
676
+ for (const listener of this.listeners) listener();
677
+ }
678
+ sleep() {
679
+ return new Promise((resolve) => setTimeout(resolve, this.settleMs));
680
+ }
681
+ open(nodes) {
682
+ this.transition = this.transition.then(async () => {
683
+ if (this.view.mode !== "chat") {
684
+ this.update(nodes);
685
+ return;
686
+ }
687
+ this.set({ mode: "blank", nodes });
688
+ await this.sleep();
689
+ this.writeRaw(ALT_SCREEN_ON);
690
+ this.set({ mode: "pane", nodes: this.pendingNodes ?? nodes });
691
+ this.pendingNodes = void 0;
692
+ });
693
+ return this.transition;
694
+ }
695
+ close() {
696
+ this.transition = this.transition.then(async () => {
697
+ if (this.view.mode === "chat") return;
698
+ this.clearTimer();
699
+ this.set({ mode: "blank", nodes: this.view.nodes });
700
+ await this.sleep();
701
+ this.writeRaw(ALT_SCREEN_OFF);
702
+ this.set({ mode: "chat", nodes: [] });
703
+ });
704
+ return this.transition;
705
+ }
706
+ /** Synchronous leave for process exit: restores the main screen without waiting. */
707
+ restore() {
708
+ this.clearTimer();
709
+ if (this.view.mode === "pane") this.writeRaw(ALT_SCREEN_OFF);
710
+ this.view = { mode: "chat", nodes: [] };
711
+ }
712
+ /** Throttled node update: the first goes through at once, later ones coalesce to the newest within `minRenderMs`. Identical content is ignored. */
713
+ update(nodes) {
714
+ if (this.view.mode === "chat") return;
715
+ if (this.view.mode === "blank") {
716
+ this.pendingNodes = nodes;
717
+ return;
718
+ }
719
+ if (this.timer) {
720
+ this.pendingNodes = nodes;
721
+ return;
722
+ }
723
+ this.apply(nodes);
724
+ this.timer = setTimeout(() => this.flush(), this.minRenderMs);
725
+ }
726
+ apply(nodes) {
727
+ if (this.view.mode !== "pane" || JSON.stringify(nodes) === JSON.stringify(this.view.nodes)) return;
728
+ this.set({ mode: "pane", nodes });
729
+ }
730
+ flush() {
731
+ this.timer = void 0;
732
+ const next = this.pendingNodes;
733
+ this.pendingNodes = void 0;
734
+ if (next) {
735
+ this.apply(next);
736
+ this.timer = setTimeout(() => this.flush(), this.minRenderMs);
737
+ }
738
+ }
739
+ clearTimer() {
740
+ if (this.timer) clearTimeout(this.timer);
741
+ this.timer = void 0;
742
+ this.pendingNodes = void 0;
743
+ }
744
+ }
745
+ const NO_PLAN_GRAPH = { subscribe: () => () => {
746
+ }, getSnapshot: /* @__PURE__ */ (() => {
747
+ const v = { mode: "chat", nodes: [] };
748
+ return () => v;
749
+ })() };
466
750
  function UserMessageBox({ text, width, borderColor = "gray" }) {
467
751
  return /* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor, flexDirection: "column", paddingX: 1, width, children: text.split("\n").map((line, i) => /* @__PURE__ */ jsx(Text, { children: line.length > 0 ? line : " " }, i)) });
468
752
  }
@@ -509,12 +793,15 @@ function StatusLine({ indicators }) {
509
793
  ] }, indicator)) });
510
794
  }
511
795
  function TuiApp(props) {
512
- const { eventLog, prompt, status, onSubmitChat, onExit, columns } = props;
796
+ const { eventLog, prompt, status, planGraph, onSubmitChat, onExit, columns } = props;
513
797
  const log = useStore(eventLog);
514
798
  const pending = useStore(prompt);
515
799
  const statusIndicators = useStore(status);
516
800
  const windowSize = useWindowSize();
517
801
  const width = columns ?? windowSize.columns;
802
+ const graphView = useStore(planGraph ?? NO_PLAN_GRAPH);
803
+ const frozenLines = useRef(0);
804
+ if (graphView.mode === "chat") frozenLines.current = log.lines.length;
518
805
  useInput((input, key) => {
519
806
  if (key.ctrl && input === "c") onExit();
520
807
  });
@@ -538,10 +825,24 @@ function TuiApp(props) {
538
825
  },
539
826
  [eventLog, prompt, pending]
540
827
  );
828
+ const closePane = useCallback(() => {
829
+ void (planGraph == null ? void 0 : planGraph.close());
830
+ }, [planGraph]);
541
831
  const hasTransient = log.progressText.length > 0 || log.transientText.length > 0;
542
832
  const showSpinner = log.waitingForOutput && !hasTransient;
833
+ const staticItems = graphView.mode === "chat" ? log.lines : log.lines.slice(0, frozenLines.current);
834
+ const paneRows = Math.max(3, (windowSize.rows ?? 24) - 1);
835
+ if (graphView.mode !== "chat") {
836
+ const promptRows = pending ? Math.min(10, Math.floor(paneRows / 2)) : 0;
837
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
838
+ /* @__PURE__ */ jsx(Static, { items: staticItems, children: (line, index) => /* @__PURE__ */ jsx(LogLineText, { line, width }, index) }),
839
+ graphView.mode === "pane" && /* @__PURE__ */ jsx(PlanGraphPane, { nodes: graphView.nodes, columns: width, rows: paneRows - promptRows, active: !pending, color: !process.env.NO_COLOR, onClose: closePane }),
840
+ graphView.mode === "pane" && (pending == null ? void 0 : pending.options) && /* @__PURE__ */ jsx(SelectPrompt, { question: pending.question, options: pending.options, onSubmit: handleSubmitPrompt }),
841
+ graphView.mode === "pane" && pending && !pending.options && /* @__PURE__ */ jsx(TuiInput, { promptLabel: pending.question, onSubmitChat: handleSubmitChat, onSubmitPrompt: handleSubmitPrompt, columns })
842
+ ] });
843
+ }
543
844
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
544
- /* @__PURE__ */ jsx(Static, { items: log.lines, children: (line, index) => /* @__PURE__ */ jsx(LogLineText, { line, width }, index) }),
845
+ /* @__PURE__ */ jsx(Static, { items: staticItems, children: (line, index) => /* @__PURE__ */ jsx(LogLineText, { line, width }, index) }),
545
846
  showSpinner && /* @__PURE__ */ jsx(Spinner, {}),
546
847
  hasTransient && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
547
848
  log.progressText.length > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: log.progressText }),
@@ -583,11 +884,17 @@ async function runTuiApp(options = {}) {
583
884
  const status = new StatusBridge();
584
885
  const originalWrite = process.stdout.write.bind(process.stdout);
585
886
  const restoreCapture = startCapture((event) => eventLog.handleEvent(event));
887
+ const planGraph = new PlanGraphBridge((chunk) => void originalWrite(chunk));
888
+ let instanceRef;
586
889
  let instance;
587
890
  try {
588
891
  const inert = createInertStreams();
589
892
  instance = await runCli({
590
893
  ...options,
894
+ openPlanGraph: (nodes) => void planGraph.open(nodes),
895
+ onPlanProgress: (tasks) => {
896
+ if (planGraph.isOpen()) void (instanceRef == null ? void 0 : instanceRef.getPlanGraphNodes(tasks).then((nodes) => nodes && planGraph.update(nodes)));
897
+ },
591
898
  input: options.input ?? inert.input,
592
899
  output: options.output ?? inert.output,
593
900
  askYesNo: prompt.askYesNo,
@@ -598,8 +905,13 @@ async function runTuiApp(options = {}) {
598
905
  restoreCapture();
599
906
  throw err;
600
907
  }
908
+ instanceRef = instance;
601
909
  const refreshStatus = async () => {
602
910
  status.set(await instance.getStatusIndicators());
911
+ if (planGraph.isOpen()) {
912
+ const nodes = await instance.getPlanGraphNodes();
913
+ if (nodes) planGraph.update(nodes);
914
+ }
603
915
  };
604
916
  await refreshStatus();
605
917
  const handleSubmitChat = (line) => {
@@ -609,12 +921,13 @@ async function runTuiApp(options = {}) {
609
921
  const exit = () => {
610
922
  if (exiting) return;
611
923
  exiting = true;
924
+ planGraph.restore();
612
925
  restoreCapture();
613
926
  instance.close();
614
927
  app.unmount();
615
928
  process.exit(0);
616
929
  };
617
- const app = render(/* @__PURE__ */ jsx(TuiApp, { eventLog, prompt, status, onSubmitChat: handleSubmitChat, onExit: exit }), {
930
+ const app = render(/* @__PURE__ */ jsx(TuiApp, { eventLog, prompt, status, planGraph, onSubmitChat: handleSubmitChat, onExit: exit }), {
618
931
  // Phase 1's startCapture already routes every console.log/process.stdout.write call into
619
932
  // eventLog — ink's own patchConsole would double-intercept the same calls with a competing
620
933
  // mechanism (writing them above its own Static area independently), not compose with it.
@@ -629,9 +942,10 @@ async function runTuiApp(options = {}) {
629
942
  }
630
943
  export {
631
944
  EventLogBridge,
945
+ PlanGraphBridge,
632
946
  PromptBridge,
633
947
  StatusBridge,
634
948
  TuiApp,
635
949
  runTuiApp
636
950
  };
637
- //# sourceMappingURL=tui-app-DeyZ4Pr9.js.map
951
+ //# sourceMappingURL=tui-app-BLR-PRFp.js.map