@stsepelin/checktrail 0.1.0-alpha.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 (385) hide show
  1. package/CONTRIBUTING.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +355 -0
  4. package/SECURITY.md +46 -0
  5. package/dist/src/actionlint-evidence.d.ts +2 -0
  6. package/dist/src/actionlint-evidence.js +166 -0
  7. package/dist/src/actionlint-inputs.d.ts +5 -0
  8. package/dist/src/actionlint-inputs.js +123 -0
  9. package/dist/src/actionlint-runner.d.ts +1 -0
  10. package/dist/src/actionlint-runner.js +122 -0
  11. package/dist/src/actionlint.d.ts +19 -0
  12. package/dist/src/actionlint.js +80 -0
  13. package/dist/src/adapters.d.ts +49 -0
  14. package/dist/src/adapters.js +430 -0
  15. package/dist/src/architecture.d.ts +107 -0
  16. package/dist/src/architecture.js +230 -0
  17. package/dist/src/clang-evidence.d.ts +2 -0
  18. package/dist/src/clang-evidence.js +194 -0
  19. package/dist/src/clang-protocol.d.ts +3 -0
  20. package/dist/src/clang-protocol.js +25 -0
  21. package/dist/src/clang-runner.d.ts +1 -0
  22. package/dist/src/clang-runner.js +159 -0
  23. package/dist/src/clang.d.ts +44 -0
  24. package/dist/src/clang.js +197 -0
  25. package/dist/src/cli.d.ts +2 -0
  26. package/dist/src/cli.js +338 -0
  27. package/dist/src/config.d.ts +33 -0
  28. package/dist/src/config.js +140 -0
  29. package/dist/src/contract-schema.d.ts +85 -0
  30. package/dist/src/contract-schema.js +56 -0
  31. package/dist/src/contract-worker.d.ts +1 -0
  32. package/dist/src/contract-worker.js +123 -0
  33. package/dist/src/contracts.d.ts +22 -0
  34. package/dist/src/contracts.js +123 -0
  35. package/dist/src/django-evidence.d.ts +2 -0
  36. package/dist/src/django-evidence.js +100 -0
  37. package/dist/src/django-runner.d.ts +1 -0
  38. package/dist/src/django-runner.js +80 -0
  39. package/dist/src/django.d.ts +9 -0
  40. package/dist/src/django.js +50 -0
  41. package/dist/src/dotnet-compiler.d.ts +1 -0
  42. package/dist/src/dotnet-compiler.js +87 -0
  43. package/dist/src/dotnet-evidence.d.ts +2 -0
  44. package/dist/src/dotnet-evidence.js +127 -0
  45. package/dist/src/dotnet-runner.d.ts +1 -0
  46. package/dist/src/dotnet-runner.js +167 -0
  47. package/dist/src/dotnet.d.ts +65 -0
  48. package/dist/src/dotnet.js +120 -0
  49. package/dist/src/engine.d.ts +19 -0
  50. package/dist/src/engine.js +239 -0
  51. package/dist/src/environment.d.ts +6 -0
  52. package/dist/src/environment.js +36 -0
  53. package/dist/src/eslint-evidence.d.ts +2 -0
  54. package/dist/src/eslint-evidence.js +98 -0
  55. package/dist/src/eslint-runner.d.ts +1 -0
  56. package/dist/src/eslint-runner.js +61 -0
  57. package/dist/src/eslint.d.ts +2 -0
  58. package/dist/src/eslint.js +40 -0
  59. package/dist/src/evidence.d.ts +2 -0
  60. package/dist/src/evidence.js +313 -0
  61. package/dist/src/external-adapter.d.ts +164 -0
  62. package/dist/src/external-adapter.js +265 -0
  63. package/dist/src/external-evidence.d.ts +2 -0
  64. package/dist/src/external-evidence.js +127 -0
  65. package/dist/src/external-runner.d.ts +1 -0
  66. package/dist/src/external-runner.js +122 -0
  67. package/dist/src/fastapi-evidence.d.ts +2 -0
  68. package/dist/src/fastapi-evidence.js +126 -0
  69. package/dist/src/fastapi-runner.d.ts +1 -0
  70. package/dist/src/fastapi-runner.js +84 -0
  71. package/dist/src/fastapi.d.ts +10 -0
  72. package/dist/src/fastapi.js +52 -0
  73. package/dist/src/fetch-pack.d.ts +16 -0
  74. package/dist/src/fetch-pack.js +154 -0
  75. package/dist/src/finding-policy-schema.d.ts +146 -0
  76. package/dist/src/finding-policy-schema.js +70 -0
  77. package/dist/src/finding-policy.d.ts +62 -0
  78. package/dist/src/finding-policy.js +206 -0
  79. package/dist/src/git-selection.d.ts +3 -0
  80. package/dist/src/git-selection.js +229 -0
  81. package/dist/src/go-directives.d.ts +1 -0
  82. package/dist/src/go-directives.js +32 -0
  83. package/dist/src/go-scope.d.ts +11 -0
  84. package/dist/src/go-scope.js +122 -0
  85. package/dist/src/golangci-evidence.d.ts +2 -0
  86. package/dist/src/golangci-evidence.js +92 -0
  87. package/dist/src/golangci-runner.d.ts +1 -0
  88. package/dist/src/golangci-runner.js +124 -0
  89. package/dist/src/golangci.d.ts +2 -0
  90. package/dist/src/golangci.js +35 -0
  91. package/dist/src/guidance.d.ts +98 -0
  92. package/dist/src/guidance.js +247 -0
  93. package/dist/src/index.d.ts +31 -0
  94. package/dist/src/index.js +16 -0
  95. package/dist/src/inventory.d.ts +4 -0
  96. package/dist/src/inventory.js +94 -0
  97. package/dist/src/java-compiler.d.ts +1 -0
  98. package/dist/src/java-compiler.js +110 -0
  99. package/dist/src/java-evidence.d.ts +2 -0
  100. package/dist/src/java-evidence.js +114 -0
  101. package/dist/src/java-runner.d.ts +1 -0
  102. package/dist/src/java-runner.js +79 -0
  103. package/dist/src/java.d.ts +25 -0
  104. package/dist/src/java.js +102 -0
  105. package/dist/src/jest-evidence.d.ts +2 -0
  106. package/dist/src/jest-evidence.js +117 -0
  107. package/dist/src/jest-runner.d.ts +1 -0
  108. package/dist/src/jest-runner.js +46 -0
  109. package/dist/src/jest.d.ts +2 -0
  110. package/dist/src/jest.js +36 -0
  111. package/dist/src/junit.d.ts +18 -0
  112. package/dist/src/junit.js +157 -0
  113. package/dist/src/laravel-evidence.d.ts +2 -0
  114. package/dist/src/laravel-evidence.js +175 -0
  115. package/dist/src/laravel-runner.d.ts +1 -0
  116. package/dist/src/laravel-runner.js +168 -0
  117. package/dist/src/laravel.d.ts +8 -0
  118. package/dist/src/laravel.js +50 -0
  119. package/dist/src/local-tool.d.ts +1 -0
  120. package/dist/src/local-tool.js +19 -0
  121. package/dist/src/mcp.d.ts +14 -0
  122. package/dist/src/mcp.js +362 -0
  123. package/dist/src/mutation.d.ts +118 -0
  124. package/dist/src/mutation.js +370 -0
  125. package/dist/src/mypy-evidence.d.ts +2 -0
  126. package/dist/src/mypy-evidence.js +63 -0
  127. package/dist/src/mypy.d.ts +2 -0
  128. package/dist/src/mypy.js +59 -0
  129. package/dist/src/node-reporter.d.ts +1 -0
  130. package/dist/src/node-reporter.js +28 -0
  131. package/dist/src/nuxt-evidence.d.ts +2 -0
  132. package/dist/src/nuxt-evidence.js +160 -0
  133. package/dist/src/nuxt-protocol.d.ts +52 -0
  134. package/dist/src/nuxt-protocol.js +29 -0
  135. package/dist/src/nuxt-runner.d.ts +1 -0
  136. package/dist/src/nuxt-runner.js +165 -0
  137. package/dist/src/nuxt.d.ts +24 -0
  138. package/dist/src/nuxt.js +105 -0
  139. package/dist/src/output.d.ts +3 -0
  140. package/dist/src/output.js +48 -0
  141. package/dist/src/phpstan-evidence.d.ts +2 -0
  142. package/dist/src/phpstan-evidence.js +81 -0
  143. package/dist/src/phpstan.d.ts +2 -0
  144. package/dist/src/phpstan.js +51 -0
  145. package/dist/src/phpunit-evidence.d.ts +2 -0
  146. package/dist/src/phpunit-evidence.js +53 -0
  147. package/dist/src/phpunit.d.ts +2 -0
  148. package/dist/src/phpunit.js +58 -0
  149. package/dist/src/pint-evidence.d.ts +2 -0
  150. package/dist/src/pint-evidence.js +79 -0
  151. package/dist/src/pint-runner.d.ts +1 -0
  152. package/dist/src/pint-runner.js +53 -0
  153. package/dist/src/pint.d.ts +2 -0
  154. package/dist/src/pint.js +37 -0
  155. package/dist/src/playwright-evidence.d.ts +2 -0
  156. package/dist/src/playwright-evidence.js +127 -0
  157. package/dist/src/playwright-reporter.d.ts +10 -0
  158. package/dist/src/playwright-reporter.js +37 -0
  159. package/dist/src/playwright-runner.d.ts +1 -0
  160. package/dist/src/playwright-runner.js +61 -0
  161. package/dist/src/playwright.d.ts +2 -0
  162. package/dist/src/playwright.js +35 -0
  163. package/dist/src/policy-pack.d.ts +21 -0
  164. package/dist/src/policy-pack.js +41 -0
  165. package/dist/src/pytest-evidence.d.ts +2 -0
  166. package/dist/src/pytest-evidence.js +116 -0
  167. package/dist/src/pytest-runner.d.ts +1 -0
  168. package/dist/src/pytest-runner.js +48 -0
  169. package/dist/src/pytest.d.ts +2 -0
  170. package/dist/src/pytest.js +25 -0
  171. package/dist/src/report-validation.d.ts +129 -0
  172. package/dist/src/report-validation.js +27 -0
  173. package/dist/src/review.d.ts +270 -0
  174. package/dist/src/review.js +349 -0
  175. package/dist/src/ruby.d.ts +2 -0
  176. package/dist/src/ruby.js +25 -0
  177. package/dist/src/ruff-evidence.d.ts +2 -0
  178. package/dist/src/ruff-evidence.js +99 -0
  179. package/dist/src/ruff.d.ts +2 -0
  180. package/dist/src/ruff.js +40 -0
  181. package/dist/src/runner.d.ts +8 -0
  182. package/dist/src/runner.js +117 -0
  183. package/dist/src/runtime-inventory.d.ts +112 -0
  184. package/dist/src/runtime-inventory.js +200 -0
  185. package/dist/src/rust-dep-info.d.ts +1 -0
  186. package/dist/src/rust-dep-info.js +46 -0
  187. package/dist/src/rust-evidence.d.ts +2 -0
  188. package/dist/src/rust-evidence.js +157 -0
  189. package/dist/src/rust-runner.d.ts +1 -0
  190. package/dist/src/rust-runner.js +161 -0
  191. package/dist/src/rust.d.ts +7 -0
  192. package/dist/src/rust.js +39 -0
  193. package/dist/src/sarif.d.ts +86 -0
  194. package/dist/src/sarif.js +113 -0
  195. package/dist/src/schemas.d.ts +393 -0
  196. package/dist/src/schemas.js +222 -0
  197. package/dist/src/staticcheck-evidence.d.ts +2 -0
  198. package/dist/src/staticcheck-evidence.js +75 -0
  199. package/dist/src/swift.d.ts +2 -0
  200. package/dist/src/swift.js +20 -0
  201. package/dist/src/task-store.d.ts +37 -0
  202. package/dist/src/task-store.js +349 -0
  203. package/dist/src/tool-versions.d.ts +3 -0
  204. package/dist/src/tool-versions.js +260 -0
  205. package/dist/src/types.d.ts +157 -0
  206. package/dist/src/types.js +37 -0
  207. package/dist/src/typescript-build-evidence.d.ts +2 -0
  208. package/dist/src/typescript-build-evidence.js +86 -0
  209. package/dist/src/typescript-build-runner.d.ts +1 -0
  210. package/dist/src/typescript-build-runner.js +132 -0
  211. package/dist/src/typescript-build.d.ts +2 -0
  212. package/dist/src/typescript-build.js +41 -0
  213. package/dist/src/typescript.d.ts +2 -0
  214. package/dist/src/typescript.js +54 -0
  215. package/dist/src/validation-task-worker.d.ts +1 -0
  216. package/dist/src/validation-task-worker.js +205 -0
  217. package/dist/src/validation-tasks-protocol.d.ts +69 -0
  218. package/dist/src/validation-tasks-protocol.js +57 -0
  219. package/dist/src/validation-tasks.d.ts +11 -0
  220. package/dist/src/validation-tasks.js +144 -0
  221. package/dist/src/vitest-evidence.d.ts +2 -0
  222. package/dist/src/vitest-evidence.js +112 -0
  223. package/dist/src/vitest-runner.d.ts +1 -0
  224. package/dist/src/vitest-runner.js +48 -0
  225. package/dist/src/vitest.d.ts +2 -0
  226. package/dist/src/vitest.js +36 -0
  227. package/dist/src/vue-router-capture.d.ts +42 -0
  228. package/dist/src/vue-router-capture.js +87 -0
  229. package/dist/src/vue-router-evidence.d.ts +2 -0
  230. package/dist/src/vue-router-evidence.js +126 -0
  231. package/dist/src/vue-router-protocol.d.ts +63 -0
  232. package/dist/src/vue-router-protocol.js +44 -0
  233. package/dist/src/vue-router-runner.d.ts +1 -0
  234. package/dist/src/vue-router-runner.js +88 -0
  235. package/dist/src/vue-router.d.ts +23 -0
  236. package/dist/src/vue-router.js +108 -0
  237. package/dist/src/vue-tsc-runner.d.ts +1 -0
  238. package/dist/src/vue-tsc-runner.js +24 -0
  239. package/dist/src/workspace.d.ts +7 -0
  240. package/dist/src/workspace.js +53 -0
  241. package/docs/ACCEPTANCE.md +56 -0
  242. package/docs/ACTIONLINT.md +112 -0
  243. package/docs/ARCHITECTURE-POLICY.md +82 -0
  244. package/docs/ARCHITECTURE.md +122 -0
  245. package/docs/CLANG.md +113 -0
  246. package/docs/CLIENTS.md +109 -0
  247. package/docs/CONTRACTS.md +73 -0
  248. package/docs/DEPENDENCIES.md +42 -0
  249. package/docs/DJANGO.md +70 -0
  250. package/docs/DOTNET.md +114 -0
  251. package/docs/ENVIRONMENTS.md +52 -0
  252. package/docs/ESLINT.md +68 -0
  253. package/docs/EVALUATION.md +124 -0
  254. package/docs/EXECUTION.md +250 -0
  255. package/docs/EXTERNAL-ADAPTERS.md +170 -0
  256. package/docs/EXTERNAL-EVALUATION.md +155 -0
  257. package/docs/EXTERNAL-RUFF-EVALUATION.md +85 -0
  258. package/docs/FASTAPI.md +73 -0
  259. package/docs/FINDING-POLICY.md +67 -0
  260. package/docs/GO-RACE.md +19 -0
  261. package/docs/GO-SCOPE.md +63 -0
  262. package/docs/GOLANGCI-LINT.md +64 -0
  263. package/docs/GUIDANCE.md +46 -0
  264. package/docs/IMPACT-MEASUREMENT.md +97 -0
  265. package/docs/INSTALLATION.md +102 -0
  266. package/docs/JAVA.md +79 -0
  267. package/docs/JEST.md +36 -0
  268. package/docs/JUNIT.md +31 -0
  269. package/docs/LANGUAGES.md +113 -0
  270. package/docs/LARAVEL.md +111 -0
  271. package/docs/MCP-COMPATIBILITY.md +68 -0
  272. package/docs/MUTATIONS.md +93 -0
  273. package/docs/MYPY.md +37 -0
  274. package/docs/NATIVE-CI.md +96 -0
  275. package/docs/NUXT.md +123 -0
  276. package/docs/PACK-DISTRIBUTION.md +98 -0
  277. package/docs/PERFORMANCE.md +71 -0
  278. package/docs/PEST.md +36 -0
  279. package/docs/PHPSTAN.md +48 -0
  280. package/docs/PHPUNIT.md +32 -0
  281. package/docs/PINT.md +41 -0
  282. package/docs/PLAN.md +265 -0
  283. package/docs/PLAYWRIGHT.md +73 -0
  284. package/docs/POLICY-PACKS.md +106 -0
  285. package/docs/PRIOR-WORKFLOW-EVALUATION.md +116 -0
  286. package/docs/PUBLICATION.md +28 -0
  287. package/docs/PYTEST.md +51 -0
  288. package/docs/RELEASE.md +115 -0
  289. package/docs/RENAMING.md +55 -0
  290. package/docs/REVIEW-EXCHANGE.md +136 -0
  291. package/docs/RUBY.md +50 -0
  292. package/docs/RUFF.md +39 -0
  293. package/docs/RUNTIME-INVENTORY.md +56 -0
  294. package/docs/RUST.md +74 -0
  295. package/docs/SARIF.md +64 -0
  296. package/docs/STATUS.md +530 -0
  297. package/docs/SWIFT.md +48 -0
  298. package/docs/TASK-STORAGE.md +141 -0
  299. package/docs/TOOL-IDENTITY.md +30 -0
  300. package/docs/TYPESCRIPT-BUILD.md +55 -0
  301. package/docs/VALIDATION-TASKS.md +119 -0
  302. package/docs/VITEST.md +36 -0
  303. package/docs/VUE-ROUTER.md +130 -0
  304. package/docs/VUE-TSC.md +26 -0
  305. package/docs/WORKSPACES.md +81 -0
  306. package/docs/licenses/nodable-entities-3.0.0.txt +21 -0
  307. package/docs/measurements/client-claude-before-schema-fix-darwin-arm64-node26.json +60 -0
  308. package/docs/measurements/client-claude-darwin-arm64-node26.json +55 -0
  309. package/docs/measurements/client-codex-darwin-arm64-node26.json +175 -0
  310. package/docs/measurements/evaluation-corpus-repo-verifier.json +332 -0
  311. package/docs/measurements/evaluation-darwin-arm64-node26.json +1236 -0
  312. package/docs/measurements/evaluation-linux-arm64-node22.json +1236 -0
  313. package/docs/measurements/external-eslint-darwin-arm64-node26.json +11866 -0
  314. package/docs/measurements/external-eslint-linux-arm64-node22.json +11866 -0
  315. package/docs/measurements/external-eslint-preservation.json +1527 -0
  316. package/docs/measurements/external-ruff-darwin-arm64-node26.json +1031 -0
  317. package/docs/measurements/external-ruff-linux-arm64-node22.json +1031 -0
  318. package/docs/measurements/hosted-ci-52ba415.json +1005 -0
  319. package/docs/measurements/impact-darwin-arm64-node26.json +6685 -0
  320. package/docs/measurements/impact-linux-arm64-node22.json +6690 -0
  321. package/docs/measurements/performance-darwin-arm64-node26.json +845 -0
  322. package/docs/measurements/performance-linux-arm64-node22.json +845 -0
  323. package/docs/measurements/required-native-profiles.json +500 -0
  324. package/package.json +72 -0
  325. package/packs/actionlint.json +8 -0
  326. package/packs/cpp.json +8 -0
  327. package/packs/dotnet.json +8 -0
  328. package/packs/go.json +7 -0
  329. package/packs/java.json +8 -0
  330. package/packs/javascript-node.json +7 -0
  331. package/packs/nuxt.json +7 -0
  332. package/packs/php-pest.json +7 -0
  333. package/packs/php-phpunit.json +7 -0
  334. package/packs/python-pytest.json +7 -0
  335. package/packs/ruby.json +7 -0
  336. package/packs/rust.json +7 -0
  337. package/packs/swift.json +7 -0
  338. package/packs/vue-router.json +7 -0
  339. package/packs/vue.json +11 -0
  340. package/schemas/actionlint-config.schema.json +19 -0
  341. package/schemas/architecture-policy.schema.json +51 -0
  342. package/schemas/architecture-report.schema.json +123 -0
  343. package/schemas/architecture-summary.schema.json +82 -0
  344. package/schemas/clang-database.schema.json +23 -0
  345. package/schemas/config.schema.json +69 -0
  346. package/schemas/contract-bundle.schema.json +78 -0
  347. package/schemas/contract-report.schema.json +114 -0
  348. package/schemas/contract-summary.schema.json +72 -0
  349. package/schemas/dependency-graph.schema.json +65 -0
  350. package/schemas/django-config.schema.json +16 -0
  351. package/schemas/dotnet-config.schema.json +60 -0
  352. package/schemas/external-manifest.schema.json +97 -0
  353. package/schemas/external-reference.schema.json +10 -0
  354. package/schemas/external-request.schema.json +56 -0
  355. package/schemas/external-result.schema.json +111 -0
  356. package/schemas/fastapi-config.schema.json +27 -0
  357. package/schemas/finding-baseline.schema.json +92 -0
  358. package/schemas/finding-comparison-summary.schema.json +95 -0
  359. package/schemas/finding-comparison.schema.json +121 -0
  360. package/schemas/guidance-context.schema.json +34 -0
  361. package/schemas/guidance-report.schema.json +176 -0
  362. package/schemas/guidance-summary.schema.json +68 -0
  363. package/schemas/java-config.schema.json +24 -0
  364. package/schemas/junit.schema.json +69 -0
  365. package/schemas/laravel-config.schema.json +11 -0
  366. package/schemas/mutation-recipe.schema.json +31 -0
  367. package/schemas/mutation-report.schema.json +238 -0
  368. package/schemas/mutation-summary.schema.json +98 -0
  369. package/schemas/nuxt-config.schema.json +51 -0
  370. package/schemas/plan-summary.schema.json +63 -0
  371. package/schemas/plan.schema.json +244 -0
  372. package/schemas/policy-pack.schema.json +41 -0
  373. package/schemas/report-summary.schema.json +100 -0
  374. package/schemas/report.schema.json +463 -0
  375. package/schemas/review-assessment.schema.json +133 -0
  376. package/schemas/review-context-summary.schema.json +31 -0
  377. package/schemas/review-context.schema.json +254 -0
  378. package/schemas/review-receipt-summary.schema.json +104 -0
  379. package/schemas/review-receipt.schema.json +271 -0
  380. package/schemas/review-selection.schema.json +30 -0
  381. package/schemas/runtime-comparison-summary.schema.json +68 -0
  382. package/schemas/runtime-comparison.schema.json +127 -0
  383. package/schemas/runtime-inventory.schema.json +99 -0
  384. package/schemas/vue-router-config.schema.json +67 -0
  385. package/server.json +47 -0
@@ -0,0 +1,205 @@
1
+ import { z } from "zod";
2
+ import { createPlan, validate } from "./engine.js";
3
+ import { openTaskStore, } from "./task-store.js";
4
+ import { validationTasksOptionsSchema, validationTaskRequestSchema, } from "./validation-tasks-protocol.js";
5
+ let store;
6
+ let options;
7
+ let initializing = false;
8
+ let closing;
9
+ let starting;
10
+ let active;
11
+ function send(message) {
12
+ if (!process.connected)
13
+ return;
14
+ try {
15
+ process.send(message, (failure) => {
16
+ if (failure)
17
+ disconnect();
18
+ });
19
+ }
20
+ catch {
21
+ disconnect();
22
+ }
23
+ }
24
+ function reply(id, value) {
25
+ send({ id, ok: true, value });
26
+ }
27
+ function error(id, code) {
28
+ send({ id, ok: false, error: code });
29
+ }
30
+ function planOptions() {
31
+ const value = options;
32
+ return {
33
+ ...(value.base !== undefined ? { base: value.base } : {}),
34
+ ...(value.policyOverlay !== undefined
35
+ ? { policyOverlay: value.policyOverlay }
36
+ : {}),
37
+ ...(value.environment !== undefined
38
+ ? { environment: value.environment }
39
+ : {}),
40
+ ...(value.externalAdapters !== undefined
41
+ ? { externalAdapters: value.externalAdapters }
42
+ : {}),
43
+ };
44
+ }
45
+ async function run(taskId, controller) {
46
+ try {
47
+ try {
48
+ const report = await validate(options.root, {
49
+ ...planOptions(),
50
+ trusted: true,
51
+ timeoutMs: options.timeoutMs,
52
+ signal: controller.signal,
53
+ });
54
+ if (!controller.signal.aborted)
55
+ store.complete(taskId, report);
56
+ }
57
+ catch {
58
+ if (!controller.signal.aborted)
59
+ store.interrupt(taskId);
60
+ }
61
+ if (controller.signal.aborted)
62
+ store.finishCancellation(taskId);
63
+ }
64
+ catch {
65
+ // Persistence failure must not release the execution slot as a successful task.
66
+ disconnect();
67
+ }
68
+ finally {
69
+ active = undefined;
70
+ }
71
+ }
72
+ async function start() {
73
+ const { plan } = await createPlan(options.root, planOptions());
74
+ if (closing)
75
+ throw new Error("closing");
76
+ const task = store.create(plan.sourceFingerprint);
77
+ const controller = new AbortController();
78
+ const done = new Promise((resolve) => {
79
+ setImmediate(() => {
80
+ void run(task.taskId, controller).finally(resolve);
81
+ });
82
+ });
83
+ active = { taskId: task.taskId, controller, done };
84
+ return task;
85
+ }
86
+ async function cancel(taskId) {
87
+ const task = store.get(taskId);
88
+ if (task.status !== "working")
89
+ return task;
90
+ if (active?.taskId !== taskId)
91
+ throw new Error("No active worker for task");
92
+ store.requestCancellation(taskId);
93
+ const running = active;
94
+ running.controller.abort();
95
+ await running.done;
96
+ return store.get(taskId);
97
+ }
98
+ async function shutdown() {
99
+ closing ??= (async () => {
100
+ await starting?.catch(() => { });
101
+ const running = active;
102
+ if (running) {
103
+ try {
104
+ store.requestCancellation(running.taskId);
105
+ }
106
+ finally {
107
+ running.controller.abort();
108
+ await running.done;
109
+ }
110
+ }
111
+ store?.close();
112
+ })();
113
+ return closing;
114
+ }
115
+ function disconnect() {
116
+ const release = () => {
117
+ try {
118
+ store?.close();
119
+ }
120
+ finally {
121
+ if (process.connected)
122
+ process.disconnect();
123
+ }
124
+ };
125
+ void shutdown().then(release, release);
126
+ }
127
+ process.on("disconnect", disconnect);
128
+ process.on("SIGTERM", disconnect);
129
+ process.on("SIGINT", disconnect);
130
+ process.on("message", (message) => {
131
+ void (async () => {
132
+ if (!options) {
133
+ if (initializing) {
134
+ error(0, "busy");
135
+ return;
136
+ }
137
+ initializing = true;
138
+ try {
139
+ const initial = z
140
+ .strictObject({ options: validationTasksOptionsSchema })
141
+ .parse(message);
142
+ store = await openTaskStore(initial.options);
143
+ if (closing) {
144
+ store.close();
145
+ return;
146
+ }
147
+ options = initial.options;
148
+ reply(0, null);
149
+ }
150
+ catch {
151
+ error(0, "unavailable");
152
+ disconnect();
153
+ }
154
+ return;
155
+ }
156
+ const request = validationTaskRequestSchema.safeParse(message);
157
+ if (!request.success)
158
+ return;
159
+ const { id, method } = request.data;
160
+ if (closing) {
161
+ error(id, "closed");
162
+ return;
163
+ }
164
+ if (method === "close") {
165
+ try {
166
+ await shutdown();
167
+ reply(id, null);
168
+ }
169
+ finally {
170
+ if (process.connected)
171
+ process.disconnect();
172
+ }
173
+ return;
174
+ }
175
+ if (method === "start") {
176
+ if (!options.allowExecution) {
177
+ error(id, "denied");
178
+ return;
179
+ }
180
+ if (starting || active) {
181
+ error(id, "busy");
182
+ return;
183
+ }
184
+ starting = start();
185
+ try {
186
+ reply(id, await starting);
187
+ }
188
+ catch {
189
+ error(id, "invalid");
190
+ }
191
+ finally {
192
+ starting = undefined;
193
+ }
194
+ return;
195
+ }
196
+ try {
197
+ reply(id, method === "get"
198
+ ? store.get(request.data.taskId)
199
+ : await cancel(request.data.taskId));
200
+ }
201
+ catch {
202
+ error(id, "invalid");
203
+ }
204
+ })().catch(disconnect);
205
+ });
@@ -0,0 +1,69 @@
1
+ import { z } from "zod";
2
+ export declare const validationTasksOptionsSchema: z.ZodObject<{
3
+ root: z.ZodString;
4
+ directory: z.ZodString;
5
+ detailed: z.ZodDefault<z.ZodBoolean>;
6
+ allowExecution: z.ZodBoolean;
7
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
8
+ base: z.ZodOptional<z.ZodString>;
9
+ policyOverlay: z.ZodOptional<z.ZodString>;
10
+ environment: z.ZodOptional<z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodString>, z.ZodTransform<Record<string, string>, Record<string, string>>>>;
11
+ externalAdapters: z.ZodOptional<z.ZodArray<z.ZodObject<{
12
+ path: z.ZodString;
13
+ sha256: z.ZodString;
14
+ }, z.core.$strict>>>;
15
+ }, z.core.$strict>;
16
+ export type ValidationTasksOptions = z.input<typeof validationTasksOptionsSchema>;
17
+ export declare const validationTaskRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
18
+ id: z.ZodNumber;
19
+ method: z.ZodLiteral<"start">;
20
+ }, z.core.$strict>, z.ZodObject<{
21
+ id: z.ZodNumber;
22
+ method: z.ZodLiteral<"get">;
23
+ taskId: z.ZodString;
24
+ }, z.core.$strict>, z.ZodObject<{
25
+ id: z.ZodNumber;
26
+ method: z.ZodLiteral<"cancel">;
27
+ taskId: z.ZodString;
28
+ }, z.core.$strict>, z.ZodObject<{
29
+ id: z.ZodNumber;
30
+ method: z.ZodLiteral<"close">;
31
+ }, z.core.$strict>], "method">;
32
+ export declare const storedValidationTaskSchema: z.ZodObject<{
33
+ taskId: z.ZodString;
34
+ status: z.ZodEnum<{
35
+ cancelled: "cancelled";
36
+ working: "working";
37
+ completed: "completed";
38
+ }>;
39
+ createdAt: z.ZodISODateTime;
40
+ lastUpdatedAt: z.ZodISODateTime;
41
+ ttlMs: z.ZodNumber;
42
+ result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
+ }, z.core.$strict>;
44
+ export declare const validationTaskResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
45
+ id: z.ZodNumber;
46
+ ok: z.ZodLiteral<true>;
47
+ value: z.ZodNullable<z.ZodObject<{
48
+ taskId: z.ZodString;
49
+ status: z.ZodEnum<{
50
+ cancelled: "cancelled";
51
+ working: "working";
52
+ completed: "completed";
53
+ }>;
54
+ createdAt: z.ZodISODateTime;
55
+ lastUpdatedAt: z.ZodISODateTime;
56
+ ttlMs: z.ZodNumber;
57
+ result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
58
+ }, z.core.$strict>>;
59
+ }, z.core.$strict>, z.ZodObject<{
60
+ id: z.ZodNumber;
61
+ ok: z.ZodLiteral<false>;
62
+ error: z.ZodEnum<{
63
+ unavailable: "unavailable";
64
+ invalid: "invalid";
65
+ denied: "denied";
66
+ busy: "busy";
67
+ closed: "closed";
68
+ }>;
69
+ }, z.core.$strict>], "ok">;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import { externalReferencesSchema } from "./external-adapter.js";
3
+ import { operatorEnvironment } from "./environment.js";
4
+ export const validationTasksOptionsSchema = z.strictObject({
5
+ root: z.string().min(1).max(4096),
6
+ directory: z.string().min(1).max(4096),
7
+ detailed: z.boolean().default(false),
8
+ allowExecution: z.boolean(),
9
+ timeoutMs: z.number().int().min(1).max(120000).default(30000),
10
+ base: z.string().min(1).max(4096).optional(),
11
+ policyOverlay: z.string().min(1).max(4096).optional(),
12
+ environment: z
13
+ .record(z.string(), z.string())
14
+ .transform((value) => operatorEnvironment(value))
15
+ .optional(),
16
+ externalAdapters: externalReferencesSchema.optional(),
17
+ });
18
+ export const validationTaskRequestSchema = z.discriminatedUnion("method", [
19
+ z.strictObject({
20
+ id: z.number().int().positive(),
21
+ method: z.literal("start"),
22
+ }),
23
+ z.strictObject({
24
+ id: z.number().int().positive(),
25
+ method: z.literal("get"),
26
+ taskId: z.string().uuid(),
27
+ }),
28
+ z.strictObject({
29
+ id: z.number().int().positive(),
30
+ method: z.literal("cancel"),
31
+ taskId: z.string().uuid(),
32
+ }),
33
+ z.strictObject({
34
+ id: z.number().int().positive(),
35
+ method: z.literal("close"),
36
+ }),
37
+ ]);
38
+ export const storedValidationTaskSchema = z.strictObject({
39
+ taskId: z.string().uuid(),
40
+ status: z.enum(["working", "completed", "cancelled"]),
41
+ createdAt: z.iso.datetime(),
42
+ lastUpdatedAt: z.iso.datetime(),
43
+ ttlMs: z.number().int().positive(),
44
+ result: z.record(z.string(), z.unknown()).optional(),
45
+ });
46
+ export const validationTaskResponseSchema = z.discriminatedUnion("ok", [
47
+ z.strictObject({
48
+ id: z.number().int().nonnegative(),
49
+ ok: z.literal(true),
50
+ value: storedValidationTaskSchema.nullable(),
51
+ }),
52
+ z.strictObject({
53
+ id: z.number().int().nonnegative(),
54
+ ok: z.literal(false),
55
+ error: z.enum(["unavailable", "denied", "busy", "invalid", "closed"]),
56
+ }),
57
+ ]);
@@ -0,0 +1,11 @@
1
+ import { type ValidationTasksOptions } from "./validation-tasks-protocol.js";
2
+ import type { StoredValidationTask } from "./task-store.js";
3
+ export type { ValidationTasksOptions } from "./validation-tasks-protocol.js";
4
+ export interface ValidationTasks {
5
+ start(): Promise<StoredValidationTask>;
6
+ get(taskId: string): Promise<StoredValidationTask>;
7
+ cancel(taskId: string): Promise<StoredValidationTask>;
8
+ close(): Promise<void>;
9
+ }
10
+ /** Own a local validation worker and durable result store; no MCP transport is implied. */
11
+ export declare function openValidationTasks(input: ValidationTasksOptions): Promise<ValidationTasks>;
@@ -0,0 +1,144 @@
1
+ import { fork } from "node:child_process";
2
+ import { realpath } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { validationTasksOptionsSchema, validationTaskRequestSchema, validationTaskResponseSchema, } from "./validation-tasks-protocol.js";
5
+ /** Own a local validation worker and durable result store; no MCP transport is implied. */
6
+ export async function openValidationTasks(input) {
7
+ const options = validationTasksOptionsSchema.parse(input);
8
+ options.root = await realpath(options.root);
9
+ options.directory = path.resolve(options.directory);
10
+ const environment = {};
11
+ for (const name of [
12
+ "PATH",
13
+ "HOME",
14
+ "TMPDIR",
15
+ "TMP",
16
+ "TEMP",
17
+ "LANG",
18
+ "LC_ALL",
19
+ ])
20
+ if (process.env[name] !== undefined)
21
+ environment[name] = process.env[name];
22
+ const child = fork(new URL("./validation-task-worker.js", import.meta.url), [], {
23
+ execArgv: [],
24
+ env: environment,
25
+ stdio: ["ignore", "ignore", "ignore", "ipc"],
26
+ });
27
+ let sequence = 0;
28
+ let closed = false;
29
+ let closing;
30
+ const pending = new Map();
31
+ function fail() {
32
+ closed = true;
33
+ for (const entry of pending.values())
34
+ entry.reject(new Error("Validation task worker unavailable"));
35
+ pending.clear();
36
+ }
37
+ const exited = new Promise((resolve) => {
38
+ const finish = () => {
39
+ fail();
40
+ resolve();
41
+ };
42
+ // With ignored streams, exit is sufficient; concurrent IPC disconnects can omit close.
43
+ child.once("exit", finish);
44
+ child.once("close", finish);
45
+ child.on("error", () => {
46
+ fail();
47
+ if (!child.pid)
48
+ resolve();
49
+ });
50
+ });
51
+ child.on("message", (message) => {
52
+ const result = validationTaskResponseSchema.safeParse(message);
53
+ if (!result.success) {
54
+ fail();
55
+ if (child.connected)
56
+ child.disconnect();
57
+ return;
58
+ }
59
+ const entry = pending.get(result.data.id);
60
+ if (!entry)
61
+ return;
62
+ pending.delete(result.data.id);
63
+ if (result.data.ok) {
64
+ const value = result.data.value;
65
+ if (value) {
66
+ const { result: payload, ...metadata } = value;
67
+ entry.resolve({
68
+ ...metadata,
69
+ ...(payload !== undefined ? { result: payload } : {}),
70
+ });
71
+ }
72
+ else
73
+ entry.resolve(null);
74
+ }
75
+ else
76
+ entry.reject(new Error(`Validation task request ${result.data.error}`));
77
+ });
78
+ async function send(id, message) {
79
+ if (closed || !child.connected)
80
+ throw new Error("Validation task worker is closed");
81
+ if (pending.size >= 32)
82
+ throw new Error("Too many pending validation task requests");
83
+ return new Promise((resolve, reject) => {
84
+ pending.set(id, { resolve, reject });
85
+ child.send(message, (error) => {
86
+ if (error) {
87
+ pending.delete(id);
88
+ reject(new Error("Validation task request could not be delivered"));
89
+ }
90
+ });
91
+ });
92
+ }
93
+ const startupTimer = setTimeout(() => {
94
+ fail();
95
+ child.kill("SIGKILL");
96
+ }, 10000);
97
+ try {
98
+ await send(0, { options });
99
+ }
100
+ catch (error) {
101
+ if (child.connected)
102
+ child.disconnect();
103
+ await exited;
104
+ throw error;
105
+ }
106
+ finally {
107
+ clearTimeout(startupTimer);
108
+ }
109
+ async function request(method, taskId) {
110
+ if (closing)
111
+ throw new Error("Validation task worker is closing");
112
+ const id = ++sequence;
113
+ const message = validationTaskRequestSchema.parse({
114
+ id,
115
+ method,
116
+ ...(taskId !== undefined ? { taskId } : {}),
117
+ });
118
+ const result = await send(id, message);
119
+ if (!result)
120
+ throw new Error("Validation task response is missing");
121
+ return result;
122
+ }
123
+ return {
124
+ start: () => request("start"),
125
+ get: (taskId) => request("get", taskId),
126
+ cancel: (taskId) => request("cancel", taskId),
127
+ close: () => {
128
+ closing ??= (async () => {
129
+ try {
130
+ if (!closed && child.connected) {
131
+ const id = ++sequence;
132
+ await send(id, { id, method: "close" });
133
+ }
134
+ }
135
+ finally {
136
+ if (child.connected)
137
+ child.disconnect();
138
+ await exited;
139
+ }
140
+ })();
141
+ return closing;
142
+ },
143
+ };
144
+ }
@@ -0,0 +1,2 @@
1
+ import type { Check, CheckResult, ProcessResult } from "./types.js";
2
+ export declare function vitestEvidence(check: Check, processes: ProcessResult[], root: string | undefined): Pick<CheckResult, "status" | "reason" | "tests">;
@@ -0,0 +1,112 @@
1
+ import path from "node:path";
2
+ import { z } from "zod";
3
+ const count = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
4
+ const schema = z.object({
5
+ success: z.boolean(),
6
+ numTotalTests: count,
7
+ numPassedTests: count,
8
+ numFailedTests: count,
9
+ numPendingTests: count,
10
+ numTodoTests: count,
11
+ numTotalTestSuites: count,
12
+ numPassedTestSuites: count,
13
+ numFailedTestSuites: count,
14
+ numPendingTestSuites: count,
15
+ testResults: z.array(z.object({
16
+ name: z.string(),
17
+ status: z.enum(["passed", "failed"]),
18
+ assertionResults: z.array(z.object({
19
+ status: z.enum([
20
+ "passed",
21
+ "failed",
22
+ "skipped",
23
+ "pending",
24
+ "todo",
25
+ "disabled",
26
+ ]),
27
+ fullName: z.string(),
28
+ })),
29
+ })),
30
+ });
31
+ export function vitestEvidence(check, processes, root) {
32
+ const incomplete = {
33
+ status: "inconclusive",
34
+ reason: "Vitest evidence is incomplete, inconsistent, or does not account for every planned test file.",
35
+ };
36
+ if (!root || processes.length !== 1 || !check.scope.length)
37
+ return incomplete;
38
+ const process = processes[0];
39
+ if (process.exitCode !== 0 && process.exitCode !== 1)
40
+ return {
41
+ status: "error",
42
+ reason: "Vitest could not start or complete normally; inspect the runtime and configuration.",
43
+ };
44
+ let report;
45
+ try {
46
+ report = schema.parse(JSON.parse(process.stdout));
47
+ }
48
+ catch {
49
+ return incomplete;
50
+ }
51
+ const expected = new Set(check.scope.map((file) => path.resolve(root, check.project, file)));
52
+ const seen = new Set();
53
+ const tests = { total: 0, passed: 0, failed: 0, skipped: 0 };
54
+ let pending = 0;
55
+ let todo = 0;
56
+ let failedFiles = false;
57
+ for (const file of report.testResults) {
58
+ if (!expected.has(file.name) || seen.has(file.name))
59
+ return incomplete;
60
+ seen.add(file.name);
61
+ failedFiles ||= file.status === "failed";
62
+ for (const assertion of file.assertionResults) {
63
+ if (assertion.status === "pending")
64
+ return incomplete;
65
+ tests.total++;
66
+ if (assertion.status === "passed")
67
+ tests.passed++;
68
+ else if (assertion.status === "failed")
69
+ tests.failed++;
70
+ else {
71
+ tests.skipped++;
72
+ if (assertion.status === "todo")
73
+ todo++;
74
+ else
75
+ pending++;
76
+ }
77
+ }
78
+ }
79
+ if (seen.size !== expected.size ||
80
+ tests.total !== report.numTotalTests ||
81
+ tests.passed !== report.numPassedTests ||
82
+ tests.failed !== report.numFailedTests ||
83
+ pending !== report.numPendingTests ||
84
+ todo !== report.numTodoTests ||
85
+ report.numTotalTestSuites !==
86
+ report.numPassedTestSuites +
87
+ report.numFailedTestSuites +
88
+ report.numPendingTestSuites ||
89
+ report.numPendingTestSuites > 0)
90
+ return incomplete;
91
+ if (tests.failed ||
92
+ failedFiles ||
93
+ report.numFailedTestSuites ||
94
+ !report.success ||
95
+ process.exitCode !== 0)
96
+ return {
97
+ status: "failed",
98
+ reason: "Vitest reported a test, suite, or execution failure.",
99
+ tests,
100
+ };
101
+ if (!tests.passed)
102
+ return {
103
+ ...incomplete,
104
+ reason: "No passing, non-skipped Vitest assertions were observed.",
105
+ tests,
106
+ };
107
+ return {
108
+ status: "passed",
109
+ reason: "Vitest accounted for every planned file and reported passing non-skipped assertions.",
110
+ tests,
111
+ };
112
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import path from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ import { withinRoot } from "./inventory.js";
4
+ async function main() {
5
+ const [entry, root, ...files] = process.argv.slice(2);
6
+ if (!entry || !root || !files.length)
7
+ throw new Error("Invalid Vitest runner arguments");
8
+ const tool = await withinRoot(root, path.relative(root, entry));
9
+ const { startVitest, JsonReporter, VitestPackageInstaller } = (await import(pathToFileURL(tool).href));
10
+ class InstalledOnly extends VitestPackageInstaller {
11
+ async ensureInstalled(dependency, cwd) {
12
+ if (!this.isPackageExists(dependency, { paths: [cwd] }))
13
+ throw new Error(`Install required Vitest dependency locally: ${dependency}`);
14
+ return true;
15
+ }
16
+ }
17
+ const filters = [];
18
+ for (const file of files)
19
+ filters.push(await withinRoot(root, path.relative(root, path.resolve(file))));
20
+ const ctx = await startVitest(filters, {
21
+ root: process.cwd(),
22
+ run: true,
23
+ watch: false,
24
+ update: "none",
25
+ allowOnly: false,
26
+ passWithNoTests: false,
27
+ dangerouslyIgnoreUnhandledErrors: false,
28
+ onUnhandledError: () => true,
29
+ cache: false,
30
+ fsModuleCache: false,
31
+ reporters: [new JsonReporter({ stdout: true, outputFile: "" })],
32
+ }, undefined, { packageInstaller: new InstalledOnly() });
33
+ const errors = ctx.state.getUnhandledErrors();
34
+ if (errors.length) {
35
+ process.exitCode = 1;
36
+ for (const error of errors) {
37
+ const message = typeof error === "object" && error !== null && "message" in error
38
+ ? String(error.message)
39
+ : String(error);
40
+ process.stderr.write(`Unhandled Vitest error: ${message}\n`);
41
+ }
42
+ }
43
+ await ctx.close();
44
+ }
45
+ main().catch((error) => {
46
+ process.stderr.write(`${error instanceof Error ? error.message : "Vitest execution failed"}\n`);
47
+ process.exitCode = 2;
48
+ });
@@ -0,0 +1,2 @@
1
+ import type { Check, Inventory, Project } from "./types.js";
2
+ export declare function vitestCheck(source: Inventory, project: Project): Promise<Check>;
@@ -0,0 +1,36 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { localTool } from "./local-tool.js";
3
+ export async function vitestCheck(source, project) {
4
+ const files = project.files.filter((file) => /\.(?:test|spec)\.(?:[cm]?[jt]s|[jt]sx)$/.test(file));
5
+ const tool = await localTool(source.root, project.path, "vitest/dist/node.js");
6
+ const check = {
7
+ id: "javascript.vitest",
8
+ adapter: project.adapter,
9
+ project: project.path,
10
+ scope: files,
11
+ kind: "test",
12
+ parser: "vitest-json",
13
+ reason: "Run installed Vitest once and account for every planned test file; require passing non-skipped assertions and consistent native JSON evidence.",
14
+ commands: tool
15
+ ? [
16
+ {
17
+ executable: process.execPath,
18
+ args: [
19
+ fileURLToPath(new URL("./vitest-runner.js", import.meta.url)),
20
+ tool,
21
+ source.root,
22
+ ...files,
23
+ ],
24
+ cwd: project.path,
25
+ env: { CI: "1" },
26
+ },
27
+ ]
28
+ : [],
29
+ };
30
+ if (!files.length)
31
+ check.unavailableReason = "No .test or .spec JS/TS files were inventoried.";
32
+ else if (!tool)
33
+ check.unavailableReason =
34
+ "Vitest is not installed within the configured root.";
35
+ return check;
36
+ }