@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,176 @@
1
+ import {
2
+ WorkflowErrorCode,
3
+ isAgentRunRole,
4
+ type CompiledManifestSource,
5
+ } from '@xemahq/kernel-contracts/workflow';
6
+ import { compileManifest } from '../../../workspace-manifest';
7
+
8
+ import { WorkflowDslError } from '../errors';
9
+ import { ANY_INTERPOLATION_RE } from '../expression/interpolation';
10
+ import type { ActionManifest } from '../types';
11
+ import { isAgentShapedAction } from './action-shape';
12
+
13
+ /**
14
+ * `metadata.version` on the synthesized envelope must satisfy the
15
+ * workspace-manifest-dsl semver regex. We use a static placeholder
16
+ * since the inline manifest never enters the manifests-api catalog —
17
+ * it lives in-process for the lifetime of the snapshot.
18
+ */
19
+ const INLINE_MANIFEST_VERSION = '0.0.0';
20
+
21
+ /**
22
+ * Compute the compile-time `manifestSource` discriminator for one job.
23
+ *
24
+ * Three terminal shapes:
25
+ * • `null` — non-agent action (the action manifest doesn't expose
26
+ * `compositionRef` + `mounts` on its `inputs:` schema).
27
+ * • `{ kind: 'ref', ref }` — long-form ref is a literal string. The
28
+ * activity resolves the Agent Composition it names at boot.
29
+ * • `{ kind: 'inline', compiled }` — short-form mounts and every
30
+ * value the inline manifest depends on (`agentSlug`, `phaseKey`
31
+ * (YAML field — mapped onto kernel `groupKey`), `deliverableSpecRef`,
32
+ * every entry of `mounts`) are YAML literals.
33
+ * We synthesize a `WorkspaceManifest` envelope and feed it through
34
+ * `compileManifest()` once at workflow compile so the worker skips
35
+ * both the DB round-trip and the runtime synthesis.
36
+ * • `{ kind: 'inline-deferred' }` — at least one of the inputs above
37
+ * is a `${{ … }}` expression that must be evaluated per dispatch.
38
+ * The worker keeps today's runtime-synthesis path for these.
39
+ *
40
+ * The `oneOf` invariant (exactly one of `compositionRef` / `mounts`) is
41
+ * enforced upstream by `enforceManifestSourceDiscriminator` in
42
+ * `mount-plan.ts`. By the time we get here that pair is already known
43
+ * to be well-formed, so this function only branches between
44
+ * literal-vs-expression.
45
+ */
46
+ export function compileManifestSource(
47
+ jobKey: string,
48
+ withBlock: Readonly<Record<string, unknown>> | undefined,
49
+ actionManifest: ActionManifest | null,
50
+ ): CompiledManifestSource | null {
51
+ if (!isAgentShapedAction(actionManifest)) return null;
52
+ const block = withBlock ?? {};
53
+
54
+ const ref = block['compositionRef'];
55
+ if (typeof ref === 'string' && ref.length > 0) {
56
+ if (isLiteralString(ref)) {
57
+ return Object.freeze({ kind: 'ref' as const, ref });
58
+ }
59
+ return Object.freeze({ kind: 'inline-deferred' as const });
60
+ }
61
+ if (ref !== undefined) {
62
+ // ref is present but not a literal string → expression.
63
+ return Object.freeze({ kind: 'inline-deferred' as const });
64
+ }
65
+
66
+ // Mounts path. Caller has already asserted `mounts` is set.
67
+ const mounts = block['mounts'];
68
+ if (containsExpressions(mounts)) {
69
+ return Object.freeze({ kind: 'inline-deferred' as const });
70
+ }
71
+
72
+ const agentSlug = block['agentSlug'];
73
+ const phaseKey = block['phaseKey'];
74
+ const deliverableSpecRef = block['deliverableSpecRef'];
75
+ const roleRaw = block['role'];
76
+ if (
77
+ !isLiteralString(agentSlug) ||
78
+ !isLiteralStringOrUndefined(phaseKey) ||
79
+ !isLiteralStringOrNullOrUndefined(deliverableSpecRef) ||
80
+ !isLiteralStringOrUndefined(roleRaw)
81
+ ) {
82
+ return Object.freeze({ kind: 'inline-deferred' as const });
83
+ }
84
+
85
+ if (typeof roleRaw !== 'string' || !isAgentRunRole(roleRaw)) {
86
+ throw new WorkflowDslError(
87
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
88
+ `Job '${jobKey}' uses inline 'mounts:' but its 'with.role' is missing or not a canonical AgentRunRole. ` +
89
+ `Declare 'role' explicitly (e.g. 'unit-worker', 'coordinator', 'gate-reviewer'); the action schema enforces this at compile time.`,
90
+ { jobKey, actionId: actionManifest.metadata.id },
91
+ );
92
+ }
93
+ const role = roleRaw;
94
+ const envelope = synthesizeInlineManifestEnvelope({
95
+ agentSlug,
96
+ phaseKey: typeof phaseKey === 'string' ? phaseKey : null,
97
+ role,
98
+ deliverableSpecRef:
99
+ typeof deliverableSpecRef === 'string' ? deliverableSpecRef : null,
100
+ mounts: mounts as Readonly<Record<string, unknown>>,
101
+ });
102
+ const result = compileManifest(envelope, {});
103
+ if (!result.ok) {
104
+ throw new WorkflowDslError(
105
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
106
+ `Job '${jobKey}' inline workspace manifest failed to compile: ${result.errors
107
+ .map((e) => `${e.path}: ${e.message}`)
108
+ .join('; ')
109
+ .slice(0, 400)}`,
110
+ { jobKey, actionId: actionManifest.metadata.id },
111
+ );
112
+ }
113
+ return Object.freeze({ kind: 'inline' as const, compiled: result.compiled });
114
+ }
115
+
116
+ interface SynthesizeArgs {
117
+ readonly agentSlug: string;
118
+ readonly phaseKey: string | null;
119
+ readonly role: string;
120
+ readonly deliverableSpecRef: string | null;
121
+ readonly mounts: Readonly<Record<string, unknown>>;
122
+ }
123
+
124
+ /**
125
+ * Build the YAML-equivalent envelope object that `compileManifest()`
126
+ * accepts. We never round-trip through YAML — the kernel's compiler
127
+ * accepts a parsed object too.
128
+ */
129
+ function synthesizeInlineManifestEnvelope(args: SynthesizeArgs): unknown {
130
+ return {
131
+ apiVersion: 'xema.dev/workspace/v1',
132
+ kind: 'WorkspaceManifest',
133
+ metadata: {
134
+ slug: 'inline',
135
+ version: INLINE_MANIFEST_VERSION,
136
+ // Inline-synthesized manifests only ever boot from a workflow
137
+ // step — interactive sessions reach the resolver through the
138
+ // long-form ref path. Pinning this here means
139
+ // `EnvironmentResolver` can fail fast if a workflow ever points
140
+ // an agent-session-only consumer at one of these.
141
+ surfaceCompat: ['workflow'],
142
+ },
143
+ spec: {
144
+ agent: {
145
+ slug: args.agentSlug,
146
+ phase: args.phaseKey ?? 'default',
147
+ role: args.role,
148
+ ...(args.deliverableSpecRef === null
149
+ ? {}
150
+ : { deliverableSpecRef: args.deliverableSpecRef }),
151
+ },
152
+ mounts: args.mounts,
153
+ },
154
+ };
155
+ }
156
+
157
+ function containsExpressions(node: unknown): boolean {
158
+ if (typeof node === 'string') return ANY_INTERPOLATION_RE.test(node);
159
+ if (Array.isArray(node)) return node.some(containsExpressions);
160
+ if (node !== null && typeof node === 'object') {
161
+ return Object.values(node as Record<string, unknown>).some(containsExpressions);
162
+ }
163
+ return false;
164
+ }
165
+
166
+ function isLiteralString(value: unknown): value is string {
167
+ return typeof value === 'string' && !ANY_INTERPOLATION_RE.test(value);
168
+ }
169
+
170
+ function isLiteralStringOrUndefined(value: unknown): boolean {
171
+ return value === undefined || isLiteralString(value);
172
+ }
173
+
174
+ function isLiteralStringOrNullOrUndefined(value: unknown): boolean {
175
+ return value === null || value === undefined || isLiteralString(value);
176
+ }
@@ -0,0 +1,135 @@
1
+ import { MatrixStrategyKind, WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
2
+ import type {
3
+ CompiledDynamicMatrixStrategy,
4
+ CompiledSingleStrategy,
5
+ CompiledStaticMatrixStrategy,
6
+ CompiledStrategy,
7
+ } from '@xemahq/kernel-contracts/workflow';
8
+ import { WorkflowDslError } from '../errors';
9
+ import type { WorkflowStrategyDeclaration } from '../types';
10
+ import { compileExpression } from '../expression';
11
+ import { stripInterpolation } from '../expression/interpolation';
12
+
13
+ /** Hard cap on matrix cardinality — static and dynamic both enforce this. */
14
+ const MATRIX_MAX_ENTRIES = 64;
15
+ const MATRIX_DEFAULT_MAX_PARALLEL = 8;
16
+
17
+ /**
18
+ * Compile an authored strategy declaration into a CompiledStrategy. Performs
19
+ * cartesian expansion for static matrices at compile time and pre-validates
20
+ * the dynamic `from:` expression.
21
+ *
22
+ * Static matrix cardinality is the product of each axis's length. The cap
23
+ * is applied to the product, not per-axis, so 8×8 (=64) is the ceiling.
24
+ */
25
+ export function compileStrategy(
26
+ declaration: WorkflowStrategyDeclaration | undefined,
27
+ jobKey: string,
28
+ ): CompiledStrategy {
29
+ if (!declaration) {
30
+ const single: CompiledSingleStrategy = { kind: MatrixStrategyKind.SINGLE };
31
+ return single;
32
+ }
33
+
34
+ if ('matrix' in declaration) {
35
+ return expandStaticMatrix(declaration.matrix, declaration.maxParallel, jobKey);
36
+ }
37
+
38
+ return compileDynamicStrategy(declaration.dynamic, declaration.maxParallel, jobKey);
39
+ }
40
+
41
+ function expandStaticMatrix(
42
+ axes: Readonly<Record<string, readonly unknown[]>>,
43
+ maxParallelRaw: number | undefined,
44
+ jobKey: string,
45
+ ): CompiledStaticMatrixStrategy {
46
+ const axisKeys = Object.keys(axes).sort();
47
+ if (axisKeys.length === 0) {
48
+ throw new WorkflowDslError(
49
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
50
+ `Job '${jobKey}' declares strategy.matrix with no axes.`,
51
+ { jobKey },
52
+ );
53
+ }
54
+
55
+ // Cartesian product in lexicographic order of axisKeys for determinism.
56
+ let entries: Record<string, unknown>[] = [{}];
57
+ for (const axis of axisKeys) {
58
+ const values = axes[axis]!;
59
+ const next: Record<string, unknown>[] = [];
60
+ for (const partial of entries) {
61
+ for (const value of values) {
62
+ next.push({ ...partial, [axis]: value });
63
+ }
64
+ if (next.length > MATRIX_MAX_ENTRIES) break;
65
+ }
66
+ entries = next;
67
+ if (entries.length > MATRIX_MAX_ENTRIES) break;
68
+ }
69
+
70
+ if (entries.length > MATRIX_MAX_ENTRIES) {
71
+ throw new WorkflowDslError(
72
+ WorkflowErrorCode.DSL_MATRIX_CARDINALITY_EXCEEDED,
73
+ `Job '${jobKey}' static matrix expansion produces ${entries.length} entries; cap is ${MATRIX_MAX_ENTRIES}.`,
74
+ { jobKey, cap: MATRIX_MAX_ENTRIES, cardinality: entries.length },
75
+ );
76
+ }
77
+
78
+ const maxParallel = resolveMaxParallel(maxParallelRaw, entries.length);
79
+
80
+ return {
81
+ kind: MatrixStrategyKind.STATIC,
82
+ entries: entries.map(Object.freeze) as readonly Readonly<Record<string, unknown>>[],
83
+ maxParallel,
84
+ };
85
+ }
86
+
87
+ function compileDynamicStrategy(
88
+ declaration: {
89
+ readonly from: string;
90
+ readonly as: string;
91
+ readonly maxEntries?: number;
92
+ readonly keyBy?: string;
93
+ },
94
+ maxParallelRaw: number | undefined,
95
+ jobKey: string,
96
+ ): CompiledDynamicMatrixStrategy {
97
+ const body = stripInterpolation(declaration.from);
98
+ // Compile expression at compile time — this rejects unknown roots and
99
+ // bad syntax now, so the runtime evaluator can only fail on an unknown
100
+ // property during real evaluation.
101
+ compileExpression(body);
102
+
103
+ const maxEntries = declaration.maxEntries ?? MATRIX_MAX_ENTRIES;
104
+ if (maxEntries < 1 || maxEntries > MATRIX_MAX_ENTRIES) {
105
+ throw new WorkflowDslError(
106
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
107
+ `Job '${jobKey}' strategy.dynamic.maxEntries must be in [1, ${MATRIX_MAX_ENTRIES}]; got ${maxEntries}.`,
108
+ { jobKey, maxEntries, cap: MATRIX_MAX_ENTRIES },
109
+ );
110
+ }
111
+ const maxParallel = resolveMaxParallel(maxParallelRaw, maxEntries);
112
+
113
+ return {
114
+ kind: MatrixStrategyKind.DYNAMIC,
115
+ fromExpression: body,
116
+ bindingName: declaration.as,
117
+ maxEntries,
118
+ maxParallel,
119
+ keyBy: declaration.keyBy ?? null,
120
+ };
121
+ }
122
+
123
+ function resolveMaxParallel(raw: number | undefined, cardinality: number): number {
124
+ if (raw === undefined) {
125
+ return Math.min(MATRIX_DEFAULT_MAX_PARALLEL, Math.max(1, cardinality));
126
+ }
127
+ if (raw < 1) {
128
+ throw new WorkflowDslError(
129
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
130
+ `strategy.maxParallel must be >= 1 (got ${raw}).`,
131
+ { raw },
132
+ );
133
+ }
134
+ return Math.min(raw, MATRIX_MAX_ENTRIES);
135
+ }
@@ -0,0 +1,202 @@
1
+ import {
2
+ AWP_V1_SPEC,
3
+ findSlot,
4
+ isKnownSlotKey,
5
+ SlotMode,
6
+ type WorkspaceSpec,
7
+ } from '@xemahq/kernel-contracts/agent-workspace';
8
+ import { WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
9
+ import type { MountPlan } from '@xemahq/kernel-contracts/workflow';
10
+ import { WorkflowDslError } from '../errors';
11
+ import type { ActionManifest } from '../types';
12
+ import { isAgentShapedAction } from './action-shape';
13
+
14
+ /**
15
+ * Compile a job's `with:` block into a compile-time {@link MountPlan} —
16
+ * a declarative list of mount keys grouped by access, validated against
17
+ * (a) the workspace spec's closed slot set and (b) the action manifest's
18
+ * `allowedMounts`.
19
+ *
20
+ * Read/write classification is per-mount with a slot-default fallback:
21
+ * - `with.mounts.<key>: true` uses the slot's `defaultMode` from the
22
+ * {@link WorkspaceSpec}.
23
+ * - `with.mounts.<key>: { mode: 'read-only' | 'read-write' }`
24
+ * overrides the slot default. The value is the closed `SlotMode`
25
+ * enum; any other string is rejected fail-fast.
26
+ *
27
+ * The legacy `with.mountKeys: []` / `with.writableMountKeys: []` array
28
+ * form is gone — the action manifest's input schema rejects it before
29
+ * this compiler runs, but we also explicitly reject those keys here so
30
+ * a misconfigured manifest can't sneak the legacy shape through.
31
+ *
32
+ * Concrete {@link MountSource} resolution is NOT the compiler's job: it
33
+ * requires access to the engine's org-scoped resource registry, which is
34
+ * only available at dispatch time.
35
+ *
36
+ * Rules:
37
+ * - `with.mounts` absent → empty plan (no implicit mounts).
38
+ * - Unknown slot keys (per the spec) fail fast.
39
+ * - If the action manifest declares `allowedMounts`, keys outside it
40
+ * also fail fast.
41
+ * - Legacy `mountKeys` / `writableMountKeys` keys on `with:` → fail fast
42
+ * with a migration hint.
43
+ */
44
+
45
+ const SPEC: WorkspaceSpec = AWP_V1_SPEC;
46
+
47
+ const LEGACY_MOUNT_KEYS = ['mountKeys', 'writableMountKeys'] as const;
48
+
49
+ export function compileMountPlan(
50
+ jobKey: string,
51
+ withBlock: Readonly<Record<string, unknown>> | undefined,
52
+ actionManifest: ActionManifest | null,
53
+ ): MountPlan {
54
+ rejectLegacyShape(jobKey, withBlock);
55
+
56
+ enforceManifestSourceDiscriminator(jobKey, withBlock, actionManifest);
57
+
58
+ const mounts = extractMountsBlock(withBlock);
59
+ if (!mounts) {
60
+ return { readOnly: [], readWrite: [] };
61
+ }
62
+
63
+ const allowed =
64
+ actionManifest?.spec.allowedMounts !== undefined
65
+ ? new Set(actionManifest.spec.allowedMounts)
66
+ : null;
67
+
68
+ const readOnly: { key: string }[] = [];
69
+ const readWrite: { key: string }[] = [];
70
+
71
+ const sortedKeys = Object.keys(mounts).sort();
72
+ for (const key of sortedKeys) {
73
+ const mode = parseMountValue(jobKey, key, mounts[key]);
74
+ if (!isKnownSlotKey(SPEC, key)) {
75
+ throw new WorkflowDslError(
76
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
77
+ `Job '${jobKey}' requests mount '${key}' which is not a known slot in WorkspaceSpec '${SPEC.id}'.`,
78
+ { jobKey, mountKey: key, knownSlots: SPEC.slots.map((s) => s.key) },
79
+ );
80
+ }
81
+ if (allowed !== null && !allowed.has(key)) {
82
+ throw new WorkflowDslError(
83
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
84
+ `Job '${jobKey}' requests mount '${key}' but action manifest does not list it in allowedMounts.`,
85
+ { jobKey, mountKey: key, allowedMounts: [...allowed] },
86
+ );
87
+ }
88
+ const slot = findSlot(SPEC, key);
89
+ const slotDefault = slot?.defaultMode ?? SlotMode.ReadOnly;
90
+ const effective = mode ?? slotDefault;
91
+ if (slot && !slot.allowedModes.includes(effective)) {
92
+ throw new WorkflowDslError(
93
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
94
+ `Job '${jobKey}' requests mount '${key}' with mode '${effective}', which is not in slot allowedModes [${slot.allowedModes.join(', ')}].`,
95
+ { jobKey, mountKey: key, requestedMode: effective, allowedModes: [...slot.allowedModes] },
96
+ );
97
+ }
98
+ if (effective === SlotMode.ReadWrite) {
99
+ readWrite.push({ key });
100
+ } else {
101
+ readOnly.push({ key });
102
+ }
103
+ }
104
+
105
+ return { readOnly, readWrite };
106
+ }
107
+
108
+ function parseMountValue(
109
+ jobKey: string,
110
+ mountKey: string,
111
+ value: unknown,
112
+ ): SlotMode | null {
113
+ if (value === true) return null;
114
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
115
+ const obj = value as Record<string, unknown>;
116
+ const mode = obj['mode'];
117
+ if (mode === SlotMode.ReadOnly || mode === SlotMode.ReadWrite) {
118
+ return mode;
119
+ }
120
+ throw new WorkflowDslError(
121
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
122
+ `Job '${jobKey}' mount '${mountKey}' has invalid 'mode': must be '${SlotMode.ReadOnly}' or '${SlotMode.ReadWrite}'.`,
123
+ { jobKey, mountKey, mode: typeof mode === 'string' ? mode : typeof mode },
124
+ );
125
+ }
126
+ throw new WorkflowDslError(
127
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
128
+ `Job '${jobKey}' mount '${mountKey}' value must be \`true\` or \`{ mode: 'read-only' | 'read-write' }\`.`,
129
+ { jobKey, mountKey, valueKind: Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value },
130
+ );
131
+ }
132
+
133
+ function extractMountsBlock(
134
+ withBlock: Readonly<Record<string, unknown>> | undefined,
135
+ ): Readonly<Record<string, unknown>> | null {
136
+ if (!withBlock) return null;
137
+ const raw = withBlock['mounts'];
138
+ if (raw === undefined) return null;
139
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
140
+ throw new WorkflowDslError(
141
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
142
+ `\`with.mounts\` must be an object mapping slot keys to \`true\` or \`{ mode }\`.`,
143
+ { mountsKind: Array.isArray(raw) ? 'array' : raw === null ? 'null' : typeof raw },
144
+ );
145
+ }
146
+ return raw as Readonly<Record<string, unknown>>;
147
+ }
148
+
149
+ function rejectLegacyShape(
150
+ jobKey: string,
151
+ withBlock: Readonly<Record<string, unknown>> | undefined,
152
+ ): void {
153
+ if (!withBlock) return;
154
+ for (const legacyKey of LEGACY_MOUNT_KEYS) {
155
+ if (legacyKey in withBlock) {
156
+ throw new WorkflowDslError(
157
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
158
+ `Job '${jobKey}' uses legacy '${legacyKey}' on \`with:\`. Migrate to \`with.mounts\` (object form): \`mounts: { references: true, deliverables: { mode: 'read-write' } }\`.`,
159
+ { jobKey, legacyKey },
160
+ );
161
+ }
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Manifest-source discriminator: when an action's `inputs:` schema
167
+ * declares both `compositionRef` and `mounts` as alternatives (via
168
+ * JSON-Schema `oneOf`), the workflow's `with:` block must specify
169
+ * exactly one of them. Detected generically so biome-shipped agent
170
+ * actions inherit the same compile-time check without a hardcoded
171
+ * action-id allowlist.
172
+ */
173
+ function enforceManifestSourceDiscriminator(
174
+ jobKey: string,
175
+ withBlock: Readonly<Record<string, unknown>> | undefined,
176
+ actionManifest: ActionManifest | null,
177
+ ): void {
178
+ if (!isAgentShapedAction(actionManifest)) return;
179
+ const hasRef =
180
+ withBlock !== undefined &&
181
+ 'compositionRef' in withBlock &&
182
+ typeof withBlock['compositionRef'] === 'string' &&
183
+ (withBlock['compositionRef'] as string).length > 0;
184
+ const hasMounts =
185
+ withBlock !== undefined &&
186
+ 'mounts' in withBlock &&
187
+ withBlock['mounts'] !== undefined;
188
+ if (hasRef && hasMounts) {
189
+ throw new WorkflowDslError(
190
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
191
+ `Job '${jobKey}' sets both \`compositionRef\` and \`mounts\` on \`with:\`. The action's manifest source is exactly one of the two.`,
192
+ { jobKey, actionId: actionManifest.metadata.id },
193
+ );
194
+ }
195
+ if (!hasRef && !hasMounts) {
196
+ throw new WorkflowDslError(
197
+ WorkflowErrorCode.DSL_SEMANTIC_INVALID,
198
+ `Job '${jobKey}' must set exactly one of \`compositionRef\` (long form) or \`mounts\` (short form) on \`with:\`.`,
199
+ { jobKey, actionId: actionManifest.metadata.id },
200
+ );
201
+ }
202
+ }