@kenkaiiii/ggcoder 4.3.196 → 4.3.198

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 (45) hide show
  1. package/dist/cli.js +18 -4
  2. package/dist/cli.js.map +1 -1
  3. package/dist/core/agent-session.d.ts +5 -1
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +28 -13
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction/compactor.d.ts +2 -0
  8. package/dist/core/compaction/compactor.d.ts.map +1 -1
  9. package/dist/core/compaction/compactor.js +6 -1
  10. package/dist/core/compaction/compactor.js.map +1 -1
  11. package/dist/core/index.d.ts +1 -1
  12. package/dist/core/index.d.ts.map +1 -1
  13. package/dist/core/index.js +1 -1
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/model-registry.d.ts +12 -1
  16. package/dist/core/model-registry.d.ts.map +1 -1
  17. package/dist/core/model-registry.js +13 -3
  18. package/dist/core/model-registry.js.map +1 -1
  19. package/dist/core/model-registry.test.d.ts +2 -0
  20. package/dist/core/model-registry.test.d.ts.map +1 -0
  21. package/dist/core/model-registry.test.js +19 -0
  22. package/dist/core/model-registry.test.js.map +1 -0
  23. package/dist/core/session-compaction.d.ts +15 -0
  24. package/dist/core/session-compaction.d.ts.map +1 -0
  25. package/dist/core/session-compaction.js +31 -0
  26. package/dist/core/session-compaction.js.map +1 -0
  27. package/dist/core/session-compaction.test.d.ts +2 -0
  28. package/dist/core/session-compaction.test.d.ts.map +1 -0
  29. package/dist/core/session-compaction.test.js +70 -0
  30. package/dist/core/session-compaction.test.js.map +1 -0
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/interactive.d.ts.map +1 -1
  36. package/dist/interactive.js +4 -2
  37. package/dist/interactive.js.map +1 -1
  38. package/dist/ui/App.d.ts.map +1 -1
  39. package/dist/ui/App.js +69 -23
  40. package/dist/ui/App.js.map +1 -1
  41. package/dist/ui/components/Footer.d.ts +3 -1
  42. package/dist/ui/components/Footer.d.ts.map +1 -1
  43. package/dist/ui/components/Footer.js +4 -4
  44. package/dist/ui/components/Footer.js.map +1 -1
  45. package/package.json +3 -3
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";
@@ -455,6 +456,7 @@ export function App(props) {
455
456
  const activeApiKey = currentCreds?.accessToken ?? props.apiKey;
456
457
  const activeAccountId = currentCreds?.accountId ?? props.accountId;
457
458
  const activeBaseUrl = currentCreds?.baseUrl ?? props.baseUrl;
459
+ const contextWindowOptions = useMemo(() => ({ provider: currentProvider, accountId: activeAccountId }), [currentProvider, activeAccountId]);
458
460
  // Load git branch — re-runs whenever the displayed cwd changes (e.g. when
459
461
  // a pixel fix moves the agent into a different project root).
460
462
  useEffect(() => {
@@ -639,27 +641,42 @@ export function App(props) {
639
641
  };
640
642
  }
641
643
  }, [props.onExitPlanRef, replaceSystemPrompt, stdout]);
642
- 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) => {
643
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 () => {
644
669
  const sp = sessionPathRef.current;
645
- if (!sm || !sp)
670
+ if (!sp)
646
671
  return;
647
672
  const allMsgs = messagesRef.current;
648
- for (let i = persistedIndexRef.current; i < allMsgs.length; i++) {
649
- const msg = allMsgs[i];
650
- if (msg.role === "system")
651
- continue;
652
- const entry = {
653
- type: "message",
654
- id: crypto.randomUUID(),
655
- parentId: null,
656
- timestamp: new Date().toISOString(),
657
- message: msg,
658
- };
659
- await sm.appendEntry(sp, entry);
660
- }
673
+ await appendMessagesToSession(sp, allMsgs, persistedIndexRef.current);
661
674
  persistedIndexRef.current = allMsgs.length;
662
- }, []);
675
+ if (sessionStore) {
676
+ sessionStore.messages = [...allMsgs];
677
+ sessionStore.sessionPath = sp;
678
+ }
679
+ }, [appendMessagesToSession, sessionStore]);
663
680
  /**
664
681
  * Run the language detector against the current cwd. If the detected set is a
665
682
  * strict superset of what's already injected, rebuild the system prompt with
@@ -695,7 +712,7 @@ export function App(props) {
695
712
  }
696
713
  }, [props.settingsFile]);
697
714
  const compactConversation = useCallback(async (messages) => {
698
- const contextWindow = getContextWindow(currentModel);
715
+ const contextWindow = getContextWindow(currentModel, contextWindowOptions);
699
716
  const tokensBefore = estimateConversationTokens(messages);
700
717
  const spinId = getId();
701
718
  log("INFO", "compaction", `Running compaction`, {
@@ -708,14 +725,20 @@ export function App(props) {
708
725
  try {
709
726
  // Resolve fresh credentials for compaction too
710
727
  let compactApiKey = activeApiKey;
728
+ let compactAccountId = activeAccountId;
729
+ let compactBaseUrl = activeBaseUrl;
711
730
  if (props.authStorage) {
712
731
  const creds = await props.authStorage.resolveCredentials(currentProvider);
713
732
  compactApiKey = creds.accessToken;
733
+ compactAccountId = creds.accountId;
734
+ compactBaseUrl = creds.baseUrl ?? compactBaseUrl;
714
735
  }
715
736
  const result = await compact(messages, {
716
737
  provider: currentProvider,
717
738
  model: currentModel,
718
739
  apiKey: compactApiKey,
740
+ accountId: compactAccountId,
741
+ baseUrl: compactBaseUrl,
719
742
  contextWindow,
720
743
  signal: undefined,
721
744
  approvedPlanPath: approvedPlanPathRef.current,
@@ -747,7 +770,15 @@ export function App(props) {
747
770
  setLiveItems((prev) => prev.map((item) => item.id === spinId ? toErrorItem(err, spinId, "Compaction failed") : item));
748
771
  return messages; // Return unchanged on failure
749
772
  }
750
- }, [currentModel, currentProvider, activeApiKey]);
773
+ }, [
774
+ currentModel,
775
+ currentProvider,
776
+ activeApiKey,
777
+ activeAccountId,
778
+ activeBaseUrl,
779
+ contextWindowOptions,
780
+ props.authStorage,
781
+ ]);
751
782
  const getRepoMapSignalCount = useCallback(() => {
752
783
  return ((props.repoMapChangedFilesRef?.current.size ?? 0) +
753
784
  (props.repoMapReadFilesRef?.current.size ?? 0));
@@ -812,6 +843,10 @@ export function App(props) {
812
843
  // Force-compact on context overflow regardless of settings
813
844
  if (options?.force) {
814
845
  const result = await compactConversation(stripped);
846
+ if (result !== stripped) {
847
+ messagesRef.current = result;
848
+ await persistCompactedSession(result);
849
+ }
815
850
  lastCompactionTimeRef.current = Date.now();
816
851
  return injectRepoMapContext(result);
817
852
  }
@@ -822,18 +857,29 @@ export function App(props) {
822
857
  log("INFO", "compaction", `Skipping compaction — cooldown active`);
823
858
  return injectRepoMapContext(stripped);
824
859
  }
825
- const contextWindow = getContextWindow(currentModel);
860
+ const contextWindow = getContextWindow(currentModel, contextWindowOptions);
826
861
  const modelInfo = getModel(currentModel);
827
862
  const reserveTokens = (modelInfo?.maxOutputTokens ?? 0) + 5_000;
828
863
  const tokensFresh = lastActualTokensTimestampRef.current > lastCompactionTimeRef.current;
829
864
  const actualTokens = lastActualTokensRef.current > 0 && tokensFresh ? lastActualTokensRef.current : undefined;
830
865
  if (shouldCompact(stripped, contextWindow, threshold, actualTokens, reserveTokens)) {
831
866
  const result = await compactConversation(stripped);
867
+ if (result !== stripped) {
868
+ messagesRef.current = result;
869
+ await persistCompactedSession(result);
870
+ }
832
871
  lastCompactionTimeRef.current = Date.now();
833
872
  return injectRepoMapContext(result);
834
873
  }
835
874
  return injectRepoMapContext(stripped);
836
- }, [currentModel, compactConversation, injectRepoMapContext, stripRepoMapMessages]);
875
+ }, [
876
+ currentModel,
877
+ compactConversation,
878
+ contextWindowOptions,
879
+ injectRepoMapContext,
880
+ persistCompactedSession,
881
+ stripRepoMapMessages,
882
+ ]);
837
883
  // ── Background task bar state (external store) ──────────
838
884
  const { bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, } = useTaskBarStore();
839
885
  useTaskBarPolling(props.processManager);
@@ -1644,7 +1690,7 @@ export function App(props) {
1644
1690
  const compacted = await compactConversation(messagesRef.current);
1645
1691
  if (compacted !== messagesRef.current) {
1646
1692
  messagesRef.current = compacted;
1647
- persistedIndexRef.current = 0; // Re-persist after compaction
1693
+ await persistCompactedSession(compacted);
1648
1694
  }
1649
1695
  return;
1650
1696
  }
@@ -2709,7 +2755,7 @@ export function App(props) {
2709
2755
  id: getId(),
2710
2756
  },
2711
2757
  ]);
2712
- }, cwd: props.cwd, commands: allCommands, eyesCount: eyesCount }), 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 })) : (_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, cwd: displayedCwd, gitBranch: gitBranch, thinkingLevel: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined, planMode: planMode, exitPending: exitPending })), (bgTasks.length > 0 || (eyesCount !== undefined && eyesCount > 0) || updatePending) && (_jsxs(Box, { children: [bgTasks.length > 0 && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate })), eyesCount !== undefined && eyesCount > 0 && (_jsx(Box, { paddingLeft: bgTasks.length > 0 ? 2 : 1, paddingRight: 1, children: _jsx(Text, { color: theme.accent, bold: true, children: `${eyesCount} eyes signal${eyesCount === 1 ? "" : "s"} · Run /eyes-improve to enhance GG Coder` }) })), updatePending && (_jsx(Box, { paddingLeft: bgTasks.length > 0 || (eyesCount !== undefined && eyesCount > 0) ? 2 : 1, paddingRight: 1, children: _jsx(Text, { color: theme.success, bold: true, children: "\u2728 Update ready \u00B7 restart to apply" }) }))] }))] }))] }));
2758
+ }, cwd: props.cwd, commands: allCommands, eyesCount: eyesCount }), 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 })) : (_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, contextWindowOptions: contextWindowOptions, cwd: displayedCwd, gitBranch: gitBranch, thinkingLevel: thinkingEnabled ? getMaxThinkingLevel(currentModel) : undefined, planMode: planMode, exitPending: exitPending })), (bgTasks.length > 0 || (eyesCount !== undefined && eyesCount > 0) || updatePending) && (_jsxs(Box, { children: [bgTasks.length > 0 && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate })), eyesCount !== undefined && eyesCount > 0 && (_jsx(Box, { paddingLeft: bgTasks.length > 0 ? 2 : 1, paddingRight: 1, children: _jsx(Text, { color: theme.accent, bold: true, children: `${eyesCount} eyes signal${eyesCount === 1 ? "" : "s"} · Run /eyes-improve to enhance GG Coder` }) })), updatePending && (_jsx(Box, { paddingLeft: bgTasks.length > 0 || (eyesCount !== undefined && eyesCount > 0) ? 2 : 1, paddingRight: 1, children: _jsx(Text, { color: theme.success, bold: true, children: "\u2728 Update ready \u00B7 restart to apply" }) }))] }))] }))] }));
2713
2759
  }
2714
2760
  function formatRepoMapCommandOutput(enabled, markdown, refreshed) {
2715
2761
  const status = enabled ? "on" : "off";