@arbidocs/blocks 0.4.72 → 0.4.73

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 (89) hide show
  1. package/dist/agents/index.cjs +400 -261
  2. package/dist/agents/index.js +6 -3
  3. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  4. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +58 -0
  5. package/dist/agents/tasks/index.d.ts +1 -0
  6. package/dist/agents/workflows/WorkflowRunner.d.ts +70 -0
  7. package/dist/agents/workflows/index.d.ts +7 -1
  8. package/dist/agents/workflows/planSteps.d.ts +28 -0
  9. package/dist/agents/workflows/run.d.ts +97 -0
  10. package/dist/agents/workflows/skillMarkdown.d.ts +15 -0
  11. package/dist/agents/workflows/types.d.ts +109 -0
  12. package/dist/agents/workflows/useWorkflowPreview.d.ts +14 -0
  13. package/dist/agents/workflows/useWorkflowView.d.ts +54 -0
  14. package/dist/agents/workflows/workflow.d.ts +3 -1
  15. package/dist/chunk-2P3T23C7.js +1250 -0
  16. package/dist/chunk-2P3T23C7.js.map +1 -0
  17. package/dist/chunk-7D737FLE.cjs +43 -0
  18. package/dist/chunk-7D737FLE.cjs.map +1 -0
  19. package/dist/{chunk-LFGJAZ5H.js → chunk-DDF5GPIJ.js} +6 -36
  20. package/dist/chunk-DDF5GPIJ.js.map +1 -0
  21. package/dist/chunk-DETZZBG2.cjs +91 -0
  22. package/dist/chunk-DETZZBG2.cjs.map +1 -0
  23. package/dist/chunk-EVUEIBNU.js +89 -0
  24. package/dist/chunk-EVUEIBNU.js.map +1 -0
  25. package/dist/chunk-GTNUQBXI.cjs +1296 -0
  26. package/dist/chunk-GTNUQBXI.cjs.map +1 -0
  27. package/dist/{chunk-DH7C2UJO.cjs → chunk-IUR565UW.cjs} +297 -524
  28. package/dist/chunk-IUR565UW.cjs.map +1 -0
  29. package/dist/{chunk-THO7DZNN.cjs → chunk-MUMH3Z6K.cjs} +20 -15
  30. package/dist/chunk-MUMH3Z6K.cjs.map +1 -0
  31. package/dist/{chunk-KOXUBCLL.js → chunk-ORA2XE7U.js} +3 -3
  32. package/dist/{chunk-KOXUBCLL.js.map → chunk-ORA2XE7U.js.map} +1 -1
  33. package/dist/{chunk-5HOAOKZL.js → chunk-OYMWV45N.js} +21 -16
  34. package/dist/chunk-OYMWV45N.js.map +1 -0
  35. package/dist/{chunk-IMC2Z32C.js → chunk-QDNXEB3T.js} +268 -484
  36. package/dist/chunk-QDNXEB3T.js.map +1 -0
  37. package/dist/{chunk-G5QTGKDJ.cjs → chunk-WOYUXVVQ.cjs} +6 -6
  38. package/dist/{chunk-G5QTGKDJ.cjs.map → chunk-WOYUXVVQ.cjs.map} +1 -1
  39. package/dist/chunk-XD2M6LIG.js +41 -0
  40. package/dist/chunk-XD2M6LIG.js.map +1 -0
  41. package/dist/{chunk-WBDK4PIA.cjs → chunk-Z5VUZ6YD.cjs} +6 -37
  42. package/dist/chunk-Z5VUZ6YD.cjs.map +1 -0
  43. package/dist/connect/docx.cjs +2 -2
  44. package/dist/connect/docx.js +1 -1
  45. package/dist/connect/index.cjs +316 -23
  46. package/dist/connect/index.cjs.map +1 -1
  47. package/dist/connect/index.d.ts +1 -0
  48. package/dist/connect/index.js +300 -8
  49. package/dist/connect/index.js.map +1 -1
  50. package/dist/connection/ConnectedWorkflowBuilder.d.ts +44 -0
  51. package/dist/connection/ConnectedWorkflowRunner.d.ts +27 -0
  52. package/dist/connection/useWorkflowThread.d.ts +34 -0
  53. package/dist/facts/index.cjs +1 -1
  54. package/dist/facts/index.js +1 -1
  55. package/dist/files/index.cjs +9 -83
  56. package/dist/files/index.cjs.map +1 -1
  57. package/dist/files/index.js +6 -83
  58. package/dist/files/index.js.map +1 -1
  59. package/dist/home/index.cjs +22 -21
  60. package/dist/home/index.cjs.map +1 -1
  61. package/dist/home/index.js +4 -3
  62. package/dist/home/index.js.map +1 -1
  63. package/dist/index.cjs +450 -311
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.js +7 -4
  66. package/dist/index.js.map +1 -1
  67. package/dist/shell/index.cjs +1 -1
  68. package/dist/shell/index.js +1 -1
  69. package/dist/studio/index.cjs +5 -5
  70. package/dist/studio/index.js +3 -3
  71. package/dist/workflow-canvas/StepInspector.d.ts +46 -0
  72. package/dist/workflow-canvas/TriggerInspector.d.ts +46 -0
  73. package/dist/workflow-canvas/WorkflowBuilder.d.ts +55 -0
  74. package/dist/workflow-canvas/WorkflowCanvas.d.ts +65 -0
  75. package/dist/workflow-canvas/edit.d.ts +54 -0
  76. package/dist/workflow-canvas/index.cjs +1609 -0
  77. package/dist/workflow-canvas/index.cjs.map +1 -0
  78. package/dist/workflow-canvas/index.d.ts +13 -0
  79. package/dist/workflow-canvas/index.js +1579 -0
  80. package/dist/workflow-canvas/index.js.map +1 -0
  81. package/dist/workflow-canvas/trigger.d.ts +51 -0
  82. package/package.json +25 -14
  83. package/src/workflow-canvas/canvas.css +113 -0
  84. package/dist/chunk-5HOAOKZL.js.map +0 -1
  85. package/dist/chunk-DH7C2UJO.cjs.map +0 -1
  86. package/dist/chunk-IMC2Z32C.js.map +0 -1
  87. package/dist/chunk-LFGJAZ5H.js.map +0 -1
  88. package/dist/chunk-THO7DZNN.cjs.map +0 -1
  89. package/dist/chunk-WBDK4PIA.cjs.map +0 -1
@@ -0,0 +1,1296 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkDETZZBG2_cjs = require('./chunk-DETZZBG2.cjs');
5
+ var chunk7D737FLE_cjs = require('./chunk-7D737FLE.cjs');
6
+ var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
7
+ var react = require('react');
8
+ var ui = require('@arbidocs/react/ui');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+ var lucideReact = require('lucide-react');
11
+
12
+ // src/agents/workflows/types.ts
13
+ var EMPTY_WORKFLOW_SCOPE = { folders: [], labels: [] };
14
+
15
+ // src/agents/workflows/workflow.ts
16
+ var isWorkflowScope = (value) => typeof value === "object" && value !== null && Array.isArray(value.folders) && Array.isArray(value.labels);
17
+ var isEmptyWorkflowScope = (scope) => scope.folders.length === 0 && scope.labels.length === 0 && !scope.documents?.length;
18
+ var isFileField = (field) => field.type === "scope" || field.type === "documents";
19
+ function emptyValue(field) {
20
+ switch (field.type) {
21
+ case "boolean":
22
+ return false;
23
+ case "scope":
24
+ return { folders: [], labels: [] };
25
+ case "documents":
26
+ return { folders: [], labels: [], documents: [] };
27
+ default:
28
+ return "";
29
+ }
30
+ }
31
+ function defaultInputs(workflow) {
32
+ const inputs = {};
33
+ for (const field of workflow.inputs) {
34
+ const d = field.default;
35
+ inputs[field.name] = d === void 0 ? emptyValue(field) : isWorkflowScope(d) ? { ...d } : d;
36
+ }
37
+ return inputs;
38
+ }
39
+ function validateInputs(workflow, inputs) {
40
+ const errors = {};
41
+ for (const field of workflow.inputs) {
42
+ const value = inputs[field.name];
43
+ if (field.type === "number") {
44
+ const blank = value === "" || value === void 0;
45
+ if (blank) {
46
+ if (field.required) errors[field.name] = "required";
47
+ continue;
48
+ }
49
+ const n = Number(value);
50
+ if (Number.isNaN(n)) errors[field.name] = "number";
51
+ else if (field.min !== void 0 && n < field.min) errors[field.name] = "min";
52
+ else if (field.max !== void 0 && n > field.max) errors[field.name] = "max";
53
+ continue;
54
+ }
55
+ if (!field.required) continue;
56
+ if (field.type === "documents") {
57
+ if (!isWorkflowScope(value) || !value.documents?.length) errors[field.name] = "required";
58
+ continue;
59
+ }
60
+ if (field.type === "boolean" || field.type === "scope") continue;
61
+ if (typeof value !== "string" || value.trim() === "") errors[field.name] = "required";
62
+ }
63
+ return errors;
64
+ }
65
+ function promptFieldName(workflow) {
66
+ return workflow.inputs.find((f) => !f.advanced && (f.type === "text" || f.type === "longtext"))?.name;
67
+ }
68
+ var quoteList = (names) => {
69
+ const quoted = names.map((n) => `"${n}"`);
70
+ return quoted.length <= 1 ? quoted[0] ?? "" : `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}`;
71
+ };
72
+ function fragment(field, value, ctx) {
73
+ switch (field.type) {
74
+ case "documents": {
75
+ const ids = isWorkflowScope(value) ? value.documents ?? [] : [];
76
+ const names = ids.flatMap((id) => {
77
+ const title = ctx?.documentTitles?.[id];
78
+ return title ? [title] : [];
79
+ });
80
+ return quoteList(names);
81
+ }
82
+ case "boolean":
83
+ return value ? field.trueText ?? "yes" : field.falseText ?? "no";
84
+ case "select": {
85
+ const option = field.options?.find((o) => o.value === value);
86
+ return option ? option.text ?? option.label : String(value ?? "");
87
+ }
88
+ case "scope":
89
+ return "";
90
+ default:
91
+ return typeof value === "string" ? value.trim() : String(value ?? "");
92
+ }
93
+ }
94
+ function composeWorkflowPrompt(workflow, inputs, ctx) {
95
+ if (workflow.run.kind !== "prompt") return "";
96
+ const byName = new Map(workflow.inputs.map((f) => [f.name, f]));
97
+ const template = workflow.run.promptTemplate;
98
+ let out = "";
99
+ let last = 0;
100
+ const append = (text, isValue) => {
101
+ let t = text;
102
+ if (!isValue) {
103
+ t = t.replace(/[ \t]{2,}/g, " ");
104
+ if (/[ \t]$/.test(out)) t = t.replace(/^[ \t]+/, "");
105
+ }
106
+ out += t;
107
+ };
108
+ for (const m of template.matchAll(/\{\{\s*([a-z][a-z0-9_]*)\s*\}\}/gi)) {
109
+ append(template.slice(last, m.index), false);
110
+ const field = byName.get(m[1]);
111
+ append(field ? fragment(field, inputs[m[1]], ctx) : "", true);
112
+ last = m.index + m[0].length;
113
+ }
114
+ append(template.slice(last), false);
115
+ return out.trim();
116
+ }
117
+ function buildLaunch(workflow, inputs, agentId) {
118
+ const scopeField = workflow.inputs.find(isFileField);
119
+ const raw = scopeField ? inputs[scopeField.name] : void 0;
120
+ const scope = isWorkflowScope(raw) ? raw : { ...EMPTY_WORKFLOW_SCOPE };
121
+ return { workflow, inputs, scope, agentId: agentId || workflow.defaultAgentId || void 0 };
122
+ }
123
+ function workflowAccepts(workflow) {
124
+ const kinds = /* @__PURE__ */ new Set();
125
+ for (const field of workflow.inputs) if (field.context) kinds.add(field.context);
126
+ return [...kinds];
127
+ }
128
+ function workflowsAccepting(workflows, supplied) {
129
+ return workflows.filter((w) => workflowAccepts(w).some((k) => supplied.includes(k)));
130
+ }
131
+ function workflowsForHost(workflows, host) {
132
+ return workflows.filter((w) => !w.host || w.host === host);
133
+ }
134
+ function inputsFromContext(workflow, context) {
135
+ const inputs = {};
136
+ for (const field of workflow.inputs) {
137
+ if (!field.context) continue;
138
+ if (field.context === "selection") {
139
+ if (context.selection) inputs[field.name] = context.selection;
140
+ continue;
141
+ }
142
+ const ids = field.context === "image" ? context.image ? [context.image] : [] : context.documents;
143
+ if (ids?.length && isFileField(field)) {
144
+ inputs[field.name] = { folders: [], labels: [], documents: ids.slice(0, field.max ?? 1) };
145
+ }
146
+ }
147
+ return inputs;
148
+ }
149
+ var SKILL_PROMPT_LABEL = "What should it work on?";
150
+ var SKILL_PROMPT_FALLBACK_PLACEHOLDER = "Describe what you want";
151
+ var plainHint = (hint) => hint.replace(/^[<[]\s*|\s*[>\]]$/g, "").trim();
152
+ function skillToWorkflow(skill) {
153
+ const hint = plainHint((skill.arg_hint ?? "").trim());
154
+ const inputs = [
155
+ {
156
+ name: "args",
157
+ type: "longtext",
158
+ label: SKILL_PROMPT_LABEL,
159
+ placeholder: hint || SKILL_PROMPT_FALLBACK_PLACEHOLDER,
160
+ required: true
161
+ }
162
+ ];
163
+ return {
164
+ id: skill.slug,
165
+ skill: skill.slug,
166
+ title: skill.name || skill.slug,
167
+ description: skill.description ?? "",
168
+ inputs,
169
+ run: { kind: "prompt", promptTemplate: `/${skill.slug} {{args}}` },
170
+ landing: "chat",
171
+ schedulable: true
172
+ };
173
+ }
174
+ var FIELD_TYPES = [
175
+ "text",
176
+ "longtext",
177
+ "boolean",
178
+ "select",
179
+ "number",
180
+ "date",
181
+ "scope",
182
+ "documents"
183
+ ];
184
+ var str = (v) => typeof v === "string" ? v : void 0;
185
+ var num = (v) => typeof v === "number" ? v : void 0;
186
+ var bool = (v) => typeof v === "boolean" ? v : void 0;
187
+ function fieldFromFrontmatter(raw) {
188
+ if (typeof raw !== "object" || raw === null) return null;
189
+ const r = raw;
190
+ const name = str(r.name);
191
+ const type = FIELD_TYPES.find((t) => t === r.type);
192
+ if (!name || !/^[a-z][a-z0-9_]*$/.test(name) || !type) return null;
193
+ const options = Array.isArray(r.options) ? r.options.flatMap((o) => {
194
+ const ro = o;
195
+ const value = str(ro?.value);
196
+ const label = str(ro?.label);
197
+ return value && label ? [
198
+ {
199
+ value,
200
+ label,
201
+ description: str(ro.description),
202
+ text: str(ro.text),
203
+ icon: str(ro.icon)
204
+ }
205
+ ] : [];
206
+ }) : void 0;
207
+ return {
208
+ name,
209
+ type,
210
+ label: str(r.label) ?? name,
211
+ description: str(r.description),
212
+ placeholder: str(r.placeholder),
213
+ required: bool(r.required),
214
+ default: r.default,
215
+ options,
216
+ min: num(r.min),
217
+ max: num(r.max),
218
+ trueText: str(r.true_text),
219
+ falseText: str(r.false_text),
220
+ advanced: bool(r.advanced),
221
+ accept: r.accept === "image" ? "image" : void 0,
222
+ context: r.context === "documents" || r.context === "selection" || r.context === "image" ? r.context : void 0,
223
+ by: Array.isArray(r.by) ? r.by.filter((b) => b === "folders" || b === "labels") : void 0
224
+ };
225
+ }
226
+ function workflowFromFrontmatter(id, frontmatter, body) {
227
+ const inputs = Array.isArray(frontmatter.inputs) ? frontmatter.inputs.flatMap((f) => {
228
+ const field = fieldFromFrontmatter(f);
229
+ return field ? [field] : [];
230
+ }) : [];
231
+ return {
232
+ id,
233
+ title: str(frontmatter.name) ?? id,
234
+ description: str(frontmatter.description) ?? "",
235
+ icon: str(frontmatter.icon),
236
+ inputs,
237
+ run: { kind: "prompt", promptTemplate: body.trim() },
238
+ landing: frontmatter.landing === "files" ? "files" : "chat",
239
+ requiresFiles: bool(frontmatter.requires_files),
240
+ schedulable: bool(frontmatter.schedulable) ?? true
241
+ };
242
+ }
243
+ function fieldToFrontmatter(field) {
244
+ return compact({
245
+ name: field.name,
246
+ type: field.type,
247
+ label: field.label,
248
+ description: field.description,
249
+ placeholder: field.placeholder,
250
+ required: field.required,
251
+ default: field.default,
252
+ options: field.options?.map(
253
+ (o) => compact({
254
+ value: o.value,
255
+ label: o.label,
256
+ description: o.description,
257
+ text: o.text,
258
+ icon: o.icon
259
+ })
260
+ ),
261
+ min: field.min,
262
+ max: field.max,
263
+ true_text: field.trueText,
264
+ false_text: field.falseText,
265
+ advanced: field.advanced,
266
+ by: field.by,
267
+ accept: field.accept,
268
+ context: field.context
269
+ });
270
+ }
271
+ var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
272
+ var DEFAULT_SCHEMA_FORM_LABELS = {
273
+ optional: "(optional)",
274
+ advanced: "More options",
275
+ errors: {
276
+ required: "This is needed to continue",
277
+ min: "Too small",
278
+ max: "Too large",
279
+ number: "Enter a number"
280
+ }
281
+ };
282
+ var TILE_MAX = 4;
283
+ function FieldControl({
284
+ field,
285
+ value,
286
+ error,
287
+ onChange,
288
+ l,
289
+ idFor,
290
+ renderScope,
291
+ renderDocuments,
292
+ renderIcon,
293
+ onEnterSubmit
294
+ }) {
295
+ const id = `${idFor()}-control`;
296
+ const testId = idFor();
297
+ switch (field.type) {
298
+ case "text":
299
+ return /* @__PURE__ */ jsxRuntime.jsx(
300
+ ui.Input,
301
+ {
302
+ id,
303
+ "data-testid": testId,
304
+ value: String(value ?? ""),
305
+ placeholder: field.placeholder,
306
+ "aria-required": field.required || void 0,
307
+ "aria-invalid": error ? true : void 0,
308
+ "aria-describedby": error ? idFor("error") : void 0,
309
+ onChange: (e) => onChange(e.target.value)
310
+ }
311
+ );
312
+ case "longtext":
313
+ return /* @__PURE__ */ jsxRuntime.jsx(
314
+ ui.Textarea,
315
+ {
316
+ id,
317
+ "data-testid": testId,
318
+ value: String(value ?? ""),
319
+ placeholder: field.placeholder,
320
+ "aria-required": field.required || void 0,
321
+ "aria-invalid": error ? true : void 0,
322
+ "aria-describedby": error ? idFor("error") : void 0,
323
+ className: "min-h-[96px]",
324
+ onChange: (e) => onChange(e.target.value),
325
+ onKeyDown: (e) => {
326
+ if (onEnterSubmit && e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
327
+ e.preventDefault();
328
+ onEnterSubmit();
329
+ }
330
+ }
331
+ }
332
+ );
333
+ case "number":
334
+ return /* @__PURE__ */ jsxRuntime.jsx(
335
+ ui.Input,
336
+ {
337
+ id,
338
+ "data-testid": testId,
339
+ type: "number",
340
+ inputMode: "decimal",
341
+ min: field.min,
342
+ max: field.max,
343
+ value: value === void 0 ? "" : String(value),
344
+ placeholder: field.placeholder,
345
+ "aria-invalid": error ? true : void 0,
346
+ "aria-describedby": error ? idFor("error") : void 0,
347
+ onChange: (e) => onChange(e.target.value === "" ? "" : Number(e.target.value))
348
+ }
349
+ );
350
+ case "date":
351
+ return /* @__PURE__ */ jsxRuntime.jsx(
352
+ ui.Input,
353
+ {
354
+ id,
355
+ "data-testid": testId,
356
+ type: "date",
357
+ value: String(value ?? ""),
358
+ "aria-invalid": error ? true : void 0,
359
+ "aria-describedby": error ? idFor("error") : void 0,
360
+ onChange: (e) => onChange(e.target.value)
361
+ }
362
+ );
363
+ case "boolean":
364
+ return /* @__PURE__ */ jsxRuntime.jsx(
365
+ ui.Switch,
366
+ {
367
+ id,
368
+ "data-testid": testId,
369
+ checked: Boolean(value),
370
+ onCheckedChange: (checked) => onChange(checked)
371
+ }
372
+ );
373
+ case "select": {
374
+ const options = field.options ?? [];
375
+ if (options.length > 0 && options.length <= TILE_MAX) {
376
+ return /* @__PURE__ */ jsxRuntime.jsx(
377
+ "div",
378
+ {
379
+ role: "radiogroup",
380
+ "aria-label": field.label,
381
+ className: "grid grid-cols-2 gap-2 sm:grid-cols-4",
382
+ "data-testid": testId,
383
+ children: options.map((option) => {
384
+ const selected = value === option.value;
385
+ return /* @__PURE__ */ jsxRuntime.jsxs(
386
+ "button",
387
+ {
388
+ type: "button",
389
+ role: "radio",
390
+ "aria-checked": selected,
391
+ "data-testid": chunkMHVNT4J3_cjs.prefixedTestId(testId, option.value, {
392
+ testId: `workflow-field-${field.name}-${option.value}`
393
+ }),
394
+ onClick: () => {
395
+ onChange(option.value);
396
+ },
397
+ className: ui.cn(
398
+ "flex min-h-24 flex-col items-center justify-center gap-1.5 rounded-lg border p-3 text-center transition-colors pointer-coarse:min-h-28 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
399
+ selected ? "border-primary bg-primary/10" : "border-border bg-card [&:hover]:border-primary [&:hover]:bg-muted"
400
+ ),
401
+ children: [
402
+ option.icon && renderIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: renderIcon(option.icon) }),
403
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: option.label }),
404
+ option.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: option.description })
405
+ ]
406
+ },
407
+ option.value
408
+ );
409
+ })
410
+ }
411
+ );
412
+ }
413
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: String(value ?? ""), onValueChange: (v) => onChange(v), children: [
414
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectTrigger, { id, "data-testid": testId, className: "pointer-coarse:min-h-11", children: /* @__PURE__ */ jsxRuntime.jsx(ui.SelectValue, { placeholder: field.placeholder }) }),
415
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectContent, { children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: o.value, children: o.label }, o.value)) })
416
+ ] });
417
+ }
418
+ case "scope": {
419
+ const scope = isWorkflowScope(value) ? value : { folders: [], labels: [] };
420
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderScope?.(field, scope, onChange) });
421
+ }
422
+ case "documents": {
423
+ const picked = isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
424
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
425
+ }
426
+ }
427
+ }
428
+ function FormField(props) {
429
+ const { field, error, l, idFor } = props;
430
+ const isBoolean = field.type === "boolean";
431
+ const showOptional = !field.required && field.type !== "boolean" && field.type !== "scope";
432
+ const label = /* @__PURE__ */ jsxRuntime.jsxs(
433
+ ui.Label,
434
+ {
435
+ htmlFor: `${idFor()}-control`,
436
+ className: isBoolean ? "cursor-pointer font-normal" : void 0,
437
+ children: [
438
+ field.label,
439
+ showOptional && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
440
+ " ",
441
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-normal text-muted-foreground", children: l.optional })
442
+ ] })
443
+ ]
444
+ }
445
+ );
446
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", "data-slot": "schema-field", "data-field": field.name, children: [
447
+ isBoolean ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 pointer-coarse:min-h-11", children: [
448
+ /* @__PURE__ */ jsxRuntime.jsx(FieldControl, { ...props }),
449
+ label
450
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
451
+ field.type !== "scope" && label,
452
+ /* @__PURE__ */ jsxRuntime.jsx(FieldControl, { ...props })
453
+ ] }),
454
+ field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: field.description }),
455
+ error && /* @__PURE__ */ jsxRuntime.jsx(
456
+ "p",
457
+ {
458
+ id: idFor("error"),
459
+ role: "alert",
460
+ className: "text-xs text-destructive",
461
+ "data-testid": idFor("error"),
462
+ children: l.errors[error]
463
+ }
464
+ )
465
+ ] });
466
+ }
467
+ function SchemaForm({
468
+ fields,
469
+ values,
470
+ onChange,
471
+ errors,
472
+ renderScope,
473
+ renderDocuments,
474
+ renderIcon,
475
+ onEnterSubmit,
476
+ testIdPrefix,
477
+ labels,
478
+ className
479
+ }) {
480
+ const l = {
481
+ ...DEFAULT_SCHEMA_FORM_LABELS,
482
+ ...labels,
483
+ errors: { ...DEFAULT_SCHEMA_FORM_LABELS.errors, ...labels?.errors }
484
+ };
485
+ const [advancedOpen, setAdvancedOpen] = react.useState(false);
486
+ const common = fields.filter((f) => !f.advanced);
487
+ const advanced = fields.filter((f) => f.advanced);
488
+ const render = (field) => /* @__PURE__ */ jsxRuntime.jsx(
489
+ FormField,
490
+ {
491
+ field,
492
+ value: values[field.name],
493
+ error: errors?.[field.name],
494
+ onChange: (v) => onChange(field.name, v),
495
+ l,
496
+ idFor: (suffix) => suffix ? `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}-${suffix}` : `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}`,
497
+ renderScope,
498
+ renderDocuments,
499
+ renderIcon,
500
+ onEnterSubmit
501
+ },
502
+ field.name
503
+ );
504
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-4", className), "data-slot": "schema-form", children: [
505
+ common.map(render),
506
+ advanced.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
507
+ chunk7D737FLE_cjs.FoldSection,
508
+ {
509
+ label: l.advanced,
510
+ open: advancedOpen,
511
+ onOpenChange: setAdvancedOpen,
512
+ testId: `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-advanced-toggle`,
513
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: advanced.map(render) })
514
+ }
515
+ )
516
+ ] });
517
+ }
518
+
519
+ // src/agents/workflows/run.ts
520
+ function workflowSteps(workflow) {
521
+ return workflow.run.kind === "steps" ? workflow.run.steps : [];
522
+ }
523
+ var isSteppedWorkflow = (workflow) => workflow.run.kind === "steps";
524
+ function stepDependencies(steps, id) {
525
+ const i = steps.findIndex((s) => s.id === id);
526
+ if (i < 0) return [];
527
+ return steps[i].after ?? (i > 0 ? [steps[i - 1].id] : []);
528
+ }
529
+ function dependsOn(steps, a, b) {
530
+ const seen = /* @__PURE__ */ new Set();
531
+ const stack = [...stepDependencies(steps, a)];
532
+ while (stack.length) {
533
+ const id = stack.pop();
534
+ if (id === b) return true;
535
+ if (seen.has(id)) continue;
536
+ seen.add(id);
537
+ stack.push(...stepDependencies(steps, id));
538
+ }
539
+ return false;
540
+ }
541
+ function orderSteps(steps) {
542
+ const explicit = steps.map((s) => ({ ...s, after: stepDependencies(steps, s.id) }));
543
+ const known = new Set(explicit.map((s) => s.id));
544
+ const placed = /* @__PURE__ */ new Set();
545
+ const out = [];
546
+ let progress = true;
547
+ while (out.length < explicit.length && progress) {
548
+ progress = false;
549
+ for (const s of explicit) {
550
+ if (placed.has(s.id)) continue;
551
+ if (s.after.every((d) => placed.has(d) || !known.has(d))) {
552
+ out.push(s);
553
+ placed.add(s.id);
554
+ progress = true;
555
+ break;
556
+ }
557
+ }
558
+ }
559
+ return [...out, ...explicit.filter((s) => !placed.has(s.id))];
560
+ }
561
+ function validateWorkflowGraph(steps) {
562
+ const problems = [];
563
+ const ids = /* @__PURE__ */ new Set();
564
+ for (const s of steps) {
565
+ if (ids.has(s.id)) problems.push({ code: "duplicate", step: s.id });
566
+ ids.add(s.id);
567
+ }
568
+ steps.forEach((s, i) => {
569
+ for (const d of stepDependencies(steps, s.id)) {
570
+ if (!ids.has(d)) problems.push({ code: "unknown", step: s.id, dependency: d });
571
+ else if (d === s.id || dependsOn(steps, d, s.id)) problems.push({ code: "cycle", step: s.id });
572
+ else if (steps.findIndex((x) => x.id === d) > i)
573
+ problems.push({ code: "order", step: s.id, dependency: d });
574
+ }
575
+ });
576
+ return problems;
577
+ }
578
+ function stepLevels(steps) {
579
+ const depth = /* @__PURE__ */ new Map();
580
+ for (const s of steps) {
581
+ const deps = stepDependencies(steps, s.id).filter((d) => depth.has(d));
582
+ depth.set(s.id, deps.length ? Math.max(...deps.map((d) => depth.get(d))) + 1 : 0);
583
+ }
584
+ const levels = [];
585
+ for (const s of steps) (levels[depth.get(s.id)] ??= []).push(s);
586
+ return levels.filter(Boolean);
587
+ }
588
+ var STEP_EVENTS = {
589
+ step_started: "running",
590
+ step_done: "done",
591
+ step_skipped: "skipped",
592
+ step_failed: "failed"
593
+ };
594
+ function stepStatesFromActivity(events) {
595
+ const states = {};
596
+ for (const e of events) {
597
+ const status = STEP_EVENTS[e.kind];
598
+ const step = e.detail?.step;
599
+ if (!status || typeof step !== "string") continue;
600
+ const responseId = typeof e.detail?.response_id === "string" ? e.detail.response_id : void 0;
601
+ const error = typeof e.detail?.error === "string" ? e.detail.error : null;
602
+ states[step] = { status, responseId: responseId ?? states[step]?.responseId ?? null, error };
603
+ }
604
+ return states;
605
+ }
606
+ function runFields(workflow) {
607
+ return [
608
+ ...workflow.inputs,
609
+ ...workflowSteps(workflow).flatMap((s) => s.kind === "form" ? s.inputs : [])
610
+ ];
611
+ }
612
+ function initialRunInputs(workflow, inputs = {}) {
613
+ return { ...defaultInputs({ ...workflow, inputs: runFields(workflow) }), ...inputs };
614
+ }
615
+ var finished = (s) => s?.status === "done" || s?.status === "skipped";
616
+ function stepPhase(steps, states, id) {
617
+ const s = states[id];
618
+ if (s && s.status !== "pending") return s.status;
619
+ return stepDependencies(steps, id).every((d) => finished(states[d])) ? "ready" : "blocked";
620
+ }
621
+ var isRunFinished = (steps, states) => steps.length > 0 && steps.every((s) => finished(states[s.id]));
622
+ var isPersonStep = (step) => step.kind !== "agent";
623
+ function nextAction(steps, states, current) {
624
+ const i = steps.findIndex((s) => s.id === current);
625
+ const step = steps[i];
626
+ if (!step) return "wait";
627
+ const phase = stepPhase(steps, states, step.id);
628
+ if (phase === "blocked") return "wait";
629
+ const following = steps[i + 1];
630
+ const independentNext = !!following && !dependsOn(steps, following.id, step.id);
631
+ if (phase === "done" || phase === "skipped") {
632
+ if (following) return "move";
633
+ return isRunFinished(steps, states) ? "finish" : "wait";
634
+ }
635
+ if (isPersonStep(step)) return "complete";
636
+ if (phase !== "failed") return independentNext ? "move" : "wait";
637
+ const waitedFor = steps.slice(i + 1).some((s) => dependsOn(steps, s.id, step.id));
638
+ return waitedFor || !following ? "skip" : "move";
639
+ }
640
+ function validateStep(step, inputs) {
641
+ if (step.kind !== "form") return {};
642
+ return validateInputs(
643
+ {
644
+ id: step.id,
645
+ title: step.title,
646
+ inputs: step.inputs},
647
+ inputs
648
+ );
649
+ }
650
+ var asText = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
651
+ function fillStepInputs(templates, inputs) {
652
+ const out = {};
653
+ for (const [name, template] of Object.entries(templates ?? {})) {
654
+ const bare = /^\{\{\s*([a-z][a-z0-9_]*)\s*\}\}$/i.exec(template);
655
+ if (bare) {
656
+ out[name] = inputs[bare[1]] ?? "";
657
+ continue;
658
+ }
659
+ out[name] = fillRunText(template, inputs);
660
+ }
661
+ return out;
662
+ }
663
+ function fillRunText(template, inputs) {
664
+ return template.replace(/\{\{([^}]*)\}\}/g, (_, expr) => {
665
+ for (const ref of expr.split("||")) {
666
+ const text = asText(inputs[ref.trim()]);
667
+ if (text) return text;
668
+ }
669
+ return "";
670
+ }).trim();
671
+ }
672
+ function runThreadTitle(workflow, inputs) {
673
+ const template = workflow.run.kind === "steps" ? workflow.run.threadTitle : void 0;
674
+ return template && fillRunText(template, inputs) || workflow.title;
675
+ }
676
+ function reviewInstructions(step, inputs) {
677
+ return step.instructions && fillRunText(step.instructions, inputs) || step.title;
678
+ }
679
+ function composeStepPrompt(workflow, step, runInputs, { resolveWorkflow, compose } = {}) {
680
+ if (step.workflow) {
681
+ const target = resolveWorkflow?.(step.workflow);
682
+ if (!target) return "";
683
+ const inputs = { ...defaultInputs(target), ...fillStepInputs(step.with, runInputs) };
684
+ return target.run.kind === "prompt" ? composeWorkflowPrompt(target, inputs) : compose?.(target.id, inputs, runInputs) ?? "";
685
+ }
686
+ if (step.run?.kind === "prompt") {
687
+ return composeWorkflowPrompt(
688
+ { ...workflow, inputs: runFields(workflow), run: step.run },
689
+ runInputs
690
+ );
691
+ }
692
+ return compose?.(step.id, runInputs, runInputs) ?? "";
693
+ }
694
+
695
+ // src/agents/workflows/planSteps.ts
696
+ var compact2 = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== ""));
697
+ function placeholders(workflow) {
698
+ return Object.fromEntries(runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
699
+ }
700
+ function agentStep(workflow, step, options) {
701
+ const target = step.workflow ? options.resolveWorkflow?.(step.workflow) : void 0;
702
+ if (target?.skill) return { skill: target.skill, inputs: step.with ?? {}, prompt: null };
703
+ const given = Object.entries(options.inputs ?? {}).filter(
704
+ ([, v]) => v !== void 0 && v !== null && v !== ""
705
+ );
706
+ const inputs = { ...placeholders(workflow), ...Object.fromEntries(given) };
707
+ return { skill: null, inputs: null, prompt: composeStepPrompt(workflow, step, inputs, options) };
708
+ }
709
+ function toPlanSteps(workflow, options = {}) {
710
+ const layout = workflow.run.kind === "steps" ? workflow.run.layout : void 0;
711
+ return workflowSteps(workflow).map((step) => {
712
+ const ui = compact2({
713
+ description: step.description,
714
+ icon: step.icon,
715
+ commit: step.commit,
716
+ next_label: step.nextLabel,
717
+ position: layout?.[step.id],
718
+ ...step.kind === "form" ? { fields: step.inputs } : {},
719
+ ...step.kind === "upload" ? { required: step.required, accept: step.accept, hint: step.hint } : {},
720
+ ...step.kind === "review" ? { instructions: step.instructions } : {},
721
+ ...step.kind === "agent" ? {
722
+ output: step.output,
723
+ workflow: step.workflow,
724
+ with: step.with,
725
+ prompt_template: step.run?.kind === "prompt" ? step.run.promptTemplate : void 0
726
+ } : {}
727
+ });
728
+ return {
729
+ id: step.id,
730
+ title: step.title,
731
+ kind: step.kind,
732
+ after: step.after ?? null,
733
+ branch: step.kind === "agent" && !!step.branch,
734
+ requires_files: false,
735
+ ui,
736
+ ...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
737
+ };
738
+ });
739
+ }
740
+ function fromPlanSteps(steps) {
741
+ return (steps ?? []).map((p) => {
742
+ const ui = p.ui ?? {};
743
+ const base = {
744
+ id: p.id,
745
+ title: p.title,
746
+ description: ui.description,
747
+ icon: ui.icon,
748
+ commit: ui.commit,
749
+ nextLabel: ui.next_label,
750
+ ...p.after != null ? { after: p.after } : {}
751
+ };
752
+ switch (p.kind) {
753
+ case "form":
754
+ return { ...base, kind: "form", inputs: ui.fields ?? [] };
755
+ case "upload":
756
+ return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
757
+ case "review":
758
+ return { ...base, kind: "review", instructions: ui.instructions };
759
+ default: {
760
+ const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
761
+ return {
762
+ ...base,
763
+ kind: "agent",
764
+ workflow: ui.workflow ?? p.skill ?? void 0,
765
+ with: ui.with ?? p.inputs ?? void 0,
766
+ run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
767
+ output: ui.output,
768
+ branch: p.branch || void 0
769
+ };
770
+ }
771
+ }
772
+ });
773
+ }
774
+ function layoutFromPlanSteps(steps) {
775
+ const entries = (steps ?? []).flatMap((p) => {
776
+ const position = p.ui?.position;
777
+ return position ? [[p.id, position]] : [];
778
+ });
779
+ return entries.length ? Object.fromEntries(entries) : void 0;
780
+ }
781
+ var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
782
+ function firstOpen(steps, states) {
783
+ const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
784
+ return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
785
+ }
786
+ function useWorkflowView(options) {
787
+ const { steps, states, inputs, setInput } = options;
788
+ const [current, setCurrent] = react.useState(() => firstOpen(steps, states));
789
+ const [showErrors, setShowErrors] = react.useState(false);
790
+ const [busy, setBusy] = react.useState(false);
791
+ const [actionError, setActionError] = react.useState(null);
792
+ const optionsRef = react.useRef(options);
793
+ optionsRef.current = options;
794
+ const placed = react.useRef(steps.length > 0);
795
+ react.useEffect(() => {
796
+ if (placed.current || steps.length === 0) return;
797
+ placed.current = true;
798
+ setCurrent(firstOpen(steps, states));
799
+ }, [steps, states]);
800
+ const step = steps.find((s) => s.id === current);
801
+ const following = react.useCallback(
802
+ (id) => {
803
+ const i = steps.findIndex((s) => s.id === id);
804
+ return steps[i + 1]?.id ?? null;
805
+ },
806
+ [steps]
807
+ );
808
+ const action = busy ? "wait" : nextAction(steps, states, current);
809
+ const next = react.useCallback(async () => {
810
+ const { steps: s, states: st, inputs: values } = optionsRef.current;
811
+ const at = s.find((x) => x.id === current);
812
+ const act2 = nextAction(s, st, current);
813
+ if (!at || act2 === "wait" || busy) return;
814
+ setActionError(null);
815
+ if (act2 === "finish") return setCurrent(null);
816
+ if (act2 === "move") return setCurrent(following(current));
817
+ setBusy(true);
818
+ try {
819
+ if (act2 === "skip") {
820
+ await optionsRef.current.skip(at.id);
821
+ } else {
822
+ if (Object.keys(validateStep(at, values)).length > 0) {
823
+ setShowErrors(true);
824
+ return;
825
+ }
826
+ await optionsRef.current.complete(at);
827
+ }
828
+ setShowErrors(false);
829
+ setCurrent(following(current) ?? current);
830
+ } catch (e) {
831
+ setActionError(errorMessage(e));
832
+ } finally {
833
+ setBusy(false);
834
+ }
835
+ }, [current, busy, following]);
836
+ const goTo = react.useCallback((stepId) => {
837
+ setShowErrors(false);
838
+ setActionError(null);
839
+ setCurrent(stepId);
840
+ }, []);
841
+ const index = steps.findIndex((s) => s.id === current);
842
+ const back = react.useCallback(() => {
843
+ const i = steps.findIndex((s) => s.id === current);
844
+ const to = i < 0 ? steps[steps.length - 1] : steps[i - 1];
845
+ if (to) goTo(to.id);
846
+ }, [steps, current, goTo]);
847
+ const act = react.useCallback(
848
+ (fn) => fn && (async (stepId) => {
849
+ setBusy(true);
850
+ setActionError(null);
851
+ try {
852
+ await fn(stepId);
853
+ } catch (e) {
854
+ setActionError(errorMessage(e));
855
+ } finally {
856
+ setBusy(false);
857
+ }
858
+ }),
859
+ []
860
+ );
861
+ const skip = react.useMemo(
862
+ () => act((id) => optionsRef.current.skip(id)),
863
+ [act]
864
+ );
865
+ const retry = react.useMemo(
866
+ () => options.retry ? act((id) => optionsRef.current.retry?.(id) ?? Promise.resolve()) : void 0,
867
+ // Only whether the host offers retry matters here.
868
+ // eslint-disable-next-line react-hooks/exhaustive-deps
869
+ [act, !!options.retry]
870
+ );
871
+ const isLocked = react.useCallback(
872
+ (stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
873
+ []
874
+ );
875
+ return {
876
+ steps,
877
+ step,
878
+ current,
879
+ isComplete: current === null,
880
+ inputs,
881
+ setInput,
882
+ stateOf: (id) => states[id],
883
+ phaseOf: (id) => stepPhase(steps, states, id),
884
+ isLocked,
885
+ errors: showErrors && step && !isLocked(step.id) ? validateStep(step, inputs) : {},
886
+ busy,
887
+ actionError,
888
+ isRunning: Object.values(states).some((s) => s.status === "running"),
889
+ action,
890
+ canBack: (current === null || index > 0) && !busy,
891
+ next,
892
+ back,
893
+ goTo,
894
+ skip,
895
+ retry,
896
+ restart: () => {
897
+ setShowErrors(false);
898
+ setActionError(null);
899
+ setCurrent(steps[0]?.id ?? null);
900
+ }
901
+ };
902
+ }
903
+ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
904
+ back: "Back",
905
+ next: "Continue",
906
+ skip: "Skip",
907
+ skipStep: "Skip this step",
908
+ finish: "Finish",
909
+ approve: "Approve",
910
+ working: "Working\u2026",
911
+ starting: "Starting\u2026",
912
+ retry: "Retry",
913
+ failed: "This step did not finish.",
914
+ blocked: "Starts after {steps}.",
915
+ awaitingReview: "Waiting for approval.",
916
+ approved: "Approved.",
917
+ skipped: "Skipped.",
918
+ branch: "Runs alongside; its result joins the thread",
919
+ complete: "Done",
920
+ restart: "Start again",
921
+ filesHeading: "Files ({count})",
922
+ noFiles: "No files yet."
923
+ };
924
+ function PhaseMark({ phase, icon }) {
925
+ if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5" });
926
+ if (phase === "running") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin" });
927
+ if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3.5" });
928
+ if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-3.5" });
929
+ return icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-3.5 items-center justify-center [&_svg]:size-3.5", children: icon }) : null;
930
+ }
931
+ function WorkflowRunner({
932
+ workflow,
933
+ run,
934
+ renderAgentOutput,
935
+ renderReview,
936
+ onUpload,
937
+ uploading = false,
938
+ files,
939
+ renderUpload,
940
+ renderStepNote,
941
+ renderComplete,
942
+ renderScope,
943
+ renderDocuments,
944
+ renderIcon,
945
+ labels,
946
+ testIdPrefix = "workflow-run",
947
+ className
948
+ }) {
949
+ const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
950
+ const { steps, step, isComplete, action } = run;
951
+ const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
952
+ const tid = (suffix) => `${testIdPrefix}-${suffix}`;
953
+ const levels = stepLevels(steps);
954
+ const crowded = levels.length > 6;
955
+ const icon = (key) => key && renderIcon ? renderIcon(key) : void 0;
956
+ const pill = (s) => {
957
+ const phase = run.phaseOf(s.id);
958
+ const current = s.id === run.current;
959
+ return /* @__PURE__ */ jsxRuntime.jsxs(
960
+ "button",
961
+ {
962
+ type: "button",
963
+ onClick: () => run.goTo(s.id),
964
+ disabled: run.busy,
965
+ className: ui.cn(
966
+ "flex shrink-0 items-center gap-2 whitespace-nowrap rounded-full border px-2.5 py-1.5 text-xs font-medium transition-colors disabled:cursor-default",
967
+ current ? "border-primary bg-primary/10 text-primary" : phase === "failed" ? "border-destructive/40 text-destructive" : phase === "done" || phase === "skipped" || phase === "running" ? "border-primary/30 bg-primary/5 text-primary" : "border-border text-muted-foreground"
968
+ ),
969
+ "aria-current": current ? "step" : void 0,
970
+ "aria-label": s.title,
971
+ title: s.title,
972
+ "data-phase": phase,
973
+ "data-testid": tid(`step-${s.id}`),
974
+ children: [
975
+ /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase, icon: icon(s.icon) }),
976
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn(current ? "inline" : crowded ? "hidden" : "hidden @4xl:inline"), children: s.title })
977
+ ]
978
+ },
979
+ s.id
980
+ );
981
+ };
982
+ const nextLabel = action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
983
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-6", className), "data-testid": testIdPrefix, children: [
984
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "@container", children: /* @__PURE__ */ jsxRuntime.jsx(
985
+ "ol",
986
+ {
987
+ className: ui.cn("flex w-full items-center gap-1.5", crowded && "overflow-x-auto pb-1"),
988
+ "data-testid": tid("steps"),
989
+ children: [...levels, null].map((level, i) => /* @__PURE__ */ jsxRuntime.jsxs(
990
+ "li",
991
+ {
992
+ className: ui.cn(
993
+ "flex items-center gap-1.5",
994
+ i < levels.length && (crowded ? "flex-none" : "min-w-0 flex-1 @4xl:flex-none")
995
+ ),
996
+ children: [
997
+ level ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-start gap-1", children: level.map(pill) }) : /* @__PURE__ */ jsxRuntime.jsxs(
998
+ "div",
999
+ {
1000
+ className: ui.cn(
1001
+ "flex shrink-0 items-center gap-2 whitespace-nowrap rounded-full border px-2.5 py-1.5 text-xs font-medium",
1002
+ isComplete ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground"
1003
+ ),
1004
+ "aria-current": isComplete ? "step" : void 0,
1005
+ "data-testid": tid("step-done"),
1006
+ children: [
1007
+ /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase: "ready", icon: icon(completion?.icon) }),
1008
+ /* @__PURE__ */ jsxRuntime.jsx(
1009
+ "span",
1010
+ {
1011
+ className: ui.cn(
1012
+ isComplete ? "inline" : crowded ? "hidden" : "hidden @4xl:inline"
1013
+ ),
1014
+ children: completion?.title ?? l.complete
1015
+ }
1016
+ )
1017
+ ]
1018
+ }
1019
+ ),
1020
+ i < levels.length && /* @__PURE__ */ jsxRuntime.jsx(
1021
+ "div",
1022
+ {
1023
+ className: ui.cn(
1024
+ "h-px",
1025
+ crowded ? "w-3 flex-none" : "min-w-2 flex-1 @4xl:w-4 @4xl:flex-none",
1026
+ level?.every((s) => ["done", "skipped"].includes(run.phaseOf(s.id))) ? "bg-primary/40" : "bg-border"
1027
+ )
1028
+ }
1029
+ )
1030
+ ]
1031
+ },
1032
+ level ? level.map((s) => s.id).join("+") : "done"
1033
+ ))
1034
+ }
1035
+ ) }),
1036
+ isComplete ? renderComplete?.(run) ?? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "mx-auto max-w-lg p-8 text-center", "data-testid": tid("done"), children: [
1037
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "mx-auto size-12 text-primary" }),
1038
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-4 text-xl font-semibold", children: completion?.title ?? l.complete }),
1039
+ completion?.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: completion.description }),
1040
+ /* @__PURE__ */ jsxRuntime.jsx(
1041
+ ui.Button,
1042
+ {
1043
+ variant: "outline",
1044
+ className: "mt-6",
1045
+ onClick: run.restart,
1046
+ "data-testid": tid("restart"),
1047
+ children: l.restart
1048
+ }
1049
+ )
1050
+ ] }) : step ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: run.phaseOf(step.id) === "blocked" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { className: "max-w-2xl p-6", "data-testid": tid(step.id), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": tid(`${step.id}-blocked`), children: l.blocked.replace(
1051
+ "{steps}",
1052
+ stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
1053
+ ) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
1054
+ step.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: step.description }),
1055
+ /* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsxRuntime.jsx(
1056
+ SchemaForm,
1057
+ {
1058
+ fields: step.inputs,
1059
+ values: run.inputs,
1060
+ onChange: run.setInput,
1061
+ errors: run.errors,
1062
+ renderScope,
1063
+ renderDocuments,
1064
+ renderIcon,
1065
+ onEnterSubmit: () => void run.next(),
1066
+ testIdPrefix: tid("field")
1067
+ }
1068
+ ) }),
1069
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
1070
+ renderStepNote?.(step, run)
1071
+ ] }) : step.kind === "upload" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
1072
+ renderUpload?.(step) ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1073
+ /* @__PURE__ */ jsxRuntime.jsx(
1074
+ chunkDETZZBG2_cjs.UploadDropzone,
1075
+ {
1076
+ onFiles: (picked) => void onUpload?.(picked),
1077
+ uploading,
1078
+ disabled: !onUpload,
1079
+ accept: step.accept,
1080
+ title: step.title,
1081
+ description: step.description,
1082
+ hint: step.hint,
1083
+ testId: tid(`${step.id}-drop`)
1084
+ }
1085
+ ),
1086
+ files && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", "data-testid": tid(`${step.id}-files`), children: [
1087
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.filesHeading.replace("{count}", String(files.length)) }),
1088
+ files.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.noFiles }),
1089
+ files.slice(0, 6).map((f) => /* @__PURE__ */ jsxRuntime.jsxs(
1090
+ "div",
1091
+ {
1092
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
1093
+ children: [
1094
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 text-primary" }),
1095
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: f.name })
1096
+ ]
1097
+ },
1098
+ f.id
1099
+ ))
1100
+ ] })
1101
+ ] }),
1102
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
1103
+ renderStepNote?.(step, run)
1104
+ ] }) : step.kind === "review" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
1105
+ /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
1106
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
1107
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", "data-testid": tid(`${step.id}-status`), children: run.phaseOf(step.id) === "done" ? l.approved : run.phaseOf(step.id) === "skipped" ? l.skipped : l.awaitingReview }),
1108
+ run.phaseOf(step.id) === "ready" && renderReview?.(step),
1109
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
1110
+ renderStepNote?.(step, run)
1111
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
1112
+ AgentStepBody,
1113
+ {
1114
+ step,
1115
+ run,
1116
+ renderAgentOutput,
1117
+ icon: icon(step.icon),
1118
+ renderStepNote,
1119
+ l,
1120
+ tid
1121
+ }
1122
+ ) }, step.id) : null,
1123
+ !isComplete && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-t border-border pt-4", children: [
1124
+ /* @__PURE__ */ jsxRuntime.jsxs(
1125
+ ui.Button,
1126
+ {
1127
+ variant: "ghost",
1128
+ onClick: run.back,
1129
+ disabled: !run.canBack,
1130
+ "data-testid": tid("back"),
1131
+ children: [
1132
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "size-4" }),
1133
+ " ",
1134
+ l.back
1135
+ ]
1136
+ }
1137
+ ),
1138
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1139
+ step && action !== "skip" && // A step that commits (creates the matter, starts the thread) is what the run stands on.
1140
+ !step.commit && ["ready", "blocked", "failed"].includes(run.phaseOf(step.id)) && /* @__PURE__ */ jsxRuntime.jsx(
1141
+ ui.Button,
1142
+ {
1143
+ variant: "ghost",
1144
+ onClick: () => void run.skip(step.id),
1145
+ disabled: run.busy,
1146
+ "data-testid": tid("skip-step"),
1147
+ children: l.skipStep
1148
+ }
1149
+ ),
1150
+ /* @__PURE__ */ jsxRuntime.jsxs(
1151
+ ui.Button,
1152
+ {
1153
+ onClick: () => void run.next(),
1154
+ disabled: action === "wait",
1155
+ "data-testid": tid("next"),
1156
+ children: [
1157
+ nextLabel,
1158
+ action === "wait" && (run.isRunning || run.busy) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "size-4" })
1159
+ ]
1160
+ }
1161
+ )
1162
+ ] })
1163
+ ] })
1164
+ ] });
1165
+ }
1166
+ function StepHeading({ step, icon }) {
1167
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
1168
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", children: [
1169
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-4 items-center justify-center text-primary [&_svg]:size-4", children: icon }),
1170
+ step.title
1171
+ ] }),
1172
+ step.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: step.description })
1173
+ ] });
1174
+ }
1175
+ function AgentStepBody({
1176
+ step,
1177
+ run,
1178
+ renderAgentOutput,
1179
+ icon,
1180
+ renderStepNote,
1181
+ l,
1182
+ tid
1183
+ }) {
1184
+ const state = run.stateOf(step.id);
1185
+ const phase = run.phaseOf(step.id);
1186
+ const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
1187
+ /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon }),
1188
+ phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: run.retry && /* @__PURE__ */ jsxRuntime.jsxs(
1189
+ ui.Button,
1190
+ {
1191
+ variant: "outline",
1192
+ size: "sm",
1193
+ onClick: () => void run.retry?.(step.id),
1194
+ disabled: run.busy,
1195
+ "data-testid": tid(`${step.id}-retry`),
1196
+ children: [
1197
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "size-4" }),
1198
+ " ",
1199
+ l.retry
1200
+ ]
1201
+ }
1202
+ ) })
1203
+ ] });
1204
+ const status = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1205
+ step.branch && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1206
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { className: "size-3.5" }),
1207
+ " ",
1208
+ l.branch
1209
+ ] }),
1210
+ (phase === "ready" || phase === "running") && !state?.text && /* @__PURE__ */ jsxRuntime.jsxs(
1211
+ "p",
1212
+ {
1213
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
1214
+ "data-testid": tid(`${step.id}-working`),
1215
+ children: [
1216
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
1217
+ " ",
1218
+ phase === "ready" ? l.starting : l.working
1219
+ ]
1220
+ }
1221
+ ),
1222
+ phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
1223
+ phase === "skipped" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped })
1224
+ ] });
1225
+ if (step.output === "artifact") {
1226
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1227
+ "div",
1228
+ {
1229
+ className: "grid gap-4 lg:grid-cols-[minmax(0,18rem)_minmax(0,1fr)]",
1230
+ "data-testid": tid(step.id),
1231
+ children: [
1232
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "h-fit space-y-3 p-5", children: [
1233
+ header,
1234
+ status,
1235
+ renderStepNote?.(step, run)
1236
+ ] }),
1237
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: renderAgentOutput(step, state) })
1238
+ ]
1239
+ }
1240
+ );
1241
+ }
1242
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "space-y-3 p-6", "data-testid": tid(step.id), children: [
1243
+ header,
1244
+ status,
1245
+ renderAgentOutput(step, state),
1246
+ renderStepNote?.(step, run)
1247
+ ] });
1248
+ }
1249
+
1250
+ exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
1251
+ exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
1252
+ exports.EMPTY_WORKFLOW_SCOPE = EMPTY_WORKFLOW_SCOPE;
1253
+ exports.SKILL_PROMPT_FALLBACK_PLACEHOLDER = SKILL_PROMPT_FALLBACK_PLACEHOLDER;
1254
+ exports.SKILL_PROMPT_LABEL = SKILL_PROMPT_LABEL;
1255
+ exports.SchemaForm = SchemaForm;
1256
+ exports.WorkflowRunner = WorkflowRunner;
1257
+ exports.buildLaunch = buildLaunch;
1258
+ exports.composeStepPrompt = composeStepPrompt;
1259
+ exports.composeWorkflowPrompt = composeWorkflowPrompt;
1260
+ exports.defaultInputs = defaultInputs;
1261
+ exports.dependsOn = dependsOn;
1262
+ exports.fieldToFrontmatter = fieldToFrontmatter;
1263
+ exports.fillRunText = fillRunText;
1264
+ exports.fillStepInputs = fillStepInputs;
1265
+ exports.fromPlanSteps = fromPlanSteps;
1266
+ exports.initialRunInputs = initialRunInputs;
1267
+ exports.inputsFromContext = inputsFromContext;
1268
+ exports.isEmptyWorkflowScope = isEmptyWorkflowScope;
1269
+ exports.isPersonStep = isPersonStep;
1270
+ exports.isRunFinished = isRunFinished;
1271
+ exports.isSteppedWorkflow = isSteppedWorkflow;
1272
+ exports.isWorkflowScope = isWorkflowScope;
1273
+ exports.layoutFromPlanSteps = layoutFromPlanSteps;
1274
+ exports.nextAction = nextAction;
1275
+ exports.orderSteps = orderSteps;
1276
+ exports.promptFieldName = promptFieldName;
1277
+ exports.reviewInstructions = reviewInstructions;
1278
+ exports.runFields = runFields;
1279
+ exports.runThreadTitle = runThreadTitle;
1280
+ exports.skillToWorkflow = skillToWorkflow;
1281
+ exports.stepDependencies = stepDependencies;
1282
+ exports.stepLevels = stepLevels;
1283
+ exports.stepPhase = stepPhase;
1284
+ exports.stepStatesFromActivity = stepStatesFromActivity;
1285
+ exports.toPlanSteps = toPlanSteps;
1286
+ exports.useWorkflowView = useWorkflowView;
1287
+ exports.validateInputs = validateInputs;
1288
+ exports.validateStep = validateStep;
1289
+ exports.validateWorkflowGraph = validateWorkflowGraph;
1290
+ exports.workflowAccepts = workflowAccepts;
1291
+ exports.workflowFromFrontmatter = workflowFromFrontmatter;
1292
+ exports.workflowSteps = workflowSteps;
1293
+ exports.workflowsAccepting = workflowsAccepting;
1294
+ exports.workflowsForHost = workflowsForHost;
1295
+ //# sourceMappingURL=chunk-GTNUQBXI.cjs.map
1296
+ //# sourceMappingURL=chunk-GTNUQBXI.cjs.map