@xemahq/kernel-contracts 0.28.0 → 0.30.0

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 (151) hide show
  1. package/dist/document-patch/index.d.ts +4 -0
  2. package/dist/document-patch/index.d.ts.map +1 -0
  3. package/dist/document-patch/index.js +20 -0
  4. package/dist/document-patch/index.js.map +1 -0
  5. package/dist/document-patch/lib/patch-anchor.d.ts +7 -0
  6. package/dist/document-patch/lib/patch-anchor.d.ts.map +1 -0
  7. package/dist/document-patch/lib/patch-anchor.js +14 -0
  8. package/dist/document-patch/lib/patch-anchor.js.map +1 -0
  9. package/dist/document-patch/lib/patch-enums.d.ts +11 -0
  10. package/dist/document-patch/lib/patch-enums.d.ts.map +1 -0
  11. package/dist/document-patch/lib/patch-enums.js +16 -0
  12. package/dist/document-patch/lib/patch-enums.js.map +1 -0
  13. package/dist/document-patch/lib/pending-patch.d.ts +22 -0
  14. package/dist/document-patch/lib/pending-patch.d.ts.map +1 -0
  15. package/dist/document-patch/lib/pending-patch.js +3 -0
  16. package/dist/document-patch/lib/pending-patch.js.map +1 -0
  17. package/dist/output/index.d.ts +7 -0
  18. package/dist/output/index.d.ts.map +1 -0
  19. package/dist/output/index.js +23 -0
  20. package/dist/output/index.js.map +1 -0
  21. package/dist/output/lib/output-deliverable-expectation.d.ts +9 -0
  22. package/dist/output/lib/output-deliverable-expectation.d.ts.map +1 -0
  23. package/dist/output/lib/output-deliverable-expectation.js +3 -0
  24. package/dist/output/lib/output-deliverable-expectation.js.map +1 -0
  25. package/dist/output/lib/output-item-dto.d.ts +25 -0
  26. package/dist/output/lib/output-item-dto.d.ts.map +1 -0
  27. package/dist/output/lib/output-item-dto.js +3 -0
  28. package/dist/output/lib/output-item-dto.js.map +1 -0
  29. package/dist/output/lib/output-kind.d.ts +14 -0
  30. package/dist/output/lib/output-kind.d.ts.map +1 -0
  31. package/dist/output/lib/output-kind.js +18 -0
  32. package/dist/output/lib/output-kind.js.map +1 -0
  33. package/dist/output/lib/output-render-hint.d.ts +11 -0
  34. package/dist/output/lib/output-render-hint.d.ts.map +1 -0
  35. package/dist/output/lib/output-render-hint.js +10 -0
  36. package/dist/output/lib/output-render-hint.js.map +1 -0
  37. package/dist/output/lib/output-version-dto.d.ts +10 -0
  38. package/dist/output/lib/output-version-dto.d.ts.map +1 -0
  39. package/dist/output/lib/output-version-dto.js +3 -0
  40. package/dist/output/lib/output-version-dto.js.map +1 -0
  41. package/dist/output/lib/payload-schemas/code-diff.d.ts +7 -0
  42. package/dist/output/lib/payload-schemas/code-diff.d.ts.map +1 -0
  43. package/dist/output/lib/payload-schemas/code-diff.js +11 -0
  44. package/dist/output/lib/payload-schemas/code-diff.js.map +1 -0
  45. package/dist/output/lib/payload-schemas/decision-record.d.ts +19 -0
  46. package/dist/output/lib/payload-schemas/decision-record.d.ts.map +1 -0
  47. package/dist/output/lib/payload-schemas/decision-record.js +39 -0
  48. package/dist/output/lib/payload-schemas/decision-record.js.map +1 -0
  49. package/dist/output/lib/payload-schemas/diagram.d.ts +12 -0
  50. package/dist/output/lib/payload-schemas/diagram.d.ts.map +1 -0
  51. package/dist/output/lib/payload-schemas/diagram.js +34 -0
  52. package/dist/output/lib/payload-schemas/diagram.js.map +1 -0
  53. package/dist/output/lib/payload-schemas/external-blob.d.ts +9 -0
  54. package/dist/output/lib/payload-schemas/external-blob.d.ts.map +1 -0
  55. package/dist/output/lib/payload-schemas/external-blob.js +15 -0
  56. package/dist/output/lib/payload-schemas/external-blob.js.map +1 -0
  57. package/dist/output/lib/payload-schemas/index.d.ts +17 -0
  58. package/dist/output/lib/payload-schemas/index.d.ts.map +1 -0
  59. package/dist/output/lib/payload-schemas/index.js +94 -0
  60. package/dist/output/lib/payload-schemas/index.js.map +1 -0
  61. package/dist/output/lib/payload-schemas/json-payload.d.ts +4 -0
  62. package/dist/output/lib/payload-schemas/json-payload.d.ts.map +1 -0
  63. package/dist/output/lib/payload-schemas/json-payload.js +9 -0
  64. package/dist/output/lib/payload-schemas/json-payload.js.map +1 -0
  65. package/dist/output/lib/payload-schemas/manifest.d.ts +37 -0
  66. package/dist/output/lib/payload-schemas/manifest.d.ts.map +1 -0
  67. package/dist/output/lib/payload-schemas/manifest.js +43 -0
  68. package/dist/output/lib/payload-schemas/manifest.js.map +1 -0
  69. package/dist/output/lib/payload-schemas/markdown-doc.d.ts +8 -0
  70. package/dist/output/lib/payload-schemas/markdown-doc.d.ts.map +1 -0
  71. package/dist/output/lib/payload-schemas/markdown-doc.js +12 -0
  72. package/dist/output/lib/payload-schemas/markdown-doc.js.map +1 -0
  73. package/dist/output/lib/payload-schemas/review-findings.d.ts +30 -0
  74. package/dist/output/lib/payload-schemas/review-findings.d.ts.map +1 -0
  75. package/dist/output/lib/payload-schemas/review-findings.js +39 -0
  76. package/dist/output/lib/payload-schemas/review-findings.js.map +1 -0
  77. package/dist/output/lib/payload-schemas/schema.d.ts +4 -0
  78. package/dist/output/lib/payload-schemas/schema.d.ts.map +1 -0
  79. package/dist/output/lib/payload-schemas/schema.js +10 -0
  80. package/dist/output/lib/payload-schemas/schema.js.map +1 -0
  81. package/dist/output/lib/payload-schemas/test-report.d.ts +33 -0
  82. package/dist/output/lib/payload-schemas/test-report.d.ts.map +1 -0
  83. package/dist/output/lib/payload-schemas/test-report.js +46 -0
  84. package/dist/output/lib/payload-schemas/test-report.js.map +1 -0
  85. package/dist/output-surface-inspect/index.d.ts +3 -0
  86. package/dist/output-surface-inspect/index.d.ts.map +1 -0
  87. package/dist/output-surface-inspect/index.js +19 -0
  88. package/dist/output-surface-inspect/index.js.map +1 -0
  89. package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts +226 -0
  90. package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts.map +1 -0
  91. package/dist/output-surface-inspect/lib/output-surface-inspect.js +85 -0
  92. package/dist/output-surface-inspect/lib/output-surface-inspect.js.map +1 -0
  93. package/dist/output-surface-inspect/lib/step-schema.d.ts +64 -0
  94. package/dist/output-surface-inspect/lib/step-schema.d.ts.map +1 -0
  95. package/dist/output-surface-inspect/lib/step-schema.js +73 -0
  96. package/dist/output-surface-inspect/lib/step-schema.js.map +1 -0
  97. package/dist/output-surface-inspect/runtime/index.d.ts +2 -0
  98. package/dist/output-surface-inspect/runtime/index.d.ts.map +1 -0
  99. package/dist/output-surface-inspect/runtime/index.js +18 -0
  100. package/dist/output-surface-inspect/runtime/index.js.map +1 -0
  101. package/dist/workspace-image/index.d.ts +5 -0
  102. package/dist/workspace-image/index.d.ts.map +1 -0
  103. package/dist/workspace-image/index.js +21 -0
  104. package/dist/workspace-image/index.js.map +1 -0
  105. package/dist/workspace-image/lib/enums.d.ts +17 -0
  106. package/dist/workspace-image/lib/enums.d.ts.map +1 -0
  107. package/dist/workspace-image/lib/enums.js +22 -0
  108. package/dist/workspace-image/lib/enums.js.map +1 -0
  109. package/dist/workspace-image/lib/hash.d.ts +3 -0
  110. package/dist/workspace-image/lib/hash.d.ts.map +1 -0
  111. package/dist/workspace-image/lib/hash.js +50 -0
  112. package/dist/workspace-image/lib/hash.js.map +1 -0
  113. package/dist/workspace-image/lib/schemas.d.ts +103 -0
  114. package/dist/workspace-image/lib/schemas.d.ts.map +1 -0
  115. package/dist/workspace-image/lib/schemas.js +53 -0
  116. package/dist/workspace-image/lib/schemas.js.map +1 -0
  117. package/dist/workspace-image/lib/types.d.ts +50 -0
  118. package/dist/workspace-image/lib/types.d.ts.map +1 -0
  119. package/dist/workspace-image/lib/types.js +3 -0
  120. package/dist/workspace-image/lib/types.js.map +1 -0
  121. package/package.json +1 -1
  122. package/src/document-patch/index.ts +25 -0
  123. package/src/document-patch/lib/patch-anchor.ts +22 -0
  124. package/src/document-patch/lib/patch-enums.ts +36 -0
  125. package/src/document-patch/lib/pending-patch.ts +31 -0
  126. package/src/output/index.ts +20 -0
  127. package/src/output/lib/output-deliverable-expectation.ts +25 -0
  128. package/src/output/lib/output-item-dto.ts +54 -0
  129. package/src/output/lib/output-kind.ts +44 -0
  130. package/src/output/lib/output-render-hint.ts +28 -0
  131. package/src/output/lib/output-version-dto.ts +21 -0
  132. package/src/output/lib/payload-schemas/code-diff.ts +20 -0
  133. package/src/output/lib/payload-schemas/decision-record.ts +71 -0
  134. package/src/output/lib/payload-schemas/diagram.ts +54 -0
  135. package/src/output/lib/payload-schemas/external-blob.ts +36 -0
  136. package/src/output/lib/payload-schemas/index.ts +133 -0
  137. package/src/output/lib/payload-schemas/json-payload.ts +19 -0
  138. package/src/output/lib/payload-schemas/manifest.ts +81 -0
  139. package/src/output/lib/payload-schemas/markdown-doc.ts +33 -0
  140. package/src/output/lib/payload-schemas/review-findings.ts +75 -0
  141. package/src/output/lib/payload-schemas/schema.ts +22 -0
  142. package/src/output/lib/payload-schemas/test-report.ts +69 -0
  143. package/src/output-surface-inspect/index.ts +4 -0
  144. package/src/output-surface-inspect/lib/output-surface-inspect.ts +427 -0
  145. package/src/output-surface-inspect/lib/step-schema.ts +107 -0
  146. package/src/output-surface-inspect/runtime/index.ts +7 -0
  147. package/src/workspace-image/index.ts +13 -0
  148. package/src/workspace-image/lib/enums.ts +38 -0
  149. package/src/workspace-image/lib/hash.ts +95 -0
  150. package/src/workspace-image/lib/schemas.ts +63 -0
  151. package/src/workspace-image/lib/types.ts +79 -0
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Architectural Decision Record (ADR) status — RFC-style lifecycle.
5
+ *
6
+ * Closed enum so the FE can render distinctive pills per state
7
+ * (`accepted` green, `superseded` strikethrough, etc.). Producers
8
+ * MUST pick one; freeform strings are rejected so we don't grow a
9
+ * long tail of bespoke statuses.
10
+ */
11
+ export enum DecisionRecordStatus {
12
+ PROPOSED = 'proposed',
13
+ ACCEPTED = 'accepted',
14
+ REJECTED = 'rejected',
15
+ DEPRECATED = 'deprecated',
16
+ SUPERSEDED = 'superseded',
17
+ }
18
+
19
+ export const DecisionRecordStatusSchema = z.nativeEnum(DecisionRecordStatus);
20
+
21
+ /**
22
+ * Payload shape for `OutputKind.DECISION_RECORD` artifacts.
23
+ *
24
+ * Follows the Michael Nygard ADR template — title, status, context,
25
+ * decision, consequences. Each field is markdown so the FE renderer
26
+ * can present them as separate sections with appropriate framing
27
+ * (status pill, headings, etc.).
28
+ *
29
+ * Backward-compat: producers that pre-date this schema emit a single
30
+ * `body` markdown string (legacy convention shared across all
31
+ * markdown-bearing kinds via `textViewOfPayload`). The schema
32
+ * tolerates that by making every structured field optional and
33
+ * requiring at-least-one-of via `superRefine`. New producers should
34
+ * emit the structured fields so the renderer's rich form lights up.
35
+ */
36
+ export const DecisionRecordPayloadSchema = z
37
+ .object({
38
+ title: z.string().optional(),
39
+ status: DecisionRecordStatusSchema.optional(),
40
+ context: z.string().optional(),
41
+ decision: z.string().optional(),
42
+ consequences: z.string().optional(),
43
+ /**
44
+ * Legacy / fallback: a single markdown document holding the whole
45
+ * ADR. New producers SHOULD prefer the structured fields; this
46
+ * stays for backward-compatibility and for cases where the ADR
47
+ * doesn't map cleanly onto the four-section template.
48
+ */
49
+ body: z.string().optional(),
50
+ })
51
+ .passthrough()
52
+ .superRefine((value, ctx) => {
53
+ const structuredFields = [
54
+ value.context,
55
+ value.decision,
56
+ value.consequences,
57
+ ];
58
+ const hasStructured = structuredFields.some(
59
+ (v) => typeof v === 'string' && v.trim().length > 0,
60
+ );
61
+ const hasBody = typeof value.body === 'string' && value.body.trim().length > 0;
62
+ if (!hasStructured && !hasBody) {
63
+ ctx.addIssue({
64
+ code: 'custom',
65
+ message:
66
+ 'decision_record payload must include at least one of `body` or the structured fields (`context`, `decision`, `consequences`).',
67
+ });
68
+ }
69
+ });
70
+
71
+ export type DecisionRecordPayload = z.infer<typeof DecisionRecordPayloadSchema>;
@@ -0,0 +1,54 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Diagram-dialect enum. Closed today on `mermaid` only — the FE
5
+ * renderer pipeline can ingest mermaid via the existing
6
+ * `MarkdownView` mermaid block. Add new values here when a new
7
+ * dialect (drawio, plantuml, …) has a renderer wired.
8
+ */
9
+ export enum DiagramDialect {
10
+ MERMAID = 'mermaid',
11
+ }
12
+
13
+ export const DiagramDialectSchema = z.nativeEnum(DiagramDialect);
14
+
15
+ /**
16
+ * Payload shape for `OutputKind.DIAGRAM` artifacts — standalone
17
+ * diagrams emitted by architecture / requirements agents.
18
+ *
19
+ * Two valid shapes (mirroring how `xema/emit-artifact` producers
20
+ * actually emit today):
21
+ *
22
+ * 1. Inline source: `{ type: 'mermaid', source: '<mermaid src>' }`.
23
+ * 2. Markdown fallback: `{ body: '...mermaid block...' }` — when
24
+ * the producer wrapped a mermaid fence in a markdown narrative.
25
+ *
26
+ * The FE `DiagramRenderer` reads `source` when present, else falls
27
+ * through to markdown rendering which itself supports mermaid.
28
+ */
29
+ export const DiagramPayloadSchema = z
30
+ .object({
31
+ type: DiagramDialectSchema.optional(),
32
+ source: z.string().optional(),
33
+ body: z.string().optional(),
34
+ })
35
+ .passthrough()
36
+ .superRefine((value, ctx) => {
37
+ const hasSource = typeof value.source === 'string' && value.source.trim().length > 0;
38
+ const hasBody = typeof value.body === 'string' && value.body.trim().length > 0;
39
+ if (!hasSource && !hasBody) {
40
+ ctx.addIssue({
41
+ code: 'custom',
42
+ message: 'diagram payload must include either `source` or `body`.',
43
+ });
44
+ }
45
+ if (hasSource && value.type === undefined) {
46
+ ctx.addIssue({
47
+ code: 'custom',
48
+ path: ['type'],
49
+ message: 'diagram payload with `source` must declare `type` (e.g. `mermaid`).',
50
+ });
51
+ }
52
+ });
53
+
54
+ export type DiagramPayload = z.infer<typeof DiagramPayloadSchema>;
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Payload shape for `OutputKind.EXTERNAL_BLOB` artifacts — images,
5
+ * PDFs, archives, and other binary content stored out-of-band in
6
+ * MinIO / S3.
7
+ *
8
+ * The `payload` itself is metadata about the external bytes. The
9
+ * actual bytes live behind `ArtifactVersion.pointer` (durable
10
+ * storage URI) and are streamed via the artifact-store's
11
+ * version-content endpoint, NOT carried inline.
12
+ *
13
+ * `contentType` (IANA media type) is required so the FE renderer
14
+ * can branch on preview mode (image / pdf / video / download).
15
+ * `size` is informational. `originalFilename` flows into the
16
+ * download affordance when present.
17
+ */
18
+ export const ExternalBlobPayloadSchema = z
19
+ .object({
20
+ contentType: z
21
+ .string()
22
+ .min(1, 'external_blob.contentType must be a non-empty IANA media type'),
23
+ /** Byte count, when known. Producers without it may omit. */
24
+ size: z.number().nonnegative().int().optional(),
25
+ /** Original filename, used as the download attachment name. */
26
+ originalFilename: z.string().optional(),
27
+ /**
28
+ * Producer-supplied alt text for image-kind blobs (a11y) and
29
+ * for any future LLM-briefing path that needs a non-visual
30
+ * description.
31
+ */
32
+ altText: z.string().optional(),
33
+ })
34
+ .passthrough();
35
+
36
+ export type ExternalBlobPayload = z.infer<typeof ExternalBlobPayloadSchema>;
@@ -0,0 +1,133 @@
1
+ import type { ZodTypeAny } from 'zod';
2
+
3
+ import { CodeDiffPayloadSchema } from './code-diff';
4
+ import { DecisionRecordPayloadSchema } from './decision-record';
5
+ import { DiagramPayloadSchema } from './diagram';
6
+ import { ExternalBlobPayloadSchema } from './external-blob';
7
+ import { JsonPayloadPayloadSchema } from './json-payload';
8
+ import { ManifestPayloadSchema } from './manifest';
9
+ import { MarkdownDocPayloadSchema } from './markdown-doc';
10
+ import { ReviewFindingsPayloadSchema } from './review-findings';
11
+ import { JsonSchemaPayloadSchema } from './schema';
12
+ import { TestReportPayloadSchema } from './test-report';
13
+
14
+ import { OutputKind } from '../output-kind';
15
+
16
+ export * from './code-diff';
17
+ export * from './decision-record';
18
+ export * from './diagram';
19
+ export * from './external-blob';
20
+ export * from './json-payload';
21
+ export * from './manifest';
22
+ export * from './markdown-doc';
23
+ export * from './review-findings';
24
+ export * from './schema';
25
+ export * from './test-report';
26
+
27
+ /**
28
+ * Registry mapping closed `OutputKind` → Zod schema for the matching
29
+ * artifact payload. Every kind that has a renderer also has a schema;
30
+ * `OutputKind.UNKNOWN` is intentionally absent — biome-supplied
31
+ * payloads we can't classify are NOT validated (they pass through to
32
+ * the `unknown` renderer's "Show raw" surface).
33
+ *
34
+ * Keeping the registry keyed on `OutputKind` rather than free-form
35
+ * `type` strings means: the `(type → OutputKind)` mapping is the single
36
+ * place biomes add new aliases; once a producer's `type` resolves to
37
+ * a known kind, validation kicks in automatically.
38
+ */
39
+ export const OUTPUT_KIND_PAYLOAD_SCHEMAS: Readonly<
40
+ Partial<Record<OutputKind, ZodTypeAny>>
41
+ > = {
42
+ [OutputKind.MARKDOWN_DOC]: MarkdownDocPayloadSchema,
43
+ [OutputKind.CODE_DIFF]: CodeDiffPayloadSchema,
44
+ [OutputKind.DECISION_RECORD]: DecisionRecordPayloadSchema,
45
+ [OutputKind.REVIEW_FINDINGS]: ReviewFindingsPayloadSchema,
46
+ [OutputKind.SCHEMA]: JsonSchemaPayloadSchema,
47
+ [OutputKind.MANIFEST]: ManifestPayloadSchema,
48
+ [OutputKind.TEST_REPORT]: TestReportPayloadSchema,
49
+ [OutputKind.DIAGRAM]: DiagramPayloadSchema,
50
+ [OutputKind.JSON_PAYLOAD]: JsonPayloadPayloadSchema,
51
+ [OutputKind.EXTERNAL_BLOB]: ExternalBlobPayloadSchema,
52
+ };
53
+
54
+ /**
55
+ * Closed mapping from producer-supplied `type` string (the
56
+ * `EmitArtifactDto.type` value) → `OutputKind` enum. This is the
57
+ * platform's authoritative `type → kind` table; the FE and BE both
58
+ * read from here. Biomes that ship new aliases for an existing kind
59
+ * extend this map via a biome-host extension point (future) or
60
+ * register a new OutputKind (kernel-level).
61
+ *
62
+ * Order is irrelevant — duplicate keys would be a build-time error
63
+ * in TS, and the map is frozen at module load.
64
+ */
65
+ export const ARTIFACT_TYPE_TO_OUTPUT_KIND: Readonly<Record<string, OutputKind>> = {
66
+ // markdown_doc
67
+ document_page: OutputKind.MARKDOWN_DOC,
68
+ 'markdown.doc': OutputKind.MARKDOWN_DOC,
69
+ 'doc.markdown': OutputKind.MARKDOWN_DOC,
70
+ 'requirements.doc': OutputKind.MARKDOWN_DOC,
71
+ 'design.doc': OutputKind.MARKDOWN_DOC,
72
+ 'spec.doc': OutputKind.MARKDOWN_DOC,
73
+ // code_diff
74
+ 'code.diff': OutputKind.CODE_DIFF,
75
+ 'src.diff': OutputKind.CODE_DIFF,
76
+ 'patch.diff': OutputKind.CODE_DIFF,
77
+ // decision_record
78
+ 'decision.record': OutputKind.DECISION_RECORD,
79
+ adr: OutputKind.DECISION_RECORD,
80
+ // review_findings
81
+ 'review.findings': OutputKind.REVIEW_FINDINGS,
82
+ 'review.report': OutputKind.REVIEW_FINDINGS,
83
+ 'review.verdict': OutputKind.REVIEW_FINDINGS,
84
+ // schema
85
+ schema: OutputKind.SCHEMA,
86
+ 'json.schema': OutputKind.SCHEMA,
87
+ // manifest
88
+ manifest: OutputKind.MANIFEST,
89
+ 'workflow.manifest': OutputKind.MANIFEST,
90
+ 'biome.manifest': OutputKind.MANIFEST,
91
+ // test_report
92
+ 'test.report': OutputKind.TEST_REPORT,
93
+ 'qa.report': OutputKind.TEST_REPORT,
94
+ // diagram
95
+ diagram: OutputKind.DIAGRAM,
96
+ mermaid: OutputKind.DIAGRAM,
97
+ // json_payload
98
+ endpoint_fetch_response: OutputKind.JSON_PAYLOAD,
99
+ structured_json: OutputKind.JSON_PAYLOAD,
100
+ 'json.payload': OutputKind.JSON_PAYLOAD,
101
+ // external_blob
102
+ 'image.png': OutputKind.EXTERNAL_BLOB,
103
+ 'image.jpeg': OutputKind.EXTERNAL_BLOB,
104
+ 'binary.blob': OutputKind.EXTERNAL_BLOB,
105
+ };
106
+
107
+ /**
108
+ * Resolve a producer-supplied `type` to the matching `OutputKind`.
109
+ * Returns `undefined` when no mapping exists — callers treat that as
110
+ * "biome-defined custom type" and skip schema validation, falling
111
+ * through to the `unknown` renderer downstream.
112
+ */
113
+ export function outputKindForType(type: string): OutputKind | undefined {
114
+ return ARTIFACT_TYPE_TO_OUTPUT_KIND[type];
115
+ }
116
+
117
+ /**
118
+ * Resolve the Zod payload schema for a given `type` string, going
119
+ * through the `type → OutputKind → schema` chain. Returns
120
+ * `undefined` when the `type` is unknown OR when the kind has no
121
+ * registered schema (today only `OutputKind.UNKNOWN`).
122
+ *
123
+ * Callers (artifact-store-api's `EmitArtifactValidator`,
124
+ * future FE preview helpers) treat `undefined` as "pass through —
125
+ * no schema-level validation for this type". Biome extensibility is
126
+ * preserved: a custom `my-org.special-output` type that's not in the
127
+ * table simply isn't validated, exactly as today.
128
+ */
129
+ export function payloadSchemaForType(type: string): ZodTypeAny | undefined {
130
+ const kind = outputKindForType(type);
131
+ if (kind === undefined) {return undefined;}
132
+ return OUTPUT_KIND_PAYLOAD_SCHEMAS[kind];
133
+ }
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Payload shape for `OutputKind.JSON_PAYLOAD` artifacts — the
5
+ * deliberate "structured JSON without a more specific kind" bucket.
6
+ * Used today by `xema/http`, `xema/endpoint-fetch`, and any producer
7
+ * emitting an opaque JSON envelope.
8
+ *
9
+ * Permissive by design — the WHOLE payload IS the deliverable, no
10
+ * particular field is required. Validation just ensures it's an
11
+ * object (not a bare primitive); arrays masquerading as the root are
12
+ * also accepted via the union below.
13
+ */
14
+ export const JsonPayloadPayloadSchema = z.union([
15
+ z.record(z.string(), z.unknown()),
16
+ z.array(z.unknown()),
17
+ ]);
18
+
19
+ export type JsonPayloadPayload = z.infer<typeof JsonPayloadPayloadSchema>;
@@ -0,0 +1,81 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * One reference inside a manifest's `refs[]` — a pointer to a KB page,
5
+ * a backlog item, an emitted file, or any other tracked artifact the
6
+ * manifest summarises.
7
+ */
8
+ export const ManifestRefSchema = z
9
+ .object({
10
+ /** Closed-ish set of ref kinds; producers may extend via .passthrough(). */
11
+ type: z.string().min(1),
12
+ id: z.string().min(1),
13
+ title: z.string().optional(),
14
+ /** Producer-defined verb describing what happened to the ref (created / modified / referenced / …). */
15
+ action: z.string().optional(),
16
+ /** File-system path for `file`-kind refs. */
17
+ path: z.string().optional(),
18
+ })
19
+ .passthrough();
20
+
21
+ export type ManifestRef = z.infer<typeof ManifestRefSchema>;
22
+
23
+ /**
24
+ * An inline diagram embedded in the manifest. Today only `mermaid`
25
+ * is supported; the FE renders via the existing mermaid pipeline in
26
+ * `MarkdownView`.
27
+ */
28
+ export const ManifestDiagramSchema = z
29
+ .object({
30
+ key: z.string().min(1),
31
+ title: z.string().min(1),
32
+ type: z.literal('mermaid'),
33
+ source: z.string().min(1),
34
+ })
35
+ .passthrough();
36
+
37
+ export type ManifestDiagram = z.infer<typeof ManifestDiagramSchema>;
38
+
39
+ /**
40
+ * Payload shape for `OutputKind.MANIFEST` artifacts — phase summaries,
41
+ * workflow manifests, biome manifests, and any structured "summary
42
+ * with cross-references" document.
43
+ *
44
+ * Two render shapes the FE recognises:
45
+ *
46
+ * 1. Rich manifest: `{ schemaVersion, summary, refs[]?, diagrams[]? }`.
47
+ * The FE renderer (`ManifestRenderer`, plus the legacy
48
+ * `ArtifactContentViewer`) renders the summary as markdown with
49
+ * phase + ref + diagram sidebars.
50
+ * 2. Plain YAML/JSON: `{ body: string }`. The renderer falls back
51
+ * to monospaced text preserving indentation.
52
+ *
53
+ * `passthrough()` so the `schemaVersion` field — which is a producer-
54
+ * declared manifest version, distinct from the artifact-store's
55
+ * `EmitArtifactDto.schemaVersion` — flows through.
56
+ */
57
+ export const ManifestPayloadSchema = z
58
+ .object({
59
+ schemaVersion: z.string().optional(),
60
+ summary: z.string().optional(),
61
+ refs: z.array(ManifestRefSchema).optional(),
62
+ diagrams: z.array(ManifestDiagramSchema).optional(),
63
+ body: z.string().optional(),
64
+ stageKey: z.string().optional(),
65
+ })
66
+ .passthrough()
67
+ .superRefine((value, ctx) => {
68
+ const hasSummary =
69
+ typeof value.summary === 'string' && value.summary.trim().length > 0;
70
+ const hasBody = typeof value.body === 'string' && value.body.trim().length > 0;
71
+ const hasRefs = Array.isArray(value.refs) && value.refs.length > 0;
72
+ if (!hasSummary && !hasBody && !hasRefs) {
73
+ ctx.addIssue({
74
+ code: 'custom',
75
+ message:
76
+ 'manifest payload must include at least one of `summary`, `body`, or non-empty `refs[]`.',
77
+ });
78
+ }
79
+ });
80
+
81
+ export type ManifestPayload = z.infer<typeof ManifestPayloadSchema>;
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Payload shape for `OutputKind.MARKDOWN_DOC` artifacts.
5
+ *
6
+ * The canonical document-page shape across the platform. Used by the
7
+ * deliverable harvester (one artifact per page), `xema/emit-artifact`
8
+ * with markdown content, requirements/design/spec agents, and KB-bound
9
+ * publications.
10
+ *
11
+ * `body` is the rendered narrative — markdown source. The FE renderer
12
+ * (`MarkdownDocRenderer`) reads `body` directly via
13
+ * `useArtifactContent.textViewOfPayload` and renders it through
14
+ * `MarkdownView` (react-markdown + remark-gfm + mermaid).
15
+ *
16
+ * `slug` and `parentSlug` are KB-publish hints; the publish-kb activity
17
+ * reads them when present, otherwise it derives slugs from the
18
+ * artifact's title + phase. They are NOT required at emit-time — a
19
+ * deliverable that's reviewed but never published has no slug.
20
+ *
21
+ * `.passthrough()` is intentional: producers may attach arbitrary
22
+ * extras (e.g. front-matter metadata, agent commentary) without the
23
+ * schema rejecting the emit.
24
+ */
25
+ export const MarkdownDocPayloadSchema = z
26
+ .object({
27
+ body: z.string().min(1, 'markdown_doc.body must be non-empty'),
28
+ slug: z.string().optional(),
29
+ parentSlug: z.string().optional(),
30
+ })
31
+ .passthrough();
32
+
33
+ export type MarkdownDocPayload = z.infer<typeof MarkdownDocPayloadSchema>;
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Closed severity enum for `ReviewFinding.severity`. Drives FE
5
+ * grouping + colouring in `ReviewFindingsRenderer`. `info` is
6
+ * commentary that doesn't gate a verdict; `minor` / `major` /
7
+ * `blocking` escalate.
8
+ */
9
+ export enum ReviewFindingSeverity {
10
+ INFO = 'info',
11
+ MINOR = 'minor',
12
+ MAJOR = 'major',
13
+ BLOCKING = 'blocking',
14
+ }
15
+
16
+ export const ReviewFindingSeveritySchema = z.nativeEnum(ReviewFindingSeverity);
17
+
18
+ /**
19
+ * A single finding inside a review-findings payload.
20
+ *
21
+ * `anchor` is a free-form string today (pre-W3C-anchor migration on
22
+ * REVIEW inquiries). Producers conventionally use shapes like
23
+ * `file:path:line` or `heading:slug`. A future tightening could
24
+ * promote this to a `WebAnnotationTarget` once the producer fleet
25
+ * is migrated, matching the inquiry-side anchor work.
26
+ */
27
+ export const ReviewFindingSchema = z
28
+ .object({
29
+ severity: ReviewFindingSeveritySchema,
30
+ message: z.string().min(1, 'review_findings.findings[].message must be non-empty'),
31
+ anchor: z.string().optional(),
32
+ })
33
+ .passthrough();
34
+
35
+ export type ReviewFinding = z.infer<typeof ReviewFindingSchema>;
36
+
37
+ /**
38
+ * Payload shape for `OutputKind.REVIEW_FINDINGS` artifacts — emitted
39
+ * by reviewer agents inside `xema/review` iterations.
40
+ *
41
+ * Two valid shapes (the FE renderer detects both):
42
+ *
43
+ * 1. Structured: `findings: ReviewFinding[]` — preferred. Renders
44
+ * as a severity-grouped table with anchors.
45
+ * 2. Legacy: `body: string` — markdown narrative of the review.
46
+ * The renderer falls back to markdown rendering when `findings`
47
+ * is absent.
48
+ *
49
+ * `verdict` + `summary` are optional rollups — the reviewer's
50
+ * top-line answer and a short paragraph framing the detailed
51
+ * findings.
52
+ */
53
+ export const ReviewFindingsPayloadSchema = z
54
+ .object({
55
+ findings: z.array(ReviewFindingSchema).optional(),
56
+ verdict: z.enum(['approve', 'reject', 'abstain']).optional(),
57
+ summary: z.string().optional(),
58
+ body: z.string().optional(),
59
+ })
60
+ .passthrough()
61
+ .superRefine((value, ctx) => {
62
+ const hasFindings = Array.isArray(value.findings) && value.findings.length > 0;
63
+ const hasBody = typeof value.body === 'string' && value.body.trim().length > 0;
64
+ const hasSummary =
65
+ typeof value.summary === 'string' && value.summary.trim().length > 0;
66
+ if (!hasFindings && !hasBody && !hasSummary) {
67
+ ctx.addIssue({
68
+ code: 'custom',
69
+ message:
70
+ 'review_findings payload must include at least one of `findings[]`, `summary`, or `body`.',
71
+ });
72
+ }
73
+ });
74
+
75
+ export type ReviewFindingsPayload = z.infer<typeof ReviewFindingsPayloadSchema>;
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Payload shape for `OutputKind.SCHEMA` artifacts — JSON Schema
5
+ * documents declared by agents.
6
+ *
7
+ * The payload IS the JSON Schema document. We don't dictate which
8
+ * dialect (Draft 07, 2020-12, OpenAPI) — the validator we use
9
+ * downstream picks based on the document's own `$schema` field.
10
+ * Minimum check: it must be a non-empty object.
11
+ *
12
+ * The FE `SchemaRenderer` reads the payload directly via
13
+ * `useArtifactContent.payload` (NOT `content`) and renders the
14
+ * schema as a typed tree.
15
+ */
16
+ export const JsonSchemaPayloadSchema = z
17
+ .record(z.string(), z.unknown())
18
+ .refine((v) => Object.keys(v).length > 0, {
19
+ message: 'schema payload must be a non-empty JSON Schema document.',
20
+ });
21
+
22
+ export type JsonSchemaPayload = z.infer<typeof JsonSchemaPayloadSchema>;
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Outcome of a single test in a test-report payload. Closed enum
5
+ * because the FE renders each state with distinctive iconography.
6
+ */
7
+ export enum TestOutcome {
8
+ PASSED = 'passed',
9
+ FAILED = 'failed',
10
+ SKIPPED = 'skipped',
11
+ ERRORED = 'errored',
12
+ }
13
+
14
+ export const TestOutcomeSchema = z.nativeEnum(TestOutcome);
15
+
16
+ export const TestCaseSchema = z
17
+ .object({
18
+ name: z.string().min(1),
19
+ outcome: TestOutcomeSchema,
20
+ /** Duration in milliseconds; producers without timing data omit. */
21
+ durationMs: z.number().nonnegative().optional(),
22
+ /** Failure / error message for FAILED + ERRORED outcomes. */
23
+ message: z.string().optional(),
24
+ /** Optional path to the file under test (e.g. `src/auth.test.ts`). */
25
+ file: z.string().optional(),
26
+ })
27
+ .passthrough();
28
+
29
+ export type TestCase = z.infer<typeof TestCaseSchema>;
30
+
31
+ /**
32
+ * Payload shape for `OutputKind.TEST_REPORT` artifacts.
33
+ *
34
+ * `tests[]` is the per-case detail; the rollup counters
35
+ * (`passed`, `failed`, `skipped`, `errored`) are derived from
36
+ * `tests[]` when present but may be supplied directly when the
37
+ * producer only has aggregate numbers.
38
+ *
39
+ * `body` is the legacy markdown fallback (same pattern as other
40
+ * markdown-bearing kinds).
41
+ */
42
+ export const TestReportPayloadSchema = z
43
+ .object({
44
+ tests: z.array(TestCaseSchema).optional(),
45
+ passed: z.number().nonnegative().int().optional(),
46
+ failed: z.number().nonnegative().int().optional(),
47
+ skipped: z.number().nonnegative().int().optional(),
48
+ errored: z.number().nonnegative().int().optional(),
49
+ summary: z.string().optional(),
50
+ body: z.string().optional(),
51
+ })
52
+ .passthrough()
53
+ .superRefine((value, ctx) => {
54
+ const hasTests = Array.isArray(value.tests) && value.tests.length > 0;
55
+ const hasCounters =
56
+ typeof value.passed === 'number' ||
57
+ typeof value.failed === 'number' ||
58
+ typeof value.skipped === 'number';
59
+ const hasBody = typeof value.body === 'string' && value.body.trim().length > 0;
60
+ if (!hasTests && !hasCounters && !hasBody) {
61
+ ctx.addIssue({
62
+ code: 'custom',
63
+ message:
64
+ 'test_report payload must include at least one of `tests[]`, the rollup counters, or `body`.',
65
+ });
66
+ }
67
+ });
68
+
69
+ export type TestReportPayload = z.infer<typeof TestReportPayloadSchema>;
@@ -0,0 +1,4 @@
1
+ // Pure, zod-free contract — safe to bundle into the browser-side bridge.
2
+ export * from './lib/output-surface-inspect';
3
+ // Runtime zod validator — pulled in by agent-session-api's broker only.
4
+ export * from './lib/step-schema';