pi-ghost-autocomplete 0.3.2 → 0.5.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.
Files changed (170) hide show
  1. package/LICENSE +561 -0
  2. package/README.md +186 -4
  3. package/dist/bench-cli.js +1 -123
  4. package/dist/bench.d.ts +7 -3
  5. package/dist/bench.js +1 -522
  6. package/dist/config.d.ts +46 -3
  7. package/dist/context-aggregator.d.ts +4 -1
  8. package/dist/cycle-manager.d.ts +2 -21
  9. package/dist/entropy-stop.d.ts +4 -1
  10. package/dist/eval-dataset.d.ts +2 -13
  11. package/dist/fuzzy-matcher.d.ts +4 -1
  12. package/dist/ghost-editor.d.ts +11 -2
  13. package/dist/index.d.ts +7 -2
  14. package/dist/index.js +1 -289
  15. package/dist/intent.d.ts +179 -0
  16. package/dist/metrics.d.ts +4 -1
  17. package/dist/path-index.d.ts +4 -1
  18. package/dist/path-matcher.d.ts +4 -1
  19. package/dist/profile-store.d.ts +4 -1
  20. package/dist/profile.d.ts +2 -20
  21. package/dist/providers/cloud-provider.d.ts +4 -1
  22. package/dist/providers/local-provider.d.ts +4 -1
  23. package/dist/providers/openai-compat-chat-provider.d.ts +31 -0
  24. package/dist/providers/openai-compat-provider.d.ts +24 -1
  25. package/dist/providers/race.d.ts +4 -1
  26. package/dist/providers/router.d.ts +59 -0
  27. package/dist/providers/types.d.ts +13 -1
  28. package/dist/recent-paths.d.ts +4 -1
  29. package/dist/replay-cli.js +1 -166
  30. package/dist/replay.d.ts +2 -7
  31. package/package.json +10 -6
  32. package/dist/bench-cli.d.ts +0 -3
  33. package/dist/bench-cli.d.ts.map +0 -1
  34. package/dist/bench-cli.js.map +0 -1
  35. package/dist/bench.d.ts.map +0 -1
  36. package/dist/bench.js.map +0 -1
  37. package/dist/cache.d.ts +0 -124
  38. package/dist/cache.d.ts.map +0 -1
  39. package/dist/cache.js +0 -173
  40. package/dist/cache.js.map +0 -1
  41. package/dist/candidate-rerank.d.ts +0 -57
  42. package/dist/candidate-rerank.d.ts.map +0 -1
  43. package/dist/candidate-rerank.js +0 -78
  44. package/dist/candidate-rerank.js.map +0 -1
  45. package/dist/config.d.ts.map +0 -1
  46. package/dist/config.js +0 -317
  47. package/dist/config.js.map +0 -1
  48. package/dist/context-aggregator.d.ts.map +0 -1
  49. package/dist/context-aggregator.js +0 -87
  50. package/dist/context-aggregator.js.map +0 -1
  51. package/dist/context-selector.d.ts +0 -128
  52. package/dist/context-selector.d.ts.map +0 -1
  53. package/dist/context-selector.js +0 -300
  54. package/dist/context-selector.js.map +0 -1
  55. package/dist/cycle-manager.d.ts.map +0 -1
  56. package/dist/cycle-manager.js +0 -168
  57. package/dist/cycle-manager.js.map +0 -1
  58. package/dist/edit-history-ring.d.ts +0 -148
  59. package/dist/edit-history-ring.d.ts.map +0 -1
  60. package/dist/edit-history-ring.js +0 -262
  61. package/dist/edit-history-ring.js.map +0 -1
  62. package/dist/entropy-stop.d.ts.map +0 -1
  63. package/dist/entropy-stop.js +0 -141
  64. package/dist/entropy-stop.js.map +0 -1
  65. package/dist/eval-dataset.d.ts.map +0 -1
  66. package/dist/eval-dataset.js +0 -127
  67. package/dist/eval-dataset.js.map +0 -1
  68. package/dist/fast-path-engine.d.ts +0 -286
  69. package/dist/fast-path-engine.d.ts.map +0 -1
  70. package/dist/fast-path-engine.js +0 -341
  71. package/dist/fast-path-engine.js.map +0 -1
  72. package/dist/fuzzy-matcher.d.ts.map +0 -1
  73. package/dist/fuzzy-matcher.js +0 -162
  74. package/dist/fuzzy-matcher.js.map +0 -1
  75. package/dist/ghost-editor.d.ts.map +0 -1
  76. package/dist/ghost-editor.js +0 -1491
  77. package/dist/ghost-editor.js.map +0 -1
  78. package/dist/index.d.ts.map +0 -1
  79. package/dist/index.js.map +0 -1
  80. package/dist/keystroke-timer.d.ts +0 -59
  81. package/dist/keystroke-timer.d.ts.map +0 -1
  82. package/dist/keystroke-timer.js +0 -94
  83. package/dist/keystroke-timer.js.map +0 -1
  84. package/dist/metrics-builder.d.ts +0 -71
  85. package/dist/metrics-builder.d.ts.map +0 -1
  86. package/dist/metrics-builder.js +0 -71
  87. package/dist/metrics-builder.js.map +0 -1
  88. package/dist/metrics.d.ts.map +0 -1
  89. package/dist/metrics.js +0 -212
  90. package/dist/metrics.js.map +0 -1
  91. package/dist/path-index.d.ts.map +0 -1
  92. package/dist/path-index.js +0 -148
  93. package/dist/path-index.js.map +0 -1
  94. package/dist/path-matcher.d.ts.map +0 -1
  95. package/dist/path-matcher.js +0 -88
  96. package/dist/path-matcher.js.map +0 -1
  97. package/dist/profile-store.d.ts.map +0 -1
  98. package/dist/profile-store.js +0 -199
  99. package/dist/profile-store.js.map +0 -1
  100. package/dist/profile.d.ts.map +0 -1
  101. package/dist/profile.js +0 -434
  102. package/dist/profile.js.map +0 -1
  103. package/dist/providers/cloud-provider.d.ts.map +0 -1
  104. package/dist/providers/cloud-provider.js +0 -109
  105. package/dist/providers/cloud-provider.js.map +0 -1
  106. package/dist/providers/local-provider.d.ts.map +0 -1
  107. package/dist/providers/local-provider.js +0 -48
  108. package/dist/providers/local-provider.js.map +0 -1
  109. package/dist/providers/openai-compat-provider.d.ts.map +0 -1
  110. package/dist/providers/openai-compat-provider.js +0 -215
  111. package/dist/providers/openai-compat-provider.js.map +0 -1
  112. package/dist/providers/openai-completions-runner.d.ts +0 -52
  113. package/dist/providers/openai-completions-runner.d.ts.map +0 -1
  114. package/dist/providers/openai-completions-runner.js +0 -141
  115. package/dist/providers/openai-completions-runner.js.map +0 -1
  116. package/dist/providers/race.d.ts.map +0 -1
  117. package/dist/providers/race.js +0 -441
  118. package/dist/providers/race.js.map +0 -1
  119. package/dist/providers/truncate.d.ts +0 -7
  120. package/dist/providers/truncate.d.ts.map +0 -1
  121. package/dist/providers/truncate.js +0 -57
  122. package/dist/providers/truncate.js.map +0 -1
  123. package/dist/providers/types.d.ts.map +0 -1
  124. package/dist/providers/types.js +0 -60
  125. package/dist/providers/types.js.map +0 -1
  126. package/dist/provisional-manager.d.ts +0 -93
  127. package/dist/provisional-manager.d.ts.map +0 -1
  128. package/dist/provisional-manager.js +0 -98
  129. package/dist/provisional-manager.js.map +0 -1
  130. package/dist/provisional.d.ts +0 -150
  131. package/dist/provisional.d.ts.map +0 -1
  132. package/dist/provisional.js +0 -238
  133. package/dist/provisional.js.map +0 -1
  134. package/dist/recent-paths.d.ts.map +0 -1
  135. package/dist/recent-paths.js +0 -114
  136. package/dist/recent-paths.js.map +0 -1
  137. package/dist/regret-tracker.d.ts +0 -84
  138. package/dist/regret-tracker.d.ts.map +0 -1
  139. package/dist/regret-tracker.js +0 -145
  140. package/dist/regret-tracker.js.map +0 -1
  141. package/dist/replay-cli.d.ts +0 -13
  142. package/dist/replay-cli.d.ts.map +0 -1
  143. package/dist/replay-cli.js.map +0 -1
  144. package/dist/replay.d.ts.map +0 -1
  145. package/dist/replay.js +0 -225
  146. package/dist/replay.js.map +0 -1
  147. package/dist/reranker.d.ts +0 -181
  148. package/dist/reranker.d.ts.map +0 -1
  149. package/dist/reranker.js +0 -324
  150. package/dist/reranker.js.map +0 -1
  151. package/dist/session-trie.d.ts +0 -103
  152. package/dist/session-trie.d.ts.map +0 -1
  153. package/dist/session-trie.js +0 -280
  154. package/dist/session-trie.js.map +0 -1
  155. package/dist/speculative.d.ts +0 -74
  156. package/dist/speculative.d.ts.map +0 -1
  157. package/dist/speculative.js +0 -107
  158. package/dist/speculative.js.map +0 -1
  159. package/dist/tool-summarize.d.ts +0 -40
  160. package/dist/tool-summarize.d.ts.map +0 -1
  161. package/dist/tool-summarize.js +0 -245
  162. package/dist/tool-summarize.js.map +0 -1
  163. package/dist/trie-sanitize.d.ts +0 -22
  164. package/dist/trie-sanitize.d.ts.map +0 -1
  165. package/dist/trie-sanitize.js +0 -142
  166. package/dist/trie-sanitize.js.map +0 -1
  167. package/dist/versions.d.ts +0 -23
  168. package/dist/versions.d.ts.map +0 -1
  169. package/dist/versions.js +0 -31
  170. package/dist/versions.js.map +0 -1
package/dist/config.d.ts CHANGED
@@ -1,5 +1,9 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  import { type KnownProvider } from "@earendil-works/pi-ai";
2
- export type ProviderKind = "cloud" | "local" | "openai-compat" | "race";
6
+ export type ProviderKind = "cloud" | "local" | "openai-compat" | "openai-compat-chat" | "race" | "router";
3
7
  export interface OpenAICompatProviderConfig {
4
8
  kind: "openai-compat";
5
9
  /** Logical name shown in metrics/UI (e.g. "mercury-edit"). */
@@ -22,6 +26,27 @@ export interface OpenAICompatProviderConfig {
22
26
  */
23
27
  parallelN: number;
24
28
  }
29
+ /**
30
+ * Chat-register sibling of {@link OpenAICompatProviderConfig}. Targets the
31
+ * OpenAI-compatible `/chat/completions` endpoint (e.g. Inception Mercury's chat
32
+ * model) instead of `/fim/completions`. Used as the natural-language leg of a
33
+ * {@link RouterProviderConfig}: where FIM completes code, this completes the
34
+ * developer's *message to the agent* with a persona system prompt.
35
+ */
36
+ export interface OpenAICompatChatProviderConfig {
37
+ kind: "openai-compat-chat";
38
+ /** Logical name shown in metrics/UI (e.g. "mercury-chat"). */
39
+ providerName: string;
40
+ baseUrl: string;
41
+ apiKey?: string;
42
+ modelId: string;
43
+ debounceMs: number;
44
+ maxTokens: number;
45
+ maxRecentMessages: number;
46
+ temperature: number;
47
+ /** Optional context-window hint. Defaults to 8192 where consulted. */
48
+ contextWindow?: number;
49
+ }
25
50
  export interface CloudProviderConfig {
26
51
  kind: "cloud";
27
52
  provider: KnownProvider;
@@ -51,7 +76,19 @@ export interface RaceProviderConfig {
51
76
  cutoffMs: number;
52
77
  maxRecentMessages: number;
53
78
  }
54
- export type ProviderConfig = CloudProviderConfig | LocalProviderConfig | OpenAICompatProviderConfig | RaceProviderConfig;
79
+ /**
80
+ * Register-routing provider (PRD §M3h): dispatches each request to the FIM leg
81
+ * or the chat leg based on the classified prompt intent. Code-shaped intents
82
+ * (`command`, `path-ref`, unclassified) go to `fim`; natural-language intents
83
+ * (`instruction`, `question`, `prose`) go to `chat`. When `chat` is absent the
84
+ * router degrades to FIM-only — identical to today's default behavior.
85
+ */
86
+ export interface RouterProviderConfig {
87
+ kind: "router";
88
+ fim: OpenAICompatProviderConfig;
89
+ chat: OpenAICompatChatProviderConfig | CloudProviderConfig | LocalProviderConfig | null;
90
+ }
91
+ export type ProviderConfig = CloudProviderConfig | LocalProviderConfig | OpenAICompatProviderConfig | OpenAICompatChatProviderConfig | RaceProviderConfig | RouterProviderConfig;
55
92
  export interface GhostConfig {
56
93
  enabled: boolean;
57
94
  provider: ProviderConfig;
@@ -61,6 +98,13 @@ export interface GhostConfig {
61
98
  export declare const DEFAULT_CLOUD_CONFIG: CloudProviderConfig;
62
99
  export declare const DEFAULT_LOCAL_CONFIG: LocalProviderConfig;
63
100
  export declare const DEFAULT_MERCURY_CONFIG: OpenAICompatProviderConfig;
101
+ /**
102
+ * Default chat-register leg for router mode. Same Inception base URL + key as
103
+ * the FIM leg, but the general (non-edit) Mercury model over `/chat/completions`.
104
+ * `mercury-2` is Inception's conversational model; override with
105
+ * `PI_GHOST_CHAT_MODEL` if the account exposes a different chat model id.
106
+ */
107
+ export declare const DEFAULT_MERCURY_CHAT_CONFIG: OpenAICompatChatProviderConfig;
64
108
  export declare const DEFAULT_CONFIG: GhostConfig;
65
109
  export declare function readConfigFromEnv(): GhostConfig;
66
110
  /**
@@ -95,4 +139,3 @@ export declare function redactConfig<T>(cfg: T): T;
95
139
  * - Other schemes (`file:`, `data:`, etc.) rejected unconditionally.
96
140
  */
97
141
  export declare function validateBaseUrl(raw: string, fieldName?: string): string | null;
98
- //# sourceMappingURL=config.d.ts.map
@@ -1,3 +1,7 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
6
  import type { AgentMessage } from "@earendil-works/pi-agent-core";
3
7
  /**
@@ -20,4 +24,3 @@ export declare function getRecentMessages(ctx: ExtensionContext, max: number, op
20
24
  includeTools?: boolean;
21
25
  }): RecentMessage[];
22
26
  export declare function extractText(msg: AgentMessage): string;
23
- //# sourceMappingURL=context-aggregator.d.ts.map
@@ -1,24 +1,6 @@
1
1
  /**
2
- * CycleManager — owns multi-candidate state and word-level partial-accept
3
- * gestures for the GREAT Ghost autocomplete.
4
- *
5
- * PRD §M3e (Alt+]/Alt+[ cycling with clamp-at-edges, no wrap) +
6
- * PRD §M3f (Ctrl+Right word-by-word acceptance in append mode).
7
- *
8
- * Design notes:
9
- *
10
- * - Candidate list is stored read-only (frozen) so that future refactors
11
- * don't accidentally mutate ranked text. Per-candidate consumption from
12
- * word-level accepts is tracked separately in `consumed[idx]`.
13
- * - `current` returns `string | null` — `null` distinguishes "no candidates
14
- * installed" from "current candidate is empty after full consumption".
15
- * - `acceptPartialWordAppend()` is named to make the append-mode invariant
16
- * impossible to forget at call sites. Replace-mode ghosts (fuzzy/path)
17
- * accept atomically; word-by-word doesn't apply.
18
- * - No hidden auto-reset: caller is responsible for `reset()` after the
19
- * final-chunk accept so the lifecycle is explicit.
20
- *
21
- * Extracted as part of refactor #57 so `GhostEditor` stays thin.
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
22
4
  */
23
5
  /**
24
6
  * Pure helper: compute the next index for Alt+]/Alt[+ cycle.
@@ -99,4 +81,3 @@ export declare class CycleManager {
99
81
  partials: number;
100
82
  };
101
83
  }
102
- //# sourceMappingURL=cycle-manager.d.ts.map
@@ -1,3 +1,7 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  /**
2
6
  * Entropy-based early stop. PRD §M7.
3
7
  *
@@ -99,4 +103,3 @@ export declare function runWithStop(tokens: Iterable<{
99
103
  stopped: boolean;
100
104
  reason?: "entropy-spike" | "max-tokens";
101
105
  };
102
- //# sourceMappingURL=entropy-stop.d.ts.map
@@ -1,16 +1,6 @@
1
1
  /**
2
- * Offline-eval dataset — capture + load. PRD §M5c.
3
- *
4
- * One JSONL example per committed prompt sample. The shape captures
5
- * everything a replay run needs to reproduce the original ghost call:
6
- * `(context, prefix, expected continuation, provider fingerprint)`.
7
- *
8
- * Privacy: examples DO contain raw prompt text. Capture is gated on the
9
- * `PI_GHOST_EVAL_CAPTURE=1` env (not a default behavior — opt-in only).
10
- * Sanitization still applies through `containsSensitive` so messages
11
- * with API keys are dropped at capture time. Downstream tooling (CLI
12
- * replay) ships a `--redact` flag that emits aggregate metrics without
13
- * raw examples for publication.
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
14
4
  */
15
5
  export declare const EVAL_REL = ".pi/ghost-autocomplete/eval.jsonl";
16
6
  /** Char positions at which to sample prefixes from a committed line. */
@@ -63,4 +53,3 @@ export declare function loadExamples(cwd: string): Promise<EvalExample[]>;
63
53
  export declare function parseExamples(body: string): EvalExample[];
64
54
  /** Parse `PI_GHOST_EVAL_CAPTURE`. Returns true only when set to "1". */
65
55
  export declare function parseEvalCaptureEnv(raw: string | undefined): boolean;
66
- //# sourceMappingURL=eval-dataset.d.ts.map
@@ -1,3 +1,7 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  import type { PathIndex } from "./path-index.js";
2
6
  export interface FindFuzzyOptions {
3
7
  recentPaths?: Set<string> | null;
@@ -55,4 +59,3 @@ export declare function hasActionTrigger(prefix: string): boolean;
55
59
  * 70-84). Scores < 70 should not be shown deterministically.
56
60
  */
57
61
  export declare function findFuzzyFilename(index: PathIndex, token: string, opts?: FindFuzzyOptions): FuzzyMatch | null;
58
- //# sourceMappingURL=fuzzy-matcher.d.ts.map
@@ -1,3 +1,7 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  import { CustomEditor, type ExtensionContext } from "@earendil-works/pi-coding-agent";
2
6
  import type { KeybindingsManager } from "@earendil-works/pi-coding-agent";
3
7
  import { type EditorTheme, type TUI } from "@earendil-works/pi-tui";
@@ -41,6 +45,12 @@ export declare class GhostEditor extends CustomEditor {
41
45
  private debounceTimer;
42
46
  private inflight;
43
47
  private lastTextSeen;
48
+ /** Last classified intent, set during handleTextChange and consumed
49
+ * by buildPredictionContext when the LLM fires after debounce. */
50
+ private currentIntent;
51
+ /** Ring buffer of recently-dismissed deterministic completions,
52
+ * used to suppress re-showing the same path in the same context. */
53
+ private readonly dismissCache;
44
54
  private disposed;
45
55
  private shownMetric;
46
56
  private recentPaths;
@@ -194,7 +204,7 @@ export declare class GhostEditor extends CustomEditor {
194
204
  * served. Profile must exist; line must start with `/`.
195
205
  */
196
206
  private trySlashFastPath;
197
- private tryDeterministic;
207
+ private tryDeterministicWithLines;
198
208
  private getRecentPaths;
199
209
  private applyDeterministic;
200
210
  private replaceTokenAtCursor;
@@ -379,4 +389,3 @@ export declare function visualWidth(s: string): number;
379
389
  * Returns the empty string if `maxCols <= 0` or no characters fit.
380
390
  */
381
391
  export declare function clipToWidth(s: string, maxCols: number): string;
382
- //# sourceMappingURL=ghost-editor.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * SPDX-License-Identifier: SSPL-1.0
3
+ * SPDX-FileCopyrightText: 2025 Alessandro Pungitore <alessandro@pungitore.ch>
4
+ */
1
5
  import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
2
6
  import { type GhostConfig } from "./config.js";
3
7
  import type { GhostDiagnostics } from "./ghost-editor.js";
@@ -13,12 +17,14 @@ export default ghost;
13
17
  export { CloudProvider } from "./providers/cloud-provider.js";
14
18
  export { LocalProvider } from "./providers/local-provider.js";
15
19
  export { OpenAICompatProvider } from "./providers/openai-compat-provider.js";
20
+ export { OpenAICompatChatProvider } from "./providers/openai-compat-chat-provider.js";
21
+ export { RouterProvider, routeToChat } from "./providers/router.js";
16
22
  export type { PreflightResult } from "./providers/openai-compat-provider.js";
17
23
  export { RaceProvider, firstNonNull } from "./providers/race.js";
18
24
  export type { RaceConfig, RaceTrace } from "./providers/race.js";
19
25
  export { GhostEditor, computeReplacement } from "./ghost-editor.js";
20
26
  export type { GhostDiagnostics } from "./ghost-editor.js";
21
- export type { GhostConfig, ProviderConfig, CloudProviderConfig, LocalProviderConfig, OpenAICompatProviderConfig, RaceProviderConfig } from "./config.js";
27
+ export type { GhostConfig, ProviderConfig, CloudProviderConfig, LocalProviderConfig, OpenAICompatProviderConfig, OpenAICompatChatProviderConfig, RaceProviderConfig, RouterProviderConfig } from "./config.js";
22
28
  export type { GhostProvider, GhostRequest } from "./providers/types.js";
23
29
  export { MetricsLogger, readMetricsConfigFromEnv } from "./metrics.js";
24
30
  export { ProfileStore } from "./profile-store.js";
@@ -39,4 +45,3 @@ export type { FindPathPrefixOptions } from "./path-matcher.js";
39
45
  export { extractRecentPaths, getRoleWeightedRecent, recentBoost } from "./recent-paths.js";
40
46
  export { formatReport, loadMetrics, parseMetricsText, quantile, runBenchmark, summarize, THRESHOLDS, } from "./bench.js";
41
47
  export type { BenchmarkReport, ModeStats, ProviderStats } from "./bench.js";
42
- //# sourceMappingURL=index.d.ts.map