trace-mcp 1.5.3 → 1.6.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/README.md +1 -1
- package/dist/cli.js +598 -283
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +250 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -17
package/dist/index.d.ts
CHANGED
|
@@ -1546,6 +1546,7 @@ declare const TraceMcpConfigSchema: z.ZodObject<{
|
|
|
1546
1546
|
enabled?: boolean | undefined;
|
|
1547
1547
|
debounceMs?: number | undefined;
|
|
1548
1548
|
}>>;
|
|
1549
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1549
1550
|
}, "strip", z.ZodTypeAny, {
|
|
1550
1551
|
root: string;
|
|
1551
1552
|
db: {
|
|
@@ -1719,6 +1720,7 @@ declare const TraceMcpConfigSchema: z.ZodObject<{
|
|
|
1719
1720
|
exclude?: string[] | undefined;
|
|
1720
1721
|
descriptions?: Record<string, string | Record<string, string>> | undefined;
|
|
1721
1722
|
} | undefined;
|
|
1723
|
+
children?: string[] | undefined;
|
|
1722
1724
|
}, {
|
|
1723
1725
|
root?: string | undefined;
|
|
1724
1726
|
db?: {
|
|
@@ -1892,6 +1894,7 @@ declare const TraceMcpConfigSchema: z.ZodObject<{
|
|
|
1892
1894
|
enabled?: boolean | undefined;
|
|
1893
1895
|
debounceMs?: number | undefined;
|
|
1894
1896
|
} | undefined;
|
|
1897
|
+
children?: string[] | undefined;
|
|
1895
1898
|
}>;
|
|
1896
1899
|
type TraceMcpConfig = z.infer<typeof TraceMcpConfigSchema>;
|
|
1897
1900
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2498,6 +2498,22 @@ function detectWorkspaces(rootPath) {
|
|
|
2498
2498
|
if (composerResult.length > 0) return composerResult;
|
|
2499
2499
|
return [];
|
|
2500
2500
|
}
|
|
2501
|
+
function buildMultiRootWorkspaces(parentDir, childRoots) {
|
|
2502
|
+
const workspaces = [];
|
|
2503
|
+
for (const childRoot of childRoots) {
|
|
2504
|
+
const relPath = path2.relative(parentDir, childRoot).replace(/\\/g, "/");
|
|
2505
|
+
const childName = path2.basename(childRoot);
|
|
2506
|
+
workspaces.push({ name: childName, path: relPath });
|
|
2507
|
+
const subWorkspaces = detectWorkspaces(childRoot);
|
|
2508
|
+
for (const sub of subWorkspaces) {
|
|
2509
|
+
workspaces.push({
|
|
2510
|
+
name: `${childName}/${sub.name}`,
|
|
2511
|
+
path: `${relPath}/${sub.path}`
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
return workspaces;
|
|
2516
|
+
}
|
|
2501
2517
|
function detectPnpmWorkspaces(rootPath) {
|
|
2502
2518
|
const yamlPath = path2.join(rootPath, "pnpm-workspace.yaml");
|
|
2503
2519
|
if (!fs2.existsSync(yamlPath)) return [];
|
|
@@ -5902,9 +5918,14 @@ var IndexingPipeline = class _IndexingPipeline {
|
|
|
5902
5918
|
const result = this._lock.then(async () => {
|
|
5903
5919
|
this._isIncremental = false;
|
|
5904
5920
|
const start = Date.now();
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "
|
|
5921
|
+
if (this.config.children?.length) {
|
|
5922
|
+
this.workspaces = buildMultiRootWorkspaces(this.rootPath, this.config.children);
|
|
5923
|
+
logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "Multi-root workspaces");
|
|
5924
|
+
} else {
|
|
5925
|
+
this.workspaces = detectWorkspaces(this.rootPath);
|
|
5926
|
+
if (this.workspaces.length > 0) {
|
|
5927
|
+
logger.info({ workspaces: this.workspaces.map((w) => w.name) }, "Detected workspaces");
|
|
5928
|
+
}
|
|
5908
5929
|
}
|
|
5909
5930
|
const filePaths = await this.collectFiles();
|
|
5910
5931
|
return this.runPipeline(filePaths, force ?? false, start);
|
|
@@ -8036,6 +8057,14 @@ function buildInstructions(detectedFrameworks, verbosity) {
|
|
|
8036
8057
|
"Before creating new functions/classes:",
|
|
8037
8058
|
'- `check_duplication` { name: "functionName", kind: "function" } \u2014 checks if similar symbols already exist. Use BEFORE writing new code to avoid reinventing existing logic.',
|
|
8038
8059
|
"",
|
|
8060
|
+
"Bulk mechanical changes (adding async/await, updating patterns, fixing imports across many files):",
|
|
8061
|
+
"- `apply_codemod` { pattern, replacement, file_pattern } \u2014 regex find-and-replace across files. Dry-run by default (shows preview). Two-step workflow:",
|
|
8062
|
+
" 1. Call with dry_run: true (default) \u2192 review preview with context lines",
|
|
8063
|
+
" 2. Call with dry_run: false \u2192 apply changes. Requires confirm_large: true if >20 files affected.",
|
|
8064
|
+
"- Use `filter_content` to narrow scope to files containing a specific substring.",
|
|
8065
|
+
"- Use `multiline: true` for patterns spanning multiple lines.",
|
|
8066
|
+
"- NEVER use dozens of Edit calls for the same regex replacement \u2014 use apply_codemod instead.",
|
|
8067
|
+
"",
|
|
8039
8068
|
"WHEN TO USE native tools (Read/Grep/Glob):",
|
|
8040
8069
|
"- Non-code files (.md, .json, .yaml, .toml, config) \u2192 Read/Grep",
|
|
8041
8070
|
"- Reading a file before editing (Edit needs full content) \u2192 Read",
|
|
@@ -16974,6 +17003,7 @@ import { z as z6 } from "zod";
|
|
|
16974
17003
|
// src/tools/refactoring/refactor.ts
|
|
16975
17004
|
import fs23 from "fs";
|
|
16976
17005
|
import path35 from "path";
|
|
17006
|
+
import fg4 from "fast-glob";
|
|
16977
17007
|
function readLines2(filePath) {
|
|
16978
17008
|
return fs23.readFileSync(filePath, "utf-8").split("\n");
|
|
16979
17009
|
}
|
|
@@ -17307,6 +17337,193 @@ ${functionDef}`
|
|
|
17307
17337
|
}
|
|
17308
17338
|
return result;
|
|
17309
17339
|
}
|
|
17340
|
+
var CODEMOD_MAX_PREVIEW = 20;
|
|
17341
|
+
var CODEMOD_LARGE_THRESHOLD = 20;
|
|
17342
|
+
var CODEMOD_CONTEXT_LINES = 2;
|
|
17343
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
17344
|
+
".png",
|
|
17345
|
+
".jpg",
|
|
17346
|
+
".jpeg",
|
|
17347
|
+
".gif",
|
|
17348
|
+
".bmp",
|
|
17349
|
+
".ico",
|
|
17350
|
+
".svg",
|
|
17351
|
+
".webp",
|
|
17352
|
+
".woff",
|
|
17353
|
+
".woff2",
|
|
17354
|
+
".ttf",
|
|
17355
|
+
".eot",
|
|
17356
|
+
".otf",
|
|
17357
|
+
".zip",
|
|
17358
|
+
".tar",
|
|
17359
|
+
".gz",
|
|
17360
|
+
".bz2",
|
|
17361
|
+
".7z",
|
|
17362
|
+
".rar",
|
|
17363
|
+
".pdf",
|
|
17364
|
+
".doc",
|
|
17365
|
+
".docx",
|
|
17366
|
+
".xls",
|
|
17367
|
+
".xlsx",
|
|
17368
|
+
".mp3",
|
|
17369
|
+
".mp4",
|
|
17370
|
+
".avi",
|
|
17371
|
+
".mov",
|
|
17372
|
+
".wav",
|
|
17373
|
+
".exe",
|
|
17374
|
+
".dll",
|
|
17375
|
+
".so",
|
|
17376
|
+
".dylib",
|
|
17377
|
+
".o",
|
|
17378
|
+
".a",
|
|
17379
|
+
".wasm",
|
|
17380
|
+
".pyc",
|
|
17381
|
+
".class"
|
|
17382
|
+
]);
|
|
17383
|
+
var SKIP_DIRS = ["node_modules", ".git", "dist", "build", "vendor", "__pycache__", ".next", ".nuxt"];
|
|
17384
|
+
function applyCodemod(projectRoot, pattern, replacement, filePattern, options) {
|
|
17385
|
+
const result = {
|
|
17386
|
+
success: false,
|
|
17387
|
+
tool: "apply_codemod",
|
|
17388
|
+
dry_run: options.dryRun,
|
|
17389
|
+
matches: [],
|
|
17390
|
+
files_modified: [],
|
|
17391
|
+
total_replacements: 0,
|
|
17392
|
+
total_files: 0,
|
|
17393
|
+
warnings: []
|
|
17394
|
+
};
|
|
17395
|
+
let regex;
|
|
17396
|
+
try {
|
|
17397
|
+
const flags = options.multiline ? "gms" : "gm";
|
|
17398
|
+
regex = new RegExp(pattern, flags);
|
|
17399
|
+
} catch (e) {
|
|
17400
|
+
result.error = `Invalid regex pattern: ${e.message}`;
|
|
17401
|
+
return result;
|
|
17402
|
+
}
|
|
17403
|
+
let files;
|
|
17404
|
+
try {
|
|
17405
|
+
files = fg4.sync(filePattern, {
|
|
17406
|
+
cwd: projectRoot,
|
|
17407
|
+
ignore: SKIP_DIRS.map((d) => `**/${d}/**`),
|
|
17408
|
+
onlyFiles: true,
|
|
17409
|
+
absolute: false
|
|
17410
|
+
});
|
|
17411
|
+
} catch (e) {
|
|
17412
|
+
result.error = `Invalid file pattern: ${e.message}`;
|
|
17413
|
+
return result;
|
|
17414
|
+
}
|
|
17415
|
+
files = files.filter((f) => !BINARY_EXTENSIONS.has(path35.extname(f).toLowerCase()));
|
|
17416
|
+
if (files.length === 0) {
|
|
17417
|
+
result.error = `No files matched pattern: ${filePattern}`;
|
|
17418
|
+
return result;
|
|
17419
|
+
}
|
|
17420
|
+
const allMatches = [];
|
|
17421
|
+
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
17422
|
+
for (const relPath of files) {
|
|
17423
|
+
const absPath = path35.resolve(projectRoot, relPath);
|
|
17424
|
+
if (!fs23.existsSync(absPath)) continue;
|
|
17425
|
+
let content;
|
|
17426
|
+
try {
|
|
17427
|
+
content = fs23.readFileSync(absPath, "utf-8");
|
|
17428
|
+
} catch {
|
|
17429
|
+
result.warnings.push(`Could not read: ${relPath}`);
|
|
17430
|
+
continue;
|
|
17431
|
+
}
|
|
17432
|
+
if (options.filterContent && !content.includes(options.filterContent)) {
|
|
17433
|
+
continue;
|
|
17434
|
+
}
|
|
17435
|
+
const lines = content.split("\n");
|
|
17436
|
+
if (options.multiline) {
|
|
17437
|
+
regex.lastIndex = 0;
|
|
17438
|
+
if (!regex.test(content)) continue;
|
|
17439
|
+
filesWithMatches.add(relPath);
|
|
17440
|
+
regex.lastIndex = 0;
|
|
17441
|
+
let matchCount = 0;
|
|
17442
|
+
const matchPositions = [];
|
|
17443
|
+
let m;
|
|
17444
|
+
while ((m = regex.exec(content)) !== null) {
|
|
17445
|
+
matchPositions.push({ index: m.index, match: m[0] });
|
|
17446
|
+
matchCount++;
|
|
17447
|
+
if (m[0].length === 0) {
|
|
17448
|
+
regex.lastIndex++;
|
|
17449
|
+
}
|
|
17450
|
+
}
|
|
17451
|
+
for (const pos of matchPositions.slice(0, CODEMOD_MAX_PREVIEW - allMatches.length)) {
|
|
17452
|
+
const lineNum = content.slice(0, pos.index).split("\n").length;
|
|
17453
|
+
const original = pos.match;
|
|
17454
|
+
regex.lastIndex = 0;
|
|
17455
|
+
const replaced = original.replace(regex, replacement);
|
|
17456
|
+
allMatches.push({
|
|
17457
|
+
file: relPath,
|
|
17458
|
+
line: lineNum,
|
|
17459
|
+
original: original.length > 200 ? original.slice(0, 200) + "\u2026" : original,
|
|
17460
|
+
replaced: replaced.length > 200 ? replaced.slice(0, 200) + "\u2026" : replaced,
|
|
17461
|
+
context_before: lines.slice(Math.max(0, lineNum - 1 - CODEMOD_CONTEXT_LINES), lineNum - 1),
|
|
17462
|
+
context_after: lines.slice(lineNum, lineNum + CODEMOD_CONTEXT_LINES)
|
|
17463
|
+
});
|
|
17464
|
+
}
|
|
17465
|
+
result.total_replacements += matchCount;
|
|
17466
|
+
} else {
|
|
17467
|
+
let fileMatchCount = 0;
|
|
17468
|
+
for (let i = 0; i < lines.length; i++) {
|
|
17469
|
+
regex.lastIndex = 0;
|
|
17470
|
+
if (!regex.test(lines[i])) continue;
|
|
17471
|
+
filesWithMatches.add(relPath);
|
|
17472
|
+
fileMatchCount++;
|
|
17473
|
+
regex.lastIndex = 0;
|
|
17474
|
+
const newLine = lines[i].replace(regex, replacement);
|
|
17475
|
+
if (allMatches.length < CODEMOD_MAX_PREVIEW) {
|
|
17476
|
+
allMatches.push({
|
|
17477
|
+
file: relPath,
|
|
17478
|
+
line: i + 1,
|
|
17479
|
+
original: lines[i],
|
|
17480
|
+
replaced: newLine,
|
|
17481
|
+
context_before: lines.slice(Math.max(0, i - CODEMOD_CONTEXT_LINES), i),
|
|
17482
|
+
context_after: lines.slice(i + 1, i + 1 + CODEMOD_CONTEXT_LINES)
|
|
17483
|
+
});
|
|
17484
|
+
}
|
|
17485
|
+
}
|
|
17486
|
+
result.total_replacements += fileMatchCount;
|
|
17487
|
+
}
|
|
17488
|
+
}
|
|
17489
|
+
result.total_files = filesWithMatches.size;
|
|
17490
|
+
if (allMatches.length === 0) {
|
|
17491
|
+
result.error = `No matches found for pattern in ${files.length} files`;
|
|
17492
|
+
return result;
|
|
17493
|
+
}
|
|
17494
|
+
if (filesWithMatches.size > CODEMOD_LARGE_THRESHOLD && !options.confirmLarge) {
|
|
17495
|
+
result.matches = allMatches;
|
|
17496
|
+
result.warnings.push(
|
|
17497
|
+
`Affects ${filesWithMatches.size} files (>${CODEMOD_LARGE_THRESHOLD}). Re-run with confirm_large: true to proceed, or narrow file_pattern.`
|
|
17498
|
+
);
|
|
17499
|
+
result.dry_run = true;
|
|
17500
|
+
result.success = true;
|
|
17501
|
+
return result;
|
|
17502
|
+
}
|
|
17503
|
+
if (options.dryRun) {
|
|
17504
|
+
result.matches = allMatches;
|
|
17505
|
+
result.success = true;
|
|
17506
|
+
return result;
|
|
17507
|
+
}
|
|
17508
|
+
for (const relPath of filesWithMatches) {
|
|
17509
|
+
const absPath = path35.resolve(projectRoot, relPath);
|
|
17510
|
+
try {
|
|
17511
|
+
const content = fs23.readFileSync(absPath, "utf-8");
|
|
17512
|
+
const flags = options.multiline ? "gms" : "gm";
|
|
17513
|
+
const freshRegex = new RegExp(pattern, flags);
|
|
17514
|
+
const newContent = content.replace(freshRegex, replacement);
|
|
17515
|
+
if (newContent !== content) {
|
|
17516
|
+
fs23.writeFileSync(absPath, newContent, "utf-8");
|
|
17517
|
+
result.files_modified.push(relPath);
|
|
17518
|
+
}
|
|
17519
|
+
} catch (e) {
|
|
17520
|
+
result.warnings.push(`Failed to write ${relPath}: ${e.message}`);
|
|
17521
|
+
}
|
|
17522
|
+
}
|
|
17523
|
+
result.matches = allMatches;
|
|
17524
|
+
result.success = true;
|
|
17525
|
+
return result;
|
|
17526
|
+
}
|
|
17310
17527
|
function detectLanguage2(ext) {
|
|
17311
17528
|
switch (ext) {
|
|
17312
17529
|
case ".ts":
|
|
@@ -17543,6 +17760,31 @@ function registerRefactoringTools(server, ctx) {
|
|
|
17543
17760
|
return { content: [{ type: "text", text: j3(result) }] };
|
|
17544
17761
|
}
|
|
17545
17762
|
);
|
|
17763
|
+
server.tool(
|
|
17764
|
+
"apply_codemod",
|
|
17765
|
+
"Bulk regex find-and-replace across files. Dry-run by default \u2014 first call shows preview, second call with dry_run=false applies. Use for mechanical changes like adding async/await, renaming patterns, updating imports across many files.",
|
|
17766
|
+
{
|
|
17767
|
+
pattern: z6.string().min(1).max(1e3).describe("Regex pattern to match (JavaScript regex syntax)"),
|
|
17768
|
+
replacement: z6.string().max(1e3).describe("Replacement string ($1, $2 for capture groups)"),
|
|
17769
|
+
file_pattern: z6.string().min(1).max(512).describe('Glob pattern for files to scan (e.g. "tests/**/*.test.ts", "src/**/*.py")'),
|
|
17770
|
+
dry_run: z6.boolean().default(true).describe("Preview changes without writing (default: true). Set to false to apply."),
|
|
17771
|
+
confirm_large: z6.boolean().optional().describe("Required when >20 files affected. Acknowledges large-scale change."),
|
|
17772
|
+
filter_content: z6.string().max(500).optional().describe("Only process files containing this substring (narrows scope)"),
|
|
17773
|
+
multiline: z6.boolean().optional().describe("Enable multiline mode (dot matches newlines, patterns span lines)")
|
|
17774
|
+
},
|
|
17775
|
+
async ({ pattern, replacement, file_pattern, dry_run, confirm_large, filter_content, multiline }) => {
|
|
17776
|
+
const result = applyCodemod(projectRoot, pattern, replacement, file_pattern, {
|
|
17777
|
+
dryRun: dry_run,
|
|
17778
|
+
confirmLarge: confirm_large,
|
|
17779
|
+
filterContent: filter_content,
|
|
17780
|
+
multiline
|
|
17781
|
+
});
|
|
17782
|
+
if (!result.success) {
|
|
17783
|
+
return { content: [{ type: "text", text: j3(result) }], isError: true };
|
|
17784
|
+
}
|
|
17785
|
+
return { content: [{ type: "text", text: j3(result) }] };
|
|
17786
|
+
}
|
|
17787
|
+
);
|
|
17546
17788
|
}
|
|
17547
17789
|
|
|
17548
17790
|
// src/tools/register/advanced.ts
|
|
@@ -26515,6 +26757,8 @@ var KNOWN_PACKAGES = {
|
|
|
26515
26757
|
"@clack/prompts": { category: "infra", priority: "medium", plugin: "clack" },
|
|
26516
26758
|
"@clack/core": { category: "infra", priority: "medium", plugin: "clack" },
|
|
26517
26759
|
"tree-sitter": { category: "infra", priority: "medium", plugin: "tree-sitter" },
|
|
26760
|
+
"web-tree-sitter": { category: "infra", priority: "medium", plugin: "tree-sitter" },
|
|
26761
|
+
"tree-sitter-wasms": { category: "infra", priority: "low", plugin: "tree-sitter" },
|
|
26518
26762
|
"n8n-workflow": { category: "infra", priority: "high", plugin: "n8n" },
|
|
26519
26763
|
// --- JavaScript / npm: Build tools (with plugin) ---
|
|
26520
26764
|
"tsup": { category: "infra", priority: "low", plugin: "build-tools" },
|
|
@@ -27484,7 +27728,7 @@ function registerSessionTools(server, ctx) {
|
|
|
27484
27728
|
}
|
|
27485
27729
|
|
|
27486
27730
|
// src/server/server.ts
|
|
27487
|
-
var PKG_VERSION = true ? "1.
|
|
27731
|
+
var PKG_VERSION = true ? "1.6.0" : "0.0.0-dev";
|
|
27488
27732
|
function j2(value) {
|
|
27489
27733
|
return JSON.stringify(value, (_key, val) => val === null || val === void 0 ? void 0 : val);
|
|
27490
27734
|
}
|
|
@@ -29149,7 +29393,8 @@ var TraceMcpConfigSchema = z13.object({
|
|
|
29149
29393
|
watch: z13.object({
|
|
29150
29394
|
enabled: z13.boolean().default(true),
|
|
29151
29395
|
debounceMs: z13.number().int().min(500).max(3e4).default(2e3)
|
|
29152
|
-
}).default({})
|
|
29396
|
+
}).default({}),
|
|
29397
|
+
children: z13.array(z13.string()).optional()
|
|
29153
29398
|
});
|
|
29154
29399
|
function loadGlobalConfigRaw() {
|
|
29155
29400
|
if (!fs37.existsSync(GLOBAL_CONFIG_PATH)) return {};
|