@kenkaiiii/ggcoder 4.3.210 → 4.3.212
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/core/goal-prerequisites.d.ts +18 -0
- package/dist/core/goal-prerequisites.d.ts.map +1 -0
- package/dist/core/goal-prerequisites.js +77 -0
- package/dist/core/goal-prerequisites.js.map +1 -0
- package/dist/core/goal-prerequisites.test.d.ts +2 -0
- package/dist/core/goal-prerequisites.test.d.ts.map +1 -0
- package/dist/core/goal-prerequisites.test.js +90 -0
- package/dist/core/goal-prerequisites.test.js.map +1 -0
- package/dist/core/goal-store.d.ts.map +1 -1
- package/dist/core/goal-store.js +11 -2
- package/dist/core/goal-store.js.map +1 -1
- package/dist/core/goal-store.test.js +14 -6
- package/dist/core/goal-store.test.js.map +1 -1
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +5 -4
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/prompt-commands.test.js +4 -0
- package/dist/core/prompt-commands.test.js.map +1 -1
- package/dist/tools/goals.d.ts.map +1 -1
- package/dist/tools/goals.js +49 -9
- package/dist/tools/goals.js.map +1 -1
- package/dist/tools/goals.test.js +43 -0
- package/dist/tools/goals.test.js.map +1 -1
- package/dist/ui/App.d.ts +12 -2
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +73 -63
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/app-state-persistence.test.js +8 -8
- package/dist/ui/app-state-persistence.test.js.map +1 -1
- package/dist/ui/goal-lifecycle-orchestration.test.js +19 -28
- package/dist/ui/goal-lifecycle-orchestration.test.js.map +1 -1
- package/dist/ui/goal-overlay.test.js +1 -1
- package/dist/ui/goal-overlay.test.js.map +1 -1
- package/package.json +5 -5
package/dist/ui/App.js
CHANGED
|
@@ -61,6 +61,7 @@ import { getMCPServers } from "../core/mcp/index.js";
|
|
|
61
61
|
import { trimFlushedItems, flushOnTurnText, flushOnTurnEnd, flushOverflow, } from "./live-item-flush.js";
|
|
62
62
|
import { appendGoalDecision, appendGoalEvidence, formatGoalBlockingPrerequisites, goalHasBlockingPrerequisites, loadGoalRuns, reconcileActiveGoalRuns, summarizeGoalCounts, summarizeGoalCountsFromRuns, updateGoalTask, upsertGoalRun, } from "../core/goal-store.js";
|
|
63
63
|
import { canCompleteGoalRun, decideGoalNextAction } from "../core/goal-controller.js";
|
|
64
|
+
import { runGoalPrerequisiteChecks } from "../core/goal-prerequisites.js";
|
|
64
65
|
import { runGoalVerifierCommand } from "../core/goal-verifier.js";
|
|
65
66
|
import { listGoalWorkers, startGoalWorker, stopGoalWorker, subscribeGoalWorkerCompletions, } from "../core/goal-worker.js";
|
|
66
67
|
import { formatGoalVerifierCompletionEvent, formatGoalWorkerCompletionEvent, isGoalSyntheticEvent, parseGoalSyntheticEvent, } from "./goal-events.js";
|
|
@@ -266,6 +267,16 @@ function goalProgressMatchesDraft(item, draft) {
|
|
|
266
267
|
item.status === draft.status &&
|
|
267
268
|
JSON.stringify(item.summaryRows ?? []) === JSON.stringify(draft.summaryRows ?? []));
|
|
268
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Reconcile terminal Goal cards that are already visible in this UI session.
|
|
272
|
+
*
|
|
273
|
+
* This intentionally does not synthesize missing cards from durable GoalRun
|
|
274
|
+
* state. Goal terminal cards are event notifications: they should appear when
|
|
275
|
+
* the terminal event happens in the current UI, not whenever a fresh session
|
|
276
|
+
* polls old Goal runs from the Goal pane. Callers that just observed a terminal
|
|
277
|
+
* event append that card first, then use this helper to tombstone stale older
|
|
278
|
+
* cards for the same run.
|
|
279
|
+
*/
|
|
269
280
|
export function completedItemsWithDurableGoalTerminalProgress(items, runs) {
|
|
270
281
|
const runIds = new Set(runs.map((run) => run.id));
|
|
271
282
|
const terminalByRun = new Map(runs
|
|
@@ -273,29 +284,18 @@ export function completedItemsWithDurableGoalTerminalProgress(items, runs) {
|
|
|
273
284
|
.filter((entry) => entry[1] !== null));
|
|
274
285
|
if (runIds.size === 0)
|
|
275
286
|
return items;
|
|
276
|
-
const upToDateRunIds = new Set();
|
|
277
287
|
let changed = false;
|
|
278
288
|
const reconciled = items.map((item, index) => {
|
|
279
289
|
const runId = goalTerminalRunIdFromItem(item);
|
|
280
290
|
if (!runId || !runIds.has(runId))
|
|
281
291
|
return item;
|
|
282
292
|
const draft = terminalByRun.get(runId);
|
|
283
|
-
if (draft && goalProgressMatchesDraft(item, draft))
|
|
284
|
-
upToDateRunIds.add(runId);
|
|
293
|
+
if (draft && goalProgressMatchesDraft(item, draft))
|
|
285
294
|
return item;
|
|
286
|
-
}
|
|
287
295
|
changed = true;
|
|
288
296
|
return { kind: "tombstone", id: `tombstone-${item.id}-${index}` };
|
|
289
297
|
});
|
|
290
|
-
|
|
291
|
-
for (const [runId, progress] of terminalByRun) {
|
|
292
|
-
if (upToDateRunIds.has(runId))
|
|
293
|
-
continue;
|
|
294
|
-
additions.push({ ...progress, id: goalTerminalProgressId({ id: runId }) });
|
|
295
|
-
}
|
|
296
|
-
if (!changed && additions.length === 0)
|
|
297
|
-
return items;
|
|
298
|
-
return [...reconciled, ...additions];
|
|
298
|
+
return changed ? reconciled : items;
|
|
299
299
|
}
|
|
300
300
|
export function formatGoalTerminalProgress(run) {
|
|
301
301
|
switch (run.status) {
|
|
@@ -344,17 +344,16 @@ export function formatGoalTerminalProgress(run) {
|
|
|
344
344
|
return null;
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
-
export function shouldHideHistoryForOverlayView(
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
return false;
|
|
347
|
+
export function shouldHideHistoryForOverlayView(isOverlayView, _isAgentRunning) {
|
|
348
|
+
// Overlay panes are standalone full-screen states. Do not render chat Static
|
|
349
|
+
// history behind them, otherwise panes appear below the previous transcript.
|
|
350
|
+
return isOverlayView;
|
|
352
351
|
}
|
|
353
352
|
export function shouldStabilizeOverlayPaneRerender({ overlayPane, isAgentRunning, }) {
|
|
354
353
|
return isAgentRunning && (overlayPane === "goal" || overlayPane === "plan");
|
|
355
354
|
}
|
|
356
|
-
export function shouldHideStaticItemsForOverlayView({ shouldHideHistoryForOverlay, stabilizeOverlayPaneRerender, }) {
|
|
357
|
-
return shouldHideHistoryForOverlay
|
|
355
|
+
export function shouldHideStaticItemsForOverlayView({ shouldHideHistoryForOverlay, stabilizeOverlayPaneRerender: _stabilizeOverlayPaneRerender, }) {
|
|
356
|
+
return shouldHideHistoryForOverlay;
|
|
358
357
|
}
|
|
359
358
|
export function getScrollStabilizationDecision({ isUserScrolled, hasNewOutput, hasTallLiveUserMessage = false, }) {
|
|
360
359
|
const shouldStabilize = isUserScrolled || hasTallLiveUserMessage;
|
|
@@ -2953,111 +2952,121 @@ export function App(props) {
|
|
|
2953
2952
|
const startGoalRun = useCallback((run) => {
|
|
2954
2953
|
runningGoalIdsRef.current.add(run.id);
|
|
2955
2954
|
void (async () => {
|
|
2956
|
-
|
|
2955
|
+
const currentRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === run.id) ?? run;
|
|
2956
|
+
const prereqCheck = await runGoalPrerequisiteChecks(props.cwd, currentRun);
|
|
2957
|
+
const checkedRun = prereqCheck.checkedCount > 0
|
|
2958
|
+
? await upsertGoalRun(props.cwd, {
|
|
2959
|
+
...prereqCheck.run,
|
|
2960
|
+
status: goalHasBlockingPrerequisites(prereqCheck.run) ? "blocked" : "ready",
|
|
2961
|
+
})
|
|
2962
|
+
: currentRun;
|
|
2963
|
+
if (goalHasBlockingPrerequisites(checkedRun)) {
|
|
2957
2964
|
setOverlay(null);
|
|
2958
|
-
const detail = formatGoalBlockingPrerequisites(
|
|
2965
|
+
const detail = formatGoalBlockingPrerequisites(checkedRun);
|
|
2959
2966
|
await upsertGoalRun(props.cwd, {
|
|
2960
|
-
...
|
|
2967
|
+
...checkedRun,
|
|
2961
2968
|
status: "blocked",
|
|
2962
|
-
blockers: Array.from(new Set([...
|
|
2969
|
+
blockers: Array.from(new Set([...checkedRun.blockers, detail])),
|
|
2963
2970
|
});
|
|
2964
2971
|
setGoalCount((await summarizeGoalCounts(props.cwd)).active);
|
|
2965
2972
|
appendGoalProgress({
|
|
2966
2973
|
kind: "goal_progress",
|
|
2967
2974
|
phase: "terminal",
|
|
2968
|
-
title: `Goal blocked: ${
|
|
2975
|
+
title: `Goal blocked: ${checkedRun.title}`,
|
|
2969
2976
|
detail,
|
|
2970
2977
|
status: "blocked",
|
|
2971
2978
|
});
|
|
2972
|
-
runningGoalIdsRef.current.delete(
|
|
2973
|
-
clearGoalStatusEntry(
|
|
2979
|
+
runningGoalIdsRef.current.delete(checkedRun.id);
|
|
2980
|
+
clearGoalStatusEntry(checkedRun.id);
|
|
2974
2981
|
return;
|
|
2975
2982
|
}
|
|
2976
|
-
const decision = decideGoalNextAction(
|
|
2977
|
-
await appendGoalDecision(props.cwd,
|
|
2983
|
+
const decision = decideGoalNextAction(checkedRun);
|
|
2984
|
+
await appendGoalDecision(props.cwd, checkedRun.id, decision);
|
|
2978
2985
|
if (decision.kind === "terminal") {
|
|
2979
|
-
const terminalProgress = formatGoalTerminalProgress(
|
|
2986
|
+
const terminalProgress = formatGoalTerminalProgress(checkedRun);
|
|
2980
2987
|
if (terminalProgress) {
|
|
2981
|
-
const item = { ...terminalProgress, id: goalTerminalProgressId(
|
|
2982
|
-
setLiveItems((prev) => completedItemsWithDurableGoalTerminalProgress([...prev, item], [
|
|
2988
|
+
const item = { ...terminalProgress, id: goalTerminalProgressId(checkedRun) };
|
|
2989
|
+
setLiveItems((prev) => completedItemsWithDurableGoalTerminalProgress([...prev, item], [checkedRun]));
|
|
2983
2990
|
}
|
|
2984
|
-
runningGoalIdsRef.current.delete(
|
|
2985
|
-
clearGoalStatusEntry(
|
|
2991
|
+
runningGoalIdsRef.current.delete(checkedRun.id);
|
|
2992
|
+
clearGoalStatusEntry(checkedRun.id);
|
|
2986
2993
|
return;
|
|
2987
2994
|
}
|
|
2988
2995
|
if (decision.kind === "wait") {
|
|
2989
2996
|
appendGoalProgress({
|
|
2990
2997
|
kind: "goal_progress",
|
|
2991
2998
|
phase: "worker_started",
|
|
2992
|
-
title: decision.workerId
|
|
2999
|
+
title: decision.workerId
|
|
3000
|
+
? `Goal working: ${checkedRun.title}`
|
|
3001
|
+
: `Goal active: ${checkedRun.title}`,
|
|
2993
3002
|
detail: decision.reason,
|
|
2994
3003
|
workerId: decision.workerId,
|
|
2995
3004
|
});
|
|
2996
3005
|
upsertGoalStatusEntry({
|
|
2997
|
-
runId:
|
|
2998
|
-
label:
|
|
3006
|
+
runId: checkedRun.id,
|
|
3007
|
+
label: checkedRun.title,
|
|
2999
3008
|
phase: decision.workerId ? "worker" : "orchestrating",
|
|
3000
3009
|
startedAt: Date.now(),
|
|
3001
3010
|
detail: decision.reason,
|
|
3002
3011
|
workerId: decision.workerId,
|
|
3003
|
-
goalNumber: goalNumberForRun(
|
|
3012
|
+
goalNumber: goalNumberForRun(checkedRun.id),
|
|
3004
3013
|
});
|
|
3005
3014
|
return;
|
|
3006
3015
|
}
|
|
3007
3016
|
if (decision.kind === "complete") {
|
|
3008
|
-
await upsertGoalRun(props.cwd, { ...
|
|
3017
|
+
await upsertGoalRun(props.cwd, { ...checkedRun, status: "passed" });
|
|
3009
3018
|
setGoalCount((await summarizeGoalCounts(props.cwd)).active);
|
|
3010
3019
|
appendGoalProgress({
|
|
3011
3020
|
kind: "goal_progress",
|
|
3012
3021
|
phase: "terminal",
|
|
3013
|
-
title: `Goal passed: ${
|
|
3022
|
+
title: `Goal passed: ${checkedRun.title}`,
|
|
3014
3023
|
detail: decision.reason,
|
|
3015
3024
|
status: "passed",
|
|
3016
3025
|
});
|
|
3017
|
-
runningGoalIdsRef.current.delete(
|
|
3018
|
-
clearGoalStatusEntry(
|
|
3026
|
+
runningGoalIdsRef.current.delete(checkedRun.id);
|
|
3027
|
+
clearGoalStatusEntry(checkedRun.id);
|
|
3019
3028
|
return;
|
|
3020
3029
|
}
|
|
3021
3030
|
if (decision.kind === "run_verifier") {
|
|
3022
|
-
await verifyGoalRun(
|
|
3031
|
+
await verifyGoalRun(checkedRun);
|
|
3023
3032
|
return;
|
|
3024
3033
|
}
|
|
3025
3034
|
if (decision.kind === "create_task") {
|
|
3026
|
-
await updateGoalTask(props.cwd,
|
|
3035
|
+
await updateGoalTask(props.cwd, checkedRun.id, `auto-${Date.now()}`, {
|
|
3027
3036
|
title: decision.title,
|
|
3028
3037
|
prompt: decision.prompt,
|
|
3029
3038
|
status: "pending",
|
|
3030
3039
|
});
|
|
3031
|
-
const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id ===
|
|
3040
|
+
const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === checkedRun.id) ?? checkedRun;
|
|
3032
3041
|
await upsertGoalRun(props.cwd, { ...latestRun, status: "ready" });
|
|
3033
|
-
setTimeout(() => continueGoalRun(
|
|
3042
|
+
setTimeout(() => continueGoalRun(checkedRun.id), 250);
|
|
3034
3043
|
return;
|
|
3035
3044
|
}
|
|
3036
3045
|
if (decision.kind === "blocked") {
|
|
3037
3046
|
await upsertGoalRun(props.cwd, {
|
|
3038
|
-
...
|
|
3047
|
+
...checkedRun,
|
|
3039
3048
|
status: "blocked",
|
|
3040
|
-
blockers: [...
|
|
3049
|
+
blockers: [...checkedRun.blockers, decision.reason],
|
|
3041
3050
|
});
|
|
3042
3051
|
setGoalCount((await summarizeGoalCounts(props.cwd)).active);
|
|
3043
3052
|
appendGoalProgress({
|
|
3044
3053
|
kind: "goal_progress",
|
|
3045
3054
|
phase: "terminal",
|
|
3046
|
-
title: `Goal blocked: ${
|
|
3055
|
+
title: `Goal blocked: ${checkedRun.title}`,
|
|
3047
3056
|
detail: decision.reason,
|
|
3048
3057
|
status: "blocked",
|
|
3049
3058
|
});
|
|
3050
|
-
runningGoalIdsRef.current.delete(
|
|
3051
|
-
clearGoalStatusEntry(
|
|
3059
|
+
runningGoalIdsRef.current.delete(checkedRun.id);
|
|
3060
|
+
clearGoalStatusEntry(checkedRun.id);
|
|
3052
3061
|
return;
|
|
3053
3062
|
}
|
|
3054
3063
|
if (decision.kind === "pause") {
|
|
3055
|
-
const runWithBlockedTask = (await updateGoalTask(props.cwd,
|
|
3064
|
+
const runWithBlockedTask = (await updateGoalTask(props.cwd, checkedRun.id, decision.task.id, {
|
|
3056
3065
|
status: "blocked",
|
|
3057
3066
|
attempts: decision.attempts,
|
|
3058
3067
|
lastSummary: "Paused after worker attempt limit.",
|
|
3059
|
-
})) ??
|
|
3060
|
-
const runWithPauseEvidence = (await appendGoalEvidence(props.cwd,
|
|
3068
|
+
})) ?? checkedRun;
|
|
3069
|
+
const runWithPauseEvidence = (await appendGoalEvidence(props.cwd, checkedRun.id, {
|
|
3061
3070
|
kind: "summary",
|
|
3062
3071
|
label: "Goal paused",
|
|
3063
3072
|
content: decision.reason,
|
|
@@ -3072,27 +3081,28 @@ export function App(props) {
|
|
|
3072
3081
|
appendGoalProgress({
|
|
3073
3082
|
kind: "goal_progress",
|
|
3074
3083
|
phase: "terminal",
|
|
3075
|
-
title: `Goal paused: ${
|
|
3084
|
+
title: `Goal paused: ${checkedRun.title}`,
|
|
3076
3085
|
detail: decision.reason,
|
|
3077
3086
|
status: "paused",
|
|
3078
3087
|
});
|
|
3079
|
-
runningGoalIdsRef.current.delete(
|
|
3080
|
-
clearGoalStatusEntry(
|
|
3088
|
+
runningGoalIdsRef.current.delete(checkedRun.id);
|
|
3089
|
+
clearGoalStatusEntry(checkedRun.id);
|
|
3081
3090
|
return;
|
|
3082
3091
|
}
|
|
3083
|
-
const runWithAttempt = (await updateGoalTask(props.cwd,
|
|
3092
|
+
const runWithAttempt = (await updateGoalTask(props.cwd, checkedRun.id, decision.task.id, {
|
|
3084
3093
|
attempts: decision.attempts,
|
|
3085
|
-
})) ??
|
|
3094
|
+
})) ?? checkedRun;
|
|
3086
3095
|
const worker = await startGoalWorker({
|
|
3087
3096
|
cwd: props.cwd,
|
|
3088
3097
|
provider: currentProvider,
|
|
3089
3098
|
model: currentModel,
|
|
3090
|
-
goalRunId:
|
|
3099
|
+
goalRunId: checkedRun.id,
|
|
3091
3100
|
goalTaskId: decision.task.id,
|
|
3092
3101
|
taskTitle: decision.task.title,
|
|
3093
3102
|
prompt: decision.task.prompt,
|
|
3094
3103
|
});
|
|
3095
|
-
const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id ===
|
|
3104
|
+
const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === checkedRun.id) ??
|
|
3105
|
+
runWithAttempt;
|
|
3096
3106
|
await upsertGoalRun(props.cwd, {
|
|
3097
3107
|
...latestRun,
|
|
3098
3108
|
status: "running",
|
|
@@ -3113,13 +3123,13 @@ export function App(props) {
|
|
|
3113
3123
|
status: worker.status,
|
|
3114
3124
|
});
|
|
3115
3125
|
upsertGoalStatusEntry({
|
|
3116
|
-
runId:
|
|
3126
|
+
runId: checkedRun.id,
|
|
3117
3127
|
label: decision.task.title,
|
|
3118
3128
|
phase: "worker",
|
|
3119
3129
|
startedAt: Date.now(),
|
|
3120
3130
|
detail: "background worker running",
|
|
3121
3131
|
workerId: worker.id,
|
|
3122
|
-
goalNumber: goalNumberForRun(
|
|
3132
|
+
goalNumber: goalNumberForRun(checkedRun.id),
|
|
3123
3133
|
});
|
|
3124
3134
|
})().catch((err) => {
|
|
3125
3135
|
clearGoalStatusEntry(run.id);
|