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,240 @@
1
+ import { readFileSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
+ import { runGit } from "./git.js";
4
+ const MAX_SYMBOLS = 25;
5
+ const MAX_REFERENCES_PER_SYMBOL = 10;
6
+ const MAX_REFERENCES = 60;
7
+ const MAX_FILE_BYTES = 512 * 1024;
8
+ const MAX_SCANNED_FILES = 5_000;
9
+ /** Short and generic names produce nothing but noise when grepped repo-wide. */
10
+ const RESERVED = new Set([
11
+ "args",
12
+ "argv",
13
+ "body",
14
+ "call",
15
+ "catch",
16
+ "class",
17
+ "count",
18
+ "data",
19
+ "done",
20
+ "entry",
21
+ "error",
22
+ "event",
23
+ "false",
24
+ "file",
25
+ "files",
26
+ "func",
27
+ "handler",
28
+ "index",
29
+ "init",
30
+ "input",
31
+ "item",
32
+ "items",
33
+ "json",
34
+ "list",
35
+ "main",
36
+ "name",
37
+ "node",
38
+ "null",
39
+ "options",
40
+ "output",
41
+ "params",
42
+ "path",
43
+ "props",
44
+ "query",
45
+ "render",
46
+ "request",
47
+ "response",
48
+ "result",
49
+ "results",
50
+ "return",
51
+ "rows",
52
+ "size",
53
+ "state",
54
+ "test",
55
+ "text",
56
+ "true",
57
+ "type",
58
+ "types",
59
+ "value",
60
+ "values",
61
+ ]);
62
+ const DECLARATIONS = [
63
+ { kind: "function", pattern: /\b(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)/ },
64
+ {
65
+ kind: "function",
66
+ pattern: /\b(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:\(|function\b)/,
67
+ },
68
+ { kind: "def", pattern: /^\s*(?:async\s+)?def\s+([A-Za-z_]\w*)/ },
69
+ { kind: "func", pattern: /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)/ },
70
+ { kind: "fn", pattern: /\bfn\s+([A-Za-z_]\w*)/ },
71
+ { kind: "type", pattern: /\b(?:export\s+)?(?:class|interface|enum|type|struct|trait)\s+([A-Za-z_$][\w$]*)/ },
72
+ ];
73
+ const HUNK_HEADER = /^@@\s*-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/;
74
+ function acceptsName(name) {
75
+ if (name.length < 4)
76
+ return false;
77
+ if (RESERVED.has(name.toLowerCase()))
78
+ return false;
79
+ return true;
80
+ }
81
+ function fileOfDiffHeader(line) {
82
+ const raw = line.slice(4).trim();
83
+ if (raw === "/dev/null")
84
+ return undefined;
85
+ return raw.replace(/^[ab]\//, "");
86
+ }
87
+ /**
88
+ * Extracts the symbols a diff actually introduces or removes. The goal is a
89
+ * short list a human can sanity-check, so constructors of anonymous callbacks
90
+ * and generic names are filtered out instead of flooding the report.
91
+ */
92
+ export function extractChangedSymbols(diff) {
93
+ const symbols = [];
94
+ const seen = new Set();
95
+ let file = "";
96
+ let lineNumber = 0;
97
+ const record = (content, atLine) => {
98
+ for (const { kind, pattern } of DECLARATIONS) {
99
+ const match = pattern.exec(content);
100
+ if (!match)
101
+ continue;
102
+ const name = match[1];
103
+ if (!acceptsName(name))
104
+ continue;
105
+ const key = `${kind}:${name}`;
106
+ if (seen.has(key))
107
+ break;
108
+ seen.add(key);
109
+ symbols.push({ name, kind, file, line: atLine });
110
+ break;
111
+ }
112
+ };
113
+ for (const line of diff.split("\n")) {
114
+ if (line.startsWith("+++ ")) {
115
+ file = fileOfDiffHeader(line) ?? "";
116
+ continue;
117
+ }
118
+ if (line.startsWith("--- ") || line.startsWith("diff --git ") || line.startsWith("index ")) {
119
+ continue;
120
+ }
121
+ const hunk = HUNK_HEADER.exec(line);
122
+ if (hunk) {
123
+ lineNumber = Number(hunk[1]);
124
+ continue;
125
+ }
126
+ if (!file)
127
+ continue;
128
+ if (line.startsWith("+")) {
129
+ record(line.slice(1), lineNumber);
130
+ lineNumber += 1;
131
+ }
132
+ else if (line.startsWith("-")) {
133
+ record(line.slice(1), lineNumber);
134
+ }
135
+ else if (line.startsWith(" ")) {
136
+ lineNumber += 1;
137
+ }
138
+ }
139
+ return symbols.slice(0, MAX_SYMBOLS);
140
+ }
141
+ function listRepoFiles(cwd) {
142
+ const result = runGit(["ls-files", "-co", "--exclude-standard", "--full-name", "-z"], cwd);
143
+ if (result.status !== 0)
144
+ return [];
145
+ return result.stdout
146
+ .split("\0")
147
+ .filter((entry) => entry.length > 0)
148
+ .slice(0, MAX_SCANNED_FILES);
149
+ }
150
+ function normalizeEntry(cwd, entry) {
151
+ const absolute = isAbsolute(entry) ? entry : resolve(cwd, entry);
152
+ const rel = relative(cwd, absolute).split(sep).join("/");
153
+ if (rel.startsWith(".."))
154
+ return undefined;
155
+ if (rel.split("/").some((part) => part === "node_modules" || part === "dist" || part === ".git")) {
156
+ return undefined;
157
+ }
158
+ return rel;
159
+ }
160
+ function escapeRegExp(value) {
161
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
162
+ }
163
+ /**
164
+ * Finds usages of the changed symbols in untouched files. It is a plain textual
165
+ * search on purpose: no language server, no AST, no repository index to keep in
166
+ * sync - just enough signal to warn that a rename has other call sites.
167
+ */
168
+ export function findSymbolReferences(cwd, symbols, touchedFiles) {
169
+ if (symbols.length === 0)
170
+ return { references: [], scannedFiles: 0 };
171
+ const touched = new Set(touchedFiles);
172
+ const byName = new Map(symbols.map((symbol) => [symbol.name, symbol]));
173
+ const matcher = new RegExp(`\\b(${[...byName.keys()].map(escapeRegExp).join("|")})\\b`, "g");
174
+ const perSymbol = new Map();
175
+ const references = [];
176
+ let scannedFiles = 0;
177
+ for (const entry of listRepoFiles(cwd)) {
178
+ const rel = normalizeEntry(cwd, entry);
179
+ if (!rel || touched.has(rel))
180
+ continue;
181
+ const absolute = join(cwd, rel);
182
+ let content;
183
+ try {
184
+ const stats = statSync(absolute);
185
+ if (!stats.isFile() || stats.size > MAX_FILE_BYTES)
186
+ continue;
187
+ content = readFileSync(absolute, "utf8");
188
+ }
189
+ catch {
190
+ continue;
191
+ }
192
+ if (content.includes("\0"))
193
+ continue;
194
+ scannedFiles += 1;
195
+ const lines = content.split("\n");
196
+ for (let index = 0; index < lines.length; index += 1) {
197
+ const text = lines[index];
198
+ matcher.lastIndex = 0;
199
+ if (!matcher.test(text))
200
+ continue;
201
+ matcher.lastIndex = 0;
202
+ let match;
203
+ while ((match = matcher.exec(text)) !== null) {
204
+ const symbol = match[1];
205
+ const used = perSymbol.get(symbol) ?? 0;
206
+ if (used >= MAX_REFERENCES_PER_SYMBOL)
207
+ break;
208
+ perSymbol.set(symbol, used + 1);
209
+ references.push({ symbol, file: rel, line: index + 1, text: text.trim().slice(0, 120) });
210
+ if (references.length >= MAX_REFERENCES)
211
+ return { references, scannedFiles };
212
+ }
213
+ }
214
+ }
215
+ return { references, scannedFiles };
216
+ }
217
+ export function analyzeImpact(cwd, diff, changedFiles) {
218
+ const symbols = extractChangedSymbols(diff);
219
+ const { references, scannedFiles } = findSymbolReferences(cwd, symbols, changedFiles);
220
+ return { symbols, references, scannedFiles, touchedFiles: changedFiles };
221
+ }
222
+ export function describeImpact(report) {
223
+ if (report.symbols.length === 0)
224
+ return "Изменённых объявлений не найдено.";
225
+ const lines = [];
226
+ for (const symbol of report.symbols) {
227
+ const hits = report.references.filter((reference) => reference.symbol === symbol.name);
228
+ const head = `${symbol.name} (${symbol.kind}) — ${symbol.file}:${symbol.line}`;
229
+ if (hits.length === 0) {
230
+ lines.push(head);
231
+ continue;
232
+ }
233
+ lines.push(head);
234
+ for (const hit of hits) {
235
+ lines.push(` ${hit.file}:${hit.line} ${hit.text}`);
236
+ }
237
+ }
238
+ return lines.join("\n");
239
+ }
240
+ //# sourceMappingURL=impact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.js","sourceRoot":"","sources":["../../src/core/impact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawnSync } from "node:child_process";
3
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import test from "node:test";
7
+ import { analyzeImpact, describeImpact, extractChangedSymbols } from "./impact.js";
8
+ const DIFF = [
9
+ "diff --git a/src/wallet.ts b/src/wallet.ts",
10
+ "--- a/src/wallet.ts",
11
+ "+++ b/src/wallet.ts",
12
+ "@@ -1,3 +1,6 @@",
13
+ "-export function charge(amount: number) {",
14
+ "+export function chargeCard(amount: number) {",
15
+ " return amount;",
16
+ " }",
17
+ "+",
18
+ "+export function refund(amount: number) {",
19
+ "+ return amount;",
20
+ "+}",
21
+ ].join("\n");
22
+ function git(args, cwd) {
23
+ const result = spawnSync("git", args, { cwd, encoding: "utf8" });
24
+ if (result.status !== 0) {
25
+ throw new Error(`git ${args.join(" ")} failed: ${result.stderr}`);
26
+ }
27
+ return result.stdout;
28
+ }
29
+ function makeRepo() {
30
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-impact-"));
31
+ git(["init"], dir);
32
+ git(["config", "user.email", "test@example.com"], dir);
33
+ git(["config", "user.name", "Test"], dir);
34
+ git(["config", "core.autocrlf", "false"], dir);
35
+ mkdirSync(join(dir, "src"), { recursive: true });
36
+ writeFileSync(join(dir, "src", "wallet.ts"), "export function charge(amount: number) {\n return amount;\n}\n");
37
+ writeFileSync(join(dir, "src", "checkout.ts"), 'import { charge } from "./wallet";\n\nexport function pay() {\n return charge(10);\n}\n');
38
+ writeFileSync(join(dir, "README.md"), "# demo\n");
39
+ git(["add", "."], dir);
40
+ git(["commit", "-m", "init"], dir);
41
+ return dir;
42
+ }
43
+ test("extractChangedSymbols reports added and removed declarations", () => {
44
+ const symbols = extractChangedSymbols(DIFF);
45
+ const byName = new Map(symbols.map((symbol) => [symbol.name, symbol]));
46
+ assert.ok(byName.has("charge"), "removed declaration is tracked");
47
+ assert.ok(byName.has("chargeCard"), "added declaration is tracked");
48
+ assert.equal(byName.get("refund")?.kind, "function");
49
+ assert.equal(byName.get("refund")?.file, "src/wallet.ts");
50
+ assert.equal(byName.get("refund")?.line, 5);
51
+ });
52
+ test("extractChangedSymbols filters generic names", () => {
53
+ const diff = [
54
+ "+++ b/src/app.ts",
55
+ "@@ -1,1 +1,3 @@",
56
+ "+function run() {",
57
+ "+const data = () => 1;",
58
+ "+export function collectInvoices() {",
59
+ ].join("\n");
60
+ const symbols = extractChangedSymbols(diff);
61
+ assert.deepEqual(symbols.map((symbol) => symbol.name), ["collectInvoices"]);
62
+ });
63
+ test("analyzeImpact finds call sites outside the changed files", () => {
64
+ const dir = makeRepo();
65
+ try {
66
+ const report = analyzeImpact(dir, DIFF, ["src/wallet.ts"]);
67
+ const chargeUses = report.references.filter((reference) => reference.symbol === "charge");
68
+ // A textual search also reports the import line; that is expected noise.
69
+ assert.deepEqual(chargeUses.map((reference) => `${reference.file}:${reference.line}`), ["src/checkout.ts:1", "src/checkout.ts:4"]);
70
+ assert.ok(report.references.every((reference) => reference.file !== "src/wallet.ts"));
71
+ assert.ok(report.scannedFiles > 0);
72
+ }
73
+ finally {
74
+ rmSync(dir, { recursive: true, force: true });
75
+ }
76
+ });
77
+ test("analyzeImpact also scans untracked files", () => {
78
+ const dir = makeRepo();
79
+ try {
80
+ writeFileSync(join(dir, "src", "extra.ts"), "export const total = refund(3);\n");
81
+ const report = analyzeImpact(dir, DIFF, ["src/wallet.ts"]);
82
+ const refundUses = report.references.filter((reference) => reference.symbol === "refund");
83
+ assert.deepEqual(refundUses.map((reference) => reference.file), ["src/extra.ts"]);
84
+ }
85
+ finally {
86
+ rmSync(dir, { recursive: true, force: true });
87
+ }
88
+ });
89
+ test("describeImpact renders symbols with and without usages", () => {
90
+ const report = {
91
+ symbols: [
92
+ { name: "refund", kind: "function", file: "src/wallet.ts", line: 5 },
93
+ { name: "Ledger", kind: "type", file: "src/ledger.ts", line: 1 },
94
+ ],
95
+ references: [{ symbol: "refund", file: "src/api.ts", line: 9, text: "await refund(5);" }],
96
+ scannedFiles: 3,
97
+ touchedFiles: ["src/wallet.ts"],
98
+ };
99
+ const text = describeImpact(report);
100
+ assert.match(text, /refund \(function\) — src\/wallet\.ts:5/);
101
+ assert.match(text, /src\/api\.ts:9 {2}await refund\(5\);/);
102
+ assert.match(text, /Ledger \(type\) — src\/ledger\.ts:1/);
103
+ assert.equal(describeImpact({ ...report, symbols: [] }), "Изменённых объявлений не найдено.");
104
+ });
105
+ //# sourceMappingURL=impact.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.test.js","sourceRoot":"","sources":["../../src/core/impact.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, join, normalize } from "node:path";
3
+ import { readRepository } from "./slop/collect.js";
4
+ const IMPORT_PATTERNS = [
5
+ /^\s*import\s+(?:type\s+)?(?:[^"']+?\s+from\s+)?["']([^"']+)["']/,
6
+ /^\s*export\s+(?:type\s+)?[^"']*?\s+from\s+["']([^"']+)["']/,
7
+ /\brequire\(\s*["']([^"']+)["']\s*\)/g,
8
+ /\bimport\(\s*["']([^"']+)["']\s*\)/g,
9
+ ];
10
+ const PY_FROM = /^\s*from\s+(\.[\w.]*)\s+import\s+/;
11
+ const EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".py"];
12
+ function normalizePath(value) {
13
+ return normalize(value).replace(/\\/g, "/").replace(/^\.\//, "");
14
+ }
15
+ function readAliases(cwd) {
16
+ const file = join(cwd, "tsconfig.json");
17
+ if (!existsSync(file))
18
+ return [];
19
+ try {
20
+ const parsed = JSON.parse(readFileSync(file, "utf8").replace(/^\uFEFF/, ""));
21
+ const options = parsed.compilerOptions;
22
+ if (!options?.paths)
23
+ return [];
24
+ const baseUrl = options.baseUrl ?? ".";
25
+ const aliases = [];
26
+ for (const [pattern, targets] of Object.entries(options.paths)) {
27
+ if (!Array.isArray(targets) || targets.length === 0)
28
+ continue;
29
+ const prefix = pattern.endsWith("*") ? pattern.slice(0, -1) : pattern;
30
+ aliases.push({ prefix, targets: targets.filter((target) => typeof target === "string"), baseUrl });
31
+ }
32
+ return aliases;
33
+ }
34
+ catch {
35
+ return [];
36
+ }
37
+ }
38
+ function aliasCandidates(specifier, aliases) {
39
+ const out = [];
40
+ for (const alias of aliases) {
41
+ if (alias.prefix && !specifier.startsWith(alias.prefix))
42
+ continue;
43
+ const rest = specifier.slice(alias.prefix.length);
44
+ for (const target of alias.targets) {
45
+ const replaced = target.includes("*") ? target.replace("*", rest) : target;
46
+ out.push(normalizePath(join(alias.baseUrl, replaced)));
47
+ }
48
+ }
49
+ return out;
50
+ }
51
+ function fileCandidates(base, files) {
52
+ const normalized = normalizePath(base);
53
+ if (files.has(normalized))
54
+ return normalized;
55
+ for (const extension of EXTENSIONS) {
56
+ if (files.has(`${normalized}${extension}`))
57
+ return `${normalized}${extension}`;
58
+ }
59
+ if (normalized.endsWith(".js")) {
60
+ const stem = normalized.slice(0, -3);
61
+ for (const extension of [".ts", ".tsx", ".mts", ".cts"]) {
62
+ if (files.has(`${stem}${extension}`))
63
+ return `${stem}${extension}`;
64
+ }
65
+ }
66
+ for (const extension of EXTENSIONS) {
67
+ const index = `${normalized}/index${extension}`;
68
+ if (files.has(index))
69
+ return index;
70
+ }
71
+ return undefined;
72
+ }
73
+ /** Resolves a specifier to a repository file when it is an internal import. */
74
+ export function resolveSpecifier(file, specifier, files, aliases = []) {
75
+ if (!specifier)
76
+ return undefined;
77
+ if (specifier.startsWith("@/")) {
78
+ return fileCandidates(`src/${specifier.slice(2)}`, files);
79
+ }
80
+ if (specifier.startsWith(".")) {
81
+ const base = normalizePath(join(dirname(file), specifier));
82
+ return fileCandidates(base, files);
83
+ }
84
+ for (const candidate of aliasCandidates(specifier, aliases)) {
85
+ const resolved = fileCandidates(candidate, files);
86
+ if (resolved)
87
+ return resolved;
88
+ }
89
+ return undefined;
90
+ }
91
+ /** Extracts static imports from one source file with their line numbers. */
92
+ export function parseImports(_file, text) {
93
+ const imports = [];
94
+ const lines = text.split("\n");
95
+ for (let index = 0; index < lines.length; index += 1) {
96
+ const line = lines[index];
97
+ let matched = false;
98
+ for (const pattern of IMPORT_PATTERNS) {
99
+ pattern.lastIndex = 0;
100
+ let match;
101
+ while ((match = pattern.exec(line)) !== null) {
102
+ if (match[1]) {
103
+ imports.push({ specifier: match[1], line: index + 1 });
104
+ matched = true;
105
+ }
106
+ if (!pattern.global)
107
+ break;
108
+ }
109
+ }
110
+ if (matched)
111
+ continue;
112
+ const python = PY_FROM.exec(line);
113
+ if (python?.[1] && python[1] !== ".") {
114
+ const dots = /^\.+/.exec(python[1])?.[0].length ?? 0;
115
+ const rest = python[1].slice(dots).replace(/\./g, "/");
116
+ const prefix = dots <= 1 ? "./" : "../".repeat(dots - 1);
117
+ imports.push({ specifier: `${prefix}${rest}`, line: index + 1 });
118
+ }
119
+ }
120
+ return imports;
121
+ }
122
+ /** Builds the internal import graph for a repository. */
123
+ export function buildImportGraph(cwd, sourceFiles) {
124
+ const files = sourceFiles ?? readRepository(cwd).files;
125
+ const paths = new Set(files.map((file) => file.path));
126
+ const aliases = readAliases(cwd);
127
+ const edges = [];
128
+ const seen = new Set();
129
+ for (const file of files) {
130
+ for (const use of parseImports(file.path, file.text)) {
131
+ const resolved = resolveSpecifier(file.path, use.specifier, paths, aliases);
132
+ if (!resolved)
133
+ continue;
134
+ const key = `${file.path}:${String(use.line)}:${resolved}`;
135
+ if (seen.has(key))
136
+ continue;
137
+ seen.add(key);
138
+ edges.push({ from: file.path, to: resolved, specifier: use.specifier, line: use.line });
139
+ }
140
+ }
141
+ const reverse = new Map();
142
+ for (const edge of edges) {
143
+ const list = reverse.get(edge.to) ?? [];
144
+ if (!list.includes(edge.from))
145
+ list.push(edge.from);
146
+ reverse.set(edge.to, list);
147
+ }
148
+ return { files: [...paths].sort(), edges, reverse };
149
+ }
150
+ /** Resolves one specifier from a file, including tsconfig aliases. */
151
+ export function resolveImportSpecifier(cwd, file, specifier, files) {
152
+ const paths = files ?? new Set(readRepository(cwd).files.map((entry) => entry.path));
153
+ return resolveSpecifier(file, specifier, paths, readAliases(cwd));
154
+ }
155
+ /** All files that transitively import one of the changed files. */
156
+ export function reverseClosure(graph, changed) {
157
+ const result = new Set();
158
+ const queue = [...changed];
159
+ while (queue.length > 0) {
160
+ const file = queue.pop();
161
+ for (const dependent of graph.reverse.get(file) ?? []) {
162
+ if (result.has(dependent))
163
+ continue;
164
+ result.add(dependent);
165
+ queue.push(dependent);
166
+ }
167
+ }
168
+ return result;
169
+ }
170
+ //# sourceMappingURL=import-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-graph.js","sourceRoot":"","sources":["../../src/core/import-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdirSync, 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 { buildImportGraph, parseImports, resolveSpecifier, reverseClosure } from "./import-graph.js";
7
+ function file(path, text) {
8
+ return { path, text };
9
+ }
10
+ test("parseImports reads static, dynamic and require imports", () => {
11
+ const imports = parseImports("src/app.ts", [
12
+ 'import { a } from "./a";',
13
+ 'import type { B } from "./b";',
14
+ 'export { c } from "./c";',
15
+ 'const d = require("./d");',
16
+ 'const e = import("./e");',
17
+ "",
18
+ ].join("\n"));
19
+ assert.deepEqual(imports.map((item) => item.specifier), ["./a", "./b", "./c", "./d", "./e"]);
20
+ assert.deepEqual(imports.map((item) => item.line), [1, 2, 3, 4, 5]);
21
+ });
22
+ test("parseImports reads relative Python imports", () => {
23
+ const imports = parseImports("pkg/app.py", "from .models import User\nfrom . import helpers\n");
24
+ assert.deepEqual(imports.map((item) => item.specifier), ["./models"]);
25
+ });
26
+ test("resolveSpecifier handles relative, index, @/ and aliases", () => {
27
+ const files = new Set(["src/a.ts", "src/lib/index.ts", "src/alias/tool.ts", "src/b.ts"]);
28
+ assert.equal(resolveSpecifier("src/app.ts", "./a", files), "src/a.ts");
29
+ assert.equal(resolveSpecifier("src/app.ts", "./lib", files), "src/lib/index.ts");
30
+ assert.equal(resolveSpecifier("src/app.ts", "@/b", files), "src/b.ts");
31
+ assert.equal(resolveSpecifier("src/app.ts", "./b.js", files), "src/b.ts");
32
+ assert.equal(resolveSpecifier("src/app.ts", "./missing", files), undefined);
33
+ });
34
+ test("buildImportGraph reads tsconfig aliases and reverseClosure finds importers", () => {
35
+ const dir = mkdtempSync(join(tmpdir(), "oc-pilot-import-graph-"));
36
+ try {
37
+ mkdirSync(join(dir, "src", "lib"), { recursive: true });
38
+ writeFileSync(join(dir, "tsconfig.json"), JSON.stringify({ compilerOptions: { baseUrl: ".", paths: { "@lib/*": ["src/lib/*"] } } }), "utf8");
39
+ const files = [
40
+ file("src/lib/wallet.ts", "export const charge = 1;\n"),
41
+ file("src/checkout.ts", 'import { charge } from "@lib/wallet";\n'),
42
+ file("src/app.ts", 'import { pay } from "./checkout";\n'),
43
+ ];
44
+ const graph = buildImportGraph(dir, files);
45
+ assert.deepEqual(graph.edges.map((edge) => `${edge.from}->${edge.to}`).sort(), ["src/app.ts->src/checkout.ts", "src/checkout.ts->src/lib/wallet.ts"]);
46
+ assert.deepEqual([...reverseClosure(graph, ["src/lib/wallet.ts"])].sort(), ["src/app.ts", "src/checkout.ts"]);
47
+ }
48
+ finally {
49
+ rmSync(dir, { recursive: true, force: true });
50
+ }
51
+ });
52
+ //# sourceMappingURL=import-graph.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-graph.test.js","sourceRoot":"","sources":["../../src/core/import-graph.test.ts"],"names":[],"mappings":"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"}