pi-goosedump 0.12.66 → 0.12.68

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 (2) hide show
  1. package/dist/index.ts +166 -86
  2. package/package.json +2 -2
package/dist/index.ts CHANGED
@@ -167,7 +167,8 @@ var GOOSE_PROVIDERS = [
167
167
  var SUMMARIZABLE_ENTRY_TYPES = new Set(["message", "custom_message", "branch_summary"]);
168
168
 
169
169
  // src/util.ts
170
- import { readFileSync } from "node:fs";
170
+ import { closeSync, openSync, readFileSync, readSync } from "node:fs";
171
+ import { StringDecoder } from "node:string_decoder";
171
172
  function isRecord(value) {
172
173
  return typeof value === "object" && value !== null && !Array.isArray(value);
173
174
  }
@@ -187,14 +188,56 @@ function compactStartedMessage(keep, queued = false) {
187
188
  const action = queued ? "Compaction queued with goosedump" : "Compacting with goosedump";
188
189
  return keep !== null ? `${action}; keeping the last ${keep} user turn${keep === 1 ? "" : "s"}.` : `${action} up to Pi's token-based cut.`;
189
190
  }
191
+ var FIRST_LINE_BUFFER_SIZE = 4096;
192
+ var MAX_FIRST_LINE_BYTES = 64 * 1024;
190
193
  function readFirstLine(path) {
194
+ let fd = null;
191
195
  try {
192
- const content = readFileSync(path, "utf8");
193
- const newline = content.indexOf(`
196
+ fd = openSync(path, "r");
197
+ const buffer = Buffer.alloc(FIRST_LINE_BUFFER_SIZE);
198
+ const decoder = new StringDecoder("utf8");
199
+ let totalText = "";
200
+ let offset = 0;
201
+ while (offset < MAX_FIRST_LINE_BYTES) {
202
+ const bytesRead = readSync(fd, buffer, 0, FIRST_LINE_BUFFER_SIZE, offset);
203
+ if (bytesRead === 0)
204
+ break;
205
+ offset += bytesRead;
206
+ const chunk = decoder.write(buffer.subarray(0, bytesRead));
207
+ const newline = chunk.indexOf(`
194
208
  `);
195
- return newline < 0 ? content : content.slice(0, newline);
196
- } catch {
209
+ if (newline >= 0) {
210
+ totalText += chunk.slice(0, newline);
211
+ return totalText.endsWith("\r") ? totalText.slice(0, -1) : totalText;
212
+ }
213
+ totalText += chunk;
214
+ if (bytesRead < FIRST_LINE_BUFFER_SIZE)
215
+ break;
216
+ }
217
+ totalText += decoder.end();
218
+ const finalNewline = totalText.indexOf(`
219
+ `);
220
+ const line = finalNewline >= 0 ? totalText.slice(0, finalNewline) : totalText;
221
+ if (line.length > 0) {
222
+ return line.endsWith("\r") ? line.slice(0, -1) : line;
223
+ }
197
224
  return null;
225
+ } catch {
226
+ try {
227
+ const content = readFileSync(path, "utf8");
228
+ const newline = content.indexOf(`
229
+ `);
230
+ const line = newline < 0 ? content : content.slice(0, newline);
231
+ return line.length > 0 ? line.endsWith("\r") ? line.slice(0, -1) : line : null;
232
+ } catch {
233
+ return null;
234
+ }
235
+ } finally {
236
+ if (fd !== null) {
237
+ try {
238
+ closeSync(fd);
239
+ } catch {}
240
+ }
198
241
  }
199
242
  }
200
243
  function formatTarget(provider, id) {
@@ -597,7 +640,12 @@ async function goosedumpCompact(target, options, signal, executablePath) {
597
640
  return { summary: output.stdout.trim(), warning: output.stderr.trim() };
598
641
  }
599
642
  function currentSessionTarget(ctx) {
600
- const sessionFile = ctx.sessionManager.getSessionFile();
643
+ const sessionManager = ctx.sessionManager;
644
+ const inMemoryId = sessionManager?.getSessionId?.() ?? sessionManager?.getHeader?.()?.id;
645
+ if (typeof inMemoryId === "string" && inMemoryId.trim().length > 0) {
646
+ return formatTarget("pi", inMemoryId.trim());
647
+ }
648
+ const sessionFile = sessionManager?.getSessionFile?.();
601
649
  if (!sessionFile)
602
650
  return null;
603
651
  const line = readFirstLine(sessionFile);
@@ -605,8 +653,8 @@ function currentSessionTarget(ctx) {
605
653
  return null;
606
654
  try {
607
655
  const entry = JSON.parse(line);
608
- if (entry.type === "session" && typeof entry.id === "string") {
609
- return formatTarget("pi", entry.id);
656
+ if (entry.type === "session" && typeof entry.id === "string" && entry.id.trim().length > 0) {
657
+ return formatTarget("pi", entry.id.trim());
610
658
  }
611
659
  } catch {
612
660
  return null;
@@ -618,7 +666,7 @@ function currentSessionTarget(ctx) {
618
666
  import { DEFAULT_COMPACTION_SETTINGS as DEFAULT_COMPACTION_SETTINGS2 } from "@earendil-works/pi-coding-agent";
619
667
 
620
668
  // src/compaction.ts
621
- import { findCutPoint } from "@earendil-works/pi-coding-agent";
669
+ import { findCutPoint, sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
622
670
 
623
671
  // src/settings.ts
624
672
  import { DEFAULT_COMPACTION_SETTINGS } from "@earendil-works/pi-coding-agent";
@@ -733,9 +781,6 @@ function writeJsonObjectAtomically(path, value) {
733
781
  throw error;
734
782
  }
735
783
  }
736
- function readGoosedumpSettingsFrom(path) {
737
- return pickValidGoosedumpSettings(readJsonObject(path).goosedump);
738
- }
739
784
  function goosedumpSettingValidationMessage(key) {
740
785
  const spec = GOOSEDUMP_SETTING_SPECS[key];
741
786
  if (spec.kind === "boolean")
@@ -756,12 +801,32 @@ function validateGoosedumpSettings(path) {
756
801
  }
757
802
  }
758
803
  }
759
- function resolveGoosedumpSettings(cwd, includeProject) {
760
- return {
804
+ var isNumberValue = (value) => typeof value === "number";
805
+ var isBooleanValue = (value) => typeof value === "boolean";
806
+ function resolveWorkspaceSettings(cwd, includeProject) {
807
+ const globalObj = readJsonObject(globalSettingsPath());
808
+ const projectObj = includeProject ? readJsonObject(projectSettingsPath(cwd)) : undefined;
809
+ const goosedump = {
761
810
  ...DEFAULT_GOOSEDUMP_SETTINGS,
762
- ...readGoosedumpSettingsFrom(globalSettingsPath()),
763
- ...includeProject ? readGoosedumpSettingsFrom(projectSettingsPath(cwd)) : {}
811
+ ...pickValidGoosedumpSettings(globalObj.goosedump),
812
+ ...projectObj ? pickValidGoosedumpSettings(projectObj.goosedump) : {}
764
813
  };
814
+ const projectCompaction = isRecord(projectObj?.compaction) ? projectObj.compaction : undefined;
815
+ const globalCompaction = isRecord(globalObj.compaction) ? globalObj.compaction : undefined;
816
+ const enabled = (isBooleanValue(projectCompaction?.enabled) ? projectCompaction.enabled : undefined) ?? (isBooleanValue(globalCompaction?.enabled) ? globalCompaction.enabled : undefined) ?? DEFAULT_COMPACTION_SETTINGS.enabled;
817
+ const keepRecentTokens = (isNumberValue(projectCompaction?.keepRecentTokens) ? projectCompaction.keepRecentTokens : undefined) ?? (isNumberValue(globalCompaction?.keepRecentTokens) ? globalCompaction.keepRecentTokens : undefined) ?? DEFAULT_COMPACTION_SETTINGS.keepRecentTokens;
818
+ const reserveTokens = (isNumberValue(projectCompaction?.reserveTokens) ? projectCompaction.reserveTokens : undefined) ?? (isNumberValue(globalCompaction?.reserveTokens) ? globalCompaction.reserveTokens : undefined) ?? DEFAULT_COMPACTION_SETTINGS.reserveTokens;
819
+ return {
820
+ goosedump,
821
+ compaction: {
822
+ enabled,
823
+ keepRecentTokens,
824
+ reserveTokens
825
+ }
826
+ };
827
+ }
828
+ function resolveGoosedumpSettings(cwd, includeProject) {
829
+ return resolveWorkspaceSettings(cwd, includeProject).goosedump;
765
830
  }
766
831
  function notifyInvalidSettings(ctx) {
767
832
  const paths = [
@@ -819,30 +884,13 @@ function clearScopedGoosedumpSetting(cwd, scope, key) {
819
884
  function formatCompactSetting(value) {
820
885
  return value === 0 ? "disabled" : String(value);
821
886
  }
822
- var isNumberValue = (value) => typeof value === "number";
823
- var isBooleanValue = (value) => typeof value === "boolean";
824
- function piCompactionValue(cwd, includeProject, key, is, fallback) {
825
- const paths = includeProject ? [projectSettingsPath(cwd), globalSettingsPath()] : [globalSettingsPath()];
826
- for (const path of paths) {
827
- const compaction = readJsonObject(path).compaction;
828
- const value = isRecord(compaction) ? compaction[key] : undefined;
829
- if (is(value))
830
- return value;
831
- }
832
- return fallback;
833
- }
834
887
  function piKeepRecentTokens(cwd, includeProject) {
835
- return piCompactionValue(cwd, includeProject, "keepRecentTokens", isNumberValue, DEFAULT_COMPACTION_SETTINGS.keepRecentTokens);
836
- }
837
- function piCompactionEnabled(cwd, includeProject) {
838
- return piCompactionValue(cwd, includeProject, "enabled", isBooleanValue, DEFAULT_COMPACTION_SETTINGS.enabled);
839
- }
840
- function piReserveTokens(cwd, includeProject) {
841
- return piCompactionValue(cwd, includeProject, "reserveTokens", isNumberValue, DEFAULT_COMPACTION_SETTINGS.reserveTokens);
888
+ return resolveWorkspaceSettings(cwd, includeProject).compaction.keepRecentTokens;
842
889
  }
843
890
  function effectiveSummaryMaxTokens(cwd, includeProject) {
844
- const configured = resolveGoosedumpSettings(cwd, includeProject).summaryMaxTokens;
845
- const reserveTokens = piReserveTokens(cwd, includeProject);
891
+ const settings = resolveWorkspaceSettings(cwd, includeProject);
892
+ const configured = settings.goosedump.summaryMaxTokens;
893
+ const reserveTokens = settings.compaction.reserveTokens;
846
894
  if (reserveTokens <= 0)
847
895
  return configured;
848
896
  return Math.max(1, Math.min(configured, Math.floor(reserveTokens * 0.8)));
@@ -858,6 +906,11 @@ function isMessageEntry(entry) {
858
906
  function isCompletedAssistant(message) {
859
907
  return message.role === "assistant" && message.stopReason !== "error" && message.stopReason !== "aborted";
860
908
  }
909
+ function hasCompactionMessage(entry) {
910
+ if (entry.type === "compaction")
911
+ return false;
912
+ return sessionEntryToContextMessages(entry).length > 0;
913
+ }
861
914
  function hasCompactableHistory(ctx) {
862
915
  const branch = ctx.sessionManager.getBranch();
863
916
  if (branch.length === 0)
@@ -868,17 +921,10 @@ function hasCompactableHistory(ctx) {
868
921
  const cut = findCutPoint(branch, boundaryStart, branch.length, piKeepRecentTokens(ctx.cwd, projectSettingsTrusted(ctx)));
869
922
  if (!branch[cut.firstKeptEntryIndex]?.id)
870
923
  return false;
871
- const historyEnd = cut.isSplitTurn ? cut.turnStartIndex : cut.firstKeptEntryIndex;
872
- for (let i = boundaryStart;i < historyEnd; i += 1) {
873
- if (SUMMARIZABLE_ENTRY_TYPES.has(branch[i].type))
924
+ for (let i = boundaryStart;i < cut.firstKeptEntryIndex; i += 1) {
925
+ if (hasCompactionMessage(branch[i]))
874
926
  return true;
875
927
  }
876
- if (cut.isSplitTurn) {
877
- for (let i = cut.turnStartIndex;i < cut.firstKeptEntryIndex; i += 1) {
878
- if (SUMMARIZABLE_ENTRY_TYPES.has(branch[i].type))
879
- return true;
880
- }
881
- }
882
928
  return false;
883
929
  }
884
930
  function latestCompaction(branchEntries) {
@@ -901,16 +947,11 @@ function activeHistoryStartIndex(branchEntries) {
901
947
  return compaction ? compactionBoundaryStartIndex(branchEntries, compaction) : 0;
902
948
  }
903
949
  function completedTurnsSinceCompaction(branchEntries) {
904
- let start = 0;
905
- for (let i = branchEntries.length - 1;i >= 0; i -= 1) {
906
- if (isCompactionEntry(branchEntries[i])) {
907
- start = i + 1;
908
- break;
909
- }
910
- }
911
950
  let completed = 0;
912
- for (let i = start;i < branchEntries.length; i += 1) {
951
+ for (let i = branchEntries.length - 1;i >= 0; i -= 1) {
913
952
  const entry = branchEntries[i];
953
+ if (isCompactionEntry(entry))
954
+ break;
914
955
  if (isMessageEntry(entry) && isCompletedAssistant(entry.message))
915
956
  completed += 1;
916
957
  }
@@ -929,26 +970,21 @@ function keepBoundaryId(branchEntries, keep) {
929
970
  }
930
971
  return;
931
972
  }
932
- function latestCompactionForRange(branchEntries, untilIndex) {
933
- for (let i = branchEntries.length - 1;i >= 0; i -= 1) {
934
- const entry = branchEntries[i];
935
- if (!isCompactionEntry(entry))
936
- continue;
937
- if (compactionBoundaryStartIndex(branchEntries, entry) < untilIndex)
938
- return entry;
939
- }
940
- return;
941
- }
942
- function compactionStartId(branchEntries, previousCompaction, untilIndex) {
943
- const boundaryStart = compactionBoundaryStartIndex(branchEntries, previousCompaction);
944
- return boundaryStart < untilIndex ? branchEntries[boundaryStart]?.id : undefined;
945
- }
946
973
  function buildCompactRange(branchEntries, firstKeptEntryId) {
947
974
  const untilIndex = branchEntries.findIndex((entry) => entry.id === firstKeptEntryId);
948
975
  if (untilIndex < 0)
949
976
  return;
950
- const previousCompaction = latestCompactionForRange(branchEntries, untilIndex);
951
- const from = previousCompaction ? compactionStartId(branchEntries, previousCompaction, untilIndex) : undefined;
977
+ let from;
978
+ for (let i = Math.min(untilIndex - 1, branchEntries.length - 1);i >= 0; i -= 1) {
979
+ const entry = branchEntries[i];
980
+ if (!isCompactionEntry(entry))
981
+ continue;
982
+ const boundaryStart = compactionBoundaryStartIndex(branchEntries, entry);
983
+ if (boundaryStart < untilIndex) {
984
+ from = branchEntries[boundaryStart]?.id;
985
+ break;
986
+ }
987
+ }
952
988
  return from && from !== firstKeptEntryId ? { scope: "lineage", from, until: firstKeptEntryId } : { scope: "lineage", until: firstKeptEntryId };
953
989
  }
954
990
  async function buildGoosedumpCompaction(target, preparation, branchEntries, summaryMaxTokens, keep, signal, executablePath) {
@@ -993,6 +1029,11 @@ function isCompactionCancellation(error) {
993
1029
  const code = error.code;
994
1030
  return error.name === "AbortError" || code === "ABORT_ERR" || isCompactionCancellationMessage(error.message);
995
1031
  }
1032
+ function isSessionTooSmallError(error) {
1033
+ if (!(error instanceof Error))
1034
+ return false;
1035
+ return /nothing to compact|session too small|already compacted/i.test(error.message);
1036
+ }
996
1037
 
997
1038
  class CompactionRuntime {
998
1039
  overrideDefaultCompaction;
@@ -1004,6 +1045,7 @@ class CompactionRuntime {
1004
1045
  piCompactionReserveTokens = DEFAULT_COMPACTION_SETTINGS2.reserveTokens;
1005
1046
  turnsRemaining = 0;
1006
1047
  counterTriggered = false;
1048
+ smallSessionDisarmed = false;
1007
1049
  compactionState = { phase: "idle" };
1008
1050
  sessionGeneration = 0;
1009
1051
  settlementGeneration = 0;
@@ -1023,6 +1065,7 @@ class CompactionRuntime {
1023
1065
  this.activePi = pi;
1024
1066
  }
1025
1067
  requestCompaction(ctx, keep) {
1068
+ this.smallSessionDisarmed = false;
1026
1069
  if (this.compactionState.phase !== "idle")
1027
1070
  return "busy";
1028
1071
  if (!this.requestHasCompactableHistory(ctx, keep))
@@ -1042,14 +1085,17 @@ class CompactionRuntime {
1042
1085
  }
1043
1086
  syncCompactCounters(ctx) {
1044
1087
  const projectTrusted = projectSettingsTrusted(ctx);
1045
- this.compactSettings = resolveGoosedumpSettings(ctx.cwd, projectTrusted);
1046
- this.piAutoCompactionEnabled = piCompactionEnabled(ctx.cwd, projectTrusted);
1047
- this.piCompactionReserveTokens = piReserveTokens(ctx.cwd, projectTrusted);
1088
+ const resolved = resolveWorkspaceSettings(ctx.cwd, projectTrusted);
1089
+ this.compactSettings = resolved.goosedump;
1090
+ this.piAutoCompactionEnabled = resolved.compaction.enabled;
1091
+ this.piCompactionReserveTokens = resolved.compaction.reserveTokens;
1048
1092
  const completedTurns = completedTurnsSinceCompaction(ctx.sessionManager.getBranch());
1049
1093
  this.turnsRemaining = Math.max(0, this.compactSettings.turnsBeforeCompact - completedTurns);
1050
1094
  this.counterTriggered = this.compactSettings.turnsBeforeCompact > 0 && completedTurns >= this.compactSettings.turnsBeforeCompact;
1051
1095
  }
1052
1096
  updateStatus(ctx) {
1097
+ if (!ctx.hasUI)
1098
+ return;
1053
1099
  const active = this.turnCompactionEnabled();
1054
1100
  let dotColor = "success";
1055
1101
  if (active) {
@@ -1060,10 +1106,17 @@ class CompactionRuntime {
1060
1106
  dotColor = "warning";
1061
1107
  }
1062
1108
  }
1063
- const dot = ctx.ui.theme.fg(dotColor, "●");
1064
1109
  const counter = active ? Math.max(0, this.turnsRemaining).toString(16).toUpperCase().padStart(2, "0") : "--";
1065
1110
  const activity = this.compactionState.phase === "queued" ? " queued" : this.compactionState.phase === "running" ? " compacting" : "";
1066
- const label = ctx.ui.theme.fg("text", `${ctx.ui.theme.bold?.("GD") ?? "GD"}:${counter}${activity}`);
1111
+ let dot = "●";
1112
+ let label = `GD:${counter}${activity}`;
1113
+ try {
1114
+ if (ctx.ui?.theme) {
1115
+ dot = ctx.ui.theme.fg(dotColor, "●");
1116
+ const boldGd = ctx.ui.theme.bold?.("GD") ?? "GD";
1117
+ label = ctx.ui.theme.fg("text", `${boldGd}:${counter}${activity}`);
1118
+ }
1119
+ } catch {}
1067
1120
  ctx.ui.setStatus("goosedump", `${dot} ${label}`);
1068
1121
  }
1069
1122
  beginSession(ctx) {
@@ -1072,6 +1125,7 @@ class CompactionRuntime {
1072
1125
  this.activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
1073
1126
  this.sessionActive = true;
1074
1127
  this.compactionState = { phase: "idle" };
1128
+ this.smallSessionDisarmed = false;
1075
1129
  this.expectedTurnBoundaryAbort = false;
1076
1130
  this.syncCompactCounters(ctx);
1077
1131
  this.updateStatus(ctx);
@@ -1084,6 +1138,7 @@ class CompactionRuntime {
1084
1138
  this.activeSessionFile = null;
1085
1139
  this.sessionActive = false;
1086
1140
  this.compactionState = { phase: "idle" };
1141
+ this.smallSessionDisarmed = false;
1087
1142
  this.expectedTurnBoundaryAbort = false;
1088
1143
  }
1089
1144
  onAgentStart(ctx) {
@@ -1308,11 +1363,13 @@ class CompactionRuntime {
1308
1363
  }
1309
1364
  resetCompactCounters(ctx) {
1310
1365
  const projectTrusted = projectSettingsTrusted(ctx);
1311
- this.compactSettings = resolveGoosedumpSettings(ctx.cwd, projectTrusted);
1312
- this.piAutoCompactionEnabled = piCompactionEnabled(ctx.cwd, projectTrusted);
1313
- this.piCompactionReserveTokens = piReserveTokens(ctx.cwd, projectTrusted);
1366
+ const resolved = resolveWorkspaceSettings(ctx.cwd, projectTrusted);
1367
+ this.compactSettings = resolved.goosedump;
1368
+ this.piAutoCompactionEnabled = resolved.compaction.enabled;
1369
+ this.piCompactionReserveTokens = resolved.compaction.reserveTokens;
1314
1370
  this.turnsRemaining = this.compactSettings.turnsBeforeCompact;
1315
1371
  this.counterTriggered = false;
1372
+ this.smallSessionDisarmed = false;
1316
1373
  }
1317
1374
  turnCompactionEnabled() {
1318
1375
  return this.overrideDefaultCompaction && this.piAutoCompactionEnabled && this.compactSettings.turnsBeforeCompact > 0;
@@ -1331,6 +1388,7 @@ class CompactionRuntime {
1331
1388
  noteCompletedTurn(ctx) {
1332
1389
  if (!this.overrideDefaultCompaction)
1333
1390
  return;
1391
+ this.smallSessionDisarmed = false;
1334
1392
  this.syncCompactCounters(ctx);
1335
1393
  this.updateStatus(ctx);
1336
1394
  }
@@ -1390,14 +1448,19 @@ class CompactionRuntime {
1390
1448
  }, { once: true });
1391
1449
  }
1392
1450
  requestHasCompactableHistory(ctx, keep) {
1393
- return keep === null ? hasCompactableHistory(ctx) : keepBoundaryId(ctx.sessionManager.getBranch(), keep) !== undefined;
1451
+ if (!hasCompactableHistory(ctx))
1452
+ return false;
1453
+ return keep === null || keepBoundaryId(ctx.sessionManager.getBranch(), keep) !== undefined;
1394
1454
  }
1395
1455
  queueTurnCompaction(ctx, eligibleSettlement, resumeAfter = false) {
1396
- if (!this.turnCompactionEnabled() || !this.counterTriggered || this.compactionState.phase !== "idle") {
1456
+ if (!this.turnCompactionEnabled() || !this.counterTriggered || this.smallSessionDisarmed || this.compactionState.phase !== "idle") {
1397
1457
  return;
1398
1458
  }
1399
- if (!hasCompactableHistory(ctx))
1459
+ if (!hasCompactableHistory(ctx)) {
1460
+ this.counterTriggered = false;
1461
+ this.smallSessionDisarmed = true;
1400
1462
  return;
1463
+ }
1401
1464
  this.setCompactionState(ctx, {
1402
1465
  phase: "queued",
1403
1466
  request: {
@@ -1425,6 +1488,10 @@ class CompactionRuntime {
1425
1488
  if (!ctx.isIdle())
1426
1489
  return false;
1427
1490
  if (!this.requestHasCompactableHistory(ctx, request.keep)) {
1491
+ if (request.origin === "turn") {
1492
+ this.counterTriggered = false;
1493
+ this.smallSessionDisarmed = true;
1494
+ }
1428
1495
  this.setCompactionState(ctx, { phase: "idle" });
1429
1496
  return false;
1430
1497
  }
@@ -1453,8 +1520,12 @@ class CompactionRuntime {
1453
1520
  return;
1454
1521
  this.setCompactionState(ctx, { phase: "idle" });
1455
1522
  this.syncCompactCounters(ctx);
1523
+ if (isSessionTooSmallError(error)) {
1524
+ this.counterTriggered = false;
1525
+ this.smallSessionDisarmed = true;
1526
+ }
1456
1527
  this.updateStatus(ctx);
1457
- if (isCompactionCancellation(error))
1528
+ if (isCompactionCancellation(error) || isSessionTooSmallError(error))
1458
1529
  return;
1459
1530
  const message = error instanceof Error ? error.message : String(error);
1460
1531
  if (ctx.hasUI)
@@ -1576,13 +1647,22 @@ var MEMORY_ACTIVITY_STATUS_KEY = "goosedump-memory-activity";
1576
1647
  function showMemoryActivity(ctx) {
1577
1648
  if (!ctx.hasUI)
1578
1649
  return;
1579
- const dot = ctx.ui.theme.fg("accent", "●");
1580
- const label = ctx.ui.theme.fg("muted", "remembering");
1650
+ let dot = "●";
1651
+ let label = "remembering";
1652
+ try {
1653
+ if (ctx.ui?.theme) {
1654
+ dot = ctx.ui.theme.fg("accent", "●");
1655
+ label = ctx.ui.theme.fg("muted", "remembering");
1656
+ }
1657
+ } catch {}
1581
1658
  ctx.ui.setStatus(MEMORY_ACTIVITY_STATUS_KEY, `${dot} ${label}`);
1582
1659
  }
1583
1660
  function hideMemoryActivity(ctx) {
1584
- if (ctx.hasUI)
1585
- ctx.ui.setStatus(MEMORY_ACTIVITY_STATUS_KEY, undefined);
1661
+ if (ctx.hasUI) {
1662
+ try {
1663
+ ctx.ui.setStatus(MEMORY_ACTIVITY_STATUS_KEY, undefined);
1664
+ } catch {}
1665
+ }
1586
1666
  }
1587
1667
 
1588
1668
  // src/policy.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.12.66",
3
+ "version": "0.12.68",
4
4
  "description": "Pi extension for goosedump session search, durable memory, session management, and compaction",
5
5
  "keywords": [
6
6
  "compaction",
@@ -37,7 +37,7 @@
37
37
  "ci:test": "npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@jarkkojs/goosedump-api": "^0.12.66"
40
+ "@jarkkojs/goosedump-api": "^0.12.68"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@earendil-works/pi-coding-agent": "^0.84.2",