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.
- package/dist/{add-MG26JWBP.mjs → add-DVPVHENV.mjs} +7 -7
- package/dist/{add-ZZYL4BSF.mjs → add-YVXM34RP.mjs} +6 -6
- package/dist/{chunk-LDSG7G2T.mjs → chunk-BSB4EDGR.mjs} +2 -2
- package/dist/{chunk-RQGD5WS6.mjs → chunk-CBMFRQ4Y.mjs} +3 -3
- package/dist/{chunk-Q4AVHUZL.mjs → chunk-FNAAA32W.mjs} +3 -3
- package/dist/{chunk-EGUFQNRB.mjs → chunk-GQ2WFKBN.mjs} +3 -3
- package/dist/{chunk-LCY32RW4.mjs → chunk-OFILN7QL.mjs} +183 -39
- package/dist/{chunk-MDE6KPJQ.mjs → chunk-OGEXYSFS.mjs} +5 -5
- package/dist/{chunk-TDBEEHTS.mjs → chunk-PYZEQ2VK.mjs} +5 -5
- package/dist/{chunk-57UWLHRH.mjs → chunk-VAZ3LJBI.mjs} +12 -1
- package/dist/{chunk-D2HWXEHH.mjs → chunk-WDMLPXOD.mjs} +2 -2
- package/dist/{chunk-WZTY77GY.mjs → chunk-XN2UIHBY.mjs} +10 -3
- package/dist/{chunk-WOMGKKZY.mjs → chunk-XPLYLRIM.mjs} +319 -15
- package/dist/{chunk-2FT37OZX.mjs → chunk-ZLWSPLWI.mjs} +53 -7
- package/dist/cli.mjs +19 -17
- package/dist/create-Z635FQKO.mjs +15 -0
- package/dist/{handle-SYVCFI6Y.mjs → handle-23EFF3BE.mjs} +1 -1
- package/dist/{mount-2ANLHHQE.mjs → mount-H2IH3MWE.mjs} +1455 -1193
- package/dist/{project-JF47ZWMF.mjs → project-DQHF4ISP.mjs} +3 -3
- package/dist/prompts/sprint-feedback.md +4 -0
- package/dist/prompts/task-evaluation.md +44 -2
- package/dist/prompts/task-execution.md +5 -0
- package/dist/{resolver-PG2DZEBX.mjs → resolver-OVPYVW6Q.mjs} +3 -3
- package/dist/{sprint-54DOSIJK.mjs → sprint-4E26AB5F.mjs} +4 -4
- package/dist/start-2WH4BTDB.mjs +19 -0
- package/package.json +1 -1
- package/dist/create-PQK6KKRD.mjs +0 -15
- 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-
|
|
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-
|
|
76
|
+
} from "./chunk-PYZEQ2VK.mjs";
|
|
75
77
|
import {
|
|
76
78
|
sprintCreateCommand
|
|
77
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-FNAAA32W.mjs";
|
|
78
80
|
import {
|
|
79
81
|
ticketAddCommand
|
|
80
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
181
|
-
import
|
|
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
|
|
334
|
-
import { Box as
|
|
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
|
|
338
|
-
import { Box as
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
2009
|
-
|
|
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
|
-
|
|
2019
|
-
|
|
2020
|
-
rateLimit: null
|
|
2012
|
+
rateLimit: null,
|
|
2013
|
+
taskRefreshError: null
|
|
2021
2014
|
};
|
|
2022
2015
|
}
|
|
2023
|
-
|
|
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
|
|
2027
|
-
const
|
|
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
|
-
|
|
2033
|
-
|
|
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
|
|
2036
|
-
|
|
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 (
|
|
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
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
}, [
|
|
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
|
-
|
|
2088
|
+
void (async () => {
|
|
2053
2089
|
try {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
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)
|
|
2065
|
-
|
|
2066
|
-
|
|
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
|
-
}, [
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
}, [
|
|
2113
|
-
|
|
2114
|
-
if (
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
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(
|
|
2121
|
-
|
|
2122
|
-
/* @__PURE__ */
|
|
2123
|
-
/* @__PURE__ */
|
|
2124
|
-
|
|
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__ */
|
|
2132
|
-
state.rateLimit ? /* @__PURE__ */
|
|
2133
|
-
/* @__PURE__ */
|
|
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
|
-
!
|
|
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__ */
|
|
2217
|
+
return /* @__PURE__ */ jsx20(Spinner, { label: `${taskName} ${glyphs.emDash} ${label}` }, taskId);
|
|
2146
2218
|
}) }) : null,
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
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__ */
|
|
2159
|
-
|
|
2226
|
+
liveExecution.summary ? /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
|
|
2227
|
+
liveExecution.summary.completed,
|
|
2160
2228
|
" completed ",
|
|
2161
2229
|
glyphs.inlineDot,
|
|
2162
2230
|
" ",
|
|
2163
|
-
|
|
2231
|
+
liveExecution.summary.remaining,
|
|
2164
2232
|
" remaining",
|
|
2165
2233
|
" ",
|
|
2166
2234
|
glyphs.inlineDot,
|
|
2167
2235
|
" ",
|
|
2168
|
-
|
|
2236
|
+
liveExecution.summary.blocked,
|
|
2169
2237
|
" blocked",
|
|
2170
2238
|
" (",
|
|
2171
|
-
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
2741
|
-
import { Box as Box24, Text as Text23, useInput as
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
3095
|
+
useInput10(
|
|
3054
3096
|
(_input, key) => {
|
|
3055
|
-
if (key.return &&
|
|
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 =
|
|
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 {
|
|
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: "
|
|
3205
|
+
{ key: "Enter", action: "back" },
|
|
3161
3206
|
{ key: "Esc", action: "back" }
|
|
3162
3207
|
];
|
|
3163
|
-
function
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
});
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
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
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
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
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
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
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
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
|
|
3335
|
+
function renderPre(phase) {
|
|
3222
3336
|
switch (phase.kind) {
|
|
3223
3337
|
case "loading":
|
|
3224
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
3258
|
-
|
|
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
|
|
3265
|
-
import { jsx as
|
|
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 =
|
|
3394
|
+
const hints = useMemo10(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
|
|
3298
3395
|
useViewHints(hints);
|
|
3299
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3401
|
+
return /* @__PURE__ */ jsx29(Spinner, { label: "Loading sprints\u2026" });
|
|
3305
3402
|
case "running":
|
|
3306
|
-
return /* @__PURE__ */
|
|
3403
|
+
return /* @__PURE__ */ jsx29(Spinner, { label: "Awaiting sprint selection\u2026" });
|
|
3307
3404
|
case "no-candidates":
|
|
3308
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3414
|
+
return /* @__PURE__ */ jsx29(ResultCard, { kind: "error", title: "Could not set current sprint", lines: [phase.message] });
|
|
3318
3415
|
case "done":
|
|
3319
|
-
return /* @__PURE__ */
|
|
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
|
|
3336
|
-
import { jsx as
|
|
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 =
|
|
3467
|
+
const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
|
|
3371
3468
|
useViewHints(hints);
|
|
3372
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3474
|
+
return /* @__PURE__ */ jsx30(Spinner, { label: "Writing requirements.md\u2026" });
|
|
3378
3475
|
case "empty":
|
|
3379
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
3494
|
+
return /* @__PURE__ */ jsx30(ResultCard, { kind: "error", title: "Could not export", lines: [phase.message] });
|
|
3398
3495
|
case "done":
|
|
3399
|
-
return /* @__PURE__ */
|
|
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
|
|
3418
|
-
import { jsx as
|
|
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 =
|
|
3544
|
+
const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
|
|
3448
3545
|
useViewHints(hints);
|
|
3449
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3551
|
+
return /* @__PURE__ */ jsx31(Spinner, { label: "Writing context.md\u2026" });
|
|
3455
3552
|
case "error":
|
|
3456
|
-
return /* @__PURE__ */
|
|
3553
|
+
return /* @__PURE__ */ jsx31(ResultCard, { kind: "error", title: "Could not export context", lines: [phase.message] });
|
|
3457
3554
|
case "done":
|
|
3458
|
-
return /* @__PURE__ */
|
|
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
|
|
3548
|
-
import { jsx as
|
|
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 =
|
|
3741
|
+
const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
|
|
3645
3742
|
useViewHints(hints);
|
|
3646
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3748
|
+
return /* @__PURE__ */ jsx32(Spinner, { label: STEP_LABEL[phase.step] });
|
|
3652
3749
|
case "no-draft-sprint":
|
|
3653
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
3695
|
-
import { jsx as
|
|
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 =
|
|
3866
|
+
const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
|
|
3770
3867
|
useViewHints(hints);
|
|
3771
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3873
|
+
return /* @__PURE__ */ jsx33(Spinner, { label: stepLabel(phase.step) });
|
|
3777
3874
|
case "no-tickets":
|
|
3778
|
-
return /* @__PURE__ */
|
|
3875
|
+
return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "No tickets to edit" });
|
|
3779
3876
|
case "no-draft-sprint":
|
|
3780
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3886
|
+
return /* @__PURE__ */ jsx33(ResultCard, { kind: "error", title: "Could not edit ticket", lines: [phase.message] });
|
|
3790
3887
|
case "done":
|
|
3791
|
-
return /* @__PURE__ */
|
|
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 {
|
|
3819
|
-
import { jsx as
|
|
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
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
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
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
}
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
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
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
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
|
|
3974
|
+
function renderPre2(phase) {
|
|
3872
3975
|
switch (phase.kind) {
|
|
3873
|
-
case "
|
|
3874
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
3981
|
+
return /* @__PURE__ */ jsx34(ResultCard, { kind: "info", title: "No tickets to remove" });
|
|
3877
3982
|
case "no-draft-sprint":
|
|
3878
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
3991
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3906
3992
|
var TITLE9 = "Re-Refine Ticket";
|
|
3907
|
-
var
|
|
3908
|
-
var
|
|
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" ?
|
|
4026
|
+
const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
|
|
3941
4027
|
useViewHints(hints);
|
|
3942
|
-
return /* @__PURE__ */
|
|
4028
|
+
return /* @__PURE__ */ jsx35(ViewShell, { title: TITLE9, children: renderBody8(phase) });
|
|
3943
4029
|
}
|
|
3944
|
-
function
|
|
4030
|
+
function renderBody8(phase) {
|
|
3945
4031
|
switch (phase.kind) {
|
|
3946
4032
|
case "running":
|
|
3947
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4035
|
+
return /* @__PURE__ */ jsx35(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
3950
4036
|
case "no-approved":
|
|
3951
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4046
|
+
return /* @__PURE__ */ jsx35(ResultCard, { kind: "error", title: "Re-refinement failed", lines: [phase.message] });
|
|
3961
4047
|
case "done":
|
|
3962
|
-
return /* @__PURE__ */
|
|
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
|
|
4062
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
3977
4063
|
var TITLE10 = "Add Task";
|
|
3978
|
-
var
|
|
3979
|
-
var
|
|
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" ?
|
|
4128
|
+
const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
|
|
4043
4129
|
useViewHints(hints);
|
|
4044
|
-
return /* @__PURE__ */
|
|
4130
|
+
return /* @__PURE__ */ jsx36(ViewShell, { title: TITLE10, children: renderBody9(phase) });
|
|
4045
4131
|
}
|
|
4046
|
-
function
|
|
4132
|
+
function renderBody9(phase) {
|
|
4047
4133
|
switch (phase.kind) {
|
|
4048
4134
|
case "running":
|
|
4049
|
-
return /* @__PURE__ */
|
|
4135
|
+
return /* @__PURE__ */ jsx36(Spinner, { label: stepLabel2(phase.step) });
|
|
4050
4136
|
case "no-project":
|
|
4051
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4139
|
+
return /* @__PURE__ */ jsx36(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
4054
4140
|
case "error":
|
|
4055
|
-
return /* @__PURE__ */
|
|
4141
|
+
return /* @__PURE__ */ jsx36(ResultCard, { kind: "error", title: "Could not add task", lines: [phase.message] });
|
|
4056
4142
|
case "done":
|
|
4057
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
4167
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
4082
4168
|
var TITLE11 = "Import Tasks";
|
|
4083
|
-
var
|
|
4084
|
-
var
|
|
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" ?
|
|
4190
|
+
const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
|
|
4105
4191
|
useViewHints(hints);
|
|
4106
|
-
return /* @__PURE__ */
|
|
4192
|
+
return /* @__PURE__ */ jsx37(ViewShell, { title: TITLE11, children: renderBody10(phase) });
|
|
4107
4193
|
}
|
|
4108
|
-
function
|
|
4194
|
+
function renderBody10(phase) {
|
|
4109
4195
|
switch (phase.kind) {
|
|
4110
4196
|
case "running":
|
|
4111
|
-
return /* @__PURE__ */
|
|
4197
|
+
return /* @__PURE__ */ jsx37(Spinner, { label: phase.step === "path" ? "Awaiting JSON file path\u2026" : "Importing tasks\u2026" });
|
|
4112
4198
|
case "done":
|
|
4113
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4201
|
+
return /* @__PURE__ */ jsx37(ResultCard, { kind: "info", title: "Import cancelled" });
|
|
4116
4202
|
case "error":
|
|
4117
|
-
return /* @__PURE__ */
|
|
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
|
|
4209
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
4124
4210
|
var TITLE12 = "Task Status";
|
|
4125
|
-
var
|
|
4126
|
-
var
|
|
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" ?
|
|
4255
|
+
const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
|
|
4170
4256
|
useViewHints(hints);
|
|
4171
|
-
return /* @__PURE__ */
|
|
4257
|
+
return /* @__PURE__ */ jsx38(ViewShell, { title: TITLE12, children: renderBody11(phase) });
|
|
4172
4258
|
}
|
|
4173
|
-
function
|
|
4259
|
+
function renderBody11(phase) {
|
|
4174
4260
|
switch (phase.kind) {
|
|
4175
4261
|
case "running":
|
|
4176
|
-
return /* @__PURE__ */
|
|
4262
|
+
return /* @__PURE__ */ jsx38(Spinner, { label: stepLabel3(phase.step) });
|
|
4177
4263
|
case "no-tasks":
|
|
4178
|
-
return /* @__PURE__ */
|
|
4264
|
+
return /* @__PURE__ */ jsx38(ResultCard, { kind: "info", title: "No tasks in this sprint" });
|
|
4179
4265
|
case "not-active":
|
|
4180
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4275
|
+
return /* @__PURE__ */ jsx38(ResultCard, { kind: "error", title: "Could not update status", lines: [phase.message] });
|
|
4190
4276
|
case "done":
|
|
4191
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
4298
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
4213
4299
|
var TITLE13 = "Reorder Task";
|
|
4214
|
-
var
|
|
4215
|
-
var
|
|
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" ?
|
|
4345
|
+
const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
|
|
4260
4346
|
useViewHints(hints);
|
|
4261
|
-
return /* @__PURE__ */
|
|
4347
|
+
return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE13, children: renderBody12(phase) });
|
|
4262
4348
|
}
|
|
4263
|
-
function
|
|
4349
|
+
function renderBody12(phase) {
|
|
4264
4350
|
switch (phase.kind) {
|
|
4265
4351
|
case "running":
|
|
4266
|
-
return /* @__PURE__ */
|
|
4352
|
+
return /* @__PURE__ */ jsx39(Spinner, { label: stepLabel4(phase.step) });
|
|
4267
4353
|
case "no-tasks":
|
|
4268
|
-
return /* @__PURE__ */
|
|
4354
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "No tasks in this sprint" });
|
|
4269
4355
|
case "not-draft":
|
|
4270
|
-
return /* @__PURE__ */
|
|
4356
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
4271
4357
|
case "error":
|
|
4272
|
-
return /* @__PURE__ */
|
|
4358
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "error", title: "Could not reorder", lines: [phase.message] });
|
|
4273
4359
|
case "done":
|
|
4274
|
-
return /* @__PURE__ */
|
|
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
|
|
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 {
|
|
4295
|
-
import { jsx as
|
|
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
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
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
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
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
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
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
|
|
4435
|
+
function renderPre3(phase) {
|
|
4344
4436
|
switch (phase.kind) {
|
|
4345
|
-
case "
|
|
4346
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4442
|
+
return /* @__PURE__ */ jsx40(ResultCard, { kind: "info", title: "No tasks to remove" });
|
|
4349
4443
|
case "not-draft":
|
|
4350
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
4377
|
-
import { jsx as
|
|
4451
|
+
import { useMemo as useMemo20 } from "react";
|
|
4452
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
4378
4453
|
var TITLE15 = "Next Task";
|
|
4379
|
-
var
|
|
4380
|
-
var
|
|
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 =
|
|
4472
|
+
const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
|
|
4398
4473
|
useViewHints(hints);
|
|
4399
|
-
return /* @__PURE__ */
|
|
4474
|
+
return /* @__PURE__ */ jsx41(ViewShell, { title: TITLE15, children: renderBody13(phase) });
|
|
4400
4475
|
}
|
|
4401
|
-
function
|
|
4476
|
+
function renderBody13(phase) {
|
|
4402
4477
|
switch (phase.kind) {
|
|
4403
4478
|
case "running":
|
|
4404
|
-
return /* @__PURE__ */
|
|
4479
|
+
return /* @__PURE__ */ jsx41(Spinner, { label: "Resolving next task\u2026" });
|
|
4405
4480
|
case "none":
|
|
4406
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
4483
|
+
return /* @__PURE__ */ jsx41(ResultCard, { kind: "error", title: "Could not resolve next task", lines: [phase.message] });
|
|
4409
4484
|
case "ready":
|
|
4410
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
4549
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
4475
4550
|
var TITLE16 = "Add Project";
|
|
4476
|
-
var
|
|
4477
|
-
var
|
|
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 =
|
|
4598
|
+
const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
|
|
4524
4599
|
useViewHints(hints);
|
|
4525
|
-
return /* @__PURE__ */
|
|
4600
|
+
return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE16, children: renderBody14(phase) });
|
|
4526
4601
|
}
|
|
4527
|
-
function
|
|
4602
|
+
function renderBody14(phase) {
|
|
4528
4603
|
switch (phase.kind) {
|
|
4529
4604
|
case "running":
|
|
4530
|
-
return /* @__PURE__ */
|
|
4605
|
+
return /* @__PURE__ */ jsx42(Spinner, { label: stepLabel5(phase.step) });
|
|
4531
4606
|
case "error":
|
|
4532
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 {
|
|
4567
|
-
import { jsx as
|
|
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
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
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
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
}
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
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
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
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
|
|
4693
|
+
function renderPre4(phase) {
|
|
4613
4694
|
switch (phase.kind) {
|
|
4614
|
-
case "
|
|
4615
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
4635
|
-
import { jsx as
|
|
4708
|
+
import { useMemo as useMemo22 } from "react";
|
|
4709
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
4636
4710
|
var TITLE18 = "Add Repository";
|
|
4637
|
-
var
|
|
4638
|
-
var
|
|
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
|
-
|
|
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 =
|
|
4751
|
+
const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
|
|
4763
4752
|
useViewHints(hints);
|
|
4764
|
-
return /* @__PURE__ */ jsx44(ViewShell, { title:
|
|
4753
|
+
return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE18, children: renderBody15(phase) });
|
|
4765
4754
|
}
|
|
4766
|
-
function
|
|
4755
|
+
function renderBody15(phase) {
|
|
4767
4756
|
switch (phase.kind) {
|
|
4768
4757
|
case "running":
|
|
4769
|
-
return /* @__PURE__ */ jsx44(Spinner, { label:
|
|
4758
|
+
return /* @__PURE__ */ jsx44(Spinner, { label: stepLabel6(phase.step) });
|
|
4770
4759
|
case "no-projects":
|
|
4771
|
-
return /* @__PURE__ */ jsx44(ResultCard, { kind: "
|
|
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
|
|
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
|
|
4768
|
+
title: "Repository added",
|
|
4784
4769
|
fields: [
|
|
4785
4770
|
["Project", phase.project.displayName],
|
|
4786
4771
|
["Repo", phase.repoName],
|
|
4787
|
-
["
|
|
4772
|
+
["Total repos", String(phase.project.repositories.length)]
|
|
4788
4773
|
]
|
|
4789
4774
|
}
|
|
4790
4775
|
);
|
|
4791
4776
|
}
|
|
4792
4777
|
}
|
|
4793
|
-
function
|
|
4778
|
+
function stepLabel6(step) {
|
|
4794
4779
|
if (step === "project") return "Awaiting project selection\u2026";
|
|
4795
|
-
if (step === "
|
|
4796
|
-
if (step === "
|
|
4797
|
-
return "
|
|
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-
|
|
4801
|
-
import {
|
|
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
|
|
4805
|
-
var
|
|
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 =
|
|
4919
|
+
const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
|
|
4848
4920
|
useViewHints(hints);
|
|
4849
|
-
return /* @__PURE__ */
|
|
4921
|
+
return /* @__PURE__ */ jsx46(ViewShell, { title: TITLE20, children: renderBody16(phase) });
|
|
4850
4922
|
}
|
|
4851
|
-
function
|
|
4923
|
+
function renderBody16(phase) {
|
|
4852
4924
|
switch (phase.kind) {
|
|
4853
4925
|
case "running":
|
|
4854
|
-
return /* @__PURE__ */
|
|
4926
|
+
return /* @__PURE__ */ jsx46(Spinner, { label: stepLabel7(phase.step) });
|
|
4855
4927
|
case "no-projects":
|
|
4856
|
-
return /* @__PURE__ */
|
|
4928
|
+
return /* @__PURE__ */ jsx46(ResultCard, { kind: "info", title: "No projects registered" });
|
|
4857
4929
|
case "error":
|
|
4858
|
-
return /* @__PURE__ */
|
|
4930
|
+
return /* @__PURE__ */ jsx46(ResultCard, { kind: "error", title: "Could not update project", lines: [phase.message] });
|
|
4859
4931
|
case "done":
|
|
4860
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
4883
|
-
import { jsx as
|
|
4954
|
+
import { useMemo as useMemo24 } from "react";
|
|
4955
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
4884
4956
|
var TITLE21 = "Onboard Repository";
|
|
4885
|
-
var
|
|
4886
|
-
var
|
|
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 =
|
|
5013
|
+
const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
|
|
4942
5014
|
useViewHints(hints);
|
|
4943
|
-
return /* @__PURE__ */
|
|
5015
|
+
return /* @__PURE__ */ jsx47(ViewShell, { title: TITLE21, children: renderBody17(phase) });
|
|
4944
5016
|
}
|
|
4945
|
-
function
|
|
5017
|
+
function renderBody17(phase) {
|
|
4946
5018
|
switch (phase.kind) {
|
|
4947
5019
|
case "running":
|
|
4948
|
-
return /* @__PURE__ */
|
|
5020
|
+
return /* @__PURE__ */ jsx47(Spinner, { label: stepLabel8(phase.step) });
|
|
4949
5021
|
case "no-projects":
|
|
4950
|
-
return /* @__PURE__ */
|
|
5022
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "info", title: "No projects registered" });
|
|
4951
5023
|
case "error":
|
|
4952
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
5039
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "success", title: "Repository onboarded", fields, nextSteps });
|
|
4968
5040
|
}
|
|
4969
5041
|
}
|
|
4970
5042
|
}
|
|
4971
|
-
function
|
|
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
|
|
4978
|
-
import { useInput as
|
|
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
|
|
4982
|
-
import { Box as Box25, Text as Text24, useInput as
|
|
4983
|
-
import { jsx as
|
|
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] =
|
|
5016
|
-
|
|
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 =
|
|
5022
|
-
|
|
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__ */
|
|
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__ */
|
|
5045
|
-
columns.map((col, i) => /* @__PURE__ */ jsxs24(
|
|
5046
|
-
/* @__PURE__ */
|
|
5047
|
-
i < columns.length - 1 ? /* @__PURE__ */
|
|
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__ */
|
|
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(
|
|
5060
|
-
/* @__PURE__ */
|
|
5061
|
-
ci < columns.length - 1 ? /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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: "
|
|
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] =
|
|
5176
|
-
const [filter, setFilter] =
|
|
5253
|
+
const [state, setState] = useState21({ kind: "loading" });
|
|
5254
|
+
const [filter, setFilter] = useState21("all");
|
|
5177
5255
|
useViewHints(state.kind === "ready" ? HINTS_READY2 : HINTS_EMPTY);
|
|
5178
|
-
|
|
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
|
-
|
|
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 === "
|
|
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 =
|
|
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__ */
|
|
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
|
|
5254
|
-
import { Box as Box26, Text as Text26, useInput as
|
|
5255
|
-
import { jsx as
|
|
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] =
|
|
5341
|
+
const [state, setState] = useState22({ kind: "loading" });
|
|
5264
5342
|
useViewHints(HINTS);
|
|
5265
|
-
|
|
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 =
|
|
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 =
|
|
5286
|
-
const [cursor, setCursor] =
|
|
5287
|
-
|
|
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__ */
|
|
5377
|
+
return /* @__PURE__ */ jsx50(ViewShell, { title: TITLE22, children: renderBody18(state, rows, sections, cursor) });
|
|
5300
5378
|
}
|
|
5301
|
-
function
|
|
5302
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5303
|
-
if (state.kind === "error") return /* @__PURE__ */
|
|
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__ */
|
|
5312
|
-
/* @__PURE__ */
|
|
5313
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
5332
|
-
rows.map((row, i) => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
5408
|
-
import { useInput as
|
|
5409
|
-
import { jsx as
|
|
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] =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
5501
|
-
import { Box as Box27, Text as Text27, useInput as
|
|
5502
|
-
import { jsx as
|
|
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] =
|
|
5509
|
-
|
|
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
|
-
|
|
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__ */
|
|
5620
|
+
return /* @__PURE__ */ jsx52(ViewShell, { title: TITLE24, children: renderBody19(state) });
|
|
5543
5621
|
}
|
|
5544
|
-
function
|
|
5545
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5546
|
-
if (state.kind === "error") return /* @__PURE__ */
|
|
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__ */
|
|
5551
|
-
/* @__PURE__ */
|
|
5552
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
5572
|
-
/* @__PURE__ */
|
|
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__ */
|
|
5576
|
-
/* @__PURE__ */
|
|
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
|
|
5583
|
-
import { useInput as
|
|
5584
|
-
import { jsx as
|
|
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] =
|
|
5657
|
-
const [filter, setFilter] =
|
|
5734
|
+
const [state, setState] = useState25({ kind: "loading" });
|
|
5735
|
+
const [filter, setFilter] = useState25("all");
|
|
5658
5736
|
useViewHints(state.kind === "ready" ? HINTS_READY4 : HINTS_EMPTY3);
|
|
5659
|
-
|
|
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
|
-
|
|
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 =
|
|
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__ */
|
|
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
|
|
5727
|
-
import { Box as Box28, Text as Text28, useInput as
|
|
5728
|
-
import { jsx as
|
|
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] =
|
|
5815
|
+
const [state, setState] = useState26({ kind: "loading" });
|
|
5738
5816
|
useViewHints(state.kind === "ready" ? HINTS_READY5 : HINTS_EMPTY4);
|
|
5739
|
-
|
|
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
|
-
|
|
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__ */
|
|
5845
|
+
return /* @__PURE__ */ jsx54(ViewShell, { title: TITLE25, children: renderBody20(state) });
|
|
5768
5846
|
}
|
|
5769
|
-
function
|
|
5770
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5771
|
-
if (state.kind === "error") return /* @__PURE__ */
|
|
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__ */
|
|
5776
|
-
/* @__PURE__ */
|
|
5777
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
5795
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
5822
|
-
import { useInput as
|
|
5823
|
-
import { jsx as
|
|
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] =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
5901
|
-
import { Box as Box29, Text as Text29, useInput as
|
|
5902
|
-
import { jsx as
|
|
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] =
|
|
5991
|
+
const [state, setState] = useState28({ kind: "loading" });
|
|
5914
5992
|
useViewHints(state.kind === "ready" ? HINTS_READY7 : HINTS_EMPTY6);
|
|
5915
|
-
|
|
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
|
-
|
|
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__ */
|
|
6029
|
+
return /* @__PURE__ */ jsx56(ViewShell, { title: TITLE27, children: renderBody21(state) });
|
|
5952
6030
|
}
|
|
5953
|
-
function
|
|
5954
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5955
|
-
if (state.kind === "error") return /* @__PURE__ */
|
|
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__ */
|
|
5960
|
-
/* @__PURE__ */
|
|
6037
|
+
/* @__PURE__ */ jsx56(Text29, { bold: true, children: project.displayName }),
|
|
6038
|
+
/* @__PURE__ */ jsx56(Text29, { dimColor: true, children: ` (${project.name})` })
|
|
5961
6039
|
] }),
|
|
5962
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
5981
|
-
/* @__PURE__ */
|
|
5982
|
-
/* @__PURE__ */
|
|
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
|
|
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
|
|
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__ */
|
|
6044
|
-
/* @__PURE__ */
|
|
6045
|
-
/* @__PURE__ */
|
|
6046
|
-
/* @__PURE__ */
|
|
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] =
|
|
6128
|
+
const [state, setState] = useState29({ kind: "running" });
|
|
6051
6129
|
useViewHints(HINTS2);
|
|
6052
|
-
|
|
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__ */
|
|
6141
|
+
return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE28, children: /* @__PURE__ */ jsx57(Spinner, { label: "Running environment checks\u2026" }) });
|
|
6064
6142
|
}
|
|
6065
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
6151
|
+
i === 0 ? null : /* @__PURE__ */ jsx57(Box30, { marginTop: spacing.section }),
|
|
6074
6152
|
/* @__PURE__ */ jsxs30(Box30, { children: [
|
|
6075
|
-
/* @__PURE__ */
|
|
6076
|
-
/* @__PURE__ */
|
|
6077
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
6170
|
+
const [state, setState] = useState30({ kind: "loading" });
|
|
6093
6171
|
useViewHints(HINTS3);
|
|
6094
|
-
|
|
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__ */
|
|
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__ */
|
|
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
|
|
6129
|
-
import { jsx as
|
|
6206
|
+
import { useMemo as useMemo29 } from "react";
|
|
6207
|
+
import { jsx as jsx59 } from "react/jsx-runtime";
|
|
6130
6208
|
var TITLE30 = "Log Progress";
|
|
6131
|
-
var
|
|
6209
|
+
var HINTS_RUNNING18 = [
|
|
6132
6210
|
{ key: "Ctrl+D", action: "submit" },
|
|
6133
6211
|
{ key: "Esc", action: "cancel" }
|
|
6134
6212
|
];
|
|
6135
|
-
var
|
|
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 =
|
|
6236
|
+
const hints = useMemo29(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
|
|
6159
6237
|
useViewHints(hints);
|
|
6160
|
-
return /* @__PURE__ */
|
|
6238
|
+
return /* @__PURE__ */ jsx59(ViewShell, { title: TITLE30, children: renderBody22(phase) });
|
|
6161
6239
|
}
|
|
6162
|
-
function
|
|
6240
|
+
function renderBody22(phase) {
|
|
6163
6241
|
switch (phase.kind) {
|
|
6164
6242
|
case "running":
|
|
6165
|
-
return /* @__PURE__ */
|
|
6243
|
+
return /* @__PURE__ */ jsx59(Spinner, { label: phase.step === "message" ? "Awaiting progress note\u2026" : "Saving progress note\u2026" });
|
|
6166
6244
|
case "cancelled":
|
|
6167
|
-
return /* @__PURE__ */
|
|
6245
|
+
return /* @__PURE__ */ jsx59(ResultCard, { kind: "info", title: "No note recorded" });
|
|
6168
6246
|
case "error":
|
|
6169
|
-
return /* @__PURE__ */
|
|
6247
|
+
return /* @__PURE__ */ jsx59(ResultCard, { kind: "error", title: "Could not log progress", lines: [phase.message] });
|
|
6170
6248
|
case "done":
|
|
6171
|
-
return /* @__PURE__ */
|
|
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
|
|
6177
|
-
import { jsx as
|
|
6254
|
+
import { useMemo as useMemo30 } from "react";
|
|
6255
|
+
import { jsx as jsx60 } from "react/jsx-runtime";
|
|
6178
6256
|
var TITLE31 = "Ideate";
|
|
6179
|
-
var
|
|
6180
|
-
var
|
|
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 =
|
|
6312
|
+
const hints = useMemo30(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
|
|
6235
6313
|
useViewHints(hints);
|
|
6236
|
-
return /* @__PURE__ */
|
|
6314
|
+
return /* @__PURE__ */ jsx60(ViewShell, { title: TITLE31, children: renderBody23(phase) });
|
|
6237
6315
|
}
|
|
6238
|
-
function
|
|
6316
|
+
function renderBody23(phase) {
|
|
6239
6317
|
switch (phase.kind) {
|
|
6240
6318
|
case "running":
|
|
6241
|
-
return /* @__PURE__ */
|
|
6319
|
+
return /* @__PURE__ */ jsx60(Spinner, { label: stepLabel9(phase.step) });
|
|
6242
6320
|
case "no-projects":
|
|
6243
|
-
return /* @__PURE__ */
|
|
6321
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Register a project first" });
|
|
6244
6322
|
case "no-draft-sprint":
|
|
6245
|
-
return /* @__PURE__ */
|
|
6323
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
6246
6324
|
case "error":
|
|
6247
|
-
return /* @__PURE__ */
|
|
6325
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "error", title: "Ideation failed", lines: [phase.message] });
|
|
6248
6326
|
case "done":
|
|
6249
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
6272
|
-
import { jsx as
|
|
6349
|
+
import { useMemo as useMemo31 } from "react";
|
|
6350
|
+
import { jsx as jsx61 } from "react/jsx-runtime";
|
|
6273
6351
|
var TITLE32 = "Welcome";
|
|
6274
|
-
var
|
|
6275
|
-
var
|
|
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 =
|
|
6400
|
+
const hints = useMemo31(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
|
|
6323
6401
|
useViewHints(hints);
|
|
6324
|
-
return /* @__PURE__ */
|
|
6402
|
+
return /* @__PURE__ */ jsx61(ViewShell, { title: TITLE32, children: renderBody24(phase) });
|
|
6325
6403
|
}
|
|
6326
|
-
function
|
|
6404
|
+
function renderBody24(phase) {
|
|
6327
6405
|
if (phase.kind === "running") {
|
|
6328
|
-
return /* @__PURE__ */
|
|
6406
|
+
return /* @__PURE__ */ jsx61(Spinner, { label: RUNNING_LABEL2[phase.step] });
|
|
6329
6407
|
}
|
|
6330
6408
|
if (phase.kind === "error") {
|
|
6331
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
6343
|
-
import { jsx as
|
|
6420
|
+
import { useMemo as useMemo32 } from "react";
|
|
6421
|
+
import { jsx as jsx62 } from "react/jsx-runtime";
|
|
6344
6422
|
var TITLE33 = "Reactivate Sprint";
|
|
6345
|
-
var
|
|
6346
|
-
var
|
|
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 =
|
|
6458
|
+
const hints = useMemo32(() => running ? HINTS_RUNNING21 : HINTS_DONE21, [running]);
|
|
6381
6459
|
useViewHints(hints);
|
|
6382
|
-
return /* @__PURE__ */
|
|
6460
|
+
return /* @__PURE__ */ jsx62(ViewShell, { title: TITLE33, children: renderBody25(phase) });
|
|
6383
6461
|
}
|
|
6384
|
-
function
|
|
6462
|
+
function renderBody25(phase) {
|
|
6385
6463
|
switch (phase.kind) {
|
|
6386
6464
|
case "loading":
|
|
6387
|
-
return /* @__PURE__ */
|
|
6465
|
+
return /* @__PURE__ */ jsx62(Spinner, { label: "Loading sprint\u2026" });
|
|
6388
6466
|
case "running":
|
|
6389
|
-
return /* @__PURE__ */
|
|
6467
|
+
return /* @__PURE__ */ jsx62(Spinner, { label: phase.step === "confirm" ? "Awaiting confirmation\u2026" : "Reactivating sprint\u2026" });
|
|
6390
6468
|
case "cancelled":
|
|
6391
|
-
return /* @__PURE__ */
|
|
6469
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "info", title: "Reactivation cancelled" });
|
|
6392
6470
|
case "missing-id":
|
|
6393
|
-
return /* @__PURE__ */
|
|
6471
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "No sprint ID provided" });
|
|
6394
6472
|
case "not-closed":
|
|
6395
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
6482
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "Could not reactivate sprint", lines: [phase.message] });
|
|
6405
6483
|
case "done":
|
|
6406
|
-
return /* @__PURE__ */
|
|
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
|
|
6423
|
-
import { jsx as
|
|
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] =
|
|
6533
|
+
const [state, setState] = useState31({ kind: "loading" });
|
|
6456
6534
|
useViewHints(HINTS4);
|
|
6457
|
-
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
6579
|
+
const [state, setState] = useState32({ kind: "loading" });
|
|
6502
6580
|
useViewHints(HINTS5);
|
|
6503
|
-
|
|
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__ */
|
|
6601
|
+
return /* @__PURE__ */ jsx64(ViewShell, { title: TITLE35, children: renderBody26(state) });
|
|
6524
6602
|
}
|
|
6525
|
-
function
|
|
6526
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
6535
|
-
/* @__PURE__ */
|
|
6536
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
6636
|
+
const [state, setState] = useState33({ kind: "loading" });
|
|
6559
6637
|
useViewHints(HINTS6);
|
|
6560
|
-
|
|
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__ */
|
|
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__ */
|
|
6585
|
-
/* @__PURE__ */
|
|
6586
|
-
/* @__PURE__ */
|
|
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
|
|
6606
|
-
import { Text as
|
|
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 =
|
|
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
|
|
6973
|
+
import { jsx as jsx68 } from "react/jsx-runtime";
|
|
6695
6974
|
function VersionHint() {
|
|
6696
|
-
const [check, setCheck] =
|
|
6697
|
-
|
|
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__ */
|
|
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
|
|
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__ */
|
|
6994
|
+
render: () => /* @__PURE__ */ jsx69(HomeView, {})
|
|
6716
6995
|
},
|
|
6717
6996
|
settings: {
|
|
6718
6997
|
label: "Settings",
|
|
6719
|
-
render: () => /* @__PURE__ */
|
|
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__ */
|
|
7006
|
+
return /* @__PURE__ */ jsx69(ExecuteView, { sprintId, executionId, executionOptions });
|
|
6727
7007
|
}
|
|
6728
7008
|
},
|
|
6729
7009
|
dashboard: {
|
|
6730
7010
|
label: "Dashboard",
|
|
6731
|
-
render: () => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
7035
|
+
return /* @__PURE__ */ jsx69(ClosePhaseView, { sprintId });
|
|
6752
7036
|
}
|
|
6753
7037
|
},
|
|
6754
7038
|
"sprint-create": {
|
|
6755
7039
|
label: "Create Sprint",
|
|
6756
|
-
render: () => /* @__PURE__ */
|
|
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__ */
|
|
7046
|
+
return /* @__PURE__ */ jsx69(DeleteSprintView, { sprintId });
|
|
6763
7047
|
}
|
|
6764
7048
|
},
|
|
6765
7049
|
"sprint-set-current": {
|
|
6766
7050
|
label: "Set Current",
|
|
6767
|
-
render: () => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
7064
|
+
return /* @__PURE__ */ jsx69(ContextExportView, { sprintId });
|
|
6781
7065
|
}
|
|
6782
7066
|
},
|
|
6783
7067
|
"ticket-add": {
|
|
6784
7068
|
label: "Add Ticket",
|
|
6785
|
-
render: () => /* @__PURE__ */
|
|
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__ */
|
|
7075
|
+
return /* @__PURE__ */ jsx69(TicketEditView, { ticketId });
|
|
6792
7076
|
}
|
|
6793
7077
|
},
|
|
6794
7078
|
"ticket-remove": {
|
|
6795
7079
|
label: "Remove Ticket",
|
|
6796
|
-
render: () => /* @__PURE__ */
|
|
7080
|
+
render: () => /* @__PURE__ */ jsx69(TicketRemoveView, {})
|
|
6797
7081
|
},
|
|
6798
7082
|
"ticket-refine": {
|
|
6799
7083
|
label: "Re-Refine Ticket",
|
|
6800
|
-
render: () => /* @__PURE__ */
|
|
7084
|
+
render: () => /* @__PURE__ */ jsx69(TicketRefineView, {})
|
|
6801
7085
|
},
|
|
6802
|
-
"task-add": { label: "Add Task", render: () => /* @__PURE__ */
|
|
6803
|
-
"task-import": { label: "Import Tasks", render: () => /* @__PURE__ */
|
|
6804
|
-
"task-status": { label: "Task Status", render: () => /* @__PURE__ */
|
|
6805
|
-
"task-reorder": { label: "Reorder Task", render: () => /* @__PURE__ */
|
|
6806
|
-
"task-remove": { label: "Remove Task", render: () => /* @__PURE__ */
|
|
6807
|
-
"task-next": { label: "Next Task", render: () => /* @__PURE__ */
|
|
6808
|
-
"project-add": { label: "Add Project", render: () => /* @__PURE__ */
|
|
6809
|
-
"project-remove": { label: "Remove Project", render: () => /* @__PURE__ */
|
|
6810
|
-
"project-repo-add": { label: "Add Repository", render: () => /* @__PURE__ */
|
|
6811
|
-
"project-repo-remove": { label: "Remove Repository", render: () => /* @__PURE__ */
|
|
6812
|
-
"project-edit": { label: "Edit Project", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7102
|
+
return /* @__PURE__ */ jsx69(ProjectOnboardView, { projectName, repo });
|
|
6819
7103
|
}
|
|
6820
7104
|
},
|
|
6821
|
-
"sprint-list": { label: "Sprints", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7110
|
+
return /* @__PURE__ */ jsx69(SprintShowView, { sprintId });
|
|
6827
7111
|
}
|
|
6828
7112
|
},
|
|
6829
|
-
"ticket-list": { label: "Tickets", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7118
|
+
return /* @__PURE__ */ jsx69(TicketShowView, { ticketId });
|
|
6835
7119
|
}
|
|
6836
7120
|
},
|
|
6837
|
-
"task-list": { label: "Tasks", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7126
|
+
return /* @__PURE__ */ jsx69(TaskShowView, { taskId });
|
|
6843
7127
|
}
|
|
6844
7128
|
},
|
|
6845
|
-
"project-list": { label: "Projects", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7134
|
+
return /* @__PURE__ */ jsx69(ProjectShowView, { projectName });
|
|
6851
7135
|
}
|
|
6852
7136
|
},
|
|
6853
|
-
doctor: { label: "Doctor", render: () => /* @__PURE__ */
|
|
6854
|
-
"progress-log": { label: "Log Progress", render: () => /* @__PURE__ */
|
|
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__ */
|
|
7143
|
+
return /* @__PURE__ */ jsx69(ProgressShowView, { sprintId });
|
|
6860
7144
|
}
|
|
6861
7145
|
},
|
|
6862
|
-
ideate: { label: "Ideate", render: () => /* @__PURE__ */
|
|
6863
|
-
onboarding: { label: "Welcome", render: () => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
7174
|
+
return /* @__PURE__ */ jsx69(FeedbackView, { sprintId });
|
|
6891
7175
|
}
|
|
6892
7176
|
}
|
|
6893
7177
|
};
|
|
6894
7178
|
function ViewRouter({ initialStack }) {
|
|
6895
|
-
const
|
|
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
|
|
6903
|
-
|
|
6904
|
-
|
|
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 =
|
|
7201
|
+
const pop = useCallback12(() => {
|
|
6914
7202
|
setStack((s) => s.length > 1 ? s.slice(0, -1) : s);
|
|
6915
7203
|
}, []);
|
|
6916
|
-
const replace =
|
|
7204
|
+
const replace = useCallback12((entry) => {
|
|
6917
7205
|
setStack((s) => s.length === 0 ? [entry] : [...s.slice(0, -1), entry]);
|
|
6918
7206
|
}, []);
|
|
6919
|
-
const reset =
|
|
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 =
|
|
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__ */
|
|
6963
|
-
/* @__PURE__ */
|
|
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__ */
|
|
6966
|
-
/* @__PURE__ */
|
|
6967
|
-
/* @__PURE__ */
|
|
6968
|
-
|
|
7224
|
+
/* @__PURE__ */ jsx69(PromptHost, {}),
|
|
7225
|
+
/* @__PURE__ */ jsx69(Box36, { marginTop: spacing.section, children: /* @__PURE__ */ jsx69(KeyboardHints, {}) }),
|
|
7226
|
+
/* @__PURE__ */ jsxs36(
|
|
7227
|
+
Box36,
|
|
6969
7228
|
{
|
|
6970
|
-
marginTop:
|
|
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__ */
|
|
6978
|
-
/* @__PURE__ */
|
|
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
|
|
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] =
|
|
7054
|
-
|
|
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] =
|
|
7069
|
-
|
|
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__ */
|
|
7348
|
+
return /* @__PURE__ */ jsx70(Box37, { width: terminalWidth });
|
|
7087
7349
|
}
|
|
7088
|
-
return /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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
|
});
|