@arbidocs/blocks 0.4.75 → 0.4.77

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 (113) hide show
  1. package/dist/agents/index.cjs +341 -253
  2. package/dist/agents/index.js +3 -3
  3. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  4. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +44 -1
  5. package/dist/agents/tasks/index.d.ts +2 -1
  6. package/dist/agents/tasks/linkedRuns.d.ts +31 -0
  7. package/dist/agents/workflows/SchemaForm.d.ts +6 -1
  8. package/dist/agents/workflows/StepParts.d.ts +109 -0
  9. package/dist/agents/workflows/WorkflowRunner.d.ts +11 -2
  10. package/dist/agents/workflows/index.d.ts +3 -2
  11. package/dist/agents/workflows/planSteps.d.ts +10 -1
  12. package/dist/agents/workflows/run.d.ts +61 -8
  13. package/dist/agents/workflows/types.d.ts +160 -4
  14. package/dist/agents/workflows/useWorkflowPreview.d.ts +2 -1
  15. package/dist/agents/workflows/useWorkflowView.d.ts +19 -0
  16. package/dist/chat/ChatPage.d.ts +1 -1
  17. package/dist/chat/WorkflowStepChip.d.ts +24 -0
  18. package/dist/chat/chat-page-types.d.ts +4 -0
  19. package/dist/chat/index.cjs +130 -122
  20. package/dist/chat/index.d.ts +1 -0
  21. package/dist/chat/index.js +2 -2
  22. package/dist/{chunk-YWYVIQ7T.js → chunk-34UW6XUQ.js} +948 -38
  23. package/dist/chunk-34UW6XUQ.js.map +1 -0
  24. package/dist/{chunk-P2RBE3FD.cjs → chunk-3XR3IEGU.cjs} +965 -35
  25. package/dist/chunk-3XR3IEGU.cjs.map +1 -0
  26. package/dist/{chunk-ZWA7UUZL.cjs → chunk-7YUFMNFW.cjs} +2 -54
  27. package/dist/chunk-7YUFMNFW.cjs.map +1 -0
  28. package/dist/chunk-A24C6BNA.js +92 -0
  29. package/dist/chunk-A24C6BNA.js.map +1 -0
  30. package/dist/chunk-AINNADMT.cjs +62 -0
  31. package/dist/chunk-AINNADMT.cjs.map +1 -0
  32. package/dist/{chunk-7CVF3DK2.cjs → chunk-EKIUMNCN.cjs} +5 -5
  33. package/dist/{chunk-7CVF3DK2.cjs.map → chunk-EKIUMNCN.cjs.map} +1 -1
  34. package/dist/chunk-FE4ULGOR.js +151 -0
  35. package/dist/chunk-FE4ULGOR.js.map +1 -0
  36. package/dist/chunk-FT5FFXSJ.js +60 -0
  37. package/dist/chunk-FT5FFXSJ.js.map +1 -0
  38. package/dist/{chunk-HITAN7JF.cjs → chunk-GTXOV7IJ.cjs} +4 -4
  39. package/dist/{chunk-HITAN7JF.cjs.map → chunk-GTXOV7IJ.cjs.map} +1 -1
  40. package/dist/{chunk-LT2UORRG.js → chunk-HEVVT6IT.js} +205 -38
  41. package/dist/chunk-HEVVT6IT.js.map +1 -0
  42. package/dist/{chunk-IPGKTUF7.cjs → chunk-HOD6OM7L.cjs} +68 -3
  43. package/dist/chunk-HOD6OM7L.cjs.map +1 -0
  44. package/dist/{chunk-F4LUD3YC.cjs → chunk-JFUN4D7D.cjs} +229 -60
  45. package/dist/chunk-JFUN4D7D.cjs.map +1 -0
  46. package/dist/{chunk-UIWLDSTF.js → chunk-NIP5BOP7.js} +68 -5
  47. package/dist/chunk-NIP5BOP7.js.map +1 -0
  48. package/dist/{chunk-MK6NJQGF.js → chunk-OEM5ARVM.js} +3 -3
  49. package/dist/{chunk-MK6NJQGF.js.map → chunk-OEM5ARVM.js.map} +1 -1
  50. package/dist/{chunk-5EBGRG3X.js → chunk-OPA2Y6YZ.js} +3 -54
  51. package/dist/chunk-OPA2Y6YZ.js.map +1 -0
  52. package/dist/chunk-TZR36PPP.cjs +95 -0
  53. package/dist/chunk-TZR36PPP.cjs.map +1 -0
  54. package/dist/{chunk-WJEKRSPH.js → chunk-UEU23PTW.js} +3 -3
  55. package/dist/{chunk-WJEKRSPH.js.map → chunk-UEU23PTW.js.map} +1 -1
  56. package/dist/chunk-ZVBPRMHJ.cjs +153 -0
  57. package/dist/chunk-ZVBPRMHJ.cjs.map +1 -0
  58. package/dist/connect/docx.cjs +10 -88
  59. package/dist/connect/docx.cjs.map +1 -1
  60. package/dist/connect/docx.js +6 -86
  61. package/dist/connect/docx.js.map +1 -1
  62. package/dist/connect/index.cjs +295 -32
  63. package/dist/connect/index.cjs.map +1 -1
  64. package/dist/connect/index.js +280 -17
  65. package/dist/connect/index.js.map +1 -1
  66. package/dist/connection/ConnectedWorkflowRunner.d.ts +16 -2
  67. package/dist/connection/WorkflowRunnerDialogs.d.ts +37 -0
  68. package/dist/connection/useWorkflowThread.d.ts +12 -0
  69. package/dist/document-tools/index.cjs +7 -143
  70. package/dist/document-tools/index.cjs.map +1 -1
  71. package/dist/document-tools/index.js +5 -144
  72. package/dist/document-tools/index.js.map +1 -1
  73. package/dist/docx/index.cjs +18 -17
  74. package/dist/docx/index.cjs.map +1 -1
  75. package/dist/docx/index.js +3 -2
  76. package/dist/docx/index.js.map +1 -1
  77. package/dist/facts/index.cjs +1 -1
  78. package/dist/facts/index.js +1 -1
  79. package/dist/files/index.cjs +1 -1
  80. package/dist/files/index.js +1 -1
  81. package/dist/home/index.cjs +1 -1
  82. package/dist/home/index.js +1 -1
  83. package/dist/index.cjs +631 -535
  84. package/dist/index.js +8 -8
  85. package/dist/settings/index.cjs +1 -1
  86. package/dist/settings/index.js +1 -1
  87. package/dist/shell/index.cjs +1 -1
  88. package/dist/shell/index.js +1 -1
  89. package/dist/studio/index.cjs +4 -4
  90. package/dist/studio/index.js +3 -3
  91. package/dist/workflow-canvas/SignalsEditor.d.ts +41 -0
  92. package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
  93. package/dist/workflow-canvas/StepInspector.d.ts +28 -2
  94. package/dist/workflow-canvas/TriggerInspector.d.ts +11 -2
  95. package/dist/workflow-canvas/WorkflowBuilder.d.ts +17 -4
  96. package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
  97. package/dist/workflow-canvas/edit.d.ts +9 -1
  98. package/dist/workflow-canvas/index.cjs +1282 -208
  99. package/dist/workflow-canvas/index.cjs.map +1 -1
  100. package/dist/workflow-canvas/index.d.ts +2 -1
  101. package/dist/workflow-canvas/index.js +1255 -188
  102. package/dist/workflow-canvas/index.js.map +1 -1
  103. package/dist/workflow-canvas/trigger.d.ts +20 -1
  104. package/package.json +4 -4
  105. package/src/workflow-canvas/canvas.css +9 -0
  106. package/dist/chunk-5EBGRG3X.js.map +0 -1
  107. package/dist/chunk-F4LUD3YC.cjs.map +0 -1
  108. package/dist/chunk-IPGKTUF7.cjs.map +0 -1
  109. package/dist/chunk-LT2UORRG.js.map +0 -1
  110. package/dist/chunk-P2RBE3FD.cjs.map +0 -1
  111. package/dist/chunk-UIWLDSTF.js.map +0 -1
  112. package/dist/chunk-YWYVIQ7T.js.map +0 -1
  113. package/dist/chunk-ZWA7UUZL.cjs.map +0 -1
@@ -2,10 +2,10 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkMUMH3Z6K_cjs = require('../chunk-MUMH3Z6K.cjs');
5
- var chunkF4LUD3YC_cjs = require('../chunk-F4LUD3YC.cjs');
5
+ var chunkJFUN4D7D_cjs = require('../chunk-JFUN4D7D.cjs');
6
6
  require('../chunk-YJQVLVBJ.cjs');
7
7
  require('../chunk-ZW6FPIFC.cjs');
8
- var chunkP2RBE3FD_cjs = require('../chunk-P2RBE3FD.cjs');
8
+ var chunk3XR3IEGU_cjs = require('../chunk-3XR3IEGU.cjs');
9
9
  require('../chunk-7RGLTF76.cjs');
10
10
  require('../chunk-3AFWGEDJ.cjs');
11
11
  require('../chunk-VFUWWH52.cjs');
@@ -16,11 +16,11 @@ require('../chunk-IXALYQT7.cjs');
16
16
  require('../chunk-Z5VUZ6YD.cjs');
17
17
  require('../chunk-7D737FLE.cjs');
18
18
  require('../chunk-OB5F4577.cjs');
19
+ require('../chunk-C54XEN5T.cjs');
19
20
  require('../chunk-B4SRYJLM.cjs');
20
21
  require('../chunk-7UTB4PHM.cjs');
21
22
  require('../chunk-FX3K6LNZ.cjs');
22
23
  require('../chunk-PPCATBOY.cjs');
23
- require('../chunk-C54XEN5T.cjs');
24
24
  require('../chunk-KDG6FER6.cjs');
25
25
  require('../chunk-ULWRNGGE.cjs');
26
26
  require('../chunk-MHVNT4J3.cjs');
@@ -33,6 +33,16 @@ var jsxRuntime = require('react/jsx-runtime');
33
33
  var react$1 = require('@xyflow/react');
34
34
 
35
35
  // src/workflow-canvas/edit.ts
36
+ var WORKFLOW_STEP_KINDS = [
37
+ "form",
38
+ "upload",
39
+ "agent",
40
+ "review",
41
+ "sign",
42
+ "email_draft",
43
+ "tabular_review"
44
+ ];
45
+ var stepKindOf = (step) => step.kind === "action" ? step.action.type : step.kind;
36
46
  function newSteppedWorkflow(id, title) {
37
47
  return {
38
48
  id,
@@ -48,11 +58,11 @@ function withSteps(workflow, steps, layout) {
48
58
  const run = workflow.run.kind === "steps" ? workflow.run : { kind: "steps", steps: [] };
49
59
  return {
50
60
  ...workflow,
51
- run: { ...run, steps: chunkP2RBE3FD_cjs.orderSteps(steps), layout: layout ?? run.layout }
61
+ run: { ...run, steps: chunk3XR3IEGU_cjs.orderSteps(steps), layout: layout ?? run.layout }
52
62
  };
53
63
  }
54
64
  var layoutOf = (workflow) => workflow.run.kind === "steps" && workflow.run.layout || {};
55
- var explicit = (steps) => steps.map((s) => ({ ...s, after: chunkP2RBE3FD_cjs.stepDependencies(steps, s.id) }));
65
+ var explicit = (steps) => steps.map((s) => ({ ...s, after: chunk3XR3IEGU_cjs.stepDependencies(steps, s.id) }));
56
66
  function stepIdFor(steps, title) {
57
67
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/^[^a-z]+/, "") || "step";
58
68
  const taken = new Set(steps.map((s) => s.id));
@@ -65,7 +75,10 @@ var DEFAULT_TITLES = {
65
75
  form: "Details",
66
76
  upload: "Upload files",
67
77
  agent: "Agent step",
68
- review: "Review"
78
+ review: "Review",
79
+ sign: "Sign",
80
+ email_draft: "Email draft",
81
+ tabular_review: "Tabular review"
69
82
  };
70
83
  function blankStep(kind, id, title) {
71
84
  switch (kind) {
@@ -77,10 +90,26 @@ function blankStep(kind, id, title) {
77
90
  return { id, kind, title };
78
91
  case "review":
79
92
  return { id, kind, title, instructions: "" };
93
+ case "sign":
94
+ return { id, kind: "action", title, action: { type: "sign", signers: [] } };
95
+ case "email_draft":
96
+ return {
97
+ id,
98
+ kind: "action",
99
+ title,
100
+ action: { type: "email_draft", to: [], subject: "", body: "" }
101
+ };
102
+ case "tabular_review":
103
+ return {
104
+ id,
105
+ kind: "action",
106
+ title,
107
+ action: { type: "tabular_review", tags: [], documents: "run_uploads" }
108
+ };
80
109
  }
81
110
  }
82
111
  function addStep(workflow, kind, options = {}) {
83
- const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
112
+ const steps = explicit(chunk3XR3IEGU_cjs.workflowSteps(workflow));
84
113
  const title = options.title ?? DEFAULT_TITLES[kind];
85
114
  const id = stepIdFor(steps, title);
86
115
  const step = { ...blankStep(kind, id, title), after: options.after ? [options.after] : [] };
@@ -89,7 +118,7 @@ function addStep(workflow, kind, options = {}) {
89
118
  return { workflow: withSteps(workflow, [...steps, step], layout), id };
90
119
  }
91
120
  function removeStep(workflow, id) {
92
- const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
121
+ const steps = explicit(chunk3XR3IEGU_cjs.workflowSteps(workflow));
93
122
  const removed = steps.find((s) => s.id === id);
94
123
  if (!removed) return workflow;
95
124
  const bridged = steps.filter((s) => s.id !== id).map(
@@ -102,8 +131,8 @@ function removeStep(workflow, id) {
102
131
  return withSteps(workflow, bridged, layout);
103
132
  }
104
133
  function connectSteps(workflow, from, to) {
105
- const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
106
- if (from === to || !steps.some((s) => s.id === from) || chunkP2RBE3FD_cjs.dependsOn(steps, from, to)) {
134
+ const steps = explicit(chunk3XR3IEGU_cjs.workflowSteps(workflow));
135
+ if (from === to || !steps.some((s) => s.id === from) || chunk3XR3IEGU_cjs.dependsOn(steps, from, to)) {
107
136
  return workflow;
108
137
  }
109
138
  return withSteps(
@@ -113,16 +142,16 @@ function connectSteps(workflow, from, to) {
113
142
  )
114
143
  );
115
144
  }
116
- var wouldCycle = (workflow, from, to) => from === to || chunkP2RBE3FD_cjs.dependsOn(chunkP2RBE3FD_cjs.workflowSteps(workflow), from, to);
145
+ var wouldCycle = (workflow, from, to) => from === to || chunk3XR3IEGU_cjs.dependsOn(chunk3XR3IEGU_cjs.workflowSteps(workflow), from, to);
117
146
  function disconnectSteps(workflow, from, to) {
118
- const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
147
+ const steps = explicit(chunk3XR3IEGU_cjs.workflowSteps(workflow));
119
148
  return withSteps(
120
149
  workflow,
121
150
  steps.map((s) => s.id === to ? { ...s, after: (s.after ?? []).filter((d) => d !== from) } : s)
122
151
  );
123
152
  }
124
153
  function updateStep(workflow, id, patch) {
125
- const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
154
+ const steps = explicit(chunk3XR3IEGU_cjs.workflowSteps(workflow));
126
155
  return withSteps(
127
156
  workflow,
128
157
  steps.map(
@@ -136,27 +165,62 @@ var renameIn = (text, from, to) => text.replace(
136
165
  );
137
166
  function renameInput(workflow, from, to) {
138
167
  if (from === to) return workflow;
139
- const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow).map((s) => {
168
+ const steps = chunk3XR3IEGU_cjs.workflowSteps(workflow).map((s) => {
140
169
  if (s.kind === "agent")
141
170
  return {
142
171
  ...s,
143
172
  with: s.with ? Object.fromEntries(Object.entries(s.with).map(([k, v]) => [k, renameIn(v, from, to)])) : s.with,
144
- run: s.run?.kind === "prompt" ? { ...s.run, promptTemplate: renameIn(s.run.promptTemplate, from, to) } : s.run
173
+ run: s.run?.kind === "prompt" ? { ...s.run, promptTemplate: renameIn(s.run.promptTemplate, from, to) } : s.run,
174
+ ...s.editDocument ? { editDocument: renameRef(s.editDocument, from, to) } : {}
145
175
  };
146
- if (s.kind === "review" && s.instructions)
147
- return { ...s, instructions: renameIn(s.instructions, from, to) };
148
- return s;
176
+ const assignee = s.assignee && renamePerson(s.assignee, from, to);
177
+ const base = assignee ? { ...s, assignee } : s;
178
+ if (base.kind === "review" && base.instructions)
179
+ return { ...base, instructions: renameIn(base.instructions, from, to) };
180
+ if (base.kind === "action") {
181
+ const a = base.action;
182
+ if (a.type === "sign")
183
+ return {
184
+ ...base,
185
+ action: {
186
+ ...a,
187
+ document: a.document && renameRef(a.document, from, to),
188
+ signers: a.signers.map((x) => renamePerson(x, from, to)),
189
+ ...a.message ? { message: renameIn(a.message, from, to) } : {}
190
+ }
191
+ };
192
+ if (a.type === "email_draft")
193
+ return {
194
+ ...base,
195
+ action: {
196
+ ...a,
197
+ to: a.to.map((t) => renameIn(t, from, to)),
198
+ ...a.cc ? { cc: a.cc.map((t) => renameIn(t, from, to)) } : {},
199
+ subject: renameIn(a.subject, from, to),
200
+ body: renameIn(a.body, from, to),
201
+ ...a.attachments ? { attachments: a.attachments.map((r) => renameRef(r, from, to)) } : {}
202
+ }
203
+ };
204
+ if (Array.isArray(a.documents))
205
+ return {
206
+ ...base,
207
+ action: { ...a, documents: a.documents.map((r) => renameRef(r, from, to)) }
208
+ };
209
+ }
210
+ return base;
149
211
  });
150
212
  return withSteps(workflow, steps);
151
213
  }
214
+ var renamePerson = (a, from, to) => "input" in a && a.input === from ? { input: to } : a;
215
+ var renameRef = (r, from, to) => "input" in r && r.input === from ? { input: to } : r;
152
216
  function moveStep(workflow, id, position) {
153
- return withSteps(workflow, chunkP2RBE3FD_cjs.workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
217
+ return withSteps(workflow, chunk3XR3IEGU_cjs.workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
154
218
  }
155
219
  var COLUMN = 300;
156
220
  var ROW = 140;
157
221
  function autoLayout(steps) {
158
222
  const layout = {};
159
- chunkP2RBE3FD_cjs.stepLevels(steps).forEach(
223
+ chunk3XR3IEGU_cjs.stepLevels(steps).forEach(
160
224
  (level, x) => level.forEach((s, y) => {
161
225
  layout[s.id] = { x: x * COLUMN, y: (y - (level.length - 1) / 2) * ROW };
162
226
  })
@@ -164,9 +228,756 @@ function autoLayout(steps) {
164
228
  return layout;
165
229
  }
166
230
  function layoutWithDefaults(workflow) {
167
- const auto = autoLayout(chunkP2RBE3FD_cjs.workflowSteps(workflow));
231
+ const auto = autoLayout(chunk3XR3IEGU_cjs.workflowSteps(workflow));
168
232
  return { ...auto, ...layoutOf(workflow) };
169
233
  }
234
+ var DEFAULT_SIGNALS_EDITOR_LABELS = {
235
+ heading: "When done, signal\u2026",
236
+ hint: "Another workflow can start on a signal (\u201CWhen a step signals\u201D), as its own thread linked to this one.",
237
+ add: "Add signal",
238
+ name: "Signal",
239
+ namePlaceholder: "e.g. risk-high",
240
+ when: "When",
241
+ always: "Whenever it is done",
242
+ fieldEquals: "A field equals",
243
+ answerContains: "The answer contains",
244
+ answerMatches: "The answer matches (regex)",
245
+ approved: "It is approved",
246
+ field: "Field",
247
+ value: "Value",
248
+ phrase: "Phrase",
249
+ phrasePlaceholder: "e.g. Risk rating: High",
250
+ pattern: "Pattern",
251
+ remove: "Remove signal"
252
+ };
253
+ function signalConditions(kind) {
254
+ switch (kind) {
255
+ case "form":
256
+ return ["always", "field"];
257
+ case "agent":
258
+ return ["always", "contains", "matches"];
259
+ case "review":
260
+ return ["approved", "always"];
261
+ default:
262
+ return ["always"];
263
+ }
264
+ }
265
+ function conditionOf(when) {
266
+ if (!when) return "always";
267
+ if ("field" in when) return "field";
268
+ if ("contains" in when) return "contains";
269
+ if ("matches" in when) return "matches";
270
+ return "approved";
271
+ }
272
+ function signalSlug(text) {
273
+ return text.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^[^a-z0-9]+/, "").slice(0, 64);
274
+ }
275
+ function startCondition(kind, step) {
276
+ switch (kind) {
277
+ case "field":
278
+ return { field: step.kind === "form" ? step.inputs[0]?.name ?? "" : "", equals: "" };
279
+ case "contains":
280
+ return { contains: "" };
281
+ case "matches":
282
+ return { matches: "" };
283
+ case "approved":
284
+ return { approved: true };
285
+ default:
286
+ return void 0;
287
+ }
288
+ }
289
+ function newSignal(step, taken) {
290
+ const base = signalSlug(step.id) || "signal";
291
+ let name = `${base}-done`;
292
+ let n = 2;
293
+ while (taken.includes(name)) name = `${base}-done-${n++}`;
294
+ const when = startCondition(signalConditions(step.kind)[0], step);
295
+ return when ? { name, when } : { name };
296
+ }
297
+ var selectClass = "flex h-8 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";
298
+ function SignalsEditor({
299
+ step,
300
+ onChange,
301
+ labels,
302
+ testId = "signals-editor"
303
+ }) {
304
+ const l = { ...DEFAULT_SIGNALS_EDITOR_LABELS, ...labels };
305
+ const signals = step.signals ?? [];
306
+ const conditions = signalConditions(step.kind);
307
+ const conditionLabel = {
308
+ always: l.always,
309
+ field: l.fieldEquals,
310
+ contains: l.answerContains,
311
+ matches: l.answerMatches,
312
+ approved: l.approved
313
+ };
314
+ const emit = (next) => onChange(next.length ? next : void 0);
315
+ const set = (i, signal) => emit(signals.map((s, j) => j === i ? signal : s));
316
+ const fields = step.kind === "form" ? step.inputs : [];
317
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [
318
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.heading }),
319
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
320
+ signals.map((signal, i) => {
321
+ const condition = conditionOf(signal.when);
322
+ const when = signal.when;
323
+ return /* @__PURE__ */ jsxRuntime.jsxs(
324
+ "div",
325
+ {
326
+ className: ui.cn(
327
+ "space-y-1.5 rounded-md border p-2",
328
+ chunk3XR3IEGU_cjs.isIncompleteSignal(signal) ? "border-destructive/50" : "border-border"
329
+ ),
330
+ "data-incomplete": chunk3XR3IEGU_cjs.isIncompleteSignal(signal) || void 0,
331
+ "data-testid": `${testId}-${i}`,
332
+ children: [
333
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
334
+ /* @__PURE__ */ jsxRuntime.jsx(
335
+ ui.Input,
336
+ {
337
+ value: signal.name,
338
+ "aria-label": l.name,
339
+ placeholder: l.namePlaceholder,
340
+ onChange: (e) => set(i, { ...signal, name: signalSlug(e.target.value) }),
341
+ className: "h-8 font-mono text-xs",
342
+ "data-testid": `${testId}-${i}-name`
343
+ }
344
+ ),
345
+ /* @__PURE__ */ jsxRuntime.jsx(
346
+ "button",
347
+ {
348
+ type: "button",
349
+ "aria-label": l.remove,
350
+ onClick: () => emit(signals.filter((_, j) => j !== i)),
351
+ "data-testid": `${testId}-${i}-remove`,
352
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4 text-muted-foreground" })
353
+ }
354
+ )
355
+ ] }),
356
+ /* @__PURE__ */ jsxRuntime.jsx(
357
+ "select",
358
+ {
359
+ "aria-label": l.when,
360
+ className: selectClass,
361
+ value: condition,
362
+ onChange: (e) => {
363
+ const nextWhen = startCondition(e.target.value, step);
364
+ set(i, nextWhen ? { name: signal.name, when: nextWhen } : { name: signal.name });
365
+ },
366
+ "data-testid": `${testId}-${i}-when`,
367
+ children: [...conditions, ...conditions.includes(condition) ? [] : [condition]].map(
368
+ (c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c, children: conditionLabel[c] }, c)
369
+ )
370
+ }
371
+ ),
372
+ when && "field" in when && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
373
+ /* @__PURE__ */ jsxRuntime.jsxs(
374
+ "select",
375
+ {
376
+ "aria-label": l.field,
377
+ className: ui.cn(selectClass, "flex-1"),
378
+ value: when.field,
379
+ onChange: (e) => set(i, { ...signal, when: { ...when, field: e.target.value } }),
380
+ "data-testid": `${testId}-${i}-field`,
381
+ children: [
382
+ fields.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.name, children: f.label }, f.name)),
383
+ !fields.some((f) => f.name === when.field) && /* @__PURE__ */ jsxRuntime.jsx("option", { value: when.field, children: when.field || "\u2014" })
384
+ ]
385
+ }
386
+ ),
387
+ /* @__PURE__ */ jsxRuntime.jsx(
388
+ ui.Input,
389
+ {
390
+ "aria-label": l.value,
391
+ placeholder: l.value,
392
+ value: String(when.equals),
393
+ onChange: (e) => set(i, { ...signal, when: { ...when, equals: e.target.value } }),
394
+ className: "h-8 flex-1",
395
+ "data-testid": `${testId}-${i}-equals`
396
+ }
397
+ )
398
+ ] }),
399
+ when && "contains" in when && /* @__PURE__ */ jsxRuntime.jsx(
400
+ ui.Input,
401
+ {
402
+ "aria-label": l.phrase,
403
+ placeholder: l.phrasePlaceholder,
404
+ value: when.contains,
405
+ onChange: (e) => set(i, { ...signal, when: { contains: e.target.value } }),
406
+ className: "h-8",
407
+ "data-testid": `${testId}-${i}-contains`
408
+ }
409
+ ),
410
+ when && "matches" in when && /* @__PURE__ */ jsxRuntime.jsx(
411
+ ui.Input,
412
+ {
413
+ "aria-label": l.pattern,
414
+ placeholder: "risk rating:\\s*high",
415
+ value: when.matches,
416
+ onChange: (e) => set(i, { ...signal, when: { matches: e.target.value } }),
417
+ className: "h-8 font-mono text-xs",
418
+ "data-testid": `${testId}-${i}-matches`
419
+ }
420
+ )
421
+ ]
422
+ },
423
+ i
424
+ );
425
+ }),
426
+ /* @__PURE__ */ jsxRuntime.jsxs(
427
+ ui.Button,
428
+ {
429
+ variant: "outline",
430
+ size: "sm",
431
+ onClick: () => emit([
432
+ ...signals,
433
+ newSignal(
434
+ step,
435
+ signals.map((s) => s.name)
436
+ )
437
+ ]),
438
+ "data-testid": `${testId}-add`,
439
+ children: [
440
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }),
441
+ " ",
442
+ l.add
443
+ ]
444
+ }
445
+ )
446
+ ] }),
447
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: l.hint })
448
+ ] });
449
+ }
450
+ var DEFAULT_STEP_ACTION_SETTINGS_LABELS = {
451
+ assignee: "Who does it",
452
+ assigneeAnyone: "Anyone on the run",
453
+ assigneeRunOwner: "Whoever started the run",
454
+ assigneeProjectLead: "The project lead",
455
+ assigneeFields: "The person in a form field",
456
+ assigneePeople: "A person",
457
+ remind: "Remind after (hours)",
458
+ remindHint: "Left that long, they are told again. Blank: no reminder.",
459
+ documentFrom: "Document",
460
+ docFromStep: "From an earlier step",
461
+ docFromInput: "From a run input",
462
+ docById: "A document",
463
+ chooseStep: "Choose a step\u2026",
464
+ chooseInput: "Choose an input\u2026",
465
+ chooseDocument: "Choose a document\u2026",
466
+ documentIdPlaceholder: "doc-\u2026",
467
+ signDocument: "Document to sign",
468
+ signers: "Signers",
469
+ addSigner: "Add signer",
470
+ signMessage: "Message to the signers",
471
+ expires: "Expires after (hours)",
472
+ expiresHint: "Unsigned by then, the step fails. Blank: no expiry.",
473
+ emailTo: "To",
474
+ emailCc: "Cc",
475
+ emailSubject: "Subject",
476
+ emailBody: "Body",
477
+ addressesHint: "Separate several with commas.",
478
+ variablesHint: "Variables (click to add to the body):",
479
+ attachments: "Attachments",
480
+ addAttachment: "Add attachment",
481
+ reviewColumns: "Columns (labels)",
482
+ noTags: "No labels in this workspace yet.",
483
+ reviewDocuments: "Documents",
484
+ reviewRunUploads: "The files this run collects",
485
+ reviewWorkspace: "Every document in the workspace",
486
+ reviewChosen: "Chosen documents",
487
+ addDocument: "Add document",
488
+ overwrite: "Fill cells that already have a value again",
489
+ editDocument: "Edit this document (tracked changes)",
490
+ editDocumentHint: "The instruction says what to change; the edited copy is saved as its next version, to accept or reject change by change."
491
+ };
492
+ 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";
493
+ function Field({
494
+ label,
495
+ children,
496
+ hint
497
+ }) {
498
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
499
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: label }),
500
+ children,
501
+ hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: hint })
502
+ ] });
503
+ }
504
+ var assigneeValue = (a) => !a ? "" : "user" in a ? `user:${a.user}` : "input" in a ? `input:${a.input}` : "runOwner" in a ? "owner" : "lead";
505
+ var parseAssignee = (v) => v === "owner" ? { runOwner: true } : v === "lead" ? { projectLead: true } : v.startsWith("user:") ? { user: v.slice(5) } : v.startsWith("input:") ? { input: v.slice(6) } : void 0;
506
+ function AssigneeSelect({
507
+ value,
508
+ onChange,
509
+ ctx,
510
+ l,
511
+ anyone,
512
+ testId,
513
+ ariaLabel
514
+ }) {
515
+ const personFields = ctx.fields.filter((f) => f.type === "person");
516
+ const v = assigneeValue(value);
517
+ const known = !v.startsWith("user:") || ctx.people.some((p) => `user:${p.value}` === v) ? null : v.slice(5);
518
+ return /* @__PURE__ */ jsxRuntime.jsxs(
519
+ "select",
520
+ {
521
+ className: selectClass2,
522
+ value: v,
523
+ "aria-label": ariaLabel,
524
+ onChange: (e) => onChange(parseAssignee(e.target.value)),
525
+ "data-testid": testId,
526
+ children: [
527
+ anyone !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: anyone }) : /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true }),
528
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "owner", children: l.assigneeRunOwner }),
529
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "lead", children: l.assigneeProjectLead }),
530
+ personFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: l.assigneeFields, children: personFields.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: `input:${f.name}`, children: f.label }, f.name)) }),
531
+ (ctx.people.length > 0 || known) && /* @__PURE__ */ jsxRuntime.jsxs("optgroup", { label: l.assigneePeople, children: [
532
+ ctx.people.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: `user:${p.value}`, children: p.label }, p.value)),
533
+ known && /* @__PURE__ */ jsxRuntime.jsx("option", { value: v, children: known })
534
+ ] })
535
+ ]
536
+ }
537
+ );
538
+ }
539
+ function AssigneeSettings({
540
+ step,
541
+ patch,
542
+ ctx,
543
+ l,
544
+ testId
545
+ }) {
546
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
547
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.assignee, children: /* @__PURE__ */ jsxRuntime.jsx(
548
+ AssigneeSelect,
549
+ {
550
+ value: step.assignee,
551
+ onChange: (assignee) => patch({ assignee }),
552
+ ctx,
553
+ l,
554
+ anyone: l.assigneeAnyone,
555
+ testId: `${testId}-assignee`
556
+ }
557
+ ) }),
558
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.remind, hint: l.remindHint, children: /* @__PURE__ */ jsxRuntime.jsx(
559
+ ui.Input,
560
+ {
561
+ type: "number",
562
+ min: 1,
563
+ value: step.remindAfterHours ?? "",
564
+ onChange: (e) => {
565
+ const n = Number(e.target.value);
566
+ patch({ remindAfterHours: e.target.value && n > 0 ? n : void 0 });
567
+ },
568
+ className: "w-28",
569
+ "data-testid": `${testId}-remind`
570
+ }
571
+ ) })
572
+ ] });
573
+ }
574
+ var modeOf = (ref) => !ref ? "step" : "step" in ref ? "step" : "input" in ref ? "input" : "id";
575
+ function DocumentRefPicker({
576
+ value,
577
+ onChange,
578
+ ctx,
579
+ l,
580
+ testId
581
+ }) {
582
+ const mode = modeOf(value);
583
+ const inputs = ctx.fields.filter((f) => f.type === "documents" || f.type === "text");
584
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [
585
+ /* @__PURE__ */ jsxRuntime.jsxs(
586
+ "select",
587
+ {
588
+ className: ui.cn(selectClass2, "h-8"),
589
+ value: mode,
590
+ "aria-label": l.documentFrom,
591
+ onChange: (e) => {
592
+ const m = e.target.value;
593
+ onChange(m === "step" ? { step: "" } : m === "input" ? { input: "" } : { id: "" });
594
+ },
595
+ "data-testid": `${testId}-mode`,
596
+ children: [
597
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "step", children: l.docFromStep }),
598
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "input", children: l.docFromInput }),
599
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "id", children: l.docById })
600
+ ]
601
+ }
602
+ ),
603
+ mode === "step" && /* @__PURE__ */ jsxRuntime.jsxs(
604
+ "select",
605
+ {
606
+ className: ui.cn(selectClass2, "h-8"),
607
+ value: value && "step" in value ? value.step : "",
608
+ onChange: (e) => onChange({ step: e.target.value }),
609
+ "data-testid": `${testId}-step`,
610
+ children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: l.chooseStep }),
612
+ ctx.earlier.map((s) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: s.id, children: s.title }, s.id))
613
+ ]
614
+ }
615
+ ),
616
+ mode === "input" && /* @__PURE__ */ jsxRuntime.jsxs(
617
+ "select",
618
+ {
619
+ className: ui.cn(selectClass2, "h-8"),
620
+ value: value && "input" in value ? value.input : "",
621
+ onChange: (e) => onChange({ input: e.target.value }),
622
+ "data-testid": `${testId}-input`,
623
+ children: [
624
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: l.chooseInput }),
625
+ inputs.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.name, children: f.label }, f.name))
626
+ ]
627
+ }
628
+ ),
629
+ mode === "id" && (ctx.documents.length ? /* @__PURE__ */ jsxRuntime.jsxs(
630
+ "select",
631
+ {
632
+ className: ui.cn(selectClass2, "h-8"),
633
+ value: value && "id" in value ? value.id : "",
634
+ onChange: (e) => onChange({ id: e.target.value }),
635
+ "data-testid": `${testId}-id`,
636
+ children: [
637
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: l.chooseDocument }),
638
+ ctx.documents.map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d.value, children: d.label }, d.value))
639
+ ]
640
+ }
641
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
642
+ ui.Input,
643
+ {
644
+ className: "h-8",
645
+ value: value && "id" in value ? value.id : "",
646
+ placeholder: l.documentIdPlaceholder,
647
+ onChange: (e) => onChange({ id: e.target.value }),
648
+ "data-testid": `${testId}-id`
649
+ }
650
+ ))
651
+ ] });
652
+ }
653
+ function DocumentRefList({
654
+ value,
655
+ onChange,
656
+ ctx,
657
+ l,
658
+ addLabel,
659
+ testId
660
+ }) {
661
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
662
+ value.map((ref, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-1.5", children: [
663
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
664
+ DocumentRefPicker,
665
+ {
666
+ value: ref,
667
+ onChange: (next) => onChange(value.map((r, j) => j === i ? next : r)),
668
+ ctx,
669
+ l,
670
+ testId: `${testId}-${i}`
671
+ }
672
+ ) }),
673
+ /* @__PURE__ */ jsxRuntime.jsx(
674
+ "button",
675
+ {
676
+ type: "button",
677
+ className: "mt-2",
678
+ "aria-label": `${addLabel} \xD7`,
679
+ onClick: () => onChange(value.filter((_, j) => j !== i)),
680
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4 text-muted-foreground" })
681
+ }
682
+ )
683
+ ] }, i)),
684
+ /* @__PURE__ */ jsxRuntime.jsxs(
685
+ ui.Button,
686
+ {
687
+ variant: "outline",
688
+ size: "sm",
689
+ onClick: () => onChange([...value, { step: "" }]),
690
+ "data-testid": `${testId}-add`,
691
+ children: [
692
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }),
693
+ " ",
694
+ addLabel
695
+ ]
696
+ }
697
+ )
698
+ ] });
699
+ }
700
+ var optionalNumber = (raw) => {
701
+ const n = Number(raw);
702
+ return raw && n > 0 ? n : void 0;
703
+ };
704
+ function SignSettings({
705
+ action,
706
+ onChange,
707
+ ctx,
708
+ l,
709
+ testId
710
+ }) {
711
+ const set = (p) => onChange({ ...action, ...p });
712
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.signDocument, children: /* @__PURE__ */ jsxRuntime.jsx(
714
+ DocumentRefPicker,
715
+ {
716
+ value: action.document,
717
+ onChange: (document) => set({ document }),
718
+ ctx,
719
+ l,
720
+ testId: `${testId}-document`
721
+ }
722
+ ) }),
723
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.signers, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", "data-testid": `${testId}-signers`, children: [
724
+ action.signers.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
725
+ /* @__PURE__ */ jsxRuntime.jsx(
726
+ AssigneeSelect,
727
+ {
728
+ value: s,
729
+ onChange: (next) => set({
730
+ signers: next ? action.signers.map((x, j) => j === i ? next : x) : action.signers.filter((_, j) => j !== i)
731
+ }),
732
+ ctx,
733
+ l,
734
+ ariaLabel: `${l.signers} ${i + 1}`,
735
+ testId: `${testId}-signer-${i}`
736
+ }
737
+ ),
738
+ /* @__PURE__ */ jsxRuntime.jsx(
739
+ "button",
740
+ {
741
+ type: "button",
742
+ "aria-label": `${l.signers} ${i + 1} \xD7`,
743
+ onClick: () => set({ signers: action.signers.filter((_, j) => j !== i) }),
744
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4 text-muted-foreground" })
745
+ }
746
+ )
747
+ ] }, i)),
748
+ /* @__PURE__ */ jsxRuntime.jsxs(
749
+ ui.Button,
750
+ {
751
+ variant: "outline",
752
+ size: "sm",
753
+ onClick: () => set({ signers: [...action.signers, { runOwner: true }] }),
754
+ "data-testid": `${testId}-add-signer`,
755
+ children: [
756
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }),
757
+ " ",
758
+ l.addSigner
759
+ ]
760
+ }
761
+ )
762
+ ] }) }),
763
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.signMessage, children: /* @__PURE__ */ jsxRuntime.jsx(
764
+ ui.Textarea,
765
+ {
766
+ rows: 3,
767
+ value: action.message ?? "",
768
+ onChange: (e) => set({ message: e.target.value || void 0 }),
769
+ "data-testid": `${testId}-message`
770
+ }
771
+ ) }),
772
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.expires, hint: l.expiresHint, children: /* @__PURE__ */ jsxRuntime.jsx(
773
+ ui.Input,
774
+ {
775
+ type: "number",
776
+ min: 1,
777
+ className: "w-28",
778
+ value: action.expiresAfterHours ?? "",
779
+ onChange: (e) => set({ expiresAfterHours: optionalNumber(e.target.value) }),
780
+ "data-testid": `${testId}-expires`
781
+ }
782
+ ) })
783
+ ] });
784
+ }
785
+ var addresses = (list) => (list ?? []).join(", ");
786
+ var parseAddresses = (text) => text.split(",").map((t) => t.trim());
787
+ function templateVariables(ctx) {
788
+ return [
789
+ ...ctx.fields.map((f) => `{{${f.name}}}`),
790
+ ...ctx.earlier.filter((s) => s.kind === "agent").map((s) => `{{${s.id}.answer}}`)
791
+ ];
792
+ }
793
+ function EmailDraftSettings({
794
+ action,
795
+ onChange,
796
+ ctx,
797
+ l,
798
+ testId
799
+ }) {
800
+ const set = (p) => onChange({ ...action, ...p });
801
+ const vars = templateVariables(ctx);
802
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
803
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.emailTo, hint: l.addressesHint, children: /* @__PURE__ */ jsxRuntime.jsx(
804
+ ui.Input,
805
+ {
806
+ value: addresses(action.to),
807
+ onChange: (e) => set({ to: parseAddresses(e.target.value) }),
808
+ placeholder: "{{client_email}}",
809
+ "data-testid": `${testId}-to`
810
+ }
811
+ ) }),
812
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.emailCc, children: /* @__PURE__ */ jsxRuntime.jsx(
813
+ ui.Input,
814
+ {
815
+ value: addresses(action.cc),
816
+ onChange: (e) => {
817
+ const cc = parseAddresses(e.target.value);
818
+ set({ cc: cc.some(Boolean) ? cc : void 0 });
819
+ },
820
+ "data-testid": `${testId}-cc`
821
+ }
822
+ ) }),
823
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.emailSubject, children: /* @__PURE__ */ jsxRuntime.jsx(
824
+ ui.Input,
825
+ {
826
+ value: action.subject,
827
+ onChange: (e) => set({ subject: e.target.value }),
828
+ "data-testid": `${testId}-subject`
829
+ }
830
+ ) }),
831
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.emailBody, children: /* @__PURE__ */ jsxRuntime.jsx(
832
+ ui.Textarea,
833
+ {
834
+ rows: 6,
835
+ value: action.body,
836
+ onChange: (e) => set({ body: e.target.value }),
837
+ "data-testid": `${testId}-body`
838
+ }
839
+ ) }),
840
+ vars.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1", "data-testid": `${testId}-variables`, children: [
841
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-full text-xs text-muted-foreground", children: l.variablesHint }),
842
+ vars.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
843
+ "button",
844
+ {
845
+ type: "button",
846
+ onClick: () => set({ body: `${action.body}${action.body ? " " : ""}${v}` }),
847
+ className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground hover:text-foreground",
848
+ title: v,
849
+ children: v
850
+ },
851
+ v
852
+ ))
853
+ ] }),
854
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.attachments, children: /* @__PURE__ */ jsxRuntime.jsx(
855
+ DocumentRefList,
856
+ {
857
+ value: action.attachments ?? [],
858
+ onChange: (attachments) => set({ attachments: attachments.length ? attachments : void 0 }),
859
+ ctx,
860
+ l,
861
+ addLabel: l.addAttachment,
862
+ testId: `${testId}-attachments`
863
+ }
864
+ ) })
865
+ ] });
866
+ }
867
+ function TabularReviewSettings({
868
+ action,
869
+ onChange,
870
+ ctx,
871
+ l,
872
+ testId
873
+ }) {
874
+ const set = (p) => onChange({ ...action, ...p });
875
+ const mode = Array.isArray(action.documents) ? "chosen" : action.documents;
876
+ const toggle = (id) => set({
877
+ tags: action.tags.includes(id) ? action.tags.filter((t) => t !== id) : [...action.tags, id]
878
+ });
879
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
880
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.reviewColumns, children: /* @__PURE__ */ jsxRuntime.jsxs(
881
+ "div",
882
+ {
883
+ className: "max-h-44 space-y-1 overflow-y-auto rounded-md border border-border p-2",
884
+ "data-testid": `${testId}-tags`,
885
+ children: [
886
+ ctx.tags.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: l.noTags }),
887
+ ctx.tags.map((t) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
888
+ /* @__PURE__ */ jsxRuntime.jsx(
889
+ ui.Checkbox,
890
+ {
891
+ checked: action.tags.includes(t.value),
892
+ onCheckedChange: () => toggle(t.value),
893
+ "data-testid": `${testId}-tag-${t.value}`
894
+ }
895
+ ),
896
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: t.label })
897
+ ] }, t.value)),
898
+ action.tags.filter((t) => !ctx.tags.some((x) => x.value === t)).map((t) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
899
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: true, onCheckedChange: () => toggle(t) }),
900
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-xs", children: t })
901
+ ] }, t))
902
+ ]
903
+ }
904
+ ) }),
905
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.reviewDocuments, children: /* @__PURE__ */ jsxRuntime.jsxs(
906
+ "select",
907
+ {
908
+ className: selectClass2,
909
+ value: mode,
910
+ onChange: (e) => {
911
+ const v = e.target.value;
912
+ set({ documents: v === "chosen" ? [] : v });
913
+ },
914
+ "data-testid": `${testId}-documents`,
915
+ children: [
916
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "run_uploads", children: l.reviewRunUploads }),
917
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "workspace", children: l.reviewWorkspace }),
918
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "chosen", children: l.reviewChosen })
919
+ ]
920
+ }
921
+ ) }),
922
+ Array.isArray(action.documents) && /* @__PURE__ */ jsxRuntime.jsx(
923
+ DocumentRefList,
924
+ {
925
+ value: action.documents,
926
+ onChange: (documents) => set({ documents }),
927
+ ctx,
928
+ l,
929
+ addLabel: l.addDocument,
930
+ testId: `${testId}-chosen`
931
+ }
932
+ ),
933
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
934
+ /* @__PURE__ */ jsxRuntime.jsx(
935
+ ui.Checkbox,
936
+ {
937
+ checked: !!action.overwrite,
938
+ onCheckedChange: (v) => set({ overwrite: v === true || void 0 })
939
+ }
940
+ ),
941
+ l.overwrite
942
+ ] })
943
+ ] });
944
+ }
945
+ function EditDocumentSettings({
946
+ step,
947
+ patch,
948
+ ctx,
949
+ l,
950
+ testId
951
+ }) {
952
+ const on = !!step.editDocument;
953
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
954
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx(
956
+ ui.Checkbox,
957
+ {
958
+ checked: on,
959
+ disabled: !!step.branch,
960
+ onCheckedChange: (v) => patch({ editDocument: v === true ? { step: "" } : void 0 }),
961
+ "data-testid": `${testId}-edit-document`
962
+ }
963
+ ),
964
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
965
+ l.editDocument,
966
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-muted-foreground", children: l.editDocumentHint })
967
+ ] })
968
+ ] }),
969
+ on && /* @__PURE__ */ jsxRuntime.jsx(
970
+ DocumentRefPicker,
971
+ {
972
+ value: step.editDocument,
973
+ onChange: (editDocument) => patch({ editDocument }),
974
+ ctx,
975
+ l,
976
+ testId: `${testId}-edit-document-ref`
977
+ }
978
+ )
979
+ ] });
980
+ }
170
981
  var DEFAULT_STEP_INSPECTOR_LABELS = {
171
982
  workflow: "Workflow",
172
983
  title: "Title",
@@ -196,17 +1007,19 @@ var DEFAULT_STEP_INSPECTOR_LABELS = {
196
1007
  hint: "Hint",
197
1008
  instructions: "What to review",
198
1009
  instructionsHint: "Shown on the review task; {{field}} and {{steps.<id>}} work here.",
1010
+ reviewFields: "Filled in when approving",
1011
+ reviewFieldsHint: "E.g. a rating or a comment; the answers join the run\u2019s inputs.",
199
1012
  deleteStep: "Delete step"
200
1013
  };
201
- var FIELD_TYPES = ["text", "longtext", "boolean", "number", "date", "scope"];
202
- 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";
203
- function Field({ label, children, hint }) {
204
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
205
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: label }),
206
- children,
207
- hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: hint })
208
- ] });
209
- }
1014
+ var FIELD_TYPES = [
1015
+ "text",
1016
+ "longtext",
1017
+ "boolean",
1018
+ "number",
1019
+ "date",
1020
+ "scope",
1021
+ "person"
1022
+ ];
210
1023
  var fieldName = (label, taken) => {
211
1024
  const base = label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").replace(/^[^a-z]+/, "") || "field";
212
1025
  let name = base;
@@ -220,11 +1033,16 @@ function StepInspector({
220
1033
  onChange,
221
1034
  onSelect,
222
1035
  workflows = [],
1036
+ people = [],
1037
+ tags = [],
1038
+ documents = [],
223
1039
  labels,
1040
+ actionLabels,
1041
+ signalLabels,
224
1042
  testId = "step-inspector"
225
1043
  }) {
226
1044
  const l = { ...DEFAULT_STEP_INSPECTOR_LABELS, ...labels };
227
- const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
1045
+ const steps = chunk3XR3IEGU_cjs.workflowSteps(workflow);
228
1046
  const step = steps.find((s) => s.id === stepId);
229
1047
  const run = workflow.run.kind === "steps" ? workflow.run : void 0;
230
1048
  if (!step || !run) {
@@ -249,7 +1067,31 @@ function StepInspector({
249
1067
  ] });
250
1068
  }
251
1069
  const patch = (p) => onChange(updateStep(workflow, step.id, p));
252
- const deps = chunkP2RBE3FD_cjs.stepDependencies(steps, step.id);
1070
+ const al = { ...DEFAULT_STEP_ACTION_SETTINGS_LABELS, ...actionLabels };
1071
+ const ctx = {
1072
+ earlier: chunk3XR3IEGU_cjs.upstreamSteps(steps, step.id),
1073
+ fields: chunk3XR3IEGU_cjs.runFields(workflow),
1074
+ people,
1075
+ tags,
1076
+ documents
1077
+ };
1078
+ const takenBy = (id) => steps.flatMap(
1079
+ (s) => s.id === id ? [] : s.kind === "form" ? s.inputs : s.kind === "review" ? s.fields ?? [] : []
1080
+ ).map((f) => f.name);
1081
+ const setFields = (before, after, key) => {
1082
+ const renamed = before.flatMap(
1083
+ (f, i) => after[i] && after[i].name !== f.name ? [[f.name, after[i].name]] : []
1084
+ );
1085
+ onChange(
1086
+ renamed.reduce(
1087
+ (w, [from, to]) => renameInput(w, from, to),
1088
+ updateStep(workflow, step.id, {
1089
+ [key]: key === "fields" && !after.length ? void 0 : after
1090
+ })
1091
+ )
1092
+ );
1093
+ };
1094
+ const deps = chunk3XR3IEGU_cjs.stepDependencies(steps, step.id);
253
1095
  const titleOf = (id) => steps.find((s) => s.id === id)?.title ?? id;
254
1096
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": `${testId}-step`, children: [
255
1097
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
@@ -298,18 +1140,8 @@ function StepInspector({
298
1140
  FormFields,
299
1141
  {
300
1142
  fields: step.inputs,
301
- taken: steps.flatMap((s) => s.kind === "form" && s.id !== step.id ? s.inputs : []).map((f) => f.name),
302
- onChange: (inputs) => {
303
- const renamed = step.inputs.flatMap(
304
- (f, i) => inputs[i] && inputs[i].name !== f.name ? [[f.name, inputs[i].name]] : []
305
- );
306
- onChange(
307
- renamed.reduce(
308
- (w, [from, to]) => renameInput(w, from, to),
309
- updateStep(workflow, step.id, { inputs })
310
- )
311
- );
312
- },
1143
+ taken: takenBy(step.id),
1144
+ onChange: (inputs) => setFields(step.inputs, inputs, "inputs"),
313
1145
  l,
314
1146
  testId
315
1147
  }
@@ -333,26 +1165,82 @@ function StepInspector({
333
1165
  }
334
1166
  ) })
335
1167
  ] }),
336
- step.kind === "agent" && /* @__PURE__ */ jsxRuntime.jsx(
337
- AgentSettings,
1168
+ step.kind === "agent" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1169
+ /* @__PURE__ */ jsxRuntime.jsx(
1170
+ AgentSettings,
1171
+ {
1172
+ step,
1173
+ workflows,
1174
+ fields: chunk3XR3IEGU_cjs.runFields(workflow).map((f) => f.name),
1175
+ patch,
1176
+ l,
1177
+ testId
1178
+ }
1179
+ ),
1180
+ /* @__PURE__ */ jsxRuntime.jsx(EditDocumentSettings, { step, patch, ctx, l: al, testId })
1181
+ ] }),
1182
+ step.kind === "review" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1183
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsxRuntime.jsx(
1184
+ ui.Textarea,
1185
+ {
1186
+ value: step.instructions ?? "",
1187
+ rows: 4,
1188
+ onChange: (e) => patch({ instructions: e.target.value || void 0 }),
1189
+ "data-testid": `${testId}-instructions`
1190
+ }
1191
+ ) }),
1192
+ /* @__PURE__ */ jsxRuntime.jsx(
1193
+ FormFields,
1194
+ {
1195
+ fields: step.fields ?? [],
1196
+ taken: takenBy(step.id),
1197
+ onChange: (fields) => setFields(step.fields ?? [], fields, "fields"),
1198
+ l: { ...l, fields: l.reviewFields },
1199
+ hint: l.reviewFieldsHint,
1200
+ testId: `${testId}-review`
1201
+ }
1202
+ )
1203
+ ] }),
1204
+ step.kind === "action" && step.action.type === "sign" && /* @__PURE__ */ jsxRuntime.jsx(
1205
+ SignSettings,
338
1206
  {
339
- step,
340
- workflows,
341
- fields: chunkP2RBE3FD_cjs.runFields(workflow).map((f) => f.name),
342
- patch,
343
- l,
344
- testId
1207
+ action: step.action,
1208
+ onChange: (action) => patch({ action }),
1209
+ ctx,
1210
+ l: al,
1211
+ testId: `${testId}-sign`
345
1212
  }
346
1213
  ),
347
- step.kind === "review" && /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsxRuntime.jsx(
348
- ui.Textarea,
1214
+ step.kind === "action" && step.action.type === "email_draft" && /* @__PURE__ */ jsxRuntime.jsx(
1215
+ EmailDraftSettings,
349
1216
  {
350
- value: step.instructions ?? "",
351
- rows: 4,
352
- onChange: (e) => patch({ instructions: e.target.value || void 0 }),
353
- "data-testid": `${testId}-instructions`
1217
+ action: step.action,
1218
+ onChange: (action) => patch({ action }),
1219
+ ctx,
1220
+ l: al,
1221
+ testId: `${testId}-email`
354
1222
  }
355
- ) }),
1223
+ ),
1224
+ step.kind === "action" && step.action.type === "tabular_review" && /* @__PURE__ */ jsxRuntime.jsx(
1225
+ TabularReviewSettings,
1226
+ {
1227
+ action: step.action,
1228
+ onChange: (action) => patch({ action }),
1229
+ ctx,
1230
+ l: al,
1231
+ testId: `${testId}-review-grid`
1232
+ }
1233
+ ),
1234
+ chunk3XR3IEGU_cjs.canAssign(step) && /* @__PURE__ */ jsxRuntime.jsx(AssigneeSettings, { step, patch, ctx, l: al, testId }),
1235
+ /* @__PURE__ */ jsxRuntime.jsx(
1236
+ SignalsEditor,
1237
+ {
1238
+ step,
1239
+ onChange: (signals) => patch({ signals }),
1240
+ labels: signalLabels,
1241
+ testId: `${testId}-signals`
1242
+ }
1243
+ ),
356
1244
  /* @__PURE__ */ jsxRuntime.jsxs(
357
1245
  ui.Button,
358
1246
  {
@@ -378,10 +1266,11 @@ function FormFields({
378
1266
  taken,
379
1267
  onChange,
380
1268
  l,
1269
+ hint,
381
1270
  testId
382
1271
  }) {
383
1272
  const set = (i, p) => onChange(fields.map((f, j) => j === i ? { ...f, ...p } : f));
384
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.fields, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": `${testId}-fields`, children: [
1273
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.fields, hint, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": `${testId}-fields`, children: [
385
1274
  fields.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 rounded-md border border-border p-2", children: [
386
1275
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
387
1276
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -414,10 +1303,12 @@ function FormFields({
414
1303
  "select",
415
1304
  {
416
1305
  "aria-label": l.fieldType,
417
- className: ui.cn(selectClass, "h-8"),
1306
+ className: ui.cn(selectClass2, "h-8"),
418
1307
  value: f.type,
419
1308
  onChange: (e) => set(i, { type: e.target.value }),
420
- children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t))
1309
+ children: (FIELD_TYPES.includes(f.type) ? FIELD_TYPES : [...FIELD_TYPES, f.type]).map(
1310
+ (t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t)
1311
+ )
421
1312
  }
422
1313
  ),
423
1314
  /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex shrink-0 items-center gap-1.5 text-xs", children: [
@@ -481,7 +1372,7 @@ function AgentSettings({
481
1372
  /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.runs, children: /* @__PURE__ */ jsxRuntime.jsxs(
482
1373
  "select",
483
1374
  {
484
- className: selectClass,
1375
+ className: selectClass2,
485
1376
  value,
486
1377
  onChange: (e) => {
487
1378
  const id = e.target.value;
@@ -538,7 +1429,7 @@ function AgentSettings({
538
1429
  /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.thread, children: /* @__PURE__ */ jsxRuntime.jsxs(
539
1430
  "select",
540
1431
  {
541
- className: selectClass,
1432
+ className: selectClass2,
542
1433
  value: step.branch ? "branch" : "main",
543
1434
  onChange: (e) => patch({ branch: e.target.value === "branch" || void 0 }),
544
1435
  "data-testid": `${testId}-thread`,
@@ -551,7 +1442,7 @@ function AgentSettings({
551
1442
  /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.output, children: /* @__PURE__ */ jsxRuntime.jsxs(
552
1443
  "select",
553
1444
  {
554
- className: selectClass,
1445
+ className: selectClass2,
555
1446
  value: step.output ?? "answer",
556
1447
  onChange: (e) => patch({ output: e.target.value === "artifact" ? "artifact" : void 0 }),
557
1448
  children: [
@@ -562,6 +1453,138 @@ function AgentSettings({
562
1453
  ) })
563
1454
  ] });
564
1455
  }
1456
+
1457
+ // src/workflow-canvas/trigger.ts
1458
+ var WORKFLOW_SIGNAL_EVENT = "workflow_signal";
1459
+ var DEFAULT_WORKFLOW_TRIGGER = {
1460
+ start: "manual",
1461
+ runAt: "",
1462
+ rrule: "",
1463
+ timezone: typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
1464
+ eventKind: "",
1465
+ signal: "",
1466
+ afterTaskId: "",
1467
+ agentId: "",
1468
+ access: "ask_each_run"
1469
+ };
1470
+ function triggerProblem(trigger) {
1471
+ if (trigger.start === "once" && !trigger.runAt) return "runAt";
1472
+ if (trigger.start === "repeat" && !trigger.rrule.trim()) return "rrule";
1473
+ if (trigger.start === "event" && !trigger.eventKind.trim()) return "event";
1474
+ if (isSignalTrigger(trigger) && !trigger.signal.trim()) return "signal";
1475
+ if (trigger.start === "task" && !trigger.afterTaskId) return "task";
1476
+ return null;
1477
+ }
1478
+ var isSignalTrigger = (trigger) => trigger.start === "event" && trigger.eventKind.trim() === WORKFLOW_SIGNAL_EVENT;
1479
+ function eventFilter(trigger) {
1480
+ if (trigger.start !== "event") return null;
1481
+ if (isSignalTrigger(trigger)) return { signal: trigger.signal.trim() };
1482
+ return trigger.eventFilter && Object.keys(trigger.eventFilter).length ? trigger.eventFilter : null;
1483
+ }
1484
+ function triggerFields(trigger, clearOthers) {
1485
+ const none = clearOthers ? null : void 0;
1486
+ const filter = eventFilter(trigger);
1487
+ return {
1488
+ timezone: trigger.timezone,
1489
+ rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
1490
+ run_at: trigger.start === "once" ? chunkJFUN4D7D_cjs.localInputToIso(trigger.runAt) : none,
1491
+ event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
1492
+ // A step signal is `workflow_signal` narrowed to one signal name.
1493
+ event_filter: filter ?? none,
1494
+ after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
1495
+ on_demand: trigger.start === "manual"
1496
+ };
1497
+ }
1498
+ var authMode = (trigger) => trigger.start === "manual" ? "run_now_temp" : trigger.access === "standing" ? "scheduled_permanent" : "scheduled_require_auth";
1499
+ var withoutUndefined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1500
+ function plan(value, options) {
1501
+ return {
1502
+ goal: value.workflow.description,
1503
+ criteria: [],
1504
+ max_passes: 3,
1505
+ documents: [],
1506
+ steps: chunk3XR3IEGU_cjs.toPlanSteps(value.workflow, options)
1507
+ };
1508
+ }
1509
+ function builderToWorkflowRequest(value, workspaceId, options = {}) {
1510
+ return withoutUndefined({
1511
+ workspace_ext_id: workspaceId,
1512
+ name: value.workflow.title,
1513
+ description: value.workflow.description,
1514
+ active: true,
1515
+ shared: true,
1516
+ ...triggerFields(value.trigger, false),
1517
+ prompt: "",
1518
+ skill_ref: null,
1519
+ skill_inputs: null,
1520
+ agent_ext_id: value.trigger.agentId || null,
1521
+ auth_mode: authMode(value.trigger),
1522
+ plan: plan(value, options)
1523
+ });
1524
+ }
1525
+ function builderToWorkflowUpdate(value, options = {}) {
1526
+ return withoutUndefined({
1527
+ name: value.workflow.title,
1528
+ description: value.workflow.description,
1529
+ ...triggerFields(value.trigger, true),
1530
+ // The steps are what runs (a classic automation's single prompt or skill becomes its one step).
1531
+ prompt: "",
1532
+ skill_ref: null,
1533
+ skill_inputs: null,
1534
+ agent_ext_id: value.trigger.agentId || null,
1535
+ auth_mode: authMode(value.trigger),
1536
+ plan: plan(value, options)
1537
+ });
1538
+ }
1539
+ function workflowRecordToBuilder(record) {
1540
+ const planned = record.plan?.steps ?? [];
1541
+ const steps = planned.length ? chunk3XR3IEGU_cjs.fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1542
+ {
1543
+ id: "work",
1544
+ kind: "agent",
1545
+ title: record.name,
1546
+ ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
1547
+ }
1548
+ ] : [];
1549
+ const when = chunkJFUN4D7D_cjs.workflowWhen(record);
1550
+ return {
1551
+ workflow: {
1552
+ id: record.external_id,
1553
+ title: record.name,
1554
+ description: record.description ?? "",
1555
+ inputs: [],
1556
+ landing: "chat",
1557
+ schedulable: false,
1558
+ run: { kind: "steps", steps, layout: chunk3XR3IEGU_cjs.layoutFromPlanSteps(planned ?? []) }
1559
+ },
1560
+ trigger: {
1561
+ ...DEFAULT_WORKFLOW_TRIGGER,
1562
+ start: when === "now" ? "manual" : when,
1563
+ runAt: chunkJFUN4D7D_cjs.isoToLocalInput(record.run_at),
1564
+ rrule: record.rrule ?? "",
1565
+ timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
1566
+ eventKind: record.event_kind ?? "",
1567
+ signal: record.event_kind === WORKFLOW_SIGNAL_EVENT && typeof record.event_filter?.signal === "string" ? record.event_filter.signal : "",
1568
+ eventFilter: record.event_kind && record.event_kind !== WORKFLOW_SIGNAL_EVENT && record.event_filter ? record.event_filter : void 0,
1569
+ afterTaskId: record.after_conversation_ext_id ?? "",
1570
+ agentId: record.agent_ext_id ?? "",
1571
+ access: record.auth_mode === "scheduled_permanent" ? "standing" : "ask_each_run"
1572
+ }
1573
+ };
1574
+ }
1575
+ function declaredSignals(records, current) {
1576
+ const out = /* @__PURE__ */ new Map();
1577
+ const add = (workflow, steps) => {
1578
+ for (const step of steps)
1579
+ for (const signal of step.signals ?? [])
1580
+ if (signal.name && !out.has(signal.name))
1581
+ out.set(signal.name, { value: signal.name, label: `${workflow} \u203A ${step.title}` });
1582
+ };
1583
+ for (const record of records)
1584
+ add(record.name, record.plan?.steps ?? []);
1585
+ if (current?.run.kind === "steps") add(current.title, current.run.steps);
1586
+ return [...out.values()];
1587
+ }
565
1588
  var DEFAULT_TRIGGER_INSPECTOR_LABELS = {
566
1589
  heading: "Start",
567
1590
  start: "Starts",
@@ -575,6 +1598,11 @@ var DEFAULT_TRIGGER_INSPECTOR_LABELS = {
575
1598
  runAt: "When",
576
1599
  event: "Event",
577
1600
  eventPlaceholder: "Pick an event",
1601
+ stepSignals: "When a step signals",
1602
+ signal: "Signal",
1603
+ signalPlaceholder: "e.g. risk-high",
1604
+ signalHint: "Starts as its own thread, linked to the thread whose step raised it, with that run\u2019s inputs.",
1605
+ signalSummary: "When a step signals \u201C{signal}\u201D",
578
1606
  afterTask: "After this task",
579
1607
  afterTaskPlaceholder: "Pick a task",
580
1608
  agent: "Runs as",
@@ -588,8 +1616,10 @@ function triggerSummary(trigger, options = {}) {
588
1616
  case "once":
589
1617
  return trigger.runAt ? new Date(trigger.runAt).toLocaleString() : l.starts.once;
590
1618
  case "repeat":
591
- return trigger.rrule ? chunkF4LUD3YC_cjs.describeRRule(trigger.rrule) : l.starts.repeat;
1619
+ return trigger.rrule ? chunkJFUN4D7D_cjs.describeRRule(trigger.rrule) : l.starts.repeat;
592
1620
  case "event":
1621
+ if (isSignalTrigger(trigger))
1622
+ return trigger.signal ? l.signalSummary.replace("{signal}", trigger.signal) : l.stepSignals;
593
1623
  return trigger.eventKind && options.eventLabel?.(trigger.eventKind) || trigger.eventKind || l.starts.event;
594
1624
  case "task":
595
1625
  return trigger.afterTaskId && options.taskLabel?.(trigger.afterTaskId) || l.starts.task;
@@ -597,7 +1627,7 @@ function triggerSummary(trigger, options = {}) {
597
1627
  return l.starts.manual;
598
1628
  }
599
1629
  }
600
- 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";
1630
+ var selectClass3 = "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";
601
1631
  var STARTS = ["manual", "once", "repeat", "event", "task"];
602
1632
  function TriggerInspector({
603
1633
  trigger,
@@ -605,11 +1635,13 @@ function TriggerInspector({
605
1635
  agents = [],
606
1636
  eventKinds = [],
607
1637
  tasks = [],
1638
+ signals = [],
608
1639
  labels,
609
1640
  testId = "trigger-inspector"
610
1641
  }) {
611
1642
  const l = { ...DEFAULT_TRIGGER_INSPECTOR_LABELS, ...labels };
612
1643
  const set = (patch) => onChange({ ...trigger, ...patch });
1644
+ const events = eventKinds.some((k) => k.value === WORKFLOW_SIGNAL_EVENT) ? eventKinds : [...eventKinds, { value: WORKFLOW_SIGNAL_EVENT, label: l.stepSignals }];
613
1645
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": testId, children: [
614
1646
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: l.heading }),
615
1647
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
@@ -643,29 +1675,45 @@ function TriggerInspector({
643
1675
  }
644
1676
  )
645
1677
  ] }),
646
- trigger.start === "repeat" && /* @__PURE__ */ jsxRuntime.jsx(chunkF4LUD3YC_cjs.RecurrenceBuilder, { rrule: trigger.rrule, onChange: (rrule) => set({ rrule }) }),
1678
+ trigger.start === "repeat" && /* @__PURE__ */ jsxRuntime.jsx(chunkJFUN4D7D_cjs.RecurrenceBuilder, { rrule: trigger.rrule, onChange: (rrule) => set({ rrule }) }),
647
1679
  trigger.start === "event" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
648
1680
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.event }),
649
1681
  /* @__PURE__ */ jsxRuntime.jsxs(
650
1682
  "select",
651
1683
  {
652
- className: selectClass2,
1684
+ className: selectClass3,
653
1685
  value: trigger.eventKind,
654
- onChange: (e) => set({ eventKind: e.target.value }),
1686
+ onChange: (e) => set({ eventKind: e.target.value, eventFilter: void 0 }),
655
1687
  "data-testid": `${testId}-event`,
656
1688
  children: [
657
1689
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.eventPlaceholder }),
658
- eventKinds.map((k) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k.value, children: k.label }, k.value))
1690
+ events.map((k) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k.value, children: k.label }, k.value))
659
1691
  ]
660
1692
  }
661
1693
  )
662
1694
  ] }),
1695
+ isSignalTrigger(trigger) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1696
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", htmlFor: `${testId}-signal`, children: l.signal }),
1697
+ /* @__PURE__ */ jsxRuntime.jsx(
1698
+ ui.Input,
1699
+ {
1700
+ id: `${testId}-signal`,
1701
+ list: `${testId}-signal-options`,
1702
+ value: trigger.signal,
1703
+ placeholder: l.signalPlaceholder,
1704
+ onChange: (e) => set({ signal: e.target.value.trim().toLowerCase() }),
1705
+ "data-testid": `${testId}-signal`
1706
+ }
1707
+ ),
1708
+ /* @__PURE__ */ jsxRuntime.jsx("datalist", { id: `${testId}-signal-options`, children: signals.map((s) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: s.value, children: s.label }, s.value)) }),
1709
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: l.signalHint })
1710
+ ] }),
663
1711
  trigger.start === "task" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
664
1712
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.afterTask }),
665
1713
  /* @__PURE__ */ jsxRuntime.jsxs(
666
1714
  "select",
667
1715
  {
668
- className: selectClass2,
1716
+ className: selectClass3,
669
1717
  value: trigger.afterTaskId,
670
1718
  onChange: (e) => set({ afterTaskId: e.target.value }),
671
1719
  "data-testid": `${testId}-after-task`,
@@ -679,7 +1727,7 @@ function TriggerInspector({
679
1727
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
680
1728
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.agent }),
681
1729
  /* @__PURE__ */ jsxRuntime.jsx(
682
- chunkF4LUD3YC_cjs.AgentSelect,
1730
+ chunkJFUN4D7D_cjs.AgentSelect,
683
1731
  {
684
1732
  agents,
685
1733
  value: trigger.agentId,
@@ -694,7 +1742,7 @@ function TriggerInspector({
694
1742
  /* @__PURE__ */ jsxRuntime.jsxs(
695
1743
  "select",
696
1744
  {
697
- className: selectClass2,
1745
+ className: selectClass3,
698
1746
  value: trigger.access,
699
1747
  onChange: (e) => set({ access: e.target.value === "standing" ? "standing" : "ask_each_run" }),
700
1748
  "data-testid": `${testId}-access`,
@@ -751,12 +1799,19 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
751
1799
  upload: "Upload",
752
1800
  agent: "AI step",
753
1801
  review: "Approval",
1802
+ sign: "Sign",
1803
+ email_draft: "Email draft",
1804
+ tabular_review: "Tabular review",
1805
+ redline: "Tracked changes",
754
1806
  branch: "Branch",
755
1807
  kindHints: {
756
1808
  form: "Ask for details",
757
1809
  upload: "Collect files",
758
1810
  agent: "Run a skill or an instruction",
759
- review: "A person approves"
1811
+ review: "A person approves",
1812
+ sign: "People e-sign a document",
1813
+ email_draft: "Prepare an email to send",
1814
+ tabular_review: "Review documents in a grid"
760
1815
  },
761
1816
  addNext: "Add the next step",
762
1817
  runs: "Runs \u201C{name}\u201D",
@@ -764,6 +1819,14 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
764
1819
  fields: "{count} fields",
765
1820
  noFields: "No fields yet",
766
1821
  approvedBy: "A person approves",
1822
+ signers: "{count} signers",
1823
+ chooseDocument: "Choose the document to sign",
1824
+ emailTo: "To {to}",
1825
+ noRecipients: "Add a recipient",
1826
+ reviewColumns: "{count} columns",
1827
+ noColumns: "Choose the columns",
1828
+ assignee: "{name}",
1829
+ remind: "Reminds after {hours}h",
767
1830
  emptyTitle: "Start your workflow",
768
1831
  emptyHint: "Add the first step: what should happen when it starts?",
769
1832
  fitView: "Fit view"
@@ -773,9 +1836,12 @@ var STEP_KIND_ICONS = {
773
1836
  form: lucideReact.FileInput,
774
1837
  upload: lucideReact.Upload,
775
1838
  agent: lucideReact.Bot,
776
- review: lucideReact.ClipboardCheck
1839
+ review: lucideReact.ClipboardCheck,
1840
+ sign: lucideReact.PenLine,
1841
+ email_draft: lucideReact.Mail,
1842
+ tabular_review: lucideReact.Table2
777
1843
  };
778
- var KINDS = ["form", "upload", "agent", "review"];
1844
+ var KINDS = WORKFLOW_STEP_KINDS;
779
1845
  function AddNext({
780
1846
  from,
781
1847
  onAdd,
@@ -828,20 +1894,23 @@ function AddNext({
828
1894
  }
829
1895
  function PhaseMark({ phase }) {
830
1896
  if (phase === "running") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "wf-kind-text size-4 animate-spin" });
1897
+ if (phase === "waiting") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hourglass, { className: "wf-kind-text size-4" });
831
1898
  if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "wf-kind-text size-4" });
832
1899
  if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-4 text-destructive" });
833
1900
  if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-4 text-muted-foreground" });
834
1901
  return null;
835
1902
  }
836
1903
  function StepNode({ data }) {
837
- const { step, phase, summary, icon, l, onAdd, testId } = data;
838
- const KindIcon = STEP_KIND_ICONS[step.kind];
1904
+ const { step, phase, summary, assignee, icon, l, onAdd, testId } = data;
1905
+ const kind = stepKindOf(step);
1906
+ const KindIcon = STEP_KIND_ICONS[kind];
1907
+ const redline = step.kind === "agent" && !!step.editDocument;
839
1908
  return /* @__PURE__ */ jsxRuntime.jsxs(
840
1909
  "div",
841
1910
  {
842
1911
  className: ui.cn(
843
1912
  "wf-node w-64 py-3 pl-4 pr-3 text-left",
844
- `wf-kind-${step.kind}`,
1913
+ `wf-kind-${kind}`,
845
1914
  phase && `wf-phase-${phase}`
846
1915
  ),
847
1916
  "data-testid": `${testId}-node-${step.id}`,
@@ -852,15 +1921,44 @@ function StepNode({ data }) {
852
1921
  /* @__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, {}) }),
853
1922
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
854
1923
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
855
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: l[step.kind] }),
1924
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: l[kind] }),
856
1925
  /* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase })
857
1926
  ] }),
858
1927
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold leading-snug", children: step.title }),
859
1928
  summary && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-snug text-muted-foreground", children: summary }),
860
- 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: [
861
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { className: "size-3" }),
862
- " ",
863
- l.branch
1929
+ (redline || step.kind === "agent" && step.branch || assignee) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex flex-wrap gap-1", children: [
1930
+ step.kind === "agent" && step.branch && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: [
1931
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { className: "size-3" }),
1932
+ " ",
1933
+ l.branch
1934
+ ] }),
1935
+ redline && /* @__PURE__ */ jsxRuntime.jsxs(
1936
+ "span",
1937
+ {
1938
+ className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
1939
+ "data-testid": `${testId}-node-${step.id}-redline`,
1940
+ children: [
1941
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FilePenLine, { className: "size-3" }),
1942
+ " ",
1943
+ l.redline
1944
+ ]
1945
+ }
1946
+ ),
1947
+ assignee && /* @__PURE__ */ jsxRuntime.jsxs(
1948
+ "span",
1949
+ {
1950
+ className: "inline-flex max-w-full items-center gap-1 truncate rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
1951
+ title: assignee,
1952
+ "data-testid": `${testId}-node-${step.id}-assignee`,
1953
+ children: [
1954
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserRound, { className: "size-3 shrink-0" }),
1955
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: l.assignee.replace(
1956
+ "{name}",
1957
+ assignee.charAt(0).toUpperCase() + assignee.slice(1)
1958
+ ) })
1959
+ ]
1960
+ }
1961
+ )
864
1962
  ] })
865
1963
  ] })
866
1964
  ] }),
@@ -909,6 +2007,16 @@ function summaryOf(step, l, workflowTitle) {
909
2007
  return step.hint;
910
2008
  case "review":
911
2009
  return step.instructions ? firstWords(step.instructions) : l.approvedBy;
2010
+ case "action": {
2011
+ const a = step.action;
2012
+ if (a.type === "sign")
2013
+ return !a.document ? l.chooseDocument : a.signers.length ? l.signers.replace("{count}", String(a.signers.length)) : void 0;
2014
+ if (a.type === "email_draft") {
2015
+ const to = a.to.find((t) => t.trim());
2016
+ return to ? l.emailTo.replace("{to}", to) : l.noRecipients;
2017
+ }
2018
+ return a.tags.length ? l.reviewColumns.replace("{count}", String(a.tags.length)) : l.noColumns;
2019
+ }
912
2020
  }
913
2021
  }
914
2022
  function WorkflowCanvas({
@@ -920,6 +2028,7 @@ function WorkflowCanvas({
920
2028
  onAddAfter,
921
2029
  phases,
922
2030
  workflowTitle,
2031
+ assigneeOf,
923
2032
  trigger,
924
2033
  renderIcon,
925
2034
  labels,
@@ -928,12 +2037,12 @@ function WorkflowCanvas({
928
2037
  testId = "workflow-canvas"
929
2038
  }) {
930
2039
  const l = react.useMemo(() => ({ ...DEFAULT_WORKFLOW_CANVAS_LABELS, ...labels }), [labels]);
931
- const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
2040
+ const steps = chunk3XR3IEGU_cjs.workflowSteps(workflow);
932
2041
  const editable = !!onChange;
933
2042
  const built = react.useMemo(() => {
934
2043
  const layout = layoutWithDefaults(workflow);
935
- const all = chunkP2RBE3FD_cjs.workflowSteps(workflow);
936
- const roots = all.filter((s) => chunkP2RBE3FD_cjs.stepDependencies(all, s.id).length === 0);
2044
+ const all = chunk3XR3IEGU_cjs.workflowSteps(workflow);
2045
+ const roots = all.filter((s) => chunk3XR3IEGU_cjs.stepDependencies(all, s.id).length === 0);
937
2046
  const triggerNode = trigger ? [
938
2047
  {
939
2048
  id: TRIGGER_NODE,
@@ -958,6 +2067,7 @@ function WorkflowCanvas({
958
2067
  step,
959
2068
  phase: phases?.[step.id],
960
2069
  summary: summaryOf(step, l, workflowTitle),
2070
+ assignee: assigneeOf?.(step),
961
2071
  icon: step.icon && renderIcon ? renderIcon(step.icon) : void 0,
962
2072
  l,
963
2073
  onAdd: onAddAfter,
@@ -965,12 +2075,23 @@ function WorkflowCanvas({
965
2075
  }
966
2076
  }))
967
2077
  ];
968
- }, [workflow, selected, phases, workflowTitle, trigger, renderIcon, l, onAddAfter, testId]);
2078
+ }, [
2079
+ workflow,
2080
+ selected,
2081
+ phases,
2082
+ workflowTitle,
2083
+ assigneeOf,
2084
+ trigger,
2085
+ renderIcon,
2086
+ l,
2087
+ onAddAfter,
2088
+ testId
2089
+ ]);
969
2090
  const [nodes, setNodes] = react.useState(built);
970
2091
  react.useEffect(() => setNodes(built), [built]);
971
2092
  const edges = react.useMemo(
972
2093
  () => steps.flatMap((s) => {
973
- const deps = chunkP2RBE3FD_cjs.stepDependencies(steps, s.id);
2094
+ const deps = chunk3XR3IEGU_cjs.stepDependencies(steps, s.id);
974
2095
  const from = deps.length ? deps : trigger ? [TRIGGER_NODE] : [];
975
2096
  return from.map((d) => ({
976
2097
  id: `${d}->${s.id}`,
@@ -1179,10 +2300,17 @@ var DEFAULT_WORKFLOW_BUILDER_LABELS = {
1179
2300
  unknown: "\u201C{step}\u201D waits for a step that does not exist.",
1180
2301
  cycle: "\u201C{step}\u201D waits for itself (a loop).",
1181
2302
  order: "\u201C{step}\u201D is listed before a step it waits for."
2303
+ },
2304
+ missing: {
2305
+ document: "\u201C{step}\u201D needs a document.",
2306
+ signers: "\u201C{step}\u201D needs at least one signer.",
2307
+ recipients: "\u201C{step}\u201D needs a recipient.",
2308
+ tags: "\u201C{step}\u201D needs at least one column.",
2309
+ documents: "\u201C{step}\u201D needs documents to review."
1182
2310
  }
1183
2311
  };
1184
2312
  var PANEL_WIDTH = 344;
1185
- var KINDS2 = ["form", "upload", "agent", "review"];
2313
+ var KINDS2 = WORKFLOW_STEP_KINDS;
1186
2314
  function WorkflowBuilder({
1187
2315
  value,
1188
2316
  onChange,
@@ -1190,6 +2318,10 @@ function WorkflowBuilder({
1190
2318
  agents = [],
1191
2319
  eventKinds = [],
1192
2320
  tasks = [],
2321
+ signals = [],
2322
+ people = [],
2323
+ tags = [],
2324
+ documents = [],
1193
2325
  compose,
1194
2326
  renderIcon,
1195
2327
  actions,
@@ -1210,8 +2342,12 @@ function WorkflowBuilder({
1210
2342
  const [mode, setMode] = react.useState("design");
1211
2343
  const [adding, setAdding] = react.useState(false);
1212
2344
  const { workflow, trigger } = value;
1213
- const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
1214
- const problems = chunkP2RBE3FD_cjs.validateWorkflowGraph(steps);
2345
+ const steps = chunk3XR3IEGU_cjs.workflowSteps(workflow);
2346
+ const problems = chunk3XR3IEGU_cjs.validateWorkflowGraph(steps);
2347
+ const missing = chunk3XR3IEGU_cjs.stepConfigProblems(steps);
2348
+ const nameOf = (id) => people.find((p) => p.value === id)?.label;
2349
+ const fields = chunk3XR3IEGU_cjs.runFields(workflow);
2350
+ const assigneeOf = (step) => chunk3XR3IEGU_cjs.canAssign(step) ? chunk3XR3IEGU_cjs.assigneeName(step.assignee, { nameOf, fields }) : void 0;
1215
2351
  const titles = react.useMemo(() => new Map(workflows.map((w) => [w.id, w.title])), [workflows]);
1216
2352
  const setWorkflow = (next) => onChange({ ...value, workflow: next });
1217
2353
  const addAfter = (from, kind) => {
@@ -1324,10 +2460,16 @@ function WorkflowBuilder({
1324
2460
  ] }),
1325
2461
  actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
1326
2462
  ] }),
1327
- 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(
1328
- "{step}",
1329
- steps.find((s) => s.id === p.step)?.title ?? p.step
1330
- ) }, i)) }),
2463
+ problems.length + missing.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-1 text-sm text-destructive", "data-testid": `${testId}-problems`, children: [
2464
+ problems.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.problems[p.code].replace(
2465
+ "{step}",
2466
+ steps.find((s) => s.id === p.step)?.title ?? p.step
2467
+ ) }, i)),
2468
+ missing.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { "data-testid": `${testId}-missing-${p.step}-${p.missing}`, children: l.missing[p.missing].replace(
2469
+ "{step}",
2470
+ steps.find((s) => s.id === p.step)?.title ?? p.step
2471
+ ) }, `m${i}`))
2472
+ ] }),
1331
2473
  mode === "design" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1332
2474
  /* @__PURE__ */ jsxRuntime.jsx(
1333
2475
  WorkflowCanvas,
@@ -1340,6 +2482,7 @@ function WorkflowBuilder({
1340
2482
  onAddAfter: addAfter,
1341
2483
  trigger: { title: l.start, summary },
1342
2484
  workflowTitle: (id) => titles.get(id),
2485
+ assigneeOf,
1343
2486
  renderIcon,
1344
2487
  labels: canvasLabels,
1345
2488
  reserveRight: panelOpen ? PANEL_WIDTH : 0,
@@ -1372,6 +2515,12 @@ function WorkflowBuilder({
1372
2515
  agents,
1373
2516
  eventKinds,
1374
2517
  tasks,
2518
+ signals: [
2519
+ ...signals,
2520
+ ...declaredSignals([], workflow).filter(
2521
+ (d) => !signals.some((s) => s.value === d.value)
2522
+ )
2523
+ ],
1375
2524
  labels: triggerLabels,
1376
2525
  testId: `${testId}-trigger`
1377
2526
  }
@@ -1383,6 +2532,9 @@ function WorkflowBuilder({
1383
2532
  onChange: setWorkflow,
1384
2533
  onSelect: setSelected,
1385
2534
  workflows,
2535
+ people,
2536
+ tags,
2537
+ documents,
1386
2538
  labels: inspectorLabels,
1387
2539
  testId: `${testId}-inspector`
1388
2540
  }
@@ -1426,13 +2578,13 @@ function WorkflowPreview({
1426
2578
  renderIcon,
1427
2579
  testId
1428
2580
  }) {
1429
- const run = chunkF4LUD3YC_cjs.useWorkflowPreview(workflow, {
2581
+ const run = chunkJFUN4D7D_cjs.useWorkflowPreview(workflow, {
1430
2582
  resolveWorkflow: (id) => workflows.find((w) => w.id === id),
1431
2583
  compose,
1432
2584
  answer
1433
2585
  });
1434
2586
  return /* @__PURE__ */ jsxRuntime.jsx(
1435
- chunkP2RBE3FD_cjs.WorkflowRunner,
2587
+ chunk3XR3IEGU_cjs.WorkflowRunner,
1436
2588
  {
1437
2589
  workflow,
1438
2590
  run,
@@ -1449,111 +2601,6 @@ function WorkflowPreview({
1449
2601
  }
1450
2602
  );
1451
2603
  }
1452
-
1453
- // src/workflow-canvas/trigger.ts
1454
- var DEFAULT_WORKFLOW_TRIGGER = {
1455
- start: "manual",
1456
- runAt: "",
1457
- rrule: "",
1458
- timezone: typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
1459
- eventKind: "",
1460
- afterTaskId: "",
1461
- agentId: "",
1462
- access: "ask_each_run"
1463
- };
1464
- function triggerProblem(trigger) {
1465
- if (trigger.start === "once" && !trigger.runAt) return "runAt";
1466
- if (trigger.start === "repeat" && !trigger.rrule.trim()) return "rrule";
1467
- if (trigger.start === "event" && !trigger.eventKind.trim()) return "event";
1468
- if (trigger.start === "task" && !trigger.afterTaskId) return "task";
1469
- return null;
1470
- }
1471
- function triggerFields(trigger, clearOthers) {
1472
- const none = clearOthers ? null : void 0;
1473
- return {
1474
- timezone: trigger.timezone,
1475
- rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
1476
- run_at: trigger.start === "once" ? chunkF4LUD3YC_cjs.localInputToIso(trigger.runAt) : none,
1477
- event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
1478
- after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
1479
- on_demand: trigger.start === "manual"
1480
- };
1481
- }
1482
- var authMode = (trigger) => trigger.start === "manual" ? "run_now_temp" : trigger.access === "standing" ? "scheduled_permanent" : "scheduled_require_auth";
1483
- var withoutUndefined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1484
- function plan(value, options) {
1485
- return {
1486
- goal: value.workflow.description,
1487
- criteria: [],
1488
- max_passes: 3,
1489
- documents: [],
1490
- steps: chunkP2RBE3FD_cjs.toPlanSteps(value.workflow, options)
1491
- };
1492
- }
1493
- function builderToWorkflowRequest(value, workspaceId, options = {}) {
1494
- return withoutUndefined({
1495
- workspace_ext_id: workspaceId,
1496
- name: value.workflow.title,
1497
- description: value.workflow.description,
1498
- active: true,
1499
- shared: true,
1500
- ...triggerFields(value.trigger, false),
1501
- prompt: "",
1502
- skill_ref: null,
1503
- skill_inputs: null,
1504
- agent_ext_id: value.trigger.agentId || null,
1505
- auth_mode: authMode(value.trigger),
1506
- plan: plan(value, options)
1507
- });
1508
- }
1509
- function builderToWorkflowUpdate(value, options = {}) {
1510
- return withoutUndefined({
1511
- name: value.workflow.title,
1512
- description: value.workflow.description,
1513
- ...triggerFields(value.trigger, true),
1514
- // The steps are what runs (a classic automation's single prompt or skill becomes its one step).
1515
- prompt: "",
1516
- skill_ref: null,
1517
- skill_inputs: null,
1518
- agent_ext_id: value.trigger.agentId || null,
1519
- auth_mode: authMode(value.trigger),
1520
- plan: plan(value, options)
1521
- });
1522
- }
1523
- function workflowRecordToBuilder(record) {
1524
- const planned = record.plan?.steps ?? [];
1525
- const steps = planned.length ? chunkP2RBE3FD_cjs.fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1526
- {
1527
- id: "work",
1528
- kind: "agent",
1529
- title: record.name,
1530
- ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
1531
- }
1532
- ] : [];
1533
- const when = chunkF4LUD3YC_cjs.workflowWhen(record);
1534
- return {
1535
- workflow: {
1536
- id: record.external_id,
1537
- title: record.name,
1538
- description: record.description ?? "",
1539
- inputs: [],
1540
- landing: "chat",
1541
- schedulable: false,
1542
- run: { kind: "steps", steps, layout: chunkP2RBE3FD_cjs.layoutFromPlanSteps(planned ?? []) }
1543
- },
1544
- trigger: {
1545
- ...DEFAULT_WORKFLOW_TRIGGER,
1546
- start: when === "now" ? "manual" : when,
1547
- runAt: chunkF4LUD3YC_cjs.isoToLocalInput(record.run_at),
1548
- rrule: record.rrule ?? "",
1549
- timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
1550
- eventKind: record.event_kind ?? "",
1551
- afterTaskId: record.after_conversation_ext_id ?? "",
1552
- agentId: record.agent_ext_id ?? "",
1553
- access: record.auth_mode === "scheduled_permanent" ? "standing" : "ask_each_run"
1554
- }
1555
- };
1556
- }
1557
2604
  var DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS = {
1558
2605
  save: "Save",
1559
2606
  saving: "Saving\u2026",
@@ -1566,7 +2613,8 @@ var DEFAULT_WORKFLOW_EVENT_KINDS = [
1566
2613
  { value: "conversation_ready", label: "Work is ready for me" },
1567
2614
  { value: "mention", label: "Someone mentions me" },
1568
2615
  { value: "workflow_completed", label: "Another workflow finishes" },
1569
- { value: "workflow_failed", label: "Another workflow fails" }
2616
+ { value: "workflow_failed", label: "Another workflow fails" },
2617
+ { value: "workflow_signal", label: "When a step signals" }
1570
2618
  ];
1571
2619
  function ConnectedWorkflowBuilder({
1572
2620
  workflowId,
@@ -1582,7 +2630,22 @@ function ConnectedWorkflowBuilder({
1582
2630
  ...builderProps
1583
2631
  }) {
1584
2632
  const l = { ...DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS, ...connectedLabels };
1585
- const { workspaceId } = chunkMUMH3Z6K_cjs.useConnection();
2633
+ const { workspaceId, status, ensureWorkspaceOpen } = chunkMUMH3Z6K_cjs.useConnection();
2634
+ const members = react$2.useWorkspaceUsers(workspaceId ?? void 0, {
2635
+ enabled: status === "authenticated" && !!workspaceId,
2636
+ beforeFetch: ensureWorkspaceOpen
2637
+ });
2638
+ const tagsQuery = react$2.useTags(workspaceId ?? void 0);
2639
+ const docsQuery = react$2.useDocuments(workspaceId ?? void 0);
2640
+ const people = (members.data ?? []).map((m) => ({
2641
+ value: m.user.external_id,
2642
+ label: [m.user.given_name, m.user.family_name].filter(Boolean).join(" ") || m.user.email
2643
+ }));
2644
+ const tagOptions = (tagsQuery.data ?? []).map((t) => ({ value: t.external_id, label: t.name }));
2645
+ const documentOptions = (docsQuery.data ?? []).map((d) => ({
2646
+ value: d.external_id,
2647
+ label: d.file_name ?? d.external_id
2648
+ }));
1586
2649
  const saved = react$2.useWorkflows();
1587
2650
  const skills = react$2.useSkills();
1588
2651
  const agentsQuery = react$2.useAgents();
@@ -1605,7 +2668,7 @@ function ConnectedWorkflowBuilder({
1605
2668
  () => [
1606
2669
  ...hostWorkflows,
1607
2670
  ...(skills.data ?? []).map(
1608
- (s) => chunkP2RBE3FD_cjs.skillToWorkflow({
2671
+ (s) => chunk3XR3IEGU_cjs.skillToWorkflow({
1609
2672
  name: s.name,
1610
2673
  slug: s.slug,
1611
2674
  description: s.description,
@@ -1621,7 +2684,7 @@ function ConnectedWorkflowBuilder({
1621
2684
  }));
1622
2685
  const tasks = (conversations.data ?? []).filter((c) => c.status && c.status !== "done").map((c) => ({ value: c.external_id, label: c.title || c.external_id }));
1623
2686
  const options = { resolveWorkflow: (wid) => workflows.find((w) => w.id === wid), compose };
1624
- const problem = triggerProblem(value.trigger) ?? (chunkP2RBE3FD_cjs.validateWorkflowGraph(chunkP2RBE3FD_cjs.workflowSteps(value.workflow)).length ? "graph" : null);
2687
+ const problem = triggerProblem(value.trigger) ?? (chunk3XR3IEGU_cjs.validateWorkflowGraph(chunk3XR3IEGU_cjs.workflowSteps(value.workflow)).length || chunk3XR3IEGU_cjs.stepConfigProblems(chunk3XR3IEGU_cjs.workflowSteps(value.workflow)).length ? "graph" : null);
1625
2688
  const busy = create.isPending || update.isPending || run.isPending;
1626
2689
  const save = async () => {
1627
2690
  if (!workspaceId) return void 0;
@@ -1643,6 +2706,10 @@ function ConnectedWorkflowBuilder({
1643
2706
  agents,
1644
2707
  eventKinds,
1645
2708
  tasks,
2709
+ people,
2710
+ tags: tagOptions,
2711
+ documents: documentOptions,
2712
+ signals: declaredSignals(saved.data ?? []),
1646
2713
  compose,
1647
2714
  testId,
1648
2715
  actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -1689,15 +2756,18 @@ function ConnectedWorkflowBuilder({
1689
2756
 
1690
2757
  exports.ConnectedWorkflowBuilder = ConnectedWorkflowBuilder;
1691
2758
  exports.DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS = DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS;
2759
+ exports.DEFAULT_SIGNALS_EDITOR_LABELS = DEFAULT_SIGNALS_EDITOR_LABELS;
1692
2760
  exports.DEFAULT_STEP_INSPECTOR_LABELS = DEFAULT_STEP_INSPECTOR_LABELS;
1693
2761
  exports.DEFAULT_TRIGGER_INSPECTOR_LABELS = DEFAULT_TRIGGER_INSPECTOR_LABELS;
1694
2762
  exports.DEFAULT_WORKFLOW_BUILDER_LABELS = DEFAULT_WORKFLOW_BUILDER_LABELS;
1695
2763
  exports.DEFAULT_WORKFLOW_CANVAS_LABELS = DEFAULT_WORKFLOW_CANVAS_LABELS;
1696
2764
  exports.DEFAULT_WORKFLOW_EVENT_KINDS = DEFAULT_WORKFLOW_EVENT_KINDS;
1697
2765
  exports.DEFAULT_WORKFLOW_TRIGGER = DEFAULT_WORKFLOW_TRIGGER;
2766
+ exports.SignalsEditor = SignalsEditor;
1698
2767
  exports.StepInspector = StepInspector;
1699
2768
  exports.TRIGGER_NODE = TRIGGER_NODE;
1700
2769
  exports.TriggerInspector = TriggerInspector;
2770
+ exports.WORKFLOW_SIGNAL_EVENT = WORKFLOW_SIGNAL_EVENT;
1701
2771
  exports.WorkflowBuilder = WorkflowBuilder;
1702
2772
  exports.WorkflowCanvas = WorkflowCanvas;
1703
2773
  exports.addStep = addStep;
@@ -1705,11 +2775,15 @@ exports.autoLayout = autoLayout;
1705
2775
  exports.builderToWorkflowRequest = builderToWorkflowRequest;
1706
2776
  exports.builderToWorkflowUpdate = builderToWorkflowUpdate;
1707
2777
  exports.connectSteps = connectSteps;
2778
+ exports.declaredSignals = declaredSignals;
1708
2779
  exports.disconnectSteps = disconnectSteps;
2780
+ exports.isSignalTrigger = isSignalTrigger;
1709
2781
  exports.layoutWithDefaults = layoutWithDefaults;
1710
2782
  exports.moveStep = moveStep;
1711
2783
  exports.newSteppedWorkflow = newSteppedWorkflow;
1712
2784
  exports.removeStep = removeStep;
2785
+ exports.signalConditions = signalConditions;
2786
+ exports.signalSlug = signalSlug;
1713
2787
  exports.stepIdFor = stepIdFor;
1714
2788
  exports.triggerProblem = triggerProblem;
1715
2789
  exports.triggerSummary = triggerSummary;