@sashabogi/argus-mcp 1.2.3 → 2.0.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 +403 -156
- package/dist/cli.mjs +272 -36
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +70 -1
- package/dist/index.mjs +252 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.mjs +812 -23
- package/dist/mcp.mjs.map +1 -1
- package/package.json +5 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
4
10
|
var __esm = (fn, res) => function __init() {
|
|
5
11
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
12
|
};
|
|
@@ -10,9 +16,15 @@ var __export = (target, all) => {
|
|
|
10
16
|
};
|
|
11
17
|
|
|
12
18
|
// node_modules/tsup/assets/esm_shims.js
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
import path from "path";
|
|
21
|
+
var getFilename, getDirname, __dirname;
|
|
13
22
|
var init_esm_shims = __esm({
|
|
14
23
|
"node_modules/tsup/assets/esm_shims.js"() {
|
|
15
24
|
"use strict";
|
|
25
|
+
getFilename = () => fileURLToPath(import.meta.url);
|
|
26
|
+
getDirname = () => path.dirname(getFilename());
|
|
27
|
+
__dirname = /* @__PURE__ */ getDirname();
|
|
16
28
|
}
|
|
17
29
|
});
|
|
18
30
|
|
|
@@ -511,14 +523,14 @@ var init_onboarding_ui = __esm({
|
|
|
511
523
|
});
|
|
512
524
|
|
|
513
525
|
// src/core/onboarding.ts
|
|
514
|
-
function detectPotentialKeyFiles(projectPath, userPatterns, fs2,
|
|
526
|
+
function detectPotentialKeyFiles(projectPath, userPatterns, fs2, path3) {
|
|
515
527
|
const detected = [];
|
|
516
528
|
function checkFile(filePath, relativePath) {
|
|
517
529
|
try {
|
|
518
530
|
const stats = fs2.statSync(filePath);
|
|
519
531
|
if (!stats.isFile()) return;
|
|
520
|
-
const fileName =
|
|
521
|
-
const ext =
|
|
532
|
+
const fileName = path3.basename(filePath).toLowerCase();
|
|
533
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
522
534
|
if (![".md", ".txt", ".org", ""].includes(ext)) return;
|
|
523
535
|
let reason = "";
|
|
524
536
|
let matchedPattern;
|
|
@@ -587,13 +599,13 @@ function detectPotentialKeyFiles(projectPath, userPatterns, fs2, path2) {
|
|
|
587
599
|
}
|
|
588
600
|
if (relativePath.split("/").filter(Boolean).length < 2) {
|
|
589
601
|
scanDir(
|
|
590
|
-
|
|
602
|
+
path3.join(dirPath, entry.name),
|
|
591
603
|
relativePath ? `${relativePath}/${entry.name}` : entry.name
|
|
592
604
|
);
|
|
593
605
|
}
|
|
594
606
|
} else {
|
|
595
607
|
checkFile(
|
|
596
|
-
|
|
608
|
+
path3.join(dirPath, entry.name),
|
|
597
609
|
relativePath ? `${relativePath}/${entry.name}` : entry.name
|
|
598
610
|
);
|
|
599
611
|
}
|
|
@@ -624,12 +636,12 @@ async function runGlobalOnboarding() {
|
|
|
624
636
|
console.log(` Key patterns: ${config.globalKeyPatterns.join(", ")}`);
|
|
625
637
|
return config;
|
|
626
638
|
}
|
|
627
|
-
async function runProjectOnboarding(projectPath, globalConfig, fs2,
|
|
628
|
-
const projectName =
|
|
639
|
+
async function runProjectOnboarding(projectPath, globalConfig, fs2, path3) {
|
|
640
|
+
const projectName = path3.basename(projectPath);
|
|
629
641
|
console.log(`
|
|
630
642
|
\u{1F4C2} Scanning project: ${projectName}
|
|
631
643
|
`);
|
|
632
|
-
const detected = detectPotentialKeyFiles(projectPath, globalConfig.globalKeyPatterns, fs2,
|
|
644
|
+
const detected = detectPotentialKeyFiles(projectPath, globalConfig.globalKeyPatterns, fs2, path3);
|
|
633
645
|
if (globalConfig.experienceLevel === "beginner") {
|
|
634
646
|
const autoSelected = detected.filter((d) => d.matchedPattern).map((d) => d.path);
|
|
635
647
|
if (autoSelected.length > 0) {
|
|
@@ -703,9 +715,9 @@ import { Command } from "commander";
|
|
|
703
715
|
import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, statSync as statSync2, unlinkSync, readdirSync as readdirSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
704
716
|
import * as fs from "fs";
|
|
705
717
|
import { homedir as homedir2 } from "os";
|
|
706
|
-
import { join as join4, resolve, basename } from "path";
|
|
707
|
-
import * as
|
|
708
|
-
import { execSync } from "child_process";
|
|
718
|
+
import { join as join4, resolve, basename as basename2 } from "path";
|
|
719
|
+
import * as path2 from "path";
|
|
720
|
+
import { execSync as execSync2 } from "child_process";
|
|
709
721
|
|
|
710
722
|
// src/core/config.ts
|
|
711
723
|
init_esm_shims();
|
|
@@ -945,7 +957,8 @@ function createSnapshot(projectPath, outputPath, options = {}) {
|
|
|
945
957
|
// src/core/enhanced-snapshot.ts
|
|
946
958
|
init_esm_shims();
|
|
947
959
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
948
|
-
import { join as join3, dirname, extname as extname2 } from "path";
|
|
960
|
+
import { join as join3, dirname, extname as extname2, basename } from "path";
|
|
961
|
+
import { execSync } from "child_process";
|
|
949
962
|
function parseImports(content, filePath) {
|
|
950
963
|
const imports = [];
|
|
951
964
|
const lines = content.split("\n");
|
|
@@ -1082,6 +1095,114 @@ function parseExports(content, filePath) {
|
|
|
1082
1095
|
}
|
|
1083
1096
|
return exports;
|
|
1084
1097
|
}
|
|
1098
|
+
function calculateComplexity(content) {
|
|
1099
|
+
const patterns = [
|
|
1100
|
+
/\bif\s*\(/g,
|
|
1101
|
+
/\belse\s+if\s*\(/g,
|
|
1102
|
+
/\bwhile\s*\(/g,
|
|
1103
|
+
/\bfor\s*\(/g,
|
|
1104
|
+
/\bcase\s+/g,
|
|
1105
|
+
/\?\s*.*\s*:/g,
|
|
1106
|
+
/\&\&/g,
|
|
1107
|
+
/\|\|/g,
|
|
1108
|
+
/\bcatch\s*\(/g
|
|
1109
|
+
];
|
|
1110
|
+
let complexity = 1;
|
|
1111
|
+
for (const pattern of patterns) {
|
|
1112
|
+
const matches = content.match(pattern);
|
|
1113
|
+
if (matches) complexity += matches.length;
|
|
1114
|
+
}
|
|
1115
|
+
return complexity;
|
|
1116
|
+
}
|
|
1117
|
+
function getComplexityLevel(score) {
|
|
1118
|
+
if (score <= 10) return "low";
|
|
1119
|
+
if (score <= 20) return "medium";
|
|
1120
|
+
return "high";
|
|
1121
|
+
}
|
|
1122
|
+
function mapTestFiles(files) {
|
|
1123
|
+
const testMap = {};
|
|
1124
|
+
const testPatterns = [
|
|
1125
|
+
// Same directory patterns
|
|
1126
|
+
(src) => src.replace(/\.tsx?$/, ".test.ts"),
|
|
1127
|
+
(src) => src.replace(/\.tsx?$/, ".test.tsx"),
|
|
1128
|
+
(src) => src.replace(/\.tsx?$/, ".spec.ts"),
|
|
1129
|
+
(src) => src.replace(/\.tsx?$/, ".spec.tsx"),
|
|
1130
|
+
(src) => src.replace(/\.jsx?$/, ".test.js"),
|
|
1131
|
+
(src) => src.replace(/\.jsx?$/, ".test.jsx"),
|
|
1132
|
+
(src) => src.replace(/\.jsx?$/, ".spec.js"),
|
|
1133
|
+
(src) => src.replace(/\.jsx?$/, ".spec.jsx"),
|
|
1134
|
+
// __tests__ directory pattern
|
|
1135
|
+
(src) => {
|
|
1136
|
+
const dir = dirname(src);
|
|
1137
|
+
const base = basename(src).replace(/\.(tsx?|jsx?)$/, "");
|
|
1138
|
+
return join3(dir, "__tests__", `${base}.test.ts`);
|
|
1139
|
+
},
|
|
1140
|
+
(src) => {
|
|
1141
|
+
const dir = dirname(src);
|
|
1142
|
+
const base = basename(src).replace(/\.(tsx?|jsx?)$/, "");
|
|
1143
|
+
return join3(dir, "__tests__", `${base}.test.tsx`);
|
|
1144
|
+
},
|
|
1145
|
+
// test/ directory pattern
|
|
1146
|
+
(src) => src.replace(/^src\//, "test/").replace(/\.(tsx?|jsx?)$/, ".test.ts"),
|
|
1147
|
+
(src) => src.replace(/^src\//, "tests/").replace(/\.(tsx?|jsx?)$/, ".test.ts")
|
|
1148
|
+
];
|
|
1149
|
+
const fileSet = new Set(files);
|
|
1150
|
+
for (const file of files) {
|
|
1151
|
+
if (file.includes(".test.") || file.includes(".spec.") || file.includes("__tests__")) continue;
|
|
1152
|
+
if (!/\.(tsx?|jsx?)$/.test(file)) continue;
|
|
1153
|
+
const tests = [];
|
|
1154
|
+
for (const pattern of testPatterns) {
|
|
1155
|
+
const testPath = pattern(file);
|
|
1156
|
+
if (testPath !== file && fileSet.has(testPath)) {
|
|
1157
|
+
tests.push(testPath);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
if (tests.length > 0) {
|
|
1161
|
+
testMap[file] = [...new Set(tests)];
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return testMap;
|
|
1165
|
+
}
|
|
1166
|
+
function getRecentChanges(projectPath) {
|
|
1167
|
+
try {
|
|
1168
|
+
execSync("git rev-parse --git-dir", { cwd: projectPath, encoding: "utf-8", stdio: "pipe" });
|
|
1169
|
+
const output = execSync(
|
|
1170
|
+
'git log --since="7 days ago" --name-only --format="COMMIT_AUTHOR:%an" --diff-filter=ACMR',
|
|
1171
|
+
{ cwd: projectPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024, stdio: "pipe" }
|
|
1172
|
+
);
|
|
1173
|
+
if (!output.trim()) return [];
|
|
1174
|
+
const fileStats = {};
|
|
1175
|
+
let currentAuthor = "";
|
|
1176
|
+
let currentCommitId = 0;
|
|
1177
|
+
for (const line of output.split("\n")) {
|
|
1178
|
+
const trimmed = line.trim();
|
|
1179
|
+
if (!trimmed) {
|
|
1180
|
+
currentCommitId++;
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
if (trimmed.startsWith("COMMIT_AUTHOR:")) {
|
|
1184
|
+
currentAuthor = trimmed.replace("COMMIT_AUTHOR:", "");
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
const file = trimmed;
|
|
1188
|
+
if (!fileStats[file]) {
|
|
1189
|
+
fileStats[file] = { commits: /* @__PURE__ */ new Set(), authors: /* @__PURE__ */ new Set() };
|
|
1190
|
+
}
|
|
1191
|
+
fileStats[file].commits.add(`${currentCommitId}`);
|
|
1192
|
+
if (currentAuthor) {
|
|
1193
|
+
fileStats[file].authors.add(currentAuthor);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
const result = Object.entries(fileStats).map(([file, stats]) => ({
|
|
1197
|
+
file,
|
|
1198
|
+
commits: stats.commits.size,
|
|
1199
|
+
authors: stats.authors.size
|
|
1200
|
+
})).sort((a, b) => b.commits - a.commits);
|
|
1201
|
+
return result;
|
|
1202
|
+
} catch {
|
|
1203
|
+
return null;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1085
1206
|
function resolveImportPath(importPath, fromFile, projectFiles) {
|
|
1086
1207
|
if (!importPath.startsWith(".")) return void 0;
|
|
1087
1208
|
const fromDir = dirname(fromFile);
|
|
@@ -1151,6 +1272,23 @@ function createEnhancedSnapshot(projectPath, outputPath, options = {}) {
|
|
|
1151
1272
|
symbolIndex[exp.symbol].push(exp.file);
|
|
1152
1273
|
}
|
|
1153
1274
|
}
|
|
1275
|
+
const complexityScores = [];
|
|
1276
|
+
for (const [relPath, metadata] of Object.entries(fileIndex)) {
|
|
1277
|
+
const fullPath = join3(projectPath, relPath);
|
|
1278
|
+
try {
|
|
1279
|
+
const content = readFileSync3(fullPath, "utf-8");
|
|
1280
|
+
const score = calculateComplexity(content);
|
|
1281
|
+
complexityScores.push({
|
|
1282
|
+
file: relPath,
|
|
1283
|
+
score,
|
|
1284
|
+
level: getComplexityLevel(score)
|
|
1285
|
+
});
|
|
1286
|
+
} catch {
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
complexityScores.sort((a, b) => b.score - a.score);
|
|
1290
|
+
const testFileMap = mapTestFiles(baseResult.files);
|
|
1291
|
+
const recentChanges = getRecentChanges(projectPath);
|
|
1154
1292
|
const metadataSection = `
|
|
1155
1293
|
|
|
1156
1294
|
================================================================================
|
|
@@ -1174,6 +1312,25 @@ METADATA: WHO IMPORTS WHOM
|
|
|
1174
1312
|
================================================================================
|
|
1175
1313
|
${Object.entries(exportGraph).map(([file, importers]) => `${file} is imported by:
|
|
1176
1314
|
${importers.map((i) => ` \u2190 ${i}`).join("\n")}`).join("\n\n")}
|
|
1315
|
+
|
|
1316
|
+
================================================================================
|
|
1317
|
+
METADATA: COMPLEXITY SCORES
|
|
1318
|
+
================================================================================
|
|
1319
|
+
${complexityScores.map((c) => `${c.file}: ${c.score} (${c.level})`).join("\n")}
|
|
1320
|
+
|
|
1321
|
+
================================================================================
|
|
1322
|
+
METADATA: TEST COVERAGE MAP
|
|
1323
|
+
================================================================================
|
|
1324
|
+
${Object.entries(testFileMap).length > 0 ? Object.entries(testFileMap).map(([src, tests]) => `${src} -> ${tests.join(", ")}`).join("\n") : "(no test file mappings found)"}
|
|
1325
|
+
${baseResult.files.filter(
|
|
1326
|
+
(f) => /\.(tsx?|jsx?)$/.test(f) && !f.includes(".test.") && !f.includes(".spec.") && !f.includes("__tests__") && !testFileMap[f]
|
|
1327
|
+
).map((f) => `${f} -> (no tests)`).join("\n")}
|
|
1328
|
+
${recentChanges !== null ? `
|
|
1329
|
+
|
|
1330
|
+
================================================================================
|
|
1331
|
+
METADATA: RECENT CHANGES (last 7 days)
|
|
1332
|
+
================================================================================
|
|
1333
|
+
${recentChanges.length > 0 ? recentChanges.map((c) => `${c.file}: ${c.commits} commit${c.commits !== 1 ? "s" : ""}, ${c.authors} author${c.authors !== 1 ? "s" : ""}`).join("\n") : "(no changes in the last 7 days)"}` : ""}
|
|
1177
1334
|
`;
|
|
1178
1335
|
const existingContent = readFileSync3(outputPath, "utf-8");
|
|
1179
1336
|
writeFileSync3(outputPath, existingContent + metadataSection);
|
|
@@ -1185,7 +1342,10 @@ ${importers.map((i) => ` \u2190 ${i}`).join("\n")}`).join("\n\n")}
|
|
|
1185
1342
|
fileIndex,
|
|
1186
1343
|
importGraph,
|
|
1187
1344
|
exportGraph,
|
|
1188
|
-
symbolIndex
|
|
1345
|
+
symbolIndex,
|
|
1346
|
+
complexityScores,
|
|
1347
|
+
testFileMap,
|
|
1348
|
+
recentChanges
|
|
1189
1349
|
}
|
|
1190
1350
|
};
|
|
1191
1351
|
}
|
|
@@ -2055,7 +2215,7 @@ program.command("init").description("Interactive setup wizard").action(async ()
|
|
|
2055
2215
|
program.command("update").description("Update Argus to the latest version").action(() => {
|
|
2056
2216
|
console.log("\n\u{1F504} Updating Argus...\n");
|
|
2057
2217
|
try {
|
|
2058
|
-
|
|
2218
|
+
execSync2("npm install -g https://github.com/sashabogi/argus/tarball/main", { stdio: "inherit" });
|
|
2059
2219
|
console.log("\n\u2705 Argus updated successfully!");
|
|
2060
2220
|
console.log("\nRun `argus --version` to check the new version.");
|
|
2061
2221
|
} catch (error) {
|
|
@@ -2064,7 +2224,7 @@ program.command("update").description("Update Argus to the latest version").acti
|
|
|
2064
2224
|
process.exit(1);
|
|
2065
2225
|
}
|
|
2066
2226
|
});
|
|
2067
|
-
program.command("analyze <path> <query>").description("Analyze a codebase or snapshot with AI").option("-p, --provider <provider>", "Override default provider").option("-t, --max-turns <n>", "Maximum reasoning turns", "15").option("-v, --verbose", "Show detailed execution logs").action(async (
|
|
2227
|
+
program.command("analyze <path> <query>").description("Analyze a codebase or snapshot with AI").option("-p, --provider <provider>", "Override default provider").option("-t, --max-turns <n>", "Maximum reasoning turns", "15").option("-v, --verbose", "Show detailed execution logs").action(async (path3, query, opts) => {
|
|
2068
2228
|
const config = loadConfig();
|
|
2069
2229
|
if (opts.provider) {
|
|
2070
2230
|
config.provider = opts.provider;
|
|
@@ -2076,7 +2236,7 @@ program.command("analyze <path> <query>").description("Analyze a codebase or sna
|
|
|
2076
2236
|
console.error("\nRun `argus init` to configure.");
|
|
2077
2237
|
process.exit(1);
|
|
2078
2238
|
}
|
|
2079
|
-
const resolvedPath = resolve(
|
|
2239
|
+
const resolvedPath = resolve(path3);
|
|
2080
2240
|
if (!existsSync4(resolvedPath)) {
|
|
2081
2241
|
console.error(`File not found: ${resolvedPath}`);
|
|
2082
2242
|
process.exit(1);
|
|
@@ -2131,14 +2291,14 @@ program.command("analyze <path> <query>").description("Analyze a codebase or sna
|
|
|
2131
2291
|
}
|
|
2132
2292
|
}
|
|
2133
2293
|
});
|
|
2134
|
-
program.command("snapshot <path>").description("Create a codebase snapshot for analysis").option("-o, --output <file>", "Output file path").option("-e, --extensions <exts>", "File extensions to include (comma-separated)").option("--exclude <patterns>", "Patterns to exclude (comma-separated)").option("--basic", "Skip structural metadata (faster, smaller snapshot)").action((
|
|
2294
|
+
program.command("snapshot <path>").description("Create a codebase snapshot for analysis").option("-o, --output <file>", "Output file path").option("-e, --extensions <exts>", "File extensions to include (comma-separated)").option("--exclude <patterns>", "Patterns to exclude (comma-separated)").option("--basic", "Skip structural metadata (faster, smaller snapshot)").action((path3, opts) => {
|
|
2135
2295
|
const config = loadConfig();
|
|
2136
|
-
const resolvedPath = resolve(
|
|
2296
|
+
const resolvedPath = resolve(path3);
|
|
2137
2297
|
if (!existsSync4(resolvedPath)) {
|
|
2138
2298
|
console.error(`Path not found: ${resolvedPath}`);
|
|
2139
2299
|
process.exit(1);
|
|
2140
2300
|
}
|
|
2141
|
-
const outputPath = opts.output || `${
|
|
2301
|
+
const outputPath = opts.output || `${basename2(resolvedPath)}-snapshot.txt`;
|
|
2142
2302
|
console.log("\u{1F4F8} Creating codebase snapshot...");
|
|
2143
2303
|
console.log(` Source: ${resolvedPath}`);
|
|
2144
2304
|
console.log(` Output: ${outputPath}`);
|
|
@@ -2196,8 +2356,8 @@ program.command("search <snapshot> <pattern>").description("Fast grep search (no
|
|
|
2196
2356
|
console.log(`${match.lineNum}: ${match.line.trim()}`);
|
|
2197
2357
|
}
|
|
2198
2358
|
});
|
|
2199
|
-
program.command("status [path]").description("Check if snapshot is up to date").option("-s, --snapshot <file>", "Snapshot file to check", ".argus/snapshot.txt").action((
|
|
2200
|
-
const projectPath =
|
|
2359
|
+
program.command("status [path]").description("Check if snapshot is up to date").option("-s, --snapshot <file>", "Snapshot file to check", ".argus/snapshot.txt").action((path3, opts) => {
|
|
2360
|
+
const projectPath = path3 ? resolve(path3) : process.cwd();
|
|
2201
2361
|
const snapshotPath = resolve(projectPath, opts.snapshot);
|
|
2202
2362
|
console.log("\u{1F4CA} Argus Status\n");
|
|
2203
2363
|
if (!existsSync4(snapshotPath)) {
|
|
@@ -2312,8 +2472,8 @@ exec argus-mcp "$@"
|
|
|
2312
2472
|
ensureConfigDir();
|
|
2313
2473
|
writeFileSync4(wrapperPath, wrapperScript, { mode: 493 });
|
|
2314
2474
|
try {
|
|
2315
|
-
|
|
2316
|
-
|
|
2475
|
+
execSync2(`claude mcp remove argus -s user 2>/dev/null || true`, { stdio: "ignore" });
|
|
2476
|
+
execSync2(`claude mcp add argus -s user -- "${wrapperPath}"`, { stdio: "inherit" });
|
|
2317
2477
|
console.log("\n\u2705 Argus MCP server installed for Claude Code!");
|
|
2318
2478
|
} catch {
|
|
2319
2479
|
console.log("\n\u26A0\uFE0F Could not automatically add to Claude Code.");
|
|
@@ -2345,7 +2505,7 @@ exec argus-mcp "$@"
|
|
|
2345
2505
|
});
|
|
2346
2506
|
mcpCommand.command("uninstall").description("Remove Argus from Claude Code").action(() => {
|
|
2347
2507
|
try {
|
|
2348
|
-
|
|
2508
|
+
execSync2("claude mcp remove argus -s user", { stdio: "inherit" });
|
|
2349
2509
|
console.log("\n\u2705 Argus MCP server removed from Claude Code.");
|
|
2350
2510
|
} catch {
|
|
2351
2511
|
console.log("\n\u26A0\uFE0F Could not remove from Claude Code.");
|
|
@@ -2354,7 +2514,7 @@ mcpCommand.command("uninstall").description("Remove Argus from Claude Code").act
|
|
|
2354
2514
|
}
|
|
2355
2515
|
});
|
|
2356
2516
|
var contextCommand = program.command("context").description("Generate architectural context for CLAUDE.md (survives compaction)");
|
|
2357
|
-
contextCommand.command("generate <path>").description("Generate architecture summary for a project").option("-o, --output <file>", "Output file (default: stdout)").option("-f, --format <format>", "Output format: markdown, json", "markdown").action(async (
|
|
2517
|
+
contextCommand.command("generate <path>").description("Generate architecture summary for a project").option("-o, --output <file>", "Output file (default: stdout)").option("-f, --format <format>", "Output format: markdown, json", "markdown").action(async (path3, opts) => {
|
|
2358
2518
|
const config = loadConfig();
|
|
2359
2519
|
const errors = validateConfig(config);
|
|
2360
2520
|
if (errors.length > 0) {
|
|
@@ -2362,7 +2522,7 @@ contextCommand.command("generate <path>").description("Generate architecture sum
|
|
|
2362
2522
|
errors.forEach((e) => console.error(` - ${e}`));
|
|
2363
2523
|
process.exit(1);
|
|
2364
2524
|
}
|
|
2365
|
-
const resolvedPath = resolve(
|
|
2525
|
+
const resolvedPath = resolve(path3);
|
|
2366
2526
|
if (!existsSync4(resolvedPath)) {
|
|
2367
2527
|
console.error(`Path not found: ${resolvedPath}`);
|
|
2368
2528
|
process.exit(1);
|
|
@@ -2410,7 +2570,7 @@ List with file paths and one-line descriptions.`;
|
|
|
2410
2570
|
}
|
|
2411
2571
|
});
|
|
2412
2572
|
console.error("\n");
|
|
2413
|
-
const projectName =
|
|
2573
|
+
const projectName = basename2(resolvedPath);
|
|
2414
2574
|
const output = generateContextMarkdown(projectName, {
|
|
2415
2575
|
modules: moduleResult.answer || "Unable to analyze modules",
|
|
2416
2576
|
patterns: patternResult.answer || "Unable to analyze patterns",
|
|
@@ -2430,13 +2590,13 @@ List with file paths and one-line descriptions.`;
|
|
|
2430
2590
|
}
|
|
2431
2591
|
}
|
|
2432
2592
|
});
|
|
2433
|
-
contextCommand.command("inject <path>").description("Add/update architecture section in CLAUDE.md").action(async (
|
|
2434
|
-
const resolvedPath = resolve(
|
|
2593
|
+
contextCommand.command("inject <path>").description("Add/update architecture section in CLAUDE.md").action(async (path3) => {
|
|
2594
|
+
const resolvedPath = resolve(path3);
|
|
2435
2595
|
const claudeMdPath = join4(resolvedPath, "CLAUDE.md");
|
|
2436
2596
|
console.error("Generating context...\n");
|
|
2437
|
-
const { execSync:
|
|
2597
|
+
const { execSync: execSync3 } = await import("child_process");
|
|
2438
2598
|
try {
|
|
2439
|
-
const contextOutput =
|
|
2599
|
+
const contextOutput = execSync3(
|
|
2440
2600
|
`argus context generate "${resolvedPath}"`,
|
|
2441
2601
|
{ encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
2442
2602
|
);
|
|
@@ -2466,10 +2626,10 @@ ${endMarker}`;
|
|
|
2466
2626
|
process.exit(1);
|
|
2467
2627
|
}
|
|
2468
2628
|
});
|
|
2469
|
-
contextCommand.command("refresh <path>").description("Regenerate architecture context (run after major changes)").action(async (
|
|
2470
|
-
const resolvedPath = resolve(
|
|
2629
|
+
contextCommand.command("refresh <path>").description("Regenerate architecture context (run after major changes)").action(async (path3) => {
|
|
2630
|
+
const resolvedPath = resolve(path3);
|
|
2471
2631
|
console.log("Refreshing codebase context...\n");
|
|
2472
|
-
|
|
2632
|
+
execSync2(`argus context inject "${resolvedPath}"`, { stdio: "inherit" });
|
|
2473
2633
|
});
|
|
2474
2634
|
function generateContextMarkdown(projectName, data) {
|
|
2475
2635
|
return `## Codebase Intelligence (Auto-generated by Argus)
|
|
@@ -2700,7 +2860,7 @@ program.command("setup [path]").description("Set up Argus for a project (snapsho
|
|
|
2700
2860
|
let projectConfig = onboardingConfig.projects[projectPath];
|
|
2701
2861
|
if (!projectConfig && opts.onboarding !== false) {
|
|
2702
2862
|
try {
|
|
2703
|
-
projectConfig = await runProjectOnboarding(projectPath, onboardingConfig, fs,
|
|
2863
|
+
projectConfig = await runProjectOnboarding(projectPath, onboardingConfig, fs, path2);
|
|
2704
2864
|
config.onboarding = config.onboarding || DEFAULT_ONBOARDING_CONFIG;
|
|
2705
2865
|
config.onboarding.projects[projectPath] = projectConfig;
|
|
2706
2866
|
saveConfig(config);
|
|
@@ -2710,7 +2870,7 @@ program.command("setup [path]").description("Set up Argus for a project (snapsho
|
|
|
2710
2870
|
}
|
|
2711
2871
|
} catch {
|
|
2712
2872
|
console.log("\n\u26A0\uFE0F Interactive selection skipped (non-interactive terminal)");
|
|
2713
|
-
const detected = detectPotentialKeyFiles(projectPath, onboardingConfig.globalKeyPatterns, fs,
|
|
2873
|
+
const detected = detectPotentialKeyFiles(projectPath, onboardingConfig.globalKeyPatterns, fs, path2);
|
|
2714
2874
|
projectConfig = {
|
|
2715
2875
|
keyFiles: detected.filter((d) => d.matchedPattern).map((d) => d.path),
|
|
2716
2876
|
customPatterns: [],
|
|
@@ -2797,5 +2957,81 @@ ${CLAUDE_MD_ARGUS_SECTION}`;
|
|
|
2797
2957
|
}
|
|
2798
2958
|
}
|
|
2799
2959
|
});
|
|
2960
|
+
program.command("ui").description("Open the Argus web UI for codebase visualization").option("-p, --port <port>", "Port to serve on", "3333").option("--no-open", "Do not open browser automatically").action(async (opts) => {
|
|
2961
|
+
const uiPath = join4(__dirname, "..", "packages", "ui");
|
|
2962
|
+
if (!existsSync4(join4(uiPath, "package.json"))) {
|
|
2963
|
+
console.error("Argus UI package not found.");
|
|
2964
|
+
console.error("\nThe UI package needs to be installed separately:");
|
|
2965
|
+
console.error(" cd packages/ui && npm install && npm run build");
|
|
2966
|
+
process.exit(1);
|
|
2967
|
+
}
|
|
2968
|
+
const distPath = join4(uiPath, "dist");
|
|
2969
|
+
const hasBuiltUI = existsSync4(distPath);
|
|
2970
|
+
console.log("Starting Argus UI...\n");
|
|
2971
|
+
try {
|
|
2972
|
+
if (hasBuiltUI) {
|
|
2973
|
+
console.log(` Serving built UI from ${distPath}`);
|
|
2974
|
+
console.log(` Open http://localhost:${opts.port} in your browser`);
|
|
2975
|
+
const http = await import("http");
|
|
2976
|
+
const mimeTypes = {
|
|
2977
|
+
".html": "text/html",
|
|
2978
|
+
".js": "text/javascript",
|
|
2979
|
+
".css": "text/css",
|
|
2980
|
+
".json": "application/json",
|
|
2981
|
+
".png": "image/png",
|
|
2982
|
+
".svg": "image/svg+xml"
|
|
2983
|
+
};
|
|
2984
|
+
const server = http.createServer((req, res) => {
|
|
2985
|
+
let filePath = join4(distPath, req.url === "/" ? "index.html" : req.url || "");
|
|
2986
|
+
if (!existsSync4(filePath) && !filePath.includes(".")) {
|
|
2987
|
+
filePath = join4(distPath, "index.html");
|
|
2988
|
+
}
|
|
2989
|
+
if (existsSync4(filePath)) {
|
|
2990
|
+
const ext = path2.extname(filePath);
|
|
2991
|
+
const contentType = mimeTypes[ext] || "application/octet-stream";
|
|
2992
|
+
const content = readFileSync5(filePath);
|
|
2993
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
2994
|
+
res.end(content);
|
|
2995
|
+
} else {
|
|
2996
|
+
res.writeHead(404);
|
|
2997
|
+
res.end("Not found");
|
|
2998
|
+
}
|
|
2999
|
+
});
|
|
3000
|
+
const port = parseInt(opts.port, 10);
|
|
3001
|
+
server.listen(port, () => {
|
|
3002
|
+
console.log(`
|
|
3003
|
+
Argus UI running at http://localhost:${port}`);
|
|
3004
|
+
if (opts.open !== false) {
|
|
3005
|
+
const { spawn } = __require("child_process");
|
|
3006
|
+
const openUrl = `http://localhost:${port}`;
|
|
3007
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
3008
|
+
spawn(openCmd, [openUrl], { detached: true, stdio: "ignore" }).unref();
|
|
3009
|
+
}
|
|
3010
|
+
});
|
|
3011
|
+
process.on("SIGINT", () => {
|
|
3012
|
+
console.log("\n\nShutting down Argus UI...");
|
|
3013
|
+
server.close();
|
|
3014
|
+
process.exit(0);
|
|
3015
|
+
});
|
|
3016
|
+
} else {
|
|
3017
|
+
console.log(` Running development server...`);
|
|
3018
|
+
console.log(` Port: ${opts.port}`);
|
|
3019
|
+
const { spawn } = __require("child_process");
|
|
3020
|
+
const vite = spawn("npm", ["run", "dev", "--", "--port", opts.port], {
|
|
3021
|
+
cwd: uiPath,
|
|
3022
|
+
stdio: "inherit"
|
|
3023
|
+
});
|
|
3024
|
+
process.on("SIGINT", () => {
|
|
3025
|
+
vite.kill();
|
|
3026
|
+
process.exit(0);
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
} catch (error) {
|
|
3030
|
+
console.error("Failed to start UI server:", error);
|
|
3031
|
+
console.error("\nTry building the UI first:");
|
|
3032
|
+
console.error(" cd packages/ui && npm install && npm run build");
|
|
3033
|
+
process.exit(1);
|
|
3034
|
+
}
|
|
3035
|
+
});
|
|
2800
3036
|
program.parse();
|
|
2801
3037
|
//# sourceMappingURL=cli.mjs.map
|