codemap-ai 3.0.0 → 3.1.1
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 +376 -151
- package/dist/{chunk-XNA2HNUR.js → chunk-LXZ73T7X.js} +46 -1
- package/dist/{chunk-XNA2HNUR.js.map → chunk-LXZ73T7X.js.map} +1 -1
- package/dist/{chunk-GX7ZMBC2.js → chunk-VB74K47A.js} +46 -1
- package/dist/{chunk-GX7ZMBC2.js.map → chunk-VB74K47A.js.map} +1 -1
- package/dist/cli.js +371 -11
- package/dist/cli.js.map +1 -1
- package/dist/{flow-server-QO7IWYLE.js → flow-server-B2SVQKDG.js} +3 -3
- package/dist/{flow-server-QO7IWYLE.js.map → flow-server-B2SVQKDG.js.map} +1 -1
- package/dist/index.d.ts +37 -0
- package/dist/index.js +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
FlowStorage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LXZ73T7X.js";
|
|
6
6
|
|
|
7
7
|
// src/cli-flow.ts
|
|
8
8
|
import { Command } from "commander";
|
|
9
|
-
import { resolve as
|
|
10
|
-
import { existsSync, mkdirSync } from "fs";
|
|
9
|
+
import { resolve as resolve3, join as join3 } from "path";
|
|
10
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
11
|
+
import { homedir } from "os";
|
|
11
12
|
import chalk from "chalk";
|
|
12
13
|
import ora from "ora";
|
|
13
14
|
|
|
@@ -1277,19 +1278,238 @@ var DEFAULT_CONFIG = {
|
|
|
1277
1278
|
languages: ["typescript", "javascript", "python"]
|
|
1278
1279
|
};
|
|
1279
1280
|
|
|
1281
|
+
// src/commands/impact.ts
|
|
1282
|
+
import { resolve as resolve2, join as join2 } from "path";
|
|
1283
|
+
|
|
1284
|
+
// src/utils/git.ts
|
|
1285
|
+
import { execSync } from "child_process";
|
|
1286
|
+
import { existsSync } from "fs";
|
|
1287
|
+
import { join } from "path";
|
|
1288
|
+
function isGitRepository(path) {
|
|
1289
|
+
return existsSync(join(path, ".git"));
|
|
1290
|
+
}
|
|
1291
|
+
function getGitChangedFiles(rootPath) {
|
|
1292
|
+
try {
|
|
1293
|
+
const output = execSync("git diff HEAD --name-status", {
|
|
1294
|
+
cwd: rootPath,
|
|
1295
|
+
encoding: "utf-8"
|
|
1296
|
+
}).trim();
|
|
1297
|
+
if (!output) {
|
|
1298
|
+
return [];
|
|
1299
|
+
}
|
|
1300
|
+
const files = [];
|
|
1301
|
+
for (const line of output.split("\n")) {
|
|
1302
|
+
const [status, path] = line.split(" ");
|
|
1303
|
+
if (path) {
|
|
1304
|
+
files.push({
|
|
1305
|
+
path,
|
|
1306
|
+
status: status === "A" ? "added" : status === "D" ? "deleted" : "modified"
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
return files;
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
return [];
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
function parseGitDiffForFunctions(rootPath, files) {
|
|
1316
|
+
const changedFunctions = [];
|
|
1317
|
+
for (const file of files) {
|
|
1318
|
+
if (file.status === "deleted") {
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
try {
|
|
1322
|
+
const diff = execSync(`git diff HEAD -- "${file.path}"`, {
|
|
1323
|
+
cwd: rootPath,
|
|
1324
|
+
encoding: "utf-8"
|
|
1325
|
+
});
|
|
1326
|
+
const lines = diff.split("\n");
|
|
1327
|
+
let currentFunction = null;
|
|
1328
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1329
|
+
const line = lines[i];
|
|
1330
|
+
if (line.startsWith("@@")) {
|
|
1331
|
+
const contextMatch = line.match(/@@.*@@\s*(.*)/);
|
|
1332
|
+
if (contextMatch) {
|
|
1333
|
+
const context = contextMatch[1];
|
|
1334
|
+
const pythonMatch = context.match(/(?:async\s+)?def\s+(\w+)/);
|
|
1335
|
+
if (pythonMatch) {
|
|
1336
|
+
currentFunction = pythonMatch[1];
|
|
1337
|
+
}
|
|
1338
|
+
const jsMatch = context.match(/(?:function|const|class)\s+(\w+)/);
|
|
1339
|
+
if (jsMatch) {
|
|
1340
|
+
currentFunction = jsMatch[1];
|
|
1341
|
+
}
|
|
1342
|
+
const lineMatch = line.match(/\+(\d+)/);
|
|
1343
|
+
const lineNumber = lineMatch ? parseInt(lineMatch[1]) : 0;
|
|
1344
|
+
if (currentFunction) {
|
|
1345
|
+
changedFunctions.push({
|
|
1346
|
+
file: file.path,
|
|
1347
|
+
functionName: currentFunction,
|
|
1348
|
+
lineNumber,
|
|
1349
|
+
changeType: file.status === "added" ? "added" : "modified"
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
continue;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return changedFunctions;
|
|
1360
|
+
}
|
|
1361
|
+
function getGitStatus(rootPath) {
|
|
1362
|
+
try {
|
|
1363
|
+
const statusOutput = execSync("git status --porcelain", {
|
|
1364
|
+
cwd: rootPath,
|
|
1365
|
+
encoding: "utf-8"
|
|
1366
|
+
}).trim();
|
|
1367
|
+
const lines = statusOutput.split("\n").filter((l) => l.trim());
|
|
1368
|
+
const staged = lines.filter((l) => l[0] !== " " && l[0] !== "?").length;
|
|
1369
|
+
const modified = lines.length;
|
|
1370
|
+
return {
|
|
1371
|
+
hasChanges: modified > 0,
|
|
1372
|
+
modifiedFiles: modified,
|
|
1373
|
+
stagedFiles: staged
|
|
1374
|
+
};
|
|
1375
|
+
} catch (error) {
|
|
1376
|
+
return {
|
|
1377
|
+
hasChanges: false,
|
|
1378
|
+
modifiedFiles: 0,
|
|
1379
|
+
stagedFiles: 0
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// src/commands/impact.ts
|
|
1385
|
+
async function analyzeImpact(options = {}) {
|
|
1386
|
+
const rootPath = resolve2(options.path || ".");
|
|
1387
|
+
const dbPath = join2(rootPath, ".codemap", "graph.db");
|
|
1388
|
+
const storage = new FlowStorage(dbPath);
|
|
1389
|
+
try {
|
|
1390
|
+
if (isGitRepository(rootPath)) {
|
|
1391
|
+
return await analyzeImpactWithGit(storage, rootPath, options);
|
|
1392
|
+
} else {
|
|
1393
|
+
return await analyzeImpactWithHash(storage, rootPath, options);
|
|
1394
|
+
}
|
|
1395
|
+
} finally {
|
|
1396
|
+
storage.close();
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
async function analyzeImpactWithGit(storage, rootPath, options) {
|
|
1400
|
+
const gitStatus = getGitStatus(rootPath);
|
|
1401
|
+
if (!gitStatus.hasChanges) {
|
|
1402
|
+
return {
|
|
1403
|
+
changedFiles: [],
|
|
1404
|
+
changedFunctions: [],
|
|
1405
|
+
directCallers: /* @__PURE__ */ new Map(),
|
|
1406
|
+
affectedEndpoints: [],
|
|
1407
|
+
riskLevel: "LOW",
|
|
1408
|
+
totalImpact: 0
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
const changedFiles = getGitChangedFiles(rootPath);
|
|
1412
|
+
const changedFilePaths = changedFiles.map((f) => f.path);
|
|
1413
|
+
const changedFunctions = parseGitDiffForFunctions(rootPath, changedFiles);
|
|
1414
|
+
const builder = new FlowBuilder(storage, {
|
|
1415
|
+
rootPath,
|
|
1416
|
+
include: changedFilePaths.map((f) => f),
|
|
1417
|
+
exclude: [],
|
|
1418
|
+
forceReindex: true
|
|
1419
|
+
});
|
|
1420
|
+
await builder.build();
|
|
1421
|
+
const directCallers = /* @__PURE__ */ new Map();
|
|
1422
|
+
const affectedEndpoints = [];
|
|
1423
|
+
for (const func of changedFunctions) {
|
|
1424
|
+
const nodes = storage.getNodesByFile(join2(rootPath, func.file)).filter((n) => n.name === func.functionName);
|
|
1425
|
+
for (const node of nodes) {
|
|
1426
|
+
const callers = storage.getResolvedCallersWithLocation(node.id);
|
|
1427
|
+
if (callers.length > 0) {
|
|
1428
|
+
directCallers.set(func.functionName, callers);
|
|
1429
|
+
}
|
|
1430
|
+
const endpoints = storage.getHttpEndpointsByHandler(node.id);
|
|
1431
|
+
for (const endpoint of endpoints) {
|
|
1432
|
+
affectedEndpoints.push(`${endpoint.method} ${endpoint.path}`);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
const totalCallers = Array.from(directCallers.values()).reduce((sum, callers) => sum + callers.length, 0);
|
|
1437
|
+
let riskLevel = "LOW";
|
|
1438
|
+
if (totalCallers > 20 || affectedEndpoints.length > 5) {
|
|
1439
|
+
riskLevel = "HIGH";
|
|
1440
|
+
} else if (totalCallers > 10 || affectedEndpoints.length > 2) {
|
|
1441
|
+
riskLevel = "MEDIUM";
|
|
1442
|
+
}
|
|
1443
|
+
return {
|
|
1444
|
+
changedFiles: changedFilePaths,
|
|
1445
|
+
changedFunctions,
|
|
1446
|
+
directCallers,
|
|
1447
|
+
affectedEndpoints,
|
|
1448
|
+
riskLevel,
|
|
1449
|
+
totalImpact: totalCallers
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
async function analyzeImpactWithHash(storage, rootPath, options) {
|
|
1453
|
+
const oldHashes = storage.getAllFileHashes();
|
|
1454
|
+
const builder = new FlowBuilder(storage, {
|
|
1455
|
+
rootPath,
|
|
1456
|
+
include: DEFAULT_CONFIG.include,
|
|
1457
|
+
exclude: DEFAULT_CONFIG.exclude,
|
|
1458
|
+
forceReindex: false
|
|
1459
|
+
// Use hash comparison
|
|
1460
|
+
});
|
|
1461
|
+
const result = await builder.build();
|
|
1462
|
+
const changedFiles = [];
|
|
1463
|
+
const newHashes = storage.getAllFileHashes();
|
|
1464
|
+
for (const [filePath, newHash] of Object.entries(newHashes)) {
|
|
1465
|
+
const oldHash = oldHashes[filePath];
|
|
1466
|
+
if (!oldHash || oldHash !== newHash) {
|
|
1467
|
+
changedFiles.push(filePath);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
return {
|
|
1471
|
+
changedFiles,
|
|
1472
|
+
changedFunctions: [],
|
|
1473
|
+
directCallers: /* @__PURE__ */ new Map(),
|
|
1474
|
+
affectedEndpoints: [],
|
|
1475
|
+
riskLevel: changedFiles.length > 10 ? "HIGH" : changedFiles.length > 5 ? "MEDIUM" : "LOW",
|
|
1476
|
+
totalImpact: result.indexed
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1280
1480
|
// src/cli-flow.ts
|
|
1281
1481
|
var program = new Command();
|
|
1282
|
-
|
|
1482
|
+
function configureMCPServer(projectPath) {
|
|
1483
|
+
try {
|
|
1484
|
+
const claudeConfigPath = join3(homedir(), ".claude", "config.json");
|
|
1485
|
+
if (!existsSync2(claudeConfigPath)) {
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
const config = JSON.parse(readFileSync2(claudeConfigPath, "utf-8"));
|
|
1489
|
+
if (!config.mcpServers) {
|
|
1490
|
+
config.mcpServers = {};
|
|
1491
|
+
}
|
|
1492
|
+
config.mcpServers.codemap = {
|
|
1493
|
+
command: "npx",
|
|
1494
|
+
args: ["codemap-ai", "mcp-server", "--path", projectPath]
|
|
1495
|
+
};
|
|
1496
|
+
writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2));
|
|
1497
|
+
return true;
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
return false;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
program.name("codemap").description("CodeMap Flow - Call graph analyzer for understanding code impact").version("3.1.1");
|
|
1283
1503
|
program.command("index").description("Build call graph for your codebase").argument("[path]", "Path to the project root", ".").option("-f, --force", "Force reindex all files (ignore cache)").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").action(async (path, options) => {
|
|
1284
|
-
const rootPath =
|
|
1285
|
-
const outputDir =
|
|
1504
|
+
const rootPath = resolve3(path);
|
|
1505
|
+
const outputDir = join3(rootPath, ".codemap");
|
|
1286
1506
|
console.log(chalk.blue.bold("\n CodeMap Call Graph Indexer\n"));
|
|
1287
1507
|
console.log(chalk.gray(` Project: ${rootPath}
|
|
1288
1508
|
`));
|
|
1289
|
-
if (!
|
|
1509
|
+
if (!existsSync2(outputDir)) {
|
|
1290
1510
|
mkdirSync(outputDir, { recursive: true });
|
|
1291
1511
|
}
|
|
1292
|
-
const dbPath =
|
|
1512
|
+
const dbPath = join3(outputDir, "graph.db");
|
|
1293
1513
|
const storage = new FlowStorage(dbPath);
|
|
1294
1514
|
const builder = new FlowBuilder(storage, {
|
|
1295
1515
|
rootPath,
|
|
@@ -1358,10 +1578,150 @@ program.command("index").description("Build call graph for your codebase").argum
|
|
|
1358
1578
|
storage.close();
|
|
1359
1579
|
}
|
|
1360
1580
|
});
|
|
1581
|
+
program.command("init").description("Initialize CodeMap (index + setup MCP)").argument("[path]", "Path to the project root", ".").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").option("--skip-mcp", "Skip MCP server configuration").action(async (path, options) => {
|
|
1582
|
+
const rootPath = resolve3(path);
|
|
1583
|
+
const outputDir = join3(rootPath, ".codemap");
|
|
1584
|
+
console.log(chalk.blue.bold("\n CodeMap Initialization\n"));
|
|
1585
|
+
console.log(chalk.gray(` Project: ${rootPath}
|
|
1586
|
+
`));
|
|
1587
|
+
if (existsSync2(join3(outputDir, "graph.db")) && !options.force) {
|
|
1588
|
+
console.log(chalk.yellow(" Already initialized. Use 'codemap reindex' to rebuild.\n"));
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
if (!existsSync2(outputDir)) {
|
|
1592
|
+
mkdirSync(outputDir, { recursive: true });
|
|
1593
|
+
}
|
|
1594
|
+
const dbPath = join3(outputDir, "graph.db");
|
|
1595
|
+
const storage = new FlowStorage(dbPath);
|
|
1596
|
+
const builder = new FlowBuilder(storage, {
|
|
1597
|
+
rootPath,
|
|
1598
|
+
include: options.include || DEFAULT_CONFIG.include,
|
|
1599
|
+
exclude: options.exclude || DEFAULT_CONFIG.exclude,
|
|
1600
|
+
forceReindex: true
|
|
1601
|
+
});
|
|
1602
|
+
const spinner = ora("Indexing codebase...").start();
|
|
1603
|
+
builder.setProgressCallback((progress) => {
|
|
1604
|
+
switch (progress.phase) {
|
|
1605
|
+
case "discovering":
|
|
1606
|
+
spinner.text = "Discovering files...";
|
|
1607
|
+
break;
|
|
1608
|
+
case "parsing":
|
|
1609
|
+
spinner.text = `Parsing (${progress.current}/${progress.total}): ${progress.currentFile}`;
|
|
1610
|
+
break;
|
|
1611
|
+
case "resolving":
|
|
1612
|
+
spinner.text = "Resolving cross-file calls...";
|
|
1613
|
+
break;
|
|
1614
|
+
case "complete":
|
|
1615
|
+
spinner.succeed(chalk.green("Indexing complete!"));
|
|
1616
|
+
break;
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
try {
|
|
1620
|
+
const result = await builder.build();
|
|
1621
|
+
console.log(chalk.blue("\n Results:\n"));
|
|
1622
|
+
console.log(` ${chalk.bold("Indexed:")} ${result.indexed} files`);
|
|
1623
|
+
console.log(` ${chalk.bold("Resolved:")} ${result.resolved} function calls`);
|
|
1624
|
+
const stats = storage.getStats();
|
|
1625
|
+
if (stats.httpEndpoints > 0) {
|
|
1626
|
+
console.log(chalk.cyan(`
|
|
1627
|
+
${chalk.bold("Framework Detection:")}`));
|
|
1628
|
+
console.log(` ${chalk.bold("HTTP Endpoints:")} ${stats.httpEndpoints} routes`);
|
|
1629
|
+
}
|
|
1630
|
+
const resolveRate = result.resolved + result.unresolved > 0 ? Math.round(result.resolved / (result.resolved + result.unresolved) * 100) : 0;
|
|
1631
|
+
console.log(chalk.gray(`
|
|
1632
|
+
Call resolution: ${resolveRate}%`));
|
|
1633
|
+
console.log(chalk.gray(` Database: ${dbPath}
|
|
1634
|
+
`));
|
|
1635
|
+
if (!options.skipMcp) {
|
|
1636
|
+
const mcpConfigured = configureMCPServer(rootPath);
|
|
1637
|
+
if (mcpConfigured) {
|
|
1638
|
+
console.log(chalk.green(" \u2713 MCP server configured in Claude Code\n"));
|
|
1639
|
+
} else {
|
|
1640
|
+
console.log(chalk.yellow(" \u26A0 Could not auto-configure MCP (Claude Code not found)"));
|
|
1641
|
+
console.log(chalk.gray(" Run manually: claude mcp add codemap -- npx codemap-ai mcp-server\n"));
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
console.log(chalk.cyan(" Ready!"));
|
|
1645
|
+
console.log(chalk.gray(" Ask Claude: 'What would break if I change authenticate_user?'\n"));
|
|
1646
|
+
} catch (error) {
|
|
1647
|
+
spinner.fail(chalk.red("Initialization failed"));
|
|
1648
|
+
console.error(error);
|
|
1649
|
+
process.exit(1);
|
|
1650
|
+
} finally {
|
|
1651
|
+
storage.close();
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
program.command("impact").description("Analyze impact of code changes").argument("[path]", "Path to the project root", ".").option("-v, --verbose", "Show detailed output").action(async (path, options) => {
|
|
1655
|
+
const rootPath = resolve3(path);
|
|
1656
|
+
const dbPath = join3(rootPath, ".codemap", "graph.db");
|
|
1657
|
+
console.log(chalk.blue.bold("\n CodeMap Impact Analysis\n"));
|
|
1658
|
+
if (!existsSync2(dbPath)) {
|
|
1659
|
+
console.log(chalk.red(" Error: Not initialized. Run 'codemap init' first.\n"));
|
|
1660
|
+
process.exit(1);
|
|
1661
|
+
}
|
|
1662
|
+
const spinner = ora("Detecting changes...").start();
|
|
1663
|
+
try {
|
|
1664
|
+
const result = await analyzeImpact({ path: rootPath, verbose: options.verbose });
|
|
1665
|
+
if (result.changedFiles.length === 0) {
|
|
1666
|
+
spinner.succeed(chalk.green("No changes detected"));
|
|
1667
|
+
console.log(chalk.gray(" All files are up to date.\n"));
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
spinner.succeed(chalk.green(`Detected ${result.changedFiles.length} modified files`));
|
|
1671
|
+
console.log(chalk.blue("\n Modified Files:\n"));
|
|
1672
|
+
for (const file of result.changedFiles.slice(0, 10)) {
|
|
1673
|
+
console.log(chalk.gray(` \u2022 ${file}`));
|
|
1674
|
+
}
|
|
1675
|
+
if (result.changedFiles.length > 10) {
|
|
1676
|
+
console.log(chalk.gray(` ... and ${result.changedFiles.length - 10} more`));
|
|
1677
|
+
}
|
|
1678
|
+
if (result.changedFunctions.length > 0) {
|
|
1679
|
+
console.log(chalk.blue("\n Changed Functions:\n"));
|
|
1680
|
+
for (const func of result.changedFunctions) {
|
|
1681
|
+
console.log(chalk.gray(` \u2022 ${func.functionName} (${func.file}:${func.lineNumber})`));
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (result.directCallers.size > 0) {
|
|
1685
|
+
console.log(chalk.blue("\n Impact Analysis:\n"));
|
|
1686
|
+
for (const [funcName, callers] of result.directCallers.entries()) {
|
|
1687
|
+
console.log(chalk.yellow(` ${funcName}:`));
|
|
1688
|
+
console.log(chalk.gray(` ${callers.length} direct callers`));
|
|
1689
|
+
if (options.verbose) {
|
|
1690
|
+
for (const caller of callers.slice(0, 5)) {
|
|
1691
|
+
console.log(chalk.gray(` \u2022 ${caller.name} (${caller.file}:${caller.line})`));
|
|
1692
|
+
}
|
|
1693
|
+
if (callers.length > 5) {
|
|
1694
|
+
console.log(chalk.gray(` ... and ${callers.length - 5} more`));
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
if (result.affectedEndpoints.length > 0) {
|
|
1700
|
+
console.log(chalk.blue("\n Affected HTTP Endpoints:\n"));
|
|
1701
|
+
for (const endpoint of result.affectedEndpoints) {
|
|
1702
|
+
console.log(chalk.gray(` \u2022 ${endpoint}`));
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
console.log(chalk.blue("\n Risk Assessment:\n"));
|
|
1706
|
+
const riskColor = result.riskLevel === "HIGH" ? chalk.red : result.riskLevel === "MEDIUM" ? chalk.yellow : chalk.green;
|
|
1707
|
+
console.log(` ${riskColor(result.riskLevel)} - ${result.totalImpact} functions affected`);
|
|
1708
|
+
console.log();
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
spinner.fail(chalk.red("Impact analysis failed"));
|
|
1711
|
+
console.error(error);
|
|
1712
|
+
process.exit(1);
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
program.command("reindex").description("Force full re-index of codebase").argument("[path]", "Path to the project root", ".").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").action(async (path, options) => {
|
|
1716
|
+
const indexCommand = program.commands.find((cmd) => cmd.name() === "index");
|
|
1717
|
+
if (indexCommand) {
|
|
1718
|
+
await indexCommand.parseAsync([path, "--force", ...options.include ? ["--include", ...options.include] : [], ...options.exclude ? ["--exclude", ...options.exclude] : []], { from: "user" });
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1361
1721
|
program.command("mcp-server").description("Start MCP server for Claude Code integration").option("-p, --path <path>", "Project root path", ".").action(async (options) => {
|
|
1362
|
-
process.env.CODEMAP_PROJECT_ROOT =
|
|
1363
|
-
process.env.CODEMAP_DB_PATH =
|
|
1364
|
-
await import("./flow-server-
|
|
1722
|
+
process.env.CODEMAP_PROJECT_ROOT = resolve3(options.path);
|
|
1723
|
+
process.env.CODEMAP_DB_PATH = join3(resolve3(options.path), ".codemap", "graph.db");
|
|
1724
|
+
await import("./flow-server-B2SVQKDG.js");
|
|
1365
1725
|
});
|
|
1366
1726
|
program.parse();
|
|
1367
1727
|
//# sourceMappingURL=cli.js.map
|