pi-mega-compact 0.7.2 → 0.7.3

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.
@@ -16,9 +16,9 @@ import { VectorStore } from "../src/vectorStore.js";
16
16
  import { toEngineMessages } from "../src/adapt.js";
17
17
  import { normalizeSessionId } from "../src/store.js";
18
18
  import { Logger } from "../src/log.js";
19
- import { recordModelSnapshot, latestModelSnapshot, upsertRepoRegistry, recordRepoModel } from "../src/store/sqlite.js";
19
+ import { recordModelSnapshot, latestModelSnapshot, upsertRepoRegistry, recordRepoModel, } from "../src/store/sqlite.js";
20
20
  import { detectCrossRepoDrift } from "../src/driftDetection.js";
21
- import { repoStateDir, resolveRepoRoot, pressureRatio, pressureFromPct, pressureBand, effectiveThresholdTokens } from "./mega-config.js";
21
+ import { repoStateDir, resolveRepoRoot, pressureRatio, pressureFromPct, pressureBand, effectiveThresholdTokens, } from "./mega-config.js";
22
22
  import { Dashboard } from "./mega-dashboard.js";
23
23
  export const STATUS_KEY = "mega-compact";
24
24
  export const WIDGET_KEY = "mega-compact-stats";
@@ -74,39 +74,51 @@ function visibleWidth(s) {
74
74
  let w = 0;
75
75
  for (const ch of stripped) {
76
76
  const cp = ch.codePointAt(0) ?? 0;
77
- const wide = cp >= 0x1100 && ((cp <= 0x115f) || (cp >= 0x2e80 && cp <= 0x303e) ||
78
- (cp >= 0x3041 && cp <= 0x33ff) || (cp >= 0x3400 && cp <= 0x4dbf) ||
79
- (cp >= 0x4e00 && cp <= 0x9fff) || (cp >= 0xa000 && cp <= 0xa4cf) ||
80
- (cp >= 0xac00 && cp <= 0xd7a3) || (cp >= 0xf900 && cp <= 0xfaff) ||
81
- (cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60) ||
82
- (cp >= 0xffe0 && cp <= 0xffe6) || (cp >= 0x1f300 && cp <= 0x1faff) ||
83
- (cp >= 0x20000 && cp <= 0x3fffd));
77
+ const wide = cp >= 0x1100 &&
78
+ (cp <= 0x115f ||
79
+ (cp >= 0x2e80 && cp <= 0x303e) ||
80
+ (cp >= 0x3041 && cp <= 0x33ff) ||
81
+ (cp >= 0x3400 && cp <= 0x4dbf) ||
82
+ (cp >= 0x4e00 && cp <= 0x9fff) ||
83
+ (cp >= 0xa000 && cp <= 0xa4cf) ||
84
+ (cp >= 0xac00 && cp <= 0xd7a3) ||
85
+ (cp >= 0xf900 && cp <= 0xfaff) ||
86
+ (cp >= 0xfe30 && cp <= 0xfe4f) ||
87
+ (cp >= 0xff00 && cp <= 0xff60) ||
88
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
89
+ (cp >= 0x1f300 && cp <= 0x1faff) ||
90
+ (cp >= 0x20000 && cp <= 0x3fffd));
84
91
  w += wide ? 2 : 1;
85
92
  }
86
93
  return w;
87
94
  }
88
95
  /** Pad a content string (with ANSI colors) to `width` cells using panel bg. */
89
- function spreadGroups(width, groups, indent = 0) {
90
- if (groups.length === 0)
91
- return panelLine('', width);
92
- // Calculate visible width of each group
93
- const groupWidths = groups.map(g => visibleWidth(PANEL_BG + g.replace(/\x1b\[0m/g, PANEL_RST)));
94
- const totalContent = groupWidths.reduce((a, b) => a + b, 0);
95
- const separator = ` ${C.dim}│${C.reset} `;
96
- const sepWidth = visibleWidth(PANEL_BG + separator.replace(/\x1b\[0m/g, PANEL_RST));
97
- const totalSep = sepWidth * (groups.length - 1);
98
- const available = width - indent - totalContent - totalSep;
99
- const gapSize = groups.length > 1 ? Math.max(1, Math.floor(available / (groups.length - 1))) : 0;
100
- const extra = groups.length > 1 ? available - gapSize * (groups.length - 1) : 0;
101
- let line = ' '.repeat(indent);
102
- for (let i = 0; i < groups.length; i++) {
103
- line += groups[i];
104
- if (i < groups.length - 1) {
105
- const gap = gapSize + (i < extra ? 1 : 0);
106
- line += separator + ' '.repeat(Math.max(0, gap));
96
+ /** Wrap a string (with ANSI codes) to fit within `maxWidth` visible chars.
97
+ * Splits at │ separators or whitespace when possible. */
98
+ function wrapLine(text, maxWidth) {
99
+ if (maxWidth <= 0)
100
+ return [text];
101
+ const result = [];
102
+ let current = "";
103
+ let currentW = 0;
104
+ // Split at boundaries first
105
+ const segments = text.split("│");
106
+ for (let i = 0; i < segments.length; i++) {
107
+ const seg = (i > 0 ? "│" : "") + segments[i];
108
+ const segW = visibleWidth(PANEL_BG + seg.replace(/\x1b\[0m/g, PANEL_RST));
109
+ if (currentW + segW <= maxWidth || currentW === 0) {
110
+ current += seg;
111
+ currentW += segW;
112
+ }
113
+ else {
114
+ result.push(current);
115
+ current = seg;
116
+ currentW = segW;
107
117
  }
108
118
  }
109
- return panelLine(line, width);
119
+ if (current)
120
+ result.push(current);
121
+ return result;
110
122
  }
111
123
  function panelLine(content, width) {
112
124
  const withBg = PANEL_BG + content.replace(/\x1b\[0m/g, PANEL_RST);
@@ -120,8 +132,10 @@ function panelBar(width, ch = "─") {
120
132
  /** Token-count formatter: M at/above 1e6, k at/above 1e3, raw below.
121
133
  * 5,472,700 → "5.5mil", 24,100 → "24.1k", 142 → "142". */
122
134
  function fmtTokens(x) {
123
- return x >= 1_000_000 ? `${(x / 1_000_000).toFixed(1)}mil`
124
- : x >= 1000 ? `${(x / 1000).toFixed(1)}k`
135
+ return x >= 1_000_000
136
+ ? `${(x / 1_000_000).toFixed(1)}mil`
137
+ : x >= 1000
138
+ ? `${(x / 1000).toFixed(1)}k`
125
139
  : `${Math.round(x)}`;
126
140
  }
127
141
  /** Retro gradient bar — `w` cells shaded by fill position (green→amber→red).
@@ -136,8 +150,10 @@ function ramp(pct, w = 12) {
136
150
  for (let i = 0; i < full; i++)
137
151
  out += (i / w < 0.6 ? C.green : i / w < 0.85 ? C.amber : C.red) + "█";
138
152
  if (fracCell)
139
- out += (full / w < 0.6 ? C.green : full / w < 0.85 ? C.amber : C.red) + fracCell;
140
- out += C.dim + "░".repeat(Math.max(0, w - full - (fracCell ? 1 : 0))) + C.reset;
153
+ out +=
154
+ (full / w < 0.6 ? C.green : full / w < 0.85 ? C.amber : C.red) + fracCell;
155
+ out +=
156
+ C.dim + "░".repeat(Math.max(0, w - full - (fracCell ? 1 : 0))) + C.reset;
141
157
  return out;
142
158
  }
143
159
  /** Human "time since" string from a millisecond delta (or null → "never"). */
@@ -268,7 +284,9 @@ export class MegaRuntime {
268
284
  * context event, or a `custom` tier with no tierPct). Always finite + in [0,1].
269
285
  */
270
286
  get pressure() {
271
- if (this.lastCtxWindow > 0 && this.config.tierPct != null && this.lastCtxPercent != null) {
287
+ if (this.lastCtxWindow > 0 &&
288
+ this.config.tierPct != null &&
289
+ this.lastCtxPercent != null) {
272
290
  // pressureFromPct(x) = x/100, and x = lastCtxPercent/tierPct, so this is
273
291
  // exactly the intended lastCtxPercent/(tierPct*100) 0–1 ratio: at the
274
292
  // fire point (lastCtxPercent == tierPct*100) pressure == 1.0, matching the
@@ -276,7 +294,9 @@ export class MegaRuntime {
276
294
  // the band doesn't jump when a token-count vs percent-only event arrives.
277
295
  return pressureFromPct(this.lastCtxPercent / this.config.tierPct);
278
296
  }
279
- if (this.lastCtxTokens != null && this.lastCtxTokens > 0 && this.config.thresholdTokens > 0) {
297
+ if (this.lastCtxTokens != null &&
298
+ this.lastCtxTokens > 0 &&
299
+ this.config.thresholdTokens > 0) {
280
300
  return pressureRatio(this.lastCtxTokens, this.config.thresholdTokens);
281
301
  }
282
302
  return pressureFromPct(this.lastCtxPercent);
@@ -302,8 +322,14 @@ export class MegaRuntime {
302
322
  }
303
323
  constructor(config) {
304
324
  this.config = config;
305
- this.store = new VectorStore({ dedupSim: config.dedupSim, stateDir: config.stateDir });
306
- this.logger = new Logger({ enabled: config.debug, path: join(config.stateDir, "mega-compact.log") });
325
+ this.store = new VectorStore({
326
+ dedupSim: config.dedupSim,
327
+ stateDir: config.stateDir,
328
+ });
329
+ this.logger = new Logger({
330
+ enabled: config.debug,
331
+ path: join(config.stateDir, "mega-compact.log"),
332
+ });
307
333
  this.dashboard = new Dashboard(config.stateDir);
308
334
  this.currentStateDir = config.stateDir;
309
335
  }
@@ -314,14 +340,22 @@ export class MegaRuntime {
314
340
  * and events are fully isolated. Falls back to the global default outside git.
315
341
  */
316
342
  bindRepo(cwd) {
317
- const dir = cwd ? repoStateDir(cwd, this.config.stateDir) : this.config.stateDir;
318
- const key = cwd ? resolveRepoRoot(cwd) ?? dir : dir;
343
+ const dir = cwd
344
+ ? repoStateDir(cwd, this.config.stateDir)
345
+ : this.config.stateDir;
346
+ const key = cwd ? (resolveRepoRoot(cwd) ?? dir) : dir;
319
347
  if (key === this.activeRepoRoot)
320
348
  return dir;
321
349
  this.activeRepoRoot = key;
322
350
  this.currentStateDir = dir;
323
- this.store = new VectorStore({ dedupSim: this.config.dedupSim, stateDir: dir });
324
- this.logger = new Logger({ enabled: this.config.debug, path: join(dir, "mega-compact.log") });
351
+ this.store = new VectorStore({
352
+ dedupSim: this.config.dedupSim,
353
+ stateDir: dir,
354
+ });
355
+ this.logger = new Logger({
356
+ enabled: this.config.debug,
357
+ path: join(dir, "mega-compact.log"),
358
+ });
325
359
  this.dashboard = new Dashboard(dir);
326
360
  // Aggregate this repo into the machine-wide index so the multi-repo
327
361
  // dashboard (Summary / All-repos tabs) can show it alongside every other
@@ -331,7 +365,7 @@ export class MegaRuntime {
331
365
  try {
332
366
  const repo = this.store.repoStats();
333
367
  const di = this.store.dataInvariant();
334
- const root = key !== dir ? key : resolveRepoRoot(cwd ?? dir) ?? dir;
368
+ const root = key !== dir ? key : (resolveRepoRoot(cwd ?? dir) ?? dir);
335
369
  upsertRepoRegistry({
336
370
  repoRoot: root,
337
371
  displayName: root.split(/[\\/]/).filter(Boolean).pop() ?? root,
@@ -371,7 +405,9 @@ export class MegaRuntime {
371
405
  // armed lights at/above the REAL fire point: max(effectiveThresholdPct,
372
406
  // fastGatePct). fastGatePct already equals tierPct*100 by default, but a
373
407
  // MEGACOMPACT_FAST_GATE_PCT override can raise it, so we take the max.
374
- const armed = this.lastCtxPercent != null && this.lastCtxPercent >= Math.max(effectiveThresholdPct ?? 0, this.config.fastGatePct);
408
+ const armed = this.lastCtxPercent != null &&
409
+ this.lastCtxPercent >=
410
+ Math.max(effectiveThresholdPct ?? 0, this.config.fastGatePct);
375
411
  const ready = armed && (this.lastCtxTokens ?? 0) >= this.effectiveThreshold;
376
412
  this.dashboard.snapshot({
377
413
  version: 1,
@@ -401,10 +437,32 @@ export class MegaRuntime {
401
437
  dedupSkips: this.rt.dedupSkips,
402
438
  dedupAttempts: this.rt.dedupAttempts,
403
439
  },
404
- context: { tokens: this.lastCtxTokens, percent: this.lastCtxPercent, contextWindow: this.lastCtxWindow },
405
- trigger: { armed, ready, currentTokens: this.lastCtxTokens, thresholdTokens: this.effectiveThreshold, fastGatePct: this.config.fastGatePct, tierPct: this.config.tierPct, effectiveThresholdPct },
440
+ context: {
441
+ tokens: this.lastCtxTokens,
442
+ percent: this.lastCtxPercent,
443
+ contextWindow: this.lastCtxWindow,
444
+ },
445
+ trigger: {
446
+ armed,
447
+ ready,
448
+ currentTokens: this.lastCtxTokens,
449
+ thresholdTokens: this.effectiveThreshold,
450
+ fastGatePct: this.config.fastGatePct,
451
+ tierPct: this.config.tierPct,
452
+ effectiveThresholdPct,
453
+ },
406
454
  crew: { activeAgents: this.activeAgents, currentTurn: this.currentTurn },
407
- store: { checkpointCount: st.checkpointCount, totalTokenEstimate: st.totalTokenEstimate, originalTokens: st.originalTokens, tokensSaved: this.rt.tokensSaved, injectedCount: st.injectedCount, dedupHitRate: st.dedupHitRate, storageDedupRate: st.storageDedupRate, dedupAttempts: st.dedupAttempts, dedupCollapsed: st.dedupCollapsed },
455
+ store: {
456
+ checkpointCount: st.checkpointCount,
457
+ totalTokenEstimate: st.totalTokenEstimate,
458
+ originalTokens: st.originalTokens,
459
+ tokensSaved: this.rt.tokensSaved,
460
+ injectedCount: st.injectedCount,
461
+ dedupHitRate: st.dedupHitRate,
462
+ storageDedupRate: st.storageDedupRate,
463
+ dedupAttempts: st.dedupAttempts,
464
+ dedupCollapsed: st.dedupCollapsed,
465
+ },
408
466
  // Reconciled token accounting (single canonical formula, session + repo).
409
467
  // Freed = In − Out; In = Freed + Out. session.Freed = rt.tokensSaved (incl.
410
468
  // deduped-away originals); repo.Freed = repo.tokensSaved meta counter.
@@ -413,14 +471,19 @@ export class MegaRuntime {
413
471
  tokensIn: this.rt.tokensSaved + st.totalTokenEstimate,
414
472
  tokensOut: st.totalTokenEstimate,
415
473
  tokensFreed: this.rt.tokensSaved,
416
- compressionPct: (this.rt.tokensSaved + st.totalTokenEstimate) > 0 ? this.rt.tokensSaved / (this.rt.tokensSaved + st.totalTokenEstimate) : 0,
474
+ compressionPct: this.rt.tokensSaved + st.totalTokenEstimate > 0
475
+ ? this.rt.tokensSaved /
476
+ (this.rt.tokensSaved + st.totalTokenEstimate)
477
+ : 0,
417
478
  dedupPct: st.storageDedupRate,
418
479
  },
419
480
  repo: {
420
481
  tokensIn: repo.tokensSaved + repo.totalTokenEstimate,
421
482
  tokensOut: repo.totalTokenEstimate,
422
483
  tokensFreed: repo.tokensSaved,
423
- compressionPct: (repo.tokensSaved + repo.totalTokenEstimate) > 0 ? repo.tokensSaved / (repo.tokensSaved + repo.totalTokenEstimate) : 0,
484
+ compressionPct: repo.tokensSaved + repo.totalTokenEstimate > 0
485
+ ? repo.tokensSaved / (repo.tokensSaved + repo.totalTokenEstimate)
486
+ : 0,
424
487
  dedupPct: repo.storageDedupRate,
425
488
  },
426
489
  },
@@ -445,14 +508,24 @@ export class MegaRuntime {
445
508
  // Live stats widget above the editor
446
509
  if (ctx) {
447
510
  // ── gather widget data (computed per snapshot, rendered per frame) ────
448
- const tokStr = this.lastCtxTokens != null ? `${Math.round(this.lastCtxTokens / 1000)}k` : "?";
449
- const maxStr = this.lastCtxWindow > 0 ? `${Math.round(this.lastCtxWindow / 1000)}k` : "?";
450
- const pctStr = this.lastCtxPercent != null ? `${Math.round(this.lastCtxPercent * 10) / 10}%` : "?%";
511
+ const tokStr = this.lastCtxTokens != null
512
+ ? `${Math.round(this.lastCtxTokens / 1000)}k`
513
+ : "?";
514
+ const maxStr = this.lastCtxWindow > 0
515
+ ? `${Math.round(this.lastCtxWindow / 1000)}k`
516
+ : "?";
517
+ const pctStr = this.lastCtxPercent != null
518
+ ? `${Math.round(this.lastCtxPercent * 10) / 10}%`
519
+ : "?%";
451
520
  // S24: the tier label is the LIVE pressure band (low/medium/high/ultra/
452
521
  // mega), not the static env preset. It climbs as context fills.
453
522
  const liveBand = this.pressureBand;
454
523
  const tierLabel = `${C.bold}${liveBand}${C.reset}${C.gray}·${this.config.tier}${C.reset}`;
455
- const triggerLabel = ready ? `${C.green}● ready${C.reset}` : armed ? `${C.amber}◐ armed${C.reset}` : `${C.gray}○ idle${C.reset}`;
524
+ const triggerLabel = ready
525
+ ? `${C.green}● ready${C.reset}`
526
+ : armed
527
+ ? `${C.amber}◐ armed${C.reset}`
528
+ : `${C.gray}○ idle${C.reset}`;
456
529
  // Storage dedup rate is cumulative (store-wide, per-repo) and survives
457
530
  // session resets. Always show a number (decimal for sub-10%).
458
531
  const storageRate = st.storageDedupRate; // 0..1
@@ -477,27 +550,55 @@ export class MegaRuntime {
477
550
  const ctxPct = this.lastCtxPercent != null ? this.lastCtxPercent / 100 : 0;
478
551
  // Model + provider (S26 capture) for the header.
479
552
  const modelName = modelSnap?.modelName ?? modelSnap?.modelId ?? "?";
480
- const modelStr = modelSnap?.provider ? `${modelName}·${modelSnap.provider}` : modelName;
553
+ const modelStr = modelSnap?.provider
554
+ ? `${modelName}·${modelSnap.provider}`
555
+ : modelName;
481
556
  // Since-last-compact (ms; null until first compaction this session).
482
- const sinceCompact = this.rt.lastCompactAt != null ? Date.now() - this.rt.lastCompactAt : null;
557
+ const sinceCompact = this.rt.lastCompactAt != null
558
+ ? Date.now() - this.rt.lastCompactAt
559
+ : null;
483
560
  // Memory store: embedder + compression ratio (original / stored).
484
561
  const embedderName = this.embedderName();
485
562
  const compRatio = st.originalTokens > 0 && st.totalTokenEstimate > 0
486
563
  ? st.originalTokens / st.totalTokenEstimate
487
- : (st.originalTokens > 0 ? 1 : 0);
564
+ : st.originalTokens > 0
565
+ ? 1
566
+ : 0;
488
567
  const compStr = compRatio >= 1 ? `${compRatio.toFixed(1)}x` : "—";
489
568
  // Cross-repo drift status (cached, read-only).
490
569
  const driftStatus = this.driftStatus();
491
570
  const agentsActive = this.activeAgents > 0;
492
571
  this.widgetData = {
493
572
  version: ownVersion(),
494
- tierLabel, triggerLabel, pctStr, tokStr, maxStr, ctxPct,
495
- chk: st.checkpointCount, agentStr, turnStr, dedupStr,
496
- sessIn, sessKept, sTxt, repoIn, repoKept, rTxt,
497
- repoChk: repo.checkpointCount, repoSess: repo.sessionCount,
498
- modelStr, sinceCompact, embedderName, compStr, driftStatus, agentsActive,
573
+ tierLabel,
574
+ triggerLabel,
575
+ pctStr,
576
+ tokStr,
577
+ maxStr,
578
+ ctxPct,
579
+ chk: st.checkpointCount,
580
+ agentStr,
581
+ turnStr,
582
+ dedupStr,
583
+ sessIn,
584
+ sessKept,
585
+ sTxt,
586
+ repoIn,
587
+ repoKept,
588
+ rTxt,
589
+ repoChk: repo.checkpointCount,
590
+ repoSess: repo.sessionCount,
591
+ modelStr,
592
+ sinceCompact,
593
+ embedderName,
594
+ compStr,
595
+ driftStatus,
596
+ agentsActive,
499
597
  fresh: Date.now() - this.lastActivityAt < 4000,
500
- ticker: this.ticker, lastWhy: this.lastWhy, tierTrace: this.tierTrace, pulsing: this.pulsing,
598
+ ticker: this.ticker,
599
+ lastWhy: this.lastWhy,
600
+ tierTrace: this.tierTrace,
601
+ pulsing: this.pulsing,
501
602
  };
502
603
  // Auto-fit: register a factory so pi re-renders the panel at the REAL
503
604
  // terminal width every frame (tui.columns), instead of guessing with
@@ -520,31 +621,35 @@ export class MegaRuntime {
520
621
  buildWidgetLines(width) {
521
622
  const wd = this.widgetData;
522
623
  if (!wd) {
523
- return [panelBar(width, "─"), panelLine(" mega-compact: warming up…", width), panelBar(width, "─")];
624
+ return [
625
+ panelBar(width, "─"),
626
+ panelLine(" mega-compact: warming up…", width),
627
+ panelBar(width, "─"),
628
+ ];
524
629
  }
525
- const pulse = wd.pulsing ? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} ` : "";
630
+ const pulse = wd.pulsing
631
+ ? `${C.cyan}${PULSE[Math.floor(Date.now() / 250) % PULSE.length]}${C.reset} `
632
+ : "";
633
+ const sep = ` ${C.dim}│${C.reset} `;
634
+ // Build one long content line — let terminal wrap it naturally
635
+ const content = [
636
+ `${C.amber}⚡ ${wd.tierLabel}${C.reset} v${C.bold}${wd.version}${C.reset} ${ramp(wd.ctxPct, 20)} ${C.bold}${wd.pctStr}${C.reset} ${wd.tokStr}/${wd.maxStr}`,
637
+ wd.triggerLabel,
638
+ `${C.cyan}${wd.modelStr}${C.reset}`,
639
+ `${wd.chk} chk${wd.agentStr}${wd.turnStr}`,
640
+ `${C.magenta}dup ${wd.dedupStr}${C.reset}`,
641
+ `${C.gray}sess${C.reset} ${fmtTokens(wd.sessIn)}→${fmtTokens(wd.sessKept)} kept ${C.green}(${wd.sTxt}% freed)${C.reset}`,
642
+ `${C.gray}all-time${C.reset} ${fmtTokens(wd.repoIn)}→${fmtTokens(wd.repoKept)} kept ${C.blue}(${wd.rTxt}% freed)${C.reset}`,
643
+ `${wd.repoChk} chk/${wd.repoSess} sess`,
644
+ `${C.gray}mem${C.reset} ${wd.embedderName} · ${wd.chk} chunks · ${C.blue}comp ${wd.compStr}${C.reset}`,
645
+ `${C.gray}drift${C.reset} ${wd.driftStatus === "ok" ? C.green : C.amber}${wd.driftStatus}${C.reset}`,
646
+ `${C.gray}compact${C.reset} ${sinceCompactStr(wd.sinceCompact)}`,
647
+ ].join(sep);
648
+ // Wrap to terminal width and pad each line
649
+ const wrapped = wrapLine(content, width - 2); // 2-char indent
526
650
  const lines = [
527
- // top border
528
651
  panelBar(width, "─"),
529
- // L1 header: tier + ctx bar + pct/tokens + status + model + chk + agents/turn
530
- spreadGroups(width, [
531
- `${C.amber}⚡ ${wd.tierLabel}${C.reset} v${C.bold}${wd.version}${C.reset} ${ramp(wd.ctxPct, 20)} ${C.bold}${wd.pctStr}${C.reset} ${wd.tokStr}/${wd.maxStr}`,
532
- wd.triggerLabel,
533
- `${C.cyan}${wd.modelStr}${C.reset}`,
534
- `${wd.chk} chk${wd.agentStr}${wd.turnStr}`,
535
- ]),
536
- // L2 — savings reconciled (session + all-time)
537
- spreadGroups(width, [
538
- `${C.magenta}dup ${wd.dedupStr}${C.reset}`,
539
- `${C.gray}sess${C.reset} ${fmtTokens(wd.sessIn)}→${fmtTokens(wd.sessKept)} kept ${C.green}(${wd.sTxt}% freed)${C.reset} · ${C.gray}all-time${C.reset} ${fmtTokens(wd.repoIn)}→${fmtTokens(wd.repoKept)} kept ${C.blue}(${wd.rTxt}% freed)${C.reset}`,
540
- `${wd.repoChk} chk/${wd.repoSess} sess`,
541
- ]),
542
- // L3 — memory store + compression + drift + since-compact (NEW)
543
- spreadGroups(width, [
544
- `${C.gray}mem${C.reset} ${wd.embedderName} · ${wd.chk} chunks · ${C.blue}comp ${wd.compStr}${C.reset}`,
545
- `${C.gray}drift${C.reset} ${wd.driftStatus === "ok" ? C.green : C.amber}${wd.driftStatus}${C.reset}`,
546
- `${C.gray}compact${C.reset} ${sinceCompactStr(wd.sinceCompact)}`,
547
- ]),
652
+ ...wrapped.map((l) => panelLine(l, width)),
548
653
  ];
549
654
  // L4 — agents block (S27, count + status; per-agent tokens gated on P0)
550
655
  if (wd.agentsActive) {
@@ -559,7 +664,9 @@ export class MegaRuntime {
559
664
  const idx = wd.ticker.length - 1 - (step % wd.ticker.length);
560
665
  const head = wd.ticker[idx].text;
561
666
  const why = wd.lastWhy ? ` ${C.gray}· ${wd.lastWhy}${C.reset}` : "";
562
- const more = wd.ticker.length > 1 ? ` ${C.dim}(+${wd.ticker.length - 1} more)${C.reset}` : "";
667
+ const more = wd.ticker.length > 1
668
+ ? ` ${C.dim}(+${wd.ticker.length - 1} more)${C.reset}`
669
+ : "";
563
670
  lines.push(panelLine(` ${wd.fresh ? C.teal : C.dim}${head}${why}${more}${C.reset}`, width));
564
671
  }
565
672
  else if (wd.pulsing) {
@@ -573,7 +680,8 @@ export class MegaRuntime {
573
680
  embedderName() {
574
681
  // MINILM_EMBEDDER flag lives in src/config/dedup.ts; read the same env var
575
682
  // the embedder factory uses so the label matches what's actually running.
576
- return process.env.MEGACOMPACT_MINILM === "true" || process.env.MEGACOMPACT_MINILM === "1"
683
+ return process.env.MEGACOMPACT_MINILM === "true" ||
684
+ process.env.MEGACOMPACT_MINILM === "1"
577
685
  ? "MiniLM"
578
686
  : "Trigram";
579
687
  }
@@ -633,13 +741,18 @@ export class MegaRuntime {
633
741
  this.appendEvent("captureModel:no-model", { cwd: ctx.cwd });
634
742
  return;
635
743
  }
636
- if (this.currentModel && this.currentModel.modelId === m.id && this.currentModel.provider === m.provider)
744
+ if (this.currentModel &&
745
+ this.currentModel.modelId === m.id &&
746
+ this.currentModel.provider === m.provider)
637
747
  return;
638
748
  let providerName = null;
639
749
  try {
640
- providerName = ctx.modelRegistry?.getProviderDisplayName(m.provider) ?? null;
750
+ providerName =
751
+ ctx.modelRegistry?.getProviderDisplayName(m.provider) ?? null;
752
+ }
753
+ catch {
754
+ /* optional */
641
755
  }
642
- catch { /* optional */ }
643
756
  const snap = {
644
757
  provider: m.provider,
645
758
  providerName,
@@ -661,14 +774,18 @@ export class MegaRuntime {
661
774
  try {
662
775
  recordModelSnapshot(repo, snap, this.currentStateDir);
663
776
  this.appendEvent("captureModel:recorded", {
664
- repo, modelId: snap.modelId, provider: snap.provider,
665
- inputRate: snap.inputRate, outputRate: snap.outputRate,
777
+ repo,
778
+ modelId: snap.modelId,
779
+ provider: snap.provider,
780
+ inputRate: snap.inputRate,
781
+ outputRate: snap.outputRate,
666
782
  });
667
783
  }
668
784
  catch (e) {
669
785
  this.diagCaptureModelFails++;
670
786
  this.appendEvent("captureModel:record-failed", {
671
- repo, modelId: snap.modelId,
787
+ repo,
788
+ modelId: snap.modelId,
672
789
  error: e instanceof Error ? e.message : String(e),
673
790
  stack: e instanceof Error ? e.stack : undefined,
674
791
  });
@@ -689,7 +806,8 @@ export class MegaRuntime {
689
806
  }
690
807
  catch (e) {
691
808
  this.appendEvent("captureModel:index-record-failed", {
692
- repo, modelId: snap.modelId,
809
+ repo,
810
+ modelId: snap.modelId,
693
811
  error: e instanceof Error ? e.message : String(e),
694
812
  });
695
813
  }
@@ -705,7 +823,9 @@ export class MegaRuntime {
705
823
  mkdirSync(this.currentStateDir, { recursive: true });
706
824
  appendFileSync(join(this.currentStateDir, "events.log"), JSON.stringify({ ts: Date.now(), event, ...fields }) + "\n");
707
825
  }
708
- catch { /* non-fatal */ }
826
+ catch {
827
+ /* non-fatal */
828
+ }
709
829
  }
710
830
  /** S21: state dir of the currently bound repo (where memories live). */
711
831
  getStateDir() {
@@ -715,10 +835,13 @@ export class MegaRuntime {
715
835
  makeTierCallback(ctx) {
716
836
  const order = ["L0", "L1", "L2", "new"];
717
837
  const seen = new Map();
718
- const glyph = (status) => status === "deduped" ? `${C.green}✓${C.reset}` :
719
- status === "passed" ? `${C.dim}○${C.reset}` :
720
- status === "scanning" ? `${C.amber}…${C.reset}` :
721
- `${C.cyan}●${C.reset}`;
838
+ const glyph = (status) => status === "deduped"
839
+ ? `${C.green}✓${C.reset}`
840
+ : status === "passed"
841
+ ? `${C.dim}○${C.reset}`
842
+ : status === "scanning"
843
+ ? `${C.amber}…${C.reset}`
844
+ : `${C.cyan}●${C.reset}`;
722
845
  return (ev) => {
723
846
  const label = ev.tier === "new"
724
847
  ? `${C.cyan}stored${C.reset}`
@@ -735,7 +858,9 @@ export class MegaRuntime {
735
858
  try {
736
859
  this.snapshot(ctx);
737
860
  }
738
- catch { /* non-fatal */ }
861
+ catch {
862
+ /* non-fatal */
863
+ }
739
864
  };
740
865
  }
741
866
  // Phase 3 — recall/activity ticker ring buffer.