ghagga-core 2.6.0 → 2.8.0

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 (153) hide show
  1. package/dist/agents/consensus.d.ts +2 -0
  2. package/dist/agents/consensus.d.ts.map +1 -1
  3. package/dist/agents/consensus.js +1 -0
  4. package/dist/agents/consensus.js.map +1 -1
  5. package/dist/agents/diagnostic.d.ts +2 -0
  6. package/dist/agents/diagnostic.d.ts.map +1 -1
  7. package/dist/agents/diagnostic.js +1 -0
  8. package/dist/agents/diagnostic.js.map +1 -1
  9. package/dist/agents/fan-out-lenses.d.ts +92 -0
  10. package/dist/agents/fan-out-lenses.d.ts.map +1 -0
  11. package/dist/agents/fan-out-lenses.js +424 -0
  12. package/dist/agents/fan-out-lenses.js.map +1 -0
  13. package/dist/agents/simple.d.ts +2 -0
  14. package/dist/agents/simple.d.ts.map +1 -1
  15. package/dist/agents/simple.js +1 -0
  16. package/dist/agents/simple.js.map +1 -1
  17. package/dist/agents/workflow.d.ts +2 -0
  18. package/dist/agents/workflow.d.ts.map +1 -1
  19. package/dist/agents/workflow.js +2 -1
  20. package/dist/agents/workflow.js.map +1 -1
  21. package/dist/checklist/config.d.ts +22 -0
  22. package/dist/checklist/config.d.ts.map +1 -0
  23. package/dist/checklist/config.js +85 -0
  24. package/dist/checklist/config.js.map +1 -0
  25. package/dist/checklist/context.d.ts +22 -0
  26. package/dist/checklist/context.d.ts.map +1 -0
  27. package/dist/checklist/context.js +76 -0
  28. package/dist/checklist/context.js.map +1 -0
  29. package/dist/checklist/defaults.d.ts +12 -0
  30. package/dist/checklist/defaults.d.ts.map +1 -0
  31. package/dist/checklist/defaults.js +172 -0
  32. package/dist/checklist/defaults.js.map +1 -0
  33. package/dist/checklist/index.d.ts +14 -0
  34. package/dist/checklist/index.d.ts.map +1 -0
  35. package/dist/checklist/index.js +15 -0
  36. package/dist/checklist/index.js.map +1 -0
  37. package/dist/checklist/scorer.d.ts +58 -0
  38. package/dist/checklist/scorer.d.ts.map +1 -0
  39. package/dist/checklist/scorer.js +142 -0
  40. package/dist/checklist/scorer.js.map +1 -0
  41. package/dist/checklist/types.d.ts +39 -0
  42. package/dist/checklist/types.d.ts.map +1 -0
  43. package/dist/checklist/types.js +17 -0
  44. package/dist/checklist/types.js.map +1 -0
  45. package/dist/exploitability/analyzer.d.ts +75 -0
  46. package/dist/exploitability/analyzer.d.ts.map +1 -0
  47. package/dist/exploitability/analyzer.js +299 -0
  48. package/dist/exploitability/analyzer.js.map +1 -0
  49. package/dist/exploitability/index.d.ts +10 -0
  50. package/dist/exploitability/index.d.ts.map +1 -0
  51. package/dist/exploitability/index.js +10 -0
  52. package/dist/exploitability/index.js.map +1 -0
  53. package/dist/exploitability/types.d.ts +32 -0
  54. package/dist/exploitability/types.d.ts.map +1 -0
  55. package/dist/exploitability/types.js +9 -0
  56. package/dist/exploitability/types.js.map +1 -0
  57. package/dist/index.d.ts +15 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +9 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/memory/context.d.ts +2 -0
  62. package/dist/memory/context.d.ts.map +1 -1
  63. package/dist/memory/context.js +2 -1
  64. package/dist/memory/context.js.map +1 -1
  65. package/dist/memory/contradiction.d.ts +46 -0
  66. package/dist/memory/contradiction.d.ts.map +1 -0
  67. package/dist/memory/contradiction.js +110 -0
  68. package/dist/memory/contradiction.js.map +1 -0
  69. package/dist/memory/decay.d.ts +25 -0
  70. package/dist/memory/decay.d.ts.map +1 -0
  71. package/dist/memory/decay.js +51 -0
  72. package/dist/memory/decay.js.map +1 -0
  73. package/dist/memory/search.d.ts.map +1 -1
  74. package/dist/memory/search.js +1 -0
  75. package/dist/memory/search.js.map +1 -1
  76. package/dist/memory/sqlite.d.ts +21 -0
  77. package/dist/memory/sqlite.d.ts.map +1 -1
  78. package/dist/memory/sqlite.js +82 -7
  79. package/dist/memory/sqlite.js.map +1 -1
  80. package/dist/memory/versioning.d.ts +94 -0
  81. package/dist/memory/versioning.d.ts.map +1 -0
  82. package/dist/memory/versioning.js +350 -0
  83. package/dist/memory/versioning.js.map +1 -0
  84. package/dist/pipeline.d.ts.map +1 -1
  85. package/dist/pipeline.js +117 -0
  86. package/dist/pipeline.js.map +1 -1
  87. package/dist/providers/index.d.ts.map +1 -1
  88. package/dist/providers/index.js +7 -2
  89. package/dist/providers/index.js.map +1 -1
  90. package/dist/recursive/index.d.ts +45 -0
  91. package/dist/recursive/index.d.ts.map +1 -0
  92. package/dist/recursive/index.js +159 -0
  93. package/dist/recursive/index.js.map +1 -0
  94. package/dist/recursive/patch-extractor.d.ts +49 -0
  95. package/dist/recursive/patch-extractor.d.ts.map +1 -0
  96. package/dist/recursive/patch-extractor.js +133 -0
  97. package/dist/recursive/patch-extractor.js.map +1 -0
  98. package/dist/recursive/re-reviewer.d.ts +31 -0
  99. package/dist/recursive/re-reviewer.d.ts.map +1 -0
  100. package/dist/recursive/re-reviewer.js +66 -0
  101. package/dist/recursive/re-reviewer.js.map +1 -0
  102. package/dist/recursive/types.d.ts +62 -0
  103. package/dist/recursive/types.d.ts.map +1 -0
  104. package/dist/recursive/types.js +11 -0
  105. package/dist/recursive/types.js.map +1 -0
  106. package/dist/scope/context-builder.d.ts +37 -0
  107. package/dist/scope/context-builder.d.ts.map +1 -0
  108. package/dist/scope/context-builder.js +108 -0
  109. package/dist/scope/context-builder.js.map +1 -0
  110. package/dist/scope/diff-mapper.d.ts +29 -0
  111. package/dist/scope/diff-mapper.d.ts.map +1 -0
  112. package/dist/scope/diff-mapper.js +76 -0
  113. package/dist/scope/diff-mapper.js.map +1 -0
  114. package/dist/scope/extractor.d.ts +25 -0
  115. package/dist/scope/extractor.d.ts.map +1 -0
  116. package/dist/scope/extractor.js +264 -0
  117. package/dist/scope/extractor.js.map +1 -0
  118. package/dist/scope/index.d.ts +13 -0
  119. package/dist/scope/index.d.ts.map +1 -0
  120. package/dist/scope/index.js +16 -0
  121. package/dist/scope/index.js.map +1 -0
  122. package/dist/scope/parser.d.ts +47 -0
  123. package/dist/scope/parser.d.ts.map +1 -0
  124. package/dist/scope/parser.js +97 -0
  125. package/dist/scope/parser.js.map +1 -0
  126. package/dist/scope/queries.d.ts +23 -0
  127. package/dist/scope/queries.d.ts.map +1 -0
  128. package/dist/scope/queries.js +134 -0
  129. package/dist/scope/queries.js.map +1 -0
  130. package/dist/scope/types.d.ts +55 -0
  131. package/dist/scope/types.d.ts.map +1 -0
  132. package/dist/scope/types.js +8 -0
  133. package/dist/scope/types.js.map +1 -0
  134. package/dist/tools/execution.d.ts.map +1 -1
  135. package/dist/tools/execution.js +2 -0
  136. package/dist/tools/execution.js.map +1 -1
  137. package/dist/tools/plugins/index.d.ts +1 -0
  138. package/dist/tools/plugins/index.d.ts.map +1 -1
  139. package/dist/tools/plugins/index.js +6 -5
  140. package/dist/tools/plugins/index.js.map +1 -1
  141. package/dist/tools/plugins/sonarqube.d.ts +54 -0
  142. package/dist/tools/plugins/sonarqube.d.ts.map +1 -0
  143. package/dist/tools/plugins/sonarqube.js +145 -0
  144. package/dist/tools/plugins/sonarqube.js.map +1 -0
  145. package/dist/tools/plugins/trivy.js +1 -1
  146. package/dist/tools/plugins/trivy.js.map +1 -1
  147. package/dist/tools/types.d.ts +7 -1
  148. package/dist/tools/types.d.ts.map +1 -1
  149. package/dist/types.d.ts +80 -1
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/types.js +9 -0
  152. package/dist/types.js.map +1 -1
  153. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-extractor.d.ts","sourceRoot":"","sources":["../../src/recursive/patch-extractor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,eAAe,EAAE,CAqB3E;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CA+D5F;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAWpE"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Patch Extractor — extracts suggestion patches from review findings
3
+ * and applies them virtually to produce a synthetic diff.
4
+ *
5
+ * No filesystem access — operates purely on diff strings.
6
+ */
7
+ // ─── Patch Extraction ──────────────────────────────────────────
8
+ /**
9
+ * Extract actionable patches from review findings.
10
+ *
11
+ * Only findings with both a `suggestion` and a `file` are included.
12
+ * Findings without a line number are included but marked as file-level.
13
+ *
14
+ * @param findings - Review findings from the AI agent
15
+ * @returns Array of suggestion patches ready for virtual application
16
+ */
17
+ export function extractPatches(findings) {
18
+ const patches = [];
19
+ for (let i = 0; i < findings.length; i++) {
20
+ const finding = findings[i];
21
+ if (!finding)
22
+ continue;
23
+ if (!finding.suggestion || !finding.file)
24
+ continue;
25
+ // Skip empty/whitespace-only suggestions
26
+ if (finding.suggestion.trim().length === 0)
27
+ continue;
28
+ patches.push({
29
+ file: finding.file,
30
+ line: finding.line,
31
+ originalMessage: finding.message,
32
+ suggestion: finding.suggestion,
33
+ findingIndex: i,
34
+ });
35
+ }
36
+ return patches;
37
+ }
38
+ // ─── Virtual Patch Application ─────────────────────────────────
39
+ /**
40
+ * Apply suggestion patches to an original diff, producing a synthetic
41
+ * patched diff for re-review.
42
+ *
43
+ * Strategy:
44
+ * - For each file in the diff, collect patches targeting that file.
45
+ * - Sort patches by line number descending (bottom-up) to avoid offset shifts.
46
+ * - For each patch, find the target line in the diff's added lines (+)
47
+ * and append a comment showing the suggested replacement.
48
+ *
49
+ * The patched diff is a SYNTHETIC representation — it shows what the code
50
+ * would look like if the suggestions were applied. This is NOT a real
51
+ * git diff; it's a review-friendly format for the LLM to analyze.
52
+ *
53
+ * @param originalDiff - The original unified diff string
54
+ * @param patches - Suggestion patches to apply
55
+ * @returns Synthetic diff with suggestions applied
56
+ */
57
+ export function applyVirtualPatches(originalDiff, patches) {
58
+ if (patches.length === 0)
59
+ return originalDiff;
60
+ // Group patches by file
61
+ const patchesByFile = new Map();
62
+ for (const patch of patches) {
63
+ const existing = patchesByFile.get(patch.file) ?? [];
64
+ existing.push(patch);
65
+ patchesByFile.set(patch.file, existing);
66
+ }
67
+ // Build the synthetic diff
68
+ const lines = originalDiff.split('\n');
69
+ const result = [];
70
+ let currentFile = null;
71
+ let currentFilePatches = [];
72
+ let lineCounter = 0; // Tracks the target-side line number in current hunk
73
+ for (const line of lines) {
74
+ // Detect file boundaries
75
+ const fileMatch = /^diff --git a\/.+ b\/(.+)$/.exec(line);
76
+ if (fileMatch?.[1]) {
77
+ currentFile = fileMatch[1];
78
+ currentFilePatches = patchesByFile.get(currentFile) ?? [];
79
+ lineCounter = 0;
80
+ }
81
+ // Track hunk line numbers
82
+ const hunkMatch = /^@@ -\d+(?:,\d+)? \+(\d+)/.exec(line);
83
+ if (hunkMatch?.[1]) {
84
+ lineCounter = parseInt(hunkMatch[1], 10) - 1;
85
+ }
86
+ // Count lines for position tracking (added or context lines increment target counter)
87
+ if (line.startsWith('+') && !line.startsWith('+++')) {
88
+ lineCounter++;
89
+ }
90
+ else if (line.startsWith('-') && !line.startsWith('---')) {
91
+ // Removed lines don't increment target counter
92
+ }
93
+ else if (!line.startsWith('\\') &&
94
+ !line.startsWith('diff ') &&
95
+ !line.startsWith('index ') &&
96
+ !line.startsWith('---') &&
97
+ !line.startsWith('+++') &&
98
+ !line.startsWith('@@')) {
99
+ lineCounter++;
100
+ }
101
+ result.push(line);
102
+ // Check if any patch targets this line
103
+ if (currentFile && currentFilePatches.length > 0) {
104
+ const matchingPatches = currentFilePatches.filter((p) => p.line === lineCounter);
105
+ for (const patch of matchingPatches) {
106
+ // Insert the suggestion as a synthetic replacement block
107
+ result.push(`+[SUGGESTED FIX] ${patch.suggestion}`);
108
+ }
109
+ }
110
+ }
111
+ return result.join('\n');
112
+ }
113
+ /**
114
+ * Build a focused review context for re-review.
115
+ *
116
+ * Instead of passing the entire diff, build a summary of what
117
+ * suggestions were applied and where, so the re-review LLM
118
+ * can focus on validating those specific changes.
119
+ *
120
+ * @param patches - The patches that were applied
121
+ * @returns Context string for the re-review prompt
122
+ */
123
+ export function buildPatchContext(patches) {
124
+ if (patches.length === 0)
125
+ return '';
126
+ const lines = ['## Applied Suggestions (validate these for regressions)', ''];
127
+ for (const patch of patches) {
128
+ lines.push(`- **${patch.file}${patch.line ? `:${patch.line}` : ''}**: ${patch.suggestion}`);
129
+ lines.push(` (Original issue: ${patch.originalMessage})`);
130
+ }
131
+ return lines.join('\n');
132
+ }
133
+ //# sourceMappingURL=patch-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-extractor.js","sourceRoot":"","sources":["../../src/recursive/patch-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Re-Reviewer — runs a lightweight review on patched diffs
3
+ * to detect regressions introduced by suggested fixes.
4
+ */
5
+ import type { GenerateTextFn } from '../providers/generate-fn.js';
6
+ import type { ReviewFinding } from '../types.js';
7
+ export interface ReReviewInput {
8
+ /** Synthetic diff with suggestions applied */
9
+ patchedDiff: string;
10
+ /** Context about which patches were applied */
11
+ patchContext: string;
12
+ /** Generation function for the LLM call */
13
+ generateFn: GenerateTextFn;
14
+ }
15
+ export interface ReReviewResult {
16
+ /** New findings from the re-review */
17
+ findings: ReviewFinding[];
18
+ /** Tokens used for this re-review call */
19
+ tokensUsed: number;
20
+ }
21
+ /**
22
+ * Run a lightweight re-review on a patched diff.
23
+ *
24
+ * Uses simple mode (single LLM call) to check whether the
25
+ * applied suggestions introduce new problems.
26
+ *
27
+ * @param input - Patched diff and LLM config
28
+ * @returns New findings from the re-review
29
+ */
30
+ export declare function runReReview(input: ReReviewInput): Promise<ReReviewResult>;
31
+ //# sourceMappingURL=re-reviewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"re-reviewer.d.ts","sourceRoot":"","sources":["../../src/recursive/re-reviewer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA+BjD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IAEpB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IAErB,2CAA2C;IAC3C,UAAU,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAE1B,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CA6B/E"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Re-Reviewer — runs a lightweight review on patched diffs
3
+ * to detect regressions introduced by suggested fixes.
4
+ */
5
+ import { parseFindingsBlock } from '../agents/simple.js';
6
+ // ─── Re-Review Prompt ──────────────────────────────────────────
7
+ const RE_REVIEW_SYSTEM = `You are a code review validator. You are reviewing code changes that include SUGGESTED FIXES from a previous code review.
8
+
9
+ Your ONLY job is to check whether the suggested fixes introduce NEW problems:
10
+ - New bugs or logic errors from the fix
11
+ - Security issues introduced by the fix
12
+ - Performance regressions from the fix
13
+ - Breaking changes caused by the fix
14
+
15
+ DO NOT repeat the original findings. ONLY report NEW issues introduced by the suggested changes.
16
+ Lines marked with [SUGGESTED FIX] are the applied suggestions — focus your analysis there.
17
+
18
+ Format your response EXACTLY as:
19
+
20
+ STATUS: [PASSED or FAILED]
21
+ SUMMARY: [1-2 sentences about whether suggestions introduced issues]
22
+ FINDINGS:
23
+ - SEVERITY: [critical|high|medium|low|info]
24
+ CATEGORY: [security|performance|bug|style|error-handling|maintainability]
25
+ FILE: [file path]
26
+ LINE: [line number or "N/A"]
27
+ MESSAGE: [description of the NEW issue introduced by the suggestion]
28
+ SUGGESTION: [how to fix the regression]
29
+
30
+ If no new issues were introduced, return STATUS: PASSED with an empty FINDINGS section.`;
31
+ // ─── Main Function ─────────────────────────────────────────────
32
+ /**
33
+ * Run a lightweight re-review on a patched diff.
34
+ *
35
+ * Uses simple mode (single LLM call) to check whether the
36
+ * applied suggestions introduce new problems.
37
+ *
38
+ * @param input - Patched diff and LLM config
39
+ * @returns New findings from the re-review
40
+ */
41
+ export async function runReReview(input) {
42
+ const { patchedDiff, patchContext, generateFn } = input;
43
+ const system = [RE_REVIEW_SYSTEM, patchContext].filter(Boolean).join('\n\n');
44
+ const prompt = `Please validate the following code changes that include applied suggestions:\n\n\`\`\`diff\n${patchedDiff}\n\`\`\``;
45
+ try {
46
+ const result = await generateFn(system, prompt);
47
+ // Parse findings from the response
48
+ const findings = parseFindingsBlock(result.text);
49
+ // Mark all findings as coming from recursive review
50
+ for (const finding of findings) {
51
+ finding.source = 'recursive-review';
52
+ }
53
+ return {
54
+ findings,
55
+ tokensUsed: result.tokensUsed,
56
+ };
57
+ }
58
+ catch {
59
+ // Non-blocking — return empty findings on failure
60
+ return {
61
+ findings: [],
62
+ tokensUsed: 0,
63
+ };
64
+ }
65
+ }
66
+ //# sourceMappingURL=re-reviewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"re-reviewer.js","sourceRoot":"","sources":["../../src/recursive/re-reviewer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAIzD,kEAAkE;AAElE,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;wFAuB+D,CAAC;AAuBzF,kEAAkE;AAElE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAoB;IACpD,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAExD,MAAM,MAAM,GAAG,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE7E,MAAM,MAAM,GAAG,+FAA+F,WAAW,UAAU,CAAC;IAEpI,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEhD,mCAAmC;QACnC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEjD,oDAAoD;QACpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;QACtC,CAAC;QAED,OAAO;YACL,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;QAClD,OAAO;YACL,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,CAAC;SACd,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Recursive Review Loop — Types
3
+ *
4
+ * Types for the self-validating review cycle that re-reviews
5
+ * suggested patches to catch regressions before they reach the user.
6
+ */
7
+ import type { ReviewFinding } from '../types.js';
8
+ /**
9
+ * A patch derived from a review finding's suggestion.
10
+ * Represents a single code change that the AI reviewer recommended.
11
+ */
12
+ export interface SuggestionPatch {
13
+ /** File path from the finding */
14
+ file: string;
15
+ /** Line number from the finding (undefined = file-level suggestion) */
16
+ line: number | undefined;
17
+ /** The original finding message for context */
18
+ originalMessage: string;
19
+ /** The suggested fix text */
20
+ suggestion: string;
21
+ /** Index of the finding in the original results (for tracing) */
22
+ findingIndex: number;
23
+ }
24
+ /**
25
+ * A finding from re-review that represents a regression
26
+ * introduced by a suggested fix.
27
+ */
28
+ export interface RegressionFinding extends ReviewFinding {
29
+ /** Always true — discriminant for regression findings */
30
+ isRegression: true;
31
+ /** The original suggestion that caused this regression */
32
+ originatingSuggestion: {
33
+ file: string;
34
+ line: number | undefined;
35
+ suggestion: string;
36
+ };
37
+ }
38
+ /**
39
+ * Report from the recursive review loop.
40
+ * Attached to ReviewResult when recursive review is enabled.
41
+ */
42
+ export interface RecursiveReviewReport {
43
+ /** Number of re-review iterations executed (1 or 2) */
44
+ iterations: number;
45
+ /** Whether the review converged (no new issues on last iteration) */
46
+ converged: boolean;
47
+ /** Findings identified as regressions from suggested fixes */
48
+ regressions: RegressionFinding[];
49
+ /** Total new issues found across all re-review iterations */
50
+ totalNewIssues: number;
51
+ }
52
+ /**
53
+ * Configuration for the recursive review step.
54
+ * Extracted from ReviewSettings for internal use.
55
+ */
56
+ export interface RecursiveReviewConfig {
57
+ /** Maximum number of re-review iterations. Default: 2 */
58
+ maxIterations: number;
59
+ }
60
+ /** Default configuration values */
61
+ export declare const DEFAULT_RECURSIVE_CONFIG: RecursiveReviewConfig;
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/recursive/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IAEb,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzB,+CAA+C;IAC/C,eAAe,EAAE,MAAM,CAAC;IAExB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IAEnB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB;AAID;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,yDAAyD;IACzD,YAAY,EAAE,IAAI,CAAC;IAEnB,0DAA0D;IAC1D,qBAAqB,EAAE;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAID;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IAEnB,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;IAEnB,8DAA8D;IAC9D,WAAW,EAAE,iBAAiB,EAAE,CAAC;IAEjC,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB;AAID;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,mCAAmC;AACnC,eAAO,MAAM,wBAAwB,EAAE,qBAEtC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Recursive Review Loop — Types
3
+ *
4
+ * Types for the self-validating review cycle that re-reviews
5
+ * suggested patches to catch regressions before they reach the user.
6
+ */
7
+ /** Default configuration values */
8
+ export const DEFAULT_RECURSIVE_CONFIG = {
9
+ maxIterations: 2,
10
+ };
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/recursive/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4EH,mCAAmC;AACnC,MAAM,CAAC,MAAM,wBAAwB,GAA0B;IAC7D,aAAa,EAAE,CAAC;CACjB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Scoped Context Builder
3
+ *
4
+ * Builds a focused review context string containing only the source
5
+ * code of symbols affected by a diff. This dramatically reduces the
6
+ * number of tokens sent to the LLM for review.
7
+ *
8
+ * Pure function with no side effects.
9
+ */
10
+ import type { ScopedFile } from './types.js';
11
+ /**
12
+ * Build a focused review context containing only the source code
13
+ * of symbols affected by diff changes.
14
+ *
15
+ * Output format:
16
+ * ```
17
+ * ## path/to/file.ts
18
+ *
19
+ * ### function foo (lines 10-25)
20
+ * ```ts
21
+ * <source lines 10-25>
22
+ * ```
23
+ *
24
+ * ### class Bar (lines 30-80)
25
+ * ```ts
26
+ * <source lines 30-80>
27
+ * ```
28
+ * ---
29
+ * ## path/to/other.ts
30
+ * ...
31
+ * ```
32
+ *
33
+ * @param scopedFiles - Files with their affected symbols and source lines
34
+ * @returns Formatted review context string, or empty string if no affected symbols
35
+ */
36
+ export declare function buildScopedContext(scopedFiles: ScopedFile[]): string;
37
+ //# sourceMappingURL=context-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/scope/context-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAe7C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAepE"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Scoped Context Builder
3
+ *
4
+ * Builds a focused review context string containing only the source
5
+ * code of symbols affected by a diff. This dramatically reduces the
6
+ * number of tokens sent to the LLM for review.
7
+ *
8
+ * Pure function with no side effects.
9
+ */
10
+ // ─── Constants ────────────────────────────────────────────────
11
+ /** Separator between file sections in the output. */
12
+ const FILE_SEPARATOR = '\n---\n';
13
+ /** Header format for each file section. */
14
+ const FILE_HEADER_PREFIX = '## ';
15
+ /** Header format for each symbol section. */
16
+ const SYMBOL_HEADER_PREFIX = '### ';
17
+ // ─── Builder ──────────────────────────────────────────────────
18
+ /**
19
+ * Build a focused review context containing only the source code
20
+ * of symbols affected by diff changes.
21
+ *
22
+ * Output format:
23
+ * ```
24
+ * ## path/to/file.ts
25
+ *
26
+ * ### function foo (lines 10-25)
27
+ * ```ts
28
+ * <source lines 10-25>
29
+ * ```
30
+ *
31
+ * ### class Bar (lines 30-80)
32
+ * ```ts
33
+ * <source lines 30-80>
34
+ * ```
35
+ * ---
36
+ * ## path/to/other.ts
37
+ * ...
38
+ * ```
39
+ *
40
+ * @param scopedFiles - Files with their affected symbols and source lines
41
+ * @returns Formatted review context string, or empty string if no affected symbols
42
+ */
43
+ export function buildScopedContext(scopedFiles) {
44
+ if (scopedFiles.length === 0)
45
+ return '';
46
+ const sections = [];
47
+ for (const file of scopedFiles) {
48
+ if (file.symbols.length === 0)
49
+ continue;
50
+ const fileSection = buildFileSection(file);
51
+ if (fileSection) {
52
+ sections.push(fileSection);
53
+ }
54
+ }
55
+ return sections.join(FILE_SEPARATOR);
56
+ }
57
+ // ─── Internals ────────────────────────────────────────────────
58
+ /**
59
+ * Build the context section for a single file.
60
+ */
61
+ function buildFileSection(file) {
62
+ const ext = inferCodeFenceLanguage(file.filePath);
63
+ const symbolSections = [];
64
+ // Deduplicate symbols by name+startLine to avoid repeating
65
+ // the same symbol if it appears in multiple hunks
66
+ const seen = new Set();
67
+ for (const affected of file.symbols) {
68
+ const { symbol } = affected;
69
+ const key = `${symbol.name}:${symbol.startLine}`;
70
+ if (seen.has(key))
71
+ continue;
72
+ seen.add(key);
73
+ const startIdx = Math.max(0, symbol.startLine - 1);
74
+ const endIdx = Math.min(file.sourceLines.length, symbol.endLine);
75
+ const sourceSlice = file.sourceLines.slice(startIdx, endIdx).join('\n');
76
+ const kindLabel = symbol.parent
77
+ ? `${symbol.kind} ${symbol.parent}.${symbol.name}`
78
+ : `${symbol.kind} ${symbol.name}`;
79
+ const lineRange = `lines ${symbol.startLine}-${symbol.endLine}`;
80
+ symbolSections.push(`${SYMBOL_HEADER_PREFIX}${kindLabel} (${lineRange})\n\`\`\`${ext}\n${sourceSlice}\n\`\`\``);
81
+ }
82
+ if (symbolSections.length === 0)
83
+ return undefined;
84
+ return `${FILE_HEADER_PREFIX}${file.filePath}\n\n${symbolSections.join('\n\n')}`;
85
+ }
86
+ /**
87
+ * Infer the code fence language hint from a file path.
88
+ */
89
+ function inferCodeFenceLanguage(filePath) {
90
+ const ext = filePath.split('.').pop()?.toLowerCase() ?? '';
91
+ const MAP = {
92
+ ts: 'ts',
93
+ tsx: 'tsx',
94
+ js: 'js',
95
+ jsx: 'jsx',
96
+ py: 'python',
97
+ go: 'go',
98
+ rs: 'rust',
99
+ java: 'java',
100
+ rb: 'ruby',
101
+ cs: 'csharp',
102
+ cpp: 'cpp',
103
+ c: 'c',
104
+ h: 'c',
105
+ };
106
+ return MAP[ext] ?? ext;
107
+ }
108
+ //# sourceMappingURL=context-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/scope/context-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,iEAAiE;AAEjE,qDAAqD;AACrD,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC,2CAA2C;AAC3C,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,6CAA6C;AAC7C,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC,iEAAiE;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAyB;IAC1D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAExC,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,WAAW,EAAE,CAAC;YAChB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACvC,CAAC;AAED,iEAAiE;AAEjE;;GAEG;AACH,SAAS,gBAAgB,CAAC,IAAgB;IACxC,MAAM,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,2DAA2D;IAC3D,kDAAkD;IAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;QAC5B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM;YAC7B,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE;YAClD,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAEpC,MAAM,SAAS,GAAG,SAAS,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAEhE,cAAc,CAAC,IAAI,CACjB,GAAG,oBAAoB,GAAG,SAAS,KAAK,SAAS,YAAY,GAAG,KAAK,WAAW,UAAU,CAC3F,CAAC;IACJ,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAElD,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAAC,QAAQ,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3D,MAAM,GAAG,GAA2B;QAClC,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,KAAK;QACV,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,KAAK;QACV,EAAE,EAAE,QAAQ;QACZ,EAAE,EAAE,IAAI;QACR,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,MAAM;QACV,EAAE,EAAE,QAAQ;QACZ,GAAG,EAAE,KAAK;QACV,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;KACP,CAAC;IACF,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AACzB,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Diff-to-Symbol Mapper
3
+ *
4
+ * Maps unified diff hunks to symbol definitions, identifying
5
+ * which symbols were affected by code changes.
6
+ *
7
+ * Pure functions with no side effects.
8
+ */
9
+ import type { AffectedSymbol, DiffHunk, SymbolInfo } from './types.js';
10
+ /**
11
+ * Parse unified diff content to extract hunk line ranges.
12
+ *
13
+ * @param diffContent - Raw unified diff content for a single file
14
+ * @returns Array of DiffHunk objects with line ranges
15
+ */
16
+ export declare function parseHunks(diffContent: string): DiffHunk[];
17
+ /**
18
+ * Map diff hunks to affected symbols.
19
+ *
20
+ * A symbol is considered "affected" if any hunk's NEW side line range
21
+ * overlaps with the symbol's line range. We use the new side because
22
+ * we're analyzing the post-change source code.
23
+ *
24
+ * @param hunks - Parsed diff hunks
25
+ * @param symbols - Extracted symbols from the NEW version of the file
26
+ * @returns Array of affected symbols with their overlapping hunks
27
+ */
28
+ export declare function mapDiffToSymbols(hunks: DiffHunk[], symbols: SymbolInfo[]): AffectedSymbol[];
29
+ //# sourceMappingURL=diff-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-mapper.d.ts","sourceRoot":"","sources":["../../src/scope/diff-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAevE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,EAAE,CAiB1D;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,CAqB3F"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Diff-to-Symbol Mapper
3
+ *
4
+ * Maps unified diff hunks to symbol definitions, identifying
5
+ * which symbols were affected by code changes.
6
+ *
7
+ * Pure functions with no side effects.
8
+ */
9
+ // ─── Hunk Parsing ──────────────────────────────────────────────
10
+ /**
11
+ * Regex to match unified diff hunk headers.
12
+ * Format: @@ -oldStart[,oldCount] +newStart[,newCount] @@
13
+ *
14
+ * Examples:
15
+ * @@ -10,5 +10,7 @@
16
+ * @@ -1 +1,3 @@
17
+ * @@ -0,0 +1,20 @@
18
+ */
19
+ const HUNK_HEADER_RE = /^@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@/;
20
+ /**
21
+ * Parse unified diff content to extract hunk line ranges.
22
+ *
23
+ * @param diffContent - Raw unified diff content for a single file
24
+ * @returns Array of DiffHunk objects with line ranges
25
+ */
26
+ export function parseHunks(diffContent) {
27
+ const hunks = [];
28
+ const lines = diffContent.split('\n');
29
+ for (const line of lines) {
30
+ const match = HUNK_HEADER_RE.exec(line);
31
+ if (match) {
32
+ hunks.push({
33
+ oldStart: Number.parseInt(match[1], 10),
34
+ oldCount: match[2] !== undefined ? Number.parseInt(match[2], 10) : 1,
35
+ newStart: Number.parseInt(match[3], 10),
36
+ newCount: match[4] !== undefined ? Number.parseInt(match[4], 10) : 1,
37
+ });
38
+ }
39
+ }
40
+ return hunks;
41
+ }
42
+ // ─── Symbol Mapping ────────────────────────────────────────────
43
+ /**
44
+ * Map diff hunks to affected symbols.
45
+ *
46
+ * A symbol is considered "affected" if any hunk's NEW side line range
47
+ * overlaps with the symbol's line range. We use the new side because
48
+ * we're analyzing the post-change source code.
49
+ *
50
+ * @param hunks - Parsed diff hunks
51
+ * @param symbols - Extracted symbols from the NEW version of the file
52
+ * @returns Array of affected symbols with their overlapping hunks
53
+ */
54
+ export function mapDiffToSymbols(hunks, symbols) {
55
+ if (hunks.length === 0 || symbols.length === 0)
56
+ return [];
57
+ const affected = [];
58
+ for (const symbol of symbols) {
59
+ const overlapping = hunks.filter((hunk) => rangesOverlap(hunk.newStart, hunk.newStart + Math.max(hunk.newCount - 1, 0), symbol.startLine, symbol.endLine));
60
+ if (overlapping.length > 0) {
61
+ affected.push({ symbol, overlappingHunks: overlapping });
62
+ }
63
+ }
64
+ return affected;
65
+ }
66
+ // ─── Helpers ───────────────────────────────────────────────────
67
+ /**
68
+ * Check if two 1-based line ranges overlap.
69
+ *
70
+ * Two ranges [a1, a2] and [b1, b2] overlap when:
71
+ * a1 <= b2 AND b1 <= a2
72
+ */
73
+ function rangesOverlap(aStart, aEnd, bStart, bEnd) {
74
+ return aStart <= bEnd && bStart <= aEnd;
75
+ }
76
+ //# sourceMappingURL=diff-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-mapper.js","sourceRoot":"","sources":["../../src/scope/diff-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,kEAAkE;AAElE;;;;;;;;GAQG;AACH,MAAM,cAAc,GAAG,mDAAmD,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC;gBACT,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;gBACxC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;gBACxC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;aACrE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kEAAkE;AAElE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAiB,EAAE,OAAqB;IACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE1D,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACxC,aAAa,CACX,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,EAC9C,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,OAAO,CACf,CACF,CAAC;QAEF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kEAAkE;AAElE;;;;;GAKG;AACH,SAAS,aAAa,CACpB,MAAc,EACd,IAAY,EACZ,MAAc,EACd,IAAY;IAEZ,OAAO,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Symbol Extractor
3
+ *
4
+ * Extracts symbol definitions (functions, classes, methods, interfaces)
5
+ * from source code using tree-sitter AST walking.
6
+ *
7
+ * Uses cursor-based traversal instead of S-expression queries for
8
+ * maximum compatibility across grammar versions.
9
+ *
10
+ * Pure function signature: (source, language, tree) => SymbolInfo[]
11
+ */
12
+ import type { Tree } from 'web-tree-sitter';
13
+ import type { ScopeLanguage, SymbolInfo } from './types.js';
14
+ /**
15
+ * Extract symbol definitions from a parsed tree-sitter tree.
16
+ *
17
+ * Walks the AST using a cursor and identifies functions, classes,
18
+ * methods, and interfaces based on language-specific node types.
19
+ *
20
+ * @param tree - Parsed tree-sitter tree
21
+ * @param language - The scope language
22
+ * @returns Array of extracted symbols
23
+ */
24
+ export declare function extractSymbolsFromTree(tree: Tree, language: ScopeLanguage): SymbolInfo[];
25
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/scope/extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAQ,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AA+DxE;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,aAAa,GACtB,UAAU,EAAE,CAad"}