pi-mega-compact 0.8.14 → 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.
- package/README.md +51 -463
- package/dist/extensions/dashboard-client/src/hooks/useApi.js +51 -0
- package/dist/extensions/dashboard-client/src/hooks/useSSE.js +63 -0
- package/dist/extensions/dashboard-server/html.js +15 -2
- package/dist/extensions/mega-cache-replay.test.js +4 -2
- package/dist/extensions/mega-compact-s38.test.js +317 -0
- package/dist/extensions/mega-compact.js +14 -0
- package/dist/extensions/mega-compact.test.js +37 -8
- package/dist/extensions/mega-config.js +5 -0
- package/dist/extensions/mega-events/agent-handlers.js +184 -4
- package/dist/extensions/mega-events/context-handler.js +35 -2
- package/dist/extensions/mega-events/error-classifier.js +118 -0
- package/dist/extensions/mega-events.js +1 -0
- package/dist/extensions/mega-runtime/state.js +82 -0
- package/dist/extensions/mega-runtime/state.test.js +37 -0
- package/dist/extensions/mega-runtime/widget.js +6 -2
- package/dist/extensions/mega-runtime/widget.test.js +47 -0
- package/dist/extensions/mega-teamrun.test.js +14 -1
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-BH26e95w.js → AchievementTiles-BozP_h3c.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-BH26e95w.js.map → AchievementTiles-BozP_h3c.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-B94wvRV_.js → AchievementsTab-DKgqx1RQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-B94wvRV_.js.map → AchievementsTab-DKgqx1RQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-DPmw3NHR.js → CacheTab-CPvso4-0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-DPmw3NHR.js.map → CacheTab-CPvso4-0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ConfigTab-DXD7zbqy.js +2 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-DXD7zbqy.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{EventsTab-B5PicfFw.js → EventsTab-BGeuYvM3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-B5PicfFw.js.map → EventsTab-BGeuYvM3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-CsVwp78a.js → GameTab-Qj19W1Y-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-CsVwp78a.js.map → GameTab-Qj19W1Y-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cf72UewX.js → MetricsTab-DA27vA95.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cf72UewX.js.map → MetricsTab-DA27vA95.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Dh6aG3gy.js → OverviewTab-lVGR1Jl_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Dh6aG3gy.js.map → OverviewTab-lVGR1Jl_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-HXf2dorl.js → ReposTab-_HNR3qYj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-HXf2dorl.js.map → ReposTab-_HNR3qYj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-kUnoospE.js → TimeSavedCard-B7aPcBMs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-kUnoospE.js.map → TimeSavedCard-B7aPcBMs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-DMntLu-8.js → index-B2JJExE9.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-DMntLu-8.js.map → index-B2JJExE9.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/styles/base.css +2 -1
- package/extensions/dashboard-client/src/tabs/ConfigTab.tsx +19 -2
- package/extensions/dashboard-server/html.ts +15 -2
- package/extensions/mega-cache-replay.test.ts +3 -3
- package/extensions/mega-compact-s38.test.ts +330 -0
- package/extensions/mega-compact.test.ts +41 -13
- package/extensions/mega-compact.ts +14 -0
- package/extensions/mega-config.ts +24 -0
- package/extensions/mega-dashboard.ts +7 -0
- package/extensions/mega-events/agent-handlers.ts +179 -5
- package/extensions/mega-events/context-handler.ts +31 -2
- package/extensions/mega-events/error-classifier.ts +109 -0
- package/extensions/mega-events.ts +1 -0
- package/extensions/mega-runtime/helpers.ts +5 -0
- package/extensions/mega-runtime/state.test.ts +33 -0
- package/extensions/mega-runtime/state.ts +81 -1
- package/extensions/mega-runtime/widget.test.ts +48 -0
- package/extensions/mega-runtime/widget.ts +6 -2
- package/extensions/mega-teamrun.test.ts +13 -1
- package/package.json +4 -1
- package/dist/extensions/dashboard-server/helpers.js +0 -37
- package/dist/extensions/dashboard-server/html/all-repos-tab.js +0 -26
- package/dist/extensions/dashboard-server/html/body-open.js +0 -23
- package/dist/extensions/dashboard-server/html/current-repo-tab.js +0 -130
- package/dist/extensions/dashboard-server/html/head-open.js +0 -16
- package/dist/extensions/dashboard-server/html/high-score-tab.js +0 -25
- package/dist/extensions/dashboard-server/html/repo-detail-modal.js +0 -26
- package/dist/extensions/dashboard-server/html/script.js +0 -259
- package/dist/extensions/dashboard-server/html/styles.js +0 -103
- package/dist/extensions/dashboard-server/html/summary-tab.js +0 -19
- package/dist/extensions/dashboard-server/html-template.js +0 -41
- package/dist/src/store/sqlite/connection.js +0 -35
- package/dist/src/store/sqlite/index-store.js +0 -167
- package/dist/src/store/sqlite/memory.js +0 -54
- package/dist/src/store/sqlite/minhash-lsh.js +0 -47
- package/dist/src/store/sqlite/sessions.js +0 -39
- package/dist/src/store/sqlite/transaction.js +0 -19
- package/dist/src/vectorStore/add.js +0 -260
- package/dist/src/vectorStore/dedup.js +0 -52
- package/dist/src/vectorStore/index.js +0 -10
- package/dist/src/vectorStore/queries.js +0 -83
- package/dist/src/vectorStore/search.js +0 -95
- package/dist/src/vectorStore/session.js +0 -19
- package/dist/src/vectorStore/store.js +0 -105
- package/dist/src/vectorStore/types.js +0 -6
- package/dist/src/vectorStore/utils.js +0 -23
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js +0 -2
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,503 +1,91 @@
|
|
|
1
1
|
# pi-mega-compact
|
|
2
2
|
|
|
3
|
-
A
|
|
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.7.9.** Storage uses the built-in `node:sqlite` backend
|
|
10
|
-
> (`DatabaseSync`, Node >=22.13): zero native build step, fully local, and zero
|
|
11
|
-
> network at runtime. See [RELEASE_NOTES.md](RELEASE_NOTES.md) for the full
|
|
12
|
-
> 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
|
-
- **
|
|
19
|
-
- **Two-layer compaction**
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- [Overview](#overview)
|
|
28
|
-
- [How it works](#how-it-works)
|
|
29
|
-
- [Installation](#installation)
|
|
30
|
-
- [Usage](#usage)
|
|
31
|
-
- [Configuration](#configuration)
|
|
32
|
-
- [Dashboard](#dashboard)
|
|
33
|
-
- [Architecture](#architecture)
|
|
34
|
-
- [Development](#development)
|
|
35
|
-
- [Testing & bug reports](#testing--bug-reports)
|
|
36
|
-
- [Acknowledgements](#acknowledgements)
|
|
37
|
-
- [License](#license)
|
|
38
|
-
|
|
39
|
-
## Overview
|
|
40
|
-
|
|
41
|
-
pi's context window is finite. When a session gets long — especially a team run
|
|
42
|
-
with sub-agents — pi-mega-compact keeps it going without overflowing:
|
|
43
|
-
|
|
44
|
-
1. **Watches one signal.** A single live `pressure = currentTokens / effectiveThreshold`
|
|
45
|
-
drives everything — the tier label, how aggressively the live trim drops
|
|
46
|
-
context, and how often durable memory is reviewed. `effectiveThreshold` is
|
|
47
|
-
`tierPct × contextWindow` (a **% of the model's context window**), so the
|
|
48
|
-
trim fires below pi's native ~80% auto-compaction for any model size. As
|
|
49
|
-
context fills, the whole system reacts together; as it's relieved, it backs off.
|
|
50
|
-
2. **Compacts in two layers.** On every LLM call it returns a **live, compacted
|
|
51
|
-
view** (the model sees a summary + recent anchor, non-destructively). And it
|
|
52
|
-
persists a durable **checkpoint** — and, at each agent settle during a team
|
|
53
|
-
run, fires pi's **native durable trim** so the on-disk transcript is actually
|
|
54
|
-
truncated (context relieves mid-run, and resume reloads the trimmed transcript
|
|
55
|
-
instead of a 150k window).
|
|
56
|
-
3. **Stores** each checkpoint in a **local vector database** (SQLite) with an
|
|
57
|
-
embedding, so similar regions are found later and **duplicate work is never
|
|
58
|
-
stored twice**.
|
|
59
|
-
4. **Recalls** the right context automatically — same-repo checkpoints on resume,
|
|
60
|
-
plus **cross-repo memory-RAG**: decisions you saved in one repo are inlined as
|
|
61
|
-
context when you start a session in another.
|
|
62
|
-
|
|
63
|
-
Everything lives on **your disk**. No telemetry, no API, no MCP server, no cloud.
|
|
64
|
-
The only optional network surface is a **user-triggered localhost dashboard** you
|
|
65
|
-
open yourself.
|
|
66
|
-
|
|
67
|
-
### Why "mega"?
|
|
68
|
-
|
|
69
|
-
The compaction pipeline is a **Trident** — three deterministic stages
|
|
70
|
-
(supersede → collapse → cluster) that run over your conversation before anything
|
|
71
|
-
is persisted. The checkpoint it produces is small (a summary + key decisions +
|
|
72
|
-
next steps + files touched), so the same session that would otherwise overflow
|
|
73
|
-
its window keeps going on a fraction of the tokens. On top of the Trident, a
|
|
74
|
-
single pressure signal orchestrates the live trim, the durable trim, and memory
|
|
75
|
-
review as one coherent system rather than four independent triggers.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## How it works
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
Layer 5 Recall / Inline ONE local vector store → 3 entry points, 1 dedup engine
|
|
83
|
-
Layer 4 Persist / Checkpoint compactSession() → embed + store in SQLite (chkpt_xxx)
|
|
84
|
-
Layer 3 Cluster (vectorize) local vector index → semantic dedup + recall
|
|
85
|
-
Layer 2 Collapse (summarize) summarizeMessages() heuristic + agent summary on /mega-compact
|
|
86
|
-
Layer 1 Supersede (prune) drop obsolete file-reads / superseded turns (zero cost)
|
|
87
|
-
─────────────────────────────────────────────────────────────────────────
|
|
88
|
-
Trigger context → token fast-gate → autoCompactCheck → live trim (per call)
|
|
89
|
-
Durable agent_end (idle + over threshold) → ctx.compact() → session_before_compact
|
|
90
|
-
supplies the summary; pi truncates the transcript (relieves context)
|
|
91
|
-
Live context handler returns { messages:[summary, …recent] } — model sees a
|
|
92
|
-
compacted window every LLM call; the on-disk transcript is untouched
|
|
93
|
-
Marker insert compact-marker; dedupe so repeated triggers cost ~0 tokens
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**One store, three ways to read it back — one dedup engine:**
|
|
97
|
-
|
|
98
|
-
| Entry point | Trigger | Behavior |
|
|
99
|
-
| --- | --- | --- |
|
|
100
|
-
| **Auto-inline** (Layer 5) | `session_start` / `session_tree` | Resume → `recallAndInline(source:"resume")` prepends the most relevant checkpoints, deduped against current context. |
|
|
101
|
-
| **On-demand recall** | `/mega-recall [query]` | Semantic search the store, dedupe, and inline the top-K. |
|
|
102
|
-
| **Dedup sentinel** | every compact | A lightweight `mega-compact-marker` entry lets auto-inline and recall skip re-injecting / re-vectorizing already-present regions. |
|
|
103
|
-
|
|
104
|
-
**The dedup cascade** (shared across all entry points) collapses redundant work
|
|
105
|
-
so storage and recall stay lean:
|
|
106
|
-
|
|
107
|
-
- **L0 — exact:** SHA-256 content hash + region hash + summary hash. Identical (or
|
|
108
|
-
whitespace/casing-normalized) regions collapse to one row.
|
|
109
|
-
- **L1 — near-dup:** MinHash signatures + LSH bucketing + trigram verification
|
|
110
|
-
catch one-word rewordings that L0 misses.
|
|
111
|
-
- **L2 — semantic:** cosine over the embedding collapses paraphrases; MMR
|
|
112
|
-
diversifies retrieval so a cluster of near-hits yields distinct results.
|
|
113
|
-
- **RAPTOR — pre-compression tree** (shadow mode by default): a hierarchical
|
|
114
|
-
summary tree over checkpoints, built + logged but not served until promoted.
|
|
115
|
-
|
|
116
|
-
Every tier is gated by its own feature flag (see [Configuration](#configuration)).
|
|
117
|
-
A tier can be put in `MARK_ONLY` (record the decision, don't collapse) as a safe
|
|
118
|
-
partial-rollout or auto-degrade state.
|
|
119
|
-
|
|
120
|
-
### Embedding (two modes, both local)
|
|
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
|
|
121
15
|
|
|
122
|
-
|
|
123
|
-
bag (512-dim, L2-normalized), **zero dependencies, instant, fully offline**. It
|
|
124
|
-
is heuristic-strength, which is the right bar for "inline the right checkpoint,"
|
|
125
|
-
not production RAG.
|
|
126
|
-
|
|
127
|
-
**Optional: bring-your-own (BYO) localhost embedder.** Set
|
|
128
|
-
`MEGACOMPACT_EMBEDDING_URL` to a **localhost/127.0.0.1** endpoint you run
|
|
129
|
-
yourself (local ONNX/TEI/llamafile/Ollama-embeddings). The extension talks to it
|
|
130
|
-
from `src/httpEmbedder.ts` (loopback-only — a remote host is rejected at config
|
|
131
|
-
time, preserving PREVENT-PI-004). Compacted content never leaves the machine and
|
|
132
|
-
no model ships with the extension. See `src/httpEmbedder.ts` for the
|
|
133
|
-
OpenAI-style contract and the `MEGACOMPACT_EMBEDDING_KEY` / `MEGACOMPACT_EMBEDDING_HEADERS`
|
|
134
|
-
/ `MEGACOMPACT_EMBEDDING_DIM` options.
|
|
135
|
-
|
|
136
|
-
> **Note on MiniLM:** a `MEGACOMPACT_MINILM` flag exists in `src/config/dedup.ts`
|
|
137
|
-
> but defaults to **off**, and the MiniLM (all-MiniLM-L6-v2) ONNX embedder was
|
|
138
|
-
> prototyped then deliberately **not shipped** (async-vs-sync conflict with the
|
|
139
|
-
> synchronous VectorStore, second native dep, no free semantic win without a
|
|
140
|
-
> network call). The `Embedder` interface remains the seam — inject a local
|
|
141
|
-
> embedder (e.g. via your own `MEGACOMPACT_EMBEDDING_URL`) instead.
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Installation
|
|
146
|
-
|
|
147
|
-
> **Full step-by-step guide** (pi + OpenClaw + every command + troubleshooting):
|
|
148
|
-
> [`docs/INSTALL_AND_USAGE.md`](docs/INSTALL_AND_USAGE.md).
|
|
149
|
-
|
|
150
|
-
### Requirements
|
|
151
|
-
|
|
152
|
-
- **Node >= 22.13** (the synchronous `node:sqlite` backend requires it; see
|
|
153
|
-
`engines.node`). No native module is compiled — the store is a Node built-in.
|
|
154
|
-
- No network call and no API key are needed at runtime (PREVENT-PI-004).
|
|
155
|
-
- A pi coding agent install with package support (`pi install` / `pi update
|
|
156
|
-
--extensions`). npm-installed packages are auto-discovered via the package's
|
|
157
|
-
`pi` manifest entry; local checkouts load from `~/.pi/agent/extensions/`.
|
|
158
|
-
|
|
159
|
-
### Install from npm (recommended)
|
|
160
|
-
|
|
161
|
-
pi installs extensions as **packages**. `pi install npm:<pkg>` writes an
|
|
162
|
-
`npm:` source into your pi config's `packages` array; pi then auto-discovers the
|
|
163
|
-
extension from the package's own `"pi": { "extensions": [...] }` manifest entry
|
|
164
|
-
— **no manual `settings.json` edit is needed**.
|
|
16
|
+
## Install
|
|
165
17
|
|
|
166
18
|
```bash
|
|
167
|
-
pi install npm:pi-mega-compact
|
|
168
|
-
pi update --extensions # thereafter: pulls the latest published version
|
|
19
|
+
pi install npm:pi-mega-compact
|
|
169
20
|
```
|
|
170
21
|
|
|
171
|
-
`pi update --extensions`
|
|
172
|
-
other devices that share this config). The package ships both the TypeScript
|
|
173
|
-
source (which pi loads directly) and the compiled `dist/`, so nothing else needs
|
|
174
|
-
building.
|
|
175
|
-
|
|
176
|
-
> **Tip — keep the spec unpinned.** Use `npm:pi-mega-compact`, not
|
|
177
|
-
> `npm:pi-mega-compact@0.5.1`. Version-pinned specs are *skipped* by
|
|
178
|
-
> `pi update --extensions`, so a pin would freeze you on that release. The
|
|
179
|
-
> installed version is always visible in the toolbar widget (`⚡ <tier> vX.Y.Z`)
|
|
180
|
-
> and via `/mega-status`.
|
|
181
|
-
|
|
182
|
-
> **From a git checkout (development only).** To hack on the extension, clone and
|
|
183
|
-
> build locally, then symlink it into pi's extensions dir — but this bypasses the
|
|
184
|
-
> package manager, so it is NOT updated by `pi update --extensions`. Convert to the
|
|
185
|
-
> npm package (above) before shipping. The bundled `./install.sh` helper does the
|
|
186
|
-
> symlink + config edit (needs `jq`).
|
|
187
|
-
>
|
|
188
|
-
> ```bash
|
|
189
|
-
> git clone https://github.com/TheArchitectit/pi-mega-compact.git \
|
|
190
|
-
> ~/.pi/agent/extensions/pi-mega-compact
|
|
191
|
-
> cd ~/.pi/agent/extensions/pi-mega-compact
|
|
192
|
-
> npm install && npm run build
|
|
193
|
-
> ```
|
|
22
|
+
That's it. `pi update --extensions` pulls updates going forward.
|
|
194
23
|
|
|
195
|
-
>
|
|
196
|
-
>
|
|
197
|
-
> a tarball bypasses pi's package manager and does not propagate to other devices.
|
|
198
|
-
> To validate a real install, bump the version, `npm publish`, then
|
|
199
|
-
> `pi update --extensions` on the device. (`.gitignore` rejects `*.tgz` so one can't
|
|
200
|
-
> be committed by accident.)
|
|
201
|
-
|
|
202
|
-
### Storage
|
|
203
|
-
|
|
204
|
-
pi-mega-compact uses a dual local backend — **zero network, no native build step**:
|
|
205
|
-
|
|
206
|
-
- **`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.
|
|
207
|
-
- **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.
|
|
208
|
-
|
|
209
|
-
Kill-switch: `MEGACOMPACT_PGLITE_DISABLED=1` fully disables the PGlite index (falls back to sync scan). Requires Node ≥22.13 (`engines.node`).
|
|
210
|
-
|
|
211
|
-
### Cross-repo recall
|
|
212
|
-
|
|
213
|
-
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.
|
|
214
|
-
|
|
215
|
-
### Memory
|
|
216
|
-
|
|
217
|
-
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`).
|
|
218
|
-
|
|
219
|
-
### Uninstall
|
|
24
|
+
<details>
|
|
25
|
+
<summary>From source (development)</summary>
|
|
220
26
|
|
|
221
27
|
```bash
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
|
225
32
|
```
|
|
226
33
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
rm -f ~/.pi/agent/extensions/pi-mega-compact
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
34
|
+
The bundled `./install.sh` helper does the symlink + config edit (needs `jq`).
|
|
35
|
+
</details>
|
|
234
36
|
|
|
235
37
|
## Usage
|
|
236
38
|
|
|
237
|
-
Once installed
|
|
238
|
-
have to drive it. Past the context threshold it compacts in the background and
|
|
239
|
-
drops a checkpoint; on resume it re-inlines the relevant ones silently.
|
|
240
|
-
|
|
241
|
-
The commands (slash commands inside pi):
|
|
242
|
-
|
|
243
|
-
### Commands
|
|
244
|
-
|
|
245
|
-
| Command | Description |
|
|
246
|
-
| --- | --- |
|
|
247
|
-
| `/mega-compact [summary...]` | Manually compact the current session. A summary arg is used verbatim; otherwise the COLLAPSE heuristics build one. Persists a `chkpt_xxx`. |
|
|
248
|
-
| `/mega-compact off` | Disable auto-compaction for this session. |
|
|
249
|
-
| `/mega-status` | Show config + current context usage + store stats (checkpoint count, dedup rate, tokens saved) + the **installed version**. |
|
|
250
|
-
| `/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. |
|
|
251
|
-
| `/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. |
|
|
252
|
-
| `/mega-restore <chkpt\|recent>` | Re-inject a checkpoint's verbatim original region into context. |
|
|
253
|
-
| `/mega-history` | List this session's checkpoints (id, date, files, tokens). |
|
|
254
|
-
| `/mega-view <chkpt\|recent>` | Show a checkpoint's verbatim original region. |
|
|
255
|
-
| `/mega-help` | Explain the toolbar widget terms (live tier, gate, dedup, tokens saved). |
|
|
256
|
-
| `/mega-compat-check` | Detect extension conflicts (duplicate commands / overlapping handlers) across installed pi extensions. |
|
|
257
|
-
| `/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. |
|
|
258
|
-
| `/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. |
|
|
259
|
-
| `/mega-db-vacuum` | `VACUUM` the DB (rebuild pages, reclaim freelist). Heavy: briefly doubles disk usage. |
|
|
260
|
-
| `/mega-db-check` | `PRAGMA integrity_check` + `wal_checkpoint(TRUNCATE)`. Fold the WAL into the main file and verify DB health. Use after a crash. |
|
|
261
|
-
| `/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. |
|
|
262
|
-
| `/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). |
|
|
263
|
-
| `/mega-dashboard-status` | Report dashboard server status (port / url / live). |
|
|
264
|
-
| `/mega-dashboard-stop` | Stop the dashboard server. |
|
|
265
|
-
|
|
266
|
-
### The tier system
|
|
267
|
-
|
|
268
|
-
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.
|
|
269
|
-
|
|
270
|
-
### Live stats widget
|
|
271
|
-
|
|
272
|
-
Above the pi editor the extension shows a compact widget:
|
|
273
|
-
|
|
274
|
-
```
|
|
275
|
-
⚡ high·low v0.7.9 │ 142k/200k tokens (71%) │ 3 chkpts │ 🤖 2 agents │ turn 5
|
|
276
|
-
◐ armed │ dedup: 92% │ saved: 45k tok
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
- **Version** — the installed npm version (read from `package.json` at runtime),
|
|
280
|
-
so the widget always reflects what `pi update --extensions` last pulled. If
|
|
281
|
-
this looks stale after an update, restart the dashboard server / pi session.
|
|
282
|
-
- **Tier** — active compaction tier (low/medium/high/ultra/mega)
|
|
283
|
-
- **Token usage** — current / max context window and %
|
|
284
|
-
- **Checkpoints** — persisted checkpoints for the session
|
|
285
|
-
- **Trigger state** — ○ idle, ◐ armed, ● ready
|
|
286
|
-
- **Dedup hit rate** — % of checkpoints collapsed as duplicates
|
|
287
|
-
- **Active agents / turn** — sub-agent count and conversation turn (when > 0)
|
|
288
|
-
|
|
289
|
-
> **DB housekeeping** — `/mega-db-stats` / `prune` / `vacuum` / `check` / `reconcile`
|
|
290
|
-
> give you manual control over the SQLite store. In addition, a best-effort
|
|
291
|
-
> **auto-maintenance** pass runs on `session_start`: it prunes rows older than
|
|
292
|
-
> 30d, checkpoints the WAL if it's over 10 MB, and VACUUMs if the DB is over
|
|
293
|
-
> 100 MB AND the freelist is >20% of pages. It never blocks session start and
|
|
294
|
-
> logs a one-line summary to the diagnostic log. (v0.7.6+)
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## Configuration (env-backed)
|
|
299
|
-
|
|
300
|
-
All defaults are in `src/config/dedup.ts` (single source of truth). Set env vars
|
|
301
|
-
before starting pi.
|
|
302
|
-
|
|
303
|
-
### Core settings
|
|
304
|
-
|
|
305
|
-
| Variable | Default | Meaning |
|
|
306
|
-
| --- | --- | --- |
|
|
307
|
-
| `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. |
|
|
308
|
-
| `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`. |
|
|
309
|
-
| `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. |
|
|
310
|
-
| `MEGACOMPACT_ANCHOR_USER_MESSAGES` | `3` | Never drop the most recent N user messages (anchor floor). |
|
|
311
|
-
| `MEGACOMPACT_PRESERVE_RECENT` | `4` | Preserve the most recent N messages verbatim. |
|
|
312
|
-
| `MEGACOMPACT_AUTO` | `true` | Enable the auto-trigger. |
|
|
313
|
-
| `MEGACOMPACT_AUTO_INLINE` | `true` | Auto-inline on resume / branch. |
|
|
314
|
-
| `MEGACOMPACT_AUTO_INLINE_K` | `3` | Top-K checkpoints to auto-inline. |
|
|
315
|
-
| `MEGACOMPACT_DEDUP_SIM` | `0.90` | Cosine threshold to collapse near-dupes. |
|
|
316
|
-
| `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). |
|
|
317
|
-
|
|
318
|
-
### 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.
|
|
319
40
|
|
|
320
|
-
|
|
321
|
-
behavior. `MARK_ONLY_*` tiers run + record their decision but never
|
|
322
|
-
collapse (safe partial-rollout / auto-degrade state).
|
|
41
|
+
Key commands:
|
|
323
42
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
| `MEGACOMPACT_RAPTOR_ENABLED` | `false` | RAPTOR pre-compression tree (**shadow mode by default** — builds + logs, does not serve retrieval). |
|
|
330
|
-
| `MEGACOMPACT_MARK_ONLY_L0` | `false` | L0: record, don't collapse. |
|
|
331
|
-
| `MEGACOMPACT_MARK_ONLY_L1` | `false` | L1: record, don't collapse. |
|
|
332
|
-
| `MEGACOMPACT_MARK_ONLY_L2` | `false` | L2: record, don't collapse. |
|
|
333
|
-
| `MEGACOMPACT_MINILM` | `false` | MiniLM embedder flag — **off; not shipped** (see Embedding). BYO via `MEGACOMPACT_EMBEDDING_URL`. |
|
|
334
|
-
| `MEGACOMPACT_EMBEDDING_URL` | *(unset)* | BYO localhost embedder endpoint (loopback-only; enables `HttpEmbedder`). |
|
|
335
|
-
| `MEGACOMPACT_L2_THRESHOLD` | `0.85` | L2 cosine firing point (trigram-honest; set higher for semantic backends). |
|
|
336
|
-
| `MEGACOMPACT_L1_JACCARD` | `0.8` | L1 MinHash/LSH near-dup Jaccard threshold. |
|
|
337
|
-
| `MEGACOMPACT_MMR_LAMBDA` | `0.5` | MMR retrieval-diversity weight (λ·relevance − (1−λ)·maxSim). |
|
|
338
|
-
| `MEGACOMPACT_SEMDEDUP_COSINE` | `0.95` | Offline SemDeDup pair threshold → `dedup_status='removed'`. |
|
|
339
|
-
| `MEGACOMPACT_FP_RATE_L0` | `0.01` | L0 false-positive alert threshold (auto → MARK_ONLY). |
|
|
340
|
-
| `MEGACOMPACT_FP_RATE_L1L2` | `0.05` | L1/L2 false-positive alert threshold (auto → MARK_ONLY). |
|
|
341
|
-
| `MEGACOMPACT_ALERT_WINDOW_MS` | `600000` | FP-rate rolling window (10 min). |
|
|
342
|
-
| `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
|
|
343
48
|
|
|
344
|
-
|
|
345
|
-
checklist, MARK_ONLY degrade) and `docs/RETENTION_POLICY.md` for TTL / soft-delete
|
|
346
|
-
/ VACUUM.
|
|
49
|
+
Full command reference: [`docs/COMMANDS.md`](docs/COMMANDS.md)
|
|
347
50
|
|
|
348
|
-
|
|
51
|
+
## Configuration
|
|
349
52
|
|
|
350
|
-
|
|
351
|
-
| --- | --- | --- |
|
|
352
|
-
| `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). |
|
|
353
|
-
| `MEGACOMPACT_CROSSREPO_ENABLED` | `true` | Cross-repo recall on resume + `/mega-recall --cross-repo` (HNSW index over every repo). |
|
|
354
|
-
| `MEGACOMPACT_CROSSREPO_COSINE` | `0.90` | Stricter cosine floor for cross-repo hits (vs `0.85` same-repo). |
|
|
355
|
-
| `MEGACOMPACT_MEMORY_AUTO_REVIEW` | `true` | Auto-review the conversation every `MEGACOMPACT_MEMORY_REVIEW_INTERVAL` turns → durable memories. |
|
|
356
|
-
| `MEGACOMPACT_MEMORY_REVIEW_INTERVAL` | `10` | Turns between auto-review cycles. |
|
|
357
|
-
| `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`.
|
|
358
54
|
|
|
359
|
-
|
|
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 |
|
|
360
62
|
|
|
361
|
-
|
|
362
|
-
app served from a detached child process on `127.0.0.1` (random port in
|
|
363
|
-
9320–9329). Every API is read-only — the server never writes the index or your
|
|
364
|
-
store. It reads the machine-wide `repo_registry`
|
|
365
|
-
(`~/.mega-compact-index/index.sqlite`) plus the current repo's own `node:sqlite`
|
|
366
|
-
store.
|
|
367
|
-
|
|
368
|
-
### Tabs
|
|
369
|
-
|
|
370
|
-
- **Current repo** — the live single-session view: context-window gauge, trigger
|
|
371
|
-
status, the Vector Store (checkpoints / dropped / kept / freed / injected /
|
|
372
|
-
dedup / collapsed), the repo-wide aggregate, the Data Safety card, the live
|
|
373
|
-
Model & Cost Savings card, and crew/agent activity.
|
|
374
|
-
- **All repos** — a machine-wide table aggregated from `repo_registry`
|
|
375
|
-
(`GET /api/index`): one row per repo with checkpoints, tokens saved,
|
|
376
|
-
compressed-originals, last-compacted, and active model. Each row opens a
|
|
377
|
-
per-repo detail modal. Currently-open sessions are badged **active** (see
|
|
378
|
-
below).
|
|
379
|
-
- **Summary** — machine-wide header tiles plus a **savings-by-model** table
|
|
380
|
-
(tokens in/out/freed, context window, $ saved) grouped by the model you were
|
|
381
|
-
running.
|
|
382
|
-
|
|
383
|
-
### Active Repos tab
|
|
384
|
-
|
|
385
|
-
The dashboard has a dedicated **Active Repos** tab that lists every server /
|
|
386
|
-
session seen within the **last 30 minutes**, each with its live tier,
|
|
387
|
-
context %, and session state. It is backed by `GET /api/servers`, which walks
|
|
388
|
-
the machine-wide `repo_registry`, reads each repo's per-process
|
|
389
|
-
`dashboard.json` snapshot, and returns one row per currently-open session —
|
|
390
|
-
so 1–6 sessions running at once are visible together in a single table instead
|
|
391
|
-
of only the single current-repo view. Each row shows that repo's live
|
|
392
|
-
cache-hit / compaction / time-saved totals (see below).
|
|
393
|
-
|
|
394
|
-
The older **All repos** view and `GET /api/summary` still surface an
|
|
395
|
-
`activeRepos` count, and `GET /api/repos?active=Nh` filters to repos seen
|
|
396
|
-
within the last *N* hours (e.g. `?active=24h`, hour-granular) for the
|
|
397
|
-
longer-window cross-repo table.
|
|
398
|
-
|
|
399
|
-
### Metrics (DB-backed, durable)
|
|
400
|
-
|
|
401
|
-
The dashboard's cumulative **Cache hits**, **Compactions**, and **Estimated
|
|
402
|
-
time saved** cards are backed by **SQLite `meta` counters**
|
|
403
|
-
(`compact_count`, `recall_injected`, `cache_hit_tokens_saved`, plus the
|
|
404
|
-
existing `tokens_saved` / `deduped`), not the per-process `dashboard.json`
|
|
405
|
-
snapshot. Because they live in the repo's `node:sqlite` store, the totals are
|
|
406
|
-
**durable across session restarts** and travel with the repo's state dir —
|
|
407
|
-
`dashboard.json` is now just the live per-process view that feeds the Active
|
|
408
|
-
Repos rows. The cards show:
|
|
409
|
-
|
|
410
|
-
- **Cache hits** = dedup collapses (`deduped`) + recall re-injections
|
|
411
|
-
(`recall_injected`) — as **current session** and **repo-wide total**.
|
|
412
|
-
- **Compactions** = current session (`checkpointCount`) + repo-wide total
|
|
413
|
-
(`compact_count` from `meta`).
|
|
414
|
-
- **Estimated time saved** = compact time saved + cache-hit time saved, derived
|
|
415
|
-
from tokens ÷ ~2k tok/s and labeled `est.`, as current session + total.
|
|
416
|
-
|
|
417
|
-
### Localhost API
|
|
418
|
-
|
|
419
|
-
`GET /api/snapshot` (current-repo live state),
|
|
420
|
-
`/api/servers` (**Active Repos** — sessions active in the last 30 min, with
|
|
421
|
-
tier / context % / state / live cache-hit & compaction totals),
|
|
422
|
-
`/api/index` (all repos), `/api/repos` (with `?active=Nh` filter), `/api/summary`
|
|
423
|
-
(header tiles + `activeRepos`), `/api/drift` (cross-repo drift: stale /
|
|
424
|
-
compaction-lag / model-churn — read-only), `/api/events` (SSE live event stream),
|
|
425
|
-
and `/api/version`.
|
|
426
|
-
|
|
427
|
-
### Data safety
|
|
428
|
-
|
|
429
|
-
Every compacted region is kept verbatim (compressed);
|
|
430
|
-
the Data Safety card shows regions retained, compressed-originals bytes, dedup
|
|
431
|
-
duplicates, and permanently-deleted bytes (**always 0**). Nothing is permanently
|
|
432
|
-
deleted — any region is restorable.
|
|
433
|
-
|
|
434
|
-
---
|
|
63
|
+
Full config reference: [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md)
|
|
435
64
|
|
|
436
65
|
## Architecture
|
|
437
66
|
|
|
438
67
|
```
|
|
439
|
-
extensions/
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
src/
|
|
444
|
-
src/
|
|
445
|
-
src/
|
|
446
|
-
src/embedder.ts default TrigramEmbedder (deterministic, 512-dim)
|
|
447
|
-
src/httpEmbedder.ts BYO localhost embedder seam (MEGACOMPACT_EMBEDDING_URL)
|
|
448
|
-
src/store/sqlite.ts the "one store" — node:sqlite context_chunks + session_state (FTS5 trigram)
|
|
449
|
-
src/store/vectorIndex.ts async PGlite/HNSW cross-repo vector index (redundant, best-effort)
|
|
450
|
-
src/store/migrate.ts JSON → SQLite migration (legacy .checkpoints.json.gz retained)
|
|
451
|
-
src/store/backfill.ts resumable backfill orchestrator (L0/L1/L2/RAPTOR)
|
|
452
|
-
src/memory.ts durable memories (decision/fact/preference) + auto-review
|
|
453
|
-
src/memoryOps.ts memory apply/consolidate ops
|
|
454
|
-
src/memoryRecall.ts memory recall + auto-inline (RAG context)
|
|
455
|
-
src/driftDetection.ts cross-repo drift report (stale/idle/compaction-lag/model-churn)
|
|
456
|
-
src/monitoring.ts local events.log + dashboard.json metrics + FP alerts
|
|
457
|
-
src/canary.ts sequential L0→L1→L2→RAPTOR rollout, auto-disable on p95 breach
|
|
458
|
-
src/config/dedup.ts single source of truth for ALL dedup tier flags + thresholds
|
|
459
|
-
src/store.ts state dir + JSON DR helpers + compression re-exports
|
|
460
|
-
src/compact.ts Layer 2: summarize / merge / autoCompactCheck
|
|
461
|
-
src/supersede.ts Layer 1: obsolete file-read pruning
|
|
462
|
-
src/boundary.ts drop-boundary guards (anchor floor + tool-pair)
|
|
463
|
-
src/tokens.ts deterministic token estimator
|
|
464
|
-
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
|
|
465
75
|
```
|
|
466
76
|
|
|
467
|
-
|
|
468
|
-
The extension entry adapts between the engine and pi's runtime types.
|
|
469
|
-
|
|
470
|
-
---
|
|
77
|
+
Detailed architecture: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
|
|
471
78
|
|
|
472
79
|
## Development
|
|
473
80
|
|
|
474
81
|
```bash
|
|
475
|
-
npm run build
|
|
476
|
-
npm test
|
|
477
|
-
npm run lint
|
|
478
|
-
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
|
|
479
85
|
```
|
|
480
86
|
|
|
481
|
-
|
|
482
|
-
change.
|
|
483
|
-
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
## Testing & bug reports
|
|
487
|
-
|
|
488
|
-
Full QA instructions — environment setup, the manual test checklist, what to
|
|
489
|
-
include in a bug report, and known limitations — live in
|
|
490
|
-
[`TESTER_GUIDE.md`](TESTER_GUIDE.md). Open issues at
|
|
491
|
-
[github.com/TheArchitectit/pi-mega-compact/issues](https://github.com/TheArchitectit/pi-mega-compact/issues).
|
|
492
|
-
|
|
493
|
-
---
|
|
494
|
-
|
|
495
|
-
## Acknowledgements
|
|
496
|
-
|
|
497
|
-
Algorithmic reference (reimplemented in TypeScript, not vendored): memory-mcp
|
|
498
|
-
(`MemoryCompactor` / `compact.py`), claw-code (`trident.rs` / `compact.rs`), and
|
|
499
|
-
neuralwatt-mcr (pi-extension mechanics). Attribution as design sources only.
|
|
87
|
+
Testing guide: [`TESTER_GUIDE.md`](TESTER_GUIDE.md)
|
|
500
88
|
|
|
501
89
|
## License
|
|
502
90
|
|
|
503
|
-
|
|
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
|
+
}
|