@aiready/core 0.23.0 → 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,
@@ -657,7 +663,8 @@ async function scanFiles(options) {
657
663
  const files = await (0, import_glob.glob)(include, {
658
664
  cwd: rootDir,
659
665
  ignore: finalExclude,
660
- absolute: true
666
+ absolute: true,
667
+ nodir: true
661
668
  });
662
669
  const gitignoreFiles = await (0, import_glob.glob)("**/.gitignore", {
663
670
  cwd: rootDir,
@@ -861,6 +868,111 @@ function getSeverityColor(severity, chalk) {
861
868
  return chalk.white;
862
869
  }
863
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
+ }
864
976
 
865
977
  // src/utils/ast-parser.ts
866
978
  var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
@@ -988,8 +1100,10 @@ var TypeScriptParser = class {
988
1100
  // camelCase for variables and functions
989
1101
  variablePattern: /^[a-z][a-zA-Z0-9]*$/,
990
1102
  functionPattern: /^[a-z][a-zA-Z0-9]*$/,
991
- // PascalCase for classes
1103
+ // PascalCase for classes, types and interfaces
992
1104
  classPattern: /^[A-Z][a-zA-Z0-9]*$/,
1105
+ typePattern: /^[A-Z][a-zA-Z0-9]*$/,
1106
+ interfacePattern: /^[A-Z][a-zA-Z0-9]*$/,
993
1107
  // UPPER_CASE for constants
994
1108
  constantPattern: /^[A-Z][A-Z0-9_]*$/,
995
1109
  // Common exceptions (React hooks, etc.)
@@ -1288,6 +1402,101 @@ async function setupParser(language) {
1288
1402
  }
1289
1403
  }
1290
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
+
1291
1500
  // src/parsers/python-parser.ts
1292
1501
  var PythonParser = class {
1293
1502
  constructor() {
@@ -1310,38 +1519,9 @@ var PythonParser = class {
1310
1519
  return this.parser.parse(code);
1311
1520
  }
1312
1521
  analyzeMetadata(node, code) {
1313
- const metadata = {
1314
- isPure: true,
1315
- hasSideEffects: false
1316
- };
1317
- const body = node.childForFieldName("body");
1318
- if (body && body.children.length > 0) {
1319
- const firstStmt = body.children[0];
1320
- if (firstStmt.type === "expression_statement" && firstStmt.firstChild?.type === "string") {
1321
- metadata.documentation = {
1322
- content: firstStmt.firstChild.text.replace(/['"`]/g, "").trim(),
1323
- type: "docstring"
1324
- };
1325
- }
1326
- }
1327
- const walk = (n) => {
1328
- if (n.type === "global_statement" || n.type === "nonlocal_statement") {
1329
- metadata.isPure = false;
1330
- metadata.hasSideEffects = true;
1331
- }
1332
- if (n.type === "call") {
1333
- const functionNode = n.childForFieldName("function");
1334
- if (functionNode && ["print", "input", "open"].includes(functionNode.text)) {
1335
- metadata.isPure = false;
1336
- metadata.hasSideEffects = true;
1337
- }
1338
- }
1339
- for (const child of n.children) {
1340
- walk(child);
1341
- }
1342
- };
1343
- if (body) walk(body);
1344
- return metadata;
1522
+ return analyzeNodeMetadata(node, code, {
1523
+ sideEffectSignatures: ["print(", "input(", "open("]
1524
+ });
1345
1525
  }
1346
1526
  parse(code, filePath) {
1347
1527
  if (!this.initialized || !this.parser) {
@@ -1690,6 +1870,113 @@ var PythonParser = class {
1690
1870
  }
1691
1871
  };
1692
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
+
1693
1980
  // src/parsers/java-parser.ts
1694
1981
  var JavaParser = class {
1695
1982
  constructor() {
@@ -1712,47 +1999,14 @@ var JavaParser = class {
1712
1999
  return this.parser.parse(code);
1713
2000
  }
1714
2001
  analyzeMetadata(node, code) {
1715
- const metadata = {
1716
- isPure: true,
1717
- hasSideEffects: false
1718
- };
1719
- let prev = node.previousSibling;
1720
- while (prev && (prev.type === "comment" || prev.type === "line_comment")) {
1721
- if (prev.text.startsWith("/**")) {
1722
- metadata.documentation = {
1723
- content: prev.text.replace(/[/*]/g, "").trim(),
1724
- type: "xml-doc"
1725
- // Using xml-doc as a catch-all for structured or we can add 'javadoc'
1726
- };
1727
- break;
1728
- }
1729
- prev = prev.previousSibling;
1730
- }
1731
- const walk = (n) => {
1732
- if (n.type === "assignment_expression") {
1733
- metadata.isPure = false;
1734
- metadata.hasSideEffects = true;
1735
- }
1736
- if (n.type === "method_invocation") {
1737
- const text = n.text;
1738
- if (text.includes("System.out.print") || text.includes("System.err.print") || text.includes("Files.write")) {
1739
- metadata.isPure = false;
1740
- metadata.hasSideEffects = true;
1741
- }
1742
- }
1743
- if (n.type === "throw_statement") {
1744
- metadata.isPure = false;
1745
- metadata.hasSideEffects = true;
1746
- }
1747
- for (const child of n.children) {
1748
- walk(child);
1749
- }
1750
- };
1751
- const body = node.children.find(
1752
- (c) => c.type === "block" || c.type === "class_body"
1753
- );
1754
- if (body) walk(body);
1755
- return metadata;
2002
+ return analyzeGeneralMetadata(node, code, {
2003
+ sideEffectSignatures: [
2004
+ "System.out",
2005
+ "System.err",
2006
+ "Files.write",
2007
+ "Logging."
2008
+ ]
2009
+ });
1756
2010
  }
1757
2011
  parse(code, filePath) {
1758
2012
  if (!this.initialized || !this.parser) {
@@ -1852,7 +2106,7 @@ var JavaParser = class {
1852
2106
  const imports = [];
1853
2107
  for (const node of rootNode.children) {
1854
2108
  if (node.type === "import_declaration") {
1855
- let sourceArr = [];
2109
+ const sourceArr = [];
1856
2110
  let isStatic = false;
1857
2111
  let isWildcard = false;
1858
2112
  for (const child of node.children) {
@@ -1950,14 +2204,7 @@ var JavaParser = class {
1950
2204
  }
1951
2205
  }
1952
2206
  extractParameters(node) {
1953
- const paramsNode = node.children.find(
1954
- (c) => c.type === "formal_parameters"
1955
- );
1956
- if (!paramsNode) return [];
1957
- return paramsNode.children.filter((c) => c.type === "formal_parameter").map((c) => {
1958
- const idNode = c.children.find((child) => child.type === "identifier");
1959
- return idNode ? idNode.text : "unknown";
1960
- });
2207
+ return extractParameterNames(node);
1961
2208
  }
1962
2209
  getNamingConventions() {
1963
2210
  return {
@@ -1995,47 +2242,9 @@ var CSharpParser = class {
1995
2242
  return this.parser.parse(code);
1996
2243
  }
1997
2244
  analyzeMetadata(node, code) {
1998
- const metadata = {
1999
- isPure: true,
2000
- hasSideEffects: false
2001
- };
2002
- let prev = node.previousSibling;
2003
- while (prev && (prev.type === "comment" || prev.type === "triple_slash_comment")) {
2004
- if (prev.text.trim().startsWith("///") || prev.type === "triple_slash_comment") {
2005
- metadata.documentation = {
2006
- content: prev.text.replace("///", "").trim(),
2007
- type: "xml-doc"
2008
- };
2009
- break;
2010
- }
2011
- prev = prev.previousSibling;
2012
- }
2013
- const walk = (n) => {
2014
- if (n.type === "assignment_expression") {
2015
- metadata.isPure = false;
2016
- metadata.hasSideEffects = true;
2017
- }
2018
- if (n.type === "invocation_expression") {
2019
- const text = n.text;
2020
- if (text.includes("Console.Write") || text.includes("File.Write") || text.includes("Log.")) {
2021
- metadata.isPure = false;
2022
- metadata.hasSideEffects = true;
2023
- }
2024
- }
2025
- if (n.type === "throw_statement") {
2026
- metadata.isPure = false;
2027
- metadata.hasSideEffects = true;
2028
- }
2029
- for (let i = 0; i < n.childCount; i++) {
2030
- const child = n.child(i);
2031
- if (child) walk(child);
2032
- }
2033
- };
2034
- const body = node.children.find(
2035
- (c) => c.type === "block" || c.type === "declaration_list"
2036
- );
2037
- if (body) walk(body);
2038
- return metadata;
2245
+ return analyzeGeneralMetadata(node, code, {
2246
+ sideEffectSignatures: ["Console.Write", "File.Write", "Logging."]
2247
+ });
2039
2248
  }
2040
2249
  parse(code, filePath) {
2041
2250
  if (!this.initialized || !this.parser) {
@@ -2240,19 +2449,7 @@ var CSharpParser = class {
2240
2449
  return modifiers;
2241
2450
  }
2242
2451
  extractParameters(node) {
2243
- const params = [];
2244
- const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
2245
- if (parameterList) {
2246
- for (const param of parameterList.children) {
2247
- if (param.type === "parameter") {
2248
- const nameNode = param.childForFieldName("name") || param.children.find((c) => c.type === "identifier");
2249
- if (nameNode) {
2250
- params.push(nameNode.text);
2251
- }
2252
- }
2253
- }
2254
- }
2255
- return params;
2452
+ return extractParameterNames(node);
2256
2453
  }
2257
2454
  getNamingConventions() {
2258
2455
  return {
@@ -2289,40 +2486,9 @@ var GoParser = class {
2289
2486
  return this.parser.parse(code);
2290
2487
  }
2291
2488
  analyzeMetadata(node, code) {
2292
- const metadata = {
2293
- isPure: true,
2294
- hasSideEffects: false
2295
- };
2296
- let prev = node.previousSibling;
2297
- while (prev && prev.type === "comment") {
2298
- metadata.documentation = {
2299
- content: prev.text.replace(/\/\/|\/\*|\*\//g, "").trim(),
2300
- type: "comment"
2301
- };
2302
- break;
2303
- }
2304
- const walk = (n) => {
2305
- if (n.type === "send_statement" || n.type === "expression_statement" && n.text.includes("<-")) {
2306
- metadata.isPure = false;
2307
- metadata.hasSideEffects = true;
2308
- }
2309
- if (n.type === "assignment_statement" || n.type === "short_var_declaration") {
2310
- }
2311
- if (n.type === "call_expression") {
2312
- const text = n.text;
2313
- if (text.includes("fmt.Print") || text.includes("os.Exit") || text.includes("panic(") || text.includes("log.")) {
2314
- metadata.isPure = false;
2315
- metadata.hasSideEffects = true;
2316
- }
2317
- }
2318
- for (let i = 0; i < n.childCount; i++) {
2319
- const child = n.child(i);
2320
- if (child) walk(child);
2321
- }
2322
- };
2323
- const body = node.childForFieldName("body");
2324
- if (body) walk(body);
2325
- return metadata;
2489
+ return analyzeGeneralMetadata(node, code, {
2490
+ sideEffectSignatures: ["<-", "fmt.Print", "fmt.Fprintf", "os.Exit"]
2491
+ });
2326
2492
  }
2327
2493
  parse(code, filePath) {
2328
2494
  if (!this.initialized || !this.parser) {
@@ -2544,17 +2710,7 @@ var GoParser = class {
2544
2710
  return exports2;
2545
2711
  }
2546
2712
  extractParameters(node) {
2547
- const params = [];
2548
- const parameterList = node.childForFieldName("parameters") || node.children.find((c) => c.type === "parameter_list");
2549
- if (parameterList) {
2550
- for (const param of parameterList.children) {
2551
- if (param.type === "parameter_declaration") {
2552
- const names = param.children.filter((c) => c.type === "identifier");
2553
- names.forEach((n) => params.push(n.text));
2554
- }
2555
- }
2556
- }
2557
- return params;
2713
+ return extractParameterNames(node);
2558
2714
  }
2559
2715
  getNamingConventions() {
2560
2716
  return {
@@ -2904,34 +3060,47 @@ var CONFIG_FILES = [
2904
3060
  async function loadConfig(rootDir) {
2905
3061
  let currentDir = (0, import_path3.resolve)(rootDir);
2906
3062
  while (true) {
3063
+ const foundConfigs = [];
2907
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];
2908
3079
  const configPath = (0, import_path3.join)(currentDir, configFile);
2909
- 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
+ );
2910
3099
  try {
2911
- let config;
2912
- if (configFile.endsWith(".js")) {
2913
- const fileUrl = (0, import_url.pathToFileURL)(configPath).href;
2914
- const module2 = await import(`${fileUrl}?t=${Date.now()}`);
2915
- config = module2.default || module2;
2916
- } else {
2917
- const content = (0, import_fs3.readFileSync)(configPath, "utf-8");
2918
- config = JSON.parse(content);
2919
- }
2920
- if (typeof config !== "object" || config === null) {
2921
- throw new Error("Config must be an object");
2922
- }
2923
- return config;
2924
- } catch (error) {
2925
- const errorMessage = error instanceof Error ? error.message : String(error);
2926
- const e = new Error(
2927
- `Failed to load config from ${configPath}: ${errorMessage}`
2928
- );
2929
- try {
2930
- e.cause = error instanceof Error ? error : void 0;
2931
- } catch {
2932
- }
2933
- throw e;
3100
+ e.cause = error instanceof Error ? error : void 0;
3101
+ } catch {
2934
3102
  }
3103
+ throw e;
2935
3104
  }
2936
3105
  }
2937
3106
  const parent = (0, import_path3.dirname)(currentDir);
@@ -3846,6 +4015,24 @@ function collectFutureProofRecommendations(params) {
3846
4015
  }
3847
4016
  return recommendations;
3848
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
+ }
3849
4036
 
3850
4037
  // src/metrics/cognitive-load.ts
3851
4038
  function calculateCognitiveLoad(params) {
@@ -4536,21 +4723,10 @@ function calculateFutureProofScore(params) {
4536
4723
  description: params.conceptCohesion.rating
4537
4724
  }
4538
4725
  ];
4539
- const recommendations = [];
4540
- for (const rec of params.patternEntropy.recommendations) {
4541
- recommendations.push({
4542
- action: rec,
4543
- estimatedImpact: 5,
4544
- priority: "medium"
4545
- });
4546
- }
4547
- if (params.conceptCohesion.rating === "poor") {
4548
- recommendations.push({
4549
- action: "Improve concept cohesion by grouping related exports",
4550
- estimatedImpact: 8,
4551
- priority: "high"
4552
- });
4553
- }
4726
+ const recommendations = collectBaseFutureProofRecommendations({
4727
+ patternEntropy: params.patternEntropy,
4728
+ conceptCohesion: params.conceptCohesion
4729
+ });
4554
4730
  const semanticDistanceAvg = params.semanticDistances?.length ? params.semanticDistances.reduce((s, d) => s + d.distance, 0) / params.semanticDistances.length : 0;
4555
4731
  return {
4556
4732
  toolName: "future-proof",
@@ -4883,6 +5059,8 @@ function emitIssuesAsAnnotations(issues) {
4883
5059
  TypeScriptParser,
4884
5060
  UnifiedReportSchema,
4885
5061
  VAGUE_FILE_NAMES,
5062
+ buildSimpleProviderScore,
5063
+ buildSpokeOutput,
4886
5064
  calculateAgentGrounding,
4887
5065
  calculateAiSignalClarity,
4888
5066
  calculateBusinessROI,
@@ -4906,6 +5084,7 @@ function emitIssuesAsAnnotations(issues) {
4906
5084
  calculateTestabilityIndex,
4907
5085
  calculateTokenBudget,
4908
5086
  clearHistory,
5087
+ createProvider,
4909
5088
  emitAnnotation,
4910
5089
  emitIssuesAsAnnotations,
4911
5090
  emitProgress,
@@ -4914,6 +5093,8 @@ function emitIssuesAsAnnotations(issues) {
4914
5093
  exportHistory,
4915
5094
  extractFunctions,
4916
5095
  extractImports,
5096
+ findLatestReport,
5097
+ findLatestScanReport,
4917
5098
  formatAcceptanceRate,
4918
5099
  formatCost,
4919
5100
  formatHours,
@@ -4940,6 +5121,7 @@ function emitIssuesAsAnnotations(issues) {
4940
5121
  getSupportedLanguages,
4941
5122
  getToolWeight,
4942
5123
  getWasmPath,
5124
+ groupIssuesByFile,
4943
5125
  handleCLIError,
4944
5126
  handleJSONOutput,
4945
5127
  initTreeSitter,