@intentius/chant 0.90.0 → 0.93.0

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 (402) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/lint.d.ts.map +1 -1
  3. package/dist/cli/handlers/components.d.ts +8 -0
  4. package/dist/cli/handlers/components.d.ts.map +1 -1
  5. package/dist/cli/handlers/graph.d.ts.map +1 -1
  6. package/dist/cli/handlers/operator.d.ts +20 -0
  7. package/dist/cli/handlers/operator.d.ts.map +1 -1
  8. package/dist/cli/handlers/run.d.ts.map +1 -1
  9. package/dist/cli/main.d.ts.map +1 -1
  10. package/dist/cli/mcp/workspace-tools.d.ts +7 -4
  11. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  12. package/dist/cli/plugins.d.ts.map +1 -1
  13. package/dist/cli/registry.d.ts +42 -1
  14. package/dist/cli/registry.d.ts.map +1 -1
  15. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  16. package/dist/components/verbs/vuln-scan.d.ts +72 -0
  17. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  18. package/dist/config.d.ts +22 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/lexicon-module.d.ts +22 -0
  21. package/dist/lexicon-module.d.ts.map +1 -1
  22. package/dist/lifecycle/converge-ledger.d.ts +19 -0
  23. package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
  24. package/dist/lifecycle/git.d.ts +40 -5
  25. package/dist/lifecycle/git.d.ts.map +1 -1
  26. package/dist/lifecycle/lease.d.ts +72 -16
  27. package/dist/lifecycle/lease.d.ts.map +1 -1
  28. package/dist/lifecycle/member-ledger.d.ts +3 -2
  29. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  30. package/dist/lifecycle/plan-ledger.d.ts +114 -0
  31. package/dist/lifecycle/plan-ledger.d.ts.map +1 -0
  32. package/dist/lifecycle/run-ledger.d.ts +2 -0
  33. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  34. package/dist/lifecycle/symptoms.d.ts +51 -0
  35. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  36. package/dist/lifecycle/work-lease.d.ts +140 -0
  37. package/dist/lifecycle/work-lease.d.ts.map +1 -0
  38. package/dist/lint/rules/index.d.ts +4 -2
  39. package/dist/lint/rules/index.d.ts.map +1 -1
  40. package/dist/lint/rules/op/index.d.ts +14 -3
  41. package/dist/lint/rules/op/index.d.ts.map +1 -1
  42. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -1
  43. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts +29 -0
  44. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts.map +1 -0
  45. package/dist/lint/rules/sys001-no-literal-key.d.ts +3 -0
  46. package/dist/lint/rules/sys001-no-literal-key.d.ts.map +1 -0
  47. package/dist/op/__fixtures__/decide-stub-backend.d.ts +53 -0
  48. package/dist/op/__fixtures__/decide-stub-backend.d.ts.map +1 -0
  49. package/dist/op/activities/activity-contracts.d.ts +203 -2
  50. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  51. package/dist/op/activities/apply.d.ts.map +1 -1
  52. package/dist/op/activities/change-coverage.d.ts +44 -0
  53. package/dist/op/activities/change-coverage.d.ts.map +1 -0
  54. package/dist/op/activities/converge.d.ts +24 -1
  55. package/dist/op/activities/converge.d.ts.map +1 -1
  56. package/dist/op/activities/decide.d.ts +107 -0
  57. package/dist/op/activities/decide.d.ts.map +1 -0
  58. package/dist/op/activities/index.d.ts +10 -0
  59. package/dist/op/activities/index.d.ts.map +1 -1
  60. package/dist/op/activities/shell.d.ts +32 -0
  61. package/dist/op/activities/shell.d.ts.map +1 -1
  62. package/dist/op/activities/source-release.d.ts +86 -0
  63. package/dist/op/activities/source-release.d.ts.map +1 -0
  64. package/dist/op/activities/source-rollback.d.ts +100 -0
  65. package/dist/op/activities/source-rollback.d.ts.map +1 -0
  66. package/dist/op/activities/work-evidence.d.ts +42 -0
  67. package/dist/op/activities/work-evidence.d.ts.map +1 -0
  68. package/dist/op/activity-contract.d.ts +1 -0
  69. package/dist/op/activity-contract.d.ts.map +1 -1
  70. package/dist/op/activity-profiles.d.ts +16 -0
  71. package/dist/op/activity-profiles.d.ts.map +1 -1
  72. package/dist/op/builders.d.ts +84 -2
  73. package/dist/op/builders.d.ts.map +1 -1
  74. package/dist/op/composites/converge-op.d.ts +31 -4
  75. package/dist/op/composites/converge-op.d.ts.map +1 -1
  76. package/dist/op/decide-backend.d.ts +116 -0
  77. package/dist/op/decide-backend.d.ts.map +1 -0
  78. package/dist/op/decide-config.d.ts +120 -0
  79. package/dist/op/decide-config.d.ts.map +1 -0
  80. package/dist/op/decide-read-inputs.d.ts +40 -0
  81. package/dist/op/decide-read-inputs.d.ts.map +1 -0
  82. package/dist/op/discover.d.ts +25 -0
  83. package/dist/op/discover.d.ts.map +1 -1
  84. package/dist/op/gate-wait.d.ts +43 -0
  85. package/dist/op/gate-wait.d.ts.map +1 -0
  86. package/dist/op/gate.d.ts +5 -2
  87. package/dist/op/gate.d.ts.map +1 -1
  88. package/dist/op/index.d.ts +18 -5
  89. package/dist/op/index.d.ts.map +1 -1
  90. package/dist/op/lifecycle-receipt-store.d.ts +34 -0
  91. package/dist/op/lifecycle-receipt-store.d.ts.map +1 -0
  92. package/dist/op/local-executor.d.ts +48 -4
  93. package/dist/op/local-executor.d.ts.map +1 -1
  94. package/dist/op/local-output.d.ts +2 -0
  95. package/dist/op/local-output.d.ts.map +1 -1
  96. package/dist/op/op-ir.d.ts +12 -1
  97. package/dist/op/op-ir.d.ts.map +1 -1
  98. package/dist/op/op-verb-class.d.ts.map +1 -1
  99. package/dist/op/operator.d.ts +126 -1
  100. package/dist/op/operator.d.ts.map +1 -1
  101. package/dist/op/runtime.d.ts +46 -5
  102. package/dist/op/runtime.d.ts.map +1 -1
  103. package/dist/op/runtimes/local.d.ts.map +1 -1
  104. package/dist/op/source-archive.d.ts +63 -0
  105. package/dist/op/source-archive.d.ts.map +1 -0
  106. package/dist/op/step-output-ref.d.ts +2 -2
  107. package/dist/op/step-output-ref.d.ts.map +1 -1
  108. package/dist/op/steward-points.d.ts +136 -0
  109. package/dist/op/steward-points.d.ts.map +1 -0
  110. package/dist/op/steward-turn.d.ts +53 -0
  111. package/dist/op/steward-turn.d.ts.map +1 -0
  112. package/dist/op/steward.d.ts +161 -0
  113. package/dist/op/steward.d.ts.map +1 -0
  114. package/dist/op/types.d.ts +58 -0
  115. package/dist/op/types.d.ts.map +1 -1
  116. package/dist/op/work-lease-decl.d.ts +18 -0
  117. package/dist/op/work-lease-decl.d.ts.map +1 -0
  118. package/dist/op/work-lease-run.d.ts +173 -0
  119. package/dist/op/work-lease-run.d.ts.map +1 -0
  120. package/dist/workspace/__fixtures__/decide-workspace.d.ts +100 -0
  121. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -0
  122. package/dist/workspace/answers-ledger.d.ts +76 -0
  123. package/dist/workspace/answers-ledger.d.ts.map +1 -0
  124. package/dist/workspace/box-isolation.d.ts +99 -0
  125. package/dist/workspace/box-isolation.d.ts.map +1 -0
  126. package/dist/workspace/changes-cli.d.ts +16 -0
  127. package/dist/workspace/changes-cli.d.ts.map +1 -0
  128. package/dist/workspace/changes.d.ts +200 -0
  129. package/dist/workspace/changes.d.ts.map +1 -0
  130. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts +59 -0
  131. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts.map +1 -0
  132. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts +51 -0
  133. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts.map +1 -0
  134. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts +26 -0
  135. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts.map +1 -0
  136. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts +59 -0
  137. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts.map +1 -0
  138. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts +22 -0
  139. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts.map +1 -0
  140. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts +71 -0
  141. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -0
  142. package/dist/workspace/chant-migrations.d.ts +99 -0
  143. package/dist/workspace/chant-migrations.d.ts.map +1 -0
  144. package/dist/workspace/checks/box-isolation.d.ts +18 -0
  145. package/dist/workspace/checks/box-isolation.d.ts.map +1 -0
  146. package/dist/workspace/checks/boxes.d.ts +104 -0
  147. package/dist/workspace/checks/boxes.d.ts.map +1 -0
  148. package/dist/workspace/checks/diagrams.d.ts +31 -0
  149. package/dist/workspace/checks/diagrams.d.ts.map +1 -0
  150. package/dist/workspace/checks/records.d.ts +8 -0
  151. package/dist/workspace/checks/records.d.ts.map +1 -1
  152. package/dist/workspace/checks.d.ts +13 -1
  153. package/dist/workspace/checks.d.ts.map +1 -1
  154. package/dist/workspace/compose-graph.d.ts +2 -0
  155. package/dist/workspace/compose-graph.d.ts.map +1 -1
  156. package/dist/workspace/conformance/index.d.ts.map +1 -1
  157. package/dist/workspace/decide.d.ts +229 -0
  158. package/dist/workspace/decide.d.ts.map +1 -0
  159. package/dist/workspace/decision-points.schema.json +137 -0
  160. package/dist/workspace/declaration.d.ts +103 -0
  161. package/dist/workspace/declaration.d.ts.map +1 -1
  162. package/dist/workspace/declaration.schema.json +285 -0
  163. package/dist/workspace/declared-kinds.d.ts +32 -0
  164. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  165. package/dist/workspace/generated-files.d.ts +7 -0
  166. package/dist/workspace/generated-files.d.ts.map +1 -1
  167. package/dist/workspace/intent.d.ts.map +1 -1
  168. package/dist/workspace/lineage-check.d.ts +3 -0
  169. package/dist/workspace/lineage-check.d.ts.map +1 -1
  170. package/dist/workspace/lineage-upgrade.d.ts +6 -1
  171. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  172. package/dist/workspace/ls.d.ts +39 -1
  173. package/dist/workspace/ls.d.ts.map +1 -1
  174. package/dist/workspace/point-answer.schema.json +95 -0
  175. package/dist/workspace/points-cli.d.ts +113 -0
  176. package/dist/workspace/points-cli.d.ts.map +1 -0
  177. package/dist/workspace/points.d.ts +320 -0
  178. package/dist/workspace/points.d.ts.map +1 -0
  179. package/dist/workspace/reason-codes.d.ts +38 -0
  180. package/dist/workspace/reason-codes.d.ts.map +1 -1
  181. package/dist/workspace/record-assets.d.ts.map +1 -1
  182. package/dist/workspace/records-cli.d.ts +23 -1
  183. package/dist/workspace/records-cli.d.ts.map +1 -1
  184. package/dist/workspace/records-close.d.ts +1 -1
  185. package/dist/workspace/records-close.d.ts.map +1 -1
  186. package/dist/workspace/records-write.d.ts +11 -5
  187. package/dist/workspace/records-write.d.ts.map +1 -1
  188. package/dist/workspace/records.d.ts +42 -6
  189. package/dist/workspace/records.d.ts.map +1 -1
  190. package/dist/workspace/status-gates.d.ts +7 -2
  191. package/dist/workspace/status-gates.d.ts.map +1 -1
  192. package/dist/workspace/status-stewards.d.ts +179 -0
  193. package/dist/workspace/status-stewards.d.ts.map +1 -0
  194. package/dist/workspace/status.d.ts +68 -1
  195. package/dist/workspace/status.d.ts.map +1 -1
  196. package/dist/workspace/work-cli.d.ts +189 -0
  197. package/dist/workspace/work-cli.d.ts.map +1 -0
  198. package/dist/workspace/work-evidence.d.ts +74 -0
  199. package/dist/workspace/work-evidence.d.ts.map +1 -0
  200. package/dist/workspace/work.d.ts +43 -1
  201. package/dist/workspace/work.d.ts.map +1 -1
  202. package/package.json +1 -1
  203. package/src/cli/commands/audit.test.ts +9 -1
  204. package/src/cli/commands/build.ts +3 -2
  205. package/src/cli/commands/lint.ts +7 -1
  206. package/src/cli/handlers/components.test.ts +93 -0
  207. package/src/cli/handlers/components.ts +44 -3
  208. package/src/cli/handlers/graph.test.ts +20 -0
  209. package/src/cli/handlers/graph.ts +16 -2
  210. package/src/cli/handlers/operator.ts +141 -4
  211. package/src/cli/handlers/run.test.ts +173 -2
  212. package/src/cli/handlers/run.ts +174 -3
  213. package/src/cli/main.test.ts +50 -0
  214. package/src/cli/main.ts +97 -2
  215. package/src/cli/mcp/workspace-tools.test.ts +48 -19
  216. package/src/cli/mcp/workspace-tools.ts +110 -8
  217. package/src/cli/plugins.ts +11 -3
  218. package/src/cli/registry.ts +42 -1
  219. package/src/codegen/pinned-upgrade.ts +2 -1
  220. package/src/codegen/release-wiring.test.ts +49 -2
  221. package/src/components/capability-plugin-loader.ts +3 -3
  222. package/src/components/cli-support.ts +2 -2
  223. package/src/components/verbs/vuln-scan.test.ts +124 -1
  224. package/src/components/verbs/vuln-scan.ts +142 -1
  225. package/src/config.ts +11 -0
  226. package/src/lexicon-module.ts +56 -1
  227. package/src/lexicon-package.test.ts +96 -0
  228. package/src/lifecycle/converge-ledger.ts +20 -0
  229. package/src/lifecycle/git.ts +65 -15
  230. package/src/lifecycle/lease.test.ts +22 -0
  231. package/src/lifecycle/lease.ts +133 -29
  232. package/src/lifecycle/member-ledger.ts +3 -2
  233. package/src/lifecycle/plan-ledger.test.ts +148 -0
  234. package/src/lifecycle/plan-ledger.ts +158 -0
  235. package/src/lifecycle/run-ledger.ts +6 -0
  236. package/src/lifecycle/symptoms.ts +95 -0
  237. package/src/lifecycle/work-lease.test.ts +236 -0
  238. package/src/lifecycle/work-lease.ts +426 -0
  239. package/src/lint/rules/index.ts +6 -2
  240. package/src/lint/rules/op/index.ts +17 -4
  241. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +23 -1
  242. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +10 -6
  243. package/src/lint/rules/op/sys010-key-over-plain-http.test.ts +52 -0
  244. package/src/lint/rules/op/sys010-key-over-plain-http.ts +100 -0
  245. package/src/lint/rules/sys001-no-literal-key.test.ts +31 -0
  246. package/src/lint/rules/sys001-no-literal-key.ts +67 -0
  247. package/src/op/__fixtures__/decide-stub-backend.ts +143 -0
  248. package/src/op/activities/activity-contracts.ts +190 -1
  249. package/src/op/activities/apply.ts +7 -6
  250. package/src/op/activities/change-coverage.ts +60 -0
  251. package/src/op/activities/converge.test.ts +55 -1
  252. package/src/op/activities/converge.ts +208 -29
  253. package/src/op/activities/decide.live.test.ts +78 -0
  254. package/src/op/activities/decide.test.ts +300 -0
  255. package/src/op/activities/decide.ts +267 -0
  256. package/src/op/activities/index.ts +21 -0
  257. package/src/op/activities/shell.test.ts +91 -1
  258. package/src/op/activities/shell.ts +91 -2
  259. package/src/op/activities/source-release.test.ts +118 -0
  260. package/src/op/activities/source-release.ts +168 -0
  261. package/src/op/activities/source-rollback.test.ts +131 -0
  262. package/src/op/activities/source-rollback.ts +239 -0
  263. package/src/op/activities/work-evidence.ts +62 -0
  264. package/src/op/activity-contract-registry.test.ts +2 -0
  265. package/src/op/activity-contract-registry.ts +2 -2
  266. package/src/op/activity-contract.test.ts +12 -0
  267. package/src/op/activity-contract.ts +6 -1
  268. package/src/op/activity-profiles.ts +29 -0
  269. package/src/op/activity-registry.test.ts +1 -1
  270. package/src/op/activity-registry.ts +2 -2
  271. package/src/op/builders.ts +124 -5
  272. package/src/op/command-gate.test.ts +192 -0
  273. package/src/op/composites/converge-op.test.ts +27 -1
  274. package/src/op/composites/converge-op.ts +69 -15
  275. package/src/op/decide-backend.test.ts +44 -0
  276. package/src/op/decide-backend.ts +212 -0
  277. package/src/op/decide-config.test.ts +52 -0
  278. package/src/op/decide-config.ts +80 -0
  279. package/src/op/decide-read-inputs.ts +117 -0
  280. package/src/op/discover.ts +71 -0
  281. package/src/op/gate-approval.ts +2 -2
  282. package/src/op/gate-wait.ts +57 -0
  283. package/src/op/gate.ts +8 -3
  284. package/src/op/generate-pipeline.ts +2 -2
  285. package/src/op/index.ts +34 -6
  286. package/src/op/lifecycle-receipt-store.test.ts +60 -0
  287. package/src/op/lifecycle-receipt-store.ts +61 -0
  288. package/src/op/local-executor.ts +367 -33
  289. package/src/op/local-output.test.ts +33 -0
  290. package/src/op/local-output.ts +33 -2
  291. package/src/op/op-ir.test.ts +10 -0
  292. package/src/op/op-ir.ts +18 -0
  293. package/src/op/op-verb-class.ts +1 -0
  294. package/src/op/operator.ts +360 -10
  295. package/src/op/runtime.ts +37 -8
  296. package/src/op/runtimes/local.ts +6 -1
  297. package/src/op/source-archive.ts +161 -0
  298. package/src/op/step-output-ref.ts +6 -2
  299. package/src/op/steward-points.test.ts +313 -0
  300. package/src/op/steward-points.ts +194 -0
  301. package/src/op/steward-turn.ts +79 -0
  302. package/src/op/steward.test.ts +296 -0
  303. package/src/op/steward.ts +277 -0
  304. package/src/op/types.ts +60 -0
  305. package/src/op/work-lease-decl.ts +80 -0
  306. package/src/op/work-lease-run.test.ts +345 -0
  307. package/src/op/work-lease-run.ts +395 -0
  308. package/src/workspace/__fixtures__/decide-workspace.ts +129 -0
  309. package/src/workspace/__fixtures__/studio-template-84c8b21.json +67 -0
  310. package/src/workspace/answers-ledger.ts +118 -0
  311. package/src/workspace/box-isolation.test.ts +261 -0
  312. package/src/workspace/box-isolation.ts +205 -0
  313. package/src/workspace/changes-cli.ts +56 -0
  314. package/src/workspace/changes.schema.json +472 -0
  315. package/src/workspace/changes.test.ts +315 -0
  316. package/src/workspace/changes.ts +512 -0
  317. package/src/workspace/chant-migrations/chud-lexicon-exit-fly-site.ts +234 -0
  318. package/src/workspace/chant-migrations/chud-lexicon-exit-live-names.ts +164 -0
  319. package/src/workspace/chant-migrations/chud-lexicon-exit-rollback.ts +223 -0
  320. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.ts +195 -0
  321. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-policy.ts +108 -0
  322. package/src/workspace/chant-migrations/chud-lexicon-exit.ts +882 -0
  323. package/src/workspace/chant-migrations.e2e.test.ts +1089 -0
  324. package/src/workspace/chant-migrations.ts +164 -0
  325. package/src/workspace/check-contract.test.ts +5 -1
  326. package/src/workspace/check.schema.json +25 -7
  327. package/src/workspace/checks/box-isolation.ts +68 -0
  328. package/src/workspace/checks/boxes.test.ts +276 -0
  329. package/src/workspace/checks/boxes.ts +442 -0
  330. package/src/workspace/checks/diagrams.test.ts +134 -0
  331. package/src/workspace/checks/diagrams.ts +108 -0
  332. package/src/workspace/checks/records.ts +72 -0
  333. package/src/workspace/checks.test.ts +7 -0
  334. package/src/workspace/checks.ts +27 -3
  335. package/src/workspace/compose-graph.ts +2 -0
  336. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +10 -0
  337. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +26 -0
  338. package/src/workspace/conformance/index.ts +5 -0
  339. package/src/workspace/decide.test.ts +224 -0
  340. package/src/workspace/decide.ts +709 -0
  341. package/src/workspace/decision-points.schema.json +137 -0
  342. package/src/workspace/declaration.schema.json +285 -0
  343. package/src/workspace/declaration.test.ts +58 -0
  344. package/src/workspace/declaration.ts +241 -0
  345. package/src/workspace/declared-kinds.test.ts +5 -5
  346. package/src/workspace/declared-kinds.ts +71 -3
  347. package/src/workspace/generated-files.ts +14 -0
  348. package/src/workspace/graph-cli.ts +1 -1
  349. package/src/workspace/graph.schema.json +9 -1
  350. package/src/workspace/intent.schema.json +12 -3
  351. package/src/workspace/intent.ts +3 -10
  352. package/src/workspace/lineage-check.ts +16 -1
  353. package/src/workspace/lineage-upgrade-cli.ts +1 -1
  354. package/src/workspace/lineage-upgrade.test.ts +70 -0
  355. package/src/workspace/lineage-upgrade.ts +81 -10
  356. package/src/workspace/ls-contract.test.ts +57 -0
  357. package/src/workspace/ls.schema.json +46 -1
  358. package/src/workspace/ls.ts +62 -3
  359. package/src/workspace/point-answer.schema.json +95 -0
  360. package/src/workspace/points-cli.ts +284 -0
  361. package/src/workspace/points-write.schema.json +499 -0
  362. package/src/workspace/points.schema.json +743 -0
  363. package/src/workspace/points.test.ts +264 -0
  364. package/src/workspace/points.ts +564 -0
  365. package/src/workspace/read-contract.test.ts +18 -1
  366. package/src/workspace/reason-codes.test.ts +24 -1
  367. package/src/workspace/reason-codes.ts +49 -0
  368. package/src/workspace/record-assets.test.ts +3 -2
  369. package/src/workspace/record-assets.ts +4 -1
  370. package/src/workspace/records-amend.schema.json +2 -0
  371. package/src/workspace/records-cli.ts +28 -5
  372. package/src/workspace/records-close.schema.json +2 -0
  373. package/src/workspace/records-contract.test.ts +3 -2
  374. package/src/workspace/records-new.schema.json +2 -0
  375. package/src/workspace/records-review.schema.json +2 -0
  376. package/src/workspace/records-sessions-write.e2e.test.ts +77 -0
  377. package/src/workspace/records-sessions-write.test.ts +2 -34
  378. package/src/workspace/records-write.e2e.test.ts +108 -0
  379. package/src/workspace/records-write.test.ts +32 -41
  380. package/src/workspace/records-write.ts +33 -15
  381. package/src/workspace/records.schema.json +53 -2
  382. package/src/workspace/records.test.ts +48 -3
  383. package/src/workspace/records.ts +142 -6
  384. package/src/workspace/status-contract.test.ts +189 -6
  385. package/src/workspace/status-gates.ts +9 -4
  386. package/src/workspace/status-stewards.ts +329 -0
  387. package/src/workspace/status.schema.json +335 -5
  388. package/src/workspace/status.ts +142 -6
  389. package/src/workspace/work-acceptance.test.ts +274 -0
  390. package/src/workspace/work-cli.e2e.test.ts +180 -0
  391. package/src/workspace/work-cli.ts +429 -0
  392. package/src/workspace/work-evidence.schema.json +212 -0
  393. package/src/workspace/work-evidence.ts +169 -0
  394. package/src/workspace/work-history.schema.json +349 -0
  395. package/src/workspace/work-history.test.ts +156 -0
  396. package/src/workspace/work-lease.schema.json +233 -0
  397. package/src/workspace/work-readiness-chud.test.ts +145 -0
  398. package/src/workspace/work.test.ts +3 -2
  399. package/src/workspace/work.ts +100 -1
  400. /package/src/cli/{discovery-skip.test.ts → discovery-skip.e2e.test.ts} +0 -0
  401. /package/src/workspace/conformance/{conformance.test.ts → conformance.e2e.test.ts} +0 -0
  402. /package/src/workspace/{which-chant.test.ts → which-chant.e2e.test.ts} +0 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * A steward's declaration (#2731): the one writer for an environment, as data
3
+ * core can read without any lexicon loaded.
4
+ *
5
+ * A steward runs a fixed list of Ops, each on its own `schedule` when it has
6
+ * one, one Op at a time. Where it runs is its form:
7
+ *
8
+ * - `fountain`: the fountain lexicon's `Steward` composite, an `acp` Agent on
9
+ * a persistent sandbox bound to a Teammate, with a Fountain `Schedule` per
10
+ * scheduled Op. A turn is one `chant run <op>` on the teammate's thread.
11
+ * - `local`: `chant operator --steward <name>` in the box itself, for a box
12
+ * with no Fountain behind it (a docker compose box, a Sprites box). The same
13
+ * Ops on the same crons, each run under its operator lease, and the steward
14
+ * itself under a lease of its own so a second local operator is refused.
15
+ *
16
+ * One declaration covers both. `form` is either one of the two, or a default
17
+ * with per-environment exceptions, so a box whose `minimal` environment has no
18
+ * Fountain and whose `fountain-k3d` one does still has exactly one steward:
19
+ *
20
+ * ```ts
21
+ * // ops/steward.op.ts
22
+ * export const steward = declareSteward({
23
+ * name: "box-steward",
24
+ * ops: [converge, dispatch, release, upgrade],
25
+ * form: { default: "local", environments: { "fountain-k3d": "fountain" } },
26
+ * });
27
+ * ```
28
+ *
29
+ * The fountain composite builds this same declaration from its own options and
30
+ * returns it as `declaration`, so a project that declares its steward there
31
+ * exports that object from an `*.op.ts` file instead of calling this function.
32
+ *
33
+ * ## Discovery
34
+ *
35
+ * A steward is discovered from the same `*.op.ts` files Ops are
36
+ * (`./discover.ts`), because it is chant's own run-time declaration and sits
37
+ * beside the Ops it runs. It is plain data with a `kind` marker, not a
38
+ * Declarable, so `chant build` never serializes it and a copy of core linked
39
+ * twice still recognises it.
40
+ *
41
+ * ## What a steward writes
42
+ *
43
+ * A steward's writes are chant writes: run, converge and gate records on the
44
+ * `chant/lifecycle` branch, the answer records of the decision points its
45
+ * Ops ask (`_answers/`, #2786), and lease refs under `refs/chant/lease/`, all made
46
+ * with git plumbing (`../lifecycle/git.ts`: `hash-object`, `mktree`,
47
+ * `commit-tree`, `update-ref`). None of them reads or writes the checkout's
48
+ * index or working tree, so a coding agent editing the app in the same
49
+ * checkout, and holding git's index lock while it commits, never collides with
50
+ * a steward turn. The app's files are the coding agent's; the steward does not
51
+ * edit them.
52
+ *
53
+ * An Op that has to change the checkout (applying a build, a workspace
54
+ * upgrade) says so with `changesCheckout` and runs under a work item's lease
55
+ * (`workLease`, #2748): its leased steps get a worktree of their own on
56
+ * `chant/work/<item>`. `declareSteward` refuses such an Op without the lease,
57
+ * and a scheduled Op whose lease leaves the item to the run.
58
+ */
59
+
60
+ import type { OpConfig } from "./types";
61
+ import { isValidCronExpression, cronSyntaxMessage } from "./cron";
62
+ import { workLeaseNeedsRunItem, workLeaseProblems } from "./work-lease-decl";
63
+
64
+ /** The entity marker a steward declaration carries. */
65
+ export const STEWARD_KIND = "Chant::Steward";
66
+
67
+ /** Where a steward runs. */
68
+ export const STEWARD_FORMS = ["local", "fountain"] as const;
69
+ export type StewardForm = (typeof STEWARD_FORMS)[number];
70
+
71
+ /** The form a declaration asks for, as given: one form, or a default with per-environment exceptions. */
72
+ export type StewardFormSpec = StewardForm | { default: StewardForm; environments?: Record<string, StewardForm> };
73
+
74
+ /** The environment a form is chosen for when none is named: the same default a run ledger uses. */
75
+ export const DEFAULT_STEWARD_ENV = "local";
76
+
77
+ /** Names a steward's lease ref and a ledger path can hold. */
78
+ export const STEWARD_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
79
+
80
+ /**
81
+ * An Op a steward runs, however the project holds it: the `Op()` declaration
82
+ * (config behind `.props`), or the bare config.
83
+ */
84
+ export type StewardOpInput = OpConfig | { props: unknown };
85
+
86
+ export interface StewardDeclarationConfig {
87
+ /** The steward's name. On Fountain, the Agent's and the Teammate's. */
88
+ name: string;
89
+ /** The Ops it runs. A scheduled one runs on its cron; any other runs when asked. */
90
+ ops: StewardOpInput[];
91
+ /** Where it runs. Default `local`. */
92
+ form?: StewardFormSpec;
93
+ /**
94
+ * The box capabilities its Ops reach through the box's broker (#2726), by
95
+ * the names the member's `box` block in the workspace declaration gives
96
+ * them, such as `fountain` or `inference`. A steward that names any holds no
97
+ * credential of its own, so it takes no `vault`.
98
+ */
99
+ capabilities?: string[];
100
+ /** The vault the steward holds on Fountain, by name, for a steward that isn't behind a broker. */
101
+ vault?: string;
102
+ }
103
+
104
+ /** A steward's declaration, normalised. Plain data: see the module doc. */
105
+ export interface StewardDeclaration {
106
+ readonly kind: typeof STEWARD_KIND;
107
+ readonly name: string;
108
+ readonly ops: readonly OpConfig[];
109
+ readonly form: { readonly default: StewardForm; readonly environments: Readonly<Record<string, StewardForm>> };
110
+ /** Brokered box capabilities its Ops use (#2726). Empty when it names none. */
111
+ readonly capabilities: readonly string[];
112
+ /** The vault it holds, by name, or null. Never set together with `capabilities`. */
113
+ readonly vault: string | null;
114
+ }
115
+
116
+ /** The config inside an op, whether it arrived as a declaration or as itself. */
117
+ export function stewardOpConfig(op: StewardOpInput): OpConfig {
118
+ const declared = (op as { props?: unknown }).props;
119
+ return (declared && typeof declared === "object" ? declared : op) as OpConfig;
120
+ }
121
+
122
+ function checkForm(steward: string, form: unknown, where: string): StewardForm {
123
+ if (!STEWARD_FORMS.includes(form as StewardForm)) {
124
+ throw new Error(`Steward "${steward}": ${where} is ${JSON.stringify(form)}; a steward's form is "local" or "fountain"`);
125
+ }
126
+ return form as StewardForm;
127
+ }
128
+
129
+ /** Normalise a form spec, refusing an unknown form or an environment name no ledger could hold. */
130
+ export function normaliseStewardForm(steward: string, spec: StewardFormSpec | undefined): StewardDeclaration["form"] {
131
+ if (spec === undefined) return { default: "local", environments: {} };
132
+ if (typeof spec === "string") return { default: checkForm(steward, spec, "form"), environments: {} };
133
+ const environments: Record<string, StewardForm> = {};
134
+ for (const [env, form] of Object.entries(spec.environments ?? {})) {
135
+ if (!STEWARD_NAME_PATTERN.test(env) || env.includes("..")) {
136
+ throw new Error(`Steward "${steward}": form.environments names ${JSON.stringify(env)}, which can't be an environment`);
137
+ }
138
+ environments[env] = checkForm(steward, form, `form.environments[${JSON.stringify(env)}]`);
139
+ }
140
+ return { default: checkForm(steward, spec.default, "form.default"), environments };
141
+ }
142
+
143
+ /**
144
+ * Declare a steward. Refuses what would make it more than one writer or a
145
+ * promise it can't keep: an Op listed twice, a schedule whose overlap isn't
146
+ * `skip` (a fire while a turn runs is dropped in both forms), a cron that
147
+ * doesn't parse, and a name a lease ref can't hold.
148
+ */
149
+ export function declareSteward(config: StewardDeclarationConfig): StewardDeclaration {
150
+ const name = config.name;
151
+ if (!STEWARD_NAME_PATTERN.test(name) || name.includes("..")) {
152
+ throw new Error(
153
+ `Steward ${JSON.stringify(name)}: a steward's name is letters, digits, ".", "_" and "-", starting with a letter or digit`,
154
+ );
155
+ }
156
+ const ops = config.ops.map(stewardOpConfig);
157
+ const seen = new Set<string>();
158
+ for (const op of ops) {
159
+ if (!op || typeof op.name !== "string" || !Array.isArray(op.phases)) {
160
+ throw new Error(`Steward "${name}": every entry in ops must be an Op`);
161
+ }
162
+ if (seen.has(op.name)) throw new Error(`Steward "${name}": op "${op.name}" is listed twice`);
163
+ seen.add(op.name);
164
+ // An Op that changes the checkout runs under a work item's lease, on a
165
+ // branch of its own (#2748): one that doesn't declare the lease, or
166
+ // declares it badly, is refused here as the executor would refuse it.
167
+ const leaseProblems = workLeaseProblems(op);
168
+ if (leaseProblems.length > 0) throw new Error(`Steward "${name}": ${leaseProblems.join("; ")}`);
169
+ if (op.schedule && workLeaseNeedsRunItem(op)) {
170
+ throw new Error(
171
+ `Steward "${name}": op "${op.name}" is scheduled, but its workLease names no item, and a scheduled run can't be given one. ` +
172
+ `Name the item, candidates, or the step whose output picks it.`,
173
+ );
174
+ }
175
+ const schedule = op.schedule;
176
+ if (!schedule) continue;
177
+ if (!isValidCronExpression(schedule.cron)) {
178
+ throw new Error(`Steward "${name}": op "${op.name}": ${cronSyntaxMessage(schedule.cron)}`);
179
+ }
180
+ if (schedule.overlap !== undefined && schedule.overlap !== "skip") {
181
+ throw new Error(
182
+ `Steward "${name}": op "${op.name}" schedules overlap "${schedule.overlap}". ` +
183
+ `A fire while the steward is busy is dropped, so "skip" is the only policy a steward can honour.`,
184
+ );
185
+ }
186
+ }
187
+ const capabilities = [...new Set(config.capabilities ?? [])];
188
+ for (const c of capabilities) {
189
+ if (typeof c !== "string" || c.trim() === "") throw new Error(`Steward "${name}": a capability is named by a non-empty string`);
190
+ }
191
+ const vault = config.vault ?? null;
192
+ if (vault !== null && capabilities.length > 0) {
193
+ throw new Error(
194
+ `Steward "${name}": it reaches ${capabilities.join(", ")} through the box's broker and also holds the vault "${vault}". ` +
195
+ `A brokered steward holds no credential of its own: drop the vault, or name no capabilities.`,
196
+ );
197
+ }
198
+ return Object.freeze({
199
+ kind: STEWARD_KIND,
200
+ name,
201
+ ops: Object.freeze([...ops]),
202
+ form: normaliseStewardForm(name, config.form),
203
+ capabilities: Object.freeze(capabilities),
204
+ vault,
205
+ });
206
+ }
207
+
208
+ /** Is this value a steward declaration? Duck-typed, like `isOpEntity`. */
209
+ export function isStewardDeclaration(value: unknown): value is StewardDeclaration {
210
+ if (!value || typeof value !== "object") return false;
211
+ const v = value as Partial<StewardDeclaration>;
212
+ return (
213
+ v.kind === STEWARD_KIND &&
214
+ typeof v.name === "string" &&
215
+ Array.isArray(v.ops) &&
216
+ !!v.form &&
217
+ typeof v.form === "object" &&
218
+ typeof v.form.default === "string"
219
+ );
220
+ }
221
+
222
+ /** The form a steward takes in `env` (`local` when none is named). */
223
+ export function stewardFormFor(steward: StewardDeclaration, env: string = DEFAULT_STEWARD_ENV): StewardForm {
224
+ return steward.form.environments[env] ?? steward.form.default;
225
+ }
226
+
227
+ /**
228
+ * The lease a local steward holds for as long as it runs, so a second
229
+ * `chant operator --steward` for the same steward is refused. It sits under
230
+ * `refs/chant/lease/_stewards/`, beside the per-Op leases, which a leading
231
+ * `_` keeps out of any Op's name.
232
+ */
233
+ export function stewardLeaseName(steward: string): string {
234
+ return `_stewards/${steward}`;
235
+ }
236
+
237
+ /**
238
+ * The lease a local steward holds for as long as one of its Ops is actually
239
+ * running: one turn (#2750). Distinct from {@link stewardLeaseName}, which one
240
+ * `chant operator --steward` process holds for its whole life (renewed
241
+ * between ticks, released only when the process stops) — this one is taken
242
+ * right before a run starts and released right after it ends, whether the
243
+ * run is a round's scheduled tick or `chant run <op>` typed by hand. That is
244
+ * what makes an on-request run wait its turn behind a turn already in
245
+ * progress, and succeed again the moment that turn ends, rather than only
246
+ * once the whole steward process stops.
247
+ *
248
+ * `_turns/<name>`, not `_stewards/<name>/turn`: a git ref name is a path
249
+ * component in the loose-refs tree, and `refs/chant/lease/_stewards/<name>`
250
+ * (the lease {@link stewardLeaseName} names) already exists as a *leaf* —
251
+ * git refuses to also create anything *under* it (`fatal: ... exists;
252
+ * cannot create ...`), so nesting the turn lease inside the steward lease's
253
+ * own name is unusable the moment both are live at once. A sibling
254
+ * top-level segment sidesteps that entirely.
255
+ */
256
+ export function stewardTurnLeaseName(steward: string): string {
257
+ return `_turns/${steward}`;
258
+ }
259
+
260
+ /**
261
+ * Pick the steward `--steward [<name>]` names, or the project's only one.
262
+ * Returns the steward, or the message to refuse with.
263
+ */
264
+ export function pickSteward(
265
+ stewards: Map<string, { declaration: StewardDeclaration }>,
266
+ name: string,
267
+ ): StewardDeclaration | string {
268
+ if (name) {
269
+ const found = stewards.get(name);
270
+ if (found) return found.declaration;
271
+ const known = [...stewards.keys()].sort();
272
+ return `No steward "${name}" is declared` + (known.length ? ` (declared: ${known.join(", ")})` : " (no *.op.ts file exports one)");
273
+ }
274
+ if (stewards.size === 1) return [...stewards.values()][0].declaration;
275
+ if (stewards.size === 0) return "No steward is declared: export declareSteward({...}) (or the fountain Steward's declaration) from an *.op.ts file";
276
+ return `${stewards.size} stewards are declared (${[...stewards.keys()].sort().join(", ")}); name one with --steward <name>`;
277
+ }
package/src/op/types.ts CHANGED
@@ -42,6 +42,59 @@ export interface OpConfig {
42
42
  * local one-shot executor ignores it.
43
43
  */
44
44
  schedule?: OpSchedule;
45
+ /**
46
+ * The work item this Op runs under (#2748, ws-055). The executor claims the
47
+ * item's work lease (`../lifecycle/work-lease.ts`) before the steps that run
48
+ * under it, renews it as a heartbeat while they run, stops the run when the
49
+ * lease is lost, and gives it back when the run ends. See
50
+ * {@link OpWorkLease} and `./work-lease-run.ts`.
51
+ */
52
+ workLease?: OpWorkLease;
53
+ /**
54
+ * The Op changes the checkout: it applies a build, or upgrades the
55
+ * workspace (#2748). Such an Op must declare {@link OpConfig.workLease}: the
56
+ * executor refuses to run it otherwise, and `declareSteward` refuses to list
57
+ * it. Its leased steps get a git worktree of their own, on the branch
58
+ * `chant/work/<item>`, so the change never lands in the working tree a
59
+ * coding agent is editing.
60
+ */
61
+ changesCheckout?: boolean;
62
+ }
63
+
64
+ /**
65
+ * The id under which a run's work lease is published to its steps (#2748):
66
+ * `stepOutput(WORK_LEASE_STEP_ID, "token")`, or `workLeaseOutput("token")`
67
+ * from `./work-lease-run.ts`. No step of an Op with a `workLease` may use it.
68
+ */
69
+ export const WORK_LEASE_STEP_ID = "workLease";
70
+
71
+ /**
72
+ * Which work item an Op runs under, and how (#2748).
73
+ *
74
+ * `item` is an id, a list of candidate ids (the first one nobody holds is
75
+ * claimed, as chud's dispatcher took the first ready contract nobody held), a
76
+ * reference to an earlier step's output that resolves to either, or omitted,
77
+ * in which case the run names it (`chant run <op> --work <id>`). A literal or
78
+ * run-time item is claimed before the first step; a referenced one right
79
+ * after the step that produces it. A run that finds nothing to claim (the
80
+ * reference resolved to nothing, or every candidate is held) ends `ok` with
81
+ * the rest of its steps skipped, and the claim's record says why.
82
+ */
83
+ export interface OpWorkLease {
84
+ item?: string | string[] | StepOutputRef;
85
+ /**
86
+ * The work kind file whose member owns the lease (#2524 D7), relative to
87
+ * the project directory. Omitted, the lease is in the project's own ledger.
88
+ */
89
+ kind?: string;
90
+ /** How long a claim lasts unless renewed, as a duration ("10m"). Renewed every third of it. Default 10m. */
91
+ ttl?: string;
92
+ /**
93
+ * How the release records a run that ended `ok`: a reference to a step
94
+ * output holding a short string (`done`, `not_done`, ...). Default `done`;
95
+ * a failed run releases `not_done` and a gated one `gated`.
96
+ */
97
+ outcome?: StepOutputRef;
45
98
  }
46
99
 
47
100
  /**
@@ -100,6 +153,13 @@ export interface ActivityStep {
100
153
  * Default: "fastIdempotent"
101
154
  */
102
155
  profile?: ActivityProfileName;
156
+ /**
157
+ * How long one attempt may run, such as `"45m"`, in place of the
158
+ * profile's timeout (#2787). The profile's retry policy is kept, so a
159
+ * `shell` step stays one attempt. At most `MAX_STEP_TIMEOUT` (six hours); a longer
160
+ * wait is a gate, not a step.
161
+ */
162
+ timeout?: string;
103
163
  /**
104
164
  * Surface this activity's return value as a named run outcome.
105
165
  *
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The rules an Op's `workLease` and `changesCheckout` declaration keeps
3
+ * (#2748), with no imports beyond the Op model, so `Op()` and
4
+ * `declareSteward` can check them without loading the lease machinery in
5
+ * `./work-lease-run.ts`.
6
+ */
7
+
8
+ import { isStepOutputRef } from "./step-output-ref";
9
+ import { parseDuration } from "./duration";
10
+ import { WORK_LEASE_STEP_ID, type OpConfig, type PhaseDefinition } from "./types";
11
+
12
+ /** A work item id a lease can be keyed by: the same pattern as `WORK_ITEM_ID_PATTERN` in `../lifecycle/work-lease.ts`. */
13
+ export const WORK_LEASE_ITEM_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
14
+
15
+ /** The ids of the activity steps in an Op's main phases, in order. */
16
+ function mainStepIds(phases: readonly PhaseDefinition[]): string[] {
17
+ const ids: string[] = [];
18
+ for (const phase of phases) {
19
+ for (const step of phase.steps) if (step.kind === "activity" && step.id) ids.push(step.id);
20
+ }
21
+ return ids;
22
+ }
23
+
24
+ /**
25
+ * What is wrong with an Op's `workLease` and `changesCheckout`, or an empty
26
+ * list. The executor refuses to start a run with any of these, and
27
+ * `declareSteward` refuses to list the Op.
28
+ */
29
+ export function workLeaseProblems(config: Pick<OpConfig, "name" | "phases" | "workLease" | "changesCheckout">): string[] {
30
+ const problems: string[] = [];
31
+ const spec = config.workLease;
32
+ const name = config.name;
33
+ if (config.changesCheckout && !spec) {
34
+ problems.push(
35
+ `Op "${name}" changes the checkout but declares no workLease. A change to the checkout happens under a work item's lease, ` +
36
+ `on a branch of its own: declare workLease on the Op.`,
37
+ );
38
+ }
39
+ if (!spec) return problems;
40
+ const ids = mainStepIds(config.phases ?? []);
41
+ if (ids.includes(WORK_LEASE_STEP_ID)) {
42
+ problems.push(`Op "${name}": step id "${WORK_LEASE_STEP_ID}" is reserved for the run's work lease; rename the step`);
43
+ }
44
+ const checkId = (id: unknown) => {
45
+ if (typeof id !== "string" || !WORK_LEASE_ITEM_PATTERN.test(id) || id.includes("..")) {
46
+ problems.push(`Op "${name}": workLease.item ${JSON.stringify(id)} can't key a work lease (letters, digits, ".", "_" and "-")`);
47
+ }
48
+ };
49
+ const item = spec.item;
50
+ if (isStepOutputRef(item)) {
51
+ if (!ids.includes(item.step)) {
52
+ problems.push(`Op "${name}": workLease.item references step "${item.step}", which no activity step in the Op's phases declares`);
53
+ }
54
+ } else if (Array.isArray(item)) {
55
+ if (item.length === 0) problems.push(`Op "${name}": workLease.item is an empty list`);
56
+ item.forEach(checkId);
57
+ } else if (item !== undefined) {
58
+ checkId(item);
59
+ }
60
+ if (spec.ttl !== undefined) {
61
+ try {
62
+ if (parseDuration(spec.ttl) < 3_000) problems.push(`Op "${name}": workLease.ttl "${spec.ttl}" is shorter than 3s`);
63
+ } catch (err) {
64
+ problems.push(`Op "${name}": workLease.ttl: ${err instanceof Error ? err.message : String(err)}`);
65
+ }
66
+ }
67
+ if (spec.outcome !== undefined && !isStepOutputRef(spec.outcome)) {
68
+ problems.push(`Op "${name}": workLease.outcome is a reference to a step's output`);
69
+ }
70
+ if (spec.kind !== undefined && (typeof spec.kind !== "string" || spec.kind.trim() === "")) {
71
+ problems.push(`Op "${name}": workLease.kind names a work kind file`);
72
+ }
73
+ return problems;
74
+ }
75
+
76
+ /** Whether a run of this Op has to be told its work item (`--work <id>`). */
77
+ export function workLeaseNeedsRunItem(config: Pick<OpConfig, "workLease">): boolean {
78
+ return config.workLease !== undefined && config.workLease.item === undefined;
79
+ }
80
+