@buildaharness/aielia 0.3.3 → 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.
- package/README.md +63 -20
- package/dist/PlanGraphPane.d.ts +19 -0
- package/dist/_memory-core-generated.d.ts +1764 -0
- package/dist/agent-loop.d.ts +31 -8
- package/dist/ambiguity-guard-flag.d.ts +12 -0
- package/dist/ambiguity-guard.d.ts +20 -0
- package/dist/answer-claim.d.ts +13 -1
- package/dist/ask-clarification-service.d.ts +12 -1
- package/dist/ask-response-format.d.ts +6 -0
- package/dist/assistant-session.d.ts +16 -5
- package/dist/assistant-source.d.ts +7 -0
- package/dist/assistant-types.d.ts +25 -1
- package/dist/assistant.d.ts +166 -5
- package/dist/benchmark-injected-failure.d.ts +6 -0
- package/dist/bin-CjKpxDxl.js +4836 -0
- package/dist/bin-CjKpxDxl.js.map +1 -0
- package/dist/cli-session.d.ts +26 -1
- package/dist/cli.d.ts +20 -2
- package/dist/cli.js +1 -1
- package/dist/code-plan-templates.d.ts +21 -0
- package/dist/config.d.ts +51 -0
- package/dist/constraint-check.d.ts +35 -0
- package/dist/contradiction-checker.d.ts +7 -0
- package/dist/decomposed-answer.d.ts +13 -0
- package/dist/decomposition-classifier.d.ts +2 -0
- package/dist/doctor-checks.d.ts +3 -0
- package/dist/episodic-digest.d.ts +89 -0
- package/dist/fact-extraction.d.ts +39 -0
- package/dist/file-tools-mcp-server.mjs +138 -12
- package/dist/file-tools.d.ts +4 -0
- package/dist/first-run.d.ts +3 -2
- package/dist/goal-graph-flag.d.ts +44 -0
- package/dist/goal-graph-reconcile.d.ts +55 -0
- package/dist/goal-graph-service.d.ts +48 -0
- package/dist/goal-graph-store.d.ts +485 -0
- package/dist/goal-graph-suggest-flag.d.ts +34 -0
- package/dist/goal-identity-matcher.d.ts +21 -0
- package/dist/goal-thread-identity.d.ts +32 -0
- package/dist/goal-thread-scheduler.d.ts +78 -0
- package/dist/grounding-check.d.ts +33 -0
- package/dist/harness-bridge.d.ts +75 -2
- package/dist/harness-token-budget.d.ts +9 -0
- package/dist/index.d.ts +30 -1
- package/dist/index.js +166 -80
- package/dist/index.js.map +1 -1
- package/dist/layer-policy-flag.d.ts +13 -0
- package/dist/layer-policy-wiring.d.ts +77 -0
- package/dist/layer-settings.d.ts +49 -0
- package/dist/layer-telemetry.d.ts +2 -0
- package/dist/lexical/lexical-mode.d.ts +29 -0
- package/dist/live-steering-channel.d.ts +31 -0
- package/dist/memory-consolidation.d.ts +80 -0
- package/dist/memory-governance.d.ts +30 -0
- package/dist/memory-reviewer.d.ts +114 -0
- package/dist/memory-service.d.ts +348 -9
- package/dist/model-json.d.ts +17 -0
- package/dist/next-step-context.d.ts +51 -0
- package/dist/next-step-proposer.d.ts +53 -0
- package/dist/plan-approval-service.d.ts +1 -1
- package/dist/plan-drafting-service.d.ts +1 -1
- package/dist/plan-graph-flag.d.ts +20 -0
- package/dist/plan-question.d.ts +60 -0
- package/dist/plan-service.d.ts +6 -2
- package/dist/plan-step-prompt.d.ts +15 -0
- package/dist/plan-store.d.ts +7 -1
- package/dist/plan-viz/normalize.d.ts +14 -0
- package/dist/plan-viz/plan-detail-lines.d.ts +3 -0
- package/dist/plan-viz/plan-layout.d.ts +48 -0
- package/dist/plan-viz/plan-nav.d.ts +29 -0
- package/dist/plan-viz/plan-raster.d.ts +36 -0
- package/dist/plan-viz/plan-routes.d.ts +6 -0
- package/dist/plan-viz/plan-snapshot.d.ts +73 -0
- package/dist/plan-viz/plan-viewport.d.ts +29 -0
- package/dist/plan-viz/plan-width.d.ts +15 -0
- package/dist/plan-viz/testkit/display-width.d.ts +12 -0
- package/dist/plan-viz/testkit/generators.d.ts +61 -0
- package/dist/plan-viz/testkit/grid-oracles.d.ts +38 -0
- package/dist/plan-viz/testkit/nav-oracles.d.ts +79 -0
- package/dist/plan-viz/testkit/types.d.ts +8 -0
- package/dist/plan-viz/types.d.ts +34 -0
- package/dist/provider-setup-LFsaTkpf.js +16606 -0
- package/dist/provider-setup-LFsaTkpf.js.map +1 -0
- package/dist/provider-setup.d.ts +51 -0
- package/dist/recall-tool.d.ts +43 -0
- package/dist/recovery-note.d.ts +22 -0
- package/dist/response-service.d.ts +28 -2
- package/dist/review-checker.d.ts +10 -4
- package/dist/reviewer-revision.d.ts +23 -0
- package/dist/risk-classifier.d.ts +7 -0
- package/dist/scope-urgency-classifier.d.ts +29 -0
- package/dist/scripted-llm-client.d.ts +26 -1
- package/dist/semantic-compaction.d.ts +15 -0
- package/dist/semantic-hypotheses.d.ts +40 -0
- package/dist/source-reliability.d.ts +71 -0
- package/dist/supervisor-flag.d.ts +20 -0
- package/dist/task-completion-check.d.ts +24 -0
- package/dist/tool-control-plane.d.ts +33 -1
- package/dist/tool-effect-class.d.ts +9 -0
- package/dist/transcript-compaction.d.ts +9 -0
- package/dist/{tui-app-CFfOP2DC.js → tui-app-BLR-PRFp.js} +321 -7
- package/dist/tui-app-BLR-PRFp.js.map +1 -0
- package/dist/tui-app.d.ts +38 -0
- package/dist/turn-intent-classifier.d.ts +75 -16
- package/dist/turn-interpreter.d.ts +25 -3
- package/dist/version.d.ts +1 -1
- package/package.json +7 -7
- package/dist/bin-Btzhiyzi.js +0 -2108
- package/dist/bin-Btzhiyzi.js.map +0 -1
- package/dist/cli-session-DnSc6Hhx.js +0 -8343
- package/dist/cli-session-DnSc6Hhx.js.map +0 -1
- package/dist/tui-app-CFfOP2DC.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-
|
|
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 {
|
|
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:
|
|
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-
|
|
951
|
+
//# sourceMappingURL=tui-app-BLR-PRFp.js.map
|