@dazl/api-client 1.0.43 → 1.0.45

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.
@@ -0,0 +1,243 @@
1
+ import { z } from "zod";
2
+ /** The only schema version there has ever been. Interactive fields are ordinary optional fields. */
3
+ export declare const WORKFLOW_DOCUMENT_SCHEMA_VERSION = "1";
4
+ /** Directory the editor creates workflow files in. Discovery is by extension, not by directory. */
5
+ export declare const WORKFLOWS_DIR = "workflows";
6
+ export declare const WORKFLOW_FILE_EXTENSION = ".flow.json";
7
+ /** How a run can start. A closed set: nothing else starts a run, and there is no schedule trigger. */
8
+ export declare const TRIGGER_SOURCES: readonly ["workspace-prompt", "chat-prompt", "chat-agent-tool"];
9
+ export type TriggerSource = (typeof TRIGGER_SOURCES)[number];
10
+ /** A non-empty path relative to the project root that cannot leave it. */
11
+ export declare const projectRelativePathSchema: z.ZodString;
12
+ /**
13
+ * What every node produces. The same shape for every node in every workflow — it is not authored and
14
+ * is not part of the document. A step that needs to hand on anything richer than prose writes a file
15
+ * and names it here.
16
+ */
17
+ export declare const workflowNodeOutputSchema: z.ZodObject<{
18
+ text: z.ZodString;
19
+ files: z.ZodDefault<z.ZodArray<z.ZodString>>;
20
+ changes: z.ZodOptional<z.ZodArray<z.ZodObject<{
21
+ dirName: z.ZodString;
22
+ from: z.ZodString;
23
+ to: z.ZodString;
24
+ commits: z.ZodNumber;
25
+ files: z.ZodArray<z.ZodString>;
26
+ }, z.core.$strip>>>;
27
+ }, z.core.$strip>;
28
+ export type WorkflowNodeOutput = z.infer<typeof workflowNodeOutputSchema>;
29
+ /** One reviewer on a review node: an agent, optionally speaking for a person. */
30
+ export declare const workflowReviewerSchema: z.ZodObject<{
31
+ agent: z.ZodString;
32
+ prompt: z.ZodOptional<z.ZodString>;
33
+ onBehalfOf: z.ZodOptional<z.ZodString>;
34
+ conversationRole: z.ZodOptional<z.ZodEnum<{
35
+ personal: "personal";
36
+ workspace: "workspace";
37
+ }>>;
38
+ }, z.core.$strip>;
39
+ export type WorkflowReviewer = z.infer<typeof workflowReviewerSchema>;
40
+ export declare const workflowNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
41
+ id: z.ZodString;
42
+ title: z.ZodString;
43
+ description: z.ZodOptional<z.ZodString>;
44
+ position: z.ZodObject<{
45
+ x: z.ZodNumber;
46
+ y: z.ZodNumber;
47
+ }, z.core.$strip>;
48
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
49
+ size: z.ZodOptional<z.ZodObject<{
50
+ width: z.ZodNumber;
51
+ height: z.ZodNumber;
52
+ }, z.core.$strip>>;
53
+ nextStep: z.ZodOptional<z.ZodString>;
54
+ skippable: z.ZodDefault<z.ZodBoolean>;
55
+ kind: z.ZodLiteral<"trigger">;
56
+ source: z.ZodEnum<{
57
+ "workspace-prompt": "workspace-prompt";
58
+ "chat-prompt": "chat-prompt";
59
+ "chat-agent-tool": "chat-agent-tool";
60
+ }>;
61
+ }, z.core.$strip>, z.ZodObject<{
62
+ id: z.ZodString;
63
+ title: z.ZodString;
64
+ description: z.ZodOptional<z.ZodString>;
65
+ position: z.ZodObject<{
66
+ x: z.ZodNumber;
67
+ y: z.ZodNumber;
68
+ }, z.core.$strip>;
69
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
70
+ size: z.ZodOptional<z.ZodObject<{
71
+ width: z.ZodNumber;
72
+ height: z.ZodNumber;
73
+ }, z.core.$strip>>;
74
+ nextStep: z.ZodOptional<z.ZodString>;
75
+ skippable: z.ZodDefault<z.ZodBoolean>;
76
+ kind: z.ZodLiteral<"work">;
77
+ interaction: z.ZodOptional<z.ZodEnum<{
78
+ interactive: "interactive";
79
+ automatic: "automatic";
80
+ }>>;
81
+ agent: z.ZodString;
82
+ prompt: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>, z.ZodObject<{
84
+ id: z.ZodString;
85
+ title: z.ZodString;
86
+ description: z.ZodOptional<z.ZodString>;
87
+ position: z.ZodObject<{
88
+ x: z.ZodNumber;
89
+ y: z.ZodNumber;
90
+ }, z.core.$strip>;
91
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
92
+ size: z.ZodOptional<z.ZodObject<{
93
+ width: z.ZodNumber;
94
+ height: z.ZodNumber;
95
+ }, z.core.$strip>>;
96
+ nextStep: z.ZodOptional<z.ZodString>;
97
+ skippable: z.ZodDefault<z.ZodBoolean>;
98
+ kind: z.ZodLiteral<"review">;
99
+ interaction: z.ZodOptional<z.ZodEnum<{
100
+ interactive: "interactive";
101
+ automatic: "automatic";
102
+ }>>;
103
+ reviewers: z.ZodDefault<z.ZodArray<z.ZodObject<{
104
+ agent: z.ZodString;
105
+ prompt: z.ZodOptional<z.ZodString>;
106
+ onBehalfOf: z.ZodOptional<z.ZodString>;
107
+ conversationRole: z.ZodOptional<z.ZodEnum<{
108
+ personal: "personal";
109
+ workspace: "workspace";
110
+ }>>;
111
+ }, z.core.$strip>>>;
112
+ }, z.core.$strip>], "kind">;
113
+ export type WorkflowNode = z.infer<typeof workflowNodeSchema>;
114
+ /**
115
+ * Kinds that can only ever *begin* a chain: nothing may name one as its `nextStep`.
116
+ *
117
+ * A named list rather than a `=== "trigger"` written out wherever the question comes up, because it
118
+ * is asked in three places that must agree - `validateWorkflowChain` below, the editor's chain
119
+ * mutations, and the editor's add menus - and two of those are in another repository reaching this
120
+ * file through the SDK. It is a list rather than a single value because several triggers in one
121
+ * workflow are coming, each starting its own chain, and because a second head-only kind would then
122
+ * be one entry here rather than a fourth copy of the same comparison.
123
+ */
124
+ export declare const CHAIN_HEAD_KINDS: readonly WorkflowNode["kind"][];
125
+ /** Whether a node of this kind can only start a chain. `undefined` - an unknown node - is not one. */
126
+ export declare function isChainHeadKind(kind: string | undefined): boolean;
127
+ export declare const workflowDocumentSchema: z.ZodObject<{
128
+ schemaVersion: z.ZodOptional<z.ZodLiteral<"1">>;
129
+ meta: z.ZodObject<{
130
+ name: z.ZodString;
131
+ description: z.ZodOptional<z.ZodString>;
132
+ }, z.core.$strip>;
133
+ nodes: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
134
+ id: z.ZodString;
135
+ title: z.ZodString;
136
+ description: z.ZodOptional<z.ZodString>;
137
+ position: z.ZodObject<{
138
+ x: z.ZodNumber;
139
+ y: z.ZodNumber;
140
+ }, z.core.$strip>;
141
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
142
+ size: z.ZodOptional<z.ZodObject<{
143
+ width: z.ZodNumber;
144
+ height: z.ZodNumber;
145
+ }, z.core.$strip>>;
146
+ nextStep: z.ZodOptional<z.ZodString>;
147
+ skippable: z.ZodDefault<z.ZodBoolean>;
148
+ kind: z.ZodLiteral<"trigger">;
149
+ source: z.ZodEnum<{
150
+ "workspace-prompt": "workspace-prompt";
151
+ "chat-prompt": "chat-prompt";
152
+ "chat-agent-tool": "chat-agent-tool";
153
+ }>;
154
+ }, z.core.$strip>, z.ZodObject<{
155
+ id: z.ZodString;
156
+ title: z.ZodString;
157
+ description: z.ZodOptional<z.ZodString>;
158
+ position: z.ZodObject<{
159
+ x: z.ZodNumber;
160
+ y: z.ZodNumber;
161
+ }, z.core.$strip>;
162
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
163
+ size: z.ZodOptional<z.ZodObject<{
164
+ width: z.ZodNumber;
165
+ height: z.ZodNumber;
166
+ }, z.core.$strip>>;
167
+ nextStep: z.ZodOptional<z.ZodString>;
168
+ skippable: z.ZodDefault<z.ZodBoolean>;
169
+ kind: z.ZodLiteral<"work">;
170
+ interaction: z.ZodOptional<z.ZodEnum<{
171
+ interactive: "interactive";
172
+ automatic: "automatic";
173
+ }>>;
174
+ agent: z.ZodString;
175
+ prompt: z.ZodOptional<z.ZodString>;
176
+ }, z.core.$strip>, z.ZodObject<{
177
+ id: z.ZodString;
178
+ title: z.ZodString;
179
+ description: z.ZodOptional<z.ZodString>;
180
+ position: z.ZodObject<{
181
+ x: z.ZodNumber;
182
+ y: z.ZodNumber;
183
+ }, z.core.$strip>;
184
+ manualPosition: z.ZodOptional<z.ZodBoolean>;
185
+ size: z.ZodOptional<z.ZodObject<{
186
+ width: z.ZodNumber;
187
+ height: z.ZodNumber;
188
+ }, z.core.$strip>>;
189
+ nextStep: z.ZodOptional<z.ZodString>;
190
+ skippable: z.ZodDefault<z.ZodBoolean>;
191
+ kind: z.ZodLiteral<"review">;
192
+ interaction: z.ZodOptional<z.ZodEnum<{
193
+ interactive: "interactive";
194
+ automatic: "automatic";
195
+ }>>;
196
+ reviewers: z.ZodDefault<z.ZodArray<z.ZodObject<{
197
+ agent: z.ZodString;
198
+ prompt: z.ZodOptional<z.ZodString>;
199
+ onBehalfOf: z.ZodOptional<z.ZodString>;
200
+ conversationRole: z.ZodOptional<z.ZodEnum<{
201
+ personal: "personal";
202
+ workspace: "workspace";
203
+ }>>;
204
+ }, z.core.$strip>>>;
205
+ }, z.core.$strip>], "kind">>>;
206
+ }, z.core.$strip>;
207
+ export type WorkflowDocument = z.infer<typeof workflowDocumentSchema>;
208
+ export type WorkflowDocumentInput = z.input<typeof workflowDocumentSchema>;
209
+ /** Inspects the whole document. Execution must first restrict this to its selected reachable chain. */
210
+ export declare function isInteractiveWorkflowDocument(document: WorkflowDocument): boolean;
211
+ export interface WorkflowDocumentError {
212
+ path: string;
213
+ message: string;
214
+ }
215
+ export type WorkflowDocumentValidation = {
216
+ valid: true;
217
+ document: WorkflowDocument;
218
+ } | {
219
+ valid: false;
220
+ errors: WorkflowDocumentError[];
221
+ };
222
+ export declare function validateWorkflowDocument(value: unknown): WorkflowDocumentValidation;
223
+ export interface WorkflowChainWarning {
224
+ nodeId: string;
225
+ message: string;
226
+ }
227
+ /**
228
+ * Chain integrity, reported separately from schema validity and deliberately as warnings.
229
+ *
230
+ * A half-built workflow is a normal state to be in while authoring — a node whose `nextStep` is not
231
+ * written yet must not make the file invalid. Step 2's sync is where these become failures.
232
+ */
233
+ export declare function validateWorkflowChain(nodes: readonly WorkflowNode[]): WorkflowChainWarning[];
234
+ export declare function createDefaultWorkflowDocument(name: string): WorkflowDocumentInput;
235
+ /**
236
+ * Filename for a workflow, derived from its display name.
237
+ *
238
+ * Throws rather than returning a bare extension for a name with no ASCII alphanumerics, matching
239
+ * `CanvasManager.createCanvasFileName`. Step 1a's agent equivalent shipped without this guard and a
240
+ * non-Latin name silently wrote a dotfile.
241
+ */
242
+ export declare function toSafeWorkflowFileName(name: string): string;
243
+ //# sourceMappingURL=workflow-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-document.d.ts","sourceRoot":"","sources":["../src/workflow-document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,oGAAoG;AACpG,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD,mGAAmG;AACnG,eAAO,MAAM,aAAa,cAAc,CAAC;AACzC,eAAO,MAAM,uBAAuB,eAAe,CAAC;AAEpD,sGAAsG;AACtG,eAAO,MAAM,eAAe,iEAAkE,CAAC;AAC/F,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAuB7D,0EAA0E;AAC1E,eAAO,MAAM,yBAAyB,aAA4B,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;iBA2BnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAmB1E,iFAAiF;AACjF,eAAO,MAAM,sBAAsB;;;;;;;;iBAcjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAyB7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,CAAC,MAAM,CAAC,EAAgB,CAAC;AAE7E,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEjE;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAYjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE3E,uGAAuG;AACvG,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAEjF;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,0BAA0B,GACpC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAC;AAElG,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAYnF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,oBAAoB,EAAE,CAqF5F;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CAkBjF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW3D"}
@@ -0,0 +1,282 @@
1
+ import { z } from "zod";
2
+ /** The only schema version there has ever been. Interactive fields are ordinary optional fields. */
3
+ export const WORKFLOW_DOCUMENT_SCHEMA_VERSION = "1";
4
+ /** Directory the editor creates workflow files in. Discovery is by extension, not by directory. */
5
+ export const WORKFLOWS_DIR = "workflows";
6
+ export const WORKFLOW_FILE_EXTENSION = ".flow.json";
7
+ /** How a run can start. A closed set: nothing else starts a run, and there is no schedule trigger. */
8
+ export const TRIGGER_SOURCES = ["workspace-prompt", "chat-prompt", "chat-agent-tool"];
9
+ /**
10
+ * Whether a path stays inside the project root it is resolved against: not an absolute POSIX, drive
11
+ * or UNC path, not a URL, no `..` segment, no NUL byte. Both `/` and `\` count as separators, so the
12
+ * guarantee holds for a consumer on Windows too. A backslash is otherwise allowed, because git
13
+ * C-quotes a non-ASCII name (`"\303\251.txt"`) and observed paths carry that verbatim. `.` and empty
14
+ * segments cannot escape, so a `./` prefix or a doubled slash is accepted rather than rejected.
15
+ */
16
+ function staysInProjectRoot(path) {
17
+ return (!/^[/\\]/.test(path) &&
18
+ !/^[a-z]:/i.test(path) &&
19
+ !/^[a-z][a-z\d+.-]*:\/\//i.test(path) &&
20
+ !path.split(/[/\\]/).includes("..") &&
21
+ !path.includes("\0"));
22
+ }
23
+ const relativePathSchema = z.string().refine(staysInProjectRoot, {
24
+ message: "Must be a project-relative path: not absolute, not a URL, and without '..' segments",
25
+ });
26
+ /** A non-empty path relative to the project root that cannot leave it. */
27
+ export const projectRelativePathSchema = relativePathSchema.min(1);
28
+ /**
29
+ * What every node produces. The same shape for every node in every workflow — it is not authored and
30
+ * is not part of the document. A step that needs to hand on anything richer than prose writes a file
31
+ * and names it here.
32
+ */
33
+ export const workflowNodeOutputSchema = z.object({
34
+ text: z.string(),
35
+ /** Project-relative paths. Never absolute, never a URL, never escaping the root. */
36
+ files: z.array(projectRelativePathSchema).default([]),
37
+ /**
38
+ * What the executor observed this step change, one entry per repository whose head moved.
39
+ *
40
+ * Written by the executor after the agent's own output, never by the agent: `text` and `files`
41
+ * are what a step says it did, and this is what it was seen to do. Optional because an output
42
+ * stored before this existed must still parse, and because a step that moved no head records
43
+ * nothing at all. Absent therefore means "nothing was observed", which covers both a step that
44
+ * changed nothing and a step nobody was watching - the two are deliberately not distinguished
45
+ * here. What is kept distinct is absent versus an empty array, which no producer ever writes.
46
+ */
47
+ changes: z
48
+ .array(z.object({
49
+ /** Directory under the project root; '' when the project root is itself the repo. */
50
+ dirName: relativePathSchema,
51
+ from: z.string(),
52
+ to: z.string(),
53
+ commits: z.number().int().nonnegative(),
54
+ /** Project-relative, as `getChangedFilesBetween` reports them. */
55
+ files: z.array(projectRelativePathSchema),
56
+ }))
57
+ .optional(),
58
+ });
59
+ const nodePositionSchema = z.object({ x: z.number(), y: z.number() });
60
+ const nodeSizeSchema = z.object({ width: z.number(), height: z.number() });
61
+ const baseNodeSchema = z.object({
62
+ id: z.string().min(1),
63
+ title: z.string(),
64
+ description: z.string().optional(),
65
+ position: nodePositionSchema,
66
+ /** Set once a user drags a node, so auto-layout stops moving it. */
67
+ manualPosition: z.boolean().optional(),
68
+ size: nodeSizeSchema.optional(),
69
+ /** The one node that follows this one. Absent means the run ends here. */
70
+ nextStep: z.string().optional(),
71
+ skippable: z.boolean().default(false),
72
+ });
73
+ /** One reviewer on a review node: an agent, optionally speaking for a person. */
74
+ export const workflowReviewerSchema = z.object({
75
+ /**
76
+ * An agent document's `meta.name`. Deliberately not `.min(1)`, for the same reason as the `work`
77
+ * node's `agent` field below: a reviewer can be added before its agent is picked, and rejecting
78
+ * `""` here would make the whole document non-conforming over the step the user just touched.
79
+ * `validateWorkflowChain` warns about an empty reviewer agent; sync time is where it becomes an
80
+ * error.
81
+ */
82
+ agent: z.string(),
83
+ prompt: z.string().optional(),
84
+ /** Email of the person this reviewer represents, matching how rule owners are named. */
85
+ onBehalfOf: z.string().optional(),
86
+ /** Omission means personal. Only an explicit designation makes a conversation workspace-visible. */
87
+ conversationRole: z.enum(["personal", "workspace"]).optional(),
88
+ });
89
+ export const workflowNodeSchema = z.discriminatedUnion("kind", [
90
+ baseNodeSchema.extend({
91
+ kind: z.literal("trigger"),
92
+ source: z.enum(TRIGGER_SOURCES),
93
+ }),
94
+ baseNodeSchema.extend({
95
+ kind: z.literal("work"),
96
+ interaction: z.enum(["automatic", "interactive"]).optional(),
97
+ /**
98
+ * An agent document's `meta.name`. Resolved at sync time, warned about while authoring -
99
+ * deliberately not `.min(1)`. A work step exists before an agent is chosen for it, and a
100
+ * `.min(1)` here would make the whole document non-conforming the instant such a step is
101
+ * created, collapsing the panel around the step the user just added. `""` is a safe sentinel
102
+ * for "not picked yet" because every other agent reference in this file is `.min(1)`, so no
103
+ * real agent can be named the empty string. `validateWorkflowChain` warns about it instead.
104
+ */
105
+ agent: z.string(),
106
+ /** Extra instruction for this step, appended to the agent's own system prompt. */
107
+ prompt: z.string().optional(),
108
+ }),
109
+ baseNodeSchema.extend({
110
+ kind: z.literal("review"),
111
+ interaction: z.enum(["automatic", "interactive"]).optional(),
112
+ reviewers: z.array(workflowReviewerSchema).default([]),
113
+ }),
114
+ ]);
115
+ /**
116
+ * Kinds that can only ever *begin* a chain: nothing may name one as its `nextStep`.
117
+ *
118
+ * A named list rather than a `=== "trigger"` written out wherever the question comes up, because it
119
+ * is asked in three places that must agree - `validateWorkflowChain` below, the editor's chain
120
+ * mutations, and the editor's add menus - and two of those are in another repository reaching this
121
+ * file through the SDK. It is a list rather than a single value because several triggers in one
122
+ * workflow are coming, each starting its own chain, and because a second head-only kind would then
123
+ * be one entry here rather than a fourth copy of the same comparison.
124
+ */
125
+ export const CHAIN_HEAD_KINDS = ["trigger"];
126
+ /** Whether a node of this kind can only start a chain. `undefined` - an unknown node - is not one. */
127
+ export function isChainHeadKind(kind) {
128
+ return kind !== undefined && CHAIN_HEAD_KINDS.includes(kind);
129
+ }
130
+ export const workflowDocumentSchema = z.object({
131
+ schemaVersion: z.literal(WORKFLOW_DOCUMENT_SCHEMA_VERSION).optional(),
132
+ meta: z.object({
133
+ /**
134
+ * Deliberately not `.min(1)`. A user clearing the field to retype it would otherwise invalidate
135
+ * the document mid-keystroke and collapse the form around them — the exact defect step 1a shipped
136
+ * and had to fix. An empty name is recoverable; a missing one is still an error.
137
+ */
138
+ name: z.string(),
139
+ description: z.string().optional(),
140
+ }),
141
+ nodes: z.array(workflowNodeSchema).default([]),
142
+ });
143
+ /** Inspects the whole document. Execution must first restrict this to its selected reachable chain. */
144
+ export function isInteractiveWorkflowDocument(document) {
145
+ return document.nodes.some((node) => node.kind !== "trigger" && node.interaction === "interactive");
146
+ }
147
+ export function validateWorkflowDocument(value) {
148
+ const result = workflowDocumentSchema.safeParse(value);
149
+ if (result.success) {
150
+ return { valid: true, document: result.data };
151
+ }
152
+ return {
153
+ valid: false,
154
+ errors: result.error.issues.map((issue) => ({
155
+ path: issue.path.length > 0 ? issue.path.join(".") : "document",
156
+ message: issue.message,
157
+ })),
158
+ };
159
+ }
160
+ /**
161
+ * Chain integrity, reported separately from schema validity and deliberately as warnings.
162
+ *
163
+ * A half-built workflow is a normal state to be in while authoring — a node whose `nextStep` is not
164
+ * written yet must not make the file invalid. Step 2's sync is where these become failures.
165
+ */
166
+ export function validateWorkflowChain(nodes) {
167
+ const warnings = [];
168
+ // Not a chain-shape problem, but the same "authoring problem, not a schema violation" category:
169
+ // `agent` accepts "" so that adding a step or a reviewer never invalidates the document, and this
170
+ // is where that loosened value gets flagged instead.
171
+ for (const node of nodes) {
172
+ if (node.kind === "work" && node.agent === "") {
173
+ warnings.push({ nodeId: node.id, message: "This step has no agent assigned yet." });
174
+ }
175
+ if (node.kind === "review") {
176
+ if (node.interaction === "interactive" &&
177
+ node.reviewers.filter((r) => r.conversationRole === "workspace").length !== 1) {
178
+ warnings.push({
179
+ nodeId: node.id,
180
+ message: "An interactive review must designate exactly one workspace reviewer.",
181
+ });
182
+ }
183
+ for (const reviewer of node.reviewers) {
184
+ if (reviewer.agent === "") {
185
+ warnings.push({ nodeId: node.id, message: "This step has a reviewer with no agent assigned yet." });
186
+ }
187
+ }
188
+ }
189
+ }
190
+ const byId = new Map(nodes.map((node) => [node.id, node]));
191
+ const incoming = new Map();
192
+ const seen = new Set();
193
+ for (const node of nodes) {
194
+ if (node.nextStep === undefined) {
195
+ continue;
196
+ }
197
+ if (node.nextStep === node.id) {
198
+ warnings.push({ nodeId: node.id, message: "This step points at itself." });
199
+ seen.add(node.id);
200
+ continue;
201
+ }
202
+ const target = byId.get(node.nextStep);
203
+ if (target === undefined) {
204
+ warnings.push({ nodeId: node.id, message: `Next step "${node.nextStep}" is not a step in this workflow.` });
205
+ continue;
206
+ }
207
+ // A trigger is a chain head and nothing may point at one. Reported against the step holding the
208
+ // link rather than against the trigger, because the link is the thing that is wrong and the step
209
+ // holding it is the only one that can be repaired - the trigger itself is fine as it is.
210
+ if (isChainHeadKind(target.kind)) {
211
+ warnings.push({
212
+ nodeId: node.id,
213
+ message: "This step points at a trigger, and a trigger can only start a chain.",
214
+ });
215
+ }
216
+ incoming.set(node.nextStep, (incoming.get(node.nextStep) ?? 0) + 1);
217
+ }
218
+ for (const [nodeId, count] of incoming) {
219
+ if (count > 1) {
220
+ warnings.push({ nodeId, message: "More than one step leads here, and the flow is a single chain." });
221
+ }
222
+ }
223
+ // A cycle is only reachable once every hop resolves, so this runs after the checks above.
224
+ for (const node of nodes) {
225
+ if (seen.has(node.id)) {
226
+ continue;
227
+ }
228
+ const path = new Set();
229
+ let current = node;
230
+ while (current && !seen.has(current.id)) {
231
+ if (path.has(current.id)) {
232
+ warnings.push({ nodeId: current.id, message: "These steps form a cycle, so the run would never end." });
233
+ break;
234
+ }
235
+ path.add(current.id);
236
+ current = current.nextStep === undefined ? undefined : byId.get(current.nextStep);
237
+ }
238
+ for (const id of path) {
239
+ seen.add(id);
240
+ }
241
+ }
242
+ return warnings;
243
+ }
244
+ export function createDefaultWorkflowDocument(name) {
245
+ return {
246
+ schemaVersion: WORKFLOW_DOCUMENT_SCHEMA_VERSION,
247
+ meta: { name },
248
+ nodes: [
249
+ {
250
+ // A uuid, like every other node id. `id` is what becomes `WorkflowNodeRun.nodeKey` when a
251
+ // run is projected, and the editor's own `createNode` uses `crypto.randomUUID()` - so the
252
+ // literal "trigger" here meant every workflow ever created shipped with exactly one node
253
+ // whose key was not a uuid, and two workflows whose first steps collided on it.
254
+ id: crypto.randomUUID(),
255
+ kind: "trigger",
256
+ title: "Start",
257
+ source: "workspace-prompt",
258
+ position: { x: 0, y: 0 },
259
+ },
260
+ ],
261
+ };
262
+ }
263
+ /**
264
+ * Filename for a workflow, derived from its display name.
265
+ *
266
+ * Throws rather than returning a bare extension for a name with no ASCII alphanumerics, matching
267
+ * `CanvasManager.createCanvasFileName`. Step 1a's agent equivalent shipped without this guard and a
268
+ * non-Latin name silently wrote a dotfile.
269
+ */
270
+ export function toSafeWorkflowFileName(name) {
271
+ const slug = name
272
+ .replace(/[^a-zA-Z0-9]/g, "-")
273
+ .replace(/-+/g, "-")
274
+ .replace(/^-+|-+$/g, "")
275
+ .slice(0, 60)
276
+ .toLowerCase();
277
+ if (!slug) {
278
+ throw new Error("Workflow name must contain at least one letter or number");
279
+ }
280
+ return `${slug}${WORKFLOW_FILE_EXTENSION}`;
281
+ }
282
+ //# sourceMappingURL=workflow-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-document.js","sourceRoot":"","sources":["../src/workflow-document.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dazl/api-client",
3
- "version": "1.0.43",
3
+ "version": "1.0.45",
4
4
  "description": "Type-safe SDK for Dazl APIs, generated from OpenAPI specifications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,6 +11,8 @@
11
11
  "./public/fetch-client": "./dist/public/client/index.js",
12
12
  "./db-types": "./dist/db/generated-types.js",
13
13
  "./feature-toggles-config": "./dist/feature-toggles-config.js",
14
+ "./agent-document": "./dist/agent-document.js",
15
+ "./workflow-document": "./dist/workflow-document.js",
14
16
  "./package.json": "./package.json"
15
17
  },
16
18
  "scripts": {
@@ -30,7 +32,8 @@
30
32
  "openapi"
31
33
  ],
32
34
  "peerDependencies": {
33
- "kysely": ">=0.27.0"
35
+ "kysely": ">=0.27.0",
36
+ "zod": "^4.4.3"
34
37
  },
35
38
  "peerDependenciesMeta": {
36
39
  "kysely": {
@@ -0,0 +1,98 @@
1
+ import { z } from "zod";
2
+
3
+ /** Bumped only on a breaking change to the document shape. */
4
+ export const AGENT_DOCUMENT_SCHEMA_VERSION = "1";
5
+
6
+ /** Directory the editor creates agent files in. Discovery is by extension, not by directory. */
7
+ export const AGENTS_DIR = "agents";
8
+ export const AGENT_FILE_EXTENSION = ".agent.json";
9
+
10
+ /** The closed set of harnesses, matching dazl's harness-definitions.ts. */
11
+ export const AGENT_HARNESSES = ["dazl", "claude", "codex", "grok", "opencode"] as const;
12
+ export type AgentHarness = (typeof AGENT_HARNESSES)[number];
13
+
14
+ /**
15
+ * One standing rule. `owners` are email addresses rather than dazl user ids, so the file stays
16
+ * readable in review and portable between workspaces; resolution to a user happens at sync time.
17
+ */
18
+ export const agentRuleSchema = z.object({
19
+ text: z.string().min(1),
20
+ owners: z.array(z.string()).default([]),
21
+ blocking: z.boolean().default(false),
22
+ });
23
+ export type AgentRule = z.infer<typeof agentRuleSchema>;
24
+
25
+ export const agentDocumentSchema = z.object({
26
+ schemaVersion: z.literal(AGENT_DOCUMENT_SCHEMA_VERSION).optional(),
27
+ meta: z.object({
28
+ name: z.string().min(1),
29
+ description: z.string().optional(),
30
+ }),
31
+ systemPrompt: z.string(),
32
+ harness: z.enum(AGENT_HARNESSES),
33
+ model: z.string().optional(),
34
+ allowedMcpServers: z.array(z.string()).default([]),
35
+ rules: z.array(agentRuleSchema).default([]),
36
+ });
37
+
38
+ export type AgentDocument = z.infer<typeof agentDocumentSchema>;
39
+ export type AgentDocumentInput = z.input<typeof agentDocumentSchema>;
40
+
41
+ export interface AgentDocumentError {
42
+ /** Dotted path to the offending field, or "document" when the failure is at the root. */
43
+ path: string;
44
+ message: string;
45
+ }
46
+
47
+ export type AgentDocumentValidation =
48
+ { valid: true; document: AgentDocument } | { valid: false; errors: AgentDocumentError[] };
49
+
50
+ export function validateAgentDocument(value: unknown): AgentDocumentValidation {
51
+ const result = agentDocumentSchema.safeParse(value);
52
+ if (result.success) {
53
+ return { valid: true, document: result.data };
54
+ }
55
+ return {
56
+ valid: false,
57
+ errors: result.error.issues.map((issue) => ({
58
+ path: issue.path.length > 0 ? issue.path.join(".") : "document",
59
+ message: issue.message,
60
+ })),
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Every optional-with-a-default key is written out explicitly. The schema would fill them in on
66
+ * parse, but the file is also read by hand and by tools that do not run zod, so a freshly created
67
+ * agent states its own shape instead of relying on defaults being applied downstream.
68
+ */
69
+ export function createDefaultAgentDocument(name: string): AgentDocumentInput {
70
+ return {
71
+ schemaVersion: AGENT_DOCUMENT_SCHEMA_VERSION,
72
+ meta: { name },
73
+ systemPrompt: "",
74
+ harness: "dazl",
75
+ allowedMcpServers: [],
76
+ rules: [],
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Filename for an agent, derived from its display name. Mirrors `toSafeWorkflowFileName` so the
82
+ * two definition types name their files the same way.
83
+ *
84
+ * Throws for a name with no ASCII alphanumerics rather than returning a bare `.agent.json` dotfile
85
+ * that every such name would collide on.
86
+ */
87
+ export function toSafeAgentFileName(name: string): string {
88
+ const slug = name
89
+ .replace(/[^a-zA-Z0-9]/g, "-")
90
+ .replace(/-+/g, "-")
91
+ .replace(/^-+|-+$/g, "")
92
+ .slice(0, 60)
93
+ .toLowerCase();
94
+ if (!slug) {
95
+ throw new Error("Agent name must contain at least one letter or number");
96
+ }
97
+ return `${slug}${AGENT_FILE_EXTENSION}`;
98
+ }