circle-ir-ai 2.16.0 → 2.18.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,139 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.18.0] - 2026-06-22
9
+
10
+ ### Added — findings-emission instrumentation env wiring (cognium-dev#145 PR C)
11
+
12
+ `circle-ir-ai` now honors the `CIRCLE_IR_INSTRUMENT_FINDINGS=1`
13
+ environment variable at analyzer-init time, flipping
14
+ `setFindingsInstrumentation(true)` on `circle-ir`'s opt-in
15
+ findings-emission hook. With the env var set, every call into
16
+ `circle-ir`'s `analyze()` — from both the scanner static path and the
17
+ mastra `runPatternMatch` LLM path — emits one `[finding]` JSON line on
18
+ stderr per `SastFinding` plus one `[findings-summary]` line per file.
19
+
20
+ Each `[finding]` payload carries the fields required to re-derive
21
+ coalesce candidates for cognium-dev#143 after the fact:
22
+
23
+ ```jsonc
24
+ {
25
+ "file": "VulnServlet.java",
26
+ "line": 9,
27
+ "rule_id": "sql-injection-jdbc",
28
+ "pass": "TaintMatcherPass",
29
+ "category": "security",
30
+ "severity": "high",
31
+ "cwe": "CWE-89",
32
+ "sink_type": "sql-query",
33
+ "source_type": "http-param",
34
+ "confidence": 0.95,
35
+ "dedup_group_id": "VulnServlet.java:9:sql-injection-jdbc"
36
+ }
37
+ ```
38
+
39
+ Per-file summary payload:
40
+
41
+ ```jsonc
42
+ {
43
+ "file": "VulnServlet.java",
44
+ "total": 3,
45
+ "unique_groups": 2,
46
+ "max_findings_per_group": 2,
47
+ "sources_count": 1,
48
+ "sinks_count": 1,
49
+ "by_rule": { "sql-injection-jdbc": 3 },
50
+ "by_severity": { "high": 3 }
51
+ }
52
+ ```
53
+
54
+ The wiring lives in `src/utils/analyzer-init.ts` so any call into
55
+ `ensureAnalyzerInitialized()` — which both `scanner.ts` and mastra's
56
+ `runPatternMatch()` already use — applies the env var idempotently. No
57
+ public API change; `setFindingsInstrumentation()` remains the
58
+ programmatic entry point for non-CLI consumers.
59
+
60
+ Output is `console.error` (per the upstream hook contract — see
61
+ `circle-ir/dist/analysis/findings-instrumentation.js:13-15`). Redirect
62
+ stderr to capture: `CIRCLE_IR_INSTRUMENT_FINDINGS=1 cognium-ai scan ./src
63
+ 2> findings.jsonl`. The flag is fully no-op when unset; no perf or
64
+ allocation overhead on the default path.
65
+
66
+ ### Why this matters
67
+
68
+ The empirical data collected here informs the **cognium-dev#143
69
+ "coalesce candidates"** decision. The `dedup_group_id` field plus per-
70
+ file `max_findings_per_group` count let us measure how often
71
+ `(file, line, rule_id)` clusters actually receive multiple
72
+ near-duplicate emissions in the wild. That measurement is the gating
73
+ input for whether circle-ir's findings pipeline should add a
74
+ post-emit coalesce pass or leave the existing dedup logic alone.
75
+
76
+ ### Verification
77
+
78
+ - `npm run build` — clean.
79
+ - `npm run typecheck` — clean.
80
+ - `npm test` — **900 / 900 pass + 3 skipped** (+2 new tests
81
+ `findings-instrumentation.test.ts` covering both env states).
82
+ - Manual: `CIRCLE_IR_INSTRUMENT_FINDINGS=1 ...` emits `[finding]` and
83
+ `[findings-summary]` lines on stderr; unsetting suppresses both.
84
+
85
+ ### Why minor (`2.17.0 → 2.18.0`)
86
+
87
+ Additive: new env-var honored at init time, no removed or renamed
88
+ exports, no change to the default observable output. Downstream
89
+ packages (`cognium-ai`, `@cognium-ai/mcp-server`, `circle-pack`) need a
90
+ dep range bump but no source-side change to benefit — setting the env
91
+ var is enough.
92
+
93
+ ## [2.17.0] - 2026-06-22
94
+
95
+ ### Dependencies
96
+
97
+ - Bump `circle-ir` `3.89.1` → `3.90.0`.
98
+
99
+ ### What 3.90.0 brings (inherited, no source-side changes here)
100
+
101
+ `circle-ir@3.90.0` adds the **findings-emission instrumentation hook**
102
+ that closes out cognium-dev#145 (PR B). Per-file `SastFinding[]`
103
+ finalization now emits to an opt-in JSONL sink controlled by the
104
+ engine's instrumentation surface (`emitFindingsInstrumentation`
105
+ callback / env-var hook — see circle-ir 3.90.0 release notes for the
106
+ exact wiring). This is the data source #143 will consume to evaluate
107
+ coalesce hypotheses against real CLI workloads.
108
+
109
+ Per-finding payload includes at minimum: `ruleId`, `file`, `line`,
110
+ `sinkType`, `sourceType`, `severity`, `confidence`, `dedup_group_id`.
111
+ **Payload schema is stable-additive** — the engine reserves the right
112
+ to add new fields driven by #143's analysis without a major bump.
113
+ Consumers should ignore unknown keys. Function signature is the
114
+ freeze point.
115
+
116
+ ### What `circle-ir-ai` does with the hook (today: nothing)
117
+
118
+ Engine-side surface is opt-in; no `circle-ir-ai` source exercises
119
+ the hook yet. The intended consumer is PR C in `circle-ir-ai`
120
+ itself (separate cycle), which will wire the hook through the
121
+ mastra `runPatternMatch → analyze()` path so cognium-ai scans
122
+ surface the instrumentation without users having to import
123
+ `circle-ir` directly. Until PR C ships, the hook fires only for
124
+ direct `circle-ir` consumers that opt in.
125
+
126
+ ### Verification
127
+
128
+ - `npm install --prefer-online` — clean; `npm ls circle-ir` shows
129
+ `3.90.0`.
130
+ - `npm run build` — clean.
131
+ - `npm run typecheck` — clean.
132
+ - `npm test` — **898 / 898 pass** (3 skipped).
133
+
134
+ ### Why minor (`2.16.0 → 2.17.0`)
135
+
136
+ New engine surface is reachable via direct `circle-ir` import even
137
+ though no `circle-ir-ai` code-path exercises it yet. Minor bump
138
+ signals the underlying capability uplift to downstream consumers
139
+ (mcp-server, circle-pack) that may wire the hook independently.
140
+
8
141
  ## [2.16.0] - 2026-06-22
9
142
 
10
143
  ### Added
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer-init.d.ts","sourceRoot":"","sources":["../../src/utils/analyzer-init.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAuC,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAKtF;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBjG;AAGD,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"analyzer-init.d.ts","sourceRoot":"","sources":["../../src/utils/analyzer-init.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,WAAW,CAAC;AAgCnB;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BjG;AAGD,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
@@ -5,14 +5,44 @@
5
5
  * This fixes issues when cognium-ai is installed globally or in various
6
6
  * node_modules configurations.
7
7
  */
8
- import { initAnalyzer, isAnalyzerInitialized } from 'circle-ir';
8
+ import { initAnalyzer, isAnalyzerInitialized, setFindingsInstrumentation, } from 'circle-ir';
9
9
  import { getWasmAnalyzerOptions } from './wasm-path.js';
10
10
  let initializationPromise = null;
11
+ let instrumentationApplied = false;
12
+ /**
13
+ * cognium-dev#145 PR C — honor `CIRCLE_IR_INSTRUMENT_FINDINGS=1` at
14
+ * analyzer-init time so every path that hits circle-ir's `analyze()`
15
+ * (scanner static path + mastra `runPatternMatch` LLM path) emits the
16
+ * per-file `[finding]` / `[findings-summary]` JSON lines on stderr.
17
+ *
18
+ * `circle-ir`'s library does not read the env var itself — only its
19
+ * own CLI does. We translate the env var to `setFindingsInstrumentation(true)`
20
+ * here so cognium-ai runs honor the same opt-in toggle without each CLI
21
+ * needing to re-implement the wiring.
22
+ *
23
+ * Idempotent: only flips the toggle on once per process even though
24
+ * `ensureAnalyzerInitialized` may be called many times. Never disables
25
+ * the flag — external `setFindingsInstrumentation(false)` calls still
26
+ * take effect.
27
+ */
28
+ function applyInstrumentationEnv() {
29
+ if (instrumentationApplied) {
30
+ return;
31
+ }
32
+ instrumentationApplied = true;
33
+ if (process.env.CIRCLE_IR_INSTRUMENT_FINDINGS === '1') {
34
+ setFindingsInstrumentation(true);
35
+ }
36
+ }
11
37
  /**
12
38
  * Initialize the analyzer with proper WASM path resolution.
13
39
  * Safe to call multiple times - will only initialize once.
14
40
  */
15
41
  export async function ensureAnalyzerInitialized(options) {
42
+ // Apply instrumentation toggle on every call (cheap, idempotent) so the
43
+ // env-var check happens even when the analyzer was warmed by an unrelated
44
+ // import path.
45
+ applyInstrumentationEnv();
16
46
  if (isAnalyzerInitialized()) {
17
47
  return;
18
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer-init.js","sourceRoot":"","sources":["../../src/utils/analyzer-init.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAwB,MAAM,WAAW,CAAC;AACtF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAExD,IAAI,qBAAqB,GAAyB,IAAI,CAAC;AAEvD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,OAAkC;IAChF,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,IAAI,qBAAqB,EAAE,CAAC;QAC1B,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,qBAAqB,GAAG,CAAC,KAAK,IAAI,EAAE;QAClC,gDAAgD;QAChD,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;QAE7C,uCAAuC;QACvC,MAAM,aAAa,GAAoB;YACrC,GAAG,WAAW;YACd,GAAG,OAAO;SACX,CAAC;QAEF,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"analyzer-init.js","sourceRoot":"","sources":["../../src/utils/analyzer-init.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,0BAA0B,GAE3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAExD,IAAI,qBAAqB,GAAyB,IAAI,CAAC;AACvD,IAAI,sBAAsB,GAAG,KAAK,CAAC;AAEnC;;;;;;;;;;;;;;;GAeG;AACH,SAAS,uBAAuB;IAC9B,IAAI,sBAAsB,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,sBAAsB,GAAG,IAAI,CAAC;IAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,GAAG,EAAE,CAAC;QACtD,0BAA0B,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,OAAkC;IAChF,wEAAwE;IACxE,0EAA0E;IAC1E,eAAe;IACf,uBAAuB,EAAE,CAAC;IAE1B,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,IAAI,qBAAqB,EAAE,CAAC;QAC1B,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,qBAAqB,GAAG,CAAC,KAAK,IAAI,EAAE;QAClC,gDAAgD;QAChD,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;QAE7C,uCAAuC;QACvC,MAAM,aAAa,GAAoB;YACrC,GAAG,WAAW;YACd,GAAG,OAAO;SACX,CAAC;QAEF,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "circle-ir-ai",
3
- "version": "2.16.0",
3
+ "version": "2.18.0",
4
4
  "description": "LLM-enhanced SAST analysis built on circle-ir",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -95,7 +95,7 @@
95
95
  "dependencies": {
96
96
  "@ax-llm/ax": "^20.0.0",
97
97
  "@mastra/core": "^1.18.0",
98
- "circle-ir": "3.89.1",
98
+ "circle-ir": "3.90.0",
99
99
  "minimatch": "^10.2.5",
100
100
  "p-queue": "^9.1.0"
101
101
  },