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