ralphctl 0.4.3 → 0.4.5

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.
Files changed (28) hide show
  1. package/dist/{add-MG26JWBP.mjs → add-DVPVHENV.mjs} +7 -7
  2. package/dist/{add-ZZYL4BSF.mjs → add-YVXM34RP.mjs} +6 -6
  3. package/dist/{chunk-LDSG7G2T.mjs → chunk-BSB4EDGR.mjs} +2 -2
  4. package/dist/{chunk-RQGD5WS6.mjs → chunk-CBMFRQ4Y.mjs} +3 -3
  5. package/dist/{chunk-Q4AVHUZL.mjs → chunk-FNAAA32W.mjs} +3 -3
  6. package/dist/{chunk-EGUFQNRB.mjs → chunk-GQ2WFKBN.mjs} +3 -3
  7. package/dist/{chunk-LCY32RW4.mjs → chunk-OFILN7QL.mjs} +183 -39
  8. package/dist/{chunk-MDE6KPJQ.mjs → chunk-OGEXYSFS.mjs} +5 -5
  9. package/dist/{chunk-TDBEEHTS.mjs → chunk-PYZEQ2VK.mjs} +5 -5
  10. package/dist/{chunk-57UWLHRH.mjs → chunk-VAZ3LJBI.mjs} +12 -1
  11. package/dist/{chunk-D2HWXEHH.mjs → chunk-WDMLPXOD.mjs} +2 -2
  12. package/dist/{chunk-WZTY77GY.mjs → chunk-XN2UIHBY.mjs} +10 -3
  13. package/dist/{chunk-WOMGKKZY.mjs → chunk-XPLYLRIM.mjs} +319 -15
  14. package/dist/{chunk-2FT37OZX.mjs → chunk-ZLWSPLWI.mjs} +53 -7
  15. package/dist/cli.mjs +19 -17
  16. package/dist/create-Z635FQKO.mjs +15 -0
  17. package/dist/{handle-SYVCFI6Y.mjs → handle-23EFF3BE.mjs} +1 -1
  18. package/dist/{mount-2ANLHHQE.mjs → mount-H2IH3MWE.mjs} +1455 -1193
  19. package/dist/{project-JF47ZWMF.mjs → project-DQHF4ISP.mjs} +3 -3
  20. package/dist/prompts/sprint-feedback.md +4 -0
  21. package/dist/prompts/task-evaluation.md +44 -2
  22. package/dist/prompts/task-execution.md +5 -0
  23. package/dist/{resolver-PG2DZEBX.mjs → resolver-OVPYVW6Q.mjs} +3 -3
  24. package/dist/{sprint-54DOSIJK.mjs → sprint-4E26AB5F.mjs} +4 -4
  25. package/dist/start-2WH4BTDB.mjs +19 -0
  26. package/package.json +1 -1
  27. package/dist/create-PQK6KKRD.mjs +0 -15
  28. package/dist/start-2SZTBKGF.mjs +0 -19
@@ -3,6 +3,7 @@ import {
3
3
  FIELD_LABEL_WIDTH,
4
4
  InMemorySignalBus,
5
5
  InkPromptAdapter,
6
+ InkSink,
6
7
  PromptHost,
7
8
  checkAiProvider,
8
9
  checkConfigSchemaValidation,
@@ -25,6 +26,7 @@ import {
25
26
  glyphs,
26
27
  inkColors,
27
28
  loadDashboardData,
29
+ logEventBus,
28
30
  progressLogCommand,
29
31
  progressShowCommand,
30
32
  projectListCommand,
@@ -60,7 +62,7 @@ import {
60
62
  ticketRemoveCommand,
61
63
  ticketShowCommand,
62
64
  useCurrentPrompt
63
- } from "./chunk-WOMGKKZY.mjs";
65
+ } from "./chunk-XPLYLRIM.mjs";
64
66
  import {
65
67
  PromptCancelledError,
66
68
  detectCheckScriptCandidates,
@@ -71,18 +73,17 @@ import {
71
73
  projectAddCommand,
72
74
  suggestCheckScript,
73
75
  validateConfigValue
74
- } from "./chunk-TDBEEHTS.mjs";
76
+ } from "./chunk-PYZEQ2VK.mjs";
75
77
  import {
76
78
  sprintCreateCommand
77
- } from "./chunk-Q4AVHUZL.mjs";
79
+ } from "./chunk-FNAAA32W.mjs";
78
80
  import {
79
81
  ticketAddCommand
80
- } from "./chunk-MDE6KPJQ.mjs";
82
+ } from "./chunk-OGEXYSFS.mjs";
81
83
  import {
82
84
  addTask,
83
85
  areAllTasksDone,
84
86
  branchExists,
85
- createExecuteSprintPipeline,
86
87
  createIdeatePipeline,
87
88
  createOnboardPipeline,
88
89
  createPlanPipeline,
@@ -98,7 +99,7 @@ import {
98
99
  reorderTask,
99
100
  sprintStartCommand,
100
101
  updateTaskStatus
101
- } from "./chunk-LCY32RW4.mjs";
102
+ } from "./chunk-OFILN7QL.mjs";
102
103
  import {
103
104
  ProviderAiSessionAdapter,
104
105
  SignalParser,
@@ -106,7 +107,7 @@ import {
106
107
  exitAltScreen,
107
108
  registerTuiInstance,
108
109
  withSuspendedTui
109
- } from "./chunk-2FT37OZX.mjs";
110
+ } from "./chunk-ZLWSPLWI.mjs";
110
111
  import {
111
112
  addTicket,
112
113
  allRequirementsApproved,
@@ -118,7 +119,7 @@ import {
118
119
  removeTicket,
119
120
  truncate,
120
121
  updateTicket
121
- } from "./chunk-EGUFQNRB.mjs";
122
+ } from "./chunk-GQ2WFKBN.mjs";
122
123
  import "./chunk-CFUVE2BP.mjs";
123
124
  import {
124
125
  getPrompt,
@@ -137,7 +138,7 @@ import {
137
138
  removeProjectRepo,
138
139
  resolveRepoPath,
139
140
  updateProject
140
- } from "./chunk-LDSG7G2T.mjs";
141
+ } from "./chunk-BSB4EDGR.mjs";
141
142
  import {
142
143
  closeSprint,
143
144
  createSprint,
@@ -149,7 +150,7 @@ import {
149
150
  logProgress,
150
151
  resolveSprintId,
151
152
  saveSprint
152
- } from "./chunk-RQGD5WS6.mjs";
153
+ } from "./chunk-CBMFRQ4Y.mjs";
153
154
  import {
154
155
  banner,
155
156
  colors,
@@ -162,7 +163,7 @@ import {
162
163
  gradients,
163
164
  setAiProvider,
164
165
  setCurrentSprint
165
- } from "./chunk-WZTY77GY.mjs";
166
+ } from "./chunk-XN2UIHBY.mjs";
166
167
  import {
167
168
  ensureError,
168
169
  wrapAsync
@@ -177,165 +178,22 @@ import {
177
178
  getTasksFilePath,
178
179
  readTextFile,
179
180
  readValidatedJson
180
- } from "./chunk-D2HWXEHH.mjs";
181
- import "./chunk-57UWLHRH.mjs";
181
+ } from "./chunk-WDMLPXOD.mjs";
182
+ import {
183
+ ExecutionAlreadyRunningError
184
+ } from "./chunk-VAZ3LJBI.mjs";
182
185
 
183
186
  // src/integration/ui/tui/runtime/mount.tsx
184
187
  import "react";
185
188
  import { render } from "ink";
186
189
 
187
- // src/integration/ui/tui/runtime/event-bus.ts
188
- var FRAME_MS = 16;
189
- var SingletonLogEventBus = class {
190
- listeners = /* @__PURE__ */ new Set();
191
- buffer = [];
192
- flushTimer = null;
193
- emit(event) {
194
- this.buffer.push(event);
195
- this.scheduleFlush();
196
- }
197
- subscribe(listener) {
198
- this.listeners.add(listener);
199
- return () => {
200
- this.listeners.delete(listener);
201
- };
202
- }
203
- dispose() {
204
- if (this.flushTimer) {
205
- clearTimeout(this.flushTimer);
206
- this.flushTimer = null;
207
- }
208
- this.listeners.clear();
209
- this.buffer.length = 0;
210
- }
211
- /** Force immediate drain. Primarily for tests. */
212
- flush() {
213
- if (this.flushTimer) {
214
- clearTimeout(this.flushTimer);
215
- this.flushTimer = null;
216
- }
217
- this.drain();
218
- }
219
- scheduleFlush() {
220
- if (this.flushTimer !== null) return;
221
- const timer = setTimeout(() => {
222
- this.flushTimer = null;
223
- this.drain();
224
- }, FRAME_MS);
225
- timer.unref();
226
- this.flushTimer = timer;
227
- }
228
- drain() {
229
- if (this.buffer.length === 0) return;
230
- const batch = this.buffer.splice(0, this.buffer.length);
231
- for (const listener of this.listeners) {
232
- try {
233
- listener(batch);
234
- } catch {
235
- }
236
- }
237
- }
238
- };
239
- var logEventBus = new SingletonLogEventBus();
240
-
241
- // src/integration/logging/ink-sink.ts
242
- var spinnerId = 0;
243
- var InkSink = class _InkSink {
244
- constructor(context = {}) {
245
- this.context = context;
246
- }
247
- context;
248
- emit(event) {
249
- logEventBus.emit(event);
250
- }
251
- // -- Structured log levels --------------------------------------------------
252
- debug(message, context) {
253
- this.emit({ kind: "log", level: "debug", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
254
- }
255
- info(message, context) {
256
- this.emit({ kind: "log", level: "info", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
257
- }
258
- warn(message, context) {
259
- this.emit({ kind: "log", level: "warn", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
260
- }
261
- error(message, context) {
262
- this.emit({ kind: "log", level: "error", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
263
- }
264
- // -- UI-level output --------------------------------------------------------
265
- success(message) {
266
- this.emit({ kind: "log", level: "success", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
267
- }
268
- warning(message) {
269
- this.emit({ kind: "log", level: "warning", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
270
- }
271
- tip(message) {
272
- this.emit({ kind: "log", level: "tip", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
273
- }
274
- // -- Layout -----------------------------------------------------------------
275
- header(title, icon) {
276
- this.emit({ kind: "header", title, icon, timestamp: /* @__PURE__ */ new Date() });
277
- }
278
- separator(width = 40) {
279
- this.emit({ kind: "separator", width, timestamp: /* @__PURE__ */ new Date() });
280
- }
281
- field(label, value, _width) {
282
- void _width;
283
- this.emit({ kind: "field", label, value, timestamp: /* @__PURE__ */ new Date() });
284
- }
285
- card(title, lines) {
286
- this.emit({ kind: "card", title, lines, timestamp: /* @__PURE__ */ new Date() });
287
- }
288
- newline() {
289
- this.emit({ kind: "newline", timestamp: /* @__PURE__ */ new Date() });
290
- }
291
- dim(message) {
292
- this.emit({ kind: "log", level: "dim", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
293
- }
294
- item(message) {
295
- this.emit({ kind: "log", level: "item", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
296
- }
297
- // -- Interactive ------------------------------------------------------------
298
- spinner(message) {
299
- const id = ++spinnerId;
300
- this.emit({ kind: "spinner-start", id, message, timestamp: /* @__PURE__ */ new Date() });
301
- return {
302
- succeed: (msg) => {
303
- this.emit({ kind: "spinner-succeed", id, message: msg, timestamp: /* @__PURE__ */ new Date() });
304
- },
305
- fail: (msg) => {
306
- this.emit({ kind: "spinner-fail", id, message: msg, timestamp: /* @__PURE__ */ new Date() });
307
- },
308
- stop: () => {
309
- this.emit({ kind: "spinner-stop", id, timestamp: /* @__PURE__ */ new Date() });
310
- }
311
- };
312
- }
313
- // -- Scoped child -----------------------------------------------------------
314
- child(context) {
315
- return new _InkSink({ ...this.context, ...context });
316
- }
317
- // -- Timing -----------------------------------------------------------------
318
- time(label) {
319
- const start = Date.now();
320
- return () => {
321
- const ms = Date.now() - start;
322
- this.debug(`${label}: ${String(ms)}ms`);
323
- };
324
- }
325
- // -- Internals --------------------------------------------------------------
326
- merge(extra) {
327
- if (!extra) return this.context;
328
- return { ...this.context, ...extra };
329
- }
330
- };
331
-
332
190
  // src/integration/ui/tui/views/app.tsx
333
- import { useEffect as useEffect29, useState as useState30 } from "react";
334
- import { Box as Box35, useStdout } from "ink";
191
+ import { useEffect as useEffect37, useState as useState38 } from "react";
192
+ import { Box as Box37, useStdout } from "ink";
335
193
 
336
194
  // src/integration/ui/tui/views/view-router.tsx
337
- import { useCallback as useCallback11, useMemo as useMemo36, useRef as useRef4, useState as useState29 } from "react";
338
- import { Box as Box34, useApp, useInput as useInput19 } from "ink";
195
+ import { useCallback as useCallback12, useMemo as useMemo34, useState as useState37 } from "react";
196
+ import { Box as Box36 } from "ink";
339
197
 
340
198
  // src/integration/ui/tui/components/banner.tsx
341
199
  import { useMemo } from "react";
@@ -455,10 +313,13 @@ function useRouter() {
455
313
  }
456
314
  return api;
457
315
  }
316
+ function useRouterOptional() {
317
+ return useContext2(RouterContext);
318
+ }
458
319
 
459
320
  // src/integration/ui/tui/views/home-view.tsx
460
321
  import { useCallback as useCallback2, useEffect as useEffect4, useState as useState4 } from "react";
461
- import { Box as Box9, Text as Text8, useInput as useInput3 } from "ink";
322
+ import { Box as Box9, Text as Text8, useInput as useInput4 } from "ink";
462
323
 
463
324
  // src/integration/ui/tui/views/menu-builder.ts
464
325
  var SEPARATOR_WIDTH = 48;
@@ -1028,8 +889,68 @@ function SectionStamp({ title, color: color2 = inkColors.primary }) {
1028
889
  // src/integration/ui/tui/components/view-shell.tsx
1029
890
  import "react";
1030
891
  import { Box as Box8 } from "ink";
892
+
893
+ // src/integration/ui/tui/runtime/use-global-keys.ts
894
+ import { useApp, useInput as useInput3 } from "ink";
895
+
896
+ // src/integration/ui/tui/views/home-submenu-memory.ts
897
+ var memory = null;
898
+ function getHomeSubmenuMemory() {
899
+ return memory;
900
+ }
901
+ function setHomeSubmenuMemory(group) {
902
+ memory = group;
903
+ }
904
+ function clearHomeSubmenuMemory() {
905
+ memory = null;
906
+ }
907
+
908
+ // src/integration/ui/tui/runtime/use-global-keys.ts
909
+ function useGlobalKeys() {
910
+ const router = useRouterOptional();
911
+ const app = useApp();
912
+ const currentPrompt = useCurrentPrompt();
913
+ const routerHotkeysActive = router !== null && currentPrompt === null;
914
+ useInput3(
915
+ (input, key) => {
916
+ if (router === null) return;
917
+ if (key.escape) {
918
+ router.pop();
919
+ return;
920
+ }
921
+ if (input === "h") {
922
+ clearHomeSubmenuMemory();
923
+ router.reset({ id: "home" });
924
+ return;
925
+ }
926
+ if (input === "s" && router.current.id !== "settings") {
927
+ router.push({ id: "settings" });
928
+ return;
929
+ }
930
+ if (input === "d" && router.current.id !== "dashboard") {
931
+ router.push({ id: "dashboard" });
932
+ return;
933
+ }
934
+ if (input === "?" && router.current.id !== "doctor") {
935
+ router.push({ id: "doctor" });
936
+ return;
937
+ }
938
+ if (input === "x" && router.current.id !== "running-executions") {
939
+ router.push({ id: "running-executions" });
940
+ return;
941
+ }
942
+ if (input === "q" && router.stack.length === 1 && router.current.id === "home") {
943
+ app.exit();
944
+ }
945
+ },
946
+ { isActive: routerHotkeysActive }
947
+ );
948
+ }
949
+
950
+ // src/integration/ui/tui/components/view-shell.tsx
1031
951
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1032
952
  function ViewShell({ title, bare = false, children }) {
953
+ useGlobalKeys();
1033
954
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1034
955
  !bare && title !== void 0 ? /* @__PURE__ */ jsx9(SectionStamp, { title }) : null,
1035
956
  /* @__PURE__ */ jsx9(Box8, { marginTop: bare ? 0 : spacing.section, flexDirection: "column", children })
@@ -1265,8 +1186,8 @@ async function loadHomeState() {
1265
1186
  ctx.nextAction = getNextAction(dashboardData);
1266
1187
  return { ctx, dashboardData, snapshot: computePipelineSnapshot(ctx) };
1267
1188
  }
1268
- var lastSubGroup = null;
1269
1189
  function HomeView() {
1190
+ useGlobalKeys();
1270
1191
  const router = useRouter();
1271
1192
  const [state, setState] = useState4(null);
1272
1193
  const [mode, setModeInternal] = useState4("main");
@@ -1276,7 +1197,7 @@ function HomeView() {
1276
1197
  const setMode = useCallback2((next) => {
1277
1198
  setModeInternal((prev) => {
1278
1199
  const resolved = typeof next === "function" ? next(prev) : next;
1279
- lastSubGroup = typeof resolved === "object" ? resolved.group : null;
1200
+ setHomeSubmenuMemory(typeof resolved === "object" ? resolved.group : null);
1280
1201
  return resolved;
1281
1202
  });
1282
1203
  }, []);
@@ -1290,9 +1211,10 @@ function HomeView() {
1290
1211
  const next = await loadHomeState();
1291
1212
  if (cancel.current) return;
1292
1213
  setState(next);
1293
- if (lastSubGroup !== null) {
1294
- const menu = buildSubMenu(lastSubGroup, next.ctx);
1295
- if (menu) setModeInternal({ kind: "sub", menu, group: lastSubGroup });
1214
+ const stored = getHomeSubmenuMemory();
1215
+ if (stored !== null) {
1216
+ const menu = buildSubMenu(stored, next.ctx);
1217
+ if (menu) setModeInternal({ kind: "sub", menu, group: stored });
1296
1218
  }
1297
1219
  } catch (err) {
1298
1220
  if (!cancel.current) setError(err instanceof Error ? err.message : String(err));
@@ -1352,12 +1274,16 @@ function HomeView() {
1352
1274
  },
1353
1275
  [refresh, router, state]
1354
1276
  );
1355
- useInput3((input, key) => {
1277
+ useInput4((input, key) => {
1356
1278
  if (mode === "busy") return;
1357
1279
  if (key.escape && typeof mode === "object") {
1358
1280
  setMode("main");
1359
1281
  return;
1360
1282
  }
1283
+ if (input === "h" && typeof mode === "object") {
1284
+ setMode("main");
1285
+ return;
1286
+ }
1361
1287
  if (mode === "main" && input === "b" && state !== null) {
1362
1288
  const menu = buildSubMenu("browse", state.ctx);
1363
1289
  if (menu) setMode({ kind: "sub", menu, group: "browse" });
@@ -1466,7 +1392,7 @@ import "react";
1466
1392
 
1467
1393
  // src/integration/ui/tui/views/settings-panel.tsx
1468
1394
  import { useCallback as useCallback3, useEffect as useEffect5, useState as useState5 } from "react";
1469
- import { Box as Box10, Text as Text9, useInput as useInput4 } from "ink";
1395
+ import { Box as Box10, Text as Text9, useInput as useInput5 } from "ink";
1470
1396
  import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1471
1397
  var SETTINGS_HINTS = [
1472
1398
  { key: "\u2191/\u2193", action: "navigate" },
@@ -1588,7 +1514,7 @@ function SettingsPanel({ onClose }) {
1588
1514
  setEditing(false);
1589
1515
  }
1590
1516
  }, [cursor, entries, config, saveValue]);
1591
- useInput4((input, key) => {
1517
+ useInput5((input, key) => {
1592
1518
  if (editing) return;
1593
1519
  if (key.escape) {
1594
1520
  onClose();
@@ -1679,15 +1605,17 @@ function SettingsView() {
1679
1605
  }
1680
1606
 
1681
1607
  // src/integration/ui/tui/views/execute-view.tsx
1682
- import { useEffect as useEffect8, useRef as useRef2, useState as useState8 } from "react";
1683
- import { Box as Box17, Text as Text16, useInput as useInput5 } from "ink";
1608
+ import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef2, useState as useState8 } from "react";
1609
+ import { Box as Box19, Text as Text18, useInput as useInput6 } from "ink";
1684
1610
 
1685
1611
  // src/integration/ui/tui/runtime/hooks.ts
1686
1612
  import { useCallback as useCallback4, useEffect as useEffect6, useRef, useState as useState6 } from "react";
1687
- function useLoggerEvents(limit = 200) {
1613
+ function useLoggerEvents(limit = 200, bus) {
1688
1614
  const [buffer, setBuffer] = useState6([]);
1615
+ const source = bus ?? logEventBus;
1689
1616
  useEffect6(() => {
1690
- const unsubscribe = logEventBus.subscribe((batch) => {
1617
+ setBuffer([]);
1618
+ const unsubscribe = source.subscribe((batch) => {
1691
1619
  setBuffer((prev) => {
1692
1620
  const next = prev.concat(batch);
1693
1621
  if (next.length > limit) next.splice(0, next.length - limit);
@@ -1695,12 +1623,29 @@ function useLoggerEvents(limit = 200) {
1695
1623
  });
1696
1624
  });
1697
1625
  return unsubscribe;
1698
- }, [limit]);
1626
+ }, [limit, source]);
1699
1627
  return buffer;
1700
1628
  }
1629
+ function useRegistryEvents(registry) {
1630
+ const [executions, setExecutions] = useState6(() => registry ? registry.list() : []);
1631
+ useEffect6(() => {
1632
+ if (registry === null) {
1633
+ setExecutions([]);
1634
+ return;
1635
+ }
1636
+ setExecutions(registry.list());
1637
+ const unsubscribe = registry.subscribe(() => {
1638
+ setExecutions(registry.list());
1639
+ });
1640
+ return unsubscribe;
1641
+ }, [registry]);
1642
+ return executions;
1643
+ }
1701
1644
  function useSignalEvents(bus, limit = 200) {
1702
1645
  const [buffer, setBuffer] = useState6([]);
1703
1646
  useEffect6(() => {
1647
+ setBuffer([]);
1648
+ if (bus === null) return;
1704
1649
  const unsubscribe = bus.subscribe((batch) => {
1705
1650
  setBuffer((prev) => {
1706
1651
  const next = prev.concat(batch);
@@ -2003,10 +1948,59 @@ function RateLimitBanner({ pausedSince, delayMs }) {
2003
1948
  ] });
2004
1949
  }
2005
1950
 
2006
- // src/integration/ui/tui/views/execute-view.tsx
1951
+ // src/integration/ui/tui/components/result-card.tsx
1952
+ import "react";
1953
+ import { Box as Box18, Text as Text17 } from "ink";
1954
+
1955
+ // src/integration/ui/tui/components/field-list.tsx
1956
+ import "react";
1957
+ import { Box as Box17, Text as Text16 } from "ink";
2007
1958
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2008
- var EXECUTE_HINTS_RUNNING = [];
2009
- var EXECUTE_HINTS_DONE = [{ key: "Enter", action: "home" }];
1959
+ function FieldList({ fields, labelWidth: labelWidth2 = FIELD_LABEL_WIDTH }) {
1960
+ return /* @__PURE__ */ jsx18(Box17, { flexDirection: "column", children: fields.map(([label, value]) => /* @__PURE__ */ jsxs16(Box17, { children: [
1961
+ /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: (label + ":").padEnd(labelWidth2) }),
1962
+ /* @__PURE__ */ jsx18(Text16, { children: ` ${value}` })
1963
+ ] }, label)) });
1964
+ }
1965
+
1966
+ // src/integration/ui/tui/components/result-card.tsx
1967
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
1968
+ var GLYPH = {
1969
+ success: glyphs.check,
1970
+ error: glyphs.cross,
1971
+ warning: glyphs.warningGlyph,
1972
+ info: glyphs.infoGlyph
1973
+ };
1974
+ var COLOR = {
1975
+ success: inkColors.success,
1976
+ error: inkColors.error,
1977
+ warning: inkColors.warning,
1978
+ info: inkColors.info
1979
+ };
1980
+ function ResultCard({ kind, title, fields, nextSteps, lines }) {
1981
+ const color2 = COLOR[kind];
1982
+ return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", children: [
1983
+ /* @__PURE__ */ jsxs17(Box18, { children: [
1984
+ /* @__PURE__ */ jsx19(Text17, { color: color2, bold: true, children: GLYPH[kind] }),
1985
+ /* @__PURE__ */ jsx19(Text17, { color: color2, bold: true, children: ` ${title}` })
1986
+ ] }),
1987
+ fields && fields.length > 0 ? /* @__PURE__ */ jsx19(Box18, { marginTop: spacing.section, children: /* @__PURE__ */ jsx19(FieldList, { fields }) }) : null,
1988
+ lines && lines.length > 0 ? /* @__PURE__ */ jsx19(Box18, { marginTop: spacing.section, flexDirection: "column", children: lines.map((line2, i) => /* @__PURE__ */ jsx19(Box18, { children: /* @__PURE__ */ jsx19(Text17, { dimColor: true, children: line2 }) }, i)) }) : null,
1989
+ nextSteps && nextSteps.length > 0 ? /* @__PURE__ */ jsxs17(Box18, { marginTop: spacing.section, flexDirection: "column", children: [
1990
+ /* @__PURE__ */ jsx19(Text17, { dimColor: true, bold: true, children: "Next" }),
1991
+ nextSteps.map((step, i) => /* @__PURE__ */ jsxs17(Box18, { paddingLeft: spacing.indent, children: [
1992
+ /* @__PURE__ */ jsx19(Text17, { color: inkColors.highlight, children: `${glyphs.arrowRight} ` }),
1993
+ /* @__PURE__ */ jsx19(Text17, { children: step.action }),
1994
+ step.description ? /* @__PURE__ */ jsx19(Text17, { dimColor: true, children: ` ${glyphs.emDash} ${step.description}` }) : null
1995
+ ] }, i))
1996
+ ] }) : null
1997
+ ] });
1998
+ }
1999
+
2000
+ // src/integration/ui/tui/views/execute-view.tsx
2001
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
2002
+ var EXECUTE_HINTS_RUNNING = [{ key: "c", action: "cancel" }];
2003
+ var EXECUTE_HINTS_TERMINAL = [{ key: "Enter", action: "back" }];
2010
2004
  function initialState() {
2011
2005
  return {
2012
2006
  sprint: null,
@@ -2015,62 +2009,104 @@ function initialState() {
2015
2009
  blocked: /* @__PURE__ */ new Set(),
2016
2010
  activity: /* @__PURE__ */ new Map(),
2017
2011
  currentStep: /* @__PURE__ */ new Map(),
2018
- summary: null,
2019
- error: null,
2020
- rateLimit: null
2012
+ rateLimit: null,
2013
+ taskRefreshError: null
2021
2014
  };
2022
2015
  }
2023
- function ExecuteView({ sprintId, executionOptions }) {
2016
+ var initialAttach = {
2017
+ kind: "attaching",
2018
+ execution: null,
2019
+ collisionId: null,
2020
+ errorMessage: null
2021
+ };
2022
+ function ExecuteView({ sprintId, executionId, executionOptions }) {
2024
2023
  const router = useRouter();
2025
2024
  const shared = getSharedDeps();
2026
- const signalEvents = useSignalEvents(shared.signalBus);
2027
- const logEvents = useLoggerEvents(200);
2025
+ const registry = shared.executionRegistry;
2026
+ const registryEvents = useRegistryEvents(registry);
2027
+ const [attach, setAttach] = useState8(initialAttach);
2028
2028
  const [state, setState] = useState8(initialState);
2029
- const [done, setDone] = useState8(false);
2030
2029
  const processedCountRef = useRef2(0);
2030
+ const startedRef = useRef2(false);
2031
+ const attachedId = attach.execution?.id ?? null;
2032
+ const liveExecution = useMemo6(() => {
2033
+ if (attachedId === null) return null;
2034
+ return registry.get(attachedId);
2035
+ }, [attachedId, registry, registryEvents]);
2031
2036
  useEffect8(() => {
2032
- const cancel = { current: false };
2033
- const load = async () => {
2037
+ if (startedRef.current) return;
2038
+ startedRef.current = true;
2039
+ if (executionId !== void 0) {
2040
+ const existing = registry.get(executionId);
2041
+ if (existing === null) {
2042
+ setAttach({
2043
+ kind: "error",
2044
+ execution: null,
2045
+ collisionId: null,
2046
+ errorMessage: `Execution ${executionId} is no longer tracked.`
2047
+ });
2048
+ return;
2049
+ }
2050
+ setAttach({ kind: "attached", execution: existing, collisionId: null, errorMessage: null });
2051
+ return;
2052
+ }
2053
+ void (async () => {
2034
2054
  try {
2035
- const [sprint, tasks] = await Promise.all([
2036
- shared.persistence.getSprint(sprintId),
2037
- shared.persistence.getTasks(sprintId)
2038
- ]);
2039
- if (!cancel.current) setState((s) => ({ ...s, sprint, tasks }));
2055
+ const execution = await registry.start({ sprintId, options: executionOptions });
2056
+ setAttach({ kind: "attached", execution, collisionId: null, errorMessage: null });
2040
2057
  } catch (err) {
2041
- if (!cancel.current) setState((s) => ({ ...s, error: err instanceof Error ? err.message : String(err) }));
2058
+ if (err instanceof ExecutionAlreadyRunningError) {
2059
+ setAttach({
2060
+ kind: "collision",
2061
+ execution: null,
2062
+ collisionId: err.existingExecutionId,
2063
+ errorMessage: err.message
2064
+ });
2065
+ return;
2066
+ }
2067
+ setAttach({
2068
+ kind: "error",
2069
+ execution: null,
2070
+ collisionId: null,
2071
+ errorMessage: err instanceof Error ? err.message : String(err)
2072
+ });
2042
2073
  }
2043
- };
2044
- void load();
2045
- return () => {
2046
- cancel.current = true;
2047
- };
2048
- }, [shared, sprintId]);
2074
+ })();
2075
+ }, [executionId, executionOptions, registry, sprintId]);
2076
+ const scopedSignalBus = useMemo6(() => {
2077
+ if (attachedId === null) return null;
2078
+ return registry.getSignalBus(attachedId);
2079
+ }, [attachedId, registry]);
2080
+ const scopedLogEventBus = useMemo6(() => {
2081
+ if (attachedId === null) return null;
2082
+ return registry.getLogEventBus(attachedId);
2083
+ }, [attachedId, registry]);
2084
+ const signalEvents = useSignalEvents(scopedSignalBus);
2085
+ const logEvents = useLoggerEvents(200, scopedLogEventBus);
2049
2086
  useEffect8(() => {
2050
- if (state.sprint === null || done) return;
2051
2087
  const cancel = { current: false };
2052
- const run = async () => {
2088
+ void (async () => {
2053
2089
  try {
2054
- const pipeline = createExecuteSprintPipeline(shared, executionOptions);
2055
- const result = await executePipeline(pipeline, { sprintId });
2056
- if (cancel.current) return;
2057
- if (result.ok) {
2058
- const summary = result.value.context.executionSummary ?? null;
2059
- setState((s) => ({ ...s, summary }));
2060
- } else {
2061
- setState((s) => ({ ...s, error: result.error.message }));
2090
+ if (liveExecution) {
2091
+ if (!cancel.current) {
2092
+ setState((s) => ({ ...s, sprint: liveExecution.sprint }));
2093
+ }
2062
2094
  }
2095
+ const tasks = await shared.persistence.getTasks(sprintId);
2096
+ if (!cancel.current) setState((s) => ({ ...s, tasks }));
2063
2097
  } catch (err) {
2064
- if (!cancel.current) setState((s) => ({ ...s, error: err instanceof Error ? err.message : String(err) }));
2065
- } finally {
2066
- if (!cancel.current) setDone(true);
2098
+ if (!cancel.current) {
2099
+ setState((s) => ({ ...s, taskRefreshError: err instanceof Error ? err.message : String(err) }));
2100
+ }
2067
2101
  }
2068
- };
2069
- void run();
2102
+ })();
2070
2103
  return () => {
2071
2104
  cancel.current = true;
2072
2105
  };
2073
- }, [state.sprint, shared, sprintId, executionOptions, done]);
2106
+ }, [liveExecution, shared, sprintId]);
2107
+ useEffect8(() => {
2108
+ processedCountRef.current = 0;
2109
+ }, [scopedSignalBus]);
2074
2110
  useEffect8(() => {
2075
2111
  if (signalEvents.length <= processedCountRef.current) return;
2076
2112
  const fresh = signalEvents.slice(processedCountRef.current);
@@ -2086,18 +2122,20 @@ function ExecuteView({ sprintId, executionOptions }) {
2086
2122
  })();
2087
2123
  }
2088
2124
  }, [signalEvents, shared, sprintId]);
2125
+ const status = liveExecution?.status ?? "running";
2126
+ const terminal = status === "completed" || status === "failed" || status === "cancelled";
2089
2127
  const [closePromptRun, setClosePromptRun] = useState8(false);
2090
2128
  useEffect8(() => {
2091
- if (!done) return;
2129
+ if (!terminal) return;
2130
+ if (closePromptRun) return;
2131
+ setClosePromptRun(true);
2092
2132
  void (async () => {
2093
2133
  try {
2094
2134
  const tasks = await shared.persistence.getTasks(sprintId);
2095
2135
  setState((s) => ({ ...s, tasks }));
2096
2136
  } catch {
2097
2137
  }
2098
- if (closePromptRun) return;
2099
- setClosePromptRun(true);
2100
- const summary = state.summary;
2138
+ const summary = liveExecution ? liveExecution.summary : void 0;
2101
2139
  if (summary?.stopReason === "all_completed" && summary.remaining === 0 && summary.completed > 0 && await areAllTasksDone(sprintId)) {
2102
2140
  try {
2103
2141
  const shouldClose = await getPrompt().confirm({
@@ -2109,28 +2147,62 @@ function ExecuteView({ sprintId, executionOptions }) {
2109
2147
  }
2110
2148
  }
2111
2149
  })();
2112
- }, [done, shared, sprintId, state.summary, closePromptRun]);
2113
- useInput5((input, key) => {
2114
- if (!done) return;
2115
- if (key.escape || input === "h" || input === "s" || input === "q") return;
2116
- if (key.return || input.length > 0) {
2117
- router.replace({ id: "home" });
2150
+ }, [terminal, closePromptRun, shared, sprintId, liveExecution]);
2151
+ useInput6((input, key) => {
2152
+ if (attach.kind === "attached" && liveExecution?.status === "running" && input === "c") {
2153
+ registry.cancel(liveExecution.id);
2154
+ return;
2155
+ }
2156
+ if (terminal && key.return) {
2157
+ router.pop();
2118
2158
  }
2119
2159
  });
2120
- useViewHints(done ? EXECUTE_HINTS_DONE : EXECUTE_HINTS_RUNNING);
2121
- return /* @__PURE__ */ jsxs16(ViewShell, { title: "Execute", children: [
2122
- /* @__PURE__ */ jsxs16(Box17, { children: [
2123
- /* @__PURE__ */ jsx18(Text16, { bold: true, color: inkColors.primary, children: state.sprint?.name ?? "Sprint" }),
2124
- /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
2160
+ useViewHints(terminal ? EXECUTE_HINTS_TERMINAL : EXECUTE_HINTS_RUNNING);
2161
+ if (attach.kind === "collision") {
2162
+ return /* @__PURE__ */ jsxs18(ViewShell, { title: "Execute", children: [
2163
+ /* @__PURE__ */ jsx20(
2164
+ ResultCard,
2165
+ {
2166
+ kind: "warning",
2167
+ title: "Execution already running",
2168
+ lines: [attach.errorMessage ?? "A run is already in progress for this project."],
2169
+ nextSteps: [
2170
+ {
2171
+ action: "Press Enter to view the running execution",
2172
+ description: "The harness keeps one execution per project."
2173
+ }
2174
+ ]
2175
+ }
2176
+ ),
2177
+ /* @__PURE__ */ jsx20(CollisionRedirect, { registry, collisionId: attach.collisionId, fallbackSprintId: sprintId })
2178
+ ] });
2179
+ }
2180
+ if (attach.kind === "error") {
2181
+ return /* @__PURE__ */ jsx20(ViewShell, { title: "Execute", children: /* @__PURE__ */ jsx20(
2182
+ ResultCard,
2183
+ {
2184
+ kind: "error",
2185
+ title: "Could not attach to execution",
2186
+ lines: [attach.errorMessage ?? "Unknown error."]
2187
+ }
2188
+ ) });
2189
+ }
2190
+ if (attach.kind === "attaching") {
2191
+ return /* @__PURE__ */ jsx20(ViewShell, { title: "Execute", children: /* @__PURE__ */ jsx20(Spinner, { label: "Attaching to execution\u2026" }) });
2192
+ }
2193
+ return /* @__PURE__ */ jsxs18(ViewShell, { title: "Execute", children: [
2194
+ /* @__PURE__ */ jsxs18(Box19, { children: [
2195
+ /* @__PURE__ */ jsx20(Text18, { bold: true, color: inkColors.primary, children: state.sprint?.name ?? "Sprint" }),
2196
+ /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
2125
2197
  " ",
2126
2198
  state.sprint?.branch ? `[${state.sprint.branch}]` : "",
2127
2199
  " ",
2128
2200
  state.sprint?.status ? `(${state.sprint.status})` : ""
2129
2201
  ] })
2130
2202
  ] }),
2131
- /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(SprintSummary, { tasks: state.tasks }) }),
2132
- state.rateLimit ? /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(RateLimitBanner, { pausedSince: state.rateLimit.pausedSince, delayMs: state.rateLimit.delayMs }) }) : null,
2133
- /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(
2203
+ /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(SprintSummary, { tasks: state.tasks }) }),
2204
+ state.rateLimit ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(RateLimitBanner, { pausedSince: state.rateLimit.pausedSince, delayMs: state.rateLimit.delayMs }) }) : null,
2205
+ /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(
2134
2206
  TaskGrid,
2135
2207
  {
2136
2208
  tasks: state.tasks,
@@ -2139,42 +2211,61 @@ function ExecuteView({ sprintId, executionOptions }) {
2139
2211
  activityByTask: state.activity
2140
2212
  }
2141
2213
  ) }),
2142
- !done && state.currentStep.size > 0 ? /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, flexDirection: "column", children: Array.from(state.currentStep.entries()).map(([taskId, label]) => {
2214
+ !terminal && state.currentStep.size > 0 ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, flexDirection: "column", children: Array.from(state.currentStep.entries()).map(([taskId, label]) => {
2143
2215
  const task = state.tasks.find((t) => t.id === taskId);
2144
2216
  const taskName = task?.name ?? taskId.slice(0, 8);
2145
- return /* @__PURE__ */ jsx18(Spinner, { label: `${taskName} ${glyphs.emDash} ${label}` }, taskId);
2217
+ return /* @__PURE__ */ jsx20(Spinner, { label: `${taskName} ${glyphs.emDash} ${label}` }, taskId);
2146
2218
  }) }) : null,
2147
- /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(LogTail, { events: logEvents }) }),
2148
- state.error ? /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs16(Text16, { color: inkColors.error, children: [
2149
- glyphs.cross,
2150
- " ",
2151
- state.error
2152
- ] }) }) : null,
2153
- state.summary && done ? /* @__PURE__ */ jsxs16(Box17, { marginTop: spacing.section, flexDirection: "column", children: [
2154
- /* @__PURE__ */ jsxs16(Text16, { color: inkColors.success, bold: true, children: [
2155
- glyphs.check,
2156
- " Execution finished"
2219
+ /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(LogTail, { events: logEvents }) }),
2220
+ terminal && liveExecution ? /* @__PURE__ */ jsxs18(Box19, { marginTop: spacing.section, flexDirection: "column", children: [
2221
+ /* @__PURE__ */ jsxs18(Text18, { color: terminalColor(liveExecution.status), bold: true, children: [
2222
+ terminalGlyph(liveExecution.status),
2223
+ " Execution ",
2224
+ liveExecution.status
2157
2225
  ] }),
2158
- /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
2159
- state.summary.completed,
2226
+ liveExecution.summary ? /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
2227
+ liveExecution.summary.completed,
2160
2228
  " completed ",
2161
2229
  glyphs.inlineDot,
2162
2230
  " ",
2163
- state.summary.remaining,
2231
+ liveExecution.summary.remaining,
2164
2232
  " remaining",
2165
2233
  " ",
2166
2234
  glyphs.inlineDot,
2167
2235
  " ",
2168
- state.summary.blocked,
2236
+ liveExecution.summary.blocked,
2169
2237
  " blocked",
2170
2238
  " (",
2171
- state.summary.stopReason,
2239
+ liveExecution.summary.stopReason,
2172
2240
  ")"
2173
- ] }),
2174
- /* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: "Press any key to return home." }) })
2241
+ ] }) : null
2175
2242
  ] }) : null
2176
2243
  ] });
2177
2244
  }
2245
+ function terminalColor(status) {
2246
+ if (status === "completed") return inkColors.success;
2247
+ if (status === "failed") return inkColors.error;
2248
+ return inkColors.muted;
2249
+ }
2250
+ function terminalGlyph(status) {
2251
+ if (status === "completed") return glyphs.check;
2252
+ if (status === "failed") return glyphs.cross;
2253
+ return glyphs.warningGlyph;
2254
+ }
2255
+ function CollisionRedirect({ registry, collisionId, fallbackSprintId }) {
2256
+ const router = useRouter();
2257
+ useInput6((_input, key) => {
2258
+ if (!collisionId) return;
2259
+ if (key.return) {
2260
+ const existingSprintId = registry.get(collisionId)?.sprintId ?? fallbackSprintId;
2261
+ router.replace({
2262
+ id: "execute",
2263
+ props: { sprintId: existingSprintId, executionId: collisionId }
2264
+ });
2265
+ }
2266
+ });
2267
+ return null;
2268
+ }
2178
2269
  var STEP_LABELS = {
2179
2270
  "branch-preflight": "Verifying branch\u2026",
2180
2271
  "contract-negotiate": "Writing contract\u2026",
@@ -2245,57 +2336,6 @@ function reduceEvents(state, events) {
2245
2336
  // src/integration/ui/tui/views/dashboard-view.tsx
2246
2337
  import { useEffect as useEffect9, useState as useState9 } from "react";
2247
2338
  import { Box as Box20, Text as Text19 } from "ink";
2248
-
2249
- // src/integration/ui/tui/components/result-card.tsx
2250
- import "react";
2251
- import { Box as Box19, Text as Text18 } from "ink";
2252
-
2253
- // src/integration/ui/tui/components/field-list.tsx
2254
- import "react";
2255
- import { Box as Box18, Text as Text17 } from "ink";
2256
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
2257
- function FieldList({ fields, labelWidth: labelWidth2 = FIELD_LABEL_WIDTH }) {
2258
- return /* @__PURE__ */ jsx19(Box18, { flexDirection: "column", children: fields.map(([label, value]) => /* @__PURE__ */ jsxs17(Box18, { children: [
2259
- /* @__PURE__ */ jsx19(Text17, { dimColor: true, children: (label + ":").padEnd(labelWidth2) }),
2260
- /* @__PURE__ */ jsx19(Text17, { children: ` ${value}` })
2261
- ] }, label)) });
2262
- }
2263
-
2264
- // src/integration/ui/tui/components/result-card.tsx
2265
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
2266
- var GLYPH = {
2267
- success: glyphs.check,
2268
- error: glyphs.cross,
2269
- warning: glyphs.warningGlyph,
2270
- info: glyphs.infoGlyph
2271
- };
2272
- var COLOR = {
2273
- success: inkColors.success,
2274
- error: inkColors.error,
2275
- warning: inkColors.warning,
2276
- info: inkColors.info
2277
- };
2278
- function ResultCard({ kind, title, fields, nextSteps, lines }) {
2279
- const color2 = COLOR[kind];
2280
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
2281
- /* @__PURE__ */ jsxs18(Box19, { children: [
2282
- /* @__PURE__ */ jsx20(Text18, { color: color2, bold: true, children: GLYPH[kind] }),
2283
- /* @__PURE__ */ jsx20(Text18, { color: color2, bold: true, children: ` ${title}` })
2284
- ] }),
2285
- fields && fields.length > 0 ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(FieldList, { fields }) }) : null,
2286
- lines && lines.length > 0 ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, flexDirection: "column", children: lines.map((line2, i) => /* @__PURE__ */ jsx20(Box19, { children: /* @__PURE__ */ jsx20(Text18, { dimColor: true, children: line2 }) }, i)) }) : null,
2287
- nextSteps && nextSteps.length > 0 ? /* @__PURE__ */ jsxs18(Box19, { marginTop: spacing.section, flexDirection: "column", children: [
2288
- /* @__PURE__ */ jsx20(Text18, { dimColor: true, bold: true, children: "Next" }),
2289
- nextSteps.map((step, i) => /* @__PURE__ */ jsxs18(Box19, { paddingLeft: spacing.indent, children: [
2290
- /* @__PURE__ */ jsx20(Text18, { color: inkColors.highlight, children: `${glyphs.arrowRight} ` }),
2291
- /* @__PURE__ */ jsx20(Text18, { children: step.action }),
2292
- step.description ? /* @__PURE__ */ jsx20(Text18, { dimColor: true, children: ` ${glyphs.emDash} ${step.description}` }) : null
2293
- ] }, i))
2294
- ] }) : null
2295
- ] });
2296
- }
2297
-
2298
- // src/integration/ui/tui/views/dashboard-view.tsx
2299
2339
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
2300
2340
  var PROGRESS_TAIL_LIMIT = 8;
2301
2341
  async function loadRecentProgress(sprintId, limit) {
@@ -2327,12 +2367,12 @@ function Hero({ data }) {
2327
2367
  const ticketCount = sprint.tickets.length;
2328
2368
  const taskCount = tasks.length;
2329
2369
  const providerLabel = aiProvider === "claude" ? "Claude" : aiProvider === "copilot" ? "Copilot" : null;
2330
- const statusColor6 = sprint.status === "active" ? inkColors.success : sprint.status === "closed" ? inkColors.info : inkColors.muted;
2370
+ const statusColor7 = sprint.status === "active" ? inkColors.success : sprint.status === "closed" ? inkColors.info : inkColors.muted;
2331
2371
  return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
2332
2372
  /* @__PURE__ */ jsxs19(Box20, { children: [
2333
2373
  /* @__PURE__ */ jsx21(Text19, { bold: true, color: inkColors.primary, children: sprint.name }),
2334
2374
  /* @__PURE__ */ jsx21(Text19, { children: " " }),
2335
- /* @__PURE__ */ jsxs19(Text19, { color: statusColor6, children: [
2375
+ /* @__PURE__ */ jsxs19(Text19, { color: statusColor7, children: [
2336
2376
  "[",
2337
2377
  sprint.status,
2338
2378
  "]"
@@ -2450,7 +2490,7 @@ var EMPTY_MAP = /* @__PURE__ */ new Map();
2450
2490
 
2451
2491
  // src/integration/ui/tui/views/phases/refine-phase-view.tsx
2452
2492
  import { useCallback as useCallback5, useEffect as useEffect10, useState as useState10 } from "react";
2453
- import { Box as Box22, Text as Text21, useInput as useInput6 } from "ink";
2493
+ import { Box as Box22, Text as Text21, useInput as useInput7 } from "ink";
2454
2494
 
2455
2495
  // src/integration/ui/tui/views/phases/phase-run-trace.tsx
2456
2496
  import "react";
@@ -2476,13 +2516,13 @@ function formatDuration(ms) {
2476
2516
  function PhaseRunTrace({ records, title = "Last run" }) {
2477
2517
  return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
2478
2518
  /* @__PURE__ */ jsx22(Box21, { children: /* @__PURE__ */ jsx22(Text20, { dimColor: true, bold: true, children: title }) }),
2479
- records.length === 0 ? /* @__PURE__ */ jsx22(Box21, { paddingLeft: 2, children: /* @__PURE__ */ jsx22(Text20, { dimColor: true, children: "(no runs yet)" }) }) : records.map((r, i) => /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", paddingLeft: 2, children: [
2519
+ records.length === 0 ? /* @__PURE__ */ jsx22(Box21, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx22(Text20, { dimColor: true, children: "(no runs yet)" }) }) : records.map((r, i) => /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", paddingLeft: spacing.indent, children: [
2480
2520
  /* @__PURE__ */ jsxs20(Box21, { children: [
2481
2521
  /* @__PURE__ */ jsx22(Text20, { color: STATUS_COLOR2[r.status], bold: true, children: STATUS_GLYPH2[r.status] }),
2482
2522
  /* @__PURE__ */ jsx22(Text20, { children: ` ${r.stepName} ` }),
2483
2523
  /* @__PURE__ */ jsx22(Text20, { dimColor: true, children: formatDuration(r.durationMs) })
2484
2524
  ] }),
2485
- r.error ? /* @__PURE__ */ jsx22(Box21, { paddingLeft: 2, children: /* @__PURE__ */ jsxs20(Text20, { color: inkColors.error, children: [
2525
+ r.error ? /* @__PURE__ */ jsx22(Box21, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsxs20(Text20, { color: inkColors.error, children: [
2486
2526
  "\u21B3 ",
2487
2527
  r.error.message
2488
2528
  ] }) }) : null
@@ -2544,7 +2584,7 @@ function RefinePhaseView({ sprintId }) {
2544
2584
  await loadSprint();
2545
2585
  }
2546
2586
  }, [shared, sprintId, loadSprint]);
2547
- useInput6(
2587
+ useInput7(
2548
2588
  (_input, key) => {
2549
2589
  if (key.return && !state.running && canRefine(state.sprint)) {
2550
2590
  void runRefine();
@@ -2606,7 +2646,7 @@ function reasonUnavailable(sprint) {
2606
2646
 
2607
2647
  // src/integration/ui/tui/views/phases/plan-phase-view.tsx
2608
2648
  import { useCallback as useCallback6, useEffect as useEffect11, useState as useState11 } from "react";
2609
- import { Box as Box23, Text as Text22, useInput as useInput7 } from "ink";
2649
+ import { Box as Box23, Text as Text22, useInput as useInput8 } from "ink";
2610
2650
  import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
2611
2651
  var HINTS_RUNNABLE2 = [
2612
2652
  { key: "Enter", action: "plan" },
@@ -2650,7 +2690,7 @@ function PlanPhaseView({ sprintId }) {
2650
2690
  await loadSprintAndTasks();
2651
2691
  }
2652
2692
  }, [shared, sprintId, loadSprintAndTasks]);
2653
- useInput7(
2693
+ useInput8(
2654
2694
  (_input, key) => {
2655
2695
  if (key.return && !state.running && canPlan(state.sprint)) {
2656
2696
  void runPlan();
@@ -2727,18 +2767,20 @@ function groupTasksByPath(tasks) {
2727
2767
  function statusGlyph(status) {
2728
2768
  if (status === "done") return glyphs.check;
2729
2769
  if (status === "in_progress") return glyphs.actionCursor;
2770
+ if (status === "cancelled") return glyphs.cross;
2730
2771
  return glyphs.inlineDot;
2731
2772
  }
2732
2773
  function statusColor2(status) {
2733
2774
  if (status === "done") return inkColors.success;
2734
2775
  if (status === "in_progress") return inkColors.warning;
2776
+ if (status === "cancelled") return inkColors.muted;
2735
2777
  return inkColors.muted;
2736
2778
  }
2737
2779
 
2738
2780
  // src/integration/ui/tui/views/phases/close-phase-view.tsx
2739
2781
  import { spawnSync } from "child_process";
2740
- import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo6, useState as useState12 } from "react";
2741
- import { Box as Box24, Text as Text23, useInput as useInput8 } from "ink";
2782
+ import { useCallback as useCallback7, useEffect as useEffect12, useMemo as useMemo7, useState as useState12 } from "react";
2783
+ import { Box as Box24, Text as Text23, useInput as useInput9 } from "ink";
2742
2784
  import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
2743
2785
  var HINTS_READY = [
2744
2786
  { key: "\u2191/\u2193", action: "select" },
@@ -2771,7 +2813,7 @@ function ClosePhaseView({ sprintId }) {
2771
2813
  useEffect12(() => {
2772
2814
  void load();
2773
2815
  }, [load]);
2774
- const actions = useMemo6(() => {
2816
+ const actions = useMemo7(() => {
2775
2817
  const sprint2 = state.sprint;
2776
2818
  if (sprint2?.status !== "active") return [];
2777
2819
  const base = ["close"];
@@ -2817,7 +2859,7 @@ function ClosePhaseView({ sprintId }) {
2817
2859
  },
2818
2860
  [sprintId, state.sprint]
2819
2861
  );
2820
- useInput8(
2862
+ useInput9(
2821
2863
  (_input, key) => {
2822
2864
  const { phase: phase2 } = state;
2823
2865
  if (phase2.kind === "done" || phase2.kind === "error") {
@@ -3016,11 +3058,11 @@ ID: ${sprintId}`
3016
3058
  }
3017
3059
 
3018
3060
  // src/integration/ui/tui/views/workflows/create-sprint-view.tsx
3019
- import { useMemo as useMemo7 } from "react";
3061
+ import { useMemo as useMemo8 } from "react";
3020
3062
 
3021
3063
  // src/integration/ui/tui/views/workflows/use-workflow.ts
3022
3064
  import { useCallback as useCallback8, useEffect as useEffect13, useState as useState13 } from "react";
3023
- import { useInput as useInput9 } from "ink";
3065
+ import { useInput as useInput10 } from "ink";
3024
3066
  var DEFAULT_NON_INTERACTIVE = /* @__PURE__ */ new Set(["running", "loading"]);
3025
3067
  function defaultIsTerminal(phase) {
3026
3068
  return !DEFAULT_NON_INTERACTIVE.has(phase.kind);
@@ -3032,7 +3074,7 @@ function useWorkflow(options) {
3032
3074
  const router = useRouter();
3033
3075
  const [phase, setPhase] = useState13(options.initial);
3034
3076
  const [started, setStarted] = useState13(false);
3035
- const isTerminal = options.isTerminal ?? defaultIsTerminal;
3077
+ const isTerminal2 = options.isTerminal ?? defaultIsTerminal;
3036
3078
  const isInteractive = options.isInteractive ?? defaultIsInteractive;
3037
3079
  const kick = useCallback8(async () => {
3038
3080
  try {
@@ -3050,9 +3092,9 @@ function useWorkflow(options) {
3050
3092
  setStarted(true);
3051
3093
  void kick();
3052
3094
  }, [started, kick]);
3053
- useInput9(
3095
+ useInput10(
3054
3096
  (_input, key) => {
3055
- if (key.return && isTerminal(phase)) router.pop();
3097
+ if (key.return && isTerminal2(phase)) router.pop();
3056
3098
  },
3057
3099
  { isActive: isInteractive(phase) }
3058
3100
  );
@@ -3110,7 +3152,7 @@ function CreateSprintView() {
3110
3152
  setPhase({ kind: "done", sprint, project, setAsCurrent });
3111
3153
  }
3112
3154
  });
3113
- const hints = useMemo7(() => phase.kind === "running" ? HINTS_RUNNING : HINTS_DONE, [phase.kind]);
3155
+ const hints = useMemo8(() => phase.kind === "running" ? HINTS_RUNNING : HINTS_DONE, [phase.kind]);
3114
3156
  useViewHints(hints);
3115
3157
  return /* @__PURE__ */ jsx26(ViewShell, { title: TITLE, children: renderBody(phase) });
3116
3158
  }
@@ -3152,84 +3194,154 @@ function renderBody(phase) {
3152
3194
  }
3153
3195
 
3154
3196
  // src/integration/ui/tui/views/workflows/delete-sprint-view.tsx
3155
- import { useMemo as useMemo8 } from "react";
3197
+ import { useEffect as useEffect15, useState as useState15 } from "react";
3198
+
3199
+ // src/integration/ui/tui/components/removal-workflow.tsx
3200
+ import { useEffect as useEffect14, useMemo as useMemo9, useState as useState14 } from "react";
3201
+ import { useInput as useInput11 } from "ink";
3156
3202
  import { jsx as jsx27 } from "react/jsx-runtime";
3157
- var TITLE2 = "Delete Sprint";
3158
3203
  var HINTS_RUNNING2 = [{ key: "Esc", action: "cancel" }];
3159
3204
  var HINTS_DONE2 = [
3160
- { key: "Enter", action: "home" },
3205
+ { key: "Enter", action: "back" },
3161
3206
  { key: "Esc", action: "back" }
3162
3207
  ];
3163
- function DeleteSprintView({ sprintId: initial2 }) {
3164
- const { phase } = useWorkflow({
3165
- initial: { kind: "loading" },
3166
- onError: (message) => ({ kind: "error", message }),
3167
- run: async ({ setPhase }) => {
3168
- const prompt = getPrompt();
3169
- let targetId = initial2 ?? null;
3170
- if (!targetId) {
3171
- const sprints = await listSprints();
3172
- if (sprints.length === 0) {
3173
- setPhase({ kind: "no-sprints" });
3174
- return;
3175
- }
3176
- setPhase({ kind: "running", step: "select" });
3177
- targetId = await prompt.select({
3178
- message: "Select sprint to delete:",
3179
- choices: sprints.map((s) => ({
3180
- label: `${s.id} \u2014 ${s.name} (${s.status})`,
3181
- value: s.id
3182
- }))
3183
- });
3184
- }
3185
- const sprint = await getSprint(targetId);
3186
- if (sprint.status === "active") {
3187
- setPhase({ kind: "active-blocked", name: sprint.name });
3188
- return;
3208
+ function RemovalWorkflow({
3209
+ entityLabel,
3210
+ confirmMessage,
3211
+ onConfirm,
3212
+ successMessage,
3213
+ onDone
3214
+ }) {
3215
+ const [phase, setPhase] = useState14({ kind: "idle" });
3216
+ const [started, setStarted] = useState14(false);
3217
+ useEffect14(() => {
3218
+ if (started) return;
3219
+ setStarted(true);
3220
+ void (async () => {
3221
+ try {
3222
+ setPhase({ kind: "confirming" });
3223
+ const confirmed = await getPrompt().confirm({ message: confirmMessage, default: false });
3224
+ if (!confirmed) {
3225
+ setPhase({ kind: "done", outcome: "cancelled" });
3226
+ return;
3227
+ }
3228
+ setPhase({ kind: "running" });
3229
+ await onConfirm();
3230
+ setPhase({ kind: "done", outcome: "success" });
3231
+ } catch (err) {
3232
+ if (err instanceof PromptCancelledError) {
3233
+ onDone();
3234
+ return;
3235
+ }
3236
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
3189
3237
  }
3190
- const tasks = await listTasks(targetId).catch(() => []);
3191
- setPhase({ kind: "running", step: "confirm" });
3192
- const confirmed = await prompt.confirm({
3193
- message: `Delete "${sprint.name}" (${String(sprint.tickets.length)} tickets, ${String(tasks.length)} tasks)? This cannot be undone.`,
3194
- default: false
3195
- });
3196
- if (!confirmed) {
3197
- setPhase({ kind: "cancelled" });
3198
- return;
3238
+ })();
3239
+ }, [started, confirmMessage, onConfirm, onDone]);
3240
+ const terminal = phase.kind === "done" || phase.kind === "error";
3241
+ const hints = useMemo9(() => terminal ? HINTS_DONE2 : HINTS_RUNNING2, [terminal]);
3242
+ useViewHints(hints);
3243
+ useInput11(
3244
+ (_input, key) => {
3245
+ if (key.return && terminal) onDone();
3246
+ },
3247
+ { isActive: terminal }
3248
+ );
3249
+ return /* @__PURE__ */ jsx27(ViewShell, { title: entityLabel, children: renderBody2(phase, successMessage, entityLabel) });
3250
+ }
3251
+ function renderBody2(phase, successMessage, entityLabel) {
3252
+ switch (phase.kind) {
3253
+ case "idle":
3254
+ case "confirming":
3255
+ return /* @__PURE__ */ jsx27(Spinner, { label: "Awaiting confirmation\u2026" });
3256
+ case "running":
3257
+ return /* @__PURE__ */ jsx27(Spinner, { label: `${entityLabel}\u2026` });
3258
+ case "done":
3259
+ return phase.outcome === "success" ? /* @__PURE__ */ jsx27(ResultCard, { kind: "success", title: successMessage }) : /* @__PURE__ */ jsx27(ResultCard, { kind: "info", title: "Removal cancelled" });
3260
+ case "error":
3261
+ return /* @__PURE__ */ jsx27(ResultCard, { kind: "error", title: `Could not complete ${entityLabel}`, lines: [phase.message] });
3262
+ }
3263
+ }
3264
+
3265
+ // src/integration/ui/tui/views/workflows/delete-sprint-view.tsx
3266
+ import { jsx as jsx28 } from "react/jsx-runtime";
3267
+ var TITLE2 = "Delete Sprint";
3268
+ function DeleteSprintView({ sprintId: initial2 }) {
3269
+ const router = useRouter();
3270
+ const [phase, setPhase] = useState15({ kind: "loading" });
3271
+ const [started, setStarted] = useState15(false);
3272
+ useEffect15(() => {
3273
+ if (started) return;
3274
+ setStarted(true);
3275
+ void (async () => {
3276
+ try {
3277
+ const prompt = getPrompt();
3278
+ let targetId = initial2 ?? null;
3279
+ if (!targetId) {
3280
+ const sprints = await listSprints();
3281
+ if (sprints.length === 0) {
3282
+ setPhase({ kind: "no-sprints" });
3283
+ return;
3284
+ }
3285
+ setPhase({ kind: "selecting" });
3286
+ targetId = await prompt.select({
3287
+ message: "Select sprint to delete:",
3288
+ choices: sprints.map((s) => ({
3289
+ label: `${s.id} \u2014 ${s.name} (${s.status})`,
3290
+ value: s.id
3291
+ }))
3292
+ });
3293
+ }
3294
+ const sprint = await getSprint(targetId);
3295
+ if (sprint.status === "active") {
3296
+ setPhase({ kind: "active-blocked", name: sprint.name });
3297
+ return;
3298
+ }
3299
+ const tasks = await listTasks(targetId).catch(() => []);
3300
+ setPhase({ kind: "ready", sprint, taskCount: tasks.length });
3301
+ } catch (err) {
3302
+ if (err instanceof PromptCancelledError) {
3303
+ router.pop();
3304
+ return;
3305
+ }
3306
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
3199
3307
  }
3200
- const reconfirmed = await prompt.confirm({
3201
- message: `Really delete "${sprint.name}"? All sprint data (tickets, tasks, progress, evaluations) will be removed.`,
3202
- default: false
3203
- });
3204
- if (!reconfirmed) {
3205
- setPhase({ kind: "cancelled" });
3206
- return;
3308
+ })();
3309
+ }, [started, initial2, router]);
3310
+ if (phase.kind === "ready") {
3311
+ const { sprint, taskCount } = phase;
3312
+ const ticketCount = sprint.tickets.length;
3313
+ const confirmMessage = `Delete "${sprint.name}" (${String(ticketCount)} ${pluralize2("ticket", ticketCount)}, ${String(
3314
+ taskCount
3315
+ )} ${pluralize2("task", taskCount)})? All sprint data \u2014 tickets, tasks, progress, evaluations \u2014 will be removed. This cannot be undone.`;
3316
+ return /* @__PURE__ */ jsx28(
3317
+ RemovalWorkflow,
3318
+ {
3319
+ entityLabel: TITLE2,
3320
+ confirmMessage,
3321
+ onConfirm: async () => {
3322
+ const currentId = await getCurrentSprint();
3323
+ await deleteSprint(sprint.id);
3324
+ if (currentId === sprint.id) await setCurrentSprint(null);
3325
+ },
3326
+ successMessage: `Sprint "${sprint.name}" deleted`,
3327
+ onDone: () => {
3328
+ router.pop();
3329
+ }
3207
3330
  }
3208
- setPhase({ kind: "running", step: "deleting" });
3209
- const currentId = await getCurrentSprint();
3210
- await deleteSprint(targetId);
3211
- const clearedCurrent = currentId === targetId;
3212
- if (clearedCurrent) await setCurrentSprint(null);
3213
- setPhase({ kind: "done", name: sprint.name, id: sprint.id, clearedCurrent });
3214
- }
3215
- });
3216
- const running = phase.kind === "running" || phase.kind === "loading";
3217
- const hints = useMemo8(() => running ? HINTS_RUNNING2 : HINTS_DONE2, [running]);
3218
- useViewHints(hints);
3219
- return /* @__PURE__ */ jsx27(ViewShell, { title: TITLE2, children: renderBody2(phase) });
3331
+ );
3332
+ }
3333
+ return /* @__PURE__ */ jsx28(ViewShell, { title: TITLE2, children: renderPre(phase) });
3220
3334
  }
3221
- function renderBody2(phase) {
3335
+ function renderPre(phase) {
3222
3336
  switch (phase.kind) {
3223
3337
  case "loading":
3224
- return /* @__PURE__ */ jsx27(Spinner, { label: "Loading sprints\u2026" });
3338
+ return /* @__PURE__ */ jsx28(Spinner, { label: "Loading sprints\u2026" });
3339
+ case "selecting":
3340
+ return /* @__PURE__ */ jsx28(Spinner, { label: "Awaiting selection\u2026" });
3225
3341
  case "no-sprints":
3226
- return /* @__PURE__ */ jsx27(ResultCard, { kind: "info", title: "No sprints to delete" });
3227
- case "running":
3228
- return /* @__PURE__ */ jsx27(Spinner, { label: runningLabel(phase.step) });
3229
- case "cancelled":
3230
- return /* @__PURE__ */ jsx27(ResultCard, { kind: "info", title: "Deletion cancelled" });
3342
+ return /* @__PURE__ */ jsx28(ResultCard, { kind: "info", title: "No sprints to delete" });
3231
3343
  case "active-blocked":
3232
- return /* @__PURE__ */ jsx27(
3344
+ return /* @__PURE__ */ jsx28(
3233
3345
  ResultCard,
3234
3346
  {
3235
3347
  kind: "warning",
@@ -3238,31 +3350,16 @@ function renderBody2(phase) {
3238
3350
  }
3239
3351
  );
3240
3352
  case "error":
3241
- return /* @__PURE__ */ jsx27(ResultCard, { kind: "error", title: "Could not delete sprint", lines: [phase.message] });
3242
- case "done":
3243
- return /* @__PURE__ */ jsx27(
3244
- ResultCard,
3245
- {
3246
- kind: "success",
3247
- title: "Sprint deleted",
3248
- fields: [
3249
- ["Name", phase.name],
3250
- ["ID", phase.id]
3251
- ],
3252
- lines: phase.clearedCurrent ? ["Current sprint pointer was cleared."] : void 0
3253
- }
3254
- );
3353
+ return /* @__PURE__ */ jsx28(ResultCard, { kind: "error", title: "Could not delete sprint", lines: [phase.message] });
3255
3354
  }
3256
3355
  }
3257
- function runningLabel(step) {
3258
- if (step === "select") return "Awaiting selection\u2026";
3259
- if (step === "confirm") return "Awaiting confirmation\u2026";
3260
- return "Deleting sprint\u2026";
3356
+ function pluralize2(noun, count) {
3357
+ return count === 1 ? noun : `${noun}s`;
3261
3358
  }
3262
3359
 
3263
3360
  // src/integration/ui/tui/views/workflows/set-current-sprint-view.tsx
3264
- import { useMemo as useMemo9 } from "react";
3265
- import { jsx as jsx28 } from "react/jsx-runtime";
3361
+ import { useMemo as useMemo10 } from "react";
3362
+ import { jsx as jsx29 } from "react/jsx-runtime";
3266
3363
  var TITLE3 = "Set Current Sprint";
3267
3364
  var HINTS_RUNNING3 = [{ key: "Esc", action: "cancel" }];
3268
3365
  var HINTS_DONE3 = [
@@ -3294,18 +3391,18 @@ function SetCurrentSprintView() {
3294
3391
  }
3295
3392
  });
3296
3393
  const running = phase.kind === "loading" || phase.kind === "running";
3297
- const hints = useMemo9(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
3394
+ const hints = useMemo10(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
3298
3395
  useViewHints(hints);
3299
- return /* @__PURE__ */ jsx28(ViewShell, { title: TITLE3, children: renderBody3(phase) });
3396
+ return /* @__PURE__ */ jsx29(ViewShell, { title: TITLE3, children: renderBody3(phase) });
3300
3397
  }
3301
3398
  function renderBody3(phase) {
3302
3399
  switch (phase.kind) {
3303
3400
  case "loading":
3304
- return /* @__PURE__ */ jsx28(Spinner, { label: "Loading sprints\u2026" });
3401
+ return /* @__PURE__ */ jsx29(Spinner, { label: "Loading sprints\u2026" });
3305
3402
  case "running":
3306
- return /* @__PURE__ */ jsx28(Spinner, { label: "Awaiting sprint selection\u2026" });
3403
+ return /* @__PURE__ */ jsx29(Spinner, { label: "Awaiting sprint selection\u2026" });
3307
3404
  case "no-candidates":
3308
- return /* @__PURE__ */ jsx28(
3405
+ return /* @__PURE__ */ jsx29(
3309
3406
  ResultCard,
3310
3407
  {
3311
3408
  kind: "info",
@@ -3314,9 +3411,9 @@ function renderBody3(phase) {
3314
3411
  }
3315
3412
  );
3316
3413
  case "error":
3317
- return /* @__PURE__ */ jsx28(ResultCard, { kind: "error", title: "Could not set current sprint", lines: [phase.message] });
3414
+ return /* @__PURE__ */ jsx29(ResultCard, { kind: "error", title: "Could not set current sprint", lines: [phase.message] });
3318
3415
  case "done":
3319
- return /* @__PURE__ */ jsx28(
3416
+ return /* @__PURE__ */ jsx29(
3320
3417
  ResultCard,
3321
3418
  {
3322
3419
  kind: "success",
@@ -3332,8 +3429,8 @@ function renderBody3(phase) {
3332
3429
 
3333
3430
  // src/integration/ui/tui/views/workflows/requirements-export-view.tsx
3334
3431
  import { join } from "path";
3335
- import { useMemo as useMemo10 } from "react";
3336
- import { jsx as jsx29 } from "react/jsx-runtime";
3432
+ import { useMemo as useMemo11 } from "react";
3433
+ import { jsx as jsx30 } from "react/jsx-runtime";
3337
3434
  var TITLE4 = "Export Requirements";
3338
3435
  var HINTS_RUNNING4 = [{ key: "Esc", action: "cancel" }];
3339
3436
  var HINTS_DONE4 = [
@@ -3367,16 +3464,16 @@ function RequirementsExportView({ sprintId }) {
3367
3464
  });
3368
3465
  }
3369
3466
  });
3370
- const hints = useMemo10(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
3467
+ const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
3371
3468
  useViewHints(hints);
3372
- return /* @__PURE__ */ jsx29(ViewShell, { title: TITLE4, children: renderBody4(phase) });
3469
+ return /* @__PURE__ */ jsx30(ViewShell, { title: TITLE4, children: renderBody4(phase) });
3373
3470
  }
3374
3471
  function renderBody4(phase) {
3375
3472
  switch (phase.kind) {
3376
3473
  case "running":
3377
- return /* @__PURE__ */ jsx29(Spinner, { label: "Writing requirements.md\u2026" });
3474
+ return /* @__PURE__ */ jsx30(Spinner, { label: "Writing requirements.md\u2026" });
3378
3475
  case "empty":
3379
- return /* @__PURE__ */ jsx29(
3476
+ return /* @__PURE__ */ jsx30(
3380
3477
  ResultCard,
3381
3478
  {
3382
3479
  kind: "warning",
@@ -3385,7 +3482,7 @@ function renderBody4(phase) {
3385
3482
  }
3386
3483
  );
3387
3484
  case "no-approved":
3388
- return /* @__PURE__ */ jsx29(
3485
+ return /* @__PURE__ */ jsx30(
3389
3486
  ResultCard,
3390
3487
  {
3391
3488
  kind: "warning",
@@ -3394,9 +3491,9 @@ function renderBody4(phase) {
3394
3491
  }
3395
3492
  );
3396
3493
  case "error":
3397
- return /* @__PURE__ */ jsx29(ResultCard, { kind: "error", title: "Could not export", lines: [phase.message] });
3494
+ return /* @__PURE__ */ jsx30(ResultCard, { kind: "error", title: "Could not export", lines: [phase.message] });
3398
3495
  case "done":
3399
- return /* @__PURE__ */ jsx29(
3496
+ return /* @__PURE__ */ jsx30(
3400
3497
  ResultCard,
3401
3498
  {
3402
3499
  kind: "success",
@@ -3414,8 +3511,8 @@ function renderBody4(phase) {
3414
3511
  // src/integration/ui/tui/views/workflows/context-export-view.tsx
3415
3512
  import { writeFile } from "fs/promises";
3416
3513
  import { join as join2 } from "path";
3417
- import { useMemo as useMemo11 } from "react";
3418
- import { jsx as jsx30 } from "react/jsx-runtime";
3514
+ import { useMemo as useMemo12 } from "react";
3515
+ import { jsx as jsx31 } from "react/jsx-runtime";
3419
3516
  var TITLE5 = "Export Context";
3420
3517
  var HINTS_RUNNING5 = [{ key: "Esc", action: "cancel" }];
3421
3518
  var HINTS_DONE5 = [
@@ -3444,18 +3541,18 @@ function ContextExportView({ sprintId }) {
3444
3541
  });
3445
3542
  }
3446
3543
  });
3447
- const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
3544
+ const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
3448
3545
  useViewHints(hints);
3449
- return /* @__PURE__ */ jsx30(ViewShell, { title: TITLE5, children: renderBody5(phase) });
3546
+ return /* @__PURE__ */ jsx31(ViewShell, { title: TITLE5, children: renderBody5(phase) });
3450
3547
  }
3451
3548
  function renderBody5(phase) {
3452
3549
  switch (phase.kind) {
3453
3550
  case "running":
3454
- return /* @__PURE__ */ jsx30(Spinner, { label: "Writing context.md\u2026" });
3551
+ return /* @__PURE__ */ jsx31(Spinner, { label: "Writing context.md\u2026" });
3455
3552
  case "error":
3456
- return /* @__PURE__ */ jsx30(ResultCard, { kind: "error", title: "Could not export context", lines: [phase.message] });
3553
+ return /* @__PURE__ */ jsx31(ResultCard, { kind: "error", title: "Could not export context", lines: [phase.message] });
3457
3554
  case "done":
3458
- return /* @__PURE__ */ jsx30(
3555
+ return /* @__PURE__ */ jsx31(
3459
3556
  ResultCard,
3460
3557
  {
3461
3558
  kind: "success",
@@ -3544,8 +3641,8 @@ async function renderContextMarkdown(sprint, tasks) {
3544
3641
  }
3545
3642
 
3546
3643
  // src/integration/ui/tui/views/workflows/ticket-add-view.tsx
3547
- import { useMemo as useMemo12 } from "react";
3548
- import { jsx as jsx31 } from "react/jsx-runtime";
3644
+ import { useMemo as useMemo13 } from "react";
3645
+ import { jsx as jsx32 } from "react/jsx-runtime";
3549
3646
  var TITLE6 = "Add Ticket";
3550
3647
  var HINTS_RUNNING6 = [{ key: "Esc", action: "cancel" }];
3551
3648
  var HINTS_DONE6 = [
@@ -3641,16 +3738,16 @@ function TicketAddView() {
3641
3738
  }
3642
3739
  }
3643
3740
  });
3644
- const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
3741
+ const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
3645
3742
  useViewHints(hints);
3646
- return /* @__PURE__ */ jsx31(ViewShell, { title: TITLE6, children: renderBody6(phase) });
3743
+ return /* @__PURE__ */ jsx32(ViewShell, { title: TITLE6, children: renderBody6(phase) });
3647
3744
  }
3648
3745
  function renderBody6(phase) {
3649
3746
  switch (phase.kind) {
3650
3747
  case "running":
3651
- return /* @__PURE__ */ jsx31(Spinner, { label: STEP_LABEL[phase.step] });
3748
+ return /* @__PURE__ */ jsx32(Spinner, { label: STEP_LABEL[phase.step] });
3652
3749
  case "no-draft-sprint":
3653
- return /* @__PURE__ */ jsx31(
3750
+ return /* @__PURE__ */ jsx32(
3654
3751
  ResultCard,
3655
3752
  {
3656
3753
  kind: "warning",
@@ -3660,7 +3757,7 @@ function renderBody6(phase) {
3660
3757
  }
3661
3758
  );
3662
3759
  case "no-project":
3663
- return /* @__PURE__ */ jsx31(
3760
+ return /* @__PURE__ */ jsx32(
3664
3761
  ResultCard,
3665
3762
  {
3666
3763
  kind: "warning",
@@ -3669,10 +3766,10 @@ function renderBody6(phase) {
3669
3766
  }
3670
3767
  );
3671
3768
  case "error":
3672
- return /* @__PURE__ */ jsx31(ResultCard, { kind: "error", title: "Could not add ticket", lines: [phase.message] });
3769
+ return /* @__PURE__ */ jsx32(ResultCard, { kind: "error", title: "Could not add ticket", lines: [phase.message] });
3673
3770
  case "done": {
3674
3771
  const title = phase.count > 1 ? `${String(phase.count)} tickets added` : phase.prefilled ? "Ticket added (prefilled from issue)" : "Ticket added";
3675
- return /* @__PURE__ */ jsx31(
3772
+ return /* @__PURE__ */ jsx32(
3676
3773
  ResultCard,
3677
3774
  {
3678
3775
  kind: "success",
@@ -3691,8 +3788,8 @@ function renderBody6(phase) {
3691
3788
  }
3692
3789
 
3693
3790
  // src/integration/ui/tui/views/workflows/ticket-edit-view.tsx
3694
- import { useMemo as useMemo13 } from "react";
3695
- import { jsx as jsx32 } from "react/jsx-runtime";
3791
+ import { useMemo as useMemo14 } from "react";
3792
+ import { jsx as jsx33 } from "react/jsx-runtime";
3696
3793
  var TITLE7 = "Edit Ticket";
3697
3794
  var HINTS_RUNNING7 = [{ key: "Esc", action: "cancel" }];
3698
3795
  var HINTS_DONE7 = [
@@ -3766,18 +3863,18 @@ function TicketEditView({ ticketId } = {}) {
3766
3863
  setPhase({ kind: "done", ticket, field });
3767
3864
  }
3768
3865
  });
3769
- const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
3866
+ const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
3770
3867
  useViewHints(hints);
3771
- return /* @__PURE__ */ jsx32(ViewShell, { title: TITLE7, children: renderBody7(phase) });
3868
+ return /* @__PURE__ */ jsx33(ViewShell, { title: TITLE7, children: renderBody7(phase) });
3772
3869
  }
3773
3870
  function renderBody7(phase) {
3774
3871
  switch (phase.kind) {
3775
3872
  case "running":
3776
- return /* @__PURE__ */ jsx32(Spinner, { label: stepLabel(phase.step) });
3873
+ return /* @__PURE__ */ jsx33(Spinner, { label: stepLabel(phase.step) });
3777
3874
  case "no-tickets":
3778
- return /* @__PURE__ */ jsx32(ResultCard, { kind: "info", title: "No tickets to edit" });
3875
+ return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "No tickets to edit" });
3779
3876
  case "no-draft-sprint":
3780
- return /* @__PURE__ */ jsx32(
3877
+ return /* @__PURE__ */ jsx33(
3781
3878
  ResultCard,
3782
3879
  {
3783
3880
  kind: "warning",
@@ -3786,9 +3883,9 @@ function renderBody7(phase) {
3786
3883
  }
3787
3884
  );
3788
3885
  case "error":
3789
- return /* @__PURE__ */ jsx32(ResultCard, { kind: "error", title: "Could not edit ticket", lines: [phase.message] });
3886
+ return /* @__PURE__ */ jsx33(ResultCard, { kind: "error", title: "Could not edit ticket", lines: [phase.message] });
3790
3887
  case "done":
3791
- return /* @__PURE__ */ jsx32(
3888
+ return /* @__PURE__ */ jsx33(
3792
3889
  ResultCard,
3793
3890
  {
3794
3891
  kind: "success",
@@ -3815,97 +3912,86 @@ function stepLabel(step) {
3815
3912
  }
3816
3913
 
3817
3914
  // src/integration/ui/tui/views/workflows/ticket-remove-view.tsx
3818
- import { useMemo as useMemo14 } from "react";
3819
- import { jsx as jsx33 } from "react/jsx-runtime";
3915
+ import { useEffect as useEffect16, useState as useState16 } from "react";
3916
+ import { jsx as jsx34 } from "react/jsx-runtime";
3820
3917
  var TITLE8 = "Remove Ticket";
3821
- var HINTS_RUNNING8 = [{ key: "Esc", action: "cancel" }];
3822
- var HINTS_DONE8 = [
3823
- { key: "Enter", action: "home" },
3824
- { key: "Esc", action: "back" }
3825
- ];
3826
3918
  function TicketRemoveView() {
3827
- const { phase } = useWorkflow({
3828
- initial: { kind: "running", step: "select" },
3829
- onError: (message) => ({ kind: "error", message }),
3830
- run: async ({ setPhase }) => {
3831
- const prompt = getPrompt();
3832
- const sprint = await getCurrentSprintOrThrow();
3833
- if (sprint.status !== "draft") {
3834
- setPhase({ kind: "no-draft-sprint" });
3835
- return;
3836
- }
3837
- const tickets = await listTickets();
3838
- if (tickets.length === 0) {
3839
- setPhase({ kind: "no-tickets" });
3840
- return;
3919
+ const router = useRouter();
3920
+ const [phase, setPhase] = useState16({ kind: "loading" });
3921
+ const [started, setStarted] = useState16(false);
3922
+ useEffect16(() => {
3923
+ if (started) return;
3924
+ setStarted(true);
3925
+ void (async () => {
3926
+ try {
3927
+ const sprint = await getCurrentSprintOrThrow();
3928
+ if (sprint.status !== "draft") {
3929
+ setPhase({ kind: "no-draft-sprint" });
3930
+ return;
3931
+ }
3932
+ const tickets = await listTickets();
3933
+ if (tickets.length === 0) {
3934
+ setPhase({ kind: "no-tickets" });
3935
+ return;
3936
+ }
3937
+ setPhase({ kind: "selecting" });
3938
+ const ticketId = await getPrompt().select({
3939
+ message: "Select ticket to remove:",
3940
+ choices: tickets.map((t) => ({
3941
+ label: `${t.id} \u2014 ${t.title}`,
3942
+ value: t.id,
3943
+ description: t.requirementStatus
3944
+ }))
3945
+ });
3946
+ const target = tickets.find((t) => t.id === ticketId);
3947
+ if (!target) throw new Error(`Ticket ${ticketId} disappeared`);
3948
+ setPhase({ kind: "ready", ticketId: target.id, ticketTitle: target.title });
3949
+ } catch (err) {
3950
+ if (err instanceof PromptCancelledError) {
3951
+ router.pop();
3952
+ return;
3953
+ }
3954
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
3841
3955
  }
3842
- setPhase({ kind: "running", step: "select" });
3843
- const ticketId = await prompt.select({
3844
- message: "Select ticket to remove:",
3845
- choices: tickets.map((t) => ({
3846
- label: `${t.id} \u2014 ${t.title}`,
3847
- value: t.id,
3848
- description: t.requirementStatus
3849
- }))
3850
- });
3851
- const target = tickets.find((t) => t.id === ticketId);
3852
- if (!target) throw new Error(`Ticket ${ticketId} disappeared`);
3853
- setPhase({ kind: "running", step: "confirm" });
3854
- const ok = await prompt.confirm({
3855
- message: `Remove ticket "${target.title}"? This cannot be undone.`,
3856
- default: false
3857
- });
3858
- if (!ok) {
3859
- setPhase({ kind: "cancelled" });
3860
- return;
3956
+ })();
3957
+ }, [started, router]);
3958
+ if (phase.kind === "ready") {
3959
+ return /* @__PURE__ */ jsx34(
3960
+ RemovalWorkflow,
3961
+ {
3962
+ entityLabel: TITLE8,
3963
+ confirmMessage: `Remove ticket "${phase.ticketTitle}"? This cannot be undone.`,
3964
+ onConfirm: () => removeTicket(phase.ticketId),
3965
+ successMessage: `Ticket "${phase.ticketTitle}" removed`,
3966
+ onDone: () => {
3967
+ router.pop();
3968
+ }
3861
3969
  }
3862
- setPhase({ kind: "running", step: "removing" });
3863
- await removeTicket(ticketId);
3864
- setPhase({ kind: "done", id: target.id, title: target.title });
3865
- }
3866
- });
3867
- const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
3868
- useViewHints(hints);
3869
- return /* @__PURE__ */ jsx33(ViewShell, { title: TITLE8, children: renderBody8(phase) });
3970
+ );
3971
+ }
3972
+ return /* @__PURE__ */ jsx34(ViewShell, { title: TITLE8, children: renderPre2(phase) });
3870
3973
  }
3871
- function renderBody8(phase) {
3974
+ function renderPre2(phase) {
3872
3975
  switch (phase.kind) {
3873
- case "running":
3874
- return /* @__PURE__ */ jsx33(Spinner, { label: stepLabel2(phase.step) });
3976
+ case "loading":
3977
+ return /* @__PURE__ */ jsx34(Spinner, { label: "Loading tickets\u2026" });
3978
+ case "selecting":
3979
+ return /* @__PURE__ */ jsx34(Spinner, { label: "Awaiting ticket selection\u2026" });
3875
3980
  case "no-tickets":
3876
- return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "No tickets to remove" });
3981
+ return /* @__PURE__ */ jsx34(ResultCard, { kind: "info", title: "No tickets to remove" });
3877
3982
  case "no-draft-sprint":
3878
- return /* @__PURE__ */ jsx33(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
3879
- case "cancelled":
3880
- return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "Removal cancelled" });
3983
+ return /* @__PURE__ */ jsx34(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
3881
3984
  case "error":
3882
- return /* @__PURE__ */ jsx33(ResultCard, { kind: "error", title: "Could not remove ticket", lines: [phase.message] });
3883
- case "done":
3884
- return /* @__PURE__ */ jsx33(
3885
- ResultCard,
3886
- {
3887
- kind: "success",
3888
- title: "Ticket removed",
3889
- fields: [
3890
- ["ID", phase.id],
3891
- ["Title", phase.title]
3892
- ]
3893
- }
3894
- );
3985
+ return /* @__PURE__ */ jsx34(ResultCard, { kind: "error", title: "Could not remove ticket", lines: [phase.message] });
3895
3986
  }
3896
3987
  }
3897
- function stepLabel2(step) {
3898
- if (step === "select") return "Awaiting ticket selection\u2026";
3899
- if (step === "confirm") return "Awaiting confirmation\u2026";
3900
- return "Removing ticket\u2026";
3901
- }
3902
3988
 
3903
3989
  // src/integration/ui/tui/views/workflows/ticket-refine-view.tsx
3904
3990
  import { useMemo as useMemo15 } from "react";
3905
- import { jsx as jsx34 } from "react/jsx-runtime";
3991
+ import { jsx as jsx35 } from "react/jsx-runtime";
3906
3992
  var TITLE9 = "Re-Refine Ticket";
3907
- var HINTS_RUNNING9 = [{ key: "Esc", action: "cancel" }];
3908
- var HINTS_DONE9 = [
3993
+ var HINTS_RUNNING8 = [{ key: "Esc", action: "cancel" }];
3994
+ var HINTS_DONE8 = [
3909
3995
  { key: "Enter", action: "home" },
3910
3996
  { key: "Esc", action: "back" }
3911
3997
  ];
@@ -3937,18 +4023,18 @@ function TicketRefineView() {
3937
4023
  setPhase({ kind: "done", ticketTitle: target.title });
3938
4024
  }
3939
4025
  });
3940
- const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
4026
+ const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
3941
4027
  useViewHints(hints);
3942
- return /* @__PURE__ */ jsx34(ViewShell, { title: TITLE9, children: renderBody9(phase) });
4028
+ return /* @__PURE__ */ jsx35(ViewShell, { title: TITLE9, children: renderBody8(phase) });
3943
4029
  }
3944
- function renderBody9(phase) {
4030
+ function renderBody8(phase) {
3945
4031
  switch (phase.kind) {
3946
4032
  case "running":
3947
- return /* @__PURE__ */ jsx34(Spinner, { label: phase.step === "select" ? "Awaiting ticket selection\u2026" : "Running AI session\u2026" });
4033
+ return /* @__PURE__ */ jsx35(Spinner, { label: phase.step === "select" ? "Awaiting ticket selection\u2026" : "Running AI session\u2026" });
3948
4034
  case "no-draft-sprint":
3949
- return /* @__PURE__ */ jsx34(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4035
+ return /* @__PURE__ */ jsx35(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
3950
4036
  case "no-approved":
3951
- return /* @__PURE__ */ jsx34(
4037
+ return /* @__PURE__ */ jsx35(
3952
4038
  ResultCard,
3953
4039
  {
3954
4040
  kind: "warning",
@@ -3957,9 +4043,9 @@ function renderBody9(phase) {
3957
4043
  }
3958
4044
  );
3959
4045
  case "error":
3960
- return /* @__PURE__ */ jsx34(ResultCard, { kind: "error", title: "Re-refinement failed", lines: [phase.message] });
4046
+ return /* @__PURE__ */ jsx35(ResultCard, { kind: "error", title: "Re-refinement failed", lines: [phase.message] });
3961
4047
  case "done":
3962
- return /* @__PURE__ */ jsx34(
4048
+ return /* @__PURE__ */ jsx35(
3963
4049
  ResultCard,
3964
4050
  {
3965
4051
  kind: "success",
@@ -3973,10 +4059,10 @@ function renderBody9(phase) {
3973
4059
 
3974
4060
  // src/integration/ui/tui/views/workflows/task-add-view.tsx
3975
4061
  import { useMemo as useMemo16 } from "react";
3976
- import { jsx as jsx35 } from "react/jsx-runtime";
4062
+ import { jsx as jsx36 } from "react/jsx-runtime";
3977
4063
  var TITLE10 = "Add Task";
3978
- var HINTS_RUNNING10 = [{ key: "Esc", action: "cancel" }];
3979
- var HINTS_DONE10 = [
4064
+ var HINTS_RUNNING9 = [{ key: "Esc", action: "cancel" }];
4065
+ var HINTS_DONE9 = [
3980
4066
  { key: "Enter", action: "home" },
3981
4067
  { key: "Esc", action: "back" }
3982
4068
  ];
@@ -4039,22 +4125,22 @@ function TaskAddView() {
4039
4125
  setPhase({ kind: "done", task, repo });
4040
4126
  }
4041
4127
  });
4042
- const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
4128
+ const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
4043
4129
  useViewHints(hints);
4044
- return /* @__PURE__ */ jsx35(ViewShell, { title: TITLE10, children: renderBody10(phase) });
4130
+ return /* @__PURE__ */ jsx36(ViewShell, { title: TITLE10, children: renderBody9(phase) });
4045
4131
  }
4046
- function renderBody10(phase) {
4132
+ function renderBody9(phase) {
4047
4133
  switch (phase.kind) {
4048
4134
  case "running":
4049
- return /* @__PURE__ */ jsx35(Spinner, { label: stepLabel3(phase.step) });
4135
+ return /* @__PURE__ */ jsx36(Spinner, { label: stepLabel2(phase.step) });
4050
4136
  case "no-project":
4051
- return /* @__PURE__ */ jsx35(ResultCard, { kind: "warning", title: "Sprint's project is missing or has no repos" });
4137
+ return /* @__PURE__ */ jsx36(ResultCard, { kind: "warning", title: "Sprint's project is missing or has no repos" });
4052
4138
  case "no-draft-sprint":
4053
- return /* @__PURE__ */ jsx35(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4139
+ return /* @__PURE__ */ jsx36(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4054
4140
  case "error":
4055
- return /* @__PURE__ */ jsx35(ResultCard, { kind: "error", title: "Could not add task", lines: [phase.message] });
4141
+ return /* @__PURE__ */ jsx36(ResultCard, { kind: "error", title: "Could not add task", lines: [phase.message] });
4056
4142
  case "done":
4057
- return /* @__PURE__ */ jsx35(
4143
+ return /* @__PURE__ */ jsx36(
4058
4144
  ResultCard,
4059
4145
  {
4060
4146
  kind: "success",
@@ -4069,7 +4155,7 @@ function renderBody10(phase) {
4069
4155
  );
4070
4156
  }
4071
4157
  }
4072
- function stepLabel3(step) {
4158
+ function stepLabel2(step) {
4073
4159
  if (step === "repo") return "Awaiting repo selection\u2026";
4074
4160
  if (step === "name") return "Awaiting task name\u2026";
4075
4161
  if (step === "description") return "Awaiting description\u2026";
@@ -4078,10 +4164,10 @@ function stepLabel3(step) {
4078
4164
 
4079
4165
  // src/integration/ui/tui/views/workflows/task-import-view.tsx
4080
4166
  import { useMemo as useMemo17 } from "react";
4081
- import { jsx as jsx36 } from "react/jsx-runtime";
4167
+ import { jsx as jsx37 } from "react/jsx-runtime";
4082
4168
  var TITLE11 = "Import Tasks";
4083
- var HINTS_RUNNING11 = [{ key: "Esc", action: "cancel" }];
4084
- var HINTS_DONE11 = [
4169
+ var HINTS_RUNNING10 = [{ key: "Esc", action: "cancel" }];
4170
+ var HINTS_DONE10 = [
4085
4171
  { key: "Enter", action: "home" },
4086
4172
  { key: "Esc", action: "back" }
4087
4173
  ];
@@ -4101,29 +4187,29 @@ function TaskImportView() {
4101
4187
  setPhase({ kind: "done" });
4102
4188
  }
4103
4189
  });
4104
- const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
4190
+ const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
4105
4191
  useViewHints(hints);
4106
- return /* @__PURE__ */ jsx36(ViewShell, { title: TITLE11, children: renderBody11(phase) });
4192
+ return /* @__PURE__ */ jsx37(ViewShell, { title: TITLE11, children: renderBody10(phase) });
4107
4193
  }
4108
- function renderBody11(phase) {
4194
+ function renderBody10(phase) {
4109
4195
  switch (phase.kind) {
4110
4196
  case "running":
4111
- return /* @__PURE__ */ jsx36(Spinner, { label: phase.step === "path" ? "Awaiting JSON file path\u2026" : "Importing tasks\u2026" });
4197
+ return /* @__PURE__ */ jsx37(Spinner, { label: phase.step === "path" ? "Awaiting JSON file path\u2026" : "Importing tasks\u2026" });
4112
4198
  case "done":
4113
- return /* @__PURE__ */ jsx36(ResultCard, { kind: "success", title: "Import finished", lines: ["Check the task list to see the result."] });
4199
+ return /* @__PURE__ */ jsx37(ResultCard, { kind: "success", title: "Import finished", lines: ["Check the task list to see the result."] });
4114
4200
  case "cancelled":
4115
- return /* @__PURE__ */ jsx36(ResultCard, { kind: "info", title: "Import cancelled" });
4201
+ return /* @__PURE__ */ jsx37(ResultCard, { kind: "info", title: "Import cancelled" });
4116
4202
  case "error":
4117
- return /* @__PURE__ */ jsx36(ResultCard, { kind: "error", title: "Import failed", lines: [phase.message] });
4203
+ return /* @__PURE__ */ jsx37(ResultCard, { kind: "error", title: "Import failed", lines: [phase.message] });
4118
4204
  }
4119
4205
  }
4120
4206
 
4121
4207
  // src/integration/ui/tui/views/workflows/task-status-view.tsx
4122
4208
  import { useMemo as useMemo18 } from "react";
4123
- import { jsx as jsx37 } from "react/jsx-runtime";
4209
+ import { jsx as jsx38 } from "react/jsx-runtime";
4124
4210
  var TITLE12 = "Task Status";
4125
- var HINTS_RUNNING12 = [{ key: "Esc", action: "cancel" }];
4126
- var HINTS_DONE12 = [
4211
+ var HINTS_RUNNING11 = [{ key: "Esc", action: "cancel" }];
4212
+ var HINTS_DONE11 = [
4127
4213
  { key: "Enter", action: "home" },
4128
4214
  { key: "Esc", action: "back" }
4129
4215
  ];
@@ -4166,18 +4252,18 @@ function TaskStatusView() {
4166
4252
  setPhase({ kind: "done", task });
4167
4253
  }
4168
4254
  });
4169
- const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
4255
+ const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
4170
4256
  useViewHints(hints);
4171
- return /* @__PURE__ */ jsx37(ViewShell, { title: TITLE12, children: renderBody12(phase) });
4257
+ return /* @__PURE__ */ jsx38(ViewShell, { title: TITLE12, children: renderBody11(phase) });
4172
4258
  }
4173
- function renderBody12(phase) {
4259
+ function renderBody11(phase) {
4174
4260
  switch (phase.kind) {
4175
4261
  case "running":
4176
- return /* @__PURE__ */ jsx37(Spinner, { label: stepLabel4(phase.step) });
4262
+ return /* @__PURE__ */ jsx38(Spinner, { label: stepLabel3(phase.step) });
4177
4263
  case "no-tasks":
4178
- return /* @__PURE__ */ jsx37(ResultCard, { kind: "info", title: "No tasks in this sprint" });
4264
+ return /* @__PURE__ */ jsx38(ResultCard, { kind: "info", title: "No tasks in this sprint" });
4179
4265
  case "not-active":
4180
- return /* @__PURE__ */ jsx37(
4266
+ return /* @__PURE__ */ jsx38(
4181
4267
  ResultCard,
4182
4268
  {
4183
4269
  kind: "warning",
@@ -4186,9 +4272,9 @@ function renderBody12(phase) {
4186
4272
  }
4187
4273
  );
4188
4274
  case "error":
4189
- return /* @__PURE__ */ jsx37(ResultCard, { kind: "error", title: "Could not update status", lines: [phase.message] });
4275
+ return /* @__PURE__ */ jsx38(ResultCard, { kind: "error", title: "Could not update status", lines: [phase.message] });
4190
4276
  case "done":
4191
- return /* @__PURE__ */ jsx37(
4277
+ return /* @__PURE__ */ jsx38(
4192
4278
  ResultCard,
4193
4279
  {
4194
4280
  kind: "success",
@@ -4201,7 +4287,7 @@ function renderBody12(phase) {
4201
4287
  );
4202
4288
  }
4203
4289
  }
4204
- function stepLabel4(step) {
4290
+ function stepLabel3(step) {
4205
4291
  if (step === "select-task") return "Awaiting task selection\u2026";
4206
4292
  if (step === "select-status") return "Awaiting status selection\u2026";
4207
4293
  return "Saving task\u2026";
@@ -4209,10 +4295,10 @@ function stepLabel4(step) {
4209
4295
 
4210
4296
  // src/integration/ui/tui/views/workflows/task-reorder-view.tsx
4211
4297
  import { useMemo as useMemo19 } from "react";
4212
- import { jsx as jsx38 } from "react/jsx-runtime";
4298
+ import { jsx as jsx39 } from "react/jsx-runtime";
4213
4299
  var TITLE13 = "Reorder Task";
4214
- var HINTS_RUNNING13 = [{ key: "Esc", action: "cancel" }];
4215
- var HINTS_DONE13 = [
4300
+ var HINTS_RUNNING12 = [{ key: "Esc", action: "cancel" }];
4301
+ var HINTS_DONE12 = [
4216
4302
  { key: "Enter", action: "home" },
4217
4303
  { key: "Esc", action: "back" }
4218
4304
  ];
@@ -4256,22 +4342,22 @@ function TaskReorderView() {
4256
4342
  setPhase({ kind: "done", task });
4257
4343
  }
4258
4344
  });
4259
- const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
4345
+ const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
4260
4346
  useViewHints(hints);
4261
- return /* @__PURE__ */ jsx38(ViewShell, { title: TITLE13, children: renderBody13(phase) });
4347
+ return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE13, children: renderBody12(phase) });
4262
4348
  }
4263
- function renderBody13(phase) {
4349
+ function renderBody12(phase) {
4264
4350
  switch (phase.kind) {
4265
4351
  case "running":
4266
- return /* @__PURE__ */ jsx38(Spinner, { label: stepLabel5(phase.step) });
4352
+ return /* @__PURE__ */ jsx39(Spinner, { label: stepLabel4(phase.step) });
4267
4353
  case "no-tasks":
4268
- return /* @__PURE__ */ jsx38(ResultCard, { kind: "info", title: "No tasks in this sprint" });
4354
+ return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "No tasks in this sprint" });
4269
4355
  case "not-draft":
4270
- return /* @__PURE__ */ jsx38(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4356
+ return /* @__PURE__ */ jsx39(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4271
4357
  case "error":
4272
- return /* @__PURE__ */ jsx38(ResultCard, { kind: "error", title: "Could not reorder", lines: [phase.message] });
4358
+ return /* @__PURE__ */ jsx39(ResultCard, { kind: "error", title: "Could not reorder", lines: [phase.message] });
4273
4359
  case "done":
4274
- return /* @__PURE__ */ jsx38(
4360
+ return /* @__PURE__ */ jsx39(
4275
4361
  ResultCard,
4276
4362
  {
4277
4363
  kind: "success",
@@ -4284,100 +4370,89 @@ function renderBody13(phase) {
4284
4370
  );
4285
4371
  }
4286
4372
  }
4287
- function stepLabel5(step) {
4373
+ function stepLabel4(step) {
4288
4374
  if (step === "select") return "Awaiting task selection\u2026";
4289
4375
  if (step === "order") return "Awaiting new order\u2026";
4290
4376
  return "Saving task\u2026";
4291
4377
  }
4292
4378
 
4293
4379
  // src/integration/ui/tui/views/workflows/task-remove-view.tsx
4294
- import { useMemo as useMemo20 } from "react";
4295
- import { jsx as jsx39 } from "react/jsx-runtime";
4380
+ import { useEffect as useEffect17, useState as useState17 } from "react";
4381
+ import { jsx as jsx40 } from "react/jsx-runtime";
4296
4382
  var TITLE14 = "Remove Task";
4297
- var HINTS_RUNNING14 = [{ key: "Esc", action: "cancel" }];
4298
- var HINTS_DONE14 = [
4299
- { key: "Enter", action: "home" },
4300
- { key: "Esc", action: "back" }
4301
- ];
4302
4383
  function TaskRemoveView() {
4303
- const { phase } = useWorkflow({
4304
- initial: { kind: "running", step: "select" },
4305
- onError: (message) => ({ kind: "error", message }),
4306
- run: async ({ setPhase }) => {
4307
- const prompt = getPrompt();
4308
- const sprint = await getCurrentSprintOrThrow();
4309
- if (sprint.status !== "draft") {
4310
- setPhase({ kind: "not-draft" });
4311
- return;
4312
- }
4313
- const tasks = await listTasks();
4314
- if (tasks.length === 0) {
4315
- setPhase({ kind: "no-tasks" });
4316
- return;
4384
+ const router = useRouter();
4385
+ const [phase, setPhase] = useState17({ kind: "loading" });
4386
+ const [started, setStarted] = useState17(false);
4387
+ useEffect17(() => {
4388
+ if (started) return;
4389
+ setStarted(true);
4390
+ void (async () => {
4391
+ try {
4392
+ const sprint = await getCurrentSprintOrThrow();
4393
+ if (sprint.status !== "draft") {
4394
+ setPhase({ kind: "not-draft" });
4395
+ return;
4396
+ }
4397
+ const tasks = await listTasks();
4398
+ if (tasks.length === 0) {
4399
+ setPhase({ kind: "no-tasks" });
4400
+ return;
4401
+ }
4402
+ setPhase({ kind: "selecting" });
4403
+ const taskId = await getPrompt().select({
4404
+ message: "Select task to remove:",
4405
+ choices: tasks.map((t) => ({ label: `${t.id} \u2014 ${t.name}`, value: t.id, description: t.status }))
4406
+ });
4407
+ const target = tasks.find((t) => t.id === taskId);
4408
+ if (!target) throw new Error(`Task ${taskId} disappeared`);
4409
+ setPhase({ kind: "ready", taskId: target.id, taskName: target.name });
4410
+ } catch (err) {
4411
+ if (err instanceof PromptCancelledError) {
4412
+ router.pop();
4413
+ return;
4414
+ }
4415
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
4317
4416
  }
4318
- setPhase({ kind: "running", step: "select" });
4319
- const taskId = await prompt.select({
4320
- message: "Select task to remove:",
4321
- choices: tasks.map((t) => ({ label: `${t.id} \u2014 ${t.name}`, value: t.id, description: t.status }))
4322
- });
4323
- const target = tasks.find((t) => t.id === taskId);
4324
- if (!target) throw new Error(`Task ${taskId} disappeared`);
4325
- setPhase({ kind: "running", step: "confirm" });
4326
- const ok = await prompt.confirm({
4327
- message: `Remove task "${target.name}"?`,
4328
- default: false
4329
- });
4330
- if (!ok) {
4331
- setPhase({ kind: "cancelled" });
4332
- return;
4417
+ })();
4418
+ }, [started, router]);
4419
+ if (phase.kind === "ready") {
4420
+ return /* @__PURE__ */ jsx40(
4421
+ RemovalWorkflow,
4422
+ {
4423
+ entityLabel: TITLE14,
4424
+ confirmMessage: `Remove task "${phase.taskName}"? This cannot be undone.`,
4425
+ onConfirm: () => removeTask(phase.taskId),
4426
+ successMessage: `Task "${phase.taskName}" removed`,
4427
+ onDone: () => {
4428
+ router.pop();
4429
+ }
4333
4430
  }
4334
- setPhase({ kind: "running", step: "removing" });
4335
- await removeTask(taskId);
4336
- setPhase({ kind: "done", id: target.id, name: target.name });
4337
- }
4338
- });
4339
- const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
4340
- useViewHints(hints);
4341
- return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE14, children: renderBody14(phase) });
4431
+ );
4432
+ }
4433
+ return /* @__PURE__ */ jsx40(ViewShell, { title: TITLE14, children: renderPre3(phase) });
4342
4434
  }
4343
- function renderBody14(phase) {
4435
+ function renderPre3(phase) {
4344
4436
  switch (phase.kind) {
4345
- case "running":
4346
- return /* @__PURE__ */ jsx39(Spinner, { label: stepLabel6(phase.step) });
4437
+ case "loading":
4438
+ return /* @__PURE__ */ jsx40(Spinner, { label: "Loading tasks\u2026" });
4439
+ case "selecting":
4440
+ return /* @__PURE__ */ jsx40(Spinner, { label: "Awaiting task selection\u2026" });
4347
4441
  case "no-tasks":
4348
- return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "No tasks to remove" });
4442
+ return /* @__PURE__ */ jsx40(ResultCard, { kind: "info", title: "No tasks to remove" });
4349
4443
  case "not-draft":
4350
- return /* @__PURE__ */ jsx39(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4351
- case "cancelled":
4352
- return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "Removal cancelled" });
4444
+ return /* @__PURE__ */ jsx40(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
4353
4445
  case "error":
4354
- return /* @__PURE__ */ jsx39(ResultCard, { kind: "error", title: "Could not remove task", lines: [phase.message] });
4355
- case "done":
4356
- return /* @__PURE__ */ jsx39(
4357
- ResultCard,
4358
- {
4359
- kind: "success",
4360
- title: "Task removed",
4361
- fields: [
4362
- ["ID", phase.id],
4363
- ["Name", phase.name]
4364
- ]
4365
- }
4366
- );
4446
+ return /* @__PURE__ */ jsx40(ResultCard, { kind: "error", title: "Could not remove task", lines: [phase.message] });
4367
4447
  }
4368
4448
  }
4369
- function stepLabel6(step) {
4370
- if (step === "select") return "Awaiting task selection\u2026";
4371
- if (step === "confirm") return "Awaiting confirmation\u2026";
4372
- return "Removing task\u2026";
4373
- }
4374
4449
 
4375
4450
  // src/integration/ui/tui/views/workflows/task-next-view.tsx
4376
- import { useMemo as useMemo21 } from "react";
4377
- import { jsx as jsx40 } from "react/jsx-runtime";
4451
+ import { useMemo as useMemo20 } from "react";
4452
+ import { jsx as jsx41 } from "react/jsx-runtime";
4378
4453
  var TITLE15 = "Next Task";
4379
- var HINTS_RUNNING15 = [{ key: "Esc", action: "cancel" }];
4380
- var HINTS_DONE15 = [
4454
+ var HINTS_RUNNING13 = [{ key: "Esc", action: "cancel" }];
4455
+ var HINTS_DONE13 = [
4381
4456
  { key: "Enter", action: "home" },
4382
4457
  { key: "Esc", action: "back" }
4383
4458
  ];
@@ -4394,20 +4469,20 @@ function TaskNextView() {
4394
4469
  setPhase({ kind: "ready", task });
4395
4470
  }
4396
4471
  });
4397
- const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
4472
+ const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
4398
4473
  useViewHints(hints);
4399
- return /* @__PURE__ */ jsx40(ViewShell, { title: TITLE15, children: renderBody15(phase) });
4474
+ return /* @__PURE__ */ jsx41(ViewShell, { title: TITLE15, children: renderBody13(phase) });
4400
4475
  }
4401
- function renderBody15(phase) {
4476
+ function renderBody13(phase) {
4402
4477
  switch (phase.kind) {
4403
4478
  case "running":
4404
- return /* @__PURE__ */ jsx40(Spinner, { label: "Resolving next task\u2026" });
4479
+ return /* @__PURE__ */ jsx41(Spinner, { label: "Resolving next task\u2026" });
4405
4480
  case "none":
4406
- return /* @__PURE__ */ jsx40(ResultCard, { kind: "info", title: "No task available", lines: ["All tasks are done or blocked."] });
4481
+ return /* @__PURE__ */ jsx41(ResultCard, { kind: "info", title: "No task available", lines: ["All tasks are done or blocked."] });
4407
4482
  case "error":
4408
- return /* @__PURE__ */ jsx40(ResultCard, { kind: "error", title: "Could not resolve next task", lines: [phase.message] });
4483
+ return /* @__PURE__ */ jsx41(ResultCard, { kind: "error", title: "Could not resolve next task", lines: [phase.message] });
4409
4484
  case "ready":
4410
- return /* @__PURE__ */ jsx40(
4485
+ return /* @__PURE__ */ jsx41(
4411
4486
  ResultCard,
4412
4487
  {
4413
4488
  kind: "info",
@@ -4426,7 +4501,7 @@ function renderBody15(phase) {
4426
4501
 
4427
4502
  // src/integration/ui/tui/views/workflows/project-add-view.tsx
4428
4503
  import { resolve } from "path";
4429
- import { useMemo as useMemo22 } from "react";
4504
+ import { useMemo as useMemo21 } from "react";
4430
4505
 
4431
4506
  // src/integration/ui/tui/views/workflows/collect-check-script.ts
4432
4507
  async function collectCheckScript(repoPath, setStep) {
@@ -4471,10 +4546,10 @@ async function collectCheckScript(repoPath, setStep) {
4471
4546
  }
4472
4547
 
4473
4548
  // src/integration/ui/tui/views/workflows/project-add-view.tsx
4474
- import { jsx as jsx41 } from "react/jsx-runtime";
4549
+ import { jsx as jsx42 } from "react/jsx-runtime";
4475
4550
  var TITLE16 = "Add Project";
4476
- var HINTS_RUNNING16 = [{ key: "Esc", action: "cancel" }];
4477
- var HINTS_DONE16 = [
4551
+ var HINTS_RUNNING14 = [{ key: "Esc", action: "cancel" }];
4552
+ var HINTS_DONE14 = [
4478
4553
  { key: "Enter", action: "home" },
4479
4554
  { key: "Esc", action: "back" }
4480
4555
  ];
@@ -4520,16 +4595,16 @@ function ProjectAddView() {
4520
4595
  setPhase({ kind: "done", project });
4521
4596
  }
4522
4597
  });
4523
- const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
4598
+ const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
4524
4599
  useViewHints(hints);
4525
- return /* @__PURE__ */ jsx41(ViewShell, { title: TITLE16, children: renderBody16(phase) });
4600
+ return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE16, children: renderBody14(phase) });
4526
4601
  }
4527
- function renderBody16(phase) {
4602
+ function renderBody14(phase) {
4528
4603
  switch (phase.kind) {
4529
4604
  case "running":
4530
- return /* @__PURE__ */ jsx41(Spinner, { label: stepLabel7(phase.step) });
4605
+ return /* @__PURE__ */ jsx42(Spinner, { label: stepLabel5(phase.step) });
4531
4606
  case "error":
4532
- return /* @__PURE__ */ jsx41(
4607
+ return /* @__PURE__ */ jsx42(
4533
4608
  ResultCard,
4534
4609
  {
4535
4610
  kind: "error",
@@ -4538,7 +4613,7 @@ function renderBody16(phase) {
4538
4613
  }
4539
4614
  );
4540
4615
  case "done":
4541
- return /* @__PURE__ */ jsx41(
4616
+ return /* @__PURE__ */ jsx42(
4542
4617
  ResultCard,
4543
4618
  {
4544
4619
  kind: "success",
@@ -4553,7 +4628,7 @@ function renderBody16(phase) {
4553
4628
  );
4554
4629
  }
4555
4630
  }
4556
- function stepLabel7(step) {
4631
+ function stepLabel5(step) {
4557
4632
  if (step === "name") return "Awaiting project slug\u2026";
4558
4633
  if (step === "display") return "Awaiting display name\u2026";
4559
4634
  if (step === "repo-path") return "Awaiting repository path\u2026";
@@ -4563,79 +4638,78 @@ function stepLabel7(step) {
4563
4638
  }
4564
4639
 
4565
4640
  // src/integration/ui/tui/views/workflows/project-remove-view.tsx
4566
- import { useMemo as useMemo23 } from "react";
4567
- import { jsx as jsx42 } from "react/jsx-runtime";
4641
+ import { useEffect as useEffect18, useState as useState18 } from "react";
4642
+ import { jsx as jsx43 } from "react/jsx-runtime";
4568
4643
  var TITLE17 = "Remove Project";
4569
- var HINTS_RUNNING17 = [{ key: "Esc", action: "cancel" }];
4570
- var HINTS_DONE17 = [
4571
- { key: "Enter", action: "home" },
4572
- { key: "Esc", action: "back" }
4573
- ];
4574
4644
  function ProjectRemoveView() {
4575
- const { phase } = useWorkflow({
4576
- initial: { kind: "running", step: "select" },
4577
- onError: (message) => ({ kind: "error", message }),
4578
- run: async ({ setPhase }) => {
4579
- const prompt = getPrompt();
4580
- const projects = await listProjects();
4581
- if (projects.length === 0) {
4582
- setPhase({ kind: "no-projects" });
4583
- return;
4645
+ const router = useRouter();
4646
+ const [phase, setPhase] = useState18({ kind: "loading" });
4647
+ const [started, setStarted] = useState18(false);
4648
+ useEffect18(() => {
4649
+ if (started) return;
4650
+ setStarted(true);
4651
+ void (async () => {
4652
+ try {
4653
+ const projects = await listProjects();
4654
+ if (projects.length === 0) {
4655
+ setPhase({ kind: "no-projects" });
4656
+ return;
4657
+ }
4658
+ setPhase({ kind: "selecting" });
4659
+ const name = await getPrompt().select({
4660
+ message: "Select project to remove:",
4661
+ choices: projects.map((p) => ({
4662
+ label: `${p.displayName} (${p.name})`,
4663
+ value: p.name,
4664
+ description: `${String(p.repositories.length)} repo${p.repositories.length === 1 ? "" : "s"}`
4665
+ }))
4666
+ });
4667
+ setPhase({ kind: "ready", name });
4668
+ } catch (err) {
4669
+ if (err instanceof PromptCancelledError) {
4670
+ router.pop();
4671
+ return;
4672
+ }
4673
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
4584
4674
  }
4585
- setPhase({ kind: "running", step: "select" });
4586
- const name = await prompt.select({
4587
- message: "Select project to remove:",
4588
- choices: projects.map((p) => ({
4589
- label: `${p.displayName} (${p.name})`,
4590
- value: p.name,
4591
- description: `${String(p.repositories.length)} repo${p.repositories.length === 1 ? "" : "s"}`
4592
- }))
4593
- });
4594
- setPhase({ kind: "running", step: "confirm" });
4595
- const ok = await prompt.confirm({
4596
- message: `Remove project "${name}"? This cannot be undone.`,
4597
- default: false
4598
- });
4599
- if (!ok) {
4600
- setPhase({ kind: "cancelled" });
4601
- return;
4675
+ })();
4676
+ }, [started, router]);
4677
+ if (phase.kind === "ready") {
4678
+ return /* @__PURE__ */ jsx43(
4679
+ RemovalWorkflow,
4680
+ {
4681
+ entityLabel: TITLE17,
4682
+ confirmMessage: `Remove project "${phase.name}"? This cannot be undone.`,
4683
+ onConfirm: () => removeProject(phase.name),
4684
+ successMessage: `Project "${phase.name}" removed`,
4685
+ onDone: () => {
4686
+ router.pop();
4687
+ }
4602
4688
  }
4603
- setPhase({ kind: "running", step: "removing" });
4604
- await removeProject(name);
4605
- setPhase({ kind: "done", name });
4606
- }
4607
- });
4608
- const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
4609
- useViewHints(hints);
4610
- return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE17, children: renderBody17(phase) });
4689
+ );
4690
+ }
4691
+ return /* @__PURE__ */ jsx43(ViewShell, { title: TITLE17, children: renderPre4(phase) });
4611
4692
  }
4612
- function renderBody17(phase) {
4693
+ function renderPre4(phase) {
4613
4694
  switch (phase.kind) {
4614
- case "running":
4615
- return /* @__PURE__ */ jsx42(Spinner, { label: stepLabel8(phase.step) });
4695
+ case "loading":
4696
+ return /* @__PURE__ */ jsx43(Spinner, { label: "Loading projects\u2026" });
4697
+ case "selecting":
4698
+ return /* @__PURE__ */ jsx43(Spinner, { label: "Awaiting project selection\u2026" });
4616
4699
  case "no-projects":
4617
- return /* @__PURE__ */ jsx42(ResultCard, { kind: "info", title: "No projects to remove" });
4618
- case "cancelled":
4619
- return /* @__PURE__ */ jsx42(ResultCard, { kind: "info", title: "Removal cancelled" });
4700
+ return /* @__PURE__ */ jsx43(ResultCard, { kind: "info", title: "No projects to remove" });
4620
4701
  case "error":
4621
- return /* @__PURE__ */ jsx42(ResultCard, { kind: "error", title: "Could not remove project", lines: [phase.message] });
4622
- case "done":
4623
- return /* @__PURE__ */ jsx42(ResultCard, { kind: "success", title: "Project removed", fields: [["Name", phase.name]] });
4702
+ return /* @__PURE__ */ jsx43(ResultCard, { kind: "error", title: "Could not remove project", lines: [phase.message] });
4624
4703
  }
4625
4704
  }
4626
- function stepLabel8(step) {
4627
- if (step === "select") return "Awaiting project selection\u2026";
4628
- if (step === "confirm") return "Awaiting confirmation\u2026";
4629
- return "Removing project\u2026";
4630
- }
4631
4705
 
4632
4706
  // src/integration/ui/tui/views/workflows/project-repo-add-view.tsx
4633
4707
  import { resolve as resolve2 } from "path";
4634
- import { useMemo as useMemo24 } from "react";
4635
- import { jsx as jsx43 } from "react/jsx-runtime";
4708
+ import { useMemo as useMemo22 } from "react";
4709
+ import { jsx as jsx44 } from "react/jsx-runtime";
4636
4710
  var TITLE18 = "Add Repository";
4637
- var HINTS_RUNNING18 = [{ key: "Esc", action: "cancel" }];
4638
- var HINTS_DONE18 = [
4711
+ var HINTS_RUNNING15 = [{ key: "Esc", action: "cancel" }];
4712
+ var HINTS_DONE15 = [
4639
4713
  { key: "Enter", action: "home" },
4640
4714
  { key: "Esc", action: "back" }
4641
4715
  ];
@@ -4665,144 +4739,142 @@ function ProjectRepoAddView() {
4665
4739
  const checkScript = await collectCheckScript(absolute, (next) => {
4666
4740
  setPhase({ kind: "running", step: next });
4667
4741
  });
4668
- setPhase({ kind: "running", step: "saving" });
4669
- const project = await addProjectRepo(projectName, {
4670
- name: repoName,
4671
- path: absolute,
4672
- ...checkScript ? { checkScript } : {}
4673
- });
4674
- setPhase({ kind: "done", project, repoName });
4675
- }
4676
- });
4677
- const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
4678
- useViewHints(hints);
4679
- return /* @__PURE__ */ jsx43(ViewShell, { title: TITLE18, children: renderBody18(phase) });
4680
- }
4681
- function renderBody18(phase) {
4682
- switch (phase.kind) {
4683
- case "running":
4684
- return /* @__PURE__ */ jsx43(Spinner, { label: stepLabel9(phase.step) });
4685
- case "no-projects":
4686
- return /* @__PURE__ */ jsx43(ResultCard, { kind: "warning", title: "No projects to add a repository to" });
4687
- case "error":
4688
- return /* @__PURE__ */ jsx43(ResultCard, { kind: "error", title: "Could not add repository", lines: [phase.message] });
4689
- case "done":
4690
- return /* @__PURE__ */ jsx43(
4691
- ResultCard,
4692
- {
4693
- kind: "success",
4694
- title: "Repository added",
4695
- fields: [
4696
- ["Project", phase.project.displayName],
4697
- ["Repo", phase.repoName],
4698
- ["Total repos", String(phase.project.repositories.length)]
4699
- ]
4700
- }
4701
- );
4702
- }
4703
- }
4704
- function stepLabel9(step) {
4705
- if (step === "project") return "Awaiting project selection\u2026";
4706
- if (step === "path") return "Awaiting repository path\u2026";
4707
- if (step === "check-script") return "Awaiting check-script confirmation\u2026";
4708
- if (step === "discovering") return "Discovering check script with AI\u2026";
4709
- return "Saving repository\u2026";
4710
- }
4711
-
4712
- // src/integration/ui/tui/views/workflows/project-repo-remove-view.tsx
4713
- import { useMemo as useMemo25 } from "react";
4714
- import { jsx as jsx44 } from "react/jsx-runtime";
4715
- var TITLE19 = "Remove Repository";
4716
- var HINTS_RUNNING19 = [{ key: "Esc", action: "cancel" }];
4717
- var HINTS_DONE19 = [
4718
- { key: "Enter", action: "home" },
4719
- { key: "Esc", action: "back" }
4720
- ];
4721
- function ProjectRepoRemoveView() {
4722
- const { phase } = useWorkflow({
4723
- initial: { kind: "running", step: "project" },
4724
- onError: (message) => ({ kind: "error", message }),
4725
- run: async ({ setPhase }) => {
4726
- const prompt = getPrompt();
4727
- const projects = await listProjects();
4728
- if (projects.length === 0) {
4729
- setPhase({ kind: "no-projects" });
4730
- return;
4731
- }
4732
- setPhase({ kind: "running", step: "project" });
4733
- const projectName = projects.length === 1 && projects[0] ? projects[0].name : await prompt.select({
4734
- message: "Which project?",
4735
- choices: projects.map((p) => ({ label: p.displayName, value: p.name }))
4736
- });
4737
- const project = projects.find((p) => p.name === projectName);
4738
- if (!project || project.repositories.length === 0) {
4739
- setPhase({ kind: "no-repos" });
4740
- return;
4741
- }
4742
- setPhase({ kind: "running", step: "repo" });
4743
- const repoPath = await prompt.select({
4744
- message: "Repository to remove:",
4745
- choices: project.repositories.map((r) => ({ label: r.name, value: r.path, description: r.path }))
4746
- });
4747
- const repoName = project.repositories.find((r) => r.path === repoPath)?.name ?? repoPath;
4748
- setPhase({ kind: "running", step: "confirm" });
4749
- const ok = await prompt.confirm({
4750
- message: `Remove repository "${repoName}" from ${project.displayName}?`,
4751
- default: false
4742
+ setPhase({ kind: "running", step: "saving" });
4743
+ const project = await addProjectRepo(projectName, {
4744
+ name: repoName,
4745
+ path: absolute,
4746
+ ...checkScript ? { checkScript } : {}
4752
4747
  });
4753
- if (!ok) {
4754
- setPhase({ kind: "cancelled" });
4755
- return;
4756
- }
4757
- setPhase({ kind: "running", step: "removing" });
4758
- const updated = await removeProjectRepo(projectName, repoPath);
4759
- setPhase({ kind: "done", project: updated, repoName });
4748
+ setPhase({ kind: "done", project, repoName });
4760
4749
  }
4761
4750
  });
4762
- const hints = useMemo25(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
4751
+ const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
4763
4752
  useViewHints(hints);
4764
- return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE19, children: renderBody19(phase) });
4753
+ return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE18, children: renderBody15(phase) });
4765
4754
  }
4766
- function renderBody19(phase) {
4755
+ function renderBody15(phase) {
4767
4756
  switch (phase.kind) {
4768
4757
  case "running":
4769
- return /* @__PURE__ */ jsx44(Spinner, { label: stepLabel10(phase.step) });
4758
+ return /* @__PURE__ */ jsx44(Spinner, { label: stepLabel6(phase.step) });
4770
4759
  case "no-projects":
4771
- return /* @__PURE__ */ jsx44(ResultCard, { kind: "info", title: "No projects" });
4772
- case "no-repos":
4773
- return /* @__PURE__ */ jsx44(ResultCard, { kind: "info", title: "Project has no repositories" });
4774
- case "cancelled":
4775
- return /* @__PURE__ */ jsx44(ResultCard, { kind: "info", title: "Removal cancelled" });
4760
+ return /* @__PURE__ */ jsx44(ResultCard, { kind: "warning", title: "No projects to add a repository to" });
4776
4761
  case "error":
4777
- return /* @__PURE__ */ jsx44(ResultCard, { kind: "error", title: "Could not remove repository", lines: [phase.message] });
4762
+ return /* @__PURE__ */ jsx44(ResultCard, { kind: "error", title: "Could not add repository", lines: [phase.message] });
4778
4763
  case "done":
4779
4764
  return /* @__PURE__ */ jsx44(
4780
4765
  ResultCard,
4781
4766
  {
4782
4767
  kind: "success",
4783
- title: "Repository removed",
4768
+ title: "Repository added",
4784
4769
  fields: [
4785
4770
  ["Project", phase.project.displayName],
4786
4771
  ["Repo", phase.repoName],
4787
- ["Remaining", String(phase.project.repositories.length)]
4772
+ ["Total repos", String(phase.project.repositories.length)]
4788
4773
  ]
4789
4774
  }
4790
4775
  );
4791
4776
  }
4792
4777
  }
4793
- function stepLabel10(step) {
4778
+ function stepLabel6(step) {
4794
4779
  if (step === "project") return "Awaiting project selection\u2026";
4795
- if (step === "repo") return "Awaiting repository selection\u2026";
4796
- if (step === "confirm") return "Awaiting confirmation\u2026";
4797
- return "Removing repository\u2026";
4780
+ if (step === "path") return "Awaiting repository path\u2026";
4781
+ if (step === "check-script") return "Awaiting check-script confirmation\u2026";
4782
+ if (step === "discovering") return "Discovering check script with AI\u2026";
4783
+ return "Saving repository\u2026";
4798
4784
  }
4799
4785
 
4800
- // src/integration/ui/tui/views/workflows/project-edit-view.tsx
4801
- import { useMemo as useMemo26 } from "react";
4786
+ // src/integration/ui/tui/views/workflows/project-repo-remove-view.tsx
4787
+ import { useEffect as useEffect19, useState as useState19 } from "react";
4802
4788
  import { jsx as jsx45 } from "react/jsx-runtime";
4789
+ var TITLE19 = "Remove Repository";
4790
+ function ProjectRepoRemoveView() {
4791
+ const router = useRouter();
4792
+ const [phase, setPhase] = useState19({ kind: "loading" });
4793
+ const [started, setStarted] = useState19(false);
4794
+ useEffect19(() => {
4795
+ if (started) return;
4796
+ setStarted(true);
4797
+ void (async () => {
4798
+ try {
4799
+ const prompt = getPrompt();
4800
+ const projects = await listProjects();
4801
+ if (projects.length === 0) {
4802
+ setPhase({ kind: "no-projects" });
4803
+ return;
4804
+ }
4805
+ setPhase({ kind: "selecting-project" });
4806
+ const projectName = projects.length === 1 && projects[0] ? projects[0].name : await prompt.select({
4807
+ message: "Which project?",
4808
+ choices: projects.map((p) => ({ label: p.displayName, value: p.name }))
4809
+ });
4810
+ const project = projects.find((p) => p.name === projectName);
4811
+ if (!project || project.repositories.length === 0) {
4812
+ setPhase({ kind: "no-repos" });
4813
+ return;
4814
+ }
4815
+ setPhase({ kind: "selecting-repo" });
4816
+ const repoPath = await prompt.select({
4817
+ message: "Repository to remove:",
4818
+ choices: project.repositories.map((r) => ({ label: r.name, value: r.path, description: r.path }))
4819
+ });
4820
+ const repoName = project.repositories.find((r) => r.path === repoPath)?.name ?? repoPath;
4821
+ setPhase({
4822
+ kind: "ready",
4823
+ projectName,
4824
+ projectDisplay: project.displayName,
4825
+ repoPath,
4826
+ repoName
4827
+ });
4828
+ } catch (err) {
4829
+ if (err instanceof PromptCancelledError) {
4830
+ router.pop();
4831
+ return;
4832
+ }
4833
+ setPhase({ kind: "error", message: err instanceof Error ? err.message : String(err) });
4834
+ }
4835
+ })();
4836
+ }, [started, router]);
4837
+ if (phase.kind === "ready") {
4838
+ return /* @__PURE__ */ jsx45(
4839
+ RemovalWorkflow,
4840
+ {
4841
+ entityLabel: TITLE19,
4842
+ confirmMessage: `Remove repository "${phase.repoName}" from ${phase.projectDisplay}? This cannot be undone.`,
4843
+ onConfirm: async () => {
4844
+ await removeProjectRepo(phase.projectName, phase.repoPath);
4845
+ },
4846
+ successMessage: `Repository "${phase.repoName}" removed from ${phase.projectDisplay}`,
4847
+ onDone: () => {
4848
+ router.pop();
4849
+ }
4850
+ }
4851
+ );
4852
+ }
4853
+ return /* @__PURE__ */ jsx45(ViewShell, { title: TITLE19, children: renderPre5(phase) });
4854
+ }
4855
+ function renderPre5(phase) {
4856
+ switch (phase.kind) {
4857
+ case "loading":
4858
+ return /* @__PURE__ */ jsx45(Spinner, { label: "Loading projects\u2026" });
4859
+ case "selecting-project":
4860
+ return /* @__PURE__ */ jsx45(Spinner, { label: "Awaiting project selection\u2026" });
4861
+ case "selecting-repo":
4862
+ return /* @__PURE__ */ jsx45(Spinner, { label: "Awaiting repository selection\u2026" });
4863
+ case "no-projects":
4864
+ return /* @__PURE__ */ jsx45(ResultCard, { kind: "info", title: "No projects" });
4865
+ case "no-repos":
4866
+ return /* @__PURE__ */ jsx45(ResultCard, { kind: "info", title: "Project has no repositories" });
4867
+ case "error":
4868
+ return /* @__PURE__ */ jsx45(ResultCard, { kind: "error", title: "Could not remove repository", lines: [phase.message] });
4869
+ }
4870
+ }
4871
+
4872
+ // src/integration/ui/tui/views/workflows/project-edit-view.tsx
4873
+ import { useMemo as useMemo23 } from "react";
4874
+ import { jsx as jsx46 } from "react/jsx-runtime";
4803
4875
  var TITLE20 = "Edit Project";
4804
- var HINTS_RUNNING20 = [{ key: "Esc", action: "cancel" }];
4805
- var HINTS_DONE20 = [
4876
+ var HINTS_RUNNING16 = [{ key: "Esc", action: "cancel" }];
4877
+ var HINTS_DONE16 = [
4806
4878
  { key: "Enter", action: "home" },
4807
4879
  { key: "Esc", action: "back" }
4808
4880
  ];
@@ -4844,20 +4916,20 @@ function ProjectEditView() {
4844
4916
  setPhase({ kind: "done", project });
4845
4917
  }
4846
4918
  });
4847
- const hints = useMemo26(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
4919
+ const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
4848
4920
  useViewHints(hints);
4849
- return /* @__PURE__ */ jsx45(ViewShell, { title: TITLE20, children: renderBody20(phase) });
4921
+ return /* @__PURE__ */ jsx46(ViewShell, { title: TITLE20, children: renderBody16(phase) });
4850
4922
  }
4851
- function renderBody20(phase) {
4923
+ function renderBody16(phase) {
4852
4924
  switch (phase.kind) {
4853
4925
  case "running":
4854
- return /* @__PURE__ */ jsx45(Spinner, { label: stepLabel11(phase.step) });
4926
+ return /* @__PURE__ */ jsx46(Spinner, { label: stepLabel7(phase.step) });
4855
4927
  case "no-projects":
4856
- return /* @__PURE__ */ jsx45(ResultCard, { kind: "info", title: "No projects registered" });
4928
+ return /* @__PURE__ */ jsx46(ResultCard, { kind: "info", title: "No projects registered" });
4857
4929
  case "error":
4858
- return /* @__PURE__ */ jsx45(ResultCard, { kind: "error", title: "Could not update project", lines: [phase.message] });
4930
+ return /* @__PURE__ */ jsx46(ResultCard, { kind: "error", title: "Could not update project", lines: [phase.message] });
4859
4931
  case "done":
4860
- return /* @__PURE__ */ jsx45(
4932
+ return /* @__PURE__ */ jsx46(
4861
4933
  ResultCard,
4862
4934
  {
4863
4935
  kind: "success",
@@ -4871,7 +4943,7 @@ function renderBody20(phase) {
4871
4943
  );
4872
4944
  }
4873
4945
  }
4874
- function stepLabel11(step) {
4946
+ function stepLabel7(step) {
4875
4947
  if (step === "select") return "Awaiting project selection\u2026";
4876
4948
  if (step === "display") return "Awaiting display name\u2026";
4877
4949
  if (step === "description") return "Awaiting description\u2026";
@@ -4879,11 +4951,11 @@ function stepLabel11(step) {
4879
4951
  }
4880
4952
 
4881
4953
  // src/integration/ui/tui/views/workflows/project-onboard-view.tsx
4882
- import { useMemo as useMemo27 } from "react";
4883
- import { jsx as jsx46 } from "react/jsx-runtime";
4954
+ import { useMemo as useMemo24 } from "react";
4955
+ import { jsx as jsx47 } from "react/jsx-runtime";
4884
4956
  var TITLE21 = "Onboard Repository";
4885
- var HINTS_RUNNING21 = [{ key: "Esc", action: "cancel" }];
4886
- var HINTS_DONE21 = [
4957
+ var HINTS_RUNNING17 = [{ key: "Esc", action: "cancel" }];
4958
+ var HINTS_DONE17 = [
4887
4959
  { key: "Enter", action: "home" },
4888
4960
  { key: "Esc", action: "back" }
4889
4961
  ];
@@ -4938,18 +5010,18 @@ function ProjectOnboardView({
4938
5010
  });
4939
5011
  }
4940
5012
  });
4941
- const hints = useMemo27(() => phase.kind === "running" ? HINTS_RUNNING21 : HINTS_DONE21, [phase.kind]);
5013
+ const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
4942
5014
  useViewHints(hints);
4943
- return /* @__PURE__ */ jsx46(ViewShell, { title: TITLE21, children: renderBody21(phase) });
5015
+ return /* @__PURE__ */ jsx47(ViewShell, { title: TITLE21, children: renderBody17(phase) });
4944
5016
  }
4945
- function renderBody21(phase) {
5017
+ function renderBody17(phase) {
4946
5018
  switch (phase.kind) {
4947
5019
  case "running":
4948
- return /* @__PURE__ */ jsx46(Spinner, { label: stepLabel12(phase.step) });
5020
+ return /* @__PURE__ */ jsx47(Spinner, { label: stepLabel8(phase.step) });
4949
5021
  case "no-projects":
4950
- return /* @__PURE__ */ jsx46(ResultCard, { kind: "info", title: "No projects registered" });
5022
+ return /* @__PURE__ */ jsx47(ResultCard, { kind: "info", title: "No projects registered" });
4951
5023
  case "error":
4952
- return /* @__PURE__ */ jsx46(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
5024
+ return /* @__PURE__ */ jsx47(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
4953
5025
  case "done": {
4954
5026
  const fields = [["Project", phase.projectName]];
4955
5027
  if (phase.writtenPath) fields.push(["Project context file", phase.writtenPath]);
@@ -4961,26 +5033,26 @@ function renderBody21(phase) {
4961
5033
  fields.push(["Review", "Low-confidence sections present \u2014 re-run interactively to tighten"]);
4962
5034
  }
4963
5035
  if (phase.alreadyCurrent) {
4964
- return /* @__PURE__ */ jsx46(ResultCard, { kind: "info", title: "Already current", fields });
5036
+ return /* @__PURE__ */ jsx47(ResultCard, { kind: "info", title: "Already current", fields });
4965
5037
  }
4966
5038
  const nextSteps = phase.lowConfidence ? [{ action: "Open the project context file and replace LOW-CONFIDENCE lines with concrete facts." }] : void 0;
4967
- return /* @__PURE__ */ jsx46(ResultCard, { kind: "success", title: "Repository onboarded", fields, nextSteps });
5039
+ return /* @__PURE__ */ jsx47(ResultCard, { kind: "success", title: "Repository onboarded", fields, nextSteps });
4968
5040
  }
4969
5041
  }
4970
5042
  }
4971
- function stepLabel12(step) {
5043
+ function stepLabel8(step) {
4972
5044
  if (step === "select-project") return "Awaiting project selection\u2026";
4973
5045
  return "Inventorying repository and reviewing proposal\u2026";
4974
5046
  }
4975
5047
 
4976
5048
  // src/integration/ui/tui/views/browse/sprint-list-view.tsx
4977
- import { useEffect as useEffect15, useMemo as useMemo29, useState as useState15 } from "react";
4978
- import { useInput as useInput11 } from "ink";
5049
+ import { useEffect as useEffect21, useMemo as useMemo26, useState as useState21 } from "react";
5050
+ import { useInput as useInput13 } from "ink";
4979
5051
 
4980
5052
  // src/integration/ui/tui/components/list-view.tsx
4981
- import React48, { useEffect as useEffect14, useMemo as useMemo28, useState as useState14 } from "react";
4982
- import { Box as Box25, Text as Text24, useInput as useInput10 } from "ink";
4983
- import { jsx as jsx47, jsxs as jsxs24 } from "react/jsx-runtime";
5053
+ import React49, { useEffect as useEffect20, useMemo as useMemo25, useState as useState20 } from "react";
5054
+ import { Box as Box25, Text as Text24, useInput as useInput12 } from "ink";
5055
+ import { jsx as jsx48, jsxs as jsxs24 } from "react/jsx-runtime";
4984
5056
  var DEFAULT_PAGE_SIZE = 12;
4985
5057
  function computeWidths(columns, rows, totalWidth) {
4986
5058
  const widths = columns.map((col) => {
@@ -5012,14 +5084,14 @@ function ListView({
5012
5084
  disabled = false,
5013
5085
  onCursorChange
5014
5086
  }) {
5015
- const [cursor, setCursor] = useState14(() => Math.max(0, Math.min(initialCursor, rows.length - 1)));
5016
- useEffect14(() => {
5087
+ const [cursor, setCursor] = useState20(() => Math.max(0, Math.min(initialCursor, rows.length - 1)));
5088
+ useEffect20(() => {
5017
5089
  if (!onCursorChange) return;
5018
5090
  const row = rows[cursor];
5019
5091
  if (row !== void 0) onCursorChange(row, cursor);
5020
5092
  }, [cursor, rows, onCursorChange]);
5021
- const widths = useMemo28(() => computeWidths(columns, rows, 72), [columns, rows]);
5022
- useInput10(
5093
+ const widths = useMemo25(() => computeWidths(columns, rows, 72), [columns, rows]);
5094
+ useInput12(
5023
5095
  (_input, key) => {
5024
5096
  if (rows.length === 0) return;
5025
5097
  if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
@@ -5034,17 +5106,17 @@ function ListView({
5034
5106
  { isActive: !disabled }
5035
5107
  );
5036
5108
  if (rows.length === 0) {
5037
- return /* @__PURE__ */ jsx47(Box25, { children: /* @__PURE__ */ jsx47(Text24, { dimColor: true, children: emptyLabel }) });
5109
+ return /* @__PURE__ */ jsx48(Box25, { children: /* @__PURE__ */ jsx48(Text24, { dimColor: true, children: emptyLabel }) });
5038
5110
  }
5039
5111
  const windowStart = Math.max(0, Math.min(cursor - Math.floor(pageSize / 2), rows.length - pageSize));
5040
5112
  const windowEnd = Math.min(rows.length, windowStart + pageSize);
5041
5113
  const visible = rows.slice(windowStart, windowEnd);
5042
5114
  return /* @__PURE__ */ jsxs24(Box25, { flexDirection: "column", children: [
5043
5115
  /* @__PURE__ */ jsxs24(Box25, { children: [
5044
- /* @__PURE__ */ jsx47(Text24, { color: inkColors.muted, bold: true, children: " " }),
5045
- columns.map((col, i) => /* @__PURE__ */ jsxs24(React48.Fragment, { children: [
5046
- /* @__PURE__ */ jsx47(Text24, { color: inkColors.muted, bold: true, children: pad(col.header.toUpperCase(), widths[i] ?? col.header.length, col.align) }),
5047
- i < columns.length - 1 ? /* @__PURE__ */ jsx47(Text24, { color: inkColors.muted, children: " " }) : null
5116
+ /* @__PURE__ */ jsx48(Text24, { color: inkColors.muted, bold: true, children: " " }),
5117
+ columns.map((col, i) => /* @__PURE__ */ jsxs24(React49.Fragment, { children: [
5118
+ /* @__PURE__ */ jsx48(Text24, { color: inkColors.muted, bold: true, children: pad(col.header.toUpperCase(), widths[i] ?? col.header.length, col.align) }),
5119
+ i < columns.length - 1 ? /* @__PURE__ */ jsx48(Text24, { color: inkColors.muted, children: " " }) : null
5048
5120
  ] }, col.header))
5049
5121
  ] }),
5050
5122
  visible.map((row, i) => {
@@ -5052,18 +5124,18 @@ function ListView({
5052
5124
  const selected = absoluteIdx === cursor;
5053
5125
  const indicatorColor = selected ? inkColors.highlight : void 0;
5054
5126
  return /* @__PURE__ */ jsxs24(Box25, { children: [
5055
- /* @__PURE__ */ jsx47(Text24, { color: indicatorColor, bold: selected, children: selected ? glyphs.actionCursor : " " }),
5127
+ /* @__PURE__ */ jsx48(Text24, { color: indicatorColor, bold: selected, children: selected ? glyphs.actionCursor : " " }),
5056
5128
  columns.map((col, ci) => {
5057
5129
  const text = pad(col.cell(row), widths[ci] ?? col.cell(row).length, col.align);
5058
5130
  const cellColor = col.color?.(row) ?? (selected ? inkColors.highlight : void 0);
5059
- return /* @__PURE__ */ jsxs24(React48.Fragment, { children: [
5060
- /* @__PURE__ */ jsx47(Text24, { color: cellColor, bold: selected && ci === 0, children: text }),
5061
- ci < columns.length - 1 ? /* @__PURE__ */ jsx47(Text24, { children: " " }) : null
5131
+ return /* @__PURE__ */ jsxs24(React49.Fragment, { children: [
5132
+ /* @__PURE__ */ jsx48(Text24, { color: cellColor, bold: selected && ci === 0, children: text }),
5133
+ ci < columns.length - 1 ? /* @__PURE__ */ jsx48(Text24, { children: " " }) : null
5062
5134
  ] }, col.header);
5063
5135
  })
5064
5136
  ] }, absoluteIdx);
5065
5137
  }),
5066
- rows.length > pageSize ? /* @__PURE__ */ jsx47(Box25, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs24(Text24, { dimColor: true, children: [
5138
+ rows.length > pageSize ? /* @__PURE__ */ jsx48(Box25, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs24(Text24, { dimColor: true, children: [
5067
5139
  String(cursor + 1),
5068
5140
  " / ",
5069
5141
  String(rows.length),
@@ -5095,6 +5167,12 @@ function chipKindForTaskStatus(status) {
5095
5167
  if (status === "in_progress") return "warning";
5096
5168
  return "muted";
5097
5169
  }
5170
+ function chipKindForExecutionStatus(status) {
5171
+ if (status === "running") return "warning";
5172
+ if (status === "completed") return "success";
5173
+ if (status === "failed") return "error";
5174
+ return "muted";
5175
+ }
5098
5176
  function StatusChip({ label, kind = "info" }) {
5099
5177
  return /* @__PURE__ */ jsxs25(Text25, { color: COLOR2[kind], bold: true, children: [
5100
5178
  "[",
@@ -5104,7 +5182,7 @@ function StatusChip({ label, kind = "info" }) {
5104
5182
  }
5105
5183
 
5106
5184
  // src/integration/ui/tui/views/browse/sprint-list-view.tsx
5107
- import { jsx as jsx48 } from "react/jsx-runtime";
5185
+ import { jsx as jsx49 } from "react/jsx-runtime";
5108
5186
  function statusChipText(status) {
5109
5187
  return `[${status.toUpperCase()}]`;
5110
5188
  }
@@ -5162,7 +5240,7 @@ var HINTS_READY2 = [
5162
5240
  { key: "f", action: "filter" },
5163
5241
  { key: "n", action: "new" },
5164
5242
  { key: "c", action: "set current" },
5165
- { key: "x", action: "delete" }
5243
+ { key: "r", action: "remove" }
5166
5244
  ];
5167
5245
  var HINTS_EMPTY = [{ key: "n", action: "new" }];
5168
5246
  var FILTER_CYCLE = ["all", "draft", "active", "closed"];
@@ -5172,10 +5250,10 @@ function nextFilter(current) {
5172
5250
  }
5173
5251
  function SprintListView() {
5174
5252
  const router = useRouter();
5175
- const [state, setState] = useState15({ kind: "loading" });
5176
- const [filter, setFilter] = useState15("all");
5253
+ const [state, setState] = useState21({ kind: "loading" });
5254
+ const [filter, setFilter] = useState21("all");
5177
5255
  useViewHints(state.kind === "ready" ? HINTS_READY2 : HINTS_EMPTY);
5178
- useEffect15(() => {
5256
+ useEffect21(() => {
5179
5257
  const ctl = { cancelled: false };
5180
5258
  void (async () => {
5181
5259
  try {
@@ -5211,7 +5289,7 @@ function SprintListView() {
5211
5289
  ctl.cancelled = true;
5212
5290
  };
5213
5291
  }, []);
5214
- useInput11((input) => {
5292
+ useInput13((input) => {
5215
5293
  if (state.kind === "loading") return;
5216
5294
  if (input === "n") {
5217
5295
  router.push({ id: "sprint-create" });
@@ -5226,17 +5304,17 @@ function SprintListView() {
5226
5304
  router.push({ id: "sprint-set-current" });
5227
5305
  return;
5228
5306
  }
5229
- if (input === "x") {
5307
+ if (input === "r") {
5230
5308
  router.push({ id: "sprint-delete" });
5231
5309
  }
5232
5310
  });
5233
5311
  const title = filter === "all" ? TITLE_BASE : `${TITLE_BASE} \xB7 filter: ${filter}`;
5234
- const filtered = useMemo29(() => {
5312
+ const filtered = useMemo26(() => {
5235
5313
  if (state.kind !== "ready") return [];
5236
5314
  if (filter === "all") return state.sprints;
5237
5315
  return state.sprints.filter((s) => s.status === filter);
5238
5316
  }, [state, filter]);
5239
- return /* @__PURE__ */ jsx48(ViewShell, { title, children: state.kind === "loading" ? /* @__PURE__ */ jsx48(Spinner, { label: "Loading sprints\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx48(ResultCard, { kind: "info", title: "No sprints yet", lines: ["Press `n` to create one."] }) : state.kind === "error" ? /* @__PURE__ */ jsx48(ResultCard, { kind: "error", title: "Could not load sprints", lines: [state.message] }) : filtered.length === 0 ? /* @__PURE__ */ jsx48(ResultCard, { kind: "info", title: `No sprints with status '${filter}'`, lines: ["Press f to cycle the filter."] }) : /* @__PURE__ */ jsx48(
5317
+ return /* @__PURE__ */ jsx49(ViewShell, { title, children: state.kind === "loading" ? /* @__PURE__ */ jsx49(Spinner, { label: "Loading sprints\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx49(ResultCard, { kind: "info", title: "No sprints yet", lines: ["Press `n` to create one."] }) : state.kind === "error" ? /* @__PURE__ */ jsx49(ResultCard, { kind: "error", title: "Could not load sprints", lines: [state.message] }) : filtered.length === 0 ? /* @__PURE__ */ jsx49(ResultCard, { kind: "info", title: `No sprints with status '${filter}'`, lines: ["Press f to cycle the filter."] }) : /* @__PURE__ */ jsx49(
5240
5318
  ListView,
5241
5319
  {
5242
5320
  rows: filtered,
@@ -5250,9 +5328,9 @@ function SprintListView() {
5250
5328
  }
5251
5329
 
5252
5330
  // src/integration/ui/tui/views/browse/sprint-show-view.tsx
5253
- import { useEffect as useEffect16, useMemo as useMemo30, useState as useState16 } from "react";
5254
- import { Box as Box26, Text as Text26, useInput as useInput12 } from "ink";
5255
- import { jsx as jsx49, jsxs as jsxs26 } from "react/jsx-runtime";
5331
+ import { useEffect as useEffect22, useMemo as useMemo27, useState as useState22 } from "react";
5332
+ import { Box as Box26, Text as Text26, useInput as useInput14 } from "ink";
5333
+ import { jsx as jsx50, jsxs as jsxs26 } from "react/jsx-runtime";
5256
5334
  var TITLE22 = "Sprint Details";
5257
5335
  var HINTS = [
5258
5336
  { key: "\u2191/\u2193", action: "move" },
@@ -5260,9 +5338,9 @@ var HINTS = [
5260
5338
  ];
5261
5339
  function SprintShowView({ sprintId }) {
5262
5340
  const router = useRouter();
5263
- const [state, setState] = useState16({ kind: "loading" });
5341
+ const [state, setState] = useState22({ kind: "loading" });
5264
5342
  useViewHints(HINTS);
5265
- useEffect16(() => {
5343
+ useEffect22(() => {
5266
5344
  const ctl = { cancelled: false };
5267
5345
  void (async () => {
5268
5346
  try {
@@ -5278,13 +5356,13 @@ function SprintShowView({ sprintId }) {
5278
5356
  ctl.cancelled = true;
5279
5357
  };
5280
5358
  }, [sprintId]);
5281
- const rows = useMemo30(() => {
5359
+ const rows = useMemo27(() => {
5282
5360
  if (state.kind !== "ready") return [];
5283
5361
  return buildRows2(state.sprint, state.tasks);
5284
5362
  }, [state]);
5285
- const sections = useMemo30(() => rows.filter((r) => r.separator !== true), [rows]);
5286
- const [cursor, setCursor] = useState16(0);
5287
- useInput12(
5363
+ const sections = useMemo27(() => rows.filter((r) => r.separator !== true), [rows]);
5364
+ const [cursor, setCursor] = useState22(0);
5365
+ useInput14(
5288
5366
  (_input, key) => {
5289
5367
  if (sections.length === 0) return;
5290
5368
  if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
@@ -5296,11 +5374,11 @@ function SprintShowView({ sprintId }) {
5296
5374
  },
5297
5375
  { isActive: state.kind === "ready" && sections.length > 0 }
5298
5376
  );
5299
- return /* @__PURE__ */ jsx49(ViewShell, { title: TITLE22, children: renderBody22(state, rows, sections, cursor) });
5377
+ return /* @__PURE__ */ jsx50(ViewShell, { title: TITLE22, children: renderBody18(state, rows, sections, cursor) });
5300
5378
  }
5301
- function renderBody22(state, rows, sections, cursor) {
5302
- if (state.kind === "loading") return /* @__PURE__ */ jsx49(Spinner, { label: "Loading sprint\u2026" });
5303
- if (state.kind === "error") return /* @__PURE__ */ jsx49(ResultCard, { kind: "error", title: "Could not load sprint", lines: [state.message] });
5379
+ function renderBody18(state, rows, sections, cursor) {
5380
+ if (state.kind === "loading") return /* @__PURE__ */ jsx50(Spinner, { label: "Loading sprint\u2026" });
5381
+ if (state.kind === "error") return /* @__PURE__ */ jsx50(ResultCard, { kind: "error", title: "Could not load sprint", lines: [state.message] });
5304
5382
  const { sprint, tasks, project } = state;
5305
5383
  const projectLabel = project ? `${project.displayName} (${project.name})` : sprint.projectId;
5306
5384
  const approved = sprint.tickets.filter((t) => t.requirementStatus === "approved").length;
@@ -5308,11 +5386,11 @@ function renderBody22(state, rows, sections, cursor) {
5308
5386
  const activeSectionId = sections[cursor]?.destination.id;
5309
5387
  return /* @__PURE__ */ jsxs26(Box26, { flexDirection: "column", children: [
5310
5388
  /* @__PURE__ */ jsxs26(Box26, { children: [
5311
- /* @__PURE__ */ jsx49(Text26, { bold: true, children: sprint.name }),
5312
- /* @__PURE__ */ jsx49(Text26, { children: " " }),
5313
- /* @__PURE__ */ jsx49(StatusChip, { label: sprint.status, kind: chipKindForSprintStatus(sprint.status) })
5389
+ /* @__PURE__ */ jsx50(Text26, { bold: true, children: sprint.name }),
5390
+ /* @__PURE__ */ jsx50(Text26, { children: " " }),
5391
+ /* @__PURE__ */ jsx50(StatusChip, { label: sprint.status, kind: chipKindForSprintStatus(sprint.status) })
5314
5392
  ] }),
5315
- /* @__PURE__ */ jsx49(Box26, { marginTop: spacing.section, children: /* @__PURE__ */ jsx49(
5393
+ /* @__PURE__ */ jsx50(Box26, { marginTop: spacing.section, children: /* @__PURE__ */ jsx50(
5316
5394
  FieldList,
5317
5395
  {
5318
5396
  fields: [
@@ -5328,22 +5406,22 @@ function renderBody22(state, rows, sections, cursor) {
5328
5406
  }
5329
5407
  ) }),
5330
5408
  /* @__PURE__ */ jsxs26(Box26, { marginTop: spacing.section, flexDirection: "column", children: [
5331
- /* @__PURE__ */ jsx49(Text26, { color: inkColors.muted, bold: true, children: "Sections" }),
5332
- rows.map((row, i) => /* @__PURE__ */ jsx49(RowRenderer, { row, isActive: row.separator !== true && row.destination.id === activeSectionId }, i))
5409
+ /* @__PURE__ */ jsx50(Text26, { color: inkColors.muted, bold: true, children: "Sections" }),
5410
+ rows.map((row, i) => /* @__PURE__ */ jsx50(RowRenderer, { row, isActive: row.separator !== true && row.destination.id === activeSectionId }, i))
5333
5411
  ] })
5334
5412
  ] });
5335
5413
  }
5336
5414
  function RowRenderer({ row, isActive }) {
5337
5415
  if (row.separator === true) {
5338
- return /* @__PURE__ */ jsx49(Box26, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx49(Text26, { color: inkColors.muted, dimColor: true, children: glyphs.sectionRule.repeat(2) }) });
5416
+ return /* @__PURE__ */ jsx50(Box26, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx50(Text26, { color: inkColors.muted, dimColor: true, children: glyphs.sectionRule.repeat(2) }) });
5339
5417
  }
5340
5418
  return /* @__PURE__ */ jsxs26(Box26, { paddingLeft: spacing.indent, children: [
5341
- /* @__PURE__ */ jsx49(Text26, { color: isActive ? inkColors.highlight : void 0, bold: isActive, children: isActive ? glyphs.actionCursor : " " }),
5419
+ /* @__PURE__ */ jsx50(Text26, { color: isActive ? inkColors.highlight : void 0, bold: isActive, children: isActive ? glyphs.actionCursor : " " }),
5342
5420
  /* @__PURE__ */ jsxs26(Text26, { color: isActive ? inkColors.highlight : void 0, bold: isActive, children: [
5343
5421
  " ",
5344
5422
  row.label
5345
5423
  ] }),
5346
- /* @__PURE__ */ jsx49(Text26, { dimColor: true, children: ` ${glyphs.emDash} ${row.description}` })
5424
+ /* @__PURE__ */ jsx50(Text26, { dimColor: true, children: ` ${glyphs.emDash} ${row.description}` })
5347
5425
  ] });
5348
5426
  }
5349
5427
  function buildRows2(sprint, tasks) {
@@ -5404,9 +5482,9 @@ function buildRows2(sprint, tasks) {
5404
5482
  }
5405
5483
 
5406
5484
  // src/integration/ui/tui/views/browse/ticket-list-view.tsx
5407
- import { useCallback as useCallback9, useEffect as useEffect17, useState as useState17 } from "react";
5408
- import { useInput as useInput13 } from "ink";
5409
- import { jsx as jsx50 } from "react/jsx-runtime";
5485
+ import { useCallback as useCallback9, useEffect as useEffect23, useState as useState23 } from "react";
5486
+ import { useInput as useInput15 } from "ink";
5487
+ import { jsx as jsx51 } from "react/jsx-runtime";
5410
5488
  function requirementColor(status) {
5411
5489
  return status === "approved" ? inkColors.success : inkColors.warning;
5412
5490
  }
@@ -5441,7 +5519,7 @@ var HINTS_READY3 = [
5441
5519
  var HINTS_EMPTY2 = [{ key: "a", action: "add" }];
5442
5520
  function TicketListView({ sprintId }) {
5443
5521
  const router = useRouter();
5444
- const [state, setState] = useState17({ kind: "loading" });
5522
+ const [state, setState] = useState23({ kind: "loading" });
5445
5523
  const load = useCallback9(async () => {
5446
5524
  try {
5447
5525
  const id = await resolveSprintId(sprintId);
@@ -5459,7 +5537,7 @@ function TicketListView({ sprintId }) {
5459
5537
  setState({ kind: "error", message: err instanceof Error ? err.message : String(err) });
5460
5538
  }
5461
5539
  }, [sprintId]);
5462
- useEffect17(() => {
5540
+ useEffect23(() => {
5463
5541
  const ctl = { cancelled: false };
5464
5542
  void (async () => {
5465
5543
  if (!ctl.cancelled) await load();
@@ -5468,7 +5546,7 @@ function TicketListView({ sprintId }) {
5468
5546
  ctl.cancelled = true;
5469
5547
  };
5470
5548
  }, [load]);
5471
- useInput13((input) => {
5549
+ useInput15((input) => {
5472
5550
  if (state.kind === "loading") return;
5473
5551
  if (input === "a") {
5474
5552
  router.push({ id: "ticket-add" });
@@ -5484,7 +5562,7 @@ function TicketListView({ sprintId }) {
5484
5562
  }
5485
5563
  });
5486
5564
  useViewHints(state.kind === "ready" ? HINTS_READY3 : HINTS_EMPTY2);
5487
- return /* @__PURE__ */ jsx50(ViewShell, { title: TITLE23, children: state.kind === "loading" ? /* @__PURE__ */ jsx50(Spinner, { label: "Loading tickets\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx50(ResultCard, { kind: "info", title: "No tickets in this sprint", lines: ["Press `a` to add a ticket."] }) : state.kind === "error" ? /* @__PURE__ */ jsx50(ResultCard, { kind: "error", title: "Could not load tickets", lines: [state.message] }) : /* @__PURE__ */ jsx50(
5565
+ return /* @__PURE__ */ jsx51(ViewShell, { title: TITLE23, children: state.kind === "loading" ? /* @__PURE__ */ jsx51(Spinner, { label: "Loading tickets\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx51(ResultCard, { kind: "info", title: "No tickets in this sprint", lines: ["Press `a` to add a ticket."] }) : state.kind === "error" ? /* @__PURE__ */ jsx51(ResultCard, { kind: "error", title: "Could not load tickets", lines: [state.message] }) : /* @__PURE__ */ jsx51(
5488
5566
  ListView,
5489
5567
  {
5490
5568
  rows: state.tickets,
@@ -5497,16 +5575,16 @@ function TicketListView({ sprintId }) {
5497
5575
  }
5498
5576
 
5499
5577
  // src/integration/ui/tui/views/browse/ticket-show-view.tsx
5500
- import { useEffect as useEffect18, useState as useState18 } from "react";
5501
- import { Box as Box27, Text as Text27, useInput as useInput14 } from "ink";
5502
- import { jsx as jsx51, jsxs as jsxs27 } from "react/jsx-runtime";
5578
+ import { useEffect as useEffect24, useState as useState24 } from "react";
5579
+ import { Box as Box27, Text as Text27, useInput as useInput16 } from "ink";
5580
+ import { jsx as jsx52, jsxs as jsxs27 } from "react/jsx-runtime";
5503
5581
  var TITLE24 = "Ticket Details";
5504
5582
  var HINTS_READ_ONLY = [];
5505
5583
  var HINTS_EDITABLE = [{ key: "e", action: "edit" }];
5506
5584
  function TicketShowView({ ticketId }) {
5507
5585
  const router = useRouter();
5508
- const [state, setState] = useState18({ kind: "loading" });
5509
- useEffect18(() => {
5586
+ const [state, setState] = useState24({ kind: "loading" });
5587
+ useEffect24(() => {
5510
5588
  const ctl = { cancelled: false };
5511
5589
  void (async () => {
5512
5590
  if (!ticketId) {
@@ -5533,23 +5611,23 @@ function TicketShowView({ ticketId }) {
5533
5611
  ctl.cancelled = true;
5534
5612
  };
5535
5613
  }, [ticketId]);
5536
- useInput14((input) => {
5614
+ useInput16((input) => {
5537
5615
  if (input === "e" && state.kind === "ready" && state.editable && ticketId) {
5538
5616
  router.push({ id: "ticket-edit", props: { ticketId } });
5539
5617
  }
5540
5618
  });
5541
5619
  useViewHints(state.kind === "ready" && state.editable ? HINTS_EDITABLE : HINTS_READ_ONLY);
5542
- return /* @__PURE__ */ jsx51(ViewShell, { title: TITLE24, children: renderBody23(state) });
5620
+ return /* @__PURE__ */ jsx52(ViewShell, { title: TITLE24, children: renderBody19(state) });
5543
5621
  }
5544
- function renderBody23(state) {
5545
- if (state.kind === "loading") return /* @__PURE__ */ jsx51(Spinner, { label: "Loading ticket\u2026" });
5546
- if (state.kind === "error") return /* @__PURE__ */ jsx51(ResultCard, { kind: "error", title: "Could not load ticket", lines: [state.message] });
5622
+ function renderBody19(state) {
5623
+ if (state.kind === "loading") return /* @__PURE__ */ jsx52(Spinner, { label: "Loading ticket\u2026" });
5624
+ if (state.kind === "error") return /* @__PURE__ */ jsx52(ResultCard, { kind: "error", title: "Could not load ticket", lines: [state.message] });
5547
5625
  const { ticket } = state;
5548
5626
  return /* @__PURE__ */ jsxs27(Box27, { flexDirection: "column", children: [
5549
5627
  /* @__PURE__ */ jsxs27(Box27, { children: [
5550
- /* @__PURE__ */ jsx51(Text27, { bold: true, children: ticket.title }),
5551
- /* @__PURE__ */ jsx51(Text27, { children: " " }),
5552
- /* @__PURE__ */ jsx51(
5628
+ /* @__PURE__ */ jsx52(Text27, { bold: true, children: ticket.title }),
5629
+ /* @__PURE__ */ jsx52(Text27, { children: " " }),
5630
+ /* @__PURE__ */ jsx52(
5553
5631
  StatusChip,
5554
5632
  {
5555
5633
  label: ticket.requirementStatus,
@@ -5557,7 +5635,7 @@ function renderBody23(state) {
5557
5635
  }
5558
5636
  )
5559
5637
  ] }),
5560
- /* @__PURE__ */ jsx51(Box27, { marginTop: spacing.section, children: /* @__PURE__ */ jsx51(
5638
+ /* @__PURE__ */ jsx52(Box27, { marginTop: spacing.section, children: /* @__PURE__ */ jsx52(
5561
5639
  FieldList,
5562
5640
  {
5563
5641
  fields: [
@@ -5568,20 +5646,20 @@ function renderBody23(state) {
5568
5646
  }
5569
5647
  ) }),
5570
5648
  ticket.description ? /* @__PURE__ */ jsxs27(Box27, { marginTop: spacing.section, flexDirection: "column", children: [
5571
- /* @__PURE__ */ jsx51(Text27, { color: inkColors.muted, bold: true, children: "Description" }),
5572
- /* @__PURE__ */ jsx51(Box27, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx51(Text27, { children: ticket.description }) })
5649
+ /* @__PURE__ */ jsx52(Text27, { color: inkColors.muted, bold: true, children: "Description" }),
5650
+ /* @__PURE__ */ jsx52(Box27, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx52(Text27, { children: ticket.description }) })
5573
5651
  ] }) : null,
5574
5652
  ticket.requirements ? /* @__PURE__ */ jsxs27(Box27, { marginTop: spacing.section, flexDirection: "column", children: [
5575
- /* @__PURE__ */ jsx51(Text27, { color: inkColors.muted, bold: true, children: "Requirements" }),
5576
- /* @__PURE__ */ jsx51(Box27, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx51(Text27, { children: ticket.requirements }) })
5653
+ /* @__PURE__ */ jsx52(Text27, { color: inkColors.muted, bold: true, children: "Requirements" }),
5654
+ /* @__PURE__ */ jsx52(Box27, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx52(Text27, { children: ticket.requirements }) })
5577
5655
  ] }) : null
5578
5656
  ] });
5579
5657
  }
5580
5658
 
5581
5659
  // src/integration/ui/tui/views/browse/task-list-view.tsx
5582
- import { useEffect as useEffect19, useMemo as useMemo31, useState as useState19 } from "react";
5583
- import { useInput as useInput15 } from "ink";
5584
- import { jsx as jsx52 } from "react/jsx-runtime";
5660
+ import { useEffect as useEffect25, useMemo as useMemo28, useState as useState25 } from "react";
5661
+ import { useInput as useInput17 } from "ink";
5662
+ import { jsx as jsx53 } from "react/jsx-runtime";
5585
5663
  var FILTER_CYCLE2 = ["all", "todo", "active", "done"];
5586
5664
  function nextFilter2(f) {
5587
5665
  const i = FILTER_CYCLE2.indexOf(f);
@@ -5653,10 +5731,10 @@ var HINTS_READY4 = [
5653
5731
  var HINTS_EMPTY3 = [{ key: "a", action: "add" }];
5654
5732
  function TaskListView({ sprintId }) {
5655
5733
  const router = useRouter();
5656
- const [state, setState] = useState19({ kind: "loading" });
5657
- const [filter, setFilter] = useState19("all");
5734
+ const [state, setState] = useState25({ kind: "loading" });
5735
+ const [filter, setFilter] = useState25("all");
5658
5736
  useViewHints(state.kind === "ready" ? HINTS_READY4 : HINTS_EMPTY3);
5659
- useEffect19(() => {
5737
+ useEffect25(() => {
5660
5738
  const ctl = { cancelled: false };
5661
5739
  void (async () => {
5662
5740
  try {
@@ -5685,7 +5763,7 @@ function TaskListView({ sprintId }) {
5685
5763
  ctl.cancelled = true;
5686
5764
  };
5687
5765
  }, [sprintId]);
5688
- useInput15((input) => {
5766
+ useInput17((input) => {
5689
5767
  if (state.kind === "loading") return;
5690
5768
  if (input === "a") {
5691
5769
  router.push({ id: "task-add" });
@@ -5704,13 +5782,13 @@ function TaskListView({ sprintId }) {
5704
5782
  router.push({ id: "task-remove" });
5705
5783
  }
5706
5784
  });
5707
- const filtered = useMemo31(() => {
5785
+ const filtered = useMemo28(() => {
5708
5786
  if (state.kind !== "ready") return [];
5709
5787
  if (filter === "all") return state.tasks;
5710
5788
  return state.tasks.filter((t) => matches(t, filter));
5711
5789
  }, [state, filter]);
5712
5790
  const title = filter === "all" ? TITLE_BASE2 : `${TITLE_BASE2} \xB7 filter: ${filter}`;
5713
- return /* @__PURE__ */ jsx52(ViewShell, { title, children: state.kind === "loading" ? /* @__PURE__ */ jsx52(Spinner, { label: "Loading tasks\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx52(ResultCard, { kind: "info", title: "No tasks in this sprint" }) : state.kind === "error" ? /* @__PURE__ */ jsx52(ResultCard, { kind: "error", title: "Could not load tasks", lines: [state.message] }) : filtered.length === 0 ? /* @__PURE__ */ jsx52(ResultCard, { kind: "info", title: `No tasks with filter '${filter}'`, lines: ["Press f to cycle the filter."] }) : /* @__PURE__ */ jsx52(
5791
+ return /* @__PURE__ */ jsx53(ViewShell, { title, children: state.kind === "loading" ? /* @__PURE__ */ jsx53(Spinner, { label: "Loading tasks\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx53(ResultCard, { kind: "info", title: "No tasks in this sprint" }) : state.kind === "error" ? /* @__PURE__ */ jsx53(ResultCard, { kind: "error", title: "Could not load tasks", lines: [state.message] }) : filtered.length === 0 ? /* @__PURE__ */ jsx53(ResultCard, { kind: "info", title: `No tasks with filter '${filter}'`, lines: ["Press f to cycle the filter."] }) : /* @__PURE__ */ jsx53(
5714
5792
  ListView,
5715
5793
  {
5716
5794
  rows: filtered,
@@ -5723,9 +5801,9 @@ function TaskListView({ sprintId }) {
5723
5801
  }
5724
5802
 
5725
5803
  // src/integration/ui/tui/views/browse/task-show-view.tsx
5726
- import { useEffect as useEffect20, useState as useState20 } from "react";
5727
- import { Box as Box28, Text as Text28, useInput as useInput16 } from "ink";
5728
- import { jsx as jsx53, jsxs as jsxs28 } from "react/jsx-runtime";
5804
+ import { useEffect as useEffect26, useState as useState26 } from "react";
5805
+ import { Box as Box28, Text as Text28, useInput as useInput18 } from "ink";
5806
+ import { jsx as jsx54, jsxs as jsxs28 } from "react/jsx-runtime";
5729
5807
  var TITLE25 = "Task Details";
5730
5808
  var HINTS_READY5 = [
5731
5809
  { key: "t", action: "status" },
@@ -5734,9 +5812,9 @@ var HINTS_READY5 = [
5734
5812
  var HINTS_EMPTY4 = [];
5735
5813
  function TaskShowView({ taskId }) {
5736
5814
  const router = useRouter();
5737
- const [state, setState] = useState20({ kind: "loading" });
5815
+ const [state, setState] = useState26({ kind: "loading" });
5738
5816
  useViewHints(state.kind === "ready" ? HINTS_READY5 : HINTS_EMPTY4);
5739
- useInput16((input) => {
5817
+ useInput18((input) => {
5740
5818
  if (state.kind !== "ready") return;
5741
5819
  if (input === "t") {
5742
5820
  router.push({ id: "task-status" });
@@ -5746,7 +5824,7 @@ function TaskShowView({ taskId }) {
5746
5824
  router.push({ id: "task-remove" });
5747
5825
  }
5748
5826
  });
5749
- useEffect20(() => {
5827
+ useEffect26(() => {
5750
5828
  const ctl = { cancelled: false };
5751
5829
  void (async () => {
5752
5830
  if (!taskId) {
@@ -5764,19 +5842,19 @@ function TaskShowView({ taskId }) {
5764
5842
  ctl.cancelled = true;
5765
5843
  };
5766
5844
  }, [taskId]);
5767
- return /* @__PURE__ */ jsx53(ViewShell, { title: TITLE25, children: renderBody24(state) });
5845
+ return /* @__PURE__ */ jsx54(ViewShell, { title: TITLE25, children: renderBody20(state) });
5768
5846
  }
5769
- function renderBody24(state) {
5770
- if (state.kind === "loading") return /* @__PURE__ */ jsx53(Spinner, { label: "Loading task\u2026" });
5771
- if (state.kind === "error") return /* @__PURE__ */ jsx53(ResultCard, { kind: "error", title: "Could not load task", lines: [state.message] });
5847
+ function renderBody20(state) {
5848
+ if (state.kind === "loading") return /* @__PURE__ */ jsx54(Spinner, { label: "Loading task\u2026" });
5849
+ if (state.kind === "error") return /* @__PURE__ */ jsx54(ResultCard, { kind: "error", title: "Could not load task", lines: [state.message] });
5772
5850
  const { task } = state;
5773
5851
  return /* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", children: [
5774
5852
  /* @__PURE__ */ jsxs28(Box28, { children: [
5775
- /* @__PURE__ */ jsx53(Text28, { bold: true, children: task.name }),
5776
- /* @__PURE__ */ jsx53(Text28, { children: " " }),
5777
- /* @__PURE__ */ jsx53(StatusChip, { label: task.status, kind: chipKindForTaskStatus(task.status) })
5853
+ /* @__PURE__ */ jsx54(Text28, { bold: true, children: task.name }),
5854
+ /* @__PURE__ */ jsx54(Text28, { children: " " }),
5855
+ /* @__PURE__ */ jsx54(StatusChip, { label: task.status, kind: chipKindForTaskStatus(task.status) })
5778
5856
  ] }),
5779
- /* @__PURE__ */ jsx53(Box28, { marginTop: spacing.section, children: /* @__PURE__ */ jsx53(
5857
+ /* @__PURE__ */ jsx54(Box28, { marginTop: spacing.section, children: /* @__PURE__ */ jsx54(
5780
5858
  FieldList,
5781
5859
  {
5782
5860
  fields: [
@@ -5791,36 +5869,36 @@ function renderBody24(state) {
5791
5869
  }
5792
5870
  ) }),
5793
5871
  task.description ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
5794
- /* @__PURE__ */ jsx53(Text28, { color: inkColors.muted, bold: true, children: "Description" }),
5795
- /* @__PURE__ */ jsx53(Box28, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx53(Text28, { children: task.description }) })
5872
+ /* @__PURE__ */ jsx54(Text28, { color: inkColors.muted, bold: true, children: "Description" }),
5873
+ /* @__PURE__ */ jsx54(Box28, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx54(Text28, { children: task.description }) })
5796
5874
  ] }) : null,
5797
5875
  task.steps.length > 0 ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
5798
- /* @__PURE__ */ jsx53(Text28, { color: inkColors.muted, bold: true, children: "Steps" }),
5876
+ /* @__PURE__ */ jsx54(Text28, { color: inkColors.muted, bold: true, children: "Steps" }),
5799
5877
  task.steps.map((step, i) => /* @__PURE__ */ jsxs28(Box28, { paddingLeft: spacing.indent, children: [
5800
5878
  /* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
5801
5879
  String(i + 1).padStart(2, " "),
5802
5880
  ". "
5803
5881
  ] }),
5804
- /* @__PURE__ */ jsx53(Text28, { children: step })
5882
+ /* @__PURE__ */ jsx54(Text28, { children: step })
5805
5883
  ] }, i))
5806
5884
  ] }) : null,
5807
5885
  task.verificationCriteria.length > 0 ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
5808
- /* @__PURE__ */ jsx53(Text28, { color: inkColors.muted, bold: true, children: "Verification" }),
5886
+ /* @__PURE__ */ jsx54(Text28, { color: inkColors.muted, bold: true, children: "Verification" }),
5809
5887
  task.verificationCriteria.map((v, i) => /* @__PURE__ */ jsxs28(Box28, { paddingLeft: spacing.indent, children: [
5810
5888
  /* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
5811
5889
  glyphs.bulletListItem,
5812
5890
  " "
5813
5891
  ] }),
5814
- /* @__PURE__ */ jsx53(Text28, { children: v })
5892
+ /* @__PURE__ */ jsx54(Text28, { children: v })
5815
5893
  ] }, i))
5816
5894
  ] }) : null
5817
5895
  ] });
5818
5896
  }
5819
5897
 
5820
5898
  // src/integration/ui/tui/views/browse/project-list-view.tsx
5821
- import { useCallback as useCallback10, useEffect as useEffect21, useRef as useRef3, useState as useState21 } from "react";
5822
- import { useInput as useInput17 } from "ink";
5823
- import { jsx as jsx54 } from "react/jsx-runtime";
5899
+ import { useCallback as useCallback10, useEffect as useEffect27, useRef as useRef3, useState as useState27 } from "react";
5900
+ import { useInput as useInput19 } from "ink";
5901
+ import { jsx as jsx55 } from "react/jsx-runtime";
5824
5902
  var COLUMNS = [
5825
5903
  { header: "Name", cell: (p) => p.name, width: 16 },
5826
5904
  { header: "Display", cell: (p) => p.displayName, flex: true },
@@ -5838,12 +5916,12 @@ var HINTS_READY6 = [
5838
5916
  var HINTS_EMPTY5 = [{ key: "a", action: "add" }];
5839
5917
  function ProjectListView() {
5840
5918
  const router = useRouter();
5841
- const [state, setState] = useState21({ kind: "loading" });
5919
+ const [state, setState] = useState27({ kind: "loading" });
5842
5920
  const highlightedRef = useRef3(null);
5843
5921
  const handleCursorChange = useCallback10((row) => {
5844
5922
  highlightedRef.current = row;
5845
5923
  }, []);
5846
- useEffect21(() => {
5924
+ useEffect27(() => {
5847
5925
  const ctl = { cancelled: false };
5848
5926
  void (async () => {
5849
5927
  try {
@@ -5860,7 +5938,7 @@ function ProjectListView() {
5860
5938
  ctl.cancelled = true;
5861
5939
  };
5862
5940
  }, []);
5863
- useInput17((input) => {
5941
+ useInput19((input) => {
5864
5942
  if (state.kind === "loading") return;
5865
5943
  if (input === "a") {
5866
5944
  router.push({ id: "project-add" });
@@ -5883,7 +5961,7 @@ function ProjectListView() {
5883
5961
  }
5884
5962
  });
5885
5963
  useViewHints(state.kind === "ready" ? HINTS_READY6 : HINTS_EMPTY5);
5886
- return /* @__PURE__ */ jsx54(ViewShell, { title: TITLE26, children: state.kind === "loading" ? /* @__PURE__ */ jsx54(Spinner, { label: "Loading projects\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx54(ResultCard, { kind: "info", title: "No projects registered", lines: ["Press `a` to add one."] }) : state.kind === "error" ? /* @__PURE__ */ jsx54(ResultCard, { kind: "error", title: "Could not load projects", lines: [state.message] }) : /* @__PURE__ */ jsx54(
5964
+ return /* @__PURE__ */ jsx55(ViewShell, { title: TITLE26, children: state.kind === "loading" ? /* @__PURE__ */ jsx55(Spinner, { label: "Loading projects\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx55(ResultCard, { kind: "info", title: "No projects registered", lines: ["Press `a` to add one."] }) : state.kind === "error" ? /* @__PURE__ */ jsx55(ResultCard, { kind: "error", title: "Could not load projects", lines: [state.message] }) : /* @__PURE__ */ jsx55(
5887
5965
  ListView,
5888
5966
  {
5889
5967
  rows: state.projects,
@@ -5897,9 +5975,9 @@ function ProjectListView() {
5897
5975
  }
5898
5976
 
5899
5977
  // src/integration/ui/tui/views/browse/project-show-view.tsx
5900
- import { useEffect as useEffect22, useState as useState22 } from "react";
5901
- import { Box as Box29, Text as Text29, useInput as useInput18 } from "ink";
5902
- import { jsx as jsx55, jsxs as jsxs29 } from "react/jsx-runtime";
5978
+ import { useEffect as useEffect28, useState as useState28 } from "react";
5979
+ import { Box as Box29, Text as Text29, useInput as useInput20 } from "ink";
5980
+ import { jsx as jsx56, jsxs as jsxs29 } from "react/jsx-runtime";
5903
5981
  var TITLE27 = "Project Details";
5904
5982
  var HINTS_READY7 = [
5905
5983
  { key: "e", action: "edit" },
@@ -5910,9 +5988,9 @@ var HINTS_READY7 = [
5910
5988
  var HINTS_EMPTY6 = [];
5911
5989
  function ProjectShowView({ projectName }) {
5912
5990
  const router = useRouter();
5913
- const [state, setState] = useState22({ kind: "loading" });
5991
+ const [state, setState] = useState28({ kind: "loading" });
5914
5992
  useViewHints(state.kind === "ready" ? HINTS_READY7 : HINTS_EMPTY6);
5915
- useInput18((input) => {
5993
+ useInput20((input) => {
5916
5994
  if (state.kind !== "ready") return;
5917
5995
  if (input === "e") {
5918
5996
  router.push({ id: "project-edit" });
@@ -5930,7 +6008,7 @@ function ProjectShowView({ projectName }) {
5930
6008
  router.push({ id: "project-repo-remove" });
5931
6009
  }
5932
6010
  });
5933
- useEffect22(() => {
6011
+ useEffect28(() => {
5934
6012
  const ctl = { cancelled: false };
5935
6013
  void (async () => {
5936
6014
  if (!projectName) {
@@ -5948,18 +6026,18 @@ function ProjectShowView({ projectName }) {
5948
6026
  ctl.cancelled = true;
5949
6027
  };
5950
6028
  }, [projectName]);
5951
- return /* @__PURE__ */ jsx55(ViewShell, { title: TITLE27, children: renderBody25(state) });
6029
+ return /* @__PURE__ */ jsx56(ViewShell, { title: TITLE27, children: renderBody21(state) });
5952
6030
  }
5953
- function renderBody25(state) {
5954
- if (state.kind === "loading") return /* @__PURE__ */ jsx55(Spinner, { label: "Loading project\u2026" });
5955
- if (state.kind === "error") return /* @__PURE__ */ jsx55(ResultCard, { kind: "error", title: "Could not load project", lines: [state.message] });
6031
+ function renderBody21(state) {
6032
+ if (state.kind === "loading") return /* @__PURE__ */ jsx56(Spinner, { label: "Loading project\u2026" });
6033
+ if (state.kind === "error") return /* @__PURE__ */ jsx56(ResultCard, { kind: "error", title: "Could not load project", lines: [state.message] });
5956
6034
  const { project } = state;
5957
6035
  return /* @__PURE__ */ jsxs29(Box29, { flexDirection: "column", children: [
5958
6036
  /* @__PURE__ */ jsxs29(Box29, { children: [
5959
- /* @__PURE__ */ jsx55(Text29, { bold: true, children: project.displayName }),
5960
- /* @__PURE__ */ jsx55(Text29, { dimColor: true, children: ` (${project.name})` })
6037
+ /* @__PURE__ */ jsx56(Text29, { bold: true, children: project.displayName }),
6038
+ /* @__PURE__ */ jsx56(Text29, { dimColor: true, children: ` (${project.name})` })
5961
6039
  ] }),
5962
- /* @__PURE__ */ jsx55(Box29, { marginTop: spacing.section, children: /* @__PURE__ */ jsx55(
6040
+ /* @__PURE__ */ jsx56(Box29, { marginTop: spacing.section, children: /* @__PURE__ */ jsx56(
5963
6041
  FieldList,
5964
6042
  {
5965
6043
  fields: [
@@ -5971,24 +6049,24 @@ function renderBody25(state) {
5971
6049
  }
5972
6050
  ) }),
5973
6051
  /* @__PURE__ */ jsxs29(Box29, { marginTop: spacing.section, flexDirection: "column", children: [
5974
- /* @__PURE__ */ jsx55(Text29, { color: inkColors.muted, bold: true, children: "Repositories" }),
6052
+ /* @__PURE__ */ jsx56(Text29, { color: inkColors.muted, bold: true, children: "Repositories" }),
5975
6053
  project.repositories.map((r) => /* @__PURE__ */ jsxs29(Box29, { paddingLeft: spacing.indent, children: [
5976
6054
  /* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
5977
6055
  glyphs.bulletListItem,
5978
6056
  " "
5979
6057
  ] }),
5980
- /* @__PURE__ */ jsx55(Text29, { children: r.name }),
5981
- /* @__PURE__ */ jsx55(Text29, { dimColor: true, children: ` ${r.path} ` }),
5982
- /* @__PURE__ */ jsx55(Text29, { dimColor: true, children: `(id: ${r.id})` })
6058
+ /* @__PURE__ */ jsx56(Text29, { children: r.name }),
6059
+ /* @__PURE__ */ jsx56(Text29, { dimColor: true, children: ` ${r.path} ` }),
6060
+ /* @__PURE__ */ jsx56(Text29, { dimColor: true, children: `(id: ${r.id})` })
5983
6061
  ] }, r.id))
5984
6062
  ] })
5985
6063
  ] });
5986
6064
  }
5987
6065
 
5988
6066
  // src/integration/ui/tui/views/browse/doctor-view.tsx
5989
- import { useEffect as useEffect23, useState as useState23 } from "react";
6067
+ import { useEffect as useEffect29, useState as useState29 } from "react";
5990
6068
  import { Box as Box30, Text as Text30 } from "ink";
5991
- import { jsx as jsx56, jsxs as jsxs30 } from "react/jsx-runtime";
6069
+ import { jsx as jsx57, jsxs as jsxs30 } from "react/jsx-runtime";
5992
6070
  var TITLE28 = "Doctor";
5993
6071
  var HINTS2 = [];
5994
6072
  var MIN_LABEL_WIDTH = 20;
@@ -6040,16 +6118,16 @@ function labelWidth(rows) {
6040
6118
  function Row({ row, width }) {
6041
6119
  const dim = row.result.status === "skip";
6042
6120
  return /* @__PURE__ */ jsxs30(Box30, { children: [
6043
- /* @__PURE__ */ jsx56(Text30, { color: color(row.result.status), bold: true, children: glyph(row.result.status) }),
6044
- /* @__PURE__ */ jsx56(Text30, { children: ` ` }),
6045
- /* @__PURE__ */ jsx56(Text30, { bold: true, dimColor: dim, children: row.name.padEnd(width + 2) }),
6046
- /* @__PURE__ */ jsx56(Text30, { dimColor: true, children: row.result.detail ?? row.result.status.toUpperCase() })
6121
+ /* @__PURE__ */ jsx57(Text30, { color: color(row.result.status), bold: true, children: glyph(row.result.status) }),
6122
+ /* @__PURE__ */ jsx57(Text30, { children: ` ` }),
6123
+ /* @__PURE__ */ jsx57(Text30, { bold: true, dimColor: dim, children: row.name.padEnd(width + 2) }),
6124
+ /* @__PURE__ */ jsx57(Text30, { dimColor: true, children: row.result.detail ?? row.result.status.toUpperCase() })
6047
6125
  ] });
6048
6126
  }
6049
6127
  function DoctorView() {
6050
- const [state, setState] = useState23({ kind: "running" });
6128
+ const [state, setState] = useState29({ kind: "running" });
6051
6129
  useViewHints(HINTS2);
6052
- useEffect23(() => {
6130
+ useEffect29(() => {
6053
6131
  const ctl = { cancelled: false };
6054
6132
  void (async () => {
6055
6133
  const sections = await runChecks();
@@ -6060,9 +6138,9 @@ function DoctorView() {
6060
6138
  };
6061
6139
  }, []);
6062
6140
  if (state.kind === "running") {
6063
- return /* @__PURE__ */ jsx56(ViewShell, { title: TITLE28, children: /* @__PURE__ */ jsx56(Spinner, { label: "Running environment checks\u2026" }) });
6141
+ return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE28, children: /* @__PURE__ */ jsx57(Spinner, { label: "Running environment checks\u2026" }) });
6064
6142
  }
6065
- return /* @__PURE__ */ jsx56(ViewShell, { title: TITLE28, children: state.sections.map((section, i) => {
6143
+ return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE28, children: state.sections.map((section, i) => {
6066
6144
  const width = labelWidth(section.rows);
6067
6145
  const passed = section.rows.filter((r) => r.result.status === "pass").length;
6068
6146
  const warned = section.rows.filter((r) => r.result.status === "warn").length;
@@ -6070,28 +6148,28 @@ function DoctorView() {
6070
6148
  const total = section.rows.filter((r) => r.result.status !== "skip").length;
6071
6149
  const summary = `${String(passed)}/${String(total)} pass${warned > 0 ? ` \xB7 ${String(warned)} warn` : ""}${failed > 0 ? ` \xB7 ${String(failed)} fail` : ""}`;
6072
6150
  return /* @__PURE__ */ jsxs30(Box30, { flexDirection: "column", children: [
6073
- i === 0 ? null : /* @__PURE__ */ jsx56(Box30, { marginTop: spacing.section }),
6151
+ i === 0 ? null : /* @__PURE__ */ jsx57(Box30, { marginTop: spacing.section }),
6074
6152
  /* @__PURE__ */ jsxs30(Box30, { children: [
6075
- /* @__PURE__ */ jsx56(Text30, { color: inkColors.primary, bold: true, children: section.title.toUpperCase() }),
6076
- /* @__PURE__ */ jsx56(Text30, { color: inkColors.muted, children: ` ${glyphs.emDash} ` }),
6077
- /* @__PURE__ */ jsx56(Text30, { color: inkColors.muted, children: summary })
6153
+ /* @__PURE__ */ jsx57(Text30, { color: inkColors.primary, bold: true, children: section.title.toUpperCase() }),
6154
+ /* @__PURE__ */ jsx57(Text30, { color: inkColors.muted, children: ` ${glyphs.emDash} ` }),
6155
+ /* @__PURE__ */ jsx57(Text30, { color: inkColors.muted, children: summary })
6078
6156
  ] }),
6079
- /* @__PURE__ */ jsx56(Box30, { marginTop: spacing.section, flexDirection: "column", children: section.rows.map((row) => /* @__PURE__ */ jsx56(Row, { row, width }, row.name)) })
6157
+ /* @__PURE__ */ jsx57(Box30, { marginTop: spacing.section, flexDirection: "column", children: section.rows.map((row) => /* @__PURE__ */ jsx57(Row, { row, width }, row.name)) })
6080
6158
  ] }, section.title);
6081
6159
  }) });
6082
6160
  }
6083
6161
 
6084
6162
  // src/integration/ui/tui/views/browse/progress-show-view.tsx
6085
- import { useEffect as useEffect24, useState as useState24 } from "react";
6163
+ import { useEffect as useEffect30, useState as useState30 } from "react";
6086
6164
  import { Box as Box31, Text as Text31 } from "ink";
6087
- import { jsx as jsx57, jsxs as jsxs31 } from "react/jsx-runtime";
6165
+ import { jsx as jsx58, jsxs as jsxs31 } from "react/jsx-runtime";
6088
6166
  var MAX_TAIL = 80;
6089
6167
  var TITLE29 = "Progress Log";
6090
6168
  var HINTS3 = [];
6091
6169
  function ProgressShowView({ sprintId } = {}) {
6092
- const [state, setState] = useState24({ kind: "loading" });
6170
+ const [state, setState] = useState30({ kind: "loading" });
6093
6171
  useViewHints(HINTS3);
6094
- useEffect24(() => {
6172
+ useEffect30(() => {
6095
6173
  const ctl = { cancelled: false };
6096
6174
  void (async () => {
6097
6175
  try {
@@ -6107,7 +6185,7 @@ function ProgressShowView({ sprintId } = {}) {
6107
6185
  ctl.cancelled = true;
6108
6186
  };
6109
6187
  }, [sprintId]);
6110
- return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE29, children: state.kind === "loading" ? /* @__PURE__ */ jsx57(Spinner, { label: "Loading progress\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx57(ResultCard, { kind: "info", title: "No progress entries yet" }) : state.kind === "error" ? /* @__PURE__ */ jsx57(ResultCard, { kind: "error", title: "Could not load progress", lines: [state.message] }) : renderContent(state.content) });
6188
+ return /* @__PURE__ */ jsx58(ViewShell, { title: TITLE29, children: state.kind === "loading" ? /* @__PURE__ */ jsx58(Spinner, { label: "Loading progress\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx58(ResultCard, { kind: "info", title: "No progress entries yet" }) : state.kind === "error" ? /* @__PURE__ */ jsx58(ResultCard, { kind: "error", title: "Could not load progress", lines: [state.message] }) : renderContent(state.content) });
6111
6189
  }
6112
6190
  function renderContent(content) {
6113
6191
  const lines = content.split("\n");
@@ -6120,19 +6198,19 @@ function renderContent(content) {
6120
6198
  String(lines.length),
6121
6199
  " total)"
6122
6200
  ] }) : null,
6123
- tail.map((line2, i) => /* @__PURE__ */ jsx57(Text31, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
6201
+ tail.map((line2, i) => /* @__PURE__ */ jsx58(Text31, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
6124
6202
  ] });
6125
6203
  }
6126
6204
 
6127
6205
  // src/integration/ui/tui/views/workflows/progress-log-view.tsx
6128
- import { useMemo as useMemo32 } from "react";
6129
- import { jsx as jsx58 } from "react/jsx-runtime";
6206
+ import { useMemo as useMemo29 } from "react";
6207
+ import { jsx as jsx59 } from "react/jsx-runtime";
6130
6208
  var TITLE30 = "Log Progress";
6131
- var HINTS_RUNNING22 = [
6209
+ var HINTS_RUNNING18 = [
6132
6210
  { key: "Ctrl+D", action: "submit" },
6133
6211
  { key: "Esc", action: "cancel" }
6134
6212
  ];
6135
- var HINTS_DONE22 = [
6213
+ var HINTS_DONE18 = [
6136
6214
  { key: "Enter", action: "home" },
6137
6215
  { key: "Esc", action: "back" }
6138
6216
  ];
@@ -6155,29 +6233,29 @@ function ProgressLogView() {
6155
6233
  setPhase({ kind: "done" });
6156
6234
  }
6157
6235
  });
6158
- const hints = useMemo32(() => phase.kind === "running" ? HINTS_RUNNING22 : HINTS_DONE22, [phase.kind]);
6236
+ const hints = useMemo29(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
6159
6237
  useViewHints(hints);
6160
- return /* @__PURE__ */ jsx58(ViewShell, { title: TITLE30, children: renderBody26(phase) });
6238
+ return /* @__PURE__ */ jsx59(ViewShell, { title: TITLE30, children: renderBody22(phase) });
6161
6239
  }
6162
- function renderBody26(phase) {
6240
+ function renderBody22(phase) {
6163
6241
  switch (phase.kind) {
6164
6242
  case "running":
6165
- return /* @__PURE__ */ jsx58(Spinner, { label: phase.step === "message" ? "Awaiting progress note\u2026" : "Saving progress note\u2026" });
6243
+ return /* @__PURE__ */ jsx59(Spinner, { label: phase.step === "message" ? "Awaiting progress note\u2026" : "Saving progress note\u2026" });
6166
6244
  case "cancelled":
6167
- return /* @__PURE__ */ jsx58(ResultCard, { kind: "info", title: "No note recorded" });
6245
+ return /* @__PURE__ */ jsx59(ResultCard, { kind: "info", title: "No note recorded" });
6168
6246
  case "error":
6169
- return /* @__PURE__ */ jsx58(ResultCard, { kind: "error", title: "Could not log progress", lines: [phase.message] });
6247
+ return /* @__PURE__ */ jsx59(ResultCard, { kind: "error", title: "Could not log progress", lines: [phase.message] });
6170
6248
  case "done":
6171
- return /* @__PURE__ */ jsx58(ResultCard, { kind: "success", title: "Progress logged" });
6249
+ return /* @__PURE__ */ jsx59(ResultCard, { kind: "success", title: "Progress logged" });
6172
6250
  }
6173
6251
  }
6174
6252
 
6175
6253
  // src/integration/ui/tui/views/workflows/ideate-view.tsx
6176
- import { useMemo as useMemo33 } from "react";
6177
- import { jsx as jsx59 } from "react/jsx-runtime";
6254
+ import { useMemo as useMemo30 } from "react";
6255
+ import { jsx as jsx60 } from "react/jsx-runtime";
6178
6256
  var TITLE31 = "Ideate";
6179
- var HINTS_RUNNING23 = [{ key: "Esc", action: "cancel" }];
6180
- var HINTS_DONE23 = [
6257
+ var HINTS_RUNNING19 = [{ key: "Esc", action: "cancel" }];
6258
+ var HINTS_DONE19 = [
6181
6259
  { key: "Enter", action: "home" },
6182
6260
  { key: "Esc", action: "back" }
6183
6261
  ];
@@ -6231,22 +6309,22 @@ function IdeateView() {
6231
6309
  setPhase({ kind: "done", summary });
6232
6310
  }
6233
6311
  });
6234
- const hints = useMemo33(() => phase.kind === "running" ? HINTS_RUNNING23 : HINTS_DONE23, [phase.kind]);
6312
+ const hints = useMemo30(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
6235
6313
  useViewHints(hints);
6236
- return /* @__PURE__ */ jsx59(ViewShell, { title: TITLE31, children: renderBody27(phase) });
6314
+ return /* @__PURE__ */ jsx60(ViewShell, { title: TITLE31, children: renderBody23(phase) });
6237
6315
  }
6238
- function renderBody27(phase) {
6316
+ function renderBody23(phase) {
6239
6317
  switch (phase.kind) {
6240
6318
  case "running":
6241
- return /* @__PURE__ */ jsx59(Spinner, { label: stepLabel13(phase.step) });
6319
+ return /* @__PURE__ */ jsx60(Spinner, { label: stepLabel9(phase.step) });
6242
6320
  case "no-projects":
6243
- return /* @__PURE__ */ jsx59(ResultCard, { kind: "warning", title: "Register a project first" });
6321
+ return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Register a project first" });
6244
6322
  case "no-draft-sprint":
6245
- return /* @__PURE__ */ jsx59(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
6323
+ return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
6246
6324
  case "error":
6247
- return /* @__PURE__ */ jsx59(ResultCard, { kind: "error", title: "Ideation failed", lines: [phase.message] });
6325
+ return /* @__PURE__ */ jsx60(ResultCard, { kind: "error", title: "Ideation failed", lines: [phase.message] });
6248
6326
  case "done":
6249
- return /* @__PURE__ */ jsx59(
6327
+ return /* @__PURE__ */ jsx60(
6250
6328
  ResultCard,
6251
6329
  {
6252
6330
  kind: "success",
@@ -6260,7 +6338,7 @@ function renderBody27(phase) {
6260
6338
  );
6261
6339
  }
6262
6340
  }
6263
- function stepLabel13(step) {
6341
+ function stepLabel9(step) {
6264
6342
  if (step === "title") return "Awaiting idea title\u2026";
6265
6343
  if (step === "description") return "Awaiting idea description\u2026";
6266
6344
  if (step === "project") return "Awaiting project selection\u2026";
@@ -6268,11 +6346,11 @@ function stepLabel13(step) {
6268
6346
  }
6269
6347
 
6270
6348
  // src/integration/ui/tui/views/onboarding-view.tsx
6271
- import { useMemo as useMemo34 } from "react";
6272
- import { jsx as jsx60 } from "react/jsx-runtime";
6349
+ import { useMemo as useMemo31 } from "react";
6350
+ import { jsx as jsx61 } from "react/jsx-runtime";
6273
6351
  var TITLE32 = "Welcome";
6274
- var HINTS_RUNNING24 = [{ key: "Esc", action: "skip" }];
6275
- var HINTS_DONE24 = [
6352
+ var HINTS_RUNNING20 = [{ key: "Esc", action: "skip" }];
6353
+ var HINTS_DONE20 = [
6276
6354
  { key: "Enter", action: "home" },
6277
6355
  { key: "Esc", action: "home" }
6278
6356
  ];
@@ -6319,31 +6397,31 @@ function OnboardingView() {
6319
6397
  }
6320
6398
  }
6321
6399
  });
6322
- const hints = useMemo34(() => phase.kind === "running" ? HINTS_RUNNING24 : HINTS_DONE24, [phase.kind]);
6400
+ const hints = useMemo31(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
6323
6401
  useViewHints(hints);
6324
- return /* @__PURE__ */ jsx60(ViewShell, { title: TITLE32, children: renderBody28(phase) });
6402
+ return /* @__PURE__ */ jsx61(ViewShell, { title: TITLE32, children: renderBody24(phase) });
6325
6403
  }
6326
- function renderBody28(phase) {
6404
+ function renderBody24(phase) {
6327
6405
  if (phase.kind === "running") {
6328
- return /* @__PURE__ */ jsx60(Spinner, { label: RUNNING_LABEL2[phase.step] });
6406
+ return /* @__PURE__ */ jsx61(Spinner, { label: RUNNING_LABEL2[phase.step] });
6329
6407
  }
6330
6408
  if (phase.kind === "error") {
6331
- return /* @__PURE__ */ jsx60(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
6409
+ return /* @__PURE__ */ jsx61(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
6332
6410
  }
6333
6411
  const providerLabel = phase.provider === "claude" ? "Claude Code" : phase.provider === "copilot" ? "GitHub Copilot" : "Skipped";
6334
6412
  const nextSteps = phase.addingProject ? [{ action: "Finish adding your project", description: "continuing to the project wizard\u2026" }] : [
6335
6413
  { action: "Register a project", description: "Browse \u2192 Projects \u2192 Add" },
6336
6414
  { action: "Create a sprint", description: "once a project exists" }
6337
6415
  ];
6338
- return /* @__PURE__ */ jsx60(ResultCard, { kind: "success", title: "You're set up", fields: [["AI provider", providerLabel]], nextSteps });
6416
+ return /* @__PURE__ */ jsx61(ResultCard, { kind: "success", title: "You're set up", fields: [["AI provider", providerLabel]], nextSteps });
6339
6417
  }
6340
6418
 
6341
6419
  // src/integration/ui/tui/views/workflows/reactivate-sprint-view.tsx
6342
- import { useMemo as useMemo35 } from "react";
6343
- import { jsx as jsx61 } from "react/jsx-runtime";
6420
+ import { useMemo as useMemo32 } from "react";
6421
+ import { jsx as jsx62 } from "react/jsx-runtime";
6344
6422
  var TITLE33 = "Reactivate Sprint";
6345
- var HINTS_RUNNING25 = [{ key: "Esc", action: "cancel" }];
6346
- var HINTS_DONE25 = [
6423
+ var HINTS_RUNNING21 = [{ key: "Esc", action: "cancel" }];
6424
+ var HINTS_DONE21 = [
6347
6425
  { key: "Enter", action: "back" },
6348
6426
  { key: "Esc", action: "back" }
6349
6427
  ];
@@ -6377,22 +6455,22 @@ function ReactivateSprintView({ sprintId }) {
6377
6455
  }
6378
6456
  });
6379
6457
  const running = phase.kind === "running" || phase.kind === "loading";
6380
- const hints = useMemo35(() => running ? HINTS_RUNNING25 : HINTS_DONE25, [running]);
6458
+ const hints = useMemo32(() => running ? HINTS_RUNNING21 : HINTS_DONE21, [running]);
6381
6459
  useViewHints(hints);
6382
- return /* @__PURE__ */ jsx61(ViewShell, { title: TITLE33, children: renderBody29(phase) });
6460
+ return /* @__PURE__ */ jsx62(ViewShell, { title: TITLE33, children: renderBody25(phase) });
6383
6461
  }
6384
- function renderBody29(phase) {
6462
+ function renderBody25(phase) {
6385
6463
  switch (phase.kind) {
6386
6464
  case "loading":
6387
- return /* @__PURE__ */ jsx61(Spinner, { label: "Loading sprint\u2026" });
6465
+ return /* @__PURE__ */ jsx62(Spinner, { label: "Loading sprint\u2026" });
6388
6466
  case "running":
6389
- return /* @__PURE__ */ jsx61(Spinner, { label: phase.step === "confirm" ? "Awaiting confirmation\u2026" : "Reactivating sprint\u2026" });
6467
+ return /* @__PURE__ */ jsx62(Spinner, { label: phase.step === "confirm" ? "Awaiting confirmation\u2026" : "Reactivating sprint\u2026" });
6390
6468
  case "cancelled":
6391
- return /* @__PURE__ */ jsx61(ResultCard, { kind: "info", title: "Reactivation cancelled" });
6469
+ return /* @__PURE__ */ jsx62(ResultCard, { kind: "info", title: "Reactivation cancelled" });
6392
6470
  case "missing-id":
6393
- return /* @__PURE__ */ jsx61(ResultCard, { kind: "error", title: "No sprint ID provided" });
6471
+ return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "No sprint ID provided" });
6394
6472
  case "not-closed":
6395
- return /* @__PURE__ */ jsx61(
6473
+ return /* @__PURE__ */ jsx62(
6396
6474
  ResultCard,
6397
6475
  {
6398
6476
  kind: "warning",
@@ -6401,9 +6479,9 @@ function renderBody29(phase) {
6401
6479
  }
6402
6480
  );
6403
6481
  case "error":
6404
- return /* @__PURE__ */ jsx61(ResultCard, { kind: "error", title: "Could not reactivate sprint", lines: [phase.message] });
6482
+ return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "Could not reactivate sprint", lines: [phase.message] });
6405
6483
  case "done":
6406
- return /* @__PURE__ */ jsx61(
6484
+ return /* @__PURE__ */ jsx62(
6407
6485
  ResultCard,
6408
6486
  {
6409
6487
  kind: "success",
@@ -6419,8 +6497,8 @@ function renderBody29(phase) {
6419
6497
  }
6420
6498
 
6421
6499
  // src/integration/ui/tui/views/browse/evaluations-view.tsx
6422
- import { useEffect as useEffect25, useState as useState25 } from "react";
6423
- import { jsx as jsx62 } from "react/jsx-runtime";
6500
+ import { useEffect as useEffect31, useState as useState31 } from "react";
6501
+ import { jsx as jsx63 } from "react/jsx-runtime";
6424
6502
  var TITLE34 = "Evaluations";
6425
6503
  var HINTS4 = [
6426
6504
  { key: "\u2191/\u2193", action: "navigate" },
@@ -6452,9 +6530,9 @@ var COLUMNS2 = [
6452
6530
  ];
6453
6531
  function EvaluationsView({ sprintId }) {
6454
6532
  const router = useRouter();
6455
- const [state, setState] = useState25({ kind: "loading" });
6533
+ const [state, setState] = useState31({ kind: "loading" });
6456
6534
  useViewHints(HINTS4);
6457
- useEffect25(() => {
6535
+ useEffect31(() => {
6458
6536
  const ctl = { cancelled: false };
6459
6537
  void (async () => {
6460
6538
  try {
@@ -6473,7 +6551,7 @@ function EvaluationsView({ sprintId }) {
6473
6551
  ctl.cancelled = true;
6474
6552
  };
6475
6553
  }, [sprintId]);
6476
- return /* @__PURE__ */ jsx62(ViewShell, { title: TITLE34, children: state.kind === "loading" ? /* @__PURE__ */ jsx62(Spinner, { label: "Loading evaluations\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx62(ResultCard, { kind: "info", title: "No evaluations yet", lines: ["Run the executor to collect evaluator output."] }) : state.kind === "error" ? /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "Could not load evaluations", lines: [state.message] }) : /* @__PURE__ */ jsx62(
6554
+ return /* @__PURE__ */ jsx63(ViewShell, { title: TITLE34, children: state.kind === "loading" ? /* @__PURE__ */ jsx63(Spinner, { label: "Loading evaluations\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx63(ResultCard, { kind: "info", title: "No evaluations yet", lines: ["Run the executor to collect evaluator output."] }) : state.kind === "error" ? /* @__PURE__ */ jsx63(ResultCard, { kind: "error", title: "Could not load evaluations", lines: [state.message] }) : /* @__PURE__ */ jsx63(
6477
6555
  ListView,
6478
6556
  {
6479
6557
  rows: state.tasks,
@@ -6486,9 +6564,9 @@ function EvaluationsView({ sprintId }) {
6486
6564
  }
6487
6565
 
6488
6566
  // src/integration/ui/tui/views/browse/evaluation-show-view.tsx
6489
- import { useEffect as useEffect26, useState as useState26 } from "react";
6567
+ import { useEffect as useEffect32, useState as useState32 } from "react";
6490
6568
  import { Box as Box32, Text as Text32 } from "ink";
6491
- import { jsx as jsx63, jsxs as jsxs32 } from "react/jsx-runtime";
6569
+ import { jsx as jsx64, jsxs as jsxs32 } from "react/jsx-runtime";
6492
6570
  var TITLE35 = "Evaluation";
6493
6571
  var HINTS5 = [];
6494
6572
  var MAX_LINES = 200;
@@ -6498,9 +6576,9 @@ function kindFor(status) {
6498
6576
  return "warning";
6499
6577
  }
6500
6578
  function EvaluationShowView({ sprintId, taskId }) {
6501
- const [state, setState] = useState26({ kind: "loading" });
6579
+ const [state, setState] = useState32({ kind: "loading" });
6502
6580
  useViewHints(HINTS5);
6503
- useEffect26(() => {
6581
+ useEffect32(() => {
6504
6582
  const ctl = { cancelled: false };
6505
6583
  void (async () => {
6506
6584
  try {
@@ -6520,22 +6598,22 @@ function EvaluationShowView({ sprintId, taskId }) {
6520
6598
  ctl.cancelled = true;
6521
6599
  };
6522
6600
  }, [sprintId, taskId]);
6523
- return /* @__PURE__ */ jsx63(ViewShell, { title: TITLE35, children: renderBody30(state) });
6601
+ return /* @__PURE__ */ jsx64(ViewShell, { title: TITLE35, children: renderBody26(state) });
6524
6602
  }
6525
- function renderBody30(state) {
6526
- if (state.kind === "loading") return /* @__PURE__ */ jsx63(Spinner, { label: "Loading evaluation\u2026" });
6603
+ function renderBody26(state) {
6604
+ if (state.kind === "loading") return /* @__PURE__ */ jsx64(Spinner, { label: "Loading evaluation\u2026" });
6527
6605
  if (state.kind === "error")
6528
- return /* @__PURE__ */ jsx63(ResultCard, { kind: "error", title: "Could not load evaluation", lines: [state.message] });
6606
+ return /* @__PURE__ */ jsx64(ResultCard, { kind: "error", title: "Could not load evaluation", lines: [state.message] });
6529
6607
  const { task, content } = state;
6530
6608
  const lines = content.split("\n");
6531
6609
  const tail = lines.length > MAX_LINES ? lines.slice(-MAX_LINES) : lines;
6532
6610
  return /* @__PURE__ */ jsxs32(Box32, { flexDirection: "column", children: [
6533
6611
  /* @__PURE__ */ jsxs32(Box32, { children: [
6534
- /* @__PURE__ */ jsx63(Text32, { bold: true, children: task.name }),
6535
- /* @__PURE__ */ jsx63(Text32, { children: " " }),
6536
- /* @__PURE__ */ jsx63(StatusChip, { label: task.evaluationStatus ?? "unknown", kind: kindFor(task.evaluationStatus) })
6612
+ /* @__PURE__ */ jsx64(Text32, { bold: true, children: task.name }),
6613
+ /* @__PURE__ */ jsx64(Text32, { children: " " }),
6614
+ /* @__PURE__ */ jsx64(StatusChip, { label: task.evaluationStatus ?? "unknown", kind: kindFor(task.evaluationStatus) })
6537
6615
  ] }),
6538
- content.trim().length === 0 ? /* @__PURE__ */ jsx63(Box32, { marginTop: spacing.section, children: /* @__PURE__ */ jsx63(Text32, { color: inkColors.muted, children: "No evaluator output recorded." }) }) : /* @__PURE__ */ jsxs32(Box32, { marginTop: spacing.section, flexDirection: "column", children: [
6616
+ content.trim().length === 0 ? /* @__PURE__ */ jsx64(Box32, { marginTop: spacing.section, children: /* @__PURE__ */ jsx64(Text32, { color: inkColors.muted, children: "No evaluator output recorded." }) }) : /* @__PURE__ */ jsxs32(Box32, { marginTop: spacing.section, flexDirection: "column", children: [
6539
6617
  lines.length > MAX_LINES ? /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
6540
6618
  "Showing last ",
6541
6619
  String(MAX_LINES),
@@ -6543,21 +6621,21 @@ function renderBody30(state) {
6543
6621
  String(lines.length),
6544
6622
  " total)"
6545
6623
  ] }) : null,
6546
- tail.map((line2, i) => /* @__PURE__ */ jsx63(Text32, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
6624
+ tail.map((line2, i) => /* @__PURE__ */ jsx64(Text32, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
6547
6625
  ] })
6548
6626
  ] });
6549
6627
  }
6550
6628
 
6551
6629
  // src/integration/ui/tui/views/browse/feedback-view.tsx
6552
- import { useEffect as useEffect27, useState as useState27 } from "react";
6630
+ import { useEffect as useEffect33, useState as useState33 } from "react";
6553
6631
  import { Box as Box33, Text as Text33 } from "ink";
6554
- import { jsx as jsx64, jsxs as jsxs33 } from "react/jsx-runtime";
6632
+ import { jsx as jsx65, jsxs as jsxs33 } from "react/jsx-runtime";
6555
6633
  var TITLE36 = "Feedback";
6556
6634
  var HINTS6 = [];
6557
6635
  function FeedbackView({ sprintId }) {
6558
- const [state, setState] = useState27({ kind: "loading" });
6636
+ const [state, setState] = useState33({ kind: "loading" });
6559
6637
  useViewHints(HINTS6);
6560
- useEffect27(() => {
6638
+ useEffect33(() => {
6561
6639
  const ctl = { cancelled: false };
6562
6640
  void (async () => {
6563
6641
  try {
@@ -6574,16 +6652,16 @@ function FeedbackView({ sprintId }) {
6574
6652
  ctl.cancelled = true;
6575
6653
  };
6576
6654
  }, [sprintId]);
6577
- return /* @__PURE__ */ jsx64(ViewShell, { title: TITLE36, children: state.kind === "loading" ? /* @__PURE__ */ jsx64(Spinner, { label: "Loading feedback\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx64(
6655
+ return /* @__PURE__ */ jsx65(ViewShell, { title: TITLE36, children: state.kind === "loading" ? /* @__PURE__ */ jsx65(Spinner, { label: "Loading feedback\u2026" }) : state.kind === "empty" ? /* @__PURE__ */ jsx65(
6578
6656
  ResultCard,
6579
6657
  {
6580
6658
  kind: "info",
6581
6659
  title: "No feedback yet",
6582
6660
  lines: ["Feedback is captured during the post-execution loop."]
6583
6661
  }
6584
- ) : state.kind === "error" ? /* @__PURE__ */ jsx64(ResultCard, { kind: "error", title: "Could not load feedback", lines: [state.message] }) : /* @__PURE__ */ jsx64(Box33, { flexDirection: "column", children: state.entries.map((entry, i) => /* @__PURE__ */ jsxs33(Box33, { marginTop: i === 0 ? 0 : spacing.section, flexDirection: "column", children: [
6585
- /* @__PURE__ */ jsx64(Text33, { color: inkColors.muted, bold: true, children: entry.timestamp }),
6586
- /* @__PURE__ */ jsx64(Text33, { children: entry.preview })
6662
+ ) : state.kind === "error" ? /* @__PURE__ */ jsx65(ResultCard, { kind: "error", title: "Could not load feedback", lines: [state.message] }) : /* @__PURE__ */ jsx65(Box33, { flexDirection: "column", children: state.entries.map((entry, i) => /* @__PURE__ */ jsxs33(Box33, { marginTop: i === 0 ? 0 : spacing.section, flexDirection: "column", children: [
6663
+ /* @__PURE__ */ jsx65(Text33, { color: inkColors.muted, bold: true, children: entry.timestamp }),
6664
+ /* @__PURE__ */ jsx65(Text33, { children: entry.preview })
6587
6665
  ] }, i)) }) });
6588
6666
  }
6589
6667
  function extractFeedback(progress) {
@@ -6601,14 +6679,215 @@ function extractFeedback(progress) {
6601
6679
  return out;
6602
6680
  }
6603
6681
 
6682
+ // src/integration/ui/tui/views/running-executions-view.tsx
6683
+ import { useCallback as useCallback11, useEffect as useEffect34, useMemo as useMemo33, useState as useState34 } from "react";
6684
+ import { Box as Box34, Text as Text34, useInput as useInput21 } from "ink";
6685
+ import { jsx as jsx66, jsxs as jsxs34 } from "react/jsx-runtime";
6686
+ var HINTS_POPULATED = [
6687
+ { key: "\u2191/\u2193", action: "navigate" },
6688
+ { key: "Enter", action: "open" },
6689
+ { key: "X", action: "cancel" },
6690
+ { key: "Esc", action: "back" }
6691
+ ];
6692
+ var HINTS_EMPTY7 = [{ key: "Esc", action: "back" }];
6693
+ function formatRelativeTime(from, now = /* @__PURE__ */ new Date()) {
6694
+ const deltaMs = Math.max(0, now.getTime() - from.getTime());
6695
+ const seconds = Math.floor(deltaMs / 1e3);
6696
+ if (seconds < 60) return `${String(seconds)}s ago`;
6697
+ const minutes = Math.floor(seconds / 60);
6698
+ if (minutes < 60) return `${String(minutes)}m ago`;
6699
+ const hours = Math.floor(minutes / 60);
6700
+ if (hours < 24) return `${String(hours)}h ago`;
6701
+ const days = Math.floor(hours / 24);
6702
+ return `${String(days)}d ago`;
6703
+ }
6704
+ function statusColor6(kind) {
6705
+ const map = {
6706
+ info: inkColors.info,
6707
+ success: inkColors.success,
6708
+ warning: inkColors.warning,
6709
+ error: inkColors.error,
6710
+ muted: inkColors.muted
6711
+ };
6712
+ return map[kind];
6713
+ }
6714
+ function buildColumns4(now) {
6715
+ return [
6716
+ {
6717
+ header: "Status",
6718
+ cell: (e) => `[${e.status.toUpperCase()}]`,
6719
+ color: (e) => statusColor6(chipKindForExecutionStatus(e.status)),
6720
+ width: 12
6721
+ },
6722
+ { header: "Project", cell: (e) => e.projectName, width: 20 },
6723
+ { header: "Sprint", cell: (e) => e.sprint.name, flex: true },
6724
+ {
6725
+ header: "Started",
6726
+ cell: (e) => formatRelativeTime(e.startedAt, now),
6727
+ width: 10,
6728
+ align: "right"
6729
+ }
6730
+ ];
6731
+ }
6732
+ function RunningExecutionsView() {
6733
+ const router = useRouter();
6734
+ const shared = getSharedDeps();
6735
+ const registry = shared.executionRegistry;
6736
+ const executions = useRegistryEvents(registry);
6737
+ const [cursor, setCursor] = useState34(0);
6738
+ const rows = useMemo33(() => {
6739
+ return [...executions].sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
6740
+ }, [executions]);
6741
+ const [now, setNow] = useState34(() => /* @__PURE__ */ new Date());
6742
+ useEffect34(() => {
6743
+ const interval = setInterval(() => {
6744
+ setNow(/* @__PURE__ */ new Date());
6745
+ }, 1e3);
6746
+ return () => {
6747
+ clearInterval(interval);
6748
+ };
6749
+ }, []);
6750
+ const columns = useMemo33(() => buildColumns4(now), [now]);
6751
+ const handleSelect = useCallback11(
6752
+ (execution) => {
6753
+ router.push({
6754
+ id: "execute",
6755
+ props: { sprintId: execution.sprintId, executionId: execution.id }
6756
+ });
6757
+ },
6758
+ [router]
6759
+ );
6760
+ const handleCursorChange = useCallback11((_row, index) => {
6761
+ setCursor(index);
6762
+ }, []);
6763
+ useViewHints(rows.length > 0 ? HINTS_POPULATED : HINTS_EMPTY7);
6764
+ useInput21((input) => {
6765
+ if (rows.length === 0) return;
6766
+ if (input !== "X") return;
6767
+ const target = rows[cursor];
6768
+ if (target?.status === "running") {
6769
+ registry.cancel(target.id);
6770
+ }
6771
+ });
6772
+ if (rows.length === 0) {
6773
+ return /* @__PURE__ */ jsx66(ViewShell, { title: "Running Executions", children: /* @__PURE__ */ jsx66(
6774
+ ResultCard,
6775
+ {
6776
+ kind: "info",
6777
+ title: "No backgrounded executions",
6778
+ lines: ["Start a sprint from home to see it here while it runs."],
6779
+ nextSteps: [{ action: "Press h to return home", description: "Then pick a sprint and start it." }]
6780
+ }
6781
+ ) });
6782
+ }
6783
+ return /* @__PURE__ */ jsx66(ViewShell, { title: "Running Executions", children: /* @__PURE__ */ jsxs34(Box34, { flexDirection: "column", children: [
6784
+ /* @__PURE__ */ jsx66(
6785
+ ListView,
6786
+ {
6787
+ rows,
6788
+ columns,
6789
+ onSelect: handleSelect,
6790
+ onCursorChange: handleCursorChange,
6791
+ emptyLabel: "No executions"
6792
+ }
6793
+ ),
6794
+ /* @__PURE__ */ jsx66(Box34, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs34(Text34, { dimColor: true, children: [
6795
+ rows.length,
6796
+ " execution",
6797
+ rows.length === 1 ? "" : "s",
6798
+ " tracked this session."
6799
+ ] }) })
6800
+ ] }) });
6801
+ }
6802
+
6803
+ // src/integration/ui/tui/components/execution-notification-banner.tsx
6804
+ import { useEffect as useEffect35, useRef as useRef4, useState as useState35 } from "react";
6805
+ import { Box as Box35, Text as Text35 } from "ink";
6806
+ import { jsx as jsx67, jsxs as jsxs35 } from "react/jsx-runtime";
6807
+ function isTerminal(status) {
6808
+ return status !== "running";
6809
+ }
6810
+ function isNotifiable(status) {
6811
+ return status === "completed" || status === "failed";
6812
+ }
6813
+ function bannerColor(status) {
6814
+ if (status === "completed") return inkColors.success;
6815
+ if (status === "failed") return inkColors.error;
6816
+ return inkColors.muted;
6817
+ }
6818
+ function bannerGlyph(status) {
6819
+ if (status === "completed") return glyphs.check;
6820
+ if (status === "failed") return glyphs.cross;
6821
+ return glyphs.warningGlyph;
6822
+ }
6823
+ function bannerLabel(status) {
6824
+ if (status === "completed") return "DONE";
6825
+ if (status === "failed") return "FAILED";
6826
+ return "ENDED";
6827
+ }
6828
+ function ExecutionNotificationBanner({ currentViewId, registry }) {
6829
+ const executions = useRegistryEvents(registry);
6830
+ const shownRef = useRef4(/* @__PURE__ */ new Set());
6831
+ const visitedRef = useRef4(/* @__PURE__ */ new Set());
6832
+ const [pending, setPending] = useState35(null);
6833
+ useEffect35(() => {
6834
+ if (currentViewId === "running-executions") {
6835
+ for (const e of executions) {
6836
+ if (isTerminal(e.status)) visitedRef.current.add(e.id);
6837
+ }
6838
+ if (pending && visitedRef.current.has(pending.id)) {
6839
+ setPending(null);
6840
+ }
6841
+ }
6842
+ }, [currentViewId, executions, pending]);
6843
+ useEffect35(() => {
6844
+ for (const e of executions) {
6845
+ if (!isTerminal(e.status)) continue;
6846
+ if (!isNotifiable(e.status)) continue;
6847
+ if (shownRef.current.has(e.id)) continue;
6848
+ if (visitedRef.current.has(e.id)) {
6849
+ shownRef.current.add(e.id);
6850
+ continue;
6851
+ }
6852
+ shownRef.current.add(e.id);
6853
+ setPending(e);
6854
+ break;
6855
+ }
6856
+ }, [executions]);
6857
+ if (!pending) return null;
6858
+ const color2 = bannerColor(pending.status);
6859
+ const icon = bannerGlyph(pending.status);
6860
+ const label = bannerLabel(pending.status);
6861
+ return /* @__PURE__ */ jsxs35(Box35, { borderStyle: "round", borderColor: color2, paddingX: spacing.cardPadX, marginBottom: spacing.section, children: [
6862
+ /* @__PURE__ */ jsxs35(Text35, { color: color2, bold: true, children: [
6863
+ icon,
6864
+ " "
6865
+ ] }),
6866
+ /* @__PURE__ */ jsxs35(Text35, { bold: true, children: [
6867
+ pending.projectName,
6868
+ " ",
6869
+ glyphs.inlineDot,
6870
+ " ",
6871
+ pending.sprint.name
6872
+ ] }),
6873
+ /* @__PURE__ */ jsxs35(Text35, { color: color2, bold: true, children: [
6874
+ " ",
6875
+ label
6876
+ ] }),
6877
+ /* @__PURE__ */ jsx67(Text35, { dimColor: true, children: ` ${glyphs.emDash} press ` }),
6878
+ /* @__PURE__ */ jsx67(Text35, { bold: true, children: "x" }),
6879
+ /* @__PURE__ */ jsx67(Text35, { dimColor: true, children: " for the runs list" })
6880
+ ] });
6881
+ }
6882
+
6604
6883
  // src/integration/ui/tui/components/version-hint.tsx
6605
- import { useEffect as useEffect28, useState as useState28 } from "react";
6606
- import { Text as Text34 } from "ink";
6884
+ import { useEffect as useEffect36, useState as useState36 } from "react";
6885
+ import { Text as Text36 } from "ink";
6607
6886
 
6608
6887
  // src/integration/external/version-check.ts
6609
6888
  import { mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
6610
6889
  import { dirname, join as join3 } from "path";
6611
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
6890
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
6612
6891
  var FETCH_TIMEOUT_MS = 3e3;
6613
6892
  var REGISTRY_URL = "https://registry.npmjs.org/ralphctl/latest";
6614
6893
  function getCachePath() {
@@ -6691,10 +6970,10 @@ async function checkLatestVersion() {
6691
6970
  }
6692
6971
 
6693
6972
  // src/integration/ui/tui/components/version-hint.tsx
6694
- import { jsx as jsx65 } from "react/jsx-runtime";
6973
+ import { jsx as jsx68 } from "react/jsx-runtime";
6695
6974
  function VersionHint() {
6696
- const [check, setCheck] = useState28(null);
6697
- useEffect28(() => {
6975
+ const [check, setCheck] = useState36(null);
6976
+ useEffect36(() => {
6698
6977
  let cancelled = false;
6699
6978
  void checkLatestVersion().then((result) => {
6700
6979
  if (!cancelled && result !== null) setCheck(result);
@@ -6704,175 +6983,180 @@ function VersionHint() {
6704
6983
  };
6705
6984
  }, []);
6706
6985
  if (!check?.updateAvailable) return null;
6707
- return /* @__PURE__ */ jsx65(Text34, { dimColor: true, children: `v${check.latest} available \xB7 npm install -g ralphctl` });
6986
+ return /* @__PURE__ */ jsx68(Text36, { dimColor: true, children: `v${check.latest} available \xB7 npm install -g ralphctl` });
6708
6987
  }
6709
6988
 
6710
6989
  // src/integration/ui/tui/views/view-router.tsx
6711
- import { jsx as jsx66, jsxs as jsxs34 } from "react/jsx-runtime";
6990
+ import { jsx as jsx69, jsxs as jsxs36 } from "react/jsx-runtime";
6712
6991
  var views = {
6713
6992
  home: {
6714
6993
  label: "Home",
6715
- render: () => /* @__PURE__ */ jsx66(HomeView, {})
6994
+ render: () => /* @__PURE__ */ jsx69(HomeView, {})
6716
6995
  },
6717
6996
  settings: {
6718
6997
  label: "Settings",
6719
- render: () => /* @__PURE__ */ jsx66(SettingsView, {})
6998
+ render: () => /* @__PURE__ */ jsx69(SettingsView, {})
6720
6999
  },
6721
7000
  execute: {
6722
7001
  label: "Execute",
6723
7002
  render: (props) => {
6724
7003
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
7004
+ const executionId = typeof props["executionId"] === "string" ? props["executionId"] : void 0;
6725
7005
  const executionOptions = props["executionOptions"];
6726
- return /* @__PURE__ */ jsx66(ExecuteView, { sprintId, executionOptions });
7006
+ return /* @__PURE__ */ jsx69(ExecuteView, { sprintId, executionId, executionOptions });
6727
7007
  }
6728
7008
  },
6729
7009
  dashboard: {
6730
7010
  label: "Dashboard",
6731
- render: () => /* @__PURE__ */ jsx66(DashboardView, {})
7011
+ render: () => /* @__PURE__ */ jsx69(DashboardView, {})
7012
+ },
7013
+ "running-executions": {
7014
+ label: "Runs",
7015
+ render: () => /* @__PURE__ */ jsx69(RunningExecutionsView, {})
6732
7016
  },
6733
7017
  "refine-phase": {
6734
7018
  label: "Refine",
6735
7019
  render: (props) => {
6736
7020
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
6737
- return /* @__PURE__ */ jsx66(RefinePhaseView, { sprintId });
7021
+ return /* @__PURE__ */ jsx69(RefinePhaseView, { sprintId });
6738
7022
  }
6739
7023
  },
6740
7024
  "plan-phase": {
6741
7025
  label: "Plan",
6742
7026
  render: (props) => {
6743
7027
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
6744
- return /* @__PURE__ */ jsx66(PlanPhaseView, { sprintId });
7028
+ return /* @__PURE__ */ jsx69(PlanPhaseView, { sprintId });
6745
7029
  }
6746
7030
  },
6747
7031
  "close-phase": {
6748
7032
  label: "Close",
6749
7033
  render: (props) => {
6750
7034
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
6751
- return /* @__PURE__ */ jsx66(ClosePhaseView, { sprintId });
7035
+ return /* @__PURE__ */ jsx69(ClosePhaseView, { sprintId });
6752
7036
  }
6753
7037
  },
6754
7038
  "sprint-create": {
6755
7039
  label: "Create Sprint",
6756
- render: () => /* @__PURE__ */ jsx66(CreateSprintView, {})
7040
+ render: () => /* @__PURE__ */ jsx69(CreateSprintView, {})
6757
7041
  },
6758
7042
  "sprint-delete": {
6759
7043
  label: "Delete Sprint",
6760
7044
  render: (props) => {
6761
7045
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6762
- return /* @__PURE__ */ jsx66(DeleteSprintView, { sprintId });
7046
+ return /* @__PURE__ */ jsx69(DeleteSprintView, { sprintId });
6763
7047
  }
6764
7048
  },
6765
7049
  "sprint-set-current": {
6766
7050
  label: "Set Current",
6767
- render: () => /* @__PURE__ */ jsx66(SetCurrentSprintView, {})
7051
+ render: () => /* @__PURE__ */ jsx69(SetCurrentSprintView, {})
6768
7052
  },
6769
7053
  "sprint-requirements-export": {
6770
7054
  label: "Requirements",
6771
7055
  render: (props) => {
6772
7056
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6773
- return /* @__PURE__ */ jsx66(RequirementsExportView, { sprintId });
7057
+ return /* @__PURE__ */ jsx69(RequirementsExportView, { sprintId });
6774
7058
  }
6775
7059
  },
6776
7060
  "sprint-context-export": {
6777
7061
  label: "Context",
6778
7062
  render: (props) => {
6779
7063
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6780
- return /* @__PURE__ */ jsx66(ContextExportView, { sprintId });
7064
+ return /* @__PURE__ */ jsx69(ContextExportView, { sprintId });
6781
7065
  }
6782
7066
  },
6783
7067
  "ticket-add": {
6784
7068
  label: "Add Ticket",
6785
- render: () => /* @__PURE__ */ jsx66(TicketAddView, {})
7069
+ render: () => /* @__PURE__ */ jsx69(TicketAddView, {})
6786
7070
  },
6787
7071
  "ticket-edit": {
6788
7072
  label: "Edit Ticket",
6789
7073
  render: (props) => {
6790
7074
  const ticketId = typeof props["ticketId"] === "string" ? props["ticketId"] : void 0;
6791
- return /* @__PURE__ */ jsx66(TicketEditView, { ticketId });
7075
+ return /* @__PURE__ */ jsx69(TicketEditView, { ticketId });
6792
7076
  }
6793
7077
  },
6794
7078
  "ticket-remove": {
6795
7079
  label: "Remove Ticket",
6796
- render: () => /* @__PURE__ */ jsx66(TicketRemoveView, {})
7080
+ render: () => /* @__PURE__ */ jsx69(TicketRemoveView, {})
6797
7081
  },
6798
7082
  "ticket-refine": {
6799
7083
  label: "Re-Refine Ticket",
6800
- render: () => /* @__PURE__ */ jsx66(TicketRefineView, {})
7084
+ render: () => /* @__PURE__ */ jsx69(TicketRefineView, {})
6801
7085
  },
6802
- "task-add": { label: "Add Task", render: () => /* @__PURE__ */ jsx66(TaskAddView, {}) },
6803
- "task-import": { label: "Import Tasks", render: () => /* @__PURE__ */ jsx66(TaskImportView, {}) },
6804
- "task-status": { label: "Task Status", render: () => /* @__PURE__ */ jsx66(TaskStatusView, {}) },
6805
- "task-reorder": { label: "Reorder Task", render: () => /* @__PURE__ */ jsx66(TaskReorderView, {}) },
6806
- "task-remove": { label: "Remove Task", render: () => /* @__PURE__ */ jsx66(TaskRemoveView, {}) },
6807
- "task-next": { label: "Next Task", render: () => /* @__PURE__ */ jsx66(TaskNextView, {}) },
6808
- "project-add": { label: "Add Project", render: () => /* @__PURE__ */ jsx66(ProjectAddView, {}) },
6809
- "project-remove": { label: "Remove Project", render: () => /* @__PURE__ */ jsx66(ProjectRemoveView, {}) },
6810
- "project-repo-add": { label: "Add Repository", render: () => /* @__PURE__ */ jsx66(ProjectRepoAddView, {}) },
6811
- "project-repo-remove": { label: "Remove Repository", render: () => /* @__PURE__ */ jsx66(ProjectRepoRemoveView, {}) },
6812
- "project-edit": { label: "Edit Project", render: () => /* @__PURE__ */ jsx66(ProjectEditView, {}) },
7086
+ "task-add": { label: "Add Task", render: () => /* @__PURE__ */ jsx69(TaskAddView, {}) },
7087
+ "task-import": { label: "Import Tasks", render: () => /* @__PURE__ */ jsx69(TaskImportView, {}) },
7088
+ "task-status": { label: "Task Status", render: () => /* @__PURE__ */ jsx69(TaskStatusView, {}) },
7089
+ "task-reorder": { label: "Reorder Task", render: () => /* @__PURE__ */ jsx69(TaskReorderView, {}) },
7090
+ "task-remove": { label: "Remove Task", render: () => /* @__PURE__ */ jsx69(TaskRemoveView, {}) },
7091
+ "task-next": { label: "Next Task", render: () => /* @__PURE__ */ jsx69(TaskNextView, {}) },
7092
+ "project-add": { label: "Add Project", render: () => /* @__PURE__ */ jsx69(ProjectAddView, {}) },
7093
+ "project-remove": { label: "Remove Project", render: () => /* @__PURE__ */ jsx69(ProjectRemoveView, {}) },
7094
+ "project-repo-add": { label: "Add Repository", render: () => /* @__PURE__ */ jsx69(ProjectRepoAddView, {}) },
7095
+ "project-repo-remove": { label: "Remove Repository", render: () => /* @__PURE__ */ jsx69(ProjectRepoRemoveView, {}) },
7096
+ "project-edit": { label: "Edit Project", render: () => /* @__PURE__ */ jsx69(ProjectEditView, {}) },
6813
7097
  "project-onboard": {
6814
7098
  label: "Onboard Repository",
6815
7099
  render: (props) => {
6816
7100
  const projectName = typeof props["projectName"] === "string" ? props["projectName"] : void 0;
6817
7101
  const repo = typeof props["repo"] === "string" ? props["repo"] : void 0;
6818
- return /* @__PURE__ */ jsx66(ProjectOnboardView, { projectName, repo });
7102
+ return /* @__PURE__ */ jsx69(ProjectOnboardView, { projectName, repo });
6819
7103
  }
6820
7104
  },
6821
- "sprint-list": { label: "Sprints", render: () => /* @__PURE__ */ jsx66(SprintListView, {}) },
7105
+ "sprint-list": { label: "Sprints", render: () => /* @__PURE__ */ jsx69(SprintListView, {}) },
6822
7106
  "sprint-show": {
6823
7107
  label: "Sprint",
6824
7108
  render: (props) => {
6825
7109
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6826
- return /* @__PURE__ */ jsx66(SprintShowView, { sprintId });
7110
+ return /* @__PURE__ */ jsx69(SprintShowView, { sprintId });
6827
7111
  }
6828
7112
  },
6829
- "ticket-list": { label: "Tickets", render: () => /* @__PURE__ */ jsx66(TicketListView, {}) },
7113
+ "ticket-list": { label: "Tickets", render: () => /* @__PURE__ */ jsx69(TicketListView, {}) },
6830
7114
  "ticket-show": {
6831
7115
  label: "Ticket",
6832
7116
  render: (props) => {
6833
7117
  const ticketId = typeof props["ticketId"] === "string" ? props["ticketId"] : void 0;
6834
- return /* @__PURE__ */ jsx66(TicketShowView, { ticketId });
7118
+ return /* @__PURE__ */ jsx69(TicketShowView, { ticketId });
6835
7119
  }
6836
7120
  },
6837
- "task-list": { label: "Tasks", render: () => /* @__PURE__ */ jsx66(TaskListView, {}) },
7121
+ "task-list": { label: "Tasks", render: () => /* @__PURE__ */ jsx69(TaskListView, {}) },
6838
7122
  "task-show": {
6839
7123
  label: "Task",
6840
7124
  render: (props) => {
6841
7125
  const taskId = typeof props["taskId"] === "string" ? props["taskId"] : void 0;
6842
- return /* @__PURE__ */ jsx66(TaskShowView, { taskId });
7126
+ return /* @__PURE__ */ jsx69(TaskShowView, { taskId });
6843
7127
  }
6844
7128
  },
6845
- "project-list": { label: "Projects", render: () => /* @__PURE__ */ jsx66(ProjectListView, {}) },
7129
+ "project-list": { label: "Projects", render: () => /* @__PURE__ */ jsx69(ProjectListView, {}) },
6846
7130
  "project-show": {
6847
7131
  label: "Project",
6848
7132
  render: (props) => {
6849
7133
  const projectName = typeof props["projectName"] === "string" ? props["projectName"] : void 0;
6850
- return /* @__PURE__ */ jsx66(ProjectShowView, { projectName });
7134
+ return /* @__PURE__ */ jsx69(ProjectShowView, { projectName });
6851
7135
  }
6852
7136
  },
6853
- doctor: { label: "Doctor", render: () => /* @__PURE__ */ jsx66(DoctorView, {}) },
6854
- "progress-log": { label: "Log Progress", render: () => /* @__PURE__ */ jsx66(ProgressLogView, {}) },
7137
+ doctor: { label: "Doctor", render: () => /* @__PURE__ */ jsx69(DoctorView, {}) },
7138
+ "progress-log": { label: "Log Progress", render: () => /* @__PURE__ */ jsx69(ProgressLogView, {}) },
6855
7139
  "progress-show": {
6856
7140
  label: "Progress",
6857
7141
  render: (props) => {
6858
7142
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6859
- return /* @__PURE__ */ jsx66(ProgressShowView, { sprintId });
7143
+ return /* @__PURE__ */ jsx69(ProgressShowView, { sprintId });
6860
7144
  }
6861
7145
  },
6862
- ideate: { label: "Ideate", render: () => /* @__PURE__ */ jsx66(IdeateView, {}) },
6863
- onboarding: { label: "Welcome", render: () => /* @__PURE__ */ jsx66(OnboardingView, {}) },
7146
+ ideate: { label: "Ideate", render: () => /* @__PURE__ */ jsx69(IdeateView, {}) },
7147
+ onboarding: { label: "Welcome", render: () => /* @__PURE__ */ jsx69(OnboardingView, {}) },
6864
7148
  "sprint-reactivate": {
6865
7149
  label: "Reactivate Sprint",
6866
7150
  render: (props) => {
6867
7151
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6868
- return /* @__PURE__ */ jsx66(ReactivateSprintView, { sprintId });
7152
+ return /* @__PURE__ */ jsx69(ReactivateSprintView, { sprintId });
6869
7153
  }
6870
7154
  },
6871
7155
  evaluations: {
6872
7156
  label: "Evaluations",
6873
7157
  render: (props) => {
6874
7158
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6875
- return /* @__PURE__ */ jsx66(EvaluationsView, { sprintId });
7159
+ return /* @__PURE__ */ jsx69(EvaluationsView, { sprintId });
6876
7160
  }
6877
7161
  },
6878
7162
  "evaluation-show": {
@@ -6880,28 +7164,32 @@ var views = {
6880
7164
  render: (props) => {
6881
7165
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
6882
7166
  const taskId = typeof props["taskId"] === "string" ? props["taskId"] : "";
6883
- return /* @__PURE__ */ jsx66(EvaluationShowView, { sprintId, taskId });
7167
+ return /* @__PURE__ */ jsx69(EvaluationShowView, { sprintId, taskId });
6884
7168
  }
6885
7169
  },
6886
7170
  feedback: {
6887
7171
  label: "Feedback",
6888
7172
  render: (props) => {
6889
7173
  const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
6890
- return /* @__PURE__ */ jsx66(FeedbackView, { sprintId });
7174
+ return /* @__PURE__ */ jsx69(FeedbackView, { sprintId });
6891
7175
  }
6892
7176
  }
6893
7177
  };
6894
7178
  function ViewRouter({ initialStack }) {
6895
- const app = useApp();
6896
- const [stack, setStack] = useState29(() => {
7179
+ const [stack, setStack] = useState37(() => {
6897
7180
  if (initialStack.length === 0) {
6898
7181
  return [{ id: "home" }];
6899
7182
  }
6900
7183
  return collapseAdjacentDuplicates(initialStack);
6901
7184
  });
6902
- const stackRef = useRef4(stack);
6903
- stackRef.current = stack;
6904
- const push = useCallback11((entry) => {
7185
+ const registry = useMemo34(() => {
7186
+ try {
7187
+ return getSharedDeps().executionRegistry;
7188
+ } catch {
7189
+ return null;
7190
+ }
7191
+ }, []);
7192
+ const push = useCallback12((entry) => {
6905
7193
  setStack((s) => {
6906
7194
  const top = s[s.length - 1];
6907
7195
  if (top?.id === entry.id && samePropsBag(top.props, entry.props)) {
@@ -6910,72 +7198,43 @@ function ViewRouter({ initialStack }) {
6910
7198
  return [...s, entry];
6911
7199
  });
6912
7200
  }, []);
6913
- const pop = useCallback11(() => {
7201
+ const pop = useCallback12(() => {
6914
7202
  setStack((s) => s.length > 1 ? s.slice(0, -1) : s);
6915
7203
  }, []);
6916
- const replace = useCallback11((entry) => {
7204
+ const replace = useCallback12((entry) => {
6917
7205
  setStack((s) => s.length === 0 ? [entry] : [...s.slice(0, -1), entry]);
6918
7206
  }, []);
6919
- const reset = useCallback11((entry) => {
7207
+ const reset = useCallback12((entry) => {
6920
7208
  setStack(() => [entry]);
6921
7209
  }, []);
6922
7210
  const current = stack[stack.length - 1];
6923
7211
  if (current === void 0) {
6924
7212
  throw new Error("ViewRouter stack is empty");
6925
7213
  }
6926
- const api = useMemo36(
7214
+ const api = useMemo34(
6927
7215
  () => ({ current, stack, push, pop, replace, reset }),
6928
7216
  [current, stack, push, pop, replace, reset]
6929
7217
  );
6930
- const currentPrompt = useCurrentPrompt();
6931
- const routerHotkeysActive = currentPrompt === null;
6932
- useInput19(
6933
- (input, key) => {
6934
- if (key.escape) {
6935
- pop();
6936
- return;
6937
- }
6938
- if (input === "h") {
6939
- reset({ id: "home" });
6940
- return;
6941
- }
6942
- if (input === "s" && current.id !== "settings") {
6943
- push({ id: "settings" });
6944
- return;
6945
- }
6946
- if (input === "d" && current.id !== "dashboard") {
6947
- push({ id: "dashboard" });
6948
- return;
6949
- }
6950
- if (input === "?" && current.id !== "doctor") {
6951
- push({ id: "doctor" });
6952
- return;
6953
- }
6954
- if (input === "q" && stackRef.current.length === 1 && current.id === "home") {
6955
- app.exit();
6956
- }
6957
- },
6958
- { isActive: routerHotkeysActive }
6959
- );
6960
7218
  const meta = views[current.id];
6961
7219
  const props = current.props ?? {};
6962
- return /* @__PURE__ */ jsx66(RouterProvider, { value: api, children: /* @__PURE__ */ jsx66(ViewHintsProvider, { children: /* @__PURE__ */ jsxs34(Box34, { flexDirection: "column", children: [
6963
- /* @__PURE__ */ jsx66(Banner, {}),
7220
+ return /* @__PURE__ */ jsx69(RouterProvider, { value: api, children: /* @__PURE__ */ jsx69(ViewHintsProvider, { children: /* @__PURE__ */ jsxs36(Box36, { flexDirection: "column", children: [
7221
+ /* @__PURE__ */ jsx69(Banner, {}),
7222
+ /* @__PURE__ */ jsx69(ExecutionNotificationBanner, { currentViewId: current.id, registry }),
6964
7223
  meta.render(props),
6965
- /* @__PURE__ */ jsx66(PromptHost, {}),
6966
- /* @__PURE__ */ jsx66(Box34, { marginTop: 1, children: /* @__PURE__ */ jsx66(KeyboardHints, {}) }),
6967
- /* @__PURE__ */ jsxs34(
6968
- Box34,
7224
+ /* @__PURE__ */ jsx69(PromptHost, {}),
7225
+ /* @__PURE__ */ jsx69(Box36, { marginTop: spacing.section, children: /* @__PURE__ */ jsx69(KeyboardHints, {}) }),
7226
+ /* @__PURE__ */ jsxs36(
7227
+ Box36,
6969
7228
  {
6970
- marginTop: 1,
7229
+ marginTop: spacing.section,
6971
7230
  borderStyle: "round",
6972
7231
  borderColor: inkColors.primary,
6973
7232
  borderDimColor: true,
6974
7233
  paddingX: spacing.indent,
6975
7234
  justifyContent: "space-between",
6976
7235
  children: [
6977
- /* @__PURE__ */ jsx66(StatusBar, { breadcrumb: stack.map((e) => views[e.id].label), hints: buildHints(current.id, stack.length) }),
6978
- /* @__PURE__ */ jsx66(VersionHint, {})
7236
+ /* @__PURE__ */ jsx69(StatusBar, { breadcrumb: stack.map((e) => views[e.id].label), hints: buildHints(current.id, stack.length) }),
7237
+ /* @__PURE__ */ jsx69(VersionHint, {})
6979
7238
  ]
6980
7239
  }
6981
7240
  )
@@ -7015,6 +7274,9 @@ function buildHints(currentId, depth) {
7015
7274
  if (currentId !== "doctor") {
7016
7275
  hints.push({ key: "?", action: "doctor" });
7017
7276
  }
7277
+ if (currentId !== "running-executions") {
7278
+ hints.push({ key: "x", action: "runs" });
7279
+ }
7018
7280
  if (currentId === "home" && depth === 1) {
7019
7281
  hints.push({ key: "b", action: "browse" });
7020
7282
  hints.push({ key: "q", action: "quit" });
@@ -7023,7 +7285,7 @@ function buildHints(currentId, depth) {
7023
7285
  }
7024
7286
 
7025
7287
  // src/integration/ui/tui/views/app.tsx
7026
- import { jsx as jsx67 } from "react/jsx-runtime";
7288
+ import { jsx as jsx70 } from "react/jsx-runtime";
7027
7289
  var MAX_CONTENT_WIDTH = 160;
7028
7290
  async function isFirstRun() {
7029
7291
  try {
@@ -7050,8 +7312,8 @@ function buildInitialStack(initialView, mountOptions) {
7050
7312
  }
7051
7313
  function useTerminalWidth() {
7052
7314
  const { stdout } = useStdout();
7053
- const [width, setWidth] = useState30(stdout.columns);
7054
- useEffect29(() => {
7315
+ const [width, setWidth] = useState38(stdout.columns);
7316
+ useEffect37(() => {
7055
7317
  const onResize = () => {
7056
7318
  setWidth(stdout.columns);
7057
7319
  };
@@ -7065,8 +7327,8 @@ function useTerminalWidth() {
7065
7327
  function App({ initialView, mountOptions }) {
7066
7328
  const terminalWidth = useTerminalWidth();
7067
7329
  const contentWidth = Math.min(terminalWidth, MAX_CONTENT_WIDTH);
7068
- const [stack, setStack] = useState30(null);
7069
- useEffect29(() => {
7330
+ const [stack, setStack] = useState38(null);
7331
+ useEffect37(() => {
7070
7332
  let cancelled = false;
7071
7333
  const decideInitial = async () => {
7072
7334
  if (initialView === "execute" && mountOptions.sprintId !== void 0) {
@@ -7083,13 +7345,13 @@ function App({ initialView, mountOptions }) {
7083
7345
  };
7084
7346
  }, [initialView, mountOptions]);
7085
7347
  if (stack === null) {
7086
- return /* @__PURE__ */ jsx67(Box35, { width: terminalWidth });
7348
+ return /* @__PURE__ */ jsx70(Box37, { width: terminalWidth });
7087
7349
  }
7088
- return /* @__PURE__ */ jsx67(Box35, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx67(Box35, { flexDirection: "column", width: contentWidth, children: /* @__PURE__ */ jsx67(ViewRouter, { initialStack: stack }) }) });
7350
+ return /* @__PURE__ */ jsx70(Box37, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx70(Box37, { flexDirection: "column", width: contentWidth, children: /* @__PURE__ */ jsx70(ViewRouter, { initialStack: stack }) }) });
7089
7351
  }
7090
7352
 
7091
7353
  // src/integration/ui/tui/runtime/mount.tsx
7092
- import { jsx as jsx68 } from "react/jsx-runtime";
7354
+ import { jsx as jsx71 } from "react/jsx-runtime";
7093
7355
  function canMountInk() {
7094
7356
  if (process.env["RALPHCTL_NO_TUI"]) return false;
7095
7357
  if (process.env["CI"]) return false;
@@ -7108,7 +7370,7 @@ async function mountInkApp(options) {
7108
7370
  setSharedDeps(createSharedDeps({ logger, signalBus, prompt }));
7109
7371
  enterAltScreen();
7110
7372
  const releaseHost = registerExternalHost();
7111
- const app = render(/* @__PURE__ */ jsx68(App, { initialView: options.initialView, mountOptions: options }), {
7373
+ const app = render(/* @__PURE__ */ jsx71(App, { initialView: options.initialView, mountOptions: options }), {
7112
7374
  exitOnCtrlC: false
7113
7375
  // We own Ctrl+C inside the app for prompt cancellation.
7114
7376
  });