@arbidocs/blocks 0.4.135 → 0.4.137

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 (123) hide show
  1. package/dist/agents/index.cjs +422 -367
  2. package/dist/agents/index.js +8 -9
  3. package/dist/agents/skills/index.d.ts +2 -0
  4. package/dist/agents/skills/skillFiles.d.ts +65 -0
  5. package/dist/agents/skills/skillImport.d.ts +36 -0
  6. package/dist/agents/workflows/WorkflowDocumentsField.d.ts +42 -5
  7. package/dist/agents/workflows/index.d.ts +3 -3
  8. package/dist/agents/workflows/workflow.d.ts +19 -0
  9. package/dist/agents/workflows/workspaceScope.d.ts +12 -0
  10. package/dist/chat/index.cjs +138 -138
  11. package/dist/chat/index.js +3 -3
  12. package/dist/chunk-2KUCVSFF.js +51 -0
  13. package/dist/chunk-2KUCVSFF.js.map +1 -0
  14. package/dist/{chunk-GDBDHOI4.js → chunk-3RJN2VTL.js} +36 -6
  15. package/dist/chunk-3RJN2VTL.js.map +1 -0
  16. package/dist/{chunk-6AALMYPS.cjs → chunk-6F7SZCVL.cjs} +23 -2
  17. package/dist/chunk-6F7SZCVL.cjs.map +1 -0
  18. package/dist/{chunk-PUCY3UXN.js → chunk-7M4C6CK7.js} +3 -3
  19. package/dist/{chunk-PUCY3UXN.js.map → chunk-7M4C6CK7.js.map} +1 -1
  20. package/dist/{chunk-2PNNCEPH.js → chunk-ATJUVHVB.js} +1545 -8
  21. package/dist/chunk-ATJUVHVB.js.map +1 -0
  22. package/dist/{chunk-4S5IDT5F.cjs → chunk-BUNZWOPX.cjs} +5 -5
  23. package/dist/{chunk-4S5IDT5F.cjs.map → chunk-BUNZWOPX.cjs.map} +1 -1
  24. package/dist/{chunk-KYDRUFWT.cjs → chunk-C3ZRLULA.cjs} +5 -5
  25. package/dist/{chunk-KYDRUFWT.cjs.map → chunk-C3ZRLULA.cjs.map} +1 -1
  26. package/dist/{chunk-SARREDFP.cjs → chunk-CHVCTKF4.cjs} +1620 -47
  27. package/dist/chunk-CHVCTKF4.cjs.map +1 -0
  28. package/dist/chunk-CQCC7LE7.js +210 -0
  29. package/dist/chunk-CQCC7LE7.js.map +1 -0
  30. package/dist/{chunk-4UMXQPNA.js → chunk-E5OYHJMU.js} +3 -3
  31. package/dist/{chunk-4UMXQPNA.js.map → chunk-E5OYHJMU.js.map} +1 -1
  32. package/dist/{chunk-PJJY6CYL.cjs → chunk-EHOPZBAX.cjs} +11 -11
  33. package/dist/{chunk-PJJY6CYL.cjs.map → chunk-EHOPZBAX.cjs.map} +1 -1
  34. package/dist/{chunk-4QIIDXLF.cjs → chunk-HDYWXEQU.cjs} +8 -8
  35. package/dist/{chunk-4QIIDXLF.cjs.map → chunk-HDYWXEQU.cjs.map} +1 -1
  36. package/dist/{chunk-GZPTWHP5.cjs → chunk-HLB4DIYV.cjs} +5 -5
  37. package/dist/{chunk-GZPTWHP5.cjs.map → chunk-HLB4DIYV.cjs.map} +1 -1
  38. package/dist/{chunk-TT6XV6WM.cjs → chunk-JY73DJOS.cjs} +78 -1274
  39. package/dist/chunk-JY73DJOS.cjs.map +1 -0
  40. package/dist/{chunk-ARDHLU73.cjs → chunk-KDUGTKVI.cjs} +21 -2
  41. package/dist/chunk-KDUGTKVI.cjs.map +1 -0
  42. package/dist/{chunk-UMIY4SQS.js → chunk-KMNZ2RVO.js} +17 -1191
  43. package/dist/chunk-KMNZ2RVO.js.map +1 -0
  44. package/dist/{chunk-6S5FLMWG.js → chunk-KSHKTOY2.js} +203 -7
  45. package/dist/chunk-KSHKTOY2.js.map +1 -0
  46. package/dist/{chunk-4RLCRFZS.js → chunk-L2PAPOZ5.js} +21 -3
  47. package/dist/chunk-L2PAPOZ5.js.map +1 -0
  48. package/dist/{chunk-QYTYW74G.js → chunk-L3T7OJRX.js} +4 -4
  49. package/dist/{chunk-QYTYW74G.js.map → chunk-L3T7OJRX.js.map} +1 -1
  50. package/dist/{chunk-ENDP7JER.js → chunk-M33QUNFH.js} +3 -3
  51. package/dist/{chunk-ENDP7JER.js.map → chunk-M33QUNFH.js.map} +1 -1
  52. package/dist/chunk-RFIBUWLF.cjs +232 -0
  53. package/dist/chunk-RFIBUWLF.cjs.map +1 -0
  54. package/dist/{chunk-N26CXGXC.cjs → chunk-RQ2Y7USX.cjs} +201 -3
  55. package/dist/chunk-RQ2Y7USX.cjs.map +1 -0
  56. package/dist/chunk-UUHUQHXR.cjs +56 -0
  57. package/dist/chunk-UUHUQHXR.cjs.map +1 -0
  58. package/dist/{chunk-SZX44LCT.js → chunk-VMESMX7N.js} +3 -3
  59. package/dist/{chunk-SZX44LCT.js.map → chunk-VMESMX7N.js.map} +1 -1
  60. package/dist/{chunk-QDEODGXE.cjs → chunk-WS5EX7DN.cjs} +37 -6
  61. package/dist/chunk-WS5EX7DN.cjs.map +1 -0
  62. package/dist/{chunk-2DFDFOM7.js → chunk-YOMPLCP6.js} +22 -3
  63. package/dist/chunk-YOMPLCP6.js.map +1 -0
  64. package/dist/connect/docx.cjs +4 -4
  65. package/dist/connect/docx.js +3 -3
  66. package/dist/connect/index.cjs +463 -97
  67. package/dist/connect/index.cjs.map +1 -1
  68. package/dist/connect/index.d.ts +5 -2
  69. package/dist/connect/index.js +387 -49
  70. package/dist/connect/index.js.map +1 -1
  71. package/dist/connection/ConnectedSkillUpload.d.ts +26 -2
  72. package/dist/connection/ConnectedWorkflowBuilder.d.ts +24 -12
  73. package/dist/connection/ConnectedWorkflowLauncher.d.ts +35 -0
  74. package/dist/connection/ConnectedWorkflowsTable.d.ts +62 -0
  75. package/dist/connection/ConnectionProvider.d.ts +17 -0
  76. package/dist/connection/workspaceData.d.ts +45 -0
  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 +20 -21
  82. package/dist/home/index.cjs.map +1 -1
  83. package/dist/home/index.js +2 -3
  84. package/dist/home/index.js.map +1 -1
  85. package/dist/index.cjs +610 -555
  86. package/dist/index.cjs.map +1 -1
  87. package/dist/index.js +14 -15
  88. package/dist/index.js.map +1 -1
  89. package/dist/settings/index.cjs +11 -11
  90. package/dist/settings/index.js +2 -2
  91. package/dist/shell/index.cjs +1 -1
  92. package/dist/shell/index.js +1 -1
  93. package/dist/site/index.cjs +5 -5
  94. package/dist/site/index.js +1 -1
  95. package/dist/studio/index.cjs +7 -7
  96. package/dist/studio/index.js +5 -5
  97. package/dist/workflow-canvas/index.cjs +122 -96
  98. package/dist/workflow-canvas/index.cjs.map +1 -1
  99. package/dist/workflow-canvas/index.d.ts +1 -1
  100. package/dist/workflow-canvas/index.js +73 -48
  101. package/dist/workflow-canvas/index.js.map +1 -1
  102. package/node_modules/@arbidocs/coedit/package.json +1 -1
  103. package/package.json +4 -4
  104. package/dist/chunk-2DFDFOM7.js.map +0 -1
  105. package/dist/chunk-2PNNCEPH.js.map +0 -1
  106. package/dist/chunk-4RLCRFZS.js.map +0 -1
  107. package/dist/chunk-4XJZ6AAY.js +0 -407
  108. package/dist/chunk-4XJZ6AAY.js.map +0 -1
  109. package/dist/chunk-6AALMYPS.cjs.map +0 -1
  110. package/dist/chunk-6S5FLMWG.js.map +0 -1
  111. package/dist/chunk-7D737FLE.cjs +0 -43
  112. package/dist/chunk-7D737FLE.cjs.map +0 -1
  113. package/dist/chunk-ARDHLU73.cjs.map +0 -1
  114. package/dist/chunk-GDBDHOI4.js.map +0 -1
  115. package/dist/chunk-N26CXGXC.cjs.map +0 -1
  116. package/dist/chunk-QDEODGXE.cjs.map +0 -1
  117. package/dist/chunk-S5HZBXZA.cjs +0 -430
  118. package/dist/chunk-S5HZBXZA.cjs.map +0 -1
  119. package/dist/chunk-SARREDFP.cjs.map +0 -1
  120. package/dist/chunk-TT6XV6WM.cjs.map +0 -1
  121. package/dist/chunk-UMIY4SQS.js.map +0 -1
  122. package/dist/chunk-XD2M6LIG.js +0 -41
  123. package/dist/chunk-XD2M6LIG.js.map +0 -1
@@ -2,14 +2,22 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkDETZZBG2_cjs = require('./chunk-DETZZBG2.cjs');
5
- var chunk7D737FLE_cjs = require('./chunk-7D737FLE.cjs');
6
- var chunk6AALMYPS_cjs = require('./chunk-6AALMYPS.cjs');
5
+ var chunkRQ2Y7USX_cjs = require('./chunk-RQ2Y7USX.cjs');
6
+ var chunkZW6FPIFC_cjs = require('./chunk-ZW6FPIFC.cjs');
7
+ var chunkWS5EX7DN_cjs = require('./chunk-WS5EX7DN.cjs');
8
+ var chunkV4ISCZJ7_cjs = require('./chunk-V4ISCZJ7.cjs');
9
+ var chunk2EI7NCUA_cjs = require('./chunk-2EI7NCUA.cjs');
10
+ var chunkC2CWWEHO_cjs = require('./chunk-C2CWWEHO.cjs');
11
+ var chunk7RGLTF76_cjs = require('./chunk-7RGLTF76.cjs');
12
+ var chunk6F7SZCVL_cjs = require('./chunk-6F7SZCVL.cjs');
7
13
  var chunk32HW2Q33_cjs = require('./chunk-32HW2Q33.cjs');
8
14
  var chunkMHVNT4J3_cjs = require('./chunk-MHVNT4J3.cjs');
15
+ var chunkKDG6FER6_cjs = require('./chunk-KDG6FER6.cjs');
9
16
  var react = require('react');
10
17
  var lucideReact = require('lucide-react');
11
18
  var ui = require('@arbidocs/react/ui');
12
19
  var jsxRuntime = require('react/jsx-runtime');
20
+ var fflate = require('fflate');
13
21
 
14
22
  var DEFAULT_SCHEMA_FORM_LABELS = {
15
23
  optional: "(optional)",
@@ -147,11 +155,11 @@ function FieldControl({
147
155
  ] });
148
156
  }
149
157
  case "scope": {
150
- const scope = chunk6AALMYPS_cjs.isWorkflowScope(value) ? value : { folders: [], labels: [] };
158
+ const scope = chunk6F7SZCVL_cjs.isWorkflowScope(value) ? value : { folders: [], labels: [] };
151
159
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderScope?.(field, scope, onChange) });
152
160
  }
153
161
  case "documents": {
154
- const picked = chunk6AALMYPS_cjs.isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
162
+ const picked = chunk6F7SZCVL_cjs.isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
155
163
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
156
164
  }
157
165
  case "person":
@@ -309,7 +317,7 @@ function SchemaForm({
309
317
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-4", className), "data-slot": "schema-form", children: [
310
318
  common.map(render),
311
319
  advanced.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
312
- chunk7D737FLE_cjs.FoldSection,
320
+ chunkWS5EX7DN_cjs.FoldSection,
313
321
  {
314
322
  label: l.advanced,
315
323
  open: advancedOpen,
@@ -320,6 +328,610 @@ function SchemaForm({
320
328
  )
321
329
  ] });
322
330
  }
331
+ function useControllableState(value, defaultValue, onChange) {
332
+ const [inner, setInner] = react.useState(defaultValue);
333
+ const isControlled = value !== void 0;
334
+ const current = isControlled ? value : inner;
335
+ const onChangeRef = react.useRef(onChange);
336
+ onChangeRef.current = onChange;
337
+ const set = react.useCallback(
338
+ (next) => {
339
+ if (!isControlled) setInner(next);
340
+ onChangeRef.current?.(next);
341
+ },
342
+ [isControlled]
343
+ );
344
+ return [current, set];
345
+ }
346
+ var DEFAULT_AGENT_SELECT_LABELS = {
347
+ label: "Run as",
348
+ myAssistant: "My assistant"
349
+ };
350
+ var ME = "__me__";
351
+ function AgentSelect({
352
+ agents,
353
+ value,
354
+ defaultValue = "",
355
+ onValueChange,
356
+ hideLabel,
357
+ disabled,
358
+ className,
359
+ labels,
360
+ testId,
361
+ optionTestId
362
+ }) {
363
+ const l = { ...DEFAULT_AGENT_SELECT_LABELS, ...labels };
364
+ const triggerId = react.useId();
365
+ const [current, setCurrent] = useControllableState(value, defaultValue, onValueChange);
366
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-1.5", className), "data-slot": "agent-select", children: [
367
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: triggerId, className: hideLabel ? "sr-only" : void 0, children: l.label }),
368
+ /* @__PURE__ */ jsxRuntime.jsxs(
369
+ ui.Select,
370
+ {
371
+ value: current === "" ? ME : current,
372
+ onValueChange: (v) => setCurrent(v === ME ? "" : v),
373
+ disabled,
374
+ children: [
375
+ /* @__PURE__ */ jsxRuntime.jsx(
376
+ ui.SelectTrigger,
377
+ {
378
+ id: triggerId,
379
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "agent-select" }),
380
+ className: "pointer-coarse:min-h-11",
381
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.SelectValue, {})
382
+ }
383
+ ),
384
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.SelectContent, { children: [
385
+ /* @__PURE__ */ jsxRuntime.jsx(
386
+ ui.SelectItem,
387
+ {
388
+ value: ME,
389
+ "data-testid": chunkMHVNT4J3_cjs.prefixedTestId(optionTestId, "me", {
390
+ testId: "agent-select-option-me"
391
+ }),
392
+ children: l.myAssistant
393
+ }
394
+ ),
395
+ agents.map((agent) => /* @__PURE__ */ jsxRuntime.jsx(
396
+ ui.SelectItem,
397
+ {
398
+ value: agent.id,
399
+ "data-testid": chunkMHVNT4J3_cjs.prefixedTestId(optionTestId, agent.id, {
400
+ testId: `agent-select-option-${agent.id}`
401
+ }),
402
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
403
+ agent.avatar,
404
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: agent.label }),
405
+ agent.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: agent.description })
406
+ ] })
407
+ },
408
+ agent.id
409
+ ))
410
+ ] })
411
+ ]
412
+ }
413
+ )
414
+ ] });
415
+ }
416
+ var DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS = {
417
+ start: "Start",
418
+ starting: "Starting\u2026",
419
+ addFilesReason: "This reads your files, and there is nothing to read yet.",
420
+ agentLabel: "Run as"
421
+ };
422
+ function WorkflowConfigDialog({
423
+ workflow,
424
+ open,
425
+ onOpenChange,
426
+ onLaunch,
427
+ initialInputs,
428
+ inputs: inputsProp,
429
+ onInputsChange,
430
+ scopeSource,
431
+ renderScope,
432
+ renderDocuments,
433
+ renderIcon,
434
+ addFilesAction,
435
+ agents,
436
+ agentId: agentIdProp,
437
+ onAgentChange,
438
+ isLaunching,
439
+ submitLabel,
440
+ fieldPlaceholder,
441
+ renderNotice,
442
+ labels,
443
+ formLabels,
444
+ agentLabels,
445
+ testId,
446
+ startTestId,
447
+ className
448
+ }) {
449
+ const l = { ...DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS, ...labels };
450
+ const initialKey = JSON.stringify(initialInputs ?? {});
451
+ const seedKey = JSON.stringify({ ...chunk6F7SZCVL_cjs.defaultInputs(workflow), ...JSON.parse(initialKey) });
452
+ const seed = react.useMemo(() => JSON.parse(seedKey), [seedKey]);
453
+ const [inputs, setInputs] = useControllableState(inputsProp, seed, onInputsChange);
454
+ const [agentId, setAgentId] = useControllableState(
455
+ agentIdProp,
456
+ workflow.defaultAgentId ?? "",
457
+ onAgentChange
458
+ );
459
+ react.useEffect(() => {
460
+ if (open && inputsProp === void 0) setInputs(seed);
461
+ }, [open, seed]);
462
+ const setField = (name, value) => setInputs({ ...inputs, [name]: value });
463
+ const errors = chunk6F7SZCVL_cjs.validateInputs(workflow, inputs);
464
+ const valid = Object.keys(errors).length === 0;
465
+ const visibleErrors = Object.fromEntries(
466
+ Object.entries(errors).filter(([, e]) => e !== "required")
467
+ );
468
+ const scopeField = workflow.inputs.find((f) => f.type === "scope");
469
+ const rawScope = scopeField ? inputs[scopeField.name] : void 0;
470
+ const scopeValue = rawScope && typeof rawScope === "object" ? rawScope : { folders: [], labels: [] };
471
+ const matchedCount = scopeSource && scopeField ? scopeSource.countMatching(scopeValue) : null;
472
+ const noFiles = Boolean(workflow.requiresFiles && scopeSource && scopeSource.totalCount === 0);
473
+ const blockedByScope = matchedCount !== null && matchedCount === 0 && Boolean(workflow.requiresFiles);
474
+ const showAgent = workflow.run.kind === "prompt" && workflow.options?.agent !== false && agents !== void 0 && agents.length > 0;
475
+ const launch = (values) => {
476
+ Promise.resolve(onLaunch(chunk6F7SZCVL_cjs.buildLaunch(workflow, values, agentId))).catch(() => {
477
+ });
478
+ };
479
+ const submit = () => {
480
+ if (!valid || noFiles || blockedByScope || isLaunching) return;
481
+ launch(inputs);
482
+ };
483
+ const fields = react.useMemo(
484
+ () => workflow.inputs.map((f) => {
485
+ const placeholder = fieldPlaceholder?.(f, inputs, workflow);
486
+ return placeholder === void 0 ? f : { ...f, placeholder };
487
+ }),
488
+ [workflow, fieldPlaceholder, inputs]
489
+ );
490
+ const id = chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "workflow-dialog" });
491
+ const formRef = react.useRef(null);
492
+ const firstField = workflow.inputs.find((f) => !f.advanced);
493
+ const focusPromptFirst = firstField?.type === "text" || firstField?.type === "longtext";
494
+ const defaultScopeRender = scopeSource ? (_field, value, onChange) => /* @__PURE__ */ jsxRuntime.jsx(
495
+ chunkWS5EX7DN_cjs.ScopePicker,
496
+ {
497
+ folders: scopeSource.folders,
498
+ unfiledCount: scopeSource.unfiledCount,
499
+ labels: scopeSource.labels,
500
+ totalCount: scopeSource.totalCount,
501
+ matchedCount: scopeSource.countMatching(value),
502
+ scope: value,
503
+ onScopeChange: onChange
504
+ }
505
+ ) : void 0;
506
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
507
+ ui.DialogContent,
508
+ {
509
+ presentation: "sheet",
510
+ className: `max-h-[calc(100dvh-2rem)] overflow-y-auto sm:max-w-xl ${className ?? ""}`,
511
+ "data-testid": id,
512
+ "data-workflow": workflow.id,
513
+ onOpenAutoFocus: (event) => {
514
+ if (!focusPromptFirst || !firstField) return;
515
+ const control = formRef.current?.querySelector(
516
+ `[data-testid="${id}-field-${firstField.name}"]`
517
+ );
518
+ if (!control) return;
519
+ event.preventDefault();
520
+ control.focus();
521
+ if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {
522
+ const end = control.value.length;
523
+ control.setSelectionRange(end, end);
524
+ }
525
+ },
526
+ children: [
527
+ /* @__PURE__ */ jsxRuntime.jsx(
528
+ chunkWS5EX7DN_cjs.QuickActionDialogHeader,
529
+ {
530
+ icon: workflow.icon && renderIcon ? renderIcon(workflow.icon) : null,
531
+ title: workflow.title,
532
+ description: workflow.details ?? workflow.description,
533
+ descriptionTestId: `${id}-description`
534
+ }
535
+ ),
536
+ /* @__PURE__ */ jsxRuntime.jsx(
537
+ "form",
538
+ {
539
+ ref: formRef,
540
+ className: "mt-2 flex flex-col gap-4",
541
+ onSubmit: (event) => {
542
+ event.preventDefault();
543
+ submit();
544
+ },
545
+ children: noFiles ? /* @__PURE__ */ jsxRuntime.jsx(
546
+ chunkWS5EX7DN_cjs.AddFilesFirst,
547
+ {
548
+ reason: l.addFilesReason,
549
+ action: addFilesAction,
550
+ testId: `${id}-empty-state`
551
+ }
552
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
553
+ /* @__PURE__ */ jsxRuntime.jsx(
554
+ SchemaForm,
555
+ {
556
+ fields,
557
+ values: inputs,
558
+ onChange: setField,
559
+ errors: visibleErrors,
560
+ renderScope: renderScope ?? defaultScopeRender,
561
+ renderDocuments,
562
+ renderIcon,
563
+ labels: formLabels,
564
+ onEnterSubmit: submit,
565
+ testIdPrefix: `${id}-field`
566
+ }
567
+ ),
568
+ renderNotice?.({ workflow, inputs }),
569
+ /* @__PURE__ */ jsxRuntime.jsxs(
570
+ "div",
571
+ {
572
+ className: "flex flex-col gap-3 border-t border-border pt-3 sm:flex-row sm:items-end sm:justify-between",
573
+ "data-slot": "workflow-footer",
574
+ children: [
575
+ showAgent ? /* @__PURE__ */ jsxRuntime.jsx(
576
+ AgentSelect,
577
+ {
578
+ agents: agents ?? [],
579
+ value: agentId,
580
+ onValueChange: setAgentId,
581
+ labels: { label: l.agentLabel, ...agentLabels },
582
+ testId: `${id}-agent`,
583
+ className: "sm:w-56"
584
+ }
585
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
586
+ /* @__PURE__ */ jsxRuntime.jsxs(
587
+ ui.Button,
588
+ {
589
+ type: "submit",
590
+ className: "gap-1.5 px-5 pointer-coarse:min-h-11",
591
+ disabled: !valid || blockedByScope || isLaunching,
592
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(startTestId, { testId: "workflow-start-button" }),
593
+ children: [
594
+ isLaunching ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-4" }),
595
+ isLaunching ? l.starting : submitLabel?.({ workflow, inputs, matchedCount }) ?? workflow.startLabel ?? l.start
596
+ ]
597
+ }
598
+ )
599
+ ]
600
+ }
601
+ )
602
+ ] })
603
+ }
604
+ )
605
+ ]
606
+ }
607
+ ) });
608
+ }
609
+ function WorkflowLauncher({
610
+ workflows,
611
+ tileWorkflows,
612
+ onLaunch,
613
+ showTiles = true,
614
+ caption,
615
+ captionTestId,
616
+ tileTestId,
617
+ disabledReason,
618
+ activeId: activeIdProp,
619
+ onActiveIdChange,
620
+ initialInputsFor,
621
+ testId,
622
+ extraTiles = [],
623
+ className,
624
+ children,
625
+ renderIcon,
626
+ ...dialog
627
+ }) {
628
+ const [activeId, setActiveId] = useControllableState(
629
+ activeIdProp,
630
+ null,
631
+ onActiveIdChange
632
+ );
633
+ const [isLaunching, setIsLaunching] = react.useState(false);
634
+ const active = workflows.find((w) => w.id === activeId) ?? null;
635
+ const run = async (launch) => {
636
+ setIsLaunching(true);
637
+ try {
638
+ await onLaunch(launch);
639
+ setActiveId(null);
640
+ } finally {
641
+ setIsLaunching(false);
642
+ }
643
+ };
644
+ const select = (workflow) => {
645
+ if (workflow.run.kind === "operation" && workflow.inputs.length === 0) {
646
+ const inputs = chunk6F7SZCVL_cjs.defaultInputs(workflow);
647
+ if (Object.keys(chunk6F7SZCVL_cjs.validateInputs(workflow, inputs)).length === 0) {
648
+ Promise.resolve(onLaunch(chunk6F7SZCVL_cjs.buildLaunch(workflow, inputs, void 0))).catch(() => {
649
+ });
650
+ return;
651
+ }
652
+ }
653
+ setActiveId(workflow.id);
654
+ };
655
+ const tiles = (tileWorkflows ?? workflows).map((workflow) => {
656
+ const reason = disabledReason?.(workflow);
657
+ return {
658
+ id: workflow.id,
659
+ iconNode: workflow.icon && renderIcon ? renderIcon(workflow.icon) : void 0,
660
+ title: workflow.title,
661
+ description: workflow.description,
662
+ onSelect: () => select(workflow),
663
+ disabled: reason !== void 0,
664
+ disabledReason: reason,
665
+ testId: tileTestId?.(workflow) ?? `workflow-tile-${workflow.id}`
666
+ };
667
+ });
668
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-slot": "workflow-launcher", children: [
669
+ showTiles && /* @__PURE__ */ jsxRuntime.jsx(
670
+ chunkWS5EX7DN_cjs.StartTiles,
671
+ {
672
+ items: [...tiles, ...extraTiles],
673
+ caption,
674
+ captionTestId,
675
+ testId
676
+ }
677
+ ),
678
+ children,
679
+ active && /* @__PURE__ */ jsxRuntime.jsx(
680
+ WorkflowConfigDialog,
681
+ {
682
+ ...dialog,
683
+ renderIcon,
684
+ workflow: active,
685
+ open: true,
686
+ onOpenChange: (open) => !open && setActiveId(null),
687
+ onLaunch: run,
688
+ isLaunching,
689
+ initialInputs: initialInputsFor?.(active)
690
+ }
691
+ )
692
+ ] });
693
+ }
694
+ function documentScopeLabels(tags) {
695
+ return tags.filter((tag) => {
696
+ if (tag.kind === "search") return false;
697
+ const onDocs = (tag.doctag_count ?? 0) > 0;
698
+ const onFacts = (tag.facttag_count ?? 0) > 0;
699
+ return onDocs || !onFacts;
700
+ });
701
+ }
702
+ var canonical = (path) => (path ?? "").split("/").map((part) => part.trim()).filter(Boolean).join("/");
703
+ function matchWorkflowScope(docs, scope) {
704
+ if (scope.documents?.length) {
705
+ const ids = new Set(scope.documents);
706
+ return docs.filter((doc) => ids.has(doc.external_id));
707
+ }
708
+ if (!scope.folders.length && !scope.labels.length) return docs;
709
+ const folders = scope.folders.map(canonical);
710
+ const labels = new Set(scope.labels);
711
+ return docs.filter((doc) => {
712
+ const folder = canonical(doc.folder);
713
+ return folders.some(
714
+ (path) => path === "" ? folder === "" : folder === path || folder.startsWith(`${path}/`)
715
+ ) || doc.doctags?.some((tag) => labels.has(tag.tag_ext_id));
716
+ });
717
+ }
718
+ function buildWorkflowScopeSource(docs, labels = []) {
719
+ const counts = /* @__PURE__ */ new Map();
720
+ for (const doc of docs) {
721
+ const parts = canonical(doc.folder).split("/").filter(Boolean);
722
+ for (let i = 1; i <= parts.length; i++) {
723
+ const path = parts.slice(0, i).join("/");
724
+ counts.set(path, (counts.get(path) ?? 0) + 1);
725
+ }
726
+ }
727
+ return {
728
+ folders: [...counts].sort(([a], [b]) => a.localeCompare(b)).map(([path, count]) => ({
729
+ path,
730
+ count,
731
+ label: path.split("/").at(-1),
732
+ depth: path.split("/").length - 1
733
+ })),
734
+ unfiledCount: docs.filter((doc) => !canonical(doc.folder)).length,
735
+ labels: labels.map((label) => ({
736
+ id: label.external_id,
737
+ name: label.name,
738
+ color: label.color ?? ui.getEntityColor(label.external_id, "medium"),
739
+ count: docs.filter((doc) => doc.doctags?.some((tag) => tag.tag_ext_id === label.external_id)).length
740
+ })),
741
+ totalCount: docs.length,
742
+ countMatching: (scope) => matchWorkflowScope(docs, scope).length,
743
+ resolveDocuments: (scope) => matchWorkflowScope(docs, scope).map((doc) => doc.external_id)
744
+ };
745
+ }
746
+ var DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS = {
747
+ pickOne: "Pick a file",
748
+ pickMany: "Pick files",
749
+ allDocuments: "All documents",
750
+ addFiles: "Add files",
751
+ adding: "Adding\u2026",
752
+ empty: "No files in this workspace yet. Drop one here, or add it.",
753
+ remove: (name) => `Remove ${name}`,
754
+ pending: (name, status) => `${name}: ${status}. You can still pick it.`,
755
+ status: {
756
+ queued: "Queued",
757
+ uploading: "Uploading",
758
+ encrypting: "Encrypting",
759
+ processing: "Processing",
760
+ parsing: "Processing",
761
+ indexing: "Indexing",
762
+ analysing: "Analysing"
763
+ }
764
+ };
765
+ var isReady = (status) => !status || ["completed", "done", "ready", "success"].includes(status.toLowerCase());
766
+ var byTitle = (a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase());
767
+ function WorkflowDocumentsField({
768
+ field,
769
+ value,
770
+ onChange,
771
+ documents,
772
+ loaded = true,
773
+ thumbnailOf,
774
+ onAddFiles,
775
+ adding,
776
+ labels
777
+ }) {
778
+ const l = { ...DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS, ...labels };
779
+ const ids = value.documents ?? [];
780
+ const max = field.max ?? 1;
781
+ const multiple = max > 1;
782
+ const [isOver, setIsOver] = react.useState(false);
783
+ const docOf = (id) => documents.find((d) => d.id === id);
784
+ const nameOf = (id) => docOf(id)?.title || id;
785
+ const set = (next) => onChange({ ...value, documents: next });
786
+ const toggle = (id) => set(ids.includes(id) ? ids.filter((d) => d !== id) : [...ids, id].slice(-max));
787
+ const offered = react.useMemo(
788
+ () => field.accept === "image" ? documents.filter((d) => d.isImage) : documents,
789
+ [documents, field.accept]
790
+ );
791
+ const awaitingAdd = react.useRef(false);
792
+ const known = react.useRef(null);
793
+ const latest = react.useRef({ ids, set });
794
+ latest.current = { ids, set };
795
+ react.useEffect(() => {
796
+ if (!loaded) return;
797
+ const current = new Set(documents.map((d) => d.id));
798
+ const before = known.current;
799
+ known.current = current;
800
+ if (!before || !awaitingAdd.current) return;
801
+ const fresh = [...current].filter((id) => !before.has(id));
802
+ if (fresh.length === 0) return;
803
+ awaitingAdd.current = false;
804
+ latest.current.set([...latest.current.ids, ...fresh].slice(-max));
805
+ }, [documents, loaded, max]);
806
+ const addFiles = (files) => {
807
+ if (!onAddFiles) return;
808
+ awaitingAdd.current = true;
809
+ onAddFiles(files?.length ? files : void 0);
810
+ };
811
+ const dropProps = onAddFiles ? {
812
+ onDragOver: (e) => {
813
+ e.preventDefault();
814
+ setIsOver(true);
815
+ },
816
+ onDragLeave: () => setIsOver(false),
817
+ onDrop: (e) => {
818
+ e.preventDefault();
819
+ setIsOver(false);
820
+ const files = Array.from(e.dataTransfer?.files ?? []);
821
+ if (files.length) addFiles(files);
822
+ }
823
+ } : {};
824
+ const dropClass = isOver ? "ring-2 ring-primary" : "";
825
+ const addButton = (className, variant = "outline") => onAddFiles && /* @__PURE__ */ jsxRuntime.jsx(
826
+ ui.Button,
827
+ {
828
+ type: "button",
829
+ size: "sm",
830
+ variant,
831
+ className,
832
+ disabled: adding,
833
+ onClick: () => addFiles(),
834
+ "data-testid": "workflow-add-files",
835
+ children: adding ? l.adding : l.addFiles
836
+ }
837
+ );
838
+ if (loaded && documents.length === 0) {
839
+ return /* @__PURE__ */ jsxRuntime.jsxs(
840
+ "div",
841
+ {
842
+ className: ui.cn(
843
+ "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border bg-muted/40 px-4 py-6 text-center",
844
+ dropClass
845
+ ),
846
+ "data-testid": "workflow-documents-empty",
847
+ ...dropProps,
848
+ children: [
849
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlus, { className: "size-5 text-muted-foreground", "aria-hidden": true }),
850
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.empty }),
851
+ addButton(void 0, "default")
852
+ ]
853
+ }
854
+ );
855
+ }
856
+ const pending = ids.flatMap((id) => {
857
+ const status = docOf(id)?.status;
858
+ return isReady(status) ? [] : [{ id, label: l.status[String(status).toLowerCase()] ?? String(status) }];
859
+ });
860
+ const selected = multiple ? void 0 : docOf(ids[0] ?? "");
861
+ return /* @__PURE__ */ jsxRuntime.jsxs(
862
+ "div",
863
+ {
864
+ className: ui.cn("flex flex-col gap-3 rounded-lg", dropClass),
865
+ "data-testid": `workflow-documents-${field.name}`,
866
+ ...dropProps,
867
+ children: [
868
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
869
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
870
+ chunkRQ2Y7USX_cjs.DocumentPicker,
871
+ {
872
+ groups: [{ id: "all", heading: l.allDocuments, docs: [...offered].sort(byTitle) }],
873
+ value: multiple ? "" : ids[0] ?? "",
874
+ onValueChange: (id) => multiple ? toggle(id) : set([id]),
875
+ selected,
876
+ selectedIds: multiple ? ids : void 0,
877
+ labels: { placeholder: field.placeholder ?? (multiple ? l.pickMany : l.pickOne) }
878
+ }
879
+ ) }),
880
+ addButton("shrink-0 pointer-coarse:h-11")
881
+ ] }),
882
+ pending.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
883
+ "p",
884
+ {
885
+ className: "text-xs text-muted-foreground",
886
+ "data-testid": `workflow-document-status-${p.id}`,
887
+ children: l.pending(nameOf(p.id), p.label)
888
+ },
889
+ p.id
890
+ )),
891
+ multiple && ids.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
892
+ "div",
893
+ {
894
+ className: "grid grid-cols-2 gap-3 sm:grid-cols-3",
895
+ "data-testid": "workflow-documents-gallery",
896
+ children: ids.map((id) => {
897
+ const thumbnail = thumbnailOf?.(id);
898
+ return /* @__PURE__ */ jsxRuntime.jsxs(
899
+ "figure",
900
+ {
901
+ className: "relative overflow-hidden rounded-lg border border-border bg-muted/40",
902
+ "data-testid": `workflow-document-${id}`,
903
+ children: [
904
+ thumbnail ? /* @__PURE__ */ jsxRuntime.jsx(
905
+ "img",
906
+ {
907
+ src: thumbnail,
908
+ alt: nameOf(id),
909
+ className: "aspect-square w-full object-cover"
910
+ }
911
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex aspect-square w-full items-center justify-center text-muted-foreground/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ImageIcon, { className: "size-8" }) }),
912
+ /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "truncate bg-background/90 px-2 py-1 text-xs text-muted-foreground", children: nameOf(id) }),
913
+ /* @__PURE__ */ jsxRuntime.jsx(
914
+ "button",
915
+ {
916
+ type: "button",
917
+ onClick: () => toggle(id),
918
+ "aria-label": l.remove(nameOf(id)),
919
+ className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-full bg-background/80 text-muted-foreground hover:text-foreground pointer-coarse:size-11",
920
+ "data-testid": `workflow-document-remove-${id}`,
921
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
922
+ }
923
+ )
924
+ ]
925
+ },
926
+ id
927
+ );
928
+ })
929
+ }
930
+ )
931
+ ]
932
+ }
933
+ );
934
+ }
323
935
 
324
936
  // src/agents/workflows/planSteps.ts
325
937
  function toPlanAssignee(a) {
@@ -429,7 +1041,7 @@ function toStepField(f) {
429
1041
  }
430
1042
  var compact = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== ""));
431
1043
  function placeholders(workflow) {
432
- return Object.fromEntries(chunk6AALMYPS_cjs.runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
1044
+ return Object.fromEntries(chunk6F7SZCVL_cjs.runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
433
1045
  }
434
1046
  function agentStep(workflow, step, options) {
435
1047
  const target = step.workflow ? options.resolveWorkflow?.(step.workflow) : void 0;
@@ -438,11 +1050,11 @@ function agentStep(workflow, step, options) {
438
1050
  ([, v]) => v !== void 0 && v !== null && v !== ""
439
1051
  );
440
1052
  const inputs = { ...placeholders(workflow), ...Object.fromEntries(given) };
441
- return { skill: null, inputs: null, prompt: chunk6AALMYPS_cjs.composeStepPrompt(workflow, step, inputs, options) };
1053
+ return { skill: null, inputs: null, prompt: chunk6F7SZCVL_cjs.composeStepPrompt(workflow, step, inputs, options) };
442
1054
  }
443
1055
  function toPlanSteps(workflow, options = {}) {
444
1056
  const layout = workflow.run.kind === "steps" ? workflow.run.layout : void 0;
445
- return chunk6AALMYPS_cjs.workflowSteps(workflow).map((step) => {
1057
+ return chunk6F7SZCVL_cjs.workflowSteps(workflow).map((step) => {
446
1058
  const ui = compact({
447
1059
  description: step.description,
448
1060
  icon: step.icon,
@@ -469,8 +1081,8 @@ function toPlanSteps(workflow, options = {}) {
469
1081
  ui,
470
1082
  // An unfinished signal (still being typed) is not saved: the server would refuse it.
471
1083
  ...step.signals?.some((s) => !isIncompleteSignal(s)) ? { signals: step.signals.filter((s) => !isIncompleteSignal(s)).map(toPlanSignal) } : {},
472
- ...step.assignee && chunk6AALMYPS_cjs.canAssign(step) ? { assignee: toPlanAssignee(step.assignee) } : {},
473
- ...step.remindAfterHours && chunk6AALMYPS_cjs.canAssign(step) ? { remind_after_hours: step.remindAfterHours } : {},
1084
+ ...step.assignee && chunk6F7SZCVL_cjs.canAssign(step) ? { assignee: toPlanAssignee(step.assignee) } : {},
1085
+ ...step.remindAfterHours && chunk6F7SZCVL_cjs.canAssign(step) ? { remind_after_hours: step.remindAfterHours } : {},
474
1086
  // A review's fields are what approving it is checked against (the server's `fields`).
475
1087
  ...step.kind === "review" && step.fields?.length ? { fields: step.fields.map(toStepField) } : {},
476
1088
  ...step.kind === "action" ? { action: toPlanAction(step.action) } : {},
@@ -571,10 +1183,51 @@ function fromStepField(f) {
571
1183
  ...f.max != null ? { max: f.max } : {}
572
1184
  };
573
1185
  }
1186
+
1187
+ // src/agents/workflows/skillMarkdown.ts
1188
+ var JSON_KEYS = /* @__PURE__ */ new Set(["inputs"]);
1189
+ var oneLine = (text) => text.replace(/\s*\n\s*/g, " ").trim();
1190
+ var skillSlug = (raw) => raw.toLowerCase().replace(/[^a-z0-9-]/g, "");
1191
+ function workflowToSkillMarkdown(workflow) {
1192
+ const { run } = workflow;
1193
+ if (run.kind !== "prompt") throw new Error("Only skills that start a chat can be copied");
1194
+ const lines = [
1195
+ "---",
1196
+ `name: ${skillSlug(workflow.id)}`,
1197
+ `description: ${oneLine(workflow.description)}`
1198
+ ];
1199
+ if (workflow.icon) lines.push(`icon: ${workflow.icon}`);
1200
+ if (workflow.landing !== "chat") lines.push(`landing: ${workflow.landing}`);
1201
+ if (workflow.requiresFiles) lines.push("requires_files: true");
1202
+ if (workflow.inputs.length > 0) {
1203
+ lines.push(`inputs: ${JSON.stringify(workflow.inputs.map(chunk6F7SZCVL_cjs.fieldToFrontmatter))}`);
1204
+ }
1205
+ lines.push("---", "", run.promptTemplate.trim(), "");
1206
+ return lines.join("\n");
1207
+ }
1208
+ function workflowFromSkillMarkdown(id, text) {
1209
+ const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(text);
1210
+ const frontmatter = {};
1211
+ const body = match ? match[2] : text;
1212
+ for (const line of (match ? match[1] : "").split("\n")) {
1213
+ const i = line.indexOf(":");
1214
+ if (i < 1) continue;
1215
+ const key = line.slice(0, i).trim();
1216
+ const value = line.slice(i + 1).trim();
1217
+ if (JSON_KEYS.has(key)) {
1218
+ try {
1219
+ frontmatter[key] = JSON.parse(value);
1220
+ } catch {
1221
+ }
1222
+ } else if (value === "true" || value === "false") frontmatter[key] = value === "true";
1223
+ else frontmatter[key] = value;
1224
+ }
1225
+ return chunk6F7SZCVL_cjs.workflowFromFrontmatter(id, frontmatter, body);
1226
+ }
574
1227
  var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
575
1228
  function firstOpen(steps, states) {
576
1229
  const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
577
- return open?.id ?? (steps.length && chunk6AALMYPS_cjs.isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
1230
+ return open?.id ?? (steps.length && chunk6F7SZCVL_cjs.isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
578
1231
  }
579
1232
  function useWorkflowView(options) {
580
1233
  const { steps, states, inputs, setInput, loaded = true } = options;
@@ -614,11 +1267,11 @@ function useWorkflowView(options) {
614
1267
  }),
615
1268
  []
616
1269
  );
617
- const action = busy ? "wait" : chunk6AALMYPS_cjs.nextAction(steps, states, current, actionOptions(options));
1270
+ const action = busy ? "wait" : chunk6F7SZCVL_cjs.nextAction(steps, states, current, actionOptions(options));
618
1271
  const next = react.useCallback(async () => {
619
1272
  const { steps: s, states: st, inputs: values } = optionsRef.current;
620
1273
  const at = s.find((x) => x.id === current);
621
- const act2 = chunk6AALMYPS_cjs.nextAction(s, st, current, actionOptions(optionsRef.current));
1274
+ const act2 = chunk6F7SZCVL_cjs.nextAction(s, st, current, actionOptions(optionsRef.current));
622
1275
  if (!at || act2 === "wait" || busy) return;
623
1276
  setActionError(null);
624
1277
  if (act2 === "finish") return setCurrent(null);
@@ -629,7 +1282,7 @@ function useWorkflowView(options) {
629
1282
  await (act2 === "start" ? optionsRef.current.start?.() : optionsRef.current.retry?.(at.id));
630
1283
  return;
631
1284
  }
632
- if (Object.keys(chunk6AALMYPS_cjs.validateStep(at, values)).length > 0) {
1285
+ if (Object.keys(chunk6F7SZCVL_cjs.validateStep(at, values)).length > 0) {
633
1286
  setShowErrors(true);
634
1287
  return;
635
1288
  }
@@ -730,10 +1383,10 @@ function useWorkflowView(options) {
730
1383
  inputs,
731
1384
  setInput,
732
1385
  stateOf: (id) => states[id],
733
- phaseOf: (id) => chunk6AALMYPS_cjs.stepPhase(steps, states, id),
734
- failedUpstreamOf: (id) => chunk6AALMYPS_cjs.failedUpstream(steps, states, id),
1386
+ phaseOf: (id) => chunk6F7SZCVL_cjs.stepPhase(steps, states, id),
1387
+ failedUpstreamOf: (id) => chunk6F7SZCVL_cjs.failedUpstream(steps, states, id),
735
1388
  isLocked,
736
- errors: showErrors && step && !isLocked(step.id) ? chunk6AALMYPS_cjs.validateStep(step, inputs) : {},
1389
+ errors: showErrors && step && !isLocked(step.id) ? chunk6F7SZCVL_cjs.validateStep(step, inputs) : {},
737
1390
  busy,
738
1391
  actionError,
739
1392
  isRunning: Object.values(states).some((s) => s.status === "running"),
@@ -751,11 +1404,11 @@ function useWorkflowView(options) {
751
1404
  nameOf: options.nameOf,
752
1405
  assigneeOf: (id) => {
753
1406
  const s = steps.find((x) => x.id === id);
754
- if (!s || !chunk6AALMYPS_cjs.canAssign(s)) return void 0;
755
- return chunk6AALMYPS_cjs.assigneeName(s.assignee, {
1407
+ if (!s || !chunk6F7SZCVL_cjs.canAssign(s)) return void 0;
1408
+ return chunk6F7SZCVL_cjs.assigneeName(s.assignee, {
756
1409
  nameOf: options.nameOf,
757
1410
  inputs,
758
- fields: chunk6AALMYPS_cjs.runFieldsOf(steps),
1411
+ fields: chunk6F7SZCVL_cjs.runFieldsOf(steps),
759
1412
  announcedTo: states[id]?.announcedTo
760
1413
  });
761
1414
  },
@@ -889,7 +1542,7 @@ function StepBarFrame({
889
1542
  }) {
890
1543
  const l = { ...DEFAULT_STEP_BAR_LABELS, ...labels };
891
1544
  const box = react.useRef(null);
892
- const { width } = chunk6AALMYPS_cjs.useElementSize(box);
1545
+ const { width } = chunk6F7SZCVL_cjs.useElementSize(box);
893
1546
  const narrow = width > 0 && width < NARROW_PX;
894
1547
  const [start, setStart] = react.useState(null);
895
1548
  react.useEffect(() => setStart(null), [current]);
@@ -956,7 +1609,7 @@ function StepBarFrame({
956
1609
  phase === "blocked" && "opacity-60"
957
1610
  ),
958
1611
  "aria-hidden": true,
959
- children: /* @__PURE__ */ jsxRuntime.jsx(chunk6AALMYPS_cjs.StepBadgeMark, { phase, icon: icon?.(s) })
1612
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunk6F7SZCVL_cjs.StepBadgeMark, { phase, icon: icon?.(s) })
960
1613
  }
961
1614
  ),
962
1615
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", title: s.title, children: s.title }),
@@ -1064,7 +1717,7 @@ function StepBarFrame({
1064
1717
  };
1065
1718
  const running = win.runningHidden;
1066
1719
  const outOfViewChip = (s, kind) => /* @__PURE__ */ jsxRuntime.jsx(
1067
- chunk6AALMYPS_cjs.StepChip,
1720
+ chunk6F7SZCVL_cjs.StepChip,
1068
1721
  {
1069
1722
  kind: kindOf(s),
1070
1723
  phase: kind === "working" ? "running" : "failed",
@@ -1237,7 +1890,7 @@ var DEFAULT_WORKFLOW_STEP_PARTS_LABELS = {
1237
1890
  someone: "someone"
1238
1891
  };
1239
1892
  var docName = (ref, nameOfDoc) => {
1240
- const { id, version } = chunk6AALMYPS_cjs.splitDocRef(ref);
1893
+ const { id, version } = chunk6F7SZCVL_cjs.splitDocRef(ref);
1241
1894
  const name = nameOfDoc?.(id) ?? id;
1242
1895
  return version ? `${name} \xB7 v${version}` : name;
1243
1896
  };
@@ -1319,7 +1972,7 @@ function SendBackControl({
1319
1972
  const states = Object.fromEntries(
1320
1973
  run.steps.map((s) => [s.id, run.stateOf(s.id) ?? { status: "pending" }])
1321
1974
  );
1322
- const targets = chunk6AALMYPS_cjs.sendBackTargets(run.steps, states, step.id);
1975
+ const targets = chunk6F7SZCVL_cjs.sendBackTargets(run.steps, states, step.id);
1323
1976
  const [open, setOpen] = react.useState(false);
1324
1977
  const [to, setTo] = react.useState(targets[0]?.id ?? "");
1325
1978
  const [note, setNote] = react.useState("");
@@ -1409,7 +2062,7 @@ function ApprovalEvidence({
1409
2062
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex flex-wrap items-center gap-1.5 text-sm font-medium", children: [
1410
2063
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "size-4 text-primary" }),
1411
2064
  approver ? l.approvedBy.replace("{name}", approver) : null,
1412
- state.at && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: l.approvedAt.replace("{date}", chunk6AALMYPS_cjs.formatDate(state.at)) })
2065
+ state.at && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: l.approvedAt.replace("{date}", chunk6F7SZCVL_cjs.formatDate(state.at)) })
1413
2066
  ] }),
1414
2067
  evidence.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1415
2068
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.approvedWhat }),
@@ -1442,7 +2095,7 @@ function ApprovalEvidence({
1442
2095
  ] }),
1443
2096
  (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: [
1444
2097
  /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: f.label }),
1445
- /* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": `${testId}-evidence-field-${f.name}`, children: chunk6AALMYPS_cjs.shownValue(run.inputs[f.name], f, run.nameOf) })
2098
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": `${testId}-evidence-field-${f.name}`, children: chunk6F7SZCVL_cjs.shownValue(run.inputs[f.name], f, run.nameOf) })
1446
2099
  ] }, f.name)) })
1447
2100
  ] });
1448
2101
  }
@@ -1538,7 +2191,7 @@ function ActionStepBody({
1538
2191
  waiting?.expires_at && phase === "waiting" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1539
2192
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "size-3.5" }),
1540
2193
  " ",
1541
- l.expires.replace("{date}", chunk6AALMYPS_cjs.formatDate(waiting.expires_at))
2194
+ l.expires.replace("{date}", chunk6F7SZCVL_cjs.formatDate(waiting.expires_at))
1542
2195
  ] }),
1543
2196
  phase === "waiting" && mine && !declining && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1544
2197
  actions?.sign && state && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1696,7 +2349,7 @@ function WorkflowStepBar({
1696
2349
  const name = `${title} (${l.phases[phase]})`;
1697
2350
  if (s.id === DONE)
1698
2351
  return /* @__PURE__ */ jsxRuntime.jsx(
1699
- chunk6AALMYPS_cjs.StepChip,
2352
+ chunk6F7SZCVL_cjs.StepChip,
1700
2353
  {
1701
2354
  inert: true,
1702
2355
  kind: "start",
@@ -1710,17 +2363,17 @@ function WorkflowStepBar({
1710
2363
  "data-testid": tid("step-done")
1711
2364
  }
1712
2365
  );
1713
- const kind = chunk6AALMYPS_cjs.stepKindOf(s);
1714
- const KindIcon = chunk6AALMYPS_cjs.STEP_KIND_ICONS[kind];
2366
+ const kind = chunk6F7SZCVL_cjs.stepKindOf(s);
2367
+ const KindIcon = chunk6F7SZCVL_cjs.STEP_KIND_ICONS[kind];
1715
2368
  return /* @__PURE__ */ jsxRuntime.jsx(
1716
- chunk6AALMYPS_cjs.StepChip,
2369
+ chunk6F7SZCVL_cjs.StepChip,
1717
2370
  {
1718
2371
  kind,
1719
2372
  phase,
1720
2373
  icon: icon(s.icon) ?? /* @__PURE__ */ jsxRuntime.jsx(KindIcon, {}),
1721
2374
  label: s.title,
1722
2375
  current: isCurrent,
1723
- heading: chunk6AALMYPS_cjs.DEFAULT_STEP_KIND_LABELS[kind],
2376
+ heading: chunk6F7SZCVL_cjs.DEFAULT_STEP_KIND_LABELS[kind],
1724
2377
  labelClassName: isCurrent ? STEP_LABEL_CURRENT : ui.cn(STEP_LABEL, STEP_LABEL_MAX),
1725
2378
  labelTestId: tid(`step-${s.id}-label`),
1726
2379
  onClick: () => run.goTo(s.id),
@@ -1753,7 +2406,7 @@ function WorkflowStepBar({
1753
2406
  isSelectable: (id) => id !== DONE,
1754
2407
  renderStep: (s) => pill(s),
1755
2408
  icon: (s) => s.id === DONE ? doneIcon : icon(s.icon),
1756
- kindOf: (s) => s.id === DONE ? "start" : chunk6AALMYPS_cjs.stepKindOf(s),
2409
+ kindOf: (s) => s.id === DONE ? "start" : chunk6F7SZCVL_cjs.stepKindOf(s),
1757
2410
  disabled: run.busy,
1758
2411
  labels,
1759
2412
  tid,
@@ -1836,7 +2489,7 @@ function WorkflowRunner({
1836
2489
  const { steps, step, isComplete, action } = run;
1837
2490
  const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
1838
2491
  const tid = (suffix) => `${testIdPrefix}-${suffix}`;
1839
- const levels = chunk6AALMYPS_cjs.stepLevels(steps);
2492
+ const levels = chunk6F7SZCVL_cjs.stepLevels(steps);
1840
2493
  const icon = (key) => key && renderIcon ? renderIcon(key) : void 0;
1841
2494
  const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
1842
2495
  const unread = added.filter((f) => f.status === "processing").length;
@@ -1844,7 +2497,7 @@ function WorkflowRunner({
1844
2497
  const sending = added.filter((f) => f.status === "uploading").length;
1845
2498
  const unsent = added.filter((f) => f.status === "upload-failed").length;
1846
2499
  const uploadHold = step?.kind === "upload" && (sending > 0 || uploading || unsent > 0);
1847
- const docsWait = !!step && chunk6AALMYPS_cjs.waitingDocuments(run.stateOf(step.id)).length > 0;
2500
+ const docsWait = !!step && chunk6F7SZCVL_cjs.waitingDocuments(run.stateOf(step.id)).length > 0;
1848
2501
  const nextLabel = sending ? sending === 1 ? l.uploadingFile : l.uploadingFiles.replace("{count}", String(sending)) : uploadHold && uploading ? l.uploadingAny : uploadHold ? unsent === 1 ? l.uploadFailed : l.uploadsFailed.replace("{count}", String(unsent)) : reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "start" ? l.start : action === "retry" ? l.retry : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "complete" && step?.kind === "action" ? l.markSent : action === "wait" && (run.isRunning || run.busy || docsWait) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
1849
2502
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn(compact2 ? "space-y-3" : "space-y-6", className), "data-testid": testIdPrefix, children: [
1850
2503
  !hideStepBar && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1876,7 +2529,7 @@ function WorkflowRunner({
1876
2529
  /* @__PURE__ */ jsxRuntime.jsx(StepNotices, { run, step, l, tid }),
1877
2530
  run.phaseOf(step.id) === "blocked" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { className: ui.cn(box, "p-6"), "data-testid": tid(step.id), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": tid(`${step.id}-blocked`), children: l.blocked.replace(
1878
2531
  "{steps}",
1879
- chunk6AALMYPS_cjs.stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
2532
+ chunk6F7SZCVL_cjs.stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
1880
2533
  ) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
1881
2534
  /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon), testId: tid(`${step.id}-title`) }),
1882
2535
  /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
@@ -1932,7 +2585,7 @@ function WorkflowRunner({
1932
2585
  ] }) : step.kind === "review" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: ui.cn(box, "space-y-4"), "data-testid": tid(step.id), children: [
1933
2586
  /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
1934
2587
  /* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
1935
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: chunk6AALMYPS_cjs.reviewInstructions(step, run.inputs) }),
2588
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: chunk6F7SZCVL_cjs.reviewInstructions(step, run.inputs) }),
1936
2589
  /* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
1937
2590
  !(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 }),
1938
2591
  (step.fields ?? []).length > 0 && run.phaseOf(step.id) === "ready" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -2199,8 +2852,8 @@ function AgentStepBody({
2199
2852
  }) {
2200
2853
  const state = run.stateOf(step.id);
2201
2854
  const phase = run.phaseOf(step.id);
2202
- const pending = chunk6AALMYPS_cjs.waitingDocuments(state);
2203
- const pendingNames = pending.flatMap((ref) => nameOfDoc?.(chunk6AALMYPS_cjs.splitDocRef(ref).id) ?? []);
2855
+ const pending = chunk6F7SZCVL_cjs.waitingDocuments(state);
2856
+ const pendingNames = pending.flatMap((ref) => nameOfDoc?.(chunk6F7SZCVL_cjs.splitDocRef(ref).id) ?? []);
2204
2857
  const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
2205
2858
  /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon }),
2206
2859
  phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: run.retry && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2285,7 +2938,7 @@ function StepNotices({
2285
2938
  l,
2286
2939
  tid
2287
2940
  }) {
2288
- const notStarted = !chunk6AALMYPS_cjs.isPersonStep(step) && run.needsStart && run.phaseOf(step.id) === "ready";
2941
+ const notStarted = !chunk6F7SZCVL_cjs.isPersonStep(step) && run.needsStart && run.phaseOf(step.id) === "ready";
2289
2942
  const failed = run.failedUpstreamOf(step.id);
2290
2943
  if (!notStarted && failed.length === 0) return null;
2291
2944
  const why = (error) => error ? `: ${error}` : "";
@@ -2321,6 +2974,890 @@ function StepNotices({
2321
2974
  ))
2322
2975
  ] });
2323
2976
  }
2977
+
2978
+ // src/agents/skills/skillFiles.ts
2979
+ var SKILL_TYPES = ["markdown", "python", "shell", "javascript", "typescript"];
2980
+ var SKILL_MAIN_FILENAME = "SKILL.md";
2981
+ var MAIN_NAMES = /* @__PURE__ */ new Set(["skill.md", "skill.py", "skill.sh", "skill.js", "skill.ts"]);
2982
+ function isMainSkillFile(filename, skillName) {
2983
+ const lower = filename.toLowerCase();
2984
+ if (MAIN_NAMES.has(lower)) return true;
2985
+ const stem = lower.includes(".") ? lower.slice(0, lower.lastIndexOf(".")) : lower;
2986
+ return stem === skillName;
2987
+ }
2988
+ function detectTypeFromContent(content, filename) {
2989
+ if (filename) {
2990
+ const lower = filename.toLowerCase();
2991
+ if (lower.endsWith(".py")) return "python";
2992
+ if (lower.endsWith(".sh")) return "shell";
2993
+ if (lower.endsWith(".js")) return "javascript";
2994
+ if (lower.endsWith(".ts")) return "typescript";
2995
+ }
2996
+ if (content) {
2997
+ const firstLine = content.split("\n", 1)[0].trim();
2998
+ if (firstLine.startsWith("#!")) {
2999
+ if (firstLine.includes("python")) return "python";
3000
+ if (firstLine.includes("bash") || firstLine.includes("/sh")) return "shell";
3001
+ if (firstLine.includes("ts-node")) return "typescript";
3002
+ if (firstLine.includes("node")) return "javascript";
3003
+ }
3004
+ }
3005
+ return "markdown";
3006
+ }
3007
+ function parseSkillFrontmatter(raw, filename = "") {
3008
+ const config = {};
3009
+ let name = "";
3010
+ let description = "";
3011
+ let skillType = "markdown";
3012
+ if (!raw.startsWith("---")) {
3013
+ return {
3014
+ content: raw,
3015
+ name,
3016
+ description,
3017
+ config,
3018
+ skillType: detectTypeFromContent(raw, filename)
3019
+ };
3020
+ }
3021
+ const end = raw.indexOf("---", 3);
3022
+ if (end === -1) {
3023
+ return {
3024
+ content: raw,
3025
+ name,
3026
+ description,
3027
+ config,
3028
+ skillType: detectTypeFromContent(raw, filename)
3029
+ };
3030
+ }
3031
+ const frontmatter = raw.slice(3, end).trim();
3032
+ const body = raw.slice(end + 3).trim();
3033
+ for (const rawLine of frontmatter.split("\n")) {
3034
+ const line = rawLine.trim();
3035
+ if (!line || !line.includes(":")) continue;
3036
+ const idx = line.indexOf(":");
3037
+ const key = line.slice(0, idx).trim().toLowerCase();
3038
+ const value = line.slice(idx + 1).trim();
3039
+ if (key === "name" && value) {
3040
+ name = value;
3041
+ } else if (key === "description" && value) {
3042
+ description = value;
3043
+ } else if (key === "model" && value) {
3044
+ config.model = value;
3045
+ } else if (key === "temperature") {
3046
+ const t = Number.parseFloat(value);
3047
+ if (!Number.isNaN(t) && t >= 0 && t <= 2) config.temperature = t;
3048
+ } else if (key === "agent") {
3049
+ config.agent = ["true", "yes", "1"].includes(value.toLowerCase());
3050
+ } else if (key === "tools" && value) {
3051
+ config.tools = value.split(",").map((t) => t.trim()).filter(Boolean);
3052
+ } else if (key === "type" && value) {
3053
+ const v = value.toLowerCase();
3054
+ if (v === "python" || v === "py") skillType = "python";
3055
+ else if (v === "shell" || v === "sh" || v === "bash") skillType = "shell";
3056
+ else if (v === "javascript" || v === "js" || v === "node") skillType = "javascript";
3057
+ else if (v === "typescript" || v === "ts") skillType = "typescript";
3058
+ }
3059
+ }
3060
+ if (skillType === "markdown") {
3061
+ skillType = detectTypeFromContent(body, filename);
3062
+ }
3063
+ return { content: body, name, description, config, skillType };
3064
+ }
3065
+ function serializeSkill(input) {
3066
+ const lines = ["---", `name: ${input.name}`, `description: ${input.description}`];
3067
+ if (input.type && input.type !== "markdown") {
3068
+ lines.push(`type: ${input.type}`);
3069
+ }
3070
+ lines.push("---", "", input.body.trim(), "");
3071
+ return lines.join("\n");
3072
+ }
3073
+ var SKILL_FOLDER_PREFIX = "skills/";
3074
+ function stripExt(name) {
3075
+ const i = name.lastIndexOf(".");
3076
+ return i > 0 ? name.slice(0, i) : name;
3077
+ }
3078
+ function isJunkPath(path) {
3079
+ if (path.endsWith("/")) return true;
3080
+ const parts = path.split("/");
3081
+ if (parts.some((p) => p === "__MACOSX")) return true;
3082
+ return parts[parts.length - 1].startsWith(".");
3083
+ }
3084
+ function folderFor(slug, relDir) {
3085
+ const root = `${SKILL_FOLDER_PREFIX}${slug}`;
3086
+ return relDir ? `${root}/${relDir}` : root;
3087
+ }
3088
+ function importMarkdownSkill(fileName, text) {
3089
+ const parsed = parseSkillFrontmatter(text, fileName);
3090
+ const slug = skillSlug(parsed.name) || skillSlug(stripExt(fileName));
3091
+ if (!slug) {
3092
+ throw new Error(
3093
+ "Could not derive a skill name. Add a `name:` to the frontmatter or rename the file."
3094
+ );
3095
+ }
3096
+ return {
3097
+ slug,
3098
+ entries: [{ folder: folderFor(slug, ""), fileName: SKILL_MAIN_FILENAME, content: text }]
3099
+ };
3100
+ }
3101
+ function commonTopDir(paths) {
3102
+ const tops = /* @__PURE__ */ new Set();
3103
+ for (const p of paths) {
3104
+ const idx = p.indexOf("/");
3105
+ if (idx === -1) return null;
3106
+ tops.add(p.slice(0, idx));
3107
+ }
3108
+ return tops.size === 1 ? [...tops][0] : null;
3109
+ }
3110
+ function buildZipSkillImport(archiveName, rawEntries) {
3111
+ const entries = rawEntries.filter((e) => e.path && !isJunkPath(e.path));
3112
+ if (entries.length === 0) throw new Error("The archive contains no importable skill files.");
3113
+ const top = commonTopDir(entries.map((e) => e.path));
3114
+ const rel = (p) => top ? p.slice(top.length + 1) : p;
3115
+ let slug = top ? skillSlug(top) : "";
3116
+ if (!slug) {
3117
+ const mainGuess = entries.find((e) => {
3118
+ const r = rel(e.path);
3119
+ return !r.includes("/") && isMainSkillFile(r, "__never__");
3120
+ }) ?? entries.find((e) => !rel(e.path).includes("/"));
3121
+ if (mainGuess) slug = skillSlug(parseSkillFrontmatter(mainGuess.text, rel(mainGuess.path)).name);
3122
+ }
3123
+ if (!slug) slug = skillSlug(stripExt(archiveName));
3124
+ if (!slug) throw new Error("Could not derive a skill name from the archive.");
3125
+ const rootFiles = entries.filter((e) => !rel(e.path).includes("/"));
3126
+ const mainEntry = rootFiles.find((e) => isMainSkillFile(rel(e.path), slug)) ?? (rootFiles.length === 1 ? rootFiles[0] : void 0);
3127
+ return {
3128
+ slug,
3129
+ entries: entries.map((e) => {
3130
+ const r = rel(e.path);
3131
+ const lastSlash = r.lastIndexOf("/");
3132
+ return {
3133
+ folder: folderFor(slug, lastSlash === -1 ? "" : r.slice(0, lastSlash)),
3134
+ fileName: mainEntry && e.path === mainEntry.path ? SKILL_MAIN_FILENAME : lastSlash === -1 ? r : r.slice(lastSlash + 1),
3135
+ content: e.text
3136
+ };
3137
+ })
3138
+ };
3139
+ }
3140
+ async function readSkillArchive(file) {
3141
+ const data = new Uint8Array(await file.arrayBuffer());
3142
+ let files;
3143
+ try {
3144
+ files = await new Promise(
3145
+ (resolve, reject) => fflate.unzip(
3146
+ data,
3147
+ { filter: (f) => !isJunkPath(f.name) },
3148
+ (err, out) => err ? reject(err) : resolve(out)
3149
+ )
3150
+ );
3151
+ } catch {
3152
+ throw new Error("The archive is empty or could not be read.");
3153
+ }
3154
+ const entries = Object.entries(files).map(([path, bytes]) => ({ path, text: fflate.strFromU8(bytes) }));
3155
+ if (entries.length === 0) throw new Error("The archive is empty or could not be read.");
3156
+ return entries;
3157
+ }
3158
+ async function importSkillFile(file) {
3159
+ const lower = file.name.toLowerCase();
3160
+ if (lower.endsWith(".zip")) return buildZipSkillImport(file.name, await readSkillArchive(file));
3161
+ if (lower.endsWith(".md") || lower.endsWith(".markdown")) {
3162
+ return importMarkdownSkill(file.name, await file.text());
3163
+ }
3164
+ throw new Error("Unsupported file type. Choose a .md skill or a .zip archive.");
3165
+ }
3166
+ async function importSkillFromUrl(url) {
3167
+ let parsed;
3168
+ try {
3169
+ parsed = new URL(url.trim());
3170
+ } catch {
3171
+ throw new Error("That does not look like a link.");
3172
+ }
3173
+ const response = await fetch(parsed.toString());
3174
+ if (!response.ok) throw new Error(`Could not open the link (${response.status}).`);
3175
+ const text = await response.text();
3176
+ const last = parsed.pathname.split("/").filter(Boolean).pop() ?? "skill";
3177
+ return importMarkdownSkill(last.includes(".") ? last : `${last}.md`, text);
3178
+ }
3179
+ function PersonPill({ person, size = "sm", testId }) {
3180
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": testId, className: "inline-flex min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
3181
+ ui.UserEntity,
3182
+ {
3183
+ variant: "pill",
3184
+ size,
3185
+ interactive: false,
3186
+ showTooltip: false,
3187
+ initials: chunkKDG6FER6_cjs.initials(person.label),
3188
+ displayName: person.label,
3189
+ avatarStyle: person.id ? ui.getEntityColorStyles(person.id) : void 0,
3190
+ isAgent: person.isAgent,
3191
+ isMe: person.isMe
3192
+ }
3193
+ ) });
3194
+ }
3195
+ var DEFAULT_TASK_TRIGGER_CHIP_LABELS = {
3196
+ after: (name) => `After \u201C${name}\u201D is done`,
3197
+ afterUnknown: "After another task is done",
3198
+ onDemand: "Manual"
3199
+ };
3200
+ function TriggerIcon({ type, chained }) {
3201
+ const cls = "size-3.5 shrink-0 text-muted-foreground";
3202
+ if (chained) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: cls, "aria-hidden": true });
3203
+ switch (type) {
3204
+ case "on_demand":
3205
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointerClick, { className: cls, "aria-hidden": true });
3206
+ case "recurring":
3207
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: cls, "aria-hidden": true });
3208
+ case "event":
3209
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: cls, "aria-hidden": true });
3210
+ default:
3211
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: cls, "aria-hidden": true });
3212
+ }
3213
+ }
3214
+ function TaskTriggerChip({
3215
+ id,
3216
+ triggerType,
3217
+ summary,
3218
+ afterTaskId,
3219
+ afterTaskName,
3220
+ testId,
3221
+ labels
3222
+ }) {
3223
+ const l = { ...DEFAULT_TASK_TRIGGER_CHIP_LABELS, ...labels };
3224
+ const chained = Boolean(afterTaskId);
3225
+ const text = chained ? afterTaskName ? l.after(afterTaskName) : l.afterUnknown : triggerType === "on_demand" ? l.onDemand : summary;
3226
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3227
+ "span",
3228
+ {
3229
+ className: "inline-flex min-w-0 max-w-full items-center gap-1.5 text-sm font-normal text-foreground",
3230
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-trigger-${id}` }),
3231
+ "data-trigger": chained ? "task" : triggerType,
3232
+ children: [
3233
+ /* @__PURE__ */ jsxRuntime.jsx(TriggerIcon, { type: triggerType, chained }),
3234
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: text })
3235
+ ]
3236
+ }
3237
+ );
3238
+ }
3239
+
3240
+ // src/agents/tasks/workflowRows.ts
3241
+ var isSkillRow = (row) => row.kind === "skill";
3242
+ var hasTrigger = (row) => !row.on_demand && Boolean(row.rrule || row.run_at || row.event_kind || row.after_conversation_ext_id);
3243
+ function workflowStatus(row) {
3244
+ if (isSkillRow(row) || !hasTrigger(row)) return "on_demand";
3245
+ return row.active ? "active" : "paused";
3246
+ }
3247
+ function workflowTriggerType(workflow) {
3248
+ if (workflow.on_demand) return "on_demand";
3249
+ if (workflow.after_conversation_ext_id) return "after";
3250
+ if (workflow.event_kind) return "event";
3251
+ if (workflow.rrule) return "recurring";
3252
+ if (workflow.run_at) return "one_time";
3253
+ return "on_demand";
3254
+ }
3255
+ function workflowRunStatusLabel(status) {
3256
+ if (!status) return "None";
3257
+ const labels = {
3258
+ completed: "Success",
3259
+ success: "Success",
3260
+ failed: "Failed",
3261
+ running: "In progress",
3262
+ awaiting_authorization: "Awaiting access"
3263
+ };
3264
+ return labels[status] ?? status.replaceAll("_", " ");
3265
+ }
3266
+ function listedRunStatus(status, threadStatus) {
3267
+ if (threadStatus === "done" && status === "running") return "completed";
3268
+ return status;
3269
+ }
3270
+
3271
+ // src/agents/tasks/workflowColumns.tsx
3272
+ var WORKFLOW_COLUMN_ORDER = [
3273
+ "name",
3274
+ "trigger",
3275
+ "last_run",
3276
+ "result",
3277
+ "status",
3278
+ "shared",
3279
+ "actions"
3280
+ ];
3281
+ function cell(render) {
3282
+ return (params) => params.data ? render(params.data) : null;
3283
+ }
3284
+ var time = (iso) => iso ? Date.parse(iso) : Number.POSITIVE_INFINITY;
3285
+ function createWorkflowColumns(o) {
3286
+ const l = o.labels;
3287
+ const base = {
3288
+ sortable: false,
3289
+ cellStyle: { display: "flex", alignItems: "center" }
3290
+ };
3291
+ return [
3292
+ {
3293
+ ...base,
3294
+ colId: "name",
3295
+ sortable: true,
3296
+ headerName: l.colName,
3297
+ flex: 3,
3298
+ minWidth: 210,
3299
+ valueGetter: (p) => p.data?.name.toLowerCase() ?? "",
3300
+ cellRenderer: cell(o.renderName)
3301
+ },
3302
+ {
3303
+ ...base,
3304
+ colId: "trigger",
3305
+ headerName: l.colTrigger,
3306
+ flex: 2.4,
3307
+ minWidth: 185,
3308
+ valueGetter: (p) => p.data ? o.getTriggerText(p.data) : "",
3309
+ cellRenderer: cell(o.renderTrigger)
3310
+ },
3311
+ {
3312
+ ...base,
3313
+ colId: "last_run",
3314
+ sortable: true,
3315
+ headerName: l.colLastRun,
3316
+ flex: 1.4,
3317
+ minWidth: 140,
3318
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
3319
+ valueGetter: (p) => time(p.data?.last_fired_at),
3320
+ cellRenderer: cell(o.renderLastRun)
3321
+ },
3322
+ {
3323
+ ...base,
3324
+ colId: "result",
3325
+ headerName: "Result",
3326
+ width: 130,
3327
+ valueGetter: (p) => p.data?.last_run_status ?? "",
3328
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
3329
+ cellRenderer: cell(o.renderResult)
3330
+ },
3331
+ {
3332
+ ...base,
3333
+ colId: "status",
3334
+ sortable: true,
3335
+ headerName: l.colStatus,
3336
+ width: 120,
3337
+ valueGetter: (p) => p.data ? workflowStatus(p.data) : "",
3338
+ cellRenderer: cell(o.renderStatus)
3339
+ },
3340
+ {
3341
+ ...base,
3342
+ colId: "shared",
3343
+ headerName: l.colShared,
3344
+ headerTooltip: l.shared,
3345
+ width: 96,
3346
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "center" },
3347
+ valueGetter: (p) => p.data?.shared ?? false,
3348
+ cellRenderer: cell(o.renderShared)
3349
+ },
3350
+ {
3351
+ ...base,
3352
+ colId: "actions",
3353
+ headerName: "",
3354
+ width: 180,
3355
+ minWidth: 180,
3356
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
3357
+ cellRenderer: cell(o.renderActions)
3358
+ }
3359
+ ];
3360
+ }
3361
+
3362
+ // src/agents/tasks/workflowTableLabels.ts
3363
+ var DEFAULT_WORKFLOW_LIST_LABELS = {
3364
+ colName: "Name",
3365
+ colType: "Type",
3366
+ colTrigger: "When",
3367
+ colAction: "What it does",
3368
+ colAgent: "Agent",
3369
+ colStatus: "Active",
3370
+ colShared: "Shared",
3371
+ colLastRun: "Last run",
3372
+ colNextRun: "Next run",
3373
+ shared: "Shared with the workspace",
3374
+ sharedOwnerOnly: "Only the creator can change who can see this",
3375
+ deleteOwnerOnly: "Only the creator or workspace owner can delete this",
3376
+ typeSkill: "Skill",
3377
+ typeWorkflow: "Workflow",
3378
+ statusActive: "Active",
3379
+ statusPaused: "Inactive",
3380
+ statusOnDemand: "On demand",
3381
+ activeSwitch: (name) => `Active: \u201C${name}\u201D`,
3382
+ agent: "Agent",
3383
+ myAssistant: "My assistant",
3384
+ me: "Me",
3385
+ someone: "Someone",
3386
+ never: "Never",
3387
+ none: "\u2014",
3388
+ reminder: "Reminder",
3389
+ failed: "Failed",
3390
+ lastRunFailed: "Last run failed",
3391
+ openLastRun: "Open the task this run created",
3392
+ editWorkflow: "Edit",
3393
+ run: "Run",
3394
+ runLater: "Run later",
3395
+ runNow: "Run now",
3396
+ runs: "Runs",
3397
+ delete: "Delete",
3398
+ moreActions: "More actions",
3399
+ searchLabel: "Search workflows",
3400
+ searchPlaceholder: "Search workflows and skills\u2026",
3401
+ emptyTitle: "Nothing to run yet",
3402
+ emptyMessage: "Skills and workflows you can run will appear here.",
3403
+ firstRun: "Run a skill now, or choose Run later to save it as a workflow that runs on its own.",
3404
+ noMatches: "Nothing in this view.",
3405
+ filterAll: "All",
3406
+ filterSkills: "Skills",
3407
+ filterWorkflows: "Workflows",
3408
+ filterActive: "Active",
3409
+ filterPaused: "Inactive",
3410
+ makeActive: "Make active",
3411
+ makePaused: "Deactivate",
3412
+ selectAll: "Select all",
3413
+ selectWorkflow: (name) => `Select ${name}`
3414
+ };
3415
+ var ROW_HEIGHT = 40;
3416
+ function WorkflowsTable(props) {
3417
+ const { workflows, isLoading, busyId, header, testId } = props;
3418
+ const l = { ...DEFAULT_WORKFLOW_LIST_LABELS, ...props.labels };
3419
+ const [filterStates, setFilterStates] = react.useState(/* @__PURE__ */ new Map());
3420
+ const [filterOpen, setFilterOpen] = react.useState(false);
3421
+ const [query, setQuery] = react.useState("");
3422
+ const [selected, setSelected] = react.useState([]);
3423
+ const apiRef = react.useRef(null);
3424
+ const q = query.trim().toLowerCase();
3425
+ const matches = (w) => !q || `${w.name} ${w.description ?? ""} ${w.prompt ?? ""} ${w.skill_ref ?? ""}`.toLowerCase().includes(q);
3426
+ const inFilter = (w, f) => f === "all" || f === "skills" && isSkillRow(w) || f === "workflows" && !isSkillRow(w) || f === "active" && workflowStatus(w) === "active" || f === "paused" && workflowStatus(w) === "paused";
3427
+ const counts = react.useMemo(() => {
3428
+ const out = { all: 0, skills: 0, workflows: 0, active: 0, paused: 0 };
3429
+ for (const w of workflows) {
3430
+ if (!matches(w)) continue;
3431
+ for (const f of Object.keys(out)) if (inFilter(w, f)) out[f] += 1;
3432
+ }
3433
+ return out;
3434
+ }, [workflows, q]);
3435
+ const shown = react.useMemo(
3436
+ () => workflows.filter((w) => {
3437
+ if (!matches(w)) return false;
3438
+ for (const group of [
3439
+ ["skills", "workflows"],
3440
+ ["active", "paused"]
3441
+ ]) {
3442
+ const included = group.filter((f) => filterStates.get(f) === "include");
3443
+ if (included.length && !included.some((f) => inFilter(w, f))) return false;
3444
+ if (group.some((f) => filterStates.get(f) === "exclude" && inFilter(w, f))) return false;
3445
+ }
3446
+ return true;
3447
+ }),
3448
+ [workflows, filterStates, q]
3449
+ );
3450
+ const renderPerson = props.renderPerson ?? ((p) => /* @__PURE__ */ jsxRuntime.jsx(PersonPill, { person: p }));
3451
+ const actionText = (w) => {
3452
+ if (w.action)
3453
+ return w.action.type === "email_documents" ? "Email latest documents" : "AI Review";
3454
+ if (isSkillRow(w))
3455
+ return w.description || w.skill_ref && props.skillNames?.[w.skill_ref] || w.name;
3456
+ return w.skill_ref ? props.skillNames?.[w.skill_ref] ?? w.skill_ref : w.prompt?.trim() || l.reminder;
3457
+ };
3458
+ const latest = react.useRef({ props, l, renderPerson, actionText });
3459
+ latest.current = { props, l, renderPerson, actionText };
3460
+ const columnDefs = react.useMemo(
3461
+ () => createWorkflowColumns({
3462
+ labels: l,
3463
+ getTriggerText: (w) => isSkillRow(w) ? l.statusOnDemand : latest.current.props.describeTrigger(w),
3464
+ renderName: (w) => {
3465
+ const { l: lb } = latest.current;
3466
+ const skill = isSkillRow(w);
3467
+ const text = skill ? latest.current.actionText(w) : w.description || latest.current.actionText(w);
3468
+ const stem = w.name.replace(/…$/, "").trim();
3469
+ const about = text && text.trim() !== w.name.trim() && text.trim() !== stem ? text : "";
3470
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 leading-tight", children: [
3471
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
3472
+ /* @__PURE__ */ jsxRuntime.jsx(
3473
+ "span",
3474
+ {
3475
+ className: ui.cn(
3476
+ "truncate text-sm font-normal",
3477
+ workflowStatus(w) === "paused" && "text-muted-foreground"
3478
+ ),
3479
+ "data-testid": `workflow-name-${w.external_id}`,
3480
+ children: w.name
3481
+ }
3482
+ ),
3483
+ skill && /* @__PURE__ */ jsxRuntime.jsx(
3484
+ "span",
3485
+ {
3486
+ className: "shrink-0 rounded-full border border-border px-1.5 text-[11px] text-muted-foreground",
3487
+ "data-testid": `workflow-type-${w.external_id}`,
3488
+ children: lb.typeSkill
3489
+ }
3490
+ )
3491
+ ] }),
3492
+ about && !latest.current.props.automationsOnly && /* @__PURE__ */ jsxRuntime.jsx(
3493
+ "p",
3494
+ {
3495
+ className: "truncate text-xs text-muted-foreground",
3496
+ "data-testid": `workflow-action-${w.external_id}`,
3497
+ children: about
3498
+ }
3499
+ )
3500
+ ] });
3501
+ },
3502
+ renderTrigger: (w) => {
3503
+ const { props: p } = latest.current;
3504
+ const after = w.after_conversation_ext_id;
3505
+ const skill = isSkillRow(w);
3506
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 leading-tight", children: /* @__PURE__ */ jsxRuntime.jsx(
3507
+ TaskTriggerChip,
3508
+ {
3509
+ id: w.external_id,
3510
+ testId: `workflow-trigger-${w.external_id}`,
3511
+ triggerType: workflowTriggerType(w),
3512
+ summary: skill ? "" : p.describeTrigger(w),
3513
+ afterTaskId: after,
3514
+ afterTaskName: after ? p.taskNames?.[after] : void 0,
3515
+ labels: p.triggerChipLabels
3516
+ }
3517
+ ) });
3518
+ },
3519
+ renderStatus: (w) => {
3520
+ const { props: p, l: lb } = latest.current;
3521
+ const canEdit = w.is_owner !== false || Boolean(p.canEditShared);
3522
+ return /* @__PURE__ */ jsxRuntime.jsx(
3523
+ ui.Switch,
3524
+ {
3525
+ checked: hasTrigger(w) && !isSkillRow(w) && Boolean(w.active),
3526
+ disabled: !hasTrigger(w) || isSkillRow(w) || !canEdit || p.busyId === w.external_id,
3527
+ onCheckedChange: (next) => p.onToggleActive(w, next),
3528
+ className: "disabled:data-[state=unchecked]:bg-muted dark:disabled:data-[state=unchecked]:bg-muted",
3529
+ "aria-label": lb.activeSwitch(w.name),
3530
+ "data-testid": `workflow-active-${w.external_id}`
3531
+ }
3532
+ );
3533
+ },
3534
+ renderShared: (w) => {
3535
+ const { props: p, l: lb } = latest.current;
3536
+ if (!p.onToggleShared || isSkillRow(w)) return null;
3537
+ const isCreator = w.is_owner !== false;
3538
+ return /* @__PURE__ */ jsxRuntime.jsx(
3539
+ ui.VisibilityToggle,
3540
+ {
3541
+ items: { shared: w.shared ?? false },
3542
+ onToggle: (share) => latest.current.props.onToggleShared?.(w, share),
3543
+ disabled: !isCreator || p.busyId === w.external_id,
3544
+ disabledTooltip: lb.sharedOwnerOnly,
3545
+ showLabel: false,
3546
+ "data-testid": `workflow-shared-${w.external_id}`
3547
+ }
3548
+ );
3549
+ },
3550
+ renderLastRun: (w) => {
3551
+ const { props: p, l: lb } = latest.current;
3552
+ const at = w.last_fired_at ?? p.lastRuns?.[w.external_id]?.at;
3553
+ return /* @__PURE__ */ jsxRuntime.jsx(
3554
+ "button",
3555
+ {
3556
+ type: "button",
3557
+ className: "h-full w-full truncate px-4 text-left text-sm hover:text-primary",
3558
+ onClick: () => p.onViewRuns?.(w),
3559
+ title: "View run history",
3560
+ "data-testid": `workflow-last-run-${w.external_id}`,
3561
+ children: at ? p.formatDate(at) : lb.never
3562
+ }
3563
+ );
3564
+ },
3565
+ renderResult: (w) => {
3566
+ const status = listedRunStatus(
3567
+ w.last_run_status,
3568
+ latest.current.props.lastRuns?.[w.external_id]?.threadStatus
3569
+ );
3570
+ const label = workflowRunStatusLabel(status);
3571
+ return /* @__PURE__ */ jsxRuntime.jsx(
3572
+ "button",
3573
+ {
3574
+ type: "button",
3575
+ onClick: () => latest.current.props.onViewRuns?.(w),
3576
+ title: "View run history",
3577
+ className: ui.cn(
3578
+ ui.badgeVariants({ variant: "outline" }),
3579
+ "mx-4 cursor-pointer text-xs font-medium",
3580
+ status === "failed" ? "border-red-border bg-red-bg text-red-text hover:bg-red-bg/80" : status === "completed" || status === "success" ? "border-green-border bg-green-bg text-green-text hover:bg-green-bg/80" : status ? "border-primary/20 bg-primary/10 text-primary hover:bg-primary/15" : "border-border bg-muted text-muted-foreground hover:bg-muted/80"
3581
+ ),
3582
+ "data-testid": `workflow-result-${w.external_id}`,
3583
+ children: label
3584
+ }
3585
+ );
3586
+ },
3587
+ renderActions: (w) => {
3588
+ const { props: p, l: lb } = latest.current;
3589
+ const id = w.external_id;
3590
+ const skill = isSkillRow(w);
3591
+ const busy = p.busyId === id;
3592
+ const isOwner = w.is_owner !== false;
3593
+ const canEdit = isOwner || Boolean(p.canEditShared);
3594
+ const canAdmin = isOwner || Boolean(p.isWorkspaceOwner);
3595
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1", children: [
3596
+ (skill || canEdit) && /* @__PURE__ */ jsxRuntime.jsxs(
3597
+ ui.Button,
3598
+ {
3599
+ size: "sm",
3600
+ variant: "outline",
3601
+ className: "h-8 gap-1.5 pointer-coarse:h-11",
3602
+ disabled: busy,
3603
+ onClick: () => p.onRun(w),
3604
+ "data-testid": `workflow-run-btn-${id}`,
3605
+ children: [
3606
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-3.5", "aria-hidden": true }),
3607
+ lb.run
3608
+ ]
3609
+ }
3610
+ ),
3611
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
3612
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3613
+ ui.Button,
3614
+ {
3615
+ variant: "ghost",
3616
+ size: "icon",
3617
+ className: "size-8 pointer-coarse:size-11",
3618
+ "aria-label": lb.moreActions,
3619
+ "data-testid": `workflow-menu-${id}`,
3620
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4", "aria-hidden": true })
3621
+ }
3622
+ ) }),
3623
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", children: [
3624
+ skill && p.onRunLater && /* @__PURE__ */ jsxRuntime.jsxs(
3625
+ ui.DropdownMenuItem,
3626
+ {
3627
+ onSelect: () => p.onRunLater?.(w),
3628
+ "data-testid": `workflow-run-later-${id}`,
3629
+ children: [
3630
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "mr-2 size-4", "aria-hidden": true }),
3631
+ lb.runLater
3632
+ ]
3633
+ }
3634
+ ),
3635
+ !skill && canEdit && /* @__PURE__ */ jsxRuntime.jsxs(
3636
+ ui.DropdownMenuItem,
3637
+ {
3638
+ onSelect: () => p.onEdit(w),
3639
+ "data-testid": `workflow-edit-${id}`,
3640
+ children: [
3641
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "mr-2 size-4", "aria-hidden": true }),
3642
+ lb.editWorkflow
3643
+ ]
3644
+ }
3645
+ ),
3646
+ !skill && p.onViewRuns && /* @__PURE__ */ jsxRuntime.jsxs(
3647
+ ui.DropdownMenuItem,
3648
+ {
3649
+ onSelect: () => p.onViewRuns?.(w),
3650
+ "data-testid": `workflow-runs-${id}`,
3651
+ children: [
3652
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "mr-2 size-4", "aria-hidden": true }),
3653
+ lb.runs
3654
+ ]
3655
+ }
3656
+ ),
3657
+ !skill && canEdit && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3658
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
3659
+ /* @__PURE__ */ jsxRuntime.jsxs(
3660
+ ui.DropdownMenuItem,
3661
+ {
3662
+ disabled: busy || !canAdmin,
3663
+ onSelect: () => p.onDelete(w),
3664
+ title: canAdmin ? void 0 : lb.deleteOwnerOnly,
3665
+ className: "text-destructive focus:text-destructive",
3666
+ "data-testid": `workflow-delete-${id}`,
3667
+ children: [
3668
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-2 size-4", "aria-hidden": true }),
3669
+ lb.delete
3670
+ ]
3671
+ }
3672
+ )
3673
+ ] })
3674
+ ] })
3675
+ ] })
3676
+ ] });
3677
+ }
3678
+ }),
3679
+ // Stable on purpose: only the header texts rebuild the columns (see `latest`).
3680
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3681
+ [
3682
+ l.colName,
3683
+ l.colType,
3684
+ l.colTrigger,
3685
+ l.colAction,
3686
+ l.colAgent,
3687
+ l.colStatus,
3688
+ l.colShared,
3689
+ l.shared,
3690
+ l.colLastRun,
3691
+ l.colNextRun
3692
+ ]
3693
+ );
3694
+ react.useEffect(() => {
3695
+ apiRef.current?.refreshCells({ force: true });
3696
+ }, [
3697
+ busyId,
3698
+ props.agentNames,
3699
+ props.skillNames,
3700
+ props.taskNames,
3701
+ props.lastRuns,
3702
+ props.renderPerson,
3703
+ props.labels,
3704
+ props.canEditShared,
3705
+ props.isWorkspaceOwner
3706
+ ]);
3707
+ const mine = selected.filter((w) => !isSkillRow(w));
3708
+ const adminSelected = mine.filter((w) => w.is_owner !== false || props.isWorkspaceOwner);
3709
+ const editableSelected = mine.filter(
3710
+ (w) => hasTrigger(w) && (w.is_owner !== false || props.canEditShared)
3711
+ );
3712
+ const clearSelection = () => setSelected([]);
3713
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3714
+ "div",
3715
+ {
3716
+ className: "flex min-h-0 flex-1 flex-col",
3717
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "workflow-list" }),
3718
+ children: [
3719
+ /* @__PURE__ */ jsxRuntime.jsx(
3720
+ chunk7RGLTF76_cjs.TabHeader,
3721
+ {
3722
+ testId: "automations-tab-header",
3723
+ tabs: [
3724
+ {
3725
+ id: "automations",
3726
+ label: "",
3727
+ count: shown.length,
3728
+ countIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "size-3.5" }),
3729
+ countPlacement: "leading",
3730
+ presentation: "count",
3731
+ hasActiveFilters: !!q || [...filterStates.values()].some(Boolean)
3732
+ },
3733
+ ...props.tabs ?? []
3734
+ ],
3735
+ activeTabId: props.activeTabId ?? "automations",
3736
+ onTabChange: props.onTabChange ?? (() => {
3737
+ }),
3738
+ firstTabContent: /* @__PURE__ */ jsxRuntime.jsx(
3739
+ chunk2EI7NCUA_cjs.FilterInput,
3740
+ {
3741
+ value: query,
3742
+ onChange: setQuery,
3743
+ fields: ["text"],
3744
+ onFieldsChange: () => {
3745
+ },
3746
+ hideFieldPicker: true,
3747
+ ariaLabel: l.searchLabel,
3748
+ testIds: { input: "workflow-search" },
3749
+ filter: /* @__PURE__ */ jsxRuntime.jsx(
3750
+ chunkRQ2Y7USX_cjs.TriStateFilterMenu,
3751
+ {
3752
+ testId: "automations-filter-button",
3753
+ open: filterOpen,
3754
+ onOpenChange: setFilterOpen,
3755
+ filterStates,
3756
+ onFiltersChange: setFilterStates,
3757
+ triggerClassName: "flex h-5 items-center gap-0.5 rounded px-1 text-muted-foreground hover:text-foreground pointer-coarse:h-11! pointer-coarse:min-w-11 pointer-coarse:justify-center",
3758
+ renderChevron: true,
3759
+ disableHoverOpen: true,
3760
+ options: [
3761
+ ...!props.automationsOnly ? [
3762
+ { id: "skills", label: l.filterSkills, count: counts.skills },
3763
+ {
3764
+ id: "workflows",
3765
+ label: l.filterWorkflows,
3766
+ count: counts.workflows
3767
+ }
3768
+ ] : [],
3769
+ { id: "active", label: l.filterActive, count: counts.active },
3770
+ { id: "paused", label: l.filterPaused, count: counts.paused }
3771
+ ]
3772
+ }
3773
+ )
3774
+ }
3775
+ ),
3776
+ rightContent: header
3777
+ }
3778
+ ),
3779
+ props.content ? props.content : workflows.length === 0 && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
3780
+ chunkZW6FPIFC_cjs.EmptyState,
3781
+ {
3782
+ icon: lucideReact.Workflow,
3783
+ title: l.emptyTitle,
3784
+ description: l.emptyMessage,
3785
+ testId: "workflow-list-empty"
3786
+ }
3787
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
3788
+ chunkC2CWWEHO_cjs.GridView,
3789
+ {
3790
+ testId: "workflow-grid",
3791
+ gridId: props.gridId ?? "workflows-grid-v2",
3792
+ items: shown,
3793
+ columnDefs,
3794
+ getItemId: (w) => w.external_id,
3795
+ getRowTestId: (w) => `workflow-row-${w.external_id}`,
3796
+ isLoading,
3797
+ showEmpty: shown.length === 0,
3798
+ emptyState: { title: l.noMatches },
3799
+ rowHeight: ROW_HEIGHT,
3800
+ height: "100%",
3801
+ onGridReady: ({ api }) => {
3802
+ apiRef.current = api;
3803
+ },
3804
+ onRowClick: (row) => props.onOpenRow?.(row),
3805
+ selection: { mode: "multiple", selected, onSelectionChange: setSelected },
3806
+ gridOptions: GRID_OPTIONS
3807
+ }
3808
+ ) }),
3809
+ !props.content && /* @__PURE__ */ jsxRuntime.jsx(chunkV4ISCZJ7_cjs.SelectionBar, { count: selected.length, onClear: clearSelection, children: (isCompact) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3810
+ props.onToggleActiveMany && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3811
+ /* @__PURE__ */ jsxRuntime.jsx(
3812
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
3813
+ {
3814
+ icon: lucideReact.Play,
3815
+ label: l.makeActive,
3816
+ onClick: () => {
3817
+ props.onToggleActiveMany?.(editableSelected, true);
3818
+ clearSelection();
3819
+ },
3820
+ disabled: editableSelected.length === 0,
3821
+ isCompact,
3822
+ testId: "workflow-bulk-activate"
3823
+ }
3824
+ ),
3825
+ /* @__PURE__ */ jsxRuntime.jsx(
3826
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
3827
+ {
3828
+ icon: lucideReact.Workflow,
3829
+ label: l.makePaused,
3830
+ onClick: () => {
3831
+ props.onToggleActiveMany?.(editableSelected, false);
3832
+ clearSelection();
3833
+ },
3834
+ disabled: editableSelected.length === 0,
3835
+ isCompact,
3836
+ testId: "workflow-bulk-pause"
3837
+ }
3838
+ )
3839
+ ] }),
3840
+ props.onDeleteMany && /* @__PURE__ */ jsxRuntime.jsx(
3841
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
3842
+ {
3843
+ icon: lucideReact.Trash2,
3844
+ label: l.delete,
3845
+ onClick: () => {
3846
+ props.onDeleteMany?.(adminSelected);
3847
+ clearSelection();
3848
+ },
3849
+ disabled: adminSelected.length === 0,
3850
+ isCompact,
3851
+ className: "border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
3852
+ testId: "workflow-bulk-delete"
3853
+ }
3854
+ )
3855
+ ] }) })
3856
+ ]
3857
+ }
3858
+ );
3859
+ }
3860
+ var GRID_OPTIONS = { suppressClickEdit: true };
2324
3861
  var DEFAULT_TASK_ACTIVITY_LABELS = {
2325
3862
  title: "Activity",
2326
3863
  empty: "Nothing has happened yet.",
@@ -2407,12 +3944,12 @@ function taskActivityHeadline(e, labels = DEFAULT_TASK_ACTIVITY_LABELS, agentNam
2407
3944
  case "step_skipped":
2408
3945
  return "Step skipped";
2409
3946
  case "step_waiting": {
2410
- const documents = chunk6AALMYPS_cjs.eventWaitingDocuments(detail);
2411
- return documents ? chunk6AALMYPS_cjs.waitingForDocumentsText(documents.length) : "Waiting on people";
3947
+ const documents = chunk6F7SZCVL_cjs.eventWaitingDocuments(detail);
3948
+ return documents ? chunk6F7SZCVL_cjs.waitingForDocumentsText(documents.length) : "Waiting on people";
2412
3949
  }
2413
3950
  case "step_progress": {
2414
- const documents = chunk6AALMYPS_cjs.eventWaitingDocuments(detail);
2415
- return documents ? chunk6AALMYPS_cjs.waitingForDocumentsText(documents.length) : detail.signed ? "Signed" : "Step moved on";
3951
+ const documents = chunk6F7SZCVL_cjs.eventWaitingDocuments(detail);
3952
+ return documents ? chunk6F7SZCVL_cjs.waitingForDocumentsText(documents.length) : detail.signed ? "Signed" : "Step moved on";
2416
3953
  }
2417
3954
  case "step_sent_back":
2418
3955
  return "Sent the work back";
@@ -2514,13 +4051,22 @@ function TaskActivityTimeline({
2514
4051
  }
2515
4052
 
2516
4053
  exports.ActionStepBody = ActionStepBody;
4054
+ exports.AgentSelect = AgentSelect;
2517
4055
  exports.ApprovalEvidence = ApprovalEvidence;
2518
4056
  exports.AssigneeLine = AssigneeLine;
4057
+ exports.DEFAULT_AGENT_SELECT_LABELS = DEFAULT_AGENT_SELECT_LABELS;
2519
4058
  exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
2520
4059
  exports.DEFAULT_STEP_BAR_LABELS = DEFAULT_STEP_BAR_LABELS;
2521
4060
  exports.DEFAULT_TASK_ACTIVITY_LABELS = DEFAULT_TASK_ACTIVITY_LABELS;
4061
+ exports.DEFAULT_TASK_TRIGGER_CHIP_LABELS = DEFAULT_TASK_TRIGGER_CHIP_LABELS;
4062
+ exports.DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS = DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS;
4063
+ exports.DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS = DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS;
4064
+ exports.DEFAULT_WORKFLOW_LIST_LABELS = DEFAULT_WORKFLOW_LIST_LABELS;
2522
4065
  exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
2523
4066
  exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
4067
+ exports.PersonPill = PersonPill;
4068
+ exports.SKILL_MAIN_FILENAME = SKILL_MAIN_FILENAME;
4069
+ exports.SKILL_TYPES = SKILL_TYPES;
2524
4070
  exports.STEP_LABEL = STEP_LABEL;
2525
4071
  exports.STEP_LABEL_CURRENT = STEP_LABEL_CURRENT;
2526
4072
  exports.STEP_LABEL_MAX = STEP_LABEL_MAX;
@@ -2528,19 +4074,46 @@ exports.SchemaForm = SchemaForm;
2528
4074
  exports.SendBackControl = SendBackControl;
2529
4075
  exports.StepBarFrame = StepBarFrame;
2530
4076
  exports.TaskActivityTimeline = TaskActivityTimeline;
4077
+ exports.TaskTriggerChip = TaskTriggerChip;
4078
+ exports.WORKFLOW_COLUMN_ORDER = WORKFLOW_COLUMN_ORDER;
4079
+ exports.WorkflowConfigDialog = WorkflowConfigDialog;
4080
+ exports.WorkflowDocumentsField = WorkflowDocumentsField;
4081
+ exports.WorkflowLauncher = WorkflowLauncher;
2531
4082
  exports.WorkflowRunner = WorkflowRunner;
2532
4083
  exports.WorkflowStepBar = WorkflowStepBar;
4084
+ exports.WorkflowsTable = WorkflowsTable;
2533
4085
  exports.activeStepId = activeStepId;
4086
+ exports.buildWorkflowScopeSource = buildWorkflowScopeSource;
4087
+ exports.buildZipSkillImport = buildZipSkillImport;
4088
+ exports.createWorkflowColumns = createWorkflowColumns;
4089
+ exports.documentScopeLabels = documentScopeLabels;
2534
4090
  exports.fromPlanAssignee = fromPlanAssignee;
2535
4091
  exports.fromPlanDocumentRef = fromPlanDocumentRef;
2536
4092
  exports.fromPlanSteps = fromPlanSteps;
4093
+ exports.hasTrigger = hasTrigger;
4094
+ exports.importMarkdownSkill = importMarkdownSkill;
4095
+ exports.importSkillFile = importSkillFile;
4096
+ exports.importSkillFromUrl = importSkillFromUrl;
2537
4097
  exports.isIncompleteSignal = isIncompleteSignal;
4098
+ exports.isMainSkillFile = isMainSkillFile;
4099
+ exports.isSkillRow = isSkillRow;
2538
4100
  exports.layoutFromPlanSteps = layoutFromPlanSteps;
4101
+ exports.matchWorkflowScope = matchWorkflowScope;
4102
+ exports.parseSkillFrontmatter = parseSkillFrontmatter;
4103
+ exports.readSkillArchive = readSkillArchive;
4104
+ exports.serializeSkill = serializeSkill;
4105
+ exports.skillSlug = skillSlug;
2539
4106
  exports.stepWindow = stepWindow;
2540
4107
  exports.taskActivityHeadline = taskActivityHeadline;
2541
4108
  exports.toPlanAssignee = toPlanAssignee;
2542
4109
  exports.toPlanDocumentRef = toPlanDocumentRef;
2543
4110
  exports.toPlanSteps = toPlanSteps;
4111
+ exports.useControllableState = useControllableState;
2544
4112
  exports.useWorkflowView = useWorkflowView;
2545
- //# sourceMappingURL=chunk-SARREDFP.cjs.map
2546
- //# sourceMappingURL=chunk-SARREDFP.cjs.map
4113
+ exports.workflowFromSkillMarkdown = workflowFromSkillMarkdown;
4114
+ exports.workflowRunStatusLabel = workflowRunStatusLabel;
4115
+ exports.workflowStatus = workflowStatus;
4116
+ exports.workflowToSkillMarkdown = workflowToSkillMarkdown;
4117
+ exports.workflowTriggerType = workflowTriggerType;
4118
+ //# sourceMappingURL=chunk-CHVCTKF4.cjs.map
4119
+ //# sourceMappingURL=chunk-CHVCTKF4.cjs.map