@kenkaiiii/ggcoder 4.3.216 → 4.3.217

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.
Files changed (94) hide show
  1. package/dist/cli.d.ts +2 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +17 -5
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config.d.ts +2 -1
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +6 -0
  8. package/dist/config.js.map +1 -1
  9. package/dist/core/goal-controller.d.ts.map +1 -1
  10. package/dist/core/goal-controller.js +46 -1
  11. package/dist/core/goal-controller.js.map +1 -1
  12. package/dist/core/goal-controller.test.js +39 -0
  13. package/dist/core/goal-controller.test.js.map +1 -1
  14. package/dist/core/goal-store.d.ts +9 -0
  15. package/dist/core/goal-store.d.ts.map +1 -1
  16. package/dist/core/goal-store.js +24 -0
  17. package/dist/core/goal-store.js.map +1 -1
  18. package/dist/core/goal-store.test.js +10 -0
  19. package/dist/core/goal-store.test.js.map +1 -1
  20. package/dist/core/goal-worker.d.ts +2 -1
  21. package/dist/core/goal-worker.d.ts.map +1 -1
  22. package/dist/core/goal-worker.js +5 -0
  23. package/dist/core/goal-worker.js.map +1 -1
  24. package/dist/core/goal-worker.test.js +29 -0
  25. package/dist/core/goal-worker.test.js.map +1 -1
  26. package/dist/system-prompt.d.ts.map +1 -1
  27. package/dist/system-prompt.js +4 -0
  28. package/dist/system-prompt.js.map +1 -1
  29. package/dist/system-prompt.test.js +18 -0
  30. package/dist/system-prompt.test.js.map +1 -1
  31. package/dist/tools/goals.d.ts +9 -0
  32. package/dist/tools/goals.d.ts.map +1 -1
  33. package/dist/tools/goals.js +49 -1
  34. package/dist/tools/goals.js.map +1 -1
  35. package/dist/tools/goals.test.js +44 -21
  36. package/dist/tools/goals.test.js.map +1 -1
  37. package/dist/ui/App.d.ts +2 -6
  38. package/dist/ui/App.d.ts.map +1 -1
  39. package/dist/ui/App.js +75 -32
  40. package/dist/ui/App.js.map +1 -1
  41. package/dist/ui/chat-layout-pinning.test.js +9 -0
  42. package/dist/ui/chat-layout-pinning.test.js.map +1 -1
  43. package/dist/ui/components/AnimationContext.d.ts.map +1 -1
  44. package/dist/ui/components/AnimationContext.js +3 -5
  45. package/dist/ui/components/AnimationContext.js.map +1 -1
  46. package/dist/ui/components/AssistantMessage.test.js +12 -12
  47. package/dist/ui/components/AssistantMessage.test.js.map +1 -1
  48. package/dist/ui/components/CompactionNotice.js +2 -2
  49. package/dist/ui/components/CompactionNotice.js.map +1 -1
  50. package/dist/ui/components/Footer.d.ts +1 -0
  51. package/dist/ui/components/Footer.d.ts.map +1 -1
  52. package/dist/ui/components/Footer.js +5 -2
  53. package/dist/ui/components/Footer.js.map +1 -1
  54. package/dist/ui/components/ServerToolExecution.d.ts.map +1 -1
  55. package/dist/ui/components/ServerToolExecution.js +5 -23
  56. package/dist/ui/components/ServerToolExecution.js.map +1 -1
  57. package/dist/ui/components/SubAgentPanel.d.ts.map +1 -1
  58. package/dist/ui/components/SubAgentPanel.js +3 -2
  59. package/dist/ui/components/SubAgentPanel.js.map +1 -1
  60. package/dist/ui/components/ToolExecution.d.ts.map +1 -1
  61. package/dist/ui/components/ToolExecution.js +12 -30
  62. package/dist/ui/components/ToolExecution.js.map +1 -1
  63. package/dist/ui/components/ToolGroupExecution.d.ts.map +1 -1
  64. package/dist/ui/components/ToolGroupExecution.js +5 -24
  65. package/dist/ui/components/ToolGroupExecution.js.map +1 -1
  66. package/dist/ui/footer-status-layout.test.js +9 -1
  67. package/dist/ui/footer-status-layout.test.js.map +1 -1
  68. package/dist/ui/goal-events.d.ts +4 -0
  69. package/dist/ui/goal-events.d.ts.map +1 -1
  70. package/dist/ui/goal-events.js +19 -1
  71. package/dist/ui/goal-events.js.map +1 -1
  72. package/dist/ui/goal-events.test.js +13 -0
  73. package/dist/ui/goal-events.test.js.map +1 -1
  74. package/dist/ui/queued-message.test.js +18 -0
  75. package/dist/ui/queued-message.test.js.map +1 -1
  76. package/dist/ui/terminal-history.d.ts.map +1 -1
  77. package/dist/ui/terminal-history.js +30 -30
  78. package/dist/ui/terminal-history.js.map +1 -1
  79. package/dist/ui/terminal-history.test.js +21 -8
  80. package/dist/ui/terminal-history.test.js.map +1 -1
  81. package/dist/ui/thinking-level-cycle.test.d.ts +2 -0
  82. package/dist/ui/thinking-level-cycle.test.d.ts.map +1 -0
  83. package/dist/ui/thinking-level-cycle.test.js +19 -0
  84. package/dist/ui/thinking-level-cycle.test.js.map +1 -0
  85. package/dist/ui/tool-group-summary.d.ts.map +1 -1
  86. package/dist/ui/tool-group-summary.js +117 -8
  87. package/dist/ui/tool-group-summary.js.map +1 -1
  88. package/dist/ui/tool-group-summary.test.d.ts +2 -0
  89. package/dist/ui/tool-group-summary.test.d.ts.map +1 -0
  90. package/dist/ui/tool-group-summary.test.js +79 -0
  91. package/dist/ui/tool-group-summary.test.js.map +1 -0
  92. package/dist/ui/tui-history-parity.test.js +30 -10
  93. package/dist/ui/tui-history-parity.test.js.map +1 -1
  94. package/package.json +4 -4
package/dist/ui/App.js CHANGED
@@ -206,7 +206,30 @@ export function buildUserContentWithAttachments(text, inputImages, modelSupports
206
206
  return parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts;
207
207
  }
208
208
  /** Tools that get aggregated into a single compact group when possible. */
209
- const AGGREGATABLE_TOOLS = new Set(["read", "grep", "find", "ls"]);
209
+ const AGGREGATABLE_TOOLS = new Set([
210
+ "read",
211
+ "grep",
212
+ "find",
213
+ "ls",
214
+ "mcp__kencode-search__searchCode",
215
+ "mcp__kencode-search__referenceSources",
216
+ "mcp__kencode-search__discoverRepos",
217
+ ]);
218
+ const OPENAI_GPT_THINKING_LEVELS = ["medium", "high", "xhigh"];
219
+ function isOpenAIGptModel(provider, model) {
220
+ return provider === "openai" && model.startsWith("gpt-");
221
+ }
222
+ export function getNextThinkingLevel(provider, model, current) {
223
+ if (!isOpenAIGptModel(provider, model)) {
224
+ return current ? undefined : getMaxThinkingLevel(model);
225
+ }
226
+ if (!current)
227
+ return "medium";
228
+ const index = OPENAI_GPT_THINKING_LEVELS.indexOf(current);
229
+ if (index === -1)
230
+ return "medium";
231
+ return OPENAI_GPT_THINKING_LEVELS[index + 1];
232
+ }
210
233
  const RUNNING_INDICATOR_ANIMATION_MS = 1_200;
211
234
  /**
212
235
  * Cap memory by replacing old finalized rows with tiny tombstones. The full
@@ -499,7 +522,6 @@ function isAgentSpacingKind(kind) {
499
522
  "stopped",
500
523
  "plan_transition",
501
524
  "goal_agent_transition",
502
- "thinking_transition",
503
525
  "model_transition",
504
526
  "theme_transition",
505
527
  "plan_event",
@@ -619,12 +641,15 @@ export function partitionCompleted(items) {
619
641
  function normalizeAssistantText(text) {
620
642
  return stripDoneMarkers(text).trim();
621
643
  }
644
+ function isReasoningMarkerText(text) {
645
+ return /^(?:currentItem\?\.type\s*=+\s*)?["']?reasoning["']?$/u.test(text.trim());
646
+ }
622
647
  function isSameAssistantText(item, text) {
623
648
  return item.kind === "assistant" && normalizeAssistantText(item.text) === text;
624
649
  }
625
650
  export function pinStreamingTextBeforeToolBoundary({ items, visibleStreamingText, thinking, thinkingMs, makeId, }) {
626
651
  const text = normalizeAssistantText(visibleStreamingText);
627
- if (text.length === 0)
652
+ if (text.length === 0 || isReasoningMarkerText(text))
628
653
  return items;
629
654
  if (items.some((item) => item.kind === "assistant"))
630
655
  return items;
@@ -777,7 +802,7 @@ export function App(props) {
777
802
  const [currentProvider, setCurrentProvider] = useState(props.provider);
778
803
  const [currentTools, setCurrentTools] = useState(props.tools);
779
804
  const currentToolsRef = useRef(props.tools);
780
- const [thinkingEnabled, setThinkingEnabled] = useState(!!props.thinking);
805
+ const [thinkingLevel, setThinkingLevel] = useState(props.thinking);
781
806
  const [renderMarkdown, setRenderMarkdown] = useState(true);
782
807
  const messagesRef = useRef(props.sessionStore?.messages ?? props.messages);
783
808
  const repoMapInjectionEnabledRef = useRef(true);
@@ -923,11 +948,19 @@ export function App(props) {
923
948
  useEffect(() => {
924
949
  onRuntimeStateChange?.({ provider: currentProvider });
925
950
  }, [currentProvider, onRuntimeStateChange]);
951
+ useEffect(() => {
952
+ if (thinkingLevel && !isOpenAIGptModel(currentProvider, currentModel)) {
953
+ const maxLevel = getMaxThinkingLevel(currentModel);
954
+ if (thinkingLevel !== maxLevel) {
955
+ setThinkingLevel(maxLevel);
956
+ }
957
+ }
958
+ }, [currentProvider, currentModel, thinkingLevel]);
926
959
  useEffect(() => {
927
960
  onRuntimeStateChange?.({
928
- thinking: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined,
961
+ thinking: thinkingLevel,
929
962
  });
930
- }, [thinkingEnabled, currentModel, onRuntimeStateChange]);
963
+ }, [thinkingLevel, onRuntimeStateChange]);
931
964
  useEffect(() => {
932
965
  printHistoryItems(history);
933
966
  }, [history, printHistoryItems]);
@@ -1471,7 +1504,7 @@ export function App(props) {
1471
1504
  tools: currentTools,
1472
1505
  webSearch: props.webSearch,
1473
1506
  maxTokens: props.maxTokens,
1474
- thinking: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined,
1507
+ thinking: thinkingLevel,
1475
1508
  apiKey: activeApiKey,
1476
1509
  baseUrl: activeBaseUrl,
1477
1510
  accountId: activeAccountId,
@@ -2636,20 +2669,20 @@ export function App(props) {
2636
2669
  }
2637
2670
  }, [agentLoop, handleDoubleExit]);
2638
2671
  const handleToggleThinking = useCallback(() => {
2639
- setThinkingEnabled((prev) => {
2640
- const next = !prev;
2641
- log("INFO", "thinking", `Thinking ${next ? "enabled" : "disabled"}`);
2642
- setLiveItems((items) => [
2643
- ...items,
2644
- { kind: "thinking_transition", active: next, id: getId() },
2645
- ]);
2672
+ setThinkingLevel((prev) => {
2673
+ const next = getNextThinkingLevel(currentProvider, currentModel, prev);
2674
+ log("INFO", "thinking", next ? `Thinking ${next}` : "Thinking disabled");
2646
2675
  if (props.settingsFile) {
2647
2676
  const sm = new SettingsManager(props.settingsFile);
2648
- sm.load().then(() => sm.set("thinkingEnabled", next));
2677
+ void sm.load().then(async () => {
2678
+ await sm.set("thinkingEnabled", !!next);
2679
+ if (next)
2680
+ await sm.set("thinkingLevel", next);
2681
+ });
2649
2682
  }
2650
2683
  return next;
2651
2684
  });
2652
- }, [props.settingsFile]);
2685
+ }, [currentProvider, currentModel, props.settingsFile]);
2653
2686
  const handleModelSelect = useCallback((value) => {
2654
2687
  setOverlay(null);
2655
2688
  const colonIdx = value.indexOf(":");
@@ -2838,7 +2871,7 @@ export function App(props) {
2838
2871
  case "user":
2839
2872
  return (_jsx(UserMessage, { text: item.text, imageCount: item.imageCount, pasteInfo: item.pasteInfo }, item.id));
2840
2873
  case "goal":
2841
- return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.success, bold: true, children: "▶ " }), _jsx(Text, { color: theme.textDim, children: "Goal: " }), _jsx(Text, { color: theme.success, children: truncateGoalProgressText(item.title) }), item.workerId ? _jsxs(Text, { color: theme.textDim, children: [" \u00B7 worker ", item.workerId] }) : null] }) }, item.id));
2874
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.success, bold: true, children: "▶ " }), _jsx(Text, { color: theme.textDim, children: "Goal: " }), _jsx(Text, { color: theme.success, children: truncateGoalProgressText(item.title) }), item.workerId ? _jsxs(Text, { color: theme.textDim, children: [" \u00B7 worker ", item.workerId] }) : null] }) }, item.id));
2842
2875
  case "goal_progress": {
2843
2876
  const color = goalProgressColor(item, theme);
2844
2877
  const loaderStatus = goalProgressLoaderStatus(item);
@@ -2851,10 +2884,10 @@ export function App(props) {
2851
2884
  case "style_pack": {
2852
2885
  const names = item.added.map((id) => LANGUAGE_DISPLAY_NAMES[id]);
2853
2886
  const headerLabel = item.added.length > 1 ? "STYLE PACKS ACTIVE" : "STYLE PACK ACTIVE";
2854
- return (_jsxs(Box, { marginTop: 1, flexShrink: 1, flexDirection: "column", borderStyle: "round", borderColor: theme.language, paddingX: 1, children: [_jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.language, bold: true, children: "◆ " }), _jsx(Text, { color: theme.language, bold: true, children: headerLabel })] }), _jsx(Text, { color: theme.text, bold: true, wrap: "wrap", children: names.join(", ") }), item.showSetupHint && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.textMuted, children: "Tip: run " }), _jsx(Text, { color: theme.language, bold: true, children: "/setup" }), _jsx(Text, { color: theme.textMuted, children: " to audit this project against the active pack(s)" })] }) }))] }, item.id));
2887
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, flexShrink: 1, children: _jsxs(Box, { flexShrink: 1, flexDirection: "column", borderStyle: "round", borderColor: theme.language, paddingX: 1, children: [_jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.language, bold: true, children: "◆ " }), _jsx(Text, { color: theme.language, bold: true, children: headerLabel })] }), _jsx(Text, { color: theme.text, bold: true, wrap: "wrap", children: names.join(", ") }), item.showSetupHint && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.textMuted, children: "Tip: run " }), _jsx(Text, { color: theme.language, bold: true, children: "/setup" }), _jsx(Text, { color: theme.textMuted, children: " to audit this project against the active pack(s)" })] }) }))] }) }, item.id));
2855
2888
  }
2856
2889
  case "setup_hint":
2857
- return (_jsxs(Box, { marginTop: 1, flexShrink: 1, flexDirection: "column", borderStyle: "round", borderColor: theme.language, paddingX: 1, children: [_jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.language, bold: true, children: "◆ " }), _jsx(Text, { color: theme.language, bold: true, children: "NO STYLE PACKS DETECTED" })] }), _jsx(Text, { color: theme.textMuted, wrap: "wrap", children: "This directory has no recognized language manifest at its root." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.textMuted, children: "Tip: run " }), _jsx(Text, { color: theme.language, bold: true, children: "/setup" }), _jsx(Text, { color: theme.textMuted, children: " to audit project hygiene or bootstrap a new project from scratch" })] }) })] }, item.id));
2890
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, flexShrink: 1, children: _jsxs(Box, { flexShrink: 1, flexDirection: "column", borderStyle: "round", borderColor: theme.language, paddingX: 1, children: [_jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.language, bold: true, children: "◆ " }), _jsx(Text, { color: theme.language, bold: true, children: "NO STYLE PACKS DETECTED" })] }), _jsx(Text, { color: theme.textMuted, wrap: "wrap", children: "This directory has no recognized language manifest at its root." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.textMuted, children: "Tip: run " }), _jsx(Text, { color: theme.language, bold: true, children: "/setup" }), _jsx(Text, { color: theme.textMuted, children: " to audit project hygiene or bootstrap a new project from scratch" })] }) })] }) }, item.id));
2858
2891
  case "assistant":
2859
2892
  return (_jsx(AssistantMessage, { text: item.text, thinking: item.thinking, thinkingMs: item.thinkingMs, renderMarkdown: renderMarkdown, availableTerminalHeight: measuredLiveAreaRows, marginTop: assistantMarginTop }, item.id));
2860
2893
  case "tool_start":
@@ -2874,15 +2907,11 @@ export function App(props) {
2874
2907
  case "info":
2875
2908
  return renderStatusMessage(item.id, "○ ", item.text, theme.commandColor, { muted: true });
2876
2909
  case "update_notice":
2877
- return (_jsx(Box, { marginTop: 1, flexShrink: 1, borderStyle: "round", borderColor: theme.commandColor, paddingX: 1, children: _jsxs(Text, { color: theme.commandColor, bold: true, wrap: "wrap", children: ["✨ ", item.text] }) }, item.id));
2910
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, flexShrink: 1, children: _jsx(Box, { flexShrink: 1, borderStyle: "round", borderColor: theme.commandColor, paddingX: 1, children: _jsxs(Text, { color: theme.commandColor, bold: true, wrap: "wrap", children: ["✨ ", item.text] }) }) }, item.id));
2878
2911
  case "plan_transition":
2879
2912
  return renderStatusMessage(item.id, "● ", normalizeStatusText(item.text), theme.commandColor, { bold: true });
2880
2913
  case "goal_agent_transition":
2881
2914
  return renderStatusMessage(item.id, "● ", normalizeStatusText(item.text), theme.commandColor, { bold: true });
2882
- case "thinking_transition": {
2883
- const glyphColor = item.active ? theme.commandColor : theme.textDim;
2884
- return renderStatusMessage(item.id, "✻ ", item.active ? "Thinking ON" : "Thinking OFF", glyphColor, { bold: true, muted: !item.active });
2885
- }
2886
2915
  case "model_transition":
2887
2916
  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 });
2888
2917
  case "theme_transition":
@@ -2903,7 +2932,7 @@ export function App(props) {
2903
2932
  // gradient. Glyph `⊘` reads as "stop" without being alarming.
2904
2933
  return renderStatusMessage(item.id, "⊘ ", normalizeStatusText(item.text), theme.commandColor, { bold: true });
2905
2934
  case "step_done":
2906
- return (_jsx(Box, { marginTop: 1, flexShrink: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.success, bold: true, children: "✓ " }), _jsx(Text, { color: theme.success, bold: true, children: `Step ${item.stepNum} done` }), item.description ? (_jsx(Text, { color: theme.textDim, children: ` — ${item.description}` })) : null] }) }, item.id));
2935
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, flexShrink: 1, children: _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: theme.success, bold: true, children: "✓ " }), _jsx(Text, { color: theme.success, bold: true, children: `Step ${item.stepNum} done` }), item.description ? (_jsx(Text, { color: theme.textDim, children: ` — ${item.description}` })) : null] }) }, item.id));
2907
2936
  case "queued": {
2908
2937
  const suffix = item.imageCount
2909
2938
  ? ` (+${item.imageCount} image${item.imageCount > 1 ? "s" : ""})`
@@ -2915,7 +2944,7 @@ export function App(props) {
2915
2944
  case "compacted":
2916
2945
  return (_jsx(CompactionDone, { originalCount: item.originalCount, newCount: item.newCount, tokensBefore: item.tokensBefore, tokensAfter: item.tokensAfter }, item.id));
2917
2946
  case "duration":
2918
- return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.textDim, children: ["✻ ", item.verb, " ", formatDuration(item.durationMs)] }) }, item.id));
2947
+ return (_jsx(Box, { paddingLeft: 1, marginTop: 1, children: _jsxs(Text, { color: theme.textDim, children: ["✻ ", item.verb, " ", formatDuration(item.durationMs)] }) }, item.id));
2919
2948
  case "subagent_group":
2920
2949
  return withPrintedBoundarySpacing(_jsx(SubAgentPanel, { agents: item.agents, aborted: item.aborted }, item.id));
2921
2950
  }
@@ -3315,6 +3344,7 @@ export function App(props) {
3315
3344
  cwd: props.cwd,
3316
3345
  provider: currentProvider,
3317
3346
  model: currentModel,
3347
+ thinkingLevel,
3318
3348
  goalRunId: checkedRun.id,
3319
3349
  goalTaskId: decision.task.id,
3320
3350
  taskTitle: decision.task.title,
@@ -3358,6 +3388,7 @@ export function App(props) {
3358
3388
  props.cwd,
3359
3389
  currentProvider,
3360
3390
  currentModel,
3391
+ thinkingLevel,
3361
3392
  appendGoalProgress,
3362
3393
  clearGoalModeIfIdle,
3363
3394
  clearGoalStatusEntry,
@@ -3667,7 +3698,7 @@ export function App(props) {
3667
3698
  contextWindowOptions,
3668
3699
  cwd: displayedCwd,
3669
3700
  gitBranch,
3670
- thinkingLevel: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined,
3701
+ thinkingLevel,
3671
3702
  goalMode,
3672
3703
  });
3673
3704
  const chatControlsLayout = getChatControlsLayoutDecision({
@@ -3722,12 +3753,24 @@ export function App(props) {
3722
3753
  const shouldReserveStreamingSpacing = agentLoop.isRunning &&
3723
3754
  !hasLiveAssistantItem &&
3724
3755
  (visibleStreamingText.trim().length > 0 || liveItems.some(isAgentSpacingItem));
3756
+ const lastLiveItem = liveItems.at(-1);
3757
+ const lastPendingHistoryItem = pendingHistoryFlushRef.current.at(-1);
3758
+ const lastHistoryItem = history.at(-1);
3725
3759
  const shouldTopSpaceStreamingText = shouldTopSpaceStreamingAssistant({
3726
3760
  visibleStreamingText,
3727
- lastLiveItem: liveItems.at(-1),
3728
- lastPendingHistoryItem: pendingHistoryFlushRef.current.at(-1),
3729
- lastHistoryItem: history.at(-1),
3761
+ lastLiveItem,
3762
+ lastPendingHistoryItem,
3763
+ lastHistoryItem,
3730
3764
  });
3765
+ const visibleQueuedCount = liveItems.filter((item) => item.kind === "queued").length;
3766
+ const hiddenQueuedCount = Math.max(0, agentLoop.queuedCount - visibleQueuedCount);
3767
+ const shouldTopSpaceQueueIndicator = hiddenQueuedCount > 0 &&
3768
+ shouldTopSpaceAfterPrintedAgentBoundary({
3769
+ currentKind: "queued",
3770
+ previousLiveItem: lastLiveItem,
3771
+ lastPendingHistoryItem,
3772
+ lastHistoryItem,
3773
+ });
3731
3774
  return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: isGoalView ? (_jsx(GoalOverlay, { cwd: props.cwd, agentRunning: agentLoop.isRunning, autoExpandNewest: goalAutoExpand, onClose: () => {
3732
3775
  goalAutoExpandRef.current = false;
3733
3776
  setGoalAutoExpand(false);
@@ -3946,7 +3989,7 @@ export function App(props) {
3946
3989
  log("ERROR", "error", errMsg);
3947
3990
  setLiveItems((prev) => [...prev, toErrorItem(err, getId())]);
3948
3991
  });
3949
- } })) : (_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: [agentLoop.queuedCount > 0 && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.warning, bold: true, children: "• " }), _jsxs(Text, { color: theme.textDim, children: [agentLoop.queuedCount, " message", agentLoop.queuedCount > 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: thinkingEnabled, 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, onToggleGoal: () => {
3992
+ } })) : (_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, onToggleGoal: () => {
3950
3993
  openOverlay("goal");
3951
3994
  }, onToggleSkills: () => {
3952
3995
  openOverlay("skills");
@@ -3954,7 +3997,7 @@ export function App(props) {
3954
3997
  openOverlay("pixel");
3955
3998
  }, onToggleMarkdown: () => {
3956
3999
  setRenderMarkdown((prev) => !prev);
3957
- }, cwd: props.cwd, commands: allCommands }), overlay === "model" ? (_jsx(ModelSelector, { onSelect: handleModelSelect, onCancel: () => setOverlay(null), loggedInProviders: props.loggedInProviders ?? [currentProvider], currentModel: currentModel, currentProvider: currentProvider })) : overlay === "theme" ? (_jsx(ThemeSelector, { onSelect: handleThemeSelect, onCancel: () => setOverlay(null), currentTheme: theme.name })) : (_jsxs(_Fragment, { children: [_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, contextWindowOptions: contextWindowOptions, cwd: displayedCwd, gitBranch: gitBranch, thinkingLevel: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined, goalMode: goalMode, exitPending: exitPending, renderMarkdown: renderMarkdown }), !exitPending && _jsx(GoalStatusBar, { entries: goalStatusEntries })] })), (footerStatusLayout.hasBackgroundTasks || footerStatusLayout.hasUpdateNotice) && (_jsxs(Box, { flexDirection: footerStatusLayout.stack ? "column" : "row", width: columns, children: [footerStatusLayout.hasBackgroundTasks && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate, compact: footerStatusLayout.compactBackgroundTasks })), footerStatusLayout.hasUpdateNotice && (_jsx(Box, { paddingLeft: footerStatusLayout.stack || !footerStatusLayout.hasBackgroundTasks ? 1 : 2, paddingRight: 1, children: _jsx(Text, { color: theme.success, bold: true, wrap: "truncate", children: "\u2728 Update ready \u00B7 restart to apply" }) }))] }))] })] })) }));
4000
+ }, cwd: props.cwd, commands: allCommands }), overlay === "model" ? (_jsx(ModelSelector, { onSelect: handleModelSelect, onCancel: () => setOverlay(null), loggedInProviders: props.loggedInProviders ?? [currentProvider], currentModel: currentModel, currentProvider: currentProvider })) : overlay === "theme" ? (_jsx(ThemeSelector, { onSelect: handleThemeSelect, onCancel: () => setOverlay(null), currentTheme: theme.name })) : (_jsxs(_Fragment, { children: [_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, contextWindowOptions: contextWindowOptions, cwd: displayedCwd, gitBranch: gitBranch, thinkingLevel: thinkingLevel, goalMode: goalMode, exitPending: exitPending, renderMarkdown: renderMarkdown }), !exitPending && _jsx(GoalStatusBar, { entries: goalStatusEntries })] })), (footerStatusLayout.hasBackgroundTasks || footerStatusLayout.hasUpdateNotice) && (_jsxs(Box, { flexDirection: footerStatusLayout.stack ? "column" : "row", width: columns, children: [footerStatusLayout.hasBackgroundTasks && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate, compact: footerStatusLayout.compactBackgroundTasks })), footerStatusLayout.hasUpdateNotice && (_jsx(Box, { paddingLeft: footerStatusLayout.stack || !footerStatusLayout.hasBackgroundTasks ? 1 : 2, paddingRight: 1, children: _jsx(Text, { color: theme.success, bold: true, wrap: "truncate", children: "\u2728 Update ready \u00B7 restart to apply" }) }))] }))] })] })) }));
3958
4001
  }
3959
4002
  function formatRepoMapCommandOutput(enabled, markdown, refreshed) {
3960
4003
  const status = enabled ? "on" : "off";