ctxo-mcp 0.6.2 → 0.6.3
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,13 @@ 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);
|
|
1494
1504
|
this.cache.clear();
|
|
1495
1505
|
for (const file of result.files) {
|
|
1496
|
-
|
|
1506
|
+
const absolutePath = resolve2(solutionDir, file.file);
|
|
1507
|
+
const projectRelative = relative(this.rootDir, absolutePath).replace(/\\/g, "/");
|
|
1508
|
+
const rewritten = rewritePaths(file, file.file, projectRelative);
|
|
1509
|
+
this.cache.set(projectRelative, rewritten);
|
|
1497
1510
|
}
|
|
1498
1511
|
log3.info(`Roslyn batch index: ${result.totalFiles} files in ${result.elapsed}`);
|
|
1499
1512
|
return result;
|
|
@@ -1557,6 +1570,26 @@ var RoslynAdapter = class {
|
|
|
1557
1570
|
this.initialized = false;
|
|
1558
1571
|
}
|
|
1559
1572
|
};
|
|
1573
|
+
function rewritePaths(file, oldPrefix, newPrefix) {
|
|
1574
|
+
const rewrite = (s) => s.replace(oldPrefix, newPrefix);
|
|
1575
|
+
return {
|
|
1576
|
+
...file,
|
|
1577
|
+
file: newPrefix,
|
|
1578
|
+
symbols: file.symbols.map((s) => ({
|
|
1579
|
+
...s,
|
|
1580
|
+
symbolId: rewrite(s.symbolId)
|
|
1581
|
+
})),
|
|
1582
|
+
edges: file.edges.map((e) => ({
|
|
1583
|
+
...e,
|
|
1584
|
+
from: rewrite(e.from),
|
|
1585
|
+
to: rewrite(e.to)
|
|
1586
|
+
})),
|
|
1587
|
+
complexity: file.complexity.map((c) => ({
|
|
1588
|
+
...c,
|
|
1589
|
+
symbolId: rewrite(c.symbolId)
|
|
1590
|
+
}))
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1560
1593
|
|
|
1561
1594
|
// src/cli/index-command.ts
|
|
1562
1595
|
var IndexCommand = class {
|
|
@@ -1609,7 +1642,7 @@ var IndexCommand = class {
|
|
|
1609
1642
|
for (const filePath of files) {
|
|
1610
1643
|
const adapter = registry.getAdapter(filePath);
|
|
1611
1644
|
if (!adapter) continue;
|
|
1612
|
-
const relativePath =
|
|
1645
|
+
const relativePath = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
1613
1646
|
try {
|
|
1614
1647
|
const source = readFileSync2(filePath, "utf-8");
|
|
1615
1648
|
const lastModified = Math.floor(Date.now() / 1e3);
|
|
@@ -1793,7 +1826,7 @@ var IndexCommand = class {
|
|
|
1793
1826
|
let staleCount = 0;
|
|
1794
1827
|
for (const filePath of files) {
|
|
1795
1828
|
if (!this.isSupportedExtension(filePath)) continue;
|
|
1796
|
-
const relativePath =
|
|
1829
|
+
const relativePath = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
1797
1830
|
const indexed = indexedMap.get(relativePath);
|
|
1798
1831
|
if (!indexed) {
|
|
1799
1832
|
console.error(`[ctxo] NOT INDEXED: ${relativePath}`);
|
|
@@ -1963,7 +1996,7 @@ import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync
|
|
|
1963
1996
|
|
|
1964
1997
|
// src/cli/ai-rules.ts
|
|
1965
1998
|
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1966
|
-
import { join as join9, dirname as
|
|
1999
|
+
import { join as join9, dirname as dirname5 } from "path";
|
|
1967
2000
|
var PLATFORMS = [
|
|
1968
2001
|
{ id: "claude-code", name: "Claude Code", file: "CLAUDE.md", mode: "append", detectPaths: ["CLAUDE.md", ".claude"], starred: true },
|
|
1969
2002
|
{ id: "cursor", name: "Cursor", file: ".cursor/rules/ctxo-mcp.mdc", mode: "create", detectPaths: [".cursor", ".cursorrules"], starred: false },
|
|
@@ -2040,7 +2073,7 @@ function installRules(projectRoot, platformId) {
|
|
|
2040
2073
|
if (!platform) throw new Error(`Unknown platform: ${platformId}`);
|
|
2041
2074
|
const filePath = join9(projectRoot, platform.file);
|
|
2042
2075
|
const content = generateRules(platformId);
|
|
2043
|
-
const dir =
|
|
2076
|
+
const dir = dirname5(filePath);
|
|
2044
2077
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2045
2078
|
if (platform.mode === "create") {
|
|
2046
2079
|
writeFileSync4(filePath, content, "utf-8");
|
|
@@ -2094,7 +2127,7 @@ version: "1.0"
|
|
|
2094
2127
|
`;
|
|
2095
2128
|
function ensureConfig(projectRoot) {
|
|
2096
2129
|
const filePath = join9(projectRoot, ".ctxo", "config.yaml");
|
|
2097
|
-
const dir =
|
|
2130
|
+
const dir = dirname5(filePath);
|
|
2098
2131
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2099
2132
|
if (existsSync6(filePath)) {
|
|
2100
2133
|
return { file: ".ctxo/config.yaml", action: "skipped" };
|
|
@@ -2126,7 +2159,7 @@ function getMcpConfigTargets(selectedPlatformIds) {
|
|
|
2126
2159
|
}
|
|
2127
2160
|
function ensureMcpConfig(projectRoot, target) {
|
|
2128
2161
|
const filePath = join9(projectRoot, target.file);
|
|
2129
|
-
const dir =
|
|
2162
|
+
const dir = dirname5(filePath);
|
|
2130
2163
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
2131
2164
|
const entry = target.extraFields ? { ...target.extraFields, ...CTXO_MCP_ENTRY } : { ...CTXO_MCP_ENTRY };
|
|
2132
2165
|
if (!existsSync6(filePath)) {
|
|
@@ -2462,7 +2495,7 @@ var InitCommand = class {
|
|
|
2462
2495
|
};
|
|
2463
2496
|
|
|
2464
2497
|
// src/cli/watch-command.ts
|
|
2465
|
-
import { join as join11, extname as extname5, relative as
|
|
2498
|
+
import { join as join11, extname as extname5, relative as relative3 } from "path";
|
|
2466
2499
|
import { readFileSync as readFileSync5 } from "fs";
|
|
2467
2500
|
|
|
2468
2501
|
// src/adapters/watcher/chokidar-watcher-adapter.ts
|
|
@@ -2549,7 +2582,7 @@ var WatchCommand = class {
|
|
|
2549
2582
|
const reindexFile = async (filePath) => {
|
|
2550
2583
|
const adapter = registry.getAdapter(filePath);
|
|
2551
2584
|
if (!adapter) return;
|
|
2552
|
-
const relativePath =
|
|
2585
|
+
const relativePath = relative3(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
2553
2586
|
try {
|
|
2554
2587
|
if (roslynAdapter?.isReady() && filePath.endsWith(".cs")) {
|
|
2555
2588
|
const result = await roslynAdapter.reindexFile(relativePath);
|
|
@@ -2637,7 +2670,7 @@ var WatchCommand = class {
|
|
|
2637
2670
|
if (event === "unlink") {
|
|
2638
2671
|
const ext = extname5(filePath).toLowerCase();
|
|
2639
2672
|
if (!supportedExtensions.has(ext)) return;
|
|
2640
|
-
const relativePath =
|
|
2673
|
+
const relativePath = relative3(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
2641
2674
|
writer.delete(relativePath);
|
|
2642
2675
|
storage.deleteSymbolFile(relativePath);
|
|
2643
2676
|
console.error(`[ctxo] Removed from index: ${relativePath}`);
|
|
@@ -3251,6 +3284,9 @@ var DoctorCommand = class {
|
|
|
3251
3284
|
this.ctxoRoot = join18(projectRoot, ".ctxo");
|
|
3252
3285
|
}
|
|
3253
3286
|
async run(options = {}) {
|
|
3287
|
+
const { getVersion: getVersion2 } = await import("./cli-router-ZG3ELO34.js");
|
|
3288
|
+
console.error(`ctxo v${getVersion2()} \u2014 health check
|
|
3289
|
+
`);
|
|
3254
3290
|
const checks = [
|
|
3255
3291
|
new NodeVersionCheck(),
|
|
3256
3292
|
new GitBinaryCheck(),
|
|
@@ -3295,6 +3331,24 @@ var DoctorCommand = class {
|
|
|
3295
3331
|
};
|
|
3296
3332
|
|
|
3297
3333
|
// src/cli/cli-router.ts
|
|
3334
|
+
function getVersion() {
|
|
3335
|
+
let dir = import.meta.dirname;
|
|
3336
|
+
for (let i = 0; i < 10; i++) {
|
|
3337
|
+
const pkg = join19(dir, "package.json");
|
|
3338
|
+
if (existsSync15(pkg)) {
|
|
3339
|
+
try {
|
|
3340
|
+
const json = JSON.parse(readFileSync9(pkg, "utf-8"));
|
|
3341
|
+
return json.version ?? "unknown";
|
|
3342
|
+
} catch {
|
|
3343
|
+
break;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
const parent = join19(dir, "..");
|
|
3347
|
+
if (parent === dir) break;
|
|
3348
|
+
dir = parent;
|
|
3349
|
+
}
|
|
3350
|
+
return "unknown";
|
|
3351
|
+
}
|
|
3298
3352
|
var CliRouter = class {
|
|
3299
3353
|
projectRoot;
|
|
3300
3354
|
constructor(projectRoot) {
|
|
@@ -3302,6 +3356,10 @@ var CliRouter = class {
|
|
|
3302
3356
|
}
|
|
3303
3357
|
async route(args) {
|
|
3304
3358
|
const command = args[0];
|
|
3359
|
+
if (command === "--version" || command === "-v" || command === "-V") {
|
|
3360
|
+
console.error(`ctxo ${getVersion()}`);
|
|
3361
|
+
return;
|
|
3362
|
+
}
|
|
3305
3363
|
if (!command || command === "--help" || command === "-h") {
|
|
3306
3364
|
this.printHelp();
|
|
3307
3365
|
return;
|
|
@@ -3370,8 +3428,9 @@ var CliRouter = class {
|
|
|
3370
3428
|
}
|
|
3371
3429
|
}
|
|
3372
3430
|
printHelp() {
|
|
3431
|
+
const v = getVersion();
|
|
3373
3432
|
console.error(`
|
|
3374
|
-
ctxo \u2014 MCP server for dependency-aware codebase context
|
|
3433
|
+
ctxo v${v} \u2014 MCP server for dependency-aware codebase context
|
|
3375
3434
|
|
|
3376
3435
|
Usage:
|
|
3377
3436
|
ctxo Start MCP server (stdio transport)
|
|
@@ -3391,6 +3450,7 @@ Usage:
|
|
|
3391
3450
|
}
|
|
3392
3451
|
};
|
|
3393
3452
|
export {
|
|
3394
|
-
CliRouter
|
|
3453
|
+
CliRouter,
|
|
3454
|
+
getVersion
|
|
3395
3455
|
};
|
|
3396
|
-
//# sourceMappingURL=cli-router-
|
|
3456
|
+
//# sourceMappingURL=cli-router-ZG3ELO34.js.map
|