@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.
- package/LICENSE +201 -0
- package/dist/deliverable-spec/index.d.ts +3 -0
- package/dist/deliverable-spec/index.d.ts.map +1 -0
- package/dist/deliverable-spec/index.js +19 -0
- package/dist/deliverable-spec/index.js.map +1 -0
- package/dist/deliverable-spec/lib/schema.d.ts +151 -0
- package/dist/deliverable-spec/lib/schema.d.ts.map +1 -0
- package/dist/deliverable-spec/lib/schema.js +139 -0
- package/dist/deliverable-spec/lib/schema.js.map +1 -0
- package/dist/deliverable-spec/lib/types.d.ts +8 -0
- package/dist/deliverable-spec/lib/types.d.ts.map +1 -0
- package/dist/deliverable-spec/lib/types.js +3 -0
- package/dist/deliverable-spec/lib/types.js.map +1 -0
- package/dist/payload-codec/index.d.ts +8 -0
- package/dist/payload-codec/index.d.ts.map +1 -0
- package/dist/payload-codec/index.js +27 -0
- package/dist/payload-codec/index.js.map +1 -0
- package/dist/payload-codec/lib/blob-store.d.ts +37 -0
- package/dist/payload-codec/lib/blob-store.d.ts.map +1 -0
- package/dist/payload-codec/lib/blob-store.js +0 -0
- package/dist/payload-codec/lib/blob-store.js.map +1 -0
- package/dist/payload-codec/lib/codec-context.d.ts +6 -0
- package/dist/payload-codec/lib/codec-context.d.ts.map +1 -0
- package/dist/payload-codec/lib/codec-context.js +16 -0
- package/dist/payload-codec/lib/codec-context.js.map +1 -0
- package/dist/payload-codec/lib/codec.d.ts +51 -0
- package/dist/payload-codec/lib/codec.d.ts.map +1 -0
- package/dist/payload-codec/lib/codec.js +330 -0
- package/dist/payload-codec/lib/codec.js.map +1 -0
- package/dist/payload-codec/lib/enums.d.ts +18 -0
- package/dist/payload-codec/lib/enums.d.ts.map +1 -0
- package/dist/payload-codec/lib/enums.js +23 -0
- package/dist/payload-codec/lib/enums.js.map +1 -0
- package/dist/payload-codec/lib/errors.d.ts +18 -0
- package/dist/payload-codec/lib/errors.d.ts.map +1 -0
- package/dist/payload-codec/lib/errors.js +39 -0
- package/dist/payload-codec/lib/errors.js.map +1 -0
- package/dist/payload-codec/lib/http-blob-store.d.ts +21 -0
- package/dist/payload-codec/lib/http-blob-store.d.ts.map +1 -0
- package/dist/payload-codec/lib/http-blob-store.js +139 -0
- package/dist/payload-codec/lib/http-blob-store.js.map +1 -0
- package/dist/payload-codec/lib/lru-cache.d.ts +12 -0
- package/dist/payload-codec/lib/lru-cache.d.ts.map +1 -0
- package/dist/payload-codec/lib/lru-cache.js +59 -0
- package/dist/payload-codec/lib/lru-cache.js.map +1 -0
- package/dist/schema/action.schema.json +181 -0
- package/dist/schema/reusable-workflow.schema.json +46 -0
- package/dist/schema/workflow.schema.json +373 -0
- package/dist/workflow/index.d.ts +14 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +49 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/lib/action-input-validator.d.ts +10 -0
- package/dist/workflow/lib/action-input-validator.d.ts.map +1 -0
- package/dist/workflow/lib/action-input-validator.js +69 -0
- package/dist/workflow/lib/action-input-validator.js.map +1 -0
- package/dist/workflow/lib/compiler/action-shape.d.ts +5 -0
- package/dist/workflow/lib/compiler/action-shape.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/action-shape.js +43 -0
- package/dist/workflow/lib/compiler/action-shape.js.map +1 -0
- package/dist/workflow/lib/compiler/canonical-json.d.ts +3 -0
- package/dist/workflow/lib/compiler/canonical-json.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/canonical-json.js +45 -0
- package/dist/workflow/lib/compiler/canonical-json.js.map +1 -0
- package/dist/workflow/lib/compiler/compile.d.ts +4 -0
- package/dist/workflow/lib/compiler/compile.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/compile.js +794 -0
- package/dist/workflow/lib/compiler/compile.js.map +1 -0
- package/dist/workflow/lib/compiler/concurrency.d.ts +5 -0
- package/dist/workflow/lib/compiler/concurrency.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/concurrency.js +104 -0
- package/dist/workflow/lib/compiler/concurrency.js.map +1 -0
- package/dist/workflow/lib/compiler/dag.d.ts +10 -0
- package/dist/workflow/lib/compiler/dag.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/dag.js +74 -0
- package/dist/workflow/lib/compiler/dag.js.map +1 -0
- package/dist/workflow/lib/compiler/index.d.ts +6 -0
- package/dist/workflow/lib/compiler/index.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/index.js +14 -0
- package/dist/workflow/lib/compiler/index.js.map +1 -0
- package/dist/workflow/lib/compiler/inputs.d.ts +4 -0
- package/dist/workflow/lib/compiler/inputs.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/inputs.js +108 -0
- package/dist/workflow/lib/compiler/inputs.js.map +1 -0
- package/dist/workflow/lib/compiler/installation-resource-validator.d.ts +9 -0
- package/dist/workflow/lib/compiler/installation-resource-validator.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/installation-resource-validator.js +76 -0
- package/dist/workflow/lib/compiler/installation-resource-validator.js.map +1 -0
- package/dist/workflow/lib/compiler/manifest-source.d.ts +4 -0
- package/dist/workflow/lib/compiler/manifest-source.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/manifest-source.js +100 -0
- package/dist/workflow/lib/compiler/manifest-source.js.map +1 -0
- package/dist/workflow/lib/compiler/matrix.d.ts +4 -0
- package/dist/workflow/lib/compiler/matrix.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/matrix.js +76 -0
- package/dist/workflow/lib/compiler/matrix.js.map +1 -0
- package/dist/workflow/lib/compiler/mount-plan.d.ts +4 -0
- package/dist/workflow/lib/compiler/mount-plan.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/mount-plan.js +96 -0
- package/dist/workflow/lib/compiler/mount-plan.js.map +1 -0
- package/dist/workflow/lib/compiler/payload-reach-in.d.ts +14 -0
- package/dist/workflow/lib/compiler/payload-reach-in.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/payload-reach-in.js +273 -0
- package/dist/workflow/lib/compiler/payload-reach-in.js.map +1 -0
- package/dist/workflow/lib/compiler/permissions.d.ts +6 -0
- package/dist/workflow/lib/compiler/permissions.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/permissions.js +43 -0
- package/dist/workflow/lib/compiler/permissions.js.map +1 -0
- package/dist/workflow/lib/compiler/retry-timeout.d.ts +6 -0
- package/dist/workflow/lib/compiler/retry-timeout.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/retry-timeout.js +64 -0
- package/dist/workflow/lib/compiler/retry-timeout.js.map +1 -0
- package/dist/workflow/lib/compiler/review-step.d.ts +18 -0
- package/dist/workflow/lib/compiler/review-step.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/review-step.js +247 -0
- package/dist/workflow/lib/compiler/review-step.js.map +1 -0
- package/dist/workflow/lib/compiler/types.d.ts +42 -0
- package/dist/workflow/lib/compiler/types.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/types.js +3 -0
- package/dist/workflow/lib/compiler/types.js.map +1 -0
- package/dist/workflow/lib/compiler/variable-requirements.d.ts +5 -0
- package/dist/workflow/lib/compiler/variable-requirements.d.ts.map +1 -0
- package/dist/workflow/lib/compiler/variable-requirements.js +119 -0
- package/dist/workflow/lib/compiler/variable-requirements.js.map +1 -0
- package/dist/workflow/lib/deliverable-spec-keys.d.ts +3 -0
- package/dist/workflow/lib/deliverable-spec-keys.d.ts.map +1 -0
- package/dist/workflow/lib/deliverable-spec-keys.js +90 -0
- package/dist/workflow/lib/deliverable-spec-keys.js.map +1 -0
- package/dist/workflow/lib/dispatch-inputs/index.d.ts +23 -0
- package/dist/workflow/lib/dispatch-inputs/index.d.ts.map +1 -0
- package/dist/workflow/lib/dispatch-inputs/index.js +106 -0
- package/dist/workflow/lib/dispatch-inputs/index.js.map +1 -0
- package/dist/workflow/lib/dispatch-inputs/to-json-schema.d.ts +3 -0
- package/dist/workflow/lib/dispatch-inputs/to-json-schema.d.ts.map +1 -0
- package/dist/workflow/lib/dispatch-inputs/to-json-schema.js +43 -0
- package/dist/workflow/lib/dispatch-inputs/to-json-schema.js.map +1 -0
- package/dist/workflow/lib/duration.d.ts +2 -0
- package/dist/workflow/lib/duration.d.ts.map +1 -0
- package/dist/workflow/lib/duration.js +26 -0
- package/dist/workflow/lib/duration.js.map +1 -0
- package/dist/workflow/lib/errors.d.ts +9 -0
- package/dist/workflow/lib/errors.d.ts.map +1 -0
- package/dist/workflow/lib/errors.js +28 -0
- package/dist/workflow/lib/errors.js.map +1 -0
- package/dist/workflow/lib/expression/ast.d.ts +61 -0
- package/dist/workflow/lib/expression/ast.d.ts.map +1 -0
- package/dist/workflow/lib/expression/ast.js +34 -0
- package/dist/workflow/lib/expression/ast.js.map +1 -0
- package/dist/workflow/lib/expression/context.d.ts +63 -0
- package/dist/workflow/lib/expression/context.d.ts.map +1 -0
- package/dist/workflow/lib/expression/context.js +32 -0
- package/dist/workflow/lib/expression/context.js.map +1 -0
- package/dist/workflow/lib/expression/evaluator.d.ts +5 -0
- package/dist/workflow/lib/expression/evaluator.d.ts.map +1 -0
- package/dist/workflow/lib/expression/evaluator.js +291 -0
- package/dist/workflow/lib/expression/evaluator.js.map +1 -0
- package/dist/workflow/lib/expression/index.d.ts +9 -0
- package/dist/workflow/lib/expression/index.d.ts.map +1 -0
- package/dist/workflow/lib/expression/index.js +26 -0
- package/dist/workflow/lib/expression/index.js.map +1 -0
- package/dist/workflow/lib/expression/interpolation.d.ts +9 -0
- package/dist/workflow/lib/expression/interpolation.d.ts.map +1 -0
- package/dist/workflow/lib/expression/interpolation.js +51 -0
- package/dist/workflow/lib/expression/interpolation.js.map +1 -0
- package/dist/workflow/lib/expression/parser.d.ts +4 -0
- package/dist/workflow/lib/expression/parser.d.ts.map +1 -0
- package/dist/workflow/lib/expression/parser.js +203 -0
- package/dist/workflow/lib/expression/parser.js.map +1 -0
- package/dist/workflow/lib/expression/template.d.ts +18 -0
- package/dist/workflow/lib/expression/template.d.ts.map +1 -0
- package/dist/workflow/lib/expression/template.js +63 -0
- package/dist/workflow/lib/expression/template.js.map +1 -0
- package/dist/workflow/lib/expression/tokenizer.d.ts +3 -0
- package/dist/workflow/lib/expression/tokenizer.d.ts.map +1 -0
- package/dist/workflow/lib/expression/tokenizer.js +153 -0
- package/dist/workflow/lib/expression/tokenizer.js.map +1 -0
- package/dist/workflow/lib/expression/tokens.d.ts +25 -0
- package/dist/workflow/lib/expression/tokens.d.ts.map +1 -0
- package/dist/workflow/lib/expression/tokens.js +24 -0
- package/dist/workflow/lib/expression/tokens.js.map +1 -0
- package/dist/workflow/lib/expression/walk-artifact-refs.d.ts +5 -0
- package/dist/workflow/lib/expression/walk-artifact-refs.d.ts.map +1 -0
- package/dist/workflow/lib/expression/walk-artifact-refs.js +138 -0
- package/dist/workflow/lib/expression/walk-artifact-refs.js.map +1 -0
- package/dist/workflow/lib/installation-resource-kind.d.ts +14 -0
- package/dist/workflow/lib/installation-resource-kind.d.ts.map +1 -0
- package/dist/workflow/lib/installation-resource-kind.js +59 -0
- package/dist/workflow/lib/installation-resource-kind.js.map +1 -0
- package/dist/workflow/lib/schemas-loader.d.ts +4 -0
- package/dist/workflow/lib/schemas-loader.d.ts.map +1 -0
- package/dist/workflow/lib/schemas-loader.js +36 -0
- package/dist/workflow/lib/schemas-loader.js.map +1 -0
- package/dist/workflow/lib/serializer.d.ts +3 -0
- package/dist/workflow/lib/serializer.d.ts.map +1 -0
- package/dist/workflow/lib/serializer.js +15 -0
- package/dist/workflow/lib/serializer.js.map +1 -0
- package/dist/workflow/lib/types.d.ts +179 -0
- package/dist/workflow/lib/types.d.ts.map +1 -0
- package/dist/workflow/lib/types.js +3 -0
- package/dist/workflow/lib/types.js.map +1 -0
- package/dist/workflow/lib/validate.d.ts +8 -0
- package/dist/workflow/lib/validate.d.ts.map +1 -0
- package/dist/workflow/lib/validate.js +119 -0
- package/dist/workflow/lib/validate.js.map +1 -0
- package/dist/workspace-manifest/index.d.ts +6 -0
- package/dist/workspace-manifest/index.d.ts.map +1 -0
- package/dist/workspace-manifest/index.js +22 -0
- package/dist/workspace-manifest/index.js.map +1 -0
- package/dist/workspace-manifest/lib/compile.d.ts +8 -0
- package/dist/workspace-manifest/lib/compile.d.ts.map +1 -0
- package/dist/workspace-manifest/lib/compile.js +439 -0
- package/dist/workspace-manifest/lib/compile.js.map +1 -0
- package/dist/workspace-manifest/lib/interpolate.d.ts +12 -0
- package/dist/workspace-manifest/lib/interpolate.d.ts.map +1 -0
- package/dist/workspace-manifest/lib/interpolate.js +81 -0
- package/dist/workspace-manifest/lib/interpolate.js.map +1 -0
- package/dist/workspace-manifest/lib/resolve-extends.d.ts +10 -0
- package/dist/workspace-manifest/lib/resolve-extends.d.ts.map +1 -0
- package/dist/workspace-manifest/lib/resolve-extends.js +108 -0
- package/dist/workspace-manifest/lib/resolve-extends.js.map +1 -0
- package/dist/workspace-manifest/lib/schema.d.ts +710 -0
- package/dist/workspace-manifest/lib/schema.d.ts.map +1 -0
- package/dist/workspace-manifest/lib/schema.js +355 -0
- package/dist/workspace-manifest/lib/schema.js.map +1 -0
- package/dist/workspace-manifest/lib/types.d.ts +153 -0
- package/dist/workspace-manifest/lib/types.d.ts.map +1 -0
- package/dist/workspace-manifest/lib/types.js +10 -0
- package/dist/workspace-manifest/lib/types.js.map +1 -0
- package/package.json +79 -0
- package/schema/action.schema.json +181 -0
- package/schema/reusable-workflow.schema.json +46 -0
- package/schema/workflow.schema.json +373 -0
- package/src/deliverable-spec/index.ts +19 -0
- package/src/deliverable-spec/lib/schema.ts +248 -0
- package/src/deliverable-spec/lib/types.ts +26 -0
- package/src/payload-codec/index.ts +40 -0
- package/src/payload-codec/lib/blob-store.ts +0 -0
- package/src/payload-codec/lib/codec-context.ts +38 -0
- package/src/payload-codec/lib/codec.ts +593 -0
- package/src/payload-codec/lib/enums.ts +58 -0
- package/src/payload-codec/lib/errors.ts +54 -0
- package/src/payload-codec/lib/http-blob-store.ts +257 -0
- package/src/payload-codec/lib/lru-cache.ts +81 -0
- package/src/workflow/index.ts +98 -0
- package/src/workflow/lib/action-input-validator.ts +160 -0
- package/src/workflow/lib/compiler/action-shape.ts +71 -0
- package/src/workflow/lib/compiler/canonical-json.ts +53 -0
- package/src/workflow/lib/compiler/compile.ts +1518 -0
- package/src/workflow/lib/compiler/concurrency.ts +223 -0
- package/src/workflow/lib/compiler/dag.ts +108 -0
- package/src/workflow/lib/compiler/index.ts +10 -0
- package/src/workflow/lib/compiler/inputs.ts +199 -0
- package/src/workflow/lib/compiler/installation-resource-validator.ts +114 -0
- package/src/workflow/lib/compiler/manifest-source.ts +176 -0
- package/src/workflow/lib/compiler/matrix.ts +135 -0
- package/src/workflow/lib/compiler/mount-plan.ts +202 -0
- package/src/workflow/lib/compiler/payload-reach-in.ts +497 -0
- package/src/workflow/lib/compiler/permissions.ts +64 -0
- package/src/workflow/lib/compiler/retry-timeout.ts +105 -0
- package/src/workflow/lib/compiler/review-step.ts +517 -0
- package/src/workflow/lib/compiler/types.ts +170 -0
- package/src/workflow/lib/compiler/variable-requirements.ts +208 -0
- package/src/workflow/lib/deliverable-spec-keys.ts +109 -0
- package/src/workflow/lib/dispatch-inputs/index.ts +160 -0
- package/src/workflow/lib/dispatch-inputs/to-json-schema.ts +60 -0
- package/src/workflow/lib/duration.ts +48 -0
- package/src/workflow/lib/errors.ts +37 -0
- package/src/workflow/lib/expression/ast.ts +108 -0
- package/src/workflow/lib/expression/context.ts +148 -0
- package/src/workflow/lib/expression/evaluator.ts +492 -0
- package/src/workflow/lib/expression/index.ts +28 -0
- package/src/workflow/lib/expression/interpolation.ts +84 -0
- package/src/workflow/lib/expression/parser.ts +264 -0
- package/src/workflow/lib/expression/template.ts +117 -0
- package/src/workflow/lib/expression/tokenizer.ts +200 -0
- package/src/workflow/lib/expression/tokens.ts +30 -0
- package/src/workflow/lib/expression/walk-artifact-refs.ts +232 -0
- package/src/workflow/lib/installation-resource-kind.ts +107 -0
- package/src/workflow/lib/schemas-loader.ts +64 -0
- package/src/workflow/lib/serializer.ts +30 -0
- package/src/workflow/lib/types.ts +361 -0
- package/src/workflow/lib/validate.ts +199 -0
- package/src/workspace-manifest/index.ts +27 -0
- package/src/workspace-manifest/lib/compile.ts +608 -0
- package/src/workspace-manifest/lib/interpolate.ts +140 -0
- package/src/workspace-manifest/lib/resolve-extends.ts +260 -0
- package/src/workspace-manifest/lib/schema.ts +612 -0
- 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
|
+
});
|