acp-visualizer-tui 0.1.0 → 0.1.1

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/dist/cli.js CHANGED
@@ -224,7 +224,7 @@ function emptyProgressData() {
224
224
  }
225
225
 
226
226
  // src/app.tsx
227
- import { useState as useState8, useCallback as useCallback5 } from "react";
227
+ import { useState as useState10, useCallback as useCallback5 } from "react";
228
228
  import { Box as Box12, Text as Text15, useApp, useInput as useInput6 } from "ink";
229
229
 
230
230
  // src/hooks/useProgressData.ts
@@ -385,19 +385,24 @@ function Header({
385
385
  projectVersion
386
386
  ] })
387
387
  ] }),
388
- /* @__PURE__ */ jsx(Box, { gap: 1, children: views.map((view) => /* @__PURE__ */ jsx(
389
- Text,
390
- {
391
- bold: view === currentView,
392
- color: view === currentView ? "cyan" : void 0,
393
- dimColor: view !== currentView,
394
- children: labels[view]
395
- },
396
- view
397
- )) }),
388
+ /* @__PURE__ */ jsx(Box, { gap: 1, children: views.map((view) => {
389
+ const isActive = view === currentView;
390
+ if (isActive) {
391
+ return /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
392
+ "[",
393
+ labels[view],
394
+ "]"
395
+ ] }, view);
396
+ }
397
+ return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
398
+ " ",
399
+ labels[view],
400
+ " "
401
+ ] }, view);
402
+ }) }),
398
403
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
399
404
  "Filter: ",
400
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: filterLabel })
405
+ /* @__PURE__ */ jsx(Text, { color: filterLabel === "All" ? "gray" : "yellow", bold: filterLabel !== "All", children: filterLabel })
401
406
  ] })
402
407
  ] });
403
408
  }
@@ -405,13 +410,13 @@ function Header({
405
410
  // src/components/HelpBar.tsx
406
411
  import { Box as Box2, Text as Text2 } from "ink";
407
412
  import { jsx as jsx2 } from "react/jsx-runtime";
408
- var COMMON_KEYS = "Tab:View f:Filter r:Refresh q:Quit ?:Help";
413
+ var COMMON_KEYS = "Tab:View f:Filter /:Search r:Refresh q:Quit ?:Help";
409
414
  var VIEW_KEYS = {
410
- dashboard: `j/k:Scroll ${COMMON_KEYS}`,
415
+ dashboard: `${COMMON_KEYS}`,
411
416
  milestones: `j/k:Navigate s:Sort Enter:Detail ${COMMON_KEYS}`,
412
- tasks: `j/k:Navigate Enter:Expand ${COMMON_KEYS}`,
413
- activity: `j/k:Scroll ${COMMON_KEYS}`,
414
- blockers: `j/k:Scroll ${COMMON_KEYS}`
417
+ tasks: `j/k:Navigate Enter:Expand/Detail Space:Toggle ${COMMON_KEYS}`,
418
+ activity: `${COMMON_KEYS}`,
419
+ blockers: `${COMMON_KEYS}`
415
420
  };
416
421
  function HelpBar({ currentView }) {
417
422
  return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: VIEW_KEYS[currentView] }) });
@@ -594,8 +599,9 @@ function MilestoneTable({ milestones, filterMatch, active, onSelect }) {
594
599
  return /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "No milestones match current filter." });
595
600
  }
596
601
  return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
597
- /* @__PURE__ */ jsxs5(Box4, { gap: 1, children: [
598
- /* @__PURE__ */ jsx6(Box4, { width: 30, children: /* @__PURE__ */ jsxs5(Text6, { bold: true, dimColor: true, children: [
602
+ /* @__PURE__ */ jsxs5(Box4, { children: [
603
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " }),
604
+ /* @__PURE__ */ jsx6(Box4, { width: 32, children: /* @__PURE__ */ jsxs5(Text6, { bold: true, dimColor: true, children: [
599
605
  colLabel("name", sortKey),
600
606
  " Name"
601
607
  ] }) }),
@@ -603,7 +609,7 @@ function MilestoneTable({ milestones, filterMatch, active, onSelect }) {
603
609
  colLabel("status", sortKey),
604
610
  " Status"
605
611
  ] }) }),
606
- /* @__PURE__ */ jsx6(Box4, { width: 10, children: /* @__PURE__ */ jsxs5(Text6, { bold: true, dimColor: true, children: [
612
+ /* @__PURE__ */ jsx6(Box4, { width: 8, children: /* @__PURE__ */ jsxs5(Text6, { bold: true, dimColor: true, children: [
607
613
  colLabel("progress", sortKey),
608
614
  " Prog"
609
615
  ] }) }),
@@ -623,20 +629,21 @@ function MilestoneTable({ milestones, filterMatch, active, onSelect }) {
623
629
  /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u2500".repeat(80) }),
624
630
  sorted.map((m, i) => {
625
631
  const isSelected = i === selectedIdx && active;
626
- return /* @__PURE__ */ jsxs5(Box4, { gap: 1, children: [
627
- /* @__PURE__ */ jsx6(Box4, { width: 30, children: /* @__PURE__ */ jsx6(Text6, { bold: isSelected, inverse: isSelected, children: truncate(m.name, 28) }) }),
628
- /* @__PURE__ */ jsx6(Box4, { width: 14, children: /* @__PURE__ */ jsx6(StatusBadge, { status: m.status }) }),
629
- /* @__PURE__ */ jsx6(Box4, { width: 10, children: /* @__PURE__ */ jsxs5(Text6, { children: [
632
+ return /* @__PURE__ */ jsxs5(Box4, { children: [
633
+ /* @__PURE__ */ jsx6(Text6, { color: isSelected ? "cyan" : void 0, bold: isSelected, children: isSelected ? "> " : " " }),
634
+ /* @__PURE__ */ jsx6(Box4, { width: 32, children: /* @__PURE__ */ jsx6(Text6, { bold: isSelected, color: isSelected ? "cyan" : void 0, children: truncate(m.name, 30) }) }),
635
+ /* @__PURE__ */ jsx6(Box4, { width: 14, children: isSelected ? /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: statusText(m.status) }) : /* @__PURE__ */ jsx6(StatusBadge, { status: m.status }) }),
636
+ /* @__PURE__ */ jsx6(Box4, { width: 8, children: /* @__PURE__ */ jsxs5(Text6, { bold: isSelected, color: isSelected ? "cyan" : void 0, children: [
630
637
  m.progress,
631
638
  "%"
632
639
  ] }) }),
633
- /* @__PURE__ */ jsx6(Box4, { width: 8, children: /* @__PURE__ */ jsxs5(Text6, { children: [
640
+ /* @__PURE__ */ jsx6(Box4, { width: 8, children: /* @__PURE__ */ jsxs5(Text6, { bold: isSelected, color: isSelected ? "cyan" : void 0, children: [
634
641
  m.tasks_completed,
635
642
  "/",
636
643
  m.tasks_total
637
644
  ] }) }),
638
- /* @__PURE__ */ jsx6(Box4, { width: 12, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: m.started ? shortDate(m.started) : "\u2014" }) }),
639
- /* @__PURE__ */ jsx6(Box4, { width: 6, children: /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
645
+ /* @__PURE__ */ jsx6(Box4, { width: 12, children: /* @__PURE__ */ jsx6(Text6, { dimColor: !isSelected, color: isSelected ? "cyan" : void 0, children: m.started ? shortDate(m.started) : "\u2014" }) }),
646
+ /* @__PURE__ */ jsx6(Box4, { width: 6, children: /* @__PURE__ */ jsxs5(Text6, { dimColor: !isSelected, color: isSelected ? "cyan" : void 0, children: [
640
647
  m.estimated_weeks,
641
648
  "w"
642
649
  ] }) })
@@ -644,6 +651,16 @@ function MilestoneTable({ milestones, filterMatch, active, onSelect }) {
644
651
  })
645
652
  ] });
646
653
  }
654
+ function statusText(status) {
655
+ switch (status) {
656
+ case "completed":
657
+ return "\u2713 Completed";
658
+ case "in_progress":
659
+ return "\u25CF In Progress";
660
+ case "not_started":
661
+ return "\u25CB Not Started";
662
+ }
663
+ }
647
664
  function colLabel(col, active) {
648
665
  return col === active ? "\u25BC" : " ";
649
666
  }
@@ -663,6 +680,11 @@ function shortDate(d) {
663
680
  import { useState as useState5, useMemo } from "react";
664
681
  import { Box as Box5, Text as Text7, useInput as useInput2 } from "ink";
665
682
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
683
+ var STATUS_DOTS = {
684
+ completed: { dot: "\u2713", color: "green" },
685
+ in_progress: { dot: "\u25CF", color: "cyan" },
686
+ not_started: { dot: "\u25CB", color: "gray" }
687
+ };
666
688
  function TaskTree({ milestones, tasks, filterMatch, active, onSelectTask }) {
667
689
  const [expanded, setExpanded] = useState5(() => {
668
690
  const set = /* @__PURE__ */ new Set();
@@ -715,37 +737,41 @@ function TaskTree({ milestones, tasks, filterMatch, active, onSelectTask }) {
715
737
  }
716
738
  return /* @__PURE__ */ jsx7(Box5, { flexDirection: "column", children: flatItems.map((item, i) => {
717
739
  const isSelected = i === cursorIdx && active;
740
+ const selColor = isSelected ? "cyan" : void 0;
718
741
  if (item.type === "milestone") {
719
742
  const m = item.milestone;
720
743
  const icon = expanded.has(m.id) ? "\u25BC" : "\u25BA";
721
744
  const taskCount = (tasks[m.id] || []).filter((t2) => filterMatch(t2.status)).length;
722
- return /* @__PURE__ */ jsxs6(Box5, { gap: 1, children: [
723
- /* @__PURE__ */ jsxs6(Text7, { bold: isSelected, inverse: isSelected, children: [
745
+ const { dot: dot2, color: color2 } = STATUS_DOTS[m.status];
746
+ return /* @__PURE__ */ jsxs6(Box5, { children: [
747
+ /* @__PURE__ */ jsxs6(Text7, { color: selColor, bold: isSelected, children: [
748
+ isSelected ? "> " : " ",
724
749
  icon,
725
750
  " ",
726
751
  m.name
727
752
  ] }),
728
- /* @__PURE__ */ jsx7(StatusBadge, { status: m.status, compact: true }),
729
- /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
730
- "[",
753
+ /* @__PURE__ */ jsx7(Text7, { children: " " }),
754
+ /* @__PURE__ */ jsx7(Text7, { color: isSelected ? "cyan" : color2, children: dot2 }),
755
+ /* @__PURE__ */ jsxs6(Text7, { dimColor: !isSelected, color: selColor, children: [
756
+ " [",
731
757
  m.progress,
732
- "%]"
733
- ] }),
734
- /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
735
- "(",
758
+ "%] (",
736
759
  taskCount,
737
760
  " tasks)"
738
761
  ] })
739
762
  ] }, m.id);
740
763
  }
741
764
  const t = item.task;
742
- return /* @__PURE__ */ jsxs6(Box5, { gap: 1, marginLeft: 4, children: [
743
- /* @__PURE__ */ jsxs6(Text7, { bold: isSelected, inverse: isSelected, children: [
744
- /* @__PURE__ */ jsx7(StatusBadge, { status: t.status, compact: true }),
765
+ const { dot, color } = STATUS_DOTS[t.status];
766
+ return /* @__PURE__ */ jsxs6(Box5, { children: [
767
+ /* @__PURE__ */ jsxs6(Text7, { color: selColor, bold: isSelected, children: [
768
+ isSelected ? "> " : " ",
769
+ /* @__PURE__ */ jsx7(Text7, { color: isSelected ? "cyan" : color, children: dot }),
745
770
  " ",
746
771
  t.name
747
772
  ] }),
748
- t.estimated_hours && /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
773
+ t.estimated_hours && /* @__PURE__ */ jsxs6(Text7, { dimColor: !isSelected, color: selColor, children: [
774
+ " ",
749
775
  t.estimated_hours,
750
776
  "h"
751
777
  ] })
@@ -800,7 +826,7 @@ function BlockersNextSteps({ blockers, nextSteps }) {
800
826
  }
801
827
 
802
828
  // src/components/MilestoneDetail.tsx
803
- import React4, { useMemo as useMemo3 } from "react";
829
+ import { useMemo as useMemo3, useState as useState6 } from "react";
804
830
  import { Box as Box9, Text as Text12, useInput as useInput3 } from "ink";
805
831
 
806
832
  // src/lib/markdown-loader.ts
@@ -858,24 +884,49 @@ function Breadcrumb({ items }) {
858
884
 
859
885
  // src/components/MarkdownRenderer.tsx
860
886
  import { useMemo as useMemo2 } from "react";
861
- import { Text as Text11, Box as Box8 } from "ink";
887
+ import { Text as Text11, Box as Box8, useStdout } from "ink";
862
888
  import { Marked } from "marked";
863
889
  import { markedTerminal } from "marked-terminal";
864
- import { jsx as jsx11 } from "react/jsx-runtime";
865
- function MarkdownRenderer({ content }) {
866
- const rendered = useMemo2(() => {
890
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
891
+ function MarkdownRenderer({ content, scrollOffset = 0, maxHeight }) {
892
+ const { stdout } = useStdout();
893
+ const termHeight = maxHeight ?? (stdout?.rows ? stdout.rows - 12 : 30);
894
+ const { visibleText, totalLines, atEnd } = useMemo2(() => {
895
+ let rendered;
867
896
  try {
868
897
  const marked = new Marked(markedTerminal());
869
- return marked.parse(content);
898
+ rendered = marked.parse(content).trimEnd();
870
899
  } catch {
871
- return content;
900
+ rendered = content;
872
901
  }
873
- }, [content]);
874
- return /* @__PURE__ */ jsx11(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsx11(Text11, { children: rendered }) });
902
+ const lines = rendered.split("\n");
903
+ const total = lines.length;
904
+ const clampedOffset = Math.max(0, Math.min(scrollOffset, Math.max(0, total - termHeight)));
905
+ const visible = lines.slice(clampedOffset, clampedOffset + termHeight);
906
+ return {
907
+ visibleText: visible.join("\n"),
908
+ totalLines: total,
909
+ atEnd: clampedOffset + termHeight >= total
910
+ };
911
+ }, [content, scrollOffset, termHeight]);
912
+ const showScrollHint = totalLines > termHeight;
913
+ return /* @__PURE__ */ jsxs10(Box8, { flexDirection: "column", children: [
914
+ /* @__PURE__ */ jsx11(Text11, { children: visibleText }),
915
+ showScrollHint && /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
916
+ "\u2500 ",
917
+ "Lines ",
918
+ scrollOffset + 1,
919
+ "-",
920
+ Math.min(scrollOffset + termHeight, totalLines),
921
+ " of ",
922
+ totalLines,
923
+ atEnd ? " (end)" : " (j/k to scroll)"
924
+ ] })
925
+ ] });
875
926
  }
876
927
 
877
928
  // src/components/MilestoneDetail.tsx
878
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
929
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
879
930
  function MilestoneDetail({
880
931
  milestone,
881
932
  tasks,
@@ -890,37 +941,49 @@ function MilestoneDetail({
890
941
  if (!resolved) return { error: `No milestone document found for ${milestone.id}` };
891
942
  return loadMarkdownFile(basePath, resolved);
892
943
  }, [filePath2, milestone.id]);
893
- const [taskIdx, setTaskIdx] = React4.useState(0);
944
+ const [scrollOffset, setScrollOffset] = useState6(0);
945
+ const [taskIdx, setTaskIdx] = useState6(0);
946
+ const [focusArea, setFocusArea] = useState6("content");
894
947
  useInput3((input, key) => {
895
948
  if (!active) return;
896
949
  if (key.escape || key.backspace || key.delete) {
897
950
  onBack();
951
+ } else if (key.tab) {
952
+ setFocusArea((f) => f === "content" ? "tasks" : "content");
898
953
  } else if (input === "j" || key.downArrow) {
899
- setTaskIdx((i) => Math.min(i + 1, tasks.length - 1));
954
+ if (focusArea === "content") {
955
+ setScrollOffset((s) => s + 3);
956
+ } else {
957
+ setTaskIdx((i) => Math.min(i + 1, tasks.length - 1));
958
+ }
900
959
  } else if (input === "k" || key.upArrow) {
901
- setTaskIdx((i) => Math.max(i - 1, 0));
902
- } else if (key.return && tasks[taskIdx] && onSelectTask) {
960
+ if (focusArea === "content") {
961
+ setScrollOffset((s) => Math.max(0, s - 3));
962
+ } else {
963
+ setTaskIdx((i) => Math.max(i - 1, 0));
964
+ }
965
+ } else if (key.return && focusArea === "tasks" && tasks[taskIdx] && onSelectTask) {
903
966
  onSelectTask(tasks[taskIdx]);
904
967
  }
905
968
  });
906
- return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", gap: 1, children: [
969
+ return /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", gap: 1, children: [
907
970
  /* @__PURE__ */ jsx12(Breadcrumb, { items: [{ label: "Milestones" }, { label: milestone.name }] }),
908
- /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
909
- /* @__PURE__ */ jsxs10(Box9, { gap: 2, children: [
971
+ /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
972
+ /* @__PURE__ */ jsxs11(Box9, { gap: 2, children: [
910
973
  /* @__PURE__ */ jsx12(StatusBadge, { status: milestone.status }),
911
974
  /* @__PURE__ */ jsx12(ProgressBar, { percent: milestone.progress, width: 15 })
912
975
  ] }),
913
- /* @__PURE__ */ jsxs10(Box9, { gap: 2, children: [
914
- /* @__PURE__ */ jsxs10(Text12, { dimColor: true, children: [
976
+ /* @__PURE__ */ jsxs11(Box9, { gap: 2, children: [
977
+ /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
915
978
  "Started: ",
916
979
  milestone.started || "\u2014"
917
980
  ] }),
918
- /* @__PURE__ */ jsxs10(Text12, { dimColor: true, children: [
981
+ /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
919
982
  "Est: ",
920
983
  milestone.estimated_weeks,
921
984
  "w"
922
985
  ] }),
923
- /* @__PURE__ */ jsxs10(Text12, { dimColor: true, children: [
986
+ /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
924
987
  "Tasks: ",
925
988
  milestone.tasks_completed,
926
989
  "/",
@@ -929,23 +992,31 @@ function MilestoneDetail({
929
992
  ] }),
930
993
  milestone.notes && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: milestone.notes })
931
994
  ] }),
932
- "content" in markdownResult ? /* @__PURE__ */ jsx12(MarkdownRenderer, { content: markdownResult.content }) : /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "error" in markdownResult ? markdownResult.error : "No content" }),
933
- tasks.length > 0 && /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
995
+ "content" in markdownResult ? /* @__PURE__ */ jsx12(Box9, { borderStyle: focusArea === "content" ? "bold" : void 0, children: /* @__PURE__ */ jsx12(MarkdownRenderer, { content: markdownResult.content, scrollOffset }) }) : /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "error" in markdownResult ? markdownResult.error : "No content" }),
996
+ tasks.length > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", borderStyle: focusArea === "tasks" ? "bold" : "single", paddingX: 1, children: [
934
997
  /* @__PURE__ */ jsx12(Text12, { bold: true, children: " Tasks" }),
935
- tasks.map((t, i) => /* @__PURE__ */ jsxs10(Text12, { bold: i === taskIdx && active, inverse: i === taskIdx && active, children: [
936
- /* @__PURE__ */ jsx12(StatusBadge, { status: t.status, compact: true }),
937
- " ",
938
- t.name
939
- ] }, t.id))
998
+ tasks.map((t, i) => {
999
+ const isSel = i === taskIdx && focusArea === "tasks";
1000
+ return /* @__PURE__ */ jsxs11(Text12, { bold: isSel, color: isSel ? "cyan" : void 0, children: [
1001
+ isSel ? "> " : " ",
1002
+ /* @__PURE__ */ jsx12(StatusBadge, { status: t.status, compact: true }),
1003
+ " ",
1004
+ t.name
1005
+ ] }, t.id);
1006
+ })
940
1007
  ] }),
941
- /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Backspace:Back j/k:Navigate tasks Enter:Open task" })
1008
+ /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
1009
+ "Esc:Back j/k:Scroll Tab:",
1010
+ focusArea === "content" ? "Focus tasks" : "Focus content",
1011
+ " Enter:Open task"
1012
+ ] })
942
1013
  ] });
943
1014
  }
944
1015
 
945
1016
  // src/components/TaskDetail.tsx
946
- import { useMemo as useMemo4 } from "react";
1017
+ import { useMemo as useMemo4, useState as useState7 } from "react";
947
1018
  import { Box as Box10, Text as Text13, useInput as useInput4 } from "ink";
948
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1019
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
949
1020
  function TaskDetail({
950
1021
  task,
951
1022
  milestone,
@@ -960,6 +1031,7 @@ function TaskDetail({
960
1031
  const basePath = getBasePath(filePath2);
961
1032
  return loadMarkdownFile(basePath, task.file);
962
1033
  }, [filePath2, task.file, task.id]);
1034
+ const [scrollOffset, setScrollOffset] = useState7(0);
963
1035
  const siblingIdx = siblings.findIndex((t) => t.id === task.id);
964
1036
  const prevTask = siblingIdx > 0 ? siblings[siblingIdx - 1] : null;
965
1037
  const nextTask = siblingIdx < siblings.length - 1 ? siblings[siblingIdx + 1] : null;
@@ -967,13 +1039,19 @@ function TaskDetail({
967
1039
  if (!active) return;
968
1040
  if (key.escape || key.backspace || key.delete) {
969
1041
  onBack();
1042
+ } else if (input === "j" || key.downArrow) {
1043
+ setScrollOffset((s) => s + 3);
1044
+ } else if (input === "k" || key.upArrow) {
1045
+ setScrollOffset((s) => Math.max(0, s - 3));
970
1046
  } else if (input === "[" && prevTask && onNavigateSibling) {
1047
+ setScrollOffset(0);
971
1048
  onNavigateSibling(prevTask);
972
1049
  } else if (input === "]" && nextTask && onNavigateSibling) {
1050
+ setScrollOffset(0);
973
1051
  onNavigateSibling(nextTask);
974
1052
  }
975
1053
  });
976
- return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "column", gap: 1, children: [
1054
+ return /* @__PURE__ */ jsxs12(Box10, { flexDirection: "column", gap: 1, children: [
977
1055
  /* @__PURE__ */ jsx13(
978
1056
  Breadcrumb,
979
1057
  {
@@ -984,44 +1062,44 @@ function TaskDetail({
984
1062
  ]
985
1063
  }
986
1064
  ),
987
- /* @__PURE__ */ jsxs11(Box10, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
1065
+ /* @__PURE__ */ jsxs12(Box10, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
988
1066
  /* @__PURE__ */ jsx13(StatusBadge, { status: task.status }),
989
- /* @__PURE__ */ jsxs11(Box10, { gap: 2, children: [
990
- task.estimated_hours && /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1067
+ /* @__PURE__ */ jsxs12(Box10, { gap: 2, children: [
1068
+ task.estimated_hours && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
991
1069
  "Est: ",
992
1070
  task.estimated_hours,
993
1071
  "h"
994
1072
  ] }),
995
- task.completed_date && /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1073
+ task.completed_date && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
996
1074
  "Completed: ",
997
1075
  task.completed_date
998
1076
  ] })
999
1077
  ] }),
1000
- /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1078
+ /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
1001
1079
  "Milestone: ",
1002
1080
  milestone.name
1003
1081
  ] }),
1004
1082
  task.notes && /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: task.notes })
1005
1083
  ] }),
1006
- "content" in markdownResult ? /* @__PURE__ */ jsx13(MarkdownRenderer, { content: markdownResult.content }) : /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "error" in markdownResult ? markdownResult.error : "No content" }),
1007
- /* @__PURE__ */ jsxs11(Box10, { gap: 2, children: [
1008
- prevTask ? /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1009
- "[: \u2190 ",
1084
+ "content" in markdownResult ? /* @__PURE__ */ jsx13(MarkdownRenderer, { content: markdownResult.content, scrollOffset }) : /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "error" in markdownResult ? markdownResult.error : "No content" }),
1085
+ /* @__PURE__ */ jsxs12(Box10, { gap: 2, children: [
1086
+ prevTask ? /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
1087
+ "[: ",
1010
1088
  prevTask.name
1011
1089
  ] }) : /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "[: (first task)" }),
1012
- nextTask ? /* @__PURE__ */ jsxs11(Text13, { dimColor: true, children: [
1013
- "]: \u2192 ",
1090
+ nextTask ? /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
1091
+ "]: ",
1014
1092
  nextTask.name
1015
1093
  ] }) : /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "]: (last task)" })
1016
1094
  ] }),
1017
- /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Backspace:Back [/]:Prev/Next task" })
1095
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Esc:Back j/k:Scroll [/]:Prev/Next task" })
1018
1096
  ] });
1019
1097
  }
1020
1098
 
1021
1099
  // src/components/SearchResults.tsx
1022
- import { useState as useState6 } from "react";
1100
+ import { useState as useState8 } from "react";
1023
1101
  import { Box as Box11, Text as Text14, useInput as useInput5 } from "ink";
1024
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1102
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1025
1103
  function SearchResults({
1026
1104
  query,
1027
1105
  results,
@@ -1030,7 +1108,7 @@ function SearchResults({
1030
1108
  onSelectTask,
1031
1109
  onCancel
1032
1110
  }) {
1033
- const [selectedIdx, setSelectedIdx] = useState6(0);
1111
+ const [selectedIdx, setSelectedIdx] = useState8(0);
1034
1112
  useInput5((input, key) => {
1035
1113
  if (!active) return;
1036
1114
  if (key.escape) {
@@ -1053,19 +1131,19 @@ function SearchResults({
1053
1131
  const milestoneResults = results.filter((r) => r.type === "milestone");
1054
1132
  const taskResults = results.filter((r) => r.type === "task");
1055
1133
  let flatIdx = 0;
1056
- return /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", gap: 1, children: [
1057
- /* @__PURE__ */ jsxs12(Text14, { children: [
1134
+ return /* @__PURE__ */ jsxs13(Box11, { flexDirection: "column", gap: 1, children: [
1135
+ /* @__PURE__ */ jsxs13(Text14, { children: [
1058
1136
  "Search: ",
1059
1137
  /* @__PURE__ */ jsx14(Text14, { bold: true, children: query }),
1060
- query && /* @__PURE__ */ jsxs12(Text14, { dimColor: true, children: [
1138
+ query && /* @__PURE__ */ jsxs13(Text14, { dimColor: true, children: [
1061
1139
  " (",
1062
1140
  results.length,
1063
1141
  " results)"
1064
1142
  ] })
1065
1143
  ] }),
1066
1144
  results.length === 0 && query.trim() && /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "No results found." }),
1067
- milestoneResults.length > 0 && /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", children: [
1068
- /* @__PURE__ */ jsxs12(Text14, { bold: true, dimColor: true, children: [
1145
+ milestoneResults.length > 0 && /* @__PURE__ */ jsxs13(Box11, { flexDirection: "column", children: [
1146
+ /* @__PURE__ */ jsxs13(Text14, { bold: true, dimColor: true, children: [
1069
1147
  "Milestones (",
1070
1148
  milestoneResults.length,
1071
1149
  ")"
@@ -1073,7 +1151,7 @@ function SearchResults({
1073
1151
  milestoneResults.map((r) => {
1074
1152
  const idx = flatIdx++;
1075
1153
  const m = r.milestone;
1076
- return /* @__PURE__ */ jsxs12(Text14, { bold: idx === selectedIdx, inverse: idx === selectedIdx, children: [
1154
+ return /* @__PURE__ */ jsxs13(Text14, { bold: idx === selectedIdx, inverse: idx === selectedIdx, children: [
1077
1155
  " ",
1078
1156
  /* @__PURE__ */ jsx14(StatusBadge, { status: m.status, compact: true }),
1079
1157
  " ",
@@ -1081,8 +1159,8 @@ function SearchResults({
1081
1159
  ] }, r.id);
1082
1160
  })
1083
1161
  ] }),
1084
- taskResults.length > 0 && /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", children: [
1085
- /* @__PURE__ */ jsxs12(Text14, { bold: true, dimColor: true, children: [
1162
+ taskResults.length > 0 && /* @__PURE__ */ jsxs13(Box11, { flexDirection: "column", children: [
1163
+ /* @__PURE__ */ jsxs13(Text14, { bold: true, dimColor: true, children: [
1086
1164
  "Tasks (",
1087
1165
  taskResults.length,
1088
1166
  ")"
@@ -1090,7 +1168,7 @@ function SearchResults({
1090
1168
  taskResults.map((r) => {
1091
1169
  const idx = flatIdx++;
1092
1170
  const t = r.task;
1093
- return /* @__PURE__ */ jsxs12(Text14, { bold: idx === selectedIdx, inverse: idx === selectedIdx, children: [
1171
+ return /* @__PURE__ */ jsxs13(Text14, { bold: idx === selectedIdx, inverse: idx === selectedIdx, children: [
1094
1172
  " ",
1095
1173
  /* @__PURE__ */ jsx14(StatusBadge, { status: t.status, compact: true }),
1096
1174
  " ",
@@ -1103,11 +1181,11 @@ function SearchResults({
1103
1181
  }
1104
1182
 
1105
1183
  // src/hooks/useSearch.ts
1106
- import { useState as useState7, useMemo as useMemo5, useCallback as useCallback4 } from "react";
1184
+ import { useState as useState9, useMemo as useMemo5, useCallback as useCallback4 } from "react";
1107
1185
  import Fuse from "fuse.js";
1108
1186
  function useSearch(data) {
1109
- const [query, setQuery] = useState7("");
1110
- const [isSearching, setIsSearching] = useState7(false);
1187
+ const [query, setQuery] = useState9("");
1188
+ const [isSearching, setIsSearching] = useState9(false);
1111
1189
  const fuse = useMemo5(() => {
1112
1190
  if (!data) return null;
1113
1191
  const items = [];
@@ -1145,15 +1223,15 @@ function useSearch(data) {
1145
1223
  }
1146
1224
 
1147
1225
  // src/app.tsx
1148
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1226
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1149
1227
  function App({ filePath: filePath2, watch, initialView }) {
1150
1228
  const { data, error, reload } = useProgressData(filePath2);
1151
1229
  useWatchMode(filePath2, watch, reload);
1152
1230
  const nav = useNavigation(initialView);
1153
1231
  const filter = useFilter();
1154
1232
  const { exit } = useApp();
1155
- const [showHelp, setShowHelp] = useState8(false);
1156
- const [detail, setDetail] = useState8({ type: "none" });
1233
+ const [showHelp, setShowHelp] = useState10(false);
1234
+ const [detail, setDetail] = useState10({ type: "none" });
1157
1235
  const search = useSearch(data);
1158
1236
  const openMilestoneDetail = useCallback5((milestone) => {
1159
1237
  setDetail({ type: "milestone", milestone });
@@ -1247,7 +1325,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1247
1325
  }
1248
1326
  });
1249
1327
  if (error && !data) {
1250
- return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsxs13(Text15, { color: "red", children: [
1328
+ return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsxs14(Text15, { color: "red", children: [
1251
1329
  "Error: ",
1252
1330
  error
1253
1331
  ] }) });
@@ -1256,50 +1334,50 @@ function App({ filePath: filePath2, watch, initialView }) {
1256
1334
  return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "Loading..." }) });
1257
1335
  }
1258
1336
  if (showHelp) {
1259
- return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", padding: 1, children: [
1337
+ return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", padding: 1, children: [
1260
1338
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "Keyboard Shortcuts" }),
1261
1339
  /* @__PURE__ */ jsx15(Text15, {}),
1262
- /* @__PURE__ */ jsxs13(Text15, { children: [
1340
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1263
1341
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "Tab" }),
1264
1342
  " / ",
1265
1343
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "Shift+Tab" }),
1266
1344
  " Switch views"
1267
1345
  ] }),
1268
- /* @__PURE__ */ jsxs13(Text15, { children: [
1346
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1269
1347
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "j/k" }),
1270
1348
  " or ",
1271
1349
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "\u2191/\u2193" }),
1272
1350
  " Navigate"
1273
1351
  ] }),
1274
- /* @__PURE__ */ jsxs13(Text15, { children: [
1352
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1275
1353
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "Enter" }),
1276
1354
  " Expand / open detail"
1277
1355
  ] }),
1278
- /* @__PURE__ */ jsxs13(Text15, { children: [
1356
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1279
1357
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "Backspace/Esc" }),
1280
1358
  " Back from detail"
1281
1359
  ] }),
1282
- /* @__PURE__ */ jsxs13(Text15, { children: [
1360
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1283
1361
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "[/]" }),
1284
1362
  " Prev/next task (in detail)"
1285
1363
  ] }),
1286
- /* @__PURE__ */ jsxs13(Text15, { children: [
1364
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1287
1365
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "s" }),
1288
1366
  " Cycle sort (table)"
1289
1367
  ] }),
1290
- /* @__PURE__ */ jsxs13(Text15, { children: [
1368
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1291
1369
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "f" }),
1292
1370
  " Cycle status filter"
1293
1371
  ] }),
1294
- /* @__PURE__ */ jsxs13(Text15, { children: [
1372
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1295
1373
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "r" }),
1296
1374
  " Refresh data"
1297
1375
  ] }),
1298
- /* @__PURE__ */ jsxs13(Text15, { children: [
1376
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1299
1377
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "q" }),
1300
1378
  " Quit"
1301
1379
  ] }),
1302
- /* @__PURE__ */ jsxs13(Text15, { children: [
1380
+ /* @__PURE__ */ jsxs14(Text15, { children: [
1303
1381
  /* @__PURE__ */ jsx15(Text15, { bold: true, children: "?" }),
1304
1382
  " Toggle this help"
1305
1383
  ] }),
@@ -1308,7 +1386,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1308
1386
  ] });
1309
1387
  }
1310
1388
  if (search.isSearching) {
1311
- return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", children: [
1389
+ return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", children: [
1312
1390
  /* @__PURE__ */ jsx15(
1313
1391
  Header,
1314
1392
  {
@@ -1342,7 +1420,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1342
1420
  }
1343
1421
  if (detail.type === "milestone") {
1344
1422
  const milestoneTasks = data.tasks[detail.milestone.id] || [];
1345
- return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", children: [
1423
+ return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", children: [
1346
1424
  /* @__PURE__ */ jsx15(
1347
1425
  Header,
1348
1426
  {
@@ -1371,7 +1449,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1371
1449
  }
1372
1450
  if (detail.type === "task") {
1373
1451
  const siblings = data.tasks[detail.milestone.id] || [];
1374
- return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", children: [
1452
+ return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", children: [
1375
1453
  /* @__PURE__ */ jsx15(
1376
1454
  Header,
1377
1455
  {
@@ -1399,7 +1477,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1399
1477
  ) })
1400
1478
  ] });
1401
1479
  }
1402
- return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", children: [
1480
+ return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", children: [
1403
1481
  /* @__PURE__ */ jsx15(
1404
1482
  Header,
1405
1483
  {
@@ -1412,7 +1490,7 @@ function App({ filePath: filePath2, watch, initialView }) {
1412
1490
  }
1413
1491
  ),
1414
1492
  /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "\u2500".repeat(80) }),
1415
- /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
1493
+ /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
1416
1494
  nav.currentView === "dashboard" && /* @__PURE__ */ jsx15(Dashboard, { data }),
1417
1495
  nav.currentView === "milestones" && /* @__PURE__ */ jsx15(
1418
1496
  MilestoneTable,
@@ -1492,6 +1570,7 @@ if (cli.flags.json) {
1492
1570
  }
1493
1571
  process.exit(0);
1494
1572
  }
1573
+ process.stdout.write("\x1B[2J\x1B[H");
1495
1574
  render(
1496
1575
  /* @__PURE__ */ jsx16(
1497
1576
  App,
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.tsx","../src/lib/yaml-loader.ts","../src/app.tsx","../src/hooks/useProgressData.ts","../src/hooks/useWatchMode.ts","../src/hooks/useNavigation.ts","../src/hooks/useFilter.ts","../src/components/Header.tsx","../src/components/HelpBar.tsx","../src/components/Dashboard.tsx","../src/components/StatusBadge.tsx","../src/components/ProgressBar.tsx","../src/components/MilestoneTable.tsx","../src/components/TaskTree.tsx","../src/components/ActivityLog.tsx","../src/components/BlockersNextSteps.tsx","../src/components/MilestoneDetail.tsx","../src/lib/markdown-loader.ts","../src/components/Breadcrumb.tsx","../src/components/MarkdownRenderer.tsx","../src/components/TaskDetail.tsx","../src/components/SearchResults.tsx","../src/hooks/useSearch.ts"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport meow from 'meow';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { parseProgressYaml } from './lib/yaml-loader.js';\nimport App from './app.js';\n\nconst cli = meow(`\n Usage\n $ acp-visualizer-tui [path]\n\n Arguments\n path Path to progress.yaml (default: ./agent/progress.yaml)\n\n Options\n -w, --watch Watch mode: auto-refresh on file changes\n -v, --view Initial view: dashboard|milestones|tasks|activity|blockers\n --json Output parsed data as JSON (non-interactive)\n --no-color Disable colors\n -h, --help Show help\n -V, --version Show version\n`, {\n importMeta: import.meta,\n flags: {\n watch: { type: 'boolean', shortFlag: 'w', default: false },\n view: { type: 'string', shortFlag: 'v', default: 'dashboard' },\n json: { type: 'boolean', default: false },\n },\n});\n\nconst filePath = cli.input[0] || './agent/progress.yaml';\nconst resolvedPath = path.resolve(filePath);\n\n// Verify file exists before proceeding\nif (!fs.existsSync(resolvedPath)) {\n console.error(`Error: File not found: ${resolvedPath}`);\n console.error(`\\nMake sure progress.yaml exists at the specified path.`);\n console.error(`Default path: ./agent/progress.yaml`);\n process.exit(1);\n}\n\n// JSON mode: parse and output, then exit\nif (cli.flags.json) {\n try {\n const raw = fs.readFileSync(resolvedPath, 'utf-8');\n const data = parseProgressYaml(raw);\n console.log(JSON.stringify(data, null, 2));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Error reading file: ${msg}`);\n process.exit(1);\n }\n process.exit(0);\n}\n\n// Interactive mode: let App handle loading via useProgressData hook\nrender(\n <App\n filePath={resolvedPath}\n watch={cli.flags.watch}\n initialView={cli.flags.view}\n />\n);\n","import yaml from 'js-yaml';\nimport type {\n ProgressData,\n ProjectMetadata,\n Milestone,\n Task,\n WorkEntry,\n DocumentationStats,\n ProgressSummary,\n Status,\n ExtraFields,\n} from './types.js';\n\nconst TASK_ALIASES: Record<string, string> = {\n est_hours: 'estimated_hours',\n hours: 'estimated_hours',\n estimate: 'estimated_hours',\n completed: 'completed_date',\n done_date: 'completed_date',\n filename: 'file',\n path: 'file',\n};\n\nfunction extractKnown(\n obj: Record<string, unknown> | null | undefined,\n knownKeys: string[],\n): { known: Record<string, unknown>; extra: ExtraFields } {\n if (!obj || typeof obj !== 'object') return { known: {}, extra: {} };\n const known: Record<string, unknown> = {};\n const extra: ExtraFields = {};\n for (const [key, value] of Object.entries(obj)) {\n const resolved = TASK_ALIASES[key] ?? key;\n if (knownKeys.includes(resolved)) {\n known[resolved] = value;\n } else {\n extra[key] = value;\n }\n }\n return { known, extra };\n}\n\nexport function normalizeStatus(value: unknown): Status {\n const s = String(value || 'not_started')\n .toLowerCase()\n .replace(/[\\s-]/g, '_');\n if (s === 'completed' || s === 'done' || s === 'complete') return 'completed';\n if (s === 'in_progress' || s === 'active' || s === 'wip') return 'in_progress';\n return 'not_started';\n}\n\nfunction normalizeStringArray(value: unknown): string[] {\n if (!value) return [];\n if (typeof value === 'string') return [value];\n if (!Array.isArray(value)) return [];\n return value.map(String);\n}\n\nfunction safeString(value: unknown, fallback = ''): string {\n if (value == null) return fallback;\n return String(value);\n}\n\nfunction safeNumber(value: unknown, fallback = 0): number {\n const n = Number(value);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction normalizeProject(raw: unknown): ProjectMetadata {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'name', 'version', 'started', 'status', 'current_milestone', 'description',\n ]);\n return {\n name: safeString(known.name, 'Unknown Project'),\n version: safeString(known.version, '0.0.0'),\n started: safeString(known.started),\n status: normalizeStatus(known.status),\n current_milestone: known.current_milestone ? safeString(known.current_milestone) : undefined,\n description: safeString(known.description),\n extra,\n };\n}\n\nfunction normalizeMilestone(raw: unknown): Milestone {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'id', 'name', 'status', 'progress', 'started', 'completed',\n 'estimated_weeks', 'tasks_completed', 'tasks_total', 'notes',\n ]);\n return {\n id: safeString(known.id),\n name: safeString(known.name),\n status: normalizeStatus(known.status),\n progress: safeNumber(known.progress),\n started: known.started ? safeString(known.started) : null,\n completed: known.completed ? safeString(known.completed) : null,\n estimated_weeks: safeString(known.estimated_weeks),\n tasks_completed: safeNumber(known.tasks_completed),\n tasks_total: safeNumber(known.tasks_total),\n notes: safeString(known.notes),\n extra,\n };\n}\n\nfunction normalizeMilestones(raw: unknown): Milestone[] {\n if (!Array.isArray(raw)) return [];\n return raw.map(normalizeMilestone);\n}\n\nfunction normalizeTask(raw: unknown, milestoneId: string): Task {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'id', 'name', 'status', 'file', 'estimated_hours', 'completed_date', 'notes',\n ]);\n return {\n id: safeString(known.id),\n name: safeString(known.name),\n status: normalizeStatus(known.status),\n milestone_id: milestoneId,\n file: safeString(known.file),\n estimated_hours: safeString(known.estimated_hours),\n completed_date: known.completed_date ? safeString(known.completed_date) : null,\n notes: safeString(known.notes),\n extra,\n };\n}\n\nfunction normalizeTasks(raw: unknown): Record<string, Task[]> {\n if (!raw || typeof raw !== 'object') return {};\n const result: Record<string, Task[]> = {};\n for (const [milestoneId, tasks] of Object.entries(raw as Record<string, unknown>)) {\n if (Array.isArray(tasks)) {\n result[milestoneId] = tasks.map((t) => normalizeTask(t, milestoneId));\n }\n }\n return result;\n}\n\nfunction normalizeWorkEntry(raw: unknown): WorkEntry {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, ['date', 'description', 'items']);\n return {\n date: safeString(known.date),\n description: safeString(known.description),\n items: normalizeStringArray(known.items),\n extra,\n };\n}\n\nfunction normalizeWorkEntries(raw: unknown): WorkEntry[] {\n if (!Array.isArray(raw)) return [];\n return raw.map(normalizeWorkEntry);\n}\n\nfunction normalizeDocStats(raw: unknown): DocumentationStats {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n return {\n design_documents: safeNumber(obj?.design_documents),\n milestone_documents: safeNumber(obj?.milestone_documents),\n pattern_documents: safeNumber(obj?.pattern_documents),\n task_documents: safeNumber(obj?.task_documents),\n };\n}\n\nfunction normalizeProgress(raw: unknown): ProgressSummary {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n return {\n planning: safeNumber(obj?.planning),\n implementation: safeNumber(obj?.implementation),\n overall: safeNumber(obj?.overall),\n };\n}\n\nexport function parseProgressYaml(raw: string): ProgressData {\n try {\n const doc = yaml.load(raw) as Record<string, unknown> | null;\n if (!doc || typeof doc !== 'object') {\n return emptyProgressData();\n }\n\n const milestones = normalizeMilestones(doc.milestones);\n const tasks = normalizeTasks(doc.tasks);\n\n // Compute milestone progress from tasks if not explicitly set\n for (const milestone of milestones) {\n const milestoneTasks = tasks[milestone.id];\n if (milestoneTasks && milestoneTasks.length > 0) {\n const completed = milestoneTasks.filter((t) => t.status === 'completed').length;\n const total = milestoneTasks.length;\n if (milestone.tasks_total === 0) milestone.tasks_total = total;\n if (milestone.tasks_completed === 0) milestone.tasks_completed = completed;\n if (milestone.progress === 0 && total > 0) {\n milestone.progress = Math.round((completed / total) * 100);\n }\n }\n }\n\n return {\n project: normalizeProject(doc.project),\n milestones,\n tasks,\n recent_work: normalizeWorkEntries(doc.recent_work),\n next_steps: normalizeStringArray(doc.next_steps),\n notes: normalizeStringArray(doc.notes),\n current_blockers: normalizeStringArray(doc.current_blockers),\n documentation: normalizeDocStats(doc.documentation),\n progress: normalizeProgress(doc.progress),\n };\n } catch {\n return emptyProgressData();\n }\n}\n\nfunction emptyProgressData(): ProgressData {\n return {\n project: {\n name: 'Unknown',\n version: '0.0.0',\n started: '',\n status: 'not_started',\n description: '',\n extra: {},\n },\n milestones: [],\n tasks: {},\n recent_work: [],\n next_steps: [],\n notes: [],\n current_blockers: [],\n documentation: { design_documents: 0, milestone_documents: 0, pattern_documents: 0, task_documents: 0 },\n progress: { planning: 0, implementation: 0, overall: 0 },\n };\n}\n","import React, { useState, useCallback } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { useProgressData } from './hooks/useProgressData.js';\nimport { useWatchMode } from './hooks/useWatchMode.js';\nimport { useNavigation } from './hooks/useNavigation.js';\nimport { useFilter } from './hooks/useFilter.js';\nimport { Header } from './components/Header.js';\nimport { HelpBar } from './components/HelpBar.js';\nimport { Dashboard } from './components/Dashboard.js';\nimport { MilestoneTable } from './components/MilestoneTable.js';\nimport { TaskTree } from './components/TaskTree.js';\nimport { ActivityLog } from './components/ActivityLog.js';\nimport { BlockersNextSteps } from './components/BlockersNextSteps.js';\nimport { MilestoneDetail } from './components/MilestoneDetail.js';\nimport { TaskDetail } from './components/TaskDetail.js';\nimport { SearchResults } from './components/SearchResults.js';\nimport { useSearch } from './hooks/useSearch.js';\nimport type { Milestone, Task } from './lib/types.js';\n\ninterface AppProps {\n filePath: string;\n watch: boolean;\n initialView?: string;\n}\n\ntype DetailState =\n | { type: 'none' }\n | { type: 'milestone'; milestone: Milestone }\n | { type: 'task'; task: Task; milestone: Milestone };\n\nexport default function App({ filePath, watch, initialView }: AppProps) {\n const { data, error, reload } = useProgressData(filePath);\n useWatchMode(filePath, watch, reload);\n const nav = useNavigation(initialView);\n const filter = useFilter();\n const { exit } = useApp();\n const [showHelp, setShowHelp] = useState(false);\n const [detail, setDetail] = useState<DetailState>({ type: 'none' });\n const search = useSearch(data);\n\n const openMilestoneDetail = useCallback((milestone: Milestone) => {\n setDetail({ type: 'milestone', milestone });\n }, []);\n\n const openTaskDetail = useCallback((task: Task) => {\n if (!data) return;\n // Find parent milestone\n const milestone = data.milestones.find((m) => m.id === task.milestone_id);\n if (milestone) {\n setDetail({ type: 'task', task, milestone });\n }\n }, [data]);\n\n const closeDetail = useCallback(() => {\n setDetail((prev) => {\n // If in task detail, go back to milestone detail\n if (prev.type === 'task') {\n return { type: 'milestone', milestone: prev.milestone };\n }\n return { type: 'none' };\n });\n }, []);\n\n const navigateToSiblingTask = useCallback((task: Task) => {\n if (!data) return;\n const milestone = data.milestones.find((m) => m.id === task.milestone_id);\n if (milestone) {\n setDetail({ type: 'task', task, milestone });\n }\n }, [data]);\n\n // Global keyboard handling\n useInput((input, key) => {\n if (showHelp) {\n setShowHelp(false);\n return;\n }\n\n // Search input mode: capture typed characters\n if (search.isSearching) {\n if (key.escape) { search.cancelSearch(); return; }\n if (key.backspace || key.delete) {\n search.setQuery(search.query.slice(0, -1));\n return;\n }\n // Let j/k/Enter pass through to SearchResults when query exists\n if (search.query && (input === 'j' || input === 'k' || key.return || key.downArrow || key.upArrow)) {\n return; // SearchResults useInput handles these\n }\n if (input && !key.ctrl && !key.meta && input.length === 1 && input !== 'q') {\n search.setQuery(search.query + input);\n return;\n }\n return;\n }\n\n // In detail view, let detail component handle most keys\n if (detail.type !== 'none') {\n if (input === 'q') { exit(); return; }\n if (input === '?') { setShowHelp(true); return; }\n if (input === 'r') { reload(); return; }\n return;\n }\n\n if (input === 'q') { exit(); return; }\n if (input === '?') { setShowHelp(true); return; }\n if (input === 'f') { filter.cycleFilter(); return; }\n if (input === 'r') { reload(); return; }\n if (input === '/') { search.startSearch(); return; }\n if (key.tab) {\n if (key.shift) { nav.prevView(); }\n else { nav.nextView(); }\n }\n });\n\n if (error && !data) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"red\">Error: {error}</Text>\n </Box>\n );\n }\n\n if (!data) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text dimColor>Loading...</Text>\n </Box>\n );\n }\n\n // Help overlay\n if (showHelp) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold>Keyboard Shortcuts</Text>\n <Text />\n <Text><Text bold>Tab</Text> / <Text bold>Shift+Tab</Text> Switch views</Text>\n <Text><Text bold>j/k</Text> or <Text bold>↑/↓</Text> Navigate</Text>\n <Text><Text bold>Enter</Text> Expand / open detail</Text>\n <Text><Text bold>Backspace/Esc</Text> Back from detail</Text>\n <Text><Text bold>[/]</Text> Prev/next task (in detail)</Text>\n <Text><Text bold>s</Text> Cycle sort (table)</Text>\n <Text><Text bold>f</Text> Cycle status filter</Text>\n <Text><Text bold>r</Text> Refresh data</Text>\n <Text><Text bold>q</Text> Quit</Text>\n <Text><Text bold>?</Text> Toggle this help</Text>\n <Text />\n <Text dimColor>Press any key to dismiss</Text>\n </Box>\n );\n }\n\n // Search view\n if (search.isSearching) {\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <SearchResults\n query={search.query}\n results={search.results}\n active={true}\n onSelectMilestone={(m) => { search.cancelSearch(); openMilestoneDetail(m); }}\n onSelectTask={(t) => { search.cancelSearch(); openTaskDetail(t); }}\n onCancel={search.cancelSearch}\n />\n </Box>\n </Box>\n );\n }\n\n // Detail views\n if (detail.type === 'milestone') {\n const milestoneTasks = data.tasks[detail.milestone.id] || [];\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <MilestoneDetail\n milestone={detail.milestone}\n tasks={milestoneTasks}\n data={data}\n filePath={filePath}\n active={true}\n onBack={closeDetail}\n onSelectTask={openTaskDetail}\n />\n </Box>\n </Box>\n );\n }\n\n if (detail.type === 'task') {\n const siblings = data.tasks[detail.milestone.id] || [];\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <TaskDetail\n task={detail.task}\n milestone={detail.milestone}\n siblings={siblings}\n data={data}\n filePath={filePath}\n active={true}\n onBack={closeDetail}\n onNavigateSibling={navigateToSiblingTask}\n />\n </Box>\n </Box>\n );\n }\n\n // Normal list views\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n {nav.currentView === 'dashboard' && (\n <Dashboard data={data} />\n )}\n {nav.currentView === 'milestones' && (\n <MilestoneTable\n milestones={data.milestones}\n filterMatch={filter.matches}\n active={true}\n onSelect={openMilestoneDetail}\n />\n )}\n {nav.currentView === 'tasks' && (\n <TaskTree\n milestones={data.milestones}\n tasks={data.tasks}\n filterMatch={filter.matches}\n active={true}\n onSelectTask={openTaskDetail}\n />\n )}\n {nav.currentView === 'activity' && (\n <ActivityLog entries={data.recent_work} />\n )}\n {nav.currentView === 'blockers' && (\n <BlockersNextSteps\n blockers={data.current_blockers}\n nextSteps={data.next_steps}\n />\n )}\n </Box>\n <Text dimColor>{'─'.repeat(80)}</Text>\n <HelpBar currentView={nav.currentView} />\n </Box>\n );\n}\n","import { useState, useCallback } from 'react';\nimport fs from 'node:fs';\nimport { parseProgressYaml } from '../lib/yaml-loader.js';\nimport type { ProgressData } from '../lib/types.js';\n\ninterface UseProgressDataResult {\n data: ProgressData | null;\n error: string | null;\n loading: boolean;\n reload: () => void;\n}\n\nexport function useProgressData(filePath: string): UseProgressDataResult {\n const [state, setState] = useState<{\n data: ProgressData | null;\n error: string | null;\n loading: boolean;\n }>(() => {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return { data: parseProgressYaml(raw), error: null, loading: false };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { data: null, error: msg, loading: false };\n }\n });\n\n const reload = useCallback(() => {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n const data = parseProgressYaml(raw);\n setState({ data, error: null, loading: false });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n setState((prev) => ({ data: prev.data, error: msg, loading: false }));\n }\n }, [filePath]);\n\n return { ...state, reload };\n}\n","import { useEffect, useRef } from 'react';\nimport fs from 'node:fs';\n\nexport function useWatchMode(\n filePath: string,\n enabled: boolean,\n onReload: () => void,\n): void {\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n\n let watcher: fs.FSWatcher | null = null;\n\n try {\n watcher = fs.watch(filePath, () => {\n // Debounce: wait 300ms after last change before reloading\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => {\n onReload();\n }, 300);\n });\n\n watcher.on('error', () => {\n // File may have been deleted — keep watching in case it comes back\n });\n } catch {\n // fs.watch not available or file doesn't exist yet\n }\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n if (watcher) watcher.close();\n };\n }, [filePath, enabled, onReload]);\n}\n","import { useState, useCallback } from 'react';\n\nexport type ViewName = 'dashboard' | 'milestones' | 'tasks' | 'activity' | 'blockers';\n\nconst VIEW_ORDER: ViewName[] = ['dashboard', 'milestones', 'tasks', 'activity', 'blockers'];\n\nconst VIEW_LABELS: Record<ViewName, string> = {\n dashboard: 'Dashboard',\n milestones: 'Milestones',\n tasks: 'Tasks',\n activity: 'Activity',\n blockers: 'Blockers',\n};\n\nexport interface NavigationState {\n currentView: ViewName;\n viewStack: ViewName[];\n views: typeof VIEW_ORDER;\n labels: typeof VIEW_LABELS;\n nextView: () => void;\n prevView: () => void;\n goToView: (view: ViewName) => void;\n pushView: (view: ViewName) => void;\n popView: () => void;\n}\n\nexport function useNavigation(initialView?: string): NavigationState {\n const initial = VIEW_ORDER.includes(initialView as ViewName)\n ? (initialView as ViewName)\n : 'dashboard';\n\n const [currentView, setCurrentView] = useState<ViewName>(initial);\n const [viewStack, setViewStack] = useState<ViewName[]>([]);\n\n const nextView = useCallback(() => {\n setCurrentView((prev) => {\n const idx = VIEW_ORDER.indexOf(prev);\n return VIEW_ORDER[(idx + 1) % VIEW_ORDER.length];\n });\n }, []);\n\n const prevView = useCallback(() => {\n setCurrentView((prev) => {\n const idx = VIEW_ORDER.indexOf(prev);\n return VIEW_ORDER[(idx - 1 + VIEW_ORDER.length) % VIEW_ORDER.length];\n });\n }, []);\n\n const goToView = useCallback((view: ViewName) => {\n setCurrentView(view);\n }, []);\n\n const pushView = useCallback((view: ViewName) => {\n setCurrentView((prev) => {\n setViewStack((stack) => [...stack, prev]);\n return view;\n });\n }, []);\n\n const popView = useCallback(() => {\n setViewStack((stack) => {\n if (stack.length === 0) return stack;\n const newStack = [...stack];\n const prev = newStack.pop()!;\n setCurrentView(prev);\n return newStack;\n });\n }, []);\n\n return {\n currentView,\n viewStack,\n views: VIEW_ORDER,\n labels: VIEW_LABELS,\n nextView,\n prevView,\n goToView,\n pushView,\n popView,\n };\n}\n","import { useState, useCallback } from 'react';\nimport type { Status } from '../lib/types.js';\n\nexport type FilterValue = 'all' | Status;\n\nconst FILTER_ORDER: FilterValue[] = ['all', 'in_progress', 'completed', 'not_started'];\n\nconst FILTER_LABELS: Record<FilterValue, string> = {\n all: 'All',\n in_progress: 'In Progress',\n completed: 'Completed',\n not_started: 'Not Started',\n};\n\nexport interface FilterState {\n filter: FilterValue;\n label: string;\n cycleFilter: () => void;\n matches: (status: Status) => boolean;\n}\n\nexport function useFilter(): FilterState {\n const [filter, setFilter] = useState<FilterValue>('all');\n\n const cycleFilter = useCallback(() => {\n setFilter((prev) => {\n const idx = FILTER_ORDER.indexOf(prev);\n return FILTER_ORDER[(idx + 1) % FILTER_ORDER.length];\n });\n }, []);\n\n const matches = useCallback(\n (status: Status) => filter === 'all' || filter === status,\n [filter],\n );\n\n return {\n filter,\n label: FILTER_LABELS[filter],\n cycleFilter,\n matches,\n };\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ViewName } from '../hooks/useNavigation.js';\n\ninterface HeaderProps {\n projectName: string;\n projectVersion: string;\n currentView: ViewName;\n views: ViewName[];\n labels: Record<ViewName, string>;\n filterLabel: string;\n}\n\nexport function Header({\n projectName,\n projectVersion,\n currentView,\n views,\n labels,\n filterLabel,\n}: HeaderProps) {\n return (\n <Box flexDirection=\"row\" justifyContent=\"space-between\">\n <Text bold>\n {projectName} <Text dimColor>v{projectVersion}</Text>\n </Text>\n <Box gap={1}>\n {views.map((view) => (\n <Text\n key={view}\n bold={view === currentView}\n color={view === currentView ? 'cyan' : undefined}\n dimColor={view !== currentView}\n >\n {labels[view]}\n </Text>\n ))}\n </Box>\n <Text dimColor>\n Filter: <Text color=\"yellow\">{filterLabel}</Text>\n </Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ViewName } from '../hooks/useNavigation.js';\n\ninterface HelpBarProps {\n currentView: ViewName;\n}\n\nconst COMMON_KEYS = 'Tab:View f:Filter r:Refresh q:Quit ?:Help';\n\nconst VIEW_KEYS: Record<ViewName, string> = {\n dashboard: `j/k:Scroll ${COMMON_KEYS}`,\n milestones: `j/k:Navigate s:Sort Enter:Detail ${COMMON_KEYS}`,\n tasks: `j/k:Navigate Enter:Expand ${COMMON_KEYS}`,\n activity: `j/k:Scroll ${COMMON_KEYS}`,\n blockers: `j/k:Scroll ${COMMON_KEYS}`,\n};\n\nexport function HelpBar({ currentView }: HelpBarProps) {\n return (\n <Box>\n <Text dimColor>{VIEW_KEYS[currentView]}</Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ProgressData } from '../lib/types.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { ProgressBar } from './ProgressBar.js';\n\ninterface DashboardProps {\n data: ProgressData;\n}\n\nexport function Dashboard({ data }: DashboardProps) {\n const { project, milestones, next_steps, current_blockers } = data;\n\n const completed = milestones.filter((m) => m.status === 'completed').length;\n const inProgress = milestones.filter((m) => m.status === 'in_progress').length;\n const notStarted = milestones.filter((m) => m.status === 'not_started').length;\n\n const currentMilestone = milestones.find((m) => m.id === project.current_milestone);\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n {/* Project Info */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Project</Text>\n <Text>\n {project.name} <Text dimColor>v{project.version}</Text>\n </Text>\n <Box gap={2}>\n <StatusBadge status={project.status} />\n <Text dimColor>Started: {project.started || 'N/A'}</Text>\n </Box>\n <ProgressBar percent={data.progress.overall} label=\"Progress:\" />\n {currentMilestone && (\n <Text>\n Current: <Text bold>{currentMilestone.name}</Text>\n </Text>\n )}\n </Box>\n\n {/* Milestone Summary */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Milestones</Text>\n <Box gap={3}>\n <Text color=\"green\">✓ Completed: {completed}</Text>\n <Text color=\"cyan\">● In Progress: {inProgress}</Text>\n <Text dimColor>○ Not Started: {notStarted}</Text>\n </Box>\n </Box>\n\n {/* Blockers */}\n {current_blockers.length > 0 && (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold color=\"red\"> Blockers</Text>\n {current_blockers.map((b, i) => (\n <Text key={i} color=\"red\"> • {b}</Text>\n ))}\n </Box>\n )}\n\n {/* Next Steps */}\n {next_steps.length > 0 && (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Next Steps</Text>\n {next_steps.map((step, i) => (\n <Text key={i}> {i + 1}. {step}</Text>\n ))}\n </Box>\n )}\n </Box>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\nimport type { Status } from '../lib/types.js';\n\ninterface StatusBadgeProps {\n status: Status;\n compact?: boolean;\n}\n\nconst STATUS_CONFIG: Record<Status, { dot: string; label: string; color: string }> = {\n completed: { dot: '✓', label: 'Completed', color: 'green' },\n in_progress: { dot: '●', label: 'In Progress', color: 'cyan' },\n not_started: { dot: '○', label: 'Not Started', color: 'gray' },\n};\n\nexport function StatusBadge({ status, compact }: StatusBadgeProps) {\n const { dot, label, color } = STATUS_CONFIG[status];\n\n if (compact) {\n return <Text color={color}>{dot}</Text>;\n }\n\n return (\n <Text color={color}>\n {dot} {label}\n </Text>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\ninterface ProgressBarProps {\n percent: number;\n width?: number;\n label?: string;\n}\n\nexport function ProgressBar({ percent, width = 20, label }: ProgressBarProps) {\n const clamped = Math.max(0, Math.min(100, percent));\n const filled = Math.round((clamped / 100) * width);\n const empty = width - filled;\n\n const bar = '█'.repeat(filled) + '░'.repeat(empty);\n\n const color = clamped >= 80 ? 'green' : clamped >= 40 ? 'cyan' : 'gray';\n\n return (\n <Text>\n {label && <Text>{label} </Text>}\n <Text color={color}>{bar}</Text>\n <Text> {clamped}%</Text>\n </Text>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Status } from '../lib/types.js';\nimport { StatusBadge } from './StatusBadge.js';\n\ninterface MilestoneTableProps {\n milestones: Milestone[];\n filterMatch: (status: Status) => boolean;\n active: boolean;\n onSelect?: (milestone: Milestone) => void;\n}\n\ntype SortKey = 'name' | 'status' | 'progress' | 'tasks' | 'started' | 'estimated_weeks';\n\nconst SORT_KEYS: SortKey[] = ['name', 'status', 'progress', 'tasks', 'started', 'estimated_weeks'];\nconst SORT_LABELS: Record<SortKey, string> = {\n name: 'Name',\n status: 'Status',\n progress: 'Progress',\n tasks: 'Tasks',\n started: 'Started',\n estimated_weeks: 'Est.',\n};\n\nconst STATUS_ORDER: Record<Status, number> = {\n in_progress: 0,\n not_started: 1,\n completed: 2,\n};\n\nfunction sortMilestones(milestones: Milestone[], key: SortKey, asc: boolean): Milestone[] {\n return [...milestones].sort((a, b) => {\n let cmp = 0;\n switch (key) {\n case 'name': cmp = a.name.localeCompare(b.name); break;\n case 'status': cmp = STATUS_ORDER[a.status] - STATUS_ORDER[b.status]; break;\n case 'progress': cmp = a.progress - b.progress; break;\n case 'tasks': cmp = a.tasks_completed - b.tasks_completed; break;\n case 'started': cmp = (a.started || '').localeCompare(b.started || ''); break;\n case 'estimated_weeks': cmp = parseFloat(a.estimated_weeks || '0') - parseFloat(b.estimated_weeks || '0'); break;\n }\n return asc ? cmp : -cmp;\n });\n}\n\nexport function MilestoneTable({ milestones, filterMatch, active, onSelect }: MilestoneTableProps) {\n const [selectedIdx, setSelectedIdx] = useState(0);\n const [sortKey, setSortKey] = useState<SortKey>('status');\n const [sortAsc, setSortAsc] = useState(true);\n\n const filtered = milestones.filter((m) => filterMatch(m.status));\n const sorted = sortMilestones(filtered, sortKey, sortAsc);\n\n useInput((input, key) => {\n if (!active) return;\n\n if (input === 'j' || key.downArrow) {\n setSelectedIdx((i) => Math.min(i + 1, sorted.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setSelectedIdx((i) => Math.max(i - 1, 0));\n } else if (input === 's') {\n setSortKey((prev) => {\n const idx = SORT_KEYS.indexOf(prev);\n const next = SORT_KEYS[(idx + 1) % SORT_KEYS.length];\n if (next === prev) setSortAsc((a) => !a);\n return next;\n });\n } else if (key.return && sorted[selectedIdx] && onSelect) {\n onSelect(sorted[selectedIdx]);\n }\n });\n\n if (sorted.length === 0) {\n return <Text dimColor>No milestones match current filter.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {/* Header row */}\n <Box gap={1}>\n <Box width={30}><Text bold dimColor>{colLabel('name', sortKey)} Name</Text></Box>\n <Box width={14}><Text bold dimColor>{colLabel('status', sortKey)} Status</Text></Box>\n <Box width={10}><Text bold dimColor>{colLabel('progress', sortKey)} Prog</Text></Box>\n <Box width={8}><Text bold dimColor>{colLabel('tasks', sortKey)} Tasks</Text></Box>\n <Box width={12}><Text bold dimColor>{colLabel('started', sortKey)} Started</Text></Box>\n <Box width={6}><Text bold dimColor>{colLabel('estimated_weeks', sortKey)} Est</Text></Box>\n </Box>\n\n {/* Separator */}\n <Text dimColor>{'─'.repeat(80)}</Text>\n\n {/* Data rows */}\n {sorted.map((m, i) => {\n const isSelected = i === selectedIdx && active;\n return (\n <Box key={m.id} gap={1}>\n <Box width={30}>\n <Text bold={isSelected} inverse={isSelected}>\n {truncate(m.name, 28)}\n </Text>\n </Box>\n <Box width={14}><StatusBadge status={m.status} /></Box>\n <Box width={10}><Text>{m.progress}%</Text></Box>\n <Box width={8}><Text>{m.tasks_completed}/{m.tasks_total}</Text></Box>\n <Box width={12}><Text dimColor>{m.started ? shortDate(m.started) : '—'}</Text></Box>\n <Box width={6}><Text dimColor>{m.estimated_weeks}w</Text></Box>\n </Box>\n );\n })}\n </Box>\n );\n}\n\nfunction colLabel(col: SortKey, active: SortKey): string {\n return col === active ? '▼' : ' ';\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - 1) + '…' : s;\n}\n\nfunction shortDate(d: string): string {\n try {\n const date = new Date(d);\n return date.toISOString().slice(0, 10);\n } catch {\n return d.slice(0, 10);\n }\n}\n","import React, { useState, useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Task, Status } from '../lib/types.js';\nimport { StatusBadge } from './StatusBadge.js';\n\ninterface TaskTreeProps {\n milestones: Milestone[];\n tasks: Record<string, Task[]>;\n filterMatch: (status: Status) => boolean;\n active: boolean;\n onSelectTask?: (task: Task) => void;\n}\n\ninterface FlatItem {\n type: 'milestone' | 'task';\n milestone: Milestone;\n task?: Task;\n}\n\nexport function TaskTree({ milestones, tasks, filterMatch, active, onSelectTask }: TaskTreeProps) {\n const [expanded, setExpanded] = useState<Set<string>>(() => {\n // Default: expand in-progress milestones\n const set = new Set<string>();\n for (const m of milestones) {\n if (m.status === 'in_progress') set.add(m.id);\n }\n return set;\n });\n const [cursorIdx, setCursorIdx] = useState(0);\n\n // Build flat list of visible items\n const flatItems = useMemo(() => {\n const items: FlatItem[] = [];\n for (const m of milestones) {\n const milestoneTasks = (tasks[m.id] || []).filter((t) => filterMatch(t.status));\n // Hide milestone if all tasks filtered out and milestone itself doesn't match\n if (milestoneTasks.length === 0 && !filterMatch(m.status)) continue;\n\n items.push({ type: 'milestone', milestone: m });\n if (expanded.has(m.id)) {\n for (const t of milestoneTasks) {\n items.push({ type: 'task', milestone: m, task: t });\n }\n }\n }\n return items;\n }, [milestones, tasks, filterMatch, expanded]);\n\n useInput((input, key) => {\n if (!active) return;\n\n if (input === 'j' || key.downArrow) {\n setCursorIdx((i) => Math.min(i + 1, flatItems.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setCursorIdx((i) => Math.max(i - 1, 0));\n } else if (key.return || input === ' ') {\n const item = flatItems[cursorIdx];\n if (!item) return;\n if (item.type === 'milestone') {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(item.milestone.id)) {\n next.delete(item.milestone.id);\n } else {\n next.add(item.milestone.id);\n }\n return next;\n });\n } else if (item.task && onSelectTask) {\n onSelectTask(item.task);\n }\n }\n });\n\n if (flatItems.length === 0) {\n return <Text dimColor>No items match current filter.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {flatItems.map((item, i) => {\n const isSelected = i === cursorIdx && active;\n\n if (item.type === 'milestone') {\n const m = item.milestone;\n const icon = expanded.has(m.id) ? '▼' : '►';\n const taskCount = (tasks[m.id] || []).filter((t) => filterMatch(t.status)).length;\n\n return (\n <Box key={m.id} gap={1}>\n <Text bold={isSelected} inverse={isSelected}>\n {icon} {m.name}\n </Text>\n <StatusBadge status={m.status} compact />\n <Text dimColor>[{m.progress}%]</Text>\n <Text dimColor>({taskCount} tasks)</Text>\n </Box>\n );\n }\n\n // Task item\n const t = item.task!;\n return (\n <Box key={t.id} gap={1} marginLeft={4}>\n <Text bold={isSelected} inverse={isSelected}>\n <StatusBadge status={t.status} compact /> {t.name}\n </Text>\n {t.estimated_hours && <Text dimColor>{t.estimated_hours}h</Text>}\n </Box>\n );\n })}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { WorkEntry } from '../lib/types.js';\n\ninterface ActivityLogProps {\n entries: WorkEntry[];\n}\n\nexport function ActivityLog({ entries }: ActivityLogProps) {\n if (entries.length === 0) {\n return <Text dimColor>No recent work entries.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n {entries.map((entry, i) => (\n <Box key={i} flexDirection=\"column\">\n <Text>\n <Text bold>{entry.date}</Text>\n <Text dimColor> — {entry.description}</Text>\n </Text>\n {entry.items.map((item, j) => (\n <Text key={j} dimColor> • {item}</Text>\n ))}\n </Box>\n ))}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\ninterface BlockersNextStepsProps {\n blockers: string[];\n nextSteps: string[];\n}\n\nexport function BlockersNextSteps({ blockers, nextSteps }: BlockersNextStepsProps) {\n return (\n <Box flexDirection=\"column\" gap={1}>\n {/* Blockers */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold color={blockers.length > 0 ? 'red' : undefined}> Current Blockers</Text>\n {blockers.length === 0 ? (\n <Text dimColor> (none)</Text>\n ) : (\n blockers.map((b, i) => (\n <Text key={i} color=\"red\"> • {b}</Text>\n ))\n )}\n </Box>\n\n {/* Next Steps */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Next Steps</Text>\n {nextSteps.length === 0 ? (\n <Text dimColor> (none)</Text>\n ) : (\n nextSteps.map((s, i) => (\n <Text key={i}> {i + 1}. {s}</Text>\n ))\n )}\n </Box>\n </Box>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Task, ProgressData } from '../lib/types.js';\nimport { getBasePath, resolveMilestoneFile, loadMarkdownFile } from '../lib/markdown-loader.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { ProgressBar } from './ProgressBar.js';\nimport { Breadcrumb } from './Breadcrumb.js';\nimport { MarkdownRenderer } from './MarkdownRenderer.js';\n\ninterface MilestoneDetailProps {\n milestone: Milestone;\n tasks: Task[];\n data: ProgressData;\n filePath: string;\n active: boolean;\n onBack: () => void;\n onSelectTask?: (task: Task) => void;\n}\n\nexport function MilestoneDetail({\n milestone,\n tasks,\n filePath,\n active,\n onBack,\n onSelectTask,\n}: MilestoneDetailProps) {\n const markdownResult = useMemo(() => {\n const basePath = getBasePath(filePath);\n const resolved = resolveMilestoneFile(basePath, milestone.id);\n if (!resolved) return { error: `No milestone document found for ${milestone.id}` };\n return loadMarkdownFile(basePath, resolved);\n }, [filePath, milestone.id]);\n\n const [taskIdx, setTaskIdx] = React.useState(0);\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape || key.backspace || key.delete) {\n onBack();\n } else if (input === 'j' || key.downArrow) {\n setTaskIdx((i) => Math.min(i + 1, tasks.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setTaskIdx((i) => Math.max(i - 1, 0));\n } else if (key.return && tasks[taskIdx] && onSelectTask) {\n onSelectTask(tasks[taskIdx]);\n }\n });\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Breadcrumb items={[{ label: 'Milestones' }, { label: milestone.name }]} />\n\n {/* Metadata */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Box gap={2}>\n <StatusBadge status={milestone.status} />\n <ProgressBar percent={milestone.progress} width={15} />\n </Box>\n <Box gap={2}>\n <Text dimColor>Started: {milestone.started || '—'}</Text>\n <Text dimColor>Est: {milestone.estimated_weeks}w</Text>\n <Text dimColor>Tasks: {milestone.tasks_completed}/{milestone.tasks_total}</Text>\n </Box>\n {milestone.notes && <Text dimColor>{milestone.notes}</Text>}\n </Box>\n\n {/* Markdown */}\n {'content' in markdownResult ? (\n <MarkdownRenderer content={markdownResult.content} />\n ) : (\n <Text dimColor>{'error' in markdownResult ? markdownResult.error : 'No content'}</Text>\n )}\n\n {/* Task list */}\n {tasks.length > 0 && (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Tasks</Text>\n {tasks.map((t, i) => (\n <Text key={t.id} bold={i === taskIdx && active} inverse={i === taskIdx && active}>\n <StatusBadge status={t.status} compact /> {t.name}\n </Text>\n ))}\n </Box>\n )}\n\n <Text dimColor>Backspace:Back j/k:Navigate tasks Enter:Open task</Text>\n </Box>\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Task } from './types.js';\n\nexport type MarkdownResult =\n | { content: string; filePath: string }\n | { error: string };\n\n/**\n * Derive project base path from progress.yaml path.\n * e.g., /home/user/project/agent/progress.yaml → /home/user/project/\n */\nexport function getBasePath(progressYamlPath: string): string {\n // Strip agent/progress.yaml to get project root\n const dir = path.dirname(progressYamlPath);\n if (path.basename(dir) === 'agent') {\n return path.dirname(dir);\n }\n return dir;\n}\n\n/**\n * Load a markdown file from the filesystem.\n */\nexport function loadMarkdownFile(basePath: string, relativePath: string): MarkdownResult {\n const fullPath = path.resolve(basePath, relativePath);\n try {\n const content = fs.readFileSync(fullPath, 'utf-8');\n return { content, filePath: relativePath };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('ENOENT')) {\n return { error: `No document found at ${relativePath}` };\n }\n if (msg.includes('EACCES')) {\n return { error: `Cannot read ${relativePath}: permission denied` };\n }\n return { error: `Error reading ${relativePath}: ${msg}` };\n }\n}\n\n/**\n * Resolve milestone file by scanning agent/milestones/ for matching filename.\n * milestone_1 → look for milestone-1-*.md (excluding templates)\n */\nexport function resolveMilestoneFile(basePath: string, milestoneId: string): string | null {\n // Extract number: milestone_1 → 1, milestone_12 → 12\n const match = milestoneId.match(/(\\d+)/);\n if (!match) return null;\n const num = match[1];\n\n const milestonesDir = path.join(basePath, 'agent', 'milestones');\n try {\n const files = fs.readdirSync(milestonesDir);\n const pattern = `milestone-${num}-`;\n const found = files.find(\n (f) => f.startsWith(pattern) && f.endsWith('.md') && !f.includes('template'),\n );\n return found ? path.join('agent', 'milestones', found) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve task file by looking up task.file in the tasks map.\n */\nexport function resolveTaskFile(\n tasks: Record<string, Task[]>,\n taskId: string,\n): string | null {\n for (const milestoneTasks of Object.values(tasks)) {\n const task = milestoneTasks.find((t) => t.id === taskId);\n if (task?.file) return task.file;\n }\n return null;\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\ninterface BreadcrumbItem {\n label: string;\n}\n\ninterface BreadcrumbProps {\n items: BreadcrumbItem[];\n}\n\nexport function Breadcrumb({ items }: BreadcrumbProps) {\n return (\n <Text>\n {items.map((item, i) => (\n <Text key={i}>\n {i < items.length - 1 ? (\n <Text dimColor>{item.label} &gt; </Text>\n ) : (\n <Text bold>{item.label}</Text>\n )}\n </Text>\n ))}\n </Text>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Text, Box } from 'ink';\nimport { Marked } from 'marked';\nimport { markedTerminal } from 'marked-terminal';\n\ninterface MarkdownRendererProps {\n content: string;\n}\n\nexport function MarkdownRenderer({ content }: MarkdownRendererProps) {\n const rendered = useMemo(() => {\n try {\n const marked = new Marked(markedTerminal() as unknown as Record<string, unknown>);\n return marked.parse(content) as string;\n } catch {\n return content;\n }\n }, [content]);\n\n return (\n <Box flexDirection=\"column\">\n <Text>{rendered}</Text>\n </Box>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Task, Milestone, ProgressData } from '../lib/types.js';\nimport { getBasePath, loadMarkdownFile } from '../lib/markdown-loader.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { Breadcrumb } from './Breadcrumb.js';\nimport { MarkdownRenderer } from './MarkdownRenderer.js';\n\ninterface TaskDetailProps {\n task: Task;\n milestone: Milestone;\n siblings: Task[];\n data: ProgressData;\n filePath: string;\n active: boolean;\n onBack: () => void;\n onNavigateSibling?: (task: Task) => void;\n}\n\nexport function TaskDetail({\n task,\n milestone,\n siblings,\n filePath,\n active,\n onBack,\n onNavigateSibling,\n}: TaskDetailProps) {\n const markdownResult = useMemo(() => {\n if (!task.file) return { error: `No file path for ${task.id}` };\n const basePath = getBasePath(filePath);\n return loadMarkdownFile(basePath, task.file);\n }, [filePath, task.file, task.id]);\n\n const siblingIdx = siblings.findIndex((t) => t.id === task.id);\n const prevTask = siblingIdx > 0 ? siblings[siblingIdx - 1] : null;\n const nextTask = siblingIdx < siblings.length - 1 ? siblings[siblingIdx + 1] : null;\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape || key.backspace || key.delete) {\n onBack();\n } else if (input === '[' && prevTask && onNavigateSibling) {\n onNavigateSibling(prevTask);\n } else if (input === ']' && nextTask && onNavigateSibling) {\n onNavigateSibling(nextTask);\n }\n });\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Breadcrumb\n items={[\n { label: 'Milestones' },\n { label: milestone.name },\n { label: task.name },\n ]}\n />\n\n {/* Metadata */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <StatusBadge status={task.status} />\n <Box gap={2}>\n {task.estimated_hours && <Text dimColor>Est: {task.estimated_hours}h</Text>}\n {task.completed_date && <Text dimColor>Completed: {task.completed_date}</Text>}\n </Box>\n <Text dimColor>Milestone: {milestone.name}</Text>\n {task.notes && <Text dimColor>{task.notes}</Text>}\n </Box>\n\n {/* Markdown */}\n {'content' in markdownResult ? (\n <MarkdownRenderer content={markdownResult.content} />\n ) : (\n <Text dimColor>{'error' in markdownResult ? markdownResult.error : 'No content'}</Text>\n )}\n\n {/* Sibling navigation */}\n <Box gap={2}>\n {prevTask ? (\n <Text dimColor>[: ← {prevTask.name}</Text>\n ) : (\n <Text dimColor>[: (first task)</Text>\n )}\n {nextTask ? (\n <Text dimColor>]: → {nextTask.name}</Text>\n ) : (\n <Text dimColor>]: (last task)</Text>\n )}\n </Box>\n\n <Text dimColor>Backspace:Back [/]:Prev/Next task</Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { SearchResult } from '../hooks/useSearch.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport type { Milestone, Task } from '../lib/types.js';\n\ninterface SearchResultsProps {\n query: string;\n results: SearchResult[];\n active: boolean;\n onSelectMilestone?: (milestone: Milestone) => void;\n onSelectTask?: (task: Task) => void;\n onCancel: () => void;\n}\n\nexport function SearchResults({\n query,\n results,\n active,\n onSelectMilestone,\n onSelectTask,\n onCancel,\n}: SearchResultsProps) {\n const [selectedIdx, setSelectedIdx] = useState(0);\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape) {\n onCancel();\n return;\n }\n if (input === 'j' || key.downArrow) {\n setSelectedIdx((i) => Math.min(i + 1, results.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setSelectedIdx((i) => Math.max(i - 1, 0));\n } else if (key.return && results[selectedIdx]) {\n const r = results[selectedIdx];\n if (r.type === 'milestone' && r.milestone && onSelectMilestone) {\n onSelectMilestone(r.milestone);\n } else if (r.type === 'task' && r.task && onSelectTask) {\n onSelectTask(r.task);\n }\n }\n });\n\n const milestoneResults = results.filter((r) => r.type === 'milestone');\n const taskResults = results.filter((r) => r.type === 'task');\n\n let flatIdx = 0;\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text>\n Search: <Text bold>{query}</Text>\n {query && <Text dimColor> ({results.length} results)</Text>}\n </Text>\n\n {results.length === 0 && query.trim() && (\n <Text dimColor>No results found.</Text>\n )}\n\n {milestoneResults.length > 0 && (\n <Box flexDirection=\"column\">\n <Text bold dimColor>Milestones ({milestoneResults.length})</Text>\n {milestoneResults.map((r) => {\n const idx = flatIdx++;\n const m = r.milestone!;\n return (\n <Text key={r.id} bold={idx === selectedIdx} inverse={idx === selectedIdx}>\n {' '}<StatusBadge status={m.status} compact /> {m.name}\n </Text>\n );\n })}\n </Box>\n )}\n\n {taskResults.length > 0 && (\n <Box flexDirection=\"column\">\n <Text bold dimColor>Tasks ({taskResults.length})</Text>\n {taskResults.map((r) => {\n const idx = flatIdx++;\n const t = r.task!;\n return (\n <Text key={r.id} bold={idx === selectedIdx} inverse={idx === selectedIdx}>\n {' '}<StatusBadge status={t.status} compact /> {t.name}\n </Text>\n );\n })}\n </Box>\n )}\n\n <Text dimColor>j/k:Navigate Enter:Open Esc:Cancel</Text>\n </Box>\n );\n}\n","import { useState, useMemo, useCallback } from 'react';\nimport Fuse from 'fuse.js';\nimport type { ProgressData, Milestone, Task } from '../lib/types.js';\n\nexport interface SearchResult {\n type: 'milestone' | 'task';\n milestone?: Milestone;\n task?: Task;\n name: string;\n id: string;\n}\n\nexport interface SearchState {\n query: string;\n setQuery: (q: string) => void;\n results: SearchResult[];\n isSearching: boolean;\n startSearch: () => void;\n cancelSearch: () => void;\n}\n\nexport function useSearch(data: ProgressData | null): SearchState {\n const [query, setQuery] = useState('');\n const [isSearching, setIsSearching] = useState(false);\n\n const fuse = useMemo(() => {\n if (!data) return null;\n\n const items: SearchResult[] = [];\n\n for (const m of data.milestones) {\n items.push({ type: 'milestone', milestone: m, name: m.name, id: m.id });\n }\n\n for (const [, tasks] of Object.entries(data.tasks)) {\n for (const t of tasks) {\n items.push({ type: 'task', task: t, name: t.name, id: t.id });\n }\n }\n\n return new Fuse(items, {\n keys: [\n { name: 'name', weight: 0.7 },\n { name: 'task.notes', weight: 0.2 },\n { name: 'milestone.notes', weight: 0.1 },\n ],\n threshold: 0.4,\n includeScore: true,\n });\n }, [data]);\n\n const results = useMemo(() => {\n if (!fuse || !query.trim()) return [];\n return fuse.search(query).map((r) => r.item);\n }, [fuse, query]);\n\n const startSearch = useCallback(() => {\n setIsSearching(true);\n setQuery('');\n }, []);\n\n const cancelSearch = useCallback(() => {\n setIsSearching(false);\n setQuery('');\n }, []);\n\n return { query, setQuery, results, isSearching, startSearch, cancelSearch };\n}\n"],"mappings":"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","names":["fs","path","useState","useCallback","Box","Text","useInput","filePath","fs","filePath","useState","useCallback","useState","useCallback","Box","Text","jsx","Box","Text","Text","jsx","jsxs","Text","jsx","jsxs","jsx","jsxs","Box","Text","useState","Box","Text","jsx","jsxs","useState","jsx","Text","jsxs","Box","useState","Box","Text","useInput","jsx","jsxs","useState","useInput","Text","Box","t","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","React","useMemo","Box","Text","useInput","fs","Text","jsx","jsxs","useMemo","Text","Box","jsx","jsx","jsxs","filePath","useMemo","React","useInput","Box","Text","useMemo","Box","Text","useInput","jsx","jsxs","filePath","useMemo","useInput","Box","Text","useState","Box","Text","useInput","jsx","jsxs","useState","useInput","Box","Text","useState","useMemo","useCallback","jsx","jsxs","filePath","useState","useCallback","useInput","Box","Text","jsx","path","fs"]}
1
+ {"version":3,"sources":["../src/cli.tsx","../src/lib/yaml-loader.ts","../src/app.tsx","../src/hooks/useProgressData.ts","../src/hooks/useWatchMode.ts","../src/hooks/useNavigation.ts","../src/hooks/useFilter.ts","../src/components/Header.tsx","../src/components/HelpBar.tsx","../src/components/Dashboard.tsx","../src/components/StatusBadge.tsx","../src/components/ProgressBar.tsx","../src/components/MilestoneTable.tsx","../src/components/TaskTree.tsx","../src/components/ActivityLog.tsx","../src/components/BlockersNextSteps.tsx","../src/components/MilestoneDetail.tsx","../src/lib/markdown-loader.ts","../src/components/Breadcrumb.tsx","../src/components/MarkdownRenderer.tsx","../src/components/TaskDetail.tsx","../src/components/SearchResults.tsx","../src/hooks/useSearch.ts"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport meow from 'meow';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { parseProgressYaml } from './lib/yaml-loader.js';\nimport App from './app.js';\n\nconst cli = meow(`\n Usage\n $ acp-visualizer-tui [path]\n\n Arguments\n path Path to progress.yaml (default: ./agent/progress.yaml)\n\n Options\n -w, --watch Watch mode: auto-refresh on file changes\n -v, --view Initial view: dashboard|milestones|tasks|activity|blockers\n --json Output parsed data as JSON (non-interactive)\n --no-color Disable colors\n -h, --help Show help\n -V, --version Show version\n`, {\n importMeta: import.meta,\n flags: {\n watch: { type: 'boolean', shortFlag: 'w', default: false },\n view: { type: 'string', shortFlag: 'v', default: 'dashboard' },\n json: { type: 'boolean', default: false },\n },\n});\n\nconst filePath = cli.input[0] || './agent/progress.yaml';\nconst resolvedPath = path.resolve(filePath);\n\n// Verify file exists before proceeding\nif (!fs.existsSync(resolvedPath)) {\n console.error(`Error: File not found: ${resolvedPath}`);\n console.error(`\\nMake sure progress.yaml exists at the specified path.`);\n console.error(`Default path: ./agent/progress.yaml`);\n process.exit(1);\n}\n\n// JSON mode: parse and output, then exit\nif (cli.flags.json) {\n try {\n const raw = fs.readFileSync(resolvedPath, 'utf-8');\n const data = parseProgressYaml(raw);\n console.log(JSON.stringify(data, null, 2));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Error reading file: ${msg}`);\n process.exit(1);\n }\n process.exit(0);\n}\n\n// Clear terminal for full-screen rendering\nprocess.stdout.write('\\x1B[2J\\x1B[H');\n\n// Interactive mode: let App handle loading via useProgressData hook\nrender(\n <App\n filePath={resolvedPath}\n watch={cli.flags.watch}\n initialView={cli.flags.view}\n />\n);\n","import yaml from 'js-yaml';\nimport type {\n ProgressData,\n ProjectMetadata,\n Milestone,\n Task,\n WorkEntry,\n DocumentationStats,\n ProgressSummary,\n Status,\n ExtraFields,\n} from './types.js';\n\nconst TASK_ALIASES: Record<string, string> = {\n est_hours: 'estimated_hours',\n hours: 'estimated_hours',\n estimate: 'estimated_hours',\n completed: 'completed_date',\n done_date: 'completed_date',\n filename: 'file',\n path: 'file',\n};\n\nfunction extractKnown(\n obj: Record<string, unknown> | null | undefined,\n knownKeys: string[],\n): { known: Record<string, unknown>; extra: ExtraFields } {\n if (!obj || typeof obj !== 'object') return { known: {}, extra: {} };\n const known: Record<string, unknown> = {};\n const extra: ExtraFields = {};\n for (const [key, value] of Object.entries(obj)) {\n const resolved = TASK_ALIASES[key] ?? key;\n if (knownKeys.includes(resolved)) {\n known[resolved] = value;\n } else {\n extra[key] = value;\n }\n }\n return { known, extra };\n}\n\nexport function normalizeStatus(value: unknown): Status {\n const s = String(value || 'not_started')\n .toLowerCase()\n .replace(/[\\s-]/g, '_');\n if (s === 'completed' || s === 'done' || s === 'complete') return 'completed';\n if (s === 'in_progress' || s === 'active' || s === 'wip') return 'in_progress';\n return 'not_started';\n}\n\nfunction normalizeStringArray(value: unknown): string[] {\n if (!value) return [];\n if (typeof value === 'string') return [value];\n if (!Array.isArray(value)) return [];\n return value.map(String);\n}\n\nfunction safeString(value: unknown, fallback = ''): string {\n if (value == null) return fallback;\n return String(value);\n}\n\nfunction safeNumber(value: unknown, fallback = 0): number {\n const n = Number(value);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction normalizeProject(raw: unknown): ProjectMetadata {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'name', 'version', 'started', 'status', 'current_milestone', 'description',\n ]);\n return {\n name: safeString(known.name, 'Unknown Project'),\n version: safeString(known.version, '0.0.0'),\n started: safeString(known.started),\n status: normalizeStatus(known.status),\n current_milestone: known.current_milestone ? safeString(known.current_milestone) : undefined,\n description: safeString(known.description),\n extra,\n };\n}\n\nfunction normalizeMilestone(raw: unknown): Milestone {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'id', 'name', 'status', 'progress', 'started', 'completed',\n 'estimated_weeks', 'tasks_completed', 'tasks_total', 'notes',\n ]);\n return {\n id: safeString(known.id),\n name: safeString(known.name),\n status: normalizeStatus(known.status),\n progress: safeNumber(known.progress),\n started: known.started ? safeString(known.started) : null,\n completed: known.completed ? safeString(known.completed) : null,\n estimated_weeks: safeString(known.estimated_weeks),\n tasks_completed: safeNumber(known.tasks_completed),\n tasks_total: safeNumber(known.tasks_total),\n notes: safeString(known.notes),\n extra,\n };\n}\n\nfunction normalizeMilestones(raw: unknown): Milestone[] {\n if (!Array.isArray(raw)) return [];\n return raw.map(normalizeMilestone);\n}\n\nfunction normalizeTask(raw: unknown, milestoneId: string): Task {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, [\n 'id', 'name', 'status', 'file', 'estimated_hours', 'completed_date', 'notes',\n ]);\n return {\n id: safeString(known.id),\n name: safeString(known.name),\n status: normalizeStatus(known.status),\n milestone_id: milestoneId,\n file: safeString(known.file),\n estimated_hours: safeString(known.estimated_hours),\n completed_date: known.completed_date ? safeString(known.completed_date) : null,\n notes: safeString(known.notes),\n extra,\n };\n}\n\nfunction normalizeTasks(raw: unknown): Record<string, Task[]> {\n if (!raw || typeof raw !== 'object') return {};\n const result: Record<string, Task[]> = {};\n for (const [milestoneId, tasks] of Object.entries(raw as Record<string, unknown>)) {\n if (Array.isArray(tasks)) {\n result[milestoneId] = tasks.map((t) => normalizeTask(t, milestoneId));\n }\n }\n return result;\n}\n\nfunction normalizeWorkEntry(raw: unknown): WorkEntry {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const { known, extra } = extractKnown(obj, ['date', 'description', 'items']);\n return {\n date: safeString(known.date),\n description: safeString(known.description),\n items: normalizeStringArray(known.items),\n extra,\n };\n}\n\nfunction normalizeWorkEntries(raw: unknown): WorkEntry[] {\n if (!Array.isArray(raw)) return [];\n return raw.map(normalizeWorkEntry);\n}\n\nfunction normalizeDocStats(raw: unknown): DocumentationStats {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n return {\n design_documents: safeNumber(obj?.design_documents),\n milestone_documents: safeNumber(obj?.milestone_documents),\n pattern_documents: safeNumber(obj?.pattern_documents),\n task_documents: safeNumber(obj?.task_documents),\n };\n}\n\nfunction normalizeProgress(raw: unknown): ProgressSummary {\n const obj = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n return {\n planning: safeNumber(obj?.planning),\n implementation: safeNumber(obj?.implementation),\n overall: safeNumber(obj?.overall),\n };\n}\n\nexport function parseProgressYaml(raw: string): ProgressData {\n try {\n const doc = yaml.load(raw) as Record<string, unknown> | null;\n if (!doc || typeof doc !== 'object') {\n return emptyProgressData();\n }\n\n const milestones = normalizeMilestones(doc.milestones);\n const tasks = normalizeTasks(doc.tasks);\n\n // Compute milestone progress from tasks if not explicitly set\n for (const milestone of milestones) {\n const milestoneTasks = tasks[milestone.id];\n if (milestoneTasks && milestoneTasks.length > 0) {\n const completed = milestoneTasks.filter((t) => t.status === 'completed').length;\n const total = milestoneTasks.length;\n if (milestone.tasks_total === 0) milestone.tasks_total = total;\n if (milestone.tasks_completed === 0) milestone.tasks_completed = completed;\n if (milestone.progress === 0 && total > 0) {\n milestone.progress = Math.round((completed / total) * 100);\n }\n }\n }\n\n return {\n project: normalizeProject(doc.project),\n milestones,\n tasks,\n recent_work: normalizeWorkEntries(doc.recent_work),\n next_steps: normalizeStringArray(doc.next_steps),\n notes: normalizeStringArray(doc.notes),\n current_blockers: normalizeStringArray(doc.current_blockers),\n documentation: normalizeDocStats(doc.documentation),\n progress: normalizeProgress(doc.progress),\n };\n } catch {\n return emptyProgressData();\n }\n}\n\nfunction emptyProgressData(): ProgressData {\n return {\n project: {\n name: 'Unknown',\n version: '0.0.0',\n started: '',\n status: 'not_started',\n description: '',\n extra: {},\n },\n milestones: [],\n tasks: {},\n recent_work: [],\n next_steps: [],\n notes: [],\n current_blockers: [],\n documentation: { design_documents: 0, milestone_documents: 0, pattern_documents: 0, task_documents: 0 },\n progress: { planning: 0, implementation: 0, overall: 0 },\n };\n}\n","import React, { useState, useCallback } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { useProgressData } from './hooks/useProgressData.js';\nimport { useWatchMode } from './hooks/useWatchMode.js';\nimport { useNavigation } from './hooks/useNavigation.js';\nimport { useFilter } from './hooks/useFilter.js';\nimport { Header } from './components/Header.js';\nimport { HelpBar } from './components/HelpBar.js';\nimport { Dashboard } from './components/Dashboard.js';\nimport { MilestoneTable } from './components/MilestoneTable.js';\nimport { TaskTree } from './components/TaskTree.js';\nimport { ActivityLog } from './components/ActivityLog.js';\nimport { BlockersNextSteps } from './components/BlockersNextSteps.js';\nimport { MilestoneDetail } from './components/MilestoneDetail.js';\nimport { TaskDetail } from './components/TaskDetail.js';\nimport { SearchResults } from './components/SearchResults.js';\nimport { useSearch } from './hooks/useSearch.js';\nimport type { Milestone, Task } from './lib/types.js';\n\ninterface AppProps {\n filePath: string;\n watch: boolean;\n initialView?: string;\n}\n\ntype DetailState =\n | { type: 'none' }\n | { type: 'milestone'; milestone: Milestone }\n | { type: 'task'; task: Task; milestone: Milestone };\n\nexport default function App({ filePath, watch, initialView }: AppProps) {\n const { data, error, reload } = useProgressData(filePath);\n useWatchMode(filePath, watch, reload);\n const nav = useNavigation(initialView);\n const filter = useFilter();\n const { exit } = useApp();\n const [showHelp, setShowHelp] = useState(false);\n const [detail, setDetail] = useState<DetailState>({ type: 'none' });\n const search = useSearch(data);\n\n const openMilestoneDetail = useCallback((milestone: Milestone) => {\n setDetail({ type: 'milestone', milestone });\n }, []);\n\n const openTaskDetail = useCallback((task: Task) => {\n if (!data) return;\n // Find parent milestone\n const milestone = data.milestones.find((m) => m.id === task.milestone_id);\n if (milestone) {\n setDetail({ type: 'task', task, milestone });\n }\n }, [data]);\n\n const closeDetail = useCallback(() => {\n setDetail((prev) => {\n // If in task detail, go back to milestone detail\n if (prev.type === 'task') {\n return { type: 'milestone', milestone: prev.milestone };\n }\n return { type: 'none' };\n });\n }, []);\n\n const navigateToSiblingTask = useCallback((task: Task) => {\n if (!data) return;\n const milestone = data.milestones.find((m) => m.id === task.milestone_id);\n if (milestone) {\n setDetail({ type: 'task', task, milestone });\n }\n }, [data]);\n\n // Global keyboard handling\n useInput((input, key) => {\n if (showHelp) {\n setShowHelp(false);\n return;\n }\n\n // Search input mode: capture typed characters\n if (search.isSearching) {\n if (key.escape) { search.cancelSearch(); return; }\n if (key.backspace || key.delete) {\n search.setQuery(search.query.slice(0, -1));\n return;\n }\n // Let j/k/Enter pass through to SearchResults when query exists\n if (search.query && (input === 'j' || input === 'k' || key.return || key.downArrow || key.upArrow)) {\n return; // SearchResults useInput handles these\n }\n if (input && !key.ctrl && !key.meta && input.length === 1 && input !== 'q') {\n search.setQuery(search.query + input);\n return;\n }\n return;\n }\n\n // In detail view, let detail component handle most keys\n if (detail.type !== 'none') {\n if (input === 'q') { exit(); return; }\n if (input === '?') { setShowHelp(true); return; }\n if (input === 'r') { reload(); return; }\n return;\n }\n\n if (input === 'q') { exit(); return; }\n if (input === '?') { setShowHelp(true); return; }\n if (input === 'f') { filter.cycleFilter(); return; }\n if (input === 'r') { reload(); return; }\n if (input === '/') { search.startSearch(); return; }\n if (key.tab) {\n if (key.shift) { nav.prevView(); }\n else { nav.nextView(); }\n }\n });\n\n if (error && !data) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"red\">Error: {error}</Text>\n </Box>\n );\n }\n\n if (!data) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text dimColor>Loading...</Text>\n </Box>\n );\n }\n\n // Help overlay\n if (showHelp) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold>Keyboard Shortcuts</Text>\n <Text />\n <Text><Text bold>Tab</Text> / <Text bold>Shift+Tab</Text> Switch views</Text>\n <Text><Text bold>j/k</Text> or <Text bold>↑/↓</Text> Navigate</Text>\n <Text><Text bold>Enter</Text> Expand / open detail</Text>\n <Text><Text bold>Backspace/Esc</Text> Back from detail</Text>\n <Text><Text bold>[/]</Text> Prev/next task (in detail)</Text>\n <Text><Text bold>s</Text> Cycle sort (table)</Text>\n <Text><Text bold>f</Text> Cycle status filter</Text>\n <Text><Text bold>r</Text> Refresh data</Text>\n <Text><Text bold>q</Text> Quit</Text>\n <Text><Text bold>?</Text> Toggle this help</Text>\n <Text />\n <Text dimColor>Press any key to dismiss</Text>\n </Box>\n );\n }\n\n // Search view\n if (search.isSearching) {\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <SearchResults\n query={search.query}\n results={search.results}\n active={true}\n onSelectMilestone={(m) => { search.cancelSearch(); openMilestoneDetail(m); }}\n onSelectTask={(t) => { search.cancelSearch(); openTaskDetail(t); }}\n onCancel={search.cancelSearch}\n />\n </Box>\n </Box>\n );\n }\n\n // Detail views\n if (detail.type === 'milestone') {\n const milestoneTasks = data.tasks[detail.milestone.id] || [];\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <MilestoneDetail\n milestone={detail.milestone}\n tasks={milestoneTasks}\n data={data}\n filePath={filePath}\n active={true}\n onBack={closeDetail}\n onSelectTask={openTaskDetail}\n />\n </Box>\n </Box>\n );\n }\n\n if (detail.type === 'task') {\n const siblings = data.tasks[detail.milestone.id] || [];\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n <TaskDetail\n task={detail.task}\n milestone={detail.milestone}\n siblings={siblings}\n data={data}\n filePath={filePath}\n active={true}\n onBack={closeDetail}\n onNavigateSibling={navigateToSiblingTask}\n />\n </Box>\n </Box>\n );\n }\n\n // Normal list views\n return (\n <Box flexDirection=\"column\">\n <Header\n projectName={data.project.name}\n projectVersion={data.project.version}\n currentView={nav.currentView}\n views={nav.views}\n labels={nav.labels}\n filterLabel={filter.label}\n />\n <Text dimColor>{'─'.repeat(80)}</Text>\n <Box flexDirection=\"column\" flexGrow={1} paddingX={1}>\n {nav.currentView === 'dashboard' && (\n <Dashboard data={data} />\n )}\n {nav.currentView === 'milestones' && (\n <MilestoneTable\n milestones={data.milestones}\n filterMatch={filter.matches}\n active={true}\n onSelect={openMilestoneDetail}\n />\n )}\n {nav.currentView === 'tasks' && (\n <TaskTree\n milestones={data.milestones}\n tasks={data.tasks}\n filterMatch={filter.matches}\n active={true}\n onSelectTask={openTaskDetail}\n />\n )}\n {nav.currentView === 'activity' && (\n <ActivityLog entries={data.recent_work} />\n )}\n {nav.currentView === 'blockers' && (\n <BlockersNextSteps\n blockers={data.current_blockers}\n nextSteps={data.next_steps}\n />\n )}\n </Box>\n <Text dimColor>{'─'.repeat(80)}</Text>\n <HelpBar currentView={nav.currentView} />\n </Box>\n );\n}\n","import { useState, useCallback } from 'react';\nimport fs from 'node:fs';\nimport { parseProgressYaml } from '../lib/yaml-loader.js';\nimport type { ProgressData } from '../lib/types.js';\n\ninterface UseProgressDataResult {\n data: ProgressData | null;\n error: string | null;\n loading: boolean;\n reload: () => void;\n}\n\nexport function useProgressData(filePath: string): UseProgressDataResult {\n const [state, setState] = useState<{\n data: ProgressData | null;\n error: string | null;\n loading: boolean;\n }>(() => {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return { data: parseProgressYaml(raw), error: null, loading: false };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { data: null, error: msg, loading: false };\n }\n });\n\n const reload = useCallback(() => {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n const data = parseProgressYaml(raw);\n setState({ data, error: null, loading: false });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n setState((prev) => ({ data: prev.data, error: msg, loading: false }));\n }\n }, [filePath]);\n\n return { ...state, reload };\n}\n","import { useEffect, useRef } from 'react';\nimport fs from 'node:fs';\n\nexport function useWatchMode(\n filePath: string,\n enabled: boolean,\n onReload: () => void,\n): void {\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n\n let watcher: fs.FSWatcher | null = null;\n\n try {\n watcher = fs.watch(filePath, () => {\n // Debounce: wait 300ms after last change before reloading\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => {\n onReload();\n }, 300);\n });\n\n watcher.on('error', () => {\n // File may have been deleted — keep watching in case it comes back\n });\n } catch {\n // fs.watch not available or file doesn't exist yet\n }\n\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n if (watcher) watcher.close();\n };\n }, [filePath, enabled, onReload]);\n}\n","import { useState, useCallback } from 'react';\n\nexport type ViewName = 'dashboard' | 'milestones' | 'tasks' | 'activity' | 'blockers';\n\nconst VIEW_ORDER: ViewName[] = ['dashboard', 'milestones', 'tasks', 'activity', 'blockers'];\n\nconst VIEW_LABELS: Record<ViewName, string> = {\n dashboard: 'Dashboard',\n milestones: 'Milestones',\n tasks: 'Tasks',\n activity: 'Activity',\n blockers: 'Blockers',\n};\n\nexport interface NavigationState {\n currentView: ViewName;\n viewStack: ViewName[];\n views: typeof VIEW_ORDER;\n labels: typeof VIEW_LABELS;\n nextView: () => void;\n prevView: () => void;\n goToView: (view: ViewName) => void;\n pushView: (view: ViewName) => void;\n popView: () => void;\n}\n\nexport function useNavigation(initialView?: string): NavigationState {\n const initial = VIEW_ORDER.includes(initialView as ViewName)\n ? (initialView as ViewName)\n : 'dashboard';\n\n const [currentView, setCurrentView] = useState<ViewName>(initial);\n const [viewStack, setViewStack] = useState<ViewName[]>([]);\n\n const nextView = useCallback(() => {\n setCurrentView((prev) => {\n const idx = VIEW_ORDER.indexOf(prev);\n return VIEW_ORDER[(idx + 1) % VIEW_ORDER.length];\n });\n }, []);\n\n const prevView = useCallback(() => {\n setCurrentView((prev) => {\n const idx = VIEW_ORDER.indexOf(prev);\n return VIEW_ORDER[(idx - 1 + VIEW_ORDER.length) % VIEW_ORDER.length];\n });\n }, []);\n\n const goToView = useCallback((view: ViewName) => {\n setCurrentView(view);\n }, []);\n\n const pushView = useCallback((view: ViewName) => {\n setCurrentView((prev) => {\n setViewStack((stack) => [...stack, prev]);\n return view;\n });\n }, []);\n\n const popView = useCallback(() => {\n setViewStack((stack) => {\n if (stack.length === 0) return stack;\n const newStack = [...stack];\n const prev = newStack.pop()!;\n setCurrentView(prev);\n return newStack;\n });\n }, []);\n\n return {\n currentView,\n viewStack,\n views: VIEW_ORDER,\n labels: VIEW_LABELS,\n nextView,\n prevView,\n goToView,\n pushView,\n popView,\n };\n}\n","import { useState, useCallback } from 'react';\nimport type { Status } from '../lib/types.js';\n\nexport type FilterValue = 'all' | Status;\n\nconst FILTER_ORDER: FilterValue[] = ['all', 'in_progress', 'completed', 'not_started'];\n\nconst FILTER_LABELS: Record<FilterValue, string> = {\n all: 'All',\n in_progress: 'In Progress',\n completed: 'Completed',\n not_started: 'Not Started',\n};\n\nexport interface FilterState {\n filter: FilterValue;\n label: string;\n cycleFilter: () => void;\n matches: (status: Status) => boolean;\n}\n\nexport function useFilter(): FilterState {\n const [filter, setFilter] = useState<FilterValue>('all');\n\n const cycleFilter = useCallback(() => {\n setFilter((prev) => {\n const idx = FILTER_ORDER.indexOf(prev);\n return FILTER_ORDER[(idx + 1) % FILTER_ORDER.length];\n });\n }, []);\n\n const matches = useCallback(\n (status: Status) => filter === 'all' || filter === status,\n [filter],\n );\n\n return {\n filter,\n label: FILTER_LABELS[filter],\n cycleFilter,\n matches,\n };\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ViewName } from '../hooks/useNavigation.js';\n\ninterface HeaderProps {\n projectName: string;\n projectVersion: string;\n currentView: ViewName;\n views: ViewName[];\n labels: Record<ViewName, string>;\n filterLabel: string;\n}\n\nexport function Header({\n projectName,\n projectVersion,\n currentView,\n views,\n labels,\n filterLabel,\n}: HeaderProps) {\n return (\n <Box flexDirection=\"row\" justifyContent=\"space-between\">\n <Text bold>\n {projectName} <Text dimColor>v{projectVersion}</Text>\n </Text>\n <Box gap={1}>\n {views.map((view) => {\n const isActive = view === currentView;\n if (isActive) {\n return (\n <Text key={view} bold color=\"cyan\">\n [{labels[view]}]\n </Text>\n );\n }\n return (\n <Text key={view} dimColor>\n {' '}{labels[view]}{' '}\n </Text>\n );\n })}\n </Box>\n <Text dimColor>\n Filter: <Text color={filterLabel === 'All' ? 'gray' : 'yellow'} bold={filterLabel !== 'All'}>{filterLabel}</Text>\n </Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ViewName } from '../hooks/useNavigation.js';\n\ninterface HelpBarProps {\n currentView: ViewName;\n}\n\nconst COMMON_KEYS = 'Tab:View f:Filter /:Search r:Refresh q:Quit ?:Help';\n\nconst VIEW_KEYS: Record<ViewName, string> = {\n dashboard: `${COMMON_KEYS}`,\n milestones: `j/k:Navigate s:Sort Enter:Detail ${COMMON_KEYS}`,\n tasks: `j/k:Navigate Enter:Expand/Detail Space:Toggle ${COMMON_KEYS}`,\n activity: `${COMMON_KEYS}`,\n blockers: `${COMMON_KEYS}`,\n};\n\nexport function HelpBar({ currentView }: HelpBarProps) {\n return (\n <Box>\n <Text dimColor>{VIEW_KEYS[currentView]}</Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ProgressData } from '../lib/types.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { ProgressBar } from './ProgressBar.js';\n\ninterface DashboardProps {\n data: ProgressData;\n}\n\nexport function Dashboard({ data }: DashboardProps) {\n const { project, milestones, next_steps, current_blockers } = data;\n\n const completed = milestones.filter((m) => m.status === 'completed').length;\n const inProgress = milestones.filter((m) => m.status === 'in_progress').length;\n const notStarted = milestones.filter((m) => m.status === 'not_started').length;\n\n const currentMilestone = milestones.find((m) => m.id === project.current_milestone);\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n {/* Project Info */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Project</Text>\n <Text>\n {project.name} <Text dimColor>v{project.version}</Text>\n </Text>\n <Box gap={2}>\n <StatusBadge status={project.status} />\n <Text dimColor>Started: {project.started || 'N/A'}</Text>\n </Box>\n <ProgressBar percent={data.progress.overall} label=\"Progress:\" />\n {currentMilestone && (\n <Text>\n Current: <Text bold>{currentMilestone.name}</Text>\n </Text>\n )}\n </Box>\n\n {/* Milestone Summary */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Milestones</Text>\n <Box gap={3}>\n <Text color=\"green\">✓ Completed: {completed}</Text>\n <Text color=\"cyan\">● In Progress: {inProgress}</Text>\n <Text dimColor>○ Not Started: {notStarted}</Text>\n </Box>\n </Box>\n\n {/* Blockers */}\n {current_blockers.length > 0 && (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold color=\"red\"> Blockers</Text>\n {current_blockers.map((b, i) => (\n <Text key={i} color=\"red\"> • {b}</Text>\n ))}\n </Box>\n )}\n\n {/* Next Steps */}\n {next_steps.length > 0 && (\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Next Steps</Text>\n {next_steps.map((step, i) => (\n <Text key={i}> {i + 1}. {step}</Text>\n ))}\n </Box>\n )}\n </Box>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\nimport type { Status } from '../lib/types.js';\n\ninterface StatusBadgeProps {\n status: Status;\n compact?: boolean;\n}\n\nconst STATUS_CONFIG: Record<Status, { dot: string; label: string; color: string }> = {\n completed: { dot: '✓', label: 'Completed', color: 'green' },\n in_progress: { dot: '●', label: 'In Progress', color: 'cyan' },\n not_started: { dot: '○', label: 'Not Started', color: 'gray' },\n};\n\nexport function StatusBadge({ status, compact }: StatusBadgeProps) {\n const { dot, label, color } = STATUS_CONFIG[status];\n\n if (compact) {\n return <Text color={color}>{dot}</Text>;\n }\n\n return (\n <Text color={color}>\n {dot} {label}\n </Text>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\ninterface ProgressBarProps {\n percent: number;\n width?: number;\n label?: string;\n}\n\nexport function ProgressBar({ percent, width = 20, label }: ProgressBarProps) {\n const clamped = Math.max(0, Math.min(100, percent));\n const filled = Math.round((clamped / 100) * width);\n const empty = width - filled;\n\n const bar = '█'.repeat(filled) + '░'.repeat(empty);\n\n const color = clamped >= 80 ? 'green' : clamped >= 40 ? 'cyan' : 'gray';\n\n return (\n <Text>\n {label && <Text>{label} </Text>}\n <Text color={color}>{bar}</Text>\n <Text> {clamped}%</Text>\n </Text>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Status } from '../lib/types.js';\nimport { StatusBadge } from './StatusBadge.js';\n\ninterface MilestoneTableProps {\n milestones: Milestone[];\n filterMatch: (status: Status) => boolean;\n active: boolean;\n onSelect?: (milestone: Milestone) => void;\n}\n\ntype SortKey = 'name' | 'status' | 'progress' | 'tasks' | 'started' | 'estimated_weeks';\n\nconst SORT_KEYS: SortKey[] = ['name', 'status', 'progress', 'tasks', 'started', 'estimated_weeks'];\n\nconst STATUS_ORDER: Record<Status, number> = {\n in_progress: 0,\n not_started: 1,\n completed: 2,\n};\n\nfunction sortMilestones(milestones: Milestone[], key: SortKey, asc: boolean): Milestone[] {\n return [...milestones].sort((a, b) => {\n let cmp = 0;\n switch (key) {\n case 'name': cmp = a.name.localeCompare(b.name); break;\n case 'status': cmp = STATUS_ORDER[a.status] - STATUS_ORDER[b.status]; break;\n case 'progress': cmp = a.progress - b.progress; break;\n case 'tasks': cmp = a.tasks_completed - b.tasks_completed; break;\n case 'started': cmp = (a.started || '').localeCompare(b.started || ''); break;\n case 'estimated_weeks': cmp = parseFloat(a.estimated_weeks || '0') - parseFloat(b.estimated_weeks || '0'); break;\n }\n return asc ? cmp : -cmp;\n });\n}\n\nexport function MilestoneTable({ milestones, filterMatch, active, onSelect }: MilestoneTableProps) {\n const [selectedIdx, setSelectedIdx] = useState(0);\n const [sortKey, setSortKey] = useState<SortKey>('status');\n const [sortAsc, setSortAsc] = useState(true);\n\n const filtered = milestones.filter((m) => filterMatch(m.status));\n const sorted = sortMilestones(filtered, sortKey, sortAsc);\n\n useInput((input, key) => {\n if (!active) return;\n\n if (input === 'j' || key.downArrow) {\n setSelectedIdx((i) => Math.min(i + 1, sorted.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setSelectedIdx((i) => Math.max(i - 1, 0));\n } else if (input === 's') {\n setSortKey((prev) => {\n const idx = SORT_KEYS.indexOf(prev);\n const next = SORT_KEYS[(idx + 1) % SORT_KEYS.length];\n if (next === prev) setSortAsc((a) => !a);\n return next;\n });\n } else if (key.return && sorted[selectedIdx] && onSelect) {\n onSelect(sorted[selectedIdx]);\n }\n });\n\n if (sorted.length === 0) {\n return <Text dimColor>No milestones match current filter.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {/* Header row */}\n <Box>\n <Text dimColor>{' '}</Text>\n <Box width={32}><Text bold dimColor>{colLabel('name', sortKey)} Name</Text></Box>\n <Box width={14}><Text bold dimColor>{colLabel('status', sortKey)} Status</Text></Box>\n <Box width={8}><Text bold dimColor>{colLabel('progress', sortKey)} Prog</Text></Box>\n <Box width={8}><Text bold dimColor>{colLabel('tasks', sortKey)} Tasks</Text></Box>\n <Box width={12}><Text bold dimColor>{colLabel('started', sortKey)} Started</Text></Box>\n <Box width={6}><Text bold dimColor>{colLabel('estimated_weeks', sortKey)} Est</Text></Box>\n </Box>\n\n {/* Separator */}\n <Text dimColor>{'─'.repeat(80)}</Text>\n\n {/* Data rows */}\n {sorted.map((m, i) => {\n const isSelected = i === selectedIdx && active;\n return (\n <Box key={m.id}>\n <Text color={isSelected ? 'cyan' : undefined} bold={isSelected}>\n {isSelected ? '> ' : ' '}\n </Text>\n <Box width={32}>\n <Text bold={isSelected} color={isSelected ? 'cyan' : undefined}>\n {truncate(m.name, 30)}\n </Text>\n </Box>\n <Box width={14}>\n {isSelected ? <Text color=\"cyan\">{statusText(m.status)}</Text> : <StatusBadge status={m.status} />}\n </Box>\n <Box width={8}>\n <Text bold={isSelected} color={isSelected ? 'cyan' : undefined}>{m.progress}%</Text>\n </Box>\n <Box width={8}>\n <Text bold={isSelected} color={isSelected ? 'cyan' : undefined}>{m.tasks_completed}/{m.tasks_total}</Text>\n </Box>\n <Box width={12}>\n <Text dimColor={!isSelected} color={isSelected ? 'cyan' : undefined}>\n {m.started ? shortDate(m.started) : '—'}\n </Text>\n </Box>\n <Box width={6}>\n <Text dimColor={!isSelected} color={isSelected ? 'cyan' : undefined}>{m.estimated_weeks}w</Text>\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n}\n\nfunction statusText(status: Status): string {\n switch (status) {\n case 'completed': return '✓ Completed';\n case 'in_progress': return '● In Progress';\n case 'not_started': return '○ Not Started';\n }\n}\n\nfunction colLabel(col: SortKey, active: SortKey): string {\n return col === active ? '▼' : ' ';\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max - 1) + '…' : s;\n}\n\nfunction shortDate(d: string): string {\n try {\n const date = new Date(d);\n return date.toISOString().slice(0, 10);\n } catch {\n return d.slice(0, 10);\n }\n}\n","import React, { useState, useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Task, Status } from '../lib/types.js';\n\ninterface TaskTreeProps {\n milestones: Milestone[];\n tasks: Record<string, Task[]>;\n filterMatch: (status: Status) => boolean;\n active: boolean;\n onSelectTask?: (task: Task) => void;\n}\n\ninterface FlatItem {\n type: 'milestone' | 'task';\n milestone: Milestone;\n task?: Task;\n}\n\nconst STATUS_DOTS: Record<Status, { dot: string; color: string }> = {\n completed: { dot: '✓', color: 'green' },\n in_progress: { dot: '●', color: 'cyan' },\n not_started: { dot: '○', color: 'gray' },\n};\n\nexport function TaskTree({ milestones, tasks, filterMatch, active, onSelectTask }: TaskTreeProps) {\n const [expanded, setExpanded] = useState<Set<string>>(() => {\n const set = new Set<string>();\n for (const m of milestones) {\n if (m.status === 'in_progress') set.add(m.id);\n }\n return set;\n });\n const [cursorIdx, setCursorIdx] = useState(0);\n\n const flatItems = useMemo(() => {\n const items: FlatItem[] = [];\n for (const m of milestones) {\n const milestoneTasks = (tasks[m.id] || []).filter((t) => filterMatch(t.status));\n if (milestoneTasks.length === 0 && !filterMatch(m.status)) continue;\n\n items.push({ type: 'milestone', milestone: m });\n if (expanded.has(m.id)) {\n for (const t of milestoneTasks) {\n items.push({ type: 'task', milestone: m, task: t });\n }\n }\n }\n return items;\n }, [milestones, tasks, filterMatch, expanded]);\n\n useInput((input, key) => {\n if (!active) return;\n\n if (input === 'j' || key.downArrow) {\n setCursorIdx((i) => Math.min(i + 1, flatItems.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setCursorIdx((i) => Math.max(i - 1, 0));\n } else if (key.return || input === ' ') {\n const item = flatItems[cursorIdx];\n if (!item) return;\n if (item.type === 'milestone') {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(item.milestone.id)) {\n next.delete(item.milestone.id);\n } else {\n next.add(item.milestone.id);\n }\n return next;\n });\n } else if (item.task && onSelectTask) {\n onSelectTask(item.task);\n }\n }\n });\n\n if (flatItems.length === 0) {\n return <Text dimColor>No items match current filter.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\">\n {flatItems.map((item, i) => {\n const isSelected = i === cursorIdx && active;\n const selColor = isSelected ? 'cyan' : undefined;\n\n if (item.type === 'milestone') {\n const m = item.milestone;\n const icon = expanded.has(m.id) ? '▼' : '►';\n const taskCount = (tasks[m.id] || []).filter((t) => filterMatch(t.status)).length;\n const { dot, color } = STATUS_DOTS[m.status];\n\n return (\n <Box key={m.id}>\n <Text color={selColor} bold={isSelected}>\n {isSelected ? '> ' : ' '}\n {icon} {m.name}\n </Text>\n <Text> </Text>\n <Text color={isSelected ? 'cyan' : color}>{dot}</Text>\n <Text dimColor={!isSelected} color={selColor}> [{m.progress}%] ({taskCount} tasks)</Text>\n </Box>\n );\n }\n\n const t = item.task!;\n const { dot, color } = STATUS_DOTS[t.status];\n return (\n <Box key={t.id}>\n <Text color={selColor} bold={isSelected}>\n {isSelected ? '> ' : ' '}\n <Text color={isSelected ? 'cyan' : color}>{dot}</Text>\n {' '}{t.name}\n </Text>\n {t.estimated_hours && <Text dimColor={!isSelected} color={selColor}> {t.estimated_hours}h</Text>}\n </Box>\n );\n })}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { WorkEntry } from '../lib/types.js';\n\ninterface ActivityLogProps {\n entries: WorkEntry[];\n}\n\nexport function ActivityLog({ entries }: ActivityLogProps) {\n if (entries.length === 0) {\n return <Text dimColor>No recent work entries.</Text>;\n }\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n {entries.map((entry, i) => (\n <Box key={i} flexDirection=\"column\">\n <Text>\n <Text bold>{entry.date}</Text>\n <Text dimColor> — {entry.description}</Text>\n </Text>\n {entry.items.map((item, j) => (\n <Text key={j} dimColor> • {item}</Text>\n ))}\n </Box>\n ))}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\ninterface BlockersNextStepsProps {\n blockers: string[];\n nextSteps: string[];\n}\n\nexport function BlockersNextSteps({ blockers, nextSteps }: BlockersNextStepsProps) {\n return (\n <Box flexDirection=\"column\" gap={1}>\n {/* Blockers */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold color={blockers.length > 0 ? 'red' : undefined}> Current Blockers</Text>\n {blockers.length === 0 ? (\n <Text dimColor> (none)</Text>\n ) : (\n blockers.map((b, i) => (\n <Text key={i} color=\"red\"> • {b}</Text>\n ))\n )}\n </Box>\n\n {/* Next Steps */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Text bold> Next Steps</Text>\n {nextSteps.length === 0 ? (\n <Text dimColor> (none)</Text>\n ) : (\n nextSteps.map((s, i) => (\n <Text key={i}> {i + 1}. {s}</Text>\n ))\n )}\n </Box>\n </Box>\n );\n}\n","import React, { useMemo, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Milestone, Task, ProgressData } from '../lib/types.js';\nimport { getBasePath, resolveMilestoneFile, loadMarkdownFile } from '../lib/markdown-loader.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { ProgressBar } from './ProgressBar.js';\nimport { Breadcrumb } from './Breadcrumb.js';\nimport { MarkdownRenderer } from './MarkdownRenderer.js';\n\ninterface MilestoneDetailProps {\n milestone: Milestone;\n tasks: Task[];\n data: ProgressData;\n filePath: string;\n active: boolean;\n onBack: () => void;\n onSelectTask?: (task: Task) => void;\n}\n\nexport function MilestoneDetail({\n milestone,\n tasks,\n filePath,\n active,\n onBack,\n onSelectTask,\n}: MilestoneDetailProps) {\n const markdownResult = useMemo(() => {\n const basePath = getBasePath(filePath);\n const resolved = resolveMilestoneFile(basePath, milestone.id);\n if (!resolved) return { error: `No milestone document found for ${milestone.id}` };\n return loadMarkdownFile(basePath, resolved);\n }, [filePath, milestone.id]);\n\n const [scrollOffset, setScrollOffset] = useState(0);\n const [taskIdx, setTaskIdx] = useState(0);\n const [focusArea, setFocusArea] = useState<'content' | 'tasks'>('content');\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape || key.backspace || key.delete) {\n onBack();\n } else if (key.tab) {\n // Toggle focus between content scroll and task list\n setFocusArea((f) => f === 'content' ? 'tasks' : 'content');\n } else if (input === 'j' || key.downArrow) {\n if (focusArea === 'content') {\n setScrollOffset((s) => s + 3);\n } else {\n setTaskIdx((i) => Math.min(i + 1, tasks.length - 1));\n }\n } else if (input === 'k' || key.upArrow) {\n if (focusArea === 'content') {\n setScrollOffset((s) => Math.max(0, s - 3));\n } else {\n setTaskIdx((i) => Math.max(i - 1, 0));\n }\n } else if (key.return && focusArea === 'tasks' && tasks[taskIdx] && onSelectTask) {\n onSelectTask(tasks[taskIdx]);\n }\n });\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Breadcrumb items={[{ label: 'Milestones' }, { label: milestone.name }]} />\n\n {/* Metadata */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <Box gap={2}>\n <StatusBadge status={milestone.status} />\n <ProgressBar percent={milestone.progress} width={15} />\n </Box>\n <Box gap={2}>\n <Text dimColor>Started: {milestone.started || '—'}</Text>\n <Text dimColor>Est: {milestone.estimated_weeks}w</Text>\n <Text dimColor>Tasks: {milestone.tasks_completed}/{milestone.tasks_total}</Text>\n </Box>\n {milestone.notes && <Text dimColor>{milestone.notes}</Text>}\n </Box>\n\n {/* Markdown */}\n {'content' in markdownResult ? (\n <Box borderStyle={focusArea === 'content' ? 'bold' : undefined}>\n <MarkdownRenderer content={markdownResult.content} scrollOffset={scrollOffset} />\n </Box>\n ) : (\n <Text dimColor>{'error' in markdownResult ? markdownResult.error : 'No content'}</Text>\n )}\n\n {/* Task list */}\n {tasks.length > 0 && (\n <Box flexDirection=\"column\" borderStyle={focusArea === 'tasks' ? 'bold' : 'single'} paddingX={1}>\n <Text bold> Tasks</Text>\n {tasks.map((t, i) => {\n const isSel = i === taskIdx && focusArea === 'tasks';\n return (\n <Text key={t.id} bold={isSel} color={isSel ? 'cyan' : undefined}>\n {isSel ? '> ' : ' '}<StatusBadge status={t.status} compact /> {t.name}\n </Text>\n );\n })}\n </Box>\n )}\n\n <Text dimColor>\n Esc:Back j/k:Scroll Tab:{focusArea === 'content' ? 'Focus tasks' : 'Focus content'} Enter:Open task\n </Text>\n </Box>\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Task } from './types.js';\n\nexport type MarkdownResult =\n | { content: string; filePath: string }\n | { error: string };\n\n/**\n * Derive project base path from progress.yaml path.\n * e.g., /home/user/project/agent/progress.yaml → /home/user/project/\n */\nexport function getBasePath(progressYamlPath: string): string {\n // Strip agent/progress.yaml to get project root\n const dir = path.dirname(progressYamlPath);\n if (path.basename(dir) === 'agent') {\n return path.dirname(dir);\n }\n return dir;\n}\n\n/**\n * Load a markdown file from the filesystem.\n */\nexport function loadMarkdownFile(basePath: string, relativePath: string): MarkdownResult {\n const fullPath = path.resolve(basePath, relativePath);\n try {\n const content = fs.readFileSync(fullPath, 'utf-8');\n return { content, filePath: relativePath };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('ENOENT')) {\n return { error: `No document found at ${relativePath}` };\n }\n if (msg.includes('EACCES')) {\n return { error: `Cannot read ${relativePath}: permission denied` };\n }\n return { error: `Error reading ${relativePath}: ${msg}` };\n }\n}\n\n/**\n * Resolve milestone file by scanning agent/milestones/ for matching filename.\n * milestone_1 → look for milestone-1-*.md (excluding templates)\n */\nexport function resolveMilestoneFile(basePath: string, milestoneId: string): string | null {\n // Extract number: milestone_1 → 1, milestone_12 → 12\n const match = milestoneId.match(/(\\d+)/);\n if (!match) return null;\n const num = match[1];\n\n const milestonesDir = path.join(basePath, 'agent', 'milestones');\n try {\n const files = fs.readdirSync(milestonesDir);\n const pattern = `milestone-${num}-`;\n const found = files.find(\n (f) => f.startsWith(pattern) && f.endsWith('.md') && !f.includes('template'),\n );\n return found ? path.join('agent', 'milestones', found) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve task file by looking up task.file in the tasks map.\n */\nexport function resolveTaskFile(\n tasks: Record<string, Task[]>,\n taskId: string,\n): string | null {\n for (const milestoneTasks of Object.values(tasks)) {\n const task = milestoneTasks.find((t) => t.id === taskId);\n if (task?.file) return task.file;\n }\n return null;\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\ninterface BreadcrumbItem {\n label: string;\n}\n\ninterface BreadcrumbProps {\n items: BreadcrumbItem[];\n}\n\nexport function Breadcrumb({ items }: BreadcrumbProps) {\n return (\n <Text>\n {items.map((item, i) => (\n <Text key={i}>\n {i < items.length - 1 ? (\n <Text dimColor>{item.label} &gt; </Text>\n ) : (\n <Text bold>{item.label}</Text>\n )}\n </Text>\n ))}\n </Text>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Text, Box, useStdout } from 'ink';\nimport { Marked } from 'marked';\nimport { markedTerminal } from 'marked-terminal';\n\ninterface MarkdownRendererProps {\n content: string;\n scrollOffset?: number;\n maxHeight?: number;\n}\n\nexport function MarkdownRenderer({ content, scrollOffset = 0, maxHeight }: MarkdownRendererProps) {\n const { stdout } = useStdout();\n const termHeight = maxHeight ?? (stdout?.rows ? stdout.rows - 12 : 30);\n\n const { visibleText, totalLines, atEnd } = useMemo(() => {\n let rendered: string;\n try {\n const marked = new Marked(markedTerminal() as unknown as Record<string, unknown>);\n rendered = (marked.parse(content) as string).trimEnd();\n } catch {\n rendered = content;\n }\n\n const lines = rendered.split('\\n');\n const total = lines.length;\n const clampedOffset = Math.max(0, Math.min(scrollOffset, Math.max(0, total - termHeight)));\n const visible = lines.slice(clampedOffset, clampedOffset + termHeight);\n return {\n visibleText: visible.join('\\n'),\n totalLines: total,\n atEnd: clampedOffset + termHeight >= total,\n };\n }, [content, scrollOffset, termHeight]);\n\n const showScrollHint = totalLines > termHeight;\n\n return (\n <Box flexDirection=\"column\">\n <Text>{visibleText}</Text>\n {showScrollHint && (\n <Text dimColor>\n {'─ '}\n Lines {scrollOffset + 1}-{Math.min(scrollOffset + termHeight, totalLines)} of {totalLines}\n {atEnd ? ' (end)' : ' (j/k to scroll)'}\n </Text>\n )}\n </Box>\n );\n}\n","import React, { useMemo, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { Task, Milestone, ProgressData } from '../lib/types.js';\nimport { getBasePath, loadMarkdownFile } from '../lib/markdown-loader.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport { Breadcrumb } from './Breadcrumb.js';\nimport { MarkdownRenderer } from './MarkdownRenderer.js';\n\ninterface TaskDetailProps {\n task: Task;\n milestone: Milestone;\n siblings: Task[];\n data: ProgressData;\n filePath: string;\n active: boolean;\n onBack: () => void;\n onNavigateSibling?: (task: Task) => void;\n}\n\nexport function TaskDetail({\n task,\n milestone,\n siblings,\n filePath,\n active,\n onBack,\n onNavigateSibling,\n}: TaskDetailProps) {\n const markdownResult = useMemo(() => {\n if (!task.file) return { error: `No file path for ${task.id}` };\n const basePath = getBasePath(filePath);\n return loadMarkdownFile(basePath, task.file);\n }, [filePath, task.file, task.id]);\n\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const siblingIdx = siblings.findIndex((t) => t.id === task.id);\n const prevTask = siblingIdx > 0 ? siblings[siblingIdx - 1] : null;\n const nextTask = siblingIdx < siblings.length - 1 ? siblings[siblingIdx + 1] : null;\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape || key.backspace || key.delete) {\n onBack();\n } else if (input === 'j' || key.downArrow) {\n setScrollOffset((s) => s + 3);\n } else if (input === 'k' || key.upArrow) {\n setScrollOffset((s) => Math.max(0, s - 3));\n } else if (input === '[' && prevTask && onNavigateSibling) {\n setScrollOffset(0);\n onNavigateSibling(prevTask);\n } else if (input === ']' && nextTask && onNavigateSibling) {\n setScrollOffset(0);\n onNavigateSibling(nextTask);\n }\n });\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Breadcrumb\n items={[\n { label: 'Milestones' },\n { label: milestone.name },\n { label: task.name },\n ]}\n />\n\n {/* Metadata */}\n <Box flexDirection=\"column\" borderStyle=\"single\" paddingX={1}>\n <StatusBadge status={task.status} />\n <Box gap={2}>\n {task.estimated_hours && <Text dimColor>Est: {task.estimated_hours}h</Text>}\n {task.completed_date && <Text dimColor>Completed: {task.completed_date}</Text>}\n </Box>\n <Text dimColor>Milestone: {milestone.name}</Text>\n {task.notes && <Text dimColor>{task.notes}</Text>}\n </Box>\n\n {/* Markdown */}\n {'content' in markdownResult ? (\n <MarkdownRenderer content={markdownResult.content} scrollOffset={scrollOffset} />\n ) : (\n <Text dimColor>{'error' in markdownResult ? markdownResult.error : 'No content'}</Text>\n )}\n\n {/* Sibling navigation */}\n <Box gap={2}>\n {prevTask ? (\n <Text dimColor>[: {prevTask.name}</Text>\n ) : (\n <Text dimColor>[: (first task)</Text>\n )}\n {nextTask ? (\n <Text dimColor>]: {nextTask.name}</Text>\n ) : (\n <Text dimColor>]: (last task)</Text>\n )}\n </Box>\n\n <Text dimColor>Esc:Back j/k:Scroll [/]:Prev/Next task</Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { SearchResult } from '../hooks/useSearch.js';\nimport { StatusBadge } from './StatusBadge.js';\nimport type { Milestone, Task } from '../lib/types.js';\n\ninterface SearchResultsProps {\n query: string;\n results: SearchResult[];\n active: boolean;\n onSelectMilestone?: (milestone: Milestone) => void;\n onSelectTask?: (task: Task) => void;\n onCancel: () => void;\n}\n\nexport function SearchResults({\n query,\n results,\n active,\n onSelectMilestone,\n onSelectTask,\n onCancel,\n}: SearchResultsProps) {\n const [selectedIdx, setSelectedIdx] = useState(0);\n\n useInput((input, key) => {\n if (!active) return;\n if (key.escape) {\n onCancel();\n return;\n }\n if (input === 'j' || key.downArrow) {\n setSelectedIdx((i) => Math.min(i + 1, results.length - 1));\n } else if (input === 'k' || key.upArrow) {\n setSelectedIdx((i) => Math.max(i - 1, 0));\n } else if (key.return && results[selectedIdx]) {\n const r = results[selectedIdx];\n if (r.type === 'milestone' && r.milestone && onSelectMilestone) {\n onSelectMilestone(r.milestone);\n } else if (r.type === 'task' && r.task && onSelectTask) {\n onSelectTask(r.task);\n }\n }\n });\n\n const milestoneResults = results.filter((r) => r.type === 'milestone');\n const taskResults = results.filter((r) => r.type === 'task');\n\n let flatIdx = 0;\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text>\n Search: <Text bold>{query}</Text>\n {query && <Text dimColor> ({results.length} results)</Text>}\n </Text>\n\n {results.length === 0 && query.trim() && (\n <Text dimColor>No results found.</Text>\n )}\n\n {milestoneResults.length > 0 && (\n <Box flexDirection=\"column\">\n <Text bold dimColor>Milestones ({milestoneResults.length})</Text>\n {milestoneResults.map((r) => {\n const idx = flatIdx++;\n const m = r.milestone!;\n return (\n <Text key={r.id} bold={idx === selectedIdx} inverse={idx === selectedIdx}>\n {' '}<StatusBadge status={m.status} compact /> {m.name}\n </Text>\n );\n })}\n </Box>\n )}\n\n {taskResults.length > 0 && (\n <Box flexDirection=\"column\">\n <Text bold dimColor>Tasks ({taskResults.length})</Text>\n {taskResults.map((r) => {\n const idx = flatIdx++;\n const t = r.task!;\n return (\n <Text key={r.id} bold={idx === selectedIdx} inverse={idx === selectedIdx}>\n {' '}<StatusBadge status={t.status} compact /> {t.name}\n </Text>\n );\n })}\n </Box>\n )}\n\n <Text dimColor>j/k:Navigate Enter:Open Esc:Cancel</Text>\n </Box>\n );\n}\n","import { useState, useMemo, useCallback } from 'react';\nimport Fuse from 'fuse.js';\nimport type { ProgressData, Milestone, Task } from '../lib/types.js';\n\nexport interface SearchResult {\n type: 'milestone' | 'task';\n milestone?: Milestone;\n task?: Task;\n name: string;\n id: string;\n}\n\nexport interface SearchState {\n query: string;\n setQuery: (q: string) => void;\n results: SearchResult[];\n isSearching: boolean;\n startSearch: () => void;\n cancelSearch: () => void;\n}\n\nexport function useSearch(data: ProgressData | null): SearchState {\n const [query, setQuery] = useState('');\n const [isSearching, setIsSearching] = useState(false);\n\n const fuse = useMemo(() => {\n if (!data) return null;\n\n const items: SearchResult[] = [];\n\n for (const m of data.milestones) {\n items.push({ type: 'milestone', milestone: m, name: m.name, id: m.id });\n }\n\n for (const [, tasks] of Object.entries(data.tasks)) {\n for (const t of tasks) {\n items.push({ type: 'task', task: t, name: t.name, id: t.id });\n }\n }\n\n return new Fuse(items, {\n keys: [\n { name: 'name', weight: 0.7 },\n { name: 'task.notes', weight: 0.2 },\n { name: 'milestone.notes', weight: 0.1 },\n ],\n threshold: 0.4,\n includeScore: true,\n });\n }, [data]);\n\n const results = useMemo(() => {\n if (!fuse || !query.trim()) return [];\n return fuse.search(query).map((r) => r.item);\n }, [fuse, query]);\n\n const startSearch = useCallback(() => {\n setIsSearching(true);\n setQuery('');\n }, []);\n\n const cancelSearch = useCallback(() => {\n setIsSearching(false);\n setQuery('');\n }, []);\n\n return { query, setQuery, results, isSearching, startSearch, cancelSearch };\n}\n"],"mappings":"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","names":["fs","path","useState","useCallback","Box","Text","useInput","filePath","fs","filePath","useState","useCallback","useState","useCallback","Box","Text","jsx","Box","Text","Text","jsx","jsxs","Text","jsx","jsxs","jsx","jsxs","Box","Text","useState","Box","Text","jsx","jsxs","useState","Text","Box","useState","Box","Text","useInput","jsx","jsxs","t","dot","color","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","useMemo","useState","Box","Text","useInput","fs","Text","jsx","jsxs","useMemo","Text","Box","jsx","jsxs","jsx","jsxs","filePath","useMemo","useState","useInput","Box","Text","useMemo","useState","Box","Text","useInput","jsx","jsxs","filePath","useMemo","useState","useInput","Box","Text","useState","Box","Text","useInput","jsx","jsxs","useState","useInput","Box","Text","useState","useMemo","useCallback","jsx","jsxs","filePath","useState","useCallback","useInput","Box","Text","jsx","path","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acp-visualizer-tui",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Terminal-based interactive visualizer for ACP progress.yaml data",
5
5
  "type": "module",
6
6
  "bin": {