@arbidocs/blocks 0.4.73 → 0.4.74

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 (58) hide show
  1. package/dist/agents/index.cjs +253 -253
  2. package/dist/agents/index.js +3 -3
  3. package/dist/agents/workflows/WorkflowRunner.d.ts +20 -4
  4. package/dist/agents/workflows/WorkflowStepBar.d.ts +23 -0
  5. package/dist/agents/workflows/run.d.ts +1 -0
  6. package/dist/agents/workflows/types.d.ts +2 -0
  7. package/dist/chat/index.cjs +124 -124
  8. package/dist/chat/index.js +3 -3
  9. package/dist/{chunk-IUR565UW.cjs → chunk-5LP54CWR.cjs} +32 -32
  10. package/dist/chunk-5LP54CWR.cjs.map +1 -0
  11. package/dist/{chunk-3SFFTSOI.cjs → chunk-7CVF3DK2.cjs} +5 -5
  12. package/dist/{chunk-3SFFTSOI.cjs.map → chunk-7CVF3DK2.cjs.map} +1 -1
  13. package/dist/{chunk-V3L5DONY.cjs → chunk-B4SRYJLM.cjs} +31 -2
  14. package/dist/chunk-B4SRYJLM.cjs.map +1 -0
  15. package/dist/{chunk-WOYUXVVQ.cjs → chunk-HITAN7JF.cjs} +4 -4
  16. package/dist/{chunk-WOYUXVVQ.cjs.map → chunk-HITAN7JF.cjs.map} +1 -1
  17. package/dist/{chunk-3VQYJBOI.js → chunk-HOXKR26S.js} +31 -4
  18. package/dist/chunk-HOXKR26S.js.map +1 -0
  19. package/dist/{chunk-KJ3QEKOJ.cjs → chunk-IPGKTUF7.cjs} +7 -33
  20. package/dist/chunk-IPGKTUF7.cjs.map +1 -0
  21. package/dist/{chunk-QDNXEB3T.js → chunk-KOSGX3UK.js} +5 -5
  22. package/dist/chunk-KOSGX3UK.js.map +1 -0
  23. package/dist/{chunk-ORA2XE7U.js → chunk-MK6NJQGF.js} +3 -3
  24. package/dist/{chunk-ORA2XE7U.js.map → chunk-MK6NJQGF.js.map} +1 -1
  25. package/dist/{chunk-GTNUQBXI.cjs → chunk-P2RBE3FD.cjs} +254 -102
  26. package/dist/chunk-P2RBE3FD.cjs.map +1 -0
  27. package/dist/{chunk-G5DP27DU.js → chunk-UIWLDSTF.js} +3 -29
  28. package/dist/chunk-UIWLDSTF.js.map +1 -0
  29. package/dist/{chunk-VRPRAU3J.js → chunk-WJEKRSPH.js} +3 -3
  30. package/dist/{chunk-VRPRAU3J.js.map → chunk-WJEKRSPH.js.map} +1 -1
  31. package/dist/{chunk-2P3T23C7.js → chunk-YWYVIQ7T.js} +256 -104
  32. package/dist/chunk-YWYVIQ7T.js.map +1 -0
  33. package/dist/connect/index.cjs +95 -36
  34. package/dist/connect/index.cjs.map +1 -1
  35. package/dist/connect/index.js +80 -21
  36. package/dist/connect/index.js.map +1 -1
  37. package/dist/connection/ConnectedWorkflowRunner.d.ts +5 -1
  38. package/dist/connection/useWorkflowThread.d.ts +4 -0
  39. package/dist/index.cjs +382 -382
  40. package/dist/index.js +6 -6
  41. package/dist/studio/index.cjs +4 -4
  42. package/dist/studio/index.js +3 -3
  43. package/dist/workflow-canvas/StepInspector.d.ts +11 -0
  44. package/dist/workflow-canvas/WorkflowCanvas.d.ts +6 -2
  45. package/dist/workflow-canvas/index.cjs +200 -90
  46. package/dist/workflow-canvas/index.cjs.map +1 -1
  47. package/dist/workflow-canvas/index.js +168 -58
  48. package/dist/workflow-canvas/index.js.map +1 -1
  49. package/dist/workflow-canvas/viewport.d.ts +47 -0
  50. package/package.json +4 -4
  51. package/dist/chunk-2P3T23C7.js.map +0 -1
  52. package/dist/chunk-3VQYJBOI.js.map +0 -1
  53. package/dist/chunk-G5DP27DU.js.map +0 -1
  54. package/dist/chunk-GTNUQBXI.cjs.map +0 -1
  55. package/dist/chunk-IUR565UW.cjs.map +0 -1
  56. package/dist/chunk-KJ3QEKOJ.cjs.map +0 -1
  57. package/dist/chunk-QDNXEB3T.js.map +0 -1
  58. package/dist/chunk-V3L5DONY.cjs.map +0 -1
@@ -2,10 +2,10 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkMUMH3Z6K_cjs = require('../chunk-MUMH3Z6K.cjs');
5
- var chunkIUR565UW_cjs = require('../chunk-IUR565UW.cjs');
5
+ var chunk5LP54CWR_cjs = require('../chunk-5LP54CWR.cjs');
6
6
  require('../chunk-YJQVLVBJ.cjs');
7
7
  require('../chunk-ZW6FPIFC.cjs');
8
- var chunkGTNUQBXI_cjs = require('../chunk-GTNUQBXI.cjs');
8
+ var chunkP2RBE3FD_cjs = require('../chunk-P2RBE3FD.cjs');
9
9
  require('../chunk-7RGLTF76.cjs');
10
10
  require('../chunk-3AFWGEDJ.cjs');
11
11
  require('../chunk-VFUWWH52.cjs');
@@ -15,7 +15,7 @@ require('../chunk-2EI7NCUA.cjs');
15
15
  require('../chunk-Z5VUZ6YD.cjs');
16
16
  require('../chunk-7D737FLE.cjs');
17
17
  require('../chunk-OB5F4577.cjs');
18
- require('../chunk-V3L5DONY.cjs');
18
+ require('../chunk-B4SRYJLM.cjs');
19
19
  require('../chunk-7UTB4PHM.cjs');
20
20
  require('../chunk-FX3K6LNZ.cjs');
21
21
  require('../chunk-PPCATBOY.cjs');
@@ -47,11 +47,11 @@ function withSteps(workflow, steps, layout) {
47
47
  const run = workflow.run.kind === "steps" ? workflow.run : { kind: "steps", steps: [] };
48
48
  return {
49
49
  ...workflow,
50
- run: { ...run, steps: chunkGTNUQBXI_cjs.orderSteps(steps), layout: layout ?? run.layout }
50
+ run: { ...run, steps: chunkP2RBE3FD_cjs.orderSteps(steps), layout: layout ?? run.layout }
51
51
  };
52
52
  }
53
53
  var layoutOf = (workflow) => workflow.run.kind === "steps" && workflow.run.layout || {};
54
- var explicit = (steps) => steps.map((s) => ({ ...s, after: chunkGTNUQBXI_cjs.stepDependencies(steps, s.id) }));
54
+ var explicit = (steps) => steps.map((s) => ({ ...s, after: chunkP2RBE3FD_cjs.stepDependencies(steps, s.id) }));
55
55
  function stepIdFor(steps, title) {
56
56
  const base = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/^[^a-z]+/, "") || "step";
57
57
  const taken = new Set(steps.map((s) => s.id));
@@ -73,13 +73,13 @@ function blankStep(kind, id, title) {
73
73
  case "upload":
74
74
  return { id, kind, title };
75
75
  case "agent":
76
- return { id, kind, title, run: { kind: "prompt", promptTemplate: "" } };
76
+ return { id, kind, title };
77
77
  case "review":
78
78
  return { id, kind, title, instructions: "" };
79
79
  }
80
80
  }
81
81
  function addStep(workflow, kind, options = {}) {
82
- const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
82
+ const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
83
83
  const title = options.title ?? DEFAULT_TITLES[kind];
84
84
  const id = stepIdFor(steps, title);
85
85
  const step = { ...blankStep(kind, id, title), after: options.after ? [options.after] : [] };
@@ -88,7 +88,7 @@ function addStep(workflow, kind, options = {}) {
88
88
  return { workflow: withSteps(workflow, [...steps, step], layout), id };
89
89
  }
90
90
  function removeStep(workflow, id) {
91
- const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
91
+ const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
92
92
  const removed = steps.find((s) => s.id === id);
93
93
  if (!removed) return workflow;
94
94
  const bridged = steps.filter((s) => s.id !== id).map(
@@ -101,8 +101,8 @@ function removeStep(workflow, id) {
101
101
  return withSteps(workflow, bridged, layout);
102
102
  }
103
103
  function connectSteps(workflow, from, to) {
104
- const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
105
- if (from === to || !steps.some((s) => s.id === from) || chunkGTNUQBXI_cjs.dependsOn(steps, from, to)) {
104
+ const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
105
+ if (from === to || !steps.some((s) => s.id === from) || chunkP2RBE3FD_cjs.dependsOn(steps, from, to)) {
106
106
  return workflow;
107
107
  }
108
108
  return withSteps(
@@ -112,16 +112,16 @@ function connectSteps(workflow, from, to) {
112
112
  )
113
113
  );
114
114
  }
115
- var wouldCycle = (workflow, from, to) => from === to || chunkGTNUQBXI_cjs.dependsOn(chunkGTNUQBXI_cjs.workflowSteps(workflow), from, to);
115
+ var wouldCycle = (workflow, from, to) => from === to || chunkP2RBE3FD_cjs.dependsOn(chunkP2RBE3FD_cjs.workflowSteps(workflow), from, to);
116
116
  function disconnectSteps(workflow, from, to) {
117
- const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
117
+ const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
118
118
  return withSteps(
119
119
  workflow,
120
120
  steps.map((s) => s.id === to ? { ...s, after: (s.after ?? []).filter((d) => d !== from) } : s)
121
121
  );
122
122
  }
123
123
  function updateStep(workflow, id, patch) {
124
- const steps = explicit(chunkGTNUQBXI_cjs.workflowSteps(workflow));
124
+ const steps = explicit(chunkP2RBE3FD_cjs.workflowSteps(workflow));
125
125
  return withSteps(
126
126
  workflow,
127
127
  steps.map(
@@ -135,7 +135,7 @@ var renameIn = (text, from, to) => text.replace(
135
135
  );
136
136
  function renameInput(workflow, from, to) {
137
137
  if (from === to) return workflow;
138
- const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow).map((s) => {
138
+ const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow).map((s) => {
139
139
  if (s.kind === "agent")
140
140
  return {
141
141
  ...s,
@@ -149,13 +149,13 @@ function renameInput(workflow, from, to) {
149
149
  return withSteps(workflow, steps);
150
150
  }
151
151
  function moveStep(workflow, id, position) {
152
- return withSteps(workflow, chunkGTNUQBXI_cjs.workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
152
+ return withSteps(workflow, chunkP2RBE3FD_cjs.workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
153
153
  }
154
154
  var COLUMN = 300;
155
155
  var ROW = 140;
156
156
  function autoLayout(steps) {
157
157
  const layout = {};
158
- chunkGTNUQBXI_cjs.stepLevels(steps).forEach(
158
+ chunkP2RBE3FD_cjs.stepLevels(steps).forEach(
159
159
  (level, x) => level.forEach((s, y) => {
160
160
  layout[s.id] = { x: x * COLUMN, y: (y - (level.length - 1) / 2) * ROW };
161
161
  })
@@ -163,7 +163,7 @@ function autoLayout(steps) {
163
163
  return layout;
164
164
  }
165
165
  function layoutWithDefaults(workflow) {
166
- const auto = autoLayout(chunkGTNUQBXI_cjs.workflowSteps(workflow));
166
+ const auto = autoLayout(chunkP2RBE3FD_cjs.workflowSteps(workflow));
167
167
  return { ...auto, ...layoutOf(workflow) };
168
168
  }
169
169
  var DEFAULT_STEP_INSPECTOR_LABELS = {
@@ -178,10 +178,13 @@ var DEFAULT_STEP_INSPECTOR_LABELS = {
178
178
  fieldType: "Type",
179
179
  required: "Required",
180
180
  runs: "Runs",
181
+ chooseRun: "Choose a skill or write an instruction\u2026",
181
182
  ownPrompt: "Its own instruction",
182
183
  prompt: "Instruction",
183
184
  promptHint: "Use {{field}} for an input and {{steps.<id>}} for an earlier step\u2019s answer.",
184
185
  inputFor: "Input",
186
+ inputHint: "Type a value, or use a field: {fields}",
187
+ inputHintNoFields: "Type a value, or add a form field to fill it from.",
185
188
  thread: "Where it runs",
186
189
  threadMain: "In the run\u2019s thread (sees the conversation so far)",
187
190
  threadBranch: "On a branch (delivers only its result to the thread)",
@@ -220,7 +223,7 @@ function StepInspector({
220
223
  testId = "step-inspector"
221
224
  }) {
222
225
  const l = { ...DEFAULT_STEP_INSPECTOR_LABELS, ...labels };
223
- const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
226
+ const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
224
227
  const step = steps.find((s) => s.id === stepId);
225
228
  const run = workflow.run.kind === "steps" ? workflow.run : void 0;
226
229
  if (!step || !run) {
@@ -245,7 +248,7 @@ function StepInspector({
245
248
  ] });
246
249
  }
247
250
  const patch = (p) => onChange(updateStep(workflow, step.id, p));
248
- const deps = chunkGTNUQBXI_cjs.stepDependencies(steps, step.id);
251
+ const deps = chunkP2RBE3FD_cjs.stepDependencies(steps, step.id);
249
252
  const titleOf = (id) => steps.find((s) => s.id === id)?.title ?? id;
250
253
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "data-testid": `${testId}-step`, children: [
251
254
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
@@ -329,7 +332,17 @@ function StepInspector({
329
332
  }
330
333
  ) })
331
334
  ] }),
332
- step.kind === "agent" && /* @__PURE__ */ jsxRuntime.jsx(AgentSettings, { step, workflows, patch, l, testId }),
335
+ step.kind === "agent" && /* @__PURE__ */ jsxRuntime.jsx(
336
+ AgentSettings,
337
+ {
338
+ step,
339
+ workflows,
340
+ fields: chunkP2RBE3FD_cjs.runFields(workflow).map((f) => f.name),
341
+ patch,
342
+ l,
343
+ testId
344
+ }
345
+ ),
333
346
  step.kind === "review" && /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsxRuntime.jsx(
334
347
  ui.Textarea,
335
348
  {
@@ -442,42 +455,77 @@ function FormFields({
442
455
  )
443
456
  ] }) });
444
457
  }
458
+ var OWN_PROMPT = "__prompt";
459
+ function prefillSkillInputs(target, fields, current = {}) {
460
+ const out = {};
461
+ for (const f of target?.inputs ?? []) {
462
+ const typed = current[f.name];
463
+ if (typed) out[f.name] = typed;
464
+ else if (fields.includes(f.name)) out[f.name] = `{{${f.name}}}`;
465
+ }
466
+ return out;
467
+ }
445
468
  function AgentSettings({
446
469
  step,
447
470
  workflows,
471
+ fields,
448
472
  patch,
449
473
  l,
450
474
  testId
451
475
  }) {
452
476
  const target = step.workflow ? workflows.find((w) => w.id === step.workflow) : void 0;
477
+ const value = step.workflow ?? (step.run ? OWN_PROMPT : "");
478
+ const codes = fields.map((f) => `{{${f}}}`).join(", ");
453
479
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
454
480
  /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.runs, children: /* @__PURE__ */ jsxRuntime.jsxs(
455
481
  "select",
456
482
  {
457
483
  className: selectClass,
458
- value: step.workflow ?? "",
459
- onChange: (e) => e.target.value ? patch({ workflow: e.target.value, run: void 0, with: step.with ?? {} }) : patch({
460
- workflow: void 0,
461
- with: void 0,
462
- run: { kind: "prompt", promptTemplate: "" }
463
- }),
484
+ value,
485
+ onChange: (e) => {
486
+ const id = e.target.value;
487
+ if (id === OWN_PROMPT)
488
+ patch({
489
+ workflow: void 0,
490
+ with: void 0,
491
+ run: { kind: "prompt", promptTemplate: "" }
492
+ });
493
+ else if (id)
494
+ patch({
495
+ workflow: id,
496
+ run: void 0,
497
+ with: prefillSkillInputs(
498
+ workflows.find((w) => w.id === id),
499
+ fields,
500
+ step.with
501
+ )
502
+ });
503
+ },
464
504
  "data-testid": `${testId}-runs`,
465
505
  children: [
466
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.ownPrompt }),
506
+ !value && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: l.chooseRun }),
507
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: OWN_PROMPT, children: l.ownPrompt }),
467
508
  workflows.map((w) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: w.id, children: w.title }, w.id)),
468
509
  step.workflow && !target && /* @__PURE__ */ jsxRuntime.jsx("option", { value: step.workflow, children: step.workflow })
469
510
  ]
470
511
  }
471
512
  ) }),
472
- step.workflow ? (target?.inputs ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsx(Field, { label: `${l.inputFor}: ${f.label}`, children: /* @__PURE__ */ jsxRuntime.jsx(
473
- ui.Input,
513
+ step.workflow ? (target?.inputs ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsx(
514
+ Field,
474
515
  {
475
- value: step.with?.[f.name] ?? "",
476
- placeholder: `{{${f.name}}}`,
477
- onChange: (e) => patch({ with: { ...step.with, [f.name]: e.target.value } }),
478
- "data-testid": `${testId}-with-${f.name}`
479
- }
480
- ) }, f.name)) : step.run?.kind === "prompt" ? /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.prompt, hint: l.promptHint, children: /* @__PURE__ */ jsxRuntime.jsx(
516
+ label: `${l.inputFor}: ${f.label}`,
517
+ hint: step.with?.[f.name] ? void 0 : codes ? l.inputHint.replace("{fields}", codes) : l.inputHintNoFields,
518
+ children: /* @__PURE__ */ jsxRuntime.jsx(
519
+ ui.Input,
520
+ {
521
+ value: step.with?.[f.name] ?? "",
522
+ onChange: (e) => patch({ with: { ...step.with, [f.name]: e.target.value } }),
523
+ "data-testid": `${testId}-with-${f.name}`
524
+ }
525
+ )
526
+ },
527
+ f.name
528
+ )) : step.run?.kind === "prompt" ? /* @__PURE__ */ jsxRuntime.jsx(Field, { label: l.prompt, hint: l.promptHint, children: /* @__PURE__ */ jsxRuntime.jsx(
481
529
  ui.Textarea,
482
530
  {
483
531
  value: step.run.promptTemplate,
@@ -539,7 +587,7 @@ function triggerSummary(trigger, options = {}) {
539
587
  case "once":
540
588
  return trigger.runAt ? new Date(trigger.runAt).toLocaleString() : l.starts.once;
541
589
  case "repeat":
542
- return trigger.rrule ? chunkIUR565UW_cjs.describeRRule(trigger.rrule) : l.starts.repeat;
590
+ return trigger.rrule ? chunk5LP54CWR_cjs.describeRRule(trigger.rrule) : l.starts.repeat;
543
591
  case "event":
544
592
  return trigger.eventKind && options.eventLabel?.(trigger.eventKind) || trigger.eventKind || l.starts.event;
545
593
  case "task":
@@ -594,7 +642,7 @@ function TriggerInspector({
594
642
  }
595
643
  )
596
644
  ] }),
597
- trigger.start === "repeat" && /* @__PURE__ */ jsxRuntime.jsx(chunkIUR565UW_cjs.RecurrenceBuilder, { rrule: trigger.rrule, onChange: (rrule) => set({ rrule }) }),
645
+ trigger.start === "repeat" && /* @__PURE__ */ jsxRuntime.jsx(chunk5LP54CWR_cjs.RecurrenceBuilder, { rrule: trigger.rrule, onChange: (rrule) => set({ rrule }) }),
598
646
  trigger.start === "event" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
599
647
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.event }),
600
648
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -630,7 +678,7 @@ function TriggerInspector({
630
678
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
631
679
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "text-xs", children: l.agent }),
632
680
  /* @__PURE__ */ jsxRuntime.jsx(
633
- chunkIUR565UW_cjs.AgentSelect,
681
+ chunk5LP54CWR_cjs.AgentSelect,
634
682
  {
635
683
  agents,
636
684
  value: trigger.agentId,
@@ -658,6 +706,45 @@ function TriggerInspector({
658
706
  ] })
659
707
  ] });
660
708
  }
709
+
710
+ // src/workflow-canvas/viewport.ts
711
+ var READABLE_ZOOM = 0.7;
712
+ var DEFAULT_W = 256;
713
+ var DEFAULT_H = 80;
714
+ var MARGIN = 48;
715
+ var sizeOf = (n) => ({
716
+ w: n.measured?.width ?? DEFAULT_W,
717
+ h: n.measured?.height ?? DEFAULT_H
718
+ });
719
+ function readableViewport(nodes, fittedZoom, frame, {
720
+ anchor,
721
+ centre = false,
722
+ reserveRight = 0
723
+ } = {}) {
724
+ if (fittedZoom >= READABLE_ZOOM || !frame.height || nodes.length === 0) return null;
725
+ const z = READABLE_ZOOM;
726
+ const at = nodes.find((n) => n.id === anchor) ?? nodes.reduce((a, b) => b.position.x < a.position.x ? b : a);
727
+ const { w, h } = sizeOf(at);
728
+ const y = frame.height / 2 - (at.position.y + h / 2) * z;
729
+ if (centre && at.id === anchor) {
730
+ const visible = Math.max(0, frame.width - reserveRight);
731
+ return { x: visible / 2 - (at.position.x + w / 2) * z, y, zoom: z };
732
+ }
733
+ return { x: MARGIN - at.position.x * z, y, zoom: z };
734
+ }
735
+ function revealCenter(node, view, frame, reserveRight = 0) {
736
+ const { w, h } = sizeOf(node);
737
+ const { x, y, zoom } = view;
738
+ const left = node.position.x * zoom + x;
739
+ const top = node.position.y * zoom + y;
740
+ const right = frame.width - reserveRight;
741
+ if (left >= 16 && top >= 16 && left + w * zoom <= right - 16 && top + h * zoom <= frame.height - 16)
742
+ return null;
743
+ return {
744
+ x: node.position.x + w / 2 + reserveRight / 2 / zoom,
745
+ y: node.position.y + h / 2
746
+ };
747
+ }
661
748
  var DEFAULT_WORKFLOW_CANVAS_LABELS = {
662
749
  form: "Form",
663
750
  upload: "Upload",
@@ -672,12 +759,13 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
672
759
  },
673
760
  addNext: "Add the next step",
674
761
  runs: "Runs \u201C{name}\u201D",
675
- instruction: "No instruction yet",
762
+ chooseRun: "Choose a skill or write an instruction",
676
763
  fields: "{count} fields",
677
764
  noFields: "No fields yet",
678
765
  approvedBy: "A person approves",
679
766
  emptyTitle: "Start your workflow",
680
- emptyHint: "Add the first step: what should happen when it starts?"
767
+ emptyHint: "Add the first step: what should happen when it starts?",
768
+ fitView: "Fit view"
681
769
  };
682
770
  var TRIGGER_NODE = "__trigger";
683
771
  var STEP_KIND_ICONS = {
@@ -802,7 +890,6 @@ function TriggerNode({ data }) {
802
890
  );
803
891
  }
804
892
  var NODE_TYPES = { step: StepNode, trigger: TriggerNode };
805
- var READABLE_ZOOM = 0.7;
806
893
  var firstWords = (text, n = 14) => {
807
894
  const words = text.trim().split(/\s+/);
808
895
  return words.length > n ? `${words.slice(0, n).join(" ")}\u2026` : text.trim();
@@ -813,7 +900,8 @@ function summaryOf(step, l, workflowTitle) {
813
900
  case "agent":
814
901
  if (step.workflow)
815
902
  return l.runs.replace("{name}", workflowTitle?.(step.workflow) ?? step.workflow);
816
- return step.run?.kind === "prompt" && step.run.promptTemplate.trim() ? firstWords(step.run.promptTemplate) : l.instruction;
903
+ if (step.run?.kind === "operation") return void 0;
904
+ return step.run?.kind === "prompt" && step.run.promptTemplate.trim() ? firstWords(step.run.promptTemplate) : l.chooseRun;
817
905
  case "form":
818
906
  return step.inputs.length ? step.inputs.length === 1 ? step.inputs[0].label : l.fields.replace("{count}", String(step.inputs.length)) : l.noFields;
819
907
  case "upload":
@@ -827,6 +915,7 @@ function WorkflowCanvas({
827
915
  onChange,
828
916
  selected = null,
829
917
  onSelect,
918
+ focus,
830
919
  onAddAfter,
831
920
  phases,
832
921
  workflowTitle,
@@ -838,12 +927,12 @@ function WorkflowCanvas({
838
927
  testId = "workflow-canvas"
839
928
  }) {
840
929
  const l = react.useMemo(() => ({ ...DEFAULT_WORKFLOW_CANVAS_LABELS, ...labels }), [labels]);
841
- const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
930
+ const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
842
931
  const editable = !!onChange;
843
932
  const built = react.useMemo(() => {
844
933
  const layout = layoutWithDefaults(workflow);
845
- const all = chunkGTNUQBXI_cjs.workflowSteps(workflow);
846
- const roots = all.filter((s) => chunkGTNUQBXI_cjs.stepDependencies(all, s.id).length === 0);
934
+ const all = chunkP2RBE3FD_cjs.workflowSteps(workflow);
935
+ const roots = all.filter((s) => chunkP2RBE3FD_cjs.stepDependencies(all, s.id).length === 0);
847
936
  const triggerNode = trigger ? [
848
937
  {
849
938
  id: TRIGGER_NODE,
@@ -880,7 +969,7 @@ function WorkflowCanvas({
880
969
  react.useEffect(() => setNodes(built), [built]);
881
970
  const edges = react.useMemo(
882
971
  () => steps.flatMap((s) => {
883
- const deps = chunkGTNUQBXI_cjs.stepDependencies(steps, s.id);
972
+ const deps = chunkP2RBE3FD_cjs.stepDependencies(steps, s.id);
884
973
  const from = deps.length ? deps : trigger ? [TRIGGER_NODE] : [];
885
974
  return from.map((d) => ({
886
975
  id: `${d}->${s.id}`,
@@ -918,46 +1007,57 @@ function WorkflowCanvas({
918
1007
  );
919
1008
  const frame = react.useRef(null);
920
1009
  const flowRef = react.useRef(null);
921
- const onInit = react.useCallback(
922
- async (flow) => {
923
- flowRef.current = flow;
1010
+ const hasTrigger = !!trigger;
1011
+ const selectedRef = react.useRef(selected);
1012
+ selectedRef.current = selected;
1013
+ const fit = react.useCallback(
1014
+ async (flow, anchorOnSelection) => {
924
1015
  await flow.fitView({
925
1016
  padding: { top: "48px", bottom: "48px", left: "48px", right: `${reserveRight + 48}px` },
926
1017
  maxZoom: 1
927
1018
  });
928
- const height = frame.current?.clientHeight;
929
- const shown = flow.getNodes();
930
- if (flow.getZoom() >= READABLE_ZOOM || !height || !shown.length) return;
931
- const left = Math.min(...shown.map((n) => n.position.x));
932
- const ys = shown.map((n) => n.position.y + (n.measured?.height ?? 0) / 2);
933
- const middle = (Math.min(...ys) + Math.max(...ys)) / 2;
934
- flow.setViewport({
935
- x: 48 - left * READABLE_ZOOM,
936
- y: height / 2 - middle * READABLE_ZOOM,
937
- zoom: READABLE_ZOOM
938
- });
1019
+ const box = frame.current;
1020
+ const picked = anchorOnSelection ? selectedRef.current : null;
1021
+ const view = readableViewport(
1022
+ flow.getNodes(),
1023
+ flow.getZoom(),
1024
+ { width: box?.clientWidth ?? 0, height: box?.clientHeight ?? 0 },
1025
+ {
1026
+ anchor: picked ?? (hasTrigger ? TRIGGER_NODE : null),
1027
+ centre: !!picked,
1028
+ reserveRight
1029
+ }
1030
+ );
1031
+ if (view) await flow.setViewport(view);
1032
+ },
1033
+ [reserveRight, hasTrigger]
1034
+ );
1035
+ const onInit = react.useCallback(
1036
+ async (flow) => {
1037
+ flowRef.current = flow;
1038
+ await fit(flow, false);
939
1039
  },
940
- [reserveRight]
1040
+ [fit]
941
1041
  );
1042
+ const target = focus ?? selected;
1043
+ const revealed = react.useRef(null);
942
1044
  react.useEffect(() => {
943
1045
  const flow = flowRef.current;
944
1046
  const box = frame.current;
945
- const node = selected ? flow?.getNode(selected) : void 0;
946
- if (!flow || !box || !node) return;
947
- const { x, y, zoom } = flow.getViewport();
948
- const w = (node.measured?.width ?? 256) * zoom;
949
- const h = (node.measured?.height ?? 80) * zoom;
950
- const left = node.position.x * zoom + x;
951
- const top = node.position.y * zoom + y;
952
- const right = box.clientWidth - reserveRight;
953
- if (left >= 16 && top >= 16 && left + w <= right - 16 && top + h <= box.clientHeight - 16)
954
- return;
955
- void flow.setCenter(
956
- node.position.x + (node.measured?.width ?? 256) / 2 + reserveRight / 2 / zoom,
957
- node.position.y + (node.measured?.height ?? 80) / 2,
958
- { zoom, duration: 250 }
1047
+ const node = target ? flow?.getNode(target) : void 0;
1048
+ const key = `${target}:${reserveRight}`;
1049
+ if (!target) revealed.current = null;
1050
+ if (!flow || !box || !node || revealed.current === key) return;
1051
+ revealed.current = key;
1052
+ const view = flow.getViewport();
1053
+ const centre = revealCenter(
1054
+ node,
1055
+ view,
1056
+ { width: box.clientWidth, height: box.clientHeight },
1057
+ reserveRight
959
1058
  );
960
- }, [selected, nodes, reserveRight]);
1059
+ if (centre) void flow.setCenter(centre.x, centre.y, { zoom: view.zoom, duration: 250 });
1060
+ }, [target, nodes, reserveRight]);
961
1061
  const onDelete = react.useCallback(
962
1062
  ({ nodes: gone, edges: cut }) => {
963
1063
  if (!onChange) return;
@@ -999,12 +1099,21 @@ function WorkflowCanvas({
999
1099
  elementsSelectable: true,
1000
1100
  deleteKeyCode: editable ? ["Backspace", "Delete"] : null,
1001
1101
  onInit,
1002
- fitViewOptions: { padding: 0.2, maxZoom: 1 },
1003
1102
  minZoom: 0.3,
1004
1103
  proOptions: { hideAttribution: true },
1005
1104
  children: [
1006
1105
  /* @__PURE__ */ jsxRuntime.jsx(react$1.Background, { variant: react$1.BackgroundVariant.Dots, gap: 18, size: 1.5 }),
1007
- /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false, position: "bottom-left" }),
1106
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false, showFitView: false, position: "bottom-left", children: /* @__PURE__ */ jsxRuntime.jsx(
1107
+ react$1.ControlButton,
1108
+ {
1109
+ className: "react-flow__controls-fitview",
1110
+ onClick: () => flowRef.current && void fit(flowRef.current, true),
1111
+ title: l.fitView,
1112
+ "aria-label": l.fitView,
1113
+ "data-testid": `${testId}-fit`,
1114
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, {})
1115
+ }
1116
+ ) }),
1008
1117
  steps.length > 3 && /* @__PURE__ */ jsxRuntime.jsx(
1009
1118
  react$1.MiniMap,
1010
1119
  {
@@ -1100,8 +1209,8 @@ function WorkflowBuilder({
1100
1209
  const [mode, setMode] = react.useState("design");
1101
1210
  const [adding, setAdding] = react.useState(false);
1102
1211
  const { workflow, trigger } = value;
1103
- const steps = chunkGTNUQBXI_cjs.workflowSteps(workflow);
1104
- const problems = chunkGTNUQBXI_cjs.validateWorkflowGraph(steps);
1212
+ const steps = chunkP2RBE3FD_cjs.workflowSteps(workflow);
1213
+ const problems = chunkP2RBE3FD_cjs.validateWorkflowGraph(steps);
1105
1214
  const titles = react.useMemo(() => new Map(workflows.map((w) => [w.id, w.title])), [workflows]);
1106
1215
  const setWorkflow = (next) => onChange({ ...value, workflow: next });
1107
1216
  const addAfter = (from, kind) => {
@@ -1226,6 +1335,7 @@ function WorkflowBuilder({
1226
1335
  onChange: setWorkflow,
1227
1336
  selected,
1228
1337
  onSelect: setSelected,
1338
+ focus: selected ?? (panelOpen ? TRIGGER_NODE : null),
1229
1339
  onAddAfter: addAfter,
1230
1340
  trigger: { title: l.start, summary },
1231
1341
  workflowTitle: (id) => titles.get(id),
@@ -1315,13 +1425,13 @@ function WorkflowPreview({
1315
1425
  renderIcon,
1316
1426
  testId
1317
1427
  }) {
1318
- const run = chunkIUR565UW_cjs.useWorkflowPreview(workflow, {
1428
+ const run = chunk5LP54CWR_cjs.useWorkflowPreview(workflow, {
1319
1429
  resolveWorkflow: (id) => workflows.find((w) => w.id === id),
1320
1430
  compose,
1321
1431
  answer
1322
1432
  });
1323
1433
  return /* @__PURE__ */ jsxRuntime.jsx(
1324
- chunkGTNUQBXI_cjs.WorkflowRunner,
1434
+ chunkP2RBE3FD_cjs.WorkflowRunner,
1325
1435
  {
1326
1436
  workflow,
1327
1437
  run,
@@ -1362,7 +1472,7 @@ function triggerFields(trigger, clearOthers) {
1362
1472
  return {
1363
1473
  timezone: trigger.timezone,
1364
1474
  rrule: trigger.start === "repeat" ? trigger.rrule.trim() : none,
1365
- run_at: trigger.start === "once" ? chunkIUR565UW_cjs.localInputToIso(trigger.runAt) : none,
1475
+ run_at: trigger.start === "once" ? chunk5LP54CWR_cjs.localInputToIso(trigger.runAt) : none,
1366
1476
  event_kind: trigger.start === "event" ? trigger.eventKind.trim() : none,
1367
1477
  after_conversation_ext_id: trigger.start === "task" ? trigger.afterTaskId : none,
1368
1478
  on_demand: trigger.start === "manual"
@@ -1376,7 +1486,7 @@ function plan(value, options) {
1376
1486
  criteria: [],
1377
1487
  max_passes: 3,
1378
1488
  documents: [],
1379
- steps: chunkGTNUQBXI_cjs.toPlanSteps(value.workflow, options)
1489
+ steps: chunkP2RBE3FD_cjs.toPlanSteps(value.workflow, options)
1380
1490
  };
1381
1491
  }
1382
1492
  function builderToWorkflowRequest(value, workspaceId, options = {}) {
@@ -1411,7 +1521,7 @@ function builderToWorkflowUpdate(value, options = {}) {
1411
1521
  }
1412
1522
  function workflowRecordToBuilder(record) {
1413
1523
  const planned = record.plan?.steps ?? [];
1414
- const steps = planned.length ? chunkGTNUQBXI_cjs.fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1524
+ const steps = planned.length ? chunkP2RBE3FD_cjs.fromPlanSteps(planned) : record.prompt || record.skill_ref ? [
1415
1525
  {
1416
1526
  id: "work",
1417
1527
  kind: "agent",
@@ -1419,7 +1529,7 @@ function workflowRecordToBuilder(record) {
1419
1529
  ...record.skill_ref ? { workflow: record.skill_ref } : { run: { kind: "prompt", promptTemplate: record.prompt } }
1420
1530
  }
1421
1531
  ] : [];
1422
- const when = chunkIUR565UW_cjs.workflowWhen(record);
1532
+ const when = chunk5LP54CWR_cjs.workflowWhen(record);
1423
1533
  return {
1424
1534
  workflow: {
1425
1535
  id: record.external_id,
@@ -1428,12 +1538,12 @@ function workflowRecordToBuilder(record) {
1428
1538
  inputs: [],
1429
1539
  landing: "chat",
1430
1540
  schedulable: false,
1431
- run: { kind: "steps", steps, layout: chunkGTNUQBXI_cjs.layoutFromPlanSteps(planned ?? []) }
1541
+ run: { kind: "steps", steps, layout: chunkP2RBE3FD_cjs.layoutFromPlanSteps(planned ?? []) }
1432
1542
  },
1433
1543
  trigger: {
1434
1544
  ...DEFAULT_WORKFLOW_TRIGGER,
1435
1545
  start: when === "now" ? "manual" : when,
1436
- runAt: chunkIUR565UW_cjs.isoToLocalInput(record.run_at),
1546
+ runAt: chunk5LP54CWR_cjs.isoToLocalInput(record.run_at),
1437
1547
  rrule: record.rrule ?? "",
1438
1548
  timezone: record.timezone || DEFAULT_WORKFLOW_TRIGGER.timezone,
1439
1549
  eventKind: record.event_kind ?? "",
@@ -1494,7 +1604,7 @@ function ConnectedWorkflowBuilder({
1494
1604
  () => [
1495
1605
  ...hostWorkflows,
1496
1606
  ...(skills.data ?? []).map(
1497
- (s) => chunkGTNUQBXI_cjs.skillToWorkflow({
1607
+ (s) => chunkP2RBE3FD_cjs.skillToWorkflow({
1498
1608
  name: s.name,
1499
1609
  slug: s.slug,
1500
1610
  description: s.description,
@@ -1510,7 +1620,7 @@ function ConnectedWorkflowBuilder({
1510
1620
  }));
1511
1621
  const tasks = (conversations.data ?? []).filter((c) => c.status && c.status !== "done").map((c) => ({ value: c.external_id, label: c.title || c.external_id }));
1512
1622
  const options = { resolveWorkflow: (wid) => workflows.find((w) => w.id === wid), compose };
1513
- const problem = triggerProblem(value.trigger) ?? (chunkGTNUQBXI_cjs.validateWorkflowGraph(chunkGTNUQBXI_cjs.workflowSteps(value.workflow)).length ? "graph" : null);
1623
+ const problem = triggerProblem(value.trigger) ?? (chunkP2RBE3FD_cjs.validateWorkflowGraph(chunkP2RBE3FD_cjs.workflowSteps(value.workflow)).length ? "graph" : null);
1514
1624
  const busy = create.isPending || update.isPending || run.isPending;
1515
1625
  const save = async () => {
1516
1626
  if (!workspaceId) return void 0;