ralphctl 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,7 +61,7 @@ import {
61
61
  ticketShowCommand,
62
62
  useCurrentPrompt,
63
63
  validateConfigValue
64
- } from "./chunk-4GHVNKLV.mjs";
64
+ } from "./chunk-EPDR6VO5.mjs";
65
65
  import {
66
66
  PromptCancelledError,
67
67
  projectAddCommand
@@ -71,7 +71,7 @@ import {
71
71
  } from "./chunk-3QBEBKMZ.mjs";
72
72
  import {
73
73
  ticketAddCommand
74
- } from "./chunk-JXMHLW42.mjs";
74
+ } from "./chunk-7JLZQICD.mjs";
75
75
  import {
76
76
  addProjectRepo,
77
77
  createProject,
@@ -108,7 +108,7 @@ import {
108
108
  sprintStartCommand,
109
109
  updateTaskStatus,
110
110
  withSuspendedTui
111
- } from "./chunk-CDOPLXFK.mjs";
111
+ } from "./chunk-CSC4TBJB.mjs";
112
112
  import {
113
113
  addTicket,
114
114
  allRequirementsApproved,
@@ -118,8 +118,9 @@ import {
118
118
  getTicket,
119
119
  listTickets,
120
120
  removeTicket,
121
+ truncate,
121
122
  updateTicket
122
- } from "./chunk-HL4ZMHCQ.mjs";
123
+ } from "./chunk-JOQO4HMM.mjs";
123
124
  import "./chunk-CFUVE2BP.mjs";
124
125
  import {
125
126
  getPrompt,
@@ -322,7 +323,7 @@ import { useEffect as useEffect28, useState as useState30 } from "react";
322
323
  import { Box as Box35, useStdout } from "ink";
323
324
 
324
325
  // src/integration/ui/tui/views/view-router.tsx
325
- import { useCallback as useCallback10, useMemo as useMemo34, useRef as useRef2, useState as useState29 } from "react";
326
+ import { useCallback as useCallback10, useMemo as useMemo35, useRef as useRef3, useState as useState29 } from "react";
326
327
  import { Box as Box34, useApp, useInput as useInput19 } from "ink";
327
328
 
328
329
  // src/integration/ui/tui/components/banner.tsx
@@ -1641,11 +1642,11 @@ function SettingsView() {
1641
1642
  }
1642
1643
 
1643
1644
  // src/integration/ui/tui/views/execute-view.tsx
1644
- import { useEffect as useEffect7, useRef, useState as useState7 } from "react";
1645
- import { Box as Box16, Text as Text15, useInput as useInput5 } from "ink";
1645
+ import { useEffect as useEffect8, useRef as useRef2, useState as useState8 } from "react";
1646
+ import { Box as Box17, Text as Text16, useInput as useInput5 } from "ink";
1646
1647
 
1647
1648
  // src/integration/ui/tui/runtime/hooks.ts
1648
- import { useCallback as useCallback4, useEffect as useEffect6, useState as useState6 } from "react";
1649
+ import { useCallback as useCallback4, useEffect as useEffect6, useRef, useState as useState6 } from "react";
1649
1650
  function useLoggerEvents(limit = 200) {
1650
1651
  const [buffer, setBuffer] = useState6([]);
1651
1652
  useEffect6(() => {
@@ -1674,14 +1675,31 @@ function useSignalEvents(bus, limit = 200) {
1674
1675
  }, [bus, limit]);
1675
1676
  return buffer;
1676
1677
  }
1678
+ var DASHBOARD_REFRESH_THROTTLE_MS = 500;
1677
1679
  function useDashboardData() {
1678
1680
  const [data, setData] = useState6(null);
1679
1681
  const [loading, setLoading] = useState6(true);
1680
1682
  const [error, setError] = useState6(null);
1681
1683
  const [counter, setCounter] = useState6(0);
1684
+ const lastRefreshAt = useRef(0);
1685
+ const pendingRefresh = useRef(null);
1682
1686
  const refresh = useCallback4(() => {
1683
1687
  setCounter((n) => n + 1);
1684
1688
  }, []);
1689
+ const scheduleRefresh = useCallback4(() => {
1690
+ const elapsed = Date.now() - lastRefreshAt.current;
1691
+ if (elapsed >= DASHBOARD_REFRESH_THROTTLE_MS) {
1692
+ lastRefreshAt.current = Date.now();
1693
+ setCounter((n) => n + 1);
1694
+ return;
1695
+ }
1696
+ if (pendingRefresh.current) return;
1697
+ pendingRefresh.current = setTimeout(() => {
1698
+ pendingRefresh.current = null;
1699
+ lastRefreshAt.current = Date.now();
1700
+ setCounter((n) => n + 1);
1701
+ }, DASHBOARD_REFRESH_THROTTLE_MS - elapsed);
1702
+ }, []);
1685
1703
  useEffect6(() => {
1686
1704
  const cancel = { current: false };
1687
1705
  setLoading(true);
@@ -1701,6 +1719,24 @@ function useDashboardData() {
1701
1719
  cancel.current = true;
1702
1720
  };
1703
1721
  }, [counter]);
1722
+ useEffect6(() => {
1723
+ let bus;
1724
+ try {
1725
+ bus = getSharedDeps().signalBus;
1726
+ } catch {
1727
+ return;
1728
+ }
1729
+ const unsubscribe = bus.subscribe(() => {
1730
+ scheduleRefresh();
1731
+ });
1732
+ return () => {
1733
+ unsubscribe();
1734
+ if (pendingRefresh.current) {
1735
+ clearTimeout(pendingRefresh.current);
1736
+ pendingRefresh.current = null;
1737
+ }
1738
+ };
1739
+ }, [scheduleRefresh]);
1704
1740
  return { data, loading, error, refresh };
1705
1741
  }
1706
1742
 
@@ -1790,9 +1826,34 @@ function SprintSummary({ tasks, width = 30 }) {
1790
1826
  }
1791
1827
 
1792
1828
  // src/integration/ui/tui/components/log-tail.tsx
1793
- import "react";
1829
+ import { useMemo as useMemo5 } from "react";
1830
+ import { Box as Box15, Text as Text14 } from "ink";
1831
+
1832
+ // src/integration/ui/tui/components/spinner.tsx
1833
+ import { useEffect as useEffect7, useState as useState7 } from "react";
1794
1834
  import { Box as Box14, Text as Text13 } from "ink";
1795
1835
  import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1836
+ function Spinner({ label, color: color2 = inkColors.warning, intervalMs = 80 }) {
1837
+ const [frame, setFrame] = useState7(0);
1838
+ const isAwaitingPrompt = label.startsWith("Awaiting");
1839
+ useEffect7(() => {
1840
+ if (isAwaitingPrompt) return;
1841
+ const id = setInterval(() => {
1842
+ setFrame((f) => (f + 1) % glyphs.spinner.length);
1843
+ }, intervalMs);
1844
+ return () => {
1845
+ clearInterval(id);
1846
+ };
1847
+ }, [intervalMs, isAwaitingPrompt]);
1848
+ if (isAwaitingPrompt) return null;
1849
+ return /* @__PURE__ */ jsxs13(Box14, { children: [
1850
+ /* @__PURE__ */ jsx16(Text13, { color: color2, bold: true, children: glyphs.spinner[frame] }),
1851
+ /* @__PURE__ */ jsx16(Text13, { children: ` ${label}` })
1852
+ ] });
1853
+ }
1854
+
1855
+ // src/integration/ui/tui/components/log-tail.tsx
1856
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1796
1857
  function levelColor(level) {
1797
1858
  switch (level) {
1798
1859
  case "error":
@@ -1812,43 +1873,46 @@ function levelColor(level) {
1812
1873
  return void 0;
1813
1874
  }
1814
1875
  }
1815
- function renderLine(event, index) {
1876
+ function renderLine(event, index, isActiveSpinner) {
1816
1877
  switch (event.kind) {
1817
1878
  case "log":
1818
- return /* @__PURE__ */ jsx16(Text13, { color: levelColor(event.level), dimColor: event.level === "dim" || event.level === "debug", children: event.message }, index);
1879
+ return /* @__PURE__ */ jsx17(Text14, { color: levelColor(event.level), dimColor: event.level === "dim" || event.level === "debug", children: event.message }, index);
1819
1880
  case "header":
1820
- return /* @__PURE__ */ jsxs13(Text13, { bold: true, children: [
1881
+ return /* @__PURE__ */ jsxs14(Text14, { bold: true, children: [
1821
1882
  event.icon ? `${event.icon} ` : "",
1822
1883
  event.title
1823
1884
  ] }, index);
1824
1885
  case "separator":
1825
- return /* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "\u2500".repeat(Math.min(event.width, 40)) }, index);
1886
+ return /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: "\u2500".repeat(Math.min(event.width, 40)) }, index);
1826
1887
  case "field":
1827
- return /* @__PURE__ */ jsxs13(Text13, { children: [
1828
- /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
1888
+ return /* @__PURE__ */ jsxs14(Text14, { children: [
1889
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
1829
1890
  event.label,
1830
1891
  ": "
1831
1892
  ] }),
1832
1893
  event.value
1833
1894
  ] }, index);
1834
1895
  case "card":
1835
- return /* @__PURE__ */ jsx16(Text13, { bold: true, children: event.title }, index);
1896
+ return /* @__PURE__ */ jsx17(Text14, { bold: true, children: event.title }, index);
1836
1897
  case "newline":
1837
- return /* @__PURE__ */ jsx16(Text13, { children: " " }, index);
1898
+ return /* @__PURE__ */ jsx17(Text14, { children: " " }, index);
1838
1899
  case "spinner-start":
1839
- return /* @__PURE__ */ jsxs13(Text13, { color: inkColors.info, children: [
1900
+ if (isActiveSpinner) {
1901
+ return /* @__PURE__ */ jsx17(Box15, { children: /* @__PURE__ */ jsx17(Spinner, { label: event.message, color: inkColors.info }) }, index);
1902
+ }
1903
+ return /* @__PURE__ */ jsxs14(Text14, { color: inkColors.info, children: [
1840
1904
  glyphs.phaseDisabled,
1841
1905
  " ",
1842
1906
  event.message
1843
1907
  ] }, index);
1844
1908
  case "spinner-succeed":
1845
- return /* @__PURE__ */ jsxs13(Text13, { color: inkColors.success, children: [
1909
+ return /* @__PURE__ */ jsxs14(Text14, { color: inkColors.success, children: [
1846
1910
  glyphs.check,
1847
1911
  " ",
1848
1912
  event.message
1849
1913
  ] }, index);
1850
1914
  case "spinner-fail":
1851
- return /* @__PURE__ */ jsxs13(Text13, { color: inkColors.error, children: [
1915
+ return /* @__PURE__ */ jsxs14(Text14, { color: inkColors.error, children: [
1852
1916
  glyphs.cross,
1853
1917
  " ",
1854
1918
  event.message
@@ -1864,25 +1928,37 @@ function renderLine(event, index) {
1864
1928
  }
1865
1929
  function LogTail({ events, limit = 8 }) {
1866
1930
  const tail = events.slice(-limit);
1867
- return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
1868
- /* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "\u2500\u2500 Log \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1869
- tail.length === 0 ? /* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "(no activity yet)" }) : tail.map((event, i) => renderLine(event, i))
1931
+ const resolvedIds = useMemo5(() => {
1932
+ const ids = /* @__PURE__ */ new Set();
1933
+ for (const ev of events) {
1934
+ if (ev.kind === "spinner-succeed" || ev.kind === "spinner-fail" || ev.kind === "spinner-stop") {
1935
+ ids.add(ev.id);
1936
+ }
1937
+ }
1938
+ return ids;
1939
+ }, [events]);
1940
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
1941
+ /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: "\u2500\u2500 Log \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1942
+ tail.length === 0 ? /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: "(no activity yet)" }) : tail.map((event, i) => {
1943
+ const active = event.kind === "spinner-start" && !resolvedIds.has(event.id);
1944
+ return renderLine(event, i, active);
1945
+ })
1870
1946
  ] });
1871
1947
  }
1872
1948
 
1873
1949
  // src/integration/ui/tui/components/rate-limit-banner.tsx
1874
1950
  import "react";
1875
- import { Box as Box15, Text as Text14 } from "ink";
1876
- import { jsxs as jsxs14 } from "react/jsx-runtime";
1951
+ import { Box as Box16, Text as Text15 } from "ink";
1952
+ import { jsxs as jsxs15 } from "react/jsx-runtime";
1877
1953
  function RateLimitBanner({ pausedSince, delayMs }) {
1878
1954
  if (!pausedSince) return null;
1879
1955
  const seconds = Math.max(0, Math.round(delayMs / 1e3));
1880
- return /* @__PURE__ */ jsxs14(Box15, { borderStyle: "round", borderColor: inkColors.warning, paddingX: spacing.gutter, children: [
1881
- /* @__PURE__ */ jsxs14(Text14, { color: inkColors.warning, bold: true, children: [
1956
+ return /* @__PURE__ */ jsxs15(Box16, { borderStyle: "round", borderColor: inkColors.warning, paddingX: spacing.gutter, children: [
1957
+ /* @__PURE__ */ jsxs15(Text15, { color: inkColors.warning, bold: true, children: [
1882
1958
  glyphs.warningGlyph,
1883
1959
  " Rate limit hit"
1884
1960
  ] }),
1885
- /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
1961
+ /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
1886
1962
  " \u2014 new tasks paused",
1887
1963
  seconds > 0 ? ` (~${String(seconds)}s)` : "",
1888
1964
  ". Running tasks continue."
@@ -1891,7 +1967,7 @@ function RateLimitBanner({ pausedSince, delayMs }) {
1891
1967
  }
1892
1968
 
1893
1969
  // src/integration/ui/tui/views/execute-view.tsx
1894
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
1970
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
1895
1971
  var EXECUTE_HINTS_RUNNING = [];
1896
1972
  var EXECUTE_HINTS_DONE = [{ key: "Enter", action: "home" }];
1897
1973
  function initialState() {
@@ -1911,10 +1987,10 @@ function ExecuteView({ sprintId, executionOptions }) {
1911
1987
  const shared = getSharedDeps();
1912
1988
  const signalEvents = useSignalEvents(shared.signalBus);
1913
1989
  const logEvents = useLoggerEvents(200);
1914
- const [state, setState] = useState7(initialState);
1915
- const [done, setDone] = useState7(false);
1916
- const processedCountRef = useRef(0);
1917
- useEffect7(() => {
1990
+ const [state, setState] = useState8(initialState);
1991
+ const [done, setDone] = useState8(false);
1992
+ const processedCountRef = useRef2(0);
1993
+ useEffect8(() => {
1918
1994
  const cancel = { current: false };
1919
1995
  const load = async () => {
1920
1996
  try {
@@ -1932,7 +2008,7 @@ function ExecuteView({ sprintId, executionOptions }) {
1932
2008
  cancel.current = true;
1933
2009
  };
1934
2010
  }, [shared, sprintId]);
1935
- useEffect7(() => {
2011
+ useEffect8(() => {
1936
2012
  if (state.sprint === null || done) return;
1937
2013
  const cancel = { current: false };
1938
2014
  const run = async () => {
@@ -1957,14 +2033,14 @@ function ExecuteView({ sprintId, executionOptions }) {
1957
2033
  cancel.current = true;
1958
2034
  };
1959
2035
  }, [state.sprint, shared, sprintId, executionOptions, done]);
1960
- useEffect7(() => {
2036
+ useEffect8(() => {
1961
2037
  if (signalEvents.length <= processedCountRef.current) return;
1962
2038
  const fresh = signalEvents.slice(processedCountRef.current);
1963
2039
  processedCountRef.current = signalEvents.length;
1964
2040
  setState((prev) => reduceEvents(prev, fresh));
1965
2041
  }, [signalEvents]);
1966
- const [closePromptRun, setClosePromptRun] = useState7(false);
1967
- useEffect7(() => {
2042
+ const [closePromptRun, setClosePromptRun] = useState8(false);
2043
+ useEffect8(() => {
1968
2044
  if (!done) return;
1969
2045
  void (async () => {
1970
2046
  try {
@@ -1995,19 +2071,19 @@ function ExecuteView({ sprintId, executionOptions }) {
1995
2071
  }
1996
2072
  });
1997
2073
  useViewHints(done ? EXECUTE_HINTS_DONE : EXECUTE_HINTS_RUNNING);
1998
- return /* @__PURE__ */ jsxs15(ViewShell, { title: "Execute", children: [
1999
- /* @__PURE__ */ jsxs15(Box16, { children: [
2000
- /* @__PURE__ */ jsx17(Text15, { bold: true, color: inkColors.primary, children: state.sprint?.name ?? "Sprint" }),
2001
- /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2074
+ return /* @__PURE__ */ jsxs16(ViewShell, { title: "Execute", children: [
2075
+ /* @__PURE__ */ jsxs16(Box17, { children: [
2076
+ /* @__PURE__ */ jsx18(Text16, { bold: true, color: inkColors.primary, children: state.sprint?.name ?? "Sprint" }),
2077
+ /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
2002
2078
  " ",
2003
2079
  state.sprint?.branch ? `[${state.sprint.branch}]` : "",
2004
2080
  " ",
2005
2081
  state.sprint?.status ? `(${state.sprint.status})` : ""
2006
2082
  ] })
2007
2083
  ] }),
2008
- /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsx17(SprintSummary, { tasks: state.tasks }) }),
2009
- state.rateLimit ? /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsx17(RateLimitBanner, { pausedSince: state.rateLimit.pausedSince, delayMs: state.rateLimit.delayMs }) }) : null,
2010
- /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsx17(
2084
+ /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(SprintSummary, { tasks: state.tasks }) }),
2085
+ state.rateLimit ? /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(RateLimitBanner, { pausedSince: state.rateLimit.pausedSince, delayMs: state.rateLimit.delayMs }) }) : null,
2086
+ /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(
2011
2087
  TaskGrid,
2012
2088
  {
2013
2089
  tasks: state.tasks,
@@ -2016,18 +2092,18 @@ function ExecuteView({ sprintId, executionOptions }) {
2016
2092
  activityByTask: state.activity
2017
2093
  }
2018
2094
  ) }),
2019
- /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsx17(LogTail, { events: logEvents }) }),
2020
- state.error ? /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs15(Text15, { color: inkColors.error, children: [
2095
+ /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(LogTail, { events: logEvents }) }),
2096
+ state.error ? /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs16(Text16, { color: inkColors.error, children: [
2021
2097
  glyphs.cross,
2022
2098
  " ",
2023
2099
  state.error
2024
2100
  ] }) }) : null,
2025
- state.summary && done ? /* @__PURE__ */ jsxs15(Box16, { marginTop: spacing.section, flexDirection: "column", children: [
2026
- /* @__PURE__ */ jsxs15(Text15, { color: inkColors.success, bold: true, children: [
2101
+ state.summary && done ? /* @__PURE__ */ jsxs16(Box17, { marginTop: spacing.section, flexDirection: "column", children: [
2102
+ /* @__PURE__ */ jsxs16(Text16, { color: inkColors.success, bold: true, children: [
2027
2103
  glyphs.check,
2028
2104
  " Execution finished"
2029
2105
  ] }),
2030
- /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
2106
+ /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
2031
2107
  state.summary.completed,
2032
2108
  " completed ",
2033
2109
  glyphs.inlineDot,
@@ -2043,7 +2119,7 @@ function ExecuteView({ sprintId, executionOptions }) {
2043
2119
  state.summary.stopReason,
2044
2120
  ")"
2045
2121
  ] }),
2046
- /* @__PURE__ */ jsx17(Box16, { marginTop: spacing.section, children: /* @__PURE__ */ jsx17(Text15, { dimColor: true, children: "Press any key to return home." }) })
2122
+ /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: "Press any key to return home." }) })
2047
2123
  ] }) : null
2048
2124
  ] });
2049
2125
  }
@@ -2092,29 +2168,6 @@ function reduceEvents(state, events) {
2092
2168
  import { useEffect as useEffect9, useState as useState9 } from "react";
2093
2169
  import { Box as Box20, Text as Text19 } from "ink";
2094
2170
 
2095
- // src/integration/ui/tui/components/spinner.tsx
2096
- import { useEffect as useEffect8, useState as useState8 } from "react";
2097
- import { Box as Box17, Text as Text16 } from "ink";
2098
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2099
- function Spinner({ label, color: color2 = inkColors.warning, intervalMs = 80 }) {
2100
- const [frame, setFrame] = useState8(0);
2101
- const isAwaitingPrompt = label.startsWith("Awaiting");
2102
- useEffect8(() => {
2103
- if (isAwaitingPrompt) return;
2104
- const id = setInterval(() => {
2105
- setFrame((f) => (f + 1) % glyphs.spinner.length);
2106
- }, intervalMs);
2107
- return () => {
2108
- clearInterval(id);
2109
- };
2110
- }, [intervalMs, isAwaitingPrompt]);
2111
- if (isAwaitingPrompt) return null;
2112
- return /* @__PURE__ */ jsxs16(Box17, { children: [
2113
- /* @__PURE__ */ jsx18(Text16, { color: color2, bold: true, children: glyphs.spinner[frame] }),
2114
- /* @__PURE__ */ jsx18(Text16, { children: ` ${label}` })
2115
- ] });
2116
- }
2117
-
2118
2171
  // src/integration/ui/tui/components/result-card.tsx
2119
2172
  import "react";
2120
2173
  import { Box as Box19, Text as Text18 } from "ink";
@@ -2177,7 +2230,7 @@ async function loadRecentProgress(sprintId, limit) {
2177
2230
  const headerMatch = /^##\s+(.+)$/m.exec(entry);
2178
2231
  const header = headerMatch?.[1]?.trim() ?? "Entry";
2179
2232
  const body = entry.replace(/^##\s+.+$/gm, "").replace(/^\*\*Project:\*\*.+$/gm, "").replace(/^###\s+.+$/gm, "").replace(/\s+/g, " ").trim();
2180
- const preview = body.length > 200 ? body.slice(0, 197) + "\u2026" : body;
2233
+ const preview = truncate(body, 200);
2181
2234
  return { header, preview };
2182
2235
  });
2183
2236
  } catch {
@@ -2597,7 +2650,7 @@ function statusColor2(status) {
2597
2650
 
2598
2651
  // src/integration/ui/tui/views/phases/close-phase-view.tsx
2599
2652
  import { spawnSync } from "child_process";
2600
- import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo5, useState as useState12 } from "react";
2653
+ import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo6, useState as useState12 } from "react";
2601
2654
  import { Box as Box24, Text as Text23, useInput as useInput8 } from "ink";
2602
2655
  import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
2603
2656
  var HINTS_READY = [
@@ -2631,7 +2684,7 @@ function ClosePhaseView({ sprintId }) {
2631
2684
  useEffect12(() => {
2632
2685
  void load();
2633
2686
  }, [load]);
2634
- const actions = useMemo5(() => {
2687
+ const actions = useMemo6(() => {
2635
2688
  const sprint2 = state.sprint;
2636
2689
  if (sprint2?.status !== "active") return [];
2637
2690
  const base = ["close"];
@@ -2876,7 +2929,7 @@ ID: ${sprintId}`
2876
2929
  }
2877
2930
 
2878
2931
  // src/integration/ui/tui/views/workflows/create-sprint-view.tsx
2879
- import { useMemo as useMemo6 } from "react";
2932
+ import { useMemo as useMemo7 } from "react";
2880
2933
 
2881
2934
  // src/integration/ui/tui/views/workflows/use-workflow.ts
2882
2935
  import { useCallback as useCallback8, useEffect as useEffect13, useState as useState13 } from "react";
@@ -2970,7 +3023,7 @@ function CreateSprintView() {
2970
3023
  setPhase({ kind: "done", sprint, project, setAsCurrent });
2971
3024
  }
2972
3025
  });
2973
- const hints = useMemo6(() => phase.kind === "running" ? HINTS_RUNNING : HINTS_DONE, [phase.kind]);
3026
+ const hints = useMemo7(() => phase.kind === "running" ? HINTS_RUNNING : HINTS_DONE, [phase.kind]);
2974
3027
  useViewHints(hints);
2975
3028
  return /* @__PURE__ */ jsx26(ViewShell, { title: TITLE, children: renderBody(phase) });
2976
3029
  }
@@ -3012,7 +3065,7 @@ function renderBody(phase) {
3012
3065
  }
3013
3066
 
3014
3067
  // src/integration/ui/tui/views/workflows/delete-sprint-view.tsx
3015
- import { useMemo as useMemo7 } from "react";
3068
+ import { useMemo as useMemo8 } from "react";
3016
3069
  import { jsx as jsx27 } from "react/jsx-runtime";
3017
3070
  var TITLE2 = "Delete Sprint";
3018
3071
  var HINTS_RUNNING2 = [{ key: "Esc", action: "cancel" }];
@@ -3074,7 +3127,7 @@ function DeleteSprintView({ sprintId: initial2 }) {
3074
3127
  }
3075
3128
  });
3076
3129
  const running = phase.kind === "running" || phase.kind === "loading";
3077
- const hints = useMemo7(() => running ? HINTS_RUNNING2 : HINTS_DONE2, [running]);
3130
+ const hints = useMemo8(() => running ? HINTS_RUNNING2 : HINTS_DONE2, [running]);
3078
3131
  useViewHints(hints);
3079
3132
  return /* @__PURE__ */ jsx27(ViewShell, { title: TITLE2, children: renderBody2(phase) });
3080
3133
  }
@@ -3121,7 +3174,7 @@ function runningLabel(step) {
3121
3174
  }
3122
3175
 
3123
3176
  // src/integration/ui/tui/views/workflows/set-current-sprint-view.tsx
3124
- import { useMemo as useMemo8 } from "react";
3177
+ import { useMemo as useMemo9 } from "react";
3125
3178
  import { jsx as jsx28 } from "react/jsx-runtime";
3126
3179
  var TITLE3 = "Set Current Sprint";
3127
3180
  var HINTS_RUNNING3 = [{ key: "Esc", action: "cancel" }];
@@ -3154,7 +3207,7 @@ function SetCurrentSprintView() {
3154
3207
  }
3155
3208
  });
3156
3209
  const running = phase.kind === "loading" || phase.kind === "running";
3157
- const hints = useMemo8(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
3210
+ const hints = useMemo9(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
3158
3211
  useViewHints(hints);
3159
3212
  return /* @__PURE__ */ jsx28(ViewShell, { title: TITLE3, children: renderBody3(phase) });
3160
3213
  }
@@ -3192,7 +3245,7 @@ function renderBody3(phase) {
3192
3245
 
3193
3246
  // src/integration/ui/tui/views/workflows/requirements-export-view.tsx
3194
3247
  import { join } from "path";
3195
- import { useMemo as useMemo9 } from "react";
3248
+ import { useMemo as useMemo10 } from "react";
3196
3249
  import { jsx as jsx29 } from "react/jsx-runtime";
3197
3250
  var TITLE4 = "Export Requirements";
3198
3251
  var HINTS_RUNNING4 = [{ key: "Esc", action: "cancel" }];
@@ -3227,7 +3280,7 @@ function RequirementsExportView({ sprintId }) {
3227
3280
  });
3228
3281
  }
3229
3282
  });
3230
- const hints = useMemo9(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
3283
+ const hints = useMemo10(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
3231
3284
  useViewHints(hints);
3232
3285
  return /* @__PURE__ */ jsx29(ViewShell, { title: TITLE4, children: renderBody4(phase) });
3233
3286
  }
@@ -3274,7 +3327,7 @@ function renderBody4(phase) {
3274
3327
  // src/integration/ui/tui/views/workflows/context-export-view.tsx
3275
3328
  import { writeFile } from "fs/promises";
3276
3329
  import { join as join2 } from "path";
3277
- import { useMemo as useMemo10 } from "react";
3330
+ import { useMemo as useMemo11 } from "react";
3278
3331
  import { jsx as jsx30 } from "react/jsx-runtime";
3279
3332
  var TITLE5 = "Export Context";
3280
3333
  var HINTS_RUNNING5 = [{ key: "Esc", action: "cancel" }];
@@ -3304,7 +3357,7 @@ function ContextExportView({ sprintId }) {
3304
3357
  });
3305
3358
  }
3306
3359
  });
3307
- const hints = useMemo10(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
3360
+ const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
3308
3361
  useViewHints(hints);
3309
3362
  return /* @__PURE__ */ jsx30(ViewShell, { title: TITLE5, children: renderBody5(phase) });
3310
3363
  }
@@ -3404,7 +3457,7 @@ async function renderContextMarkdown(sprint, tasks) {
3404
3457
  }
3405
3458
 
3406
3459
  // src/integration/ui/tui/views/workflows/ticket-add-view.tsx
3407
- import { useMemo as useMemo11 } from "react";
3460
+ import { useMemo as useMemo12 } from "react";
3408
3461
  import { jsx as jsx31 } from "react/jsx-runtime";
3409
3462
  var TITLE6 = "Add Ticket";
3410
3463
  var HINTS_RUNNING6 = [{ key: "Esc", action: "cancel" }];
@@ -3488,7 +3541,7 @@ function TicketAddView() {
3488
3541
  setPhase({ kind: "done", ticket, project, prefilled: prefill !== null });
3489
3542
  }
3490
3543
  });
3491
- const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
3544
+ const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
3492
3545
  useViewHints(hints);
3493
3546
  return /* @__PURE__ */ jsx31(ViewShell, { title: TITLE6, children: renderBody6(phase) });
3494
3547
  }
@@ -3536,7 +3589,7 @@ function renderBody6(phase) {
3536
3589
  }
3537
3590
 
3538
3591
  // src/integration/ui/tui/views/workflows/ticket-edit-view.tsx
3539
- import { useMemo as useMemo12 } from "react";
3592
+ import { useMemo as useMemo13 } from "react";
3540
3593
  import { jsx as jsx32 } from "react/jsx-runtime";
3541
3594
  var TITLE7 = "Edit Ticket";
3542
3595
  var HINTS_RUNNING7 = [{ key: "Esc", action: "cancel" }];
@@ -3611,7 +3664,7 @@ function TicketEditView({ ticketId } = {}) {
3611
3664
  setPhase({ kind: "done", ticket, field });
3612
3665
  }
3613
3666
  });
3614
- const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
3667
+ const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
3615
3668
  useViewHints(hints);
3616
3669
  return /* @__PURE__ */ jsx32(ViewShell, { title: TITLE7, children: renderBody7(phase) });
3617
3670
  }
@@ -3660,7 +3713,7 @@ function stepLabel(step) {
3660
3713
  }
3661
3714
 
3662
3715
  // src/integration/ui/tui/views/workflows/ticket-remove-view.tsx
3663
- import { useMemo as useMemo13 } from "react";
3716
+ import { useMemo as useMemo14 } from "react";
3664
3717
  import { jsx as jsx33 } from "react/jsx-runtime";
3665
3718
  var TITLE8 = "Remove Ticket";
3666
3719
  var HINTS_RUNNING8 = [{ key: "Esc", action: "cancel" }];
@@ -3709,7 +3762,7 @@ function TicketRemoveView() {
3709
3762
  setPhase({ kind: "done", id: target.id, title: target.title });
3710
3763
  }
3711
3764
  });
3712
- const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
3765
+ const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
3713
3766
  useViewHints(hints);
3714
3767
  return /* @__PURE__ */ jsx33(ViewShell, { title: TITLE8, children: renderBody8(phase) });
3715
3768
  }
@@ -3746,7 +3799,7 @@ function stepLabel2(step) {
3746
3799
  }
3747
3800
 
3748
3801
  // src/integration/ui/tui/views/workflows/ticket-refine-view.tsx
3749
- import { useMemo as useMemo14 } from "react";
3802
+ import { useMemo as useMemo15 } from "react";
3750
3803
  import { jsx as jsx34 } from "react/jsx-runtime";
3751
3804
  var TITLE9 = "Re-Refine Ticket";
3752
3805
  var HINTS_RUNNING9 = [{ key: "Esc", action: "cancel" }];
@@ -3782,7 +3835,7 @@ function TicketRefineView() {
3782
3835
  setPhase({ kind: "done", ticketTitle: target.title });
3783
3836
  }
3784
3837
  });
3785
- const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
3838
+ const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
3786
3839
  useViewHints(hints);
3787
3840
  return /* @__PURE__ */ jsx34(ViewShell, { title: TITLE9, children: renderBody9(phase) });
3788
3841
  }
@@ -3817,7 +3870,7 @@ function renderBody9(phase) {
3817
3870
  }
3818
3871
 
3819
3872
  // src/integration/ui/tui/views/workflows/task-add-view.tsx
3820
- import { useMemo as useMemo15 } from "react";
3873
+ import { useMemo as useMemo16 } from "react";
3821
3874
  import { jsx as jsx35 } from "react/jsx-runtime";
3822
3875
  var TITLE10 = "Add Task";
3823
3876
  var HINTS_RUNNING10 = [{ key: "Esc", action: "cancel" }];
@@ -3884,7 +3937,7 @@ function TaskAddView() {
3884
3937
  setPhase({ kind: "done", task, repo });
3885
3938
  }
3886
3939
  });
3887
- const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
3940
+ const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
3888
3941
  useViewHints(hints);
3889
3942
  return /* @__PURE__ */ jsx35(ViewShell, { title: TITLE10, children: renderBody10(phase) });
3890
3943
  }
@@ -3922,7 +3975,7 @@ function stepLabel3(step) {
3922
3975
  }
3923
3976
 
3924
3977
  // src/integration/ui/tui/views/workflows/task-import-view.tsx
3925
- import { useMemo as useMemo16 } from "react";
3978
+ import { useMemo as useMemo17 } from "react";
3926
3979
  import { jsx as jsx36 } from "react/jsx-runtime";
3927
3980
  var TITLE11 = "Import Tasks";
3928
3981
  var HINTS_RUNNING11 = [{ key: "Esc", action: "cancel" }];
@@ -3946,7 +3999,7 @@ function TaskImportView() {
3946
3999
  setPhase({ kind: "done" });
3947
4000
  }
3948
4001
  });
3949
- const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
4002
+ const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
3950
4003
  useViewHints(hints);
3951
4004
  return /* @__PURE__ */ jsx36(ViewShell, { title: TITLE11, children: renderBody11(phase) });
3952
4005
  }
@@ -3964,7 +4017,7 @@ function renderBody11(phase) {
3964
4017
  }
3965
4018
 
3966
4019
  // src/integration/ui/tui/views/workflows/task-status-view.tsx
3967
- import { useMemo as useMemo17 } from "react";
4020
+ import { useMemo as useMemo18 } from "react";
3968
4021
  import { jsx as jsx37 } from "react/jsx-runtime";
3969
4022
  var TITLE12 = "Task Status";
3970
4023
  var HINTS_RUNNING12 = [{ key: "Esc", action: "cancel" }];
@@ -4011,7 +4064,7 @@ function TaskStatusView() {
4011
4064
  setPhase({ kind: "done", task });
4012
4065
  }
4013
4066
  });
4014
- const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
4067
+ const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
4015
4068
  useViewHints(hints);
4016
4069
  return /* @__PURE__ */ jsx37(ViewShell, { title: TITLE12, children: renderBody12(phase) });
4017
4070
  }
@@ -4053,7 +4106,7 @@ function stepLabel4(step) {
4053
4106
  }
4054
4107
 
4055
4108
  // src/integration/ui/tui/views/workflows/task-reorder-view.tsx
4056
- import { useMemo as useMemo18 } from "react";
4109
+ import { useMemo as useMemo19 } from "react";
4057
4110
  import { jsx as jsx38 } from "react/jsx-runtime";
4058
4111
  var TITLE13 = "Reorder Task";
4059
4112
  var HINTS_RUNNING13 = [{ key: "Esc", action: "cancel" }];
@@ -4101,7 +4154,7 @@ function TaskReorderView() {
4101
4154
  setPhase({ kind: "done", task });
4102
4155
  }
4103
4156
  });
4104
- const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
4157
+ const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
4105
4158
  useViewHints(hints);
4106
4159
  return /* @__PURE__ */ jsx38(ViewShell, { title: TITLE13, children: renderBody13(phase) });
4107
4160
  }
@@ -4136,7 +4189,7 @@ function stepLabel5(step) {
4136
4189
  }
4137
4190
 
4138
4191
  // src/integration/ui/tui/views/workflows/task-remove-view.tsx
4139
- import { useMemo as useMemo19 } from "react";
4192
+ import { useMemo as useMemo20 } from "react";
4140
4193
  import { jsx as jsx39 } from "react/jsx-runtime";
4141
4194
  var TITLE14 = "Remove Task";
4142
4195
  var HINTS_RUNNING14 = [{ key: "Esc", action: "cancel" }];
@@ -4181,7 +4234,7 @@ function TaskRemoveView() {
4181
4234
  setPhase({ kind: "done", id: target.id, name: target.name });
4182
4235
  }
4183
4236
  });
4184
- const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
4237
+ const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
4185
4238
  useViewHints(hints);
4186
4239
  return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE14, children: renderBody14(phase) });
4187
4240
  }
@@ -4218,7 +4271,7 @@ function stepLabel6(step) {
4218
4271
  }
4219
4272
 
4220
4273
  // src/integration/ui/tui/views/workflows/task-next-view.tsx
4221
- import { useMemo as useMemo20 } from "react";
4274
+ import { useMemo as useMemo21 } from "react";
4222
4275
  import { jsx as jsx40 } from "react/jsx-runtime";
4223
4276
  var TITLE15 = "Next Task";
4224
4277
  var HINTS_RUNNING15 = [{ key: "Esc", action: "cancel" }];
@@ -4239,7 +4292,7 @@ function TaskNextView() {
4239
4292
  setPhase({ kind: "ready", task });
4240
4293
  }
4241
4294
  });
4242
- const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
4295
+ const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
4243
4296
  useViewHints(hints);
4244
4297
  return /* @__PURE__ */ jsx40(ViewShell, { title: TITLE15, children: renderBody15(phase) });
4245
4298
  }
@@ -4271,7 +4324,7 @@ function renderBody15(phase) {
4271
4324
 
4272
4325
  // src/integration/ui/tui/views/workflows/project-add-view.tsx
4273
4326
  import { resolve } from "path";
4274
- import { useMemo as useMemo21 } from "react";
4327
+ import { useMemo as useMemo22 } from "react";
4275
4328
  import { jsx as jsx41 } from "react/jsx-runtime";
4276
4329
  var TITLE16 = "Add Project";
4277
4330
  var HINTS_RUNNING16 = [{ key: "Esc", action: "cancel" }];
@@ -4318,7 +4371,7 @@ function ProjectAddView() {
4318
4371
  setPhase({ kind: "done", project });
4319
4372
  }
4320
4373
  });
4321
- const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
4374
+ const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
4322
4375
  useViewHints(hints);
4323
4376
  return /* @__PURE__ */ jsx41(ViewShell, { title: TITLE16, children: renderBody16(phase) });
4324
4377
  }
@@ -4359,7 +4412,7 @@ function stepLabel7(step) {
4359
4412
  }
4360
4413
 
4361
4414
  // src/integration/ui/tui/views/workflows/project-remove-view.tsx
4362
- import { useMemo as useMemo22 } from "react";
4415
+ import { useMemo as useMemo23 } from "react";
4363
4416
  import { jsx as jsx42 } from "react/jsx-runtime";
4364
4417
  var TITLE17 = "Remove Project";
4365
4418
  var HINTS_RUNNING17 = [{ key: "Esc", action: "cancel" }];
@@ -4401,7 +4454,7 @@ function ProjectRemoveView() {
4401
4454
  setPhase({ kind: "done", name });
4402
4455
  }
4403
4456
  });
4404
- const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
4457
+ const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
4405
4458
  useViewHints(hints);
4406
4459
  return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE17, children: renderBody17(phase) });
4407
4460
  }
@@ -4427,7 +4480,7 @@ function stepLabel8(step) {
4427
4480
 
4428
4481
  // src/integration/ui/tui/views/workflows/project-repo-add-view.tsx
4429
4482
  import { resolve as resolve2 } from "path";
4430
- import { useMemo as useMemo23 } from "react";
4483
+ import { useMemo as useMemo24 } from "react";
4431
4484
  import { jsx as jsx43 } from "react/jsx-runtime";
4432
4485
  var TITLE18 = "Add Repository";
4433
4486
  var HINTS_RUNNING18 = [{ key: "Esc", action: "cancel" }];
@@ -4463,7 +4516,7 @@ function ProjectRepoAddView() {
4463
4516
  setPhase({ kind: "done", project, repoName });
4464
4517
  }
4465
4518
  });
4466
- const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
4519
+ const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
4467
4520
  useViewHints(hints);
4468
4521
  return /* @__PURE__ */ jsx43(ViewShell, { title: TITLE18, children: renderBody18(phase) });
4469
4522
  }
@@ -4497,7 +4550,7 @@ function stepLabel9(step) {
4497
4550
  }
4498
4551
 
4499
4552
  // src/integration/ui/tui/views/workflows/project-repo-remove-view.tsx
4500
- import { useMemo as useMemo24 } from "react";
4553
+ import { useMemo as useMemo25 } from "react";
4501
4554
  import { jsx as jsx44 } from "react/jsx-runtime";
4502
4555
  var TITLE19 = "Remove Repository";
4503
4556
  var HINTS_RUNNING19 = [{ key: "Esc", action: "cancel" }];
@@ -4546,7 +4599,7 @@ function ProjectRepoRemoveView() {
4546
4599
  setPhase({ kind: "done", project: updated, repoName });
4547
4600
  }
4548
4601
  });
4549
- const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
4602
+ const hints = useMemo25(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
4550
4603
  useViewHints(hints);
4551
4604
  return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE19, children: renderBody19(phase) });
4552
4605
  }
@@ -4585,7 +4638,7 @@ function stepLabel10(step) {
4585
4638
  }
4586
4639
 
4587
4640
  // src/integration/ui/tui/views/workflows/project-edit-view.tsx
4588
- import { useMemo as useMemo25 } from "react";
4641
+ import { useMemo as useMemo26 } from "react";
4589
4642
  import { jsx as jsx45 } from "react/jsx-runtime";
4590
4643
  var TITLE20 = "Edit Project";
4591
4644
  var HINTS_RUNNING20 = [{ key: "Esc", action: "cancel" }];
@@ -4631,7 +4684,7 @@ function ProjectEditView() {
4631
4684
  setPhase({ kind: "done", project });
4632
4685
  }
4633
4686
  });
4634
- const hints = useMemo25(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
4687
+ const hints = useMemo26(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
4635
4688
  useViewHints(hints);
4636
4689
  return /* @__PURE__ */ jsx45(ViewShell, { title: TITLE20, children: renderBody20(phase) });
4637
4690
  }
@@ -4666,11 +4719,11 @@ function stepLabel11(step) {
4666
4719
  }
4667
4720
 
4668
4721
  // src/integration/ui/tui/views/browse/sprint-list-view.tsx
4669
- import { useEffect as useEffect14, useMemo as useMemo27, useState as useState15 } from "react";
4722
+ import { useEffect as useEffect14, useMemo as useMemo28, useState as useState15 } from "react";
4670
4723
  import { useInput as useInput11 } from "ink";
4671
4724
 
4672
4725
  // src/integration/ui/tui/components/list-view.tsx
4673
- import React47, { useMemo as useMemo26, useState as useState14 } from "react";
4726
+ import React47, { useMemo as useMemo27, useState as useState14 } from "react";
4674
4727
  import { Box as Box25, Text as Text24, useInput as useInput10 } from "ink";
4675
4728
  import { jsx as jsx46, jsxs as jsxs24 } from "react/jsx-runtime";
4676
4729
  var DEFAULT_PAGE_SIZE = 12;
@@ -4704,7 +4757,7 @@ function ListView({
4704
4757
  disabled = false
4705
4758
  }) {
4706
4759
  const [cursor, setCursor] = useState14(() => Math.max(0, Math.min(initialCursor, rows.length - 1)));
4707
- const widths = useMemo26(() => computeWidths(columns, rows, 72), [columns, rows]);
4760
+ const widths = useMemo27(() => computeWidths(columns, rows, 72), [columns, rows]);
4708
4761
  useInput10(
4709
4762
  (_input, key) => {
4710
4763
  if (rows.length === 0) return;
@@ -4917,7 +4970,7 @@ function SprintListView() {
4917
4970
  }
4918
4971
  });
4919
4972
  const title = filter === "all" ? TITLE_BASE : `${TITLE_BASE} \xB7 filter: ${filter}`;
4920
- const filtered = useMemo27(() => {
4973
+ const filtered = useMemo28(() => {
4921
4974
  if (state.kind !== "ready") return [];
4922
4975
  if (filter === "all") return state.sprints;
4923
4976
  return state.sprints.filter((s) => s.status === filter);
@@ -4936,7 +4989,7 @@ function SprintListView() {
4936
4989
  }
4937
4990
 
4938
4991
  // src/integration/ui/tui/views/browse/sprint-show-view.tsx
4939
- import { useEffect as useEffect15, useMemo as useMemo28, useState as useState16 } from "react";
4992
+ import { useEffect as useEffect15, useMemo as useMemo29, useState as useState16 } from "react";
4940
4993
  import { Box as Box26, Text as Text26, useInput as useInput12 } from "ink";
4941
4994
  import { jsx as jsx48, jsxs as jsxs26 } from "react/jsx-runtime";
4942
4995
  var TITLE21 = "Sprint Details";
@@ -4964,11 +5017,11 @@ function SprintShowView({ sprintId }) {
4964
5017
  ctl.cancelled = true;
4965
5018
  };
4966
5019
  }, [sprintId]);
4967
- const rows = useMemo28(() => {
5020
+ const rows = useMemo29(() => {
4968
5021
  if (state.kind !== "ready") return [];
4969
5022
  return buildRows2(state.sprint, state.tasks);
4970
5023
  }, [state]);
4971
- const sections = useMemo28(() => rows.filter((r) => r.separator !== true), [rows]);
5024
+ const sections = useMemo29(() => rows.filter((r) => r.separator !== true), [rows]);
4972
5025
  const [cursor, setCursor] = useState16(0);
4973
5026
  useInput12(
4974
5027
  (_input, key) => {
@@ -5265,7 +5318,7 @@ function renderBody22(state) {
5265
5318
  }
5266
5319
 
5267
5320
  // src/integration/ui/tui/views/browse/task-list-view.tsx
5268
- import { useEffect as useEffect18, useMemo as useMemo29, useState as useState19 } from "react";
5321
+ import { useEffect as useEffect18, useMemo as useMemo30, useState as useState19 } from "react";
5269
5322
  import { useInput as useInput15 } from "ink";
5270
5323
  import { jsx as jsx51 } from "react/jsx-runtime";
5271
5324
  var FILTER_CYCLE2 = ["all", "todo", "active", "done"];
@@ -5390,7 +5443,7 @@ function TaskListView({ sprintId }) {
5390
5443
  router.push({ id: "task-remove" });
5391
5444
  }
5392
5445
  });
5393
- const filtered = useMemo29(() => {
5446
+ const filtered = useMemo30(() => {
5394
5447
  if (state.kind !== "ready") return [];
5395
5448
  if (filter === "all") return state.tasks;
5396
5449
  return state.tasks.filter((t) => matches(t, filter));
@@ -5756,7 +5809,7 @@ function renderContent(content) {
5756
5809
  }
5757
5810
 
5758
5811
  // src/integration/ui/tui/views/workflows/progress-log-view.tsx
5759
- import { useMemo as useMemo30 } from "react";
5812
+ import { useMemo as useMemo31 } from "react";
5760
5813
  import { jsx as jsx57 } from "react/jsx-runtime";
5761
5814
  var TITLE29 = "Log Progress";
5762
5815
  var HINTS_RUNNING21 = [
@@ -5786,7 +5839,7 @@ function ProgressLogView() {
5786
5839
  setPhase({ kind: "done" });
5787
5840
  }
5788
5841
  });
5789
- const hints = useMemo30(() => phase.kind === "running" ? HINTS_RUNNING21 : HINTS_DONE21, [phase.kind]);
5842
+ const hints = useMemo31(() => phase.kind === "running" ? HINTS_RUNNING21 : HINTS_DONE21, [phase.kind]);
5790
5843
  useViewHints(hints);
5791
5844
  return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE29, children: renderBody25(phase) });
5792
5845
  }
@@ -5804,7 +5857,7 @@ function renderBody25(phase) {
5804
5857
  }
5805
5858
 
5806
5859
  // src/integration/ui/tui/views/workflows/ideate-view.tsx
5807
- import { useMemo as useMemo31 } from "react";
5860
+ import { useMemo as useMemo32 } from "react";
5808
5861
  import { jsx as jsx58 } from "react/jsx-runtime";
5809
5862
  var TITLE30 = "Ideate";
5810
5863
  var HINTS_RUNNING22 = [{ key: "Esc", action: "cancel" }];
@@ -5862,7 +5915,7 @@ function IdeateView() {
5862
5915
  setPhase({ kind: "done", summary });
5863
5916
  }
5864
5917
  });
5865
- const hints = useMemo31(() => phase.kind === "running" ? HINTS_RUNNING22 : HINTS_DONE22, [phase.kind]);
5918
+ const hints = useMemo32(() => phase.kind === "running" ? HINTS_RUNNING22 : HINTS_DONE22, [phase.kind]);
5866
5919
  useViewHints(hints);
5867
5920
  return /* @__PURE__ */ jsx58(ViewShell, { title: TITLE30, children: renderBody26(phase) });
5868
5921
  }
@@ -5899,7 +5952,7 @@ function stepLabel12(step) {
5899
5952
  }
5900
5953
 
5901
5954
  // src/integration/ui/tui/views/onboarding-view.tsx
5902
- import { useMemo as useMemo32 } from "react";
5955
+ import { useMemo as useMemo33 } from "react";
5903
5956
  import { jsx as jsx59 } from "react/jsx-runtime";
5904
5957
  var TITLE31 = "Welcome";
5905
5958
  var HINTS_RUNNING23 = [{ key: "Esc", action: "skip" }];
@@ -5950,7 +6003,7 @@ function OnboardingView() {
5950
6003
  }
5951
6004
  }
5952
6005
  });
5953
- const hints = useMemo32(() => phase.kind === "running" ? HINTS_RUNNING23 : HINTS_DONE23, [phase.kind]);
6006
+ const hints = useMemo33(() => phase.kind === "running" ? HINTS_RUNNING23 : HINTS_DONE23, [phase.kind]);
5954
6007
  useViewHints(hints);
5955
6008
  return /* @__PURE__ */ jsx59(ViewShell, { title: TITLE31, children: renderBody27(phase) });
5956
6009
  }
@@ -5970,7 +6023,7 @@ function renderBody27(phase) {
5970
6023
  }
5971
6024
 
5972
6025
  // src/integration/ui/tui/views/workflows/reactivate-sprint-view.tsx
5973
- import { useMemo as useMemo33 } from "react";
6026
+ import { useMemo as useMemo34 } from "react";
5974
6027
  import { jsx as jsx60 } from "react/jsx-runtime";
5975
6028
  var TITLE32 = "Reactivate Sprint";
5976
6029
  var HINTS_RUNNING24 = [{ key: "Esc", action: "cancel" }];
@@ -6008,7 +6061,7 @@ function ReactivateSprintView({ sprintId }) {
6008
6061
  }
6009
6062
  });
6010
6063
  const running = phase.kind === "running" || phase.kind === "loading";
6011
- const hints = useMemo33(() => running ? HINTS_RUNNING24 : HINTS_DONE24, [running]);
6064
+ const hints = useMemo34(() => running ? HINTS_RUNNING24 : HINTS_DONE24, [running]);
6012
6065
  useViewHints(hints);
6013
6066
  return /* @__PURE__ */ jsx60(ViewShell, { title: TITLE32, children: renderBody28(phase) });
6014
6067
  }
@@ -6522,7 +6575,7 @@ function ViewRouter({ initialStack }) {
6522
6575
  }
6523
6576
  return collapseAdjacentDuplicates(initialStack);
6524
6577
  });
6525
- const stackRef = useRef2(stack);
6578
+ const stackRef = useRef3(stack);
6526
6579
  stackRef.current = stack;
6527
6580
  const push = useCallback10((entry) => {
6528
6581
  setStack((s) => {
@@ -6546,7 +6599,7 @@ function ViewRouter({ initialStack }) {
6546
6599
  if (current === void 0) {
6547
6600
  throw new Error("ViewRouter stack is empty");
6548
6601
  }
6549
- const api = useMemo34(
6602
+ const api = useMemo35(
6550
6603
  () => ({ current, stack, push, pop, replace, reset }),
6551
6604
  [current, stack, push, pop, replace, reset]
6552
6605
  );