@tomkapa/tayto 0.7.0 → 0.8.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.
@@ -1,21 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ APP_VERSION,
3
4
  DependencyType,
4
5
  TaskLevel,
5
6
  TaskStatus,
6
7
  TaskType,
7
8
  UIDependencyType,
9
+ define_CHANGELOG_ENTRIES_default,
8
10
  detectGitRemote,
11
+ isNewerVersion,
9
12
  isTerminalStatus,
10
13
  logger
11
- } from "./chunk-5V4TBQ5S.js";
14
+ } from "./chunk-6ZNCVCAS.js";
12
15
 
13
16
  // src/tui/index.tsx
14
17
  import { render } from "ink";
15
18
 
16
19
  // src/tui/components/App.tsx
17
- import { useReducer, useEffect as useEffect4, useCallback as useCallback2, useMemo as useMemo2, useState as useState7, useRef as useRef5 } from "react";
18
- import { Box as Box19, Text as Text19, useInput as useInput7, useApp, useStdout as useStdout4 } from "ink";
20
+ import { useReducer, useEffect as useEffect5, useCallback as useCallback2, useMemo as useMemo3, useState as useState8, useRef as useRef5 } from "react";
21
+ import { Box as Box21, Text as Text21, useInput as useInput7, useApp, useStdout as useStdout4 } from "ink";
19
22
 
20
23
  // src/tui/types.ts
21
24
  var ViewType = {
@@ -181,7 +184,10 @@ var initialState = {
181
184
  editingProject: null,
182
185
  isEpicReordering: false,
183
186
  epicReorderSnapshot: null,
184
- detectedGitRemote: null
187
+ detectedGitRemote: null,
188
+ changelogEntries: null,
189
+ changelogIndex: 0,
190
+ changelogDialogOpen: false
185
191
  };
186
192
  function appReducer(state, action) {
187
193
  switch (action.type) {
@@ -393,11 +399,25 @@ function appReducer(state, action) {
393
399
  return { ...state, editingProject: action.project };
394
400
  case "SET_DETECTED_GIT_REMOTE":
395
401
  return { ...state, detectedGitRemote: action.remote };
402
+ case "SET_CHANGELOG":
403
+ return { ...state, changelogEntries: action.entries, changelogIndex: 0 };
404
+ case "CHANGELOG_NAVIGATE": {
405
+ if (!state.changelogEntries) return state;
406
+ const max = Math.max(0, state.changelogEntries.length - 1);
407
+ const newIdx = action.direction === "up" ? Math.max(0, state.changelogIndex - 1) : Math.min(max, state.changelogIndex + 1);
408
+ return { ...state, changelogIndex: newIdx };
409
+ }
410
+ case "DISMISS_CHANGELOG":
411
+ return { ...state, changelogEntries: null, changelogIndex: 0, changelogDialogOpen: false };
412
+ case "OPEN_CHANGELOG_DIALOG":
413
+ return { ...state, changelogDialogOpen: true, changelogIndex: 0 };
414
+ case "CLOSE_CHANGELOG_DIALOG":
415
+ return { ...state, changelogDialogOpen: false };
396
416
  }
397
417
  }
398
418
 
399
419
  // src/tui/components/Header.tsx
400
- import { Box as Box2, Text as Text2 } from "ink";
420
+ import { Box as Box3, Text as Text3 } from "ink";
401
421
 
402
422
  // src/tui/components/Logo.tsx
403
423
  import React from "react";
@@ -432,10 +452,71 @@ var Logo = React.memo(function Logo2() {
432
452
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines });
433
453
  });
434
454
 
435
- // src/tui/components/Header.tsx
455
+ // src/tui/components/ChangelogTicker.tsx
456
+ import { useState, useEffect, useMemo } from "react";
457
+ import { Box as Box2, Text as Text2 } from "ink";
436
458
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
459
+ var INTERVAL_MS = 4e3;
460
+ var WIDTH = 98;
461
+ function ChangelogTicker({ entries }) {
462
+ const items = useMemo(
463
+ () => entries.flatMap(
464
+ (entry) => entry.sections.flatMap(
465
+ (section) => section.items.map((item) => ({
466
+ version: entry.version,
467
+ section: section.heading,
468
+ text: item
469
+ }))
470
+ )
471
+ ),
472
+ [entries]
473
+ );
474
+ const [index, setIndex] = useState(0);
475
+ useEffect(() => {
476
+ if (items.length <= 1) return;
477
+ const timer = setInterval(() => {
478
+ setIndex((i) => (i + 1) % items.length);
479
+ }, INTERVAL_MS);
480
+ return () => {
481
+ clearInterval(timer);
482
+ };
483
+ }, [items.length]);
484
+ const current = items[index % Math.max(1, items.length)];
485
+ if (!current) return null;
486
+ return /* @__PURE__ */ jsxs(
487
+ Box2,
488
+ {
489
+ borderStyle: "bold",
490
+ borderColor: theme.border,
491
+ paddingX: 2,
492
+ width: WIDTH,
493
+ flexShrink: 0,
494
+ flexDirection: "column",
495
+ children: [
496
+ /* @__PURE__ */ jsxs(Box2, { gap: 1, children: [
497
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dialog.label, bold: true, children: `v${current.version}` }),
498
+ /* @__PURE__ */ jsx2(Text2, { color: theme.border, children: "\xB7" }),
499
+ /* @__PURE__ */ jsx2(Text2, { color: theme.table.headerFg, children: current.section })
500
+ ] }),
501
+ /* @__PURE__ */ jsxs(Box2, { flexDirection: "row", gap: 1, children: [
502
+ /* @__PURE__ */ jsx2(Box2, { flexGrow: 1, children: /* @__PURE__ */ jsx2(Text2, { color: theme.fg, wrap: "truncate", children: current.text }) }),
503
+ /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(Text2, { color: theme.menu.key, bold: true, children: "<W>" }) })
504
+ ] })
505
+ ]
506
+ }
507
+ );
508
+ }
509
+
510
+ // src/tui/components/Header.tsx
511
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
437
512
  function getKeyHints(state) {
438
513
  const { activeView, isSearchActive, isReordering, isEpicReordering, isAddingDep, focusedPanel } = state;
514
+ if (state.changelogDialogOpen) {
515
+ return [
516
+ { key: "\u2191/\u2193", desc: "navigate" },
517
+ { key: "esc", desc: "close" }
518
+ ];
519
+ }
439
520
  if (isAddingDep) {
440
521
  return [
441
522
  { key: "type", desc: "search" },
@@ -566,40 +647,47 @@ function Header({ state, latestVersion }) {
566
647
  const hints = getKeyHints(state);
567
648
  const hintCols = hints.length <= 7 ? 2 : hints.length <= 12 ? 3 : 4;
568
649
  const columns = chunkHints(hints, hintCols);
569
- return /* @__PURE__ */ jsxs(Box2, { flexDirection: "row", gap: 1, children: [
570
- /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(Logo, {}) }),
571
- /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", justifyContent: "center", flexShrink: 0, paddingLeft: 1, children: [
572
- /* @__PURE__ */ jsx2(Text2, { color: theme.logo, bold: true, children: "tayto" }),
573
- /* @__PURE__ */ jsxs(Box2, { gap: 1, children: [
574
- /* @__PURE__ */ jsx2(Text2, { color: theme.fg, children: "Project:" }),
575
- /* @__PURE__ */ jsx2(Text2, { color: theme.titleCounter, bold: true, children: projectName })
650
+ const hasTicker = state.changelogEntries !== null;
651
+ return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "row", gap: 1, children: [
652
+ /* @__PURE__ */ jsx3(Box3, { flexShrink: 0, children: /* @__PURE__ */ jsx3(Logo, {}) }),
653
+ /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", justifyContent: "center", flexShrink: 0, paddingLeft: 1, children: [
654
+ /* @__PURE__ */ jsx3(Text3, { color: theme.logo, bold: true, children: "tayto" }),
655
+ /* @__PURE__ */ jsxs2(Box3, { gap: 1, children: [
656
+ /* @__PURE__ */ jsx3(Text3, { color: theme.fg, children: "Project:" }),
657
+ /* @__PURE__ */ jsx3(Text3, { color: theme.titleCounter, bold: true, children: projectName })
576
658
  ] }),
577
- /* @__PURE__ */ jsxs(Box2, { gap: 1, children: [
578
- /* @__PURE__ */ jsx2(Text2, { color: theme.fg, children: "Tasks:" }),
579
- /* @__PURE__ */ jsx2(Text2, { color: theme.titleCounter, bold: true, children: taskCount })
659
+ /* @__PURE__ */ jsxs2(Box3, { gap: 1, children: [
660
+ /* @__PURE__ */ jsx3(Text3, { color: theme.fg, children: "Tasks:" }),
661
+ /* @__PURE__ */ jsx3(Text3, { color: theme.titleCounter, bold: true, children: taskCount })
580
662
  ] }),
581
- latestVersion && /* @__PURE__ */ jsxs(Box2, { gap: 1, children: [
582
- /* @__PURE__ */ jsxs(Text2, { color: theme.flash.warn, children: [
663
+ latestVersion && /* @__PURE__ */ jsxs2(Box3, { gap: 1, children: [
664
+ /* @__PURE__ */ jsxs2(Text3, { color: theme.flash.warn, children: [
583
665
  "Update ",
584
666
  latestVersion
585
667
  ] }),
586
- /* @__PURE__ */ jsx2(Text2, { color: theme.fg, children: "\u2014 tayto upgrade" })
668
+ /* @__PURE__ */ jsx3(Text3, { color: theme.fg, children: "\u2014 tayto upgrade" })
587
669
  ] })
588
670
  ] }),
589
- /* @__PURE__ */ jsx2(Box2, { flexGrow: 1, justifyContent: "flex-end", children: /* @__PURE__ */ jsx2(Box2, { flexDirection: "row", gap: 2, children: columns.map((col, ci) => /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: col.map((h) => /* @__PURE__ */ jsxs(Box2, { children: [
590
- /* @__PURE__ */ jsxs(Text2, { color: theme.menu.key, bold: true, children: [
591
- "<",
592
- h.key,
593
- ">"
594
- ] }),
595
- /* @__PURE__ */ jsx2(Text2, { color: theme.menu.desc, children: h.desc })
596
- ] }, h.key)) }, col[0]?.key ?? String(ci))) }) })
671
+ hasTicker && state.changelogEntries ? /* @__PURE__ */ jsxs2(Fragment, { children: [
672
+ /* @__PURE__ */ jsx3(Box3, { flexGrow: 1, justifyContent: "center", children: /* @__PURE__ */ jsx3(ChangelogTicker, { entries: state.changelogEntries }) }),
673
+ /* @__PURE__ */ jsx3(Box3, { flexShrink: 0, children: /* @__PURE__ */ jsx3(HintGrid, { columns }) })
674
+ ] }) : /* @__PURE__ */ jsx3(Box3, { flexGrow: 1, justifyContent: "flex-end", children: /* @__PURE__ */ jsx3(HintGrid, { columns }) })
597
675
  ] });
598
676
  }
677
+ function HintGrid({ columns }) {
678
+ return /* @__PURE__ */ jsx3(Box3, { flexDirection: "row", gap: 2, children: columns.map((col, ci) => /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: col.map((h) => /* @__PURE__ */ jsxs2(Box3, { children: [
679
+ /* @__PURE__ */ jsxs2(Text3, { color: theme.menu.key, bold: true, children: [
680
+ "<",
681
+ h.key,
682
+ ">"
683
+ ] }),
684
+ /* @__PURE__ */ jsx3(Text3, { color: theme.menu.desc, children: h.desc })
685
+ ] }, h.key)) }, col[0]?.key ?? String(ci))) });
686
+ }
599
687
 
600
688
  // src/tui/components/Crumbs.tsx
601
- import { Box as Box3, Text as Text3 } from "ink";
602
- import { jsx as jsx3 } from "react/jsx-runtime";
689
+ import { Box as Box4, Text as Text4 } from "ink";
690
+ import { jsx as jsx4 } from "react/jsx-runtime";
603
691
  var VIEW_LABELS = {
604
692
  "task-list": "tasks",
605
693
  "task-detail": "detail",
@@ -609,11 +697,11 @@ var VIEW_LABELS = {
609
697
  help: "help"
610
698
  };
611
699
  function Crumbs({ breadcrumbs }) {
612
- return /* @__PURE__ */ jsx3(Box3, { flexDirection: "row", gap: 0, width: "100%", children: breadcrumbs.map((crumb, i) => {
700
+ return /* @__PURE__ */ jsx4(Box4, { flexDirection: "row", gap: 0, width: "100%", children: breadcrumbs.map((crumb, i) => {
613
701
  const isActive = i === breadcrumbs.length - 1;
614
702
  const label = ` ${VIEW_LABELS[crumb] ?? crumb} `;
615
- return /* @__PURE__ */ jsx3(
616
- Text3,
703
+ return /* @__PURE__ */ jsx4(
704
+ Text4,
617
705
  {
618
706
  color: theme.crumb.fg,
619
707
  backgroundColor: isActive ? theme.crumb.activeBg : theme.crumb.bg,
@@ -626,20 +714,20 @@ function Crumbs({ breadcrumbs }) {
626
714
  }
627
715
 
628
716
  // src/tui/components/FlashMessage.tsx
629
- import { Box as Box4, Text as Text4 } from "ink";
630
- import { jsx as jsx4 } from "react/jsx-runtime";
717
+ import { Box as Box5, Text as Text5 } from "ink";
718
+ import { jsx as jsx5 } from "react/jsx-runtime";
631
719
  var LEVEL_COLOR = {
632
720
  info: theme.flash.info,
633
721
  warn: theme.flash.warn,
634
722
  error: theme.flash.error
635
723
  };
636
724
  function FlashMessage({ message, level }) {
637
- return /* @__PURE__ */ jsx4(Box4, { justifyContent: "center", width: "100%", children: /* @__PURE__ */ jsx4(Text4, { color: LEVEL_COLOR[level], bold: level === "error", children: message }) });
725
+ return /* @__PURE__ */ jsx5(Box5, { justifyContent: "center", width: "100%", children: /* @__PURE__ */ jsx5(Text5, { color: LEVEL_COLOR[level], bold: level === "error", children: message }) });
638
726
  }
639
727
 
640
728
  // src/tui/components/TaskList.tsx
641
- import { Box as Box5, Text as Text5 } from "ink";
642
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
729
+ import { Box as Box6, Text as Text6 } from "ink";
730
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
643
731
  var COL = {
644
732
  rank: 5,
645
733
  type: 12,
@@ -667,50 +755,50 @@ function TaskList({
667
755
  if (filter.type) filterParts.push(`type:${filter.type}`);
668
756
  if (filter.search) filterParts.push(filter.search);
669
757
  const filterText = filterParts.length > 0 ? filterParts.join(" ") : "";
670
- return /* @__PURE__ */ jsxs2(
671
- Box5,
758
+ return /* @__PURE__ */ jsxs3(
759
+ Box6,
672
760
  {
673
761
  flexDirection: "column",
674
762
  flexGrow: 1,
675
763
  borderStyle: "bold",
676
764
  borderColor: isFocused ? theme.borderFocus : theme.border,
677
765
  children: [
678
- /* @__PURE__ */ jsxs2(Box5, { children: [
679
- /* @__PURE__ */ jsxs2(Text5, { color: theme.title, bold: true, children: [
766
+ /* @__PURE__ */ jsxs3(Box6, { children: [
767
+ /* @__PURE__ */ jsxs3(Text6, { color: theme.title, bold: true, children: [
680
768
  " ",
681
769
  "tasks"
682
770
  ] }),
683
- /* @__PURE__ */ jsx5(Text5, { color: theme.fg, children: "(" }),
684
- /* @__PURE__ */ jsx5(Text5, { color: theme.titleHighlight, bold: true, children: activeProjectName }),
685
- /* @__PURE__ */ jsx5(Text5, { color: theme.fg, children: ")" }),
686
- /* @__PURE__ */ jsxs2(Text5, { color: theme.titleCounter, bold: true, children: [
771
+ /* @__PURE__ */ jsx6(Text6, { color: theme.fg, children: "(" }),
772
+ /* @__PURE__ */ jsx6(Text6, { color: theme.titleHighlight, bold: true, children: activeProjectName }),
773
+ /* @__PURE__ */ jsx6(Text6, { color: theme.fg, children: ")" }),
774
+ /* @__PURE__ */ jsxs3(Text6, { color: theme.titleCounter, bold: true, children: [
687
775
  "[",
688
776
  tasks.length,
689
777
  "]"
690
778
  ] }),
691
- isReordering && /* @__PURE__ */ jsxs2(Text5, { color: theme.flash.warn, bold: true, children: [
779
+ isReordering && /* @__PURE__ */ jsxs3(Text6, { color: theme.flash.warn, bold: true, children: [
692
780
  " ",
693
781
  "REORDER"
694
782
  ] }),
695
- epicFilterActive && /* @__PURE__ */ jsx5(Text5, { color: theme.titleHighlight, children: " [epic]" }),
696
- filterText && /* @__PURE__ */ jsxs2(Text5, { color: theme.titleFilter, children: [
783
+ epicFilterActive && /* @__PURE__ */ jsx6(Text6, { color: theme.titleHighlight, children: " [epic]" }),
784
+ filterText && /* @__PURE__ */ jsxs3(Text6, { color: theme.titleFilter, children: [
697
785
  " /",
698
786
  filterText
699
787
  ] })
700
788
  ] }),
701
- isSearchActive && /* @__PURE__ */ jsxs2(Box5, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
702
- /* @__PURE__ */ jsx5(Text5, { color: theme.prompt, children: "/" }),
703
- /* @__PURE__ */ jsx5(Text5, { color: theme.prompt, children: searchQuery }),
704
- /* @__PURE__ */ jsx5(Text5, { color: theme.promptSuggest, children: "_" })
789
+ isSearchActive && /* @__PURE__ */ jsxs3(Box6, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
790
+ /* @__PURE__ */ jsx6(Text6, { color: theme.prompt, children: "/" }),
791
+ /* @__PURE__ */ jsx6(Text6, { color: theme.prompt, children: searchQuery }),
792
+ /* @__PURE__ */ jsx6(Text6, { color: theme.promptSuggest, children: "_" })
705
793
  ] }),
706
- /* @__PURE__ */ jsxs2(Box5, { children: [
707
- /* @__PURE__ */ jsx5(Text5, { color: theme.table.headerFg, bold: true, children: " " }),
708
- /* @__PURE__ */ jsx5(Text5, { color: theme.table.headerFg, bold: true, children: "#".padEnd(COL.rank) }),
709
- /* @__PURE__ */ jsx5(Text5, { color: theme.table.headerFg, bold: true, children: "TYPE".padEnd(COL.type) }),
710
- /* @__PURE__ */ jsx5(Text5, { color: theme.table.headerFg, bold: true, children: "STATUS".padEnd(COL.status) }),
711
- /* @__PURE__ */ jsx5(Text5, { color: theme.table.headerFg, bold: true, children: "NAME" })
794
+ /* @__PURE__ */ jsxs3(Box6, { children: [
795
+ /* @__PURE__ */ jsx6(Text6, { color: theme.table.headerFg, bold: true, children: " " }),
796
+ /* @__PURE__ */ jsx6(Text6, { color: theme.table.headerFg, bold: true, children: "#".padEnd(COL.rank) }),
797
+ /* @__PURE__ */ jsx6(Text6, { color: theme.table.headerFg, bold: true, children: "TYPE".padEnd(COL.type) }),
798
+ /* @__PURE__ */ jsx6(Text6, { color: theme.table.headerFg, bold: true, children: "STATUS".padEnd(COL.status) }),
799
+ /* @__PURE__ */ jsx6(Text6, { color: theme.table.headerFg, bold: true, children: "NAME" })
712
800
  ] }),
713
- /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: tasks.length === 0 ? /* @__PURE__ */ jsx5(Box5, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx5(Text5, { color: theme.fg, children: "No tasks found. Press 'c' to create one." }) }) : visibleTasks.map((task, i) => {
801
+ /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: tasks.length === 0 ? /* @__PURE__ */ jsx6(Box6, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx6(Text6, { color: theme.fg, children: "No tasks found. Press 'c' to create one." }) }) : visibleTasks.map((task, i) => {
714
802
  const actualIndex = viewStart + i;
715
803
  const isSelected = actualIndex === selectedIndex;
716
804
  const isNonTerminalBlocker = nonTerminalBlockerIds.has(task.id);
@@ -720,7 +808,7 @@ function TaskList({
720
808
  const depMarker = isNonTerminalBlocker ? "\u25B2 " : isNonTerminalDependent ? "\u25BC " : " ";
721
809
  if (isSelected) {
722
810
  const cursorBg = isReordering ? theme.flash.warn : isSelectedBlocked ? theme.table.blockedCursorBg : theme.table.cursorBg;
723
- return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsxs2(Text5, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
811
+ return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs3(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
724
812
  isReordering ? "~ " : "> ",
725
813
  rowNum.padEnd(COL.rank),
726
814
  task.type.padEnd(COL.type),
@@ -729,7 +817,7 @@ function TaskList({
729
817
  ] }) }, task.id);
730
818
  }
731
819
  if (isNonTerminalBlocker || isNonTerminalDependent) {
732
- return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsxs2(Text5, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: [
820
+ return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs3(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: [
733
821
  depMarker,
734
822
  rowNum.padEnd(COL.rank),
735
823
  task.type.padEnd(COL.type),
@@ -737,15 +825,15 @@ function TaskList({
737
825
  task.name
738
826
  ] }) }, task.id);
739
827
  }
740
- return /* @__PURE__ */ jsxs2(Box5, { children: [
741
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
742
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: rowNum.padEnd(COL.rank) }),
743
- /* @__PURE__ */ jsx5(Text5, { color: TYPE_COLOR[task.type] ?? rowColor, children: task.type.padEnd(COL.type) }),
744
- /* @__PURE__ */ jsx5(Text5, { color: STATUS_COLOR[task.status] ?? rowColor, children: task.status.padEnd(COL.status) }),
745
- /* @__PURE__ */ jsx5(Text5, { color: rowColor, children: task.name })
828
+ return /* @__PURE__ */ jsxs3(Box6, { children: [
829
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
830
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: rowNum.padEnd(COL.rank) }),
831
+ /* @__PURE__ */ jsx6(Text6, { color: TYPE_COLOR[task.type] ?? rowColor, children: task.type.padEnd(COL.type) }),
832
+ /* @__PURE__ */ jsx6(Text6, { color: STATUS_COLOR[task.status] ?? rowColor, children: task.status.padEnd(COL.status) }),
833
+ /* @__PURE__ */ jsx6(Text6, { color: rowColor, children: task.name })
746
834
  ] }, task.id);
747
835
  }) }),
748
- tasks.length > PAGE_SIZE && /* @__PURE__ */ jsx5(Box5, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs2(Text5, { dimColor: true, children: [
836
+ tasks.length > PAGE_SIZE && /* @__PURE__ */ jsx6(Box6, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
749
837
  "[",
750
838
  viewStart + 1,
751
839
  "-",
@@ -760,12 +848,12 @@ function TaskList({
760
848
  }
761
849
 
762
850
  // src/tui/components/TaskDetail.tsx
763
- import { useMemo } from "react";
764
- import { Box as Box7, Text as Text7, useStdout } from "ink";
851
+ import { useMemo as useMemo2 } from "react";
852
+ import { Box as Box8, Text as Text8, useStdout } from "ink";
765
853
  import chalk2 from "chalk";
766
854
 
767
855
  // src/tui/components/Markdown.tsx
768
- import { Text as Text6, Box as Box6 } from "ink";
856
+ import { Text as Text7, Box as Box7 } from "ink";
769
857
  import { Marked } from "marked";
770
858
  import { markedTerminal } from "marked-terminal";
771
859
  import chalk from "chalk";
@@ -801,7 +889,7 @@ mermaid.initialize({ startOnLoad: true, theme: 'dark' });
801
889
  }
802
890
 
803
891
  // src/tui/components/Markdown.tsx
804
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
892
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
805
893
  function extractMermaidBlocks(content) {
806
894
  const lexer = new Marked();
807
895
  const tokens = lexer.lexer(content);
@@ -862,12 +950,12 @@ function renderMarkdown(content) {
862
950
  function MermaidHint({ content }) {
863
951
  const blocks = extractMermaidBlocks(content);
864
952
  if (blocks.length === 0) return null;
865
- return /* @__PURE__ */ jsxs3(Box6, { children: [
866
- /* @__PURE__ */ jsxs3(Text6, { color: theme.menu.key, bold: true, children: [
953
+ return /* @__PURE__ */ jsxs4(Box7, { children: [
954
+ /* @__PURE__ */ jsxs4(Text7, { color: theme.menu.key, bold: true, children: [
867
955
  "<m>",
868
956
  " "
869
957
  ] }),
870
- /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
958
+ /* @__PURE__ */ jsxs4(Text7, { dimColor: true, children: [
871
959
  "Open ",
872
960
  blocks.length,
873
961
  " mermaid diagram",
@@ -885,7 +973,7 @@ function openAllMermaidDiagrams(content) {
885
973
  }
886
974
 
887
975
  // src/tui/components/TaskDetail.tsx
888
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
976
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
889
977
  var PAD = " ";
890
978
  function field(label, value) {
891
979
  return PAD + chalk2.hex(theme.yaml.key).bold(label) + chalk2.hex(theme.yaml.colon)(": ") + chalk2.hex(theme.yaml.value)(value);
@@ -961,44 +1049,44 @@ function TaskDetail({
961
1049
  const allText = `${task.description}
962
1050
  ${task.technicalNotes}
963
1051
  ${task.additionalRequirements}`;
964
- const contentLines = useMemo(
1052
+ const contentLines = useMemo2(
965
1053
  () => buildContentLines(task, blockers, dependents, related, duplicates),
966
1054
  [task, blockers, dependents, related, duplicates]
967
1055
  );
968
1056
  const viewportHeight = Math.max(1, (stdout.rows > 0 ? stdout.rows : 24) - CHROME_LINES);
969
1057
  const visibleLines = contentLines.slice(scrollOffset, scrollOffset + viewportHeight);
970
- return /* @__PURE__ */ jsxs4(
971
- Box7,
1058
+ return /* @__PURE__ */ jsxs5(
1059
+ Box8,
972
1060
  {
973
1061
  flexDirection: "column",
974
1062
  flexGrow: 1,
975
1063
  borderStyle: "bold",
976
1064
  borderColor: isFocused ? theme.borderFocus : theme.border,
977
1065
  children: [
978
- /* @__PURE__ */ jsxs4(Box7, { gap: 0, children: [
979
- /* @__PURE__ */ jsxs4(Text7, { color: theme.title, bold: true, children: [
1066
+ /* @__PURE__ */ jsxs5(Box8, { gap: 0, children: [
1067
+ /* @__PURE__ */ jsxs5(Text8, { color: theme.title, bold: true, children: [
980
1068
  " ",
981
1069
  "detail"
982
1070
  ] }),
983
- /* @__PURE__ */ jsx7(Text7, { color: theme.fg, children: "(" }),
984
- /* @__PURE__ */ jsx7(Text7, { color: theme.titleHighlight, bold: true, children: task.name }),
985
- /* @__PURE__ */ jsx7(Text7, { color: theme.fg, children: ")" }),
986
- scrollOffset > 0 && /* @__PURE__ */ jsxs4(Text7, { dimColor: true, children: [
1071
+ /* @__PURE__ */ jsx8(Text8, { color: theme.fg, children: "(" }),
1072
+ /* @__PURE__ */ jsx8(Text8, { color: theme.titleHighlight, bold: true, children: task.name }),
1073
+ /* @__PURE__ */ jsx8(Text8, { color: theme.fg, children: ")" }),
1074
+ scrollOffset > 0 && /* @__PURE__ */ jsxs5(Text8, { dimColor: true, children: [
987
1075
  " \u2191",
988
1076
  scrollOffset
989
1077
  ] })
990
1078
  ] }),
991
- /* @__PURE__ */ jsx7(Text7, { children: visibleLines.join("\n") }),
992
- /* @__PURE__ */ jsx7(Box7, { flexGrow: 1 }),
993
- /* @__PURE__ */ jsx7(Box7, { paddingX: 1, children: /* @__PURE__ */ jsx7(MermaidHint, { content: allText }) })
1079
+ /* @__PURE__ */ jsx8(Text8, { children: visibleLines.join("\n") }),
1080
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1 }),
1081
+ /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsx8(MermaidHint, { content: allText }) })
994
1082
  ]
995
1083
  }
996
1084
  );
997
1085
  }
998
1086
 
999
1087
  // src/tui/components/TaskForm.tsx
1000
- import { useState as useState2, useCallback, useEffect, useRef } from "react";
1001
- import { Box as Box9, Text as Text9, useInput as useInput2, useStdin } from "ink";
1088
+ import { useState as useState3, useCallback, useEffect as useEffect2, useRef } from "react";
1089
+ import { Box as Box10, Text as Text10, useInput as useInput2, useStdin } from "ink";
1002
1090
 
1003
1091
  // src/tui/editor.ts
1004
1092
  import { writeFileSync as writeFileSync2, readFileSync, unlinkSync, mkdtempSync as mkdtempSync2 } from "fs";
@@ -1036,9 +1124,9 @@ function openInEditor(content, filename, options) {
1036
1124
  }
1037
1125
 
1038
1126
  // src/tui/components/TaskPicker.tsx
1039
- import { useState } from "react";
1040
- import { Box as Box8, Text as Text8, useInput, useStdout as useStdout2 } from "ink";
1041
- import { Fragment, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1127
+ import { useState as useState2 } from "react";
1128
+ import { Box as Box9, Text as Text9, useInput, useStdout as useStdout2 } from "ink";
1129
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1042
1130
  var DEP_TYPE_VALUES = Object.values(UIDependencyType);
1043
1131
  var DEP_TYPE_COLOR = {
1044
1132
  [DependencyType.Blocks]: theme.status.error,
@@ -1050,10 +1138,10 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1050
1138
  const { stdout } = useStdout2();
1051
1139
  const termHeight = stdout.rows > 0 ? stdout.rows : 24;
1052
1140
  const maxVisible = Math.max(3, termHeight - 12);
1053
- const [searchQuery, setSearchQuery] = useState("");
1054
- const [isSearching, setIsSearching] = useState(false);
1055
- const [cursorIndex, setCursorIndex] = useState(0);
1056
- const [selected, setSelected] = useState(() => {
1141
+ const [searchQuery, setSearchQuery] = useState2("");
1142
+ const [isSearching, setIsSearching] = useState2(false);
1143
+ const [cursorIndex, setCursorIndex] = useState2(0);
1144
+ const [selected, setSelected] = useState2(() => {
1057
1145
  const map = /* @__PURE__ */ new Map();
1058
1146
  if (initialSelection) {
1059
1147
  for (const dep of initialSelection) {
@@ -1152,28 +1240,28 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1152
1240
  return;
1153
1241
  }
1154
1242
  });
1155
- return /* @__PURE__ */ jsxs5(Box8, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
1156
- /* @__PURE__ */ jsxs5(Box8, { gap: 0, children: [
1157
- /* @__PURE__ */ jsxs5(Text8, { color: theme.title, bold: true, children: [
1243
+ return /* @__PURE__ */ jsxs6(Box9, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
1244
+ /* @__PURE__ */ jsxs6(Box9, { gap: 0, children: [
1245
+ /* @__PURE__ */ jsxs6(Text9, { color: theme.title, bold: true, children: [
1158
1246
  " ",
1159
1247
  "select dependencies"
1160
1248
  ] }),
1161
- /* @__PURE__ */ jsxs5(Text8, { color: theme.titleCounter, bold: true, children: [
1249
+ /* @__PURE__ */ jsxs6(Text9, { color: theme.titleCounter, bold: true, children: [
1162
1250
  " ",
1163
1251
  "[",
1164
1252
  selected.size,
1165
1253
  " selected]"
1166
1254
  ] })
1167
1255
  ] }),
1168
- isSearching ? /* @__PURE__ */ jsxs5(Box8, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
1169
- /* @__PURE__ */ jsx8(Text8, { color: theme.prompt, children: "/" }),
1170
- /* @__PURE__ */ jsx8(Text8, { color: theme.prompt, children: searchQuery }),
1171
- /* @__PURE__ */ jsx8(Text8, { color: theme.promptSuggest, children: "_" })
1172
- ] }) : searchQuery ? /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsxs5(Text8, { color: theme.titleFilter, children: [
1256
+ isSearching ? /* @__PURE__ */ jsxs6(Box9, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
1257
+ /* @__PURE__ */ jsx9(Text9, { color: theme.prompt, children: "/" }),
1258
+ /* @__PURE__ */ jsx9(Text9, { color: theme.prompt, children: searchQuery }),
1259
+ /* @__PURE__ */ jsx9(Text9, { color: theme.promptSuggest, children: "_" })
1260
+ ] }) : searchQuery ? /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs6(Text9, { color: theme.titleFilter, children: [
1173
1261
  "/",
1174
1262
  searchQuery
1175
1263
  ] }) }) : null,
1176
- /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsxs5(Text8, { color: theme.table.headerFg, bold: true, children: [
1264
+ /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs6(Text9, { color: theme.table.headerFg, bold: true, children: [
1177
1265
  " ",
1178
1266
  "SEL".padEnd(5),
1179
1267
  "ID".padEnd(14),
@@ -1181,7 +1269,7 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1181
1269
  "STATUS".padEnd(14),
1182
1270
  "NAME"
1183
1271
  ] }) }),
1184
- available.length === 0 ? /* @__PURE__ */ jsx8(Box8, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "No tasks match the filter" }) }) : visible.map((task, i) => {
1272
+ available.length === 0 ? /* @__PURE__ */ jsx9(Box9, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "No tasks match the filter" }) }) : visible.map((task, i) => {
1185
1273
  const actualIndex = viewStart + i;
1186
1274
  const isCursor = actualIndex === cursorIndex;
1187
1275
  const entry = selected.get(task.id);
@@ -1189,24 +1277,24 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1189
1277
  const checkMark = isChecked ? "[x]" : "[ ]";
1190
1278
  const depType = entry ? DEP_TYPE_LABEL[entry.type] ?? entry.type : "";
1191
1279
  const depColor = entry ? DEP_TYPE_COLOR[entry.type] ?? theme.table.fg : theme.table.fg;
1192
- return /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs5(Text8, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
1280
+ return /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs6(Text9, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
1193
1281
  "> ",
1194
1282
  checkMark.padEnd(5),
1195
1283
  task.id.padEnd(14),
1196
1284
  depType.padEnd(12),
1197
1285
  task.status.padEnd(14),
1198
1286
  task.name
1199
- ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1200
- /* @__PURE__ */ jsx8(Text8, { children: " " }),
1201
- /* @__PURE__ */ jsx8(Text8, { color: isChecked ? theme.status.added : theme.table.fg, children: checkMark.padEnd(5) }),
1202
- /* @__PURE__ */ jsx8(Text8, { color: theme.yaml.value, children: task.id.padEnd(14) }),
1203
- /* @__PURE__ */ jsx8(Text8, { color: depColor, children: depType.padEnd(12) }),
1204
- /* @__PURE__ */ jsx8(Text8, { color: theme.status.completed, children: task.status.padEnd(14) }),
1205
- /* @__PURE__ */ jsx8(Text8, { color: theme.table.fg, children: task.name })
1287
+ ] }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
1288
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
1289
+ /* @__PURE__ */ jsx9(Text9, { color: isChecked ? theme.status.added : theme.table.fg, children: checkMark.padEnd(5) }),
1290
+ /* @__PURE__ */ jsx9(Text9, { color: theme.yaml.value, children: task.id.padEnd(14) }),
1291
+ /* @__PURE__ */ jsx9(Text9, { color: depColor, children: depType.padEnd(12) }),
1292
+ /* @__PURE__ */ jsx9(Text9, { color: theme.status.completed, children: task.status.padEnd(14) }),
1293
+ /* @__PURE__ */ jsx9(Text9, { color: theme.table.fg, children: task.name })
1206
1294
  ] }) }, task.id);
1207
1295
  }),
1208
- /* @__PURE__ */ jsx8(Box8, { flexGrow: 1 }),
1209
- available.length > maxVisible && /* @__PURE__ */ jsx8(Box8, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs5(Text8, { dimColor: true, children: [
1296
+ /* @__PURE__ */ jsx9(Box9, { flexGrow: 1 }),
1297
+ available.length > maxVisible && /* @__PURE__ */ jsx9(Box9, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs6(Text9, { dimColor: true, children: [
1210
1298
  "[",
1211
1299
  viewStart + 1,
1212
1300
  "-",
@@ -1215,11 +1303,11 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1215
1303
  available.length,
1216
1304
  "]"
1217
1305
  ] }) }),
1218
- selected.size > 0 && /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, flexDirection: "column", children: [
1219
- /* @__PURE__ */ jsx8(Text8, { color: theme.table.headerFg, bold: true, children: "Selected:" }),
1220
- /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text8, { children: Array.from(selected.values()).map((d) => `${d.id} (${DEP_TYPE_LABEL[d.type] ?? d.type})`).join(", ") }) })
1306
+ selected.size > 0 && /* @__PURE__ */ jsxs6(Box9, { paddingX: 1, flexDirection: "column", children: [
1307
+ /* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: "Selected:" }),
1308
+ /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { children: Array.from(selected.values()).map((d) => `${d.id} (${DEP_TYPE_LABEL[d.type] ?? d.type})`).join(", ") }) })
1221
1309
  ] }),
1222
- /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsxs5(Text8, { dimColor: true, children: [
1310
+ /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs6(Text9, { dimColor: true, children: [
1223
1311
  "space/t: select & cycle type (blocks ",
1224
1312
  "->",
1225
1313
  " relates-to ",
@@ -1235,7 +1323,7 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
1235
1323
  }
1236
1324
 
1237
1325
  // src/tui/components/TaskForm.tsx
1238
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1326
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1239
1327
  var FIELDS = [
1240
1328
  { label: "Name", key: "name", type: "inline" },
1241
1329
  { label: "Type", key: "type", type: "select", options: TYPE_VALUES },
@@ -1256,8 +1344,8 @@ var FIELDS = [
1256
1344
  }
1257
1345
  ];
1258
1346
  function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
1259
- const [focusIndex, setFocusIndex] = useState2(0);
1260
- const [values, setValues] = useState2({
1347
+ const [focusIndex, setFocusIndex] = useState3(0);
1348
+ const [values, setValues] = useState3({
1261
1349
  name: editingTask?.name ?? "",
1262
1350
  type: editingTask?.type ?? TaskType.Story,
1263
1351
  status: editingTask?.status ?? TaskStatus.Backlog,
@@ -1265,14 +1353,14 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
1265
1353
  technicalNotes: editingTask?.technicalNotes ?? "",
1266
1354
  additionalRequirements: editingTask?.additionalRequirements ?? ""
1267
1355
  });
1268
- const [cursorPos, setCursorPos] = useState2(() => (editingTask?.name ?? "").length);
1356
+ const [cursorPos, setCursorPos] = useState3(() => (editingTask?.name ?? "").length);
1269
1357
  const cursorRef = useRef(cursorPos);
1270
1358
  cursorRef.current = cursorPos;
1271
- const [editorActive, setEditorActive] = useState2(false);
1272
- const [pickerActive, setPickerActive] = useState2(false);
1273
- const [pickedDeps, setPickedDeps] = useState2(initialDeps ?? []);
1359
+ const [editorActive, setEditorActive] = useState3(false);
1360
+ const [pickerActive, setPickerActive] = useState3(false);
1361
+ const [pickedDeps, setPickedDeps] = useState3(initialDeps ?? []);
1274
1362
  const { setRawMode } = useStdin();
1275
- useEffect(() => {
1363
+ useEffect2(() => {
1276
1364
  const field2 = FIELDS[focusIndex];
1277
1365
  if (field2?.type === "inline") {
1278
1366
  const pos = values[field2.key]?.length ?? 0;
@@ -1402,7 +1490,7 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
1402
1490
  );
1403
1491
  if (pickerActive) {
1404
1492
  const pickerExclude = editingTask ? { excludeIds: /* @__PURE__ */ new Set([editingTask.id]) } : {};
1405
- return /* @__PURE__ */ jsx9(
1493
+ return /* @__PURE__ */ jsx10(
1406
1494
  TaskPicker,
1407
1495
  {
1408
1496
  tasks: allTasks,
@@ -1415,53 +1503,53 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
1415
1503
  }
1416
1504
  const isEdit = editingTask !== null;
1417
1505
  const depSummary = pickedDeps.length > 0 ? pickedDeps.map((d) => `${d.id} (${DEP_TYPE_LABEL[d.type] ?? d.type})`).join(", ") : "";
1418
- return /* @__PURE__ */ jsxs6(Box9, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1419
- /* @__PURE__ */ jsx9(Box9, { gap: 0, children: /* @__PURE__ */ jsxs6(Text9, { color: theme.title, bold: true, children: [
1506
+ return /* @__PURE__ */ jsxs7(Box10, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1507
+ /* @__PURE__ */ jsx10(Box10, { gap: 0, children: /* @__PURE__ */ jsxs7(Text10, { color: theme.title, bold: true, children: [
1420
1508
  " ",
1421
1509
  isEdit ? "edit" : "create"
1422
1510
  ] }) }),
1423
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS.map((field2, i) => {
1511
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS.map((field2, i) => {
1424
1512
  const isFocused = i === focusIndex;
1425
1513
  const value = field2.key === "dependsOn" ? depSummary : values[field2.key] ?? "";
1426
- return /* @__PURE__ */ jsxs6(Box9, { gap: 1, children: [
1427
- /* @__PURE__ */ jsxs6(Text9, { color: isFocused ? theme.dialog.label : theme.yaml.key, bold: isFocused, children: [
1514
+ return /* @__PURE__ */ jsxs7(Box10, { gap: 1, children: [
1515
+ /* @__PURE__ */ jsxs7(Text10, { color: isFocused ? theme.dialog.label : theme.yaml.key, bold: isFocused, children: [
1428
1516
  isFocused ? ">" : " ",
1429
1517
  " ",
1430
1518
  field2.label.padEnd(14)
1431
1519
  ] }),
1432
- field2.type === "inline" && /* @__PURE__ */ jsx9(Text9, { color: isFocused ? theme.yaml.value : theme.table.fg, children: isFocused ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
1520
+ field2.type === "inline" && /* @__PURE__ */ jsx10(Text10, { color: isFocused ? theme.yaml.value : theme.table.fg, children: isFocused ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
1433
1521
  value.slice(0, cursorPos),
1434
- /* @__PURE__ */ jsx9(Text9, { color: theme.titleHighlight, children: "_" }),
1522
+ /* @__PURE__ */ jsx10(Text10, { color: theme.titleHighlight, children: "_" }),
1435
1523
  value.slice(cursorPos)
1436
1524
  ] }) : value }),
1437
- field2.type === "picker" && /* @__PURE__ */ jsxs6(Text9, { children: [
1438
- value ? /* @__PURE__ */ jsx9(Text9, { color: theme.status.added, children: value.length > 60 ? value.slice(0, 60) + "..." : value }) : /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: isFocused ? "press enter to select" : "none" }),
1439
- isFocused && /* @__PURE__ */ jsx9(Text9, { color: theme.menu.key, children: " [enter: open picker]" })
1525
+ field2.type === "picker" && /* @__PURE__ */ jsxs7(Text10, { children: [
1526
+ value ? /* @__PURE__ */ jsx10(Text10, { color: theme.status.added, children: value.length > 60 ? value.slice(0, 60) + "..." : value }) : /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: isFocused ? "press enter to select" : "none" }),
1527
+ isFocused && /* @__PURE__ */ jsx10(Text10, { color: theme.menu.key, children: " [enter: open picker]" })
1440
1528
  ] }),
1441
- field2.type === "editor" && /* @__PURE__ */ jsxs6(Text9, { children: [
1442
- value ? /* @__PURE__ */ jsxs6(Text9, { color: theme.status.added, children: [
1529
+ field2.type === "editor" && /* @__PURE__ */ jsxs7(Text10, { children: [
1530
+ value ? /* @__PURE__ */ jsxs7(Text10, { color: theme.status.added, children: [
1443
1531
  value.split("\n")[0]?.slice(0, 50),
1444
1532
  value.length > 50 || value.includes("\n") ? "..." : ""
1445
- ] }) : /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: isFocused ? "press enter" : "empty" }),
1446
- isFocused && /* @__PURE__ */ jsx9(Text9, { color: theme.menu.key, children: " [enter: $EDITOR]" })
1533
+ ] }) : /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: isFocused ? "press enter" : "empty" }),
1534
+ isFocused && /* @__PURE__ */ jsx10(Text10, { color: theme.menu.key, children: " [enter: $EDITOR]" })
1447
1535
  ] }),
1448
- field2.type === "select" && /* @__PURE__ */ jsxs6(Text9, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1536
+ field2.type === "select" && /* @__PURE__ */ jsxs7(Text10, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1449
1537
  isFocused ? "< " : " ",
1450
1538
  value,
1451
1539
  isFocused ? " >" : ""
1452
1540
  ] })
1453
1541
  ] }, field2.key);
1454
1542
  }) }),
1455
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1 }),
1456
- /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191\u2193/tab: navigate | \u2190\u2192: cursor | ctrl+s: save | esc: cancel" }) }),
1457
- editorActive && /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { color: theme.flash.warn, bold: true, children: "Editor open... save and close to return" }) })
1543
+ /* @__PURE__ */ jsx10(Box10, { flexGrow: 1 }),
1544
+ /* @__PURE__ */ jsx10(Box10, { paddingX: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2191\u2193/tab: navigate | \u2190\u2192: cursor | ctrl+s: save | esc: cancel" }) }),
1545
+ editorActive && /* @__PURE__ */ jsx10(Box10, { paddingX: 1, children: /* @__PURE__ */ jsx10(Text10, { color: theme.flash.warn, bold: true, children: "Editor open... save and close to return" }) })
1458
1546
  ] });
1459
1547
  }
1460
1548
 
1461
1549
  // src/tui/components/ProjectSelector.tsx
1462
- import { useState as useState3 } from "react";
1463
- import { Box as Box10, Text as Text10, useInput as useInput3 } from "ink";
1464
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1550
+ import { useState as useState4 } from "react";
1551
+ import { Box as Box11, Text as Text11, useInput as useInput3 } from "ink";
1552
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1465
1553
  function ProjectSelector({
1466
1554
  projects,
1467
1555
  activeProject,
@@ -1472,7 +1560,7 @@ function ProjectSelector({
1472
1560
  onLink,
1473
1561
  onCancel
1474
1562
  }) {
1475
- const [selectedIndex, setSelectedIndex] = useState3(() => {
1563
+ const [selectedIndex, setSelectedIndex] = useState4(() => {
1476
1564
  if (!activeProject) return 0;
1477
1565
  const idx = projects.findIndex((p) => p.id === activeProject.id);
1478
1566
  return idx >= 0 ? idx : 0;
@@ -1521,24 +1609,24 @@ function ProjectSelector({
1521
1609
  setSelectedIndex((i) => Math.min(projects.length - 1, i + 1));
1522
1610
  }
1523
1611
  });
1524
- return /* @__PURE__ */ jsxs7(Box10, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1525
- /* @__PURE__ */ jsxs7(Box10, { gap: 0, children: [
1526
- /* @__PURE__ */ jsxs7(Text10, { color: theme.title, bold: true, children: [
1612
+ return /* @__PURE__ */ jsxs8(Box11, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1613
+ /* @__PURE__ */ jsxs8(Box11, { gap: 0, children: [
1614
+ /* @__PURE__ */ jsxs8(Text11, { color: theme.title, bold: true, children: [
1527
1615
  " ",
1528
1616
  "projects"
1529
1617
  ] }),
1530
- /* @__PURE__ */ jsxs7(Text10, { color: theme.titleCounter, bold: true, children: [
1618
+ /* @__PURE__ */ jsxs8(Text11, { color: theme.titleCounter, bold: true, children: [
1531
1619
  "[",
1532
1620
  projects.length,
1533
1621
  "]"
1534
1622
  ] })
1535
1623
  ] }),
1536
- /* @__PURE__ */ jsxs7(Box10, { paddingX: 1, children: [
1537
- /* @__PURE__ */ jsx10(Text10, { color: theme.table.headerFg, bold: true, children: " NAME".padEnd(30) }),
1538
- /* @__PURE__ */ jsx10(Text10, { color: theme.table.headerFg, bold: true, children: "GIT REMOTE".padEnd(40) }),
1539
- /* @__PURE__ */ jsx10(Text10, { color: theme.table.headerFg, bold: true, children: "DESCRIPTION" })
1624
+ /* @__PURE__ */ jsxs8(Box11, { paddingX: 1, children: [
1625
+ /* @__PURE__ */ jsx11(Text11, { color: theme.table.headerFg, bold: true, children: " NAME".padEnd(30) }),
1626
+ /* @__PURE__ */ jsx11(Text11, { color: theme.table.headerFg, bold: true, children: "GIT REMOTE".padEnd(40) }),
1627
+ /* @__PURE__ */ jsx11(Text11, { color: theme.table.headerFg, bold: true, children: "DESCRIPTION" })
1540
1628
  ] }),
1541
- projects.length === 0 ? /* @__PURE__ */ jsx10(Box10, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx10(Text10, { color: theme.fg, children: "No projects. Press 'c' to create one." }) }) : projects.map((project, i) => {
1629
+ projects.length === 0 ? /* @__PURE__ */ jsx11(Box11, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx11(Text11, { color: theme.fg, children: "No projects. Press 'c' to create one." }) }) : projects.map((project, i) => {
1542
1630
  const isSelected = i === selectedIndex;
1543
1631
  const isActive = project.id === activeProject?.id;
1544
1632
  const activeMarker = isActive ? "*" : " ";
@@ -1546,7 +1634,7 @@ function ProjectSelector({
1546
1634
  const marker = `${activeMarker}${defaultMarker}`;
1547
1635
  const remoteDisplay = (project.gitRemote?.value ?? "").slice(0, 38).padEnd(40);
1548
1636
  if (isSelected) {
1549
- return /* @__PURE__ */ jsx10(Box10, { paddingX: 1, children: /* @__PURE__ */ jsxs7(Text10, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
1637
+ return /* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsxs8(Text11, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
1550
1638
  marker,
1551
1639
  " ",
1552
1640
  project.name.padEnd(27),
@@ -1554,25 +1642,25 @@ function ProjectSelector({
1554
1642
  project.description
1555
1643
  ] }) }, project.id);
1556
1644
  }
1557
- return /* @__PURE__ */ jsxs7(Box10, { paddingX: 1, children: [
1558
- /* @__PURE__ */ jsxs7(Text10, { color: isActive ? theme.status.modified : theme.table.fg, children: [
1645
+ return /* @__PURE__ */ jsxs8(Box11, { paddingX: 1, children: [
1646
+ /* @__PURE__ */ jsxs8(Text11, { color: isActive ? theme.status.modified : theme.table.fg, children: [
1559
1647
  marker,
1560
1648
  " ",
1561
1649
  project.name.padEnd(27)
1562
1650
  ] }),
1563
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: remoteDisplay }),
1564
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: project.description })
1651
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: remoteDisplay }),
1652
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: project.description })
1565
1653
  ] }, project.id);
1566
1654
  }),
1567
- /* @__PURE__ */ jsx10(Box10, { flexGrow: 1 }),
1568
- /* @__PURE__ */ jsx10(Box10, { paddingX: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "enter: select | e: edit | d: set default | l: link git | c: create | esc: back" }) })
1655
+ /* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
1656
+ /* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "enter: select | e: edit | d: set default | l: link git | c: create | esc: back" }) })
1569
1657
  ] });
1570
1658
  }
1571
1659
 
1572
1660
  // src/tui/components/ProjectForm.tsx
1573
- import { useState as useState4, useEffect as useEffect2, useRef as useRef2 } from "react";
1574
- import { Box as Box11, Text as Text11, useInput as useInput4 } from "ink";
1575
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1661
+ import { useState as useState5, useEffect as useEffect3, useRef as useRef2 } from "react";
1662
+ import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
1663
+ import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1576
1664
  var FIELDS2 = [
1577
1665
  { label: "Name", key: "name", type: "inline" },
1578
1666
  { label: "Key", key: "key", type: "inline" },
@@ -1582,8 +1670,8 @@ var FIELDS2 = [
1582
1670
  ];
1583
1671
  function ProjectForm({ editingProject, initialGitRemote, onSave, onCancel }) {
1584
1672
  const isEditing = !!editingProject;
1585
- const [focusIndex, setFocusIndex] = useState4(0);
1586
- const [values, setValues] = useState4(() => {
1673
+ const [focusIndex, setFocusIndex] = useState5(0);
1674
+ const [values, setValues] = useState5(() => {
1587
1675
  if (editingProject) {
1588
1676
  return {
1589
1677
  name: editingProject.name,
@@ -1601,10 +1689,10 @@ function ProjectForm({ editingProject, initialGitRemote, onSave, onCancel }) {
1601
1689
  isDefault: "no"
1602
1690
  };
1603
1691
  });
1604
- const [cursorPos, setCursorPos] = useState4(0);
1692
+ const [cursorPos, setCursorPos] = useState5(0);
1605
1693
  const cursorRef = useRef2(cursorPos);
1606
1694
  cursorRef.current = cursorPos;
1607
- useEffect2(() => {
1695
+ useEffect3(() => {
1608
1696
  const field2 = FIELDS2[focusIndex];
1609
1697
  if (field2?.type === "inline") {
1610
1698
  const pos = values[field2.key]?.length ?? 0;
@@ -1685,48 +1773,48 @@ function ProjectForm({ editingProject, initialGitRemote, onSave, onCancel }) {
1685
1773
  }
1686
1774
  }
1687
1775
  });
1688
- return /* @__PURE__ */ jsxs8(Box11, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1689
- /* @__PURE__ */ jsx11(Box11, { gap: 0, children: /* @__PURE__ */ jsxs8(Text11, { color: theme.title, bold: true, children: [
1776
+ return /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1777
+ /* @__PURE__ */ jsx12(Box12, { gap: 0, children: /* @__PURE__ */ jsxs9(Text12, { color: theme.title, bold: true, children: [
1690
1778
  " ",
1691
1779
  isEditing ? "edit project" : "new project"
1692
1780
  ] }) }),
1693
- /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS2.map((field2, i) => {
1781
+ /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS2.map((field2, i) => {
1694
1782
  const isFocused = i === focusIndex;
1695
1783
  const value = values[field2.key] ?? "";
1696
- return /* @__PURE__ */ jsxs8(Box11, { gap: 1, children: [
1697
- /* @__PURE__ */ jsxs8(Text11, { color: isFocused ? theme.dialog.label : theme.yaml.key, bold: isFocused, children: [
1784
+ return /* @__PURE__ */ jsxs9(Box12, { gap: 1, children: [
1785
+ /* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.dialog.label : theme.yaml.key, bold: isFocused, children: [
1698
1786
  isFocused ? ">" : " ",
1699
1787
  " ",
1700
1788
  field2.label.padEnd(14)
1701
1789
  ] }),
1702
- field2.type === "inline" && /* @__PURE__ */ jsxs8(Text11, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1703
- isFocused ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
1790
+ field2.type === "inline" && /* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1791
+ isFocused ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
1704
1792
  value.slice(0, cursorPos),
1705
- /* @__PURE__ */ jsx11(Text11, { color: theme.titleHighlight, children: "_" }),
1793
+ /* @__PURE__ */ jsx12(Text12, { color: theme.titleHighlight, children: "_" }),
1706
1794
  value.slice(cursorPos)
1707
1795
  ] }) : value,
1708
- field2.key === "key" && !value && !isEditing && /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: isFocused ? " (auto from name)" : "" }),
1709
- field2.key === "key" && isEditing && isFocused && /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: " (read-only)" })
1796
+ field2.key === "key" && !value && !isEditing && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: isFocused ? " (auto from name)" : "" }),
1797
+ field2.key === "key" && isEditing && isFocused && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: " (read-only)" })
1710
1798
  ] }),
1711
- field2.type === "toggle" && /* @__PURE__ */ jsxs8(Text11, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1799
+ field2.type === "toggle" && /* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
1712
1800
  isFocused ? "< " : " ",
1713
1801
  value,
1714
1802
  isFocused ? " >" : ""
1715
1803
  ] })
1716
1804
  ] }, field2.key);
1717
1805
  }) }),
1718
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
1719
- /* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2191\u2193/tab: navigate | \u2190\u2192: cursor | ctrl+s: save | esc: cancel" }) })
1806
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1 }),
1807
+ /* @__PURE__ */ jsx12(Box12, { paddingX: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2191\u2193/tab: navigate | \u2190\u2192: cursor | ctrl+s: save | esc: cancel" }) })
1720
1808
  ] });
1721
1809
  }
1722
1810
 
1723
1811
  // src/tui/components/ProjectLinkForm.tsx
1724
- import { useState as useState5, useRef as useRef3 } from "react";
1725
- import { Box as Box12, Text as Text12, useInput as useInput5 } from "ink";
1726
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1812
+ import { useState as useState6, useRef as useRef3 } from "react";
1813
+ import { Box as Box13, Text as Text13, useInput as useInput5 } from "ink";
1814
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1727
1815
  function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
1728
- const [remoteUrl, setRemoteUrl] = useState5(project.gitRemote?.value ?? "");
1729
- const [cursorPos, setCursorPos] = useState5(() => (project.gitRemote?.value ?? "").length);
1816
+ const [remoteUrl, setRemoteUrl] = useState6(project.gitRemote?.value ?? "");
1817
+ const [cursorPos, setCursorPos] = useState6(() => (project.gitRemote?.value ?? "").length);
1730
1818
  const cursorRef = useRef3(cursorPos);
1731
1819
  cursorRef.current = cursorPos;
1732
1820
  useInput5((input, key) => {
@@ -1780,24 +1868,24 @@ function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
1780
1868
  setCursorPos(pos + input.length);
1781
1869
  }
1782
1870
  });
1783
- return /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1784
- /* @__PURE__ */ jsxs9(Box12, { gap: 0, children: [
1785
- /* @__PURE__ */ jsxs9(Text12, { color: theme.title, bold: true, children: [
1871
+ return /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
1872
+ /* @__PURE__ */ jsxs10(Box13, { gap: 0, children: [
1873
+ /* @__PURE__ */ jsxs10(Text13, { color: theme.title, bold: true, children: [
1786
1874
  " ",
1787
1875
  "link git remote"
1788
1876
  ] }),
1789
- /* @__PURE__ */ jsxs9(Text12, { color: theme.titleCounter, bold: true, children: [
1877
+ /* @__PURE__ */ jsxs10(Text13, { color: theme.titleCounter, bold: true, children: [
1790
1878
  " ",
1791
1879
  "[",
1792
1880
  project.name,
1793
1881
  "]"
1794
1882
  ] })
1795
1883
  ] }),
1796
- /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
1797
- /* @__PURE__ */ jsxs9(Box12, { gap: 1, children: [
1798
- /* @__PURE__ */ jsx12(Text12, { color: theme.dialog.label, bold: true, children: "Current:" }),
1799
- /* @__PURE__ */ jsx12(
1800
- Text12,
1884
+ /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
1885
+ /* @__PURE__ */ jsxs10(Box13, { gap: 1, children: [
1886
+ /* @__PURE__ */ jsx13(Text13, { color: theme.dialog.label, bold: true, children: "Current:" }),
1887
+ /* @__PURE__ */ jsx13(
1888
+ Text13,
1801
1889
  {
1802
1890
  color: project.gitRemote ? theme.yaml.value : theme.table.fg,
1803
1891
  dimColor: !project.gitRemote,
@@ -1805,17 +1893,17 @@ function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
1805
1893
  }
1806
1894
  )
1807
1895
  ] }),
1808
- /* @__PURE__ */ jsxs9(Box12, { gap: 1, marginTop: 1, children: [
1809
- /* @__PURE__ */ jsx12(Text12, { color: theme.dialog.label, bold: true, children: "Remote URL: " }),
1810
- /* @__PURE__ */ jsxs9(Text12, { color: theme.yaml.value, children: [
1896
+ /* @__PURE__ */ jsxs10(Box13, { gap: 1, marginTop: 1, children: [
1897
+ /* @__PURE__ */ jsx13(Text13, { color: theme.dialog.label, bold: true, children: "Remote URL: " }),
1898
+ /* @__PURE__ */ jsxs10(Text13, { color: theme.yaml.value, children: [
1811
1899
  remoteUrl.slice(0, cursorPos),
1812
- /* @__PURE__ */ jsx12(Text12, { color: theme.titleHighlight, children: "_" }),
1900
+ /* @__PURE__ */ jsx13(Text13, { color: theme.titleHighlight, children: "_" }),
1813
1901
  remoteUrl.slice(cursorPos)
1814
1902
  ] })
1815
1903
  ] })
1816
1904
  ] }),
1817
- /* @__PURE__ */ jsx12(Box12, { flexGrow: 1 }),
1818
- /* @__PURE__ */ jsx12(Box12, { paddingX: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "ctrl+s: save | ctrl+d: detect from cwd | ctrl+u: unlink | esc: cancel" }) })
1905
+ /* @__PURE__ */ jsx13(Box13, { flexGrow: 1 }),
1906
+ /* @__PURE__ */ jsx13(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "ctrl+s: save | ctrl+d: detect from cwd | ctrl+u: unlink | esc: cancel" }) })
1819
1907
  ] });
1820
1908
  }
1821
1909
 
@@ -1847,13 +1935,16 @@ function dismissRemote(filePath, remote) {
1847
1935
  writeFileSync3(filePath, JSON.stringify(list), "utf-8");
1848
1936
  logger.info(`dismissRemote: persisted ${remote.value} to ${filePath}`);
1849
1937
  } catch (e) {
1850
- logger.error(`dismissRemote: failed to write ${filePath}`, e instanceof Error ? e : new Error(String(e)));
1938
+ logger.error(
1939
+ `dismissRemote: failed to write ${filePath}`,
1940
+ e instanceof Error ? e : new Error(String(e))
1941
+ );
1851
1942
  }
1852
1943
  }
1853
1944
 
1854
1945
  // src/tui/components/HelpOverlay.tsx
1855
- import { Box as Box13, Text as Text13 } from "ink";
1856
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1946
+ import { Box as Box14, Text as Text14 } from "ink";
1947
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1857
1948
  var ROW1 = [
1858
1949
  {
1859
1950
  title: "NAVIGATION",
@@ -1939,21 +2030,21 @@ var ROW2 = [
1939
2030
  }
1940
2031
  ];
1941
2032
  function SectionRow({ sections }) {
1942
- return /* @__PURE__ */ jsx13(Box13, { flexDirection: "row", gap: 4, children: sections.map((section) => /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", children: [
1943
- /* @__PURE__ */ jsx13(Text13, { color: theme.table.headerFg, bold: true, children: section.title }),
1944
- section.keys.map(([key, desc]) => /* @__PURE__ */ jsxs10(Box13, { gap: 1, children: [
1945
- /* @__PURE__ */ jsxs10(Text13, { color: theme.menu.key, bold: true, children: [
2033
+ return /* @__PURE__ */ jsx14(Box14, { flexDirection: "row", gap: 4, children: sections.map((section) => /* @__PURE__ */ jsxs11(Box14, { flexDirection: "column", children: [
2034
+ /* @__PURE__ */ jsx14(Text14, { color: theme.table.headerFg, bold: true, children: section.title }),
2035
+ section.keys.map(([key, desc]) => /* @__PURE__ */ jsxs11(Box14, { gap: 1, children: [
2036
+ /* @__PURE__ */ jsxs11(Text14, { color: theme.menu.key, bold: true, children: [
1946
2037
  "<",
1947
2038
  key.padEnd(5),
1948
2039
  ">"
1949
2040
  ] }),
1950
- /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: desc })
2041
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: desc })
1951
2042
  ] }, key))
1952
2043
  ] }, section.title)) });
1953
2044
  }
1954
2045
  function HelpOverlay() {
1955
- return /* @__PURE__ */ jsxs10(
1956
- Box13,
2046
+ return /* @__PURE__ */ jsxs11(
2047
+ Box14,
1957
2048
  {
1958
2049
  flexDirection: "column",
1959
2050
  borderStyle: "bold",
@@ -1961,28 +2052,28 @@ function HelpOverlay() {
1961
2052
  paddingX: 2,
1962
2053
  paddingY: 1,
1963
2054
  children: [
1964
- /* @__PURE__ */ jsxs10(Text13, { color: theme.title, bold: true, children: [
2055
+ /* @__PURE__ */ jsxs11(Text14, { color: theme.title, bold: true, children: [
1965
2056
  " ",
1966
2057
  "Help"
1967
2058
  ] }),
1968
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
1969
- /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", gap: 1, children: [
1970
- /* @__PURE__ */ jsx13(SectionRow, { sections: ROW1 }),
1971
- /* @__PURE__ */ jsx13(SectionRow, { sections: ROW2 })
2059
+ /* @__PURE__ */ jsx14(Text14, { children: " " }),
2060
+ /* @__PURE__ */ jsxs11(Box14, { flexDirection: "column", gap: 1, children: [
2061
+ /* @__PURE__ */ jsx14(SectionRow, { sections: ROW1 }),
2062
+ /* @__PURE__ */ jsx14(SectionRow, { sections: ROW2 })
1972
2063
  ] }),
1973
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
1974
- /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Press any key to close" })
2064
+ /* @__PURE__ */ jsx14(Text14, { children: " " }),
2065
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Press any key to close" })
1975
2066
  ]
1976
2067
  }
1977
2068
  );
1978
2069
  }
1979
2070
 
1980
2071
  // src/tui/components/ConfirmDialog.tsx
1981
- import { Box as Box14, Text as Text14 } from "ink";
1982
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
2072
+ import { Box as Box15, Text as Text15 } from "ink";
2073
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1983
2074
  function ConfirmDialog({ task }) {
1984
- return /* @__PURE__ */ jsxs11(
1985
- Box14,
2075
+ return /* @__PURE__ */ jsxs12(
2076
+ Box15,
1986
2077
  {
1987
2078
  flexDirection: "column",
1988
2079
  borderStyle: "bold",
@@ -1991,17 +2082,17 @@ function ConfirmDialog({ task }) {
1991
2082
  paddingY: 1,
1992
2083
  alignSelf: "center",
1993
2084
  children: [
1994
- /* @__PURE__ */ jsx14(Text14, { color: theme.dialog.label, bold: true, children: "<Delete>" }),
1995
- /* @__PURE__ */ jsx14(Text14, { children: " " }),
1996
- /* @__PURE__ */ jsxs11(Text14, { color: theme.dialog.fg, children: [
2085
+ /* @__PURE__ */ jsx15(Text15, { color: theme.dialog.label, bold: true, children: "<Delete>" }),
2086
+ /* @__PURE__ */ jsx15(Text15, { children: " " }),
2087
+ /* @__PURE__ */ jsxs12(Text15, { color: theme.dialog.fg, children: [
1997
2088
  'Delete task "',
1998
2089
  task.name,
1999
2090
  '"?'
2000
2091
  ] }),
2001
- /* @__PURE__ */ jsx14(Text14, { children: " " }),
2002
- /* @__PURE__ */ jsxs11(Box14, { gap: 3, children: [
2003
- /* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(
2004
- Text14,
2092
+ /* @__PURE__ */ jsx15(Text15, { children: " " }),
2093
+ /* @__PURE__ */ jsxs12(Box15, { gap: 3, children: [
2094
+ /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(
2095
+ Text15,
2005
2096
  {
2006
2097
  backgroundColor: theme.dialog.buttonFocusBg,
2007
2098
  color: theme.dialog.buttonFocusFg,
@@ -2009,7 +2100,7 @@ function ConfirmDialog({ task }) {
2009
2100
  children: " y: OK "
2010
2101
  }
2011
2102
  ) }),
2012
- /* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(Text14, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Cancel " }) })
2103
+ /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text15, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Cancel " }) })
2013
2104
  ] })
2014
2105
  ]
2015
2106
  }
@@ -2017,11 +2108,11 @@ function ConfirmDialog({ task }) {
2017
2108
  }
2018
2109
 
2019
2110
  // src/tui/components/DetectedProjectDialog.tsx
2020
- import { Box as Box15, Text as Text15 } from "ink";
2021
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
2111
+ import { Box as Box16, Text as Text16 } from "ink";
2112
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
2022
2113
  function DetectedProjectDialog({ remote }) {
2023
- return /* @__PURE__ */ jsxs12(
2024
- Box15,
2114
+ return /* @__PURE__ */ jsxs13(
2115
+ Box16,
2025
2116
  {
2026
2117
  flexDirection: "column",
2027
2118
  borderStyle: "bold",
@@ -2030,18 +2121,18 @@ function DetectedProjectDialog({ remote }) {
2030
2121
  paddingY: 1,
2031
2122
  alignSelf: "center",
2032
2123
  children: [
2033
- /* @__PURE__ */ jsx15(Text15, { color: theme.dialog.label, bold: true, children: "<New Repo Detected>" }),
2034
- /* @__PURE__ */ jsx15(Text15, { children: " " }),
2035
- /* @__PURE__ */ jsxs12(Text15, { color: theme.dialog.fg, children: [
2124
+ /* @__PURE__ */ jsx16(Text16, { color: theme.dialog.label, bold: true, children: "<New Repo Detected>" }),
2125
+ /* @__PURE__ */ jsx16(Text16, { children: " " }),
2126
+ /* @__PURE__ */ jsxs13(Text16, { color: theme.dialog.fg, children: [
2036
2127
  "Git remote: ",
2037
- /* @__PURE__ */ jsx15(Text15, { bold: true, children: remote.value })
2128
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: remote.value })
2038
2129
  ] }),
2039
- /* @__PURE__ */ jsx15(Text15, { color: theme.dialog.fg, children: "No project is linked to this repo yet." }),
2040
- /* @__PURE__ */ jsx15(Text15, { color: theme.dialog.fg, children: "Would you like to create one and link it?" }),
2041
- /* @__PURE__ */ jsx15(Text15, { children: " " }),
2042
- /* @__PURE__ */ jsxs12(Box15, { gap: 3, children: [
2043
- /* @__PURE__ */ jsx15(Text15, { backgroundColor: theme.dialog.buttonFocusBg, color: theme.dialog.buttonFocusFg, bold: true, children: " y: Create " }),
2044
- /* @__PURE__ */ jsx15(Text15, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Skip " })
2130
+ /* @__PURE__ */ jsx16(Text16, { color: theme.dialog.fg, children: "No project is linked to this repo yet." }),
2131
+ /* @__PURE__ */ jsx16(Text16, { color: theme.dialog.fg, children: "Would you like to create one and link it?" }),
2132
+ /* @__PURE__ */ jsx16(Text16, { children: " " }),
2133
+ /* @__PURE__ */ jsxs13(Box16, { gap: 3, children: [
2134
+ /* @__PURE__ */ jsx16(Text16, { backgroundColor: theme.dialog.buttonFocusBg, color: theme.dialog.buttonFocusFg, bold: true, children: " y: Create " }),
2135
+ /* @__PURE__ */ jsx16(Text16, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Skip " })
2045
2136
  ] })
2046
2137
  ]
2047
2138
  }
@@ -2049,8 +2140,8 @@ function DetectedProjectDialog({ remote }) {
2049
2140
  }
2050
2141
 
2051
2142
  // src/tui/components/DependencyList.tsx
2052
- import { Box as Box16, Text as Text16 } from "ink";
2053
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
2143
+ import { Box as Box17, Text as Text17 } from "ink";
2144
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
2054
2145
  function TaskRow({
2055
2146
  task,
2056
2147
  globalIndex,
@@ -2058,16 +2149,16 @@ function TaskRow({
2058
2149
  }) {
2059
2150
  const isSelected = globalIndex === selectedIndex;
2060
2151
  const statusColor = STATUS_COLOR[task.status] ?? theme.table.fg;
2061
- return /* @__PURE__ */ jsx16(Box16, { children: isSelected ? /* @__PURE__ */ jsxs13(Text16, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
2152
+ return /* @__PURE__ */ jsx17(Box17, { children: isSelected ? /* @__PURE__ */ jsxs14(Text17, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
2062
2153
  "> ",
2063
2154
  task.id.padEnd(12),
2064
2155
  task.status.padEnd(14),
2065
2156
  task.name
2066
- ] }) : /* @__PURE__ */ jsxs13(Fragment4, { children: [
2067
- /* @__PURE__ */ jsx16(Text16, { children: " " }),
2068
- /* @__PURE__ */ jsx16(Text16, { color: theme.yaml.value, children: task.id.padEnd(12) }),
2069
- /* @__PURE__ */ jsx16(Text16, { color: statusColor, children: task.status.padEnd(14) }),
2070
- /* @__PURE__ */ jsx16(Text16, { color: theme.table.fg, children: task.name })
2157
+ ] }) : /* @__PURE__ */ jsxs14(Fragment5, { children: [
2158
+ /* @__PURE__ */ jsx17(Text17, { children: " " }),
2159
+ /* @__PURE__ */ jsx17(Text17, { color: theme.yaml.value, children: task.id.padEnd(12) }),
2160
+ /* @__PURE__ */ jsx17(Text17, { color: statusColor, children: task.status.padEnd(14) }),
2161
+ /* @__PURE__ */ jsx17(Text17, { color: theme.table.fg, children: task.name })
2071
2162
  ] }) }, task.id);
2072
2163
  }
2073
2164
  function DependencyList({
@@ -2088,23 +2179,23 @@ function DependencyList({
2088
2179
  const relatedOffset = offset;
2089
2180
  offset += related.length;
2090
2181
  const duplicatesOffset = offset;
2091
- return /* @__PURE__ */ jsxs13(Box16, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
2092
- /* @__PURE__ */ jsxs13(Box16, { gap: 0, children: [
2093
- /* @__PURE__ */ jsxs13(Text16, { color: theme.title, bold: true, children: [
2182
+ return /* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
2183
+ /* @__PURE__ */ jsxs14(Box17, { gap: 0, children: [
2184
+ /* @__PURE__ */ jsxs14(Text17, { color: theme.title, bold: true, children: [
2094
2185
  " ",
2095
2186
  "dependencies"
2096
2187
  ] }),
2097
- /* @__PURE__ */ jsx16(Text16, { color: theme.fg, children: "(" }),
2098
- /* @__PURE__ */ jsx16(Text16, { color: theme.titleHighlight, bold: true, children: task.name }),
2099
- /* @__PURE__ */ jsx16(Text16, { color: theme.fg, children: ")" })
2188
+ /* @__PURE__ */ jsx17(Text17, { color: theme.fg, children: "(" }),
2189
+ /* @__PURE__ */ jsx17(Text17, { color: theme.titleHighlight, bold: true, children: task.name }),
2190
+ /* @__PURE__ */ jsx17(Text17, { color: theme.fg, children: ")" })
2100
2191
  ] }),
2101
- /* @__PURE__ */ jsxs13(Box16, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2102
- /* @__PURE__ */ jsxs13(Text16, { color: theme.table.headerFg, bold: true, children: [
2192
+ /* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2193
+ /* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
2103
2194
  "BLOCKED BY (",
2104
2195
  blockers.length,
2105
2196
  ")"
2106
2197
  ] }),
2107
- blockers.length === 0 ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: " No blockers" }) : blockers.map((t, i) => /* @__PURE__ */ jsx16(
2198
+ blockers.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No blockers" }) : blockers.map((t, i) => /* @__PURE__ */ jsx17(
2108
2199
  TaskRow,
2109
2200
  {
2110
2201
  task: t,
@@ -2114,13 +2205,13 @@ function DependencyList({
2114
2205
  t.id
2115
2206
  ))
2116
2207
  ] }),
2117
- /* @__PURE__ */ jsxs13(Box16, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2118
- /* @__PURE__ */ jsxs13(Text16, { color: theme.table.headerFg, bold: true, children: [
2208
+ /* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2209
+ /* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
2119
2210
  "BLOCKS (",
2120
2211
  dependents.length,
2121
2212
  ")"
2122
2213
  ] }),
2123
- dependents.length === 0 ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: " No dependents" }) : dependents.map((t, i) => /* @__PURE__ */ jsx16(
2214
+ dependents.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No dependents" }) : dependents.map((t, i) => /* @__PURE__ */ jsx17(
2124
2215
  TaskRow,
2125
2216
  {
2126
2217
  task: t,
@@ -2130,13 +2221,13 @@ function DependencyList({
2130
2221
  t.id
2131
2222
  ))
2132
2223
  ] }),
2133
- /* @__PURE__ */ jsxs13(Box16, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2134
- /* @__PURE__ */ jsxs13(Text16, { color: theme.table.headerFg, bold: true, children: [
2224
+ /* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2225
+ /* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
2135
2226
  "RELATES TO (",
2136
2227
  related.length,
2137
2228
  ")"
2138
2229
  ] }),
2139
- related.length === 0 ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: " No related tasks" }) : related.map((t, i) => /* @__PURE__ */ jsx16(
2230
+ related.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No related tasks" }) : related.map((t, i) => /* @__PURE__ */ jsx17(
2140
2231
  TaskRow,
2141
2232
  {
2142
2233
  task: t,
@@ -2146,13 +2237,13 @@ function DependencyList({
2146
2237
  t.id
2147
2238
  ))
2148
2239
  ] }),
2149
- /* @__PURE__ */ jsxs13(Box16, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2150
- /* @__PURE__ */ jsxs13(Text16, { color: theme.table.headerFg, bold: true, children: [
2240
+ /* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
2241
+ /* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
2151
2242
  "DUPLICATES (",
2152
2243
  duplicates.length,
2153
2244
  ")"
2154
2245
  ] }),
2155
- duplicates.length === 0 ? /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: " No duplicate tasks" }) : duplicates.map((t, i) => /* @__PURE__ */ jsx16(
2246
+ duplicates.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No duplicate tasks" }) : duplicates.map((t, i) => /* @__PURE__ */ jsx17(
2156
2247
  TaskRow,
2157
2248
  {
2158
2249
  task: t,
@@ -2162,19 +2253,19 @@ function DependencyList({
2162
2253
  t.id
2163
2254
  ))
2164
2255
  ] }),
2165
- /* @__PURE__ */ jsx16(Box16, { flexGrow: 1 }),
2166
- isAddingDep && /* @__PURE__ */ jsxs13(Box16, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
2167
- /* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: "depends on (id or id:type): " }),
2168
- /* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: addDepInput }),
2169
- /* @__PURE__ */ jsx16(Text16, { color: theme.promptSuggest, children: "_" })
2256
+ /* @__PURE__ */ jsx17(Box17, { flexGrow: 1 }),
2257
+ isAddingDep && /* @__PURE__ */ jsxs14(Box17, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
2258
+ /* @__PURE__ */ jsx17(Text17, { color: theme.prompt, children: "depends on (id or id:type): " }),
2259
+ /* @__PURE__ */ jsx17(Text17, { color: theme.prompt, children: addDepInput }),
2260
+ /* @__PURE__ */ jsx17(Text17, { color: theme.promptSuggest, children: "_" })
2170
2261
  ] }),
2171
- /* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "a: add dep (id or id:relates-to) | x: remove selected | enter: go to task | esc: back" }) })
2262
+ /* @__PURE__ */ jsx17(Box17, { paddingX: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "a: add dep (id or id:relates-to) | x: remove selected | enter: go to task | esc: back" }) })
2172
2263
  ] });
2173
2264
  }
2174
2265
 
2175
2266
  // src/tui/components/EpicPanel.tsx
2176
- import { Box as Box17, Text as Text17 } from "ink";
2177
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
2267
+ import { Box as Box18, Text as Text18 } from "ink";
2268
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2178
2269
  var PAGE_SIZE2 = 20;
2179
2270
  function EpicPanel({
2180
2271
  epics,
@@ -2187,34 +2278,34 @@ function EpicPanel({
2187
2278
  const currentPage = Math.floor(selectedIndex / PAGE_SIZE2);
2188
2279
  const viewStart = currentPage * PAGE_SIZE2;
2189
2280
  const visibleEpics = epics.slice(viewStart, viewStart + PAGE_SIZE2);
2190
- return /* @__PURE__ */ jsxs14(
2191
- Box17,
2281
+ return /* @__PURE__ */ jsxs15(
2282
+ Box18,
2192
2283
  {
2193
2284
  flexDirection: "column",
2194
2285
  width: 48,
2195
2286
  borderStyle: "bold",
2196
2287
  borderColor: isFocused ? theme.borderFocus : theme.border,
2197
2288
  children: [
2198
- /* @__PURE__ */ jsxs14(Box17, { children: [
2199
- /* @__PURE__ */ jsxs14(Text17, { color: theme.title, bold: true, children: [
2289
+ /* @__PURE__ */ jsxs15(Box18, { children: [
2290
+ /* @__PURE__ */ jsxs15(Text18, { color: theme.title, bold: true, children: [
2200
2291
  " ",
2201
2292
  "epics"
2202
2293
  ] }),
2203
- /* @__PURE__ */ jsxs14(Text17, { color: theme.titleCounter, bold: true, children: [
2294
+ /* @__PURE__ */ jsxs15(Text18, { color: theme.titleCounter, bold: true, children: [
2204
2295
  "[",
2205
2296
  epics.length,
2206
2297
  "]"
2207
2298
  ] }),
2208
- isReordering && /* @__PURE__ */ jsxs14(Text17, { color: theme.flash.warn, bold: true, children: [
2299
+ isReordering && /* @__PURE__ */ jsxs15(Text18, { color: theme.flash.warn, bold: true, children: [
2209
2300
  " ",
2210
2301
  "REORDER"
2211
2302
  ] }),
2212
- filterActive && /* @__PURE__ */ jsxs14(Text17, { color: theme.titleFilter, children: [
2303
+ filterActive && /* @__PURE__ */ jsxs15(Text18, { color: theme.titleFilter, children: [
2213
2304
  " *",
2214
2305
  selectedEpicIds.size
2215
2306
  ] })
2216
2307
  ] }),
2217
- /* @__PURE__ */ jsx17(Box17, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: epics.length === 0 ? /* @__PURE__ */ jsx17(Box17, { paddingX: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "No epics" }) }) : visibleEpics.map((epic, i) => {
2308
+ /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: epics.length === 0 ? /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "No epics" }) }) : visibleEpics.map((epic, i) => {
2218
2309
  const actualIndex = viewStart + i;
2219
2310
  const isSelected = actualIndex === selectedIndex && isFocused;
2220
2311
  const isChecked = selectedEpicIds.has(epic.id);
@@ -2222,21 +2313,21 @@ function EpicPanel({
2222
2313
  const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
2223
2314
  if (isSelected) {
2224
2315
  const cursorBg = isReordering ? theme.flash.warn : theme.table.cursorBg;
2225
- return /* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsxs14(Text17, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
2316
+ return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
2226
2317
  isReordering ? "~ " : " ",
2227
2318
  marker,
2228
2319
  " ",
2229
2320
  epic.name
2230
2321
  ] }) }, epic.id);
2231
2322
  }
2232
- return /* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsxs14(Text17, { color: isChecked ? theme.titleHighlight : statusColor, children: [
2323
+ return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { color: isChecked ? theme.titleHighlight : statusColor, children: [
2233
2324
  " ",
2234
2325
  marker,
2235
2326
  " ",
2236
2327
  epic.name
2237
2328
  ] }) }, epic.id);
2238
2329
  }) }),
2239
- epics.length > PAGE_SIZE2 && /* @__PURE__ */ jsx17(Box17, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs14(Text17, { dimColor: true, children: [
2330
+ epics.length > PAGE_SIZE2 && /* @__PURE__ */ jsx18(Box18, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs15(Text18, { dimColor: true, children: [
2240
2331
  "[",
2241
2332
  viewStart + 1,
2242
2333
  "-",
@@ -2251,16 +2342,16 @@ function EpicPanel({
2251
2342
  }
2252
2343
 
2253
2344
  // src/tui/components/EpicPicker.tsx
2254
- import { useState as useState6 } from "react";
2255
- import { Box as Box18, Text as Text18, useInput as useInput6, useStdout as useStdout3 } from "ink";
2256
- import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2345
+ import { useState as useState7 } from "react";
2346
+ import { Box as Box19, Text as Text19, useInput as useInput6, useStdout as useStdout3 } from "ink";
2347
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2257
2348
  function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
2258
2349
  const { stdout } = useStdout3();
2259
2350
  const termHeight = stdout.rows > 0 ? stdout.rows : 24;
2260
2351
  const maxVisible = Math.max(3, termHeight - 10);
2261
- const [searchQuery, setSearchQuery] = useState6("");
2262
- const [isSearching, setIsSearching] = useState6(false);
2263
- const [cursorIndex, setCursorIndex] = useState6(0);
2352
+ const [searchQuery, setSearchQuery] = useState7("");
2353
+ const [isSearching, setIsSearching] = useState7(false);
2354
+ const [cursorIndex, setCursorIndex] = useState7(0);
2264
2355
  const filtered = epics.filter((e) => {
2265
2356
  if (!searchQuery.trim()) return true;
2266
2357
  const q = searchQuery.toLowerCase();
@@ -2326,53 +2417,53 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
2326
2417
  return;
2327
2418
  }
2328
2419
  });
2329
- return /* @__PURE__ */ jsxs15(Box18, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
2330
- /* @__PURE__ */ jsxs15(Box18, { gap: 0, children: [
2331
- /* @__PURE__ */ jsxs15(Text18, { color: theme.title, bold: true, children: [
2420
+ return /* @__PURE__ */ jsxs16(Box19, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
2421
+ /* @__PURE__ */ jsxs16(Box19, { gap: 0, children: [
2422
+ /* @__PURE__ */ jsxs16(Text19, { color: theme.title, bold: true, children: [
2332
2423
  " ",
2333
2424
  "assign to epic"
2334
2425
  ] }),
2335
- /* @__PURE__ */ jsxs15(Text18, { color: theme.titleCounter, bold: true, children: [
2426
+ /* @__PURE__ */ jsxs16(Text19, { color: theme.titleCounter, bold: true, children: [
2336
2427
  " ",
2337
2428
  "[",
2338
2429
  epics.length,
2339
2430
  "]"
2340
2431
  ] })
2341
2432
  ] }),
2342
- isSearching ? /* @__PURE__ */ jsxs15(Box18, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
2343
- /* @__PURE__ */ jsx18(Text18, { color: theme.prompt, children: "/" }),
2344
- /* @__PURE__ */ jsx18(Text18, { color: theme.prompt, children: searchQuery }),
2345
- /* @__PURE__ */ jsx18(Text18, { color: theme.promptSuggest, children: "_" })
2346
- ] }) : searchQuery ? /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: /* @__PURE__ */ jsxs15(Text18, { color: theme.titleFilter, children: [
2433
+ isSearching ? /* @__PURE__ */ jsxs16(Box19, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
2434
+ /* @__PURE__ */ jsx19(Text19, { color: theme.prompt, children: "/" }),
2435
+ /* @__PURE__ */ jsx19(Text19, { color: theme.prompt, children: searchQuery }),
2436
+ /* @__PURE__ */ jsx19(Text19, { color: theme.promptSuggest, children: "_" })
2437
+ ] }) : searchQuery ? /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text19, { color: theme.titleFilter, children: [
2347
2438
  "/",
2348
2439
  searchQuery
2349
2440
  ] }) }) : null,
2350
- /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: /* @__PURE__ */ jsxs15(Text18, { color: theme.table.headerFg, bold: true, children: [
2441
+ /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text19, { color: theme.table.headerFg, bold: true, children: [
2351
2442
  " ",
2352
2443
  "ID".padEnd(14),
2353
2444
  "STATUS".padEnd(14),
2354
2445
  "NAME"
2355
2446
  ] }) }),
2356
- filtered.length === 0 ? /* @__PURE__ */ jsx18(Box18, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "No epics match the filter" }) }) : visible.map((epic, i) => {
2447
+ filtered.length === 0 ? /* @__PURE__ */ jsx19(Box19, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "No epics match the filter" }) }) : visible.map((epic, i) => {
2357
2448
  const actualIndex = viewStart + i;
2358
2449
  const isCursor = actualIndex === cursorIndex;
2359
2450
  const isCurrent = epic.id === currentEpicId;
2360
2451
  const marker = isCurrent ? "* " : " ";
2361
2452
  const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
2362
- return /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs15(Text18, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
2453
+ return /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs16(Text19, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
2363
2454
  "> ",
2364
2455
  epic.id.padEnd(14),
2365
2456
  epic.status.padEnd(14),
2366
2457
  epic.name
2367
- ] }) : /* @__PURE__ */ jsxs15(Fragment5, { children: [
2368
- /* @__PURE__ */ jsx18(Text18, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: marker }),
2369
- /* @__PURE__ */ jsx18(Text18, { color: theme.yaml.value, children: epic.id.padEnd(14) }),
2370
- /* @__PURE__ */ jsx18(Text18, { color: statusColor, children: epic.status.padEnd(14) }),
2371
- /* @__PURE__ */ jsx18(Text18, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: epic.name })
2458
+ ] }) : /* @__PURE__ */ jsxs16(Fragment6, { children: [
2459
+ /* @__PURE__ */ jsx19(Text19, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: marker }),
2460
+ /* @__PURE__ */ jsx19(Text19, { color: theme.yaml.value, children: epic.id.padEnd(14) }),
2461
+ /* @__PURE__ */ jsx19(Text19, { color: statusColor, children: epic.status.padEnd(14) }),
2462
+ /* @__PURE__ */ jsx19(Text19, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: epic.name })
2372
2463
  ] }) }, epic.id);
2373
2464
  }),
2374
- /* @__PURE__ */ jsx18(Box18, { flexGrow: 1 }),
2375
- filtered.length > maxVisible && /* @__PURE__ */ jsx18(Box18, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs15(Text18, { dimColor: true, children: [
2465
+ /* @__PURE__ */ jsx19(Box19, { flexGrow: 1 }),
2466
+ filtered.length > maxVisible && /* @__PURE__ */ jsx19(Box19, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs16(Text19, { dimColor: true, children: [
2376
2467
  "[",
2377
2468
  viewStart + 1,
2378
2469
  "-",
@@ -2381,19 +2472,52 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
2381
2472
  filtered.length,
2382
2473
  "]"
2383
2474
  ] }) }),
2384
- /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "enter: assign | x: unassign | /: search | esc: cancel" }) })
2475
+ /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "enter: assign | x: unassign | /: search | esc: cancel" }) })
2385
2476
  ] });
2386
2477
  }
2387
2478
 
2479
+ // src/tui/components/ChangelogBanner.tsx
2480
+ import { Box as Box20, Text as Text20 } from "ink";
2481
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2482
+ function ChangelogBanner({ entries, currentIndex }) {
2483
+ const entry = entries[currentIndex];
2484
+ if (!entry) return null;
2485
+ const total = entries.length;
2486
+ return /* @__PURE__ */ jsxs17(
2487
+ Box20,
2488
+ {
2489
+ flexDirection: "column",
2490
+ borderStyle: "bold",
2491
+ borderColor: theme.borderFocus,
2492
+ paddingX: 3,
2493
+ paddingY: 1,
2494
+ gap: 1,
2495
+ alignSelf: "center",
2496
+ children: [
2497
+ /* @__PURE__ */ jsx20(Text20, { color: theme.dialog.label, bold: true, children: `<What's New \u2014 v${entry.version}${entry.date ? ` (${entry.date})` : ""}>` }),
2498
+ entry.sections.map((section) => /* @__PURE__ */ jsxs17(Box20, { flexDirection: "column", children: [
2499
+ /* @__PURE__ */ jsx20(Text20, { color: theme.table.headerFg, bold: true, children: `### ${section.heading}` }),
2500
+ section.items.map((item, i) => /* @__PURE__ */ jsx20(Text20, { color: theme.dialog.fg, children: `- ${item}` }, `${section.heading}-${i}`))
2501
+ ] }, section.heading)),
2502
+ /* @__PURE__ */ jsxs17(Box20, { gap: 2, children: [
2503
+ /* @__PURE__ */ jsx20(Text20, { color: theme.fg, children: `[${currentIndex + 1}/${total}]` }),
2504
+ /* @__PURE__ */ jsx20(Text20, { color: theme.menu.desc, children: "\u2191/\u2193: navigate" }),
2505
+ /* @__PURE__ */ jsx20(Text20, { color: theme.menu.desc, children: "esc: close" })
2506
+ ] })
2507
+ ]
2508
+ }
2509
+ );
2510
+ }
2511
+
2388
2512
  // src/tui/useAutoRefetch.ts
2389
- import { useEffect as useEffect3, useRef as useRef4 } from "react";
2513
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
2390
2514
  import { watchFile, unwatchFile } from "fs";
2391
2515
  var POLL_INTERVAL_MS = 1e3;
2392
2516
  var DEBOUNCE_MS = 200;
2393
2517
  function useAutoRefetch(dbPath, onRefetch) {
2394
2518
  const callbackRef = useRef4(onRefetch);
2395
2519
  callbackRef.current = onRefetch;
2396
- useEffect3(() => {
2520
+ useEffect4(() => {
2397
2521
  let debounceTimer = null;
2398
2522
  const handleChange = () => {
2399
2523
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -2420,8 +2544,47 @@ function useAutoRefetch(dbPath, onRefetch) {
2420
2544
  }, [dbPath]);
2421
2545
  }
2422
2546
 
2547
+ // src/changelog.ts
2548
+ var CHANGELOG_ENTRIES = typeof define_CHANGELOG_ENTRIES_default !== "undefined" ? define_CHANGELOG_ENTRIES_default : [];
2549
+
2550
+ // src/utils/changelog-seen.ts
2551
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
2552
+ function isValidSeenCache(value) {
2553
+ if (typeof value !== "object" || value === null) return false;
2554
+ return typeof value["changelogSeenVersion"] === "string";
2555
+ }
2556
+ function readSeenVersion(cachePath) {
2557
+ try {
2558
+ const raw = readFileSync3(cachePath, "utf-8");
2559
+ const parsed = JSON.parse(raw);
2560
+ if (isValidSeenCache(parsed)) return parsed.changelogSeenVersion;
2561
+ return null;
2562
+ } catch {
2563
+ logger.info("changelog-seen: cache not available", { path: cachePath });
2564
+ return null;
2565
+ }
2566
+ }
2567
+ function writeSeenVersion(cachePath, version) {
2568
+ try {
2569
+ let existing = {};
2570
+ try {
2571
+ const raw = readFileSync3(cachePath, "utf-8");
2572
+ const parsed = JSON.parse(raw);
2573
+ if (typeof parsed === "object" && parsed !== null) {
2574
+ existing = parsed;
2575
+ }
2576
+ } catch {
2577
+ }
2578
+ existing["changelogSeenVersion"] = version;
2579
+ writeFileSync4(cachePath, JSON.stringify(existing), "utf-8");
2580
+ logger.info("changelog-seen: persisted seen version", { version, path: cachePath });
2581
+ } catch {
2582
+ logger.warn("changelog-seen: failed to write seen version", { path: cachePath });
2583
+ }
2584
+ }
2585
+
2423
2586
  // src/tui/components/App.tsx
2424
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2587
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2425
2588
  var STATUS_CYCLE = [
2426
2589
  TaskStatus.Backlog,
2427
2590
  TaskStatus.Todo,
@@ -2434,8 +2597,8 @@ function App({ container, initialProject, latestVersion }) {
2434
2597
  const { exit } = useApp();
2435
2598
  const { stdout } = useStdout4();
2436
2599
  const [state, dispatch] = useReducer(appReducer, initialState);
2437
- const [, setResizeTick] = useState7(0);
2438
- useEffect4(() => {
2600
+ const [, setResizeTick] = useState8(0);
2601
+ useEffect5(() => {
2439
2602
  const onResize = () => {
2440
2603
  setResizeTick((n) => n + 1);
2441
2604
  };
@@ -2600,10 +2763,10 @@ function App({ container, initialProject, latestVersion }) {
2600
2763
  loadEpics();
2601
2764
  }, [loadProjects, loadTasks, loadEpics]);
2602
2765
  useAutoRefetch(container.dbPath, refetchAll);
2603
- useEffect4(() => {
2766
+ useEffect5(() => {
2604
2767
  loadProjects();
2605
2768
  }, [loadProjects]);
2606
- useEffect4(() => {
2769
+ useEffect5(() => {
2607
2770
  if (state.projects.length > 0 && !state.activeProject) {
2608
2771
  logger.info(`TUI.resolveProject: resolving initialProject=${initialProject ?? "(default)"}`);
2609
2772
  const result = container.projectService.resolveProject(initialProject);
@@ -2621,7 +2784,7 @@ function App({ container, initialProject, latestVersion }) {
2621
2784
  }
2622
2785
  }, [state.projects, state.activeProject, initialProject, container]);
2623
2786
  const gitRemoteCheckedRef = useRef5(false);
2624
- useEffect4(() => {
2787
+ useEffect5(() => {
2625
2788
  if (state.projects.length > 0 && !gitRemoteCheckedRef.current && !initialProject) {
2626
2789
  gitRemoteCheckedRef.current = true;
2627
2790
  const remoteResult = detectGitRemote();
@@ -2636,13 +2799,31 @@ function App({ container, initialProject, latestVersion }) {
2636
2799
  }
2637
2800
  }
2638
2801
  }, [state.projects, initialProject]);
2639
- useEffect4(() => {
2802
+ const changelogCheckedRef = useRef5(false);
2803
+ useEffect5(() => {
2804
+ if (changelogCheckedRef.current) return;
2805
+ changelogCheckedRef.current = true;
2806
+ const seenVersion = readSeenVersion(container.updateCachePath);
2807
+ if (seenVersion !== APP_VERSION) {
2808
+ const newEntries = CHANGELOG_ENTRIES.filter(
2809
+ (e) => isNewerVersion(e.version, seenVersion ?? "0.0.0") && !isNewerVersion(e.version, APP_VERSION)
2810
+ );
2811
+ if (newEntries.length > 0) {
2812
+ logger.info(
2813
+ `TUI.changelog: showing ticker for [${newEntries.map((e) => e.version).join(", ")}] (last seen: ${seenVersion ?? "none"})`
2814
+ );
2815
+ dispatch({ type: "SET_CHANGELOG", entries: newEntries });
2816
+ writeSeenVersion(container.updateCachePath, APP_VERSION);
2817
+ }
2818
+ }
2819
+ }, [container.updateCachePath]);
2820
+ useEffect5(() => {
2640
2821
  if (state.activeProject) {
2641
2822
  loadTasks();
2642
2823
  loadEpics();
2643
2824
  }
2644
2825
  }, [state.activeProject, state.filter, loadTasks, loadEpics]);
2645
- useEffect4(() => {
2826
+ useEffect5(() => {
2646
2827
  if (state.flash) {
2647
2828
  const timer = setTimeout(() => {
2648
2829
  dispatch({ type: "CLEAR_FLASH" });
@@ -2654,6 +2835,21 @@ function App({ container, initialProject, latestVersion }) {
2654
2835
  return void 0;
2655
2836
  }, [state.flash]);
2656
2837
  useInput7((input, key) => {
2838
+ if (state.changelogDialogOpen) {
2839
+ if (key.upArrow || input === "k") {
2840
+ dispatch({ type: "CHANGELOG_NAVIGATE", direction: "up" });
2841
+ return;
2842
+ }
2843
+ if (key.downArrow || input === "j") {
2844
+ dispatch({ type: "CHANGELOG_NAVIGATE", direction: "down" });
2845
+ return;
2846
+ }
2847
+ if (key.escape || input === "q" || input === "W") {
2848
+ dispatch({ type: "CLOSE_CHANGELOG_DIALOG" });
2849
+ return;
2850
+ }
2851
+ return;
2852
+ }
2657
2853
  if (state.confirmDelete) {
2658
2854
  if (input === "y") {
2659
2855
  const result = container.taskService.deleteTask(state.confirmDelete.id);
@@ -3015,6 +3211,10 @@ function App({ container, initialProject, latestVersion }) {
3015
3211
  dispatch({ type: "CLEAR_FILTER" });
3016
3212
  return;
3017
3213
  }
3214
+ if (input === "W" && state.changelogEntries) {
3215
+ dispatch({ type: "OPEN_CHANGELOG_DIALOG" });
3216
+ return;
3217
+ }
3018
3218
  }
3019
3219
  if (state.activeView === ViewType.TaskList && state.focusedPanel === "detail" && previewTask) {
3020
3220
  if (key.upArrow || input === "k") {
@@ -3367,7 +3567,7 @@ ${state.selectedTask.additionalRequirements}`;
3367
3567
  dispatch({ type: "GO_BACK" });
3368
3568
  }, []);
3369
3569
  const previewTask = state.tasks[state.selectedIndex] ?? null;
3370
- const initialDepsForEdit = useMemo2(() => {
3570
+ const initialDepsForEdit = useMemo3(() => {
3371
3571
  return [
3372
3572
  ...state.depBlockers.map((t) => ({ id: t.id, name: t.name, type: DependencyType.Blocks })),
3373
3573
  ...state.depRelated.map((t) => ({ id: t.id, name: t.name, type: DependencyType.RelatesTo })),
@@ -3378,23 +3578,24 @@ ${state.selectedTask.additionalRequirements}`;
3378
3578
  }))
3379
3579
  ];
3380
3580
  }, [state.depBlockers, state.depRelated, state.depDuplicates]);
3381
- const allProjectTasks = useMemo2(() => {
3581
+ const allProjectTasks = useMemo3(() => {
3382
3582
  if (!state.activeProject) return [];
3383
3583
  const result = container.taskService.listTasks(state.activeProject, {});
3384
3584
  return result.ok ? result.value : [];
3385
3585
  }, [container, state.activeProject, state.tasks]);
3386
3586
  const previewTaskId = previewTask?.id ?? null;
3387
- useEffect4(() => {
3587
+ useEffect5(() => {
3388
3588
  if (state.activeView === ViewType.TaskList && previewTaskId) {
3389
3589
  loadDeps(previewTaskId);
3390
3590
  }
3391
3591
  }, [state.activeView, previewTaskId, loadDeps]);
3392
- return /* @__PURE__ */ jsxs16(Box19, { flexDirection: "column", height: stdout.rows, children: [
3393
- /* @__PURE__ */ jsx19(Header, { state, latestVersion }),
3394
- /* @__PURE__ */ jsxs16(Box19, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [
3395
- state.confirmDelete && /* @__PURE__ */ jsx19(ConfirmDialog, { task: state.confirmDelete }),
3396
- !state.confirmDelete && state.activeView === ViewType.TaskList && (state.detectedGitRemote ? /* @__PURE__ */ jsx19(DetectedProjectDialog, { remote: state.detectedGitRemote }) : /* @__PURE__ */ jsxs16(Box19, { flexDirection: "row", flexGrow: 1, children: [
3397
- /* @__PURE__ */ jsx19(
3592
+ return /* @__PURE__ */ jsxs18(Box21, { flexDirection: "column", height: stdout.rows, children: [
3593
+ /* @__PURE__ */ jsx21(Header, { state, latestVersion }),
3594
+ /* @__PURE__ */ jsxs18(Box21, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [
3595
+ state.confirmDelete && /* @__PURE__ */ jsx21(ConfirmDialog, { task: state.confirmDelete }),
3596
+ !state.confirmDelete && state.changelogEntries && state.changelogDialogOpen && state.activeView === ViewType.TaskList && /* @__PURE__ */ jsx21(ChangelogBanner, { entries: state.changelogEntries, currentIndex: state.changelogIndex }),
3597
+ !state.confirmDelete && !state.changelogDialogOpen && state.activeView === ViewType.TaskList && (state.detectedGitRemote ? /* @__PURE__ */ jsx21(DetectedProjectDialog, { remote: state.detectedGitRemote }) : /* @__PURE__ */ jsxs18(Box21, { flexDirection: "row", flexGrow: 1, children: [
3598
+ /* @__PURE__ */ jsx21(
3398
3599
  EpicPanel,
3399
3600
  {
3400
3601
  epics: state.epics,
@@ -3404,7 +3605,7 @@ ${state.selectedTask.additionalRequirements}`;
3404
3605
  isReordering: state.isEpicReordering
3405
3606
  }
3406
3607
  ),
3407
- /* @__PURE__ */ jsx19(Box19, { width: taskListWidth, children: /* @__PURE__ */ jsx19(
3608
+ /* @__PURE__ */ jsx21(Box21, { width: taskListWidth, children: /* @__PURE__ */ jsx21(
3408
3609
  TaskList,
3409
3610
  {
3410
3611
  tasks: state.tasks,
@@ -3425,7 +3626,7 @@ ${state.selectedTask.additionalRequirements}`;
3425
3626
  epicFilterActive: state.selectedEpicIds.size > 0
3426
3627
  }
3427
3628
  ) }),
3428
- /* @__PURE__ */ jsx19(Box19, { width: taskDetailWidth, children: previewTask ? /* @__PURE__ */ jsx19(
3629
+ /* @__PURE__ */ jsx21(Box21, { width: taskDetailWidth, children: previewTask ? /* @__PURE__ */ jsx21(
3429
3630
  TaskDetail,
3430
3631
  {
3431
3632
  task: previewTask,
@@ -3436,24 +3637,24 @@ ${state.selectedTask.additionalRequirements}`;
3436
3637
  isFocused: state.focusedPanel === "detail",
3437
3638
  scrollOffset: state.detailScrollOffset
3438
3639
  }
3439
- ) : /* @__PURE__ */ jsxs16(
3440
- Box19,
3640
+ ) : /* @__PURE__ */ jsxs18(
3641
+ Box21,
3441
3642
  {
3442
3643
  flexDirection: "column",
3443
3644
  flexGrow: 1,
3444
3645
  borderStyle: "bold",
3445
3646
  borderColor: theme.border,
3446
3647
  children: [
3447
- /* @__PURE__ */ jsx19(Box19, { children: /* @__PURE__ */ jsxs16(Text19, { color: theme.title, bold: true, children: [
3648
+ /* @__PURE__ */ jsx21(Box21, { children: /* @__PURE__ */ jsxs18(Text21, { color: theme.title, bold: true, children: [
3448
3649
  " ",
3449
3650
  "detail"
3450
3651
  ] }) }),
3451
- /* @__PURE__ */ jsx19(Box19, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "No task selected" }) })
3652
+ /* @__PURE__ */ jsx21(Box21, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "No task selected" }) })
3452
3653
  ]
3453
3654
  }
3454
3655
  ) })
3455
3656
  ] })),
3456
- !state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx19(
3657
+ !state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx21(
3457
3658
  TaskDetail,
3458
3659
  {
3459
3660
  task: state.selectedTask,
@@ -3464,7 +3665,7 @@ ${state.selectedTask.additionalRequirements}`;
3464
3665
  scrollOffset: state.detailScrollOffset
3465
3666
  }
3466
3667
  ),
3467
- !state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx19(
3668
+ !state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx21(
3468
3669
  DependencyList,
3469
3670
  {
3470
3671
  task: state.selectedTask,
@@ -3477,7 +3678,7 @@ ${state.selectedTask.additionalRequirements}`;
3477
3678
  addDepInput: state.addDepInput
3478
3679
  }
3479
3680
  ),
3480
- !state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx19(
3681
+ !state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx21(
3481
3682
  TaskForm,
3482
3683
  {
3483
3684
  editingTask: state.activeView === ViewType.TaskEdit ? state.selectedTask : null,
@@ -3487,7 +3688,7 @@ ${state.selectedTask.additionalRequirements}`;
3487
3688
  onCancel: handleFormCancel
3488
3689
  }
3489
3690
  ),
3490
- !state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */ jsx19(
3691
+ !state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */ jsx21(
3491
3692
  EpicPicker,
3492
3693
  {
3493
3694
  epics: state.epics,
@@ -3496,7 +3697,7 @@ ${state.selectedTask.additionalRequirements}`;
3496
3697
  onCancel: handleEpicPickerCancel
3497
3698
  }
3498
3699
  ),
3499
- !state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx19(
3700
+ !state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx21(
3500
3701
  ProjectSelector,
3501
3702
  {
3502
3703
  projects: state.projects,
@@ -3509,7 +3710,7 @@ ${state.selectedTask.additionalRequirements}`;
3509
3710
  onCancel: handleProjectCancel
3510
3711
  }
3511
3712
  ),
3512
- !state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx19(
3713
+ !state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx21(
3513
3714
  ProjectForm,
3514
3715
  {
3515
3716
  initialGitRemote: state.detectedGitRemote ?? void 0,
@@ -3517,7 +3718,7 @@ ${state.selectedTask.additionalRequirements}`;
3517
3718
  onCancel: handleProjectFormCancel
3518
3719
  }
3519
3720
  ),
3520
- !state.confirmDelete && state.activeView === ViewType.ProjectEdit && state.editingProject && /* @__PURE__ */ jsx19(
3721
+ !state.confirmDelete && state.activeView === ViewType.ProjectEdit && state.editingProject && /* @__PURE__ */ jsx21(
3521
3722
  ProjectForm,
3522
3723
  {
3523
3724
  editingProject: state.editingProject,
@@ -3525,7 +3726,7 @@ ${state.selectedTask.additionalRequirements}`;
3525
3726
  onCancel: handleProjectFormCancel
3526
3727
  }
3527
3728
  ),
3528
- !state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx19(
3729
+ !state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx21(
3529
3730
  ProjectLinkForm,
3530
3731
  {
3531
3732
  project: state.linkingProject,
@@ -3535,18 +3736,18 @@ ${state.selectedTask.additionalRequirements}`;
3535
3736
  onCancel: handleLinkCancel
3536
3737
  }
3537
3738
  ),
3538
- !state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx19(HelpOverlay, {})
3739
+ !state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx21(HelpOverlay, {})
3539
3740
  ] }),
3540
- /* @__PURE__ */ jsx19(Crumbs, { breadcrumbs: state.breadcrumbs }),
3541
- state.flash && /* @__PURE__ */ jsx19(FlashMessage, { message: state.flash.message, level: state.flash.level })
3741
+ /* @__PURE__ */ jsx21(Crumbs, { breadcrumbs: state.breadcrumbs }),
3742
+ state.flash && /* @__PURE__ */ jsx21(FlashMessage, { message: state.flash.message, level: state.flash.level })
3542
3743
  ] });
3543
3744
  }
3544
3745
 
3545
3746
  // src/tui/index.tsx
3546
- import { jsx as jsx20 } from "react/jsx-runtime";
3747
+ import { jsx as jsx22 } from "react/jsx-runtime";
3547
3748
  async function launchTUI(container, initialProject, latestVersion) {
3548
3749
  const instance = render(
3549
- /* @__PURE__ */ jsx20(App, { container, initialProject, latestVersion }),
3750
+ /* @__PURE__ */ jsx22(App, { container, initialProject, latestVersion }),
3550
3751
  {
3551
3752
  exitOnCtrlC: true
3552
3753
  }
@@ -3556,4 +3757,4 @@ async function launchTUI(container, initialProject, latestVersion) {
3556
3757
  export {
3557
3758
  launchTUI
3558
3759
  };
3559
- //# sourceMappingURL=tui-NCL4RFFD.js.map
3760
+ //# sourceMappingURL=tui-APMSKU4E.js.map