pi-mega-compact 0.7.7 → 0.7.9
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 +11 -12
- package/dist/extensions/dashboard-server/helpers.js +37 -0
- package/dist/extensions/dashboard-server/html/all-repos-tab.js +26 -0
- package/dist/extensions/dashboard-server/html/body-open.js +23 -0
- package/dist/extensions/dashboard-server/html/current-repo-tab.js +130 -0
- package/dist/extensions/dashboard-server/html/head-open.js +16 -0
- package/dist/extensions/dashboard-server/html/high-score-tab.js +25 -0
- package/dist/extensions/dashboard-server/html/repo-detail-modal.js +26 -0
- package/dist/extensions/dashboard-server/html/script.js +259 -0
- package/dist/extensions/dashboard-server/html/styles.js +103 -0
- package/dist/extensions/dashboard-server/html/summary-tab.js +19 -0
- package/dist/extensions/dashboard-server/html-template.js +41 -0
- package/dist/extensions/dashboard-server/html.js +756 -0
- package/dist/extensions/dashboard-server/index-reader.js +133 -0
- package/dist/extensions/dashboard-server/server.js +370 -0
- package/dist/extensions/dashboard-server/snapshot.js +43 -0
- package/dist/extensions/dashboard-server/state.js +30 -0
- package/dist/extensions/dashboard-server/types.js +5 -0
- package/dist/extensions/dashboard-server.js +7 -1315
- package/dist/extensions/mega-commands.js +162 -134
- package/dist/extensions/mega-compact.test.js +292 -24
- package/dist/extensions/mega-config.js +10 -0
- package/dist/extensions/mega-conflict-cmds.js +5 -1
- package/dist/extensions/mega-dashboard-cmds.js +29 -22
- package/dist/extensions/mega-db-cmds.js +11 -2
- package/dist/extensions/mega-events/agent-handlers.js +173 -0
- package/dist/extensions/mega-events/compact-handlers.js +133 -0
- package/dist/extensions/mega-events/context-handler.js +249 -0
- package/dist/extensions/mega-events/register.js +21 -0
- package/dist/extensions/mega-events/session-handlers.js +142 -0
- package/dist/extensions/mega-events.js +15 -652
- package/dist/extensions/mega-pipeline/compact.js +324 -0
- package/dist/extensions/mega-pipeline/memory-review.js +38 -0
- package/dist/extensions/mega-pipeline/recall.js +147 -0
- package/dist/extensions/mega-pipeline.js +9 -480
- package/dist/extensions/mega-runtime/helpers.js +40 -0
- package/dist/extensions/mega-runtime/query.js +29 -0
- package/dist/extensions/mega-runtime/state.js +711 -0
- package/dist/extensions/mega-runtime/widget.js +197 -0
- package/dist/extensions/mega-runtime.js +15 -932
- package/dist/src/store/sqlite/checkpoints.js +145 -0
- package/dist/src/store/sqlite/connection.js +35 -0
- package/dist/src/store/sqlite/dedup-mirror.js +64 -0
- package/dist/src/store/sqlite/foundation.js +38 -0
- package/dist/src/store/sqlite/global-index.js +224 -0
- package/dist/src/store/sqlite/index-store.js +167 -0
- package/dist/src/store/sqlite/maintenance.js +235 -0
- package/dist/src/store/sqlite/memories.js +164 -0
- package/dist/src/store/sqlite/memory.js +54 -0
- package/dist/src/store/sqlite/meta.js +82 -0
- package/dist/src/store/sqlite/minhash-lsh.js +47 -0
- package/dist/src/store/sqlite/model-snapshots.js +47 -0
- package/dist/src/store/sqlite/raptor.js +57 -0
- package/dist/src/store/sqlite/raw-transcript.js +134 -0
- package/dist/src/store/sqlite/schema.js +250 -0
- package/dist/src/store/sqlite/session-state.js +28 -0
- package/dist/src/store/sqlite/sessions.js +39 -0
- package/dist/src/store/sqlite/stats.js +66 -0
- package/dist/src/store/sqlite/transaction.js +19 -0
- package/dist/src/store/sqlite/utils.js +120 -0
- package/dist/src/store/sqlite.js +20 -1607
- package/dist/src/vectorStore/add.js +260 -0
- package/dist/src/vectorStore/dedup.js +52 -0
- package/dist/src/vectorStore/index.js +10 -0
- package/dist/src/vectorStore/queries.js +83 -0
- package/dist/src/vectorStore/search.js +95 -0
- package/dist/src/vectorStore/session.js +19 -0
- package/dist/src/vectorStore/store.js +105 -0
- package/dist/src/vectorStore/types.js +6 -0
- package/dist/src/vectorStore/utils.js +23 -0
- package/extensions/dashboard-server/html.ts +758 -0
- package/extensions/dashboard-server/index-reader.ts +130 -0
- package/extensions/dashboard-server/server.ts +358 -0
- package/extensions/dashboard-server/snapshot.ts +44 -0
- package/extensions/dashboard-server/state.ts +33 -0
- package/extensions/dashboard-server/types.ts +134 -0
- package/extensions/dashboard-server.ts +7 -1431
- package/extensions/mega-commands.ts +33 -10
- package/extensions/mega-compact.test.ts +453 -37
- package/extensions/mega-config.ts +22 -0
- package/extensions/mega-conflict-cmds.ts +6 -2
- package/extensions/mega-dashboard-cmds.ts +30 -23
- package/extensions/mega-db-cmds.ts +11 -3
- package/extensions/mega-events/agent-handlers.ts +214 -0
- package/extensions/mega-events/compact-handlers.ts +164 -0
- package/extensions/mega-events/context-handler.ts +290 -0
- package/extensions/mega-events/register.ts +37 -0
- package/extensions/mega-events/session-handlers.ts +165 -0
- package/extensions/mega-events.ts +15 -732
- package/extensions/mega-pipeline/compact.ts +366 -0
- package/extensions/mega-pipeline/memory-review.ts +46 -0
- package/extensions/mega-pipeline/recall.ts +165 -0
- package/extensions/mega-pipeline.ts +9 -537
- package/extensions/mega-runtime/helpers.ts +68 -0
- package/extensions/mega-runtime/query.ts +29 -0
- package/extensions/mega-runtime/state.ts +797 -0
- package/extensions/mega-runtime/widget.ts +258 -0
- package/extensions/mega-runtime.ts +15 -1076
- package/package.json +4 -3
- package/src/store/sqlite/checkpoints.ts +204 -0
- package/src/store/sqlite/dedup-mirror.ts +114 -0
- package/src/store/sqlite/foundation.ts +63 -0
- package/src/store/sqlite/global-index.ts +305 -0
- package/src/store/sqlite/maintenance.ts +294 -0
- package/src/store/sqlite/memories.ts +217 -0
- package/src/store/sqlite/meta.ts +108 -0
- package/src/store/sqlite/model-snapshots.ts +83 -0
- package/src/store/sqlite/raptor.ts +107 -0
- package/src/store/sqlite/raw-transcript.ts +221 -0
- package/src/store/sqlite/schema.ts +258 -0
- package/src/store/sqlite/session-state.ts +38 -0
- package/src/store/sqlite/stats.ts +127 -0
- package/src/store/sqlite/utils.ts +125 -0
- package/src/store/sqlite.ts +20 -2204
|
@@ -9,7 +9,7 @@ import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
|
|
|
9
9
|
import { normalizeSessionId } from "../src/store.js";
|
|
10
10
|
import { listCheckpoints, latestModelSnapshot, countInjectedGlobal, listRepoRegistry } from "../src/store/sqlite.js";
|
|
11
11
|
import { decompressSmart } from "../src/store/compression.js";
|
|
12
|
-
import { loadMetrics, fpRate, p95 } from "../src/monitoring.js";
|
|
12
|
+
import { loadMetrics, fpRate, p95, defaultMetricsPath } from "../src/monitoring.js";
|
|
13
13
|
import { C, recentUserQuery } from "./mega-runtime.js";
|
|
14
14
|
import { runCompact, doRecall, doRecallAsync } from "./mega-pipeline.js";
|
|
15
15
|
/** Resolve a checkpoint by id (or "recent"/"last") from this session's store. */
|
|
@@ -26,149 +26,172 @@ export function registerCommands(pi, runtime, config) {
|
|
|
26
26
|
pi.registerCommand("mega-compact", {
|
|
27
27
|
description: "Compress current session context into the local vector store.",
|
|
28
28
|
handler: async (args, ctx) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
try {
|
|
30
|
+
const sessionEntries = ctx.sessionManager.getEntries();
|
|
31
|
+
// Project entries (branch-aware) into the message view.
|
|
32
|
+
const messages = sessionEntries.flatMap((e) => sessionEntryToContextMessages(e));
|
|
33
|
+
const summaryArg = args.trim();
|
|
34
|
+
const ran = runCompact(pi, runtime, config, ctx, messages, summaryArg ? { summary: summaryArg } : {});
|
|
35
|
+
if ("skipped" in ran && ran.skipped) {
|
|
36
|
+
ctx.ui.notify("[mega-compact] Nothing to compact (session too small).");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const r = ran.result;
|
|
40
|
+
ctx.ui.notify(`[mega-compact] ${r.deduped ? "region already compacted (deduped)" : `persisted ${r.checkpointId}`} · ` +
|
|
41
|
+
`${r.tokenEstimate} tok · ${runtime.currentStateDir}`);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
ctx.ui.notify(`[mega-compact] /mega-compact failed: ${String(e)}`);
|
|
37
45
|
}
|
|
38
|
-
const r = ran.result;
|
|
39
|
-
ctx.ui.notify(`[mega-compact] ${r.deduped ? "region already compacted (deduped)" : `persisted ${r.checkpointId}`} · ` +
|
|
40
|
-
`${r.tokenEstimate} tok · ${runtime.currentStateDir}`);
|
|
41
46
|
},
|
|
42
47
|
});
|
|
43
48
|
pi.registerCommand("mega-recall", {
|
|
44
49
|
description: "Recall relevant compacted context from the vector store and inline it. Use --cross-repo to search all repos.",
|
|
45
50
|
handler: async (args, ctx) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
try {
|
|
52
|
+
// S17: --cross-repo (or --cross repo) runs the async path over every repo's
|
|
53
|
+
// PGlite HNSW index (stricter cosine floor + source labels).
|
|
54
|
+
const crossRepo = /--cross[- ]repo\b/.test(args);
|
|
55
|
+
const query = args.replace(/--cross[- ]repo\b/, "").trim() || recentUserQuery(ctx);
|
|
56
|
+
if (!query) {
|
|
57
|
+
ctx.ui.notify("[mega-compact] /mega-recall needs a query or a prior user message.");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const r = crossRepo
|
|
61
|
+
? await doRecallAsync(runtime, config, ctx, query, "command", { crossRepo: true })
|
|
62
|
+
: doRecall(runtime, config, ctx, query, "command");
|
|
63
|
+
if (r.empty) {
|
|
64
|
+
runtime.logger.info("recall-empty", { query, crossRepo });
|
|
65
|
+
ctx.ui.notify(`[mega-compact] recall found nothing new for "${query}".`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Stage the block so the next before_agent_start prepends it (actual
|
|
69
|
+
// injection). Report what was selected now for immediate feedback.
|
|
70
|
+
runtime.pendingRecallBlock = r.block;
|
|
71
|
+
const list = r.report.map((l) => l).join("\n");
|
|
72
|
+
runtime.logger.info("recall", { query, crossRepo, injected: r.toInject.map((h) => h.checkpoint.checkpointId) });
|
|
73
|
+
runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt${crossRepo ? " (cross-repo)" : ""}`);
|
|
74
|
+
ctx.ui.notify(`[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}"${crossRepo ? " (cross-repo)" : ""}:\n${list}\n` +
|
|
75
|
+
`(injected at the next turn via system prompt)`);
|
|
53
76
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
: doRecall(runtime, config, ctx, query, "command");
|
|
57
|
-
if (r.empty) {
|
|
58
|
-
runtime.logger.info("recall-empty", { query, crossRepo });
|
|
59
|
-
ctx.ui.notify(`[mega-compact] recall found nothing new for "${query}".`);
|
|
60
|
-
return;
|
|
77
|
+
catch (e) {
|
|
78
|
+
ctx.ui.notify(`[mega-compact] /mega-recall failed: ${String(e)}`);
|
|
61
79
|
}
|
|
62
|
-
// Stage the block so the next before_agent_start prepends it (actual
|
|
63
|
-
// injection). Report what was selected now for immediate feedback.
|
|
64
|
-
runtime.pendingRecallBlock = r.block;
|
|
65
|
-
const list = r.report.map((l) => l).join("\n");
|
|
66
|
-
runtime.logger.info("recall", { query, crossRepo, injected: r.toInject.map((h) => h.checkpoint.checkpointId) });
|
|
67
|
-
runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt${crossRepo ? " (cross-repo)" : ""}`);
|
|
68
|
-
ctx.ui.notify(`[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}"${crossRepo ? " (cross-repo)" : ""}:\n${list}\n` +
|
|
69
|
-
`(injected at the next turn via system prompt)`);
|
|
70
80
|
},
|
|
71
81
|
});
|
|
72
82
|
pi.registerCommand("mega-status", {
|
|
73
83
|
description: "Show mega-compact config, context usage, and the data-safety invariant.",
|
|
74
84
|
handler: async (_args, ctx) => {
|
|
75
|
-
runtime.bindRepo(ctx.cwd);
|
|
76
|
-
const usage = ctx.getContextUsage();
|
|
77
|
-
const pct = usage?.percent != null ? `${usage.percent}%` : "n/a";
|
|
78
|
-
const tokens = usage?.tokens != null ? `${usage.tokens} tok` : "n/a";
|
|
79
|
-
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
80
|
-
const st = runtime.store.stats(sid);
|
|
81
|
-
const repo = runtime.store.repoStats();
|
|
82
|
-
const di = runtime.store.dataInvariant();
|
|
83
|
-
const fmtB = (b) => b >= 1_048_576 ? `${(b / 1_048_576).toFixed(1)} MiB` :
|
|
84
|
-
b >= 1024 ? `${(b / 1024).toFixed(1)} KiB` : `${b} B`;
|
|
85
|
-
// Real cost: tokens saved × the captured model's input rate (USD/token),
|
|
86
|
-
// read from the model_snapshots table (Phase 5b schema). Falls back to 0
|
|
87
|
-
// when no model has been captured yet. contextWindow ÷ savedRate = context
|
|
88
|
-
// windows extended (how much "extra" conversation the freed space buys).
|
|
89
|
-
const model = latestModelSnapshot(runtime.currentStateDir);
|
|
90
|
-
const rate = model?.inputRate ?? 0;
|
|
91
|
-
const usd = (repo.tokensSaved * rate).toFixed(4);
|
|
92
|
-
const ctxWindow = usage?.contextWindow ?? 0;
|
|
93
|
-
const daysExtended = ctxWindow > 0 && repo.tokensSaved > 0
|
|
94
|
-
? (repo.tokensSaved / ctxWindow).toFixed(1)
|
|
95
|
-
: "0";
|
|
96
|
-
// Identified model/provider (captured on model_select / session_start).
|
|
97
|
-
// Shows the human model name + provider so the user knows WHICH model's
|
|
98
|
-
// pricing drives the cost figure. Falls back when none captured yet.
|
|
99
|
-
const modelStr = model
|
|
100
|
-
? `${model.modelName ?? model.modelId} · ${model.providerName ?? model.provider}`
|
|
101
|
-
: "unknown (no model captured)";
|
|
102
|
-
const costStr = `≈ $${usd} saved · ${daysExtended} context-windows extended`;
|
|
103
|
-
// Recall-quality badge (Phase 4): trust score from monitoring metrics.
|
|
104
|
-
const m = loadMetrics(runtime.currentStateDir);
|
|
105
|
-
const fp = fpRate(m, "L2");
|
|
106
|
-
const p95L2 = p95(m.latency.L2 ?? []);
|
|
107
|
-
const relPct = (st.dedupHitRate * 100).toFixed(0);
|
|
108
|
-
const qualityStr = `recall ${relPct}% relevant · FP ${(fp * 100).toFixed(1)}% · L2 p95 ${p95L2.toFixed(0)}ms`;
|
|
109
|
-
// S18: cross-repo stats from the machine-wide index (best-effort; the
|
|
110
|
-
// index dir may be unset → 0/empty, never throws).
|
|
111
|
-
let crossRepoInjections = 0;
|
|
112
|
-
let repoCount = 0;
|
|
113
85
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
86
|
+
runtime.bindRepo(ctx.cwd);
|
|
87
|
+
const usage = ctx.getContextUsage();
|
|
88
|
+
const pct = usage?.percent != null ? `${usage.percent}%` : "n/a";
|
|
89
|
+
const tokens = usage?.tokens != null ? `${usage.tokens} tok` : "n/a";
|
|
90
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
91
|
+
const st = runtime.store.stats(sid);
|
|
92
|
+
const repo = runtime.store.repoStats();
|
|
93
|
+
const di = runtime.store.dataInvariant();
|
|
94
|
+
const fmtB = (b) => b >= 1_048_576 ? `${(b / 1_048_576).toFixed(1)} MiB` :
|
|
95
|
+
b >= 1024 ? `${(b / 1024).toFixed(1)} KiB` : `${b} B`;
|
|
96
|
+
// Real cost: tokens saved × the captured model's input rate (USD/token),
|
|
97
|
+
// read from the model_snapshots table (Phase 5b schema). Falls back to 0
|
|
98
|
+
// when no model has been captured yet. contextWindow ÷ savedRate = context
|
|
99
|
+
// windows extended (how much "extra" conversation the freed space buys).
|
|
100
|
+
const model = latestModelSnapshot(runtime.currentStateDir);
|
|
101
|
+
const rate = model?.inputRate ?? 0;
|
|
102
|
+
const usd = ((repo.tokensSaved ?? 0) * rate).toFixed(4);
|
|
103
|
+
const ctxWindow = usage?.contextWindow ?? 0;
|
|
104
|
+
const daysExtended = ctxWindow > 0 && repo.tokensSaved > 0
|
|
105
|
+
? (repo.tokensSaved / ctxWindow).toFixed(1)
|
|
106
|
+
: "0";
|
|
107
|
+
// Identified model/provider (captured on model_select / session_start).
|
|
108
|
+
// Shows the human model name + provider so the user knows WHICH model's
|
|
109
|
+
// pricing drives the cost figure. Falls back when none captured yet.
|
|
110
|
+
const modelStr = model
|
|
111
|
+
? `${model.modelName ?? model.modelId ?? "?"} · ${model.providerName ?? model.provider ?? "?"}`
|
|
112
|
+
: "unknown (no model captured)";
|
|
113
|
+
const costStr = `≈ $${usd} saved · ${daysExtended} context-windows extended`;
|
|
114
|
+
// Recall-quality badge (Phase 4): trust score from monitoring metrics.
|
|
115
|
+
// H1 fix: loadMetrics expects a *file* path (dashboard.json), not the
|
|
116
|
+
// state dir — passing the dir made existsSync() true (dirs exist) then
|
|
117
|
+
// readFileSync() threw EISDIR, silently caught → metrics always zero.
|
|
118
|
+
const m = loadMetrics(defaultMetricsPath(runtime.currentStateDir));
|
|
119
|
+
const fp = fpRate(m, "L2");
|
|
120
|
+
const p95L2 = p95(m.latency.L2 ?? []);
|
|
121
|
+
const relPct = (st.dedupHitRate * 100).toFixed(0);
|
|
122
|
+
const qualityStr = `recall ${relPct}% relevant · FP ${(fp * 100).toFixed(1)}% · L2 p95 ${p95L2.toFixed(0)}ms`;
|
|
123
|
+
// S18: cross-repo stats from the machine-wide index (best-effort; the
|
|
124
|
+
// index dir may be unset → 0/empty, never throws).
|
|
125
|
+
let crossRepoInjections = 0;
|
|
126
|
+
let repoCount = 0;
|
|
127
|
+
try {
|
|
128
|
+
crossRepoInjections = countInjectedGlobal(process.env.MEGACOMPACT_INDEX_DIR);
|
|
129
|
+
repoCount = listRepoRegistry(process.env.MEGACOMPACT_INDEX_DIR).length;
|
|
130
|
+
}
|
|
131
|
+
catch { /* non-fatal */ }
|
|
132
|
+
const crossRepoStr = `${crossRepoInjections} cross-repo injections recorded · ${repoCount} repos indexed`;
|
|
133
|
+
// Effective compaction threshold = tierPct × model context window (kept
|
|
134
|
+
// BELOW pi's native ~80% auto-compact for any model size). Falls back to
|
|
135
|
+
// the boot token value when the window is unknown (custom tier / pre-
|
|
136
|
+
// model-select). Display matches the dashboard's percentage-based view.
|
|
137
|
+
const effThreshold = config.tierPct != null && ctxWindow > 0
|
|
138
|
+
? Math.round(config.tierPct * ctxWindow)
|
|
139
|
+
: config.thresholdTokens;
|
|
140
|
+
const winStr = ctxWindow > 0
|
|
141
|
+
? (ctxWindow >= 1_000_000 ? `${Math.round(ctxWindow / 1_000_000)}M` : `${Math.round(ctxWindow / 1_000)}k`)
|
|
142
|
+
: "?";
|
|
143
|
+
const tierPctStr = config.tierPct != null ? `${Math.round(config.tierPct * 100)}%` : "n/a";
|
|
144
|
+
ctx.ui.notify(`[mega-compact] pct=${pct} tokens=${tokens} tier=${runtime.pressureBand} (live) preset=${config.tier} ` +
|
|
145
|
+
`pressure=${Math.round(runtime.pressure * 100)}% fastGate=${config.fastGatePct}% ` +
|
|
146
|
+
`threshold=${effThreshold.toLocaleString()} (${tierPctStr} of ${winStr} window) tierPct=${config.tierPct != null ? config.tierPct.toFixed(2) : "n/a"} auto=${config.auto} autoInline=${config.autoInline}\n` +
|
|
147
|
+
`[mega-compact] store: ${st.checkpointCount} chkpt · ` +
|
|
148
|
+
`${st.totalTokenEstimate} tok · last=${st.lastCheckpointId ?? "—"} · ` +
|
|
149
|
+
`injected=${st.injectedCount} · dedup=${(st.dedupHitRate * 100).toFixed(0)}%\n` +
|
|
150
|
+
`[mega-compact] anchor=${config.anchorUserMessages} preserveRecent=${config.preserveRecent} ` +
|
|
151
|
+
`autoInlineK=${config.autoInlineK} dedupSim=${config.dedupSim} debug=${config.debug}\n` +
|
|
152
|
+
`[mega-compact] 🛡 data-safe: ${di.regionsRetained} regions retained ` +
|
|
153
|
+
`(${fmtB(di.compressedOriginalBytes)} compressed-original) · ` +
|
|
154
|
+
`${di.duplicatesCollapsed} dedup-duplicates collapsed · ` +
|
|
155
|
+
`${C.green}0 bytes permanently deleted${C.reset}\n` +
|
|
156
|
+
`[mega-compact] 💰 ${costStr}\n` +
|
|
157
|
+
`[mega-compact] 🤖 model: ${modelStr}\n` +
|
|
158
|
+
`[mega-compact] 🎯 ${qualityStr}\n` +
|
|
159
|
+
`[mega-compact] 🌐 ${crossRepoStr}\n` +
|
|
160
|
+
`[mega-compact] stateDir=${runtime.currentStateDir}`);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
ctx.ui.notify(`[mega-compact] /mega-status error: ${String(e)}`);
|
|
116
164
|
}
|
|
117
|
-
catch { /* non-fatal */ }
|
|
118
|
-
const crossRepoStr = `${crossRepoInjections} cross-repo injections recorded · ${repoCount} repos indexed`;
|
|
119
|
-
// Effective compaction threshold = tierPct × model context window (kept
|
|
120
|
-
// BELOW pi's native ~80% auto-compact for any model size). Falls back to
|
|
121
|
-
// the boot token value when the window is unknown (custom tier / pre-
|
|
122
|
-
// model-select). Display matches the dashboard's percentage-based view.
|
|
123
|
-
const effThreshold = config.tierPct != null && ctxWindow > 0
|
|
124
|
-
? Math.round(config.tierPct * ctxWindow)
|
|
125
|
-
: config.thresholdTokens;
|
|
126
|
-
const winStr = ctxWindow > 0
|
|
127
|
-
? (ctxWindow >= 1_000_000 ? `${Math.round(ctxWindow / 1_000_000)}M` : `${Math.round(ctxWindow / 1_000)}k`)
|
|
128
|
-
: "?";
|
|
129
|
-
const tierPctStr = config.tierPct != null ? `${Math.round(config.tierPct * 100)}%` : "n/a";
|
|
130
|
-
ctx.ui.notify(`[mega-compact] pct=${pct} tokens=${tokens} tier=${runtime.pressureBand} (live) preset=${config.tier} ` +
|
|
131
|
-
`pressure=${Math.round(runtime.pressure * 100)}% fastGate=${config.fastGatePct}% ` +
|
|
132
|
-
`threshold=${effThreshold.toLocaleString()} (${tierPctStr} of ${winStr} window) tierPct=${config.tierPct != null ? config.tierPct.toFixed(2) : "n/a"} auto=${config.auto} autoInline=${config.autoInline}\n` +
|
|
133
|
-
`[mega-compact] store: ${st.checkpointCount} chkpt · ` +
|
|
134
|
-
`${st.totalTokenEstimate} tok · last=${st.lastCheckpointId ?? "—"} · ` +
|
|
135
|
-
`injected=${st.injectedCount} · dedup=${(st.dedupHitRate * 100).toFixed(0)}%\n` +
|
|
136
|
-
`[mega-compact] anchor=${config.anchorUserMessages} preserveRecent=${config.preserveRecent} ` +
|
|
137
|
-
`autoInlineK=${config.autoInlineK} dedupSim=${config.dedupSim} debug=${config.debug}\n` +
|
|
138
|
-
`[mega-compact] 🛡 data-safe: ${di.regionsRetained} regions retained ` +
|
|
139
|
-
`(${fmtB(di.compressedOriginalBytes)} compressed-original) · ` +
|
|
140
|
-
`${di.duplicatesCollapsed} dedup-duplicates collapsed · ` +
|
|
141
|
-
`${C.green}0 bytes permanently deleted${C.reset}\n` +
|
|
142
|
-
`[mega-compact] 💰 ${costStr}\n` +
|
|
143
|
-
`[mega-compact] 🤖 model: ${modelStr}\n` +
|
|
144
|
-
`[mega-compact] 🎯 ${qualityStr}\n` +
|
|
145
|
-
`[mega-compact] 🌐 ${crossRepoStr}\n` +
|
|
146
|
-
`[mega-compact] stateDir=${runtime.currentStateDir}`);
|
|
147
165
|
},
|
|
148
166
|
});
|
|
149
167
|
// ---- Phase 4: cheap standout commands (data is already persisted) -------
|
|
150
168
|
pi.registerCommand("mega-restore", {
|
|
151
169
|
description: "Re-inject a checkpoint's verbatim original region into context. Usage: /mega-restore <chkpt|recent>",
|
|
152
170
|
handler: async (args, ctx) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
171
|
+
try {
|
|
172
|
+
runtime.bindRepo(ctx.cwd);
|
|
173
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
174
|
+
const cp = findCheckpoint(runtime, sid, args.trim());
|
|
175
|
+
if (!cp) {
|
|
176
|
+
ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""} in this session. Try /mega-history.`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!cp.compressedOriginal) {
|
|
180
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} has no recoverable original (pre-blob or direct add). Cannot restore verbatim.`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
184
|
+
// Re-inject verbatim via before_agent_start (PREVENT-PI-003) — never
|
|
185
|
+
// touches live messages, only prepends the restored region to systemPrompt.
|
|
186
|
+
runtime.pendingRecallBlock = `The following compacted context was RESTORED from checkpoint ${cp.checkpointId} (verbatim original region):\n\n${original}`;
|
|
187
|
+
const files = cp.filesModified?.length ? cp.filesModified.join(", ") : "(no files captured)";
|
|
188
|
+
ctx.ui.notify(`[mega-compact] ♻ restored ${cp.checkpointId} — ${original.length} chars re-injected on next turn.\n` +
|
|
189
|
+
`[mega-compact] files: ${files}`);
|
|
190
|
+
runtime.dashboard.event("restore", { checkpointId: cp.checkpointId, chars: original.length });
|
|
159
191
|
}
|
|
160
|
-
|
|
161
|
-
ctx.ui.notify(`[mega-compact]
|
|
162
|
-
return;
|
|
192
|
+
catch (e) {
|
|
193
|
+
ctx.ui.notify(`[mega-compact] /mega-restore failed (checkpoint may be corrupt): ${String(e)}`);
|
|
163
194
|
}
|
|
164
|
-
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
165
|
-
// Re-inject verbatim via before_agent_start (PREVENT-PI-003) — never
|
|
166
|
-
// touches live messages, only prepends the restored region to systemPrompt.
|
|
167
|
-
runtime.pendingRecallBlock = `The following compacted context was RESTORED from checkpoint ${cp.checkpointId} (verbatim original region):\n\n${original}`;
|
|
168
|
-
const files = cp.filesModified?.length ? cp.filesModified.join(", ") : "(no files captured)";
|
|
169
|
-
ctx.ui.notify(`[mega-compact] ♻ restored ${cp.checkpointId} — ${original.length} chars re-injected on next turn.\n` +
|
|
170
|
-
`[mega-compact] files: ${files}`);
|
|
171
|
-
runtime.dashboard.event("restore", { checkpointId: cp.checkpointId, chars: original.length });
|
|
172
195
|
},
|
|
173
196
|
});
|
|
174
197
|
pi.registerCommand("mega-history", {
|
|
@@ -183,7 +206,7 @@ export function registerCommands(pi, runtime, config) {
|
|
|
183
206
|
}
|
|
184
207
|
const rows = all.map((c) => {
|
|
185
208
|
const when = c.timestamp ? new Date(c.timestamp).toISOString().slice(0, 16).replace("T", " ") : "—";
|
|
186
|
-
const files = c.filesModified?.length ? c.filesModified.map((f) => f.split("/").pop()).join(", ") : "—";
|
|
209
|
+
const files = c.filesModified?.length ? c.filesModified.map((f) => f.split("/").pop() ?? f).join(", ") : "—";
|
|
187
210
|
const orig = c.originalTokenEstimate ?? 0;
|
|
188
211
|
const stored = c.tokenEstimate ?? 0;
|
|
189
212
|
const saved = Math.max(0, orig - stored);
|
|
@@ -196,20 +219,25 @@ export function registerCommands(pi, runtime, config) {
|
|
|
196
219
|
pi.registerCommand("mega-view", {
|
|
197
220
|
description: "Show a checkpoint's verbatim original region. Usage: /mega-view <chkpt|recent>",
|
|
198
221
|
handler: async (args, ctx) => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
222
|
+
try {
|
|
223
|
+
runtime.bindRepo(ctx.cwd);
|
|
224
|
+
const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
|
|
225
|
+
const cp = findCheckpoint(runtime, sid, args.trim());
|
|
226
|
+
if (!cp) {
|
|
227
|
+
ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""}. Try /mega-history.`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (!cp.compressedOriginal) {
|
|
231
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} summary:\n${cp.summary.slice(0, 500)}${cp.summary.length > 500 ? "…" : ""}\n(no verbatim original stored)`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
235
|
+
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} — original region (${original.length} chars):\n` +
|
|
236
|
+
`${original.slice(0, 1500)}${original.length > 1500 ? "\n…(truncated)" : ""}`);
|
|
205
237
|
}
|
|
206
|
-
|
|
207
|
-
ctx.ui.notify(`[mega-compact]
|
|
208
|
-
return;
|
|
238
|
+
catch (e) {
|
|
239
|
+
ctx.ui.notify(`[mega-compact] /mega-view failed (checkpoint may be corrupt): ${String(e)}`);
|
|
209
240
|
}
|
|
210
|
-
const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
|
|
211
|
-
ctx.ui.notify(`[mega-compact] ${cp.checkpointId} — original region (${original.length} chars):\n` +
|
|
212
|
-
`${original.slice(0, 1500)}${original.length > 1500 ? "\n…(truncated)" : ""}`);
|
|
213
241
|
},
|
|
214
242
|
});
|
|
215
243
|
pi.registerCommand("mega-help", {
|