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 +198 -119
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -224,7 +224,7 @@ function emptyProgressData() {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// src/app.tsx
|
|
227
|
-
import { useState as
|
|
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) =>
|
|
389
|
-
|
|
390
|
-
{
|
|
391
|
-
bold:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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:
|
|
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:
|
|
414
|
-
blockers:
|
|
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, {
|
|
598
|
-
/* @__PURE__ */ jsx6(
|
|
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:
|
|
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, {
|
|
627
|
-
/* @__PURE__ */ jsx6(
|
|
628
|
-
/* @__PURE__ */ jsx6(Box4, { width:
|
|
629
|
-
/* @__PURE__ */ jsx6(Box4, { width:
|
|
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:
|
|
639
|
-
/* @__PURE__ */ jsx6(Box4, { width: 6, children: /* @__PURE__ */ jsxs5(Text6, { dimColor:
|
|
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
|
-
|
|
723
|
-
|
|
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(
|
|
729
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
|
|
898
|
+
rendered = marked.parse(content).trimEnd();
|
|
870
899
|
} catch {
|
|
871
|
-
|
|
900
|
+
rendered = content;
|
|
872
901
|
}
|
|
873
|
-
|
|
874
|
-
|
|
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
|
|
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 [
|
|
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
|
-
|
|
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
|
-
|
|
902
|
-
|
|
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__ */
|
|
969
|
+
return /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", gap: 1, children: [
|
|
907
970
|
/* @__PURE__ */ jsx12(Breadcrumb, { items: [{ label: "Milestones" }, { label: milestone.name }] }),
|
|
908
|
-
/* @__PURE__ */
|
|
909
|
-
/* @__PURE__ */
|
|
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__ */
|
|
914
|
-
/* @__PURE__ */
|
|
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__ */
|
|
981
|
+
/* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
|
|
919
982
|
"Est: ",
|
|
920
983
|
milestone.estimated_weeks,
|
|
921
984
|
"w"
|
|
922
985
|
] }),
|
|
923
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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) =>
|
|
936
|
-
|
|
937
|
-
"
|
|
938
|
-
|
|
939
|
-
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
1065
|
+
/* @__PURE__ */ jsxs12(Box10, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [
|
|
988
1066
|
/* @__PURE__ */ jsx13(StatusBadge, { status: task.status }),
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
task.estimated_hours && /* @__PURE__ */
|
|
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__ */
|
|
1073
|
+
task.completed_date && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
|
|
996
1074
|
"Completed: ",
|
|
997
1075
|
task.completed_date
|
|
998
1076
|
] })
|
|
999
1077
|
] }),
|
|
1000
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1008
|
-
prevTask ? /* @__PURE__ */
|
|
1009
|
-
"[:
|
|
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__ */
|
|
1013
|
-
"]:
|
|
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: "
|
|
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
|
|
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
|
|
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] =
|
|
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__ */
|
|
1057
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1068
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1085
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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] =
|
|
1110
|
-
const [isSearching, setIsSearching] =
|
|
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
|
|
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] =
|
|
1156
|
-
const [detail, setDetail] =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1352
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1275
1353
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "Enter" }),
|
|
1276
1354
|
" Expand / open detail"
|
|
1277
1355
|
] }),
|
|
1278
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1279
1357
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "Backspace/Esc" }),
|
|
1280
1358
|
" Back from detail"
|
|
1281
1359
|
] }),
|
|
1282
|
-
/* @__PURE__ */
|
|
1360
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1283
1361
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "[/]" }),
|
|
1284
1362
|
" Prev/next task (in detail)"
|
|
1285
1363
|
] }),
|
|
1286
|
-
/* @__PURE__ */
|
|
1364
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1287
1365
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "s" }),
|
|
1288
1366
|
" Cycle sort (table)"
|
|
1289
1367
|
] }),
|
|
1290
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1291
1369
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "f" }),
|
|
1292
1370
|
" Cycle status filter"
|
|
1293
1371
|
] }),
|
|
1294
|
-
/* @__PURE__ */
|
|
1372
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1295
1373
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "r" }),
|
|
1296
1374
|
" Refresh data"
|
|
1297
1375
|
] }),
|
|
1298
|
-
/* @__PURE__ */
|
|
1376
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
1299
1377
|
/* @__PURE__ */ jsx15(Text15, { bold: true, children: "q" }),
|
|
1300
1378
|
" Quit"
|
|
1301
1379
|
] }),
|
|
1302
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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} > </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} > </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":";;;AACA,SAAS,cAAc;AACvB,OAAO,UAAU;AACjB,OAAOA,SAAQ;AACf,OAAOC,WAAU;;;ACJjB,OAAO,UAAU;AAajB,IAAM,eAAuC;AAAA,EAC3C,WAAW;AAAA,EACX,OAAO;AAAA,EACP,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,MAAM;AACR;AAEA,SAAS,aACP,KACA,WACwD;AACxD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AACnE,QAAM,QAAiC,CAAC;AACxC,QAAM,QAAqB,CAAC;AAC5B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,UAAM,WAAW,aAAa,GAAG,KAAK;AACtC,QAAI,UAAU,SAAS,QAAQ,GAAG;AAChC,YAAM,QAAQ,IAAI;AAAA,IACpB,OAAO;AACL,YAAM,GAAG,IAAI;AAAA,IACf;AAAA,EACF;AACA,SAAO,EAAE,OAAO,MAAM;AACxB;AAEO,SAAS,gBAAgB,OAAwB;AACtD,QAAM,IAAI,OAAO,SAAS,aAAa,EACpC,YAAY,EACZ,QAAQ,UAAU,GAAG;AACxB,MAAI,MAAM,eAAe,MAAM,UAAU,MAAM,WAAY,QAAO;AAClE,MAAI,MAAM,iBAAiB,MAAM,YAAY,MAAM,MAAO,QAAO;AACjE,SAAO;AACT;AAEA,SAAS,qBAAqB,OAA0B;AACtD,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,MAAI,OAAO,UAAU,SAAU,QAAO,CAAC,KAAK;AAC5C,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM,IAAI,MAAM;AACzB;AAEA,SAAS,WAAW,OAAgB,WAAW,IAAY;AACzD,MAAI,SAAS,KAAM,QAAO;AAC1B,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,WAAW,OAAgB,WAAW,GAAW;AACxD,QAAM,IAAI,OAAO,KAAK;AACtB,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,SAAS,iBAAiB,KAA+B;AACvD,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,QAAM,EAAE,OAAO,MAAM,IAAI,aAAa,KAAK;AAAA,IACzC;AAAA,IAAQ;AAAA,IAAW;AAAA,IAAW;AAAA,IAAU;AAAA,IAAqB;AAAA,EAC/D,CAAC;AACD,SAAO;AAAA,IACL,MAAM,WAAW,MAAM,MAAM,iBAAiB;AAAA,IAC9C,SAAS,WAAW,MAAM,SAAS,OAAO;AAAA,IAC1C,SAAS,WAAW,MAAM,OAAO;AAAA,IACjC,QAAQ,gBAAgB,MAAM,MAAM;AAAA,IACpC,mBAAmB,MAAM,oBAAoB,WAAW,MAAM,iBAAiB,IAAI;AAAA,IACnF,aAAa,WAAW,MAAM,WAAW;AAAA,IACzC;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,KAAyB;AACnD,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,QAAM,EAAE,OAAO,MAAM,IAAI,aAAa,KAAK;AAAA,IACzC;AAAA,IAAM;AAAA,IAAQ;AAAA,IAAU;AAAA,IAAY;AAAA,IAAW;AAAA,IAC/C;AAAA,IAAmB;AAAA,IAAmB;AAAA,IAAe;AAAA,EACvD,CAAC;AACD,SAAO;AAAA,IACL,IAAI,WAAW,MAAM,EAAE;AAAA,IACvB,MAAM,WAAW,MAAM,IAAI;AAAA,IAC3B,QAAQ,gBAAgB,MAAM,MAAM;AAAA,IACpC,UAAU,WAAW,MAAM,QAAQ;AAAA,IACnC,SAAS,MAAM,UAAU,WAAW,MAAM,OAAO,IAAI;AAAA,IACrD,WAAW,MAAM,YAAY,WAAW,MAAM,SAAS,IAAI;AAAA,IAC3D,iBAAiB,WAAW,MAAM,eAAe;AAAA,IACjD,iBAAiB,WAAW,MAAM,eAAe;AAAA,IACjD,aAAa,WAAW,MAAM,WAAW;AAAA,IACzC,OAAO,WAAW,MAAM,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,KAA2B;AACtD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IAAI,IAAI,kBAAkB;AACnC;AAEA,SAAS,cAAc,KAAc,aAA2B;AAC9D,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,QAAM,EAAE,OAAO,MAAM,IAAI,aAAa,KAAK;AAAA,IACzC;AAAA,IAAM;AAAA,IAAQ;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAmB;AAAA,IAAkB;AAAA,EACvE,CAAC;AACD,SAAO;AAAA,IACL,IAAI,WAAW,MAAM,EAAE;AAAA,IACvB,MAAM,WAAW,MAAM,IAAI;AAAA,IAC3B,QAAQ,gBAAgB,MAAM,MAAM;AAAA,IACpC,cAAc;AAAA,IACd,MAAM,WAAW,MAAM,IAAI;AAAA,IAC3B,iBAAiB,WAAW,MAAM,eAAe;AAAA,IACjD,gBAAgB,MAAM,iBAAiB,WAAW,MAAM,cAAc,IAAI;AAAA,IAC1E,OAAO,WAAW,MAAM,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;AAEA,SAAS,eAAe,KAAsC;AAC5D,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,CAAC;AAC7C,QAAM,SAAiC,CAAC;AACxC,aAAW,CAAC,aAAa,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACjF,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,WAAW,IAAI,MAAM,IAAI,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAAA,IACtE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAyB;AACnD,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,QAAM,EAAE,OAAO,MAAM,IAAI,aAAa,KAAK,CAAC,QAAQ,eAAe,OAAO,CAAC;AAC3E,SAAO;AAAA,IACL,MAAM,WAAW,MAAM,IAAI;AAAA,IAC3B,aAAa,WAAW,MAAM,WAAW;AAAA,IACzC,OAAO,qBAAqB,MAAM,KAAK;AAAA,IACvC;AAAA,EACF;AACF;AAEA,SAAS,qBAAqB,KAA2B;AACvD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IAAI,IAAI,kBAAkB;AACnC;AAEA,SAAS,kBAAkB,KAAkC;AAC3D,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,SAAO;AAAA,IACL,kBAAkB,WAAW,KAAK,gBAAgB;AAAA,IAClD,qBAAqB,WAAW,KAAK,mBAAmB;AAAA,IACxD,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,IACpD,gBAAgB,WAAW,KAAK,cAAc;AAAA,EAChD;AACF;AAEA,SAAS,kBAAkB,KAA+B;AACxD,QAAM,MAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AACrD,SAAO;AAAA,IACL,UAAU,WAAW,KAAK,QAAQ;AAAA,IAClC,gBAAgB,WAAW,KAAK,cAAc;AAAA,IAC9C,SAAS,WAAW,KAAK,OAAO;AAAA,EAClC;AACF;AAEO,SAAS,kBAAkB,KAA2B;AAC3D,MAAI;AACF,UAAM,MAAM,KAAK,KAAK,GAAG;AACzB,QAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,aAAa,oBAAoB,IAAI,UAAU;AACrD,UAAM,QAAQ,eAAe,IAAI,KAAK;AAGtC,eAAW,aAAa,YAAY;AAClC,YAAM,iBAAiB,MAAM,UAAU,EAAE;AACzC,UAAI,kBAAkB,eAAe,SAAS,GAAG;AAC/C,cAAM,YAAY,eAAe,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE;AACzE,cAAM,QAAQ,eAAe;AAC7B,YAAI,UAAU,gBAAgB,EAAG,WAAU,cAAc;AACzD,YAAI,UAAU,oBAAoB,EAAG,WAAU,kBAAkB;AACjE,YAAI,UAAU,aAAa,KAAK,QAAQ,GAAG;AACzC,oBAAU,WAAW,KAAK,MAAO,YAAY,QAAS,GAAG;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,iBAAiB,IAAI,OAAO;AAAA,MACrC;AAAA,MACA;AAAA,MACA,aAAa,qBAAqB,IAAI,WAAW;AAAA,MACjD,YAAY,qBAAqB,IAAI,UAAU;AAAA,MAC/C,OAAO,qBAAqB,IAAI,KAAK;AAAA,MACrC,kBAAkB,qBAAqB,IAAI,gBAAgB;AAAA,MAC3D,eAAe,kBAAkB,IAAI,aAAa;AAAA,MAClD,UAAU,kBAAkB,IAAI,QAAQ;AAAA,IAC1C;AAAA,EACF,QAAQ;AACN,WAAO,kBAAkB;AAAA,EAC3B;AACF;AAEA,SAAS,oBAAkC;AACzC,SAAO;AAAA,IACL,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,OAAO,CAAC;AAAA,IACV;AAAA,IACA,YAAY,CAAC;AAAA,IACb,OAAO,CAAC;AAAA,IACR,aAAa,CAAC;AAAA,IACd,YAAY,CAAC;AAAA,IACb,OAAO,CAAC;AAAA,IACR,kBAAkB,CAAC;AAAA,IACnB,eAAe,EAAE,kBAAkB,GAAG,qBAAqB,GAAG,mBAAmB,GAAG,gBAAgB,EAAE;AAAA,IACtG,UAAU,EAAE,UAAU,GAAG,gBAAgB,GAAG,SAAS,EAAE;AAAA,EACzD;AACF;;;ACxOA,SAAgB,YAAAC,YAAU,eAAAC,oBAAmB;AAC7C,SAAS,OAAAC,OAAK,QAAAC,QAAM,QAAQ,YAAAC,iBAAgB;;;ACD5C,SAAS,UAAU,mBAAmB;AACtC,OAAO,QAAQ;AAWR,SAAS,gBAAgBC,WAAyC;AACvE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAIvB,MAAM;AACP,QAAI;AACF,YAAM,MAAM,GAAG,aAAaA,WAAU,OAAO;AAC7C,aAAO,EAAE,MAAM,kBAAkB,GAAG,GAAG,OAAO,MAAM,SAAS,MAAM;AAAA,IACrE,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,EAAE,MAAM,MAAM,OAAO,KAAK,SAAS,MAAM;AAAA,IAClD;AAAA,EACF,CAAC;AAED,QAAM,SAAS,YAAY,MAAM;AAC/B,QAAI;AACF,YAAM,MAAM,GAAG,aAAaA,WAAU,OAAO;AAC7C,YAAM,OAAO,kBAAkB,GAAG;AAClC,eAAS,EAAE,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC;AAAA,IAChD,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,SAAS,MAAM,EAAE;AAAA,IACtE;AAAA,EACF,GAAG,CAACA,SAAQ,CAAC;AAEb,SAAO,EAAE,GAAG,OAAO,OAAO;AAC5B;;;ACvCA,SAAS,WAAW,cAAc;AAClC,OAAOC,SAAQ;AAER,SAAS,aACdC,WACA,SACA,UACM;AACN,QAAM,WAAW,OAA6C,IAAI;AAElE,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,QAAI,UAA+B;AAEnC,QAAI;AACF,gBAAUD,IAAG,MAAMC,WAAU,MAAM;AAEjC,YAAI,SAAS,QAAS,cAAa,SAAS,OAAO;AACnD,iBAAS,UAAU,WAAW,MAAM;AAClC,mBAAS;AAAA,QACX,GAAG,GAAG;AAAA,MACR,CAAC;AAED,cAAQ,GAAG,SAAS,MAAM;AAAA,MAE1B,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAEA,WAAO,MAAM;AACX,UAAI,SAAS,QAAS,cAAa,SAAS,OAAO;AACnD,UAAI,QAAS,SAAQ,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,CAACA,WAAU,SAAS,QAAQ,CAAC;AAClC;;;ACpCA,SAAS,YAAAC,WAAU,eAAAC,oBAAmB;AAItC,IAAM,aAAyB,CAAC,aAAa,cAAc,SAAS,YAAY,UAAU;AAE1F,IAAM,cAAwC;AAAA,EAC5C,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AACZ;AAcO,SAAS,cAAc,aAAuC;AACnE,QAAM,UAAU,WAAW,SAAS,WAAuB,IACtD,cACD;AAEJ,QAAM,CAAC,aAAa,cAAc,IAAID,UAAmB,OAAO;AAChE,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAqB,CAAC,CAAC;AAEzD,QAAM,WAAWC,aAAY,MAAM;AACjC,mBAAe,CAAC,SAAS;AACvB,YAAM,MAAM,WAAW,QAAQ,IAAI;AACnC,aAAO,YAAY,MAAM,KAAK,WAAW,MAAM;AAAA,IACjD,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,WAAWA,aAAY,MAAM;AACjC,mBAAe,CAAC,SAAS;AACvB,YAAM,MAAM,WAAW,QAAQ,IAAI;AACnC,aAAO,YAAY,MAAM,IAAI,WAAW,UAAU,WAAW,MAAM;AAAA,IACrE,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,WAAWA,aAAY,CAAC,SAAmB;AAC/C,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,WAAWA,aAAY,CAAC,SAAmB;AAC/C,mBAAe,CAAC,SAAS;AACvB,mBAAa,CAAC,UAAU,CAAC,GAAG,OAAO,IAAI,CAAC;AACxC,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,UAAUA,aAAY,MAAM;AAChC,iBAAa,CAAC,UAAU;AACtB,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,YAAM,WAAW,CAAC,GAAG,KAAK;AAC1B,YAAM,OAAO,SAAS,IAAI;AAC1B,qBAAe,IAAI;AACnB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AChFA,SAAS,YAAAC,WAAU,eAAAC,oBAAmB;AAKtC,IAAM,eAA8B,CAAC,OAAO,eAAe,aAAa,aAAa;AAErF,IAAM,gBAA6C;AAAA,EACjD,KAAK;AAAA,EACL,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AACf;AASO,SAAS,YAAyB;AACvC,QAAM,CAAC,QAAQ,SAAS,IAAID,UAAsB,KAAK;AAEvD,QAAM,cAAcC,aAAY,MAAM;AACpC,cAAU,CAAC,SAAS;AAClB,YAAM,MAAM,aAAa,QAAQ,IAAI;AACrC,aAAO,cAAc,MAAM,KAAK,aAAa,MAAM;AAAA,IACrD,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,UAAUA;AAAA,IACd,CAAC,WAAmB,WAAW,SAAS,WAAW;AAAA,IACnD,CAAC,MAAM;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,cAAc,MAAM;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AACF;;;ACzCA,SAAS,KAAK,YAAY;AAuBJ,SAEhB,KAFgB;AAXf,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgB;AACd,SACE,qBAAC,OAAI,eAAc,OAAM,gBAAe,iBACtC;AAAA,yBAAC,QAAK,MAAI,MACP;AAAA;AAAA,MAAY;AAAA,MAAC,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,QAAE;AAAA,SAAe;AAAA,OAChD;AAAA,IACA,oBAAC,OAAI,KAAK,GACP,gBAAM,IAAI,CAAC,SAAS;AACnB,YAAM,WAAW,SAAS;AAC1B,UAAI,UAAU;AACZ,eACE,qBAAC,QAAgB,MAAI,MAAC,OAAM,QAAO;AAAA;AAAA,UAC/B,OAAO,IAAI;AAAA,UAAE;AAAA,aADN,IAEX;AAAA,MAEJ;AACA,aACE,qBAAC,QAAgB,UAAQ,MACtB;AAAA;AAAA,QAAK,OAAO,IAAI;AAAA,QAAG;AAAA,WADX,IAEX;AAAA,IAEJ,CAAC,GACH;AAAA,IACA,qBAAC,QAAK,UAAQ,MAAC;AAAA;AAAA,MACL,oBAAC,QAAK,OAAO,gBAAgB,QAAQ,SAAS,UAAU,MAAM,gBAAgB,OAAQ,uBAAY;AAAA,OAC5G;AAAA,KACF;AAEJ;;;AC/CA,SAAS,OAAAC,MAAK,QAAAC,aAAY;AAoBpB,gBAAAC,YAAA;AAbN,IAAM,cAAc;AAEpB,IAAM,YAAsC;AAAA,EAC1C,WAAW,GAAG,WAAW;AAAA,EACzB,YAAY,uCAAuC,WAAW;AAAA,EAC9D,OAAO,oDAAoD,WAAW;AAAA,EACtE,UAAU,GAAG,WAAW;AAAA,EACxB,UAAU,GAAG,WAAW;AAC1B;AAEO,SAAS,QAAQ,EAAE,YAAY,GAAiB;AACrD,SACE,gBAAAA,KAACF,MAAA,EACC,0BAAAE,KAACD,OAAA,EAAK,UAAQ,MAAE,oBAAU,WAAW,GAAE,GACzC;AAEJ;;;ACvBA,SAAS,OAAAE,MAAK,QAAAC,aAAY;;;ACA1B,SAAS,QAAAC,aAAY;AAkBV,gBAAAC,MAIP,QAAAC,aAJO;AAVX,IAAM,gBAA+E;AAAA,EACnF,WAAW,EAAE,KAAK,UAAK,OAAO,aAAa,OAAO,QAAQ;AAAA,EAC1D,aAAa,EAAE,KAAK,UAAK,OAAO,eAAe,OAAO,OAAO;AAAA,EAC7D,aAAa,EAAE,KAAK,UAAK,OAAO,eAAe,OAAO,OAAO;AAC/D;AAEO,SAAS,YAAY,EAAE,QAAQ,QAAQ,GAAqB;AACjE,QAAM,EAAE,KAAK,OAAO,MAAM,IAAI,cAAc,MAAM;AAElD,MAAI,SAAS;AACX,WAAO,gBAAAD,KAACD,OAAA,EAAK,OAAe,eAAI;AAAA,EAClC;AAEA,SACE,gBAAAE,MAACF,OAAA,EAAK,OACH;AAAA;AAAA,IAAI;AAAA,IAAE;AAAA,KACT;AAEJ;;;AC1BA,SAAS,QAAAG,aAAY;AAmBL,SACV,OAAAC,MADU,QAAAC,aAAA;AAXT,SAAS,YAAY,EAAE,SAAS,QAAQ,IAAI,MAAM,GAAqB;AAC5E,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,OAAO,CAAC;AAClD,QAAM,SAAS,KAAK,MAAO,UAAU,MAAO,KAAK;AACjD,QAAM,QAAQ,QAAQ;AAEtB,QAAM,MAAM,SAAI,OAAO,MAAM,IAAI,SAAI,OAAO,KAAK;AAEjD,QAAM,QAAQ,WAAW,KAAK,UAAU,WAAW,KAAK,SAAS;AAEjE,SACE,gBAAAA,MAACF,OAAA,EACE;AAAA,aAAS,gBAAAE,MAACF,OAAA,EAAM;AAAA;AAAA,MAAM;AAAA,OAAC;AAAA,IACxB,gBAAAC,KAACD,OAAA,EAAK,OAAe,eAAI;AAAA,IACzB,gBAAAE,MAACF,OAAA,EAAK;AAAA;AAAA,MAAE;AAAA,MAAQ;AAAA,OAAC;AAAA,KACnB;AAEJ;;;AFFQ,gBAAAG,MAEiB,QAAAC,aAFjB;AAbD,SAAS,UAAU,EAAE,KAAK,GAAmB;AAClD,QAAM,EAAE,SAAS,YAAY,YAAY,iBAAiB,IAAI;AAE9D,QAAM,YAAY,WAAW,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE;AACrE,QAAM,aAAa,WAAW,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE;AACxE,QAAM,aAAa,WAAW,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE;AAExE,QAAM,mBAAmB,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ,iBAAiB;AAElF,SACE,gBAAAA,MAACC,MAAA,EAAI,eAAc,UAAS,KAAK,GAE/B;AAAA,oBAAAD,MAACC,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAF,KAACG,OAAA,EAAK,MAAI,MAAC,sBAAQ;AAAA,MACnB,gBAAAF,MAACE,OAAA,EACE;AAAA,gBAAQ;AAAA,QAAK;AAAA,QAAC,gBAAAF,MAACE,OAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAE,QAAQ;AAAA,WAAQ;AAAA,SAClD;AAAA,MACA,gBAAAF,MAACC,MAAA,EAAI,KAAK,GACR;AAAA,wBAAAF,KAAC,eAAY,QAAQ,QAAQ,QAAQ;AAAA,QACrC,gBAAAC,MAACE,OAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAU,QAAQ,WAAW;AAAA,WAAM;AAAA,SACpD;AAAA,MACA,gBAAAH,KAAC,eAAY,SAAS,KAAK,SAAS,SAAS,OAAM,aAAY;AAAA,MAC9D,oBACC,gBAAAC,MAACE,OAAA,EAAK;AAAA;AAAA,QACK,gBAAAH,KAACG,OAAA,EAAK,MAAI,MAAE,2BAAiB,MAAK;AAAA,SAC7C;AAAA,OAEJ;AAAA,IAGA,gBAAAF,MAACC,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAF,KAACG,OAAA,EAAK,MAAI,MAAC,yBAAW;AAAA,MACtB,gBAAAF,MAACC,MAAA,EAAI,KAAK,GACR;AAAA,wBAAAD,MAACE,OAAA,EAAK,OAAM,SAAQ;AAAA;AAAA,UAAc;AAAA,WAAU;AAAA,QAC5C,gBAAAF,MAACE,OAAA,EAAK,OAAM,QAAO;AAAA;AAAA,UAAgB;AAAA,WAAW;AAAA,QAC9C,gBAAAF,MAACE,OAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAgB;AAAA,WAAW;AAAA,SAC5C;AAAA,OACF;AAAA,IAGC,iBAAiB,SAAS,KACzB,gBAAAF,MAACC,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAF,KAACG,OAAA,EAAK,MAAI,MAAC,OAAM,OAAM,uBAAS;AAAA,MAC/B,iBAAiB,IAAI,CAAC,GAAG,MACxB,gBAAAF,MAACE,OAAA,EAAa,OAAM,OAAM;AAAA;AAAA,QAAK;AAAA,WAApB,CAAsB,CAClC;AAAA,OACH;AAAA,IAID,WAAW,SAAS,KACnB,gBAAAF,MAACC,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAF,KAACG,OAAA,EAAK,MAAI,MAAC,yBAAW;AAAA,MACrB,WAAW,IAAI,CAAC,MAAM,MACrB,gBAAAF,MAACE,OAAA,EAAa;AAAA;AAAA,QAAG,IAAI;AAAA,QAAE;AAAA,QAAG;AAAA,WAAf,CAAoB,CAChC;AAAA,OACH;AAAA,KAEJ;AAEJ;;;AGtEA,SAAgB,YAAAC,iBAAgB;AAChC,SAAS,OAAAC,MAAK,QAAAC,OAAM,gBAAgB;AAgEzB,gBAAAC,MAQa,QAAAC,aARb;AAnDX,IAAM,YAAuB,CAAC,QAAQ,UAAU,YAAY,SAAS,WAAW,iBAAiB;AAEjG,IAAM,eAAuC;AAAA,EAC3C,aAAa;AAAA,EACb,aAAa;AAAA,EACb,WAAW;AACb;AAEA,SAAS,eAAe,YAAyB,KAAc,KAA2B;AACxF,SAAO,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM;AACpC,QAAI,MAAM;AACV,YAAQ,KAAK;AAAA,MACX,KAAK;AAAQ,cAAM,EAAE,KAAK,cAAc,EAAE,IAAI;AAAG;AAAA,MACjD,KAAK;AAAU,cAAM,aAAa,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM;AAAG;AAAA,MACtE,KAAK;AAAY,cAAM,EAAE,WAAW,EAAE;AAAU;AAAA,MAChD,KAAK;AAAS,cAAM,EAAE,kBAAkB,EAAE;AAAiB;AAAA,MAC3D,KAAK;AAAW,eAAO,EAAE,WAAW,IAAI,cAAc,EAAE,WAAW,EAAE;AAAG;AAAA,MACxE,KAAK;AAAmB,cAAM,WAAW,EAAE,mBAAmB,GAAG,IAAI,WAAW,EAAE,mBAAmB,GAAG;AAAG;AAAA,IAC7G;AACA,WAAO,MAAM,MAAM,CAAC;AAAA,EACtB,CAAC;AACH;AAEO,SAAS,eAAe,EAAE,YAAY,aAAa,QAAQ,SAAS,GAAwB;AACjG,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAS,CAAC;AAChD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAkB,QAAQ;AACxD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,IAAI;AAE3C,QAAM,WAAW,WAAW,OAAO,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC;AAC/D,QAAM,SAAS,eAAe,UAAU,SAAS,OAAO;AAExD,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,CAAC,OAAQ;AAEb,QAAI,UAAU,OAAO,IAAI,WAAW;AAClC,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,OAAO,SAAS,CAAC,CAAC;AAAA,IAC1D,WAAW,UAAU,OAAO,IAAI,SAAS;AACvC,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IAC1C,WAAW,UAAU,KAAK;AACxB,iBAAW,CAAC,SAAS;AACnB,cAAM,MAAM,UAAU,QAAQ,IAAI;AAClC,cAAM,OAAO,WAAW,MAAM,KAAK,UAAU,MAAM;AACnD,YAAI,SAAS,KAAM,YAAW,CAAC,MAAM,CAAC,CAAC;AACvC,eAAO;AAAA,MACT,CAAC;AAAA,IACH,WAAW,IAAI,UAAU,OAAO,WAAW,KAAK,UAAU;AACxD,eAAS,OAAO,WAAW,CAAC;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,gBAAAF,KAACG,OAAA,EAAK,UAAQ,MAAC,iDAAmC;AAAA,EAC3D;AAEA,SACE,gBAAAF,MAACG,MAAA,EAAI,eAAc,UAEjB;AAAA,oBAAAH,MAACG,MAAA,EACC;AAAA,sBAAAJ,KAACG,OAAA,EAAK,UAAQ,MAAE,gBAAK;AAAA,MACrB,gBAAAH,KAACI,MAAA,EAAI,OAAO,IAAI,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,QAAQ,OAAO;AAAA,QAAE;AAAA,SAAK,GAAO;AAAA,MAC3E,gBAAAH,KAACI,MAAA,EAAI,OAAO,IAAI,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,UAAU,OAAO;AAAA,QAAE;AAAA,SAAO,GAAO;AAAA,MAC/E,gBAAAH,KAACI,MAAA,EAAI,OAAO,GAAG,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,YAAY,OAAO;AAAA,QAAE;AAAA,SAAK,GAAO;AAAA,MAC9E,gBAAAH,KAACI,MAAA,EAAI,OAAO,GAAG,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,SAAS,OAAO;AAAA,QAAE;AAAA,SAAM,GAAO;AAAA,MAC5E,gBAAAH,KAACI,MAAA,EAAI,OAAO,IAAI,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,WAAW,OAAO;AAAA,QAAE;AAAA,SAAQ,GAAO;AAAA,MACjF,gBAAAH,KAACI,MAAA,EAAI,OAAO,GAAG,0BAAAH,MAACE,OAAA,EAAK,MAAI,MAAC,UAAQ,MAAE;AAAA,iBAAS,mBAAmB,OAAO;AAAA,QAAE;AAAA,SAAI,GAAO;AAAA,OACtF;AAAA,IAGA,gBAAAH,KAACG,OAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,IAG9B,OAAO,IAAI,CAAC,GAAG,MAAM;AACpB,YAAM,aAAa,MAAM,eAAe;AACxC,aACE,gBAAAF,MAACG,MAAA,EACC;AAAA,wBAAAJ,KAACG,OAAA,EAAK,OAAO,aAAa,SAAS,QAAW,MAAM,YACjD,uBAAa,OAAO,MACvB;AAAA,QACA,gBAAAH,KAACI,MAAA,EAAI,OAAO,IACV,0BAAAJ,KAACG,OAAA,EAAK,MAAM,YAAY,OAAO,aAAa,SAAS,QAClD,mBAAS,EAAE,MAAM,EAAE,GACtB,GACF;AAAA,QACA,gBAAAH,KAACI,MAAA,EAAI,OAAO,IACT,uBAAa,gBAAAJ,KAACG,OAAA,EAAK,OAAM,QAAQ,qBAAW,EAAE,MAAM,GAAE,IAAU,gBAAAH,KAAC,eAAY,QAAQ,EAAE,QAAQ,GAClG;AAAA,QACA,gBAAAA,KAACI,MAAA,EAAI,OAAO,GACV,0BAAAH,MAACE,OAAA,EAAK,MAAM,YAAY,OAAO,aAAa,SAAS,QAAY;AAAA,YAAE;AAAA,UAAS;AAAA,WAAC,GAC/E;AAAA,QACA,gBAAAH,KAACI,MAAA,EAAI,OAAO,GACV,0BAAAH,MAACE,OAAA,EAAK,MAAM,YAAY,OAAO,aAAa,SAAS,QAAY;AAAA,YAAE;AAAA,UAAgB;AAAA,UAAE,EAAE;AAAA,WAAY,GACrG;AAAA,QACA,gBAAAH,KAACI,MAAA,EAAI,OAAO,IACV,0BAAAJ,KAACG,OAAA,EAAK,UAAU,CAAC,YAAY,OAAO,aAAa,SAAS,QACvD,YAAE,UAAU,UAAU,EAAE,OAAO,IAAI,UACtC,GACF;AAAA,QACA,gBAAAH,KAACI,MAAA,EAAI,OAAO,GACV,0BAAAH,MAACE,OAAA,EAAK,UAAU,CAAC,YAAY,OAAO,aAAa,SAAS,QAAY;AAAA,YAAE;AAAA,UAAgB;AAAA,WAAC,GAC3F;AAAA,WAzBQ,EAAE,EA0BZ;AAAA,IAEJ,CAAC;AAAA,KACH;AAEJ;AAEA,SAAS,WAAW,QAAwB;AAC1C,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAe,aAAO;AAAA,IAC3B,KAAK;AAAe,aAAO;AAAA,EAC7B;AACF;AAEA,SAAS,SAAS,KAAc,QAAyB;AACvD,SAAO,QAAQ,SAAS,WAAM;AAChC;AAEA,SAAS,SAAS,GAAW,KAAqB;AAChD,SAAO,EAAE,SAAS,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,WAAM;AACtD;AAEA,SAAS,UAAU,GAAmB;AACpC,MAAI;AACF,UAAM,OAAO,IAAI,KAAK,CAAC;AACvB,WAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AAAA,EACvC,QAAQ;AACN,WAAO,EAAE,MAAM,GAAG,EAAE;AAAA,EACtB;AACF;;;AChJA,SAAgB,YAAAE,WAAU,eAAe;AACzC,SAAS,OAAAC,MAAK,QAAAC,OAAM,YAAAC,iBAAgB;AA4EzB,gBAAAC,MAiBG,QAAAC,aAjBH;AA3DX,IAAM,cAA8D;AAAA,EAClE,WAAW,EAAE,KAAK,UAAK,OAAO,QAAQ;AAAA,EACtC,aAAa,EAAE,KAAK,UAAK,OAAO,OAAO;AAAA,EACvC,aAAa,EAAE,KAAK,UAAK,OAAO,OAAO;AACzC;AAEO,SAAS,SAAS,EAAE,YAAY,OAAO,aAAa,QAAQ,aAAa,GAAkB;AAChG,QAAM,CAAC,UAAU,WAAW,IAAIL,UAAsB,MAAM;AAC1D,UAAM,MAAM,oBAAI,IAAY;AAC5B,eAAW,KAAK,YAAY;AAC1B,UAAI,EAAE,WAAW,cAAe,KAAI,IAAI,EAAE,EAAE;AAAA,IAC9C;AACA,WAAO;AAAA,EACT,CAAC;AACD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,CAAC;AAE5C,QAAM,YAAY,QAAQ,MAAM;AAC9B,UAAM,QAAoB,CAAC;AAC3B,eAAW,KAAK,YAAY;AAC1B,YAAM,kBAAkB,MAAM,EAAE,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC;AAC9E,UAAI,eAAe,WAAW,KAAK,CAAC,YAAY,EAAE,MAAM,EAAG;AAE3D,YAAM,KAAK,EAAE,MAAM,aAAa,WAAW,EAAE,CAAC;AAC9C,UAAI,SAAS,IAAI,EAAE,EAAE,GAAG;AACtB,mBAAW,KAAK,gBAAgB;AAC9B,gBAAM,KAAK,EAAE,MAAM,QAAQ,WAAW,GAAG,MAAM,EAAE,CAAC;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,OAAO,aAAa,QAAQ,CAAC;AAE7C,EAAAG,UAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,CAAC,OAAQ;AAEb,QAAI,UAAU,OAAO,IAAI,WAAW;AAClC,mBAAa,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,UAAU,SAAS,CAAC,CAAC;AAAA,IAC3D,WAAW,UAAU,OAAO,IAAI,SAAS;AACvC,mBAAa,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IACxC,WAAW,IAAI,UAAU,UAAU,KAAK;AACtC,YAAM,OAAO,UAAU,SAAS;AAChC,UAAI,CAAC,KAAM;AACX,UAAI,KAAK,SAAS,aAAa;AAC7B,oBAAY,CAAC,SAAS;AACpB,gBAAM,OAAO,IAAI,IAAI,IAAI;AACzB,cAAI,KAAK,IAAI,KAAK,UAAU,EAAE,GAAG;AAC/B,iBAAK,OAAO,KAAK,UAAU,EAAE;AAAA,UAC/B,OAAO;AACL,iBAAK,IAAI,KAAK,UAAU,EAAE;AAAA,UAC5B;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH,WAAW,KAAK,QAAQ,cAAc;AACpC,qBAAa,KAAK,IAAI;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,gBAAAC,KAACF,OAAA,EAAK,UAAQ,MAAC,4CAA8B;AAAA,EACtD;AAEA,SACE,gBAAAE,KAACH,MAAA,EAAI,eAAc,UAChB,oBAAU,IAAI,CAAC,MAAM,MAAM;AAC1B,UAAM,aAAa,MAAM,aAAa;AACtC,UAAM,WAAW,aAAa,SAAS;AAEvC,QAAI,KAAK,SAAS,aAAa;AAC7B,YAAM,IAAI,KAAK;AACf,YAAM,OAAO,SAAS,IAAI,EAAE,EAAE,IAAI,WAAM;AACxC,YAAM,aAAa,MAAM,EAAE,EAAE,KAAK,CAAC,GAAG,OAAO,CAACK,OAAM,YAAYA,GAAE,MAAM,CAAC,EAAE;AAC3E,YAAM,EAAE,KAAAC,MAAK,OAAAC,OAAM,IAAI,YAAY,EAAE,MAAM;AAE3C,aACE,gBAAAH,MAACJ,MAAA,EACC;AAAA,wBAAAI,MAACH,OAAA,EAAK,OAAO,UAAU,MAAM,YAC1B;AAAA,uBAAa,OAAO;AAAA,UACpB;AAAA,UAAK;AAAA,UAAE,EAAE;AAAA,WACZ;AAAA,QACA,gBAAAE,KAACF,OAAA,EAAK,eAAC;AAAA,QACP,gBAAAE,KAACF,OAAA,EAAK,OAAO,aAAa,SAASM,QAAQ,UAAAD,MAAI;AAAA,QAC/C,gBAAAF,MAACH,OAAA,EAAK,UAAU,CAAC,YAAY,OAAO,UAAU;AAAA;AAAA,UAAG,EAAE;AAAA,UAAS;AAAA,UAAK;AAAA,UAAU;AAAA,WAAO;AAAA,WAP1E,EAAE,EAQZ;AAAA,IAEJ;AAEA,UAAM,IAAI,KAAK;AACf,UAAM,EAAE,KAAK,MAAM,IAAI,YAAY,EAAE,MAAM;AAC3C,WACE,gBAAAG,MAACJ,MAAA,EACC;AAAA,sBAAAI,MAACH,OAAA,EAAK,OAAO,UAAU,MAAM,YAC1B;AAAA,qBAAa,WAAW;AAAA,QACzB,gBAAAE,KAACF,OAAA,EAAK,OAAO,aAAa,SAAS,OAAQ,eAAI;AAAA,QAC9C;AAAA,QAAK,EAAE;AAAA,SACV;AAAA,MACC,EAAE,mBAAmB,gBAAAG,MAACH,OAAA,EAAK,UAAU,CAAC,YAAY,OAAO,UAAU;AAAA;AAAA,QAAE,EAAE;AAAA,QAAgB;AAAA,SAAC;AAAA,SANjF,EAAE,EAOZ;AAAA,EAEJ,CAAC,GACH;AAEJ;;;ACvHA,SAAS,OAAAO,MAAK,QAAAC,aAAY;AASf,gBAAAC,MASC,QAAAC,aATD;AAFJ,SAAS,YAAY,EAAE,QAAQ,GAAqB;AACzD,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,gBAAAD,KAACD,OAAA,EAAK,UAAQ,MAAC,qCAAuB;AAAA,EAC/C;AAEA,SACE,gBAAAC,KAACF,MAAA,EAAI,eAAc,UAAS,KAAK,GAC9B,kBAAQ,IAAI,CAAC,OAAO,MACnB,gBAAAG,MAACH,MAAA,EAAY,eAAc,UACzB;AAAA,oBAAAG,MAACF,OAAA,EACC;AAAA,sBAAAC,KAACD,OAAA,EAAK,MAAI,MAAE,gBAAM,MAAK;AAAA,MACvB,gBAAAE,MAACF,OAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,QAAI,MAAM;AAAA,SAAY;AAAA,OACvC;AAAA,IACC,MAAM,MAAM,IAAI,CAAC,MAAM,MACtB,gBAAAE,MAACF,OAAA,EAAa,UAAQ,MAAC;AAAA;AAAA,MAAK;AAAA,SAAjB,CAAsB,CAClC;AAAA,OAPO,CAQV,CACD,GACH;AAEJ;;;AC3BA,SAAS,OAAAG,MAAK,QAAAC,aAAY;AAYlB,gBAAAC,MAKI,QAAAC,aALJ;AALD,SAAS,kBAAkB,EAAE,UAAU,UAAU,GAA2B;AACjF,SACE,gBAAAA,MAACH,MAAA,EAAI,eAAc,UAAS,KAAK,GAE/B;AAAA,oBAAAG,MAACH,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAE,KAACD,OAAA,EAAK,MAAI,MAAC,OAAO,SAAS,SAAS,IAAI,QAAQ,QAAW,+BAAiB;AAAA,MAC3E,SAAS,WAAW,IACnB,gBAAAC,KAACD,OAAA,EAAK,UAAQ,MAAC,sBAAQ,IAEvB,SAAS,IAAI,CAAC,GAAG,MACf,gBAAAE,MAACF,OAAA,EAAa,OAAM,OAAM;AAAA;AAAA,QAAK;AAAA,WAApB,CAAsB,CAClC;AAAA,OAEL;AAAA,IAGA,gBAAAE,MAACH,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAE,KAACD,OAAA,EAAK,MAAI,MAAC,yBAAW;AAAA,MACrB,UAAU,WAAW,IACpB,gBAAAC,KAACD,OAAA,EAAK,UAAQ,MAAC,sBAAQ,IAEvB,UAAU,IAAI,CAAC,GAAG,MAChB,gBAAAE,MAACF,OAAA,EAAa;AAAA;AAAA,QAAG,IAAI;AAAA,QAAE;AAAA,QAAG;AAAA,WAAf,CAAiB,CAC7B;AAAA,OAEL;AAAA,KACF;AAEJ;;;ACpCA,SAAgB,WAAAG,UAAS,YAAAC,iBAAgB;AACzC,SAAS,OAAAC,MAAK,QAAAC,QAAM,YAAAC,iBAAgB;;;ACDpC,OAAOC,SAAQ;AACf,OAAO,UAAU;AAWV,SAAS,YAAY,kBAAkC;AAE5D,QAAM,MAAM,KAAK,QAAQ,gBAAgB;AACzC,MAAI,KAAK,SAAS,GAAG,MAAM,SAAS;AAClC,WAAO,KAAK,QAAQ,GAAG;AAAA,EACzB;AACA,SAAO;AACT;AAKO,SAAS,iBAAiB,UAAkB,cAAsC;AACvF,QAAM,WAAW,KAAK,QAAQ,UAAU,YAAY;AACpD,MAAI;AACF,UAAM,UAAUA,IAAG,aAAa,UAAU,OAAO;AACjD,WAAO,EAAE,SAAS,UAAU,aAAa;AAAA,EAC3C,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,QAAI,IAAI,SAAS,QAAQ,GAAG;AAC1B,aAAO,EAAE,OAAO,wBAAwB,YAAY,GAAG;AAAA,IACzD;AACA,QAAI,IAAI,SAAS,QAAQ,GAAG;AAC1B,aAAO,EAAE,OAAO,eAAe,YAAY,sBAAsB;AAAA,IACnE;AACA,WAAO,EAAE,OAAO,iBAAiB,YAAY,KAAK,GAAG,GAAG;AAAA,EAC1D;AACF;AAMO,SAAS,qBAAqB,UAAkB,aAAoC;AAEzF,QAAM,QAAQ,YAAY,MAAM,OAAO;AACvC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,MAAM,CAAC;AAEnB,QAAM,gBAAgB,KAAK,KAAK,UAAU,SAAS,YAAY;AAC/D,MAAI;AACF,UAAM,QAAQA,IAAG,YAAY,aAAa;AAC1C,UAAM,UAAU,aAAa,GAAG;AAChC,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,MAAM,EAAE,WAAW,OAAO,KAAK,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU;AAAA,IAC7E;AACA,WAAO,QAAQ,KAAK,KAAK,SAAS,cAAc,KAAK,IAAI;AAAA,EAC3D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC7DA,SAAS,QAAAC,cAAY;AAgBT,SAEA,OAAAC,OAFA,QAAAC,aAAA;AANL,SAAS,WAAW,EAAE,MAAM,GAAoB;AACrD,SACE,gBAAAD,MAACD,QAAA,EACE,gBAAM,IAAI,CAAC,MAAM,MAChB,gBAAAC,MAACD,QAAA,EACE,cAAI,MAAM,SAAS,IAClB,gBAAAE,MAACF,QAAA,EAAK,UAAQ,MAAE;AAAA,SAAK;AAAA,IAAM;AAAA,KAAM,IAEjC,gBAAAC,MAACD,QAAA,EAAK,MAAI,MAAE,eAAK,OAAM,KAJhB,CAMX,CACD,GACH;AAEJ;;;ACzBA,SAAgB,WAAAG,gBAAe;AAC/B,SAAS,QAAAC,QAAM,OAAAC,MAAK,iBAAiB;AACrC,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAoCzB,gBAAAC,OAEE,QAAAC,cAFF;AA5BC,SAAS,iBAAiB,EAAE,SAAS,eAAe,GAAG,UAAU,GAA0B;AAChG,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,QAAM,aAAa,cAAc,QAAQ,OAAO,OAAO,OAAO,KAAK;AAEnE,QAAM,EAAE,aAAa,YAAY,MAAM,IAAIJ,SAAQ,MAAM;AACvD,QAAI;AACJ,QAAI;AACF,YAAM,SAAS,IAAI,OAAO,eAAe,CAAuC;AAChF,iBAAY,OAAO,MAAM,OAAO,EAAa,QAAQ;AAAA,IACvD,QAAQ;AACN,iBAAW;AAAA,IACb;AAEA,UAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,UAAM,QAAQ,MAAM;AACpB,UAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,cAAc,KAAK,IAAI,GAAG,QAAQ,UAAU,CAAC,CAAC;AACzF,UAAM,UAAU,MAAM,MAAM,eAAe,gBAAgB,UAAU;AACrE,WAAO;AAAA,MACL,aAAa,QAAQ,KAAK,IAAI;AAAA,MAC9B,YAAY;AAAA,MACZ,OAAO,gBAAgB,cAAc;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,SAAS,cAAc,UAAU,CAAC;AAEtC,QAAM,iBAAiB,aAAa;AAEpC,SACE,gBAAAI,OAACF,MAAA,EAAI,eAAc,UACjB;AAAA,oBAAAC,MAACF,QAAA,EAAM,uBAAY;AAAA,IAClB,kBACC,gBAAAG,OAACH,QAAA,EAAK,UAAQ,MACX;AAAA;AAAA,MAAK;AAAA,MACC,eAAe;AAAA,MAAE;AAAA,MAAE,KAAK,IAAI,eAAe,YAAY,UAAU;AAAA,MAAE;AAAA,MAAK;AAAA,MAC9E,QAAQ,WAAW;AAAA,OACtB;AAAA,KAEJ;AAEJ;;;AHeM,gBAAAI,OAIE,QAAAC,cAJF;AA7CC,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,iBAAiBC,SAAQ,MAAM;AACnC,UAAM,WAAW,YAAYD,SAAQ;AACrC,UAAM,WAAW,qBAAqB,UAAU,UAAU,EAAE;AAC5D,QAAI,CAAC,SAAU,QAAO,EAAE,OAAO,mCAAmC,UAAU,EAAE,GAAG;AACjF,WAAO,iBAAiB,UAAU,QAAQ;AAAA,EAC5C,GAAG,CAACA,WAAU,UAAU,EAAE,CAAC;AAE3B,QAAM,CAAC,cAAc,eAAe,IAAIE,UAAS,CAAC;AAClD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,CAAC;AACxC,QAAM,CAAC,WAAW,YAAY,IAAIA,UAA8B,SAAS;AAEzE,EAAAC,UAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,CAAC,OAAQ;AACb,QAAI,IAAI,UAAU,IAAI,aAAa,IAAI,QAAQ;AAC7C,aAAO;AAAA,IACT,WAAW,IAAI,KAAK;AAElB,mBAAa,CAAC,MAAM,MAAM,YAAY,UAAU,SAAS;AAAA,IAC3D,WAAW,UAAU,OAAO,IAAI,WAAW;AACzC,UAAI,cAAc,WAAW;AAC3B,wBAAgB,CAAC,MAAM,IAAI,CAAC;AAAA,MAC9B,OAAO;AACL,mBAAW,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,MAAM,SAAS,CAAC,CAAC;AAAA,MACrD;AAAA,IACF,WAAW,UAAU,OAAO,IAAI,SAAS;AACvC,UAAI,cAAc,WAAW;AAC3B,wBAAgB,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,MAC3C,OAAO;AACL,mBAAW,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,MACtC;AAAA,IACF,WAAW,IAAI,UAAU,cAAc,WAAW,MAAM,OAAO,KAAK,cAAc;AAChF,mBAAa,MAAM,OAAO,CAAC;AAAA,IAC7B;AAAA,EACF,CAAC;AAED,SACE,gBAAAJ,OAACK,MAAA,EAAI,eAAc,UAAS,KAAK,GAC/B;AAAA,oBAAAN,MAAC,cAAW,OAAO,CAAC,EAAE,OAAO,aAAa,GAAG,EAAE,OAAO,UAAU,KAAK,CAAC,GAAG;AAAA,IAGzE,gBAAAC,OAACK,MAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAL,OAACK,MAAA,EAAI,KAAK,GACR;AAAA,wBAAAN,MAAC,eAAY,QAAQ,UAAU,QAAQ;AAAA,QACvC,gBAAAA,MAAC,eAAY,SAAS,UAAU,UAAU,OAAO,IAAI;AAAA,SACvD;AAAA,MACA,gBAAAC,OAACK,MAAA,EAAI,KAAK,GACR;AAAA,wBAAAL,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAU,UAAU,WAAW;AAAA,WAAI;AAAA,QAClD,gBAAAN,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAM,UAAU;AAAA,UAAgB;AAAA,WAAC;AAAA,QAChD,gBAAAN,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAQ,UAAU;AAAA,UAAgB;AAAA,UAAE,UAAU;AAAA,WAAY;AAAA,SAC3E;AAAA,MACC,UAAU,SAAS,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAE,oBAAU,OAAM;AAAA,OACtD;AAAA,IAGC,aAAa,iBACZ,gBAAAP,MAACM,MAAA,EAAI,aAAa,cAAc,YAAY,SAAS,QACnD,0BAAAN,MAAC,oBAAiB,SAAS,eAAe,SAAS,cAA4B,GACjF,IAEA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,qBAAW,iBAAiB,eAAe,QAAQ,cAAa;AAAA,IAIjF,MAAM,SAAS,KACd,gBAAAN,OAACK,MAAA,EAAI,eAAc,UAAS,aAAa,cAAc,UAAU,SAAS,UAAU,UAAU,GAC5F;AAAA,sBAAAN,MAACO,QAAA,EAAK,MAAI,MAAC,oBAAM;AAAA,MAChB,MAAM,IAAI,CAAC,GAAG,MAAM;AACnB,cAAM,QAAQ,MAAM,WAAW,cAAc;AAC7C,eACE,gBAAAN,OAACM,QAAA,EAAgB,MAAM,OAAO,OAAO,QAAQ,SAAS,QACnD;AAAA,kBAAQ,OAAO;AAAA,UAAK,gBAAAP,MAAC,eAAY,QAAQ,EAAE,QAAQ,SAAO,MAAC;AAAA,UAAE;AAAA,UAAE,EAAE;AAAA,aADzD,EAAE,EAEb;AAAA,MAEJ,CAAC;AAAA,OACH;AAAA,IAGF,gBAAAC,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,MACc,cAAc,YAAY,gBAAgB;AAAA,MAAgB;AAAA,OACvF;AAAA,KACF;AAEJ;;;AI7GA,SAAgB,WAAAC,UAAS,YAAAC,iBAAgB;AACzC,SAAS,OAAAC,OAAK,QAAAC,QAAM,YAAAC,iBAAgB;AA0D9B,gBAAAC,OAY6B,QAAAC,cAZ7B;AAxCC,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,iBAAiBC,SAAQ,MAAM;AACnC,QAAI,CAAC,KAAK,KAAM,QAAO,EAAE,OAAO,oBAAoB,KAAK,EAAE,GAAG;AAC9D,UAAM,WAAW,YAAYD,SAAQ;AACrC,WAAO,iBAAiB,UAAU,KAAK,IAAI;AAAA,EAC7C,GAAG,CAACA,WAAU,KAAK,MAAM,KAAK,EAAE,CAAC;AAEjC,QAAM,CAAC,cAAc,eAAe,IAAIE,UAAS,CAAC;AAElD,QAAM,aAAa,SAAS,UAAU,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AAC7D,QAAM,WAAW,aAAa,IAAI,SAAS,aAAa,CAAC,IAAI;AAC7D,QAAM,WAAW,aAAa,SAAS,SAAS,IAAI,SAAS,aAAa,CAAC,IAAI;AAE/E,EAAAC,UAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,CAAC,OAAQ;AACb,QAAI,IAAI,UAAU,IAAI,aAAa,IAAI,QAAQ;AAC7C,aAAO;AAAA,IACT,WAAW,UAAU,OAAO,IAAI,WAAW;AACzC,sBAAgB,CAAC,MAAM,IAAI,CAAC;AAAA,IAC9B,WAAW,UAAU,OAAO,IAAI,SAAS;AACvC,sBAAgB,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,IAC3C,WAAW,UAAU,OAAO,YAAY,mBAAmB;AACzD,sBAAgB,CAAC;AACjB,wBAAkB,QAAQ;AAAA,IAC5B,WAAW,UAAU,OAAO,YAAY,mBAAmB;AACzD,sBAAgB,CAAC;AACjB,wBAAkB,QAAQ;AAAA,IAC5B;AAAA,EACF,CAAC;AAED,SACE,gBAAAJ,OAACK,OAAA,EAAI,eAAc,UAAS,KAAK,GAC/B;AAAA,oBAAAN;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,EAAE,OAAO,aAAa;AAAA,UACtB,EAAE,OAAO,UAAU,KAAK;AAAA,UACxB,EAAE,OAAO,KAAK,KAAK;AAAA,QACrB;AAAA;AAAA,IACF;AAAA,IAGA,gBAAAC,OAACK,OAAA,EAAI,eAAc,UAAS,aAAY,UAAS,UAAU,GACzD;AAAA,sBAAAN,MAAC,eAAY,QAAQ,KAAK,QAAQ;AAAA,MAClC,gBAAAC,OAACK,OAAA,EAAI,KAAK,GACP;AAAA,aAAK,mBAAmB,gBAAAL,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAM,KAAK;AAAA,UAAgB;AAAA,WAAC;AAAA,QACnE,KAAK,kBAAkB,gBAAAN,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,UAAY,KAAK;AAAA,WAAe;AAAA,SACzE;AAAA,MACA,gBAAAN,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,QAAY,UAAU;AAAA,SAAK;AAAA,MACzC,KAAK,SAAS,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAE,eAAK,OAAM;AAAA,OAC5C;AAAA,IAGC,aAAa,iBACZ,gBAAAP,MAAC,oBAAiB,SAAS,eAAe,SAAS,cAA4B,IAE/E,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,qBAAW,iBAAiB,eAAe,QAAQ,cAAa;AAAA,IAIlF,gBAAAN,OAACK,OAAA,EAAI,KAAK,GACP;AAAA,iBACC,gBAAAL,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,QAAI,SAAS;AAAA,SAAK,IAEjC,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAC,6BAAe;AAAA,MAE/B,WACC,gBAAAN,OAACM,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,QAAI,SAAS;AAAA,SAAK,IAEjC,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAC,4BAAc;AAAA,OAEjC;AAAA,IAEA,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAC,sDAAwC;AAAA,KACzD;AAEJ;;;ACtGA,SAAgB,YAAAC,iBAAgB;AAChC,SAAS,OAAAC,OAAK,QAAAC,QAAM,YAAAC,iBAAgB;AAoDpB,gBAAAC,OACE,QAAAC,cADF;AAtCT,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAS,CAAC;AAEhD,EAAAC,UAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,CAAC,OAAQ;AACb,QAAI,IAAI,QAAQ;AACd,eAAS;AACT;AAAA,IACF;AACA,QAAI,UAAU,OAAO,IAAI,WAAW;AAClC,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,QAAQ,SAAS,CAAC,CAAC;AAAA,IAC3D,WAAW,UAAU,OAAO,IAAI,SAAS;AACvC,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IAC1C,WAAW,IAAI,UAAU,QAAQ,WAAW,GAAG;AAC7C,YAAM,IAAI,QAAQ,WAAW;AAC7B,UAAI,EAAE,SAAS,eAAe,EAAE,aAAa,mBAAmB;AAC9D,0BAAkB,EAAE,SAAS;AAAA,MAC/B,WAAW,EAAE,SAAS,UAAU,EAAE,QAAQ,cAAc;AACtD,qBAAa,EAAE,IAAI;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,mBAAmB,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AACrE,QAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAE3D,MAAI,UAAU;AAEd,SACE,gBAAAF,OAACG,OAAA,EAAI,eAAc,UAAS,KAAK,GAC/B;AAAA,oBAAAH,OAACI,QAAA,EAAK;AAAA;AAAA,MACI,gBAAAL,MAACK,QAAA,EAAK,MAAI,MAAE,iBAAM;AAAA,MACzB,SAAS,gBAAAJ,OAACI,QAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,QAAG,QAAQ;AAAA,QAAO;AAAA,SAAS;AAAA,OACtD;AAAA,IAEC,QAAQ,WAAW,KAAK,MAAM,KAAK,KAClC,gBAAAL,MAACK,QAAA,EAAK,UAAQ,MAAC,+BAAiB;AAAA,IAGjC,iBAAiB,SAAS,KACzB,gBAAAJ,OAACG,OAAA,EAAI,eAAc,UACjB;AAAA,sBAAAH,OAACI,QAAA,EAAK,MAAI,MAAC,UAAQ,MAAC;AAAA;AAAA,QAAa,iBAAiB;AAAA,QAAO;AAAA,SAAC;AAAA,MACzD,iBAAiB,IAAI,CAAC,MAAM;AAC3B,cAAM,MAAM;AACZ,cAAM,IAAI,EAAE;AACZ,eACE,gBAAAJ,OAACI,QAAA,EAAgB,MAAM,QAAQ,aAAa,SAAS,QAAQ,aAC1D;AAAA;AAAA,UAAK,gBAAAL,MAAC,eAAY,QAAQ,EAAE,QAAQ,SAAO,MAAC;AAAA,UAAE;AAAA,UAAE,EAAE;AAAA,aAD1C,EAAE,EAEb;AAAA,MAEJ,CAAC;AAAA,OACH;AAAA,IAGD,YAAY,SAAS,KACpB,gBAAAC,OAACG,OAAA,EAAI,eAAc,UACjB;AAAA,sBAAAH,OAACI,QAAA,EAAK,MAAI,MAAC,UAAQ,MAAC;AAAA;AAAA,QAAQ,YAAY;AAAA,QAAO;AAAA,SAAC;AAAA,MAC/C,YAAY,IAAI,CAAC,MAAM;AACtB,cAAM,MAAM;AACZ,cAAM,IAAI,EAAE;AACZ,eACE,gBAAAJ,OAACI,QAAA,EAAgB,MAAM,QAAQ,aAAa,SAAS,QAAQ,aAC1D;AAAA;AAAA,UAAK,gBAAAL,MAAC,eAAY,QAAQ,EAAE,QAAQ,SAAO,MAAC;AAAA,UAAE;AAAA,UAAE,EAAE;AAAA,aAD1C,EAAE,EAEb;AAAA,MAEJ,CAAC;AAAA,OACH;AAAA,IAGF,gBAAAA,MAACK,QAAA,EAAK,UAAQ,MAAC,kDAAoC;AAAA,KACrD;AAEJ;;;AC9FA,SAAS,YAAAC,WAAU,WAAAC,UAAS,eAAAC,oBAAmB;AAC/C,OAAO,UAAU;AAoBV,SAAS,UAAU,MAAwC;AAChE,QAAM,CAAC,OAAO,QAAQ,IAAIF,UAAS,EAAE;AACrC,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AAEpD,QAAM,OAAOC,SAAQ,MAAM;AACzB,QAAI,CAAC,KAAM,QAAO;AAElB,UAAM,QAAwB,CAAC;AAE/B,eAAW,KAAK,KAAK,YAAY;AAC/B,YAAM,KAAK,EAAE,MAAM,aAAa,WAAW,GAAG,MAAM,EAAE,MAAM,IAAI,EAAE,GAAG,CAAC;AAAA,IACxE;AAEA,eAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AAClD,iBAAW,KAAK,OAAO;AACrB,cAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,EAAE,GAAG,CAAC;AAAA,MAC9D;AAAA,IACF;AAEA,WAAO,IAAI,KAAK,OAAO;AAAA,MACrB,MAAM;AAAA,QACJ,EAAE,MAAM,QAAQ,QAAQ,IAAI;AAAA,QAC5B,EAAE,MAAM,cAAc,QAAQ,IAAI;AAAA,QAClC,EAAE,MAAM,mBAAmB,QAAQ,IAAI;AAAA,MACzC;AAAA,MACA,WAAW;AAAA,MACX,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,UAAUA,SAAQ,MAAM;AAC5B,QAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,EAAG,QAAO,CAAC;AACpC,WAAO,KAAK,OAAO,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EAC7C,GAAG,CAAC,MAAM,KAAK,CAAC;AAEhB,QAAM,cAAcC,aAAY,MAAM;AACpC,mBAAe,IAAI;AACnB,aAAS,EAAE;AAAA,EACb,GAAG,CAAC,CAAC;AAEL,QAAM,eAAeA,aAAY,MAAM;AACrC,mBAAe,KAAK;AACpB,aAAS,EAAE;AAAA,EACb,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,OAAO,UAAU,SAAS,aAAa,aAAa,aAAa;AAC5E;;;ApBkDM,gBAAAC,OACE,QAAAC,cADF;AAvFS,SAAR,IAAqB,EAAE,UAAAC,WAAU,OAAO,YAAY,GAAa;AACtE,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,gBAAgBA,SAAQ;AACxD,eAAaA,WAAU,OAAO,MAAM;AACpC,QAAM,MAAM,cAAc,WAAW;AACrC,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,KAAK,IAAI,OAAO;AACxB,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAS,KAAK;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAsB,EAAE,MAAM,OAAO,CAAC;AAClE,QAAM,SAAS,UAAU,IAAI;AAE7B,QAAM,sBAAsBC,aAAY,CAAC,cAAyB;AAChE,cAAU,EAAE,MAAM,aAAa,UAAU,CAAC;AAAA,EAC5C,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiBA,aAAY,CAAC,SAAe;AACjD,QAAI,CAAC,KAAM;AAEX,UAAM,YAAY,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,YAAY;AACxE,QAAI,WAAW;AACb,gBAAU,EAAE,MAAM,QAAQ,MAAM,UAAU,CAAC;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,cAAcA,aAAY,MAAM;AACpC,cAAU,CAAC,SAAS;AAElB,UAAI,KAAK,SAAS,QAAQ;AACxB,eAAO,EAAE,MAAM,aAAa,WAAW,KAAK,UAAU;AAAA,MACxD;AACA,aAAO,EAAE,MAAM,OAAO;AAAA,IACxB,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAwBA,aAAY,CAAC,SAAe;AACxD,QAAI,CAAC,KAAM;AACX,UAAM,YAAY,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,YAAY;AACxE,QAAI,WAAW;AACb,gBAAU,EAAE,MAAM,QAAQ,MAAM,UAAU,CAAC;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAGT,EAAAC,UAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,UAAU;AACZ,kBAAY,KAAK;AACjB;AAAA,IACF;AAGA,QAAI,OAAO,aAAa;AACtB,UAAI,IAAI,QAAQ;AAAE,eAAO,aAAa;AAAG;AAAA,MAAQ;AACjD,UAAI,IAAI,aAAa,IAAI,QAAQ;AAC/B,eAAO,SAAS,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC;AACzC;AAAA,MACF;AAEA,UAAI,OAAO,UAAU,UAAU,OAAO,UAAU,OAAO,IAAI,UAAU,IAAI,aAAa,IAAI,UAAU;AAClG;AAAA,MACF;AACA,UAAI,SAAS,CAAC,IAAI,QAAQ,CAAC,IAAI,QAAQ,MAAM,WAAW,KAAK,UAAU,KAAK;AAC1E,eAAO,SAAS,OAAO,QAAQ,KAAK;AACpC;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,OAAO,SAAS,QAAQ;AAC1B,UAAI,UAAU,KAAK;AAAE,aAAK;AAAG;AAAA,MAAQ;AACrC,UAAI,UAAU,KAAK;AAAE,oBAAY,IAAI;AAAG;AAAA,MAAQ;AAChD,UAAI,UAAU,KAAK;AAAE,eAAO;AAAG;AAAA,MAAQ;AACvC;AAAA,IACF;AAEA,QAAI,UAAU,KAAK;AAAE,WAAK;AAAG;AAAA,IAAQ;AACrC,QAAI,UAAU,KAAK;AAAE,kBAAY,IAAI;AAAG;AAAA,IAAQ;AAChD,QAAI,UAAU,KAAK;AAAE,aAAO,YAAY;AAAG;AAAA,IAAQ;AACnD,QAAI,UAAU,KAAK;AAAE,aAAO;AAAG;AAAA,IAAQ;AACvC,QAAI,UAAU,KAAK;AAAE,aAAO,YAAY;AAAG;AAAA,IAAQ;AACnD,QAAI,IAAI,KAAK;AACX,UAAI,IAAI,OAAO;AAAE,YAAI,SAAS;AAAA,MAAG,OAC5B;AAAE,YAAI,SAAS;AAAA,MAAG;AAAA,IACzB;AAAA,EACF,CAAC;AAED,MAAI,SAAS,CAAC,MAAM;AAClB,WACE,gBAAAL,MAACM,OAAA,EAAI,eAAc,UAAS,SAAS,GACnC,0BAAAL,OAACM,QAAA,EAAK,OAAM,OAAM;AAAA;AAAA,MAAQ;AAAA,OAAM,GAClC;AAAA,EAEJ;AAEA,MAAI,CAAC,MAAM;AACT,WACE,gBAAAP,MAACM,OAAA,EAAI,eAAc,UAAS,SAAS,GACnC,0BAAAN,MAACO,QAAA,EAAK,UAAQ,MAAC,wBAAU,GAC3B;AAAA,EAEJ;AAGA,MAAI,UAAU;AACZ,WACE,gBAAAN,OAACK,OAAA,EAAI,eAAc,UAAS,SAAS,GACnC;AAAA,sBAAAN,MAACO,QAAA,EAAK,MAAI,MAAC,gCAAkB;AAAA,MAC7B,gBAAAP,MAACO,QAAA,EAAK;AAAA,MACN,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,QAAG,gBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,uBAAS;AAAA,QAAO;AAAA,SAAc;AAAA,MACvE,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,QAAI,gBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,2BAAG;AAAA,QAAO;AAAA,SAAe;AAAA,MACnE,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,mBAAK;AAAA,QAAO;AAAA,SAAkC;AAAA,MAC/D,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,2BAAa;AAAA,QAAO;AAAA,SAAsB;AAAA,MAC3D,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,iBAAG;AAAA,QAAO;AAAA,SAA0C;AAAA,MACrE,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,eAAC;AAAA,QAAO;AAAA,SAAoC;AAAA,MAC7D,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,eAAC;AAAA,QAAO;AAAA,SAAqC;AAAA,MAC9D,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,eAAC;AAAA,QAAO;AAAA,SAA8B;AAAA,MACvD,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,eAAC;AAAA,QAAO;AAAA,SAAsB;AAAA,MAC/C,gBAAAN,OAACM,QAAA,EAAK;AAAA,wBAAAP,MAACO,QAAA,EAAK,MAAI,MAAC,eAAC;AAAA,QAAO;AAAA,SAAkC;AAAA,MAC3D,gBAAAP,MAACO,QAAA,EAAK;AAAA,MACN,gBAAAP,MAACO,QAAA,EAAK,UAAQ,MAAC,sCAAwB;AAAA,OACzC;AAAA,EAEJ;AAGA,MAAI,OAAO,aAAa;AACtB,WACE,gBAAAN,OAACK,OAAA,EAAI,eAAc,UACjB;AAAA,sBAAAN;AAAA,QAAC;AAAA;AAAA,UACC,aAAa,KAAK,QAAQ;AAAA,UAC1B,gBAAgB,KAAK,QAAQ;AAAA,UAC7B,aAAa,IAAI;AAAA,UACjB,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,aAAa,OAAO;AAAA;AAAA,MACtB;AAAA,MACA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,MAC/B,gBAAAP,MAACM,OAAA,EAAI,eAAc,UAAS,UAAU,GAAG,UAAU,GACjD,0BAAAN;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO;AAAA,UACd,SAAS,OAAO;AAAA,UAChB,QAAQ;AAAA,UACR,mBAAmB,CAAC,MAAM;AAAE,mBAAO,aAAa;AAAG,gCAAoB,CAAC;AAAA,UAAG;AAAA,UAC3E,cAAc,CAAC,MAAM;AAAE,mBAAO,aAAa;AAAG,2BAAe,CAAC;AAAA,UAAG;AAAA,UACjE,UAAU,OAAO;AAAA;AAAA,MACnB,GACF;AAAA,OACF;AAAA,EAEJ;AAGA,MAAI,OAAO,SAAS,aAAa;AAC/B,UAAM,iBAAiB,KAAK,MAAM,OAAO,UAAU,EAAE,KAAK,CAAC;AAC3D,WACE,gBAAAC,OAACK,OAAA,EAAI,eAAc,UACjB;AAAA,sBAAAN;AAAA,QAAC;AAAA;AAAA,UACC,aAAa,KAAK,QAAQ;AAAA,UAC1B,gBAAgB,KAAK,QAAQ;AAAA,UAC7B,aAAa,IAAI;AAAA,UACjB,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,aAAa,OAAO;AAAA;AAAA,MACtB;AAAA,MACA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,MAC/B,gBAAAP,MAACM,OAAA,EAAI,eAAc,UAAS,UAAU,GAAG,UAAU,GACjD,0BAAAN;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,OAAO;AAAA,UACP;AAAA,UACA,UAAUE;AAAA,UACV,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,cAAc;AAAA;AAAA,MAChB,GACF;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,OAAO,SAAS,QAAQ;AAC1B,UAAM,WAAW,KAAK,MAAM,OAAO,UAAU,EAAE,KAAK,CAAC;AACrD,WACE,gBAAAD,OAACK,OAAA,EAAI,eAAc,UACjB;AAAA,sBAAAN;AAAA,QAAC;AAAA;AAAA,UACC,aAAa,KAAK,QAAQ;AAAA,UAC1B,gBAAgB,KAAK,QAAQ;AAAA,UAC7B,aAAa,IAAI;AAAA,UACjB,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,aAAa,OAAO;AAAA;AAAA,MACtB;AAAA,MACA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,MAC/B,gBAAAP,MAACM,OAAA,EAAI,eAAc,UAAS,UAAU,GAAG,UAAU,GACjD,0BAAAN;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,OAAO;AAAA,UACb,WAAW,OAAO;AAAA,UAClB;AAAA,UACA;AAAA,UACA,UAAUE;AAAA,UACV,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,mBAAmB;AAAA;AAAA,MACrB,GACF;AAAA,OACF;AAAA,EAEJ;AAGA,SACE,gBAAAD,OAACK,OAAA,EAAI,eAAc,UACjB;AAAA,oBAAAN;AAAA,MAAC;AAAA;AAAA,QACC,aAAa,KAAK,QAAQ;AAAA,QAC1B,gBAAgB,KAAK,QAAQ;AAAA,QAC7B,aAAa,IAAI;AAAA,QACjB,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,aAAa,OAAO;AAAA;AAAA,IACtB;AAAA,IACA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,IAC/B,gBAAAN,OAACK,OAAA,EAAI,eAAc,UAAS,UAAU,GAAG,UAAU,GAChD;AAAA,UAAI,gBAAgB,eACnB,gBAAAN,MAAC,aAAU,MAAY;AAAA,MAExB,IAAI,gBAAgB,gBACnB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,YAAY,KAAK;AAAA,UACjB,aAAa,OAAO;AAAA,UACpB,QAAQ;AAAA,UACR,UAAU;AAAA;AAAA,MACZ;AAAA,MAED,IAAI,gBAAgB,WACnB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,YAAY,KAAK;AAAA,UACjB,OAAO,KAAK;AAAA,UACZ,aAAa,OAAO;AAAA,UACpB,QAAQ;AAAA,UACR,cAAc;AAAA;AAAA,MAChB;AAAA,MAED,IAAI,gBAAgB,cACnB,gBAAAA,MAAC,eAAY,SAAS,KAAK,aAAa;AAAA,MAEzC,IAAI,gBAAgB,cACnB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,KAAK;AAAA,UACf,WAAW,KAAK;AAAA;AAAA,MAClB;AAAA,OAEJ;AAAA,IACA,gBAAAA,MAACO,QAAA,EAAK,UAAQ,MAAE,mBAAI,OAAO,EAAE,GAAE;AAAA,IAC/B,gBAAAP,MAAC,WAAQ,aAAa,IAAI,aAAa;AAAA,KACzC;AAEJ;;;AFhOE,gBAAAQ,aAAA;AArDF,IAAM,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAcd;AAAA,EACD,YAAY;AAAA,EACZ,OAAO;AAAA,IACL,OAAO,EAAE,MAAM,WAAW,WAAW,KAAK,SAAS,MAAM;AAAA,IACzD,MAAM,EAAE,MAAM,UAAU,WAAW,KAAK,SAAS,YAAY;AAAA,IAC7D,MAAM,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,EAC1C;AACF,CAAC;AAED,IAAM,WAAW,IAAI,MAAM,CAAC,KAAK;AACjC,IAAM,eAAeC,MAAK,QAAQ,QAAQ;AAG1C,IAAI,CAACC,IAAG,WAAW,YAAY,GAAG;AAChC,UAAQ,MAAM,0BAA0B,YAAY,EAAE;AACtD,UAAQ,MAAM;AAAA,sDAAyD;AACvE,UAAQ,MAAM,qCAAqC;AACnD,UAAQ,KAAK,CAAC;AAChB;AAGA,IAAI,IAAI,MAAM,MAAM;AAClB,MAAI;AACF,UAAM,MAAMA,IAAG,aAAa,cAAc,OAAO;AACjD,UAAM,OAAO,kBAAkB,GAAG;AAClC,YAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,EAC3C,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAQ,MAAM,uBAAuB,GAAG,EAAE;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,KAAK,CAAC;AAChB;AAGA,QAAQ,OAAO,MAAM,eAAe;AAGpC;AAAA,EACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,OAAO,IAAI,MAAM;AAAA,MACjB,aAAa,IAAI,MAAM;AAAA;AAAA,EACzB;AACF;","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"]}
|