oc-pilot 0.5.1 → 0.88.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 (481) hide show
  1. package/CHANGELOG.md +683 -0
  2. package/CONTRIBUTING.md +4 -2
  3. package/README.md +588 -20
  4. package/README.ru.md +572 -10
  5. package/dist/cli.js +185 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cli.test.js +1211 -1
  8. package/dist/cli.test.js.map +1 -1
  9. package/dist/commands/anti-regression.js +97 -0
  10. package/dist/commands/anti-regression.js.map +1 -0
  11. package/dist/commands/arch-diff.js +80 -0
  12. package/dist/commands/arch-diff.js.map +1 -0
  13. package/dist/commands/authz.js +167 -0
  14. package/dist/commands/authz.js.map +1 -0
  15. package/dist/commands/autopsy.js +64 -0
  16. package/dist/commands/autopsy.js.map +1 -0
  17. package/dist/commands/bankruptcy.js +60 -0
  18. package/dist/commands/bankruptcy.js.map +1 -0
  19. package/dist/commands/battle.js +119 -0
  20. package/dist/commands/battle.js.map +1 -0
  21. package/dist/commands/boundaries.js +114 -0
  22. package/dist/commands/boundaries.js.map +1 -0
  23. package/dist/commands/bounty.js +56 -0
  24. package/dist/commands/bounty.js.map +1 -0
  25. package/dist/commands/brag.js +62 -0
  26. package/dist/commands/brag.js.map +1 -0
  27. package/dist/commands/cache.js +62 -0
  28. package/dist/commands/cache.js.map +1 -0
  29. package/dist/commands/cinema.js +61 -0
  30. package/dist/commands/cinema.js.map +1 -0
  31. package/dist/commands/cleanup.js +110 -0
  32. package/dist/commands/cleanup.js.map +1 -0
  33. package/dist/commands/commit.js +177 -0
  34. package/dist/commands/commit.js.map +1 -0
  35. package/dist/commands/commit.test.js +160 -0
  36. package/dist/commands/commit.test.js.map +1 -0
  37. package/dist/commands/compliance.js +121 -0
  38. package/dist/commands/compliance.js.map +1 -0
  39. package/dist/commands/contract-drift.js +97 -0
  40. package/dist/commands/contract-drift.js.map +1 -0
  41. package/dist/commands/coverage.js +137 -0
  42. package/dist/commands/coverage.js.map +1 -0
  43. package/dist/commands/day.js +116 -0
  44. package/dist/commands/day.js.map +1 -0
  45. package/dist/commands/day.test.js +45 -0
  46. package/dist/commands/day.test.js.map +1 -0
  47. package/dist/commands/deps.js +245 -0
  48. package/dist/commands/deps.js.map +1 -0
  49. package/dist/commands/docgen.js +4 -2
  50. package/dist/commands/docgen.js.map +1 -1
  51. package/dist/commands/doctor.js +146 -2
  52. package/dist/commands/doctor.js.map +1 -1
  53. package/dist/commands/doctor.test.js +69 -0
  54. package/dist/commands/doctor.test.js.map +1 -0
  55. package/dist/commands/echo.js +78 -0
  56. package/dist/commands/echo.js.map +1 -0
  57. package/dist/commands/ecosystem-verify.js +113 -0
  58. package/dist/commands/ecosystem-verify.js.map +1 -0
  59. package/dist/commands/env-sync.js +102 -0
  60. package/dist/commands/env-sync.js.map +1 -0
  61. package/dist/commands/explain.js +115 -0
  62. package/dist/commands/explain.js.map +1 -0
  63. package/dist/commands/fix.js +145 -3
  64. package/dist/commands/fix.js.map +1 -1
  65. package/dist/commands/flaky.js +111 -0
  66. package/dist/commands/flaky.js.map +1 -0
  67. package/dist/commands/fuzz.js +119 -0
  68. package/dist/commands/fuzz.js.map +1 -0
  69. package/dist/commands/hivemind.js +124 -0
  70. package/dist/commands/hivemind.js.map +1 -0
  71. package/dist/commands/impact.js +73 -0
  72. package/dist/commands/impact.js.map +1 -0
  73. package/dist/commands/init.js +73 -11
  74. package/dist/commands/init.js.map +1 -1
  75. package/dist/commands/init.test.js +138 -0
  76. package/dist/commands/init.test.js.map +1 -0
  77. package/dist/commands/install-hook.js +161 -0
  78. package/dist/commands/install-hook.js.map +1 -0
  79. package/dist/commands/install-hook.test.js +100 -0
  80. package/dist/commands/install-hook.test.js.map +1 -0
  81. package/dist/commands/invariants.js +103 -0
  82. package/dist/commands/invariants.js.map +1 -0
  83. package/dist/commands/mock-leak.js +97 -0
  84. package/dist/commands/mock-leak.js.map +1 -0
  85. package/dist/commands/mutate.js +99 -0
  86. package/dist/commands/mutate.js.map +1 -0
  87. package/dist/commands/pack.js +144 -0
  88. package/dist/commands/pack.js.map +1 -0
  89. package/dist/commands/preflight.js +137 -0
  90. package/dist/commands/preflight.js.map +1 -0
  91. package/dist/commands/query.js +57 -0
  92. package/dist/commands/query.js.map +1 -0
  93. package/dist/commands/ready.js +152 -0
  94. package/dist/commands/ready.js.map +1 -0
  95. package/dist/commands/receipt.js +289 -0
  96. package/dist/commands/receipt.js.map +1 -0
  97. package/dist/commands/replay.js +112 -0
  98. package/dist/commands/replay.js.map +1 -0
  99. package/dist/commands/replay.test.js +125 -0
  100. package/dist/commands/replay.test.js.map +1 -0
  101. package/dist/commands/restore.js +54 -0
  102. package/dist/commands/restore.js.map +1 -0
  103. package/dist/commands/review.js +263 -4
  104. package/dist/commands/review.js.map +1 -1
  105. package/dist/commands/review.test.js +160 -0
  106. package/dist/commands/review.test.js.map +1 -0
  107. package/dist/commands/reviewers.js +86 -0
  108. package/dist/commands/reviewers.js.map +1 -0
  109. package/dist/commands/roast.js +102 -0
  110. package/dist/commands/roast.js.map +1 -0
  111. package/dist/commands/sandbox.js +82 -0
  112. package/dist/commands/sandbox.js.map +1 -0
  113. package/dist/commands/sast.js +162 -0
  114. package/dist/commands/sast.js.map +1 -0
  115. package/dist/commands/scan.js +47 -12
  116. package/dist/commands/scan.js.map +1 -1
  117. package/dist/commands/slop.js +145 -0
  118. package/dist/commands/slop.js.map +1 -0
  119. package/dist/commands/slop.test.js +135 -0
  120. package/dist/commands/slop.test.js.map +1 -0
  121. package/dist/commands/stats.js +61 -0
  122. package/dist/commands/stats.js.map +1 -0
  123. package/dist/commands/test-gen.js +372 -0
  124. package/dist/commands/test-gen.js.map +1 -0
  125. package/dist/commands/test-guard.js +89 -0
  126. package/dist/commands/test-guard.js.map +1 -0
  127. package/dist/commands/test-plan.js +133 -0
  128. package/dist/commands/test-plan.js.map +1 -0
  129. package/dist/commands/zoom-symbol.js +52 -0
  130. package/dist/commands/zoom-symbol.js.map +1 -0
  131. package/dist/core/agent-rules.js +35 -0
  132. package/dist/core/agent-rules.js.map +1 -0
  133. package/dist/core/anthropic.test.js +116 -0
  134. package/dist/core/anthropic.test.js.map +1 -0
  135. package/dist/core/anti-regression.js +161 -0
  136. package/dist/core/anti-regression.js.map +1 -0
  137. package/dist/core/anti-regression.test.js +154 -0
  138. package/dist/core/anti-regression.test.js.map +1 -0
  139. package/dist/core/aql.js +220 -0
  140. package/dist/core/aql.js.map +1 -0
  141. package/dist/core/aql.test.js +64 -0
  142. package/dist/core/aql.test.js.map +1 -0
  143. package/dist/core/arch-diff.js +122 -0
  144. package/dist/core/arch-diff.js.map +1 -0
  145. package/dist/core/arch-diff.test.js +93 -0
  146. package/dist/core/arch-diff.test.js.map +1 -0
  147. package/dist/core/authz.js +292 -0
  148. package/dist/core/authz.js.map +1 -0
  149. package/dist/core/authz.test.js +115 -0
  150. package/dist/core/authz.test.js.map +1 -0
  151. package/dist/core/autopsy.js +230 -0
  152. package/dist/core/autopsy.js.map +1 -0
  153. package/dist/core/autopsy.test.js +106 -0
  154. package/dist/core/autopsy.test.js.map +1 -0
  155. package/dist/core/bankruptcy.js +232 -0
  156. package/dist/core/bankruptcy.js.map +1 -0
  157. package/dist/core/bankruptcy.test.js +91 -0
  158. package/dist/core/bankruptcy.test.js.map +1 -0
  159. package/dist/core/baseline.js +131 -0
  160. package/dist/core/baseline.js.map +1 -0
  161. package/dist/core/baseline.test.js +91 -0
  162. package/dist/core/baseline.test.js.map +1 -0
  163. package/dist/core/battle.js +213 -0
  164. package/dist/core/battle.js.map +1 -0
  165. package/dist/core/battle.test.js +116 -0
  166. package/dist/core/battle.test.js.map +1 -0
  167. package/dist/core/boundaries.js +200 -0
  168. package/dist/core/boundaries.js.map +1 -0
  169. package/dist/core/boundaries.test.js +62 -0
  170. package/dist/core/boundaries.test.js.map +1 -0
  171. package/dist/core/bounty.js +128 -0
  172. package/dist/core/bounty.js.map +1 -0
  173. package/dist/core/bounty.test.js +82 -0
  174. package/dist/core/bounty.test.js.map +1 -0
  175. package/dist/core/brag.js +174 -0
  176. package/dist/core/brag.js.map +1 -0
  177. package/dist/core/brag.test.js +43 -0
  178. package/dist/core/brag.test.js.map +1 -0
  179. package/dist/core/cache.js +189 -0
  180. package/dist/core/cache.js.map +1 -0
  181. package/dist/core/cache.test.js +159 -0
  182. package/dist/core/cache.test.js.map +1 -0
  183. package/dist/core/cinema.js +242 -0
  184. package/dist/core/cinema.js.map +1 -0
  185. package/dist/core/cinema.test.js +73 -0
  186. package/dist/core/cinema.test.js.map +1 -0
  187. package/dist/core/cleanup.js +107 -0
  188. package/dist/core/cleanup.js.map +1 -0
  189. package/dist/core/compliance.js +193 -0
  190. package/dist/core/compliance.js.map +1 -0
  191. package/dist/core/compliance.test.js +123 -0
  192. package/dist/core/compliance.test.js.map +1 -0
  193. package/dist/core/config.js +78 -0
  194. package/dist/core/config.js.map +1 -1
  195. package/dist/core/config.test.js +66 -0
  196. package/dist/core/config.test.js.map +1 -1
  197. package/dist/core/contract-drift.js +296 -0
  198. package/dist/core/contract-drift.js.map +1 -0
  199. package/dist/core/contract-drift.test.js +166 -0
  200. package/dist/core/contract-drift.test.js.map +1 -0
  201. package/dist/core/cost.test.js +103 -0
  202. package/dist/core/cost.test.js.map +1 -0
  203. package/dist/core/coverage.js +335 -0
  204. package/dist/core/coverage.js.map +1 -0
  205. package/dist/core/coverage.test.js +190 -0
  206. package/dist/core/coverage.test.js.map +1 -0
  207. package/dist/core/deps-fix.js +169 -0
  208. package/dist/core/deps-fix.js.map +1 -0
  209. package/dist/core/deps-fix.test.js +176 -0
  210. package/dist/core/deps-fix.test.js.map +1 -0
  211. package/dist/core/deps-health.js +353 -0
  212. package/dist/core/deps-health.js.map +1 -0
  213. package/dist/core/deps-health.test.js +230 -0
  214. package/dist/core/deps-health.test.js.map +1 -0
  215. package/dist/core/deps-why.js +260 -0
  216. package/dist/core/deps-why.js.map +1 -0
  217. package/dist/core/deps-why.test.js +175 -0
  218. package/dist/core/deps-why.test.js.map +1 -0
  219. package/dist/core/deps.js +179 -0
  220. package/dist/core/deps.js.map +1 -0
  221. package/dist/core/deps.test.js +88 -0
  222. package/dist/core/deps.test.js.map +1 -0
  223. package/dist/core/diff-source.js +4 -2
  224. package/dist/core/diff-source.js.map +1 -1
  225. package/dist/core/echo.js +151 -0
  226. package/dist/core/echo.js.map +1 -0
  227. package/dist/core/echo.test.js +90 -0
  228. package/dist/core/echo.test.js.map +1 -0
  229. package/dist/core/ecosystem-verify.js +331 -0
  230. package/dist/core/ecosystem-verify.js.map +1 -0
  231. package/dist/core/ecosystem-verify.test.js +158 -0
  232. package/dist/core/ecosystem-verify.test.js.map +1 -0
  233. package/dist/core/engine-preset.test.js +60 -0
  234. package/dist/core/engine-preset.test.js.map +1 -0
  235. package/dist/core/engine.js +278 -32
  236. package/dist/core/engine.js.map +1 -1
  237. package/dist/core/engine.test.js +63 -0
  238. package/dist/core/engine.test.js.map +1 -1
  239. package/dist/core/env-sync.js +122 -0
  240. package/dist/core/env-sync.js.map +1 -0
  241. package/dist/core/env-sync.test.js +99 -0
  242. package/dist/core/env-sync.test.js.map +1 -0
  243. package/dist/core/file-context.js +4 -2
  244. package/dist/core/file-context.js.map +1 -1
  245. package/dist/core/findings-baseline.js +60 -0
  246. package/dist/core/findings-baseline.js.map +1 -0
  247. package/dist/core/findings-baseline.test.js +77 -0
  248. package/dist/core/findings-baseline.test.js.map +1 -0
  249. package/dist/core/findings.js +68 -21
  250. package/dist/core/findings.js.map +1 -1
  251. package/dist/core/flaky.js +137 -0
  252. package/dist/core/flaky.js.map +1 -0
  253. package/dist/core/flaky.test.js +97 -0
  254. package/dist/core/flaky.test.js.map +1 -0
  255. package/dist/core/format.js +5 -3
  256. package/dist/core/format.js.map +1 -1
  257. package/dist/core/fuzz.js +306 -0
  258. package/dist/core/fuzz.js.map +1 -0
  259. package/dist/core/fuzz.test.js +121 -0
  260. package/dist/core/fuzz.test.js.map +1 -0
  261. package/dist/core/git.js +22 -0
  262. package/dist/core/git.js.map +1 -1
  263. package/dist/core/gitlab.js +176 -0
  264. package/dist/core/gitlab.js.map +1 -0
  265. package/dist/core/gitlab.test.js +199 -0
  266. package/dist/core/gitlab.test.js.map +1 -0
  267. package/dist/core/hivemind.js +250 -0
  268. package/dist/core/hivemind.js.map +1 -0
  269. package/dist/core/hivemind.test.js +79 -0
  270. package/dist/core/hivemind.test.js.map +1 -0
  271. package/dist/core/hologram.js +463 -0
  272. package/dist/core/hologram.js.map +1 -0
  273. package/dist/core/hologram.test.js +124 -0
  274. package/dist/core/hologram.test.js.map +1 -0
  275. package/dist/core/impact.js +240 -0
  276. package/dist/core/impact.js.map +1 -0
  277. package/dist/core/impact.test.js +105 -0
  278. package/dist/core/impact.test.js.map +1 -0
  279. package/dist/core/import-graph.js +170 -0
  280. package/dist/core/import-graph.js.map +1 -0
  281. package/dist/core/import-graph.test.js +52 -0
  282. package/dist/core/import-graph.test.js.map +1 -0
  283. package/dist/core/injection.js +55 -0
  284. package/dist/core/injection.js.map +1 -0
  285. package/dist/core/injection.test.js +45 -0
  286. package/dist/core/injection.test.js.map +1 -0
  287. package/dist/core/invariants.js +286 -0
  288. package/dist/core/invariants.js.map +1 -0
  289. package/dist/core/invariants.test.js +87 -0
  290. package/dist/core/invariants.test.js.map +1 -0
  291. package/dist/core/last-review.js +92 -0
  292. package/dist/core/last-review.js.map +1 -0
  293. package/dist/core/last-review.test.js +97 -0
  294. package/dist/core/last-review.test.js.map +1 -0
  295. package/dist/core/lockfile-support.test.js +112 -0
  296. package/dist/core/lockfile-support.test.js.map +1 -0
  297. package/dist/core/lockfile.js +284 -0
  298. package/dist/core/lockfile.js.map +1 -0
  299. package/dist/core/lockfile.test.js +203 -0
  300. package/dist/core/lockfile.test.js.map +1 -0
  301. package/dist/core/mock-leak.js +120 -0
  302. package/dist/core/mock-leak.js.map +1 -0
  303. package/dist/core/mock-leak.test.js +79 -0
  304. package/dist/core/mock-leak.test.js.map +1 -0
  305. package/dist/core/mutation.js +206 -0
  306. package/dist/core/mutation.js.map +1 -0
  307. package/dist/core/mutation.test.js +104 -0
  308. package/dist/core/mutation.test.js.map +1 -0
  309. package/dist/core/opencode.js +15 -2
  310. package/dist/core/opencode.js.map +1 -1
  311. package/dist/core/opencode.test.js +10 -1
  312. package/dist/core/opencode.test.js.map +1 -1
  313. package/dist/core/options.js +51 -3
  314. package/dist/core/options.js.map +1 -1
  315. package/dist/core/osv.js +202 -0
  316. package/dist/core/osv.js.map +1 -0
  317. package/dist/core/osv.test.js +173 -0
  318. package/dist/core/osv.test.js.map +1 -0
  319. package/dist/core/output-format.test.js +102 -0
  320. package/dist/core/output-format.test.js.map +1 -0
  321. package/dist/core/pack.js +212 -0
  322. package/dist/core/pack.js.map +1 -0
  323. package/dist/core/pack.test.js +129 -0
  324. package/dist/core/pack.test.js.map +1 -0
  325. package/dist/core/phantom.js +155 -0
  326. package/dist/core/phantom.js.map +1 -0
  327. package/dist/core/phantom.test.js +58 -0
  328. package/dist/core/phantom.test.js.map +1 -0
  329. package/dist/core/pr-comment.js +116 -0
  330. package/dist/core/pr-comment.js.map +1 -0
  331. package/dist/core/pr-comment.test.js +53 -0
  332. package/dist/core/pr-comment.test.js.map +1 -0
  333. package/dist/core/pr-review.js +160 -0
  334. package/dist/core/pr-review.js.map +1 -0
  335. package/dist/core/pr-review.test.js +62 -0
  336. package/dist/core/pr-review.test.js.map +1 -0
  337. package/dist/core/preflight-run.js +106 -0
  338. package/dist/core/preflight-run.js.map +1 -0
  339. package/dist/core/preflight.js +173 -0
  340. package/dist/core/preflight.js.map +1 -0
  341. package/dist/core/preflight.test.js +187 -0
  342. package/dist/core/preflight.test.js.map +1 -0
  343. package/dist/core/presets.js +408 -0
  344. package/dist/core/presets.js.map +1 -0
  345. package/dist/core/presets.test.js +79 -0
  346. package/dist/core/presets.test.js.map +1 -0
  347. package/dist/core/prompt.golden.test.js +74 -0
  348. package/dist/core/prompt.golden.test.js.map +1 -0
  349. package/dist/core/prompt.js +43 -4
  350. package/dist/core/prompt.js.map +1 -1
  351. package/dist/core/prompt.test.js +16 -0
  352. package/dist/core/prompt.test.js.map +1 -1
  353. package/dist/core/readiness-fix.js +111 -0
  354. package/dist/core/readiness-fix.js.map +1 -0
  355. package/dist/core/readiness-fix.test.js +99 -0
  356. package/dist/core/readiness-fix.test.js.map +1 -0
  357. package/dist/core/readiness.js +189 -0
  358. package/dist/core/readiness.js.map +1 -0
  359. package/dist/core/readiness.test.js +199 -0
  360. package/dist/core/readiness.test.js.map +1 -0
  361. package/dist/core/receipt.js +193 -0
  362. package/dist/core/receipt.js.map +1 -0
  363. package/dist/core/receipt.test.js +193 -0
  364. package/dist/core/receipt.test.js.map +1 -0
  365. package/dist/core/reviewers.js +179 -0
  366. package/dist/core/reviewers.js.map +1 -0
  367. package/dist/core/reviewers.test.js +105 -0
  368. package/dist/core/reviewers.test.js.map +1 -0
  369. package/dist/core/roast.js +27 -0
  370. package/dist/core/roast.js.map +1 -0
  371. package/dist/core/roast.test.js +19 -0
  372. package/dist/core/roast.test.js.map +1 -0
  373. package/dist/core/router.js +8 -0
  374. package/dist/core/router.js.map +1 -0
  375. package/dist/core/router.test.js +157 -0
  376. package/dist/core/router.test.js.map +1 -0
  377. package/dist/core/rules.js +2 -2
  378. package/dist/core/rules.js.map +1 -1
  379. package/dist/core/run.js +322 -20
  380. package/dist/core/run.js.map +1 -1
  381. package/dist/core/sarif.js +125 -0
  382. package/dist/core/sarif.js.map +1 -0
  383. package/dist/core/sarif.test.js +60 -0
  384. package/dist/core/sarif.test.js.map +1 -0
  385. package/dist/core/sast.js +324 -0
  386. package/dist/core/sast.js.map +1 -0
  387. package/dist/core/sast.test.js +105 -0
  388. package/dist/core/sast.test.js.map +1 -0
  389. package/dist/core/sbom.js +121 -0
  390. package/dist/core/sbom.js.map +1 -0
  391. package/dist/core/sbom.test.js +81 -0
  392. package/dist/core/sbom.test.js.map +1 -0
  393. package/dist/core/second-opinion.js +88 -0
  394. package/dist/core/second-opinion.js.map +1 -0
  395. package/dist/core/second-opinion.test.js +89 -0
  396. package/dist/core/second-opinion.test.js.map +1 -0
  397. package/dist/core/secrets.js +120 -5
  398. package/dist/core/secrets.js.map +1 -1
  399. package/dist/core/secrets.test.js +74 -1
  400. package/dist/core/secrets.test.js.map +1 -1
  401. package/dist/core/shadow.js +94 -0
  402. package/dist/core/shadow.js.map +1 -0
  403. package/dist/core/shadow.test.js +50 -0
  404. package/dist/core/shadow.test.js.map +1 -0
  405. package/dist/core/slicing.js +110 -0
  406. package/dist/core/slicing.js.map +1 -0
  407. package/dist/core/slicing.test.js +287 -0
  408. package/dist/core/slicing.test.js.map +1 -0
  409. package/dist/core/slop/churn.js +49 -0
  410. package/dist/core/slop/churn.js.map +1 -0
  411. package/dist/core/slop/collect.js +186 -0
  412. package/dist/core/slop/collect.js.map +1 -0
  413. package/dist/core/slop/dead-exports.js +101 -0
  414. package/dist/core/slop/dead-exports.js.map +1 -0
  415. package/dist/core/slop/duplicates.js +155 -0
  416. package/dist/core/slop/duplicates.js.map +1 -0
  417. package/dist/core/slop/index.js +72 -0
  418. package/dist/core/slop/index.js.map +1 -0
  419. package/dist/core/slop/model.js +2 -0
  420. package/dist/core/slop/model.js.map +1 -0
  421. package/dist/core/slop/score.js +185 -0
  422. package/dist/core/slop/score.js.map +1 -0
  423. package/dist/core/slop/slop.test.js +160 -0
  424. package/dist/core/slop/slop.test.js.map +1 -0
  425. package/dist/core/slop/source.js +129 -0
  426. package/dist/core/slop/source.js.map +1 -0
  427. package/dist/core/slop/test-debt.js +178 -0
  428. package/dist/core/slop/test-debt.js.map +1 -0
  429. package/dist/core/slop/test-debt.test.js +114 -0
  430. package/dist/core/slop/test-debt.test.js.map +1 -0
  431. package/dist/core/slop/todos.js +117 -0
  432. package/dist/core/slop/todos.js.map +1 -0
  433. package/dist/core/snapshot.js +214 -0
  434. package/dist/core/snapshot.js.map +1 -0
  435. package/dist/core/snapshot.test.js +101 -0
  436. package/dist/core/snapshot.test.js.map +1 -0
  437. package/dist/core/stats.js +119 -0
  438. package/dist/core/stats.js.map +1 -0
  439. package/dist/core/stats.test.js +86 -0
  440. package/dist/core/stats.test.js.map +1 -0
  441. package/dist/core/suppressions.js +96 -0
  442. package/dist/core/suppressions.js.map +1 -0
  443. package/dist/core/suppressions.test.js +90 -0
  444. package/dist/core/suppressions.test.js.map +1 -0
  445. package/dist/core/test-delta.js +53 -0
  446. package/dist/core/test-delta.js.map +1 -0
  447. package/dist/core/test-delta.test.js +41 -0
  448. package/dist/core/test-delta.test.js.map +1 -0
  449. package/dist/core/test-plan.js +212 -0
  450. package/dist/core/test-plan.js.map +1 -0
  451. package/dist/core/test-plan.test.js +94 -0
  452. package/dist/core/test-plan.test.js.map +1 -0
  453. package/dist/core/test-weakening.js +191 -0
  454. package/dist/core/test-weakening.js.map +1 -0
  455. package/dist/core/test-weakening.test.js +114 -0
  456. package/dist/core/test-weakening.test.js.map +1 -0
  457. package/dist/core/tree-scan.js +77 -0
  458. package/dist/core/tree-scan.js.map +1 -0
  459. package/dist/core/tree-scan.test.js +58 -0
  460. package/dist/core/tree-scan.test.js.map +1 -0
  461. package/dist/mcp-prompts.test.js +133 -0
  462. package/dist/mcp-prompts.test.js.map +1 -0
  463. package/dist/mcp.js +3303 -240
  464. package/dist/mcp.js.map +1 -1
  465. package/dist/mcp.test.js +1739 -1
  466. package/dist/mcp.test.js.map +1 -1
  467. package/dist/skills.test.js +221 -0
  468. package/dist/skills.test.js.map +1 -0
  469. package/dist/version.js +1 -1
  470. package/dist/version.js.map +1 -1
  471. package/docs/integrations.md +151 -7
  472. package/package.json +2 -1
  473. package/prompts/oc-pilot.en.md +8 -1
  474. package/prompts/oc-pilot.ru.md +8 -1
  475. package/server.json +2 -2
  476. package/skills/agent-self-review/SKILL.md +87 -0
  477. package/skills/commit-discipline/SKILL.md +86 -0
  478. package/skills/oc-pilot/SKILL.md +86 -0
  479. package/skills/secure-diff-gate/SKILL.md +101 -0
  480. package/skills/stack-review-packs/SKILL.md +76 -0
  481. package/skills/test-failure-triage/SKILL.md +88 -0
@@ -0,0 +1,99 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import test from "node:test";
6
+ import { analyzeEnvSync, extractEnvReferences, listEnvFiles } from "./env-sync.js";
7
+ const DIFF = [
8
+ "diff --git a/src/app.ts b/src/app.ts",
9
+ "--- a/src/app.ts",
10
+ "+++ b/src/app.ts",
11
+ "@@ -1,2 +1,8 @@",
12
+ " const a = 1;",
13
+ "+const key = process.env.NEW_SERVICE_KEY;",
14
+ '+const quoted = process.env["QUOTED_KEY"];',
15
+ "+const vite = import.meta.env.VITE_API_URL;",
16
+ '+const deno = Deno.env.get("DENO_TOKEN");',
17
+ "+const bun = Bun.env.BUN_FLAG;",
18
+ "+const ignored = process.env.NODE_ENV;",
19
+ " const b = 2;",
20
+ "",
21
+ ].join("\n");
22
+ test("extractEnvReferences reads every supported env syntax", () => {
23
+ const references = extractEnvReferences(DIFF);
24
+ assert.deepEqual(references.map((reference) => reference.name), ["NEW_SERVICE_KEY", "QUOTED_KEY", "VITE_API_URL", "DENO_TOKEN", "BUN_FLAG"]);
25
+ assert.deepEqual(references.map((reference) => reference.line), [2, 3, 4, 5, 6]);
26
+ assert.deepEqual(references.map((reference) => reference.source), ["process.env", "process.env", "import.meta.env", "Deno.env", "Bun.env"]);
27
+ assert.ok(references.every((reference) => reference.file === "src/app.ts"));
28
+ assert.ok(!references.some((reference) => reference.name === "NODE_ENV"));
29
+ });
30
+ test("analyzeEnvSync warns about defined but undocumented variables", () => {
31
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-env-sync-"));
32
+ try {
33
+ writeFileSync(join(dir, ".env"), "NEW_SERVICE_KEY=1\nQUOTED_KEY=2\nVITE_API_URL=https://example.com\nDENO_TOKEN=3\nBUN_FLAG=1\n", "utf8");
34
+ writeFileSync(join(dir, ".env.example"), "NEW_SERVICE_KEY=\n", "utf8");
35
+ const report = analyzeEnvSync(dir, DIFF);
36
+ assert.equal(report.status, "warn");
37
+ assert.deepEqual(report.envFiles, [".env", ".env.example"]);
38
+ assert.deepEqual(report.exampleFiles, [".env.example"]);
39
+ assert.deepEqual(report.missing, []);
40
+ assert.deepEqual(report.undocumented, ["BUN_FLAG", "DENO_TOKEN", "QUOTED_KEY", "VITE_API_URL"]);
41
+ }
42
+ finally {
43
+ rmSync(dir, { recursive: true, force: true });
44
+ }
45
+ });
46
+ test("analyzeEnvSync fails on a referenced variable that is not defined", () => {
47
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-env-sync-"));
48
+ try {
49
+ writeFileSync(join(dir, ".env"), "NEW_SERVICE_KEY=1\nQUOTED_KEY=2\nVITE_API_URL=x\n", "utf8");
50
+ writeFileSync(join(dir, ".env.example"), "NEW_SERVICE_KEY=\nQUOTED_KEY=\nVITE_API_URL=\nDENO_TOKEN=\n", "utf8");
51
+ const report = analyzeEnvSync(dir, DIFF);
52
+ assert.equal(report.status, "fail");
53
+ assert.deepEqual(report.missing, ["BUN_FLAG"]);
54
+ assert.deepEqual(report.undocumented, []);
55
+ }
56
+ finally {
57
+ rmSync(dir, { recursive: true, force: true });
58
+ }
59
+ });
60
+ test("analyzeEnvSync passes when every variable is defined and documented", () => {
61
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-env-sync-"));
62
+ try {
63
+ writeFileSync(join(dir, ".env"), "NEW_SERVICE_KEY=1\nQUOTED_KEY=2\nVITE_API_URL=x\nDENO_TOKEN=y\nBUN_FLAG=1\n", "utf8");
64
+ writeFileSync(join(dir, ".env.example"), "NEW_SERVICE_KEY=\nQUOTED_KEY=\nVITE_API_URL=\nDENO_TOKEN=\nBUN_FLAG=\n", "utf8");
65
+ const report = analyzeEnvSync(dir, DIFF);
66
+ assert.equal(report.status, "pass");
67
+ assert.deepEqual(report.missing, []);
68
+ assert.deepEqual(report.undocumented, []);
69
+ }
70
+ finally {
71
+ rmSync(dir, { recursive: true, force: true });
72
+ }
73
+ });
74
+ test("listEnvFiles parses export lines and detects example files", () => {
75
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-env-sync-"));
76
+ try {
77
+ writeFileSync(join(dir, ".env.local"), "export SECRET_TOKEN=abc\n", "utf8");
78
+ writeFileSync(join(dir, ".env.example"), "SECRET_TOKEN=\n", "utf8");
79
+ writeFileSync(join(dir, "README.md"), "# demo\n", "utf8");
80
+ assert.deepEqual(listEnvFiles(dir), [".env.example", ".env.local"]);
81
+ const diff = [
82
+ "diff --git a/src/auth.ts b/src/auth.ts",
83
+ "--- a/src/auth.ts",
84
+ "+++ b/src/auth.ts",
85
+ "@@ -1,1 +1,2 @@",
86
+ " const a = 1;",
87
+ "+const token = process.env.SECRET_TOKEN;",
88
+ "",
89
+ ].join("\n");
90
+ const report = analyzeEnvSync(dir, diff);
91
+ assert.equal(report.status, "pass");
92
+ assert.deepEqual(report.defined, ["SECRET_TOKEN"]);
93
+ assert.deepEqual(report.documented, ["SECRET_TOKEN"]);
94
+ }
95
+ finally {
96
+ rmSync(dir, { recursive: true, force: true });
97
+ }
98
+ });
99
+ //# sourceMappingURL=env-sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-sync.test.js","sourceRoot":"","sources":["../../src/core/env-sync.test.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, statSync } from "node:fs";
2
2
  import { isAbsolute, relative, resolve } from "node:path";
3
3
  import { truncateText } from "./diff.js";
4
- import { scanText } from "./secrets.js";
4
+ import { loadSecretIgnore, scanText } from "./secrets.js";
5
5
  const DEFAULT_TOTAL = 60_000;
6
6
  const DEFAULT_FILE = 20_000;
7
7
  const MAX_FILE_BYTES = 2 * 1024 * 1024;
@@ -41,7 +41,9 @@ export function buildFileContext(cwd, changedFiles, options = {}) {
41
41
  omitted.push(rel);
42
42
  continue;
43
43
  }
44
- const scan = redact ? scanText(content, rel) : { findings: [], redacted: content };
44
+ const scan = redact
45
+ ? scanText(content, rel, { ignore: loadSecretIgnore(cwd) })
46
+ : { findings: [], redacted: content };
45
47
  findings.push(...scan.findings);
46
48
  const perFile = truncateText(scan.redacted, maxFile, { mode: "head" });
47
49
  const block = `--- FILE: ${rel} ---\n${perFile.text.trimEnd()}`;
@@ -1 +1 @@
1
- {"version":3,"file":"file-context.js","sourceRoot":"","sources":["../../src/core/file-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-context.js","sourceRoot":"","sources":["../../src/core/file-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { PilotError } from "./errors.js";
5
+ export const BASELINE_VERSION = 1;
6
+ export const DEFAULT_BASELINE_PATH = ".oc-pilot/baseline.json";
7
+ function fingerprint(parts) {
8
+ return createHash("sha256").update(parts.join("\u0000")).digest("hex").slice(0, 32);
9
+ }
10
+ /** A SAST finding keeps its identity when the file moves lines or gains whitespace. */
11
+ export function sastFingerprint(finding) {
12
+ return fingerprint(["sast", finding.rule, finding.file, finding.snippet.trim()]);
13
+ }
14
+ /** A route finding is identified by the rule and the route it protects. */
15
+ export function authzFingerprint(finding) {
16
+ return fingerprint(["authz", finding.rule, finding.file, finding.method, finding.route]);
17
+ }
18
+ export function emptyBaseline() {
19
+ return { version: BASELINE_VERSION, sast: [], authz: [] };
20
+ }
21
+ function stringArray(value) {
22
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
23
+ }
24
+ export function loadFindingsBaseline(cwd, file = DEFAULT_BASELINE_PATH) {
25
+ const path = resolve(cwd, file);
26
+ if (!existsSync(path))
27
+ return { path, baseline: emptyBaseline(), exists: false };
28
+ let data;
29
+ try {
30
+ data = JSON.parse(readFileSync(path, "utf8").replace(/^\uFEFF/, ""));
31
+ }
32
+ catch {
33
+ throw new PilotError(`Не удалось прочитать baseline: ${file}`, {
34
+ hint: "Файл baseline должен содержать JSON, созданный через --update-baseline.",
35
+ exitCode: 2,
36
+ });
37
+ }
38
+ const record = typeof data === "object" && data !== null ? data : {};
39
+ return {
40
+ path,
41
+ exists: true,
42
+ baseline: {
43
+ version: BASELINE_VERSION,
44
+ sast: stringArray(record.sast),
45
+ authz: stringArray(record.authz),
46
+ },
47
+ };
48
+ }
49
+ export function saveFindingsBaseline(cwd, file, baseline) {
50
+ const path = resolve(cwd, file);
51
+ mkdirSync(dirname(path), { recursive: true });
52
+ const payload = {
53
+ version: BASELINE_VERSION,
54
+ sast: [...new Set(baseline.sast)].sort(),
55
+ authz: [...new Set(baseline.authz)].sort(),
56
+ };
57
+ writeFileSync(path, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
58
+ return path;
59
+ }
60
+ //# sourceMappingURL=findings-baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings-baseline.js","sourceRoot":"","sources":["../../src/core/findings-baseline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { test } from "node:test";
6
+ import { BASELINE_VERSION, authzFingerprint, loadFindingsBaseline, sastFingerprint, saveFindingsBaseline, } from "./findings-baseline.js";
7
+ const SAST = {
8
+ rule: "command-injection",
9
+ severity: "high",
10
+ file: "src/app.ts",
11
+ line: 4,
12
+ column: 3,
13
+ message: "user input reaches exec",
14
+ snippet: "exec(req.query.cmd)",
15
+ };
16
+ const AUTHZ = {
17
+ rule: "idor",
18
+ severity: "high",
19
+ file: "src/routes.ts",
20
+ line: 2,
21
+ column: 3,
22
+ method: "GET",
23
+ route: "/users/:id",
24
+ message: "object by id without an owner check",
25
+ };
26
+ function makeRepo() {
27
+ return mkdtempSync(join(tmpdir(), "oc-pilot-baseline-"));
28
+ }
29
+ test("fingerprints survive line moves and distinguish targets", () => {
30
+ assert.equal(sastFingerprint(SAST), sastFingerprint({ ...SAST, line: 40, column: 9 }));
31
+ assert.notEqual(sastFingerprint(SAST), sastFingerprint({ ...SAST, rule: "sql-injection" }));
32
+ assert.notEqual(sastFingerprint(SAST), sastFingerprint({ ...SAST, file: "src/other.ts" }));
33
+ assert.equal(authzFingerprint(AUTHZ), authzFingerprint({ ...AUTHZ, line: 30 }));
34
+ assert.notEqual(authzFingerprint(AUTHZ), authzFingerprint({ ...AUTHZ, route: "/orders/:id" }));
35
+ });
36
+ test("loadFindingsBaseline treats a missing file as empty", () => {
37
+ const dir = makeRepo();
38
+ try {
39
+ const loaded = loadFindingsBaseline(dir);
40
+ assert.equal(loaded.exists, false);
41
+ assert.equal(loaded.baseline.version, BASELINE_VERSION);
42
+ assert.deepEqual(loaded.baseline.sast, []);
43
+ assert.deepEqual(loaded.baseline.authz, []);
44
+ }
45
+ finally {
46
+ rmSync(dir, { recursive: true, force: true });
47
+ }
48
+ });
49
+ test("saveFindingsBaseline sorts and deduplicates entries", () => {
50
+ const dir = makeRepo();
51
+ try {
52
+ const path = saveFindingsBaseline(dir, "base.json", {
53
+ version: BASELINE_VERSION,
54
+ sast: ["b", "a", "a"],
55
+ authz: ["z", "y", "z"],
56
+ });
57
+ assert.match(path, /base\.json$/);
58
+ const loaded = loadFindingsBaseline(dir, "base.json");
59
+ assert.equal(loaded.exists, true);
60
+ assert.deepEqual(loaded.baseline.sast, ["a", "b"]);
61
+ assert.deepEqual(loaded.baseline.authz, ["y", "z"]);
62
+ }
63
+ finally {
64
+ rmSync(dir, { recursive: true, force: true });
65
+ }
66
+ });
67
+ test("loadFindingsBaseline rejects broken JSON", () => {
68
+ const dir = makeRepo();
69
+ try {
70
+ writeFileSync(join(dir, "baseline.json"), "{not json", "utf8");
71
+ assert.throws(() => loadFindingsBaseline(dir, "baseline.json"), /baseline/);
72
+ }
73
+ finally {
74
+ rmSync(dir, { recursive: true, force: true });
75
+ }
76
+ });
77
+ //# sourceMappingURL=findings-baseline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings-baseline.test.js","sourceRoot":"","sources":["../../src/core/findings-baseline.test.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,40 @@ function detectSeverity(text) {
35
35
  return "style";
36
36
  return undefined;
37
37
  }
38
+ const LINE_RANGE = /^(.*?):(\d+)(?::(\d+))?(?:\s*[-–—,]\s*\d+(?::\d+)?)*$/;
39
+ const HASH_LINE = /^(.*?)#L(\d+)(?:-L?\d+)?$/i;
40
+ const WORD_LINE = /^(.*?)\s*\(?\s*(?:line|строк[аи])\s*(\d+)\s*\)?$/i;
41
+ /**
42
+ * Brings the location formats models actually produce to `file:line[:column]`:
43
+ * `a.ts:10-14` → `a.ts:10`, `a.ts:10,12` → `a.ts:10`, `a.ts#L10` → `a.ts:10`,
44
+ * `a.ts (line 10)` → `a.ts:10`. Ranges collapse to their first line because the
45
+ * PR/MR APIs anchor a comment to a single line. Unknown shapes are kept as-is.
46
+ */
47
+ export function normalizeLocation(value) {
48
+ const raw = value.trim().replace(/\\/g, "/").replace(/^\.\//, "");
49
+ if (!raw)
50
+ return undefined;
51
+ const range = LINE_RANGE.exec(raw);
52
+ if (range) {
53
+ const file = (range[1] ?? "").trim();
54
+ if (!file)
55
+ return undefined;
56
+ return `${file}:${range[2]}${range[3] ? `:${range[3]}` : ""}`;
57
+ }
58
+ const hash = HASH_LINE.exec(raw);
59
+ if (hash) {
60
+ const file = (hash[1] ?? "").trim();
61
+ if (file)
62
+ return `${file}:${hash[2]}`;
63
+ }
64
+ const word = WORD_LINE.exec(raw);
65
+ if (word) {
66
+ const file = (word[1] ?? "").trim();
67
+ if (file)
68
+ return `${file}:${word[2]}`;
69
+ }
70
+ return raw;
71
+ }
38
72
  function stripMarkdown(value) {
39
73
  return value
40
74
  .replace(/`/g, "")
@@ -47,11 +81,36 @@ function stripMarkdown(value) {
47
81
  * Actions`) section of an analysis response. The output schema is intentionally
48
82
  * simple, but models vary in spacing and emphasis, so the parser is permissive.
49
83
  */
84
+ /** Parses a single findings bullet; returns undefined for non-finding lines. */
85
+ export function parseFindingBullet(line) {
86
+ const bullet = /^\s*[-*]\s+(.+)$/.exec(line);
87
+ if (!bullet)
88
+ return undefined;
89
+ const body = bullet[1].trim();
90
+ const severity = detectSeverity(body);
91
+ if (!severity)
92
+ return undefined;
93
+ const locationMatch = /`([^`]+)`/.exec(body);
94
+ const location = locationMatch ? normalizeLocation(locationMatch[1]) : undefined;
95
+ let rawText = body;
96
+ if (locationMatch)
97
+ rawText = rawText.replace(locationMatch[0], "");
98
+ let text = stripMarkdown(rawText);
99
+ text = text
100
+ .replace(/^🔴\s*/, "")
101
+ .replace(/^🟡\s*/, "")
102
+ .replace(/^🔵\s*/, "")
103
+ .replace(/^(?:critical|warning|style|note|критич\w*|предупрежд\w*|стиль)(?:\s*\/\s*(?:critical|warning|style|note|критич\w*|предупрежд\w*|стиль))?\s*[:—-]?\s*/i, "")
104
+ .replace(/^\/\s*/, "")
105
+ .replace(/^[:\s—-]+/, "")
106
+ .trim();
107
+ return { severity, location, text: text || "замечание без описания" };
108
+ }
50
109
  export function parseFindings(markdown) {
51
110
  const normalized = markdown.replace(/\r\n?/g, "\n");
52
111
  if (/LGTM:\s*(?:критических проблем не обнаружено|no critical issues found)/i.test(normalized))
53
112
  return [];
54
- const heading = /^####\s+(?:Замечания\s*\/\s*Действия|Findings\s*\/\s*Actions)\s*$/im.exec(normalized);
113
+ const heading = /^####\s+(?:Замечания|Findings)(?:\s*\/\s*(?:Действия|Actions))?\s*:?\s*$/im.exec(normalized);
55
114
  if (!heading)
56
115
  return [];
57
116
  const start = heading.index + heading[0].length;
@@ -61,29 +120,17 @@ export function parseFindings(markdown) {
61
120
  if (!section)
62
121
  return [];
63
122
  const findings = [];
123
+ let fenced = false;
64
124
  for (const line of section.split("\n")) {
65
- const bullet = /^\s*[-*]\s+(.+)$/.exec(line);
66
- if (!bullet)
125
+ if (/^\s*(?:```|~~~)/.test(line)) {
126
+ fenced = !fenced;
67
127
  continue;
68
- const body = bullet[1].trim();
69
- const severity = detectSeverity(body);
70
- if (!severity)
128
+ }
129
+ if (fenced)
71
130
  continue;
72
- const locationMatch = /`([^`]+)`/.exec(body);
73
- const location = locationMatch ? locationMatch[1].trim() : undefined;
74
- let rawText = body;
75
- if (locationMatch)
76
- rawText = rawText.replace(locationMatch[0], "");
77
- let text = stripMarkdown(rawText);
78
- text = text
79
- .replace(/^🔴\s*/, "")
80
- .replace(/^🟡\s*/, "")
81
- .replace(/^🔵\s*/, "")
82
- .replace(/^(?:critical|warning|style|note|критич\w*|предупрежд\w*|стиль)(?:\s*\/\s*(?:critical|warning|style|note|критич\w*|предупрежд\w*|стиль))?\s*[:—-]?\s*/i, "")
83
- .replace(/^\/\s*/, "")
84
- .replace(/^[:\s—-]+/, "")
85
- .trim();
86
- findings.push({ severity, location, text: text || "замечание без описания" });
131
+ const finding = parseFindingBullet(line);
132
+ if (finding)
133
+ findings.push(finding);
87
134
  }
88
135
  return findings;
89
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/core/findings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/core/findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ const ANSI = /\u001B\[[0-9;]*m/g;
2
+ /** Strips ANSI colors so status markers survive any reporter. */
3
+ export function stripAnsi(text) {
4
+ return text.replace(ANSI, "");
5
+ }
6
+ const PATTERNS = [
7
+ // node:test spec reporter
8
+ { status: "pass", regex: /^\s*\u2714\s+(.+?)(?:\s+\(\d+(?:\.\d+)?\s*m?s\))?\s*$/ },
9
+ { status: "fail", regex: /^\s*[\u2716\u2717]\s+(.+?)(?:\s+\(\d+(?:\.\d+)?\s*m?s\))?\s*$/ },
10
+ // TAP
11
+ { status: "pass", regex: /^ok\s+\d+\s+-\s+(.+?)\s*$/ },
12
+ { status: "fail", regex: /^not ok\s+\d+\s+-\s+(.+?)\s*$/ },
13
+ // go test
14
+ { status: "pass", regex: /^--- PASS:\s+(\S+)/ },
15
+ { status: "fail", regex: /^--- FAIL:\s+(\S+)/ },
16
+ // pytest -v
17
+ { status: "pass", regex: /^PASSED\s+(\S+)/ },
18
+ { status: "fail", regex: /^FAILED\s+(\S+)/ },
19
+ // jest / vitest
20
+ { status: "pass", regex: /^\s*\u2713\s+(.+?)(?:\s+\(\d+(?:\.\d+)?\s*m?s\))?\s*$/ },
21
+ { status: "fail", regex: /^\s*[\u2715\u00d7]\s+(.+?)(?:\s+\(\d+(?:\.\d+)?\s*m?s\))?\s*$/ },
22
+ ];
23
+ /** Extracts per-test pass/fail markers from common reporter output. */
24
+ export function parseTestOutput(output) {
25
+ const results = new Map();
26
+ for (const rawLine of stripAnsi(output).split(/\r?\n/)) {
27
+ for (const { status, regex } of PATTERNS) {
28
+ const match = regex.exec(rawLine);
29
+ if (match?.[1]) {
30
+ results.set(match[1].trim(), status);
31
+ break;
32
+ }
33
+ }
34
+ }
35
+ return results;
36
+ }
37
+ /** Aggregates per-run results into stable, failing and flaky tests. */
38
+ export function classifyRuns(runs) {
39
+ const totals = new Map();
40
+ for (const run of runs) {
41
+ for (const [name, status] of run) {
42
+ const entry = totals.get(name) ?? { passes: 0, failures: 0 };
43
+ if (status === "pass")
44
+ entry.passes += 1;
45
+ else
46
+ entry.failures += 1;
47
+ totals.set(name, entry);
48
+ }
49
+ }
50
+ const outcomes = [];
51
+ for (const [name, entry] of totals) {
52
+ const status = entry.passes > 0 && entry.failures > 0 ? "flaky" : entry.failures > 0 ? "failing" : "passing";
53
+ outcomes.push({ name, passes: entry.passes, failures: entry.failures, status });
54
+ }
55
+ const rank = { flaky: 0, failing: 1, passing: 2 };
56
+ outcomes.sort((a, b) => rank[a.status] - rank[b.status] || a.name.localeCompare(b.name));
57
+ return outcomes;
58
+ }
59
+ /** Builds the report from completed runs. */
60
+ export function buildFlakyReport(command, runs) {
61
+ const parsedRuns = runs.map((run) => parseTestOutput(run.output));
62
+ const parsed = parsedRuns.some((run) => run.size > 0);
63
+ const tests = parsed ? classifyRuns(parsedRuns) : [];
64
+ return {
65
+ command,
66
+ runs: runs.length,
67
+ completed: runs.filter((run) => run.exitCode !== null && !run.timedOut).length,
68
+ parsed,
69
+ tests,
70
+ flaky: tests.filter((test) => test.status === "flaky"),
71
+ failing: tests.filter((test) => test.status === "failing"),
72
+ };
73
+ }
74
+ /** Human-readable summary. */
75
+ export function renderFlaky(report) {
76
+ const lines = [
77
+ `Команда: ${report.command}`,
78
+ `Прогонов: ${String(report.runs)} (завершено ${String(report.completed)}).`,
79
+ ];
80
+ if (!report.parsed) {
81
+ lines.push("Не удалось распознать отдельные тесты в выводе — проверьте коды возврата вручную.");
82
+ return `${lines.join("\n")}\n`;
83
+ }
84
+ lines.push(`Тестов распознано: ${String(report.tests.length)}.`);
85
+ if (report.flaky.length === 0) {
86
+ lines.push("Нестабильных тестов не найдено.");
87
+ }
88
+ else {
89
+ lines.push(`Нестабильные (${String(report.flaky.length)}):`);
90
+ for (const test of report.flaky) {
91
+ lines.push(` ${test.name} — упал в ${String(test.failures)} из ${String(report.runs)} прогонов`);
92
+ }
93
+ }
94
+ if (report.failing.length > 0) {
95
+ lines.push(`Всегда падают (${String(report.failing.length)}):`);
96
+ for (const test of report.failing)
97
+ lines.push(` ${test.name}`);
98
+ }
99
+ return `${lines.join("\n")}\n`;
100
+ }
101
+ /** Deterministic PRNG so the same seed always reproduces the same order. */
102
+ function mulberry32(seed) {
103
+ let state = seed >>> 0;
104
+ return () => {
105
+ state = (state + 0x6d2b79f5) >>> 0;
106
+ let value = state;
107
+ value = Math.imul(value ^ (value >>> 15), value | 1);
108
+ value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
109
+ return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296;
110
+ };
111
+ }
112
+ function hashSeed(seed) {
113
+ let hash = 0x811c9dc5;
114
+ for (let index = 0; index < seed.length; index += 1) {
115
+ hash ^= seed.charCodeAt(index);
116
+ hash = Math.imul(hash, 0x01000193);
117
+ }
118
+ return hash >>> 0;
119
+ }
120
+ export function seededShuffle(items, seed) {
121
+ const random = mulberry32(hashSeed(seed));
122
+ const result = [...items];
123
+ for (let index = result.length - 1; index > 0; index -= 1) {
124
+ const swap = Math.floor(random() * (index + 1));
125
+ const current = result[index];
126
+ result[index] = result[swap];
127
+ result[swap] = current;
128
+ }
129
+ return result;
130
+ }
131
+ function shellQuote(value) {
132
+ return /[\s"'$`\\]/.test(value) ? `"${value.replace(/["\\$`]/g, "\\$&")}"` : value;
133
+ }
134
+ export function buildShuffleCommand(command, files, seed) {
135
+ return command.replaceAll("{files}", seededShuffle(files, seed).map(shellQuote).join(" "));
136
+ }
137
+ //# sourceMappingURL=flaky.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flaky.js","sourceRoot":"","sources":["../../src/core/flaky.ts"],"names":[],"mappings":"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"}