koneck 2.33.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +27 -0
- package/dist/engine.js.map +1 -1
- package/dist/lsp.d.ts +110 -0
- package/dist/lsp.d.ts.map +1 -0
- package/dist/lsp.js +473 -0
- package/dist/lsp.js.map +1 -0
- package/dist/router-failure.d.ts +56 -0
- package/dist/router-failure.d.ts.map +1 -0
- package/dist/router-failure.js +118 -0
- package/dist/router-failure.js.map +1 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +71 -0
- package/dist/tools.js.map +1 -1
- package/dist/web/ui-client.d.ts.map +1 -1
- package/dist/web/ui-client.js +261 -54
- package/dist/web/ui-client.js.map +1 -1
- package/dist/web/ui-css.d.ts.map +1 -1
- package/dist/web/ui-css.js +68 -5
- package/dist/web/ui-css.js.map +1 -1
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +9 -1
- package/dist/web/ui.js.map +1 -1
- package/package.json +1 -1
package/dist/lsp.js
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking the language instead of grepping for it.
|
|
3
|
+
*
|
|
4
|
+
* "Where is this defined", "what calls this", "what type is this" are questions with exact answers,
|
|
5
|
+
* and an agent that greps for them gets a list of places the name appears — comments, strings, a
|
|
6
|
+
* different symbol with the same name in another module, and not the definition if it is re-exported.
|
|
7
|
+
* Every wrong entry costs a file read, and the one that matters may not be in the list at all.
|
|
8
|
+
*
|
|
9
|
+
* Two providers, because there is no single one that is both correct and always present:
|
|
10
|
+
*
|
|
11
|
+
* - A real language server, if one is on PATH. Speaks LSP over stdio, works for whatever language
|
|
12
|
+
* the server is for, and is the authority when it exists.
|
|
13
|
+
* - The workspace's own TypeScript, otherwise. A TypeScript or JavaScript project being worked on
|
|
14
|
+
* almost always has `typescript` in its node_modules, and its compiler API answers the same
|
|
15
|
+
* questions with the same precision for those files.
|
|
16
|
+
*
|
|
17
|
+
* KONECK installs with `npm i -g koneck`, so neither is a dependency of KONECK. Requiring a global
|
|
18
|
+
* language-server install would mean the feature was broken on the day most people first tried it,
|
|
19
|
+
* and bundling a compiler for one language would put megabytes into every install to serve some of
|
|
20
|
+
* them. What is present is used; what is absent is reported as absent, which is a usable answer.
|
|
21
|
+
*/
|
|
22
|
+
import { spawn } from 'child_process';
|
|
23
|
+
import { createRequire } from 'module';
|
|
24
|
+
import path from 'path';
|
|
25
|
+
import { existsSync } from 'fs';
|
|
26
|
+
import { readFile } from 'fs/promises';
|
|
27
|
+
/**
|
|
28
|
+
* Servers KONECK knows how to start, in the order they are preferred.
|
|
29
|
+
*
|
|
30
|
+
* Only ones that speak LSP over stdio and need no configuration file to do it: a server that must
|
|
31
|
+
* be configured before it will answer is not something to start behind somebody's back.
|
|
32
|
+
*/
|
|
33
|
+
export const SERVERS = [
|
|
34
|
+
{ command: 'typescript-language-server', args: ['--stdio'],
|
|
35
|
+
extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'], language: 'typescript' },
|
|
36
|
+
{ command: 'pyright-langserver', args: ['--stdio'], extensions: ['.py', '.pyi'], language: 'python' },
|
|
37
|
+
{ command: 'pylsp', args: [], extensions: ['.py', '.pyi'], language: 'python' },
|
|
38
|
+
{ command: 'gopls', args: ['serve'], extensions: ['.go'], language: 'go' },
|
|
39
|
+
{ command: 'rust-analyzer', args: [], extensions: ['.rs'], language: 'rust' },
|
|
40
|
+
{ command: 'clangd', args: [], extensions: ['.c', '.h', '.cc', '.cpp', '.hpp'], language: 'c' },
|
|
41
|
+
{ command: 'jdtls', args: [], extensions: ['.java'], language: 'java' },
|
|
42
|
+
];
|
|
43
|
+
function onPath(command) {
|
|
44
|
+
const dirs = (process.env['PATH'] ?? '').split(path.delimiter).filter(Boolean);
|
|
45
|
+
const exts = process.platform === 'win32'
|
|
46
|
+
? (process.env['PATHEXT'] ?? '.EXE;.CMD;.BAT').split(';')
|
|
47
|
+
: [''];
|
|
48
|
+
return dirs.some(dir => exts.some(ext => existsSync(path.join(dir, command + ext))));
|
|
49
|
+
}
|
|
50
|
+
/** The server for a file, or nothing. */
|
|
51
|
+
export function serverFor(file, has = onPath) {
|
|
52
|
+
const ext = path.extname(file).toLowerCase();
|
|
53
|
+
return SERVERS.find(s => s.extensions.includes(ext) && has(s.command)) ?? null;
|
|
54
|
+
}
|
|
55
|
+
/* ── LSP over stdio ───────────────────────────────────────────────────────────────────────── */
|
|
56
|
+
/**
|
|
57
|
+
* The framing, which is the part that is easy to get subtly wrong.
|
|
58
|
+
*
|
|
59
|
+
* Every message is `Content-Length: N\r\n\r\n` then exactly N BYTES of JSON — bytes, not
|
|
60
|
+
* characters. A header counted in characters truncates the first message containing anything
|
|
61
|
+
* outside ASCII, which in practice means the first identifier with an accent in it.
|
|
62
|
+
*/
|
|
63
|
+
export function frame(message) {
|
|
64
|
+
const body = Buffer.from(JSON.stringify(message), 'utf8');
|
|
65
|
+
return Buffer.concat([Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, 'ascii'), body]);
|
|
66
|
+
}
|
|
67
|
+
/** Pulls whole messages out of a growing buffer, leaving any partial one behind. */
|
|
68
|
+
export function unframe(buffer) {
|
|
69
|
+
const messages = [];
|
|
70
|
+
let rest = buffer;
|
|
71
|
+
for (;;) {
|
|
72
|
+
const split = rest.indexOf('\r\n\r\n');
|
|
73
|
+
if (split === -1)
|
|
74
|
+
break;
|
|
75
|
+
const header = rest.subarray(0, split).toString('ascii');
|
|
76
|
+
const match = /content-length:\s*(\d+)/i.exec(header);
|
|
77
|
+
if (!match) {
|
|
78
|
+
rest = rest.subarray(split + 4);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const length = Number(match[1]);
|
|
82
|
+
const start = split + 4;
|
|
83
|
+
if (rest.length < start + length)
|
|
84
|
+
break; // the body has not all arrived
|
|
85
|
+
try {
|
|
86
|
+
messages.push(JSON.parse(rest.subarray(start, start + length).toString('utf8')));
|
|
87
|
+
}
|
|
88
|
+
catch { /* a malformed body is dropped rather than desynchronising the stream */ }
|
|
89
|
+
rest = Buffer.from(rest.subarray(start + length));
|
|
90
|
+
}
|
|
91
|
+
return { messages, rest };
|
|
92
|
+
}
|
|
93
|
+
const fileUri = (file) => 'file://' + path.resolve(file).split(path.sep).join('/');
|
|
94
|
+
const fromUri = (uri) => decodeURIComponent(uri.replace(/^file:\/\//, ''));
|
|
95
|
+
/** One conversation with one server, for one question. Started, asked, and shut down. */
|
|
96
|
+
class Session {
|
|
97
|
+
root;
|
|
98
|
+
child;
|
|
99
|
+
buffer = Buffer.alloc(0);
|
|
100
|
+
nextId = 1;
|
|
101
|
+
waiting = new Map();
|
|
102
|
+
diagnostics = new Map();
|
|
103
|
+
constructor(spec, root) {
|
|
104
|
+
this.root = root;
|
|
105
|
+
this.child = spawn(spec.command, spec.args, {
|
|
106
|
+
cwd: root, stdio: ['pipe', 'pipe', 'pipe'],
|
|
107
|
+
});
|
|
108
|
+
this.child.stdout.on('data', (chunk) => {
|
|
109
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
110
|
+
const { messages, rest } = unframe(this.buffer);
|
|
111
|
+
this.buffer = Buffer.from(rest);
|
|
112
|
+
for (const message of messages)
|
|
113
|
+
this.receive(message);
|
|
114
|
+
});
|
|
115
|
+
// A server's stderr is its own business; reading it stops the pipe filling and blocking it.
|
|
116
|
+
this.child.stderr.on('data', () => { });
|
|
117
|
+
this.child.on('error', () => { for (const r of this.waiting.values())
|
|
118
|
+
r(null); });
|
|
119
|
+
}
|
|
120
|
+
receive(message) {
|
|
121
|
+
const m = message;
|
|
122
|
+
if (m.method === 'textDocument/publishDiagnostics') {
|
|
123
|
+
const p = m.params;
|
|
124
|
+
if (p?.uri)
|
|
125
|
+
this.diagnostics.set(p.uri, p.diagnostics ?? []);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (typeof m.id === 'number' && this.waiting.has(m.id)) {
|
|
129
|
+
this.waiting.get(m.id)(m.result ?? null);
|
|
130
|
+
this.waiting.delete(m.id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
notify(method, params) {
|
|
134
|
+
try {
|
|
135
|
+
this.child.stdin.write(frame({ jsonrpc: '2.0', method, params }));
|
|
136
|
+
}
|
|
137
|
+
catch { /* gone */ }
|
|
138
|
+
}
|
|
139
|
+
request(method, params, timeoutMs) {
|
|
140
|
+
const id = this.nextId++;
|
|
141
|
+
return new Promise(resolve => {
|
|
142
|
+
const timer = setTimeout(() => { this.waiting.delete(id); resolve(null); }, timeoutMs);
|
|
143
|
+
this.waiting.set(id, value => { clearTimeout(timer); resolve(value); });
|
|
144
|
+
try {
|
|
145
|
+
this.child.stdin.write(frame({ jsonrpc: '2.0', id, method, params }));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
resolve(null);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
diagnosticsFor(uri) { return this.diagnostics.get(uri) ?? []; }
|
|
154
|
+
async start(timeoutMs) {
|
|
155
|
+
const result = await this.request('initialize', {
|
|
156
|
+
processId: process.pid,
|
|
157
|
+
rootUri: fileUri(this.root),
|
|
158
|
+
workspaceFolders: [{ uri: fileUri(this.root), name: path.basename(this.root) }],
|
|
159
|
+
capabilities: {
|
|
160
|
+
textDocument: {
|
|
161
|
+
definition: { linkSupport: true },
|
|
162
|
+
references: {},
|
|
163
|
+
hover: { contentFormat: ['plaintext', 'markdown'] },
|
|
164
|
+
publishDiagnostics: {},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
}, timeoutMs);
|
|
168
|
+
if (result === null)
|
|
169
|
+
return false;
|
|
170
|
+
this.notify('initialized', {});
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
stop() {
|
|
174
|
+
this.notify('shutdown', null);
|
|
175
|
+
this.notify('exit', null);
|
|
176
|
+
// Killed rather than waited for: the answer has already been given, and a server that is slow
|
|
177
|
+
// to exit must not hold up the tool that asked.
|
|
178
|
+
setTimeout(() => { try {
|
|
179
|
+
this.child.kill('SIGKILL');
|
|
180
|
+
}
|
|
181
|
+
catch { /* gone */ } }, 200).unref?.();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** How long a server gets. Generous for a first request, which may include indexing. */
|
|
185
|
+
export const LSP_TIMEOUT_MS = 20_000;
|
|
186
|
+
function locationsFrom(result, source) {
|
|
187
|
+
const raw = Array.isArray(result) ? result : result == null ? [] : [result];
|
|
188
|
+
const out = [];
|
|
189
|
+
for (const item of raw) {
|
|
190
|
+
const r = item;
|
|
191
|
+
const uri = r.uri ?? r.targetUri;
|
|
192
|
+
const start = (r.range ?? r.targetSelectionRange)?.start;
|
|
193
|
+
if (!uri || !start)
|
|
194
|
+
continue;
|
|
195
|
+
out.push({ path: fromUri(uri) || source, line: start.line + 1, column: start.character + 1 });
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
/** Asks a real language server. Returns null when there is none, or it never answered. */
|
|
200
|
+
export async function askServer(kind, file, at, root) {
|
|
201
|
+
const spec = serverFor(file);
|
|
202
|
+
if (!spec)
|
|
203
|
+
return null;
|
|
204
|
+
const session = new Session(spec, root);
|
|
205
|
+
try {
|
|
206
|
+
if (!await session.start(LSP_TIMEOUT_MS))
|
|
207
|
+
return null;
|
|
208
|
+
const text = await readFile(file, 'utf8').catch(() => '');
|
|
209
|
+
const uri = fileUri(file);
|
|
210
|
+
session.notify('textDocument/didOpen', {
|
|
211
|
+
textDocument: { uri, languageId: spec.language, version: 1, text },
|
|
212
|
+
});
|
|
213
|
+
if (kind === 'diagnostics') {
|
|
214
|
+
// Diagnostics arrive unsolicited after didOpen, so this waits rather than asks.
|
|
215
|
+
await new Promise(r => setTimeout(r, 1_500));
|
|
216
|
+
const problems = session.diagnosticsFor(uri).map(d => {
|
|
217
|
+
const p = d;
|
|
218
|
+
const start = p.range?.start ?? { line: 0, character: 0 };
|
|
219
|
+
return {
|
|
220
|
+
path: file, line: start.line + 1, column: start.character + 1,
|
|
221
|
+
severity: (p.severity === 1 ? 'error' : p.severity === 2 ? 'warning' : 'info'),
|
|
222
|
+
message: String(p.message ?? ''),
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
return { kind, via: 'language-server', found: [], problems };
|
|
226
|
+
}
|
|
227
|
+
const method = kind === 'definition' ? 'textDocument/definition'
|
|
228
|
+
: kind === 'references' ? 'textDocument/references'
|
|
229
|
+
: 'textDocument/hover';
|
|
230
|
+
const params = { textDocument: { uri }, position: at };
|
|
231
|
+
if (kind === 'references')
|
|
232
|
+
params['context'] = { includeDeclaration: false };
|
|
233
|
+
const result = await session.request(method, params, LSP_TIMEOUT_MS);
|
|
234
|
+
if (result === null)
|
|
235
|
+
return null;
|
|
236
|
+
if (kind === 'hover') {
|
|
237
|
+
const h = result;
|
|
238
|
+
const contents = h?.contents;
|
|
239
|
+
const info = typeof contents === 'string' ? contents
|
|
240
|
+
: Array.isArray(contents) ? contents.map(c => typeof c === 'string' ? c : String(c.value ?? '')).join('\n')
|
|
241
|
+
: String(contents?.value ?? '');
|
|
242
|
+
return { kind, via: 'language-server', found: [], info: info.trim() };
|
|
243
|
+
}
|
|
244
|
+
return { kind, via: 'language-server', found: locationsFrom(result, file) };
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
session.stop();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/* ── the workspace's own TypeScript ───────────────────────────────────────────────────────── */
|
|
251
|
+
const TS_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'];
|
|
252
|
+
/** The workspace's typescript, if it has one. Never KONECK's: this is about their code. */
|
|
253
|
+
export function workspaceTypeScript(root) {
|
|
254
|
+
try {
|
|
255
|
+
const require = createRequire(path.join(path.resolve(root), 'package.json'));
|
|
256
|
+
return require('typescript');
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* The files the compiler should know about.
|
|
264
|
+
*
|
|
265
|
+
* One file is enough for a definition or a hover — the compiler follows imports from disk as it
|
|
266
|
+
* needs them. It is NOT enough for references, which live in the files that do the referencing: a
|
|
267
|
+
* one-file program answered "0 references" for a function used in eleven places, and a confidently
|
|
268
|
+
* wrong zero is worse than an admission of ignorance. So a references query loads the project's
|
|
269
|
+
* own file list from tsconfig.json, and pays the seconds that costs.
|
|
270
|
+
*/
|
|
271
|
+
function programFiles(ts, root, absolute, wide) {
|
|
272
|
+
if (!wide)
|
|
273
|
+
return [absolute];
|
|
274
|
+
const configPath = ts.findConfigFile(path.resolve(root), ts.sys.fileExists, 'tsconfig.json');
|
|
275
|
+
if (!configPath)
|
|
276
|
+
return [absolute];
|
|
277
|
+
try {
|
|
278
|
+
const read = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
279
|
+
if (read.error)
|
|
280
|
+
return [absolute];
|
|
281
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, path.dirname(configPath));
|
|
282
|
+
// Capped: a repository with tens of thousands of files would spend a minute here, and the
|
|
283
|
+
// answer to "what references this" is not worth a minute.
|
|
284
|
+
const files = parsed.fileNames.slice(0, MAX_PROJECT_FILES);
|
|
285
|
+
return files.includes(absolute) ? files : [absolute, ...files];
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return [absolute];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/** Above this, a references query loads the file alone and says the answer may be partial. */
|
|
292
|
+
export const MAX_PROJECT_FILES = 3_000;
|
|
293
|
+
/**
|
|
294
|
+
* Asks the compiler directly.
|
|
295
|
+
*
|
|
296
|
+
* The program is as small as the question allows: see programFiles.
|
|
297
|
+
*/
|
|
298
|
+
export async function askTypeScript(kind, file, at, root) {
|
|
299
|
+
if (!TS_EXTENSIONS.includes(path.extname(file).toLowerCase()))
|
|
300
|
+
return null;
|
|
301
|
+
const ts = workspaceTypeScript(root);
|
|
302
|
+
if (!ts)
|
|
303
|
+
return null;
|
|
304
|
+
const absolute = path.resolve(file);
|
|
305
|
+
const text = await readFile(absolute, 'utf8').catch(() => null);
|
|
306
|
+
if (text === null)
|
|
307
|
+
return null;
|
|
308
|
+
// Only a references query needs the whole project; everything else is answered from one file.
|
|
309
|
+
const files = programFiles(ts, root, absolute, kind === 'references');
|
|
310
|
+
const host = {
|
|
311
|
+
getScriptFileNames: () => files,
|
|
312
|
+
getScriptVersion: () => '1',
|
|
313
|
+
getScriptSnapshot: name => {
|
|
314
|
+
if (name === absolute)
|
|
315
|
+
return ts.ScriptSnapshot.fromString(text);
|
|
316
|
+
const source = ts.sys.readFile(name);
|
|
317
|
+
return source === undefined ? undefined : ts.ScriptSnapshot.fromString(source);
|
|
318
|
+
},
|
|
319
|
+
getCurrentDirectory: () => path.resolve(root),
|
|
320
|
+
getCompilationSettings: () => ({
|
|
321
|
+
allowJs: true, checkJs: false, target: ts.ScriptTarget.ESNext,
|
|
322
|
+
module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
323
|
+
jsx: ts.JsxEmit.ReactJSX, allowImportingTsExtensions: true, noEmit: true,
|
|
324
|
+
}),
|
|
325
|
+
getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
|
|
326
|
+
fileExists: ts.sys.fileExists,
|
|
327
|
+
readFile: ts.sys.readFile,
|
|
328
|
+
readDirectory: ts.sys.readDirectory,
|
|
329
|
+
directoryExists: ts.sys.directoryExists,
|
|
330
|
+
getDirectories: ts.sys.getDirectories,
|
|
331
|
+
};
|
|
332
|
+
const service = ts.createLanguageService(host, ts.createDocumentRegistry());
|
|
333
|
+
const lines = text.split('\n');
|
|
334
|
+
const offset = lines.slice(0, at.line).reduce((n, l) => n + l.length + 1, 0) + at.character;
|
|
335
|
+
const lineText = (n) => lines[n - 1]?.trim();
|
|
336
|
+
const place = (name, start) => {
|
|
337
|
+
const source = name === absolute ? text : (ts.sys.readFile(name) ?? '');
|
|
338
|
+
const before = source.slice(0, start).split('\n');
|
|
339
|
+
return {
|
|
340
|
+
path: path.relative(path.resolve(root), name) || name,
|
|
341
|
+
line: before.length,
|
|
342
|
+
column: (before.at(-1)?.length ?? 0) + 1,
|
|
343
|
+
...(name === absolute ? { text: lineText(before.length) } : {}),
|
|
344
|
+
};
|
|
345
|
+
};
|
|
346
|
+
if (kind === 'definition') {
|
|
347
|
+
const found = service.getDefinitionAtPosition(absolute, offset) ?? [];
|
|
348
|
+
return { kind, via: 'typescript',
|
|
349
|
+
found: found.map(d => place(d.fileName, d.textSpan.start)) };
|
|
350
|
+
}
|
|
351
|
+
if (kind === 'references') {
|
|
352
|
+
const found = service.getReferencesAtPosition(absolute, offset) ?? [];
|
|
353
|
+
return { kind, via: 'typescript',
|
|
354
|
+
// The declaration comes back in the list. It is not a caller, so it is dropped — by
|
|
355
|
+
// position rather than by a flag, which this TypeScript version does not expose.
|
|
356
|
+
found: found
|
|
357
|
+
.filter(r => !(r.fileName === absolute && r.textSpan.start <= offset
|
|
358
|
+
&& offset < r.textSpan.start + r.textSpan.length))
|
|
359
|
+
.map(r => place(r.fileName, r.textSpan.start)),
|
|
360
|
+
...(files.length === 1
|
|
361
|
+
? { note: 'Answered from this file alone — no tsconfig.json was found, so references in '
|
|
362
|
+
+ 'other files were not visible. Searching the text would be more complete.' }
|
|
363
|
+
: {}) };
|
|
364
|
+
}
|
|
365
|
+
if (kind === 'hover') {
|
|
366
|
+
const info = service.getQuickInfoAtPosition(absolute, offset);
|
|
367
|
+
const parts = info ? ts.displayPartsToString(info.displayParts) : '';
|
|
368
|
+
const doc = info?.documentation ? ts.displayPartsToString(info.documentation) : '';
|
|
369
|
+
return { kind, via: 'typescript', found: [],
|
|
370
|
+
info: [parts, doc].filter(Boolean).join('\n\n') };
|
|
371
|
+
}
|
|
372
|
+
const problems = [
|
|
373
|
+
...service.getSyntacticDiagnostics(absolute),
|
|
374
|
+
...service.getSemanticDiagnostics(absolute),
|
|
375
|
+
].map(d => {
|
|
376
|
+
const start = d.start ?? 0;
|
|
377
|
+
const before = text.slice(0, start).split('\n');
|
|
378
|
+
return {
|
|
379
|
+
path: path.relative(path.resolve(root), absolute) || absolute,
|
|
380
|
+
line: before.length,
|
|
381
|
+
column: (before.at(-1)?.length ?? 0) + 1,
|
|
382
|
+
severity: (d.category === ts.DiagnosticCategory.Error ? 'error'
|
|
383
|
+
: d.category === ts.DiagnosticCategory.Warning ? 'warning' : 'info'),
|
|
384
|
+
message: ts.flattenDiagnosticMessageText(d.messageText, ' '),
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
return { kind, via: 'typescript', found: [], problems };
|
|
388
|
+
}
|
|
389
|
+
/* ── the one question ─────────────────────────────────────────────────────────────────────── */
|
|
390
|
+
/**
|
|
391
|
+
* Finds a symbol's position in a file by name, so a caller need not count characters.
|
|
392
|
+
*
|
|
393
|
+
* A tool call saying "where is `resolveEndpoint` defined" is what an agent can actually produce;
|
|
394
|
+
* a line and character offset is what it would have to guess at.
|
|
395
|
+
*/
|
|
396
|
+
export function findSymbol(text, symbol) {
|
|
397
|
+
const lines = text.split('\n');
|
|
398
|
+
const pattern = new RegExp(`\\b${symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
399
|
+
for (let i = 0; i < lines.length; i++) {
|
|
400
|
+
const line = lines[i];
|
|
401
|
+
// Skip a line that is only a comment: the declaration is what is wanted, and a mention in
|
|
402
|
+
// prose above it is the commonest first match.
|
|
403
|
+
if (/^\s*(\/\/|\*|#)/.test(line))
|
|
404
|
+
continue;
|
|
405
|
+
const match = pattern.exec(line);
|
|
406
|
+
if (match)
|
|
407
|
+
return { line: i, character: match.index };
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* The answer, from whichever provider can give one.
|
|
413
|
+
*
|
|
414
|
+
* A real server first, because it is the authority for its language and knows about the whole
|
|
415
|
+
* project. The compiler second, because it is nearly always there for the files it covers. Neither
|
|
416
|
+
* being available is reported plainly — an agent told "no language support here" greps, which is
|
|
417
|
+
* what it would have done anyway; an agent told nothing assumes an empty answer means no results.
|
|
418
|
+
*/
|
|
419
|
+
export async function ask(kind, file, symbolOrPosition, root) {
|
|
420
|
+
const absolute = path.resolve(root, file);
|
|
421
|
+
if (!existsSync(absolute)) {
|
|
422
|
+
return { kind, via: 'none', found: [], note: `${file} is not a file in this workspace` };
|
|
423
|
+
}
|
|
424
|
+
/*
|
|
425
|
+
* Whether anything can answer at all, before looking for the symbol.
|
|
426
|
+
*
|
|
427
|
+
* The other way round produces a misleading answer: hunting for the symbol first meant a
|
|
428
|
+
* markdown file came back as "nothing does not appear in notes.md" — which is both wrong (the
|
|
429
|
+
* word is right there) and beside the point. It was wrong because findSymbol skips comment lines
|
|
430
|
+
* and `#` opens a comment in most languages but a heading in that one; and beside the point
|
|
431
|
+
* because no provider covers markdown, so the symbol's whereabouts were never the issue.
|
|
432
|
+
*/
|
|
433
|
+
const ext = path.extname(absolute).toLowerCase();
|
|
434
|
+
const supported = serverFor(absolute) !== null
|
|
435
|
+
|| (TS_EXTENSIONS.includes(ext) && workspaceTypeScript(root) !== null);
|
|
436
|
+
if (!supported) {
|
|
437
|
+
return {
|
|
438
|
+
kind, via: 'none', found: [],
|
|
439
|
+
note: TS_EXTENSIONS.includes(ext)
|
|
440
|
+
? `No language support for ${file}: this workspace has no typescript installed and no `
|
|
441
|
+
+ `language server is on PATH. Searching the text is the alternative.`
|
|
442
|
+
: `No language server on PATH for ${ext || 'that kind of file'}. `
|
|
443
|
+
+ `Searching the text is the alternative.`,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
let at;
|
|
447
|
+
if (typeof symbolOrPosition === 'string') {
|
|
448
|
+
const text = await readFile(absolute, 'utf8').catch(() => '');
|
|
449
|
+
const found = findSymbol(text, symbolOrPosition);
|
|
450
|
+
if (!found && kind !== 'diagnostics') {
|
|
451
|
+
return { kind, via: 'none', found: [],
|
|
452
|
+
note: `"${symbolOrPosition}" does not appear in ${file}` };
|
|
453
|
+
}
|
|
454
|
+
at = found ?? { line: 0, character: 0 };
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
at = symbolOrPosition;
|
|
458
|
+
}
|
|
459
|
+
const viaServer = await askServer(kind, absolute, at, root).catch(() => null);
|
|
460
|
+
if (viaServer)
|
|
461
|
+
return viaServer;
|
|
462
|
+
const viaTs = await askTypeScript(kind, absolute, at, root).catch(() => null);
|
|
463
|
+
if (viaTs)
|
|
464
|
+
return viaTs;
|
|
465
|
+
// A provider was available and did not answer — a server that failed to start, or a compiler
|
|
466
|
+
// that could not load the file. Different from "not supported", and worth saying so.
|
|
467
|
+
return {
|
|
468
|
+
kind, via: 'none', found: [],
|
|
469
|
+
note: `Nothing could answer about ${file}: the language support for it is present but did not `
|
|
470
|
+
+ `respond. Searching the text is the alternative.`,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
//# sourceMappingURL=lsp.js.map
|
package/dist/lsp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lsp.js","sourceRoot":"","sources":["../src/lsp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a router's own account of what it tried.
|
|
3
|
+
*
|
|
4
|
+
* A gateway fronting many models reports failure as one message listing every upstream it
|
|
5
|
+
* attempted, which arrives looking like a single opaque error:
|
|
6
|
+
*
|
|
7
|
+
* Stream ended before producing a non-ping SSE event
|
|
8
|
+
* [oc/deepseek-v4-flash-free (400), oc/nemotron-3-ultra-free (502)] (bad_gateway)
|
|
9
|
+
*
|
|
10
|
+
* Treated as one failure that is worth retrying, which is what it looks like, the run retries
|
|
11
|
+
* against the same exhausted pool and then gives up — reported three times in a row by the same
|
|
12
|
+
* person, on the same alias, with the same two models.
|
|
13
|
+
*
|
|
14
|
+
* The list is the useful part, and the status beside each name says something different about each:
|
|
15
|
+
*
|
|
16
|
+
* - 5xx is the upstream being unwell. Retrying can reach a healthy one.
|
|
17
|
+
* - 429 is a quota. Retrying can work once it resets, which is usually seconds.
|
|
18
|
+
* - 4xx other than 429 is the REQUEST being refused, and it will be refused identically every
|
|
19
|
+
* time. On a free model it is almost always the prompt exceeding a context window far smaller
|
|
20
|
+
* than the alias implies. Retrying that is time spent to arrive at the same answer.
|
|
21
|
+
*
|
|
22
|
+
* So a pool where every attempt was refused is not transient, however transient the wrapper says
|
|
23
|
+
* it was, and saying which models failed and how turns "it broke again" into a decision the person
|
|
24
|
+
* can actually make.
|
|
25
|
+
*/
|
|
26
|
+
export interface RouterAttempt {
|
|
27
|
+
model: string;
|
|
28
|
+
status: number;
|
|
29
|
+
}
|
|
30
|
+
export interface RouterFailure {
|
|
31
|
+
attempts: RouterAttempt[];
|
|
32
|
+
/** True when at least one upstream failure could plausibly succeed on another try. */
|
|
33
|
+
worthRetrying: boolean;
|
|
34
|
+
/** What to tell the person, when there is something worth telling them. */
|
|
35
|
+
advice: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The per-model attempts a router listed, if it listed any.
|
|
39
|
+
*
|
|
40
|
+
* Deliberately narrow: it matches a bracketed list of `name (status)` pairs and nothing else,
|
|
41
|
+
* because guessing at the shape of a message from an unknown gateway is how a parser starts
|
|
42
|
+
* inventing failures that never happened.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseRouterAttempts(message: string): RouterAttempt[];
|
|
45
|
+
/** Whether one upstream status could plausibly go differently next time. */
|
|
46
|
+
export declare function statusWorthRetrying(status: number): boolean;
|
|
47
|
+
/** What a status means, in words a person can act on. */
|
|
48
|
+
export declare function describeStatus(status: number): string;
|
|
49
|
+
/**
|
|
50
|
+
* Reads a router failure, if that is what this is.
|
|
51
|
+
*
|
|
52
|
+
* Returns null for anything that does not carry a per-model list, so ordinary errors keep their
|
|
53
|
+
* ordinary handling rather than being re-interpreted by a parser that wanted to find something.
|
|
54
|
+
*/
|
|
55
|
+
export declare function readRouterFailure(message: string): RouterFailure | null;
|
|
56
|
+
//# sourceMappingURL=router-failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-failure.d.ts","sourceRoot":"","sources":["../src/router-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,sFAAsF;IACtF,aAAa,EAAE,OAAO,CAAC;IACvB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAapE;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI3D;AAED,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQrD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAuCvE"}
|