pi-goosedump 0.12.15 → 0.12.17
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/README.md +5 -4
- package/dist/index.ts +118 -56
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -97,10 +97,11 @@ compaction. Each completed model response counts as one turn, including response
|
|
|
97
97
|
that call tools. The countdown is restored when a session resumes and appears in
|
|
98
98
|
the footer with a status dot (green when >25% turns remain, yellow when ≤25%, red
|
|
99
99
|
when ≤12.5%) followed by a hexadecimal countdown. `● GD:0A` means ten turns
|
|
100
|
-
remain, `● GD:00` is ready to compact, and `● GD:--` is disabled.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
remain, `● GD:00` is ready to compact, and `● GD:--` is disabled. The footer
|
|
101
|
+
adds `queued` while compaction is waiting for the active agent run to settle and
|
|
102
|
+
`compacting` while the summary is being built. Pi remains the sole scheduler for
|
|
103
|
+
its normal context threshold. Whichever limit is reached first compacts once,
|
|
104
|
+
and every successful compaction resets the countdown. A failed or cancelled
|
|
104
105
|
compaction leaves the counter armed at zero and is not retried in the same
|
|
105
106
|
settlement.
|
|
106
107
|
|
package/dist/index.ts
CHANGED
|
@@ -1467,9 +1467,14 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1467
1467
|
}
|
|
1468
1468
|
const dot = ctx.ui.theme.fg(dotColor, "●");
|
|
1469
1469
|
const counter = active ? Math.max(0, turnsRemaining).toString(16).toUpperCase().padStart(2, "0") : "--";
|
|
1470
|
-
const
|
|
1470
|
+
const activity = compactionState.phase === "queued" ? " queued" : compactionState.phase === "running" ? " compacting" : "";
|
|
1471
|
+
const label = ctx.ui.theme.fg("text", `${ctx.ui.theme.bold?.("GD") ?? "GD"}:${counter}${activity}`);
|
|
1471
1472
|
ctx.ui.setStatus("goosedump", `${dot} ${label}`);
|
|
1472
1473
|
}
|
|
1474
|
+
function setCompactionState(ctx, state) {
|
|
1475
|
+
compactionState = state;
|
|
1476
|
+
updateStatus(ctx);
|
|
1477
|
+
}
|
|
1473
1478
|
function noteCompletedTurn(ctx) {
|
|
1474
1479
|
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
|
|
1475
1480
|
return;
|
|
@@ -1497,6 +1502,19 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1497
1502
|
function runningOperationIsCurrent(operation, generation, sessionFile) {
|
|
1498
1503
|
return generation === sessionGeneration && sessionFile === activeSessionFile && compactionState.phase === "running" && compactionState.operation === operation;
|
|
1499
1504
|
}
|
|
1505
|
+
function releasePiCompactionOnAbort(ctx, signal, operation, generation, sessionFile, request, reason) {
|
|
1506
|
+
signal?.addEventListener("abort", () => {
|
|
1507
|
+
if (!runningOperationIsCurrent(operation, generation, sessionFile))
|
|
1508
|
+
return;
|
|
1509
|
+
setCompactionState(ctx, reason !== "manual" && request && requestIsCurrent(request) ? {
|
|
1510
|
+
phase: "queued",
|
|
1511
|
+
request: {
|
|
1512
|
+
...request,
|
|
1513
|
+
eligibleSettlement: Math.max(request.eligibleSettlement, settlementGeneration + 2)
|
|
1514
|
+
}
|
|
1515
|
+
} : { phase: "idle" });
|
|
1516
|
+
}, { once: true });
|
|
1517
|
+
}
|
|
1500
1518
|
function requestHasCompactableHistory(ctx, keep) {
|
|
1501
1519
|
return keep === null ? hasCompactableHistory(ctx) : keepBoundaryId(ctx.sessionManager.getBranch(), keep) !== undefined;
|
|
1502
1520
|
}
|
|
@@ -1505,53 +1523,52 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1505
1523
|
return;
|
|
1506
1524
|
if (!hasCompactableHistory(ctx))
|
|
1507
1525
|
return;
|
|
1508
|
-
|
|
1526
|
+
setCompactionState(ctx, {
|
|
1509
1527
|
phase: "queued",
|
|
1510
1528
|
request: {
|
|
1511
1529
|
keep: null,
|
|
1512
|
-
origin: "turn",
|
|
1513
1530
|
sessionGeneration,
|
|
1514
1531
|
sessionFile: activeSessionFile,
|
|
1515
1532
|
eligibleSettlement
|
|
1516
1533
|
}
|
|
1517
|
-
};
|
|
1534
|
+
});
|
|
1518
1535
|
}
|
|
1519
1536
|
function startQueuedCompaction(ctx) {
|
|
1520
1537
|
if (compactionState.phase !== "queued")
|
|
1521
1538
|
return false;
|
|
1522
1539
|
const request = compactionState.request;
|
|
1523
1540
|
if (!requestIsCurrent(request)) {
|
|
1524
|
-
|
|
1541
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
1525
1542
|
return false;
|
|
1526
1543
|
}
|
|
1527
1544
|
if (!ctx.isIdle() || ctx.hasPendingMessages())
|
|
1528
1545
|
return false;
|
|
1529
1546
|
if (!requestHasCompactableHistory(ctx, request.keep)) {
|
|
1530
|
-
|
|
1547
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
1531
1548
|
return false;
|
|
1532
1549
|
}
|
|
1533
1550
|
const operation = ++operationGeneration;
|
|
1534
1551
|
const generation = request.sessionGeneration;
|
|
1535
1552
|
const sessionFile = request.sessionFile;
|
|
1536
|
-
|
|
1553
|
+
setCompactionState(ctx, {
|
|
1537
1554
|
phase: "running",
|
|
1538
1555
|
request,
|
|
1539
1556
|
owner: "extension",
|
|
1540
1557
|
operation,
|
|
1541
1558
|
sessionGeneration: generation,
|
|
1542
1559
|
sessionFile,
|
|
1543
|
-
|
|
1544
|
-
};
|
|
1560
|
+
hookClaimed: false
|
|
1561
|
+
});
|
|
1545
1562
|
ctx.compact({
|
|
1546
1563
|
onComplete: () => {
|
|
1547
1564
|
if (!runningOperationIsCurrent(operation, generation, sessionFile))
|
|
1548
1565
|
return;
|
|
1549
|
-
|
|
1566
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
1550
1567
|
},
|
|
1551
1568
|
onError: (error) => {
|
|
1552
1569
|
if (!runningOperationIsCurrent(operation, generation, sessionFile))
|
|
1553
1570
|
return;
|
|
1554
|
-
|
|
1571
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
1555
1572
|
const message = error instanceof Error ? error.message : String(error);
|
|
1556
1573
|
if (ctx.hasUI)
|
|
1557
1574
|
ctx.ui.notify(`goosedump compaction failed: ${message}`, "error");
|
|
@@ -1559,21 +1576,31 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1559
1576
|
});
|
|
1560
1577
|
return true;
|
|
1561
1578
|
}
|
|
1562
|
-
function
|
|
1579
|
+
function deferQueuedCompaction(ctx) {
|
|
1580
|
+
if (compactionState.phase !== "queued")
|
|
1581
|
+
return;
|
|
1582
|
+
const request = compactionState.request;
|
|
1583
|
+
setImmediate(() => {
|
|
1584
|
+
if (compactionState.phase !== "queued" || compactionState.request !== request || !contextIsCurrent(ctx)) {
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
startQueuedCompaction(ctx);
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
function requestCompaction(ctx, keep) {
|
|
1563
1591
|
if (compactionState.phase !== "idle")
|
|
1564
1592
|
return "busy";
|
|
1565
1593
|
if (!requestHasCompactableHistory(ctx, keep))
|
|
1566
1594
|
return "nothing-to-compact";
|
|
1567
|
-
|
|
1595
|
+
setCompactionState(ctx, {
|
|
1568
1596
|
phase: "queued",
|
|
1569
1597
|
request: {
|
|
1570
1598
|
keep,
|
|
1571
|
-
origin,
|
|
1572
1599
|
sessionGeneration,
|
|
1573
1600
|
sessionFile: activeSessionFile,
|
|
1574
1601
|
eligibleSettlement: settlementGeneration + 1
|
|
1575
1602
|
}
|
|
1576
|
-
};
|
|
1603
|
+
});
|
|
1577
1604
|
return startQueuedCompaction(ctx) ? "started" : "queued";
|
|
1578
1605
|
}
|
|
1579
1606
|
function register(pi) {
|
|
@@ -1848,7 +1875,7 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1848
1875
|
if (!goosedumpAvailable)
|
|
1849
1876
|
return goosedumpUnavailableResult();
|
|
1850
1877
|
const keep = params.keep ?? null;
|
|
1851
|
-
const result = requestCompaction(ctx, keep
|
|
1878
|
+
const result = requestCompaction(ctx, keep);
|
|
1852
1879
|
if (result === "busy")
|
|
1853
1880
|
return textResult("Compaction already in progress.");
|
|
1854
1881
|
if (result === "nothing-to-compact") {
|
|
@@ -1930,20 +1957,20 @@ ${lines.join(`
|
|
|
1930
1957
|
settlementGeneration += 1;
|
|
1931
1958
|
if (compactionState.phase === "running" && compactionState.owner === "pi") {
|
|
1932
1959
|
const request = compactionState.request;
|
|
1933
|
-
|
|
1960
|
+
setCompactionState(ctx, request && requestIsCurrent(request) ? {
|
|
1934
1961
|
phase: "queued",
|
|
1935
1962
|
request: { ...request, eligibleSettlement: settlementGeneration + 1 }
|
|
1936
|
-
} : { phase: "idle" };
|
|
1963
|
+
} : { phase: "idle" });
|
|
1937
1964
|
return;
|
|
1938
1965
|
}
|
|
1939
1966
|
if (compactionState.phase === "queued" && !requestIsCurrent(compactionState.request)) {
|
|
1940
|
-
|
|
1967
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
1941
1968
|
}
|
|
1942
1969
|
if (compactionState.phase === "idle") {
|
|
1943
1970
|
queueTurnCompaction(ctx, settlementGeneration);
|
|
1944
1971
|
}
|
|
1945
1972
|
if (compactionState.phase === "queued" && compactionState.request.eligibleSettlement <= settlementGeneration) {
|
|
1946
|
-
|
|
1973
|
+
deferQueuedCompaction(ctx);
|
|
1947
1974
|
}
|
|
1948
1975
|
}
|
|
1949
1976
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -1957,6 +1984,7 @@ ${lines.join(`
|
|
|
1957
1984
|
syncCompactCounters(ctx);
|
|
1958
1985
|
updateStatus(ctx);
|
|
1959
1986
|
queueTurnCompaction(ctx, 1);
|
|
1987
|
+
deferQueuedCompaction(ctx);
|
|
1960
1988
|
});
|
|
1961
1989
|
pi.on("session_shutdown", async () => {
|
|
1962
1990
|
sessionGeneration += 1;
|
|
@@ -1965,6 +1993,15 @@ ${lines.join(`
|
|
|
1965
1993
|
sessionActive = false;
|
|
1966
1994
|
compactionState = { phase: "idle" };
|
|
1967
1995
|
});
|
|
1996
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
1997
|
+
if (compactionState.phase !== "running" || compactionState.owner !== "pi")
|
|
1998
|
+
return;
|
|
1999
|
+
const request = compactionState.request;
|
|
2000
|
+
setCompactionState(ctx, request && requestIsCurrent(request) ? {
|
|
2001
|
+
phase: "queued",
|
|
2002
|
+
request: { ...request, eligibleSettlement: settlementGeneration + 1 }
|
|
2003
|
+
} : { phase: "idle" });
|
|
2004
|
+
});
|
|
1968
2005
|
pi.on("turn_end", async (event, ctx) => {
|
|
1969
2006
|
if (isCompletedAssistant(event.message))
|
|
1970
2007
|
noteCompletedTurn(ctx);
|
|
@@ -1975,32 +2012,33 @@ ${lines.join(`
|
|
|
1975
2012
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
1976
2013
|
if (!shouldOverrideDefaultCompaction || !goosedumpAvailable)
|
|
1977
2014
|
return;
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
return { cancel: true };
|
|
1981
|
-
if (compactionState.phase === "queued") {
|
|
1982
|
-
if (compactionState.request.origin !== "turn")
|
|
1983
|
-
return { cancel: true };
|
|
1984
|
-
compactionState = {
|
|
1985
|
-
phase: "queued",
|
|
1986
|
-
request: {
|
|
1987
|
-
...compactionState.request,
|
|
1988
|
-
eligibleSettlement: Math.max(compactionState.request.eligibleSettlement, settlementGeneration + 2)
|
|
1989
|
-
}
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
return;
|
|
1993
|
-
}
|
|
1994
|
-
if (event.signal.aborted) {
|
|
2015
|
+
const signal = event.signal;
|
|
2016
|
+
if (signal?.aborted) {
|
|
1995
2017
|
if (compactionState.phase === "queued" && requestIsCurrent(compactionState.request)) {
|
|
1996
|
-
|
|
2018
|
+
setCompactionState(ctx, event.reason === "manual" ? { phase: "idle" } : {
|
|
1997
2019
|
phase: "queued",
|
|
1998
2020
|
request: {
|
|
1999
2021
|
...compactionState.request,
|
|
2000
2022
|
eligibleSettlement: Math.max(compactionState.request.eligibleSettlement, settlementGeneration + 2)
|
|
2001
2023
|
}
|
|
2002
|
-
};
|
|
2024
|
+
});
|
|
2003
2025
|
}
|
|
2026
|
+
return { cancel: true };
|
|
2027
|
+
}
|
|
2028
|
+
if (event.customInstructions?.trim()) {
|
|
2029
|
+
if (compactionState.phase === "running")
|
|
2030
|
+
return { cancel: true };
|
|
2031
|
+
const operation2 = ++operationGeneration;
|
|
2032
|
+
setCompactionState(ctx, {
|
|
2033
|
+
phase: "running",
|
|
2034
|
+
request: null,
|
|
2035
|
+
owner: "pi",
|
|
2036
|
+
operation: operation2,
|
|
2037
|
+
sessionGeneration,
|
|
2038
|
+
sessionFile: activeSessionFile,
|
|
2039
|
+
hookClaimed: true
|
|
2040
|
+
});
|
|
2041
|
+
releasePiCompactionOnAbort(ctx, signal, operation2, sessionGeneration, activeSessionFile, null, event.reason);
|
|
2004
2042
|
return;
|
|
2005
2043
|
}
|
|
2006
2044
|
let operation;
|
|
@@ -2009,7 +2047,7 @@ ${lines.join(`
|
|
|
2009
2047
|
let request;
|
|
2010
2048
|
let owner;
|
|
2011
2049
|
if (compactionState.phase === "running") {
|
|
2012
|
-
if (compactionState.
|
|
2050
|
+
if (compactionState.hookClaimed || compactionState.owner === "pi") {
|
|
2013
2051
|
return { cancel: true };
|
|
2014
2052
|
}
|
|
2015
2053
|
operation = compactionState.operation;
|
|
@@ -2017,22 +2055,25 @@ ${lines.join(`
|
|
|
2017
2055
|
sessionFile = compactionState.sessionFile;
|
|
2018
2056
|
request = compactionState.request;
|
|
2019
2057
|
owner = "extension";
|
|
2020
|
-
compactionState = { ...compactionState,
|
|
2058
|
+
compactionState = { ...compactionState, hookClaimed: true };
|
|
2021
2059
|
} else {
|
|
2022
2060
|
request = compactionState.phase === "queued" && requestIsCurrent(compactionState.request) ? compactionState.request : null;
|
|
2023
2061
|
operation = ++operationGeneration;
|
|
2024
2062
|
generation = sessionGeneration;
|
|
2025
2063
|
sessionFile = activeSessionFile;
|
|
2026
2064
|
owner = "pi";
|
|
2027
|
-
|
|
2065
|
+
setCompactionState(ctx, {
|
|
2028
2066
|
phase: "running",
|
|
2029
2067
|
request,
|
|
2030
2068
|
owner,
|
|
2031
2069
|
operation,
|
|
2032
2070
|
sessionGeneration: generation,
|
|
2033
2071
|
sessionFile,
|
|
2034
|
-
|
|
2035
|
-
};
|
|
2072
|
+
hookClaimed: true
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
if (owner === "pi") {
|
|
2076
|
+
releasePiCompactionOnAbort(ctx, signal, operation, generation, sessionFile, request, event.reason);
|
|
2036
2077
|
}
|
|
2037
2078
|
try {
|
|
2038
2079
|
const { messagesToSummarize, turnPrefixMessages } = event.preparation;
|
|
@@ -2049,17 +2090,26 @@ ${lines.join(`
|
|
|
2049
2090
|
}
|
|
2050
2091
|
keep = undefined;
|
|
2051
2092
|
if (runningOperationIsCurrent(operation, generation, sessionFile)) {
|
|
2052
|
-
|
|
2093
|
+
request = null;
|
|
2094
|
+
setCompactionState(ctx, {
|
|
2095
|
+
phase: "running",
|
|
2096
|
+
request,
|
|
2097
|
+
owner,
|
|
2098
|
+
operation,
|
|
2099
|
+
sessionGeneration: generation,
|
|
2100
|
+
sessionFile,
|
|
2101
|
+
hookClaimed: true
|
|
2102
|
+
});
|
|
2053
2103
|
}
|
|
2054
2104
|
}
|
|
2055
|
-
const compaction = await buildGoosedumpCompaction(target, event.preparation, event.branchEntries, effectiveSummaryMaxTokens(ctx.cwd, projectSettingsTrusted(ctx)), keep,
|
|
2105
|
+
const compaction = await buildGoosedumpCompaction(target, event.preparation, event.branchEntries, effectiveSummaryMaxTokens(ctx.cwd, projectSettingsTrusted(ctx)), keep, signal, nativeExecutablePath);
|
|
2056
2106
|
if (!runningOperationIsCurrent(operation, generation, sessionFile)) {
|
|
2057
2107
|
return { cancel: true };
|
|
2058
2108
|
}
|
|
2059
2109
|
if (compaction && "cancel" in compaction) {
|
|
2060
2110
|
if (ctx.hasUI)
|
|
2061
2111
|
ctx.ui.notify(compaction.reason, "info");
|
|
2062
|
-
return
|
|
2112
|
+
return;
|
|
2063
2113
|
}
|
|
2064
2114
|
const warning = compaction?.details?.warning;
|
|
2065
2115
|
if (warning && ctx.hasUI) {
|
|
@@ -2067,23 +2117,33 @@ ${lines.join(`
|
|
|
2067
2117
|
}
|
|
2068
2118
|
if (compaction)
|
|
2069
2119
|
return { compaction };
|
|
2070
|
-
return
|
|
2120
|
+
return;
|
|
2071
2121
|
} catch (err) {
|
|
2072
2122
|
if (!runningOperationIsCurrent(operation, generation, sessionFile)) {
|
|
2073
2123
|
return { cancel: true };
|
|
2074
2124
|
}
|
|
2075
|
-
if (
|
|
2125
|
+
if (signal?.aborted) {
|
|
2126
|
+
if (owner === "pi" && event.reason === "manual") {
|
|
2127
|
+
setCompactionState(ctx, { phase: "idle" });
|
|
2128
|
+
}
|
|
2076
2129
|
return { cancel: true };
|
|
2077
|
-
|
|
2130
|
+
}
|
|
2078
2131
|
if (ctx.hasUI) {
|
|
2079
2132
|
const message = err instanceof Error ? err.message : String(err);
|
|
2080
|
-
|
|
2081
|
-
ctx.ui.notify(`goosedump compaction failed${action}: ${message}`, "error");
|
|
2133
|
+
ctx.ui.notify(`goosedump compaction failed; falling back to Pi compaction: ${message}`, "error");
|
|
2082
2134
|
}
|
|
2083
|
-
return
|
|
2135
|
+
return;
|
|
2084
2136
|
} finally {
|
|
2085
2137
|
if (runningOperationIsCurrent(operation, generation, sessionFile)) {
|
|
2086
|
-
|
|
2138
|
+
setCompactionState(ctx, {
|
|
2139
|
+
phase: "running",
|
|
2140
|
+
request,
|
|
2141
|
+
owner,
|
|
2142
|
+
operation,
|
|
2143
|
+
sessionGeneration: generation,
|
|
2144
|
+
sessionFile,
|
|
2145
|
+
hookClaimed: true
|
|
2146
|
+
});
|
|
2087
2147
|
}
|
|
2088
2148
|
}
|
|
2089
2149
|
});
|
|
@@ -2095,7 +2155,9 @@ ${lines.join(`
|
|
|
2095
2155
|
if (compactionState.phase === "queued" && compactionState.request.keep !== null && ctx.hasUI) {
|
|
2096
2156
|
ctx.ui.notify("Queued keep request was superseded by another compaction.", "info");
|
|
2097
2157
|
}
|
|
2098
|
-
|
|
2158
|
+
const extensionOwned = compactionState.phase === "running" && compactionState.owner === "extension";
|
|
2159
|
+
if (!extensionOwned)
|
|
2160
|
+
compactionState = { phase: "idle" };
|
|
2099
2161
|
syncCompactCounters(ctx);
|
|
2100
2162
|
updateStatus(ctx);
|
|
2101
2163
|
if (!goosedumpAvailable)
|
|
@@ -2158,7 +2220,7 @@ ${lines.join(`
|
|
|
2158
2220
|
return;
|
|
2159
2221
|
}
|
|
2160
2222
|
}
|
|
2161
|
-
const result = requestCompaction(ctx, keep
|
|
2223
|
+
const result = requestCompaction(ctx, keep);
|
|
2162
2224
|
if (result === "busy") {
|
|
2163
2225
|
ctx.ui.notify("Compaction already in progress", "info");
|
|
2164
2226
|
} else if (result === "nothing-to-compact") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.17",
|
|
4
4
|
"description": "Pi extension for goosedump session search, durable memory, and compaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compaction",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@earendil-works/pi-tui": "^0.82.1",
|
|
41
|
-
"@jarkkojs/goosedump": "^0.12.
|
|
41
|
+
"@jarkkojs/goosedump": "^0.12.17",
|
|
42
42
|
"@sinclair/typebox": "^0.34.49"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|