pi-mega-compact 0.8.15 → 0.8.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 (40) hide show
  1. package/README.md +51 -486
  2. package/dist/extensions/dashboard-client/src/hooks/useApi.js +51 -0
  3. package/dist/extensions/dashboard-client/src/hooks/useSSE.js +63 -0
  4. package/dist/extensions/dashboard-server/html.js +15 -2
  5. package/dist/extensions/mega-runtime/state.js +66 -0
  6. package/dist/extensions/mega-runtime/state.test.js +37 -0
  7. package/dist/extensions/mega-runtime/widget.js +6 -2
  8. package/dist/extensions/mega-runtime/widget.test.js +47 -0
  9. package/extensions/dashboard-client/dist/assets/{AchievementTiles-BH26e95w.js → AchievementTiles-BozP_h3c.js} +2 -2
  10. package/extensions/dashboard-client/dist/assets/{AchievementTiles-BH26e95w.js.map → AchievementTiles-BozP_h3c.js.map} +1 -1
  11. package/extensions/dashboard-client/dist/assets/{AchievementsTab-B94wvRV_.js → AchievementsTab-DKgqx1RQ.js} +2 -2
  12. package/extensions/dashboard-client/dist/assets/{AchievementsTab-B94wvRV_.js.map → AchievementsTab-DKgqx1RQ.js.map} +1 -1
  13. package/extensions/dashboard-client/dist/assets/{CacheTab-DPmw3NHR.js → CacheTab-CPvso4-0.js} +2 -2
  14. package/extensions/dashboard-client/dist/assets/{CacheTab-DPmw3NHR.js.map → CacheTab-CPvso4-0.js.map} +1 -1
  15. package/extensions/dashboard-client/dist/assets/ConfigTab-DXD7zbqy.js +2 -0
  16. package/extensions/dashboard-client/dist/assets/ConfigTab-DXD7zbqy.js.map +1 -0
  17. package/extensions/dashboard-client/dist/assets/{EventsTab-B5PicfFw.js → EventsTab-BGeuYvM3.js} +2 -2
  18. package/extensions/dashboard-client/dist/assets/{EventsTab-B5PicfFw.js.map → EventsTab-BGeuYvM3.js.map} +1 -1
  19. package/extensions/dashboard-client/dist/assets/{GameTab-CsVwp78a.js → GameTab-Qj19W1Y-.js} +2 -2
  20. package/extensions/dashboard-client/dist/assets/{GameTab-CsVwp78a.js.map → GameTab-Qj19W1Y-.js.map} +1 -1
  21. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cf72UewX.js → MetricsTab-DA27vA95.js} +2 -2
  22. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cf72UewX.js.map → MetricsTab-DA27vA95.js.map} +1 -1
  23. package/extensions/dashboard-client/dist/assets/{OverviewTab-Dh6aG3gy.js → OverviewTab-lVGR1Jl_.js} +2 -2
  24. package/extensions/dashboard-client/dist/assets/{OverviewTab-Dh6aG3gy.js.map → OverviewTab-lVGR1Jl_.js.map} +1 -1
  25. package/extensions/dashboard-client/dist/assets/{ReposTab-HXf2dorl.js → ReposTab-_HNR3qYj.js} +2 -2
  26. package/extensions/dashboard-client/dist/assets/{ReposTab-HXf2dorl.js.map → ReposTab-_HNR3qYj.js.map} +1 -1
  27. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-kUnoospE.js → TimeSavedCard-B7aPcBMs.js} +2 -2
  28. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-kUnoospE.js.map → TimeSavedCard-B7aPcBMs.js.map} +1 -1
  29. package/extensions/dashboard-client/dist/assets/{index-DMntLu-8.js → index-B2JJExE9.js} +3 -3
  30. package/extensions/dashboard-client/dist/assets/{index-DMntLu-8.js.map → index-B2JJExE9.js.map} +1 -1
  31. package/extensions/dashboard-client/dist/index.html +1 -1
  32. package/extensions/dashboard-client/src/tabs/ConfigTab.tsx +19 -2
  33. package/extensions/dashboard-server/html.ts +15 -2
  34. package/extensions/mega-runtime/state.test.ts +33 -0
  35. package/extensions/mega-runtime/state.ts +64 -0
  36. package/extensions/mega-runtime/widget.test.ts +48 -0
  37. package/extensions/mega-runtime/widget.ts +6 -2
  38. package/package.json +1 -1
  39. package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js +0 -2
  40. package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js.map +0 -1
package/README.md CHANGED
@@ -1,526 +1,91 @@
1
1
  # pi-mega-compact
2
2
 
3
- A **layered, local, vector-backed context compressor** for the
4
- [pi coding agent](https://github.com/earendil-works/pi). It compacts long
5
- sessions into a **local SQLite store** and offers **deduped inline recall** — all
6
- running **locally inside the extension**, with **no remote MCP server** and
7
- **zero network calls at runtime** (PREVENT-PI-004).
8
-
9
- > **Status - v0.8.14.** The React dashboard (8 tabs, responsive scaling from
10
- > 1280×720 to 4K) now ships in the npm tarball alongside the fallback html.ts.
11
- > Game Mode adds themes, levels, achievements, and leaderboards. See
12
- > [RELEASE_NOTES.md](RELEASE_NOTES.md) for the full changelog.
13
-
14
- ---
3
+ A local context compressor for the [pi coding agent](https://github.com/earendil-works/pi). Keeps long sessions running without overflowing the context window. All on your machine — no cloud, no API calls, no telemetry.
15
4
 
16
5
  ## Features
17
6
 
18
- - **Local & private** - everything stays on your disk. No telemetry, no API key, no MCP server, no cloud. The only network surface is an optional localhost dashboard you open yourself.
19
- - **Two-layer compaction** - a non-destructive live summary every LLM call, plus durable checkpoints that relieve context mid-run (not just at the end).
20
- - **Vector store + dedup** - each checkpoint is embedded and stored locally; an L0->L2 + RAPTOR cascade collapses duplicate work so storage and recall stay lean.
21
- - **Automatic recall** - the most relevant checkpoints are re-inlined on resume or branch switch; cross-repo memory-RAG augments a thin store with decisions from other repos.
22
- - **Game Mode** - optional progression layer with 6 themes, player levels (one per turn-doubling), 9 achievements (8 visible + 1 hidden easter-egg), and per-metric leaderboards. Toggle with `/mega-compact-settings`.
23
- - **Live dashboard** - React-based 8-tab dashboard (Overview, Repos, Events, Config, Metrics, Cache, Game, Achievements) with responsive scaling from laptop (1280×720) to ultrawide/4K. Active Repos tab shows every currently-open session side by side.
24
- - **Perf metrics** - Model latency (turn/provider p50/p95), throughput (TPS/cache hit %), process (RSS/heap/CPU), snapshot cost (DB recompute/disk write), and TUI lag proxy — all polled on a 2s interval while the dashboard is open.
25
- - **Database maintenance** - `/mega-db-*` commands plus best-effort auto-maintenance on session start.
26
-
27
- ## Table of contents
28
-
29
- - [Overview](#overview)
30
- - [How it works](#how-it-works)
31
- - [Installation](#installation)
32
- - [Usage](#usage)
33
- - [Configuration](#configuration)
34
- - [Dashboard](#dashboard)
35
- - [Architecture](#architecture)
36
- - [Development](#development)
37
- - [Testing & bug reports](#testing--bug-reports)
38
- - [Acknowledgements](#acknowledgements)
39
- - [License](#license)
40
-
41
- ## Overview
42
-
43
- pi's context window is finite. When a session gets long — especially a team run
44
- with sub-agents — pi-mega-compact keeps it going without overflowing:
45
-
46
- 1. **Watches one signal.** A single live `pressure = currentTokens / effectiveThreshold`
47
- drives everything — the tier label, how aggressively the live trim drops
48
- context, and how often durable memory is reviewed. `effectiveThreshold` is
49
- `tierPct × contextWindow` (a **% of the model's context window**), so the
50
- trim fires below pi's native ~80% auto-compaction for any model size. As
51
- context fills, the whole system reacts together; as it's relieved, it backs off.
52
- 2. **Compacts in two layers.** On every LLM call it returns a **live, compacted
53
- view** (the model sees a summary + recent anchor, non-destructively). And it
54
- persists a durable **checkpoint** — and, at each agent settle during a team
55
- run, fires pi's **native durable trim** so the on-disk transcript is actually
56
- truncated (context relieves mid-run, and resume reloads the trimmed transcript
57
- instead of a 150k window).
58
- 3. **Stores** each checkpoint in a **local vector database** (SQLite) with an
59
- embedding, so similar regions are found later and **duplicate work is never
60
- stored twice**.
61
- 4. **Recalls** the right context automatically — same-repo checkpoints on resume,
62
- plus **cross-repo memory-RAG**: decisions you saved in one repo are inlined as
63
- context when you start a session in another.
64
-
65
- Everything lives on **your disk**. No telemetry, no API, no MCP server, no cloud.
66
- The only optional network surface is a **user-triggered localhost dashboard** you
67
- open yourself.
68
-
69
- ### Why "mega"?
70
-
71
- The compaction pipeline is a **Trident** — three deterministic stages
72
- (supersede → collapse → cluster) that run over your conversation before anything
73
- is persisted. The checkpoint it produces is small (a summary + key decisions +
74
- next steps + files touched), so the same session that would otherwise overflow
75
- its window keeps going on a fraction of the tokens. On top of the Trident, a
76
- single pressure signal orchestrates the live trim, the durable trim, and memory
77
- review as one coherent system rather than four independent triggers.
78
-
79
- ---
80
-
81
- ## How it works
82
-
83
- ```
84
- Layer 5 Recall / Inline ONE local vector store → 3 entry points, 1 dedup engine
85
- Layer 4 Persist / Checkpoint compactSession() → embed + store in SQLite (chkpt_xxx)
86
- Layer 3 Cluster (vectorize) local vector index → semantic dedup + recall
87
- Layer 2 Collapse (summarize) summarizeMessages() heuristic + agent summary on /mega-compact
88
- Layer 1 Supersede (prune) drop obsolete file-reads / superseded turns (zero cost)
89
- ─────────────────────────────────────────────────────────────────────────
90
- Trigger context → token fast-gate → autoCompactCheck → live trim (per call)
91
- Durable agent_end (idle + over threshold) → ctx.compact() → session_before_compact
92
- supplies the summary; pi truncates the transcript (relieves context)
93
- Live context handler returns { messages:[summary, …recent] } — model sees a
94
- compacted window every LLM call; the on-disk transcript is untouched
95
- Marker insert compact-marker; dedupe so repeated triggers cost ~0 tokens
96
- ```
97
-
98
- **One store, three ways to read it back — one dedup engine:**
99
-
100
- | Entry point | Trigger | Behavior |
101
- | --- | --- | --- |
102
- | **Auto-inline** (Layer 5) | `session_start` / `session_tree` | Resume → `recallAndInline(source:"resume")` prepends the most relevant checkpoints, deduped against current context. |
103
- | **On-demand recall** | `/mega-recall [query]` | Semantic search the store, dedupe, and inline the top-K. |
104
- | **Dedup sentinel** | every compact | A lightweight `mega-compact-marker` entry lets auto-inline and recall skip re-injecting / re-vectorizing already-present regions. |
105
-
106
- **The dedup cascade** (shared across all entry points) collapses redundant work
107
- so storage and recall stay lean:
108
-
109
- - **L0 — exact:** SHA-256 content hash + region hash + summary hash. Identical (or
110
- whitespace/casing-normalized) regions collapse to one row.
111
- - **L1 — near-dup:** MinHash signatures + LSH bucketing + trigram verification
112
- catch one-word rewordings that L0 misses.
113
- - **L2 — semantic:** cosine over the embedding collapses paraphrases; MMR
114
- diversifies retrieval so a cluster of near-hits yields distinct results.
115
- - **RAPTOR — pre-compression tree** (shadow mode by default): a hierarchical
116
- summary tree over checkpoints, built + logged but not served until promoted.
117
-
118
- Every tier is gated by its own feature flag (see [Configuration](#configuration)).
119
- A tier can be put in `MARK_ONLY` (record the decision, don't collapse) as a safe
120
- partial-rollout or auto-degrade state.
121
-
122
- ### Embedding (two modes, both local)
123
-
124
- The default embedder is **`TrigramEmbedder`** — a deterministic hashed trigram
125
- bag (512-dim, L2-normalized), **zero dependencies, instant, fully offline**. It
126
- is heuristic-strength, which is the right bar for "inline the right checkpoint,"
127
- not production RAG.
7
+ - **Auto-compaction** watches context pressure and compacts in the background before you hit the ceiling
8
+ - **Two-layer compaction** live trim on every LLM call (model sees a smaller window) + durable checkpoints persisted to SQLite
9
+ - **Semantic dedup** — three-stage pipeline (exact hash MinHash/LSH cosine) collapses redundant work so nothing is stored twice
10
+ - **Cross-repo recall** decisions saved in one repo surface when you start a session in another
11
+ - **Durable memory** — auto-reviews conversation every 10 turns, writes decisions/facts/preferences to SQLite, injects them as RAG context on recall
12
+ - **Fully local** SQLite + trigram embedder by default. Bring your own localhost embedder (ONNX, Ollama, TEI) for better semantic matching
13
+ - **Team-run aware** fires native durable trim at agent settle during sub-agent runs, so context relieves mid-run not just at the end
14
+ - **Dashboard** optional localhost-only live dashboard with token gauge, store stats, and event stream
128
15
 
129
- **Optional: bring-your-own (BYO) localhost embedder.** Set
130
- `MEGACOMPACT_EMBEDDING_URL` to a **localhost/127.0.0.1** endpoint you run
131
- yourself (local ONNX/TEI/llamafile/Ollama-embeddings). The extension talks to it
132
- from `src/httpEmbedder.ts` (loopback-only — a remote host is rejected at config
133
- time, preserving PREVENT-PI-004). Compacted content never leaves the machine and
134
- no model ships with the extension. See `src/httpEmbedder.ts` for the
135
- OpenAI-style contract and the `MEGACOMPACT_EMBEDDING_KEY` / `MEGACOMPACT_EMBEDDING_HEADERS`
136
- / `MEGACOMPACT_EMBEDDING_DIM` options.
137
-
138
- > **Note on MiniLM:** a `MEGACOMPACT_MINILM` flag exists in `src/config/dedup.ts`
139
- > but defaults to **off**, and the MiniLM (all-MiniLM-L6-v2) ONNX embedder was
140
- > prototyped then deliberately **not shipped** (async-vs-sync conflict with the
141
- > synchronous VectorStore, second native dep, no free semantic win without a
142
- > network call). The `Embedder` interface remains the seam — inject a local
143
- > embedder (e.g. via your own `MEGACOMPACT_EMBEDDING_URL`) instead.
144
-
145
- ---
146
-
147
- ## Installation
148
-
149
- > **Full step-by-step guide** (pi + OpenClaw + every command + troubleshooting):
150
- > [`docs/INSTALL_AND_USAGE.md`](docs/INSTALL_AND_USAGE.md).
151
-
152
- ### Requirements
153
-
154
- - **Node >= 22.13** (the synchronous `node:sqlite` backend requires it; see
155
- `engines.node`). No native module is compiled — the store is a Node built-in.
156
- - No network call and no API key are needed at runtime (PREVENT-PI-004).
157
- - A pi coding agent install with package support (`pi install` / `pi update
158
- --extensions`). npm-installed packages are auto-discovered via the package's
159
- `pi` manifest entry; local checkouts load from `~/.pi/agent/extensions/`.
160
-
161
- ### Install from npm (recommended)
162
-
163
- pi installs extensions as **packages**. `pi install npm:<pkg>` writes an
164
- `npm:` source into your pi config's `packages` array; pi then auto-discovers the
165
- extension from the package's own `"pi": { "extensions": [...] }` manifest entry
166
- — **no manual `settings.json` edit is needed**.
16
+ ## Install
167
17
 
168
18
  ```bash
169
- pi install npm:pi-mega-compact # first time: adds to packages + installs
170
- pi update --extensions # thereafter: pulls the latest published version
19
+ pi install npm:pi-mega-compact
171
20
  ```
172
21
 
173
- `pi update --extensions` refreshes every `npm:` entry in `packages` (including on
174
- other devices that share this config). The package ships both the TypeScript
175
- source (which pi loads directly) and the compiled `dist/`, so nothing else needs
176
- building.
177
-
178
- > **Tip — keep the spec unpinned.** Use `npm:pi-mega-compact`, not
179
- > `npm:pi-mega-compact@0.5.1`. Version-pinned specs are *skipped* by
180
- > `pi update --extensions`, so a pin would freeze you on that release. The
181
- > installed version is always visible in the toolbar widget (`⚡ <tier> vX.Y.Z`)
182
- > and via `/mega-status`.
183
-
184
- > **From a git checkout (development only).** To hack on the extension, clone and
185
- > build locally, then symlink it into pi's extensions dir — but this bypasses the
186
- > package manager, so it is NOT updated by `pi update --extensions`. Convert to the
187
- > npm package (above) before shipping. The bundled `./install.sh` helper does the
188
- > symlink + config edit (needs `jq`).
189
- >
190
- > ```bash
191
- > git clone https://github.com/TheArchitectit/pi-mega-compact.git \
192
- > ~/.pi/agent/extensions/pi-mega-compact
193
- > cd ~/.pi/agent/extensions/pi-mega-compact
194
- > npm install && npm run build
195
- > ```
196
-
197
- > **No tarballs — ever.** Distribution and updates go through `npm publish` +
198
- > `pi update --extensions` **only**. Never build or rely on a `.tgz` (`npm pack`):
199
- > a tarball bypasses pi's package manager and does not propagate to other devices.
200
- > To validate a real install, bump the version, `npm publish`, then
201
- > `pi update --extensions` on the device. (`.gitignore` rejects `*.tgz` so one can't
202
- > be committed by accident.)
203
- >
204
- > **Releasing (authoritative pipeline):** every release MUST go through
205
- > `./scripts/deploy.sh <new-version>`. It enforces a clean tree, the full gate
206
- > (`build` + `test` + `lint` + `regression_check` + `guardrails-scan`), builds the
207
- > React dashboard, and — critically — verifies `extensions/dashboard-client/dist/index.html`
208
- > is present AND listed by `npm pack --dry-run` **before** `npm publish`. This is
209
- > the gate that was missing when v0.8.5 shipped without the dashboard bundle. The
210
- > script then bumps the version, commits, publishes via npm only, tags, pushes,
211
- > and prints device-side verification steps. Never publish by hand.
212
-
213
- ### Storage
214
-
215
- pi-mega-compact uses a dual local backend — **zero network, no native build step**:
216
-
217
- - **`node:sqlite`** (`DatabaseSync`, Node ≥22.13 built-in) — the synchronous source of truth for checkpoints, session state, and the dedup index. No dependency, no install script, survives pi's `install-scripts` block.
218
- - **PGlite + `@electric-sql/pglite-pgvector`** (WASM Postgres + HNSW `vector_cosine_ops`) — an optional, best-effort async vector index for **cross-repo recall** at `~/.pi/mega-compact-vector`. It holds both checkpoint embeddings and durable-memory embeddings, so decisions saved in one repo are findable from another. The sync store stays authoritative; the index degrades to the sync per-session scan on any failure.
219
-
220
- Kill-switch: `MEGACOMPACT_PGLITE_DISABLED=1` fully disables the PGlite index (falls back to sync scan). Requires Node ≥22.13 (`engines.node`).
221
-
222
- ### Cross-repo recall
223
-
224
- On resume, recall augments from other repos' checkpoints when this repo's store is thin; `/mega-recall --cross-repo` searches all repos via the HNSW index. Cross-repo hits use a stricter cosine floor (`MEGACOMPACT_CROSSREPO_COSINE`, default 0.90) and are labeled with their source repo. A machine-wide injected-set (`~/.mega-compact-index/index.sqlite`) prevents re-injecting the same foreign checkpoint.
225
-
226
- ### Memory
227
-
228
- pi-mega-compact auto-reviews the conversation every 10 turns (the cadence shortens as pressure climbs) and writes durable `decision`/`fact`/`preference` memories to SQLite (local, hallucination-guarded). Relevant memories are injected as RAG context on recall (capped, deduped). **Cross-repo memory-RAG (S24):** every memory write is mirrored into the PGlite/HNSW index, so when same-repo recall is thin the system augments with the nearest memories from *other* repos (stricter `MEGACOMPACT_CROSSREPO_COSINE` floor, deduped against what's already in view). Manual: `/mega-memory save|list|forget` (or `/m`).
229
-
230
- ### Uninstall
231
-
232
- ```bash
233
- pi uninstall npm:pi-mega-compact # removes from settings.packages + the npm tree
234
- # or, to keep the config entry but drop the package:
235
- npm uninstall pi-mega-compact
236
- ```
22
+ That's it. `pi update --extensions` pulls updates going forward.
237
23
 
238
- If you symlinked it into pi's extensions dir (dev only), also remove that link:
24
+ <details>
25
+ <summary>From source (development)</summary>
239
26
 
240
27
  ```bash
241
- rm -f ~/.pi/agent/extensions/pi-mega-compact
28
+ git clone https://github.com/TheArchitectit/pi-mega-compact.git \
29
+ ~/.pi/agent/extensions/pi-mega-compact
30
+ cd ~/.pi/agent/extensions/pi-mega-compact
31
+ npm install && npm run build
242
32
  ```
243
33
 
244
- ---
34
+ The bundled `./install.sh` helper does the symlink + config edit (needs `jq`).
35
+ </details>
245
36
 
246
37
  ## Usage
247
38
 
248
- Once installed and registered, pi-mega-compact runs **automatically** you don't
249
- have to drive it. Past the context threshold it compacts in the background and
250
- drops a checkpoint; on resume it re-inlines the relevant ones silently.
251
-
252
- The commands (slash commands inside pi):
253
-
254
- ### Commands
255
-
256
- | Command | Description |
257
- | --- | --- |
258
- | `/mega-compact [summary...]` | Manually compact the current session. A summary arg is used verbatim; otherwise the COLLAPSE heuristics build one. Persists a `chkpt_xxx`. |
259
- | `/mega-compact off` | Disable auto-compaction for this session. |
260
- | `/mega-compact-settings [on\|off\|theme [id\|next]\|tui [full\|minimal]\|achievements]` | Toggle game mode, pick a theme, switch TUI display mode, list unlocked achievements. (Alias: `/mega-game`.) |
261
- | `/mega-status` | Show config + current context usage + store stats (checkpoint count, dedup rate, tokens saved) + the **installed version**. |
262
- | `/mega-recall [query]` | Semantic-search the local store, dedupe against the current window, and inline the top-K relevant checkpoints. No query → uses your latest message. `--cross-repo` searches all repos. |
263
- | `/mega-memory save <text>` / `save <category> <text>` / `list` / `search <query>` / `forget <text>` / `consolidate` | Manage durable memories (decisions, facts, preferences) written by auto-review and recalled as RAG context. Also `/m` shortform. |
264
- | `/mega-restore <chkpt\|recent>` | Re-inject a checkpoint's verbatim original region into context. |
265
- | `/mega-history` | List this session's checkpoints (id, date, files, tokens). |
266
- | `/mega-view <chkpt\|recent>` | Show a checkpoint's verbatim original region. |
267
- | `/mega-help` | Explain the toolbar widget terms (live tier, gate, dedup, tokens saved). |
268
- | `/mega-compat-check` | Detect extension conflicts (duplicate commands / overlapping handlers) across installed pi extensions. |
269
- | `/mega-db-stats` | Show mega-compact SQLite DB stats: table row counts, disk footprint (db + WAL + SHM), page count, freelist %, WAL frames. Read-only; safe any time. |
270
- | `/mega-db-prune [days]` | DELETE `raw_transcript` + `checkpoint_epochs` rows older than N days (default 30) + orphan `dedup_mirror` rows. Reports deleted counts + reclaimed bytes. |
271
- | `/mega-db-vacuum` | `VACUUM` the DB (rebuild pages, reclaim freelist). Heavy: briefly doubles disk usage. |
272
- | `/mega-db-check` | `PRAGMA integrity_check` + `wal_checkpoint(TRUNCATE)`. Fold the WAL into the main file and verify DB health. Use after a crash. |
273
- | `/mega-db-reconcile` | Fix `dedup_mirror.ref_count` drift vs actual `raw_transcript` refs, delete orphan dedup rows, backfill missing `content_ref`. Run after `/mega-db-prune` or a crash. |
274
- | `/mega-dashboard [open]` | Start the **localhost-only** live dashboard and open it in a browser (token gauge, store stats, live event stream, per-repo + All-repos/Summary views, cross-repo drift). |
275
- | `/mega-dashboard-status` | Report dashboard server status (port / url / live). |
276
- | `/mega-dashboard-stop` | Stop the dashboard server. |
277
-
278
- ### The tier system
279
-
280
- The **tier** you see in the toolbar and dashboard is a *live pressure band* (`low` → `medium` → `high` → `ultra` → `mega`) that climbs automatically as your context window fills and falls back as it's relieved — it is driven by `currentTokens / effectiveThreshold`, not a manual setting. The base compaction *threshold* is set by `MEGACOMPACT_TIER` at startup as a **% of the model context window** (`low` 50% · `medium` 60% · `high` 70% · `ultra` 70% · `mega` 75%; default `low`) — the fire point is `tierPct × contextWindow`, so it always lands below pi's native ~80% auto-compaction (any model size). The old static token amounts (50k/100k/200k/1M/10M) are now only the boot fallback used before the first context event reports a window. `/mega-tier` was removed in v0.7.6. Higher pressure also deepens the live trim and reviews durable memory more often — the whole system reacts as one.
281
-
282
- ### Game Mode
283
-
284
- Optional progression layer (toggle with `/mega-compact-settings on`):
285
-
286
- - **6 themes** — transparent (default), neon, retro, ocean, forest, cyber. CSS-variable skins for the TUI widget and dashboard.
287
- - **Player levels** — one level per turn-doubling (`turnLevel(n) = floor(log2(n+1))+1`). Level-up fires a one-cycle ANSI blink on the TUI + a CSS pulse on the dashboard.
288
- - **Achievements** — 9 total (8 visible + 1 hidden easter-egg). Unlock conditions: First Compact, Compact Streak (5 in one session), Turn Veteran (25 turns), Level 5, Dedupe Master (100 chunks), Repo Explorer (3 repos), Night Owl (00:00–05:00), Flawless (exactly 100% cache), and Opie's Wild Ride (hidden: push cache past 100%).
289
- - **Leaderboards** — per-metric (Cache %, Dedupe collapsed, Turns LVL, MEGA CACHE trophies) with repos badge. Stored in SQLite `game_scores`.
290
- - **MEGA CACHE easter-egg** — when the dedup hit rate exceeds 100% (real ratio > 1), a transient "oopsie" toast fires (TUI + dashboard) and the hidden Opie achievement unlocks.
291
-
292
- ### Live stats widget
293
-
294
- Above the pi editor the extension shows a compact widget:
295
-
296
- ```
297
- ⚡ high·low v0.8.14 │ 142k/200k tokens (71%) │ 3 chkpts │ 🤖 2 agents │ turn 5
298
- ◐ armed │ dedup: 92% │ saved: 45k tok │ LVL 4
299
- ```
300
-
301
- - **Version** — the installed npm version (read from `package.json` at runtime),
302
- so the widget always reflects what `pi update --extensions` last pulled. If
303
- this looks stale after an update, restart the dashboard server / pi session.
304
- - **Tier** — active compaction tier (low/medium/high/ultra/mega)
305
- - **Token usage** — current / max context window and %
306
- - **Checkpoints** — persisted checkpoints for the session
307
- - **Trigger state** — ○ idle, ◐ armed, ● ready
308
- - **Dedup hit rate** — % of checkpoints collapsed as duplicates
309
- - **Active agents / turn** — sub-agent count and conversation turn (when > 0)
310
- - **LVL** — player level (one per turn-doubling; game mode only)
311
-
312
- > **DB housekeeping** — `/mega-db-stats` / `prune` / `vacuum` / `check` / `reconcile`
313
- > give you manual control over the SQLite store. In addition, a best-effort
314
- > **auto-maintenance** pass runs on `session_start`: it prunes rows older than
315
- > 30d, checkpoints the WAL if it's over 10 MB, and VACUUMs if the DB is over
316
- > 100 MB AND the freelist is >20% of pages. It never blocks session start and
317
- > logs a one-line summary to the diagnostic log. (v0.7.6+)
318
-
319
- ---
320
-
321
- ## Configuration (env-backed)
322
-
323
- All defaults are in `src/config/dedup.ts` (single source of truth). Set env vars
324
- before starting pi.
325
-
326
- ### Core settings
327
-
328
- | Variable | Default | Meaning |
329
- | --- | --- | --- |
330
- | `MEGACOMPACT_FAST_GATE_PCT` | `70` | Context-usage % that arms the auto-trigger. Defaults to the tier's % of window (`tierPct*100`): low 50 · med 60 · high 70 · ultra 70 · mega 75. Override raises the arming floor. |
331
- | `MEGACOMPACT_TIER` | `low` | Named trigger preset — sets the compaction threshold as a **% of the model context window**: `low`(50%) `medium`(60%) `high`(70%) `ultra`(70%) `mega`(75%). Fire point = `tierPct × contextWindow`, so it always fires below pi's native ~80% auto-compaction (any model size). The old static token amounts (50k/100k/200k/1M/10M) are now only the **boot fallback** used before the first context event reports a window. Default `low`. |
332
- | `MEGACOMPACT_THRESHOLD_TOKENS` | *(tier default)* | Explicit **absolute** token budget (the `custom` tier). Overrides `MEGACOMPACT_TIER` when set and is **never percent-scaled** — use this to pin an exact token fire point regardless of model window. |
333
- | `MEGACOMPACT_ANCHOR_USER_MESSAGES` | `3` | Never drop the most recent N user messages (anchor floor). |
334
- | `MEGACOMPACT_PRESERVE_RECENT` | `4` | Preserve the most recent N messages verbatim. |
335
- | `MEGACOMPACT_AUTO` | `true` | Enable the auto-trigger. |
336
- | `MEGACOMPACT_AUTO_INLINE` | `true` | Auto-inline on resume / branch. |
337
- | `MEGACOMPACT_AUTO_INLINE_K` | `3` | Top-K checkpoints to auto-inline. |
338
- | `MEGACOMPACT_DEDUP_SIM` | `0.90` | Cosine threshold to collapse near-dupes. |
339
- | `MEGACOMPACT_STATE_DIR` | *(none — per-repo default)* | Override the store location. By default state is per-repo at `<repo>/.pi/mega-compact/`; this env var forces a single explicit dir (used as the fallback for non-git cwds). |
340
-
341
- ### Dedup pipeline flags
39
+ Once installed, it runs automatically. Past the context threshold it compacts in the background. On resume, it re-inlines relevant checkpoints silently.
342
40
 
343
- These gate the L0/L1/L2/RAPTOR dedup tiers. Defaults reproduce the all-active
344
- behavior. `MARK_ONLY_*` tiers run + record their decision but never
345
- collapse (safe partial-rollout / auto-degrade state).
41
+ Key commands:
346
42
 
347
- | Variable | Default | Meaning |
348
- | --- | --- | --- |
349
- | `MEGACOMPACT_L0_ENABLED` | `true` | L0 exact content-hash dedup. |
350
- | `MEGACOMPACT_L1_ENABLED` | `true` | L1 MinHash/LSH near-dup verification. |
351
- | `MEGACOMPACT_L2_ENABLED` | `true` | L2 semantic cosine dedup + MMR retrieval diversity. |
352
- | `MEGACOMPACT_RAPTOR_ENABLED` | `false` | RAPTOR pre-compression tree (**shadow mode by default** — builds + logs, does not serve retrieval). |
353
- | `MEGACOMPACT_MARK_ONLY_L0` | `false` | L0: record, don't collapse. |
354
- | `MEGACOMPACT_MARK_ONLY_L1` | `false` | L1: record, don't collapse. |
355
- | `MEGACOMPACT_MARK_ONLY_L2` | `false` | L2: record, don't collapse. |
356
- | `MEGACOMPACT_MINILM` | `false` | MiniLM embedder flag — **off; not shipped** (see Embedding). BYO via `MEGACOMPACT_EMBEDDING_URL`. |
357
- | `MEGACOMPACT_EMBEDDING_URL` | *(unset)* | BYO localhost embedder endpoint (loopback-only; enables `HttpEmbedder`). |
358
- | `MEGACOMPACT_L2_THRESHOLD` | `0.85` | L2 cosine firing point (trigram-honest; set higher for semantic backends). |
359
- | `MEGACOMPACT_L1_JACCARD` | `0.8` | L1 MinHash/LSH near-dup Jaccard threshold. |
360
- | `MEGACOMPACT_MMR_LAMBDA` | `0.5` | MMR retrieval-diversity weight (λ·relevance − (1−λ)·maxSim). |
361
- | `MEGACOMPACT_SEMDEDUP_COSINE` | `0.95` | Offline SemDeDup pair threshold → `dedup_status='removed'`. |
362
- | `MEGACOMPACT_FP_RATE_L0` | `0.01` | L0 false-positive alert threshold (auto → MARK_ONLY). |
363
- | `MEGACOMPACT_FP_RATE_L1L2` | `0.05` | L1/L2 false-positive alert threshold (auto → MARK_ONLY). |
364
- | `MEGACOMPACT_ALERT_WINDOW_MS` | `600000` | FP-rate rolling window (10 min). |
365
- | `MEGACOMPACT_P95_BUDGET_MS` | `100` | Per-tier p95 latency budget; canary auto-disables on breach. |
43
+ - `/mega-compact` manually compact the current session
44
+ - `/mega-status` show context usage, store stats, version
45
+ - `/mega-recall [query]` semantic search the store, `--cross-repo` for all repos
46
+ - `/mega-memory save|list|search|forget` manage durable memories
47
+ - `/mega-dashboard` start the localhost dashboard
366
48
 
367
- See `docs/DEDUP_RUNBOOK.md` for incident response (SEV tiers, first-15-min
368
- checklist, MARK_ONLY degrade) and `docs/RETENTION_POLICY.md` for TTL / soft-delete
369
- / VACUUM.
49
+ Full command reference: [`docs/COMMANDS.md`](docs/COMMANDS.md)
370
50
 
371
- ### Continuity & memory
51
+ ## Configuration
372
52
 
373
- | Variable | Default | Meaning |
374
- | --- | --- | --- |
375
- | `MEGACOMPACT_LEGACY_DURABLE_TRIM` | `false` | Restore the legacy auto-trigger (`ctx.compact()` stops the agent). One-release rollback; default uses live context-event trim + pi native auto-compaction (compact-and-continue). |
376
- | `MEGACOMPACT_CROSSREPO_ENABLED` | `true` | Cross-repo recall on resume + `/mega-recall --cross-repo` (HNSW index over every repo). |
377
- | `MEGACOMPACT_CROSSREPO_COSINE` | `0.90` | Stricter cosine floor for cross-repo hits (vs `0.85` same-repo). |
378
- | `MEGACOMPACT_MEMORY_AUTO_REVIEW` | `true` | Auto-review the conversation every `MEGACOMPACT_MEMORY_REVIEW_INTERVAL` turns → durable memories. |
379
- | `MEGACOMPACT_MEMORY_REVIEW_INTERVAL` | `10` | Turns between auto-review cycles. |
380
- | `MEGACOMPACT_PGLITE_DISABLED` | *(unset — index on)* | Kill-switch for the PGlite/HNSW cross-repo index; set `1`/`true` to disable (falls back to sync per-session scan). |
53
+ Set env vars before starting pi. Defaults are in `src/config/dedup.ts`.
381
54
 
382
- ## Dashboard
55
+ | Variable | Default | Description |
56
+ |---|---|---|
57
+ | `MEGACOMPACT_TIER` | `low` | Threshold as % of context window (low=50%, medium=60%, high=70%) |
58
+ | `MEGACOMPACT_AUTO` | `true` | Enable auto-compaction |
59
+ | `MEGACOMPACT_DEDUP_SIM` | `0.90` | Cosine threshold for near-dup collapse |
60
+ | `MEGACOMPACT_CROSSREPO_ENABLED` | `true` | Cross-repo recall on resume |
61
+ | `MEGACOMPACT_EMBEDDING_URL` | _(unset)_ | BYO localhost embedder endpoint |
383
62
 
384
- The localhost-only dashboard (started with `/mega-dashboard`) is a single-page
385
- app served from a detached child process on `127.0.0.1` (random port in
386
- 9320–9329). Every API is read-only — the server never writes the index or your
387
- store. It reads the machine-wide `repo_registry`
388
- (`~/.mega-compact-index/index.sqlite`) plus the current repo's own `node:sqlite`
389
- store.
390
-
391
- ### Tabs (React dashboard)
392
-
393
- The dashboard (started with `/mega-dashboard`) now ships as a React SPA with 8 tabs, responsive scaling from 1280×720 to 4K:
394
-
395
- - **Overview** — context-window gauge (green/yellow/red), trigger status (armed/ready/idle), Vector Store (9 fields + compression bar), Repo (all sessions, 7 fields), Data Safety shield (regions retained, dedup %), Configuration (tier/preset/threshold), Model & Cost Savings ($, rates), Crew/Agents (active agents/turn/status), "What these numbers mean" legend.
396
- - **Repos** — All Repositories table, Active Repos live table, Savings by Model table, per-repo detail modal, summary tiles.
397
- - **Events** — live SSE stream with category filter (all/compact/recall/config/crew/game).
398
- - **Config** — game mode toggle, theme picker (6 themes), TUI display mode (full/minimal), read-only config display.
399
- - **Metrics** — model latency (turn/provider p50/p95), throughput (TPS/cache hit %), process (RSS/heap/CPU), snapshot cost (DB recompute/disk write), TUI lag proxy. Per-model cache status table.
400
- - **Cache** — Cache Hits (session/total), Tokens Saved (session/total), Compactions (session/total), Time Saved (session/total).
401
- - **Game** — MEGA CACHE banner, Opie unlock tile, leaderboards (Cache %, Dedupe collapsed, Turns LVL, MEGA CACHE trophies), repos badge, achievements sub-section.
402
- - **Achievements** — achievement tiles grid with unlock states, toast area.
403
-
404
- The older html.ts fallback (1071 lines, all data) is retained for environments without the React build.
405
-
406
- ### Active Repos tab
407
-
408
- The dashboard has a dedicated **Active Repos** tab that lists every server /
409
- session seen within the **last 30 minutes**, each with its live tier,
410
- context %, and session state. It is backed by `GET /api/servers`, which walks
411
- the machine-wide `repo_registry`, reads each repo's per-process
412
- `dashboard.json` snapshot, and returns one row per currently-open session —
413
- so 1–6 sessions running at once are visible together in a single table instead
414
- of only the single current-repo view. Each row shows that repo's live
415
- cache-hit / compaction / time-saved totals (see below).
416
-
417
- The older **All repos** view and `GET /api/summary` still surface an
418
- `activeRepos` count, and `GET /api/repos?active=Nh` filters to repos seen
419
- within the last *N* hours (e.g. `?active=24h`, hour-granular) for the
420
- longer-window cross-repo table.
421
-
422
- ### Metrics (DB-backed, durable)
423
-
424
- The dashboard's cumulative **Cache hits**, **Compactions**, and **Estimated
425
- time saved** cards are backed by **SQLite `meta` counters**
426
- (`compact_count`, `recall_injected`, `cache_hit_tokens_saved`, plus the
427
- existing `tokens_saved` / `deduped`), not the per-process `dashboard.json`
428
- snapshot. Because they live in the repo's `node:sqlite` store, the totals are
429
- **durable across session restarts** and travel with the repo's state dir —
430
- `dashboard.json` is now just the live per-process view that feeds the Active
431
- Repos rows. The cards show:
432
-
433
- - **Cache hits** = dedup collapses (`deduped`) + recall re-injections
434
- (`recall_injected`) — as **current session** and **repo-wide total**.
435
- - **Compactions** = current session (`checkpointCount`) + repo-wide total
436
- (`compact_count` from `meta`).
437
- - **Estimated time saved** = compact time saved + cache-hit time saved, derived
438
- from tokens ÷ ~2k tok/s and labeled `est.`, as current session + total.
439
-
440
- ### Localhost API
441
-
442
- `GET /api/snapshot` (current-repo live state),
443
- `/api/servers` (**Active Repos** — sessions active in the last 30 min, with
444
- tier / context % / state / live cache-hit & compaction totals),
445
- `/api/index` (all repos), `/api/repos` (with `?active=Nh` filter), `/api/summary`
446
- (header tiles + `activeRepos`), `/api/drift` (cross-repo drift: stale /
447
- compaction-lag / model-churn — read-only), `/api/events` (SSE live event stream),
448
- and `/api/version`.
449
-
450
- ### Data safety
451
-
452
- Every compacted region is kept verbatim (compressed);
453
- the Data Safety card shows regions retained, compressed-originals bytes, dedup
454
- duplicates, and permanently-deleted bytes (**always 0**). Nothing is permanently
455
- deleted — any region is restorable.
456
-
457
- ---
63
+ Full config reference: [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md)
458
64
 
459
65
  ## Architecture
460
66
 
461
67
  ```
462
- extensions/mega-compact.ts pi extension entry; wires src/ into pi lifecycle
463
- extensions/mega-trim.ts live context-event trim (compact-and-continue, no abort)
464
- extensions/mega-conflict-cmds.ts extension-conflict detector (/mega-compat-check)
465
- extensions/dashboard-server.ts localhost dashboard (HTML + snapshot/version/drift APIs)
466
- src/adapt.ts the single pi↔engine message adapter (index-aligned)
467
- src/engine.ts Layer 4: compactSession() Trident pipeline + recall()
468
- src/vectorStore.ts Layer 3: local vector DB (add/search/dedupe + near-dup)
469
- src/embedder.ts default TrigramEmbedder (deterministic, 512-dim)
470
- src/httpEmbedder.ts BYO localhost embedder seam (MEGACOMPACT_EMBEDDING_URL)
471
- src/store/sqlite.ts the "one store" — node:sqlite context_chunks + session_state (FTS5 trigram)
472
- src/store/vectorIndex.ts async PGlite/HNSW cross-repo vector index (redundant, best-effort)
473
- src/store/migrate.ts JSON → SQLite migration (legacy .checkpoints.json.gz retained)
474
- src/store/backfill.ts resumable backfill orchestrator (L0/L1/L2/RAPTOR)
475
- src/memory.ts durable memories (decision/fact/preference) + auto-review
476
- src/memoryOps.ts memory apply/consolidate ops
477
- src/memoryRecall.ts memory recall + auto-inline (RAG context)
478
- src/driftDetection.ts cross-repo drift report (stale/idle/compaction-lag/model-churn)
479
- src/monitoring.ts local events.log + dashboard.json metrics + FP alerts
480
- src/canary.ts sequential L0→L1→L2→RAPTOR rollout, auto-disable on p95 breach
481
- src/config/dedup.ts single source of truth for ALL dedup tier flags + thresholds
482
- src/store.ts state dir + JSON DR helpers + compression re-exports
483
- src/compact.ts Layer 2: summarize / merge / autoCompactCheck
484
- src/supersede.ts Layer 1: obsolete file-read pruning
485
- src/boundary.ts drop-boundary guards (anchor floor + tool-pair)
486
- src/tokens.ts deterministic token estimator
487
- src/types.ts engine-internal types
68
+ extensions/ Pi entry points (mega-compact, mega-trim, dashboard)
69
+ src/engine.ts Trident pipeline (supersede collapse → cluster)
70
+ src/vectorStore.ts Local vector DB (add/search/dedupe)
71
+ src/compact.ts Summarize / merge / auto-compact
72
+ src/memory.ts Durable memories + auto-review
73
+ src/store/sqlite.ts node:sqlite store (Node ≥22.13)
74
+ src/store/vectorIndex.ts PGlite/HNSW cross-repo index
488
75
  ```
489
76
 
490
- The `src/` directory is **pi-agnostic** and fully unit-tested (`node --test`).
491
- The extension entry adapts between the engine and pi's runtime types.
492
-
493
- ---
77
+ Detailed architecture: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
494
78
 
495
79
  ## Development
496
80
 
497
81
  ```bash
498
- npm run build # tsc
499
- npm test # build + node --test on dist/**/*.test.js (407 tests)
500
- npm run lint # tsc --noEmit + guardrails-scan
501
- npm run guardrails # regression_check + guardrails-scan
82
+ npm run build # TypeScript compile
83
+ npm test # Build + 353 tests
84
+ npm run lint # Type check + guardrails scan
502
85
  ```
503
86
 
504
- The agent-guardrails suite (Four Laws, scope, secrets, regression) gates every
505
- change.
506
-
507
- ---
508
-
509
- ## Testing & bug reports
510
-
511
- Full QA instructions — environment setup, the manual test checklist, what to
512
- include in a bug report, and known limitations — live in
513
- [`TESTER_GUIDE.md`](TESTER_GUIDE.md). Open issues at
514
- [github.com/TheArchitectit/pi-mega-compact/issues](https://github.com/TheArchitectit/pi-mega-compact/issues).
515
-
516
- ---
517
-
518
- ## Acknowledgements
519
-
520
- Algorithmic reference (reimplemented in TypeScript, not vendored): memory-mcp
521
- (`MemoryCompactor` / `compact.py`), claw-code (`trident.rs` / `compact.rs`), and
522
- neuralwatt-mcr (pi-extension mechanics). Attribution as design sources only.
87
+ Testing guide: [`TESTER_GUIDE.md`](TESTER_GUIDE.md)
523
88
 
524
89
  ## License
525
90
 
526
- [BSD-2-Clause](./LICENSE)
91
+ BSD-2-Clause
@@ -0,0 +1,51 @@
1
+ /**
2
+ * dashboard-client/src/hooks/useApi.ts — Generic data fetching hook.
3
+ *
4
+ * Provides typed fetch with retry, stale detection, and error handling.
5
+ * SPRINT-B1: basic fetch. SPRINT-D1: retry + stale.
6
+ */
7
+ import { useState, useEffect, useCallback, useRef } from 'react';
8
+ // SPRINT-D1-REMAINING: integrate retryWithBackoff from utils/retry.ts.
9
+ // SPRINT-D1-REMAINING: integrate staleness detection from utils/staleness.ts.
10
+ // SPRINT-T1-REMAINING: add Authorization header when auth token present.
11
+ export function useApi(fetchFn, options = {}) {
12
+ const { pollInterval = 0, maxRetries = 0 } = options;
13
+ const [data, setData] = useState(null);
14
+ const [error, setError] = useState(null);
15
+ const [loading, setLoading] = useState(true);
16
+ const [lastFetchedAt, setLastFetchedAt] = useState(null);
17
+ const mountedRef = useRef(true);
18
+ const doFetch = useCallback(async () => {
19
+ setLoading(true);
20
+ setError(null);
21
+ try {
22
+ const result = await fetchFn();
23
+ if (mountedRef.current) {
24
+ setData(result);
25
+ setLastFetchedAt(Date.now());
26
+ }
27
+ }
28
+ catch (err) {
29
+ if (mountedRef.current) {
30
+ setError(err instanceof Error ? err : new Error(String(err)));
31
+ }
32
+ }
33
+ finally {
34
+ if (mountedRef.current) {
35
+ setLoading(false);
36
+ }
37
+ }
38
+ }, [fetchFn]);
39
+ useEffect(() => {
40
+ mountedRef.current = true;
41
+ doFetch();
42
+ return () => { mountedRef.current = false; };
43
+ }, [doFetch]);
44
+ useEffect(() => {
45
+ if (pollInterval <= 0)
46
+ return;
47
+ const timer = setInterval(doFetch, pollInterval);
48
+ return () => clearInterval(timer);
49
+ }, [doFetch, pollInterval]);
50
+ return { data, error, loading, refetch: doFetch, lastFetchedAt };
51
+ }