devcontour-harness 0.0.0-stage → 0.1.0-alpha.6

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 (390) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -2
  3. package/docs/architecture.md +473 -0
  4. package/docs/compatibility-versions.md +56 -0
  5. package/docs/compatibility.md +192 -0
  6. package/docs/connectors.md +323 -0
  7. package/docs/contracts.md +603 -0
  8. package/docs/integrations/hindsight.md +148 -0
  9. package/docs/quickstart.md +182 -0
  10. package/docs/release-notes/0.1.0-alpha.6.md +238 -0
  11. package/docs/review-probes.md +120 -0
  12. package/docs/review-protocol.md +251 -0
  13. package/docs/toolchains.md +167 -0
  14. package/docs/turbo-starter.md +269 -0
  15. package/docs/upgrade.md +202 -0
  16. package/examples/README.md +27 -0
  17. package/examples/external-connector/README.md +19 -0
  18. package/examples/external-connector/connector.mjs +55 -0
  19. package/examples/files-only/README.md +28 -0
  20. package/examples/files-only/context/norms/rules.md +4 -0
  21. package/examples/files-only/graph.json +23 -0
  22. package/examples/files-only/policy.json +30 -0
  23. package/examples/one-vendor/README.md +19 -0
  24. package/examples/one-vendor/policy.json +27 -0
  25. package/examples/single-task/README.md +18 -0
  26. package/examples/single-task/graph.json +27 -0
  27. package/examples/single-task/policy-same-vendor.json +55 -0
  28. package/examples/single-task/policy.json +52 -0
  29. package/examples/single-task/src/.gitkeep +0 -0
  30. package/examples/single-task/test/run.js +19 -0
  31. package/examples/toolchains/README.md +32 -0
  32. package/examples/toolchains/go/bad/label/label.go +9 -0
  33. package/examples/toolchains/go/good/label/label.go +9 -0
  34. package/examples/toolchains/go/policy.json +79 -0
  35. package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
  36. package/examples/toolchains/go/repo/_gitignore +1 -0
  37. package/examples/toolchains/go/repo/go.mod +5 -0
  38. package/examples/toolchains/go/repo/go.sum +2 -0
  39. package/examples/toolchains/go/repo/label/label.go +9 -0
  40. package/examples/toolchains/go/repo/label/label_test.go +27 -0
  41. package/examples/toolchains/go/repo/label/version.go +9 -0
  42. package/examples/toolchains/go/task.json +25 -0
  43. package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
  44. package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
  45. package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
  46. package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
  47. package/examples/toolchains/mixed-go/policy.json +126 -0
  48. package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
  49. package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
  50. package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
  51. package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
  52. package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
  53. package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
  54. package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
  55. package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
  56. package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
  57. package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
  58. package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
  59. package/examples/toolchains/mixed-go/task.json +25 -0
  60. package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
  61. package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
  62. package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
  63. package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
  64. package/examples/toolchains/mixed-python/policy.json +121 -0
  65. package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
  66. package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
  67. package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
  68. package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
  69. package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
  70. package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
  71. package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
  72. package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
  73. package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
  74. package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
  75. package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
  76. package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
  77. package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
  78. package/examples/toolchains/mixed-python/task.json +25 -0
  79. package/examples/toolchains/npm/bad/src/label.js +4 -0
  80. package/examples/toolchains/npm/good/src/label.js +4 -0
  81. package/examples/toolchains/npm/policy.json +82 -0
  82. package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
  83. package/examples/toolchains/npm/repo/_gitignore +4 -0
  84. package/examples/toolchains/npm/repo/package-lock.json +22 -0
  85. package/examples/toolchains/npm/repo/package.json +13 -0
  86. package/examples/toolchains/npm/repo/src/label.js +4 -0
  87. package/examples/toolchains/npm/repo/test/label.test.js +13 -0
  88. package/examples/toolchains/npm/task.json +25 -0
  89. package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
  90. package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
  91. package/examples/toolchains/pnpm/policy.json +85 -0
  92. package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
  93. package/examples/toolchains/pnpm/repo/_gitignore +4 -0
  94. package/examples/toolchains/pnpm/repo/package.json +10 -0
  95. package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
  96. package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
  97. package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
  98. package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
  99. package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
  100. package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
  101. package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
  102. package/examples/toolchains/pnpm/task.json +25 -0
  103. package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
  104. package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
  105. package/examples/toolchains/python/policy.json +80 -0
  106. package/examples/toolchains/python/repo/.python-version +1 -0
  107. package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
  108. package/examples/toolchains/python/repo/_gitignore +5 -0
  109. package/examples/toolchains/python/repo/pyproject.toml +19 -0
  110. package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
  111. package/examples/toolchains/python/repo/tests/test_label.py +13 -0
  112. package/examples/toolchains/python/repo/uv.lock +108 -0
  113. package/examples/toolchains/python/task.json +25 -0
  114. package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
  115. package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
  116. package/examples/toolchains/turbo/policy.json +110 -0
  117. package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
  118. package/examples/toolchains/turbo/repo/_gitignore +4 -0
  119. package/examples/toolchains/turbo/repo/package.json +13 -0
  120. package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
  121. package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
  122. package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
  123. package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
  124. package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
  125. package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
  126. package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
  127. package/examples/toolchains/turbo/repo/turbo.json +7 -0
  128. package/examples/toolchains/turbo/task.json +25 -0
  129. package/examples/turbo-starter/README.md +16 -0
  130. package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
  131. package/examples/turbo-starter/changes/issued-at.patch +130 -0
  132. package/examples/turbo-starter/cleanup.mjs +58 -0
  133. package/examples/turbo-starter/graph.json +32 -0
  134. package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
  135. package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
  136. package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
  137. package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
  138. package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
  139. package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
  140. package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
  141. package/examples/turbo-starter/harness/env/backend.env.template +7 -0
  142. package/examples/turbo-starter/harness/env/compose.env.template +6 -0
  143. package/examples/turbo-starter/policy.json +109 -0
  144. package/examples/turbo-starter/policy.lifecycle.json +114 -0
  145. package/examples/turbo-starter/setup.mjs +352 -0
  146. package/examples/two-vendors/policy.json +30 -0
  147. package/lib/agents/cli-adapter.d.ts +48 -0
  148. package/lib/agents/cli-adapter.js +386 -0
  149. package/lib/agents/inspect.d.ts +6 -0
  150. package/lib/agents/inspect.js +46 -0
  151. package/lib/agents/probe-server.d.ts +2 -0
  152. package/lib/agents/probe-server.js +13 -0
  153. package/lib/agents/review-probe.d.ts +295 -0
  154. package/lib/agents/review-probe.js +872 -0
  155. package/lib/agents/runtime-events.d.ts +11 -0
  156. package/lib/agents/runtime-events.js +21 -0
  157. package/lib/agents/schemas.d.ts +217 -0
  158. package/lib/agents/schemas.js +124 -0
  159. package/lib/agents/usage.d.ts +8 -0
  160. package/lib/agents/usage.js +83 -0
  161. package/lib/cli.d.ts +2 -0
  162. package/lib/cli.js +491 -0
  163. package/lib/connectors/files.d.ts +108 -0
  164. package/lib/connectors/files.js +133 -0
  165. package/lib/contracts/checks.d.ts +307 -0
  166. package/lib/contracts/checks.js +181 -0
  167. package/lib/contracts/cli.d.ts +3895 -0
  168. package/lib/contracts/cli.js +664 -0
  169. package/lib/contracts/context.d.ts +135 -0
  170. package/lib/contracts/context.js +129 -0
  171. package/lib/contracts/digest.d.ts +9 -0
  172. package/lib/contracts/digest.js +22 -0
  173. package/lib/contracts/errors.d.ts +81 -0
  174. package/lib/contracts/errors.js +70 -0
  175. package/lib/contracts/events.d.ts +827 -0
  176. package/lib/contracts/events.js +258 -0
  177. package/lib/contracts/execution.d.ts +3216 -0
  178. package/lib/contracts/execution.js +872 -0
  179. package/lib/contracts/failure.d.ts +67 -0
  180. package/lib/contracts/failure.js +127 -0
  181. package/lib/contracts/index.d.ts +18 -0
  182. package/lib/contracts/index.js +18 -0
  183. package/lib/contracts/policy.d.ts +1080 -0
  184. package/lib/contracts/policy.js +544 -0
  185. package/lib/contracts/ports.d.ts +417 -0
  186. package/lib/contracts/ports.js +1 -0
  187. package/lib/contracts/primitives.d.ts +63 -0
  188. package/lib/contracts/primitives.js +73 -0
  189. package/lib/contracts/profiles.d.ts +336 -0
  190. package/lib/contracts/profiles.js +109 -0
  191. package/lib/contracts/published.d.ts +3237 -0
  192. package/lib/contracts/published.js +34 -0
  193. package/lib/contracts/result.d.ts +1280 -0
  194. package/lib/contracts/result.js +311 -0
  195. package/lib/contracts/review.d.ts +441 -0
  196. package/lib/contracts/review.js +477 -0
  197. package/lib/contracts/toolchain.d.ts +96 -0
  198. package/lib/contracts/toolchain.js +89 -0
  199. package/lib/contracts/version.d.ts +17 -0
  200. package/lib/contracts/version.js +17 -0
  201. package/lib/contracts/work.d.ts +173 -0
  202. package/lib/contracts/work.js +178 -0
  203. package/lib/control/base-move.d.ts +44 -0
  204. package/lib/control/base-move.js +90 -0
  205. package/lib/control/doctor.d.ts +50 -0
  206. package/lib/control/doctor.js +113 -0
  207. package/lib/control/harness.d.ts +1125 -0
  208. package/lib/control/harness.js +741 -0
  209. package/lib/control/provenance.d.ts +17 -0
  210. package/lib/control/provenance.js +25 -0
  211. package/lib/control/recovery.d.ts +237 -0
  212. package/lib/control/recovery.js +236 -0
  213. package/lib/control/review.d.ts +62 -0
  214. package/lib/control/review.js +178 -0
  215. package/lib/control/workflow.d.ts +247 -0
  216. package/lib/control/workflow.js +259 -0
  217. package/lib/engine/budget.d.ts +345 -0
  218. package/lib/engine/budget.js +278 -0
  219. package/lib/engine/classify.d.ts +8 -0
  220. package/lib/engine/classify.js +32 -0
  221. package/lib/engine/engine.d.ts +1527 -0
  222. package/lib/engine/engine.js +2259 -0
  223. package/lib/engine/failure.d.ts +1 -0
  224. package/lib/engine/failure.js +3 -0
  225. package/lib/engine/joint-runner.d.ts +257 -0
  226. package/lib/engine/joint-runner.js +254 -0
  227. package/lib/engine/measured.d.ts +15 -0
  228. package/lib/engine/measured.js +82 -0
  229. package/lib/engine/prompt.d.ts +66 -0
  230. package/lib/engine/prompt.js +131 -0
  231. package/lib/engine/property-recovery.d.ts +50 -0
  232. package/lib/engine/property-recovery.js +171 -0
  233. package/lib/engine/repair.d.ts +33 -0
  234. package/lib/engine/repair.js +82 -0
  235. package/lib/engine/result.d.ts +9 -0
  236. package/lib/engine/result.js +218 -0
  237. package/lib/engine/reuse.d.ts +80 -0
  238. package/lib/engine/reuse.js +102 -0
  239. package/lib/engine/runner.d.ts +360 -0
  240. package/lib/engine/runner.js +1836 -0
  241. package/lib/engine/standalone.d.ts +6 -0
  242. package/lib/engine/standalone.js +48 -0
  243. package/lib/engine/usage.d.ts +87 -0
  244. package/lib/engine/usage.js +165 -0
  245. package/lib/environment/isolation.d.ts +110 -0
  246. package/lib/environment/isolation.js +238 -0
  247. package/lib/environment/lifecycle.d.ts +40 -0
  248. package/lib/environment/lifecycle.js +197 -0
  249. package/lib/environment/live-calls.d.ts +14 -0
  250. package/lib/environment/live-calls.js +73 -0
  251. package/lib/environment/os-tools.d.ts +16 -0
  252. package/lib/environment/os-tools.js +35 -0
  253. package/lib/environment/process.d.ts +32 -0
  254. package/lib/environment/process.js +369 -0
  255. package/lib/environment/redaction.d.ts +22 -0
  256. package/lib/environment/redaction.js +102 -0
  257. package/lib/environment/resources.d.ts +31 -0
  258. package/lib/environment/resources.js +120 -0
  259. package/lib/index.d.ts +65 -0
  260. package/lib/index.js +67 -0
  261. package/lib/integrations/connector/commands.d.ts +358 -0
  262. package/lib/integrations/connector/commands.js +428 -0
  263. package/lib/integrations/connector/config.d.ts +215 -0
  264. package/lib/integrations/connector/config.js +214 -0
  265. package/lib/integrations/connector/delivery.d.ts +107 -0
  266. package/lib/integrations/connector/delivery.js +591 -0
  267. package/lib/integrations/connector/fake.d.ts +291 -0
  268. package/lib/integrations/connector/fake.js +786 -0
  269. package/lib/integrations/connector/history.d.ts +124 -0
  270. package/lib/integrations/connector/history.js +497 -0
  271. package/lib/integrations/connector/index.d.ts +16 -0
  272. package/lib/integrations/connector/index.js +16 -0
  273. package/lib/integrations/connector/redact.d.ts +19 -0
  274. package/lib/integrations/connector/redact.js +91 -0
  275. package/lib/integrations/connector/registry.d.ts +15 -0
  276. package/lib/integrations/connector/registry.js +43 -0
  277. package/lib/integrations/connector/snapshot.d.ts +131 -0
  278. package/lib/integrations/connector/snapshot.js +422 -0
  279. package/lib/integrations/connector/source.d.ts +37 -0
  280. package/lib/integrations/connector/source.js +73 -0
  281. package/lib/integrations/connector/steps.d.ts +71 -0
  282. package/lib/integrations/connector/steps.js +188 -0
  283. package/lib/integrations/connector/store.d.ts +140 -0
  284. package/lib/integrations/connector/store.js +277 -0
  285. package/lib/integrations/connector/summary.d.ts +38 -0
  286. package/lib/integrations/connector/summary.js +59 -0
  287. package/lib/integrations/connector/testing-worker.d.ts +1 -0
  288. package/lib/integrations/connector/testing-worker.js +81 -0
  289. package/lib/integrations/connector/testing.d.ts +205 -0
  290. package/lib/integrations/connector/testing.js +1615 -0
  291. package/lib/integrations/connector/transport.d.ts +240 -0
  292. package/lib/integrations/connector/transport.js +28 -0
  293. package/lib/integrations/memory/context.d.ts +120 -0
  294. package/lib/integrations/memory/context.js +239 -0
  295. package/lib/integrations/memory/index.d.ts +8 -0
  296. package/lib/integrations/memory/index.js +8 -0
  297. package/lib/integrations/memory/provider.d.ts +79 -0
  298. package/lib/integrations/memory/provider.js +22 -0
  299. package/lib/integrations/memory/sink.d.ts +56 -0
  300. package/lib/integrations/memory/sink.js +116 -0
  301. package/lib/integrations/memory/testing.d.ts +44 -0
  302. package/lib/integrations/memory/testing.js +61 -0
  303. package/lib/integrations/relay-v1/index.d.ts +122 -0
  304. package/lib/integrations/relay-v1/index.js +860 -0
  305. package/lib/integrations/relay-v2/index.d.ts +145 -0
  306. package/lib/integrations/relay-v2/index.js +752 -0
  307. package/lib/integrations/relay-v2/process.d.ts +32 -0
  308. package/lib/integrations/relay-v2/process.js +112 -0
  309. package/lib/integrations/relay-v2/protocol.d.ts +172 -0
  310. package/lib/integrations/relay-v2/protocol.js +142 -0
  311. package/lib/package.d.ts +2 -0
  312. package/lib/package.js +3 -0
  313. package/lib/profiles/resolve.d.ts +190 -0
  314. package/lib/profiles/resolve.js +273 -0
  315. package/lib/storage/document.d.ts +1234 -0
  316. package/lib/storage/document.js +80 -0
  317. package/lib/storage/sqlite.d.ts +35 -0
  318. package/lib/storage/sqlite.js +260 -0
  319. package/lib/testing/index.d.ts +5 -0
  320. package/lib/testing/index.js +5 -0
  321. package/lib/testing/store-contract.d.ts +8 -0
  322. package/lib/testing/store-contract.js +167 -0
  323. package/lib/toolchains/index.d.ts +9 -0
  324. package/lib/toolchains/index.js +9 -0
  325. package/lib/toolchains/inspect.d.ts +105 -0
  326. package/lib/toolchains/inspect.js +831 -0
  327. package/lib/toolchains/manifests.d.ts +67 -0
  328. package/lib/toolchains/manifests.js +238 -0
  329. package/lib/toolchains/probe.d.ts +28 -0
  330. package/lib/toolchains/probe.js +54 -0
  331. package/lib/toolchains/recipes.d.ts +33 -0
  332. package/lib/toolchains/recipes.js +51 -0
  333. package/lib/validate.d.ts +36 -0
  334. package/lib/validate.js +175 -0
  335. package/lib/verification/acceptance.d.ts +284 -0
  336. package/lib/verification/acceptance.js +670 -0
  337. package/lib/verification/checks.d.ts +72 -0
  338. package/lib/verification/checks.js +190 -0
  339. package/lib/verification/confirm.d.ts +125 -0
  340. package/lib/verification/confirm.js +411 -0
  341. package/lib/verification/corpus.d.ts +1303 -0
  342. package/lib/verification/corpus.js +744 -0
  343. package/lib/verification/dependencies.d.ts +66 -0
  344. package/lib/verification/dependencies.js +144 -0
  345. package/lib/verification/gates.d.ts +160 -0
  346. package/lib/verification/gates.js +600 -0
  347. package/lib/verification/joint.d.ts +63 -0
  348. package/lib/verification/joint.js +121 -0
  349. package/lib/verification/proof.d.ts +54 -0
  350. package/lib/verification/proof.js +96 -0
  351. package/lib/verification/property.d.ts +86 -0
  352. package/lib/verification/property.js +214 -0
  353. package/lib/verification/requirements.d.ts +25 -0
  354. package/lib/verification/requirements.js +69 -0
  355. package/lib/verification/self-check.d.ts +29 -0
  356. package/lib/verification/self-check.js +99 -0
  357. package/lib/verification/spike.d.ts +79 -0
  358. package/lib/verification/spike.js +124 -0
  359. package/package.json +100 -4
  360. package/profiles/expo-mobile.json +15 -0
  361. package/profiles/go-api.json +15 -0
  362. package/profiles/go-gotestsum.json +21 -0
  363. package/profiles/mobile-maestro.json +29 -0
  364. package/profiles/nest-api.json +26 -0
  365. package/profiles/next-product.json +72 -0
  366. package/profiles/node-checks.json +77 -0
  367. package/profiles/npm-ci.json +22 -0
  368. package/profiles/pnpm-frozen.json +24 -0
  369. package/profiles/python-api.json +32 -0
  370. package/profiles/python-uv.json +26 -0
  371. package/profiles/react-native.json +50 -0
  372. package/profiles/react-vite-admin.json +71 -0
  373. package/schemas/context-snapshot.schema.json +231 -0
  374. package/schemas/contract-document.schema.json +385 -0
  375. package/schemas/execution-document.schema.json +3695 -0
  376. package/schemas/execution-policy.schema.json +2196 -0
  377. package/schemas/joint-verification.schema.json +617 -0
  378. package/schemas/result-envelope.schema.json +1652 -0
  379. package/schemas/review-record.schema.json +177 -0
  380. package/schemas/run-event.schema.json +2458 -0
  381. package/schemas/run-result.schema.json +1570 -0
  382. package/schemas/stack-profile.schema.json +535 -0
  383. package/schemas/work-graph.schema.json +381 -0
  384. package/schemas/work-order.schema.json +256 -0
  385. package/skills/harness/SKILL.md +64 -0
  386. package/templates/AGENTS.md +13 -0
  387. package/templates/controller-mode/AGENTS.controller.md +58 -0
  388. package/templates/controller-mode/README.md +44 -0
  389. package/templates/graph.json +22 -0
  390. package/templates/policy.json +28 -0
@@ -0,0 +1,66 @@
1
+ import type { ExecutionPolicy } from '../contracts/index.ts';
2
+ import type { AttemptState } from '../contracts/index.ts';
3
+ type Repo = ExecutionPolicy['repositories'][number];
4
+ export type DependencySnapshot = NonNullable<AttemptState['dependencies']>[number];
5
+ export type DependencyFreshness = NonNullable<AttemptState['dependencyFreshness']>[number];
6
+ /** Репозитории политики с разрешёнными путями checkout. */
7
+ export interface Repositories {
8
+ repo(id: string): Repo;
9
+ path(repo: Repo): string;
10
+ }
11
+ /** Зависимости компонентов в топологическом порядке, транзитивно. */
12
+ export declare function dependencyOrder(repos: Repositories, ids: string[]): string[];
13
+ export declare function artifactDigest(root: string, path: string): Promise<string>;
14
+ /**
15
+ * Снимок зависимостей компонента в топологическом порядке: рабочее дерево
16
+ * целевой ветки каждой зависимости, её `dependencyBuild` и digests
17
+ * `dependencyArtifacts`.
18
+ *
19
+ * `overrides` подставляет зависимость уже существующим деревом (проверка
20
+ * потребителя: компонент поручения — его интегрированный результат).
21
+ * Подстановка идёт до сборки: промежуточные зависимости собираются уже против
22
+ * неё. `predecessors` — принятые результаты поручений, от которых зависит
23
+ * работа: их SHA обязан быть в снимке. Каждое созданное здесь рабочее дерево
24
+ * принадлежит снимку с момента создания: при отказе на любом шаге созданные
25
+ * деревья убираются, и отказ очистки не скрывается.
26
+ */
27
+ export declare function snapshotDependencies(input: {
28
+ repos: Repositories;
29
+ repositoryId: string;
30
+ dir: string;
31
+ artifacts: string;
32
+ runId: string;
33
+ policy: ExecutionPolicy;
34
+ environment: NodeJS.ProcessEnv;
35
+ signal: AbortSignal;
36
+ predecessors?: {
37
+ repositoryId: string;
38
+ resultSha: string;
39
+ }[];
40
+ overrides?: Map<string, {
41
+ path: string;
42
+ sha: string;
43
+ }>;
44
+ }): Promise<{
45
+ repositoryId: string;
46
+ sha: string;
47
+ tree: string;
48
+ path: string;
49
+ artifacts: {
50
+ path: string;
51
+ digest: string;
52
+ }[];
53
+ }[]>;
54
+ /** Убирает рабочие деревья снимков; возвращает отказы, а не скрывает их. */
55
+ export declare function removeSnapshots(repos: Repositories, snapshots: DependencySnapshot[]): Promise<string[]>;
56
+ /** Закреплённый снимок не изменён: HEAD, отслеживаемые файлы и artifacts. */
57
+ export declare function assertDependencies(snapshots: DependencySnapshot[]): Promise<void>;
58
+ /**
59
+ * Свежесть снимка на момент окончания проверки: голова целевой ветки каждой
60
+ * зависимости и совпадает ли она со снимком. Параллельная работа законно
61
+ * двигает ветки зависимостей, поэтому сдвиг не отклоняет результат, а
62
+ * фиксируется в попытке и результате; сочетание версий проверяет совместная
63
+ * проверка по закреплённому манифесту.
64
+ */
65
+ export declare function dependencyFreshness(repos: Repositories, snapshots: Pick<DependencySnapshot, 'repositoryId' | 'sha'>[]): Promise<DependencyFreshness[]>;
66
+ export {};
@@ -0,0 +1,144 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
3
+ import { join, sep } from 'node:path';
4
+ import { git } from "../environment/process.js";
5
+ import { executionEnvironment, runSteps } from "../environment/lifecycle.js";
6
+ /** Зависимости компонентов в топологическом порядке, транзитивно. */
7
+ export function dependencyOrder(repos, ids) {
8
+ const ordered = [];
9
+ const active = new Set();
10
+ const visit = (id) => {
11
+ if (ordered.includes(id))
12
+ return;
13
+ if (active.has(id))
14
+ throw new Error('Цикл зависимостей компонентов');
15
+ active.add(id);
16
+ for (const parent of repos.repo(id).dependsOn)
17
+ visit(parent);
18
+ active.delete(id);
19
+ ordered.push(id);
20
+ };
21
+ ids.forEach(visit);
22
+ return ordered;
23
+ }
24
+ export async function artifactDigest(root, path) {
25
+ const full = await realpath(join(root, path));
26
+ if (!full.startsWith((await realpath(root)) + sep))
27
+ throw new Error('Artifact выходит из компонента');
28
+ return createHash('sha256')
29
+ .update(await readFile(full))
30
+ .digest('hex');
31
+ }
32
+ /**
33
+ * Снимок зависимостей компонента в топологическом порядке: рабочее дерево
34
+ * целевой ветки каждой зависимости, её `dependencyBuild` и digests
35
+ * `dependencyArtifacts`.
36
+ *
37
+ * `overrides` подставляет зависимость уже существующим деревом (проверка
38
+ * потребителя: компонент поручения — его интегрированный результат).
39
+ * Подстановка идёт до сборки: промежуточные зависимости собираются уже против
40
+ * неё. `predecessors` — принятые результаты поручений, от которых зависит
41
+ * работа: их SHA обязан быть в снимке. Каждое созданное здесь рабочее дерево
42
+ * принадлежит снимку с момента создания: при отказе на любом шаге созданные
43
+ * деревья убираются, и отказ очистки не скрывается.
44
+ */
45
+ export async function snapshotDependencies(input) {
46
+ const { repos, signal } = input;
47
+ const ids = dependencyOrder(repos, repos.repo(input.repositoryId).dependsOn);
48
+ const snapshots = [];
49
+ const created = [];
50
+ await mkdir(input.dir, { recursive: true });
51
+ try {
52
+ for (const id of ids) {
53
+ signal.throwIfAborted();
54
+ const repo = repos.repo(id);
55
+ const override = input.overrides?.get(id);
56
+ if (override) {
57
+ snapshots.push({
58
+ repositoryId: id,
59
+ sha: override.sha,
60
+ tree: await git(override.path, 'rev-parse', 'HEAD^{tree}'),
61
+ path: override.path,
62
+ artifacts: [],
63
+ });
64
+ continue;
65
+ }
66
+ const checkout = repos.path(repo);
67
+ const sha = await git(checkout, 'rev-parse', repo.targetRef);
68
+ for (const predecessor of (input.predecessors ?? []).filter((p) => p.repositoryId === id))
69
+ await git(checkout, 'merge-base', '--is-ancestor', predecessor.resultSha, sha).catch(() => {
70
+ throw new Error(`Принятый результат зависимости ${id} (${predecessor.resultSha}) отсутствует в ${repo.targetRef}`);
71
+ });
72
+ const path = join(input.dir, id);
73
+ await git(checkout, 'worktree', 'add', '--detach', path, sha);
74
+ const snapshot = {
75
+ repositoryId: id,
76
+ sha,
77
+ tree: await git(path, 'rev-parse', 'HEAD^{tree}'),
78
+ path,
79
+ artifacts: [],
80
+ };
81
+ created.push(snapshot);
82
+ snapshots.push(snapshot);
83
+ }
84
+ const paths = Object.fromEntries(snapshots.map((s) => [s.repositoryId, s.path]));
85
+ for (const snapshot of snapshots) {
86
+ const repo = repos.repo(snapshot.repositoryId);
87
+ const execution = executionEnvironment([input.policy.environment, repo.environment], {
88
+ DEVCONTOUR_RUN_ID: input.runId,
89
+ DEVCONTOUR_COMPONENTS_JSON: JSON.stringify(paths),
90
+ }, input.environment);
91
+ await runSteps(repo.dependencyBuild, snapshot.path, join(input.artifacts, 'dependency-build', repo.id), execution, signal);
92
+ for (const path of repo.dependencyArtifacts)
93
+ snapshot.artifacts.push({ path, digest: await artifactDigest(snapshot.path, path) });
94
+ }
95
+ await assertDependencies(snapshots);
96
+ await writeFile(join(input.dir, 'manifest.json'), JSON.stringify(snapshots, null, 2));
97
+ return snapshots;
98
+ }
99
+ catch (error) {
100
+ const failures = await removeSnapshots(repos, created);
101
+ if (failures.length)
102
+ throw new Error(`${error instanceof Error ? error.message : String(error)}; не удалось убрать снимки: ${failures.join('; ')}`, { cause: error });
103
+ throw error;
104
+ }
105
+ }
106
+ /** Убирает рабочие деревья снимков; возвращает отказы, а не скрывает их. */
107
+ export async function removeSnapshots(repos, snapshots) {
108
+ const failures = [];
109
+ for (const snapshot of snapshots)
110
+ await git(repos.path(repos.repo(snapshot.repositoryId)), 'worktree', 'remove', '--force', snapshot.path).catch((e) => failures.push(`${snapshot.repositoryId}: ${e instanceof Error ? e.message : String(e)}`));
111
+ return failures;
112
+ }
113
+ /** Закреплённый снимок не изменён: HEAD, отслеживаемые файлы и artifacts. */
114
+ export async function assertDependencies(snapshots) {
115
+ for (const snapshot of snapshots) {
116
+ if ((await git(snapshot.path, 'rev-parse', 'HEAD')) !== snapshot.sha ||
117
+ (await git(snapshot.path, 'status', '--porcelain', '--untracked-files=no')))
118
+ throw new Error('Изменён закреплённый dependency snapshot: ' + snapshot.repositoryId);
119
+ for (const artifact of snapshot.artifacts)
120
+ if ((await artifactDigest(snapshot.path, artifact.path)) !== artifact.digest)
121
+ throw new Error('Изменён artifact зависимости: ' + snapshot.repositoryId + '/' + artifact.path);
122
+ }
123
+ }
124
+ /**
125
+ * Свежесть снимка на момент окончания проверки: голова целевой ветки каждой
126
+ * зависимости и совпадает ли она со снимком. Параллельная работа законно
127
+ * двигает ветки зависимостей, поэтому сдвиг не отклоняет результат, а
128
+ * фиксируется в попытке и результате; сочетание версий проверяет совместная
129
+ * проверка по закреплённому манифесту.
130
+ */
131
+ export async function dependencyFreshness(repos, snapshots) {
132
+ const result = [];
133
+ for (const snapshot of snapshots) {
134
+ const repo = repos.repo(snapshot.repositoryId);
135
+ const head = await git(repos.path(repo), 'rev-parse', repo.targetRef);
136
+ result.push({
137
+ repositoryId: repo.id,
138
+ snapshot: snapshot.sha,
139
+ head,
140
+ fresh: head === snapshot.sha,
141
+ });
142
+ }
143
+ return result;
144
+ }
@@ -0,0 +1,160 @@
1
+ import { type EvidenceRecord, type ExecutionPolicy, type GatePolicy } from '../contracts/index.ts';
2
+ import { isolationSupport } from '../environment/isolation.ts';
3
+ import { type CheckManifest } from './property.ts';
4
+ /** Длинное имя testcase заменяется хешем, а не обрезается: обрезка дала бы ложные совпадения. */
5
+ export declare const TEST_ID_LIMIT = 1000;
6
+ export declare function portableTest<T extends {
7
+ id: string;
8
+ opaque?: true;
9
+ }>(test: T): T;
10
+ /**
11
+ * Сводка JUnit-отчёта.
12
+ *
13
+ * `redact` применяется к именам и сообщениям до любой обрезки: обрезанный
14
+ * секрет redactor уже не узнаёт, и в сводке оставался бы его префикс. Имя
15
+ * testcase тоже проходит redact — оно попадает в состояние, журнал и API.
16
+ * Изменённое так имя не совпадёт с названным критерием, и подтверждения
17
+ * не будет: для секрета в имени теста это правильный исход.
18
+ */
19
+ /**
20
+ * Значение атрибута XML: парсер работает без обработки сущностей (DOCTYPE
21
+ * запрещён, внешних сущностей нет), поэтому предопределённые сущности и
22
+ * числовые ссылки раскрываются здесь — один раз, без рекурсии. Иначе testcase
23
+ * `a["b"]` сохранялся как `a[&quot;b&quot;]` и не совпадал с названным
24
+ * testId требования или критерия. Репортер JUnit Node.js экранирует `"`
25
+ * дважды (`&amp;quot;`); оставшийся после раскрытия `&quot;` поэтому тоже
26
+ * читается как `"`.
27
+ */
28
+ export declare function xmlAttribute(value: string): string;
29
+ export declare function junitSummary(xml: string, redact?: (value: string) => string): {
30
+ tests: number;
31
+ failures: number;
32
+ skipped: number;
33
+ /** Имена провалившихся testcases: по ним различаются разные провалы. */
34
+ failed: string[];
35
+ /** Те же testcases с первыми словами сообщения о провале. */
36
+ failedDetails: string[];
37
+ /** Что именно выполнилось и с каким исходом. */
38
+ cases: NonNullable<EvidenceRecord['tests']>;
39
+ /** Список обрезан: отсутствие теста по нему доказать нельзя. */
40
+ truncated: boolean;
41
+ };
42
+ /**
43
+ * Песочница отказала до запуска команды: процесс завершился неуспешно, а
44
+ * метка старта, которую обёртка создаёт перед exec, не появилась. Текст
45
+ * stderr признаком не служит — его может напечатать и сама проверка.
46
+ */
47
+ export declare function sandboxNotStarted(result: {
48
+ code: number;
49
+ }, started: string | undefined): boolean;
50
+ /**
51
+ * Путь отчёта внутри корня, созданный без выхода за него.
52
+ *
53
+ * Раньше каталоги создавались рекурсивно, а граница проверялась потом:
54
+ * symlink внутри worktree успевал увести создание каталога наружу до отказа.
55
+ * Теперь путь проходится от корня по одному компоненту: существующий symlink
56
+ * или не-каталог — отказ до любой записи, недостающий каталог создаётся
57
+ * только внутри уже проверенного родителя.
58
+ */
59
+ export declare function prepareReportPath(root: string, path: string, escape: string): Promise<string>;
60
+ /**
61
+ * Команда проверки — задачи или общей приёмки workspace — в песочнице ОС.
62
+ *
63
+ * Прежде проверка шла обычным процессом хоста и могла читать базу контура и
64
+ * соседние файлы, писать вне worktree и ходить в сеть: сверка HEAD и
65
+ * отслеживаемых файлов после неё этого не видит. Без механизма песочницы
66
+ * проверка не запускается — снять изоляцию можно только явным
67
+ * isolation.mode: none. Запись — в `write` и собственный scratch (TMPDIR).
68
+ */
69
+ export declare function runCheck(h: {
70
+ config: Pick<ExecutionPolicy, 'isolation'>;
71
+ }, options: {
72
+ argv: string[];
73
+ cwd: string;
74
+ env: NodeJS.ProcessEnv;
75
+ redact?: (value: string) => string;
76
+ timeoutMs?: number;
77
+ signal: AbortSignal;
78
+ write: string[];
79
+ readable: string[];
80
+ controller: string[];
81
+ settingsDir: string;
82
+ }): Promise<{
83
+ attempts: number;
84
+ code: number;
85
+ stdout: string;
86
+ stderr: string;
87
+ timedOut: boolean;
88
+ diagnostics: import("../contracts/execution.ts").RuntimeDiagnostics;
89
+ }>;
90
+ /** Проверка механизма песочницы; тест подменяет её, чтобы проверить отказ. */
91
+ export declare const isolationBackend: {
92
+ check: typeof isolationSupport;
93
+ };
94
+ /**
95
+ * Хосты, в сети к которым проверке, по всей видимости, отказала песочница.
96
+ *
97
+ * Прокси песочницы отвечает на запрещённый домен `403`, но клиенты вроде
98
+ * pnpm показывают только «Forbidden - 403» и URL. На пилоте такой отказ
99
+ * записывался провалом проверки, и контур переписывал код, который был ни
100
+ * при чём. Признак узкий: в выводе есть отказ (403, Forbidden, прокси или
101
+ * тело ответа песочницы) и URL хоста, которого нет в `isolation.domains`.
102
+ */
103
+ export declare function sandboxBlockedHosts(output: string, allowed: string[]): string[];
104
+ /**
105
+ * Окружение свежести test gate: те же переменные у gate движка и у gate,
106
+ * запущенного проверкой reviewer, — иначе probe мог бы прочитать cache там,
107
+ * где gate исполняет тесты заново.
108
+ */
109
+ export declare function freshnessEnv(kind: GatePolicy['kind'], env: NodeJS.ProcessEnv): Record<string, string>;
110
+ /** Что нужно для запуска gate попытки. */
111
+ export interface GateRun {
112
+ policy: Pick<ExecutionPolicy, 'isolation'>;
113
+ /** Запись evidence под fencing попытки. */
114
+ record: (evidence: Omit<EvidenceRecord, 'id' | 'runId' | 'createdAt'>) => EvidenceRecord;
115
+ cwd: string;
116
+ sha: string;
117
+ phase: EvidenceRecord['phase'];
118
+ gate: GatePolicy;
119
+ artifactDir: string;
120
+ signal: AbortSignal;
121
+ /** Окружение фазы: переменные и маска секретов. */
122
+ execution: {
123
+ env: NodeJS.ProcessEnv;
124
+ redact: (value: string) => string;
125
+ };
126
+ /** Закрытое проверке (состояние controller, чужие checkout) и открытое внутри него. */
127
+ boundary: {
128
+ hidden: string[];
129
+ readable: string[];
130
+ };
131
+ /** Проверка потребителя: evidence несёт его компонент и не закрывает собственные gates. */
132
+ consumer?: string;
133
+ /**
134
+ * Генеративный gate (`gate.property`): попытка, от которой seed, и
135
+ * ожидаемая проверка поручения. Без `expected` — прежний уровень (отчёт
136
+ * сверяется сам с собой и с JUnit).
137
+ */
138
+ property?: {
139
+ runId: string;
140
+ expected?: CheckManifest;
141
+ /** Закреплённый корпус попытки: материализуется вне worktree только для чтения. */
142
+ corpus?: {
143
+ digest: string;
144
+ content: string;
145
+ };
146
+ /** Контракты поручения по digest и их закреплённые файлы. */
147
+ contracts: Record<string, string>;
148
+ artifacts: {
149
+ path: string;
150
+ blob: string;
151
+ }[];
152
+ };
153
+ }
154
+ /**
155
+ * Gate попытки. `test` принимается только по свежему (прежний отчёт удалён до
156
+ * запуска) непустому JUnit без failures, errors и skips на этом SHA; exit 0
157
+ * без отчёта — отказ. Gate, изменивший HEAD или отслеживаемые файлы, не
158
+ * проходит. Evidence записывается при любом исходе; провал — `TaskFailure`.
159
+ */
160
+ export declare function runGate(run: GateRun): Promise<EvidenceRecord>;