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,259 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { executionDigest, HarnessError, WORKSPACE_OWNER, digestOf, } from "../contracts/index.js";
3
+ /** Стадии работы над графом: 0 — ревью и согласование плана, 1 — исполнение, 2 — завершено. */
4
+ export const GRAPH_STAGES = 2;
5
+ const iso = (ms) => new Date(ms).toISOString();
6
+ export class WorkflowQueue {
7
+ store;
8
+ policy;
9
+ now;
10
+ subjects;
11
+ constructor(store, policy, now = Date.now, subjects) {
12
+ this.store = store;
13
+ this.policy = policy;
14
+ this.now = now;
15
+ this.subjects = subjects;
16
+ }
17
+ /** Вход задания. Без предметов хоста — граф: его digest, политика и режим согласования. */
18
+ bound(kind, id, view) {
19
+ if (this.subjects)
20
+ return this.subjects.input(kind, id, view);
21
+ if (kind !== 'graph')
22
+ throw new HarnessError('INVALID_INPUT', 'Неизвестный вид задания: ' + kind);
23
+ const graph = view.graph(id);
24
+ if (!graph)
25
+ return undefined;
26
+ return {
27
+ digest: digestOf({
28
+ kind,
29
+ id,
30
+ graph: graph.digest,
31
+ policy: executionDigest(this.policy),
32
+ approvalMode: this.policy.approvalMode,
33
+ }),
34
+ };
35
+ }
36
+ /** Digest входа задания; нет предмета — `undefined`. */
37
+ input(kind, id, view) {
38
+ return this.bound(kind, id, view)?.digest;
39
+ }
40
+ current(job, view) {
41
+ try {
42
+ const bound = this.bound(job.kind, job.id, view);
43
+ return bound?.digest === job.inputDigest && bound.owner === job.owner;
44
+ }
45
+ catch (error) {
46
+ // Удалённый или ставший недопустимым предмет — устаревшее задание, а не
47
+ // повод блокировать все следующие.
48
+ if (error instanceof HarnessError)
49
+ return false;
50
+ throw error;
51
+ }
52
+ }
53
+ static owner(owner) {
54
+ return owner ?? WORKSPACE_OWNER;
55
+ }
56
+ /** Задания владельца (по умолчанию — общие). */
57
+ list(owner) {
58
+ return this.store.read((v) => v.locals('workflow-jobs', WorkflowQueue.owner(owner)).map((r) => r.value));
59
+ }
60
+ get(key, owner) {
61
+ const job = this.store.read((v) => v.local('workflow-jobs', WorkflowQueue.owner(owner), key));
62
+ if (!job)
63
+ throw new HarnessError('NOT_FOUND', 'Задание не найдено: ' + key);
64
+ return job;
65
+ }
66
+ /** Безопасное представление задания: без токена и срока владения. */
67
+ view(key, owner) {
68
+ const job = this.get(key, owner);
69
+ return {
70
+ key: job.key,
71
+ kind: job.kind,
72
+ id: job.id,
73
+ stage: job.stage,
74
+ status: job.status,
75
+ attempts: job.attempts,
76
+ repairs: job.repairs ?? 0,
77
+ repairBudget: this.policy.repairBudget,
78
+ ...(job.error ? { error: job.error } : {}),
79
+ history: job.history.slice(-20),
80
+ };
81
+ }
82
+ /** Поставить задание; повтор того же входа возвращает прежнее, другой автор — отказ. */
83
+ start(input) {
84
+ return this.store.transact('workflow.updated', (tx) => {
85
+ const bound = this.bound(input.kind, input.id, tx);
86
+ if (!bound)
87
+ throw new HarnessError('NOT_FOUND', 'Предмет задания не найден: ' + input.id);
88
+ const digest = bound.digest;
89
+ const key = digestOf({ kind: input.kind, id: input.id, input: digest });
90
+ const old = tx.local('workflow-jobs', WorkflowQueue.owner(bound.owner), key);
91
+ if (old) {
92
+ if (old.authorRuntime !== input.authorRuntime)
93
+ throw new HarnessError('INVALID_INPUT', 'Runtime автора уже закреплён за этим входом: ' + old.authorRuntime);
94
+ return old;
95
+ }
96
+ const job = {
97
+ kind: input.kind,
98
+ id: input.id,
99
+ authorRuntime: input.authorRuntime,
100
+ maxAttempts: input.maxAttempts ?? 3,
101
+ key,
102
+ ...(bound.owner ? { owner: bound.owner } : {}),
103
+ inputDigest: digest,
104
+ stage: 0,
105
+ attempts: 0,
106
+ status: 'queued',
107
+ startedAt: iso(this.now()),
108
+ history: [],
109
+ };
110
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(job.owner), key, job);
111
+ return job;
112
+ });
113
+ }
114
+ /**
115
+ * Взять стадию задания. Пока применяется политика, стадии не начинаются:
116
+ * они читали бы прежний контекст. Изменившийся вход — `stale`; исчерпанные
117
+ * попытки стадии — `failed`. Чужое действующее владение не перехватывается.
118
+ */
119
+ claim(key, owner) {
120
+ return this.store.transact('workflow.updated', (tx) => {
121
+ // Пока политика применяется — и до паузы операции, по самому запросу, — стадии не начинаются.
122
+ const control = tx.control();
123
+ if (control.pauseReason === 'reconfigure' ||
124
+ (control.reconfigure && !control.reconfigure.appliedAt))
125
+ return undefined;
126
+ const job = tx.local('workflow-jobs', WorkflowQueue.owner(owner), key);
127
+ if (!job)
128
+ throw new HarnessError('NOT_FOUND', 'Задание не найдено: ' + key);
129
+ if (!['queued', 'running'].includes(job.status) ||
130
+ (job.status === 'running' && job.leaseUntil > this.now()))
131
+ return undefined;
132
+ const next = { ...job, history: [...job.history] };
133
+ if (!this.current(job, tx)) {
134
+ next.status = 'stale';
135
+ next.error = 'Вход задания изменился или удалён';
136
+ delete next.token;
137
+ delete next.leaseUntil;
138
+ }
139
+ else if (job.attempts >= job.maxAttempts) {
140
+ next.status = 'failed';
141
+ next.error = 'Исчерпаны попытки стадии';
142
+ delete next.token;
143
+ delete next.leaseUntil;
144
+ }
145
+ else {
146
+ next.status = 'running';
147
+ next.token = randomUUID();
148
+ next.leaseUntil = this.now() + this.policy.leaseMs;
149
+ next.attempts = job.attempts + 1;
150
+ }
151
+ next.history.push({ at: iso(this.now()), stage: job.stage, event: next.status });
152
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(owner), key, next);
153
+ return next.status === 'running' ? next : undefined;
154
+ });
155
+ }
156
+ /** Владение заданием и актуальность входа; иначе — отказ. */
157
+ guard(job, view) {
158
+ const check = (v) => {
159
+ const current = v.local('workflow-jobs', WorkflowQueue.owner(job.owner), job.key);
160
+ if (current?.status !== 'running' ||
161
+ current.token !== job.token ||
162
+ current.leaseUntil <= this.now())
163
+ throw new HarnessError('LEASE_STALE', 'Владение заданием утрачено');
164
+ if (!this.current(job, v))
165
+ throw new HarnessError('APPROVAL_STALE', 'Вход задания изменился');
166
+ return current;
167
+ };
168
+ return view ? check(view) : this.store.read(check);
169
+ }
170
+ heartbeat(job) {
171
+ this.store.transact('workflow.updated', (tx) => {
172
+ const current = this.guard(job, tx);
173
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(job.owner), job.key, {
174
+ ...current,
175
+ leaseUntil: this.now() + this.policy.leaseMs,
176
+ });
177
+ });
178
+ }
179
+ /**
180
+ * Завершить стадию. `wait` — стадия ждёт доменного состояния (повтор,
181
+ * пауза) и внешнего действия не выполняла: попытка стадии возвращается, а
182
+ * её запись о захвате снимается. Именно запись о захвате: последним в
183
+ * истории может стоять решение о восстановлении, и оно должно остаться.
184
+ */
185
+ finish(job, wait = false, stages = GRAPH_STAGES) {
186
+ return this.store.transact('workflow.updated', (tx) => {
187
+ const current = this.guard(job, tx);
188
+ const next = { ...current, history: [...current.history] };
189
+ if (!wait) {
190
+ next.stage = current.stage + 1;
191
+ next.attempts = 0;
192
+ }
193
+ else {
194
+ next.attempts = current.attempts - 1;
195
+ const claimed = next.history.map((h) => h.event).lastIndexOf('running');
196
+ if (claimed >= 0)
197
+ next.history.splice(claimed, 1);
198
+ }
199
+ next.status = next.stage >= stages ? 'completed' : 'queued';
200
+ if (next.status === 'completed')
201
+ next.finishedAt = iso(this.now());
202
+ delete next.token;
203
+ delete next.leaseUntil;
204
+ delete next.error;
205
+ if (!wait)
206
+ next.history.push({ at: iso(this.now()), stage: job.stage, event: 'completed' });
207
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(job.owner), job.key, next);
208
+ return next;
209
+ });
210
+ }
211
+ /** Отказ стадии: прерванная — снова в очереди, изменившийся вход — `stale`, иначе `failed`. */
212
+ fail(job, message, interrupted = false) {
213
+ this.store.transact('workflow.updated', (tx) => {
214
+ const current = tx.local('workflow-jobs', WorkflowQueue.owner(job.owner), job.key);
215
+ if (!current || current.token !== job.token || current.status !== 'running')
216
+ return;
217
+ const next = {
218
+ ...current,
219
+ status: !this.current(job, tx) ? 'stale' : interrupted ? 'queued' : 'failed',
220
+ error: message.slice(0, 1000),
221
+ };
222
+ delete next.token;
223
+ delete next.leaseUntil;
224
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(job.owner), job.key, next);
225
+ });
226
+ }
227
+ /**
228
+ * Записать восстановление и выполнить его одной транзакцией. Счётчик и само
229
+ * действие неразделимы: прерывание между ними дало бы либо повтор без учёта
230
+ * (цикл крутился бы мимо бюджета), либо учёт без повтора.
231
+ */
232
+ repair(job, event, apply) {
233
+ return this.store.transact('task.retry', (tx) => {
234
+ const current = this.guard(job, tx);
235
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(job.owner), job.key, {
236
+ ...current,
237
+ repairs: (current.repairs ?? 0) + 1,
238
+ history: [...current.history, { at: iso(this.now()), stage: job.stage, event }],
239
+ });
240
+ return apply();
241
+ });
242
+ }
243
+ /** Повтор остановленного задания — решение человека, в пределах попыток стадии. */
244
+ retry(key, owner) {
245
+ return this.store.transact('workflow.updated', (tx) => {
246
+ const job = tx.local('workflow-jobs', WorkflowQueue.owner(owner), key);
247
+ if (!job)
248
+ throw new HarnessError('NOT_FOUND', 'Задание не найдено: ' + key);
249
+ if (job.status !== 'failed' || job.attempts >= job.maxAttempts)
250
+ throw new HarnessError('NOT_READY', 'Повтор задания недоступен; проверьте статус и попытки');
251
+ if (!this.current(job, tx))
252
+ throw new HarnessError('APPROVAL_STALE', 'Вход задания изменился: нужно новое задание');
253
+ const next = { ...job, status: 'queued' };
254
+ delete next.error;
255
+ tx.putLocal('workflow-jobs', WorkflowQueue.owner(owner), key, next);
256
+ return next;
257
+ });
258
+ }
259
+ }
@@ -0,0 +1,345 @@
1
+ import type { BudgetScopes, CallRecord, ExecutionPolicy, ExecutionView } from '../contracts/index.ts';
2
+ import { usageTotals } from './usage.ts';
3
+ /**
4
+ * Бюджеты расходов и времени вызовов моделей.
5
+ *
6
+ * Расход считается по сохранённым записям вызовов, а не по счётчикам попыток:
7
+ * `retry --reset`, возврат попытки после отказа окружения, переход этапа
8
+ * очереди и перезапуск процесса его не уменьшают. Ошибочные, идущие и
9
+ * прерванные вызовы входят в расход. Неизвестная стоимость делает денежный
10
+ * бюджет неопределённым; что тогда делать, задаёт `budgets.onUnknown`.
11
+ *
12
+ * Учёт локален: записи вызовов не переносятся между клонами, поэтому бюджет
13
+ * считает вызовы этой установки.
14
+ */
15
+ export type BudgetScope = {
16
+ kind: 'work' | 'group' | 'total';
17
+ id?: string;
18
+ };
19
+ /** Правила и области бюджетов: политика и группы хоста. */
20
+ export interface BudgetContext {
21
+ policy: ExecutionPolicy;
22
+ scopes: BudgetScopes;
23
+ }
24
+ /**
25
+ * Прежняя запись вызова о группе: вида предмета нет, но при вызове закреплена
26
+ * группа без поручения и без попытки. Вызов о поручении закреплял его
27
+ * `workId`, поэтому совпадение ID предмета с поручением такую запись не
28
+ * делает расходом одного поручения — она остаётся расходом группы.
29
+ */
30
+ export declare function legacyGroupCall(r: {
31
+ runId?: string;
32
+ subjectKind?: CallRecord['subjectKind'];
33
+ groupId?: string;
34
+ workId?: string;
35
+ }): boolean;
36
+ /**
37
+ * Записи вызовов области. Поручению принадлежат его попытки, вызовы о нём и
38
+ * вызовы о его группе целиком (ревью плана): правила долевой атрибуции нет,
39
+ * и вызов о группе не должен считаться нулевым для поручения. Группе — вызовы,
40
+ * закреплённые за ней при вызове: перенос поручения в другую группу расход не
41
+ * переносит.
42
+ */
43
+ export declare function scopeRecords(c: BudgetContext, view: ExecutionView, records: CallRecord[], scope: BudgetScope): {
44
+ id: string;
45
+ stage: string;
46
+ runtime: string;
47
+ model: string | null;
48
+ runtimeVersion: string | null;
49
+ startedAt: string;
50
+ outcome: "error" | "active" | "returned" | "abandoned";
51
+ promptBytes: number;
52
+ promptDigest: string;
53
+ usage: {
54
+ inputTokens: number | null;
55
+ outputTokens: number | null;
56
+ cacheReadTokens: number | null;
57
+ cacheWriteTokens: number | null;
58
+ reportedUsd: number | null;
59
+ complete: boolean;
60
+ source: "fixture" | "unavailable" | "codex-turn-events" | "claude-result";
61
+ };
62
+ costUsd: number | null;
63
+ costSource: "unknown" | "provider-reported" | "tariff-estimate";
64
+ repositoryId?: string | undefined;
65
+ runId?: string | undefined;
66
+ subjectId?: string | undefined;
67
+ subjectKind?: "work" | "group" | "other" | undefined;
68
+ finishedAt?: string | undefined;
69
+ process?: {
70
+ id: string;
71
+ pid: number;
72
+ startedAt?: number | undefined;
73
+ } | undefined;
74
+ abandonedAt?: string | undefined;
75
+ durationMs?: number | undefined;
76
+ elapsedMs?: number | undefined;
77
+ startedHr?: string | undefined;
78
+ durationUnknown?: true | undefined;
79
+ bootId?: string | undefined;
80
+ workId?: string | undefined;
81
+ groupId?: string | undefined;
82
+ workIds?: string[] | undefined;
83
+ price?: {
84
+ runtime: "codex" | "claude";
85
+ model: string;
86
+ effectiveAt: string;
87
+ input: number;
88
+ output: number;
89
+ cacheRead: number;
90
+ cacheWrite: number;
91
+ } | undefined;
92
+ diagnostics?: {
93
+ startedAt: string;
94
+ finishedAt: string;
95
+ lastOutputAt: string | null;
96
+ exitCode: number | null;
97
+ signal: string | null;
98
+ timedOut: boolean;
99
+ aborted: boolean;
100
+ stdoutTail: string;
101
+ stderrTail: string;
102
+ processTree?: {
103
+ available: boolean;
104
+ processes: {
105
+ pid: number;
106
+ parentPid: number;
107
+ groupPid: number;
108
+ name: string;
109
+ }[];
110
+ reason?: string | undefined;
111
+ } | undefined;
112
+ } | undefined;
113
+ }[];
114
+ export type BudgetStatus = {
115
+ scope: BudgetScope;
116
+ limit: {
117
+ usd?: number;
118
+ timeMs?: number;
119
+ };
120
+ spent: ReturnType<typeof usageTotals> & {
121
+ uncoveredRuns: number;
122
+ liveCalls: number;
123
+ };
124
+ state: 'within' | 'exceeded' | 'undetermined';
125
+ reason?: string;
126
+ };
127
+ export declare function budgetStatus(c: BudgetContext, view: ExecutionView, scope: BudgetScope, records?: CallRecord[], at?: number): BudgetStatus | undefined;
128
+ /** Бюджеты, относящиеся к поручению: его собственный, его групп и общий. */
129
+ export declare function workBudgets(c: BudgetContext, view: ExecutionView, workId: string, records?: {
130
+ id: string;
131
+ stage: string;
132
+ runtime: string;
133
+ model: string | null;
134
+ runtimeVersion: string | null;
135
+ startedAt: string;
136
+ outcome: "error" | "active" | "returned" | "abandoned";
137
+ promptBytes: number;
138
+ promptDigest: string;
139
+ usage: {
140
+ inputTokens: number | null;
141
+ outputTokens: number | null;
142
+ cacheReadTokens: number | null;
143
+ cacheWriteTokens: number | null;
144
+ reportedUsd: number | null;
145
+ complete: boolean;
146
+ source: "fixture" | "unavailable" | "codex-turn-events" | "claude-result";
147
+ };
148
+ costUsd: number | null;
149
+ costSource: "unknown" | "provider-reported" | "tariff-estimate";
150
+ repositoryId?: string | undefined;
151
+ runId?: string | undefined;
152
+ subjectId?: string | undefined;
153
+ subjectKind?: "work" | "group" | "other" | undefined;
154
+ finishedAt?: string | undefined;
155
+ process?: {
156
+ id: string;
157
+ pid: number;
158
+ startedAt?: number | undefined;
159
+ } | undefined;
160
+ abandonedAt?: string | undefined;
161
+ durationMs?: number | undefined;
162
+ elapsedMs?: number | undefined;
163
+ startedHr?: string | undefined;
164
+ durationUnknown?: true | undefined;
165
+ bootId?: string | undefined;
166
+ workId?: string | undefined;
167
+ groupId?: string | undefined;
168
+ workIds?: string[] | undefined;
169
+ price?: {
170
+ runtime: "codex" | "claude";
171
+ model: string;
172
+ effectiveAt: string;
173
+ input: number;
174
+ output: number;
175
+ cacheRead: number;
176
+ cacheWrite: number;
177
+ } | undefined;
178
+ diagnostics?: {
179
+ startedAt: string;
180
+ finishedAt: string;
181
+ lastOutputAt: string | null;
182
+ exitCode: number | null;
183
+ signal: string | null;
184
+ timedOut: boolean;
185
+ aborted: boolean;
186
+ stdoutTail: string;
187
+ stderrTail: string;
188
+ processTree?: {
189
+ available: boolean;
190
+ processes: {
191
+ pid: number;
192
+ parentPid: number;
193
+ groupPid: number;
194
+ name: string;
195
+ }[];
196
+ reason?: string | undefined;
197
+ } | undefined;
198
+ } | undefined;
199
+ }[], at?: number): BudgetStatus[];
200
+ /** Сведения о вызове: попытка, предмет (поручение, группа, документ), стадия. */
201
+ export interface CallMeta {
202
+ repositoryId?: string;
203
+ runId?: string;
204
+ subjectId?: string;
205
+ /** Вид предмета: явный вид важнее совпадения ID с поручением. */
206
+ subjectKind?: CallRecord['subjectKind'];
207
+ stage: string;
208
+ /**
209
+ * Состав группы из входа вызова (ревью плана до регистрации графа): группа и
210
+ * её поручения закрепляются за расходом на момент вызова, а не по составу,
211
+ * который хранилище узнает позже.
212
+ */
213
+ group?: {
214
+ id: string;
215
+ workIds: string[];
216
+ };
217
+ }
218
+ /**
219
+ * Бюджеты вызова модели: по его попытке или поручению — бюджеты поручения; о
220
+ * группе — бюджеты группы и каждого её открытого поручения, за которыми вызов
221
+ * будет учтён; о прочем (контракт) — общий.
222
+ */
223
+ export declare function callBudgets(c: BudgetContext, view: ExecutionView, meta: Pick<CallMeta, 'runId' | 'subjectId' | 'subjectKind' | 'group'>, records?: {
224
+ id: string;
225
+ stage: string;
226
+ runtime: string;
227
+ model: string | null;
228
+ runtimeVersion: string | null;
229
+ startedAt: string;
230
+ outcome: "error" | "active" | "returned" | "abandoned";
231
+ promptBytes: number;
232
+ promptDigest: string;
233
+ usage: {
234
+ inputTokens: number | null;
235
+ outputTokens: number | null;
236
+ cacheReadTokens: number | null;
237
+ cacheWriteTokens: number | null;
238
+ reportedUsd: number | null;
239
+ complete: boolean;
240
+ source: "fixture" | "unavailable" | "codex-turn-events" | "claude-result";
241
+ };
242
+ costUsd: number | null;
243
+ costSource: "unknown" | "provider-reported" | "tariff-estimate";
244
+ repositoryId?: string | undefined;
245
+ runId?: string | undefined;
246
+ subjectId?: string | undefined;
247
+ subjectKind?: "work" | "group" | "other" | undefined;
248
+ finishedAt?: string | undefined;
249
+ process?: {
250
+ id: string;
251
+ pid: number;
252
+ startedAt?: number | undefined;
253
+ } | undefined;
254
+ abandonedAt?: string | undefined;
255
+ durationMs?: number | undefined;
256
+ elapsedMs?: number | undefined;
257
+ startedHr?: string | undefined;
258
+ durationUnknown?: true | undefined;
259
+ bootId?: string | undefined;
260
+ workId?: string | undefined;
261
+ groupId?: string | undefined;
262
+ workIds?: string[] | undefined;
263
+ price?: {
264
+ runtime: "codex" | "claude";
265
+ model: string;
266
+ effectiveAt: string;
267
+ input: number;
268
+ output: number;
269
+ cacheRead: number;
270
+ cacheWrite: number;
271
+ } | undefined;
272
+ diagnostics?: {
273
+ startedAt: string;
274
+ finishedAt: string;
275
+ lastOutputAt: string | null;
276
+ exitCode: number | null;
277
+ signal: string | null;
278
+ timedOut: boolean;
279
+ aborted: boolean;
280
+ stdoutTail: string;
281
+ stderrTail: string;
282
+ processTree?: {
283
+ available: boolean;
284
+ processes: {
285
+ pid: number;
286
+ parentPid: number;
287
+ groupPid: number;
288
+ name: string;
289
+ }[];
290
+ reason?: string | undefined;
291
+ } | undefined;
292
+ } | undefined;
293
+ }[], at?: number): BudgetStatus[];
294
+ /**
295
+ * Поручение и группа вызова на момент вызова: за ними остаётся его расход.
296
+ * У вызова о группе — её открытые поручения.
297
+ */
298
+ export declare function callAttribution(c: BudgetContext, view: ExecutionView, meta: Pick<CallMeta, 'runId' | 'subjectId' | 'subjectKind' | 'group'>, all?: boolean): Pick<CallRecord, 'workId' | 'groupId' | 'workIds'>;
299
+ /** Бюджет, который запрещает тратить: превышен или не определён при `onUnknown: stop`. */
300
+ export declare function blockingBudget(c: BudgetContext, statuses: BudgetStatus[]): BudgetStatus | undefined;
301
+ /** Отказ до траты: превышенный или неопределённый бюджет не даёт начать вызов. */
302
+ export declare function assertBudget(c: BudgetContext, statuses: BudgetStatus[]): void;
303
+ /** Компактный вид бюджета для статуса и потребителей. */
304
+ export declare function budgetView(b: BudgetStatus): {
305
+ reason?: string | undefined;
306
+ scope: BudgetScope;
307
+ state: "exceeded" | "undetermined" | "within";
308
+ limit: {
309
+ usd?: number;
310
+ timeMs?: number;
311
+ };
312
+ reportedUsd: number;
313
+ estimatedUsd: number;
314
+ unknownCalls: number;
315
+ unfinishedCalls: number;
316
+ abandonedCalls: number;
317
+ errorCalls: number;
318
+ uncoveredRuns: number;
319
+ durationMs: number;
320
+ remainingUsd: number | null;
321
+ remainingMs: number | null;
322
+ };
323
+ /** Бюджеты установки: общий, группы с незавершённой работой, незавершённые поручения. */
324
+ export declare function budgetOverview(c: BudgetContext, view: ExecutionView, records?: CallRecord[]): {
325
+ onUnknown: "stop" | "continue";
326
+ budgets: {
327
+ reason?: string | undefined;
328
+ scope: BudgetScope;
329
+ state: "exceeded" | "undetermined" | "within";
330
+ limit: {
331
+ usd?: number;
332
+ timeMs?: number;
333
+ };
334
+ reportedUsd: number;
335
+ estimatedUsd: number;
336
+ unknownCalls: number;
337
+ unfinishedCalls: number;
338
+ abandonedCalls: number;
339
+ errorCalls: number;
340
+ uncoveredRuns: number;
341
+ durationMs: number;
342
+ remainingUsd: number | null;
343
+ remainingMs: number | null;
344
+ }[];
345
+ } | undefined;