pi-ghost-autocomplete 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +101 -6
  2. package/dist/bench-cli.js +81 -5
  3. package/dist/bench-cli.js.map +1 -1
  4. package/dist/bench.d.ts +130 -2
  5. package/dist/bench.d.ts.map +1 -1
  6. package/dist/bench.js +285 -4
  7. package/dist/bench.js.map +1 -1
  8. package/dist/cache.d.ts +124 -0
  9. package/dist/cache.d.ts.map +1 -0
  10. package/dist/cache.js +173 -0
  11. package/dist/cache.js.map +1 -0
  12. package/dist/candidate-rerank.d.ts +57 -0
  13. package/dist/candidate-rerank.d.ts.map +1 -0
  14. package/dist/candidate-rerank.js +78 -0
  15. package/dist/candidate-rerank.js.map +1 -0
  16. package/dist/config.d.ts +43 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +148 -18
  19. package/dist/config.js.map +1 -1
  20. package/dist/context-aggregator.d.ts +14 -5
  21. package/dist/context-aggregator.d.ts.map +1 -1
  22. package/dist/context-aggregator.js +38 -9
  23. package/dist/context-aggregator.js.map +1 -1
  24. package/dist/context-selector.d.ts +128 -0
  25. package/dist/context-selector.d.ts.map +1 -0
  26. package/dist/context-selector.js +300 -0
  27. package/dist/context-selector.js.map +1 -0
  28. package/dist/cycle-manager.d.ts +102 -0
  29. package/dist/cycle-manager.d.ts.map +1 -0
  30. package/dist/cycle-manager.js +168 -0
  31. package/dist/cycle-manager.js.map +1 -0
  32. package/dist/edit-history-ring.d.ts +148 -0
  33. package/dist/edit-history-ring.d.ts.map +1 -0
  34. package/dist/edit-history-ring.js +262 -0
  35. package/dist/edit-history-ring.js.map +1 -0
  36. package/dist/entropy-stop.d.ts +102 -0
  37. package/dist/entropy-stop.d.ts.map +1 -0
  38. package/dist/entropy-stop.js +141 -0
  39. package/dist/entropy-stop.js.map +1 -0
  40. package/dist/eval-dataset.d.ts +66 -0
  41. package/dist/eval-dataset.d.ts.map +1 -0
  42. package/dist/eval-dataset.js +127 -0
  43. package/dist/eval-dataset.js.map +1 -0
  44. package/dist/fast-path-engine.d.ts +286 -0
  45. package/dist/fast-path-engine.d.ts.map +1 -0
  46. package/dist/fast-path-engine.js +341 -0
  47. package/dist/fast-path-engine.js.map +1 -0
  48. package/dist/fuzzy-matcher.d.ts +8 -0
  49. package/dist/fuzzy-matcher.d.ts.map +1 -1
  50. package/dist/fuzzy-matcher.js +5 -3
  51. package/dist/fuzzy-matcher.js.map +1 -1
  52. package/dist/ghost-editor.d.ts +321 -4
  53. package/dist/ghost-editor.d.ts.map +1 -1
  54. package/dist/ghost-editor.js +1190 -144
  55. package/dist/ghost-editor.js.map +1 -1
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +81 -2
  59. package/dist/index.js.map +1 -1
  60. package/dist/keystroke-timer.d.ts +59 -0
  61. package/dist/keystroke-timer.d.ts.map +1 -0
  62. package/dist/keystroke-timer.js +94 -0
  63. package/dist/keystroke-timer.js.map +1 -0
  64. package/dist/metrics-builder.d.ts +71 -0
  65. package/dist/metrics-builder.d.ts.map +1 -0
  66. package/dist/metrics-builder.js +71 -0
  67. package/dist/metrics-builder.js.map +1 -0
  68. package/dist/metrics.d.ts +99 -2
  69. package/dist/metrics.d.ts.map +1 -1
  70. package/dist/metrics.js +131 -17
  71. package/dist/metrics.js.map +1 -1
  72. package/dist/path-matcher.d.ts +9 -0
  73. package/dist/path-matcher.d.ts.map +1 -1
  74. package/dist/path-matcher.js +5 -2
  75. package/dist/path-matcher.js.map +1 -1
  76. package/dist/profile-store.d.ts +82 -0
  77. package/dist/profile-store.d.ts.map +1 -0
  78. package/dist/profile-store.js +199 -0
  79. package/dist/profile-store.js.map +1 -0
  80. package/dist/profile.d.ts +185 -0
  81. package/dist/profile.d.ts.map +1 -0
  82. package/dist/profile.js +434 -0
  83. package/dist/profile.js.map +1 -0
  84. package/dist/providers/cloud-provider.d.ts +10 -1
  85. package/dist/providers/cloud-provider.d.ts.map +1 -1
  86. package/dist/providers/cloud-provider.js +71 -14
  87. package/dist/providers/cloud-provider.js.map +1 -1
  88. package/dist/providers/local-provider.d.ts +8 -1
  89. package/dist/providers/local-provider.d.ts.map +1 -1
  90. package/dist/providers/local-provider.js +15 -3
  91. package/dist/providers/local-provider.js.map +1 -1
  92. package/dist/providers/openai-compat-provider.d.ts +11 -1
  93. package/dist/providers/openai-compat-provider.d.ts.map +1 -1
  94. package/dist/providers/openai-compat-provider.js +93 -6
  95. package/dist/providers/openai-compat-provider.js.map +1 -1
  96. package/dist/providers/openai-completions-runner.d.ts +25 -1
  97. package/dist/providers/openai-completions-runner.d.ts.map +1 -1
  98. package/dist/providers/openai-completions-runner.js +109 -14
  99. package/dist/providers/openai-completions-runner.js.map +1 -1
  100. package/dist/providers/race.d.ts +58 -1
  101. package/dist/providers/race.d.ts.map +1 -1
  102. package/dist/providers/race.js +317 -4
  103. package/dist/providers/race.js.map +1 -1
  104. package/dist/providers/truncate.d.ts.map +1 -1
  105. package/dist/providers/truncate.js +20 -2
  106. package/dist/providers/truncate.js.map +1 -1
  107. package/dist/providers/types.d.ts +96 -1
  108. package/dist/providers/types.d.ts.map +1 -1
  109. package/dist/providers/types.js +59 -1
  110. package/dist/providers/types.js.map +1 -1
  111. package/dist/provisional-manager.d.ts +93 -0
  112. package/dist/provisional-manager.d.ts.map +1 -0
  113. package/dist/provisional-manager.js +98 -0
  114. package/dist/provisional-manager.js.map +1 -0
  115. package/dist/provisional.d.ts +150 -0
  116. package/dist/provisional.d.ts.map +1 -0
  117. package/dist/provisional.js +238 -0
  118. package/dist/provisional.js.map +1 -0
  119. package/dist/regret-tracker.d.ts +84 -0
  120. package/dist/regret-tracker.d.ts.map +1 -0
  121. package/dist/regret-tracker.js +145 -0
  122. package/dist/regret-tracker.js.map +1 -0
  123. package/dist/replay-cli.d.ts +13 -0
  124. package/dist/replay-cli.d.ts.map +1 -0
  125. package/dist/replay-cli.js +167 -0
  126. package/dist/replay-cli.js.map +1 -0
  127. package/dist/replay.d.ts +107 -0
  128. package/dist/replay.d.ts.map +1 -0
  129. package/dist/replay.js +225 -0
  130. package/dist/replay.js.map +1 -0
  131. package/dist/reranker.d.ts +181 -0
  132. package/dist/reranker.d.ts.map +1 -0
  133. package/dist/reranker.js +324 -0
  134. package/dist/reranker.js.map +1 -0
  135. package/dist/session-trie.d.ts +103 -0
  136. package/dist/session-trie.d.ts.map +1 -0
  137. package/dist/session-trie.js +280 -0
  138. package/dist/session-trie.js.map +1 -0
  139. package/dist/speculative.d.ts +74 -0
  140. package/dist/speculative.d.ts.map +1 -0
  141. package/dist/speculative.js +107 -0
  142. package/dist/speculative.js.map +1 -0
  143. package/dist/tool-summarize.d.ts +40 -0
  144. package/dist/tool-summarize.d.ts.map +1 -0
  145. package/dist/tool-summarize.js +245 -0
  146. package/dist/tool-summarize.js.map +1 -0
  147. package/dist/trie-sanitize.d.ts +22 -0
  148. package/dist/trie-sanitize.d.ts.map +1 -0
  149. package/dist/trie-sanitize.js +142 -0
  150. package/dist/trie-sanitize.js.map +1 -0
  151. package/dist/versions.d.ts +23 -0
  152. package/dist/versions.d.ts.map +1 -0
  153. package/dist/versions.js +31 -0
  154. package/dist/versions.js.map +1 -0
  155. package/package.json +3 -2
package/README.md CHANGED
@@ -14,8 +14,8 @@ Four provider modes ship in the same package:
14
14
  | --- | --- | --- | --- |
15
15
  | `cloud` | Groq / Cerebras / OpenRouter via `@earendil-works/pi-ai` | 150 ms | `groq/llama-3.1-8b-instant` |
16
16
  | `local` | Ollama / vLLM (OpenAI-compatible) | 400 ms | `qwen2.5-coder:1.5b` on `http://localhost:11434` |
17
- | `openai-compat` | Any OpenAI-compatible REST API (e.g. Mercury Edit) — available as a race member only | 150 ms | provider-specific |
18
- | `race` | Multiple providers in parallel; first valid response wins | 150 ms | per-member defaults |
17
+ | `openai-compat` | Any OpenAI-compatible REST API (e.g. Mercury Edit) — also used as the **default** provider | 150 ms | `mercury-edit-2` on `https://api.inceptionlabs.ai/v1` |
18
+ | `race` | Multiple providers in parallel; first valid response wins | 400 ms | per-member defaults |
19
19
 
20
20
  ## Getting started
21
21
 
@@ -70,7 +70,17 @@ Start typing at the prompt. A dim ghost text should appear to the right of your
70
70
  Run `/ghost` to confirm the extension loaded and see the active configuration:
71
71
 
72
72
  ```
73
- Pi Ghost: enabled · openai-compat=mercury-edit/mercury-edit-2 debounce=150ms
73
+ Pi Ghost: enabled
74
+ minChars=3
75
+ maxLineLength=240
76
+ mode=openai-compat
77
+ provider=mercury-edit
78
+ baseUrl=https://api.inceptionlabs.ai/v1
79
+ model=mercury-edit-2
80
+ apiKey=4e24***
81
+ debounceMs=150
82
+ maxTokens=64
83
+ maxRecentMessages=4
74
84
  ```
75
85
 
76
86
  ### 4. (Optional) Load the extension without installing
@@ -104,9 +114,37 @@ All knobs are environment variables — no extra config file needed:
104
114
  | `PI_GHOST_RECENT` | 4 (cloud) / 2 (local) | Number of recent user/assistant messages bundled as context |
105
115
  | `PI_GHOST_MIN_CHARS` | 3 | Minimum draft length before a prediction fires |
106
116
  | `PI_GHOST_MAX_LINE` | 240 | Predictions skipped if the current line exceeds this length |
117
+ | `PI_GHOST_TEMPERATURE` | `0` | Sampling temperature [0, 2]. `0` is best-effort deterministic; see note below |
118
+ | `PI_GHOST_MERCURY_PARALLEL_N` | `1` | Mercury FIM only: fire N parallel candidate completions for cycling. Requires `PI_GHOST_TEMPERATURE > 0` (downgrades silently to 1 at temp=0). Costs scale linearly with N |
119
+ | `PI_GHOST_CONTEXT_MAX_SCAN` | `200` | M6b: cap on the candidate pool scanned for relevance ranking |
120
+ | `PI_GHOST_CONTEXT_MAX_SELECTED` | `8` | M6b: max number of selected context entries |
121
+ | `PI_GHOST_CONTEXT_MAX_CHARS` | `4000` | M6b: total char budget for the selected context window |
122
+ | `PI_GHOST_CONTEXT_BM25_WEIGHT` | `0.3` | M6b: weight of BM25 content score vs recency (0=pure recency, 1=pure relevance) |
123
+ | `PI_GHOST_CONTEXT_TOOL_MAX` | `3` | M6c: max number of tool entries to include in selected context (0 disables tools entirely) |
124
+ | `PI_GHOST_ALLOW_INSECURE` | unset | Set to `1` to allow `http://` provider base URLs on non-localhost hosts. Off by default — API keys + prompts would be sent in clear |
125
+ | `PI_GHOST_PROFILE` | unset | Set to `off` to disable persistent profile capture + reranking. Default: enabled. Profile is local-only — see [Profile](#user-profile) below |
126
+ | `PI_GHOST_PROFILE_DECAY_DAYS` | `90` | Days before an unused profile record's weight halves during compaction |
127
+ | `PI_GHOST_PROVISIONAL` | unset | Set to `off` to disable the 150 ms provisional fallback. Default: enabled |
128
+ | `PI_GHOST_PROVISIONAL_PREFER` | unset | Set to `1`/`true`/`on`/`yes` to bias swap decisions toward the already-displayed provisional. Raises the LLM-vs-provisional swap margin from 0.1 to 0.3, reducing perceived flicker at the cost of recall. Bench reports a `flicker=X%` rate so this knob can be evaluated |
129
+ | `PI_GHOST_MIN_CONFIDENCE` | `0.55` | M3c.1: minimum reranker score for the top candidate to be shown. Range `[0, 1]`. Lower = more lenient, more ghosts shown |
130
+ | `PI_GHOST_RERANK_WEIGHTS` | `0.45,0.25,0.15,0.15` | M3c: reranker weights as `logprob,profileBias,lengthPrior,agreement`. Negative values clamped to 0 |
131
+ | `PI_GHOST_EVAL_CAPTURE` | unset | Set to `1` to capture committed prompts to `.pi/ghost-autocomplete/eval.jsonl` for offline replay (`pi-ghost-replay`). **Sensitive**: contains raw prompt text. Off by default |
132
+ | `PI_GHOST_REGRET_WINDOW_MS` | `3000` | After accept, window in ms during which a >50% deletion of inserted text flags the record `acceptRegret: true` |
133
+ | `PI_GHOST_SHORT_HOVER_MS` | `800` | Enhancement #3: a ghost dismissed within this many ms is flagged `shortHoverDismiss: true` and triggers a soft trie penalty (magnitude 0.25). Tunes the bench `short-hover` rate |
107
134
  | `PI_GHOST_METRICS` | unset | Set to `1` to write metrics to `.pi/ghost-autocomplete/metrics.jsonl` |
108
135
  | `PI_GHOST_DEBUG_LOG` | unset | Set to `1` to write debug records to `.pi/ghost-autocomplete/debug.jsonl` |
109
136
 
137
+ ### Note on `temperature=0`
138
+
139
+ `temperature=0` is the default and asks the provider for greedy decoding so
140
+ the same prefix produces the same completion. This is **best-effort, not
141
+ guaranteed**: vendors batch requests across users and kernel scheduling
142
+ differences can produce different greedy paths from one call to the next.
143
+ The session's in-memory completion cache is the real determinism guarantee
144
+ — retyping the same prefix in the same context will reuse the previous
145
+ ghost rather than re-querying. Raise temperature only if you want
146
+ cache-miss diversity (e.g. `PI_GHOST_TEMPERATURE=0.5`).
147
+
110
148
  Run `/ghost` inside Pi to see the effective config; `/ghost on` and
111
149
  `/ghost off` toggle the feature for the current session.
112
150
 
@@ -159,6 +197,41 @@ shown, and acceptance outcome (`accepted`, `dismissed`, `stale`, `expired`).
159
197
  Raw prompt text and LLM output are never written to the metrics file. Both
160
198
  files rotate at 10 MB.
161
199
 
200
+ ## User profile
201
+
202
+ The extension keeps a long-lived JSONL store at
203
+ `.pi/ghost-autocomplete/profile.jsonl` to learn slash-command, path, and
204
+ trigram frequencies across sessions. The profile feeds three local-only
205
+ signals:
206
+
207
+ 1. **Slash fast-path.** When the active line starts with `/`, the editor
208
+ serves the most-typed extension as a ghost before the LLM is queried
209
+ (mode `trie`, provider `profile-slash`). Press Right to accept.
210
+ 2. **Profile-bias rerank (M3c hook).** A `profileBias` score plugs into
211
+ the multi-candidate reranker. Wired but only takes effect when the
212
+ provider returns >1 candidate.
213
+ 3. **Bounded path boost.** Persistent path frequency adds a small
214
+ capped boost to deterministic path/fuzzy ranking, capped so it cannot
215
+ beat a fresh exact path-prefix match.
216
+
217
+ What's stored: paths (`src/foo.ts`), slash commands (`/review`),
218
+ trigrams from committed prompts, and acceptance records keyed by the
219
+ SHA-256 hash of the prefix. Raw prefixes and raw completions are
220
+ **never** written. Token tuples are tokenized and capped at 4 for
221
+ prefix tails / 8 for completions.
222
+
223
+ Sanitization runs before persistence: messages with API keys (`sk-…`,
224
+ `ghp_…`, JWT, etc.) or high-entropy tokens (Shannon > 4.0 bits/char,
225
+ length ≥ 20) are dropped entirely. The check is shared with the session
226
+ trie (`src/trie-sanitize.ts`).
227
+
228
+ Rotation: when the JSONL exceeds 2 MB, the store compacts in place —
229
+ sums weights per `(kind, key)`, halves records older than 90 days
230
+ (configurable via `PI_GHOST_PROFILE_DECAY_DAYS`), drops weights below
231
+ 0.1. The original file is preserved as `profile.jsonl.1`.
232
+
233
+ Set `PI_GHOST_PROFILE=off` to disable capture + use entirely.
234
+
162
235
  ## Benchmark CLI
163
236
 
164
237
  The `pi-ghost-bench` binary reads a metrics JSONL file and reports p50/p95
@@ -186,11 +259,22 @@ Exit code is `0` when all thresholds pass, `1` when any fail, `2` on I/O error o
186
259
  - The path index is built asynchronously at session start via `git ls-files`
187
260
  from the repository root, capped at 20 000 files. High-confidence
188
261
  basename-prefix matches (score ≥85) preempt the LLM unconditionally; lower-
189
- confidence fuzzy matches only activate when an action word (open, edit,
190
- read, …) precedes the token.
262
+ confidence fuzzy matches only activate when an action word (`open`, `edit`,
263
+ `read`, `show`, `view`, `find`, `check`, `look`, `load`, `import`, `include`,
264
+ `see`, `run`) precedes the token.
191
265
  - Recent agent messages come from `ctx.sessionManager.getBranch()` — only
192
266
  user/assistant text, no tool calls. Both providers truncate to a small,
193
267
  fixed payload so cloud requests don't ship the whole file.
268
+ - Path mentions are extracted from recent conversation messages (slashed
269
+ paths, backticked path-like tokens, and bare filenames with known code
270
+ extensions). These give a ranking boost (+10 exact, +7 basename) to
271
+ deterministic path completions, so recently discussed files surface
272
+ higher.
273
+ - For fuzzy filename matches where the typed token is not a prefix of the
274
+ match, the editor enters **replace mode**: accepting the ghost replaces
275
+ the typed token with the full matched path. A `→ ` prefix is rendered
276
+ before the ghost text to signal this behaviour. Prefix-suffix matches
277
+ still append as usual.
194
278
  - `render()` searches for `CURSOR_MARKER` in the lines returned by
195
279
  `super.render()` and injects ANSI dim text directly after it. Pi's
196
280
  differential renderer redraws only the changed cells — no flicker, no
@@ -201,6 +285,17 @@ Exit code is `0` when all thresholds pass, `1` when any fail, `2` on I/O error o
201
285
  handles legacy CSI/SS3 sequences and the Kitty keyboard protocol uniformly,
202
286
  so kitty / WezTerm / iTerm2 (Kitty-mode) all work. Otherwise the input
203
287
  passes through to `super.handleInput`.
288
+ - **Ctrl+Right** accepts the next *word* of the ghost (PRD §M3f). A "word"
289
+ is a run of `\w+` characters, or a single non-word non-whitespace char
290
+ with optional leading whitespace — VS Code's *Cursor Word Right* semantics.
291
+ Repeated presses peel the ghost off one token at a time; the final press
292
+ finalises the metric as `accepted-partial`.
293
+ - **Alt+]** / **Alt+[** cycle through ranked candidates when the provider
294
+ returns more than one (e.g. `openai-compat` with `PI_GHOST_MERCURY_PARALLEL_N>1`
295
+ and `PI_GHOST_TEMPERATURE>0`). Single-candidate sources (cache, trie,
296
+ speculative warm, deterministic path, default LLM fire) treat both keys
297
+ as no-ops. The selected candidate's index is logged as `candidateRank`
298
+ on accept along with `cycledCount`.
204
299
  - Visible-column math uses `string-width` + `strip-ansi`. Ghost text is
205
300
  clipped grapheme-aware to the remaining columns on the current visual line
206
301
  so wide CJK characters and emoji never overflow the row.
@@ -210,7 +305,7 @@ Exit code is `0` when all thresholds pass, `1` when any fail, `2` on I/O error o
210
305
  ```bash
211
306
  npm install
212
307
  npm run typecheck # tsc --noEmit against pi-tui / pi-coding-agent v0.74
213
- npm test # vitest, ~30 unit tests
308
+ npm test # vitest, ~170 unit tests
214
309
  npm run build # emits dist/
215
310
  ```
216
311
 
package/dist/bench-cli.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import { unwatchFile, watchFile } from "node:fs";
2
3
  import { resolve } from "node:path";
3
- import { formatReport, runBenchmark } from "./bench.js";
4
+ import { formatReport, renderLiveFrame, runBenchmark } from "./bench.js";
4
5
  const DEFAULT_PATH = ".pi/ghost-autocomplete/metrics.jsonl";
6
+ const DEFAULT_LIVE_INTERVAL_MS = 2000;
5
7
  async function main() {
6
8
  const args = process.argv.slice(2);
7
9
  if (args.includes("-h") || args.includes("--help")) {
@@ -9,8 +11,17 @@ async function main() {
9
11
  return;
10
12
  }
11
13
  const wantJson = args.includes("--json");
14
+ const wantLive = args.includes("--live");
15
+ const intervalFlag = args.find((a) => a.startsWith("--interval="));
16
+ const intervalMs = intervalFlag
17
+ ? Math.max(250, Number.parseInt(intervalFlag.slice("--interval=".length), 10) || DEFAULT_LIVE_INTERVAL_MS)
18
+ : DEFAULT_LIVE_INTERVAL_MS;
12
19
  const positional = args.filter((a) => !a.startsWith("-"));
13
20
  const target = resolve(process.cwd(), positional[0] ?? DEFAULT_PATH);
21
+ if (wantLive) {
22
+ await runLive(target, intervalMs);
23
+ return;
24
+ }
14
25
  try {
15
26
  const report = await runBenchmark(target);
16
27
  if (wantJson) {
@@ -32,15 +43,80 @@ async function main() {
32
43
  process.exit(2);
33
44
  }
34
45
  }
46
+ /**
47
+ * Live mode (Enhancement #6): re-render the report whenever `target` changes.
48
+ * Polls via `fs.watchFile` rather than `fs.watch` because the latter is
49
+ * unreliable on Windows for append-only logs. Renders once at startup so
50
+ * the user sees the current state before the first append.
51
+ *
52
+ * Exit on SIGINT. Errors during a refresh are reported inline and the
53
+ * loop continues — a transient I/O hiccup shouldn't kill the watcher.
54
+ */
55
+ async function runLive(target, intervalMs) {
56
+ let frame = 0;
57
+ let refreshing = false;
58
+ let pendingRefresh = false;
59
+ const refresh = async () => {
60
+ // If a refresh is already in flight, mark the file dirty so we run
61
+ // one more pass after it completes. Without this, two writes during
62
+ // the same render would render only once; subsequent writes wouldn't
63
+ // trigger anything until the watcher saw another mtime change.
64
+ if (refreshing) {
65
+ pendingRefresh = true;
66
+ return;
67
+ }
68
+ refreshing = true;
69
+ try {
70
+ const report = await runBenchmark(target);
71
+ frame++;
72
+ const frameText = renderLiveFrame(report, {
73
+ now: new Date(),
74
+ frameNumber: frame,
75
+ watchedPath: target,
76
+ });
77
+ // ANSI: clear screen + cursor home. Plain-text fallback would just
78
+ // scroll, which is fine in a non-TTY pipe.
79
+ const clearSeq = process.stdout.isTTY ? "\x1b[2J\x1b[H" : "";
80
+ process.stdout.write(`${clearSeq}${frameText}\n`);
81
+ }
82
+ catch (err) {
83
+ const msg = err instanceof Error ? err.message : String(err);
84
+ process.stderr.write(`pi-ghost-bench --live: refresh error: ${msg}\n`);
85
+ }
86
+ finally {
87
+ refreshing = false;
88
+ if (pendingRefresh) {
89
+ pendingRefresh = false;
90
+ void refresh();
91
+ }
92
+ }
93
+ };
94
+ process.on("SIGINT", () => {
95
+ unwatchFile(target);
96
+ process.stdout.write("\npi-ghost-bench --live: stopped.\n");
97
+ // Exit with 128 + signal number (130 = 128 + SIGINT/2). Matches the
98
+ // convention shells use when reporting a Ctrl-C terminated process.
99
+ process.exit(130);
100
+ });
101
+ await refresh();
102
+ watchFile(target, { interval: intervalMs }, (curr, prev) => {
103
+ if (curr.mtimeMs !== prev.mtimeMs || curr.size !== prev.size) {
104
+ void refresh();
105
+ }
106
+ });
107
+ }
35
108
  function usage() {
36
109
  return [
37
- "pi-ghost-bench [path] [--json]",
110
+ "pi-ghost-bench [path] [--json] [--live] [--interval=MS]",
38
111
  "",
39
- " path JSONL metrics file (default: .pi/ghost-autocomplete/metrics.jsonl)",
40
- " --json emit JSON instead of formatted text",
41
- " -h show this help",
112
+ " path JSONL metrics file (default: .pi/ghost-autocomplete/metrics.jsonl)",
113
+ " --json Emit JSON instead of formatted text",
114
+ " --live Watch the file and re-render on each change (Ctrl+C to exit)",
115
+ " --interval=MS Poll interval for --live (default: 2000, min: 250)",
116
+ " -h Show this help",
42
117
  "",
43
118
  "Exit code: 0 if all PRD thresholds pass, 1 if any fail, 2 on I/O error.",
119
+ "--live runs until interrupted (no exit code gating).",
44
120
  "",
45
121
  ].join("\n");
46
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bench-cli.js","sourceRoot":"","sources":["../src/bench-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAE5D,KAAK,UAAU,IAAI;IAClB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9B,OAAO;IACR,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC;IAErE,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CACnB,wCAAwC,MAAM,2BAA2B,CACzE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;AACF,CAAC;AAED,SAAS,KAAK;IACb,OAAO;QACN,gCAAgC;QAChC,EAAE;QACF,+EAA+E;QAC/E,gDAAgD;QAChD,2BAA2B;QAC3B,EAAE;QACF,yEAAyE;QACzE,EAAE;KACF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"bench-cli.js","sourceRoot":"","sources":["../src/bench-cli.ts"],"names":[],"mappings":"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"}
package/dist/bench.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MetricsRecord } from "./metrics.js";
1
+ import { type MetricsRecord } from "./metrics.js";
2
2
  /**
3
3
  * PRD §Success Metrics initial candidate thresholds. These are red/green
4
4
  * targets, not gates — the harness reports compliance but never errors out.
@@ -9,6 +9,15 @@ export declare const THRESHOLDS: {
9
9
  readonly deterministicP50Ms: 30;
10
10
  readonly validOutputRate: 0.85;
11
11
  readonly badOutputRate: 0.15;
12
+ /**
13
+ * Enhancement #6 hard gate: fraction of accepted-or-shown ghosts whose
14
+ * `estimatedTimeSavedMs` came out negative — i.e. the user spent more
15
+ * time waiting for the ghost than the keystrokes the accept could ever
16
+ * save. <10% is healthy, 10–20% warns, ≥20% fails. Calibrated against
17
+ * Yeh/Laban "saved-time" surveys and our own M5 data.
18
+ */
19
+ readonly negativeTimeSavedYellow: 0.1;
20
+ readonly negativeTimeSavedRed: 0.2;
12
21
  };
13
22
  export interface ProviderStats {
14
23
  provider: string;
@@ -28,8 +37,9 @@ export interface ProviderStats {
28
37
  /** (empty + rejected + error) / count */
29
38
  badRate: number;
30
39
  }
40
+ export type AnyMode = "deterministic" | "llm" | "cache" | "trie" | "speculative-warm" | "provisional";
31
41
  export interface ModeStats {
32
- mode: "deterministic" | "llm";
42
+ mode: AnyMode;
33
43
  count: number;
34
44
  shown: number;
35
45
  accepted: number;
@@ -39,17 +49,121 @@ export interface ModeStats {
39
49
  acceptanceRate: number;
40
50
  providers: ProviderStats[];
41
51
  }
52
+ /**
53
+ * Advanced metrics from M5a fields. All optional — values are populated only
54
+ * when the records carry the required field. Skipping rather than zeroing
55
+ * keeps a sparse session from looking artificially well-instrumented.
56
+ */
57
+ export interface AdvancedStats {
58
+ /** Time-to-first-token (LLM modes), p50/p95 in ms. */
59
+ ttftMs?: {
60
+ p50: number;
61
+ p95: number;
62
+ n: number;
63
+ };
64
+ /** Estimated typing time saved per accepted ghost, p50/p95 in ms. */
65
+ timeSavedMs?: {
66
+ p50: number;
67
+ p95: number;
68
+ total: number;
69
+ n: number;
70
+ };
71
+ /**
72
+ * Enhancement #6 hard gate: fraction of `estimatedTimeSavedMs` samples
73
+ * that came out negative. `severity`:
74
+ * - "ok": fraction < THRESHOLDS.negativeTimeSavedYellow
75
+ * - "yellow": yellow ≤ fraction < red
76
+ * - "red": fraction ≥ THRESHOLDS.negativeTimeSavedRed
77
+ * `n` is the denominator (records with `estimatedTimeSavedMs`).
78
+ */
79
+ negativeTimeSaved?: {
80
+ count: number;
81
+ fraction: number;
82
+ n: number;
83
+ severity: "ok" | "yellow" | "red";
84
+ };
85
+ /**
86
+ * Accept-regret rate per PRD §M5b: fraction of accepted ghosts the user
87
+ * deleted >50% of within the regret window. Calibration target: <10%.
88
+ * `n` is the denominator (accepted + accepted-partial outcomes).
89
+ */
90
+ acceptRegretRate?: {
91
+ rate: number;
92
+ n: number;
93
+ };
94
+ /**
95
+ * Enhancement #3: fraction of *dismissed* ghosts where the user dismissed
96
+ * within `PI_GHOST_SHORT_HOVER_MS` (default 800 ms). High rate signals
97
+ * the rerank/confidence gate is letting through low-value candidates.
98
+ * `n` is the denominator (dismissed outcomes).
99
+ */
100
+ shortHoverDismissRate?: {
101
+ rate: number;
102
+ n: number;
103
+ };
104
+ /**
105
+ * Enhancement #5: fraction of stale records where the user typed at
106
+ * least `TYPED_PAST_DIVERGENT_THRESHOLD` consecutive divergent
107
+ * characters past the served ghost. High rate is a strong signal that
108
+ * the suggestions are off-target for this user's style. `n` is the
109
+ * denominator (stale outcomes).
110
+ */
111
+ typedPastDivergentRate?: {
112
+ rate: number;
113
+ n: number;
114
+ };
115
+ /**
116
+ * Provisional-fallback stats per PRD §M5b: how often provisional fired,
117
+ * what fraction the LLM ended up matching, and mean swap latency for
118
+ * the cases that did swap.
119
+ */
120
+ provisional?: {
121
+ shown: number;
122
+ swapped: number;
123
+ correctRate: number;
124
+ meanSwapMs: number;
125
+ /**
126
+ * Fraction of `swapped` events where the user dismissed/aborted within
127
+ * `SWAP_FLICKER_WINDOW_MS` — visual jumps that didn't help. With
128
+ * `PREFER` margin now the default, this should converge to a low
129
+ * single-digit % under normal use.
130
+ */
131
+ flickerRate?: number;
132
+ /** Per-source counts of provisional shows that survived to outcome
133
+ * WITHOUT being superseded by the LLM (i.e., `mode === "provisional"`
134
+ * on the final record). Keys: `trie`, `profile-accept`,
135
+ * `session-cache`. Provisional+LLM-swap cases are counted under
136
+ * `swapped` instead, because the final shownMetric is the LLM's. */
137
+ bySource?: Record<string, number>;
138
+ /** Accept rate over `shown` — i.e., provisionals that survived alone
139
+ * to outcome (no LLM swap). Measures how good the local guess is
140
+ * when the LLM doesn't take over. Production target: ≥45 %. */
141
+ acceptRate?: number;
142
+ };
143
+ /** Fraction of shown ghosts accepted at first display (rank 0). */
144
+ savedAt1?: number;
145
+ /** Same, after cycling up to 3 candidates. */
146
+ savedAt3?: number;
147
+ /** Same, after 5. */
148
+ savedAt5?: number;
149
+ }
42
150
  export interface BenchmarkReport {
43
151
  source: string;
44
152
  records: number;
45
153
  parseErrors: number;
46
154
  deterministic: ModeStats;
47
155
  llm: ModeStats;
156
+ /** All non-zero modes from the records, keyed by mode name. */
157
+ byMode: ModeStats[];
158
+ advanced: AdvancedStats;
48
159
  thresholds: Array<{
49
160
  name: string;
50
161
  target: string;
51
162
  observed: string;
52
163
  pass: boolean;
164
+ /** Present when the threshold has a yellow band. "warn" means observed
165
+ * is past the yellow line but still under the red line — pass=true. */
166
+ severity?: "warn";
53
167
  }>;
54
168
  }
55
169
  /**
@@ -90,4 +204,18 @@ export declare function formatReport(report: BenchmarkReport): string;
90
204
  * One-shot helper: load a JSONL file and produce a report. Used by the CLI.
91
205
  */
92
206
  export declare function runBenchmark(path: string): Promise<BenchmarkReport>;
207
+ /**
208
+ * Enhancement #6: a single rendered "frame" for `pi-ghost-bench --live`.
209
+ * The frame is a self-contained block of text — caller clears the screen
210
+ * and prints it on every metrics-file change. ANSI escapes are emitted by
211
+ * the CLI, not this helper, so the function stays pure and unit-testable.
212
+ *
213
+ * Format: banner with timestamp + frame counter, then the standard
214
+ * formatted report, then a footer with the watched path.
215
+ */
216
+ export declare function renderLiveFrame(report: BenchmarkReport, opts: {
217
+ now: Date;
218
+ frameNumber: number;
219
+ watchedPath: string;
220
+ }): string;
93
221
  //# sourceMappingURL=bench.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bench.d.ts","sourceRoot":"","sources":["../src/bench.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,aAAa,EAAkC,MAAM,cAAc,CAAC;AAErG;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;CAMb,CAAC;AAEX,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,eAAe,GAAG,KAAK,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,SAAS,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;IACf,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrF;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAG5D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAC/C,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACpB,CAcA;AAaD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,SAAa,EACnB,WAAW,SAAI,GACb,eAAe,CAajB;AAqHD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA8B5D;AAMD;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAGzE"}
1
+ {"version":3,"file":"bench.d.ts","sourceRoot":"","sources":["../src/bench.ts"],"names":[],"mappings":"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"}