@rigour-labs/core 6.7.10 → 6.8.1-rc.1

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 (346) hide show
  1. package/dist/brief/briefing.d.ts +59 -0
  2. package/dist/brief/briefing.js +126 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +2 -0
  5. package/dist/inference/cloud-provider.js +12 -2
  6. package/dist/review/backtest-init.d.ts +8 -5
  7. package/dist/review/backtest-init.js +27 -9
  8. package/dist/review/backtest-last.js +3 -1
  9. package/dist/review/reviewer/adapters.d.ts +4 -0
  10. package/dist/review/reviewer/adapters.js +23 -0
  11. package/dist/review/reviewer/inputs.d.ts +4 -1
  12. package/dist/review/reviewer/inputs.js +36 -2
  13. package/dist/review/reviewer/record.d.ts +5 -0
  14. package/dist/review/reviewer/record.js +3 -3
  15. package/dist/review/reviewer/verdict.d.ts +14 -0
  16. package/dist/review/reviewer/verdict.js +46 -6
  17. package/dist/review/reviewer.d.ts +2 -0
  18. package/dist/review/reviewer.js +24 -5
  19. package/dist/review-learning/repo-rules.d.ts +14 -2
  20. package/dist/review-learning/repo-rules.js +59 -9
  21. package/dist/task/thread.d.ts +47 -0
  22. package/dist/task/thread.js +234 -0
  23. package/dist/templates/universal-config.js +4 -0
  24. package/dist/types/index.d.ts +21 -0
  25. package/dist/types/index.js +7 -0
  26. package/package.json +11 -8
  27. package/dist/context/automatic-index-cache.test.d.ts +0 -1
  28. package/dist/context/automatic-index-cache.test.js +0 -30
  29. package/dist/context/automatic-index.test.d.ts +0 -1
  30. package/dist/context/automatic-index.test.js +0 -45
  31. package/dist/context/cache-engine.test.d.ts +0 -1
  32. package/dist/context/cache-engine.test.js +0 -99
  33. package/dist/context/dependency-graph.test.d.ts +0 -1
  34. package/dist/context/dependency-graph.test.js +0 -13
  35. package/dist/context/index-status.test.d.ts +0 -1
  36. package/dist/context/index-status.test.js +0 -26
  37. package/dist/context.test.d.ts +0 -1
  38. package/dist/context.test.js +0 -228
  39. package/dist/deep/agent-review.test.d.ts +0 -1
  40. package/dist/deep/agent-review.test.js +0 -53
  41. package/dist/deep/code-context.test.d.ts +0 -1
  42. package/dist/deep/code-context.test.js +0 -48
  43. package/dist/deep/code-pass.test.d.ts +0 -1
  44. package/dist/deep/code-pass.test.js +0 -112
  45. package/dist/deep/code-review-prompt.test.d.ts +0 -1
  46. package/dist/deep/code-review-prompt.test.js +0 -20
  47. package/dist/deep/code-verifier.test.d.ts +0 -1
  48. package/dist/deep/code-verifier.test.js +0 -54
  49. package/dist/deep/diff-tests/calls.test.d.ts +0 -1
  50. package/dist/deep/diff-tests/calls.test.js +0 -33
  51. package/dist/deep/diff-tests/run.test.d.ts +0 -1
  52. package/dist/deep/diff-tests/run.test.js +0 -58
  53. package/dist/deep/fact-extractor.test.d.ts +0 -1
  54. package/dist/deep/fact-extractor.test.js +0 -581
  55. package/dist/deep/parse-findings.test.d.ts +0 -1
  56. package/dist/deep/parse-findings.test.js +0 -25
  57. package/dist/deep/pr-review.test.d.ts +0 -1
  58. package/dist/deep/pr-review.test.js +0 -80
  59. package/dist/deep/prompts.test.d.ts +0 -1
  60. package/dist/deep/prompts.test.js +0 -235
  61. package/dist/deep/reference-pack.test.d.ts +0 -1
  62. package/dist/deep/reference-pack.test.js +0 -46
  63. package/dist/deep/related-changes.test.d.ts +0 -1
  64. package/dist/deep/related-changes.test.js +0 -33
  65. package/dist/deep/review-context-export.test.d.ts +0 -1
  66. package/dist/deep/review-context-export.test.js +0 -32
  67. package/dist/deep/review-tools.test.d.ts +0 -1
  68. package/dist/deep/review-tools.test.js +0 -39
  69. package/dist/deep/risk.test.d.ts +0 -1
  70. package/dist/deep/risk.test.js +0 -101
  71. package/dist/deep/verifier.test.d.ts +0 -1
  72. package/dist/deep/verifier.test.js +0 -635
  73. package/dist/discovery.test.d.ts +0 -1
  74. package/dist/discovery.test.js +0 -93
  75. package/dist/environment.test.d.ts +0 -1
  76. package/dist/environment.test.js +0 -94
  77. package/dist/firewall/firewall.test.d.ts +0 -1
  78. package/dist/firewall/firewall.test.js +0 -117
  79. package/dist/firewall/trust-boundaries.test.d.ts +0 -1
  80. package/dist/firewall/trust-boundaries.test.js +0 -64
  81. package/dist/firewall/trusted-control.test.d.ts +0 -1
  82. package/dist/firewall/trusted-control.test.js +0 -188
  83. package/dist/gates/agent-team.test.d.ts +0 -1
  84. package/dist/gates/agent-team.test.js +0 -113
  85. package/dist/gates/ast.test.d.ts +0 -1
  86. package/dist/gates/ast.test.js +0 -112
  87. package/dist/gates/checkpoint.test.d.ts +0 -1
  88. package/dist/gates/checkpoint.test.js +0 -105
  89. package/dist/gates/content.test.d.ts +0 -1
  90. package/dist/gates/content.test.js +0 -73
  91. package/dist/gates/coverage.test.d.ts +0 -1
  92. package/dist/gates/coverage.test.js +0 -53
  93. package/dist/gates/dedupe-failures.test.d.ts +0 -1
  94. package/dist/gates/dedupe-failures.test.js +0 -12
  95. package/dist/gates/deep-analysis.test.d.ts +0 -1
  96. package/dist/gates/deep-analysis.test.js +0 -86
  97. package/dist/gates/deep-intent.test.d.ts +0 -1
  98. package/dist/gates/deep-intent.test.js +0 -51
  99. package/dist/gates/deep-timeout.test.d.ts +0 -1
  100. package/dist/gates/deep-timeout.test.js +0 -10
  101. package/dist/gates/deprecated-apis.test.d.ts +0 -1
  102. package/dist/gates/deprecated-apis.test.js +0 -318
  103. package/dist/gates/deprecated-dependencies.test.d.ts +0 -1
  104. package/dist/gates/deprecated-dependencies.test.js +0 -55
  105. package/dist/gates/frontend-secret-exposure.test.d.ts +0 -1
  106. package/dist/gates/frontend-secret-exposure.test.js +0 -148
  107. package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.d.ts +0 -1
  108. package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.js +0 -27
  109. package/dist/gates/hallucinated-imports/js-resolver-types.test.d.ts +0 -1
  110. package/dist/gates/hallucinated-imports/js-resolver-types.test.js +0 -14
  111. package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +0 -1
  112. package/dist/gates/hallucinated-imports-sveltekit.test.js +0 -132
  113. package/dist/gates/hallucinated-imports.test.d.ts +0 -1
  114. package/dist/gates/hallucinated-imports.test.js +0 -1206
  115. package/dist/gates/js-style-context.test.d.ts +0 -1
  116. package/dist/gates/js-style-context.test.js +0 -35
  117. package/dist/gates/logic-drift.test.d.ts +0 -1
  118. package/dist/gates/logic-drift.test.js +0 -52
  119. package/dist/gates/phantom-apis.test.d.ts +0 -1
  120. package/dist/gates/phantom-apis.test.js +0 -396
  121. package/dist/gates/promise-safety.test.d.ts +0 -1
  122. package/dist/gates/promise-safety.test.js +0 -34
  123. package/dist/gates/runner.test.d.ts +0 -1
  124. package/dist/gates/runner.test.js +0 -77
  125. package/dist/gates/scoped-gates.test.d.ts +0 -1
  126. package/dist/gates/scoped-gates.test.js +0 -52
  127. package/dist/gates/security-patterns-owasp.test.d.ts +0 -1
  128. package/dist/gates/security-patterns-owasp.test.js +0 -186
  129. package/dist/gates/security-patterns.test.d.ts +0 -1
  130. package/dist/gates/security-patterns.test.js +0 -194
  131. package/dist/gates/semantic-bugs.test.d.ts +0 -1
  132. package/dist/gates/semantic-bugs.test.js +0 -76
  133. package/dist/gates/side-effect-analysis.test.d.ts +0 -1
  134. package/dist/gates/side-effect-analysis.test.js +0 -162
  135. package/dist/gates/style-drift.test.d.ts +0 -1
  136. package/dist/gates/style-drift.test.js +0 -26
  137. package/dist/gates/test-quality.test.d.ts +0 -1
  138. package/dist/gates/test-quality.test.js +0 -325
  139. package/dist/gates/trusted-reviews.test.d.ts +0 -1
  140. package/dist/gates/trusted-reviews.test.js +0 -16
  141. package/dist/gates/unindexed-reads/queries.test.d.ts +0 -1
  142. package/dist/gates/unindexed-reads/queries.test.js +0 -54
  143. package/dist/gates/unindexed-reads/schema.test.d.ts +0 -1
  144. package/dist/gates/unindexed-reads/schema.test.js +0 -81
  145. package/dist/gates/unindexed-reads/unindexed-reads.test.d.ts +0 -1
  146. package/dist/gates/unindexed-reads/unindexed-reads.test.js +0 -90
  147. package/dist/hooks/checker.test.d.ts +0 -1
  148. package/dist/hooks/checker.test.js +0 -159
  149. package/dist/hooks/dlp-confidence.test.d.ts +0 -1
  150. package/dist/hooks/dlp-confidence.test.js +0 -51
  151. package/dist/hooks/dlp-feedback.test.d.ts +0 -1
  152. package/dist/hooks/dlp-feedback.test.js +0 -131
  153. package/dist/hooks/input-validator.test.d.ts +0 -1
  154. package/dist/hooks/input-validator.test.js +0 -329
  155. package/dist/hooks/templates.test.d.ts +0 -1
  156. package/dist/hooks/templates.test.js +0 -27
  157. package/dist/inference/brain-placeholder.test.d.ts +0 -1
  158. package/dist/inference/brain-placeholder.test.js +0 -28
  159. package/dist/inference/cloud-provider.test.d.ts +0 -1
  160. package/dist/inference/cloud-provider.test.js +0 -139
  161. package/dist/inference/executable.test.d.ts +0 -1
  162. package/dist/inference/executable.test.js +0 -41
  163. package/dist/inference/http-download.test.d.ts +0 -1
  164. package/dist/inference/http-download.test.js +0 -109
  165. package/dist/inference/llama-engine-checksum.test.d.ts +0 -1
  166. package/dist/inference/llama-engine-checksum.test.js +0 -27
  167. package/dist/inference/llama-engine.test.d.ts +0 -1
  168. package/dist/inference/llama-engine.test.js +0 -51
  169. package/dist/inference/llama-process.test.d.ts +0 -1
  170. package/dist/inference/llama-process.test.js +0 -61
  171. package/dist/inference/local-model.test.d.ts +0 -1
  172. package/dist/inference/local-model.test.js +0 -23
  173. package/dist/inference/model-download.test.d.ts +0 -1
  174. package/dist/inference/model-download.test.js +0 -125
  175. package/dist/inference/model-manager.test.d.ts +0 -1
  176. package/dist/inference/model-manager.test.js +0 -24
  177. package/dist/inference/types.test.d.ts +0 -1
  178. package/dist/inference/types.test.js +0 -19
  179. package/dist/memory/recall.test.d.ts +0 -1
  180. package/dist/memory/recall.test.js +0 -36
  181. package/dist/pattern-index/indexer.test.d.ts +0 -6
  182. package/dist/pattern-index/indexer.test.js +0 -197
  183. package/dist/pattern-index/matcher.test.d.ts +0 -6
  184. package/dist/pattern-index/matcher.test.js +0 -238
  185. package/dist/pattern-index/pattern-reuse.test.d.ts +0 -1
  186. package/dist/pattern-index/pattern-reuse.test.js +0 -76
  187. package/dist/pattern-index/semantic-runtime.test.d.ts +0 -1
  188. package/dist/pattern-index/semantic-runtime.test.js +0 -31
  189. package/dist/pattern-index/staleness.test.d.ts +0 -6
  190. package/dist/pattern-index/staleness.test.js +0 -211
  191. package/dist/review/agent-fixes.test.d.ts +0 -1
  192. package/dist/review/agent-fixes.test.js +0 -32
  193. package/dist/review/backtest-init.test.d.ts +0 -1
  194. package/dist/review/backtest-init.test.js +0 -98
  195. package/dist/review/backtest-judges.test.d.ts +0 -1
  196. package/dist/review/backtest-judges.test.js +0 -32
  197. package/dist/review/backtest-last.test.d.ts +0 -1
  198. package/dist/review/backtest-last.test.js +0 -109
  199. package/dist/review/backtest.test.d.ts +0 -1
  200. package/dist/review/backtest.test.js +0 -183
  201. package/dist/review/baseline.test.d.ts +0 -1
  202. package/dist/review/baseline.test.js +0 -22
  203. package/dist/review/branch-checks.test.d.ts +0 -1
  204. package/dist/review/branch-checks.test.js +0 -48
  205. package/dist/review/check-outcomes.test.d.ts +0 -1
  206. package/dist/review/check-outcomes.test.js +0 -56
  207. package/dist/review/code-patterns.test.d.ts +0 -1
  208. package/dist/review/code-patterns.test.js +0 -142
  209. package/dist/review/dead-code.test.d.ts +0 -1
  210. package/dist/review/dead-code.test.js +0 -154
  211. package/dist/review/deep-runs.test.d.ts +0 -1
  212. package/dist/review/deep-runs.test.js +0 -23
  213. package/dist/review/effectiveness.test.d.ts +0 -1
  214. package/dist/review/effectiveness.test.js +0 -42
  215. package/dist/review/fix-scope.test.d.ts +0 -1
  216. package/dist/review/fix-scope.test.js +0 -104
  217. package/dist/review/generated-files.test.d.ts +0 -1
  218. package/dist/review/generated-files.test.js +0 -25
  219. package/dist/review/migration-order.test.d.ts +0 -1
  220. package/dist/review/migration-order.test.js +0 -62
  221. package/dist/review/quiet.test.d.ts +0 -1
  222. package/dist/review/quiet.test.js +0 -38
  223. package/dist/review/receipt.test.d.ts +0 -1
  224. package/dist/review/receipt.test.js +0 -60
  225. package/dist/review/review-task.test.d.ts +0 -1
  226. package/dist/review/review-task.test.js +0 -89
  227. package/dist/review/review.test.d.ts +0 -1
  228. package/dist/review/review.test.js +0 -203
  229. package/dist/review/reviewer/adapters.test.d.ts +0 -1
  230. package/dist/review/reviewer/adapters.test.js +0 -60
  231. package/dist/review/reviewer/api-judge.test.d.ts +0 -1
  232. package/dist/review/reviewer/api-judge.test.js +0 -108
  233. package/dist/review/reviewer/background.test.d.ts +0 -1
  234. package/dist/review/reviewer/background.test.js +0 -118
  235. package/dist/review/reviewer/context.test.d.ts +0 -1
  236. package/dist/review/reviewer/context.test.js +0 -45
  237. package/dist/review/reviewer/exec.test.d.ts +0 -1
  238. package/dist/review/reviewer/exec.test.js +0 -59
  239. package/dist/review/reviewer/inputs.test.d.ts +0 -1
  240. package/dist/review/reviewer/inputs.test.js +0 -26
  241. package/dist/review/reviewer/panel.test.d.ts +0 -1
  242. package/dist/review/reviewer/panel.test.js +0 -110
  243. package/dist/review/reviewer/record.test.d.ts +0 -1
  244. package/dist/review/reviewer/record.test.js +0 -32
  245. package/dist/review/reviewer/rule-writer.test.d.ts +0 -1
  246. package/dist/review/reviewer/rule-writer.test.js +0 -52
  247. package/dist/review/reviewer/settings.test.d.ts +0 -1
  248. package/dist/review/reviewer/settings.test.js +0 -57
  249. package/dist/review/reviewer/usage.test.d.ts +0 -1
  250. package/dist/review/reviewer/usage.test.js +0 -14
  251. package/dist/review/reviewer.test.d.ts +0 -1
  252. package/dist/review/reviewer.test.js +0 -705
  253. package/dist/review/stories.test.d.ts +0 -1
  254. package/dist/review/stories.test.js +0 -58
  255. package/dist/review/toolchain.test.d.ts +0 -1
  256. package/dist/review/toolchain.test.js +0 -108
  257. package/dist/review/typed/redundancy.test.d.ts +0 -1
  258. package/dist/review/typed/redundancy.test.js +0 -315
  259. package/dist/review/typed/schema-nullability.test.d.ts +0 -1
  260. package/dist/review/typed/schema-nullability.test.js +0 -63
  261. package/dist/review-learning/human-edits.test.d.ts +0 -1
  262. package/dist/review-learning/human-edits.test.js +0 -47
  263. package/dist/review-learning/repo-rules.test.d.ts +0 -1
  264. package/dist/review-learning/repo-rules.test.js +0 -55
  265. package/dist/review-learning/review-learning.test.d.ts +0 -1
  266. package/dist/review-learning/review-learning.test.js +0 -249
  267. package/dist/safety.test.d.ts +0 -1
  268. package/dist/safety.test.js +0 -42
  269. package/dist/semantic/benchmark.test.d.ts +0 -1
  270. package/dist/semantic/benchmark.test.js +0 -22
  271. package/dist/semantic/intent/intent.test.d.ts +0 -1
  272. package/dist/semantic/intent/intent.test.js +0 -46
  273. package/dist/semantic/learn/learn.test.d.ts +0 -1
  274. package/dist/semantic/learn/learn.test.js +0 -67
  275. package/dist/semantic/origins.test.d.ts +0 -1
  276. package/dist/semantic/origins.test.js +0 -77
  277. package/dist/semantic/project-facts.test.d.ts +0 -1
  278. package/dist/semantic/project-facts.test.js +0 -45
  279. package/dist/semantic/sites/call-sites.test.d.ts +0 -1
  280. package/dist/semantic/sites/call-sites.test.js +0 -46
  281. package/dist/services/adaptive-thresholds.test.d.ts +0 -1
  282. package/dist/services/adaptive-thresholds.test.js +0 -53
  283. package/dist/services/agent-history.test.d.ts +0 -1
  284. package/dist/services/agent-history.test.js +0 -69
  285. package/dist/services/context-scope-summary.test.d.ts +0 -1
  286. package/dist/services/context-scope-summary.test.js +0 -17
  287. package/dist/services/context-telemetry-service.test.d.ts +0 -1
  288. package/dist/services/context-telemetry-service.test.js +0 -182
  289. package/dist/services/cursor-usage-sync.test.d.ts +0 -1
  290. package/dist/services/cursor-usage-sync.test.js +0 -173
  291. package/dist/services/engineering-knowledge-graph.test.d.ts +0 -1
  292. package/dist/services/engineering-knowledge-graph.test.js +0 -76
  293. package/dist/services/model-pricing.test.d.ts +0 -1
  294. package/dist/services/model-pricing.test.js +0 -44
  295. package/dist/services/observed-savings.test.d.ts +0 -1
  296. package/dist/services/observed-savings.test.js +0 -37
  297. package/dist/services/score-history.test.d.ts +0 -1
  298. package/dist/services/score-history.test.js +0 -61
  299. package/dist/smoke.test.d.ts +0 -1
  300. package/dist/smoke.test.js +0 -17
  301. package/dist/storage/cache-cleanup.test.d.ts +0 -1
  302. package/dist/storage/cache-cleanup.test.js +0 -54
  303. package/dist/storage/context-telemetry.test.d.ts +0 -1
  304. package/dist/storage/context-telemetry.test.js +0 -80
  305. package/dist/storage/db.test.d.ts +0 -1
  306. package/dist/storage/db.test.js +0 -46
  307. package/dist/storage/fix-lessons.test.d.ts +0 -1
  308. package/dist/storage/fix-lessons.test.js +0 -61
  309. package/dist/storage/lessons.test.d.ts +0 -1
  310. package/dist/storage/lessons.test.js +0 -81
  311. package/dist/storage/local-encryption.test.d.ts +0 -1
  312. package/dist/storage/local-encryption.test.js +0 -34
  313. package/dist/storage/local-memory.test.d.ts +0 -1
  314. package/dist/storage/local-memory.test.js +0 -55
  315. package/dist/storage/share-memory.test.d.ts +0 -1
  316. package/dist/storage/share-memory.test.js +0 -34
  317. package/dist/storage/team-diagnostics.test.d.ts +0 -1
  318. package/dist/storage/team-diagnostics.test.js +0 -51
  319. package/dist/storage/team-scope.test.d.ts +0 -1
  320. package/dist/storage/team-scope.test.js +0 -22
  321. package/dist/storage/team-store.test.d.ts +0 -1
  322. package/dist/storage/team-store.test.js +0 -11
  323. package/dist/storage/team-sync-scope.test.d.ts +0 -1
  324. package/dist/storage/team-sync-scope.test.js +0 -100
  325. package/dist/storage/team-vector-store.test.d.ts +0 -1
  326. package/dist/storage/team-vector-store.test.js +0 -56
  327. package/dist/storage/telemetry-scope.test.d.ts +0 -1
  328. package/dist/storage/telemetry-scope.test.js +0 -38
  329. package/dist/telemetry/telemetry.test.d.ts +0 -1
  330. package/dist/telemetry/telemetry.test.js +0 -64
  331. package/dist/types/index.test.d.ts +0 -1
  332. package/dist/types/index.test.js +0 -33
  333. package/dist/utils/command-line.test.d.ts +0 -1
  334. package/dist/utils/command-line.test.js +0 -8
  335. package/dist/utils/diff-removed.test.d.ts +0 -1
  336. package/dist/utils/diff-removed.test.js +0 -29
  337. package/dist/utils/diff.test.d.ts +0 -1
  338. package/dist/utils/diff.test.js +0 -38
  339. package/dist/utils/glob-paths.test.d.ts +0 -1
  340. package/dist/utils/glob-paths.test.js +0 -40
  341. package/dist/utils/profile.test.d.ts +0 -1
  342. package/dist/utils/profile.test.js +0 -68
  343. package/dist/utils/scanner.test.d.ts +0 -1
  344. package/dist/utils/scanner.test.js +0 -48
  345. package/dist/utils/scope.test.d.ts +0 -1
  346. package/dist/utils/scope.test.js +0 -38
@@ -1,113 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { AgentTeamGate, registerAgent, getSession, clearSession } from './agent-team.js';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import * as os from 'os';
6
- describe('AgentTeamGate', () => {
7
- let testDir;
8
- beforeEach(() => {
9
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-team-test-'));
10
- });
11
- afterEach(() => {
12
- clearSession(testDir);
13
- fs.rmSync(testDir, { recursive: true, force: true });
14
- });
15
- describe('gate initialization', () => {
16
- it('should create gate with default config', () => {
17
- const gate = new AgentTeamGate();
18
- expect(gate.id).toBe('agent-team');
19
- expect(gate.title).toBe('Agent Team Governance');
20
- });
21
- it('should skip when not enabled', async () => {
22
- const gate = new AgentTeamGate({ enabled: false });
23
- const failures = await gate.run({ cwd: testDir });
24
- expect(failures).toEqual([]);
25
- });
26
- });
27
- describe('session management', () => {
28
- it('should register an agent', () => {
29
- const session = registerAgent(testDir, 'agent-a', ['src/api/**']);
30
- expect(session.agents).toHaveLength(1);
31
- expect(session.agents[0].agentId).toBe('agent-a');
32
- expect(session.agents[0].taskScope).toEqual(['src/api/**']);
33
- });
34
- it('should update existing agent registration', () => {
35
- registerAgent(testDir, 'agent-a', ['src/api/**']);
36
- const session = registerAgent(testDir, 'agent-a', ['src/api/**', 'src/utils/**']);
37
- expect(session.agents).toHaveLength(1);
38
- expect(session.agents[0].taskScope).toEqual(['src/api/**', 'src/utils/**']);
39
- });
40
- it('should persist session to disk', () => {
41
- registerAgent(testDir, 'agent-a', ['src/**']);
42
- const sessionPath = path.join(testDir, '.rigour', 'agent-session.json');
43
- expect(fs.existsSync(sessionPath)).toBe(true);
44
- });
45
- it('should load session from disk', () => {
46
- registerAgent(testDir, 'agent-a', ['src/**']);
47
- // Clear in-memory cache
48
- clearSession(testDir);
49
- // Re-register to re-create session file
50
- registerAgent(testDir, 'agent-b', ['tests/**']);
51
- const session = getSession(testDir);
52
- expect(session).not.toBeNull();
53
- expect(session.agents).toHaveLength(1); // Only agent-b after clearSession
54
- });
55
- it('should clear session', () => {
56
- registerAgent(testDir, 'agent-a', ['src/**']);
57
- clearSession(testDir);
58
- const session = getSession(testDir);
59
- expect(session).toBeNull();
60
- });
61
- });
62
- describe('max concurrent agents check', () => {
63
- it('should pass when under limit', async () => {
64
- const gate = new AgentTeamGate({ enabled: true, max_concurrent_agents: 3 });
65
- registerAgent(testDir, 'agent-a', ['src/a/**']);
66
- registerAgent(testDir, 'agent-b', ['src/b/**']);
67
- const failures = await gate.run({ cwd: testDir });
68
- expect(failures).toEqual([]);
69
- });
70
- it('should fail when over limit', async () => {
71
- const gate = new AgentTeamGate({ enabled: true, max_concurrent_agents: 2 });
72
- registerAgent(testDir, 'agent-a', ['src/a/**']);
73
- registerAgent(testDir, 'agent-b', ['src/b/**']);
74
- registerAgent(testDir, 'agent-c', ['src/c/**']);
75
- const failures = await gate.run({ cwd: testDir });
76
- expect(failures).toHaveLength(1);
77
- expect(failures[0].title).toBe('Too Many Concurrent Agents');
78
- });
79
- });
80
- describe('task scope conflicts (strict mode)', () => {
81
- it('should pass when scopes are disjoint', async () => {
82
- const gate = new AgentTeamGate({
83
- enabled: true,
84
- task_ownership: 'strict'
85
- });
86
- registerAgent(testDir, 'agent-a', ['src/api/**']);
87
- registerAgent(testDir, 'agent-b', ['src/ui/**']);
88
- const failures = await gate.run({ cwd: testDir });
89
- expect(failures).toEqual([]);
90
- });
91
- it('should fail when scopes overlap', async () => {
92
- const gate = new AgentTeamGate({
93
- enabled: true,
94
- task_ownership: 'strict'
95
- });
96
- registerAgent(testDir, 'agent-a', ['src/api/**']);
97
- registerAgent(testDir, 'agent-b', ['src/api/**']); // Same scope!
98
- const failures = await gate.run({ cwd: testDir });
99
- expect(failures).toHaveLength(1);
100
- expect(failures[0].title).toBe('Task Scope Conflict');
101
- });
102
- it('should allow overlapping scopes in collaborative mode', async () => {
103
- const gate = new AgentTeamGate({
104
- enabled: true,
105
- task_ownership: 'collaborative'
106
- });
107
- registerAgent(testDir, 'agent-a', ['src/api/**']);
108
- registerAgent(testDir, 'agent-b', ['src/api/**']); // Same scope - OK in collaborative
109
- const failures = await gate.run({ cwd: testDir });
110
- expect(failures).toEqual([]);
111
- });
112
- });
113
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,112 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
- import fs from 'fs';
3
- import os from 'os';
4
- import path from 'path';
5
- import { ASTGate } from './ast.js';
6
- describe('ASTGate ignore behavior', () => {
7
- let testDir;
8
- beforeEach(() => {
9
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-gate-test-'));
10
- });
11
- afterEach(() => {
12
- fs.rmSync(testDir, { recursive: true, force: true });
13
- });
14
- it('keeps default ignores when context.ignore is an empty array', async () => {
15
- const gate = new ASTGate({
16
- ast: { max_params: 1 },
17
- });
18
- fs.mkdirSync(path.join(testDir, 'node_modules', 'example'), { recursive: true });
19
- fs.writeFileSync(path.join(testDir, 'node_modules', 'example', 'bad.js'), 'function fromDeps(a, b, c) { return a + b + c; }', 'utf-8');
20
- fs.mkdirSync(path.join(testDir, 'src'), { recursive: true });
21
- fs.writeFileSync(path.join(testDir, 'src', 'ok.js'), 'function ok(a) { return a; }', 'utf-8');
22
- const failures = await gate.run({
23
- cwd: testDir,
24
- ignore: [],
25
- });
26
- expect(failures).toHaveLength(0);
27
- });
28
- it('merges user ignore patterns with default ignores', async () => {
29
- const gate = new ASTGate({
30
- ast: { max_params: 1 },
31
- });
32
- fs.mkdirSync(path.join(testDir, 'generated'), { recursive: true });
33
- fs.writeFileSync(path.join(testDir, 'generated', 'bad.js'), 'function generated(a, b, c) { return a + b + c; }', 'utf-8');
34
- fs.mkdirSync(path.join(testDir, 'src'), { recursive: true });
35
- fs.writeFileSync(path.join(testDir, 'src', 'ok.js'), 'function ok(a) { return a; }', 'utf-8');
36
- const failures = await gate.run({
37
- cwd: testDir,
38
- ignore: ['generated/**'],
39
- });
40
- expect(failures).toHaveLength(0);
41
- });
42
- it('ignores generated studio-dist assets by default', async () => {
43
- const gate = new ASTGate({
44
- ast: { max_params: 1 },
45
- });
46
- fs.mkdirSync(path.join(testDir, 'packages', 'rigour-cli', 'studio-dist', 'assets'), { recursive: true });
47
- fs.writeFileSync(path.join(testDir, 'packages', 'rigour-cli', 'studio-dist', 'assets', 'index.js'), 'function fromBundle(a, b, c) { return a + b + c; }', 'utf-8');
48
- const failures = await gate.run({
49
- cwd: testDir,
50
- ignore: [],
51
- });
52
- expect(failures).toHaveLength(0);
53
- });
54
- it('ignores examples directory by default', async () => {
55
- const gate = new ASTGate({
56
- ast: { max_params: 1 },
57
- });
58
- fs.mkdirSync(path.join(testDir, 'examples', 'demo', 'src'), { recursive: true });
59
- fs.writeFileSync(path.join(testDir, 'examples', 'demo', 'src', 'bad.js'), 'function noisy(a, b, c) { return a + b + c; }', 'utf-8');
60
- const failures = await gate.run({
61
- cwd: testDir,
62
- ignore: [],
63
- });
64
- expect(failures).toHaveLength(0);
65
- });
66
- it('sets severity and provenance on AST violations', async () => {
67
- const gate = new ASTGate({
68
- ast: { max_params: 1 },
69
- });
70
- fs.mkdirSync(path.join(testDir, 'src'), { recursive: true });
71
- fs.writeFileSync(path.join(testDir, 'src', 'bad.js'), 'function tooMany(a, b, c) { return a + b + c; }', 'utf-8');
72
- const failures = await gate.run({ cwd: testDir, ignore: [] });
73
- const target = failures.find((failure) => failure.id === 'AST_MAX_PARAMS');
74
- expect(target).toBeDefined();
75
- expect(target?.severity).toBe('medium');
76
- expect(target?.provenance).toBe('traditional');
77
- });
78
- it('marks prototype pollution findings as security-critical', async () => {
79
- const gate = new ASTGate({
80
- ast: { max_params: 10 },
81
- });
82
- fs.mkdirSync(path.join(testDir, 'src'), { recursive: true });
83
- fs.writeFileSync(path.join(testDir, 'src', 'pollute.js'), 'const target = {}; target.__proto__ = {};', 'utf-8');
84
- const failures = await gate.run({ cwd: testDir, ignore: [] });
85
- const target = failures.find((failure) => failure.id === 'SECURITY_PROTOTYPE_POLLUTION');
86
- expect(target).toBeDefined();
87
- expect(target?.severity).toBe('critical');
88
- expect(target?.provenance).toBe('security');
89
- });
90
- it('does not attribute nested function complexity to parent function', async () => {
91
- const gate = new ASTGate({
92
- ast: { complexity: 3, max_params: 10 },
93
- });
94
- fs.mkdirSync(path.join(testDir, 'src'), { recursive: true });
95
- fs.writeFileSync(path.join(testDir, 'src', 'nested.ts'), `
96
- function outer(flag: boolean) {
97
- function inner(x: number) {
98
- if (x > 0) { return 1; }
99
- if (x < 0) { return -1; }
100
- if (x === 0) { return 0; }
101
- return 0;
102
- }
103
- return flag ? inner(1) : inner(-1);
104
- }
105
- `, 'utf-8');
106
- const failures = await gate.run({ cwd: testDir, ignore: [] });
107
- const complexityTitles = failures
108
- .filter((failure) => failure.id === 'AST_COMPLEXITY')
109
- .map((failure) => failure.title);
110
- expect(complexityTitles.some((title) => title.includes("'outer'"))).toBe(false);
111
- });
112
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,105 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { CheckpointGate, recordCheckpoint, getCheckpointSession, clearCheckpointSession, getOrCreateCheckpointSession, completeCheckpointSession, abortCheckpointSession } from './checkpoint.js';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import * as os from 'os';
6
- describe('CheckpointGate', () => {
7
- let testDir;
8
- beforeEach(() => {
9
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'checkpoint-test-'));
10
- });
11
- afterEach(() => {
12
- clearCheckpointSession(testDir);
13
- fs.rmSync(testDir, { recursive: true, force: true });
14
- });
15
- describe('gate initialization', () => {
16
- it('should create gate with default config', () => {
17
- const gate = new CheckpointGate();
18
- expect(gate.id).toBe('checkpoint');
19
- expect(gate.title).toBe('Checkpoint Supervision');
20
- });
21
- it('should skip when not enabled', async () => {
22
- const gate = new CheckpointGate({ enabled: false });
23
- const failures = await gate.run({ cwd: testDir });
24
- expect(failures).toEqual([]);
25
- });
26
- });
27
- describe('session management', () => {
28
- it('should create a new session', () => {
29
- const session = getOrCreateCheckpointSession(testDir);
30
- expect(session.sessionId).toMatch(/^chk-session-/);
31
- expect(session.status).toBe('active');
32
- expect(session.checkpoints).toHaveLength(0);
33
- });
34
- it('should record a checkpoint', () => {
35
- const result = recordCheckpoint(testDir, 25, // progressPct
36
- ['src/api/users.ts'], 'Implemented user API', 85 // qualityScore
37
- );
38
- expect(result.continue).toBe(true);
39
- expect(result.checkpoint.progressPct).toBe(25);
40
- expect(result.checkpoint.qualityScore).toBe(85);
41
- });
42
- it('should persist session to disk', () => {
43
- recordCheckpoint(testDir, 50, [], 'Test', 90);
44
- const sessionPath = path.join(testDir, '.rigour', 'checkpoint-session.json');
45
- expect(fs.existsSync(sessionPath)).toBe(true);
46
- });
47
- it('should complete session', () => {
48
- getOrCreateCheckpointSession(testDir);
49
- completeCheckpointSession(testDir);
50
- const session = getCheckpointSession(testDir);
51
- expect(session?.status).toBe('completed');
52
- });
53
- it('should abort session with reason', () => {
54
- getOrCreateCheckpointSession(testDir);
55
- abortCheckpointSession(testDir, 'Quality too low');
56
- const session = getCheckpointSession(testDir);
57
- expect(session?.status).toBe('aborted');
58
- expect(session?.checkpoints[0].summary).toContain('Quality too low');
59
- });
60
- });
61
- describe('quality threshold', () => {
62
- it('should continue when quality above threshold', () => {
63
- const result = recordCheckpoint(testDir, 50, [], 'Good work', 85);
64
- expect(result.continue).toBe(true);
65
- expect(result.warnings).toHaveLength(0);
66
- });
67
- it('should stop when quality below threshold', () => {
68
- const result = recordCheckpoint(testDir, 50, [], 'Poor work', 70);
69
- expect(result.continue).toBe(false);
70
- expect(result.warnings).toContain('Quality score 70% is below threshold 80%');
71
- });
72
- });
73
- describe('drift detection', () => {
74
- it('should detect quality degradation', () => {
75
- // Record checkpoints with a sharp quality drop.
76
- // EWMA with α=0.3: after 95, 90, the EWMA ≈ 93.5.
77
- // A sudden drop to 55 creates a gap of ~38 which exceeds the
78
- // drift_drop_threshold of 15, triggering the "Sudden quality drop" warning.
79
- recordCheckpoint(testDir, 20, [], 'Start', 95);
80
- recordCheckpoint(testDir, 40, [], 'Middle', 90);
81
- const result = recordCheckpoint(testDir, 60, [], 'Decline', 55);
82
- expect(result.warnings.some(w => w.includes('Sudden quality drop'))).toBe(true);
83
- });
84
- it('should not flag stable quality', () => {
85
- recordCheckpoint(testDir, 20, [], 'Start', 85);
86
- recordCheckpoint(testDir, 40, [], 'Middle', 85);
87
- const result = recordCheckpoint(testDir, 60, [], 'Stable', 85);
88
- expect(result.warnings.filter(w => w.includes('Drift'))).toHaveLength(0);
89
- });
90
- });
91
- describe('gate run', () => {
92
- it('should pass with healthy checkpoints', async () => {
93
- const gate = new CheckpointGate({ enabled: true, quality_threshold: 80 });
94
- recordCheckpoint(testDir, 50, [], 'Good work', 90);
95
- const failures = await gate.run({ cwd: testDir });
96
- expect(failures).toHaveLength(0);
97
- });
98
- it('should fail when quality below threshold', async () => {
99
- const gate = new CheckpointGate({ enabled: true, quality_threshold: 80 });
100
- recordCheckpoint(testDir, 50, [], 'Poor work', 70);
101
- const failures = await gate.run({ cwd: testDir });
102
- expect(failures.some(f => f.title === 'Quality Below Threshold')).toBe(true);
103
- });
104
- });
105
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,73 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import * as fs from 'fs';
3
- import * as path from 'path';
4
- import * as os from 'os';
5
- import { ContentGate } from './content.js';
6
- describe('ContentGate', () => {
7
- let testDir;
8
- beforeEach(() => {
9
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'content-gate-test-'));
10
- });
11
- afterEach(() => {
12
- fs.rmSync(testDir, { recursive: true, force: true });
13
- });
14
- it('flags TODO and FIXME in comments', async () => {
15
- fs.writeFileSync(path.join(testDir, 'app.ts'), `
16
- // TODO: remove temporary fallback
17
- const value = 1;
18
- const x = value; // FIXME clean this before release
19
- `);
20
- const gate = new ContentGate({ forbidTodos: true, forbidFixme: true });
21
- const failures = await gate.run({ cwd: testDir });
22
- expect(failures).toHaveLength(2);
23
- });
24
- it('does not flag TODO or FIXME in non-comment string literals', async () => {
25
- fs.writeFileSync(path.join(testDir, 'app.ts'), `
26
- const message = "TODO this is user-facing text";
27
- const note = "FIXME should not trigger in strings";
28
- `);
29
- const gate = new ContentGate({ forbidTodos: true, forbidFixme: true });
30
- const failures = await gate.run({ cwd: testDir });
31
- expect(failures).toHaveLength(0);
32
- });
33
- it('does not scan markdown files', async () => {
34
- fs.writeFileSync(path.join(testDir, 'README.md'), `
35
- # TODO
36
- This is a product roadmap item.
37
- `);
38
- const gate = new ContentGate({ forbidTodos: true, forbidFixme: true });
39
- const failures = await gate.run({ cwd: testDir });
40
- expect(failures).toHaveLength(0);
41
- });
42
- it('respects config toggles', async () => {
43
- fs.writeFileSync(path.join(testDir, 'app.ts'), `
44
- // TODO: one
45
- // FIXME: two
46
- `);
47
- const todoOnly = new ContentGate({ forbidTodos: true, forbidFixme: false });
48
- const todoFailures = await todoOnly.run({ cwd: testDir });
49
- expect(todoFailures).toHaveLength(1);
50
- expect(todoFailures[0].details).toContain("TODO");
51
- const fixmeOnly = new ContentGate({ forbidTodos: false, forbidFixme: true });
52
- const fixmeFailures = await fixmeOnly.run({ cwd: testDir });
53
- expect(fixmeFailures).toHaveLength(1);
54
- expect(fixmeFailures[0].details).toContain("FIXME");
55
- });
56
- it('does not flag explanatory mentions of TODO/FIXME in comments', async () => {
57
- fs.writeFileSync(path.join(testDir, 'notes.ts'), `
58
- // counts TODO and FIXME markers from parsed files
59
- const metrics = true;
60
- `);
61
- const gate = new ContentGate({ forbidTodos: true, forbidFixme: true });
62
- const failures = await gate.run({ cwd: testDir });
63
- expect(failures).toHaveLength(0);
64
- });
65
- it('skips test/spec files', async () => {
66
- fs.writeFileSync(path.join(testDir, 'sample.test.ts'), `
67
- // TODO: this should not be checked by content gate
68
- `);
69
- const gate = new ContentGate({ forbidTodos: true, forbidFixme: true });
70
- const failures = await gate.run({ cwd: testDir });
71
- expect(failures).toHaveLength(0);
72
- });
73
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,53 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
- import fs from 'fs';
3
- import os from 'os';
4
- import path from 'path';
5
- import { CoverageGate } from './coverage.js';
6
- describe('CoverageGate', () => {
7
- let testDir;
8
- beforeEach(() => {
9
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'coverage-gate-test-'));
10
- });
11
- afterEach(() => {
12
- fs.rmSync(testDir, { recursive: true, force: true });
13
- });
14
- it('flags low coverage from lcov report', async () => {
15
- fs.mkdirSync(path.join(testDir, 'coverage'), { recursive: true });
16
- fs.writeFileSync(path.join(testDir, 'coverage', 'lcov.info'), [
17
- 'TN:',
18
- 'SF:src/alpha.ts',
19
- 'LF:10',
20
- 'LH:3',
21
- 'end_of_record',
22
- ].join('\n'), 'utf-8');
23
- const gate = new CoverageGate({});
24
- const failures = await gate.run({ cwd: testDir });
25
- expect(failures).toHaveLength(1);
26
- expect(failures[0].id).toBe('DYNAMIC_COVERAGE_LOW');
27
- expect(failures[0].files).toEqual(['src/alpha.ts']);
28
- });
29
- it('parses coverage-final.json reports', async () => {
30
- fs.writeFileSync(path.join(testDir, 'coverage-final.json'), JSON.stringify({
31
- 'src/beta.ts': {
32
- s: { '1': 1, '2': 0, '3': 0, '4': 1 },
33
- },
34
- }), 'utf-8');
35
- const gate = new CoverageGate({});
36
- const failures = await gate.run({ cwd: testDir });
37
- expect(failures).toHaveLength(0);
38
- });
39
- it('ignores coverage reports under node_modules', async () => {
40
- fs.mkdirSync(path.join(testDir, 'node_modules', 'pkg', 'coverage'), { recursive: true });
41
- fs.writeFileSync(path.join(testDir, 'node_modules', 'pkg', 'coverage', 'lcov.info'), ['TN:', 'SF:src/dep.ts', 'LF:10', 'LH:0', 'end_of_record'].join('\n'), 'utf-8');
42
- const gate = new CoverageGate({});
43
- const failures = await gate.run({ cwd: testDir });
44
- expect(failures).toHaveLength(0);
45
- });
46
- it('respects context.ignore for coverage report discovery', async () => {
47
- fs.mkdirSync(path.join(testDir, 'generated', 'reports'), { recursive: true });
48
- fs.writeFileSync(path.join(testDir, 'generated', 'reports', 'lcov.info'), ['TN:', 'SF:src/generated.ts', 'LF:10', 'LH:0', 'end_of_record'].join('\n'), 'utf-8');
49
- const gate = new CoverageGate({});
50
- const failures = await gate.run({ cwd: testDir, ignore: ['generated/**'] });
51
- expect(failures).toHaveLength(0);
52
- });
53
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,12 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { dedupeFailures } from './runner.js';
3
- const finding = (title, line = 3) => ({ id: 'semantic-bugs', title, details: '', severity: 'high', provenance: 'traditional', files: ['src/a.ts'], line });
4
- describe('dedupeFailures', () => {
5
- it('keeps a learned rule that fires on the same line as a built-in rule of the same gate', () => {
6
- const kept = dedupeFailures([finding('credential-redirect'), finding('learned-rule: require-option-redirect')]);
7
- expect(kept.map(f => f.title)).toEqual(['credential-redirect', 'learned-rule: require-option-redirect']);
8
- });
9
- it('still drops the same rule reported twice on one line', () => {
10
- expect(dedupeFailures([finding('credential-redirect'), finding('credential-redirect'), finding('credential-redirect', 9)])).toHaveLength(2);
11
- });
12
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,86 +0,0 @@
1
- import fs from 'fs-extra';
2
- import os from 'os';
3
- import path from 'path';
4
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
- const provider = vi.hoisted(() => ({
6
- setup: vi.fn(async () => undefined),
7
- analyze: vi.fn(async (_prompt) => '{"findings": []}'),
8
- }));
9
- vi.mock('../inference/index.js', () => ({
10
- createProvider: () => ({
11
- name: 'fake',
12
- isAvailable: async () => true,
13
- setup: provider.setup,
14
- analyze: provider.analyze,
15
- dispose: () => undefined,
16
- }),
17
- }));
18
- vi.mock('../storage/local-memory.js', () => ({ checkLocalPatterns: async () => [] }));
19
- const { DeepAnalysisGate } = await import('./deep-analysis.js');
20
- const REPORT_TS = [
21
- 'export async function loadReport(days: number) {',
22
- ' const rows = await fetchAll(days);',
23
- ' return rows.length;',
24
- '}',
25
- ].join('\n');
26
- describe('DeepAnalysisGate', () => {
27
- let cwd;
28
- beforeEach(async () => {
29
- cwd = await fs.mkdtemp(path.join(os.tmpdir(), 'rigour-deep-gate-'));
30
- await fs.outputFile(path.join(cwd, 'src/report.ts'), REPORT_TS);
31
- await fs.outputFile(path.join(cwd, 'src/other.ts'), 'export const other = 1;\nexport const two = 2;\nexport const three = 3;\n');
32
- provider.setup.mockReset().mockResolvedValue(undefined);
33
- provider.analyze.mockReset().mockResolvedValue('{"findings": []}');
34
- });
35
- afterEach(async () => { await fs.remove(cwd); });
36
- const gate = () => new DeepAnalysisGate({ options: { enabled: true, provider: 'local' } });
37
- it('records an error outcome when setup fails', async () => {
38
- provider.setup.mockRejectedValue(new Error('engine missing'));
39
- const g = gate();
40
- expect(await g.run({ cwd })).toEqual([]);
41
- expect(g.getOutcome()).toMatchObject({ status: 'error', error: 'engine missing' });
42
- });
43
- it('records an error outcome when every inference call fails', async () => {
44
- provider.analyze.mockRejectedValue(new Error('invalid argument: --json'));
45
- const g = gate();
46
- await g.run({ cwd, patterns: ['src/report.ts', 'src/other.ts'] });
47
- expect(g.getOutcome()).toMatchObject({ status: 'error', chunksTotal: 2, chunksFailed: 2 });
48
- expect(g.getOutcome().error).toContain('invalid argument: --json');
49
- });
50
- it('records a partial outcome when some calls fail', async () => {
51
- provider.analyze.mockRejectedValueOnce(new Error('timed out')).mockResolvedValue('{"findings": []}');
52
- const g = gate();
53
- await g.run({ cwd, patterns: ['src/report.ts', 'src/other.ts'] });
54
- expect(g.getOutcome()).toMatchObject({ status: 'partial', chunksTotal: 2, chunksFailed: 1 });
55
- });
56
- it('reviews only the scoped file, with its numbered source', async () => {
57
- const g = gate();
58
- await g.run({ cwd, patterns: ['src/report.ts'] });
59
- expect(provider.analyze).toHaveBeenCalledTimes(1);
60
- const prompt = provider.analyze.mock.calls[0][0];
61
- expect(prompt).toContain('2| const rows = await fetchAll(days);');
62
- expect(prompt).not.toContain('src/other.ts');
63
- expect(g.getOutcome()).toMatchObject({ status: 'ok', mode: 'code', filesAnalyzed: 1 });
64
- });
65
- it('keeps grounded findings and drops ones about code that was not sent', async () => {
66
- provider.analyze.mockResolvedValue(JSON.stringify({ findings: [
67
- { category: 'scalability', severity: 'high', file: 'src/report.ts', line: 2, description: '`fetchAll` loads every row.', suggestion: 'Aggregate in SQL.', confidence: 0.8 },
68
- { category: 'security', severity: 'high', file: 'src/report.ts', line: 3, description: '`sendSecret` leaks a token.', suggestion: 'x', confidence: 0.9 },
69
- ] }));
70
- const failures = await gate().run({ cwd, patterns: ['src/report.ts'] });
71
- expect(failures).toHaveLength(1);
72
- expect(failures[0]).toMatchObject({ id: 'deep-analysis', files: ['src/report.ts'], line: 2, provenance: 'deep-analysis', verified: true });
73
- });
74
- it('uses the facts prompt for an unscoped run', async () => {
75
- const g = gate();
76
- await g.run({ cwd });
77
- expect(provider.analyze.mock.calls[0][0]).toContain('AST-EXTRACTED FACTS');
78
- expect(g.getOutcome()).toMatchObject({ status: 'ok', mode: 'facts', filesAnalyzed: 2 });
79
- });
80
- it('is ok with no analyzable files in scope', async () => {
81
- const g = gate();
82
- expect(await g.run({ cwd, patterns: ['README.md'] })).toEqual([]);
83
- expect(g.getOutcome()).toMatchObject({ status: 'ok', filesAnalyzed: 0 });
84
- expect(provider.analyze).not.toHaveBeenCalled();
85
- });
86
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,51 +0,0 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
- import { runIntentChecks } from './deep-intent.js';
6
- const DASHBOARD = [
7
- 'declare function getAccount(id: string): Promise<{ name: string }>;',
8
- 'declare function getRecommendedCourses(id: string): Promise<string[]>;',
9
- 'export async function loadDashboard(id: string) {',
10
- ' const [account, recommended] = await Promise.all([getAccount(id), getRecommendedCourses(id)]);',
11
- ' return { account, recommended };',
12
- '}',
13
- ].join('\n');
14
- /** Answers as if getRecommendedCourses were optional and getAccount required. */
15
- function provider(calls) {
16
- return {
17
- name: 'fake',
18
- isAvailable: async () => true,
19
- setup: async () => { },
20
- dispose: () => { },
21
- analyze: async (prompt) => {
22
- calls.push(prompt);
23
- const optional = /Question: [^\n]*getRecommendedCourses/.test(prompt);
24
- const ifFails = prompt.includes('Question: If');
25
- return JSON.stringify({ answer: ifFails === optional ? 'yes' : 'no' });
26
- },
27
- };
28
- }
29
- describe('runIntentChecks', () => {
30
- let cwd;
31
- beforeEach(() => { cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'deep-intent-')); });
32
- afterEach(() => { fs.rmSync(cwd, { recursive: true, force: true }); });
33
- it('reports an optional read that can take down a required one', async () => {
34
- fs.writeFileSync(path.join(cwd, 'dashboard.ts'), DASHBOARD);
35
- const calls = [];
36
- const [failure, ...rest] = await runIntentChecks(cwd, ['dashboard.ts'], provider(calls));
37
- expect(rest).toHaveLength(0);
38
- expect(calls).toHaveLength(4);
39
- expect(failure).toMatchObject({
40
- id: 'deep-analysis', files: ['dashboard.ts'], line: 4, category: 'optional-read-no-fallback',
41
- provenance: 'deep-analysis', source: 'hybrid', verified: false,
42
- });
43
- expect(failure.details).toContain('`getRecommendedCourses` looks optional');
44
- });
45
- it('asks nothing when no file has an unhandled Promise.all', async () => {
46
- fs.writeFileSync(path.join(cwd, 'plain.ts'), 'export const x = 1;\n');
47
- const calls = [];
48
- expect(await runIntentChecks(cwd, ['plain.ts', 'README.md'], provider(calls))).toEqual([]);
49
- expect(calls).toEqual([]);
50
- });
51
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,10 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { defaultTimeout } from './deep-analysis.js';
3
- describe('deep inference timeout', () => {
4
- it('gives the local 7B tier four minutes a call, the small tiers one, and cloud two', () => {
5
- expect(defaultTimeout({ enabled: true })).toBe(60_000);
6
- expect(defaultTimeout({ enabled: true, pro: true })).toBe(60_000);
7
- expect(defaultTimeout({ enabled: true, max: true })).toBe(240_000);
8
- expect(defaultTimeout({ enabled: true, apiKey: 'k', provider: 'claude' })).toBe(120_000);
9
- });
10
- });
@@ -1 +0,0 @@
1
- export {};