@aiready/core 0.23.1 → 0.23.2

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/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,
@@ -131,6 +136,7 @@ __export(index_exports, {
131
136
  getSupportedLanguages: () => getSupportedLanguages,
132
137
  getToolWeight: () => getToolWeight,
133
138
  getWasmPath: () => getWasmPath,
139
+ groupIssuesByFile: () => groupIssuesByFile,
134
140
  handleCLIError: () => handleCLIError,
135
141
  handleJSONOutput: () => handleJSONOutput,
136
142
  initTreeSitter: () => initTreeSitter,
@@ -862,6 +868,111 @@ function getSeverityColor(severity, chalk) {
862
868
  return chalk.white;
863
869
  }
864
870
  }
871
+ function findLatestReport(dirPath) {
872
+ const aireadyDir = (0, import_path2.resolve)(dirPath, ".aiready");
873
+ if (!(0, import_fs2.existsSync)(aireadyDir)) {
874
+ return null;
875
+ }
876
+ let files = (0, import_fs2.readdirSync)(aireadyDir).filter(
877
+ (f) => f.startsWith("aiready-report-") && f.endsWith(".json")
878
+ );
879
+ if (files.length === 0) {
880
+ files = (0, import_fs2.readdirSync)(aireadyDir).filter(
881
+ (f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
882
+ );
883
+ }
884
+ if (files.length === 0) {
885
+ return null;
886
+ }
887
+ const sortedFiles = files.map((f) => ({
888
+ name: f,
889
+ path: (0, import_path2.resolve)(aireadyDir, f),
890
+ mtime: (0, import_fs2.statSync)((0, import_path2.resolve)(aireadyDir, f)).mtime
891
+ })).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
892
+ return sortedFiles[0].path;
893
+ }
894
+ function findLatestScanReport(scanReportsDir, reportFilePrefix) {
895
+ try {
896
+ let reportFiles = [];
897
+ if ((0, import_fs2.existsSync)(scanReportsDir)) {
898
+ const files = (0, import_fs2.readdirSync)(scanReportsDir);
899
+ if (files.length > 0) {
900
+ const prefixRegex = new RegExp(`^${reportFilePrefix}\\d+\\.json$`);
901
+ reportFiles = files.filter((file) => prefixRegex.test(file));
902
+ }
903
+ }
904
+ if (reportFiles.length === 0) return null;
905
+ reportFiles.sort((a, b) => {
906
+ const idA = parseInt(a.match(/\d+/)?.[0] || "0", 10);
907
+ const idB = parseInt(b.match(/\d+/)?.[0] || "0", 10);
908
+ return idB - idA;
909
+ });
910
+ return (0, import_path2.join)(scanReportsDir, reportFiles[0]);
911
+ } catch (e) {
912
+ console.error("Error while finding latest scan report:", e);
913
+ return null;
914
+ }
915
+ }
916
+
917
+ // src/utils/provider-utils.ts
918
+ function groupIssuesByFile(issues) {
919
+ const fileIssuesMap = /* @__PURE__ */ new Map();
920
+ for (const issue of issues) {
921
+ const file = issue.location?.file ?? "unknown";
922
+ if (!fileIssuesMap.has(file)) fileIssuesMap.set(file, []);
923
+ fileIssuesMap.get(file).push(issue);
924
+ }
925
+ return Array.from(fileIssuesMap.entries()).map(([fileName, issueList]) => ({
926
+ fileName,
927
+ issues: issueList,
928
+ metrics: {}
929
+ }));
930
+ }
931
+ function buildSimpleProviderScore(toolName, summary, rawData = {}) {
932
+ return {
933
+ toolName,
934
+ score: summary.score ?? 0,
935
+ rawMetrics: { ...summary, ...rawData },
936
+ factors: [],
937
+ recommendations: (summary.recommendations ?? []).map((action) => ({
938
+ action,
939
+ estimatedImpact: 5,
940
+ priority: "medium"
941
+ }))
942
+ };
943
+ }
944
+ function buildSpokeOutput(toolName, version, summary, results, metadata = {}) {
945
+ return SpokeOutputSchema.parse({
946
+ results,
947
+ summary,
948
+ metadata: {
949
+ toolName,
950
+ version,
951
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
952
+ ...metadata
953
+ }
954
+ });
955
+ }
956
+ function createProvider(config) {
957
+ return {
958
+ id: config.id,
959
+ alias: config.alias,
960
+ defaultWeight: config.defaultWeight,
961
+ async analyze(options) {
962
+ const report = await config.analyzeReport(options);
963
+ return buildSpokeOutput(
964
+ config.id,
965
+ config.version,
966
+ config.getSummary(report),
967
+ config.getResults(report),
968
+ config.getMetadata?.(report) ?? {}
969
+ );
970
+ },
971
+ score(output, options) {
972
+ return config.score(output, options);
973
+ }
974
+ };
975
+ }
865
976
 
866
977
  // src/utils/ast-parser.ts
867
978
  var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
@@ -989,8 +1100,10 @@ var TypeScriptParser = class {
989
1100
  // camelCase for variables and functions
990
1101
  variablePattern: /^[a-z][a-zA-Z0-9]*$/,
991
1102
  functionPattern: /^[a-z][a-zA-Z0-9]*$/,
992
- // PascalCase for classes
1103
+ // PascalCase for classes, types and interfaces
993
1104
  classPattern: /^[A-Z][a-zA-Z0-9]*$/,
1105
+ typePattern: /^[A-Z][a-zA-Z0-9]*$/,
1106
+ interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
994
1107
  // UPPER_CASE for constants
995
1108
  constantPattern: /^[A-Z][A-Z0-9_]*$/,
996
1109
  // Common exceptions (React hooks, etc.)
@@ -1289,6 +1402,101 @@ async function setupParser(language) {
1289
1402
  }
1290
1403
  }
1291
1404
 
1405
+ // src/parsers/metadata-utils.ts
1406
+ function analyzeNodeMetadata(node, code, options) {
1407
+ const metadata = {
1408
+ isPure: true,
1409
+ hasSideEffects: false
1410
+ };
1411
+ try {
1412
+ let prev = node.previousSibling || null;
1413
+ while (prev && /comment/i.test(prev.type)) {
1414
+ const text = prev.text || "";
1415
+ if (text.trim().startsWith("/**") || text.trim().startsWith("/*")) {
1416
+ metadata.documentation = {
1417
+ content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
1418
+ type: "comment"
1419
+ };
1420
+ break;
1421
+ }
1422
+ if (text.trim().startsWith("///")) {
1423
+ metadata.documentation = {
1424
+ content: text.replace(/^\/\/\//, "").trim(),
1425
+ type: "xml-doc"
1426
+ };
1427
+ break;
1428
+ }
1429
+ if (text.trim().startsWith("//")) {
1430
+ metadata.documentation = {
1431
+ content: text.replace(/^\/\//, "").trim(),
1432
+ type: "comment"
1433
+ };
1434
+ break;
1435
+ }
1436
+ prev = prev.previousSibling;
1437
+ }
1438
+ if (node.type === "function_definition") {
1439
+ const body2 = node.childForFieldName ? node.childForFieldName("body") : node.children.find((c) => c.type === "block");
1440
+ if (body2 && body2.children.length > 0) {
1441
+ const firstStmt = body2.children[0];
1442
+ if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
1443
+ metadata.documentation = {
1444
+ content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
1445
+ type: "docstring"
1446
+ };
1447
+ }
1448
+ }
1449
+ }
1450
+ } catch {
1451
+ }
1452
+ const defaultSignatures = [
1453
+ "console.",
1454
+ "fmt.",
1455
+ "panic(",
1456
+ "os.Exit",
1457
+ "log.",
1458
+ "Console.Write",
1459
+ "File.Write",
1460
+ "System.out",
1461
+ "System.err",
1462
+ "Files.write",
1463
+ "process.exit",
1464
+ "exit("
1465
+ ];
1466
+ const signatures = Array.from(
1467
+ /* @__PURE__ */ new Set([...options?.sideEffectSignatures || [], ...defaultSignatures])
1468
+ );
1469
+ const walk = (n) => {
1470
+ try {
1471
+ const t = n.type || "";
1472
+ if (/assign|assignment|assignment_statement|assignment_expression|throw|throw_statement|send_statement|global_statement|nonlocal_statement/i.test(
1473
+ t
1474
+ )) {
1475
+ metadata.isPure = false;
1476
+ metadata.hasSideEffects = true;
1477
+ }
1478
+ const text = n.text || "";
1479
+ for (const s of signatures) {
1480
+ if (text.includes(s)) {
1481
+ metadata.isPure = false;
1482
+ metadata.hasSideEffects = true;
1483
+ break;
1484
+ }
1485
+ }
1486
+ for (let i = 0; i < n.childCount; i++) {
1487
+ const c = n.child(i);
1488
+ if (c) walk(c);
1489
+ }
1490
+ } catch {
1491
+ }
1492
+ };
1493
+ const body = node.childForFieldName?.("body") || node.children.find(
1494
+ (c) => /body|block|class_body|declaration_list|function_body/.test(c.type)
1495
+ );
1496
+ if (body) walk(body);
1497
+ return metadata;
1498
+ }
1499
+
1292
1500
  // src/parsers/python-parser.ts
1293
1501
  var PythonParser = class {
1294
1502
  constructor() {
@@ -1311,38 +1519,9 @@ var PythonParser = class {
1311
1519
  return this.parser.parse(code);
1312
1520
  }
1313
1521
  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;
1522
+ return analyzeNodeMetadata(node, code, {
1523
+ sideEffectSignatures: ["print(", "input(", "open("]
1524
+ });
1346
1525
  }
1347
1526
  parse(code, filePath) {
1348
1527
  if (!this.initialized || !this.parser) {
@@ -1691,6 +1870,113 @@ var PythonParser = class {
1691
1870
  }
1692
1871
  };
1693
1872
 
1873
+ // src/parsers/shared-parser-utils.ts
1874
+ var SIDE_EFFECT_KEYWORDS = [
1875
+ "print(",
1876
+ "console.",
1877
+ "System.out",
1878
+ "System.err",
1879
+ "fmt.",
1880
+ "File.Write",
1881
+ "Files.write",
1882
+ "os.Exit",
1883
+ "panic(",
1884
+ "throw ",
1885
+ "Logging.",
1886
+ "log."
1887
+ ];
1888
+ function analyzeGeneralMetadata(node, code, options = {}) {
1889
+ const metadata = {
1890
+ isPure: true,
1891
+ hasSideEffects: false
1892
+ };
1893
+ try {
1894
+ let prev = node.previousSibling || null;
1895
+ while (prev && /comment/i.test(prev.type)) {
1896
+ const text = prev.text || "";
1897
+ if (text.trim().startsWith("/**")) {
1898
+ metadata.documentation = {
1899
+ content: text.replace(/^[/*]+|[/*]+$/g, "").trim(),
1900
+ type: "jsdoc"
1901
+ };
1902
+ break;
1903
+ }
1904
+ if (text.trim().startsWith("///")) {
1905
+ metadata.documentation = {
1906
+ content: text.replace(/^\/\/\//, "").trim(),
1907
+ type: "xml-doc"
1908
+ };
1909
+ break;
1910
+ }
1911
+ if (text.trim().startsWith("//")) {
1912
+ metadata.documentation = {
1913
+ content: text.replace(/^\/\//, "").trim(),
1914
+ type: "comment"
1915
+ };
1916
+ break;
1917
+ }
1918
+ prev = prev.previousSibling;
1919
+ }
1920
+ } catch {
1921
+ }
1922
+ const signatures = [
1923
+ ...SIDE_EFFECT_KEYWORDS,
1924
+ ...options.sideEffectSignatures || []
1925
+ ];
1926
+ const walk = (n) => {
1927
+ if (/assign|assignment|assignment_statement|assignment_expression/i.test(
1928
+ n.type
1929
+ )) {
1930
+ metadata.isPure = false;
1931
+ metadata.hasSideEffects = true;
1932
+ }
1933
+ const text = n.text;
1934
+ for (const sig of signatures) {
1935
+ if (text.includes(sig)) {
1936
+ metadata.isPure = false;
1937
+ metadata.hasSideEffects = true;
1938
+ break;
1939
+ }
1940
+ }
1941
+ if (!metadata.hasSideEffects) {
1942
+ for (let i = 0; i < n.childCount; i++) {
1943
+ const child = n.child(i);
1944
+ if (child) walk(child);
1945
+ }
1946
+ }
1947
+ };
1948
+ walk(node);
1949
+ return metadata;
1950
+ }
1951
+ function extractParameterNames(node) {
1952
+ const params = [];
1953
+ const candidates = [
1954
+ // common field name
1955
+ node.childForFieldName ? node.childForFieldName("parameters") : null,
1956
+ node.childForFieldName ? node.childForFieldName("parameter_list") : null,
1957
+ node.children.find((c) => c.type === "parameter_list") || null,
1958
+ node.children.find((c) => c.type === "parameters") || null,
1959
+ node.children.find((c) => c.type === "formal_parameters") || null,
1960
+ node.children.find((c) => c.type === "formal_parameter") || null
1961
+ ];
1962
+ const list = candidates.find(Boolean);
1963
+ if (!list) return params;
1964
+ for (const child of list.children) {
1965
+ if (!child) continue;
1966
+ const id = child.childForFieldName?.("name") || child.children.find(
1967
+ (c) => [
1968
+ "identifier",
1969
+ "variable_name",
1970
+ "name",
1971
+ "parameter",
1972
+ "formal_parameter"
1973
+ ].includes(c.type)
1974
+ ) || (child.type === "identifier" ? child : void 0);
1975
+ if (id && typeof id.text === "string") params.push(id.text);
1976
+ }
1977
+ return params;
1978
+ }
1979
+
1694
1980
  // src/parsers/java-parser.ts
1695
1981
  var JavaParser = class {
1696
1982
  constructor() {
@@ -1713,47 +1999,14 @@ var JavaParser = class {
1713
1999
  return this.parser.parse(code);
1714
2000
  }
1715
2001
  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("/**")) {
1723
- metadata.documentation = {
1724
- content: prev.text.replace(/[/*]/g, "").trim(),
1725
- type: "xml-doc"
1726
- // Using xml-doc as a catch-all for structured or we can add 'javadoc'
1727
- };
1728
- break;
1729
- }
1730
- prev = prev.previousSibling;
1731
- }
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") {
1745
- metadata.isPure = false;
1746
- metadata.hasSideEffects = true;
1747
- }
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;
2002
+ return analyzeGeneralMetadata(node, code, {
2003
+ sideEffectSignatures: [
2004
+ "System.out",
2005
+ "System.err",
2006
+ "Files.write",
2007
+ "Logging."
2008
+ ]
2009
+ });
1757
2010
  }
1758
2011
  parse(code, filePath) {
1759
2012
  if (!this.initialized || !this.parser) {
@@ -1853,7 +2106,7 @@ var JavaParser = class {
1853
2106
  const imports = [];
1854
2107
  for (const node of rootNode.children) {
1855
2108
  if (node.type === "import_declaration") {
1856
- let sourceArr = [];
2109
+ const sourceArr = [];
1857
2110
  let isStatic = false;
1858
2111
  let isWildcard = false;
1859
2112
  for (const child of node.children) {
@@ -1951,14 +2204,7 @@ var JavaParser = class {
1951
2204
  }
1952
2205
  }
1953
2206
  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
- });
2207
+ return extractParameterNames(node);
1962
2208
  }
1963
2209
  getNamingConventions() {
1964
2210
  return {
@@ -1996,47 +2242,9 @@ var CSharpParser = class {
1996
2242
  return this.parser.parse(code);
1997
2243
  }
1998
2244
  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;
2245
+ return analyzeGeneralMetadata(node, code, {
2246
+ sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
2247
+ });
2040
2248
  }
2041
2249
  parse(code, filePath) {
2042
2250
  if (!this.initialized || !this.parser) {
@@ -2241,19 +2449,7 @@ var CSharpParser = class {
2241
2449
  return modifiers;
2242
2450
  }
2243
2451
  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;
2452
+ return extractParameterNames(node);
2257
2453
  }
2258
2454
  getNamingConventions() {
2259
2455
  return {
@@ -2290,40 +2486,9 @@ var GoParser = class {
2290
2486
  return this.parser.parse(code);
2291
2487
  }
2292
2488
  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;
2489
+ return analyzeGeneralMetadata(node, code, {
2490
+ sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
2491
+ });
2327
2492
  }
2328
2493
  parse(code, filePath) {
2329
2494
  if (!this.initialized || !this.parser) {
@@ -2545,17 +2710,7 @@ var GoParser = class {
2545
2710
  return exports2;
2546
2711
  }
2547
2712
  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;
2713
+ return extractParameterNames(node);
2559
2714
  }
2560
2715
  getNamingConventions() {
2561
2716
  return {
@@ -2905,34 +3060,47 @@ var CONFIG_FILES = [
2905
3060
  async function loadConfig(rootDir) {
2906
3061
  let currentDir = (0, import_path3.resolve)(rootDir);
2907
3062
  while (true) {
3063
+ const foundConfigs = [];
2908
3064
  for (const configFile of CONFIG_FILES) {
3065
+ if ((0, import_fs3.existsSync)((0, import_path3.join)(currentDir, configFile))) {
3066
+ foundConfigs.push(configFile);
3067
+ }
3068
+ }
3069
+ if (foundConfigs.length > 0) {
3070
+ if (foundConfigs.length > 1) {
3071
+ console.warn(
3072
+ `\u26A0\uFE0F Multiple configuration files found in ${currentDir}: ${foundConfigs.join(
3073
+ ", "
3074
+ )}. Using ${foundConfigs[0]}.`
3075
+ );
3076
+ } else {
3077
+ }
3078
+ const configFile = foundConfigs[0];
2909
3079
  const configPath = (0, import_path3.join)(currentDir, configFile);
2910
- if ((0, import_fs3.existsSync)(configPath)) {
3080
+ try {
3081
+ let config;
3082
+ if (configFile.endsWith(".js")) {
3083
+ const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
3084
+ const module2 = await import(`${fileUrl}?t=${Date.now()}`);
3085
+ config = module2.default || module2;
3086
+ } else {
3087
+ const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
3088
+ config = JSON.parse(content);
3089
+ }
3090
+ if (typeof config !== "object" || config === null) {
3091
+ throw new Error("Config must be an object");
3092
+ }
3093
+ return config;
3094
+ } catch (error) {
3095
+ const errorMessage = error instanceof Error ? error.message : String(error);
3096
+ const e = new Error(
3097
+ `Failed to load config from ${configPath}: ${errorMessage}`
3098
+ );
2911
3099
  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;
3100
+ e.cause = error instanceof Error ? error : void 0;
3101
+ } catch {
2935
3102
  }
3103
+ throw e;
2936
3104
  }
2937
3105
  }
2938
3106
  const parent = (0, import_path3.dirname)(currentDir);
@@ -3847,6 +4015,24 @@ function collectFutureProofRecommendations(params) {
3847
4015
  }
3848
4016
  return recommendations;
3849
4017
  }
4018
+ function collectBaseFutureProofRecommendations(params) {
4019
+ const recommendations = [];
4020
+ for (const rec of params.patternEntropy.recommendations) {
4021
+ recommendations.push({
4022
+ action: rec,
4023
+ estimatedImpact: 5,
4024
+ priority: "medium"
4025
+ });
4026
+ }
4027
+ if (params.conceptCohesion.rating === "poor") {
4028
+ recommendations.push({
4029
+ action: "Improve concept cohesion by grouping related exports",
4030
+ estimatedImpact: 8,
4031
+ priority: "high"
4032
+ });
4033
+ }
4034
+ return recommendations;
4035
+ }
3850
4036
 
3851
4037
  // src/metrics/cognitive-load.ts
3852
4038
  function calculateCognitiveLoad(params) {
@@ -4537,21 +4723,10 @@ function calculateFutureProofScore(params) {
4537
4723
  description: params.conceptCohesion.rating
4538
4724
  }
4539
4725
  ];
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
- }
4726
+ const recommendations = collectBaseFutureProofRecommendations({
4727
+ patternEntropy: params.patternEntropy,
4728
+ conceptCohesion: params.conceptCohesion
4729
+ });
4555
4730
  const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
4556
4731
  return {
4557
4732
  toolName: "future-proof",
@@ -4884,6 +5059,8 @@ function emitIssuesAsAnnotations(issues) {
4884
5059
  TypeScriptParser,
4885
5060
  UnifiedReportSchema,
4886
5061
  VAGUE_FILE_NAMES,
5062
+ buildSimpleProviderScore,
5063
+ buildSpokeOutput,
4887
5064
  calculateAgentGrounding,
4888
5065
  calculateAiSignalClarity,
4889
5066
  calculateBusinessROI,
@@ -4907,6 +5084,7 @@ function emitIssuesAsAnnotations(issues) {
4907
5084
  calculateTestabilityIndex,
4908
5085
  calculateTokenBudget,
4909
5086
  clearHistory,
5087
+ createProvider,
4910
5088
  emitAnnotation,
4911
5089
  emitIssuesAsAnnotations,
4912
5090
  emitProgress,
@@ -4915,6 +5093,8 @@ function emitIssuesAsAnnotations(issues) {
4915
5093
  exportHistory,
4916
5094
  extractFunctions,
4917
5095
  extractImports,
5096
+ findLatestReport,
5097
+ findLatestScanReport,
4918
5098
  formatAcceptanceRate,
4919
5099
  formatCost,
4920
5100
  formatHours,
@@ -4941,6 +5121,7 @@ function emitIssuesAsAnnotations(issues) {
4941
5121
  getSupportedLanguages,
4942
5122
  getToolWeight,
4943
5123
  getWasmPath,
5124
+ groupIssuesByFile,
4944
5125
  handleCLIError,
4945
5126
  handleJSONOutput,
4946
5127
  initTreeSitter,