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.
- package/dist/index.ts +166 -86
- 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
|
-
|
|
193
|
-
const
|
|
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
|
-
|
|
196
|
-
|
|
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
|
|
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
|
-
|
|
760
|
-
|
|
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
|
-
...
|
|
763
|
-
...
|
|
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
|
|
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
|
|
845
|
-
const
|
|
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
|
-
|
|
872
|
-
|
|
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 =
|
|
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
|
-
|
|
951
|
-
|
|
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
|
-
|
|
1046
|
-
this.
|
|
1047
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
1312
|
-
this.
|
|
1313
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
1580
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
40
|
+
"@jarkkojs/goosedump-api": "^0.12.68"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": "^0.84.2",
|