pi-smart-compact 7.19.0 → 7.20.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.20.0] - 2026-07-14
4
+
5
+ ### Fixed
6
+ - **Mixed parallel tool calls could lose unrelated edits** — redundant-read and failed-chain pruning deleted an entire assistant message when only one nested tool call was redundant. Pruning now removes individual direct or `multi_tool_use.parallel` blocks while preserving sibling calls, text, and tool-result pairing.
7
+ - **`smart_compact` ignored host cancellation** — the tool now links Pi's `AbortSignal` to the pipeline controller, handles already-aborted calls before authentication, removes listeners in `finally`, and prevents stale pending summaries.
8
+ - **Cross-compaction delta omissions** — removed decisions and resolved errors now count as meaningful changes and render correctly through one shared delta predicate.
9
+
10
+ ### Added
11
+ - **Pi version compatibility runner** — `bun run compat:pi [version]` validates an exact or latest Pi release in an isolated temporary workspace without changing the checkout. Daily CI exercises the latest host packages; a package-boundary regression test prevents accidental bundling or version pinning.
12
+ - **Repeatable hot-path benchmark** — `bun run bench` reports median/p95 performance for incremental extraction and pruning.
13
+
14
+ ### Changed
15
+ - **Pi core dependency boundary** — `@earendil-works/pi-*` and `typebox` are host-provided wildcard peers only; duplicated versioned development dependencies were removed. The lockfile remains the reproducible local baseline.
16
+ - **Bounded runtime logs** — metrics and damage JSONL logs retain complete trailing records under a 5 MiB cap using the same lock as concurrent appenders.
17
+ - **Metrics UI separation** — text/HTML reporting moved from `utils/cache.ts` to `ui/metrics-report.ts`, reusing shared dashboard formatters; legacy service lifecycle comments now match production's run-scoped DI.
18
+ - **Deferred filesystem maintenance** — extraction-cache cleanup now runs on a later event-loop turn rather than in the microtask queue.
19
+
20
+ ### Performance
21
+ - **Incremental extraction** — cache hits no longer build an unused full-history tool-call index. The 5,000-message benchmark reduced the measured median from about 0.133 ms to 0.035 ms on the development machine (~74%).
22
+
3
23
  ## [7.19.0] - 2026-07-10
4
24
 
5
25
  ### Fixed
package/README.md CHANGED
@@ -223,6 +223,11 @@ The legacy config key `semanticCompact` is still accepted.
223
223
 
224
224
  ## Companions & compatibility
225
225
 
226
+ Pi core libraries are host-provided wildcard peers and are excluded from the
227
+ published bundle. This keeps the extension independent from Pi's release cadence:
228
+ the lockfile provides a reproducible development baseline, while daily CI runs
229
+ the full suite against the latest Pi packages without changing the manifest.
230
+
226
231
  `pi-smart-compact` is designed to coexist with — and recommended alongside —
227
232
  [`pi-toolkit`](https://github.com/ersintarhan/pi-toolkit). pi-toolkit handles
228
233
  everyday context hygiene (anchors, pivots, status lines, old tool-output
@@ -245,11 +250,11 @@ The extension writes under `~/.pi/agent/`:
245
250
  | `settings.json` | configuration (read) |
246
251
  | `compact-backups/` | conversation backups (retention-pruned) |
247
252
  | `.cache/compact-extraction-<session>.json` | incremental extraction cache |
248
- | `.cache/compact-metrics.jsonl` | metrics log |
253
+ | `.cache/compact-metrics.jsonl` | metrics log (tail-retained, 5 MiB cap) |
249
254
  | `.cache/smart-compact-report.html` | HTML dashboard |
250
255
  | `.cache/smart-compact/projects/<projectId>.json` | project fingerprint |
251
256
  | `.cache/smart-compact/states/<projectId>.json` | reusable compaction state |
252
- | `.cache/smart-compact/damage-reports.jsonl` | regression signals |
257
+ | `.cache/smart-compact/damage-reports.jsonl` | regression signals (tail-retained, 5 MiB cap) |
253
258
  | `.cache/smart-compact/remediation-<projectId>.json` | files to re-preserve after damage |
254
259
 
255
260
  ## Development
@@ -258,6 +263,9 @@ The extension writes under `~/.pi/agent/`:
258
263
  bun install
259
264
  bun run typecheck # tsc --noEmit
260
265
  bun test # full test suite
266
+ bun run bench # repeatable hot-path benchmark
267
+ bun run compat:pi # latest Pi, without changing package.json or bun.lock
268
+ bun run compat:pi 0.80.6 # optional exact Pi version
261
269
  bun run build # dist/ output for publishing
262
270
  ```
263
271
 
@@ -62,6 +62,8 @@ export interface SmartCompactOptions {
62
62
  force?: boolean;
63
63
  /** Optional hard budget for native auto-trigger only. Manual/tool runs do not time out by default. */
64
64
  timeoutMs?: number;
65
+ /** Host cancellation for tool/manual callers. Linked to the pipeline controller. */
66
+ abortSignal?: AbortSignal;
65
67
  /**
66
68
  * If provided, populated with the run's cancellation handle before any
67
69
  * async work begins. The session_before_compact hook uses this to enforce
@@ -1 +1 @@
1
- {"version":3,"file":"run-smart-compact.d.ts","sourceRoot":"","sources":["../../src/app/run-smart-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,OAAO,KAAK,EACQ,UAAU,EAC7B,MAAM,kBAAkB,CAAC;AAc1B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC;;;;;;;OAOG;IACH,GAAG,EAAE,gBAAgB,CAAC;IACtB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;CACrD;AAwCD,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyL9E"}
1
+ {"version":3,"file":"run-smart-compact.d.ts","sourceRoot":"","sources":["../../src/app/run-smart-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,OAAO,KAAK,EACQ,UAAU,EAC7B,MAAM,kBAAkB,CAAC;AAc1B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC;;;;;;;OAOG;IACH,GAAG,EAAE,gBAAgB,CAAC;IACtB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;CACrD;AAwCD,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmM9E"}
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../src/app/steps/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkB/D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAwJ1D"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../src/app/steps/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkB/D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAuJ1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/app/steps/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAY9D,wBAAgB,UAAU,CAAC,EAAE,EAAE,UAAU,GAAG,QAAQ,CAqFnD"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/app/steps/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAY9D,wBAAgB,UAAU,CAAC,EAAE,EAAE,UAAU,GAAG,QAAQ,CAoFnD"}
@@ -8,7 +8,7 @@ import type { CompressionProfile, ProfileConfig } from "./types.ts";
8
8
  * `package.json#version`. Do not hand-edit this line for releases; bump
9
9
  * package.json and run `bun run sync-version`.
10
10
  */
11
- export declare const VERSION = "7.19.0";
11
+ export declare const VERSION = "7.20.0";
12
12
  export declare const CHARS_PER_TOKEN = 3.8;
13
13
  export declare const COMPACT_SYSTEM_PREFIX: string;
14
14
  export declare const PROFILES: Record<CompressionProfile, ProfileConfig>;
@@ -111,6 +111,7 @@ export declare const ERROR_RETRY_WINDOW = 6;
111
111
  /** How far forward to look for that retry's resolving (non-error) result. */
112
112
  export declare const ERROR_RESOLVE_WINDOW = 10;
113
113
  export declare const METRICS_BUFFER_MAX = 200;
114
+ export declare const RUNTIME_LOG_MAX_BYTES: number;
114
115
  export declare const DAMAGE_LOOKBACK_MSGS = 15;
115
116
  export declare const VERIFICATION_GAP_SNIPPET_LEN = 80;
116
117
  export declare const CONFIG_KEY = "smartCompact";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,OAAO,WAAW,CAAC;AAChC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,eAAO,MAAM,qBAAqB,QAKqB,CAAC;AAExD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,kBAAkB,EAAE,aAAa,CAyB9D,CAAC;AAEF,eAAO,MAAM,cAAc;IACzB,OAAO,EAAgB,kBAAkB;IACzC,QAAQ;IACR,YAAY,EAAU,MAAM,GAAG,IAAI;IACnC,iBAAiB,EAAU,MAAM,GAAG,IAAI;IACxC,WAAW;IACX,oBAAoB;IACpB,aAAa;IACb,SAAS;IACT,iBAAiB;IACjB,QAAQ,EAAQ,MAAM,EAAE;CACzB,CAAC;AAEF,eAAO,MAAM,QAAQ,QAA+E,CAAC;AAIrG,eAAO,MAAM,QAAQ,QAAwK,CAAC;AAC9L,eAAO,MAAM,SAAS,QAAmG,CAAC;AAI1H,eAAO,MAAM,kBAAkB,QAgB+C,CAAC;AAE/E,eAAO,MAAM,kBAAkB,yHACyF,CAAC;AAEzH,eAAO,MAAM,mBAAmB,QAWoB,CAAC;AAErD,eAAO,MAAM,mBAAmB,8DAA8D,CAAC;AAE/F,eAAO,MAAM,sBAAsB,QAoB2B,CAAC;AAE/D,eAAO,MAAM,sBAAsB,8OAC0M,CAAC;AAI9O,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK5D,CAAC;AAGF,eAAO,MAAM,YAAY,YAAY,CAAC;AACtC,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAClE,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAC9C,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AACpD,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAClD,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAClD,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAClD,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAClD,eAAO,MAAM,eAAe,qCAAqC,CAAC;AAGlE,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAG5C,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAQxC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAG1D,eAAO,MAAM,eAAe,QAAgB,CAAC;AAC7C,eAAO,MAAM,WAAW,QAAiB,CAAC;AAC1C,eAAO,MAAM,aAAa,QAA0B,CAAC;AACrD,eAAO,MAAM,cAAc,QAA2B,CAAC;AAGvD,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAG7D,eAAO,MAAM,SAAS;aACpB,OAAO,EAAE,OAAO;aAChB,eAAe,EAAE,KAAK;aACtB,wBAAwB,EAAE,MAAM;aAChC,SAAS,EAAE,OAAO;aAClB,QAAQ,EAAE,WAAW;aACrB,KAAK,EAAE,QAAQ;CACP,CAAC;AAGX,eAAO,MAAM,MAAM;aACjB,QAAQ,EAAE,GAAG;aACb,UAAU,EAAE,GAAG;aACf,qBAAqB,EAAE,GAAG;aAC1B,qBAAqB,EAAE,CAAG;aAC1B,eAAe,EAAE,IAAI;aACrB,iBAAiB,EAAE,GAAG;aACtB,cAAc,EAAE,GAAG;CACX,CAAC;AAGX,eAAO,MAAM,KAAK;aAEhB,OAAO,EAAE,GAAG;aACZ,YAAY,EAAE,GAAG;aACjB,gBAAgB,EAAE,GAAG;aACrB,aAAa,EAAE,GAAG;aAClB,eAAe,EAAE,GAAG;aACpB,iBAAiB,EAAE,GAAG;aACtB,cAAc,EAAE,GAAG;aACnB,cAAc,EAAE,GAAG;aAEnB,OAAO,EAAE,EAAE;aACX,OAAO,EAAE,GAAG;aACZ,WAAW,EAAE,GAAG;aAChB,MAAM,EAAE,GAAG;aACX,YAAY,EAAE,GAAG;aACjB,UAAU,EAAE,GAAG;aACf,cAAc,EAAE,GAAG;aACnB,eAAe,EAAE,EAAE;aACnB,WAAW,EAAE,GAAG;aAEhB,YAAY,EAAE,EAAE;aAChB,SAAS,EAAE,CAAC;aACZ,WAAW,EAAE,CAAC;aACd,kBAAkB,EAAE,EAAE;aACtB,aAAa,EAAE,EAAE;aACjB,gBAAgB,EAAE,EAAE;aACpB,eAAe,EAAE,EAAE;aACnB,oBAAoB,EAAE,CAAC;aACvB,eAAe,EAAE,CAAC;CACV,CAAC;AAGX,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAG3C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAGzC,sFAAsF;AACtF,eAAO,MAAM,eAAe,QAA8J,CAAC;AAC3L,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAOvC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAGtC,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAGrD,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAGvC,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAG/C,eAAO,MAAM,UAAU,iBAAiB,CAAC;AACzC,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,eAAO,MAAM,sBAAsB,QAU6T,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,UAAU,EAAwE,MAAM,oBAAoB,CAAC;AA+CtH,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAG5F;AAED,wBAAgB,aAAa,CAC3B,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,EACrC,QAAQ,UAAQ,GACf;IAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;CAAE,CAoBxE;AAED,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,QA4R7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,UAAU,EAAwE,MAAM,oBAAoB,CAAC;AAgDtH,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAG5F;AAED,wBAAgB,aAAa,CAC3B,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,EACrC,QAAQ,UAAQ,GACf;IAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;CAAE,CAoBxE;AAED,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,QA4R7D"}
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
  var __require = import.meta.require;
18
18
 
19
19
  // src/constants.ts
20
- var VERSION = "7.19.0", CHARS_PER_TOKEN = 3.8, COMPACT_SYSTEM_PREFIX, PROFILES, DEFAULT_CONFIG, NO_OP_RE, SHIFT_RE, CHOICE_RE, SINGLE_PASS_PREFIX, SINGLE_PASS_SUFFIX = `
20
+ var VERSION = "7.20.0", CHARS_PER_TOKEN = 3.8, COMPACT_SYSTEM_PREFIX, PROFILES, DEFAULT_CONFIG, NO_OP_RE, SHIFT_RE, CHOICE_RE, SINGLE_PASS_PREFIX, SINGLE_PASS_SUFFIX = `
21
21
  {PREV_CONTEXT}
22
22
 
23
23
  {EXTRACTION_CONTEXT}
@@ -40,7 +40,7 @@ IMMUTABLE CONTEXT (verified deterministic data):
40
40
  {EXPLORATION_CONTEXT}
41
41
  {PREV_CONTEXT}
42
42
 
43
- <summaries>{SUMMARIES}</summaries>`, SESSION_TYPE_INSTRUCTIONS, SECTION_GOAL = "## Goal", SECTION_CONSTRAINTS = "## Constraints & Preferences", SECTION_PROGRESS = "## Progress", SECTION_DECISIONS = "## Key Decisions", SECTION_FILES_MODIFIED = "## Files Modified", SECTION_FILES_READ = "## Files Read", SECTION_NEXT_STEPS = "## Next Steps", SECTION_CRITICAL_CONTEXT = "## Critical Context", SECTION_TOPICS = "## Topics Covered", SECTION_OPEN_LOOPS = "## Open Loops", SECTION_CHANGES = "## Changes Since Last Compaction", LOG_PREFIX = "[smart-compact]", MIN_TOKEN_THRESHOLD = 5000, MAX_EXPLORATION_ROUNDS = 8, BACKUP_MAX_FILES = 20, BACKUP_MAX_AGE_MS, FIVE_MINUTES_MS, ONE_HOUR_MS, SEVEN_DAYS_MS, THIRTY_DAYS_MS, EXTRACTION_CACHE_PREFIX = "compact-extraction-", ID_PREFIX, TUNING, TRUNC, MAX_TOOL_OUTPUT_CHARS = 800, LIKELY_ERROR_RE, ERROR_SCAN_MAX_LEN = 2000, ERROR_RETRY_WINDOW = 6, ERROR_RESOLVE_WINDOW = 10, METRICS_BUFFER_MAX = 200, CONFIG_KEY = "smartCompact", CONFIG_KEY_ALT = "semanticCompact", EXPLORER_SYSTEM_PROMPT;
43
+ <summaries>{SUMMARIES}</summaries>`, SESSION_TYPE_INSTRUCTIONS, SECTION_GOAL = "## Goal", SECTION_CONSTRAINTS = "## Constraints & Preferences", SECTION_PROGRESS = "## Progress", SECTION_DECISIONS = "## Key Decisions", SECTION_FILES_MODIFIED = "## Files Modified", SECTION_FILES_READ = "## Files Read", SECTION_NEXT_STEPS = "## Next Steps", SECTION_CRITICAL_CONTEXT = "## Critical Context", SECTION_TOPICS = "## Topics Covered", SECTION_OPEN_LOOPS = "## Open Loops", SECTION_CHANGES = "## Changes Since Last Compaction", LOG_PREFIX = "[smart-compact]", MIN_TOKEN_THRESHOLD = 5000, MAX_EXPLORATION_ROUNDS = 8, BACKUP_MAX_FILES = 20, BACKUP_MAX_AGE_MS, FIVE_MINUTES_MS, ONE_HOUR_MS, SEVEN_DAYS_MS, THIRTY_DAYS_MS, EXTRACTION_CACHE_PREFIX = "compact-extraction-", ID_PREFIX, TUNING, TRUNC, MAX_TOOL_OUTPUT_CHARS = 800, LIKELY_ERROR_RE, ERROR_SCAN_MAX_LEN = 2000, ERROR_RETRY_WINDOW = 6, ERROR_RESOLVE_WINDOW = 10, METRICS_BUFFER_MAX = 200, RUNTIME_LOG_MAX_BYTES, CONFIG_KEY = "smartCompact", CONFIG_KEY_ALT = "semanticCompact", EXPLORER_SYSTEM_PROMPT;
44
44
  var init_constants = __esm(() => {
45
45
  COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
46
46
  PROFILES = {
@@ -229,6 +229,7 @@ Rules for Accuracy:
229
229
  FINGERPRINT_SEG: 2
230
230
  };
231
231
  LIKELY_ERROR_RE = /(?:command not found|no such file|permission denied|syntax error|cannot find|module not found|compilation error|build failed|test failed|^FAIL\b|ERROR:)/i;
232
+ RUNTIME_LOG_MAX_BYTES = 5 * 1024 * 1024;
232
233
  EXPLORER_SYSTEM_PROMPT = `You are a conversation analyst. You have deterministic extraction data and can query the raw conversation using tools.
233
234
 
234
235
  ` + `Your job:
@@ -402,6 +403,42 @@ function appendLineLocked(target, line) {
402
403
  release();
403
404
  }
404
405
  }
406
+ function trimFileTailLocked(target, maxBytes) {
407
+ const release = acquireLockSync(target);
408
+ try {
409
+ const stat = fs.statSync(target);
410
+ if (stat.size <= maxBytes)
411
+ return;
412
+ const length = Math.min(stat.size, maxBytes);
413
+ const buffer = Buffer.allocUnsafe(length);
414
+ const fd = fs.openSync(target, "r");
415
+ try {
416
+ fs.readSync(fd, buffer, 0, length, stat.size - length);
417
+ } finally {
418
+ fs.closeSync(fd);
419
+ }
420
+ const tail = buffer.toString("utf8");
421
+ const firstNewline = tail.indexOf(`
422
+ `);
423
+ atomicWriteFileSync(target, firstNewline >= 0 ? tail.slice(firstNewline + 1) : "");
424
+ } finally {
425
+ release();
426
+ }
427
+ }
428
+ function scheduleFileTailTrim(target, maxBytes) {
429
+ if (scheduledTailTrims.has(target))
430
+ return;
431
+ scheduledTailTrims.add(target);
432
+ setTimeout(() => {
433
+ try {
434
+ trimFileTailLocked(target, maxBytes);
435
+ } catch (e) {
436
+ debug("tail trim failed for " + target, e);
437
+ } finally {
438
+ scheduledTailTrims.delete(target);
439
+ }
440
+ }, 0);
441
+ }
405
442
  function readJsonSync(target) {
406
443
  try {
407
444
  if (!fs.existsSync(target))
@@ -416,9 +453,10 @@ function readJsonSync(target) {
416
453
  function writeJsonSync(target, value, pretty = false) {
417
454
  atomicWriteFileSync(target, pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value));
418
455
  }
419
- var LOCK_STALE_MS = 5000, LOCK_RETRY_MS = 25, LOCK_MAX_RETRIES = 80;
456
+ var LOCK_STALE_MS = 5000, LOCK_RETRY_MS = 25, LOCK_MAX_RETRIES = 80, scheduledTailTrims;
420
457
  var init_fs = __esm(() => {
421
458
  init_logger();
459
+ scheduledTailTrims = new Set;
422
460
  });
423
461
 
424
462
  // src/utils/tokens.ts
@@ -1051,7 +1089,7 @@ function scheduleExtractionCacheCleanup() {
1051
1089
  if (_extractionPruneInFlight)
1052
1090
  return;
1053
1091
  _extractionPruneInFlight = true;
1054
- queueMicrotask(() => {
1092
+ setTimeout(() => {
1055
1093
  try {
1056
1094
  const dir = path5.dirname(getCachePath("_"));
1057
1095
  if (!fs3.existsSync(dir))
@@ -1121,7 +1159,9 @@ function appendMetricsLog(sessionId, extra, services) {
1121
1159
  ...summary,
1122
1160
  ...extra
1123
1161
  };
1124
- appendLineLocked(metricsLogFile(), JSON.stringify(entry));
1162
+ const logPath = metricsLogFile();
1163
+ appendLineLocked(logPath, JSON.stringify(entry));
1164
+ scheduleFileTailTrim(logPath, RUNTIME_LOG_MAX_BYTES);
1125
1165
  } catch (e) {
1126
1166
  warn("appendMetricsLog failed", e);
1127
1167
  }
@@ -1165,238 +1205,6 @@ function readMetricsLog(limit = 100) {
1165
1205
  return [];
1166
1206
  }
1167
1207
  }
1168
- function escapeHtml(value) {
1169
- return String(value ?? "").replace(/[&<>\"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] ?? c);
1170
- }
1171
- function durationOf(entry) {
1172
- return entry.durationMs ?? entry.phaseTimings?.reduce((sum, phase) => sum + phase.durationMs, 0) ?? 0;
1173
- }
1174
- function percentile(values, p) {
1175
- if (!values.length)
1176
- return 0;
1177
- const sorted = [...values].sort((a, b) => a - b);
1178
- return sorted[Math.min(sorted.length - 1, Math.max(0, Math.floor(p / 100 * sorted.length)))];
1179
- }
1180
- function average(values) {
1181
- return values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : 0;
1182
- }
1183
- function compactNumber(value) {
1184
- return new Intl.NumberFormat("en", { notation: Math.abs(value) >= 1e4 ? "compact" : "standard", maximumFractionDigits: 1 }).format(value);
1185
- }
1186
- function formatNumber(value) {
1187
- if (typeof value !== "number" || !Number.isFinite(value))
1188
- return escapeHtml(value);
1189
- return value.toLocaleString();
1190
- }
1191
- function formatMs(value) {
1192
- if (!value)
1193
- return "0ms";
1194
- if (value >= 60000)
1195
- return (value / 60000).toFixed(value >= 600000 ? 0 : 1) + "m";
1196
- if (value >= 1000)
1197
- return (value / 1000).toFixed(value >= 1e4 ? 0 : 1) + "s";
1198
- return Math.round(value) + "ms";
1199
- }
1200
- function formatPercent(value) {
1201
- return Math.round(value * 100) + "%";
1202
- }
1203
- function statusClass(status) {
1204
- if (status === "timeout" || status === "error")
1205
- return "bad";
1206
- if (status === "dry-run")
1207
- return "warn";
1208
- return "good";
1209
- }
1210
- function statusLabel(status) {
1211
- return status ?? "success";
1212
- }
1213
- function badge(status) {
1214
- const label = statusLabel(status);
1215
- return `<span class="badge ${statusClass(label)}">${escapeHtml(label)}</span>`;
1216
- }
1217
- function summarizeDashboard(entries) {
1218
- const durations = entries.map(durationOf).filter(Boolean);
1219
- const success = entries.filter((e) => statusLabel(e.status) === "success").length;
1220
- const timeout = entries.filter((e) => e.status === "timeout").length;
1221
- const error = entries.filter((e) => e.status === "error").length;
1222
- const dryRun = entries.filter((e) => e.status === "dry-run").length;
1223
- const scored = entries.map((e) => e.verificationScore).filter((v) => typeof v === "number");
1224
- return {
1225
- runs: entries.length,
1226
- success,
1227
- timeout,
1228
- error,
1229
- dryRun,
1230
- successRate: entries.length ? success / entries.length : 0,
1231
- avgDuration: Math.round(average(durations)),
1232
- p95Duration: percentile(durations, 95),
1233
- totalCalls: entries.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
1234
- totalInput: entries.reduce((sum, e) => sum + (e.totalInput ?? 0), 0),
1235
- totalOutput: entries.reduce((sum, e) => sum + (e.totalOutput ?? 0), 0),
1236
- totalSaved: entries.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
1237
- avgScore: Math.round(average(scored))
1238
- };
1239
- }
1240
- function groupMetrics(entries, keyFn) {
1241
- const groups = new Map;
1242
- for (const entry of entries) {
1243
- const key = keyFn(entry);
1244
- if (!key)
1245
- continue;
1246
- groups.set(key, [...groups.get(key) ?? [], entry]);
1247
- }
1248
- return [...groups.entries()].map(([name, group]) => {
1249
- const durations = group.map(durationOf).filter(Boolean);
1250
- const scores = group.map((e) => e.verificationScore).filter((v) => typeof v === "number");
1251
- const failures = group.filter((e) => e.status === "timeout" || e.status === "error").length;
1252
- return {
1253
- name,
1254
- runs: group.length,
1255
- avgDuration: Math.round(average(durations)),
1256
- p95Duration: percentile(durations, 95),
1257
- avgScore: Math.round(average(scores)),
1258
- totalSaved: group.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
1259
- totalCalls: group.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
1260
- errorRate: group.length ? failures / group.length : 0
1261
- };
1262
- }).sort((a, b) => b.runs - a.runs || a.name.localeCompare(b.name));
1263
- }
1264
- function progressBar(value, label = formatPercent(value)) {
1265
- const pct = Math.max(0, Math.min(100, Math.round(value * 100)));
1266
- return `<div class="meter" title="${escapeHtml(label)}"><span style="width:${pct}%"></span></div>`;
1267
- }
1268
- function sparkline(values) {
1269
- const nums = values.filter((v) => Number.isFinite(v));
1270
- if (nums.length < 2)
1271
- return `<div class="empty">Need at least two runs for trend</div>`;
1272
- const width = 520;
1273
- const height = 120;
1274
- const min = Math.min(...nums);
1275
- const max = Math.max(...nums);
1276
- const span = Math.max(1, max - min);
1277
- const points = nums.map((value, i) => {
1278
- const x = i / Math.max(1, nums.length - 1) * width;
1279
- const y = height - (value - min) / span * (height - 18) - 9;
1280
- return `${x.toFixed(1)},${y.toFixed(1)}`;
1281
- }).join(" ");
1282
- const last = nums[nums.length - 1];
1283
- return `<svg class="spark" viewBox="0 0 ${width} ${height}" role="img" aria-label="Duration trend"><polyline points="${points}" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><circle cx="${width}" cy="${(height - (last - min) / span * (height - 18) - 9).toFixed(1)}" r="4" fill="currentColor"/><text x="0" y="14">${escapeHtml(formatMs(max))}</text><text x="0" y="${height - 4}">${escapeHtml(formatMs(min))}</text></svg>`;
1284
- }
1285
- function metricCard(label, value, detail, tone = "neutral") {
1286
- return `<article class="card ${tone}"><div class="label">${escapeHtml(label)}</div><div class="value">${escapeHtml(value)}</div><div class="detail">${escapeHtml(detail)}</div></article>`;
1287
- }
1288
- function comparisonRows(groups) {
1289
- if (!groups.length)
1290
- return `<tr><td colspan="8" class="empty">No data yet</td></tr>`;
1291
- return groups.map((group) => `<tr>
1292
- <td><strong>${escapeHtml(group.name)}</strong></td>
1293
- <td class="num">${formatNumber(group.runs)}</td>
1294
- <td class="num">${escapeHtml(formatMs(group.avgDuration))}</td>
1295
- <td class="num">${escapeHtml(formatMs(group.p95Duration))}</td>
1296
- <td class="num">${group.avgScore ? formatNumber(group.avgScore) : "\u2014"}</td>
1297
- <td class="num">${formatNumber(group.totalCalls)}</td>
1298
- <td class="num">${formatNumber(group.totalSaved)}</td>
1299
- <td>${progressBar(1 - group.errorRate, formatPercent(1 - group.errorRate) + " reliable")}</td>
1300
- </tr>`).join(`
1301
- `);
1302
- }
1303
- function phaseRows(entry) {
1304
- const timings = entry?.phaseTimings ?? [];
1305
- if (!timings.length)
1306
- return `<tr><td colspan="3" class="empty">No phase timings yet</td></tr>`;
1307
- const total = timings.reduce((sum, phase) => sum + phase.durationMs, 0) || 1;
1308
- return timings.map((phase) => `<tr>
1309
- <td>${escapeHtml(phase.phase)}</td>
1310
- <td class="num">${escapeHtml(formatMs(phase.durationMs))}</td>
1311
- <td>${progressBar(phase.durationMs / total, formatPercent(phase.durationMs / total))}</td>
1312
- </tr>`).join(`
1313
- `);
1314
- }
1315
- function recentRunRows(entries) {
1316
- if (!entries.length)
1317
- return `<tr><td colspan="12" class="empty">No runs recorded yet</td></tr>`;
1318
- return entries.slice(-80).reverse().map((entry) => `<tr>
1319
- <td class="mono small">${escapeHtml(entry.ts)}</td>
1320
- <td>${escapeHtml(entry.profile)}</td>
1321
- <td>${escapeHtml(entry.provider ?? entry.model?.split("/")[0])}</td>
1322
- <td>${escapeHtml(entry.method)}</td>
1323
- <td>${escapeHtml(entry.runType)}</td>
1324
- <td>${badge(entry.status)}</td>
1325
- <td class="num">${escapeHtml(formatMs(durationOf(entry)))}</td>
1326
- <td class="num">${typeof entry.verificationScore === "number" ? formatNumber(entry.verificationScore) : "\u2014"}</td>
1327
- <td class="num">${typeof entry.tokensSaved === "number" ? formatNumber(entry.tokensSaved) : "\u2014"}</td>
1328
- <td class="num">${formatNumber(entry.totalCalls ?? 0)}</td>
1329
- <td class="num">${typeof entry.extractionCacheHitRate === "number" ? formatPercent(entry.extractionCacheHitRate) : "\u2014"}</td>
1330
- <td class="mono small reason">${escapeHtml(entry.fallbackReason ?? entry.extractionCacheMissReason ?? "")}</td>
1331
- </tr>`).join(`
1332
- `);
1333
- }
1334
- function dashboardCss() {
1335
- return `:root{color-scheme:dark;--bg:#08111f;--surface:#0f172a;--surface2:#111c33;--card:#111827;--text:#e5edf8;--muted:#8fa3bf;--line:#24324a;--accent:#60a5fa;--good:#22c55e;--bad:#fb7185;--warn:#fbbf24;--shadow:0 18px 50px rgba(0,0,0,.28)}@media(prefers-color-scheme:light){:root{color-scheme:light;--bg:#f4f7fb;--surface:#ffffff;--surface2:#f8fafc;--card:#ffffff;--text:#0f172a;--muted:#64748b;--line:#e2e8f0;--shadow:0 18px 50px rgba(15,23,42,.08)}}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at top left,rgba(96,165,250,.20),transparent 34rem),var(--bg);color:var(--text);font:14px/1.5 Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}main{max-width:1280px;margin:0 auto;padding:32px}header{display:flex;justify-content:space-between;gap:20px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:var(--accent);font-weight:700;text-transform:uppercase;letter-spacing:.08em;font-size:12px}h1{font-size:32px;line-height:1.1;margin:6px 0 6px}.muted,.detail{color:var(--muted)}.cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin:20px 0 22px}.card{background:linear-gradient(180deg,rgba(255,255,255,.035),transparent),var(--card);border:1px solid var(--line);border-radius:18px;padding:16px;box-shadow:var(--shadow)}.card.good{border-color:rgba(34,197,94,.45)}.card.warn{border-color:rgba(251,191,36,.45)}.card.bad{border-color:rgba(251,113,133,.5)}.label{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.08em;font-weight:700}.value{font-size:28px;font-weight:800;margin-top:6px}.layout{display:grid;grid-template-columns:1.15fr .85fr;gap:18px}.panel{background:var(--surface);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);overflow:hidden}.panel h2{display:flex;align-items:center;justify-content:space-between;margin:0;padding:15px 18px;background:linear-gradient(180deg,rgba(255,255,255,.035),transparent),var(--surface2);font-size:15px}.table-wrap{overflow:auto;max-height:560px}table{border-collapse:separate;border-spacing:0;width:100%}th,td{border-bottom:1px solid var(--line);padding:9px 11px;text-align:left;vertical-align:middle;white-space:nowrap}th{position:sticky;top:0;z-index:1;background:var(--surface2);color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em}tr:hover td{background:rgba(96,165,250,.06)}.num{text-align:right}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.small{font-size:12px}.reason{max-width:280px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.badge{display:inline-flex;align-items:center;border-radius:999px;padding:3px 9px;font-size:12px;font-weight:800}.badge.good{background:rgba(34,197,94,.14);color:var(--good)}.badge.bad{background:rgba(251,113,133,.16);color:var(--bad)}.badge.warn{background:rgba(251,191,36,.16);color:var(--warn)}.meter{height:8px;background:rgba(148,163,184,.22);border-radius:99px;min-width:96px;overflow:hidden}.meter span{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--accent),var(--good))}.spark{width:100%;height:160px;color:var(--accent);padding:18px}.spark text{fill:var(--muted);font-size:12px}.empty{padding:18px;color:var(--muted);text-align:center}pre{white-space:pre-wrap;background:var(--surface);border:1px solid var(--line);border-radius:18px;padding:16px;overflow:auto}.section{margin-top:18px}.two{display:grid;grid-template-columns:1fr 1fr;gap:18px}@media(max-width:960px){main{padding:20px}.cards,.layout,.two{grid-template-columns:1fr}header{display:block}th,td{padding:8px}.value{font-size:24px}}`;
1336
- }
1337
- function buildMetricsReport(entries = readMetricsLog(100)) {
1338
- if (!entries.length)
1339
- return "No smart-compact metrics recorded yet.";
1340
- const summary = summarizeDashboard(entries);
1341
- const byProfile = groupMetrics(entries, (e) => e.profile);
1342
- const byProvider = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
1343
- const summarizeGroup = (group) => "- " + group.name + ": n=" + group.runs + ", avg=" + group.avgDuration + "ms, p95=" + group.p95Duration + "ms, score=" + group.avgScore + ", saved=" + group.totalSaved + "t, reliability=" + formatPercent(1 - group.errorRate);
1344
- const extractionCacheRuns = entries.filter((e) => typeof e.extractionCacheHitRate === "number");
1345
- const extractionCacheAvg = average(extractionCacheRuns.map((e) => e.extractionCacheHitRate ?? 0));
1346
- return [
1347
- "# Smart Compact Metrics",
1348
- "",
1349
- "Runs: " + summary.runs + " (success " + summary.success + ", dry-run " + summary.dryRun + ", timeout " + summary.timeout + ", error " + summary.error + ")",
1350
- "Reliability: " + formatPercent(summary.successRate),
1351
- "Latency: avg " + summary.avgDuration + "ms, p95 " + summary.p95Duration + "ms",
1352
- "LLM calls: " + summary.totalCalls + ", input " + summary.totalInput + "t, output " + summary.totalOutput + "t",
1353
- "Extraction cache: avg " + (extractionCacheRuns.length ? formatPercent(extractionCacheAvg) : "\u2014") + " across " + extractionCacheRuns.length + " measured run(s)",
1354
- "Tokens saved: " + summary.totalSaved + "t, average verification score: " + summary.avgScore,
1355
- "",
1356
- "## Profile comparison",
1357
- ...byProfile.map(summarizeGroup),
1358
- "",
1359
- "## Provider comparison",
1360
- ...byProvider.map(summarizeGroup)
1361
- ].join(`
1362
- `);
1363
- }
1364
- function writeMetricsDashboard(entries = readMetricsLog(200)) {
1365
- try {
1366
- ensureDir(cacheDir());
1367
- const summary = summarizeDashboard(entries);
1368
- const latest = entries[entries.length - 1];
1369
- const report = buildMetricsReport(entries);
1370
- const profileGroups = groupMetrics(entries, (e) => e.profile);
1371
- const providerGroups = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
1372
- const healthTone = summary.error + summary.timeout > 0 ? "warn" : "good";
1373
- const html = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Smart Compact Metrics</title><style>${dashboardCss()}</style></head><body><main>
1374
- <header><div><div class="eyebrow">pi-smart-compact</div><h1>Operational Metrics</h1><div class="muted">Generated ${escapeHtml(new Date().toISOString())} \xB7 ${formatNumber(entries.length)} recent runs \xB7 local file dashboard</div></div><div>${badge(latest?.status)} ${latest ? `<span class="muted">latest ${escapeHtml(latest.profile ?? "unknown")}</span>` : ""}</div></header>
1375
- <section class="cards">
1376
- ${metricCard("Reliability", formatPercent(summary.successRate), `${summary.success} success \xB7 ${summary.timeout} timeout \xB7 ${summary.error} error`, healthTone)}
1377
- ${metricCard("Avg duration", formatMs(summary.avgDuration), `p95 ${formatMs(summary.p95Duration)}`)}
1378
- ${metricCard("LLM calls", compactNumber(summary.totalCalls), `${compactNumber(summary.totalInput)} input \xB7 ${compactNumber(summary.totalOutput)} output`)}
1379
- ${metricCard("Tokens saved", compactNumber(summary.totalSaved), `avg score ${summary.avgScore || "\u2014"}`)}
1380
- </section>
1381
- <section class="layout">
1382
- <div class="panel"><h2>Duration trend <span class="muted">last ${Math.min(entries.length, 80)} runs</span></h2>${sparkline(entries.slice(-80).map(durationOf))}</div>
1383
- <div class="panel"><h2>Latest phase timings</h2><div class="table-wrap"><table><thead><tr><th>Phase</th><th class="num">Duration</th><th>Share</th></tr></thead><tbody>${phaseRows(latest)}</tbody></table></div></div>
1384
- </section>
1385
- <section class="two section">
1386
- <div class="panel"><h2>Profile comparison</h2><div class="table-wrap"><table><thead><tr><th>Profile</th><th class="num">Runs</th><th class="num">Avg</th><th class="num">p95</th><th class="num">Score</th><th class="num">Calls</th><th class="num">Saved</th><th>Reliability</th></tr></thead><tbody>${comparisonRows(profileGroups)}</tbody></table></div></div>
1387
- <div class="panel"><h2>Provider comparison</h2><div class="table-wrap"><table><thead><tr><th>Provider</th><th class="num">Runs</th><th class="num">Avg</th><th class="num">p95</th><th class="num">Score</th><th class="num">Calls</th><th class="num">Saved</th><th>Reliability</th></tr></thead><tbody>${comparisonRows(providerGroups)}</tbody></table></div></div>
1388
- </section>
1389
- <section class="panel section"><h2>Recent runs</h2><div class="table-wrap"><table><thead><tr><th>Time</th><th>Profile</th><th>Provider</th><th>Method</th><th>Run</th><th>Status</th><th class="num">Duration</th><th class="num">Score</th><th class="num">Saved</th><th class="num">Calls</th><th class="num">Ext cache</th><th>Reason</th></tr></thead><tbody>${recentRunRows(entries)}</tbody></table></div></section>
1390
- <section class="section"><h2>Raw text report</h2><pre>${escapeHtml(report)}</pre></section>
1391
- </main></body></html>`;
1392
- const fp = metricsDashboardFile();
1393
- atomicWriteFileSync(fp, html);
1394
- return fp;
1395
- } catch (e) {
1396
- warn("writeMetricsDashboard failed", e);
1397
- return null;
1398
- }
1399
- }
1400
1208
  var INTERNAL_PHASES, EXTRACTION_CACHE_TTL_MS, EXTRACTION_CACHE_PRUNE_MAX_AGE_MS, _extractionPruneInFlight = false;
1401
1209
  var init_cache = __esm(() => {
1402
1210
  init_tokens();
@@ -1427,6 +1235,8 @@ function metricDuration(entry) {
1427
1235
  function metricMs(ms) {
1428
1236
  if (!Number.isFinite(ms) || ms <= 0)
1429
1237
  return "0ms";
1238
+ if (ms >= 60000)
1239
+ return (ms / 60000).toFixed(ms >= 600000 ? 0 : 1) + "m";
1430
1240
  return ms >= 1000 ? (ms / 1000).toFixed(ms >= 1e4 ? 0 : 1) + "s" : Math.round(ms) + "ms";
1431
1241
  }
1432
1242
  function clampRatio(value) {
@@ -3122,6 +2932,223 @@ function buildExplorationContext(report) {
3122
2932
  init_tokens();
3123
2933
  init_cache();
3124
2934
 
2935
+ // src/ui/metrics-report.ts
2936
+ init_paths();
2937
+ init_fs();
2938
+ init_logger();
2939
+ init_cache();
2940
+ function escapeHtml(value) {
2941
+ return String(value ?? "").replace(/[&<>\"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] ?? c);
2942
+ }
2943
+ function percentile(values, p) {
2944
+ if (!values.length)
2945
+ return 0;
2946
+ const sorted = [...values].sort((a, b) => a - b);
2947
+ return sorted[Math.min(sorted.length - 1, Math.max(0, Math.floor(p / 100 * sorted.length)))];
2948
+ }
2949
+ function average(values) {
2950
+ return values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : 0;
2951
+ }
2952
+ function compactNumber(value) {
2953
+ return new Intl.NumberFormat("en", { notation: Math.abs(value) >= 1e4 ? "compact" : "standard", maximumFractionDigits: 1 }).format(value);
2954
+ }
2955
+ function statusClass(status) {
2956
+ if (status === "timeout" || status === "error")
2957
+ return "bad";
2958
+ if (status === "dry-run")
2959
+ return "warn";
2960
+ return "good";
2961
+ }
2962
+ function statusLabel(status) {
2963
+ return status ?? "success";
2964
+ }
2965
+ function badge(status) {
2966
+ const label = statusLabel(status);
2967
+ return `<span class="badge ${statusClass(label)}">${escapeHtml(label)}</span>`;
2968
+ }
2969
+ function summarizeDashboard(entries) {
2970
+ const durations = entries.map(metricDuration).filter(Boolean);
2971
+ const success = entries.filter((e) => statusLabel(e.status) === "success").length;
2972
+ const timeout = entries.filter((e) => e.status === "timeout").length;
2973
+ const error = entries.filter((e) => e.status === "error").length;
2974
+ const dryRun = entries.filter((e) => e.status === "dry-run").length;
2975
+ const scored = entries.map((e) => e.verificationScore).filter((v) => typeof v === "number");
2976
+ return {
2977
+ runs: entries.length,
2978
+ success,
2979
+ timeout,
2980
+ error,
2981
+ dryRun,
2982
+ successRate: entries.length ? success / entries.length : 0,
2983
+ avgDuration: Math.round(average(durations)),
2984
+ p95Duration: percentile(durations, 95),
2985
+ totalCalls: entries.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
2986
+ totalInput: entries.reduce((sum, e) => sum + (e.totalInput ?? 0), 0),
2987
+ totalOutput: entries.reduce((sum, e) => sum + (e.totalOutput ?? 0), 0),
2988
+ totalSaved: entries.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
2989
+ avgScore: Math.round(average(scored))
2990
+ };
2991
+ }
2992
+ function groupMetrics(entries, keyFn) {
2993
+ const groups = new Map;
2994
+ for (const entry of entries) {
2995
+ const key = keyFn(entry);
2996
+ if (!key)
2997
+ continue;
2998
+ groups.set(key, [...groups.get(key) ?? [], entry]);
2999
+ }
3000
+ return [...groups.entries()].map(([name, group]) => {
3001
+ const durations = group.map(metricDuration).filter(Boolean);
3002
+ const scores = group.map((e) => e.verificationScore).filter((v) => typeof v === "number");
3003
+ const failures = group.filter((e) => e.status === "timeout" || e.status === "error").length;
3004
+ return {
3005
+ name,
3006
+ runs: group.length,
3007
+ avgDuration: Math.round(average(durations)),
3008
+ p95Duration: percentile(durations, 95),
3009
+ avgScore: Math.round(average(scores)),
3010
+ totalSaved: group.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
3011
+ totalCalls: group.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
3012
+ errorRate: group.length ? failures / group.length : 0
3013
+ };
3014
+ }).sort((a, b) => b.runs - a.runs || a.name.localeCompare(b.name));
3015
+ }
3016
+ function progressBar(value, label = metricPct(value)) {
3017
+ const pct = Math.max(0, Math.min(100, Math.round(value * 100)));
3018
+ return `<div class="meter" title="${escapeHtml(label)}"><span style="width:${pct}%"></span></div>`;
3019
+ }
3020
+ function sparkline(values) {
3021
+ const nums = values.filter((v) => Number.isFinite(v));
3022
+ if (nums.length < 2)
3023
+ return `<div class="empty">Need at least two runs for trend</div>`;
3024
+ const width = 520;
3025
+ const height = 120;
3026
+ const min = Math.min(...nums);
3027
+ const max = Math.max(...nums);
3028
+ const span = Math.max(1, max - min);
3029
+ const points = nums.map((value, i) => {
3030
+ const x = i / Math.max(1, nums.length - 1) * width;
3031
+ const y = height - (value - min) / span * (height - 18) - 9;
3032
+ return `${x.toFixed(1)},${y.toFixed(1)}`;
3033
+ }).join(" ");
3034
+ const last = nums[nums.length - 1];
3035
+ return `<svg class="spark" viewBox="0 0 ${width} ${height}" role="img" aria-label="Duration trend"><polyline points="${points}" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><circle cx="${width}" cy="${(height - (last - min) / span * (height - 18) - 9).toFixed(1)}" r="4" fill="currentColor"/><text x="0" y="14">${escapeHtml(metricMs(max))}</text><text x="0" y="${height - 4}">${escapeHtml(metricMs(min))}</text></svg>`;
3036
+ }
3037
+ function metricCard(label, value, detail, tone = "neutral") {
3038
+ return `<article class="card ${tone}"><div class="label">${escapeHtml(label)}</div><div class="value">${escapeHtml(value)}</div><div class="detail">${escapeHtml(detail)}</div></article>`;
3039
+ }
3040
+ function comparisonRows(groups) {
3041
+ if (!groups.length)
3042
+ return `<tr><td colspan="8" class="empty">No data yet</td></tr>`;
3043
+ return groups.map((group) => `<tr>
3044
+ <td><strong>${escapeHtml(group.name)}</strong></td>
3045
+ <td class="num">${metricNum(group.runs)}</td>
3046
+ <td class="num">${escapeHtml(metricMs(group.avgDuration))}</td>
3047
+ <td class="num">${escapeHtml(metricMs(group.p95Duration))}</td>
3048
+ <td class="num">${group.avgScore ? metricNum(group.avgScore) : "\u2014"}</td>
3049
+ <td class="num">${metricNum(group.totalCalls)}</td>
3050
+ <td class="num">${metricNum(group.totalSaved)}</td>
3051
+ <td>${progressBar(1 - group.errorRate, metricPct(1 - group.errorRate) + " reliable")}</td>
3052
+ </tr>`).join(`
3053
+ `);
3054
+ }
3055
+ function phaseRows(entry) {
3056
+ const timings = entry?.phaseTimings ?? [];
3057
+ if (!timings.length)
3058
+ return `<tr><td colspan="3" class="empty">No phase timings yet</td></tr>`;
3059
+ const total = timings.reduce((sum, phase) => sum + phase.durationMs, 0) || 1;
3060
+ return timings.map((phase) => `<tr>
3061
+ <td>${escapeHtml(phase.phase)}</td>
3062
+ <td class="num">${escapeHtml(metricMs(phase.durationMs))}</td>
3063
+ <td>${progressBar(phase.durationMs / total, metricPct(phase.durationMs / total))}</td>
3064
+ </tr>`).join(`
3065
+ `);
3066
+ }
3067
+ function recentRunRows(entries) {
3068
+ if (!entries.length)
3069
+ return `<tr><td colspan="12" class="empty">No runs recorded yet</td></tr>`;
3070
+ return entries.slice(-80).reverse().map((entry) => `<tr>
3071
+ <td class="mono small">${escapeHtml(entry.ts)}</td>
3072
+ <td>${escapeHtml(entry.profile)}</td>
3073
+ <td>${escapeHtml(entry.provider ?? entry.model?.split("/")[0])}</td>
3074
+ <td>${escapeHtml(entry.method)}</td>
3075
+ <td>${escapeHtml(entry.runType)}</td>
3076
+ <td>${badge(entry.status)}</td>
3077
+ <td class="num">${escapeHtml(metricMs(metricDuration(entry)))}</td>
3078
+ <td class="num">${typeof entry.verificationScore === "number" ? metricNum(entry.verificationScore) : "\u2014"}</td>
3079
+ <td class="num">${typeof entry.tokensSaved === "number" ? metricNum(entry.tokensSaved) : "\u2014"}</td>
3080
+ <td class="num">${metricNum(entry.totalCalls ?? 0)}</td>
3081
+ <td class="num">${typeof entry.extractionCacheHitRate === "number" ? metricPct(entry.extractionCacheHitRate) : "\u2014"}</td>
3082
+ <td class="mono small reason">${escapeHtml(entry.fallbackReason ?? entry.extractionCacheMissReason ?? "")}</td>
3083
+ </tr>`).join(`
3084
+ `);
3085
+ }
3086
+ function dashboardCss() {
3087
+ return `:root{color-scheme:dark;--bg:#08111f;--surface:#0f172a;--surface2:#111c33;--card:#111827;--text:#e5edf8;--muted:#8fa3bf;--line:#24324a;--accent:#60a5fa;--good:#22c55e;--bad:#fb7185;--warn:#fbbf24;--shadow:0 18px 50px rgba(0,0,0,.28)}@media(prefers-color-scheme:light){:root{color-scheme:light;--bg:#f4f7fb;--surface:#ffffff;--surface2:#f8fafc;--card:#ffffff;--text:#0f172a;--muted:#64748b;--line:#e2e8f0;--shadow:0 18px 50px rgba(15,23,42,.08)}}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at top left,rgba(96,165,250,.20),transparent 34rem),var(--bg);color:var(--text);font:14px/1.5 Inter,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}main{max-width:1280px;margin:0 auto;padding:32px}header{display:flex;justify-content:space-between;gap:20px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:var(--accent);font-weight:700;text-transform:uppercase;letter-spacing:.08em;font-size:12px}h1{font-size:32px;line-height:1.1;margin:6px 0 6px}.muted,.detail{color:var(--muted)}.cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin:20px 0 22px}.card{background:linear-gradient(180deg,rgba(255,255,255,.035),transparent),var(--card);border:1px solid var(--line);border-radius:18px;padding:16px;box-shadow:var(--shadow)}.card.good{border-color:rgba(34,197,94,.45)}.card.warn{border-color:rgba(251,191,36,.45)}.card.bad{border-color:rgba(251,113,133,.5)}.label{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.08em;font-weight:700}.value{font-size:28px;font-weight:800;margin-top:6px}.layout{display:grid;grid-template-columns:1.15fr .85fr;gap:18px}.panel{background:var(--surface);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);overflow:hidden}.panel h2{display:flex;align-items:center;justify-content:space-between;margin:0;padding:15px 18px;background:linear-gradient(180deg,rgba(255,255,255,.035),transparent),var(--surface2);font-size:15px}.table-wrap{overflow:auto;max-height:560px}table{border-collapse:separate;border-spacing:0;width:100%}th,td{border-bottom:1px solid var(--line);padding:9px 11px;text-align:left;vertical-align:middle;white-space:nowrap}th{position:sticky;top:0;z-index:1;background:var(--surface2);color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em}tr:hover td{background:rgba(96,165,250,.06)}.num{text-align:right}.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.small{font-size:12px}.reason{max-width:280px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.badge{display:inline-flex;align-items:center;border-radius:999px;padding:3px 9px;font-size:12px;font-weight:800}.badge.good{background:rgba(34,197,94,.14);color:var(--good)}.badge.bad{background:rgba(251,113,133,.16);color:var(--bad)}.badge.warn{background:rgba(251,191,36,.16);color:var(--warn)}.meter{height:8px;background:rgba(148,163,184,.22);border-radius:99px;min-width:96px;overflow:hidden}.meter span{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--accent),var(--good))}.spark{width:100%;height:160px;color:var(--accent);padding:18px}.spark text{fill:var(--muted);font-size:12px}.empty{padding:18px;color:var(--muted);text-align:center}pre{white-space:pre-wrap;background:var(--surface);border:1px solid var(--line);border-radius:18px;padding:16px;overflow:auto}.section{margin-top:18px}.two{display:grid;grid-template-columns:1fr 1fr;gap:18px}@media(max-width:960px){main{padding:20px}.cards,.layout,.two{grid-template-columns:1fr}header{display:block}th,td{padding:8px}.value{font-size:24px}}`;
3088
+ }
3089
+ function buildMetricsReport(entries = readMetricsLog(100)) {
3090
+ if (!entries.length)
3091
+ return "No smart-compact metrics recorded yet.";
3092
+ const summary = summarizeDashboard(entries);
3093
+ const byProfile = groupMetrics(entries, (e) => e.profile);
3094
+ const byProvider = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
3095
+ const summarizeGroup = (group) => "- " + group.name + ": n=" + group.runs + ", avg=" + group.avgDuration + "ms, p95=" + group.p95Duration + "ms, score=" + group.avgScore + ", saved=" + group.totalSaved + "t, reliability=" + metricPct(1 - group.errorRate);
3096
+ const extractionCacheRuns = entries.filter((e) => typeof e.extractionCacheHitRate === "number");
3097
+ const extractionCacheAvg = average(extractionCacheRuns.map((e) => e.extractionCacheHitRate ?? 0));
3098
+ return [
3099
+ "# Smart Compact Metrics",
3100
+ "",
3101
+ "Runs: " + summary.runs + " (success " + summary.success + ", dry-run " + summary.dryRun + ", timeout " + summary.timeout + ", error " + summary.error + ")",
3102
+ "Reliability: " + metricPct(summary.successRate),
3103
+ "Latency: avg " + summary.avgDuration + "ms, p95 " + summary.p95Duration + "ms",
3104
+ "LLM calls: " + summary.totalCalls + ", input " + summary.totalInput + "t, output " + summary.totalOutput + "t",
3105
+ "Extraction cache: avg " + (extractionCacheRuns.length ? metricPct(extractionCacheAvg) : "\u2014") + " across " + extractionCacheRuns.length + " measured run(s)",
3106
+ "Tokens saved: " + summary.totalSaved + "t, average verification score: " + summary.avgScore,
3107
+ "",
3108
+ "## Profile comparison",
3109
+ ...byProfile.map(summarizeGroup),
3110
+ "",
3111
+ "## Provider comparison",
3112
+ ...byProvider.map(summarizeGroup)
3113
+ ].join(`
3114
+ `);
3115
+ }
3116
+ function writeMetricsDashboard(entries = readMetricsLog(200)) {
3117
+ try {
3118
+ const summary = summarizeDashboard(entries);
3119
+ const latest = entries[entries.length - 1];
3120
+ const report = buildMetricsReport(entries);
3121
+ const profileGroups = groupMetrics(entries, (e) => e.profile);
3122
+ const providerGroups = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
3123
+ const healthTone = summary.error + summary.timeout > 0 ? "warn" : "good";
3124
+ const html = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Smart Compact Metrics</title><style>${dashboardCss()}</style></head><body><main>
3125
+ <header><div><div class="eyebrow">pi-smart-compact</div><h1>Operational Metrics</h1><div class="muted">Generated ${escapeHtml(new Date().toISOString())} \xB7 ${metricNum(entries.length)} recent runs \xB7 local file dashboard</div></div><div>${badge(latest?.status)} ${latest ? `<span class="muted">latest ${escapeHtml(latest.profile ?? "unknown")}</span>` : ""}</div></header>
3126
+ <section class="cards">
3127
+ ${metricCard("Reliability", metricPct(summary.successRate), `${summary.success} success \xB7 ${summary.timeout} timeout \xB7 ${summary.error} error`, healthTone)}
3128
+ ${metricCard("Avg duration", metricMs(summary.avgDuration), `p95 ${metricMs(summary.p95Duration)}`)}
3129
+ ${metricCard("LLM calls", compactNumber(summary.totalCalls), `${compactNumber(summary.totalInput)} input \xB7 ${compactNumber(summary.totalOutput)} output`)}
3130
+ ${metricCard("Tokens saved", compactNumber(summary.totalSaved), `avg score ${summary.avgScore || "\u2014"}`)}
3131
+ </section>
3132
+ <section class="layout">
3133
+ <div class="panel"><h2>Duration trend <span class="muted">last ${Math.min(entries.length, 80)} runs</span></h2>${sparkline(entries.slice(-80).map(metricDuration))}</div>
3134
+ <div class="panel"><h2>Latest phase timings</h2><div class="table-wrap"><table><thead><tr><th>Phase</th><th class="num">Duration</th><th>Share</th></tr></thead><tbody>${phaseRows(latest)}</tbody></table></div></div>
3135
+ </section>
3136
+ <section class="two section">
3137
+ <div class="panel"><h2>Profile comparison</h2><div class="table-wrap"><table><thead><tr><th>Profile</th><th class="num">Runs</th><th class="num">Avg</th><th class="num">p95</th><th class="num">Score</th><th class="num">Calls</th><th class="num">Saved</th><th>Reliability</th></tr></thead><tbody>${comparisonRows(profileGroups)}</tbody></table></div></div>
3138
+ <div class="panel"><h2>Provider comparison</h2><div class="table-wrap"><table><thead><tr><th>Provider</th><th class="num">Runs</th><th class="num">Avg</th><th class="num">p95</th><th class="num">Score</th><th class="num">Calls</th><th class="num">Saved</th><th>Reliability</th></tr></thead><tbody>${comparisonRows(providerGroups)}</tbody></table></div></div>
3139
+ </section>
3140
+ <section class="panel section"><h2>Recent runs</h2><div class="table-wrap"><table><thead><tr><th>Time</th><th>Profile</th><th>Provider</th><th>Method</th><th>Run</th><th>Status</th><th class="num">Duration</th><th class="num">Score</th><th class="num">Saved</th><th class="num">Calls</th><th class="num">Ext cache</th><th>Reason</th></tr></thead><tbody>${recentRunRows(entries)}</tbody></table></div></section>
3141
+ <section class="section"><h2>Raw text report</h2><pre>${escapeHtml(report)}</pre></section>
3142
+ </main></body></html>`;
3143
+ const fp = metricsDashboardFile();
3144
+ atomicWriteFileSync(fp, html);
3145
+ return fp;
3146
+ } catch (e) {
3147
+ warn("writeMetricsDashboard failed", e);
3148
+ return null;
3149
+ }
3150
+ }
3151
+
3125
3152
  // src/app/run-smart-compact.ts
3126
3153
  init_overlays();
3127
3154
  init_logger();
@@ -3501,6 +3528,7 @@ function pruneRedundant(msgs, precomputedTcIdx) {
3501
3528
  }
3502
3529
  const tcIdx = ensuredIndex;
3503
3530
  const keep = new Set(msgs.map((_, i2) => i2));
3531
+ const removedToolCallIds = new Set;
3504
3532
  const reasonMap = new Map;
3505
3533
  const readIndices = new Map;
3506
3534
  for (let i2 = 0;i2 < msgs.length; i2++) {
@@ -3518,10 +3546,10 @@ function pruneRedundant(msgs, precomputedTcIdx) {
3518
3546
  }
3519
3547
  for (const [fp, indices] of readIndices) {
3520
3548
  for (let j = 0;j < indices.length - 1; j++) {
3549
+ const toolCallId = msgs[indices[j]].toolCallId ?? "";
3521
3550
  keep.delete(indices[j]);
3522
- const tc = tcIdx.get(msgs[indices[j]].toolCallId ?? "");
3523
- if (tc)
3524
- keep.delete(tc.msgIndex);
3551
+ if (tcIdx.has(toolCallId))
3552
+ removedToolCallIds.add(toolCallId);
3525
3553
  }
3526
3554
  if (indices.length > 1) {
3527
3555
  reasonMap.set("Duplicate file reads", (reasonMap.get("Duplicate file reads") ?? 0) + indices.length - 1);
@@ -3531,8 +3559,9 @@ function pruneRedundant(msgs, precomputedTcIdx) {
3531
3559
  for (let i2 = 0;i2 < msgs.length; i2++) {
3532
3560
  if (msgs[i2].role !== "toolResult" || !msgs[i2].isError)
3533
3561
  continue;
3534
- const tc = tcIdx.get(msgs[i2].toolCallId ?? "");
3535
- failedToolResults.push({ index: i2, tool: tc?.name ?? "unknown", tcIndex: tc?.msgIndex ?? -1 });
3562
+ const toolCallId = msgs[i2].toolCallId ?? "";
3563
+ const tc = tcIdx.get(toolCallId);
3564
+ failedToolResults.push({ index: i2, tool: tc?.name ?? "unknown", toolCallId });
3536
3565
  }
3537
3566
  let i = 0;
3538
3567
  while (i < failedToolResults.length) {
@@ -3544,8 +3573,8 @@ function pruneRedundant(msgs, precomputedTcIdx) {
3544
3573
  if (j - i >= 3) {
3545
3574
  for (let k = i + 1;k < j - 1; k++) {
3546
3575
  keep.delete(failedToolResults[k].index);
3547
- if (failedToolResults[k].tcIndex >= 0)
3548
- keep.delete(failedToolResults[k].tcIndex);
3576
+ if (tcIdx.has(failedToolResults[k].toolCallId))
3577
+ removedToolCallIds.add(failedToolResults[k].toolCallId);
3549
3578
  }
3550
3579
  reasonMap.set("Collapsed error chains", (reasonMap.get("Collapsed error chains") ?? 0) + (j - i - 2));
3551
3580
  }
@@ -3583,22 +3612,57 @@ function pruneRedundant(msgs, precomputedTcIdx) {
3583
3612
  const half = Math.floor(MAX_TOOL_OUTPUT_CHARS / 2);
3584
3613
  for (let idx = 0;idx < msgs.length; idx++) {
3585
3614
  const m = msgs[idx];
3586
- const text = extractText(m.content);
3587
- if (text.length > 0)
3588
- originalTokens += estimateTokens(text);
3615
+ const originalText = extractText(m.content);
3616
+ if (originalText.length > 0)
3617
+ originalTokens += estimateTokens(originalText);
3589
3618
  if (!keep.has(idx))
3590
3619
  continue;
3591
- const protectFromTruncation = m.role === "toolResult" && text.length > MAX_TOOL_OUTPUT_CHARS && text.length < ERROR_SCAN_MAX_LEN && LIKELY_ERROR_RE.test(text);
3592
- if (m.role === "toolResult" && text.length > MAX_TOOL_OUTPUT_CHARS && !protectFromTruncation) {
3620
+ let keptMessage = m;
3621
+ if (m.role === "assistant" && removedToolCallIds.size > 0 && Array.isArray(m.content)) {
3622
+ let changed = false;
3623
+ const content = [];
3624
+ for (const block of m.content) {
3625
+ if (!isToolCallBlock(block)) {
3626
+ content.push(block);
3627
+ continue;
3628
+ }
3629
+ if (block.name === "multi_tool_use.parallel" && Array.isArray(block.arguments?.tool_uses)) {
3630
+ const tools = block.arguments.tool_uses;
3631
+ const retained = tools.filter((tool, toolIndex) => {
3632
+ const id = typeof tool.id === "string" ? tool.id : block.id ? block.id + "_" + toolIndex : "mtu_" + idx + "_" + toolIndex;
3633
+ return !removedToolCallIds.has(id);
3634
+ });
3635
+ if (retained.length !== tools.length)
3636
+ changed = true;
3637
+ if (retained.length > 0) {
3638
+ content.push(retained.length === tools.length ? block : { ...block, arguments: { ...block.arguments, tool_uses: retained } });
3639
+ }
3640
+ continue;
3641
+ }
3642
+ if (block.id && removedToolCallIds.has(block.id)) {
3643
+ changed = true;
3644
+ continue;
3645
+ }
3646
+ content.push(block);
3647
+ }
3648
+ if (changed) {
3649
+ if (content.length === 0)
3650
+ continue;
3651
+ keptMessage = { ...m, content };
3652
+ }
3653
+ }
3654
+ const text = extractText(keptMessage.content);
3655
+ const protectFromTruncation = keptMessage.role === "toolResult" && text.length > MAX_TOOL_OUTPUT_CHARS && text.length < ERROR_SCAN_MAX_LEN && LIKELY_ERROR_RE.test(text);
3656
+ if (keptMessage.role === "toolResult" && text.length > MAX_TOOL_OUTPUT_CHARS && !protectFromTruncation) {
3593
3657
  const head = text.slice(0, half);
3594
3658
  const tail = text.slice(-half);
3595
3659
  const truncated = head + `
3596
3660
  ... [truncated ` + (text.length - MAX_TOOL_OUTPUT_CHARS) + ` chars] ...
3597
3661
  ` + tail;
3598
- finalMsgs.push({ ...m, content: [{ type: "text", text: truncated }] });
3662
+ finalMsgs.push({ ...keptMessage, content: [{ type: "text", text: truncated }] });
3599
3663
  prunedTokens += estimateTokens(truncated);
3600
3664
  } else {
3601
- finalMsgs.push(m);
3665
+ finalMsgs.push(keptMessage);
3602
3666
  if (text.length > 0)
3603
3667
  prunedTokens += estimateTokens(text);
3604
3668
  }
@@ -3884,7 +3948,6 @@ function extractWithCache(rc) {
3884
3948
  rc.vlog("Extraction cache ignored: legacy entry lacks keptEntryIds/keptEntryIdsFp");
3885
3949
  }
3886
3950
  }
3887
- const prunedTcIdx = buildToolCallIndex(rc.llmMessages);
3888
3951
  if (cacheUsable && cachedExt) {
3889
3952
  const newMsgs = rc.llmMessages.slice(cachedExt.messageCount);
3890
3953
  const deltaTcIdx = buildToolCallIndex(newMsgs);
@@ -3895,6 +3958,7 @@ function extractWithCache(rc) {
3895
3958
  missReason = undefined;
3896
3959
  recordExtractionCacheHit(rc.services);
3897
3960
  } else {
3961
+ const prunedTcIdx = buildToolCallIndex(rc.llmMessages);
3898
3962
  extraction = extractStructured(rc.llmMessages, rc.profileCfg, prunedTcIdx);
3899
3963
  rc.notify("Phase 1 Full: " + extraction.modifiedFiles.length + " files, " + extraction.errors.length + " errors", "info");
3900
3964
  rc.vlog("Full extraction \u2014 " + rc.llmMessages.length + " messages, tier=" + rc.tier);
@@ -5342,6 +5406,9 @@ function computeDelta(prev, current) {
5342
5406
  previousGoal: goalChanged ? prev.goal : null
5343
5407
  };
5344
5408
  }
5409
+ function hasDeltaChanges(delta) {
5410
+ return delta.goalChanged || delta.removedDecisions.length > 0 || delta.resolvedLoops.length > 0 || delta.newLoops.length > 0 || delta.newDecisions.length > 0 || delta.resolvedErrors.length > 0 || delta.newErrors.length > 0 || delta.newModifiedFiles.length > 0;
5411
+ }
5345
5412
  function formatDeltaSection(delta) {
5346
5413
  const lines = ["## Changes Since Last Compaction", ""];
5347
5414
  if (delta.goalChanged) {
@@ -5359,6 +5426,9 @@ function formatDeltaSection(delta) {
5359
5426
  if (delta.newDecisions.length) {
5360
5427
  lines.push("- **New decisions**: " + delta.newDecisions.map((s) => s.slice(0, TRUNC.SNIPPET)).join("; "));
5361
5428
  }
5429
+ if (delta.removedDecisions.length) {
5430
+ lines.push("- **Removed decisions**: " + delta.removedDecisions.map((s) => "~~" + s.slice(0, TRUNC.SNIPPET) + "~~").join("; "));
5431
+ }
5362
5432
  if (delta.resolvedErrors.length) {
5363
5433
  lines.push("- **Resolved errors**: " + delta.resolvedErrors.map((s) => s.slice(0, TRUNC.DECISION_DETAIL)).join("; "));
5364
5434
  }
@@ -5373,8 +5443,7 @@ function formatDeltaSection(delta) {
5373
5443
  `);
5374
5444
  }
5375
5445
  function injectDeltaSection(summary, delta) {
5376
- const hasChanges = delta.goalChanged || delta.resolvedLoops.length > 0 || delta.newLoops.length > 0 || delta.newDecisions.length > 0 || delta.newErrors.length > 0 || delta.newModifiedFiles.length > 0;
5377
- if (!hasChanges)
5446
+ if (!hasDeltaChanges(delta))
5378
5447
  return summary;
5379
5448
  const body = formatDeltaSection(delta).replace(/^## Changes Since Last Compaction\s*\n?/i, "").trim();
5380
5449
  if (!body)
@@ -5512,7 +5581,9 @@ function logDamageReport(sessionId, report, details) {
5512
5581
  signals: report.signals.length,
5513
5582
  summary: report.summary
5514
5583
  };
5515
- appendLineLocked(damageReportsFile(), JSON.stringify(entry));
5584
+ const logPath = damageReportsFile();
5585
+ appendLineLocked(logPath, JSON.stringify(entry));
5586
+ scheduleFileTailTrim(logPath, RUNTIME_LOG_MAX_BYTES);
5516
5587
  } catch (e) {
5517
5588
  warn("logDamageReport failed", e);
5518
5589
  }
@@ -5564,7 +5635,7 @@ function buildState(rc) {
5564
5635
  const prevState = loadCompactionState(rc.projectId);
5565
5636
  if (prevState) {
5566
5637
  const delta = computeDelta(prevState, compactionState);
5567
- if (delta.newLoops.length || delta.resolvedLoops.length || delta.newDecisions.length || delta.newErrors.length || delta.newModifiedFiles.length) {
5638
+ if (hasDeltaChanges(delta)) {
5568
5639
  summary = injectDeltaSection(summary, delta);
5569
5640
  rc.notify("Delta: " + delta.newLoops.length + " new loops, " + delta.resolvedLoops.length + " resolved, " + delta.newModifiedFiles.length + " new files", "info");
5570
5641
  }
@@ -5788,6 +5859,16 @@ async function runSmartCompact(opts) {
5788
5859
  }
5789
5860
  opts.isRunning.value = true;
5790
5861
  const base = makeBase(opts);
5862
+ const abortFromHost = () => {
5863
+ base.cancellation.timedOut = true;
5864
+ base.cancellation.controller.abort();
5865
+ };
5866
+ if (opts.abortSignal) {
5867
+ if (opts.abortSignal.aborted)
5868
+ abortFromHost();
5869
+ else
5870
+ opts.abortSignal.addEventListener("abort", abortFromHost, { once: true });
5871
+ }
5791
5872
  let finalRc = null;
5792
5873
  let failureSummaryFields = { profile: opts.profile };
5793
5874
  if (opts.cancellationOut) {
@@ -5805,6 +5886,8 @@ async function runSmartCompact(opts) {
5805
5886
  };
5806
5887
  }
5807
5888
  try {
5889
+ if (base.cancellation.signal.aborted)
5890
+ return;
5808
5891
  const prepared = await prepareRun(base);
5809
5892
  if (!prepared)
5810
5893
  return;
@@ -5882,6 +5965,7 @@ async function runSmartCompact(opts) {
5882
5965
  recordFailureMetrics(finalRc ?? base, err, failureSummaryFields);
5883
5966
  throw err;
5884
5967
  } finally {
5968
+ opts.abortSignal?.removeEventListener("abort", abortFromHost);
5885
5969
  if (base.cancellation.timeoutId)
5886
5970
  clearTimeout(base.cancellation.timeoutId);
5887
5971
  opts.isRunning.value = false;
@@ -6202,7 +6286,7 @@ function smartCompactExtension(pi) {
6202
6286
  dashboard: { type: "boolean", description: "Write a local HTML metrics dashboard and return its path." }
6203
6287
  }
6204
6288
  },
6205
- async execute(_id, params, _sig, _onUp, ctx) {
6289
+ async execute(_id, params, signal, _onUp, ctx) {
6206
6290
  const profile = params.profile === "light" || params.profile === "balanced" || params.profile === "aggressive" ? params.profile : undefined;
6207
6291
  const verbose = !!params.verbose;
6208
6292
  const dryRun = !!params.dry_run;
@@ -6232,7 +6316,7 @@ Dashboard: ` + fp : "") }], details: undefined };
6232
6316
  }
6233
6317
  try {
6234
6318
  const toolStart = Date.now();
6235
- await runSmartCompact({ ctx, summaryModel: sumModel, segModel: segModel ?? sumModel, profile: resolvedProfile, verbose, dryRun, pendingRef, isRunning, autoTriggered: true, skipCompact: true });
6319
+ await runSmartCompact({ ctx, summaryModel: sumModel, segModel: segModel ?? sumModel, profile: resolvedProfile, verbose, dryRun, pendingRef, isRunning, autoTriggered: true, skipCompact: true, abortSignal: signal });
6236
6320
  const toolSecs = ((Date.now() - toolStart) / 1000).toFixed(1);
6237
6321
  const staged = pendingRef.peek();
6238
6322
  if (staged) {
@@ -52,6 +52,10 @@ export declare function acquireLockSync(target: string): () => void;
52
52
  * `line` does not already end with one.
53
53
  */
54
54
  export declare function appendLineLocked(target: string, line: string): void;
55
+ /** Keep only complete trailing lines that fit within `maxBytes`. */
56
+ export declare function trimFileTailLocked(target: string, maxBytes: number): void;
57
+ /** Defer disk retention work to a later event-loop turn and coalesce writers. */
58
+ export declare function scheduleFileTailTrim(target: string, maxBytes: number): void;
55
59
  export declare function readJsonSync<T>(target: string): T | null;
56
60
  export declare function writeJsonSync(target: string, value: unknown, pretty?: boolean): void;
57
61
  //# sourceMappingURL=fs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/infra/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAYH,wDAAwD;AACxD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQ3C;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/D;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAWnF;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CA2D1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQnE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CASxD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,IAAI,CAElF"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/infra/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAYH,wDAAwD;AACxD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQ3C;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/D;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAWnF;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CA2D1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQnE;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBzE;AAID,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQ3E;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CASxD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,IAAI,CAElF"}
@@ -107,6 +107,6 @@ export declare function createServices(overrides?: Partial<SmartCompactServices>
107
107
  export declare function getDefaultServices(): SmartCompactServices;
108
108
  /** Swap the default container; tests use this to inject a clock/llm. */
109
109
  export declare function setDefaultServices(services: SmartCompactServices): void;
110
- /** Reset between runs equivalent to the old per-session `resetMetrics`. */
110
+ /** Reset the legacy/test default container. Production runs do not call this. */
111
111
  export declare function resetDefaultServices(): void;
112
112
  //# sourceMappingURL=services.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/infra/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6D;IACrF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,YAAY,KAAK,SAAc,EAAyB;IAExD,wEAAwE;IACxE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAKjD;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAElD;IAED,8DAA8D;IAC9D,IAAI,IAAI,MAAM,CAA8B;CAC7C;AAED;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,YAAY,UAAU,SAAqB,EAAmC;IAE9E,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAOlC;IAED,QAAQ,IAAI,aAAa,EAAE,CAA0B;IACrD,KAAK,IAAI,IAAI,CAAyB;IAEtC,OAAO,IAAI;QACT,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAC5D,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;KACjE,CAeA;CACF;AAED;;;;;GAKG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB,SAAS,IAAI,IAAI,CAAiB;IAClC,UAAU,IAAI,IAAI,CAAmB;IAErC,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAG5D;IAED,KAAK,IAAI,IAAI,CAAoC;CAClD;AAED,oCAAoC;AACpC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,gBAAgB,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,gFAAgF;IAChF,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAAG,oBAAoB,CAalG;AAgBD,wBAAgB,kBAAkB,IAAI,oBAAoB,CAAqB;AAE/E,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAyB;AAEjG,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,IAAI,CAAiC"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/infra/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6D;IACrF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,YAAY,KAAK,SAAc,EAAyB;IAExD,wEAAwE;IACxE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAKjD;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAElD;IAED,8DAA8D;IAC9D,IAAI,IAAI,MAAM,CAA8B;CAC7C;AAED;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,YAAY,UAAU,SAAqB,EAAmC;IAE9E,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAOlC;IAED,QAAQ,IAAI,aAAa,EAAE,CAA0B;IACrD,KAAK,IAAI,IAAI,CAAyB;IAEtC,OAAO,IAAI;QACT,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAC5D,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;KACjE,CAeA;CACF;AAED;;;;;GAKG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB,SAAS,IAAI,IAAI,CAAiB;IAClC,UAAU,IAAI,IAAI,CAAmB;IAErC,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAG5D;IAED,KAAK,IAAI,IAAI,CAAoC;CAClD;AAED,oCAAoC;AACpC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,gBAAgB,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,gFAAgF;IAChF,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,cAAc,CAAC,SAAS,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAAG,oBAAoB,CAalG;AAWD,wBAAgB,kBAAkB,IAAI,oBAAoB,CAAqB;AAE/E,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAyB;AAEjG,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,IAAI,CAAiC"}
@@ -20,13 +20,10 @@ export declare function fallbackExplorationReport(llmMessages: LlmMessage[]): Ex
20
20
  /**
21
21
  * Top-level exploration entry point.
22
22
  *
23
- * `services` is threaded in explicitly rather than reached via
24
- * `getDefaultServices()` because `runSmartCompact` resets the default
25
- * services container at the start of every run. Two concurrent pi sessions
26
- * sharing the Node process would otherwise stomp on each other's
27
- * `toolSupport` cache. The optional fallback to `getDefaultServices()` is
28
- * preserved for direct callers that haven't been migrated yet (legacy
29
- * tests, REPL use).
23
+ * `services` is threaded in explicitly so concurrent production runs never
24
+ * share mutable tool-support state. The optional `getDefaultServices()`
25
+ * fallback exists only for legacy direct callers and test/REPL use; the
26
+ * production orchestrator always supplies a run-scoped container.
30
27
  */
31
28
  export declare function exploreConversation(llmMessages: LlmMessage[], extraction: StructuredExtraction, model: Model<Api>, auth: {
32
29
  apiKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/phases/explore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAwC,MAAM,uBAAuB,CAAC;AAE9F,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAiB,MAAM,aAAa,CAAC;AAQtG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAQjE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAcvE;AAoCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAsFpI;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAmCjG;AA0CD,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CA2B9G;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAOtF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EAAE,SAAS,SAAyB,EACxD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,EAC/E,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CA+IhF;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAiB5B;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAsB5B"}
1
+ {"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/phases/explore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAwC,MAAM,uBAAuB,CAAC;AAE9F,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAiB,MAAM,aAAa,CAAC;AAQtG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAQjE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAcvE;AAoCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAsFpI;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAmCjG;AA0CD,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CA2B9G;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAOtF;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EAAE,SAAS,SAAyB,EACxD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,EAC/E,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CA+IhF;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAiB5B;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAC3D,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAC7E,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC7D,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAsB5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-format.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,aAAa,CAAC;AAE5E,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEjE;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG3C;AAMD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAE1E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEzE;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBhG;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAmBnH;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,EAAE,CAOzE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D"}
1
+ {"version":3,"file":"dashboard-format.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,aAAa,CAAC;AAE5E,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEjE;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAI3C;AAMD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAE1E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEzE;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBhG;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAmBnH;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,EAAE,CAOzE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D"}
@@ -0,0 +1,4 @@
1
+ import type { CompactMetricsEntry } from "../types.ts";
2
+ export declare function buildMetricsReport(entries?: CompactMetricsEntry[]): string;
3
+ export declare function writeMetricsDashboard(entries?: CompactMetricsEntry[]): string | null;
4
+ //# sourceMappingURL=metrics-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-report.d.ts","sourceRoot":"","sources":["../../src/ui/metrics-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA4LvD,wBAAgB,kBAAkB,CAAC,OAAO,wBAAsB,GAAG,MAAM,CAwBxE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,wBAAsB,GAAG,MAAM,GAAG,IAAI,CA+BlF"}
@@ -80,6 +80,4 @@ export declare function appendMetricsLog(sessionId: string, extra: Partial<Omit<
80
80
  * - Returned in chronological order (oldest -> newest within the window).
81
81
  */
82
82
  export declare function readMetricsLog(limit?: number): CompactMetricsEntry[];
83
- export declare function buildMetricsReport(entries?: CompactMetricsEntry[]): string;
84
- export declare function writeMetricsDashboard(entries?: CompactMetricsEntry[]): string | null;
85
83
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAuB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGtJ,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAQnF,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYrF,wBAAgB,SAAS,CACvB,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,EACzC,QAAQ,EAAE,oBAAoB,GAC7B,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAY5C;AAWD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAgC;AAEpH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAO9F;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAUlM;AAKD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAUD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAEzH;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAA+C;AAC7H,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAgD;AAE/H;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,IAAI,CAUN;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAS/E;AAwCD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAoCpI;AAGD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC,GAAG,SAAS,EACzK,QAAQ,EAAE,oBAAoB,GAC7B,IAAI,CAaN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAM,GAAG,mBAAmB,EAAE,CAkCjE;AA2MD,wBAAgB,kBAAkB,CAAC,OAAO,wBAAsB,GAAG,MAAM,CAwBxE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,wBAAsB,GAAG,MAAM,GAAG,IAAI,CAgClF"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGjI,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAKnF,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYrF,wBAAgB,SAAS,CACvB,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,EACzC,QAAQ,EAAE,oBAAoB,GAC7B,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAY5C;AAWD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAgC;AAEpH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAO9F;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAUlM;AAKD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAUD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAEzH;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAA+C;AAC7H,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAgD;AAE/H;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,IAAI,CAUN;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAS/E;AAwCD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAoCpI;AAGD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC,GAAG,SAAS,EACzK,QAAQ,EAAE,oBAAoB,GAC7B,IAAI,CAeN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAM,GAAG,mBAAmB,EAAE,CAkCjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"damage.d.ts","sourceRoot":"","sources":["../../src/utils/damage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAUnE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,gBAAgB,CAAC;IACrE,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB;mEAC+D;IAC/D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AASD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,UAAU,EAAE,EAC1B,OAAO,EAAE,mBAAmB,GAC3B,YAAY,CA2Fd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,mBAAmB,GAC3B,IAAI,CAeN;AAID;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAO9E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAKhE"}
1
+ {"version":3,"file":"damage.d.ts","sourceRoot":"","sources":["../../src/utils/damage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAUnE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,gBAAgB,CAAC;IACrE,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB;mEAC+D;IAC/D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AASD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,UAAU,EAAE,EAC1B,OAAO,EAAE,mBAAmB,GAC3B,YAAY,CA2Fd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,mBAAmB,GAC3B,IAAI,CAiBN;AAID;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAO9E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAKhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"pruning.d.ts","sourceRoot":"","sources":["../../src/utils/pruning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAmC,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGtF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD;;;;;;;OAOG;IACH,aAAa,EAAE,aAAa,CAAC;CAC9B;AAYD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,gBAAgB,CAAC,EAAE,aAAa,GAAG,aAAa,CAyKlG"}
1
+ {"version":3,"file":"pruning.d.ts","sourceRoot":"","sources":["../../src/utils/pruning.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAmC,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGtF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD;;;;;;;OAOG;IACH,aAAa,EAAE,aAAa,CAAC;CAC9B;AAYD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,gBAAgB,CAAC,EAAE,aAAa,GAAG,aAAa,CAoNlG"}
@@ -52,6 +52,7 @@ export interface CompactionDelta {
52
52
  previousGoal: string | null;
53
53
  }
54
54
  export declare function computeDelta(prev: CompactionState, current: CompactionState): CompactionDelta;
55
+ export declare function hasDeltaChanges(delta: CompactionDelta): boolean;
55
56
  /**
56
57
  * Format delta as Markdown section for injection into summary.
57
58
  */
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAe,MAAM,aAAa,CAAC;AAanH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAInF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAa7E;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,EAAE,MAAM,EAAE,GACxB,eAAe,CAsDjB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAYrF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAsD7F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+BjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CA4BlF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAapF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAU5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/utils/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAe,MAAM,aAAa,CAAC;AAanH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAInF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAa7E;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,oBAAoB,EAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EAAE,EACrB,eAAe,EAAE,MAAM,EAAE,GACxB,eAAe,CAsDjB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAYrF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAsD7F;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAS/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAkCjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,CAsBlF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAapF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAU5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE"}
package/docs/RELEASE.md CHANGED
@@ -17,6 +17,7 @@ Use this checklist before publishing `pi-smart-compact`.
17
17
  bun run typecheck
18
18
  bun test
19
19
  bun run build
20
+ bun run compat:pi
20
21
  ```
21
22
 
22
23
  The CI `verify` job runs the same validation on pull requests.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-smart-compact",
3
- "version": "7.19.0",
3
+ "version": "7.20.0",
4
4
  "description": "Verification-oriented smart compaction extension for Pi Coding Agent — deterministic extraction, exploration, synthesis, verification, metrics, and safety checks.",
5
5
  "packageManager": "bun@1.3.14",
6
6
  "license": "MIT",
@@ -47,6 +47,8 @@
47
47
  "prebuild": "bun run sync-version",
48
48
  "build": "rm -rf dist && mkdir dist && bun build ./src/index.ts --outdir ./dist --target bun --external '@earendil-works/*' --external 'typebox' && bun x tsc --emitDeclarationOnly --outDir dist",
49
49
  "test": "bun test",
50
+ "bench": "bun bench/hot-paths.bench.ts",
51
+ "compat:pi": "bun run scripts/check-pi-compat.ts",
50
52
  "typecheck": "bun x tsc --noEmit",
51
53
  "prepublishOnly": "bun run typecheck && bun test && bun run build"
52
54
  },
@@ -62,11 +64,7 @@
62
64
  },
63
65
  "devDependencies": {
64
66
  "@types/node": "^26.1.1",
65
- "@earendil-works/pi-ai": "^0.80.3",
66
- "@earendil-works/pi-coding-agent": "^0.80.3",
67
- "@earendil-works/pi-tui": "^0.80.3",
68
- "typebox": "^1.3.6",
69
- "typescript": "^7.0.0"
67
+ "typescript": "^7.0.2"
70
68
  },
71
69
  "publishConfig": {
72
70
  "access": "public"