pi-ghost-autocomplete 0.3.1

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 (74) hide show
  1. package/README.md +236 -0
  2. package/dist/bench-cli.d.ts +3 -0
  3. package/dist/bench-cli.d.ts.map +1 -0
  4. package/dist/bench-cli.js +48 -0
  5. package/dist/bench-cli.js.map +1 -0
  6. package/dist/bench.d.ts +93 -0
  7. package/dist/bench.d.ts.map +1 -0
  8. package/dist/bench.js +241 -0
  9. package/dist/bench.js.map +1 -0
  10. package/dist/config.d.ts +55 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +187 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/context-aggregator.d.ts +14 -0
  15. package/dist/context-aggregator.d.ts.map +1 -0
  16. package/dist/context-aggregator.js +58 -0
  17. package/dist/context-aggregator.js.map +1 -0
  18. package/dist/fuzzy-matcher.d.ts +50 -0
  19. package/dist/fuzzy-matcher.d.ts.map +1 -0
  20. package/dist/fuzzy-matcher.js +160 -0
  21. package/dist/fuzzy-matcher.js.map +1 -0
  22. package/dist/ghost-editor.d.ts +65 -0
  23. package/dist/ghost-editor.d.ts.map +1 -0
  24. package/dist/ghost-editor.js +445 -0
  25. package/dist/ghost-editor.js.map +1 -0
  26. package/dist/index.d.ts +25 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +210 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/metrics.d.ts +56 -0
  31. package/dist/metrics.d.ts.map +1 -0
  32. package/dist/metrics.js +98 -0
  33. package/dist/metrics.js.map +1 -0
  34. package/dist/path-index.d.ts +20 -0
  35. package/dist/path-index.d.ts.map +1 -0
  36. package/dist/path-index.js +148 -0
  37. package/dist/path-index.js.map +1 -0
  38. package/dist/path-matcher.d.ts +32 -0
  39. package/dist/path-matcher.d.ts.map +1 -0
  40. package/dist/path-matcher.js +85 -0
  41. package/dist/path-matcher.js.map +1 -0
  42. package/dist/providers/cloud-provider.d.ts +10 -0
  43. package/dist/providers/cloud-provider.d.ts.map +1 -0
  44. package/dist/providers/cloud-provider.js +52 -0
  45. package/dist/providers/cloud-provider.js.map +1 -0
  46. package/dist/providers/local-provider.d.ts +11 -0
  47. package/dist/providers/local-provider.d.ts.map +1 -0
  48. package/dist/providers/local-provider.js +36 -0
  49. package/dist/providers/local-provider.js.map +1 -0
  50. package/dist/providers/openai-compat-provider.d.ts +29 -0
  51. package/dist/providers/openai-compat-provider.d.ts.map +1 -0
  52. package/dist/providers/openai-compat-provider.js +128 -0
  53. package/dist/providers/openai-compat-provider.js.map +1 -0
  54. package/dist/providers/openai-completions-runner.d.ts +28 -0
  55. package/dist/providers/openai-completions-runner.d.ts.map +1 -0
  56. package/dist/providers/openai-completions-runner.js +46 -0
  57. package/dist/providers/openai-completions-runner.js.map +1 -0
  58. package/dist/providers/race.d.ts +40 -0
  59. package/dist/providers/race.d.ts.map +1 -0
  60. package/dist/providers/race.js +128 -0
  61. package/dist/providers/race.js.map +1 -0
  62. package/dist/providers/truncate.d.ts +7 -0
  63. package/dist/providers/truncate.d.ts.map +1 -0
  64. package/dist/providers/truncate.js +39 -0
  65. package/dist/providers/truncate.js.map +1 -0
  66. package/dist/providers/types.d.ts +18 -0
  67. package/dist/providers/types.d.ts.map +1 -0
  68. package/dist/providers/types.js +2 -0
  69. package/dist/providers/types.js.map +1 -0
  70. package/dist/recent-paths.d.ts +25 -0
  71. package/dist/recent-paths.d.ts.map +1 -0
  72. package/dist/recent-paths.js +114 -0
  73. package/dist/recent-paths.js.map +1 -0
  74. package/package.json +79 -0
@@ -0,0 +1,55 @@
1
+ import { type KnownProvider } from "@earendil-works/pi-ai";
2
+ export type ProviderKind = "cloud" | "local" | "openai-compat" | "race";
3
+ export interface OpenAICompatProviderConfig {
4
+ kind: "openai-compat";
5
+ /** Logical name shown in metrics/UI (e.g. "mercury-edit"). */
6
+ providerName: string;
7
+ baseUrl: string;
8
+ apiKey?: string;
9
+ modelId: string;
10
+ debounceMs: number;
11
+ maxTokens: number;
12
+ maxRecentMessages: number;
13
+ /** Optional context-window hint passed to pi-ai. Defaults to 8192. */
14
+ contextWindow?: number;
15
+ }
16
+ export interface CloudProviderConfig {
17
+ kind: "cloud";
18
+ provider: KnownProvider;
19
+ modelId: string;
20
+ apiKey?: string;
21
+ debounceMs: number;
22
+ maxTokens: number;
23
+ maxRecentMessages: number;
24
+ }
25
+ export interface LocalProviderConfig {
26
+ kind: "local";
27
+ baseUrl: string;
28
+ modelId: string;
29
+ debounceMs: number;
30
+ maxTokens: number;
31
+ maxRecentMessages: number;
32
+ /** Optional context-window hint passed to pi-ai. Defaults to 8192. */
33
+ contextWindow?: number;
34
+ }
35
+ export interface RaceProviderConfig {
36
+ kind: "race";
37
+ members: Array<CloudProviderConfig | LocalProviderConfig | OpenAICompatProviderConfig>;
38
+ pauseMs: number;
39
+ cooldownMs: number;
40
+ cutoffMs: number;
41
+ maxRecentMessages: number;
42
+ }
43
+ export type ProviderConfig = CloudProviderConfig | LocalProviderConfig | OpenAICompatProviderConfig | RaceProviderConfig;
44
+ export interface GhostConfig {
45
+ enabled: boolean;
46
+ provider: ProviderConfig;
47
+ minChars: number;
48
+ maxLineLength: number;
49
+ }
50
+ export declare const DEFAULT_CLOUD_CONFIG: CloudProviderConfig;
51
+ export declare const DEFAULT_LOCAL_CONFIG: LocalProviderConfig;
52
+ export declare const DEFAULT_MERCURY_CONFIG: OpenAICompatProviderConfig;
53
+ export declare const DEFAULT_CONFIG: GhostConfig;
54
+ export declare function readConfigFromEnv(): GhostConfig;
55
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,GAAG,eAAe,GAAG,MAAM,CAAC;AAExE,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE,eAAe,CAAC;IACtB,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC,mBAAmB,GAAG,mBAAmB,GAAG,0BAA0B,CAAC,CAAC;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GACvB,mBAAmB,GACnB,mBAAmB,GACnB,0BAA0B,GAC1B,kBAAkB,CAAC;AAEtB,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,mBAOlC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,mBAOlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,0BAQpC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAK5B,CAAC;AAqBF,wBAAgB,iBAAiB,IAAI,WAAW,CAwC/C"}
package/dist/config.js ADDED
@@ -0,0 +1,187 @@
1
+ import { getModels } from "@earendil-works/pi-ai";
2
+ export const DEFAULT_CLOUD_CONFIG = {
3
+ kind: "cloud",
4
+ provider: "groq",
5
+ modelId: "llama-3.1-8b-instant",
6
+ debounceMs: 150,
7
+ maxTokens: 64,
8
+ maxRecentMessages: 4,
9
+ };
10
+ export const DEFAULT_LOCAL_CONFIG = {
11
+ kind: "local",
12
+ baseUrl: "http://localhost:11434",
13
+ modelId: "qwen2.5-coder:1.5b",
14
+ debounceMs: 400,
15
+ maxTokens: 48,
16
+ maxRecentMessages: 2,
17
+ };
18
+ export const DEFAULT_MERCURY_CONFIG = {
19
+ kind: "openai-compat",
20
+ providerName: "mercury-edit",
21
+ baseUrl: "https://api.inceptionlabs.ai/v1",
22
+ modelId: "mercury-edit-2",
23
+ debounceMs: 150,
24
+ maxTokens: 64,
25
+ maxRecentMessages: 4,
26
+ };
27
+ export const DEFAULT_CONFIG = {
28
+ enabled: true,
29
+ provider: DEFAULT_MERCURY_CONFIG,
30
+ minChars: 3,
31
+ maxLineLength: 240,
32
+ };
33
+ /**
34
+ * Default per-provider model id when racing. Models chosen for speed; users
35
+ * can override individually with `PI_GHOST_RACE_<NAME>_MODEL`.
36
+ */
37
+ const RACE_DEFAULT_MODELS = {
38
+ groq: "llama-3.1-8b-instant",
39
+ cerebras: "llama-3.1-8b",
40
+ };
41
+ /**
42
+ * Aliases recognized as Mercury Edit (Inception Labs). Limited to the brand
43
+ * name and the specific model version — broader aliases like bare "mercury"
44
+ * or "inception" would lock in a routing that might surprise a user wanting
45
+ * a future model from the same vendor.
46
+ */
47
+ const MERCURY_ALIASES = new Set(["mercury", "mercury-2", "mercury-edit", "mercury-edit-2"]);
48
+ const MERCURY_DEFAULT_BASE_URL = "https://api.inceptionlabs.ai/v1";
49
+ const MERCURY_DEFAULT_MODEL = "mercury-edit-2";
50
+ export function readConfigFromEnv() {
51
+ const raceList = process.env.PI_GHOST_RACE_PROVIDERS;
52
+ const mode = process.env.PI_GHOST_PROVIDER?.toLowerCase();
53
+ const cfg = {
54
+ enabled: process.env.PI_GHOST_DISABLED !== "1",
55
+ provider: raceList
56
+ ? buildRaceFromEnv(raceList)
57
+ : mode === "local"
58
+ ? { ...DEFAULT_LOCAL_CONFIG }
59
+ : mode === "cloud"
60
+ ? { ...DEFAULT_CLOUD_CONFIG }
61
+ : { ...DEFAULT_MERCURY_CONFIG },
62
+ minChars: numEnv("PI_GHOST_MIN_CHARS", DEFAULT_CONFIG.minChars),
63
+ maxLineLength: numEnv("PI_GHOST_MAX_LINE", DEFAULT_CONFIG.maxLineLength),
64
+ };
65
+ if (cfg.provider.kind === "cloud") {
66
+ if (process.env.PI_GHOST_PROVIDER_NAME)
67
+ cfg.provider.provider = process.env.PI_GHOST_PROVIDER_NAME;
68
+ if (process.env.PI_GHOST_MODEL)
69
+ cfg.provider.modelId = process.env.PI_GHOST_MODEL;
70
+ if (process.env.PI_GHOST_API_KEY)
71
+ cfg.provider.apiKey = process.env.PI_GHOST_API_KEY;
72
+ cfg.provider.debounceMs = numEnv("PI_GHOST_DEBOUNCE_MS", cfg.provider.debounceMs);
73
+ cfg.provider.maxTokens = numEnv("PI_GHOST_MAX_TOKENS", cfg.provider.maxTokens);
74
+ cfg.provider.maxRecentMessages = numEnv("PI_GHOST_RECENT", cfg.provider.maxRecentMessages);
75
+ }
76
+ else if (cfg.provider.kind === "openai-compat") {
77
+ if (process.env.PI_GHOST_BASE_URL)
78
+ cfg.provider.baseUrl = process.env.PI_GHOST_BASE_URL;
79
+ else if (process.env.INCEPTION_BASE_URL)
80
+ cfg.provider.baseUrl = process.env.INCEPTION_BASE_URL;
81
+ if (process.env.PI_GHOST_MODEL)
82
+ cfg.provider.modelId = process.env.PI_GHOST_MODEL;
83
+ if (process.env.PI_GHOST_API_KEY)
84
+ cfg.provider.apiKey = process.env.PI_GHOST_API_KEY;
85
+ else if (process.env.INCEPTION_API_KEY)
86
+ cfg.provider.apiKey = process.env.INCEPTION_API_KEY;
87
+ cfg.provider.debounceMs = numEnv("PI_GHOST_DEBOUNCE_MS", cfg.provider.debounceMs);
88
+ cfg.provider.maxTokens = numEnv("PI_GHOST_MAX_TOKENS", cfg.provider.maxTokens);
89
+ cfg.provider.maxRecentMessages = numEnv("PI_GHOST_RECENT", cfg.provider.maxRecentMessages);
90
+ }
91
+ else if (cfg.provider.kind === "local") {
92
+ if (process.env.PI_GHOST_BASE_URL)
93
+ cfg.provider.baseUrl = process.env.PI_GHOST_BASE_URL;
94
+ if (process.env.PI_GHOST_MODEL)
95
+ cfg.provider.modelId = process.env.PI_GHOST_MODEL;
96
+ cfg.provider.debounceMs = numEnv("PI_GHOST_DEBOUNCE_MS", cfg.provider.debounceMs);
97
+ cfg.provider.maxTokens = numEnv("PI_GHOST_MAX_TOKENS", cfg.provider.maxTokens);
98
+ cfg.provider.maxRecentMessages = numEnv("PI_GHOST_RECENT", cfg.provider.maxRecentMessages);
99
+ }
100
+ return cfg;
101
+ }
102
+ function buildRaceFromEnv(raceList) {
103
+ const names = raceList
104
+ .split(",")
105
+ .map((s) => s.trim().toLowerCase())
106
+ .filter((s) => s.length > 0);
107
+ const members = [];
108
+ for (const name of names) {
109
+ const member = buildRaceMember(name);
110
+ if (member)
111
+ members.push(member);
112
+ }
113
+ const pauseMs = numEnv("PI_GHOST_RACE_PAUSE_MS", 400);
114
+ const cooldownMs = numEnv("PI_GHOST_RACE_COOLDOWN_MS", 1500);
115
+ const cutoffMs = numEnv("PI_GHOST_RACE_CUTOFF_MS", 700);
116
+ return {
117
+ kind: "race",
118
+ members,
119
+ pauseMs,
120
+ cooldownMs,
121
+ cutoffMs,
122
+ maxRecentMessages: numEnv("PI_GHOST_RECENT", DEFAULT_CLOUD_CONFIG.maxRecentMessages),
123
+ };
124
+ }
125
+ function buildRaceMember(name) {
126
+ const upper = name.replace(/[^A-Za-z0-9]/g, "_").toUpperCase();
127
+ if (name === "local" || name === "ollama") {
128
+ return {
129
+ ...DEFAULT_LOCAL_CONFIG,
130
+ baseUrl: process.env[`PI_GHOST_RACE_${upper}_BASE_URL`] ?? DEFAULT_LOCAL_CONFIG.baseUrl,
131
+ modelId: process.env[`PI_GHOST_RACE_${upper}_MODEL`] ?? DEFAULT_LOCAL_CONFIG.modelId,
132
+ };
133
+ }
134
+ if (MERCURY_ALIASES.has(name)) {
135
+ const baseUrl = process.env[`PI_GHOST_RACE_${upper}_BASE_URL`] ??
136
+ process.env.INCEPTION_BASE_URL ??
137
+ MERCURY_DEFAULT_BASE_URL;
138
+ const modelId = process.env[`PI_GHOST_RACE_${upper}_MODEL`] ?? MERCURY_DEFAULT_MODEL;
139
+ const apiKey = process.env[`PI_GHOST_RACE_${upper}_API_KEY`] ?? process.env.INCEPTION_API_KEY;
140
+ return {
141
+ kind: "openai-compat",
142
+ providerName: "mercury-edit",
143
+ baseUrl,
144
+ modelId,
145
+ ...(apiKey !== undefined ? { apiKey } : {}),
146
+ debounceMs: DEFAULT_CLOUD_CONFIG.debounceMs,
147
+ maxTokens: DEFAULT_CLOUD_CONFIG.maxTokens,
148
+ maxRecentMessages: DEFAULT_CLOUD_CONFIG.maxRecentMessages,
149
+ };
150
+ }
151
+ const provider = name;
152
+ if (!isKnownCloudProvider(provider)) {
153
+ process.stderr.write(`Pi Ghost: ignoring unknown race provider '${name}' in PI_GHOST_RACE_PROVIDERS\n`);
154
+ return null;
155
+ }
156
+ const modelEnv = process.env[`PI_GHOST_RACE_${upper}_MODEL`];
157
+ const modelId = modelEnv ?? RACE_DEFAULT_MODELS[provider] ?? DEFAULT_CLOUD_CONFIG.modelId;
158
+ const apiKey = process.env[`PI_GHOST_RACE_${upper}_API_KEY`];
159
+ return {
160
+ ...DEFAULT_CLOUD_CONFIG,
161
+ provider,
162
+ modelId,
163
+ ...(apiKey !== undefined ? { apiKey } : {}),
164
+ };
165
+ }
166
+ /**
167
+ * Return true when pi-ai recognizes `name` as a cloud provider with at least
168
+ * one registered model. Used at config-parse time to reject typos in
169
+ * `PI_GHOST_RACE_PROVIDERS` before they cause repeated runtime errors.
170
+ */
171
+ function isKnownCloudProvider(name) {
172
+ try {
173
+ const models = getModels(name);
174
+ return Array.isArray(models) && models.length > 0;
175
+ }
176
+ catch {
177
+ return false;
178
+ }
179
+ }
180
+ function numEnv(name, fallback) {
181
+ const raw = process.env[name];
182
+ if (!raw)
183
+ return fallback;
184
+ const v = Number(raw);
185
+ return Number.isFinite(v) && v >= 0 ? v : fallback;
186
+ }
187
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
3
+ export interface RecentMessage {
4
+ role: "user" | "assistant";
5
+ text: string;
6
+ }
7
+ /**
8
+ * Read up to `max` recent user/assistant messages from the current branch.
9
+ * Returns oldest-first. Tool calls and non-text content are ignored — ghost
10
+ * predictions only need conversational context, not full agent transcripts.
11
+ */
12
+ export declare function getRecentMessages(ctx: ExtensionContext, max: number): RecentMessage[];
13
+ export declare function extractText(msg: AgentMessage): string;
14
+ //# sourceMappingURL=context-aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-aggregator.d.ts","sourceRoot":"","sources":["../src/context-aggregator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAiBrF;AAiBD,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAYrD"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Read up to `max` recent user/assistant messages from the current branch.
3
+ * Returns oldest-first. Tool calls and non-text content are ignored — ghost
4
+ * predictions only need conversational context, not full agent transcripts.
5
+ */
6
+ export function getRecentMessages(ctx, max) {
7
+ if (max <= 0)
8
+ return [];
9
+ const branch = safeBranch(ctx);
10
+ if (!branch)
11
+ return [];
12
+ const out = [];
13
+ for (let i = branch.length - 1; i >= 0 && out.length < max; i--) {
14
+ const entry = branch[i];
15
+ if (!entry || entry.type !== "message")
16
+ continue;
17
+ const role = roleOf(entry.message);
18
+ if (role !== "user" && role !== "assistant")
19
+ continue;
20
+ const text = extractText(entry.message);
21
+ if (!text)
22
+ continue;
23
+ out.push({ role, text });
24
+ }
25
+ out.reverse();
26
+ return out;
27
+ }
28
+ function safeBranch(ctx) {
29
+ try {
30
+ return ctx.sessionManager.getBranch();
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ function roleOf(msg) {
37
+ if (msg && typeof msg === "object" && "role" in msg && typeof msg.role === "string") {
38
+ return msg.role;
39
+ }
40
+ return undefined;
41
+ }
42
+ export function extractText(msg) {
43
+ if (!msg || typeof msg !== "object" || !("content" in msg))
44
+ return "";
45
+ const content = msg.content;
46
+ if (typeof content === "string")
47
+ return content.trim();
48
+ if (!Array.isArray(content))
49
+ return "";
50
+ const parts = [];
51
+ for (const c of content) {
52
+ if (c && typeof c === "object" && "type" in c && c.type === "text" && "text" in c && typeof c.text === "string") {
53
+ parts.push(c.text);
54
+ }
55
+ }
56
+ return parts.join("").trim();
57
+ }
58
+ //# sourceMappingURL=context-aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-aggregator.js","sourceRoot":"","sources":["../src/context-aggregator.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAqB,EAAE,GAAW;IACnE,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvB,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjE,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW;YAAE,SAAS;QACtD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,GAAG,CAAC,OAAO,EAAE,CAAC;IACd,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,UAAU,CAAC,GAAqB;IACxC,IAAI,CAAC;QACJ,OAAO,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,SAAS,MAAM,CAAC,GAAiB;IAChC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrF,OAAO,GAAG,CAAC,IAAI,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAiB;IAC5C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACtE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5B,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjH,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { PathIndex } from "./path-index.js";
2
+ export interface FindFuzzyOptions {
3
+ recentPaths?: Set<string> | null;
4
+ }
5
+ export type FuzzyBand = "basename-prefix" | "fuzzy-basename" | "fuzzy-path";
6
+ export interface FuzzyToken {
7
+ token: string;
8
+ startCol: number;
9
+ hasActionTrigger: boolean;
10
+ insideQuote: boolean;
11
+ }
12
+ export interface FuzzyMatch {
13
+ match: string;
14
+ score: number;
15
+ band: FuzzyBand;
16
+ /** Text to show as appended ghost text. */
17
+ ghost: string;
18
+ /** When true, accept replaces `[startCol, cursor]` with `insert`. Else `ghost` is appended. */
19
+ replace: boolean;
20
+ /** Full replacement text when `replace` is true. */
21
+ insert: string;
22
+ }
23
+ /**
24
+ * Extract a fuzzy-search token from `line` ending at `col`. Returns null when
25
+ * the token is shorter than the minimum length, contains a `/` (path-prefix
26
+ * mode handles slashed tokens), or starts at col 0 with no preceding word.
27
+ *
28
+ * `hasActionTrigger` is true when the word immediately before the token is one
29
+ * of the action verbs that gate medium-confidence fuzzy matches.
30
+ */
31
+ export declare function extractFuzzyToken(line: string, col: number): FuzzyToken | null;
32
+ /**
33
+ * True when `prefix` ends with an action verb followed by whitespace.
34
+ */
35
+ export declare function hasActionTrigger(prefix: string): boolean;
36
+ /**
37
+ * Pick the best fuzzy match for `token` across the index.
38
+ *
39
+ * Scoring bands (per PRD):
40
+ * - basename-prefix: 85 + boosts
41
+ * - fuzzy-basename: 60-80 + boosts
42
+ * - fuzzy-path: 45-70 + boosts
43
+ *
44
+ * Boosts: cwd subtree (+5), shorter paths (up to +5).
45
+ *
46
+ * Caller is responsible for trigger gating (action-word requirement at score
47
+ * 70-84). Scores < 70 should not be shown deterministically.
48
+ */
49
+ export declare function findFuzzyFilename(index: PathIndex, token: string, opts?: FindFuzzyOptions): FuzzyMatch | null;
50
+ //# sourceMappingURL=fuzzy-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy-matcher.d.ts","sourceRoot":"","sources":["../src/fuzzy-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAChC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CACjC;AAsBD,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE5E,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAqB9E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,gBAAqB,GACzB,UAAU,GAAG,IAAI,CAuDnB"}
@@ -0,0 +1,160 @@
1
+ import { recentBoost } from "./recent-paths.js";
2
+ const ACTION_WORDS = new Set([
3
+ "open",
4
+ "edit",
5
+ "read",
6
+ "show",
7
+ "view",
8
+ "find",
9
+ "check",
10
+ "look",
11
+ "load",
12
+ "import",
13
+ "include",
14
+ "see",
15
+ "run",
16
+ ]);
17
+ const FUZZY_CHAR = /[A-Za-z0-9_.\-]/;
18
+ const QUOTE_CHARS = new Set(['"', "'", "`"]);
19
+ const MIN_FUZZY_LEN = 3;
20
+ /**
21
+ * Extract a fuzzy-search token from `line` ending at `col`. Returns null when
22
+ * the token is shorter than the minimum length, contains a `/` (path-prefix
23
+ * mode handles slashed tokens), or starts at col 0 with no preceding word.
24
+ *
25
+ * `hasActionTrigger` is true when the word immediately before the token is one
26
+ * of the action verbs that gate medium-confidence fuzzy matches.
27
+ */
28
+ export function extractFuzzyToken(line, col) {
29
+ if (col < MIN_FUZZY_LEN)
30
+ return null;
31
+ let start = col;
32
+ while (start > 0) {
33
+ const ch = line[start - 1];
34
+ if (!ch || !FUZZY_CHAR.test(ch))
35
+ break;
36
+ start--;
37
+ }
38
+ const token = line.slice(start, col);
39
+ if (token.length < MIN_FUZZY_LEN)
40
+ return null;
41
+ if (token.includes("/"))
42
+ return null;
43
+ const prev = start > 0 ? line[start - 1] : undefined;
44
+ // Skip fuzzy when token sits in a path context (`src/foo`); path-prefix
45
+ // matcher owns slashed tokens.
46
+ if (prev === "/")
47
+ return null;
48
+ return {
49
+ token,
50
+ startCol: start,
51
+ hasActionTrigger: hasActionTrigger(line.slice(0, start)),
52
+ insideQuote: prev !== undefined && QUOTE_CHARS.has(prev),
53
+ };
54
+ }
55
+ /**
56
+ * True when `prefix` ends with an action verb followed by whitespace.
57
+ */
58
+ export function hasActionTrigger(prefix) {
59
+ const m = prefix.match(/(?:^|\s)([A-Za-z]+)\s+$/);
60
+ if (!m || !m[1])
61
+ return false;
62
+ return ACTION_WORDS.has(m[1].toLowerCase());
63
+ }
64
+ /**
65
+ * Pick the best fuzzy match for `token` across the index.
66
+ *
67
+ * Scoring bands (per PRD):
68
+ * - basename-prefix: 85 + boosts
69
+ * - fuzzy-basename: 60-80 + boosts
70
+ * - fuzzy-path: 45-70 + boosts
71
+ *
72
+ * Boosts: cwd subtree (+5), shorter paths (up to +5).
73
+ *
74
+ * Caller is responsible for trigger gating (action-word requirement at score
75
+ * 70-84). Scores < 70 should not be shown deterministically.
76
+ */
77
+ export function findFuzzyFilename(index, token, opts = {}) {
78
+ if (token.length < MIN_FUZZY_LEN)
79
+ return null;
80
+ const lowerToken = token.toLowerCase();
81
+ const cwdRel = relSubtree(index.root, index.cwd);
82
+ const recent = opts.recentPaths ?? null;
83
+ let best = null;
84
+ for (const f of index.files) {
85
+ const bn = basename(f);
86
+ const lowerBn = bn.toLowerCase();
87
+ const inSub = cwdRel === "" || f.startsWith(cwdRel);
88
+ const subBoost = inSub ? 5 : 0;
89
+ const shortBoost = Math.max(0, 5 - Math.floor(f.length / 30));
90
+ const recentBoostV = recentBoost(f, recent);
91
+ let candidate = null;
92
+ if (lowerBn.startsWith(lowerToken)) {
93
+ const score = 85 + subBoost + shortBoost + recentBoostV;
94
+ const suffix = bn.slice(token.length);
95
+ if (suffix) {
96
+ candidate = {
97
+ match: f,
98
+ score,
99
+ band: "basename-prefix",
100
+ ghost: suffix,
101
+ replace: false,
102
+ insert: suffix,
103
+ };
104
+ }
105
+ }
106
+ else if (isSubsequence(lowerToken, lowerBn)) {
107
+ const ratio = token.length / bn.length;
108
+ const score = 60 + Math.floor(ratio * 20) + subBoost + shortBoost + recentBoostV;
109
+ candidate = {
110
+ match: f,
111
+ score,
112
+ band: "fuzzy-basename",
113
+ ghost: f,
114
+ replace: true,
115
+ insert: f,
116
+ };
117
+ }
118
+ else if (isSubsequence(lowerToken, f.toLowerCase())) {
119
+ const ratio = token.length / f.length;
120
+ const score = 45 + Math.floor(ratio * 25) + subBoost + shortBoost + recentBoostV;
121
+ candidate = {
122
+ match: f,
123
+ score,
124
+ band: "fuzzy-path",
125
+ ghost: f,
126
+ replace: true,
127
+ insert: f,
128
+ };
129
+ }
130
+ if (candidate && (!best || candidate.score > best.score)) {
131
+ best = candidate;
132
+ }
133
+ }
134
+ return best;
135
+ }
136
+ function isSubsequence(needle, hay) {
137
+ if (!needle)
138
+ return true;
139
+ let i = 0;
140
+ for (let j = 0; j < hay.length && i < needle.length; j++) {
141
+ if (needle[i] === hay[j])
142
+ i++;
143
+ }
144
+ return i === needle.length;
145
+ }
146
+ function basename(p) {
147
+ const i = p.lastIndexOf("/");
148
+ return i < 0 ? p : p.slice(i + 1);
149
+ }
150
+ function relSubtree(root, cwd) {
151
+ const r = root.replace(/\\/g, "/").replace(/\/+$/, "");
152
+ const c = cwd.replace(/\\/g, "/").replace(/\/+$/, "");
153
+ if (c === r)
154
+ return "";
155
+ const prefix = `${r}/`;
156
+ if (c.startsWith(prefix))
157
+ return `${c.slice(prefix.length)}/`;
158
+ return "";
159
+ }
160
+ //# sourceMappingURL=fuzzy-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy-matcher.js","sourceRoot":"","sources":["../src/fuzzy-matcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC5B,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,QAAQ;IACR,SAAS;IACT,KAAK;IACL,KAAK;CACL,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7C,MAAM,aAAa,GAAG,CAAC,CAAC;AAuBxB;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,GAAW;IAC1D,IAAI,GAAG,GAAG,aAAa;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,KAAK,GAAG,GAAG,CAAC;IAChB,OAAO,KAAK,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,MAAM;QACvC,KAAK,EAAE,CAAC;IACT,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,GAAG,aAAa;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,wEAAwE;IACxE,+BAA+B;IAC/B,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO;QACN,KAAK;QACL,QAAQ,EAAE,KAAK;QACf,gBAAgB,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACxD,WAAW,EAAE,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;KACxD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAgB,EAChB,KAAa,EACb,OAAyB,EAAE;IAE3B,IAAI,KAAK,CAAC,MAAM,GAAG,aAAa;QAAE,OAAO,IAAI,CAAC;IAC9C,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC;IACxC,IAAI,IAAI,GAAsB,IAAI,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,SAAS,GAAsB,IAAI,CAAC;QACxC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,EAAE,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;YACxD,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,MAAM,EAAE,CAAC;gBACZ,SAAS,GAAG;oBACX,KAAK,EAAE,CAAC;oBACR,KAAK;oBACL,IAAI,EAAE,iBAAiB;oBACvB,KAAK,EAAE,MAAM;oBACb,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,MAAM;iBACd,CAAC;YACH,CAAC;QACF,CAAC;aAAM,IAAI,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;YACvC,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;YACjF,SAAS,GAAG;gBACX,KAAK,EAAE,CAAC;gBACR,KAAK;gBACL,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,CAAC;aACT,CAAC;QACH,CAAC;aAAM,IAAI,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtC,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;YACjF,SAAS,GAAG;gBACX,KAAK,EAAE,CAAC;gBACR,KAAK;gBACL,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,CAAC;aACT,CAAC;QACH,CAAC;QACD,IAAI,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,IAAI,GAAG,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,MAAc,EAAE,GAAW;IACjD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1D,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAAE,CAAC,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC;AAC5B,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAW;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;IACvB,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;IAC9D,OAAO,EAAE,CAAC;AACX,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { CustomEditor, type ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import type { KeybindingsManager } from "@earendil-works/pi-coding-agent";
3
+ import { type EditorTheme, type TUI } from "@earendil-works/pi-tui";
4
+ import type { GhostConfig } from "./config.js";
5
+ import type { MetricsLogger } from "./metrics.js";
6
+ import type { PathIndex } from "./path-index.js";
7
+ import type { GhostProvider } from "./providers/types.js";
8
+ export declare class GhostEditor extends CustomEditor {
9
+ private provider;
10
+ private readonly config;
11
+ private readonly extCtx;
12
+ private readonly metrics;
13
+ private readonly onError;
14
+ private pathIndex;
15
+ private ghostText;
16
+ private ghostForText;
17
+ private ghostReplaceFrom;
18
+ private debounceTimer;
19
+ private inflight;
20
+ private lastTextSeen;
21
+ private disposed;
22
+ private shownMetric;
23
+ private recentPaths;
24
+ private recentPathsAt;
25
+ constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, extCtx: ExtensionContext, config: GhostConfig, provider: GhostProvider | null, metrics?: MetricsLogger | null, pathIndex?: PathIndex | null, onError?: ((err: Error) => void) | null);
26
+ setPathIndex(index: PathIndex | null): void;
27
+ setProvider(provider: GhostProvider | null): void;
28
+ dispose(): void;
29
+ handleInput(data: string): void;
30
+ render(width: number): string[];
31
+ private cursorAtEnd;
32
+ private shouldShowGhost;
33
+ private clearGhost;
34
+ private cancelInflight;
35
+ private handleTextChange;
36
+ private tryDeterministic;
37
+ private getRecentPaths;
38
+ private applyDeterministic;
39
+ private replaceTokenAtCursor;
40
+ private requestPrediction;
41
+ private emitMetric;
42
+ private finalizeShown;
43
+ }
44
+ /**
45
+ * Pure helper: replace the slice `[from.col, end-of-line]` on `from.line` of
46
+ * `text` with `replacement`. Exported for testability.
47
+ *
48
+ * Caller must guarantee the cursor sits at end of `from.line` and that the
49
+ * replacement is intended to land there; this helper does not validate.
50
+ */
51
+ export declare function computeReplacement(text: string, from: {
52
+ line: number;
53
+ col: number;
54
+ }, replacement: string): string;
55
+ /**
56
+ * Visible column width of a possibly-ANSI-colored string.
57
+ * Uses string-width which handles wide chars, combining marks, and emoji.
58
+ */
59
+ export declare function visualWidth(s: string): number;
60
+ /**
61
+ * Clip a string to fit in `maxCols` terminal columns, grapheme-aware.
62
+ * Returns the empty string if `maxCols <= 0` or no characters fit.
63
+ */
64
+ export declare function clipToWidth(s: string, maxCols: number): string;
65
+ //# sourceMappingURL=ghost-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ghost-editor.d.ts","sourceRoot":"","sources":["../src/ghost-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAiB,KAAK,WAAW,EAA+B,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAGhH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,KAAK,EAAqC,aAAa,EAAmD,MAAM,cAAc,CAAC;AACtI,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAW1D,qBAAa,WAAY,SAAQ,YAAY;IAC5C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,SAAS,CAAmB;IAEpC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,aAAa,CAAK;gBAGzB,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,kBAAkB,EAC/B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,aAAa,GAAG,IAAI,EAC9B,OAAO,GAAE,aAAa,GAAG,IAAW,EACpC,SAAS,GAAE,SAAS,GAAG,IAAW,EAClC,OAAO,GAAE,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,IAAW;IAY9C,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;IAI3C,WAAW,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI;IAKjD,OAAO,IAAI,IAAI;IAON,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAsC/B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IA8BxC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,oBAAoB;YAgBd,iBAAiB;IA2E/B,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,aAAa;CA0BrB;AAwBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACnC,WAAW,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAY9D"}