lynkr 7.0.1 → 7.2.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/CLAWROUTER_ROUTING_PLAN.md +910 -0
- package/README.md +41 -7
- package/package.json +9 -5
- package/src/api/health.js +10 -1
- package/src/api/openai-router.js +12 -1
- package/src/budget/index.js +10 -2
- package/src/clients/databricks.js +11 -0
- package/src/clients/ollama-startup.js +120 -0
- package/src/config/index.js +7 -3
- package/src/indexer/babel-parser.js +213 -0
- package/src/indexer/parser.js +126 -49
- package/src/server.js +8 -0
package/src/indexer/parser.js
CHANGED
|
@@ -6,41 +6,74 @@ let JavaScript = null;
|
|
|
6
6
|
let TypeScript = null;
|
|
7
7
|
let TSX = null;
|
|
8
8
|
let Python = null;
|
|
9
|
+
let treeSitterAvailable = null; // null = not checked, true/false = result
|
|
10
|
+
|
|
11
|
+
function isTreeSitterAvailable() {
|
|
12
|
+
if (treeSitterAvailable !== null) {
|
|
13
|
+
return treeSitterAvailable;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
require.resolve("tree-sitter");
|
|
17
|
+
treeSitterAvailable = true;
|
|
18
|
+
logger.info("[Parser] tree-sitter available");
|
|
19
|
+
} catch {
|
|
20
|
+
treeSitterAvailable = false;
|
|
21
|
+
logger.info("[Parser] tree-sitter not available - using babel fallback for JS/TS (Python parsing disabled)");
|
|
22
|
+
}
|
|
23
|
+
return treeSitterAvailable;
|
|
24
|
+
}
|
|
9
25
|
|
|
10
26
|
function getTreeSitterParser() {
|
|
27
|
+
if (!isTreeSitterAvailable()) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
11
30
|
if (!Parser) {
|
|
12
|
-
|
|
31
|
+
try {
|
|
32
|
+
Parser = require("tree-sitter");
|
|
33
|
+
} catch (err) {
|
|
34
|
+
logger.warn({ err: err.message }, "[Parser] Failed to load tree-sitter");
|
|
35
|
+
treeSitterAvailable = false;
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
13
38
|
}
|
|
14
39
|
return Parser;
|
|
15
40
|
}
|
|
16
41
|
|
|
17
42
|
function getLanguageModule(language) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
if (!isTreeSitterAvailable()) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
switch (language) {
|
|
48
|
+
case "javascript":
|
|
49
|
+
case "javascript-react":
|
|
50
|
+
if (!JavaScript) {
|
|
51
|
+
JavaScript = require("tree-sitter-javascript");
|
|
52
|
+
}
|
|
53
|
+
return JavaScript;
|
|
54
|
+
case "typescript":
|
|
55
|
+
if (!TypeScript) {
|
|
56
|
+
const ts = require("tree-sitter-typescript");
|
|
57
|
+
TypeScript = ts.typescript;
|
|
58
|
+
}
|
|
59
|
+
return TypeScript;
|
|
60
|
+
case "typescript-react":
|
|
61
|
+
if (!TSX) {
|
|
62
|
+
const ts = require("tree-sitter-typescript");
|
|
63
|
+
TSX = ts.tsx;
|
|
64
|
+
}
|
|
65
|
+
return TSX;
|
|
66
|
+
case "python":
|
|
67
|
+
if (!Python) {
|
|
68
|
+
Python = require("tree-sitter-python");
|
|
69
|
+
}
|
|
70
|
+
return Python;
|
|
71
|
+
default:
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
logger.warn({ err: err.message, language }, "[Parser] Failed to load language module");
|
|
76
|
+
return null;
|
|
44
77
|
}
|
|
45
78
|
}
|
|
46
79
|
|
|
@@ -55,10 +88,14 @@ const LANGUAGE_MAP = {
|
|
|
55
88
|
};
|
|
56
89
|
|
|
57
90
|
function getParser(languageKey) {
|
|
91
|
+
if (!isTreeSitterAvailable()) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
58
94
|
const entry = LANGUAGE_MAP[languageKey];
|
|
59
95
|
if (!entry) return null;
|
|
60
96
|
if (!parserCache[languageKey]) {
|
|
61
97
|
const ParserClass = getTreeSitterParser();
|
|
98
|
+
if (!ParserClass) return null;
|
|
62
99
|
const parser = new ParserClass();
|
|
63
100
|
const language = entry.getLanguage();
|
|
64
101
|
if (!language) return null;
|
|
@@ -330,37 +367,77 @@ function extractPython(tree, source) {
|
|
|
330
367
|
}
|
|
331
368
|
|
|
332
369
|
function parseFile(relativePath, content, language) {
|
|
370
|
+
// Try tree-sitter first (faster, more accurate)
|
|
333
371
|
const parser = getParser(language);
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
372
|
+
if (parser) {
|
|
373
|
+
try {
|
|
374
|
+
const tree = parser.parse(content);
|
|
375
|
+
const langType = LANGUAGE_MAP[language]?.type;
|
|
376
|
+
if (langType === "javascript" || langType === "typescript") {
|
|
377
|
+
const analysis = extractJavaScript(tree, content);
|
|
378
|
+
return {
|
|
379
|
+
...analysis,
|
|
380
|
+
language: langType,
|
|
381
|
+
definitions: analysis.symbols,
|
|
382
|
+
parser: "tree-sitter",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if (langType === "python") {
|
|
386
|
+
const analysis = extractPython(tree, content);
|
|
387
|
+
return {
|
|
388
|
+
...analysis,
|
|
389
|
+
language: langType,
|
|
390
|
+
definitions: analysis.symbols,
|
|
391
|
+
parser: "tree-sitter",
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
} catch (err) {
|
|
395
|
+
logger.warn({ err, file: relativePath, language }, "Tree-sitter parse failed, trying babel fallback");
|
|
347
396
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Fallback to Babel parser for JS/TS (pure JS, no native modules)
|
|
400
|
+
const langType = LANGUAGE_MAP[language]?.type;
|
|
401
|
+
if (langType === "javascript" || langType === "typescript") {
|
|
402
|
+
try {
|
|
403
|
+
const babelParser = require("./babel-parser");
|
|
404
|
+
const result = babelParser.parseFile(relativePath, content, language);
|
|
405
|
+
if (result) {
|
|
406
|
+
logger.debug({ file: relativePath, parser: "babel" }, "Parsed with babel fallback");
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
} catch (err) {
|
|
410
|
+
logger.debug({ err: err.message }, "Babel parser fallback not available");
|
|
355
411
|
}
|
|
356
|
-
} catch (err) {
|
|
357
|
-
logger.warn({ err, file: relativePath, language }, "Tree-sitter parse failed");
|
|
358
412
|
}
|
|
413
|
+
|
|
359
414
|
return null;
|
|
360
415
|
}
|
|
361
416
|
|
|
417
|
+
/**
|
|
418
|
+
* Get info about available parsers
|
|
419
|
+
*/
|
|
420
|
+
function getParserInfo() {
|
|
421
|
+
const treeSitter = isTreeSitterAvailable();
|
|
422
|
+
let babel = false;
|
|
423
|
+
try {
|
|
424
|
+
const babelParser = require("./babel-parser");
|
|
425
|
+
babel = babelParser.isBabelAvailable();
|
|
426
|
+
} catch {
|
|
427
|
+
babel = false;
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
treeSitter,
|
|
431
|
+
babel,
|
|
432
|
+
jsTs: treeSitter || babel, // JS/TS parsing available
|
|
433
|
+
python: treeSitter, // Python only via tree-sitter
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
362
437
|
module.exports = {
|
|
363
438
|
parseFile,
|
|
364
439
|
LANGUAGE_MAP,
|
|
365
440
|
getParser,
|
|
441
|
+
isTreeSitterAvailable,
|
|
442
|
+
getParserInfo,
|
|
366
443
|
};
|
package/src/server.js
CHANGED
|
@@ -32,6 +32,7 @@ const { initializeHeadroom, shutdownHeadroom, getHeadroomManager } = require("./
|
|
|
32
32
|
const { getWorkerPool, isWorkerPoolReady } = require("./workers/pool");
|
|
33
33
|
const lazyLoader = require("./tools/lazy-loader");
|
|
34
34
|
const { setLazyLoader } = require("./tools");
|
|
35
|
+
const { waitForOllama } = require("./clients/ollama-startup");
|
|
35
36
|
|
|
36
37
|
// Initialize MCP
|
|
37
38
|
initialiseMcp();
|
|
@@ -199,6 +200,13 @@ async function start() {
|
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
const app = createApp();
|
|
203
|
+
|
|
204
|
+
// Wait for Ollama if it's the configured provider or preferred for routing
|
|
205
|
+
const provider = config.modelProvider?.type?.toLowerCase();
|
|
206
|
+
if (provider === "ollama" || config.modelProvider?.preferOllama) {
|
|
207
|
+
await waitForOllama();
|
|
208
|
+
}
|
|
209
|
+
|
|
202
210
|
const server = app.listen(config.port, () => {
|
|
203
211
|
console.log(`Claude→Databricks proxy listening on http://localhost:${config.port}`);
|
|
204
212
|
});
|