@kenkaiiii/ggcoder 4.3.218 → 4.3.219
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 +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/goal-store.d.ts +2 -0
- package/dist/core/goal-store.d.ts.map +1 -1
- package/dist/core/goal-store.js +21 -0
- package/dist/core/goal-store.js.map +1 -1
- package/dist/core/tasks-store.d.ts +24 -0
- package/dist/core/tasks-store.d.ts.map +1 -0
- package/dist/core/tasks-store.js +81 -0
- package/dist/core/tasks-store.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/tasks.d.ts +16 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +93 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/ui/App.d.ts +1 -0
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +153 -127
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/app-items.d.ts +6 -1
- package/dist/ui/app-items.d.ts.map +1 -1
- package/dist/ui/app-state-persistence.test.js +19 -1
- package/dist/ui/app-state-persistence.test.js.map +1 -1
- package/dist/ui/chat-layout-pinning.test.js +10 -0
- package/dist/ui/chat-layout-pinning.test.js.map +1 -1
- package/dist/ui/components/Banner.js +2 -2
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/GoalPickerMenu.d.ts +9 -0
- package/dist/ui/components/GoalPickerMenu.d.ts.map +1 -0
- package/dist/ui/components/GoalPickerMenu.js +37 -0
- package/dist/ui/components/GoalPickerMenu.js.map +1 -0
- package/dist/ui/components/InputArea.d.ts +16 -1
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +91 -3
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/TaskPickerMenu.d.ts +9 -0
- package/dist/ui/components/TaskPickerMenu.d.ts.map +1 -0
- package/dist/ui/components/TaskPickerMenu.js +33 -0
- package/dist/ui/components/TaskPickerMenu.js.map +1 -0
- package/dist/ui/item-helpers.d.ts +2 -0
- package/dist/ui/item-helpers.d.ts.map +1 -1
- package/dist/ui/item-helpers.js +16 -0
- package/dist/ui/item-helpers.js.map +1 -1
- package/dist/ui/layout-decisions.d.ts.map +1 -1
- package/dist/ui/layout-decisions.js +1 -0
- package/dist/ui/layout-decisions.js.map +1 -1
- package/dist/ui/terminal-history-spacing.d.ts.map +1 -1
- package/dist/ui/terminal-history-spacing.js +1 -0
- package/dist/ui/terminal-history-spacing.js.map +1 -1
- package/dist/ui/terminal-history.d.ts.map +1 -1
- package/dist/ui/terminal-history.js +6 -3
- package/dist/ui/terminal-history.js.map +1 -1
- package/dist/ui/tui-history-parity.test.js +3 -0
- package/dist/ui/tui-history-parity.test.js.map +1 -1
- package/package.json +3 -3
package/dist/ui/App.js
CHANGED
|
@@ -27,7 +27,6 @@ import { GoalStatusBar, reconcileGoalStatusEntriesWithRuns, removeGoalStatusEntr
|
|
|
27
27
|
import { Banner } from "./components/Banner.js";
|
|
28
28
|
import { PlanOverlay } from "./components/PlanOverlay.js";
|
|
29
29
|
import { ModelSelector } from "./components/ModelSelector.js";
|
|
30
|
-
import { GoalOverlay } from "./components/GoalOverlay.js";
|
|
31
30
|
import { PixelOverlay } from "./components/PixelOverlay.js";
|
|
32
31
|
import { SkillsOverlay } from "./components/SkillsOverlay.js";
|
|
33
32
|
import { ThemeSelector } from "./components/ThemeSelector.js";
|
|
@@ -58,7 +57,8 @@ import { extractPlanSteps, findCompletedMarkers, markStepsCompleted, segmentDisp
|
|
|
58
57
|
import { getMCPServers } from "../core/mcp/index.js";
|
|
59
58
|
import { trimFlushedItems, flushOnTurnText, flushOnTurnEnd, flushOverflow, } from "./live-item-flush.js";
|
|
60
59
|
import { splitAssistantStreamingText } from "./utils/assistant-stream-split.js";
|
|
61
|
-
import { appendGoalDecision, appendGoalEvidence, formatGoalBlockingPrerequisites, goalHasBlockingPrerequisites, loadGoalRuns, reconcileActiveGoalRuns, updateGoalTask, upsertGoalRun, } from "../core/goal-store.js";
|
|
60
|
+
import { appendGoalDecision, appendGoalEvidence, formatGoalBlockingPrerequisites, goalHasBlockingPrerequisites, loadGoalRuns, loadGoalRunsSync, reconcileActiveGoalRuns, saveGoalRunsSync, updateGoalTask, upsertGoalRun, } from "../core/goal-store.js";
|
|
61
|
+
import { getNextPendingTask, loadTasksSync, markTaskInProgress, saveTasksSync, } from "../core/tasks-store.js";
|
|
62
62
|
import { canCompleteGoalRun, decideGoalNextAction } from "../core/goal-controller.js";
|
|
63
63
|
import { runGoalPrerequisiteChecks } from "../core/goal-prerequisites.js";
|
|
64
64
|
import { runGoalVerifierCommand } from "../core/goal-verifier.js";
|
|
@@ -67,8 +67,8 @@ import { formatGoalVerifierCompletionEvent, formatGoalWorkerCompletionEvent, isG
|
|
|
67
67
|
import { buildUserContentWithAttachments, isGoalPromptCommandName, routePromptCommandInput, runGoalPromptSetupSequence, } from "./prompt-routing.js";
|
|
68
68
|
import { getNextThinkingLevel, isThinkingLevelSupported } from "./thinking-level.js";
|
|
69
69
|
import { appendGoalProgressDraft, completedItemsWithDurableGoalTerminalProgress, formatGoalTerminalProgress, formatGoalWorkerFinishedTitle, getGoalContinuationChoiceKey, goalTerminalProgressId, routeGoalSyntheticEvent, summarizeGoalCompletion, truncateGoalProgressText, } from "./goal-progress.js";
|
|
70
|
-
import { getChatControlsLayoutDecision, getDoneFlushDecision,
|
|
71
|
-
import { compactHistory, getNextGeneratedItemId, isActiveItem, isSameAssistantText, normalizeAssistantText, partitionCompleted, pinStreamingTextBeforeToolBoundary, } from "./item-helpers.js";
|
|
70
|
+
import { getChatControlsLayoutDecision, getDoneFlushDecision, getGoalSetupPaneTransitionAfterRun, isAgentSpacingItem, MIN_LIVE_AREA_ROWS, nextGoalModeAfterAgentDone, shouldTopSpaceAfterPrintedAgentBoundary, shouldTopSpaceAssistantAfterToolBoundary, shouldTopSpaceStreamingAssistant, } from "./layout-decisions.js";
|
|
71
|
+
import { compactHistory, getNextGeneratedItemId, isActiveItem, isSameAssistantText, normalizeAssistantText, partitionCompleted, pinStreamingTextBeforeToolBoundary, removeItemsWithIds, uniqueItemsById, } from "./item-helpers.js";
|
|
72
72
|
export { buildGoalSetupPromptFromPlanner, buildUserContentWithAttachments, collectAssistantTextSince, isGoalPromptCommandName, routePromptCommandInput, runGoalPromptSetupSequence, } from "./prompt-routing.js";
|
|
73
73
|
export { getNextThinkingLevel } from "./thinking-level.js";
|
|
74
74
|
export { appendGoalProgressDraft, completedItemsWithDurableGoalTerminalProgress, formatGoalTerminalProgress, getGoalContinuationChoiceKey, routeGoalSyntheticEvent, truncateGoalProgressText, } from "./goal-progress.js";
|
|
@@ -261,7 +261,11 @@ export function App(props) {
|
|
|
261
261
|
// Items from the current/last turn — rendered in the live area so they stay visible.
|
|
262
262
|
// Seed from sessionStore so Goal progress/completion rows and other live output
|
|
263
263
|
// survive pane/overlay/resize remounts before they are finalized.
|
|
264
|
-
const [liveItems, setLiveItems] = useState(() =>
|
|
264
|
+
const [liveItems, setLiveItems] = useState(() => {
|
|
265
|
+
const restoredLiveItems = uniqueItemsById(props.sessionStore?.liveItems ?? []);
|
|
266
|
+
const restoredHistoryIds = new Set(history.map((item) => item.id));
|
|
267
|
+
return removeItemsWithIds(restoredLiveItems, restoredHistoryIds);
|
|
268
|
+
});
|
|
265
269
|
// overlay seeded from sessionStore (lives across remount). Falls back to
|
|
266
270
|
// props.initialOverlay (CLI launched with one), then null.
|
|
267
271
|
const [overlay, setOverlay] = useState(props.sessionStore?.overlay ?? props.initialOverlay ?? null);
|
|
@@ -274,6 +278,13 @@ export function App(props) {
|
|
|
274
278
|
const goalContinuationFlightsRef = useRef(new Set());
|
|
275
279
|
const goalContinuationRecentChoicesRef = useRef(new Map());
|
|
276
280
|
const startGoalRunRef = useRef(() => { });
|
|
281
|
+
const [runAllTasks, setRunAllTasks] = useState(props.sessionStore?.runAllTasks ?? false);
|
|
282
|
+
const [taskPickerOpen, setTaskPickerOpen] = useState(false);
|
|
283
|
+
const [taskPickerTasks, setTaskPickerTasks] = useState(() => loadTasksSync(props.cwd));
|
|
284
|
+
const [goalPickerOpen, setGoalPickerOpen] = useState(false);
|
|
285
|
+
const [goalPickerGoals, setGoalPickerGoals] = useState(() => loadGoalRunsSync(props.cwd));
|
|
286
|
+
const runAllTasksRef = useRef(props.sessionStore?.runAllTasks ?? false);
|
|
287
|
+
const startTaskRef = useRef(() => { });
|
|
277
288
|
const runAllPixelRef = useRef(props.sessionStore?.runAllPixel ?? false);
|
|
278
289
|
const currentPixelFixRef = useRef(null);
|
|
279
290
|
const startPixelFixRef = useRef(() => { });
|
|
@@ -412,7 +423,7 @@ export function App(props) {
|
|
|
412
423
|
pendingHistoryFlushRef.current = [...pendingHistoryFlushRef.current, ...flushed];
|
|
413
424
|
if (sessionStore) {
|
|
414
425
|
const queuedIds = new Set(items.map((item) => item.id));
|
|
415
|
-
sessionStore.liveItems = (sessionStore.liveItems ?? [])
|
|
426
|
+
sessionStore.liveItems = removeItemsWithIds(uniqueItemsById(sessionStore.liveItems ?? []), queuedIds);
|
|
416
427
|
}
|
|
417
428
|
setHistoryFlushGeneration((generation) => generation + 1);
|
|
418
429
|
}, [sessionStore]);
|
|
@@ -477,8 +488,10 @@ export function App(props) {
|
|
|
477
488
|
sessionStore.history = history;
|
|
478
489
|
}, [history, sessionStore]);
|
|
479
490
|
useEffect(() => {
|
|
480
|
-
if (sessionStore)
|
|
481
|
-
|
|
491
|
+
if (!sessionStore)
|
|
492
|
+
return;
|
|
493
|
+
const historyIds = new Set(historyRef.current.map((item) => item.id));
|
|
494
|
+
sessionStore.liveItems = removeItemsWithIds(uniqueItemsById(liveItems), historyIds);
|
|
482
495
|
}, [liveItems, sessionStore]);
|
|
483
496
|
useEffect(() => {
|
|
484
497
|
if (sessionStore)
|
|
@@ -1528,6 +1541,21 @@ export function App(props) {
|
|
|
1528
1541
|
if (nextGoalMode !== goalModeStateRef.current) {
|
|
1529
1542
|
void setGoalModeAndPrompt(nextGoalMode);
|
|
1530
1543
|
}
|
|
1544
|
+
// Run-all: auto-start next pending task after a short delay.
|
|
1545
|
+
if (runAllTasksRef.current) {
|
|
1546
|
+
setTimeout(() => {
|
|
1547
|
+
const cwd = cwdRef.current;
|
|
1548
|
+
const next = getNextPendingTask(cwd);
|
|
1549
|
+
if (next) {
|
|
1550
|
+
markTaskInProgress(cwd, next.id);
|
|
1551
|
+
startTaskRef.current(next.title, next.prompt, next.id);
|
|
1552
|
+
}
|
|
1553
|
+
else {
|
|
1554
|
+
setRunAllTasks(false);
|
|
1555
|
+
log("INFO", "tasks", "Run-all complete — no more pending tasks");
|
|
1556
|
+
}
|
|
1557
|
+
}, 500);
|
|
1558
|
+
}
|
|
1531
1559
|
// Goal loop: after the orchestrator handles a worker/verifier event,
|
|
1532
1560
|
// continue the same Goal automatically until it reaches a terminal state.
|
|
1533
1561
|
for (const runId of [...runningGoalIdsRef.current]) {
|
|
@@ -1949,26 +1977,11 @@ export function App(props) {
|
|
|
1949
1977
|
]);
|
|
1950
1978
|
return;
|
|
1951
1979
|
}
|
|
1952
|
-
// Handle /goals — open goal
|
|
1980
|
+
// Handle /goals — open the input-area goal picker.
|
|
1953
1981
|
if (trimmed === "/goals") {
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
props.sessionStore.goalAutoExpand = false;
|
|
1958
|
-
props.resetUI();
|
|
1959
|
-
}
|
|
1960
|
-
else {
|
|
1961
|
-
if (props.sessionStore) {
|
|
1962
|
-
props.sessionStore.overlay = "goal";
|
|
1963
|
-
props.sessionStore.planAutoExpand = false;
|
|
1964
|
-
props.sessionStore.goalAutoExpand = false;
|
|
1965
|
-
if (agentLoop.isRunning)
|
|
1966
|
-
props.sessionStore.pendingResetUI = true;
|
|
1967
|
-
}
|
|
1968
|
-
setPlanAutoExpand(false);
|
|
1969
|
-
setGoalAutoExpand(false);
|
|
1970
|
-
setOverlay("goal");
|
|
1971
|
-
}
|
|
1982
|
+
setGoalPickerGoals(loadGoalRunsSync(displayedCwd));
|
|
1983
|
+
setTaskPickerOpen(false);
|
|
1984
|
+
setGoalPickerOpen(true);
|
|
1972
1985
|
return;
|
|
1973
1986
|
}
|
|
1974
1987
|
// Handle prompt-template commands (built-in + custom from .gg/commands/)
|
|
@@ -2045,26 +2058,11 @@ export function App(props) {
|
|
|
2045
2058
|
await setGoalModeAndPrompt("off");
|
|
2046
2059
|
}
|
|
2047
2060
|
if (paneTransition) {
|
|
2048
|
-
goalAutoExpandRef.current =
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
hasResetUI: resetUI !== undefined,
|
|
2054
|
-
hasSessionStore: sessionStore !== undefined,
|
|
2055
|
-
}) &&
|
|
2056
|
-
resetUI &&
|
|
2057
|
-
sessionStore) {
|
|
2058
|
-
sessionStore.overlay = paneTransition.overlay;
|
|
2059
|
-
sessionStore.goalAutoExpand = paneTransition.goalAutoExpand;
|
|
2060
|
-
sessionStore.planAutoExpand = paneTransition.planAutoExpand;
|
|
2061
|
-
resetUI();
|
|
2062
|
-
return;
|
|
2063
|
-
}
|
|
2064
|
-
setGoalAutoExpand(paneTransition.goalAutoExpand);
|
|
2065
|
-
setPlanAutoExpand(paneTransition.planAutoExpand);
|
|
2066
|
-
setOverlay(paneTransition.overlay);
|
|
2067
|
-
}, 300);
|
|
2061
|
+
goalAutoExpandRef.current = false;
|
|
2062
|
+
setGoalAutoExpand(false);
|
|
2063
|
+
setPlanAutoExpand(false);
|
|
2064
|
+
setGoalPickerGoals(loadGoalRunsSync(displayedCwd));
|
|
2065
|
+
setGoalPickerOpen(true);
|
|
2068
2066
|
}
|
|
2069
2067
|
}
|
|
2070
2068
|
}
|
|
@@ -2415,6 +2413,8 @@ export function App(props) {
|
|
|
2415
2413
|
return renderStatusMessage(item.id, `${BLACK_CIRCLE} `, normalizeStatusText(item.text), theme.commandColor, { bold: true });
|
|
2416
2414
|
case "goal_agent_transition":
|
|
2417
2415
|
return renderStatusMessage(item.id, `${BLACK_CIRCLE} `, normalizeStatusText(item.text), theme.commandColor, { bold: true });
|
|
2416
|
+
case "task":
|
|
2417
|
+
return withPrintedBoundarySpacing(renderStatusMessage(item.id, "▸ ", _jsxs(_Fragment, { children: [_jsx(Text, { color: theme.textDim, children: "Task: " }), _jsx(Text, { color: theme.commandColor, bold: true, children: item.title })] }), theme.commandColor, { bold: true }));
|
|
2418
2418
|
case "model_transition":
|
|
2419
2419
|
return renderStatusMessage(item.id, "▸ ", _jsxs(_Fragment, { children: [_jsx(Text, { color: theme.textDim, children: "Switched to " }), _jsx(Text, { color: theme.commandColor, bold: true, children: item.modelName })] }), theme.commandColor, { bold: true });
|
|
2420
2420
|
case "theme_transition":
|
|
@@ -2479,18 +2479,6 @@ export function App(props) {
|
|
|
2479
2479
|
setOverlay(kind);
|
|
2480
2480
|
}
|
|
2481
2481
|
}, [agentLoop.isRunning, props]);
|
|
2482
|
-
const closeOverlay = useCallback(() => {
|
|
2483
|
-
if (props.resetUI && props.sessionStore && !agentLoop.isRunning) {
|
|
2484
|
-
props.sessionStore.overlay = null;
|
|
2485
|
-
props.resetUI();
|
|
2486
|
-
}
|
|
2487
|
-
else {
|
|
2488
|
-
if (props.sessionStore) {
|
|
2489
|
-
props.sessionStore.overlay = null;
|
|
2490
|
-
}
|
|
2491
|
-
setOverlay(null);
|
|
2492
|
-
}
|
|
2493
|
-
}, [agentLoop.isRunning, overlay, props]);
|
|
2494
2482
|
const runGoalSyntheticEvent = useCallback((eventText) => {
|
|
2495
2483
|
const eventInfo = parseGoalSyntheticEvent(eventText);
|
|
2496
2484
|
const detail = eventInfo?.kind === "worker"
|
|
@@ -3065,8 +3053,71 @@ export function App(props) {
|
|
|
3065
3053
|
setLiveItems((prev) => [...prev, toErrorItem(err, getId(), "Goal")]);
|
|
3066
3054
|
});
|
|
3067
3055
|
}, [appendGoalProgress, clearGoalModeIfIdle, clearGoalStatusEntry, props.cwd]);
|
|
3056
|
+
const startTask = useCallback((title, prompt, taskId) => {
|
|
3057
|
+
const taskCwd = cwdRef.current;
|
|
3058
|
+
const shortId = taskId.slice(0, 8);
|
|
3059
|
+
const completionHint = `\n\n---\nWhen you have fully completed this task, call the tasks tool to mark it done:\n` +
|
|
3060
|
+
`tasks({ action: "done", id: "${shortId}" })`;
|
|
3061
|
+
const fullPrompt = prompt + completionHint;
|
|
3062
|
+
if (props.resetUI && props.sessionStore) {
|
|
3063
|
+
const sysMsg = messagesRef.current[0];
|
|
3064
|
+
const newMessages = sysMsg && sysMsg.role === "system" ? [sysMsg] : messagesRef.current.slice(0, 1);
|
|
3065
|
+
const taskItem = { kind: "task", title, id: getId() };
|
|
3066
|
+
const sm = sessionManagerRef.current;
|
|
3067
|
+
void (async () => {
|
|
3068
|
+
let newSessionPath;
|
|
3069
|
+
if (sm) {
|
|
3070
|
+
try {
|
|
3071
|
+
const session = await sm.create(taskCwd, currentProvider, currentModel);
|
|
3072
|
+
newSessionPath = session.path;
|
|
3073
|
+
log("INFO", "tasks", "New session for task", { path: session.path });
|
|
3074
|
+
}
|
|
3075
|
+
catch {
|
|
3076
|
+
// Session creation is best-effort.
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
if (props.sessionStore)
|
|
3080
|
+
props.sessionStore.overlay = null;
|
|
3081
|
+
props.resetUI?.({
|
|
3082
|
+
wipeSession: true,
|
|
3083
|
+
messages: newMessages,
|
|
3084
|
+
history: [{ kind: "banner", id: "banner" }, taskItem],
|
|
3085
|
+
sessionPath: newSessionPath,
|
|
3086
|
+
pendingAction: { prompt: fullPrompt },
|
|
3087
|
+
});
|
|
3088
|
+
})();
|
|
3089
|
+
return;
|
|
3090
|
+
}
|
|
3091
|
+
pendingHistoryFlushRef.current = [];
|
|
3092
|
+
props.terminalHistoryPrinter?.clear();
|
|
3093
|
+
setHistory([{ kind: "banner", id: "banner" }]);
|
|
3094
|
+
setLiveItems([]);
|
|
3095
|
+
messagesRef.current = messagesRef.current.slice(0, 1);
|
|
3096
|
+
agentLoop.reset();
|
|
3097
|
+
persistedIndexRef.current = messagesRef.current.length;
|
|
3098
|
+
const sm = sessionManagerRef.current;
|
|
3099
|
+
if (sm) {
|
|
3100
|
+
void sm.create(taskCwd, currentProvider, currentModel).then((session) => {
|
|
3101
|
+
sessionPathRef.current = session.path;
|
|
3102
|
+
log("INFO", "tasks", "New session for task", { path: session.path });
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
const taskItem = { kind: "task", title, id: getId() };
|
|
3106
|
+
setLastUserMessage(title);
|
|
3107
|
+
setDoneStatus(null);
|
|
3108
|
+
setLiveItems([taskItem]);
|
|
3109
|
+
void agentLoop.run(fullPrompt).catch((err) => {
|
|
3110
|
+
setLiveItems((prev) => [...prev, toErrorItem(err, getId())]);
|
|
3111
|
+
});
|
|
3112
|
+
}, [agentLoop, currentModel, currentProvider, props]);
|
|
3068
3113
|
// Keep refs in sync for access from stale closures (onDone)
|
|
3114
|
+
startTaskRef.current = startTask;
|
|
3069
3115
|
startGoalRunRef.current = startGoalRun;
|
|
3116
|
+
useEffect(() => {
|
|
3117
|
+
runAllTasksRef.current = runAllTasks;
|
|
3118
|
+
if (props.sessionStore)
|
|
3119
|
+
props.sessionStore.runAllTasks = runAllTasks;
|
|
3120
|
+
}, [runAllTasks, props.sessionStore]);
|
|
3070
3121
|
useEffect(() => {
|
|
3071
3122
|
agentRunningRef.current = agentLoop.isRunning;
|
|
3072
3123
|
}, [agentLoop.isRunning]);
|
|
@@ -3166,7 +3217,6 @@ export function App(props) {
|
|
|
3166
3217
|
if (props.sessionStore)
|
|
3167
3218
|
props.sessionStore.runAllPixel = runAllPixel;
|
|
3168
3219
|
}, [runAllPixel, props.sessionStore]);
|
|
3169
|
-
const isGoalView = overlay === "goal";
|
|
3170
3220
|
const isSkillsView = overlay === "skills";
|
|
3171
3221
|
const isPlanView = overlay === "plan";
|
|
3172
3222
|
const footerStatusLayout = getFooterStatusLayoutDecision({
|
|
@@ -3278,71 +3328,7 @@ export function App(props) {
|
|
|
3278
3328
|
lastPendingHistoryItem,
|
|
3279
3329
|
lastHistoryItem,
|
|
3280
3330
|
});
|
|
3281
|
-
return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children:
|
|
3282
|
-
goalAutoExpandRef.current = false;
|
|
3283
|
-
setGoalAutoExpand(false);
|
|
3284
|
-
if (props.sessionStore)
|
|
3285
|
-
props.sessionStore.goalAutoExpand = false;
|
|
3286
|
-
closeOverlay();
|
|
3287
|
-
}, onRunGoal: (run) => {
|
|
3288
|
-
const paneTransition = getGoalActivationPaneTransition();
|
|
3289
|
-
goalAutoExpandRef.current = paneTransition.goalAutoExpand;
|
|
3290
|
-
setGoalAutoExpand(paneTransition.goalAutoExpand);
|
|
3291
|
-
setPlanAutoExpand(paneTransition.planAutoExpand);
|
|
3292
|
-
if (props.sessionStore) {
|
|
3293
|
-
props.sessionStore.overlay = paneTransition.overlay;
|
|
3294
|
-
props.sessionStore.goalAutoExpand = paneTransition.goalAutoExpand;
|
|
3295
|
-
props.sessionStore.planAutoExpand = paneTransition.planAutoExpand;
|
|
3296
|
-
}
|
|
3297
|
-
if (paneTransition.resetReviewScreen && props.resetUI && props.sessionStore) {
|
|
3298
|
-
props.sessionStore.pendingGoalRun = run;
|
|
3299
|
-
props.resetUI();
|
|
3300
|
-
return;
|
|
3301
|
-
}
|
|
3302
|
-
setOverlay(paneTransition.overlay);
|
|
3303
|
-
startGoalRun(run);
|
|
3304
|
-
}, onVerifyGoal: (run) => {
|
|
3305
|
-
void verifyGoalRun(run);
|
|
3306
|
-
}, onPauseGoal: (run) => {
|
|
3307
|
-
pauseGoalRun(run);
|
|
3308
|
-
}, onRefineGoal: (run, feedback) => {
|
|
3309
|
-
goalAutoExpandRef.current = true;
|
|
3310
|
-
setGoalAutoExpand(true);
|
|
3311
|
-
void (async () => {
|
|
3312
|
-
try {
|
|
3313
|
-
await setGoalModeAndPrompt("setup");
|
|
3314
|
-
await agentLoop.run(`Refine Goal run ${run.id} (${run.title}) based on this user feedback. Update durable Goal setup only, then stop and reopen the Goal pane for review.\n\nFeedback: ${feedback}`);
|
|
3315
|
-
}
|
|
3316
|
-
catch (err) {
|
|
3317
|
-
log("ERROR", "goal", err instanceof Error ? err.message : String(err));
|
|
3318
|
-
setLiveItems((prev) => [...prev, toErrorItem(err, getId(), "Goal")]);
|
|
3319
|
-
}
|
|
3320
|
-
finally {
|
|
3321
|
-
await setGoalModeAndPrompt("off");
|
|
3322
|
-
const paneTransition = getGoalSetupFinishedPaneTransition();
|
|
3323
|
-
goalAutoExpandRef.current = paneTransition.goalAutoExpand;
|
|
3324
|
-
setTimeout(() => {
|
|
3325
|
-
const resetUI = props.resetUI;
|
|
3326
|
-
const sessionStore = props.sessionStore;
|
|
3327
|
-
if (shouldResetUIForGoalSetupPaneTransition({
|
|
3328
|
-
hasResetUI: resetUI !== undefined,
|
|
3329
|
-
hasSessionStore: sessionStore !== undefined,
|
|
3330
|
-
}) &&
|
|
3331
|
-
resetUI &&
|
|
3332
|
-
sessionStore) {
|
|
3333
|
-
sessionStore.overlay = paneTransition.overlay;
|
|
3334
|
-
sessionStore.goalAutoExpand = paneTransition.goalAutoExpand;
|
|
3335
|
-
sessionStore.planAutoExpand = paneTransition.planAutoExpand;
|
|
3336
|
-
resetUI();
|
|
3337
|
-
return;
|
|
3338
|
-
}
|
|
3339
|
-
setGoalAutoExpand(paneTransition.goalAutoExpand);
|
|
3340
|
-
setPlanAutoExpand(paneTransition.planAutoExpand);
|
|
3341
|
-
setOverlay(paneTransition.overlay);
|
|
3342
|
-
}, 300);
|
|
3343
|
-
}
|
|
3344
|
-
})();
|
|
3345
|
-
} })) : isPixelView ? (_jsx(PixelOverlay, { version: props.version, agentRunning: agentLoop.isRunning, onClose: () => {
|
|
3331
|
+
return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: isPixelView ? (_jsx(PixelOverlay, { version: props.version, agentRunning: agentLoop.isRunning, onClose: () => {
|
|
3346
3332
|
if (props.resetUI && props.sessionStore && !agentLoop.isRunning) {
|
|
3347
3333
|
props.sessionStore.overlay = null;
|
|
3348
3334
|
props.resetUI();
|
|
@@ -3496,8 +3482,48 @@ export function App(props) {
|
|
|
3496
3482
|
log("ERROR", "error", errMsg);
|
|
3497
3483
|
setLiveItems((prev) => [...prev, toErrorItem(err, getId())]);
|
|
3498
3484
|
});
|
|
3499
|
-
} })) : (_jsxs(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 0, flexShrink: 1, overflowY: "hidden", children: [liveItems.map((item, index, items) => renderItem(item, index, items)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: visibleStreamingText, streamingThinking: agentLoop.streamingThinking, thinkingMs: agentLoop.thinkingMs, reserveSpacing: shouldReserveStreamingSpacing, renderMarkdown: renderMarkdown, availableTerminalHeight: measuredLiveAreaRows, assistantMarginTop: shouldTopSpaceStreamingText ? 1 : 0, continuation: streamedAssistantFlushRef.current.flushedChars > 0 })] }), _jsxs(Box, { ref: mainControlsRef, flexDirection: "column", flexShrink: 0, flexGrow: 0, children: [hiddenQueuedCount > 0 && (_jsxs(Box, { flexDirection: "row", paddingLeft: 1, marginTop: shouldTopSpaceQueueIndicator ? 2 : 1, flexShrink: 0, children: [_jsx(Box, { width: 2, flexShrink: 0, children: _jsx(Text, { color: theme.warning, bold: true, children: "• " }) }), _jsxs(Text, { color: theme.textDim, children: [hiddenQueuedCount, " message", hiddenQueuedCount > 1 ? "s" : "", " queued"] })] })), _jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: theme.textDim, width: columns, height: 0 }), _jsx(Box, { paddingLeft: 1, paddingRight: 1, width: columns, children: statusSlotVisible ? (activityVisible ? (_jsx(ActivityIndicator, { phase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, runStartRef: agentLoop.runStartRef, thinkingMs: agentLoop.thinkingMs, isThinking: agentLoop.isThinking, thinkingEnabled: !!thinkingLevel, tokenEstimate: agentLoop.streamedTokenEstimate, charCountRef: agentLoop.charCountRef, realTokensAccumRef: agentLoop.realTokensAccumRef, userMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name), retryInfo: agentLoop.retryInfo, planDone: planSteps.filter((s) => s.completed).length, planTotal: planSteps.length, staticDisplay: true })) : stallStatusVisible ? (_jsx(Text, { color: theme.warning, wrap: "truncate", children: "⚠ API provider stream interrupted — retries exhausted. Your conversation is preserved." })) : doneStatus ? (_jsxs(Text, { color: theme.success, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] })) : (_jsxs(Text, { children: [_jsx(Text, { color: theme.commandColor, children: "⠿ " }), _jsx(Text, { color: theme.textDim, children: "Ready to go.." }), !renderMarkdown && (_jsx(Text, { color: theme.warning, children: " · raw markdown mode" }))] }))) : (_jsxs(Text, { children: [_jsx(Text, { color: theme.commandColor, children: "⠿ " }), _jsx(Text, { color: theme.textDim, children: "Ready to go.." })] })) })] }), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused && !overlay, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking,
|
|
3500
|
-
|
|
3485
|
+
} })) : (_jsxs(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 0, flexShrink: 1, overflowY: "hidden", children: [uniqueItemsById(liveItems).map((item, index, items) => renderItem(item, index, items)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: visibleStreamingText, streamingThinking: agentLoop.streamingThinking, thinkingMs: agentLoop.thinkingMs, reserveSpacing: shouldReserveStreamingSpacing, renderMarkdown: renderMarkdown, availableTerminalHeight: measuredLiveAreaRows, assistantMarginTop: shouldTopSpaceStreamingText ? 1 : 0, continuation: streamedAssistantFlushRef.current.flushedChars > 0 })] }), _jsxs(Box, { ref: mainControlsRef, flexDirection: "column", flexShrink: 0, flexGrow: 0, children: [hiddenQueuedCount > 0 && (_jsxs(Box, { flexDirection: "row", paddingLeft: 1, marginTop: shouldTopSpaceQueueIndicator ? 2 : 1, flexShrink: 0, children: [_jsx(Box, { width: 2, flexShrink: 0, children: _jsx(Text, { color: theme.warning, bold: true, children: "• " }) }), _jsxs(Text, { color: theme.textDim, children: [hiddenQueuedCount, " message", hiddenQueuedCount > 1 ? "s" : "", " queued"] })] })), _jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: theme.textDim, width: columns, height: 0 }), _jsx(Box, { paddingLeft: 1, paddingRight: 1, width: columns, children: statusSlotVisible ? (activityVisible ? (_jsx(ActivityIndicator, { phase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, runStartRef: agentLoop.runStartRef, thinkingMs: agentLoop.thinkingMs, isThinking: agentLoop.isThinking, thinkingEnabled: !!thinkingLevel, tokenEstimate: agentLoop.streamedTokenEstimate, charCountRef: agentLoop.charCountRef, realTokensAccumRef: agentLoop.realTokensAccumRef, userMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name), retryInfo: agentLoop.retryInfo, planDone: planSteps.filter((s) => s.completed).length, planTotal: planSteps.length, staticDisplay: true })) : stallStatusVisible ? (_jsx(Text, { color: theme.warning, wrap: "truncate", children: "⚠ API provider stream interrupted — retries exhausted. Your conversation is preserved." })) : doneStatus ? (_jsxs(Text, { color: theme.success, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] })) : (_jsxs(Text, { children: [_jsx(Text, { color: theme.commandColor, children: "⠿ " }), _jsx(Text, { color: theme.textDim, children: "Ready to go.." }), !renderMarkdown && (_jsx(Text, { color: theme.warning, children: " · raw markdown mode" }))] }))) : (_jsxs(Text, { children: [_jsx(Text, { color: theme.commandColor, children: "⠿ " }), _jsx(Text, { color: theme.textDim, children: "Ready to go.." })] })) })] }), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused && !overlay, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking, onToggleTasks: () => {
|
|
3486
|
+
setGoalPickerOpen(false);
|
|
3487
|
+
setTaskPickerTasks(loadTasksSync(displayedCwd));
|
|
3488
|
+
setTaskPickerOpen((open) => !open);
|
|
3489
|
+
}, taskPickerOpen: taskPickerOpen, tasks: taskPickerTasks, onCloseTaskPicker: () => setTaskPickerOpen(false), onStartTask: (task) => {
|
|
3490
|
+
setTaskPickerOpen(false);
|
|
3491
|
+
markTaskInProgress(displayedCwd, task.id);
|
|
3492
|
+
setTaskPickerTasks(loadTasksSync(displayedCwd));
|
|
3493
|
+
startTask(task.title, task.prompt, task.id);
|
|
3494
|
+
}, onRunAllTasks: (task) => {
|
|
3495
|
+
setTaskPickerOpen(false);
|
|
3496
|
+
setRunAllTasks(true);
|
|
3497
|
+
const selected = task
|
|
3498
|
+
? {
|
|
3499
|
+
id: task.id,
|
|
3500
|
+
title: task.title,
|
|
3501
|
+
prompt: task.prompt || task.text || task.title,
|
|
3502
|
+
}
|
|
3503
|
+
: getNextPendingTask(displayedCwd);
|
|
3504
|
+
if (selected) {
|
|
3505
|
+
markTaskInProgress(displayedCwd, selected.id);
|
|
3506
|
+
setTaskPickerTasks(loadTasksSync(displayedCwd));
|
|
3507
|
+
startTask(selected.title, selected.prompt, selected.id);
|
|
3508
|
+
}
|
|
3509
|
+
}, onDeleteTask: (task) => {
|
|
3510
|
+
const nextTasks = loadTasksSync(displayedCwd).filter((candidate) => candidate.id !== task.id);
|
|
3511
|
+
saveTasksSync(displayedCwd, nextTasks);
|
|
3512
|
+
setTaskPickerTasks(nextTasks);
|
|
3513
|
+
}, goalPickerOpen: goalPickerOpen, goals: goalPickerGoals, onCloseGoalPicker: () => setGoalPickerOpen(false), onRunGoal: (run) => {
|
|
3514
|
+
setGoalPickerOpen(false);
|
|
3515
|
+
startGoalRun(run);
|
|
3516
|
+
}, onDeleteGoal: (run) => {
|
|
3517
|
+
const nextGoals = loadGoalRunsSync(displayedCwd).filter((candidate) => candidate.id !== run.id);
|
|
3518
|
+
saveGoalRunsSync(displayedCwd, nextGoals);
|
|
3519
|
+
setGoalPickerGoals(nextGoals);
|
|
3520
|
+
}, onPauseGoal: (run) => {
|
|
3521
|
+
setGoalPickerOpen(false);
|
|
3522
|
+
pauseGoalRun(run);
|
|
3523
|
+
}, onToggleGoal: () => {
|
|
3524
|
+
setTaskPickerOpen(false);
|
|
3525
|
+
setGoalPickerGoals(loadGoalRunsSync(displayedCwd));
|
|
3526
|
+
setGoalPickerOpen((open) => !open);
|
|
3501
3527
|
}, onToggleSkills: () => {
|
|
3502
3528
|
openOverlay("skills");
|
|
3503
3529
|
}, onTogglePixel: () => {
|