ghagga-core 2.9.1 → 3.0.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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agents/consensus.d.ts.map +1 -1
  3. package/dist/agents/consensus.js +7 -2
  4. package/dist/agents/consensus.js.map +1 -1
  5. package/dist/agents/diagnostic.d.ts.map +1 -1
  6. package/dist/agents/diagnostic.js +7 -2
  7. package/dist/agents/diagnostic.js.map +1 -1
  8. package/dist/agents/fan-out-lenses.d.ts.map +1 -1
  9. package/dist/agents/fan-out-lenses.js +7 -2
  10. package/dist/agents/fan-out-lenses.js.map +1 -1
  11. package/dist/agents/prompts.d.ts +49 -1
  12. package/dist/agents/prompts.d.ts.map +1 -1
  13. package/dist/agents/prompts.js +133 -5
  14. package/dist/agents/prompts.js.map +1 -1
  15. package/dist/agents/simple.d.ts +1 -1
  16. package/dist/agents/simple.d.ts.map +1 -1
  17. package/dist/agents/simple.js +6 -4
  18. package/dist/agents/simple.js.map +1 -1
  19. package/dist/agents/workflow.d.ts.map +1 -1
  20. package/dist/agents/workflow.js +13 -4
  21. package/dist/agents/workflow.js.map +1 -1
  22. package/dist/critique/critique.d.ts.map +1 -1
  23. package/dist/critique/critique.js +14 -6
  24. package/dist/critique/critique.js.map +1 -1
  25. package/dist/diff/index.d.ts +12 -0
  26. package/dist/diff/index.d.ts.map +1 -0
  27. package/dist/diff/index.js +11 -0
  28. package/dist/diff/index.js.map +1 -0
  29. package/dist/diff/parse.d.ts +41 -0
  30. package/dist/diff/parse.d.ts.map +1 -0
  31. package/dist/diff/parse.js +303 -0
  32. package/dist/diff/parse.js.map +1 -0
  33. package/dist/diff/types.d.ts +106 -0
  34. package/dist/diff/types.d.ts.map +1 -0
  35. package/dist/diff/types.js +23 -0
  36. package/dist/diff/types.js.map +1 -0
  37. package/dist/embed.d.ts +5 -2
  38. package/dist/embed.d.ts.map +1 -1
  39. package/dist/embed.js +7 -3
  40. package/dist/embed.js.map +1 -1
  41. package/dist/enhance/prompt.d.ts +5 -1
  42. package/dist/enhance/prompt.d.ts.map +1 -1
  43. package/dist/enhance/prompt.js +9 -2
  44. package/dist/enhance/prompt.js.map +1 -1
  45. package/dist/format.d.ts +31 -0
  46. package/dist/format.d.ts.map +1 -1
  47. package/dist/format.js +256 -15
  48. package/dist/format.js.map +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/memory/pageindex/index.d.ts +2 -2
  54. package/dist/memory/pageindex/index.d.ts.map +1 -1
  55. package/dist/memory/pageindex/index.js.map +1 -1
  56. package/dist/memory/pageindex/service.d.ts +10 -1
  57. package/dist/memory/pageindex/service.d.ts.map +1 -1
  58. package/dist/memory/pageindex/service.js +2 -2
  59. package/dist/memory/pageindex/service.js.map +1 -1
  60. package/dist/memory/persist.d.ts.map +1 -1
  61. package/dist/memory/persist.js +10 -3
  62. package/dist/memory/persist.js.map +1 -1
  63. package/dist/memory/privacy.d.ts.map +1 -1
  64. package/dist/memory/privacy.js +45 -6
  65. package/dist/memory/privacy.js.map +1 -1
  66. package/dist/memory/sqlite.d.ts +1 -13
  67. package/dist/memory/sqlite.d.ts.map +1 -1
  68. package/dist/memory/sqlite.js +45 -27
  69. package/dist/memory/sqlite.js.map +1 -1
  70. package/dist/memory/taxonomy.d.ts.map +1 -1
  71. package/dist/memory/taxonomy.js +6 -1
  72. package/dist/memory/taxonomy.js.map +1 -1
  73. package/dist/pipeline/degrade.d.ts +61 -0
  74. package/dist/pipeline/degrade.d.ts.map +1 -0
  75. package/dist/pipeline/degrade.js +58 -0
  76. package/dist/pipeline/degrade.js.map +1 -0
  77. package/dist/pipeline/enrich.d.ts +29 -0
  78. package/dist/pipeline/enrich.d.ts.map +1 -0
  79. package/dist/pipeline/enrich.js +271 -0
  80. package/dist/pipeline/enrich.js.map +1 -0
  81. package/dist/pipeline/execute.d.ts +22 -0
  82. package/dist/pipeline/execute.d.ts.map +1 -0
  83. package/dist/pipeline/execute.js +250 -0
  84. package/dist/pipeline/execute.js.map +1 -0
  85. package/dist/pipeline/finalize.d.ts +26 -0
  86. package/dist/pipeline/finalize.d.ts.map +1 -0
  87. package/dist/pipeline/finalize.js +52 -0
  88. package/dist/pipeline/finalize.js.map +1 -0
  89. package/dist/pipeline/gather-context.d.ts +25 -0
  90. package/dist/pipeline/gather-context.d.ts.map +1 -0
  91. package/dist/pipeline/gather-context.js +169 -0
  92. package/dist/pipeline/gather-context.js.map +1 -0
  93. package/dist/pipeline/gather-safe.d.ts +39 -0
  94. package/dist/pipeline/gather-safe.d.ts.map +1 -0
  95. package/dist/pipeline/gather-safe.js +127 -0
  96. package/dist/pipeline/gather-safe.js.map +1 -0
  97. package/dist/pipeline/prepare-graph.d.ts +54 -0
  98. package/dist/pipeline/prepare-graph.d.ts.map +1 -0
  99. package/dist/pipeline/prepare-graph.js +174 -0
  100. package/dist/pipeline/prepare-graph.js.map +1 -0
  101. package/dist/pipeline/prepare.d.ts +40 -0
  102. package/dist/pipeline/prepare.d.ts.map +1 -0
  103. package/dist/pipeline/prepare.js +233 -0
  104. package/dist/pipeline/prepare.js.map +1 -0
  105. package/dist/pipeline/providers.d.ts +54 -0
  106. package/dist/pipeline/providers.d.ts.map +1 -0
  107. package/dist/pipeline/providers.js +163 -0
  108. package/dist/pipeline/providers.js.map +1 -0
  109. package/dist/pipeline/results.d.ts +35 -0
  110. package/dist/pipeline/results.d.ts.map +1 -0
  111. package/dist/pipeline/results.js +122 -0
  112. package/dist/pipeline/results.js.map +1 -0
  113. package/dist/pipeline/state.d.ts +92 -0
  114. package/dist/pipeline/state.d.ts.map +1 -0
  115. package/dist/pipeline/state.js +13 -0
  116. package/dist/pipeline/state.js.map +1 -0
  117. package/dist/pipeline.d.ts +10 -9
  118. package/dist/pipeline.d.ts.map +1 -1
  119. package/dist/pipeline.js +36 -1213
  120. package/dist/pipeline.js.map +1 -1
  121. package/dist/providers/gateway.d.ts.map +1 -1
  122. package/dist/providers/gateway.js +8 -0
  123. package/dist/providers/gateway.js.map +1 -1
  124. package/dist/recursive/index.d.ts +1 -0
  125. package/dist/recursive/index.d.ts.map +1 -1
  126. package/dist/recursive/index.js +7 -3
  127. package/dist/recursive/index.js.map +1 -1
  128. package/dist/recursive/patch-extractor.d.ts +58 -6
  129. package/dist/recursive/patch-extractor.d.ts.map +1 -1
  130. package/dist/recursive/patch-extractor.js +207 -26
  131. package/dist/recursive/patch-extractor.js.map +1 -1
  132. package/dist/sanitize.d.ts +51 -0
  133. package/dist/sanitize.d.ts.map +1 -0
  134. package/dist/sanitize.js +90 -0
  135. package/dist/sanitize.js.map +1 -0
  136. package/dist/scope/diff-mapper.d.ts +12 -0
  137. package/dist/scope/diff-mapper.d.ts.map +1 -1
  138. package/dist/scope/diff-mapper.js +25 -18
  139. package/dist/scope/diff-mapper.js.map +1 -1
  140. package/dist/scope/entity-diff.d.ts +21 -4
  141. package/dist/scope/entity-diff.d.ts.map +1 -1
  142. package/dist/scope/entity-diff.js +132 -34
  143. package/dist/scope/entity-diff.js.map +1 -1
  144. package/dist/scope/types.d.ts +10 -0
  145. package/dist/scope/types.d.ts.map +1 -1
  146. package/dist/semantic-diff/index.d.ts +25 -2
  147. package/dist/semantic-diff/index.d.ts.map +1 -1
  148. package/dist/semantic-diff/index.js +147 -53
  149. package/dist/semantic-diff/index.js.map +1 -1
  150. package/dist/tools/gitleaks-config.toml +35 -0
  151. package/dist/tools/plugins/gitleaks.d.ts +10 -0
  152. package/dist/tools/plugins/gitleaks.d.ts.map +1 -1
  153. package/dist/tools/plugins/gitleaks.js +29 -2
  154. package/dist/tools/plugins/gitleaks.js.map +1 -1
  155. package/dist/tools/plugins/semgrep.d.ts +11 -0
  156. package/dist/tools/plugins/semgrep.d.ts.map +1 -1
  157. package/dist/tools/plugins/semgrep.js +30 -1
  158. package/dist/tools/plugins/semgrep.js.map +1 -1
  159. package/dist/tools/semgrep-rules.yml +305 -0
  160. package/dist/types.d.ts +51 -1
  161. package/dist/types.d.ts.map +1 -1
  162. package/dist/types.js.map +1 -1
  163. package/dist/utils/diff.d.ts +22 -2
  164. package/dist/utils/diff.d.ts.map +1 -1
  165. package/dist/utils/diff.js +36 -40
  166. package/dist/utils/diff.js.map +1 -1
  167. package/package.json +21 -22
  168. package/dist/providers/fallback.d.ts +0 -54
  169. package/dist/providers/fallback.d.ts.map +0 -1
  170. package/dist/providers/fallback.js +0 -102
  171. package/dist/providers/fallback.js.map +0 -1
  172. package/dist/providers/index.d.ts +0 -49
  173. package/dist/providers/index.d.ts.map +0 -1
  174. package/dist/providers/index.js +0 -146
  175. package/dist/providers/index.js.map +0 -1
@@ -4,9 +4,29 @@
4
4
  * Instead of raw line diffs, extracts WHAT changed at the entity level:
5
5
  * function renamed, class added, method signature changed, etc.
6
6
  *
7
- * Implementation is regex-based — no tree-sitter required.
7
+ * Implementation is regex-based — no tree-sitter required. File sectioning
8
+ * is delegated to the unified diff parser (`src/diff/parse.ts`); declaration
9
+ * detection stays local.
10
+ *
11
+ * WIRED TO PRODUCTION (SDD wire-semantic-diff, 2026-06-13).
12
+ * `extractSemanticDiff` runs in the enrich phase (`pipeline/enrich.ts`),
13
+ * its result lands on `ReviewResult.semanticDiff`, and that feeds the
14
+ * "What changed" section of the PR comment via `formatSemanticDiffSection`
15
+ * (`format.ts`). This is no longer an unwired re-export.
16
+ *
17
+ * Known limitations (real, by design — the extractor is regex-based, not a
18
+ * parser, and matches single-line declarations only; all pinned in
19
+ * `index.test.ts`):
20
+ * - a multiline arrow whose `=>` lands on the next line is not detected;
21
+ * - a generic constraint CONTAINING parens (`<T extends () => void>`) is
22
+ * not detected (the `[^(]*` guard that keeps comparisons out excludes it);
23
+ * - declarations spanning multiple lines are matched only by their first
24
+ * line.
25
+ * The presentation layer (`format.ts`) drops `method_*` noise and gates to
26
+ * TS/JS files, so these misses degrade the cosmetic comment section only —
27
+ * never the review verdict.
8
28
  */
9
- export type EntityChangeKind = 'function_added' | 'function_removed' | 'function_modified' | 'class_added' | 'class_removed' | 'method_added' | 'method_removed' | 'method_modified' | 'import_added' | 'import_removed' | 'export_added' | 'export_removed' | 'type_added' | 'type_removed' | 'type_modified';
29
+ export type EntityChangeKind = 'function_added' | 'function_removed' | 'function_modified' | 'class_added' | 'class_removed' | 'class_modified' | 'method_added' | 'method_removed' | 'method_modified' | 'import_added' | 'import_removed' | 'import_modified' | 'export_added' | 'export_removed' | 'export_modified' | 'type_added' | 'type_removed' | 'type_modified';
10
30
  export interface EntityChange {
11
31
  kind: EntityChangeKind;
12
32
  name: string;
@@ -26,6 +46,9 @@ export interface SemanticDiff {
26
46
  *
27
47
  * Returns a SemanticDiff with individual EntityChange items and a
28
48
  * human-readable summary string.
49
+ *
50
+ * Wired into the review pipeline (enrich phase → `ReviewResult.semanticDiff`
51
+ * → "What changed" PR comment section). See the module header.
29
52
  */
30
53
  export declare function extractSemanticDiff(unifiedDiff: string): SemanticDiff;
31
54
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semantic-diff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,mBAAmB,GACnB,aAAa,GACb,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AAqJD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAiCrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semantic-diff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,mBAAmB,GACnB,aAAa,GACb,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,YAAY,GACZ,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AA+MD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAiCrE"}
@@ -4,25 +4,48 @@
4
4
  * Instead of raw line diffs, extracts WHAT changed at the entity level:
5
5
  * function renamed, class added, method signature changed, etc.
6
6
  *
7
- * Implementation is regex-based — no tree-sitter required.
7
+ * Implementation is regex-based — no tree-sitter required. File sectioning
8
+ * is delegated to the unified diff parser (`src/diff/parse.ts`); declaration
9
+ * detection stays local.
10
+ *
11
+ * WIRED TO PRODUCTION (SDD wire-semantic-diff, 2026-06-13).
12
+ * `extractSemanticDiff` runs in the enrich phase (`pipeline/enrich.ts`),
13
+ * its result lands on `ReviewResult.semanticDiff`, and that feeds the
14
+ * "What changed" section of the PR comment via `formatSemanticDiffSection`
15
+ * (`format.ts`). This is no longer an unwired re-export.
16
+ *
17
+ * Known limitations (real, by design — the extractor is regex-based, not a
18
+ * parser, and matches single-line declarations only; all pinned in
19
+ * `index.test.ts`):
20
+ * - a multiline arrow whose `=>` lands on the next line is not detected;
21
+ * - a generic constraint CONTAINING parens (`<T extends () => void>`) is
22
+ * not detected (the `[^(]*` guard that keeps comparisons out excludes it);
23
+ * - declarations spanning multiple lines are matched only by their first
24
+ * line.
25
+ * The presentation layer (`format.ts`) drops `method_*` noise and gates to
26
+ * TS/JS files, so these misses degrade the cosmetic comment section only —
27
+ * never the review verdict.
8
28
  */
29
+ import { parseUnifiedDiff } from '../diff/index.js';
9
30
  // ─── Regex Patterns ──────────────────────────────────────────────
10
31
  /**
11
32
  * Patterns that match declaration lines.
12
33
  * Each entry includes the entity category for grouping (function|class|method|import|export|type).
13
34
  */
14
35
  const DECLARATION_PATTERNS = [
36
+ // NOTE: ORDER MATTERS. The generic "export <name>" pattern is intentionally
37
+ // listed LAST so that more specific declarations — `export function foo`,
38
+ // `export class Foo`, `export const fn = () => …`, `export type Foo` — are
39
+ // classified by their real entity kind (function/class/type) instead of being
40
+ // swallowed by a catch-all `export` rule. Only plain value re-exports
41
+ // (e.g. `export const VERSION = '1.0'`, `export default expr`) fall through
42
+ // to the `export` kind.
15
43
  // import statements — match before export/function to avoid conflicts
16
44
  {
17
45
  kind: 'import',
18
46
  pattern: /^\s*import\s+(?:type\s+)?(?:\{[^}]*\}|[\w*]+(?:\s+as\s+\w+)?)\s+from\s+['"][^'"]+['"]/,
19
47
  },
20
- // export default / named
21
- {
22
- kind: 'export',
23
- pattern: /^\s*export\s+(?:default\s+)?(?:const|let|var|function\*?|async\s+function\*?)\s+(\w+)/,
24
- },
25
- // export type / interface
48
+ // export type / interface / enum (before the generic export rule)
26
49
  {
27
50
  kind: 'type',
28
51
  pattern: /^\s*export\s+(?:type|interface|enum)\s+(\w+)/,
@@ -32,30 +55,47 @@ const DECLARATION_PATTERNS = [
32
55
  kind: 'type',
33
56
  pattern: /^\s*(?:type|interface|enum)\s+(\w+)/,
34
57
  },
35
- // class declaration
58
+ // class declaration (handles `export class` and `export abstract class`)
36
59
  {
37
60
  kind: 'class',
38
- pattern: /^\s*(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/,
61
+ pattern: /^\s*(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(\w+)/,
39
62
  },
40
- // method inside class (indented + no leading "function" keyword, has "()")
63
+ // top-level function declaration (handles `export function` / `export async function`)
41
64
  {
42
- kind: 'method',
43
- pattern: /^[ \t]+(?:(?:public|private|protected|static|async|override|readonly)\s+)*(\w+)\s*\(/,
65
+ kind: 'function',
66
+ pattern: /^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\*?\s+(\w+)\s*\(/,
44
67
  },
45
- // top-level function declaration
68
+ // arrow / function-expression assigned to const/let/var (handles `export const fn = () =>`,
69
+ // optionally typed: `export const fn: Foo = async () =>`).
70
+ // The RHS must be a real function: `function` keyword, or arrow params
71
+ // (paren-params — with an optional generic prefix `<T>` / `<T extends X>` —
72
+ // bare single param, optional return-type annotation) followed by `=>`
73
+ // ON THE SAME LINE. A bare `(` is NOT enough — that misclassified
74
+ // parenthesized non-function initializers (e.g.
75
+ // `const x = (row.metadata as Foo).bar`) as function_added.
76
+ // The generic prefix `<[^(]*>` is anchored to paren-params only (a bare
77
+ // param after a generic is not valid TS) and cannot contain `(` — so a
78
+ // `<` comparison initializer (`const a = x < y`) never enters this branch,
79
+ // and the cast false positive stays closed. Nested generics without parens
80
+ // (`<T extends Record<string, K>>`) resolve via the greedy last-`>`.
81
+ // Known limitations (accepted, pinned in index.test.ts):
82
+ // - a multiline arrow whose `=>` lands on the next line is not detected;
83
+ // - a generic constraint CONTAINING parens (`<T extends () => void>`)
84
+ // is not detected (the `[^(]*` guard that keeps comparisons out
85
+ // excludes it).
46
86
  {
47
87
  kind: 'function',
48
- pattern: /^\s*(?:export\s+)?(?:async\s+)?function\*?\s+(\w+)\s*\(/,
88
+ pattern: /^\s*(?:export\s+)?(?:const|let|var)\s+(\w+)\s*(?::\s*[\w<>,\s|[\]]+?)?\s*=\s*(?:async\s+)?(?:function\b|(?:(?:<[^(]*>\s*)?\([^)]*\)|[\w$]+)\s*(?::[^=]*)?=>)/,
49
89
  },
50
- // arrow function / const fn = ...
90
+ // method inside class (indented + no leading "function" keyword, has "()")
51
91
  {
52
- kind: 'function',
53
- pattern: /^\s*(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(/,
92
+ kind: 'method',
93
+ pattern: /^[ \t]+(?:(?:public|private|protected|static|async|override|readonly)\s+)*(\w+)\s*\(/,
54
94
  },
55
- // const fn = async () => or const fn = () =>
95
+ // generic export of a plain value LAST so the rules above win first
56
96
  {
57
- kind: 'function',
58
- pattern: /^\s*(?:export\s+)?(?:const|let|var)\s+(\w+)\s*(?::\s*\w[\w<>,\s]*?)?\s*=\s*(?:async\s+)?\(/,
97
+ kind: 'export',
98
+ pattern: /^\s*export\s+(?:default\s+)?(?:const|let|var)\s+(\w+)/,
59
99
  },
60
100
  ];
61
101
  /**
@@ -80,37 +120,75 @@ function extractDeclaration(line) {
80
120
  return null;
81
121
  }
82
122
  /**
83
- * Parse a unified diff and split added/removed declaration lines per file.
123
+ * FROZEN LEGACY BEHAVIOR path resolution for the pre-header
124
+ * pseudo-section. The historical splitter (`split(/^diff --git /m)`) kept
125
+ * everything before the first file header as a section of its own and
126
+ * resolved its "path" by running this tail regex over the FIRST line
127
+ * (almost always yielding `unknown`). Reachable via arbitrary ACP input
128
+ * and bare diff fragments, so it is preserved verbatim. This is NOT a
129
+ * file-header or hunk-header regex (spec R8 keeps those solely in
130
+ * `src/diff/`): it matches the tail of an already-isolated line.
84
131
  */
85
- function parseHunks(unifiedDiff) {
86
- const result = [];
87
- const filePattern = /^diff --git a\/.+ b\/(.+)$/m;
88
- const sections = unifiedDiff.split(/^diff --git /m).filter(Boolean);
89
- for (const section of sections) {
90
- const pathMatch = /a\/.+ b\/(.+)$/.exec(section.split('\n')[0] ?? '');
91
- const filePath = pathMatch?.[1] ?? 'unknown';
92
- const added = new Map();
93
- const removed = new Map();
94
- for (const line of section.split('\n')) {
95
- if (line.startsWith('+') && !line.startsWith('+++')) {
96
- const content = line.slice(1);
97
- const decl = extractDeclaration(content);
98
- if (decl) {
99
- added.set(decl.name, { name: decl.name, signature: content.trim(), kind: decl.kind });
100
- }
132
+ const LEGACY_SECTION_PATH_RE = /a\/.+ b\/(.+)$/;
133
+ /** Scan a section's raw lines for added/removed declaration lines. */
134
+ function scanSection(lines, filePath) {
135
+ const added = new Map();
136
+ const removed = new Map();
137
+ for (const line of lines) {
138
+ if (line.startsWith('+') && !line.startsWith('+++')) {
139
+ const content = line.slice(1);
140
+ const decl = extractDeclaration(content);
141
+ if (decl) {
142
+ added.set(decl.name, { name: decl.name, signature: content.trim(), kind: decl.kind });
101
143
  }
102
- else if (line.startsWith('-') && !line.startsWith('---')) {
103
- const content = line.slice(1);
104
- const decl = extractDeclaration(content);
105
- if (decl) {
106
- removed.set(decl.name, { name: decl.name, signature: content.trim(), kind: decl.kind });
107
- }
144
+ }
145
+ else if (line.startsWith('-') && !line.startsWith('---')) {
146
+ const content = line.slice(1);
147
+ const decl = extractDeclaration(content);
148
+ if (decl) {
149
+ removed.set(decl.name, { name: decl.name, signature: content.trim(), kind: decl.kind });
108
150
  }
109
151
  }
110
- result.push({ filePath, added, removed });
111
152
  }
112
- // Suppress unused import warning — filePattern is used for documentation only
113
- void filePattern;
153
+ return { filePath, added, removed };
154
+ }
155
+ /**
156
+ * Split added/removed declaration lines per file.
157
+ *
158
+ * Thin adapter over the unified parser (`src/diff/parse.ts`) — replaces the
159
+ * historical local `parseHunks` that re-split the diff with its own
160
+ * `/^diff --git /m` regex. Sections scan `rawLines` (NOT the structured
161
+ * `hunk.lines`): the historical scanner looked at EVERY section line with
162
+ * the +/- prefix checks, including metadata regions and orphan +/- tails
163
+ * after a genuine empty line mid-hunk, which structured hunks do not carry.
164
+ *
165
+ * Path authority per file = the b-side of the `diff --git` header itself
166
+ * (`headerNewPath`), which equals the historical regex capture for every
167
+ * plain header (last ` b/` boundary included). Documented deltas vs the
168
+ * historical splitter, pinned in
169
+ * `src/diff/__tests__/parity-extract-semantic-diff.test.ts`:
170
+ * - quoted headers (CORE-M6 umbrella): historically the section existed
171
+ * but its path never matched the legacy regex → `unknown`; now the real
172
+ * unescaped path is resolved.
173
+ * - synthetic-only malformed headers (`diff --git <garbage>` mid-diff,
174
+ * mixed-quoted forms): the historical splitter opened a new section at
175
+ * ANY line starting with `diff --git `; the model only does so for
176
+ * parseable headers, so declarations after a garbage header line stay
177
+ * attributed to the previous file. Unreachable in git/GitHub/truncateDiff
178
+ * output.
179
+ */
180
+ function collectHunkSets(unifiedDiff) {
181
+ const { preamble, files } = parseUnifiedDiff(unifiedDiff);
182
+ const result = [];
183
+ // Legacy pre-header pseudo-section (see LEGACY_SECTION_PATH_RE). The
184
+ // historical splitter dropped it only when empty (`filter(Boolean)`).
185
+ if (preamble.length > 0 && preamble.join('\n') !== '') {
186
+ const pathMatch = LEGACY_SECTION_PATH_RE.exec(preamble[0] ?? '');
187
+ result.push(scanSection(preamble, pathMatch?.[1] ?? 'unknown'));
188
+ }
189
+ for (const file of files) {
190
+ result.push(scanSection(file.rawLines, file.headerNewPath || 'unknown'));
191
+ }
114
192
  return result;
115
193
  }
116
194
  // ─── Main Export ─────────────────────────────────────────────────
@@ -119,9 +197,12 @@ function parseHunks(unifiedDiff) {
119
197
  *
120
198
  * Returns a SemanticDiff with individual EntityChange items and a
121
199
  * human-readable summary string.
200
+ *
201
+ * Wired into the review pipeline (enrich phase → `ReviewResult.semanticDiff`
202
+ * → "What changed" PR comment section). See the module header.
122
203
  */
123
204
  export function extractSemanticDiff(unifiedDiff) {
124
- const hunkSets = parseHunks(unifiedDiff);
205
+ const hunkSets = collectHunkSets(unifiedDiff);
125
206
  const changes = [];
126
207
  for (const { filePath, added, removed } of hunkSets) {
127
208
  // Entities in both added and removed → modified
@@ -166,17 +247,30 @@ function mapToChangeKind(category, direction) {
166
247
  ? 'class_added'
167
248
  : direction === 'removed'
168
249
  ? 'class_removed'
169
- : 'function_modified'; // classes cannot be "modified" at entity level, treat as function_modified
250
+ : 'class_modified';
170
251
  case 'method':
171
252
  return direction === 'added'
172
253
  ? 'method_added'
173
254
  : direction === 'removed'
174
255
  ? 'method_removed'
175
256
  : 'method_modified';
257
+ // Modified imports/exports ARE reachable: a declaration whose name (for
258
+ // imports, the from-module) appears on both the +/- sides of a section is
259
+ // derived with direction 'modified'. Historically these fell into the
260
+ // false branch of a two-way ternary and were misreported as
261
+ // import_removed/export_removed (with both signatures set).
176
262
  case 'import':
177
- return direction === 'added' ? 'import_added' : 'import_removed';
263
+ return direction === 'added'
264
+ ? 'import_added'
265
+ : direction === 'removed'
266
+ ? 'import_removed'
267
+ : 'import_modified';
178
268
  case 'export':
179
- return direction === 'added' ? 'export_added' : 'export_removed';
269
+ return direction === 'added'
270
+ ? 'export_added'
271
+ : direction === 'removed'
272
+ ? 'export_removed'
273
+ : 'export_modified';
180
274
  case 'type':
181
275
  return direction === 'added'
182
276
  ? 'type_added'
@@ -203,10 +297,10 @@ function buildSummary(changes) {
203
297
  parts.push(`${modified} ${label} modified`);
204
298
  };
205
299
  groupSummary('function_added', 'function_removed', 'function_modified', 'function');
206
- groupSummary('class_added', 'class_removed', 'function_modified', 'class');
300
+ groupSummary('class_added', 'class_removed', 'class_modified', 'class');
207
301
  groupSummary('method_added', 'method_removed', 'method_modified', 'method');
208
- groupSummary('import_added', 'import_removed', 'import_added', 'import');
209
- groupSummary('export_added', 'export_removed', 'export_added', 'export');
302
+ groupSummary('import_added', 'import_removed', 'import_modified', 'import');
303
+ groupSummary('export_added', 'export_removed', 'export_modified', 'export');
210
304
  groupSummary('type_added', 'type_removed', 'type_modified', 'type');
211
305
  if (parts.length === 0)
212
306
  return 'no entity-level changes detected';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/semantic-diff/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/semantic-diff/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ # =============================================================================
2
+ # GHAGGA bundled Gitleaks configuration
3
+ # =============================================================================
4
+ # Extends the gitleaks built-in default ruleset and adds a conservative
5
+ # path-based allowlist for test files / fixtures.
6
+ #
7
+ # Tradeoff (accepted by maintainer): this reduces noise from fake tokens in
8
+ # test fixtures at the cost of potentially missing a REAL secret that is
9
+ # hardcoded inside a test/fixture file. Production source is unaffected.
10
+ #
11
+ # NOTE: pinned gitleaks version is 8.21.2 (< 8.25.0), which uses the singular
12
+ # `[allowlist]` table with `paths = [...]` regexes. Do NOT switch to the
13
+ # `[[allowlists]]` array form unless the pinned version is bumped to >= 8.25.0.
14
+ # =============================================================================
15
+
16
+ title = "GHAGGA Gitleaks configuration"
17
+
18
+ [extend]
19
+ # Keep all of gitleaks' built-in default rules.
20
+ useDefault = true
21
+
22
+ [allowlist]
23
+ description = "Ignore secrets found in test files and fixtures (conservative)"
24
+ # Go (RE2) regexes matched against the file path. A finding whose path matches
25
+ # ANY of these is suppressed.
26
+ paths = [
27
+ '''.*\.test\.[tj]sx?$''',
28
+ '''.*\.spec\.[tj]sx?$''',
29
+ '''.*_test\.(py|go)$''',
30
+ '''.*test_.*\.py$''',
31
+ '''.*/__tests__/.*''',
32
+ '''.*/tests?/.*''',
33
+ '''.*/fixtures?/.*''',
34
+ '''.*/testdata/.*''',
35
+ ]
@@ -8,6 +8,16 @@
8
8
  */
9
9
  import type { ReviewFinding } from '../../types.js';
10
10
  import type { RawToolOutput, ToolDefinition } from '../types.js';
11
+ /**
12
+ * Resolve the bundled gitleaks config (extends defaults + test-file allowlist).
13
+ *
14
+ * Works in BOTH dev (src/tools/plugins/gitleaks.ts -> src/tools/gitleaks-config.toml)
15
+ * and the published build (dist/tools/plugins/gitleaks.js -> dist/tools/gitleaks-config.toml),
16
+ * provided the build copies the .toml into dist/tools/ (see package.json `build` script).
17
+ *
18
+ * Returns undefined if missing so the plugin degrades gracefully to default rules.
19
+ */
20
+ export declare function resolveGitleaksConfigPath(): string | undefined;
11
21
  /**
12
22
  * Parse Gitleaks JSON output into ReviewFinding[].
13
23
  * Gitleaks writes results to a report file; we read from stdout or the report.
@@ -1 +1 @@
1
- {"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/gitleaks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAanF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAiBxF;AAED,eAAO,MAAM,cAAc,EAAE,cAgE5B,CAAC"}
1
+ {"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/gitleaks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKnF;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,GAAG,SAAS,CAI9D;AAUD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAiBxF;AAED,eAAO,MAAM,cAAc,EAAE,cAuE5B,CAAC"}
@@ -6,8 +6,25 @@
6
6
  *
7
7
  * Uses ExecutionContext for DI instead of direct child_process.
8
8
  */
9
+ import { existsSync } from 'node:fs';
10
+ import { dirname, join } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
9
12
  const GITLEAKS_VERSION = '8.21.2';
10
13
  const GITLEAKS_BIN = '/usr/local/bin/gitleaks';
14
+ /**
15
+ * Resolve the bundled gitleaks config (extends defaults + test-file allowlist).
16
+ *
17
+ * Works in BOTH dev (src/tools/plugins/gitleaks.ts -> src/tools/gitleaks-config.toml)
18
+ * and the published build (dist/tools/plugins/gitleaks.js -> dist/tools/gitleaks-config.toml),
19
+ * provided the build copies the .toml into dist/tools/ (see package.json `build` script).
20
+ *
21
+ * Returns undefined if missing so the plugin degrades gracefully to default rules.
22
+ */
23
+ export function resolveGitleaksConfigPath() {
24
+ const here = dirname(fileURLToPath(import.meta.url));
25
+ const configPath = join(here, '..', 'gitleaks-config.toml');
26
+ return existsSync(configPath) ? configPath : undefined;
27
+ }
11
28
  /**
12
29
  * Parse Gitleaks JSON output into ReviewFinding[].
13
30
  * Gitleaks writes results to a report file; we read from stdout or the report.
@@ -60,14 +77,24 @@ export const gitleaksPlugin = {
60
77
  },
61
78
  async run(ctx, repoDir, _files, timeout) {
62
79
  const reportPath = '/tmp/gitleaks-result.json';
63
- await ctx.exec('gitleaks', [
80
+ const detectArgs = [
64
81
  'detect',
65
82
  `--source=${repoDir}`,
66
83
  '--report-format=json',
67
84
  `--report-path=${reportPath}`,
68
85
  '--no-git',
69
86
  '--exit-code=0',
70
- ], {
87
+ ];
88
+ // Apply ghagga's bundled config (default rules + test-file allowlist) when
89
+ // available. Degrade gracefully to gitleaks' built-in defaults if missing.
90
+ const configPath = resolveGitleaksConfigPath();
91
+ if (configPath) {
92
+ detectArgs.push(`--config=${configPath}`);
93
+ }
94
+ else {
95
+ ctx.log('warn', 'gitleaks: bundled gitleaks-config.toml not found, using default rules only');
96
+ }
97
+ await ctx.exec('gitleaks', detectArgs, {
71
98
  timeoutMs: timeout,
72
99
  });
73
100
  // Read the report file and return it as stdout
@@ -1 +1 @@
1
- {"version":3,"file":"gitleaks.js","sourceRoot":"","sources":["../../../src/tools/plugins/gitleaks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAClC,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAU/C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAkB,EAAE,OAAe;IACrE,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAsB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE3D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1B,QAAQ,EAAE,UAAmB;YAC7B,QAAQ,EAAE,SAAS;YACnB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC;YACvC,IAAI,EAAE,CAAC,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC,MAAM,GAAG;YAC/C,MAAM,EAAE,UAAmB;SAC5B,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,UAAU;IACvB,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,gBAAgB;IACzB,YAAY,EAAE,MAAM;IACpB,UAAU,EAAE,CAAC,YAAY,CAAC;IAE1B,KAAK,CAAC,OAAO,CAAC,GAAqB;QACjC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;QAClE,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,iEAAiE,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,MAAM,GAAG,CAAC,IAAI,CACZ,MAAM,EACN;YACE,IAAI;YACJ,qEAAqE,gBAAgB,aAAa,gBAAgB,wDAAwD;SAC3K,EACD,EAAE,SAAS,EAAE,OAAO,EAAE,CACvB,CAAC;QACF,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/D,MAAM,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAqB,EACrB,OAAe,EACf,MAAgB,EAChB,OAAe;QAEf,MAAM,UAAU,GAAG,2BAA2B,CAAC;QAE/C,MAAM,GAAG,CAAC,IAAI,CACZ,UAAU,EACV;YACE,QAAQ;YACR,YAAY,OAAO,EAAE;YACrB,sBAAsB;YACtB,iBAAiB,UAAU,EAAE;YAC7B,UAAU;YACV,eAAe;SAChB,EACD;YACE,SAAS,EAAE,OAAO;SACnB,CACF,CAAC;QAEF,+CAA+C;QAC/C,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;YACnC,SAAS,EAAE,MAAM;YACjB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,mCAAmC;SACzD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,EAAE,mBAAmB;CAC3B,CAAC"}
1
+ {"version":3,"file":"gitleaks.js","sourceRoot":"","sources":["../../../src/tools/plugins/gitleaks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAClC,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,sBAAsB,CAAC,CAAC;IAC5D,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAkB,EAAE,OAAe;IACrE,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAsB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE3D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1B,QAAQ,EAAE,UAAmB;YAC7B,QAAQ,EAAE,SAAS;YACnB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC;YACvC,IAAI,EAAE,CAAC,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC,MAAM,GAAG;YAC/C,MAAM,EAAE,UAAmB;SAC5B,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,UAAU;IACvB,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,gBAAgB;IACzB,YAAY,EAAE,MAAM;IACpB,UAAU,EAAE,CAAC,YAAY,CAAC;IAE1B,KAAK,CAAC,OAAO,CAAC,GAAqB;QACjC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;QAClE,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,iEAAiE,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,MAAM,GAAG,CAAC,IAAI,CACZ,MAAM,EACN;YACE,IAAI;YACJ,qEAAqE,gBAAgB,aAAa,gBAAgB,wDAAwD;SAC3K,EACD,EAAE,SAAS,EAAE,OAAO,EAAE,CACvB,CAAC;QACF,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/D,MAAM,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAqB,EACrB,OAAe,EACf,MAAgB,EAChB,OAAe;QAEf,MAAM,UAAU,GAAG,2BAA2B,CAAC;QAE/C,MAAM,UAAU,GAAG;YACjB,QAAQ;YACR,YAAY,OAAO,EAAE;YACrB,sBAAsB;YACtB,iBAAiB,UAAU,EAAE;YAC7B,UAAU;YACV,eAAe;SAChB,CAAC;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,MAAM,UAAU,GAAG,yBAAyB,EAAE,CAAC;QAC/C,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,YAAY,UAAU,EAAE,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,4EAA4E,CAAC,CAAC;QAChG,CAAC;QAED,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE;YACrC,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QAEH,+CAA+C;QAC/C,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;YACnC,SAAS,EAAE,MAAM;YACjB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,mCAAmC;SACzD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,EAAE,mBAAmB;CAC3B,CAAC"}
@@ -9,6 +9,17 @@
9
9
  */
10
10
  import type { FindingSeverity, ReviewFinding } from '../../types.js';
11
11
  import type { RawToolOutput, ToolDefinition } from '../types.js';
12
+ /**
13
+ * Resolve the bundled curated ruleset path relative to this plugin's location.
14
+ *
15
+ * Works in BOTH dev (src/tools/plugins/semgrep.ts -> src/tools/semgrep-rules.yml)
16
+ * and the published build (dist/tools/plugins/semgrep.js -> dist/tools/semgrep-rules.yml),
17
+ * provided the build copies the .yml into dist/tools/ (see package.json `build` script).
18
+ *
19
+ * Returns undefined if the file is not present so the plugin degrades gracefully
20
+ * to `--config auto` only.
21
+ */
22
+ export declare function resolveSemgrepRulesPath(): string | undefined;
12
23
  /**
13
24
  * Map Semgrep severity to GHAGGA FindingSeverity.
14
25
  * ERROR -> high, WARNING -> medium, INFO -> info, default -> low
@@ -1 +1 @@
1
- {"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/semgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAInF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAW3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAuBvF;AAED,eAAO,MAAM,aAAa,EAAE,cAwC3B,CAAC"}
1
+ {"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/semgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAInF;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAI5D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAW3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAuBvF;AAED,eAAO,MAAM,aAAa,EAAE,cAmD3B,CAAC"}
@@ -7,7 +7,25 @@
7
7
  *
8
8
  * Uses ExecutionContext for DI instead of direct child_process.
9
9
  */
10
+ import { existsSync } from 'node:fs';
11
+ import { dirname, join } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
10
13
  const SEMGREP_VERSION = '1.90.0';
14
+ /**
15
+ * Resolve the bundled curated ruleset path relative to this plugin's location.
16
+ *
17
+ * Works in BOTH dev (src/tools/plugins/semgrep.ts -> src/tools/semgrep-rules.yml)
18
+ * and the published build (dist/tools/plugins/semgrep.js -> dist/tools/semgrep-rules.yml),
19
+ * provided the build copies the .yml into dist/tools/ (see package.json `build` script).
20
+ *
21
+ * Returns undefined if the file is not present so the plugin degrades gracefully
22
+ * to `--config auto` only.
23
+ */
24
+ export function resolveSemgrepRulesPath() {
25
+ const here = dirname(fileURLToPath(import.meta.url));
26
+ const rulesPath = join(here, '..', 'semgrep-rules.yml');
27
+ return existsSync(rulesPath) ? rulesPath : undefined;
28
+ }
11
29
  /**
12
30
  * Map Semgrep severity to GHAGGA FindingSeverity.
13
31
  * ERROR -> high, WARNING -> medium, INFO -> info, default -> low
@@ -72,7 +90,18 @@ export const semgrepPlugin = {
72
90
  await ctx.cacheSave('semgrep', ['/usr/local/bin/semgrep']);
73
91
  },
74
92
  async run(ctx, repoDir, _files, timeout) {
75
- return ctx.exec('semgrep', ['--json', '--config', 'auto', '--quiet', repoDir], {
93
+ // Always run the broad registry ruleset (`auto`) AND, when available, ghagga's
94
+ // own curated rules bundled with the package. Semgrep unions multiple --config
95
+ // flags, so the curated rules run even offline. Degrade gracefully if missing.
96
+ const configArgs = ['--config', 'auto'];
97
+ const rulesPath = resolveSemgrepRulesPath();
98
+ if (rulesPath) {
99
+ configArgs.push('--config', rulesPath);
100
+ }
101
+ else {
102
+ ctx.log('warn', 'semgrep: bundled semgrep-rules.yml not found, using --config auto only');
103
+ }
104
+ return ctx.exec('semgrep', ['--json', ...configArgs, '--quiet', repoDir], {
76
105
  timeoutMs: timeout,
77
106
  allowExitCodes: [1], // semgrep returns 1 when findings are present
78
107
  });
@@ -1 +1 @@
1
- {"version":3,"file":"semgrep.js","sourceRoot":"","sources":["../../../src/tools/plugins/semgrep.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"semgrep.js","sourceRoot":"","sources":["../../../src/tools/plugins/semgrep.ts"],"names":[],"mappings":"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"}