@prosdevlab/dev-agent 0.10.2 → 0.10.4

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/mcp.js CHANGED
@@ -20005,6 +20005,35 @@ var init_vector = __esm({
20005
20005
  this.assertReady();
20006
20006
  return this.store.getAll(options);
20007
20007
  }
20008
+ /**
20009
+ * Get indexed documents grouped by file path.
20010
+ *
20011
+ * Uses getAll with a capped limit + client-side exact path filter.
20012
+ * More reliable than BM25 search which tokenizes paths unpredictably.
20013
+ *
20014
+ * Note: Fetches up to 5,000 docs client-side. Fine for single repos,
20015
+ * won't scale to monorepos with 50k+ files. See .claude/scratchpad.md.
20016
+ */
20017
+ async getDocsByFilePath(filePaths) {
20018
+ this.assertReady();
20019
+ const DOC_LIMIT = 5e3;
20020
+ const pathSet = new Set(filePaths);
20021
+ const allDocs = await this.getAll({ limit: DOC_LIMIT });
20022
+ if (allDocs.length >= DOC_LIMIT) {
20023
+ console.error(
20024
+ `[dev-agent] Warning: getDocsByFilePath hit ${DOC_LIMIT} doc limit. Some files may be missing.`
20025
+ );
20026
+ }
20027
+ const byFile = /* @__PURE__ */ new Map();
20028
+ for (const doc of allDocs) {
20029
+ const docPath = doc.metadata.path;
20030
+ if (pathSet.has(docPath)) {
20031
+ if (!byFile.has(docPath)) byFile.set(docPath, []);
20032
+ byFile.get(docPath).push(doc);
20033
+ }
20034
+ }
20035
+ return byFile;
20036
+ }
20008
20037
  /**
20009
20038
  * Get a document by ID
20010
20039
  */
@@ -38492,6 +38521,44 @@ var init_test_utils = __esm({
38492
38521
  });
38493
38522
 
38494
38523
  // ../core/src/services/pattern-analysis-service.ts
38524
+ function extractImportStyleFromContent(content3) {
38525
+ const esmImports = content3.match(/^import\s/gm) || [];
38526
+ const cjsImports = content3.match(/require\s*\(/g) || [];
38527
+ const hasESM = esmImports.length > 0;
38528
+ const hasCJS = cjsImports.length > 0;
38529
+ if (!hasESM && !hasCJS) return { style: "unknown", importCount: 0 };
38530
+ const importCount = esmImports.length + cjsImports.length;
38531
+ const style = hasESM && hasCJS ? "mixed" : hasESM ? "esm" : "cjs";
38532
+ return { style, importCount };
38533
+ }
38534
+ function extractErrorHandlingFromContent(content3) {
38535
+ const counts = {
38536
+ throw: [...content3.matchAll(/throw\s+new\s+\w*Error/g)].length,
38537
+ result: [...content3.matchAll(/Result<|{\s*ok:\s*(true|false)/g)].length,
38538
+ errorReturn: [...content3.matchAll(/\)\s*:\s*\([^)]*,\s*error\)/g)].length
38539
+ };
38540
+ const total = counts.throw + counts.result + counts.errorReturn;
38541
+ if (total === 0) return { style: "unknown", examples: [] };
38542
+ const max = Math.max(counts.throw, counts.result, counts.errorReturn);
38543
+ const hasMultiple = Object.values(counts).filter((c) => c > 0).length > 1;
38544
+ let style = "unknown";
38545
+ if (hasMultiple) style = "mixed";
38546
+ else if (counts.throw === max) style = "throw";
38547
+ else if (counts.result === max) style = "result";
38548
+ else if (counts.errorReturn === max) style = "error-return";
38549
+ return { style, examples: [] };
38550
+ }
38551
+ function extractTypeCoverageFromSignatures(signatures) {
38552
+ if (signatures.length === 0) return { coverage: "none", annotatedCount: 0, totalCount: 0 };
38553
+ const annotated = signatures.filter((sig) => /(\)|=>)\s*:\s*\w+/.test(sig));
38554
+ const ratio = annotated.length / signatures.length;
38555
+ let coverage;
38556
+ if (ratio >= 0.9) coverage = "full";
38557
+ else if (ratio >= 0.5) coverage = "partial";
38558
+ else if (ratio > 0) coverage = "minimal";
38559
+ else coverage = "none";
38560
+ return { coverage, annotatedCount: annotated.length, totalCount: signatures.length };
38561
+ }
38495
38562
  var fs9, path13, PatternAnalysisService;
38496
38563
  var init_pattern_analysis_service = __esm({
38497
38564
  "../core/src/services/pattern-analysis-service.ts"() {
@@ -38519,38 +38586,72 @@ var init_pattern_analysis_service = __esm({
38519
38586
  return this.analyzeFileWithDocs(filePath, documents);
38520
38587
  }
38521
38588
  /**
38522
- * Compare patterns between target file and similar files
38589
+ * Analyze file patterns using indexed metadata (fast no ts-morph).
38523
38590
  *
38524
- * OPTIMIZED: Batch scans all files in one pass to avoid repeated ts-morph initialization
38591
+ * Reads signatures from the Antfly index, content from disk (for line count
38592
+ * and error handling regex). Falls back gracefully on ENOENT (deleted file).
38593
+ */
38594
+ async analyzeFileFromIndex(filePath, indexedDocs) {
38595
+ const fullPath = path13.join(this.config.repositoryPath, filePath);
38596
+ let content3 = "";
38597
+ let bytes = 0;
38598
+ let lines = 0;
38599
+ try {
38600
+ const [fileContent, stat2] = await Promise.all([
38601
+ fs9.readFile(fullPath, "utf-8"),
38602
+ fs9.stat(fullPath)
38603
+ ]);
38604
+ content3 = fileContent;
38605
+ bytes = stat2.size;
38606
+ lines = content3.split("\n").length;
38607
+ } catch (error46) {
38608
+ if (error46.code !== "ENOENT") throw error46;
38609
+ }
38610
+ const testing = await this.analyzeTesting(filePath);
38611
+ const signatures = indexedDocs.filter((d) => d.metadata.type === "function" || d.metadata.type === "method").map((d) => d.metadata.signature || "").filter(Boolean);
38612
+ return {
38613
+ fileSize: { lines, bytes },
38614
+ testing,
38615
+ importStyle: extractImportStyleFromContent(content3),
38616
+ errorHandling: extractErrorHandlingFromContent(content3),
38617
+ typeAnnotations: extractTypeCoverageFromSignatures(signatures)
38618
+ };
38619
+ }
38620
+ /**
38621
+ * Compare patterns between target file and similar files
38525
38622
  *
38526
- * @param targetFile - Target file to analyze
38527
- * @param similarFiles - Array of similar file paths
38528
- * @returns Pattern comparison results
38623
+ * Uses Antfly index when vectorStorage is available (fast path, ~100ms).
38624
+ * Falls back to ts-morph scanning when not (tests, offline).
38529
38625
  */
38530
38626
  async comparePatterns(targetFile, similarFiles) {
38531
38627
  const allFiles = [targetFile, ...similarFiles];
38532
- const batchResult = await scanRepository({
38533
- repoRoot: this.config.repositoryPath,
38534
- include: allFiles
38535
- });
38536
- const docsByFile = /* @__PURE__ */ new Map();
38537
- for (const doc of batchResult.documents) {
38538
- const file2 = doc.metadata.file;
38539
- if (!docsByFile.has(file2)) {
38540
- docsByFile.set(file2, []);
38541
- }
38542
- const docs = docsByFile.get(file2);
38543
- if (docs) {
38544
- docs.push(doc);
38545
- }
38628
+ let targetPatterns;
38629
+ let similarPatterns;
38630
+ if (this.config.vectorStorage) {
38631
+ const docsByFile = await this.config.vectorStorage.getDocsByFilePath(allFiles);
38632
+ targetPatterns = await this.analyzeFileFromIndex(
38633
+ targetFile,
38634
+ docsByFile.get(targetFile) || []
38635
+ );
38636
+ similarPatterns = await Promise.all(
38637
+ similarFiles.map((f) => this.analyzeFileFromIndex(f, docsByFile.get(f) || []))
38638
+ );
38639
+ } else {
38640
+ const batchResult = await scanRepository({
38641
+ repoRoot: this.config.repositoryPath,
38642
+ include: allFiles
38643
+ });
38644
+ const docsByFile = /* @__PURE__ */ new Map();
38645
+ for (const doc of batchResult.documents) {
38646
+ const file2 = doc.metadata.file;
38647
+ if (!docsByFile.has(file2)) docsByFile.set(file2, []);
38648
+ docsByFile.get(file2).push(doc);
38649
+ }
38650
+ targetPatterns = await this.analyzeFileWithDocs(targetFile, docsByFile.get(targetFile) || []);
38651
+ similarPatterns = await Promise.all(
38652
+ similarFiles.map((f) => this.analyzeFileWithDocs(f, docsByFile.get(f) || []))
38653
+ );
38546
38654
  }
38547
- const targetPatterns = await this.analyzeFileWithDocs(
38548
- targetFile,
38549
- docsByFile.get(targetFile) || []
38550
- );
38551
- const similarPatterns = await Promise.all(
38552
- similarFiles.map((f) => this.analyzeFileWithDocs(f, docsByFile.get(f) || []))
38553
- );
38554
38655
  return {
38555
38656
  fileSize: this.compareFileSize(
38556
38657
  targetPatterns.fileSize,
@@ -38575,34 +38676,26 @@ var init_pattern_analysis_service = __esm({
38575
38676
  };
38576
38677
  }
38577
38678
  /**
38578
- * Analyze file patterns using pre-scanned documents (faster)
38579
- *
38580
- * @param filePath - Relative path from repository root
38581
- * @param documents - Pre-scanned documents for this file
38582
- * @returns Pattern analysis results
38679
+ * Analyze file patterns using pre-scanned documents (fallback path).
38583
38680
  */
38584
38681
  async analyzeFileWithDocs(filePath, documents) {
38585
38682
  const fullPath = path13.join(this.config.repositoryPath, filePath);
38586
- const [stat2, content3] = await Promise.all([fs9.stat(fullPath), fs9.readFile(fullPath, "utf-8")]);
38587
- const lines = content3.split("\n").length;
38683
+ const [content3, stat2, testing] = await Promise.all([
38684
+ fs9.readFile(fullPath, "utf-8"),
38685
+ fs9.stat(fullPath),
38686
+ this.analyzeTesting(filePath)
38687
+ ]);
38688
+ const signatures = documents.filter((d) => d.type === "function" || d.type === "method").map((d) => d.metadata.signature || "").filter(Boolean);
38588
38689
  return {
38589
- fileSize: {
38590
- lines,
38591
- bytes: stat2.size
38592
- },
38593
- testing: await this.analyzeTesting(filePath),
38594
- importStyle: await this.analyzeImportsFromFile(filePath, documents),
38595
- errorHandling: this.analyzeErrorHandling(content3),
38596
- typeAnnotations: this.analyzeTypes(documents)
38690
+ fileSize: { lines: content3.split("\n").length, bytes: stat2.size },
38691
+ testing,
38692
+ importStyle: extractImportStyleFromContent(content3),
38693
+ errorHandling: extractErrorHandlingFromContent(content3),
38694
+ typeAnnotations: extractTypeCoverageFromSignatures(signatures)
38597
38695
  };
38598
38696
  }
38599
- // ========================================================================
38600
- // Pattern Extractors (MVP: 5 core patterns)
38601
- // ========================================================================
38602
38697
  /**
38603
38698
  * Analyze test coverage for a file
38604
- *
38605
- * Checks for co-located test files (*.test.*, *.spec.*)
38606
38699
  */
38607
38700
  async analyzeTesting(filePath) {
38608
38701
  if (isTestFile(filePath)) {
@@ -38614,109 +38707,6 @@ var init_pattern_analysis_service = __esm({
38614
38707
  testPath: testFile || void 0
38615
38708
  };
38616
38709
  }
38617
- /**
38618
- * Analyze import style from documents
38619
- *
38620
- * Always uses content analysis for reliability (scanner may not extract imports from all files).
38621
- */
38622
- async analyzeImportsFromFile(filePath, _documents) {
38623
- const fullPath = path13.join(this.config.repositoryPath, filePath);
38624
- const content3 = await fs9.readFile(fullPath, "utf-8");
38625
- return this.analyzeImportsFromContent(content3);
38626
- }
38627
- /**
38628
- * Analyze imports from raw file content (fallback method)
38629
- */
38630
- analyzeImportsFromContent(content3) {
38631
- const esmImports = content3.match(/^import\s/gm) || [];
38632
- const cjsImports = content3.match(/require\s*\(/g) || [];
38633
- const hasESM = esmImports.length > 0;
38634
- const hasCJS = cjsImports.length > 0;
38635
- if (!hasESM && !hasCJS) {
38636
- return { style: "unknown", importCount: 0 };
38637
- }
38638
- const importCount = esmImports.length + cjsImports.length;
38639
- let style;
38640
- if (hasESM && hasCJS) {
38641
- style = "mixed";
38642
- } else if (hasESM) {
38643
- style = "esm";
38644
- } else {
38645
- style = "cjs";
38646
- }
38647
- return { style, importCount };
38648
- }
38649
- /**
38650
- * Analyze error handling patterns in file content
38651
- *
38652
- * Detects: throw, Result<T>, error returns (Go style)
38653
- */
38654
- analyzeErrorHandling(content3) {
38655
- const patterns = {
38656
- throw: /throw\s+new\s+\w*Error/g,
38657
- result: /Result<|{\s*ok:\s*(true|false)/g,
38658
- errorReturn: /\)\s*:\s*\([^)]*,\s*error\)/g
38659
- // Go: (val, error)
38660
- };
38661
- const matches = {
38662
- throw: [...content3.matchAll(patterns.throw)],
38663
- result: [...content3.matchAll(patterns.result)],
38664
- errorReturn: [...content3.matchAll(patterns.errorReturn)]
38665
- };
38666
- const counts = {
38667
- throw: matches.throw.length,
38668
- result: matches.result.length,
38669
- errorReturn: matches.errorReturn.length
38670
- };
38671
- const total = counts.throw + counts.result + counts.errorReturn;
38672
- if (total === 0) {
38673
- return { style: "unknown", examples: [] };
38674
- }
38675
- const max = Math.max(counts.throw, counts.result, counts.errorReturn);
38676
- const hasMultiple = Object.values(counts).filter((c) => c > 0).length > 1;
38677
- let style = "unknown";
38678
- if (hasMultiple) {
38679
- style = "mixed";
38680
- } else if (counts.throw === max) {
38681
- style = "throw";
38682
- } else if (counts.result === max) {
38683
- style = "result";
38684
- } else if (counts.errorReturn === max) {
38685
- style = "error-return";
38686
- }
38687
- return { style, examples: [] };
38688
- }
38689
- /**
38690
- * Analyze type annotation coverage from documents
38691
- *
38692
- * Checks function/method signatures for explicit types.
38693
- */
38694
- analyzeTypes(documents) {
38695
- const functions = documents.filter((d) => d.type === "function" || d.type === "method");
38696
- if (functions.length === 0) {
38697
- return { coverage: "none", annotatedCount: 0, totalCount: 0 };
38698
- }
38699
- const annotated = functions.filter((d) => {
38700
- const sig = d.metadata.signature || "";
38701
- return /(\)|=>)\s*:\s*\w+/.test(sig);
38702
- });
38703
- const coverage = annotated.length / functions.length;
38704
- let coverageLevel;
38705
- if (coverage >= 0.9) {
38706
- coverageLevel = "full";
38707
- } else if (coverage >= 0.5) {
38708
- coverageLevel = "partial";
38709
- } else if (coverage > 0) {
38710
- coverageLevel = "minimal";
38711
- } else {
38712
- coverageLevel = "none";
38713
- }
38714
- return {
38715
- coverage: coverageLevel,
38716
- annotatedCount: annotated.length,
38717
- totalCount: functions.length
38718
- };
38719
- }
38720
38710
  // ========================================================================
38721
38711
  // Pattern Comparisons
38722
38712
  // ========================================================================
@@ -54366,7 +54356,7 @@ var require_schemas3 = __commonJS({
54366
54356
  "../mcp-server/dist/src/schemas/index.js"(exports2) {
54367
54357
  "use strict";
54368
54358
  Object.defineProperty(exports2, "__esModule", { value: true });
54369
- exports2.InspectOutputSchema = exports2.RefsOutputSchema = exports2.RefResultSchema = exports2.MapOutputSchema = exports2.HealthOutputSchema = exports2.HealthCheckResultSchema = exports2.SearchOutputSchema = exports2.HealthArgsSchema = exports2.StatusOutputSchema = exports2.StatusArgsSchema = exports2.MapArgsSchema = exports2.RefsArgsSchema = exports2.SearchArgsSchema = exports2.InspectArgsSchema = exports2.BaseQuerySchema = exports2.FormatSchema = void 0;
54359
+ exports2.InspectOutputSchema = exports2.RefsOutputSchema = exports2.RefResultSchema = exports2.MapOutputSchema = exports2.SearchOutputSchema = exports2.StatusOutputSchema = exports2.StatusArgsSchema = exports2.MapArgsSchema = exports2.RefsArgsSchema = exports2.SearchArgsSchema = exports2.InspectArgsSchema = exports2.BaseQuerySchema = exports2.FormatSchema = void 0;
54370
54360
  var zod_1 = require_zod();
54371
54361
  exports2.FormatSchema = zod_1.z.enum(["compact", "verbose"]);
54372
54362
  exports2.BaseQuerySchema = zod_1.z.object({
@@ -54374,9 +54364,9 @@ var require_schemas3 = __commonJS({
54374
54364
  limit: zod_1.z.number().int().min(1).max(50).default(10)
54375
54365
  });
54376
54366
  exports2.InspectArgsSchema = zod_1.z.object({
54377
- query: zod_1.z.string().min(1, "Query must be a non-empty string (file path)"),
54367
+ filePath: zod_1.z.string().min(1, "filePath must be a non-empty file path"),
54378
54368
  limit: zod_1.z.number().int().min(1).max(50).default(10),
54379
- format: exports2.FormatSchema.default("compact")
54369
+ format: zod_1.z.enum(["compact", "verbose", "json"]).default("compact")
54380
54370
  }).strict();
54381
54371
  exports2.SearchArgsSchema = zod_1.z.object({
54382
54372
  query: zod_1.z.string().min(1, "Query must be a non-empty string"),
@@ -54407,31 +54397,11 @@ var require_schemas3 = __commonJS({
54407
54397
  format: zod_1.z.string(),
54408
54398
  length: zod_1.z.number()
54409
54399
  });
54410
- exports2.HealthArgsSchema = zod_1.z.object({
54411
- verbose: zod_1.z.boolean().default(false)
54412
- }).strict();
54413
54400
  exports2.SearchOutputSchema = zod_1.z.object({
54414
54401
  query: zod_1.z.string(),
54415
54402
  format: zod_1.z.string(),
54416
54403
  content: zod_1.z.string()
54417
54404
  });
54418
- exports2.HealthCheckResultSchema = zod_1.z.object({
54419
- status: zod_1.z.enum(["pass", "warn", "fail"]),
54420
- message: zod_1.z.string(),
54421
- details: zod_1.z.any().optional()
54422
- // Allow any type for details
54423
- });
54424
- exports2.HealthOutputSchema = zod_1.z.object({
54425
- status: zod_1.z.enum(["healthy", "degraded", "unhealthy"]),
54426
- uptime: zod_1.z.number(),
54427
- timestamp: zod_1.z.string(),
54428
- checks: zod_1.z.object({
54429
- vectorStorage: exports2.HealthCheckResultSchema,
54430
- repository: exports2.HealthCheckResultSchema,
54431
- githubIndex: exports2.HealthCheckResultSchema.optional()
54432
- }),
54433
- formattedReport: zod_1.z.string()
54434
- });
54435
54405
  exports2.MapOutputSchema = zod_1.z.object({
54436
54406
  content: zod_1.z.string(),
54437
54407
  totalComponents: zod_1.z.number(),
@@ -54689,302 +54659,6 @@ var require_validation = __commonJS({
54689
54659
  }
54690
54660
  });
54691
54661
 
54692
- // ../mcp-server/dist/src/adapters/built-in/health-adapter.js
54693
- var require_health_adapter = __commonJS({
54694
- "../mcp-server/dist/src/adapters/built-in/health-adapter.js"(exports2) {
54695
- "use strict";
54696
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
54697
- if (k2 === void 0) k2 = k;
54698
- var desc = Object.getOwnPropertyDescriptor(m, k);
54699
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
54700
- desc = { enumerable: true, get: function() {
54701
- return m[k];
54702
- } };
54703
- }
54704
- Object.defineProperty(o, k2, desc);
54705
- }) : (function(o, m, k, k2) {
54706
- if (k2 === void 0) k2 = k;
54707
- o[k2] = m[k];
54708
- }));
54709
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
54710
- Object.defineProperty(o, "default", { enumerable: true, value: v });
54711
- }) : function(o, v) {
54712
- o["default"] = v;
54713
- });
54714
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
54715
- var ownKeys = function(o) {
54716
- ownKeys = Object.getOwnPropertyNames || function(o2) {
54717
- var ar = [];
54718
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
54719
- return ar;
54720
- };
54721
- return ownKeys(o);
54722
- };
54723
- return function(mod) {
54724
- if (mod && mod.__esModule) return mod;
54725
- var result = {};
54726
- if (mod != null) {
54727
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54728
- }
54729
- __setModuleDefault(result, mod);
54730
- return result;
54731
- };
54732
- })();
54733
- Object.defineProperty(exports2, "__esModule", { value: true });
54734
- exports2.HealthAdapter = void 0;
54735
- var fs11 = __importStar(require("fs/promises"));
54736
- var index_js_1 = require_schemas3();
54737
- var tool_adapter_1 = require_tool_adapter();
54738
- var validation_js_1 = require_validation();
54739
- var HealthAdapter = class extends tool_adapter_1.ToolAdapter {
54740
- metadata = {
54741
- name: "health-adapter",
54742
- version: "1.0.0",
54743
- description: "Provides health and readiness checks for the MCP server"
54744
- };
54745
- config;
54746
- startTime;
54747
- constructor(config2) {
54748
- super();
54749
- this.config = config2;
54750
- this.startTime = Date.now();
54751
- }
54752
- async initialize(context) {
54753
- this.initializeBase(context);
54754
- }
54755
- async shutdown() {
54756
- }
54757
- getToolDefinition() {
54758
- return {
54759
- name: "dev_health",
54760
- description: "Check the health status of the dev-agent MCP server and its dependencies (vector storage, repository, GitHub index)",
54761
- inputSchema: {
54762
- type: "object",
54763
- properties: {
54764
- verbose: {
54765
- type: "boolean",
54766
- description: "Include detailed diagnostic information",
54767
- default: false
54768
- }
54769
- }
54770
- }
54771
- };
54772
- }
54773
- async execute(args, context) {
54774
- const validation = (0, validation_js_1.validateArgs)(index_js_1.HealthArgsSchema, args);
54775
- if (!validation.success) {
54776
- return validation.error;
54777
- }
54778
- const { verbose } = validation.data;
54779
- try {
54780
- const health = await this.performHealthChecks(verbose);
54781
- const status = this.getOverallStatus(health);
54782
- const emoji3 = status === "healthy" ? "\u2705" : status === "degraded" ? "\u26A0\uFE0F" : "\u274C";
54783
- const content3 = this.formatHealthReport(health, verbose);
54784
- return {
54785
- success: true,
54786
- data: `${emoji3} **MCP Server Health: ${status.toUpperCase()}**
54787
-
54788
- ${content3}`
54789
- };
54790
- } catch (error46) {
54791
- context.logger.error("Health check failed", {
54792
- error: error46 instanceof Error ? error46.message : String(error46)
54793
- });
54794
- return {
54795
- success: false,
54796
- error: {
54797
- code: "HEALTH_CHECK_ERROR",
54798
- message: error46 instanceof Error ? error46.message : "Health check failed",
54799
- recoverable: true
54800
- }
54801
- };
54802
- }
54803
- }
54804
- async performHealthChecks(verbose) {
54805
- const [vectorStorage, repository, githubIndex] = await Promise.all([
54806
- this.checkVectorStorage(verbose),
54807
- this.checkRepository(verbose),
54808
- this.config.githubStatePath ? this.checkGitHubIndex(verbose) : Promise.resolve(void 0)
54809
- ]);
54810
- const checks = {
54811
- vectorStorage,
54812
- repository
54813
- };
54814
- if (githubIndex) {
54815
- checks.githubIndex = githubIndex;
54816
- }
54817
- return {
54818
- status: this.getOverallStatus({ checks }),
54819
- checks,
54820
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
54821
- uptime: Date.now() - this.startTime
54822
- };
54823
- }
54824
- async checkVectorStorage(verbose) {
54825
- try {
54826
- const stats = await fs11.stat(this.config.vectorStorePath);
54827
- if (!stats.isDirectory()) {
54828
- return {
54829
- status: "fail",
54830
- message: "Vector storage path is not a directory"
54831
- };
54832
- }
54833
- const files = await fs11.readdir(this.config.vectorStorePath);
54834
- const hasData = files.length > 0;
54835
- if (!hasData) {
54836
- return {
54837
- status: "warn",
54838
- message: "Vector storage is empty (repository may not be indexed)",
54839
- details: verbose ? { path: this.config.vectorStorePath } : void 0
54840
- };
54841
- }
54842
- return {
54843
- status: "pass",
54844
- message: `Vector storage operational (${files.length} files)`,
54845
- details: verbose ? { path: this.config.vectorStorePath, fileCount: files.length } : void 0
54846
- };
54847
- } catch (error46) {
54848
- return {
54849
- status: "fail",
54850
- message: `Vector storage not accessible: ${error46 instanceof Error ? error46.message : String(error46)}`,
54851
- details: verbose ? { path: this.config.vectorStorePath } : void 0
54852
- };
54853
- }
54854
- }
54855
- async checkRepository(verbose) {
54856
- try {
54857
- const stats = await fs11.stat(this.config.repositoryPath);
54858
- if (!stats.isDirectory()) {
54859
- return {
54860
- status: "fail",
54861
- message: "Repository path is not a directory"
54862
- };
54863
- }
54864
- try {
54865
- await fs11.stat(`${this.config.repositoryPath}/.git`);
54866
- return {
54867
- status: "pass",
54868
- message: "Repository accessible and is a Git repository",
54869
- details: verbose ? { path: this.config.repositoryPath } : void 0
54870
- };
54871
- } catch {
54872
- return {
54873
- status: "warn",
54874
- message: "Repository accessible but not a Git repository",
54875
- details: verbose ? { path: this.config.repositoryPath } : void 0
54876
- };
54877
- }
54878
- } catch (error46) {
54879
- return {
54880
- status: "fail",
54881
- message: `Repository not accessible: ${error46 instanceof Error ? error46.message : String(error46)}`,
54882
- details: verbose ? { path: this.config.repositoryPath } : void 0
54883
- };
54884
- }
54885
- }
54886
- async checkGitHubIndex(verbose) {
54887
- if (!this.config.githubStatePath) {
54888
- return {
54889
- status: "warn",
54890
- message: "GitHub index not configured"
54891
- };
54892
- }
54893
- try {
54894
- const content3 = await fs11.readFile(this.config.githubStatePath, "utf-8");
54895
- const state = JSON.parse(content3);
54896
- const lastIndexed = state.lastIndexed ? new Date(state.lastIndexed) : null;
54897
- const itemCount = state.items?.length ?? 0;
54898
- if (!lastIndexed) {
54899
- return {
54900
- status: "warn",
54901
- message: "GitHub index exists but has no lastIndexed timestamp",
54902
- details: verbose ? { path: this.config.githubStatePath } : void 0
54903
- };
54904
- }
54905
- const ageMs = Date.now() - lastIndexed.getTime();
54906
- const ageHours = Math.floor(ageMs / (1e3 * 60 * 60));
54907
- if (ageHours > 24) {
54908
- return {
54909
- status: "warn",
54910
- message: `GitHub index is ${ageHours}h old (${itemCount} items) - consider re-indexing`,
54911
- details: verbose ? { path: this.config.githubStatePath, lastIndexed: lastIndexed.toISOString() } : void 0
54912
- };
54913
- }
54914
- return {
54915
- status: "pass",
54916
- message: `GitHub index operational (${itemCount} items, indexed ${ageHours}h ago)`,
54917
- details: verbose ? { path: this.config.githubStatePath, lastIndexed: lastIndexed.toISOString() } : void 0
54918
- };
54919
- } catch (error46) {
54920
- return {
54921
- status: "warn",
54922
- message: `GitHub index not accessible: ${error46 instanceof Error ? error46.message : String(error46)}`,
54923
- details: verbose ? { path: this.config.githubStatePath } : void 0
54924
- };
54925
- }
54926
- }
54927
- getOverallStatus(health) {
54928
- const checks = Object.values(health.checks).filter((check2) => check2 !== void 0);
54929
- const hasFail = checks.some((check2) => check2.status === "fail");
54930
- const hasWarn = checks.some((check2) => check2.status === "warn");
54931
- if (hasFail) {
54932
- return "unhealthy";
54933
- }
54934
- if (hasWarn) {
54935
- return "degraded";
54936
- }
54937
- return "healthy";
54938
- }
54939
- formatHealthReport(health, verbose) {
54940
- const lines = [];
54941
- const uptimeMs = health.uptime;
54942
- const uptimeStr = this.formatUptime(uptimeMs);
54943
- lines.push(`**Uptime:** ${uptimeStr}`);
54944
- lines.push(`**Timestamp:** ${new Date(health.timestamp).toLocaleString()}`);
54945
- lines.push("");
54946
- lines.push("**Component Status:**");
54947
- lines.push("");
54948
- for (const [name, check2] of Object.entries(health.checks)) {
54949
- if (!check2)
54950
- continue;
54951
- const statusEmoji = check2.status === "pass" ? "\u2705" : check2.status === "warn" ? "\u26A0\uFE0F" : "\u274C";
54952
- const componentName = this.formatComponentName(name);
54953
- lines.push(`${statusEmoji} **${componentName}:** ${check2.message}`);
54954
- if (verbose && check2.details) {
54955
- lines.push(` *Details:* ${JSON.stringify(check2.details)}`);
54956
- }
54957
- }
54958
- return lines.join("\n");
54959
- }
54960
- formatComponentName(name) {
54961
- return name.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
54962
- }
54963
- formatUptime(ms) {
54964
- const seconds = Math.floor(ms / 1e3);
54965
- const minutes = Math.floor(seconds / 60);
54966
- const hours = Math.floor(minutes / 60);
54967
- const days = Math.floor(hours / 24);
54968
- if (days > 0) {
54969
- return `${days}d ${hours % 24}h ${minutes % 60}m`;
54970
- }
54971
- if (hours > 0) {
54972
- return `${hours}h ${minutes % 60}m`;
54973
- }
54974
- if (minutes > 0) {
54975
- return `${minutes}m ${seconds % 60}s`;
54976
- }
54977
- return `${seconds}s`;
54978
- }
54979
- async healthCheck() {
54980
- const health = await this.performHealthChecks(false);
54981
- return health.status === "healthy";
54982
- }
54983
- };
54984
- exports2.HealthAdapter = HealthAdapter;
54985
- }
54986
- });
54987
-
54988
54662
  // ../mcp-server/dist/src/adapters/built-in/inspect-adapter.js
54989
54663
  var require_inspect_adapter = __commonJS({
54990
54664
  "../mcp-server/dist/src/adapters/built-in/inspect-adapter.js"(exports2) {
@@ -55012,7 +54686,8 @@ var require_inspect_adapter = __commonJS({
55012
54686
  this.repositoryPath = config2.repositoryPath;
55013
54687
  this.searchService = config2.searchService;
55014
54688
  this.patternService = new dev_agent_core_12.PatternAnalysisService({
55015
- repositoryPath: config2.repositoryPath
54689
+ repositoryPath: config2.repositoryPath,
54690
+ vectorStorage: config2.vectorStorage
55016
54691
  });
55017
54692
  this.defaultLimit = config2.defaultLimit ?? 10;
55018
54693
  this.defaultThreshold = config2.defaultThreshold ?? 0.7;
@@ -55031,11 +54706,11 @@ var require_inspect_adapter = __commonJS({
55031
54706
  getToolDefinition() {
55032
54707
  return {
55033
54708
  name: "dev_patterns",
55034
- description: "Analyze coding patterns in a file against the codebase. Compares import style, error handling, type coverage, test coverage, and file size against similar files. Use for code reviews and consistency checks.",
54709
+ description: "Analyze coding patterns in a file against similar code in the codebase. Compares import style, error handling, type coverage, test coverage, and file size. Use for code reviews and consistency checks. NOT for finding code (use dev_search) or tracing calls (use dev_refs).",
55035
54710
  inputSchema: {
55036
54711
  type: "object",
55037
54712
  properties: {
55038
- query: {
54713
+ filePath: {
55039
54714
  type: "string",
55040
54715
  description: 'File path to analyze (e.g., "src/auth/middleware.ts")'
55041
54716
  },
@@ -55048,12 +54723,12 @@ var require_inspect_adapter = __commonJS({
55048
54723
  },
55049
54724
  format: {
55050
54725
  type: "string",
55051
- enum: ["compact", "verbose"],
55052
- description: 'Output format: "compact" for summaries (default), "verbose" for full details',
54726
+ enum: ["compact", "verbose", "json"],
54727
+ description: 'Output format: "compact" (default), "verbose" for details, "json" for structured data',
55053
54728
  default: this.defaultFormat
55054
54729
  }
55055
54730
  },
55056
- required: ["query"]
54731
+ required: ["filePath"]
55057
54732
  }
55058
54733
  };
55059
54734
  }
@@ -55062,34 +54737,42 @@ var require_inspect_adapter = __commonJS({
55062
54737
  if (!validation.success) {
55063
54738
  return validation.error;
55064
54739
  }
55065
- const { query, limit, format } = validation.data;
54740
+ const { filePath, limit, format } = validation.data;
55066
54741
  try {
55067
54742
  context.logger.debug("Executing pattern analysis", {
55068
- query,
54743
+ filePath,
55069
54744
  limit,
55070
54745
  format
55071
54746
  });
55072
- const { content: content3, similarFilesCount, patternsAnalyzed } = await this.inspectFile(
55073
- query,
55074
- limit,
55075
- 0,
55076
- // No threshold — let the pattern service decide relevance
55077
- format
55078
- );
54747
+ const { content: content3, similarFilesCount, patternsAnalyzed, patternComparison } = await this.inspectFile(filePath, limit, 0, format);
55079
54748
  context.logger.info("File inspection completed", {
55080
- query,
54749
+ filePath,
55081
54750
  similarFilesCount,
55082
54751
  patternsAnalyzed,
55083
54752
  contentLength: content3.length
55084
54753
  });
54754
+ if (format === "json" && patternComparison) {
54755
+ const jsonData = JSON.stringify(patternComparison, null, 2);
54756
+ return {
54757
+ success: true,
54758
+ data: jsonData,
54759
+ metadata: {
54760
+ tokens: jsonData.length / 4,
54761
+ duration_ms: 0,
54762
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
54763
+ cached: false,
54764
+ similar_files_count: similarFilesCount,
54765
+ patterns_analyzed: patternsAnalyzed,
54766
+ format: "json"
54767
+ }
54768
+ };
54769
+ }
55085
54770
  return {
55086
54771
  success: true,
55087
54772
  data: content3,
55088
54773
  metadata: {
55089
54774
  tokens: content3.length / 4,
55090
- // Rough estimate
55091
54775
  duration_ms: 0,
55092
- // Calculated by MCP server
55093
54776
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
55094
54777
  cached: false,
55095
54778
  similar_files_count: similarFilesCount,
@@ -55105,7 +54788,7 @@ var require_inspect_adapter = __commonJS({
55105
54788
  success: false,
55106
54789
  error: {
55107
54790
  code: "FILE_NOT_FOUND",
55108
- message: `File not found: ${query}`,
54791
+ message: `File not found: ${filePath}`,
55109
54792
  suggestion: "Check the file path and ensure it exists in the repository."
55110
54793
  }
55111
54794
  };
@@ -55125,7 +54808,8 @@ var require_inspect_adapter = __commonJS({
55125
54808
  success: false,
55126
54809
  error: {
55127
54810
  code: "INSPECTION_ERROR",
55128
- message: error46 instanceof Error ? error46.message : "Unknown inspection error"
54811
+ message: error46 instanceof Error ? error46.message : "Unknown inspection error",
54812
+ suggestion: "Check the file path is valid and the repository is indexed."
55129
54813
  }
55130
54814
  };
55131
54815
  }
@@ -55161,12 +54845,12 @@ var require_inspect_adapter = __commonJS({
55161
54845
  }
55162
54846
  const similarFilePaths = filteredResults.map((r) => r.metadata.path);
55163
54847
  const patternComparison = await this.patternService.comparePatterns(filePath, similarFilePaths);
55164
- const content3 = format === "verbose" ? await this.formatInspectionVerbose(filePath, filteredResults, patternComparison) : await this.formatInspectionCompact(filePath, filteredResults, patternComparison);
54848
+ const content3 = format === "json" ? "" : format === "verbose" ? await this.formatInspectionVerbose(filePath, filteredResults, patternComparison) : await this.formatInspectionCompact(filePath, filteredResults, patternComparison);
55165
54849
  return {
55166
54850
  content: content3,
55167
54851
  similarFilesCount: filteredResults.length,
55168
- patternsAnalyzed: 5
55169
- // Currently analyzing 5 pattern categories
54852
+ patternsAnalyzed: 5,
54853
+ patternComparison
55170
54854
  };
55171
54855
  }
55172
54856
  /**
@@ -55491,7 +55175,7 @@ var require_map_adapter = __commonJS({
55491
55175
  error: {
55492
55176
  code: "MAP_FAILED",
55493
55177
  message: error46 instanceof Error ? error46.message : "Unknown error",
55494
- details: error46
55178
+ suggestion: 'Run "dev index" first. Try a lower depth if the map is too large.'
55495
55179
  }
55496
55180
  };
55497
55181
  }
@@ -55584,7 +55268,8 @@ var require_refs_adapter = __commonJS({
55584
55268
  success: false,
55585
55269
  error: {
55586
55270
  code: "NOT_FOUND",
55587
- message: `Could not find function or method named "${name}"`
55271
+ message: `Could not find function or method named "${name}"`,
55272
+ suggestion: "Verify the function name exists with dev_search first. Names are case-sensitive."
55588
55273
  }
55589
55274
  };
55590
55275
  }
@@ -55629,7 +55314,7 @@ var require_refs_adapter = __commonJS({
55629
55314
  error: {
55630
55315
  code: "REFS_FAILED",
55631
55316
  message: error46 instanceof Error ? error46.message : "Unknown error",
55632
- details: error46
55317
+ suggestion: "Try dev_search to find the correct function name first."
55633
55318
  }
55634
55319
  };
55635
55320
  }
@@ -56383,7 +56068,7 @@ var require_search_adapter = __commonJS({
56383
56068
  error: {
56384
56069
  code: "SEARCH_FAILED",
56385
56070
  message: error46 instanceof Error ? error46.message : "Unknown error",
56386
- details: error46
56071
+ suggestion: 'Run "dev index" to index the repository. Try a different query if no results.'
56387
56072
  }
56388
56073
  };
56389
56074
  }
@@ -56524,7 +56209,7 @@ var require_status_adapter = __commonJS({
56524
56209
  error: {
56525
56210
  code: "STATUS_FAILED",
56526
56211
  message: error46 instanceof Error ? error46.message : "Unknown error",
56527
- details: error46
56212
+ suggestion: 'Run "dev setup" to ensure Antfly is running, then "dev index" to index.'
56528
56213
  }
56529
56214
  };
56530
56215
  }
@@ -56725,11 +56410,7 @@ var require_built_in = __commonJS({
56725
56410
  "../mcp-server/dist/src/adapters/built-in/index.js"(exports2) {
56726
56411
  "use strict";
56727
56412
  Object.defineProperty(exports2, "__esModule", { value: true });
56728
- exports2.StatusAdapter = exports2.SearchAdapter = exports2.RefsAdapter = exports2.MapAdapter = exports2.InspectAdapter = exports2.HealthAdapter = void 0;
56729
- var health_adapter_js_1 = require_health_adapter();
56730
- Object.defineProperty(exports2, "HealthAdapter", { enumerable: true, get: function() {
56731
- return health_adapter_js_1.HealthAdapter;
56732
- } });
56413
+ exports2.StatusAdapter = exports2.SearchAdapter = exports2.RefsAdapter = exports2.MapAdapter = exports2.InspectAdapter = void 0;
56733
56414
  var inspect_adapter_js_1 = require_inspect_adapter();
56734
56415
  Object.defineProperty(exports2, "InspectAdapter", { enumerable: true, get: function() {
56735
56416
  return inspect_adapter_js_1.InspectAdapter;
@@ -58403,14 +58084,11 @@ async function main() {
58403
58084
  const inspectAdapter = new built_in_1.InspectAdapter({
58404
58085
  repositoryPath,
58405
58086
  searchService,
58087
+ vectorStorage: indexer.getVectorStorage(),
58406
58088
  defaultLimit: 10,
58407
58089
  defaultThreshold: 0.7,
58408
58090
  defaultFormat: "compact"
58409
58091
  });
58410
- const healthAdapter = new built_in_1.HealthAdapter({
58411
- repositoryPath,
58412
- vectorStorePath: filePaths.vectors
58413
- });
58414
58092
  const refsAdapter = new built_in_1.RefsAdapter({
58415
58093
  searchService,
58416
58094
  defaultLimit: 20
@@ -58431,14 +58109,7 @@ async function main() {
58431
58109
  logLevel
58432
58110
  },
58433
58111
  transport: "stdio",
58434
- adapters: [
58435
- searchAdapter,
58436
- statusAdapter,
58437
- inspectAdapter,
58438
- healthAdapter,
58439
- refsAdapter,
58440
- mapAdapter
58441
- ]
58112
+ adapters: [searchAdapter, statusAdapter, inspectAdapter, refsAdapter, mapAdapter]
58442
58113
  });
58443
58114
  await server.start();
58444
58115
  const incrementalIndexer = (0, watcher_1.createIncrementalIndexer)({