@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,208 @@
1
+ import {
2
+ WorkflowErrorCode,
3
+ type WalletContents,
4
+ type WorkflowVariableRequirement,
5
+ } from '@xemahq/kernel-contracts/workflow';
6
+ import { WorkflowDslError } from '../errors';
7
+ import {
8
+ compileExpression,
9
+ ExpressionNodeKind,
10
+ extractInterpolations,
11
+ type ExpressionNode,
12
+ } from '../expression';
13
+ import { ExpressionRoot } from '../expression/ast';
14
+ import { stripInterpolation } from '../expression/interpolation';
15
+ import type { WorkflowDocument } from '../types';
16
+
17
+ /**
18
+ * Compile-time handling of `requires.wallets` and the `vars.*` /
19
+ * `secrets.*` expression namespaces.
20
+ *
21
+ * The compiler trusts the engine to pre-fetch the contents of every
22
+ * wallet listed in `workflow.requires.wallets` (plus any additional
23
+ * wallets the dispatch caller asked for) and pass them as the
24
+ * `resolvedWallets` map. Two responsibilities here, both fail-fast:
25
+ *
26
+ * 1. `WORKFLOW_WALLET_NOT_FOUND` — every wallet name declared under
27
+ * `requires.wallets` must have an entry in `resolvedWallets`.
28
+ * Missing entry = the engine couldn't find the wallet for the
29
+ * workflow's project/org scope.
30
+ *
31
+ * 2. `DSL_EXPRESSION_INVALID` — every `${{ vars.X }}` / `${{ secrets.X }}`
32
+ * member access must resolve to a key in the union of the resolved
33
+ * wallets' contents (modulo the YAML-static `vars:` block which can
34
+ * also satisfy a `vars.X` lookup). Catches typos / stale references
35
+ * at compile time instead of a runtime evaluator failure.
36
+ *
37
+ * The function returns the canonical flat list emitted into
38
+ * `CompiledRun.requiredVariables` — the union of every wallet's
39
+ * `(key, isSecret)` entries with duplicates collapsed (last writer wins
40
+ * for `isSecret` if two wallets disagree; the engine surfaces the
41
+ * conflict at fetch time with a different code).
42
+ */
43
+ export function resolveWalletRequirements(
44
+ doc: WorkflowDocument,
45
+ resolvedWallets: Readonly<Record<string, WalletContents>> | undefined,
46
+ ): readonly WorkflowVariableRequirement[] {
47
+ const declaredWallets = doc.requires?.wallets ?? [];
48
+
49
+ if (resolvedWallets === undefined) {
50
+ // Engine opted out (preview-raw / tests). Skip both checks and
51
+ // emit an empty requirements list — `${{ vars.X }}` / `${{ secrets.X }}`
52
+ // references that don't satisfy the YAML-static fallback will still
53
+ // surface at runtime, which is the documented contract for opt-out.
54
+ return Object.freeze([]);
55
+ }
56
+
57
+ const missingWallets: string[] = [];
58
+ for (const name of declaredWallets) {
59
+ if (!Object.hasOwn(resolvedWallets, name)) {
60
+ missingWallets.push(name);
61
+ }
62
+ }
63
+ if (missingWallets.length > 0) {
64
+ throw new WorkflowDslError(
65
+ WorkflowErrorCode.WORKFLOW_WALLET_NOT_FOUND,
66
+ `Wallet(s) declared in requires.wallets are not available for this project/org scope: ${missingWallets.join(', ')}`,
67
+ { missing: missingWallets },
68
+ );
69
+ }
70
+
71
+ const merged = new Map<string, WorkflowVariableRequirement>();
72
+ for (const name of declaredWallets) {
73
+ const wallet = resolvedWallets[name];
74
+ if (!wallet) {
75
+ // `declaredWallets` is derived from the same `resolvedWallets`
76
+ // map upstream, so a missing entry here would be an internal
77
+ // invariant violation — surface it instead of silently producing
78
+ // an empty merge.
79
+ throw new Error(
80
+ `Internal: declaredWallets references unresolved wallet '${name}'.`,
81
+ );
82
+ }
83
+ for (const entry of wallet.entries) {
84
+ merged.set(entry.key, {
85
+ name: entry.key,
86
+ secret: entry.isSecret,
87
+ optional: false,
88
+ });
89
+ }
90
+ }
91
+ return Object.freeze([...merged.values()]);
92
+ }
93
+
94
+ /**
95
+ * Walk every `${{ ... }}` expression body in the workflow and, for each
96
+ * `vars.<NAME>` / `secrets.<NAME>` member access, verify the referenced
97
+ * name is satisfiable from the resolved wallets (or, for `vars.*` only,
98
+ * from the YAML-static `vars:` block).
99
+ */
100
+ export function validateVariableReferences(
101
+ doc: WorkflowDocument,
102
+ requiredVariables: readonly WorkflowVariableRequirement[],
103
+ resolvedWallets: Readonly<Record<string, WalletContents>> | undefined,
104
+ ): void {
105
+ if (resolvedWallets === undefined) {
106
+ return;
107
+ }
108
+ const staticVarNames = new Set(Object.keys(doc.vars ?? {}));
109
+ const allowedVars = new Set<string>(staticVarNames);
110
+ const allowedSecrets = new Set<string>();
111
+ for (const r of requiredVariables) {
112
+ if (r.secret) {
113
+ allowedSecrets.add(r.name);
114
+ } else {
115
+ allowedVars.add(r.name);
116
+ }
117
+ }
118
+
119
+ for (const { source, pathLabel } of collectAllExpressions(doc)) {
120
+ const ast = compileExpression(source);
121
+ walkVariableAccesses(ast, (root, name) => {
122
+ if (root === ExpressionRoot.VARS && !allowedVars.has(name)) {
123
+ throw new WorkflowDslError(
124
+ WorkflowErrorCode.DSL_EXPRESSION_INVALID,
125
+ `Expression at ${pathLabel} reads vars.${name}, but '${name}' is not provided by workflow.vars or any wallet in requires.wallets.`,
126
+ { pathLabel, root, name, source },
127
+ );
128
+ }
129
+ if (root === ExpressionRoot.SECRETS && !allowedSecrets.has(name)) {
130
+ throw new WorkflowDslError(
131
+ WorkflowErrorCode.DSL_EXPRESSION_INVALID,
132
+ `Expression at ${pathLabel} reads secrets.${name}, but '${name}' is not provided by any wallet in requires.wallets (or the wallet entry is not marked secret).`,
133
+ { pathLabel, root, name, source },
134
+ );
135
+ }
136
+ });
137
+ }
138
+ }
139
+
140
+ interface CollectedExpression {
141
+ readonly source: string;
142
+ readonly pathLabel: string;
143
+ }
144
+
145
+ function collectAllExpressions(doc: WorkflowDocument): CollectedExpression[] {
146
+ const out: CollectedExpression[] = [];
147
+ for (const [jobKey, job] of Object.entries(doc.jobs)) {
148
+ for (const expr of extractInterpolations(job.with, ['jobs', jobKey, 'with'])) {
149
+ out.push({ source: expr.source, pathLabel: expr.path.join('.') });
150
+ }
151
+ for (const expr of extractInterpolations(job.outputs, ['jobs', jobKey, 'outputs'])) {
152
+ out.push({ source: expr.source, pathLabel: expr.path.join('.') });
153
+ }
154
+ if (typeof job.if === 'string' && job.if.length > 0) {
155
+ out.push({ source: stripInterpolation(job.if), pathLabel: `jobs.${jobKey}.if` });
156
+ }
157
+ }
158
+ return out;
159
+ }
160
+
161
+ /**
162
+ * Visits every `<root>.<name>` member access in the AST and invokes
163
+ * `onAccess(root, name)`. Other access shapes are ignored — the caller
164
+ * validates only the first hop, which is sufficient because both
165
+ * `vars.*` and `secrets.*` are string-keyed flat maps.
166
+ */
167
+ function walkVariableAccesses(
168
+ node: ExpressionNode,
169
+ onAccess: (root: ExpressionRoot, name: string) => void,
170
+ ): void {
171
+ switch (node.kind) {
172
+ case ExpressionNodeKind.MEMBER: {
173
+ const target = node.target;
174
+ if (
175
+ target.kind === ExpressionNodeKind.IDENTIFIER &&
176
+ (target.name === ExpressionRoot.VARS ||
177
+ target.name === ExpressionRoot.SECRETS)
178
+ ) {
179
+ onAccess(target.name as ExpressionRoot, node.property);
180
+ return;
181
+ }
182
+ walkVariableAccesses(target, onAccess);
183
+ return;
184
+ }
185
+ case ExpressionNodeKind.INDEX:
186
+ walkVariableAccesses(node.target, onAccess);
187
+ walkVariableAccesses(node.index, onAccess);
188
+ return;
189
+ case ExpressionNodeKind.CALL:
190
+ for (const arg of node.args) {
191
+ walkVariableAccesses(arg, onAccess);
192
+ }
193
+ return;
194
+ case ExpressionNodeKind.UNARY_NOT:
195
+ walkVariableAccesses(node.operand, onAccess);
196
+ return;
197
+ case ExpressionNodeKind.BINARY_EQ:
198
+ case ExpressionNodeKind.BINARY_NEQ:
199
+ case ExpressionNodeKind.BINARY_AND:
200
+ case ExpressionNodeKind.BINARY_OR:
201
+ walkVariableAccesses(node.left, onAccess);
202
+ walkVariableAccesses(node.right, onAccess);
203
+ return;
204
+ case ExpressionNodeKind.IDENTIFIER:
205
+ case ExpressionNodeKind.LITERAL:
206
+ return;
207
+ }
208
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Static introspection of deliverable-spec content to recover the
3
+ * top-level keys an agent's output object MUST expose. The compiler uses
4
+ * these keys to validate workflow expressions of shape
5
+ * `${{ job.outputs.deliverable.content.value.<field> }}` against the
6
+ * spec the producing job declared via `with.deliverableSpecRef` —
7
+ * catching "the YAML reads `.changeUnits` but the spec has
8
+ * `.handoffPackage`" at compile time, not at runtime when projection
9
+ * blows up.
10
+ *
11
+ * Two extractors:
12
+ * - `extractZodTopLevelObjectKeys`: parses a `z.object({ ... })`
13
+ * literal out of TypeScript Zod source. Same regex-based brace walker
14
+ * the deliverable-specs-api ZodSchemaHandler uses for harvest-time
15
+ * validation; single source of truth lives here so the DSL compiler
16
+ * and the harvester agree.
17
+ * - `extractJsonSchemaTopLevelKeys`: pulls keys from the `properties`
18
+ * object of a JSON Schema document.
19
+ *
20
+ * Both return `null` when introspection fails so callers can skip the
21
+ * field check (preview / specs without introspectable shape).
22
+ */
23
+
24
+ /**
25
+ * Parse the FIRST `z.object({ ... })` literal in the source and return
26
+ * the top-level field identifiers. Returns `null` when the literal is
27
+ * absent or its braces are unbalanced — the spec layer fails fast on
28
+ * such specs at content-validation time, but here in the compiler we
29
+ * gracefully degrade so a malformed spec doesn't block unrelated
30
+ * expression checks elsewhere.
31
+ */
32
+ export function extractZodTopLevelObjectKeys(source: string): readonly string[] | null {
33
+ if (!source || source.trim().length === 0) return null;
34
+ const body = sliceTopLevelObjectBody(source);
35
+ if (body === null) return null;
36
+ return Object.freeze(parseObjectKeysAtTopLevel(body));
37
+ }
38
+
39
+ /**
40
+ * Pull the top-level field names from a JSON Schema document. Accepts
41
+ * either a parsed object or a raw JSON string. Honors `properties` —
42
+ * the conventional shape — and ignores `patternProperties` /
43
+ * `additionalProperties` / Draft 2020 `unevaluatedProperties` because
44
+ * those don't enumerate concrete keys an author can reference by name.
45
+ *
46
+ * Returns `null` when the schema is unparseable or has no `properties`
47
+ * map.
48
+ */
49
+ export function extractJsonSchemaTopLevelKeys(
50
+ source: string | object,
51
+ ): readonly string[] | null {
52
+ let parsed: unknown;
53
+ if (typeof source === 'string') {
54
+ if (source.trim().length === 0) return null;
55
+ try {
56
+ parsed = JSON.parse(source);
57
+ } catch {
58
+ return null;
59
+ }
60
+ } else {
61
+ parsed = source;
62
+ }
63
+ if (!isPlainObject(parsed)) return null;
64
+ const properties = (parsed as Record<string, unknown>)['properties'];
65
+ if (!isPlainObject(properties)) return null;
66
+ const keys = Object.keys(properties);
67
+ return Object.freeze(keys);
68
+ }
69
+
70
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
71
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
72
+ }
73
+
74
+ /** Substring between matching braces of the first `z.object({ ... })`, or null. */
75
+ function sliceTopLevelObjectBody(source: string): string | null {
76
+ const match = /z\.object\s*\(\s*\{/.exec(source);
77
+ if (!match) return null;
78
+ const start = match.index + match[0].length;
79
+ let depth = 1;
80
+ for (let i = start; i < source.length; i += 1) {
81
+ const ch = source[i];
82
+ if (ch === '{') depth += 1;
83
+ else if (ch === '}' && --depth === 0) return source.slice(start, i);
84
+ }
85
+ return null;
86
+ }
87
+
88
+ /** Walk the body once, recording identifiers at brace+paren depth 0. */
89
+ function parseObjectKeysAtTopLevel(body: string): string[] {
90
+ const keys: string[] = [];
91
+ const depth = { brace: 0, paren: 0 };
92
+ for (let i = 0; i < body.length; i += 1) {
93
+ if (updateDepth(depth, body[i])) continue;
94
+ if (depth.brace !== 0 || depth.paren !== 0) continue;
95
+ if (i !== 0 && body[i] !== '\n' && body[i] !== ',') continue;
96
+ const rest = body.slice(i === 0 ? 0 : i + 1);
97
+ const keyMatch = /^\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*:/.exec(rest);
98
+ if (keyMatch?.[1]) keys.push(keyMatch[1]);
99
+ }
100
+ return keys;
101
+ }
102
+
103
+ function updateDepth(depth: { brace: number; paren: number }, ch: string | undefined): boolean {
104
+ if (ch === '{') { depth.brace += 1; return true; }
105
+ if (ch === '}') { depth.brace = Math.max(0, depth.brace - 1); return true; }
106
+ if (ch === '(') { depth.paren += 1; return true; }
107
+ if (ch === ')') { depth.paren = Math.max(0, depth.paren - 1); return true; }
108
+ return false;
109
+ }
@@ -0,0 +1,160 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // ── Dispatch-input descriptor extraction ──
3
+ //
4
+ // Shared, tree-shakable module that projects a parsed workflow
5
+ // document's `on.workflow_dispatch.inputs` declaration into a
6
+ // normalized `DispatchInputDescriptor[]` the frontend renders as a
7
+ // dispatch form and the engine consumes for endpoint-returned schema
8
+ // metadata.
9
+ //
10
+ // Single source of truth: the engine and the web frontend both call
11
+ // this function. Keeping the extraction + field-type enumeration in
12
+ // one place removes the "two validation authorities" anti-pattern
13
+ // (per CLAUDE.md fail-fast rule). The pure extraction logic here is
14
+ // NOT validation — the engine's DSL validator (in `lib/validate.ts`)
15
+ // remains the sole validator at compile + dispatch time.
16
+ //
17
+ // No Ajv, no js-yaml — this module is deliberately self-contained so
18
+ // the frontend bundle can import it without pulling heavy
19
+ // transitive deps through tree-shaking.
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+
22
+ /**
23
+ * Closed set of field types surfaced to the dispatch form. Mirrors
24
+ * `WorkflowInputDeclaration.type` but narrows to the subset the form
25
+ * renderer knows how to render. Unknown type values in the parsed
26
+ * document cause the field to be skipped (fail-fast — no silent
27
+ * downgrade to a string input).
28
+ */
29
+ export enum DispatchInputFieldType {
30
+ String = 'string',
31
+ Number = 'number',
32
+ Integer = 'integer',
33
+ Boolean = 'boolean',
34
+ Object = 'object',
35
+ Array = 'array',
36
+ }
37
+
38
+ /**
39
+ * Normalized descriptor the dispatch form consumes. Flat + closed
40
+ * shape so renderer code doesn't have to probe optional fields.
41
+ */
42
+ export interface DispatchInputDescriptor {
43
+ readonly name: string;
44
+ readonly type: DispatchInputFieldType;
45
+ readonly required: boolean;
46
+ readonly description: string | null;
47
+ /** String values only — non-string enum members are dropped. */
48
+ readonly enumValues: readonly string[] | null;
49
+ /** For `type: string`, a hint for multiline rendering. Closed set. */
50
+ readonly format: DispatchInputStringFormat | null;
51
+ /** For `type: array`, the item type (only `string[]` is form-rendered; other item types fall to raw JSON). */
52
+ readonly itemType: DispatchInputFieldType | null;
53
+ readonly defaultValue: unknown;
54
+ }
55
+
56
+ export enum DispatchInputStringFormat {
57
+ Multiline = 'multiline',
58
+ }
59
+
60
+ /**
61
+ * Extracts descriptors from a parsed workflow document. Returns an
62
+ * empty array when the document declares no dispatch inputs (reusable
63
+ * workflows or schedule/webhook-only workflows). Never throws — a
64
+ * malformed inputs bag (unknown `type`, non-object entries) drops the
65
+ * offending field rather than failing the whole extraction, so the
66
+ * dispatch UI stays renderable even if one input declaration is
67
+ * stale. The engine's compile path remains authoritative for
68
+ * validation.
69
+ */
70
+ export function extractDispatchInputDescriptors(
71
+ parsedDocument: unknown,
72
+ ): readonly DispatchInputDescriptor[] {
73
+ const inputs = readDispatchInputsBag(parsedDocument);
74
+ if (!inputs) return [];
75
+ const descriptors: DispatchInputDescriptor[] = [];
76
+ for (const [name, raw] of Object.entries(inputs)) {
77
+ const descriptor = toDescriptor(name, raw);
78
+ if (descriptor !== null) descriptors.push(descriptor);
79
+ }
80
+ return descriptors;
81
+ }
82
+
83
+ function readDispatchInputsBag(
84
+ parsedDocument: unknown,
85
+ ): Record<string, unknown> | null {
86
+ if (!parsedDocument || typeof parsedDocument !== 'object') return null;
87
+ const doc = parsedDocument as Record<string, unknown>;
88
+ const on = doc['on'];
89
+ if (!on || typeof on !== 'object') return null;
90
+ const wfDispatch = (on as Record<string, unknown>)['workflow_dispatch'];
91
+ if (!wfDispatch || typeof wfDispatch !== 'object') return null;
92
+ const inputs = (wfDispatch as Record<string, unknown>)['inputs'];
93
+ if (!inputs || typeof inputs !== 'object' || Array.isArray(inputs)) {
94
+ return null;
95
+ }
96
+ return inputs as Record<string, unknown>;
97
+ }
98
+
99
+ function toDescriptor(
100
+ name: string,
101
+ raw: unknown,
102
+ ): DispatchInputDescriptor | null {
103
+ if (!raw || typeof raw !== 'object') return null;
104
+ const field = raw as Record<string, unknown>;
105
+ const type = parseFieldType(field['type']);
106
+ if (type === null) return null;
107
+ const required = field['required'] === true;
108
+ const description =
109
+ typeof field['description'] === 'string' ? field['description'] : null;
110
+ const enumValues = parseEnumValues(field['enum']);
111
+ const format = parseStringFormat(field['format']);
112
+ const itemType = parseItemType(field['items']);
113
+ return {
114
+ name,
115
+ type,
116
+ required,
117
+ description,
118
+ enumValues,
119
+ format,
120
+ itemType,
121
+ defaultValue: field['default'] ?? undefined,
122
+ };
123
+ }
124
+
125
+ function parseFieldType(value: unknown): DispatchInputFieldType | null {
126
+ if (typeof value !== 'string') return null;
127
+ switch (value) {
128
+ case 'string':
129
+ return DispatchInputFieldType.String;
130
+ case 'number':
131
+ return DispatchInputFieldType.Number;
132
+ case 'integer':
133
+ return DispatchInputFieldType.Integer;
134
+ case 'boolean':
135
+ return DispatchInputFieldType.Boolean;
136
+ case 'object':
137
+ return DispatchInputFieldType.Object;
138
+ case 'array':
139
+ return DispatchInputFieldType.Array;
140
+ default:
141
+ return null;
142
+ }
143
+ }
144
+
145
+ function parseEnumValues(value: unknown): readonly string[] | null {
146
+ if (!Array.isArray(value) || value.length === 0) return null;
147
+ const strings = value.filter((v): v is string => typeof v === 'string');
148
+ return strings.length === value.length ? strings : null;
149
+ }
150
+
151
+ function parseStringFormat(value: unknown): DispatchInputStringFormat | null {
152
+ if (value === 'multiline') return DispatchInputStringFormat.Multiline;
153
+ return null;
154
+ }
155
+
156
+ function parseItemType(value: unknown): DispatchInputFieldType | null {
157
+ if (!value || typeof value !== 'object') return null;
158
+ const items = value as Record<string, unknown>;
159
+ return parseFieldType(items['type']);
160
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ DispatchInputFieldType,
3
+ DispatchInputStringFormat,
4
+ type DispatchInputDescriptor,
5
+ } from './index';
6
+
7
+ /**
8
+ * Project a flat `DispatchInputDescriptor[]` into a JSON Schema
9
+ * Draft 2020-12 object the MCP gateway uses as `inputSchema` on
10
+ * workflow-tool projections (and the frontend dispatch dialog uses
11
+ * for form rendering parity).
12
+ *
13
+ * Single source of truth for the descriptor → JSON Schema mapping so
14
+ * the gateway, the engine, and the frontend agree on the shape an
15
+ * agent sees vs the shape a human sees in the dispatch dialog.
16
+ *
17
+ * Closed-set conservatively: unknown enum values are dropped (the
18
+ * extractor already filters), unknown type combinations fall back to
19
+ * `{ type: 'object' }` to keep the schema valid rather than throwing.
20
+ */
21
+ export function dispatchInputsToJsonSchema(
22
+ descriptors: readonly DispatchInputDescriptor[],
23
+ ): Readonly<Record<string, unknown>> {
24
+ const properties: Record<string, Record<string, unknown>> = {};
25
+ const required: string[] = [];
26
+ for (const d of descriptors) {
27
+ properties[d.name] = descriptorToProperty(d);
28
+ if (d.required) required.push(d.name);
29
+ }
30
+ const schema: Record<string, unknown> = {
31
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
32
+ type: 'object',
33
+ properties,
34
+ additionalProperties: false,
35
+ };
36
+ if (required.length > 0) {
37
+ schema['required'] = required;
38
+ }
39
+ return Object.freeze(schema);
40
+ }
41
+
42
+ function descriptorToProperty(d: DispatchInputDescriptor): Record<string, unknown> {
43
+ const prop: Record<string, unknown> = { type: d.type };
44
+ if (d.description) {
45
+ prop['description'] = d.description;
46
+ }
47
+ if (d.enumValues && d.enumValues.length > 0) {
48
+ prop['enum'] = [...d.enumValues];
49
+ }
50
+ if (d.format === DispatchInputStringFormat.Multiline) {
51
+ prop['x-widget'] = 'multiline';
52
+ }
53
+ if (d.type === DispatchInputFieldType.Array && d.itemType) {
54
+ prop['items'] = { type: d.itemType };
55
+ }
56
+ if (d.defaultValue !== undefined) {
57
+ prop['default'] = d.defaultValue;
58
+ }
59
+ return prop;
60
+ }
@@ -0,0 +1,48 @@
1
+ import { WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
2
+ import { WorkflowDslError } from './errors';
3
+
4
+ /**
5
+ * Duration literal parser. Accepts `<int><unit>` where unit is `s`, `m`, or
6
+ * `h`. Deterministic; rejects malformed input with a typed error. There is
7
+ * no silent zero fallback — callers must pass a value that matches the
8
+ * schema pattern (already enforced by Ajv upstream).
9
+ *
10
+ * Cap: hours limited to 8760 (= 365 days). The cap is a sanity guard
11
+ * against typos (`100000h` ≈ 11 years), not a policy bound — real
12
+ * human-driven flows (compliance reviews, multi-stakeholder approvals,
13
+ * SCM PRs that go a quarter without merging) routinely take months.
14
+ *
15
+ * For redraft loops (`xema/review@v3`), the workflow `continueAsNew`s
16
+ * every 25 iterations, which resets the runtime clock — the practical
17
+ * ceiling on a single review is unbounded. This cap applies only to a
18
+ * single iteration window of the child workflow.
19
+ */
20
+ const MAX_HOURS = 8760;
21
+
22
+ export function parseDurationMs(literal: string): number {
23
+ const match = /^([1-9][0-9]*)(s|m|h)$/.exec(literal);
24
+ if (!match) {
25
+ throw new WorkflowDslError(
26
+ WorkflowErrorCode.DSL_SCHEMA_INVALID,
27
+ `Duration literal does not match pattern <int><s|m|h>: ${literal}`,
28
+ { literal },
29
+ );
30
+ }
31
+ const value = Number.parseInt(match[1]!, 10);
32
+ const unit = match[2] as 's' | 'm' | 'h';
33
+ if (unit === 'h' && value > MAX_HOURS) {
34
+ throw new WorkflowDslError(
35
+ WorkflowErrorCode.DSL_SCHEMA_INVALID,
36
+ `Duration exceeds cap of ${MAX_HOURS}h: ${literal}`,
37
+ { literal, maxHours: MAX_HOURS },
38
+ );
39
+ }
40
+ switch (unit) {
41
+ case 's':
42
+ return value * 1_000;
43
+ case 'm':
44
+ return value * 60_000;
45
+ case 'h':
46
+ return value * 3_600_000;
47
+ }
48
+ }
@@ -0,0 +1,37 @@
1
+ import { WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
2
+
3
+ /**
4
+ * Structured error produced by every DSL entry point (validate, parseYaml,
5
+ * evaluateExpression, compile). Callers MUST branch on `.code` — free-form
6
+ * message matching is forbidden so error handling stays exhaustive.
7
+ */
8
+ export class WorkflowDslError extends Error {
9
+ readonly code: WorkflowErrorCode;
10
+ readonly details: Readonly<Record<string, unknown>>;
11
+
12
+ constructor(
13
+ code: WorkflowErrorCode,
14
+ message: string,
15
+ details: Readonly<Record<string, unknown>> = {},
16
+ ) {
17
+ super(message);
18
+ this.name = 'WorkflowDslError';
19
+ this.code = code;
20
+ this.details = details;
21
+ Object.setPrototypeOf(this, new.target.prototype);
22
+ }
23
+
24
+ toJSON(): Readonly<Record<string, unknown>> {
25
+ return {
26
+ name: this.name,
27
+ code: this.code,
28
+ message: this.message,
29
+ details: this.details,
30
+ };
31
+ }
32
+ }
33
+
34
+ /** Narrowing helper. */
35
+ export function isWorkflowDslError(err: unknown): err is WorkflowDslError {
36
+ return err instanceof WorkflowDslError;
37
+ }