@kenkaiiii/ggcoder 4.3.211 → 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/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";
@@ -343,17 +344,16 @@ export function formatGoalTerminalProgress(run) {
343
344
  return null;
344
345
  }
345
346
  }
346
- export function shouldHideHistoryForOverlayView(_isOverlayView, _isAgentRunning) {
347
- // Ink Static is append-only. Passing [] for overlay panes rewrites the Static
348
- // accumulator and can destroy scrollback when the pane closes. Keep history
349
- // mounted and let overlays render below it.
350
- 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;
351
351
  }
352
352
  export function shouldStabilizeOverlayPaneRerender({ overlayPane, isAgentRunning, }) {
353
353
  return isAgentRunning && (overlayPane === "goal" || overlayPane === "plan");
354
354
  }
355
- export function shouldHideStaticItemsForOverlayView({ shouldHideHistoryForOverlay, stabilizeOverlayPaneRerender, }) {
356
- return shouldHideHistoryForOverlay && !stabilizeOverlayPaneRerender;
355
+ export function shouldHideStaticItemsForOverlayView({ shouldHideHistoryForOverlay, stabilizeOverlayPaneRerender: _stabilizeOverlayPaneRerender, }) {
356
+ return shouldHideHistoryForOverlay;
357
357
  }
358
358
  export function getScrollStabilizationDecision({ isUserScrolled, hasNewOutput, hasTallLiveUserMessage = false, }) {
359
359
  const shouldStabilize = isUserScrolled || hasTallLiveUserMessage;
@@ -2952,111 +2952,121 @@ export function App(props) {
2952
2952
  const startGoalRun = useCallback((run) => {
2953
2953
  runningGoalIdsRef.current.add(run.id);
2954
2954
  void (async () => {
2955
- if (goalHasBlockingPrerequisites(run)) {
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)) {
2956
2964
  setOverlay(null);
2957
- const detail = formatGoalBlockingPrerequisites(run);
2965
+ const detail = formatGoalBlockingPrerequisites(checkedRun);
2958
2966
  await upsertGoalRun(props.cwd, {
2959
- ...run,
2967
+ ...checkedRun,
2960
2968
  status: "blocked",
2961
- blockers: Array.from(new Set([...run.blockers, detail])),
2969
+ blockers: Array.from(new Set([...checkedRun.blockers, detail])),
2962
2970
  });
2963
2971
  setGoalCount((await summarizeGoalCounts(props.cwd)).active);
2964
2972
  appendGoalProgress({
2965
2973
  kind: "goal_progress",
2966
2974
  phase: "terminal",
2967
- title: `Goal blocked: ${run.title}`,
2975
+ title: `Goal blocked: ${checkedRun.title}`,
2968
2976
  detail,
2969
2977
  status: "blocked",
2970
2978
  });
2971
- runningGoalIdsRef.current.delete(run.id);
2972
- clearGoalStatusEntry(run.id);
2979
+ runningGoalIdsRef.current.delete(checkedRun.id);
2980
+ clearGoalStatusEntry(checkedRun.id);
2973
2981
  return;
2974
2982
  }
2975
- const decision = decideGoalNextAction(run);
2976
- await appendGoalDecision(props.cwd, run.id, decision);
2983
+ const decision = decideGoalNextAction(checkedRun);
2984
+ await appendGoalDecision(props.cwd, checkedRun.id, decision);
2977
2985
  if (decision.kind === "terminal") {
2978
- const terminalProgress = formatGoalTerminalProgress(run);
2986
+ const terminalProgress = formatGoalTerminalProgress(checkedRun);
2979
2987
  if (terminalProgress) {
2980
- const item = { ...terminalProgress, id: goalTerminalProgressId(run) };
2981
- setLiveItems((prev) => completedItemsWithDurableGoalTerminalProgress([...prev, item], [run]));
2988
+ const item = { ...terminalProgress, id: goalTerminalProgressId(checkedRun) };
2989
+ setLiveItems((prev) => completedItemsWithDurableGoalTerminalProgress([...prev, item], [checkedRun]));
2982
2990
  }
2983
- runningGoalIdsRef.current.delete(run.id);
2984
- clearGoalStatusEntry(run.id);
2991
+ runningGoalIdsRef.current.delete(checkedRun.id);
2992
+ clearGoalStatusEntry(checkedRun.id);
2985
2993
  return;
2986
2994
  }
2987
2995
  if (decision.kind === "wait") {
2988
2996
  appendGoalProgress({
2989
2997
  kind: "goal_progress",
2990
2998
  phase: "worker_started",
2991
- title: decision.workerId ? `Goal working: ${run.title}` : `Goal active: ${run.title}`,
2999
+ title: decision.workerId
3000
+ ? `Goal working: ${checkedRun.title}`
3001
+ : `Goal active: ${checkedRun.title}`,
2992
3002
  detail: decision.reason,
2993
3003
  workerId: decision.workerId,
2994
3004
  });
2995
3005
  upsertGoalStatusEntry({
2996
- runId: run.id,
2997
- label: run.title,
3006
+ runId: checkedRun.id,
3007
+ label: checkedRun.title,
2998
3008
  phase: decision.workerId ? "worker" : "orchestrating",
2999
3009
  startedAt: Date.now(),
3000
3010
  detail: decision.reason,
3001
3011
  workerId: decision.workerId,
3002
- goalNumber: goalNumberForRun(run.id),
3012
+ goalNumber: goalNumberForRun(checkedRun.id),
3003
3013
  });
3004
3014
  return;
3005
3015
  }
3006
3016
  if (decision.kind === "complete") {
3007
- await upsertGoalRun(props.cwd, { ...run, status: "passed" });
3017
+ await upsertGoalRun(props.cwd, { ...checkedRun, status: "passed" });
3008
3018
  setGoalCount((await summarizeGoalCounts(props.cwd)).active);
3009
3019
  appendGoalProgress({
3010
3020
  kind: "goal_progress",
3011
3021
  phase: "terminal",
3012
- title: `Goal passed: ${run.title}`,
3022
+ title: `Goal passed: ${checkedRun.title}`,
3013
3023
  detail: decision.reason,
3014
3024
  status: "passed",
3015
3025
  });
3016
- runningGoalIdsRef.current.delete(run.id);
3017
- clearGoalStatusEntry(run.id);
3026
+ runningGoalIdsRef.current.delete(checkedRun.id);
3027
+ clearGoalStatusEntry(checkedRun.id);
3018
3028
  return;
3019
3029
  }
3020
3030
  if (decision.kind === "run_verifier") {
3021
- await verifyGoalRun(run);
3031
+ await verifyGoalRun(checkedRun);
3022
3032
  return;
3023
3033
  }
3024
3034
  if (decision.kind === "create_task") {
3025
- await updateGoalTask(props.cwd, run.id, `auto-${Date.now()}`, {
3035
+ await updateGoalTask(props.cwd, checkedRun.id, `auto-${Date.now()}`, {
3026
3036
  title: decision.title,
3027
3037
  prompt: decision.prompt,
3028
3038
  status: "pending",
3029
3039
  });
3030
- const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === run.id) ?? run;
3040
+ const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === checkedRun.id) ?? checkedRun;
3031
3041
  await upsertGoalRun(props.cwd, { ...latestRun, status: "ready" });
3032
- setTimeout(() => continueGoalRun(run.id), 250);
3042
+ setTimeout(() => continueGoalRun(checkedRun.id), 250);
3033
3043
  return;
3034
3044
  }
3035
3045
  if (decision.kind === "blocked") {
3036
3046
  await upsertGoalRun(props.cwd, {
3037
- ...run,
3047
+ ...checkedRun,
3038
3048
  status: "blocked",
3039
- blockers: [...run.blockers, decision.reason],
3049
+ blockers: [...checkedRun.blockers, decision.reason],
3040
3050
  });
3041
3051
  setGoalCount((await summarizeGoalCounts(props.cwd)).active);
3042
3052
  appendGoalProgress({
3043
3053
  kind: "goal_progress",
3044
3054
  phase: "terminal",
3045
- title: `Goal blocked: ${run.title}`,
3055
+ title: `Goal blocked: ${checkedRun.title}`,
3046
3056
  detail: decision.reason,
3047
3057
  status: "blocked",
3048
3058
  });
3049
- runningGoalIdsRef.current.delete(run.id);
3050
- clearGoalStatusEntry(run.id);
3059
+ runningGoalIdsRef.current.delete(checkedRun.id);
3060
+ clearGoalStatusEntry(checkedRun.id);
3051
3061
  return;
3052
3062
  }
3053
3063
  if (decision.kind === "pause") {
3054
- const runWithBlockedTask = (await updateGoalTask(props.cwd, run.id, decision.task.id, {
3064
+ const runWithBlockedTask = (await updateGoalTask(props.cwd, checkedRun.id, decision.task.id, {
3055
3065
  status: "blocked",
3056
3066
  attempts: decision.attempts,
3057
3067
  lastSummary: "Paused after worker attempt limit.",
3058
- })) ?? run;
3059
- const runWithPauseEvidence = (await appendGoalEvidence(props.cwd, run.id, {
3068
+ })) ?? checkedRun;
3069
+ const runWithPauseEvidence = (await appendGoalEvidence(props.cwd, checkedRun.id, {
3060
3070
  kind: "summary",
3061
3071
  label: "Goal paused",
3062
3072
  content: decision.reason,
@@ -3071,27 +3081,28 @@ export function App(props) {
3071
3081
  appendGoalProgress({
3072
3082
  kind: "goal_progress",
3073
3083
  phase: "terminal",
3074
- title: `Goal paused: ${run.title}`,
3084
+ title: `Goal paused: ${checkedRun.title}`,
3075
3085
  detail: decision.reason,
3076
3086
  status: "paused",
3077
3087
  });
3078
- runningGoalIdsRef.current.delete(run.id);
3079
- clearGoalStatusEntry(run.id);
3088
+ runningGoalIdsRef.current.delete(checkedRun.id);
3089
+ clearGoalStatusEntry(checkedRun.id);
3080
3090
  return;
3081
3091
  }
3082
- const runWithAttempt = (await updateGoalTask(props.cwd, run.id, decision.task.id, {
3092
+ const runWithAttempt = (await updateGoalTask(props.cwd, checkedRun.id, decision.task.id, {
3083
3093
  attempts: decision.attempts,
3084
- })) ?? run;
3094
+ })) ?? checkedRun;
3085
3095
  const worker = await startGoalWorker({
3086
3096
  cwd: props.cwd,
3087
3097
  provider: currentProvider,
3088
3098
  model: currentModel,
3089
- goalRunId: run.id,
3099
+ goalRunId: checkedRun.id,
3090
3100
  goalTaskId: decision.task.id,
3091
3101
  taskTitle: decision.task.title,
3092
3102
  prompt: decision.task.prompt,
3093
3103
  });
3094
- const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === run.id) ?? runWithAttempt;
3104
+ const latestRun = (await loadGoalRuns(props.cwd)).find((item) => item.id === checkedRun.id) ??
3105
+ runWithAttempt;
3095
3106
  await upsertGoalRun(props.cwd, {
3096
3107
  ...latestRun,
3097
3108
  status: "running",
@@ -3112,13 +3123,13 @@ export function App(props) {
3112
3123
  status: worker.status,
3113
3124
  });
3114
3125
  upsertGoalStatusEntry({
3115
- runId: run.id,
3126
+ runId: checkedRun.id,
3116
3127
  label: decision.task.title,
3117
3128
  phase: "worker",
3118
3129
  startedAt: Date.now(),
3119
3130
  detail: "background worker running",
3120
3131
  workerId: worker.id,
3121
- goalNumber: goalNumberForRun(run.id),
3132
+ goalNumber: goalNumberForRun(checkedRun.id),
3122
3133
  });
3123
3134
  })().catch((err) => {
3124
3135
  clearGoalStatusEntry(run.id);