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((resolve2) => {
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
- resolve2({ files: [], projectGraph: null, totalFiles: 0, elapsed: "" });
1350
+ resolve3({ files: [], projectGraph: null, totalFiles: 0, elapsed: "" });
1344
1351
  return;
1345
1352
  }
1346
- resolve2({ files, projectGraph, totalFiles, elapsed });
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
- resolve2({ files: [], projectGraph: null, totalFiles: 0, elapsed: "" });
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((resolve2) => {
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
- resolve2(true);
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
- resolve2(false);
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((resolve2) => {
1421
- this.pending.set(relativePath, resolve2);
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
- resolve2(null);
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
- this.cache.set(file.file, file);
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 = relative(this.projectRoot, filePath).replace(/\\/g, "/");
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 = relative(this.projectRoot, filePath).replace(/\\/g, "/");
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 dirname4 } from "path";
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 = dirname4(filePath);
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 = dirname4(filePath);
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 = dirname4(filePath);
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 relative2 } from "path";
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 = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
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 = relative2(this.projectRoot, filePath).replace(/\\/g, "/");
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-LW4YTNHW.js.map
3456
+ //# sourceMappingURL=cli-router-ZG3ELO34.js.map