ctxo-mcp 0.6.2 → 0.6.4
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.
|
@@ -517,10 +517,14 @@ var init_go_adapter = __esm({
|
|
|
517
517
|
}
|
|
518
518
|
});
|
|
519
519
|
|
|
520
|
+
// src/cli/cli-router.ts
|
|
521
|
+
import { readFileSync as readFileSync9, existsSync as existsSync15 } from "fs";
|
|
522
|
+
import { join as join19 } from "path";
|
|
523
|
+
|
|
520
524
|
// src/cli/index-command.ts
|
|
521
525
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
522
526
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, statSync, readdirSync as readdirSync2 } from "fs";
|
|
523
|
-
import { join as join5, relative, extname as extname4 } from "path";
|
|
527
|
+
import { join as join5, relative as relative2, extname as extname4 } from "path";
|
|
524
528
|
|
|
525
529
|
// src/core/staleness/content-hasher.ts
|
|
526
530
|
import { createHash } from "crypto";
|
|
@@ -1205,6 +1209,9 @@ var SchemaManager = class {
|
|
|
1205
1209
|
}
|
|
1206
1210
|
};
|
|
1207
1211
|
|
|
1212
|
+
// src/adapters/language/roslyn/roslyn-adapter.ts
|
|
1213
|
+
import { relative, dirname as dirname4, resolve as resolve2 } from "path";
|
|
1214
|
+
|
|
1208
1215
|
// src/adapters/language/roslyn/solution-discovery.ts
|
|
1209
1216
|
import { execFileSync } from "child_process";
|
|
1210
1217
|
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
@@ -1294,7 +1301,7 @@ function findCtxoRoslynProject() {
|
|
|
1294
1301
|
import { spawn } from "child_process";
|
|
1295
1302
|
var log2 = createLogger("ctxo:roslyn");
|
|
1296
1303
|
async function runBatchIndex(projectDir, solutionPath, timeoutMs = 12e4) {
|
|
1297
|
-
return new Promise((
|
|
1304
|
+
return new Promise((resolve3) => {
|
|
1298
1305
|
const proc = spawn("dotnet", ["run", "--project", projectDir, "--", solutionPath], {
|
|
1299
1306
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1300
1307
|
timeout: timeoutMs
|
|
@@ -1340,14 +1347,14 @@ async function runBatchIndex(projectDir, solutionPath, timeoutMs = 12e4) {
|
|
|
1340
1347
|
proc.on("close", (code) => {
|
|
1341
1348
|
if (code !== 0) {
|
|
1342
1349
|
log2.error(`ctxo-roslyn exited with code ${code}: ${stderr.trim()}`);
|
|
1343
|
-
|
|
1350
|
+
resolve3({ files: [], projectGraph: null, totalFiles: 0, elapsed: "" });
|
|
1344
1351
|
return;
|
|
1345
1352
|
}
|
|
1346
|
-
|
|
1353
|
+
resolve3({ files, projectGraph, totalFiles, elapsed });
|
|
1347
1354
|
});
|
|
1348
1355
|
proc.on("error", (err) => {
|
|
1349
1356
|
log2.error(`ctxo-roslyn spawn error: ${err.message}`);
|
|
1350
|
-
|
|
1357
|
+
resolve3({ files: [], projectGraph: null, totalFiles: 0, elapsed: "" });
|
|
1351
1358
|
});
|
|
1352
1359
|
});
|
|
1353
1360
|
}
|
|
@@ -1365,7 +1372,7 @@ var RoslynKeepAlive = class {
|
|
|
1365
1372
|
this.timeoutMs = timeoutMs;
|
|
1366
1373
|
}
|
|
1367
1374
|
async start() {
|
|
1368
|
-
return new Promise((
|
|
1375
|
+
return new Promise((resolve3) => {
|
|
1369
1376
|
this.proc = spawn("dotnet", ["run", "--project", this.projectDir, "--", this.solutionPath, "--keep-alive"], {
|
|
1370
1377
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1371
1378
|
});
|
|
@@ -1380,7 +1387,7 @@ var RoslynKeepAlive = class {
|
|
|
1380
1387
|
const obj = JSON.parse(line);
|
|
1381
1388
|
if (obj.type === "ready") {
|
|
1382
1389
|
log2.info(`Roslyn keep-alive ready: ${obj.projectCount} projects, ${obj.fileCount} files`);
|
|
1383
|
-
|
|
1390
|
+
resolve3(true);
|
|
1384
1391
|
} else if (obj.type === "file") {
|
|
1385
1392
|
const result = obj;
|
|
1386
1393
|
const callback = this.pending.get(result.file);
|
|
@@ -1407,7 +1414,7 @@ var RoslynKeepAlive = class {
|
|
|
1407
1414
|
});
|
|
1408
1415
|
this.proc.on("error", (err) => {
|
|
1409
1416
|
log2.error(`Roslyn keep-alive error: ${err.message}`);
|
|
1410
|
-
|
|
1417
|
+
resolve3(false);
|
|
1411
1418
|
});
|
|
1412
1419
|
this.resetInactivityTimer();
|
|
1413
1420
|
});
|
|
@@ -1417,14 +1424,14 @@ var RoslynKeepAlive = class {
|
|
|
1417
1424
|
return null;
|
|
1418
1425
|
}
|
|
1419
1426
|
this.resetInactivityTimer();
|
|
1420
|
-
return new Promise((
|
|
1421
|
-
this.pending.set(relativePath,
|
|
1427
|
+
return new Promise((resolve3) => {
|
|
1428
|
+
this.pending.set(relativePath, resolve3);
|
|
1422
1429
|
this.proc.stdin.write(JSON.stringify({ file: relativePath }) + "\n");
|
|
1423
1430
|
setTimeout(() => {
|
|
1424
1431
|
if (this.pending.has(relativePath)) {
|
|
1425
1432
|
this.pending.delete(relativePath);
|
|
1426
1433
|
log2.error(`Roslyn keep-alive timeout for ${relativePath}`);
|
|
1427
|
-
|
|
1434
|
+
resolve3(null);
|
|
1428
1435
|
}
|
|
1429
1436
|
}, 3e4);
|
|
1430
1437
|
});
|
|
@@ -1456,6 +1463,7 @@ var RoslynAdapter = class {
|
|
|
1456
1463
|
tier = "full";
|
|
1457
1464
|
roslynProjectDir = null;
|
|
1458
1465
|
solutionPath = null;
|
|
1466
|
+
rootDir = null;
|
|
1459
1467
|
cache = /* @__PURE__ */ new Map();
|
|
1460
1468
|
keepAlive = null;
|
|
1461
1469
|
initialized = false;
|
|
@@ -1481,6 +1489,7 @@ var RoslynAdapter = class {
|
|
|
1481
1489
|
log3.info("Roslyn adapter unavailable: no .sln or .csproj found");
|
|
1482
1490
|
return;
|
|
1483
1491
|
}
|
|
1492
|
+
this.rootDir = rootDir;
|
|
1484
1493
|
log3.info(`Roslyn adapter ready: SDK ${sdk.version}, solution ${this.solutionPath}`);
|
|
1485
1494
|
this.initialized = true;
|
|
1486
1495
|
}
|
|
@@ -1491,9 +1500,18 @@ var RoslynAdapter = class {
|
|
|
1491
1500
|
async batchIndex() {
|
|
1492
1501
|
if (!this.isReady()) return null;
|
|
1493
1502
|
const result = await runBatchIndex(this.roslynProjectDir, this.solutionPath);
|
|
1503
|
+
const solutionDir = dirname4(this.solutionPath);
|
|
1504
|
+
const pathMap = /* @__PURE__ */ new Map();
|
|
1505
|
+
for (const file of result.files) {
|
|
1506
|
+
const absolutePath = resolve2(solutionDir, file.file);
|
|
1507
|
+
const projectRelative = relative(this.rootDir, absolutePath).replace(/\\/g, "/");
|
|
1508
|
+
pathMap.set(file.file, projectRelative);
|
|
1509
|
+
}
|
|
1494
1510
|
this.cache.clear();
|
|
1495
1511
|
for (const file of result.files) {
|
|
1496
|
-
|
|
1512
|
+
const projectRelative = pathMap.get(file.file);
|
|
1513
|
+
const rewritten = rewriteAllPaths(file, projectRelative, pathMap);
|
|
1514
|
+
this.cache.set(projectRelative, rewritten);
|
|
1497
1515
|
}
|
|
1498
1516
|
log3.info(`Roslyn batch index: ${result.totalFiles} files in ${result.elapsed}`);
|
|
1499
1517
|
return result;
|
|
@@ -1557,6 +1575,33 @@ var RoslynAdapter = class {
|
|
|
1557
1575
|
this.initialized = false;
|
|
1558
1576
|
}
|
|
1559
1577
|
};
|
|
1578
|
+
function rewriteAllPaths(file, newFilePath, pathMap) {
|
|
1579
|
+
const rewrite = (s) => {
|
|
1580
|
+
for (const [oldPath, newPath] of pathMap) {
|
|
1581
|
+
if (s.includes(oldPath)) {
|
|
1582
|
+
return s.replaceAll(oldPath, newPath);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
return s;
|
|
1586
|
+
};
|
|
1587
|
+
return {
|
|
1588
|
+
...file,
|
|
1589
|
+
file: newFilePath,
|
|
1590
|
+
symbols: file.symbols.map((s) => ({
|
|
1591
|
+
...s,
|
|
1592
|
+
symbolId: rewrite(s.symbolId)
|
|
1593
|
+
})),
|
|
1594
|
+
edges: file.edges.map((e) => ({
|
|
1595
|
+
...e,
|
|
1596
|
+
from: rewrite(e.from),
|
|
1597
|
+
to: rewrite(e.to)
|
|
1598
|
+
})),
|
|
1599
|
+
complexity: file.complexity.map((c) => ({
|
|
1600
|
+
...c,
|
|
1601
|
+
symbolId: rewrite(c.symbolId)
|
|
1602
|
+
}))
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1560
1605
|
|
|
1561
1606
|
// src/cli/index-command.ts
|
|
1562
1607
|
var IndexCommand = class {
|
|
@@ -1609,7 +1654,7 @@ var IndexCommand = class {
|
|
|
1609
1654
|
for (const filePath of files) {
|
|
1610
1655
|
const adapter = registry.getAdapter(filePath);
|
|
1611
1656
|
if (!adapter) continue;
|
|
1612
|
-
const relativePath =
|
|
1657
|
+
const relativePath = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
1613
1658
|
try {
|
|
1614
1659
|
const source = readFileSync2(filePath, "utf-8");
|
|
1615
1660
|
const lastModified = Math.floor(Date.now() / 1e3);
|
|
@@ -1793,7 +1838,7 @@ var IndexCommand = class {
|
|
|
1793
1838
|
let staleCount = 0;
|
|
1794
1839
|
for (const filePath of files) {
|
|
1795
1840
|
if (!this.isSupportedExtension(filePath)) continue;
|
|
1796
|
-
const relativePath =
|
|
1841
|
+
const relativePath = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
1797
1842
|
const indexed = indexedMap.get(relativePath);
|
|
1798
1843
|
if (!indexed) {
|
|
1799
1844
|
console.error(`[ctxo] NOT INDEXED: ${relativePath}`);
|
|
@@ -1963,7 +2008,7 @@ import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync
|
|
|
1963
2008
|
|
|
1964
2009
|
// src/cli/ai-rules.ts
|
|
1965
2010
|
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1966
|
-
import { join as join9, dirname as
|
|
2011
|
+
import { join as join9, dirname as dirname5 } from "path";
|
|
1967
2012
|
var PLATFORMS = [
|
|
1968
2013
|
{ id: "claude-code", name: "Claude Code", file: "CLAUDE.md", mode: "append", detectPaths: ["CLAUDE.md", ".claude"], starred: true },
|
|
1969
2014
|
{ id: "cursor", name: "Cursor", file: ".cursor/rules/ctxo-mcp.mdc", mode: "create", detectPaths: [".cursor", ".cursorrules"], starred: false },
|
|
@@ -2040,7 +2085,7 @@ function installRules(projectRoot, platformId) {
|
|
|
2040
2085
|
if (!platform) throw new Error(`Unknown platform: ${platformId}`);
|
|
2041
2086
|
const filePath = join9(projectRoot, platform.file);
|
|
2042
2087
|
const content = generateRules(platformId);
|
|
2043
|
-
const dir =
|
|
2088
|
+
const dir = dirname5(filePath);
|
|
2044
2089
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2045
2090
|
if (platform.mode === "create") {
|
|
2046
2091
|
writeFileSync4(filePath, content, "utf-8");
|
|
@@ -2094,7 +2139,7 @@ version: "1.0"
|
|
|
2094
2139
|
`;
|
|
2095
2140
|
function ensureConfig(projectRoot) {
|
|
2096
2141
|
const filePath = join9(projectRoot, ".ctxo", "config.yaml");
|
|
2097
|
-
const dir =
|
|
2142
|
+
const dir = dirname5(filePath);
|
|
2098
2143
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2099
2144
|
if (existsSync6(filePath)) {
|
|
2100
2145
|
return { file: ".ctxo/config.yaml", action: "skipped" };
|
|
@@ -2126,7 +2171,7 @@ function getMcpConfigTargets(selectedPlatformIds) {
|
|
|
2126
2171
|
}
|
|
2127
2172
|
function ensureMcpConfig(projectRoot, target) {
|
|
2128
2173
|
const filePath = join9(projectRoot, target.file);
|
|
2129
|
-
const dir =
|
|
2174
|
+
const dir = dirname5(filePath);
|
|
2130
2175
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2131
2176
|
const entry = target.extraFields ? { ...target.extraFields, ...CTXO_MCP_ENTRY } : { ...CTXO_MCP_ENTRY };
|
|
2132
2177
|
if (!existsSync6(filePath)) {
|
|
@@ -2462,7 +2507,7 @@ var InitCommand = class {
|
|
|
2462
2507
|
};
|
|
2463
2508
|
|
|
2464
2509
|
// src/cli/watch-command.ts
|
|
2465
|
-
import { join as join11, extname as extname5, relative as
|
|
2510
|
+
import { join as join11, extname as extname5, relative as relative3 } from "path";
|
|
2466
2511
|
import { readFileSync as readFileSync5 } from "fs";
|
|
2467
2512
|
|
|
2468
2513
|
// src/adapters/watcher/chokidar-watcher-adapter.ts
|
|
@@ -2549,7 +2594,7 @@ var WatchCommand = class {
|
|
|
2549
2594
|
const reindexFile = async (filePath) => {
|
|
2550
2595
|
const adapter = registry.getAdapter(filePath);
|
|
2551
2596
|
if (!adapter) return;
|
|
2552
|
-
const relativePath =
|
|
2597
|
+
const relativePath = relative3(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
2553
2598
|
try {
|
|
2554
2599
|
if (roslynAdapter?.isReady() && filePath.endsWith(".cs")) {
|
|
2555
2600
|
const result = await roslynAdapter.reindexFile(relativePath);
|
|
@@ -2637,7 +2682,7 @@ var WatchCommand = class {
|
|
|
2637
2682
|
if (event === "unlink") {
|
|
2638
2683
|
const ext = extname5(filePath).toLowerCase();
|
|
2639
2684
|
if (!supportedExtensions.has(ext)) return;
|
|
2640
|
-
const relativePath =
|
|
2685
|
+
const relativePath = relative3(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
2641
2686
|
writer.delete(relativePath);
|
|
2642
2687
|
storage.deleteSymbolFile(relativePath);
|
|
2643
2688
|
console.error(`[ctxo] Removed from index: ${relativePath}`);
|
|
@@ -3251,6 +3296,9 @@ var DoctorCommand = class {
|
|
|
3251
3296
|
this.ctxoRoot = join18(projectRoot, ".ctxo");
|
|
3252
3297
|
}
|
|
3253
3298
|
async run(options = {}) {
|
|
3299
|
+
const { getVersion: getVersion2 } = await import("./cli-router-JX7ZFVAW.js");
|
|
3300
|
+
console.error(`ctxo v${getVersion2()} \u2014 health check
|
|
3301
|
+
`);
|
|
3254
3302
|
const checks = [
|
|
3255
3303
|
new NodeVersionCheck(),
|
|
3256
3304
|
new GitBinaryCheck(),
|
|
@@ -3295,6 +3343,24 @@ var DoctorCommand = class {
|
|
|
3295
3343
|
};
|
|
3296
3344
|
|
|
3297
3345
|
// src/cli/cli-router.ts
|
|
3346
|
+
function getVersion() {
|
|
3347
|
+
let dir = import.meta.dirname;
|
|
3348
|
+
for (let i = 0; i < 10; i++) {
|
|
3349
|
+
const pkg = join19(dir, "package.json");
|
|
3350
|
+
if (existsSync15(pkg)) {
|
|
3351
|
+
try {
|
|
3352
|
+
const json = JSON.parse(readFileSync9(pkg, "utf-8"));
|
|
3353
|
+
return json.version ?? "unknown";
|
|
3354
|
+
} catch {
|
|
3355
|
+
break;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
const parent = join19(dir, "..");
|
|
3359
|
+
if (parent === dir) break;
|
|
3360
|
+
dir = parent;
|
|
3361
|
+
}
|
|
3362
|
+
return "unknown";
|
|
3363
|
+
}
|
|
3298
3364
|
var CliRouter = class {
|
|
3299
3365
|
projectRoot;
|
|
3300
3366
|
constructor(projectRoot) {
|
|
@@ -3302,6 +3368,10 @@ var CliRouter = class {
|
|
|
3302
3368
|
}
|
|
3303
3369
|
async route(args) {
|
|
3304
3370
|
const command = args[0];
|
|
3371
|
+
if (command === "--version" || command === "-v" || command === "-V") {
|
|
3372
|
+
console.error(`ctxo ${getVersion()}`);
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3305
3375
|
if (!command || command === "--help" || command === "-h") {
|
|
3306
3376
|
this.printHelp();
|
|
3307
3377
|
return;
|
|
@@ -3370,8 +3440,9 @@ var CliRouter = class {
|
|
|
3370
3440
|
}
|
|
3371
3441
|
}
|
|
3372
3442
|
printHelp() {
|
|
3443
|
+
const v = getVersion();
|
|
3373
3444
|
console.error(`
|
|
3374
|
-
ctxo \u2014 MCP server for dependency-aware codebase context
|
|
3445
|
+
ctxo v${v} \u2014 MCP server for dependency-aware codebase context
|
|
3375
3446
|
|
|
3376
3447
|
Usage:
|
|
3377
3448
|
ctxo Start MCP server (stdio transport)
|
|
@@ -3391,6 +3462,7 @@ Usage:
|
|
|
3391
3462
|
}
|
|
3392
3463
|
};
|
|
3393
3464
|
export {
|
|
3394
|
-
CliRouter
|
|
3465
|
+
CliRouter,
|
|
3466
|
+
getVersion
|
|
3395
3467
|
};
|
|
3396
|
-
//# sourceMappingURL=cli-router-
|
|
3468
|
+
//# sourceMappingURL=cli-router-JX7ZFVAW.js.map
|