@xemahq/dsl 0.8.1 → 0.8.3

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 (80) hide show
  1. package/dist/payload-codec/index.d.ts.map +1 -1
  2. package/dist/payload-codec/index.js.map +1 -1
  3. package/dist/payload-codec/lib/codec.d.ts.map +1 -1
  4. package/dist/payload-codec/lib/codec.js +2 -1
  5. package/dist/payload-codec/lib/codec.js.map +1 -1
  6. package/dist/payload-codec/lib/payload.d.ts.map +1 -1
  7. package/dist/schema/action.schema.json +205 -39
  8. package/dist/schema/workflow.schema.json +335 -88
  9. package/dist/workflow/index.d.ts.map +1 -1
  10. package/dist/workflow/index.js.map +1 -1
  11. package/dist/workflow/lib/compiler/compile.js +1 -1
  12. package/dist/workflow/lib/compiler/compile.js.map +1 -1
  13. package/package.json +2 -18
  14. package/schema/action.schema.json +205 -39
  15. package/schema/workflow.schema.json +335 -88
  16. package/dist/payload-codec/temporal/index.d.ts +0 -5
  17. package/dist/payload-codec/temporal/index.d.ts.map +0 -1
  18. package/dist/payload-codec/temporal/index.js +0 -7
  19. package/dist/payload-codec/temporal/index.js.map +0 -1
  20. package/src/deliverable-spec/index.ts +0 -19
  21. package/src/deliverable-spec/lib/schema.ts +0 -270
  22. package/src/deliverable-spec/lib/types.ts +0 -26
  23. package/src/payload-codec/index.ts +0 -44
  24. package/src/payload-codec/lib/blob-store.ts +0 -176
  25. package/src/payload-codec/lib/codec-context.ts +0 -38
  26. package/src/payload-codec/lib/codec.ts +0 -605
  27. package/src/payload-codec/lib/enums.ts +0 -58
  28. package/src/payload-codec/lib/errors.ts +0 -54
  29. package/src/payload-codec/lib/http-blob-store.ts +0 -267
  30. package/src/payload-codec/lib/lru-cache.ts +0 -81
  31. package/src/payload-codec/lib/payload.ts +0 -26
  32. package/src/payload-codec/temporal/index.ts +0 -36
  33. package/src/workflow/index.ts +0 -108
  34. package/src/workflow/lib/action-input-validator.ts +0 -160
  35. package/src/workflow/lib/compiler/action-shape.ts +0 -71
  36. package/src/workflow/lib/compiler/canonical-json.ts +0 -66
  37. package/src/workflow/lib/compiler/compile.ts +0 -1742
  38. package/src/workflow/lib/compiler/concurrency.ts +0 -223
  39. package/src/workflow/lib/compiler/dag.ts +0 -108
  40. package/src/workflow/lib/compiler/gate-defaults.ts +0 -153
  41. package/src/workflow/lib/compiler/index.ts +0 -11
  42. package/src/workflow/lib/compiler/inputs.ts +0 -254
  43. package/src/workflow/lib/compiler/installation-resource-validator.ts +0 -114
  44. package/src/workflow/lib/compiler/manifest-source.ts +0 -71
  45. package/src/workflow/lib/compiler/matrix.ts +0 -135
  46. package/src/workflow/lib/compiler/mount-plan.ts +0 -190
  47. package/src/workflow/lib/compiler/payload-reach-in.ts +0 -497
  48. package/src/workflow/lib/compiler/permissions.ts +0 -64
  49. package/src/workflow/lib/compiler/retry-timeout.ts +0 -105
  50. package/src/workflow/lib/compiler/review-step.ts +0 -548
  51. package/src/workflow/lib/compiler/types.ts +0 -172
  52. package/src/workflow/lib/compiler/variable-requirements.ts +0 -208
  53. package/src/workflow/lib/deliverable-spec-introspection-error.ts +0 -63
  54. package/src/workflow/lib/deliverable-spec-keys.ts +0 -147
  55. package/src/workflow/lib/deliverable-spec-source-scan.ts +0 -280
  56. package/src/workflow/lib/dispatch-inputs/index.ts +0 -160
  57. package/src/workflow/lib/dispatch-inputs/to-json-schema.ts +0 -60
  58. package/src/workflow/lib/duration.ts +0 -43
  59. package/src/workflow/lib/errors.ts +0 -37
  60. package/src/workflow/lib/expression/ast.ts +0 -108
  61. package/src/workflow/lib/expression/context.ts +0 -148
  62. package/src/workflow/lib/expression/evaluator.ts +0 -492
  63. package/src/workflow/lib/expression/index.ts +0 -28
  64. package/src/workflow/lib/expression/interpolation.ts +0 -84
  65. package/src/workflow/lib/expression/parser.ts +0 -264
  66. package/src/workflow/lib/expression/template.ts +0 -117
  67. package/src/workflow/lib/expression/tokenizer.ts +0 -200
  68. package/src/workflow/lib/expression/tokens.ts +0 -30
  69. package/src/workflow/lib/expression/walk-artifact-refs.ts +0 -232
  70. package/src/workflow/lib/installation-resource-kind.ts +0 -107
  71. package/src/workflow/lib/schemas-loader.ts +0 -64
  72. package/src/workflow/lib/serializer.ts +0 -30
  73. package/src/workflow/lib/types.ts +0 -417
  74. package/src/workflow/lib/validate.ts +0 -199
  75. package/src/workspace-manifest/index.ts +0 -27
  76. package/src/workspace-manifest/lib/compile.ts +0 -619
  77. package/src/workspace-manifest/lib/interpolate.ts +0 -166
  78. package/src/workspace-manifest/lib/resolve-extends.ts +0 -260
  79. package/src/workspace-manifest/lib/schema.ts +0 -692
  80. package/src/workspace-manifest/lib/types.ts +0 -446
@@ -1,417 +0,0 @@
1
- import type {
2
- ConcurrencyMode,
3
- PermissionScope,
4
- } from '@xemahq/kernel-contracts/workflow';
5
-
6
- /**
7
- * Authored-shape TypeScript types for a Xema workflow document. These match
8
- * the JSON Schema at schema/workflow.schema.json — validation is the source
9
- * of truth, these types are ergonomics for callers that have already
10
- * validated the input.
11
- *
12
- * Do NOT trust unvalidated user input typed as `WorkflowDocument` — always
13
- * pass through `validateWorkflowDocument(raw)` first, which produces a
14
- * narrowed value safely typed as this interface.
15
- */
16
- export interface WorkflowDocument {
17
- readonly apiVersion: 'xema.dev/workflow/v1alpha1';
18
- readonly kind: 'Workflow';
19
- readonly metadata: WorkflowMetadata;
20
- readonly on: WorkflowTriggerDeclarations;
21
- readonly concurrency?: WorkflowConcurrencyDeclaration;
22
- readonly defaults?: WorkflowDefaults;
23
- readonly permissions?: WorkflowPermissions;
24
- readonly vars?: Readonly<Record<string, unknown>>;
25
- /**
26
- * Wallets (variable + secret bundles) the workflow needs at dispatch
27
- * time. A wallet is a named group of project / org variables managed
28
- * through `project-registry-api`. The engine resolves each declared
29
- * wallet to its contents before starting the run; missing wallets or
30
- * missing keys referenced by `${{ vars.X }}` / `${{ secrets.X }}`
31
- * surface as
32
- * `WorkflowErrorCode.WORKFLOW_WALLET_NOT_FOUND` /
33
- * `WorkflowErrorCode.WORKFLOW_VARIABLES_MISSING` respectively, and
34
- * the run is never started.
35
- *
36
- * Dispatch callers may pass additional wallet names on top of this
37
- * list — additive only.
38
- */
39
- readonly requires?: WorkflowRequiresDeclaration;
40
- readonly jobs: Readonly<Record<string, WorkflowJobDeclaration>>;
41
- /**
42
- * Workflow-level named outputs. Each entry references a single
43
- * `(job, outputName)` pair and declares the kind of value it
44
- * surfaces — deliverable artifact (the most common), structured
45
- * JSON value, or plain text.
46
- *
47
- * Consumers:
48
- * - Biome `mcpWorkflowTools[].outputProjection.slug` (cross-
49
- * referenced at biome boot — the slug MUST match a key here).
50
- * - Future `workflow_call` reusable composition (consumes outputs
51
- * declared by the called workflow).
52
- * - Run-detail projections (`RunResponseDto.deliverables`) — built
53
- * by walking this map against the producing JobRun outputs.
54
- *
55
- * Validation at compile time:
56
- * - `fromJob` MUST exist in `jobs`.
57
- * - `fromOutput` MUST appear in that job's `outputs:` map.
58
- * - For `kind: 'deliverable'`, `deliverableSpecRef` MUST resolve
59
- * through the spec prefetch path.
60
- */
61
- readonly outputs?: Readonly<Record<string, WorkflowOutputDeclaration>>;
62
- }
63
-
64
- /**
65
- * Per-output declaration shape. Discriminated by `kind`. Lives at the
66
- * workflow document level (`workflow.outputs.<name>`), NOT on a job.
67
- * Job-level `outputs:` remain the per-step expressions feeding into
68
- * workflow outputs via `fromJob` / `fromOutput`.
69
- */
70
- export type WorkflowOutputDeclaration =
71
- | WorkflowDeliverableOutputDeclaration
72
- | WorkflowStructuredOutputDeclaration
73
- | WorkflowTextOutputDeclaration;
74
-
75
- interface WorkflowOutputDeclarationBase {
76
- readonly slug: string;
77
- readonly fromJob: string;
78
- readonly fromOutput: string;
79
- readonly description?: string;
80
- }
81
-
82
- export interface WorkflowDeliverableOutputDeclaration
83
- extends WorkflowOutputDeclarationBase {
84
- readonly kind: 'deliverable';
85
- /** Reference to a published `DeliverableSpec` (slug or slug@version). */
86
- readonly deliverableSpecRef: string;
87
- }
88
-
89
- export interface WorkflowStructuredOutputDeclaration
90
- extends WorkflowOutputDeclarationBase {
91
- readonly kind: 'structured';
92
- /** Optional JSON Schema ref the platform validates the value against. */
93
- readonly schemaRef?: string;
94
- }
95
-
96
- export interface WorkflowTextOutputDeclaration
97
- extends WorkflowOutputDeclarationBase {
98
- readonly kind: 'text';
99
- }
100
-
101
- export interface WorkflowRequiresDeclaration {
102
- /** Wallet names; must match `^[a-z][a-z0-9-]{0,62}$`. */
103
- readonly wallets?: readonly string[];
104
- /**
105
- * Connector adapter kinds the workflow consumes. Biome-shipped
106
- * workflows declare these so `biome-host-api` can cross-validate
107
- * them against the biome's manifest `connectorRequirements` at
108
- * boot. Stand-alone workflows (not biome-owned) may also declare
109
- * them as documentation; dispatch-time enforcement only kicks in
110
- * for biome-gated runs.
111
- */
112
- readonly connectors?: readonly WorkflowConnectorRequirement[];
113
- }
114
-
115
- export interface WorkflowConnectorRequirement {
116
- /** Adapter kind slug (e.g. `scm`, `tracker`, `documentation`). */
117
- readonly adapterKind: string;
118
- /** Capability slugs the workflow exercises against the adapter. */
119
- readonly capabilities: readonly string[];
120
- /** Whether the workflow can degrade if the connector is unbound. */
121
- readonly optional?: boolean;
122
- }
123
-
124
- export interface WorkflowMetadata {
125
- readonly name: string;
126
- /**
127
- * Compatibility version for an explicitly reusable public workflow API.
128
- * Ordinary workflows omit this; their immutable revision is generated by
129
- * the workflow registry.
130
- */
131
- readonly contractVersion?: string;
132
- readonly title?: string;
133
- readonly description?: string;
134
- readonly category?: string;
135
- readonly tags?: readonly string[];
136
- }
137
-
138
- export interface WorkflowTriggerDeclarations {
139
- readonly workflow_dispatch?: WorkflowDispatchDeclaration;
140
- readonly schedule?: readonly ScheduleDeclaration[];
141
- readonly webhook?: readonly WebhookDeclaration[];
142
- readonly workflow_call?: WorkflowCallDeclaration;
143
- }
144
-
145
- export interface WorkflowDispatchDeclaration {
146
- readonly inputs?: Readonly<Record<string, WorkflowInputDeclaration>>;
147
- }
148
-
149
- export interface ScheduleDeclaration {
150
- readonly cron: string;
151
- readonly timezone?: string;
152
- readonly inputs?: Readonly<Record<string, unknown>>;
153
- }
154
-
155
- export interface WebhookDeclaration {
156
- readonly event: string;
157
- readonly secretRef?: string;
158
- readonly filters?: Readonly<Record<string, string>>;
159
- }
160
-
161
- export interface WorkflowCallDeclaration {
162
- readonly inputs?: Readonly<Record<string, WorkflowInputDeclaration>>;
163
- readonly outputs?: Readonly<Record<string, string>>;
164
- }
165
-
166
- export interface WorkflowInputDeclaration {
167
- readonly type:
168
- | 'string'
169
- | 'number'
170
- | 'integer'
171
- | 'boolean'
172
- | 'object'
173
- | 'array';
174
- readonly required?: boolean;
175
- readonly default?: unknown;
176
- readonly description?: string;
177
- readonly enum?: readonly unknown[];
178
- readonly items?: Readonly<Record<string, unknown>>;
179
- }
180
-
181
- export interface WorkflowConcurrencyDeclaration {
182
- readonly group: string;
183
- readonly mode: ConcurrencyMode;
184
- }
185
-
186
- export interface WorkflowDefaults {
187
- readonly retry?: WorkflowRetryDeclaration;
188
- readonly timeout?: string;
189
- readonly gate?: WorkflowGateDefaults;
190
- }
191
-
192
- /**
193
- * Workflow-level defaults for decision-gate jobs (`defaults.gate`).
194
- *
195
- * For every job whose `uses:` resolves to the `xema/decision-gate` action
196
- * (matched on the action id, regardless of version), the compiler fills
197
- * each ABSENT `with:` key from this block before any other compile pass
198
- * runs. Explicit per-gate values always win, and the fill happens per
199
- * top-level key only — a gate that declares its own `policy` /
200
- * `recipients` keeps that value verbatim (no partial merge inside it).
201
- *
202
- * Every value may be a `${{ … }}` expression; merged values compile and
203
- * evaluate per-job exactly as if they had been written inline. The key
204
- * set is closed by the JSON schema AND cross-validated at compile time
205
- * against the resolved gate manifest's declared `inputs` (fail-fast on
206
- * drift between the schema's key set and the pinned gate version).
207
- */
208
- export interface WorkflowGateDefaults {
209
- readonly timeoutSeconds?: unknown;
210
- readonly onTimeout?: unknown;
211
- readonly autonomyMode?: unknown;
212
- readonly recipients?: unknown;
213
- readonly policy?: unknown;
214
- readonly escalationChain?: unknown;
215
- }
216
-
217
- export interface WorkflowRetryDeclaration {
218
- readonly maxAttempts?: number;
219
- readonly initialInterval?: string;
220
- readonly backoffCoefficient?: number;
221
- readonly maximumInterval?: string;
222
- readonly nonRetryableErrorTypes?: readonly string[];
223
- }
224
-
225
- export type WorkflowPermissions = Partial<
226
- Record<
227
- 'repos' | 'kb' | 'backlog' | 'connectors' | 'artifacts' | 'memory',
228
- PermissionScope
229
- >
230
- >;
231
-
232
- export interface WorkflowJobDeclaration {
233
- readonly title?: string;
234
- readonly needs?: readonly string[];
235
- readonly if?: string;
236
- readonly strategy?: WorkflowStrategyDeclaration;
237
- readonly matrixGather?: readonly string[];
238
- readonly uses: string;
239
- readonly with?: Readonly<Record<string, unknown>>;
240
- readonly outputs?: Readonly<Record<string, string>>;
241
- readonly retry?: WorkflowRetryDeclaration;
242
- readonly timeout?: string;
243
- readonly permissions?: WorkflowPermissions;
244
- }
245
-
246
- export type WorkflowStrategyDeclaration =
247
- | {
248
- readonly matrix: Readonly<Record<string, readonly unknown[]>>;
249
- readonly maxParallel?: number;
250
- }
251
- | {
252
- readonly dynamic: WorkflowDynamicStrategyDeclaration;
253
- readonly maxParallel?: number;
254
- };
255
-
256
- export interface WorkflowDynamicStrategyDeclaration {
257
- readonly from: string;
258
- readonly as: string;
259
- readonly maxEntries?: number;
260
- /**
261
- * Optional dotted path on each bound entry whose value becomes the
262
- * entry's key in `needs.<thisJob>.outputs.byKey`. Enables per-CU
263
- * downstream consumers to write
264
- * `needs.X.outputs.byKey[matrix.<binding>.<keyBy>].field`. Validated
265
- * lexically by the schema; resolved against actual entries at
266
- * dispatch time.
267
- */
268
- readonly keyBy?: string;
269
- }
270
-
271
- // ── Action manifest ─────────────────────────────────────────────────────
272
-
273
- export interface ActionManifest {
274
- readonly apiVersion: 'xema.dev/workflow/v1alpha1';
275
- readonly kind: 'Action';
276
- readonly metadata: ActionManifestMetadata;
277
- readonly spec: ActionManifestSpec;
278
- }
279
-
280
- export interface ActionManifestMetadata {
281
- readonly id: string;
282
- readonly version: string;
283
- readonly title?: string;
284
- readonly description?: string;
285
- }
286
-
287
- export interface ActionManifestSpec {
288
- readonly executionKind: 'activity' | 'child_workflow';
289
- readonly taskQueue: 'xema_default' | 'xema_agent' | 'xema_human';
290
- /**
291
- * Semantic category — drives consumer presentation (FE canvas
292
- * shape, badge icon). Optional; omitted manifests fall back to
293
- * `generic`. Closed values mirror `ActionKind` in
294
- * `@xemahq/kernel-contracts/workflow`; consumers MUST treat unknown
295
- * strings as `generic` so newer manifests stay safe with older
296
- * clients.
297
- */
298
- readonly actionKind?:
299
- | 'agent'
300
- | 'review'
301
- | 'wait'
302
- | 'timer'
303
- | 'aggregate'
304
- | 'dispatch'
305
- | 'branch'
306
- | 'loop'
307
- | 'publish'
308
- | 'notify'
309
- | 'inquiry'
310
- | 'fetch'
311
- | 'transform'
312
- | 'validate'
313
- | 'terminate'
314
- | 'generic';
315
- readonly inputs: Readonly<Record<string, unknown>>;
316
- readonly outputs: Readonly<Record<string, unknown>>;
317
- /**
318
- * Per-output deliverable-spec bindings.
319
- * Each entry pins a named output to a deliverable-spec ref like
320
- * `agent-summary@1.0.0`. The DSL compiler consults this first when
321
- * resolving typed payload reach-in (`outputs.<name>.<field>`); it
322
- * falls back to the job-level `with.deliverableSpecRef` only when no
323
- * per-output binding is declared, preserving the current single-spec
324
- * agent flow.
325
- *
326
- * Optional. Activities with no fixed per-output spec (e.g. the agent
327
- * activity, whose deliverables spec is workflow-author-chosen) omit
328
- * this. The compiler always proves at least one of (per-output spec,
329
- * job-level spec) is set before letting a reach-in compile.
330
- */
331
- readonly outputBindings?: Readonly<Record<string, ActionOutputBinding>>;
332
- readonly permissions?: WorkflowPermissions;
333
- readonly allowedMounts?: readonly string[];
334
- readonly retryDefaults: ActionManifestRetryDefaults;
335
- readonly timeoutDefaults: ActionManifestTimeoutDefaults;
336
- readonly auditEventMapping?: Partial<{
337
- started: string;
338
- succeeded: string;
339
- failed: string;
340
- }>;
341
- /**
342
- * Declarative contracts the action opts into. The DSL compiler reads
343
- * this list to decide which validation lanes apply — e.g. the
344
- * `workspace-manifest@v1` entry enables the manifest-source lane
345
- * (`agentRef` required) and the frontend canvas Inspector renders the
346
- * manifest picker. Closed-set
347
- * `kind`/`version` pair so biome-shipped agent actions inherit the
348
- * same lanes without per-action-id branching.
349
- *
350
- * Today the only kind is `workspace-manifest`. New kinds extend the
351
- * closed enum (deliverable-spec, knowledge-base-binding, …) with a
352
- * single PR that fans out across the compiler, canvas, and runtime.
353
- */
354
- readonly consumes?: readonly ActionContract[];
355
- }
356
-
357
- /**
358
- * Per-output binding declaration on an action manifest. Today the only
359
- * binding field is `deliverableSpecRef`; future bindings (e.g. KB-page
360
- * slug, custom contracts) extend the type.
361
- */
362
- export interface ActionOutputBinding {
363
- /**
364
- * Deliverable spec ref governing this output's payload shape, in the
365
- * canonical `<slug>@<version>` form (e.g. `metrics-snapshot@1.0.0`).
366
- */
367
- readonly deliverableSpecRef?: string;
368
- }
369
-
370
- /**
371
- * Versioned consume-contract declaration on an action manifest.
372
- *
373
- * `workspace-manifest@v1` — enables the workspace-manifest lane on
374
- * `with:` (`agentRef` is required — the sole agent reference). Optional
375
- * fields:
376
- * - `surfaces`: restricts the surfaces the action can be invoked on
377
- * (must intersect the manifest's `metadata.surfaceCompat`).
378
- * - `roleHint`: pins the manifest's `spec.agent.role` to a closed
379
- * `AgentRunRole`. Compile-time fail when a workflow points the
380
- * action at a manifest whose role doesn't match.
381
- *
382
- * `agent-composition@v1` — enables the `with.composition` field: a
383
- * `slug@version` reference to an Agent (llm-registry-api
384
- * composition registry). The composition is the source of truth for the
385
- * step's agent + sub-agents + skill/tool selection. Resolved at dispatch
386
- * time by the runtime via the composition resolution endpoint. Optional
387
- * and additive — existing workflows that point an agent step at a
388
- * workspace manifest are unaffected.
389
- */
390
- export type ActionContract =
391
- | WorkspaceManifestActionContract
392
- | AgentActionContract;
393
-
394
- export interface WorkspaceManifestActionContract {
395
- readonly kind: 'workspace-manifest';
396
- readonly version: 'v1';
397
- readonly surfaces?: readonly ('workflow' | 'agent-session')[];
398
- readonly roleHint?: string;
399
- }
400
-
401
- export interface AgentActionContract {
402
- readonly kind: 'agent';
403
- readonly version: 'v1';
404
- }
405
-
406
- export interface ActionManifestRetryDefaults {
407
- readonly maxAttempts: number;
408
- readonly initialInterval: string;
409
- readonly backoffCoefficient: number;
410
- readonly maximumInterval: string;
411
- readonly nonRetryableErrorTypes?: readonly string[];
412
- }
413
-
414
- export interface ActionManifestTimeoutDefaults {
415
- readonly startToClose: string;
416
- readonly heartbeat?: string;
417
- }
@@ -1,199 +0,0 @@
1
- import Ajv2020, { type ErrorObject, type ValidateFunction } from 'ajv/dist/2020';
2
- import addFormats from 'ajv-formats';
3
- import { load as parseYaml } from 'js-yaml';
4
- import { WorkflowErrorCode } from '@xemahq/kernel-contracts/workflow';
5
- import { WorkflowDslError } from './errors';
6
- import {
7
- ACTION_SCHEMA,
8
- REUSABLE_WORKFLOW_SCHEMA,
9
- WORKFLOW_SCHEMA,
10
- } from './schemas-loader';
11
- import type { ActionManifest, WorkflowDocument } from './types';
12
-
13
- /**
14
- * Ajv is constructed exactly once per process (module scope). `strict:true`
15
- * keeps us honest — we catch schema authoring bugs at module-load time
16
- * instead of silently coercing them at runtime.
17
- *
18
- * Per-request validation is a hot path; re-compiling schemas would burn CPU
19
- * for no correctness gain. Rule 7 (horizontal scalability): this validator
20
- * is stateless and safe to share across concurrent requests in a NestJS
21
- * process.
22
- *
23
- * `strictRequired` is explicitly disabled: it conflicts with the standard
24
- * JSON-Schema-2020-12 `oneOf` discrimination idiom (`oneOf: [{required:[a]},
25
- * {required:[b]}]`) where the referenced properties are declared in the
26
- * parent subschema's `properties`. The remaining strict flags
27
- * (`strictSchema`, `strictTypes`, `strictTuples`) plus
28
- * `additionalProperties:false` in every object schema already catch the
29
- * typos `strictRequired` would catch, so the safety tradeoff is zero.
30
- */
31
- const ajv = new Ajv2020({
32
- strict: true,
33
- strictSchema: true,
34
- strictTypes: true,
35
- strictRequired: false,
36
- strictTuples: true,
37
- allErrors: true,
38
- allowUnionTypes: false,
39
- useDefaults: false,
40
- validateFormats: true,
41
- });
42
- addFormats(ajv);
43
-
44
- // Register referenced schemas so `$ref` across files resolves. Order
45
- // matters: reusable-workflow references workflow.schema.json by $id.
46
- ajv.addSchema(WORKFLOW_SCHEMA);
47
- ajv.addSchema(REUSABLE_WORKFLOW_SCHEMA);
48
- ajv.addSchema(ACTION_SCHEMA);
49
-
50
- const validateWorkflow = compile<WorkflowDocument>(
51
- 'https://xema.dev/schemas/workflow/v1alpha1/Workflow.json',
52
- );
53
- const validateReusableWorkflow = compile<WorkflowDocument>(
54
- 'https://xema.dev/schemas/workflow/v1alpha1/ReusableWorkflow.json',
55
- );
56
- const validateAction = compile<ActionManifest>(
57
- 'https://xema.dev/schemas/workflow/v1alpha1/Action.json',
58
- );
59
-
60
- function compile<T>(schemaId: string): ValidateFunction<T> {
61
- const fn = ajv.getSchema<T>(schemaId);
62
- if (!fn) {
63
- throw new WorkflowDslError(
64
- WorkflowErrorCode.COMPILE_INTERNAL,
65
- `Ajv failed to compile schema ${schemaId}. Schema registration order is wrong.`,
66
- { schemaId },
67
- );
68
- }
69
- return fn;
70
- }
71
-
72
- /**
73
- * Parse a YAML workflow document and validate it against the workflow
74
- * schema. Returns the narrowed document on success; throws
75
- * {@link WorkflowDslError} with code DSL_SCHEMA_INVALID on any validation
76
- * failure (never silent pass-through, never partial validation).
77
- */
78
- export function parseAndValidateWorkflowYaml(yaml: string): WorkflowDocument {
79
- return parseAndValidate(yaml, validateWorkflow, 'workflow');
80
- }
81
-
82
- /**
83
- * Parse a YAML reusable-workflow document and validate it against the
84
- * reusable-workflow schema.
85
- */
86
- export function parseAndValidateReusableWorkflowYaml(yaml: string): WorkflowDocument {
87
- return parseAndValidate(yaml, validateReusableWorkflow, 'reusable-workflow');
88
- }
89
-
90
- /** Parse a YAML action manifest and validate it against the action schema. */
91
- export function parseAndValidateActionYaml(yaml: string): ActionManifest {
92
- return parseAndValidate(yaml, validateAction, 'action');
93
- }
94
-
95
- /**
96
- * Validate an already-parsed document object. Useful for programmatic
97
- * construction (e.g. tests) and for the engine seeding path that reads
98
- * JSON directly from the DB.
99
- */
100
- export function validateWorkflowDocument(doc: unknown): WorkflowDocument {
101
- if (doc !== null && typeof doc === 'object' && !Array.isArray(doc)) {
102
- normalizeJobNeedsShorthand(doc);
103
- }
104
- return runValidator(doc, validateWorkflow, 'workflow');
105
- }
106
-
107
- export function validateReusableWorkflowDocument(doc: unknown): WorkflowDocument {
108
- if (doc !== null && typeof doc === 'object' && !Array.isArray(doc)) {
109
- normalizeJobNeedsShorthand(doc);
110
- }
111
- return runValidator(doc, validateReusableWorkflow, 'reusable-workflow');
112
- }
113
-
114
- export function validateActionManifest(doc: unknown): ActionManifest {
115
- return runValidator(doc, validateAction, 'action');
116
- }
117
-
118
- function parseAndValidate<T>(
119
- yaml: string,
120
- validator: ValidateFunction<T>,
121
- kind: 'workflow' | 'reusable-workflow' | 'action',
122
- ): T {
123
- let parsed: unknown;
124
- try {
125
- parsed = parseYaml(yaml, { schema: undefined, json: false });
126
- } catch (err) {
127
- throw new WorkflowDslError(
128
- WorkflowErrorCode.DSL_SCHEMA_INVALID,
129
- `YAML parse failure in ${kind} document: ${(err as Error).message}`,
130
- { kind },
131
- );
132
- }
133
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
134
- throw new WorkflowDslError(
135
- WorkflowErrorCode.DSL_SCHEMA_INVALID,
136
- `Top-level YAML value in ${kind} document must be a mapping.`,
137
- { kind },
138
- );
139
- }
140
- // Shorthand: `needs: <string>` → `[<string>]`. Normalize
141
- // BEFORE validation so the schema stays strict (one canonical shape)
142
- // and the rest of the compiler never branches on shorthand. Workflow +
143
- // reusable-workflow documents both have `jobs: { <key>: { needs?... } }`;
144
- // action manifests have no `needs`, so this is a no-op there.
145
- if (kind !== 'action') {
146
- normalizeJobNeedsShorthand(parsed);
147
- }
148
- return runValidator(parsed, validator, kind);
149
- }
150
-
151
- /**
152
- * Mutates `doc.jobs.<key>.needs` from `<string>` to `[<string>]` in
153
- * place. Authors can write either form; the canonical form is the
154
- * array. Documented under "Simplified DSL".
155
- */
156
- function normalizeJobNeedsShorthand(doc: object): void {
157
- const jobs = (doc as { jobs?: unknown }).jobs;
158
- if (!jobs || typeof jobs !== 'object' || Array.isArray(jobs)) return;
159
- for (const job of Object.values(jobs as Record<string, unknown>)) {
160
- if (!job || typeof job !== 'object' || Array.isArray(job)) continue;
161
- const rec = job as Record<string, unknown>;
162
- if (typeof rec.needs === 'string') {
163
- rec.needs = [rec.needs];
164
- }
165
- }
166
- }
167
-
168
- function runValidator<T>(
169
- doc: unknown,
170
- validator: ValidateFunction<T>,
171
- kind: 'workflow' | 'reusable-workflow' | 'action',
172
- ): T {
173
- if (validator(doc)) {
174
- return doc;
175
- }
176
- const errors = validator.errors ?? [];
177
- throw new WorkflowDslError(
178
- WorkflowErrorCode.DSL_SCHEMA_INVALID,
179
- `Schema validation failed for ${kind} document: ${formatErrors(errors)}`,
180
- { kind, issues: errors.map(formatIssue) },
181
- );
182
- }
183
-
184
- function formatIssue(err: ErrorObject): Readonly<Record<string, unknown>> {
185
- return {
186
- instancePath: err.instancePath,
187
- schemaPath: err.schemaPath,
188
- keyword: err.keyword,
189
- message: err.message ?? '',
190
- params: err.params,
191
- };
192
- }
193
-
194
- function formatErrors(errors: readonly ErrorObject[]): string {
195
- if (errors.length === 0) return '(no detail)';
196
- return errors
197
- .map((e) => `${e.instancePath || '/'} ${e.message ?? ''} [${e.keyword}]`.trim())
198
- .join('; ');
199
- }
@@ -1,27 +0,0 @@
1
- // ═══════════════════════════════════════════════════════════════════════════
2
- // ── @xemahq/workspace-manifest-dsl ──
3
- //
4
- // Schema, compiler, and interpolation engine for `AgentWorkspaceSpec`
5
- // YAMLs. A manifest declares the SHAPE of `/workspace/` for an agent
6
- // invocation — which user-data slots are populated, which agent runs,
7
- // which seed files are dropped in.
8
- //
9
- // Consumers:
10
- // - `biomes/agent-runtime/api/llm-registry-api` (composition seeder): compiles each
11
- // biome-shipped manifest and projects it into a published
12
- // `Agent` row.
13
- // - `packages/agent-session-runtime` (composer): turns a compiled
14
- // manifest + bind inputs into a `WorkspaceMountPlan` that gets
15
- // applied via workspace-proxy `/workspace/mounts/apply`.
16
- // - `packages/workflow-dsl`: validates inline `mounts:` blocks on
17
- // `xema/agent` jobs at workflow compile time.
18
- //
19
- // Sibling to `@xemahq/workflow-dsl`. Workflow DSL describes the
20
- // process; workspace manifest describes the environment shape.
21
- // ═══════════════════════════════════════════════════════════════════════════
22
-
23
- export * from './lib/types';
24
- export * from './lib/schema';
25
- export * from './lib/interpolate';
26
- export * from './lib/compile';
27
- export * from './lib/resolve-extends';