ralphctl 0.4.2 → 0.4.4
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/README.md +13 -11
- package/dist/{add-CIM72NE3.mjs → add-DVPVHENV.mjs} +7 -7
- package/dist/{add-GX7P7XTT.mjs → add-YVXM34RP.mjs} +6 -5
- package/dist/{chunk-GL7MKLLS.mjs → chunk-ACRMBVEE.mjs} +458 -181
- package/dist/{chunk-NUYQK5MN.mjs → chunk-BSB4EDGR.mjs} +2 -2
- package/dist/{chunk-YCDUVPRT.mjs → chunk-CBMFRQ4Y.mjs} +5 -73
- package/dist/{chunk-3QBEBKMZ.mjs → chunk-FNAAA32W.mjs} +7 -7
- package/dist/{chunk-JOQO4HMM.mjs → chunk-GQ2WFKBN.mjs} +11 -11
- package/dist/{chunk-TKPTT2UG.mjs → chunk-OFILN7QL.mjs} +798 -1023
- package/dist/{chunk-7JLZQICD.mjs → chunk-OGEXYSFS.mjs} +7 -7
- package/dist/{chunk-D2YGPLIV.mjs → chunk-PYZEQ2VK.mjs} +214 -9
- package/dist/{chunk-57UWLHRH.mjs → chunk-VAZ3LJBI.mjs} +12 -1
- package/dist/{chunk-CTP2A436.mjs → chunk-WDMLPXOD.mjs} +11 -4
- package/dist/{chunk-FKMKOWLA.mjs → chunk-XN2UIHBY.mjs} +84 -3
- package/dist/chunk-ZLWSPLWI.mjs +1117 -0
- package/dist/cli.mjs +72 -21
- package/dist/create-Z635FQKO.mjs +15 -0
- package/dist/{handle-BBAZJ44Y.mjs → handle-23EFF3BE.mjs} +1 -1
- package/dist/{mount-ISHZM36X.mjs → mount-VEV3TESX.mjs} +1702 -1202
- package/dist/{project-2IE7VWDB.mjs → project-DQHF4ISP.mjs} +3 -3
- package/dist/prompts/check-script-discover.md +69 -0
- package/dist/prompts/repo-onboard.md +111 -0
- 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-EOE5WUMV.mjs → resolver-OVPYVW6Q.mjs} +4 -4
- package/dist/{sprint-OGOFEJJH.mjs → sprint-4E26AB5F.mjs} +4 -4
- package/dist/start-2WH4BTDB.mjs +19 -0
- package/package.json +6 -6
- package/dist/create-7WFSCMP4.mjs +0 -15
- package/dist/start-76JKJQIH.mjs +0 -17
|
@@ -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,
|
|
@@ -14,18 +15,18 @@ import {
|
|
|
14
15
|
checkGlabInstalled,
|
|
15
16
|
checkNodeVersion,
|
|
16
17
|
checkProjectPaths,
|
|
18
|
+
checkRepoOnboarding,
|
|
17
19
|
cliMetadata,
|
|
18
20
|
configSetCommand,
|
|
19
21
|
configShowCommand,
|
|
20
22
|
createSharedDeps,
|
|
21
23
|
doctorCommand,
|
|
22
24
|
exportRequirementsToMarkdown,
|
|
23
|
-
getAllSchemaEntries,
|
|
24
25
|
getNextAction,
|
|
25
26
|
glyphs,
|
|
26
27
|
inkColors,
|
|
27
28
|
loadDashboardData,
|
|
28
|
-
|
|
29
|
+
logEventBus,
|
|
29
30
|
progressLogCommand,
|
|
30
31
|
progressShowCommand,
|
|
31
32
|
projectListCommand,
|
|
@@ -60,56 +61,53 @@ import {
|
|
|
60
61
|
ticketRefineCommand,
|
|
61
62
|
ticketRemoveCommand,
|
|
62
63
|
ticketShowCommand,
|
|
63
|
-
useCurrentPrompt
|
|
64
|
-
|
|
65
|
-
} from "./chunk-GL7MKLLS.mjs";
|
|
64
|
+
useCurrentPrompt
|
|
65
|
+
} from "./chunk-ACRMBVEE.mjs";
|
|
66
66
|
import {
|
|
67
67
|
PromptCancelledError,
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
detectCheckScriptCandidates,
|
|
69
|
+
discoverCheckScriptWithAi,
|
|
70
|
+
getAllSchemaEntries,
|
|
71
|
+
getConfigDefaultValue,
|
|
72
|
+
parseConfigValue,
|
|
73
|
+
projectAddCommand,
|
|
74
|
+
suggestCheckScript,
|
|
75
|
+
validateConfigValue
|
|
76
|
+
} from "./chunk-PYZEQ2VK.mjs";
|
|
70
77
|
import {
|
|
71
78
|
sprintCreateCommand
|
|
72
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-FNAAA32W.mjs";
|
|
73
80
|
import {
|
|
74
81
|
ticketAddCommand
|
|
75
|
-
} from "./chunk-
|
|
76
|
-
import {
|
|
77
|
-
addProjectRepo,
|
|
78
|
-
createProject,
|
|
79
|
-
getProject,
|
|
80
|
-
getProjectById,
|
|
81
|
-
getRepoById,
|
|
82
|
-
listProjects,
|
|
83
|
-
projectExists,
|
|
84
|
-
removeProject,
|
|
85
|
-
removeProjectRepo,
|
|
86
|
-
resolveRepoPath,
|
|
87
|
-
updateProject
|
|
88
|
-
} from "./chunk-NUYQK5MN.mjs";
|
|
82
|
+
} from "./chunk-OGEXYSFS.mjs";
|
|
89
83
|
import {
|
|
90
84
|
addTask,
|
|
91
85
|
areAllTasksDone,
|
|
92
86
|
branchExists,
|
|
93
|
-
createExecuteSprintPipeline,
|
|
94
87
|
createIdeatePipeline,
|
|
88
|
+
createOnboardPipeline,
|
|
95
89
|
createPlanPipeline,
|
|
96
90
|
createRefinePipeline,
|
|
97
|
-
enterAltScreen,
|
|
98
91
|
executePipeline,
|
|
99
|
-
exitAltScreen,
|
|
100
92
|
getDefaultBranch,
|
|
101
93
|
getNextTask,
|
|
102
94
|
getTask,
|
|
103
95
|
getTasks,
|
|
104
96
|
isGhAvailable,
|
|
105
97
|
listTasks,
|
|
106
|
-
registerTuiInstance,
|
|
107
98
|
removeTask,
|
|
108
99
|
reorderTask,
|
|
109
100
|
sprintStartCommand,
|
|
110
|
-
updateTaskStatus
|
|
101
|
+
updateTaskStatus
|
|
102
|
+
} from "./chunk-OFILN7QL.mjs";
|
|
103
|
+
import {
|
|
104
|
+
ProviderAiSessionAdapter,
|
|
105
|
+
SignalParser,
|
|
106
|
+
enterAltScreen,
|
|
107
|
+
exitAltScreen,
|
|
108
|
+
registerTuiInstance,
|
|
111
109
|
withSuspendedTui
|
|
112
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-ZLWSPLWI.mjs";
|
|
113
111
|
import {
|
|
114
112
|
addTicket,
|
|
115
113
|
allRequirementsApproved,
|
|
@@ -121,38 +119,51 @@ import {
|
|
|
121
119
|
removeTicket,
|
|
122
120
|
truncate,
|
|
123
121
|
updateTicket
|
|
124
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-GQ2WFKBN.mjs";
|
|
125
123
|
import "./chunk-CFUVE2BP.mjs";
|
|
126
124
|
import {
|
|
127
125
|
getPrompt,
|
|
128
126
|
getSharedDeps,
|
|
129
127
|
setSharedDeps
|
|
130
128
|
} from "./chunk-747KW2RW.mjs";
|
|
129
|
+
import {
|
|
130
|
+
addProjectRepo,
|
|
131
|
+
createProject,
|
|
132
|
+
getProject,
|
|
133
|
+
getProjectById,
|
|
134
|
+
getRepoById,
|
|
135
|
+
listProjects,
|
|
136
|
+
projectExists,
|
|
137
|
+
removeProject,
|
|
138
|
+
removeProjectRepo,
|
|
139
|
+
resolveRepoPath,
|
|
140
|
+
updateProject
|
|
141
|
+
} from "./chunk-BSB4EDGR.mjs";
|
|
131
142
|
import {
|
|
132
143
|
closeSprint,
|
|
133
144
|
createSprint,
|
|
134
145
|
deleteSprint,
|
|
135
|
-
getAiProvider,
|
|
136
|
-
getConfig,
|
|
137
|
-
getCurrentSprint,
|
|
138
146
|
getCurrentSprintOrThrow,
|
|
139
|
-
getEditor,
|
|
140
|
-
getEvaluationIterations,
|
|
141
147
|
getProgress,
|
|
142
148
|
getSprint,
|
|
143
149
|
listSprints,
|
|
144
150
|
logProgress,
|
|
145
151
|
resolveSprintId,
|
|
146
|
-
saveSprint
|
|
147
|
-
|
|
148
|
-
setCurrentSprint
|
|
149
|
-
} from "./chunk-YCDUVPRT.mjs";
|
|
152
|
+
saveSprint
|
|
153
|
+
} from "./chunk-CBMFRQ4Y.mjs";
|
|
150
154
|
import {
|
|
151
155
|
banner,
|
|
152
156
|
colors,
|
|
157
|
+
getAiProvider,
|
|
158
|
+
getConfig,
|
|
159
|
+
getCurrentSprint,
|
|
160
|
+
getEditor,
|
|
161
|
+
getEvaluationIterations,
|
|
153
162
|
getRandomQuote,
|
|
154
|
-
gradients
|
|
155
|
-
|
|
163
|
+
gradients,
|
|
164
|
+
setAiProvider,
|
|
165
|
+
setCurrentSprint
|
|
166
|
+
} from "./chunk-XN2UIHBY.mjs";
|
|
156
167
|
import {
|
|
157
168
|
ensureError,
|
|
158
169
|
wrapAsync
|
|
@@ -167,165 +178,22 @@ import {
|
|
|
167
178
|
getTasksFilePath,
|
|
168
179
|
readTextFile,
|
|
169
180
|
readValidatedJson
|
|
170
|
-
} from "./chunk-
|
|
171
|
-
import
|
|
181
|
+
} from "./chunk-WDMLPXOD.mjs";
|
|
182
|
+
import {
|
|
183
|
+
ExecutionAlreadyRunningError
|
|
184
|
+
} from "./chunk-VAZ3LJBI.mjs";
|
|
172
185
|
|
|
173
186
|
// src/integration/ui/tui/runtime/mount.tsx
|
|
174
187
|
import "react";
|
|
175
188
|
import { render } from "ink";
|
|
176
189
|
|
|
177
|
-
// src/integration/ui/tui/runtime/event-bus.ts
|
|
178
|
-
var FRAME_MS = 16;
|
|
179
|
-
var SingletonLogEventBus = class {
|
|
180
|
-
listeners = /* @__PURE__ */ new Set();
|
|
181
|
-
buffer = [];
|
|
182
|
-
flushTimer = null;
|
|
183
|
-
emit(event) {
|
|
184
|
-
this.buffer.push(event);
|
|
185
|
-
this.scheduleFlush();
|
|
186
|
-
}
|
|
187
|
-
subscribe(listener) {
|
|
188
|
-
this.listeners.add(listener);
|
|
189
|
-
return () => {
|
|
190
|
-
this.listeners.delete(listener);
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
dispose() {
|
|
194
|
-
if (this.flushTimer) {
|
|
195
|
-
clearTimeout(this.flushTimer);
|
|
196
|
-
this.flushTimer = null;
|
|
197
|
-
}
|
|
198
|
-
this.listeners.clear();
|
|
199
|
-
this.buffer.length = 0;
|
|
200
|
-
}
|
|
201
|
-
/** Force immediate drain. Primarily for tests. */
|
|
202
|
-
flush() {
|
|
203
|
-
if (this.flushTimer) {
|
|
204
|
-
clearTimeout(this.flushTimer);
|
|
205
|
-
this.flushTimer = null;
|
|
206
|
-
}
|
|
207
|
-
this.drain();
|
|
208
|
-
}
|
|
209
|
-
scheduleFlush() {
|
|
210
|
-
if (this.flushTimer !== null) return;
|
|
211
|
-
const timer = setTimeout(() => {
|
|
212
|
-
this.flushTimer = null;
|
|
213
|
-
this.drain();
|
|
214
|
-
}, FRAME_MS);
|
|
215
|
-
timer.unref();
|
|
216
|
-
this.flushTimer = timer;
|
|
217
|
-
}
|
|
218
|
-
drain() {
|
|
219
|
-
if (this.buffer.length === 0) return;
|
|
220
|
-
const batch = this.buffer.splice(0, this.buffer.length);
|
|
221
|
-
for (const listener of this.listeners) {
|
|
222
|
-
try {
|
|
223
|
-
listener(batch);
|
|
224
|
-
} catch {
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
var logEventBus = new SingletonLogEventBus();
|
|
230
|
-
|
|
231
|
-
// src/integration/logging/ink-sink.ts
|
|
232
|
-
var spinnerId = 0;
|
|
233
|
-
var InkSink = class _InkSink {
|
|
234
|
-
constructor(context = {}) {
|
|
235
|
-
this.context = context;
|
|
236
|
-
}
|
|
237
|
-
context;
|
|
238
|
-
emit(event) {
|
|
239
|
-
logEventBus.emit(event);
|
|
240
|
-
}
|
|
241
|
-
// -- Structured log levels --------------------------------------------------
|
|
242
|
-
debug(message, context) {
|
|
243
|
-
this.emit({ kind: "log", level: "debug", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
|
|
244
|
-
}
|
|
245
|
-
info(message, context) {
|
|
246
|
-
this.emit({ kind: "log", level: "info", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
|
|
247
|
-
}
|
|
248
|
-
warn(message, context) {
|
|
249
|
-
this.emit({ kind: "log", level: "warn", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
|
|
250
|
-
}
|
|
251
|
-
error(message, context) {
|
|
252
|
-
this.emit({ kind: "log", level: "error", message, context: this.merge(context), timestamp: /* @__PURE__ */ new Date() });
|
|
253
|
-
}
|
|
254
|
-
// -- UI-level output --------------------------------------------------------
|
|
255
|
-
success(message) {
|
|
256
|
-
this.emit({ kind: "log", level: "success", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
|
|
257
|
-
}
|
|
258
|
-
warning(message) {
|
|
259
|
-
this.emit({ kind: "log", level: "warning", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
|
|
260
|
-
}
|
|
261
|
-
tip(message) {
|
|
262
|
-
this.emit({ kind: "log", level: "tip", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
|
|
263
|
-
}
|
|
264
|
-
// -- Layout -----------------------------------------------------------------
|
|
265
|
-
header(title, icon) {
|
|
266
|
-
this.emit({ kind: "header", title, icon, timestamp: /* @__PURE__ */ new Date() });
|
|
267
|
-
}
|
|
268
|
-
separator(width = 40) {
|
|
269
|
-
this.emit({ kind: "separator", width, timestamp: /* @__PURE__ */ new Date() });
|
|
270
|
-
}
|
|
271
|
-
field(label, value, _width) {
|
|
272
|
-
void _width;
|
|
273
|
-
this.emit({ kind: "field", label, value, timestamp: /* @__PURE__ */ new Date() });
|
|
274
|
-
}
|
|
275
|
-
card(title, lines) {
|
|
276
|
-
this.emit({ kind: "card", title, lines, timestamp: /* @__PURE__ */ new Date() });
|
|
277
|
-
}
|
|
278
|
-
newline() {
|
|
279
|
-
this.emit({ kind: "newline", timestamp: /* @__PURE__ */ new Date() });
|
|
280
|
-
}
|
|
281
|
-
dim(message) {
|
|
282
|
-
this.emit({ kind: "log", level: "dim", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
|
|
283
|
-
}
|
|
284
|
-
item(message) {
|
|
285
|
-
this.emit({ kind: "log", level: "item", message, context: this.context, timestamp: /* @__PURE__ */ new Date() });
|
|
286
|
-
}
|
|
287
|
-
// -- Interactive ------------------------------------------------------------
|
|
288
|
-
spinner(message) {
|
|
289
|
-
const id = ++spinnerId;
|
|
290
|
-
this.emit({ kind: "spinner-start", id, message, timestamp: /* @__PURE__ */ new Date() });
|
|
291
|
-
return {
|
|
292
|
-
succeed: (msg) => {
|
|
293
|
-
this.emit({ kind: "spinner-succeed", id, message: msg, timestamp: /* @__PURE__ */ new Date() });
|
|
294
|
-
},
|
|
295
|
-
fail: (msg) => {
|
|
296
|
-
this.emit({ kind: "spinner-fail", id, message: msg, timestamp: /* @__PURE__ */ new Date() });
|
|
297
|
-
},
|
|
298
|
-
stop: () => {
|
|
299
|
-
this.emit({ kind: "spinner-stop", id, timestamp: /* @__PURE__ */ new Date() });
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
// -- Scoped child -----------------------------------------------------------
|
|
304
|
-
child(context) {
|
|
305
|
-
return new _InkSink({ ...this.context, ...context });
|
|
306
|
-
}
|
|
307
|
-
// -- Timing -----------------------------------------------------------------
|
|
308
|
-
time(label) {
|
|
309
|
-
const start = Date.now();
|
|
310
|
-
return () => {
|
|
311
|
-
const ms = Date.now() - start;
|
|
312
|
-
this.debug(`${label}: ${String(ms)}ms`);
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
// -- Internals --------------------------------------------------------------
|
|
316
|
-
merge(extra) {
|
|
317
|
-
if (!extra) return this.context;
|
|
318
|
-
return { ...this.context, ...extra };
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
|
|
322
190
|
// src/integration/ui/tui/views/app.tsx
|
|
323
|
-
import { useEffect as
|
|
324
|
-
import { Box as
|
|
191
|
+
import { useEffect as useEffect37, useState as useState38 } from "react";
|
|
192
|
+
import { Box as Box37, useStdout } from "ink";
|
|
325
193
|
|
|
326
194
|
// src/integration/ui/tui/views/view-router.tsx
|
|
327
|
-
import { useCallback as
|
|
328
|
-
import { Box as
|
|
195
|
+
import { useCallback as useCallback12, useMemo as useMemo34, useState as useState37 } from "react";
|
|
196
|
+
import { Box as Box36 } from "ink";
|
|
329
197
|
|
|
330
198
|
// src/integration/ui/tui/components/banner.tsx
|
|
331
199
|
import { useMemo } from "react";
|
|
@@ -445,10 +313,13 @@ function useRouter() {
|
|
|
445
313
|
}
|
|
446
314
|
return api;
|
|
447
315
|
}
|
|
316
|
+
function useRouterOptional() {
|
|
317
|
+
return useContext2(RouterContext);
|
|
318
|
+
}
|
|
448
319
|
|
|
449
320
|
// src/integration/ui/tui/views/home-view.tsx
|
|
450
321
|
import { useCallback as useCallback2, useEffect as useEffect4, useState as useState4 } from "react";
|
|
451
|
-
import { Box as Box9, Text as Text8, useInput as
|
|
322
|
+
import { Box as Box9, Text as Text8, useInput as useInput4 } from "ink";
|
|
452
323
|
|
|
453
324
|
// src/integration/ui/tui/views/menu-builder.ts
|
|
454
325
|
var SEPARATOR_WIDTH = 48;
|
|
@@ -581,6 +452,11 @@ function buildProjectSubMenu() {
|
|
|
581
452
|
description: "Add repository to project"
|
|
582
453
|
});
|
|
583
454
|
items.push({ name: "Remove Repository", value: "repo remove", description: "Remove repository" });
|
|
455
|
+
items.push({
|
|
456
|
+
name: "Onboard repo for agentic work",
|
|
457
|
+
value: "onboard",
|
|
458
|
+
description: "AI-assisted project context file + check script"
|
|
459
|
+
});
|
|
584
460
|
items.push(line());
|
|
585
461
|
items.push({ name: "Remove", value: "remove", description: "Remove a project" });
|
|
586
462
|
items.push({ name: "Back", value: "back", description: "Return to main menu" });
|
|
@@ -1013,8 +889,68 @@ function SectionStamp({ title, color: color2 = inkColors.primary }) {
|
|
|
1013
889
|
// src/integration/ui/tui/components/view-shell.tsx
|
|
1014
890
|
import "react";
|
|
1015
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
|
|
1016
951
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1017
952
|
function ViewShell({ title, bare = false, children }) {
|
|
953
|
+
useGlobalKeys();
|
|
1018
954
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
1019
955
|
!bare && title !== void 0 ? /* @__PURE__ */ jsx9(SectionStamp, { title }) : null,
|
|
1020
956
|
/* @__PURE__ */ jsx9(Box8, { marginTop: bare ? 0 : spacing.section, flexDirection: "column", children })
|
|
@@ -1169,7 +1105,8 @@ var WORKFLOW_VIEWS = {
|
|
|
1169
1105
|
remove: "project-remove",
|
|
1170
1106
|
"repo add": "project-repo-add",
|
|
1171
1107
|
"repo remove": "project-repo-remove",
|
|
1172
|
-
edit: "project-edit"
|
|
1108
|
+
edit: "project-edit",
|
|
1109
|
+
onboard: "project-onboard"
|
|
1173
1110
|
},
|
|
1174
1111
|
progress: {
|
|
1175
1112
|
log: "progress-log",
|
|
@@ -1249,8 +1186,8 @@ async function loadHomeState() {
|
|
|
1249
1186
|
ctx.nextAction = getNextAction(dashboardData);
|
|
1250
1187
|
return { ctx, dashboardData, snapshot: computePipelineSnapshot(ctx) };
|
|
1251
1188
|
}
|
|
1252
|
-
var lastSubGroup = null;
|
|
1253
1189
|
function HomeView() {
|
|
1190
|
+
useGlobalKeys();
|
|
1254
1191
|
const router = useRouter();
|
|
1255
1192
|
const [state, setState] = useState4(null);
|
|
1256
1193
|
const [mode, setModeInternal] = useState4("main");
|
|
@@ -1260,7 +1197,7 @@ function HomeView() {
|
|
|
1260
1197
|
const setMode = useCallback2((next) => {
|
|
1261
1198
|
setModeInternal((prev) => {
|
|
1262
1199
|
const resolved = typeof next === "function" ? next(prev) : next;
|
|
1263
|
-
|
|
1200
|
+
setHomeSubmenuMemory(typeof resolved === "object" ? resolved.group : null);
|
|
1264
1201
|
return resolved;
|
|
1265
1202
|
});
|
|
1266
1203
|
}, []);
|
|
@@ -1274,9 +1211,10 @@ function HomeView() {
|
|
|
1274
1211
|
const next = await loadHomeState();
|
|
1275
1212
|
if (cancel.current) return;
|
|
1276
1213
|
setState(next);
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1214
|
+
const stored = getHomeSubmenuMemory();
|
|
1215
|
+
if (stored !== null) {
|
|
1216
|
+
const menu = buildSubMenu(stored, next.ctx);
|
|
1217
|
+
if (menu) setModeInternal({ kind: "sub", menu, group: stored });
|
|
1280
1218
|
}
|
|
1281
1219
|
} catch (err) {
|
|
1282
1220
|
if (!cancel.current) setError(err instanceof Error ? err.message : String(err));
|
|
@@ -1336,12 +1274,16 @@ function HomeView() {
|
|
|
1336
1274
|
},
|
|
1337
1275
|
[refresh, router, state]
|
|
1338
1276
|
);
|
|
1339
|
-
|
|
1277
|
+
useInput4((input, key) => {
|
|
1340
1278
|
if (mode === "busy") return;
|
|
1341
1279
|
if (key.escape && typeof mode === "object") {
|
|
1342
1280
|
setMode("main");
|
|
1343
1281
|
return;
|
|
1344
1282
|
}
|
|
1283
|
+
if (input === "h" && typeof mode === "object") {
|
|
1284
|
+
setMode("main");
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1345
1287
|
if (mode === "main" && input === "b" && state !== null) {
|
|
1346
1288
|
const menu = buildSubMenu("browse", state.ctx);
|
|
1347
1289
|
if (menu) setMode({ kind: "sub", menu, group: "browse" });
|
|
@@ -1450,7 +1392,7 @@ import "react";
|
|
|
1450
1392
|
|
|
1451
1393
|
// src/integration/ui/tui/views/settings-panel.tsx
|
|
1452
1394
|
import { useCallback as useCallback3, useEffect as useEffect5, useState as useState5 } from "react";
|
|
1453
|
-
import { Box as Box10, Text as Text9, useInput as
|
|
1395
|
+
import { Box as Box10, Text as Text9, useInput as useInput5 } from "ink";
|
|
1454
1396
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1455
1397
|
var SETTINGS_HINTS = [
|
|
1456
1398
|
{ key: "\u2191/\u2193", action: "navigate" },
|
|
@@ -1572,7 +1514,7 @@ function SettingsPanel({ onClose }) {
|
|
|
1572
1514
|
setEditing(false);
|
|
1573
1515
|
}
|
|
1574
1516
|
}, [cursor, entries, config, saveValue]);
|
|
1575
|
-
|
|
1517
|
+
useInput5((input, key) => {
|
|
1576
1518
|
if (editing) return;
|
|
1577
1519
|
if (key.escape) {
|
|
1578
1520
|
onClose();
|
|
@@ -1663,15 +1605,17 @@ function SettingsView() {
|
|
|
1663
1605
|
}
|
|
1664
1606
|
|
|
1665
1607
|
// src/integration/ui/tui/views/execute-view.tsx
|
|
1666
|
-
import { useEffect as useEffect8, useRef as useRef2, useState as useState8 } from "react";
|
|
1667
|
-
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";
|
|
1668
1610
|
|
|
1669
1611
|
// src/integration/ui/tui/runtime/hooks.ts
|
|
1670
1612
|
import { useCallback as useCallback4, useEffect as useEffect6, useRef, useState as useState6 } from "react";
|
|
1671
|
-
function useLoggerEvents(limit = 200) {
|
|
1613
|
+
function useLoggerEvents(limit = 200, bus) {
|
|
1672
1614
|
const [buffer, setBuffer] = useState6([]);
|
|
1615
|
+
const source = bus ?? logEventBus;
|
|
1673
1616
|
useEffect6(() => {
|
|
1674
|
-
|
|
1617
|
+
setBuffer([]);
|
|
1618
|
+
const unsubscribe = source.subscribe((batch) => {
|
|
1675
1619
|
setBuffer((prev) => {
|
|
1676
1620
|
const next = prev.concat(batch);
|
|
1677
1621
|
if (next.length > limit) next.splice(0, next.length - limit);
|
|
@@ -1679,12 +1623,29 @@ function useLoggerEvents(limit = 200) {
|
|
|
1679
1623
|
});
|
|
1680
1624
|
});
|
|
1681
1625
|
return unsubscribe;
|
|
1682
|
-
}, [limit]);
|
|
1626
|
+
}, [limit, source]);
|
|
1683
1627
|
return buffer;
|
|
1684
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
|
+
}
|
|
1685
1644
|
function useSignalEvents(bus, limit = 200) {
|
|
1686
1645
|
const [buffer, setBuffer] = useState6([]);
|
|
1687
1646
|
useEffect6(() => {
|
|
1647
|
+
setBuffer([]);
|
|
1648
|
+
if (bus === null) return;
|
|
1688
1649
|
const unsubscribe = bus.subscribe((batch) => {
|
|
1689
1650
|
setBuffer((prev) => {
|
|
1690
1651
|
const next = prev.concat(batch);
|
|
@@ -1987,10 +1948,59 @@ function RateLimitBanner({ pausedSince, delayMs }) {
|
|
|
1987
1948
|
] });
|
|
1988
1949
|
}
|
|
1989
1950
|
|
|
1990
|
-
// 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";
|
|
1991
1958
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1992
|
-
|
|
1993
|
-
|
|
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" }];
|
|
1994
2004
|
function initialState() {
|
|
1995
2005
|
return {
|
|
1996
2006
|
sprint: null,
|
|
@@ -1999,62 +2009,104 @@ function initialState() {
|
|
|
1999
2009
|
blocked: /* @__PURE__ */ new Set(),
|
|
2000
2010
|
activity: /* @__PURE__ */ new Map(),
|
|
2001
2011
|
currentStep: /* @__PURE__ */ new Map(),
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
rateLimit: null
|
|
2012
|
+
rateLimit: null,
|
|
2013
|
+
taskRefreshError: null
|
|
2005
2014
|
};
|
|
2006
2015
|
}
|
|
2007
|
-
|
|
2016
|
+
var initialAttach = {
|
|
2017
|
+
kind: "attaching",
|
|
2018
|
+
execution: null,
|
|
2019
|
+
collisionId: null,
|
|
2020
|
+
errorMessage: null
|
|
2021
|
+
};
|
|
2022
|
+
function ExecuteView({ sprintId, executionId, executionOptions }) {
|
|
2008
2023
|
const router = useRouter();
|
|
2009
2024
|
const shared = getSharedDeps();
|
|
2010
|
-
const
|
|
2011
|
-
const
|
|
2025
|
+
const registry = shared.executionRegistry;
|
|
2026
|
+
const registryEvents = useRegistryEvents(registry);
|
|
2027
|
+
const [attach, setAttach] = useState8(initialAttach);
|
|
2012
2028
|
const [state, setState] = useState8(initialState);
|
|
2013
|
-
const [done, setDone] = useState8(false);
|
|
2014
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]);
|
|
2015
2036
|
useEffect8(() => {
|
|
2016
|
-
|
|
2017
|
-
|
|
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 () => {
|
|
2018
2054
|
try {
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
shared.persistence.getTasks(sprintId)
|
|
2022
|
-
]);
|
|
2023
|
-
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 });
|
|
2024
2057
|
} catch (err) {
|
|
2025
|
-
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
|
+
});
|
|
2026
2073
|
}
|
|
2027
|
-
};
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}, [
|
|
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);
|
|
2033
2086
|
useEffect8(() => {
|
|
2034
|
-
if (state.sprint === null || done) return;
|
|
2035
2087
|
const cancel = { current: false };
|
|
2036
|
-
|
|
2088
|
+
void (async () => {
|
|
2037
2089
|
try {
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
const summary = result.value.context.executionSummary ?? null;
|
|
2043
|
-
setState((s) => ({ ...s, summary }));
|
|
2044
|
-
} else {
|
|
2045
|
-
setState((s) => ({ ...s, error: result.error.message }));
|
|
2090
|
+
if (liveExecution) {
|
|
2091
|
+
if (!cancel.current) {
|
|
2092
|
+
setState((s) => ({ ...s, sprint: liveExecution.sprint }));
|
|
2093
|
+
}
|
|
2046
2094
|
}
|
|
2095
|
+
const tasks = await shared.persistence.getTasks(sprintId);
|
|
2096
|
+
if (!cancel.current) setState((s) => ({ ...s, tasks }));
|
|
2047
2097
|
} catch (err) {
|
|
2048
|
-
if (!cancel.current)
|
|
2049
|
-
|
|
2050
|
-
|
|
2098
|
+
if (!cancel.current) {
|
|
2099
|
+
setState((s) => ({ ...s, taskRefreshError: err instanceof Error ? err.message : String(err) }));
|
|
2100
|
+
}
|
|
2051
2101
|
}
|
|
2052
|
-
};
|
|
2053
|
-
void run();
|
|
2102
|
+
})();
|
|
2054
2103
|
return () => {
|
|
2055
2104
|
cancel.current = true;
|
|
2056
2105
|
};
|
|
2057
|
-
}, [
|
|
2106
|
+
}, [liveExecution, shared, sprintId]);
|
|
2107
|
+
useEffect8(() => {
|
|
2108
|
+
processedCountRef.current = 0;
|
|
2109
|
+
}, [scopedSignalBus]);
|
|
2058
2110
|
useEffect8(() => {
|
|
2059
2111
|
if (signalEvents.length <= processedCountRef.current) return;
|
|
2060
2112
|
const fresh = signalEvents.slice(processedCountRef.current);
|
|
@@ -2070,18 +2122,20 @@ function ExecuteView({ sprintId, executionOptions }) {
|
|
|
2070
2122
|
})();
|
|
2071
2123
|
}
|
|
2072
2124
|
}, [signalEvents, shared, sprintId]);
|
|
2125
|
+
const status = liveExecution?.status ?? "running";
|
|
2126
|
+
const terminal = status === "completed" || status === "failed" || status === "cancelled";
|
|
2073
2127
|
const [closePromptRun, setClosePromptRun] = useState8(false);
|
|
2074
2128
|
useEffect8(() => {
|
|
2075
|
-
if (!
|
|
2129
|
+
if (!terminal) return;
|
|
2130
|
+
if (closePromptRun) return;
|
|
2131
|
+
setClosePromptRun(true);
|
|
2076
2132
|
void (async () => {
|
|
2077
2133
|
try {
|
|
2078
2134
|
const tasks = await shared.persistence.getTasks(sprintId);
|
|
2079
2135
|
setState((s) => ({ ...s, tasks }));
|
|
2080
2136
|
} catch {
|
|
2081
2137
|
}
|
|
2082
|
-
|
|
2083
|
-
setClosePromptRun(true);
|
|
2084
|
-
const summary = state.summary;
|
|
2138
|
+
const summary = liveExecution ? liveExecution.summary : void 0;
|
|
2085
2139
|
if (summary?.stopReason === "all_completed" && summary.remaining === 0 && summary.completed > 0 && await areAllTasksDone(sprintId)) {
|
|
2086
2140
|
try {
|
|
2087
2141
|
const shouldClose = await getPrompt().confirm({
|
|
@@ -2093,28 +2147,62 @@ function ExecuteView({ sprintId, executionOptions }) {
|
|
|
2093
2147
|
}
|
|
2094
2148
|
}
|
|
2095
2149
|
})();
|
|
2096
|
-
}, [
|
|
2097
|
-
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
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();
|
|
2102
2158
|
}
|
|
2103
2159
|
});
|
|
2104
|
-
useViewHints(
|
|
2105
|
-
|
|
2106
|
-
/* @__PURE__ */
|
|
2107
|
-
/* @__PURE__ */
|
|
2108
|
-
|
|
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: [
|
|
2109
2197
|
" ",
|
|
2110
2198
|
state.sprint?.branch ? `[${state.sprint.branch}]` : "",
|
|
2111
2199
|
" ",
|
|
2112
2200
|
state.sprint?.status ? `(${state.sprint.status})` : ""
|
|
2113
2201
|
] })
|
|
2114
2202
|
] }),
|
|
2115
|
-
/* @__PURE__ */
|
|
2116
|
-
state.rateLimit ? /* @__PURE__ */
|
|
2117
|
-
/* @__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(
|
|
2118
2206
|
TaskGrid,
|
|
2119
2207
|
{
|
|
2120
2208
|
tasks: state.tasks,
|
|
@@ -2123,42 +2211,61 @@ function ExecuteView({ sprintId, executionOptions }) {
|
|
|
2123
2211
|
activityByTask: state.activity
|
|
2124
2212
|
}
|
|
2125
2213
|
) }),
|
|
2126
|
-
!
|
|
2214
|
+
!terminal && state.currentStep.size > 0 ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, flexDirection: "column", children: Array.from(state.currentStep.entries()).map(([taskId, label]) => {
|
|
2127
2215
|
const task = state.tasks.find((t) => t.id === taskId);
|
|
2128
2216
|
const taskName = task?.name ?? taskId.slice(0, 8);
|
|
2129
|
-
return /* @__PURE__ */
|
|
2217
|
+
return /* @__PURE__ */ jsx20(Spinner, { label: `${taskName} ${glyphs.emDash} ${label}` }, taskId);
|
|
2130
2218
|
}) }) : null,
|
|
2131
|
-
/* @__PURE__ */
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
state.summary && done ? /* @__PURE__ */ jsxs16(Box17, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
2138
|
-
/* @__PURE__ */ jsxs16(Text16, { color: inkColors.success, bold: true, children: [
|
|
2139
|
-
glyphs.check,
|
|
2140
|
-
" 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
|
|
2141
2225
|
] }),
|
|
2142
|
-
/* @__PURE__ */
|
|
2143
|
-
|
|
2226
|
+
liveExecution.summary ? /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
|
|
2227
|
+
liveExecution.summary.completed,
|
|
2144
2228
|
" completed ",
|
|
2145
2229
|
glyphs.inlineDot,
|
|
2146
2230
|
" ",
|
|
2147
|
-
|
|
2231
|
+
liveExecution.summary.remaining,
|
|
2148
2232
|
" remaining",
|
|
2149
2233
|
" ",
|
|
2150
2234
|
glyphs.inlineDot,
|
|
2151
2235
|
" ",
|
|
2152
|
-
|
|
2236
|
+
liveExecution.summary.blocked,
|
|
2153
2237
|
" blocked",
|
|
2154
2238
|
" (",
|
|
2155
|
-
|
|
2239
|
+
liveExecution.summary.stopReason,
|
|
2156
2240
|
")"
|
|
2157
|
-
] })
|
|
2158
|
-
/* @__PURE__ */ jsx18(Box17, { marginTop: spacing.section, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: "Press any key to return home." }) })
|
|
2241
|
+
] }) : null
|
|
2159
2242
|
] }) : null
|
|
2160
2243
|
] });
|
|
2161
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
|
+
}
|
|
2162
2269
|
var STEP_LABELS = {
|
|
2163
2270
|
"branch-preflight": "Verifying branch\u2026",
|
|
2164
2271
|
"contract-negotiate": "Writing contract\u2026",
|
|
@@ -2229,57 +2336,6 @@ function reduceEvents(state, events) {
|
|
|
2229
2336
|
// src/integration/ui/tui/views/dashboard-view.tsx
|
|
2230
2337
|
import { useEffect as useEffect9, useState as useState9 } from "react";
|
|
2231
2338
|
import { Box as Box20, Text as Text19 } from "ink";
|
|
2232
|
-
|
|
2233
|
-
// src/integration/ui/tui/components/result-card.tsx
|
|
2234
|
-
import "react";
|
|
2235
|
-
import { Box as Box19, Text as Text18 } from "ink";
|
|
2236
|
-
|
|
2237
|
-
// src/integration/ui/tui/components/field-list.tsx
|
|
2238
|
-
import "react";
|
|
2239
|
-
import { Box as Box18, Text as Text17 } from "ink";
|
|
2240
|
-
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2241
|
-
function FieldList({ fields, labelWidth = FIELD_LABEL_WIDTH }) {
|
|
2242
|
-
return /* @__PURE__ */ jsx19(Box18, { flexDirection: "column", children: fields.map(([label, value]) => /* @__PURE__ */ jsxs17(Box18, { children: [
|
|
2243
|
-
/* @__PURE__ */ jsx19(Text17, { dimColor: true, children: (label + ":").padEnd(labelWidth) }),
|
|
2244
|
-
/* @__PURE__ */ jsx19(Text17, { children: ` ${value}` })
|
|
2245
|
-
] }, label)) });
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
// src/integration/ui/tui/components/result-card.tsx
|
|
2249
|
-
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2250
|
-
var GLYPH = {
|
|
2251
|
-
success: glyphs.check,
|
|
2252
|
-
error: glyphs.cross,
|
|
2253
|
-
warning: glyphs.warningGlyph,
|
|
2254
|
-
info: glyphs.infoGlyph
|
|
2255
|
-
};
|
|
2256
|
-
var COLOR = {
|
|
2257
|
-
success: inkColors.success,
|
|
2258
|
-
error: inkColors.error,
|
|
2259
|
-
warning: inkColors.warning,
|
|
2260
|
-
info: inkColors.info
|
|
2261
|
-
};
|
|
2262
|
-
function ResultCard({ kind, title, fields, nextSteps, lines }) {
|
|
2263
|
-
const color2 = COLOR[kind];
|
|
2264
|
-
return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
|
|
2265
|
-
/* @__PURE__ */ jsxs18(Box19, { children: [
|
|
2266
|
-
/* @__PURE__ */ jsx20(Text18, { color: color2, bold: true, children: GLYPH[kind] }),
|
|
2267
|
-
/* @__PURE__ */ jsx20(Text18, { color: color2, bold: true, children: ` ${title}` })
|
|
2268
|
-
] }),
|
|
2269
|
-
fields && fields.length > 0 ? /* @__PURE__ */ jsx20(Box19, { marginTop: spacing.section, children: /* @__PURE__ */ jsx20(FieldList, { fields }) }) : null,
|
|
2270
|
-
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,
|
|
2271
|
-
nextSteps && nextSteps.length > 0 ? /* @__PURE__ */ jsxs18(Box19, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
2272
|
-
/* @__PURE__ */ jsx20(Text18, { dimColor: true, bold: true, children: "Next" }),
|
|
2273
|
-
nextSteps.map((step, i) => /* @__PURE__ */ jsxs18(Box19, { paddingLeft: spacing.indent, children: [
|
|
2274
|
-
/* @__PURE__ */ jsx20(Text18, { color: inkColors.highlight, children: `${glyphs.arrowRight} ` }),
|
|
2275
|
-
/* @__PURE__ */ jsx20(Text18, { children: step.action }),
|
|
2276
|
-
step.description ? /* @__PURE__ */ jsx20(Text18, { dimColor: true, children: ` ${glyphs.emDash} ${step.description}` }) : null
|
|
2277
|
-
] }, i))
|
|
2278
|
-
] }) : null
|
|
2279
|
-
] });
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
// src/integration/ui/tui/views/dashboard-view.tsx
|
|
2283
2339
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2284
2340
|
var PROGRESS_TAIL_LIMIT = 8;
|
|
2285
2341
|
async function loadRecentProgress(sprintId, limit) {
|
|
@@ -2311,12 +2367,12 @@ function Hero({ data }) {
|
|
|
2311
2367
|
const ticketCount = sprint.tickets.length;
|
|
2312
2368
|
const taskCount = tasks.length;
|
|
2313
2369
|
const providerLabel = aiProvider === "claude" ? "Claude" : aiProvider === "copilot" ? "Copilot" : null;
|
|
2314
|
-
const
|
|
2370
|
+
const statusColor7 = sprint.status === "active" ? inkColors.success : sprint.status === "closed" ? inkColors.info : inkColors.muted;
|
|
2315
2371
|
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
2316
2372
|
/* @__PURE__ */ jsxs19(Box20, { children: [
|
|
2317
2373
|
/* @__PURE__ */ jsx21(Text19, { bold: true, color: inkColors.primary, children: sprint.name }),
|
|
2318
2374
|
/* @__PURE__ */ jsx21(Text19, { children: " " }),
|
|
2319
|
-
/* @__PURE__ */ jsxs19(Text19, { color:
|
|
2375
|
+
/* @__PURE__ */ jsxs19(Text19, { color: statusColor7, children: [
|
|
2320
2376
|
"[",
|
|
2321
2377
|
sprint.status,
|
|
2322
2378
|
"]"
|
|
@@ -2434,7 +2490,7 @@ var EMPTY_MAP = /* @__PURE__ */ new Map();
|
|
|
2434
2490
|
|
|
2435
2491
|
// src/integration/ui/tui/views/phases/refine-phase-view.tsx
|
|
2436
2492
|
import { useCallback as useCallback5, useEffect as useEffect10, useState as useState10 } from "react";
|
|
2437
|
-
import { Box as Box22, Text as Text21, useInput as
|
|
2493
|
+
import { Box as Box22, Text as Text21, useInput as useInput7 } from "ink";
|
|
2438
2494
|
|
|
2439
2495
|
// src/integration/ui/tui/views/phases/phase-run-trace.tsx
|
|
2440
2496
|
import "react";
|
|
@@ -2460,13 +2516,13 @@ function formatDuration(ms) {
|
|
|
2460
2516
|
function PhaseRunTrace({ records, title = "Last run" }) {
|
|
2461
2517
|
return /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", children: [
|
|
2462
2518
|
/* @__PURE__ */ jsx22(Box21, { children: /* @__PURE__ */ jsx22(Text20, { dimColor: true, bold: true, children: title }) }),
|
|
2463
|
-
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: [
|
|
2464
2520
|
/* @__PURE__ */ jsxs20(Box21, { children: [
|
|
2465
2521
|
/* @__PURE__ */ jsx22(Text20, { color: STATUS_COLOR2[r.status], bold: true, children: STATUS_GLYPH2[r.status] }),
|
|
2466
2522
|
/* @__PURE__ */ jsx22(Text20, { children: ` ${r.stepName} ` }),
|
|
2467
2523
|
/* @__PURE__ */ jsx22(Text20, { dimColor: true, children: formatDuration(r.durationMs) })
|
|
2468
2524
|
] }),
|
|
2469
|
-
r.error ? /* @__PURE__ */ jsx22(Box21, { paddingLeft:
|
|
2525
|
+
r.error ? /* @__PURE__ */ jsx22(Box21, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsxs20(Text20, { color: inkColors.error, children: [
|
|
2470
2526
|
"\u21B3 ",
|
|
2471
2527
|
r.error.message
|
|
2472
2528
|
] }) }) : null
|
|
@@ -2528,7 +2584,7 @@ function RefinePhaseView({ sprintId }) {
|
|
|
2528
2584
|
await loadSprint();
|
|
2529
2585
|
}
|
|
2530
2586
|
}, [shared, sprintId, loadSprint]);
|
|
2531
|
-
|
|
2587
|
+
useInput7(
|
|
2532
2588
|
(_input, key) => {
|
|
2533
2589
|
if (key.return && !state.running && canRefine(state.sprint)) {
|
|
2534
2590
|
void runRefine();
|
|
@@ -2590,7 +2646,7 @@ function reasonUnavailable(sprint) {
|
|
|
2590
2646
|
|
|
2591
2647
|
// src/integration/ui/tui/views/phases/plan-phase-view.tsx
|
|
2592
2648
|
import { useCallback as useCallback6, useEffect as useEffect11, useState as useState11 } from "react";
|
|
2593
|
-
import { Box as Box23, Text as Text22, useInput as
|
|
2649
|
+
import { Box as Box23, Text as Text22, useInput as useInput8 } from "ink";
|
|
2594
2650
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2595
2651
|
var HINTS_RUNNABLE2 = [
|
|
2596
2652
|
{ key: "Enter", action: "plan" },
|
|
@@ -2634,7 +2690,7 @@ function PlanPhaseView({ sprintId }) {
|
|
|
2634
2690
|
await loadSprintAndTasks();
|
|
2635
2691
|
}
|
|
2636
2692
|
}, [shared, sprintId, loadSprintAndTasks]);
|
|
2637
|
-
|
|
2693
|
+
useInput8(
|
|
2638
2694
|
(_input, key) => {
|
|
2639
2695
|
if (key.return && !state.running && canPlan(state.sprint)) {
|
|
2640
2696
|
void runPlan();
|
|
@@ -2711,18 +2767,20 @@ function groupTasksByPath(tasks) {
|
|
|
2711
2767
|
function statusGlyph(status) {
|
|
2712
2768
|
if (status === "done") return glyphs.check;
|
|
2713
2769
|
if (status === "in_progress") return glyphs.actionCursor;
|
|
2770
|
+
if (status === "cancelled") return glyphs.cross;
|
|
2714
2771
|
return glyphs.inlineDot;
|
|
2715
2772
|
}
|
|
2716
2773
|
function statusColor2(status) {
|
|
2717
2774
|
if (status === "done") return inkColors.success;
|
|
2718
2775
|
if (status === "in_progress") return inkColors.warning;
|
|
2776
|
+
if (status === "cancelled") return inkColors.muted;
|
|
2719
2777
|
return inkColors.muted;
|
|
2720
2778
|
}
|
|
2721
2779
|
|
|
2722
2780
|
// src/integration/ui/tui/views/phases/close-phase-view.tsx
|
|
2723
2781
|
import { spawnSync } from "child_process";
|
|
2724
|
-
import { useCallback as useCallback7, useEffect as useEffect12, useMemo as
|
|
2725
|
-
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";
|
|
2726
2784
|
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2727
2785
|
var HINTS_READY = [
|
|
2728
2786
|
{ key: "\u2191/\u2193", action: "select" },
|
|
@@ -2755,7 +2813,7 @@ function ClosePhaseView({ sprintId }) {
|
|
|
2755
2813
|
useEffect12(() => {
|
|
2756
2814
|
void load();
|
|
2757
2815
|
}, [load]);
|
|
2758
|
-
const actions =
|
|
2816
|
+
const actions = useMemo7(() => {
|
|
2759
2817
|
const sprint2 = state.sprint;
|
|
2760
2818
|
if (sprint2?.status !== "active") return [];
|
|
2761
2819
|
const base = ["close"];
|
|
@@ -2801,7 +2859,7 @@ function ClosePhaseView({ sprintId }) {
|
|
|
2801
2859
|
},
|
|
2802
2860
|
[sprintId, state.sprint]
|
|
2803
2861
|
);
|
|
2804
|
-
|
|
2862
|
+
useInput9(
|
|
2805
2863
|
(_input, key) => {
|
|
2806
2864
|
const { phase: phase2 } = state;
|
|
2807
2865
|
if (phase2.kind === "done" || phase2.kind === "error") {
|
|
@@ -3000,11 +3058,11 @@ ID: ${sprintId}`
|
|
|
3000
3058
|
}
|
|
3001
3059
|
|
|
3002
3060
|
// src/integration/ui/tui/views/workflows/create-sprint-view.tsx
|
|
3003
|
-
import { useMemo as
|
|
3061
|
+
import { useMemo as useMemo8 } from "react";
|
|
3004
3062
|
|
|
3005
3063
|
// src/integration/ui/tui/views/workflows/use-workflow.ts
|
|
3006
3064
|
import { useCallback as useCallback8, useEffect as useEffect13, useState as useState13 } from "react";
|
|
3007
|
-
import { useInput as
|
|
3065
|
+
import { useInput as useInput10 } from "ink";
|
|
3008
3066
|
var DEFAULT_NON_INTERACTIVE = /* @__PURE__ */ new Set(["running", "loading"]);
|
|
3009
3067
|
function defaultIsTerminal(phase) {
|
|
3010
3068
|
return !DEFAULT_NON_INTERACTIVE.has(phase.kind);
|
|
@@ -3016,7 +3074,7 @@ function useWorkflow(options) {
|
|
|
3016
3074
|
const router = useRouter();
|
|
3017
3075
|
const [phase, setPhase] = useState13(options.initial);
|
|
3018
3076
|
const [started, setStarted] = useState13(false);
|
|
3019
|
-
const
|
|
3077
|
+
const isTerminal2 = options.isTerminal ?? defaultIsTerminal;
|
|
3020
3078
|
const isInteractive = options.isInteractive ?? defaultIsInteractive;
|
|
3021
3079
|
const kick = useCallback8(async () => {
|
|
3022
3080
|
try {
|
|
@@ -3034,9 +3092,9 @@ function useWorkflow(options) {
|
|
|
3034
3092
|
setStarted(true);
|
|
3035
3093
|
void kick();
|
|
3036
3094
|
}, [started, kick]);
|
|
3037
|
-
|
|
3095
|
+
useInput10(
|
|
3038
3096
|
(_input, key) => {
|
|
3039
|
-
if (key.return &&
|
|
3097
|
+
if (key.return && isTerminal2(phase)) router.pop();
|
|
3040
3098
|
},
|
|
3041
3099
|
{ isActive: isInteractive(phase) }
|
|
3042
3100
|
);
|
|
@@ -3094,7 +3152,7 @@ function CreateSprintView() {
|
|
|
3094
3152
|
setPhase({ kind: "done", sprint, project, setAsCurrent });
|
|
3095
3153
|
}
|
|
3096
3154
|
});
|
|
3097
|
-
const hints =
|
|
3155
|
+
const hints = useMemo8(() => phase.kind === "running" ? HINTS_RUNNING : HINTS_DONE, [phase.kind]);
|
|
3098
3156
|
useViewHints(hints);
|
|
3099
3157
|
return /* @__PURE__ */ jsx26(ViewShell, { title: TITLE, children: renderBody(phase) });
|
|
3100
3158
|
}
|
|
@@ -3136,84 +3194,154 @@ function renderBody(phase) {
|
|
|
3136
3194
|
}
|
|
3137
3195
|
|
|
3138
3196
|
// src/integration/ui/tui/views/workflows/delete-sprint-view.tsx
|
|
3139
|
-
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";
|
|
3140
3202
|
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
3141
|
-
var TITLE2 = "Delete Sprint";
|
|
3142
3203
|
var HINTS_RUNNING2 = [{ key: "Esc", action: "cancel" }];
|
|
3143
3204
|
var HINTS_DONE2 = [
|
|
3144
|
-
{ key: "Enter", action: "
|
|
3205
|
+
{ key: "Enter", action: "back" },
|
|
3145
3206
|
{ key: "Esc", action: "back" }
|
|
3146
3207
|
];
|
|
3147
|
-
function
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
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" });
|
|
3158
3226
|
return;
|
|
3159
3227
|
}
|
|
3160
|
-
setPhase({ kind: "running"
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
}
|
|
3168
|
-
|
|
3169
|
-
const sprint = await getSprint(targetId);
|
|
3170
|
-
if (sprint.status === "active") {
|
|
3171
|
-
setPhase({ kind: "active-blocked", name: sprint.name });
|
|
3172
|
-
return;
|
|
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) });
|
|
3173
3237
|
}
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
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) });
|
|
3183
3307
|
}
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
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
|
+
}
|
|
3191
3330
|
}
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
const clearedCurrent = currentId === targetId;
|
|
3196
|
-
if (clearedCurrent) await setCurrentSprint(null);
|
|
3197
|
-
setPhase({ kind: "done", name: sprint.name, id: sprint.id, clearedCurrent });
|
|
3198
|
-
}
|
|
3199
|
-
});
|
|
3200
|
-
const running = phase.kind === "running" || phase.kind === "loading";
|
|
3201
|
-
const hints = useMemo8(() => running ? HINTS_RUNNING2 : HINTS_DONE2, [running]);
|
|
3202
|
-
useViewHints(hints);
|
|
3203
|
-
return /* @__PURE__ */ jsx27(ViewShell, { title: TITLE2, children: renderBody2(phase) });
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
return /* @__PURE__ */ jsx28(ViewShell, { title: TITLE2, children: renderPre(phase) });
|
|
3204
3334
|
}
|
|
3205
|
-
function
|
|
3335
|
+
function renderPre(phase) {
|
|
3206
3336
|
switch (phase.kind) {
|
|
3207
3337
|
case "loading":
|
|
3208
|
-
return /* @__PURE__ */
|
|
3338
|
+
return /* @__PURE__ */ jsx28(Spinner, { label: "Loading sprints\u2026" });
|
|
3339
|
+
case "selecting":
|
|
3340
|
+
return /* @__PURE__ */ jsx28(Spinner, { label: "Awaiting selection\u2026" });
|
|
3209
3341
|
case "no-sprints":
|
|
3210
|
-
return /* @__PURE__ */
|
|
3211
|
-
case "running":
|
|
3212
|
-
return /* @__PURE__ */ jsx27(Spinner, { label: runningLabel(phase.step) });
|
|
3213
|
-
case "cancelled":
|
|
3214
|
-
return /* @__PURE__ */ jsx27(ResultCard, { kind: "info", title: "Deletion cancelled" });
|
|
3342
|
+
return /* @__PURE__ */ jsx28(ResultCard, { kind: "info", title: "No sprints to delete" });
|
|
3215
3343
|
case "active-blocked":
|
|
3216
|
-
return /* @__PURE__ */
|
|
3344
|
+
return /* @__PURE__ */ jsx28(
|
|
3217
3345
|
ResultCard,
|
|
3218
3346
|
{
|
|
3219
3347
|
kind: "warning",
|
|
@@ -3222,31 +3350,16 @@ function renderBody2(phase) {
|
|
|
3222
3350
|
}
|
|
3223
3351
|
);
|
|
3224
3352
|
case "error":
|
|
3225
|
-
return /* @__PURE__ */
|
|
3226
|
-
case "done":
|
|
3227
|
-
return /* @__PURE__ */ jsx27(
|
|
3228
|
-
ResultCard,
|
|
3229
|
-
{
|
|
3230
|
-
kind: "success",
|
|
3231
|
-
title: "Sprint deleted",
|
|
3232
|
-
fields: [
|
|
3233
|
-
["Name", phase.name],
|
|
3234
|
-
["ID", phase.id]
|
|
3235
|
-
],
|
|
3236
|
-
lines: phase.clearedCurrent ? ["Current sprint pointer was cleared."] : void 0
|
|
3237
|
-
}
|
|
3238
|
-
);
|
|
3353
|
+
return /* @__PURE__ */ jsx28(ResultCard, { kind: "error", title: "Could not delete sprint", lines: [phase.message] });
|
|
3239
3354
|
}
|
|
3240
3355
|
}
|
|
3241
|
-
function
|
|
3242
|
-
|
|
3243
|
-
if (step === "confirm") return "Awaiting confirmation\u2026";
|
|
3244
|
-
return "Deleting sprint\u2026";
|
|
3356
|
+
function pluralize2(noun, count) {
|
|
3357
|
+
return count === 1 ? noun : `${noun}s`;
|
|
3245
3358
|
}
|
|
3246
3359
|
|
|
3247
3360
|
// src/integration/ui/tui/views/workflows/set-current-sprint-view.tsx
|
|
3248
|
-
import { useMemo as
|
|
3249
|
-
import { jsx as
|
|
3361
|
+
import { useMemo as useMemo10 } from "react";
|
|
3362
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
3250
3363
|
var TITLE3 = "Set Current Sprint";
|
|
3251
3364
|
var HINTS_RUNNING3 = [{ key: "Esc", action: "cancel" }];
|
|
3252
3365
|
var HINTS_DONE3 = [
|
|
@@ -3278,18 +3391,18 @@ function SetCurrentSprintView() {
|
|
|
3278
3391
|
}
|
|
3279
3392
|
});
|
|
3280
3393
|
const running = phase.kind === "loading" || phase.kind === "running";
|
|
3281
|
-
const hints =
|
|
3394
|
+
const hints = useMemo10(() => running ? HINTS_RUNNING3 : HINTS_DONE3, [running]);
|
|
3282
3395
|
useViewHints(hints);
|
|
3283
|
-
return /* @__PURE__ */
|
|
3396
|
+
return /* @__PURE__ */ jsx29(ViewShell, { title: TITLE3, children: renderBody3(phase) });
|
|
3284
3397
|
}
|
|
3285
3398
|
function renderBody3(phase) {
|
|
3286
3399
|
switch (phase.kind) {
|
|
3287
3400
|
case "loading":
|
|
3288
|
-
return /* @__PURE__ */
|
|
3401
|
+
return /* @__PURE__ */ jsx29(Spinner, { label: "Loading sprints\u2026" });
|
|
3289
3402
|
case "running":
|
|
3290
|
-
return /* @__PURE__ */
|
|
3403
|
+
return /* @__PURE__ */ jsx29(Spinner, { label: "Awaiting sprint selection\u2026" });
|
|
3291
3404
|
case "no-candidates":
|
|
3292
|
-
return /* @__PURE__ */
|
|
3405
|
+
return /* @__PURE__ */ jsx29(
|
|
3293
3406
|
ResultCard,
|
|
3294
3407
|
{
|
|
3295
3408
|
kind: "info",
|
|
@@ -3298,9 +3411,9 @@ function renderBody3(phase) {
|
|
|
3298
3411
|
}
|
|
3299
3412
|
);
|
|
3300
3413
|
case "error":
|
|
3301
|
-
return /* @__PURE__ */
|
|
3414
|
+
return /* @__PURE__ */ jsx29(ResultCard, { kind: "error", title: "Could not set current sprint", lines: [phase.message] });
|
|
3302
3415
|
case "done":
|
|
3303
|
-
return /* @__PURE__ */
|
|
3416
|
+
return /* @__PURE__ */ jsx29(
|
|
3304
3417
|
ResultCard,
|
|
3305
3418
|
{
|
|
3306
3419
|
kind: "success",
|
|
@@ -3316,8 +3429,8 @@ function renderBody3(phase) {
|
|
|
3316
3429
|
|
|
3317
3430
|
// src/integration/ui/tui/views/workflows/requirements-export-view.tsx
|
|
3318
3431
|
import { join } from "path";
|
|
3319
|
-
import { useMemo as
|
|
3320
|
-
import { jsx as
|
|
3432
|
+
import { useMemo as useMemo11 } from "react";
|
|
3433
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
3321
3434
|
var TITLE4 = "Export Requirements";
|
|
3322
3435
|
var HINTS_RUNNING4 = [{ key: "Esc", action: "cancel" }];
|
|
3323
3436
|
var HINTS_DONE4 = [
|
|
@@ -3351,16 +3464,16 @@ function RequirementsExportView({ sprintId }) {
|
|
|
3351
3464
|
});
|
|
3352
3465
|
}
|
|
3353
3466
|
});
|
|
3354
|
-
const hints =
|
|
3467
|
+
const hints = useMemo11(() => phase.kind === "running" ? HINTS_RUNNING4 : HINTS_DONE4, [phase.kind]);
|
|
3355
3468
|
useViewHints(hints);
|
|
3356
|
-
return /* @__PURE__ */
|
|
3469
|
+
return /* @__PURE__ */ jsx30(ViewShell, { title: TITLE4, children: renderBody4(phase) });
|
|
3357
3470
|
}
|
|
3358
3471
|
function renderBody4(phase) {
|
|
3359
3472
|
switch (phase.kind) {
|
|
3360
3473
|
case "running":
|
|
3361
|
-
return /* @__PURE__ */
|
|
3474
|
+
return /* @__PURE__ */ jsx30(Spinner, { label: "Writing requirements.md\u2026" });
|
|
3362
3475
|
case "empty":
|
|
3363
|
-
return /* @__PURE__ */
|
|
3476
|
+
return /* @__PURE__ */ jsx30(
|
|
3364
3477
|
ResultCard,
|
|
3365
3478
|
{
|
|
3366
3479
|
kind: "warning",
|
|
@@ -3369,7 +3482,7 @@ function renderBody4(phase) {
|
|
|
3369
3482
|
}
|
|
3370
3483
|
);
|
|
3371
3484
|
case "no-approved":
|
|
3372
|
-
return /* @__PURE__ */
|
|
3485
|
+
return /* @__PURE__ */ jsx30(
|
|
3373
3486
|
ResultCard,
|
|
3374
3487
|
{
|
|
3375
3488
|
kind: "warning",
|
|
@@ -3378,9 +3491,9 @@ function renderBody4(phase) {
|
|
|
3378
3491
|
}
|
|
3379
3492
|
);
|
|
3380
3493
|
case "error":
|
|
3381
|
-
return /* @__PURE__ */
|
|
3494
|
+
return /* @__PURE__ */ jsx30(ResultCard, { kind: "error", title: "Could not export", lines: [phase.message] });
|
|
3382
3495
|
case "done":
|
|
3383
|
-
return /* @__PURE__ */
|
|
3496
|
+
return /* @__PURE__ */ jsx30(
|
|
3384
3497
|
ResultCard,
|
|
3385
3498
|
{
|
|
3386
3499
|
kind: "success",
|
|
@@ -3398,8 +3511,8 @@ function renderBody4(phase) {
|
|
|
3398
3511
|
// src/integration/ui/tui/views/workflows/context-export-view.tsx
|
|
3399
3512
|
import { writeFile } from "fs/promises";
|
|
3400
3513
|
import { join as join2 } from "path";
|
|
3401
|
-
import { useMemo as
|
|
3402
|
-
import { jsx as
|
|
3514
|
+
import { useMemo as useMemo12 } from "react";
|
|
3515
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
3403
3516
|
var TITLE5 = "Export Context";
|
|
3404
3517
|
var HINTS_RUNNING5 = [{ key: "Esc", action: "cancel" }];
|
|
3405
3518
|
var HINTS_DONE5 = [
|
|
@@ -3428,18 +3541,18 @@ function ContextExportView({ sprintId }) {
|
|
|
3428
3541
|
});
|
|
3429
3542
|
}
|
|
3430
3543
|
});
|
|
3431
|
-
const hints =
|
|
3544
|
+
const hints = useMemo12(() => phase.kind === "running" ? HINTS_RUNNING5 : HINTS_DONE5, [phase.kind]);
|
|
3432
3545
|
useViewHints(hints);
|
|
3433
|
-
return /* @__PURE__ */
|
|
3546
|
+
return /* @__PURE__ */ jsx31(ViewShell, { title: TITLE5, children: renderBody5(phase) });
|
|
3434
3547
|
}
|
|
3435
3548
|
function renderBody5(phase) {
|
|
3436
3549
|
switch (phase.kind) {
|
|
3437
3550
|
case "running":
|
|
3438
|
-
return /* @__PURE__ */
|
|
3551
|
+
return /* @__PURE__ */ jsx31(Spinner, { label: "Writing context.md\u2026" });
|
|
3439
3552
|
case "error":
|
|
3440
|
-
return /* @__PURE__ */
|
|
3553
|
+
return /* @__PURE__ */ jsx31(ResultCard, { kind: "error", title: "Could not export context", lines: [phase.message] });
|
|
3441
3554
|
case "done":
|
|
3442
|
-
return /* @__PURE__ */
|
|
3555
|
+
return /* @__PURE__ */ jsx31(
|
|
3443
3556
|
ResultCard,
|
|
3444
3557
|
{
|
|
3445
3558
|
kind: "success",
|
|
@@ -3528,8 +3641,8 @@ async function renderContextMarkdown(sprint, tasks) {
|
|
|
3528
3641
|
}
|
|
3529
3642
|
|
|
3530
3643
|
// src/integration/ui/tui/views/workflows/ticket-add-view.tsx
|
|
3531
|
-
import { useMemo as
|
|
3532
|
-
import { jsx as
|
|
3644
|
+
import { useMemo as useMemo13 } from "react";
|
|
3645
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
3533
3646
|
var TITLE6 = "Add Ticket";
|
|
3534
3647
|
var HINTS_RUNNING6 = [{ key: "Esc", action: "cancel" }];
|
|
3535
3648
|
var HINTS_DONE6 = [
|
|
@@ -3625,16 +3738,16 @@ function TicketAddView() {
|
|
|
3625
3738
|
}
|
|
3626
3739
|
}
|
|
3627
3740
|
});
|
|
3628
|
-
const hints =
|
|
3741
|
+
const hints = useMemo13(() => phase.kind === "running" ? HINTS_RUNNING6 : HINTS_DONE6, [phase.kind]);
|
|
3629
3742
|
useViewHints(hints);
|
|
3630
|
-
return /* @__PURE__ */
|
|
3743
|
+
return /* @__PURE__ */ jsx32(ViewShell, { title: TITLE6, children: renderBody6(phase) });
|
|
3631
3744
|
}
|
|
3632
3745
|
function renderBody6(phase) {
|
|
3633
3746
|
switch (phase.kind) {
|
|
3634
3747
|
case "running":
|
|
3635
|
-
return /* @__PURE__ */
|
|
3748
|
+
return /* @__PURE__ */ jsx32(Spinner, { label: STEP_LABEL[phase.step] });
|
|
3636
3749
|
case "no-draft-sprint":
|
|
3637
|
-
return /* @__PURE__ */
|
|
3750
|
+
return /* @__PURE__ */ jsx32(
|
|
3638
3751
|
ResultCard,
|
|
3639
3752
|
{
|
|
3640
3753
|
kind: "warning",
|
|
@@ -3644,7 +3757,7 @@ function renderBody6(phase) {
|
|
|
3644
3757
|
}
|
|
3645
3758
|
);
|
|
3646
3759
|
case "no-project":
|
|
3647
|
-
return /* @__PURE__ */
|
|
3760
|
+
return /* @__PURE__ */ jsx32(
|
|
3648
3761
|
ResultCard,
|
|
3649
3762
|
{
|
|
3650
3763
|
kind: "warning",
|
|
@@ -3653,10 +3766,10 @@ function renderBody6(phase) {
|
|
|
3653
3766
|
}
|
|
3654
3767
|
);
|
|
3655
3768
|
case "error":
|
|
3656
|
-
return /* @__PURE__ */
|
|
3769
|
+
return /* @__PURE__ */ jsx32(ResultCard, { kind: "error", title: "Could not add ticket", lines: [phase.message] });
|
|
3657
3770
|
case "done": {
|
|
3658
3771
|
const title = phase.count > 1 ? `${String(phase.count)} tickets added` : phase.prefilled ? "Ticket added (prefilled from issue)" : "Ticket added";
|
|
3659
|
-
return /* @__PURE__ */
|
|
3772
|
+
return /* @__PURE__ */ jsx32(
|
|
3660
3773
|
ResultCard,
|
|
3661
3774
|
{
|
|
3662
3775
|
kind: "success",
|
|
@@ -3675,8 +3788,8 @@ function renderBody6(phase) {
|
|
|
3675
3788
|
}
|
|
3676
3789
|
|
|
3677
3790
|
// src/integration/ui/tui/views/workflows/ticket-edit-view.tsx
|
|
3678
|
-
import { useMemo as
|
|
3679
|
-
import { jsx as
|
|
3791
|
+
import { useMemo as useMemo14 } from "react";
|
|
3792
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
3680
3793
|
var TITLE7 = "Edit Ticket";
|
|
3681
3794
|
var HINTS_RUNNING7 = [{ key: "Esc", action: "cancel" }];
|
|
3682
3795
|
var HINTS_DONE7 = [
|
|
@@ -3750,18 +3863,18 @@ function TicketEditView({ ticketId } = {}) {
|
|
|
3750
3863
|
setPhase({ kind: "done", ticket, field });
|
|
3751
3864
|
}
|
|
3752
3865
|
});
|
|
3753
|
-
const hints =
|
|
3866
|
+
const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING7 : HINTS_DONE7, [phase.kind]);
|
|
3754
3867
|
useViewHints(hints);
|
|
3755
|
-
return /* @__PURE__ */
|
|
3868
|
+
return /* @__PURE__ */ jsx33(ViewShell, { title: TITLE7, children: renderBody7(phase) });
|
|
3756
3869
|
}
|
|
3757
3870
|
function renderBody7(phase) {
|
|
3758
3871
|
switch (phase.kind) {
|
|
3759
3872
|
case "running":
|
|
3760
|
-
return /* @__PURE__ */
|
|
3873
|
+
return /* @__PURE__ */ jsx33(Spinner, { label: stepLabel(phase.step) });
|
|
3761
3874
|
case "no-tickets":
|
|
3762
|
-
return /* @__PURE__ */
|
|
3875
|
+
return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "No tickets to edit" });
|
|
3763
3876
|
case "no-draft-sprint":
|
|
3764
|
-
return /* @__PURE__ */
|
|
3877
|
+
return /* @__PURE__ */ jsx33(
|
|
3765
3878
|
ResultCard,
|
|
3766
3879
|
{
|
|
3767
3880
|
kind: "warning",
|
|
@@ -3770,9 +3883,9 @@ function renderBody7(phase) {
|
|
|
3770
3883
|
}
|
|
3771
3884
|
);
|
|
3772
3885
|
case "error":
|
|
3773
|
-
return /* @__PURE__ */
|
|
3886
|
+
return /* @__PURE__ */ jsx33(ResultCard, { kind: "error", title: "Could not edit ticket", lines: [phase.message] });
|
|
3774
3887
|
case "done":
|
|
3775
|
-
return /* @__PURE__ */
|
|
3888
|
+
return /* @__PURE__ */ jsx33(
|
|
3776
3889
|
ResultCard,
|
|
3777
3890
|
{
|
|
3778
3891
|
kind: "success",
|
|
@@ -3799,97 +3912,86 @@ function stepLabel(step) {
|
|
|
3799
3912
|
}
|
|
3800
3913
|
|
|
3801
3914
|
// src/integration/ui/tui/views/workflows/ticket-remove-view.tsx
|
|
3802
|
-
import {
|
|
3803
|
-
import { jsx as
|
|
3915
|
+
import { useEffect as useEffect16, useState as useState16 } from "react";
|
|
3916
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
3804
3917
|
var TITLE8 = "Remove Ticket";
|
|
3805
|
-
var HINTS_RUNNING8 = [{ key: "Esc", action: "cancel" }];
|
|
3806
|
-
var HINTS_DONE8 = [
|
|
3807
|
-
{ key: "Enter", action: "home" },
|
|
3808
|
-
{ key: "Esc", action: "back" }
|
|
3809
|
-
];
|
|
3810
3918
|
function TicketRemoveView() {
|
|
3811
|
-
const
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
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) });
|
|
3825
3955
|
}
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
}
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
message: `Remove ticket "${target.title}"? This cannot be undone.`,
|
|
3840
|
-
default: false
|
|
3841
|
-
});
|
|
3842
|
-
if (!ok) {
|
|
3843
|
-
setPhase({ kind: "cancelled" });
|
|
3844
|
-
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
|
+
}
|
|
3845
3969
|
}
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
}
|
|
3850
|
-
});
|
|
3851
|
-
const hints = useMemo14(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
|
|
3852
|
-
useViewHints(hints);
|
|
3853
|
-
return /* @__PURE__ */ jsx33(ViewShell, { title: TITLE8, children: renderBody8(phase) });
|
|
3970
|
+
);
|
|
3971
|
+
}
|
|
3972
|
+
return /* @__PURE__ */ jsx34(ViewShell, { title: TITLE8, children: renderPre2(phase) });
|
|
3854
3973
|
}
|
|
3855
|
-
function
|
|
3974
|
+
function renderPre2(phase) {
|
|
3856
3975
|
switch (phase.kind) {
|
|
3857
|
-
case "
|
|
3858
|
-
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" });
|
|
3859
3980
|
case "no-tickets":
|
|
3860
|
-
return /* @__PURE__ */
|
|
3981
|
+
return /* @__PURE__ */ jsx34(ResultCard, { kind: "info", title: "No tickets to remove" });
|
|
3861
3982
|
case "no-draft-sprint":
|
|
3862
|
-
return /* @__PURE__ */
|
|
3863
|
-
case "cancelled":
|
|
3864
|
-
return /* @__PURE__ */ jsx33(ResultCard, { kind: "info", title: "Removal cancelled" });
|
|
3983
|
+
return /* @__PURE__ */ jsx34(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
3865
3984
|
case "error":
|
|
3866
|
-
return /* @__PURE__ */
|
|
3867
|
-
case "done":
|
|
3868
|
-
return /* @__PURE__ */ jsx33(
|
|
3869
|
-
ResultCard,
|
|
3870
|
-
{
|
|
3871
|
-
kind: "success",
|
|
3872
|
-
title: "Ticket removed",
|
|
3873
|
-
fields: [
|
|
3874
|
-
["ID", phase.id],
|
|
3875
|
-
["Title", phase.title]
|
|
3876
|
-
]
|
|
3877
|
-
}
|
|
3878
|
-
);
|
|
3985
|
+
return /* @__PURE__ */ jsx34(ResultCard, { kind: "error", title: "Could not remove ticket", lines: [phase.message] });
|
|
3879
3986
|
}
|
|
3880
3987
|
}
|
|
3881
|
-
function stepLabel2(step) {
|
|
3882
|
-
if (step === "select") return "Awaiting ticket selection\u2026";
|
|
3883
|
-
if (step === "confirm") return "Awaiting confirmation\u2026";
|
|
3884
|
-
return "Removing ticket\u2026";
|
|
3885
|
-
}
|
|
3886
3988
|
|
|
3887
3989
|
// src/integration/ui/tui/views/workflows/ticket-refine-view.tsx
|
|
3888
3990
|
import { useMemo as useMemo15 } from "react";
|
|
3889
|
-
import { jsx as
|
|
3991
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3890
3992
|
var TITLE9 = "Re-Refine Ticket";
|
|
3891
|
-
var
|
|
3892
|
-
var
|
|
3993
|
+
var HINTS_RUNNING8 = [{ key: "Esc", action: "cancel" }];
|
|
3994
|
+
var HINTS_DONE8 = [
|
|
3893
3995
|
{ key: "Enter", action: "home" },
|
|
3894
3996
|
{ key: "Esc", action: "back" }
|
|
3895
3997
|
];
|
|
@@ -3921,18 +4023,18 @@ function TicketRefineView() {
|
|
|
3921
4023
|
setPhase({ kind: "done", ticketTitle: target.title });
|
|
3922
4024
|
}
|
|
3923
4025
|
});
|
|
3924
|
-
const hints = useMemo15(() => phase.kind === "running" ?
|
|
4026
|
+
const hints = useMemo15(() => phase.kind === "running" ? HINTS_RUNNING8 : HINTS_DONE8, [phase.kind]);
|
|
3925
4027
|
useViewHints(hints);
|
|
3926
|
-
return /* @__PURE__ */
|
|
4028
|
+
return /* @__PURE__ */ jsx35(ViewShell, { title: TITLE9, children: renderBody8(phase) });
|
|
3927
4029
|
}
|
|
3928
|
-
function
|
|
4030
|
+
function renderBody8(phase) {
|
|
3929
4031
|
switch (phase.kind) {
|
|
3930
4032
|
case "running":
|
|
3931
|
-
return /* @__PURE__ */
|
|
4033
|
+
return /* @__PURE__ */ jsx35(Spinner, { label: phase.step === "select" ? "Awaiting ticket selection\u2026" : "Running AI session\u2026" });
|
|
3932
4034
|
case "no-draft-sprint":
|
|
3933
|
-
return /* @__PURE__ */
|
|
4035
|
+
return /* @__PURE__ */ jsx35(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
3934
4036
|
case "no-approved":
|
|
3935
|
-
return /* @__PURE__ */
|
|
4037
|
+
return /* @__PURE__ */ jsx35(
|
|
3936
4038
|
ResultCard,
|
|
3937
4039
|
{
|
|
3938
4040
|
kind: "warning",
|
|
@@ -3941,9 +4043,9 @@ function renderBody9(phase) {
|
|
|
3941
4043
|
}
|
|
3942
4044
|
);
|
|
3943
4045
|
case "error":
|
|
3944
|
-
return /* @__PURE__ */
|
|
4046
|
+
return /* @__PURE__ */ jsx35(ResultCard, { kind: "error", title: "Re-refinement failed", lines: [phase.message] });
|
|
3945
4047
|
case "done":
|
|
3946
|
-
return /* @__PURE__ */
|
|
4048
|
+
return /* @__PURE__ */ jsx35(
|
|
3947
4049
|
ResultCard,
|
|
3948
4050
|
{
|
|
3949
4051
|
kind: "success",
|
|
@@ -3957,10 +4059,10 @@ function renderBody9(phase) {
|
|
|
3957
4059
|
|
|
3958
4060
|
// src/integration/ui/tui/views/workflows/task-add-view.tsx
|
|
3959
4061
|
import { useMemo as useMemo16 } from "react";
|
|
3960
|
-
import { jsx as
|
|
4062
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
3961
4063
|
var TITLE10 = "Add Task";
|
|
3962
|
-
var
|
|
3963
|
-
var
|
|
4064
|
+
var HINTS_RUNNING9 = [{ key: "Esc", action: "cancel" }];
|
|
4065
|
+
var HINTS_DONE9 = [
|
|
3964
4066
|
{ key: "Enter", action: "home" },
|
|
3965
4067
|
{ key: "Esc", action: "back" }
|
|
3966
4068
|
];
|
|
@@ -4023,22 +4125,22 @@ function TaskAddView() {
|
|
|
4023
4125
|
setPhase({ kind: "done", task, repo });
|
|
4024
4126
|
}
|
|
4025
4127
|
});
|
|
4026
|
-
const hints = useMemo16(() => phase.kind === "running" ?
|
|
4128
|
+
const hints = useMemo16(() => phase.kind === "running" ? HINTS_RUNNING9 : HINTS_DONE9, [phase.kind]);
|
|
4027
4129
|
useViewHints(hints);
|
|
4028
|
-
return /* @__PURE__ */
|
|
4130
|
+
return /* @__PURE__ */ jsx36(ViewShell, { title: TITLE10, children: renderBody9(phase) });
|
|
4029
4131
|
}
|
|
4030
|
-
function
|
|
4132
|
+
function renderBody9(phase) {
|
|
4031
4133
|
switch (phase.kind) {
|
|
4032
4134
|
case "running":
|
|
4033
|
-
return /* @__PURE__ */
|
|
4135
|
+
return /* @__PURE__ */ jsx36(Spinner, { label: stepLabel2(phase.step) });
|
|
4034
4136
|
case "no-project":
|
|
4035
|
-
return /* @__PURE__ */
|
|
4137
|
+
return /* @__PURE__ */ jsx36(ResultCard, { kind: "warning", title: "Sprint's project is missing or has no repos" });
|
|
4036
4138
|
case "no-draft-sprint":
|
|
4037
|
-
return /* @__PURE__ */
|
|
4139
|
+
return /* @__PURE__ */ jsx36(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
4038
4140
|
case "error":
|
|
4039
|
-
return /* @__PURE__ */
|
|
4141
|
+
return /* @__PURE__ */ jsx36(ResultCard, { kind: "error", title: "Could not add task", lines: [phase.message] });
|
|
4040
4142
|
case "done":
|
|
4041
|
-
return /* @__PURE__ */
|
|
4143
|
+
return /* @__PURE__ */ jsx36(
|
|
4042
4144
|
ResultCard,
|
|
4043
4145
|
{
|
|
4044
4146
|
kind: "success",
|
|
@@ -4053,7 +4155,7 @@ function renderBody10(phase) {
|
|
|
4053
4155
|
);
|
|
4054
4156
|
}
|
|
4055
4157
|
}
|
|
4056
|
-
function
|
|
4158
|
+
function stepLabel2(step) {
|
|
4057
4159
|
if (step === "repo") return "Awaiting repo selection\u2026";
|
|
4058
4160
|
if (step === "name") return "Awaiting task name\u2026";
|
|
4059
4161
|
if (step === "description") return "Awaiting description\u2026";
|
|
@@ -4062,10 +4164,10 @@ function stepLabel3(step) {
|
|
|
4062
4164
|
|
|
4063
4165
|
// src/integration/ui/tui/views/workflows/task-import-view.tsx
|
|
4064
4166
|
import { useMemo as useMemo17 } from "react";
|
|
4065
|
-
import { jsx as
|
|
4167
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
4066
4168
|
var TITLE11 = "Import Tasks";
|
|
4067
|
-
var
|
|
4068
|
-
var
|
|
4169
|
+
var HINTS_RUNNING10 = [{ key: "Esc", action: "cancel" }];
|
|
4170
|
+
var HINTS_DONE10 = [
|
|
4069
4171
|
{ key: "Enter", action: "home" },
|
|
4070
4172
|
{ key: "Esc", action: "back" }
|
|
4071
4173
|
];
|
|
@@ -4085,29 +4187,29 @@ function TaskImportView() {
|
|
|
4085
4187
|
setPhase({ kind: "done" });
|
|
4086
4188
|
}
|
|
4087
4189
|
});
|
|
4088
|
-
const hints = useMemo17(() => phase.kind === "running" ?
|
|
4190
|
+
const hints = useMemo17(() => phase.kind === "running" ? HINTS_RUNNING10 : HINTS_DONE10, [phase.kind]);
|
|
4089
4191
|
useViewHints(hints);
|
|
4090
|
-
return /* @__PURE__ */
|
|
4192
|
+
return /* @__PURE__ */ jsx37(ViewShell, { title: TITLE11, children: renderBody10(phase) });
|
|
4091
4193
|
}
|
|
4092
|
-
function
|
|
4194
|
+
function renderBody10(phase) {
|
|
4093
4195
|
switch (phase.kind) {
|
|
4094
4196
|
case "running":
|
|
4095
|
-
return /* @__PURE__ */
|
|
4197
|
+
return /* @__PURE__ */ jsx37(Spinner, { label: phase.step === "path" ? "Awaiting JSON file path\u2026" : "Importing tasks\u2026" });
|
|
4096
4198
|
case "done":
|
|
4097
|
-
return /* @__PURE__ */
|
|
4199
|
+
return /* @__PURE__ */ jsx37(ResultCard, { kind: "success", title: "Import finished", lines: ["Check the task list to see the result."] });
|
|
4098
4200
|
case "cancelled":
|
|
4099
|
-
return /* @__PURE__ */
|
|
4201
|
+
return /* @__PURE__ */ jsx37(ResultCard, { kind: "info", title: "Import cancelled" });
|
|
4100
4202
|
case "error":
|
|
4101
|
-
return /* @__PURE__ */
|
|
4203
|
+
return /* @__PURE__ */ jsx37(ResultCard, { kind: "error", title: "Import failed", lines: [phase.message] });
|
|
4102
4204
|
}
|
|
4103
4205
|
}
|
|
4104
4206
|
|
|
4105
4207
|
// src/integration/ui/tui/views/workflows/task-status-view.tsx
|
|
4106
4208
|
import { useMemo as useMemo18 } from "react";
|
|
4107
|
-
import { jsx as
|
|
4209
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
4108
4210
|
var TITLE12 = "Task Status";
|
|
4109
|
-
var
|
|
4110
|
-
var
|
|
4211
|
+
var HINTS_RUNNING11 = [{ key: "Esc", action: "cancel" }];
|
|
4212
|
+
var HINTS_DONE11 = [
|
|
4111
4213
|
{ key: "Enter", action: "home" },
|
|
4112
4214
|
{ key: "Esc", action: "back" }
|
|
4113
4215
|
];
|
|
@@ -4150,18 +4252,18 @@ function TaskStatusView() {
|
|
|
4150
4252
|
setPhase({ kind: "done", task });
|
|
4151
4253
|
}
|
|
4152
4254
|
});
|
|
4153
|
-
const hints = useMemo18(() => phase.kind === "running" ?
|
|
4255
|
+
const hints = useMemo18(() => phase.kind === "running" ? HINTS_RUNNING11 : HINTS_DONE11, [phase.kind]);
|
|
4154
4256
|
useViewHints(hints);
|
|
4155
|
-
return /* @__PURE__ */
|
|
4257
|
+
return /* @__PURE__ */ jsx38(ViewShell, { title: TITLE12, children: renderBody11(phase) });
|
|
4156
4258
|
}
|
|
4157
|
-
function
|
|
4259
|
+
function renderBody11(phase) {
|
|
4158
4260
|
switch (phase.kind) {
|
|
4159
4261
|
case "running":
|
|
4160
|
-
return /* @__PURE__ */
|
|
4262
|
+
return /* @__PURE__ */ jsx38(Spinner, { label: stepLabel3(phase.step) });
|
|
4161
4263
|
case "no-tasks":
|
|
4162
|
-
return /* @__PURE__ */
|
|
4264
|
+
return /* @__PURE__ */ jsx38(ResultCard, { kind: "info", title: "No tasks in this sprint" });
|
|
4163
4265
|
case "not-active":
|
|
4164
|
-
return /* @__PURE__ */
|
|
4266
|
+
return /* @__PURE__ */ jsx38(
|
|
4165
4267
|
ResultCard,
|
|
4166
4268
|
{
|
|
4167
4269
|
kind: "warning",
|
|
@@ -4170,9 +4272,9 @@ function renderBody12(phase) {
|
|
|
4170
4272
|
}
|
|
4171
4273
|
);
|
|
4172
4274
|
case "error":
|
|
4173
|
-
return /* @__PURE__ */
|
|
4275
|
+
return /* @__PURE__ */ jsx38(ResultCard, { kind: "error", title: "Could not update status", lines: [phase.message] });
|
|
4174
4276
|
case "done":
|
|
4175
|
-
return /* @__PURE__ */
|
|
4277
|
+
return /* @__PURE__ */ jsx38(
|
|
4176
4278
|
ResultCard,
|
|
4177
4279
|
{
|
|
4178
4280
|
kind: "success",
|
|
@@ -4185,7 +4287,7 @@ function renderBody12(phase) {
|
|
|
4185
4287
|
);
|
|
4186
4288
|
}
|
|
4187
4289
|
}
|
|
4188
|
-
function
|
|
4290
|
+
function stepLabel3(step) {
|
|
4189
4291
|
if (step === "select-task") return "Awaiting task selection\u2026";
|
|
4190
4292
|
if (step === "select-status") return "Awaiting status selection\u2026";
|
|
4191
4293
|
return "Saving task\u2026";
|
|
@@ -4193,10 +4295,10 @@ function stepLabel4(step) {
|
|
|
4193
4295
|
|
|
4194
4296
|
// src/integration/ui/tui/views/workflows/task-reorder-view.tsx
|
|
4195
4297
|
import { useMemo as useMemo19 } from "react";
|
|
4196
|
-
import { jsx as
|
|
4298
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
4197
4299
|
var TITLE13 = "Reorder Task";
|
|
4198
|
-
var
|
|
4199
|
-
var
|
|
4300
|
+
var HINTS_RUNNING12 = [{ key: "Esc", action: "cancel" }];
|
|
4301
|
+
var HINTS_DONE12 = [
|
|
4200
4302
|
{ key: "Enter", action: "home" },
|
|
4201
4303
|
{ key: "Esc", action: "back" }
|
|
4202
4304
|
];
|
|
@@ -4240,22 +4342,22 @@ function TaskReorderView() {
|
|
|
4240
4342
|
setPhase({ kind: "done", task });
|
|
4241
4343
|
}
|
|
4242
4344
|
});
|
|
4243
|
-
const hints = useMemo19(() => phase.kind === "running" ?
|
|
4345
|
+
const hints = useMemo19(() => phase.kind === "running" ? HINTS_RUNNING12 : HINTS_DONE12, [phase.kind]);
|
|
4244
4346
|
useViewHints(hints);
|
|
4245
|
-
return /* @__PURE__ */
|
|
4347
|
+
return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE13, children: renderBody12(phase) });
|
|
4246
4348
|
}
|
|
4247
|
-
function
|
|
4349
|
+
function renderBody12(phase) {
|
|
4248
4350
|
switch (phase.kind) {
|
|
4249
4351
|
case "running":
|
|
4250
|
-
return /* @__PURE__ */
|
|
4352
|
+
return /* @__PURE__ */ jsx39(Spinner, { label: stepLabel4(phase.step) });
|
|
4251
4353
|
case "no-tasks":
|
|
4252
|
-
return /* @__PURE__ */
|
|
4354
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "No tasks in this sprint" });
|
|
4253
4355
|
case "not-draft":
|
|
4254
|
-
return /* @__PURE__ */
|
|
4356
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
4255
4357
|
case "error":
|
|
4256
|
-
return /* @__PURE__ */
|
|
4358
|
+
return /* @__PURE__ */ jsx39(ResultCard, { kind: "error", title: "Could not reorder", lines: [phase.message] });
|
|
4257
4359
|
case "done":
|
|
4258
|
-
return /* @__PURE__ */
|
|
4360
|
+
return /* @__PURE__ */ jsx39(
|
|
4259
4361
|
ResultCard,
|
|
4260
4362
|
{
|
|
4261
4363
|
kind: "success",
|
|
@@ -4268,100 +4370,89 @@ function renderBody13(phase) {
|
|
|
4268
4370
|
);
|
|
4269
4371
|
}
|
|
4270
4372
|
}
|
|
4271
|
-
function
|
|
4373
|
+
function stepLabel4(step) {
|
|
4272
4374
|
if (step === "select") return "Awaiting task selection\u2026";
|
|
4273
4375
|
if (step === "order") return "Awaiting new order\u2026";
|
|
4274
4376
|
return "Saving task\u2026";
|
|
4275
4377
|
}
|
|
4276
4378
|
|
|
4277
4379
|
// src/integration/ui/tui/views/workflows/task-remove-view.tsx
|
|
4278
|
-
import {
|
|
4279
|
-
import { jsx as
|
|
4380
|
+
import { useEffect as useEffect17, useState as useState17 } from "react";
|
|
4381
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
4280
4382
|
var TITLE14 = "Remove Task";
|
|
4281
|
-
var HINTS_RUNNING14 = [{ key: "Esc", action: "cancel" }];
|
|
4282
|
-
var HINTS_DONE14 = [
|
|
4283
|
-
{ key: "Enter", action: "home" },
|
|
4284
|
-
{ key: "Esc", action: "back" }
|
|
4285
|
-
];
|
|
4286
4383
|
function TaskRemoveView() {
|
|
4287
|
-
const
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
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) });
|
|
4301
4416
|
}
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
setPhase({ kind: "cancelled" });
|
|
4316
|
-
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
|
+
}
|
|
4317
4430
|
}
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
}
|
|
4322
|
-
});
|
|
4323
|
-
const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
|
|
4324
|
-
useViewHints(hints);
|
|
4325
|
-
return /* @__PURE__ */ jsx39(ViewShell, { title: TITLE14, children: renderBody14(phase) });
|
|
4431
|
+
);
|
|
4432
|
+
}
|
|
4433
|
+
return /* @__PURE__ */ jsx40(ViewShell, { title: TITLE14, children: renderPre3(phase) });
|
|
4326
4434
|
}
|
|
4327
|
-
function
|
|
4435
|
+
function renderPre3(phase) {
|
|
4328
4436
|
switch (phase.kind) {
|
|
4329
|
-
case "
|
|
4330
|
-
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" });
|
|
4331
4441
|
case "no-tasks":
|
|
4332
|
-
return /* @__PURE__ */
|
|
4442
|
+
return /* @__PURE__ */ jsx40(ResultCard, { kind: "info", title: "No tasks to remove" });
|
|
4333
4443
|
case "not-draft":
|
|
4334
|
-
return /* @__PURE__ */
|
|
4335
|
-
case "cancelled":
|
|
4336
|
-
return /* @__PURE__ */ jsx39(ResultCard, { kind: "info", title: "Removal cancelled" });
|
|
4444
|
+
return /* @__PURE__ */ jsx40(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
4337
4445
|
case "error":
|
|
4338
|
-
return /* @__PURE__ */
|
|
4339
|
-
case "done":
|
|
4340
|
-
return /* @__PURE__ */ jsx39(
|
|
4341
|
-
ResultCard,
|
|
4342
|
-
{
|
|
4343
|
-
kind: "success",
|
|
4344
|
-
title: "Task removed",
|
|
4345
|
-
fields: [
|
|
4346
|
-
["ID", phase.id],
|
|
4347
|
-
["Name", phase.name]
|
|
4348
|
-
]
|
|
4349
|
-
}
|
|
4350
|
-
);
|
|
4446
|
+
return /* @__PURE__ */ jsx40(ResultCard, { kind: "error", title: "Could not remove task", lines: [phase.message] });
|
|
4351
4447
|
}
|
|
4352
4448
|
}
|
|
4353
|
-
function stepLabel6(step) {
|
|
4354
|
-
if (step === "select") return "Awaiting task selection\u2026";
|
|
4355
|
-
if (step === "confirm") return "Awaiting confirmation\u2026";
|
|
4356
|
-
return "Removing task\u2026";
|
|
4357
|
-
}
|
|
4358
4449
|
|
|
4359
4450
|
// src/integration/ui/tui/views/workflows/task-next-view.tsx
|
|
4360
|
-
import { useMemo as
|
|
4361
|
-
import { jsx as
|
|
4451
|
+
import { useMemo as useMemo20 } from "react";
|
|
4452
|
+
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
4362
4453
|
var TITLE15 = "Next Task";
|
|
4363
|
-
var
|
|
4364
|
-
var
|
|
4454
|
+
var HINTS_RUNNING13 = [{ key: "Esc", action: "cancel" }];
|
|
4455
|
+
var HINTS_DONE13 = [
|
|
4365
4456
|
{ key: "Enter", action: "home" },
|
|
4366
4457
|
{ key: "Esc", action: "back" }
|
|
4367
4458
|
];
|
|
@@ -4378,20 +4469,20 @@ function TaskNextView() {
|
|
|
4378
4469
|
setPhase({ kind: "ready", task });
|
|
4379
4470
|
}
|
|
4380
4471
|
});
|
|
4381
|
-
const hints =
|
|
4472
|
+
const hints = useMemo20(() => phase.kind === "running" ? HINTS_RUNNING13 : HINTS_DONE13, [phase.kind]);
|
|
4382
4473
|
useViewHints(hints);
|
|
4383
|
-
return /* @__PURE__ */
|
|
4474
|
+
return /* @__PURE__ */ jsx41(ViewShell, { title: TITLE15, children: renderBody13(phase) });
|
|
4384
4475
|
}
|
|
4385
|
-
function
|
|
4476
|
+
function renderBody13(phase) {
|
|
4386
4477
|
switch (phase.kind) {
|
|
4387
4478
|
case "running":
|
|
4388
|
-
return /* @__PURE__ */
|
|
4479
|
+
return /* @__PURE__ */ jsx41(Spinner, { label: "Resolving next task\u2026" });
|
|
4389
4480
|
case "none":
|
|
4390
|
-
return /* @__PURE__ */
|
|
4481
|
+
return /* @__PURE__ */ jsx41(ResultCard, { kind: "info", title: "No task available", lines: ["All tasks are done or blocked."] });
|
|
4391
4482
|
case "error":
|
|
4392
|
-
return /* @__PURE__ */
|
|
4483
|
+
return /* @__PURE__ */ jsx41(ResultCard, { kind: "error", title: "Could not resolve next task", lines: [phase.message] });
|
|
4393
4484
|
case "ready":
|
|
4394
|
-
return /* @__PURE__ */
|
|
4485
|
+
return /* @__PURE__ */ jsx41(
|
|
4395
4486
|
ResultCard,
|
|
4396
4487
|
{
|
|
4397
4488
|
kind: "info",
|
|
@@ -4410,11 +4501,55 @@ function renderBody15(phase) {
|
|
|
4410
4501
|
|
|
4411
4502
|
// src/integration/ui/tui/views/workflows/project-add-view.tsx
|
|
4412
4503
|
import { resolve } from "path";
|
|
4413
|
-
import { useMemo as
|
|
4414
|
-
|
|
4504
|
+
import { useMemo as useMemo21 } from "react";
|
|
4505
|
+
|
|
4506
|
+
// src/integration/ui/tui/views/workflows/collect-check-script.ts
|
|
4507
|
+
async function collectCheckScript(repoPath, setStep) {
|
|
4508
|
+
const prompt = getPrompt();
|
|
4509
|
+
setStep("check-script");
|
|
4510
|
+
let detection;
|
|
4511
|
+
try {
|
|
4512
|
+
detection = detectCheckScriptCandidates(repoPath);
|
|
4513
|
+
} catch {
|
|
4514
|
+
detection = null;
|
|
4515
|
+
}
|
|
4516
|
+
let suggested = detection ? suggestCheckScript(repoPath) : null;
|
|
4517
|
+
if (suggested === null) {
|
|
4518
|
+
const config = await getConfig();
|
|
4519
|
+
const enabled = config.aiCheckScriptDiscovery ?? getConfigDefaultValue("aiCheckScriptDiscovery");
|
|
4520
|
+
if (enabled && config.aiProvider) {
|
|
4521
|
+
const wantAi = await prompt.confirm({
|
|
4522
|
+
message: "No ecosystem detected. Ask AI to inspect the repo and suggest a check script?",
|
|
4523
|
+
default: true
|
|
4524
|
+
});
|
|
4525
|
+
if (wantAi) {
|
|
4526
|
+
setStep("discovering");
|
|
4527
|
+
const aiSession = new ProviderAiSessionAdapter();
|
|
4528
|
+
const signalParser = new SignalParser();
|
|
4529
|
+
const discoverR = await wrapAsync(async () => {
|
|
4530
|
+
await aiSession.ensureReady();
|
|
4531
|
+
return discoverCheckScriptWithAi(repoPath, aiSession, signalParser);
|
|
4532
|
+
}, ensureError);
|
|
4533
|
+
if (discoverR.ok && discoverR.value) {
|
|
4534
|
+
suggested = discoverR.value;
|
|
4535
|
+
}
|
|
4536
|
+
setStep("check-script");
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
}
|
|
4540
|
+
const value = await prompt.input({
|
|
4541
|
+
message: "Check script (optional):",
|
|
4542
|
+
default: suggested ?? void 0
|
|
4543
|
+
});
|
|
4544
|
+
const trimmed = value.trim();
|
|
4545
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// src/integration/ui/tui/views/workflows/project-add-view.tsx
|
|
4549
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
4415
4550
|
var TITLE16 = "Add Project";
|
|
4416
|
-
var
|
|
4417
|
-
var
|
|
4551
|
+
var HINTS_RUNNING14 = [{ key: "Esc", action: "cancel" }];
|
|
4552
|
+
var HINTS_DONE14 = [
|
|
4418
4553
|
{ key: "Enter", action: "home" },
|
|
4419
4554
|
{ key: "Esc", action: "back" }
|
|
4420
4555
|
];
|
|
@@ -4448,25 +4583,28 @@ function ProjectAddView() {
|
|
|
4448
4583
|
});
|
|
4449
4584
|
const absolute = resolve(repoPath.trim().replace(/^~(\/|$)/, `${process.env["HOME"] ?? ""}$1`));
|
|
4450
4585
|
const repoName = absolute.split(/[\\/]/).pop() ?? "repo";
|
|
4586
|
+
const checkScript = await collectCheckScript(absolute, (next) => {
|
|
4587
|
+
setPhase({ kind: "running", step: next });
|
|
4588
|
+
});
|
|
4451
4589
|
setPhase({ kind: "running", step: "saving" });
|
|
4452
4590
|
const project = await createProject({
|
|
4453
4591
|
name: name.trim(),
|
|
4454
4592
|
displayName: display.trim(),
|
|
4455
|
-
repositories: [{ name: repoName, path: absolute }]
|
|
4593
|
+
repositories: [{ name: repoName, path: absolute, ...checkScript ? { checkScript } : {} }]
|
|
4456
4594
|
});
|
|
4457
4595
|
setPhase({ kind: "done", project });
|
|
4458
4596
|
}
|
|
4459
4597
|
});
|
|
4460
|
-
const hints =
|
|
4598
|
+
const hints = useMemo21(() => phase.kind === "running" ? HINTS_RUNNING14 : HINTS_DONE14, [phase.kind]);
|
|
4461
4599
|
useViewHints(hints);
|
|
4462
|
-
return /* @__PURE__ */
|
|
4600
|
+
return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE16, children: renderBody14(phase) });
|
|
4463
4601
|
}
|
|
4464
|
-
function
|
|
4602
|
+
function renderBody14(phase) {
|
|
4465
4603
|
switch (phase.kind) {
|
|
4466
4604
|
case "running":
|
|
4467
|
-
return /* @__PURE__ */
|
|
4605
|
+
return /* @__PURE__ */ jsx42(Spinner, { label: stepLabel5(phase.step) });
|
|
4468
4606
|
case "error":
|
|
4469
|
-
return /* @__PURE__ */
|
|
4607
|
+
return /* @__PURE__ */ jsx42(
|
|
4470
4608
|
ResultCard,
|
|
4471
4609
|
{
|
|
4472
4610
|
kind: "error",
|
|
@@ -4475,7 +4613,7 @@ function renderBody16(phase) {
|
|
|
4475
4613
|
}
|
|
4476
4614
|
);
|
|
4477
4615
|
case "done":
|
|
4478
|
-
return /* @__PURE__ */
|
|
4616
|
+
return /* @__PURE__ */ jsx42(
|
|
4479
4617
|
ResultCard,
|
|
4480
4618
|
{
|
|
4481
4619
|
kind: "success",
|
|
@@ -4490,87 +4628,88 @@ function renderBody16(phase) {
|
|
|
4490
4628
|
);
|
|
4491
4629
|
}
|
|
4492
4630
|
}
|
|
4493
|
-
function
|
|
4631
|
+
function stepLabel5(step) {
|
|
4494
4632
|
if (step === "name") return "Awaiting project slug\u2026";
|
|
4495
4633
|
if (step === "display") return "Awaiting display name\u2026";
|
|
4496
4634
|
if (step === "repo-path") return "Awaiting repository path\u2026";
|
|
4635
|
+
if (step === "check-script") return "Awaiting check-script confirmation\u2026";
|
|
4636
|
+
if (step === "discovering") return "Discovering check script with AI\u2026";
|
|
4497
4637
|
return "Saving project\u2026";
|
|
4498
4638
|
}
|
|
4499
4639
|
|
|
4500
4640
|
// src/integration/ui/tui/views/workflows/project-remove-view.tsx
|
|
4501
|
-
import {
|
|
4502
|
-
import { jsx as
|
|
4641
|
+
import { useEffect as useEffect18, useState as useState18 } from "react";
|
|
4642
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
4503
4643
|
var TITLE17 = "Remove Project";
|
|
4504
|
-
var HINTS_RUNNING17 = [{ key: "Esc", action: "cancel" }];
|
|
4505
|
-
var HINTS_DONE17 = [
|
|
4506
|
-
{ key: "Enter", action: "home" },
|
|
4507
|
-
{ key: "Esc", action: "back" }
|
|
4508
|
-
];
|
|
4509
4644
|
function ProjectRemoveView() {
|
|
4510
|
-
const
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
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) });
|
|
4519
4674
|
}
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
});
|
|
4534
|
-
if (!ok) {
|
|
4535
|
-
setPhase({ kind: "cancelled" });
|
|
4536
|
-
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
|
+
}
|
|
4537
4688
|
}
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
}
|
|
4542
|
-
});
|
|
4543
|
-
const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
|
|
4544
|
-
useViewHints(hints);
|
|
4545
|
-
return /* @__PURE__ */ jsx42(ViewShell, { title: TITLE17, children: renderBody17(phase) });
|
|
4689
|
+
);
|
|
4690
|
+
}
|
|
4691
|
+
return /* @__PURE__ */ jsx43(ViewShell, { title: TITLE17, children: renderPre4(phase) });
|
|
4546
4692
|
}
|
|
4547
|
-
function
|
|
4693
|
+
function renderPre4(phase) {
|
|
4548
4694
|
switch (phase.kind) {
|
|
4549
|
-
case "
|
|
4550
|
-
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" });
|
|
4551
4699
|
case "no-projects":
|
|
4552
|
-
return /* @__PURE__ */
|
|
4553
|
-
case "cancelled":
|
|
4554
|
-
return /* @__PURE__ */ jsx42(ResultCard, { kind: "info", title: "Removal cancelled" });
|
|
4700
|
+
return /* @__PURE__ */ jsx43(ResultCard, { kind: "info", title: "No projects to remove" });
|
|
4555
4701
|
case "error":
|
|
4556
|
-
return /* @__PURE__ */
|
|
4557
|
-
case "done":
|
|
4558
|
-
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] });
|
|
4559
4703
|
}
|
|
4560
4704
|
}
|
|
4561
|
-
function stepLabel8(step) {
|
|
4562
|
-
if (step === "select") return "Awaiting project selection\u2026";
|
|
4563
|
-
if (step === "confirm") return "Awaiting confirmation\u2026";
|
|
4564
|
-
return "Removing project\u2026";
|
|
4565
|
-
}
|
|
4566
4705
|
|
|
4567
4706
|
// src/integration/ui/tui/views/workflows/project-repo-add-view.tsx
|
|
4568
4707
|
import { resolve as resolve2 } from "path";
|
|
4569
|
-
import { useMemo as
|
|
4570
|
-
import { jsx as
|
|
4708
|
+
import { useMemo as useMemo22 } from "react";
|
|
4709
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
4571
4710
|
var TITLE18 = "Add Repository";
|
|
4572
|
-
var
|
|
4573
|
-
var
|
|
4711
|
+
var HINTS_RUNNING15 = [{ key: "Esc", action: "cancel" }];
|
|
4712
|
+
var HINTS_DONE15 = [
|
|
4574
4713
|
{ key: "Enter", action: "home" },
|
|
4575
4714
|
{ key: "Esc", action: "back" }
|
|
4576
4715
|
];
|
|
@@ -4597,25 +4736,32 @@ function ProjectRepoAddView() {
|
|
|
4597
4736
|
});
|
|
4598
4737
|
const absolute = resolve2(repoPath.trim().replace(/^~(\/|$)/, `${process.env["HOME"] ?? ""}$1`));
|
|
4599
4738
|
const repoName = absolute.split(/[\\/]/).pop() ?? "repo";
|
|
4739
|
+
const checkScript = await collectCheckScript(absolute, (next) => {
|
|
4740
|
+
setPhase({ kind: "running", step: next });
|
|
4741
|
+
});
|
|
4600
4742
|
setPhase({ kind: "running", step: "saving" });
|
|
4601
|
-
const project = await addProjectRepo(projectName, {
|
|
4743
|
+
const project = await addProjectRepo(projectName, {
|
|
4744
|
+
name: repoName,
|
|
4745
|
+
path: absolute,
|
|
4746
|
+
...checkScript ? { checkScript } : {}
|
|
4747
|
+
});
|
|
4602
4748
|
setPhase({ kind: "done", project, repoName });
|
|
4603
4749
|
}
|
|
4604
4750
|
});
|
|
4605
|
-
const hints =
|
|
4751
|
+
const hints = useMemo22(() => phase.kind === "running" ? HINTS_RUNNING15 : HINTS_DONE15, [phase.kind]);
|
|
4606
4752
|
useViewHints(hints);
|
|
4607
|
-
return /* @__PURE__ */
|
|
4753
|
+
return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE18, children: renderBody15(phase) });
|
|
4608
4754
|
}
|
|
4609
|
-
function
|
|
4755
|
+
function renderBody15(phase) {
|
|
4610
4756
|
switch (phase.kind) {
|
|
4611
4757
|
case "running":
|
|
4612
|
-
return /* @__PURE__ */
|
|
4758
|
+
return /* @__PURE__ */ jsx44(Spinner, { label: stepLabel6(phase.step) });
|
|
4613
4759
|
case "no-projects":
|
|
4614
|
-
return /* @__PURE__ */
|
|
4760
|
+
return /* @__PURE__ */ jsx44(ResultCard, { kind: "warning", title: "No projects to add a repository to" });
|
|
4615
4761
|
case "error":
|
|
4616
|
-
return /* @__PURE__ */
|
|
4762
|
+
return /* @__PURE__ */ jsx44(ResultCard, { kind: "error", title: "Could not add repository", lines: [phase.message] });
|
|
4617
4763
|
case "done":
|
|
4618
|
-
return /* @__PURE__ */
|
|
4764
|
+
return /* @__PURE__ */ jsx44(
|
|
4619
4765
|
ResultCard,
|
|
4620
4766
|
{
|
|
4621
4767
|
kind: "success",
|
|
@@ -4629,106 +4775,106 @@ function renderBody18(phase) {
|
|
|
4629
4775
|
);
|
|
4630
4776
|
}
|
|
4631
4777
|
}
|
|
4632
|
-
function
|
|
4778
|
+
function stepLabel6(step) {
|
|
4633
4779
|
if (step === "project") return "Awaiting project selection\u2026";
|
|
4634
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";
|
|
4635
4783
|
return "Saving repository\u2026";
|
|
4636
4784
|
}
|
|
4637
4785
|
|
|
4638
4786
|
// src/integration/ui/tui/views/workflows/project-repo-remove-view.tsx
|
|
4639
|
-
import {
|
|
4640
|
-
import { jsx as
|
|
4787
|
+
import { useEffect as useEffect19, useState as useState19 } from "react";
|
|
4788
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
4641
4789
|
var TITLE19 = "Remove Repository";
|
|
4642
|
-
var HINTS_RUNNING19 = [{ key: "Esc", action: "cancel" }];
|
|
4643
|
-
var HINTS_DONE19 = [
|
|
4644
|
-
{ key: "Enter", action: "home" },
|
|
4645
|
-
{ key: "Esc", action: "back" }
|
|
4646
|
-
];
|
|
4647
4790
|
function ProjectRepoRemoveView() {
|
|
4648
|
-
const
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
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) });
|
|
4667
4834
|
}
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
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
|
+
}
|
|
4682
4850
|
}
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
}
|
|
4687
|
-
});
|
|
4688
|
-
const hints = useMemo25(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
|
|
4689
|
-
useViewHints(hints);
|
|
4690
|
-
return /* @__PURE__ */ jsx44(ViewShell, { title: TITLE19, children: renderBody19(phase) });
|
|
4851
|
+
);
|
|
4852
|
+
}
|
|
4853
|
+
return /* @__PURE__ */ jsx45(ViewShell, { title: TITLE19, children: renderPre5(phase) });
|
|
4691
4854
|
}
|
|
4692
|
-
function
|
|
4855
|
+
function renderPre5(phase) {
|
|
4693
4856
|
switch (phase.kind) {
|
|
4694
|
-
case "
|
|
4695
|
-
return /* @__PURE__ */
|
|
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" });
|
|
4696
4863
|
case "no-projects":
|
|
4697
|
-
return /* @__PURE__ */
|
|
4864
|
+
return /* @__PURE__ */ jsx45(ResultCard, { kind: "info", title: "No projects" });
|
|
4698
4865
|
case "no-repos":
|
|
4699
|
-
return /* @__PURE__ */
|
|
4700
|
-
case "cancelled":
|
|
4701
|
-
return /* @__PURE__ */ jsx44(ResultCard, { kind: "info", title: "Removal cancelled" });
|
|
4866
|
+
return /* @__PURE__ */ jsx45(ResultCard, { kind: "info", title: "Project has no repositories" });
|
|
4702
4867
|
case "error":
|
|
4703
|
-
return /* @__PURE__ */
|
|
4704
|
-
|
|
4705
|
-
return /* @__PURE__ */ jsx44(
|
|
4706
|
-
ResultCard,
|
|
4707
|
-
{
|
|
4708
|
-
kind: "success",
|
|
4709
|
-
title: "Repository removed",
|
|
4710
|
-
fields: [
|
|
4711
|
-
["Project", phase.project.displayName],
|
|
4712
|
-
["Repo", phase.repoName],
|
|
4713
|
-
["Remaining", String(phase.project.repositories.length)]
|
|
4714
|
-
]
|
|
4715
|
-
}
|
|
4716
|
-
);
|
|
4717
|
-
}
|
|
4718
|
-
}
|
|
4719
|
-
function stepLabel10(step) {
|
|
4720
|
-
if (step === "project") return "Awaiting project selection\u2026";
|
|
4721
|
-
if (step === "repo") return "Awaiting repository selection\u2026";
|
|
4722
|
-
if (step === "confirm") return "Awaiting confirmation\u2026";
|
|
4723
|
-
return "Removing repository\u2026";
|
|
4868
|
+
return /* @__PURE__ */ jsx45(ResultCard, { kind: "error", title: "Could not remove repository", lines: [phase.message] });
|
|
4869
|
+
}
|
|
4724
4870
|
}
|
|
4725
4871
|
|
|
4726
4872
|
// src/integration/ui/tui/views/workflows/project-edit-view.tsx
|
|
4727
|
-
import { useMemo as
|
|
4728
|
-
import { jsx as
|
|
4873
|
+
import { useMemo as useMemo23 } from "react";
|
|
4874
|
+
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
4729
4875
|
var TITLE20 = "Edit Project";
|
|
4730
|
-
var
|
|
4731
|
-
var
|
|
4876
|
+
var HINTS_RUNNING16 = [{ key: "Esc", action: "cancel" }];
|
|
4877
|
+
var HINTS_DONE16 = [
|
|
4732
4878
|
{ key: "Enter", action: "home" },
|
|
4733
4879
|
{ key: "Esc", action: "back" }
|
|
4734
4880
|
];
|
|
@@ -4770,20 +4916,20 @@ function ProjectEditView() {
|
|
|
4770
4916
|
setPhase({ kind: "done", project });
|
|
4771
4917
|
}
|
|
4772
4918
|
});
|
|
4773
|
-
const hints =
|
|
4919
|
+
const hints = useMemo23(() => phase.kind === "running" ? HINTS_RUNNING16 : HINTS_DONE16, [phase.kind]);
|
|
4774
4920
|
useViewHints(hints);
|
|
4775
|
-
return /* @__PURE__ */
|
|
4921
|
+
return /* @__PURE__ */ jsx46(ViewShell, { title: TITLE20, children: renderBody16(phase) });
|
|
4776
4922
|
}
|
|
4777
|
-
function
|
|
4923
|
+
function renderBody16(phase) {
|
|
4778
4924
|
switch (phase.kind) {
|
|
4779
4925
|
case "running":
|
|
4780
|
-
return /* @__PURE__ */
|
|
4926
|
+
return /* @__PURE__ */ jsx46(Spinner, { label: stepLabel7(phase.step) });
|
|
4781
4927
|
case "no-projects":
|
|
4782
|
-
return /* @__PURE__ */
|
|
4928
|
+
return /* @__PURE__ */ jsx46(ResultCard, { kind: "info", title: "No projects registered" });
|
|
4783
4929
|
case "error":
|
|
4784
|
-
return /* @__PURE__ */
|
|
4930
|
+
return /* @__PURE__ */ jsx46(ResultCard, { kind: "error", title: "Could not update project", lines: [phase.message] });
|
|
4785
4931
|
case "done":
|
|
4786
|
-
return /* @__PURE__ */
|
|
4932
|
+
return /* @__PURE__ */ jsx46(
|
|
4787
4933
|
ResultCard,
|
|
4788
4934
|
{
|
|
4789
4935
|
kind: "success",
|
|
@@ -4797,21 +4943,116 @@ function renderBody20(phase) {
|
|
|
4797
4943
|
);
|
|
4798
4944
|
}
|
|
4799
4945
|
}
|
|
4800
|
-
function
|
|
4946
|
+
function stepLabel7(step) {
|
|
4801
4947
|
if (step === "select") return "Awaiting project selection\u2026";
|
|
4802
4948
|
if (step === "display") return "Awaiting display name\u2026";
|
|
4803
4949
|
if (step === "description") return "Awaiting description\u2026";
|
|
4804
4950
|
return "Saving project\u2026";
|
|
4805
4951
|
}
|
|
4806
4952
|
|
|
4953
|
+
// src/integration/ui/tui/views/workflows/project-onboard-view.tsx
|
|
4954
|
+
import { useMemo as useMemo24 } from "react";
|
|
4955
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
4956
|
+
var TITLE21 = "Onboard Repository";
|
|
4957
|
+
var HINTS_RUNNING17 = [{ key: "Esc", action: "cancel" }];
|
|
4958
|
+
var HINTS_DONE17 = [
|
|
4959
|
+
{ key: "Enter", action: "home" },
|
|
4960
|
+
{ key: "Esc", action: "back" }
|
|
4961
|
+
];
|
|
4962
|
+
function ProjectOnboardView({
|
|
4963
|
+
projectName: preselectedProject,
|
|
4964
|
+
repo: preselectedRepo
|
|
4965
|
+
} = {}) {
|
|
4966
|
+
const { phase } = useWorkflow({
|
|
4967
|
+
initial: preselectedProject ? { kind: "running", step: "onboarding" } : { kind: "running", step: "select-project" },
|
|
4968
|
+
onError: (message) => ({ kind: "error", message }),
|
|
4969
|
+
run: async ({ setPhase }) => {
|
|
4970
|
+
const shared = getSharedDeps();
|
|
4971
|
+
const prompt = shared.prompt;
|
|
4972
|
+
const projects = await listProjects();
|
|
4973
|
+
if (projects.length === 0) {
|
|
4974
|
+
setPhase({ kind: "no-projects" });
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4977
|
+
let projectName;
|
|
4978
|
+
if (preselectedProject) {
|
|
4979
|
+
projectName = preselectedProject;
|
|
4980
|
+
} else {
|
|
4981
|
+
setPhase({ kind: "running", step: "select-project" });
|
|
4982
|
+
projectName = await prompt.select({
|
|
4983
|
+
message: "Select a project to onboard:",
|
|
4984
|
+
choices: projects.map((p) => ({
|
|
4985
|
+
label: `${p.displayName} (${p.name})`,
|
|
4986
|
+
value: p.name,
|
|
4987
|
+
description: `${String(p.repositories.length)} repo${p.repositories.length === 1 ? "" : "s"}`
|
|
4988
|
+
}))
|
|
4989
|
+
});
|
|
4990
|
+
}
|
|
4991
|
+
setPhase({ kind: "running", step: "onboarding" });
|
|
4992
|
+
const options = preselectedRepo ? { repo: preselectedRepo } : {};
|
|
4993
|
+
const pipeline = createOnboardPipeline(shared, options);
|
|
4994
|
+
const initialContext = { sprintId: "", projectName };
|
|
4995
|
+
const result = await executePipeline(pipeline, initialContext);
|
|
4996
|
+
if (!result.ok) {
|
|
4997
|
+
setPhase({ kind: "error", message: result.error.message });
|
|
4998
|
+
return;
|
|
4999
|
+
}
|
|
5000
|
+
const ctx = result.value.context;
|
|
5001
|
+
const agentsMd = ctx.agentsMdFinal ?? ctx.agentsMdDraft ?? "";
|
|
5002
|
+
setPhase({
|
|
5003
|
+
kind: "done",
|
|
5004
|
+
projectName,
|
|
5005
|
+
writtenPath: ctx.writtenPath,
|
|
5006
|
+
checkScript: ctx.checkScriptFinal ?? null,
|
|
5007
|
+
driftWarnings: ctx.driftWarnings ?? [],
|
|
5008
|
+
lowConfidence: agentsMd.includes("LOW-CONFIDENCE:"),
|
|
5009
|
+
alreadyCurrent: ctx.alreadyCurrent
|
|
5010
|
+
});
|
|
5011
|
+
}
|
|
5012
|
+
});
|
|
5013
|
+
const hints = useMemo24(() => phase.kind === "running" ? HINTS_RUNNING17 : HINTS_DONE17, [phase.kind]);
|
|
5014
|
+
useViewHints(hints);
|
|
5015
|
+
return /* @__PURE__ */ jsx47(ViewShell, { title: TITLE21, children: renderBody17(phase) });
|
|
5016
|
+
}
|
|
5017
|
+
function renderBody17(phase) {
|
|
5018
|
+
switch (phase.kind) {
|
|
5019
|
+
case "running":
|
|
5020
|
+
return /* @__PURE__ */ jsx47(Spinner, { label: stepLabel8(phase.step) });
|
|
5021
|
+
case "no-projects":
|
|
5022
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "info", title: "No projects registered" });
|
|
5023
|
+
case "error":
|
|
5024
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
|
|
5025
|
+
case "done": {
|
|
5026
|
+
const fields = [["Project", phase.projectName]];
|
|
5027
|
+
if (phase.writtenPath) fields.push(["Project context file", phase.writtenPath]);
|
|
5028
|
+
if (phase.checkScript) fields.push(["Check script", phase.checkScript]);
|
|
5029
|
+
if (phase.driftWarnings && phase.driftWarnings.length > 0) {
|
|
5030
|
+
fields.push(["Warnings", phase.driftWarnings.join("; ")]);
|
|
5031
|
+
}
|
|
5032
|
+
if (phase.lowConfidence) {
|
|
5033
|
+
fields.push(["Review", "Low-confidence sections present \u2014 re-run interactively to tighten"]);
|
|
5034
|
+
}
|
|
5035
|
+
if (phase.alreadyCurrent) {
|
|
5036
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "info", title: "Already current", fields });
|
|
5037
|
+
}
|
|
5038
|
+
const nextSteps = phase.lowConfidence ? [{ action: "Open the project context file and replace LOW-CONFIDENCE lines with concrete facts." }] : void 0;
|
|
5039
|
+
return /* @__PURE__ */ jsx47(ResultCard, { kind: "success", title: "Repository onboarded", fields, nextSteps });
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
}
|
|
5043
|
+
function stepLabel8(step) {
|
|
5044
|
+
if (step === "select-project") return "Awaiting project selection\u2026";
|
|
5045
|
+
return "Inventorying repository and reviewing proposal\u2026";
|
|
5046
|
+
}
|
|
5047
|
+
|
|
4807
5048
|
// src/integration/ui/tui/views/browse/sprint-list-view.tsx
|
|
4808
|
-
import { useEffect as
|
|
4809
|
-
import { useInput as
|
|
5049
|
+
import { useEffect as useEffect21, useMemo as useMemo26, useState as useState21 } from "react";
|
|
5050
|
+
import { useInput as useInput13 } from "ink";
|
|
4810
5051
|
|
|
4811
5052
|
// src/integration/ui/tui/components/list-view.tsx
|
|
4812
|
-
import
|
|
4813
|
-
import { Box as Box25, Text as Text24, useInput as
|
|
4814
|
-
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";
|
|
4815
5056
|
var DEFAULT_PAGE_SIZE = 12;
|
|
4816
5057
|
function computeWidths(columns, rows, totalWidth) {
|
|
4817
5058
|
const widths = columns.map((col) => {
|
|
@@ -4840,11 +5081,17 @@ function ListView({
|
|
|
4840
5081
|
emptyLabel = "(empty)",
|
|
4841
5082
|
pageSize = DEFAULT_PAGE_SIZE,
|
|
4842
5083
|
initialCursor = 0,
|
|
4843
|
-
disabled = false
|
|
5084
|
+
disabled = false,
|
|
5085
|
+
onCursorChange
|
|
4844
5086
|
}) {
|
|
4845
|
-
const [cursor, setCursor] =
|
|
4846
|
-
|
|
4847
|
-
|
|
5087
|
+
const [cursor, setCursor] = useState20(() => Math.max(0, Math.min(initialCursor, rows.length - 1)));
|
|
5088
|
+
useEffect20(() => {
|
|
5089
|
+
if (!onCursorChange) return;
|
|
5090
|
+
const row = rows[cursor];
|
|
5091
|
+
if (row !== void 0) onCursorChange(row, cursor);
|
|
5092
|
+
}, [cursor, rows, onCursorChange]);
|
|
5093
|
+
const widths = useMemo25(() => computeWidths(columns, rows, 72), [columns, rows]);
|
|
5094
|
+
useInput12(
|
|
4848
5095
|
(_input, key) => {
|
|
4849
5096
|
if (rows.length === 0) return;
|
|
4850
5097
|
if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
|
|
@@ -4859,17 +5106,17 @@ function ListView({
|
|
|
4859
5106
|
{ isActive: !disabled }
|
|
4860
5107
|
);
|
|
4861
5108
|
if (rows.length === 0) {
|
|
4862
|
-
return /* @__PURE__ */
|
|
5109
|
+
return /* @__PURE__ */ jsx48(Box25, { children: /* @__PURE__ */ jsx48(Text24, { dimColor: true, children: emptyLabel }) });
|
|
4863
5110
|
}
|
|
4864
5111
|
const windowStart = Math.max(0, Math.min(cursor - Math.floor(pageSize / 2), rows.length - pageSize));
|
|
4865
5112
|
const windowEnd = Math.min(rows.length, windowStart + pageSize);
|
|
4866
5113
|
const visible = rows.slice(windowStart, windowEnd);
|
|
4867
5114
|
return /* @__PURE__ */ jsxs24(Box25, { flexDirection: "column", children: [
|
|
4868
5115
|
/* @__PURE__ */ jsxs24(Box25, { children: [
|
|
4869
|
-
/* @__PURE__ */
|
|
4870
|
-
columns.map((col, i) => /* @__PURE__ */ jsxs24(
|
|
4871
|
-
/* @__PURE__ */
|
|
4872
|
-
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
|
|
4873
5120
|
] }, col.header))
|
|
4874
5121
|
] }),
|
|
4875
5122
|
visible.map((row, i) => {
|
|
@@ -4877,18 +5124,18 @@ function ListView({
|
|
|
4877
5124
|
const selected = absoluteIdx === cursor;
|
|
4878
5125
|
const indicatorColor = selected ? inkColors.highlight : void 0;
|
|
4879
5126
|
return /* @__PURE__ */ jsxs24(Box25, { children: [
|
|
4880
|
-
/* @__PURE__ */
|
|
5127
|
+
/* @__PURE__ */ jsx48(Text24, { color: indicatorColor, bold: selected, children: selected ? glyphs.actionCursor : " " }),
|
|
4881
5128
|
columns.map((col, ci) => {
|
|
4882
5129
|
const text = pad(col.cell(row), widths[ci] ?? col.cell(row).length, col.align);
|
|
4883
5130
|
const cellColor = col.color?.(row) ?? (selected ? inkColors.highlight : void 0);
|
|
4884
|
-
return /* @__PURE__ */ jsxs24(
|
|
4885
|
-
/* @__PURE__ */
|
|
4886
|
-
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
|
|
4887
5134
|
] }, col.header);
|
|
4888
5135
|
})
|
|
4889
5136
|
] }, absoluteIdx);
|
|
4890
5137
|
}),
|
|
4891
|
-
rows.length > pageSize ? /* @__PURE__ */
|
|
5138
|
+
rows.length > pageSize ? /* @__PURE__ */ jsx48(Box25, { marginTop: spacing.section, children: /* @__PURE__ */ jsxs24(Text24, { dimColor: true, children: [
|
|
4892
5139
|
String(cursor + 1),
|
|
4893
5140
|
" / ",
|
|
4894
5141
|
String(rows.length),
|
|
@@ -4920,6 +5167,12 @@ function chipKindForTaskStatus(status) {
|
|
|
4920
5167
|
if (status === "in_progress") return "warning";
|
|
4921
5168
|
return "muted";
|
|
4922
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
|
+
}
|
|
4923
5176
|
function StatusChip({ label, kind = "info" }) {
|
|
4924
5177
|
return /* @__PURE__ */ jsxs25(Text25, { color: COLOR2[kind], bold: true, children: [
|
|
4925
5178
|
"[",
|
|
@@ -4929,7 +5182,7 @@ function StatusChip({ label, kind = "info" }) {
|
|
|
4929
5182
|
}
|
|
4930
5183
|
|
|
4931
5184
|
// src/integration/ui/tui/views/browse/sprint-list-view.tsx
|
|
4932
|
-
import { jsx as
|
|
5185
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
4933
5186
|
function statusChipText(status) {
|
|
4934
5187
|
return `[${status.toUpperCase()}]`;
|
|
4935
5188
|
}
|
|
@@ -4987,7 +5240,7 @@ var HINTS_READY2 = [
|
|
|
4987
5240
|
{ key: "f", action: "filter" },
|
|
4988
5241
|
{ key: "n", action: "new" },
|
|
4989
5242
|
{ key: "c", action: "set current" },
|
|
4990
|
-
{ key: "
|
|
5243
|
+
{ key: "r", action: "remove" }
|
|
4991
5244
|
];
|
|
4992
5245
|
var HINTS_EMPTY = [{ key: "n", action: "new" }];
|
|
4993
5246
|
var FILTER_CYCLE = ["all", "draft", "active", "closed"];
|
|
@@ -4997,10 +5250,10 @@ function nextFilter(current) {
|
|
|
4997
5250
|
}
|
|
4998
5251
|
function SprintListView() {
|
|
4999
5252
|
const router = useRouter();
|
|
5000
|
-
const [state, setState] =
|
|
5001
|
-
const [filter, setFilter] =
|
|
5253
|
+
const [state, setState] = useState21({ kind: "loading" });
|
|
5254
|
+
const [filter, setFilter] = useState21("all");
|
|
5002
5255
|
useViewHints(state.kind === "ready" ? HINTS_READY2 : HINTS_EMPTY);
|
|
5003
|
-
|
|
5256
|
+
useEffect21(() => {
|
|
5004
5257
|
const ctl = { cancelled: false };
|
|
5005
5258
|
void (async () => {
|
|
5006
5259
|
try {
|
|
@@ -5036,7 +5289,7 @@ function SprintListView() {
|
|
|
5036
5289
|
ctl.cancelled = true;
|
|
5037
5290
|
};
|
|
5038
5291
|
}, []);
|
|
5039
|
-
|
|
5292
|
+
useInput13((input) => {
|
|
5040
5293
|
if (state.kind === "loading") return;
|
|
5041
5294
|
if (input === "n") {
|
|
5042
5295
|
router.push({ id: "sprint-create" });
|
|
@@ -5051,17 +5304,17 @@ function SprintListView() {
|
|
|
5051
5304
|
router.push({ id: "sprint-set-current" });
|
|
5052
5305
|
return;
|
|
5053
5306
|
}
|
|
5054
|
-
if (input === "
|
|
5307
|
+
if (input === "r") {
|
|
5055
5308
|
router.push({ id: "sprint-delete" });
|
|
5056
5309
|
}
|
|
5057
5310
|
});
|
|
5058
5311
|
const title = filter === "all" ? TITLE_BASE : `${TITLE_BASE} \xB7 filter: ${filter}`;
|
|
5059
|
-
const filtered =
|
|
5312
|
+
const filtered = useMemo26(() => {
|
|
5060
5313
|
if (state.kind !== "ready") return [];
|
|
5061
5314
|
if (filter === "all") return state.sprints;
|
|
5062
5315
|
return state.sprints.filter((s) => s.status === filter);
|
|
5063
5316
|
}, [state, filter]);
|
|
5064
|
-
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(
|
|
5065
5318
|
ListView,
|
|
5066
5319
|
{
|
|
5067
5320
|
rows: filtered,
|
|
@@ -5075,19 +5328,19 @@ function SprintListView() {
|
|
|
5075
5328
|
}
|
|
5076
5329
|
|
|
5077
5330
|
// src/integration/ui/tui/views/browse/sprint-show-view.tsx
|
|
5078
|
-
import { useEffect as
|
|
5079
|
-
import { Box as Box26, Text as Text26, useInput as
|
|
5080
|
-
import { jsx as
|
|
5081
|
-
var
|
|
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";
|
|
5334
|
+
var TITLE22 = "Sprint Details";
|
|
5082
5335
|
var HINTS = [
|
|
5083
5336
|
{ key: "\u2191/\u2193", action: "move" },
|
|
5084
5337
|
{ key: "Enter", action: "open" }
|
|
5085
5338
|
];
|
|
5086
5339
|
function SprintShowView({ sprintId }) {
|
|
5087
5340
|
const router = useRouter();
|
|
5088
|
-
const [state, setState] =
|
|
5341
|
+
const [state, setState] = useState22({ kind: "loading" });
|
|
5089
5342
|
useViewHints(HINTS);
|
|
5090
|
-
|
|
5343
|
+
useEffect22(() => {
|
|
5091
5344
|
const ctl = { cancelled: false };
|
|
5092
5345
|
void (async () => {
|
|
5093
5346
|
try {
|
|
@@ -5103,13 +5356,13 @@ function SprintShowView({ sprintId }) {
|
|
|
5103
5356
|
ctl.cancelled = true;
|
|
5104
5357
|
};
|
|
5105
5358
|
}, [sprintId]);
|
|
5106
|
-
const rows =
|
|
5359
|
+
const rows = useMemo27(() => {
|
|
5107
5360
|
if (state.kind !== "ready") return [];
|
|
5108
5361
|
return buildRows2(state.sprint, state.tasks);
|
|
5109
5362
|
}, [state]);
|
|
5110
|
-
const sections =
|
|
5111
|
-
const [cursor, setCursor] =
|
|
5112
|
-
|
|
5363
|
+
const sections = useMemo27(() => rows.filter((r) => r.separator !== true), [rows]);
|
|
5364
|
+
const [cursor, setCursor] = useState22(0);
|
|
5365
|
+
useInput14(
|
|
5113
5366
|
(_input, key) => {
|
|
5114
5367
|
if (sections.length === 0) return;
|
|
5115
5368
|
if (key.upArrow) setCursor((c) => Math.max(0, c - 1));
|
|
@@ -5121,11 +5374,11 @@ function SprintShowView({ sprintId }) {
|
|
|
5121
5374
|
},
|
|
5122
5375
|
{ isActive: state.kind === "ready" && sections.length > 0 }
|
|
5123
5376
|
);
|
|
5124
|
-
return /* @__PURE__ */
|
|
5377
|
+
return /* @__PURE__ */ jsx50(ViewShell, { title: TITLE22, children: renderBody18(state, rows, sections, cursor) });
|
|
5125
5378
|
}
|
|
5126
|
-
function
|
|
5127
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5128
|
-
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] });
|
|
5129
5382
|
const { sprint, tasks, project } = state;
|
|
5130
5383
|
const projectLabel = project ? `${project.displayName} (${project.name})` : sprint.projectId;
|
|
5131
5384
|
const approved = sprint.tickets.filter((t) => t.requirementStatus === "approved").length;
|
|
@@ -5133,11 +5386,11 @@ function renderBody21(state, rows, sections, cursor) {
|
|
|
5133
5386
|
const activeSectionId = sections[cursor]?.destination.id;
|
|
5134
5387
|
return /* @__PURE__ */ jsxs26(Box26, { flexDirection: "column", children: [
|
|
5135
5388
|
/* @__PURE__ */ jsxs26(Box26, { children: [
|
|
5136
|
-
/* @__PURE__ */
|
|
5137
|
-
/* @__PURE__ */
|
|
5138
|
-
/* @__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) })
|
|
5139
5392
|
] }),
|
|
5140
|
-
/* @__PURE__ */
|
|
5393
|
+
/* @__PURE__ */ jsx50(Box26, { marginTop: spacing.section, children: /* @__PURE__ */ jsx50(
|
|
5141
5394
|
FieldList,
|
|
5142
5395
|
{
|
|
5143
5396
|
fields: [
|
|
@@ -5153,22 +5406,22 @@ function renderBody21(state, rows, sections, cursor) {
|
|
|
5153
5406
|
}
|
|
5154
5407
|
) }),
|
|
5155
5408
|
/* @__PURE__ */ jsxs26(Box26, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5156
|
-
/* @__PURE__ */
|
|
5157
|
-
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))
|
|
5158
5411
|
] })
|
|
5159
5412
|
] });
|
|
5160
5413
|
}
|
|
5161
5414
|
function RowRenderer({ row, isActive }) {
|
|
5162
5415
|
if (row.separator === true) {
|
|
5163
|
-
return /* @__PURE__ */
|
|
5416
|
+
return /* @__PURE__ */ jsx50(Box26, { paddingLeft: spacing.indent, children: /* @__PURE__ */ jsx50(Text26, { color: inkColors.muted, dimColor: true, children: glyphs.sectionRule.repeat(2) }) });
|
|
5164
5417
|
}
|
|
5165
5418
|
return /* @__PURE__ */ jsxs26(Box26, { paddingLeft: spacing.indent, children: [
|
|
5166
|
-
/* @__PURE__ */
|
|
5419
|
+
/* @__PURE__ */ jsx50(Text26, { color: isActive ? inkColors.highlight : void 0, bold: isActive, children: isActive ? glyphs.actionCursor : " " }),
|
|
5167
5420
|
/* @__PURE__ */ jsxs26(Text26, { color: isActive ? inkColors.highlight : void 0, bold: isActive, children: [
|
|
5168
5421
|
" ",
|
|
5169
5422
|
row.label
|
|
5170
5423
|
] }),
|
|
5171
|
-
/* @__PURE__ */
|
|
5424
|
+
/* @__PURE__ */ jsx50(Text26, { dimColor: true, children: ` ${glyphs.emDash} ${row.description}` })
|
|
5172
5425
|
] });
|
|
5173
5426
|
}
|
|
5174
5427
|
function buildRows2(sprint, tasks) {
|
|
@@ -5229,9 +5482,9 @@ function buildRows2(sprint, tasks) {
|
|
|
5229
5482
|
}
|
|
5230
5483
|
|
|
5231
5484
|
// src/integration/ui/tui/views/browse/ticket-list-view.tsx
|
|
5232
|
-
import { useCallback as useCallback9, useEffect as
|
|
5233
|
-
import { useInput as
|
|
5234
|
-
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";
|
|
5235
5488
|
function requirementColor(status) {
|
|
5236
5489
|
return status === "approved" ? inkColors.success : inkColors.warning;
|
|
5237
5490
|
}
|
|
@@ -5255,7 +5508,7 @@ function buildColumns2(repoNamesById) {
|
|
|
5255
5508
|
}
|
|
5256
5509
|
];
|
|
5257
5510
|
}
|
|
5258
|
-
var
|
|
5511
|
+
var TITLE23 = "Tickets";
|
|
5259
5512
|
var HINTS_READY3 = [
|
|
5260
5513
|
{ key: "\u2191/\u2193", action: "navigate" },
|
|
5261
5514
|
{ key: "Enter", action: "open" },
|
|
@@ -5266,7 +5519,7 @@ var HINTS_READY3 = [
|
|
|
5266
5519
|
var HINTS_EMPTY2 = [{ key: "a", action: "add" }];
|
|
5267
5520
|
function TicketListView({ sprintId }) {
|
|
5268
5521
|
const router = useRouter();
|
|
5269
|
-
const [state, setState] =
|
|
5522
|
+
const [state, setState] = useState23({ kind: "loading" });
|
|
5270
5523
|
const load = useCallback9(async () => {
|
|
5271
5524
|
try {
|
|
5272
5525
|
const id = await resolveSprintId(sprintId);
|
|
@@ -5284,7 +5537,7 @@ function TicketListView({ sprintId }) {
|
|
|
5284
5537
|
setState({ kind: "error", message: err instanceof Error ? err.message : String(err) });
|
|
5285
5538
|
}
|
|
5286
5539
|
}, [sprintId]);
|
|
5287
|
-
|
|
5540
|
+
useEffect23(() => {
|
|
5288
5541
|
const ctl = { cancelled: false };
|
|
5289
5542
|
void (async () => {
|
|
5290
5543
|
if (!ctl.cancelled) await load();
|
|
@@ -5293,7 +5546,7 @@ function TicketListView({ sprintId }) {
|
|
|
5293
5546
|
ctl.cancelled = true;
|
|
5294
5547
|
};
|
|
5295
5548
|
}, [load]);
|
|
5296
|
-
|
|
5549
|
+
useInput15((input) => {
|
|
5297
5550
|
if (state.kind === "loading") return;
|
|
5298
5551
|
if (input === "a") {
|
|
5299
5552
|
router.push({ id: "ticket-add" });
|
|
@@ -5309,7 +5562,7 @@ function TicketListView({ sprintId }) {
|
|
|
5309
5562
|
}
|
|
5310
5563
|
});
|
|
5311
5564
|
useViewHints(state.kind === "ready" ? HINTS_READY3 : HINTS_EMPTY2);
|
|
5312
|
-
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(
|
|
5313
5566
|
ListView,
|
|
5314
5567
|
{
|
|
5315
5568
|
rows: state.tickets,
|
|
@@ -5322,16 +5575,16 @@ function TicketListView({ sprintId }) {
|
|
|
5322
5575
|
}
|
|
5323
5576
|
|
|
5324
5577
|
// src/integration/ui/tui/views/browse/ticket-show-view.tsx
|
|
5325
|
-
import { useEffect as
|
|
5326
|
-
import { Box as Box27, Text as Text27, useInput as
|
|
5327
|
-
import { jsx as
|
|
5328
|
-
var
|
|
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";
|
|
5581
|
+
var TITLE24 = "Ticket Details";
|
|
5329
5582
|
var HINTS_READ_ONLY = [];
|
|
5330
5583
|
var HINTS_EDITABLE = [{ key: "e", action: "edit" }];
|
|
5331
5584
|
function TicketShowView({ ticketId }) {
|
|
5332
5585
|
const router = useRouter();
|
|
5333
|
-
const [state, setState] =
|
|
5334
|
-
|
|
5586
|
+
const [state, setState] = useState24({ kind: "loading" });
|
|
5587
|
+
useEffect24(() => {
|
|
5335
5588
|
const ctl = { cancelled: false };
|
|
5336
5589
|
void (async () => {
|
|
5337
5590
|
if (!ticketId) {
|
|
@@ -5358,23 +5611,23 @@ function TicketShowView({ ticketId }) {
|
|
|
5358
5611
|
ctl.cancelled = true;
|
|
5359
5612
|
};
|
|
5360
5613
|
}, [ticketId]);
|
|
5361
|
-
|
|
5614
|
+
useInput16((input) => {
|
|
5362
5615
|
if (input === "e" && state.kind === "ready" && state.editable && ticketId) {
|
|
5363
5616
|
router.push({ id: "ticket-edit", props: { ticketId } });
|
|
5364
5617
|
}
|
|
5365
5618
|
});
|
|
5366
5619
|
useViewHints(state.kind === "ready" && state.editable ? HINTS_EDITABLE : HINTS_READ_ONLY);
|
|
5367
|
-
return /* @__PURE__ */
|
|
5620
|
+
return /* @__PURE__ */ jsx52(ViewShell, { title: TITLE24, children: renderBody19(state) });
|
|
5368
5621
|
}
|
|
5369
|
-
function
|
|
5370
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5371
|
-
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] });
|
|
5372
5625
|
const { ticket } = state;
|
|
5373
5626
|
return /* @__PURE__ */ jsxs27(Box27, { flexDirection: "column", children: [
|
|
5374
5627
|
/* @__PURE__ */ jsxs27(Box27, { children: [
|
|
5375
|
-
/* @__PURE__ */
|
|
5376
|
-
/* @__PURE__ */
|
|
5377
|
-
/* @__PURE__ */
|
|
5628
|
+
/* @__PURE__ */ jsx52(Text27, { bold: true, children: ticket.title }),
|
|
5629
|
+
/* @__PURE__ */ jsx52(Text27, { children: " " }),
|
|
5630
|
+
/* @__PURE__ */ jsx52(
|
|
5378
5631
|
StatusChip,
|
|
5379
5632
|
{
|
|
5380
5633
|
label: ticket.requirementStatus,
|
|
@@ -5382,7 +5635,7 @@ function renderBody22(state) {
|
|
|
5382
5635
|
}
|
|
5383
5636
|
)
|
|
5384
5637
|
] }),
|
|
5385
|
-
/* @__PURE__ */
|
|
5638
|
+
/* @__PURE__ */ jsx52(Box27, { marginTop: spacing.section, children: /* @__PURE__ */ jsx52(
|
|
5386
5639
|
FieldList,
|
|
5387
5640
|
{
|
|
5388
5641
|
fields: [
|
|
@@ -5393,20 +5646,20 @@ function renderBody22(state) {
|
|
|
5393
5646
|
}
|
|
5394
5647
|
) }),
|
|
5395
5648
|
ticket.description ? /* @__PURE__ */ jsxs27(Box27, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5396
|
-
/* @__PURE__ */
|
|
5397
|
-
/* @__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 }) })
|
|
5398
5651
|
] }) : null,
|
|
5399
5652
|
ticket.requirements ? /* @__PURE__ */ jsxs27(Box27, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5400
|
-
/* @__PURE__ */
|
|
5401
|
-
/* @__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 }) })
|
|
5402
5655
|
] }) : null
|
|
5403
5656
|
] });
|
|
5404
5657
|
}
|
|
5405
5658
|
|
|
5406
5659
|
// src/integration/ui/tui/views/browse/task-list-view.tsx
|
|
5407
|
-
import { useEffect as
|
|
5408
|
-
import { useInput as
|
|
5409
|
-
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";
|
|
5410
5663
|
var FILTER_CYCLE2 = ["all", "todo", "active", "done"];
|
|
5411
5664
|
function nextFilter2(f) {
|
|
5412
5665
|
const i = FILTER_CYCLE2.indexOf(f);
|
|
@@ -5478,10 +5731,10 @@ var HINTS_READY4 = [
|
|
|
5478
5731
|
var HINTS_EMPTY3 = [{ key: "a", action: "add" }];
|
|
5479
5732
|
function TaskListView({ sprintId }) {
|
|
5480
5733
|
const router = useRouter();
|
|
5481
|
-
const [state, setState] =
|
|
5482
|
-
const [filter, setFilter] =
|
|
5734
|
+
const [state, setState] = useState25({ kind: "loading" });
|
|
5735
|
+
const [filter, setFilter] = useState25("all");
|
|
5483
5736
|
useViewHints(state.kind === "ready" ? HINTS_READY4 : HINTS_EMPTY3);
|
|
5484
|
-
|
|
5737
|
+
useEffect25(() => {
|
|
5485
5738
|
const ctl = { cancelled: false };
|
|
5486
5739
|
void (async () => {
|
|
5487
5740
|
try {
|
|
@@ -5510,7 +5763,7 @@ function TaskListView({ sprintId }) {
|
|
|
5510
5763
|
ctl.cancelled = true;
|
|
5511
5764
|
};
|
|
5512
5765
|
}, [sprintId]);
|
|
5513
|
-
|
|
5766
|
+
useInput17((input) => {
|
|
5514
5767
|
if (state.kind === "loading") return;
|
|
5515
5768
|
if (input === "a") {
|
|
5516
5769
|
router.push({ id: "task-add" });
|
|
@@ -5529,13 +5782,13 @@ function TaskListView({ sprintId }) {
|
|
|
5529
5782
|
router.push({ id: "task-remove" });
|
|
5530
5783
|
}
|
|
5531
5784
|
});
|
|
5532
|
-
const filtered =
|
|
5785
|
+
const filtered = useMemo28(() => {
|
|
5533
5786
|
if (state.kind !== "ready") return [];
|
|
5534
5787
|
if (filter === "all") return state.tasks;
|
|
5535
5788
|
return state.tasks.filter((t) => matches(t, filter));
|
|
5536
5789
|
}, [state, filter]);
|
|
5537
5790
|
const title = filter === "all" ? TITLE_BASE2 : `${TITLE_BASE2} \xB7 filter: ${filter}`;
|
|
5538
|
-
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(
|
|
5539
5792
|
ListView,
|
|
5540
5793
|
{
|
|
5541
5794
|
rows: filtered,
|
|
@@ -5548,10 +5801,10 @@ function TaskListView({ sprintId }) {
|
|
|
5548
5801
|
}
|
|
5549
5802
|
|
|
5550
5803
|
// src/integration/ui/tui/views/browse/task-show-view.tsx
|
|
5551
|
-
import { useEffect as
|
|
5552
|
-
import { Box as Box28, Text as Text28, useInput as
|
|
5553
|
-
import { jsx as
|
|
5554
|
-
var
|
|
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";
|
|
5807
|
+
var TITLE25 = "Task Details";
|
|
5555
5808
|
var HINTS_READY5 = [
|
|
5556
5809
|
{ key: "t", action: "status" },
|
|
5557
5810
|
{ key: "r", action: "remove" }
|
|
@@ -5559,9 +5812,9 @@ var HINTS_READY5 = [
|
|
|
5559
5812
|
var HINTS_EMPTY4 = [];
|
|
5560
5813
|
function TaskShowView({ taskId }) {
|
|
5561
5814
|
const router = useRouter();
|
|
5562
|
-
const [state, setState] =
|
|
5815
|
+
const [state, setState] = useState26({ kind: "loading" });
|
|
5563
5816
|
useViewHints(state.kind === "ready" ? HINTS_READY5 : HINTS_EMPTY4);
|
|
5564
|
-
|
|
5817
|
+
useInput18((input) => {
|
|
5565
5818
|
if (state.kind !== "ready") return;
|
|
5566
5819
|
if (input === "t") {
|
|
5567
5820
|
router.push({ id: "task-status" });
|
|
@@ -5571,7 +5824,7 @@ function TaskShowView({ taskId }) {
|
|
|
5571
5824
|
router.push({ id: "task-remove" });
|
|
5572
5825
|
}
|
|
5573
5826
|
});
|
|
5574
|
-
|
|
5827
|
+
useEffect26(() => {
|
|
5575
5828
|
const ctl = { cancelled: false };
|
|
5576
5829
|
void (async () => {
|
|
5577
5830
|
if (!taskId) {
|
|
@@ -5589,19 +5842,19 @@ function TaskShowView({ taskId }) {
|
|
|
5589
5842
|
ctl.cancelled = true;
|
|
5590
5843
|
};
|
|
5591
5844
|
}, [taskId]);
|
|
5592
|
-
return /* @__PURE__ */
|
|
5845
|
+
return /* @__PURE__ */ jsx54(ViewShell, { title: TITLE25, children: renderBody20(state) });
|
|
5593
5846
|
}
|
|
5594
|
-
function
|
|
5595
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5596
|
-
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] });
|
|
5597
5850
|
const { task } = state;
|
|
5598
5851
|
return /* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", children: [
|
|
5599
5852
|
/* @__PURE__ */ jsxs28(Box28, { children: [
|
|
5600
|
-
/* @__PURE__ */
|
|
5601
|
-
/* @__PURE__ */
|
|
5602
|
-
/* @__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) })
|
|
5603
5856
|
] }),
|
|
5604
|
-
/* @__PURE__ */
|
|
5857
|
+
/* @__PURE__ */ jsx54(Box28, { marginTop: spacing.section, children: /* @__PURE__ */ jsx54(
|
|
5605
5858
|
FieldList,
|
|
5606
5859
|
{
|
|
5607
5860
|
fields: [
|
|
@@ -5616,54 +5869,59 @@ function renderBody23(state) {
|
|
|
5616
5869
|
}
|
|
5617
5870
|
) }),
|
|
5618
5871
|
task.description ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5619
|
-
/* @__PURE__ */
|
|
5620
|
-
/* @__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 }) })
|
|
5621
5874
|
] }) : null,
|
|
5622
5875
|
task.steps.length > 0 ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5623
|
-
/* @__PURE__ */
|
|
5876
|
+
/* @__PURE__ */ jsx54(Text28, { color: inkColors.muted, bold: true, children: "Steps" }),
|
|
5624
5877
|
task.steps.map((step, i) => /* @__PURE__ */ jsxs28(Box28, { paddingLeft: spacing.indent, children: [
|
|
5625
5878
|
/* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
|
|
5626
5879
|
String(i + 1).padStart(2, " "),
|
|
5627
5880
|
". "
|
|
5628
5881
|
] }),
|
|
5629
|
-
/* @__PURE__ */
|
|
5882
|
+
/* @__PURE__ */ jsx54(Text28, { children: step })
|
|
5630
5883
|
] }, i))
|
|
5631
5884
|
] }) : null,
|
|
5632
5885
|
task.verificationCriteria.length > 0 ? /* @__PURE__ */ jsxs28(Box28, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5633
|
-
/* @__PURE__ */
|
|
5886
|
+
/* @__PURE__ */ jsx54(Text28, { color: inkColors.muted, bold: true, children: "Verification" }),
|
|
5634
5887
|
task.verificationCriteria.map((v, i) => /* @__PURE__ */ jsxs28(Box28, { paddingLeft: spacing.indent, children: [
|
|
5635
5888
|
/* @__PURE__ */ jsxs28(Text28, { dimColor: true, children: [
|
|
5636
5889
|
glyphs.bulletListItem,
|
|
5637
5890
|
" "
|
|
5638
5891
|
] }),
|
|
5639
|
-
/* @__PURE__ */
|
|
5892
|
+
/* @__PURE__ */ jsx54(Text28, { children: v })
|
|
5640
5893
|
] }, i))
|
|
5641
5894
|
] }) : null
|
|
5642
5895
|
] });
|
|
5643
5896
|
}
|
|
5644
5897
|
|
|
5645
5898
|
// src/integration/ui/tui/views/browse/project-list-view.tsx
|
|
5646
|
-
import { useEffect as
|
|
5647
|
-
import { useInput as
|
|
5648
|
-
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";
|
|
5649
5902
|
var COLUMNS = [
|
|
5650
5903
|
{ header: "Name", cell: (p) => p.name, width: 16 },
|
|
5651
5904
|
{ header: "Display", cell: (p) => p.displayName, flex: true },
|
|
5652
5905
|
{ header: "Repos", cell: (p) => String(p.repositories.length), align: "right", width: 6 }
|
|
5653
5906
|
];
|
|
5654
|
-
var
|
|
5907
|
+
var TITLE26 = "Projects";
|
|
5655
5908
|
var HINTS_READY6 = [
|
|
5656
5909
|
{ key: "\u2191/\u2193", action: "navigate" },
|
|
5657
5910
|
{ key: "Enter", action: "open" },
|
|
5658
5911
|
{ key: "a", action: "add" },
|
|
5659
5912
|
{ key: "e", action: "edit" },
|
|
5913
|
+
{ key: "o", action: "onboard" },
|
|
5660
5914
|
{ key: "r", action: "remove" }
|
|
5661
5915
|
];
|
|
5662
5916
|
var HINTS_EMPTY5 = [{ key: "a", action: "add" }];
|
|
5663
5917
|
function ProjectListView() {
|
|
5664
5918
|
const router = useRouter();
|
|
5665
|
-
const [state, setState] =
|
|
5666
|
-
|
|
5919
|
+
const [state, setState] = useState27({ kind: "loading" });
|
|
5920
|
+
const highlightedRef = useRef3(null);
|
|
5921
|
+
const handleCursorChange = useCallback10((row) => {
|
|
5922
|
+
highlightedRef.current = row;
|
|
5923
|
+
}, []);
|
|
5924
|
+
useEffect27(() => {
|
|
5667
5925
|
const ctl = { cancelled: false };
|
|
5668
5926
|
void (async () => {
|
|
5669
5927
|
try {
|
|
@@ -5680,7 +5938,7 @@ function ProjectListView() {
|
|
|
5680
5938
|
ctl.cancelled = true;
|
|
5681
5939
|
};
|
|
5682
5940
|
}, []);
|
|
5683
|
-
|
|
5941
|
+
useInput19((input) => {
|
|
5684
5942
|
if (state.kind === "loading") return;
|
|
5685
5943
|
if (input === "a") {
|
|
5686
5944
|
router.push({ id: "project-add" });
|
|
@@ -5691,16 +5949,24 @@ function ProjectListView() {
|
|
|
5691
5949
|
router.push({ id: "project-edit" });
|
|
5692
5950
|
return;
|
|
5693
5951
|
}
|
|
5952
|
+
if (input === "o") {
|
|
5953
|
+
const target = highlightedRef.current ?? state.projects[0];
|
|
5954
|
+
if (target) {
|
|
5955
|
+
router.push({ id: "project-onboard", props: { projectName: target.name } });
|
|
5956
|
+
}
|
|
5957
|
+
return;
|
|
5958
|
+
}
|
|
5694
5959
|
if (input === "r") {
|
|
5695
5960
|
router.push({ id: "project-remove" });
|
|
5696
5961
|
}
|
|
5697
5962
|
});
|
|
5698
5963
|
useViewHints(state.kind === "ready" ? HINTS_READY6 : HINTS_EMPTY5);
|
|
5699
|
-
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(
|
|
5700
5965
|
ListView,
|
|
5701
5966
|
{
|
|
5702
5967
|
rows: state.projects,
|
|
5703
5968
|
columns: COLUMNS,
|
|
5969
|
+
onCursorChange: handleCursorChange,
|
|
5704
5970
|
onSelect: (p) => {
|
|
5705
5971
|
router.push({ id: "project-show", props: { projectName: p.name } });
|
|
5706
5972
|
}
|
|
@@ -5709,21 +5975,22 @@ function ProjectListView() {
|
|
|
5709
5975
|
}
|
|
5710
5976
|
|
|
5711
5977
|
// src/integration/ui/tui/views/browse/project-show-view.tsx
|
|
5712
|
-
import { useEffect as
|
|
5713
|
-
import { Box as Box29, Text as Text29, useInput as
|
|
5714
|
-
import { jsx as
|
|
5715
|
-
var
|
|
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";
|
|
5981
|
+
var TITLE27 = "Project Details";
|
|
5716
5982
|
var HINTS_READY7 = [
|
|
5717
5983
|
{ key: "e", action: "edit" },
|
|
5718
5984
|
{ key: "a", action: "add repo" },
|
|
5985
|
+
{ key: "o", action: "onboard" },
|
|
5719
5986
|
{ key: "r", action: "remove repo" }
|
|
5720
5987
|
];
|
|
5721
5988
|
var HINTS_EMPTY6 = [];
|
|
5722
5989
|
function ProjectShowView({ projectName }) {
|
|
5723
5990
|
const router = useRouter();
|
|
5724
|
-
const [state, setState] =
|
|
5991
|
+
const [state, setState] = useState28({ kind: "loading" });
|
|
5725
5992
|
useViewHints(state.kind === "ready" ? HINTS_READY7 : HINTS_EMPTY6);
|
|
5726
|
-
|
|
5993
|
+
useInput20((input) => {
|
|
5727
5994
|
if (state.kind !== "ready") return;
|
|
5728
5995
|
if (input === "e") {
|
|
5729
5996
|
router.push({ id: "project-edit" });
|
|
@@ -5733,11 +6000,15 @@ function ProjectShowView({ projectName }) {
|
|
|
5733
6000
|
router.push({ id: "project-repo-add" });
|
|
5734
6001
|
return;
|
|
5735
6002
|
}
|
|
6003
|
+
if (input === "o") {
|
|
6004
|
+
router.push({ id: "project-onboard", props: { projectName: state.project.name } });
|
|
6005
|
+
return;
|
|
6006
|
+
}
|
|
5736
6007
|
if (input === "r") {
|
|
5737
6008
|
router.push({ id: "project-repo-remove" });
|
|
5738
6009
|
}
|
|
5739
6010
|
});
|
|
5740
|
-
|
|
6011
|
+
useEffect28(() => {
|
|
5741
6012
|
const ctl = { cancelled: false };
|
|
5742
6013
|
void (async () => {
|
|
5743
6014
|
if (!projectName) {
|
|
@@ -5755,18 +6026,18 @@ function ProjectShowView({ projectName }) {
|
|
|
5755
6026
|
ctl.cancelled = true;
|
|
5756
6027
|
};
|
|
5757
6028
|
}, [projectName]);
|
|
5758
|
-
return /* @__PURE__ */
|
|
6029
|
+
return /* @__PURE__ */ jsx56(ViewShell, { title: TITLE27, children: renderBody21(state) });
|
|
5759
6030
|
}
|
|
5760
|
-
function
|
|
5761
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
5762
|
-
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] });
|
|
5763
6034
|
const { project } = state;
|
|
5764
6035
|
return /* @__PURE__ */ jsxs29(Box29, { flexDirection: "column", children: [
|
|
5765
6036
|
/* @__PURE__ */ jsxs29(Box29, { children: [
|
|
5766
|
-
/* @__PURE__ */
|
|
5767
|
-
/* @__PURE__ */
|
|
6037
|
+
/* @__PURE__ */ jsx56(Text29, { bold: true, children: project.displayName }),
|
|
6038
|
+
/* @__PURE__ */ jsx56(Text29, { dimColor: true, children: ` (${project.name})` })
|
|
5768
6039
|
] }),
|
|
5769
|
-
/* @__PURE__ */
|
|
6040
|
+
/* @__PURE__ */ jsx56(Box29, { marginTop: spacing.section, children: /* @__PURE__ */ jsx56(
|
|
5770
6041
|
FieldList,
|
|
5771
6042
|
{
|
|
5772
6043
|
fields: [
|
|
@@ -5778,28 +6049,29 @@ function renderBody24(state) {
|
|
|
5778
6049
|
}
|
|
5779
6050
|
) }),
|
|
5780
6051
|
/* @__PURE__ */ jsxs29(Box29, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
5781
|
-
/* @__PURE__ */
|
|
6052
|
+
/* @__PURE__ */ jsx56(Text29, { color: inkColors.muted, bold: true, children: "Repositories" }),
|
|
5782
6053
|
project.repositories.map((r) => /* @__PURE__ */ jsxs29(Box29, { paddingLeft: spacing.indent, children: [
|
|
5783
6054
|
/* @__PURE__ */ jsxs29(Text29, { dimColor: true, children: [
|
|
5784
6055
|
glyphs.bulletListItem,
|
|
5785
6056
|
" "
|
|
5786
6057
|
] }),
|
|
5787
|
-
/* @__PURE__ */
|
|
5788
|
-
/* @__PURE__ */
|
|
5789
|
-
/* @__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})` })
|
|
5790
6061
|
] }, r.id))
|
|
5791
6062
|
] })
|
|
5792
6063
|
] });
|
|
5793
6064
|
}
|
|
5794
6065
|
|
|
5795
6066
|
// src/integration/ui/tui/views/browse/doctor-view.tsx
|
|
5796
|
-
import { useEffect as
|
|
6067
|
+
import { useEffect as useEffect29, useState as useState29 } from "react";
|
|
5797
6068
|
import { Box as Box30, Text as Text30 } from "ink";
|
|
5798
|
-
import { jsx as
|
|
5799
|
-
var
|
|
6069
|
+
import { jsx as jsx57, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6070
|
+
var TITLE28 = "Doctor";
|
|
5800
6071
|
var HINTS2 = [];
|
|
6072
|
+
var MIN_LABEL_WIDTH = 20;
|
|
5801
6073
|
async function runChecks() {
|
|
5802
|
-
const
|
|
6074
|
+
const environment = [
|
|
5803
6075
|
["Node.js version", checkNodeVersion()],
|
|
5804
6076
|
["git installed", checkGitInstalled()],
|
|
5805
6077
|
["git identity", checkGitIdentity()],
|
|
@@ -5811,17 +6083,27 @@ async function runChecks() {
|
|
|
5811
6083
|
["Config schema", await checkConfigSchemaValidation()],
|
|
5812
6084
|
["Current sprint", await checkCurrentSprint()]
|
|
5813
6085
|
];
|
|
5814
|
-
|
|
5815
|
-
|
|
6086
|
+
const envRows = await Promise.all(
|
|
6087
|
+
environment.map(async ([name, r]) => ({
|
|
5816
6088
|
name,
|
|
5817
6089
|
result: r instanceof Promise ? await r : r
|
|
5818
6090
|
}))
|
|
5819
6091
|
);
|
|
6092
|
+
const onboardingResults = await checkRepoOnboarding();
|
|
6093
|
+
const onboardingRows = onboardingResults.map((result) => ({
|
|
6094
|
+
name: result.name.replace(/^Onboarding\s+—\s+/u, ""),
|
|
6095
|
+
result
|
|
6096
|
+
}));
|
|
6097
|
+
const sections = [{ title: "Environment", rows: envRows }];
|
|
6098
|
+
if (onboardingRows.length > 0) {
|
|
6099
|
+
sections.push({ title: "Onboarding", rows: onboardingRows });
|
|
6100
|
+
}
|
|
6101
|
+
return sections;
|
|
5820
6102
|
}
|
|
5821
6103
|
function glyph(status) {
|
|
5822
6104
|
if (status === "pass") return glyphs.check;
|
|
5823
|
-
if (status === "warn") return
|
|
5824
|
-
if (status === "skip") return glyphs.
|
|
6105
|
+
if (status === "warn") return glyphs.warningGlyph;
|
|
6106
|
+
if (status === "skip") return glyphs.phaseDisabled;
|
|
5825
6107
|
return glyphs.cross;
|
|
5826
6108
|
}
|
|
5827
6109
|
function color(status) {
|
|
@@ -5830,38 +6112,64 @@ function color(status) {
|
|
|
5830
6112
|
if (status === "skip") return inkColors.muted;
|
|
5831
6113
|
return inkColors.error;
|
|
5832
6114
|
}
|
|
6115
|
+
function labelWidth(rows) {
|
|
6116
|
+
return Math.max(MIN_LABEL_WIDTH, ...rows.map((r) => r.name.length));
|
|
6117
|
+
}
|
|
6118
|
+
function Row({ row, width }) {
|
|
6119
|
+
const dim = row.result.status === "skip";
|
|
6120
|
+
return /* @__PURE__ */ jsxs30(Box30, { children: [
|
|
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() })
|
|
6125
|
+
] });
|
|
6126
|
+
}
|
|
5833
6127
|
function DoctorView() {
|
|
5834
|
-
const [state, setState] =
|
|
6128
|
+
const [state, setState] = useState29({ kind: "running" });
|
|
5835
6129
|
useViewHints(HINTS2);
|
|
5836
|
-
|
|
6130
|
+
useEffect29(() => {
|
|
5837
6131
|
const ctl = { cancelled: false };
|
|
5838
6132
|
void (async () => {
|
|
5839
|
-
const
|
|
5840
|
-
if (!ctl.cancelled) setState({ kind: "done",
|
|
6133
|
+
const sections = await runChecks();
|
|
6134
|
+
if (!ctl.cancelled) setState({ kind: "done", sections });
|
|
5841
6135
|
})();
|
|
5842
6136
|
return () => {
|
|
5843
6137
|
ctl.cancelled = true;
|
|
5844
6138
|
};
|
|
5845
6139
|
}, []);
|
|
5846
|
-
|
|
5847
|
-
/* @__PURE__ */
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
6140
|
+
if (state.kind === "running") {
|
|
6141
|
+
return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE28, children: /* @__PURE__ */ jsx57(Spinner, { label: "Running environment checks\u2026" }) });
|
|
6142
|
+
}
|
|
6143
|
+
return /* @__PURE__ */ jsx57(ViewShell, { title: TITLE28, children: state.sections.map((section, i) => {
|
|
6144
|
+
const width = labelWidth(section.rows);
|
|
6145
|
+
const passed = section.rows.filter((r) => r.result.status === "pass").length;
|
|
6146
|
+
const warned = section.rows.filter((r) => r.result.status === "warn").length;
|
|
6147
|
+
const failed = section.rows.filter((r) => r.result.status === "fail").length;
|
|
6148
|
+
const total = section.rows.filter((r) => r.result.status !== "skip").length;
|
|
6149
|
+
const summary = `${String(passed)}/${String(total)} pass${warned > 0 ? ` \xB7 ${String(warned)} warn` : ""}${failed > 0 ? ` \xB7 ${String(failed)} fail` : ""}`;
|
|
6150
|
+
return /* @__PURE__ */ jsxs30(Box30, { flexDirection: "column", children: [
|
|
6151
|
+
i === 0 ? null : /* @__PURE__ */ jsx57(Box30, { marginTop: spacing.section }),
|
|
6152
|
+
/* @__PURE__ */ jsxs30(Box30, { children: [
|
|
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 })
|
|
6156
|
+
] }),
|
|
6157
|
+
/* @__PURE__ */ jsx57(Box30, { marginTop: spacing.section, flexDirection: "column", children: section.rows.map((row) => /* @__PURE__ */ jsx57(Row, { row, width }, row.name)) })
|
|
6158
|
+
] }, section.title);
|
|
6159
|
+
}) });
|
|
5852
6160
|
}
|
|
5853
6161
|
|
|
5854
6162
|
// src/integration/ui/tui/views/browse/progress-show-view.tsx
|
|
5855
|
-
import { useEffect as
|
|
6163
|
+
import { useEffect as useEffect30, useState as useState30 } from "react";
|
|
5856
6164
|
import { Box as Box31, Text as Text31 } from "ink";
|
|
5857
|
-
import { jsx as
|
|
6165
|
+
import { jsx as jsx58, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5858
6166
|
var MAX_TAIL = 80;
|
|
5859
|
-
var
|
|
6167
|
+
var TITLE29 = "Progress Log";
|
|
5860
6168
|
var HINTS3 = [];
|
|
5861
6169
|
function ProgressShowView({ sprintId } = {}) {
|
|
5862
|
-
const [state, setState] =
|
|
6170
|
+
const [state, setState] = useState30({ kind: "loading" });
|
|
5863
6171
|
useViewHints(HINTS3);
|
|
5864
|
-
|
|
6172
|
+
useEffect30(() => {
|
|
5865
6173
|
const ctl = { cancelled: false };
|
|
5866
6174
|
void (async () => {
|
|
5867
6175
|
try {
|
|
@@ -5877,7 +6185,7 @@ function ProgressShowView({ sprintId } = {}) {
|
|
|
5877
6185
|
ctl.cancelled = true;
|
|
5878
6186
|
};
|
|
5879
6187
|
}, [sprintId]);
|
|
5880
|
-
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) });
|
|
5881
6189
|
}
|
|
5882
6190
|
function renderContent(content) {
|
|
5883
6191
|
const lines = content.split("\n");
|
|
@@ -5890,19 +6198,19 @@ function renderContent(content) {
|
|
|
5890
6198
|
String(lines.length),
|
|
5891
6199
|
" total)"
|
|
5892
6200
|
] }) : null,
|
|
5893
|
-
tail.map((line2, i) => /* @__PURE__ */
|
|
6201
|
+
tail.map((line2, i) => /* @__PURE__ */ jsx58(Text31, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
|
|
5894
6202
|
] });
|
|
5895
6203
|
}
|
|
5896
6204
|
|
|
5897
6205
|
// src/integration/ui/tui/views/workflows/progress-log-view.tsx
|
|
5898
|
-
import { useMemo as
|
|
5899
|
-
import { jsx as
|
|
5900
|
-
var
|
|
5901
|
-
var
|
|
6206
|
+
import { useMemo as useMemo29 } from "react";
|
|
6207
|
+
import { jsx as jsx59 } from "react/jsx-runtime";
|
|
6208
|
+
var TITLE30 = "Log Progress";
|
|
6209
|
+
var HINTS_RUNNING18 = [
|
|
5902
6210
|
{ key: "Ctrl+D", action: "submit" },
|
|
5903
6211
|
{ key: "Esc", action: "cancel" }
|
|
5904
6212
|
];
|
|
5905
|
-
var
|
|
6213
|
+
var HINTS_DONE18 = [
|
|
5906
6214
|
{ key: "Enter", action: "home" },
|
|
5907
6215
|
{ key: "Esc", action: "back" }
|
|
5908
6216
|
];
|
|
@@ -5925,29 +6233,29 @@ function ProgressLogView() {
|
|
|
5925
6233
|
setPhase({ kind: "done" });
|
|
5926
6234
|
}
|
|
5927
6235
|
});
|
|
5928
|
-
const hints =
|
|
6236
|
+
const hints = useMemo29(() => phase.kind === "running" ? HINTS_RUNNING18 : HINTS_DONE18, [phase.kind]);
|
|
5929
6237
|
useViewHints(hints);
|
|
5930
|
-
return /* @__PURE__ */
|
|
6238
|
+
return /* @__PURE__ */ jsx59(ViewShell, { title: TITLE30, children: renderBody22(phase) });
|
|
5931
6239
|
}
|
|
5932
|
-
function
|
|
6240
|
+
function renderBody22(phase) {
|
|
5933
6241
|
switch (phase.kind) {
|
|
5934
6242
|
case "running":
|
|
5935
|
-
return /* @__PURE__ */
|
|
6243
|
+
return /* @__PURE__ */ jsx59(Spinner, { label: phase.step === "message" ? "Awaiting progress note\u2026" : "Saving progress note\u2026" });
|
|
5936
6244
|
case "cancelled":
|
|
5937
|
-
return /* @__PURE__ */
|
|
6245
|
+
return /* @__PURE__ */ jsx59(ResultCard, { kind: "info", title: "No note recorded" });
|
|
5938
6246
|
case "error":
|
|
5939
|
-
return /* @__PURE__ */
|
|
6247
|
+
return /* @__PURE__ */ jsx59(ResultCard, { kind: "error", title: "Could not log progress", lines: [phase.message] });
|
|
5940
6248
|
case "done":
|
|
5941
|
-
return /* @__PURE__ */
|
|
6249
|
+
return /* @__PURE__ */ jsx59(ResultCard, { kind: "success", title: "Progress logged" });
|
|
5942
6250
|
}
|
|
5943
6251
|
}
|
|
5944
6252
|
|
|
5945
6253
|
// src/integration/ui/tui/views/workflows/ideate-view.tsx
|
|
5946
|
-
import { useMemo as
|
|
5947
|
-
import { jsx as
|
|
5948
|
-
var
|
|
5949
|
-
var
|
|
5950
|
-
var
|
|
6254
|
+
import { useMemo as useMemo30 } from "react";
|
|
6255
|
+
import { jsx as jsx60 } from "react/jsx-runtime";
|
|
6256
|
+
var TITLE31 = "Ideate";
|
|
6257
|
+
var HINTS_RUNNING19 = [{ key: "Esc", action: "cancel" }];
|
|
6258
|
+
var HINTS_DONE19 = [
|
|
5951
6259
|
{ key: "Enter", action: "home" },
|
|
5952
6260
|
{ key: "Esc", action: "back" }
|
|
5953
6261
|
];
|
|
@@ -6001,22 +6309,22 @@ function IdeateView() {
|
|
|
6001
6309
|
setPhase({ kind: "done", summary });
|
|
6002
6310
|
}
|
|
6003
6311
|
});
|
|
6004
|
-
const hints =
|
|
6312
|
+
const hints = useMemo30(() => phase.kind === "running" ? HINTS_RUNNING19 : HINTS_DONE19, [phase.kind]);
|
|
6005
6313
|
useViewHints(hints);
|
|
6006
|
-
return /* @__PURE__ */
|
|
6314
|
+
return /* @__PURE__ */ jsx60(ViewShell, { title: TITLE31, children: renderBody23(phase) });
|
|
6007
6315
|
}
|
|
6008
|
-
function
|
|
6316
|
+
function renderBody23(phase) {
|
|
6009
6317
|
switch (phase.kind) {
|
|
6010
6318
|
case "running":
|
|
6011
|
-
return /* @__PURE__ */
|
|
6319
|
+
return /* @__PURE__ */ jsx60(Spinner, { label: stepLabel9(phase.step) });
|
|
6012
6320
|
case "no-projects":
|
|
6013
|
-
return /* @__PURE__ */
|
|
6321
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Register a project first" });
|
|
6014
6322
|
case "no-draft-sprint":
|
|
6015
|
-
return /* @__PURE__ */
|
|
6323
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "warning", title: "Current sprint is not a draft" });
|
|
6016
6324
|
case "error":
|
|
6017
|
-
return /* @__PURE__ */
|
|
6325
|
+
return /* @__PURE__ */ jsx60(ResultCard, { kind: "error", title: "Ideation failed", lines: [phase.message] });
|
|
6018
6326
|
case "done":
|
|
6019
|
-
return /* @__PURE__ */
|
|
6327
|
+
return /* @__PURE__ */ jsx60(
|
|
6020
6328
|
ResultCard,
|
|
6021
6329
|
{
|
|
6022
6330
|
kind: "success",
|
|
@@ -6030,7 +6338,7 @@ function renderBody26(phase) {
|
|
|
6030
6338
|
);
|
|
6031
6339
|
}
|
|
6032
6340
|
}
|
|
6033
|
-
function
|
|
6341
|
+
function stepLabel9(step) {
|
|
6034
6342
|
if (step === "title") return "Awaiting idea title\u2026";
|
|
6035
6343
|
if (step === "description") return "Awaiting idea description\u2026";
|
|
6036
6344
|
if (step === "project") return "Awaiting project selection\u2026";
|
|
@@ -6038,11 +6346,11 @@ function stepLabel12(step) {
|
|
|
6038
6346
|
}
|
|
6039
6347
|
|
|
6040
6348
|
// src/integration/ui/tui/views/onboarding-view.tsx
|
|
6041
|
-
import { useMemo as
|
|
6042
|
-
import { jsx as
|
|
6043
|
-
var
|
|
6044
|
-
var
|
|
6045
|
-
var
|
|
6349
|
+
import { useMemo as useMemo31 } from "react";
|
|
6350
|
+
import { jsx as jsx61 } from "react/jsx-runtime";
|
|
6351
|
+
var TITLE32 = "Welcome";
|
|
6352
|
+
var HINTS_RUNNING20 = [{ key: "Esc", action: "skip" }];
|
|
6353
|
+
var HINTS_DONE20 = [
|
|
6046
6354
|
{ key: "Enter", action: "home" },
|
|
6047
6355
|
{ key: "Esc", action: "home" }
|
|
6048
6356
|
];
|
|
@@ -6089,31 +6397,31 @@ function OnboardingView() {
|
|
|
6089
6397
|
}
|
|
6090
6398
|
}
|
|
6091
6399
|
});
|
|
6092
|
-
const hints =
|
|
6400
|
+
const hints = useMemo31(() => phase.kind === "running" ? HINTS_RUNNING20 : HINTS_DONE20, [phase.kind]);
|
|
6093
6401
|
useViewHints(hints);
|
|
6094
|
-
return /* @__PURE__ */
|
|
6402
|
+
return /* @__PURE__ */ jsx61(ViewShell, { title: TITLE32, children: renderBody24(phase) });
|
|
6095
6403
|
}
|
|
6096
|
-
function
|
|
6404
|
+
function renderBody24(phase) {
|
|
6097
6405
|
if (phase.kind === "running") {
|
|
6098
|
-
return /* @__PURE__ */
|
|
6406
|
+
return /* @__PURE__ */ jsx61(Spinner, { label: RUNNING_LABEL2[phase.step] });
|
|
6099
6407
|
}
|
|
6100
6408
|
if (phase.kind === "error") {
|
|
6101
|
-
return /* @__PURE__ */
|
|
6409
|
+
return /* @__PURE__ */ jsx61(ResultCard, { kind: "error", title: "Onboarding failed", lines: [phase.message] });
|
|
6102
6410
|
}
|
|
6103
6411
|
const providerLabel = phase.provider === "claude" ? "Claude Code" : phase.provider === "copilot" ? "GitHub Copilot" : "Skipped";
|
|
6104
6412
|
const nextSteps = phase.addingProject ? [{ action: "Finish adding your project", description: "continuing to the project wizard\u2026" }] : [
|
|
6105
6413
|
{ action: "Register a project", description: "Browse \u2192 Projects \u2192 Add" },
|
|
6106
6414
|
{ action: "Create a sprint", description: "once a project exists" }
|
|
6107
6415
|
];
|
|
6108
|
-
return /* @__PURE__ */
|
|
6416
|
+
return /* @__PURE__ */ jsx61(ResultCard, { kind: "success", title: "You're set up", fields: [["AI provider", providerLabel]], nextSteps });
|
|
6109
6417
|
}
|
|
6110
6418
|
|
|
6111
6419
|
// src/integration/ui/tui/views/workflows/reactivate-sprint-view.tsx
|
|
6112
|
-
import { useMemo as
|
|
6113
|
-
import { jsx as
|
|
6114
|
-
var
|
|
6115
|
-
var
|
|
6116
|
-
var
|
|
6420
|
+
import { useMemo as useMemo32 } from "react";
|
|
6421
|
+
import { jsx as jsx62 } from "react/jsx-runtime";
|
|
6422
|
+
var TITLE33 = "Reactivate Sprint";
|
|
6423
|
+
var HINTS_RUNNING21 = [{ key: "Esc", action: "cancel" }];
|
|
6424
|
+
var HINTS_DONE21 = [
|
|
6117
6425
|
{ key: "Enter", action: "back" },
|
|
6118
6426
|
{ key: "Esc", action: "back" }
|
|
6119
6427
|
];
|
|
@@ -6147,22 +6455,22 @@ function ReactivateSprintView({ sprintId }) {
|
|
|
6147
6455
|
}
|
|
6148
6456
|
});
|
|
6149
6457
|
const running = phase.kind === "running" || phase.kind === "loading";
|
|
6150
|
-
const hints =
|
|
6458
|
+
const hints = useMemo32(() => running ? HINTS_RUNNING21 : HINTS_DONE21, [running]);
|
|
6151
6459
|
useViewHints(hints);
|
|
6152
|
-
return /* @__PURE__ */
|
|
6460
|
+
return /* @__PURE__ */ jsx62(ViewShell, { title: TITLE33, children: renderBody25(phase) });
|
|
6153
6461
|
}
|
|
6154
|
-
function
|
|
6462
|
+
function renderBody25(phase) {
|
|
6155
6463
|
switch (phase.kind) {
|
|
6156
6464
|
case "loading":
|
|
6157
|
-
return /* @__PURE__ */
|
|
6465
|
+
return /* @__PURE__ */ jsx62(Spinner, { label: "Loading sprint\u2026" });
|
|
6158
6466
|
case "running":
|
|
6159
|
-
return /* @__PURE__ */
|
|
6467
|
+
return /* @__PURE__ */ jsx62(Spinner, { label: phase.step === "confirm" ? "Awaiting confirmation\u2026" : "Reactivating sprint\u2026" });
|
|
6160
6468
|
case "cancelled":
|
|
6161
|
-
return /* @__PURE__ */
|
|
6469
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "info", title: "Reactivation cancelled" });
|
|
6162
6470
|
case "missing-id":
|
|
6163
|
-
return /* @__PURE__ */
|
|
6471
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "No sprint ID provided" });
|
|
6164
6472
|
case "not-closed":
|
|
6165
|
-
return /* @__PURE__ */
|
|
6473
|
+
return /* @__PURE__ */ jsx62(
|
|
6166
6474
|
ResultCard,
|
|
6167
6475
|
{
|
|
6168
6476
|
kind: "warning",
|
|
@@ -6171,9 +6479,9 @@ function renderBody28(phase) {
|
|
|
6171
6479
|
}
|
|
6172
6480
|
);
|
|
6173
6481
|
case "error":
|
|
6174
|
-
return /* @__PURE__ */
|
|
6482
|
+
return /* @__PURE__ */ jsx62(ResultCard, { kind: "error", title: "Could not reactivate sprint", lines: [phase.message] });
|
|
6175
6483
|
case "done":
|
|
6176
|
-
return /* @__PURE__ */
|
|
6484
|
+
return /* @__PURE__ */ jsx62(
|
|
6177
6485
|
ResultCard,
|
|
6178
6486
|
{
|
|
6179
6487
|
kind: "success",
|
|
@@ -6189,9 +6497,9 @@ function renderBody28(phase) {
|
|
|
6189
6497
|
}
|
|
6190
6498
|
|
|
6191
6499
|
// src/integration/ui/tui/views/browse/evaluations-view.tsx
|
|
6192
|
-
import { useEffect as
|
|
6193
|
-
import { jsx as
|
|
6194
|
-
var
|
|
6500
|
+
import { useEffect as useEffect31, useState as useState31 } from "react";
|
|
6501
|
+
import { jsx as jsx63 } from "react/jsx-runtime";
|
|
6502
|
+
var TITLE34 = "Evaluations";
|
|
6195
6503
|
var HINTS4 = [
|
|
6196
6504
|
{ key: "\u2191/\u2193", action: "navigate" },
|
|
6197
6505
|
{ key: "Enter", action: "open" }
|
|
@@ -6222,9 +6530,9 @@ var COLUMNS2 = [
|
|
|
6222
6530
|
];
|
|
6223
6531
|
function EvaluationsView({ sprintId }) {
|
|
6224
6532
|
const router = useRouter();
|
|
6225
|
-
const [state, setState] =
|
|
6533
|
+
const [state, setState] = useState31({ kind: "loading" });
|
|
6226
6534
|
useViewHints(HINTS4);
|
|
6227
|
-
|
|
6535
|
+
useEffect31(() => {
|
|
6228
6536
|
const ctl = { cancelled: false };
|
|
6229
6537
|
void (async () => {
|
|
6230
6538
|
try {
|
|
@@ -6243,7 +6551,7 @@ function EvaluationsView({ sprintId }) {
|
|
|
6243
6551
|
ctl.cancelled = true;
|
|
6244
6552
|
};
|
|
6245
6553
|
}, [sprintId]);
|
|
6246
|
-
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(
|
|
6247
6555
|
ListView,
|
|
6248
6556
|
{
|
|
6249
6557
|
rows: state.tasks,
|
|
@@ -6256,10 +6564,10 @@ function EvaluationsView({ sprintId }) {
|
|
|
6256
6564
|
}
|
|
6257
6565
|
|
|
6258
6566
|
// src/integration/ui/tui/views/browse/evaluation-show-view.tsx
|
|
6259
|
-
import { useEffect as
|
|
6567
|
+
import { useEffect as useEffect32, useState as useState32 } from "react";
|
|
6260
6568
|
import { Box as Box32, Text as Text32 } from "ink";
|
|
6261
|
-
import { jsx as
|
|
6262
|
-
var
|
|
6569
|
+
import { jsx as jsx64, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
6570
|
+
var TITLE35 = "Evaluation";
|
|
6263
6571
|
var HINTS5 = [];
|
|
6264
6572
|
var MAX_LINES = 200;
|
|
6265
6573
|
function kindFor(status) {
|
|
@@ -6268,9 +6576,9 @@ function kindFor(status) {
|
|
|
6268
6576
|
return "warning";
|
|
6269
6577
|
}
|
|
6270
6578
|
function EvaluationShowView({ sprintId, taskId }) {
|
|
6271
|
-
const [state, setState] =
|
|
6579
|
+
const [state, setState] = useState32({ kind: "loading" });
|
|
6272
6580
|
useViewHints(HINTS5);
|
|
6273
|
-
|
|
6581
|
+
useEffect32(() => {
|
|
6274
6582
|
const ctl = { cancelled: false };
|
|
6275
6583
|
void (async () => {
|
|
6276
6584
|
try {
|
|
@@ -6290,22 +6598,22 @@ function EvaluationShowView({ sprintId, taskId }) {
|
|
|
6290
6598
|
ctl.cancelled = true;
|
|
6291
6599
|
};
|
|
6292
6600
|
}, [sprintId, taskId]);
|
|
6293
|
-
return /* @__PURE__ */
|
|
6601
|
+
return /* @__PURE__ */ jsx64(ViewShell, { title: TITLE35, children: renderBody26(state) });
|
|
6294
6602
|
}
|
|
6295
|
-
function
|
|
6296
|
-
if (state.kind === "loading") return /* @__PURE__ */
|
|
6603
|
+
function renderBody26(state) {
|
|
6604
|
+
if (state.kind === "loading") return /* @__PURE__ */ jsx64(Spinner, { label: "Loading evaluation\u2026" });
|
|
6297
6605
|
if (state.kind === "error")
|
|
6298
|
-
return /* @__PURE__ */
|
|
6606
|
+
return /* @__PURE__ */ jsx64(ResultCard, { kind: "error", title: "Could not load evaluation", lines: [state.message] });
|
|
6299
6607
|
const { task, content } = state;
|
|
6300
6608
|
const lines = content.split("\n");
|
|
6301
6609
|
const tail = lines.length > MAX_LINES ? lines.slice(-MAX_LINES) : lines;
|
|
6302
6610
|
return /* @__PURE__ */ jsxs32(Box32, { flexDirection: "column", children: [
|
|
6303
6611
|
/* @__PURE__ */ jsxs32(Box32, { children: [
|
|
6304
|
-
/* @__PURE__ */
|
|
6305
|
-
/* @__PURE__ */
|
|
6306
|
-
/* @__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) })
|
|
6307
6615
|
] }),
|
|
6308
|
-
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: [
|
|
6309
6617
|
lines.length > MAX_LINES ? /* @__PURE__ */ jsxs32(Text32, { dimColor: true, children: [
|
|
6310
6618
|
"Showing last ",
|
|
6311
6619
|
String(MAX_LINES),
|
|
@@ -6313,21 +6621,21 @@ function renderBody29(state) {
|
|
|
6313
6621
|
String(lines.length),
|
|
6314
6622
|
" total)"
|
|
6315
6623
|
] }) : null,
|
|
6316
|
-
tail.map((line2, i) => /* @__PURE__ */
|
|
6624
|
+
tail.map((line2, i) => /* @__PURE__ */ jsx64(Text32, { dimColor: line2.trim().length === 0, children: line2.length > 0 ? line2 : " " }, i))
|
|
6317
6625
|
] })
|
|
6318
6626
|
] });
|
|
6319
6627
|
}
|
|
6320
6628
|
|
|
6321
6629
|
// src/integration/ui/tui/views/browse/feedback-view.tsx
|
|
6322
|
-
import { useEffect as
|
|
6630
|
+
import { useEffect as useEffect33, useState as useState33 } from "react";
|
|
6323
6631
|
import { Box as Box33, Text as Text33 } from "ink";
|
|
6324
|
-
import { jsx as
|
|
6325
|
-
var
|
|
6632
|
+
import { jsx as jsx65, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
6633
|
+
var TITLE36 = "Feedback";
|
|
6326
6634
|
var HINTS6 = [];
|
|
6327
6635
|
function FeedbackView({ sprintId }) {
|
|
6328
|
-
const [state, setState] =
|
|
6636
|
+
const [state, setState] = useState33({ kind: "loading" });
|
|
6329
6637
|
useViewHints(HINTS6);
|
|
6330
|
-
|
|
6638
|
+
useEffect33(() => {
|
|
6331
6639
|
const ctl = { cancelled: false };
|
|
6332
6640
|
void (async () => {
|
|
6333
6641
|
try {
|
|
@@ -6344,16 +6652,16 @@ function FeedbackView({ sprintId }) {
|
|
|
6344
6652
|
ctl.cancelled = true;
|
|
6345
6653
|
};
|
|
6346
6654
|
}, [sprintId]);
|
|
6347
|
-
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(
|
|
6348
6656
|
ResultCard,
|
|
6349
6657
|
{
|
|
6350
6658
|
kind: "info",
|
|
6351
6659
|
title: "No feedback yet",
|
|
6352
6660
|
lines: ["Feedback is captured during the post-execution loop."]
|
|
6353
6661
|
}
|
|
6354
|
-
) : state.kind === "error" ? /* @__PURE__ */
|
|
6355
|
-
/* @__PURE__ */
|
|
6356
|
-
/* @__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 })
|
|
6357
6665
|
] }, i)) }) });
|
|
6358
6666
|
}
|
|
6359
6667
|
function extractFeedback(progress) {
|
|
@@ -6371,9 +6679,210 @@ function extractFeedback(progress) {
|
|
|
6371
6679
|
return out;
|
|
6372
6680
|
}
|
|
6373
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
|
+
|
|
6374
6883
|
// src/integration/ui/tui/components/version-hint.tsx
|
|
6375
|
-
import { useEffect as
|
|
6376
|
-
import { Text as
|
|
6884
|
+
import { useEffect as useEffect36, useState as useState36 } from "react";
|
|
6885
|
+
import { Text as Text36 } from "ink";
|
|
6377
6886
|
|
|
6378
6887
|
// src/integration/external/version-check.ts
|
|
6379
6888
|
import { mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -6461,10 +6970,10 @@ async function checkLatestVersion() {
|
|
|
6461
6970
|
}
|
|
6462
6971
|
|
|
6463
6972
|
// src/integration/ui/tui/components/version-hint.tsx
|
|
6464
|
-
import { jsx as
|
|
6973
|
+
import { jsx as jsx68 } from "react/jsx-runtime";
|
|
6465
6974
|
function VersionHint() {
|
|
6466
|
-
const [check, setCheck] =
|
|
6467
|
-
|
|
6975
|
+
const [check, setCheck] = useState36(null);
|
|
6976
|
+
useEffect36(() => {
|
|
6468
6977
|
let cancelled = false;
|
|
6469
6978
|
void checkLatestVersion().then((result) => {
|
|
6470
6979
|
if (!cancelled && result !== null) setCheck(result);
|
|
@@ -6474,167 +6983,180 @@ function VersionHint() {
|
|
|
6474
6983
|
};
|
|
6475
6984
|
}, []);
|
|
6476
6985
|
if (!check?.updateAvailable) return null;
|
|
6477
|
-
return /* @__PURE__ */
|
|
6986
|
+
return /* @__PURE__ */ jsx68(Text36, { dimColor: true, children: `v${check.latest} available \xB7 npm install -g ralphctl` });
|
|
6478
6987
|
}
|
|
6479
6988
|
|
|
6480
6989
|
// src/integration/ui/tui/views/view-router.tsx
|
|
6481
|
-
import { jsx as
|
|
6990
|
+
import { jsx as jsx69, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
6482
6991
|
var views = {
|
|
6483
6992
|
home: {
|
|
6484
6993
|
label: "Home",
|
|
6485
|
-
render: () => /* @__PURE__ */
|
|
6994
|
+
render: () => /* @__PURE__ */ jsx69(HomeView, {})
|
|
6486
6995
|
},
|
|
6487
6996
|
settings: {
|
|
6488
6997
|
label: "Settings",
|
|
6489
|
-
render: () => /* @__PURE__ */
|
|
6998
|
+
render: () => /* @__PURE__ */ jsx69(SettingsView, {})
|
|
6490
6999
|
},
|
|
6491
7000
|
execute: {
|
|
6492
7001
|
label: "Execute",
|
|
6493
7002
|
render: (props) => {
|
|
6494
7003
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
|
|
7004
|
+
const executionId = typeof props["executionId"] === "string" ? props["executionId"] : void 0;
|
|
6495
7005
|
const executionOptions = props["executionOptions"];
|
|
6496
|
-
return /* @__PURE__ */
|
|
7006
|
+
return /* @__PURE__ */ jsx69(ExecuteView, { sprintId, executionId, executionOptions });
|
|
6497
7007
|
}
|
|
6498
7008
|
},
|
|
6499
7009
|
dashboard: {
|
|
6500
7010
|
label: "Dashboard",
|
|
6501
|
-
render: () => /* @__PURE__ */
|
|
7011
|
+
render: () => /* @__PURE__ */ jsx69(DashboardView, {})
|
|
7012
|
+
},
|
|
7013
|
+
"running-executions": {
|
|
7014
|
+
label: "Runs",
|
|
7015
|
+
render: () => /* @__PURE__ */ jsx69(RunningExecutionsView, {})
|
|
6502
7016
|
},
|
|
6503
7017
|
"refine-phase": {
|
|
6504
7018
|
label: "Refine",
|
|
6505
7019
|
render: (props) => {
|
|
6506
7020
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
|
|
6507
|
-
return /* @__PURE__ */
|
|
7021
|
+
return /* @__PURE__ */ jsx69(RefinePhaseView, { sprintId });
|
|
6508
7022
|
}
|
|
6509
7023
|
},
|
|
6510
7024
|
"plan-phase": {
|
|
6511
7025
|
label: "Plan",
|
|
6512
7026
|
render: (props) => {
|
|
6513
7027
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
|
|
6514
|
-
return /* @__PURE__ */
|
|
7028
|
+
return /* @__PURE__ */ jsx69(PlanPhaseView, { sprintId });
|
|
6515
7029
|
}
|
|
6516
7030
|
},
|
|
6517
7031
|
"close-phase": {
|
|
6518
7032
|
label: "Close",
|
|
6519
7033
|
render: (props) => {
|
|
6520
7034
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
|
|
6521
|
-
return /* @__PURE__ */
|
|
7035
|
+
return /* @__PURE__ */ jsx69(ClosePhaseView, { sprintId });
|
|
6522
7036
|
}
|
|
6523
7037
|
},
|
|
6524
7038
|
"sprint-create": {
|
|
6525
7039
|
label: "Create Sprint",
|
|
6526
|
-
render: () => /* @__PURE__ */
|
|
7040
|
+
render: () => /* @__PURE__ */ jsx69(CreateSprintView, {})
|
|
6527
7041
|
},
|
|
6528
7042
|
"sprint-delete": {
|
|
6529
7043
|
label: "Delete Sprint",
|
|
6530
7044
|
render: (props) => {
|
|
6531
7045
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6532
|
-
return /* @__PURE__ */
|
|
7046
|
+
return /* @__PURE__ */ jsx69(DeleteSprintView, { sprintId });
|
|
6533
7047
|
}
|
|
6534
7048
|
},
|
|
6535
7049
|
"sprint-set-current": {
|
|
6536
7050
|
label: "Set Current",
|
|
6537
|
-
render: () => /* @__PURE__ */
|
|
7051
|
+
render: () => /* @__PURE__ */ jsx69(SetCurrentSprintView, {})
|
|
6538
7052
|
},
|
|
6539
7053
|
"sprint-requirements-export": {
|
|
6540
7054
|
label: "Requirements",
|
|
6541
7055
|
render: (props) => {
|
|
6542
7056
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6543
|
-
return /* @__PURE__ */
|
|
7057
|
+
return /* @__PURE__ */ jsx69(RequirementsExportView, { sprintId });
|
|
6544
7058
|
}
|
|
6545
7059
|
},
|
|
6546
7060
|
"sprint-context-export": {
|
|
6547
7061
|
label: "Context",
|
|
6548
7062
|
render: (props) => {
|
|
6549
7063
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6550
|
-
return /* @__PURE__ */
|
|
7064
|
+
return /* @__PURE__ */ jsx69(ContextExportView, { sprintId });
|
|
6551
7065
|
}
|
|
6552
7066
|
},
|
|
6553
7067
|
"ticket-add": {
|
|
6554
7068
|
label: "Add Ticket",
|
|
6555
|
-
render: () => /* @__PURE__ */
|
|
7069
|
+
render: () => /* @__PURE__ */ jsx69(TicketAddView, {})
|
|
6556
7070
|
},
|
|
6557
7071
|
"ticket-edit": {
|
|
6558
7072
|
label: "Edit Ticket",
|
|
6559
7073
|
render: (props) => {
|
|
6560
7074
|
const ticketId = typeof props["ticketId"] === "string" ? props["ticketId"] : void 0;
|
|
6561
|
-
return /* @__PURE__ */
|
|
7075
|
+
return /* @__PURE__ */ jsx69(TicketEditView, { ticketId });
|
|
6562
7076
|
}
|
|
6563
7077
|
},
|
|
6564
7078
|
"ticket-remove": {
|
|
6565
7079
|
label: "Remove Ticket",
|
|
6566
|
-
render: () => /* @__PURE__ */
|
|
7080
|
+
render: () => /* @__PURE__ */ jsx69(TicketRemoveView, {})
|
|
6567
7081
|
},
|
|
6568
7082
|
"ticket-refine": {
|
|
6569
7083
|
label: "Re-Refine Ticket",
|
|
6570
|
-
render: () => /* @__PURE__ */
|
|
7084
|
+
render: () => /* @__PURE__ */ jsx69(TicketRefineView, {})
|
|
6571
7085
|
},
|
|
6572
|
-
"task-add": { label: "Add Task", render: () => /* @__PURE__ */
|
|
6573
|
-
"task-import": { label: "Import Tasks", render: () => /* @__PURE__ */
|
|
6574
|
-
"task-status": { label: "Task Status", render: () => /* @__PURE__ */
|
|
6575
|
-
"task-reorder": { label: "Reorder Task", render: () => /* @__PURE__ */
|
|
6576
|
-
"task-remove": { label: "Remove Task", render: () => /* @__PURE__ */
|
|
6577
|
-
"task-next": { label: "Next Task", render: () => /* @__PURE__ */
|
|
6578
|
-
"project-add": { label: "Add Project", render: () => /* @__PURE__ */
|
|
6579
|
-
"project-remove": { label: "Remove Project", render: () => /* @__PURE__ */
|
|
6580
|
-
"project-repo-add": { label: "Add Repository", render: () => /* @__PURE__ */
|
|
6581
|
-
"project-repo-remove": { label: "Remove Repository", render: () => /* @__PURE__ */
|
|
6582
|
-
"project-edit": { label: "Edit Project", render: () => /* @__PURE__ */
|
|
6583
|
-
"
|
|
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, {}) },
|
|
7097
|
+
"project-onboard": {
|
|
7098
|
+
label: "Onboard Repository",
|
|
7099
|
+
render: (props) => {
|
|
7100
|
+
const projectName = typeof props["projectName"] === "string" ? props["projectName"] : void 0;
|
|
7101
|
+
const repo = typeof props["repo"] === "string" ? props["repo"] : void 0;
|
|
7102
|
+
return /* @__PURE__ */ jsx69(ProjectOnboardView, { projectName, repo });
|
|
7103
|
+
}
|
|
7104
|
+
},
|
|
7105
|
+
"sprint-list": { label: "Sprints", render: () => /* @__PURE__ */ jsx69(SprintListView, {}) },
|
|
6584
7106
|
"sprint-show": {
|
|
6585
7107
|
label: "Sprint",
|
|
6586
7108
|
render: (props) => {
|
|
6587
7109
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6588
|
-
return /* @__PURE__ */
|
|
7110
|
+
return /* @__PURE__ */ jsx69(SprintShowView, { sprintId });
|
|
6589
7111
|
}
|
|
6590
7112
|
},
|
|
6591
|
-
"ticket-list": { label: "Tickets", render: () => /* @__PURE__ */
|
|
7113
|
+
"ticket-list": { label: "Tickets", render: () => /* @__PURE__ */ jsx69(TicketListView, {}) },
|
|
6592
7114
|
"ticket-show": {
|
|
6593
7115
|
label: "Ticket",
|
|
6594
7116
|
render: (props) => {
|
|
6595
7117
|
const ticketId = typeof props["ticketId"] === "string" ? props["ticketId"] : void 0;
|
|
6596
|
-
return /* @__PURE__ */
|
|
7118
|
+
return /* @__PURE__ */ jsx69(TicketShowView, { ticketId });
|
|
6597
7119
|
}
|
|
6598
7120
|
},
|
|
6599
|
-
"task-list": { label: "Tasks", render: () => /* @__PURE__ */
|
|
7121
|
+
"task-list": { label: "Tasks", render: () => /* @__PURE__ */ jsx69(TaskListView, {}) },
|
|
6600
7122
|
"task-show": {
|
|
6601
7123
|
label: "Task",
|
|
6602
7124
|
render: (props) => {
|
|
6603
7125
|
const taskId = typeof props["taskId"] === "string" ? props["taskId"] : void 0;
|
|
6604
|
-
return /* @__PURE__ */
|
|
7126
|
+
return /* @__PURE__ */ jsx69(TaskShowView, { taskId });
|
|
6605
7127
|
}
|
|
6606
7128
|
},
|
|
6607
|
-
"project-list": { label: "Projects", render: () => /* @__PURE__ */
|
|
7129
|
+
"project-list": { label: "Projects", render: () => /* @__PURE__ */ jsx69(ProjectListView, {}) },
|
|
6608
7130
|
"project-show": {
|
|
6609
7131
|
label: "Project",
|
|
6610
7132
|
render: (props) => {
|
|
6611
7133
|
const projectName = typeof props["projectName"] === "string" ? props["projectName"] : void 0;
|
|
6612
|
-
return /* @__PURE__ */
|
|
7134
|
+
return /* @__PURE__ */ jsx69(ProjectShowView, { projectName });
|
|
6613
7135
|
}
|
|
6614
7136
|
},
|
|
6615
|
-
doctor: { label: "Doctor", render: () => /* @__PURE__ */
|
|
6616
|
-
"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, {}) },
|
|
6617
7139
|
"progress-show": {
|
|
6618
7140
|
label: "Progress",
|
|
6619
7141
|
render: (props) => {
|
|
6620
7142
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6621
|
-
return /* @__PURE__ */
|
|
7143
|
+
return /* @__PURE__ */ jsx69(ProgressShowView, { sprintId });
|
|
6622
7144
|
}
|
|
6623
7145
|
},
|
|
6624
|
-
ideate: { label: "Ideate", render: () => /* @__PURE__ */
|
|
6625
|
-
onboarding: { label: "Welcome", render: () => /* @__PURE__ */
|
|
7146
|
+
ideate: { label: "Ideate", render: () => /* @__PURE__ */ jsx69(IdeateView, {}) },
|
|
7147
|
+
onboarding: { label: "Welcome", render: () => /* @__PURE__ */ jsx69(OnboardingView, {}) },
|
|
6626
7148
|
"sprint-reactivate": {
|
|
6627
7149
|
label: "Reactivate Sprint",
|
|
6628
7150
|
render: (props) => {
|
|
6629
7151
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6630
|
-
return /* @__PURE__ */
|
|
7152
|
+
return /* @__PURE__ */ jsx69(ReactivateSprintView, { sprintId });
|
|
6631
7153
|
}
|
|
6632
7154
|
},
|
|
6633
7155
|
evaluations: {
|
|
6634
7156
|
label: "Evaluations",
|
|
6635
7157
|
render: (props) => {
|
|
6636
7158
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6637
|
-
return /* @__PURE__ */
|
|
7159
|
+
return /* @__PURE__ */ jsx69(EvaluationsView, { sprintId });
|
|
6638
7160
|
}
|
|
6639
7161
|
},
|
|
6640
7162
|
"evaluation-show": {
|
|
@@ -6642,28 +7164,32 @@ var views = {
|
|
|
6642
7164
|
render: (props) => {
|
|
6643
7165
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : "";
|
|
6644
7166
|
const taskId = typeof props["taskId"] === "string" ? props["taskId"] : "";
|
|
6645
|
-
return /* @__PURE__ */
|
|
7167
|
+
return /* @__PURE__ */ jsx69(EvaluationShowView, { sprintId, taskId });
|
|
6646
7168
|
}
|
|
6647
7169
|
},
|
|
6648
7170
|
feedback: {
|
|
6649
7171
|
label: "Feedback",
|
|
6650
7172
|
render: (props) => {
|
|
6651
7173
|
const sprintId = typeof props["sprintId"] === "string" ? props["sprintId"] : void 0;
|
|
6652
|
-
return /* @__PURE__ */
|
|
7174
|
+
return /* @__PURE__ */ jsx69(FeedbackView, { sprintId });
|
|
6653
7175
|
}
|
|
6654
7176
|
}
|
|
6655
7177
|
};
|
|
6656
7178
|
function ViewRouter({ initialStack }) {
|
|
6657
|
-
const
|
|
6658
|
-
const [stack, setStack] = useState29(() => {
|
|
7179
|
+
const [stack, setStack] = useState37(() => {
|
|
6659
7180
|
if (initialStack.length === 0) {
|
|
6660
7181
|
return [{ id: "home" }];
|
|
6661
7182
|
}
|
|
6662
7183
|
return collapseAdjacentDuplicates(initialStack);
|
|
6663
7184
|
});
|
|
6664
|
-
const
|
|
6665
|
-
|
|
6666
|
-
|
|
7185
|
+
const registry = useMemo34(() => {
|
|
7186
|
+
try {
|
|
7187
|
+
return getSharedDeps().executionRegistry;
|
|
7188
|
+
} catch {
|
|
7189
|
+
return null;
|
|
7190
|
+
}
|
|
7191
|
+
}, []);
|
|
7192
|
+
const push = useCallback12((entry) => {
|
|
6667
7193
|
setStack((s) => {
|
|
6668
7194
|
const top = s[s.length - 1];
|
|
6669
7195
|
if (top?.id === entry.id && samePropsBag(top.props, entry.props)) {
|
|
@@ -6672,72 +7198,43 @@ function ViewRouter({ initialStack }) {
|
|
|
6672
7198
|
return [...s, entry];
|
|
6673
7199
|
});
|
|
6674
7200
|
}, []);
|
|
6675
|
-
const pop =
|
|
7201
|
+
const pop = useCallback12(() => {
|
|
6676
7202
|
setStack((s) => s.length > 1 ? s.slice(0, -1) : s);
|
|
6677
7203
|
}, []);
|
|
6678
|
-
const replace =
|
|
7204
|
+
const replace = useCallback12((entry) => {
|
|
6679
7205
|
setStack((s) => s.length === 0 ? [entry] : [...s.slice(0, -1), entry]);
|
|
6680
7206
|
}, []);
|
|
6681
|
-
const reset =
|
|
7207
|
+
const reset = useCallback12((entry) => {
|
|
6682
7208
|
setStack(() => [entry]);
|
|
6683
7209
|
}, []);
|
|
6684
7210
|
const current = stack[stack.length - 1];
|
|
6685
7211
|
if (current === void 0) {
|
|
6686
7212
|
throw new Error("ViewRouter stack is empty");
|
|
6687
7213
|
}
|
|
6688
|
-
const api =
|
|
7214
|
+
const api = useMemo34(
|
|
6689
7215
|
() => ({ current, stack, push, pop, replace, reset }),
|
|
6690
7216
|
[current, stack, push, pop, replace, reset]
|
|
6691
7217
|
);
|
|
6692
|
-
const currentPrompt = useCurrentPrompt();
|
|
6693
|
-
const routerHotkeysActive = currentPrompt === null;
|
|
6694
|
-
useInput19(
|
|
6695
|
-
(input, key) => {
|
|
6696
|
-
if (key.escape) {
|
|
6697
|
-
pop();
|
|
6698
|
-
return;
|
|
6699
|
-
}
|
|
6700
|
-
if (input === "h") {
|
|
6701
|
-
reset({ id: "home" });
|
|
6702
|
-
return;
|
|
6703
|
-
}
|
|
6704
|
-
if (input === "s" && current.id !== "settings") {
|
|
6705
|
-
push({ id: "settings" });
|
|
6706
|
-
return;
|
|
6707
|
-
}
|
|
6708
|
-
if (input === "d" && current.id !== "dashboard") {
|
|
6709
|
-
push({ id: "dashboard" });
|
|
6710
|
-
return;
|
|
6711
|
-
}
|
|
6712
|
-
if (input === "?" && current.id !== "doctor") {
|
|
6713
|
-
push({ id: "doctor" });
|
|
6714
|
-
return;
|
|
6715
|
-
}
|
|
6716
|
-
if (input === "q" && stackRef.current.length === 1 && current.id === "home") {
|
|
6717
|
-
app.exit();
|
|
6718
|
-
}
|
|
6719
|
-
},
|
|
6720
|
-
{ isActive: routerHotkeysActive }
|
|
6721
|
-
);
|
|
6722
7218
|
const meta = views[current.id];
|
|
6723
7219
|
const props = current.props ?? {};
|
|
6724
|
-
return /* @__PURE__ */
|
|
6725
|
-
/* @__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 }),
|
|
6726
7223
|
meta.render(props),
|
|
6727
|
-
/* @__PURE__ */
|
|
6728
|
-
/* @__PURE__ */
|
|
6729
|
-
/* @__PURE__ */
|
|
6730
|
-
|
|
7224
|
+
/* @__PURE__ */ jsx69(PromptHost, {}),
|
|
7225
|
+
/* @__PURE__ */ jsx69(Box36, { marginTop: spacing.section, children: /* @__PURE__ */ jsx69(KeyboardHints, {}) }),
|
|
7226
|
+
/* @__PURE__ */ jsxs36(
|
|
7227
|
+
Box36,
|
|
6731
7228
|
{
|
|
6732
|
-
marginTop:
|
|
7229
|
+
marginTop: spacing.section,
|
|
6733
7230
|
borderStyle: "round",
|
|
6734
7231
|
borderColor: inkColors.primary,
|
|
6735
7232
|
borderDimColor: true,
|
|
6736
7233
|
paddingX: spacing.indent,
|
|
6737
7234
|
justifyContent: "space-between",
|
|
6738
7235
|
children: [
|
|
6739
|
-
/* @__PURE__ */
|
|
6740
|
-
/* @__PURE__ */
|
|
7236
|
+
/* @__PURE__ */ jsx69(StatusBar, { breadcrumb: stack.map((e) => views[e.id].label), hints: buildHints(current.id, stack.length) }),
|
|
7237
|
+
/* @__PURE__ */ jsx69(VersionHint, {})
|
|
6741
7238
|
]
|
|
6742
7239
|
}
|
|
6743
7240
|
)
|
|
@@ -6777,6 +7274,9 @@ function buildHints(currentId, depth) {
|
|
|
6777
7274
|
if (currentId !== "doctor") {
|
|
6778
7275
|
hints.push({ key: "?", action: "doctor" });
|
|
6779
7276
|
}
|
|
7277
|
+
if (currentId !== "running-executions") {
|
|
7278
|
+
hints.push({ key: "x", action: "runs" });
|
|
7279
|
+
}
|
|
6780
7280
|
if (currentId === "home" && depth === 1) {
|
|
6781
7281
|
hints.push({ key: "b", action: "browse" });
|
|
6782
7282
|
hints.push({ key: "q", action: "quit" });
|
|
@@ -6785,7 +7285,7 @@ function buildHints(currentId, depth) {
|
|
|
6785
7285
|
}
|
|
6786
7286
|
|
|
6787
7287
|
// src/integration/ui/tui/views/app.tsx
|
|
6788
|
-
import { jsx as
|
|
7288
|
+
import { jsx as jsx70 } from "react/jsx-runtime";
|
|
6789
7289
|
var MAX_CONTENT_WIDTH = 160;
|
|
6790
7290
|
async function isFirstRun() {
|
|
6791
7291
|
try {
|
|
@@ -6812,8 +7312,8 @@ function buildInitialStack(initialView, mountOptions) {
|
|
|
6812
7312
|
}
|
|
6813
7313
|
function useTerminalWidth() {
|
|
6814
7314
|
const { stdout } = useStdout();
|
|
6815
|
-
const [width, setWidth] =
|
|
6816
|
-
|
|
7315
|
+
const [width, setWidth] = useState38(stdout.columns);
|
|
7316
|
+
useEffect37(() => {
|
|
6817
7317
|
const onResize = () => {
|
|
6818
7318
|
setWidth(stdout.columns);
|
|
6819
7319
|
};
|
|
@@ -6827,8 +7327,8 @@ function useTerminalWidth() {
|
|
|
6827
7327
|
function App({ initialView, mountOptions }) {
|
|
6828
7328
|
const terminalWidth = useTerminalWidth();
|
|
6829
7329
|
const contentWidth = Math.min(terminalWidth, MAX_CONTENT_WIDTH);
|
|
6830
|
-
const [stack, setStack] =
|
|
6831
|
-
|
|
7330
|
+
const [stack, setStack] = useState38(null);
|
|
7331
|
+
useEffect37(() => {
|
|
6832
7332
|
let cancelled = false;
|
|
6833
7333
|
const decideInitial = async () => {
|
|
6834
7334
|
if (initialView === "execute" && mountOptions.sprintId !== void 0) {
|
|
@@ -6845,13 +7345,13 @@ function App({ initialView, mountOptions }) {
|
|
|
6845
7345
|
};
|
|
6846
7346
|
}, [initialView, mountOptions]);
|
|
6847
7347
|
if (stack === null) {
|
|
6848
|
-
return /* @__PURE__ */
|
|
7348
|
+
return /* @__PURE__ */ jsx70(Box37, { width: terminalWidth });
|
|
6849
7349
|
}
|
|
6850
|
-
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 }) }) });
|
|
6851
7351
|
}
|
|
6852
7352
|
|
|
6853
7353
|
// src/integration/ui/tui/runtime/mount.tsx
|
|
6854
|
-
import { jsx as
|
|
7354
|
+
import { jsx as jsx71 } from "react/jsx-runtime";
|
|
6855
7355
|
function canMountInk() {
|
|
6856
7356
|
if (process.env["RALPHCTL_NO_TUI"]) return false;
|
|
6857
7357
|
if (process.env["CI"]) return false;
|
|
@@ -6870,7 +7370,7 @@ async function mountInkApp(options) {
|
|
|
6870
7370
|
setSharedDeps(createSharedDeps({ logger, signalBus, prompt }));
|
|
6871
7371
|
enterAltScreen();
|
|
6872
7372
|
const releaseHost = registerExternalHost();
|
|
6873
|
-
const app = render(/* @__PURE__ */
|
|
7373
|
+
const app = render(/* @__PURE__ */ jsx71(App, { initialView: options.initialView, mountOptions: options }), {
|
|
6874
7374
|
exitOnCtrlC: false
|
|
6875
7375
|
// We own Ctrl+C inside the app for prompt cancellation.
|
|
6876
7376
|
});
|