@tomkapa/tayto 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-XD24XQNF.js +255 -0
- package/dist/chunk-XD24XQNF.js.map +1 -0
- package/dist/index.js +184 -38
- package/dist/index.js.map +1 -1
- package/dist/{tui-WMESKCRD.js → tui-NKAKDHTY.js} +859 -396
- package/dist/tui-NKAKDHTY.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-74Q55TOV.js +0 -199
- package/dist/chunk-74Q55TOV.js.map +0 -1
- package/dist/tui-WMESKCRD.js.map +0 -1
|
@@ -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-
|
|
14
|
+
} from "./chunk-XD24XQNF.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
|
|
18
|
-
import { Box as
|
|
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 = {
|
|
@@ -25,6 +28,7 @@ var ViewType = {
|
|
|
25
28
|
TaskEdit: "task-edit",
|
|
26
29
|
ProjectSelector: "project-selector",
|
|
27
30
|
ProjectCreate: "project-create",
|
|
31
|
+
ProjectEdit: "project-edit",
|
|
28
32
|
DependencyList: "dependency-list",
|
|
29
33
|
EpicPicker: "epic-picker",
|
|
30
34
|
ProjectLink: "project-link",
|
|
@@ -177,8 +181,13 @@ var initialState = {
|
|
|
177
181
|
epicSelectedIndex: 0,
|
|
178
182
|
selectedEpicIds: /* @__PURE__ */ new Set(),
|
|
179
183
|
linkingProject: null,
|
|
184
|
+
editingProject: null,
|
|
180
185
|
isEpicReordering: false,
|
|
181
|
-
epicReorderSnapshot: null
|
|
186
|
+
epicReorderSnapshot: null,
|
|
187
|
+
detectedGitRemote: null,
|
|
188
|
+
changelogEntries: null,
|
|
189
|
+
changelogIndex: 0,
|
|
190
|
+
changelogDialogOpen: false
|
|
182
191
|
};
|
|
183
192
|
function appReducer(state, action) {
|
|
184
193
|
switch (action.type) {
|
|
@@ -200,6 +209,8 @@ function appReducer(state, action) {
|
|
|
200
209
|
isSearchActive: false,
|
|
201
210
|
formData: null,
|
|
202
211
|
linkingProject: null,
|
|
212
|
+
editingProject: null,
|
|
213
|
+
detectedGitRemote: null,
|
|
203
214
|
focusedPanel: "list"
|
|
204
215
|
};
|
|
205
216
|
}
|
|
@@ -384,11 +395,29 @@ function appReducer(state, action) {
|
|
|
384
395
|
}
|
|
385
396
|
case "SET_LINKING_PROJECT":
|
|
386
397
|
return { ...state, linkingProject: action.project };
|
|
398
|
+
case "SET_EDITING_PROJECT":
|
|
399
|
+
return { ...state, editingProject: action.project };
|
|
400
|
+
case "SET_DETECTED_GIT_REMOTE":
|
|
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 };
|
|
387
416
|
}
|
|
388
417
|
}
|
|
389
418
|
|
|
390
419
|
// src/tui/components/Header.tsx
|
|
391
|
-
import { Box as
|
|
420
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
392
421
|
|
|
393
422
|
// src/tui/components/Logo.tsx
|
|
394
423
|
import React from "react";
|
|
@@ -423,10 +452,71 @@ var Logo = React.memo(function Logo2() {
|
|
|
423
452
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: lines });
|
|
424
453
|
});
|
|
425
454
|
|
|
426
|
-
// src/tui/components/
|
|
455
|
+
// src/tui/components/ChangelogTicker.tsx
|
|
456
|
+
import { useState, useEffect, useMemo } from "react";
|
|
457
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
427
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";
|
|
428
512
|
function getKeyHints(state) {
|
|
429
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
|
+
}
|
|
430
520
|
if (isAddingDep) {
|
|
431
521
|
return [
|
|
432
522
|
{ key: "type", desc: "search" },
|
|
@@ -513,7 +603,8 @@ function getKeyHints(state) {
|
|
|
513
603
|
}
|
|
514
604
|
if (activeView === ViewType.TaskCreate || activeView === ViewType.TaskEdit) {
|
|
515
605
|
return [
|
|
516
|
-
{ key: "tab", desc: "
|
|
606
|
+
{ key: "\u2191\u2193/tab", desc: "navigate" },
|
|
607
|
+
{ key: "\u2190\u2192", desc: "cursor" },
|
|
517
608
|
{ key: "ctrl+s", desc: "save" },
|
|
518
609
|
{ key: "esc", desc: "cancel" }
|
|
519
610
|
];
|
|
@@ -522,6 +613,7 @@ function getKeyHints(state) {
|
|
|
522
613
|
return [
|
|
523
614
|
{ key: "j/k", desc: "nav" },
|
|
524
615
|
{ key: "enter", desc: "select" },
|
|
616
|
+
{ key: "e", desc: "edit" },
|
|
525
617
|
{ key: "c", desc: "create" },
|
|
526
618
|
{ key: "l", desc: "link" },
|
|
527
619
|
{ key: "d", desc: "default" },
|
|
@@ -555,40 +647,47 @@ function Header({ state, latestVersion }) {
|
|
|
555
647
|
const hints = getKeyHints(state);
|
|
556
648
|
const hintCols = hints.length <= 7 ? 2 : hints.length <= 12 ? 3 : 4;
|
|
557
649
|
const columns = chunkHints(hints, hintCols);
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
/* @__PURE__ */
|
|
561
|
-
|
|
562
|
-
/* @__PURE__ */
|
|
563
|
-
|
|
564
|
-
/* @__PURE__ */
|
|
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 })
|
|
565
658
|
] }),
|
|
566
|
-
/* @__PURE__ */
|
|
567
|
-
/* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
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 })
|
|
569
662
|
] }),
|
|
570
|
-
latestVersion && /* @__PURE__ */
|
|
571
|
-
/* @__PURE__ */
|
|
663
|
+
latestVersion && /* @__PURE__ */ jsxs2(Box3, { gap: 1, children: [
|
|
664
|
+
/* @__PURE__ */ jsxs2(Text3, { color: theme.flash.warn, children: [
|
|
572
665
|
"Update ",
|
|
573
666
|
latestVersion
|
|
574
667
|
] }),
|
|
575
|
-
/* @__PURE__ */
|
|
668
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.fg, children: "\u2014 tayto upgrade" })
|
|
576
669
|
] })
|
|
577
670
|
] }),
|
|
578
|
-
|
|
579
|
-
/* @__PURE__ */
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
">"
|
|
583
|
-
] }),
|
|
584
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.menu.desc, children: h.desc })
|
|
585
|
-
] }, 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 }) })
|
|
586
675
|
] });
|
|
587
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
|
+
}
|
|
588
687
|
|
|
589
688
|
// src/tui/components/Crumbs.tsx
|
|
590
|
-
import { Box as
|
|
591
|
-
import { jsx as
|
|
689
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
690
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
592
691
|
var VIEW_LABELS = {
|
|
593
692
|
"task-list": "tasks",
|
|
594
693
|
"task-detail": "detail",
|
|
@@ -598,11 +697,11 @@ var VIEW_LABELS = {
|
|
|
598
697
|
help: "help"
|
|
599
698
|
};
|
|
600
699
|
function Crumbs({ breadcrumbs }) {
|
|
601
|
-
return /* @__PURE__ */
|
|
700
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "row", gap: 0, width: "100%", children: breadcrumbs.map((crumb, i) => {
|
|
602
701
|
const isActive = i === breadcrumbs.length - 1;
|
|
603
702
|
const label = ` ${VIEW_LABELS[crumb] ?? crumb} `;
|
|
604
|
-
return /* @__PURE__ */
|
|
605
|
-
|
|
703
|
+
return /* @__PURE__ */ jsx4(
|
|
704
|
+
Text4,
|
|
606
705
|
{
|
|
607
706
|
color: theme.crumb.fg,
|
|
608
707
|
backgroundColor: isActive ? theme.crumb.activeBg : theme.crumb.bg,
|
|
@@ -615,20 +714,20 @@ function Crumbs({ breadcrumbs }) {
|
|
|
615
714
|
}
|
|
616
715
|
|
|
617
716
|
// src/tui/components/FlashMessage.tsx
|
|
618
|
-
import { Box as
|
|
619
|
-
import { jsx as
|
|
717
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
718
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
620
719
|
var LEVEL_COLOR = {
|
|
621
720
|
info: theme.flash.info,
|
|
622
721
|
warn: theme.flash.warn,
|
|
623
722
|
error: theme.flash.error
|
|
624
723
|
};
|
|
625
724
|
function FlashMessage({ message, level }) {
|
|
626
|
-
return /* @__PURE__ */
|
|
725
|
+
return /* @__PURE__ */ jsx5(Box5, { justifyContent: "center", width: "100%", children: /* @__PURE__ */ jsx5(Text5, { color: LEVEL_COLOR[level], bold: level === "error", children: message }) });
|
|
627
726
|
}
|
|
628
727
|
|
|
629
728
|
// src/tui/components/TaskList.tsx
|
|
630
|
-
import { Box as
|
|
631
|
-
import { jsx as
|
|
729
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
730
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
632
731
|
var COL = {
|
|
633
732
|
rank: 5,
|
|
634
733
|
type: 12,
|
|
@@ -656,50 +755,50 @@ function TaskList({
|
|
|
656
755
|
if (filter.type) filterParts.push(`type:${filter.type}`);
|
|
657
756
|
if (filter.search) filterParts.push(filter.search);
|
|
658
757
|
const filterText = filterParts.length > 0 ? filterParts.join(" ") : "";
|
|
659
|
-
return /* @__PURE__ */
|
|
660
|
-
|
|
758
|
+
return /* @__PURE__ */ jsxs3(
|
|
759
|
+
Box6,
|
|
661
760
|
{
|
|
662
761
|
flexDirection: "column",
|
|
663
762
|
flexGrow: 1,
|
|
664
763
|
borderStyle: "bold",
|
|
665
764
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
666
765
|
children: [
|
|
667
|
-
/* @__PURE__ */
|
|
668
|
-
/* @__PURE__ */
|
|
766
|
+
/* @__PURE__ */ jsxs3(Box6, { children: [
|
|
767
|
+
/* @__PURE__ */ jsxs3(Text6, { color: theme.title, bold: true, children: [
|
|
669
768
|
" ",
|
|
670
769
|
"tasks"
|
|
671
770
|
] }),
|
|
672
|
-
/* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
675
|
-
/* @__PURE__ */
|
|
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: [
|
|
676
775
|
"[",
|
|
677
776
|
tasks.length,
|
|
678
777
|
"]"
|
|
679
778
|
] }),
|
|
680
|
-
isReordering && /* @__PURE__ */
|
|
779
|
+
isReordering && /* @__PURE__ */ jsxs3(Text6, { color: theme.flash.warn, bold: true, children: [
|
|
681
780
|
" ",
|
|
682
781
|
"REORDER"
|
|
683
782
|
] }),
|
|
684
|
-
epicFilterActive && /* @__PURE__ */
|
|
685
|
-
filterText && /* @__PURE__ */
|
|
783
|
+
epicFilterActive && /* @__PURE__ */ jsx6(Text6, { color: theme.titleHighlight, children: " [epic]" }),
|
|
784
|
+
filterText && /* @__PURE__ */ jsxs3(Text6, { color: theme.titleFilter, children: [
|
|
686
785
|
" /",
|
|
687
786
|
filterText
|
|
688
787
|
] })
|
|
689
788
|
] }),
|
|
690
|
-
isSearchActive && /* @__PURE__ */
|
|
691
|
-
/* @__PURE__ */
|
|
692
|
-
/* @__PURE__ */
|
|
693
|
-
/* @__PURE__ */
|
|
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: "_" })
|
|
694
793
|
] }),
|
|
695
|
-
/* @__PURE__ */
|
|
696
|
-
/* @__PURE__ */
|
|
697
|
-
/* @__PURE__ */
|
|
698
|
-
/* @__PURE__ */
|
|
699
|
-
/* @__PURE__ */
|
|
700
|
-
/* @__PURE__ */
|
|
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" })
|
|
701
800
|
] }),
|
|
702
|
-
/* @__PURE__ */
|
|
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) => {
|
|
703
802
|
const actualIndex = viewStart + i;
|
|
704
803
|
const isSelected = actualIndex === selectedIndex;
|
|
705
804
|
const isNonTerminalBlocker = nonTerminalBlockerIds.has(task.id);
|
|
@@ -709,7 +808,7 @@ function TaskList({
|
|
|
709
808
|
const depMarker = isNonTerminalBlocker ? "\u25B2 " : isNonTerminalDependent ? "\u25BC " : " ";
|
|
710
809
|
if (isSelected) {
|
|
711
810
|
const cursorBg = isReordering ? theme.flash.warn : isSelectedBlocked ? theme.table.blockedCursorBg : theme.table.cursorBg;
|
|
712
|
-
return /* @__PURE__ */
|
|
811
|
+
return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs3(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
713
812
|
isReordering ? "~ " : "> ",
|
|
714
813
|
rowNum.padEnd(COL.rank),
|
|
715
814
|
task.type.padEnd(COL.type),
|
|
@@ -718,7 +817,7 @@ function TaskList({
|
|
|
718
817
|
] }) }, task.id);
|
|
719
818
|
}
|
|
720
819
|
if (isNonTerminalBlocker || isNonTerminalDependent) {
|
|
721
|
-
return /* @__PURE__ */
|
|
820
|
+
return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs3(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: [
|
|
722
821
|
depMarker,
|
|
723
822
|
rowNum.padEnd(COL.rank),
|
|
724
823
|
task.type.padEnd(COL.type),
|
|
@@ -726,15 +825,15 @@ function TaskList({
|
|
|
726
825
|
task.name
|
|
727
826
|
] }) }, task.id);
|
|
728
827
|
}
|
|
729
|
-
return /* @__PURE__ */
|
|
730
|
-
/* @__PURE__ */
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
/* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
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 })
|
|
735
834
|
] }, task.id);
|
|
736
835
|
}) }),
|
|
737
|
-
tasks.length > PAGE_SIZE && /* @__PURE__ */
|
|
836
|
+
tasks.length > PAGE_SIZE && /* @__PURE__ */ jsx6(Box6, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
|
|
738
837
|
"[",
|
|
739
838
|
viewStart + 1,
|
|
740
839
|
"-",
|
|
@@ -749,12 +848,12 @@ function TaskList({
|
|
|
749
848
|
}
|
|
750
849
|
|
|
751
850
|
// src/tui/components/TaskDetail.tsx
|
|
752
|
-
import { useMemo } from "react";
|
|
753
|
-
import { Box as
|
|
851
|
+
import { useMemo as useMemo2 } from "react";
|
|
852
|
+
import { Box as Box8, Text as Text8, useStdout } from "ink";
|
|
754
853
|
import chalk2 from "chalk";
|
|
755
854
|
|
|
756
855
|
// src/tui/components/Markdown.tsx
|
|
757
|
-
import { Text as
|
|
856
|
+
import { Text as Text7, Box as Box7 } from "ink";
|
|
758
857
|
import { Marked } from "marked";
|
|
759
858
|
import { markedTerminal } from "marked-terminal";
|
|
760
859
|
import chalk from "chalk";
|
|
@@ -790,7 +889,7 @@ mermaid.initialize({ startOnLoad: true, theme: 'dark' });
|
|
|
790
889
|
}
|
|
791
890
|
|
|
792
891
|
// src/tui/components/Markdown.tsx
|
|
793
|
-
import { jsx as
|
|
892
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
794
893
|
function extractMermaidBlocks(content) {
|
|
795
894
|
const lexer = new Marked();
|
|
796
895
|
const tokens = lexer.lexer(content);
|
|
@@ -851,12 +950,12 @@ function renderMarkdown(content) {
|
|
|
851
950
|
function MermaidHint({ content }) {
|
|
852
951
|
const blocks = extractMermaidBlocks(content);
|
|
853
952
|
if (blocks.length === 0) return null;
|
|
854
|
-
return /* @__PURE__ */
|
|
855
|
-
/* @__PURE__ */
|
|
953
|
+
return /* @__PURE__ */ jsxs4(Box7, { children: [
|
|
954
|
+
/* @__PURE__ */ jsxs4(Text7, { color: theme.menu.key, bold: true, children: [
|
|
856
955
|
"<m>",
|
|
857
956
|
" "
|
|
858
957
|
] }),
|
|
859
|
-
/* @__PURE__ */
|
|
958
|
+
/* @__PURE__ */ jsxs4(Text7, { dimColor: true, children: [
|
|
860
959
|
"Open ",
|
|
861
960
|
blocks.length,
|
|
862
961
|
" mermaid diagram",
|
|
@@ -874,7 +973,7 @@ function openAllMermaidDiagrams(content) {
|
|
|
874
973
|
}
|
|
875
974
|
|
|
876
975
|
// src/tui/components/TaskDetail.tsx
|
|
877
|
-
import { jsx as
|
|
976
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
878
977
|
var PAD = " ";
|
|
879
978
|
function field(label, value) {
|
|
880
979
|
return PAD + chalk2.hex(theme.yaml.key).bold(label) + chalk2.hex(theme.yaml.colon)(": ") + chalk2.hex(theme.yaml.value)(value);
|
|
@@ -950,44 +1049,44 @@ function TaskDetail({
|
|
|
950
1049
|
const allText = `${task.description}
|
|
951
1050
|
${task.technicalNotes}
|
|
952
1051
|
${task.additionalRequirements}`;
|
|
953
|
-
const contentLines =
|
|
1052
|
+
const contentLines = useMemo2(
|
|
954
1053
|
() => buildContentLines(task, blockers, dependents, related, duplicates),
|
|
955
1054
|
[task, blockers, dependents, related, duplicates]
|
|
956
1055
|
);
|
|
957
1056
|
const viewportHeight = Math.max(1, (stdout.rows > 0 ? stdout.rows : 24) - CHROME_LINES);
|
|
958
1057
|
const visibleLines = contentLines.slice(scrollOffset, scrollOffset + viewportHeight);
|
|
959
|
-
return /* @__PURE__ */
|
|
960
|
-
|
|
1058
|
+
return /* @__PURE__ */ jsxs5(
|
|
1059
|
+
Box8,
|
|
961
1060
|
{
|
|
962
1061
|
flexDirection: "column",
|
|
963
1062
|
flexGrow: 1,
|
|
964
1063
|
borderStyle: "bold",
|
|
965
1064
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
966
1065
|
children: [
|
|
967
|
-
/* @__PURE__ */
|
|
968
|
-
/* @__PURE__ */
|
|
1066
|
+
/* @__PURE__ */ jsxs5(Box8, { gap: 0, children: [
|
|
1067
|
+
/* @__PURE__ */ jsxs5(Text8, { color: theme.title, bold: true, children: [
|
|
969
1068
|
" ",
|
|
970
1069
|
"detail"
|
|
971
1070
|
] }),
|
|
972
|
-
/* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
974
|
-
/* @__PURE__ */
|
|
975
|
-
scrollOffset > 0 && /* @__PURE__ */
|
|
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: [
|
|
976
1075
|
" \u2191",
|
|
977
1076
|
scrollOffset
|
|
978
1077
|
] })
|
|
979
1078
|
] }),
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
/* @__PURE__ */
|
|
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 }) })
|
|
983
1082
|
]
|
|
984
1083
|
}
|
|
985
1084
|
);
|
|
986
1085
|
}
|
|
987
1086
|
|
|
988
1087
|
// src/tui/components/TaskForm.tsx
|
|
989
|
-
import { useState as
|
|
990
|
-
import { Box as
|
|
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";
|
|
991
1090
|
|
|
992
1091
|
// src/tui/editor.ts
|
|
993
1092
|
import { writeFileSync as writeFileSync2, readFileSync, unlinkSync, mkdtempSync as mkdtempSync2 } from "fs";
|
|
@@ -997,15 +1096,17 @@ import { spawnSync } from "child_process";
|
|
|
997
1096
|
function getEditor() {
|
|
998
1097
|
return process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
|
|
999
1098
|
}
|
|
1000
|
-
function openInEditor(content, filename) {
|
|
1099
|
+
function openInEditor(content, filename, options) {
|
|
1001
1100
|
const dir = mkdtempSync2(join2(tmpdir2(), "task-"));
|
|
1002
1101
|
const filepath = join2(dir, filename);
|
|
1003
1102
|
writeFileSync2(filepath, content, "utf-8");
|
|
1004
1103
|
const editor = getEditor();
|
|
1104
|
+
options?.beforeOpen?.();
|
|
1005
1105
|
const result = spawnSync(editor, [filepath], {
|
|
1006
1106
|
stdio: "inherit",
|
|
1007
1107
|
shell: true
|
|
1008
1108
|
});
|
|
1109
|
+
options?.afterOpen?.();
|
|
1009
1110
|
if (result.status !== 0) {
|
|
1010
1111
|
try {
|
|
1011
1112
|
unlinkSync(filepath);
|
|
@@ -1023,9 +1124,9 @@ function openInEditor(content, filename) {
|
|
|
1023
1124
|
}
|
|
1024
1125
|
|
|
1025
1126
|
// src/tui/components/TaskPicker.tsx
|
|
1026
|
-
import { useState } from "react";
|
|
1027
|
-
import { Box as
|
|
1028
|
-
import { Fragment, jsx as
|
|
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";
|
|
1029
1130
|
var DEP_TYPE_VALUES = Object.values(UIDependencyType);
|
|
1030
1131
|
var DEP_TYPE_COLOR = {
|
|
1031
1132
|
[DependencyType.Blocks]: theme.status.error,
|
|
@@ -1037,10 +1138,10 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1037
1138
|
const { stdout } = useStdout2();
|
|
1038
1139
|
const termHeight = stdout.rows > 0 ? stdout.rows : 24;
|
|
1039
1140
|
const maxVisible = Math.max(3, termHeight - 12);
|
|
1040
|
-
const [searchQuery, setSearchQuery] =
|
|
1041
|
-
const [isSearching, setIsSearching] =
|
|
1042
|
-
const [cursorIndex, setCursorIndex] =
|
|
1043
|
-
const [selected, setSelected] =
|
|
1141
|
+
const [searchQuery, setSearchQuery] = useState2("");
|
|
1142
|
+
const [isSearching, setIsSearching] = useState2(false);
|
|
1143
|
+
const [cursorIndex, setCursorIndex] = useState2(0);
|
|
1144
|
+
const [selected, setSelected] = useState2(() => {
|
|
1044
1145
|
const map = /* @__PURE__ */ new Map();
|
|
1045
1146
|
if (initialSelection) {
|
|
1046
1147
|
for (const dep of initialSelection) {
|
|
@@ -1139,28 +1240,28 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1139
1240
|
return;
|
|
1140
1241
|
}
|
|
1141
1242
|
});
|
|
1142
|
-
return /* @__PURE__ */
|
|
1143
|
-
/* @__PURE__ */
|
|
1144
|
-
/* @__PURE__ */
|
|
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: [
|
|
1145
1246
|
" ",
|
|
1146
1247
|
"select dependencies"
|
|
1147
1248
|
] }),
|
|
1148
|
-
/* @__PURE__ */
|
|
1249
|
+
/* @__PURE__ */ jsxs6(Text9, { color: theme.titleCounter, bold: true, children: [
|
|
1149
1250
|
" ",
|
|
1150
1251
|
"[",
|
|
1151
1252
|
selected.size,
|
|
1152
1253
|
" selected]"
|
|
1153
1254
|
] })
|
|
1154
1255
|
] }),
|
|
1155
|
-
isSearching ? /* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
] }) : searchQuery ? /* @__PURE__ */
|
|
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: [
|
|
1160
1261
|
"/",
|
|
1161
1262
|
searchQuery
|
|
1162
1263
|
] }) }) : null,
|
|
1163
|
-
/* @__PURE__ */
|
|
1264
|
+
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs6(Text9, { color: theme.table.headerFg, bold: true, children: [
|
|
1164
1265
|
" ",
|
|
1165
1266
|
"SEL".padEnd(5),
|
|
1166
1267
|
"ID".padEnd(14),
|
|
@@ -1168,7 +1269,7 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1168
1269
|
"STATUS".padEnd(14),
|
|
1169
1270
|
"NAME"
|
|
1170
1271
|
] }) }),
|
|
1171
|
-
available.length === 0 ? /* @__PURE__ */
|
|
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) => {
|
|
1172
1273
|
const actualIndex = viewStart + i;
|
|
1173
1274
|
const isCursor = actualIndex === cursorIndex;
|
|
1174
1275
|
const entry = selected.get(task.id);
|
|
@@ -1176,24 +1277,24 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1176
1277
|
const checkMark = isChecked ? "[x]" : "[ ]";
|
|
1177
1278
|
const depType = entry ? DEP_TYPE_LABEL[entry.type] ?? entry.type : "";
|
|
1178
1279
|
const depColor = entry ? DEP_TYPE_COLOR[entry.type] ?? theme.table.fg : theme.table.fg;
|
|
1179
|
-
return /* @__PURE__ */
|
|
1280
|
+
return /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs6(Text9, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1180
1281
|
"> ",
|
|
1181
1282
|
checkMark.padEnd(5),
|
|
1182
1283
|
task.id.padEnd(14),
|
|
1183
1284
|
depType.padEnd(12),
|
|
1184
1285
|
task.status.padEnd(14),
|
|
1185
1286
|
task.name
|
|
1186
|
-
] }) : /* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1189
|
-
/* @__PURE__ */
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1192
|
-
/* @__PURE__ */
|
|
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 })
|
|
1193
1294
|
] }) }, task.id);
|
|
1194
1295
|
}),
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
available.length > maxVisible && /* @__PURE__ */
|
|
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: [
|
|
1197
1298
|
"[",
|
|
1198
1299
|
viewStart + 1,
|
|
1199
1300
|
"-",
|
|
@@ -1202,11 +1303,11 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1202
1303
|
available.length,
|
|
1203
1304
|
"]"
|
|
1204
1305
|
] }) }),
|
|
1205
|
-
selected.size > 0 && /* @__PURE__ */
|
|
1206
|
-
/* @__PURE__ */
|
|
1207
|
-
/* @__PURE__ */
|
|
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(", ") }) })
|
|
1208
1309
|
] }),
|
|
1209
|
-
/* @__PURE__ */
|
|
1310
|
+
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs6(Text9, { dimColor: true, children: [
|
|
1210
1311
|
"space/t: select & cycle type (blocks ",
|
|
1211
1312
|
"->",
|
|
1212
1313
|
" relates-to ",
|
|
@@ -1222,7 +1323,7 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1222
1323
|
}
|
|
1223
1324
|
|
|
1224
1325
|
// src/tui/components/TaskForm.tsx
|
|
1225
|
-
import { jsx as
|
|
1326
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1226
1327
|
var FIELDS = [
|
|
1227
1328
|
{ label: "Name", key: "name", type: "inline" },
|
|
1228
1329
|
{ label: "Type", key: "type", type: "select", options: TYPE_VALUES },
|
|
@@ -1243,8 +1344,8 @@ var FIELDS = [
|
|
|
1243
1344
|
}
|
|
1244
1345
|
];
|
|
1245
1346
|
function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
|
|
1246
|
-
const [focusIndex, setFocusIndex] =
|
|
1247
|
-
const [values, setValues] =
|
|
1347
|
+
const [focusIndex, setFocusIndex] = useState3(0);
|
|
1348
|
+
const [values, setValues] = useState3({
|
|
1248
1349
|
name: editingTask?.name ?? "",
|
|
1249
1350
|
type: editingTask?.type ?? TaskType.Story,
|
|
1250
1351
|
status: editingTask?.status ?? TaskStatus.Backlog,
|
|
@@ -1252,23 +1353,42 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
|
|
|
1252
1353
|
technicalNotes: editingTask?.technicalNotes ?? "",
|
|
1253
1354
|
additionalRequirements: editingTask?.additionalRequirements ?? ""
|
|
1254
1355
|
});
|
|
1255
|
-
const [
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1356
|
+
const [cursorPos, setCursorPos] = useState3(() => (editingTask?.name ?? "").length);
|
|
1357
|
+
const cursorRef = useRef(cursorPos);
|
|
1358
|
+
cursorRef.current = cursorPos;
|
|
1359
|
+
const [editorActive, setEditorActive] = useState3(false);
|
|
1360
|
+
const [pickerActive, setPickerActive] = useState3(false);
|
|
1361
|
+
const [pickedDeps, setPickedDeps] = useState3(initialDeps ?? []);
|
|
1362
|
+
const { setRawMode } = useStdin();
|
|
1363
|
+
useEffect2(() => {
|
|
1364
|
+
const field2 = FIELDS[focusIndex];
|
|
1365
|
+
if (field2?.type === "inline") {
|
|
1366
|
+
const pos = values[field2.key]?.length ?? 0;
|
|
1367
|
+
setCursorPos(pos);
|
|
1368
|
+
cursorRef.current = pos;
|
|
1369
|
+
}
|
|
1370
|
+
}, [focusIndex]);
|
|
1258
1371
|
const currentField = FIELDS[focusIndex];
|
|
1259
1372
|
const launchEditor = useCallback(
|
|
1260
1373
|
(field2) => {
|
|
1261
1374
|
setEditorActive(true);
|
|
1262
1375
|
setTimeout(() => {
|
|
1263
1376
|
const content = values[field2.key] ?? "";
|
|
1264
|
-
const result = openInEditor(content, field2.editorFilename ?? `${field2.key}.md
|
|
1377
|
+
const result = openInEditor(content, field2.editorFilename ?? `${field2.key}.md`, {
|
|
1378
|
+
beforeOpen: () => {
|
|
1379
|
+
setRawMode(false);
|
|
1380
|
+
},
|
|
1381
|
+
afterOpen: () => {
|
|
1382
|
+
setRawMode(true);
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1265
1385
|
if (result !== null) {
|
|
1266
1386
|
setValues((v) => ({ ...v, [field2.key]: result }));
|
|
1267
1387
|
}
|
|
1268
1388
|
setEditorActive(false);
|
|
1269
1389
|
}, 50);
|
|
1270
1390
|
},
|
|
1271
|
-
[values]
|
|
1391
|
+
[values, setRawMode]
|
|
1272
1392
|
);
|
|
1273
1393
|
const handlePickerConfirm = useCallback((selected) => {
|
|
1274
1394
|
setPickedDeps(selected);
|
|
@@ -1308,32 +1428,49 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
|
|
|
1308
1428
|
}
|
|
1309
1429
|
return;
|
|
1310
1430
|
}
|
|
1431
|
+
if (key.upArrow) {
|
|
1432
|
+
setFocusIndex((i) => Math.max(0, i - 1));
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
if (key.downArrow) {
|
|
1436
|
+
setFocusIndex((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1311
1439
|
if (currentField.type === "inline") {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1440
|
+
if (key.leftArrow) {
|
|
1441
|
+
setCursorPos((p) => Math.max(0, p - 1));
|
|
1442
|
+
} else if (key.rightArrow) {
|
|
1443
|
+
setCursorPos((p) => Math.min((values[currentField.key] ?? "").length, p + 1));
|
|
1444
|
+
} else if (key.backspace || key.delete) {
|
|
1445
|
+
const pos = cursorRef.current;
|
|
1446
|
+
if (pos > 0) {
|
|
1447
|
+
setValues((v) => {
|
|
1448
|
+
const cur = v[currentField.key] ?? "";
|
|
1449
|
+
return { ...v, [currentField.key]: cur.slice(0, pos - 1) + cur.slice(pos) };
|
|
1450
|
+
});
|
|
1451
|
+
cursorRef.current = pos - 1;
|
|
1452
|
+
setCursorPos(pos - 1);
|
|
1453
|
+
}
|
|
1315
1454
|
} else if (key.return) {
|
|
1316
1455
|
setFocusIndex((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1317
1456
|
} else if (input && !key.ctrl && !key.meta) {
|
|
1318
|
-
|
|
1457
|
+
const pos = cursorRef.current;
|
|
1458
|
+
setValues((v) => {
|
|
1459
|
+
const cur = v[currentField.key] ?? "";
|
|
1460
|
+
return { ...v, [currentField.key]: cur.slice(0, pos) + input + cur.slice(pos) };
|
|
1461
|
+
});
|
|
1462
|
+
cursorRef.current = pos + input.length;
|
|
1463
|
+
setCursorPos(pos + input.length);
|
|
1319
1464
|
}
|
|
1320
1465
|
}
|
|
1321
1466
|
if (currentField.type === "picker") {
|
|
1322
1467
|
if (key.return) {
|
|
1323
1468
|
setPickerActive(true);
|
|
1324
|
-
} else if (key.downArrow) {
|
|
1325
|
-
setFocusIndex((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1326
|
-
} else if (key.upArrow) {
|
|
1327
|
-
setFocusIndex((i) => Math.max(0, i - 1));
|
|
1328
1469
|
}
|
|
1329
1470
|
}
|
|
1330
1471
|
if (currentField.type === "editor") {
|
|
1331
1472
|
if (key.return) {
|
|
1332
1473
|
launchEditor(currentField);
|
|
1333
|
-
} else if (key.downArrow) {
|
|
1334
|
-
setFocusIndex((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1335
|
-
} else if (key.upArrow) {
|
|
1336
|
-
setFocusIndex((i) => Math.max(0, i - 1));
|
|
1337
1474
|
}
|
|
1338
1475
|
}
|
|
1339
1476
|
if (currentField.type === "select") {
|
|
@@ -1353,7 +1490,7 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
|
|
|
1353
1490
|
);
|
|
1354
1491
|
if (pickerActive) {
|
|
1355
1492
|
const pickerExclude = editingTask ? { excludeIds: /* @__PURE__ */ new Set([editingTask.id]) } : {};
|
|
1356
|
-
return /* @__PURE__ */
|
|
1493
|
+
return /* @__PURE__ */ jsx10(
|
|
1357
1494
|
TaskPicker,
|
|
1358
1495
|
{
|
|
1359
1496
|
tasks: allTasks,
|
|
@@ -1366,63 +1503,64 @@ function TaskForm({ editingTask, allTasks, initialDeps, onSave, onCancel }) {
|
|
|
1366
1503
|
}
|
|
1367
1504
|
const isEdit = editingTask !== null;
|
|
1368
1505
|
const depSummary = pickedDeps.length > 0 ? pickedDeps.map((d) => `${d.id} (${DEP_TYPE_LABEL[d.type] ?? d.type})`).join(", ") : "";
|
|
1369
|
-
return /* @__PURE__ */
|
|
1370
|
-
/* @__PURE__ */
|
|
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: [
|
|
1371
1508
|
" ",
|
|
1372
1509
|
isEdit ? "edit" : "create"
|
|
1373
1510
|
] }) }),
|
|
1374
|
-
/* @__PURE__ */
|
|
1511
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS.map((field2, i) => {
|
|
1375
1512
|
const isFocused = i === focusIndex;
|
|
1376
1513
|
const value = field2.key === "dependsOn" ? depSummary : values[field2.key] ?? "";
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
/* @__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: [
|
|
1380
1516
|
isFocused ? ">" : " ",
|
|
1381
1517
|
" ",
|
|
1382
1518
|
field2.label.padEnd(14)
|
|
1383
1519
|
] }),
|
|
1384
|
-
field2.type === "inline" && /* @__PURE__ */
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1520
|
+
field2.type === "inline" && /* @__PURE__ */ jsx10(Text10, { color: isFocused ? theme.yaml.value : theme.table.fg, children: isFocused ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1521
|
+
value.slice(0, cursorPos),
|
|
1522
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.titleHighlight, children: "_" }),
|
|
1523
|
+
value.slice(cursorPos)
|
|
1524
|
+
] }) : value }),
|
|
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]" })
|
|
1391
1528
|
] }),
|
|
1392
|
-
field2.type === "editor" && /* @__PURE__ */
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
] }) : /* @__PURE__ */
|
|
1397
|
-
isFocused && /* @__PURE__ */
|
|
1529
|
+
field2.type === "editor" && /* @__PURE__ */ jsxs7(Text10, { children: [
|
|
1530
|
+
value ? /* @__PURE__ */ jsxs7(Text10, { color: theme.status.added, children: [
|
|
1531
|
+
value.split("\n")[0]?.slice(0, 50),
|
|
1532
|
+
value.length > 50 || value.includes("\n") ? "..." : ""
|
|
1533
|
+
] }) : /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: isFocused ? "press enter" : "empty" }),
|
|
1534
|
+
isFocused && /* @__PURE__ */ jsx10(Text10, { color: theme.menu.key, children: " [enter: $EDITOR]" })
|
|
1398
1535
|
] }),
|
|
1399
|
-
field2.type === "select" && /* @__PURE__ */
|
|
1536
|
+
field2.type === "select" && /* @__PURE__ */ jsxs7(Text10, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
|
|
1400
1537
|
isFocused ? "< " : " ",
|
|
1401
|
-
|
|
1538
|
+
value,
|
|
1402
1539
|
isFocused ? " >" : ""
|
|
1403
1540
|
] })
|
|
1404
1541
|
] }, field2.key);
|
|
1405
1542
|
}) }),
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
editorActive && /* @__PURE__ */
|
|
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" }) })
|
|
1409
1546
|
] });
|
|
1410
1547
|
}
|
|
1411
1548
|
|
|
1412
1549
|
// src/tui/components/ProjectSelector.tsx
|
|
1413
|
-
import { useState as
|
|
1414
|
-
import { Box as
|
|
1415
|
-
import { jsx as
|
|
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";
|
|
1416
1553
|
function ProjectSelector({
|
|
1417
1554
|
projects,
|
|
1418
1555
|
activeProject,
|
|
1419
1556
|
onSelect,
|
|
1420
1557
|
onCreate,
|
|
1558
|
+
onEdit,
|
|
1421
1559
|
onSetDefault,
|
|
1422
1560
|
onLink,
|
|
1423
1561
|
onCancel
|
|
1424
1562
|
}) {
|
|
1425
|
-
const [selectedIndex, setSelectedIndex] =
|
|
1563
|
+
const [selectedIndex, setSelectedIndex] = useState4(() => {
|
|
1426
1564
|
if (!activeProject) return 0;
|
|
1427
1565
|
const idx = projects.findIndex((p) => p.id === activeProject.id);
|
|
1428
1566
|
return idx >= 0 ? idx : 0;
|
|
@@ -1443,6 +1581,13 @@ function ProjectSelector({
|
|
|
1443
1581
|
onCreate();
|
|
1444
1582
|
return;
|
|
1445
1583
|
}
|
|
1584
|
+
if (input === "e") {
|
|
1585
|
+
const project = projects[selectedIndex];
|
|
1586
|
+
if (project) {
|
|
1587
|
+
onEdit(project);
|
|
1588
|
+
}
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1446
1591
|
if (input === "d") {
|
|
1447
1592
|
const project = projects[selectedIndex];
|
|
1448
1593
|
if (project) {
|
|
@@ -1464,32 +1609,32 @@ function ProjectSelector({
|
|
|
1464
1609
|
setSelectedIndex((i) => Math.min(projects.length - 1, i + 1));
|
|
1465
1610
|
}
|
|
1466
1611
|
});
|
|
1467
|
-
return /* @__PURE__ */
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
/* @__PURE__ */
|
|
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: [
|
|
1470
1615
|
" ",
|
|
1471
1616
|
"projects"
|
|
1472
1617
|
] }),
|
|
1473
|
-
/* @__PURE__ */
|
|
1618
|
+
/* @__PURE__ */ jsxs8(Text11, { color: theme.titleCounter, bold: true, children: [
|
|
1474
1619
|
"[",
|
|
1475
1620
|
projects.length,
|
|
1476
1621
|
"]"
|
|
1477
1622
|
] })
|
|
1478
1623
|
] }),
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
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" })
|
|
1483
1628
|
] }),
|
|
1484
|
-
projects.length === 0 ? /* @__PURE__ */
|
|
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) => {
|
|
1485
1630
|
const isSelected = i === selectedIndex;
|
|
1486
1631
|
const isActive = project.id === activeProject?.id;
|
|
1487
1632
|
const activeMarker = isActive ? "*" : " ";
|
|
1488
1633
|
const defaultMarker = project.isDefault ? "D" : " ";
|
|
1489
1634
|
const marker = `${activeMarker}${defaultMarker}`;
|
|
1490
|
-
const remoteDisplay = (project.gitRemote ?? "").slice(0, 38).padEnd(40);
|
|
1635
|
+
const remoteDisplay = (project.gitRemote?.value ?? "").slice(0, 38).padEnd(40);
|
|
1491
1636
|
if (isSelected) {
|
|
1492
|
-
return /* @__PURE__ */
|
|
1637
|
+
return /* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsxs8(Text11, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1493
1638
|
marker,
|
|
1494
1639
|
" ",
|
|
1495
1640
|
project.name.padEnd(27),
|
|
@@ -1497,39 +1642,64 @@ function ProjectSelector({
|
|
|
1497
1642
|
project.description
|
|
1498
1643
|
] }) }, project.id);
|
|
1499
1644
|
}
|
|
1500
|
-
return /* @__PURE__ */
|
|
1501
|
-
/* @__PURE__ */
|
|
1645
|
+
return /* @__PURE__ */ jsxs8(Box11, { paddingX: 1, children: [
|
|
1646
|
+
/* @__PURE__ */ jsxs8(Text11, { color: isActive ? theme.status.modified : theme.table.fg, children: [
|
|
1502
1647
|
marker,
|
|
1503
1648
|
" ",
|
|
1504
1649
|
project.name.padEnd(27)
|
|
1505
1650
|
] }),
|
|
1506
|
-
/* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1651
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: remoteDisplay }),
|
|
1652
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: project.description })
|
|
1508
1653
|
] }, project.id);
|
|
1509
1654
|
}),
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
1512
1657
|
] });
|
|
1513
1658
|
}
|
|
1514
1659
|
|
|
1515
1660
|
// src/tui/components/ProjectForm.tsx
|
|
1516
|
-
import { useState as
|
|
1517
|
-
import { Box as
|
|
1518
|
-
import { jsx as
|
|
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";
|
|
1519
1664
|
var FIELDS2 = [
|
|
1520
1665
|
{ label: "Name", key: "name", type: "inline" },
|
|
1521
1666
|
{ label: "Key", key: "key", type: "inline" },
|
|
1522
1667
|
{ label: "Description", key: "description", type: "inline" },
|
|
1668
|
+
{ label: "Git Remote", key: "gitRemote", type: "inline" },
|
|
1523
1669
|
{ label: "Default", key: "isDefault", type: "toggle" }
|
|
1524
1670
|
];
|
|
1525
|
-
function ProjectForm({ onSave, onCancel }) {
|
|
1526
|
-
const
|
|
1527
|
-
const [
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1671
|
+
function ProjectForm({ editingProject, initialGitRemote, onSave, onCancel }) {
|
|
1672
|
+
const isEditing = !!editingProject;
|
|
1673
|
+
const [focusIndex, setFocusIndex] = useState5(0);
|
|
1674
|
+
const [values, setValues] = useState5(() => {
|
|
1675
|
+
if (editingProject) {
|
|
1676
|
+
return {
|
|
1677
|
+
name: editingProject.name,
|
|
1678
|
+
key: editingProject.key,
|
|
1679
|
+
description: editingProject.description,
|
|
1680
|
+
gitRemote: editingProject.gitRemote?.value ?? "",
|
|
1681
|
+
isDefault: editingProject.isDefault ? "yes" : "no"
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
return {
|
|
1685
|
+
name: "",
|
|
1686
|
+
key: "",
|
|
1687
|
+
description: "",
|
|
1688
|
+
gitRemote: initialGitRemote?.value ?? "",
|
|
1689
|
+
isDefault: "no"
|
|
1690
|
+
};
|
|
1532
1691
|
});
|
|
1692
|
+
const [cursorPos, setCursorPos] = useState5(0);
|
|
1693
|
+
const cursorRef = useRef2(cursorPos);
|
|
1694
|
+
cursorRef.current = cursorPos;
|
|
1695
|
+
useEffect3(() => {
|
|
1696
|
+
const field2 = FIELDS2[focusIndex];
|
|
1697
|
+
if (field2?.type === "inline") {
|
|
1698
|
+
const pos = values[field2.key]?.length ?? 0;
|
|
1699
|
+
setCursorPos(pos);
|
|
1700
|
+
cursorRef.current = pos;
|
|
1701
|
+
}
|
|
1702
|
+
}, [focusIndex]);
|
|
1533
1703
|
const currentField = FIELDS2[focusIndex];
|
|
1534
1704
|
useInput4((input, key) => {
|
|
1535
1705
|
if (key.escape) {
|
|
@@ -1552,19 +1722,46 @@ function ProjectForm({ onSave, onCancel }) {
|
|
|
1552
1722
|
name: nameVal,
|
|
1553
1723
|
key: values["key"] ?? "",
|
|
1554
1724
|
description: values["description"] ?? "",
|
|
1725
|
+
gitRemote: values["gitRemote"] ?? "",
|
|
1555
1726
|
isDefault: values["isDefault"] === "yes"
|
|
1556
1727
|
});
|
|
1557
1728
|
}
|
|
1558
1729
|
return;
|
|
1559
1730
|
}
|
|
1560
|
-
if (
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1731
|
+
if (key.upArrow) {
|
|
1732
|
+
setFocusIndex((i) => Math.max(0, i - 1));
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
if (key.downArrow) {
|
|
1736
|
+
setFocusIndex((i) => Math.min(FIELDS2.length - 1, i + 1));
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
const isReadOnly = isEditing && currentField.key === "key";
|
|
1740
|
+
if (currentField.type === "inline" && !isReadOnly) {
|
|
1741
|
+
if (key.leftArrow) {
|
|
1742
|
+
setCursorPos((p) => Math.max(0, p - 1));
|
|
1743
|
+
} else if (key.rightArrow) {
|
|
1744
|
+
setCursorPos((p) => Math.min((values[currentField.key] ?? "").length, p + 1));
|
|
1745
|
+
} else if (key.backspace || key.delete) {
|
|
1746
|
+
const pos = cursorRef.current;
|
|
1747
|
+
if (pos > 0) {
|
|
1748
|
+
setValues((v) => {
|
|
1749
|
+
const cur = v[currentField.key] ?? "";
|
|
1750
|
+
return { ...v, [currentField.key]: cur.slice(0, pos - 1) + cur.slice(pos) };
|
|
1751
|
+
});
|
|
1752
|
+
cursorRef.current = pos - 1;
|
|
1753
|
+
setCursorPos(pos - 1);
|
|
1754
|
+
}
|
|
1564
1755
|
} else if (key.return) {
|
|
1565
1756
|
setFocusIndex((i) => Math.min(FIELDS2.length - 1, i + 1));
|
|
1566
1757
|
} else if (input && !key.ctrl && !key.meta) {
|
|
1567
|
-
|
|
1758
|
+
const pos = cursorRef.current;
|
|
1759
|
+
setValues((v) => {
|
|
1760
|
+
const cur = v[currentField.key] ?? "";
|
|
1761
|
+
return { ...v, [currentField.key]: cur.slice(0, pos) + input + cur.slice(pos) };
|
|
1762
|
+
});
|
|
1763
|
+
cursorRef.current = pos + input.length;
|
|
1764
|
+
setCursorPos(pos + input.length);
|
|
1568
1765
|
}
|
|
1569
1766
|
}
|
|
1570
1767
|
if (currentField.type === "toggle") {
|
|
@@ -1576,43 +1773,50 @@ function ProjectForm({ onSave, onCancel }) {
|
|
|
1576
1773
|
}
|
|
1577
1774
|
}
|
|
1578
1775
|
});
|
|
1579
|
-
return /* @__PURE__ */
|
|
1580
|
-
/* @__PURE__ */
|
|
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: [
|
|
1581
1778
|
" ",
|
|
1582
|
-
"new project"
|
|
1779
|
+
isEditing ? "edit project" : "new project"
|
|
1583
1780
|
] }) }),
|
|
1584
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsx12(Box12, { flexDirection: "column", paddingX: 1, paddingY: 0, children: FIELDS2.map((field2, i) => {
|
|
1585
1782
|
const isFocused = i === focusIndex;
|
|
1586
1783
|
const value = values[field2.key] ?? "";
|
|
1587
|
-
return /* @__PURE__ */
|
|
1588
|
-
/* @__PURE__ */
|
|
1784
|
+
return /* @__PURE__ */ jsxs9(Box12, { gap: 1, children: [
|
|
1785
|
+
/* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.dialog.label : theme.yaml.key, bold: isFocused, children: [
|
|
1589
1786
|
isFocused ? ">" : " ",
|
|
1590
1787
|
" ",
|
|
1591
1788
|
field2.label.padEnd(14)
|
|
1592
1789
|
] }),
|
|
1593
|
-
field2.type === "inline" && /* @__PURE__ */
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1790
|
+
field2.type === "inline" && /* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
|
|
1791
|
+
isFocused ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1792
|
+
value.slice(0, cursorPos),
|
|
1793
|
+
/* @__PURE__ */ jsx12(Text12, { color: theme.titleHighlight, children: "_" }),
|
|
1794
|
+
value.slice(cursorPos)
|
|
1795
|
+
] }) : value,
|
|
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)" })
|
|
1597
1798
|
] }),
|
|
1598
|
-
field2.type === "toggle" && /* @__PURE__ */
|
|
1799
|
+
field2.type === "toggle" && /* @__PURE__ */ jsxs9(Text12, { color: isFocused ? theme.yaml.value : theme.table.fg, children: [
|
|
1599
1800
|
isFocused ? "< " : " ",
|
|
1600
1801
|
value,
|
|
1601
1802
|
isFocused ? " >" : ""
|
|
1602
1803
|
] })
|
|
1603
1804
|
] }, field2.key);
|
|
1604
1805
|
}) }),
|
|
1605
|
-
/* @__PURE__ */
|
|
1606
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
1607
1808
|
] });
|
|
1608
1809
|
}
|
|
1609
1810
|
|
|
1610
1811
|
// src/tui/components/ProjectLinkForm.tsx
|
|
1611
|
-
import { useState as
|
|
1612
|
-
import { Box as
|
|
1613
|
-
import { jsx as
|
|
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";
|
|
1614
1815
|
function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
|
|
1615
|
-
const [remoteUrl, setRemoteUrl] =
|
|
1816
|
+
const [remoteUrl, setRemoteUrl] = useState6(project.gitRemote?.value ?? "");
|
|
1817
|
+
const [cursorPos, setCursorPos] = useState6(() => (project.gitRemote?.value ?? "").length);
|
|
1818
|
+
const cursorRef = useRef3(cursorPos);
|
|
1819
|
+
cursorRef.current = cursorPos;
|
|
1616
1820
|
useInput5((input, key) => {
|
|
1617
1821
|
if (key.escape) {
|
|
1618
1822
|
onCancel();
|
|
@@ -1629,6 +1833,8 @@ function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
|
|
|
1629
1833
|
const detected = onDetect();
|
|
1630
1834
|
if (detected) {
|
|
1631
1835
|
setRemoteUrl(detected);
|
|
1836
|
+
cursorRef.current = detected.length;
|
|
1837
|
+
setCursorPos(detected.length);
|
|
1632
1838
|
}
|
|
1633
1839
|
return;
|
|
1634
1840
|
}
|
|
@@ -1638,55 +1844,107 @@ function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
|
|
|
1638
1844
|
}
|
|
1639
1845
|
return;
|
|
1640
1846
|
}
|
|
1847
|
+
if (key.leftArrow) {
|
|
1848
|
+
setCursorPos((p) => Math.max(0, p - 1));
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
if (key.rightArrow) {
|
|
1852
|
+
setCursorPos((p) => Math.min(remoteUrl.length, p + 1));
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1641
1855
|
if (key.backspace || key.delete) {
|
|
1642
|
-
|
|
1856
|
+
const pos = cursorRef.current;
|
|
1857
|
+
if (pos > 0) {
|
|
1858
|
+
setRemoteUrl((v) => v.slice(0, pos - 1) + v.slice(pos));
|
|
1859
|
+
cursorRef.current = pos - 1;
|
|
1860
|
+
setCursorPos(pos - 1);
|
|
1861
|
+
}
|
|
1643
1862
|
return;
|
|
1644
1863
|
}
|
|
1645
1864
|
if (input && !key.ctrl && !key.meta) {
|
|
1646
|
-
|
|
1865
|
+
const pos = cursorRef.current;
|
|
1866
|
+
setRemoteUrl((v) => v.slice(0, pos) + input + v.slice(pos));
|
|
1867
|
+
cursorRef.current = pos + input.length;
|
|
1868
|
+
setCursorPos(pos + input.length);
|
|
1647
1869
|
}
|
|
1648
1870
|
});
|
|
1649
|
-
return /* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
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: [
|
|
1652
1874
|
" ",
|
|
1653
1875
|
"link git remote"
|
|
1654
1876
|
] }),
|
|
1655
|
-
/* @__PURE__ */
|
|
1877
|
+
/* @__PURE__ */ jsxs10(Text13, { color: theme.titleCounter, bold: true, children: [
|
|
1656
1878
|
" ",
|
|
1657
1879
|
"[",
|
|
1658
1880
|
project.name,
|
|
1659
1881
|
"]"
|
|
1660
1882
|
] })
|
|
1661
1883
|
] }),
|
|
1662
|
-
/* @__PURE__ */
|
|
1663
|
-
/* @__PURE__ */
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
1666
|
-
|
|
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,
|
|
1667
1889
|
{
|
|
1668
1890
|
color: project.gitRemote ? theme.yaml.value : theme.table.fg,
|
|
1669
1891
|
dimColor: !project.gitRemote,
|
|
1670
|
-
children: project.gitRemote ?? "(none)"
|
|
1892
|
+
children: project.gitRemote?.value ?? "(none)"
|
|
1671
1893
|
}
|
|
1672
1894
|
)
|
|
1673
1895
|
] }),
|
|
1674
|
-
/* @__PURE__ */
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1677
|
-
remoteUrl,
|
|
1678
|
-
/* @__PURE__ */
|
|
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: [
|
|
1899
|
+
remoteUrl.slice(0, cursorPos),
|
|
1900
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.titleHighlight, children: "_" }),
|
|
1901
|
+
remoteUrl.slice(cursorPos)
|
|
1679
1902
|
] })
|
|
1680
1903
|
] })
|
|
1681
1904
|
] }),
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
1684
1907
|
] });
|
|
1685
1908
|
}
|
|
1686
1909
|
|
|
1910
|
+
// src/utils/dismissed-remotes.ts
|
|
1911
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
1912
|
+
function isDismissedRemote(filePath, remote) {
|
|
1913
|
+
try {
|
|
1914
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1915
|
+
const list = JSON.parse(content);
|
|
1916
|
+
if (!Array.isArray(list)) return false;
|
|
1917
|
+
return list.includes(remote.value);
|
|
1918
|
+
} catch {
|
|
1919
|
+
return false;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
function dismissRemote(filePath, remote) {
|
|
1923
|
+
let list = [];
|
|
1924
|
+
try {
|
|
1925
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1926
|
+
const parsed = JSON.parse(content);
|
|
1927
|
+
if (Array.isArray(parsed)) {
|
|
1928
|
+
list = parsed.filter((v) => typeof v === "string");
|
|
1929
|
+
}
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
if (list.includes(remote.value)) return;
|
|
1933
|
+
list.push(remote.value);
|
|
1934
|
+
try {
|
|
1935
|
+
writeFileSync3(filePath, JSON.stringify(list), "utf-8");
|
|
1936
|
+
logger.info(`dismissRemote: persisted ${remote.value} to ${filePath}`);
|
|
1937
|
+
} catch (e) {
|
|
1938
|
+
logger.error(
|
|
1939
|
+
`dismissRemote: failed to write ${filePath}`,
|
|
1940
|
+
e instanceof Error ? e : new Error(String(e))
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1687
1945
|
// src/tui/components/HelpOverlay.tsx
|
|
1688
|
-
import { Box as
|
|
1689
|
-
import { jsx as
|
|
1946
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1947
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1690
1948
|
var ROW1 = [
|
|
1691
1949
|
{
|
|
1692
1950
|
title: "NAVIGATION",
|
|
@@ -1755,10 +2013,10 @@ var ROW2 = [
|
|
|
1755
2013
|
{
|
|
1756
2014
|
title: "FORMS",
|
|
1757
2015
|
keys: [
|
|
1758
|
-
["tab", "
|
|
1759
|
-
["
|
|
2016
|
+
["\u2191\u2193/tab", "Navigate fields"],
|
|
2017
|
+
["\u2190\u2192", "Move cursor"],
|
|
1760
2018
|
["ctrl+s", "Save"],
|
|
1761
|
-
["enter", "Open editor"],
|
|
2019
|
+
["enter", "Open editor / next"],
|
|
1762
2020
|
["esc", "Cancel"]
|
|
1763
2021
|
]
|
|
1764
2022
|
},
|
|
@@ -1772,21 +2030,21 @@ var ROW2 = [
|
|
|
1772
2030
|
}
|
|
1773
2031
|
];
|
|
1774
2032
|
function SectionRow({ sections }) {
|
|
1775
|
-
return /* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1777
|
-
section.keys.map(([key, desc]) => /* @__PURE__ */
|
|
1778
|
-
/* @__PURE__ */
|
|
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: [
|
|
1779
2037
|
"<",
|
|
1780
2038
|
key.padEnd(5),
|
|
1781
2039
|
">"
|
|
1782
2040
|
] }),
|
|
1783
|
-
/* @__PURE__ */
|
|
2041
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: desc })
|
|
1784
2042
|
] }, key))
|
|
1785
2043
|
] }, section.title)) });
|
|
1786
2044
|
}
|
|
1787
2045
|
function HelpOverlay() {
|
|
1788
|
-
return /* @__PURE__ */
|
|
1789
|
-
|
|
2046
|
+
return /* @__PURE__ */ jsxs11(
|
|
2047
|
+
Box14,
|
|
1790
2048
|
{
|
|
1791
2049
|
flexDirection: "column",
|
|
1792
2050
|
borderStyle: "bold",
|
|
@@ -1794,28 +2052,28 @@ function HelpOverlay() {
|
|
|
1794
2052
|
paddingX: 2,
|
|
1795
2053
|
paddingY: 1,
|
|
1796
2054
|
children: [
|
|
1797
|
-
/* @__PURE__ */
|
|
2055
|
+
/* @__PURE__ */ jsxs11(Text14, { color: theme.title, bold: true, children: [
|
|
1798
2056
|
" ",
|
|
1799
2057
|
"Help"
|
|
1800
2058
|
] }),
|
|
1801
|
-
/* @__PURE__ */
|
|
1802
|
-
/* @__PURE__ */
|
|
1803
|
-
/* @__PURE__ */
|
|
1804
|
-
/* @__PURE__ */
|
|
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 })
|
|
1805
2063
|
] }),
|
|
1806
|
-
/* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
2064
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " }),
|
|
2065
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Press any key to close" })
|
|
1808
2066
|
]
|
|
1809
2067
|
}
|
|
1810
2068
|
);
|
|
1811
2069
|
}
|
|
1812
2070
|
|
|
1813
2071
|
// src/tui/components/ConfirmDialog.tsx
|
|
1814
|
-
import { Box as
|
|
1815
|
-
import { jsx as
|
|
2072
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
2073
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1816
2074
|
function ConfirmDialog({ task }) {
|
|
1817
|
-
return /* @__PURE__ */
|
|
1818
|
-
|
|
2075
|
+
return /* @__PURE__ */ jsxs12(
|
|
2076
|
+
Box15,
|
|
1819
2077
|
{
|
|
1820
2078
|
flexDirection: "column",
|
|
1821
2079
|
borderStyle: "bold",
|
|
@@ -1824,17 +2082,17 @@ function ConfirmDialog({ task }) {
|
|
|
1824
2082
|
paddingY: 1,
|
|
1825
2083
|
alignSelf: "center",
|
|
1826
2084
|
children: [
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */
|
|
1829
|
-
/* @__PURE__ */
|
|
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: [
|
|
1830
2088
|
'Delete task "',
|
|
1831
2089
|
task.name,
|
|
1832
2090
|
'"?'
|
|
1833
2091
|
] }),
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
/* @__PURE__ */
|
|
1836
|
-
/* @__PURE__ */
|
|
1837
|
-
|
|
2092
|
+
/* @__PURE__ */ jsx15(Text15, { children: " " }),
|
|
2093
|
+
/* @__PURE__ */ jsxs12(Box15, { gap: 3, children: [
|
|
2094
|
+
/* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(
|
|
2095
|
+
Text15,
|
|
1838
2096
|
{
|
|
1839
2097
|
backgroundColor: theme.dialog.buttonFocusBg,
|
|
1840
2098
|
color: theme.dialog.buttonFocusFg,
|
|
@@ -1842,7 +2100,39 @@ function ConfirmDialog({ task }) {
|
|
|
1842
2100
|
children: " y: OK "
|
|
1843
2101
|
}
|
|
1844
2102
|
) }),
|
|
1845
|
-
/* @__PURE__ */
|
|
2103
|
+
/* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text15, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Cancel " }) })
|
|
2104
|
+
] })
|
|
2105
|
+
]
|
|
2106
|
+
}
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// src/tui/components/DetectedProjectDialog.tsx
|
|
2111
|
+
import { Box as Box16, Text as Text16 } from "ink";
|
|
2112
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2113
|
+
function DetectedProjectDialog({ remote }) {
|
|
2114
|
+
return /* @__PURE__ */ jsxs13(
|
|
2115
|
+
Box16,
|
|
2116
|
+
{
|
|
2117
|
+
flexDirection: "column",
|
|
2118
|
+
borderStyle: "bold",
|
|
2119
|
+
borderColor: theme.borderFocus,
|
|
2120
|
+
paddingX: 3,
|
|
2121
|
+
paddingY: 1,
|
|
2122
|
+
alignSelf: "center",
|
|
2123
|
+
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: [
|
|
2127
|
+
"Git remote: ",
|
|
2128
|
+
/* @__PURE__ */ jsx16(Text16, { bold: true, children: remote.value })
|
|
2129
|
+
] }),
|
|
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 " })
|
|
1846
2136
|
] })
|
|
1847
2137
|
]
|
|
1848
2138
|
}
|
|
@@ -1850,8 +2140,8 @@ function ConfirmDialog({ task }) {
|
|
|
1850
2140
|
}
|
|
1851
2141
|
|
|
1852
2142
|
// src/tui/components/DependencyList.tsx
|
|
1853
|
-
import { Box as
|
|
1854
|
-
import { Fragment as
|
|
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";
|
|
1855
2145
|
function TaskRow({
|
|
1856
2146
|
task,
|
|
1857
2147
|
globalIndex,
|
|
@@ -1859,16 +2149,16 @@ function TaskRow({
|
|
|
1859
2149
|
}) {
|
|
1860
2150
|
const isSelected = globalIndex === selectedIndex;
|
|
1861
2151
|
const statusColor = STATUS_COLOR[task.status] ?? theme.table.fg;
|
|
1862
|
-
return /* @__PURE__ */
|
|
2152
|
+
return /* @__PURE__ */ jsx17(Box17, { children: isSelected ? /* @__PURE__ */ jsxs14(Text17, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1863
2153
|
"> ",
|
|
1864
2154
|
task.id.padEnd(12),
|
|
1865
2155
|
task.status.padEnd(14),
|
|
1866
2156
|
task.name
|
|
1867
|
-
] }) : /* @__PURE__ */
|
|
1868
|
-
/* @__PURE__ */
|
|
1869
|
-
/* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
1871
|
-
/* @__PURE__ */
|
|
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 })
|
|
1872
2162
|
] }) }, task.id);
|
|
1873
2163
|
}
|
|
1874
2164
|
function DependencyList({
|
|
@@ -1889,23 +2179,23 @@ function DependencyList({
|
|
|
1889
2179
|
const relatedOffset = offset;
|
|
1890
2180
|
offset += related.length;
|
|
1891
2181
|
const duplicatesOffset = offset;
|
|
1892
|
-
return /* @__PURE__ */
|
|
1893
|
-
/* @__PURE__ */
|
|
1894
|
-
/* @__PURE__ */
|
|
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: [
|
|
1895
2185
|
" ",
|
|
1896
2186
|
"dependencies"
|
|
1897
2187
|
] }),
|
|
1898
|
-
/* @__PURE__ */
|
|
1899
|
-
/* @__PURE__ */
|
|
1900
|
-
/* @__PURE__ */
|
|
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: ")" })
|
|
1901
2191
|
] }),
|
|
1902
|
-
/* @__PURE__ */
|
|
1903
|
-
/* @__PURE__ */
|
|
2192
|
+
/* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
2193
|
+
/* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
|
|
1904
2194
|
"BLOCKED BY (",
|
|
1905
2195
|
blockers.length,
|
|
1906
2196
|
")"
|
|
1907
2197
|
] }),
|
|
1908
|
-
blockers.length === 0 ? /* @__PURE__ */
|
|
2198
|
+
blockers.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No blockers" }) : blockers.map((t, i) => /* @__PURE__ */ jsx17(
|
|
1909
2199
|
TaskRow,
|
|
1910
2200
|
{
|
|
1911
2201
|
task: t,
|
|
@@ -1915,13 +2205,13 @@ function DependencyList({
|
|
|
1915
2205
|
t.id
|
|
1916
2206
|
))
|
|
1917
2207
|
] }),
|
|
1918
|
-
/* @__PURE__ */
|
|
1919
|
-
/* @__PURE__ */
|
|
2208
|
+
/* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
2209
|
+
/* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
|
|
1920
2210
|
"BLOCKS (",
|
|
1921
2211
|
dependents.length,
|
|
1922
2212
|
")"
|
|
1923
2213
|
] }),
|
|
1924
|
-
dependents.length === 0 ? /* @__PURE__ */
|
|
2214
|
+
dependents.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No dependents" }) : dependents.map((t, i) => /* @__PURE__ */ jsx17(
|
|
1925
2215
|
TaskRow,
|
|
1926
2216
|
{
|
|
1927
2217
|
task: t,
|
|
@@ -1931,13 +2221,13 @@ function DependencyList({
|
|
|
1931
2221
|
t.id
|
|
1932
2222
|
))
|
|
1933
2223
|
] }),
|
|
1934
|
-
/* @__PURE__ */
|
|
1935
|
-
/* @__PURE__ */
|
|
2224
|
+
/* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
2225
|
+
/* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
|
|
1936
2226
|
"RELATES TO (",
|
|
1937
2227
|
related.length,
|
|
1938
2228
|
")"
|
|
1939
2229
|
] }),
|
|
1940
|
-
related.length === 0 ? /* @__PURE__ */
|
|
2230
|
+
related.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No related tasks" }) : related.map((t, i) => /* @__PURE__ */ jsx17(
|
|
1941
2231
|
TaskRow,
|
|
1942
2232
|
{
|
|
1943
2233
|
task: t,
|
|
@@ -1947,13 +2237,13 @@ function DependencyList({
|
|
|
1947
2237
|
t.id
|
|
1948
2238
|
))
|
|
1949
2239
|
] }),
|
|
1950
|
-
/* @__PURE__ */
|
|
1951
|
-
/* @__PURE__ */
|
|
2240
|
+
/* @__PURE__ */ jsxs14(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
2241
|
+
/* @__PURE__ */ jsxs14(Text17, { color: theme.table.headerFg, bold: true, children: [
|
|
1952
2242
|
"DUPLICATES (",
|
|
1953
2243
|
duplicates.length,
|
|
1954
2244
|
")"
|
|
1955
2245
|
] }),
|
|
1956
|
-
duplicates.length === 0 ? /* @__PURE__ */
|
|
2246
|
+
duplicates.length === 0 ? /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " No duplicate tasks" }) : duplicates.map((t, i) => /* @__PURE__ */ jsx17(
|
|
1957
2247
|
TaskRow,
|
|
1958
2248
|
{
|
|
1959
2249
|
task: t,
|
|
@@ -1963,19 +2253,19 @@ function DependencyList({
|
|
|
1963
2253
|
t.id
|
|
1964
2254
|
))
|
|
1965
2255
|
] }),
|
|
1966
|
-
/* @__PURE__ */
|
|
1967
|
-
isAddingDep && /* @__PURE__ */
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
/* @__PURE__ */
|
|
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: "_" })
|
|
1971
2261
|
] }),
|
|
1972
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
1973
2263
|
] });
|
|
1974
2264
|
}
|
|
1975
2265
|
|
|
1976
2266
|
// src/tui/components/EpicPanel.tsx
|
|
1977
|
-
import { Box as
|
|
1978
|
-
import { jsx as
|
|
2267
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
2268
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1979
2269
|
var PAGE_SIZE2 = 20;
|
|
1980
2270
|
function EpicPanel({
|
|
1981
2271
|
epics,
|
|
@@ -1988,34 +2278,34 @@ function EpicPanel({
|
|
|
1988
2278
|
const currentPage = Math.floor(selectedIndex / PAGE_SIZE2);
|
|
1989
2279
|
const viewStart = currentPage * PAGE_SIZE2;
|
|
1990
2280
|
const visibleEpics = epics.slice(viewStart, viewStart + PAGE_SIZE2);
|
|
1991
|
-
return /* @__PURE__ */
|
|
1992
|
-
|
|
2281
|
+
return /* @__PURE__ */ jsxs15(
|
|
2282
|
+
Box18,
|
|
1993
2283
|
{
|
|
1994
2284
|
flexDirection: "column",
|
|
1995
2285
|
width: 48,
|
|
1996
2286
|
borderStyle: "bold",
|
|
1997
2287
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
1998
2288
|
children: [
|
|
1999
|
-
/* @__PURE__ */
|
|
2000
|
-
/* @__PURE__ */
|
|
2289
|
+
/* @__PURE__ */ jsxs15(Box18, { children: [
|
|
2290
|
+
/* @__PURE__ */ jsxs15(Text18, { color: theme.title, bold: true, children: [
|
|
2001
2291
|
" ",
|
|
2002
2292
|
"epics"
|
|
2003
2293
|
] }),
|
|
2004
|
-
/* @__PURE__ */
|
|
2294
|
+
/* @__PURE__ */ jsxs15(Text18, { color: theme.titleCounter, bold: true, children: [
|
|
2005
2295
|
"[",
|
|
2006
2296
|
epics.length,
|
|
2007
2297
|
"]"
|
|
2008
2298
|
] }),
|
|
2009
|
-
isReordering && /* @__PURE__ */
|
|
2299
|
+
isReordering && /* @__PURE__ */ jsxs15(Text18, { color: theme.flash.warn, bold: true, children: [
|
|
2010
2300
|
" ",
|
|
2011
2301
|
"REORDER"
|
|
2012
2302
|
] }),
|
|
2013
|
-
filterActive && /* @__PURE__ */
|
|
2303
|
+
filterActive && /* @__PURE__ */ jsxs15(Text18, { color: theme.titleFilter, children: [
|
|
2014
2304
|
" *",
|
|
2015
2305
|
selectedEpicIds.size
|
|
2016
2306
|
] })
|
|
2017
2307
|
] }),
|
|
2018
|
-
/* @__PURE__ */
|
|
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) => {
|
|
2019
2309
|
const actualIndex = viewStart + i;
|
|
2020
2310
|
const isSelected = actualIndex === selectedIndex && isFocused;
|
|
2021
2311
|
const isChecked = selectedEpicIds.has(epic.id);
|
|
@@ -2023,21 +2313,21 @@ function EpicPanel({
|
|
|
2023
2313
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
2024
2314
|
if (isSelected) {
|
|
2025
2315
|
const cursorBg = isReordering ? theme.flash.warn : theme.table.cursorBg;
|
|
2026
|
-
return /* @__PURE__ */
|
|
2316
|
+
return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
2027
2317
|
isReordering ? "~ " : " ",
|
|
2028
2318
|
marker,
|
|
2029
2319
|
" ",
|
|
2030
2320
|
epic.name
|
|
2031
2321
|
] }) }, epic.id);
|
|
2032
2322
|
}
|
|
2033
|
-
return /* @__PURE__ */
|
|
2323
|
+
return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { color: isChecked ? theme.titleHighlight : statusColor, children: [
|
|
2034
2324
|
" ",
|
|
2035
2325
|
marker,
|
|
2036
2326
|
" ",
|
|
2037
2327
|
epic.name
|
|
2038
2328
|
] }) }, epic.id);
|
|
2039
2329
|
}) }),
|
|
2040
|
-
epics.length > PAGE_SIZE2 && /* @__PURE__ */
|
|
2330
|
+
epics.length > PAGE_SIZE2 && /* @__PURE__ */ jsx18(Box18, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs15(Text18, { dimColor: true, children: [
|
|
2041
2331
|
"[",
|
|
2042
2332
|
viewStart + 1,
|
|
2043
2333
|
"-",
|
|
@@ -2052,16 +2342,16 @@ function EpicPanel({
|
|
|
2052
2342
|
}
|
|
2053
2343
|
|
|
2054
2344
|
// src/tui/components/EpicPicker.tsx
|
|
2055
|
-
import { useState as
|
|
2056
|
-
import { Box as
|
|
2057
|
-
import { Fragment as
|
|
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";
|
|
2058
2348
|
function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
2059
2349
|
const { stdout } = useStdout3();
|
|
2060
2350
|
const termHeight = stdout.rows > 0 ? stdout.rows : 24;
|
|
2061
2351
|
const maxVisible = Math.max(3, termHeight - 10);
|
|
2062
|
-
const [searchQuery, setSearchQuery] =
|
|
2063
|
-
const [isSearching, setIsSearching] =
|
|
2064
|
-
const [cursorIndex, setCursorIndex] =
|
|
2352
|
+
const [searchQuery, setSearchQuery] = useState7("");
|
|
2353
|
+
const [isSearching, setIsSearching] = useState7(false);
|
|
2354
|
+
const [cursorIndex, setCursorIndex] = useState7(0);
|
|
2065
2355
|
const filtered = epics.filter((e) => {
|
|
2066
2356
|
if (!searchQuery.trim()) return true;
|
|
2067
2357
|
const q = searchQuery.toLowerCase();
|
|
@@ -2127,53 +2417,53 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
2127
2417
|
return;
|
|
2128
2418
|
}
|
|
2129
2419
|
});
|
|
2130
|
-
return /* @__PURE__ */
|
|
2131
|
-
/* @__PURE__ */
|
|
2132
|
-
/* @__PURE__ */
|
|
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: [
|
|
2133
2423
|
" ",
|
|
2134
2424
|
"assign to epic"
|
|
2135
2425
|
] }),
|
|
2136
|
-
/* @__PURE__ */
|
|
2426
|
+
/* @__PURE__ */ jsxs16(Text19, { color: theme.titleCounter, bold: true, children: [
|
|
2137
2427
|
" ",
|
|
2138
2428
|
"[",
|
|
2139
2429
|
epics.length,
|
|
2140
2430
|
"]"
|
|
2141
2431
|
] })
|
|
2142
2432
|
] }),
|
|
2143
|
-
isSearching ? /* @__PURE__ */
|
|
2144
|
-
/* @__PURE__ */
|
|
2145
|
-
/* @__PURE__ */
|
|
2146
|
-
/* @__PURE__ */
|
|
2147
|
-
] }) : searchQuery ? /* @__PURE__ */
|
|
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: [
|
|
2148
2438
|
"/",
|
|
2149
2439
|
searchQuery
|
|
2150
2440
|
] }) }) : null,
|
|
2151
|
-
/* @__PURE__ */
|
|
2441
|
+
/* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text19, { color: theme.table.headerFg, bold: true, children: [
|
|
2152
2442
|
" ",
|
|
2153
2443
|
"ID".padEnd(14),
|
|
2154
2444
|
"STATUS".padEnd(14),
|
|
2155
2445
|
"NAME"
|
|
2156
2446
|
] }) }),
|
|
2157
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
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) => {
|
|
2158
2448
|
const actualIndex = viewStart + i;
|
|
2159
2449
|
const isCursor = actualIndex === cursorIndex;
|
|
2160
2450
|
const isCurrent = epic.id === currentEpicId;
|
|
2161
2451
|
const marker = isCurrent ? "* " : " ";
|
|
2162
2452
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
2163
|
-
return /* @__PURE__ */
|
|
2453
|
+
return /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs16(Text19, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
2164
2454
|
"> ",
|
|
2165
2455
|
epic.id.padEnd(14),
|
|
2166
2456
|
epic.status.padEnd(14),
|
|
2167
2457
|
epic.name
|
|
2168
|
-
] }) : /* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2170
|
-
/* @__PURE__ */
|
|
2171
|
-
/* @__PURE__ */
|
|
2172
|
-
/* @__PURE__ */
|
|
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 })
|
|
2173
2463
|
] }) }, epic.id);
|
|
2174
2464
|
}),
|
|
2175
|
-
/* @__PURE__ */
|
|
2176
|
-
filtered.length > maxVisible && /* @__PURE__ */
|
|
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: [
|
|
2177
2467
|
"[",
|
|
2178
2468
|
viewStart + 1,
|
|
2179
2469
|
"-",
|
|
@@ -2182,19 +2472,52 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
2182
2472
|
filtered.length,
|
|
2183
2473
|
"]"
|
|
2184
2474
|
] }) }),
|
|
2185
|
-
/* @__PURE__ */
|
|
2475
|
+
/* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "enter: assign | x: unassign | /: search | esc: cancel" }) })
|
|
2186
2476
|
] });
|
|
2187
2477
|
}
|
|
2188
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
|
+
|
|
2189
2512
|
// src/tui/useAutoRefetch.ts
|
|
2190
|
-
import { useEffect, useRef } from "react";
|
|
2513
|
+
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
2191
2514
|
import { watchFile, unwatchFile } from "fs";
|
|
2192
2515
|
var POLL_INTERVAL_MS = 1e3;
|
|
2193
2516
|
var DEBOUNCE_MS = 200;
|
|
2194
2517
|
function useAutoRefetch(dbPath, onRefetch) {
|
|
2195
|
-
const callbackRef =
|
|
2518
|
+
const callbackRef = useRef4(onRefetch);
|
|
2196
2519
|
callbackRef.current = onRefetch;
|
|
2197
|
-
|
|
2520
|
+
useEffect4(() => {
|
|
2198
2521
|
let debounceTimer = null;
|
|
2199
2522
|
const handleChange = () => {
|
|
2200
2523
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
@@ -2221,8 +2544,47 @@ function useAutoRefetch(dbPath, onRefetch) {
|
|
|
2221
2544
|
}, [dbPath]);
|
|
2222
2545
|
}
|
|
2223
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
|
+
|
|
2224
2586
|
// src/tui/components/App.tsx
|
|
2225
|
-
import { jsx as
|
|
2587
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2226
2588
|
var STATUS_CYCLE = [
|
|
2227
2589
|
TaskStatus.Backlog,
|
|
2228
2590
|
TaskStatus.Todo,
|
|
@@ -2235,8 +2597,8 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2235
2597
|
const { exit } = useApp();
|
|
2236
2598
|
const { stdout } = useStdout4();
|
|
2237
2599
|
const [state, dispatch] = useReducer(appReducer, initialState);
|
|
2238
|
-
const [, setResizeTick] =
|
|
2239
|
-
|
|
2600
|
+
const [, setResizeTick] = useState8(0);
|
|
2601
|
+
useEffect5(() => {
|
|
2240
2602
|
const onResize = () => {
|
|
2241
2603
|
setResizeTick((n) => n + 1);
|
|
2242
2604
|
};
|
|
@@ -2401,10 +2763,10 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2401
2763
|
loadEpics();
|
|
2402
2764
|
}, [loadProjects, loadTasks, loadEpics]);
|
|
2403
2765
|
useAutoRefetch(container.dbPath, refetchAll);
|
|
2404
|
-
|
|
2766
|
+
useEffect5(() => {
|
|
2405
2767
|
loadProjects();
|
|
2406
2768
|
}, [loadProjects]);
|
|
2407
|
-
|
|
2769
|
+
useEffect5(() => {
|
|
2408
2770
|
if (state.projects.length > 0 && !state.activeProject) {
|
|
2409
2771
|
logger.info(`TUI.resolveProject: resolving initialProject=${initialProject ?? "(default)"}`);
|
|
2410
2772
|
const result = container.projectService.resolveProject(initialProject);
|
|
@@ -2421,13 +2783,47 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2421
2783
|
}
|
|
2422
2784
|
}
|
|
2423
2785
|
}, [state.projects, state.activeProject, initialProject, container]);
|
|
2424
|
-
|
|
2786
|
+
const gitRemoteCheckedRef = useRef5(false);
|
|
2787
|
+
useEffect5(() => {
|
|
2788
|
+
if (state.projects.length > 0 && !gitRemoteCheckedRef.current && !initialProject) {
|
|
2789
|
+
gitRemoteCheckedRef.current = true;
|
|
2790
|
+
const remoteResult = detectGitRemote();
|
|
2791
|
+
if (remoteResult.ok && remoteResult.value) {
|
|
2792
|
+
const remote = remoteResult.value;
|
|
2793
|
+
const alreadyLinked = state.projects.some((p) => p.gitRemote?.equals(remote));
|
|
2794
|
+
const dismissed = isDismissedRemote(container.dismissedGitRemotesPath, remote);
|
|
2795
|
+
if (!alreadyLinked && !dismissed) {
|
|
2796
|
+
logger.info(`TUI.detectGitRemote: unlinked remote detected: ${remote.value}`);
|
|
2797
|
+
dispatch({ type: "SET_DETECTED_GIT_REMOTE", remote });
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}, [state.projects, initialProject]);
|
|
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(() => {
|
|
2425
2821
|
if (state.activeProject) {
|
|
2426
2822
|
loadTasks();
|
|
2427
2823
|
loadEpics();
|
|
2428
2824
|
}
|
|
2429
2825
|
}, [state.activeProject, state.filter, loadTasks, loadEpics]);
|
|
2430
|
-
|
|
2826
|
+
useEffect5(() => {
|
|
2431
2827
|
if (state.flash) {
|
|
2432
2828
|
const timer = setTimeout(() => {
|
|
2433
2829
|
dispatch({ type: "CLEAR_FLASH" });
|
|
@@ -2439,6 +2835,21 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2439
2835
|
return void 0;
|
|
2440
2836
|
}, [state.flash]);
|
|
2441
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
|
+
}
|
|
2442
2853
|
if (state.confirmDelete) {
|
|
2443
2854
|
if (input === "y") {
|
|
2444
2855
|
const result = container.taskService.deleteTask(state.confirmDelete.id);
|
|
@@ -2459,11 +2870,20 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2459
2870
|
}
|
|
2460
2871
|
return;
|
|
2461
2872
|
}
|
|
2873
|
+
if (state.detectedGitRemote && state.activeView === ViewType.TaskList) {
|
|
2874
|
+
if (input === "y") {
|
|
2875
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectCreate });
|
|
2876
|
+
} else if (input === "n" || key.escape) {
|
|
2877
|
+
dismissRemote(container.dismissedGitRemotesPath, state.detectedGitRemote);
|
|
2878
|
+
dispatch({ type: "SET_DETECTED_GIT_REMOTE", remote: null });
|
|
2879
|
+
}
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2462
2882
|
if (state.activeView === ViewType.Help) {
|
|
2463
2883
|
dispatch({ type: "GO_BACK" });
|
|
2464
2884
|
return;
|
|
2465
2885
|
}
|
|
2466
|
-
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.ProjectLink || state.activeView === ViewType.EpicPicker) {
|
|
2886
|
+
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.ProjectEdit || state.activeView === ViewType.ProjectLink || state.activeView === ViewType.EpicPicker) {
|
|
2467
2887
|
return;
|
|
2468
2888
|
}
|
|
2469
2889
|
if (state.activeView === ViewType.DependencyList && state.isAddingDep) {
|
|
@@ -2791,6 +3211,10 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2791
3211
|
dispatch({ type: "CLEAR_FILTER" });
|
|
2792
3212
|
return;
|
|
2793
3213
|
}
|
|
3214
|
+
if (input === "W" && state.changelogEntries) {
|
|
3215
|
+
dispatch({ type: "OPEN_CHANGELOG_DIALOG" });
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
2794
3218
|
}
|
|
2795
3219
|
if (state.activeView === ViewType.TaskList && state.focusedPanel === "detail" && previewTask) {
|
|
2796
3220
|
if (key.upArrow || input === "k") {
|
|
@@ -3037,35 +3461,57 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3037
3461
|
const handleProjectCreate = useCallback2(() => {
|
|
3038
3462
|
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectCreate });
|
|
3039
3463
|
}, []);
|
|
3464
|
+
const handleProjectEdit = useCallback2((project) => {
|
|
3465
|
+
dispatch({ type: "SET_EDITING_PROJECT", project });
|
|
3466
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectEdit });
|
|
3467
|
+
}, []);
|
|
3040
3468
|
const handleProjectFormSave = useCallback2(
|
|
3041
3469
|
(data) => {
|
|
3042
|
-
const
|
|
3470
|
+
const editing = state.activeView === ViewType.ProjectEdit ? state.editingProject : null;
|
|
3471
|
+
const result = editing ? container.projectService.updateProject(editing.id, {
|
|
3472
|
+
name: data.name,
|
|
3473
|
+
description: data.description,
|
|
3474
|
+
isDefault: data.isDefault,
|
|
3475
|
+
gitRemote: data.gitRemote || null
|
|
3476
|
+
}) : container.projectService.createProject({
|
|
3043
3477
|
name: data.name,
|
|
3044
3478
|
key: data.key || void 0,
|
|
3045
3479
|
description: data.description || void 0,
|
|
3046
|
-
isDefault: data.isDefault
|
|
3480
|
+
isDefault: data.isDefault,
|
|
3481
|
+
gitRemote: data.gitRemote || void 0
|
|
3047
3482
|
});
|
|
3048
3483
|
if (result.ok) {
|
|
3049
|
-
|
|
3484
|
+
const verb = editing ? "updated" : "created";
|
|
3485
|
+
logger.info(
|
|
3486
|
+
`TUI.${editing ? "editProject" : "createProject"}: ${verb} key=${result.value.key} name=${result.value.name}`
|
|
3487
|
+
);
|
|
3050
3488
|
dispatch({
|
|
3051
3489
|
type: "FLASH",
|
|
3052
|
-
message: `Project
|
|
3490
|
+
message: `Project ${verb}: ${result.value.name}`,
|
|
3053
3491
|
level: "info"
|
|
3054
3492
|
});
|
|
3055
|
-
|
|
3056
|
-
|
|
3493
|
+
if (editing && state.activeProject?.id === result.value.id) {
|
|
3494
|
+
dispatch({ type: "SET_ACTIVE_PROJECT", project: result.value });
|
|
3495
|
+
}
|
|
3496
|
+
if (!editing) {
|
|
3497
|
+
dispatch({ type: "SET_ACTIVE_PROJECT", project: result.value });
|
|
3498
|
+
dispatch({ type: "GO_BACK" });
|
|
3499
|
+
}
|
|
3057
3500
|
dispatch({ type: "GO_BACK" });
|
|
3058
3501
|
loadProjects();
|
|
3059
3502
|
} else {
|
|
3060
|
-
logger.error("
|
|
3503
|
+
logger.error(`TUI.${editing ? "editProject" : "createProject"}: failed`, result.error);
|
|
3061
3504
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
3062
3505
|
}
|
|
3063
3506
|
},
|
|
3064
|
-
[container, loadProjects]
|
|
3507
|
+
[container, state.activeView, state.editingProject, state.activeProject, loadProjects]
|
|
3065
3508
|
);
|
|
3066
3509
|
const handleProjectFormCancel = useCallback2(() => {
|
|
3510
|
+
if (state.activeView === ViewType.ProjectCreate && state.detectedGitRemote) {
|
|
3511
|
+
dismissRemote(container.dismissedGitRemotesPath, state.detectedGitRemote);
|
|
3512
|
+
}
|
|
3067
3513
|
dispatch({ type: "GO_BACK" });
|
|
3068
|
-
}, []);
|
|
3514
|
+
}, [state.activeView, state.detectedGitRemote, container]);
|
|
3069
3515
|
const handleProjectLink = useCallback2((project) => {
|
|
3070
3516
|
dispatch({ type: "SET_LINKING_PROJECT", project });
|
|
3071
3517
|
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectLink });
|
|
@@ -3076,11 +3522,11 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3076
3522
|
const result = container.projectService.linkGitRemote(state.linkingProject.id, remote);
|
|
3077
3523
|
if (result.ok) {
|
|
3078
3524
|
logger.info(
|
|
3079
|
-
`TUI.linkGitRemote: linked project=${state.linkingProject.id} remote=${result.value.gitRemote}`
|
|
3525
|
+
`TUI.linkGitRemote: linked project=${state.linkingProject.id} remote=${result.value.gitRemote?.value}`
|
|
3080
3526
|
);
|
|
3081
3527
|
dispatch({
|
|
3082
3528
|
type: "FLASH",
|
|
3083
|
-
message: `Linked to: ${result.value.gitRemote}`,
|
|
3529
|
+
message: `Linked to: ${result.value.gitRemote?.value}`,
|
|
3084
3530
|
level: "info"
|
|
3085
3531
|
});
|
|
3086
3532
|
dispatch({ type: "GO_BACK" });
|
|
@@ -3108,8 +3554,8 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3108
3554
|
const handleLinkDetect = useCallback2(() => {
|
|
3109
3555
|
const result = detectGitRemote();
|
|
3110
3556
|
if (result.ok && result.value) {
|
|
3111
|
-
dispatch({ type: "FLASH", message: `Detected: ${result.value}`, level: "info" });
|
|
3112
|
-
return result.value;
|
|
3557
|
+
dispatch({ type: "FLASH", message: `Detected: ${result.value.value}`, level: "info" });
|
|
3558
|
+
return result.value.value;
|
|
3113
3559
|
}
|
|
3114
3560
|
dispatch({ type: "FLASH", message: "No git remote detected in cwd", level: "warn" });
|
|
3115
3561
|
return null;
|
|
@@ -3121,7 +3567,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3121
3567
|
dispatch({ type: "GO_BACK" });
|
|
3122
3568
|
}, []);
|
|
3123
3569
|
const previewTask = state.tasks[state.selectedIndex] ?? null;
|
|
3124
|
-
const initialDepsForEdit =
|
|
3570
|
+
const initialDepsForEdit = useMemo3(() => {
|
|
3125
3571
|
return [
|
|
3126
3572
|
...state.depBlockers.map((t) => ({ id: t.id, name: t.name, type: DependencyType.Blocks })),
|
|
3127
3573
|
...state.depRelated.map((t) => ({ id: t.id, name: t.name, type: DependencyType.RelatesTo })),
|
|
@@ -3132,23 +3578,24 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3132
3578
|
}))
|
|
3133
3579
|
];
|
|
3134
3580
|
}, [state.depBlockers, state.depRelated, state.depDuplicates]);
|
|
3135
|
-
const allProjectTasks =
|
|
3581
|
+
const allProjectTasks = useMemo3(() => {
|
|
3136
3582
|
if (!state.activeProject) return [];
|
|
3137
3583
|
const result = container.taskService.listTasks(state.activeProject, {});
|
|
3138
3584
|
return result.ok ? result.value : [];
|
|
3139
3585
|
}, [container, state.activeProject, state.tasks]);
|
|
3140
3586
|
const previewTaskId = previewTask?.id ?? null;
|
|
3141
|
-
|
|
3587
|
+
useEffect5(() => {
|
|
3142
3588
|
if (state.activeView === ViewType.TaskList && previewTaskId) {
|
|
3143
3589
|
loadDeps(previewTaskId);
|
|
3144
3590
|
}
|
|
3145
3591
|
}, [state.activeView, previewTaskId, loadDeps]);
|
|
3146
|
-
return /* @__PURE__ */
|
|
3147
|
-
/* @__PURE__ */
|
|
3148
|
-
/* @__PURE__ */
|
|
3149
|
-
state.confirmDelete && /* @__PURE__ */
|
|
3150
|
-
!state.confirmDelete && state.activeView === ViewType.TaskList && /* @__PURE__ */
|
|
3151
|
-
|
|
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(
|
|
3152
3599
|
EpicPanel,
|
|
3153
3600
|
{
|
|
3154
3601
|
epics: state.epics,
|
|
@@ -3158,7 +3605,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3158
3605
|
isReordering: state.isEpicReordering
|
|
3159
3606
|
}
|
|
3160
3607
|
),
|
|
3161
|
-
/* @__PURE__ */
|
|
3608
|
+
/* @__PURE__ */ jsx21(Box21, { width: taskListWidth, children: /* @__PURE__ */ jsx21(
|
|
3162
3609
|
TaskList,
|
|
3163
3610
|
{
|
|
3164
3611
|
tasks: state.tasks,
|
|
@@ -3179,7 +3626,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3179
3626
|
epicFilterActive: state.selectedEpicIds.size > 0
|
|
3180
3627
|
}
|
|
3181
3628
|
) }),
|
|
3182
|
-
/* @__PURE__ */
|
|
3629
|
+
/* @__PURE__ */ jsx21(Box21, { width: taskDetailWidth, children: previewTask ? /* @__PURE__ */ jsx21(
|
|
3183
3630
|
TaskDetail,
|
|
3184
3631
|
{
|
|
3185
3632
|
task: previewTask,
|
|
@@ -3190,24 +3637,24 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3190
3637
|
isFocused: state.focusedPanel === "detail",
|
|
3191
3638
|
scrollOffset: state.detailScrollOffset
|
|
3192
3639
|
}
|
|
3193
|
-
) : /* @__PURE__ */
|
|
3194
|
-
|
|
3640
|
+
) : /* @__PURE__ */ jsxs18(
|
|
3641
|
+
Box21,
|
|
3195
3642
|
{
|
|
3196
3643
|
flexDirection: "column",
|
|
3197
3644
|
flexGrow: 1,
|
|
3198
3645
|
borderStyle: "bold",
|
|
3199
3646
|
borderColor: theme.border,
|
|
3200
3647
|
children: [
|
|
3201
|
-
/* @__PURE__ */
|
|
3648
|
+
/* @__PURE__ */ jsx21(Box21, { children: /* @__PURE__ */ jsxs18(Text21, { color: theme.title, bold: true, children: [
|
|
3202
3649
|
" ",
|
|
3203
3650
|
"detail"
|
|
3204
3651
|
] }) }),
|
|
3205
|
-
/* @__PURE__ */
|
|
3652
|
+
/* @__PURE__ */ jsx21(Box21, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx21(Text21, { dimColor: true, children: "No task selected" }) })
|
|
3206
3653
|
]
|
|
3207
3654
|
}
|
|
3208
3655
|
) })
|
|
3209
|
-
] }),
|
|
3210
|
-
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */
|
|
3656
|
+
] })),
|
|
3657
|
+
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx21(
|
|
3211
3658
|
TaskDetail,
|
|
3212
3659
|
{
|
|
3213
3660
|
task: state.selectedTask,
|
|
@@ -3218,7 +3665,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3218
3665
|
scrollOffset: state.detailScrollOffset
|
|
3219
3666
|
}
|
|
3220
3667
|
),
|
|
3221
|
-
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */
|
|
3668
|
+
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx21(
|
|
3222
3669
|
DependencyList,
|
|
3223
3670
|
{
|
|
3224
3671
|
task: state.selectedTask,
|
|
@@ -3231,7 +3678,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3231
3678
|
addDepInput: state.addDepInput
|
|
3232
3679
|
}
|
|
3233
3680
|
),
|
|
3234
|
-
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */
|
|
3681
|
+
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx21(
|
|
3235
3682
|
TaskForm,
|
|
3236
3683
|
{
|
|
3237
3684
|
editingTask: state.activeView === ViewType.TaskEdit ? state.selectedTask : null,
|
|
@@ -3241,7 +3688,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3241
3688
|
onCancel: handleFormCancel
|
|
3242
3689
|
}
|
|
3243
3690
|
),
|
|
3244
|
-
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */
|
|
3691
|
+
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */ jsx21(
|
|
3245
3692
|
EpicPicker,
|
|
3246
3693
|
{
|
|
3247
3694
|
epics: state.epics,
|
|
@@ -3250,20 +3697,36 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3250
3697
|
onCancel: handleEpicPickerCancel
|
|
3251
3698
|
}
|
|
3252
3699
|
),
|
|
3253
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */
|
|
3700
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx21(
|
|
3254
3701
|
ProjectSelector,
|
|
3255
3702
|
{
|
|
3256
3703
|
projects: state.projects,
|
|
3257
3704
|
activeProject: state.activeProject,
|
|
3258
3705
|
onSelect: handleProjectSelect,
|
|
3259
3706
|
onCreate: handleProjectCreate,
|
|
3707
|
+
onEdit: handleProjectEdit,
|
|
3260
3708
|
onSetDefault: handleSetDefault,
|
|
3261
3709
|
onLink: handleProjectLink,
|
|
3262
3710
|
onCancel: handleProjectCancel
|
|
3263
3711
|
}
|
|
3264
3712
|
),
|
|
3265
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */
|
|
3266
|
-
|
|
3713
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx21(
|
|
3714
|
+
ProjectForm,
|
|
3715
|
+
{
|
|
3716
|
+
initialGitRemote: state.detectedGitRemote ?? void 0,
|
|
3717
|
+
onSave: handleProjectFormSave,
|
|
3718
|
+
onCancel: handleProjectFormCancel
|
|
3719
|
+
}
|
|
3720
|
+
),
|
|
3721
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectEdit && state.editingProject && /* @__PURE__ */ jsx21(
|
|
3722
|
+
ProjectForm,
|
|
3723
|
+
{
|
|
3724
|
+
editingProject: state.editingProject,
|
|
3725
|
+
onSave: handleProjectFormSave,
|
|
3726
|
+
onCancel: handleProjectFormCancel
|
|
3727
|
+
}
|
|
3728
|
+
),
|
|
3729
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx21(
|
|
3267
3730
|
ProjectLinkForm,
|
|
3268
3731
|
{
|
|
3269
3732
|
project: state.linkingProject,
|
|
@@ -3273,18 +3736,18 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3273
3736
|
onCancel: handleLinkCancel
|
|
3274
3737
|
}
|
|
3275
3738
|
),
|
|
3276
|
-
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */
|
|
3739
|
+
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx21(HelpOverlay, {})
|
|
3277
3740
|
] }),
|
|
3278
|
-
/* @__PURE__ */
|
|
3279
|
-
state.flash && /* @__PURE__ */
|
|
3741
|
+
/* @__PURE__ */ jsx21(Crumbs, { breadcrumbs: state.breadcrumbs }),
|
|
3742
|
+
state.flash && /* @__PURE__ */ jsx21(FlashMessage, { message: state.flash.message, level: state.flash.level })
|
|
3280
3743
|
] });
|
|
3281
3744
|
}
|
|
3282
3745
|
|
|
3283
3746
|
// src/tui/index.tsx
|
|
3284
|
-
import { jsx as
|
|
3747
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
3285
3748
|
async function launchTUI(container, initialProject, latestVersion) {
|
|
3286
3749
|
const instance = render(
|
|
3287
|
-
/* @__PURE__ */
|
|
3750
|
+
/* @__PURE__ */ jsx22(App, { container, initialProject, latestVersion }),
|
|
3288
3751
|
{
|
|
3289
3752
|
exitOnCtrlC: true
|
|
3290
3753
|
}
|
|
@@ -3294,4 +3757,4 @@ async function launchTUI(container, initialProject, latestVersion) {
|
|
|
3294
3757
|
export {
|
|
3295
3758
|
launchTUI
|
|
3296
3759
|
};
|
|
3297
|
-
//# sourceMappingURL=tui-
|
|
3760
|
+
//# sourceMappingURL=tui-NKAKDHTY.js.map
|