pi-goosedump 0.12.15 → 0.12.16

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 (3) hide show
  1. package/README.md +5 -4
  2. package/dist/index.ts +60 -41
  3. 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. Pi remains the
101
- sole scheduler for its normal context threshold. Whichever limit is reached first
102
- compacts once, and every successful compaction resets the countdown. A turn or
103
- tool request waits until the agent run is fully settled. A failed or cancelled
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
@@ -1411,6 +1411,7 @@ function createGoosedumpIntegration(options = {}) {
1411
1411
  let operationGeneration = 0;
1412
1412
  let activeSessionFile = null;
1413
1413
  let sessionActive = false;
1414
+ let agentEndObserved = true;
1414
1415
  const rememberQueue = [];
1415
1416
  let rememberRunning = null;
1416
1417
  function enqueueRemember(target, reportError) {
@@ -1467,9 +1468,14 @@ function createGoosedumpIntegration(options = {}) {
1467
1468
  }
1468
1469
  const dot = ctx.ui.theme.fg(dotColor, "●");
1469
1470
  const counter = active ? Math.max(0, turnsRemaining).toString(16).toUpperCase().padStart(2, "0") : "--";
1470
- const label = ctx.ui.theme.fg("text", `${ctx.ui.theme.bold?.("GD") ?? "GD"}:${counter}`);
1471
+ const activity = compactionState.phase === "queued" ? " queued" : compactionState.phase === "running" ? " compacting" : "";
1472
+ const label = ctx.ui.theme.fg("text", `${ctx.ui.theme.bold?.("GD") ?? "GD"}:${counter}${activity}`);
1471
1473
  ctx.ui.setStatus("goosedump", `${dot} ${label}`);
1472
1474
  }
1475
+ function setCompactionState(ctx, state) {
1476
+ compactionState = state;
1477
+ updateStatus(ctx);
1478
+ }
1473
1479
  function noteCompletedTurn(ctx) {
1474
1480
  if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
1475
1481
  return;
@@ -1505,35 +1511,34 @@ function createGoosedumpIntegration(options = {}) {
1505
1511
  return;
1506
1512
  if (!hasCompactableHistory(ctx))
1507
1513
  return;
1508
- compactionState = {
1514
+ setCompactionState(ctx, {
1509
1515
  phase: "queued",
1510
1516
  request: {
1511
1517
  keep: null,
1512
- origin: "turn",
1513
1518
  sessionGeneration,
1514
1519
  sessionFile: activeSessionFile,
1515
1520
  eligibleSettlement
1516
1521
  }
1517
- };
1522
+ });
1518
1523
  }
1519
1524
  function startQueuedCompaction(ctx) {
1520
1525
  if (compactionState.phase !== "queued")
1521
1526
  return false;
1522
1527
  const request = compactionState.request;
1523
1528
  if (!requestIsCurrent(request)) {
1524
- compactionState = { phase: "idle" };
1529
+ setCompactionState(ctx, { phase: "idle" });
1525
1530
  return false;
1526
1531
  }
1527
1532
  if (!ctx.isIdle() || ctx.hasPendingMessages())
1528
1533
  return false;
1529
1534
  if (!requestHasCompactableHistory(ctx, request.keep)) {
1530
- compactionState = { phase: "idle" };
1535
+ setCompactionState(ctx, { phase: "idle" });
1531
1536
  return false;
1532
1537
  }
1533
1538
  const operation = ++operationGeneration;
1534
1539
  const generation = request.sessionGeneration;
1535
1540
  const sessionFile = request.sessionFile;
1536
- compactionState = {
1541
+ setCompactionState(ctx, {
1537
1542
  phase: "running",
1538
1543
  request,
1539
1544
  owner: "extension",
@@ -1541,17 +1546,17 @@ function createGoosedumpIntegration(options = {}) {
1541
1546
  sessionGeneration: generation,
1542
1547
  sessionFile,
1543
1548
  hookActive: false
1544
- };
1549
+ });
1545
1550
  ctx.compact({
1546
1551
  onComplete: () => {
1547
1552
  if (!runningOperationIsCurrent(operation, generation, sessionFile))
1548
1553
  return;
1549
- compactionState = { phase: "idle" };
1554
+ setCompactionState(ctx, { phase: "idle" });
1550
1555
  },
1551
1556
  onError: (error) => {
1552
1557
  if (!runningOperationIsCurrent(operation, generation, sessionFile))
1553
1558
  return;
1554
- compactionState = { phase: "idle" };
1559
+ setCompactionState(ctx, { phase: "idle" });
1555
1560
  const message = error instanceof Error ? error.message : String(error);
1556
1561
  if (ctx.hasUI)
1557
1562
  ctx.ui.notify(`goosedump compaction failed: ${message}`, "error");
@@ -1559,21 +1564,20 @@ function createGoosedumpIntegration(options = {}) {
1559
1564
  });
1560
1565
  return true;
1561
1566
  }
1562
- function requestCompaction(ctx, keep, origin) {
1567
+ function requestCompaction(ctx, keep) {
1563
1568
  if (compactionState.phase !== "idle")
1564
1569
  return "busy";
1565
1570
  if (!requestHasCompactableHistory(ctx, keep))
1566
1571
  return "nothing-to-compact";
1567
- compactionState = {
1572
+ setCompactionState(ctx, {
1568
1573
  phase: "queued",
1569
1574
  request: {
1570
1575
  keep,
1571
- origin,
1572
1576
  sessionGeneration,
1573
1577
  sessionFile: activeSessionFile,
1574
1578
  eligibleSettlement: settlementGeneration + 1
1575
1579
  }
1576
- };
1580
+ });
1577
1581
  return startQueuedCompaction(ctx) ? "started" : "queued";
1578
1582
  }
1579
1583
  function register(pi) {
@@ -1848,7 +1852,7 @@ function createGoosedumpIntegration(options = {}) {
1848
1852
  if (!goosedumpAvailable)
1849
1853
  return goosedumpUnavailableResult();
1850
1854
  const keep = params.keep ?? null;
1851
- const result = requestCompaction(ctx, keep, "tool");
1855
+ const result = requestCompaction(ctx, keep);
1852
1856
  if (result === "busy")
1853
1857
  return textResult("Compaction already in progress.");
1854
1858
  if (result === "nothing-to-compact") {
@@ -1930,19 +1934,19 @@ ${lines.join(`
1930
1934
  settlementGeneration += 1;
1931
1935
  if (compactionState.phase === "running" && compactionState.owner === "pi") {
1932
1936
  const request = compactionState.request;
1933
- compactionState = request && requestIsCurrent(request) ? {
1937
+ setCompactionState(ctx, request && requestIsCurrent(request) ? {
1934
1938
  phase: "queued",
1935
1939
  request: { ...request, eligibleSettlement: settlementGeneration + 1 }
1936
- } : { phase: "idle" };
1940
+ } : { phase: "idle" });
1937
1941
  return;
1938
1942
  }
1939
1943
  if (compactionState.phase === "queued" && !requestIsCurrent(compactionState.request)) {
1940
- compactionState = { phase: "idle" };
1944
+ setCompactionState(ctx, { phase: "idle" });
1941
1945
  }
1942
1946
  if (compactionState.phase === "idle") {
1943
1947
  queueTurnCompaction(ctx, settlementGeneration);
1944
1948
  }
1945
- if (compactionState.phase === "queued" && compactionState.request.eligibleSettlement <= settlementGeneration) {
1949
+ if (agentEndObserved && compactionState.phase === "queued" && compactionState.request.eligibleSettlement <= settlementGeneration) {
1946
1950
  startQueuedCompaction(ctx);
1947
1951
  }
1948
1952
  }
@@ -1951,6 +1955,7 @@ ${lines.join(`
1951
1955
  settlementGeneration = 0;
1952
1956
  activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
1953
1957
  sessionActive = true;
1958
+ agentEndObserved = true;
1954
1959
  compactionState = { phase: "idle" };
1955
1960
  goosedumpAvailable = checkGoosedump(ctx);
1956
1961
  notifyInvalidSettings(ctx);
@@ -1963,8 +1968,15 @@ ${lines.join(`
1963
1968
  settlementGeneration = 0;
1964
1969
  activeSessionFile = null;
1965
1970
  sessionActive = false;
1971
+ agentEndObserved = true;
1966
1972
  compactionState = { phase: "idle" };
1967
1973
  });
1974
+ pi.on("agent_start", async () => {
1975
+ agentEndObserved = false;
1976
+ });
1977
+ pi.on("agent_end", async () => {
1978
+ agentEndObserved = true;
1979
+ });
1968
1980
  pi.on("turn_end", async (event, ctx) => {
1969
1981
  if (isCompletedAssistant(event.message))
1970
1982
  noteCompletedTurn(ctx);
@@ -1979,27 +1991,19 @@ ${lines.join(`
1979
1991
  if (compactionState.phase === "running")
1980
1992
  return { cancel: true };
1981
1993
  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
- };
1994
+ setCompactionState(ctx, { phase: "idle" });
1991
1995
  }
1992
1996
  return;
1993
1997
  }
1994
1998
  if (event.signal.aborted) {
1995
1999
  if (compactionState.phase === "queued" && requestIsCurrent(compactionState.request)) {
1996
- compactionState = event.reason === "manual" ? { phase: "idle" } : {
2000
+ setCompactionState(ctx, event.reason === "manual" ? { phase: "idle" } : {
1997
2001
  phase: "queued",
1998
2002
  request: {
1999
2003
  ...compactionState.request,
2000
2004
  eligibleSettlement: Math.max(compactionState.request.eligibleSettlement, settlementGeneration + 2)
2001
2005
  }
2002
- };
2006
+ });
2003
2007
  }
2004
2008
  return;
2005
2009
  }
@@ -2024,7 +2028,7 @@ ${lines.join(`
2024
2028
  generation = sessionGeneration;
2025
2029
  sessionFile = activeSessionFile;
2026
2030
  owner = "pi";
2027
- compactionState = {
2031
+ setCompactionState(ctx, {
2028
2032
  phase: "running",
2029
2033
  request,
2030
2034
  owner,
@@ -2032,7 +2036,7 @@ ${lines.join(`
2032
2036
  sessionGeneration: generation,
2033
2037
  sessionFile,
2034
2038
  hookActive: true
2035
- };
2039
+ });
2036
2040
  }
2037
2041
  try {
2038
2042
  const { messagesToSummarize, turnPrefixMessages } = event.preparation;
@@ -2049,7 +2053,16 @@ ${lines.join(`
2049
2053
  }
2050
2054
  keep = undefined;
2051
2055
  if (runningOperationIsCurrent(operation, generation, sessionFile)) {
2052
- compactionState = { ...compactionState, request: null };
2056
+ request = null;
2057
+ setCompactionState(ctx, {
2058
+ phase: "running",
2059
+ request,
2060
+ owner,
2061
+ operation,
2062
+ sessionGeneration: generation,
2063
+ sessionFile,
2064
+ hookActive: true
2065
+ });
2053
2066
  }
2054
2067
  }
2055
2068
  const compaction = await buildGoosedumpCompaction(target, event.preparation, event.branchEntries, effectiveSummaryMaxTokens(ctx.cwd, projectSettingsTrusted(ctx)), keep, event.signal, nativeExecutablePath);
@@ -2059,7 +2072,7 @@ ${lines.join(`
2059
2072
  if (compaction && "cancel" in compaction) {
2060
2073
  if (ctx.hasUI)
2061
2074
  ctx.ui.notify(compaction.reason, "info");
2062
- return owner === "pi" && event.reason === "manual" ? { cancel: true } : undefined;
2075
+ return;
2063
2076
  }
2064
2077
  const warning = compaction?.details?.warning;
2065
2078
  if (warning && ctx.hasUI) {
@@ -2067,23 +2080,29 @@ ${lines.join(`
2067
2080
  }
2068
2081
  if (compaction)
2069
2082
  return { compaction };
2070
- return owner === "pi" && event.reason === "manual" ? { cancel: true } : undefined;
2083
+ return;
2071
2084
  } catch (err) {
2072
2085
  if (!runningOperationIsCurrent(operation, generation, sessionFile)) {
2073
2086
  return { cancel: true };
2074
2087
  }
2075
2088
  if (event.signal.aborted)
2076
2089
  return { cancel: true };
2077
- const useFallback = owner === "extension" || event.reason !== "manual";
2078
2090
  if (ctx.hasUI) {
2079
2091
  const message = err instanceof Error ? err.message : String(err);
2080
- const action = useFallback ? "; falling back to Pi compaction" : "";
2081
- ctx.ui.notify(`goosedump compaction failed${action}: ${message}`, "error");
2092
+ ctx.ui.notify(`goosedump compaction failed; falling back to Pi compaction: ${message}`, "error");
2082
2093
  }
2083
- return useFallback ? undefined : { cancel: true };
2094
+ return;
2084
2095
  } finally {
2085
2096
  if (runningOperationIsCurrent(operation, generation, sessionFile)) {
2086
- compactionState = owner === "pi" && event.reason === "manual" ? { phase: "idle" } : { ...compactionState, hookActive: false };
2097
+ setCompactionState(ctx, owner === "pi" && event.reason === "manual" ? { phase: "idle" } : {
2098
+ phase: "running",
2099
+ request,
2100
+ owner,
2101
+ operation,
2102
+ sessionGeneration: generation,
2103
+ sessionFile,
2104
+ hookActive: false
2105
+ });
2087
2106
  }
2088
2107
  }
2089
2108
  });
@@ -2158,7 +2177,7 @@ ${lines.join(`
2158
2177
  return;
2159
2178
  }
2160
2179
  }
2161
- const result = requestCompaction(ctx, keep, "command");
2180
+ const result = requestCompaction(ctx, keep);
2162
2181
  if (result === "busy") {
2163
2182
  ctx.ui.notify("Compaction already in progress", "info");
2164
2183
  } 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.15",
3
+ "version": "0.12.16",
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.15",
41
+ "@jarkkojs/goosedump": "^0.12.16",
42
42
  "@sinclair/typebox": "^0.34.49"
43
43
  },
44
44
  "devDependencies": {