pi-mega-compact 0.4.6 → 0.4.8

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.
@@ -229,7 +229,7 @@ export default function (pi) {
229
229
  const tokStr = lastCtxTokens != null ? `${Math.round(lastCtxTokens / 1000)}k` : "?";
230
230
  const maxStr = lastCtxWindow > 0 ? `${Math.round(lastCtxWindow / 1000)}k` : "?";
231
231
  const pctStr = lastCtxPercent != null ? `${Math.round(lastCtxPercent * 10) / 10}%` : "?%";
232
- const triggerLabel = ready ? "● ready" : armed ? "◐ armed" : "○ idle";
232
+ const triggerLabel = ready ? `${C.green}● ready${C.reset}` : armed ? `${C.amber}◐ armed${C.reset}` : `${C.gray}○ idle${C.reset}`;
233
233
  // Storage dedup rate is cumulative (store-wide, per-repo) and survives
234
234
  // session resets. Always show a number: 0% before any compaction, a
235
235
  // decimal for sub-10% rates so small-but-real dedup isn't rounded away.
@@ -244,14 +244,21 @@ export default function (pi) {
244
244
  // vs st.totalTokenEstimate). Use "k" only at/above 1000 so small-but-real
245
245
  // numbers stay visible (previously Math.round(x/1000) zeroed <1000).
246
246
  const fmt = (x) => (x >= 1000 ? `${(x / 1000).toFixed(1)}k` : `${x}`);
247
- const savedStr = `${fmt(rt.tokensSaved)} sess / ${fmt(repo.tokensSaved)} repo`;
248
- const usedStr = `${fmt(st.totalTokenEstimate)} sess / ${fmt(repo.totalTokenEstimate)} repo`;
247
+ const savedStr = `${C.green}${fmt(rt.tokensSaved)} sess${C.reset} / ${C.blue}${fmt(repo.tokensSaved)} repo${C.reset}`;
248
+ const usedStr = `${C.cyan}${fmt(st.totalTokenEstimate)} sess${C.reset} / ${C.blue}${fmt(repo.totalTokenEstimate)} repo${C.reset}`;
249
249
  const agentStr = activeAgents > 0 ? ` │ 🤖 ${activeAgents} agent${activeAgents === 1 ? "" : "s"}` : "";
250
250
  const turnStr = currentTurn > 0 ? ` │ turn ${currentTurn}` : "";
251
- ctx.ui.setWidget(WIDGET_KEY, [
252
- ` ⚡ ${config.tier} │ ${tokStr}/${maxStr} tokens (${pctStr}) │ ${st.checkpointCount} chkpt${st.checkpointCount === 1 ? "" : "s"}${agentStr}${turnStr}`,
253
- ` ${triggerLabel} │ dedup: ${dedupStr} │ used: ${usedStr} │ saved: ${savedStr}`,
254
- ], { placement: "aboveEditor" });
251
+ const lines = [
252
+ ` ${C.amber}⚡ ${config.tier}${C.reset} │ ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) │ ${st.checkpointCount} chkpt${st.checkpointCount === 1 ? "" : "s"}${agentStr}${turnStr}`,
253
+ ` ${triggerLabel} │ ${C.magenta}dedup: ${dedupStr}${C.reset}${C.gray}used:${C.reset} ${usedStr} │ ${C.gray}saved:${C.reset} ${savedStr}`,
254
+ ];
255
+ // Live "now processing" line — teal while fresh (≤4s), then the last-seen
256
+ // action keeps the widget lively. Cleared on session reset.
257
+ if (currentActivity) {
258
+ const fresh = Date.now() - lastActivityAt < 4000;
259
+ lines.push(` ${fresh ? C.teal : C.dim}${currentActivity}${C.reset}`);
260
+ }
261
+ ctx.ui.setWidget(WIDGET_KEY, lines, { placement: "aboveEditor" });
255
262
  }
256
263
  }
257
264
  // The only mutable per-session state. Reset on session_start / session_tree.
@@ -273,6 +280,26 @@ export default function (pi) {
273
280
  // before_agent_start should prepend to the system prompt. Unset after use.
274
281
  let pendingRecallBlock;
275
282
  let statusKey; // current status text for dashboard
283
+ // Live "what it's doing right now" line for the toolbar. Set on each
284
+ // compaction; shown in teal while recent, then kept as the last-seen action so
285
+ // the widget is never blank. Cleared on session reset.
286
+ let currentActivity;
287
+ let lastActivityAt = 0;
288
+ // ANSI palette for the toolbar. The pi TUI's Text component preserves ANSI
289
+ // escape codes (see wrapTextWithAnsi), so raw escapes render as colors. No
290
+ // chalk dependency needed — these are just strings.
291
+ const C = {
292
+ reset: "\x1b[0m",
293
+ dim: "\x1b[2m",
294
+ bold: "\x1b[1m",
295
+ amber: "\x1b[38;5;214m", // tier / ready
296
+ green: "\x1b[38;5;120m", // saved
297
+ cyan: "\x1b[38;5;51m", // used / live activity
298
+ teal: "\x1b[38;5;37m", // processing (compress/dedup)
299
+ magenta: "\x1b[38;5;201m", // dedup rate
300
+ blue: "\x1b[38;5;75m", // repo totals
301
+ gray: "\x1b[38;5;245m", // labels
302
+ };
276
303
  function setStatus(ctx, text) {
277
304
  statusKey = text;
278
305
  ctx.ui.setStatus(STATUS_KEY, text);
@@ -294,6 +321,8 @@ export default function (pi) {
294
321
  statusKey = undefined;
295
322
  activeAgents = 0;
296
323
  currentTurn = 0;
324
+ currentActivity = undefined;
325
+ lastActivityAt = 0;
297
326
  }
298
327
  /** Run the full compaction pipeline and persist a checkpoint. Returns the result. */
299
328
  function runCompact(ctx, messages, opts = {}) {
@@ -332,6 +361,16 @@ export default function (pi) {
332
361
  rt.tokensSaved += saved;
333
362
  if (result.deduped)
334
363
  rt.dedupSkips++;
364
+ // Live toolbar "now processing" line: what file/region just got compacted or
365
+ // deduped. Reset to the last-seen action after a few seconds (see snapshot).
366
+ const files = result.filesModified ?? [];
367
+ const fileLabel = files.length
368
+ ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ")
369
+ : result.regionHash.slice(0, 8);
370
+ currentActivity = result.deduped
371
+ ? `♻ deduped ${fileLabel}`
372
+ : `🗜 compacted ${result.checkpointId} · ${fileLabel}`;
373
+ lastActivityAt = Date.now();
335
374
  // Record session activity + a daily-log entry in the per-repo SQLite store
336
375
  // (foundation for resume-sessions / daily-log features). Best-effort — never
337
376
  // block a compaction on bookkeeping.
@@ -46,6 +46,7 @@ export function compactSession(input, store = getDefaultStore()) {
46
46
  summary: "",
47
47
  regionHash: "",
48
48
  tokenEstimate: 0,
49
+ filesModified: [],
49
50
  originalTokenEstimate: 0,
50
51
  compactedFrom,
51
52
  };
@@ -111,6 +112,7 @@ export function compactSession(input, store = getDefaultStore()) {
111
112
  summary,
112
113
  regionHash,
113
114
  tokenEstimate: storedTokens,
115
+ filesModified,
114
116
  originalTokenEstimate,
115
117
  compactedFrom,
116
118
  };
@@ -325,7 +325,7 @@ export default function (pi: ExtensionAPI) {
325
325
  const tokStr = lastCtxTokens != null ? `${Math.round(lastCtxTokens / 1000)}k` : "?";
326
326
  const maxStr = lastCtxWindow > 0 ? `${Math.round(lastCtxWindow / 1000)}k` : "?";
327
327
  const pctStr = lastCtxPercent != null ? `${Math.round(lastCtxPercent * 10) / 10}%` : "?%";
328
- const triggerLabel = ready ? "● ready" : armed ? "◐ armed" : "○ idle";
328
+ const triggerLabel = ready ? `${C.green}● ready${C.reset}` : armed ? `${C.amber}◐ armed${C.reset}` : `${C.gray}○ idle${C.reset}`;
329
329
  // Storage dedup rate is cumulative (store-wide, per-repo) and survives
330
330
  // session resets. Always show a number: 0% before any compaction, a
331
331
  // decimal for sub-10% rates so small-but-real dedup isn't rounded away.
@@ -340,18 +340,21 @@ export default function (pi: ExtensionAPI) {
340
340
  // vs st.totalTokenEstimate). Use "k" only at/above 1000 so small-but-real
341
341
  // numbers stay visible (previously Math.round(x/1000) zeroed <1000).
342
342
  const fmt = (x: number) => (x >= 1000 ? `${(x / 1000).toFixed(1)}k` : `${x}`);
343
- const savedStr = `${fmt(rt.tokensSaved)} sess / ${fmt(repo.tokensSaved)} repo`;
344
- const usedStr = `${fmt(st.totalTokenEstimate)} sess / ${fmt(repo.totalTokenEstimate)} repo`;
343
+ const savedStr = `${C.green}${fmt(rt.tokensSaved)} sess${C.reset} / ${C.blue}${fmt(repo.tokensSaved)} repo${C.reset}`;
344
+ const usedStr = `${C.cyan}${fmt(st.totalTokenEstimate)} sess${C.reset} / ${C.blue}${fmt(repo.totalTokenEstimate)} repo${C.reset}`;
345
345
  const agentStr = activeAgents > 0 ? ` │ 🤖 ${activeAgents} agent${activeAgents === 1 ? "" : "s"}` : "";
346
346
  const turnStr = currentTurn > 0 ? ` │ turn ${currentTurn}` : "";
347
- ctx.ui.setWidget(
348
- WIDGET_KEY,
349
- [
350
- ` ⚡ ${config.tier} │ ${tokStr}/${maxStr} tokens (${pctStr}) │ ${st.checkpointCount} chkpt${st.checkpointCount === 1 ? "" : "s"}${agentStr}${turnStr}`,
351
- ` ${triggerLabel} dedup: ${dedupStr} used: ${usedStr} saved: ${savedStr}`,
352
- ],
353
- { placement: "aboveEditor" },
354
- );
347
+ const lines = [
348
+ ` ${C.amber}⚡ ${config.tier}${C.reset} │ ${tokStr}/${maxStr} tokens (${C.bold}${pctStr}${C.reset}) │ ${st.checkpointCount} chkpt${st.checkpointCount === 1 ? "" : "s"}${agentStr}${turnStr}`,
349
+ ` ${triggerLabel} │ ${C.magenta}dedup: ${dedupStr}${C.reset} │ ${C.gray}used:${C.reset} ${usedStr} │ ${C.gray}saved:${C.reset} ${savedStr}`,
350
+ ];
351
+ // Live "now processing" line teal while fresh (≤4s), then the last-seen
352
+ // action keeps the widget lively. Cleared on session reset.
353
+ if (currentActivity) {
354
+ const fresh = Date.now() - lastActivityAt < 4000;
355
+ lines.push(` ${fresh ? C.teal : C.dim}${currentActivity}${C.reset}`);
356
+ }
357
+ ctx.ui.setWidget(WIDGET_KEY, lines, { placement: "aboveEditor" });
355
358
  }
356
359
  }
357
360
 
@@ -374,6 +377,26 @@ export default function (pi: ExtensionAPI) {
374
377
  // before_agent_start should prepend to the system prompt. Unset after use.
375
378
  let pendingRecallBlock: string | undefined;
376
379
  let statusKey: string | undefined; // current status text for dashboard
380
+ // Live "what it's doing right now" line for the toolbar. Set on each
381
+ // compaction; shown in teal while recent, then kept as the last-seen action so
382
+ // the widget is never blank. Cleared on session reset.
383
+ let currentActivity: string | undefined;
384
+ let lastActivityAt = 0;
385
+ // ANSI palette for the toolbar. The pi TUI's Text component preserves ANSI
386
+ // escape codes (see wrapTextWithAnsi), so raw escapes render as colors. No
387
+ // chalk dependency needed — these are just strings.
388
+ const C = {
389
+ reset: "\x1b[0m",
390
+ dim: "\x1b[2m",
391
+ bold: "\x1b[1m",
392
+ amber: "\x1b[38;5;214m", // tier / ready
393
+ green: "\x1b[38;5;120m", // saved
394
+ cyan: "\x1b[38;5;51m", // used / live activity
395
+ teal: "\x1b[38;5;37m", // processing (compress/dedup)
396
+ magenta: "\x1b[38;5;201m", // dedup rate
397
+ blue: "\x1b[38;5;75m", // repo totals
398
+ gray: "\x1b[38;5;245m", // labels
399
+ };
377
400
 
378
401
  function setStatus(ctx: ExtensionContext, text: string | undefined) {
379
402
  statusKey = text;
@@ -396,6 +419,8 @@ export default function (pi: ExtensionAPI) {
396
419
  statusKey = undefined;
397
420
  activeAgents = 0;
398
421
  currentTurn = 0;
422
+ currentActivity = undefined;
423
+ lastActivityAt = 0;
399
424
  }
400
425
 
401
426
  /** Run the full compaction pipeline and persist a checkpoint. Returns the result. */
@@ -443,6 +468,17 @@ export default function (pi: ExtensionAPI) {
443
468
  rt.tokensSaved += saved;
444
469
  if (result.deduped) rt.dedupSkips++;
445
470
 
471
+ // Live toolbar "now processing" line: what file/region just got compacted or
472
+ // deduped. Reset to the last-seen action after a few seconds (see snapshot).
473
+ const files = result.filesModified ?? [];
474
+ const fileLabel = files.length
475
+ ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ")
476
+ : result.regionHash.slice(0, 8);
477
+ currentActivity = result.deduped
478
+ ? `♻ deduped ${fileLabel}`
479
+ : `🗜 compacted ${result.checkpointId} · ${fileLabel}`;
480
+ lastActivityAt = Date.now();
481
+
446
482
  // Record session activity + a daily-log entry in the per-repo SQLite store
447
483
  // (foundation for resume-sessions / daily-log features). Best-effort — never
448
484
  // block a compaction on bookkeeping.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-2-Clause",
package/src/engine.ts CHANGED
@@ -51,6 +51,9 @@ export interface CompactResult {
51
51
  summary: string;
52
52
  regionHash: string;
53
53
  tokenEstimate: number;
54
+ /** Files touched by the compacted region (surfaced to the UI for a live
55
+ * "compressing <file>" activity line). May be empty if not captured. */
56
+ filesModified: string[];
54
57
  /** Token count of the original dropped region (before compaction). The honest
55
58
  * "tokens saved" base = originalTokenEstimate − tokenEstimate (stored), or the
56
59
  * full originalTokenEstimate when the region deduped onto an existing
@@ -92,6 +95,7 @@ export function compactSession(input: CompactInput, store: VectorStore = getDefa
92
95
  summary: "",
93
96
  regionHash: "",
94
97
  tokenEstimate: 0,
98
+ filesModified: [],
95
99
  originalTokenEstimate: 0,
96
100
  compactedFrom,
97
101
  };
@@ -163,6 +167,7 @@ export function compactSession(input: CompactInput, store: VectorStore = getDefa
163
167
  summary,
164
168
  regionHash,
165
169
  tokenEstimate: storedTokens,
170
+ filesModified,
166
171
  originalTokenEstimate,
167
172
  compactedFrom,
168
173
  };