@aiready/core 0.23.1 → 0.23.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/__tests__/parser-factory.test.d.ts +1 -1
  2. package/dist/__tests__/parser-factory.test.js +62 -50
  3. package/dist/__tests__/python-parser.test.d.ts +1 -1
  4. package/dist/__tests__/python-parser.test.js +111 -109
  5. package/dist/__tests__/scoring.test.d.ts +1 -1
  6. package/dist/__tests__/scoring.test.js +193 -176
  7. package/dist/chunk-3YI4IS3D.mjs +191 -173
  8. package/dist/chunk-5HIXDC3X.mjs +273 -251
  9. package/dist/chunk-5V3L53AE.mjs +805 -0
  10. package/dist/chunk-CKVKHN3G.mjs +228 -211
  11. package/dist/chunk-COHIBX3Q.mjs +213 -195
  12. package/dist/chunk-CWRCDSKZ.mjs +91 -82
  13. package/dist/chunk-D3D3NCRR.mjs +147 -129
  14. package/dist/chunk-HCFYP7UD.mjs +805 -0
  15. package/dist/chunk-HFLFBA6F.mjs +79 -72
  16. package/dist/chunk-HKSARRCD.mjs +66 -58
  17. package/dist/chunk-JJ5JL5FX.mjs +91 -82
  18. package/dist/chunk-KDSTXVLQ.mjs +724 -0
  19. package/dist/chunk-KI7XORTN.mjs +91 -82
  20. package/dist/chunk-LTMHFNFK.mjs +690 -0
  21. package/dist/chunk-LTNXTXRI.mjs +228 -211
  22. package/dist/chunk-M22BXHBR.mjs +805 -0
  23. package/dist/chunk-MH3A3LX6.mjs +200 -182
  24. package/dist/chunk-NGHT7JOG.mjs +697 -0
  25. package/dist/chunk-OQ6IGDXG.mjs +147 -129
  26. package/dist/chunk-QAFB3HXQ.mjs +181 -165
  27. package/dist/chunk-QQBKXHLU.mjs +678 -0
  28. package/dist/chunk-RDHYGES7.mjs +678 -0
  29. package/dist/chunk-SWTDBVYJ.mjs +228 -213
  30. package/dist/chunk-UIWL5JQB.mjs +79 -72
  31. package/dist/chunk-UQGI67WR.mjs +79 -72
  32. package/dist/chunk-UTZOO4XO.mjs +147 -131
  33. package/dist/chunk-X4F46I5L.mjs +213 -195
  34. package/dist/chunk-XKK7YHPX.mjs +204 -186
  35. package/dist/chunk-YCA4FTEK.mjs +190 -172
  36. package/dist/chunk-ZSZRRTJM.mjs +719 -0
  37. package/dist/client-BgmiMoil.d.mts +1344 -0
  38. package/dist/client-BgmiMoil.d.ts +1344 -0
  39. package/dist/client-BxGrPuuN.d.mts +1191 -0
  40. package/dist/client-BxGrPuuN.d.ts +1191 -0
  41. package/dist/client-D-cn9ydj.d.mts +1136 -0
  42. package/dist/client-D-cn9ydj.d.ts +1136 -0
  43. package/dist/client-D9seCH4K.d.mts +1334 -0
  44. package/dist/client-D9seCH4K.d.ts +1334 -0
  45. package/dist/client-DIXIh7rw.d.mts +1193 -0
  46. package/dist/client-DIXIh7rw.d.ts +1193 -0
  47. package/dist/client-DVHXWOHw.d.mts +1245 -0
  48. package/dist/client-DVHXWOHw.d.ts +1245 -0
  49. package/dist/client.d.mts +2 -1094
  50. package/dist/client.d.ts +2 -1094
  51. package/dist/client.js +23 -43
  52. package/dist/client.mjs +3 -25
  53. package/dist/index.d.mts +380 -108
  54. package/dist/index.d.ts +380 -108
  55. package/dist/index.js +609 -445
  56. package/dist/index.mjs +587 -429
  57. package/dist/parsers/parser-factory.d.ts +45 -45
  58. package/dist/parsers/parser-factory.js +86 -84
  59. package/dist/parsers/python-parser.d.ts +33 -28
  60. package/dist/parsers/python-parser.js +224 -222
  61. package/dist/parsers/typescript-parser.d.ts +15 -10
  62. package/dist/parsers/typescript-parser.js +223 -197
  63. package/dist/scoring.d.ts +59 -49
  64. package/dist/scoring.js +129 -127
  65. package/dist/types/language.d.ts +104 -93
  66. package/dist/types/language.js +23 -23
  67. package/dist/types.d.ts +105 -87
  68. package/dist/types.js +1 -1
  69. package/dist/utils/ast-parser.d.ts +42 -33
  70. package/dist/utils/ast-parser.js +159 -162
  71. package/dist/utils/cli-helpers.d.ts +27 -10
  72. package/dist/utils/cli-helpers.js +45 -43
  73. package/dist/utils/config.d.ts +8 -3
  74. package/dist/utils/config.js +67 -69
  75. package/dist/utils/file-scanner.d.ts +1 -1
  76. package/dist/utils/file-scanner.js +80 -76
  77. package/dist/utils/metrics.d.ts +1 -1
  78. package/dist/utils/metrics.js +2 -2
  79. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -74,6 +74,8 @@ __export(index_exports, {
74
74
  TypeScriptParser: () => TypeScriptParser,
75
75
  UnifiedReportSchema: () => UnifiedReportSchema,
76
76
  VAGUE_FILE_NAMES: () => VAGUE_FILE_NAMES,
77
+ buildSimpleProviderScore: () => buildSimpleProviderScore,
78
+ buildSpokeOutput: () => buildSpokeOutput,
77
79
  calculateAgentGrounding: () => calculateAgentGrounding,
78
80
  calculateAiSignalClarity: () => calculateAiSignalClarity,
79
81
  calculateBusinessROI: () => calculateBusinessROI,
@@ -97,6 +99,7 @@ __export(index_exports, {
97
99
  calculateTestabilityIndex: () => calculateTestabilityIndex,
98
100
  calculateTokenBudget: () => calculateTokenBudget,
99
101
  clearHistory: () => clearHistory,
102
+ createProvider: () => createProvider,
100
103
  emitAnnotation: () => emitAnnotation,
101
104
  emitIssuesAsAnnotations: () => emitIssuesAsAnnotations,
102
105
  emitProgress: () => emitProgress,
@@ -105,6 +108,8 @@ __export(index_exports, {
105
108
  exportHistory: () => exportHistory,
106
109
  extractFunctions: () => extractFunctions,
107
110
  extractImports: () => extractImports,
111
+ findLatestReport: () => findLatestReport,
112
+ findLatestScanReport: () => findLatestScanReport,
108
113
  formatAcceptanceRate: () => formatAcceptanceRate,
109
114
  formatCost: () => formatCost,
110
115
  formatHours: () => formatHours,
@@ -122,15 +127,21 @@ __export(index_exports, {
122
127
  getProjectSizeTier: () => getProjectSizeTier,
123
128
  getRating: () => getRating,
124
129
  getRatingDisplay: () => getRatingDisplay,
130
+ getRatingSlug: () => getRatingSlug,
125
131
  getRatingWithContext: () => getRatingWithContext,
126
132
  getRecommendedThreshold: () => getRecommendedThreshold,
127
133
  getRepoMetadata: () => getRepoMetadata,
128
134
  getSafetyIcon: () => getSafetyIcon,
129
135
  getScoreBar: () => getScoreBar,
136
+ getSeverityBadge: () => getSeverityBadge,
130
137
  getSeverityColor: () => getSeverityColor,
138
+ getSeverityEnum: () => getSeverityEnum,
139
+ getSeverityLevel: () => getSeverityLevel,
140
+ getSeverityValue: () => getSeverityValue,
131
141
  getSupportedLanguages: () => getSupportedLanguages,
132
142
  getToolWeight: () => getToolWeight,
133
143
  getWasmPath: () => getWasmPath,
144
+ groupIssuesByFile: () => groupIssuesByFile,
134
145
  handleCLIError: () => handleCLIError,
135
146
  handleJSONOutput: () => handleJSONOutput,
136
147
  initTreeSitter: () => initTreeSitter,
@@ -322,33 +333,28 @@ var UnifiedReportSchema = import_zod.z.object({
322
333
  // src/types.ts
323
334
  var GLOBAL_INFRA_OPTIONS = [
324
335
  "rootDir",
325
- // Essential for every tool
326
336
  "include",
327
337
  "exclude",
328
- "onProgress",
329
- "progressCallback",
330
- "includeTests",
331
- "useSmartDefaults",
332
- "streamResults",
333
- "batchSize",
334
- "costConfig",
335
338
  "tools",
336
- "toolConfigs"
339
+ "scoring"
340
+ ];
341
+ var GLOBAL_SCAN_OPTIONS = [
342
+ "rootDir",
343
+ "include",
344
+ "exclude",
345
+ "config",
346
+ "threshold",
347
+ "output",
348
+ "format",
349
+ "parallel",
350
+ "showBreakdown"
337
351
  ];
338
352
  var COMMON_FINE_TUNING_OPTIONS = [
339
353
  "maxDepth",
340
354
  "minSimilarity",
341
- "minLines",
342
- "minCohesion",
343
- // AI Signal Clarity options
344
- "checkMagicLiterals",
345
- "checkBooleanTraps",
346
- "checkAmbiguousNames",
347
- "checkUndocumentedExports",
348
- "checkImplicitSideEffects",
349
- "checkDeepCallbacks"
355
+ "threshold",
356
+ "showBreakdown"
350
357
  ];
351
- var GLOBAL_SCAN_OPTIONS = [...GLOBAL_INFRA_OPTIONS];
352
358
 
353
359
  // src/types/language.ts
354
360
  var Language = /* @__PURE__ */ ((Language3) => {
@@ -777,6 +783,7 @@ function isSourceFile(filePath) {
777
783
  // src/utils/cli-helpers.ts
778
784
  var import_fs2 = require("fs");
779
785
  var import_path2 = require("path");
786
+ var import_chalk = __toESM(require("chalk"));
780
787
  function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()) {
781
788
  let outputPath;
782
789
  if (userPath) {
@@ -844,25 +851,180 @@ function emitProgress(processed, total, toolId, message, onProgress, throttleCou
844
851
  onProgress(processed, total, `${message} (${processed}/${total})`);
845
852
  }
846
853
  }
847
- function getSeverityColor(severity, chalk) {
854
+ function getSeverityColor(severity, chalkInstance = import_chalk.default) {
848
855
  switch (severity.toLowerCase()) {
849
856
  case "critical":
850
857
  case "high-risk":
851
858
  case "blind-risk":
852
- return chalk.red;
859
+ return chalkInstance.red;
853
860
  case "major":
854
861
  case "moderate-risk":
855
- return chalk.yellow;
862
+ return chalkInstance.yellow;
856
863
  case "minor":
857
864
  case "safe":
858
- return chalk.green;
865
+ return chalkInstance.green;
866
+ case "info":
867
+ return chalkInstance.blue;
868
+ default:
869
+ return chalkInstance.white;
870
+ }
871
+ }
872
+ function getSeverityValue(s) {
873
+ if (!s) return 0;
874
+ switch (s.toLowerCase()) {
875
+ case "critical":
876
+ return 4;
877
+ case "major":
878
+ return 3;
879
+ case "minor":
880
+ return 2;
859
881
  case "info":
860
- return chalk.blue;
882
+ return 1;
883
+ default:
884
+ return 0;
885
+ }
886
+ }
887
+ function getSeverityLevel(s) {
888
+ return getSeverityValue(s);
889
+ }
890
+ function getSeverityBadge(severity, chalkInstance = import_chalk.default) {
891
+ const val = getSeverityValue(
892
+ typeof severity === "string" ? severity : severity
893
+ );
894
+ switch (val) {
895
+ case 4:
896
+ return chalkInstance.bgRed.white.bold(" CRITICAL ");
897
+ case 3:
898
+ return chalkInstance.bgYellow.black.bold(" MAJOR ");
899
+ case 2:
900
+ return chalkInstance.bgBlue.white.bold(" MINOR ");
901
+ case 1:
902
+ return chalkInstance.bgCyan.black(" INFO ");
861
903
  default:
862
- return chalk.white;
904
+ return chalkInstance.bgCyan.black(" INFO ");
905
+ }
906
+ }
907
+ function getSeverityEnum(s) {
908
+ const level = getSeverityLevel(s);
909
+ switch (level) {
910
+ case 4:
911
+ return "critical";
912
+ case 3:
913
+ return "major";
914
+ case 2:
915
+ return "minor";
916
+ case 1:
917
+ return "info";
918
+ default:
919
+ return "info";
920
+ }
921
+ }
922
+ function findLatestReport(dirPath) {
923
+ const aireadyDir = (0, import_path2.resolve)(dirPath, ".aiready");
924
+ if (!(0, import_fs2.existsSync)(aireadyDir)) {
925
+ return null;
926
+ }
927
+ let files = (0, import_fs2.readdirSync)(aireadyDir).filter(
928
+ (f) => f.startsWith("aiready-report-") && f.endsWith(".json")
929
+ );
930
+ if (files.length === 0) {
931
+ files = (0, import_fs2.readdirSync)(aireadyDir).filter(
932
+ (f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
933
+ );
934
+ }
935
+ if (files.length === 0) {
936
+ return null;
937
+ }
938
+ const sortedFiles = files.map((f) => ({
939
+ name: f,
940
+ path: (0, import_path2.resolve)(aireadyDir, f),
941
+ mtime: (0, import_fs2.statSync)((0, import_path2.resolve)(aireadyDir, f)).mtime
942
+ })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
943
+ return sortedFiles[0].path;
944
+ }
945
+ function findLatestScanReport(scanReportsDir, reportFilePrefix) {
946
+ try {
947
+ let reportFiles = [];
948
+ if ((0, import_fs2.existsSync)(scanReportsDir)) {
949
+ const files = (0, import_fs2.readdirSync)(scanReportsDir);
950
+ if (files.length > 0) {
951
+ const prefixRegex = new RegExp(`^${reportFilePrefix}\\d+\\.json$`);
952
+ reportFiles = files.filter((file) => prefixRegex.test(file));
953
+ }
954
+ }
955
+ if (reportFiles.length === 0) return null;
956
+ reportFiles.sort((a, b) => {
957
+ const idA = parseInt(a.match(/\d+/)?.[0] || "0", 10);
958
+ const idB = parseInt(b.match(/\d+/)?.[0] || "0", 10);
959
+ return idB - idA;
960
+ });
961
+ return (0, import_path2.join)(scanReportsDir, reportFiles[0]);
962
+ } catch (e) {
963
+ console.error("Error while finding latest scan report:", e);
964
+ return null;
863
965
  }
864
966
  }
865
967
 
968
+ // src/utils/provider-utils.ts
969
+ function groupIssuesByFile(issues) {
970
+ const fileIssuesMap = /* @__PURE__ */ new Map();
971
+ for (const issue of issues) {
972
+ const file = issue.location?.file ?? "unknown";
973
+ if (!fileIssuesMap.has(file)) fileIssuesMap.set(file, []);
974
+ fileIssuesMap.get(file).push(issue);
975
+ }
976
+ return Array.from(fileIssuesMap.entries()).map(([fileName, issueList]) => ({
977
+ fileName,
978
+ issues: issueList,
979
+ metrics: {}
980
+ }));
981
+ }
982
+ function buildSimpleProviderScore(toolName, summary, rawData = {}) {
983
+ return {
984
+ toolName,
985
+ score: summary.score ?? 0,
986
+ rawMetrics: { ...summary, ...rawData },
987
+ factors: [],
988
+ recommendations: (summary.recommendations ?? []).map((action) => ({
989
+ action,
990
+ estimatedImpact: 5,
991
+ priority: "medium"
992
+ }))
993
+ };
994
+ }
995
+ function buildSpokeOutput(toolName, version, summary, results, metadata = {}) {
996
+ return SpokeOutputSchema.parse({
997
+ results,
998
+ summary,
999
+ metadata: {
1000
+ toolName,
1001
+ version,
1002
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1003
+ ...metadata
1004
+ }
1005
+ });
1006
+ }
1007
+ function createProvider(config) {
1008
+ return {
1009
+ id: config.id,
1010
+ alias: config.alias,
1011
+ defaultWeight: config.defaultWeight,
1012
+ async analyze(options) {
1013
+ const report = await config.analyzeReport(options);
1014
+ return buildSpokeOutput(
1015
+ config.id,
1016
+ config.version,
1017
+ config.getSummary(report),
1018
+ config.getResults(report),
1019
+ config.getMetadata?.(report) ?? {}
1020
+ );
1021
+ },
1022
+ score(output, options) {
1023
+ return config.score(output, options);
1024
+ }
1025
+ };
1026
+ }
1027
+
866
1028
  // src/utils/ast-parser.ts
867
1029
  var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
868
1030
 
@@ -989,8 +1151,10 @@ var TypeScriptParser = class {
989
1151
  // camelCase for variables and functions
990
1152
  variablePattern: /^[a-z][a-zA-Z0-9]*$/,
991
1153
  functionPattern: /^[a-z][a-zA-Z0-9]*$/,
992
- // PascalCase for classes
1154
+ // PascalCase for classes, types and interfaces
993
1155
  classPattern: /^[A-Z][a-zA-Z0-9]*$/,
1156
+ typePattern: /^[A-Z][a-zA-Z0-9]*$/,
1157
+ interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
994
1158
  // UPPER_CASE for constants
995
1159
  constantPattern: /^[A-Z][A-Z0-9_]*$/,
996
1160
  // Common exceptions (React hooks, etc.)
@@ -1201,6 +1365,101 @@ var TypeScriptParser = class {
1201
1365
  }
1202
1366
  };
1203
1367
 
1368
+ // src/parsers/metadata-utils.ts
1369
+ function analyzeNodeMetadata(node, code, options) {
1370
+ const metadata = {
1371
+ isPure: true,
1372
+ hasSideEffects: false
1373
+ };
1374
+ try {
1375
+ let prev = node.previousSibling || null;
1376
+ while (prev && /comment/i.test(prev.type)) {
1377
+ const text = prev.text || "";
1378
+ if (text.trim().startsWith("/**") || text.trim().startsWith("/*")) {
1379
+ metadata.documentation = {
1380
+ content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
1381
+ type: "comment"
1382
+ };
1383
+ break;
1384
+ }
1385
+ if (text.trim().startsWith("///")) {
1386
+ metadata.documentation = {
1387
+ content: text.replace(/^\/\/\//, "").trim(),
1388
+ type: "xml-doc"
1389
+ };
1390
+ break;
1391
+ }
1392
+ if (text.trim().startsWith("//")) {
1393
+ metadata.documentation = {
1394
+ content: text.replace(/^\/\//, "").trim(),
1395
+ type: "comment"
1396
+ };
1397
+ break;
1398
+ }
1399
+ prev = prev.previousSibling;
1400
+ }
1401
+ if (node.type === "function_definition") {
1402
+ const body2 = node.childForFieldName ? node.childForFieldName("body") : node.children.find((c) => c.type === "block");
1403
+ if (body2 && body2.children.length > 0) {
1404
+ const firstStmt = body2.children[0];
1405
+ if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
1406
+ metadata.documentation = {
1407
+ content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
1408
+ type: "docstring"
1409
+ };
1410
+ }
1411
+ }
1412
+ }
1413
+ } catch {
1414
+ }
1415
+ const defaultSignatures = [
1416
+ "console.",
1417
+ "fmt.",
1418
+ "panic(",
1419
+ "os.Exit",
1420
+ "log.",
1421
+ "Console.Write",
1422
+ "File.Write",
1423
+ "System.out",
1424
+ "System.err",
1425
+ "Files.write",
1426
+ "process.exit",
1427
+ "exit("
1428
+ ];
1429
+ const signatures = Array.from(
1430
+ /* @__PURE__ */ new Set([...options?.sideEffectSignatures || [], ...defaultSignatures])
1431
+ );
1432
+ const walk = (n) => {
1433
+ try {
1434
+ const t = n.type || "";
1435
+ if (/assign|assignment|assignment_statement|assignment_expression|throw|throw_statement|send_statement|global_statement|nonlocal_statement/i.test(
1436
+ t
1437
+ )) {
1438
+ metadata.isPure = false;
1439
+ metadata.hasSideEffects = true;
1440
+ }
1441
+ const text = n.text || "";
1442
+ for (const s of signatures) {
1443
+ if (text.includes(s)) {
1444
+ metadata.isPure = false;
1445
+ metadata.hasSideEffects = true;
1446
+ break;
1447
+ }
1448
+ }
1449
+ for (let i = 0; i < n.childCount; i++) {
1450
+ const c = n.child(i);
1451
+ if (c) walk(c);
1452
+ }
1453
+ } catch {
1454
+ }
1455
+ };
1456
+ const body = node.childForFieldName?.("body") || node.children.find(
1457
+ (c) => /body|block|class_body|declaration_list|function_body/.test(c.type)
1458
+ );
1459
+ if (body) walk(body);
1460
+ return metadata;
1461
+ }
1462
+
1204
1463
  // src/parsers/tree-sitter-utils.ts
1205
1464
  var Parser = __toESM(require("web-tree-sitter"));
1206
1465
  var path = __toESM(require("path"));
@@ -1289,11 +1548,9 @@ async function setupParser(language) {
1289
1548
  }
1290
1549
  }
1291
1550
 
1292
- // src/parsers/python-parser.ts
1293
- var PythonParser = class {
1551
+ // src/parsers/base-parser.ts
1552
+ var BaseLanguageParser = class {
1294
1553
  constructor() {
1295
- this.language = "python" /* Python */;
1296
- this.extensions = [".py"];
1297
1554
  this.parser = null;
1298
1555
  this.initialized = false;
1299
1556
  }
@@ -1302,48 +1559,18 @@ var PythonParser = class {
1302
1559
  */
1303
1560
  async initialize() {
1304
1561
  if (this.initialized) return;
1305
- this.parser = await setupParser("python");
1306
- this.initialized = true;
1562
+ try {
1563
+ this.parser = await setupParser(this.getParserName());
1564
+ this.initialized = true;
1565
+ } catch (error) {
1566
+ console.warn(`Failed to initialize ${this.language} parser:`, error);
1567
+ }
1307
1568
  }
1308
1569
  async getAST(code, filePath) {
1309
1570
  if (!this.initialized) await this.initialize();
1310
1571
  if (!this.parser) return null;
1311
1572
  return this.parser.parse(code);
1312
1573
  }
1313
- analyzeMetadata(node, code) {
1314
- const metadata = {
1315
- isPure: true,
1316
- hasSideEffects: false
1317
- };
1318
- const body = node.childForFieldName("body");
1319
- if (body && body.children.length > 0) {
1320
- const firstStmt = body.children[0];
1321
- if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
1322
- metadata.documentation = {
1323
- content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
1324
- type: "docstring"
1325
- };
1326
- }
1327
- }
1328
- const walk = (n) => {
1329
- if (n.type === "global_statement" || n.type === "nonlocal_statement") {
1330
- metadata.isPure = false;
1331
- metadata.hasSideEffects = true;
1332
- }
1333
- if (n.type === "call") {
1334
- const functionNode = n.childForFieldName("function");
1335
- if (functionNode && ["print", "input", "open"].includes(functionNode.text)) {
1336
- metadata.isPure = false;
1337
- metadata.hasSideEffects = true;
1338
- }
1339
- }
1340
- for (const child of n.children) {
1341
- walk(child);
1342
- }
1343
- };
1344
- if (body) walk(body);
1345
- return metadata;
1346
- }
1347
1574
  parse(code, filePath) {
1348
1575
  if (!this.initialized || !this.parser) {
1349
1576
  return this.parseRegex(code, filePath);
@@ -1353,19 +1580,42 @@ var PythonParser = class {
1353
1580
  if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
1354
1581
  return this.parseRegex(code, filePath);
1355
1582
  }
1356
- const rootNode = tree.rootNode;
1357
- const imports = this.extractImportsAST(rootNode);
1358
- const exports2 = this.extractExportsAST(rootNode, code);
1583
+ const imports = this.extractImportsAST(tree.rootNode);
1584
+ const exports2 = this.extractExportsAST(tree.rootNode, code);
1359
1585
  return {
1360
1586
  exports: exports2,
1361
1587
  imports,
1362
- language: "python" /* Python */,
1588
+ language: this.language,
1363
1589
  warnings: []
1364
1590
  };
1365
1591
  } catch (error) {
1592
+ console.warn(
1593
+ `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1594
+ );
1366
1595
  return this.parseRegex(code, filePath);
1367
1596
  }
1368
1597
  }
1598
+ canHandle(filePath) {
1599
+ const lowerPath = filePath.toLowerCase();
1600
+ return this.extensions.some((ext) => lowerPath.endsWith(ext));
1601
+ }
1602
+ };
1603
+
1604
+ // src/parsers/python-parser.ts
1605
+ var PythonParser = class extends BaseLanguageParser {
1606
+ constructor() {
1607
+ super(...arguments);
1608
+ this.language = "python" /* Python */;
1609
+ this.extensions = [".py"];
1610
+ }
1611
+ getParserName() {
1612
+ return "python";
1613
+ }
1614
+ analyzeMetadata(node, code) {
1615
+ return analyzeNodeMetadata(node, code, {
1616
+ sideEffectSignatures: ["print(", "input(", "open("]
1617
+ });
1618
+ }
1369
1619
  extractImportsAST(rootNode) {
1370
1620
  const imports = [];
1371
1621
  const processImportNode = (node) => {
@@ -1691,94 +1941,132 @@ var PythonParser = class {
1691
1941
  }
1692
1942
  };
1693
1943
 
1694
- // src/parsers/java-parser.ts
1695
- var JavaParser = class {
1696
- constructor() {
1697
- this.language = "java" /* Java */;
1698
- this.extensions = [".java"];
1699
- this.parser = null;
1700
- this.initialized = false;
1701
- }
1702
- /**
1703
- * Initialize the tree-sitter parser
1704
- */
1705
- async initialize() {
1706
- if (this.initialized) return;
1707
- this.parser = await setupParser("java");
1708
- this.initialized = true;
1709
- }
1710
- async getAST(code, filePath) {
1711
- if (!this.initialized) await this.initialize();
1712
- if (!this.parser) return null;
1713
- return this.parser.parse(code);
1714
- }
1715
- analyzeMetadata(node, code) {
1716
- const metadata = {
1717
- isPure: true,
1718
- hasSideEffects: false
1719
- };
1720
- let prev = node.previousSibling;
1721
- while (prev && (prev.type === "comment" || prev.type === "line_comment")) {
1722
- if (prev.text.startsWith("/**")) {
1944
+ // src/parsers/shared-parser-utils.ts
1945
+ var SIDE_EFFECT_KEYWORDS = [
1946
+ "print(",
1947
+ "console.",
1948
+ "System.out",
1949
+ "System.err",
1950
+ "fmt.",
1951
+ "File.Write",
1952
+ "Files.write",
1953
+ "os.Exit",
1954
+ "panic(",
1955
+ "throw ",
1956
+ "Logging.",
1957
+ "log."
1958
+ ];
1959
+ function analyzeGeneralMetadata(node, code, options = {}) {
1960
+ const metadata = {
1961
+ isPure: true,
1962
+ hasSideEffects: false
1963
+ };
1964
+ try {
1965
+ let prev = node.previousSibling || null;
1966
+ while (prev && /comment/i.test(prev.type)) {
1967
+ const text = prev.text || "";
1968
+ if (text.trim().startsWith("/**")) {
1969
+ metadata.documentation = {
1970
+ content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
1971
+ type: "jsdoc"
1972
+ };
1973
+ break;
1974
+ }
1975
+ if (text.trim().startsWith("///")) {
1723
1976
  metadata.documentation = {
1724
- content: prev.text.replace(/[/*]/g, "").trim(),
1977
+ content: text.replace(/^\/\/\//, "").trim(),
1725
1978
  type: "xml-doc"
1726
- // Using xml-doc as a catch-all for structured or we can add 'javadoc'
1979
+ };
1980
+ break;
1981
+ }
1982
+ if (text.trim().startsWith("//")) {
1983
+ metadata.documentation = {
1984
+ content: text.replace(/^\/\//, "").trim(),
1985
+ type: "comment"
1727
1986
  };
1728
1987
  break;
1729
1988
  }
1730
1989
  prev = prev.previousSibling;
1731
1990
  }
1732
- const walk = (n) => {
1733
- if (n.type === "assignment_expression") {
1734
- metadata.isPure = false;
1735
- metadata.hasSideEffects = true;
1736
- }
1737
- if (n.type === "method_invocation") {
1738
- const text = n.text;
1739
- if (text.includes("System.out.print") || text.includes("System.err.print") || text.includes("Files.write")) {
1740
- metadata.isPure = false;
1741
- metadata.hasSideEffects = true;
1742
- }
1743
- }
1744
- if (n.type === "throw_statement") {
1991
+ } catch {
1992
+ }
1993
+ const signatures = [
1994
+ ...SIDE_EFFECT_KEYWORDS,
1995
+ ...options.sideEffectSignatures || []
1996
+ ];
1997
+ const walk = (n) => {
1998
+ if (/assign|assignment|assignment_statement|assignment_expression/i.test(
1999
+ n.type
2000
+ )) {
2001
+ metadata.isPure = false;
2002
+ metadata.hasSideEffects = true;
2003
+ }
2004
+ const text = n.text;
2005
+ for (const sig of signatures) {
2006
+ if (text.includes(sig)) {
1745
2007
  metadata.isPure = false;
1746
2008
  metadata.hasSideEffects = true;
2009
+ break;
1747
2010
  }
1748
- for (const child of n.children) {
1749
- walk(child);
1750
- }
1751
- };
1752
- const body = node.children.find(
1753
- (c) => c.type === "block" || c.type === "class_body"
1754
- );
1755
- if (body) walk(body);
1756
- return metadata;
1757
- }
1758
- parse(code, filePath) {
1759
- if (!this.initialized || !this.parser) {
1760
- return this.parseRegex(code, filePath);
1761
2011
  }
1762
- try {
1763
- const tree = this.parser.parse(code);
1764
- if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
1765
- return this.parseRegex(code, filePath);
2012
+ if (!metadata.hasSideEffects) {
2013
+ for (let i = 0; i < n.childCount; i++) {
2014
+ const child = n.child(i);
2015
+ if (child) walk(child);
1766
2016
  }
1767
- const rootNode = tree.rootNode;
1768
- const imports = this.extractImportsAST(rootNode);
1769
- const exports2 = this.extractExportsAST(rootNode, code);
1770
- return {
1771
- exports: exports2,
1772
- imports,
1773
- language: "java" /* Java */,
1774
- warnings: []
1775
- };
1776
- } catch (error) {
1777
- console.warn(
1778
- `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
1779
- );
1780
- return this.parseRegex(code, filePath);
1781
2017
  }
2018
+ };
2019
+ walk(node);
2020
+ return metadata;
2021
+ }
2022
+ function extractParameterNames(node) {
2023
+ const params = [];
2024
+ const candidates = [
2025
+ // common field name
2026
+ node.childForFieldName ? node.childForFieldName("parameters") : null,
2027
+ node.childForFieldName ? node.childForFieldName("parameter_list") : null,
2028
+ node.children.find((c) => c.type === "parameter_list") || null,
2029
+ node.children.find((c) => c.type === "parameters") || null,
2030
+ node.children.find((c) => c.type === "formal_parameters") || null,
2031
+ node.children.find((c) => c.type === "formal_parameter") || null
2032
+ ];
2033
+ const list = candidates.find(Boolean);
2034
+ if (!list) return params;
2035
+ for (const child of list.children) {
2036
+ if (!child) continue;
2037
+ const id = child.childForFieldName?.("name") || child.children.find(
2038
+ (c) => [
2039
+ "identifier",
2040
+ "variable_name",
2041
+ "name",
2042
+ "parameter",
2043
+ "formal_parameter"
2044
+ ].includes(c.type)
2045
+ ) || (child.type === "identifier" ? child : void 0);
2046
+ if (id && typeof id.text === "string") params.push(id.text);
2047
+ }
2048
+ return params;
2049
+ }
2050
+
2051
+ // src/parsers/java-parser.ts
2052
+ var JavaParser = class extends BaseLanguageParser {
2053
+ constructor() {
2054
+ super(...arguments);
2055
+ this.language = "java" /* Java */;
2056
+ this.extensions = [".java"];
2057
+ }
2058
+ getParserName() {
2059
+ return "java";
2060
+ }
2061
+ analyzeMetadata(node, code) {
2062
+ return analyzeGeneralMetadata(node, code, {
2063
+ sideEffectSignatures: [
2064
+ "System.out",
2065
+ "System.err",
2066
+ "Files.write",
2067
+ "Logging."
2068
+ ]
2069
+ });
1782
2070
  }
1783
2071
  parseRegex(code, filePath) {
1784
2072
  const lines = code.split("\n");
@@ -1853,7 +2141,7 @@ var JavaParser = class {
1853
2141
  const imports = [];
1854
2142
  for (const node of rootNode.children) {
1855
2143
  if (node.type === "import_declaration") {
1856
- let sourceArr = [];
2144
+ const sourceArr = [];
1857
2145
  let isStatic = false;
1858
2146
  let isWildcard = false;
1859
2147
  for (const child of node.children) {
@@ -1951,14 +2239,7 @@ var JavaParser = class {
1951
2239
  }
1952
2240
  }
1953
2241
  extractParameters(node) {
1954
- const paramsNode = node.children.find(
1955
- (c) => c.type === "formal_parameters"
1956
- );
1957
- if (!paramsNode) return [];
1958
- return paramsNode.children.filter((c) => c.type === "formal_parameter").map((c) => {
1959
- const idNode = c.children.find((child) => child.type === "identifier");
1960
- return idNode ? idNode.text : "unknown";
1961
- });
2242
+ return extractParameterNames(node);
1962
2243
  }
1963
2244
  getNamingConventions() {
1964
2245
  return {
@@ -1975,91 +2256,19 @@ var JavaParser = class {
1975
2256
  };
1976
2257
 
1977
2258
  // src/parsers/csharp-parser.ts
1978
- var CSharpParser = class {
2259
+ var CSharpParser = class extends BaseLanguageParser {
1979
2260
  constructor() {
2261
+ super(...arguments);
1980
2262
  this.language = "csharp" /* CSharp */;
1981
2263
  this.extensions = [".cs"];
1982
- this.parser = null;
1983
- this.initialized = false;
1984
2264
  }
1985
- /**
1986
- * Initialize the tree-sitter parser
1987
- */
1988
- async initialize() {
1989
- if (this.initialized) return;
1990
- this.parser = await setupParser("c_sharp");
1991
- this.initialized = true;
1992
- }
1993
- async getAST(code, filePath) {
1994
- if (!this.initialized) await this.initialize();
1995
- if (!this.parser) return null;
1996
- return this.parser.parse(code);
2265
+ getParserName() {
2266
+ return "c_sharp";
1997
2267
  }
1998
2268
  analyzeMetadata(node, code) {
1999
- const metadata = {
2000
- isPure: true,
2001
- hasSideEffects: false
2002
- };
2003
- let prev = node.previousSibling;
2004
- while (prev && (prev.type === "comment" || prev.type === "triple_slash_comment")) {
2005
- if (prev.text.trim().startsWith("///") || prev.type === "triple_slash_comment") {
2006
- metadata.documentation = {
2007
- content: prev.text.replace("///", "").trim(),
2008
- type: "xml-doc"
2009
- };
2010
- break;
2011
- }
2012
- prev = prev.previousSibling;
2013
- }
2014
- const walk = (n) => {
2015
- if (n.type === "assignment_expression") {
2016
- metadata.isPure = false;
2017
- metadata.hasSideEffects = true;
2018
- }
2019
- if (n.type === "invocation_expression") {
2020
- const text = n.text;
2021
- if (text.includes("Console.Write") || text.includes("File.Write") || text.includes("Log.")) {
2022
- metadata.isPure = false;
2023
- metadata.hasSideEffects = true;
2024
- }
2025
- }
2026
- if (n.type === "throw_statement") {
2027
- metadata.isPure = false;
2028
- metadata.hasSideEffects = true;
2029
- }
2030
- for (let i = 0; i < n.childCount; i++) {
2031
- const child = n.child(i);
2032
- if (child) walk(child);
2033
- }
2034
- };
2035
- const body = node.children.find(
2036
- (c) => c.type === "block" || c.type === "declaration_list"
2037
- );
2038
- if (body) walk(body);
2039
- return metadata;
2040
- }
2041
- parse(code, filePath) {
2042
- if (!this.initialized || !this.parser) {
2043
- return this.parseRegex(code, filePath);
2044
- }
2045
- try {
2046
- const tree = this.parser.parse(code);
2047
- if (!tree) throw new Error("Parser.parse(code) returned null");
2048
- const rootNode = tree.rootNode;
2049
- const imports = this.extractImportsAST(rootNode);
2050
- const exports2 = this.extractExportsAST(rootNode, code);
2051
- return {
2052
- exports: exports2,
2053
- imports,
2054
- language: "csharp" /* CSharp */,
2055
- warnings: []
2056
- };
2057
- } catch (error) {
2058
- console.warn(
2059
- `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
2060
- );
2061
- return this.parseRegex(code, filePath);
2062
- }
2269
+ return analyzeGeneralMetadata(node, code, {
2270
+ sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
2271
+ });
2063
2272
  }
2064
2273
  parseRegex(code, filePath) {
2065
2274
  const lines = code.split("\n");
@@ -2241,19 +2450,7 @@ var CSharpParser = class {
2241
2450
  return modifiers;
2242
2451
  }
2243
2452
  extractParameters(node) {
2244
- const params = [];
2245
- const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
2246
- if (parameterList) {
2247
- for (const param of parameterList.children) {
2248
- if (param.type === "parameter") {
2249
- const nameNode = param.childForFieldName("name") || param.children.find((c) => c.type === "identifier");
2250
- if (nameNode) {
2251
- params.push(nameNode.text);
2252
- }
2253
- }
2254
- }
2255
- }
2256
- return params;
2453
+ return extractParameterNames(node);
2257
2454
  }
2258
2455
  getNamingConventions() {
2259
2456
  return {
@@ -2269,86 +2466,19 @@ var CSharpParser = class {
2269
2466
  };
2270
2467
 
2271
2468
  // src/parsers/go-parser.ts
2272
- var GoParser = class {
2469
+ var GoParser = class extends BaseLanguageParser {
2273
2470
  constructor() {
2471
+ super(...arguments);
2274
2472
  this.language = "go" /* Go */;
2275
2473
  this.extensions = [".go"];
2276
- this.parser = null;
2277
- this.initialized = false;
2278
- }
2279
- /**
2280
- * Initialize the tree-sitter parser
2281
- */
2282
- async initialize() {
2283
- if (this.initialized) return;
2284
- this.parser = await setupParser("go");
2285
- this.initialized = true;
2286
2474
  }
2287
- async getAST(code, filePath) {
2288
- if (!this.initialized) await this.initialize();
2289
- if (!this.parser) return null;
2290
- return this.parser.parse(code);
2475
+ getParserName() {
2476
+ return "go";
2291
2477
  }
2292
2478
  analyzeMetadata(node, code) {
2293
- const metadata = {
2294
- isPure: true,
2295
- hasSideEffects: false
2296
- };
2297
- let prev = node.previousSibling;
2298
- while (prev && prev.type === "comment") {
2299
- metadata.documentation = {
2300
- content: prev.text.replace(/\/\/|\/\*|\*\//g, "").trim(),
2301
- type: "comment"
2302
- };
2303
- break;
2304
- }
2305
- const walk = (n) => {
2306
- if (n.type === "send_statement" || n.type === "expression_statement" && n.text.includes("<-")) {
2307
- metadata.isPure = false;
2308
- metadata.hasSideEffects = true;
2309
- }
2310
- if (n.type === "assignment_statement" || n.type === "short_var_declaration") {
2311
- }
2312
- if (n.type === "call_expression") {
2313
- const text = n.text;
2314
- if (text.includes("fmt.Print") || text.includes("os.Exit") || text.includes("panic(") || text.includes("log.")) {
2315
- metadata.isPure = false;
2316
- metadata.hasSideEffects = true;
2317
- }
2318
- }
2319
- for (let i = 0; i < n.childCount; i++) {
2320
- const child = n.child(i);
2321
- if (child) walk(child);
2322
- }
2323
- };
2324
- const body = node.childForFieldName("body");
2325
- if (body) walk(body);
2326
- return metadata;
2327
- }
2328
- parse(code, filePath) {
2329
- if (!this.initialized || !this.parser) {
2330
- return this.parseRegex(code, filePath);
2331
- }
2332
- try {
2333
- const tree = this.parser.parse(code);
2334
- if (!tree || tree.rootNode.type === "ERROR" || tree.rootNode.hasError) {
2335
- return this.parseRegex(code, filePath);
2336
- }
2337
- const rootNode = tree.rootNode;
2338
- const imports = this.extractImportsAST(rootNode);
2339
- const exports2 = this.extractExportsAST(rootNode, code);
2340
- return {
2341
- exports: exports2,
2342
- imports,
2343
- language: "go" /* Go */,
2344
- warnings: []
2345
- };
2346
- } catch (error) {
2347
- console.warn(
2348
- `AST parsing failed for ${filePath}, falling back to regex: ${error.message}`
2349
- );
2350
- return this.parseRegex(code, filePath);
2351
- }
2479
+ return analyzeGeneralMetadata(node, code, {
2480
+ sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
2481
+ });
2352
2482
  }
2353
2483
  parseRegex(code, filePath) {
2354
2484
  const lines = code.split("\n");
@@ -2545,17 +2675,7 @@ var GoParser = class {
2545
2675
  return exports2;
2546
2676
  }
2547
2677
  extractParameters(node) {
2548
- const params = [];
2549
- const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
2550
- if (parameterList) {
2551
- for (const param of parameterList.children) {
2552
- if (param.type === "parameter_declaration") {
2553
- const names = param.children.filter((c) => c.type === "identifier");
2554
- names.forEach((n) => params.push(n.text));
2555
- }
2556
- }
2557
- }
2558
- return params;
2678
+ return extractParameterNames(node);
2559
2679
  }
2560
2680
  getNamingConventions() {
2561
2681
  return {
@@ -2686,48 +2806,7 @@ function getSupportedLanguages() {
2686
2806
  return ParserFactory.getInstance().getSupportedLanguages();
2687
2807
  }
2688
2808
 
2689
- // src/utils/ast-parser.ts
2690
- function parseFileExports(code, filePath) {
2691
- const parser = getParser(filePath);
2692
- if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
2693
- try {
2694
- const result = parser.parse(code, filePath);
2695
- return {
2696
- exports: result.exports.map((e) => ({
2697
- name: e.name,
2698
- type: e.type,
2699
- imports: e.imports || [],
2700
- dependencies: e.dependencies || [],
2701
- typeReferences: e.typeReferences || [],
2702
- loc: e.loc ? {
2703
- start: { line: e.loc.start.line, column: e.loc.start.column },
2704
- end: { line: e.loc.end.line, column: e.loc.end.column }
2705
- } : void 0
2706
- })),
2707
- imports: result.imports.map((i) => ({
2708
- source: i.source,
2709
- specifiers: i.specifiers,
2710
- isTypeOnly: i.isTypeOnly || false
2711
- }))
2712
- };
2713
- } catch (e) {
2714
- return { exports: [], imports: [] };
2715
- }
2716
- }
2717
- try {
2718
- const ast = (0, import_typescript_estree2.parse)(code, {
2719
- loc: true,
2720
- range: true,
2721
- jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
2722
- filePath
2723
- });
2724
- const imports = extractFileImports(ast);
2725
- const exports2 = extractExportsWithDependencies(ast, imports);
2726
- return { exports: exports2, imports };
2727
- } catch (error) {
2728
- return { exports: [], imports: [] };
2729
- }
2730
- }
2809
+ // src/utils/ast-visitor.ts
2731
2810
  function extractFileImports(ast) {
2732
2811
  const imports = [];
2733
2812
  for (const node of ast.body) {
@@ -2785,22 +2864,23 @@ function extractExportsWithDependencies(ast, fileImports) {
2785
2864
  }
2786
2865
  return exports2;
2787
2866
  }
2788
- function extractFromDeclaration(declaration) {
2867
+ function extractFromDeclaration(node) {
2868
+ if (!node) return [];
2789
2869
  const results = [];
2790
- if (declaration.type === "FunctionDeclaration" && "id" in declaration && declaration.id) {
2791
- results.push({ name: declaration.id.name, type: "function" });
2792
- } else if (declaration.type === "ClassDeclaration" && "id" in declaration && declaration.id) {
2793
- results.push({ name: declaration.id.name, type: "class" });
2794
- } else if (declaration.type === "VariableDeclaration") {
2795
- for (const declarator of declaration.declarations) {
2796
- if (declarator.id.type === "Identifier") {
2797
- results.push({ name: declarator.id.name, type: "const" });
2870
+ if (node.type === "FunctionDeclaration" && node.id) {
2871
+ results.push({ name: node.id.name, type: "function" });
2872
+ } else if (node.type === "ClassDeclaration" && node.id) {
2873
+ results.push({ name: node.id.name, type: "class" });
2874
+ } else if (node.type === "VariableDeclaration") {
2875
+ for (const decl of node.declarations) {
2876
+ if (decl.id.type === "Identifier") {
2877
+ results.push({ name: decl.id.name, type: "const" });
2798
2878
  }
2799
2879
  }
2800
- } else if (declaration.type === "TSTypeAliasDeclaration") {
2801
- results.push({ name: declaration.id.name, type: "type" });
2802
- } else if (declaration.type === "TSInterfaceDeclaration") {
2803
- results.push({ name: declaration.id.name, type: "interface" });
2880
+ } else if (node.type === "TSInterfaceDeclaration" && node.id) {
2881
+ results.push({ name: node.id.name, type: "interface" });
2882
+ } else if (node.type === "TSTypeAliasDeclaration" && node.id) {
2883
+ results.push({ name: node.id.name, type: "type" });
2804
2884
  }
2805
2885
  return results;
2806
2886
  }
@@ -2828,16 +2908,6 @@ function findUsedImports(node, importedNames) {
2828
2908
  visit(node);
2829
2909
  return Array.from(usedImports);
2830
2910
  }
2831
- function calculateImportSimilarity(export1, export2) {
2832
- if (export1.imports.length === 0 && export2.imports.length === 0) {
2833
- return 1;
2834
- }
2835
- const set1 = new Set(export1.imports);
2836
- const set2 = new Set(export2.imports);
2837
- const intersection = new Set([...set1].filter((x) => set2.has(x)));
2838
- const union = /* @__PURE__ */ new Set([...set1, ...set2]);
2839
- return intersection.size / union.size;
2840
- }
2841
2911
  function extractTypeReferences(node) {
2842
2912
  const types = /* @__PURE__ */ new Set();
2843
2913
  function visit(n) {
@@ -2875,6 +2945,59 @@ function extractTypeReferences(node) {
2875
2945
  visit(node);
2876
2946
  return Array.from(types);
2877
2947
  }
2948
+
2949
+ // src/utils/ast-parser.ts
2950
+ function parseFileExports(code, filePath) {
2951
+ const parser = getParser(filePath);
2952
+ if (parser && parser.language !== "typescript" /* TypeScript */ && parser.language !== "javascript" /* JavaScript */) {
2953
+ try {
2954
+ const result = parser.parse(code, filePath);
2955
+ return {
2956
+ exports: result.exports.map((e) => ({
2957
+ name: e.name,
2958
+ type: e.type,
2959
+ imports: e.imports || [],
2960
+ dependencies: e.dependencies || [],
2961
+ typeReferences: e.typeReferences || [],
2962
+ loc: e.loc ? {
2963
+ start: { line: e.loc.start.line, column: e.loc.start.column },
2964
+ end: { line: e.loc.end.line, column: e.loc.end.column }
2965
+ } : void 0
2966
+ })),
2967
+ imports: result.imports.map((i) => ({
2968
+ source: i.source,
2969
+ specifiers: i.specifiers,
2970
+ isTypeOnly: i.isTypeOnly || false
2971
+ }))
2972
+ };
2973
+ } catch (e) {
2974
+ return { exports: [], imports: [] };
2975
+ }
2976
+ }
2977
+ try {
2978
+ const ast = (0, import_typescript_estree2.parse)(code, {
2979
+ loc: true,
2980
+ range: true,
2981
+ jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
2982
+ filePath
2983
+ });
2984
+ const imports = extractFileImports(ast);
2985
+ const exports2 = extractExportsWithDependencies(ast, imports);
2986
+ return { exports: exports2, imports };
2987
+ } catch (error) {
2988
+ return { exports: [], imports: [] };
2989
+ }
2990
+ }
2991
+ function calculateImportSimilarity(export1, export2) {
2992
+ if (export1.imports.length === 0 && export2.imports.length === 0) {
2993
+ return 1;
2994
+ }
2995
+ const set1 = new Set(export1.imports);
2996
+ const set2 = new Set(export2.imports);
2997
+ const intersection = new Set([...set1].filter((x) => set2.has(x)));
2998
+ const union = /* @__PURE__ */ new Set([...set1, ...set2]);
2999
+ return intersection.size / union.size;
3000
+ }
2878
3001
  function parseCode(code, language) {
2879
3002
  return null;
2880
3003
  }
@@ -2905,34 +3028,47 @@ var CONFIG_FILES = [
2905
3028
  async function loadConfig(rootDir) {
2906
3029
  let currentDir = (0, import_path3.resolve)(rootDir);
2907
3030
  while (true) {
3031
+ const foundConfigs = [];
2908
3032
  for (const configFile of CONFIG_FILES) {
3033
+ if ((0, import_fs3.existsSync)((0, import_path3.join)(currentDir, configFile))) {
3034
+ foundConfigs.push(configFile);
3035
+ }
3036
+ }
3037
+ if (foundConfigs.length > 0) {
3038
+ if (foundConfigs.length > 1) {
3039
+ console.warn(
3040
+ `\u26A0\uFE0F Multiple configuration files found in ${currentDir}: ${foundConfigs.join(
3041
+ ", "
3042
+ )}. Using ${foundConfigs[0]}.`
3043
+ );
3044
+ } else {
3045
+ }
3046
+ const configFile = foundConfigs[0];
2909
3047
  const configPath = (0, import_path3.join)(currentDir, configFile);
2910
- if ((0, import_fs3.existsSync)(configPath)) {
3048
+ try {
3049
+ let config;
3050
+ if (configFile.endsWith(".js")) {
3051
+ const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
3052
+ const module2 = await import(`${fileUrl}?t=${Date.now()}`);
3053
+ config = module2.default || module2;
3054
+ } else {
3055
+ const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
3056
+ config = JSON.parse(content);
3057
+ }
3058
+ if (typeof config !== "object" || config === null) {
3059
+ throw new Error("Config must be an object");
3060
+ }
3061
+ return config;
3062
+ } catch (error) {
3063
+ const errorMessage = error instanceof Error ? error.message : String(error);
3064
+ const configError = new Error(
3065
+ `Failed to load config from ${configPath}: ${errorMessage}`
3066
+ );
2911
3067
  try {
2912
- let config;
2913
- if (configFile.endsWith(".js")) {
2914
- const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
2915
- const module2 = await import(`${fileUrl}?t=${Date.now()}`);
2916
- config = module2.default || module2;
2917
- } else {
2918
- const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
2919
- config = JSON.parse(content);
2920
- }
2921
- if (typeof config !== "object" || config === null) {
2922
- throw new Error("Config must be an object");
2923
- }
2924
- return config;
2925
- } catch (error) {
2926
- const errorMessage = error instanceof Error ? error.message : String(error);
2927
- const e = new Error(
2928
- `Failed to load config from ${configPath}: ${errorMessage}`
2929
- );
2930
- try {
2931
- e.cause = error instanceof Error ? error : void 0;
2932
- } catch {
2933
- }
2934
- throw e;
3068
+ configError.cause = error instanceof Error ? error : void 0;
3069
+ } catch {
2935
3070
  }
3071
+ throw configError;
2936
3072
  }
2937
3073
  }
2938
3074
  const parent = (0, import_path3.dirname)(currentDir);
@@ -2945,28 +3081,28 @@ async function loadConfig(rootDir) {
2945
3081
  }
2946
3082
  function mergeConfigWithDefaults(userConfig, defaults) {
2947
3083
  if (!userConfig) return defaults;
2948
- const result = { ...defaults };
3084
+ const mergedConfig = { ...defaults };
2949
3085
  if (userConfig.scan) {
2950
- if (userConfig.scan.include) result.include = userConfig.scan.include;
2951
- if (userConfig.scan.exclude) result.exclude = userConfig.scan.exclude;
3086
+ if (userConfig.scan.include) mergedConfig.include = userConfig.scan.include;
3087
+ if (userConfig.scan.exclude) mergedConfig.exclude = userConfig.scan.exclude;
2952
3088
  }
2953
3089
  const toolOverrides = userConfig.tools && !Array.isArray(userConfig.tools) && typeof userConfig.tools === "object" ? userConfig.tools : userConfig.toolConfigs;
2954
3090
  if (toolOverrides) {
2955
- if (!result.toolConfigs) result.toolConfigs = {};
3091
+ if (!mergedConfig.toolConfigs) mergedConfig.toolConfigs = {};
2956
3092
  for (const [toolName, toolConfig] of Object.entries(toolOverrides)) {
2957
3093
  if (typeof toolConfig === "object" && toolConfig !== null) {
2958
- result[toolName] = { ...result[toolName], ...toolConfig };
2959
- result.toolConfigs[toolName] = {
2960
- ...result.toolConfigs[toolName],
3094
+ mergedConfig[toolName] = { ...mergedConfig[toolName], ...toolConfig };
3095
+ mergedConfig.toolConfigs[toolName] = {
3096
+ ...mergedConfig.toolConfigs[toolName],
2961
3097
  ...toolConfig
2962
3098
  };
2963
3099
  }
2964
3100
  }
2965
3101
  }
2966
3102
  if (userConfig.output) {
2967
- result.output = { ...result.output, ...userConfig.output };
3103
+ mergedConfig.output = { ...mergedConfig.output, ...userConfig.output };
2968
3104
  }
2969
- return result;
3105
+ return mergedConfig;
2970
3106
  }
2971
3107
 
2972
3108
  // src/utils/visualization.ts
@@ -3335,6 +3471,13 @@ function getRating(score) {
3335
3471
  if (score >= 40) return "Needs Work" /* NeedsWork */;
3336
3472
  return "Critical" /* Critical */;
3337
3473
  }
3474
+ function getRatingSlug(score) {
3475
+ if (score >= 90) return "excellent";
3476
+ if (score >= 75) return "good";
3477
+ if (score >= 60) return "fair";
3478
+ if (score >= 40) return "needs-work";
3479
+ return "critical";
3480
+ }
3338
3481
  function getRatingWithContext(score, fileCount, modelTier = "standard") {
3339
3482
  const threshold = getRecommendedThreshold(fileCount, modelTier);
3340
3483
  const normalized = score - threshold + 70;
@@ -3604,7 +3747,10 @@ function predictAcceptanceRate(toolOutputs) {
3604
3747
  impact: Math.round((50 - aiSignalClarity.score) * 2e-3 * 100)
3605
3748
  });
3606
3749
  }
3607
- const totalImpact = factors.reduce((sum, f) => sum + f.impact / 100, 0);
3750
+ const totalImpact = factors.reduce(
3751
+ (sum, f) => sum + f.impact / 100,
3752
+ 0
3753
+ );
3608
3754
  const rate = Math.max(0.05, Math.min(0.8, baseRate + totalImpact));
3609
3755
  let confidence = 0.35;
3610
3756
  if (toolOutputs.size >= 4) confidence = 0.75;
@@ -3847,6 +3993,24 @@ function collectFutureProofRecommendations(params) {
3847
3993
  }
3848
3994
  return recommendations;
3849
3995
  }
3996
+ function collectBaseFutureProofRecommendations(params) {
3997
+ const recommendations = [];
3998
+ for (const rec of params.patternEntropy.recommendations) {
3999
+ recommendations.push({
4000
+ action: rec,
4001
+ estimatedImpact: 5,
4002
+ priority: "medium"
4003
+ });
4004
+ }
4005
+ if (params.conceptCohesion.rating === "poor") {
4006
+ recommendations.push({
4007
+ action: "Improve concept cohesion by grouping related exports",
4008
+ estimatedImpact: 8,
4009
+ priority: "high"
4010
+ });
4011
+ }
4012
+ return recommendations;
4013
+ }
3850
4014
 
3851
4015
  // src/metrics/cognitive-load.ts
3852
4016
  function calculateCognitiveLoad(params) {
@@ -4537,21 +4701,10 @@ function calculateFutureProofScore(params) {
4537
4701
  description: params.conceptCohesion.rating
4538
4702
  }
4539
4703
  ];
4540
- const recommendations = [];
4541
- for (const rec of params.patternEntropy.recommendations) {
4542
- recommendations.push({
4543
- action: rec,
4544
- estimatedImpact: 5,
4545
- priority: "medium"
4546
- });
4547
- }
4548
- if (params.conceptCohesion.rating === "poor") {
4549
- recommendations.push({
4550
- action: "Improve concept cohesion by grouping related exports",
4551
- estimatedImpact: 8,
4552
- priority: "high"
4553
- });
4554
- }
4704
+ const recommendations = collectBaseFutureProofRecommendations({
4705
+ patternEntropy: params.patternEntropy,
4706
+ conceptCohesion: params.conceptCohesion
4707
+ });
4555
4708
  const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
4556
4709
  return {
4557
4710
  toolName: "future-proof",
@@ -4884,6 +5037,8 @@ function emitIssuesAsAnnotations(issues) {
4884
5037
  TypeScriptParser,
4885
5038
  UnifiedReportSchema,
4886
5039
  VAGUE_FILE_NAMES,
5040
+ buildSimpleProviderScore,
5041
+ buildSpokeOutput,
4887
5042
  calculateAgentGrounding,
4888
5043
  calculateAiSignalClarity,
4889
5044
  calculateBusinessROI,
@@ -4907,6 +5062,7 @@ function emitIssuesAsAnnotations(issues) {
4907
5062
  calculateTestabilityIndex,
4908
5063
  calculateTokenBudget,
4909
5064
  clearHistory,
5065
+ createProvider,
4910
5066
  emitAnnotation,
4911
5067
  emitIssuesAsAnnotations,
4912
5068
  emitProgress,
@@ -4915,6 +5071,8 @@ function emitIssuesAsAnnotations(issues) {
4915
5071
  exportHistory,
4916
5072
  extractFunctions,
4917
5073
  extractImports,
5074
+ findLatestReport,
5075
+ findLatestScanReport,
4918
5076
  formatAcceptanceRate,
4919
5077
  formatCost,
4920
5078
  formatHours,
@@ -4932,15 +5090,21 @@ function emitIssuesAsAnnotations(issues) {
4932
5090
  getProjectSizeTier,
4933
5091
  getRating,
4934
5092
  getRatingDisplay,
5093
+ getRatingSlug,
4935
5094
  getRatingWithContext,
4936
5095
  getRecommendedThreshold,
4937
5096
  getRepoMetadata,
4938
5097
  getSafetyIcon,
4939
5098
  getScoreBar,
5099
+ getSeverityBadge,
4940
5100
  getSeverityColor,
5101
+ getSeverityEnum,
5102
+ getSeverityLevel,
5103
+ getSeverityValue,
4941
5104
  getSupportedLanguages,
4942
5105
  getToolWeight,
4943
5106
  getWasmPath,
5107
+ groupIssuesByFile,
4944
5108
  handleCLIError,
4945
5109
  handleJSONOutput,
4946
5110
  initTreeSitter,