@neotx/cli 0.1.0-alpha.2 → 0.1.0-alpha.20

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 (60) hide show
  1. package/README.md +383 -0
  2. package/dist/activity-LWUVGQVN.js +86 -0
  3. package/dist/activity-LWUVGQVN.js.map +1 -0
  4. package/dist/{agents-Y6LREFXP.js → agents-PH3P7G7E.js} +2 -2
  5. package/dist/{chunk-CP54H7WA.js → chunk-3ZP3BQXB.js} +6 -11
  6. package/dist/chunk-3ZP3BQXB.js.map +1 -0
  7. package/dist/{chunk-TNJOG54I.js → chunk-F622JUDY.js} +6 -2
  8. package/dist/{chunk-TNJOG54I.js.map → chunk-F622JUDY.js.map} +1 -1
  9. package/dist/config-NYF6AJXU.js +282 -0
  10. package/dist/config-NYF6AJXU.js.map +1 -0
  11. package/dist/{cost-DNGKT4UC.js → cost-OQGFNBBG.js} +3 -8
  12. package/dist/cost-OQGFNBBG.js.map +1 -0
  13. package/dist/daemon/supervisor-worker.js +7 -1
  14. package/dist/daemon/supervisor-worker.js.map +1 -1
  15. package/dist/daemon/worker.js +27 -10
  16. package/dist/daemon/worker.js.map +1 -1
  17. package/dist/decision-PNZ2S2TU.js +362 -0
  18. package/dist/decision-PNZ2S2TU.js.map +1 -0
  19. package/dist/doctor-ZBO73UID.js +337 -0
  20. package/dist/doctor-ZBO73UID.js.map +1 -0
  21. package/dist/guide-UQRNA3FC.js +23 -0
  22. package/dist/guide-UQRNA3FC.js.map +1 -0
  23. package/dist/index.js +17 -9
  24. package/dist/index.js.map +1 -1
  25. package/dist/{init-YNSPTCA3.js → init-UYS6KS5U.js} +4 -20
  26. package/dist/init-UYS6KS5U.js.map +1 -0
  27. package/dist/log-PTHLI7ZN.js +141 -0
  28. package/dist/log-PTHLI7ZN.js.map +1 -0
  29. package/dist/{mcp-GH6CCW7A.js → mcp-XHZND5A4.js} +6 -1
  30. package/dist/mcp-XHZND5A4.js.map +1 -0
  31. package/dist/memory-6R22DFS7.js +292 -0
  32. package/dist/memory-6R22DFS7.js.map +1 -0
  33. package/dist/{run-KIU2ZE72.js → run-OF53USMD.js} +46 -20
  34. package/dist/run-OF53USMD.js.map +1 -0
  35. package/dist/{runs-CHA2JM5K.js → runs-TAASM3YF.js} +16 -12
  36. package/dist/runs-TAASM3YF.js.map +1 -0
  37. package/dist/status-LQOFOJJI.js +90 -0
  38. package/dist/status-LQOFOJJI.js.map +1 -0
  39. package/dist/{supervise-KIB2EYY4.js → supervise-FI6MYULH.js} +33 -28
  40. package/dist/supervise-FI6MYULH.js.map +1 -0
  41. package/dist/supervisor-3RUX5SPH.js +16 -0
  42. package/dist/supervisor-3RUX5SPH.js.map +1 -0
  43. package/dist/{tui-QS3RPHKH.js → tui-JJ6CD2YW.js} +377 -43
  44. package/dist/tui-JJ6CD2YW.js.map +1 -0
  45. package/dist/version-XVOAMGDD.js +26 -0
  46. package/dist/version-XVOAMGDD.js.map +1 -0
  47. package/dist/webhooks-PUKAHFHE.js +151 -0
  48. package/dist/webhooks-PUKAHFHE.js.map +1 -0
  49. package/package.json +22 -4
  50. package/dist/chunk-CP54H7WA.js.map +0 -1
  51. package/dist/cost-DNGKT4UC.js.map +0 -1
  52. package/dist/doctor-GC4NH7H6.js +0 -173
  53. package/dist/doctor-GC4NH7H6.js.map +0 -1
  54. package/dist/init-YNSPTCA3.js.map +0 -1
  55. package/dist/mcp-GH6CCW7A.js.map +0 -1
  56. package/dist/run-KIU2ZE72.js.map +0 -1
  57. package/dist/runs-CHA2JM5K.js.map +0 -1
  58. package/dist/supervise-KIB2EYY4.js.map +0 -1
  59. package/dist/tui-QS3RPHKH.js.map +0 -1
  60. /package/dist/{agents-Y6LREFXP.js.map → agents-PH3P7G7E.js.map} +0 -0
@@ -4,11 +4,17 @@ import React from "react";
4
4
 
5
5
  // src/tui/supervisor-tui.tsx
6
6
  import { randomUUID } from "crypto";
7
- import { appendFile, readFile } from "fs/promises";
7
+ import { appendFile, mkdir, readFile } from "fs/promises";
8
+ import path from "path";
8
9
  import {
10
+ DecisionStore,
9
11
  getSupervisorActivityPath,
12
+ getSupervisorDecisionsPath,
13
+ getSupervisorDir,
10
14
  getSupervisorInboxPath,
11
- getSupervisorStatePath
15
+ getSupervisorStatePath,
16
+ loadGlobalConfig,
17
+ MemoryStore
12
18
  } from "@neotx/core";
13
19
  import { Box, Text, useApp, useInput, useStdout } from "ink";
14
20
  import TextInput from "ink-text-input";
@@ -283,39 +289,195 @@ function ActivityRow({
283
289
  /* @__PURE__ */ jsx(Text, { dimColor: isOld, children: formatTime(entry.timestamp) }),
284
290
  /* @__PURE__ */ jsx(Text, { color, dimColor: isOld, bold: isLatest, children: icon }),
285
291
  /* @__PURE__ */ jsx(Text, { color, dimColor: isOld, bold: true, children: label }),
286
- /* @__PURE__ */ jsx(Text, { dimColor: isOld, bold: isLatest, wrap: "truncate", children: entry.summary })
292
+ /* @__PURE__ */ jsx(Text, { dimColor: isOld, bold: isLatest, children: entry.summary })
287
293
  ] });
288
294
  }
289
- function ThinkingPanel({ entries }) {
290
- const latest = [...entries].reverse().find((e) => {
291
- const type = e.type;
292
- return type === "thinking" || type === "plan";
293
- });
294
- if (!latest) return null;
295
- const icon = TYPE_ICONS[latest.type] ?? "\xB7";
296
- const color = TYPE_COLORS[latest.type] ?? "#9ca3af";
297
- const label = latest.type === "thinking" ? "THINKING" : "PLANNING";
298
- const text = latest.summary.length > 600 ? `${latest.summary.slice(0, 600)}...` : latest.summary;
295
+ var TASK_STATUS_COLORS = {
296
+ in_progress: "#60a5fa",
297
+ blocked: "#f87171",
298
+ pending: "#6b7280",
299
+ done: "#4ade80"
300
+ };
301
+ var TASK_STATUS_LABELS = {
302
+ in_progress: "ACTIVE",
303
+ blocked: "BLOCK",
304
+ pending: "\xB7"
305
+ };
306
+ function TaskPanel({ tasks }) {
307
+ const active = tasks.filter((t) => t.outcome !== "done" && t.outcome !== "abandoned");
308
+ const doneCount = tasks.filter((t) => t.outcome === "done").length;
309
+ if (tasks.length === 0) return null;
310
+ const MAX_VISIBLE = 6;
311
+ const visible = active.slice(0, MAX_VISIBLE);
312
+ const overflow = active.length - visible.length;
299
313
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
300
314
  /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
301
315
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
302
- /* @__PURE__ */ jsxs(Text, { color, bold: true, children: [
303
- icon,
304
- " ",
305
- label
316
+ /* @__PURE__ */ jsx(Text, { dimColor: true, bold: true, children: "TASKS" }),
317
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
318
+ "(",
319
+ active.length,
320
+ " active, ",
321
+ doneCount,
322
+ " done)"
306
323
  ] }),
307
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(36) })
324
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(30) })
308
325
  ] }),
309
- /* @__PURE__ */ jsxs(Box, { paddingX: 2, children: [
310
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 " }),
311
- /* @__PURE__ */ jsx(Text, { color, wrap: "truncate-end", children: text })
326
+ visible.map((t) => {
327
+ const status = t.outcome ?? "pending";
328
+ const color = TASK_STATUS_COLORS[status] ?? "#6b7280";
329
+ const label = (TASK_STATUS_LABELS[status] ?? "\xB7").padEnd(6);
330
+ const prio = t.severity ? `[${t.severity.slice(0, 3)}] ` : "";
331
+ const repo = t.scope !== "global" ? path.basename(t.scope) : "";
332
+ const run = t.runId ? `run:${t.runId.slice(0, 4)}` : "";
333
+ const meta = [repo, run].filter(Boolean).join(" ");
334
+ return /* @__PURE__ */ jsxs(Box, { gap: 1, paddingX: 2, children: [
335
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
336
+ /* @__PURE__ */ jsx(Text, { color, bold: true, children: label }),
337
+ prio && /* @__PURE__ */ jsx(Text, { dimColor: true, children: prio.padEnd(5) }),
338
+ /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: t.content }),
339
+ meta && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
340
+ "(",
341
+ meta,
342
+ ")"
343
+ ] })
344
+ ] }, t.id);
345
+ }),
346
+ overflow > 0 && /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
347
+ "\u2502 ... +",
348
+ overflow,
349
+ " more pending"
350
+ ] }) })
351
+ ] });
352
+ }
353
+ function DecisionBanner({ decisions, frame }) {
354
+ if (decisions.length === 0) return null;
355
+ const pulseChars = ["\u2605", "\u2606"];
356
+ const pulse = pulseChars[frame % pulseChars.length];
357
+ return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
358
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
359
+ /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
360
+ pulse,
361
+ " ",
362
+ decisions.length,
363
+ " decision",
364
+ decisions.length > 1 ? "s" : "",
365
+ " pending"
312
366
  ] }),
313
- /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) })
367
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
368
+ "\u2014 press ",
369
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
370
+ " to review"
371
+ ] })
314
372
  ] });
315
373
  }
374
+ function DecisionInputPanel({
375
+ decision,
376
+ optionIndex,
377
+ isTextMode,
378
+ textInput,
379
+ onTextChange,
380
+ onSubmit,
381
+ decisionCount,
382
+ decisionIdx,
383
+ frame
384
+ }) {
385
+ const hasOptions = decision.options && decision.options.length > 0;
386
+ const pulseChars = ["\u2605", "\u2606"];
387
+ const pulse = pulseChars[frame % pulseChars.length];
388
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
389
+ /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
390
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
391
+ /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
392
+ pulse,
393
+ " DECISION"
394
+ ] }),
395
+ decisionCount > 1 && /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", children: [
396
+ "(",
397
+ decisionIdx + 1,
398
+ "/",
399
+ decisionCount,
400
+ ")"
401
+ ] }),
402
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(30) })
403
+ ] }),
404
+ /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
405
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
406
+ /* @__PURE__ */ jsx(Text, { bold: true, wrap: "truncate-end", children: decision.question })
407
+ ] }),
408
+ decision.context && /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
409
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
410
+ /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: decision.context })
411
+ ] }),
412
+ hasOptions ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: (decision.options ?? []).map((opt, idx) => {
413
+ const isSelected = idx === optionIndex;
414
+ return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
415
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
416
+ isSelected ? /* @__PURE__ */ jsxs(Text, { color: "#fbbf24", bold: true, children: [
417
+ "\u25B8 ",
418
+ opt.label
419
+ ] }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
420
+ " ",
421
+ opt.label
422
+ ] }),
423
+ opt.description && isSelected && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
424
+ "\u2014 ",
425
+ opt.description
426
+ ] })
427
+ ] }, opt.key);
428
+ }) }) : /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
429
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
430
+ /* @__PURE__ */ jsx(Text, { color: "#fbbf24", bold: true, children: "\u276F" }),
431
+ /* @__PURE__ */ jsx(
432
+ TextInput,
433
+ {
434
+ value: textInput,
435
+ onChange: onTextChange,
436
+ onSubmit,
437
+ focus: isTextMode,
438
+ placeholder: "type your answer..."
439
+ }
440
+ )
441
+ ] }),
442
+ /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
443
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2514" }),
444
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
445
+ hasOptions ? /* @__PURE__ */ jsxs(Fragment, { children: [
446
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "\u2191\u2193" }),
447
+ " choose \xB7 ",
448
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
449
+ " confirm"
450
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
451
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
452
+ " send"
453
+ ] }),
454
+ decisionCount > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
455
+ " \xB7 ",
456
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "\u2190\u2192" }),
457
+ " prev/next"
458
+ ] }),
459
+ " \xB7 ",
460
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
461
+ " chat \xB7 ",
462
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "esc" }),
463
+ " back"
464
+ ] })
465
+ ] })
466
+ ] });
467
+ }
468
+ var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
469
+ "heartbeat",
470
+ "decision",
471
+ "action",
472
+ "dispatch",
473
+ "error",
474
+ "event",
475
+ "message"
476
+ ]);
316
477
  function ActivityPanel({ entries, termHeight }) {
317
- const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 14));
318
- const visible = entries.slice(-maxVisible);
478
+ const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 10));
479
+ const filtered = entries.filter((e) => ACTIVITY_TYPES.has(e.type));
480
+ const visible = filtered.slice(-maxVisible);
319
481
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
320
482
  /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
321
483
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u251C" }),
@@ -338,7 +500,8 @@ function InputPanel({
338
500
  value,
339
501
  onChange,
340
502
  onSubmit,
341
- lastSent
503
+ lastSent,
504
+ focus
342
505
  }) {
343
506
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
344
507
  /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, children: [
@@ -350,6 +513,7 @@ function InputPanel({
350
513
  value,
351
514
  onChange,
352
515
  onSubmit,
516
+ focus,
353
517
  placeholder: "message the supervisor..."
354
518
  }
355
519
  )
@@ -364,7 +528,7 @@ function InputPanel({
364
528
  ] })
365
529
  ] });
366
530
  }
367
- function Footer() {
531
+ function Footer({ hasDecisions }) {
368
532
  return /* @__PURE__ */ jsxs(Box, { paddingX: 2, gap: 1, justifyContent: "center", children: [
369
533
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
370
534
  /* @__PURE__ */ jsx(Text, { bold: true, children: "esc" }),
@@ -375,6 +539,13 @@ function Footer() {
375
539
  /* @__PURE__ */ jsx(Text, { bold: true, children: "enter" }),
376
540
  " send"
377
541
  ] }),
542
+ hasDecisions && /* @__PURE__ */ jsxs(Fragment, { children: [
543
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
544
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
545
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "tab" }),
546
+ " decisions"
547
+ ] })
548
+ ] }),
378
549
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
379
550
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "daemon keeps running" })
380
551
  ] });
@@ -404,16 +575,62 @@ async function readActivity(name, maxEntries) {
404
575
  return [];
405
576
  }
406
577
  }
407
- async function sendMessage(name, text) {
408
- const message = {
578
+ function readTasks(name) {
579
+ try {
580
+ const dir = getSupervisorDir(name);
581
+ const store = new MemoryStore(path.join(dir, "memory.sqlite"));
582
+ const tasks = store.query({ types: ["task"], limit: 20, sortBy: "createdAt" });
583
+ store.close();
584
+ return tasks;
585
+ } catch {
586
+ return [];
587
+ }
588
+ }
589
+ async function readDecisions(name) {
590
+ try {
591
+ const store = new DecisionStore(getSupervisorDecisionsPath(name));
592
+ return await store.pending();
593
+ } catch {
594
+ return [];
595
+ }
596
+ }
597
+ async function appendToJsonl(filePath, data) {
598
+ const dir = path.dirname(filePath);
599
+ try {
600
+ await mkdir(dir, { recursive: true });
601
+ await appendFile(filePath, `${JSON.stringify(data)}
602
+ `, "utf-8");
603
+ return true;
604
+ } catch (error) {
605
+ console.error(
606
+ `Warning: Failed to write to ${path.basename(filePath)}: ${error instanceof Error ? error.message : String(error)}`
607
+ );
608
+ return false;
609
+ }
610
+ }
611
+ async function writeToInbox(name, message) {
612
+ const inboxPath = getSupervisorInboxPath(name);
613
+ return appendToJsonl(inboxPath, message);
614
+ }
615
+ async function answerDecision(name, id, answer) {
616
+ const store = new DecisionStore(getSupervisorDecisionsPath(name));
617
+ await store.answer(id, answer);
618
+ const inboxMessage = {
409
619
  id: randomUUID(),
410
620
  from: "tui",
411
- text,
621
+ text: `decision:answer ${id} ${answer}`,
412
622
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
413
623
  };
414
- const inboxPath = getSupervisorInboxPath(name);
415
- await appendFile(inboxPath, `${JSON.stringify(message)}
416
- `, "utf-8");
624
+ await writeToInbox(name, inboxMessage);
625
+ }
626
+ async function sendMessage(name, text) {
627
+ const id = randomUUID();
628
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
629
+ const message = { id, from: "tui", text, timestamp };
630
+ await writeToInbox(name, message);
631
+ const activityEntry = { id, type: "message", summary: text, timestamp };
632
+ const activityPath = getSupervisorActivityPath(name);
633
+ await appendToJsonl(activityPath, activityEntry);
417
634
  }
418
635
  function SupervisorTui({ name }) {
419
636
  const { exit } = useApp();
@@ -422,9 +639,16 @@ function SupervisorTui({ name }) {
422
639
  const clock = useClock();
423
640
  const [state, setState] = useState(null);
424
641
  const [entries, setEntries] = useState([]);
642
+ const [tasks, setTasks] = useState([]);
643
+ const [decisions, setDecisions] = useState([]);
644
+ const [dailyCap, setDailyCap] = useState(50);
425
645
  const [input, setInput] = useState("");
426
646
  const [lastSent, setLastSent] = useState("");
427
647
  const [termHeight, setTermHeight] = useState(stdout?.rows ?? 30);
648
+ const [decisionIndex, setDecisionIndex] = useState(0);
649
+ const [optionIndex, setOptionIndex] = useState(0);
650
+ const [decisionAnswer, setDecisionAnswer] = useState("");
651
+ const [focusMode, setFocusMode] = useState("input");
428
652
  useEffect(() => {
429
653
  function onResize() {
430
654
  if (stdout) setTermHeight(stdout.rows);
@@ -434,17 +658,33 @@ function SupervisorTui({ name }) {
434
658
  stdout?.off("resize", onResize);
435
659
  };
436
660
  }, [stdout]);
661
+ useEffect(() => {
662
+ loadGlobalConfig().then((cfg) => setDailyCap(cfg.supervisor.dailyCapUsd)).catch(() => {
663
+ });
664
+ }, []);
437
665
  useEffect(() => {
438
666
  let active = true;
439
667
  async function poll() {
440
668
  if (!active) return;
441
- const [newState, newEntries] = await Promise.all([
669
+ const [newState, newEntries, newDecisions] = await Promise.all([
442
670
  readState(name),
443
- readActivity(name, MAX_VISIBLE_ENTRIES)
671
+ readActivity(name, MAX_VISIBLE_ENTRIES),
672
+ readDecisions(name)
444
673
  ]);
445
674
  if (!active) return;
446
675
  setState(newState);
447
676
  setEntries(newEntries);
677
+ setDecisions(newDecisions);
678
+ setTasks(readTasks(name));
679
+ if (newDecisions.length > 0 && decisionIndex >= newDecisions.length) {
680
+ setDecisionIndex(0);
681
+ }
682
+ if (newDecisions.length > 0 && decisions.length === 0) {
683
+ setFocusMode("decisions");
684
+ }
685
+ if (newDecisions.length === 0 && decisions.length > 0) {
686
+ setFocusMode("input");
687
+ }
448
688
  }
449
689
  poll();
450
690
  const interval = setInterval(poll, POLL_INTERVAL_MS);
@@ -452,10 +692,67 @@ function SupervisorTui({ name }) {
452
692
  active = false;
453
693
  clearInterval(interval);
454
694
  };
455
- }, [name]);
456
- useInput((_input, key) => {
695
+ }, [name, decisionIndex, decisions.length]);
696
+ const currentDecision = decisions[decisionIndex];
697
+ const currentHasOptions = (currentDecision?.options?.length ?? 0) > 0;
698
+ const submitDecisionAnswer = useCallback(
699
+ async (answer) => {
700
+ if (!answer.trim() || !currentDecision) return;
701
+ try {
702
+ await answerDecision(name, currentDecision.id, answer.trim());
703
+ setLastSent(`Decision ${currentDecision.id.slice(4, 12)}: "${answer.trim()}"`);
704
+ setDecisionAnswer("");
705
+ setOptionIndex(0);
706
+ } catch {
707
+ }
708
+ },
709
+ [name, currentDecision]
710
+ );
711
+ const handleOptionNav = useCallback(
712
+ (key) => {
713
+ const options = currentDecision?.options;
714
+ if (!options || options.length === 0) return false;
715
+ if (key.upArrow) {
716
+ setOptionIndex((i) => Math.max(0, i - 1));
717
+ return true;
718
+ }
719
+ if (key.downArrow) {
720
+ setOptionIndex((i) => Math.min(options.length - 1, i + 1));
721
+ return true;
722
+ }
723
+ if (key.return) {
724
+ const opt = options[optionIndex];
725
+ if (opt) submitDecisionAnswer(opt.key);
726
+ return true;
727
+ }
728
+ return false;
729
+ },
730
+ [currentDecision, optionIndex, submitDecisionAnswer]
731
+ );
732
+ useInput((_char, key) => {
733
+ if (key.tab && decisions.length > 0) {
734
+ setFocusMode((m) => m === "input" ? "decisions" : "input");
735
+ setOptionIndex(0);
736
+ return;
737
+ }
457
738
  if (key.escape) {
458
- exit();
739
+ if (focusMode === "decisions") {
740
+ setFocusMode("input");
741
+ } else {
742
+ exit();
743
+ }
744
+ return;
745
+ }
746
+ if (focusMode !== "decisions" || decisions.length === 0) return;
747
+ if (currentHasOptions && handleOptionNav(key)) return;
748
+ if (decisions.length > 1) {
749
+ if (key.leftArrow) {
750
+ setDecisionIndex((i) => Math.max(0, i - 1));
751
+ setOptionIndex(0);
752
+ } else if (key.rightArrow) {
753
+ setDecisionIndex((i) => Math.min(decisions.length - 1, i + 1));
754
+ setOptionIndex(0);
755
+ }
459
756
  }
460
757
  });
461
758
  const handleSubmit = useCallback(
@@ -468,13 +765,50 @@ function SupervisorTui({ name }) {
468
765
  [name]
469
766
  );
470
767
  const costHistory = extractCostHistory(entries);
768
+ const activeTaskCount = tasks.filter(
769
+ (t) => t.outcome !== "done" && t.outcome !== "abandoned"
770
+ ).length;
771
+ const taskPanelLines = tasks.length > 0 ? Math.min(activeTaskCount, 6) + 2 : 0;
772
+ const decisionPanelLines = focusMode === "decisions" && currentDecision ? (currentHasOptions ? currentDecision.options?.length ?? 0 : 1) + 4 : decisions.length > 0 ? 1 : 0;
773
+ const bottomPanel = focusMode === "decisions" && currentDecision ? /* @__PURE__ */ jsx(
774
+ DecisionInputPanel,
775
+ {
776
+ decision: currentDecision,
777
+ optionIndex,
778
+ isTextMode: !currentHasOptions,
779
+ textInput: decisionAnswer,
780
+ onTextChange: setDecisionAnswer,
781
+ onSubmit: submitDecisionAnswer,
782
+ decisionCount: decisions.length,
783
+ decisionIdx: decisionIndex,
784
+ frame
785
+ }
786
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
787
+ /* @__PURE__ */ jsx(
788
+ InputPanel,
789
+ {
790
+ value: input,
791
+ onChange: setInput,
792
+ onSubmit: handleSubmit,
793
+ lastSent,
794
+ focus: focusMode === "input"
795
+ }
796
+ ),
797
+ /* @__PURE__ */ jsx(Footer, { hasDecisions: decisions.length > 0 })
798
+ ] });
471
799
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
472
800
  /* @__PURE__ */ jsx(HeaderBar, { state, name, frame, clock }),
473
- /* @__PURE__ */ jsx(BudgetPanel, { state, dailyCap: 50, costHistory }),
474
- /* @__PURE__ */ jsx(ThinkingPanel, { entries }),
475
- /* @__PURE__ */ jsx(ActivityPanel, { entries, termHeight }),
476
- /* @__PURE__ */ jsx(InputPanel, { value: input, onChange: setInput, onSubmit: handleSubmit, lastSent }),
477
- /* @__PURE__ */ jsx(Footer, {})
801
+ /* @__PURE__ */ jsx(BudgetPanel, { state, dailyCap, costHistory }),
802
+ focusMode !== "decisions" && /* @__PURE__ */ jsx(DecisionBanner, { decisions, frame }),
803
+ /* @__PURE__ */ jsx(TaskPanel, { tasks }),
804
+ /* @__PURE__ */ jsx(
805
+ ActivityPanel,
806
+ {
807
+ entries,
808
+ termHeight: termHeight - taskPanelLines - decisionPanelLines
809
+ }
810
+ ),
811
+ bottomPanel
478
812
  ] });
479
813
  }
480
814
 
@@ -486,4 +820,4 @@ async function renderSupervisorTui(name) {
486
820
  export {
487
821
  renderSupervisorTui
488
822
  };
489
- //# sourceMappingURL=tui-QS3RPHKH.js.map
823
+ //# sourceMappingURL=tui-JJ6CD2YW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tui/index.ts","../src/tui/supervisor-tui.tsx"],"sourcesContent":["import { render } from \"ink\";\nimport React from \"react\";\nimport { SupervisorTui } from \"./supervisor-tui.js\";\n\n/**\n * Render the supervisor TUI. Returns a promise that resolves when the user exits.\n */\nexport async function renderSupervisorTui(name: string): Promise<void> {\n const { waitUntilExit } = render(React.createElement(SupervisorTui, { name }));\n await waitUntilExit();\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ActivityEntry,\n Decision,\n InboxMessage,\n MemoryEntry,\n SupervisorDaemonState,\n} from \"@neotx/core\";\nimport {\n DecisionStore,\n getSupervisorActivityPath,\n getSupervisorDecisionsPath,\n getSupervisorDir,\n getSupervisorInboxPath,\n getSupervisorStatePath,\n loadGlobalConfig,\n MemoryStore,\n} from \"@neotx/core\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport TextInput from \"ink-text-input\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n// ─── Constants ───────────────────────────────────────────\n\nconst MAX_VISIBLE_ENTRIES = 24;\nconst POLL_INTERVAL_MS = 1_500;\nconst ANIMATION_TICK_MS = 400;\n\n// ─── Unicode Visual Elements ─────────────────────────────\n\nconst SPARK_CHARS = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"];\nconst BLOCK_FULL = \"█\";\nconst BLOCK_EMPTY = \"░\";\nconst PULSE_FRAMES = [\"◉\", \"◎\", \"○\", \"◎\"];\nconst IDLE_FRAMES = [\"◌\", \"◌\", \"◌\", \"◌\"];\n\nconst TYPE_ICONS: Record<string, string> = {\n heartbeat: \"♥\",\n decision: \"★\",\n action: \"⚡\",\n error: \"✖\",\n event: \"◆\",\n message: \"✉\",\n thinking: \"◇\",\n plan: \"▸\",\n dispatch: \"↗\",\n tool_use: \"⊘\",\n};\n\nconst TYPE_COLORS: Record<string, string> = {\n heartbeat: \"#6ee7b7\",\n decision: \"#fbbf24\",\n action: \"#60a5fa\",\n error: \"#f87171\",\n event: \"#c084fc\",\n message: \"#67e8f9\",\n thinking: \"#a78bfa\",\n plan: \"#34d399\",\n dispatch: \"#f472b6\",\n tool_use: \"#38bdf8\",\n};\n\nconst TYPE_LABELS: Record<string, string> = {\n heartbeat: \"BEAT\",\n decision: \"DECIDE\",\n action: \"ACTION\",\n error: \"ERROR\",\n event: \"EVENT\",\n message: \"MSG\",\n thinking: \"THINK\",\n plan: \"PLAN\",\n dispatch: \"SEND\",\n tool_use: \"TOOL\",\n};\n\n// ─── Helpers ─────────────────────────────────────────────\n\nfunction formatTime(timestamp: string): string {\n return timestamp.slice(11, 19);\n}\n\nfunction formatUptime(startedAt: string): string {\n const ms = Date.now() - new Date(startedAt).getTime();\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n if (days > 0) return `${days}d ${hours % 24}h`;\n if (hours > 0) return `${hours}h ${minutes % 60}m`;\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\n}\n\nfunction formatTimeAgo(timestamp: string): string {\n const ms = Date.now() - new Date(timestamp).getTime();\n const seconds = Math.floor(ms / 1000);\n if (seconds < 60) return `${seconds}s ago`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n return `${hours}h ago`;\n}\n\nfunction buildProgressBar(ratio: number, width: number): { filled: string; empty: string } {\n const clamped = Math.max(0, Math.min(1, ratio));\n const filledCount = Math.round(clamped * width);\n return {\n filled: BLOCK_FULL.repeat(filledCount),\n empty: BLOCK_EMPTY.repeat(width - filledCount),\n };\n}\n\nfunction buildSparkline(values: number[], width: number): string {\n if (values.length === 0) return \"▁\".repeat(width);\n const recent = values.slice(-width);\n const max = Math.max(...recent, 0.001);\n return recent\n .map((v) => {\n const idx = Math.min(\n Math.floor((v / max) * (SPARK_CHARS.length - 1)),\n SPARK_CHARS.length - 1,\n );\n return SPARK_CHARS[idx];\n })\n .join(\"\");\n}\n\nfunction extractCostHistory(entries: ActivityEntry[]): number[] {\n return entries\n .filter((e) => e.type === \"heartbeat\" && e.summary.includes(\"complete\"))\n .map((e) => {\n const detail = e.detail as Record<string, unknown> | undefined;\n return typeof detail?.costUsd === \"number\" ? detail.costUsd : 0;\n });\n}\n\n// ─── Animated Hooks ──────────────────────────────────────\n\nfunction useAnimationFrame(): number {\n const [frame, setFrame] = useState(0);\n useEffect(() => {\n const interval = setInterval(() => setFrame((f) => f + 1), ANIMATION_TICK_MS);\n return () => clearInterval(interval);\n }, []);\n return frame;\n}\n\nfunction useClock(): string {\n const [time, setTime] = useState(() => new Date().toLocaleTimeString());\n useEffect(() => {\n const interval = setInterval(() => setTime(new Date().toLocaleTimeString()), 1000);\n return () => clearInterval(interval);\n }, []);\n return time;\n}\n\n// ─── Components ──────────────────────────────────────────\n\nfunction Logo() {\n return (\n <Box paddingX={1} gap={1}>\n <Text color=\"#c084fc\" bold>\n ◆\n </Text>\n <Text bold>\n <Text color=\"#c084fc\">N</Text>\n <Text color=\"#a78bfa\">E</Text>\n <Text color=\"#818cf8\">O</Text>\n </Text>\n <Text dimColor>SUPERVISOR</Text>\n </Box>\n );\n}\n\nfunction LiveIndicator({ frame, isRunning }: { frame: number; isRunning: boolean }) {\n const frames = isRunning ? PULSE_FRAMES : IDLE_FRAMES;\n const dot = frames[frame % frames.length];\n return (\n <Box paddingX={1}>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {dot}\n </Text>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {\" \"}\n {isRunning ? \"LIVE\" : \"IDLE\"}\n </Text>\n </Box>\n );\n}\n\nfunction HeaderBar({\n state,\n name,\n frame,\n clock,\n}: {\n state: SupervisorDaemonState | null;\n name: string;\n frame: number;\n clock: string;\n}) {\n if (!state) {\n return (\n <Box borderStyle=\"round\" borderColor=\"#6b7280\" paddingX={1} flexDirection=\"column\">\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n <Box paddingX={1}>\n <Text color=\"#fbbf24\">⟳ Connecting to \"{name}\"...</Text>\n </Box>\n </Box>\n );\n }\n\n const isRunning = state.status === \"running\";\n\n return (\n <Box\n borderStyle=\"round\"\n borderColor={isRunning ? \"#6ee7b7\" : \"#f87171\"}\n paddingX={0}\n flexDirection=\"column\"\n >\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box gap={2}>\n <LiveIndicator frame={frame} isRunning={isRunning} />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box paddingX={1} gap={1}>\n <Text dimColor>│</Text>\n <Text>\n <Text dimColor>pid</Text> <Text bold>{state.pid}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>port</Text> <Text bold>:{state.port}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>beats</Text>{\" \"}\n <Text bold color=\"#6ee7b7\">\n ▲{state.heartbeatCount}\n </Text>\n </Text>\n {state.lastHeartbeat && (\n <>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>last</Text> <Text>{formatTimeAgo(state.lastHeartbeat)}</Text>\n </Text>\n </>\n )}\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>up</Text> <Text>{formatUptime(state.startedAt)}</Text>\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction BudgetPanel({\n state,\n dailyCap,\n costHistory,\n}: {\n state: SupervisorDaemonState | null;\n dailyCap: number;\n costHistory: number[];\n}) {\n if (!state) return null;\n\n const todayCost = state.todayCostUsd ?? 0;\n const totalCost = state.totalCostUsd ?? 0;\n const ratio = dailyCap > 0 ? todayCost / dailyCap : 0;\n const barWidth = 20;\n const bar = buildProgressBar(ratio, barWidth);\n const pct = Math.round(ratio * 100);\n\n const barColor = pct < 50 ? \"#4ade80\" : pct < 80 ? \"#fbbf24\" : \"#f87171\";\n\n const sparkline = buildSparkline(costHistory, 12);\n\n return (\n <Box paddingX={2} gap={2}>\n <Box gap={1}>\n <Text dimColor>budget</Text>\n <Text color={barColor}>{bar.filled}</Text>\n <Text dimColor>{bar.empty}</Text>\n <Text bold color={barColor}>\n {pct}%\n </Text>\n <Text dimColor>\n (${todayCost.toFixed(2)}/${dailyCap})\n </Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>total</Text>\n <Text bold>${totalCost.toFixed(2)}</Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>cost/beat</Text>\n <Text color=\"#818cf8\">{sparkline}</Text>\n </Box>\n </Box>\n );\n}\n\nfunction ActivityRow({\n entry,\n isLatest,\n isOld,\n}: {\n entry: ActivityEntry;\n isLatest: boolean;\n isOld: boolean;\n}) {\n const icon = TYPE_ICONS[entry.type] ?? \"·\";\n const color = TYPE_COLORS[entry.type] ?? \"#9ca3af\";\n const label = (TYPE_LABELS[entry.type] ?? (entry.type as string).toUpperCase()).padEnd(7);\n\n return (\n <Box gap={1} paddingX={2}>\n <Text dimColor={isOld}>{isLatest ? \"│\" : \"│\"}</Text>\n <Text dimColor={isOld}>{formatTime(entry.timestamp)}</Text>\n <Text color={color} dimColor={isOld} bold={isLatest}>\n {icon}\n </Text>\n <Text color={color} dimColor={isOld} bold>\n {label}\n </Text>\n <Text dimColor={isOld} bold={isLatest}>\n {entry.summary}\n </Text>\n </Box>\n );\n}\n\nconst TASK_STATUS_COLORS: Record<string, string> = {\n in_progress: \"#60a5fa\",\n blocked: \"#f87171\",\n pending: \"#6b7280\",\n done: \"#4ade80\",\n};\n\nconst TASK_STATUS_LABELS: Record<string, string> = {\n in_progress: \"ACTIVE\",\n blocked: \"BLOCK\",\n pending: \"·\",\n};\n\nfunction TaskPanel({ tasks }: { tasks: MemoryEntry[] }) {\n const active = tasks.filter((t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\");\n const doneCount = tasks.filter((t) => t.outcome === \"done\").length;\n\n if (tasks.length === 0) return null;\n\n const MAX_VISIBLE = 6;\n const visible = active.slice(0, MAX_VISIBLE);\n const overflow = active.length - visible.length;\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n TASKS\n </Text>\n <Text dimColor>\n ({active.length} active, {doneCount} done)\n </Text>\n <Text dimColor>{\"─\".repeat(30)}</Text>\n </Box>\n {visible.map((t) => {\n const status = t.outcome ?? \"pending\";\n const color = TASK_STATUS_COLORS[status] ?? \"#6b7280\";\n const label = (TASK_STATUS_LABELS[status] ?? \"·\").padEnd(6);\n const prio = t.severity ? `[${t.severity.slice(0, 3)}] ` : \"\";\n const repo = t.scope !== \"global\" ? path.basename(t.scope) : \"\";\n const run = t.runId ? `run:${t.runId.slice(0, 4)}` : \"\";\n const meta = [repo, run].filter(Boolean).join(\" \");\n\n return (\n <Box key={t.id} gap={1} paddingX={2}>\n <Text dimColor>│</Text>\n <Text color={color} bold>\n {label}\n </Text>\n {prio && <Text dimColor>{prio.padEnd(5)}</Text>}\n <Text wrap=\"truncate\">{t.content}</Text>\n {meta && <Text dimColor>({meta})</Text>}\n </Box>\n );\n })}\n {overflow > 0 && (\n <Box paddingX={2}>\n <Text dimColor>│ ... +{overflow} more pending</Text>\n </Box>\n )}\n </Box>\n );\n}\n\n/** Compact banner shown above activity when decisions exist but input is focused on chat */\nfunction DecisionBanner({ decisions, frame }: { decisions: Decision[]; frame: number }) {\n if (decisions.length === 0) return null;\n\n const pulseChars = [\"★\", \"☆\"];\n const pulse = pulseChars[frame % pulseChars.length];\n\n return (\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text color=\"#fbbf24\" bold>\n {pulse} {decisions.length} decision{decisions.length > 1 ? \"s\" : \"\"} pending\n </Text>\n <Text dimColor>\n — press <Text bold>tab</Text> to review\n </Text>\n </Box>\n );\n}\n\n/** Full decision input panel — replaces the chat input when focused */\nfunction DecisionInputPanel({\n decision,\n optionIndex,\n isTextMode,\n textInput,\n onTextChange,\n onSubmit,\n decisionCount,\n decisionIdx,\n frame,\n}: {\n decision: Decision;\n optionIndex: number;\n isTextMode: boolean;\n textInput: string;\n onTextChange: (v: string) => void;\n onSubmit: (v: string) => void;\n decisionCount: number;\n decisionIdx: number;\n frame: number;\n}) {\n const hasOptions = decision.options && decision.options.length > 0;\n const pulseChars = [\"★\", \"☆\"];\n const pulse = pulseChars[frame % pulseChars.length];\n\n return (\n <Box flexDirection=\"column\">\n {/* Header */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text color=\"#fbbf24\" bold>\n {pulse} DECISION\n </Text>\n {decisionCount > 1 && (\n <Text color=\"#fbbf24\">\n ({decisionIdx + 1}/{decisionCount})\n </Text>\n )}\n <Text dimColor>{\"─\".repeat(30)}</Text>\n </Box>\n\n {/* Question */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text bold wrap=\"truncate-end\">\n {decision.question}\n </Text>\n </Box>\n\n {/* Context if available */}\n {decision.context && (\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text dimColor wrap=\"truncate-end\">\n {decision.context}\n </Text>\n </Box>\n )}\n\n {/* Option selector or free text */}\n {hasOptions ? (\n <Box flexDirection=\"column\">\n {(decision.options ?? []).map((opt, idx) => {\n const isSelected = idx === optionIndex;\n return (\n <Box key={opt.key} paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n {isSelected ? (\n <Text color=\"#fbbf24\" bold>\n ▸ {opt.label}\n </Text>\n ) : (\n <Text dimColor>\n {\" \"}\n {opt.label}\n </Text>\n )}\n {opt.description && isSelected && <Text dimColor>— {opt.description}</Text>}\n </Box>\n );\n })}\n </Box>\n ) : (\n <Box paddingX={2} gap={1}>\n <Text dimColor>│</Text>\n <Text color=\"#fbbf24\" bold>\n ❯\n </Text>\n <TextInput\n value={textInput}\n onChange={onTextChange}\n onSubmit={onSubmit}\n focus={isTextMode}\n placeholder=\"type your answer...\"\n />\n </Box>\n )}\n\n {/* Footer hints */}\n <Box paddingX={2} gap={1}>\n <Text dimColor>└</Text>\n <Text dimColor>\n {hasOptions ? (\n <>\n <Text bold>↑↓</Text> choose · <Text bold>enter</Text> confirm\n </>\n ) : (\n <>\n <Text bold>enter</Text> send\n </>\n )}\n {decisionCount > 1 && (\n <>\n {\" · \"}\n <Text bold>←→</Text> prev/next\n </>\n )}\n {\" · \"}\n <Text bold>tab</Text> chat · <Text bold>esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n\n/** Types shown in the activity feed — plan/thinking are internal, not shown */\nconst ACTIVITY_TYPES = new Set([\n \"heartbeat\",\n \"decision\",\n \"action\",\n \"dispatch\",\n \"error\",\n \"event\",\n \"message\",\n]);\n\nfunction ActivityPanel({ entries, termHeight }: { entries: ActivityEntry[]; termHeight: number }) {\n // Reserve lines for header (5), budget (1), separator (1), input (2), footer (1) = 10\n const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 10));\n const filtered = entries.filter((e) => ACTIVITY_TYPES.has(e.type));\n const visible = filtered.slice(-maxVisible);\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n ACTIVITY\n </Text>\n <Text dimColor>{\"─\".repeat(40)}</Text>\n </Box>\n\n {visible.length === 0 ? (\n <Box paddingX={2}>\n <Text dimColor>│ Waiting for heartbeats...</Text>\n </Box>\n ) : (\n visible.map((entry, idx) => (\n <ActivityRow\n key={entry.id}\n entry={entry}\n isLatest={idx === visible.length - 1}\n isOld={idx < visible.length - 5}\n />\n ))\n )}\n\n <Box paddingX={2}>\n <Text dimColor>│</Text>\n </Box>\n </Box>\n );\n}\n\nfunction InputPanel({\n value,\n onChange,\n onSubmit,\n lastSent,\n focus,\n}: {\n value: string;\n onChange: (v: string) => void;\n onSubmit: (v: string) => void;\n lastSent: string;\n focus: boolean;\n}) {\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>└</Text>\n <Text bold color=\"#60a5fa\">\n ❯\n </Text>\n <TextInput\n value={value}\n onChange={onChange}\n onSubmit={onSubmit}\n focus={focus}\n placeholder=\"message the supervisor...\"\n />\n </Box>\n <Box paddingX={2} gap={1}>\n <Text dimColor> </Text>\n {lastSent ? <Text color=\"#6b7280\">✓ \"{lastSent}\"</Text> : null}\n </Box>\n </Box>\n );\n}\n\nfunction Footer({ hasDecisions }: { hasDecisions: boolean }) {\n return (\n <Box paddingX={2} gap={1} justifyContent=\"center\">\n <Text dimColor>\n <Text bold>esc</Text> quit\n </Text>\n <Text dimColor>·</Text>\n <Text dimColor>\n <Text bold>enter</Text> send\n </Text>\n {hasDecisions && (\n <>\n <Text dimColor>·</Text>\n <Text dimColor>\n <Text bold>tab</Text> decisions\n </Text>\n </>\n )}\n <Text dimColor>·</Text>\n <Text dimColor>daemon keeps running</Text>\n </Box>\n );\n}\n\n// ─── Data Fetching ───────────────────────────────────────\n\nasync function readState(name: string): Promise<SupervisorDaemonState | null> {\n try {\n const raw = await readFile(getSupervisorStatePath(name), \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n}\n\nasync function readActivity(name: string, maxEntries: number): Promise<ActivityEntry[]> {\n try {\n const content = await readFile(getSupervisorActivityPath(name), \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const lastLines = lines.slice(-maxEntries);\n const entries: ActivityEntry[] = [];\n for (const line of lastLines) {\n try {\n entries.push(JSON.parse(line) as ActivityEntry);\n } catch {\n // Skip malformed\n }\n }\n return entries;\n } catch {\n return [];\n }\n}\n\nfunction readTasks(name: string): MemoryEntry[] {\n try {\n const dir = getSupervisorDir(name);\n const store = new MemoryStore(path.join(dir, \"memory.sqlite\"));\n const tasks = store.query({ types: [\"task\"], limit: 20, sortBy: \"createdAt\" });\n store.close();\n return tasks;\n } catch {\n return [];\n }\n}\n\nasync function readDecisions(name: string): Promise<Decision[]> {\n try {\n const store = new DecisionStore(getSupervisorDecisionsPath(name));\n return await store.pending();\n } catch {\n return [];\n }\n}\n\n/**\n * Appends a JSON entry to a JSONL file.\n * Creates the parent directory if needed. Returns false on error.\n */\nasync function appendToJsonl(filePath: string, data: unknown): Promise<boolean> {\n const dir = path.dirname(filePath);\n try {\n await mkdir(dir, { recursive: true });\n await appendFile(filePath, `${JSON.stringify(data)}\\n`, \"utf-8\");\n return true;\n } catch (error) {\n console.error(\n `Warning: Failed to write to ${path.basename(filePath)}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return false;\n }\n}\n\n/**\n * Writes a message to the supervisor's inbox.jsonl file.\n * Creates the directory if it doesn't exist and handles write errors gracefully.\n */\nasync function writeToInbox(name: string, message: InboxMessage): Promise<boolean> {\n const inboxPath = getSupervisorInboxPath(name);\n return appendToJsonl(inboxPath, message);\n}\n\nasync function answerDecision(name: string, id: string, answer: string): Promise<void> {\n const store = new DecisionStore(getSupervisorDecisionsPath(name));\n await store.answer(id, answer);\n\n // Wake up the supervisor heartbeat by appending to inbox.jsonl\n const inboxMessage: InboxMessage = {\n id: randomUUID(),\n from: \"tui\",\n text: `decision:answer ${id} ${answer}`,\n timestamp: new Date().toISOString(),\n };\n await writeToInbox(name, inboxMessage);\n}\n\nasync function sendMessage(name: string, text: string): Promise<void> {\n const id = randomUUID();\n const timestamp = new Date().toISOString();\n\n const message: InboxMessage = { id, from: \"tui\", text, timestamp };\n await writeToInbox(name, message);\n\n // Write to activity.jsonl so the message appears in the TUI conversation\n const activityEntry: ActivityEntry = { id, type: \"message\", summary: text, timestamp };\n const activityPath = getSupervisorActivityPath(name);\n await appendToJsonl(activityPath, activityEntry);\n}\n\n// ─── Main Component ──────────────────────────────────────\n\nexport function SupervisorTui({ name }: { name: string }) {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const frame = useAnimationFrame();\n const clock = useClock();\n\n const [state, setState] = useState<SupervisorDaemonState | null>(null);\n const [entries, setEntries] = useState<ActivityEntry[]>([]);\n const [tasks, setTasks] = useState<MemoryEntry[]>([]);\n const [decisions, setDecisions] = useState<Decision[]>([]);\n const [dailyCap, setDailyCap] = useState(50);\n const [input, setInput] = useState(\"\");\n const [lastSent, setLastSent] = useState(\"\");\n const [termHeight, setTermHeight] = useState(stdout?.rows ?? 30);\n\n // Decision interaction state\n const [decisionIndex, setDecisionIndex] = useState(0);\n const [optionIndex, setOptionIndex] = useState(0);\n const [decisionAnswer, setDecisionAnswer] = useState(\"\");\n const [focusMode, setFocusMode] = useState<\"input\" | \"decisions\">(\"input\");\n\n // Track terminal resize\n useEffect(() => {\n function onResize() {\n if (stdout) setTermHeight(stdout.rows);\n }\n stdout?.on(\"resize\", onResize);\n return () => {\n stdout?.off(\"resize\", onResize);\n };\n }, [stdout]);\n\n // Load daily cap from config\n useEffect(() => {\n loadGlobalConfig()\n .then((cfg) => setDailyCap(cfg.supervisor.dailyCapUsd))\n .catch(() => {});\n }, []);\n\n // Poll state, activity, and decisions\n useEffect(() => {\n let active = true;\n\n async function poll() {\n if (!active) return;\n const [newState, newEntries, newDecisions] = await Promise.all([\n readState(name),\n readActivity(name, MAX_VISIBLE_ENTRIES),\n readDecisions(name),\n ]);\n if (!active) return;\n setState(newState);\n setEntries(newEntries);\n setDecisions(newDecisions);\n setTasks(readTasks(name));\n // Reset decision index if out of bounds\n if (newDecisions.length > 0 && decisionIndex >= newDecisions.length) {\n setDecisionIndex(0);\n }\n // Auto-switch to decisions mode when new decisions appear\n if (newDecisions.length > 0 && decisions.length === 0) {\n setFocusMode(\"decisions\");\n }\n // Return to input mode when all decisions are resolved\n if (newDecisions.length === 0 && decisions.length > 0) {\n setFocusMode(\"input\");\n }\n }\n\n poll();\n const interval = setInterval(poll, POLL_INTERVAL_MS);\n return () => {\n active = false;\n clearInterval(interval);\n };\n }, [name, decisionIndex, decisions.length]);\n\n // Current decision being interacted with\n const currentDecision = decisions[decisionIndex] as Decision | undefined;\n const currentHasOptions = (currentDecision?.options?.length ?? 0) > 0;\n\n // Submit the selected option or free-text answer\n const submitDecisionAnswer = useCallback(\n async (answer: string) => {\n if (!answer.trim() || !currentDecision) return;\n try {\n await answerDecision(name, currentDecision.id, answer.trim());\n setLastSent(`Decision ${currentDecision.id.slice(4, 12)}: \"${answer.trim()}\"`);\n setDecisionAnswer(\"\");\n setOptionIndex(0);\n } catch {\n // Decision may have been answered already\n }\n },\n [name, currentDecision],\n );\n\n const handleOptionNav = useCallback(\n (key: { upArrow: boolean; downArrow: boolean; return: boolean }): boolean => {\n const options = currentDecision?.options;\n if (!options || options.length === 0) return false;\n\n if (key.upArrow) {\n setOptionIndex((i) => Math.max(0, i - 1));\n return true;\n }\n if (key.downArrow) {\n setOptionIndex((i) => Math.min(options.length - 1, i + 1));\n return true;\n }\n if (key.return) {\n const opt = options[optionIndex];\n if (opt) submitDecisionAnswer(opt.key);\n return true;\n }\n return false;\n },\n [currentDecision, optionIndex, submitDecisionAnswer],\n );\n\n useInput((_char, key) => {\n if (key.tab && decisions.length > 0) {\n setFocusMode((m) => (m === \"input\" ? \"decisions\" : \"input\"));\n setOptionIndex(0);\n return;\n }\n\n if (key.escape) {\n if (focusMode === \"decisions\") {\n setFocusMode(\"input\");\n } else {\n exit();\n }\n return;\n }\n\n if (focusMode !== \"decisions\" || decisions.length === 0) return;\n\n if (currentHasOptions && handleOptionNav(key)) return;\n\n // ←→ to switch between decisions when multiple\n if (decisions.length > 1) {\n if (key.leftArrow) {\n setDecisionIndex((i) => Math.max(0, i - 1));\n setOptionIndex(0);\n } else if (key.rightArrow) {\n setDecisionIndex((i) => Math.min(decisions.length - 1, i + 1));\n setOptionIndex(0);\n }\n }\n });\n\n const handleSubmit = useCallback(\n (text: string) => {\n if (!text.trim()) return;\n sendMessage(name, text.trim());\n setLastSent(text.trim());\n setInput(\"\");\n },\n [name],\n );\n\n const costHistory = extractCostHistory(entries);\n\n // Calculate height adjustments for panels\n const activeTaskCount = tasks.filter(\n (t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\",\n ).length;\n const taskPanelLines = tasks.length > 0 ? Math.min(activeTaskCount, 6) + 2 : 0;\n const decisionPanelLines =\n focusMode === \"decisions\" && currentDecision\n ? (currentHasOptions ? (currentDecision.options?.length ?? 0) : 1) + 4\n : decisions.length > 0\n ? 1\n : 0;\n\n // Bottom panel: either decision input or chat input\n const bottomPanel =\n focusMode === \"decisions\" && currentDecision ? (\n <DecisionInputPanel\n decision={currentDecision}\n optionIndex={optionIndex}\n isTextMode={!currentHasOptions}\n textInput={decisionAnswer}\n onTextChange={setDecisionAnswer}\n onSubmit={submitDecisionAnswer}\n decisionCount={decisions.length}\n decisionIdx={decisionIndex}\n frame={frame}\n />\n ) : (\n <>\n <InputPanel\n value={input}\n onChange={setInput}\n onSubmit={handleSubmit}\n lastSent={lastSent}\n focus={focusMode === \"input\"}\n />\n <Footer hasDecisions={decisions.length > 0} />\n </>\n );\n\n return (\n <Box flexDirection=\"column\">\n <HeaderBar state={state} name={name} frame={frame} clock={clock} />\n <BudgetPanel state={state} dailyCap={dailyCap} costHistory={costHistory} />\n {focusMode !== \"decisions\" && <DecisionBanner decisions={decisions} frame={frame} />}\n <TaskPanel tasks={tasks} />\n <ActivityPanel\n entries={entries}\n termHeight={termHeight - taskPanelLines - decisionPanelLines}\n />\n {bottomPanel}\n </Box>\n );\n}\n"],"mappings":"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","names":[]}