@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
@@ -4,9 +4,9 @@ import { FoldSection } from './chunk-XD2M6LIG.js';
4
4
  import { useElementSize } from './chunk-HOXKR26S.js';
5
5
  import { testIdOr, prefixedTestId } from './chunk-7F6CBP3Z.js';
6
6
  import { useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'react';
7
- import { cn, Card, Button, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Switch, Input, Textarea } from '@arbidocs/react/ui';
7
+ import { cn, Button, Textarea, Card, Label, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Switch } from '@arbidocs/react/ui';
8
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
- import { CheckCircle2, ArrowLeft, Loader2, ArrowRight, RotateCw, GitBranch, FileText, Check, AlertTriangle, MinusCircle } from 'lucide-react';
9
+ import { UserRound, CornerUpLeft, ShieldCheck, MessageSquare, Check, Hourglass, Clock, PenLine, X, ExternalLink, Mail, Table2, CheckCircle2, ArrowLeft, Loader2, ArrowRight, RotateCw, GitBranch, FileText, AlertTriangle, MinusCircle } from 'lucide-react';
10
10
 
11
11
  // src/agents/workflows/types.ts
12
12
  var EMPTY_WORKFLOW_SCOPE = { folders: [], labels: [] };
@@ -289,7 +289,8 @@ function FieldControl({
289
289
  renderScope,
290
290
  renderDocuments,
291
291
  renderIcon,
292
- onEnterSubmit
292
+ onEnterSubmit,
293
+ people
293
294
  }) {
294
295
  const id = `${idFor()}-control`;
295
296
  const testId = idFor();
@@ -422,6 +423,34 @@ function FieldControl({
422
423
  const picked = isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
423
424
  return /* @__PURE__ */ jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
424
425
  }
426
+ case "person":
427
+ return people?.length ? /* @__PURE__ */ jsxs(
428
+ "select",
429
+ {
430
+ id,
431
+ "data-testid": testId,
432
+ value: String(value ?? ""),
433
+ "aria-required": field.required || void 0,
434
+ "aria-invalid": error ? true : void 0,
435
+ onChange: (e) => onChange(e.target.value),
436
+ className: "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm",
437
+ children: [
438
+ /* @__PURE__ */ jsx("option", { value: "", children: field.placeholder ?? "" }),
439
+ people.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
440
+ ]
441
+ }
442
+ ) : /* @__PURE__ */ jsx(
443
+ Input,
444
+ {
445
+ id,
446
+ "data-testid": testId,
447
+ value: String(value ?? ""),
448
+ placeholder: field.placeholder ?? "usr-\u2026",
449
+ "aria-required": field.required || void 0,
450
+ "aria-invalid": error ? true : void 0,
451
+ onChange: (e) => onChange(e.target.value)
452
+ }
453
+ );
425
454
  }
426
455
  }
427
456
  function FormField(props) {
@@ -472,6 +501,7 @@ function SchemaForm({
472
501
  renderDocuments,
473
502
  renderIcon,
474
503
  onEnterSubmit,
504
+ people,
475
505
  testIdPrefix,
476
506
  labels,
477
507
  className
@@ -496,7 +526,8 @@ function SchemaForm({
496
526
  renderScope,
497
527
  renderDocuments,
498
528
  renderIcon,
499
- onEnterSubmit
529
+ onEnterSubmit,
530
+ people
500
531
  },
501
532
  field.name
502
533
  );
@@ -586,33 +617,81 @@ function stepLevels(steps) {
586
617
  }
587
618
  var STEP_EVENTS = {
588
619
  step_started: "running",
620
+ step_waiting: "waiting",
589
621
  step_done: "done",
590
622
  step_skipped: "skipped",
591
623
  step_failed: "failed"
592
624
  };
625
+ var str2 = (v) => typeof v === "string" && v ? v : void 0;
626
+ var ACTION_TYPES = ["sign", "email_draft", "tabular_review"];
627
+ var asAction = (v) => ACTION_TYPES.includes(v) ? v : void 0;
628
+ var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
629
+ var asStrings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : void 0;
630
+ function reopenedBy(detail) {
631
+ const to = str2(detail.to);
632
+ return asStrings(detail.reopened) ?? (to ? [to] : []);
633
+ }
593
634
  function stepStatesFromActivity(events) {
594
635
  const states = {};
595
636
  for (const e of events) {
637
+ const detail = e.detail ?? {};
638
+ const step = str2(detail.step);
639
+ if (!step) continue;
640
+ if (e.kind === "step_sent_back") {
641
+ const to = str2(detail.to);
642
+ for (const id of reopenedBy(detail))
643
+ states[id] = id === to ? {
644
+ status: "pending",
645
+ sentBack: true,
646
+ hasNote: typeof detail.note_encrypted === "string"
647
+ } : { status: "pending" };
648
+ continue;
649
+ }
650
+ if (e.kind === "step_ready") {
651
+ states[step] = { ...states[step] ?? { status: "pending" }, announcedTo: str2(detail.to) };
652
+ continue;
653
+ }
654
+ if (e.kind === "step_progress") {
655
+ const before2 = states[step];
656
+ const waiting2 = asRecord(detail.waiting);
657
+ if (before2?.status === "waiting" && waiting2) states[step] = { ...before2, waiting: waiting2 };
658
+ continue;
659
+ }
596
660
  const status = STEP_EVENTS[e.kind];
597
- const step = e.detail?.step;
598
- if (!status || typeof step !== "string") continue;
599
- const responseId = typeof e.detail?.response_id === "string" ? e.detail.response_id : void 0;
600
- const error = typeof e.detail?.error === "string" ? e.detail.error : null;
601
- const startedAt = status === "running" ? e.created_at : states[step]?.startedAt;
661
+ if (!status) continue;
662
+ const before = states[step];
663
+ const responseId = str2(detail.response_id) ?? before?.responseId ?? null;
664
+ const startedAt = status === "running" ? e.created_at : before?.startedAt;
665
+ const action = asAction(detail.action) ?? before?.action;
666
+ const documents = asStrings(detail.documents) ?? before?.documents;
667
+ const waiting = status === "waiting" ? asRecord(detail.waiting) : void 0;
668
+ const output = status === "done" ? asRecord(detail.output) : void 0;
669
+ const approved = Array.isArray(detail.approved) ? detail.approved.filter(asRecord) : void 0;
670
+ const finished2 = status === "done" || status === "skipped" || status === "failed";
671
+ const declinedBy = str2(detail.declined_by);
602
672
  states[step] = {
603
673
  status,
604
- responseId: responseId ?? states[step]?.responseId ?? null,
605
- error,
606
- ...startedAt ? { startedAt } : {}
674
+ responseId,
675
+ error: str2(detail.error) ?? null,
676
+ ...startedAt ? { startedAt } : {},
677
+ ...action ? { action } : {},
678
+ ...documents?.length ? { documents } : {},
679
+ ...waiting ? { waiting } : {},
680
+ ...output ? { output } : {},
681
+ ...approved ? { approved } : {},
682
+ ...finished2 ? { by: e.actor_ext_id ?? null } : {},
683
+ ...finished2 && e.created_at ? { at: e.created_at } : {},
684
+ ...declinedBy ? { declinedBy } : {}
607
685
  };
608
686
  }
609
687
  return states;
610
688
  }
689
+ function stepFields(step) {
690
+ return step.kind === "form" ? step.inputs : step.kind === "review" ? step.fields ?? [] : [];
691
+ }
692
+ var runFieldsOf = (steps) => steps.flatMap(stepFields);
611
693
  function runFields(workflow) {
612
- return [
613
- ...workflow.inputs,
614
- ...workflowSteps(workflow).flatMap((s) => s.kind === "form" ? s.inputs : [])
615
- ];
694
+ return [...workflow.inputs, ...workflowSteps(workflow).flatMap(stepFields)];
616
695
  }
617
696
  function initialRunInputs(workflow, inputs = {}) {
618
697
  return { ...defaultInputs({ ...workflow, inputs: runFields(workflow) }), ...inputs };
@@ -624,7 +703,9 @@ function stepPhase(steps, states, id) {
624
703
  return stepDependencies(steps, id).every((d) => finished(states[d])) ? "ready" : "blocked";
625
704
  }
626
705
  var isRunFinished = (steps, states) => steps.length > 0 && steps.every((s) => finished(states[s.id]));
627
- var isPersonStep = (step) => step.kind !== "agent";
706
+ var isPersonStep = (step) => step.kind !== "agent" && step.kind !== "action";
707
+ var isPersonAction = (step) => step.kind === "action" && (step.action.type === "sign" || step.action.type === "email_draft");
708
+ var canAssign = (step) => isPersonStep(step) || isPersonAction(step);
628
709
  function nextAction(steps, states, current) {
629
710
  const i = steps.findIndex((s) => s.id === current);
630
711
  const step = steps[i];
@@ -638,20 +719,76 @@ function nextAction(steps, states, current) {
638
719
  return isRunFinished(steps, states) ? "finish" : "wait";
639
720
  }
640
721
  if (isPersonStep(step)) return "complete";
722
+ if (phase === "waiting" && step.kind === "action" && step.action.type === "email_draft")
723
+ return "complete";
641
724
  if (phase !== "failed") return independentNext ? "move" : "wait";
642
725
  const waitedFor = steps.slice(i + 1).some((s) => dependsOn(steps, s.id, step.id));
643
726
  return waitedFor || !following ? "skip" : "move";
644
727
  }
645
728
  function validateStep(step, inputs) {
646
- if (step.kind !== "form") return {};
729
+ const fields = stepFields(step);
730
+ if (!fields.length) return {};
647
731
  return validateInputs(
648
732
  {
649
733
  id: step.id,
650
734
  title: step.title,
651
- inputs: step.inputs},
735
+ inputs: fields},
652
736
  inputs
653
737
  );
654
738
  }
739
+ function upstreamSteps(steps, id) {
740
+ return steps.filter((s) => s.id !== id && dependsOn(steps, id, s.id));
741
+ }
742
+ function sendBackTargets(steps, states, id) {
743
+ return upstreamSteps(steps, id).filter((s) => ["done", "skipped", "failed"].includes(states[s.id]?.status ?? "pending")).reverse();
744
+ }
745
+ var isBlankRef = (ref) => "step" in ref ? !ref.step : "input" in ref ? !ref.input : !ref.id.trim();
746
+ function stepConfigProblems(steps) {
747
+ const out = [];
748
+ for (const s of steps) {
749
+ if (s.kind === "action") {
750
+ const a = s.action;
751
+ if (a.type === "sign") {
752
+ if (!a.document || isBlankRef(a.document)) out.push({ step: s.id, missing: "document" });
753
+ if (!a.signers.length) out.push({ step: s.id, missing: "signers" });
754
+ } else if (a.type === "email_draft") {
755
+ if (!a.to.some((t) => t.trim())) out.push({ step: s.id, missing: "recipients" });
756
+ } else {
757
+ if (!a.tags.length) out.push({ step: s.id, missing: "tags" });
758
+ if (Array.isArray(a.documents) && !a.documents.length)
759
+ out.push({ step: s.id, missing: "documents" });
760
+ }
761
+ }
762
+ if (s.kind === "agent" && s.editDocument && isBlankRef(s.editDocument))
763
+ out.push({ step: s.id, missing: "document" });
764
+ }
765
+ return out;
766
+ }
767
+ function splitDocRef(ref) {
768
+ const m = /^(doc-[A-Za-z0-9]+)(?:@v(\d+))?$/.exec(ref);
769
+ return m ? { id: m[1], ...m[2] ? { version: Number(m[2]) } : {} } : { id: ref };
770
+ }
771
+ var DEFAULT_ASSIGNEE_WORDING = {
772
+ runOwner: "whoever started the run",
773
+ projectLead: "the project lead",
774
+ input: "the person in \u201C{field}\u201D"
775
+ };
776
+ function assigneeName(assignee, options = {}) {
777
+ const w = { ...DEFAULT_ASSIGNEE_WORDING, ...options.wording };
778
+ const name = (id) => options.nameOf?.(id) ?? id;
779
+ const told = options.announcedTo ? options.nameOf?.(options.announcedTo) : void 0;
780
+ if (told) return told;
781
+ if (!assignee) return void 0;
782
+ if ("user" in assignee) return name(assignee.user);
783
+ if ("input" in assignee) {
784
+ const value = options.inputs?.[assignee.input];
785
+ if (typeof value === "string" && value) return name(value);
786
+ const label = options.fields?.find((f) => f.name === assignee.input)?.label ?? assignee.input;
787
+ return w.input.replace("{field}", label);
788
+ }
789
+ if ("runOwner" in assignee) return w.runOwner;
790
+ return w.projectLead;
791
+ }
655
792
  var asText = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
656
793
  function fillStepInputs(templates, inputs) {
657
794
  const out = {};
@@ -698,6 +835,111 @@ function composeStepPrompt(workflow, step, runInputs, { resolveWorkflow, compose
698
835
  }
699
836
 
700
837
  // src/agents/workflows/planSteps.ts
838
+ function toPlanAssignee(a) {
839
+ if ("user" in a) return { user: a.user };
840
+ if ("input" in a) return { input: a.input };
841
+ if ("runOwner" in a) return { run_owner: true };
842
+ return { project_lead: true };
843
+ }
844
+ function fromPlanAssignee(a) {
845
+ if (!a) return void 0;
846
+ if (a.user) return { user: a.user };
847
+ if (a.input) return { input: a.input };
848
+ if (a.run_owner) return { runOwner: true };
849
+ if (a.project_lead) return { projectLead: true };
850
+ return void 0;
851
+ }
852
+ function toPlanDocumentRef(ref) {
853
+ if ("step" in ref) return { step: ref.step };
854
+ if ("input" in ref) return { input: ref.input };
855
+ return ref.id.trim();
856
+ }
857
+ function fromPlanDocumentRef(ref) {
858
+ if (!ref) return void 0;
859
+ if (typeof ref === "string") return { id: ref };
860
+ if (ref.step) return { step: ref.step };
861
+ if (ref.input) return { input: ref.input };
862
+ return void 0;
863
+ }
864
+ var docRefs = (refs) => (refs ?? []).map(toPlanDocumentRef);
865
+ var fromDocRefs = (refs) => (refs ?? []).flatMap((r) => {
866
+ const ref = fromPlanDocumentRef(r);
867
+ return ref ? [ref] : [];
868
+ });
869
+ function toPlanAction(a) {
870
+ switch (a.type) {
871
+ case "sign":
872
+ return {
873
+ type: "sign",
874
+ // The builder may hold a signature step whose document is not chosen yet: the server
875
+ // refuses it, and the builder says so before saving (`stepConfigProblems`).
876
+ document: a.document ? toPlanDocumentRef(a.document) : "",
877
+ signers: a.signers.map(toPlanAssignee),
878
+ ...a.message?.trim() ? { message: a.message.trim() } : {},
879
+ ...a.expiresAfterHours ? { expires_after_hours: a.expiresAfterHours } : {}
880
+ };
881
+ case "email_draft":
882
+ return {
883
+ type: "email_draft",
884
+ to: a.to.map((t) => t.trim()).filter(Boolean),
885
+ cc: (a.cc ?? []).map((t) => t.trim()).filter(Boolean),
886
+ subject: a.subject,
887
+ body_template: a.body,
888
+ attachments: docRefs(a.attachments)
889
+ };
890
+ case "tabular_review":
891
+ return {
892
+ type: "tabular_review",
893
+ tags: a.tags,
894
+ documents: Array.isArray(a.documents) ? docRefs(a.documents) : a.documents,
895
+ overwrite: !!a.overwrite
896
+ };
897
+ }
898
+ }
899
+ function fromPlanAction(a) {
900
+ switch (a?.type) {
901
+ case "sign":
902
+ return {
903
+ type: "sign",
904
+ document: fromPlanDocumentRef(a.document),
905
+ signers: (a.signers ?? []).flatMap((s) => {
906
+ const one = fromPlanAssignee(s);
907
+ return one ? [one] : [];
908
+ }),
909
+ ...a.message ? { message: a.message } : {},
910
+ ...a.expires_after_hours ? { expiresAfterHours: a.expires_after_hours } : {}
911
+ };
912
+ case "email_draft":
913
+ return {
914
+ type: "email_draft",
915
+ to: a.to ?? [],
916
+ ...a.cc?.length ? { cc: a.cc } : {},
917
+ subject: a.subject ?? "",
918
+ body: a.body_template ?? "",
919
+ ...a.attachments?.length ? { attachments: fromDocRefs(a.attachments) } : {}
920
+ };
921
+ case "tabular_review":
922
+ return {
923
+ type: "tabular_review",
924
+ tags: a.tags ?? [],
925
+ documents: Array.isArray(a.documents) ? fromDocRefs(a.documents) : a.documents ?? "run_uploads",
926
+ ...a.overwrite ? { overwrite: true } : {}
927
+ };
928
+ default:
929
+ return { type: "tabular_review", tags: [], documents: "run_uploads" };
930
+ }
931
+ }
932
+ function toStepField(f) {
933
+ return {
934
+ name: f.name,
935
+ type: f.type,
936
+ label: f.label,
937
+ required: !!f.required,
938
+ ...f.options ? { options: f.options.map((o) => ({ value: o.value, label: o.label })) } : {},
939
+ ...f.min !== void 0 ? { min: f.min } : {},
940
+ ...f.max !== void 0 ? { max: f.max } : {}
941
+ };
942
+ }
701
943
  var compact2 = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== ""));
702
944
  function placeholders(workflow) {
703
945
  return Object.fromEntries(runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
@@ -722,7 +964,7 @@ function toPlanSteps(workflow, options = {}) {
722
964
  position: layout?.[step.id],
723
965
  ...step.kind === "form" ? { fields: step.inputs } : {},
724
966
  ...step.kind === "upload" ? { required: step.required, accept: step.accept, hint: step.hint } : {},
725
- ...step.kind === "review" ? { instructions: step.instructions } : {},
967
+ ...step.kind === "review" ? { instructions: step.instructions, fields: step.fields?.length ? step.fields : void 0 } : {},
726
968
  ...step.kind === "agent" ? {
727
969
  output: step.output,
728
970
  workflow: step.workflow,
@@ -738,10 +980,35 @@ function toPlanSteps(workflow, options = {}) {
738
980
  branch: step.kind === "agent" && !!step.branch,
739
981
  requires_files: false,
740
982
  ui,
983
+ // An unfinished signal (still being typed) is not saved: the server would refuse it.
984
+ ...step.signals?.some((s) => !isIncompleteSignal(s)) ? { signals: step.signals.filter((s) => !isIncompleteSignal(s)).map(toPlanSignal) } : {},
985
+ ...step.assignee && canAssign(step) ? { assignee: toPlanAssignee(step.assignee) } : {},
986
+ ...step.remindAfterHours && canAssign(step) ? { remind_after_hours: step.remindAfterHours } : {},
987
+ // A review's fields are what approving it is checked against (the server's `fields`).
988
+ ...step.kind === "review" && step.fields?.length ? { fields: step.fields.map(toStepField) } : {},
989
+ ...step.kind === "action" ? { action: toPlanAction(step.action) } : {},
990
+ ...step.kind === "agent" && step.editDocument && !step.branch ? { edit_document: toPlanDocumentRef(step.editDocument) } : {},
741
991
  ...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
742
992
  };
743
993
  });
744
994
  }
995
+ function toPlanSignal(signal) {
996
+ return signal.when ? { name: signal.name, when: signal.when } : { name: signal.name };
997
+ }
998
+ function isIncompleteSignal(signal) {
999
+ const when = signal.when;
1000
+ if (!signal.name.trim()) return true;
1001
+ if (!when) return false;
1002
+ if ("field" in when) return !when.field || String(when.equals).trim() === "";
1003
+ if ("contains" in when) return !when.contains.trim();
1004
+ if ("matches" in when) return !when.matches.trim();
1005
+ return false;
1006
+ }
1007
+ function fromPlanSignal(signal) {
1008
+ const w = signal.when;
1009
+ const when = w?.field != null && w.equals != null ? { field: w.field, equals: w.equals } : w?.contains != null ? { contains: w.contains } : w?.matches != null ? { matches: w.matches } : w?.approved ? { approved: true } : void 0;
1010
+ return when ? { name: signal.name, when } : { name: signal.name };
1011
+ }
745
1012
  function fromPlanSteps(steps) {
746
1013
  return (steps ?? []).map((p) => {
747
1014
  const ui = p.ui ?? {};
@@ -752,7 +1019,10 @@ function fromPlanSteps(steps) {
752
1019
  icon: ui.icon,
753
1020
  commit: ui.commit,
754
1021
  nextLabel: ui.next_label,
755
- ...p.after != null ? { after: p.after } : {}
1022
+ ...p.after != null ? { after: p.after } : {},
1023
+ ...p.signals?.length ? { signals: p.signals.map(fromPlanSignal) } : {},
1024
+ ...fromPlanAssignee(p.assignee) ? { assignee: fromPlanAssignee(p.assignee) } : {},
1025
+ ...p.remind_after_hours ? { remindAfterHours: p.remind_after_hours } : {}
756
1026
  };
757
1027
  switch (p.kind) {
758
1028
  case "form":
@@ -760,7 +1030,15 @@ function fromPlanSteps(steps) {
760
1030
  case "upload":
761
1031
  return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
762
1032
  case "review":
763
- return { ...base, kind: "review", instructions: ui.instructions };
1033
+ return {
1034
+ ...base,
1035
+ kind: "review",
1036
+ instructions: ui.instructions,
1037
+ // The client's copy of the fields (labels, options) when it kept one, else the plan's.
1038
+ ...ui.fields?.length ? { fields: ui.fields } : p.fields?.length ? { fields: p.fields.map(fromStepField) } : {}
1039
+ };
1040
+ case "action":
1041
+ return { ...base, kind: "action", action: fromPlanAction(p.action) };
764
1042
  default: {
765
1043
  const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
766
1044
  return {
@@ -770,7 +1048,8 @@ function fromPlanSteps(steps) {
770
1048
  with: ui.with ?? p.inputs ?? void 0,
771
1049
  run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
772
1050
  output: ui.output,
773
- branch: p.branch || void 0
1051
+ branch: p.branch || void 0,
1052
+ ...fromPlanDocumentRef(p.edit_document) ? { editDocument: fromPlanDocumentRef(p.edit_document) } : {}
774
1053
  };
775
1054
  }
776
1055
  }
@@ -783,25 +1062,47 @@ function layoutFromPlanSteps(steps) {
783
1062
  });
784
1063
  return entries.length ? Object.fromEntries(entries) : void 0;
785
1064
  }
1065
+ var FIELD_TYPES2 = /* @__PURE__ */ new Set([
1066
+ "text",
1067
+ "longtext",
1068
+ "boolean",
1069
+ "select",
1070
+ "number",
1071
+ "date",
1072
+ "scope",
1073
+ "documents",
1074
+ "person"
1075
+ ]);
1076
+ function fromStepField(f) {
1077
+ return {
1078
+ name: f.name,
1079
+ type: FIELD_TYPES2.has(f.type) ? f.type : "text",
1080
+ label: f.label ?? f.name,
1081
+ ...f.required ? { required: true } : {},
1082
+ ...f.options?.length ? { options: f.options.map((o) => ({ value: o.value, label: o.label ?? o.value })) } : {},
1083
+ ...f.min != null ? { min: f.min } : {},
1084
+ ...f.max != null ? { max: f.max } : {}
1085
+ };
1086
+ }
786
1087
  var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
787
1088
  function firstOpen(steps, states) {
788
1089
  const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
789
1090
  return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
790
1091
  }
791
1092
  function useWorkflowView(options) {
792
- const { steps, states, inputs, setInput } = options;
1093
+ const { steps, states, inputs, setInput, loaded = true } = options;
793
1094
  const [current, setCurrent] = useState(() => firstOpen(steps, states));
794
1095
  const [showErrors, setShowErrors] = useState(false);
795
1096
  const [busy, setBusy] = useState(false);
796
1097
  const [actionError, setActionError] = useState(null);
797
1098
  const optionsRef = useRef(options);
798
1099
  optionsRef.current = options;
799
- const placed = useRef(steps.length > 0);
1100
+ const placed = useRef(steps.length > 0 && loaded);
800
1101
  useEffect(() => {
801
- if (placed.current || steps.length === 0) return;
1102
+ if (placed.current || steps.length === 0 || !loaded) return;
802
1103
  placed.current = true;
803
1104
  setCurrent(firstOpen(steps, states));
804
- }, [steps, states]);
1105
+ }, [steps, states, loaded]);
805
1106
  const step = steps.find((s) => s.id === current);
806
1107
  const following = useCallback(
807
1108
  (id) => {
@@ -889,6 +1190,40 @@ function useWorkflowView(options) {
889
1190
  // eslint-disable-next-line react-hooks/exhaustive-deps
890
1191
  [act, !!options.retry]
891
1192
  );
1193
+ const sendBack = useMemo(
1194
+ () => options.sendBack ? async (stepId, to, note) => {
1195
+ setBusy(true);
1196
+ setActionError(null);
1197
+ try {
1198
+ await optionsRef.current.sendBack?.(stepId, to, note);
1199
+ setShowErrors(false);
1200
+ setCurrent(to);
1201
+ } catch (e) {
1202
+ setActionError(errorMessage(e));
1203
+ } finally {
1204
+ setBusy(false);
1205
+ }
1206
+ } : void 0,
1207
+ // Only whether the host offers it matters here.
1208
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1209
+ [!!options.sendBack]
1210
+ );
1211
+ const declineWithNote = useMemo(
1212
+ () => options.decline ? async (stepId, note) => {
1213
+ setBusy(true);
1214
+ setActionError(null);
1215
+ try {
1216
+ await optionsRef.current.decline?.(stepId, note);
1217
+ } catch (e) {
1218
+ setActionError(errorMessage(e));
1219
+ } finally {
1220
+ setBusy(false);
1221
+ }
1222
+ } : void 0,
1223
+ // Only whether the host offers it matters here.
1224
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1225
+ [!!options.decline]
1226
+ );
892
1227
  const isLocked = useCallback(
893
1228
  (stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
894
1229
  []
@@ -914,6 +1249,19 @@ function useWorkflowView(options) {
914
1249
  goTo,
915
1250
  skip,
916
1251
  retry,
1252
+ sendBack,
1253
+ decline: declineWithNote,
1254
+ nameOf: options.nameOf,
1255
+ assigneeOf: (id) => {
1256
+ const s = steps.find((x) => x.id === id);
1257
+ if (!s || !canAssign(s)) return void 0;
1258
+ return assigneeName(s.assignee, {
1259
+ nameOf: options.nameOf,
1260
+ inputs,
1261
+ fields: runFieldsOf(steps),
1262
+ announcedTo: states[id]?.announcedTo
1263
+ });
1264
+ },
917
1265
  restart: () => {
918
1266
  setShowErrors(false);
919
1267
  setActionError(null);
@@ -921,9 +1269,489 @@ function useWorkflowView(options) {
921
1269
  }
922
1270
  };
923
1271
  }
1272
+ var DEFAULT_WORKFLOW_STEP_PARTS_LABELS = {
1273
+ waitingFor: "Waiting for {name}",
1274
+ sendBack: "Send back",
1275
+ sendBackTo: "Send back to",
1276
+ sendBackNote: "What needs to change? (optional)",
1277
+ cancel: "Cancel",
1278
+ sentBackHere: "This step was sent back to be done again.",
1279
+ approvedBy: "Approved by {name}",
1280
+ approvedAt: "{date}",
1281
+ approvedWhat: "What was approved",
1282
+ viewAnswer: "View the answer",
1283
+ fieldsHeading: "Recorded with the approval",
1284
+ signers: "Signers",
1285
+ signed: "Signed",
1286
+ notSigned: "Not signed yet",
1287
+ openAndSign: "Open and sign",
1288
+ decline: "Decline",
1289
+ declineNote: "Why are you declining? (optional)",
1290
+ declineConfirm: "Decline to sign",
1291
+ declined: "Declined by {name}.",
1292
+ signedVersion: "Open the signed version",
1293
+ preparingSign: "Preparing the signature request\u2026",
1294
+ expires: "Expires {date}",
1295
+ preparingDraft: "Preparing the draft\u2026",
1296
+ draftReady: "The draft is ready in native mail. Check it, send it, then mark it as sent.",
1297
+ openDraft: "Open draft",
1298
+ emailSent: "Sent.",
1299
+ reviewRunning: "Reviewing the documents\u2026",
1300
+ reviewDone: "Reviewed {docs} documents in {cols} columns.",
1301
+ openReview: "Open the review",
1302
+ openInWord: "Open in Word",
1303
+ redlineHint: "The edits are tracked changes: accept or reject each one in Word.",
1304
+ someone: "someone"
1305
+ };
1306
+ var formatDate = (iso) => {
1307
+ const t = iso ? Date.parse(iso) : NaN;
1308
+ return Number.isNaN(t) ? "" : new Date(t).toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
1309
+ };
1310
+ var docName = (ref, nameOfDoc) => {
1311
+ const { id, version } = splitDocRef(ref);
1312
+ const name = nameOfDoc?.(id) ?? id;
1313
+ return version ? `${name} \xB7 v${version}` : name;
1314
+ };
1315
+ function DocChip({
1316
+ docRef,
1317
+ actions,
1318
+ nameOfDoc,
1319
+ testId
1320
+ }) {
1321
+ const label = docName(docRef, nameOfDoc);
1322
+ const cls = "inline-flex max-w-full items-center gap-1 rounded-md border border-border px-1.5 py-0.5 text-xs";
1323
+ return actions?.openDocument ? /* @__PURE__ */ jsxs(
1324
+ "button",
1325
+ {
1326
+ type: "button",
1327
+ onClick: () => actions.openDocument?.(docRef),
1328
+ className: cn(cls, "hover:border-primary/40 hover:text-primary"),
1329
+ title: docRef,
1330
+ "data-testid": testId,
1331
+ children: [
1332
+ /* @__PURE__ */ jsx(FileText, { className: "size-3 shrink-0" }),
1333
+ " ",
1334
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
1335
+ ]
1336
+ }
1337
+ ) : /* @__PURE__ */ jsxs("span", { className: cls, title: docRef, "data-testid": testId, children: [
1338
+ /* @__PURE__ */ jsx(FileText, { className: "size-3 shrink-0" }),
1339
+ " ",
1340
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
1341
+ ] });
1342
+ }
1343
+ function AssigneeLine({
1344
+ run,
1345
+ stepId,
1346
+ l,
1347
+ testId
1348
+ }) {
1349
+ const name = run.assigneeOf(stepId);
1350
+ const phase = run.phaseOf(stepId);
1351
+ if (!name || !["ready", "waiting", "blocked"].includes(phase)) return null;
1352
+ return /* @__PURE__ */ jsxs(
1353
+ "p",
1354
+ {
1355
+ className: "flex items-center gap-1.5 text-xs text-muted-foreground",
1356
+ "data-testid": `${testId}-assignee`,
1357
+ children: [
1358
+ /* @__PURE__ */ jsx(UserRound, { className: "size-3.5" }),
1359
+ " ",
1360
+ l.waitingFor.replace("{name}", name)
1361
+ ]
1362
+ }
1363
+ );
1364
+ }
1365
+ function SentBackNote({
1366
+ state,
1367
+ l,
1368
+ testId
1369
+ }) {
1370
+ if (!state?.sentBack) return null;
1371
+ return /* @__PURE__ */ jsxs(
1372
+ "p",
1373
+ {
1374
+ className: "flex items-center gap-1.5 rounded-md bg-amber-500/10 px-2 py-1 text-xs text-amber-700 dark:text-amber-300",
1375
+ "data-testid": `${testId}-sent-back`,
1376
+ children: [
1377
+ /* @__PURE__ */ jsx(CornerUpLeft, { className: "size-3.5" }),
1378
+ " ",
1379
+ l.sentBackHere
1380
+ ]
1381
+ }
1382
+ );
1383
+ }
1384
+ function SendBackControl({
1385
+ run,
1386
+ step,
1387
+ l,
1388
+ testId
1389
+ }) {
1390
+ const states = Object.fromEntries(
1391
+ run.steps.map((s) => [s.id, run.stateOf(s.id) ?? { status: "pending" }])
1392
+ );
1393
+ const targets = sendBackTargets(run.steps, states, step.id);
1394
+ const [open, setOpen] = useState(false);
1395
+ const [to, setTo] = useState(targets[0]?.id ?? "");
1396
+ const [note, setNote] = useState("");
1397
+ if (!run.sendBack || run.phaseOf(step.id) !== "ready" || targets.length === 0) return null;
1398
+ if (!open)
1399
+ return /* @__PURE__ */ jsxs(
1400
+ Button,
1401
+ {
1402
+ variant: "outline",
1403
+ size: "sm",
1404
+ onClick: () => setOpen(true),
1405
+ disabled: run.busy,
1406
+ "data-testid": `${testId}-send-back`,
1407
+ children: [
1408
+ /* @__PURE__ */ jsx(CornerUpLeft, { className: "size-4" }),
1409
+ " ",
1410
+ l.sendBack
1411
+ ]
1412
+ }
1413
+ );
1414
+ const target = targets.some((t) => t.id === to) ? to : targets[0].id;
1415
+ return /* @__PURE__ */ jsxs(
1416
+ "div",
1417
+ {
1418
+ className: "space-y-2 rounded-md border border-border p-3",
1419
+ "data-testid": `${testId}-send-back-form`,
1420
+ children: [
1421
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs font-medium", children: [
1422
+ l.sendBackTo,
1423
+ /* @__PURE__ */ jsx(
1424
+ "select",
1425
+ {
1426
+ className: "flex h-8 w-full rounded-md border border-input bg-background px-2 text-sm",
1427
+ value: target,
1428
+ onChange: (e) => setTo(e.target.value),
1429
+ "data-testid": `${testId}-send-back-to`,
1430
+ children: targets.map((t) => /* @__PURE__ */ jsx("option", { value: t.id, children: t.title }, t.id))
1431
+ }
1432
+ )
1433
+ ] }),
1434
+ /* @__PURE__ */ jsx(
1435
+ Textarea,
1436
+ {
1437
+ rows: 3,
1438
+ value: note,
1439
+ placeholder: l.sendBackNote,
1440
+ "aria-label": l.sendBackNote,
1441
+ onChange: (e) => setNote(e.target.value),
1442
+ "data-testid": `${testId}-send-back-note`
1443
+ }
1444
+ ),
1445
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
1446
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setOpen(false), children: l.cancel }),
1447
+ /* @__PURE__ */ jsxs(
1448
+ Button,
1449
+ {
1450
+ size: "sm",
1451
+ disabled: run.busy,
1452
+ onClick: () => void run.sendBack?.(step.id, target, note.trim() || void 0),
1453
+ "data-testid": `${testId}-send-back-confirm`,
1454
+ children: [
1455
+ /* @__PURE__ */ jsx(CornerUpLeft, { className: "size-4" }),
1456
+ " ",
1457
+ l.sendBack
1458
+ ]
1459
+ }
1460
+ )
1461
+ ] })
1462
+ ]
1463
+ }
1464
+ );
1465
+ }
1466
+ var shownValue = (v, field, nameOf) => {
1467
+ if (v === void 0 || v === null || v === "") return "\u2014";
1468
+ if (typeof v === "boolean") return v ? "\u2713" : "\u2717";
1469
+ if (field.type === "person" && typeof v === "string") return nameOf?.(v) ?? v;
1470
+ if (field.type === "select") return field.options?.find((o) => o.value === v)?.label ?? String(v);
1471
+ return typeof v === "object" ? JSON.stringify(v) : String(v);
1472
+ };
1473
+ function ApprovalEvidence({
1474
+ run,
1475
+ step,
1476
+ actions,
1477
+ nameOfDoc,
1478
+ l,
1479
+ testId
1480
+ }) {
1481
+ const state = run.stateOf(step.id);
1482
+ if (state?.status !== "done") return null;
1483
+ const approver = state.by ? run.nameOf?.(state.by) ?? l.someone : void 0;
1484
+ const evidence = state.approved ?? [];
1485
+ const titleOf = (id) => run.steps.find((s) => s.id === id)?.title ?? id;
1486
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-md bg-muted/40 p-3", "data-testid": `${testId}-evidence`, children: [
1487
+ /* @__PURE__ */ jsxs("p", { className: "flex flex-wrap items-center gap-1.5 text-sm font-medium", children: [
1488
+ /* @__PURE__ */ jsx(ShieldCheck, { className: "size-4 text-primary" }),
1489
+ approver ? l.approvedBy.replace("{name}", approver) : null,
1490
+ state.at && /* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-muted-foreground", children: l.approvedAt.replace("{date}", formatDate(state.at)) })
1491
+ ] }),
1492
+ evidence.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1493
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.approvedWhat }),
1494
+ evidence.map((e) => /* @__PURE__ */ jsxs(
1495
+ "div",
1496
+ {
1497
+ className: "flex flex-wrap items-center gap-1.5 text-xs",
1498
+ "data-testid": `${testId}-evidence-${e.step}`,
1499
+ children: [
1500
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: titleOf(e.step) }),
1501
+ e.response_id && (actions?.openMessage ? /* @__PURE__ */ jsxs(
1502
+ "button",
1503
+ {
1504
+ type: "button",
1505
+ onClick: () => actions.openMessage?.(e.response_id),
1506
+ className: "inline-flex items-center gap-1 text-primary hover:underline",
1507
+ "data-testid": `${testId}-evidence-${e.step}-answer`,
1508
+ children: [
1509
+ /* @__PURE__ */ jsx(MessageSquare, { className: "size-3" }),
1510
+ " ",
1511
+ l.viewAnswer
1512
+ ]
1513
+ }
1514
+ ) : null),
1515
+ (e.documents ?? []).map((d) => /* @__PURE__ */ jsx(DocChip, { docRef: d, actions, nameOfDoc }, d))
1516
+ ]
1517
+ },
1518
+ e.step
1519
+ ))
1520
+ ] }),
1521
+ (step.fields ?? []).length > 0 && /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-0.5 text-xs", children: (step.fields ?? []).map((f) => /* @__PURE__ */ jsxs("div", { className: "contents", children: [
1522
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: f.label }),
1523
+ /* @__PURE__ */ jsx("dd", { "data-testid": `${testId}-evidence-field-${f.name}`, children: shownValue(run.inputs[f.name], f, run.nameOf) })
1524
+ ] }, f.name)) })
1525
+ ] });
1526
+ }
1527
+ function RedlineOpen({
1528
+ step,
1529
+ state,
1530
+ actions,
1531
+ l,
1532
+ testId
1533
+ }) {
1534
+ const version = state?.status === "done" ? state.documents?.[0] : void 0;
1535
+ if (!step.editDocument || !version || !actions?.openRedline) return null;
1536
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", "data-testid": `${testId}-redline`, children: [
1537
+ /* @__PURE__ */ jsxs(
1538
+ Button,
1539
+ {
1540
+ size: "sm",
1541
+ onClick: () => actions.openRedline?.(version),
1542
+ "data-testid": `${testId}-open-word`,
1543
+ children: [
1544
+ /* @__PURE__ */ jsx(FileText, { className: "size-4" }),
1545
+ " ",
1546
+ l.openInWord
1547
+ ]
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: l.redlineHint })
1551
+ ] });
1552
+ }
1553
+ function ActionStepBody({
1554
+ step,
1555
+ run,
1556
+ actions,
1557
+ nameOfDoc,
1558
+ heading,
1559
+ l,
1560
+ testId
1561
+ }) {
1562
+ const state = run.stateOf(step.id);
1563
+ const phase = run.phaseOf(step.id);
1564
+ const name = (id) => run.nameOf?.(id) ?? id;
1565
+ const [declining, setDeclining] = useState(false);
1566
+ const [note, setNote] = useState("");
1567
+ const a = step.action;
1568
+ const working = (text) => /* @__PURE__ */ jsxs(
1569
+ "p",
1570
+ {
1571
+ className: "flex items-center gap-2 text-sm text-muted-foreground",
1572
+ "data-testid": `${testId}-working`,
1573
+ children: [
1574
+ /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }),
1575
+ " ",
1576
+ text
1577
+ ]
1578
+ }
1579
+ );
1580
+ let body = null;
1581
+ if (a.type === "sign") {
1582
+ const waiting = state?.waiting;
1583
+ const signers = waiting?.signers ?? [];
1584
+ const signed = new Set(waiting?.signed ?? []);
1585
+ const mine = !actions?.me || signers.includes(actions.me) && !signed.has(actions.me);
1586
+ const signedRef = state?.status === "done" ? state.documents?.[0] : void 0;
1587
+ body = /* @__PURE__ */ jsxs(Fragment, { children: [
1588
+ (phase === "ready" || phase === "running") && working(l.preparingSign),
1589
+ phase === "waiting" && waiting?.doc_ext_id && /* @__PURE__ */ jsx(
1590
+ DocChip,
1591
+ {
1592
+ docRef: `${waiting.doc_ext_id}${waiting.version ? `@v${waiting.version}` : ""}`,
1593
+ actions,
1594
+ nameOfDoc,
1595
+ testId: `${testId}-document`
1596
+ }
1597
+ ),
1598
+ signers.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1", "data-testid": `${testId}-signers`, children: [
1599
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.signers }),
1600
+ signers.map((id) => /* @__PURE__ */ jsxs(
1601
+ "p",
1602
+ {
1603
+ className: "flex items-center gap-2 text-sm",
1604
+ "data-signed": signed.has(id) || void 0,
1605
+ "data-testid": `${testId}-signer-${id}`,
1606
+ children: [
1607
+ signed.has(id) ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" }) : /* @__PURE__ */ jsx(Hourglass, { className: "size-3.5 text-muted-foreground" }),
1608
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: name(id) }),
1609
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: signed.has(id) ? l.signed : l.notSigned })
1610
+ ]
1611
+ },
1612
+ id
1613
+ ))
1614
+ ] }),
1615
+ waiting?.expires_at && phase === "waiting" && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1616
+ /* @__PURE__ */ jsx(Clock, { className: "size-3.5" }),
1617
+ " ",
1618
+ l.expires.replace("{date}", formatDate(waiting.expires_at))
1619
+ ] }),
1620
+ phase === "waiting" && mine && !declining && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
1621
+ actions?.sign && state && /* @__PURE__ */ jsxs(
1622
+ Button,
1623
+ {
1624
+ size: "sm",
1625
+ onClick: () => actions.sign?.(step, state),
1626
+ "data-testid": `${testId}-open-sign`,
1627
+ children: [
1628
+ /* @__PURE__ */ jsx(PenLine, { className: "size-4" }),
1629
+ " ",
1630
+ l.openAndSign
1631
+ ]
1632
+ }
1633
+ ),
1634
+ run.decline && /* @__PURE__ */ jsxs(
1635
+ Button,
1636
+ {
1637
+ size: "sm",
1638
+ variant: "ghost",
1639
+ onClick: () => setDeclining(true),
1640
+ "data-testid": `${testId}-decline`,
1641
+ children: [
1642
+ /* @__PURE__ */ jsx(X, { className: "size-4" }),
1643
+ " ",
1644
+ l.decline
1645
+ ]
1646
+ }
1647
+ )
1648
+ ] }),
1649
+ declining && /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": `${testId}-decline-form`, children: [
1650
+ /* @__PURE__ */ jsx(
1651
+ Textarea,
1652
+ {
1653
+ rows: 2,
1654
+ value: note,
1655
+ placeholder: l.declineNote,
1656
+ "aria-label": l.declineNote,
1657
+ onChange: (e) => setNote(e.target.value),
1658
+ "data-testid": `${testId}-decline-note`
1659
+ }
1660
+ ),
1661
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
1662
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setDeclining(false), children: l.cancel }),
1663
+ /* @__PURE__ */ jsx(
1664
+ Button,
1665
+ {
1666
+ size: "sm",
1667
+ variant: "destructive",
1668
+ disabled: run.busy,
1669
+ onClick: async () => {
1670
+ await run.decline?.(step.id, note.trim() || void 0);
1671
+ setDeclining(false);
1672
+ },
1673
+ "data-testid": `${testId}-decline-confirm`,
1674
+ children: l.declineConfirm
1675
+ }
1676
+ )
1677
+ ] })
1678
+ ] }),
1679
+ phase === "failed" && state?.declinedBy && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-declined`, children: l.declined.replace("{name}", name(state.declinedBy)) }),
1680
+ signedRef && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions?.openDocument ? /* @__PURE__ */ jsxs(
1681
+ Button,
1682
+ {
1683
+ size: "sm",
1684
+ variant: "outline",
1685
+ onClick: () => actions.openDocument?.(signedRef),
1686
+ "data-testid": `${testId}-signed-version`,
1687
+ children: [
1688
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-4" }),
1689
+ " ",
1690
+ l.signedVersion
1691
+ ]
1692
+ }
1693
+ ) : /* @__PURE__ */ jsx(DocChip, { docRef: signedRef, nameOfDoc }) })
1694
+ ] });
1695
+ } else if (a.type === "email_draft") {
1696
+ const draftId = state?.waiting?.draft_id ?? (typeof state?.output?.draft_id === "string" ? state.output.draft_id : void 0);
1697
+ body = /* @__PURE__ */ jsxs(Fragment, { children: [
1698
+ (phase === "ready" || phase === "running") && working(l.preparingDraft),
1699
+ phase === "waiting" && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: l.draftReady }),
1700
+ phase === "done" && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-sm", "data-testid": `${testId}-sent`, children: [
1701
+ /* @__PURE__ */ jsx(Check, { className: "size-4 text-primary" }),
1702
+ " ",
1703
+ l.emailSent
1704
+ ] }),
1705
+ draftId && actions?.openDraft && phase !== "done" && /* @__PURE__ */ jsxs(
1706
+ Button,
1707
+ {
1708
+ size: "sm",
1709
+ variant: "outline",
1710
+ onClick: () => actions.openDraft?.(draftId, state?.waiting?.mailbox),
1711
+ "data-testid": `${testId}-open-draft`,
1712
+ children: [
1713
+ /* @__PURE__ */ jsx(Mail, { className: "size-4" }),
1714
+ " ",
1715
+ l.openDraft
1716
+ ]
1717
+ }
1718
+ )
1719
+ ] });
1720
+ } else {
1721
+ const tags = state?.output?.tag_ext_ids ?? a.tags;
1722
+ const docs = state?.output?.doc_ext_ids ?? [];
1723
+ body = /* @__PURE__ */ jsxs(Fragment, { children: [
1724
+ (phase === "ready" || phase === "running") && working(l.reviewRunning),
1725
+ phase === "done" && /* @__PURE__ */ jsxs(Fragment, { children: [
1726
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-reviewed`, children: l.reviewDone.replace("{docs}", String(docs.length)).replace("{cols}", String(tags.length)) }),
1727
+ actions?.openReview && /* @__PURE__ */ jsxs(
1728
+ Button,
1729
+ {
1730
+ size: "sm",
1731
+ onClick: () => actions.openReview?.(tags, docs),
1732
+ "data-testid": `${testId}-open-review`,
1733
+ children: [
1734
+ /* @__PURE__ */ jsx(Table2, { className: "size-4" }),
1735
+ " ",
1736
+ l.openReview
1737
+ ]
1738
+ }
1739
+ )
1740
+ ] })
1741
+ ] });
1742
+ }
1743
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1744
+ heading,
1745
+ /* @__PURE__ */ jsx(SentBackNote, { state, l, testId }),
1746
+ /* @__PURE__ */ jsx(AssigneeLine, { run, stepId: step.id, l, testId }),
1747
+ body,
1748
+ phase === "failed" && !state?.declinedBy && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-failed`, children: state?.error || "" })
1749
+ ] });
1750
+ }
924
1751
  function PhaseMark({ phase, icon }) {
925
1752
  if (phase === "done") return /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0" });
926
1753
  if (phase === "running") return /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 shrink-0 animate-spin" });
1754
+ if (phase === "waiting") return /* @__PURE__ */ jsx(Hourglass, { className: "size-3.5 shrink-0" });
927
1755
  if (phase === "failed") return /* @__PURE__ */ jsx(AlertTriangle, { className: "size-3.5 shrink-0" });
928
1756
  if (phase === "skipped") return /* @__PURE__ */ jsx(MinusCircle, { className: "size-3.5 shrink-0" });
929
1757
  return icon ? /* @__PURE__ */ jsx("span", { className: "flex size-3.5 shrink-0 items-center justify-center [&_svg]:size-3.5", children: icon }) : null;
@@ -956,6 +1784,8 @@ function WorkflowStepBar({
956
1784
  const pill = (s) => {
957
1785
  const phase = run.phaseOf(s.id);
958
1786
  const current = s.id === run.current;
1787
+ const assignee = ["ready", "waiting"].includes(phase) ? run.assigneeOf(s.id) : void 0;
1788
+ const title = assignee ? `${s.title} \xB7 ${assignee}` : s.title;
959
1789
  return /* @__PURE__ */ jsxs(
960
1790
  "button",
961
1791
  {
@@ -965,16 +1795,27 @@ function WorkflowStepBar({
965
1795
  className: cn(
966
1796
  PILL,
967
1797
  "transition-colors disabled:cursor-default",
968
- current ? "border-primary bg-primary/10 text-primary" : phase === "failed" ? "border-destructive/40 text-destructive" : phase === "done" || phase === "skipped" || phase === "running" ? "border-primary/30 bg-primary/5 text-primary" : "border-border text-muted-foreground"
1798
+ current ? "border-primary bg-primary/10 text-primary" : phase === "failed" ? "border-destructive/40 text-destructive" : phase === "done" || phase === "skipped" || phase === "running" || phase === "waiting" ? "border-primary/30 bg-primary/5 text-primary" : "border-border text-muted-foreground"
969
1799
  ),
970
1800
  "aria-current": current ? "step" : void 0,
971
- "aria-label": s.title,
972
- title: s.title,
1801
+ "aria-label": title,
1802
+ title,
973
1803
  "data-phase": phase,
974
1804
  "data-testid": tid(`step-${s.id}`),
975
1805
  children: [
976
1806
  /* @__PURE__ */ jsx(PhaseMark, { phase, icon: icon(s.icon) }),
977
- (current || !compact3) && /* @__PURE__ */ jsx("span", { className: LABEL, "data-testid": tid(`step-${s.id}-label`), children: s.title })
1807
+ (current || !compact3) && /* @__PURE__ */ jsx("span", { className: LABEL, "data-testid": tid(`step-${s.id}-label`), children: s.title }),
1808
+ assignee && !compact3 && /* @__PURE__ */ jsxs(
1809
+ "span",
1810
+ {
1811
+ className: "min-w-0 max-w-[8rem] truncate font-normal opacity-75",
1812
+ "data-testid": tid(`step-${s.id}-assignee`),
1813
+ children: [
1814
+ "\xB7 ",
1815
+ assignee
1816
+ ]
1817
+ }
1818
+ )
978
1819
  ]
979
1820
  },
980
1821
  s.id
@@ -1079,7 +1920,8 @@ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
1079
1920
  fileReading: "Reading\u2026",
1080
1921
  fileReady: "Ready",
1081
1922
  fileFailed: "Could not be read",
1082
- readingFiles: "Reading {current} of {count} files\u2026"
1923
+ readingFiles: "Reading {current} of {count} files\u2026",
1924
+ markSent: "Mark as sent"
1083
1925
  };
1084
1926
  function WorkflowRunner({
1085
1927
  workflow,
@@ -1095,11 +1937,16 @@ function WorkflowRunner({
1095
1937
  renderScope,
1096
1938
  renderDocuments,
1097
1939
  renderIcon,
1940
+ people,
1941
+ actions,
1942
+ nameOfDoc,
1098
1943
  labels,
1944
+ partsLabels,
1099
1945
  testIdPrefix = "workflow-run",
1100
1946
  className
1101
1947
  }) {
1102
1948
  const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
1949
+ const pl = { ...DEFAULT_WORKFLOW_STEP_PARTS_LABELS, ...partsLabels };
1103
1950
  const { steps, step, isComplete, action } = run;
1104
1951
  const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
1105
1952
  const tid = (suffix) => `${testIdPrefix}-${suffix}`;
@@ -1108,7 +1955,7 @@ function WorkflowRunner({
1108
1955
  const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
1109
1956
  const unread = added.filter((f) => f.status === "processing").length;
1110
1957
  const reading = action === "complete" && unread > 0;
1111
- const nextLabel = reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
1958
+ const nextLabel = reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "complete" && step?.kind === "action" ? l.markSent : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
1112
1959
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-6", className), "data-testid": testIdPrefix, children: [
1113
1960
  /* @__PURE__ */ jsx(
1114
1961
  WorkflowStepBar,
@@ -1140,6 +1987,8 @@ function WorkflowRunner({
1140
1987
  stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
1141
1988
  ) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
1142
1989
  /* @__PURE__ */ jsx(StepHeading, { step, icon: icon(step.icon), testId: tid(`${step.id}-title`) }),
1990
+ /* @__PURE__ */ jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
1991
+ /* @__PURE__ */ jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
1143
1992
  /* @__PURE__ */ jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsx(
1144
1993
  SchemaForm,
1145
1994
  {
@@ -1150,6 +1999,7 @@ function WorkflowRunner({
1150
1999
  renderScope,
1151
2000
  renderDocuments,
1152
2001
  renderIcon,
2002
+ people,
1153
2003
  onEnterSubmit: () => void run.next(),
1154
2004
  testIdPrefix: tid("field")
1155
2005
  }
@@ -1157,6 +2007,8 @@ function WorkflowRunner({
1157
2007
  run.actionError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
1158
2008
  renderStepNote?.(step, run)
1159
2009
  ] }) : step.kind === "upload" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
2010
+ /* @__PURE__ */ jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2011
+ /* @__PURE__ */ jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
1160
2012
  renderUpload?.(step) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
1161
2013
  /* @__PURE__ */ jsx(
1162
2014
  UploadDropzone,
@@ -1185,9 +2037,52 @@ function WorkflowRunner({
1185
2037
  renderStepNote?.(step, run)
1186
2038
  ] }) : step.kind === "review" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
1187
2039
  /* @__PURE__ */ jsx(StepHeading, { step, icon: icon(step.icon) }),
2040
+ /* @__PURE__ */ jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
1188
2041
  /* @__PURE__ */ jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
1189
- /* @__PURE__ */ jsx("p", { className: "text-sm", "data-testid": tid(`${step.id}-status`), children: run.phaseOf(step.id) === "done" ? l.approved : run.phaseOf(step.id) === "skipped" ? l.skipped : l.awaitingReview }),
2042
+ /* @__PURE__ */ jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
2043
+ !(run.phaseOf(step.id) === "done" && run.stateOf(step.id)?.by) && /* @__PURE__ */ jsx("p", { className: "text-sm", "data-testid": tid(`${step.id}-status`), children: run.phaseOf(step.id) === "done" ? l.approved : run.phaseOf(step.id) === "skipped" ? l.skipped : l.awaitingReview }),
2044
+ (step.fields ?? []).length > 0 && run.phaseOf(step.id) === "ready" && /* @__PURE__ */ jsx(
2045
+ SchemaForm,
2046
+ {
2047
+ fields: step.fields ?? [],
2048
+ values: run.inputs,
2049
+ onChange: run.setInput,
2050
+ errors: run.errors,
2051
+ renderScope,
2052
+ renderDocuments,
2053
+ renderIcon,
2054
+ people,
2055
+ testIdPrefix: tid("field")
2056
+ }
2057
+ ),
2058
+ /* @__PURE__ */ jsx(
2059
+ ApprovalEvidence,
2060
+ {
2061
+ run,
2062
+ step,
2063
+ actions,
2064
+ nameOfDoc,
2065
+ l: pl,
2066
+ testId: tid(step.id)
2067
+ }
2068
+ ),
1190
2069
  run.phaseOf(step.id) === "ready" && renderReview?.(step),
2070
+ /* @__PURE__ */ jsx(SendBackControl, { run, step, l: pl, testId: tid(step.id) }),
2071
+ run.actionError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
2072
+ renderStepNote?.(step, run)
2073
+ ] }) : step.kind === "action" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
2074
+ /* @__PURE__ */ jsx(
2075
+ ActionStepBody,
2076
+ {
2077
+ step,
2078
+ run,
2079
+ actions,
2080
+ nameOfDoc,
2081
+ heading: /* @__PURE__ */ jsx(StepHeading, { step, icon: icon(step.icon) }),
2082
+ l: pl,
2083
+ testId: tid(step.id)
2084
+ }
2085
+ ),
1191
2086
  run.actionError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
1192
2087
  renderStepNote?.(step, run)
1193
2088
  ] }) : /* @__PURE__ */ jsx(
@@ -1198,6 +2093,19 @@ function WorkflowRunner({
1198
2093
  renderAgentOutput,
1199
2094
  icon: icon(step.icon),
1200
2095
  renderStepNote,
2096
+ extra: /* @__PURE__ */ jsxs(Fragment, { children: [
2097
+ /* @__PURE__ */ jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
2098
+ /* @__PURE__ */ jsx(
2099
+ RedlineOpen,
2100
+ {
2101
+ step,
2102
+ state: run.stateOf(step.id),
2103
+ actions,
2104
+ l: pl,
2105
+ testId: tid(step.id)
2106
+ }
2107
+ )
2108
+ ] }),
1201
2109
  l,
1202
2110
  tid
1203
2111
  }
@@ -1328,6 +2236,7 @@ function AgentStepBody({
1328
2236
  renderAgentOutput,
1329
2237
  icon,
1330
2238
  renderStepNote,
2239
+ extra,
1331
2240
  l,
1332
2241
  tid
1333
2242
  }) {
@@ -1370,7 +2279,8 @@ function AgentStepBody({
1370
2279
  }
1371
2280
  ),
1372
2281
  phase === "failed" && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
1373
- phase === "skipped" && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped })
2282
+ phase === "skipped" && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped }),
2283
+ extra
1374
2284
  ] });
1375
2285
  if (step.output === "artifact") {
1376
2286
  return /* @__PURE__ */ jsxs(
@@ -1397,6 +2307,6 @@ function AgentStepBody({
1397
2307
  ] });
1398
2308
  }
1399
2309
 
1400
- export { DEFAULT_SCHEMA_FORM_LABELS, DEFAULT_WORKFLOW_RUNNER_LABELS, EMPTY_WORKFLOW_SCOPE, SKILL_PROMPT_FALLBACK_PLACEHOLDER, SKILL_PROMPT_LABEL, SchemaForm, WorkflowRunner, buildLaunch, composeStepPrompt, composeWorkflowPrompt, defaultInputs, dependsOn, fieldToFrontmatter, fillRunText, fillStepInputs, fromPlanSteps, initialRunInputs, inputsFromContext, isEmptyWorkflowScope, isPersonStep, isRunFinished, isSteppedWorkflow, isWorkflowScope, layoutFromPlanSteps, nextAction, orderSteps, promptFieldName, reviewInstructions, runFields, runThreadTitle, skillToWorkflow, stepDependencies, stepLevels, stepPhase, stepStatesFromActivity, toPlanSteps, useWorkflowView, validateInputs, validateStep, validateWorkflowGraph, workflowAccepts, workflowFromFrontmatter, workflowSteps, workflowsAccepting, workflowsForHost };
1401
- //# sourceMappingURL=chunk-YWYVIQ7T.js.map
1402
- //# sourceMappingURL=chunk-YWYVIQ7T.js.map
2310
+ export { ActionStepBody, ApprovalEvidence, AssigneeLine, DEFAULT_ASSIGNEE_WORDING, DEFAULT_SCHEMA_FORM_LABELS, DEFAULT_WORKFLOW_RUNNER_LABELS, DEFAULT_WORKFLOW_STEP_PARTS_LABELS, EMPTY_WORKFLOW_SCOPE, SKILL_PROMPT_FALLBACK_PLACEHOLDER, SKILL_PROMPT_LABEL, SchemaForm, SendBackControl, WorkflowRunner, assigneeName, buildLaunch, canAssign, composeStepPrompt, composeWorkflowPrompt, defaultInputs, dependsOn, fieldToFrontmatter, fillRunText, fillStepInputs, fromPlanAssignee, fromPlanDocumentRef, fromPlanSteps, initialRunInputs, inputsFromContext, isEmptyWorkflowScope, isIncompleteSignal, isPersonAction, isPersonStep, isRunFinished, isSteppedWorkflow, isWorkflowScope, layoutFromPlanSteps, nextAction, orderSteps, promptFieldName, reviewInstructions, runFields, runFieldsOf, runThreadTitle, sendBackTargets, skillToWorkflow, splitDocRef, stepConfigProblems, stepDependencies, stepFields, stepLevels, stepPhase, stepStatesFromActivity, toPlanAssignee, toPlanDocumentRef, toPlanSteps, upstreamSteps, useWorkflowView, validateInputs, validateStep, validateWorkflowGraph, workflowAccepts, workflowFromFrontmatter, workflowSteps, workflowsAccepting, workflowsForHost };
2311
+ //# sourceMappingURL=chunk-34UW6XUQ.js.map
2312
+ //# sourceMappingURL=chunk-34UW6XUQ.js.map