tryassay 0.33.2 → 0.35.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 (164) hide show
  1. package/dist/bayesian/__tests__/bas-calculator.test.d.ts +1 -0
  2. package/dist/bayesian/__tests__/bas-calculator.test.js +63 -0
  3. package/dist/bayesian/__tests__/bas-calculator.test.js.map +1 -0
  4. package/dist/bayesian/__tests__/structural-entropy.test.d.ts +1 -0
  5. package/dist/bayesian/__tests__/structural-entropy.test.js +21 -0
  6. package/dist/bayesian/__tests__/structural-entropy.test.js.map +1 -0
  7. package/dist/bayesian/bas-calculator.d.ts +41 -0
  8. package/dist/bayesian/bas-calculator.js +198 -0
  9. package/dist/bayesian/bas-calculator.js.map +1 -0
  10. package/dist/bayesian/index.d.ts +3 -0
  11. package/dist/bayesian/index.js +3 -0
  12. package/dist/bayesian/index.js.map +1 -0
  13. package/dist/bayesian/structural-entropy.d.ts +12 -0
  14. package/dist/bayesian/structural-entropy.js +37 -0
  15. package/dist/bayesian/structural-entropy.js.map +1 -0
  16. package/dist/bayesian/types.d.ts +37 -0
  17. package/dist/bayesian/types.js +6 -0
  18. package/dist/bayesian/types.js.map +1 -0
  19. package/dist/cli.js +46 -0
  20. package/dist/cli.js.map +1 -1
  21. package/dist/commands/__tests__/assess-formal.test.d.ts +1 -0
  22. package/dist/commands/__tests__/assess-formal.test.js +72 -0
  23. package/dist/commands/__tests__/assess-formal.test.js.map +1 -0
  24. package/dist/commands/activate.d.ts +1 -0
  25. package/dist/commands/activate.js +48 -0
  26. package/dist/commands/activate.js.map +1 -0
  27. package/dist/commands/assess.js +100 -5
  28. package/dist/commands/assess.js.map +1 -1
  29. package/dist/commands/bas-score.d.ts +13 -0
  30. package/dist/commands/bas-score.js +310 -0
  31. package/dist/commands/bas-score.js.map +1 -0
  32. package/dist/commands/bounty-watch.js.map +1 -1
  33. package/dist/commands/hunt.js +32 -0
  34. package/dist/commands/hunt.js.map +1 -1
  35. package/dist/commands/mcp.d.ts +14 -0
  36. package/dist/commands/mcp.js +18 -0
  37. package/dist/commands/mcp.js.map +1 -0
  38. package/dist/commands/runtime.js +11 -10
  39. package/dist/commands/runtime.js.map +1 -1
  40. package/dist/commands/stream-verify.d.ts +16 -0
  41. package/dist/commands/stream-verify.js +228 -0
  42. package/dist/commands/stream-verify.js.map +1 -0
  43. package/dist/commands/watch.d.ts +19 -0
  44. package/dist/commands/watch.js +158 -0
  45. package/dist/commands/watch.js.map +1 -0
  46. package/dist/hunt/__tests__/deep-dive.test.js.map +1 -1
  47. package/dist/hunt/__tests__/e2e.test.js.map +1 -1
  48. package/dist/hunt/__tests__/finding-to-template.test.js +10 -1
  49. package/dist/hunt/__tests__/finding-to-template.test.js.map +1 -1
  50. package/dist/hunt/__tests__/orchestrator.test.js.map +1 -1
  51. package/dist/hunt/__tests__/templates.test.js +2 -2
  52. package/dist/hunt/__tests__/triage.test.js.map +1 -1
  53. package/dist/hunt/deep-dive.js +7 -7
  54. package/dist/hunt/deep-dive.js.map +1 -1
  55. package/dist/hunt/parse-utils.d.ts +1 -1
  56. package/dist/hunt/state.js.map +1 -1
  57. package/dist/hunt/templates/injection.js +1 -1
  58. package/dist/hunt/templates/injection.js.map +1 -1
  59. package/dist/hunt/triage.js +5 -5
  60. package/dist/hunt/triage.js.map +1 -1
  61. package/dist/lib/__tests__/arithmetic-quick-test.js +10 -9
  62. package/dist/lib/__tests__/arithmetic-quick-test.js.map +1 -1
  63. package/dist/lib/__tests__/arithmetic-real-llm-test.js +8 -8
  64. package/dist/lib/__tests__/arithmetic-real-llm-test.js.map +1 -1
  65. package/dist/lib/__tests__/formal-verifier-behavioral.test.d.ts +18 -0
  66. package/dist/lib/__tests__/formal-verifier-behavioral.test.js +576 -0
  67. package/dist/lib/__tests__/formal-verifier-behavioral.test.js.map +1 -0
  68. package/dist/lib/__tests__/formal-verifier-claimless-async.test.d.ts +1 -0
  69. package/dist/lib/__tests__/formal-verifier-claimless-async.test.js +154 -0
  70. package/dist/lib/__tests__/formal-verifier-claimless-async.test.js.map +1 -0
  71. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.d.ts +1 -0
  72. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.js +121 -0
  73. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.js.map +1 -0
  74. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.d.ts +1 -0
  75. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.js +119 -0
  76. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.js.map +1 -0
  77. package/dist/lib/__tests__/formal-verifier-claimless.test.d.ts +1 -0
  78. package/dist/lib/__tests__/formal-verifier-claimless.test.js +667 -0
  79. package/dist/lib/__tests__/formal-verifier-claimless.test.js.map +1 -0
  80. package/dist/lib/__tests__/mr-gsm8k-benchmark.js +6 -6
  81. package/dist/lib/__tests__/mr-gsm8k-benchmark.js.map +1 -1
  82. package/dist/lib/__tests__/pr-harvester.test.js.map +1 -1
  83. package/dist/lib/assessment-reporter.d.ts +1 -1
  84. package/dist/lib/assessment-reporter.js +2 -1
  85. package/dist/lib/assessment-reporter.js.map +1 -1
  86. package/dist/lib/chain-analyzer.d.ts +4 -3
  87. package/dist/lib/chain-analyzer.js.map +1 -1
  88. package/dist/lib/formal-verifier.d.ts +20 -1
  89. package/dist/lib/formal-verifier.js +1180 -23
  90. package/dist/lib/formal-verifier.js.map +1 -1
  91. package/dist/lib/issue-reporter.d.ts +2 -1
  92. package/dist/lib/issue-reporter.js.map +1 -1
  93. package/dist/lib/remediation-generator.js.map +1 -1
  94. package/dist/lib/report-generator.js.map +1 -1
  95. package/dist/lib/rule-harvester/ground-truth.js +13 -2
  96. package/dist/lib/rule-harvester/ground-truth.js.map +1 -1
  97. package/dist/lib/rule-harvester/scanner.d.ts +1 -1
  98. package/dist/lib/user-config.d.ts +1 -0
  99. package/dist/lib/user-config.js.map +1 -1
  100. package/dist/realtime/__tests__/catch-real-bugs.test.d.ts +9 -0
  101. package/dist/realtime/__tests__/catch-real-bugs.test.js +205 -0
  102. package/dist/realtime/__tests__/catch-real-bugs.test.js.map +1 -0
  103. package/dist/realtime/__tests__/code-buffer.test.d.ts +1 -0
  104. package/dist/realtime/__tests__/code-buffer.test.js +202 -0
  105. package/dist/realtime/__tests__/code-buffer.test.js.map +1 -0
  106. package/dist/realtime/__tests__/correction-injector.test.d.ts +1 -0
  107. package/dist/realtime/__tests__/correction-injector.test.js +168 -0
  108. package/dist/realtime/__tests__/correction-injector.test.js.map +1 -0
  109. package/dist/realtime/__tests__/entropy-detector.test.d.ts +1 -0
  110. package/dist/realtime/__tests__/entropy-detector.test.js +200 -0
  111. package/dist/realtime/__tests__/entropy-detector.test.js.map +1 -0
  112. package/dist/realtime/__tests__/entropy-live-demo.d.ts +1 -0
  113. package/dist/realtime/__tests__/entropy-live-demo.js +103 -0
  114. package/dist/realtime/__tests__/entropy-live-demo.js.map +1 -0
  115. package/dist/realtime/__tests__/entropy-live.d.ts +8 -0
  116. package/dist/realtime/__tests__/entropy-live.js +114 -0
  117. package/dist/realtime/__tests__/entropy-live.js.map +1 -0
  118. package/dist/realtime/__tests__/stream-interceptor.test.d.ts +1 -0
  119. package/dist/realtime/__tests__/stream-interceptor.test.js +193 -0
  120. package/dist/realtime/__tests__/stream-interceptor.test.js.map +1 -0
  121. package/dist/realtime/__tests__/streaming-checks.test.d.ts +1 -0
  122. package/dist/realtime/__tests__/streaming-checks.test.js +478 -0
  123. package/dist/realtime/__tests__/streaming-checks.test.js.map +1 -0
  124. package/dist/realtime/__tests__/streaming-verifier.test.d.ts +1 -0
  125. package/dist/realtime/__tests__/streaming-verifier.test.js +157 -0
  126. package/dist/realtime/__tests__/streaming-verifier.test.js.map +1 -0
  127. package/dist/realtime/code-buffer.d.ts +52 -0
  128. package/dist/realtime/code-buffer.js +276 -0
  129. package/dist/realtime/code-buffer.js.map +1 -0
  130. package/dist/realtime/correction-injector.d.ts +56 -0
  131. package/dist/realtime/correction-injector.js +96 -0
  132. package/dist/realtime/correction-injector.js.map +1 -0
  133. package/dist/realtime/entropy-detector.d.ts +143 -0
  134. package/dist/realtime/entropy-detector.js +504 -0
  135. package/dist/realtime/entropy-detector.js.map +1 -0
  136. package/dist/realtime/index.d.ts +14 -0
  137. package/dist/realtime/index.js +11 -0
  138. package/dist/realtime/index.js.map +1 -0
  139. package/dist/realtime/mcp-server.d.ts +20 -0
  140. package/dist/realtime/mcp-server.js +576 -0
  141. package/dist/realtime/mcp-server.js.map +1 -0
  142. package/dist/realtime/stream-interceptor.d.ts +93 -0
  143. package/dist/realtime/stream-interceptor.js +378 -0
  144. package/dist/realtime/stream-interceptor.js.map +1 -0
  145. package/dist/realtime/streaming-checks.d.ts +55 -0
  146. package/dist/realtime/streaming-checks.js +480 -0
  147. package/dist/realtime/streaming-checks.js.map +1 -0
  148. package/dist/realtime/streaming-verifier.d.ts +102 -0
  149. package/dist/realtime/streaming-verifier.js +227 -0
  150. package/dist/realtime/streaming-verifier.js.map +1 -0
  151. package/dist/realtime/types.d.ts +155 -0
  152. package/dist/realtime/types.js +8 -0
  153. package/dist/realtime/types.js.map +1 -0
  154. package/dist/runtime/agents/research-agent.js +10 -1
  155. package/dist/runtime/agents/research-agent.js.map +1 -1
  156. package/dist/runtime/agents/test-agent.js +10 -7
  157. package/dist/runtime/agents/test-agent.js.map +1 -1
  158. package/dist/runtime/composition-verifier.js +13 -3
  159. package/dist/runtime/composition-verifier.js.map +1 -1
  160. package/dist/runtime/fs-helpers.js.map +1 -1
  161. package/dist/runtime/prompt-safety-analyzer.js.map +1 -1
  162. package/dist/sdk/verified-generate.js.map +1 -1
  163. package/dist/types.d.ts +14 -0
  164. package/package.json +4 -2
@@ -0,0 +1,480 @@
1
+ /**
2
+ * Streaming Checks — stateless, pre-compiled pattern matchers for real-time verification.
3
+ *
4
+ * Extracts the regex-based formal verification checks from the existing
5
+ * formal-verifier.ts into standalone StreamingCheck objects. Also loads
6
+ * learned rules from the catalog and compiles them into the same format.
7
+ *
8
+ * All regex patterns are created once at module load time and reused across
9
+ * invocations. The `runChecks` function targets <10ms for the full check set
10
+ * against a single code unit.
11
+ */
12
+ import { readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+ // ── Formal Checks (hand-crafted) ────────────────────────────────
15
+ const JS_LANGS = ['typescript', 'javascript', 'ts', 'js', 'tsx', 'jsx'];
16
+ const PY_LANGS = ['python', 'py'];
17
+ const ALL_LANGS = []; // empty = applies to all
18
+ /**
19
+ * Libraries that use tagged template literals for SQL parameterization.
20
+ * When these imports are detected, template literal SQL checks are suppressed
21
+ * because ${} values are sent as bound parameters, not string-concatenated.
22
+ *
23
+ * - postgres / postgresjs: sql`SELECT * FROM users WHERE id = ${id}`
24
+ * - slonik: sql.unsafe`...` (raw) vs sql`...` (parameterized)
25
+ * - @electric-sql/pglite: tagged template syntax
26
+ * - sql-template-strings / sql-template-tag: tagged template helpers
27
+ */
28
+ const TAGGED_TEMPLATE_SQL_LIBS = [
29
+ /from\s+['"]postgres['"]/, // import postgres from 'postgres'
30
+ /require\s*\(\s*['"]postgres['"]\s*\)/, // const sql = require('postgres')
31
+ /from\s+['"]slonik['"]/,
32
+ /from\s+['"]@electric-sql\/pglite['"]/,
33
+ /from\s+['"]sql-template-strings['"]/,
34
+ /from\s+['"]sql-template-tag['"]/,
35
+ /postgres\.Sql\b/, // type annotation: db: postgres.Sql
36
+ /:\s*Sql\b/, // short form: db: Sql (with import type { Sql } from 'postgres')
37
+ ];
38
+ /**
39
+ * Returns all hand-crafted formal checks as StreamingCheck objects.
40
+ *
41
+ * These cover the key vulnerability patterns from formal-verifier.ts,
42
+ * adapted for streaming (line/statement-level) detection during generation.
43
+ */
44
+ export function getFormalChecks() {
45
+ return FORMAL_CHECKS;
46
+ }
47
+ const FORMAL_CHECKS = [
48
+ // 1. SQL injection — string concatenation in queries
49
+ {
50
+ id: 'sql_concat_injection',
51
+ name: 'SQL string concatenation',
52
+ languages: [...JS_LANGS, ...PY_LANGS],
53
+ pattern: /(?:SELECT|INSERT|UPDATE|DELETE)\s[^;]*["'`]\s*\+\s*\w+/i,
54
+ verdict: 'FAIL',
55
+ severity: 'critical',
56
+ evidenceTemplate: 'SQL query uses string concatenation: $0',
57
+ suggestion: 'Use parameterized queries ($1, ?, or :named placeholders) instead of string concatenation.',
58
+ source: 'formal',
59
+ },
60
+ {
61
+ id: 'sql_template_injection',
62
+ name: 'SQL template literal injection',
63
+ languages: JS_LANGS,
64
+ pattern: /`[^`]*(?:SELECT|INSERT|UPDATE|DELETE)[^`]*\$\{(?!\d)/i,
65
+ verdict: 'FAIL',
66
+ severity: 'critical',
67
+ evidenceTemplate: 'SQL query uses template literal interpolation: $0',
68
+ suggestion: 'Use parameterized queries instead of template literal interpolation in SQL strings.',
69
+ source: 'formal',
70
+ // Suppressed when file uses tagged template libraries (postgres.js, slonik, pglite, sql-template-strings)
71
+ // These libraries use tagged template literals as their parameterization mechanism — ${} values
72
+ // are sent as bound parameters, not concatenated into SQL strings.
73
+ suppressWhen: TAGGED_TEMPLATE_SQL_LIBS,
74
+ },
75
+ // 2. Missing error handling — unhandled promise chains
76
+ {
77
+ id: 'unhandled_promise',
78
+ name: 'Unhandled promise (no .catch)',
79
+ languages: JS_LANGS,
80
+ pattern: /(?:fetch|axios\.\w+)\s*\([^)]*\)\s*\.then\s*\([^)]*\)(?![\s\S]*\.catch)/,
81
+ verdict: 'FAIL',
82
+ severity: 'high',
83
+ evidenceTemplate: 'Promise chain without .catch() handler: $0',
84
+ suggestion: 'Add a .catch() handler or use try/catch with await.',
85
+ source: 'formal',
86
+ },
87
+ // 3. Hardcoded credentials/secrets
88
+ {
89
+ id: 'hardcoded_secret',
90
+ name: 'Hardcoded secret or API key',
91
+ languages: ALL_LANGS,
92
+ pattern: /(?:const|let|var|=)\s*(?:\w+)?\s*(?:api[_-]?key|secret|password|token|auth)\s*=\s*["'`](?:sk-|pk-|ghp_|gho_|github_pat_|xox[bpors]-|AIza|AKIA|bearer\s).{8,}/i,
93
+ verdict: 'FAIL',
94
+ severity: 'critical',
95
+ evidenceTemplate: 'Hardcoded secret detected: $0',
96
+ suggestion: 'Use environment variables or a secrets manager instead of hardcoding credentials.',
97
+ source: 'formal',
98
+ },
99
+ // 4. Unsafe eval / Function constructor
100
+ {
101
+ id: 'unsafe_eval',
102
+ name: 'Unsafe eval() usage',
103
+ languages: JS_LANGS,
104
+ pattern: /\beval\s*\(\s*(?!\s*['"`][\s\S]*['"`]\s*\))/, // eval( but not eval("literal")
105
+ verdict: 'FAIL',
106
+ severity: 'critical',
107
+ evidenceTemplate: 'Unsafe eval() call detected: $0',
108
+ suggestion: 'Replace eval() with a safer alternative like JSON.parse() or a sandboxed evaluator.',
109
+ source: 'formal',
110
+ },
111
+ {
112
+ id: 'unsafe_function_constructor',
113
+ name: 'Unsafe Function constructor',
114
+ languages: JS_LANGS,
115
+ pattern: /new\s+Function\s*\(/,
116
+ verdict: 'FAIL',
117
+ severity: 'critical',
118
+ evidenceTemplate: 'Unsafe new Function() call detected: $0',
119
+ suggestion: 'Avoid new Function(). Use static code paths or a sandboxed evaluator.',
120
+ source: 'formal',
121
+ },
122
+ // 5. Insecure randomness (Math.random for security)
123
+ {
124
+ id: 'insecure_random',
125
+ name: 'Math.random() used for security',
126
+ languages: JS_LANGS,
127
+ pattern: /(?:token|secret|key|nonce|csrf|session|password|salt|hash)\s*(?:=|:)\s*.*Math\.random/i,
128
+ verdict: 'FAIL',
129
+ severity: 'high',
130
+ evidenceTemplate: 'Math.random() used in security-sensitive context: $0',
131
+ suggestion: 'Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive random values.',
132
+ source: 'formal',
133
+ },
134
+ {
135
+ id: 'insecure_random_token',
136
+ name: 'Math.random() token generation',
137
+ languages: JS_LANGS,
138
+ pattern: /Math\.random\(\)\.toString\(36\)/,
139
+ verdict: 'FAIL',
140
+ severity: 'high',
141
+ evidenceTemplate: 'Insecure token generation using Math.random(): $0',
142
+ suggestion: 'Use crypto.randomUUID() or crypto.randomBytes() for token generation.',
143
+ source: 'formal',
144
+ },
145
+ // 6. Prototype pollution patterns
146
+ {
147
+ id: 'prototype_pollution',
148
+ name: 'Prototype pollution risk',
149
+ languages: JS_LANGS,
150
+ pattern: /\w+\[(?:\w+|\w+\[\w+\])\]\s*=\s*(?!\s*(?:null|undefined|false|true|0|''|""|``)\s*[;,)])/,
151
+ verdict: 'FAIL',
152
+ severity: 'high',
153
+ evidenceTemplate: 'Dynamic property assignment may allow prototype pollution: $0',
154
+ suggestion: 'Validate property names against __proto__, constructor, and prototype before dynamic assignment.',
155
+ source: 'formal',
156
+ },
157
+ // 7. Path traversal
158
+ {
159
+ id: 'path_traversal',
160
+ name: 'Path traversal vulnerability',
161
+ languages: [...JS_LANGS, ...PY_LANGS],
162
+ pattern: /(?:readFile|readFileSync|createReadStream|writeFile|writeFileSync|open)\s*\(\s*(?:req\.(?:params|query|body)|request\.(?:args|form|json))\s*[\[.]/,
163
+ verdict: 'FAIL',
164
+ severity: 'critical',
165
+ evidenceTemplate: 'User input passed directly to filesystem operation: $0',
166
+ suggestion: 'Sanitize file paths with path.resolve() and verify they stay within the intended directory.',
167
+ source: 'formal',
168
+ },
169
+ // 8. Command injection
170
+ {
171
+ id: 'command_injection',
172
+ name: 'Command injection vulnerability',
173
+ languages: [...JS_LANGS, ...PY_LANGS],
174
+ pattern: /(?:exec|execSync|spawn|spawnSync|system|popen)\s*\(\s*(?:["'`][^"'`]*["'`]\s*\+|`[^`]*\$\{)/,
175
+ verdict: 'FAIL',
176
+ severity: 'critical',
177
+ evidenceTemplate: 'Command injection risk — shell command built with concatenation: $0',
178
+ suggestion: 'Use execFile() or spawn() with an argument array instead of exec() with string concatenation.',
179
+ source: 'formal',
180
+ },
181
+ // 9. Null/undefined access without check
182
+ {
183
+ id: 'unchecked_array_index',
184
+ name: 'Unchecked array index access',
185
+ languages: JS_LANGS,
186
+ pattern: /\w+\[0\]\.\w+(?!\s*\?\.)/, // arr[0].prop without optional chaining
187
+ verdict: 'FAIL',
188
+ severity: 'medium',
189
+ evidenceTemplate: 'Array element accessed without null check: $0',
190
+ suggestion: 'Check array length before accessing elements, or use optional chaining (arr[0]?.prop).',
191
+ source: 'formal',
192
+ },
193
+ // 10. Input validation missing — direct use of request params in DB queries
194
+ {
195
+ id: 'unvalidated_input_to_query',
196
+ name: 'Unvalidated input passed to database query',
197
+ languages: JS_LANGS,
198
+ pattern: /\.(?:query|execute|findOne|find|delete|update)\s*\(\s*\{[^}]*(?:req\.(?:params|query|body)|request\.\w+)/,
199
+ verdict: 'FAIL',
200
+ severity: 'high',
201
+ evidenceTemplate: 'Request input passed directly to database query without validation: $0',
202
+ suggestion: 'Validate and sanitize request input with zod, joi, or manual type checks before passing to queries.',
203
+ source: 'formal',
204
+ },
205
+ ];
206
+ // ── Learned Rule Conversion ─────────────────────────────────────
207
+ /**
208
+ * Keyword map: maps keyword triggers found in rule name/description/category
209
+ * to context keywords that must appear in code for the rule to be relevant.
210
+ *
211
+ * When a rule's name, description, or category contains a trigger (left side),
212
+ * the associated keywords (right side) are assigned. The check only runs if
213
+ * at least one keyword is found in the code unit text.
214
+ */
215
+ const CONTEXT_KEYWORD_MAP = [
216
+ // React / JSX
217
+ {
218
+ triggers: /\b(?:react|jsx|tsx|component|hook|use[A-Z]\w+|memo(?:iz)|useEffect|useState|useRef|useCallback|useMemo)\b/i,
219
+ keywords: ['React', 'useState', 'useEffect', 'useRef', 'useCallback', 'useMemo', 'jsx', 'tsx', 'import react', 'from \'react', 'from "react'],
220
+ },
221
+ // OpenAPI / Swagger / NestJS decorators
222
+ {
223
+ triggers: /\b(?:openapi|swagger|@Api\w*|@Controller|@Get|@Post|@Put|@Delete|@Patch|decorator|NestJS)\b/i,
224
+ keywords: ['@Api', '@Controller', '@Get(', '@Post(', '@Put(', '@Delete(', '@Patch(', 'swagger', 'openapi', '@nestjs'],
225
+ },
226
+ // Canvas / Drawing / 2D rendering
227
+ {
228
+ triggers: /\b(?:canvas|drawImage|getContext|2d\s*context|fillRect|strokeRect|beginPath|WebGL)\b/i,
229
+ keywords: ['canvas', 'drawImage', 'getContext', 'fillRect', 'strokeRect', 'beginPath', 'CanvasRenderingContext', 'webgl'],
230
+ },
231
+ // Stripe
232
+ {
233
+ triggers: /\b(?:stripe|payment.?intent|checkout.?session|subscription)\b/i,
234
+ keywords: ['stripe', 'Stripe', 'payment_intent', 'checkout.sessions', 'PaymentIntent'],
235
+ },
236
+ // GraphQL
237
+ {
238
+ triggers: /\b(?:graphql|resolver|mutation|gql`|@Query|@Mutation|@Resolver)\b/i,
239
+ keywords: ['graphql', 'GraphQL', 'gql`', '@Query', '@Mutation', '@Resolver', 'typeDefs', 'resolvers'],
240
+ },
241
+ // Docker / Container
242
+ {
243
+ triggers: /\b(?:docker|dockerfile|container|ENTRYPOINT|CMD\s)\b/i,
244
+ keywords: ['FROM ', 'ENTRYPOINT', 'CMD [', 'EXPOSE ', 'Dockerfile', 'docker-compose'],
245
+ },
246
+ // Redis
247
+ {
248
+ triggers: /\b(?:redis|HSET|HGET|ZADD|pub.?sub|ioredis)\b/i,
249
+ keywords: ['redis', 'Redis', 'ioredis', 'HSET', 'HGET', 'createClient'],
250
+ },
251
+ // MongoDB / Mongoose
252
+ {
253
+ triggers: /\b(?:mongo(?:db|ose)?|Schema\.Types|ObjectId|aggregate)\b/i,
254
+ keywords: ['mongoose', 'MongoDB', 'MongoClient', 'Schema.Types', 'ObjectId', '.aggregate('],
255
+ },
256
+ // Django
257
+ {
258
+ triggers: /\b(?:django|models\.Model|views\.py|urls\.py|INSTALLED_APPS)\b/i,
259
+ keywords: ['django', 'Django', 'models.Model', 'INSTALLED_APPS', 'urlpatterns', 'from django'],
260
+ },
261
+ // Flask
262
+ {
263
+ triggers: /\b(?:flask|@app\.route|Blueprint|Jinja)\b/i,
264
+ keywords: ['flask', 'Flask', '@app.route', 'Blueprint', 'from flask'],
265
+ },
266
+ // Vue
267
+ {
268
+ triggers: /\b(?:vue|v-model|v-bind|v-if|defineComponent|ref\(\)|computed\(\))\b/i,
269
+ keywords: ['vue', 'Vue', 'v-model', 'v-bind', 'defineComponent', 'from \'vue', 'from "vue'],
270
+ },
271
+ // Angular
272
+ {
273
+ triggers: /\b(?:angular|@Component|@Injectable|@NgModule|ngOnInit)\b/i,
274
+ keywords: ['@Component', '@Injectable', '@NgModule', 'ngOnInit', '@angular', 'from \'@angular'],
275
+ },
276
+ // WebSocket
277
+ {
278
+ triggers: /\b(?:websocket|ws:\/\/|wss:\/\/|socket\.io|onmessage)\b/i,
279
+ keywords: ['WebSocket', 'ws://', 'wss://', 'socket.io', 'onmessage', 'Socket('],
280
+ },
281
+ // AWS SDK
282
+ {
283
+ triggers: /\b(?:aws.?sdk|S3Client|DynamoDB|Lambda|SQS|SNS|@aws-sdk)\b/i,
284
+ keywords: ['aws-sdk', '@aws-sdk', 'S3Client', 'DynamoDB', 'LambdaClient', 'SQSClient'],
285
+ },
286
+ // Prisma
287
+ {
288
+ triggers: /\b(?:prisma|PrismaClient|prisma\.\$|findUnique|findMany)\b/i,
289
+ keywords: ['prisma', 'Prisma', 'PrismaClient', 'prisma.', '@prisma/client'],
290
+ },
291
+ ];
292
+ /**
293
+ * Derive context keywords for a learned rule based on its name, description,
294
+ * and category. Returns undefined if no specific context can be inferred
295
+ * (the rule will run against all code units).
296
+ */
297
+ function deriveContextKeywords(rule) {
298
+ const searchText = [
299
+ rule.pattern.description,
300
+ rule.pattern.claimCategory,
301
+ rule.id,
302
+ rule.fixDescription ?? '',
303
+ ].join(' ');
304
+ for (const entry of CONTEXT_KEYWORD_MAP) {
305
+ if (entry.triggers.test(searchText)) {
306
+ return entry.keywords;
307
+ }
308
+ }
309
+ // Fallback: try to extract literal strings from the regex pattern itself.
310
+ // Sequences of 4+ alphanumeric chars (likely meaningful identifiers).
311
+ if (rule.pattern.regexPattern) {
312
+ const literals = extractRegexLiterals(rule.pattern.regexPattern);
313
+ if (literals.length > 0) {
314
+ return literals;
315
+ }
316
+ }
317
+ return undefined;
318
+ }
319
+ /**
320
+ * Extract literal substrings (4+ alphanumeric chars) from a regex pattern.
321
+ * These are likely the actual identifiers the rule is looking for.
322
+ */
323
+ function extractRegexLiterals(regexStr) {
324
+ // Match sequences of word chars that are at least 4 chars long,
325
+ // excluding common regex syntax fragments
326
+ const REGEX_NOISE = new Set([
327
+ 'true', 'false', 'null', 'undefined', 'this', 'that',
328
+ 'with', 'from', 'each', 'some', 'every', 'filter',
329
+ ]);
330
+ const matches = regexStr.match(/[a-zA-Z_][a-zA-Z0-9_]{3,}/g) ?? [];
331
+ const unique = [...new Set(matches)].filter(m => !REGEX_NOISE.has(m.toLowerCase()));
332
+ return unique.length <= 10 ? unique : unique.slice(0, 10);
333
+ }
334
+ /**
335
+ * Load learned rules from the catalog and convert them to StreamingCheck format.
336
+ *
337
+ * Default path: `.assay/learned/rules.json` relative to process.cwd().
338
+ * Falls back to an empty set if the file doesn't exist (starter rules
339
+ * are loaded separately by getFormalChecks equivalent in the catalog).
340
+ *
341
+ * Each rule is assigned contextKeywords for relevance filtering — the check
342
+ * only runs on code units that contain at least one keyword.
343
+ */
344
+ export function loadLearnedChecks(catalogPath) {
345
+ const filePath = catalogPath ?? join(process.cwd(), '.assay', 'learned', 'rules.json');
346
+ let rules;
347
+ try {
348
+ const content = readFileSync(filePath, 'utf-8');
349
+ const parsed = JSON.parse(content);
350
+ rules = Array.isArray(parsed) ? parsed : [];
351
+ }
352
+ catch {
353
+ // No catalog on disk — return empty (starter rules are part of formal checks)
354
+ return [];
355
+ }
356
+ return rules
357
+ .filter(r => r.status === 'promoted' || r.status === 'validated')
358
+ .filter(r => r.pattern.kind === 'regex' && r.pattern.regexPattern)
359
+ .map(r => learnedRuleToCheck(r));
360
+ }
361
+ function learnedRuleToCheck(rule) {
362
+ let pattern;
363
+ try {
364
+ pattern = new RegExp(rule.pattern.regexPattern, 'i');
365
+ }
366
+ catch {
367
+ // Invalid regex — create a pattern that never matches
368
+ pattern = /(?!)/;
369
+ }
370
+ return {
371
+ id: `learned_${rule.id}`,
372
+ name: rule.pattern.description.slice(0, 80),
373
+ languages: [...rule.pattern.languages],
374
+ pattern,
375
+ verdict: rule.pattern.matchBehavior === 'presence_is_bad' ? 'FAIL' : 'PASS',
376
+ severity: rule.pattern.severity,
377
+ evidenceTemplate: rule.pattern.evidenceTemplate,
378
+ suggestion: rule.fixDescription,
379
+ source: 'learned',
380
+ contextKeywords: deriveContextKeywords(rule),
381
+ };
382
+ }
383
+ // Exported for testing
384
+ export { deriveContextKeywords as _deriveContextKeywords, extractRegexLiterals as _extractRegexLiterals };
385
+ // ── Compilation ─────────────────────────────────────────────────
386
+ /**
387
+ * Filter checks by language and return a pre-compiled set ready for fast execution.
388
+ *
389
+ * If no checks are provided, uses the built-in formal checks.
390
+ */
391
+ export function compileCheckSet(language, checks) {
392
+ const start = performance.now();
393
+ const allChecks = checks ?? FORMAL_CHECKS;
394
+ const langLower = language.toLowerCase();
395
+ const filtered = allChecks.filter(check => {
396
+ if (check.languages.length === 0)
397
+ return true; // applies to all languages
398
+ return check.languages.some(l => l.toLowerCase() === langLower);
399
+ });
400
+ const compileTimeMs = performance.now() - start;
401
+ return {
402
+ checks: filtered,
403
+ language: langLower,
404
+ compileTimeMs,
405
+ };
406
+ }
407
+ // ── Execution ───────────────────────────────────────────────────
408
+ /**
409
+ * Run all checks in the set against a code unit. Returns verification events.
410
+ *
411
+ * Designed to complete in <10ms for the full check set against a typical code unit.
412
+ */
413
+ export function runChecks(unit, checkSet) {
414
+ const events = [];
415
+ const unitStart = performance.now();
416
+ const textLower = unit.text.toLowerCase();
417
+ for (const check of checkSet.checks) {
418
+ // Level 2 filtering: skip checks whose contextKeywords don't match the code
419
+ if (check.contextKeywords && check.contextKeywords.length > 0) {
420
+ const hasRelevantKeyword = check.contextKeywords.some(kw => textLower.includes(kw.toLowerCase()));
421
+ if (!hasRelevantKeyword)
422
+ continue;
423
+ }
424
+ const checkStart = performance.now();
425
+ // Suppression: skip check if any suppressWhen pattern matches the code
426
+ if (check.suppressWhen && check.suppressWhen.some(re => re.test(unit.text))) {
427
+ continue;
428
+ }
429
+ // Reset lastIndex for patterns with the global flag
430
+ check.pattern.lastIndex = 0;
431
+ const match = check.pattern.exec(unit.text);
432
+ const latencyMs = performance.now() - checkStart;
433
+ if (match && check.verdict === 'FAIL') {
434
+ // Pattern matched and that means a failure
435
+ const evidence = formatEvidence(check.evidenceTemplate, match);
436
+ events.push({
437
+ type: 'finding',
438
+ codeUnit: unit,
439
+ checkId: check.id,
440
+ checkName: check.name,
441
+ verdict: 'FAIL',
442
+ evidence,
443
+ severity: check.severity,
444
+ suggestion: check.suggestion,
445
+ latencyMs,
446
+ });
447
+ }
448
+ else if (!match && check.verdict === 'PASS') {
449
+ // Pattern was supposed to match (PASS means "match = good") but didn't
450
+ // This is the absence_is_bad case from learned rules
451
+ events.push({
452
+ type: 'finding',
453
+ codeUnit: unit,
454
+ checkId: check.id,
455
+ checkName: check.name,
456
+ verdict: 'FAIL',
457
+ evidence: formatEvidence(check.evidenceTemplate, null),
458
+ severity: check.severity,
459
+ suggestion: check.suggestion,
460
+ latencyMs,
461
+ });
462
+ }
463
+ // Other cases: match+PASS (good) or no-match+FAIL (no problem found) — no event
464
+ }
465
+ return events;
466
+ }
467
+ // ── Helpers ─────────────────────────────────────────────────────
468
+ function formatEvidence(template, match) {
469
+ if (!match)
470
+ return template;
471
+ let result = template;
472
+ // Replace $0 with full match
473
+ result = result.replace(/\$0/g, match[0]);
474
+ // Replace $1, $2, etc. with capture groups
475
+ for (let i = 1; i < match.length; i++) {
476
+ result = result.replace(new RegExp(`\\$${i}`, 'g'), match[i] ?? '');
477
+ }
478
+ return result;
479
+ }
480
+ //# sourceMappingURL=streaming-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-checks.js","sourceRoot":"","sources":["../../src/realtime/streaming-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,mEAAmE;AAEnE,MAAM,QAAQ,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACxE,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAClC,MAAM,SAAS,GAAa,EAAE,CAAC,CAAC,yBAAyB;AAEzD;;;;;;;;;GASG;AACH,MAAM,wBAAwB,GAAa;IACzC,yBAAyB,EAAc,kCAAkC;IACzE,sCAAsC,EAAE,kCAAkC;IAC1E,uBAAuB;IACvB,sCAAsC;IACtC,qCAAqC;IACrC,iCAAiC;IACjC,iBAAiB,EAAuB,oCAAoC;IAC5E,WAAW,EAA6B,iEAAiE;CAC1G,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,aAAa,GAAqB;IACtC,qDAAqD;IACrD;QACE,EAAE,EAAE,sBAAsB;QAC1B,IAAI,EAAE,0BAA0B;QAChC,SAAS,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC;QACrC,OAAO,EAAE,yDAAyD;QAClE,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,yCAAyC;QAC3D,UAAU,EAAE,4FAA4F;QACxG,MAAM,EAAE,QAAQ;KACjB;IACD;QACE,EAAE,EAAE,wBAAwB;QAC5B,IAAI,EAAE,gCAAgC;QACtC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,uDAAuD;QAChE,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,mDAAmD;QACrE,UAAU,EAAE,qFAAqF;QACjG,MAAM,EAAE,QAAQ;QAChB,0GAA0G;QAC1G,gGAAgG;QAChG,mEAAmE;QACnE,YAAY,EAAE,wBAAwB;KACvC;IAED,uDAAuD;IACvD;QACE,EAAE,EAAE,mBAAmB;QACvB,IAAI,EAAE,+BAA+B;QACrC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,yEAAyE;QAClF,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,4CAA4C;QAC9D,UAAU,EAAE,qDAAqD;QACjE,MAAM,EAAE,QAAQ;KACjB;IAED,mCAAmC;IACnC;QACE,EAAE,EAAE,kBAAkB;QACtB,IAAI,EAAE,6BAA6B;QACnC,SAAS,EAAE,SAAS;QACpB,OAAO,EAAE,+JAA+J;QACxK,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,+BAA+B;QACjD,UAAU,EAAE,mFAAmF;QAC/F,MAAM,EAAE,QAAQ;KACjB;IAED,wCAAwC;IACxC;QACE,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,qBAAqB;QAC3B,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,6CAA6C,EAAE,gCAAgC;QACxF,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,iCAAiC;QACnD,UAAU,EAAE,qFAAqF;QACjG,MAAM,EAAE,QAAQ;KACjB;IACD;QACE,EAAE,EAAE,6BAA6B;QACjC,IAAI,EAAE,6BAA6B;QACnC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,qBAAqB;QAC9B,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,yCAAyC;QAC3D,UAAU,EAAE,uEAAuE;QACnF,MAAM,EAAE,QAAQ;KACjB;IAED,oDAAoD;IACpD;QACE,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,iCAAiC;QACvC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,wFAAwF;QACjG,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,sDAAsD;QACxE,UAAU,EAAE,2FAA2F;QACvG,MAAM,EAAE,QAAQ;KACjB;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,IAAI,EAAE,gCAAgC;QACtC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,kCAAkC;QAC3C,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,mDAAmD;QACrE,UAAU,EAAE,uEAAuE;QACnF,MAAM,EAAE,QAAQ;KACjB;IAED,kCAAkC;IAClC;QACE,EAAE,EAAE,qBAAqB;QACzB,IAAI,EAAE,0BAA0B;QAChC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,yFAAyF;QAClG,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,+DAA+D;QACjF,UAAU,EAAE,kGAAkG;QAC9G,MAAM,EAAE,QAAQ;KACjB;IAED,oBAAoB;IACpB;QACE,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,8BAA8B;QACpC,SAAS,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC;QACrC,OAAO,EAAE,mJAAmJ;QAC5J,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,wDAAwD;QAC1E,UAAU,EAAE,6FAA6F;QACzG,MAAM,EAAE,QAAQ;KACjB;IAED,uBAAuB;IACvB;QACE,EAAE,EAAE,mBAAmB;QACvB,IAAI,EAAE,iCAAiC;QACvC,SAAS,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAAC;QACrC,OAAO,EAAE,6FAA6F;QACtG,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,UAAU;QACpB,gBAAgB,EAAE,qEAAqE;QACvF,UAAU,EAAE,+FAA+F;QAC3G,MAAM,EAAE,QAAQ;KACjB;IAED,yCAAyC;IACzC;QACE,EAAE,EAAE,uBAAuB;QAC3B,IAAI,EAAE,8BAA8B;QACpC,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,0BAA0B,EAAE,wCAAwC;QAC7E,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,QAAQ;QAClB,gBAAgB,EAAE,+CAA+C;QACjE,UAAU,EAAE,wFAAwF;QACpG,MAAM,EAAE,QAAQ;KACjB;IAED,4EAA4E;IAC5E;QACE,EAAE,EAAE,4BAA4B;QAChC,IAAI,EAAE,4CAA4C;QAClD,SAAS,EAAE,QAAQ;QACnB,OAAO,EAAE,0GAA0G;QACnH,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;QAChB,gBAAgB,EAAE,wEAAwE;QAC1F,UAAU,EAAE,qGAAqG;QACjH,MAAM,EAAE,QAAQ;KACjB;CACF,CAAC;AAEF,mEAAmE;AAEnE;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAoD;IAC3E,cAAc;IACd;QACE,QAAQ,EAAE,4GAA4G;QACtH,QAAQ,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,CAAC;KAC9I;IACD,wCAAwC;IACxC;QACE,QAAQ,EAAE,8FAA8F;QACxG,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;KACtH;IACD,kCAAkC;IAClC;QACE,QAAQ,EAAE,uFAAuF;QACjG,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,wBAAwB,EAAE,OAAO,CAAC;KAC1H;IACD,SAAS;IACT;QACE,QAAQ,EAAE,gEAAgE;QAC1E,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,eAAe,CAAC;KACvF;IACD,UAAU;IACV;QACE,QAAQ,EAAE,oEAAoE;QAC9E,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,CAAC;KACtG;IACD,qBAAqB;IACrB;QACE,QAAQ,EAAE,uDAAuD;QACjE,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,CAAC;KACtF;IACD,QAAQ;IACR;QACE,QAAQ,EAAE,gDAAgD;QAC1D,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC;KACxE;IACD,qBAAqB;IACrB;QACE,QAAQ,EAAE,4DAA4D;QACtE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,CAAC;KAC5F;IACD,SAAS;IACT;QACE,QAAQ,EAAE,iEAAiE;QAC3E,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,CAAC;KAC/F;IACD,QAAQ;IACR;QACE,QAAQ,EAAE,4CAA4C;QACtD,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC;KACtE;IACD,MAAM;IACN;QACE,QAAQ,EAAE,uEAAuE;QACjF,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,CAAC;KAC5F;IACD,UAAU;IACV;QACE,QAAQ,EAAE,4DAA4D;QACtE,QAAQ,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC;KAChG;IACD,YAAY;IACZ;QACE,QAAQ,EAAE,0DAA0D;QACpE,QAAQ,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,CAAC;KAChF;IACD,UAAU;IACV;QACE,QAAQ,EAAE,6DAA6D;QACvE,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,CAAC;KACvF;IACD,SAAS;IACT;QACE,QAAQ,EAAE,6DAA6D;QACvE,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,gBAAgB,CAAC;KAC5E;CACF,CAAC;AAEF;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,IAAiB;IAC9C,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,OAAO,CAAC,WAAW;QACxB,IAAI,CAAC,OAAO,CAAC,aAAa;QAC1B,IAAI,CAAC,EAAE;QACP,IAAI,CAAC,cAAc,IAAI,EAAE;KAC1B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,KAAK,MAAM,KAAK,IAAI,mBAAmB,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC,QAAQ,CAAC;QACxB,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACjE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,gEAAgE;IAChE,0CAA0C;IAC1C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;QAC1B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM;QACpD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;KAClD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACpF,OAAO,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAoB;IACpD,MAAM,QAAQ,GAAG,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAEvF,IAAI,KAAoB,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;QAC9E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;SAChE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;SACjE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAiB;IAC3C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;QACtD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,OAAO;QACL,EAAE,EAAE,WAAW,IAAI,CAAC,EAAE,EAAE;QACxB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC3C,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QACtC,OAAO;QACP,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,KAAK,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAC3E,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAyB;QAChD,gBAAgB,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB;QAC/C,UAAU,EAAE,IAAI,CAAC,cAAc;QAC/B,MAAM,EAAE,SAAS;QACjB,eAAe,EAAE,qBAAqB,CAAC,IAAI,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,uBAAuB;AACvB,OAAO,EAAE,qBAAqB,IAAI,sBAAsB,EAAE,oBAAoB,IAAI,qBAAqB,EAAE,CAAC;AAE1G,mEAAmE;AAEnE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,MAAyB;IAEzB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,MAAM,IAAI,aAAa,CAAC;IAC1C,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAEzC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACxC,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,2BAA2B;QAC1E,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAEhD,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,SAAS;QACnB,aAAa;KACd,CAAC;AACJ,CAAC;AAED,mEAAmE;AAEnE;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,IAAc,EACd,QAA0B;IAE1B,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAE1C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpC,4EAA4E;QAC5E,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9D,MAAM,kBAAkB,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,CACnD,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAC3C,CAAC;YACF,IAAI,CAAC,kBAAkB;gBAAE,SAAS;QACpC,CAAC;QAED,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAErC,uEAAuE;QACvE,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC5E,SAAS;QACX,CAAC;QAED,oDAAoD;QACpD,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE5C,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;QAEjD,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YACtC,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EAAE,MAAM;gBACf,QAAQ;gBACR,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,SAAS;aACV,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC9C,uEAAuE;YACvE,qDAAqD;YACrD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EAAE,MAAM;gBACf,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC;gBACtD,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,SAAS;aACV,CAAC,CAAC;QACL,CAAC;QACD,gFAAgF;IAClF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mEAAmE;AAEnE,SAAS,cAAc,CAAC,QAAgB,EAAE,KAA6B;IACrE,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAE5B,IAAI,MAAM,GAAG,QAAQ,CAAC;IACtB,6BAA6B;IAC7B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,2CAA2C;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * StreamingVerifier — orchestrator for the real-time verification pipeline.
3
+ *
4
+ * Wires CodeBuffer (token accumulation + code unit detection) with
5
+ * StreamingChecks (pattern-based formal + learned checks) into a single
6
+ * stateful pipeline. Feed it tokens, it buffers them, detects completed
7
+ * code units, runs checks, and emits verification events.
8
+ */
9
+ import type { CheckSeverity, StreamingVerifierStats, VerificationEvent } from './types.js';
10
+ import type { EntropyDetector } from './entropy-detector.js';
11
+ export interface StreamingVerifierOptions {
12
+ language: string;
13
+ /** Path to project root for loading learned rules catalog */
14
+ projectPath?: string;
15
+ /** Callback fired for each verification event */
16
+ onEvent?: (event: VerificationEvent) => void;
17
+ /** Only auto-correct findings at or above this severity. Default: 'high' */
18
+ minCorrectionSeverity?: CheckSeverity;
19
+ /**
20
+ * Enable adaptive verification depth based on BAS score.
21
+ * When true:
22
+ * - green (BAS < 0.3): skip formal checks for this block
23
+ * - amber (BAS 0.3–0.7): queue formal checks for async execution
24
+ * - red (BAS > 0.7): run formal checks immediately
25
+ * When false (default): run all checks on every block (current behavior).
26
+ */
27
+ adaptiveDepth?: boolean;
28
+ /**
29
+ * Optional entropy detector instance. When provided and adaptiveDepth is
30
+ * true, the verifier consumes BAS depth from the detector to route checks.
31
+ */
32
+ entropyDetector?: EntropyDetector;
33
+ }
34
+ export declare class StreamingVerifier {
35
+ private readonly codeBuffer;
36
+ private readonly checkSet;
37
+ private readonly onEvent?;
38
+ private readonly adaptiveDepth;
39
+ private readonly entropyDetector?;
40
+ private events;
41
+ private unitsProcessed;
42
+ private checksRun;
43
+ private findingsCount;
44
+ private totalTimeMs;
45
+ private maxLatencyMs;
46
+ private skippedGreen;
47
+ private deferredAmber;
48
+ private immediateRed;
49
+ private deferredUnits;
50
+ /**
51
+ * Tracks the highest endOffset from any code unit we have processed.
52
+ * Used by flush() to know where unchecked trailing code begins.
53
+ */
54
+ private coveredOffset;
55
+ constructor(options: StreamingVerifierOptions);
56
+ /**
57
+ * Feed tokens from the LLM stream. Returns any verification events triggered.
58
+ */
59
+ push(tokens: string): VerificationEvent[];
60
+ /**
61
+ * Flush the buffer — run checks on any remaining buffered code.
62
+ * Call at the end of the stream to verify trailing code that never
63
+ * reached a structural boundary (closing brace, semicolon, etc.).
64
+ * Also processes any deferred (amber) code units.
65
+ */
66
+ flush(): VerificationEvent[];
67
+ /** Get cumulative statistics. */
68
+ getStats(): StreamingVerifierStats;
69
+ /** Get all findings (FAIL events) accumulated so far. */
70
+ getFindings(): VerificationEvent[];
71
+ /** Get the full generated code accumulated so far. */
72
+ getGeneratedCode(): string;
73
+ /** Reset all state — buffer, events, stats. */
74
+ reset(): void;
75
+ /**
76
+ * Determine the adaptive verification depth for a code unit.
77
+ * When adaptiveDepth is disabled or no entropy detector is available,
78
+ * returns undefined (meaning: check everything).
79
+ */
80
+ private getUnitDepth;
81
+ /**
82
+ * Run checks against a list of code units, accumulate stats, fire callbacks.
83
+ * When adaptiveDepth is enabled, routes based on BAS:
84
+ * green — skip formal checks (log as pass)
85
+ * amber — defer checks (queued for later via flushDeferred)
86
+ * red — run checks immediately
87
+ */
88
+ private processUnits;
89
+ /**
90
+ * Process all deferred (amber) code units. Call this when the statement
91
+ * completes or at stream end to run checks on amber-queued blocks.
92
+ * Returns any verification events from the deferred checks.
93
+ */
94
+ flushDeferred(): VerificationEvent[];
95
+ /** Get adaptive depth routing statistics. */
96
+ getDepthStats(): {
97
+ skippedGreen: number;
98
+ deferredAmber: number;
99
+ immediateRed: number;
100
+ pendingDeferred: number;
101
+ };
102
+ }