@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,612 @@
1
+ import { z } from 'zod';
2
+
3
+ import {
4
+ AGENT_RUN_ROLES,
5
+ type AgentRunRole,
6
+ CREDENTIAL_KINDS,
7
+ type CredentialKind,
8
+ MANIFEST_GIT_PUSH_BRANCH_SUFFIXES,
9
+ MANIFEST_GIT_PUSH_CONCURRENCY_MODES,
10
+ MANIFEST_SURFACES,
11
+ type ManifestGitPushBranchSuffix,
12
+ type ManifestGitPushConcurrencyMode,
13
+ type ManifestSurface,
14
+ ModelClassSchema,
15
+ OUTPUT_SURFACE_KINDS,
16
+ type OutputSurfaceKind,
17
+ TOOLSET_KEYS,
18
+ type ToolsetKey,
19
+ } from '@xemahq/kernel-contracts/workflow';
20
+
21
+ // ═══════════════════════════════════════════════════════════════════════════
22
+ // ── Zod schema for WorkspaceManifest YAML ──
23
+ //
24
+ // Mirrors the TypeScript types in `./types.ts`. Used by `compileManifest`
25
+ // for validation; the compiler surfaces issues as `ManifestIssue[]`
26
+ // (inside `CompileResult`) so the Monaco editor can render inline diagnostics.
27
+ // ═══════════════════════════════════════════════════════════════════════════
28
+
29
+ const SlugRegex = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;
30
+ const VersionRegex = /^\d+\.\d+\.\d+$/;
31
+
32
+ export const ManifestInputDeclarationSchema = z.object({
33
+ type: z.enum(['string', 'string[]', 'boolean', 'number', 'object[]']),
34
+ required: z.boolean().optional(),
35
+ /**
36
+ * Default value. The accepted union mirrors `type`:
37
+ * - `string` → string
38
+ * - `number` → number
39
+ * - `boolean` → boolean
40
+ * - `string[]` → readonly string[]
41
+ * - `object[]` → readonly { [k: string]: unknown }[] (structured
42
+ * list-of-objects; renderers consume the shape
43
+ * the producing manifest declares — the DSL does
44
+ * not enforce per-object key validation.)
45
+ */
46
+ default: z
47
+ .union([
48
+ z.string(),
49
+ z.number(),
50
+ z.boolean(),
51
+ z.array(z.string()),
52
+ z.array(z.record(z.string(), z.unknown())),
53
+ ])
54
+ .optional(),
55
+ enum: z.array(z.string()).optional(),
56
+ description: z.string().optional(),
57
+ });
58
+
59
+ /**
60
+ * Mount declaration: either a literal boolean (true=enable with defaults,
61
+ * false=disable inherited mount), OR a strict object with a closed set of
62
+ * configuration keys.
63
+ *
64
+ * Previously this was `z.record(z.string(), z.unknown())` which let any
65
+ * key/value through and made the renderer the de-facto validator. CLAUDE
66
+ * .md requires enums/closed sets at the boundary, so the object form is
67
+ * `.strict()` and rejects unknown keys at compile time.
68
+ */
69
+ export const ManifestMountConfigSchema = z
70
+ .object({
71
+ mode: z.enum(['read-only', 'read-write']).optional(),
72
+ /** Override the mount source path (relative to the upstream root). */
73
+ source: z.string().min(1).optional(),
74
+ /** Override the path the mount appears at inside the workspace. */
75
+ path: z.string().min(1).optional(),
76
+ })
77
+ .strict();
78
+
79
+ export const ManifestMountDeclarationSchema = z.union([
80
+ z.boolean(),
81
+ ManifestMountConfigSchema,
82
+ ]);
83
+
84
+ /**
85
+ * Primitive-only value type for seed-file `vars`. Vars flow into
86
+ * Handlebars rendering; non-primitive values are a footgun (`.toString()`
87
+ * on `[object Object]`) and special keys like `__proto__` /
88
+ * `constructor` / `prototype` can pollute the template context, so we
89
+ * reject those at the schema layer.
90
+ */
91
+ const SafeVarKeyRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
92
+ const RESERVED_VAR_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
93
+ export const ManifestVarsSchema = z
94
+ .record(
95
+ z
96
+ .string()
97
+ .regex(SafeVarKeyRegex, 'var name must match /^[a-zA-Z_][a-zA-Z0-9_]*$/'),
98
+ z.union([z.string(), z.number(), z.boolean()]),
99
+ )
100
+ .refine(
101
+ (vars) => Object.keys(vars).every((k) => !RESERVED_VAR_KEYS.has(k)),
102
+ {
103
+ message:
104
+ 'seed-file vars cannot use reserved keys (__proto__, constructor, prototype)',
105
+ },
106
+ );
107
+
108
+ /**
109
+ * Zod enum for AgentRunRole, sourced from the canonical kernel array.
110
+ * The cast to `readonly [AgentRunRole, ...AgentRunRole[]]` preserves
111
+ * the string-literal union under z.infer, so consumers (compileManifest
112
+ * → CompiledWorkspaceManifest.agent.role) get a strongly-typed value
113
+ * back, not a generic `string`.
114
+ */
115
+ const AgentRunRoleEnumSchema = z.enum(
116
+ AGENT_RUN_ROLES as readonly [AgentRunRole, ...AgentRunRole[]],
117
+ );
118
+
119
+ /**
120
+ * Discriminated `ModelRef` for manifest-level model recommendations.
121
+ * Closed `kind` values match `@xemahq/workflow-contracts:ModelRef` and
122
+ * the `xema/agent` action manifest's `model` property.
123
+ */
124
+ export const ManifestModelRefSchema = z.discriminatedUnion('kind', [
125
+ z.object({
126
+ kind: z.literal('concrete'),
127
+ modelId: z.string().min(1),
128
+ providerSlug: z.string().min(1).optional(),
129
+ temperature: z.number().min(0).max(2).optional(),
130
+ }),
131
+ z.object({
132
+ kind: z.literal('strategy'),
133
+ modelClass: ModelClassSchema,
134
+ temperature: z.number().min(0).max(2).optional(),
135
+ }),
136
+ ]);
137
+
138
+ export const ManifestSubAgentSchema = z
139
+ .object({
140
+ slug: z
141
+ .string()
142
+ .min(1)
143
+ .regex(
144
+ /^[a-z][a-z0-9-]*$/,
145
+ 'sub-agent slug must match /^[a-z][a-z0-9-]*$/',
146
+ ),
147
+ alias: z.string().max(64).optional(),
148
+ defaultModel: ManifestModelRefSchema.optional(),
149
+ })
150
+ .strict();
151
+
152
+ export const ManifestAgentBlockSchema = z
153
+ .object({
154
+ slug: z.string().min(1),
155
+ phase: z.string().min(1),
156
+ /**
157
+ * The agent's role on the surface this manifest provisions. Closed
158
+ * enum — the canonical list lives in `@xemahq/kernel-contracts/workflow`'s
159
+ * `AGENT_RUN_ROLES`. Manifest upserts that name a role outside the
160
+ * list fail at compile time with a typed `ManifestIssue`.
161
+ */
162
+ role: AgentRunRoleEnumSchema,
163
+ deliverableSpecRef: z.string().optional(),
164
+ defaultModel: ManifestModelRefSchema.optional(),
165
+ subAgents: z.array(ManifestSubAgentSchema).optional(),
166
+ })
167
+ .strict()
168
+ .refine(
169
+ (a) => !a.subAgents || a.subAgents.every((s) => s.slug !== a.slug),
170
+ {
171
+ message:
172
+ 'manifest agent block cannot bind itself as a sub-agent (no self-delegation)',
173
+ },
174
+ );
175
+
176
+ /**
177
+ * Closed-set enum schemas built from the canonical kernel arrays. The
178
+ * cast to `[T, ...T[]]` preserves the literal-union under z.infer so
179
+ * compileManifest's output stays strongly typed.
180
+ */
181
+ const ManifestSurfaceEnumSchema = z.enum(
182
+ MANIFEST_SURFACES as readonly [ManifestSurface, ...ManifestSurface[]],
183
+ );
184
+
185
+ const ToolsetKeyEnumSchema = z.enum(
186
+ TOOLSET_KEYS as readonly [ToolsetKey, ...ToolsetKey[]],
187
+ );
188
+
189
+ const CredentialKindEnumSchema = z.enum(
190
+ CREDENTIAL_KINDS as readonly [CredentialKind, ...CredentialKind[]],
191
+ );
192
+
193
+ const OutputSurfaceKindEnumSchema = z.enum(
194
+ OUTPUT_SURFACE_KINDS as readonly [OutputSurfaceKind, ...OutputSurfaceKind[]],
195
+ );
196
+
197
+ /** Generic slug used by skill refs. Looser than the manifest slug. */
198
+ const RefSlugRegex = /^[a-z0-9][a-z0-9._-]*$/;
199
+ const SemverRangeRegex = /^[~^]?\d+(\.\d+(\.\d+)?)?(-[a-zA-Z0-9.-]+)?$/;
200
+
201
+ export const ManifestSkillRefSchema = z
202
+ .object({
203
+ slug: z.string().regex(RefSlugRegex, 'skill slug must match /^[a-z0-9][a-z0-9._-]*$/'),
204
+ version: z.string().regex(SemverRangeRegex, 'version must be a semver pin or range').optional(),
205
+ })
206
+ .strict();
207
+
208
+ export const ManifestCredentialSchema = z
209
+ .object({
210
+ name: z
211
+ .string()
212
+ .min(1)
213
+ .regex(/^[A-Z_][A-Z0-9_]*$/, 'credential names must be UPPER_SNAKE_CASE'),
214
+ kind: CredentialKindEnumSchema,
215
+ sourceRef: z.string().min(1),
216
+ required: z.boolean().optional(),
217
+ })
218
+ .strict();
219
+
220
+ export const ManifestPermissionsSchema = z
221
+ .object({
222
+ tools: z
223
+ .object({
224
+ allow: z.array(ToolsetKeyEnumSchema).optional(),
225
+ deny: z.array(ToolsetKeyEnumSchema).optional(),
226
+ })
227
+ .strict(),
228
+ })
229
+ .strict();
230
+
231
+ const PersistencePathRegex = /^[a-zA-Z0-9_.][a-zA-Z0-9_./-]*$/;
232
+
233
+ const GitPushBranchSuffixEnumSchema = z.enum(
234
+ MANIFEST_GIT_PUSH_BRANCH_SUFFIXES as readonly [
235
+ ManifestGitPushBranchSuffix,
236
+ ...ManifestGitPushBranchSuffix[],
237
+ ],
238
+ );
239
+
240
+ const GitPushConcurrencyModeEnumSchema = z.enum(
241
+ MANIFEST_GIT_PUSH_CONCURRENCY_MODES as readonly [
242
+ ManifestGitPushConcurrencyMode,
243
+ ...ManifestGitPushConcurrencyMode[],
244
+ ],
245
+ );
246
+
247
+ /**
248
+ * Per-slot persistence policy override. Only `git-push` is overridable
249
+ * today because `tarball`/`none` have no fields a biome needs to tune.
250
+ * Schema is `.strict()` so a typo in a closed-set value fails compile.
251
+ */
252
+ export const ManifestSlotPersistenceOverrideSchema = z
253
+ .object({
254
+ kind: z.literal('git-push'),
255
+ branchPrefix: z
256
+ .string()
257
+ .min(1)
258
+ .regex(
259
+ /^[a-zA-Z0-9][a-zA-Z0-9._\-/]*\/$/,
260
+ 'branchPrefix must end with `/` and contain only [A-Za-z0-9._-/]',
261
+ ),
262
+ branchSuffix: GitPushBranchSuffixEnumSchema.optional(),
263
+ concurrencyMode: GitPushConcurrencyModeEnumSchema.optional(),
264
+ })
265
+ .strict();
266
+
267
+ /**
268
+ * Keys allowed inside `persistence.overrides`. Closed to the slot keys
269
+ * that have a non-`none` persistence policy in the AWP kernel — today
270
+ * just `repos` (git-push) and `tmp` / `uploads` / `deliverables`
271
+ * (tarball, no overridable fields, so still rejected at runtime via
272
+ * the `kind: 'git-push'` literal). The compiler additionally validates
273
+ * the key is git-push-persisted on the resolved spec.
274
+ */
275
+ const PersistenceOverrideKeyRegex = /^[a-z][a-z0-9-]*$/;
276
+
277
+ export const ManifestPersistenceSchema = z
278
+ .object({
279
+ paths: z
280
+ .array(
281
+ z
282
+ .string()
283
+ .min(1)
284
+ .regex(PersistencePathRegex, 'persistence path must be /workspace/-relative')
285
+ .refine((p) => !p.includes('..'), {
286
+ message: "persistence path must not contain '..' segments",
287
+ })
288
+ .refine((p) => !p.startsWith('/'), {
289
+ message: 'persistence path must not start with /',
290
+ }),
291
+ )
292
+ .min(1),
293
+ /**
294
+ * Per-slot persistence policy overrides. Replaces the AWP kernel
295
+ * default for the named slot at session lifecycle time. The compile
296
+ * step additionally enforces that each key names a slot whose
297
+ * default policy is `git-push` — overriding a `tarball` or `none`
298
+ * slot is nonsense and fails fast.
299
+ */
300
+ overrides: z
301
+ .record(
302
+ z.string().regex(PersistenceOverrideKeyRegex, 'slot key must be kebab-case'),
303
+ ManifestSlotPersistenceOverrideSchema,
304
+ )
305
+ .optional(),
306
+ })
307
+ .strict();
308
+
309
+ const StaticRootPathRegex = /^[a-zA-Z0-9_.][a-zA-Z0-9_./-]*$/;
310
+
311
+ export const ManifestOutputSurfaceSchema = z
312
+ .object({
313
+ kind: OutputSurfaceKindEnumSchema,
314
+ port: z.number().int().min(1).max(65535).optional(),
315
+ healthPath: z
316
+ .string()
317
+ .min(1)
318
+ .regex(/^\//, 'healthPath must start with /')
319
+ .optional(),
320
+ autoOpen: z.boolean().optional(),
321
+ /**
322
+ * Single-port (legacy) vs. multi-app output surface. `single` is
323
+ * the historical behaviour and the default — one output surface
324
+ * process per session, pinned to `port`. `multi` flips workspace-proxy's
325
+ * output-surface supervisor into per-app mode: it discovers app targets
326
+ * (from `.xema/output-surface.yaml` or autodetection), allocates a port
327
+ * per app, and emits one gateway route per app. When `mode` is
328
+ * `multi`, the top-level `port` is ignored and may be omitted.
329
+ */
330
+ mode: z.enum(['single', 'multi']).optional(),
331
+ /**
332
+ * Workspace-relative directory served by the baked
333
+ * `static-artifact-server.mjs`. REQUIRED when `kind === 'static'`
334
+ * and REJECTED for any other kind.
335
+ */
336
+ root: z
337
+ .string()
338
+ .min(1)
339
+ .regex(StaticRootPathRegex, 'root must be a /workspace/-relative path')
340
+ .refine((p) => !p.includes('..'), {
341
+ message: "root must not contain '..' segments",
342
+ })
343
+ .refine((p) => !p.startsWith('/'), {
344
+ message: 'root must not start with /',
345
+ })
346
+ .optional(),
347
+ /**
348
+ * Default document name for directory requests under a `static`
349
+ * surface (e.g. `index.html`). Only meaningful when
350
+ * `kind === 'static'`.
351
+ */
352
+ defaultDocument: z
353
+ .string()
354
+ .min(1)
355
+ .regex(/^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*$/, 'defaultDocument must be a plain filename')
356
+ .optional(),
357
+ })
358
+ .strict()
359
+ .superRefine((p, ctx) => {
360
+ if (p.kind === 'static') {
361
+ if (p.root === undefined) {
362
+ ctx.addIssue({
363
+ code: z.ZodIssueCode.custom,
364
+ message: "outputSurface.root is required when kind === 'static'",
365
+ path: ['root'],
366
+ });
367
+ }
368
+ if (p.port !== undefined) {
369
+ ctx.addIssue({
370
+ code: z.ZodIssueCode.custom,
371
+ message:
372
+ "outputSurface.port is not allowed when kind === 'static' — the supervisor assigns the port",
373
+ path: ['port'],
374
+ });
375
+ }
376
+ if (p.mode !== undefined && p.mode !== 'single') {
377
+ ctx.addIssue({
378
+ code: z.ZodIssueCode.custom,
379
+ message: "outputSurface.mode must be 'single' (or omitted) when kind === 'static'",
380
+ path: ['mode'],
381
+ });
382
+ }
383
+ return;
384
+ }
385
+ if (p.root !== undefined) {
386
+ ctx.addIssue({
387
+ code: z.ZodIssueCode.custom,
388
+ message: `outputSurface.root is only valid when kind === 'static' (got kind="${p.kind}")`,
389
+ path: ['root'],
390
+ });
391
+ }
392
+ if (p.defaultDocument !== undefined) {
393
+ ctx.addIssue({
394
+ code: z.ZodIssueCode.custom,
395
+ message: `outputSurface.defaultDocument is only valid when kind === 'static' (got kind="${p.kind}")`,
396
+ path: ['defaultDocument'],
397
+ });
398
+ }
399
+ if (p.kind !== 'none' && p.mode !== 'multi' && p.port === undefined) {
400
+ ctx.addIssue({
401
+ code: z.ZodIssueCode.custom,
402
+ message:
403
+ "outputSurface.port is required when kind !== 'none' and mode !== 'multi'",
404
+ path: ['port'],
405
+ });
406
+ }
407
+ });
408
+
409
+ export const ManifestDisplayMetadataSchema = z
410
+ .object({
411
+ title: z.string().min(1).optional(),
412
+ blurb: z.string().min(1).optional(),
413
+ icon: z.string().min(1).optional(),
414
+ category: z.string().min(1).optional(),
415
+ badges: z.array(z.string().min(1)).optional(),
416
+ sortOrder: z.number().int().optional(),
417
+ hidden: z.boolean().optional(),
418
+ ctaText: z.string().min(1).optional(),
419
+ curated: z.boolean().optional(),
420
+ })
421
+ .strict();
422
+
423
+ export const ManifestSeedFileSchema = z
424
+ .object({
425
+ path: z.string().min(1),
426
+ slot: z.string().optional(),
427
+ template: z.string().optional(),
428
+ content: z.string().optional(),
429
+ vars: ManifestVarsSchema.optional(),
430
+ })
431
+ .refine(
432
+ (sf) => sf.template !== undefined || sf.content !== undefined,
433
+ { message: 'seedFile must declare either `template` or `content`' },
434
+ )
435
+ .refine(
436
+ (sf) => !(sf.template !== undefined && sf.content !== undefined),
437
+ { message: 'seedFile cannot declare both `template` and `content`' },
438
+ );
439
+
440
+ export const ManifestEnvVarSchema = z.object({
441
+ name: z
442
+ .string()
443
+ .min(1)
444
+ .regex(/^[A-Z_][A-Z0-9_]*$/, 'env var names must be UPPER_SNAKE_CASE'),
445
+ value: z.string(),
446
+ });
447
+
448
+ /**
449
+ * Working-file declaration (`spec.workingFiles[]`). Closed-set `format` /
450
+ * `syncDirection` enums; `path` is workspace-relative; `slug` is the
451
+ * stable agent-facing identifier; `sourceKind` is an open snake_case
452
+ * string registered with the worker's working-file engine; `sourceRef`
453
+ * is a kind-specific string map (values may carry `${input.x}`).
454
+ */
455
+ const WORKING_FILE_PATH_RE = /^[a-zA-Z0-9_.][a-zA-Z0-9_./-]*$/;
456
+ const WORKING_FILE_SLUG_RE = /^[a-z0-9][a-z0-9._-]*$/;
457
+ const WORKING_FILE_SOURCE_KIND_RE = /^[a-z][a-z0-9-]*(?:_[a-z0-9-]+)*$/;
458
+
459
+ /**
460
+ * Strip every `${input.x}` template token before applying a regex check.
461
+ * `workingFiles[].slug` and `workingFiles[].path` legitimately carry
462
+ * input-template tokens (one document buddy session per KB page, with
463
+ * `slug = ${input.pageSlug}`), and the post-`extends:` schema pass runs
464
+ * BEFORE input interpolation — so the validator MUST tolerate templates
465
+ * on the same characters the regex enforces on the resolved value.
466
+ *
467
+ * After interpolation the workspace pipeline re-validates the resolved
468
+ * literal, so loosening the schema here does not weaken the contract;
469
+ * it just moves the literal-shape check past the substitution boundary.
470
+ */
471
+ const INPUT_TOKEN_RE = /\$\{\s*input\.[a-zA-Z_]\w*\s*\}/g;
472
+ function stripInputTokens(value: string): string {
473
+ return value.replace(INPUT_TOKEN_RE, '');
474
+ }
475
+
476
+ export const ManifestWorkingFileSchema = z
477
+ .object({
478
+ slug: z
479
+ .string()
480
+ .min(1)
481
+ .refine(
482
+ (s) => WORKING_FILE_SLUG_RE.test(stripInputTokens(s) || 'a'),
483
+ 'slug must match /^[a-z0-9][a-z0-9._-]*$/ (input-template tokens permitted)',
484
+ ),
485
+ path: z
486
+ .string()
487
+ .min(1)
488
+ .refine(
489
+ (p) => WORKING_FILE_PATH_RE.test(stripInputTokens(p) || 'a'),
490
+ 'path must be a /workspace/-relative slash path (input-template tokens permitted)',
491
+ )
492
+ .refine((p) => !p.includes('..'), {
493
+ message: "path must not contain '..' segments",
494
+ })
495
+ .refine((p) => !p.startsWith('/'), {
496
+ message: 'path must not start with /',
497
+ }),
498
+ format: z.enum(['markdown', 'html', 'json', 'yaml', 'text']),
499
+ syncDirection: z.enum(['down-only', 'up-only', 'bidirectional']),
500
+ sourceKind: z
501
+ .string()
502
+ .min(1)
503
+ .regex(
504
+ WORKING_FILE_SOURCE_KIND_RE,
505
+ 'sourceKind must be kebab-or-snake case (e.g. kb-page)',
506
+ ),
507
+ sourceRef: z.record(z.string().min(1), z.string()),
508
+ })
509
+ .strict();
510
+
511
+ /**
512
+ * Default tool selection inherited by every session/run booted on
513
+ * this workspace. Shape matches the kernel `ToolSelectionEntry` from
514
+ * `@xemahq/kernel-contracts/mcp-tool`. Resolved at boot via mcp-gateway-api
515
+ * `POST /mcp-resolve` and dropped into `opencode.json:mcp`. Sessions
516
+ * may override per-instance via `PATCH /sessions/:id/tools`.
517
+ */
518
+ export const ManifestToolSelectionEntrySchema = z.discriminatedUnion('kind', [
519
+ z
520
+ .object({
521
+ kind: z.literal('provider'),
522
+ providerKind: z.enum([
523
+ 'mcp_server',
524
+ 'catalog',
525
+ 'biome_workflow_tools',
526
+ 'biome_code_tools',
527
+ ]),
528
+ resourceId: z.string().min(1).max(256),
529
+ })
530
+ .strict(),
531
+ z
532
+ .object({
533
+ kind: z.literal('tool'),
534
+ providerKind: z.enum([
535
+ 'mcp_server',
536
+ 'catalog',
537
+ 'biome_workflow_tools',
538
+ 'biome_code_tools',
539
+ ]),
540
+ resourceId: z.string().min(1).max(256),
541
+ toolName: z.string().min(1).max(256),
542
+ })
543
+ .strict(),
544
+ ]);
545
+
546
+ export const WorkspaceManifestSpecSchema = z.object({
547
+ inputs: z.record(z.string(), ManifestInputDeclarationSchema).optional(),
548
+ mounts: z.record(z.string(), ManifestMountDeclarationSchema).optional(),
549
+ agent: ManifestAgentBlockSchema,
550
+ skills: z.array(ManifestSkillRefSchema).optional(),
551
+ /**
552
+ * Default MCP tool selection for sessions/runs booted on this manifest.
553
+ * Resolved at boot via mcp-gateway-api `POST /mcp-resolve` and merged
554
+ * into `opencode.json:mcp`.
555
+ */
556
+ toolSelection: z.array(ManifestToolSelectionEntrySchema).max(128).optional(),
557
+ credentials: z.array(ManifestCredentialSchema).optional(),
558
+ permissions: ManifestPermissionsSchema.optional(),
559
+ persistence: ManifestPersistenceSchema.optional(),
560
+ outputSurface: ManifestOutputSurfaceSchema.optional(),
561
+ seedFiles: z.array(ManifestSeedFileSchema).optional(),
562
+ env: z.array(ManifestEnvVarSchema).optional(),
563
+ workingFiles: z.array(ManifestWorkingFileSchema).max(32).optional(),
564
+ });
565
+
566
+ export const WorkspaceManifestMetadataSchema = z.object({
567
+ slug: z.string().regex(SlugRegex, 'slug must be lowercase kebab-case'),
568
+ version: z.string().regex(VersionRegex, 'version must follow semver MAJOR.MINOR.PATCH'),
569
+ org: z.string().optional(),
570
+ description: z.string().optional(),
571
+ /**
572
+ * Optional in the YAML for additive rollout; the compiler defaults
573
+ * absent values to `[workflow, agent-session]` so existing
574
+ * manifests keep compiling. New biome/org manifests SHOULD declare
575
+ * this explicitly — Phase 9 sweeps the shipped manifests.
576
+ */
577
+ surfaceCompat: z
578
+ .array(ManifestSurfaceEnumSchema)
579
+ .min(1, 'metadata.surfaceCompat must list at least one surface')
580
+ .optional(),
581
+ display: ManifestDisplayMetadataSchema.optional(),
582
+ });
583
+
584
+ /**
585
+ * `extends:` URI shape — `xema://manifest/<slug>@<version>` (version
586
+ * required; resolver pins to a specific row at compile time so old
587
+ * runs stay deterministic). Validation is lenient on slug chars
588
+ * because biome / org templates may use richer naming than the
589
+ * kernel-shipped slugs.
590
+ */
591
+ const ManifestExtendsRegex = /^xema:\/\/manifest\/[a-z0-9][a-z0-9._-]*@\d+\.\d+\.\d+$/;
592
+
593
+ export const WorkspaceManifestSchema = z
594
+ .object({
595
+ apiVersion: z.literal('xema.dev/workspace/v1'),
596
+ kind: z.literal('WorkspaceManifest'),
597
+ extends: z
598
+ .string()
599
+ .regex(
600
+ ManifestExtendsRegex,
601
+ 'extends must look like `xema://manifest/<slug>@<MAJOR.MINOR.PATCH>`',
602
+ )
603
+ .optional(),
604
+ metadata: WorkspaceManifestMetadataSchema,
605
+ spec: WorkspaceManifestSpecSchema,
606
+ })
607
+ .meta({
608
+ id: 'https://xema.dev/schemas/workspace/v1/WorkspaceManifest.json',
609
+ title: 'Xema WorkspaceManifest',
610
+ description:
611
+ 'Declarative shape of /workspace/ for an agent invocation: mounts, agent block, seed files, env vars.',
612
+ });