@tomkapa/tayto 0.3.1 → 0.4.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-FUNYPBWJ.js → chunk-74Q55TOV.js} +46 -2
- package/dist/chunk-74Q55TOV.js.map +1 -0
- package/dist/index.js +376 -120
- package/dist/index.js.map +1 -1
- package/dist/migrations/005_project_git_remote.sql +5 -0
- package/dist/{tui-5JJH67YY.js → tui-4GNIGMCK.js} +342 -132
- package/dist/tui-4GNIGMCK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-FUNYPBWJ.js.map +0 -1
- package/dist/tui-5JJH67YY.js.map +0 -1
|
@@ -5,16 +5,17 @@ import {
|
|
|
5
5
|
TaskStatus,
|
|
6
6
|
TaskType,
|
|
7
7
|
UIDependencyType,
|
|
8
|
+
detectGitRemote,
|
|
8
9
|
isTerminalStatus,
|
|
9
10
|
logger
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-74Q55TOV.js";
|
|
11
12
|
|
|
12
13
|
// src/tui/index.tsx
|
|
13
14
|
import { render } from "ink";
|
|
14
15
|
|
|
15
16
|
// src/tui/components/App.tsx
|
|
16
|
-
import { useReducer, useEffect as useEffect2, useCallback as useCallback2, useMemo as useMemo2, useState as
|
|
17
|
-
import { Box as
|
|
17
|
+
import { useReducer, useEffect as useEffect2, useCallback as useCallback2, useMemo as useMemo2, useState as useState7 } from "react";
|
|
18
|
+
import { Box as Box17, Text as Text17, useInput as useInput7, useApp, useStdout as useStdout4 } from "ink";
|
|
18
19
|
|
|
19
20
|
// src/tui/types.ts
|
|
20
21
|
var ViewType = {
|
|
@@ -26,6 +27,7 @@ var ViewType = {
|
|
|
26
27
|
ProjectCreate: "project-create",
|
|
27
28
|
DependencyList: "dependency-list",
|
|
28
29
|
EpicPicker: "epic-picker",
|
|
30
|
+
ProjectLink: "project-link",
|
|
29
31
|
Help: "help"
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -192,6 +194,7 @@ var initialState = {
|
|
|
192
194
|
epics: [],
|
|
193
195
|
epicSelectedIndex: 0,
|
|
194
196
|
selectedEpicIds: /* @__PURE__ */ new Set(),
|
|
197
|
+
linkingProject: null,
|
|
195
198
|
isEpicReordering: false,
|
|
196
199
|
epicReorderSnapshot: null
|
|
197
200
|
};
|
|
@@ -214,6 +217,7 @@ function appReducer(state, action) {
|
|
|
214
217
|
confirmDelete: null,
|
|
215
218
|
isSearchActive: false,
|
|
216
219
|
formData: null,
|
|
220
|
+
linkingProject: null,
|
|
217
221
|
focusedPanel: "list"
|
|
218
222
|
};
|
|
219
223
|
}
|
|
@@ -396,6 +400,8 @@ function appReducer(state, action) {
|
|
|
396
400
|
epicReorderSnapshot: null
|
|
397
401
|
};
|
|
398
402
|
}
|
|
403
|
+
case "SET_LINKING_PROJECT":
|
|
404
|
+
return { ...state, linkingProject: action.project };
|
|
399
405
|
}
|
|
400
406
|
}
|
|
401
407
|
|
|
@@ -1314,6 +1320,7 @@ function ProjectSelector({
|
|
|
1314
1320
|
onSelect,
|
|
1315
1321
|
onCreate,
|
|
1316
1322
|
onSetDefault,
|
|
1323
|
+
onLink,
|
|
1317
1324
|
onCancel
|
|
1318
1325
|
}) {
|
|
1319
1326
|
const [selectedIndex, setSelectedIndex] = useState3(() => {
|
|
@@ -1344,6 +1351,13 @@ function ProjectSelector({
|
|
|
1344
1351
|
}
|
|
1345
1352
|
return;
|
|
1346
1353
|
}
|
|
1354
|
+
if (input === "l") {
|
|
1355
|
+
const project = projects[selectedIndex];
|
|
1356
|
+
if (project) {
|
|
1357
|
+
onLink(project);
|
|
1358
|
+
}
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1347
1361
|
if (key.upArrow || input === "k") {
|
|
1348
1362
|
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1349
1363
|
}
|
|
@@ -1365,6 +1379,7 @@ function ProjectSelector({
|
|
|
1365
1379
|
] }),
|
|
1366
1380
|
/* @__PURE__ */ jsxs7(Box9, { paddingX: 1, children: [
|
|
1367
1381
|
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: " NAME".padEnd(30) }),
|
|
1382
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: "GIT REMOTE".padEnd(40) }),
|
|
1368
1383
|
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: "DESCRIPTION" })
|
|
1369
1384
|
] }),
|
|
1370
1385
|
projects.length === 0 ? /* @__PURE__ */ jsx9(Box9, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx9(Text9, { color: theme.fg, children: "No projects. Press 'c' to create one." }) }) : projects.map((project, i) => {
|
|
@@ -1373,11 +1388,13 @@ function ProjectSelector({
|
|
|
1373
1388
|
const activeMarker = isActive ? "*" : " ";
|
|
1374
1389
|
const defaultMarker = project.isDefault ? "D" : " ";
|
|
1375
1390
|
const marker = `${activeMarker}${defaultMarker}`;
|
|
1391
|
+
const remoteDisplay = (project.gitRemote ?? "").slice(0, 38).padEnd(40);
|
|
1376
1392
|
if (isSelected) {
|
|
1377
1393
|
return /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs7(Text9, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1378
1394
|
marker,
|
|
1379
1395
|
" ",
|
|
1380
1396
|
project.name.padEnd(27),
|
|
1397
|
+
remoteDisplay,
|
|
1381
1398
|
project.description
|
|
1382
1399
|
] }) }, project.id);
|
|
1383
1400
|
}
|
|
@@ -1387,11 +1404,12 @@ function ProjectSelector({
|
|
|
1387
1404
|
" ",
|
|
1388
1405
|
project.name.padEnd(27)
|
|
1389
1406
|
] }),
|
|
1407
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: remoteDisplay }),
|
|
1390
1408
|
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: project.description })
|
|
1391
1409
|
] }, project.id);
|
|
1392
1410
|
}),
|
|
1393
1411
|
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1 }),
|
|
1394
|
-
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "enter: select | d: set default | c: create | esc: back" }) })
|
|
1412
|
+
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "enter: select | d: set default | l: link git | c: create | esc: back" }) })
|
|
1395
1413
|
] });
|
|
1396
1414
|
}
|
|
1397
1415
|
|
|
@@ -1490,9 +1508,86 @@ function ProjectForm({ onSave, onCancel }) {
|
|
|
1490
1508
|
] });
|
|
1491
1509
|
}
|
|
1492
1510
|
|
|
1493
|
-
// src/tui/components/
|
|
1494
|
-
import {
|
|
1511
|
+
// src/tui/components/ProjectLinkForm.tsx
|
|
1512
|
+
import { useState as useState5 } from "react";
|
|
1513
|
+
import { Box as Box11, Text as Text11, useInput as useInput5 } from "ink";
|
|
1495
1514
|
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1515
|
+
function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
|
|
1516
|
+
const [remoteUrl, setRemoteUrl] = useState5(project.gitRemote ?? "");
|
|
1517
|
+
useInput5((input, key) => {
|
|
1518
|
+
if (key.escape) {
|
|
1519
|
+
onCancel();
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
if (input === "s" && key.ctrl) {
|
|
1523
|
+
const trimmed = remoteUrl.trim();
|
|
1524
|
+
if (trimmed) {
|
|
1525
|
+
onSave(trimmed);
|
|
1526
|
+
}
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
if (input === "d" && key.ctrl) {
|
|
1530
|
+
const detected = onDetect();
|
|
1531
|
+
if (detected) {
|
|
1532
|
+
setRemoteUrl(detected);
|
|
1533
|
+
}
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
if (input === "u" && key.ctrl) {
|
|
1537
|
+
if (project.gitRemote) {
|
|
1538
|
+
onUnlink();
|
|
1539
|
+
}
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (key.backspace || key.delete) {
|
|
1543
|
+
setRemoteUrl((v) => v.slice(0, -1));
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
if (input && !key.ctrl && !key.meta) {
|
|
1547
|
+
setRemoteUrl((v) => v + input);
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
|
|
1551
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 0, children: [
|
|
1552
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.title, bold: true, children: [
|
|
1553
|
+
" ",
|
|
1554
|
+
"link git remote"
|
|
1555
|
+
] }),
|
|
1556
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.titleCounter, bold: true, children: [
|
|
1557
|
+
" ",
|
|
1558
|
+
"[",
|
|
1559
|
+
project.name,
|
|
1560
|
+
"]"
|
|
1561
|
+
] })
|
|
1562
|
+
] }),
|
|
1563
|
+
/* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
1564
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 1, children: [
|
|
1565
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.dialog.label, bold: true, children: "Current:" }),
|
|
1566
|
+
/* @__PURE__ */ jsx11(
|
|
1567
|
+
Text11,
|
|
1568
|
+
{
|
|
1569
|
+
color: project.gitRemote ? theme.yaml.value : theme.table.fg,
|
|
1570
|
+
dimColor: !project.gitRemote,
|
|
1571
|
+
children: project.gitRemote ?? "(none)"
|
|
1572
|
+
}
|
|
1573
|
+
)
|
|
1574
|
+
] }),
|
|
1575
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 1, marginTop: 1, children: [
|
|
1576
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.dialog.label, bold: true, children: "Remote URL: " }),
|
|
1577
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.yaml.value, children: [
|
|
1578
|
+
remoteUrl,
|
|
1579
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.titleHighlight, children: "_" })
|
|
1580
|
+
] })
|
|
1581
|
+
] })
|
|
1582
|
+
] }),
|
|
1583
|
+
/* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
|
|
1584
|
+
/* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "ctrl+s: save | ctrl+d: detect from cwd | ctrl+u: unlink | esc: cancel" }) })
|
|
1585
|
+
] });
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/tui/components/HelpOverlay.tsx
|
|
1589
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1590
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1496
1591
|
var SECTIONS = [
|
|
1497
1592
|
{
|
|
1498
1593
|
title: "NAVIGATION",
|
|
@@ -1520,6 +1615,8 @@ var SECTIONS = [
|
|
|
1520
1615
|
keys: [
|
|
1521
1616
|
["\u2190", "Enter reorder"],
|
|
1522
1617
|
["\u2191\u2193", "Move task"],
|
|
1618
|
+
["t", "Jump to top"],
|
|
1619
|
+
["b", "Jump to bottom"],
|
|
1523
1620
|
["\u2192", "Save position"],
|
|
1524
1621
|
["esc/\u2190", "Cancel"]
|
|
1525
1622
|
]
|
|
@@ -1552,8 +1649,8 @@ var SECTIONS = [
|
|
|
1552
1649
|
}
|
|
1553
1650
|
];
|
|
1554
1651
|
function HelpOverlay() {
|
|
1555
|
-
return /* @__PURE__ */
|
|
1556
|
-
|
|
1652
|
+
return /* @__PURE__ */ jsxs10(
|
|
1653
|
+
Box12,
|
|
1557
1654
|
{
|
|
1558
1655
|
flexDirection: "column",
|
|
1559
1656
|
borderStyle: "bold",
|
|
@@ -1561,35 +1658,35 @@ function HelpOverlay() {
|
|
|
1561
1658
|
paddingX: 2,
|
|
1562
1659
|
paddingY: 1,
|
|
1563
1660
|
children: [
|
|
1564
|
-
/* @__PURE__ */
|
|
1661
|
+
/* @__PURE__ */ jsxs10(Text12, { color: theme.title, bold: true, children: [
|
|
1565
1662
|
" ",
|
|
1566
1663
|
"Help"
|
|
1567
1664
|
] }),
|
|
1568
|
-
/* @__PURE__ */
|
|
1569
|
-
/* @__PURE__ */
|
|
1570
|
-
/* @__PURE__ */
|
|
1571
|
-
section.keys.map(([key, desc]) => /* @__PURE__ */
|
|
1572
|
-
/* @__PURE__ */
|
|
1665
|
+
/* @__PURE__ */ jsx12(Text12, { children: " " }),
|
|
1666
|
+
/* @__PURE__ */ jsx12(Box12, { flexDirection: "row", gap: 4, children: SECTIONS.map((section) => /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", children: [
|
|
1667
|
+
/* @__PURE__ */ jsx12(Text12, { color: theme.table.headerFg, bold: true, children: section.title }),
|
|
1668
|
+
section.keys.map(([key, desc]) => /* @__PURE__ */ jsxs10(Box12, { gap: 1, children: [
|
|
1669
|
+
/* @__PURE__ */ jsxs10(Text12, { color: theme.menu.key, bold: true, children: [
|
|
1573
1670
|
"<",
|
|
1574
1671
|
(key ?? "").padEnd(5),
|
|
1575
1672
|
">"
|
|
1576
1673
|
] }),
|
|
1577
|
-
/* @__PURE__ */
|
|
1674
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: desc })
|
|
1578
1675
|
] }, key))
|
|
1579
1676
|
] }, section.title)) }),
|
|
1580
|
-
/* @__PURE__ */
|
|
1581
|
-
/* @__PURE__ */
|
|
1677
|
+
/* @__PURE__ */ jsx12(Text12, { children: " " }),
|
|
1678
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Press any key to close" })
|
|
1582
1679
|
]
|
|
1583
1680
|
}
|
|
1584
1681
|
);
|
|
1585
1682
|
}
|
|
1586
1683
|
|
|
1587
1684
|
// src/tui/components/ConfirmDialog.tsx
|
|
1588
|
-
import { Box as
|
|
1589
|
-
import { jsx as
|
|
1685
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1686
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1590
1687
|
function ConfirmDialog({ task }) {
|
|
1591
|
-
return /* @__PURE__ */
|
|
1592
|
-
|
|
1688
|
+
return /* @__PURE__ */ jsxs11(
|
|
1689
|
+
Box13,
|
|
1593
1690
|
{
|
|
1594
1691
|
flexDirection: "column",
|
|
1595
1692
|
borderStyle: "bold",
|
|
@@ -1598,17 +1695,17 @@ function ConfirmDialog({ task }) {
|
|
|
1598
1695
|
paddingY: 1,
|
|
1599
1696
|
alignSelf: "center",
|
|
1600
1697
|
children: [
|
|
1601
|
-
/* @__PURE__ */
|
|
1602
|
-
/* @__PURE__ */
|
|
1603
|
-
/* @__PURE__ */
|
|
1698
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.dialog.label, bold: true, children: "<Delete>" }),
|
|
1699
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " }),
|
|
1700
|
+
/* @__PURE__ */ jsxs11(Text13, { color: theme.dialog.fg, children: [
|
|
1604
1701
|
'Delete task "',
|
|
1605
1702
|
task.name,
|
|
1606
1703
|
'"?'
|
|
1607
1704
|
] }),
|
|
1608
|
-
/* @__PURE__ */
|
|
1609
|
-
/* @__PURE__ */
|
|
1610
|
-
/* @__PURE__ */
|
|
1611
|
-
|
|
1705
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " }),
|
|
1706
|
+
/* @__PURE__ */ jsxs11(Box13, { gap: 3, children: [
|
|
1707
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(
|
|
1708
|
+
Text13,
|
|
1612
1709
|
{
|
|
1613
1710
|
backgroundColor: theme.dialog.buttonFocusBg,
|
|
1614
1711
|
color: theme.dialog.buttonFocusFg,
|
|
@@ -1616,7 +1713,7 @@ function ConfirmDialog({ task }) {
|
|
|
1616
1713
|
children: " y: OK "
|
|
1617
1714
|
}
|
|
1618
1715
|
) }),
|
|
1619
|
-
/* @__PURE__ */
|
|
1716
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text13, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Cancel " }) })
|
|
1620
1717
|
] })
|
|
1621
1718
|
]
|
|
1622
1719
|
}
|
|
@@ -1624,8 +1721,8 @@ function ConfirmDialog({ task }) {
|
|
|
1624
1721
|
}
|
|
1625
1722
|
|
|
1626
1723
|
// src/tui/components/DependencyList.tsx
|
|
1627
|
-
import { Box as
|
|
1628
|
-
import { Fragment as Fragment2, jsx as
|
|
1724
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1725
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1629
1726
|
function TaskRow({
|
|
1630
1727
|
task,
|
|
1631
1728
|
globalIndex,
|
|
@@ -1633,16 +1730,16 @@ function TaskRow({
|
|
|
1633
1730
|
}) {
|
|
1634
1731
|
const isSelected = globalIndex === selectedIndex;
|
|
1635
1732
|
const statusColor = STATUS_COLOR[task.status] ?? theme.table.fg;
|
|
1636
|
-
return /* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsx14(Box14, { children: isSelected ? /* @__PURE__ */ jsxs12(Text14, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1637
1734
|
"> ",
|
|
1638
1735
|
task.id.padEnd(12),
|
|
1639
1736
|
task.status.padEnd(14),
|
|
1640
1737
|
task.name
|
|
1641
|
-
] }) : /* @__PURE__ */
|
|
1642
|
-
/* @__PURE__ */
|
|
1643
|
-
/* @__PURE__ */
|
|
1644
|
-
/* @__PURE__ */
|
|
1645
|
-
/* @__PURE__ */
|
|
1738
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
1739
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " }),
|
|
1740
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.yaml.value, children: task.id.padEnd(12) }),
|
|
1741
|
+
/* @__PURE__ */ jsx14(Text14, { color: statusColor, children: task.status.padEnd(14) }),
|
|
1742
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.table.fg, children: task.name })
|
|
1646
1743
|
] }) }, task.id);
|
|
1647
1744
|
}
|
|
1648
1745
|
function DependencyList({
|
|
@@ -1663,23 +1760,23 @@ function DependencyList({
|
|
|
1663
1760
|
const relatedOffset = offset;
|
|
1664
1761
|
offset += related.length;
|
|
1665
1762
|
const duplicatesOffset = offset;
|
|
1666
|
-
return /* @__PURE__ */
|
|
1667
|
-
/* @__PURE__ */
|
|
1668
|
-
/* @__PURE__ */
|
|
1763
|
+
return /* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
|
|
1764
|
+
/* @__PURE__ */ jsxs12(Box14, { gap: 0, children: [
|
|
1765
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.title, bold: true, children: [
|
|
1669
1766
|
" ",
|
|
1670
1767
|
"dependencies"
|
|
1671
1768
|
] }),
|
|
1672
|
-
/* @__PURE__ */
|
|
1673
|
-
/* @__PURE__ */
|
|
1674
|
-
/* @__PURE__ */
|
|
1769
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.fg, children: "(" }),
|
|
1770
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.titleHighlight, bold: true, children: task.name }),
|
|
1771
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.fg, children: ")" })
|
|
1675
1772
|
] }),
|
|
1676
|
-
/* @__PURE__ */
|
|
1677
|
-
/* @__PURE__ */
|
|
1773
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1774
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1678
1775
|
"BLOCKED BY (",
|
|
1679
1776
|
blockers.length,
|
|
1680
1777
|
")"
|
|
1681
1778
|
] }),
|
|
1682
|
-
blockers.length === 0 ? /* @__PURE__ */
|
|
1779
|
+
blockers.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No blockers" }) : blockers.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1683
1780
|
TaskRow,
|
|
1684
1781
|
{
|
|
1685
1782
|
task: t,
|
|
@@ -1689,13 +1786,13 @@ function DependencyList({
|
|
|
1689
1786
|
t.id
|
|
1690
1787
|
))
|
|
1691
1788
|
] }),
|
|
1692
|
-
/* @__PURE__ */
|
|
1693
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1790
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1694
1791
|
"BLOCKS (",
|
|
1695
1792
|
dependents.length,
|
|
1696
1793
|
")"
|
|
1697
1794
|
] }),
|
|
1698
|
-
dependents.length === 0 ? /* @__PURE__ */
|
|
1795
|
+
dependents.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No dependents" }) : dependents.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1699
1796
|
TaskRow,
|
|
1700
1797
|
{
|
|
1701
1798
|
task: t,
|
|
@@ -1705,13 +1802,13 @@ function DependencyList({
|
|
|
1705
1802
|
t.id
|
|
1706
1803
|
))
|
|
1707
1804
|
] }),
|
|
1708
|
-
/* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
1805
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1806
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1710
1807
|
"RELATES TO (",
|
|
1711
1808
|
related.length,
|
|
1712
1809
|
")"
|
|
1713
1810
|
] }),
|
|
1714
|
-
related.length === 0 ? /* @__PURE__ */
|
|
1811
|
+
related.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No related tasks" }) : related.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1715
1812
|
TaskRow,
|
|
1716
1813
|
{
|
|
1717
1814
|
task: t,
|
|
@@ -1721,13 +1818,13 @@ function DependencyList({
|
|
|
1721
1818
|
t.id
|
|
1722
1819
|
))
|
|
1723
1820
|
] }),
|
|
1724
|
-
/* @__PURE__ */
|
|
1725
|
-
/* @__PURE__ */
|
|
1821
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1822
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1726
1823
|
"DUPLICATES (",
|
|
1727
1824
|
duplicates.length,
|
|
1728
1825
|
")"
|
|
1729
1826
|
] }),
|
|
1730
|
-
duplicates.length === 0 ? /* @__PURE__ */
|
|
1827
|
+
duplicates.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No duplicate tasks" }) : duplicates.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1731
1828
|
TaskRow,
|
|
1732
1829
|
{
|
|
1733
1830
|
task: t,
|
|
@@ -1737,19 +1834,19 @@ function DependencyList({
|
|
|
1737
1834
|
t.id
|
|
1738
1835
|
))
|
|
1739
1836
|
] }),
|
|
1740
|
-
/* @__PURE__ */
|
|
1741
|
-
isAddingDep && /* @__PURE__ */
|
|
1742
|
-
/* @__PURE__ */
|
|
1743
|
-
/* @__PURE__ */
|
|
1744
|
-
/* @__PURE__ */
|
|
1837
|
+
/* @__PURE__ */ jsx14(Box14, { flexGrow: 1 }),
|
|
1838
|
+
isAddingDep && /* @__PURE__ */ jsxs12(Box14, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
|
|
1839
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.prompt, children: "depends on (id or id:type): " }),
|
|
1840
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.prompt, children: addDepInput }),
|
|
1841
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.promptSuggest, children: "_" })
|
|
1745
1842
|
] }),
|
|
1746
|
-
/* @__PURE__ */
|
|
1843
|
+
/* @__PURE__ */ jsx14(Box14, { paddingX: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "a: add dep (id or id:relates-to) | x: remove selected | enter: go to task | esc: back" }) })
|
|
1747
1844
|
] });
|
|
1748
1845
|
}
|
|
1749
1846
|
|
|
1750
1847
|
// src/tui/components/EpicPanel.tsx
|
|
1751
|
-
import { Box as
|
|
1752
|
-
import { jsx as
|
|
1848
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
1849
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1753
1850
|
var PAGE_SIZE2 = 20;
|
|
1754
1851
|
function EpicPanel({
|
|
1755
1852
|
epics,
|
|
@@ -1762,34 +1859,34 @@ function EpicPanel({
|
|
|
1762
1859
|
const currentPage = Math.floor(selectedIndex / PAGE_SIZE2);
|
|
1763
1860
|
const viewStart = currentPage * PAGE_SIZE2;
|
|
1764
1861
|
const visibleEpics = epics.slice(viewStart, viewStart + PAGE_SIZE2);
|
|
1765
|
-
return /* @__PURE__ */
|
|
1766
|
-
|
|
1862
|
+
return /* @__PURE__ */ jsxs13(
|
|
1863
|
+
Box15,
|
|
1767
1864
|
{
|
|
1768
1865
|
flexDirection: "column",
|
|
1769
1866
|
width: 48,
|
|
1770
1867
|
borderStyle: "bold",
|
|
1771
1868
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
1772
1869
|
children: [
|
|
1773
|
-
/* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1870
|
+
/* @__PURE__ */ jsxs13(Box15, { children: [
|
|
1871
|
+
/* @__PURE__ */ jsxs13(Text15, { color: theme.title, bold: true, children: [
|
|
1775
1872
|
" ",
|
|
1776
1873
|
"epics"
|
|
1777
1874
|
] }),
|
|
1778
|
-
/* @__PURE__ */
|
|
1875
|
+
/* @__PURE__ */ jsxs13(Text15, { color: theme.titleCounter, bold: true, children: [
|
|
1779
1876
|
"[",
|
|
1780
1877
|
epics.length,
|
|
1781
1878
|
"]"
|
|
1782
1879
|
] }),
|
|
1783
|
-
isReordering && /* @__PURE__ */
|
|
1880
|
+
isReordering && /* @__PURE__ */ jsxs13(Text15, { color: theme.flash.warn, bold: true, children: [
|
|
1784
1881
|
" ",
|
|
1785
1882
|
"REORDER"
|
|
1786
1883
|
] }),
|
|
1787
|
-
filterActive && /* @__PURE__ */
|
|
1884
|
+
filterActive && /* @__PURE__ */ jsxs13(Text15, { color: theme.titleFilter, children: [
|
|
1788
1885
|
" *",
|
|
1789
1886
|
selectedEpicIds.size
|
|
1790
1887
|
] })
|
|
1791
1888
|
] }),
|
|
1792
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx15(Box15, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: epics.length === 0 ? /* @__PURE__ */ jsx15(Box15, { paddingX: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "No epics" }) }) : visibleEpics.map((epic, i) => {
|
|
1793
1890
|
const actualIndex = viewStart + i;
|
|
1794
1891
|
const isSelected = actualIndex === selectedIndex && isFocused;
|
|
1795
1892
|
const isChecked = selectedEpicIds.has(epic.id);
|
|
@@ -1797,21 +1894,21 @@ function EpicPanel({
|
|
|
1797
1894
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
1798
1895
|
if (isSelected) {
|
|
1799
1896
|
const cursorBg = isReordering ? theme.flash.warn : theme.table.cursorBg;
|
|
1800
|
-
return /* @__PURE__ */
|
|
1897
|
+
return /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs13(Text15, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1801
1898
|
isReordering ? "~ " : " ",
|
|
1802
1899
|
marker,
|
|
1803
1900
|
" ",
|
|
1804
1901
|
epic.name
|
|
1805
1902
|
] }) }, epic.id);
|
|
1806
1903
|
}
|
|
1807
|
-
return /* @__PURE__ */
|
|
1904
|
+
return /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs13(Text15, { color: isChecked ? theme.titleHighlight : statusColor, children: [
|
|
1808
1905
|
" ",
|
|
1809
1906
|
marker,
|
|
1810
1907
|
" ",
|
|
1811
1908
|
epic.name
|
|
1812
1909
|
] }) }, epic.id);
|
|
1813
1910
|
}) }),
|
|
1814
|
-
epics.length > PAGE_SIZE2 && /* @__PURE__ */
|
|
1911
|
+
epics.length > PAGE_SIZE2 && /* @__PURE__ */ jsx15(Box15, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs13(Text15, { dimColor: true, children: [
|
|
1815
1912
|
"[",
|
|
1816
1913
|
viewStart + 1,
|
|
1817
1914
|
"-",
|
|
@@ -1826,16 +1923,16 @@ function EpicPanel({
|
|
|
1826
1923
|
}
|
|
1827
1924
|
|
|
1828
1925
|
// src/tui/components/EpicPicker.tsx
|
|
1829
|
-
import { useState as
|
|
1830
|
-
import { Box as
|
|
1831
|
-
import { Fragment as Fragment3, jsx as
|
|
1926
|
+
import { useState as useState6 } from "react";
|
|
1927
|
+
import { Box as Box16, Text as Text16, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
1928
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1832
1929
|
function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
1833
1930
|
const { stdout } = useStdout3();
|
|
1834
1931
|
const termHeight = stdout.rows > 0 ? stdout.rows : 24;
|
|
1835
1932
|
const maxVisible = Math.max(3, termHeight - 10);
|
|
1836
|
-
const [searchQuery, setSearchQuery] =
|
|
1837
|
-
const [isSearching, setIsSearching] =
|
|
1838
|
-
const [cursorIndex, setCursorIndex] =
|
|
1933
|
+
const [searchQuery, setSearchQuery] = useState6("");
|
|
1934
|
+
const [isSearching, setIsSearching] = useState6(false);
|
|
1935
|
+
const [cursorIndex, setCursorIndex] = useState6(0);
|
|
1839
1936
|
const filtered = epics.filter((e) => {
|
|
1840
1937
|
if (!searchQuery.trim()) return true;
|
|
1841
1938
|
const q = searchQuery.toLowerCase();
|
|
@@ -1849,7 +1946,7 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1849
1946
|
viewStart = cursorIndex;
|
|
1850
1947
|
}
|
|
1851
1948
|
const visible = filtered.slice(viewStart, viewStart + maxVisible);
|
|
1852
|
-
|
|
1949
|
+
useInput6((input, key) => {
|
|
1853
1950
|
if (isSearching) {
|
|
1854
1951
|
if (key.escape) {
|
|
1855
1952
|
setIsSearching(false);
|
|
@@ -1901,53 +1998,53 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1901
1998
|
return;
|
|
1902
1999
|
}
|
|
1903
2000
|
});
|
|
1904
|
-
return /* @__PURE__ */
|
|
1905
|
-
/* @__PURE__ */
|
|
1906
|
-
/* @__PURE__ */
|
|
2001
|
+
return /* @__PURE__ */ jsxs14(Box16, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
|
|
2002
|
+
/* @__PURE__ */ jsxs14(Box16, { gap: 0, children: [
|
|
2003
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.title, bold: true, children: [
|
|
1907
2004
|
" ",
|
|
1908
2005
|
"assign to epic"
|
|
1909
2006
|
] }),
|
|
1910
|
-
/* @__PURE__ */
|
|
2007
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.titleCounter, bold: true, children: [
|
|
1911
2008
|
" ",
|
|
1912
2009
|
"[",
|
|
1913
2010
|
epics.length,
|
|
1914
2011
|
"]"
|
|
1915
2012
|
] })
|
|
1916
2013
|
] }),
|
|
1917
|
-
isSearching ? /* @__PURE__ */
|
|
1918
|
-
/* @__PURE__ */
|
|
1919
|
-
/* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
] }) : searchQuery ? /* @__PURE__ */
|
|
2014
|
+
isSearching ? /* @__PURE__ */ jsxs14(Box16, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
|
|
2015
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: "/" }),
|
|
2016
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: searchQuery }),
|
|
2017
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.promptSuggest, children: "_" })
|
|
2018
|
+
] }) : searchQuery ? /* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: theme.titleFilter, children: [
|
|
1922
2019
|
"/",
|
|
1923
2020
|
searchQuery
|
|
1924
2021
|
] }) }) : null,
|
|
1925
|
-
/* @__PURE__ */
|
|
2022
|
+
/* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: theme.table.headerFg, bold: true, children: [
|
|
1926
2023
|
" ",
|
|
1927
2024
|
"ID".padEnd(14),
|
|
1928
2025
|
"STATUS".padEnd(14),
|
|
1929
2026
|
"NAME"
|
|
1930
2027
|
] }) }),
|
|
1931
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
2028
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx16(Box16, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "No epics match the filter" }) }) : visible.map((epic, i) => {
|
|
1932
2029
|
const actualIndex = viewStart + i;
|
|
1933
2030
|
const isCursor = actualIndex === cursorIndex;
|
|
1934
2031
|
const isCurrent = epic.id === currentEpicId;
|
|
1935
2032
|
const marker = isCurrent ? "* " : " ";
|
|
1936
2033
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
1937
|
-
return /* @__PURE__ */
|
|
2034
|
+
return /* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs14(Text16, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1938
2035
|
"> ",
|
|
1939
2036
|
epic.id.padEnd(14),
|
|
1940
2037
|
epic.status.padEnd(14),
|
|
1941
2038
|
epic.name
|
|
1942
|
-
] }) : /* @__PURE__ */
|
|
1943
|
-
/* @__PURE__ */
|
|
1944
|
-
/* @__PURE__ */
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
2039
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
2040
|
+
/* @__PURE__ */ jsx16(Text16, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: marker }),
|
|
2041
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.yaml.value, children: epic.id.padEnd(14) }),
|
|
2042
|
+
/* @__PURE__ */ jsx16(Text16, { color: statusColor, children: epic.status.padEnd(14) }),
|
|
2043
|
+
/* @__PURE__ */ jsx16(Text16, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: epic.name })
|
|
1947
2044
|
] }) }, epic.id);
|
|
1948
2045
|
}),
|
|
1949
|
-
/* @__PURE__ */
|
|
1950
|
-
filtered.length > maxVisible && /* @__PURE__ */
|
|
2046
|
+
/* @__PURE__ */ jsx16(Box16, { flexGrow: 1 }),
|
|
2047
|
+
filtered.length > maxVisible && /* @__PURE__ */ jsx16(Box16, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs14(Text16, { dimColor: true, children: [
|
|
1951
2048
|
"[",
|
|
1952
2049
|
viewStart + 1,
|
|
1953
2050
|
"-",
|
|
@@ -1956,7 +2053,7 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1956
2053
|
filtered.length,
|
|
1957
2054
|
"]"
|
|
1958
2055
|
] }) }),
|
|
1959
|
-
/* @__PURE__ */
|
|
2056
|
+
/* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "enter: assign | x: unassign | /: search | esc: cancel" }) })
|
|
1960
2057
|
] });
|
|
1961
2058
|
}
|
|
1962
2059
|
|
|
@@ -1996,7 +2093,7 @@ function useAutoRefetch(dbPath, onRefetch) {
|
|
|
1996
2093
|
}
|
|
1997
2094
|
|
|
1998
2095
|
// src/tui/components/App.tsx
|
|
1999
|
-
import { jsx as
|
|
2096
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2000
2097
|
var STATUS_CYCLE = [
|
|
2001
2098
|
TaskStatus.Backlog,
|
|
2002
2099
|
TaskStatus.Todo,
|
|
@@ -2009,7 +2106,7 @@ function App({ container, initialProject }) {
|
|
|
2009
2106
|
const { exit } = useApp();
|
|
2010
2107
|
const { stdout } = useStdout4();
|
|
2011
2108
|
const [state, dispatch] = useReducer(appReducer, initialState);
|
|
2012
|
-
const [, setResizeTick] =
|
|
2109
|
+
const [, setResizeTick] = useState7(0);
|
|
2013
2110
|
useEffect2(() => {
|
|
2014
2111
|
const onResize = () => {
|
|
2015
2112
|
setResizeTick((n) => n + 1);
|
|
@@ -2131,6 +2228,37 @@ function App({ container, initialProject }) {
|
|
|
2131
2228
|
});
|
|
2132
2229
|
loadEpics();
|
|
2133
2230
|
}, [container, state.epics, state.epicSelectedIndex, loadEpics]);
|
|
2231
|
+
const rerankSelectedToEdge = useCallback2(
|
|
2232
|
+
(kind, edge) => {
|
|
2233
|
+
const isEpic = kind === "epic";
|
|
2234
|
+
const item = isEpic ? state.epics[state.epicSelectedIndex] : state.tasks[state.selectedIndex];
|
|
2235
|
+
if (!item) return;
|
|
2236
|
+
const result = container.taskService.rerankTask({
|
|
2237
|
+
taskId: item.id,
|
|
2238
|
+
...edge === "top" ? { top: true } : { bottom: true }
|
|
2239
|
+
});
|
|
2240
|
+
dispatch({
|
|
2241
|
+
type: isEpic ? "EXIT_EPIC_REORDER" : "EXIT_REORDER",
|
|
2242
|
+
save: result.ok
|
|
2243
|
+
});
|
|
2244
|
+
dispatch({
|
|
2245
|
+
type: "FLASH",
|
|
2246
|
+
message: result.ok ? `${isEpic ? "Epic moved" : "Moved"} to ${edge}` : result.error.message,
|
|
2247
|
+
level: result.ok ? "info" : "error"
|
|
2248
|
+
});
|
|
2249
|
+
if (isEpic) loadEpics();
|
|
2250
|
+
else loadTasks();
|
|
2251
|
+
},
|
|
2252
|
+
[
|
|
2253
|
+
container,
|
|
2254
|
+
state.tasks,
|
|
2255
|
+
state.selectedIndex,
|
|
2256
|
+
state.epics,
|
|
2257
|
+
state.epicSelectedIndex,
|
|
2258
|
+
loadTasks,
|
|
2259
|
+
loadEpics
|
|
2260
|
+
]
|
|
2261
|
+
);
|
|
2134
2262
|
const refetchAll = useCallback2(() => {
|
|
2135
2263
|
loadProjects();
|
|
2136
2264
|
loadTasks();
|
|
@@ -2143,7 +2271,7 @@ function App({ container, initialProject }) {
|
|
|
2143
2271
|
useEffect2(() => {
|
|
2144
2272
|
if (state.projects.length > 0 && !state.activeProject) {
|
|
2145
2273
|
logger.info(`TUI.resolveProject: resolving initialProject=${initialProject ?? "(default)"}`);
|
|
2146
|
-
const result = container.projectService.
|
|
2274
|
+
const result = container.projectService.resolveProjectWithGit(initialProject);
|
|
2147
2275
|
if (result.ok) {
|
|
2148
2276
|
logger.info(
|
|
2149
2277
|
`TUI.resolveProject: resolved to key=${result.value.key} name=${result.value.name}`
|
|
@@ -2174,7 +2302,7 @@ function App({ container, initialProject }) {
|
|
|
2174
2302
|
}
|
|
2175
2303
|
return void 0;
|
|
2176
2304
|
}, [state.flash]);
|
|
2177
|
-
|
|
2305
|
+
useInput7((input, key) => {
|
|
2178
2306
|
if (state.confirmDelete) {
|
|
2179
2307
|
if (input === "y") {
|
|
2180
2308
|
const result = container.taskService.deleteTask(state.confirmDelete.id);
|
|
@@ -2199,7 +2327,7 @@ function App({ container, initialProject }) {
|
|
|
2199
2327
|
dispatch({ type: "GO_BACK" });
|
|
2200
2328
|
return;
|
|
2201
2329
|
}
|
|
2202
|
-
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.EpicPicker) {
|
|
2330
|
+
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) {
|
|
2203
2331
|
return;
|
|
2204
2332
|
}
|
|
2205
2333
|
if (state.activeView === ViewType.DependencyList && state.isAddingDep) {
|
|
@@ -2279,6 +2407,14 @@ function App({ container, initialProject }) {
|
|
|
2279
2407
|
dispatch({ type: "EPIC_REORDER_MOVE", direction: "down" });
|
|
2280
2408
|
return;
|
|
2281
2409
|
}
|
|
2410
|
+
if (input === "t") {
|
|
2411
|
+
rerankSelectedToEdge("epic", "top");
|
|
2412
|
+
return;
|
|
2413
|
+
}
|
|
2414
|
+
if (input === "b") {
|
|
2415
|
+
rerankSelectedToEdge("epic", "bottom");
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2282
2418
|
if (key.rightArrow) {
|
|
2283
2419
|
saveEpicReorder();
|
|
2284
2420
|
return;
|
|
@@ -2299,6 +2435,14 @@ function App({ container, initialProject }) {
|
|
|
2299
2435
|
dispatch({ type: "REORDER_MOVE", direction: "down" });
|
|
2300
2436
|
return;
|
|
2301
2437
|
}
|
|
2438
|
+
if (input === "t") {
|
|
2439
|
+
rerankSelectedToEdge("task", "top");
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
if (input === "b") {
|
|
2443
|
+
rerankSelectedToEdge("task", "bottom");
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2302
2446
|
if (key.rightArrow) {
|
|
2303
2447
|
saveReorder();
|
|
2304
2448
|
return;
|
|
@@ -2358,7 +2502,7 @@ function App({ container, initialProject }) {
|
|
|
2358
2502
|
dispatch({ type: "ENTER_EPIC_REORDER" });
|
|
2359
2503
|
dispatch({
|
|
2360
2504
|
type: "FLASH",
|
|
2361
|
-
message: "Reorder: \u2191\u2193 move, \u2192 save, \u2190 cancel",
|
|
2505
|
+
message: "Reorder: \u2191\u2193 move, t top, b bottom, \u2192 save, \u2190 cancel",
|
|
2362
2506
|
level: "info"
|
|
2363
2507
|
});
|
|
2364
2508
|
}
|
|
@@ -2482,7 +2626,11 @@ function App({ container, initialProject }) {
|
|
|
2482
2626
|
}
|
|
2483
2627
|
if (state.tasks.length > 0) {
|
|
2484
2628
|
dispatch({ type: "ENTER_REORDER" });
|
|
2485
|
-
dispatch({
|
|
2629
|
+
dispatch({
|
|
2630
|
+
type: "FLASH",
|
|
2631
|
+
message: "Reorder: \u2191\u2193 move, t top, b bottom, \u2192 save, \u2190 cancel",
|
|
2632
|
+
level: "info"
|
|
2633
|
+
});
|
|
2486
2634
|
}
|
|
2487
2635
|
return;
|
|
2488
2636
|
}
|
|
@@ -2780,6 +2928,57 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2780
2928
|
const handleProjectFormCancel = useCallback2(() => {
|
|
2781
2929
|
dispatch({ type: "GO_BACK" });
|
|
2782
2930
|
}, []);
|
|
2931
|
+
const handleProjectLink = useCallback2((project) => {
|
|
2932
|
+
dispatch({ type: "SET_LINKING_PROJECT", project });
|
|
2933
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectLink });
|
|
2934
|
+
}, []);
|
|
2935
|
+
const handleLinkSave = useCallback2(
|
|
2936
|
+
(remote) => {
|
|
2937
|
+
if (!state.linkingProject) return;
|
|
2938
|
+
const result = container.projectService.linkGitRemote(state.linkingProject.id, remote);
|
|
2939
|
+
if (result.ok) {
|
|
2940
|
+
logger.info(
|
|
2941
|
+
`TUI.linkGitRemote: linked project=${state.linkingProject.id} remote=${result.value.gitRemote}`
|
|
2942
|
+
);
|
|
2943
|
+
dispatch({
|
|
2944
|
+
type: "FLASH",
|
|
2945
|
+
message: `Linked to: ${result.value.gitRemote}`,
|
|
2946
|
+
level: "info"
|
|
2947
|
+
});
|
|
2948
|
+
dispatch({ type: "GO_BACK" });
|
|
2949
|
+
loadProjects();
|
|
2950
|
+
} else {
|
|
2951
|
+
logger.error("TUI.linkGitRemote: failed", result.error);
|
|
2952
|
+
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2953
|
+
}
|
|
2954
|
+
},
|
|
2955
|
+
[container, state.linkingProject, loadProjects]
|
|
2956
|
+
);
|
|
2957
|
+
const handleLinkUnlink = useCallback2(() => {
|
|
2958
|
+
if (!state.linkingProject) return;
|
|
2959
|
+
const result = container.projectService.unlinkGitRemote(state.linkingProject.id);
|
|
2960
|
+
if (result.ok) {
|
|
2961
|
+
logger.info(`TUI.unlinkGitRemote: unlinked project=${state.linkingProject.id}`);
|
|
2962
|
+
dispatch({ type: "FLASH", message: "Git remote unlinked", level: "info" });
|
|
2963
|
+
dispatch({ type: "GO_BACK" });
|
|
2964
|
+
loadProjects();
|
|
2965
|
+
} else {
|
|
2966
|
+
logger.error("TUI.unlinkGitRemote: failed", result.error);
|
|
2967
|
+
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2968
|
+
}
|
|
2969
|
+
}, [container, state.linkingProject, loadProjects]);
|
|
2970
|
+
const handleLinkDetect = useCallback2(() => {
|
|
2971
|
+
const result = detectGitRemote();
|
|
2972
|
+
if (result.ok && result.value) {
|
|
2973
|
+
dispatch({ type: "FLASH", message: `Detected: ${result.value}`, level: "info" });
|
|
2974
|
+
return result.value;
|
|
2975
|
+
}
|
|
2976
|
+
dispatch({ type: "FLASH", message: "No git remote detected in cwd", level: "warn" });
|
|
2977
|
+
return null;
|
|
2978
|
+
}, []);
|
|
2979
|
+
const handleLinkCancel = useCallback2(() => {
|
|
2980
|
+
dispatch({ type: "GO_BACK" });
|
|
2981
|
+
}, []);
|
|
2783
2982
|
const handleProjectCancel = useCallback2(() => {
|
|
2784
2983
|
dispatch({ type: "GO_BACK" });
|
|
2785
2984
|
}, []);
|
|
@@ -2806,12 +3005,12 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2806
3005
|
loadDeps(previewTaskId);
|
|
2807
3006
|
}
|
|
2808
3007
|
}, [state.activeView, previewTaskId, loadDeps]);
|
|
2809
|
-
return /* @__PURE__ */
|
|
2810
|
-
/* @__PURE__ */
|
|
2811
|
-
/* @__PURE__ */
|
|
2812
|
-
state.confirmDelete && /* @__PURE__ */
|
|
2813
|
-
!state.confirmDelete && state.activeView === ViewType.TaskList && /* @__PURE__ */
|
|
2814
|
-
/* @__PURE__ */
|
|
3008
|
+
return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", height: stdout.rows, children: [
|
|
3009
|
+
/* @__PURE__ */ jsx17(Header, { state }),
|
|
3010
|
+
/* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [
|
|
3011
|
+
state.confirmDelete && /* @__PURE__ */ jsx17(ConfirmDialog, { task: state.confirmDelete }),
|
|
3012
|
+
!state.confirmDelete && state.activeView === ViewType.TaskList && /* @__PURE__ */ jsxs15(Box17, { flexDirection: "row", flexGrow: 1, children: [
|
|
3013
|
+
/* @__PURE__ */ jsx17(
|
|
2815
3014
|
EpicPanel,
|
|
2816
3015
|
{
|
|
2817
3016
|
epics: state.epics,
|
|
@@ -2821,7 +3020,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2821
3020
|
isReordering: state.isEpicReordering
|
|
2822
3021
|
}
|
|
2823
3022
|
),
|
|
2824
|
-
/* @__PURE__ */
|
|
3023
|
+
/* @__PURE__ */ jsx17(Box17, { width: taskListWidth, children: /* @__PURE__ */ jsx17(
|
|
2825
3024
|
TaskList,
|
|
2826
3025
|
{
|
|
2827
3026
|
tasks: state.tasks,
|
|
@@ -2842,7 +3041,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2842
3041
|
epicFilterActive: state.selectedEpicIds.size > 0
|
|
2843
3042
|
}
|
|
2844
3043
|
) }),
|
|
2845
|
-
/* @__PURE__ */
|
|
3044
|
+
/* @__PURE__ */ jsx17(Box17, { width: taskDetailWidth, children: previewTask ? /* @__PURE__ */ jsx17(
|
|
2846
3045
|
TaskDetail,
|
|
2847
3046
|
{
|
|
2848
3047
|
task: previewTask,
|
|
@@ -2853,24 +3052,24 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2853
3052
|
isFocused: state.focusedPanel === "detail",
|
|
2854
3053
|
scrollOffset: state.detailScrollOffset
|
|
2855
3054
|
}
|
|
2856
|
-
) : /* @__PURE__ */
|
|
2857
|
-
|
|
3055
|
+
) : /* @__PURE__ */ jsxs15(
|
|
3056
|
+
Box17,
|
|
2858
3057
|
{
|
|
2859
3058
|
flexDirection: "column",
|
|
2860
3059
|
flexGrow: 1,
|
|
2861
3060
|
borderStyle: "bold",
|
|
2862
3061
|
borderColor: theme.border,
|
|
2863
3062
|
children: [
|
|
2864
|
-
/* @__PURE__ */
|
|
3063
|
+
/* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsxs15(Text17, { color: theme.title, bold: true, children: [
|
|
2865
3064
|
" ",
|
|
2866
3065
|
"detail"
|
|
2867
3066
|
] }) }),
|
|
2868
|
-
/* @__PURE__ */
|
|
3067
|
+
/* @__PURE__ */ jsx17(Box17, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "No task selected" }) })
|
|
2869
3068
|
]
|
|
2870
3069
|
}
|
|
2871
3070
|
) })
|
|
2872
3071
|
] }),
|
|
2873
|
-
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */
|
|
3072
|
+
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2874
3073
|
TaskDetail,
|
|
2875
3074
|
{
|
|
2876
3075
|
task: state.selectedTask,
|
|
@@ -2881,7 +3080,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2881
3080
|
scrollOffset: state.detailScrollOffset
|
|
2882
3081
|
}
|
|
2883
3082
|
),
|
|
2884
|
-
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */
|
|
3083
|
+
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2885
3084
|
DependencyList,
|
|
2886
3085
|
{
|
|
2887
3086
|
task: state.selectedTask,
|
|
@@ -2894,7 +3093,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2894
3093
|
addDepInput: state.addDepInput
|
|
2895
3094
|
}
|
|
2896
3095
|
),
|
|
2897
|
-
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */
|
|
3096
|
+
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx17(
|
|
2898
3097
|
TaskForm,
|
|
2899
3098
|
{
|
|
2900
3099
|
editingTask: state.activeView === ViewType.TaskEdit ? state.selectedTask : null,
|
|
@@ -2904,7 +3103,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2904
3103
|
onCancel: handleFormCancel
|
|
2905
3104
|
}
|
|
2906
3105
|
),
|
|
2907
|
-
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */
|
|
3106
|
+
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2908
3107
|
EpicPicker,
|
|
2909
3108
|
{
|
|
2910
3109
|
epics: state.epics,
|
|
@@ -2913,7 +3112,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2913
3112
|
onCancel: handleEpicPickerCancel
|
|
2914
3113
|
}
|
|
2915
3114
|
),
|
|
2916
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */
|
|
3115
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx17(
|
|
2917
3116
|
ProjectSelector,
|
|
2918
3117
|
{
|
|
2919
3118
|
projects: state.projects,
|
|
@@ -2921,21 +3120,32 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2921
3120
|
onSelect: handleProjectSelect,
|
|
2922
3121
|
onCreate: handleProjectCreate,
|
|
2923
3122
|
onSetDefault: handleSetDefault,
|
|
3123
|
+
onLink: handleProjectLink,
|
|
2924
3124
|
onCancel: handleProjectCancel
|
|
2925
3125
|
}
|
|
2926
3126
|
),
|
|
2927
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */
|
|
2928
|
-
!state.confirmDelete && state.activeView === ViewType.
|
|
3127
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx17(ProjectForm, { onSave: handleProjectFormSave, onCancel: handleProjectFormCancel }),
|
|
3128
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx17(
|
|
3129
|
+
ProjectLinkForm,
|
|
3130
|
+
{
|
|
3131
|
+
project: state.linkingProject,
|
|
3132
|
+
onSave: handleLinkSave,
|
|
3133
|
+
onUnlink: handleLinkUnlink,
|
|
3134
|
+
onDetect: handleLinkDetect,
|
|
3135
|
+
onCancel: handleLinkCancel
|
|
3136
|
+
}
|
|
3137
|
+
),
|
|
3138
|
+
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx17(HelpOverlay, {})
|
|
2929
3139
|
] }),
|
|
2930
|
-
/* @__PURE__ */
|
|
2931
|
-
state.flash && /* @__PURE__ */
|
|
3140
|
+
/* @__PURE__ */ jsx17(Crumbs, { breadcrumbs: state.breadcrumbs }),
|
|
3141
|
+
state.flash && /* @__PURE__ */ jsx17(FlashMessage, { message: state.flash.message, level: state.flash.level })
|
|
2932
3142
|
] });
|
|
2933
3143
|
}
|
|
2934
3144
|
|
|
2935
3145
|
// src/tui/index.tsx
|
|
2936
|
-
import { jsx as
|
|
3146
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
2937
3147
|
async function launchTUI(container, initialProject) {
|
|
2938
|
-
const instance = render(/* @__PURE__ */
|
|
3148
|
+
const instance = render(/* @__PURE__ */ jsx18(App, { container, initialProject }), {
|
|
2939
3149
|
exitOnCtrlC: true
|
|
2940
3150
|
});
|
|
2941
3151
|
await instance.waitUntilExit();
|
|
@@ -2943,4 +3153,4 @@ async function launchTUI(container, initialProject) {
|
|
|
2943
3153
|
export {
|
|
2944
3154
|
launchTUI
|
|
2945
3155
|
};
|
|
2946
|
-
//# sourceMappingURL=tui-
|
|
3156
|
+
//# sourceMappingURL=tui-4GNIGMCK.js.map
|