@kenkaiiii/gg-boss 4.8.0 → 4.8.2

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.
@@ -74730,7 +74730,9 @@ var SettingsSchema = external_exports.object({
74730
74730
  ]).default("auto"),
74731
74731
  showTokenUsage: external_exports.boolean().default(true),
74732
74732
  idealReviewEnabled: external_exports.boolean().default(true),
74733
- enabledTools: external_exports.array(external_exports.string()).optional()
74733
+ enabledTools: external_exports.array(external_exports.string()).optional(),
74734
+ /** Delete session transcripts older than this many days at startup. 0 disables pruning. */
74735
+ sessionRetentionDays: external_exports.number().int().min(0).default(30)
74734
74736
  });
74735
74737
  var DEFAULT_SETTINGS = {
74736
74738
  autoCompact: true,
@@ -74740,7 +74742,8 @@ var DEFAULT_SETTINGS = {
74740
74742
  thinkingEnabled: false,
74741
74743
  theme: "auto",
74742
74744
  showTokenUsage: true,
74743
- idealReviewEnabled: true
74745
+ idealReviewEnabled: true,
74746
+ sessionRetentionDays: 30
74744
74747
  };
74745
74748
  var SettingsManager = class {
74746
74749
  settings = { ...DEFAULT_SETTINGS };
@@ -74792,9 +74795,29 @@ function encodeCwd(cwd2) {
74792
74795
  }
74793
74796
  var SessionManager = class _SessionManager {
74794
74797
  sessionsDir;
74798
+ warnedPersistCodes = /* @__PURE__ */ new Set();
74799
+ /** Called once per error code when session persistence fails (e.g. ENOSPC). */
74800
+ onPersistError;
74795
74801
  constructor(sessionsDir) {
74796
74802
  this.sessionsDir = sessionsDir;
74797
74803
  }
74804
+ /**
74805
+ * Session persistence must never crash a live session. Disk-full (ENOSPC),
74806
+ * permission, or quota errors during transcript writes are reported once
74807
+ * per error code and otherwise swallowed — the in-memory session keeps going.
74808
+ */
74809
+ handlePersistError(error51, op) {
74810
+ const err = error51;
74811
+ const code = err?.code ?? "UNKNOWN";
74812
+ if (this.warnedPersistCodes.has(code))
74813
+ return;
74814
+ this.warnedPersistCodes.add(code);
74815
+ log("WARN", "session", `Session persistence failed (${op}); continuing without saving`, {
74816
+ code,
74817
+ message: err?.message ?? String(error51)
74818
+ });
74819
+ this.onPersistError?.(err);
74820
+ }
74798
74821
  dirForCwd(cwd2) {
74799
74822
  return path27.join(this.sessionsDir, encodeCwd(cwd2));
74800
74823
  }
@@ -74923,10 +74946,76 @@ var SessionManager = class _SessionManager {
74923
74946
  const sessions = await this.list(cwd2);
74924
74947
  return sessions.find((session) => session.id === sessionId2)?.path ?? null;
74925
74948
  }
74949
+ /**
74950
+ * Delete session files older than `maxAgeDays` across ALL project dirs.
74951
+ * Age is judged by file mtime, so a session that's still being appended to
74952
+ * is never considered old. Best-effort: per-file errors are skipped so a
74953
+ * locked or vanished file can't break startup. Empty project dirs left
74954
+ * behind are removed. Returns what was freed for logging.
74955
+ */
74956
+ async pruneOldSessions(options) {
74957
+ const result = { deletedFiles: 0, freedBytes: 0 };
74958
+ if (options.maxAgeDays <= 0)
74959
+ return result;
74960
+ const cutoffMs = Date.now() - options.maxAgeDays * 864e5;
74961
+ const keep = new Set((options.keepPaths ?? []).map((p) => path27.resolve(p)));
74962
+ let cwdDirs;
74963
+ try {
74964
+ cwdDirs = await fs23.readdir(this.sessionsDir);
74965
+ } catch {
74966
+ return result;
74967
+ }
74968
+ for (const dirName of cwdDirs) {
74969
+ const dir = path27.join(this.sessionsDir, dirName);
74970
+ let files;
74971
+ try {
74972
+ const stat = await fs23.stat(dir);
74973
+ if (!stat.isDirectory())
74974
+ continue;
74975
+ files = await fs23.readdir(dir);
74976
+ } catch {
74977
+ continue;
74978
+ }
74979
+ let remaining = files.length;
74980
+ for (const file2 of files) {
74981
+ if (!file2.endsWith(".jsonl"))
74982
+ continue;
74983
+ const filePath = path27.join(dir, file2);
74984
+ if (keep.has(path27.resolve(filePath)))
74985
+ continue;
74986
+ try {
74987
+ const stat = await fs23.stat(filePath);
74988
+ if (stat.mtimeMs >= cutoffMs)
74989
+ continue;
74990
+ await fs23.unlink(filePath);
74991
+ result.deletedFiles += 1;
74992
+ result.freedBytes += stat.size;
74993
+ remaining -= 1;
74994
+ } catch {
74995
+ }
74996
+ }
74997
+ if (remaining === 0) {
74998
+ await fs23.rmdir(dir).catch(() => {
74999
+ });
75000
+ }
75001
+ }
75002
+ return result;
75003
+ }
74926
75004
  async appendEntry(sessionPath, entry) {
74927
- await fs23.appendFile(sessionPath, JSON.stringify(entry) + "\n", "utf-8");
75005
+ try {
75006
+ await fs23.appendFile(sessionPath, JSON.stringify(entry) + "\n", "utf-8");
75007
+ } catch (error51) {
75008
+ this.handlePersistError(error51, "appendEntry");
75009
+ }
74928
75010
  }
74929
75011
  async updateLeaf(sessionPath, leafId) {
75012
+ try {
75013
+ await this.updateLeafUnsafe(sessionPath, leafId);
75014
+ } catch (error51) {
75015
+ this.handlePersistError(error51, "updateLeaf");
75016
+ }
75017
+ }
75018
+ async updateLeafUnsafe(sessionPath, leafId) {
74930
75019
  const fd2 = await fs23.open(sessionPath, "r+");
74931
75020
  try {
74932
75021
  const buf = Buffer.alloc(4096);
@@ -107605,12 +107694,40 @@ function renderMarkdownToAnsiLines({ text, theme, width, isPending = false, avai
107605
107694
  if (tableHeaders.length > 0 && tableRows.length > 0) {
107606
107695
  const styledHeaders = tableHeaders.map((header) => renderInlineMarkdownToAnsi(stripUnsafeCharacters(header), theme, theme.link));
107607
107696
  const styledRows = tableRows.map((row) => row.map((cell) => renderInlineMarkdownToAnsi(stripUnsafeCharacters(cell), theme, theme.text)));
107608
- addLines(renderAnsiTable({ headers: styledHeaders, rows: styledRows, terminalWidth: width, theme }));
107697
+ const tableLines = renderAnsiTable({
107698
+ headers: styledHeaders,
107699
+ rows: styledRows,
107700
+ terminalWidth: width,
107701
+ theme
107702
+ });
107703
+ if (isPending && availableTerminalHeight !== void 0) {
107704
+ const reservedLines = 2;
107705
+ const maxTableLinesWhenPending = Math.max(0, availableTerminalHeight - reservedLines);
107706
+ if (tableLines.length > maxTableLinesWhenPending) {
107707
+ if (maxTableLinesWhenPending < 1) {
107708
+ addLines([colorize3("... table is being written ...", theme.textMuted)]);
107709
+ } else {
107710
+ addLines(tableLines.slice(0, maxTableLinesWhenPending));
107711
+ addLines([colorize3("... generating more ...", theme.textMuted)]);
107712
+ }
107713
+ inTable = false;
107714
+ tableRows = [];
107715
+ tableHeaders = [];
107716
+ return;
107717
+ }
107718
+ }
107719
+ addLines(tableLines);
107609
107720
  }
107610
107721
  inTable = false;
107611
107722
  tableRows = [];
107612
107723
  tableHeaders = [];
107613
107724
  };
107725
+ let pendingTableTailStart = lines.length;
107726
+ if (isPending) {
107727
+ while (pendingTableTailStart > 0 && /^\s*\|/.test(lines[pendingTableTailStart - 1] ?? "") && lines.length - pendingTableTailStart < 2) {
107728
+ pendingTableTailStart -= 1;
107729
+ }
107730
+ }
107614
107731
  lines.forEach((line, index) => {
107615
107732
  if (inCodeBlock) {
107616
107733
  const fenceMatch = line.match(codeFenceRegex);
@@ -107641,7 +107758,7 @@ function renderMarkdownToAnsiLines({ text, theme, width, isPending = false, avai
107641
107758
  inTable = true;
107642
107759
  tableHeaders = tableRowMatch[1]?.split("|").map((cell) => cell.trim()) ?? [];
107643
107760
  tableRows = [];
107644
- } else {
107761
+ } else if (index < pendingTableTailStart) {
107645
107762
  addInlineLine(line);
107646
107763
  }
107647
107764
  } else if (inTable && tableSeparatorMatch) {
@@ -107653,6 +107770,9 @@ function renderMarkdownToAnsiLines({ text, theme, width, isPending = false, avai
107653
107770
  cells.length = tableHeaders.length;
107654
107771
  tableRows.push(cells);
107655
107772
  } else if (inTable && !tableRowMatch) {
107773
+ if (index >= pendingTableTailStart) {
107774
+ return;
107775
+ }
107656
107776
  flushTable();
107657
107777
  if (line.trim().length > 0)
107658
107778
  addInlineLine(line);
@@ -107678,7 +107798,7 @@ function renderMarkdownToAnsiLines({ text, theme, width, isPending = false, avai
107678
107798
  output.push(EMPTY_RENDER_LINE);
107679
107799
  lastLineEmpty = true;
107680
107800
  }
107681
- } else {
107801
+ } else if (index < pendingTableTailStart) {
107682
107802
  addInlineLine(line);
107683
107803
  }
107684
107804
  });
@@ -114607,4 +114727,4 @@ react/cjs/react-jsx-runtime.development.js:
114607
114727
  * LICENSE file in the root directory of this source tree.
114608
114728
  *)
114609
114729
  */
114610
- //# sourceMappingURL=chunk-JZC6MVWQ.js.map
114730
+ //# sourceMappingURL=chunk-ROHVABKQ.js.map