@kenkaiiii/ggcoder 4.3.197 → 4.3.199

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 (39) hide show
  1. package/dist/cli.js +15 -3
  2. package/dist/cli.js.map +1 -1
  3. package/dist/core/session-compaction.d.ts +15 -0
  4. package/dist/core/session-compaction.d.ts.map +1 -0
  5. package/dist/core/session-compaction.js +31 -0
  6. package/dist/core/session-compaction.js.map +1 -0
  7. package/dist/core/session-compaction.test.d.ts +2 -0
  8. package/dist/core/session-compaction.test.d.ts.map +1 -0
  9. package/dist/core/session-compaction.test.js +70 -0
  10. package/dist/core/session-compaction.test.js.map +1 -0
  11. package/dist/core/settings-manager.d.ts +0 -1
  12. package/dist/core/settings-manager.d.ts.map +1 -1
  13. package/dist/core/settings-manager.js +0 -2
  14. package/dist/core/settings-manager.js.map +1 -1
  15. package/dist/ui/App.d.ts +0 -1
  16. package/dist/ui/App.d.ts.map +1 -1
  17. package/dist/ui/App.js +45 -20
  18. package/dist/ui/App.js.map +1 -1
  19. package/dist/ui/components/ActivityIndicator.d.ts +5 -0
  20. package/dist/ui/components/ActivityIndicator.d.ts.map +1 -1
  21. package/dist/ui/components/ActivityIndicator.js +23 -13
  22. package/dist/ui/components/ActivityIndicator.js.map +1 -1
  23. package/dist/ui/components/ActivityIndicator.test.d.ts +2 -0
  24. package/dist/ui/components/ActivityIndicator.test.d.ts.map +1 -0
  25. package/dist/ui/components/ActivityIndicator.test.js +40 -0
  26. package/dist/ui/components/ActivityIndicator.test.js.map +1 -0
  27. package/dist/ui/components/AssistantMessage.js +1 -1
  28. package/dist/ui/components/AssistantMessage.js.map +1 -1
  29. package/dist/ui/components/StreamingArea.js +1 -1
  30. package/dist/ui/components/StreamingArea.js.map +1 -1
  31. package/dist/ui/components/index.d.ts +0 -1
  32. package/dist/ui/components/index.d.ts.map +1 -1
  33. package/dist/ui/components/index.js +0 -1
  34. package/dist/ui/components/index.js.map +1 -1
  35. package/dist/ui/render.d.ts +0 -1
  36. package/dist/ui/render.d.ts.map +1 -1
  37. package/dist/ui/render.js +0 -1
  38. package/dist/ui/render.js.map +1 -1
  39. package/package.json +4 -4
package/dist/ui/App.js CHANGED
@@ -4,7 +4,7 @@ import { Box, Text, Static, useStdout } from "ink";
4
4
  import { useTerminalSize } from "./hooks/useTerminalSize.js";
5
5
  import { useDoublePress } from "./hooks/useDoublePress.js";
6
6
  import { useTaskBarStore, useTaskBarPolling, focusTaskBar, exitTaskBar, expandTaskBar, collapseTaskBar, navigateTaskBar, killTask, } from "./stores/taskbar-store.js";
7
- import crypto, { createHash } from "node:crypto";
7
+ import { createHash } from "node:crypto";
8
8
  import { readFileSync, writeFileSync } from "node:fs";
9
9
  import { homedir } from "node:os";
10
10
  import { join } from "node:path";
@@ -40,6 +40,7 @@ import { useTerminalTitle } from "./hooks/useTerminalTitle.js";
40
40
  import { getGitBranch } from "../utils/git.js";
41
41
  import { getModel, getContextWindow, getMaxThinkingLevel } from "../core/model-registry.js";
42
42
  import { SessionManager } from "../core/session-manager.js";
43
+ import { appendMessagesToSession as appendSessionMessages, createCompactedSessionCheckpoint, } from "../core/session-compaction.js";
43
44
  import { log } from "../core/logger.js";
44
45
  import { getPendingUpdate, startPeriodicUpdateCheck, stopPeriodicUpdateCheck, } from "../core/auto-update.js";
45
46
  import { generateSessionTitle } from "../utils/session-title.js";
@@ -640,27 +641,42 @@ export function App(props) {
640
641
  };
641
642
  }
642
643
  }, [props.onExitPlanRef, replaceSystemPrompt, stdout]);
643
- const persistNewMessages = useCallback(async () => {
644
+ const appendMessagesToSession = useCallback(async (sessionPath, messages, startIndex) => {
645
+ const sm = sessionManagerRef.current;
646
+ if (!sm)
647
+ return;
648
+ await appendSessionMessages(sm, sessionPath, messages, startIndex);
649
+ }, []);
650
+ const persistCompactedSession = useCallback(async (compactedMessages) => {
644
651
  const sm = sessionManagerRef.current;
652
+ if (!sm)
653
+ return;
654
+ const session = await createCompactedSessionCheckpoint(sm, {
655
+ cwd: cwdRef.current,
656
+ provider: currentProvider,
657
+ model: currentModel,
658
+ messages: compactedMessages,
659
+ });
660
+ sessionPathRef.current = session.path;
661
+ persistedIndexRef.current = compactedMessages.length;
662
+ if (sessionStore) {
663
+ sessionStore.sessionPath = session.path;
664
+ sessionStore.messages = [...compactedMessages];
665
+ }
666
+ log("INFO", "compaction", "Persisted compacted session checkpoint", { path: session.path });
667
+ }, [currentModel, currentProvider, sessionStore]);
668
+ const persistNewMessages = useCallback(async () => {
645
669
  const sp = sessionPathRef.current;
646
- if (!sm || !sp)
670
+ if (!sp)
647
671
  return;
648
672
  const allMsgs = messagesRef.current;
649
- for (let i = persistedIndexRef.current; i < allMsgs.length; i++) {
650
- const msg = allMsgs[i];
651
- if (msg.role === "system")
652
- continue;
653
- const entry = {
654
- type: "message",
655
- id: crypto.randomUUID(),
656
- parentId: null,
657
- timestamp: new Date().toISOString(),
658
- message: msg,
659
- };
660
- await sm.appendEntry(sp, entry);
661
- }
673
+ await appendMessagesToSession(sp, allMsgs, persistedIndexRef.current);
662
674
  persistedIndexRef.current = allMsgs.length;
663
- }, []);
675
+ if (sessionStore) {
676
+ sessionStore.messages = [...allMsgs];
677
+ sessionStore.sessionPath = sp;
678
+ }
679
+ }, [appendMessagesToSession, sessionStore]);
664
680
  /**
665
681
  * Run the language detector against the current cwd. If the detected set is a
666
682
  * strict superset of what's already injected, rebuild the system prompt with
@@ -827,6 +843,10 @@ export function App(props) {
827
843
  // Force-compact on context overflow regardless of settings
828
844
  if (options?.force) {
829
845
  const result = await compactConversation(stripped);
846
+ if (result !== stripped) {
847
+ messagesRef.current = result;
848
+ await persistCompactedSession(result);
849
+ }
830
850
  lastCompactionTimeRef.current = Date.now();
831
851
  return injectRepoMapContext(result);
832
852
  }
@@ -844,6 +864,10 @@ export function App(props) {
844
864
  const actualTokens = lastActualTokensRef.current > 0 && tokensFresh ? lastActualTokensRef.current : undefined;
845
865
  if (shouldCompact(stripped, contextWindow, threshold, actualTokens, reserveTokens)) {
846
866
  const result = await compactConversation(stripped);
867
+ if (result !== stripped) {
868
+ messagesRef.current = result;
869
+ await persistCompactedSession(result);
870
+ }
847
871
  lastCompactionTimeRef.current = Date.now();
848
872
  return injectRepoMapContext(result);
849
873
  }
@@ -853,6 +877,7 @@ export function App(props) {
853
877
  compactConversation,
854
878
  contextWindowOptions,
855
879
  injectRepoMapContext,
880
+ persistCompactedSession,
856
881
  stripRepoMapMessages,
857
882
  ]);
858
883
  // ── Background task bar state (external store) ──────────
@@ -1665,7 +1690,7 @@ export function App(props) {
1665
1690
  const compacted = await compactConversation(messagesRef.current);
1666
1691
  if (compacted !== messagesRef.current) {
1667
1692
  messagesRef.current = compacted;
1668
- persistedIndexRef.current = 0; // Re-persist after compaction
1693
+ await persistCompactedSession(compacted);
1669
1694
  }
1670
1695
  return;
1671
1696
  }
@@ -2197,7 +2222,7 @@ export function App(props) {
2197
2222
  case "setup_hint":
2198
2223
  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));
2199
2224
  case "assistant":
2200
- return (_jsx(AssistantMessage, { text: item.text, thinking: item.thinking, thinkingMs: item.thinkingMs, showThinking: props.showThinking, planMode: item.planMode }, item.id));
2225
+ return (_jsx(AssistantMessage, { text: item.text, thinking: item.thinking, thinkingMs: item.thinkingMs, planMode: item.planMode }, item.id));
2201
2226
  case "tool_start":
2202
2227
  return (_jsx(ToolExecution, { status: "running", name: item.name, args: item.args, progressOutput: item.progressOutput }, item.id));
2203
2228
  case "tool_done":
@@ -2669,7 +2694,7 @@ export function App(props) {
2669
2694
  log("ERROR", "error", errMsg);
2670
2695
  setLiveItems((prev) => [...prev, toErrorItem(err, getId())]);
2671
2696
  });
2672
- } })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingRight: 1, children: [liveItems.map((item) => renderItem(item)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: agentLoop.streamingText, streamingThinking: agentLoop.streamingThinking, showThinking: props.showThinking, thinkingMs: agentLoop.thinkingMs, planMode: planMode })] }), agentLoop.isRunning && agentLoop.activityPhase !== "idle" ? (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: agentLoop.activityPhase === "thinking"
2697
+ } })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingRight: 1, children: [liveItems.map((item) => renderItem(item)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: agentLoop.streamingText, streamingThinking: agentLoop.streamingThinking, thinkingMs: agentLoop.thinkingMs, planMode: planMode })] }), agentLoop.isRunning && agentLoop.activityPhase !== "idle" ? (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: agentLoop.activityPhase === "thinking"
2673
2698
  ? THINKING_BORDER_COLORS[thinkingBorderFrame]
2674
2699
  : "transparent", paddingLeft: 1, paddingRight: 1, width: columns, children: _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), planMode: planMode, retryInfo: agentLoop.retryInfo, planDone: planSteps.filter((s) => s.completed).length, planTotal: planSteps.length }) })) : agentLoop.stallError ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: theme.warning, children: "⚠ API provider stream interrupted — retries exhausted." }), _jsx(Text, { color: theme.textDim, children: " Your conversation is preserved. Send a message to continue." })] })) : (doneStatus &&
2675
2700
  !agentLoop.isRunning && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.success, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] }) }))), agentLoop.queuedCount > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.accent, children: ["⏳ ", agentLoop.queuedCount, " message", agentLoop.queuedCount > 1 ? "s" : "", " queued"] }) })), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused && !overlay, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking, onToggleTasks: () => {