@sashabogi/argus-mcp 1.2.3 → 2.0.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/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, path2) {
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 = path2.basename(filePath).toLowerCase();
521
- const ext = path2.extname(filePath).toLowerCase();
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
- path2.join(dirPath, entry.name),
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
- path2.join(dirPath, entry.name),
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, path2) {
628
- const projectName = path2.basename(projectPath);
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, path2);
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 path from "path";
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
  }
@@ -1976,7 +2136,7 @@ function listProviderTypes() {
1976
2136
  // src/cli.ts
1977
2137
  init_onboarding();
1978
2138
  var program = new Command();
1979
- program.name("argus").description("Codebase Intelligence Beyond Context Limits").version("1.2.0");
2139
+ program.name("argus").description("Codebase Intelligence Beyond Context Limits").version("2.0.0");
1980
2140
  program.command("init").description("Interactive setup wizard").action(async () => {
1981
2141
  console.log("\n\u{1F52E} Argus Setup Wizard\n");
1982
2142
  console.log("This will configure your AI provider and create ~/.argus/config.json\n");
@@ -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
- execSync("npm install -g https://github.com/sashabogi/argus/tarball/main", { stdio: "inherit" });
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 (path2, query, opts) => {
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(path2);
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((path2, opts) => {
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(path2);
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 || `${basename(resolvedPath)}-snapshot.txt`;
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((path2, opts) => {
2200
- const projectPath = path2 ? resolve(path2) : process.cwd();
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
- execSync(`claude mcp remove argus -s user 2>/dev/null || true`, { stdio: "ignore" });
2316
- execSync(`claude mcp add argus -s user -- "${wrapperPath}"`, { stdio: "inherit" });
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
- execSync("claude mcp remove argus -s user", { stdio: "inherit" });
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 (path2, opts) => {
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(path2);
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 = basename(resolvedPath);
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 (path2) => {
2434
- const resolvedPath = resolve(path2);
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: execSync2 } = await import("child_process");
2597
+ const { execSync: execSync3 } = await import("child_process");
2438
2598
  try {
2439
- const contextOutput = execSync2(
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 (path2) => {
2470
- const resolvedPath = resolve(path2);
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
- execSync(`argus context inject "${resolvedPath}"`, { stdio: "inherit" });
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, path);
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, path);
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