@arbidocs/blocks 0.4.76 → 0.4.78

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 (123) hide show
  1. package/dist/agents/index.cjs +346 -258
  2. package/dist/agents/index.js +5 -5
  3. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  4. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +15 -4
  5. package/dist/agents/workflows/SchemaForm.d.ts +6 -1
  6. package/dist/agents/workflows/StepBarFrame.d.ts +75 -0
  7. package/dist/agents/workflows/StepParts.d.ts +109 -0
  8. package/dist/agents/workflows/WorkflowRunner.d.ts +15 -2
  9. package/dist/agents/workflows/WorkflowStepBar.d.ts +9 -11
  10. package/dist/agents/workflows/index.d.ts +5 -2
  11. package/dist/agents/workflows/planSteps.d.ts +8 -1
  12. package/dist/agents/workflows/run.d.ts +61 -8
  13. package/dist/agents/workflows/stepWindow.d.ts +59 -0
  14. package/dist/agents/workflows/types.d.ts +133 -4
  15. package/dist/agents/workflows/useWorkflowPreview.d.ts +2 -1
  16. package/dist/agents/workflows/useWorkflowView.d.ts +19 -0
  17. package/dist/chat/ChatPage.d.ts +1 -1
  18. package/dist/chat/WorkflowStepChip.d.ts +24 -0
  19. package/dist/chat/chat-page-types.d.ts +9 -0
  20. package/dist/chat/index.cjs +130 -122
  21. package/dist/chat/index.d.ts +1 -0
  22. package/dist/chat/index.js +2 -2
  23. package/dist/{chunk-TKB7TVMW.js → chunk-5OC5CGYX.js} +168 -100
  24. package/dist/chunk-5OC5CGYX.js.map +1 -0
  25. package/dist/{chunk-ZWA7UUZL.cjs → chunk-7YUFMNFW.cjs} +2 -54
  26. package/dist/chunk-7YUFMNFW.cjs.map +1 -0
  27. package/dist/chunk-A24C6BNA.js +92 -0
  28. package/dist/chunk-A24C6BNA.js.map +1 -0
  29. package/dist/chunk-AINNADMT.cjs +62 -0
  30. package/dist/chunk-AINNADMT.cjs.map +1 -0
  31. package/dist/chunk-CWAZNXC5.js +441 -0
  32. package/dist/chunk-CWAZNXC5.js.map +1 -0
  33. package/dist/{chunk-UIWLDSTF.js → chunk-EWSEQEPL.js} +71 -7
  34. package/dist/chunk-EWSEQEPL.js.map +1 -0
  35. package/dist/chunk-FE4ULGOR.js +151 -0
  36. package/dist/chunk-FE4ULGOR.js.map +1 -0
  37. package/dist/chunk-FT5FFXSJ.js +60 -0
  38. package/dist/chunk-FT5FFXSJ.js.map +1 -0
  39. package/dist/{chunk-WJEKRSPH.js → chunk-ICBAFX5B.js} +3 -3
  40. package/dist/{chunk-WJEKRSPH.js.map → chunk-ICBAFX5B.js.map} +1 -1
  41. package/dist/{chunk-7CVF3DK2.cjs → chunk-IF6VAYIA.cjs} +5 -5
  42. package/dist/{chunk-7CVF3DK2.cjs.map → chunk-IF6VAYIA.cjs.map} +1 -1
  43. package/dist/chunk-MLAHDAN5.cjs +450 -0
  44. package/dist/chunk-MLAHDAN5.cjs.map +1 -0
  45. package/dist/{chunk-IPGKTUF7.cjs → chunk-MP6FK43E.cjs} +71 -5
  46. package/dist/chunk-MP6FK43E.cjs.map +1 -0
  47. package/dist/{chunk-5EBGRG3X.js → chunk-OPA2Y6YZ.js} +3 -54
  48. package/dist/chunk-OPA2Y6YZ.js.map +1 -0
  49. package/dist/{chunk-7FKARMA3.cjs → chunk-SSDISIDW.cjs} +190 -122
  50. package/dist/chunk-SSDISIDW.cjs.map +1 -0
  51. package/dist/chunk-TZR36PPP.cjs +95 -0
  52. package/dist/chunk-TZR36PPP.cjs.map +1 -0
  53. package/dist/chunk-VFIZYSZB.cjs +2783 -0
  54. package/dist/chunk-VFIZYSZB.cjs.map +1 -0
  55. package/dist/chunk-WXRCMIAE.js +2707 -0
  56. package/dist/chunk-WXRCMIAE.js.map +1 -0
  57. package/dist/{chunk-HITAN7JF.cjs → chunk-XMBYDLZQ.cjs} +4 -4
  58. package/dist/{chunk-HITAN7JF.cjs.map → chunk-XMBYDLZQ.cjs.map} +1 -1
  59. package/dist/{chunk-MK6NJQGF.js → chunk-XQDM6T6C.js} +3 -3
  60. package/dist/{chunk-MK6NJQGF.js.map → chunk-XQDM6T6C.js.map} +1 -1
  61. package/dist/chunk-ZVBPRMHJ.cjs +153 -0
  62. package/dist/chunk-ZVBPRMHJ.cjs.map +1 -0
  63. package/dist/connect/docx.cjs +10 -88
  64. package/dist/connect/docx.cjs.map +1 -1
  65. package/dist/connect/docx.js +6 -86
  66. package/dist/connect/docx.js.map +1 -1
  67. package/dist/connect/index.cjs +468 -49
  68. package/dist/connect/index.cjs.map +1 -1
  69. package/dist/connect/index.d.ts +2 -0
  70. package/dist/connect/index.js +454 -37
  71. package/dist/connect/index.js.map +1 -1
  72. package/dist/connection/ConnectedTagMatrix.d.ts +20 -0
  73. package/dist/connection/ConnectedWorkflowRunner.d.ts +28 -2
  74. package/dist/connection/WorkflowRunThread.d.ts +21 -0
  75. package/dist/connection/WorkflowRunnerDialogs.d.ts +37 -0
  76. package/dist/connection/useWorkflowThread.d.ts +12 -0
  77. package/dist/document-tools/index.cjs +7 -143
  78. package/dist/document-tools/index.cjs.map +1 -1
  79. package/dist/document-tools/index.js +5 -144
  80. package/dist/document-tools/index.js.map +1 -1
  81. package/dist/docx/index.cjs +18 -17
  82. package/dist/docx/index.cjs.map +1 -1
  83. package/dist/docx/index.js +3 -2
  84. package/dist/docx/index.js.map +1 -1
  85. package/dist/facts/index.cjs +1 -1
  86. package/dist/facts/index.js +1 -1
  87. package/dist/files/index.cjs +1 -1
  88. package/dist/files/index.js +1 -1
  89. package/dist/home/index.cjs +1 -1
  90. package/dist/home/index.js +1 -1
  91. package/dist/index.cjs +560 -431
  92. package/dist/index.cjs.map +1 -1
  93. package/dist/index.d.ts +1 -0
  94. package/dist/index.js +10 -9
  95. package/dist/index.js.map +1 -1
  96. package/dist/shell/index.cjs +1 -1
  97. package/dist/shell/index.js +1 -1
  98. package/dist/studio/index.cjs +4 -4
  99. package/dist/studio/index.js +3 -3
  100. package/dist/tags/TagMatrix.d.ts +64 -0
  101. package/dist/tags/index.d.ts +3 -0
  102. package/dist/tags/tagMatrixModel.d.ts +39 -0
  103. package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
  104. package/dist/workflow-canvas/StepInspector.d.ts +25 -2
  105. package/dist/workflow-canvas/WorkflowBuilder.d.ts +11 -3
  106. package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
  107. package/dist/workflow-canvas/edit.d.ts +9 -1
  108. package/dist/workflow-canvas/index.cjs +882 -102
  109. package/dist/workflow-canvas/index.cjs.map +1 -1
  110. package/dist/workflow-canvas/index.js +849 -69
  111. package/dist/workflow-canvas/index.js.map +1 -1
  112. package/package.json +4 -4
  113. package/src/workflow-canvas/canvas.css +9 -0
  114. package/dist/chunk-22P5KNIM.js +0 -1422
  115. package/dist/chunk-22P5KNIM.js.map +0 -1
  116. package/dist/chunk-5EBGRG3X.js.map +0 -1
  117. package/dist/chunk-7FKARMA3.cjs.map +0 -1
  118. package/dist/chunk-IPGKTUF7.cjs.map +0 -1
  119. package/dist/chunk-TKB7TVMW.js.map +0 -1
  120. package/dist/chunk-UIWLDSTF.js.map +0 -1
  121. package/dist/chunk-VYRKO3XU.cjs +0 -1469
  122. package/dist/chunk-VYRKO3XU.cjs.map +0 -1
  123. package/dist/chunk-ZWA7UUZL.cjs.map +0 -1
@@ -0,0 +1,2783 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunk7D737FLE_cjs = require('./chunk-7D737FLE.cjs');
5
+ var chunkDETZZBG2_cjs = require('./chunk-DETZZBG2.cjs');
6
+ var chunkB4SRYJLM_cjs = require('./chunk-B4SRYJLM.cjs');
7
+ var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
8
+ var react = require('react');
9
+ var ui = require('@arbidocs/react/ui');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+ var lucideReact = require('lucide-react');
12
+
13
+ // src/agents/workflows/types.ts
14
+ var EMPTY_WORKFLOW_SCOPE = { folders: [], labels: [] };
15
+
16
+ // src/agents/workflows/workflow.ts
17
+ var isWorkflowScope = (value) => typeof value === "object" && value !== null && Array.isArray(value.folders) && Array.isArray(value.labels);
18
+ var isEmptyWorkflowScope = (scope) => scope.folders.length === 0 && scope.labels.length === 0 && !scope.documents?.length;
19
+ var isFileField = (field) => field.type === "scope" || field.type === "documents";
20
+ function emptyValue(field) {
21
+ switch (field.type) {
22
+ case "boolean":
23
+ return false;
24
+ case "scope":
25
+ return { folders: [], labels: [] };
26
+ case "documents":
27
+ return { folders: [], labels: [], documents: [] };
28
+ default:
29
+ return "";
30
+ }
31
+ }
32
+ function defaultInputs(workflow) {
33
+ const inputs = {};
34
+ for (const field of workflow.inputs) {
35
+ const d = field.default;
36
+ inputs[field.name] = d === void 0 ? emptyValue(field) : isWorkflowScope(d) ? { ...d } : d;
37
+ }
38
+ return inputs;
39
+ }
40
+ function validateInputs(workflow, inputs) {
41
+ const errors = {};
42
+ for (const field of workflow.inputs) {
43
+ const value = inputs[field.name];
44
+ if (field.type === "number") {
45
+ const blank = value === "" || value === void 0;
46
+ if (blank) {
47
+ if (field.required) errors[field.name] = "required";
48
+ continue;
49
+ }
50
+ const n = Number(value);
51
+ if (Number.isNaN(n)) errors[field.name] = "number";
52
+ else if (field.min !== void 0 && n < field.min) errors[field.name] = "min";
53
+ else if (field.max !== void 0 && n > field.max) errors[field.name] = "max";
54
+ continue;
55
+ }
56
+ if (!field.required) continue;
57
+ if (field.type === "documents") {
58
+ if (!isWorkflowScope(value) || !value.documents?.length) errors[field.name] = "required";
59
+ continue;
60
+ }
61
+ if (field.type === "boolean" || field.type === "scope") continue;
62
+ if (typeof value !== "string" || value.trim() === "") errors[field.name] = "required";
63
+ }
64
+ return errors;
65
+ }
66
+ function promptFieldName(workflow) {
67
+ return workflow.inputs.find((f) => !f.advanced && (f.type === "text" || f.type === "longtext"))?.name;
68
+ }
69
+ var quoteList = (names) => {
70
+ const quoted = names.map((n) => `"${n}"`);
71
+ return quoted.length <= 1 ? quoted[0] ?? "" : `${quoted.slice(0, -1).join(", ")} and ${quoted[quoted.length - 1]}`;
72
+ };
73
+ function fragment(field, value, ctx) {
74
+ switch (field.type) {
75
+ case "documents": {
76
+ const ids = isWorkflowScope(value) ? value.documents ?? [] : [];
77
+ const names = ids.flatMap((id) => {
78
+ const title = ctx?.documentTitles?.[id];
79
+ return title ? [title] : [];
80
+ });
81
+ return quoteList(names);
82
+ }
83
+ case "boolean":
84
+ return value ? field.trueText ?? "yes" : field.falseText ?? "no";
85
+ case "select": {
86
+ const option = field.options?.find((o) => o.value === value);
87
+ return option ? option.text ?? option.label : String(value ?? "");
88
+ }
89
+ case "scope":
90
+ return "";
91
+ default:
92
+ return typeof value === "string" ? value.trim() : String(value ?? "");
93
+ }
94
+ }
95
+ function composeWorkflowPrompt(workflow, inputs, ctx) {
96
+ if (workflow.run.kind !== "prompt") return "";
97
+ const byName = new Map(workflow.inputs.map((f) => [f.name, f]));
98
+ const template = workflow.run.promptTemplate;
99
+ let out = "";
100
+ let last = 0;
101
+ const append = (text, isValue) => {
102
+ let t = text;
103
+ if (!isValue) {
104
+ t = t.replace(/[ \t]{2,}/g, " ");
105
+ if (/[ \t]$/.test(out)) t = t.replace(/^[ \t]+/, "");
106
+ }
107
+ out += t;
108
+ };
109
+ for (const m of template.matchAll(/\{\{\s*([a-z][a-z0-9_]*)\s*\}\}/gi)) {
110
+ append(template.slice(last, m.index), false);
111
+ const field = byName.get(m[1]);
112
+ append(field ? fragment(field, inputs[m[1]], ctx) : "", true);
113
+ last = m.index + m[0].length;
114
+ }
115
+ append(template.slice(last), false);
116
+ return out.trim();
117
+ }
118
+ function buildLaunch(workflow, inputs, agentId) {
119
+ const scopeField = workflow.inputs.find(isFileField);
120
+ const raw = scopeField ? inputs[scopeField.name] : void 0;
121
+ const scope = isWorkflowScope(raw) ? raw : { ...EMPTY_WORKFLOW_SCOPE };
122
+ return { workflow, inputs, scope, agentId: agentId || workflow.defaultAgentId || void 0 };
123
+ }
124
+ function workflowAccepts(workflow) {
125
+ const kinds = /* @__PURE__ */ new Set();
126
+ for (const field of workflow.inputs) if (field.context) kinds.add(field.context);
127
+ return [...kinds];
128
+ }
129
+ function workflowsAccepting(workflows, supplied) {
130
+ return workflows.filter((w) => workflowAccepts(w).some((k) => supplied.includes(k)));
131
+ }
132
+ function workflowsForHost(workflows, host) {
133
+ return workflows.filter((w) => !w.host || w.host === host);
134
+ }
135
+ function inputsFromContext(workflow, context) {
136
+ const inputs = {};
137
+ for (const field of workflow.inputs) {
138
+ if (!field.context) continue;
139
+ if (field.context === "selection") {
140
+ if (context.selection) inputs[field.name] = context.selection;
141
+ continue;
142
+ }
143
+ const ids = field.context === "image" ? context.image ? [context.image] : [] : context.documents;
144
+ if (ids?.length && isFileField(field)) {
145
+ inputs[field.name] = { folders: [], labels: [], documents: ids.slice(0, field.max ?? 1) };
146
+ }
147
+ }
148
+ return inputs;
149
+ }
150
+ var SKILL_PROMPT_LABEL = "What should it work on?";
151
+ var SKILL_PROMPT_FALLBACK_PLACEHOLDER = "Describe what you want";
152
+ var plainHint = (hint) => hint.replace(/^[<[]\s*|\s*[>\]]$/g, "").trim();
153
+ function skillToWorkflow(skill) {
154
+ const hint = plainHint((skill.arg_hint ?? "").trim());
155
+ const inputs = [
156
+ {
157
+ name: "args",
158
+ type: "longtext",
159
+ label: SKILL_PROMPT_LABEL,
160
+ placeholder: hint || SKILL_PROMPT_FALLBACK_PLACEHOLDER,
161
+ required: true
162
+ }
163
+ ];
164
+ return {
165
+ id: skill.slug,
166
+ skill: skill.slug,
167
+ title: skill.name || skill.slug,
168
+ description: skill.description ?? "",
169
+ inputs,
170
+ run: { kind: "prompt", promptTemplate: `/${skill.slug} {{args}}` },
171
+ landing: "chat",
172
+ schedulable: true
173
+ };
174
+ }
175
+ var FIELD_TYPES = [
176
+ "text",
177
+ "longtext",
178
+ "boolean",
179
+ "select",
180
+ "number",
181
+ "date",
182
+ "scope",
183
+ "documents"
184
+ ];
185
+ var str = (v) => typeof v === "string" ? v : void 0;
186
+ var num = (v) => typeof v === "number" ? v : void 0;
187
+ var bool = (v) => typeof v === "boolean" ? v : void 0;
188
+ function fieldFromFrontmatter(raw) {
189
+ if (typeof raw !== "object" || raw === null) return null;
190
+ const r = raw;
191
+ const name = str(r.name);
192
+ const type = FIELD_TYPES.find((t) => t === r.type);
193
+ if (!name || !/^[a-z][a-z0-9_]*$/.test(name) || !type) return null;
194
+ const options = Array.isArray(r.options) ? r.options.flatMap((o) => {
195
+ const ro = o;
196
+ const value = str(ro?.value);
197
+ const label = str(ro?.label);
198
+ return value && label ? [
199
+ {
200
+ value,
201
+ label,
202
+ description: str(ro.description),
203
+ text: str(ro.text),
204
+ icon: str(ro.icon)
205
+ }
206
+ ] : [];
207
+ }) : void 0;
208
+ return {
209
+ name,
210
+ type,
211
+ label: str(r.label) ?? name,
212
+ description: str(r.description),
213
+ placeholder: str(r.placeholder),
214
+ required: bool(r.required),
215
+ default: r.default,
216
+ options,
217
+ min: num(r.min),
218
+ max: num(r.max),
219
+ trueText: str(r.true_text),
220
+ falseText: str(r.false_text),
221
+ advanced: bool(r.advanced),
222
+ accept: r.accept === "image" ? "image" : void 0,
223
+ context: r.context === "documents" || r.context === "selection" || r.context === "image" ? r.context : void 0,
224
+ by: Array.isArray(r.by) ? r.by.filter((b) => b === "folders" || b === "labels") : void 0
225
+ };
226
+ }
227
+ function workflowFromFrontmatter(id, frontmatter, body) {
228
+ const inputs = Array.isArray(frontmatter.inputs) ? frontmatter.inputs.flatMap((f) => {
229
+ const field = fieldFromFrontmatter(f);
230
+ return field ? [field] : [];
231
+ }) : [];
232
+ return {
233
+ id,
234
+ title: str(frontmatter.name) ?? id,
235
+ description: str(frontmatter.description) ?? "",
236
+ icon: str(frontmatter.icon),
237
+ inputs,
238
+ run: { kind: "prompt", promptTemplate: body.trim() },
239
+ landing: frontmatter.landing === "files" ? "files" : "chat",
240
+ requiresFiles: bool(frontmatter.requires_files),
241
+ schedulable: bool(frontmatter.schedulable) ?? true
242
+ };
243
+ }
244
+ function fieldToFrontmatter(field) {
245
+ return compact({
246
+ name: field.name,
247
+ type: field.type,
248
+ label: field.label,
249
+ description: field.description,
250
+ placeholder: field.placeholder,
251
+ required: field.required,
252
+ default: field.default,
253
+ options: field.options?.map(
254
+ (o) => compact({
255
+ value: o.value,
256
+ label: o.label,
257
+ description: o.description,
258
+ text: o.text,
259
+ icon: o.icon
260
+ })
261
+ ),
262
+ min: field.min,
263
+ max: field.max,
264
+ true_text: field.trueText,
265
+ false_text: field.falseText,
266
+ advanced: field.advanced,
267
+ by: field.by,
268
+ accept: field.accept,
269
+ context: field.context
270
+ });
271
+ }
272
+ var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
273
+ var DEFAULT_SCHEMA_FORM_LABELS = {
274
+ optional: "(optional)",
275
+ advanced: "More options",
276
+ errors: {
277
+ required: "This is needed to continue",
278
+ min: "Too small",
279
+ max: "Too large",
280
+ number: "Enter a number"
281
+ }
282
+ };
283
+ var TILE_MAX = 4;
284
+ function FieldControl({
285
+ field,
286
+ value,
287
+ error,
288
+ onChange,
289
+ l,
290
+ idFor,
291
+ renderScope,
292
+ renderDocuments,
293
+ renderIcon,
294
+ onEnterSubmit,
295
+ people
296
+ }) {
297
+ const id = `${idFor()}-control`;
298
+ const testId = idFor();
299
+ switch (field.type) {
300
+ case "text":
301
+ return /* @__PURE__ */ jsxRuntime.jsx(
302
+ ui.Input,
303
+ {
304
+ id,
305
+ "data-testid": testId,
306
+ value: String(value ?? ""),
307
+ placeholder: field.placeholder,
308
+ "aria-required": field.required || void 0,
309
+ "aria-invalid": error ? true : void 0,
310
+ "aria-describedby": error ? idFor("error") : void 0,
311
+ onChange: (e) => onChange(e.target.value)
312
+ }
313
+ );
314
+ case "longtext":
315
+ return /* @__PURE__ */ jsxRuntime.jsx(
316
+ ui.Textarea,
317
+ {
318
+ id,
319
+ "data-testid": testId,
320
+ value: String(value ?? ""),
321
+ placeholder: field.placeholder,
322
+ "aria-required": field.required || void 0,
323
+ "aria-invalid": error ? true : void 0,
324
+ "aria-describedby": error ? idFor("error") : void 0,
325
+ className: "min-h-[96px]",
326
+ onChange: (e) => onChange(e.target.value),
327
+ onKeyDown: (e) => {
328
+ if (onEnterSubmit && e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
329
+ e.preventDefault();
330
+ onEnterSubmit();
331
+ }
332
+ }
333
+ }
334
+ );
335
+ case "number":
336
+ return /* @__PURE__ */ jsxRuntime.jsx(
337
+ ui.Input,
338
+ {
339
+ id,
340
+ "data-testid": testId,
341
+ type: "number",
342
+ inputMode: "decimal",
343
+ min: field.min,
344
+ max: field.max,
345
+ value: value === void 0 ? "" : String(value),
346
+ placeholder: field.placeholder,
347
+ "aria-invalid": error ? true : void 0,
348
+ "aria-describedby": error ? idFor("error") : void 0,
349
+ onChange: (e) => onChange(e.target.value === "" ? "" : Number(e.target.value))
350
+ }
351
+ );
352
+ case "date":
353
+ return /* @__PURE__ */ jsxRuntime.jsx(
354
+ ui.Input,
355
+ {
356
+ id,
357
+ "data-testid": testId,
358
+ type: "date",
359
+ value: String(value ?? ""),
360
+ "aria-invalid": error ? true : void 0,
361
+ "aria-describedby": error ? idFor("error") : void 0,
362
+ onChange: (e) => onChange(e.target.value)
363
+ }
364
+ );
365
+ case "boolean":
366
+ return /* @__PURE__ */ jsxRuntime.jsx(
367
+ ui.Switch,
368
+ {
369
+ id,
370
+ "data-testid": testId,
371
+ checked: Boolean(value),
372
+ onCheckedChange: (checked) => onChange(checked)
373
+ }
374
+ );
375
+ case "select": {
376
+ const options = field.options ?? [];
377
+ if (options.length > 0 && options.length <= TILE_MAX) {
378
+ return /* @__PURE__ */ jsxRuntime.jsx(
379
+ "div",
380
+ {
381
+ role: "radiogroup",
382
+ "aria-label": field.label,
383
+ className: "grid grid-cols-2 gap-2 sm:grid-cols-4",
384
+ "data-testid": testId,
385
+ children: options.map((option) => {
386
+ const selected = value === option.value;
387
+ return /* @__PURE__ */ jsxRuntime.jsxs(
388
+ "button",
389
+ {
390
+ type: "button",
391
+ role: "radio",
392
+ "aria-checked": selected,
393
+ "data-testid": chunkMHVNT4J3_cjs.prefixedTestId(testId, option.value, {
394
+ testId: `workflow-field-${field.name}-${option.value}`
395
+ }),
396
+ onClick: () => {
397
+ onChange(option.value);
398
+ },
399
+ className: ui.cn(
400
+ "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",
401
+ selected ? "border-primary bg-primary/10" : "border-border bg-card [&:hover]:border-primary [&:hover]:bg-muted"
402
+ ),
403
+ children: [
404
+ option.icon && renderIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: renderIcon(option.icon) }),
405
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: option.label }),
406
+ option.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: option.description })
407
+ ]
408
+ },
409
+ option.value
410
+ );
411
+ })
412
+ }
413
+ );
414
+ }
415
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: String(value ?? ""), onValueChange: (v) => onChange(v), children: [
416
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectTrigger, { id, "data-testid": testId, className: "pointer-coarse:min-h-11", children: /* @__PURE__ */ jsxRuntime.jsx(ui.SelectValue, { placeholder: field.placeholder }) }),
417
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectContent, { children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: o.value, children: o.label }, o.value)) })
418
+ ] });
419
+ }
420
+ case "scope": {
421
+ const scope = isWorkflowScope(value) ? value : { folders: [], labels: [] };
422
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderScope?.(field, scope, onChange) });
423
+ }
424
+ case "documents": {
425
+ const picked = isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
426
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
427
+ }
428
+ case "person":
429
+ return people?.length ? /* @__PURE__ */ jsxRuntime.jsxs(
430
+ "select",
431
+ {
432
+ id,
433
+ "data-testid": testId,
434
+ value: String(value ?? ""),
435
+ "aria-required": field.required || void 0,
436
+ "aria-invalid": error ? true : void 0,
437
+ onChange: (e) => onChange(e.target.value),
438
+ className: "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm",
439
+ children: [
440
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder ?? "" }),
441
+ people.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
442
+ ]
443
+ }
444
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
445
+ ui.Input,
446
+ {
447
+ id,
448
+ "data-testid": testId,
449
+ value: String(value ?? ""),
450
+ placeholder: field.placeholder ?? "usr-\u2026",
451
+ "aria-required": field.required || void 0,
452
+ "aria-invalid": error ? true : void 0,
453
+ onChange: (e) => onChange(e.target.value)
454
+ }
455
+ );
456
+ }
457
+ }
458
+ function FormField(props) {
459
+ const { field, error, l, idFor } = props;
460
+ const isBoolean = field.type === "boolean";
461
+ const showOptional = !field.required && field.type !== "boolean" && field.type !== "scope";
462
+ const label = /* @__PURE__ */ jsxRuntime.jsxs(
463
+ ui.Label,
464
+ {
465
+ htmlFor: `${idFor()}-control`,
466
+ className: isBoolean ? "cursor-pointer font-normal" : void 0,
467
+ children: [
468
+ field.label,
469
+ showOptional && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
470
+ " ",
471
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-normal text-muted-foreground", children: l.optional })
472
+ ] })
473
+ ]
474
+ }
475
+ );
476
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", "data-slot": "schema-field", "data-field": field.name, children: [
477
+ isBoolean ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 pointer-coarse:min-h-11", children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx(FieldControl, { ...props }),
479
+ label
480
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
481
+ field.type !== "scope" && label,
482
+ /* @__PURE__ */ jsxRuntime.jsx(FieldControl, { ...props })
483
+ ] }),
484
+ field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: field.description }),
485
+ error && /* @__PURE__ */ jsxRuntime.jsx(
486
+ "p",
487
+ {
488
+ id: idFor("error"),
489
+ role: "alert",
490
+ className: "text-xs text-destructive",
491
+ "data-testid": idFor("error"),
492
+ children: l.errors[error]
493
+ }
494
+ )
495
+ ] });
496
+ }
497
+ function SchemaForm({
498
+ fields,
499
+ values,
500
+ onChange,
501
+ errors,
502
+ renderScope,
503
+ renderDocuments,
504
+ renderIcon,
505
+ onEnterSubmit,
506
+ people,
507
+ testIdPrefix,
508
+ labels,
509
+ className
510
+ }) {
511
+ const l = {
512
+ ...DEFAULT_SCHEMA_FORM_LABELS,
513
+ ...labels,
514
+ errors: { ...DEFAULT_SCHEMA_FORM_LABELS.errors, ...labels?.errors }
515
+ };
516
+ const [advancedOpen, setAdvancedOpen] = react.useState(false);
517
+ const common = fields.filter((f) => !f.advanced);
518
+ const advanced = fields.filter((f) => f.advanced);
519
+ const render = (field) => /* @__PURE__ */ jsxRuntime.jsx(
520
+ FormField,
521
+ {
522
+ field,
523
+ value: values[field.name],
524
+ error: errors?.[field.name],
525
+ onChange: (v) => onChange(field.name, v),
526
+ l,
527
+ idFor: (suffix) => suffix ? `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}-${suffix}` : `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-${field.name}`,
528
+ renderScope,
529
+ renderDocuments,
530
+ renderIcon,
531
+ onEnterSubmit,
532
+ people
533
+ },
534
+ field.name
535
+ );
536
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-4", className), "data-slot": "schema-form", children: [
537
+ common.map(render),
538
+ advanced.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
539
+ chunk7D737FLE_cjs.FoldSection,
540
+ {
541
+ label: l.advanced,
542
+ open: advancedOpen,
543
+ onOpenChange: setAdvancedOpen,
544
+ testId: `${chunkMHVNT4J3_cjs.testIdOr(testIdPrefix, { testId: "workflow-field" })}-advanced-toggle`,
545
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: advanced.map(render) })
546
+ }
547
+ )
548
+ ] });
549
+ }
550
+
551
+ // src/agents/workflows/run.ts
552
+ function workflowSteps(workflow) {
553
+ return workflow.run.kind === "steps" ? workflow.run.steps : [];
554
+ }
555
+ var isSteppedWorkflow = (workflow) => workflow.run.kind === "steps";
556
+ function stepDependencies(steps, id) {
557
+ const i = steps.findIndex((s) => s.id === id);
558
+ if (i < 0) return [];
559
+ return steps[i].after ?? (i > 0 ? [steps[i - 1].id] : []);
560
+ }
561
+ function dependsOn(steps, a, b) {
562
+ const seen = /* @__PURE__ */ new Set();
563
+ const stack = [...stepDependencies(steps, a)];
564
+ while (stack.length) {
565
+ const id = stack.pop();
566
+ if (id === b) return true;
567
+ if (seen.has(id)) continue;
568
+ seen.add(id);
569
+ stack.push(...stepDependencies(steps, id));
570
+ }
571
+ return false;
572
+ }
573
+ function orderSteps(steps) {
574
+ const explicit = steps.map((s) => ({ ...s, after: stepDependencies(steps, s.id) }));
575
+ const known = new Set(explicit.map((s) => s.id));
576
+ const placed = /* @__PURE__ */ new Set();
577
+ const out = [];
578
+ let progress = true;
579
+ while (out.length < explicit.length && progress) {
580
+ progress = false;
581
+ for (const s of explicit) {
582
+ if (placed.has(s.id)) continue;
583
+ if (s.after.every((d) => placed.has(d) || !known.has(d))) {
584
+ out.push(s);
585
+ placed.add(s.id);
586
+ progress = true;
587
+ break;
588
+ }
589
+ }
590
+ }
591
+ return [...out, ...explicit.filter((s) => !placed.has(s.id))];
592
+ }
593
+ function validateWorkflowGraph(steps) {
594
+ const problems = [];
595
+ const ids = /* @__PURE__ */ new Set();
596
+ for (const s of steps) {
597
+ if (ids.has(s.id)) problems.push({ code: "duplicate", step: s.id });
598
+ ids.add(s.id);
599
+ }
600
+ steps.forEach((s, i) => {
601
+ for (const d of stepDependencies(steps, s.id)) {
602
+ if (!ids.has(d)) problems.push({ code: "unknown", step: s.id, dependency: d });
603
+ else if (d === s.id || dependsOn(steps, d, s.id)) problems.push({ code: "cycle", step: s.id });
604
+ else if (steps.findIndex((x) => x.id === d) > i)
605
+ problems.push({ code: "order", step: s.id, dependency: d });
606
+ }
607
+ });
608
+ return problems;
609
+ }
610
+ function stepLevels(steps) {
611
+ const depth = /* @__PURE__ */ new Map();
612
+ for (const s of steps) {
613
+ const deps = stepDependencies(steps, s.id).filter((d) => depth.has(d));
614
+ depth.set(s.id, deps.length ? Math.max(...deps.map((d) => depth.get(d))) + 1 : 0);
615
+ }
616
+ const levels = [];
617
+ for (const s of steps) (levels[depth.get(s.id)] ??= []).push(s);
618
+ return levels.filter(Boolean);
619
+ }
620
+ var STEP_EVENTS = {
621
+ step_started: "running",
622
+ step_waiting: "waiting",
623
+ step_done: "done",
624
+ step_skipped: "skipped",
625
+ step_failed: "failed"
626
+ };
627
+ var str2 = (v) => typeof v === "string" && v ? v : void 0;
628
+ var ACTION_TYPES = ["sign", "email_draft", "tabular_review"];
629
+ var asAction = (v) => ACTION_TYPES.includes(v) ? v : void 0;
630
+ var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
631
+ var asStrings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : void 0;
632
+ function reopenedBy(detail) {
633
+ const to = str2(detail.to);
634
+ return asStrings(detail.reopened) ?? (to ? [to] : []);
635
+ }
636
+ function stepStatesFromActivity(events) {
637
+ const states = {};
638
+ for (const e of events) {
639
+ const detail = e.detail ?? {};
640
+ const step = str2(detail.step);
641
+ if (!step) continue;
642
+ if (e.kind === "step_sent_back") {
643
+ const to = str2(detail.to);
644
+ for (const id of reopenedBy(detail))
645
+ states[id] = id === to ? {
646
+ status: "pending",
647
+ sentBack: true,
648
+ hasNote: typeof detail.note_encrypted === "string"
649
+ } : { status: "pending" };
650
+ continue;
651
+ }
652
+ if (e.kind === "step_ready") {
653
+ states[step] = { ...states[step] ?? { status: "pending" }, announcedTo: str2(detail.to) };
654
+ continue;
655
+ }
656
+ if (e.kind === "step_progress") {
657
+ const before2 = states[step];
658
+ const waiting2 = asRecord(detail.waiting);
659
+ if (before2?.status === "waiting" && waiting2) states[step] = { ...before2, waiting: waiting2 };
660
+ continue;
661
+ }
662
+ const status = STEP_EVENTS[e.kind];
663
+ if (!status) continue;
664
+ const before = states[step];
665
+ const responseId = str2(detail.response_id) ?? before?.responseId ?? null;
666
+ const startedAt = status === "running" ? e.created_at : before?.startedAt;
667
+ const action = asAction(detail.action) ?? before?.action;
668
+ const documents = asStrings(detail.documents) ?? before?.documents;
669
+ const waiting = status === "waiting" ? asRecord(detail.waiting) : void 0;
670
+ const output = status === "done" ? asRecord(detail.output) : void 0;
671
+ const approved = Array.isArray(detail.approved) ? detail.approved.filter(asRecord) : void 0;
672
+ const finished2 = status === "done" || status === "skipped" || status === "failed";
673
+ const declinedBy = str2(detail.declined_by);
674
+ states[step] = {
675
+ status,
676
+ responseId,
677
+ error: str2(detail.error) ?? null,
678
+ ...startedAt ? { startedAt } : {},
679
+ ...action ? { action } : {},
680
+ ...documents?.length ? { documents } : {},
681
+ ...waiting ? { waiting } : {},
682
+ ...output ? { output } : {},
683
+ ...approved ? { approved } : {},
684
+ ...finished2 ? { by: e.actor_ext_id ?? null } : {},
685
+ ...finished2 && e.created_at ? { at: e.created_at } : {},
686
+ ...declinedBy ? { declinedBy } : {}
687
+ };
688
+ }
689
+ return states;
690
+ }
691
+ function stepFields(step) {
692
+ return step.kind === "form" ? step.inputs : step.kind === "review" ? step.fields ?? [] : [];
693
+ }
694
+ var runFieldsOf = (steps) => steps.flatMap(stepFields);
695
+ function runFields(workflow) {
696
+ return [...workflow.inputs, ...workflowSteps(workflow).flatMap(stepFields)];
697
+ }
698
+ function initialRunInputs(workflow, inputs = {}) {
699
+ return { ...defaultInputs({ ...workflow, inputs: runFields(workflow) }), ...inputs };
700
+ }
701
+ var finished = (s) => s?.status === "done" || s?.status === "skipped";
702
+ function stepPhase(steps, states, id) {
703
+ const s = states[id];
704
+ if (s && s.status !== "pending") return s.status;
705
+ return stepDependencies(steps, id).every((d) => finished(states[d])) ? "ready" : "blocked";
706
+ }
707
+ var isRunFinished = (steps, states) => steps.length > 0 && steps.every((s) => finished(states[s.id]));
708
+ var isPersonStep = (step) => step.kind !== "agent" && step.kind !== "action";
709
+ var isPersonAction = (step) => step.kind === "action" && (step.action.type === "sign" || step.action.type === "email_draft");
710
+ var canAssign = (step) => isPersonStep(step) || isPersonAction(step);
711
+ function nextAction(steps, states, current) {
712
+ const i = steps.findIndex((s) => s.id === current);
713
+ const step = steps[i];
714
+ if (!step) return "wait";
715
+ const phase = stepPhase(steps, states, step.id);
716
+ if (phase === "blocked") return "wait";
717
+ const following = steps[i + 1];
718
+ const independentNext = !!following && !dependsOn(steps, following.id, step.id);
719
+ if (phase === "done" || phase === "skipped") {
720
+ if (following) return "move";
721
+ return isRunFinished(steps, states) ? "finish" : "wait";
722
+ }
723
+ if (isPersonStep(step)) return "complete";
724
+ if (phase === "waiting" && step.kind === "action" && step.action.type === "email_draft")
725
+ return "complete";
726
+ if (phase !== "failed") return independentNext ? "move" : "wait";
727
+ const waitedFor = steps.slice(i + 1).some((s) => dependsOn(steps, s.id, step.id));
728
+ return waitedFor || !following ? "skip" : "move";
729
+ }
730
+ function validateStep(step, inputs) {
731
+ const fields = stepFields(step);
732
+ if (!fields.length) return {};
733
+ return validateInputs(
734
+ {
735
+ id: step.id,
736
+ title: step.title,
737
+ inputs: fields},
738
+ inputs
739
+ );
740
+ }
741
+ function upstreamSteps(steps, id) {
742
+ return steps.filter((s) => s.id !== id && dependsOn(steps, id, s.id));
743
+ }
744
+ function sendBackTargets(steps, states, id) {
745
+ return upstreamSteps(steps, id).filter((s) => ["done", "skipped", "failed"].includes(states[s.id]?.status ?? "pending")).reverse();
746
+ }
747
+ var isBlankRef = (ref) => "step" in ref ? !ref.step : "input" in ref ? !ref.input : !ref.id.trim();
748
+ function stepConfigProblems(steps) {
749
+ const out = [];
750
+ for (const s of steps) {
751
+ if (s.kind === "action") {
752
+ const a = s.action;
753
+ if (a.type === "sign") {
754
+ if (!a.document || isBlankRef(a.document)) out.push({ step: s.id, missing: "document" });
755
+ if (!a.signers.length) out.push({ step: s.id, missing: "signers" });
756
+ } else if (a.type === "email_draft") {
757
+ if (!a.to.some((t) => t.trim())) out.push({ step: s.id, missing: "recipients" });
758
+ } else {
759
+ if (!a.tags.length) out.push({ step: s.id, missing: "tags" });
760
+ if (Array.isArray(a.documents) && !a.documents.length)
761
+ out.push({ step: s.id, missing: "documents" });
762
+ }
763
+ }
764
+ if (s.kind === "agent" && s.editDocument && isBlankRef(s.editDocument))
765
+ out.push({ step: s.id, missing: "document" });
766
+ }
767
+ return out;
768
+ }
769
+ function splitDocRef(ref) {
770
+ const m = /^(doc-[A-Za-z0-9]+)(?:@v(\d+))?$/.exec(ref);
771
+ return m ? { id: m[1], ...m[2] ? { version: Number(m[2]) } : {} } : { id: ref };
772
+ }
773
+ var DEFAULT_ASSIGNEE_WORDING = {
774
+ runOwner: "whoever started the run",
775
+ projectLead: "the project lead",
776
+ input: "the person in \u201C{field}\u201D"
777
+ };
778
+ function assigneeName(assignee, options = {}) {
779
+ const w = { ...DEFAULT_ASSIGNEE_WORDING, ...options.wording };
780
+ const name = (id) => options.nameOf?.(id) ?? id;
781
+ const told = options.announcedTo ? options.nameOf?.(options.announcedTo) : void 0;
782
+ if (told) return told;
783
+ if (!assignee) return void 0;
784
+ if ("user" in assignee) return name(assignee.user);
785
+ if ("input" in assignee) {
786
+ const value = options.inputs?.[assignee.input];
787
+ if (typeof value === "string" && value) return name(value);
788
+ const label = options.fields?.find((f) => f.name === assignee.input)?.label ?? assignee.input;
789
+ return w.input.replace("{field}", label);
790
+ }
791
+ if ("runOwner" in assignee) return w.runOwner;
792
+ return w.projectLead;
793
+ }
794
+ var asText = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
795
+ function fillStepInputs(templates, inputs) {
796
+ const out = {};
797
+ for (const [name, template] of Object.entries(templates ?? {})) {
798
+ const bare = /^\{\{\s*([a-z][a-z0-9_]*)\s*\}\}$/i.exec(template);
799
+ if (bare) {
800
+ out[name] = inputs[bare[1]] ?? "";
801
+ continue;
802
+ }
803
+ out[name] = fillRunText(template, inputs);
804
+ }
805
+ return out;
806
+ }
807
+ function fillRunText(template, inputs) {
808
+ return template.replace(/\{\{([^}]*)\}\}/g, (_, expr) => {
809
+ for (const ref of expr.split("||")) {
810
+ const text = asText(inputs[ref.trim()]);
811
+ if (text) return text;
812
+ }
813
+ return "";
814
+ }).trim();
815
+ }
816
+ function runThreadTitle(workflow, inputs) {
817
+ const template = workflow.run.kind === "steps" ? workflow.run.threadTitle : void 0;
818
+ return template && fillRunText(template, inputs) || workflow.title;
819
+ }
820
+ function reviewInstructions(step, inputs) {
821
+ return step.instructions && fillRunText(step.instructions, inputs) || step.title;
822
+ }
823
+ function composeStepPrompt(workflow, step, runInputs, { resolveWorkflow, compose } = {}) {
824
+ if (step.workflow) {
825
+ const target = resolveWorkflow?.(step.workflow);
826
+ if (!target) return "";
827
+ const inputs = { ...defaultInputs(target), ...fillStepInputs(step.with, runInputs) };
828
+ return target.run.kind === "prompt" ? composeWorkflowPrompt(target, inputs) : compose?.(target.id, inputs, runInputs) ?? "";
829
+ }
830
+ if (step.run?.kind === "prompt") {
831
+ return composeWorkflowPrompt(
832
+ { ...workflow, inputs: runFields(workflow), run: step.run },
833
+ runInputs
834
+ );
835
+ }
836
+ return compose?.(step.id, runInputs, runInputs) ?? "";
837
+ }
838
+
839
+ // src/agents/workflows/planSteps.ts
840
+ function toPlanAssignee(a) {
841
+ if ("user" in a) return { user: a.user };
842
+ if ("input" in a) return { input: a.input };
843
+ if ("runOwner" in a) return { run_owner: true };
844
+ return { project_lead: true };
845
+ }
846
+ function fromPlanAssignee(a) {
847
+ if (!a) return void 0;
848
+ if (a.user) return { user: a.user };
849
+ if (a.input) return { input: a.input };
850
+ if (a.run_owner) return { runOwner: true };
851
+ if (a.project_lead) return { projectLead: true };
852
+ return void 0;
853
+ }
854
+ function toPlanDocumentRef(ref) {
855
+ if ("step" in ref) return { step: ref.step };
856
+ if ("input" in ref) return { input: ref.input };
857
+ return ref.id.trim();
858
+ }
859
+ function fromPlanDocumentRef(ref) {
860
+ if (!ref) return void 0;
861
+ if (typeof ref === "string") return { id: ref };
862
+ if (ref.step) return { step: ref.step };
863
+ if (ref.input) return { input: ref.input };
864
+ return void 0;
865
+ }
866
+ var docRefs = (refs) => (refs ?? []).map(toPlanDocumentRef);
867
+ var fromDocRefs = (refs) => (refs ?? []).flatMap((r) => {
868
+ const ref = fromPlanDocumentRef(r);
869
+ return ref ? [ref] : [];
870
+ });
871
+ function toPlanAction(a) {
872
+ switch (a.type) {
873
+ case "sign":
874
+ return {
875
+ type: "sign",
876
+ // The builder may hold a signature step whose document is not chosen yet: the server
877
+ // refuses it, and the builder says so before saving (`stepConfigProblems`).
878
+ document: a.document ? toPlanDocumentRef(a.document) : "",
879
+ signers: a.signers.map(toPlanAssignee),
880
+ ...a.message?.trim() ? { message: a.message.trim() } : {},
881
+ ...a.expiresAfterHours ? { expires_after_hours: a.expiresAfterHours } : {}
882
+ };
883
+ case "email_draft":
884
+ return {
885
+ type: "email_draft",
886
+ to: a.to.map((t) => t.trim()).filter(Boolean),
887
+ cc: (a.cc ?? []).map((t) => t.trim()).filter(Boolean),
888
+ subject: a.subject,
889
+ body_template: a.body,
890
+ attachments: docRefs(a.attachments)
891
+ };
892
+ case "tabular_review":
893
+ return {
894
+ type: "tabular_review",
895
+ tags: a.tags,
896
+ documents: Array.isArray(a.documents) ? docRefs(a.documents) : a.documents,
897
+ overwrite: !!a.overwrite
898
+ };
899
+ }
900
+ }
901
+ function fromPlanAction(a) {
902
+ switch (a?.type) {
903
+ case "sign":
904
+ return {
905
+ type: "sign",
906
+ document: fromPlanDocumentRef(a.document),
907
+ signers: (a.signers ?? []).flatMap((s) => {
908
+ const one = fromPlanAssignee(s);
909
+ return one ? [one] : [];
910
+ }),
911
+ ...a.message ? { message: a.message } : {},
912
+ ...a.expires_after_hours ? { expiresAfterHours: a.expires_after_hours } : {}
913
+ };
914
+ case "email_draft":
915
+ return {
916
+ type: "email_draft",
917
+ to: a.to ?? [],
918
+ ...a.cc?.length ? { cc: a.cc } : {},
919
+ subject: a.subject ?? "",
920
+ body: a.body_template ?? "",
921
+ ...a.attachments?.length ? { attachments: fromDocRefs(a.attachments) } : {}
922
+ };
923
+ case "tabular_review":
924
+ return {
925
+ type: "tabular_review",
926
+ tags: a.tags ?? [],
927
+ documents: Array.isArray(a.documents) ? fromDocRefs(a.documents) : a.documents ?? "run_uploads",
928
+ ...a.overwrite ? { overwrite: true } : {}
929
+ };
930
+ default:
931
+ return { type: "tabular_review", tags: [], documents: "run_uploads" };
932
+ }
933
+ }
934
+ function toStepField(f) {
935
+ return {
936
+ name: f.name,
937
+ type: f.type,
938
+ label: f.label,
939
+ required: !!f.required,
940
+ ...f.options ? { options: f.options.map((o) => ({ value: o.value, label: o.label })) } : {},
941
+ ...f.min !== void 0 ? { min: f.min } : {},
942
+ ...f.max !== void 0 ? { max: f.max } : {}
943
+ };
944
+ }
945
+ var compact2 = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== ""));
946
+ function placeholders(workflow) {
947
+ return Object.fromEntries(runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
948
+ }
949
+ function agentStep(workflow, step, options) {
950
+ const target = step.workflow ? options.resolveWorkflow?.(step.workflow) : void 0;
951
+ if (target?.skill) return { skill: target.skill, inputs: step.with ?? {}, prompt: null };
952
+ const given = Object.entries(options.inputs ?? {}).filter(
953
+ ([, v]) => v !== void 0 && v !== null && v !== ""
954
+ );
955
+ const inputs = { ...placeholders(workflow), ...Object.fromEntries(given) };
956
+ return { skill: null, inputs: null, prompt: composeStepPrompt(workflow, step, inputs, options) };
957
+ }
958
+ function toPlanSteps(workflow, options = {}) {
959
+ const layout = workflow.run.kind === "steps" ? workflow.run.layout : void 0;
960
+ return workflowSteps(workflow).map((step) => {
961
+ const ui = compact2({
962
+ description: step.description,
963
+ icon: step.icon,
964
+ commit: step.commit,
965
+ next_label: step.nextLabel,
966
+ position: layout?.[step.id],
967
+ ...step.kind === "form" ? { fields: step.inputs } : {},
968
+ ...step.kind === "upload" ? { required: step.required, accept: step.accept, hint: step.hint } : {},
969
+ ...step.kind === "review" ? { instructions: step.instructions, fields: step.fields?.length ? step.fields : void 0 } : {},
970
+ ...step.kind === "agent" ? {
971
+ output: step.output,
972
+ workflow: step.workflow,
973
+ with: step.with,
974
+ prompt_template: step.run?.kind === "prompt" ? step.run.promptTemplate : void 0
975
+ } : {}
976
+ });
977
+ return {
978
+ id: step.id,
979
+ title: step.title,
980
+ kind: step.kind,
981
+ after: step.after ?? null,
982
+ branch: step.kind === "agent" && !!step.branch,
983
+ requires_files: false,
984
+ ui,
985
+ // An unfinished signal (still being typed) is not saved: the server would refuse it.
986
+ ...step.signals?.some((s) => !isIncompleteSignal(s)) ? { signals: step.signals.filter((s) => !isIncompleteSignal(s)).map(toPlanSignal) } : {},
987
+ ...step.assignee && canAssign(step) ? { assignee: toPlanAssignee(step.assignee) } : {},
988
+ ...step.remindAfterHours && canAssign(step) ? { remind_after_hours: step.remindAfterHours } : {},
989
+ // A review's fields are what approving it is checked against (the server's `fields`).
990
+ ...step.kind === "review" && step.fields?.length ? { fields: step.fields.map(toStepField) } : {},
991
+ ...step.kind === "action" ? { action: toPlanAction(step.action) } : {},
992
+ ...step.kind === "agent" && step.editDocument && !step.branch ? { edit_document: toPlanDocumentRef(step.editDocument) } : {},
993
+ ...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
994
+ };
995
+ });
996
+ }
997
+ function toPlanSignal(signal) {
998
+ return signal.when ? { name: signal.name, when: signal.when } : { name: signal.name };
999
+ }
1000
+ function isIncompleteSignal(signal) {
1001
+ const when = signal.when;
1002
+ if (!signal.name.trim()) return true;
1003
+ if (!when) return false;
1004
+ if ("field" in when) return !when.field || String(when.equals).trim() === "";
1005
+ if ("contains" in when) return !when.contains.trim();
1006
+ if ("matches" in when) return !when.matches.trim();
1007
+ return false;
1008
+ }
1009
+ function fromPlanSignal(signal) {
1010
+ const w = signal.when;
1011
+ const when = w?.field != null && w.equals != null ? { field: w.field, equals: w.equals } : w?.contains != null ? { contains: w.contains } : w?.matches != null ? { matches: w.matches } : w?.approved ? { approved: true } : void 0;
1012
+ return when ? { name: signal.name, when } : { name: signal.name };
1013
+ }
1014
+ function fromPlanSteps(steps) {
1015
+ return (steps ?? []).map((p) => {
1016
+ const ui = p.ui ?? {};
1017
+ const base = {
1018
+ id: p.id,
1019
+ title: p.title,
1020
+ description: ui.description,
1021
+ icon: ui.icon,
1022
+ commit: ui.commit,
1023
+ nextLabel: ui.next_label,
1024
+ ...p.after != null ? { after: p.after } : {},
1025
+ ...p.signals?.length ? { signals: p.signals.map(fromPlanSignal) } : {},
1026
+ ...fromPlanAssignee(p.assignee) ? { assignee: fromPlanAssignee(p.assignee) } : {},
1027
+ ...p.remind_after_hours ? { remindAfterHours: p.remind_after_hours } : {}
1028
+ };
1029
+ switch (p.kind) {
1030
+ case "form":
1031
+ return { ...base, kind: "form", inputs: ui.fields ?? [] };
1032
+ case "upload":
1033
+ return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
1034
+ case "review":
1035
+ return {
1036
+ ...base,
1037
+ kind: "review",
1038
+ instructions: ui.instructions,
1039
+ // The client's copy of the fields (labels, options) when it kept one, else the plan's.
1040
+ ...ui.fields?.length ? { fields: ui.fields } : p.fields?.length ? { fields: p.fields.map(fromStepField) } : {}
1041
+ };
1042
+ case "action":
1043
+ return { ...base, kind: "action", action: fromPlanAction(p.action) };
1044
+ default: {
1045
+ const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
1046
+ return {
1047
+ ...base,
1048
+ kind: "agent",
1049
+ workflow: ui.workflow ?? p.skill ?? void 0,
1050
+ with: ui.with ?? p.inputs ?? void 0,
1051
+ run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
1052
+ output: ui.output,
1053
+ branch: p.branch || void 0,
1054
+ ...fromPlanDocumentRef(p.edit_document) ? { editDocument: fromPlanDocumentRef(p.edit_document) } : {}
1055
+ };
1056
+ }
1057
+ }
1058
+ });
1059
+ }
1060
+ function layoutFromPlanSteps(steps) {
1061
+ const entries = (steps ?? []).flatMap((p) => {
1062
+ const position = p.ui?.position;
1063
+ return position ? [[p.id, position]] : [];
1064
+ });
1065
+ return entries.length ? Object.fromEntries(entries) : void 0;
1066
+ }
1067
+ var FIELD_TYPES2 = /* @__PURE__ */ new Set([
1068
+ "text",
1069
+ "longtext",
1070
+ "boolean",
1071
+ "select",
1072
+ "number",
1073
+ "date",
1074
+ "scope",
1075
+ "documents",
1076
+ "person"
1077
+ ]);
1078
+ function fromStepField(f) {
1079
+ return {
1080
+ name: f.name,
1081
+ type: FIELD_TYPES2.has(f.type) ? f.type : "text",
1082
+ label: f.label ?? f.name,
1083
+ ...f.required ? { required: true } : {},
1084
+ ...f.options?.length ? { options: f.options.map((o) => ({ value: o.value, label: o.label ?? o.value })) } : {},
1085
+ ...f.min != null ? { min: f.min } : {},
1086
+ ...f.max != null ? { max: f.max } : {}
1087
+ };
1088
+ }
1089
+ var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
1090
+ function firstOpen(steps, states) {
1091
+ const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
1092
+ return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
1093
+ }
1094
+ function useWorkflowView(options) {
1095
+ const { steps, states, inputs, setInput, loaded = true } = options;
1096
+ const [current, setCurrent] = react.useState(() => firstOpen(steps, states));
1097
+ const [showErrors, setShowErrors] = react.useState(false);
1098
+ const [busy, setBusy] = react.useState(false);
1099
+ const [actionError, setActionError] = react.useState(null);
1100
+ const optionsRef = react.useRef(options);
1101
+ optionsRef.current = options;
1102
+ const placed = react.useRef(steps.length > 0 && loaded);
1103
+ react.useEffect(() => {
1104
+ if (placed.current || steps.length === 0 || !loaded) return;
1105
+ placed.current = true;
1106
+ setCurrent(firstOpen(steps, states));
1107
+ }, [steps, states, loaded]);
1108
+ const step = steps.find((s) => s.id === current);
1109
+ const following = react.useCallback(
1110
+ (id) => {
1111
+ const i = steps.findIndex((s) => s.id === id);
1112
+ return steps[i + 1]?.id ?? null;
1113
+ },
1114
+ [steps]
1115
+ );
1116
+ const onward = react.useCallback(
1117
+ (id) => {
1118
+ const { steps: s, states: st } = optionsRef.current;
1119
+ const i = s.findIndex((x) => x.id === id);
1120
+ const open = s.slice(i + 1).find((x) => !["done", "skipped"].includes(st[x.id]?.status ?? "pending"));
1121
+ return open?.id ?? following(id);
1122
+ },
1123
+ [following]
1124
+ );
1125
+ const action = busy ? "wait" : nextAction(steps, states, current);
1126
+ const next = react.useCallback(async () => {
1127
+ const { steps: s, states: st, inputs: values } = optionsRef.current;
1128
+ const at = s.find((x) => x.id === current);
1129
+ const act2 = nextAction(s, st, current);
1130
+ if (!at || act2 === "wait" || busy) return;
1131
+ setActionError(null);
1132
+ if (act2 === "finish") return setCurrent(null);
1133
+ if (act2 === "move") return setCurrent(following(current));
1134
+ setBusy(true);
1135
+ try {
1136
+ if (act2 === "skip") {
1137
+ await optionsRef.current.skip(at.id);
1138
+ } else {
1139
+ if (Object.keys(validateStep(at, values)).length > 0) {
1140
+ setShowErrors(true);
1141
+ return;
1142
+ }
1143
+ await optionsRef.current.complete(at);
1144
+ }
1145
+ setShowErrors(false);
1146
+ setCurrent(onward(at.id) ?? current);
1147
+ } catch (e) {
1148
+ setActionError(errorMessage(e));
1149
+ } finally {
1150
+ setBusy(false);
1151
+ }
1152
+ }, [current, busy, following, onward]);
1153
+ const goTo = react.useCallback((stepId) => {
1154
+ setShowErrors(false);
1155
+ setActionError(null);
1156
+ setCurrent(stepId);
1157
+ }, []);
1158
+ const index = steps.findIndex((s) => s.id === current);
1159
+ const back = react.useCallback(() => {
1160
+ const i = steps.findIndex((s) => s.id === current);
1161
+ const to = i < 0 ? steps[steps.length - 1] : steps[i - 1];
1162
+ if (to) goTo(to.id);
1163
+ }, [steps, current, goTo]);
1164
+ const act = react.useCallback(
1165
+ (fn) => fn && (async (stepId) => {
1166
+ setBusy(true);
1167
+ setActionError(null);
1168
+ try {
1169
+ await fn(stepId);
1170
+ } catch (e) {
1171
+ setActionError(errorMessage(e));
1172
+ } finally {
1173
+ setBusy(false);
1174
+ }
1175
+ }),
1176
+ []
1177
+ );
1178
+ const currentRef = react.useRef(current);
1179
+ currentRef.current = current;
1180
+ const skip = react.useMemo(
1181
+ () => act(async (id) => {
1182
+ await optionsRef.current.skip(id);
1183
+ if (currentRef.current !== id) return;
1184
+ setShowErrors(false);
1185
+ setCurrent(onward(id) ?? id);
1186
+ }),
1187
+ [act, onward]
1188
+ );
1189
+ const retry = react.useMemo(
1190
+ () => options.retry ? act((id) => optionsRef.current.retry?.(id) ?? Promise.resolve()) : void 0,
1191
+ // Only whether the host offers retry matters here.
1192
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1193
+ [act, !!options.retry]
1194
+ );
1195
+ const sendBack = react.useMemo(
1196
+ () => options.sendBack ? async (stepId, to, note) => {
1197
+ setBusy(true);
1198
+ setActionError(null);
1199
+ try {
1200
+ await optionsRef.current.sendBack?.(stepId, to, note);
1201
+ setShowErrors(false);
1202
+ setCurrent(to);
1203
+ } catch (e) {
1204
+ setActionError(errorMessage(e));
1205
+ } finally {
1206
+ setBusy(false);
1207
+ }
1208
+ } : void 0,
1209
+ // Only whether the host offers it matters here.
1210
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1211
+ [!!options.sendBack]
1212
+ );
1213
+ const declineWithNote = react.useMemo(
1214
+ () => options.decline ? async (stepId, note) => {
1215
+ setBusy(true);
1216
+ setActionError(null);
1217
+ try {
1218
+ await optionsRef.current.decline?.(stepId, note);
1219
+ } catch (e) {
1220
+ setActionError(errorMessage(e));
1221
+ } finally {
1222
+ setBusy(false);
1223
+ }
1224
+ } : void 0,
1225
+ // Only whether the host offers it matters here.
1226
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1227
+ [!!options.decline]
1228
+ );
1229
+ const isLocked = react.useCallback(
1230
+ (stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
1231
+ []
1232
+ );
1233
+ return {
1234
+ steps,
1235
+ step,
1236
+ current,
1237
+ isComplete: current === null,
1238
+ inputs,
1239
+ setInput,
1240
+ stateOf: (id) => states[id],
1241
+ phaseOf: (id) => stepPhase(steps, states, id),
1242
+ isLocked,
1243
+ errors: showErrors && step && !isLocked(step.id) ? validateStep(step, inputs) : {},
1244
+ busy,
1245
+ actionError,
1246
+ isRunning: Object.values(states).some((s) => s.status === "running"),
1247
+ action,
1248
+ canBack: (current === null || index > 0) && !busy,
1249
+ next,
1250
+ back,
1251
+ goTo,
1252
+ skip,
1253
+ retry,
1254
+ sendBack,
1255
+ decline: declineWithNote,
1256
+ nameOf: options.nameOf,
1257
+ assigneeOf: (id) => {
1258
+ const s = steps.find((x) => x.id === id);
1259
+ if (!s || !canAssign(s)) return void 0;
1260
+ return assigneeName(s.assignee, {
1261
+ nameOf: options.nameOf,
1262
+ inputs,
1263
+ fields: runFieldsOf(steps),
1264
+ announcedTo: states[id]?.announcedTo
1265
+ });
1266
+ },
1267
+ restart: () => {
1268
+ setShowErrors(false);
1269
+ setActionError(null);
1270
+ setCurrent(steps[0]?.id ?? null);
1271
+ }
1272
+ };
1273
+ }
1274
+
1275
+ // src/agents/workflows/stepWindow.ts
1276
+ var ATTENTION = ["waiting", "failed", "ready"];
1277
+ function activeStepId(levels, phaseOf) {
1278
+ const all = levels.flat();
1279
+ for (const phase of ["running", ...ATTENTION]) {
1280
+ const hit = all.find((s) => phaseOf(s.id) === phase);
1281
+ if (hit) return hit.id;
1282
+ }
1283
+ return all[all.length - 1]?.id;
1284
+ }
1285
+ function primaryOf(steps, phaseOf, current) {
1286
+ return steps.find((s) => phaseOf(s.id) === "running") ?? steps.find((s) => s.id === current) ?? ATTENTION.map((p) => steps.find((s) => phaseOf(s.id) === p)).find(Boolean) ?? steps[0];
1287
+ }
1288
+ function stepWindow({
1289
+ levels: raw,
1290
+ phaseOf,
1291
+ current,
1292
+ start: requested,
1293
+ span = 3
1294
+ }) {
1295
+ const levelsIn = raw.filter((l) => l.length > 0);
1296
+ const known = current && levelsIn.some((l) => l.some((s) => s.id === current));
1297
+ const at = known ? current : activeStepId(levelsIn, phaseOf);
1298
+ const currentLevel = Math.max(
1299
+ 0,
1300
+ levelsIn.findIndex((l) => l.some((s) => s.id === at))
1301
+ );
1302
+ const n = levelsIn.length;
1303
+ const size = Math.max(1, Math.min(span, n));
1304
+ const maxStart = Math.max(0, n - size);
1305
+ const auto = currentLevel - (size >= 3 ? 1 : 0);
1306
+ const start = Math.min(maxStart, Math.max(0, requested ?? auto));
1307
+ const end = start + size;
1308
+ const levels = levelsIn.map((steps, index) => {
1309
+ const primary = primaryOf(steps, phaseOf, at);
1310
+ return {
1311
+ index,
1312
+ steps,
1313
+ primary,
1314
+ others: steps.filter((s) => s !== primary),
1315
+ role: index === currentLevel ? "current" : index === currentLevel - 1 ? "previous" : index === currentLevel + 1 ? "next" : "other"
1316
+ };
1317
+ });
1318
+ const visible = levels.slice(start, end);
1319
+ const count = (ls) => ls.reduce((sum, l) => sum + l.steps.length, 0);
1320
+ const shown = new Set(visible.map((l) => l.primary.id));
1321
+ const all = levelsIn.flat();
1322
+ return {
1323
+ levels,
1324
+ visible,
1325
+ start,
1326
+ end,
1327
+ currentLevel,
1328
+ hiddenBefore: count(levels.slice(0, start)),
1329
+ hiddenAfter: count(levels.slice(end)),
1330
+ canBack: start > 0,
1331
+ canForward: end < n,
1332
+ runningHidden: all.filter((s) => phaseOf(s.id) === "running" && !shown.has(s.id)),
1333
+ position: Math.max(1, all.findIndex((s) => s.id === at) + 1),
1334
+ total: all.length
1335
+ };
1336
+ }
1337
+ function PhaseMark({ phase, icon }) {
1338
+ if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 shrink-0" });
1339
+ if (phase === "running") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 shrink-0 animate-spin" });
1340
+ if (phase === "waiting") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hourglass, { className: "size-3.5 shrink-0" });
1341
+ if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3.5 shrink-0" });
1342
+ if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-3.5 shrink-0" });
1343
+ return icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-3.5 shrink-0 items-center justify-center [&_svg]:size-3.5", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 size-1.5 shrink-0 rounded-full bg-current opacity-60" });
1344
+ }
1345
+ var DEFAULT_STEP_BAR_LABELS = {
1346
+ nav: "Workflow steps",
1347
+ back: "Earlier steps",
1348
+ forward: "Later steps",
1349
+ hiddenBefore: "{count} earlier steps: show all steps",
1350
+ hiddenAfter: "{count} later steps: show all steps",
1351
+ position: "Step {position} of {total}",
1352
+ parallel: "{count} more in parallel",
1353
+ inParallel: "In parallel",
1354
+ working: "Working: {title}",
1355
+ moreWorking: "+{count} working",
1356
+ waitingFor: "Waiting for {name}",
1357
+ phases: {
1358
+ blocked: "Not started",
1359
+ ready: "To do",
1360
+ running: "Working",
1361
+ waiting: "Waiting",
1362
+ done: "Done",
1363
+ skipped: "Skipped",
1364
+ failed: "Failed"
1365
+ }
1366
+ };
1367
+ function stepPillTone(phase, current) {
1368
+ if (current) return "border-primary bg-primary/10 text-primary font-semibold shadow-sm";
1369
+ switch (phase) {
1370
+ case "done":
1371
+ return "border-emerald-600/30 text-emerald-700 dark:border-emerald-400/30 dark:text-emerald-400";
1372
+ case "running":
1373
+ return "border-primary/40 bg-primary/5 text-primary";
1374
+ case "waiting":
1375
+ return "border-amber-500/40 text-amber-700 dark:text-amber-300";
1376
+ case "failed":
1377
+ return "border-destructive/40 text-destructive";
1378
+ case "skipped":
1379
+ return "border-border text-muted-foreground line-through decoration-1";
1380
+ case "ready":
1381
+ return "border-border text-foreground";
1382
+ default:
1383
+ return "border-dashed border-border text-muted-foreground";
1384
+ }
1385
+ }
1386
+ var PHASE_TEXT = {
1387
+ done: "text-emerald-700 dark:text-emerald-400",
1388
+ running: "text-primary",
1389
+ waiting: "text-amber-700 dark:text-amber-300",
1390
+ failed: "text-destructive",
1391
+ skipped: "text-muted-foreground",
1392
+ ready: "text-foreground",
1393
+ blocked: "text-muted-foreground"
1394
+ };
1395
+ var STEP_PILL = "flex min-w-0 items-center gap-1.5 whitespace-nowrap rounded-full border px-2.5 py-1 text-xs font-medium transition-colors";
1396
+ var STEP_LABEL = "min-w-[2.5rem] truncate";
1397
+ var STEP_EXTRA = "min-w-0 shrink-[6] truncate font-normal opacity-80";
1398
+ var fill = (template, values) => Object.entries(values).reduce((s, [k, v]) => s.replace(`{${k}}`, String(v)), template);
1399
+ var NARROW_PX = 560;
1400
+ var FULL_LEVEL_PX = 190;
1401
+ function StepBarFrame({
1402
+ levels,
1403
+ phaseOf,
1404
+ current,
1405
+ onSelect,
1406
+ renderStep,
1407
+ noteOf,
1408
+ renderAfter,
1409
+ leading,
1410
+ trailing,
1411
+ isSelectable = () => true,
1412
+ icon,
1413
+ disabled,
1414
+ labels,
1415
+ tid,
1416
+ className
1417
+ }) {
1418
+ const l = { ...DEFAULT_STEP_BAR_LABELS, ...labels };
1419
+ const box = react.useRef(null);
1420
+ const { width } = chunkB4SRYJLM_cjs.useElementSize(box);
1421
+ const narrow = width > 0 && width < NARROW_PX;
1422
+ const [start, setStart] = react.useState(null);
1423
+ react.useEffect(() => setStart(null), [current]);
1424
+ const span = narrow ? 2 : width >= levels.length * FULL_LEVEL_PX ? levels.length : 3;
1425
+ const win = stepWindow({ levels, phaseOf, current, start, span });
1426
+ const [listOpen, setListOpen] = react.useState(null);
1427
+ const move = (to) => setStart(Math.max(0, Math.min(win.levels.length - 1, to)));
1428
+ const select = (id) => {
1429
+ setListOpen(null);
1430
+ setStart(null);
1431
+ onSelect(id);
1432
+ };
1433
+ const onKeyDown = (e) => {
1434
+ if (!box.current?.contains(e.target)) return;
1435
+ const to = e.key === "ArrowLeft" ? win.start - 1 : e.key === "ArrowRight" ? win.start + 1 : e.key === "Home" ? 0 : e.key === "End" ? win.levels.length : null;
1436
+ if (to === null) return;
1437
+ e.preventDefault();
1438
+ move(to);
1439
+ };
1440
+ const row = (s, isCurrent) => {
1441
+ const phase = phaseOf(s.id);
1442
+ const selectable = isSelectable(s.id);
1443
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1444
+ "button",
1445
+ {
1446
+ type: "button",
1447
+ disabled: !selectable || disabled,
1448
+ onClick: () => select(s.id),
1449
+ "aria-current": isCurrent ? "step" : void 0,
1450
+ className: ui.cn(
1451
+ "flex w-full min-w-0 items-center gap-2 rounded-md px-2 py-1 text-left text-xs hover:bg-accent disabled:cursor-default disabled:hover:bg-transparent",
1452
+ isCurrent && "bg-primary/10 font-semibold text-primary"
1453
+ ),
1454
+ "data-phase": phase,
1455
+ "data-testid": tid(`list-step-${s.id}`),
1456
+ children: [
1457
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("flex shrink-0", !isCurrent && PHASE_TEXT[phase]), children: /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase, icon: icon?.(s) }) }),
1458
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", title: s.title, children: s.title }),
1459
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[10px] font-normal text-muted-foreground", children: l.phases[phase] })
1460
+ ]
1461
+ },
1462
+ s.id
1463
+ );
1464
+ };
1465
+ const at = win.levels[win.currentLevel];
1466
+ const atId = at && (at.steps.find((s) => s.id === current) ?? at.primary).id;
1467
+ const focusCurrent = (e) => {
1468
+ const el = e.currentTarget?.querySelector(
1469
+ '[aria-current="step"]'
1470
+ );
1471
+ if (!el) return;
1472
+ e.preventDefault();
1473
+ el.focus();
1474
+ el.scrollIntoView?.({ block: "nearest" });
1475
+ };
1476
+ const allSteps = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1477
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 py-1 text-[11px] font-medium text-muted-foreground", children: fill(l.position, { position: win.position, total: win.total }) }),
1478
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { children: win.levels.map((level) => /* @__PURE__ */ jsxRuntime.jsxs(
1479
+ "li",
1480
+ {
1481
+ className: ui.cn(level.steps.length > 1 && "my-0.5 border-l-2 border-primary/30 pl-1"),
1482
+ children: [
1483
+ level.steps.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 text-[10px] uppercase tracking-wide text-muted-foreground", children: l.inParallel }),
1484
+ level.steps.map((s) => row(s, s.id === atId))
1485
+ ]
1486
+ },
1487
+ level.index
1488
+ )) })
1489
+ ] });
1490
+ const overflow = (side, count) => narrow && side === "before" ? null : narrow && side === "after" ? win.hiddenBefore + win.hiddenAfter > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: listOpen === side, onOpenChange: (o) => setListOpen(o ? side : null), children: [
1491
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1492
+ "button",
1493
+ {
1494
+ type: "button",
1495
+ className: "flex shrink-0 items-center rounded-full px-1.5 py-1 text-[11px] tabular-nums text-muted-foreground hover:bg-accent hover:text-foreground",
1496
+ "aria-label": fill(l.position, { position: win.position, total: win.total }),
1497
+ title: fill(l.position, { position: win.position, total: win.total }),
1498
+ "data-testid": tid("steps-count"),
1499
+ children: [
1500
+ win.position,
1501
+ "/",
1502
+ win.total
1503
+ ]
1504
+ }
1505
+ ) }),
1506
+ /* @__PURE__ */ jsxRuntime.jsx(
1507
+ ui.PopoverContent,
1508
+ {
1509
+ align: "end",
1510
+ className: "max-h-[min(24rem,70vh)] w-72 overflow-y-auto p-1",
1511
+ onOpenAutoFocus: focusCurrent,
1512
+ "data-testid": tid("all-steps"),
1513
+ children: allSteps
1514
+ }
1515
+ )
1516
+ ] }) : null : count > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: listOpen === side, onOpenChange: (o) => setListOpen(o ? side : null), children: [
1517
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1518
+ "button",
1519
+ {
1520
+ type: "button",
1521
+ className: "flex shrink-0 items-center gap-0.5 rounded-full px-1.5 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
1522
+ "aria-label": fill(side === "before" ? l.hiddenBefore : l.hiddenAfter, { count }),
1523
+ title: fill(side === "before" ? l.hiddenBefore : l.hiddenAfter, { count }),
1524
+ "data-testid": tid(`hidden-${side}`),
1525
+ children: [
1526
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2026" }),
1527
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: count })
1528
+ ]
1529
+ }
1530
+ ) }),
1531
+ /* @__PURE__ */ jsxRuntime.jsx(
1532
+ ui.PopoverContent,
1533
+ {
1534
+ align: side === "before" ? "start" : "end",
1535
+ className: "max-h-[min(24rem,70vh)] w-80 overflow-y-auto p-1",
1536
+ onOpenAutoFocus: focusCurrent,
1537
+ "data-testid": tid("all-steps"),
1538
+ children: allSteps
1539
+ }
1540
+ )
1541
+ ] }) : null;
1542
+ const arrow = (dir) => {
1543
+ const can = dir === "back" ? win.canBack : win.canForward;
1544
+ const Icon = dir === "back" ? lucideReact.ChevronLeft : lucideReact.ChevronRight;
1545
+ return /* @__PURE__ */ jsxRuntime.jsx(
1546
+ "button",
1547
+ {
1548
+ type: "button",
1549
+ onClick: () => move(win.start + (dir === "back" ? -1 : 1)),
1550
+ disabled: !can,
1551
+ "aria-label": dir === "back" ? l.back : l.forward,
1552
+ title: dir === "back" ? l.back : l.forward,
1553
+ className: "flex size-6 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-30",
1554
+ "data-testid": tid(`steps-${dir}`),
1555
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" })
1556
+ }
1557
+ );
1558
+ };
1559
+ const running = win.runningHidden;
1560
+ const workingPill = (s) => /* @__PURE__ */ jsxRuntime.jsxs(
1561
+ "button",
1562
+ {
1563
+ type: "button",
1564
+ onClick: () => select(s.id),
1565
+ className: "flex min-w-0 max-w-[14rem] shrink items-center gap-1.5 rounded-full border border-primary/40 bg-primary/5 px-2 py-1 text-xs text-primary hover:bg-primary/10",
1566
+ title: fill(l.working, { title: s.title }),
1567
+ "data-testid": tid(`working-${s.id}`),
1568
+ children: [
1569
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 shrink-0 animate-spin" }),
1570
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: fill(l.working, { title: s.title }) })
1571
+ ]
1572
+ },
1573
+ s.id
1574
+ );
1575
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1576
+ "nav",
1577
+ {
1578
+ ref: box,
1579
+ "aria-label": l.nav,
1580
+ onKeyDown,
1581
+ className: ui.cn("flex min-w-0 items-center gap-1", narrow && "flex-wrap", className),
1582
+ "data-testid": tid("steps"),
1583
+ "data-narrow": narrow || void 0,
1584
+ children: [
1585
+ arrow("back"),
1586
+ win.start === 0 && leading,
1587
+ overflow("before", win.hiddenBefore),
1588
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 flex-1 items-center gap-1", children: win.visible.map((level, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1589
+ "li",
1590
+ {
1591
+ className: ui.cn(
1592
+ "flex min-w-[5.5rem] items-center gap-1",
1593
+ i === win.visible.length - 1 ? "flex-[0_1_auto]" : "flex-[1_1_auto]"
1594
+ ),
1595
+ "data-role": level.role,
1596
+ children: [
1597
+ renderStep(level.primary, level, win, narrow),
1598
+ level.others.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1599
+ GroupChip,
1600
+ {
1601
+ level,
1602
+ label: fill(l.parallel, { count: level.others.length }),
1603
+ heading: l.inParallel,
1604
+ row: (s) => row(s, s.id === atId),
1605
+ tid
1606
+ }
1607
+ ),
1608
+ renderAfter?.(level),
1609
+ i < win.visible.length - 1 && !narrow && /* @__PURE__ */ jsxRuntime.jsx(
1610
+ "span",
1611
+ {
1612
+ "aria-hidden": true,
1613
+ className: ui.cn(
1614
+ "h-px min-w-3 flex-1",
1615
+ level.steps.every((s) => ["done", "skipped"].includes(phaseOf(s.id))) ? "bg-emerald-600/40" : "bg-border"
1616
+ )
1617
+ }
1618
+ )
1619
+ ]
1620
+ },
1621
+ level.steps.map((s) => s.id).join("+")
1622
+ )) }),
1623
+ overflow("after", win.hiddenAfter),
1624
+ !win.canForward && trailing,
1625
+ arrow("forward"),
1626
+ narrow && atId && noteOf?.(atId) && /* @__PURE__ */ jsxRuntime.jsx(
1627
+ "p",
1628
+ {
1629
+ className: "min-w-0 basis-full truncate px-1 text-[11px] text-muted-foreground",
1630
+ "data-testid": tid("note"),
1631
+ children: noteOf(atId)
1632
+ }
1633
+ ),
1634
+ running.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
1635
+ "div",
1636
+ {
1637
+ className: ui.cn("flex min-w-0 shrink items-center gap-1", narrow && "basis-full"),
1638
+ "data-testid": tid("working"),
1639
+ children: [
1640
+ (running.length > 2 ? running.slice(0, 1) : running).map(workingPill),
1641
+ running.length > 2 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
1642
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1643
+ "button",
1644
+ {
1645
+ type: "button",
1646
+ className: "flex shrink-0 items-center gap-1 rounded-full border border-primary/40 bg-primary/5 px-2 py-1 text-xs text-primary hover:bg-primary/10",
1647
+ "data-testid": tid("working-more"),
1648
+ children: [
1649
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin" }),
1650
+ fill(l.moreWorking, { count: running.length - 1 })
1651
+ ]
1652
+ }
1653
+ ) }),
1654
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { align: "end", className: "w-72 p-1", children: running.slice(1).map((s) => row(s, false)) })
1655
+ ] })
1656
+ ]
1657
+ }
1658
+ )
1659
+ ]
1660
+ }
1661
+ );
1662
+ }
1663
+ function GroupChip({
1664
+ level,
1665
+ label,
1666
+ heading,
1667
+ row,
1668
+ tid
1669
+ }) {
1670
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
1671
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
1672
+ "button",
1673
+ {
1674
+ type: "button",
1675
+ className: "shrink-0 rounded-full border border-border bg-muted px-1.5 py-0.5 text-[11px] font-medium tabular-nums text-muted-foreground hover:border-primary/40 hover:text-primary",
1676
+ "aria-label": label,
1677
+ title: label,
1678
+ "data-testid": tid(`group-${level.steps[0].id}`),
1679
+ children: [
1680
+ "+",
1681
+ level.others.length
1682
+ ]
1683
+ }
1684
+ ) }),
1685
+ /* @__PURE__ */ jsxRuntime.jsxs(
1686
+ ui.PopoverContent,
1687
+ {
1688
+ align: "start",
1689
+ className: "w-72 p-1",
1690
+ "data-testid": tid(`group-${level.steps[0].id}-list`),
1691
+ children: [
1692
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 py-1 text-[11px] font-medium text-muted-foreground", children: heading }),
1693
+ level.steps.map(row)
1694
+ ]
1695
+ }
1696
+ )
1697
+ ] });
1698
+ }
1699
+ var DEFAULT_WORKFLOW_STEP_PARTS_LABELS = {
1700
+ waitingFor: "Waiting for {name}",
1701
+ sendBack: "Send back",
1702
+ sendBackTo: "Send back to",
1703
+ sendBackNote: "What needs to change? (optional)",
1704
+ cancel: "Cancel",
1705
+ sentBackHere: "This step was sent back to be done again.",
1706
+ approvedBy: "Approved by {name}",
1707
+ approvedAt: "{date}",
1708
+ approvedWhat: "What was approved",
1709
+ viewAnswer: "View the answer",
1710
+ fieldsHeading: "Recorded with the approval",
1711
+ signers: "Signers",
1712
+ signed: "Signed",
1713
+ notSigned: "Not signed yet",
1714
+ openAndSign: "Open and sign",
1715
+ decline: "Decline",
1716
+ declineNote: "Why are you declining? (optional)",
1717
+ declineConfirm: "Decline to sign",
1718
+ declined: "Declined by {name}.",
1719
+ signedVersion: "Open the signed version",
1720
+ preparingSign: "Preparing the signature request\u2026",
1721
+ expires: "Expires {date}",
1722
+ preparingDraft: "Preparing the draft\u2026",
1723
+ draftReady: "The draft is ready in native mail. Check it, send it, then mark it as sent.",
1724
+ openDraft: "Open draft",
1725
+ emailSent: "Sent.",
1726
+ reviewRunning: "Reviewing the documents\u2026",
1727
+ reviewDone: "Reviewed {docs} documents in {cols} columns.",
1728
+ openReview: "Open the review",
1729
+ openInWord: "Open in Word",
1730
+ redlineHint: "The edits are tracked changes: accept or reject each one in Word.",
1731
+ someone: "someone"
1732
+ };
1733
+ var formatDate = (iso) => {
1734
+ const t = iso ? Date.parse(iso) : NaN;
1735
+ return Number.isNaN(t) ? "" : new Date(t).toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
1736
+ };
1737
+ var docName = (ref, nameOfDoc) => {
1738
+ const { id, version } = splitDocRef(ref);
1739
+ const name = nameOfDoc?.(id) ?? id;
1740
+ return version ? `${name} \xB7 v${version}` : name;
1741
+ };
1742
+ function DocChip({
1743
+ docRef,
1744
+ actions,
1745
+ nameOfDoc,
1746
+ testId
1747
+ }) {
1748
+ const label = docName(docRef, nameOfDoc);
1749
+ const cls = "inline-flex max-w-full items-center gap-1 rounded-md border border-border px-1.5 py-0.5 text-xs";
1750
+ return actions?.openDocument ? /* @__PURE__ */ jsxRuntime.jsxs(
1751
+ "button",
1752
+ {
1753
+ type: "button",
1754
+ onClick: () => actions.openDocument?.(docRef),
1755
+ className: ui.cn(cls, "hover:border-primary/40 hover:text-primary"),
1756
+ title: docRef,
1757
+ "data-testid": testId,
1758
+ children: [
1759
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3 shrink-0" }),
1760
+ " ",
1761
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
1762
+ ]
1763
+ }
1764
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cls, title: docRef, "data-testid": testId, children: [
1765
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3 shrink-0" }),
1766
+ " ",
1767
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
1768
+ ] });
1769
+ }
1770
+ function AssigneeLine({
1771
+ run,
1772
+ stepId,
1773
+ l,
1774
+ testId
1775
+ }) {
1776
+ const name = run.assigneeOf(stepId);
1777
+ const phase = run.phaseOf(stepId);
1778
+ if (!name || !["ready", "waiting", "blocked"].includes(phase)) return null;
1779
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1780
+ "p",
1781
+ {
1782
+ className: "flex items-center gap-1.5 text-xs text-muted-foreground",
1783
+ "data-testid": `${testId}-assignee`,
1784
+ children: [
1785
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserRound, { className: "size-3.5" }),
1786
+ " ",
1787
+ l.waitingFor.replace("{name}", name)
1788
+ ]
1789
+ }
1790
+ );
1791
+ }
1792
+ function SentBackNote({
1793
+ state,
1794
+ l,
1795
+ testId
1796
+ }) {
1797
+ if (!state?.sentBack) return null;
1798
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1799
+ "p",
1800
+ {
1801
+ className: "flex items-center gap-1.5 rounded-md bg-amber-500/10 px-2 py-1 text-xs text-amber-700 dark:text-amber-300",
1802
+ "data-testid": `${testId}-sent-back`,
1803
+ children: [
1804
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-3.5" }),
1805
+ " ",
1806
+ l.sentBackHere
1807
+ ]
1808
+ }
1809
+ );
1810
+ }
1811
+ function SendBackControl({
1812
+ run,
1813
+ step,
1814
+ l,
1815
+ testId
1816
+ }) {
1817
+ const states = Object.fromEntries(
1818
+ run.steps.map((s) => [s.id, run.stateOf(s.id) ?? { status: "pending" }])
1819
+ );
1820
+ const targets = sendBackTargets(run.steps, states, step.id);
1821
+ const [open, setOpen] = react.useState(false);
1822
+ const [to, setTo] = react.useState(targets[0]?.id ?? "");
1823
+ const [note, setNote] = react.useState("");
1824
+ if (!run.sendBack || run.phaseOf(step.id) !== "ready" || targets.length === 0) return null;
1825
+ if (!open)
1826
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1827
+ ui.Button,
1828
+ {
1829
+ variant: "outline",
1830
+ size: "sm",
1831
+ onClick: () => setOpen(true),
1832
+ disabled: run.busy,
1833
+ "data-testid": `${testId}-send-back`,
1834
+ children: [
1835
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-4" }),
1836
+ " ",
1837
+ l.sendBack
1838
+ ]
1839
+ }
1840
+ );
1841
+ const target = targets.some((t) => t.id === to) ? to : targets[0].id;
1842
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1843
+ "div",
1844
+ {
1845
+ className: "space-y-2 rounded-md border border-border p-3",
1846
+ "data-testid": `${testId}-send-back-form`,
1847
+ children: [
1848
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs font-medium", children: [
1849
+ l.sendBackTo,
1850
+ /* @__PURE__ */ jsxRuntime.jsx(
1851
+ "select",
1852
+ {
1853
+ className: "flex h-8 w-full rounded-md border border-input bg-background px-2 text-sm",
1854
+ value: target,
1855
+ onChange: (e) => setTo(e.target.value),
1856
+ "data-testid": `${testId}-send-back-to`,
1857
+ children: targets.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.id, children: t.title }, t.id))
1858
+ }
1859
+ )
1860
+ ] }),
1861
+ /* @__PURE__ */ jsxRuntime.jsx(
1862
+ ui.Textarea,
1863
+ {
1864
+ rows: 3,
1865
+ value: note,
1866
+ placeholder: l.sendBackNote,
1867
+ "aria-label": l.sendBackNote,
1868
+ onChange: (e) => setNote(e.target.value),
1869
+ "data-testid": `${testId}-send-back-note`
1870
+ }
1871
+ ),
1872
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
1873
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", size: "sm", onClick: () => setOpen(false), children: l.cancel }),
1874
+ /* @__PURE__ */ jsxRuntime.jsxs(
1875
+ ui.Button,
1876
+ {
1877
+ size: "sm",
1878
+ disabled: run.busy,
1879
+ onClick: () => void run.sendBack?.(step.id, target, note.trim() || void 0),
1880
+ "data-testid": `${testId}-send-back-confirm`,
1881
+ children: [
1882
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-4" }),
1883
+ " ",
1884
+ l.sendBack
1885
+ ]
1886
+ }
1887
+ )
1888
+ ] })
1889
+ ]
1890
+ }
1891
+ );
1892
+ }
1893
+ var shownValue = (v, field, nameOf) => {
1894
+ if (v === void 0 || v === null || v === "") return "\u2014";
1895
+ if (typeof v === "boolean") return v ? "\u2713" : "\u2717";
1896
+ if (field.type === "person" && typeof v === "string") return nameOf?.(v) ?? v;
1897
+ if (field.type === "select") return field.options?.find((o) => o.value === v)?.label ?? String(v);
1898
+ return typeof v === "object" ? JSON.stringify(v) : String(v);
1899
+ };
1900
+ function ApprovalEvidence({
1901
+ run,
1902
+ step,
1903
+ actions,
1904
+ nameOfDoc,
1905
+ l,
1906
+ testId
1907
+ }) {
1908
+ const state = run.stateOf(step.id);
1909
+ if (state?.status !== "done") return null;
1910
+ const approver = state.by ? run.nameOf?.(state.by) ?? l.someone : void 0;
1911
+ const evidence = state.approved ?? [];
1912
+ const titleOf = (id) => run.steps.find((s) => s.id === id)?.title ?? id;
1913
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-md bg-muted/40 p-3", "data-testid": `${testId}-evidence`, children: [
1914
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex flex-wrap items-center gap-1.5 text-sm font-medium", children: [
1915
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "size-4 text-primary" }),
1916
+ approver ? l.approvedBy.replace("{name}", approver) : null,
1917
+ state.at && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: l.approvedAt.replace("{date}", formatDate(state.at)) })
1918
+ ] }),
1919
+ evidence.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1920
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.approvedWhat }),
1921
+ evidence.map((e) => /* @__PURE__ */ jsxRuntime.jsxs(
1922
+ "div",
1923
+ {
1924
+ className: "flex flex-wrap items-center gap-1.5 text-xs",
1925
+ "data-testid": `${testId}-evidence-${e.step}`,
1926
+ children: [
1927
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: titleOf(e.step) }),
1928
+ e.response_id && (actions?.openMessage ? /* @__PURE__ */ jsxRuntime.jsxs(
1929
+ "button",
1930
+ {
1931
+ type: "button",
1932
+ onClick: () => actions.openMessage?.(e.response_id),
1933
+ className: "inline-flex items-center gap-1 text-primary hover:underline",
1934
+ "data-testid": `${testId}-evidence-${e.step}-answer`,
1935
+ children: [
1936
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-3" }),
1937
+ " ",
1938
+ l.viewAnswer
1939
+ ]
1940
+ }
1941
+ ) : null),
1942
+ (e.documents ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsx(DocChip, { docRef: d, actions, nameOfDoc }, d))
1943
+ ]
1944
+ },
1945
+ e.step
1946
+ ))
1947
+ ] }),
1948
+ (step.fields ?? []).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-0.5 text-xs", children: (step.fields ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "contents", children: [
1949
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: f.label }),
1950
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": `${testId}-evidence-field-${f.name}`, children: shownValue(run.inputs[f.name], f, run.nameOf) })
1951
+ ] }, f.name)) })
1952
+ ] });
1953
+ }
1954
+ function RedlineOpen({
1955
+ step,
1956
+ state,
1957
+ actions,
1958
+ l,
1959
+ testId
1960
+ }) {
1961
+ const version = state?.status === "done" ? state.documents?.[0] : void 0;
1962
+ if (!step.editDocument || !version || !actions?.openRedline) return null;
1963
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", "data-testid": `${testId}-redline`, children: [
1964
+ /* @__PURE__ */ jsxRuntime.jsxs(
1965
+ ui.Button,
1966
+ {
1967
+ size: "sm",
1968
+ onClick: () => actions.openRedline?.(version),
1969
+ "data-testid": `${testId}-open-word`,
1970
+ children: [
1971
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-4" }),
1972
+ " ",
1973
+ l.openInWord
1974
+ ]
1975
+ }
1976
+ ),
1977
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: l.redlineHint })
1978
+ ] });
1979
+ }
1980
+ function ActionStepBody({
1981
+ step,
1982
+ run,
1983
+ actions,
1984
+ nameOfDoc,
1985
+ heading,
1986
+ l,
1987
+ testId
1988
+ }) {
1989
+ const state = run.stateOf(step.id);
1990
+ const phase = run.phaseOf(step.id);
1991
+ const name = (id) => run.nameOf?.(id) ?? id;
1992
+ const [declining, setDeclining] = react.useState(false);
1993
+ const [note, setNote] = react.useState("");
1994
+ const a = step.action;
1995
+ const working = (text) => /* @__PURE__ */ jsxRuntime.jsxs(
1996
+ "p",
1997
+ {
1998
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
1999
+ "data-testid": `${testId}-working`,
2000
+ children: [
2001
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
2002
+ " ",
2003
+ text
2004
+ ]
2005
+ }
2006
+ );
2007
+ let body = null;
2008
+ if (a.type === "sign") {
2009
+ const waiting = state?.waiting;
2010
+ const signers = waiting?.signers ?? [];
2011
+ const signed = new Set(waiting?.signed ?? []);
2012
+ const mine = !actions?.me || signers.includes(actions.me) && !signed.has(actions.me);
2013
+ const signedRef = state?.status === "done" ? state.documents?.[0] : void 0;
2014
+ body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2015
+ (phase === "ready" || phase === "running") && working(l.preparingSign),
2016
+ phase === "waiting" && waiting?.doc_ext_id && /* @__PURE__ */ jsxRuntime.jsx(
2017
+ DocChip,
2018
+ {
2019
+ docRef: `${waiting.doc_ext_id}${waiting.version ? `@v${waiting.version}` : ""}`,
2020
+ actions,
2021
+ nameOfDoc,
2022
+ testId: `${testId}-document`
2023
+ }
2024
+ ),
2025
+ signers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", "data-testid": `${testId}-signers`, children: [
2026
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.signers }),
2027
+ signers.map((id) => /* @__PURE__ */ jsxRuntime.jsxs(
2028
+ "p",
2029
+ {
2030
+ className: "flex items-center gap-2 text-sm",
2031
+ "data-signed": signed.has(id) || void 0,
2032
+ "data-testid": `${testId}-signer-${id}`,
2033
+ children: [
2034
+ signed.has(id) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-primary" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hourglass, { className: "size-3.5 text-muted-foreground" }),
2035
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: name(id) }),
2036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: signed.has(id) ? l.signed : l.notSigned })
2037
+ ]
2038
+ },
2039
+ id
2040
+ ))
2041
+ ] }),
2042
+ waiting?.expires_at && phase === "waiting" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
2043
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "size-3.5" }),
2044
+ " ",
2045
+ l.expires.replace("{date}", formatDate(waiting.expires_at))
2046
+ ] }),
2047
+ phase === "waiting" && mine && !declining && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
2048
+ actions?.sign && state && /* @__PURE__ */ jsxRuntime.jsxs(
2049
+ ui.Button,
2050
+ {
2051
+ size: "sm",
2052
+ onClick: () => actions.sign?.(step, state),
2053
+ "data-testid": `${testId}-open-sign`,
2054
+ children: [
2055
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PenLine, { className: "size-4" }),
2056
+ " ",
2057
+ l.openAndSign
2058
+ ]
2059
+ }
2060
+ ),
2061
+ run.decline && /* @__PURE__ */ jsxRuntime.jsxs(
2062
+ ui.Button,
2063
+ {
2064
+ size: "sm",
2065
+ variant: "ghost",
2066
+ onClick: () => setDeclining(true),
2067
+ "data-testid": `${testId}-decline`,
2068
+ children: [
2069
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" }),
2070
+ " ",
2071
+ l.decline
2072
+ ]
2073
+ }
2074
+ )
2075
+ ] }),
2076
+ declining && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": `${testId}-decline-form`, children: [
2077
+ /* @__PURE__ */ jsxRuntime.jsx(
2078
+ ui.Textarea,
2079
+ {
2080
+ rows: 2,
2081
+ value: note,
2082
+ placeholder: l.declineNote,
2083
+ "aria-label": l.declineNote,
2084
+ onChange: (e) => setNote(e.target.value),
2085
+ "data-testid": `${testId}-decline-note`
2086
+ }
2087
+ ),
2088
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
2089
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", size: "sm", onClick: () => setDeclining(false), children: l.cancel }),
2090
+ /* @__PURE__ */ jsxRuntime.jsx(
2091
+ ui.Button,
2092
+ {
2093
+ size: "sm",
2094
+ variant: "destructive",
2095
+ disabled: run.busy,
2096
+ onClick: async () => {
2097
+ await run.decline?.(step.id, note.trim() || void 0);
2098
+ setDeclining(false);
2099
+ },
2100
+ "data-testid": `${testId}-decline-confirm`,
2101
+ children: l.declineConfirm
2102
+ }
2103
+ )
2104
+ ] })
2105
+ ] }),
2106
+ phase === "failed" && state?.declinedBy && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-declined`, children: l.declined.replace("{name}", name(state.declinedBy)) }),
2107
+ signedRef && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions?.openDocument ? /* @__PURE__ */ jsxRuntime.jsxs(
2108
+ ui.Button,
2109
+ {
2110
+ size: "sm",
2111
+ variant: "outline",
2112
+ onClick: () => actions.openDocument?.(signedRef),
2113
+ "data-testid": `${testId}-signed-version`,
2114
+ children: [
2115
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "size-4" }),
2116
+ " ",
2117
+ l.signedVersion
2118
+ ]
2119
+ }
2120
+ ) : /* @__PURE__ */ jsxRuntime.jsx(DocChip, { docRef: signedRef, nameOfDoc }) })
2121
+ ] });
2122
+ } else if (a.type === "email_draft") {
2123
+ const draftId = state?.waiting?.draft_id ?? (typeof state?.output?.draft_id === "string" ? state.output.draft_id : void 0);
2124
+ body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2125
+ (phase === "ready" || phase === "running") && working(l.preparingDraft),
2126
+ phase === "waiting" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.draftReady }),
2127
+ phase === "done" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-sm", "data-testid": `${testId}-sent`, children: [
2128
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-4 text-primary" }),
2129
+ " ",
2130
+ l.emailSent
2131
+ ] }),
2132
+ draftId && actions?.openDraft && phase !== "done" && /* @__PURE__ */ jsxRuntime.jsxs(
2133
+ ui.Button,
2134
+ {
2135
+ size: "sm",
2136
+ variant: "outline",
2137
+ onClick: () => actions.openDraft?.(draftId, state?.waiting?.mailbox),
2138
+ "data-testid": `${testId}-open-draft`,
2139
+ children: [
2140
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "size-4" }),
2141
+ " ",
2142
+ l.openDraft
2143
+ ]
2144
+ }
2145
+ )
2146
+ ] });
2147
+ } else {
2148
+ const tags = state?.output?.tag_ext_ids ?? a.tags;
2149
+ const docs = state?.output?.doc_ext_ids ?? [];
2150
+ body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2151
+ (phase === "ready" || phase === "running") && working(l.reviewRunning),
2152
+ phase === "done" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2153
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-reviewed`, children: l.reviewDone.replace("{docs}", String(docs.length)).replace("{cols}", String(tags.length)) }),
2154
+ actions?.openReview && /* @__PURE__ */ jsxRuntime.jsxs(
2155
+ ui.Button,
2156
+ {
2157
+ size: "sm",
2158
+ onClick: () => actions.openReview?.(tags, docs),
2159
+ "data-testid": `${testId}-open-review`,
2160
+ children: [
2161
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Table2, { className: "size-4" }),
2162
+ " ",
2163
+ l.openReview
2164
+ ]
2165
+ }
2166
+ )
2167
+ ] })
2168
+ ] });
2169
+ }
2170
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
2171
+ heading,
2172
+ /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state, l, testId }),
2173
+ /* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l, testId }),
2174
+ body,
2175
+ phase === "failed" && !state?.declinedBy && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-failed`, children: state?.error || "" })
2176
+ ] });
2177
+ }
2178
+ var DONE = "__done";
2179
+ function WorkflowStepBar({
2180
+ run,
2181
+ levels,
2182
+ doneTitle,
2183
+ doneIcon,
2184
+ icon,
2185
+ tid,
2186
+ labels
2187
+ }) {
2188
+ const l = { ...DEFAULT_STEP_BAR_LABELS, ...labels };
2189
+ const done = { id: DONE, title: doneTitle };
2190
+ const phaseOf = (id) => id === DONE ? run.isComplete ? "done" : "blocked" : run.phaseOf(id);
2191
+ const current = run.isComplete ? DONE : run.current;
2192
+ const waitingOf = (id) => {
2193
+ if (id === DONE || !["ready", "waiting"].includes(phaseOf(id))) return void 0;
2194
+ const assignee = run.assigneeOf(id);
2195
+ return assignee ? l.waitingFor.replace("{name}", assignee) : void 0;
2196
+ };
2197
+ const pill = (s, narrow = false) => {
2198
+ const phase = phaseOf(s.id);
2199
+ const isCurrent = s.id === current;
2200
+ const assignee = ["ready", "waiting"].includes(phase) ? run.assigneeOf(s.id) : void 0;
2201
+ const waiting = assignee ? l.waitingFor.replace("{name}", assignee) : void 0;
2202
+ const title = waiting ? `${s.title} \xB7 ${waiting}` : s.title;
2203
+ const name = `${title} (${l.phases[phase]})`;
2204
+ if (s.id === DONE)
2205
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2206
+ "span",
2207
+ {
2208
+ className: ui.cn(STEP_PILL, stepPillTone(phase, isCurrent)),
2209
+ "aria-current": isCurrent ? "step" : void 0,
2210
+ "aria-label": name,
2211
+ title: doneTitle,
2212
+ "data-phase": phase,
2213
+ "data-testid": tid("step-done"),
2214
+ children: [
2215
+ /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase: run.isComplete ? "done" : "ready", icon: doneIcon }),
2216
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn(STEP_LABEL, "max-w-[12rem]"), children: doneTitle })
2217
+ ]
2218
+ }
2219
+ );
2220
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2221
+ "button",
2222
+ {
2223
+ type: "button",
2224
+ onClick: () => run.goTo(s.id),
2225
+ disabled: run.busy,
2226
+ className: ui.cn(STEP_PILL, stepPillTone(phase, isCurrent), "disabled:cursor-default"),
2227
+ "aria-current": isCurrent ? "step" : void 0,
2228
+ "aria-label": name,
2229
+ title,
2230
+ "data-phase": phase,
2231
+ "data-testid": tid(`step-${s.id}`),
2232
+ children: [
2233
+ /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase, icon: icon(s.icon) }),
2234
+ /* @__PURE__ */ jsxRuntime.jsx(
2235
+ "span",
2236
+ {
2237
+ className: ui.cn(STEP_LABEL, isCurrent ? "max-w-[18rem]" : "max-w-[12rem]"),
2238
+ "data-testid": tid(`step-${s.id}-label`),
2239
+ children: s.title
2240
+ }
2241
+ ),
2242
+ assignee && isCurrent && !narrow && /* @__PURE__ */ jsxRuntime.jsxs(
2243
+ "span",
2244
+ {
2245
+ className: ui.cn(STEP_EXTRA, "max-w-[12rem]"),
2246
+ "data-testid": tid(`step-${s.id}-assignee`),
2247
+ children: [
2248
+ "\xB7 ",
2249
+ waiting
2250
+ ]
2251
+ }
2252
+ )
2253
+ ]
2254
+ }
2255
+ );
2256
+ };
2257
+ return /* @__PURE__ */ jsxRuntime.jsx(
2258
+ StepBarFrame,
2259
+ {
2260
+ levels: [...levels, [done]],
2261
+ phaseOf,
2262
+ current,
2263
+ onSelect: (id) => id !== DONE && run.goTo(id),
2264
+ isSelectable: (id) => id !== DONE,
2265
+ renderStep: (s, _level, _win, narrow) => pill(s, narrow),
2266
+ noteOf: waitingOf,
2267
+ icon: (s) => s.id === DONE ? doneIcon : icon(s.icon),
2268
+ disabled: run.busy,
2269
+ labels,
2270
+ tid,
2271
+ className: "w-full"
2272
+ }
2273
+ );
2274
+ }
2275
+ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
2276
+ back: "Back",
2277
+ next: "Continue",
2278
+ skip: "Skip",
2279
+ skipStep: "Skip this step",
2280
+ finish: "Finish",
2281
+ approve: "Approve",
2282
+ working: "Working\u2026",
2283
+ stepWorking: "{step}\u2026 {elapsed}",
2284
+ starting: "Starting\u2026",
2285
+ retry: "Retry",
2286
+ failed: "This step did not finish.",
2287
+ blocked: "Starts after {steps}.",
2288
+ awaitingReview: "Waiting for approval.",
2289
+ approved: "Approved.",
2290
+ skipped: "Skipped.",
2291
+ branch: "Runs alongside; its result joins the thread",
2292
+ complete: "Done",
2293
+ restart: "Start again",
2294
+ filesHeading: "Already in the workspace ({count})",
2295
+ addedHeading: "Added for this step ({count})",
2296
+ noFiles: "No files yet.",
2297
+ fileReading: "Reading\u2026",
2298
+ fileReady: "Ready",
2299
+ fileFailed: "Could not be read",
2300
+ readingFiles: "Reading {current} of {count} files\u2026",
2301
+ markSent: "Mark as sent"
2302
+ };
2303
+ function WorkflowRunner({
2304
+ workflow,
2305
+ run,
2306
+ renderAgentOutput,
2307
+ renderReview,
2308
+ onUpload,
2309
+ uploading = false,
2310
+ files,
2311
+ renderUpload,
2312
+ renderStepNote,
2313
+ renderComplete,
2314
+ renderScope,
2315
+ renderDocuments,
2316
+ renderIcon,
2317
+ people,
2318
+ actions,
2319
+ nameOfDoc,
2320
+ hideStepBar,
2321
+ compact: compact3,
2322
+ labels,
2323
+ partsLabels,
2324
+ testIdPrefix = "workflow-run",
2325
+ className
2326
+ }) {
2327
+ const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
2328
+ const pl = { ...DEFAULT_WORKFLOW_STEP_PARTS_LABELS, ...partsLabels };
2329
+ const box = compact3 ? "p-4" : "max-w-2xl p-6";
2330
+ const { steps, step, isComplete, action } = run;
2331
+ const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
2332
+ const tid = (suffix) => `${testIdPrefix}-${suffix}`;
2333
+ const levels = stepLevels(steps);
2334
+ const icon = (key) => key && renderIcon ? renderIcon(key) : void 0;
2335
+ const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
2336
+ const unread = added.filter((f) => f.status === "processing").length;
2337
+ const reading = action === "complete" && unread > 0;
2338
+ const nextLabel = reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "complete" && step?.kind === "action" ? l.markSent : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
2339
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn(compact3 ? "space-y-3" : "space-y-6", className), "data-testid": testIdPrefix, children: [
2340
+ !hideStepBar && /* @__PURE__ */ jsxRuntime.jsx(
2341
+ WorkflowStepBar,
2342
+ {
2343
+ run,
2344
+ levels,
2345
+ doneTitle: completion?.title ?? l.complete,
2346
+ doneIcon: icon(completion?.icon),
2347
+ icon,
2348
+ tid
2349
+ }
2350
+ ),
2351
+ isComplete ? renderComplete?.(run) ?? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "mx-auto max-w-lg p-8 text-center", "data-testid": tid("done"), children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "mx-auto size-12 text-primary" }),
2353
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-4 text-xl font-semibold", children: completion?.title ?? l.complete }),
2354
+ completion?.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: completion.description }),
2355
+ /* @__PURE__ */ jsxRuntime.jsx(
2356
+ ui.Button,
2357
+ {
2358
+ variant: "outline",
2359
+ className: "mt-6",
2360
+ onClick: run.restart,
2361
+ "data-testid": tid("restart"),
2362
+ children: l.restart
2363
+ }
2364
+ )
2365
+ ] }) : step ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: run.phaseOf(step.id) === "blocked" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { className: ui.cn(box, "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(
2366
+ "{steps}",
2367
+ stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
2368
+ ) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
2369
+ /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon), testId: tid(`${step.id}-title`) }),
2370
+ /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2371
+ /* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
2372
+ /* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsxRuntime.jsx(
2373
+ SchemaForm,
2374
+ {
2375
+ fields: step.inputs,
2376
+ values: run.inputs,
2377
+ onChange: run.setInput,
2378
+ errors: run.errors,
2379
+ renderScope,
2380
+ renderDocuments,
2381
+ renderIcon,
2382
+ people,
2383
+ onEnterSubmit: () => void run.next(),
2384
+ testIdPrefix: tid("field")
2385
+ }
2386
+ ) }),
2387
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
2388
+ renderStepNote?.(step, run)
2389
+ ] }) : step.kind === "upload" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
2390
+ /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2391
+ /* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
2392
+ renderUpload?.(step) ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2393
+ /* @__PURE__ */ jsxRuntime.jsx(
2394
+ chunkDETZZBG2_cjs.UploadDropzone,
2395
+ {
2396
+ onFiles: (picked) => void onUpload?.(picked, step),
2397
+ uploading,
2398
+ disabled: !onUpload,
2399
+ accept: step.accept,
2400
+ title: step.title,
2401
+ description: step.description,
2402
+ hint: step.hint,
2403
+ testId: tid(`${step.id}-drop`)
2404
+ }
2405
+ ),
2406
+ files && /* @__PURE__ */ jsxRuntime.jsx(
2407
+ UploadFiles,
2408
+ {
2409
+ added,
2410
+ others: files.filter((f) => f.addedFor !== step.id),
2411
+ l,
2412
+ testId: tid(`${step.id}-files`)
2413
+ }
2414
+ )
2415
+ ] }),
2416
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
2417
+ renderStepNote?.(step, run)
2418
+ ] }) : step.kind === "review" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
2419
+ /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
2420
+ /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2421
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
2422
+ /* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
2423
+ !(run.phaseOf(step.id) === "done" && run.stateOf(step.id)?.by) && /* @__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 }),
2424
+ (step.fields ?? []).length > 0 && run.phaseOf(step.id) === "ready" && /* @__PURE__ */ jsxRuntime.jsx(
2425
+ SchemaForm,
2426
+ {
2427
+ fields: step.fields ?? [],
2428
+ values: run.inputs,
2429
+ onChange: run.setInput,
2430
+ errors: run.errors,
2431
+ renderScope,
2432
+ renderDocuments,
2433
+ renderIcon,
2434
+ people,
2435
+ testIdPrefix: tid("field")
2436
+ }
2437
+ ),
2438
+ /* @__PURE__ */ jsxRuntime.jsx(
2439
+ ApprovalEvidence,
2440
+ {
2441
+ run,
2442
+ step,
2443
+ actions,
2444
+ nameOfDoc,
2445
+ l: pl,
2446
+ testId: tid(step.id)
2447
+ }
2448
+ ),
2449
+ run.phaseOf(step.id) === "ready" && renderReview?.(step),
2450
+ /* @__PURE__ */ jsxRuntime.jsx(SendBackControl, { run, step, l: pl, testId: tid(step.id) }),
2451
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
2452
+ renderStepNote?.(step, run)
2453
+ ] }) : step.kind === "action" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
2454
+ /* @__PURE__ */ jsxRuntime.jsx(
2455
+ ActionStepBody,
2456
+ {
2457
+ step,
2458
+ run,
2459
+ actions,
2460
+ nameOfDoc,
2461
+ heading: /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
2462
+ l: pl,
2463
+ testId: tid(step.id)
2464
+ }
2465
+ ),
2466
+ run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
2467
+ renderStepNote?.(step, run)
2468
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
2469
+ AgentStepBody,
2470
+ {
2471
+ step,
2472
+ run,
2473
+ renderAgentOutput,
2474
+ icon: icon(step.icon),
2475
+ renderStepNote,
2476
+ compact: compact3,
2477
+ extra: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2478
+ /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2479
+ /* @__PURE__ */ jsxRuntime.jsx(
2480
+ RedlineOpen,
2481
+ {
2482
+ step,
2483
+ state: run.stateOf(step.id),
2484
+ actions,
2485
+ l: pl,
2486
+ testId: tid(step.id)
2487
+ }
2488
+ )
2489
+ ] }),
2490
+ l,
2491
+ tid
2492
+ }
2493
+ ) }, step.id) : null,
2494
+ !isComplete && /* @__PURE__ */ jsxRuntime.jsxs(
2495
+ "div",
2496
+ {
2497
+ className: ui.cn(
2498
+ "flex items-center justify-between border-t border-border pt-4",
2499
+ compact3 && "flex-wrap gap-2 pt-3"
2500
+ ),
2501
+ children: [
2502
+ /* @__PURE__ */ jsxRuntime.jsxs(
2503
+ ui.Button,
2504
+ {
2505
+ variant: "ghost",
2506
+ onClick: run.back,
2507
+ disabled: !run.canBack,
2508
+ "data-testid": tid("back"),
2509
+ children: [
2510
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "size-4" }),
2511
+ " ",
2512
+ l.back
2513
+ ]
2514
+ }
2515
+ ),
2516
+ /* @__PURE__ */ jsxRuntime.jsxs(
2517
+ "div",
2518
+ {
2519
+ className: ui.cn("flex items-center gap-2", compact3 && "ml-auto flex-wrap justify-end"),
2520
+ children: [
2521
+ step && action !== "skip" && // A step that commits (creates the matter, starts the thread) is what the run stands on.
2522
+ !step.commit && ["ready", "blocked", "failed"].includes(run.phaseOf(step.id)) && /* @__PURE__ */ jsxRuntime.jsx(
2523
+ ui.Button,
2524
+ {
2525
+ variant: "ghost",
2526
+ onClick: () => void run.skip(step.id),
2527
+ disabled: run.busy,
2528
+ "data-testid": tid("skip-step"),
2529
+ children: l.skipStep
2530
+ }
2531
+ ),
2532
+ /* @__PURE__ */ jsxRuntime.jsxs(
2533
+ ui.Button,
2534
+ {
2535
+ onClick: () => void run.next(),
2536
+ disabled: action === "wait" || reading,
2537
+ "data-testid": tid("next"),
2538
+ children: [
2539
+ nextLabel,
2540
+ reading || action === "wait" && (run.isRunning || run.busy) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "size-4" })
2541
+ ]
2542
+ }
2543
+ )
2544
+ ]
2545
+ }
2546
+ )
2547
+ ]
2548
+ }
2549
+ )
2550
+ ] });
2551
+ }
2552
+ function UploadFiles({
2553
+ added,
2554
+ others,
2555
+ l,
2556
+ testId
2557
+ }) {
2558
+ const heading = "text-xs font-semibold uppercase tracking-wide text-muted-foreground";
2559
+ const row = (f) => /* @__PURE__ */ jsxRuntime.jsxs(
2560
+ "div",
2561
+ {
2562
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
2563
+ "data-status": f.status,
2564
+ "data-testid": `${testId}-file-${f.id}`,
2565
+ children: [
2566
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 shrink-0 text-primary" }),
2567
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", title: f.name, children: f.name }),
2568
+ f.status === "processing" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1 text-xs", children: [
2569
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3 animate-spin" }),
2570
+ " ",
2571
+ l.fileReading
2572
+ ] }),
2573
+ f.status === "ready" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1 text-xs text-primary", children: [
2574
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3" }),
2575
+ " ",
2576
+ l.fileReady
2577
+ ] }),
2578
+ f.status === "failed" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1 text-xs text-destructive", children: [
2579
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3" }),
2580
+ " ",
2581
+ l.fileFailed
2582
+ ] })
2583
+ ]
2584
+ },
2585
+ f.id
2586
+ );
2587
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", "data-testid": testId, children: [
2588
+ added.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", "data-testid": `${testId}-added`, children: [
2589
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: heading, children: l.addedHeading.replace("{count}", String(added.length)) }),
2590
+ added.map(row)
2591
+ ] }),
2592
+ added.length === 0 && others.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.noFiles }),
2593
+ others.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "space-y-1", "data-testid": `${testId}-others`, children: [
2594
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { className: ui.cn(heading, "cursor-pointer select-none"), children: l.filesHeading.replace("{count}", String(others.length)) }),
2595
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 max-h-48 space-y-1 overflow-y-auto", children: others.map(row) })
2596
+ ] })
2597
+ ] });
2598
+ }
2599
+ function StepHeading({
2600
+ step,
2601
+ icon,
2602
+ testId
2603
+ }) {
2604
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
2605
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", "data-testid": testId, children: [
2606
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-4 items-center justify-center text-primary [&_svg]:size-4", children: icon }),
2607
+ step.title
2608
+ ] }),
2609
+ step.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: step.description })
2610
+ ] });
2611
+ }
2612
+ function formatElapsed(ms) {
2613
+ const total = Math.max(0, Math.floor(ms / 1e3));
2614
+ const h = Math.floor(total / 3600);
2615
+ const m = Math.floor(total % 3600 / 60);
2616
+ const sec = String(total % 60).padStart(2, "0");
2617
+ return h ? `${h}:${String(m).padStart(2, "0")}:${sec}` : `${m}:${sec}`;
2618
+ }
2619
+ function StepWorking({ title, since, label }) {
2620
+ const seen = react.useRef(Date.now());
2621
+ const start = since && Date.parse(since) || seen.current;
2622
+ const [now, setNow] = react.useState(() => Date.now());
2623
+ react.useEffect(() => {
2624
+ const t = setInterval(() => setNow(Date.now()), 1e3);
2625
+ return () => clearInterval(t);
2626
+ }, []);
2627
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: label.replace("{step}", title).replace("{elapsed}", formatElapsed(now - start)) });
2628
+ }
2629
+ function AgentStepBody({
2630
+ step,
2631
+ run,
2632
+ renderAgentOutput,
2633
+ icon,
2634
+ renderStepNote,
2635
+ extra,
2636
+ compact: compact3,
2637
+ l,
2638
+ tid
2639
+ }) {
2640
+ const state = run.stateOf(step.id);
2641
+ const phase = run.phaseOf(step.id);
2642
+ const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
2643
+ /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon }),
2644
+ phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: run.retry && /* @__PURE__ */ jsxRuntime.jsxs(
2645
+ ui.Button,
2646
+ {
2647
+ variant: "outline",
2648
+ size: "sm",
2649
+ onClick: () => void run.retry?.(step.id),
2650
+ disabled: run.busy,
2651
+ "data-testid": tid(`${step.id}-retry`),
2652
+ children: [
2653
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "size-4" }),
2654
+ " ",
2655
+ l.retry
2656
+ ]
2657
+ }
2658
+ ) })
2659
+ ] });
2660
+ const status = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
2661
+ step.branch && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
2662
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { className: "size-3.5" }),
2663
+ " ",
2664
+ l.branch
2665
+ ] }),
2666
+ (phase === "ready" || phase === "running") && !state?.text && /* @__PURE__ */ jsxRuntime.jsxs(
2667
+ "p",
2668
+ {
2669
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
2670
+ "data-testid": tid(`${step.id}-working`),
2671
+ children: [
2672
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
2673
+ " ",
2674
+ phase === "ready" ? l.starting : /* @__PURE__ */ jsxRuntime.jsx(StepWorking, { title: step.title, since: state?.startedAt, label: l.stepWorking })
2675
+ ]
2676
+ }
2677
+ ),
2678
+ phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
2679
+ phase === "skipped" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped }),
2680
+ extra
2681
+ ] });
2682
+ if (step.output === "artifact" && !compact3) {
2683
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2684
+ "div",
2685
+ {
2686
+ className: "grid gap-4 lg:grid-cols-[minmax(0,18rem)_minmax(0,1fr)]",
2687
+ "data-testid": tid(step.id),
2688
+ children: [
2689
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "h-fit space-y-3 p-5", children: [
2690
+ header,
2691
+ status,
2692
+ renderStepNote?.(step, run)
2693
+ ] }),
2694
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: renderAgentOutput(step, state) })
2695
+ ]
2696
+ }
2697
+ );
2698
+ }
2699
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn("space-y-3", compact3 ? "p-4" : "p-6"), "data-testid": tid(step.id), children: [
2700
+ header,
2701
+ status,
2702
+ renderAgentOutput(step, state),
2703
+ renderStepNote?.(step, run)
2704
+ ] });
2705
+ }
2706
+
2707
+ exports.ActionStepBody = ActionStepBody;
2708
+ exports.ApprovalEvidence = ApprovalEvidence;
2709
+ exports.AssigneeLine = AssigneeLine;
2710
+ exports.DEFAULT_ASSIGNEE_WORDING = DEFAULT_ASSIGNEE_WORDING;
2711
+ exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
2712
+ exports.DEFAULT_STEP_BAR_LABELS = DEFAULT_STEP_BAR_LABELS;
2713
+ exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
2714
+ exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
2715
+ exports.EMPTY_WORKFLOW_SCOPE = EMPTY_WORKFLOW_SCOPE;
2716
+ exports.PhaseMark = PhaseMark;
2717
+ exports.SKILL_PROMPT_FALLBACK_PLACEHOLDER = SKILL_PROMPT_FALLBACK_PLACEHOLDER;
2718
+ exports.SKILL_PROMPT_LABEL = SKILL_PROMPT_LABEL;
2719
+ exports.STEP_EXTRA = STEP_EXTRA;
2720
+ exports.STEP_LABEL = STEP_LABEL;
2721
+ exports.STEP_PILL = STEP_PILL;
2722
+ exports.SchemaForm = SchemaForm;
2723
+ exports.SendBackControl = SendBackControl;
2724
+ exports.StepBarFrame = StepBarFrame;
2725
+ exports.WorkflowRunner = WorkflowRunner;
2726
+ exports.WorkflowStepBar = WorkflowStepBar;
2727
+ exports.activeStepId = activeStepId;
2728
+ exports.assigneeName = assigneeName;
2729
+ exports.buildLaunch = buildLaunch;
2730
+ exports.canAssign = canAssign;
2731
+ exports.composeStepPrompt = composeStepPrompt;
2732
+ exports.composeWorkflowPrompt = composeWorkflowPrompt;
2733
+ exports.defaultInputs = defaultInputs;
2734
+ exports.dependsOn = dependsOn;
2735
+ exports.fieldToFrontmatter = fieldToFrontmatter;
2736
+ exports.fillRunText = fillRunText;
2737
+ exports.fillStepInputs = fillStepInputs;
2738
+ exports.fromPlanAssignee = fromPlanAssignee;
2739
+ exports.fromPlanDocumentRef = fromPlanDocumentRef;
2740
+ exports.fromPlanSteps = fromPlanSteps;
2741
+ exports.initialRunInputs = initialRunInputs;
2742
+ exports.inputsFromContext = inputsFromContext;
2743
+ exports.isEmptyWorkflowScope = isEmptyWorkflowScope;
2744
+ exports.isIncompleteSignal = isIncompleteSignal;
2745
+ exports.isPersonAction = isPersonAction;
2746
+ exports.isPersonStep = isPersonStep;
2747
+ exports.isRunFinished = isRunFinished;
2748
+ exports.isSteppedWorkflow = isSteppedWorkflow;
2749
+ exports.isWorkflowScope = isWorkflowScope;
2750
+ exports.layoutFromPlanSteps = layoutFromPlanSteps;
2751
+ exports.nextAction = nextAction;
2752
+ exports.orderSteps = orderSteps;
2753
+ exports.promptFieldName = promptFieldName;
2754
+ exports.reviewInstructions = reviewInstructions;
2755
+ exports.runFields = runFields;
2756
+ exports.runFieldsOf = runFieldsOf;
2757
+ exports.runThreadTitle = runThreadTitle;
2758
+ exports.sendBackTargets = sendBackTargets;
2759
+ exports.skillToWorkflow = skillToWorkflow;
2760
+ exports.splitDocRef = splitDocRef;
2761
+ exports.stepConfigProblems = stepConfigProblems;
2762
+ exports.stepDependencies = stepDependencies;
2763
+ exports.stepFields = stepFields;
2764
+ exports.stepLevels = stepLevels;
2765
+ exports.stepPhase = stepPhase;
2766
+ exports.stepPillTone = stepPillTone;
2767
+ exports.stepStatesFromActivity = stepStatesFromActivity;
2768
+ exports.stepWindow = stepWindow;
2769
+ exports.toPlanAssignee = toPlanAssignee;
2770
+ exports.toPlanDocumentRef = toPlanDocumentRef;
2771
+ exports.toPlanSteps = toPlanSteps;
2772
+ exports.upstreamSteps = upstreamSteps;
2773
+ exports.useWorkflowView = useWorkflowView;
2774
+ exports.validateInputs = validateInputs;
2775
+ exports.validateStep = validateStep;
2776
+ exports.validateWorkflowGraph = validateWorkflowGraph;
2777
+ exports.workflowAccepts = workflowAccepts;
2778
+ exports.workflowFromFrontmatter = workflowFromFrontmatter;
2779
+ exports.workflowSteps = workflowSteps;
2780
+ exports.workflowsAccepting = workflowsAccepting;
2781
+ exports.workflowsForHost = workflowsForHost;
2782
+ //# sourceMappingURL=chunk-VFIZYSZB.cjs.map
2783
+ //# sourceMappingURL=chunk-VFIZYSZB.cjs.map