trace-mcp 1.6.1 → 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 +1147 -275
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +43 -2
- package/dist/index.js +337 -19
- 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 +1 -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
|
}
|
|
@@ -5947,7 +6152,7 @@ function extractSymbolSource(content, symbolName, symbolKind) {
|
|
|
5947
6152
|
}
|
|
5948
6153
|
let startLine = -1;
|
|
5949
6154
|
for (let i = 0; i < lines.length; i++) {
|
|
5950
|
-
if (patterns.some((
|
|
6155
|
+
if (patterns.some((p5) => p5.test(lines[i]))) {
|
|
5951
6156
|
startLine = i;
|
|
5952
6157
|
break;
|
|
5953
6158
|
}
|
|
@@ -7409,16 +7614,18 @@ var EnvIndexer = class {
|
|
|
7409
7614
|
|
|
7410
7615
|
// src/indexer/pipeline.ts
|
|
7411
7616
|
var IndexingPipeline = class _IndexingPipeline {
|
|
7412
|
-
constructor(store, registry, config, rootPath) {
|
|
7617
|
+
constructor(store, registry, config, rootPath, progress) {
|
|
7413
7618
|
this.store = store;
|
|
7414
7619
|
this.registry = registry;
|
|
7415
7620
|
this.config = config;
|
|
7416
7621
|
this.rootPath = rootPath;
|
|
7622
|
+
this.progress = progress;
|
|
7417
7623
|
}
|
|
7418
7624
|
store;
|
|
7419
7625
|
registry;
|
|
7420
7626
|
config;
|
|
7421
7627
|
rootPath;
|
|
7628
|
+
progress;
|
|
7422
7629
|
workspaces = [];
|
|
7423
7630
|
_lock = Promise.resolve();
|
|
7424
7631
|
_projectContext;
|
|
@@ -7503,6 +7710,13 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7503
7710
|
errors: 0,
|
|
7504
7711
|
durationMs: 0
|
|
7505
7712
|
};
|
|
7713
|
+
this.progress?.update("indexing", {
|
|
7714
|
+
phase: "running",
|
|
7715
|
+
processed: 0,
|
|
7716
|
+
total: relPaths.length,
|
|
7717
|
+
startedAt: Date.now(),
|
|
7718
|
+
completedAt: 0
|
|
7719
|
+
});
|
|
7506
7720
|
this._projectContext = void 0;
|
|
7507
7721
|
this.registry.clearCaches();
|
|
7508
7722
|
this._changedFileIds.clear();
|
|
@@ -7549,6 +7763,8 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7549
7763
|
persister.persistBatch(extractions);
|
|
7550
7764
|
result.indexed += extractions.length;
|
|
7551
7765
|
}
|
|
7766
|
+
const processed = result.indexed + result.skipped + result.errors;
|
|
7767
|
+
this.progress?.update("indexing", { processed });
|
|
7552
7768
|
}
|
|
7553
7769
|
enableFts5Triggers(this.store.db);
|
|
7554
7770
|
const edgeResolver = new EdgeResolver(this.getPipelineState());
|
|
@@ -7574,6 +7790,11 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
7574
7790
|
}
|
|
7575
7791
|
result.durationMs = Date.now() - startMs;
|
|
7576
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
|
+
});
|
|
7577
7798
|
logger.info(result, "Indexing pipeline completed");
|
|
7578
7799
|
return result;
|
|
7579
7800
|
}
|
|
@@ -8169,14 +8390,16 @@ async function hybridSearch(db, query, vectorStore, embeddingService, limit, rer
|
|
|
8169
8390
|
// src/ai/embedding-pipeline.ts
|
|
8170
8391
|
var DEFAULT_BATCH_SIZE = 50;
|
|
8171
8392
|
var EmbeddingPipeline = class {
|
|
8172
|
-
constructor(store, embeddingService, vectorStore) {
|
|
8393
|
+
constructor(store, embeddingService, vectorStore, progress) {
|
|
8173
8394
|
this.store = store;
|
|
8174
8395
|
this.embeddingService = embeddingService;
|
|
8175
8396
|
this.vectorStore = vectorStore;
|
|
8397
|
+
this.progress = progress;
|
|
8176
8398
|
}
|
|
8177
8399
|
store;
|
|
8178
8400
|
embeddingService;
|
|
8179
8401
|
vectorStore;
|
|
8402
|
+
progress;
|
|
8180
8403
|
async indexSymbol(symbolId, text) {
|
|
8181
8404
|
const embedding = await this.embeddingService.embed(text);
|
|
8182
8405
|
if (embedding.length > 0) {
|
|
@@ -8184,10 +8407,48 @@ var EmbeddingPipeline = class {
|
|
|
8184
8407
|
}
|
|
8185
8408
|
}
|
|
8186
8409
|
/**
|
|
8187
|
-
* Find symbols that don't have embeddings yet and embed them.
|
|
8188
|
-
*
|
|
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.
|
|
8189
8412
|
*/
|
|
8190
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) {
|
|
8191
8452
|
const unembedded = this.store.db.prepare(`
|
|
8192
8453
|
SELECT s.id, s.name, s.fqn, s.kind, s.signature, s.summary
|
|
8193
8454
|
FROM symbols s
|
|
@@ -8218,13 +8479,7 @@ var EmbeddingPipeline = class {
|
|
|
8218
8479
|
*/
|
|
8219
8480
|
async reindexAll() {
|
|
8220
8481
|
this.store.db.exec("DELETE FROM symbol_embeddings");
|
|
8221
|
-
|
|
8222
|
-
let batch;
|
|
8223
|
-
do {
|
|
8224
|
-
batch = await this.indexUnembedded(DEFAULT_BATCH_SIZE);
|
|
8225
|
-
total += batch;
|
|
8226
|
-
} while (batch > 0);
|
|
8227
|
-
return total;
|
|
8482
|
+
return this.indexUnembedded(DEFAULT_BATCH_SIZE);
|
|
8228
8483
|
}
|
|
8229
8484
|
};
|
|
8230
8485
|
function buildEmbeddingText(symbol) {
|
|
@@ -8406,31 +8661,53 @@ import fs12 from "fs";
|
|
|
8406
8661
|
import path12 from "path";
|
|
8407
8662
|
var MAX_SOURCE_LINES = 80;
|
|
8408
8663
|
var SummarizationPipeline = class {
|
|
8409
|
-
constructor(store, inferenceService, rootPath, config) {
|
|
8664
|
+
constructor(store, inferenceService, rootPath, config, progress) {
|
|
8410
8665
|
this.store = store;
|
|
8411
8666
|
this.inferenceService = inferenceService;
|
|
8412
8667
|
this.rootPath = rootPath;
|
|
8413
8668
|
this.config = config;
|
|
8669
|
+
this.progress = progress;
|
|
8414
8670
|
}
|
|
8415
8671
|
store;
|
|
8416
8672
|
inferenceService;
|
|
8417
8673
|
rootPath;
|
|
8418
8674
|
config;
|
|
8675
|
+
progress;
|
|
8419
8676
|
async summarizeUnsummarized() {
|
|
8420
8677
|
let totalSummarized = 0;
|
|
8421
8678
|
let batch;
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
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;
|
|
8434
8711
|
}
|
|
8435
8712
|
return totalSummarized;
|
|
8436
8713
|
}
|
|
@@ -9232,8 +9509,8 @@ var SessionJournal = class _SessionJournal {
|
|
|
9232
9509
|
};
|
|
9233
9510
|
this.entries.push(entry);
|
|
9234
9511
|
if (tool === "get_symbol" || tool === "get_outline") {
|
|
9235
|
-
const
|
|
9236
|
-
if (
|
|
9512
|
+
const path108 = params.path ?? params.file_path ?? "";
|
|
9513
|
+
if (path108) this.filesRead.add(path108);
|
|
9237
9514
|
}
|
|
9238
9515
|
if (resultCount === 0 && this.isSearchTool(tool)) {
|
|
9239
9516
|
this.zeroResultQueries.set(hash, summary);
|
|
@@ -9389,7 +9666,7 @@ var SessionJournal = class _SessionJournal {
|
|
|
9389
9666
|
fileReads.set(file, existing);
|
|
9390
9667
|
}
|
|
9391
9668
|
}
|
|
9392
|
-
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 }));
|
|
9393
9670
|
const editedSet = /* @__PURE__ */ new Set();
|
|
9394
9671
|
for (const entry of this.entries) {
|
|
9395
9672
|
if (entry.tool === "register_edit") {
|
|
@@ -10020,7 +10297,7 @@ function getIndexHealth(store, config) {
|
|
|
10020
10297
|
}
|
|
10021
10298
|
function getProjectMap(store, registry, summaryOnly, projectContext) {
|
|
10022
10299
|
const stats = store.getStats();
|
|
10023
|
-
const frameworks = registry.getAllFrameworkPlugins().map((
|
|
10300
|
+
const frameworks = registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name);
|
|
10024
10301
|
const detectedVersions = projectContext?.detectedVersions;
|
|
10025
10302
|
if (summaryOnly) {
|
|
10026
10303
|
const languageRows2 = store.db.prepare(
|
|
@@ -10133,7 +10410,7 @@ var W_KIND = 0.15;
|
|
|
10133
10410
|
var W_SIGNATURE = 0.25;
|
|
10134
10411
|
var W_TOKEN = 0.15;
|
|
10135
10412
|
function tokenizeName(name) {
|
|
10136
|
-
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);
|
|
10137
10414
|
return new Set(parts);
|
|
10138
10415
|
}
|
|
10139
10416
|
function jaccard(a, b) {
|
|
@@ -10304,10 +10581,13 @@ function registerCoreTools(server, ctx) {
|
|
|
10304
10581
|
const { store, registry, config, projectRoot, guardPath, j: j3, jh, journal } = ctx;
|
|
10305
10582
|
server.tool(
|
|
10306
10583
|
"get_index_health",
|
|
10307
|
-
"Get index status, statistics, and
|
|
10584
|
+
"Get index status, statistics, health information, and pipeline progress (indexing, summarization, embedding)",
|
|
10308
10585
|
{},
|
|
10309
10586
|
async () => {
|
|
10310
10587
|
const result = getIndexHealth(store, config);
|
|
10588
|
+
if (ctx.progress) {
|
|
10589
|
+
result.progress = ctx.progress.snapshot();
|
|
10590
|
+
}
|
|
10311
10591
|
return { content: [{ type: "text", text: j3(result) }] };
|
|
10312
10592
|
}
|
|
10313
10593
|
);
|
|
@@ -10699,8 +10979,8 @@ function getCoChangesForFile(store, filePath, graphFiles) {
|
|
|
10699
10979
|
function findAffectedTests(store, targetPath, dependentPaths) {
|
|
10700
10980
|
const seen = /* @__PURE__ */ new Set();
|
|
10701
10981
|
const allPaths = [targetPath, ...dependentPaths];
|
|
10702
|
-
for (const
|
|
10703
|
-
const file = store.getFile(
|
|
10982
|
+
for (const p5 of allPaths) {
|
|
10983
|
+
const file = store.getFile(p5);
|
|
10704
10984
|
if (!file) continue;
|
|
10705
10985
|
const fileNodeId = store.getNodeId("file", file.id);
|
|
10706
10986
|
if (fileNodeId != null) {
|
|
@@ -10998,9 +11278,9 @@ function deduplicateByFile(rawDeps) {
|
|
|
10998
11278
|
}
|
|
10999
11279
|
}
|
|
11000
11280
|
const result = [];
|
|
11001
|
-
for (const [
|
|
11281
|
+
for (const [path108, entry] of fileMap) {
|
|
11002
11282
|
const dep = {
|
|
11003
|
-
path:
|
|
11283
|
+
path: path108,
|
|
11004
11284
|
edgeTypes: [...entry.edgeTypes],
|
|
11005
11285
|
depth: entry.depth
|
|
11006
11286
|
};
|
|
@@ -11582,7 +11862,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11582
11862
|
}
|
|
11583
11863
|
primarySymbols.push({ sym, file });
|
|
11584
11864
|
}
|
|
11585
|
-
const primaryInternalIds = primarySymbols.map((
|
|
11865
|
+
const primaryInternalIds = primarySymbols.map((p5) => p5.sym.id);
|
|
11586
11866
|
const primaryNodeMap = store.getNodeIdsBatch("symbol", primaryInternalIds);
|
|
11587
11867
|
const primaryNodeIds = primaryInternalIds.map((id) => primaryNodeMap.get(id)).filter((n) => n != null);
|
|
11588
11868
|
const seenDepIds = new Set(primaryInternalIds);
|
|
@@ -11657,7 +11937,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11657
11937
|
}
|
|
11658
11938
|
}
|
|
11659
11939
|
const primaryItems = primarySymbols.map(
|
|
11660
|
-
(
|
|
11940
|
+
(p5, i) => toContextItem(p5.sym, p5.file, rootPath, 1 - i * 0.01)
|
|
11661
11941
|
);
|
|
11662
11942
|
const depItems = depSymbols.map(
|
|
11663
11943
|
(d, i) => toContextItem(d.sym, d.file, rootPath, 0.8 - i * 5e-3)
|
|
@@ -11673,7 +11953,7 @@ function getContextBundle(store, rootPath, opts) {
|
|
|
11673
11953
|
totalBudget: budget
|
|
11674
11954
|
});
|
|
11675
11955
|
const result = {
|
|
11676
|
-
primary: primarySymbols.map((
|
|
11956
|
+
primary: primarySymbols.map((p5) => toBundleItem(p5.sym, p5.file)),
|
|
11677
11957
|
dependencies: depSymbols.slice(0, assembled.dependencies.length).map((d) => toBundleItem(d.sym, d.file)),
|
|
11678
11958
|
callers: callerSymbols.slice(0, assembled.callers.length).map((c) => toBundleItem(c.sym, c.file)),
|
|
11679
11959
|
totalTokens: assembled.totalTokens,
|
|
@@ -12096,7 +12376,7 @@ function suggestQueries(store) {
|
|
|
12096
12376
|
// src/tools/navigation/related.ts
|
|
12097
12377
|
import { ok as ok4, err as err5 } from "neverthrow";
|
|
12098
12378
|
function tokenizeName2(name) {
|
|
12099
|
-
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);
|
|
12100
12380
|
return new Set(parts);
|
|
12101
12381
|
}
|
|
12102
12382
|
function jaccard2(a, b) {
|
|
@@ -13470,8 +13750,8 @@ var NestJSPlugin = class {
|
|
|
13470
13750
|
const patterns = extractMicroservicePatterns(source);
|
|
13471
13751
|
if (patterns.length > 0) {
|
|
13472
13752
|
if (!result.routes) result.routes = [];
|
|
13473
|
-
for (const
|
|
13474
|
-
result.routes.push({ method:
|
|
13753
|
+
for (const p5 of patterns) {
|
|
13754
|
+
result.routes.push({ method: p5.type === "message" ? "MSG" : "EVT", uri: p5.pattern });
|
|
13475
13755
|
}
|
|
13476
13756
|
}
|
|
13477
13757
|
}
|
|
@@ -14381,8 +14661,8 @@ function getLivewireContext(store, componentName) {
|
|
|
14381
14661
|
const properties = [];
|
|
14382
14662
|
const actions = [];
|
|
14383
14663
|
if (Array.isArray(meta.properties)) {
|
|
14384
|
-
for (const
|
|
14385
|
-
properties.push({ name: String(
|
|
14664
|
+
for (const p5 of meta.properties) {
|
|
14665
|
+
properties.push({ name: String(p5.name ?? ""), type: p5.type });
|
|
14386
14666
|
}
|
|
14387
14667
|
}
|
|
14388
14668
|
if (Array.isArray(meta.actions)) {
|
|
@@ -15026,18 +15306,18 @@ function getApiSurface(store, filePattern) {
|
|
|
15026
15306
|
};
|
|
15027
15307
|
}
|
|
15028
15308
|
function getPluginRegistry(store, registry, activeFrameworkNames) {
|
|
15029
|
-
const languagePlugins = registry.getLanguagePlugins().map((
|
|
15030
|
-
name:
|
|
15031
|
-
version:
|
|
15032
|
-
priority:
|
|
15033
|
-
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
|
|
15034
15314
|
}));
|
|
15035
|
-
const frameworkPlugins = registry.getAllFrameworkPlugins().map((
|
|
15036
|
-
name:
|
|
15037
|
-
version:
|
|
15038
|
-
priority:
|
|
15039
|
-
dependencies:
|
|
15040
|
-
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)
|
|
15041
15321
|
}));
|
|
15042
15322
|
const edgeTypes = store.getEdgeTypes();
|
|
15043
15323
|
return {
|
|
@@ -15580,7 +15860,7 @@ function getComplexityTrend(store, cwd, filePath, options = {}) {
|
|
|
15580
15860
|
function registerAnalysisTools(server, ctx) {
|
|
15581
15861
|
const { store, registry, projectRoot, guardPath, j: j3, jh } = ctx;
|
|
15582
15862
|
const frameworkNames = new Set(
|
|
15583
|
-
registry.getAllFrameworkPlugins().map((
|
|
15863
|
+
registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name)
|
|
15584
15864
|
);
|
|
15585
15865
|
server.tool(
|
|
15586
15866
|
"get_implementations",
|
|
@@ -15890,7 +16170,7 @@ var BARREL_PATTERNS = [
|
|
|
15890
16170
|
];
|
|
15891
16171
|
function isBarrelFile(filePath) {
|
|
15892
16172
|
const base = path30.basename(filePath);
|
|
15893
|
-
return BARREL_PATTERNS.some((
|
|
16173
|
+
return BARREL_PATTERNS.some((p5) => p5.test(base));
|
|
15894
16174
|
}
|
|
15895
16175
|
function buildImportedNamesSet(store) {
|
|
15896
16176
|
const importedNames = /* @__PURE__ */ new Set();
|
|
@@ -17057,7 +17337,7 @@ function detectEmptyFunctions(content, lines, symbols, filePath, language) {
|
|
|
17057
17337
|
const strippedLines = body.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).filter((l) => !/^(?:\/\/|#|--|\/\*|\*\/|\*)\s*$/.test(l));
|
|
17058
17338
|
const joined = strippedLines.join("\n");
|
|
17059
17339
|
const isEmpty = strippedLines.length === 0;
|
|
17060
|
-
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));
|
|
17061
17341
|
if (isEmpty || isStub) {
|
|
17062
17342
|
const description = isEmpty ? `Empty ${sym.kind} '${sym.name}' \u2014 no implementation` : `Stub ${sym.kind} '${sym.name}' \u2014 placeholder implementation`;
|
|
17063
17343
|
findings.push({
|
|
@@ -17189,8 +17469,8 @@ function detectHardcodedValues(lines, filePath) {
|
|
|
17189
17469
|
return findings;
|
|
17190
17470
|
}
|
|
17191
17471
|
var PRIORITY_ORDER = { high: 0, medium: 1, low: 2 };
|
|
17192
|
-
function priorityRank(
|
|
17193
|
-
return PRIORITY_ORDER[
|
|
17472
|
+
function priorityRank(p5) {
|
|
17473
|
+
return PRIORITY_ORDER[p5];
|
|
17194
17474
|
}
|
|
17195
17475
|
var BATCH_SIZE2 = 100;
|
|
17196
17476
|
var MAX_FILE_SIZE2 = 512 * 1024;
|
|
@@ -17659,8 +17939,8 @@ function interProceduralAnalysis(store, projectRoot, perFileResults, limit) {
|
|
|
17659
17939
|
const sig = sym.signature ?? "";
|
|
17660
17940
|
const paramMatch = sig.match(/\(([^)]*)\)/);
|
|
17661
17941
|
if (paramMatch) {
|
|
17662
|
-
const params = paramMatch[1].split(",").map((
|
|
17663
|
-
const trimmed =
|
|
17942
|
+
const params = paramMatch[1].split(",").map((p5) => {
|
|
17943
|
+
const trimmed = p5.trim();
|
|
17664
17944
|
const parts = trimmed.split(/[\s:]+/);
|
|
17665
17945
|
return parts[0].replace(/^[&*$]/, "").trim();
|
|
17666
17946
|
});
|
|
@@ -17698,7 +17978,7 @@ function taintAnalysis(store, projectRoot, opts = {}) {
|
|
|
17698
17978
|
const sinkFilter = opts.sinks ? new Set(opts.sinks) : null;
|
|
17699
17979
|
const scope = opts.scope?.replace(/\/+$/, "");
|
|
17700
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();
|
|
17701
|
-
const isTest = (
|
|
17981
|
+
const isTest = (p5) => /(?:^|\/)(?:tests?|__tests__|spec)\/|\.(?:test|spec)\.\w+$/.test(p5);
|
|
17702
17982
|
const sourceFiles = files.filter((f) => !isTest(f.path) && f.language);
|
|
17703
17983
|
let allFlows = [];
|
|
17704
17984
|
let analyzed = 0;
|
|
@@ -19221,7 +19501,7 @@ ${bodyLines.join("\n")}`;
|
|
|
19221
19501
|
callSite = `${baseIndent}${functionName}(${paramStr})`;
|
|
19222
19502
|
}
|
|
19223
19503
|
} else if (lang === "go") {
|
|
19224
|
-
const paramStr = params.map((
|
|
19504
|
+
const paramStr = params.map((p5) => `${p5} interface{}`).join(", ");
|
|
19225
19505
|
const returnTypes = returns.length > 0 ? ` (${returns.map(() => "interface{}").join(", ")})` : "";
|
|
19226
19506
|
functionDef = `func ${functionName}(${paramStr})${returnTypes} {
|
|
19227
19507
|
${bodyLines.join("\n")}`;
|
|
@@ -19842,7 +20122,7 @@ CREATE INDEX IF NOT EXISTS idx_client_calls_target ON client_calls(target_repo_i
|
|
|
19842
20122
|
CREATE INDEX IF NOT EXISTS idx_client_calls_endpoint ON client_calls(matched_endpoint_id);
|
|
19843
20123
|
`;
|
|
19844
20124
|
function findBestEndpointMatch(urlPattern, method, endpoints) {
|
|
19845
|
-
const normalize = (
|
|
20125
|
+
const normalize = (p5) => p5.replace(/\{[^}]+\}/g, "{*}").replace(/:[\w]+/g, "{*}").replace(/\/+$/, "");
|
|
19846
20126
|
const normalizedUrl = normalize(urlPattern);
|
|
19847
20127
|
let bestMatch = null;
|
|
19848
20128
|
let bestScore = 0;
|
|
@@ -20216,9 +20496,9 @@ function detectFromDockerCompose(root) {
|
|
|
20216
20496
|
const composeFiles = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
|
|
20217
20497
|
let composePath;
|
|
20218
20498
|
for (const f of composeFiles) {
|
|
20219
|
-
const
|
|
20220
|
-
if (fs25.existsSync(
|
|
20221
|
-
composePath =
|
|
20499
|
+
const p5 = path36.join(root, f);
|
|
20500
|
+
if (fs25.existsSync(p5)) {
|
|
20501
|
+
composePath = p5;
|
|
20222
20502
|
break;
|
|
20223
20503
|
}
|
|
20224
20504
|
}
|
|
@@ -21692,9 +21972,9 @@ var RuntimeAggregator = class {
|
|
|
21692
21972
|
return { bucketsUpdated: rows.length, nodesAffected: nodesAffected.size };
|
|
21693
21973
|
}
|
|
21694
21974
|
};
|
|
21695
|
-
function percentile(sorted,
|
|
21975
|
+
function percentile(sorted, p5) {
|
|
21696
21976
|
if (sorted.length === 0) return 0;
|
|
21697
|
-
const idx = Math.ceil(
|
|
21977
|
+
const idx = Math.ceil(p5 * sorted.length) - 1;
|
|
21698
21978
|
return sorted[Math.max(0, idx)];
|
|
21699
21979
|
}
|
|
21700
21980
|
|
|
@@ -21706,7 +21986,7 @@ var RuntimeIntelligence = class {
|
|
|
21706
21986
|
this.ingester = new SpanIngester(store.db, config.retention.prune_interval);
|
|
21707
21987
|
this.mapper = new SpanMapper(store, {
|
|
21708
21988
|
fqnAttributes: config.mapping.fqn_attributes,
|
|
21709
|
-
routePatterns: config.mapping.route_patterns.map((
|
|
21989
|
+
routePatterns: config.mapping.route_patterns.map((p5) => new RegExp(p5))
|
|
21710
21990
|
});
|
|
21711
21991
|
this.aggregator = new RuntimeAggregator(store.db);
|
|
21712
21992
|
}
|
|
@@ -22889,16 +23169,16 @@ function findShortestPath(store, startNodeId, endNodeId, maxDepth) {
|
|
|
22889
23169
|
parent.set(nodeId, { from, edgeType: edge.edge_type_name });
|
|
22890
23170
|
nextFrontier.push(nodeId);
|
|
22891
23171
|
if (nodeId === endNodeId) {
|
|
22892
|
-
const
|
|
23172
|
+
const path108 = [endNodeId];
|
|
22893
23173
|
const edgeTypes = [];
|
|
22894
23174
|
let cur = endNodeId;
|
|
22895
23175
|
while (cur !== startNodeId) {
|
|
22896
|
-
const
|
|
22897
|
-
|
|
22898
|
-
edgeTypes.unshift(
|
|
22899
|
-
cur =
|
|
23176
|
+
const p5 = parent.get(cur);
|
|
23177
|
+
path108.unshift(p5.from);
|
|
23178
|
+
edgeTypes.unshift(p5.edgeType);
|
|
23179
|
+
cur = p5.from;
|
|
22900
23180
|
}
|
|
22901
|
-
return { path:
|
|
23181
|
+
return { path: path108, edgeTypes };
|
|
22902
23182
|
}
|
|
22903
23183
|
}
|
|
22904
23184
|
}
|
|
@@ -22920,7 +23200,7 @@ function generateMermaid(nodes, edges, paths) {
|
|
|
22920
23200
|
lines.push(` ${id}["${label}"]`);
|
|
22921
23201
|
}
|
|
22922
23202
|
if (paths && paths.length > 0) {
|
|
22923
|
-
const pathSymbols = new Set(paths.flatMap((
|
|
23203
|
+
const pathSymbols = new Set(paths.flatMap((p5) => p5.map((s) => s.symbol_id)));
|
|
22924
23204
|
const pathIds = [...pathSymbols].map((sid) => idMap.get(sid)).filter(Boolean);
|
|
22925
23205
|
if (pathIds.length > 0) {
|
|
22926
23206
|
lines.push(` style ${pathIds.join(",")} fill:#f9f,stroke:#333,stroke-width:2px`);
|
|
@@ -23182,7 +23462,7 @@ function getDataflow(store, projectRoot, opts) {
|
|
|
23182
23462
|
const retMatch = line.match(/\breturn\s+(.+?)(?:;|\s*$)/);
|
|
23183
23463
|
if (retMatch) {
|
|
23184
23464
|
const expr = retMatch[1].trim();
|
|
23185
|
-
const sources = params.map((
|
|
23465
|
+
const sources = params.map((p5) => p5.name).filter((name) => new RegExp(`\\b${escapeRegex3(name)}\\b`).test(expr));
|
|
23186
23466
|
returns.push({ expression: expr, line: absLine, sources });
|
|
23187
23467
|
}
|
|
23188
23468
|
}
|
|
@@ -23193,7 +23473,7 @@ function getDataflow(store, projectRoot, opts) {
|
|
|
23193
23473
|
const assignMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=\s*(.+?)(?:;|\s*$)/);
|
|
23194
23474
|
if (assignMatch) {
|
|
23195
23475
|
const [, varName, source] = assignMatch;
|
|
23196
|
-
const involvesParam = params.some((
|
|
23476
|
+
const involvesParam = params.some((p5) => new RegExp(`\\b${escapeRegex3(p5.name)}\\b`).test(source));
|
|
23197
23477
|
if (involvesParam || /\w+\s*\(/.test(source)) {
|
|
23198
23478
|
localAssignments.push({
|
|
23199
23479
|
name: varName,
|
|
@@ -23220,15 +23500,15 @@ function parseParameters(signature) {
|
|
|
23220
23500
|
if (!match) return [];
|
|
23221
23501
|
const paramStr = match[1].trim();
|
|
23222
23502
|
if (!paramStr) return [];
|
|
23223
|
-
return paramStr.split(",").map((
|
|
23224
|
-
const trimmed =
|
|
23503
|
+
return paramStr.split(",").map((p5) => {
|
|
23504
|
+
const trimmed = p5.trim();
|
|
23225
23505
|
const tsMatch = trimmed.match(/^(\w+)\??\s*:\s*(.+)$/);
|
|
23226
23506
|
if (tsMatch) return { name: tsMatch[1], type: tsMatch[2].trim() };
|
|
23227
23507
|
const pyMatch = trimmed.match(/^(\w+)(?:\s*:\s*(.+))?$/);
|
|
23228
23508
|
if (pyMatch) return { name: pyMatch[1], type: pyMatch[2]?.trim() ?? null };
|
|
23229
23509
|
const word = trimmed.split(/\s/)[0];
|
|
23230
23510
|
return { name: word, type: null };
|
|
23231
|
-
}).filter((
|
|
23511
|
+
}).filter((p5) => p5.name && p5.name !== "...");
|
|
23232
23512
|
}
|
|
23233
23513
|
function buildCalleeMap(store, symbol) {
|
|
23234
23514
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -23859,7 +24139,7 @@ function predictBugs(store, cwd, options = {}) {
|
|
|
23859
24139
|
const couplingMap = /* @__PURE__ */ new Map();
|
|
23860
24140
|
for (const c of couplingResults) couplingMap.set(c.file, c);
|
|
23861
24141
|
const pagerankMap = /* @__PURE__ */ new Map();
|
|
23862
|
-
for (const
|
|
24142
|
+
for (const p5 of pagerankResults) pagerankMap.set(p5.file, p5);
|
|
23863
24143
|
const complexityRows = store.db.prepare(`
|
|
23864
24144
|
SELECT f.path, MAX(s.cyclomatic) as max_cyclomatic
|
|
23865
24145
|
FROM symbols s JOIN files f ON s.file_id = f.id
|
|
@@ -25365,7 +25645,7 @@ function autoLabel(files) {
|
|
|
25365
25645
|
const segments = /* @__PURE__ */ new Map();
|
|
25366
25646
|
const ignore = /* @__PURE__ */ new Set(["src", "lib", "app", "dist", "build", "node_modules", "vendor", "index"]);
|
|
25367
25647
|
for (const file of files) {
|
|
25368
|
-
const parts = file.split("/").filter((
|
|
25648
|
+
const parts = file.split("/").filter((p5) => !ignore.has(p5) && !p5.includes("."));
|
|
25369
25649
|
for (const part of parts) {
|
|
25370
25650
|
segments.set(part, (segments.get(part) ?? 0) + 1);
|
|
25371
25651
|
}
|
|
@@ -26099,8 +26379,8 @@ function getPackageDeps(options) {
|
|
|
26099
26379
|
const manifest = readManifest(absPath);
|
|
26100
26380
|
repoManifests.set(repoPath, manifest);
|
|
26101
26381
|
const allPublishes = [...entry.publishes ?? [], ...manifest.publishes];
|
|
26102
|
-
for (const
|
|
26103
|
-
publishMap.set(
|
|
26382
|
+
for (const p5 of new Set(allPublishes)) {
|
|
26383
|
+
publishMap.set(p5, { repo: entry.name ?? path44.basename(repoPath), repoPath });
|
|
26104
26384
|
}
|
|
26105
26385
|
}
|
|
26106
26386
|
const results = [];
|
|
@@ -26111,8 +26391,8 @@ function getPackageDeps(options) {
|
|
|
26111
26391
|
for (const [repoPath, manifest] of repoManifests) {
|
|
26112
26392
|
const entry = registry[repoPath];
|
|
26113
26393
|
if (entry?.name === project || path44.basename(repoPath) === project) {
|
|
26114
|
-
for (const
|
|
26115
|
-
targetPackages.add(
|
|
26394
|
+
for (const p5 of manifest.publishes) {
|
|
26395
|
+
targetPackages.add(p5);
|
|
26116
26396
|
}
|
|
26117
26397
|
}
|
|
26118
26398
|
}
|
|
@@ -26149,7 +26429,7 @@ function getPackageDeps(options) {
|
|
|
26149
26429
|
for (const [repoPath, manifest] of repoManifests) {
|
|
26150
26430
|
const entry = registry[repoPath];
|
|
26151
26431
|
const repoName = entry?.name ?? path44.basename(repoPath);
|
|
26152
|
-
const isTarget = manifest.publishes.some((
|
|
26432
|
+
const isTarget = manifest.publishes.some((p5) => targetPackages.has(p5));
|
|
26153
26433
|
if (!isTarget && targetPackages.size > 0) continue;
|
|
26154
26434
|
for (const [dep, info] of manifest.deps) {
|
|
26155
26435
|
const publisher = publishMap.get(dep);
|
|
@@ -26685,10 +26965,10 @@ function getScopeFiles(store, scope, scopePath, query, limit) {
|
|
|
26685
26965
|
function buildFileTree(paths) {
|
|
26686
26966
|
const lines = [];
|
|
26687
26967
|
const sorted = paths.sort();
|
|
26688
|
-
for (const
|
|
26689
|
-
const depth =
|
|
26968
|
+
for (const p5 of sorted.slice(0, 200)) {
|
|
26969
|
+
const depth = p5.split("/").length - 1;
|
|
26690
26970
|
const indent = " ".repeat(Math.min(depth, 6));
|
|
26691
|
-
lines.push(`${indent}${path45.basename(
|
|
26971
|
+
lines.push(`${indent}${path45.basename(p5)}`);
|
|
26692
26972
|
}
|
|
26693
26973
|
if (sorted.length > 200) {
|
|
26694
26974
|
lines.push(` ... and ${sorted.length - 200} more files`);
|
|
@@ -27462,10 +27742,10 @@ function getManifestPath() {
|
|
|
27462
27742
|
return path47.join(BUNDLES_DIR, "manifest.json");
|
|
27463
27743
|
}
|
|
27464
27744
|
function loadManifest() {
|
|
27465
|
-
const
|
|
27466
|
-
if (!fs35.existsSync(
|
|
27745
|
+
const p5 = getManifestPath();
|
|
27746
|
+
if (!fs35.existsSync(p5)) return { bundles: [] };
|
|
27467
27747
|
try {
|
|
27468
|
-
return JSON.parse(fs35.readFileSync(
|
|
27748
|
+
return JSON.parse(fs35.readFileSync(p5, "utf-8"));
|
|
27469
27749
|
} catch {
|
|
27470
27750
|
return { bundles: [] };
|
|
27471
27751
|
}
|
|
@@ -27761,8 +28041,8 @@ var AnalyticsStore = class {
|
|
|
27761
28041
|
db;
|
|
27762
28042
|
constructor(dbPath) {
|
|
27763
28043
|
ensureGlobalDirs();
|
|
27764
|
-
const
|
|
27765
|
-
this.db = new Database5(
|
|
28044
|
+
const p5 = dbPath ?? ANALYTICS_DB_PATH;
|
|
28045
|
+
this.db = new Database5(p5);
|
|
27766
28046
|
this.db.pragma("journal_mode = WAL");
|
|
27767
28047
|
this.db.pragma("foreign_keys = OFF");
|
|
27768
28048
|
this.db.exec(SCHEMA_SQL);
|
|
@@ -28751,6 +29031,94 @@ function benchmarkTaskContext(store, symbols, files, count, rand) {
|
|
|
28751
29031
|
});
|
|
28752
29032
|
return buildScenario("composite_task", "NL task \u2192 optimal code context (baseline: search + read 5-8 files + grep)", details);
|
|
28753
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
|
+
}
|
|
28754
29122
|
function runBenchmark(store, opts = {}) {
|
|
28755
29123
|
const n = opts.queries ?? 10;
|
|
28756
29124
|
const rand = seededRandom(opts.seed ?? 42);
|
|
@@ -28760,8 +29128,13 @@ function runBenchmark(store, opts = {}) {
|
|
|
28760
29128
|
benchmarkSymbolLookup(symbols, n, rand),
|
|
28761
29129
|
benchmarkFileExploration(files, n, rand),
|
|
28762
29130
|
benchmarkSearch(symbols, n, rand),
|
|
29131
|
+
benchmarkFindUsages(store, symbols, n, rand),
|
|
29132
|
+
benchmarkContextBundle(store, symbols, n, rand),
|
|
29133
|
+
benchmarkBatchOverhead(symbols, files, n, rand),
|
|
28763
29134
|
benchmarkImpactAnalysis(store, symbols, n, rand),
|
|
28764
29135
|
benchmarkCallGraph(store, symbols, n, rand),
|
|
29136
|
+
benchmarkTypeHierarchy(store, symbols, n, rand),
|
|
29137
|
+
benchmarkTestsFor(store, symbols, n, rand),
|
|
28765
29138
|
benchmarkTaskContext(store, symbols, files, n, rand)
|
|
28766
29139
|
];
|
|
28767
29140
|
const totalQueries = scenarios.reduce((s, sc) => s + sc.queries, 0);
|
|
@@ -29329,11 +29702,11 @@ function registerPrompts(server, ctx) {
|
|
|
29329
29702
|
sections.push("");
|
|
29330
29703
|
}
|
|
29331
29704
|
}
|
|
29332
|
-
const deadCode = safe2(() => getDeadCodeV2(store, { threshold: 0.5, limit: 10 }), {
|
|
29333
|
-
if (deadCode.
|
|
29334
|
-
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})
|
|
29335
29708
|
`);
|
|
29336
|
-
for (const d of deadCode.
|
|
29709
|
+
for (const d of deadCode.dead_symbols.slice(0, 5)) {
|
|
29337
29710
|
sections.push(`- ${d.name} in ${d.file} (confidence: ${d.confidence})`);
|
|
29338
29711
|
}
|
|
29339
29712
|
sections.push("");
|
|
@@ -29372,10 +29745,10 @@ Provide a thorough code review with risk assessment, suggested tests, and archit
|
|
|
29372
29745
|
sections.push("```json");
|
|
29373
29746
|
sections.push(JSON.stringify(map, null, 2));
|
|
29374
29747
|
sections.push("```\n");
|
|
29375
|
-
const health = safe2(() => getRepoHealth(store),
|
|
29748
|
+
const health = safe2(() => getRepoHealth(store), null);
|
|
29376
29749
|
sections.push("## Architecture Health\n");
|
|
29377
|
-
sections.push(`-
|
|
29378
|
-
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}`);
|
|
29379
29752
|
sections.push("");
|
|
29380
29753
|
sections.push("## Key Entry Points\n");
|
|
29381
29754
|
const context = safe2(() => getFeatureContext(store, projectRoot, "main entry point application startup", 4e3), { symbols: [] });
|
|
@@ -29458,7 +29831,7 @@ Analyze this bug. Identify the most likely failure point, suggest debugging step
|
|
|
29458
29831
|
sections.push(`## Dependency Cycles: ${cycles.length}
|
|
29459
29832
|
`);
|
|
29460
29833
|
for (const c of cycles.slice(0, 5)) {
|
|
29461
|
-
sections.push(`- ${c.join(" \u2192 ")}`);
|
|
29834
|
+
sections.push(`- ${c.files.join(" \u2192 ")}`);
|
|
29462
29835
|
}
|
|
29463
29836
|
sections.push("");
|
|
29464
29837
|
const debt = safe2(() => getTechDebt(store, projectRoot, {
|
|
@@ -29539,11 +29912,11 @@ Analyze this project's architecture health. Identify the most critical issues an
|
|
|
29539
29912
|
sections.push(...riskFiles);
|
|
29540
29913
|
sections.push("");
|
|
29541
29914
|
}
|
|
29542
|
-
const dead = safe2(() => getDeadCodeV2(store, { threshold: 0.6, limit: 10 }), {
|
|
29543
|
-
if (dead.
|
|
29544
|
-
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}
|
|
29545
29918
|
`);
|
|
29546
|
-
for (const d of dead.
|
|
29919
|
+
for (const d of dead.dead_symbols.slice(0, 5)) {
|
|
29547
29920
|
sections.push(`- ${d.name} (${d.file})`);
|
|
29548
29921
|
}
|
|
29549
29922
|
sections.push("");
|
|
@@ -29884,7 +30257,7 @@ function registerSessionTools(server, ctx) {
|
|
|
29884
30257
|
}
|
|
29885
30258
|
|
|
29886
30259
|
// src/server/server.ts
|
|
29887
|
-
var PKG_VERSION = true ? "1.
|
|
30260
|
+
var PKG_VERSION = true ? "1.7.0" : "0.0.0-dev";
|
|
29888
30261
|
function j2(value) {
|
|
29889
30262
|
return JSON.stringify(value, (_key, val) => val === null || val === void 0 ? void 0 : val);
|
|
29890
30263
|
}
|
|
@@ -29988,10 +30361,10 @@ function extractCompactResult(toolName, response) {
|
|
|
29988
30361
|
return void 0;
|
|
29989
30362
|
}
|
|
29990
30363
|
}
|
|
29991
|
-
function createServer2(store, registry, config, rootPath) {
|
|
30364
|
+
function createServer2(store, registry, config, rootPath, progress) {
|
|
29992
30365
|
const projectRoot = rootPath ?? process.cwd();
|
|
29993
30366
|
const frameworkNames = new Set(
|
|
29994
|
-
registry.getAllFrameworkPlugins().map((
|
|
30367
|
+
registry.getAllFrameworkPlugins().map((p5) => p5.manifest.name)
|
|
29995
30368
|
);
|
|
29996
30369
|
const has = (...names) => names.some((n) => frameworkNames.has(n));
|
|
29997
30370
|
const detectedFrameworks = [...frameworkNames].join(", ") || "none";
|
|
@@ -30097,7 +30470,7 @@ function createServer2(store, registry, config, rootPath) {
|
|
|
30097
30470
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
30098
30471
|
const reranker = config.ai?.enabled ? new LLMReranker(aiProvider.fastInference()) : null;
|
|
30099
30472
|
if (config.watch?.enabled !== false) {
|
|
30100
|
-
const knownExtensions = new Set(registry.getLanguagePlugins().flatMap((
|
|
30473
|
+
const knownExtensions = new Set(registry.getLanguagePlugins().flatMap((p5) => p5.supportedExtensions));
|
|
30101
30474
|
const fileWatcher = new FileWatcher(
|
|
30102
30475
|
projectRoot,
|
|
30103
30476
|
async (files) => {
|
|
@@ -30135,7 +30508,8 @@ function createServer2(store, registry, config, rootPath) {
|
|
|
30135
30508
|
guardPath,
|
|
30136
30509
|
j: j2,
|
|
30137
30510
|
jh,
|
|
30138
|
-
markExplored: explored.markExplored
|
|
30511
|
+
markExplored: explored.markExplored,
|
|
30512
|
+
progress: progress ?? null
|
|
30139
30513
|
};
|
|
30140
30514
|
const metaCtx = {
|
|
30141
30515
|
...ctx,
|
|
@@ -31535,8 +31909,8 @@ function extractProps(scriptContent) {
|
|
|
31535
31909
|
const body = typeMatch[1];
|
|
31536
31910
|
const propNames = body.match(/(\w+)\s*[?]?\s*:/g);
|
|
31537
31911
|
if (propNames) {
|
|
31538
|
-
for (const
|
|
31539
|
-
props.push(
|
|
31912
|
+
for (const p5 of propNames) {
|
|
31913
|
+
props.push(p5.replace(/\s*[?]?\s*:/, ""));
|
|
31540
31914
|
}
|
|
31541
31915
|
}
|
|
31542
31916
|
return props;
|
|
@@ -31556,8 +31930,8 @@ function extractProps(scriptContent) {
|
|
|
31556
31930
|
const body = objectMatch[1];
|
|
31557
31931
|
const propNames = body.match(/(\w+)\s*:/g);
|
|
31558
31932
|
if (propNames) {
|
|
31559
|
-
for (const
|
|
31560
|
-
const name =
|
|
31933
|
+
for (const p5 of propNames) {
|
|
31934
|
+
const name = p5.replace(/\s*:/, "");
|
|
31561
31935
|
if (!["type", "default", "required", "validator"].includes(name)) {
|
|
31562
31936
|
props.push(name);
|
|
31563
31937
|
}
|
|
@@ -31692,7 +32066,7 @@ var VueLanguagePlugin = class {
|
|
|
31692
32066
|
kind: "component",
|
|
31693
32067
|
framework: "vue",
|
|
31694
32068
|
...props.length > 0 && {
|
|
31695
|
-
props: Object.fromEntries(props.map((
|
|
32069
|
+
props: Object.fromEntries(props.map((p5) => [p5, { type: "unknown" }]))
|
|
31696
32070
|
},
|
|
31697
32071
|
...emits.length > 0 && { emits },
|
|
31698
32072
|
...composables.length > 0 && { composables }
|
|
@@ -34281,9 +34655,9 @@ function extractImplMethods(body, filePath, typeName, typeSymbolId) {
|
|
|
34281
34655
|
if (isPublic(child)) meta.exported = 1;
|
|
34282
34656
|
const params = child.childForFieldName("parameters");
|
|
34283
34657
|
if (params) {
|
|
34284
|
-
for (const
|
|
34285
|
-
if (
|
|
34286
|
-
meta.receiver =
|
|
34658
|
+
for (const p5 of params.namedChildren) {
|
|
34659
|
+
if (p5.type === "self_parameter") {
|
|
34660
|
+
meta.receiver = p5.text;
|
|
34287
34661
|
break;
|
|
34288
34662
|
}
|
|
34289
34663
|
}
|
|
@@ -36575,7 +36949,7 @@ var ObjCLanguagePlugin = class {
|
|
|
36575
36949
|
const selectorLine = m[2].trim();
|
|
36576
36950
|
const parts = selectorLine.match(/\w+(?=\s*:)|^\w+$/gm);
|
|
36577
36951
|
if (!parts) continue;
|
|
36578
|
-
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("");
|
|
36579
36953
|
const isStatic = prefix === "+";
|
|
36580
36954
|
add(selector, "method", m.index, m[0], { static: isStatic });
|
|
36581
36955
|
}
|
|
@@ -38675,9 +39049,9 @@ var XmlLanguagePlugin = class {
|
|
|
38675
39049
|
}
|
|
38676
39050
|
const schemaLoc = getAttr(attrs, "schemaLocation");
|
|
38677
39051
|
if (schemaLoc) {
|
|
38678
|
-
for (const
|
|
38679
|
-
if (
|
|
38680
|
-
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 } });
|
|
38681
39055
|
}
|
|
38682
39056
|
}
|
|
38683
39057
|
}
|
|
@@ -38741,7 +39115,7 @@ var PrismaPlugin = class {
|
|
|
38741
39115
|
path51.join(ctx.rootPath, "prisma", "schema.prisma"),
|
|
38742
39116
|
path51.join(ctx.rootPath, "schema.prisma")
|
|
38743
39117
|
];
|
|
38744
|
-
return candidates.some((
|
|
39118
|
+
return candidates.some((p5) => fs38.existsSync(p5));
|
|
38745
39119
|
} catch {
|
|
38746
39120
|
return false;
|
|
38747
39121
|
}
|
|
@@ -38812,7 +39186,7 @@ function parsePrismaSchema(source) {
|
|
|
38812
39186
|
const fieldName = fieldMatch[1];
|
|
38813
39187
|
const fieldType = fieldMatch[2];
|
|
38814
39188
|
const attrs = fieldMatch[3] ?? "";
|
|
38815
|
-
if (["@@", "//"].some((
|
|
39189
|
+
if (["@@", "//"].some((p5) => fieldName.startsWith(p5))) continue;
|
|
38816
39190
|
const field = {
|
|
38817
39191
|
name: fieldName,
|
|
38818
39192
|
type: fieldType.replace("?", "").replace("[]", ""),
|
|
@@ -40197,7 +40571,7 @@ import { ok as ok32 } from "neverthrow";
|
|
|
40197
40571
|
function symId3(filePath, name, kind) {
|
|
40198
40572
|
return `${filePath}::${name}#${kind}`;
|
|
40199
40573
|
}
|
|
40200
|
-
function
|
|
40574
|
+
function stripJsonComments2(source) {
|
|
40201
40575
|
let result = "";
|
|
40202
40576
|
let i = 0;
|
|
40203
40577
|
let inString = false;
|
|
@@ -40316,8 +40690,8 @@ function extractEslint(obj, add, edges) {
|
|
|
40316
40690
|
}
|
|
40317
40691
|
}
|
|
40318
40692
|
if (Array.isArray(obj.plugins)) {
|
|
40319
|
-
for (const
|
|
40320
|
-
if (typeof
|
|
40693
|
+
for (const p5 of obj.plugins) {
|
|
40694
|
+
if (typeof p5 === "string") edges.push({ edgeType: "imports", metadata: { module: p5, dialect: "eslint" } });
|
|
40321
40695
|
}
|
|
40322
40696
|
}
|
|
40323
40697
|
}
|
|
@@ -40347,14 +40721,14 @@ function extractLerna(obj, add) {
|
|
|
40347
40721
|
}
|
|
40348
40722
|
function extractBabel(obj, add, edges) {
|
|
40349
40723
|
if (Array.isArray(obj.presets)) {
|
|
40350
|
-
for (const
|
|
40351
|
-
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;
|
|
40352
40726
|
if (name) edges.push({ edgeType: "imports", metadata: { module: name, dialect: "babel" } });
|
|
40353
40727
|
}
|
|
40354
40728
|
}
|
|
40355
40729
|
if (Array.isArray(obj.plugins)) {
|
|
40356
|
-
for (const
|
|
40357
|
-
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;
|
|
40358
40732
|
if (name) edges.push({ edgeType: "imports", metadata: { module: name, dialect: "babel" } });
|
|
40359
40733
|
}
|
|
40360
40734
|
}
|
|
@@ -40450,7 +40824,7 @@ var JsonLanguagePlugin = class {
|
|
|
40450
40824
|
obj = JSON.parse(source);
|
|
40451
40825
|
} catch {
|
|
40452
40826
|
try {
|
|
40453
|
-
obj = JSON.parse(
|
|
40827
|
+
obj = JSON.parse(stripJsonComments2(source));
|
|
40454
40828
|
} catch {
|
|
40455
40829
|
return ok32({ language: "json", status: "ok", symbols: [] });
|
|
40456
40830
|
}
|
|
@@ -45345,8 +45719,8 @@ var SpringPlugin = class {
|
|
|
45345
45719
|
const re = new RegExp(`@${annotation}\\s*(?:\\(\\s*(?:value\\s*=\\s*)?["']([^"']*)["']\\s*\\))?`, "g");
|
|
45346
45720
|
let m;
|
|
45347
45721
|
while ((m = re.exec(source)) !== null) {
|
|
45348
|
-
const
|
|
45349
|
-
const uri = normalizePath(classPrefix + "/" +
|
|
45722
|
+
const path108 = m[1] ?? "";
|
|
45723
|
+
const uri = normalizePath(classPrefix + "/" + path108);
|
|
45350
45724
|
result.routes.push({ method, uri, line: source.substring(0, m.index).split("\n").length });
|
|
45351
45725
|
}
|
|
45352
45726
|
}
|
|
@@ -45406,8 +45780,8 @@ var SpringPlugin = class {
|
|
|
45406
45780
|
}
|
|
45407
45781
|
}
|
|
45408
45782
|
};
|
|
45409
|
-
function normalizePath(
|
|
45410
|
-
return "/" +
|
|
45783
|
+
function normalizePath(path108) {
|
|
45784
|
+
return "/" + path108.replace(/\/+/g, "/").replace(/^\/|\/$/g, "");
|
|
45411
45785
|
}
|
|
45412
45786
|
|
|
45413
45787
|
// src/indexer/plugins/integration/framework/express/index.ts
|
|
@@ -46915,8 +47289,8 @@ var NextJSPlugin = class {
|
|
|
46915
47289
|
const fileSymbols = ctx.getSymbolsByFile(file.id);
|
|
46916
47290
|
const fileSym = fileSymbols.find((s) => s.kind === "function" || s.kind === "class");
|
|
46917
47291
|
if (!fileSym) continue;
|
|
46918
|
-
const targetPage = pages.find((
|
|
46919
|
-
const pageRoute = appRouterPathToRoute(
|
|
47292
|
+
const targetPage = pages.find((p5) => {
|
|
47293
|
+
const pageRoute = appRouterPathToRoute(p5.path);
|
|
46920
47294
|
return pageRoute === info.interceptedRoute;
|
|
46921
47295
|
});
|
|
46922
47296
|
if (targetPage) {
|
|
@@ -48675,8 +49049,8 @@ var RawSqlPlugin = class {
|
|
|
48675
49049
|
...pkg.dependencies,
|
|
48676
49050
|
...pkg.devDependencies
|
|
48677
49051
|
};
|
|
48678
|
-
for (const
|
|
48679
|
-
if (
|
|
49052
|
+
for (const p5 of RAW_SQL_PACKAGES) {
|
|
49053
|
+
if (p5 in deps) return true;
|
|
48680
49054
|
}
|
|
48681
49055
|
} catch {
|
|
48682
49056
|
}
|
|
@@ -49363,8 +49737,8 @@ function extractExpoNavigationCalls(source) {
|
|
|
49363
49737
|
}
|
|
49364
49738
|
const templateRegex = /router\.(push|replace|navigate)\s*\(\s*`([^`]+)`/g;
|
|
49365
49739
|
while ((match = templateRegex.exec(source)) !== null) {
|
|
49366
|
-
const
|
|
49367
|
-
paths.push(
|
|
49740
|
+
const path108 = match[2].replace(/\$\{[^}]+\}/g, ":param");
|
|
49741
|
+
paths.push(path108);
|
|
49368
49742
|
}
|
|
49369
49743
|
const linkRegex = /<Link\s+[^>]*href\s*=\s*(?:\{?\s*)?['"]([^'"]+)['"]/g;
|
|
49370
49744
|
while ((match = linkRegex.exec(source)) !== null) {
|
|
@@ -49376,9 +49750,9 @@ function extractExpoNavigationCalls(source) {
|
|
|
49376
49750
|
}
|
|
49377
49751
|
return [...new Set(paths)];
|
|
49378
49752
|
}
|
|
49379
|
-
function matchExpoRoute(
|
|
49380
|
-
if (
|
|
49381
|
-
const pathParts =
|
|
49753
|
+
function matchExpoRoute(path108, routePattern) {
|
|
49754
|
+
if (path108 === routePattern) return true;
|
|
49755
|
+
const pathParts = path108.split("/").filter(Boolean);
|
|
49382
49756
|
const routeParts = routePattern.split("/").filter(Boolean);
|
|
49383
49757
|
if (pathParts.length !== routeParts.length) {
|
|
49384
49758
|
if (routeParts[routeParts.length - 1] === "*" && pathParts.length >= routeParts.length - 1) {
|
|
@@ -50336,7 +50710,7 @@ var ShadcnPlugin = class {
|
|
|
50336
50710
|
name: comp.name,
|
|
50337
50711
|
kind: "component",
|
|
50338
50712
|
framework: "shadcn-vue",
|
|
50339
|
-
props: Object.fromEntries(comp.props.map((
|
|
50713
|
+
props: Object.fromEntries(comp.props.map((p5) => [p5, true])),
|
|
50340
50714
|
emits: comp.emits,
|
|
50341
50715
|
slots: comp.slots
|
|
50342
50716
|
});
|
|
@@ -51323,7 +51697,7 @@ var NuxtUiPlugin = class {
|
|
|
51323
51697
|
name: usage.name,
|
|
51324
51698
|
kind: "component",
|
|
51325
51699
|
framework: isPro ? "nuxt-ui-pro" : "nuxt-ui",
|
|
51326
|
-
props: Object.fromEntries(usage.propsUsed.map((
|
|
51700
|
+
props: Object.fromEntries(usage.propsUsed.map((p5) => [p5, true]))
|
|
51327
51701
|
});
|
|
51328
51702
|
result.edges.push({
|
|
51329
51703
|
edgeType: isPro ? "nuxt_ui_pro_component" : "nuxt_ui_component",
|
|
@@ -53466,11 +53840,11 @@ function detectTestFramework(source, _filePath) {
|
|
|
53466
53840
|
function extractTestedRoutes(source) {
|
|
53467
53841
|
const routes = [];
|
|
53468
53842
|
const seen = /* @__PURE__ */ new Set();
|
|
53469
|
-
function add(
|
|
53470
|
-
const key = `${method ?? ""}:${
|
|
53843
|
+
function add(p5, method) {
|
|
53844
|
+
const key = `${method ?? ""}:${p5}`;
|
|
53471
53845
|
if (!seen.has(key)) {
|
|
53472
53846
|
seen.add(key);
|
|
53473
|
-
routes.push({ path:
|
|
53847
|
+
routes.push({ path: p5, method });
|
|
53474
53848
|
}
|
|
53475
53849
|
}
|
|
53476
53850
|
let m;
|
|
@@ -55374,8 +55748,8 @@ var CommanderPlugin = class {
|
|
|
55374
55748
|
...pkg.dependencies,
|
|
55375
55749
|
...pkg.devDependencies
|
|
55376
55750
|
};
|
|
55377
|
-
for (const
|
|
55378
|
-
if (
|
|
55751
|
+
for (const p5 of CLI_PACKAGES) {
|
|
55752
|
+
if (p5 in deps) return true;
|
|
55379
55753
|
}
|
|
55380
55754
|
} catch {
|
|
55381
55755
|
return false;
|
|
@@ -55472,8 +55846,8 @@ var TreeSitterPlugin = class {
|
|
|
55472
55846
|
...pkg.dependencies,
|
|
55473
55847
|
...pkg.devDependencies
|
|
55474
55848
|
};
|
|
55475
|
-
for (const
|
|
55476
|
-
if (
|
|
55849
|
+
for (const p5 of TREE_SITTER_PACKAGES) {
|
|
55850
|
+
if (p5 in deps) return true;
|
|
55477
55851
|
}
|
|
55478
55852
|
} catch {
|
|
55479
55853
|
return false;
|
|
@@ -55603,8 +55977,8 @@ var BuildToolsPlugin = class {
|
|
|
55603
55977
|
...pkg.dependencies,
|
|
55604
55978
|
...pkg.devDependencies
|
|
55605
55979
|
};
|
|
55606
|
-
for (const
|
|
55607
|
-
if (
|
|
55980
|
+
for (const p5 of BUILD_PACKAGES) {
|
|
55981
|
+
if (p5 in deps) return true;
|
|
55608
55982
|
}
|
|
55609
55983
|
} catch {
|
|
55610
55984
|
return false;
|
|
@@ -55750,8 +56124,8 @@ var PinoPlugin = class {
|
|
|
55750
56124
|
...pkg.dependencies,
|
|
55751
56125
|
...pkg.devDependencies
|
|
55752
56126
|
};
|
|
55753
|
-
for (const
|
|
55754
|
-
if (
|
|
56127
|
+
for (const p5 of LOGGING_PACKAGES) {
|
|
56128
|
+
if (p5 in deps) return true;
|
|
55755
56129
|
}
|
|
55756
56130
|
} catch {
|
|
55757
56131
|
return false;
|
|
@@ -55825,8 +56199,8 @@ var CosmiconfigPlugin = class {
|
|
|
55825
56199
|
...pkg.dependencies,
|
|
55826
56200
|
...pkg.devDependencies
|
|
55827
56201
|
};
|
|
55828
|
-
for (const
|
|
55829
|
-
if (
|
|
56202
|
+
for (const p5 of CONFIG_PACKAGES) {
|
|
56203
|
+
if (p5 in deps) return true;
|
|
55830
56204
|
}
|
|
55831
56205
|
} catch {
|
|
55832
56206
|
return false;
|
|
@@ -55897,8 +56271,8 @@ var NeverthrowPlugin = class {
|
|
|
55897
56271
|
...pkg.dependencies,
|
|
55898
56272
|
...pkg.devDependencies
|
|
55899
56273
|
};
|
|
55900
|
-
for (const
|
|
55901
|
-
if (
|
|
56274
|
+
for (const p5 of RESULT_PACKAGES) {
|
|
56275
|
+
if (p5 in deps) return true;
|
|
55902
56276
|
}
|
|
55903
56277
|
} catch {
|
|
55904
56278
|
return false;
|
|
@@ -55978,8 +56352,8 @@ var ClackPlugin = class {
|
|
|
55978
56352
|
...pkg.dependencies,
|
|
55979
56353
|
...pkg.devDependencies
|
|
55980
56354
|
};
|
|
55981
|
-
for (const
|
|
55982
|
-
if (
|
|
56355
|
+
for (const p5 of PROMPT_PACKAGES) {
|
|
56356
|
+
if (p5 in deps) return true;
|
|
55983
56357
|
}
|
|
55984
56358
|
} catch {
|
|
55985
56359
|
return false;
|
|
@@ -56109,9 +56483,9 @@ var FileWatcher2 = class {
|
|
|
56109
56483
|
logger.error({ error: err32 }, "Watcher error");
|
|
56110
56484
|
return;
|
|
56111
56485
|
}
|
|
56112
|
-
const notIgnored = (
|
|
56113
|
-
if (ignoreDirs.some((d) =>
|
|
56114
|
-
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);
|
|
56115
56489
|
return !traceignore.isIgnored(rel);
|
|
56116
56490
|
};
|
|
56117
56491
|
const changed = events.filter((e) => e.type === "create" || e.type === "update").map((e) => e.path).filter(notIgnored);
|
|
@@ -56121,7 +56495,7 @@ var FileWatcher2 = class {
|
|
|
56121
56495
|
await onDeletes(deleted);
|
|
56122
56496
|
}
|
|
56123
56497
|
if (changed.length === 0) return;
|
|
56124
|
-
for (const
|
|
56498
|
+
for (const p5 of changed) this.pendingPaths.add(p5);
|
|
56125
56499
|
if (this.debounceTimer) this._clearTimeout(this.debounceTimer);
|
|
56126
56500
|
this.debounceTimer = this._setTimeout(async () => {
|
|
56127
56501
|
const paths = Array.from(this.pendingPaths);
|
|
@@ -56155,6 +56529,122 @@ var FileWatcher2 = class {
|
|
|
56155
56529
|
}
|
|
56156
56530
|
};
|
|
56157
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
|
+
|
|
56158
56648
|
// src/cli.ts
|
|
56159
56649
|
import http from "http";
|
|
56160
56650
|
|
|
@@ -56430,7 +56920,7 @@ import path95 from "path";
|
|
|
56430
56920
|
import os6 from "os";
|
|
56431
56921
|
|
|
56432
56922
|
// src/init/types.ts
|
|
56433
|
-
var GUARD_HOOK_VERSION = "0.
|
|
56923
|
+
var GUARD_HOOK_VERSION = "0.5.0";
|
|
56434
56924
|
var REINDEX_HOOK_VERSION = "0.1.0";
|
|
56435
56925
|
var PRECOMPACT_HOOK_VERSION = "0.1.0";
|
|
56436
56926
|
var WORKTREE_HOOK_VERSION = "0.1.0";
|
|
@@ -56452,7 +56942,7 @@ var CLIENTS = [
|
|
|
56452
56942
|
var GUARD_HOOK = {
|
|
56453
56943
|
scriptName: "trace-mcp-guard",
|
|
56454
56944
|
settingsKey: "PreToolUse",
|
|
56455
|
-
matcher: "Read|Grep|Glob|Bash",
|
|
56945
|
+
matcher: "Read|Grep|Glob|Bash|Agent",
|
|
56456
56946
|
version: GUARD_HOOK_VERSION,
|
|
56457
56947
|
dryRunLabel: "Would install guard hook"
|
|
56458
56948
|
};
|
|
@@ -56542,7 +57032,10 @@ function removeHookEntry(settings, desc) {
|
|
|
56542
57032
|
const entries = hooks[desc.settingsKey];
|
|
56543
57033
|
if (!Array.isArray(entries)) return;
|
|
56544
57034
|
hooks[desc.settingsKey] = entries.filter(
|
|
56545
|
-
(h) =>
|
|
57035
|
+
(h) => {
|
|
57036
|
+
const entry = h;
|
|
57037
|
+
return !entry.hooks?.some((hh) => hh.command?.includes(desc.scriptName));
|
|
57038
|
+
}
|
|
56546
57039
|
);
|
|
56547
57040
|
if (hooks[desc.settingsKey].length === 0) delete hooks[desc.settingsKey];
|
|
56548
57041
|
if (Object.keys(hooks).length === 0) delete settings.hooks;
|
|
@@ -56720,12 +57213,12 @@ function detectProject(dir) {
|
|
|
56720
57213
|
const ctx = buildProjectContext(projectRoot);
|
|
56721
57214
|
const packageManagers = detectPackageManagers(projectRoot);
|
|
56722
57215
|
const registry = new PluginRegistry();
|
|
56723
|
-
for (const
|
|
56724
|
-
for (const
|
|
57216
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
57217
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
56725
57218
|
const activeResult = registry.getActiveFrameworkPlugins(ctx);
|
|
56726
|
-
const frameworks = activeResult.isOk() ? activeResult.value.map((
|
|
56727
|
-
const dep = ctx.allDependencies.find((d) => d.name ===
|
|
56728
|
-
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 };
|
|
56729
57222
|
}) : [];
|
|
56730
57223
|
const languageMap = {
|
|
56731
57224
|
node: "TypeScript",
|
|
@@ -56843,8 +57336,8 @@ function detectExistingConfig(root) {
|
|
|
56843
57336
|
path97.join(root, ".trace-mcp.json"),
|
|
56844
57337
|
path97.join(root, ".config", "trace-mcp.json")
|
|
56845
57338
|
];
|
|
56846
|
-
for (const
|
|
56847
|
-
if (fs84.existsSync(
|
|
57339
|
+
for (const p5 of candidates) {
|
|
57340
|
+
if (fs84.existsSync(p5)) return { path: p5 };
|
|
56848
57341
|
}
|
|
56849
57342
|
const pkgPath = path97.join(root, "package.json");
|
|
56850
57343
|
if (fs84.existsSync(pkgPath)) {
|
|
@@ -56858,7 +57351,7 @@ function detectExistingConfig(root) {
|
|
|
56858
57351
|
}
|
|
56859
57352
|
function detectExistingDb(root, globalDbPath) {
|
|
56860
57353
|
const candidates = globalDbPath ? [globalDbPath, path97.join(root, ".trace-mcp", "index.db")] : [path97.join(root, ".trace-mcp", "index.db")];
|
|
56861
|
-
const dbPath = candidates.find((
|
|
57354
|
+
const dbPath = candidates.find((p5) => fs84.existsSync(p5));
|
|
56862
57355
|
if (!dbPath) return null;
|
|
56863
57356
|
try {
|
|
56864
57357
|
const db = new Database6(dbPath, { readonly: true });
|
|
@@ -57469,9 +57962,9 @@ function scanGlobalArtifacts() {
|
|
|
57469
57962
|
}
|
|
57470
57963
|
return conflicts;
|
|
57471
57964
|
}
|
|
57472
|
-
function shortPath(
|
|
57473
|
-
if (
|
|
57474
|
-
return
|
|
57965
|
+
function shortPath(p5) {
|
|
57966
|
+
if (p5.startsWith(HOME4)) return "~" + p5.slice(HOME4.length);
|
|
57967
|
+
return p5;
|
|
57475
57968
|
}
|
|
57476
57969
|
function truncate(s, maxLen) {
|
|
57477
57970
|
return s.length > maxLen ? s.slice(0, maxLen - 1) + "\u2026" : s;
|
|
@@ -57754,10 +58247,10 @@ function fixGlobalArtifact(conflict, opts) {
|
|
|
57754
58247
|
return { conflictId: conflict.id, action: "skipped", detail: `Failed to remove: ${err32.message}`, target: dirPath };
|
|
57755
58248
|
}
|
|
57756
58249
|
}
|
|
57757
|
-
function shortPath2(
|
|
58250
|
+
function shortPath2(p5) {
|
|
57758
58251
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
57759
|
-
if (home &&
|
|
57760
|
-
return
|
|
58252
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58253
|
+
return p5;
|
|
57761
58254
|
}
|
|
57762
58255
|
|
|
57763
58256
|
// src/project-root.ts
|
|
@@ -58024,16 +58517,16 @@ function generateConfig(detection) {
|
|
|
58024
58517
|
for (const fw of detection.frameworks) {
|
|
58025
58518
|
const preset = FRAMEWORK_PRESETS[fw.name];
|
|
58026
58519
|
if (preset) {
|
|
58027
|
-
for (const
|
|
58028
|
-
for (const
|
|
58520
|
+
for (const p5 of preset.include) include.add(p5);
|
|
58521
|
+
for (const p5 of preset.exclude) exclude.add(p5);
|
|
58029
58522
|
}
|
|
58030
58523
|
}
|
|
58031
58524
|
if (include.size === 0) {
|
|
58032
58525
|
for (const lang of detection.languages) {
|
|
58033
58526
|
const preset = LANGUAGE_PRESETS[lang.toLowerCase()];
|
|
58034
58527
|
if (preset) {
|
|
58035
|
-
for (const
|
|
58036
|
-
for (const
|
|
58528
|
+
for (const p5 of preset.include) include.add(p5);
|
|
58529
|
+
for (const p5 of preset.exclude) exclude.add(p5);
|
|
58037
58530
|
}
|
|
58038
58531
|
}
|
|
58039
58532
|
}
|
|
@@ -58283,7 +58776,16 @@ var initCommand = new Command("init").description("One-time global setup: config
|
|
|
58283
58776
|
}
|
|
58284
58777
|
}
|
|
58285
58778
|
if (indexProject) {
|
|
58286
|
-
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
|
+
}
|
|
58287
58789
|
steps.push(indexStep);
|
|
58288
58790
|
}
|
|
58289
58791
|
const existingProjects = listProjects();
|
|
@@ -58365,7 +58867,7 @@ var initCommand = new Command("init").description("One-time global setup: config
|
|
|
58365
58867
|
p.note(lines.join("\n"), "Already configured");
|
|
58366
58868
|
}
|
|
58367
58869
|
p.outro(
|
|
58368
|
-
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."
|
|
58369
58871
|
);
|
|
58370
58872
|
}
|
|
58371
58873
|
});
|
|
@@ -58397,7 +58899,31 @@ function executeSteps(steps, opts) {
|
|
|
58397
58899
|
steps.push(mdResult);
|
|
58398
58900
|
}
|
|
58399
58901
|
}
|
|
58400
|
-
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) {
|
|
58401
58927
|
let projectRoot = null;
|
|
58402
58928
|
try {
|
|
58403
58929
|
projectRoot = findProjectRoot(dir);
|
|
@@ -58408,7 +58934,7 @@ function registerAndIndexProject(dir, opts) {
|
|
|
58408
58934
|
if (childRoots.length === 0) {
|
|
58409
58935
|
return { target: dir, action: "skipped", detail: "Could not detect project root or child projects" };
|
|
58410
58936
|
}
|
|
58411
|
-
return registerMultiRootProject(dir, childRoots, opts);
|
|
58937
|
+
return await registerMultiRootProject(dir, childRoots, opts);
|
|
58412
58938
|
}
|
|
58413
58939
|
if (opts.dryRun) {
|
|
58414
58940
|
return { target: projectRoot, action: "skipped", detail: "Would register and index project" };
|
|
@@ -58428,13 +58954,15 @@ function registerAndIndexProject(dir, opts) {
|
|
|
58428
58954
|
const db = initializeDatabase(dbPath);
|
|
58429
58955
|
db.close();
|
|
58430
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)`;
|
|
58431
58959
|
return {
|
|
58432
58960
|
target: projectRoot,
|
|
58433
58961
|
action: existing ? "updated" : "created",
|
|
58434
|
-
detail
|
|
58962
|
+
detail
|
|
58435
58963
|
};
|
|
58436
58964
|
}
|
|
58437
|
-
function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
58965
|
+
async function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
58438
58966
|
if (opts.dryRun) {
|
|
58439
58967
|
return {
|
|
58440
58968
|
target: parentDir,
|
|
@@ -58474,10 +59002,12 @@ function registerMultiRootProject(parentDir, childRoots, opts) {
|
|
|
58474
59002
|
const db = initializeDatabase(dbPath);
|
|
58475
59003
|
db.close();
|
|
58476
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)`;
|
|
58477
59007
|
return {
|
|
58478
59008
|
target: parentDir,
|
|
58479
59009
|
action: existing ? "updated" : "created",
|
|
58480
|
-
detail
|
|
59010
|
+
detail
|
|
58481
59011
|
};
|
|
58482
59012
|
}
|
|
58483
59013
|
function formatClientName(name) {
|
|
@@ -58491,12 +59021,12 @@ function formatClientName(name) {
|
|
|
58491
59021
|
};
|
|
58492
59022
|
return names[name] ?? name;
|
|
58493
59023
|
}
|
|
58494
|
-
function shortPath3(
|
|
59024
|
+
function shortPath3(p5) {
|
|
58495
59025
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58496
|
-
if (home &&
|
|
59026
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58497
59027
|
const cwd = process.cwd();
|
|
58498
|
-
if (
|
|
58499
|
-
return
|
|
59028
|
+
if (p5.startsWith(cwd)) return p5.slice(cwd.length + 1) || ".";
|
|
59029
|
+
return p5;
|
|
58500
59030
|
}
|
|
58501
59031
|
|
|
58502
59032
|
// src/cli/upgrade.ts
|
|
@@ -58513,11 +59043,11 @@ var upgradeCommand = new Command2("upgrade").description("Upgrade trace-mcp: run
|
|
|
58513
59043
|
console.error("No registered projects. Run `trace-mcp add` first, or specify a directory.");
|
|
58514
59044
|
process.exit(1);
|
|
58515
59045
|
}
|
|
58516
|
-
for (const
|
|
58517
|
-
if (fs90.existsSync(
|
|
58518
|
-
projectRoots.push(
|
|
59046
|
+
for (const p5 of projects) {
|
|
59047
|
+
if (fs90.existsSync(p5.root)) {
|
|
59048
|
+
projectRoots.push(p5.root);
|
|
58519
59049
|
} else {
|
|
58520
|
-
logger.warn({ root:
|
|
59050
|
+
logger.warn({ root: p5.root }, "Skipping stale project (directory not found)");
|
|
58521
59051
|
}
|
|
58522
59052
|
}
|
|
58523
59053
|
}
|
|
@@ -58547,8 +59077,8 @@ var upgradeCommand = new Command2("upgrade").description("Upgrade trace-mcp: run
|
|
|
58547
59077
|
});
|
|
58548
59078
|
if (!opts.skipReindex) {
|
|
58549
59079
|
const registry = new PluginRegistry();
|
|
58550
|
-
for (const
|
|
58551
|
-
for (const
|
|
59080
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
59081
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
58552
59082
|
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
58553
59083
|
const result = await pipeline.indexAll(true);
|
|
58554
59084
|
steps.push({
|
|
@@ -58611,7 +59141,39 @@ import { Command as Command3 } from "commander";
|
|
|
58611
59141
|
import fs91 from "fs";
|
|
58612
59142
|
import path104 from "path";
|
|
58613
59143
|
import * as p2 from "@clack/prompts";
|
|
58614
|
-
|
|
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) => {
|
|
58615
59177
|
const resolvedDir = path104.resolve(dir);
|
|
58616
59178
|
if (!fs91.existsSync(resolvedDir)) {
|
|
58617
59179
|
console.error(`Directory does not exist: ${resolvedDir}`);
|
|
@@ -58697,6 +59259,21 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58697
59259
|
const db = initializeDatabase(dbPath);
|
|
58698
59260
|
db.close();
|
|
58699
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
|
+
}
|
|
58700
59277
|
if (opts.json) {
|
|
58701
59278
|
console.log(JSON.stringify({
|
|
58702
59279
|
status: existing ? "re-registered" : "registered",
|
|
@@ -58705,7 +59282,8 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58705
59282
|
detection: {
|
|
58706
59283
|
languages: detection.languages,
|
|
58707
59284
|
frameworks: detection.frameworks.map((f) => f.name)
|
|
58708
|
-
}
|
|
59285
|
+
},
|
|
59286
|
+
indexing: indexResult ?? void 0
|
|
58709
59287
|
}, null, 2));
|
|
58710
59288
|
} else {
|
|
58711
59289
|
const lines = [];
|
|
@@ -58715,8 +59293,16 @@ DB: ${shortPath4(existing.dbPath)}`, "Existing");
|
|
|
58715
59293
|
if (migrated) {
|
|
58716
59294
|
lines.push(`Migrated existing index from .trace-mcp/index.db`);
|
|
58717
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
|
+
}
|
|
58718
59300
|
p2.note(lines.join("\n"), existing ? "Re-registered" : "Registered");
|
|
58719
|
-
|
|
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
|
+
}
|
|
58720
59306
|
}
|
|
58721
59307
|
});
|
|
58722
59308
|
async function handleMultiRoot(parentDir, childRoots, opts) {
|
|
@@ -58799,13 +59385,29 @@ Discovered ${childRoots.length} child project(s):
|
|
|
58799
59385
|
type: "multi-root",
|
|
58800
59386
|
children: childRoots
|
|
58801
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
|
+
}
|
|
58802
59403
|
if (opts.json) {
|
|
58803
59404
|
console.log(JSON.stringify({
|
|
58804
59405
|
status: existing ? "re-registered" : "registered",
|
|
58805
59406
|
type: "multi-root",
|
|
58806
59407
|
project: entry,
|
|
58807
59408
|
children: childRoots.map((r) => path104.basename(r)),
|
|
58808
|
-
cleaned
|
|
59409
|
+
cleaned,
|
|
59410
|
+
indexing: indexResult ?? void 0
|
|
58809
59411
|
}, null, 2));
|
|
58810
59412
|
} else {
|
|
58811
59413
|
const lines = [];
|
|
@@ -58813,14 +59415,22 @@ Discovered ${childRoots.length} child project(s):
|
|
|
58813
59415
|
lines.push(`Root: ${parentDir}`);
|
|
58814
59416
|
lines.push(`DB: ${shortPath4(dbPath)}`);
|
|
58815
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
|
+
}
|
|
58816
59422
|
p2.note(lines.join("\n"), existing ? "Re-registered" : "Registered");
|
|
58817
|
-
|
|
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
|
+
}
|
|
58818
59428
|
}
|
|
58819
59429
|
}
|
|
58820
|
-
function shortPath4(
|
|
59430
|
+
function shortPath4(p5) {
|
|
58821
59431
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58822
|
-
if (home &&
|
|
58823
|
-
return
|
|
59432
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
59433
|
+
return p5;
|
|
58824
59434
|
}
|
|
58825
59435
|
|
|
58826
59436
|
// src/cli/doctor.ts
|
|
@@ -58882,11 +59492,11 @@ var doctorCommand = new Command4("doctor").description("Check for competing tool
|
|
|
58882
59492
|
return;
|
|
58883
59493
|
}
|
|
58884
59494
|
if (!opts.dryRun) {
|
|
58885
|
-
const
|
|
59495
|
+
const confirm4 = await p3.confirm({
|
|
58886
59496
|
message: `Fix ${fixable2.length} conflict${fixable2.length > 1 ? "s" : ""} automatically?`,
|
|
58887
59497
|
initialValue: true
|
|
58888
59498
|
});
|
|
58889
|
-
if (p3.isCancel(
|
|
59499
|
+
if (p3.isCancel(confirm4) || !confirm4) {
|
|
58890
59500
|
p3.cancel("No changes made.");
|
|
58891
59501
|
return;
|
|
58892
59502
|
}
|
|
@@ -58952,12 +59562,12 @@ function printFixResults(results, dryRun) {
|
|
|
58952
59562
|
p3.outro("Dry run complete \u2014 no changes made. Run with --fix to apply.");
|
|
58953
59563
|
}
|
|
58954
59564
|
}
|
|
58955
|
-
function shortPath5(
|
|
59565
|
+
function shortPath5(p5) {
|
|
58956
59566
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
58957
|
-
if (home &&
|
|
59567
|
+
if (home && p5.startsWith(home)) return "~" + p5.slice(home.length);
|
|
58958
59568
|
const cwd = process.cwd();
|
|
58959
|
-
if (
|
|
58960
|
-
return
|
|
59569
|
+
if (p5.startsWith(cwd)) return p5.slice(cwd.length + 1) || ".";
|
|
59570
|
+
return p5;
|
|
58961
59571
|
}
|
|
58962
59572
|
|
|
58963
59573
|
// src/cli/ci.ts
|
|
@@ -59321,8 +59931,8 @@ ${msg}
|
|
|
59321
59931
|
const store = new Store(db);
|
|
59322
59932
|
if (opts.index) {
|
|
59323
59933
|
const registry = new PluginRegistry();
|
|
59324
|
-
for (const
|
|
59325
|
-
for (const
|
|
59934
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
59935
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59326
59936
|
logger.info("CI report: indexing project...");
|
|
59327
59937
|
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
59328
59938
|
await pipeline.indexAll(false);
|
|
@@ -59445,8 +60055,8 @@ var checkCommand = new Command6("check").description("Run quality gate checks ag
|
|
|
59445
60055
|
const store = new Store(db);
|
|
59446
60056
|
if (opts.index) {
|
|
59447
60057
|
const registry = new PluginRegistry();
|
|
59448
|
-
for (const
|
|
59449
|
-
for (const
|
|
60058
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
60059
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59450
60060
|
logger.info("Indexing project before quality check...");
|
|
59451
60061
|
const pipeline = new IndexingPipeline(store, registry, config, projectRoot);
|
|
59452
60062
|
await pipeline.indexAll(false);
|
|
@@ -59928,13 +60538,269 @@ analyticsCommand.command("trends").description("Show daily usage trends: tokens,
|
|
|
59928
60538
|
}
|
|
59929
60539
|
});
|
|
59930
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
|
+
|
|
59931
60797
|
// src/cli.ts
|
|
59932
|
-
var PKG_VERSION2 = true ? "1.
|
|
60798
|
+
var PKG_VERSION2 = true ? "1.7.0" : "0.0.0-dev";
|
|
59933
60799
|
function registerDefaultPlugins(registry) {
|
|
59934
|
-
for (const
|
|
59935
|
-
for (const
|
|
60800
|
+
for (const p5 of createAllLanguagePlugins()) registry.registerLanguagePlugin(p5);
|
|
60801
|
+
for (const p5 of createAllIntegrationPlugins()) registry.registerFrameworkPlugin(p5);
|
|
59936
60802
|
}
|
|
59937
|
-
function
|
|
60803
|
+
function resolveDbPath6(projectRoot) {
|
|
59938
60804
|
const entry = getProject(projectRoot);
|
|
59939
60805
|
if (entry) return entry.dbPath;
|
|
59940
60806
|
return getDbPath(projectRoot);
|
|
@@ -59968,7 +60834,7 @@ function runFederationAutoSync(projectRoot, config) {
|
|
|
59968
60834
|
logger.warn({ error: e }, "Federation auto-sync failed (non-fatal)");
|
|
59969
60835
|
}
|
|
59970
60836
|
}
|
|
59971
|
-
var program = new
|
|
60837
|
+
var program = new Command12();
|
|
59972
60838
|
program.name("trace-mcp").description("Framework-Aware Code Intelligence for Laravel/Vue/Inertia/Nuxt").version(PKG_VERSION2);
|
|
59973
60839
|
program.command("serve").description("Start MCP server (stdio transport)").action(async () => {
|
|
59974
60840
|
const projectRoot = process.cwd();
|
|
@@ -59988,18 +60854,19 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
59988
60854
|
process.exit(1);
|
|
59989
60855
|
}
|
|
59990
60856
|
const config = configResult.value;
|
|
59991
|
-
const dbPath =
|
|
60857
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
59992
60858
|
ensureGlobalDirs();
|
|
59993
60859
|
const db = initializeDatabase(dbPath);
|
|
59994
60860
|
const store = new Store(db);
|
|
59995
60861
|
const registry = new PluginRegistry();
|
|
59996
60862
|
registerDefaultPlugins(registry);
|
|
59997
|
-
const
|
|
60863
|
+
const progress = new ProgressState(db);
|
|
60864
|
+
const pipeline = new IndexingPipeline(store, registry, config, projectRoot, progress);
|
|
59998
60865
|
const watcher = new FileWatcher2();
|
|
59999
60866
|
const aiProvider = createAIProvider(config);
|
|
60000
60867
|
const vectorStore = config.ai?.enabled ? new BlobVectorStore(store.db) : null;
|
|
60001
60868
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
60002
|
-
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore) : null;
|
|
60869
|
+
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore, progress) : null;
|
|
60003
60870
|
const inferenceCache = config.ai?.enabled ? new InferenceCache(store.db) : null;
|
|
60004
60871
|
inferenceCache?.evictExpired();
|
|
60005
60872
|
const summarizationPipeline = config.ai?.enabled && config.ai.summarize_on_index !== false ? new SummarizationPipeline(
|
|
@@ -60010,7 +60877,8 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
60010
60877
|
batchSize: config.ai.summarize_batch_size ?? 20,
|
|
60011
60878
|
kinds: config.ai.summarize_kinds ?? ["class", "function", "method", "interface", "trait", "enum", "type"],
|
|
60012
60879
|
concurrency: config.ai.concurrency ?? 1
|
|
60013
|
-
}
|
|
60880
|
+
},
|
|
60881
|
+
progress
|
|
60014
60882
|
) : null;
|
|
60015
60883
|
const runEmbeddings = () => {
|
|
60016
60884
|
if (!embeddingPipeline) return;
|
|
@@ -60044,7 +60912,7 @@ program.command("serve").description("Start MCP server (stdio transport)").actio
|
|
|
60044
60912
|
};
|
|
60045
60913
|
process.on("SIGINT", shutdown);
|
|
60046
60914
|
process.on("SIGTERM", shutdown);
|
|
60047
|
-
const server = createServer2(store, registry, config, projectRoot);
|
|
60915
|
+
const server = createServer2(store, registry, config, projectRoot, progress);
|
|
60048
60916
|
const transport = new StdioServerTransport();
|
|
60049
60917
|
logger.info({ projectRoot, dbPath }, "Starting trace-mcp MCP server...");
|
|
60050
60918
|
await server.connect(transport);
|
|
@@ -60057,18 +60925,19 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60057
60925
|
process.exit(1);
|
|
60058
60926
|
}
|
|
60059
60927
|
const config = configResult.value;
|
|
60060
|
-
const dbPath =
|
|
60928
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
60061
60929
|
ensureGlobalDirs();
|
|
60062
60930
|
const db = initializeDatabase(dbPath);
|
|
60063
60931
|
const store = new Store(db);
|
|
60064
60932
|
const registry = new PluginRegistry();
|
|
60065
60933
|
registerDefaultPlugins(registry);
|
|
60066
|
-
const
|
|
60934
|
+
const progress2 = new ProgressState(db);
|
|
60935
|
+
const pipeline = new IndexingPipeline(store, registry, config, projectRoot, progress2);
|
|
60067
60936
|
const watcher = new FileWatcher2();
|
|
60068
60937
|
const aiProvider = createAIProvider(config);
|
|
60069
60938
|
const vectorStore = config.ai?.enabled ? new BlobVectorStore(store.db) : null;
|
|
60070
60939
|
const embeddingService = config.ai?.enabled ? aiProvider.embedding() : null;
|
|
60071
|
-
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore) : null;
|
|
60940
|
+
const embeddingPipeline = vectorStore && embeddingService ? new EmbeddingPipeline(store, embeddingService, vectorStore, progress2) : null;
|
|
60072
60941
|
const inferenceCache2 = config.ai?.enabled ? new InferenceCache(store.db) : null;
|
|
60073
60942
|
inferenceCache2?.evictExpired();
|
|
60074
60943
|
const summarizationPipeline2 = config.ai?.enabled && config.ai.summarize_on_index !== false ? new SummarizationPipeline(
|
|
@@ -60079,7 +60948,8 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60079
60948
|
batchSize: config.ai.summarize_batch_size ?? 20,
|
|
60080
60949
|
kinds: config.ai.summarize_kinds ?? ["class", "function", "method", "interface", "trait", "enum", "type"],
|
|
60081
60950
|
concurrency: config.ai.concurrency ?? 1
|
|
60082
|
-
}
|
|
60951
|
+
},
|
|
60952
|
+
progress2
|
|
60083
60953
|
) : null;
|
|
60084
60954
|
const runEmbeddings = () => {
|
|
60085
60955
|
if (!embeddingPipeline) return;
|
|
@@ -60109,7 +60979,7 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60109
60979
|
});
|
|
60110
60980
|
const port = parseInt(opts.port, 10);
|
|
60111
60981
|
const host = opts.host;
|
|
60112
|
-
const server = createServer2(store, registry, config, projectRoot);
|
|
60982
|
+
const server = createServer2(store, registry, config, projectRoot, progress2);
|
|
60113
60983
|
const transport = new StreamableHTTPServerTransport({
|
|
60114
60984
|
sessionIdGenerator: () => randomUUID()
|
|
60115
60985
|
});
|
|
@@ -60211,8 +61081,8 @@ program.command("serve-http").description("Start MCP server (HTTP/SSE transport)
|
|
|
60211
61081
|
});
|
|
60212
61082
|
});
|
|
60213
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) => {
|
|
60214
|
-
const resolvedDir =
|
|
60215
|
-
if (!
|
|
61084
|
+
const resolvedDir = path107.resolve(dir);
|
|
61085
|
+
if (!fs96.existsSync(resolvedDir)) {
|
|
60216
61086
|
logger.error({ dir: resolvedDir }, "Directory does not exist");
|
|
60217
61087
|
process.exit(1);
|
|
60218
61088
|
}
|
|
@@ -60222,7 +61092,7 @@ program.command("index").description("Index a project directory").argument("<dir
|
|
|
60222
61092
|
process.exit(1);
|
|
60223
61093
|
}
|
|
60224
61094
|
const config = configResult.value;
|
|
60225
|
-
const dbPath =
|
|
61095
|
+
const dbPath = resolveDbPath6(resolvedDir);
|
|
60226
61096
|
ensureGlobalDirs();
|
|
60227
61097
|
const db = initializeDatabase(dbPath);
|
|
60228
61098
|
const store = new Store(db);
|
|
@@ -60236,20 +61106,20 @@ program.command("index").description("Index a project directory").argument("<dir
|
|
|
60236
61106
|
db.close();
|
|
60237
61107
|
});
|
|
60238
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) => {
|
|
60239
|
-
const resolvedFile =
|
|
60240
|
-
if (!
|
|
61109
|
+
const resolvedFile = path107.resolve(file);
|
|
61110
|
+
if (!fs96.existsSync(resolvedFile)) {
|
|
60241
61111
|
process.exit(0);
|
|
60242
61112
|
}
|
|
60243
61113
|
let projectRoot;
|
|
60244
61114
|
try {
|
|
60245
|
-
projectRoot = findProjectRoot(
|
|
61115
|
+
projectRoot = findProjectRoot(path107.dirname(resolvedFile));
|
|
60246
61116
|
} catch {
|
|
60247
61117
|
process.exit(0);
|
|
60248
61118
|
}
|
|
60249
61119
|
const configResult = await loadConfig(projectRoot);
|
|
60250
61120
|
if (configResult.isErr()) process.exit(0);
|
|
60251
61121
|
const config = configResult.value;
|
|
60252
|
-
const dbPath =
|
|
61122
|
+
const dbPath = resolveDbPath6(projectRoot);
|
|
60253
61123
|
ensureGlobalDirs();
|
|
60254
61124
|
const db = initializeDatabase(dbPath);
|
|
60255
61125
|
const store = new Store(db);
|
|
@@ -60277,11 +61147,11 @@ program.command("list").description("List all registered projects").option("--js
|
|
|
60277
61147
|
console.log("No projects registered. Run `trace-mcp add` in a project directory.");
|
|
60278
61148
|
} else {
|
|
60279
61149
|
console.log("Registered projects:\n");
|
|
60280
|
-
for (const
|
|
60281
|
-
const lastIdx =
|
|
60282
|
-
const dbExists =
|
|
60283
|
-
console.log(` ${
|
|
60284
|
-
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}`);
|
|
60285
61155
|
console.log(` DB: ${dbExists}`);
|
|
60286
61156
|
console.log(` Last indexed: ${lastIdx}`);
|
|
60287
61157
|
console.log();
|
|
@@ -60291,11 +61161,13 @@ program.command("list").description("List all registered projects").option("--js
|
|
|
60291
61161
|
program.addCommand(initCommand);
|
|
60292
61162
|
program.addCommand(upgradeCommand);
|
|
60293
61163
|
program.addCommand(addCommand);
|
|
61164
|
+
program.addCommand(removeCommand);
|
|
60294
61165
|
program.addCommand(doctorCommand);
|
|
60295
61166
|
program.addCommand(ciReportCommand);
|
|
60296
61167
|
program.addCommand(checkCommand);
|
|
60297
61168
|
program.addCommand(bundlesCommand);
|
|
60298
61169
|
program.addCommand(federationCommand);
|
|
60299
61170
|
program.addCommand(analyticsCommand);
|
|
61171
|
+
program.addCommand(statusCommand);
|
|
60300
61172
|
program.parse();
|
|
60301
61173
|
//# sourceMappingURL=cli.js.map
|