trace-mcp 1.6.0 → 1.7.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/cli.js +1210 -318
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +43 -2
- package/dist/index.js +359 -30
- package/dist/index.js.map +1 -1
- package/hooks/trace-mcp-guard.cmd +28 -2
- package/hooks/trace-mcp-guard.sh +29 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -530,8 +530,8 @@ var require_utils = __commonJS({
|
|
|
530
530
|
}
|
|
531
531
|
return output;
|
|
532
532
|
};
|
|
533
|
-
exports.basename = (
|
|
534
|
-
const segs =
|
|
533
|
+
exports.basename = (path108, { windows } = {}) => {
|
|
534
|
+
const segs = path108.split(windows ? /[\\/]/ : "/");
|
|
535
535
|
const last = segs[segs.length - 1];
|
|
536
536
|
if (last === "") {
|
|
537
537
|
return segs[segs.length - 2];
|
|
@@ -1960,7 +1960,7 @@ var require_picomatch = __commonJS({
|
|
|
1960
1960
|
};
|
|
1961
1961
|
picomatch3.isMatch = (str2, patterns, options) => picomatch3(patterns, options)(str2);
|
|
1962
1962
|
picomatch3.parse = (pattern, options) => {
|
|
1963
|
-
if (Array.isArray(pattern)) return pattern.map((
|
|
1963
|
+
if (Array.isArray(pattern)) return pattern.map((p5) => picomatch3.parse(p5, options));
|
|
1964
1964
|
return parse(pattern, { ...options, fastpaths: false });
|
|
1965
1965
|
};
|
|
1966
1966
|
picomatch3.scan = (input, options) => scan(input, options);
|
|
@@ -2083,7 +2083,7 @@ function detectLayerPreset(store) {
|
|
|
2083
2083
|
let matchCount = 0;
|
|
2084
2084
|
for (const layer of layers) {
|
|
2085
2085
|
const hasMatch = layer.path_prefixes.some(
|
|
2086
|
-
(prefix) => paths.some((
|
|
2086
|
+
(prefix) => paths.some((p5) => p5.startsWith(prefix))
|
|
2087
2087
|
);
|
|
2088
2088
|
if (hasMatch) matchCount++;
|
|
2089
2089
|
}
|
|
@@ -2115,9 +2115,9 @@ var init_layer_violations = __esm({
|
|
|
2115
2115
|
});
|
|
2116
2116
|
|
|
2117
2117
|
// src/cli.ts
|
|
2118
|
-
import { Command as
|
|
2119
|
-
import
|
|
2120
|
-
import
|
|
2118
|
+
import { Command as Command12 } from "commander";
|
|
2119
|
+
import path107 from "path";
|
|
2120
|
+
import fs96 from "fs";
|
|
2121
2121
|
import { randomUUID } from "crypto";
|
|
2122
2122
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2123
2123
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -2134,7 +2134,7 @@ var logger = pino({
|
|
|
2134
2134
|
}, process.stderr);
|
|
2135
2135
|
|
|
2136
2136
|
// src/db/schema.ts
|
|
2137
|
-
var SCHEMA_VERSION =
|
|
2137
|
+
var SCHEMA_VERSION = 17;
|
|
2138
2138
|
var DDL = `
|
|
2139
2139
|
-- ============================================================
|
|
2140
2140
|
-- UNIFIED ADDRESS SPACE
|
|
@@ -3015,6 +3015,25 @@ var MIGRATIONS = {
|
|
|
3015
3015
|
AND (json_extract(metadata, '$.extends') IS NOT NULL
|
|
3016
3016
|
OR json_extract(metadata, '$.implements') IS NOT NULL)
|
|
3017
3017
|
`);
|
|
3018
|
+
},
|
|
3019
|
+
17: (db) => {
|
|
3020
|
+
db.exec(`
|
|
3021
|
+
CREATE TABLE IF NOT EXISTS indexing_progress (
|
|
3022
|
+
pipeline TEXT PRIMARY KEY,
|
|
3023
|
+
phase TEXT NOT NULL DEFAULT 'idle',
|
|
3024
|
+
processed INTEGER NOT NULL DEFAULT 0,
|
|
3025
|
+
total INTEGER NOT NULL DEFAULT 0,
|
|
3026
|
+
started_at INTEGER NOT NULL DEFAULT 0,
|
|
3027
|
+
completed_at INTEGER NOT NULL DEFAULT 0,
|
|
3028
|
+
error TEXT,
|
|
3029
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
3030
|
+
)
|
|
3031
|
+
`);
|
|
3032
|
+
db.exec(`
|
|
3033
|
+
INSERT OR IGNORE INTO indexing_progress (pipeline) VALUES ('indexing');
|
|
3034
|
+
INSERT OR IGNORE INTO indexing_progress (pipeline) VALUES ('summarization');
|
|
3035
|
+
INSERT OR IGNORE INTO indexing_progress (pipeline) VALUES ('embedding');
|
|
3036
|
+
`);
|
|
3018
3037
|
}
|
|
3019
3038
|
};
|
|
3020
3039
|
function runMigrations(db, fromVersion) {
|
|
@@ -3129,14 +3148,14 @@ var FileRepository = class {
|
|
|
3129
3148
|
}
|
|
3130
3149
|
db;
|
|
3131
3150
|
_stmts;
|
|
3132
|
-
insertFile(
|
|
3133
|
-
const result = this._stmts.insertFile.run(
|
|
3151
|
+
insertFile(path108, language, contentHash, byteLength, workspace, mtimeMs, createNode) {
|
|
3152
|
+
const result = this._stmts.insertFile.run(path108, language, contentHash, byteLength, workspace, mtimeMs);
|
|
3134
3153
|
const fileId = Number(result.lastInsertRowid);
|
|
3135
3154
|
createNode("file", fileId);
|
|
3136
3155
|
return fileId;
|
|
3137
3156
|
}
|
|
3138
|
-
getFile(
|
|
3139
|
-
return this._stmts.getFile.get(
|
|
3157
|
+
getFile(path108) {
|
|
3158
|
+
return this._stmts.getFile.get(path108);
|
|
3140
3159
|
}
|
|
3141
3160
|
getFileById(id) {
|
|
3142
3161
|
return this._stmts.getFileById.get(id);
|
|
@@ -3366,6 +3385,24 @@ var SymbolRepository = class {
|
|
|
3366
3385
|
updateSymbolSummary(symbolId, summary) {
|
|
3367
3386
|
this.db.prepare("UPDATE symbols SET summary = ? WHERE id = ?").run(summary, symbolId);
|
|
3368
3387
|
}
|
|
3388
|
+
countUnsummarizedSymbols(kinds) {
|
|
3389
|
+
if (kinds.length === 0) return 0;
|
|
3390
|
+
const placeholders = kinds.map(() => "?").join(",");
|
|
3391
|
+
const row = this.db.prepare(`
|
|
3392
|
+
SELECT COUNT(*) as cnt FROM symbols s
|
|
3393
|
+
JOIN files f ON s.file_id = f.id
|
|
3394
|
+
WHERE s.summary IS NULL AND s.kind IN (${placeholders}) AND f.gitignored = 0
|
|
3395
|
+
`).get(...kinds);
|
|
3396
|
+
return row.cnt;
|
|
3397
|
+
}
|
|
3398
|
+
countUnembeddedSymbols() {
|
|
3399
|
+
const row = this.db.prepare(`
|
|
3400
|
+
SELECT COUNT(*) as cnt FROM symbols s
|
|
3401
|
+
LEFT JOIN symbol_embeddings se ON se.symbol_id = s.id
|
|
3402
|
+
WHERE se.symbol_id IS NULL
|
|
3403
|
+
`).get();
|
|
3404
|
+
return row.cnt;
|
|
3405
|
+
}
|
|
3369
3406
|
getUnsummarizedSymbols(kinds, limit) {
|
|
3370
3407
|
if (kinds.length === 0) return [];
|
|
3371
3408
|
const placeholders = kinds.map(() => "?").join(",");
|
|
@@ -3980,9 +4017,9 @@ var Store = class {
|
|
|
3980
4017
|
domain;
|
|
3981
4018
|
analytics;
|
|
3982
4019
|
// --- Files (delegates to FileRepository) ---
|
|
3983
|
-
insertFile(
|
|
4020
|
+
insertFile(path108, language, contentHash, byteLength, workspace, mtimeMs) {
|
|
3984
4021
|
return this.files.insertFile(
|
|
3985
|
-
|
|
4022
|
+
path108,
|
|
3986
4023
|
language,
|
|
3987
4024
|
contentHash,
|
|
3988
4025
|
byteLength,
|
|
@@ -3991,8 +4028,8 @@ var Store = class {
|
|
|
3991
4028
|
(nodeType, refId) => this.graph.createNode(nodeType, refId)
|
|
3992
4029
|
);
|
|
3993
4030
|
}
|
|
3994
|
-
getFile(
|
|
3995
|
-
return this.files.getFile(
|
|
4031
|
+
getFile(path108) {
|
|
4032
|
+
return this.files.getFile(path108);
|
|
3996
4033
|
}
|
|
3997
4034
|
getFileById(id) {
|
|
3998
4035
|
return this.files.getFileById(id);
|
|
@@ -4080,6 +4117,12 @@ var Store = class {
|
|
|
4080
4117
|
updateSymbolSummary(symbolId, summary) {
|
|
4081
4118
|
this.symbols.updateSymbolSummary(symbolId, summary);
|
|
4082
4119
|
}
|
|
4120
|
+
countUnsummarizedSymbols(kinds) {
|
|
4121
|
+
return this.symbols.countUnsummarizedSymbols(kinds);
|
|
4122
|
+
}
|
|
4123
|
+
countUnembeddedSymbols() {
|
|
4124
|
+
return this.symbols.countUnembeddedSymbols();
|
|
4125
|
+
}
|
|
4083
4126
|
getUnsummarizedSymbols(kinds, limit) {
|
|
4084
4127
|
return this.symbols.getUnsummarizedSymbols(kinds, limit);
|
|
4085
4128
|
}
|
|
@@ -4264,7 +4307,7 @@ var PluginRegistry = class {
|
|
|
4264
4307
|
}
|
|
4265
4308
|
getActiveFrameworkPlugins(ctx) {
|
|
4266
4309
|
if (this._activeFrameworkCache) return this._activeFrameworkCache;
|
|
4267
|
-
const active = this.frameworkPlugins.filter((
|
|
4310
|
+
const active = this.frameworkPlugins.filter((p5) => p5.detect(ctx));
|
|
4268
4311
|
this._activeFrameworkCache = this.topologicalSort(active);
|
|
4269
4312
|
return this._activeFrameworkCache;
|
|
4270
4313
|
}
|
|
@@ -4295,8 +4338,8 @@ var PluginRegistry = class {
|
|
|
4295
4338
|
}
|
|
4296
4339
|
topologicalSort(plugins) {
|
|
4297
4340
|
const nameMap = /* @__PURE__ */ new Map();
|
|
4298
|
-
for (const
|
|
4299
|
-
nameMap.set(
|
|
4341
|
+
for (const p5 of plugins) {
|
|
4342
|
+
nameMap.set(p5.manifest.name, p5);
|
|
4300
4343
|
}
|
|
4301
4344
|
const sorted = [];
|
|
4302
4345
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -4346,8 +4389,170 @@ var GLOBAL_CONFIG_PATH = path.join(TRACE_MCP_HOME, ".config.json");
|
|
|
4346
4389
|
var INDEX_DIR = path.join(TRACE_MCP_HOME, "index");
|
|
4347
4390
|
var REGISTRY_PATH = path.join(TRACE_MCP_HOME, "registry.json");
|
|
4348
4391
|
var TOPOLOGY_DB_PATH = path.join(TRACE_MCP_HOME, "topology.db");
|
|
4392
|
+
function stripJsonComments(text) {
|
|
4393
|
+
let result = "";
|
|
4394
|
+
let i = 0;
|
|
4395
|
+
while (i < text.length) {
|
|
4396
|
+
if (text[i] === '"') {
|
|
4397
|
+
const start = i;
|
|
4398
|
+
i++;
|
|
4399
|
+
while (i < text.length && text[i] !== '"') {
|
|
4400
|
+
if (text[i] === "\\") i++;
|
|
4401
|
+
i++;
|
|
4402
|
+
}
|
|
4403
|
+
i++;
|
|
4404
|
+
result += text.slice(start, i);
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
if (text[i] === "/" && text[i + 1] === "/") {
|
|
4408
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
4409
|
+
continue;
|
|
4410
|
+
}
|
|
4411
|
+
result += text[i];
|
|
4412
|
+
i++;
|
|
4413
|
+
}
|
|
4414
|
+
return result.replace(/,(\s*[}\]])/g, "$1");
|
|
4415
|
+
}
|
|
4416
|
+
var DEFAULT_CONFIG_JSONC = `{
|
|
4417
|
+
// \u2500\u2500 AI / Embeddings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4418
|
+
"ai": {
|
|
4419
|
+
"enabled": false,
|
|
4420
|
+
"provider": "ollama", // "ollama" | "openai"
|
|
4421
|
+
// "base_url": "http://localhost:11434", // custom endpoint
|
|
4422
|
+
// "api_key": "", // required for openai; or set OPENAI_API_KEY env
|
|
4423
|
+
// "inference_model": "", // ollama: "gemma4-e4b", openai: "gpt-4o-mini"
|
|
4424
|
+
// "fast_model": "", // ollama: "gemma4-e4b", openai: "gpt-4o-mini"
|
|
4425
|
+
// "embedding_model": "", // ollama: "qwen3-embedding:0.6b", openai: "text-embedding-3-small"
|
|
4426
|
+
// "embedding_dimensions": 1536, // provider-specific
|
|
4427
|
+
"summarize_on_index": true,
|
|
4428
|
+
"summarize_batch_size": 20,
|
|
4429
|
+
"summarize_kinds": ["class", "function", "method", "interface", "trait", "enum", "type"],
|
|
4430
|
+
"concurrency": 1 // match OLLAMA_NUM_PARALLEL for ollama
|
|
4431
|
+
// "reranker_model": "" // optional: e.g. "bge-reranker-v2-m3"
|
|
4432
|
+
},
|
|
4433
|
+
|
|
4434
|
+
// \u2500\u2500 Security \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4435
|
+
"security": {
|
|
4436
|
+
// "secret_patterns": [], // extra regex patterns to detect secrets
|
|
4437
|
+
// "max_file_size_bytes": 1048576, // skip files larger than this (1 MB)
|
|
4438
|
+
// "max_files": 10000 // max files per project
|
|
4439
|
+
},
|
|
4440
|
+
|
|
4441
|
+
// \u2500\u2500 Predictive analysis \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4442
|
+
"predictive": {
|
|
4443
|
+
"enabled": true,
|
|
4444
|
+
"weights": {
|
|
4445
|
+
"bug": { "churn": 0.20, "fix_ratio": 0.20, "complexity": 0.20, "coupling": 0.15, "pagerank": 0.10, "authors": 0.15 },
|
|
4446
|
+
"tech_debt": { "complexity": 0.30, "coupling": 0.25, "test_gap": 0.25, "churn": 0.20 },
|
|
4447
|
+
"change_risk": { "blast_radius": 0.25, "complexity": 0.20, "churn": 0.20, "test_gap": 0.20, "coupling": 0.15 }
|
|
4448
|
+
},
|
|
4449
|
+
"cache_ttl_minutes": 60,
|
|
4450
|
+
"git_since_days": 180,
|
|
4451
|
+
"module_depth": 2
|
|
4452
|
+
},
|
|
4453
|
+
|
|
4454
|
+
// \u2500\u2500 Intent / domain classification \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4455
|
+
"intent": {
|
|
4456
|
+
"enabled": false,
|
|
4457
|
+
// "domain_hints": {}, // { "domain_name": ["path/pattern/**"] }
|
|
4458
|
+
// "custom_domains": [], // [{ "name": "...", "path_patterns": ["..."] }]
|
|
4459
|
+
"auto_classify_on_index": true,
|
|
4460
|
+
"classify_batch_size": 100
|
|
4461
|
+
},
|
|
4462
|
+
|
|
4463
|
+
// \u2500\u2500 Runtime tracing (OpenTelemetry) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4464
|
+
"runtime": {
|
|
4465
|
+
"enabled": false,
|
|
4466
|
+
"otlp": {
|
|
4467
|
+
"port": 4318,
|
|
4468
|
+
"host": "127.0.0.1",
|
|
4469
|
+
"max_body_bytes": 4194304
|
|
4470
|
+
},
|
|
4471
|
+
"retention": {
|
|
4472
|
+
"max_span_age_days": 7,
|
|
4473
|
+
"max_aggregate_age_days": 90,
|
|
4474
|
+
"prune_interval": 100
|
|
4475
|
+
},
|
|
4476
|
+
"mapping": {
|
|
4477
|
+
"fqn_attributes": ["code.function", "code.namespace", "code.filepath"],
|
|
4478
|
+
"route_patterns": ["^(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\\\s+(.+)$"]
|
|
4479
|
+
}
|
|
4480
|
+
},
|
|
4481
|
+
|
|
4482
|
+
// \u2500\u2500 Cross-repo topology \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4483
|
+
"topology": {
|
|
4484
|
+
"enabled": true,
|
|
4485
|
+
// "repos": [], // extra repo paths to federate
|
|
4486
|
+
"auto_detect": true,
|
|
4487
|
+
"auto_federation": true
|
|
4488
|
+
// "contract_globs": [] // globs for API contract files
|
|
4489
|
+
},
|
|
4490
|
+
|
|
4491
|
+
// \u2500\u2500 Quality gates \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4492
|
+
"quality_gates": {
|
|
4493
|
+
"enabled": true,
|
|
4494
|
+
"fail_on": "error", // "error" | "warning" | "none"
|
|
4495
|
+
"rules": {
|
|
4496
|
+
// "max_cyclomatic_complexity": { "threshold": 20, "severity": "error" },
|
|
4497
|
+
// "max_coupling_instability": { "threshold": 0.8, "severity": "warning" },
|
|
4498
|
+
// "max_circular_import_chains": { "threshold": 0, "severity": "error" },
|
|
4499
|
+
// "max_dead_exports_percent": { "threshold": 10, "severity": "warning" },
|
|
4500
|
+
// "max_tech_debt_grade": { "threshold": "C", "severity": "warning" },
|
|
4501
|
+
// "max_security_critical_findings": { "threshold": 0, "severity": "error" },
|
|
4502
|
+
// "max_antipattern_count": { "threshold": 5, "severity": "warning" },
|
|
4503
|
+
// "max_code_smell_count": { "threshold": 10, "severity": "warning" }
|
|
4504
|
+
}
|
|
4505
|
+
},
|
|
4506
|
+
|
|
4507
|
+
// \u2500\u2500 Tool exposure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4508
|
+
"tools": {
|
|
4509
|
+
"preset": "full", // "full" | "minimal" | custom preset name
|
|
4510
|
+
// "include": [], // whitelist specific tools
|
|
4511
|
+
// "exclude": [], // blacklist specific tools
|
|
4512
|
+
// "descriptions": {}, // override tool descriptions
|
|
4513
|
+
"description_verbosity": "full", // "full" | "minimal" | "none"
|
|
4514
|
+
"instructions_verbosity": "full", // "full" | "minimal" | "none"
|
|
4515
|
+
"meta_fields": true // true | false | ["_hints", "_budget_warning", ...]
|
|
4516
|
+
},
|
|
4517
|
+
|
|
4518
|
+
// \u2500\u2500 Indexing ignore rules \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4519
|
+
"ignore": {
|
|
4520
|
+
"directories": [], // extra directory names to skip
|
|
4521
|
+
"patterns": [] // extra gitignore-style patterns
|
|
4522
|
+
},
|
|
4523
|
+
|
|
4524
|
+
// \u2500\u2500 Framework-specific \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4525
|
+
"frameworks": {
|
|
4526
|
+
"laravel": {
|
|
4527
|
+
"artisan": { "enabled": true, "timeout": 10000 },
|
|
4528
|
+
"graceful_degradation": true
|
|
4529
|
+
}
|
|
4530
|
+
},
|
|
4531
|
+
|
|
4532
|
+
// \u2500\u2500 File watcher \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4533
|
+
"watch": {
|
|
4534
|
+
"enabled": true,
|
|
4535
|
+
"debounceMs": 2000
|
|
4536
|
+
},
|
|
4537
|
+
|
|
4538
|
+
// \u2500\u2500 Per-project overrides \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4539
|
+
// Keys are absolute paths; values override any top-level setting for that project.
|
|
4540
|
+
// Example:
|
|
4541
|
+
// "projects": {
|
|
4542
|
+
// "/path/to/project": {
|
|
4543
|
+
// "ai": { "enabled": true, "concurrency": 4 },
|
|
4544
|
+
// "include": ["src/**/*.ts"],
|
|
4545
|
+
// "exclude": ["dist/**"]
|
|
4546
|
+
// }
|
|
4547
|
+
// }
|
|
4548
|
+
"projects": {}
|
|
4549
|
+
}
|
|
4550
|
+
`;
|
|
4349
4551
|
function ensureGlobalDirs() {
|
|
4350
4552
|
fs.mkdirSync(INDEX_DIR, { recursive: true });
|
|
4553
|
+
if (!fs.existsSync(GLOBAL_CONFIG_PATH)) {
|
|
4554
|
+
fs.writeFileSync(GLOBAL_CONFIG_PATH, DEFAULT_CONFIG_JSONC);
|
|
4555
|
+
}
|
|
4351
4556
|
}
|
|
4352
4557
|
function projectHash(absolutePath) {
|
|
4353
4558
|
return crypto.createHash("sha256").update(absolutePath).digest("hex").slice(0, 12);
|
|
@@ -4569,7 +4774,7 @@ var TraceMcpConfigSchema = z.object({
|
|
|
4569
4774
|
function loadGlobalConfigRaw() {
|
|
4570
4775
|
if (!fs2.existsSync(GLOBAL_CONFIG_PATH)) return {};
|
|
4571
4776
|
try {
|
|
4572
|
-
return JSON.parse(fs2.readFileSync(GLOBAL_CONFIG_PATH, "utf-8"));
|
|
4777
|
+
return JSON.parse(stripJsonComments(fs2.readFileSync(GLOBAL_CONFIG_PATH, "utf-8")));
|
|
4573
4778
|
} catch {
|
|
4574
4779
|
return {};
|
|
4575
4780
|
}
|
|
@@ -5025,6 +5230,10 @@ function detectWorkspaces(rootPath) {
|
|
|
5025
5230
|
function buildMultiRootWorkspaces(parentDir, childRoots) {
|
|
5026
5231
|
const workspaces = [];
|
|
5027
5232
|
for (const childRoot of childRoots) {
|
|
5233
|
+
if (!fs4.existsSync(childRoot)) {
|
|
5234
|
+
logger.warn({ childRoot }, "Skipping missing multi-root child directory");
|
|
5235
|
+
continue;
|
|
5236
|
+
}
|
|
5028
5237
|
const relPath = path3.relative(parentDir, childRoot).replace(/\\/g, "/");
|
|
5029
5238
|
const childName = path3.basename(childRoot);
|
|
5030
5239
|
workspaces.push({ name: childName, path: relPath });
|
|
@@ -5943,7 +6152,7 @@ function extractSymbolSource(content, symbolName, symbolKind) {
|
|
|
5943
6152
|
}
|
|
5944
6153
|
let startLine = -1;
|
|
5945
6154
|
for (let i = 0; i < lines.length; i++) {
|
|
5946
|
-
if (patterns.some((
|
|
6155
|
+
if (patterns.some((p5) => p5.test(lines[i]))) {
|
|
5947
6156
|
startLine = i;
|
|
5948
6157
|
break;
|
|
5949
6158
|
}
|
|
@@ -6312,12 +6521,15 @@ var FilePersister = class {
|
|
|
6312
6521
|
}
|
|
6313
6522
|
if (ext.symbols.length > 0) {
|
|
6314
6523
|
const insertedIds = store.insertSymbols(fileId, ext.symbols);
|
|
6315
|
-
const
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6524
|
+
const trigramBySymbolId = /* @__PURE__ */ new Map();
|
|
6525
|
+
for (let i = 0; i < ext.symbols.length; i++) {
|
|
6526
|
+
trigramBySymbolId.set(ext.symbols[i].symbolId, {
|
|
6527
|
+
id: insertedIds[i],
|
|
6528
|
+
name: ext.symbols[i].name,
|
|
6529
|
+
fqn: ext.symbols[i].fqn ?? null
|
|
6530
|
+
});
|
|
6531
|
+
}
|
|
6532
|
+
indexTrigramsBatch(store.db, [...trigramBySymbolId.values()]);
|
|
6321
6533
|
}
|
|
6322
6534
|
if (ext.otherEdges.length > 0) this.storeRawEdges(ext.otherEdges);
|
|
6323
6535
|
if (ext.importEdges.length > 0) {
|
|
@@ -6333,11 +6545,15 @@ var FilePersister = class {
|
|
|
6333
6545
|
for (const fwResult of ext.frameworkExtracts) {
|
|
6334
6546
|
if (fwResult.symbols.length > 0) {
|
|
6335
6547
|
const fwIds = store.insertSymbols(fileId, fwResult.symbols);
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6548
|
+
const fwTrigramBySymbolId = /* @__PURE__ */ new Map();
|
|
6549
|
+
for (let i = 0; i < fwResult.symbols.length; i++) {
|
|
6550
|
+
fwTrigramBySymbolId.set(fwResult.symbols[i].symbolId, {
|
|
6551
|
+
id: fwIds[i],
|
|
6552
|
+
name: fwResult.symbols[i].name,
|
|
6553
|
+
fqn: fwResult.symbols[i].fqn ?? null
|
|
6554
|
+
});
|
|
6555
|
+
}
|
|
6556
|
+
indexTrigramsBatch(store.db, [...fwTrigramBySymbolId.values()]);
|
|
6341
6557
|
}
|
|
6342
6558
|
if (fwResult.edges?.length) {
|
|
6343
6559
|
this.storeRawEdges(fwResult.edges);
|
|
@@ -7398,16 +7614,18 @@ var EnvIndexer = class {
|
|
|
7398
7614
|
|
|
7399
7615
|
// src/indexer/pipeline.ts
|
|
7400
7616
|
var IndexingPipeline = class _IndexingPipeline {
|
|
7401
|
-
constructor(store, registry, config, rootPath) {
|
|
7617
|
+
constructor(store, registry, config, rootPath, progress) {
|
|
7402
7618
|
this.store = store;
|
|
7403
7619
|
this.registry = registry;
|
|
7404
7620
|
this.config = config;
|
|
7405
7621
|
this.rootPath = rootPath;
|
|
7622
|
+
this.progress = progress;
|
|
7406
7623
|
}
|
|
7407
7624
|
store;
|
|
7408
7625
|
registry;
|
|
7409
7626
|
config;
|
|
7410
7627
|
rootPath;
|
|
7628
|
+
progress;
|
|
7411
7629
|
workspaces = [];
|
|
7412
7630
|
_lock = Promise.resolve();
|
|
7413
7631
|
_projectContext;
|
|
@@ -7492,6 +7710,13 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7492
7710
|
errors: 0,
|
|
7493
7711
|
durationMs: 0
|
|
7494
7712
|
};
|
|
7713
|
+
this.progress?.update("indexing", {
|
|
7714
|
+
phase: "running",
|
|
7715
|
+
processed: 0,
|
|
7716
|
+
total: relPaths.length,
|
|
7717
|
+
startedAt: Date.now(),
|
|
7718
|
+
completedAt: 0
|
|
7719
|
+
});
|
|
7495
7720
|
this._projectContext = void 0;
|
|
7496
7721
|
this.registry.clearCaches();
|
|
7497
7722
|
this._changedFileIds.clear();
|
|
@@ -7538,6 +7763,8 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7538
7763
|
persister.persistBatch(extractions);
|
|
7539
7764
|
result.indexed += extractions.length;
|
|
7540
7765
|
}
|
|
7766
|
+
const processed = result.indexed + result.skipped + result.errors;
|
|
7767
|
+
this.progress?.update("indexing", { processed });
|
|
7541
7768
|
}
|
|
7542
7769
|
enableFts5Triggers(this.store.db);
|
|
7543
7770
|
const edgeResolver = new EdgeResolver(this.getPipelineState());
|
|
@@ -7563,6 +7790,11 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7563
7790
|
}
|
|
7564
7791
|
result.durationMs = Date.now() - startMs;
|
|
7565
7792
|
result.incremental = this._isIncremental;
|
|
7793
|
+
this.progress?.update("indexing", {
|
|
7794
|
+
phase: "completed",
|
|
7795
|
+
processed: result.indexed + result.skipped + result.errors,
|
|
7796
|
+
completedAt: Date.now()
|
|
7797
|
+
});
|
|
7566
7798
|
logger.info(result, "Indexing pipeline completed");
|
|
7567
7799
|
return result;
|
|
7568
7800
|
}
|
|
@@ -8158,14 +8390,16 @@ async function hybridSearch(db, query, vectorStore, embeddingService, limit, rer
|
|
|
8158
8390
|
// src/ai/embedding-pipeline.ts
|
|
8159
8391
|
var DEFAULT_BATCH_SIZE = 50;
|
|
8160
8392
|
var EmbeddingPipeline = class {
|
|
8161
|
-
constructor(store, embeddingService, vectorStore) {
|
|
8393
|
+
constructor(store, embeddingService, vectorStore, progress) {
|
|
8162
8394
|
this.store = store;
|
|
8163
8395
|
this.embeddingService = embeddingService;
|
|
8164
8396
|
this.vectorStore = vectorStore;
|
|
8397
|
+
this.progress = progress;
|
|
8165
8398
|
}
|
|
8166
8399
|
store;
|
|
8167
8400
|
embeddingService;
|
|
8168
8401
|
vectorStore;
|
|
8402
|
+
progress;
|
|
8169
8403
|
async indexSymbol(symbolId, text) {
|
|
8170
8404
|
const embedding = await this.embeddingService.embed(text);
|
|
8171
8405
|
if (embedding.length > 0) {
|
|
@@ -8173,10 +8407,48 @@ var EmbeddingPipeline = class {
|
|
|
8173
8407
|
}
|
|
8174
8408
|
}
|
|
8175
8409
|
/**
|
|
8176
|
-
* Find symbols that don't have embeddings yet and embed them.
|
|
8177
|
-
*
|
|
8410
|
+
* Find symbols that don't have embeddings yet and embed them in a loop.
|
|
8411
|
+
* Reports progress and returns the total number of newly embedded symbols.
|
|
8178
8412
|
*/
|
|
8179
8413
|
async indexUnembedded(batchSize = DEFAULT_BATCH_SIZE) {
|
|
8414
|
+
const totalToEmbed = this.store.countUnembeddedSymbols();
|
|
8415
|
+
if (totalToEmbed === 0) return 0;
|
|
8416
|
+
this.progress?.update("embedding", {
|
|
8417
|
+
phase: "running",
|
|
8418
|
+
processed: 0,
|
|
8419
|
+
total: totalToEmbed,
|
|
8420
|
+
startedAt: Date.now(),
|
|
8421
|
+
completedAt: 0
|
|
8422
|
+
});
|
|
8423
|
+
let totalIndexed = 0;
|
|
8424
|
+
try {
|
|
8425
|
+
let batch;
|
|
8426
|
+
do {
|
|
8427
|
+
batch = await this.embedBatch(batchSize);
|
|
8428
|
+
totalIndexed += batch;
|
|
8429
|
+
if (batch > 0) {
|
|
8430
|
+
this.progress?.update("embedding", { processed: totalIndexed });
|
|
8431
|
+
}
|
|
8432
|
+
} while (batch > 0);
|
|
8433
|
+
this.progress?.update("embedding", {
|
|
8434
|
+
phase: "completed",
|
|
8435
|
+
processed: totalIndexed,
|
|
8436
|
+
completedAt: Date.now()
|
|
8437
|
+
});
|
|
8438
|
+
} catch (e) {
|
|
8439
|
+
this.progress?.update("embedding", {
|
|
8440
|
+
phase: "error",
|
|
8441
|
+
error: e instanceof Error ? e.message : String(e)
|
|
8442
|
+
});
|
|
8443
|
+
throw e;
|
|
8444
|
+
}
|
|
8445
|
+
return totalIndexed;
|
|
8446
|
+
}
|
|
8447
|
+
/**
|
|
8448
|
+
* Embed a single batch of unembedded symbols.
|
|
8449
|
+
* Returns the number of symbols embedded in this batch.
|
|
8450
|
+
*/
|
|
8451
|
+
async embedBatch(batchSize) {
|
|
8180
8452
|
const unembedded = this.store.db.prepare(`
|
|
8181
8453
|
SELECT s.id, s.name, s.fqn, s.kind, s.signature, s.summary
|
|
8182
8454
|
FROM symbols s
|
|
@@ -8207,13 +8479,7 @@ var EmbeddingPipeline = class {
|
|
|
8207
8479
|
*/
|
|
8208
8480
|
async reindexAll() {
|
|
8209
8481
|
this.store.db.exec("DELETE FROM symbol_embeddings");
|
|
8210
|
-
|
|
8211
|
-
let batch;
|
|
8212
|
-
do {
|
|
8213
|
-
batch = await this.indexUnembedded(DEFAULT_BATCH_SIZE);
|
|
8214
|
-
total += batch;
|
|
8215
|
-
} while (batch > 0);
|
|
8216
|
-
return total;
|
|
8482
|
+
return this.indexUnembedded(DEFAULT_BATCH_SIZE);
|
|
8217
8483
|
}
|
|
8218
8484
|
};
|
|
8219
8485
|
function buildEmbeddingText(symbol) {
|
|
@@ -8395,31 +8661,53 @@ import fs12 from "fs";
|
|
|
8395
8661
|
import path12 from "path";
|
|
8396
8662
|
var MAX_SOURCE_LINES = 80;
|
|
8397
8663
|
var SummarizationPipeline = class {
|
|
8398
|
-
constructor(store, inferenceService, rootPath, config) {
|
|
8664
|
+
constructor(store, inferenceService, rootPath, config, progress) {
|
|
8399
8665
|
this.store = store;
|
|
8400
8666
|
this.inferenceService = inferenceService;
|
|
8401
8667
|
this.rootPath = rootPath;
|
|
8402
8668
|
this.config = config;
|
|
8669
|
+
this.progress = progress;
|
|
8403
8670
|
}
|
|
8404
8671
|
store;
|
|
8405
8672
|
inferenceService;
|
|
8406
8673
|
rootPath;
|
|
8407
8674
|
config;
|
|
8675
|
+
progress;
|
|
8408
8676
|
async summarizeUnsummarized() {
|
|
8409
8677
|
let totalSummarized = 0;
|
|
8410
8678
|
let batch;
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8679
|
+
const total = this.store.countUnsummarizedSymbols(this.config.kinds);
|
|
8680
|
+
if (total === 0) return 0;
|
|
8681
|
+
this.progress?.update("summarization", {
|
|
8682
|
+
phase: "running",
|
|
8683
|
+
processed: 0,
|
|
8684
|
+
total,
|
|
8685
|
+
startedAt: Date.now(),
|
|
8686
|
+
completedAt: 0
|
|
8687
|
+
});
|
|
8688
|
+
try {
|
|
8689
|
+
do {
|
|
8690
|
+
batch = this.store.getUnsummarizedSymbols(this.config.kinds, this.config.batchSize);
|
|
8691
|
+
if (batch.length === 0) break;
|
|
8692
|
+
const results = await this.summarizeBatch(batch);
|
|
8693
|
+
for (const { id, summary } of results) {
|
|
8694
|
+
this.store.updateSymbolSummary(id, summary);
|
|
8695
|
+
totalSummarized++;
|
|
8696
|
+
}
|
|
8697
|
+
this.progress?.update("summarization", { processed: totalSummarized });
|
|
8698
|
+
logger.debug({ batch: batch.length, total: totalSummarized }, "Summarization batch complete");
|
|
8699
|
+
} while (batch.length === this.config.batchSize);
|
|
8700
|
+
this.progress?.update("summarization", {
|
|
8701
|
+
phase: "completed",
|
|
8702
|
+
processed: totalSummarized,
|
|
8703
|
+
completedAt: Date.now()
|
|
8704
|
+
});
|
|
8705
|
+
} catch (e) {
|
|
8706
|
+
this.progress?.update("summarization", {
|
|
8707
|
+
phase: "error",
|
|
8708
|
+
error: e instanceof Error ? e.message : String(e)
|
|
8709
|
+
});
|
|
8710
|
+
throw e;
|
|
8423
8711
|
}
|
|
8424
8712
|
return totalSummarized;
|
|
8425
8713
|
}
|
|
@@ -9221,8 +9509,8 @@ var SessionJournal = class _SessionJournal {
|
|
|
9221
9509
|
};
|
|
9222
9510
|
this.entries.push(entry);
|
|
9223
9511
|
if (tool === "get_symbol" || tool === "get_outline") {
|
|
9224
|
-
const
|
|
9225
|
-
if (
|
|
9512
|
+
const path108 = params.path ?? params.file_path ?? "";
|
|
9513
|
+
if (path108) this.filesRead.add(path108);
|
|
9226
9514
|
}
|
|
9227
9515
|
if (resultCount === 0 && this.isSearchTool(tool)) {
|
|
9228
9516
|
this.zeroResultQueries.set(hash, summary);
|
|
@@ -9378,7 +9666,7 @@ var SessionJournal = class _SessionJournal {
|
|
|
9378
9666
|
fileReads.set(file, existing);
|
|
9379
9667
|
}
|
|
9380
9668
|
}
|
|
9381
|
-
const focusFiles = [...fileReads.entries()].sort((a, b) => b[1].reads - a[1].reads).slice(0, maxFiles).map(([
|
|
9669
|
+
const focusFiles = [...fileReads.entries()].sort((a, b) => b[1].reads - a[1].reads).slice(0, maxFiles).map(([p5, v]) => ({ path: p5, reads: v.reads, last_tool: v.lastTool }));
|
|
9382
9670
|
const editedSet = /* @__PURE__ */ new Set();
|
|
9383
9671
|
for (const entry of this.entries) {
|
|
9384
9672
|
if (entry.tool === "register_edit") {
|
|
@@ -10009,7 +10297,7 @@ function getIndexHealth(store, config) {
|
|
|
10009
10297
|
}
|
|
10010
10298
|
function getProjectMap(store, registry, summaryOnly, projectContext) {
|
|
10011
10299
|
const stats = store.getStats();
|
|
10012
|
-
const frameworks = registry.getAllFrameworkPlugins().map((
|
|
10300
|
+
const frameworks = registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name);
|
|
10013
10301
|
const detectedVersions = projectContext?.detectedVersions;
|
|
10014
10302
|
if (summaryOnly) {
|
|
10015
10303
|
const languageRows2 = store.db.prepare(
|
|
@@ -10122,7 +10410,7 @@ var W_KIND = 0.15;
|
|
|
10122
10410
|
var W_SIGNATURE = 0.25;
|
|
10123
10411
|
var W_TOKEN = 0.15;
|
|
10124
10412
|
function tokenizeName(name) {
|
|
10125
|
-
const parts = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().split(/[_\-./:]+/).filter((
|
|
10413
|
+
const parts = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().split(/[_\-./:]+/).filter((p5) => p5.length > 1);
|
|
10126
10414
|
return new Set(parts);
|
|
10127
10415
|
}
|
|
10128
10416
|
function jaccard(a, b) {
|
|
@@ -10293,10 +10581,13 @@ function registerCoreTools(server, ctx) {
|
|
|
10293
10581
|
const { store, registry, config, projectRoot, guardPath, j: j3, jh, journal } = ctx;
|
|
10294
10582
|
server.tool(
|
|
10295
10583
|
"get_index_health",
|
|
10296
|
-
"Get index status, statistics, and
|
|
10584
|
+
"Get index status, statistics, health information, and pipeline progress (indexing, summarization, embedding)",
|
|
10297
10585
|
{},
|
|
10298
10586
|
async () => {
|
|
10299
10587
|
const result = getIndexHealth(store, config);
|
|
10588
|
+
if (ctx.progress) {
|
|
10589
|
+
result.progress = ctx.progress.snapshot();
|
|
10590
|
+
}
|
|
10300
10591
|
return { content: [{ type: "text", text: j3(result) }] };
|
|
10301
10592
|
}
|
|
10302
10593
|
);
|
|
@@ -10688,8 +10979,8 @@ function getCoChangesForFile(store, filePath, graphFiles) {
|
|
|
10688
10979
|
function findAffectedTests(store, targetPath, dependentPaths) {
|
|
10689
10980
|
const seen = /* @__PURE__ */ new Set();
|
|
10690
10981
|
const allPaths = [targetPath, ...dependentPaths];
|
|
10691
|
-
for (const
|
|
10692
|
-
const file = store.getFile(
|
|
10982
|
+
for (const p5 of allPaths) {
|
|
10983
|
+
const file = store.getFile(p5);
|
|
10693
10984
|
if (!file) continue;
|
|
10694
10985
|
const fileNodeId = store.getNodeId("file", file.id);
|
|
10695
10986
|
if (fileNodeId != null) {
|
|
@@ -10987,9 +11278,9 @@ function deduplicateByFile(rawDeps) {
|
|
|
10987
11278
|
}
|
|
10988
11279
|
}
|
|
10989
11280
|
const result = [];
|
|
10990
|
-
for (const [
|
|
11281
|
+
for (const [path108, entry] of fileMap) {
|
|
10991
11282
|
const dep = {
|
|
10992
|
-
path:
|
|
11283
|
+
path: path108,
|
|
10993
11284
|
edgeTypes: [...entry.edgeTypes],
|
|
10994
11285
|
depth: entry.depth
|
|
10995
11286
|
};
|
|
@@ -11571,7 +11862,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11571
11862
|
}
|
|
11572
11863
|
primarySymbols.push({ sym, file });
|
|
11573
11864
|
}
|
|
11574
|
-
const primaryInternalIds = primarySymbols.map((
|
|
11865
|
+
const primaryInternalIds = primarySymbols.map((p5) => p5.sym.id);
|
|
11575
11866
|
const primaryNodeMap = store.getNodeIdsBatch("symbol", primaryInternalIds);
|
|
11576
11867
|
const primaryNodeIds = primaryInternalIds.map((id) => primaryNodeMap.get(id)).filter((n) => n != null);
|
|
11577
11868
|
const seenDepIds = new Set(primaryInternalIds);
|
|
@@ -11646,7 +11937,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11646
11937
|
}
|
|
11647
11938
|
}
|
|
11648
11939
|
const primaryItems = primarySymbols.map(
|
|
11649
|
-
(
|
|
11940
|
+
(p5, i) => toContextItem(p5.sym, p5.file, rootPath, 1 - i * 0.01)
|
|
11650
11941
|
);
|
|
11651
11942
|
const depItems = depSymbols.map(
|
|
11652
11943
|
(d, i) => toContextItem(d.sym, d.file, rootPath, 0.8 - i * 5e-3)
|
|
@@ -11662,7 +11953,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11662
11953
|
totalBudget: budget
|
|
11663
11954
|
});
|
|
11664
11955
|
const result = {
|
|
11665
|
-
primary: primarySymbols.map((
|
|
11956
|
+
primary: primarySymbols.map((p5) => toBundleItem(p5.sym, p5.file)),
|
|
11666
11957
|
dependencies: depSymbols.slice(0, assembled.dependencies.length).map((d) => toBundleItem(d.sym, d.file)),
|
|
11667
11958
|
callers: callerSymbols.slice(0, assembled.callers.length).map((c) => toBundleItem(c.sym, c.file)),
|
|
11668
11959
|
totalTokens: assembled.totalTokens,
|
|
@@ -12085,7 +12376,7 @@ function suggestQueries(store) {
|
|
|
12085
12376
|
// src/tools/navigation/related.ts
|
|
12086
12377
|
import { ok as ok4, err as err5 } from "neverthrow";
|
|
12087
12378
|
function tokenizeName2(name) {
|
|
12088
|
-
const parts = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().split(/[_\-.]/).filter((
|
|
12379
|
+
const parts = name.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().split(/[_\-.]/).filter((p5) => p5.length > 1);
|
|
12089
12380
|
return new Set(parts);
|
|
12090
12381
|
}
|
|
12091
12382
|
function jaccard2(a, b) {
|
|
@@ -13459,8 +13750,8 @@ var NestJSPlugin = class {
|
|
|
13459
13750
|
const patterns = extractMicroservicePatterns(source);
|
|
13460
13751
|
if (patterns.length > 0) {
|
|
13461
13752
|
if (!result.routes) result.routes = [];
|
|
13462
|
-
for (const
|
|
13463
|
-
result.routes.push({ method:
|
|
13753
|
+
for (const p5 of patterns) {
|
|
13754
|
+
result.routes.push({ method: p5.type === "message" ? "MSG" : "EVT", uri: p5.pattern });
|
|
13464
13755
|
}
|
|
13465
13756
|
}
|
|
13466
13757
|
}
|
|
@@ -14370,8 +14661,8 @@ function getLivewireContext(store, componentName) {
|
|
|
14370
14661
|
const properties = [];
|
|
14371
14662
|
const actions = [];
|
|
14372
14663
|
if (Array.isArray(meta.properties)) {
|
|
14373
|
-
for (const
|
|
14374
|
-
properties.push({ name: String(
|
|
14664
|
+
for (const p5 of meta.properties) {
|
|
14665
|
+
properties.push({ name: String(p5.name ?? ""), type: p5.type });
|
|
14375
14666
|
}
|
|
14376
14667
|
}
|
|
14377
14668
|
if (Array.isArray(meta.actions)) {
|
|
@@ -15015,18 +15306,18 @@ function getApiSurface(store, filePattern) {
|
|
|
15015
15306
|
};
|
|
15016
15307
|
}
|
|
15017
15308
|
function getPluginRegistry(store, registry, activeFrameworkNames) {
|
|
15018
|
-
const languagePlugins = registry.getLanguagePlugins().map((
|
|
15019
|
-
name:
|
|
15020
|
-
version:
|
|
15021
|
-
priority:
|
|
15022
|
-
extensions:
|
|
15309
|
+
const languagePlugins = registry.getLanguagePlugins().map((p5) => ({
|
|
15310
|
+
name: p5.manifest.name,
|
|
15311
|
+
version: p5.manifest.version,
|
|
15312
|
+
priority: p5.manifest.priority,
|
|
15313
|
+
extensions: p5.supportedExtensions
|
|
15023
15314
|
}));
|
|
15024
|
-
const frameworkPlugins = registry.getAllFrameworkPlugins().map((
|
|
15025
|
-
name:
|
|
15026
|
-
version:
|
|
15027
|
-
priority:
|
|
15028
|
-
dependencies:
|
|
15029
|
-
active: activeFrameworkNames.has(
|
|
15315
|
+
const frameworkPlugins = registry.getAllFrameworkPlugins().map((p5) => ({
|
|
15316
|
+
name: p5.manifest.name,
|
|
15317
|
+
version: p5.manifest.version,
|
|
15318
|
+
priority: p5.manifest.priority,
|
|
15319
|
+
dependencies: p5.manifest.dependencies ?? [],
|
|
15320
|
+
active: activeFrameworkNames.has(p5.manifest.name)
|
|
15030
15321
|
}));
|
|
15031
15322
|
const edgeTypes = store.getEdgeTypes();
|
|
15032
15323
|
return {
|
|
@@ -15569,7 +15860,7 @@ function getComplexityTrend(store, cwd, filePath, options = {}) {
|
|
|
15569
15860
|
function registerAnalysisTools(server, ctx) {
|
|
15570
15861
|
const { store, registry, projectRoot, guardPath, j: j3, jh } = ctx;
|
|
15571
15862
|
const frameworkNames = new Set(
|
|
15572
|
-
registry.getAllFrameworkPlugins().map((
|
|
15863
|
+
registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name)
|
|
15573
15864
|
);
|
|
15574
15865
|
server.tool(
|
|
15575
15866
|
"get_implementations",
|
|
@@ -15879,7 +16170,7 @@ var BARREL_PATTERNS = [
|
|
|
15879
16170
|
];
|
|
15880
16171
|
function isBarrelFile(filePath) {
|
|
15881
16172
|
const base = path30.basename(filePath);
|
|
15882
|
-
return BARREL_PATTERNS.some((
|
|
16173
|
+
return BARREL_PATTERNS.some((p5) => p5.test(base));
|
|
15883
16174
|
}
|
|
15884
16175
|
function buildImportedNamesSet(store) {
|
|
15885
16176
|
const importedNames = /* @__PURE__ */ new Set();
|
|
@@ -17046,7 +17337,7 @@ function detectEmptyFunctions(content, lines, symbols, filePath, language) {
|
|
|
17046
17337
|
const strippedLines = body.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).filter((l) => !/^(?:\/\/|#|--|\/\*|\*\/|\*)\s*$/.test(l));
|
|
17047
17338
|
const joined = strippedLines.join("\n");
|
|
17048
17339
|
const isEmpty = strippedLines.length === 0;
|
|
17049
|
-
const isStub = !isEmpty && strippedLines.length <= 2 && STUB_BODY_PATTERNS.some((
|
|
17340
|
+
const isStub = !isEmpty && strippedLines.length <= 2 && STUB_BODY_PATTERNS.some((p5) => p5.test(joined));
|
|
17050
17341
|
if (isEmpty || isStub) {
|
|
17051
17342
|
const description = isEmpty ? `Empty ${sym.kind} '${sym.name}' \u2014 no implementation` : `Stub ${sym.kind} '${sym.name}' \u2014 placeholder implementation`;
|
|
17052
17343
|
findings.push({
|
|
@@ -17178,8 +17469,8 @@ function detectHardcodedValues(lines, filePath) {
|
|
|
17178
17469
|
return findings;
|
|
17179
17470
|
}
|
|
17180
17471
|
var PRIORITY_ORDER = { high: 0, medium: 1, low: 2 };
|
|
17181
|
-
function priorityRank(
|
|
17182
|
-
return PRIORITY_ORDER[
|
|
17472
|
+
function priorityRank(p5) {
|
|
17473
|
+
return PRIORITY_ORDER[p5];
|
|
17183
17474
|
}
|
|
17184
17475
|
var BATCH_SIZE2 = 100;
|
|
17185
17476
|
var MAX_FILE_SIZE2 = 512 * 1024;
|
|
@@ -17648,8 +17939,8 @@ function interProceduralAnalysis(store, projectRoot, perFileResults, limit) {
|
|
|
17648
17939
|
const sig = sym.signature ?? "";
|
|
17649
17940
|
const paramMatch = sig.match(/\(([^)]*)\)/);
|
|
17650
17941
|
if (paramMatch) {
|
|
17651
|
-
const params = paramMatch[1].split(",").map((
|
|
17652
|
-
const trimmed =
|
|
17942
|
+
const params = paramMatch[1].split(",").map((p5) => {
|
|
17943
|
+
const trimmed = p5.trim();
|
|
17653
17944
|
const parts = trimmed.split(/[\s:]+/);
|
|
17654
17945
|
return parts[0].replace(/^[&*$]/, "").trim();
|
|
17655
17946
|
});
|
|
@@ -17687,7 +17978,7 @@ function taintAnalysis(store, projectRoot, opts = {}) {
|
|
|
17687
17978
|
const sinkFilter = opts.sinks ? new Set(opts.sinks) : null;
|
|
17688
17979
|
const scope = opts.scope?.replace(/\/+$/, "");
|
|
17689
17980
|
const files = scope ? store.db.prepare("SELECT path, language FROM files WHERE path LIKE ? AND (status = 'ok' OR status IS NULL)").all(`${scope}%`) : store.db.prepare("SELECT path, language FROM files WHERE (status = 'ok' OR status IS NULL)").all();
|
|
17690
|
-
const isTest = (
|
|
17981
|
+
const isTest = (p5) => /(?:^|\/)(?:tests?|__tests__|spec)\/|\.(?:test|spec)\.\w+$/.test(p5);
|
|
17691
17982
|
const sourceFiles = files.filter((f) => !isTest(f.path) && f.language);
|
|
17692
17983
|
let allFlows = [];
|
|
17693
17984
|
let analyzed = 0;
|
|
@@ -19210,7 +19501,7 @@ ${bodyLines.join("\n")}`;
|
|
|
19210
19501
|
callSite = `${baseIndent}${functionName}(${paramStr})`;
|
|
19211
19502
|
}
|
|
19212
19503
|
} else if (lang === "go") {
|
|
19213
|
-
const paramStr = params.map((
|
|
19504
|
+
const paramStr = params.map((p5) => `${p5} interface{}`).join(", ");
|
|
19214
19505
|
const returnTypes = returns.length > 0 ? ` (${returns.map(() => "interface{}").join(", ")})` : "";
|
|
19215
19506
|
functionDef = `func ${functionName}(${paramStr})${returnTypes} {
|
|
19216
19507
|
${bodyLines.join("\n")}`;
|
|
@@ -19831,7 +20122,7 @@ CREATE INDEX IF NOT EXISTS idx_client_calls_target ON client_calls(target_repo_i
|
|
|
19831
20122
|
CREATE INDEX IF NOT EXISTS idx_client_calls_endpoint ON client_calls(matched_endpoint_id);
|
|
19832
20123
|
`;
|
|
19833
20124
|
function findBestEndpointMatch(urlPattern, method, endpoints) {
|
|
19834
|
-
const normalize = (
|
|
20125
|
+
const normalize = (p5) => p5.replace(/\{[^}]+\}/g, "{*}").replace(/:[\w]+/g, "{*}").replace(/\/+$/, "");
|
|
19835
20126
|
const normalizedUrl = normalize(urlPattern);
|
|
19836
20127
|
let bestMatch = null;
|
|
19837
20128
|
let bestScore = 0;
|
|
@@ -20205,9 +20496,9 @@ function detectFromDockerCompose(root) {
|
|
|
20205
20496
|
const composeFiles = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
|
|
20206
20497
|
let composePath;
|
|
20207
20498
|
for (const f of composeFiles) {
|
|
20208
|
-
const
|
|
20209
|
-
if (fs25.existsSync(
|
|
20210
|
-
composePath =
|
|
20499
|
+
const p5 = path36.join(root, f);
|
|
20500
|
+
if (fs25.existsSync(p5)) {
|
|
20501
|
+
composePath = p5;
|
|
20211
20502
|
break;
|
|
20212
20503
|
}
|
|
20213
20504
|
}
|
|
@@ -21681,9 +21972,9 @@ var RuntimeAggregator = class {
|
|
|
21681
21972
|
return { bucketsUpdated: rows.length, nodesAffected: nodesAffected.size };
|
|
21682
21973
|
}
|
|
21683
21974
|
};
|
|
21684
|
-
function percentile(sorted,
|
|
21975
|
+
function percentile(sorted, p5) {
|
|
21685
21976
|
if (sorted.length === 0) return 0;
|
|
21686
|
-
const idx = Math.ceil(
|
|
21977
|
+
const idx = Math.ceil(p5 * sorted.length) - 1;
|
|
21687
21978
|
return sorted[Math.max(0, idx)];
|
|
21688
21979
|
}
|
|
21689
21980
|
|
|
@@ -21695,7 +21986,7 @@ var RuntimeIntelligence = class {
|
|
|
21695
21986
|
this.ingester = new SpanIngester(store.db, config.retention.prune_interval);
|
|
21696
21987
|
this.mapper = new SpanMapper(store, {
|
|
21697
21988
|
fqnAttributes: config.mapping.fqn_attributes,
|
|
21698
|
-
routePatterns: config.mapping.route_patterns.map((
|
|
21989
|
+
routePatterns: config.mapping.route_patterns.map((p5) => new RegExp(p5))
|
|
21699
21990
|
});
|
|
21700
21991
|
this.aggregator = new RuntimeAggregator(store.db);
|
|
21701
21992
|
}
|
|
@@ -22878,16 +23169,16 @@ function findShortestPath(store, startNodeId, endNodeId, maxDepth) {
|
|
|
22878
23169
|
parent.set(nodeId, { from, edgeType: edge.edge_type_name });
|
|
22879
23170
|
nextFrontier.push(nodeId);
|
|
22880
23171
|
if (nodeId === endNodeId) {
|
|
22881
|
-
const
|
|
23172
|
+
const path108 = [endNodeId];
|
|
22882
23173
|
const edgeTypes = [];
|
|
22883
23174
|
let cur = endNodeId;
|
|
22884
23175
|
while (cur !== startNodeId) {
|
|
22885
|
-
const
|
|
22886
|
-
|
|
22887
|
-
edgeTypes.unshift(
|
|
22888
|
-
cur =
|
|
23176
|
+
const p5 = parent.get(cur);
|
|
23177
|
+
path108.unshift(p5.from);
|
|
23178
|
+
edgeTypes.unshift(p5.edgeType);
|
|
23179
|
+
cur = p5.from;
|
|
22889
23180
|
}
|
|
22890
|
-
return { path:
|
|
23181
|
+
return { path: path108, edgeTypes };
|
|
22891
23182
|
}
|
|
22892
23183
|
}
|
|
22893
23184
|
}
|
|
@@ -22909,7 +23200,7 @@ function generateMermaid(nodes, edges, paths) {
|
|
|
22909
23200
|
lines.push(` ${id}["${label}"]`);
|
|
22910
23201
|
}
|
|
22911
23202
|
if (paths && paths.length > 0) {
|
|
22912
|
-
const pathSymbols = new Set(paths.flatMap((
|
|
23203
|
+
const pathSymbols = new Set(paths.flatMap((p5) => p5.map((s) => s.symbol_id)));
|
|
22913
23204
|
const pathIds = [...pathSymbols].map((sid) => idMap.get(sid)).filter(Boolean);
|
|
22914
23205
|
if (pathIds.length > 0) {
|
|
22915
23206
|
lines.push(` style ${pathIds.join(",")} fill:#f9f,stroke:#333,stroke-width:2px`);
|
|
@@ -23171,7 +23462,7 @@ function getDataflow(store, projectRoot, opts) {
|
|
|
23171
23462
|
const retMatch = line.match(/\breturn\s+(.+?)(?:;|\s*$)/);
|
|
23172
23463
|
if (retMatch) {
|
|
23173
23464
|
const expr = retMatch[1].trim();
|
|
23174
|
-
const sources = params.map((
|
|
23465
|
+
const sources = params.map((p5) => p5.name).filter((name) => new RegExp(`\\b${escapeRegex3(name)}\\b`).test(expr));
|
|
23175
23466
|
returns.push({ expression: expr, line: absLine, sources });
|
|
23176
23467
|
}
|
|
23177
23468
|
}
|
|
@@ -23182,7 +23473,7 @@ function getDataflow(store, projectRoot, opts) {
|
|
|
23182
23473
|
const assignMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=\s*(.+?)(?:;|\s*$)/);
|
|
23183
23474
|
if (assignMatch) {
|
|
23184
23475
|
const [, varName, source] = assignMatch;
|
|
23185
|
-
const involvesParam = params.some((
|
|
23476
|
+
const involvesParam = params.some((p5) => new RegExp(`\\b${escapeRegex3(p5.name)}\\b`).test(source));
|
|
23186
23477
|
if (involvesParam || /\w+\s*\(/.test(source)) {
|
|
23187
23478
|
localAssignments.push({
|
|
23188
23479
|
name: varName,
|
|
@@ -23209,15 +23500,15 @@ function parseParameters(signature) {
|
|
|
23209
23500
|
if (!match) return [];
|
|
23210
23501
|
const paramStr = match[1].trim();
|
|
23211
23502
|
if (!paramStr) return [];
|
|
23212
|
-
return paramStr.split(",").map((
|
|
23213
|
-
const trimmed =
|
|
23503
|
+
return paramStr.split(",").map((p5) => {
|
|
23504
|
+
const trimmed = p5.trim();
|
|
23214
23505
|
const tsMatch = trimmed.match(/^(\w+)\??\s*:\s*(.+)$/);
|
|
23215
23506
|
if (tsMatch) return { name: tsMatch[1], type: tsMatch[2].trim() };
|
|
23216
23507
|
const pyMatch = trimmed.match(/^(\w+)(?:\s*:\s*(.+))?$/);
|
|
23217
23508
|
if (pyMatch) return { name: pyMatch[1], type: pyMatch[2]?.trim() ?? null };
|
|
23218
23509
|
const word = trimmed.split(/\s/)[0];
|
|
23219
23510
|
return { name: word, type: null };
|
|
23220
|
-
}).filter((
|
|
23511
|
+
}).filter((p5) => p5.name && p5.name !== "...");
|
|
23221
23512
|
}
|
|
23222
23513
|
function buildCalleeMap(store, symbol) {
|
|
23223
23514
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -23848,7 +24139,7 @@ function predictBugs(store, cwd, options = {}) {
|
|
|
23848
24139
|
const couplingMap = /* @__PURE__ */ new Map();
|
|
23849
24140
|
for (const c of couplingResults) couplingMap.set(c.file, c);
|
|
23850
24141
|
const pagerankMap = /* @__PURE__ */ new Map();
|
|
23851
|
-
for (const
|
|
24142
|
+
for (const p5 of pagerankResults) pagerankMap.set(p5.file, p5);
|
|
23852
24143
|
const complexityRows = store.db.prepare(`
|
|
23853
24144
|
SELECT f.path, MAX(s.cyclomatic) as max_cyclomatic
|
|
23854
24145
|
FROM symbols s JOIN files f ON s.file_id = f.id
|
|
@@ -25354,7 +25645,7 @@ function autoLabel(files) {
|
|
|
25354
25645
|
const segments = /* @__PURE__ */ new Map();
|
|
25355
25646
|
const ignore = /* @__PURE__ */ new Set(["src", "lib", "app", "dist", "build", "node_modules", "vendor", "index"]);
|
|
25356
25647
|
for (const file of files) {
|
|
25357
|
-
const parts = file.split("/").filter((
|
|
25648
|
+
const parts = file.split("/").filter((p5) => !ignore.has(p5) && !p5.includes("."));
|
|
25358
25649
|
for (const part of parts) {
|
|
25359
25650
|
segments.set(part, (segments.get(part) ?? 0) + 1);
|
|
25360
25651
|
}
|
|
@@ -26088,8 +26379,8 @@ function getPackageDeps(options) {
|
|
|
26088
26379
|
const manifest = readManifest(absPath);
|
|
26089
26380
|
repoManifests.set(repoPath, manifest);
|
|
26090
26381
|
const allPublishes = [...entry.publishes ?? [], ...manifest.publishes];
|
|
26091
|
-
for (const
|
|
26092
|
-
publishMap.set(
|
|
26382
|
+
for (const p5 of new Set(allPublishes)) {
|
|
26383
|
+
publishMap.set(p5, { repo: entry.name ?? path44.basename(repoPath), repoPath });
|
|
26093
26384
|
}
|
|
26094
26385
|
}
|
|
26095
26386
|
const results = [];
|
|
@@ -26100,8 +26391,8 @@ function getPackageDeps(options) {
|
|
|
26100
26391
|
for (const [repoPath, manifest] of repoManifests) {
|
|
26101
26392
|
const entry = registry[repoPath];
|
|
26102
26393
|
if (entry?.name === project || path44.basename(repoPath) === project) {
|
|
26103
|
-
for (const
|
|
26104
|
-
targetPackages.add(
|
|
26394
|
+
for (const p5 of manifest.publishes) {
|
|
26395
|
+
targetPackages.add(p5);
|
|
26105
26396
|
}
|
|
26106
26397
|
}
|
|
26107
26398
|
}
|
|
@@ -26138,7 +26429,7 @@ function getPackageDeps(options) {
|
|
|
26138
26429
|
for (const [repoPath, manifest] of repoManifests) {
|
|
26139
26430
|
const entry = registry[repoPath];
|
|
26140
26431
|
const repoName = entry?.name ?? path44.basename(repoPath);
|
|
26141
|
-
const isTarget = manifest.publishes.some((
|
|
26432
|
+
const isTarget = manifest.publishes.some((p5) => targetPackages.has(p5));
|
|
26142
26433
|
if (!isTarget && targetPackages.size > 0) continue;
|
|
26143
26434
|
for (const [dep, info] of manifest.deps) {
|
|
26144
26435
|
const publisher = publishMap.get(dep);
|
|
@@ -26674,10 +26965,10 @@ function getScopeFiles(store, scope, scopePath, query, limit) {
|
|
|
26674
26965
|
function buildFileTree(paths) {
|
|
26675
26966
|
const lines = [];
|
|
26676
26967
|
const sorted = paths.sort();
|
|
26677
|
-
for (const
|
|
26678
|
-
const depth =
|
|
26968
|
+
for (const p5 of sorted.slice(0, 200)) {
|
|
26969
|
+
const depth = p5.split("/").length - 1;
|
|
26679
26970
|
const indent = " ".repeat(Math.min(depth, 6));
|
|
26680
|
-
lines.push(`${indent}${path45.basename(
|
|
26971
|
+
lines.push(`${indent}${path45.basename(p5)}`);
|
|
26681
26972
|
}
|
|
26682
26973
|
if (sorted.length > 200) {
|
|
26683
26974
|
lines.push(` ... and ${sorted.length - 200} more files`);
|
|
@@ -27451,10 +27742,10 @@ function getManifestPath() {
|
|
|
27451
27742
|
return path47.join(BUNDLES_DIR, "manifest.json");
|
|
27452
27743
|
}
|
|
27453
27744
|
function loadManifest() {
|
|
27454
|
-
const
|
|
27455
|
-
if (!fs35.existsSync(
|
|
27745
|
+
const p5 = getManifestPath();
|
|
27746
|
+
if (!fs35.existsSync(p5)) return { bundles: [] };
|
|
27456
27747
|
try {
|
|
27457
|
-
return JSON.parse(fs35.readFileSync(
|
|
27748
|
+
return JSON.parse(fs35.readFileSync(p5, "utf-8"));
|
|
27458
27749
|
} catch {
|
|
27459
27750
|
return { bundles: [] };
|
|
27460
27751
|
}
|
|
@@ -27750,8 +28041,8 @@ var AnalyticsStore = class {
|
|
|
27750
28041
|
db;
|
|
27751
28042
|
constructor(dbPath) {
|
|
27752
28043
|
ensureGlobalDirs();
|
|
27753
|
-
const
|
|
27754
|
-
this.db = new Database5(
|
|
28044
|
+
const p5 = dbPath ?? ANALYTICS_DB_PATH;
|
|
28045
|
+
this.db = new Database5(p5);
|
|
27755
28046
|
this.db.pragma("journal_mode = WAL");
|
|
27756
28047
|
this.db.pragma("foreign_keys = OFF");
|
|
27757
28048
|
this.db.exec(SCHEMA_SQL);
|
|
@@ -28740,6 +29031,94 @@ function benchmarkTaskContext(store, symbols, files, count, rand) {
|
|
|
28740
29031
|
});
|
|
28741
29032
|
return buildScenario("composite_task", "NL task \u2192 optimal code context (baseline: search + read 5-8 files + grep)", details);
|
|
28742
29033
|
}
|
|
29034
|
+
function benchmarkFindUsages(store, symbols, count, rand) {
|
|
29035
|
+
const sampled = sample(symbols.filter((s) => s.kind === "function" || s.kind === "method"), count, rand);
|
|
29036
|
+
const details = sampled.map((s) => {
|
|
29037
|
+
const grepMatches = 10;
|
|
29038
|
+
const grepContextLines = 5;
|
|
29039
|
+
const grepChars = grepMatches * grepContextLines * 80;
|
|
29040
|
+
const bl = estimateTokens3(grepChars);
|
|
29041
|
+
const tm = estimateTokens3(grepMatches * 60);
|
|
29042
|
+
return { query: s.name, file: s.file_path, baseline_tokens: bl, trace_mcp_tokens: tm, reduction_pct: reductionPct(bl, tm) };
|
|
29043
|
+
});
|
|
29044
|
+
return buildScenario("find_usages", "All usages of a symbol (baseline: grep with context lines)", details);
|
|
29045
|
+
}
|
|
29046
|
+
function benchmarkContextBundle(store, symbols, count, rand) {
|
|
29047
|
+
const funcs = symbols.filter((s) => s.kind === "function" || s.kind === "method");
|
|
29048
|
+
const batchSize = 3;
|
|
29049
|
+
const batches = Math.min(count, Math.floor(funcs.length / batchSize));
|
|
29050
|
+
const sampled = sample(funcs, batches * batchSize, rand);
|
|
29051
|
+
const details = [];
|
|
29052
|
+
for (let i = 0; i < batches; i++) {
|
|
29053
|
+
const group = sampled.slice(i * batchSize, (i + 1) * batchSize);
|
|
29054
|
+
const totalSourceBytes = group.reduce((s, sym) => s + (sym.source_bytes || Math.round(sym.file_byte_length * 0.08)), 0);
|
|
29055
|
+
const importOverhead = group.length * 200;
|
|
29056
|
+
const bl = estimateTokens3(totalSourceBytes + importOverhead);
|
|
29057
|
+
const tm = estimateTokens3(Math.round((totalSourceBytes + importOverhead) * 0.6));
|
|
29058
|
+
const names = group.map((g) => g.name).join(", ");
|
|
29059
|
+
details.push({ query: names, file: group[0].file_path, baseline_tokens: bl, trace_mcp_tokens: tm, reduction_pct: reductionPct(bl, tm) });
|
|
29060
|
+
}
|
|
29061
|
+
return buildScenario("context_bundle", "Batch symbol+imports lookup (baseline: N \xD7 get_symbol + Read imports)", details);
|
|
29062
|
+
}
|
|
29063
|
+
function benchmarkBatchOverhead(symbols, files, count, rand) {
|
|
29064
|
+
const batchSize = 3;
|
|
29065
|
+
const batches = Math.min(count, Math.floor(symbols.length / batchSize));
|
|
29066
|
+
const sampledSymbols = sample(symbols, batches * batchSize, rand);
|
|
29067
|
+
const details = [];
|
|
29068
|
+
for (let i = 0; i < batches; i++) {
|
|
29069
|
+
const group = sampledSymbols.slice(i * batchSize, (i + 1) * batchSize);
|
|
29070
|
+
const perCallOverhead = 150;
|
|
29071
|
+
const contentTokens = group.reduce((s, sym) => s + estimateTokens3(sym.source_bytes || 200), 0);
|
|
29072
|
+
const bl = contentTokens + batchSize * perCallOverhead;
|
|
29073
|
+
const tm = contentTokens + perCallOverhead;
|
|
29074
|
+
const names = group.map((g) => g.name).join(", ");
|
|
29075
|
+
details.push({ query: names, file: group[0].file_path, baseline_tokens: bl, trace_mcp_tokens: tm, reduction_pct: reductionPct(bl, tm) });
|
|
29076
|
+
}
|
|
29077
|
+
return buildScenario("batch_overhead", "N independent queries batched (baseline: N separate MCP round-trips)", details);
|
|
29078
|
+
}
|
|
29079
|
+
function benchmarkTypeHierarchy(store, symbols, count, rand) {
|
|
29080
|
+
const types = symbols.filter((s) => s.kind === "interface" || s.kind === "class");
|
|
29081
|
+
const sampled = sample(types, count, rand);
|
|
29082
|
+
const details = sampled.map((s) => {
|
|
29083
|
+
const nodeRow = store.db.prepare(
|
|
29084
|
+
"SELECT n.id FROM nodes n JOIN symbols sym ON n.ref_id = sym.id AND n.node_type = ? WHERE sym.symbol_id = ?"
|
|
29085
|
+
).get("symbol", s.symbol_id);
|
|
29086
|
+
let implFileBytes = 0;
|
|
29087
|
+
let implCount = 0;
|
|
29088
|
+
if (nodeRow) {
|
|
29089
|
+
const impls = store.db.prepare(`
|
|
29090
|
+
SELECT DISTINCT f.byte_length FROM edges e
|
|
29091
|
+
JOIN edge_types et ON e.edge_type_id = et.id
|
|
29092
|
+
JOIN nodes n2 ON e.source_node_id = n2.id AND n2.node_type = 'symbol'
|
|
29093
|
+
JOIN symbols s2 ON n2.ref_id = s2.id
|
|
29094
|
+
JOIN files f ON s2.file_id = f.id
|
|
29095
|
+
WHERE e.target_node_id = ?
|
|
29096
|
+
AND et.name IN ('implements', 'extends')
|
|
29097
|
+
LIMIT 10
|
|
29098
|
+
`).all(nodeRow.id);
|
|
29099
|
+
implFileBytes = impls.reduce((sum, d) => sum + (d.byte_length || 0), 0);
|
|
29100
|
+
implCount = impls.length;
|
|
29101
|
+
}
|
|
29102
|
+
const grepChars = Math.max(implCount, 3) * 5 * 80;
|
|
29103
|
+
const readChars = implFileBytes || s.file_byte_length * 3;
|
|
29104
|
+
const bl = estimateTokens3(grepChars + readChars);
|
|
29105
|
+
const tm = estimateTokens3(Math.max(implCount, 3) * 120);
|
|
29106
|
+
return { query: s.name, file: s.file_path, baseline_tokens: bl, trace_mcp_tokens: tm, reduction_pct: reductionPct(bl, tm) };
|
|
29107
|
+
});
|
|
29108
|
+
return buildScenario("type_hierarchy", "Find all implementations of interface/class (baseline: grep + read files)", details);
|
|
29109
|
+
}
|
|
29110
|
+
function benchmarkTestsFor(store, symbols, count, rand) {
|
|
29111
|
+
const sampled = sample(symbols.filter((s) => s.kind === "function" || s.kind === "method"), count, rand);
|
|
29112
|
+
const details = sampled.map((s) => {
|
|
29113
|
+
const globTokens = 200;
|
|
29114
|
+
const grepTokens = 3 * 5 * 80 / 3.5;
|
|
29115
|
+
const testFileReadTokens = 2 * estimateTokens3(3e3);
|
|
29116
|
+
const bl = Math.round(globTokens + grepTokens + testFileReadTokens);
|
|
29117
|
+
const tm = estimateTokens3(400);
|
|
29118
|
+
return { query: s.name, file: s.file_path, baseline_tokens: bl, trace_mcp_tokens: tm, reduction_pct: reductionPct(bl, tm) };
|
|
29119
|
+
});
|
|
29120
|
+
return buildScenario("tests_for", "Find tests for a symbol (baseline: glob + grep + read test files)", details);
|
|
29121
|
+
}
|
|
28743
29122
|
function runBenchmark(store, opts = {}) {
|
|
28744
29123
|
const n = opts.queries ?? 10;
|
|
28745
29124
|
const rand = seededRandom(opts.seed ?? 42);
|
|
@@ -28749,8 +29128,13 @@ function runBenchmark(store, opts = {}) {
|
|
|
28749
29128
|
benchmarkSymbolLookup(symbols, n, rand),
|
|
28750
29129
|
benchmarkFileExploration(files, n, rand),
|
|
28751
29130
|
benchmarkSearch(symbols, n, rand),
|
|
29131
|
+
benchmarkFindUsages(store, symbols, n, rand),
|
|
29132
|
+
benchmarkContextBundle(store, symbols, n, rand),
|
|
29133
|
+
benchmarkBatchOverhead(symbols, files, n, rand),
|
|
28752
29134
|
benchmarkImpactAnalysis(store, symbols, n, rand),
|
|
28753
29135
|
benchmarkCallGraph(store, symbols, n, rand),
|
|
29136
|
+
benchmarkTypeHierarchy(store, symbols, n, rand),
|
|
29137
|
+
benchmarkTestsFor(store, symbols, n, rand),
|
|
28754
29138
|
benchmarkTaskContext(store, symbols, files, n, rand)
|
|
28755
29139
|
];
|
|
28756
29140
|
const totalQueries = scenarios.reduce((s, sc) => s + sc.queries, 0);
|
|
@@ -29318,11 +29702,11 @@ function registerPrompts(server, ctx) {
|
|
|
29318
29702
|
sections.push("");
|
|
29319
29703
|
}
|
|
29320
29704
|
}
|
|
29321
|
-
const deadCode = safe2(() => getDeadCodeV2(store, { threshold: 0.5, limit: 10 }), {
|
|
29322
|
-
if (deadCode.
|
|
29323
|
-
sections.push(`## Dead Code Candidates (${deadCode.
|
|
29705
|
+
const deadCode = safe2(() => getDeadCodeV2(store, { threshold: 0.5, limit: 10 }), { dead_symbols: [], file_pattern: null, total_exports: 0, total_dead: 0, threshold: 0.5 });
|
|
29706
|
+
if (deadCode.dead_symbols && deadCode.dead_symbols.length > 0) {
|
|
29707
|
+
sections.push(`## Dead Code Candidates (${deadCode.dead_symbols.length})
|
|
29324
29708
|
`);
|
|
29325
|
-
for (const d of deadCode.
|
|
29709
|
+
for (const d of deadCode.dead_symbols.slice(0, 5)) {
|
|
29326
29710
|
sections.push(`- ${d.name} in ${d.file} (confidence: ${d.confidence})`);
|
|
29327
29711
|
}
|
|
29328
29712
|
sections.push("");
|
|
@@ -29361,10 +29745,10 @@ Provide a thorough code review with risk assessment, suggested tests, and archit
|
|
|
29361
29745
|
sections.push("```json");
|
|
29362
29746
|
sections.push(JSON.stringify(map, null, 2));
|
|
29363
29747
|
sections.push("```\n");
|
|
29364
|
-
const health = safe2(() => getRepoHealth(store),
|
|
29748
|
+
const health = safe2(() => getRepoHealth(store), null);
|
|
29365
29749
|
sections.push("## Architecture Health\n");
|
|
29366
|
-
sections.push(`-
|
|
29367
|
-
sections.push(`- Dependency cycles: ${health
|
|
29750
|
+
sections.push(`- Files in graph: ${health?.summary?.files_in_graph ?? "N/A"}`);
|
|
29751
|
+
sections.push(`- Dependency cycles: ${health?.cycles?.length ?? 0}`);
|
|
29368
29752
|
sections.push("");
|
|
29369
29753
|
sections.push("## Key Entry Points\n");
|
|
29370
29754
|
const context = safe2(() => getFeatureContext(store, projectRoot, "main entry point application startup", 4e3), { symbols: [] });
|
|
@@ -29447,7 +29831,7 @@ Analyze this bug. Identify the most likely failure point, suggest debugging step
|
|
|
29447
29831
|
sections.push(`## Dependency Cycles: ${cycles.length}
|
|
29448
29832
|
`);
|
|
29449
29833
|
for (const c of cycles.slice(0, 5)) {
|
|
29450
|
-
sections.push(`- ${c.join(" \u2192 ")}`);
|
|
29834
|
+
sections.push(`- ${c.files.join(" \u2192 ")}`);
|
|
29451
29835
|
}
|
|
29452
29836
|
sections.push("");
|
|
29453
29837
|
const debt = safe2(() => getTechDebt(store, projectRoot, {
|
|
@@ -29528,11 +29912,11 @@ Analyze this project's architecture health. Identify the most critical issues an
|
|
|
29528
29912
|
sections.push(...riskFiles);
|
|
29529
29913
|
sections.push("");
|
|
29530
29914
|
}
|
|
29531
|
-
const dead = safe2(() => getDeadCodeV2(store, { threshold: 0.6, limit: 10 }), {
|
|
29532
|
-
if (dead.
|
|
29533
|
-
sections.push(`## Potential Dead Code: ${dead.
|
|
29915
|
+
const dead = safe2(() => getDeadCodeV2(store, { threshold: 0.6, limit: 10 }), { dead_symbols: [], file_pattern: null, total_exports: 0, total_dead: 0, threshold: 0.6 });
|
|
29916
|
+
if (dead.dead_symbols && dead.dead_symbols.length > 0) {
|
|
29917
|
+
sections.push(`## Potential Dead Code: ${dead.dead_symbols.length}
|
|
29534
29918
|
`);
|
|
29535
|
-
for (const d of dead.
|
|
29919
|
+
for (const d of dead.dead_symbols.slice(0, 5)) {
|
|
29536
29920
|
sections.push(`- ${d.name} (${d.file})`);
|
|
29537
29921
|
}
|
|
29538
29922
|
sections.push("");
|
|
@@ -29873,7 +30257,7 @@ function registerSessionTools(server, ctx) {
|
|
|
29873
30257
|
}
|
|
29874
30258
|
|
|
29875
30259
|
// src/server/server.ts
|
|
29876
|
-
var PKG_VERSION = true ? "1.
|
|
30260
|
+
var PKG_VERSION = true ? "1.7.0" : "0.0.0-dev";
|
|
29877
30261
|
function j2(value) {
|
|
29878
30262
|
return JSON.stringify(value, (_key, val) => val === null || val === void 0 ? void 0 : val);
|
|
29879
30263
|
}
|
|
@@ -29977,10 +30361,10 @@ function extractCompactResult(toolName, response) {
|
|
|
29977
30361
|
return void 0;
|
|
29978
30362
|
}
|
|
29979
30363
|
}
|
|
29980
|
-
function createServer2(store, registry, config, rootPath) {
|
|
30364
|
+
function createServer2(store, registry, config, rootPath, progress) {
|
|
29981
30365
|
const projectRoot = rootPath ?? process.cwd();
|
|
29982
30366
|
const frameworkNames = new Set(
|
|
29983
|
-
registry.getAllFrameworkPlugins().map((
|
|
30367
|
+
registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name)
|
|
29984
30368
|
);
|
|
29985
30369
|
const has = (...names) => names.some((n) => frameworkNames.has(n));
|
|
29986
30370
|
const detectedFrameworks = [...frameworkNames].join(", ") || "none";
|
|
@@ -30086,7 +30470,7 @@ function createServer2(store, registry, config, rootPath) {
|
|
|
30086
30470
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
30087
30471
|
const reranker = config.ai?.enabled ? new LLMReranker(aiProvider.fastInference()) : null;
|
|
30088
30472
|
if (config.watch?.enabled !== false) {
|
|
30089
|
-
const knownExtensions = new Set(registry.getLanguagePlugins().flatMap((
|
|
30473
|
+
const knownExtensions = new Set(registry.getLanguagePlugins().flatMap((p5) => p5.supportedExtensions));
|
|
30090
30474
|
const fileWatcher = new FileWatcher(
|
|
30091
30475
|
projectRoot,
|
|
30092
30476
|
async (files) => {
|
|
@@ -30124,7 +30508,8 @@ function createServer2(store, registry, config, rootPath) {
|
|
|
30124
30508
|
guardPath,
|
|
30125
30509
|
j: j2,
|
|
30126
30510
|
jh,
|
|
30127
|
-
markExplored: explored.markExplored
|
|
30511
|
+
markExplored: explored.markExplored,
|
|
30512
|
+
progress: progress ?? null
|
|
30128
30513
|
};
|
|
30129
30514
|
const metaCtx = {
|
|
30130
30515
|
...ctx,
|
|
@@ -31524,8 +31909,8 @@ function extractProps(scriptContent) {
|
|
|
31524
31909
|
const body = typeMatch[1];
|
|
31525
31910
|
const propNames = body.match(/(\w+)\s*[?]?\s*:/g);
|
|
31526
31911
|
if (propNames) {
|
|
31527
|
-
for (const
|
|
31528
|
-
props.push(
|
|
31912
|
+
for (const p5 of propNames) {
|
|
31913
|
+
props.push(p5.replace(/\s*[?]?\s*:/, ""));
|
|
31529
31914
|
}
|
|
31530
31915
|
}
|
|
31531
31916
|
return props;
|
|
@@ -31545,8 +31930,8 @@ function extractProps(scriptContent) {
|
|
|
31545
31930
|
const body = objectMatch[1];
|
|
31546
31931
|
const propNames = body.match(/(\w+)\s*:/g);
|
|
31547
31932
|
if (propNames) {
|
|
31548
|
-
for (const
|
|
31549
|
-
const name =
|
|
31933
|
+
for (const p5 of propNames) {
|
|
31934
|
+
const name = p5.replace(/\s*:/, "");
|
|
31550
31935
|
if (!["type", "default", "required", "validator"].includes(name)) {
|
|
31551
31936
|
props.push(name);
|
|
31552
31937
|
}
|
|
@@ -31681,7 +32066,7 @@ var VueLanguagePlugin = class {
|
|
|
31681
32066
|
kind: "component",
|
|
31682
32067
|
framework: "vue",
|
|
31683
32068
|
...props.length > 0 && {
|
|
31684
|
-
props: Object.fromEntries(props.map((
|
|
32069
|
+
props: Object.fromEntries(props.map((p5) => [p5, { type: "unknown" }]))
|
|
31685
32070
|
},
|
|
31686
32071
|
...emits.length > 0 && { emits },
|
|
31687
32072
|
...composables.length > 0 && { composables }
|
|
@@ -34270,9 +34655,9 @@ function extractImplMethods(body, filePath, typeName, typeSymbolId) {
|
|
|
34270
34655
|
if (isPublic(child)) meta.exported = 1;
|
|
34271
34656
|
const params = child.childForFieldName("parameters");
|
|
34272
34657
|
if (params) {
|
|
34273
|
-
for (const
|
|
34274
|
-
if (
|
|
34275
|
-
meta.receiver =
|
|
34658
|
+
for (const p5 of params.namedChildren) {
|
|
34659
|
+
if (p5.type === "self_parameter") {
|
|
34660
|
+
meta.receiver = p5.text;
|
|
34276
34661
|
break;
|
|
34277
34662
|
}
|
|
34278
34663
|
}
|
|
@@ -36564,7 +36949,7 @@ var ObjCLanguagePlugin = class {
|
|
|
36564
36949
|
const selectorLine = m[2].trim();
|
|
36565
36950
|
const parts = selectorLine.match(/\w+(?=\s*:)|^\w+$/gm);
|
|
36566
36951
|
if (!parts) continue;
|
|
36567
|
-
const selector = parts.length === 1 && !selectorLine.includes(":") ? parts[0] : parts.map((
|
|
36952
|
+
const selector = parts.length === 1 && !selectorLine.includes(":") ? parts[0] : parts.map((p5) => p5 + ":").join("");
|
|
36568
36953
|
const isStatic = prefix === "+";
|
|
36569
36954
|
add(selector, "method", m.index, m[0], { static: isStatic });
|
|
36570
36955
|
}
|
|
@@ -38664,9 +39049,9 @@ var XmlLanguagePlugin = class {
|
|
|
38664
39049
|
}
|
|
38665
39050
|
const schemaLoc = getAttr(attrs, "schemaLocation");
|
|
38666
39051
|
if (schemaLoc) {
|
|
38667
|
-
for (const
|
|
38668
|
-
if (
|
|
38669
|
-
edges.push({ edgeType: "imports", metadata: { module:
|
|
39052
|
+
for (const p5 of schemaLoc.trim().split(/\s+/)) {
|
|
39053
|
+
if (p5.endsWith(".xsd") || p5.endsWith(".wsdl") || p5.startsWith("http")) {
|
|
39054
|
+
edges.push({ edgeType: "imports", metadata: { module: p5, tag } });
|
|
38670
39055
|
}
|
|
38671
39056
|
}
|
|
38672
39057
|
}
|
|
@@ -38730,7 +39115,7 @@ var PrismaPlugin = class {
|
|
|
38730
39115
|
path51.join(ctx.rootPath, "prisma", "schema.prisma"),
|
|
38731
39116
|
path51.join(ctx.rootPath, "schema.prisma")
|
|
38732
39117
|
];
|
|
38733
|
-
return candidates.some((
|
|
39118
|
+
return candidates.some((p5) => fs38.existsSync(p5));
|
|
38734
39119
|
} catch {
|
|
38735
39120
|
return false;
|
|
38736
39121
|
}
|
|
@@ -38801,7 +39186,7 @@ function parsePrismaSchema(source) {
|
|
|
38801
39186
|
const fieldName = fieldMatch[1];
|
|
38802
39187
|
const fieldType = fieldMatch[2];
|
|
38803
39188
|
const attrs = fieldMatch[3] ?? "";
|
|
38804
|
-
if (["@@", "//"].some((
|
|
39189
|
+
if (["@@", "//"].some((p5) => fieldName.startsWith(p5))) continue;
|
|
38805
39190
|
const field = {
|
|
38806
39191
|
name: fieldName,
|
|
38807
39192
|
type: fieldType.replace("?", "").replace("[]", ""),
|
|
@@ -40186,7 +40571,7 @@ import { ok as ok32 } from "neverthrow";
|
|
|
40186
40571
|
function symId3(filePath, name, kind) {
|
|
40187
40572
|
return `${filePath}::${name}#${kind}`;
|
|
40188
40573
|
}
|
|
40189
|
-
function
|
|
40574
|
+
function stripJsonComments2(source) {
|
|
40190
40575
|
let result = "";
|
|
40191
40576
|
let i = 0;
|
|
40192
40577
|
let inString = false;
|
|
@@ -40305,8 +40690,8 @@ function extractEslint(obj, add, edges) {
|
|
|
40305
40690
|
}
|
|
40306
40691
|
}
|
|
40307
40692
|
if (Array.isArray(obj.plugins)) {
|
|
40308
|
-
for (const
|
|
40309
|
-
if (typeof
|
|
40693
|
+
for (const p5 of obj.plugins) {
|
|
40694
|
+
if (typeof p5 === "string") edges.push({ edgeType: "imports", metadata: { module: p5, dialect: "eslint" } });
|
|
40310
40695
|
}
|
|
40311
40696
|
}
|
|
40312
40697
|
}
|
|
@@ -40336,14 +40721,14 @@ function extractLerna(obj, add) {
|
|
|
40336
40721
|
}
|
|
40337
40722
|
function extractBabel(obj, add, edges) {
|
|
40338
40723
|
if (Array.isArray(obj.presets)) {
|
|
40339
|
-
for (const
|
|
40340
|
-
const name = typeof
|
|
40724
|
+
for (const p5 of obj.presets) {
|
|
40725
|
+
const name = typeof p5 === "string" ? p5 : Array.isArray(p5) && typeof p5[0] === "string" ? p5[0] : null;
|
|
40341
40726
|
if (name) edges.push({ edgeType: "imports", metadata: { module: name, dialect: "babel" } });
|
|
40342
40727
|
}
|
|
40343
40728
|
}
|
|
40344
40729
|
if (Array.isArray(obj.plugins)) {
|
|
40345
|
-
for (const
|
|
40346
|
-
const name = typeof
|
|
40730
|
+
for (const p5 of obj.plugins) {
|
|
40731
|
+
const name = typeof p5 === "string" ? p5 : Array.isArray(p5) && typeof p5[0] === "string" ? p5[0] : null;
|
|
40347
40732
|
if (name) edges.push({ edgeType: "imports", metadata: { module: name, dialect: "babel" } });
|
|
40348
40733
|
}
|
|
40349
40734
|
}
|
|
@@ -40439,7 +40824,7 @@ var JsonLanguagePlugin = class {
|
|
|
40439
40824
|
obj = JSON.parse(source);
|
|
40440
40825
|
} catch {
|
|
40441
40826
|
try {
|
|
40442
|
-
obj = JSON.parse(
|
|
40827
|
+
obj = JSON.parse(stripJsonComments2(source));
|
|
40443
40828
|
} catch {
|
|
40444
40829
|
return ok32({ language: "json", status: "ok", symbols: [] });
|
|
40445
40830
|
}
|
|
@@ -45334,8 +45719,8 @@ var SpringPlugin = class {
|
|
|
45334
45719
|
const re = new RegExp(`@${annotation}\\s*(?:\\(\\s*(?:value\\s*=\\s*)?["']([^"']*)["']\\s*\\))?`, "g");
|
|
45335
45720
|
let m;
|
|
45336
45721
|
while ((m = re.exec(source)) !== null) {
|
|
45337
|
-
const
|
|
45338
|
-
const uri = normalizePath(classPrefix + "/" +
|
|
45722
|
+
const path108 = m[1] ?? "";
|
|
45723
|
+
const uri = normalizePath(classPrefix + "/" + path108);
|
|
45339
45724
|
result.routes.push({ method, uri, line: source.substring(0, m.index).split("\n").length });
|
|
45340
45725
|
}
|
|
45341
45726
|
}
|
|
@@ -45395,8 +45780,8 @@ var SpringPlugin = class {
|
|
|
45395
45780
|
}
|
|
45396
45781
|
}
|
|
45397
45782
|
};
|
|
45398
|
-
function normalizePath(
|
|
45399
|
-
return "/" +
|
|
45783
|
+
function normalizePath(path108) {
|
|
45784
|
+
return "/" + path108.replace(/\/+/g, "/").replace(/^\/|\/$/g, "");
|
|
45400
45785
|
}
|
|
45401
45786
|
|
|
45402
45787
|
// src/indexer/plugins/integration/framework/express/index.ts
|
|
@@ -46904,8 +47289,8 @@ var NextJSPlugin = class {
|
|
|
46904
47289
|
const fileSymbols = ctx.getSymbolsByFile(file.id);
|
|
46905
47290
|
const fileSym = fileSymbols.find((s) => s.kind === "function" || s.kind === "class");
|
|
46906
47291
|
if (!fileSym) continue;
|
|
46907
|
-
const targetPage = pages.find((
|
|
46908
|
-
const pageRoute = appRouterPathToRoute(
|
|
47292
|
+
const targetPage = pages.find((p5) => {
|
|
47293
|
+
const pageRoute = appRouterPathToRoute(p5.path);
|
|
46909
47294
|
return pageRoute === info.interceptedRoute;
|
|
46910
47295
|
});
|
|
46911
47296
|
if (targetPage) {
|
|
@@ -48664,8 +49049,8 @@ var RawSqlPlugin = class {
|
|
|
48664
49049
|
...pkg.dependencies,
|
|
48665
49050
|
...pkg.devDependencies
|
|
48666
49051
|
};
|
|
48667
|
-
for (const
|
|
48668
|
-
if (
|
|
49052
|
+
for (const p5 of RAW_SQL_PACKAGES) {
|
|
49053
|
+
if (p5 in deps) return true;
|
|
48669
49054
|
}
|
|
48670
49055
|
} catch {
|
|
48671
49056
|
}
|
|
@@ -49352,8 +49737,8 @@ function extractExpoNavigationCalls(source) {
|
|
|
49352
49737
|
}
|
|
49353
49738
|
const templateRegex = /router\.(push|replace|navigate)\s*\(\s*`([^`]+)`/g;
|
|
49354
49739
|
while ((match = templateRegex.exec(source)) !== null) {
|
|
49355
|
-
const
|
|
49356
|
-
paths.push(
|
|
49740
|
+
const path108 = match[2].replace(/\$\{[^}]+\}/g, ":param");
|
|
49741
|
+
paths.push(path108);
|
|
49357
49742
|
}
|
|
49358
49743
|
const linkRegex = /<Link\s+[^>]*href\s*=\s*(?:\{?\s*)?['"]([^'"]+)['"]/g;
|
|
49359
49744
|
while ((match = linkRegex.exec(source)) !== null) {
|
|
@@ -49365,9 +49750,9 @@ function extractExpoNavigationCalls(source) {
|
|
|
49365
49750
|
}
|
|
49366
49751
|
return [...new Set(paths)];
|
|
49367
49752
|
}
|
|
49368
|
-
function matchExpoRoute(
|
|
49369
|
-
if (
|
|
49370
|
-
const pathParts =
|
|
49753
|
+
function matchExpoRoute(path108, routePattern) {
|
|
49754
|
+
if (path108 === routePattern) return true;
|
|
49755
|
+
const pathParts = path108.split("/").filter(Boolean);
|
|
49371
49756
|
const routeParts = routePattern.split("/").filter(Boolean);
|
|
49372
49757
|
if (pathParts.length !== routeParts.length) {
|
|
49373
49758
|
if (routeParts[routeParts.length - 1] === "*" && pathParts.length >= routeParts.length - 1) {
|
|
@@ -50325,7 +50710,7 @@ var ShadcnPlugin = class {
|
|
|
50325
50710
|
name: comp.name,
|
|
50326
50711
|
kind: "component",
|
|
50327
50712
|
framework: "shadcn-vue",
|
|
50328
|
-
props: Object.fromEntries(comp.props.map((
|
|
50713
|
+
props: Object.fromEntries(comp.props.map((p5) => [p5, true])),
|
|
50329
50714
|
emits: comp.emits,
|
|
50330
50715
|
slots: comp.slots
|
|
50331
50716
|
});
|
|
@@ -51312,7 +51697,7 @@ var NuxtUiPlugin = class {
|
|
|
51312
51697
|
name: usage.name,
|
|
51313
51698
|
kind: "component",
|
|
51314
51699
|
framework: isPro ? "nuxt-ui-pro" : "nuxt-ui",
|
|
51315
|
-
props: Object.fromEntries(usage.propsUsed.map((
|
|
51700
|
+
props: Object.fromEntries(usage.propsUsed.map((p5) => [p5, true]))
|
|
51316
51701
|
});
|
|
51317
51702
|
result.edges.push({
|
|
51318
51703
|
edgeType: isPro ? "nuxt_ui_pro_component" : "nuxt_ui_component",
|
|
@@ -53455,11 +53840,11 @@ function detectTestFramework(source, _filePath) {
|
|
|
53455
53840
|
function extractTestedRoutes(source) {
|
|
53456
53841
|
const routes = [];
|
|
53457
53842
|
const seen = /* @__PURE__ */ new Set();
|
|
53458
|
-
function add(
|
|
53459
|
-
const key = `${method ?? ""}:${
|
|
53843
|
+
function add(p5, method) {
|
|
53844
|
+
const key = `${method ?? ""}:${p5}`;
|
|
53460
53845
|
if (!seen.has(key)) {
|
|
53461
53846
|
seen.add(key);
|
|
53462
|
-
routes.push({ path:
|
|
53847
|
+
routes.push({ path: p5, method });
|
|
53463
53848
|
}
|
|
53464
53849
|
}
|
|
53465
53850
|
let m;
|
|
@@ -55363,8 +55748,8 @@ var CommanderPlugin = class {
|
|
|
55363
55748
|
...pkg.dependencies,
|
|
55364
55749
|
...pkg.devDependencies
|
|
55365
55750
|
};
|
|
55366
|
-
for (const
|
|
55367
|
-
if (
|
|
55751
|
+
for (const p5 of CLI_PACKAGES) {
|
|
55752
|
+
if (p5 in deps) return true;
|
|
55368
55753
|
}
|
|
55369
55754
|
} catch {
|
|
55370
55755
|
return false;
|
|
@@ -55461,8 +55846,8 @@ var TreeSitterPlugin = class {
|
|
|
55461
55846
|
...pkg.dependencies,
|
|
55462
55847
|
...pkg.devDependencies
|
|
55463
55848
|
};
|
|
55464
|
-
for (const
|
|
55465
|
-
if (
|
|
55849
|
+
for (const p5 of TREE_SITTER_PACKAGES) {
|
|
55850
|
+
if (p5 in deps) return true;
|
|
55466
55851
|
}
|
|
55467
55852
|
} catch {
|
|
55468
55853
|
return false;
|
|
@@ -55592,8 +55977,8 @@ var BuildToolsPlugin = class {
|
|
|
55592
55977
|
...pkg.dependencies,
|
|
55593
55978
|
...pkg.devDependencies
|
|
55594
55979
|
};
|
|
55595
|
-
for (const
|
|
55596
|
-
if (
|
|
55980
|
+
for (const p5 of BUILD_PACKAGES) {
|
|
55981
|
+
if (p5 in deps) return true;
|
|
55597
55982
|
}
|
|
55598
55983
|
} catch {
|
|
55599
55984
|
return false;
|
|
@@ -55739,8 +56124,8 @@ var PinoPlugin = class {
|
|
|
55739
56124
|
...pkg.dependencies,
|
|
55740
56125
|
...pkg.devDependencies
|
|
55741
56126
|
};
|
|
55742
|
-
for (const
|
|
55743
|
-
if (
|
|
56127
|
+
for (const p5 of LOGGING_PACKAGES) {
|
|
56128
|
+
if (p5 in deps) return true;
|
|
55744
56129
|
}
|
|
55745
56130
|
} catch {
|
|
55746
56131
|
return false;
|
|
@@ -55814,8 +56199,8 @@ var CosmiconfigPlugin = class {
|
|
|
55814
56199
|
...pkg.dependencies,
|
|
55815
56200
|
...pkg.devDependencies
|
|
55816
56201
|
};
|
|
55817
|
-
for (const
|
|
55818
|
-
if (
|
|
56202
|
+
for (const p5 of CONFIG_PACKAGES) {
|
|
56203
|
+
if (p5 in deps) return true;
|
|
55819
56204
|
}
|
|
55820
56205
|
} catch {
|
|
55821
56206
|
return false;
|
|
@@ -55886,8 +56271,8 @@ var NeverthrowPlugin = class {
|
|
|
55886
56271
|
...pkg.dependencies,
|
|
55887
56272
|
...pkg.devDependencies
|
|
55888
56273
|
};
|
|
55889
|
-
for (const
|
|
55890
|
-
if (
|
|
56274
|
+
for (const p5 of RESULT_PACKAGES) {
|
|
56275
|
+
if (p5 in deps) return true;
|
|
55891
56276
|
}
|
|
55892
56277
|
} catch {
|
|
55893
56278
|
return false;
|
|
@@ -55967,8 +56352,8 @@ var ClackPlugin = class {
|
|
|
55967
56352
|
...pkg.dependencies,
|
|
55968
56353
|
...pkg.devDependencies
|
|
55969
56354
|
};
|
|
55970
|
-
for (const
|
|
55971
|
-
if (
|
|
56355
|
+
for (const p5 of PROMPT_PACKAGES) {
|
|
56356
|
+
if (p5 in deps) return true;
|
|
55972
56357
|
}
|
|
55973
56358
|
} catch {
|
|
55974
56359
|
return false;
|
|
@@ -56098,9 +56483,9 @@ var FileWatcher2 = class {
|
|
|
56098
56483
|
logger.error({ error: err32 }, "Watcher error");
|
|
56099
56484
|
return;
|
|
56100
56485
|
}
|
|
56101
|
-
const notIgnored = (
|
|
56102
|
-
if (ignoreDirs.some((d) =>
|
|
56103
|
-
const rel = path92.relative(rootPath,
|
|
56486
|
+
const notIgnored = (p5) => {
|
|
56487
|
+
if (ignoreDirs.some((d) => p5.startsWith(d))) return false;
|
|
56488
|
+
const rel = path92.relative(rootPath, p5);
|
|
56104
56489
|
return !traceignore.isIgnored(rel);
|
|
56105
56490
|
};
|
|
56106
56491
|
const changed = events.filter((e) => e.type === "create" || e.type === "update").map((e) => e.path).filter(notIgnored);
|
|
@@ -56110,7 +56495,7 @@ var FileWatcher2 = class {
|
|
|
56110
56495
|
await onDeletes(deleted);
|
|
56111
56496
|
}
|
|
56112
56497
|
if (changed.length === 0) return;
|
|
56113
|
-
for (const
|
|
56498
|
+
for (const p5 of changed) this.pendingPaths.add(p5);
|
|
56114
56499
|
if (this.debounceTimer) this._clearTimeout(this.debounceTimer);
|
|
56115
56500
|
this.debounceTimer = this._setTimeout(async () => {
|
|
56116
56501
|
const paths = Array.from(this.pendingPaths);
|
|
@@ -56144,6 +56529,122 @@ var FileWatcher2 = class {
|
|
|
56144
56529
|
}
|
|
56145
56530
|
};
|
|
56146
56531
|
|
|
56532
|
+
// src/progress.ts
|
|
56533
|
+
function idleProgress() {
|
|
56534
|
+
return { phase: "idle", processed: 0, total: 0, startedAt: 0, completedAt: 0 };
|
|
56535
|
+
}
|
|
56536
|
+
function snapOne(p5) {
|
|
56537
|
+
const now = Date.now();
|
|
56538
|
+
const endTime = p5.completedAt > 0 ? p5.completedAt : now;
|
|
56539
|
+
return {
|
|
56540
|
+
...p5,
|
|
56541
|
+
percentage: p5.total > 0 ? Math.round(p5.processed / p5.total * 100) : null,
|
|
56542
|
+
elapsedMs: p5.startedAt > 0 ? endTime - p5.startedAt : 0
|
|
56543
|
+
};
|
|
56544
|
+
}
|
|
56545
|
+
var ProgressState = class {
|
|
56546
|
+
indexing = idleProgress();
|
|
56547
|
+
summarization = idleProgress();
|
|
56548
|
+
embedding = idleProgress();
|
|
56549
|
+
db;
|
|
56550
|
+
constructor(db) {
|
|
56551
|
+
this.db = db ?? null;
|
|
56552
|
+
if (this.db) {
|
|
56553
|
+
this.loadFromDb();
|
|
56554
|
+
}
|
|
56555
|
+
}
|
|
56556
|
+
update(name, partial) {
|
|
56557
|
+
const current = this[name];
|
|
56558
|
+
Object.assign(current, partial);
|
|
56559
|
+
this.persist(name);
|
|
56560
|
+
if (partial.phase === "running" && partial.total !== void 0) {
|
|
56561
|
+
logger.info({ pipeline: name, total: current.total }, "%s started: %d items to process", name, current.total);
|
|
56562
|
+
} else if (partial.phase === "completed") {
|
|
56563
|
+
const elapsed = current.completedAt > 0 && current.startedAt > 0 ? Math.round((current.completedAt - current.startedAt) / 1e3) : 0;
|
|
56564
|
+
logger.info({ pipeline: name, processed: current.processed, elapsed }, "%s completed: %d items in %ds", name, current.processed, elapsed);
|
|
56565
|
+
} else if (partial.phase === "error") {
|
|
56566
|
+
logger.error({ pipeline: name, error: current.error }, "%s failed: %s", name, current.error);
|
|
56567
|
+
} else if (partial.processed !== void 0 && current.total > 0) {
|
|
56568
|
+
const pct = Math.round(current.processed / current.total * 100);
|
|
56569
|
+
logger.info({ pipeline: name, processed: current.processed, total: current.total, pct }, "%s progress: %d/%d (%d%%)", name, current.processed, current.total, pct);
|
|
56570
|
+
}
|
|
56571
|
+
}
|
|
56572
|
+
snapshot() {
|
|
56573
|
+
return {
|
|
56574
|
+
indexing: snapOne(this.indexing),
|
|
56575
|
+
summarization: snapOne(this.summarization),
|
|
56576
|
+
embedding: snapOne(this.embedding)
|
|
56577
|
+
};
|
|
56578
|
+
}
|
|
56579
|
+
persist(name) {
|
|
56580
|
+
if (!this.db) return;
|
|
56581
|
+
const p5 = this[name];
|
|
56582
|
+
try {
|
|
56583
|
+
this.db.prepare(`
|
|
56584
|
+
INSERT OR REPLACE INTO indexing_progress
|
|
56585
|
+
(pipeline, phase, processed, total, started_at, completed_at, error, updated_at)
|
|
56586
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
56587
|
+
`).run(
|
|
56588
|
+
name,
|
|
56589
|
+
p5.phase,
|
|
56590
|
+
p5.processed,
|
|
56591
|
+
p5.total,
|
|
56592
|
+
p5.startedAt,
|
|
56593
|
+
p5.completedAt,
|
|
56594
|
+
p5.error ?? null,
|
|
56595
|
+
Date.now()
|
|
56596
|
+
);
|
|
56597
|
+
} catch (e) {
|
|
56598
|
+
logger.debug({ error: e }, "Failed to persist progress");
|
|
56599
|
+
}
|
|
56600
|
+
}
|
|
56601
|
+
loadFromDb() {
|
|
56602
|
+
if (!this.db) return;
|
|
56603
|
+
try {
|
|
56604
|
+
const rows = this.db.prepare("SELECT * FROM indexing_progress").all();
|
|
56605
|
+
for (const row of rows) {
|
|
56606
|
+
if (row.pipeline in this) {
|
|
56607
|
+
this[row.pipeline] = {
|
|
56608
|
+
phase: row.phase,
|
|
56609
|
+
processed: row.processed,
|
|
56610
|
+
total: row.total,
|
|
56611
|
+
startedAt: row.started_at,
|
|
56612
|
+
completedAt: row.completed_at,
|
|
56613
|
+
error: row.error ?? void 0
|
|
56614
|
+
};
|
|
56615
|
+
}
|
|
56616
|
+
}
|
|
56617
|
+
} catch {
|
|
56618
|
+
}
|
|
56619
|
+
}
|
|
56620
|
+
};
|
|
56621
|
+
function readProgressFromDb(db) {
|
|
56622
|
+
try {
|
|
56623
|
+
const rows = db.prepare("SELECT * FROM indexing_progress").all();
|
|
56624
|
+
if (rows.length === 0) return null;
|
|
56625
|
+
const map = new Map(rows.map((r) => [r.pipeline, r]));
|
|
56626
|
+
const toProgress = (name) => {
|
|
56627
|
+
const r = map.get(name);
|
|
56628
|
+
if (!r) return idleProgress();
|
|
56629
|
+
return {
|
|
56630
|
+
phase: r.phase,
|
|
56631
|
+
processed: r.processed,
|
|
56632
|
+
total: r.total,
|
|
56633
|
+
startedAt: r.started_at,
|
|
56634
|
+
completedAt: r.completed_at,
|
|
56635
|
+
error: r.error ?? void 0
|
|
56636
|
+
};
|
|
56637
|
+
};
|
|
56638
|
+
return {
|
|
56639
|
+
indexing: snapOne(toProgress("indexing")),
|
|
56640
|
+
summarization: snapOne(toProgress("summarization")),
|
|
56641
|
+
embedding: snapOne(toProgress("embedding"))
|
|
56642
|
+
};
|
|
56643
|
+
} catch {
|
|
56644
|
+
return null;
|
|
56645
|
+
}
|
|
56646
|
+
}
|
|
56647
|
+
|
|
56147
56648
|
// src/cli.ts
|
|
56148
56649
|
import http from "http";
|
|
56149
56650
|
|
|
@@ -56419,7 +56920,7 @@ import path95 from "path";
|
|
|
56419
56920
|
import os6 from "os";
|
|
56420
56921
|
|
|
56421
56922
|
// src/init/types.ts
|
|
56422
|
-
var GUARD_HOOK_VERSION = "0.
|
|
56923
|
+
var GUARD_HOOK_VERSION = "0.5.0";
|
|
56423
56924
|
var REINDEX_HOOK_VERSION = "0.1.0";
|
|
56424
56925
|
var PRECOMPACT_HOOK_VERSION = "0.1.0";
|
|
56425
56926
|
var WORKTREE_HOOK_VERSION = "0.1.0";
|
|
@@ -56441,7 +56942,7 @@ var CLIENTS = [
|
|
|
56441
56942
|
var GUARD_HOOK = {
|
|
56442
56943
|
scriptName: "trace-mcp-guard",
|
|
56443
56944
|
settingsKey: "PreToolUse",
|
|
56444
|
-
matcher: "Read|Grep|Glob|Bash",
|
|
56945
|
+
matcher: "Read|Grep|Glob|Bash|Agent",
|
|
56445
56946
|
version: GUARD_HOOK_VERSION,
|
|
56446
56947
|
dryRunLabel: "Would install guard hook"
|
|
56447
56948
|
};
|
|
@@ -56531,7 +57032,10 @@ function removeHookEntry(settings, desc) {
|
|
|
56531
57032
|
const entries = hooks[desc.settingsKey];
|
|
56532
57033
|
if (!Array.isArray(entries)) return;
|
|
56533
57034
|
hooks[desc.settingsKey] = entries.filter(
|
|
56534
|
-
(h) =>
|
|
57035
|
+
(h) => {
|
|
57036
|
+
const entry = h;
|
|
57037
|
+
return !entry.hooks?.some((hh) => hh.command?.includes(desc.scriptName));
|
|
57038
|
+
}
|
|
56535
57039
|
);
|
|
56536
57040
|
if (hooks[desc.settingsKey].length === 0) delete hooks[desc.settingsKey];
|
|
56537
57041
|
if (Object.keys(hooks).length === 0) delete settings.hooks;
|
|
@@ -56709,12 +57213,12 @@ function detectProject(dir) {
|
|
|
56709
57213
|
const ctx = buildProjectContext(projectRoot);
|
|
56710
57214
|
const packageManagers = detectPackageManagers(projectRoot);
|
|
56711
57215
|
const registry = new PluginRegistry();
|
|
56712
|
-
for (const
|
|
56713
|
-
for (const
|
|
57216
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
57217
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
56714
57218
|
const activeResult = registry.getActiveFrameworkPlugins(ctx);
|
|
56715
|
-
const frameworks = activeResult.isOk() ? activeResult.value.map((
|
|
56716
|
-
const dep = ctx.allDependencies.find((d) => d.name ===
|
|
56717
|
-
return { name:
|
|
57219
|
+
const frameworks = activeResult.isOk() ? activeResult.value.map((p5) => {
|
|
57220
|
+
const dep = ctx.allDependencies.find((d) => d.name === p5.manifest.name);
|
|
57221
|
+
return { name: p5.manifest.name, version: dep?.version, category: p5.manifest.category };
|
|
56718
57222
|
}) : [];
|
|
56719
57223
|
const languageMap = {
|
|
56720
57224
|
node: "TypeScript",
|
|
@@ -56832,8 +57336,8 @@ function detectExistingConfig(root) {
|
|
|
56832
57336
|
path97.join(root, ".trace-mcp.json"),
|
|
56833
57337
|
path97.join(root, ".config", "trace-mcp.json")
|
|
56834
57338
|
];
|
|
56835
|
-
for (const
|
|
56836
|
-
if (fs84.existsSync(
|
|
57339
|
+
for (const p5 of candidates) {
|
|
57340
|
+
if (fs84.existsSync(p5)) return { path: p5 };
|
|
56837
57341
|
}
|
|
56838
57342
|
const pkgPath = path97.join(root, "package.json");
|
|
56839
57343
|
if (fs84.existsSync(pkgPath)) {
|
|
@@ -56847,7 +57351,7 @@ function detectExistingConfig(root) {
|
|
|
56847
57351
|
}
|
|
56848
57352
|
function detectExistingDb(root, globalDbPath) {
|
|
56849
57353
|
const candidates = globalDbPath ? [globalDbPath, path97.join(root, ".trace-mcp", "index.db")] : [path97.join(root, ".trace-mcp", "index.db")];
|
|
56850
|
-
const dbPath = candidates.find((
|
|
57354
|
+
const dbPath = candidates.find((p5) => fs84.existsSync(p5));
|
|
56851
57355
|
if (!dbPath) return null;
|
|
56852
57356
|
try {
|
|
56853
57357
|
const db = new Database6(dbPath, { readonly: true });
|
|
@@ -57458,9 +57962,9 @@ function scanGlobalArtifacts() {
|
|
|
57458
57962
|
}
|
|
57459
57963
|
return conflicts;
|
|
57460
57964
|
}
|
|
57461
|
-
function shortPath(
|
|
57462
|
-
if (
|
|
57463
|
-
return
|
|
57965
|
+
function shortPath(p5) {
|
|
57966
|
+
if (p5.startsWith(HOME4)) return "~" + p5.slice(HOME4.length);
|
|
57967
|
+
return p5;
|
|
57464
57968
|
}
|
|
57465
57969
|
function truncate(s, maxLen) {
|
|
57466
57970
|
return s.length > maxLen ? s.slice(0, maxLen - 1) + "\u2026" : s;
|
|
@@ -57743,10 +58247,10 @@ function fixGlobalArtifact(conflict, opts) {
|
|
|
57743
58247
|
return { conflictId: conflict.id, action: "skipped", detail: `Failed to remove: ${err32.message}`, target: dirPath };
|
|
57744
58248
|
}
|
|
57745
58249
|
}
|
|
57746
|
-
function shortPath2(
|
|
58250
|
+
function shortPath2(p5) {
|
|
57747
58251
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
57748
|
-
if (home &&
|
|
57749
|
-
return
|
|
58252
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58253
|
+
return p5;
|
|
57750
58254
|
}
|
|
57751
58255
|
|
|
57752
58256
|
// src/project-root.ts
|
|
@@ -58013,16 +58517,16 @@ function generateConfig(detection) {
|
|
|
58013
58517
|
for (const fw of detection.frameworks) {
|
|
58014
58518
|
const preset = FRAMEWORK_PRESETS[fw.name];
|
|
58015
58519
|
if (preset) {
|
|
58016
|
-
for (const
|
|
58017
|
-
for (const
|
|
58520
|
+
for (const p5 of preset.include) include.add(p5);
|
|
58521
|
+
for (const p5 of preset.exclude) exclude.add(p5);
|
|
58018
58522
|
}
|
|
58019
58523
|
}
|
|
58020
58524
|
if (include.size === 0) {
|
|
58021
58525
|
for (const lang of detection.languages) {
|
|
58022
58526
|
const preset = LANGUAGE_PRESETS[lang.toLowerCase()];
|
|
58023
58527
|
if (preset) {
|
|
58024
|
-
for (const
|
|
58025
|
-
for (const
|
|
58528
|
+
for (const p5 of preset.include) include.add(p5);
|
|
58529
|
+
for (const p5 of preset.exclude) exclude.add(p5);
|
|
58026
58530
|
}
|
|
58027
58531
|
}
|
|
58028
58532
|
}
|
|
@@ -58272,7 +58776,16 @@ var initCommand = new Command("init").description("One-time global setup: config
|
|
|
58272
58776
|
}
|
|
58273
58777
|
}
|
|
58274
58778
|
if (indexProject) {
|
|
58275
|
-
const
|
|
58779
|
+
const spin = !nonInteractive ? p.spinner() : null;
|
|
58780
|
+
spin?.start("Registering and indexing current project...");
|
|
58781
|
+
const indexStep = await registerAndIndexProject(process.cwd(), { dryRun: opts.dryRun, force: opts.force });
|
|
58782
|
+
if (spin) {
|
|
58783
|
+
if (indexStep.detail?.includes("Indexed")) {
|
|
58784
|
+
spin.stop(indexStep.detail);
|
|
58785
|
+
} else {
|
|
58786
|
+
spin.stop(indexStep.detail ?? indexStep.action);
|
|
58787
|
+
}
|
|
58788
|
+
}
|
|
58276
58789
|
steps.push(indexStep);
|
|
58277
58790
|
}
|
|
58278
58791
|
const existingProjects = listProjects();
|
|
@@ -58308,21 +58821,25 @@ var initCommand = new Command("init").description("One-time global setup: config
|
|
|
58308
58821
|
steps.push({ target: proj.root, action: "skipped", detail: "Config load failed" });
|
|
58309
58822
|
continue;
|
|
58310
58823
|
}
|
|
58311
|
-
|
|
58312
|
-
|
|
58313
|
-
|
|
58314
|
-
|
|
58315
|
-
|
|
58316
|
-
|
|
58317
|
-
|
|
58318
|
-
|
|
58319
|
-
|
|
58320
|
-
|
|
58321
|
-
|
|
58322
|
-
|
|
58323
|
-
|
|
58324
|
-
|
|
58325
|
-
|
|
58824
|
+
try {
|
|
58825
|
+
const dbPath = getDbPath(proj.root);
|
|
58826
|
+
const db = initializeDatabase(dbPath);
|
|
58827
|
+
const store = new Store(db);
|
|
58828
|
+
const registry = new PluginRegistry();
|
|
58829
|
+
for (const lp of createAllLanguagePlugins()) registry.registerLanguagePlugin(lp);
|
|
58830
|
+
for (const fp of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(fp);
|
|
58831
|
+
const pipeline = new IndexingPipeline(store, registry, configResult.value, proj.root);
|
|
58832
|
+
const result = await pipeline.indexAll(true);
|
|
58833
|
+
steps.push({
|
|
58834
|
+
target: proj.root,
|
|
58835
|
+
action: "updated",
|
|
58836
|
+
detail: `Upgraded: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
|
|
58837
|
+
});
|
|
58838
|
+
updateLastIndexed(proj.root);
|
|
58839
|
+
db.close();
|
|
58840
|
+
} catch (err32) {
|
|
58841
|
+
steps.push({ target: proj.root, action: "skipped", detail: `Upgrade failed: ${err32.message}` });
|
|
58842
|
+
}
|
|
58326
58843
|
}
|
|
58327
58844
|
spin?.stop("Upgrade complete");
|
|
58328
58845
|
}
|
|
@@ -58350,7 +58867,7 @@ var initCommand = new Command("init").description("One-time global setup: config
|
|
|
58350
58867
|
p.note(lines.join("\n"), "Already configured");
|
|
58351
58868
|
}
|
|
58352
58869
|
p.outro(
|
|
58353
|
-
indexProject ? "Ready! Project registered and
|
|
58870
|
+
indexProject ? "Ready! Project registered and indexed." : "Ready! Run `trace-mcp add` in a project directory to register it for indexing."
|
|
58354
58871
|
);
|
|
58355
58872
|
}
|
|
58356
58873
|
});
|
|
@@ -58382,7 +58899,31 @@ function executeSteps(steps, opts) {
|
|
|
58382
58899
|
steps.push(mdResult);
|
|
58383
58900
|
}
|
|
58384
58901
|
}
|
|
58385
|
-
function
|
|
58902
|
+
function formatDuration(ms) {
|
|
58903
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
58904
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
58905
|
+
}
|
|
58906
|
+
async function runIndexingForProject(projectRoot) {
|
|
58907
|
+
const configResult = await loadConfig(projectRoot);
|
|
58908
|
+
if (configResult.isErr()) return null;
|
|
58909
|
+
const dbPath = getDbPath(projectRoot);
|
|
58910
|
+
const db = initializeDatabase(dbPath);
|
|
58911
|
+
const store = new Store(db);
|
|
58912
|
+
const registry = new PluginRegistry();
|
|
58913
|
+
for (const lp of createAllLanguagePlugins()) registry.registerLanguagePlugin(lp);
|
|
58914
|
+
for (const fp of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(fp);
|
|
58915
|
+
const pipeline = new IndexingPipeline(store, registry, configResult.value, projectRoot);
|
|
58916
|
+
try {
|
|
58917
|
+
const result = await pipeline.indexAll(true);
|
|
58918
|
+
updateLastIndexed(projectRoot);
|
|
58919
|
+
return { indexed: result.indexed, skipped: result.skipped, errors: result.errors, durationMs: result.durationMs };
|
|
58920
|
+
} catch {
|
|
58921
|
+
return null;
|
|
58922
|
+
} finally {
|
|
58923
|
+
db.close();
|
|
58924
|
+
}
|
|
58925
|
+
}
|
|
58926
|
+
async function registerAndIndexProject(dir, opts) {
|
|
58386
58927
|
let projectRoot = null;
|
|
58387
58928
|
try {
|
|
58388
58929
|
projectRoot = findProjectRoot(dir);
|
|
@@ -58393,7 +58934,7 @@ function registerAndIndexProject(dir, opts) {
|
|
|
58393
58934
|
if (childRoots.length === 0) {
|
|
58394
58935
|
return { target: dir, action: "skipped", detail: "Could not detect project root or child projects" };
|
|
58395
58936
|
}
|
|
58396
|
-
return registerMultiRootProject(dir, childRoots, opts);
|
|
58937
|
+
return await registerMultiRootProject(dir, childRoots, opts);
|
|
58397
58938
|
}
|
|
58398
58939
|
if (opts.dryRun) {
|
|
58399
58940
|
return { target: projectRoot, action: "skipped", detail: "Would register and index project" };
|
|
@@ -58413,13 +58954,15 @@ function registerAndIndexProject(dir, opts) {
|
|
|
58413
58954
|
const db = initializeDatabase(dbPath);
|
|
58414
58955
|
db.close();
|
|
58415
58956
|
const entry = registerProject(projectRoot);
|
|
58957
|
+
const indexResult = await runIndexingForProject(projectRoot);
|
|
58958
|
+
const detail = indexResult ? `Registered and indexed: ${entry.name} \u2014 ${indexResult.indexed} files in ${formatDuration(indexResult.durationMs)} (${indexResult.skipped} skipped, ${indexResult.errors} errors)` : `Registered project: ${entry.name} (indexing failed)`;
|
|
58416
58959
|
return {
|
|
58417
58960
|
target: projectRoot,
|
|
58418
58961
|
action: existing ? "updated" : "created",
|
|
58419
|
-
detail
|
|
58962
|
+
detail
|
|
58420
58963
|
};
|
|
58421
58964
|
}
|
|
58422
|
-
function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
58965
|
+
async function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
58423
58966
|
if (opts.dryRun) {
|
|
58424
58967
|
return {
|
|
58425
58968
|
target: parentDir,
|
|
@@ -58459,10 +59002,12 @@ function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
|
58459
59002
|
const db = initializeDatabase(dbPath);
|
|
58460
59003
|
db.close();
|
|
58461
59004
|
const entry = registerProject(parentDir, { type: "multi-root", children: childRoots });
|
|
59005
|
+
const indexResult = await runIndexingForProject(parentDir);
|
|
59006
|
+
const detail = indexResult ? `Registered and indexed multi-root: ${entry.name} (${childRoots.length} children) \u2014 ${indexResult.indexed} files in ${formatDuration(indexResult.durationMs)}` : `Registered multi-root (${childRoots.length} children): ${childRoots.map((r) => path102.basename(r)).join(", ")} (indexing failed)`;
|
|
58462
59007
|
return {
|
|
58463
59008
|
target: parentDir,
|
|
58464
59009
|
action: existing ? "updated" : "created",
|
|
58465
|
-
detail
|
|
59010
|
+
detail
|
|
58466
59011
|
};
|
|
58467
59012
|
}
|
|
58468
59013
|
function formatClientName(name) {
|
|
@@ -58476,12 +59021,12 @@ function formatClientName(name) {
|
|
|
58476
59021
|
};
|
|
58477
59022
|
return names[name] ?? name;
|
|
58478
59023
|
}
|
|
58479
|
-
function shortPath3(
|
|
59024
|
+
function shortPath3(p5) {
|
|
58480
59025
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58481
|
-
if (home &&
|
|
59026
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58482
59027
|
const cwd = process.cwd();
|
|
58483
|
-
if (
|
|
58484
|
-
return
|
|
59028
|
+
if (p5.startsWith(cwd)) return p5.slice(cwd.length + 1) || ".";
|
|
59029
|
+
return p5;
|
|
58485
59030
|
}
|
|
58486
59031
|
|
|
58487
59032
|
// src/cli/upgrade.ts
|
|
@@ -58498,11 +59043,11 @@ var upgradeCommand = new Command2("upgrade").description("Upgrade trace-mcp: run
|
|
|
58498
59043
|
console.error("No registered projects. Run `trace-mcp add` first, or specify a directory.");
|
|
58499
59044
|
process.exit(1);
|
|
58500
59045
|
}
|
|
58501
|
-
for (const
|
|
58502
|
-
if (fs90.existsSync(
|
|
58503
|
-
projectRoots.push(
|
|
59046
|
+
for (const p5 of projects) {
|
|
59047
|
+
if (fs90.existsSync(p5.root)) {
|
|
59048
|
+
projectRoots.push(p5.root);
|
|
58504
59049
|
} else {
|
|
58505
|
-
logger.warn({ root:
|
|
59050
|
+
logger.warn({ root: p5.root }, "Skipping stale project (directory not found)");
|
|
58506
59051
|
}
|
|
58507
59052
|
}
|
|
58508
59053
|
}
|
|
@@ -58520,29 +59065,34 @@ var upgradeCommand = new Command2("upgrade").description("Upgrade trace-mcp: run
|
|
|
58520
59065
|
const dbPath = getDbPath(projectRoot);
|
|
58521
59066
|
ensureGlobalDirs();
|
|
58522
59067
|
if (!opts.dryRun) {
|
|
58523
|
-
|
|
58524
|
-
|
|
58525
|
-
|
|
58526
|
-
|
|
58527
|
-
|
|
58528
|
-
target: dbPath,
|
|
58529
|
-
action: "updated",
|
|
58530
|
-
detail: `Schema v${currentVersion}`
|
|
58531
|
-
});
|
|
58532
|
-
if (!opts.skipReindex) {
|
|
58533
|
-
const registry = new PluginRegistry();
|
|
58534
|
-
for (const p4 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p4);
|
|
58535
|
-
for (const p4 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p4);
|
|
58536
|
-
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
58537
|
-
const result = await pipeline.indexAll(true);
|
|
59068
|
+
try {
|
|
59069
|
+
const db = initializeDatabase(dbPath);
|
|
59070
|
+
const store = new Store(db);
|
|
59071
|
+
const versionRow = db.prepare("SELECT value FROM schema_meta WHERE key = ?").get("schema_version");
|
|
59072
|
+
const currentVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
|
|
58538
59073
|
steps.push({
|
|
58539
|
-
target:
|
|
59074
|
+
target: dbPath,
|
|
58540
59075
|
action: "updated",
|
|
58541
|
-
detail: `
|
|
59076
|
+
detail: `Schema v${currentVersion}`
|
|
58542
59077
|
});
|
|
58543
|
-
|
|
59078
|
+
if (!opts.skipReindex) {
|
|
59079
|
+
const registry = new PluginRegistry();
|
|
59080
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
59081
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59082
|
+
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
59083
|
+
const result = await pipeline.indexAll(true);
|
|
59084
|
+
steps.push({
|
|
59085
|
+
target: projectRoot,
|
|
59086
|
+
action: "updated",
|
|
59087
|
+
detail: `Reindexed: ${result.indexed} files, ${result.skipped} skipped, ${result.errors} errors`
|
|
59088
|
+
});
|
|
59089
|
+
updateLastIndexed(projectRoot);
|
|
59090
|
+
}
|
|
59091
|
+
db.close();
|
|
59092
|
+
} catch (err32) {
|
|
59093
|
+
logger.error({ error: err32.message, project: projectRoot }, "Upgrade failed");
|
|
59094
|
+
steps.push({ target: projectRoot, action: "skipped", detail: `Upgrade failed: ${err32.message}` });
|
|
58544
59095
|
}
|
|
58545
|
-
db.close();
|
|
58546
59096
|
} else {
|
|
58547
59097
|
steps.push({ target: dbPath, action: "skipped", detail: "Would run migrations" });
|
|
58548
59098
|
if (!opts.skipReindex) {
|
|
@@ -58591,7 +59141,39 @@ import { Command as Command3 } from "commander";
|
|
|
58591
59141
|
import fs91 from "fs";
|
|
58592
59142
|
import path104 from "path";
|
|
58593
59143
|
import * as p2 from "@clack/prompts";
|
|
58594
|
-
|
|
59144
|
+
async function runIndexing(projectRoot, opts) {
|
|
59145
|
+
const configResult = await loadConfig(projectRoot);
|
|
59146
|
+
if (configResult.isErr()) {
|
|
59147
|
+
if (!opts.json) {
|
|
59148
|
+
p2.log.warn(`Could not load config for indexing: ${configResult.error}`);
|
|
59149
|
+
}
|
|
59150
|
+
return null;
|
|
59151
|
+
}
|
|
59152
|
+
const dbPath = getDbPath(projectRoot);
|
|
59153
|
+
const db = initializeDatabase(dbPath);
|
|
59154
|
+
const store = new Store(db);
|
|
59155
|
+
const registry = new PluginRegistry();
|
|
59156
|
+
for (const lp of createAllLanguagePlugins()) registry.registerLanguagePlugin(lp);
|
|
59157
|
+
for (const fp of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(fp);
|
|
59158
|
+
const pipeline = new IndexingPipeline(store, registry, configResult.value, projectRoot);
|
|
59159
|
+
try {
|
|
59160
|
+
const result = await pipeline.indexAll(true);
|
|
59161
|
+
updateLastIndexed(projectRoot);
|
|
59162
|
+
return { indexed: result.indexed, skipped: result.skipped, errors: result.errors, durationMs: result.durationMs };
|
|
59163
|
+
} catch (err32) {
|
|
59164
|
+
if (!opts.json) {
|
|
59165
|
+
p2.log.warn(`Indexing failed: ${err32.message}`);
|
|
59166
|
+
}
|
|
59167
|
+
return null;
|
|
59168
|
+
} finally {
|
|
59169
|
+
db.close();
|
|
59170
|
+
}
|
|
59171
|
+
}
|
|
59172
|
+
function formatDuration2(ms) {
|
|
59173
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
59174
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
59175
|
+
}
|
|
59176
|
+
var addCommand = new Command3("add").description("Register a project for indexing: detect root, create DB, add to registry").argument("[dir]", "Project directory (default: current directory)", ".").option("--force", "Re-register even if already registered").option("--no-index", "Skip indexing after registration").option("--json", "Output results as JSON").action(async (dir, opts) => {
|
|
58595
59177
|
const resolvedDir = path104.resolve(dir);
|
|
58596
59178
|
if (!fs91.existsSync(resolvedDir)) {
|
|
58597
59179
|
console.error(`Directory does not exist: ${resolvedDir}`);
|
|
@@ -58677,6 +59259,21 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58677
59259
|
const db = initializeDatabase(dbPath);
|
|
58678
59260
|
db.close();
|
|
58679
59261
|
const entry = registerProject(projectRoot);
|
|
59262
|
+
let indexResult = null;
|
|
59263
|
+
if (opts.index !== false) {
|
|
59264
|
+
if (isInteractive) {
|
|
59265
|
+
const spin = p2.spinner();
|
|
59266
|
+
spin.start("Indexing project...");
|
|
59267
|
+
indexResult = await runIndexing(projectRoot, opts);
|
|
59268
|
+
if (indexResult) {
|
|
59269
|
+
spin.stop(`Indexed ${indexResult.indexed} files in ${formatDuration2(indexResult.durationMs)}`);
|
|
59270
|
+
} else {
|
|
59271
|
+
spin.stop("Indexing skipped");
|
|
59272
|
+
}
|
|
59273
|
+
} else {
|
|
59274
|
+
indexResult = await runIndexing(projectRoot, opts);
|
|
59275
|
+
}
|
|
59276
|
+
}
|
|
58680
59277
|
if (opts.json) {
|
|
58681
59278
|
console.log(JSON.stringify({
|
|
58682
59279
|
status: existing ? "re-registered" : "registered",
|
|
@@ -58685,7 +59282,8 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58685
59282
|
detection: {
|
|
58686
59283
|
languages: detection.languages,
|
|
58687
59284
|
frameworks: detection.frameworks.map((f) => f.name)
|
|
58688
|
-
}
|
|
59285
|
+
},
|
|
59286
|
+
indexing: indexResult ?? void 0
|
|
58689
59287
|
}, null, 2));
|
|
58690
59288
|
} else {
|
|
58691
59289
|
const lines = [];
|
|
@@ -58695,8 +59293,16 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58695
59293
|
if (migrated) {
|
|
58696
59294
|
lines.push(`Migrated existing index from .trace-mcp/index.db`);
|
|
58697
59295
|
}
|
|
59296
|
+
if (indexResult) {
|
|
59297
|
+
lines.push(`Indexed: ${indexResult.indexed} files (${indexResult.skipped} skipped, ${indexResult.errors} errors)`);
|
|
59298
|
+
lines.push(`Duration: ${formatDuration2(indexResult.durationMs)}`);
|
|
59299
|
+
}
|
|
58698
59300
|
p2.note(lines.join("\n"), existing ? "Re-registered" : "Registered");
|
|
58699
|
-
|
|
59301
|
+
if (indexResult) {
|
|
59302
|
+
p2.outro("Project registered and indexed.");
|
|
59303
|
+
} else {
|
|
59304
|
+
p2.outro("Project registered. Run `trace-mcp index` to index it.");
|
|
59305
|
+
}
|
|
58700
59306
|
}
|
|
58701
59307
|
});
|
|
58702
59308
|
async function handleMultiRoot(parentDir, childRoots, opts) {
|
|
@@ -58779,13 +59385,29 @@ Discovered ${childRoots.length} child project(s):
|
|
|
58779
59385
|
type: "multi-root",
|
|
58780
59386
|
children: childRoots
|
|
58781
59387
|
});
|
|
59388
|
+
let indexResult = null;
|
|
59389
|
+
if (opts.index !== false) {
|
|
59390
|
+
if (isInteractive) {
|
|
59391
|
+
const spin = p2.spinner();
|
|
59392
|
+
spin.start("Indexing multi-root project...");
|
|
59393
|
+
indexResult = await runIndexing(parentDir, opts);
|
|
59394
|
+
if (indexResult) {
|
|
59395
|
+
spin.stop(`Indexed ${indexResult.indexed} files in ${formatDuration2(indexResult.durationMs)}`);
|
|
59396
|
+
} else {
|
|
59397
|
+
spin.stop("Indexing skipped");
|
|
59398
|
+
}
|
|
59399
|
+
} else {
|
|
59400
|
+
indexResult = await runIndexing(parentDir, opts);
|
|
59401
|
+
}
|
|
59402
|
+
}
|
|
58782
59403
|
if (opts.json) {
|
|
58783
59404
|
console.log(JSON.stringify({
|
|
58784
59405
|
status: existing ? "re-registered" : "registered",
|
|
58785
59406
|
type: "multi-root",
|
|
58786
59407
|
project: entry,
|
|
58787
59408
|
children: childRoots.map((r) => path104.basename(r)),
|
|
58788
|
-
cleaned
|
|
59409
|
+
cleaned,
|
|
59410
|
+
indexing: indexResult ?? void 0
|
|
58789
59411
|
}, null, 2));
|
|
58790
59412
|
} else {
|
|
58791
59413
|
const lines = [];
|
|
@@ -58793,14 +59415,22 @@ Discovered ${childRoots.length} child project(s):
|
|
|
58793
59415
|
lines.push(`Root: ${parentDir}`);
|
|
58794
59416
|
lines.push(`DB: ${shortPath4(dbPath)}`);
|
|
58795
59417
|
lines.push(`Children: ${childRoots.map((r) => path104.basename(r)).join(", ")}`);
|
|
59418
|
+
if (indexResult) {
|
|
59419
|
+
lines.push(`Indexed: ${indexResult.indexed} files (${indexResult.skipped} skipped, ${indexResult.errors} errors)`);
|
|
59420
|
+
lines.push(`Duration: ${formatDuration2(indexResult.durationMs)}`);
|
|
59421
|
+
}
|
|
58796
59422
|
p2.note(lines.join("\n"), existing ? "Re-registered" : "Registered");
|
|
58797
|
-
|
|
59423
|
+
if (indexResult) {
|
|
59424
|
+
p2.outro("Multi-root project registered and indexed.");
|
|
59425
|
+
} else {
|
|
59426
|
+
p2.outro("Multi-root project registered. Run `trace-mcp index` to index it.");
|
|
59427
|
+
}
|
|
58798
59428
|
}
|
|
58799
59429
|
}
|
|
58800
|
-
function shortPath4(
|
|
59430
|
+
function shortPath4(p5) {
|
|
58801
59431
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58802
|
-
if (home &&
|
|
58803
|
-
return
|
|
59432
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
59433
|
+
return p5;
|
|
58804
59434
|
}
|
|
58805
59435
|
|
|
58806
59436
|
// src/cli/doctor.ts
|
|
@@ -58862,11 +59492,11 @@ var doctorCommand = new Command4("doctor").description("Check for competing tool
|
|
|
58862
59492
|
return;
|
|
58863
59493
|
}
|
|
58864
59494
|
if (!opts.dryRun) {
|
|
58865
|
-
const
|
|
59495
|
+
const confirm4 = await p3.confirm({
|
|
58866
59496
|
message: `Fix ${fixable2.length} conflict${fixable2.length > 1 ? "s" : ""} automatically?`,
|
|
58867
59497
|
initialValue: true
|
|
58868
59498
|
});
|
|
58869
|
-
if (p3.isCancel(
|
|
59499
|
+
if (p3.isCancel(confirm4) || !confirm4) {
|
|
58870
59500
|
p3.cancel("No changes made.");
|
|
58871
59501
|
return;
|
|
58872
59502
|
}
|
|
@@ -58932,12 +59562,12 @@ function printFixResults(results, dryRun) {
|
|
|
58932
59562
|
p3.outro("Dry run complete \u2014 no changes made. Run with --fix to apply.");
|
|
58933
59563
|
}
|
|
58934
59564
|
}
|
|
58935
|
-
function shortPath5(
|
|
59565
|
+
function shortPath5(p5) {
|
|
58936
59566
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58937
|
-
if (home &&
|
|
59567
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58938
59568
|
const cwd = process.cwd();
|
|
58939
|
-
if (
|
|
58940
|
-
return
|
|
59569
|
+
if (p5.startsWith(cwd)) return p5.slice(cwd.length + 1) || ".";
|
|
59570
|
+
return p5;
|
|
58941
59571
|
}
|
|
58942
59572
|
|
|
58943
59573
|
// src/cli/ci.ts
|
|
@@ -59301,8 +59931,8 @@ ${msg}
|
|
|
59301
59931
|
const store = new Store(db);
|
|
59302
59932
|
if (opts.index) {
|
|
59303
59933
|
const registry = new PluginRegistry();
|
|
59304
|
-
for (const
|
|
59305
|
-
for (const
|
|
59934
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
59935
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59306
59936
|
logger.info("CI report: indexing project...");
|
|
59307
59937
|
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
59308
59938
|
await pipeline.indexAll(false);
|
|
@@ -59425,8 +60055,8 @@ var checkCommand = new Command6("check").description("Run quality gate checks ag
|
|
|
59425
60055
|
const store = new Store(db);
|
|
59426
60056
|
if (opts.index) {
|
|
59427
60057
|
const registry = new PluginRegistry();
|
|
59428
|
-
for (const
|
|
59429
|
-
for (const
|
|
60058
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
60059
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59430
60060
|
logger.info("Indexing project before quality check...");
|
|
59431
60061
|
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
59432
60062
|
await pipeline.indexAll(false);
|
|
@@ -59908,13 +60538,269 @@ analyticsCommand.command("trends").description("Show daily usage trends: tokens,
|
|
|
59908
60538
|
}
|
|
59909
60539
|
});
|
|
59910
60540
|
|
|
60541
|
+
// src/cli/remove.ts
|
|
60542
|
+
import { Command as Command10 } from "commander";
|
|
60543
|
+
import fs94 from "fs";
|
|
60544
|
+
import path106 from "path";
|
|
60545
|
+
import * as p4 from "@clack/prompts";
|
|
60546
|
+
var removeCommand = new Command10("remove").description("Unregister a project and delete its index").argument("[dir]", "Project directory (default: current directory)", ".").option("--force", "Remove without confirmation").option("--keep-db", "Keep the database file (only unregister)").option("--json", "Output results as JSON").action(async (dir, opts) => {
|
|
60547
|
+
const resolvedDir = path106.resolve(dir);
|
|
60548
|
+
const isInteractive = !opts.json;
|
|
60549
|
+
let projectRoot;
|
|
60550
|
+
try {
|
|
60551
|
+
projectRoot = findProjectRoot(resolvedDir);
|
|
60552
|
+
} catch {
|
|
60553
|
+
projectRoot = resolvedDir;
|
|
60554
|
+
}
|
|
60555
|
+
const parentEntry = findParentProject(projectRoot);
|
|
60556
|
+
if (parentEntry) {
|
|
60557
|
+
await handleRemoveFromMultiRoot(projectRoot, parentEntry, opts);
|
|
60558
|
+
return;
|
|
60559
|
+
}
|
|
60560
|
+
const entry = getProject(projectRoot);
|
|
60561
|
+
if (!entry) {
|
|
60562
|
+
if (opts.json) {
|
|
60563
|
+
console.log(JSON.stringify({ status: "not_registered", dir: projectRoot }));
|
|
60564
|
+
} else {
|
|
60565
|
+
if (isInteractive) p4.intro("trace-mcp remove");
|
|
60566
|
+
p4.log.warn(`Project not registered: ${projectRoot}`);
|
|
60567
|
+
p4.log.info("Use `trace-mcp list` to see registered projects.");
|
|
60568
|
+
}
|
|
60569
|
+
return;
|
|
60570
|
+
}
|
|
60571
|
+
if (isInteractive) {
|
|
60572
|
+
p4.intro("trace-mcp remove");
|
|
60573
|
+
const lines = [];
|
|
60574
|
+
lines.push(`Project: ${entry.name}`);
|
|
60575
|
+
lines.push(`Root: ${entry.root}`);
|
|
60576
|
+
lines.push(`DB: ${shortPath6(entry.dbPath)}`);
|
|
60577
|
+
if (entry.type === "multi-root" && entry.children) {
|
|
60578
|
+
lines.push(`Children: ${entry.children.map((c) => path106.basename(c)).join(", ")}`);
|
|
60579
|
+
}
|
|
60580
|
+
p4.note(lines.join("\n"), "Project to remove");
|
|
60581
|
+
}
|
|
60582
|
+
if (!opts.force && isInteractive) {
|
|
60583
|
+
const confirm4 = await p4.confirm({
|
|
60584
|
+
message: entry.type === "multi-root" ? `Remove multi-root project "${entry.name}" and its unified index?` : `Remove project "${entry.name}" and delete its index?`,
|
|
60585
|
+
initialValue: false
|
|
60586
|
+
});
|
|
60587
|
+
if (p4.isCancel(confirm4) || !confirm4) {
|
|
60588
|
+
p4.cancel("Cancelled.");
|
|
60589
|
+
return;
|
|
60590
|
+
}
|
|
60591
|
+
}
|
|
60592
|
+
let dbDeleted = false;
|
|
60593
|
+
if (!opts.keepDb && fs94.existsSync(entry.dbPath)) {
|
|
60594
|
+
fs94.unlinkSync(entry.dbPath);
|
|
60595
|
+
dbDeleted = true;
|
|
60596
|
+
}
|
|
60597
|
+
removeProjectConfig(entry.root);
|
|
60598
|
+
unregisterProject(entry.root);
|
|
60599
|
+
if (opts.json) {
|
|
60600
|
+
console.log(JSON.stringify({
|
|
60601
|
+
status: "removed",
|
|
60602
|
+
project: entry.name,
|
|
60603
|
+
root: entry.root,
|
|
60604
|
+
dbDeleted
|
|
60605
|
+
}, null, 2));
|
|
60606
|
+
} else {
|
|
60607
|
+
const lines = [];
|
|
60608
|
+
lines.push(`Project: ${entry.name}`);
|
|
60609
|
+
if (dbDeleted) {
|
|
60610
|
+
lines.push(`Database deleted: ${shortPath6(entry.dbPath)}`);
|
|
60611
|
+
} else if (opts.keepDb) {
|
|
60612
|
+
lines.push(`Database kept: ${shortPath6(entry.dbPath)}`);
|
|
60613
|
+
}
|
|
60614
|
+
lines.push("Config removed");
|
|
60615
|
+
p4.note(lines.join("\n"), "Removed");
|
|
60616
|
+
p4.outro("Project unregistered.");
|
|
60617
|
+
}
|
|
60618
|
+
});
|
|
60619
|
+
async function handleRemoveFromMultiRoot(childRoot, parent, opts) {
|
|
60620
|
+
const isInteractive = !opts.json;
|
|
60621
|
+
if (isInteractive) {
|
|
60622
|
+
p4.intro("trace-mcp remove (from multi-root)");
|
|
60623
|
+
p4.note(
|
|
60624
|
+
`This project is part of multi-root index: ${parent.name}
|
|
60625
|
+
Parent root: ${parent.root}
|
|
60626
|
+
Child to exclude: ${path106.basename(childRoot)}`,
|
|
60627
|
+
"Multi-root"
|
|
60628
|
+
);
|
|
60629
|
+
}
|
|
60630
|
+
if (!opts.force && isInteractive) {
|
|
60631
|
+
const confirm4 = await p4.confirm({
|
|
60632
|
+
message: `Exclude "${path106.basename(childRoot)}" from multi-root "${parent.name}"? (The parent index will be re-registered without this child.)`,
|
|
60633
|
+
initialValue: false
|
|
60634
|
+
});
|
|
60635
|
+
if (p4.isCancel(confirm4) || !confirm4) {
|
|
60636
|
+
p4.cancel("Cancelled.");
|
|
60637
|
+
return;
|
|
60638
|
+
}
|
|
60639
|
+
}
|
|
60640
|
+
const currentChildren = parent.children ?? [];
|
|
60641
|
+
const newChildren = currentChildren.filter((c) => path106.resolve(c) !== path106.resolve(childRoot));
|
|
60642
|
+
if (newChildren.length === 0) {
|
|
60643
|
+
if (!opts.keepDb && fs94.existsSync(parent.dbPath)) {
|
|
60644
|
+
fs94.unlinkSync(parent.dbPath);
|
|
60645
|
+
}
|
|
60646
|
+
removeProjectConfig(parent.root);
|
|
60647
|
+
unregisterProject(parent.root);
|
|
60648
|
+
if (opts.json) {
|
|
60649
|
+
console.log(JSON.stringify({
|
|
60650
|
+
status: "removed_multi_root",
|
|
60651
|
+
reason: "no children remaining",
|
|
60652
|
+
parent: parent.name
|
|
60653
|
+
}, null, 2));
|
|
60654
|
+
} else {
|
|
60655
|
+
p4.note("No children remaining \u2014 entire multi-root project removed.", "Removed");
|
|
60656
|
+
p4.outro("Multi-root project unregistered.");
|
|
60657
|
+
}
|
|
60658
|
+
return;
|
|
60659
|
+
}
|
|
60660
|
+
if (newChildren.length === 1) {
|
|
60661
|
+
const remainingChild = newChildren[0];
|
|
60662
|
+
if (!opts.keepDb && fs94.existsSync(parent.dbPath)) {
|
|
60663
|
+
fs94.unlinkSync(parent.dbPath);
|
|
60664
|
+
}
|
|
60665
|
+
removeProjectConfig(parent.root);
|
|
60666
|
+
unregisterProject(parent.root);
|
|
60667
|
+
if (opts.json) {
|
|
60668
|
+
console.log(JSON.stringify({
|
|
60669
|
+
status: "excluded_from_multi_root",
|
|
60670
|
+
excluded: path106.basename(childRoot),
|
|
60671
|
+
remaining: path106.basename(remainingChild),
|
|
60672
|
+
hint: `Run \`trace-mcp add ${remainingChild}\` to re-register the remaining project individually.`
|
|
60673
|
+
}, null, 2));
|
|
60674
|
+
} else {
|
|
60675
|
+
p4.note(
|
|
60676
|
+
`Excluded: ${path106.basename(childRoot)}
|
|
60677
|
+
Only one child remaining: ${path106.basename(remainingChild)}
|
|
60678
|
+
Multi-root removed. Run \`trace-mcp add ${remainingChild}\` to re-register individually.`,
|
|
60679
|
+
"Converted"
|
|
60680
|
+
);
|
|
60681
|
+
p4.outro("Child excluded from multi-root.");
|
|
60682
|
+
}
|
|
60683
|
+
return;
|
|
60684
|
+
}
|
|
60685
|
+
if (!opts.keepDb && fs94.existsSync(parent.dbPath)) {
|
|
60686
|
+
fs94.unlinkSync(parent.dbPath);
|
|
60687
|
+
}
|
|
60688
|
+
removeProjectConfig(parent.root);
|
|
60689
|
+
unregisterProject(parent.root);
|
|
60690
|
+
if (opts.json) {
|
|
60691
|
+
console.log(JSON.stringify({
|
|
60692
|
+
status: "excluded_from_multi_root",
|
|
60693
|
+
excluded: path106.basename(childRoot),
|
|
60694
|
+
remaining: newChildren.map((c) => path106.basename(c)),
|
|
60695
|
+
hint: `Run \`trace-mcp add ${parent.root}\` to re-register with ${newChildren.length} children.`
|
|
60696
|
+
}, null, 2));
|
|
60697
|
+
} else {
|
|
60698
|
+
p4.note(
|
|
60699
|
+
`Excluded: ${path106.basename(childRoot)}
|
|
60700
|
+
Remaining children: ${newChildren.map((c) => path106.basename(c)).join(", ")}
|
|
60701
|
+
Run \`trace-mcp add ${parent.root}\` to re-register the multi-root.`,
|
|
60702
|
+
"Excluded"
|
|
60703
|
+
);
|
|
60704
|
+
p4.outro("Child excluded. Re-add the parent to rebuild the index.");
|
|
60705
|
+
}
|
|
60706
|
+
}
|
|
60707
|
+
function shortPath6(p5) {
|
|
60708
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
60709
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
60710
|
+
return p5;
|
|
60711
|
+
}
|
|
60712
|
+
|
|
60713
|
+
// src/cli/status.ts
|
|
60714
|
+
import { Command as Command11 } from "commander";
|
|
60715
|
+
import fs95 from "fs";
|
|
60716
|
+
import Database7 from "better-sqlite3";
|
|
60717
|
+
function resolveDbPath5(projectRoot) {
|
|
60718
|
+
const entry = getProject(projectRoot);
|
|
60719
|
+
if (entry) return entry.dbPath;
|
|
60720
|
+
return getDbPath(projectRoot);
|
|
60721
|
+
}
|
|
60722
|
+
function formatDuration3(ms) {
|
|
60723
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
60724
|
+
const s = Math.round(ms / 1e3);
|
|
60725
|
+
if (s < 60) return `${s}s`;
|
|
60726
|
+
const m = Math.floor(s / 60);
|
|
60727
|
+
const rem = s % 60;
|
|
60728
|
+
return rem > 0 ? `${m}m ${rem}s` : `${m}m`;
|
|
60729
|
+
}
|
|
60730
|
+
function formatPipeline(name, p5) {
|
|
60731
|
+
const label = name.padEnd(16);
|
|
60732
|
+
switch (p5.phase) {
|
|
60733
|
+
case "idle":
|
|
60734
|
+
return ` ${label} idle`;
|
|
60735
|
+
case "running": {
|
|
60736
|
+
const pct = p5.percentage !== null ? `(${p5.percentage}%)` : "";
|
|
60737
|
+
const count = p5.total > 0 ? `${p5.processed}/${p5.total}` : `${p5.processed}`;
|
|
60738
|
+
const elapsed = p5.elapsedMs > 0 ? ` ${formatDuration3(p5.elapsedMs)} elapsed` : "";
|
|
60739
|
+
return ` ${label} running ${count} ${pct}${elapsed}`;
|
|
60740
|
+
}
|
|
60741
|
+
case "completed": {
|
|
60742
|
+
const count = p5.total > 0 ? `${p5.processed}/${p5.total}` : `${p5.processed}`;
|
|
60743
|
+
const elapsed = p5.elapsedMs > 0 ? ` ${formatDuration3(p5.elapsedMs)}` : "";
|
|
60744
|
+
return ` ${label} completed ${count} (100%)${elapsed}`;
|
|
60745
|
+
}
|
|
60746
|
+
case "error":
|
|
60747
|
+
return ` ${label} error ${p5.error ?? "unknown error"}`;
|
|
60748
|
+
default:
|
|
60749
|
+
return ` ${label} ${p5.phase}`;
|
|
60750
|
+
}
|
|
60751
|
+
}
|
|
60752
|
+
var statusCommand = new Command11("status").description("Show indexing progress for the current project").option("--json", "Output as JSON").action((opts) => {
|
|
60753
|
+
let projectRoot;
|
|
60754
|
+
try {
|
|
60755
|
+
projectRoot = findProjectRoot(process.cwd());
|
|
60756
|
+
} catch {
|
|
60757
|
+
projectRoot = process.cwd();
|
|
60758
|
+
}
|
|
60759
|
+
const dbPath = resolveDbPath5(projectRoot);
|
|
60760
|
+
if (!fs95.existsSync(dbPath)) {
|
|
60761
|
+
console.log(`No index found for ${projectRoot}`);
|
|
60762
|
+
console.log("Run `trace-mcp serve` or `trace-mcp index` first.");
|
|
60763
|
+
process.exit(1);
|
|
60764
|
+
}
|
|
60765
|
+
const db = new Database7(dbPath, { readonly: true });
|
|
60766
|
+
db.pragma("journal_mode = WAL");
|
|
60767
|
+
try {
|
|
60768
|
+
const progress = readProgressFromDb(db);
|
|
60769
|
+
const stats = db.prepare(`
|
|
60770
|
+
SELECT
|
|
60771
|
+
(SELECT COUNT(*) FROM files) as files,
|
|
60772
|
+
(SELECT COUNT(*) FROM symbols) as symbols,
|
|
60773
|
+
(SELECT COUNT(*) FROM edges) as edges
|
|
60774
|
+
`).get();
|
|
60775
|
+
if (opts.json) {
|
|
60776
|
+
console.log(JSON.stringify({ projectRoot, stats, progress }, null, 2));
|
|
60777
|
+
return;
|
|
60778
|
+
}
|
|
60779
|
+
console.log(`
|
|
60780
|
+
trace-mcp status \u2014 ${projectRoot}
|
|
60781
|
+
`);
|
|
60782
|
+
if (progress) {
|
|
60783
|
+
console.log(formatPipeline("Indexing:", progress.indexing));
|
|
60784
|
+
console.log(formatPipeline("Summarization:", progress.summarization));
|
|
60785
|
+
console.log(formatPipeline("Embedding:", progress.embedding));
|
|
60786
|
+
} else {
|
|
60787
|
+
console.log(" No progress data available (server may not have run yet)");
|
|
60788
|
+
}
|
|
60789
|
+
console.log(`
|
|
60790
|
+
Stats: ${stats.files} files \xB7 ${stats.symbols} symbols \xB7 ${stats.edges} edges
|
|
60791
|
+
`);
|
|
60792
|
+
} finally {
|
|
60793
|
+
db.close();
|
|
60794
|
+
}
|
|
60795
|
+
});
|
|
60796
|
+
|
|
59911
60797
|
// src/cli.ts
|
|
59912
|
-
var PKG_VERSION2 = true ? "1.
|
|
60798
|
+
var PKG_VERSION2 = true ? "1.7.0" : "0.0.0-dev";
|
|
59913
60799
|
function registerDefaultPlugins(registry) {
|
|
59914
|
-
for (const
|
|
59915
|
-
for (const
|
|
60800
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
60801
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59916
60802
|
}
|
|
59917
|
-
function
|
|
60803
|
+
function resolveDbPath6(projectRoot) {
|
|
59918
60804
|
const entry = getProject(projectRoot);
|
|
59919
60805
|
if (entry) return entry.dbPath;
|
|
59920
60806
|
return getDbPath(projectRoot);
|
|
@@ -59948,7 +60834,7 @@ function runFederationAutoSync(projectRoot, config) {
|
|
|
59948
60834
|
logger.warn({ error: e }, "Federation auto-sync failed (non-fatal)");
|
|
59949
60835
|
}
|
|
59950
60836
|
}
|
|
59951
|
-
var program = new
|
|
60837
|
+
var program = new Command12();
|
|
59952
60838
|
program.name("trace-mcp").description("Framework-Aware Code Intelligence for Laravel/Vue/Inertia/Nuxt").version(PKG_VERSION2);
|
|
59953
60839
|
program.command("serve").description("Start MCP server (stdio transport)").action(async () => {
|
|
59954
60840
|
const projectRoot = process.cwd();
|
|
@@ -59968,18 +60854,19 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
59968
60854
|
process.exit(1);
|
|
59969
60855
|
}
|
|
59970
60856
|
const config = configResult.value;
|
|
59971
|
-
const dbPath =
|
|
60857
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
59972
60858
|
ensureGlobalDirs();
|
|
59973
60859
|
const db = initializeDatabase(dbPath);
|
|
59974
60860
|
const store = new Store(db);
|
|
59975
60861
|
const registry = new PluginRegistry();
|
|
59976
60862
|
registerDefaultPlugins(registry);
|
|
59977
|
-
const
|
|
60863
|
+
const progress = new ProgressState(db);
|
|
60864
|
+
const pipeline = new IndexingPipeline(store, registry, config, projectRoot, progress);
|
|
59978
60865
|
const watcher = new FileWatcher2();
|
|
59979
60866
|
const aiProvider = createAIProvider(config);
|
|
59980
60867
|
const vectorStore = config.ai?.enabled ? new BlobVectorStore(store.db) : null;
|
|
59981
60868
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
59982
|
-
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore) : null;
|
|
60869
|
+
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore, progress) : null;
|
|
59983
60870
|
const inferenceCache = config.ai?.enabled ? new InferenceCache(store.db) : null;
|
|
59984
60871
|
inferenceCache?.evictExpired();
|
|
59985
60872
|
const summarizationPipeline = config.ai?.enabled && config.ai.summarize_on_index !== false ? new SummarizationPipeline(
|
|
@@ -59990,7 +60877,8 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
59990
60877
|
batchSize: config.ai.summarize_batch_size ?? 20,
|
|
59991
60878
|
kinds: config.ai.summarize_kinds ?? ["class", "function", "method", "interface", "trait", "enum", "type"],
|
|
59992
60879
|
concurrency: config.ai.concurrency ?? 1
|
|
59993
|
-
}
|
|
60880
|
+
},
|
|
60881
|
+
progress
|
|
59994
60882
|
) : null;
|
|
59995
60883
|
const runEmbeddings = () => {
|
|
59996
60884
|
if (!embeddingPipeline) return;
|
|
@@ -60024,7 +60912,7 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
60024
60912
|
};
|
|
60025
60913
|
process.on("SIGINT", shutdown);
|
|
60026
60914
|
process.on("SIGTERM", shutdown);
|
|
60027
|
-
const server = createServer2(store, registry, config, projectRoot);
|
|
60915
|
+
const server = createServer2(store, registry, config, projectRoot, progress);
|
|
60028
60916
|
const transport = new StdioServerTransport();
|
|
60029
60917
|
logger.info({ projectRoot, dbPath }, "Starting trace-mcp MCP server...");
|
|
60030
60918
|
await server.connect(transport);
|
|
@@ -60037,18 +60925,19 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60037
60925
|
process.exit(1);
|
|
60038
60926
|
}
|
|
60039
60927
|
const config = configResult.value;
|
|
60040
|
-
const dbPath =
|
|
60928
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
60041
60929
|
ensureGlobalDirs();
|
|
60042
60930
|
const db = initializeDatabase(dbPath);
|
|
60043
60931
|
const store = new Store(db);
|
|
60044
60932
|
const registry = new PluginRegistry();
|
|
60045
60933
|
registerDefaultPlugins(registry);
|
|
60046
|
-
const
|
|
60934
|
+
const progress2 = new ProgressState(db);
|
|
60935
|
+
const pipeline = new IndexingPipeline(store, registry, config, projectRoot, progress2);
|
|
60047
60936
|
const watcher = new FileWatcher2();
|
|
60048
60937
|
const aiProvider = createAIProvider(config);
|
|
60049
60938
|
const vectorStore = config.ai?.enabled ? new BlobVectorStore(store.db) : null;
|
|
60050
60939
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
60051
|
-
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore) : null;
|
|
60940
|
+
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore, progress2) : null;
|
|
60052
60941
|
const inferenceCache2 = config.ai?.enabled ? new InferenceCache(store.db) : null;
|
|
60053
60942
|
inferenceCache2?.evictExpired();
|
|
60054
60943
|
const summarizationPipeline2 = config.ai?.enabled && config.ai.summarize_on_index !== false ? new SummarizationPipeline(
|
|
@@ -60059,7 +60948,8 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60059
60948
|
batchSize: config.ai.summarize_batch_size ?? 20,
|
|
60060
60949
|
kinds: config.ai.summarize_kinds ?? ["class", "function", "method", "interface", "trait", "enum", "type"],
|
|
60061
60950
|
concurrency: config.ai.concurrency ?? 1
|
|
60062
|
-
}
|
|
60951
|
+
},
|
|
60952
|
+
progress2
|
|
60063
60953
|
) : null;
|
|
60064
60954
|
const runEmbeddings = () => {
|
|
60065
60955
|
if (!embeddingPipeline) return;
|
|
@@ -60089,7 +60979,7 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60089
60979
|
});
|
|
60090
60980
|
const port = parseInt(opts.port, 10);
|
|
60091
60981
|
const host = opts.host;
|
|
60092
|
-
const server = createServer2(store, registry, config, projectRoot);
|
|
60982
|
+
const server = createServer2(store, registry, config, projectRoot, progress2);
|
|
60093
60983
|
const transport = new StreamableHTTPServerTransport({
|
|
60094
60984
|
sessionIdGenerator: () => randomUUID()
|
|
60095
60985
|
});
|
|
@@ -60191,8 +61081,8 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60191
61081
|
});
|
|
60192
61082
|
});
|
|
60193
61083
|
program.command("index").description("Index a project directory").argument("<dir>", "Directory to index").option("-f, --force", "Force reindex all files").action(async (dir, opts) => {
|
|
60194
|
-
const resolvedDir =
|
|
60195
|
-
if (!
|
|
61084
|
+
const resolvedDir = path107.resolve(dir);
|
|
61085
|
+
if (!fs96.existsSync(resolvedDir)) {
|
|
60196
61086
|
logger.error({ dir: resolvedDir }, "Directory does not exist");
|
|
60197
61087
|
process.exit(1);
|
|
60198
61088
|
}
|
|
@@ -60202,7 +61092,7 @@ program.command("index").description("Index a project directory").argument("<dir
|
|
|
60202
61092
|
process.exit(1);
|
|
60203
61093
|
}
|
|
60204
61094
|
const config = configResult.value;
|
|
60205
|
-
const dbPath =
|
|
61095
|
+
const dbPath = resolveDbPath6(resolvedDir);
|
|
60206
61096
|
ensureGlobalDirs();
|
|
60207
61097
|
const db = initializeDatabase(dbPath);
|
|
60208
61098
|
const store = new Store(db);
|
|
@@ -60216,20 +61106,20 @@ program.command("index").description("Index a project directory").argument("<dir
|
|
|
60216
61106
|
db.close();
|
|
60217
61107
|
});
|
|
60218
61108
|
program.command("index-file").description("Incrementally reindex a single file (called by the PostToolUse auto-reindex hook)").argument("<file>", "Absolute or relative path to the file to reindex").action(async (file) => {
|
|
60219
|
-
const resolvedFile =
|
|
60220
|
-
if (!
|
|
61109
|
+
const resolvedFile = path107.resolve(file);
|
|
61110
|
+
if (!fs96.existsSync(resolvedFile)) {
|
|
60221
61111
|
process.exit(0);
|
|
60222
61112
|
}
|
|
60223
61113
|
let projectRoot;
|
|
60224
61114
|
try {
|
|
60225
|
-
projectRoot = findProjectRoot(
|
|
61115
|
+
projectRoot = findProjectRoot(path107.dirname(resolvedFile));
|
|
60226
61116
|
} catch {
|
|
60227
61117
|
process.exit(0);
|
|
60228
61118
|
}
|
|
60229
61119
|
const configResult = await loadConfig(projectRoot);
|
|
60230
61120
|
if (configResult.isErr()) process.exit(0);
|
|
60231
61121
|
const config = configResult.value;
|
|
60232
|
-
const dbPath =
|
|
61122
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
60233
61123
|
ensureGlobalDirs();
|
|
60234
61124
|
const db = initializeDatabase(dbPath);
|
|
60235
61125
|
const store = new Store(db);
|
|
@@ -60257,11 +61147,11 @@ program.command("list").description("List all registered projects").option("--js
|
|
|
60257
61147
|
console.log("No projects registered. Run `trace-mcp add` in a project directory.");
|
|
60258
61148
|
} else {
|
|
60259
61149
|
console.log("Registered projects:\n");
|
|
60260
|
-
for (const
|
|
60261
|
-
const lastIdx =
|
|
60262
|
-
const dbExists =
|
|
60263
|
-
console.log(` ${
|
|
60264
|
-
console.log(` Root: ${
|
|
61150
|
+
for (const p5 of projects) {
|
|
61151
|
+
const lastIdx = p5.lastIndexed ? new Date(p5.lastIndexed).toLocaleString() : "never";
|
|
61152
|
+
const dbExists = fs96.existsSync(p5.dbPath) ? "ok" : "missing";
|
|
61153
|
+
console.log(` ${p5.name}`);
|
|
61154
|
+
console.log(` Root: ${p5.root}`);
|
|
60265
61155
|
console.log(` DB: ${dbExists}`);
|
|
60266
61156
|
console.log(` Last indexed: ${lastIdx}`);
|
|
60267
61157
|
console.log();
|
|
@@ -60271,11 +61161,13 @@ program.command("list").description("List all registered projects").option("--js
|
|
|
60271
61161
|
program.addCommand(initCommand);
|
|
60272
61162
|
program.addCommand(upgradeCommand);
|
|
60273
61163
|
program.addCommand(addCommand);
|
|
61164
|
+
program.addCommand(removeCommand);
|
|
60274
61165
|
program.addCommand(doctorCommand);
|
|
60275
61166
|
program.addCommand(ciReportCommand);
|
|
60276
61167
|
program.addCommand(checkCommand);
|
|
60277
61168
|
program.addCommand(bundlesCommand);
|
|
60278
61169
|
program.addCommand(federationCommand);
|
|
60279
61170
|
program.addCommand(analyticsCommand);
|
|
61171
|
+
program.addCommand(statusCommand);
|
|
60280
61172
|
program.parse();
|
|
60281
61173
|
//# sourceMappingURL=cli.js.map
|