@arbidocs/blocks 0.4.71 → 0.4.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/agents/index.cjs +404 -266
  2. package/dist/agents/index.js +10 -8
  3. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  4. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +58 -0
  5. package/dist/agents/tasks/index.d.ts +1 -0
  6. package/dist/agents/workflows/WorkflowRunner.d.ts +70 -0
  7. package/dist/agents/workflows/index.d.ts +7 -1
  8. package/dist/agents/workflows/planSteps.d.ts +28 -0
  9. package/dist/agents/workflows/run.d.ts +97 -0
  10. package/dist/agents/workflows/skillMarkdown.d.ts +15 -0
  11. package/dist/agents/workflows/types.d.ts +109 -0
  12. package/dist/agents/workflows/useWorkflowPreview.d.ts +14 -0
  13. package/dist/agents/workflows/useWorkflowView.d.ts +54 -0
  14. package/dist/agents/workflows/workflow.d.ts +3 -1
  15. package/dist/calendar/CalendarGrid.d.ts +2 -0
  16. package/dist/calendar/CalendarList.d.ts +2 -0
  17. package/dist/calendar/CalendarSettingsForm.d.ts +2 -0
  18. package/dist/calendar/EventDetails.d.ts +2 -0
  19. package/dist/calendar/EventEditor.d.ts +2 -0
  20. package/dist/calendar/MiniMonth.d.ts +2 -0
  21. package/dist/calendar/RecurrenceEditor.d.ts +13 -0
  22. package/dist/calendar/RoomFinder.d.ts +2 -0
  23. package/dist/calendar/SchedulingAssistant.d.ts +2 -0
  24. package/dist/calendar/ScopeDialog.d.ts +2 -0
  25. package/dist/calendar/TimeZonePicker.d.ts +2 -0
  26. package/dist/calendar/colors.d.ts +4 -0
  27. package/dist/calendar/draft.d.ts +43 -0
  28. package/dist/calendar/format.d.ts +14 -0
  29. package/dist/calendar/grid-model.d.ts +24 -0
  30. package/dist/calendar/index.cjs +4122 -0
  31. package/dist/calendar/index.cjs.map +1 -0
  32. package/dist/calendar/index.d.ts +30 -0
  33. package/dist/calendar/index.js +4043 -0
  34. package/dist/calendar/index.js.map +1 -0
  35. package/dist/calendar/labels.d.ts +4 -0
  36. package/dist/calendar/recurrence-labels.d.ts +22 -0
  37. package/dist/calendar/recurrence.d.ts +66 -0
  38. package/dist/calendar/reminders.d.ts +26 -0
  39. package/dist/calendar/scheduling.d.ts +27 -0
  40. package/dist/calendar/types.d.ts +605 -0
  41. package/dist/calendar/ui.d.ts +16 -0
  42. package/dist/calendar/zone.d.ts +56 -0
  43. package/dist/chat/index.cjs +123 -123
  44. package/dist/chat/index.js +3 -3
  45. package/dist/chunk-2P3T23C7.js +1250 -0
  46. package/dist/chunk-2P3T23C7.js.map +1 -0
  47. package/dist/{chunk-XNRGCQPZ.cjs → chunk-3SFFTSOI.cjs} +5 -5
  48. package/dist/{chunk-XNRGCQPZ.cjs.map → chunk-3SFFTSOI.cjs.map} +1 -1
  49. package/dist/{chunk-7WM62NMM.cjs → chunk-6OL5S7MJ.cjs} +5 -2
  50. package/dist/chunk-6OL5S7MJ.cjs.map +1 -0
  51. package/dist/chunk-7D737FLE.cjs +43 -0
  52. package/dist/chunk-7D737FLE.cjs.map +1 -0
  53. package/dist/{chunk-VUEZARW5.cjs → chunk-B3WCKBJ7.cjs} +278 -5
  54. package/dist/chunk-B3WCKBJ7.cjs.map +1 -0
  55. package/dist/{chunk-L5UPP2HC.js → chunk-D46ZAPEE.js} +5 -2
  56. package/dist/chunk-D46ZAPEE.js.map +1 -0
  57. package/dist/{chunk-LFGJAZ5H.js → chunk-DDF5GPIJ.js} +6 -36
  58. package/dist/chunk-DDF5GPIJ.js.map +1 -0
  59. package/dist/chunk-DETZZBG2.cjs +91 -0
  60. package/dist/chunk-DETZZBG2.cjs.map +1 -0
  61. package/dist/chunk-EVUEIBNU.js +89 -0
  62. package/dist/chunk-EVUEIBNU.js.map +1 -0
  63. package/dist/{chunk-CXWESDIZ.cjs → chunk-F4RUCUXF.cjs} +6 -6
  64. package/dist/{chunk-CXWESDIZ.cjs.map → chunk-F4RUCUXF.cjs.map} +1 -1
  65. package/dist/{chunk-DABEWNL2.js → chunk-G5DP27DU.js} +3 -3
  66. package/dist/{chunk-DABEWNL2.js.map → chunk-G5DP27DU.js.map} +1 -1
  67. package/dist/{chunk-VZGBCBYB.js → chunk-GJV2G4FC.js} +276 -7
  68. package/dist/chunk-GJV2G4FC.js.map +1 -0
  69. package/dist/chunk-GTNUQBXI.cjs +1296 -0
  70. package/dist/chunk-GTNUQBXI.cjs.map +1 -0
  71. package/dist/{chunk-7M22KND4.cjs → chunk-IUR565UW.cjs} +303 -530
  72. package/dist/chunk-IUR565UW.cjs.map +1 -0
  73. package/dist/{chunk-5DM6VU4L.cjs → chunk-KJ3QEKOJ.cjs} +3 -3
  74. package/dist/{chunk-5DM6VU4L.cjs.map → chunk-KJ3QEKOJ.cjs.map} +1 -1
  75. package/dist/{chunk-THO7DZNN.cjs → chunk-MUMH3Z6K.cjs} +20 -15
  76. package/dist/chunk-MUMH3Z6K.cjs.map +1 -0
  77. package/dist/{chunk-3TVTG7FK.js → chunk-ORA2XE7U.js} +4 -4
  78. package/dist/{chunk-3TVTG7FK.js.map → chunk-ORA2XE7U.js.map} +1 -1
  79. package/dist/{chunk-5HOAOKZL.js → chunk-OYMWV45N.js} +21 -16
  80. package/dist/chunk-OYMWV45N.js.map +1 -0
  81. package/dist/{chunk-HLMFU7L2.js → chunk-QDNXEB3T.js} +272 -488
  82. package/dist/chunk-QDNXEB3T.js.map +1 -0
  83. package/dist/{chunk-ILGHS6ZV.js → chunk-SB5ZKOYN.js} +3 -3
  84. package/dist/{chunk-ILGHS6ZV.js.map → chunk-SB5ZKOYN.js.map} +1 -1
  85. package/dist/{chunk-CPMNAJLF.js → chunk-TX2ZICS7.js} +24 -4
  86. package/dist/chunk-TX2ZICS7.js.map +1 -0
  87. package/dist/{chunk-2ZTONLT5.cjs → chunk-ULWRNGGE.cjs} +25 -4
  88. package/dist/chunk-ULWRNGGE.cjs.map +1 -0
  89. package/dist/{chunk-BMWZTNZB.js → chunk-VRPRAU3J.js} +3 -3
  90. package/dist/{chunk-BMWZTNZB.js.map → chunk-VRPRAU3J.js.map} +1 -1
  91. package/dist/{chunk-LTA2IAQB.cjs → chunk-WOYUXVVQ.cjs} +8 -8
  92. package/dist/{chunk-LTA2IAQB.cjs.map → chunk-WOYUXVVQ.cjs.map} +1 -1
  93. package/dist/chunk-XD2M6LIG.js +41 -0
  94. package/dist/chunk-XD2M6LIG.js.map +1 -0
  95. package/dist/{chunk-WBDK4PIA.cjs → chunk-Z5VUZ6YD.cjs} +6 -37
  96. package/dist/chunk-Z5VUZ6YD.cjs.map +1 -0
  97. package/dist/collaboration/index.cjs +44 -45
  98. package/dist/collaboration/index.js +2 -3
  99. package/dist/connect/docx.cjs +2 -2
  100. package/dist/connect/docx.js +1 -1
  101. package/dist/connect/index.cjs +370 -48
  102. package/dist/connect/index.cjs.map +1 -1
  103. package/dist/connect/index.d.ts +2 -1
  104. package/dist/connect/index.js +331 -12
  105. package/dist/connect/index.js.map +1 -1
  106. package/dist/connection/ConnectedSettings.d.ts +13 -0
  107. package/dist/connection/ConnectedWorkflowBuilder.d.ts +44 -0
  108. package/dist/connection/ConnectedWorkflowRunner.d.ts +27 -0
  109. package/dist/connection/useWorkflowThread.d.ts +34 -0
  110. package/dist/document-tools/index.cjs +4 -5
  111. package/dist/document-tools/index.cjs.map +1 -1
  112. package/dist/document-tools/index.js +1 -2
  113. package/dist/document-tools/index.js.map +1 -1
  114. package/dist/facts/index.cjs +1 -1
  115. package/dist/facts/index.js +1 -1
  116. package/dist/files/import/index.d.ts +0 -1
  117. package/dist/files/index.cjs +31 -169
  118. package/dist/files/index.cjs.map +1 -1
  119. package/dist/files/index.js +8 -147
  120. package/dist/files/index.js.map +1 -1
  121. package/dist/home/index.cjs +21 -20
  122. package/dist/home/index.cjs.map +1 -1
  123. package/dist/home/index.js +3 -2
  124. package/dist/home/index.js.map +1 -1
  125. package/dist/index.cjs +680 -542
  126. package/dist/index.cjs.map +1 -1
  127. package/dist/index.js +15 -13
  128. package/dist/index.js.map +1 -1
  129. package/dist/settings/Billing.d.ts +4 -0
  130. package/dist/settings/IdentityVerification.d.ts +83 -0
  131. package/dist/settings/PlanBadge.d.ts +2 -2
  132. package/dist/settings/PlanCard.d.ts +6 -1
  133. package/dist/settings/ProfileCard.d.ts +5 -1
  134. package/dist/settings/SubscriptionParts.d.ts +6 -2
  135. package/dist/settings/index.cjs +128 -95
  136. package/dist/settings/index.cjs.map +1 -1
  137. package/dist/settings/index.d.ts +1 -0
  138. package/dist/settings/index.js +64 -47
  139. package/dist/settings/index.js.map +1 -1
  140. package/dist/shell/ActionCluster.d.ts +3 -1
  141. package/dist/shell/index.cjs +54 -54
  142. package/dist/shell/index.js +2 -2
  143. package/dist/studio/index.cjs +6 -6
  144. package/dist/studio/index.js +4 -4
  145. package/dist/workflow-canvas/StepInspector.d.ts +46 -0
  146. package/dist/workflow-canvas/TriggerInspector.d.ts +46 -0
  147. package/dist/workflow-canvas/WorkflowBuilder.d.ts +55 -0
  148. package/dist/workflow-canvas/WorkflowCanvas.d.ts +65 -0
  149. package/dist/workflow-canvas/edit.d.ts +54 -0
  150. package/dist/workflow-canvas/index.cjs +1609 -0
  151. package/dist/workflow-canvas/index.cjs.map +1 -0
  152. package/dist/workflow-canvas/index.d.ts +13 -0
  153. package/dist/workflow-canvas/index.js +1579 -0
  154. package/dist/workflow-canvas/index.js.map +1 -0
  155. package/dist/workflow-canvas/trigger.d.ts +51 -0
  156. package/dist/workspaces/index.cjs +2 -3
  157. package/dist/workspaces/index.cjs.map +1 -1
  158. package/dist/workspaces/index.js +1 -2
  159. package/dist/workspaces/index.js.map +1 -1
  160. package/package.json +41 -12
  161. package/src/calendar/calendar.css +316 -0
  162. package/src/workflow-canvas/canvas.css +113 -0
  163. package/dist/chunk-2ZTONLT5.cjs.map +0 -1
  164. package/dist/chunk-5HOAOKZL.js.map +0 -1
  165. package/dist/chunk-7M22KND4.cjs.map +0 -1
  166. package/dist/chunk-7WM62NMM.cjs.map +0 -1
  167. package/dist/chunk-CPMNAJLF.js.map +0 -1
  168. package/dist/chunk-DCDVWPMB.cjs +0 -29
  169. package/dist/chunk-DCDVWPMB.cjs.map +0 -1
  170. package/dist/chunk-HLMFU7L2.js.map +0 -1
  171. package/dist/chunk-L5UPP2HC.js.map +0 -1
  172. package/dist/chunk-LFGJAZ5H.js.map +0 -1
  173. package/dist/chunk-THO7DZNN.cjs.map +0 -1
  174. package/dist/chunk-TJMKFY5P.js +0 -27
  175. package/dist/chunk-TJMKFY5P.js.map +0 -1
  176. package/dist/chunk-VUEZARW5.cjs.map +0 -1
  177. package/dist/chunk-VZGBCBYB.js.map +0 -1
  178. package/dist/chunk-WBDK4PIA.cjs.map +0 -1
  179. package/dist/files/import/CalendarImportRow.d.ts +0 -26
@@ -0,0 +1,1609 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkMUMH3Z6K_cjs = require('../chunk-MUMH3Z6K.cjs');
5
+ var chunkIUR565UW_cjs = require('../chunk-IUR565UW.cjs');
6
+ require('../chunk-YJQVLVBJ.cjs');
7
+ require('../chunk-ZW6FPIFC.cjs');
8
+ var chunkGTNUQBXI_cjs = require('../chunk-GTNUQBXI.cjs');
9
+ require('../chunk-7RGLTF76.cjs');
10
+ require('../chunk-3AFWGEDJ.cjs');
11
+ require('../chunk-VFUWWH52.cjs');
12
+ require('../chunk-DETZZBG2.cjs');
13
+ require('../chunk-IA7RTPT3.cjs');
14
+ require('../chunk-2EI7NCUA.cjs');
15
+ require('../chunk-Z5VUZ6YD.cjs');
16
+ require('../chunk-7D737FLE.cjs');
17
+ require('../chunk-OB5F4577.cjs');
18
+ require('../chunk-V3L5DONY.cjs');
19
+ require('../chunk-7UTB4PHM.cjs');
20
+ require('../chunk-FX3K6LNZ.cjs');
21
+ require('../chunk-PPCATBOY.cjs');
22
+ require('../chunk-C54XEN5T.cjs');
23
+ require('../chunk-KDG6FER6.cjs');
24
+ require('../chunk-ULWRNGGE.cjs');
25
+ require('../chunk-MHVNT4J3.cjs');
26
+ require('../chunk-DES3K4SD.cjs');
27
+ var react = require('react');
28
+ var react$2 = require('@arbidocs/react');
29
+ var ui = require('@arbidocs/react/ui');
30
+ var lucideReact = require('lucide-react');
31
+ var jsxRuntime = require('react/jsx-runtime');
32
+ var react$1 = require('@xyflow/react');
33
+
34
+ // src/workflow-canvas/edit.ts
35
+ function newSteppedWorkflow(id, title) {
36
+ return {
37
+ id,
38
+ title,
39
+ description: "",
40
+ inputs: [],
41
+ landing: "chat",
42
+ schedulable: false,
43
+ run: { kind: "steps", steps: [] }
44
+ };
45
+ }
46
+ function withSteps(workflow, steps, layout) {
47
+ const run = workflow.run.kind === "steps" ? workflow.run : { kind: "steps", steps: [] };
48
+ return {
49
+ ...workflow,
50
+ run: { ...run, steps: chunkGTNUQBXI_cjs.orderSteps(steps), layout: layout ?? run.layout }
51
+ };
52
+ }
53
+ var layoutOf = (workflow) => workflow.run.kind === "steps" && workflow.run.layout || {};
54
+ var explicit = (steps) => steps.map((s) => ({ ...s, after: chunkGTNUQBXI_cjs.stepDependencies(steps, s.id) }));
55
+ function stepIdFor(steps, title) {
56
+ const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/^[^a-z]+/, "") || "step";
57
+ const taken = new Set(steps.map((s) => s.id));
58
+ if (!taken.has(base)) return base;
59
+ let n = 2;
60
+ while (taken.has(`${base}-${n}`)) n++;
61
+ return `${base}-${n}`;
62
+ }
63
+ var DEFAULT_TITLES = {
64
+ form: "Details",
65
+ upload: "Upload files",
66
+ agent: "Agent step",
67
+ review: "Review"
68
+ };
69
+ function blankStep(kind, id, title) {
70
+ switch (kind) {
71
+ case "form":
72
+ return { id, kind, title, inputs: [] };
73
+ case "upload":
74
+ return { id, kind, title };
75
+ case "agent":
76
+ return { id, kind, title, run: { kind: "prompt", promptTemplate: "" } };
77
+ case "review":
78
+ return { id, kind, title, instructions: "" };
79
+ }
80
+ }
81
+ function addStep(workflow, kind, options = {}) {
82
+ const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
83
+ const title = options.title ?? DEFAULT_TITLES[kind];
84
+ const id = stepIdFor(steps, title);
85
+ const step = { ...blankStep(kind, id, title), after: options.after ? [options.after] : [] };
86
+ const layout = { ...layoutOf(workflow) };
87
+ if (options.position) layout[id] = options.position;
88
+ return { workflow: withSteps(workflow, [...steps, step], layout), id };
89
+ }
90
+ function removeStep(workflow, id) {
91
+ const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
92
+ const removed = steps.find((s) => s.id === id);
93
+ if (!removed) return workflow;
94
+ const bridged = steps.filter((s) => s.id !== id).map(
95
+ (s) => s.after?.includes(id) ? {
96
+ ...s,
97
+ after: [.../* @__PURE__ */ new Set([...s.after.filter((d) => d !== id), ...removed.after ?? []])]
98
+ } : s
99
+ );
100
+ const { [id]: _gone, ...layout } = layoutOf(workflow);
101
+ return withSteps(workflow, bridged, layout);
102
+ }
103
+ function connectSteps(workflow, from, to) {
104
+ const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
105
+ if (from === to || !steps.some((s) => s.id === from) || chunkGTNUQBXI_cjs.dependsOn(steps, from, to)) {
106
+ return workflow;
107
+ }
108
+ return withSteps(
109
+ workflow,
110
+ steps.map(
111
+ (s) => s.id === to && !s.after?.includes(from) ? { ...s, after: [...s.after ?? [], from] } : s
112
+ )
113
+ );
114
+ }
115
+ var wouldCycle = (workflow, from, to) => from === to || chunkGTNUQBXI_cjs.dependsOn(chunkGTNUQBXI_cjs.workflowSteps(workflow), from, to);
116
+ function disconnectSteps(workflow, from, to) {
117
+ const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
118
+ return withSteps(
119
+ workflow,
120
+ steps.map((s) => s.id === to ? { ...s, after: (s.after ?? []).filter((d) => d !== from) } : s)
121
+ );
122
+ }
123
+ function updateStep(workflow, id, patch) {
124
+ const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
125
+ return withSteps(
126
+ workflow,
127
+ steps.map(
128
+ (s) => s.id === id ? { ...s, ...patch, id: s.id, kind: s.kind } : s
129
+ )
130
+ );
131
+ }
132
+ var renameIn = (text, from, to) => text.replace(
133
+ /\{\{([^}]*)\}\}/g,
134
+ (_, inner) => `{{${inner.split("||").map((part) => part.trim() === from ? part.replace(from, to) : part).join("||")}}}`
135
+ );
136
+ function renameInput(workflow, from, to) {
137
+ if (from === to) return workflow;
138
+ const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow).map((s) => {
139
+ if (s.kind === "agent")
140
+ return {
141
+ ...s,
142
+ with: s.with ? Object.fromEntries(Object.entries(s.with).map(([k, v]) => [k, renameIn(v, from, to)])) : s.with,
143
+ run: s.run?.kind === "prompt" ? { ...s.run, promptTemplate: renameIn(s.run.promptTemplate, from, to) } : s.run
144
+ };
145
+ if (s.kind === "review" && s.instructions)
146
+ return { ...s, instructions: renameIn(s.instructions, from, to) };
147
+ return s;
148
+ });
149
+ return withSteps(workflow, steps);
150
+ }
151
+ function moveStep(workflow, id, position) {
152
+ return withSteps(workflow, chunkGTNUQBXI_cjs.workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
153
+ }
154
+ var COLUMN = 300;
155
+ var ROW = 140;
156
+ function autoLayout(steps) {
157
+ const layout = {};
158
+ chunkGTNUQBXI_cjs.stepLevels(steps).forEach(
159
+ (level, x) => level.forEach((s, y) => {
160
+ layout[s.id] = { x: x * COLUMN, y: (y - (level.length - 1) / 2) * ROW };
161
+ })
162
+ );
163
+ return layout;
164
+ }
165
+ function layoutWithDefaults(workflow) {
166
+ const auto = autoLayout(chunkGTNUQBXI_cjs.workflowSteps(workflow));
167
+ return { ...auto, ...layoutOf(workflow) };
168
+ }
169
+ var DEFAULT_STEP_INSPECTOR_LABELS = {
170
+ workflow: "Workflow",
171
+ title: "Title",
172
+ description: "Description",
173
+ waitsFor: "Waits for",
174
+ startsWithRun: "Starts with the run",
175
+ fields: "Fields",
176
+ addField: "Add field",
177
+ fieldLabel: "Label",
178
+ fieldType: "Type",
179
+ required: "Required",
180
+ runs: "Runs",
181
+ ownPrompt: "Its own instruction",
182
+ prompt: "Instruction",
183
+ promptHint: "Use {{field}} for an input and {{steps.<id>}} for an earlier step\u2019s answer.",
184
+ inputFor: "Input",
185
+ thread: "Where it runs",
186
+ threadMain: "In the run\u2019s thread (sees the conversation so far)",
187
+ threadBranch: "On a branch (delivers only its result to the thread)",
188
+ output: "Shows",
189
+ outputAnswer: "The answer",
190
+ outputArtifact: "A drafted document",
191
+ uploadRequired: "Files are required",
192
+ hint: "Hint",
193
+ instructions: "What to review",
194
+ instructionsHint: "Shown on the review task; {{field}} and {{steps.<id>}} work here.",
195
+ deleteStep: "Delete step"
196
+ };
197
+ var FIELD_TYPES = ["text", "longtext", "boolean", "number", "date", "scope"];
198
+ var selectClass = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
199
+ function Field({ label, children, hint }) {
200
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
201
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: label }),
202
+ children,
203
+ hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: hint })
204
+ ] });
205
+ }
206
+ var fieldName = (label, taken) => {
207
+ const base = label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").replace(/^[^a-z]+/, "") || "field";
208
+ let name = base;
209
+ let n = 2;
210
+ while (taken.includes(name)) name = `${base}_${n++}`;
211
+ return name;
212
+ };
213
+ function StepInspector({
214
+ workflow,
215
+ stepId,
216
+ onChange,
217
+ onSelect,
218
+ workflows = [],
219
+ labels,
220
+ testId = "step-inspector"
221
+ }) {
222
+ const l = { ...DEFAULT_STEP_INSPECTOR_LABELS, ...labels };
223
+ const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
224
+ const step = steps.find((s) => s.id === stepId);
225
+ const run = workflow.run.kind === "steps" ? workflow.run : void 0;
226
+ if (!step || !run) {
227
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": `${testId}-workflow`, children: [
228
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: l.workflow }),
229
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.title, children: /* @__PURE__ */ jsxRuntime.jsx(
230
+ ui.Input,
231
+ {
232
+ value: workflow.title,
233
+ onChange: (e) => onChange({ ...workflow, title: e.target.value }),
234
+ "data-testid": `${testId}-workflow-title`
235
+ }
236
+ ) }),
237
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.description, children: /* @__PURE__ */ jsxRuntime.jsx(
238
+ ui.Textarea,
239
+ {
240
+ value: workflow.description,
241
+ rows: 2,
242
+ onChange: (e) => onChange({ ...workflow, description: e.target.value })
243
+ }
244
+ ) })
245
+ ] });
246
+ }
247
+ const patch = (p) => onChange(updateStep(workflow, step.id, p));
248
+ const deps = chunkGTNUQBXI_cjs.stepDependencies(steps, step.id);
249
+ const titleOf = (id) => steps.find((s) => s.id === id)?.title ?? id;
250
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": `${testId}-step`, children: [
251
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
252
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold", children: step.title }),
253
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground", children: step.id })
254
+ ] }),
255
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.title, children: /* @__PURE__ */ jsxRuntime.jsx(
256
+ ui.Input,
257
+ {
258
+ value: step.title,
259
+ onChange: (e) => patch({ title: e.target.value }),
260
+ "data-testid": `${testId}-title`
261
+ }
262
+ ) }),
263
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.description, children: /* @__PURE__ */ jsxRuntime.jsx(
264
+ ui.Textarea,
265
+ {
266
+ value: step.description ?? "",
267
+ rows: 2,
268
+ onChange: (e) => patch({ description: e.target.value || void 0 })
269
+ }
270
+ ) }),
271
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.waitsFor, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5", "data-testid": `${testId}-waits-for`, children: [
272
+ deps.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: l.startsWithRun }),
273
+ deps.map((d) => /* @__PURE__ */ jsxRuntime.jsxs(
274
+ "span",
275
+ {
276
+ className: "inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 text-xs",
277
+ children: [
278
+ titleOf(d),
279
+ /* @__PURE__ */ jsxRuntime.jsx(
280
+ "button",
281
+ {
282
+ type: "button",
283
+ "aria-label": `${titleOf(d)} \xD7`,
284
+ onClick: () => onChange(disconnectSteps(workflow, d, step.id)),
285
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3" })
286
+ }
287
+ )
288
+ ]
289
+ },
290
+ d
291
+ ))
292
+ ] }) }),
293
+ step.kind === "form" && /* @__PURE__ */ jsxRuntime.jsx(
294
+ FormFields,
295
+ {
296
+ fields: step.inputs,
297
+ taken: steps.flatMap((s) => s.kind === "form" && s.id !== step.id ? s.inputs : []).map((f) => f.name),
298
+ onChange: (inputs) => {
299
+ const renamed = step.inputs.flatMap(
300
+ (f, i) => inputs[i] && inputs[i].name !== f.name ? [[f.name, inputs[i].name]] : []
301
+ );
302
+ onChange(
303
+ renamed.reduce(
304
+ (w, [from, to]) => renameInput(w, from, to),
305
+ updateStep(workflow, step.id, { inputs })
306
+ )
307
+ );
308
+ },
309
+ l,
310
+ testId
311
+ }
312
+ ),
313
+ step.kind === "upload" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
314
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
315
+ /* @__PURE__ */ jsxRuntime.jsx(
316
+ ui.Checkbox,
317
+ {
318
+ checked: !!step.required,
319
+ onCheckedChange: (v) => patch({ required: v === true || void 0 })
320
+ }
321
+ ),
322
+ l.uploadRequired
323
+ ] }),
324
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.hint, children: /* @__PURE__ */ jsxRuntime.jsx(
325
+ ui.Input,
326
+ {
327
+ value: step.hint ?? "",
328
+ onChange: (e) => patch({ hint: e.target.value || void 0 })
329
+ }
330
+ ) })
331
+ ] }),
332
+ step.kind === "agent" && /* @__PURE__ */ jsxRuntime.jsx(AgentSettings, { step, workflows, patch, l, testId }),
333
+ step.kind === "review" && /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsxRuntime.jsx(
334
+ ui.Textarea,
335
+ {
336
+ value: step.instructions ?? "",
337
+ rows: 4,
338
+ onChange: (e) => patch({ instructions: e.target.value || void 0 }),
339
+ "data-testid": `${testId}-instructions`
340
+ }
341
+ ) }),
342
+ /* @__PURE__ */ jsxRuntime.jsxs(
343
+ ui.Button,
344
+ {
345
+ variant: "ghost",
346
+ size: "sm",
347
+ className: "text-destructive",
348
+ onClick: () => {
349
+ onChange(removeStep(workflow, step.id));
350
+ onSelect?.(null);
351
+ },
352
+ "data-testid": `${testId}-delete`,
353
+ children: [
354
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" }),
355
+ " ",
356
+ l.deleteStep
357
+ ]
358
+ }
359
+ )
360
+ ] });
361
+ }
362
+ function FormFields({
363
+ fields,
364
+ taken,
365
+ onChange,
366
+ l,
367
+ testId
368
+ }) {
369
+ const set = (i, p) => onChange(fields.map((f, j) => j === i ? { ...f, ...p } : f));
370
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.fields, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": `${testId}-fields`, children: [
371
+ fields.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 rounded-md border border-border p-2", children: [
372
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
373
+ /* @__PURE__ */ jsxRuntime.jsx(
374
+ ui.Input,
375
+ {
376
+ value: f.label,
377
+ "aria-label": l.fieldLabel,
378
+ onChange: (e) => set(i, {
379
+ label: e.target.value,
380
+ name: fieldName(e.target.value, [
381
+ ...taken,
382
+ ...fields.filter((_, j) => j !== i).map((x) => x.name)
383
+ ])
384
+ }),
385
+ className: "h-8"
386
+ }
387
+ ),
388
+ /* @__PURE__ */ jsxRuntime.jsx(
389
+ "button",
390
+ {
391
+ type: "button",
392
+ "aria-label": `${f.label} \xD7`,
393
+ onClick: () => onChange(fields.filter((_, j) => j !== i)),
394
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4 text-muted-foreground" })
395
+ }
396
+ )
397
+ ] }),
398
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
399
+ /* @__PURE__ */ jsxRuntime.jsx(
400
+ "select",
401
+ {
402
+ "aria-label": l.fieldType,
403
+ className: ui.cn(selectClass, "h-8"),
404
+ value: f.type,
405
+ onChange: (e) => set(i, { type: e.target.value }),
406
+ children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t))
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex shrink-0 items-center gap-1.5 text-xs", children: [
410
+ /* @__PURE__ */ jsxRuntime.jsx(
411
+ ui.Checkbox,
412
+ {
413
+ checked: !!f.required,
414
+ onCheckedChange: (v) => set(i, { required: v === true || void 0 })
415
+ }
416
+ ),
417
+ l.required
418
+ ] }),
419
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "shrink-0 text-[11px] text-muted-foreground", children: `{{${f.name}}}` })
420
+ ] })
421
+ ] }, i)),
422
+ /* @__PURE__ */ jsxRuntime.jsxs(
423
+ ui.Button,
424
+ {
425
+ variant: "outline",
426
+ size: "sm",
427
+ onClick: () => onChange([
428
+ ...fields,
429
+ {
430
+ name: fieldName("Field", [...taken, ...fields.map((f) => f.name)]),
431
+ type: "text",
432
+ label: "Field"
433
+ }
434
+ ]),
435
+ "data-testid": `${testId}-add-field`,
436
+ children: [
437
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }),
438
+ " ",
439
+ l.addField
440
+ ]
441
+ }
442
+ )
443
+ ] }) });
444
+ }
445
+ function AgentSettings({
446
+ step,
447
+ workflows,
448
+ patch,
449
+ l,
450
+ testId
451
+ }) {
452
+ const target = step.workflow ? workflows.find((w) => w.id === step.workflow) : void 0;
453
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
454
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.runs, children: /* @__PURE__ */ jsxRuntime.jsxs(
455
+ "select",
456
+ {
457
+ className: selectClass,
458
+ value: step.workflow ?? "",
459
+ onChange: (e) => e.target.value ? patch({ workflow: e.target.value, run: void 0, with: step.with ?? {} }) : patch({
460
+ workflow: void 0,
461
+ with: void 0,
462
+ run: { kind: "prompt", promptTemplate: "" }
463
+ }),
464
+ "data-testid": `${testId}-runs`,
465
+ children: [
466
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.ownPrompt }),
467
+ workflows.map((w) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: w.id, children: w.title }, w.id)),
468
+ step.workflow && !target && /* @__PURE__ */ jsxRuntime.jsx("option", { value: step.workflow, children: step.workflow })
469
+ ]
470
+ }
471
+ ) }),
472
+ step.workflow ? (target?.inputs ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsx(Field, { label: `${l.inputFor}: ${f.label}`, children: /* @__PURE__ */ jsxRuntime.jsx(
473
+ ui.Input,
474
+ {
475
+ value: step.with?.[f.name] ?? "",
476
+ placeholder: `{{${f.name}}}`,
477
+ onChange: (e) => patch({ with: { ...step.with, [f.name]: e.target.value } }),
478
+ "data-testid": `${testId}-with-${f.name}`
479
+ }
480
+ ) }, f.name)) : step.run?.kind === "prompt" ? /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.prompt, hint: l.promptHint, children: /* @__PURE__ */ jsxRuntime.jsx(
481
+ ui.Textarea,
482
+ {
483
+ value: step.run.promptTemplate,
484
+ rows: 5,
485
+ onChange: (e) => patch({ run: { kind: "prompt", promptTemplate: e.target.value } }),
486
+ "data-testid": `${testId}-prompt`
487
+ }
488
+ ) }) : null,
489
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.thread, children: /* @__PURE__ */ jsxRuntime.jsxs(
490
+ "select",
491
+ {
492
+ className: selectClass,
493
+ value: step.branch ? "branch" : "main",
494
+ onChange: (e) => patch({ branch: e.target.value === "branch" || void 0 }),
495
+ "data-testid": `${testId}-thread`,
496
+ children: [
497
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "main", children: l.threadMain }),
498
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "branch", children: l.threadBranch })
499
+ ]
500
+ }
501
+ ) }),
502
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.output, children: /* @__PURE__ */ jsxRuntime.jsxs(
503
+ "select",
504
+ {
505
+ className: selectClass,
506
+ value: step.output ?? "answer",
507
+ onChange: (e) => patch({ output: e.target.value === "artifact" ? "artifact" : void 0 }),
508
+ children: [
509
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "answer", children: l.outputAnswer }),
510
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "artifact", children: l.outputArtifact })
511
+ ]
512
+ }
513
+ ) })
514
+ ] });
515
+ }
516
+ var DEFAULT_TRIGGER_INSPECTOR_LABELS = {
517
+ heading: "Start",
518
+ start: "Starts",
519
+ starts: {
520
+ manual: "When someone runs it",
521
+ once: "Once, at a time",
522
+ repeat: "On a schedule",
523
+ event: "When something happens",
524
+ task: "When a task is done"
525
+ },
526
+ runAt: "When",
527
+ event: "Event",
528
+ eventPlaceholder: "Pick an event",
529
+ afterTask: "After this task",
530
+ afterTaskPlaceholder: "Pick a task",
531
+ agent: "Runs as",
532
+ access: "Access when nobody is there",
533
+ accessAsk: "Ask me each run",
534
+ accessStanding: "Keep access"
535
+ };
536
+ function triggerSummary(trigger, options = {}) {
537
+ const l = { ...DEFAULT_TRIGGER_INSPECTOR_LABELS, ...options.labels };
538
+ switch (trigger.start) {
539
+ case "once":
540
+ return trigger.runAt ? new Date(trigger.runAt).toLocaleString() : l.starts.once;
541
+ case "repeat":
542
+ return trigger.rrule ? chunkIUR565UW_cjs.describeRRule(trigger.rrule) : l.starts.repeat;
543
+ case "event":
544
+ return trigger.eventKind && options.eventLabel?.(trigger.eventKind) || trigger.eventKind || l.starts.event;
545
+ case "task":
546
+ return trigger.afterTaskId && options.taskLabel?.(trigger.afterTaskId) || l.starts.task;
547
+ default:
548
+ return l.starts.manual;
549
+ }
550
+ }
551
+ var selectClass2 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
552
+ var STARTS = ["manual", "once", "repeat", "event", "task"];
553
+ function TriggerInspector({
554
+ trigger,
555
+ onChange,
556
+ agents = [],
557
+ eventKinds = [],
558
+ tasks = [],
559
+ labels,
560
+ testId = "trigger-inspector"
561
+ }) {
562
+ const l = { ...DEFAULT_TRIGGER_INSPECTOR_LABELS, ...labels };
563
+ const set = (patch) => onChange({ ...trigger, ...patch });
564
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": testId, children: [
565
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: l.heading }),
566
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
567
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.start }),
568
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-1.5", role: "radiogroup", "aria-label": l.start, children: STARTS.map((start) => /* @__PURE__ */ jsxRuntime.jsx(
569
+ "button",
570
+ {
571
+ type: "button",
572
+ role: "radio",
573
+ "aria-checked": trigger.start === start,
574
+ onClick: () => set({ start }),
575
+ className: ui.cn(
576
+ "rounded-md border px-3 py-2 text-left text-sm transition-colors",
577
+ trigger.start === start ? "border-primary bg-primary/10 text-primary" : "border-border hover:bg-muted/50"
578
+ ),
579
+ "data-testid": `${testId}-start-${start}`,
580
+ children: l.starts[start]
581
+ },
582
+ start
583
+ )) })
584
+ ] }),
585
+ trigger.start === "once" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
586
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.runAt }),
587
+ /* @__PURE__ */ jsxRuntime.jsx(
588
+ ui.Input,
589
+ {
590
+ type: "datetime-local",
591
+ value: trigger.runAt,
592
+ onChange: (e) => set({ runAt: e.target.value }),
593
+ "data-testid": `${testId}-run-at`
594
+ }
595
+ )
596
+ ] }),
597
+ trigger.start === "repeat" && /* @__PURE__ */ jsxRuntime.jsx(chunkIUR565UW_cjs.RecurrenceBuilder, { rrule: trigger.rrule, onChange: (rrule) => set({ rrule }) }),
598
+ trigger.start === "event" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
599
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.event }),
600
+ /* @__PURE__ */ jsxRuntime.jsxs(
601
+ "select",
602
+ {
603
+ className: selectClass2,
604
+ value: trigger.eventKind,
605
+ onChange: (e) => set({ eventKind: e.target.value }),
606
+ "data-testid": `${testId}-event`,
607
+ children: [
608
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.eventPlaceholder }),
609
+ eventKinds.map((k) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k.value, children: k.label }, k.value))
610
+ ]
611
+ }
612
+ )
613
+ ] }),
614
+ trigger.start === "task" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
615
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.afterTask }),
616
+ /* @__PURE__ */ jsxRuntime.jsxs(
617
+ "select",
618
+ {
619
+ className: selectClass2,
620
+ value: trigger.afterTaskId,
621
+ onChange: (e) => set({ afterTaskId: e.target.value }),
622
+ "data-testid": `${testId}-after-task`,
623
+ children: [
624
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.afterTaskPlaceholder }),
625
+ tasks.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.value, children: t.label }, t.value))
626
+ ]
627
+ }
628
+ )
629
+ ] }),
630
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
631
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.agent }),
632
+ /* @__PURE__ */ jsxRuntime.jsx(
633
+ chunkIUR565UW_cjs.AgentSelect,
634
+ {
635
+ agents,
636
+ value: trigger.agentId,
637
+ onValueChange: (agentId) => set({ agentId }),
638
+ hideLabel: true,
639
+ testId: `${testId}-agent`
640
+ }
641
+ )
642
+ ] }),
643
+ trigger.start !== "manual" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
644
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.access }),
645
+ /* @__PURE__ */ jsxRuntime.jsxs(
646
+ "select",
647
+ {
648
+ className: selectClass2,
649
+ value: trigger.access,
650
+ onChange: (e) => set({ access: e.target.value === "standing" ? "standing" : "ask_each_run" }),
651
+ "data-testid": `${testId}-access`,
652
+ children: [
653
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "ask_each_run", children: l.accessAsk }),
654
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "standing", children: l.accessStanding })
655
+ ]
656
+ }
657
+ )
658
+ ] })
659
+ ] });
660
+ }
661
+ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
662
+ form: "Form",
663
+ upload: "Upload",
664
+ agent: "AI step",
665
+ review: "Approval",
666
+ branch: "Branch",
667
+ kindHints: {
668
+ form: "Ask for details",
669
+ upload: "Collect files",
670
+ agent: "Run a skill or an instruction",
671
+ review: "A person approves"
672
+ },
673
+ addNext: "Add the next step",
674
+ runs: "Runs \u201C{name}\u201D",
675
+ instruction: "No instruction yet",
676
+ fields: "{count} fields",
677
+ noFields: "No fields yet",
678
+ approvedBy: "A person approves",
679
+ emptyTitle: "Start your workflow",
680
+ emptyHint: "Add the first step: what should happen when it starts?"
681
+ };
682
+ var TRIGGER_NODE = "__trigger";
683
+ var STEP_KIND_ICONS = {
684
+ form: lucideReact.FileInput,
685
+ upload: lucideReact.Upload,
686
+ agent: lucideReact.Bot,
687
+ review: lucideReact.ClipboardCheck
688
+ };
689
+ var KINDS = ["form", "upload", "agent", "review"];
690
+ function AddNext({
691
+ from,
692
+ onAdd,
693
+ l,
694
+ testId
695
+ }) {
696
+ const [open, setOpen] = react.useState(false);
697
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open, onOpenChange: setOpen, children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
699
+ "button",
700
+ {
701
+ type: "button",
702
+ className: "wf-add nodrag nopan flex size-7 items-center justify-center rounded-full border border-border bg-card text-muted-foreground shadow-sm hover:text-foreground",
703
+ "aria-label": l.addNext,
704
+ "data-testid": `${testId}-add-after-${from === TRIGGER_NODE ? "trigger" : from}`,
705
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" })
706
+ }
707
+ ) }),
708
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.PopoverContent, { side: "right", align: "start", className: "w-60 p-1.5", children: [
709
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 pb-1 pt-0.5 text-xs font-medium text-muted-foreground", children: l.addNext }),
710
+ KINDS.map((kind) => {
711
+ const Icon = STEP_KIND_ICONS[kind];
712
+ return /* @__PURE__ */ jsxRuntime.jsxs(
713
+ "button",
714
+ {
715
+ type: "button",
716
+ onClick: (e) => {
717
+ e.stopPropagation();
718
+ setOpen(false);
719
+ onAdd(from, kind);
720
+ },
721
+ className: ui.cn(
722
+ `wf-kind-${kind}`,
723
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-left hover:bg-muted"
724
+ ),
725
+ "data-testid": `${testId}-add-after-${from === TRIGGER_NODE ? "trigger" : from}-${kind}`,
726
+ children: [
727
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-badge flex size-7 shrink-0 items-center justify-center rounded-md", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }),
728
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
729
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm font-medium", children: l[kind] }),
730
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-muted-foreground", children: l.kindHints[kind] })
731
+ ] })
732
+ ]
733
+ },
734
+ kind
735
+ );
736
+ })
737
+ ] })
738
+ ] });
739
+ }
740
+ function PhaseMark({ phase }) {
741
+ if (phase === "running") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "wf-kind-text size-4 animate-spin" });
742
+ if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "wf-kind-text size-4" });
743
+ if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-4 text-destructive" });
744
+ if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-4 text-muted-foreground" });
745
+ return null;
746
+ }
747
+ function StepNode({ data }) {
748
+ const { step, phase, summary, icon, l, onAdd, testId } = data;
749
+ const KindIcon = STEP_KIND_ICONS[step.kind];
750
+ return /* @__PURE__ */ jsxRuntime.jsxs(
751
+ "div",
752
+ {
753
+ className: ui.cn(
754
+ "wf-node w-64 py-3 pl-4 pr-3 text-left",
755
+ `wf-kind-${step.kind}`,
756
+ phase && `wf-phase-${phase}`
757
+ ),
758
+ "data-testid": `${testId}-node-${step.id}`,
759
+ "data-phase": phase,
760
+ children: [
761
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "target", position: react$1.Position.Left }),
762
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2.5", children: [
763
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-badge flex size-8 shrink-0 items-center justify-center rounded-lg [&_svg]:size-4", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(KindIcon, {}) }),
764
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
765
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: l[step.kind] }),
767
+ /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase })
768
+ ] }),
769
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold leading-snug", children: step.title }),
770
+ summary && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-snug text-muted-foreground", children: summary }),
771
+ step.kind === "agent" && step.branch && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-1.5 inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: [
772
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { className: "size-3" }),
773
+ " ",
774
+ l.branch
775
+ ] })
776
+ ] })
777
+ ] }),
778
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "source", position: react$1.Position.Right }),
779
+ onAdd && /* @__PURE__ */ jsxRuntime.jsx(AddNext, { from: step.id, onAdd, l, testId })
780
+ ]
781
+ }
782
+ );
783
+ }
784
+ function TriggerNode({ data }) {
785
+ return /* @__PURE__ */ jsxRuntime.jsxs(
786
+ "div",
787
+ {
788
+ className: "wf-start wf-kind-start relative w-60 px-4 py-3 text-left",
789
+ "data-testid": `${data.testId}-node-trigger`,
790
+ children: [
791
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-badge flex size-8 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { className: "size-4" }) }),
793
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
794
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: data.title }),
795
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold", children: data.summary })
796
+ ] })
797
+ ] }),
798
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "source", position: react$1.Position.Right }),
799
+ data.onAdd && /* @__PURE__ */ jsxRuntime.jsx(AddNext, { from: TRIGGER_NODE, onAdd: data.onAdd, l: data.l, testId: data.testId })
800
+ ]
801
+ }
802
+ );
803
+ }
804
+ var NODE_TYPES = { step: StepNode, trigger: TriggerNode };
805
+ var READABLE_ZOOM = 0.7;
806
+ var firstWords = (text, n = 14) => {
807
+ const words = text.trim().split(/\s+/);
808
+ return words.length > n ? `${words.slice(0, n).join(" ")}\u2026` : text.trim();
809
+ };
810
+ function summaryOf(step, l, workflowTitle) {
811
+ if (step.description) return step.description;
812
+ switch (step.kind) {
813
+ case "agent":
814
+ if (step.workflow)
815
+ return l.runs.replace("{name}", workflowTitle?.(step.workflow) ?? step.workflow);
816
+ return step.run?.kind === "prompt" && step.run.promptTemplate.trim() ? firstWords(step.run.promptTemplate) : l.instruction;
817
+ case "form":
818
+ return step.inputs.length ? step.inputs.length === 1 ? step.inputs[0].label : l.fields.replace("{count}", String(step.inputs.length)) : l.noFields;
819
+ case "upload":
820
+ return step.hint;
821
+ case "review":
822
+ return step.instructions ? firstWords(step.instructions) : l.approvedBy;
823
+ }
824
+ }
825
+ function WorkflowCanvas({
826
+ workflow,
827
+ onChange,
828
+ selected = null,
829
+ onSelect,
830
+ onAddAfter,
831
+ phases,
832
+ workflowTitle,
833
+ trigger,
834
+ renderIcon,
835
+ labels,
836
+ className,
837
+ reserveRight = 0,
838
+ testId = "workflow-canvas"
839
+ }) {
840
+ const l = react.useMemo(() => ({ ...DEFAULT_WORKFLOW_CANVAS_LABELS, ...labels }), [labels]);
841
+ const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
842
+ const editable = !!onChange;
843
+ const built = react.useMemo(() => {
844
+ const layout = layoutWithDefaults(workflow);
845
+ const all = chunkGTNUQBXI_cjs.workflowSteps(workflow);
846
+ const roots = all.filter((s) => chunkGTNUQBXI_cjs.stepDependencies(all, s.id).length === 0);
847
+ const triggerNode = trigger ? [
848
+ {
849
+ id: TRIGGER_NODE,
850
+ type: "trigger",
851
+ deletable: false,
852
+ selected: selected === TRIGGER_NODE,
853
+ position: layout[TRIGGER_NODE] ?? {
854
+ x: Math.min(0, ...Object.values(layout).map((p) => p.x)) - 320,
855
+ y: roots.length ? roots.reduce((sum, s) => sum + (layout[s.id]?.y ?? 0), 0) / roots.length : 0
856
+ },
857
+ data: { title: trigger.title, summary: trigger.summary, l, onAdd: onAddAfter, testId }
858
+ }
859
+ ] : [];
860
+ return [
861
+ ...triggerNode,
862
+ ...all.map((step) => ({
863
+ id: step.id,
864
+ type: "step",
865
+ position: layout[step.id] ?? { x: 0, y: 0 },
866
+ selected: step.id === selected,
867
+ data: {
868
+ step,
869
+ phase: phases?.[step.id],
870
+ summary: summaryOf(step, l, workflowTitle),
871
+ icon: step.icon && renderIcon ? renderIcon(step.icon) : void 0,
872
+ l,
873
+ onAdd: onAddAfter,
874
+ testId
875
+ }
876
+ }))
877
+ ];
878
+ }, [workflow, selected, phases, workflowTitle, trigger, renderIcon, l, onAddAfter, testId]);
879
+ const [nodes, setNodes] = react.useState(built);
880
+ react.useEffect(() => setNodes(built), [built]);
881
+ const edges = react.useMemo(
882
+ () => steps.flatMap((s) => {
883
+ const deps = chunkGTNUQBXI_cjs.stepDependencies(steps, s.id);
884
+ const from = deps.length ? deps : trigger ? [TRIGGER_NODE] : [];
885
+ return from.map((d) => ({
886
+ id: `${d}->${s.id}`,
887
+ source: d,
888
+ target: s.id,
889
+ type: "smoothstep",
890
+ deletable: d !== TRIGGER_NODE,
891
+ markerEnd: { type: react$1.MarkerType.ArrowClosed, width: 16, height: 16 },
892
+ animated: phases?.[s.id] === "running"
893
+ }));
894
+ }),
895
+ [steps, phases, trigger]
896
+ );
897
+ const onNodesChange = react.useCallback(
898
+ (changes) => {
899
+ setNodes((ns) => react$1.applyNodeChanges(changes, ns));
900
+ if (!onChange) return;
901
+ let next = workflow;
902
+ for (const c of changes) {
903
+ if (c.type === "position" && c.dragging === false && c.position && c.id !== TRIGGER_NODE) {
904
+ next = moveStep(next, c.id, c.position);
905
+ }
906
+ }
907
+ if (next !== workflow) onChange(next);
908
+ },
909
+ [workflow, onChange]
910
+ );
911
+ const onConnect = react.useCallback(
912
+ (c) => {
913
+ if (!onChange || !c.source || !c.target) return;
914
+ if (c.source === TRIGGER_NODE) onChange(updateStep(workflow, c.target, { after: [] }));
915
+ else onChange(connectSteps(workflow, c.source, c.target));
916
+ },
917
+ [workflow, onChange]
918
+ );
919
+ const frame = react.useRef(null);
920
+ const flowRef = react.useRef(null);
921
+ const onInit = react.useCallback(
922
+ async (flow) => {
923
+ flowRef.current = flow;
924
+ await flow.fitView({
925
+ padding: { top: "48px", bottom: "48px", left: "48px", right: `${reserveRight + 48}px` },
926
+ maxZoom: 1
927
+ });
928
+ const height = frame.current?.clientHeight;
929
+ const shown = flow.getNodes();
930
+ if (flow.getZoom() >= READABLE_ZOOM || !height || !shown.length) return;
931
+ const left = Math.min(...shown.map((n) => n.position.x));
932
+ const ys = shown.map((n) => n.position.y + (n.measured?.height ?? 0) / 2);
933
+ const middle = (Math.min(...ys) + Math.max(...ys)) / 2;
934
+ flow.setViewport({
935
+ x: 48 - left * READABLE_ZOOM,
936
+ y: height / 2 - middle * READABLE_ZOOM,
937
+ zoom: READABLE_ZOOM
938
+ });
939
+ },
940
+ [reserveRight]
941
+ );
942
+ react.useEffect(() => {
943
+ const flow = flowRef.current;
944
+ const box = frame.current;
945
+ const node = selected ? flow?.getNode(selected) : void 0;
946
+ if (!flow || !box || !node) return;
947
+ const { x, y, zoom } = flow.getViewport();
948
+ const w = (node.measured?.width ?? 256) * zoom;
949
+ const h = (node.measured?.height ?? 80) * zoom;
950
+ const left = node.position.x * zoom + x;
951
+ const top = node.position.y * zoom + y;
952
+ const right = box.clientWidth - reserveRight;
953
+ if (left >= 16 && top >= 16 && left + w <= right - 16 && top + h <= box.clientHeight - 16)
954
+ return;
955
+ void flow.setCenter(
956
+ node.position.x + (node.measured?.width ?? 256) / 2 + reserveRight / 2 / zoom,
957
+ node.position.y + (node.measured?.height ?? 80) / 2,
958
+ { zoom, duration: 250 }
959
+ );
960
+ }, [selected, nodes, reserveRight]);
961
+ const onDelete = react.useCallback(
962
+ ({ nodes: gone, edges: cut }) => {
963
+ if (!onChange) return;
964
+ const removed = new Set(gone.map((n) => n.id));
965
+ let next = gone.reduce((w, n) => removeStep(w, n.id), workflow);
966
+ for (const e of cut) {
967
+ if (!removed.has(e.source) && !removed.has(e.target)) {
968
+ next = disconnectSteps(next, e.source, e.target);
969
+ }
970
+ }
971
+ onChange(next);
972
+ },
973
+ [workflow, onChange]
974
+ );
975
+ return /* @__PURE__ */ jsxRuntime.jsxs(
976
+ "div",
977
+ {
978
+ className: ui.cn(
979
+ "relative h-[max(560px,calc(100dvh-200px))] w-full overflow-hidden rounded-xl border border-border bg-muted/30",
980
+ className
981
+ ),
982
+ ref: frame,
983
+ "data-testid": testId,
984
+ children: [
985
+ /* @__PURE__ */ jsxRuntime.jsxs(
986
+ react$1.ReactFlow,
987
+ {
988
+ nodes,
989
+ edges,
990
+ nodeTypes: NODE_TYPES,
991
+ onNodesChange,
992
+ onConnect,
993
+ onDelete,
994
+ isValidConnection: (c) => !!c.source && !!c.target && !wouldCycle(workflow, c.source, c.target),
995
+ onNodeClick: (_, node) => onSelect?.(node.id),
996
+ onPaneClick: () => onSelect?.(null),
997
+ nodesDraggable: editable,
998
+ nodesConnectable: editable,
999
+ elementsSelectable: true,
1000
+ deleteKeyCode: editable ? ["Backspace", "Delete"] : null,
1001
+ onInit,
1002
+ fitViewOptions: { padding: 0.2, maxZoom: 1 },
1003
+ minZoom: 0.3,
1004
+ proOptions: { hideAttribution: true },
1005
+ children: [
1006
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Background, { variant: react$1.BackgroundVariant.Dots, gap: 18, size: 1.5 }),
1007
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false, position: "bottom-left" }),
1008
+ steps.length > 3 && /* @__PURE__ */ jsxRuntime.jsx(
1009
+ react$1.MiniMap,
1010
+ {
1011
+ pannable: true,
1012
+ zoomable: true,
1013
+ position: "bottom-right",
1014
+ className: "wf-minimap !rounded-lg !border !border-border",
1015
+ style: { width: 168, height: 104 },
1016
+ nodeBorderRadius: 8,
1017
+ nodeStrokeWidth: 0
1018
+ }
1019
+ )
1020
+ ]
1021
+ }
1022
+ ),
1023
+ steps.length === 0 && onAddAfter && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-16 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
1024
+ "div",
1025
+ {
1026
+ className: "pointer-events-auto rounded-xl border border-dashed border-border bg-card/90 p-5 text-center shadow-sm backdrop-blur",
1027
+ "data-testid": `${testId}-empty`,
1028
+ children: [
1029
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: l.emptyTitle }),
1030
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: l.emptyHint }),
1031
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 grid grid-cols-2 gap-2", children: KINDS.map((kind) => {
1032
+ const Icon = STEP_KIND_ICONS[kind];
1033
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1034
+ "button",
1035
+ {
1036
+ type: "button",
1037
+ onClick: () => onAddAfter(TRIGGER_NODE, kind),
1038
+ className: ui.cn(
1039
+ `wf-kind-${kind}`,
1040
+ "flex items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-left text-sm hover:bg-muted"
1041
+ ),
1042
+ "data-testid": `${testId}-empty-${kind}`,
1043
+ children: [
1044
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-badge flex size-6 items-center justify-center rounded-md", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5" }) }),
1045
+ l[kind]
1046
+ ]
1047
+ },
1048
+ kind
1049
+ );
1050
+ }) })
1051
+ ]
1052
+ }
1053
+ ) })
1054
+ ]
1055
+ }
1056
+ );
1057
+ }
1058
+ var DEFAULT_WORKFLOW_BUILDER_LABELS = {
1059
+ addStep: "Add step",
1060
+ tidy: "Tidy",
1061
+ settings: "Workflow settings",
1062
+ closePanel: "Close panel",
1063
+ design: "Design",
1064
+ preview: "Preview",
1065
+ start: "Start",
1066
+ previewAnswer: "Preview: the agent would be asked \u2014\n\n{prompt}",
1067
+ problems: {
1068
+ duplicate: "\u201C{step}\u201D appears twice.",
1069
+ unknown: "\u201C{step}\u201D waits for a step that does not exist.",
1070
+ cycle: "\u201C{step}\u201D waits for itself (a loop).",
1071
+ order: "\u201C{step}\u201D is listed before a step it waits for."
1072
+ }
1073
+ };
1074
+ var PANEL_WIDTH = 344;
1075
+ var KINDS2 = ["form", "upload", "agent", "review"];
1076
+ function WorkflowBuilder({
1077
+ value,
1078
+ onChange,
1079
+ workflows = [],
1080
+ agents = [],
1081
+ eventKinds = [],
1082
+ tasks = [],
1083
+ compose,
1084
+ renderIcon,
1085
+ actions,
1086
+ labels,
1087
+ canvasLabels,
1088
+ inspectorLabels,
1089
+ triggerLabels,
1090
+ testId = "workflow-builder",
1091
+ className
1092
+ }) {
1093
+ const l = { ...DEFAULT_WORKFLOW_BUILDER_LABELS, ...labels };
1094
+ const [selected, setSelectedState] = react.useState(null);
1095
+ const [panelOpen, setPanelOpen] = react.useState(false);
1096
+ const setSelected = (id) => {
1097
+ setSelectedState(id);
1098
+ if (id) setPanelOpen(true);
1099
+ };
1100
+ const [mode, setMode] = react.useState("design");
1101
+ const [adding, setAdding] = react.useState(false);
1102
+ const { workflow, trigger } = value;
1103
+ const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
1104
+ const problems = chunkGTNUQBXI_cjs.validateWorkflowGraph(steps);
1105
+ const titles = react.useMemo(() => new Map(workflows.map((w) => [w.id, w.title])), [workflows]);
1106
+ const setWorkflow = (next) => onChange({ ...value, workflow: next });
1107
+ const addAfter = (from, kind) => {
1108
+ const layout = layoutWithDefaults(workflow);
1109
+ const origin = from && from !== TRIGGER_NODE ? layout[from] : void 0;
1110
+ const siblings = steps.filter(
1111
+ (s) => from && from !== TRIGGER_NODE ? s.after?.includes(from) : s.after?.length === 0
1112
+ ).length;
1113
+ const { workflow: next, id } = addStep(workflow, kind, {
1114
+ after: from && from !== TRIGGER_NODE ? from : void 0,
1115
+ position: origin ? { x: origin.x + 320, y: origin.y + siblings * 150 } : {
1116
+ x: Math.max(0, ...Object.values(layout).map((p) => p.x)) + (steps.length ? 320 : 0),
1117
+ y: siblings * 150
1118
+ }
1119
+ });
1120
+ setWorkflow(next);
1121
+ setSelected(id);
1122
+ };
1123
+ const add = (kind) => addAfter(
1124
+ selected && selected !== TRIGGER_NODE ? selected : steps.at(-1)?.id ?? TRIGGER_NODE,
1125
+ kind
1126
+ );
1127
+ const summary = triggerSummary(trigger, {
1128
+ labels: triggerLabels,
1129
+ eventLabel: (k) => eventKinds.find((e) => e.value === k)?.label,
1130
+ taskLabel: (id) => tasks.find((t) => t.value === id)?.label
1131
+ });
1132
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-3", className), "data-testid": testId, children: [
1133
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1134
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex rounded-md border border-border p-0.5", children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsxs(
1136
+ ui.Button,
1137
+ {
1138
+ variant: mode === "design" ? "secondary" : "ghost",
1139
+ size: "sm",
1140
+ onClick: () => setMode("design"),
1141
+ "data-testid": `${testId}-mode-design`,
1142
+ children: [
1143
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PencilRuler, { className: "size-4" }),
1144
+ " ",
1145
+ l.design
1146
+ ]
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ jsxRuntime.jsxs(
1150
+ ui.Button,
1151
+ {
1152
+ variant: mode === "preview" ? "secondary" : "ghost",
1153
+ size: "sm",
1154
+ onClick: () => setMode("preview"),
1155
+ disabled: problems.length > 0 || steps.length === 0,
1156
+ "data-testid": `${testId}-mode-preview`,
1157
+ children: [
1158
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "size-4" }),
1159
+ " ",
1160
+ l.preview
1161
+ ]
1162
+ }
1163
+ )
1164
+ ] }),
1165
+ mode === "design" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: adding, onOpenChange: setAdding, children: [
1167
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "sm", "data-testid": `${testId}-add`, children: [
1168
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }),
1169
+ " ",
1170
+ l.addStep
1171
+ ] }) }),
1172
+ /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { align: "start", className: "w-64 p-1.5", children: KINDS2.map((kind) => {
1173
+ const Icon = STEP_KIND_ICONS[kind];
1174
+ const cls = { ...DEFAULT_WORKFLOW_CANVAS_LABELS, ...canvasLabels };
1175
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1176
+ "button",
1177
+ {
1178
+ type: "button",
1179
+ onClick: () => {
1180
+ setAdding(false);
1181
+ add(kind);
1182
+ },
1183
+ className: ui.cn(
1184
+ `wf-kind-${kind}`,
1185
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-left hover:bg-muted"
1186
+ ),
1187
+ "data-testid": `${testId}-add-${kind}`,
1188
+ children: [
1189
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-badge flex size-7 shrink-0 items-center justify-center rounded-md", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }),
1190
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
1191
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm font-medium", children: cls[kind] }),
1192
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-muted-foreground", children: cls.kindHints[kind] })
1193
+ ] })
1194
+ ]
1195
+ },
1196
+ kind
1197
+ );
1198
+ }) })
1199
+ ] }),
1200
+ /* @__PURE__ */ jsxRuntime.jsxs(
1201
+ ui.Button,
1202
+ {
1203
+ variant: "ghost",
1204
+ size: "sm",
1205
+ onClick: () => workflow.run.kind === "steps" && setWorkflow({ ...workflow, run: { ...workflow.run, layout: autoLayout(steps) } }),
1206
+ "data-testid": `${testId}-tidy`,
1207
+ children: [
1208
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { className: "size-4" }),
1209
+ " ",
1210
+ l.tidy
1211
+ ]
1212
+ }
1213
+ )
1214
+ ] }),
1215
+ actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
1216
+ ] }),
1217
+ problems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1 text-sm text-destructive", "data-testid": `${testId}-problems`, children: problems.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.problems[p.code].replace(
1218
+ "{step}",
1219
+ steps.find((s) => s.id === p.step)?.title ?? p.step
1220
+ ) }, i)) }),
1221
+ mode === "design" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1222
+ /* @__PURE__ */ jsxRuntime.jsx(
1223
+ WorkflowCanvas,
1224
+ {
1225
+ workflow,
1226
+ onChange: setWorkflow,
1227
+ selected,
1228
+ onSelect: setSelected,
1229
+ onAddAfter: addAfter,
1230
+ trigger: { title: l.start, summary },
1231
+ workflowTitle: (id) => titles.get(id),
1232
+ renderIcon,
1233
+ labels: canvasLabels,
1234
+ reserveRight: panelOpen ? PANEL_WIDTH : 0,
1235
+ testId: `${testId}-canvas`
1236
+ }
1237
+ ),
1238
+ panelOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
1239
+ "div",
1240
+ {
1241
+ className: "absolute bottom-3 right-3 top-3 z-10 w-80 max-w-[calc(100%-1.5rem)] overflow-y-auto rounded-xl border border-border bg-card/95 p-4 pt-10 shadow-lg backdrop-blur",
1242
+ "data-testid": `${testId}-panel`,
1243
+ children: [
1244
+ /* @__PURE__ */ jsxRuntime.jsx(
1245
+ ui.Button,
1246
+ {
1247
+ size: "icon",
1248
+ variant: "ghost",
1249
+ className: "absolute right-2 top-2 size-7",
1250
+ onClick: () => setPanelOpen(false),
1251
+ "aria-label": l.closePanel,
1252
+ "data-testid": `${testId}-panel-close`,
1253
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
1254
+ }
1255
+ ),
1256
+ selected === TRIGGER_NODE ? /* @__PURE__ */ jsxRuntime.jsx(
1257
+ TriggerInspector,
1258
+ {
1259
+ trigger,
1260
+ onChange: (next) => onChange({ ...value, trigger: next }),
1261
+ agents,
1262
+ eventKinds,
1263
+ tasks,
1264
+ labels: triggerLabels,
1265
+ testId: `${testId}-trigger`
1266
+ }
1267
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1268
+ StepInspector,
1269
+ {
1270
+ workflow,
1271
+ stepId: selected,
1272
+ onChange: setWorkflow,
1273
+ onSelect: setSelected,
1274
+ workflows,
1275
+ labels: inspectorLabels,
1276
+ testId: `${testId}-inspector`
1277
+ }
1278
+ )
1279
+ ]
1280
+ }
1281
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
1282
+ ui.Button,
1283
+ {
1284
+ size: "sm",
1285
+ variant: "outline",
1286
+ className: "absolute right-3 top-3 z-10 bg-card shadow-sm",
1287
+ onClick: () => setPanelOpen(true),
1288
+ "data-testid": `${testId}-panel-open`,
1289
+ children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { className: "size-4" }),
1291
+ " ",
1292
+ l.settings
1293
+ ]
1294
+ }
1295
+ )
1296
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
1297
+ WorkflowPreview,
1298
+ {
1299
+ workflow,
1300
+ workflows,
1301
+ compose,
1302
+ answer: l.previewAnswer,
1303
+ renderIcon,
1304
+ testId: `${testId}-preview`
1305
+ },
1306
+ JSON.stringify(workflow)
1307
+ )
1308
+ ] });
1309
+ }
1310
+ function WorkflowPreview({
1311
+ workflow,
1312
+ workflows,
1313
+ compose,
1314
+ answer,
1315
+ renderIcon,
1316
+ testId
1317
+ }) {
1318
+ const run = chunkIUR565UW_cjs.useWorkflowPreview(workflow, {
1319
+ resolveWorkflow: (id) => workflows.find((w) => w.id === id),
1320
+ compose,
1321
+ answer
1322
+ });
1323
+ return /* @__PURE__ */ jsxRuntime.jsx(
1324
+ chunkGTNUQBXI_cjs.WorkflowRunner,
1325
+ {
1326
+ workflow,
1327
+ run,
1328
+ renderIcon,
1329
+ testIdPrefix: testId,
1330
+ renderAgentOutput: (step, state) => state?.text ? /* @__PURE__ */ jsxRuntime.jsx(
1331
+ "pre",
1332
+ {
1333
+ className: "whitespace-pre-wrap rounded-md bg-muted/40 p-3 text-xs text-muted-foreground",
1334
+ "data-testid": `${testId}-${step.id}-answer`,
1335
+ children: state.text
1336
+ }
1337
+ ) : null
1338
+ }
1339
+ );
1340
+ }
1341
+
1342
+ // src/workflow-canvas/trigger.ts
1343
+ var DEFAULT_WORKFLOW_TRIGGER = {
1344
+ start: "manual",
1345
+ runAt: "",
1346
+ rrule: "",
1347
+ timezone: typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
1348
+ eventKind: "",
1349
+ afterTaskId: "",
1350
+ agentId: "",
1351
+ access: "ask_each_run"
1352
+ };
1353
+ function triggerProblem(trigger) {
1354
+ if (trigger.start === "once" && !trigger.runAt) return "runAt";
1355
+ if (trigger.start === "repeat" && !trigger.rrule.trim()) return "rrule";
1356
+ if (trigger.start === "event" && !trigger.eventKind.trim()) return "event";
1357
+ if (trigger.start === "task" && !trigger.afterTaskId) return "task";
1358
+ return null;
1359
+ }
1360
+ function triggerFields(trigger, clearOthers) {
1361
+ const none = clearOthers ? null : void 0;
1362
+ return {
1363
+ timezone: trigger.timezone,
1364
+ rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
1365
+ run_at: trigger.start === "once" ? chunkIUR565UW_cjs.localInputToIso(trigger.runAt) : none,
1366
+ event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
1367
+ after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
1368
+ on_demand: trigger.start === "manual"
1369
+ };
1370
+ }
1371
+ var authMode = (trigger) => trigger.start === "manual" ? "run_now_temp" : trigger.access === "standing" ? "scheduled_permanent" : "scheduled_require_auth";
1372
+ var withoutUndefined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1373
+ function plan(value, options) {
1374
+ return {
1375
+ goal: value.workflow.description,
1376
+ criteria: [],
1377
+ max_passes: 3,
1378
+ documents: [],
1379
+ steps: chunkGTNUQBXI_cjs.toPlanSteps(value.workflow, options)
1380
+ };
1381
+ }
1382
+ function builderToWorkflowRequest(value, workspaceId, options = {}) {
1383
+ return withoutUndefined({
1384
+ workspace_ext_id: workspaceId,
1385
+ name: value.workflow.title,
1386
+ description: value.workflow.description,
1387
+ active: true,
1388
+ shared: true,
1389
+ ...triggerFields(value.trigger, false),
1390
+ prompt: "",
1391
+ skill_ref: null,
1392
+ skill_inputs: null,
1393
+ agent_ext_id: value.trigger.agentId || null,
1394
+ auth_mode: authMode(value.trigger),
1395
+ plan: plan(value, options)
1396
+ });
1397
+ }
1398
+ function builderToWorkflowUpdate(value, options = {}) {
1399
+ return withoutUndefined({
1400
+ name: value.workflow.title,
1401
+ description: value.workflow.description,
1402
+ ...triggerFields(value.trigger, true),
1403
+ // The steps are what runs (a classic automation's single prompt or skill becomes its one step).
1404
+ prompt: "",
1405
+ skill_ref: null,
1406
+ skill_inputs: null,
1407
+ agent_ext_id: value.trigger.agentId || null,
1408
+ auth_mode: authMode(value.trigger),
1409
+ plan: plan(value, options)
1410
+ });
1411
+ }
1412
+ function workflowRecordToBuilder(record) {
1413
+ const planned = record.plan?.steps ?? [];
1414
+ const steps = planned.length ? chunkGTNUQBXI_cjs.fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1415
+ {
1416
+ id: "work",
1417
+ kind: "agent",
1418
+ title: record.name,
1419
+ ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
1420
+ }
1421
+ ] : [];
1422
+ const when = chunkIUR565UW_cjs.workflowWhen(record);
1423
+ return {
1424
+ workflow: {
1425
+ id: record.external_id,
1426
+ title: record.name,
1427
+ description: record.description ?? "",
1428
+ inputs: [],
1429
+ landing: "chat",
1430
+ schedulable: false,
1431
+ run: { kind: "steps", steps, layout: chunkGTNUQBXI_cjs.layoutFromPlanSteps(planned ?? []) }
1432
+ },
1433
+ trigger: {
1434
+ ...DEFAULT_WORKFLOW_TRIGGER,
1435
+ start: when === "now" ? "manual" : when,
1436
+ runAt: chunkIUR565UW_cjs.isoToLocalInput(record.run_at),
1437
+ rrule: record.rrule ?? "",
1438
+ timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
1439
+ eventKind: record.event_kind ?? "",
1440
+ afterTaskId: record.after_conversation_ext_id ?? "",
1441
+ agentId: record.agent_ext_id ?? "",
1442
+ access: record.auth_mode === "scheduled_permanent" ? "standing" : "ask_each_run"
1443
+ }
1444
+ };
1445
+ }
1446
+ var DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS = {
1447
+ save: "Save",
1448
+ saving: "Saving\u2026",
1449
+ runNow: "Run now",
1450
+ saved: "Saved.",
1451
+ needTrigger: "Finish setting when it starts."
1452
+ };
1453
+ var DEFAULT_WORKFLOW_EVENT_KINDS = [
1454
+ { value: "conversation_done", label: "A task is marked done" },
1455
+ { value: "conversation_ready", label: "Work is ready for me" },
1456
+ { value: "mention", label: "Someone mentions me" },
1457
+ { value: "workflow_completed", label: "Another workflow finishes" },
1458
+ { value: "workflow_failed", label: "Another workflow fails" }
1459
+ ];
1460
+ function ConnectedWorkflowBuilder({
1461
+ workflowId,
1462
+ initial,
1463
+ workflows: hostWorkflows = [],
1464
+ eventKinds = DEFAULT_WORKFLOW_EVENT_KINDS,
1465
+ compose,
1466
+ onSaved,
1467
+ onRun,
1468
+ actions,
1469
+ connectedLabels,
1470
+ testId = "workflow-builder",
1471
+ ...builderProps
1472
+ }) {
1473
+ const l = { ...DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS, ...connectedLabels };
1474
+ const { workspaceId } = chunkMUMH3Z6K_cjs.useConnection();
1475
+ const saved = react$2.useWorkflows();
1476
+ const skills = react$2.useSkills();
1477
+ const agentsQuery = react$2.useAgents();
1478
+ const conversations = react$2.useConversations(workspaceId ?? void 0);
1479
+ const create = react$2.useCreateWorkflow();
1480
+ const update = react$2.useUpdateWorkflow();
1481
+ const run = react$2.useRunWorkflow();
1482
+ const [id, setId] = react.useState(workflowId);
1483
+ const [value, setValue] = react.useState(initial);
1484
+ const [message, setMessage] = react.useState(null);
1485
+ const record = saved.data?.find((w) => w.external_id === id);
1486
+ const [loaded, setLoaded] = react.useState(void 0);
1487
+ react.useEffect(() => {
1488
+ if (record && loaded !== record.external_id) {
1489
+ setValue(workflowRecordToBuilder(record));
1490
+ setLoaded(record.external_id);
1491
+ }
1492
+ }, [record, loaded]);
1493
+ const workflows = react.useMemo(
1494
+ () => [
1495
+ ...hostWorkflows,
1496
+ ...(skills.data ?? []).map(
1497
+ (s) => chunkGTNUQBXI_cjs.skillToWorkflow({
1498
+ name: s.name,
1499
+ slug: s.slug,
1500
+ description: s.description,
1501
+ arg_hint: s.arg_hint
1502
+ })
1503
+ )
1504
+ ],
1505
+ [hostWorkflows, skills.data]
1506
+ );
1507
+ const agents = (agentsQuery.data ?? []).map((a) => ({
1508
+ id: a.external_id,
1509
+ label: a.given_name || a.email
1510
+ }));
1511
+ const tasks = (conversations.data ?? []).filter((c) => c.status && c.status !== "done").map((c) => ({ value: c.external_id, label: c.title || c.external_id }));
1512
+ const options = { resolveWorkflow: (wid) => workflows.find((w) => w.id === wid), compose };
1513
+ const problem = triggerProblem(value.trigger) ?? (chunkGTNUQBXI_cjs.validateWorkflowGraph(chunkGTNUQBXI_cjs.workflowSteps(value.workflow)).length ? "graph" : null);
1514
+ const busy = create.isPending || update.isPending || run.isPending;
1515
+ const save = async () => {
1516
+ if (!workspaceId) return void 0;
1517
+ setMessage(null);
1518
+ const result = id ? await update.mutateAsync({ workflowId: id, patch: builderToWorkflowUpdate(value, options) }) : await create.mutateAsync(builderToWorkflowRequest(value, workspaceId, options));
1519
+ setId(result.external_id);
1520
+ setLoaded(result.external_id);
1521
+ setMessage(l.saved);
1522
+ onSaved?.(result.external_id);
1523
+ return result.external_id;
1524
+ };
1525
+ return /* @__PURE__ */ jsxRuntime.jsx(
1526
+ WorkflowBuilder,
1527
+ {
1528
+ ...builderProps,
1529
+ value,
1530
+ onChange: setValue,
1531
+ workflows,
1532
+ agents,
1533
+ eventKinds,
1534
+ tasks,
1535
+ compose,
1536
+ testId,
1537
+ actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1538
+ actions,
1539
+ message && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: message }),
1540
+ problem && problem !== "graph" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: l.needTrigger }),
1541
+ /* @__PURE__ */ jsxRuntime.jsxs(
1542
+ ui.Button,
1543
+ {
1544
+ variant: "outline",
1545
+ size: "sm",
1546
+ disabled: !!problem || busy || !workspaceId,
1547
+ onClick: async () => {
1548
+ const saved2 = await save();
1549
+ if (!saved2) return;
1550
+ const started = await run.mutateAsync(saved2);
1551
+ onRun?.(started.conversation_ext_id ?? void 0);
1552
+ },
1553
+ "data-testid": `${testId}-run`,
1554
+ children: [
1555
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-4" }),
1556
+ " ",
1557
+ l.runNow
1558
+ ]
1559
+ }
1560
+ ),
1561
+ /* @__PURE__ */ jsxRuntime.jsxs(
1562
+ ui.Button,
1563
+ {
1564
+ size: "sm",
1565
+ disabled: !!problem || busy || !workspaceId,
1566
+ onClick: () => void save(),
1567
+ "data-testid": `${testId}-save`,
1568
+ children: [
1569
+ create.isPending || update.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "size-4" }),
1570
+ create.isPending || update.isPending ? l.saving : l.save
1571
+ ]
1572
+ }
1573
+ )
1574
+ ] })
1575
+ }
1576
+ );
1577
+ }
1578
+
1579
+ exports.ConnectedWorkflowBuilder = ConnectedWorkflowBuilder;
1580
+ exports.DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS = DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS;
1581
+ exports.DEFAULT_STEP_INSPECTOR_LABELS = DEFAULT_STEP_INSPECTOR_LABELS;
1582
+ exports.DEFAULT_TRIGGER_INSPECTOR_LABELS = DEFAULT_TRIGGER_INSPECTOR_LABELS;
1583
+ exports.DEFAULT_WORKFLOW_BUILDER_LABELS = DEFAULT_WORKFLOW_BUILDER_LABELS;
1584
+ exports.DEFAULT_WORKFLOW_CANVAS_LABELS = DEFAULT_WORKFLOW_CANVAS_LABELS;
1585
+ exports.DEFAULT_WORKFLOW_EVENT_KINDS = DEFAULT_WORKFLOW_EVENT_KINDS;
1586
+ exports.DEFAULT_WORKFLOW_TRIGGER = DEFAULT_WORKFLOW_TRIGGER;
1587
+ exports.StepInspector = StepInspector;
1588
+ exports.TRIGGER_NODE = TRIGGER_NODE;
1589
+ exports.TriggerInspector = TriggerInspector;
1590
+ exports.WorkflowBuilder = WorkflowBuilder;
1591
+ exports.WorkflowCanvas = WorkflowCanvas;
1592
+ exports.addStep = addStep;
1593
+ exports.autoLayout = autoLayout;
1594
+ exports.builderToWorkflowRequest = builderToWorkflowRequest;
1595
+ exports.builderToWorkflowUpdate = builderToWorkflowUpdate;
1596
+ exports.connectSteps = connectSteps;
1597
+ exports.disconnectSteps = disconnectSteps;
1598
+ exports.layoutWithDefaults = layoutWithDefaults;
1599
+ exports.moveStep = moveStep;
1600
+ exports.newSteppedWorkflow = newSteppedWorkflow;
1601
+ exports.removeStep = removeStep;
1602
+ exports.stepIdFor = stepIdFor;
1603
+ exports.triggerProblem = triggerProblem;
1604
+ exports.triggerSummary = triggerSummary;
1605
+ exports.updateStep = updateStep;
1606
+ exports.workflowRecordToBuilder = workflowRecordToBuilder;
1607
+ exports.wouldCycle = wouldCycle;
1608
+ //# sourceMappingURL=index.cjs.map
1609
+ //# sourceMappingURL=index.cjs.map