@xemahq/dsl 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/LICENSE +201 -0
  2. package/dist/deliverable-spec/index.d.ts +3 -0
  3. package/dist/deliverable-spec/index.d.ts.map +1 -0
  4. package/dist/deliverable-spec/index.js +19 -0
  5. package/dist/deliverable-spec/index.js.map +1 -0
  6. package/dist/deliverable-spec/lib/schema.d.ts +151 -0
  7. package/dist/deliverable-spec/lib/schema.d.ts.map +1 -0
  8. package/dist/deliverable-spec/lib/schema.js +139 -0
  9. package/dist/deliverable-spec/lib/schema.js.map +1 -0
  10. package/dist/deliverable-spec/lib/types.d.ts +8 -0
  11. package/dist/deliverable-spec/lib/types.d.ts.map +1 -0
  12. package/dist/deliverable-spec/lib/types.js +3 -0
  13. package/dist/deliverable-spec/lib/types.js.map +1 -0
  14. package/dist/payload-codec/index.d.ts +8 -0
  15. package/dist/payload-codec/index.d.ts.map +1 -0
  16. package/dist/payload-codec/index.js +27 -0
  17. package/dist/payload-codec/index.js.map +1 -0
  18. package/dist/payload-codec/lib/blob-store.d.ts +37 -0
  19. package/dist/payload-codec/lib/blob-store.d.ts.map +1 -0
  20. package/dist/payload-codec/lib/blob-store.js +0 -0
  21. package/dist/payload-codec/lib/blob-store.js.map +1 -0
  22. package/dist/payload-codec/lib/codec-context.d.ts +6 -0
  23. package/dist/payload-codec/lib/codec-context.d.ts.map +1 -0
  24. package/dist/payload-codec/lib/codec-context.js +16 -0
  25. package/dist/payload-codec/lib/codec-context.js.map +1 -0
  26. package/dist/payload-codec/lib/codec.d.ts +51 -0
  27. package/dist/payload-codec/lib/codec.d.ts.map +1 -0
  28. package/dist/payload-codec/lib/codec.js +330 -0
  29. package/dist/payload-codec/lib/codec.js.map +1 -0
  30. package/dist/payload-codec/lib/enums.d.ts +18 -0
  31. package/dist/payload-codec/lib/enums.d.ts.map +1 -0
  32. package/dist/payload-codec/lib/enums.js +23 -0
  33. package/dist/payload-codec/lib/enums.js.map +1 -0
  34. package/dist/payload-codec/lib/errors.d.ts +18 -0
  35. package/dist/payload-codec/lib/errors.d.ts.map +1 -0
  36. package/dist/payload-codec/lib/errors.js +39 -0
  37. package/dist/payload-codec/lib/errors.js.map +1 -0
  38. package/dist/payload-codec/lib/http-blob-store.d.ts +21 -0
  39. package/dist/payload-codec/lib/http-blob-store.d.ts.map +1 -0
  40. package/dist/payload-codec/lib/http-blob-store.js +139 -0
  41. package/dist/payload-codec/lib/http-blob-store.js.map +1 -0
  42. package/dist/payload-codec/lib/lru-cache.d.ts +12 -0
  43. package/dist/payload-codec/lib/lru-cache.d.ts.map +1 -0
  44. package/dist/payload-codec/lib/lru-cache.js +59 -0
  45. package/dist/payload-codec/lib/lru-cache.js.map +1 -0
  46. package/dist/schema/action.schema.json +181 -0
  47. package/dist/schema/reusable-workflow.schema.json +46 -0
  48. package/dist/schema/workflow.schema.json +373 -0
  49. package/dist/workflow/index.d.ts +14 -0
  50. package/dist/workflow/index.d.ts.map +1 -0
  51. package/dist/workflow/index.js +49 -0
  52. package/dist/workflow/index.js.map +1 -0
  53. package/dist/workflow/lib/action-input-validator.d.ts +10 -0
  54. package/dist/workflow/lib/action-input-validator.d.ts.map +1 -0
  55. package/dist/workflow/lib/action-input-validator.js +69 -0
  56. package/dist/workflow/lib/action-input-validator.js.map +1 -0
  57. package/dist/workflow/lib/compiler/action-shape.d.ts +5 -0
  58. package/dist/workflow/lib/compiler/action-shape.d.ts.map +1 -0
  59. package/dist/workflow/lib/compiler/action-shape.js +43 -0
  60. package/dist/workflow/lib/compiler/action-shape.js.map +1 -0
  61. package/dist/workflow/lib/compiler/canonical-json.d.ts +3 -0
  62. package/dist/workflow/lib/compiler/canonical-json.d.ts.map +1 -0
  63. package/dist/workflow/lib/compiler/canonical-json.js +45 -0
  64. package/dist/workflow/lib/compiler/canonical-json.js.map +1 -0
  65. package/dist/workflow/lib/compiler/compile.d.ts +4 -0
  66. package/dist/workflow/lib/compiler/compile.d.ts.map +1 -0
  67. package/dist/workflow/lib/compiler/compile.js +794 -0
  68. package/dist/workflow/lib/compiler/compile.js.map +1 -0
  69. package/dist/workflow/lib/compiler/concurrency.d.ts +5 -0
  70. package/dist/workflow/lib/compiler/concurrency.d.ts.map +1 -0
  71. package/dist/workflow/lib/compiler/concurrency.js +104 -0
  72. package/dist/workflow/lib/compiler/concurrency.js.map +1 -0
  73. package/dist/workflow/lib/compiler/dag.d.ts +10 -0
  74. package/dist/workflow/lib/compiler/dag.d.ts.map +1 -0
  75. package/dist/workflow/lib/compiler/dag.js +74 -0
  76. package/dist/workflow/lib/compiler/dag.js.map +1 -0
  77. package/dist/workflow/lib/compiler/index.d.ts +6 -0
  78. package/dist/workflow/lib/compiler/index.d.ts.map +1 -0
  79. package/dist/workflow/lib/compiler/index.js +14 -0
  80. package/dist/workflow/lib/compiler/index.js.map +1 -0
  81. package/dist/workflow/lib/compiler/inputs.d.ts +4 -0
  82. package/dist/workflow/lib/compiler/inputs.d.ts.map +1 -0
  83. package/dist/workflow/lib/compiler/inputs.js +108 -0
  84. package/dist/workflow/lib/compiler/inputs.js.map +1 -0
  85. package/dist/workflow/lib/compiler/installation-resource-validator.d.ts +9 -0
  86. package/dist/workflow/lib/compiler/installation-resource-validator.d.ts.map +1 -0
  87. package/dist/workflow/lib/compiler/installation-resource-validator.js +76 -0
  88. package/dist/workflow/lib/compiler/installation-resource-validator.js.map +1 -0
  89. package/dist/workflow/lib/compiler/manifest-source.d.ts +4 -0
  90. package/dist/workflow/lib/compiler/manifest-source.d.ts.map +1 -0
  91. package/dist/workflow/lib/compiler/manifest-source.js +100 -0
  92. package/dist/workflow/lib/compiler/manifest-source.js.map +1 -0
  93. package/dist/workflow/lib/compiler/matrix.d.ts +4 -0
  94. package/dist/workflow/lib/compiler/matrix.d.ts.map +1 -0
  95. package/dist/workflow/lib/compiler/matrix.js +76 -0
  96. package/dist/workflow/lib/compiler/matrix.js.map +1 -0
  97. package/dist/workflow/lib/compiler/mount-plan.d.ts +4 -0
  98. package/dist/workflow/lib/compiler/mount-plan.d.ts.map +1 -0
  99. package/dist/workflow/lib/compiler/mount-plan.js +96 -0
  100. package/dist/workflow/lib/compiler/mount-plan.js.map +1 -0
  101. package/dist/workflow/lib/compiler/payload-reach-in.d.ts +14 -0
  102. package/dist/workflow/lib/compiler/payload-reach-in.d.ts.map +1 -0
  103. package/dist/workflow/lib/compiler/payload-reach-in.js +273 -0
  104. package/dist/workflow/lib/compiler/payload-reach-in.js.map +1 -0
  105. package/dist/workflow/lib/compiler/permissions.d.ts +6 -0
  106. package/dist/workflow/lib/compiler/permissions.d.ts.map +1 -0
  107. package/dist/workflow/lib/compiler/permissions.js +43 -0
  108. package/dist/workflow/lib/compiler/permissions.js.map +1 -0
  109. package/dist/workflow/lib/compiler/retry-timeout.d.ts +6 -0
  110. package/dist/workflow/lib/compiler/retry-timeout.d.ts.map +1 -0
  111. package/dist/workflow/lib/compiler/retry-timeout.js +64 -0
  112. package/dist/workflow/lib/compiler/retry-timeout.js.map +1 -0
  113. package/dist/workflow/lib/compiler/review-step.d.ts +18 -0
  114. package/dist/workflow/lib/compiler/review-step.d.ts.map +1 -0
  115. package/dist/workflow/lib/compiler/review-step.js +247 -0
  116. package/dist/workflow/lib/compiler/review-step.js.map +1 -0
  117. package/dist/workflow/lib/compiler/types.d.ts +42 -0
  118. package/dist/workflow/lib/compiler/types.d.ts.map +1 -0
  119. package/dist/workflow/lib/compiler/types.js +3 -0
  120. package/dist/workflow/lib/compiler/types.js.map +1 -0
  121. package/dist/workflow/lib/compiler/variable-requirements.d.ts +5 -0
  122. package/dist/workflow/lib/compiler/variable-requirements.d.ts.map +1 -0
  123. package/dist/workflow/lib/compiler/variable-requirements.js +119 -0
  124. package/dist/workflow/lib/compiler/variable-requirements.js.map +1 -0
  125. package/dist/workflow/lib/deliverable-spec-keys.d.ts +3 -0
  126. package/dist/workflow/lib/deliverable-spec-keys.d.ts.map +1 -0
  127. package/dist/workflow/lib/deliverable-spec-keys.js +90 -0
  128. package/dist/workflow/lib/deliverable-spec-keys.js.map +1 -0
  129. package/dist/workflow/lib/dispatch-inputs/index.d.ts +23 -0
  130. package/dist/workflow/lib/dispatch-inputs/index.d.ts.map +1 -0
  131. package/dist/workflow/lib/dispatch-inputs/index.js +106 -0
  132. package/dist/workflow/lib/dispatch-inputs/index.js.map +1 -0
  133. package/dist/workflow/lib/dispatch-inputs/to-json-schema.d.ts +3 -0
  134. package/dist/workflow/lib/dispatch-inputs/to-json-schema.d.ts.map +1 -0
  135. package/dist/workflow/lib/dispatch-inputs/to-json-schema.js +43 -0
  136. package/dist/workflow/lib/dispatch-inputs/to-json-schema.js.map +1 -0
  137. package/dist/workflow/lib/duration.d.ts +2 -0
  138. package/dist/workflow/lib/duration.d.ts.map +1 -0
  139. package/dist/workflow/lib/duration.js +26 -0
  140. package/dist/workflow/lib/duration.js.map +1 -0
  141. package/dist/workflow/lib/errors.d.ts +9 -0
  142. package/dist/workflow/lib/errors.d.ts.map +1 -0
  143. package/dist/workflow/lib/errors.js +28 -0
  144. package/dist/workflow/lib/errors.js.map +1 -0
  145. package/dist/workflow/lib/expression/ast.d.ts +61 -0
  146. package/dist/workflow/lib/expression/ast.d.ts.map +1 -0
  147. package/dist/workflow/lib/expression/ast.js +34 -0
  148. package/dist/workflow/lib/expression/ast.js.map +1 -0
  149. package/dist/workflow/lib/expression/context.d.ts +63 -0
  150. package/dist/workflow/lib/expression/context.d.ts.map +1 -0
  151. package/dist/workflow/lib/expression/context.js +32 -0
  152. package/dist/workflow/lib/expression/context.js.map +1 -0
  153. package/dist/workflow/lib/expression/evaluator.d.ts +5 -0
  154. package/dist/workflow/lib/expression/evaluator.d.ts.map +1 -0
  155. package/dist/workflow/lib/expression/evaluator.js +291 -0
  156. package/dist/workflow/lib/expression/evaluator.js.map +1 -0
  157. package/dist/workflow/lib/expression/index.d.ts +9 -0
  158. package/dist/workflow/lib/expression/index.d.ts.map +1 -0
  159. package/dist/workflow/lib/expression/index.js +26 -0
  160. package/dist/workflow/lib/expression/index.js.map +1 -0
  161. package/dist/workflow/lib/expression/interpolation.d.ts +9 -0
  162. package/dist/workflow/lib/expression/interpolation.d.ts.map +1 -0
  163. package/dist/workflow/lib/expression/interpolation.js +51 -0
  164. package/dist/workflow/lib/expression/interpolation.js.map +1 -0
  165. package/dist/workflow/lib/expression/parser.d.ts +4 -0
  166. package/dist/workflow/lib/expression/parser.d.ts.map +1 -0
  167. package/dist/workflow/lib/expression/parser.js +203 -0
  168. package/dist/workflow/lib/expression/parser.js.map +1 -0
  169. package/dist/workflow/lib/expression/template.d.ts +18 -0
  170. package/dist/workflow/lib/expression/template.d.ts.map +1 -0
  171. package/dist/workflow/lib/expression/template.js +63 -0
  172. package/dist/workflow/lib/expression/template.js.map +1 -0
  173. package/dist/workflow/lib/expression/tokenizer.d.ts +3 -0
  174. package/dist/workflow/lib/expression/tokenizer.d.ts.map +1 -0
  175. package/dist/workflow/lib/expression/tokenizer.js +153 -0
  176. package/dist/workflow/lib/expression/tokenizer.js.map +1 -0
  177. package/dist/workflow/lib/expression/tokens.d.ts +25 -0
  178. package/dist/workflow/lib/expression/tokens.d.ts.map +1 -0
  179. package/dist/workflow/lib/expression/tokens.js +24 -0
  180. package/dist/workflow/lib/expression/tokens.js.map +1 -0
  181. package/dist/workflow/lib/expression/walk-artifact-refs.d.ts +5 -0
  182. package/dist/workflow/lib/expression/walk-artifact-refs.d.ts.map +1 -0
  183. package/dist/workflow/lib/expression/walk-artifact-refs.js +138 -0
  184. package/dist/workflow/lib/expression/walk-artifact-refs.js.map +1 -0
  185. package/dist/workflow/lib/installation-resource-kind.d.ts +14 -0
  186. package/dist/workflow/lib/installation-resource-kind.d.ts.map +1 -0
  187. package/dist/workflow/lib/installation-resource-kind.js +59 -0
  188. package/dist/workflow/lib/installation-resource-kind.js.map +1 -0
  189. package/dist/workflow/lib/schemas-loader.d.ts +4 -0
  190. package/dist/workflow/lib/schemas-loader.d.ts.map +1 -0
  191. package/dist/workflow/lib/schemas-loader.js +36 -0
  192. package/dist/workflow/lib/schemas-loader.js.map +1 -0
  193. package/dist/workflow/lib/serializer.d.ts +3 -0
  194. package/dist/workflow/lib/serializer.d.ts.map +1 -0
  195. package/dist/workflow/lib/serializer.js +15 -0
  196. package/dist/workflow/lib/serializer.js.map +1 -0
  197. package/dist/workflow/lib/types.d.ts +179 -0
  198. package/dist/workflow/lib/types.d.ts.map +1 -0
  199. package/dist/workflow/lib/types.js +3 -0
  200. package/dist/workflow/lib/types.js.map +1 -0
  201. package/dist/workflow/lib/validate.d.ts +8 -0
  202. package/dist/workflow/lib/validate.d.ts.map +1 -0
  203. package/dist/workflow/lib/validate.js +119 -0
  204. package/dist/workflow/lib/validate.js.map +1 -0
  205. package/dist/workspace-manifest/index.d.ts +6 -0
  206. package/dist/workspace-manifest/index.d.ts.map +1 -0
  207. package/dist/workspace-manifest/index.js +22 -0
  208. package/dist/workspace-manifest/index.js.map +1 -0
  209. package/dist/workspace-manifest/lib/compile.d.ts +8 -0
  210. package/dist/workspace-manifest/lib/compile.d.ts.map +1 -0
  211. package/dist/workspace-manifest/lib/compile.js +439 -0
  212. package/dist/workspace-manifest/lib/compile.js.map +1 -0
  213. package/dist/workspace-manifest/lib/interpolate.d.ts +12 -0
  214. package/dist/workspace-manifest/lib/interpolate.d.ts.map +1 -0
  215. package/dist/workspace-manifest/lib/interpolate.js +81 -0
  216. package/dist/workspace-manifest/lib/interpolate.js.map +1 -0
  217. package/dist/workspace-manifest/lib/resolve-extends.d.ts +10 -0
  218. package/dist/workspace-manifest/lib/resolve-extends.d.ts.map +1 -0
  219. package/dist/workspace-manifest/lib/resolve-extends.js +108 -0
  220. package/dist/workspace-manifest/lib/resolve-extends.js.map +1 -0
  221. package/dist/workspace-manifest/lib/schema.d.ts +710 -0
  222. package/dist/workspace-manifest/lib/schema.d.ts.map +1 -0
  223. package/dist/workspace-manifest/lib/schema.js +355 -0
  224. package/dist/workspace-manifest/lib/schema.js.map +1 -0
  225. package/dist/workspace-manifest/lib/types.d.ts +153 -0
  226. package/dist/workspace-manifest/lib/types.d.ts.map +1 -0
  227. package/dist/workspace-manifest/lib/types.js +10 -0
  228. package/dist/workspace-manifest/lib/types.js.map +1 -0
  229. package/package.json +79 -0
  230. package/schema/action.schema.json +181 -0
  231. package/schema/reusable-workflow.schema.json +46 -0
  232. package/schema/workflow.schema.json +373 -0
  233. package/src/deliverable-spec/index.ts +19 -0
  234. package/src/deliverable-spec/lib/schema.ts +248 -0
  235. package/src/deliverable-spec/lib/types.ts +26 -0
  236. package/src/payload-codec/index.ts +40 -0
  237. package/src/payload-codec/lib/blob-store.ts +0 -0
  238. package/src/payload-codec/lib/codec-context.ts +38 -0
  239. package/src/payload-codec/lib/codec.ts +593 -0
  240. package/src/payload-codec/lib/enums.ts +58 -0
  241. package/src/payload-codec/lib/errors.ts +54 -0
  242. package/src/payload-codec/lib/http-blob-store.ts +257 -0
  243. package/src/payload-codec/lib/lru-cache.ts +81 -0
  244. package/src/workflow/index.ts +98 -0
  245. package/src/workflow/lib/action-input-validator.ts +160 -0
  246. package/src/workflow/lib/compiler/action-shape.ts +71 -0
  247. package/src/workflow/lib/compiler/canonical-json.ts +53 -0
  248. package/src/workflow/lib/compiler/compile.ts +1518 -0
  249. package/src/workflow/lib/compiler/concurrency.ts +223 -0
  250. package/src/workflow/lib/compiler/dag.ts +108 -0
  251. package/src/workflow/lib/compiler/index.ts +10 -0
  252. package/src/workflow/lib/compiler/inputs.ts +199 -0
  253. package/src/workflow/lib/compiler/installation-resource-validator.ts +114 -0
  254. package/src/workflow/lib/compiler/manifest-source.ts +176 -0
  255. package/src/workflow/lib/compiler/matrix.ts +135 -0
  256. package/src/workflow/lib/compiler/mount-plan.ts +202 -0
  257. package/src/workflow/lib/compiler/payload-reach-in.ts +497 -0
  258. package/src/workflow/lib/compiler/permissions.ts +64 -0
  259. package/src/workflow/lib/compiler/retry-timeout.ts +105 -0
  260. package/src/workflow/lib/compiler/review-step.ts +517 -0
  261. package/src/workflow/lib/compiler/types.ts +170 -0
  262. package/src/workflow/lib/compiler/variable-requirements.ts +208 -0
  263. package/src/workflow/lib/deliverable-spec-keys.ts +109 -0
  264. package/src/workflow/lib/dispatch-inputs/index.ts +160 -0
  265. package/src/workflow/lib/dispatch-inputs/to-json-schema.ts +60 -0
  266. package/src/workflow/lib/duration.ts +48 -0
  267. package/src/workflow/lib/errors.ts +37 -0
  268. package/src/workflow/lib/expression/ast.ts +108 -0
  269. package/src/workflow/lib/expression/context.ts +148 -0
  270. package/src/workflow/lib/expression/evaluator.ts +492 -0
  271. package/src/workflow/lib/expression/index.ts +28 -0
  272. package/src/workflow/lib/expression/interpolation.ts +84 -0
  273. package/src/workflow/lib/expression/parser.ts +264 -0
  274. package/src/workflow/lib/expression/template.ts +117 -0
  275. package/src/workflow/lib/expression/tokenizer.ts +200 -0
  276. package/src/workflow/lib/expression/tokens.ts +30 -0
  277. package/src/workflow/lib/expression/walk-artifact-refs.ts +232 -0
  278. package/src/workflow/lib/installation-resource-kind.ts +107 -0
  279. package/src/workflow/lib/schemas-loader.ts +64 -0
  280. package/src/workflow/lib/serializer.ts +30 -0
  281. package/src/workflow/lib/types.ts +361 -0
  282. package/src/workflow/lib/validate.ts +199 -0
  283. package/src/workspace-manifest/index.ts +27 -0
  284. package/src/workspace-manifest/lib/compile.ts +608 -0
  285. package/src/workspace-manifest/lib/interpolate.ts +140 -0
  286. package/src/workspace-manifest/lib/resolve-extends.ts +260 -0
  287. package/src/workspace-manifest/lib/schema.ts +612 -0
  288. package/src/workspace-manifest/lib/types.ts +392 -0
@@ -0,0 +1,517 @@
1
+ /**
2
+ * Compile-time helpers for `xema/review@*` steps.
3
+ *
4
+ * The review action's author surface is intentionally small:
5
+ *
6
+ * uses: xema/review@<semver>
7
+ * needs: [<producer>]
8
+ * with:
9
+ * subject: ${{ needs.<producer>.outputs.deliverable }} # or an array
10
+ * redraft: { step: <producer> } # optional
11
+ * reviewers: [...]
12
+ * policy: { kind: ... }
13
+ * iterationTimeoutSeconds: ...
14
+ * onIterationTimeout: ...
15
+ *
16
+ * The worker contract on `reviewWorkflow` is different: it expects
17
+ * `subjects: unknown[]` (always-array) and `redraft: { uses, with }`
18
+ * (embedded action invocation, not a step ref). This module bridges
19
+ * the two:
20
+ *
21
+ * 1. `validateReviewSteps` — throws on bad author shapes BEFORE
22
+ * anything else compiles. Catches missing/dangling step refs,
23
+ * shape mismatches, and the forbidden `redraft set without
24
+ * subject` combination.
25
+ *
26
+ * 2. `computeReviewNeedsExtensions` — returns a map of
27
+ * `reviewJobKey → string[]` of extra needs the compiler must add
28
+ * so the review step's expression context (built from `needs:` at
29
+ * dispatch) can resolve every `${{ needs.* }}` reference embedded
30
+ * in the redraft step's inherited `with:` block. Authors don't
31
+ * have to repeat the producer's transitive needs by hand.
32
+ *
33
+ * 3. `rewriteReviewStepWith` — produces the IR `with:` for a review
34
+ * step: `subject` normalized to `subjects: unknown[]`, and
35
+ * `redraft.step` resolved into the named producer's
36
+ * `{ uses, with }`.
37
+ *
38
+ * The action manifest's input schema (in built-in-action-manifests.ts)
39
+ * describes the AUTHOR shape. The IR shape produced here is the
40
+ * worker's runtime contract — they intentionally diverge.
41
+ */
42
+
43
+ import { WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
44
+
45
+ import { WorkflowDslError } from '../errors';
46
+ import {
47
+ compileExpression,
48
+ ExpressionNodeKind,
49
+ type ExpressionNode,
50
+ } from '../expression';
51
+ import { stripInterpolation } from '../expression/interpolation';
52
+ import type {
53
+ WorkflowDocument,
54
+ WorkflowJobDeclaration,
55
+ WorkflowStrategyDeclaration,
56
+ } from '../types';
57
+
58
+ /** Matches `xema/review@<semver>` (1, 2, or 3 dotted version segments). */
59
+ const REVIEW_ACTION_RE =
60
+ /^xema\/review@[0-9]+(\.[0-9]+(\.[0-9]+(-[A-Za-z0-9.-]+)?)?)?$/;
61
+
62
+ /** Matches `xema/agent@<semver>` — only valid `redraft.step` producer kind. */
63
+ const AGENT_ACTION_RE =
64
+ /^xema\/agent@[0-9]+(\.[0-9]+(\.[0-9]+(-[A-Za-z0-9.-]+)?)?)?$/;
65
+
66
+ export function isReviewActionRef(uses: string): boolean {
67
+ return REVIEW_ACTION_RE.test(uses);
68
+ }
69
+
70
+ interface ReviewWithShape {
71
+ readonly subject: string | readonly string[] | undefined;
72
+ readonly redraft: { readonly step: string } | undefined;
73
+ }
74
+
75
+ /**
76
+ * Per-job redraft-strategy descriptor carried on the IR `redraft` block
77
+ * when the producer step has a matrix strategy. Mirrors the worker
78
+ * consumer in `biomes/workflow-runtime/api/workflow-runtime-worker/src/workflows/review.workflow.ts`
79
+ * — kept JSON-serializable so the IR survives Temporal payload encoding.
80
+ *
81
+ * `static` entries are already cartesian-expanded at compile time;
82
+ * `dynamic.fromExpression` is the producer's expression body (already
83
+ * `${{ … }}`-stripped) which the parent dispatcher evaluates against
84
+ * the review step's expression context before spawning the child
85
+ * workflow. `keyBy` is informational only — per-CU keyed targeting is
86
+ * a Phase-2 feature; Phase 1 always re-runs every matrix entry.
87
+ */
88
+ export type ReviewRedraftStrategyIR =
89
+ | {
90
+ readonly kind: 'static';
91
+ readonly entries: readonly Readonly<Record<string, unknown>>[];
92
+ readonly maxParallel: number;
93
+ }
94
+ | {
95
+ readonly kind: 'dynamic';
96
+ readonly fromExpression: string;
97
+ readonly bindingName: string;
98
+ readonly maxEntries: number;
99
+ readonly maxParallel: number;
100
+ readonly keyBy: string | null;
101
+ };
102
+
103
+ /**
104
+ * Lightweight typed projection of a review step's `with:` block.
105
+ * Throws DSL_SEMANTIC_INVALID on malformed shape; downstream consumers
106
+ * (rewriter, validators) trust the projection.
107
+ */
108
+ function projectReviewWith(
109
+ jobKey: string,
110
+ rawWith: Readonly<Record<string, unknown>> | undefined,
111
+ ): ReviewWithShape {
112
+ const w = rawWith ?? {};
113
+ const subjectRaw = (w as Record<string, unknown>)['subject'];
114
+ let subject: ReviewWithShape['subject'];
115
+ if (subjectRaw === undefined) {
116
+ subject = undefined;
117
+ } else if (typeof subjectRaw === 'string') {
118
+ if (subjectRaw.length === 0) {
119
+ throw new WorkflowDslError(
120
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
121
+ `Job '${jobKey}' with.subject must be a non-empty string or array of strings.`,
122
+ { jobKey, fieldPath: 'with.subject' },
123
+ );
124
+ }
125
+ subject = subjectRaw;
126
+ } else if (Array.isArray(subjectRaw)) {
127
+ if (subjectRaw.length === 0) {
128
+ throw new WorkflowDslError(
129
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
130
+ `Job '${jobKey}' with.subject must be a non-empty array (got []).`,
131
+ { jobKey, fieldPath: 'with.subject' },
132
+ );
133
+ }
134
+ for (let i = 0; i < subjectRaw.length; i++) {
135
+ const item = subjectRaw[i];
136
+ if (typeof item !== 'string' || item.length === 0) {
137
+ throw new WorkflowDslError(
138
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
139
+ `Job '${jobKey}' with.subject[${i}] must be a non-empty string.`,
140
+ { jobKey, fieldPath: `with.subject[${i}]` },
141
+ );
142
+ }
143
+ }
144
+ subject = subjectRaw as readonly string[];
145
+ } else {
146
+ throw new WorkflowDslError(
147
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
148
+ `Job '${jobKey}' with.subject must be a string or an array of strings (got ${typeof subjectRaw}).`,
149
+ { jobKey, fieldPath: 'with.subject' },
150
+ );
151
+ }
152
+
153
+ const redraftRaw = (w as Record<string, unknown>)['redraft'];
154
+ let redraft: ReviewWithShape['redraft'];
155
+ if (redraftRaw === undefined) {
156
+ redraft = undefined;
157
+ } else if (
158
+ typeof redraftRaw === 'object' &&
159
+ redraftRaw !== null &&
160
+ !Array.isArray(redraftRaw)
161
+ ) {
162
+ const stepRaw = (redraftRaw as Record<string, unknown>)['step'];
163
+ if (typeof stepRaw !== 'string' || stepRaw.length === 0) {
164
+ throw new WorkflowDslError(
165
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
166
+ `Job '${jobKey}' with.redraft.step must be a non-empty string naming a producer step.`,
167
+ { jobKey, fieldPath: 'with.redraft.step' },
168
+ );
169
+ }
170
+ redraft = { step: stepRaw };
171
+ } else {
172
+ throw new WorkflowDslError(
173
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
174
+ `Job '${jobKey}' with.redraft must be an object of shape '{ step: <stepName> }'.`,
175
+ { jobKey, fieldPath: 'with.redraft' },
176
+ );
177
+ }
178
+
179
+ return { subject, redraft };
180
+ }
181
+
182
+ /**
183
+ * Validate every review step in the workflow. Run before topo sort +
184
+ * expression validation so author errors surface with clear messages
185
+ * before downstream passes throw less-helpful errors.
186
+ */
187
+ export function validateReviewSteps(workflow: WorkflowDocument): void {
188
+ for (const [jobKey, job] of Object.entries(workflow.jobs)) {
189
+ if (!isReviewActionRef(job.uses)) {
190
+ continue;
191
+ }
192
+ const shape = projectReviewWith(jobKey, job.with);
193
+
194
+ // `redraft` set without `subject` is forbidden — the producer
195
+ // must be authored as a separate step that publishes a deliverable
196
+ // as the iter-1 subject. This keeps the standalone draft step
197
+ // observable in the run UI and avoids the "ghost step that runs
198
+ // but is ignored" footgun.
199
+ if (shape.redraft !== undefined && shape.subject === undefined) {
200
+ throw new WorkflowDslError(
201
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
202
+ `Job '${jobKey}' has 'redraft' set but no 'subject'. Author the producer as a separate step and reference it via 'subject: \${{ needs.${shape.redraft.step}.outputs.deliverable }}'.`,
203
+ { jobKey, fieldPath: 'with' },
204
+ );
205
+ }
206
+
207
+ if (shape.redraft !== undefined) {
208
+ const stepName = shape.redraft.step;
209
+ const producer = workflow.jobs[stepName];
210
+ if (!producer) {
211
+ throw new WorkflowDslError(
212
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
213
+ `Job '${jobKey}' with.redraft.step references unknown job '${stepName}'.`,
214
+ { jobKey, fieldPath: 'with.redraft.step', referencedJob: stepName },
215
+ );
216
+ }
217
+ if (stepName === jobKey) {
218
+ throw new WorkflowDslError(
219
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
220
+ `Job '${jobKey}' with.redraft.step cannot reference itself.`,
221
+ { jobKey, fieldPath: 'with.redraft.step' },
222
+ );
223
+ }
224
+ if (!AGENT_ACTION_RE.test(producer.uses)) {
225
+ throw new WorkflowDslError(
226
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
227
+ `Job '${jobKey}' with.redraft.step = '${stepName}' must reference a step that uses 'xema/agent@<semver>' (got '${producer.uses}').`,
228
+ {
229
+ jobKey,
230
+ fieldPath: 'with.redraft.step',
231
+ referencedJob: stepName,
232
+ referencedUses: producer.uses,
233
+ },
234
+ );
235
+ }
236
+ // Matrix-strategy producers ARE allowed here — on `reject`, the
237
+ // worker re-dispatches every matrix entry of the producer in
238
+ // parallel (one entry → one redraft agent dispatch). The DSL
239
+ // pre-resolves the matrix shape onto the IR `redraft.strategy`
240
+ // block so the parent dispatcher (root-run.workflow.ts) can
241
+ // evaluate dynamic `from:` expressions against the review step's
242
+ // expression context before spawning the child review workflow.
243
+ const declaredNeeds = job.needs ?? [];
244
+ if (!declaredNeeds.includes(stepName)) {
245
+ throw new WorkflowDslError(
246
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
247
+ `Job '${jobKey}' with.redraft.step = '${stepName}' must also be listed in 'needs:'. Add 'needs: [${[...declaredNeeds, stepName].map((s) => `'${s}'`).join(', ')}]'.`,
248
+ {
249
+ jobKey,
250
+ fieldPath: 'with.redraft.step',
251
+ referencedJob: stepName,
252
+ },
253
+ );
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Compute extra `needs:` entries each review step requires beyond what
261
+ * the author declared. Specifically: for any review step with
262
+ * `redraft.step: <producer>`, add `<producer>`'s OWN `needs:` list so
263
+ * the review step's expression context (built from its `needs:`) has
264
+ * every upstream value the embedded redraft `with:` may reference at
265
+ * dispatch time.
266
+ *
267
+ * Returns an empty map when no review steps have a redraft. The caller
268
+ * folds these into the topo-sort input alongside `matrixGather`.
269
+ */
270
+ export function computeReviewNeedsExtensions(
271
+ workflow: WorkflowDocument,
272
+ ): Readonly<Record<string, readonly string[]>> {
273
+ const out: Record<string, readonly string[]> = {};
274
+ for (const [jobKey, job] of Object.entries(workflow.jobs)) {
275
+ if (!isReviewActionRef(job.uses)) {
276
+ continue;
277
+ }
278
+ const shape = projectReviewWith(jobKey, job.with);
279
+ if (shape.redraft === undefined) {
280
+ continue;
281
+ }
282
+ const producer = workflow.jobs[shape.redraft.step];
283
+ if (!producer) {
284
+ // validateReviewSteps already throws for this case; defensive only.
285
+ continue;
286
+ }
287
+ const declared = new Set<string>(producer.needs ?? []);
288
+ // For dynamic-matrix producers, the `from:` expression is evaluated
289
+ // by the parent dispatcher at review-dispatch time against the
290
+ // review step's expression context — every `needs.<X>` it
291
+ // references MUST therefore be in the review step's `needs:` too.
292
+ if (producer.strategy !== undefined && 'dynamic' in producer.strategy) {
293
+ const fromRefs = collectNeedsReferencesFromExpression(
294
+ producer.strategy.dynamic.from,
295
+ );
296
+ for (const ref of fromRefs) {
297
+ declared.add(ref);
298
+ }
299
+ }
300
+ if (declared.size === 0) {
301
+ continue;
302
+ }
303
+ out[jobKey] = Object.freeze([...declared]) as readonly string[];
304
+ }
305
+ return Object.freeze(out);
306
+ }
307
+
308
+ /**
309
+ * Walk a `${{ … }}`-wrapped expression body and collect every
310
+ * `needs.<X>` root reference. Used by the review-step needs extension
311
+ * pass when the redraft producer is a dynamic matrix — its `from:`
312
+ * expression resolves at the parent dispatcher's review-dispatch time
313
+ * against the review step's expression context, so every referenced
314
+ * upstream step must be in the review step's `needs:` too. Returns a
315
+ * deduplicated sorted-by-insertion list of step keys.
316
+ */
317
+ function collectNeedsReferencesFromExpression(
318
+ rawExpression: string,
319
+ ): readonly string[] {
320
+ const body = stripInterpolation(rawExpression);
321
+ const ast = compileExpression(body);
322
+ const seen = new Set<string>();
323
+ walkForNeedsRefs(ast, seen);
324
+ return [...seen];
325
+ }
326
+
327
+ function walkForNeedsRefs(node: ExpressionNode, sink: Set<string>): void {
328
+ switch (node.kind) {
329
+ case ExpressionNodeKind.MEMBER: {
330
+ // Match `needs.<X>` (target is the `needs` identifier).
331
+ if (
332
+ node.target.kind === ExpressionNodeKind.IDENTIFIER &&
333
+ node.target.name === 'needs'
334
+ ) {
335
+ sink.add(node.property);
336
+ }
337
+ walkForNeedsRefs(node.target, sink);
338
+ return;
339
+ }
340
+ case ExpressionNodeKind.INDEX:
341
+ walkForNeedsRefs(node.target, sink);
342
+ walkForNeedsRefs(node.index, sink);
343
+ return;
344
+ case ExpressionNodeKind.CALL:
345
+ for (const arg of node.args) {
346
+ walkForNeedsRefs(arg, sink);
347
+ }
348
+ return;
349
+ case ExpressionNodeKind.UNARY_NOT:
350
+ walkForNeedsRefs(node.operand, sink);
351
+ return;
352
+ case ExpressionNodeKind.BINARY_EQ:
353
+ case ExpressionNodeKind.BINARY_NEQ:
354
+ case ExpressionNodeKind.BINARY_AND:
355
+ case ExpressionNodeKind.BINARY_OR:
356
+ walkForNeedsRefs(node.left, sink);
357
+ walkForNeedsRefs(node.right, sink);
358
+ return;
359
+ case ExpressionNodeKind.LITERAL:
360
+ case ExpressionNodeKind.IDENTIFIER:
361
+ return;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Rewrite a review step's `with:` block from the author shape to the
367
+ * worker contract:
368
+ *
369
+ * - Author `subject: <string>` → IR `subjects: [<string>]`
370
+ * - Author `subject: <string[]>` → IR `subjects: <string[]>`
371
+ * - Author `redraft: { step: X }` → IR `redraft: { uses, with }`
372
+ * looked up from the named producer step.
373
+ *
374
+ * Other fields pass through verbatim. Inputs that are not review steps
375
+ * fall back to `payload.with ?? {}` unchanged — callers may always
376
+ * route through this helper without an `isReviewActionRef` check.
377
+ */
378
+ export function rewriteReviewStepWith(
379
+ jobKey: string,
380
+ payload: WorkflowJobDeclaration,
381
+ workflow: WorkflowDocument,
382
+ ): Readonly<Record<string, unknown>> {
383
+ if (!isReviewActionRef(payload.uses)) {
384
+ return payload.with ?? {};
385
+ }
386
+ const shape = projectReviewWith(jobKey, payload.with);
387
+ const out: Record<string, unknown> = { ...(payload.with ?? {}) };
388
+ // Drop the author-only fields so the IR carries only worker-facing
389
+ // shapes.
390
+ delete out['subject'];
391
+ delete out['redraft'];
392
+
393
+ if (shape.subject !== undefined) {
394
+ out['subjects'] =
395
+ typeof shape.subject === 'string' ? [shape.subject] : [...shape.subject];
396
+ }
397
+
398
+ if (shape.redraft !== undefined) {
399
+ const producer = workflow.jobs[shape.redraft.step];
400
+ if (!producer) {
401
+ // validateReviewSteps already throws here; keep defensive.
402
+ throw new WorkflowDslError(
403
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
404
+ `Job '${jobKey}' with.redraft.step references unknown job '${shape.redraft.step}'.`,
405
+ { jobKey, fieldPath: 'with.redraft.step' },
406
+ );
407
+ }
408
+ // Preserve the original step name on the IR `redraft` block. The
409
+ // worker uses it as the `artifactScope` override when the redraft's
410
+ // agent activity emits its outputs, so the regenerated bytes
411
+ // version the SAME logical artifact as the original draft (e.g.
412
+ // v2 of `draft.response`) rather than landing under the review
413
+ // step's identity (which would create a parallel `review.response`
414
+ // artifact and starve the reviewer's iter-2 view of the new draft).
415
+ //
416
+ // For matrix producers, also carry the producer's matrix shape
417
+ // onto the IR so the parent dispatcher (root-run.workflow.ts) can
418
+ // expand entries at review-dispatch time and pass the resolved
419
+ // bindings into the review child workflow. On `reject`, the worker
420
+ // re-dispatches every matrix entry in parallel — one redraft agent
421
+ // dispatch per entry.
422
+ const ir: Record<string, unknown> = {
423
+ step: shape.redraft.step,
424
+ uses: producer.uses,
425
+ with: producer.with ?? {},
426
+ };
427
+ const strategy = compileRedraftStrategyIR(producer.strategy);
428
+ if (strategy !== null) {
429
+ ir['strategy'] = strategy;
430
+ }
431
+ if (producer.matrixGather && producer.matrixGather.length > 0) {
432
+ ir['matrixGather'] = [...producer.matrixGather];
433
+ }
434
+ out['redraft'] = ir;
435
+ }
436
+
437
+ return out;
438
+ }
439
+
440
+ /**
441
+ * Pre-resolve a producer step's authored matrix strategy into a
442
+ * JSON-serializable IR descriptor the worker carries through the
443
+ * review step's `with.redraft`. `null` for non-matrix producers — the
444
+ * worker takes the legacy single-dispatch path when `strategy` is
445
+ * absent on the IR `redraft` block. Static matrices are NOT
446
+ * cartesian-expanded here (that's the job of `compileStrategy` which
447
+ * runs against the producer's own job IR); we propagate the raw axes
448
+ * because the worker reuses the same compile-time expansion behavior
449
+ * via the parent dispatcher's per-job CompiledJob lookup. Keeping this
450
+ * descriptor small and shape-faithful avoids drift with
451
+ * `compileStrategy`'s output — the parent dispatcher reads the
452
+ * producer's own `CompiledJob.strategy` (Source of truth) and uses
453
+ * THIS descriptor only as a discriminator hint + entry-resolution
454
+ * fallback. Mirror of the worker contract `ReviewRedraftStrategyIR`.
455
+ */
456
+ function compileRedraftStrategyIR(
457
+ strategy: WorkflowStrategyDeclaration | undefined,
458
+ ): ReviewRedraftStrategyIR | null {
459
+ if (strategy === undefined) {
460
+ return null;
461
+ }
462
+ if ('matrix' in strategy) {
463
+ // Carry static axes; the worker side mirrors `compileStrategy`'s
464
+ // cartesian expansion. `maxParallel` defaults align with
465
+ // `matrix.ts:resolveMaxParallel` — when absent, the worker uses 8.
466
+ const entries = expandStaticMatrixAxes(strategy.matrix);
467
+ const maxParallel =
468
+ strategy.maxParallel !== undefined && strategy.maxParallel > 0
469
+ ? Math.min(strategy.maxParallel, entries.length || 1)
470
+ : Math.min(8, Math.max(1, entries.length));
471
+ return {
472
+ kind: 'static',
473
+ entries,
474
+ maxParallel,
475
+ };
476
+ }
477
+ const dyn = strategy.dynamic;
478
+ const body = stripInterpolation(dyn.from);
479
+ const maxEntries = dyn.maxEntries ?? 64;
480
+ const maxParallel =
481
+ strategy.maxParallel !== undefined && strategy.maxParallel > 0
482
+ ? Math.min(strategy.maxParallel, maxEntries)
483
+ : Math.min(8, maxEntries);
484
+ return {
485
+ kind: 'dynamic',
486
+ fromExpression: body,
487
+ bindingName: dyn.as,
488
+ maxEntries,
489
+ maxParallel,
490
+ keyBy: dyn.keyBy ?? null,
491
+ };
492
+ }
493
+
494
+ /**
495
+ * Cartesian expansion of a static-matrix axes block. Mirrors
496
+ * `expandStaticMatrix` in `./matrix.ts` minus the cap-checking, which
497
+ * has already been enforced on the producer's own CompiledJob by the
498
+ * normal compile path. Lexicographic axis order keeps replay
499
+ * deterministic.
500
+ */
501
+ function expandStaticMatrixAxes(
502
+ axes: Readonly<Record<string, readonly unknown[]>>,
503
+ ): readonly Readonly<Record<string, unknown>>[] {
504
+ const axisKeys = Object.keys(axes).sort();
505
+ let entries: Record<string, unknown>[] = [{}];
506
+ for (const axis of axisKeys) {
507
+ const values = axes[axis]!;
508
+ const next: Record<string, unknown>[] = [];
509
+ for (const partial of entries) {
510
+ for (const value of values) {
511
+ next.push({ ...partial, [axis]: value });
512
+ }
513
+ }
514
+ entries = next;
515
+ }
516
+ return entries.map(Object.freeze) as readonly Readonly<Record<string, unknown>>[];
517
+ }
@@ -0,0 +1,170 @@
1
+ import type {
2
+ ActionExecutionKind,
3
+ Briefcase,
4
+ TaskQueueName,
5
+ TriggerPayload,
6
+ WalletContents,
7
+ WorkflowRef,
8
+ } from '@xemahq/kernel-contracts/workflow';
9
+ import type { ActionManifest, WorkflowDocument } from '../types';
10
+
11
+ /**
12
+ * Everything the compiler needs beyond the workflow document itself. The
13
+ * engine gathers these inputs before calling `compileWorkflow(...)`:
14
+ *
15
+ * - `workflow` — validated WorkflowDocument (pass through
16
+ * `validateWorkflowDocument` first).
17
+ * - `workflowRef` — slug/version/isSystem, resolved from the DB.
18
+ * - `trigger` — the payload that fired this run.
19
+ * - `resolvedRefs` — map of `uses:` strings to resolved refs, populated
20
+ * by looking up each job's `uses:` in the action-manifest registry
21
+ * (for `xema/...`) or the reusable-workflow registry (for
22
+ * `xema://workflow/...`).
23
+ * - `workflowDefinitionVersionSha256` — sha256 of the source YAML the
24
+ * compiler is consuming. Emitted into CompiledRun for audit.
25
+ */
26
+ export interface CompileInput {
27
+ readonly workflow: WorkflowDocument;
28
+ readonly workflowRef: WorkflowRef;
29
+ readonly trigger: TriggerPayload;
30
+ readonly resolvedRefs: Readonly<Record<string, ResolvedRef>>;
31
+ /**
32
+ * Map of literal `agentSlug` values (used in `with.agentSlug` and
33
+ * `with.reviewers[].agentSlug`) to the agent metadata the compiler
34
+ * needs for validation. The engine pre-fetches this from
35
+ * llm-registry-api. The compiler validates that every literal slug
36
+ * appears here; expression-shaped slugs (e.g. `${{ inputs.agentSlug }}`)
37
+ * are skipped — they resolve at dispatch and the activity's
38
+ * `AGENT_NOT_REGISTERED` preflight catches them at runtime.
39
+ *
40
+ * Pass an empty map (or omit) to opt out of agent validation (e.g.
41
+ * for the `preview-raw` endpoint when the engine cannot reach the
42
+ * registry, or for tests that don't exercise the registry).
43
+ */
44
+ readonly resolvedAgents?: Readonly<Record<string, ResolvedAgent>>;
45
+ /**
46
+ * Map of literal deliverable-spec refs (used in `with.deliverableSpecRef`
47
+ * and the `produces:` array) to the spec metadata the compiler needs
48
+ * for validation. The engine pre-fetches this from
49
+ * deliverable-specs-api. Same literal-vs-expression rule as
50
+ * `resolvedAgents`. Same opt-out semantics: empty / omitted = skip.
51
+ */
52
+ readonly resolvedDeliverableSpecs?: Readonly<
53
+ Record<string, ResolvedDeliverableSpec>
54
+ >;
55
+ readonly workflowDefinitionVersionSha256: string;
56
+ /**
57
+ * Contents of every wallet referenced under `requires.wallets`, plus
58
+ * any additional wallets a dispatch caller asked for. The compiler
59
+ * unions the entries to derive `CompiledRun.requiredVariables` and to
60
+ * validate `${{ vars.X }}` / `${{ secrets.X }}` references. When
61
+ * omitted, wallet-derived validation is skipped — used by
62
+ * `preview-raw` during authoring where the engine can't reach the
63
+ * variable store.
64
+ */
65
+ readonly resolvedWallets?: Readonly<Record<string, WalletContents>>;
66
+ /**
67
+ * Installation scope of this dispatch — present when the workflow is
68
+ * dispatched from a biome installation (webhook trigger gated on
69
+ * the installation, manual dispatch from the installation's UX, a
70
+ * scheduled trigger tied to the installation). Absent for system /
71
+ * org-wide dispatches that don't belong to any installation.
72
+ *
73
+ * The compiler's installation-resource validator uses this scope to
74
+ * resolve `x-installation-resource: { kind: ... }` references in
75
+ * action input schemas against the installation's bound resources
76
+ * (wallets / repos / channels / …). When `installationScope` is
77
+ * undefined, the validator skips installation-bound fields — system
78
+ * workflows can still reference wallet ids, but compile-time
79
+ * binding-set validation only happens for biome-installed runs.
80
+ */
81
+ readonly installationScope?: InstallationCompileScope;
82
+ /**
83
+ * When true, the compiler substitutes type-appropriate sentinel values
84
+ * for missing required inputs instead of throwing. Intended only for
85
+ * the `preview-raw` endpoint (Monaco editor live feedback) where the
86
+ * caller deliberately omits real input values during YAML authoring.
87
+ * Never set this on real run compilation paths.
88
+ */
89
+ readonly previewMode?: boolean;
90
+ /**
91
+ * Run-scoped Briefcase the dispatch caller attached to this run.
92
+ * Synthesized server-side from the StartRun request body (uploads /
93
+ * references / vars / mcpTools) and threaded into the CompiledRun so
94
+ * the run's snapshot captures the dispatch payload alongside its
95
+ * inputs and trigger. Absent for runs without dispatch-attached
96
+ * context (compiler treats absent and `emptyBriefcase()` identically
97
+ * downstream).
98
+ */
99
+ readonly briefcase?: Briefcase;
100
+ }
101
+
102
+ /**
103
+ * Installation context the engine pre-fetches at dispatch time. Each
104
+ * `boundResources` entry lists the resource ids the installation is
105
+ * bound to for a single `InstallationResourceKind` — the compiler
106
+ * checks every literal value in a `x-installation-resource` field
107
+ * against the matching kind's set and rejects unbound values.
108
+ *
109
+ * The engine populates this from biome-host-api right before calling
110
+ * the compiler. Passing an empty array for a kind means "no resources
111
+ * bound" — every literal value for that kind fails validation.
112
+ */
113
+ export interface InstallationCompileScope {
114
+ readonly installationId: string;
115
+ readonly orgId: string;
116
+ readonly projectId: string;
117
+ readonly biomeId: string;
118
+ readonly boundResources: Readonly<Record<string, readonly string[]>>;
119
+ }
120
+
121
+ /**
122
+ * Minimal agent metadata the compiler keeps for each literal `agentSlug`.
123
+ * The engine fetches the full row from llm-registry-api but the compiler
124
+ * only needs the existence proof and the snapshot hash (so a future
125
+ * `CompiledRun` can carry it for cache-invalidation matching). Extend
126
+ * with more fields only when the compiler actually consumes them.
127
+ */
128
+ export interface ResolvedAgent {
129
+ readonly slug: string;
130
+ readonly snapshotHash: string;
131
+ }
132
+
133
+ /**
134
+ * Minimal deliverable-spec metadata the compiler keeps for each literal
135
+ * `deliverableSpecRef`. Same minimality rule as `ResolvedAgent`.
136
+ *
137
+ * Optional `topLevelKeys` enables compile-time field validation for
138
+ * expressions of shape
139
+ * `${{ job.outputs.deliverable.content.value.<field> }}` — when
140
+ * populated, the DSL asserts `<field>` is one of these. The engine
141
+ * extracts the keys from the spec's `zodSchemaSource` (Zod) or
142
+ * `content`'s `properties` (JSON Schema) at registry-fetch time. Specs
143
+ * whose kind has no known shape (e.g. CUSTOM, ENDPOINT_FETCH) leave it
144
+ * undefined and the validator skips them.
145
+ */
146
+ export interface ResolvedDeliverableSpec {
147
+ readonly ref: string;
148
+ readonly slug: string;
149
+ readonly snapshotHash: string;
150
+ readonly topLevelKeys?: readonly string[];
151
+ }
152
+
153
+ /**
154
+ * Resolved reference for a single `uses:` value. Emitted by the engine's
155
+ * ref-resolution layer before compilation; the compiler trusts it blindly.
156
+ *
157
+ * For action refs, `actionManifest` is the full manifest (the compiler
158
+ * needs retry/timeout/allowedMounts). For reusable-workflow refs,
159
+ * `actionManifest` is null — reusable workflows have their own compilation
160
+ * pass, so this outer compilation only records the pointer.
161
+ */
162
+ export interface ResolvedRef {
163
+ readonly id: string;
164
+ readonly version: string;
165
+ readonly manifestSha256: string;
166
+ readonly executionKind: ActionExecutionKind;
167
+ readonly taskQueue: TaskQueueName;
168
+ readonly isReusableWorkflow: boolean;
169
+ readonly actionManifest: ActionManifest | null;
170
+ }