@kenkaiiii/ggcoder 4.3.206 → 4.3.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +10 -7
- package/dist/cli.js.map +1 -1
- package/dist/core/goal-controller.js +13 -13
- package/dist/core/goal-controller.js.map +1 -1
- package/dist/core/goal-controller.test.js +54 -12
- package/dist/core/goal-controller.test.js.map +1 -1
- package/dist/core/goal-worker-dev-server-lifecycle.test.d.ts +2 -0
- package/dist/core/goal-worker-dev-server-lifecycle.test.d.ts.map +1 -0
- package/dist/core/goal-worker-dev-server-lifecycle.test.js +68 -0
- package/dist/core/goal-worker-dev-server-lifecycle.test.js.map +1 -0
- package/dist/core/goal-worker.d.ts +7 -3
- package/dist/core/goal-worker.d.ts.map +1 -1
- package/dist/core/goal-worker.js +15 -5
- package/dist/core/goal-worker.js.map +1 -1
- package/dist/core/goal-worker.test.js +19 -1
- package/dist/core/goal-worker.test.js.map +1 -1
- package/dist/core/model-registry.test.js +51 -1
- package/dist/core/model-registry.test.js.map +1 -1
- package/dist/core/process-manager-dev-server-repro.test.d.ts +2 -0
- package/dist/core/process-manager-dev-server-repro.test.d.ts.map +1 -0
- package/dist/core/process-manager-dev-server-repro.test.js +100 -0
- package/dist/core/process-manager-dev-server-repro.test.js.map +1 -0
- package/dist/core/process-manager.js +2 -2
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +2 -1
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/prompt-commands.test.js +2 -0
- package/dist/core/prompt-commands.test.js.map +1 -1
- package/dist/core/repomap.js +8 -1
- package/dist/core/repomap.js.map +1 -1
- package/dist/core/repomap.test.js +32 -0
- package/dist/core/repomap.test.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +1 -0
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +22 -12
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.js +29 -6
- package/dist/tools/edit.test.js.map +1 -1
- package/dist/ui/App.d.ts +39 -4
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +216 -147
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/app-state-persistence.test.js +80 -6
- package/dist/ui/app-state-persistence.test.js.map +1 -1
- package/dist/ui/components/GoalOverlay.d.ts +54 -1
- package/dist/ui/components/GoalOverlay.d.ts.map +1 -1
- package/dist/ui/components/GoalOverlay.js +392 -53
- package/dist/ui/components/GoalOverlay.js.map +1 -1
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +38 -1
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/InputArea.test.d.ts +2 -0
- package/dist/ui/components/InputArea.test.d.ts.map +1 -0
- package/dist/ui/components/InputArea.test.js +79 -0
- package/dist/ui/components/InputArea.test.js.map +1 -0
- package/dist/ui/components/ToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ToolExecution.js +2 -2
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/goal-events.d.ts +88 -1
- package/dist/ui/goal-events.d.ts.map +1 -1
- package/dist/ui/goal-events.js +249 -28
- package/dist/ui/goal-events.js.map +1 -1
- package/dist/ui/goal-events.test.js +89 -4
- package/dist/ui/goal-events.test.js.map +1 -1
- package/dist/ui/goal-overlay.test.js +155 -1
- package/dist/ui/goal-overlay.test.js.map +1 -1
- package/dist/ui/render.d.ts +3 -1
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +2 -0
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/scroll-stabilization.test.js +49 -2
- package/dist/ui/scroll-stabilization.test.js.map +1 -1
- package/dist/ui/slash-command-images.test.d.ts +2 -0
- package/dist/ui/slash-command-images.test.d.ts.map +1 -0
- package/dist/ui/slash-command-images.test.js +47 -0
- package/dist/ui/slash-command-images.test.js.map +1 -0
- package/package.json +5 -5
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
5
4
|
import { basename } from "node:path";
|
|
6
|
-
import {
|
|
5
|
+
import { formatGoalPrerequisiteInstruction, goalHasBlockingPrerequisites, isBlockingGoalPrerequisite, loadGoalRuns, saveGoalRuns, summarizeGoalCountsFromRuns, } from "../../core/goal-store.js";
|
|
7
6
|
import { useTerminalSize } from "../hooks/useTerminalSize.js";
|
|
8
7
|
import { useTheme } from "../theme/theme.js";
|
|
9
8
|
const GOAL_LOGO = [" ▄▀▀▀ ▄▀▀▀", " █ ▀█ █ ▀█", " ▀▄▄▀ ▀▄▄▀"];
|
|
@@ -63,10 +62,203 @@ export function formatGoalVerifierSummary(run) {
|
|
|
63
62
|
return "verifier described";
|
|
64
63
|
return "no verifier";
|
|
65
64
|
}
|
|
65
|
+
export function getGoalReadinessText(run) {
|
|
66
|
+
if (goalHasBlockingPrerequisites(run))
|
|
67
|
+
return "needs user input";
|
|
68
|
+
if (run.status === "running" || run.status === "verifying")
|
|
69
|
+
return "work in progress";
|
|
70
|
+
if (run.status === "passed")
|
|
71
|
+
return "verified";
|
|
72
|
+
if (run.verifier?.command)
|
|
73
|
+
return "ready to verify";
|
|
74
|
+
if (run.tasks.length > 0)
|
|
75
|
+
return "ready to run";
|
|
76
|
+
return "drafting plan";
|
|
77
|
+
}
|
|
78
|
+
export function formatGoalProgressText(run) {
|
|
79
|
+
const prereqTotal = run.prerequisites.length;
|
|
80
|
+
const prereqMet = run.prerequisites.filter((item) => item.status === "met").length;
|
|
81
|
+
const taskTotal = run.tasks.length;
|
|
82
|
+
const taskDone = run.tasks.filter((item) => item.status === "done").length;
|
|
83
|
+
const prereq = prereqTotal > 0 ? `prereqs ${prereqMet}/${prereqTotal}` : "no prereqs";
|
|
84
|
+
const tasks = taskTotal > 0 ? `tasks ${taskDone}/${taskTotal}` : "no tasks";
|
|
85
|
+
return `${prereq} · ${tasks}`;
|
|
86
|
+
}
|
|
66
87
|
export function getGoalStatusCountsText(runs) {
|
|
67
88
|
const counts = summarizeGoalCountsFromRuns(runs);
|
|
68
89
|
return `${counts.passed} passed · ${counts.running} running · ${counts.pending} pending · ${counts.blocked} blocked`;
|
|
69
90
|
}
|
|
91
|
+
export function clampGoalScrollOffset(offset, itemCount, viewportRows) {
|
|
92
|
+
const visibleRows = Math.max(1, Math.floor(viewportRows));
|
|
93
|
+
const maxOffset = Math.max(0, itemCount - visibleRows);
|
|
94
|
+
if (!Number.isFinite(offset))
|
|
95
|
+
return 0;
|
|
96
|
+
return Math.min(Math.max(0, Math.floor(offset)), maxOffset);
|
|
97
|
+
}
|
|
98
|
+
export function getGoalOverlayViewportRows(terminalRows, reservedRows = 8) {
|
|
99
|
+
if (!Number.isFinite(terminalRows))
|
|
100
|
+
return 8;
|
|
101
|
+
return Math.max(4, Math.floor(terminalRows) - reservedRows);
|
|
102
|
+
}
|
|
103
|
+
export function getGoalScrollOffsetForSelection({ selectedIndex, currentOffset, itemCount, viewportRows, }) {
|
|
104
|
+
const selected = clampGoalSelectedIndex(selectedIndex, itemCount);
|
|
105
|
+
const offset = clampGoalScrollOffset(currentOffset, itemCount, viewportRows);
|
|
106
|
+
const rows = Math.max(1, Math.floor(viewportRows));
|
|
107
|
+
if (selected < offset)
|
|
108
|
+
return selected;
|
|
109
|
+
if (selected >= offset + rows)
|
|
110
|
+
return clampGoalScrollOffset(selected - rows + 1, itemCount, rows);
|
|
111
|
+
return offset;
|
|
112
|
+
}
|
|
113
|
+
export function getGoalDetailRowCount(run) {
|
|
114
|
+
let count = 2;
|
|
115
|
+
count += 1 + Math.max(1, run.successCriteria.length);
|
|
116
|
+
if (run.prerequisites.length > 0) {
|
|
117
|
+
count += 1;
|
|
118
|
+
for (const prerequisite of run.prerequisites) {
|
|
119
|
+
count += 1;
|
|
120
|
+
if (isBlockingGoalPrerequisite(prerequisite) || prerequisite.evidence)
|
|
121
|
+
count += 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
count += 1;
|
|
125
|
+
if (run.tasks.length === 0) {
|
|
126
|
+
count += 1;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
for (const task of run.tasks) {
|
|
130
|
+
count += 1;
|
|
131
|
+
if (task.lastSummary)
|
|
132
|
+
count += 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (run.harness.length > 0)
|
|
136
|
+
count += 1 + run.harness.length;
|
|
137
|
+
if (run.evidencePlan.length > 0)
|
|
138
|
+
count += 1 + run.evidencePlan.length;
|
|
139
|
+
if (run.verifier)
|
|
140
|
+
count += 2;
|
|
141
|
+
if (run.blockers.length > 0)
|
|
142
|
+
count += 1 + run.blockers.length;
|
|
143
|
+
if (run.evidence.length > 0)
|
|
144
|
+
count += 1 + Math.min(5, run.evidence.length);
|
|
145
|
+
return count;
|
|
146
|
+
}
|
|
147
|
+
export function getGoalCardExtraRowCount(run) {
|
|
148
|
+
let count = 0;
|
|
149
|
+
if (goalHasBlockingPrerequisites(run))
|
|
150
|
+
count += 1;
|
|
151
|
+
else if (run.status === "running" || run.status === "verifying")
|
|
152
|
+
count += 1;
|
|
153
|
+
if (run.blockers.length > 0)
|
|
154
|
+
count += 1;
|
|
155
|
+
return count;
|
|
156
|
+
}
|
|
157
|
+
export function getGoalListCardRowCount({ run }) {
|
|
158
|
+
const compactCardRows = 1 + // title/status row
|
|
159
|
+
2 + // compact summary rows
|
|
160
|
+
getGoalCardExtraRowCount(run);
|
|
161
|
+
const marginRows = 1;
|
|
162
|
+
return compactCardRows + marginRows;
|
|
163
|
+
}
|
|
164
|
+
function compareGoalListWindows({ candidate, current, selectedIndex, }) {
|
|
165
|
+
if (!current)
|
|
166
|
+
return candidate;
|
|
167
|
+
const candidateCount = candidate.end - candidate.start;
|
|
168
|
+
const currentCount = current.end - current.start;
|
|
169
|
+
if (candidateCount !== currentCount)
|
|
170
|
+
return candidateCount > currentCount ? candidate : current;
|
|
171
|
+
if (candidate.rowsUsed !== current.rowsUsed)
|
|
172
|
+
return candidate.rowsUsed > current.rowsUsed ? candidate : current;
|
|
173
|
+
const candidateBalance = Math.abs(selectedIndex - candidate.start - (candidate.end - selectedIndex - 1));
|
|
174
|
+
const currentBalance = Math.abs(selectedIndex - current.start - (current.end - selectedIndex - 1));
|
|
175
|
+
if (candidateBalance !== currentBalance)
|
|
176
|
+
return candidateBalance < currentBalance ? candidate : current;
|
|
177
|
+
return candidate.start > current.start ? candidate : current;
|
|
178
|
+
}
|
|
179
|
+
export function getGoalListWindow({ runs, selectedIndex, viewportRows, }) {
|
|
180
|
+
const rows = Number.isFinite(viewportRows) ? Math.max(1, Math.floor(viewportRows)) : 8;
|
|
181
|
+
const fixedRows = 1;
|
|
182
|
+
if (runs.length === 0) {
|
|
183
|
+
return { start: 0, end: 0, hiddenBefore: 0, hiddenAfter: 0, rowsUsed: fixedRows };
|
|
184
|
+
}
|
|
185
|
+
const selected = clampGoalSelectedIndex(selectedIndex, runs.length);
|
|
186
|
+
let best = null;
|
|
187
|
+
for (let start = 0; start <= selected; start++) {
|
|
188
|
+
let cardRows = 0;
|
|
189
|
+
for (let end = start + 1; end <= runs.length; end++) {
|
|
190
|
+
const index = end - 1;
|
|
191
|
+
const run = runs[index];
|
|
192
|
+
if (!run)
|
|
193
|
+
continue;
|
|
194
|
+
cardRows += getGoalListCardRowCount({ run });
|
|
195
|
+
if (end <= selected)
|
|
196
|
+
continue;
|
|
197
|
+
const hiddenBefore = start;
|
|
198
|
+
const hiddenAfter = runs.length - end;
|
|
199
|
+
const indicatorRows = (hiddenBefore > 0 ? 1 : 0) + (hiddenAfter > 0 ? 1 : 0);
|
|
200
|
+
const rowsUsed = fixedRows + indicatorRows + cardRows;
|
|
201
|
+
if (rowsUsed > rows)
|
|
202
|
+
continue;
|
|
203
|
+
best = compareGoalListWindows({
|
|
204
|
+
candidate: { start, end, hiddenBefore, hiddenAfter, rowsUsed },
|
|
205
|
+
current: best,
|
|
206
|
+
selectedIndex: selected,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (best)
|
|
211
|
+
return best;
|
|
212
|
+
const start = selected;
|
|
213
|
+
const end = selected + 1;
|
|
214
|
+
const hiddenBefore = start;
|
|
215
|
+
const hiddenAfter = runs.length - end;
|
|
216
|
+
const indicatorRows = (hiddenBefore > 0 ? 1 : 0) + (hiddenAfter > 0 ? 1 : 0);
|
|
217
|
+
const run = runs[selected];
|
|
218
|
+
const cardRows = run ? getGoalListCardRowCount({ run }) : 0;
|
|
219
|
+
return {
|
|
220
|
+
start,
|
|
221
|
+
end,
|
|
222
|
+
hiddenBefore,
|
|
223
|
+
hiddenAfter,
|
|
224
|
+
rowsUsed: fixedRows + indicatorRows + cardRows,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
export function getGoalExpandedDetailViewportRows({ viewportRows, cardExtraRows, }) {
|
|
228
|
+
const rows = Number.isFinite(viewportRows) ? Math.max(1, Math.floor(viewportRows)) : 8;
|
|
229
|
+
const selectedCardRows = 1 + Math.max(0, Math.floor(cardExtraRows));
|
|
230
|
+
const fixedRows = 1 + // Goals heading
|
|
231
|
+
selectedCardRows +
|
|
232
|
+
2 + // selected card border
|
|
233
|
+
1 + // detail top margin
|
|
234
|
+
1; // selected card bottom margin
|
|
235
|
+
return Math.max(1, rows - fixedRows);
|
|
236
|
+
}
|
|
237
|
+
export function clampGoalDetailScrollOffset(offset, detailRowCount, viewportRows) {
|
|
238
|
+
const visibleRows = Math.max(1, Math.floor(viewportRows));
|
|
239
|
+
const scrolledBodyRows = Math.max(1, visibleRows - 1);
|
|
240
|
+
const maxOffset = Math.max(0, detailRowCount - scrolledBodyRows);
|
|
241
|
+
if (!Number.isFinite(offset))
|
|
242
|
+
return 0;
|
|
243
|
+
return Math.min(Math.max(0, Math.floor(offset)), maxOffset);
|
|
244
|
+
}
|
|
245
|
+
export function getGoalDetailScrollWindow({ detailRowCount, scrollOffset, viewportRows, }) {
|
|
246
|
+
const rows = Math.max(1, Math.floor(viewportRows));
|
|
247
|
+
const start = clampGoalDetailScrollOffset(scrollOffset, detailRowCount, rows);
|
|
248
|
+
const topIndicatorRows = start > 0 && rows > 2 ? 1 : 0;
|
|
249
|
+
let bodyRows = Math.max(1, rows - topIndicatorRows);
|
|
250
|
+
let hiddenAfter = Math.max(0, detailRowCount - start - bodyRows);
|
|
251
|
+
if (hiddenAfter > 0 && bodyRows > 1) {
|
|
252
|
+
bodyRows -= 1;
|
|
253
|
+
hiddenAfter = Math.max(0, detailRowCount - start - bodyRows);
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
start,
|
|
257
|
+
end: Math.min(detailRowCount, start + bodyRows),
|
|
258
|
+
hiddenBefore: start,
|
|
259
|
+
hiddenAfter,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
70
262
|
export function sortGoalRunsForOverlay(runs) {
|
|
71
263
|
return [...runs].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
72
264
|
}
|
|
@@ -116,6 +308,21 @@ function statusColor(status) {
|
|
|
116
308
|
return "";
|
|
117
309
|
}
|
|
118
310
|
}
|
|
311
|
+
export function getGoalCardStatusColor({ status, selected, primaryColor, textColor, }) {
|
|
312
|
+
return statusColor(status) || (selected ? primaryColor : textColor);
|
|
313
|
+
}
|
|
314
|
+
export function getGoalCardTitleColor({ selected, primaryColor, textColor, }) {
|
|
315
|
+
return selected ? primaryColor : textColor;
|
|
316
|
+
}
|
|
317
|
+
function verifierSummaryColor(run, fallbackColor) {
|
|
318
|
+
if (run.verifier?.lastResult)
|
|
319
|
+
return verifierStatusColor(run.verifier.lastResult.status);
|
|
320
|
+
if (run.verifier?.command)
|
|
321
|
+
return "cyan";
|
|
322
|
+
if (run.verifier?.description)
|
|
323
|
+
return "magenta";
|
|
324
|
+
return fallbackColor;
|
|
325
|
+
}
|
|
119
326
|
function taskStatusColor(status) {
|
|
120
327
|
switch (status) {
|
|
121
328
|
case "done":
|
|
@@ -141,6 +348,40 @@ function prerequisiteStatusColor(status) {
|
|
|
141
348
|
return "cyan";
|
|
142
349
|
}
|
|
143
350
|
}
|
|
351
|
+
function evidencePlanStatusColor(status) {
|
|
352
|
+
switch (status) {
|
|
353
|
+
case "ready":
|
|
354
|
+
return "green";
|
|
355
|
+
case "blocked":
|
|
356
|
+
return "yellow";
|
|
357
|
+
case "planned":
|
|
358
|
+
return "cyan";
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function verifierStatusColor(status) {
|
|
362
|
+
switch (status) {
|
|
363
|
+
case "pass":
|
|
364
|
+
return "green";
|
|
365
|
+
case "fail":
|
|
366
|
+
return "red";
|
|
367
|
+
case "unknown":
|
|
368
|
+
return "yellow";
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function evidenceKindColor(kind) {
|
|
372
|
+
switch (kind) {
|
|
373
|
+
case "command":
|
|
374
|
+
return "cyan";
|
|
375
|
+
case "file":
|
|
376
|
+
return "blue";
|
|
377
|
+
case "log":
|
|
378
|
+
return "yellow";
|
|
379
|
+
case "screenshot":
|
|
380
|
+
return "magenta";
|
|
381
|
+
case "summary":
|
|
382
|
+
return "green";
|
|
383
|
+
}
|
|
384
|
+
}
|
|
144
385
|
export function getGoalDetailTaskHeading(run) {
|
|
145
386
|
return run.prerequisites.length > 0 ? "2. Worker tasks" : "Worker tasks";
|
|
146
387
|
}
|
|
@@ -156,6 +397,10 @@ export function formatGoalTaskDetailSummary(summary) {
|
|
|
156
397
|
return "";
|
|
157
398
|
return firstLine.length > 180 ? `${firstLine.slice(0, 177)}…` : firstLine;
|
|
158
399
|
}
|
|
400
|
+
function truncateGoalDetailText(text, maxLength = 220) {
|
|
401
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
402
|
+
return collapsed.length > maxLength ? `${collapsed.slice(0, maxLength - 1)}…` : collapsed;
|
|
403
|
+
}
|
|
159
404
|
function GoalHeader({ cwd, runs, agentRunning, }) {
|
|
160
405
|
const theme = useTheme();
|
|
161
406
|
const { columns } = useTerminalSize();
|
|
@@ -166,11 +411,83 @@ function GoalHeader({ cwd, runs, agentRunning, }) {
|
|
|
166
411
|
}
|
|
167
412
|
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, width: columns, children: [_jsxs(Box, { children: [_jsx(GoalGradientText, { text: GOAL_LOGO[0] }), _jsx(Text, { children: GAP }), _jsx(Text, { color: GOAL_SUCCESS, bold: true, children: "Goal Pane" }), agentRunning && _jsx(Text, { color: GOAL_ACTIVE, children: " (agent running)" })] }), _jsxs(Box, { children: [_jsx(GoalGradientText, { text: GOAL_LOGO[1] }), _jsx(Text, { children: GAP }), _jsx(Text, { color: theme.textDim, wrap: "truncate", children: displayPath })] }), _jsxs(Box, { children: [_jsx(GoalGradientText, { text: GOAL_LOGO[2] }), _jsx(Text, { children: GAP }), _jsxs(Text, { children: [_jsxs(Text, { color: GOAL_SUCCESS, children: [counts.passed, " passed"] }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsxs(Text, { color: GOAL_ACTIVE, children: [counts.running, " active"] }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsxs(Text, { color: theme.text, children: [counts.pending, " pending"] }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsxs(Text, { color: GOAL_ACTIVE, children: [counts.blocked, " blocked"] })] })] })] }));
|
|
168
413
|
}
|
|
169
|
-
function
|
|
414
|
+
function StatusChip({ label, color }) {
|
|
415
|
+
return (_jsxs(Text, { color: color, bold: true, children: ["\u25D6 ", label, " \u25D7"] }));
|
|
416
|
+
}
|
|
417
|
+
function GoalDetail({ run, maxRows, scrollOffset, }) {
|
|
170
418
|
const theme = useTheme();
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
419
|
+
const rows = [
|
|
420
|
+
_jsxs(Text, { children: [_jsx(Text, { color: theme.primary, bold: true, children: "Goal" }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsx(Text, { color: statusColor(run.status) || theme.secondary, children: getGoalReadinessText(run) }), _jsxs(Text, { color: theme.textDim, children: [" \u00B7 ", formatGoalProgressText(run)] })] }, "goal-heading"),
|
|
421
|
+
_jsx(Text, { color: theme.text, children: truncateGoalDetailText(run.goal || run.title) }, "goal-text"),
|
|
422
|
+
_jsx(Text, { color: theme.primary, bold: true, children: "Success criteria" }, "success-heading"),
|
|
423
|
+
];
|
|
424
|
+
if (run.successCriteria.length === 0) {
|
|
425
|
+
rows.push(_jsx(Text, { color: theme.textDim, children: "- none recorded" }, "success-none"));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
for (const [index, criterion] of run.successCriteria.entries()) {
|
|
429
|
+
rows.push(_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "\u2713 " }), _jsx(Text, { color: theme.text, children: truncateGoalDetailText(criterion) })] }, `success-${index}`));
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (run.prerequisites.length > 0) {
|
|
433
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: getGoalUserPrerequisiteHeading(run) }, "prereq-heading"));
|
|
434
|
+
for (const prerequisite of run.prerequisites) {
|
|
435
|
+
rows.push(_jsxs(Text, { children: [_jsxs(Text, { color: prerequisiteStatusColor(prerequisite.status), children: ["\u25CF ", prerequisite.status] }), _jsxs(Text, { color: theme.text, bold: isBlockingGoalPrerequisite(prerequisite), children: [" ", prerequisite.label] }), isBlockingGoalPrerequisite(prerequisite) ? (_jsx(Text, { color: theme.warning, children: " \u00B7 user action required" })) : null] }, `prereq-${prerequisite.id}`));
|
|
436
|
+
if (isBlockingGoalPrerequisite(prerequisite)) {
|
|
437
|
+
rows.push(_jsxs(Text, { color: theme.textDim, wrap: "truncate", children: ["\u2514\u2500 ", formatGoalPrerequisiteInstruction(prerequisite)] }, `prereq-${prerequisite.id}-instruction`));
|
|
438
|
+
}
|
|
439
|
+
else if (prerequisite.evidence) {
|
|
440
|
+
rows.push(_jsxs(Text, { color: theme.textDim, wrap: "truncate", children: ["\u2514\u2500 ", prerequisite.evidence] }, `prereq-${prerequisite.id}-evidence`));
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: getGoalDetailTaskHeading(run) }, "task-heading"));
|
|
445
|
+
if (run.tasks.length === 0) {
|
|
446
|
+
rows.push(_jsx(Text, { color: theme.textDim, children: goalHasBlockingPrerequisites(run)
|
|
447
|
+
? "⏸ Waiting for prerequisites before workers can start."
|
|
448
|
+
: "✨ No worker tasks yet — run the goal to generate focused work." }, "no-tasks"));
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
for (const task of run.tasks) {
|
|
452
|
+
rows.push(_jsxs(Text, { children: [_jsxs(Text, { color: taskStatusColor(task.status), children: ["\u25CF ", task.status] }), _jsxs(Text, { color: theme.text, children: [" ", task.title] }), _jsxs(Text, { color: theme.textDim, children: [" \u00B7 try ", task.attempts] }), task.workerId ? _jsxs(Text, { color: theme.textDim, children: [" \u00B7 ", task.workerId] }) : null] }, `task-${task.id}`));
|
|
453
|
+
if (task.lastSummary) {
|
|
454
|
+
rows.push(_jsxs(Text, { color: theme.textDim, wrap: "truncate", children: ["\u2514\u2500 ", formatGoalTaskDetailSummary(task.lastSummary)] }, `task-${task.id}-summary`));
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (run.harness.length > 0) {
|
|
459
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: "Harness" }, "harness-heading"));
|
|
460
|
+
for (const item of run.harness) {
|
|
461
|
+
rows.push(_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: "\u25E6 " }), _jsx(Text, { color: theme.text, children: item.label }), item.command ? _jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", item.command] }) : null, !item.command && item.path ? _jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", item.path] }) : null] }, `harness-${item.id}`));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (run.evidencePlan.length > 0) {
|
|
465
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: "Evidence plan" }, "evidence-plan-heading"));
|
|
466
|
+
for (const item of run.evidencePlan) {
|
|
467
|
+
rows.push(_jsxs(Text, { children: [_jsxs(Text, { color: evidencePlanStatusColor(item.status), children: ["\u25CF ", item.status] }), _jsxs(Text, { color: theme.text, children: [" \u00B7 ", item.label] }), item.command ? _jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", item.command] }) : null, !item.command && item.path ? _jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", item.path] }) : null] }, `evidence-plan-${item.id}`));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (run.verifier) {
|
|
471
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: "Verifier" }, "verifier-heading"), _jsxs(Text, { wrap: "truncate", children: [run.verifier.lastResult ? (_jsxs(Text, { color: verifierStatusColor(run.verifier.lastResult.status), children: ["\u25CF ", formatGoalVerifierSummary(run)] })) : (_jsxs(Text, { color: run.verifier.command ? "cyan" : theme.textDim, children: ["\u25CF ", formatGoalVerifierSummary(run)] })), run.verifier.command ? (_jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", run.verifier.command] })) : null] }, "verifier-summary"));
|
|
472
|
+
}
|
|
473
|
+
if (run.blockers.length > 0) {
|
|
474
|
+
rows.push(_jsx(Text, { color: theme.warning, bold: true, children: "Blockers" }, "blockers-heading"));
|
|
475
|
+
for (const [index, blocker] of run.blockers.entries()) {
|
|
476
|
+
rows.push(_jsxs(Text, { color: theme.warning, children: ["- ", truncateGoalDetailText(blocker)] }, `blocker-${index}`));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (run.evidence.length > 0) {
|
|
480
|
+
rows.push(_jsx(Text, { color: theme.primary, bold: true, children: "Recent evidence" }, "evidence-heading"));
|
|
481
|
+
for (const item of run.evidence.slice(-5)) {
|
|
482
|
+
rows.push(_jsxs(Text, { children: [_jsxs(Text, { color: evidenceKindColor(item.kind), children: ["[", item.kind, "]"] }), _jsxs(Text, { color: theme.text, children: [" ", item.label] }), item.path ? _jsxs(Text, { color: theme.secondary, children: [" \u00B7 ", item.path] }) : null] }, `evidence-${item.id}`));
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const window = getGoalDetailScrollWindow({
|
|
486
|
+
detailRowCount: rows.length,
|
|
487
|
+
scrollOffset,
|
|
488
|
+
viewportRows: maxRows,
|
|
489
|
+
});
|
|
490
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, height: maxRows, overflowY: "hidden", children: [window.hiddenBefore > 0 ? (_jsxs(Text, { color: theme.secondary, children: ["\u2191 ", window.hiddenBefore, " detail row(s) above \u00B7 PgUp"] })) : null, rows.slice(window.start, window.end), window.hiddenAfter > 0 ? (_jsxs(Text, { color: theme.secondary, children: ["\u2193 ", window.hiddenAfter, " more detail row(s) \u00B7 PgDn"] })) : null] }));
|
|
174
491
|
}
|
|
175
492
|
export function GoalOverlay({ cwd, onClose, onRunGoal, onVerifyGoal, onPauseGoal, agentRunning, }) {
|
|
176
493
|
const theme = useTheme();
|
|
@@ -179,8 +496,8 @@ export function GoalOverlay({ cwd, onClose, onRunGoal, onVerifyGoal, onPauseGoal
|
|
|
179
496
|
const [loaded, setLoaded] = useState(false);
|
|
180
497
|
const [expandedRunId, setExpandedRunId] = useState(null);
|
|
181
498
|
const [mode, setMode] = useState("normal");
|
|
182
|
-
const [inputText, setInputText] = useState("");
|
|
183
499
|
const [status, setStatus] = useState("");
|
|
500
|
+
const [detailScrollOffset, setDetailScrollOffset] = useState(0);
|
|
184
501
|
const statusTimer = useRef(null);
|
|
185
502
|
const saveTimer = useRef(null);
|
|
186
503
|
const lastPersistedRunsRef = useRef([]);
|
|
@@ -235,46 +552,39 @@ export function GoalOverlay({ cwd, onClose, onRunGoal, onVerifyGoal, onPauseGoal
|
|
|
235
552
|
void saveGoalRuns(cwd, runs);
|
|
236
553
|
}, 100);
|
|
237
554
|
}, [cwd, loaded, runs]);
|
|
555
|
+
const { rows } = useTerminalSize();
|
|
556
|
+
const viewportRows = getGoalOverlayViewportRows(rows);
|
|
238
557
|
const selectedRun = runs[selectedIndex];
|
|
239
558
|
const expandedRun = selectedRun && selectedRun.id === expandedRunId ? selectedRun : null;
|
|
559
|
+
const selectedCardExtraRows = selectedRun ? getGoalCardExtraRowCount(selectedRun) : 0;
|
|
560
|
+
const expandedCardExtraRows = expandedRun ? selectedCardExtraRows : 0;
|
|
561
|
+
const detailViewportRows = expandedRun
|
|
562
|
+
? getGoalExpandedDetailViewportRows({
|
|
563
|
+
viewportRows,
|
|
564
|
+
cardExtraRows: expandedCardExtraRows,
|
|
565
|
+
})
|
|
566
|
+
: 0;
|
|
567
|
+
const listWindow = expandedRun
|
|
568
|
+
? null
|
|
569
|
+
: getGoalListWindow({
|
|
570
|
+
runs,
|
|
571
|
+
selectedIndex,
|
|
572
|
+
viewportRows,
|
|
573
|
+
});
|
|
574
|
+
const scrollOffset = expandedRun ? selectedIndex : (listWindow?.start ?? 0);
|
|
575
|
+
const visibleRuns = expandedRun
|
|
576
|
+
? [expandedRun]
|
|
577
|
+
: runs.slice(listWindow?.start ?? 0, listWindow?.end ?? 0);
|
|
578
|
+
const hiddenBefore = expandedRun ? 0 : (listWindow?.hiddenBefore ?? 0);
|
|
579
|
+
const hiddenAfter = expandedRun ? 0 : (listWindow?.hiddenAfter ?? 0);
|
|
580
|
+
const detailRowCount = expandedRun ? getGoalDetailRowCount(expandedRun) : 0;
|
|
581
|
+
useEffect(() => {
|
|
582
|
+
setDetailScrollOffset(0);
|
|
583
|
+
}, [expandedRunId]);
|
|
584
|
+
useEffect(() => {
|
|
585
|
+
setDetailScrollOffset((offset) => clampGoalDetailScrollOffset(offset, detailRowCount, detailViewportRows));
|
|
586
|
+
}, [detailRowCount, detailViewportRows]);
|
|
240
587
|
useInput((input, key) => {
|
|
241
|
-
if (mode === "adding") {
|
|
242
|
-
if (key.escape) {
|
|
243
|
-
setMode("normal");
|
|
244
|
-
setInputText("");
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
if (key.return) {
|
|
248
|
-
const text = inputText.trim();
|
|
249
|
-
if (text) {
|
|
250
|
-
const run = createGoalRun(cwd, {
|
|
251
|
-
id: randomUUID(),
|
|
252
|
-
title: text.slice(0, 80),
|
|
253
|
-
goal: text,
|
|
254
|
-
status: "draft",
|
|
255
|
-
successCriteria: [],
|
|
256
|
-
prerequisites: [],
|
|
257
|
-
harness: [],
|
|
258
|
-
tasks: [],
|
|
259
|
-
evidence: [],
|
|
260
|
-
blockers: [],
|
|
261
|
-
});
|
|
262
|
-
setRuns((previousRuns) => sortGoalRunsForOverlay([run, ...previousRuns]));
|
|
263
|
-
setSelectedIndex(0);
|
|
264
|
-
showStatus("Draft goal added");
|
|
265
|
-
}
|
|
266
|
-
setMode("normal");
|
|
267
|
-
setInputText("");
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (key.backspace || key.delete) {
|
|
271
|
-
setInputText((previous) => previous.slice(0, -1));
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
if (input && !key.ctrl && !key.meta)
|
|
275
|
-
setInputText((previous) => previous + input);
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
588
|
if (mode === "confirmDelete") {
|
|
279
589
|
if (key.escape || input === "n") {
|
|
280
590
|
setMode("normal");
|
|
@@ -293,6 +603,30 @@ export function GoalOverlay({ cwd, onClose, onRunGoal, onVerifyGoal, onPauseGoal
|
|
|
293
603
|
onClose();
|
|
294
604
|
return;
|
|
295
605
|
}
|
|
606
|
+
if (expandedRun && (key.pageUp || input === "[")) {
|
|
607
|
+
setDetailScrollOffset((offset) => clampGoalDetailScrollOffset(offset - Math.max(1, detailViewportRows - 1), detailRowCount, detailViewportRows));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (expandedRun && (key.pageDown || input === "]")) {
|
|
611
|
+
setDetailScrollOffset((offset) => clampGoalDetailScrollOffset(offset + Math.max(1, detailViewportRows - 1), detailRowCount, detailViewportRows));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
if (expandedRun && key.home) {
|
|
615
|
+
setDetailScrollOffset(0);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (expandedRun && key.end) {
|
|
619
|
+
setDetailScrollOffset(clampGoalDetailScrollOffset(detailRowCount, detailRowCount, detailViewportRows));
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (expandedRun && (key.upArrow || input === "k")) {
|
|
623
|
+
setDetailScrollOffset((offset) => clampGoalDetailScrollOffset(offset - 1, detailRowCount, detailViewportRows));
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
if (expandedRun && (key.downArrow || input === "j")) {
|
|
627
|
+
setDetailScrollOffset((offset) => clampGoalDetailScrollOffset(offset + 1, detailRowCount, detailViewportRows));
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
296
630
|
if (key.upArrow || input === "k") {
|
|
297
631
|
setSelectedIndex((index) => clampGoalSelectedIndex(index - 1, runs.length));
|
|
298
632
|
return;
|
|
@@ -317,20 +651,25 @@ export function GoalOverlay({ cwd, onClose, onRunGoal, onVerifyGoal, onPauseGoal
|
|
|
317
651
|
onPauseGoal(selectedRun);
|
|
318
652
|
return;
|
|
319
653
|
}
|
|
320
|
-
if (input === "a") {
|
|
321
|
-
setMode("adding");
|
|
322
|
-
setInputText("");
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
654
|
if (input === "x" && selectedRun) {
|
|
326
655
|
setMode("confirmDelete");
|
|
327
656
|
showStatus("Archive goal? y/n");
|
|
328
657
|
}
|
|
329
658
|
});
|
|
330
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(GoalHeader, { cwd: cwd, runs: runs, agentRunning: agentRunning }), agentRunning ? (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: theme.textDim, children: "Agent is running; Goal pane stays available without resetting chat." }) })) : null, !loaded ? (_jsx(Text, { color: theme.textDim, children: "Loading goals\u2026" })) : runs.length === 0 ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: theme.textDim, children: "No goals.
|
|
659
|
+
return (_jsxs(Box, { flexDirection: "column", height: rows, overflow: "hidden", children: [_jsx(GoalHeader, { cwd: cwd, runs: runs, agentRunning: agentRunning }), agentRunning ? (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: theme.textDim, children: "Agent is running; Goal pane stays available without resetting chat." }) })) : null, !loaded ? (_jsx(Box, { borderStyle: "round", borderColor: theme.textDim, paddingX: 1, children: _jsx(Text, { color: theme.textDim, children: "Loading goals\u2026" }) })) : runs.length === 0 ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: theme.primary, paddingX: 1, paddingY: 1, children: [_jsx(Text, { color: theme.primary, bold: true, children: "Start a durable Goal run" }), _jsx(Text, { color: theme.textDim, children: "No goals yet. Ask the agent to start a durable Goal." }), _jsx(Text, { color: theme.textDim, children: "Prerequisites, worker tasks, evidence, and verifier results will appear in this pane." })] })) : (_jsxs(Box, { flexDirection: "column", height: viewportRows, overflowY: "hidden", children: [_jsx(Text, { color: theme.textDim, bold: true, children: "Goals" }), hiddenBefore > 0 ? (_jsxs(Text, { color: theme.textDim, children: ["\u2191 ", hiddenBefore, " earlier goal", hiddenBefore === 1 ? "" : "s"] })) : null, visibleRuns.map((run, visibleIndex) => {
|
|
660
|
+
const index = scrollOffset + visibleIndex;
|
|
331
661
|
const selected = index === selectedIndex;
|
|
332
662
|
const blocked = goalHasBlockingPrerequisites(run);
|
|
333
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1,
|
|
334
|
-
|
|
663
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, borderStyle: expandedRun?.id === run.id ? "round" : undefined, borderColor: expandedRun?.id === run.id ? theme.primary : undefined, paddingX: expandedRun?.id === run.id ? 1 : 0, children: [_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: selected ? theme.primary : theme.textDim, children: selected ? "❯ " : " " }), _jsx(StatusChip, { label: run.status, color: getGoalCardStatusColor({
|
|
664
|
+
status: run.status,
|
|
665
|
+
selected,
|
|
666
|
+
primaryColor: theme.primary,
|
|
667
|
+
textColor: theme.text,
|
|
668
|
+
}) }), _jsxs(Text, { color: getGoalCardTitleColor({
|
|
669
|
+
selected,
|
|
670
|
+
primaryColor: theme.primary,
|
|
671
|
+
textColor: theme.text,
|
|
672
|
+
}), bold: selected, children: [" ", run.title] }), _jsxs(Text, { color: theme.textDim, children: [" \u00B7 ", run.id.slice(0, 8)] })] }), expandedRun?.id === run.id ? null : (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: theme.textDim, children: selected ? " " : " " }), _jsx(Text, { color: statusColor(run.status) || theme.secondary, children: getGoalReadinessText(run) }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsx(Text, { color: theme.text, children: formatGoalProgressText(run) }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsx(Text, { color: verifierSummaryColor(run, theme.textDim), children: formatGoalVerifierSummary(run) })] }), _jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: theme.textDim, children: selected ? " " : " " }), _jsx(Text, { color: goalHasBlockingPrerequisites(run) ? theme.warning : GOAL_SUCCESS, children: formatGoalPrerequisiteSummary(run) }), _jsx(Text, { color: theme.textDim, children: " \u00B7 " }), _jsx(Text, { color: run.tasks.length > 0 ? GOAL_SUCCESS : theme.text, children: formatGoalTaskSummary(run) })] })] })), blocked ? (_jsxs(Text, { color: theme.warning, wrap: "truncate", children: [selected ? " " : " ", "\u26A0 prerequisite needed before workers continue"] })) : run.status === "running" || run.status === "verifying" ? (_jsxs(Text, { color: GOAL_ACTIVE, wrap: "truncate", children: [selected ? " " : " ", "\u25CF active \u2014 watching worker/verifier progress"] })) : null, run.blockers.length > 0 ? (_jsxs(Text, { color: theme.warning, wrap: "truncate", children: [selected ? " " : " ", "blocker: ", run.blockers[0]] })) : null, expandedRun?.id === run.id ? (_jsx(GoalDetail, { run: run, maxRows: detailViewportRows, scrollOffset: detailScrollOffset })) : null] }, run.id));
|
|
673
|
+
}), hiddenAfter > 0 ? (_jsxs(Text, { color: theme.textDim, children: ["\u2193 ", hiddenAfter, " later goal", hiddenAfter === 1 ? "" : "s"] })) : null] })), _jsx(Box, { marginTop: 1, children: mode === "confirmDelete" ? (_jsx(Text, { color: theme.warning, children: "Confirm archive selected goal: y/n" })) : (_jsxs(Text, { color: theme.textDim, children: [_jsx(Text, { color: theme.primary, children: "\u2191\u2193/jk" }), expandedRun ? " scroll detail · " : " select · ", _jsx(Text, { color: theme.primary, children: "Enter/d" }), expandedRun ? " close detail · " : " detail · ", expandedRun ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.primary, children: "PgUp/PgDn" }), " page detail · "] })) : null, _jsx(Text, { color: theme.primary, children: "r" }), " run · ", _jsx(Text, { color: theme.primary, children: "v" }), " verify · ", _jsx(Text, { color: theme.primary, children: "p" }), " pause · ", _jsx(Text, { color: theme.primary, children: "x" }), " archive · ", _jsx(Text, { color: theme.primary, children: "Esc" }), " close"] })) }), status ? (_jsx(Box, { children: _jsx(Text, { color: theme.secondary, children: status }) })) : null] }));
|
|
335
674
|
}
|
|
336
675
|
//# sourceMappingURL=GoalOverlay.js.map
|