pi-blackhole 0.3.2 → 0.3.4
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 +63 -62
- package/package.json +1 -1
- package/src/commands/memory.ts +5 -5
- package/src/commands/pi-vcc.ts +44 -7
- package/src/core/settings.ts +17 -2
- package/src/core/unified-config.ts +184 -20
- package/src/hooks/before-compact.ts +148 -9
- package/src/om/compaction-trigger.ts +26 -12
- package/src/om/configure-overlay.ts +383 -0
- package/src/om/consolidation.ts +64 -6
- package/src/om/cooldown.ts +10 -0
- package/src/om/key-matcher.ts +38 -0
- package/src/om/model-budget.ts +22 -0
- package/src/om/runtime.ts +31 -1
- package/src/om/status-overlay.ts +243 -0
package/README.md
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
# pi-blackhole
|
|
2
2
|
|
|
3
|
-
> [!
|
|
4
|
-
> **
|
|
5
|
-
>
|
|
6
|
-
>
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Blackhole is the default compaction engine** (`compactionEngine: "blackhole"`, `compaction: "auto"`). Auto-compaction fires at the configured threshold using blackhole's pipeline — both auto-trigger and Pi's `/compact` command use it. No additional setup needed. To work automatically, blackhole needs to register its hook so it overrides /compact with the `blackhole` compaction engine. Opting out or opting for manual compaction with blackhole can be done as below:
|
|
5
|
+
>
|
|
6
|
+
> | Setting | Auto-trigger after threshold | `/compact` (Pi built-in) |
|
|
7
|
+
> |---|---|---|
|
|
8
|
+
> | `"auto"` + `"blackhole"` (default) | blackhole handles ✓ | blackhole handles |
|
|
9
|
+
> | `"auto"` + `"pi-default"` | Pi handles | Pi handles |
|
|
10
|
+
> | `"manual"` + any | skipped | Pi handles ✓ |
|
|
11
|
+
> | `"off"` + any | skipped (Pi handles) | Pi handles ✓ |
|
|
12
|
+
>
|
|
13
|
+
> The `/blackhole` command always uses blackhole's pipeline regardless of settings.
|
|
14
|
+
>
|
|
15
|
+
> **Upgrading from an older version?** This version replaces legacy keys (`passive`, `noAutoCompact`, `overrideDefaultCompaction`) with `compaction`, `compactionEngine`, and `tailBehavior`. Automatic migration runs at startup — old configs continue to work. Best effort was made to preserve existing behavior, but review [`MIGRATION-GUIDE.md`](MIGRATION-GUIDE.md) if something behaves differently.
|
|
7
16
|
>
|
|
8
17
|
> See [`CONFIG.md`](CONFIG.md) for the full reference.
|
|
9
18
|
|
|
@@ -13,25 +22,12 @@ Blackhole merges the best ideas from [pi-vcc](https://github.com/sting8k/pi-vcc)
|
|
|
13
22
|
|
|
14
23
|
> **Why this exists:** I liked both extensions but they fought each other — OM hooked into Pi's default compaction and blocked vcc from working. So I merged them, made them share a single hook and output, and added everything both were missing: fallback chains, cooldowns, a memory toggle, and a manual mode for people who want to control when context gets compressed.
|
|
15
24
|
>
|
|
16
|
-
> The codebase has since diverged heavily from both upstreams, but tries to keep up-to-date with any fixes from them
|
|
17
|
-
|
|
18
|
-
> [!IMPORTANT]
|
|
19
|
-
> **Auto-compaction behavior & configuration**
|
|
20
|
-
>
|
|
21
|
-
> Blackhole's auto-compaction **only activates when explicitly opted in**. By default (`overrideDefaultCompaction: false`), blackhole stays out of Pi's compaction — Pi handles its own automatically, and blackhole's `/blackhole` command still works manually.
|
|
22
|
-
>
|
|
23
|
-
> Configure via your Pi agent's `config.json`:
|
|
24
|
-
>
|
|
25
|
-
> | What you want | `overrideDefaultCompaction` | `noAutoCompact` |
|
|
26
|
-
> |---|---|---|
|
|
27
|
-
> | Blackhole auto-compacts at your threshold | `true` | `false` |
|
|
28
|
-
> | Pi handles auto-compaction (default) | `false` | `false` |
|
|
29
|
-
> | Manual only — use `/blackhole` | any | `true` |
|
|
30
|
-
>
|
|
31
|
-
> See [`CONFIG.md`](CONFIG.md) for the full reference.
|
|
25
|
+
> The codebase has since diverged heavily from both upstreams, but tries to keep up-to-date with any fixes from them.
|
|
32
26
|
|
|
33
27
|
📖 See [`CHANGELOG.md`](CHANGELOG.md) for release history.
|
|
34
28
|
⚙️ See [`CONFIG.md`](CONFIG.md) for the full configuration reference.
|
|
29
|
+
🔄 See [`MIGRATION-GUIDE.md`](MIGRATION-GUIDE.md) if upgrading from an older version.
|
|
30
|
+
📜 See [`OLD_CONFIG.md`](OLD_CONFIG.md) for the legacy config documentation.
|
|
35
31
|
|
|
36
32
|
---
|
|
37
33
|
|
|
@@ -66,9 +62,13 @@ pi-blackhole tracks both upstream repositories via a [lockstep audit system](.pi
|
|
|
66
62
|
|
|
67
63
|
## Demo
|
|
68
64
|
|
|
69
|
-
`/blackhole` collapses ~
|
|
65
|
+
`/blackhole` collapses ~143k tokens of conversation into a ~6.3k structured summary (YMMV based on your settings). `/blackhole-memory` shows pipeline status. `/blackhole-recall` searches history the agent can also reach via its `recall` tool and incrementally search previous conversation history.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
https://github.com/user-attachments/assets/a7dd804d-6aca-4bdb-8b6e-0dd779363a43
|
|
70
|
+
|
|
70
71
|
|
|
71
|
-
https://github.com/user-attachments/assets/ab7c5787-1bbd-466f-a231-0818e68e9f39
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
---
|
|
@@ -86,28 +86,6 @@ The two upstream projects each solve one half:
|
|
|
86
86
|
|
|
87
87
|
**pi-blackhole** puts vcc in the compaction slot and OM in the memory layer, where each does what it's designed for.
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## Feature comparison
|
|
93
|
-
|
|
94
|
-
| | pi-blackhole | pi-vcc | pi-obs-memory | Pi default |
|
|
95
|
-
|---|---|---|---|---|
|
|
96
|
-
| Algorithmic compaction (no LLM cost) | ✓ | ✓ | — | — |
|
|
97
|
-
| Deterministic output | ✓ | ✓ | — | — |
|
|
98
|
-
| Structured summary sections | ✓ | ✓ | — | — |
|
|
99
|
-
| Observations + reflections | ✓ | — | ✓ | — |
|
|
100
|
-
| Context survives across compactions | ✓ | — | ✓ | — |
|
|
101
|
-
| Background memory workers | ✓ | — | ✓ | — |
|
|
102
|
-
| Searchable history after compaction | ✓ | ✓ | partial | — |
|
|
103
|
-
| Per-worker model config | ✓ | — | — | — |
|
|
104
|
-
| Fallback model chains + persisted cooldowns | ✓ | — | — | — |
|
|
105
|
-
| Manual flush mode (`noAutoCompact`) | ✓ | — | — | — |
|
|
106
|
-
| Memory toggle (`/blackhole om-off`) | ✓ | — | — | — |
|
|
107
|
-
| Unified single-file config | ✓ | — | — | — |
|
|
108
|
-
| Per-session pending state | ✓ | — | — | — |
|
|
109
|
-
|
|
110
|
-
|
|
111
89
|
---
|
|
112
90
|
|
|
113
91
|
## How it works
|
|
@@ -121,7 +99,7 @@ The agent receives a deterministic recap of recent work *plus* durable facts fro
|
|
|
121
99
|
|
|
122
100
|
### The three memory workers
|
|
123
101
|
|
|
124
|
-
Three background workers run automatically during the session (when `memory: true`, which is the default):
|
|
102
|
+
Three background workers (separate LLM calls) run automatically during the session (when `memory: true`, which is the default):
|
|
125
103
|
|
|
126
104
|
- **Observer** — reads conversation since the last observation marker and extracts timestamped facts: events, decisions, preferences. Input is capped to `observerChunkMaxTokens` newest-first to prevent context blowup on long sessions. Runs most frequently.
|
|
127
105
|
- **Reflector** — distills new observations into durable reflections: stable facts, patterns, and constraints that survive future compactions. Runs less often.
|
|
@@ -203,7 +181,7 @@ When exact source context is needed for precision or traceability, use the `reca
|
|
|
203
181
|
----
|
|
204
182
|
```
|
|
205
183
|
|
|
206
|
-
> **Note:** The OM injection format uses `## Reflections` and `## Observations` Markdown headers with a preamble and footer. Each observation and reflection has a 12-char hex identifier you can use with the `recall` tool to recover source evidence.
|
|
184
|
+
> **Note:** The OM injection format uses `## Reflections` and `## Observations` Markdown headers with a preamble and footer. Each observation and reflection has a 12-char hex identifier you can use with the `recall` tool to recover source evidence, as well as the agent can search based on them and get relevant context back.
|
|
207
185
|
|
|
208
186
|
---
|
|
209
187
|
|
|
@@ -212,11 +190,11 @@ When exact source context is needed for precision or traceability, use the `reca
|
|
|
212
190
|
Two modes, one shared goal: keep your agent's context sharp without manual housekeeping.
|
|
213
191
|
|
|
214
192
|
- **Auto mode (default):** install and forget. Workers run, observations are appended as invisible conversation markers, compaction fires automatically when tokens exceed threshold.
|
|
215
|
-
- **Manual mode (`
|
|
193
|
+
- **Manual mode (`compaction: "manual"` — the maintainer's daily driver):** same workers, same pipeline. But observations go to per-session disk buffers and compaction only happens when you run `/blackhole`. Cleaner conversation, manual schedule.
|
|
216
194
|
|
|
217
195
|
The tradeoff is simplicity vs cleanliness:
|
|
218
196
|
|
|
219
|
-
| | Auto (default) | Manual (`
|
|
197
|
+
| | Auto (default) | Manual (`compaction: "manual"`) |
|
|
220
198
|
|---|---|---|
|
|
221
199
|
| Workers run? | Yes | Yes |
|
|
222
200
|
| Observations go to | Conversation markers (invisible in TUI) | Disk (`<sessionId>-pending.json`) |
|
|
@@ -234,15 +212,15 @@ The difference from Pi's built-in `/compact`:
|
|
|
234
212
|
- `/compact` calls an LLM to write a free-form summary — costly, lossy, no memory layer.
|
|
235
213
|
- `/blackhole` uses algorithmic section extraction (goals, files, commits, preferences...) plus injects observations/reflections from the session ledger. No LLM involved in the compaction itself. Fast, deterministic, memory-preserving.
|
|
236
214
|
|
|
237
|
-
###
|
|
215
|
+
### Fully disabled
|
|
238
216
|
|
|
239
|
-
Set `
|
|
217
|
+
Set `compaction: "off"` and `memory: false` (or the environment variable `PI_BLACKHOLE_PASSIVE=true` which sets both) to completely disable all background workers and blackhole's auto-compaction trigger. Pi handles auto-compaction normally. Explicit `/blackhole` still uses blackhole's pipeline. This is useful for debugging or if you want manual-only blackhole involvement.
|
|
240
218
|
|
|
241
219
|
### Without observational memory (vcc-only)
|
|
242
220
|
|
|
243
221
|
Set `memory: false` or run `/blackhole om-off` for pure vcc compaction — no background workers, no memory injection. The compaction still uses the algorithmic vcc pipeline (not Pi's LLM-based compaction). Re-enable with `/blackhole om-on` or setting `memory: true`.
|
|
244
222
|
|
|
245
|
-
This is a lighter alternative to `
|
|
223
|
+
This is a lighter alternative to `compaction: "off"`: workers are off but blackhole's compaction engine still handles compaction.
|
|
246
224
|
|
|
247
225
|
---
|
|
248
226
|
|
|
@@ -250,7 +228,7 @@ This is a lighter alternative to `passive`: workers are off but auto-compaction
|
|
|
250
228
|
|
|
251
229
|
| Command | What it does |
|
|
252
230
|
|---|---|
|
|
253
|
-
| `/blackhole` | Compact the conversation. Subcommands: `om-off` / `om-on` toggle observational memory. |
|
|
231
|
+
| `/blackhole` | Compact the conversation. Subcommands: `configure` (settings overlay), `om-off` / `om-on` toggle observational memory. |
|
|
254
232
|
| `/blackhole-memory` (or `status`) | Pipeline status: token progress, observation/reflection counts, pending data, last errors |
|
|
255
233
|
| `/blackhole-memory view` | Show visible observations and reflections (after compaction trimming), copied to clipboard |
|
|
256
234
|
| `/blackhole-memory full` | Show ALL recorded memory (including dropped observations), copied to clipboard |
|
|
@@ -276,7 +254,7 @@ The agent gets a unified `recall` tool that handles three types of input:
|
|
|
276
254
|
|
|
277
255
|
## Configuration
|
|
278
256
|
|
|
279
|
-
All settings in a single JSON file: **`~/.pi/agent/pi-blackhole/pi-blackhole-config.json`** — auto-created with defaults on first startup. See [`CONFIG.md`](CONFIG.md) for the full reference with detailed explanations for every knob. An annotated example config is at [`example-config.json`](example-config.json).
|
|
257
|
+
All settings in a single JSON file: **`~/.pi/agent/pi-blackhole/pi-blackhole-config.json`** — auto-created with defaults on first startup. See [`CONFIG.md`](CONFIG.md) for the full reference with detailed explanations for every knob. An annotated example config with the new config surface is at [`example-config-v2.json`](example-config-v2.json). The legacy example is at [`example-config.json`](example-config.json).
|
|
280
258
|
|
|
281
259
|
Quick start — just set custom models (if you want):
|
|
282
260
|
|
|
@@ -288,27 +266,28 @@ Quick start — just set custom models (if you want):
|
|
|
288
266
|
}
|
|
289
267
|
```
|
|
290
268
|
|
|
291
|
-
|
|
269
|
+
Everything else has sensible defaults.
|
|
292
270
|
|
|
293
271
|
### Settings at a glance
|
|
294
272
|
|
|
295
273
|
| Setting | Default | What it controls |
|
|
296
274
|
|---|---|---|
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
275
|
+
| `compaction` | `"auto"` | When compaction triggers: `"auto"` (blackhole auto-fires), `"manual"` (only `/blackhole`), `"off"` (Pi handles auto + `/compact`, `/blackhole` still works) |
|
|
276
|
+
| `compactionEngine` | `"blackhole"` | Which engine handles auto-compaction: `"blackhole"` or `"pi-default"`. Only meaningful when `compaction: "auto"` — for `"manual"`/`"off"` the hook lets Pi handle everything except `/blackhole` |
|
|
277
|
+
| `tailBehavior` | `"minimal"` | How much of the transcript stays visible after compaction: `"minimal"` (last user message only, default) or `"pi-default"` (gentle, ~20k tokens) |
|
|
278
|
+
| `memory` | `true` | `false` = OM workers off + no memory injection (compaction still runs) |
|
|
301
279
|
| `model` | — | Base fallback model for all workers (last resort before session model) |
|
|
302
280
|
| `observerModel` / `observerFallbackModels` | — / `[]` | Primary + fallback models for observer (extracts facts) |
|
|
303
281
|
| `reflectorModel` / `reflectorFallbackModels` | — / `[]` | Primary + fallback models for reflector (synthesizes reflections) |
|
|
304
282
|
| `dropperModel` / `dropperFallbackModels` | — / `[]` | Primary + fallback models for dropper (prunes observations) |
|
|
305
283
|
| *(per model)* `thinking` | `"low"` | Thinking/reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
|
306
284
|
| *(per model)* `cooldownHours` | `1` | How long to skip this model after a retryable error |
|
|
285
|
+
| *(per model)* `contextWindow` | *(inherited from Pi)* | Override context window for this model. If unset, inherits from Pi's model registry. When set, the OM pipeline checks if the estimated input fits before calling the model — if not, the next fallback is tried. |
|
|
307
286
|
| `observeAfterTokens` | `15000` | Min accumulated tokens before observer runs |
|
|
308
287
|
| `reflectAfterTokens` | `25000` | Min accumulated tokens before reflector + dropper run |
|
|
309
|
-
| `compactAfterTokens` | `81000` | Auto-compaction threshold (when `
|
|
288
|
+
| `compactAfterTokens` | `81000` | Auto-compaction threshold (when `compaction: "auto"`) |
|
|
310
289
|
| `observerChunkMaxTokens` | `40000` | Max observer input per run (newest-first) |
|
|
311
|
-
| `observerPreambleMaxTokens` | `0` (auto) | Preamble cap for observer in `
|
|
290
|
+
| `observerPreambleMaxTokens` | `0` (auto) | Preamble cap for observer in `compaction: "manual"` mode (auto = 30% of chunk) |
|
|
312
291
|
| `observationsPoolMaxTokens` | `20000` | Max active observation pool before dropper prunes |
|
|
313
292
|
| `observationsPoolTargetTokens` | `10000` | Target size dropper aims for after pruning (derived: half of pool max) |
|
|
314
293
|
| `reflectorInputMaxTokens` | `80000` | Max reflector input budget |
|
|
@@ -317,7 +296,7 @@ That's it. Everything else has sensible defaults.
|
|
|
317
296
|
| `debug` | `false` | Pre-compaction snapshot to `/tmp/pi-blackhole-debug.json` |
|
|
318
297
|
| `debugLog` | `false` | Continuous JSONL debug log to `~/.pi/agent/pi-blackhole/debug.ndjson` |
|
|
319
298
|
|
|
320
|
-
**Environment override:** `PI_BLACKHOLE_PASSIVE=true`
|
|
299
|
+
**Environment override:** `PI_BLACKHOLE_PASSIVE=true` sets `compaction: "off"` + `memory: false` without touching the config file. Also accepts legacy `PI_VCC_OM_PASSIVE` / `PI_OBSERVATIONAL_MEMORY_PASSIVE`.
|
|
321
300
|
|
|
322
301
|
### Configuration presets
|
|
323
302
|
|
|
@@ -502,6 +481,28 @@ Results are shown as a collapsible message and auto-fed to the agent as context.
|
|
|
502
481
|
|
|
503
482
|
**Touched mode** (`mode:touched`) aggregates all files written, edited, or read across the session, grouped by path. Each entry shows which tool operation touched the file and the line count. Useful for getting a lay of the land after a long session.
|
|
504
483
|
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Feature comparison
|
|
487
|
+
|
|
488
|
+
| | pi-blackhole | pi-vcc | pi-obs-memory | Pi default |
|
|
489
|
+
|---|---|---|---|---|
|
|
490
|
+
| Algorithmic compaction (no LLM cost) | ✓ | ✓ | — | — |
|
|
491
|
+
| Deterministic output | ✓ | ✓ | — | — |
|
|
492
|
+
| Structured summary sections | ✓ | ✓ | — | — |
|
|
493
|
+
| Observations + reflections | ✓ | — | ✓ | — |
|
|
494
|
+
| Context survives across compactions | ✓ | — | ✓ | — |
|
|
495
|
+
| Background memory workers | ✓ | — | ✓ | — |
|
|
496
|
+
| Searchable history after compaction | ✓ | ✓ | partial | — |
|
|
497
|
+
| Per-worker model config | ✓ | — | — | — |
|
|
498
|
+
| Fallback model chains + persisted cooldowns | ✓ | — | — | — |
|
|
499
|
+
| Manual flush mode (`compaction: "manual"`) | ✓ | — | — | — |
|
|
500
|
+
| Memory toggle (`/blackhole om-off`) | ✓ | — | — | — |
|
|
501
|
+
| Unified single-file config | ✓ | — | — | — |
|
|
502
|
+
| Per-session pending state | ✓ | — | — | — |
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
505
506
|
## Uninstall
|
|
506
507
|
|
|
507
508
|
```bash
|
|
@@ -522,7 +523,7 @@ What blackhole adds and reworks on top:
|
|
|
522
523
|
|
|
523
524
|
- **Unified configuration** — one JSON file, not two
|
|
524
525
|
- **Per-worker model fallback chains** with persisted cooldowns that survive Pi restarts
|
|
525
|
-
- **Manual flush mode** — `
|
|
526
|
+
- **Manual flush mode** — `compaction: "manual"` saves observations to per-session disk buffers
|
|
526
527
|
- **Conflict resolution** — OM hooks into vcc's compaction, not Pi's default
|
|
527
528
|
- **Memory toggle** (`/blackhole om-off` / `/blackhole om-on`) — disable the memory layer without uninstalling
|
|
528
529
|
- **Per-session pending state** — isolated per-session JSON files, no cross-session contamination
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-blackhole",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"packageManager": "pnpm@11.2.2",
|
|
5
5
|
"description": "Unified compaction + observational memory extension for Pi — compresses conversation context while preserving durable observations and reflections",
|
|
6
6
|
"license": "MIT",
|
package/src/commands/memory.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /memory command — shows memory pipeline status and content.
|
|
2
|
+
* /blackhole-memory command — shows memory pipeline status and content.
|
|
3
3
|
*
|
|
4
4
|
* Created by pi-vcc-om. Replaces OM's standalone /om-status and /om-view.
|
|
5
|
-
* Usage: /memory
|
|
5
|
+
* Usage: /blackhole-memory [status|view|full]
|
|
6
6
|
*/
|
|
7
7
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { copyTextToClipboard } from "../om/clipboard.js";
|
|
@@ -79,7 +79,7 @@ export function registerMemoryCommand(pi: ExtensionAPI, runtime: Runtime): void
|
|
|
79
79
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
80
80
|
const mode = firstArg(args);
|
|
81
81
|
|
|
82
|
-
// /memory full — show full recorded memory + copy to clipboard
|
|
82
|
+
// /blackhole-memory full — show full recorded memory + copy to clipboard
|
|
83
83
|
if (mode === "full") {
|
|
84
84
|
const projection = fullProjection(entries);
|
|
85
85
|
const output = renderContentOnlyProjection(projection, "recorded");
|
|
@@ -91,7 +91,7 @@ export function registerMemoryCommand(pi: ExtensionAPI, runtime: Runtime): void
|
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
// /memory view — show visible memory + copy to clipboard
|
|
94
|
+
// /blackhole-memory view — show visible memory + copy to clipboard
|
|
95
95
|
if (mode === "view") {
|
|
96
96
|
const projection = visibleProjection(entries);
|
|
97
97
|
const output = renderContentOnlyProjection(projection, "visible");
|
|
@@ -103,7 +103,7 @@ export function registerMemoryCommand(pi: ExtensionAPI, runtime: Runtime): void
|
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// /memory (no args) — show status
|
|
106
|
+
// /blackhole-memory (no args) — show status
|
|
107
107
|
if (mode && mode !== "status") {
|
|
108
108
|
ctx.ui.notify("Usage: /blackhole-memory [status|view|full]", "info");
|
|
109
109
|
return;
|
package/src/commands/pi-vcc.ts
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import type { Runtime } from "../om/runtime.js";
|
|
11
|
-
import { PI_VCC_COMPACT_INSTRUCTION } from "../hooks/before-compact";
|
|
12
|
-
import { saveUnifiedConfig } from "../core/unified-config.js";
|
|
11
|
+
import { PI_VCC_COMPACT_INSTRUCTION, notifyMigrationReminder } from "../hooks/before-compact";
|
|
12
|
+
import { saveUnifiedConfig, configPath } from "../core/unified-config.js";
|
|
13
13
|
import { readPendingState, clearPendingState, hasPendingData } from "../om/pending.js";
|
|
14
|
+
import { createConfigureOverlay } from "../om/configure-overlay.js";
|
|
14
15
|
import {
|
|
15
16
|
OM_OBSERVATIONS_DROPPED,
|
|
16
17
|
OM_OBSERVATIONS_RECORDED,
|
|
@@ -23,15 +24,50 @@ const formatTokens = (n: number): string => {
|
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export const registerPiVccCommand = (pi: ExtensionAPI, runtime: Runtime) => {
|
|
27
|
+
const fuzzyMatch = (value: string, prefix: string): boolean => {
|
|
28
|
+
const q = prefix.toLowerCase();
|
|
29
|
+
let qi = 0;
|
|
30
|
+
for (const ch of value) {
|
|
31
|
+
if (qi < q.length && ch === q[qi]) qi++;
|
|
32
|
+
if (qi === q.length) return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
};
|
|
36
|
+
|
|
26
37
|
pi.registerCommand("blackhole", {
|
|
27
38
|
description:
|
|
28
39
|
"Compact conversation — structured summary (with observational memory when enabled). " +
|
|
29
|
-
"Subcommands: /blackhole
|
|
40
|
+
"Subcommands: /blackhole configure (open settings overlay), " +
|
|
41
|
+
"/blackhole om-off (disable memory), /blackhole om-on (re-enable memory).",
|
|
42
|
+
getArgumentCompletions: (prefix: string) => {
|
|
43
|
+
const subcommands = [
|
|
44
|
+
{ value: "configure", label: "Open configuration overlay to edit settings [configure]" },
|
|
45
|
+
{ value: "om-off", label: "Disable observational memory [om-off]" },
|
|
46
|
+
{ value: "om-on", label: "Enable observational memory [om-on]" },
|
|
47
|
+
];
|
|
48
|
+
if (!prefix) return subcommands;
|
|
49
|
+
return subcommands.filter((s) => fuzzyMatch(s.value, prefix));
|
|
50
|
+
},
|
|
30
51
|
handler: async (args, ctx) => {
|
|
31
52
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
32
53
|
|
|
33
|
-
// Handle
|
|
54
|
+
// Handle subcommands
|
|
34
55
|
const trimmed = (typeof args === "string" ? args : "").trim();
|
|
56
|
+
if (trimmed === "configure") {
|
|
57
|
+
// Open the config overlay
|
|
58
|
+
const result = await ctx.ui.custom<{ saved: boolean; path: string } | undefined>(
|
|
59
|
+
(tui, theme, _kb, done) => createConfigureOverlay(configPath(), theme, tui, done),
|
|
60
|
+
{ overlay: true },
|
|
61
|
+
);
|
|
62
|
+
if (result) {
|
|
63
|
+
if (result.saved) {
|
|
64
|
+
ctx.ui.notify("Configuration saved.", "info");
|
|
65
|
+
} else {
|
|
66
|
+
ctx.ui.notify("Failed to save configuration — the config file may be read-only (e.g., managed by Nix).", "warning");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
35
71
|
if (trimmed === "om-off") {
|
|
36
72
|
const saved = saveUnifiedConfig({ memory: false });
|
|
37
73
|
runtime.config.memory = false;
|
|
@@ -61,9 +97,9 @@ export const registerPiVccCommand = (pi: ExtensionAPI, runtime: Runtime) => {
|
|
|
61
97
|
return;
|
|
62
98
|
}
|
|
63
99
|
|
|
64
|
-
// If noAutoCompact: flush pending OM entries
|
|
65
|
-
// before compacting so the summary includes accumulated memory.
|
|
66
|
-
if (runtime.config.
|
|
100
|
+
// If compaction is manual (or legacy noAutoCompact): flush pending OM entries
|
|
101
|
+
// into the branch before compacting so the summary includes accumulated memory.
|
|
102
|
+
if (runtime.config.compaction === "manual" && hasPendingData(sessionId)) {
|
|
67
103
|
const pending = readPendingState(sessionId);
|
|
68
104
|
// Write all accumulated observation batches (or latest single batch
|
|
69
105
|
// as fallback for legacy pending.json without batch arrays).
|
|
@@ -105,6 +141,7 @@ export const registerPiVccCommand = (pi: ExtensionAPI, runtime: Runtime) => {
|
|
|
105
141
|
} else {
|
|
106
142
|
ctx.ui.notify("Compacted with blackhole", "info");
|
|
107
143
|
}
|
|
144
|
+
notifyMigrationReminder(sessionId, (msg, level) => ctx.ui.notify(msg, level as any));
|
|
108
145
|
},
|
|
109
146
|
onError: (err) => {
|
|
110
147
|
if (err.message === "Compaction cancelled" || err.message === "Already compacted") {
|
package/src/core/settings.ts
CHANGED
|
@@ -7,17 +7,32 @@
|
|
|
7
7
|
import { loadUnifiedConfig, scaffoldConfig } from "./unified-config.js";
|
|
8
8
|
|
|
9
9
|
export interface PiVccSettings {
|
|
10
|
-
/**
|
|
10
|
+
/** @deprecated Use compactionEngine instead. */
|
|
11
11
|
overrideDefaultCompaction: boolean;
|
|
12
|
+
/** @deprecated Use compaction instead. */
|
|
13
|
+
noAutoCompact: boolean;
|
|
14
|
+
/** @deprecated Use compaction + memory instead. */
|
|
15
|
+
passive: boolean;
|
|
12
16
|
/** Write debug snapshots to /tmp/pi-blackhole-debug.json. */
|
|
13
17
|
debug: boolean;
|
|
18
|
+
/** Unified compaction control: "auto" | "manual" | "off". */
|
|
19
|
+
compaction: "auto" | "manual" | "off";
|
|
20
|
+
/** Compaction engine: "blackhole" | "pi-default". */
|
|
21
|
+
compactionEngine: "blackhole" | "pi-default";
|
|
22
|
+
/** Visible tail behavior: "pi-default" | "minimal". */
|
|
23
|
+
tailBehavior: "pi-default" | "minimal";
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
export function loadSettings(): PiVccSettings {
|
|
17
27
|
const config = loadUnifiedConfig(process.cwd());
|
|
18
28
|
return {
|
|
19
|
-
overrideDefaultCompaction: config.overrideDefaultCompaction,
|
|
29
|
+
overrideDefaultCompaction: config.overrideDefaultCompaction ?? false,
|
|
30
|
+
noAutoCompact: config.noAutoCompact ?? false,
|
|
31
|
+
passive: config.passive ?? false,
|
|
20
32
|
debug: config.debug,
|
|
33
|
+
compaction: config.compaction,
|
|
34
|
+
compactionEngine: config.compactionEngine,
|
|
35
|
+
tailBehavior: config.tailBehavior,
|
|
21
36
|
};
|
|
22
37
|
}
|
|
23
38
|
|