@arbidocs/blocks 0.4.136 → 0.4.138

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 (110) hide show
  1. package/dist/agents/index.cjs +384 -353
  2. package/dist/agents/index.js +8 -9
  3. package/dist/agents/skills/SkillLibraryDetail.d.ts +26 -0
  4. package/dist/agents/skills/index.d.ts +2 -0
  5. package/dist/agents/skills/skillLibrary.d.ts +46 -0
  6. package/dist/agents/workflows/WorkflowDocumentsField.d.ts +42 -5
  7. package/dist/agents/workflows/index.d.ts +2 -2
  8. package/dist/agents/workflows/workspaceScope.d.ts +12 -0
  9. package/dist/calls/index.cjs +3 -3
  10. package/dist/calls/index.js +2 -2
  11. package/dist/chunk-2KUCVSFF.js +51 -0
  12. package/dist/chunk-2KUCVSFF.js.map +1 -0
  13. package/dist/{chunk-LIHRGG4M.cjs → chunk-3BI6EWKP.cjs} +2022 -89
  14. package/dist/chunk-3BI6EWKP.cjs.map +1 -0
  15. package/dist/{chunk-3FFRYZKV.js → chunk-3RJN2VTL.js} +36 -6
  16. package/dist/chunk-3RJN2VTL.js.map +1 -0
  17. package/dist/{chunk-OR4CO743.cjs → chunk-AAFX64WD.cjs} +3 -3
  18. package/dist/{chunk-OR4CO743.cjs.map → chunk-AAFX64WD.cjs.map} +1 -1
  19. package/dist/chunk-CQCC7LE7.js +210 -0
  20. package/dist/chunk-CQCC7LE7.js.map +1 -0
  21. package/dist/{chunk-ZAVEMQ37.cjs → chunk-DWZXSPMB.cjs} +3 -3
  22. package/dist/{chunk-ZAVEMQ37.cjs.map → chunk-DWZXSPMB.cjs.map} +1 -1
  23. package/dist/{chunk-VIU7AMHF.js → chunk-E5OYHJMU.js} +3 -3
  24. package/dist/{chunk-VIU7AMHF.js.map → chunk-E5OYHJMU.js.map} +1 -1
  25. package/dist/{chunk-RUB62J2X.js → chunk-ED4HHTIA.js} +3 -3
  26. package/dist/{chunk-RUB62J2X.js.map → chunk-ED4HHTIA.js.map} +1 -1
  27. package/dist/{chunk-5HFPRI3W.js → chunk-FUTMU4FR.js} +3 -3
  28. package/dist/{chunk-5HFPRI3W.js.map → chunk-FUTMU4FR.js.map} +1 -1
  29. package/dist/{chunk-C44D4WFG.cjs → chunk-HLB4DIYV.cjs} +3 -3
  30. package/dist/{chunk-C44D4WFG.cjs.map → chunk-HLB4DIYV.cjs.map} +1 -1
  31. package/dist/{chunk-N55UIXVT.cjs → chunk-JVL7HUIQ.cjs} +5 -5
  32. package/dist/{chunk-N55UIXVT.cjs.map → chunk-JVL7HUIQ.cjs.map} +1 -1
  33. package/dist/{chunk-6S5FLMWG.js → chunk-KSHKTOY2.js} +203 -7
  34. package/dist/chunk-KSHKTOY2.js.map +1 -0
  35. package/dist/{chunk-OZLWSNUC.cjs → chunk-MJKBVIV3.cjs} +83 -1650
  36. package/dist/chunk-MJKBVIV3.cjs.map +1 -0
  37. package/dist/{chunk-DJM7DLCT.cjs → chunk-OPTBQSCV.cjs} +3 -3
  38. package/dist/{chunk-DJM7DLCT.cjs.map → chunk-OPTBQSCV.cjs.map} +1 -1
  39. package/dist/{chunk-GFYGYME3.js → chunk-OQ7RUNOC.js} +3 -3
  40. package/dist/{chunk-GFYGYME3.js.map → chunk-OQ7RUNOC.js.map} +1 -1
  41. package/dist/chunk-RFIBUWLF.cjs +232 -0
  42. package/dist/chunk-RFIBUWLF.cjs.map +1 -0
  43. package/dist/{chunk-N26CXGXC.cjs → chunk-RQ2Y7USX.cjs} +201 -3
  44. package/dist/chunk-RQ2Y7USX.cjs.map +1 -0
  45. package/dist/{chunk-LT2X5N37.js → chunk-UBEI6WFJ.js} +58 -1592
  46. package/dist/chunk-UBEI6WFJ.js.map +1 -0
  47. package/dist/chunk-UUHUQHXR.cjs +56 -0
  48. package/dist/chunk-UUHUQHXR.cjs.map +1 -0
  49. package/dist/{chunk-ECERC6TI.js → chunk-VHJHY7TT.js} +3 -3
  50. package/dist/{chunk-ECERC6TI.js.map → chunk-VHJHY7TT.js.map} +1 -1
  51. package/dist/{chunk-44R3CCZT.cjs → chunk-WS5EX7DN.cjs} +37 -6
  52. package/dist/chunk-WS5EX7DN.cjs.map +1 -0
  53. package/dist/{chunk-IQU2GI6V.js → chunk-XVME4XYD.js} +1982 -93
  54. package/dist/chunk-XVME4XYD.js.map +1 -0
  55. package/dist/collaboration/index.cjs +42 -42
  56. package/dist/collaboration/index.js +2 -2
  57. package/dist/connect/docx.cjs +5 -5
  58. package/dist/connect/docx.js +4 -4
  59. package/dist/connect/index.cjs +710 -51
  60. package/dist/connect/index.cjs.map +1 -1
  61. package/dist/connect/index.d.ts +4 -0
  62. package/dist/connect/index.js +655 -20
  63. package/dist/connect/index.js.map +1 -1
  64. package/dist/connection/ConnectedSkillsLibrary.d.ts +26 -0
  65. package/dist/connection/ConnectedWorkflowBuilder.d.ts +1 -1
  66. package/dist/connection/ConnectedWorkflowLauncher.d.ts +35 -0
  67. package/dist/connection/ConnectedWorkflowsTable.d.ts +62 -0
  68. package/dist/connection/workspaceData.d.ts +45 -0
  69. package/dist/facts/index.cjs +2 -2
  70. package/dist/facts/index.js +2 -2
  71. package/dist/files/index.cjs +3 -3
  72. package/dist/files/index.js +3 -3
  73. package/dist/home/index.cjs +22 -23
  74. package/dist/home/index.cjs.map +1 -1
  75. package/dist/home/index.js +4 -5
  76. package/dist/home/index.js.map +1 -1
  77. package/dist/index.cjs +503 -472
  78. package/dist/index.cjs.map +1 -1
  79. package/dist/index.js +12 -13
  80. package/dist/index.js.map +1 -1
  81. package/dist/retrieval/index.cjs +1 -1
  82. package/dist/retrieval/index.js +1 -1
  83. package/dist/settings/index.cjs +49 -49
  84. package/dist/settings/index.js +6 -6
  85. package/dist/shell/index.cjs +2 -2
  86. package/dist/shell/index.js +2 -2
  87. package/dist/studio/index.cjs +2 -2
  88. package/dist/studio/index.js +2 -2
  89. package/dist/workflow-canvas/index.cjs +32 -30
  90. package/dist/workflow-canvas/index.cjs.map +1 -1
  91. package/dist/workflow-canvas/index.js +20 -18
  92. package/dist/workflow-canvas/index.js.map +1 -1
  93. package/node_modules/@arbidocs/coedit/package.json +1 -1
  94. package/package.json +4 -4
  95. package/dist/chunk-3FFRYZKV.js.map +0 -1
  96. package/dist/chunk-44R3CCZT.cjs.map +0 -1
  97. package/dist/chunk-4XJZ6AAY.js +0 -407
  98. package/dist/chunk-4XJZ6AAY.js.map +0 -1
  99. package/dist/chunk-6S5FLMWG.js.map +0 -1
  100. package/dist/chunk-7D737FLE.cjs +0 -43
  101. package/dist/chunk-7D737FLE.cjs.map +0 -1
  102. package/dist/chunk-IQU2GI6V.js.map +0 -1
  103. package/dist/chunk-LIHRGG4M.cjs.map +0 -1
  104. package/dist/chunk-LT2X5N37.js.map +0 -1
  105. package/dist/chunk-N26CXGXC.cjs.map +0 -1
  106. package/dist/chunk-OZLWSNUC.cjs.map +0 -1
  107. package/dist/chunk-S5HZBXZA.cjs +0 -430
  108. package/dist/chunk-S5HZBXZA.cjs.map +0 -1
  109. package/dist/chunk-XD2M6LIG.js +0 -41
  110. package/dist/chunk-XD2M6LIG.js.map +0 -1
@@ -1,11 +1,18 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunk7D737FLE_cjs = require('./chunk-7D737FLE.cjs');
4
+ var chunkWS5EX7DN_cjs = require('./chunk-WS5EX7DN.cjs');
5
+ var chunkRQ2Y7USX_cjs = require('./chunk-RQ2Y7USX.cjs');
6
+ var chunkZW6FPIFC_cjs = require('./chunk-ZW6FPIFC.cjs');
5
7
  var chunkDETZZBG2_cjs = require('./chunk-DETZZBG2.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');
6
12
  var chunkOWCEQKAR_cjs = require('./chunk-OWCEQKAR.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');
@@ -310,7 +317,7 @@ function SchemaForm({
310
317
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-4", className), "data-slot": "schema-form", children: [
311
318
  common.map(render),
312
319
  advanced.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
313
- chunk7D737FLE_cjs.FoldSection,
320
+ chunkWS5EX7DN_cjs.FoldSection,
314
321
  {
315
322
  label: l.advanced,
316
323
  open: advancedOpen,
@@ -321,6 +328,610 @@ function SchemaForm({
321
328
  )
322
329
  ] });
323
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({ ...chunkOWCEQKAR_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 = chunkOWCEQKAR_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(chunkOWCEQKAR_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 = chunkOWCEQKAR_cjs.defaultInputs(workflow);
647
+ if (Object.keys(chunkOWCEQKAR_cjs.validateInputs(workflow, inputs)).length === 0) {
648
+ Promise.resolve(onLaunch(chunkOWCEQKAR_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
+ }
324
935
 
325
936
  // src/agents/workflows/planSteps.ts
326
937
  function toPlanAssignee(a) {
@@ -2363,95 +2974,496 @@ function StepNotices({
2363
2974
  ))
2364
2975
  ] });
2365
2976
  }
2366
-
2367
- // src/agents/skills/skillFiles.ts
2368
- var SKILL_TYPES = ["markdown", "python", "shell", "javascript", "typescript"];
2369
- var SKILL_MAIN_FILENAME = "SKILL.md";
2370
- var MAIN_NAMES = /* @__PURE__ */ new Set(["skill.md", "skill.py", "skill.sh", "skill.js", "skill.ts"]);
2371
- function isMainSkillFile(filename, skillName) {
2372
- const lower = filename.toLowerCase();
2373
- if (MAIN_NAMES.has(lower)) return true;
2374
- const stem = lower.includes(".") ? lower.slice(0, lower.lastIndexOf(".")) : lower;
2375
- return stem === skillName;
2376
- }
2377
- function detectTypeFromContent(content, filename) {
2378
- if (filename) {
2379
- const lower = filename.toLowerCase();
2380
- if (lower.endsWith(".py")) return "python";
2381
- if (lower.endsWith(".sh")) return "shell";
2382
- if (lower.endsWith(".js")) return "javascript";
2383
- if (lower.endsWith(".ts")) return "typescript";
2384
- }
2385
- if (content) {
2386
- const firstLine = content.split("\n", 1)[0].trim();
2387
- if (firstLine.startsWith("#!")) {
2388
- if (firstLine.includes("python")) return "python";
2389
- if (firstLine.includes("bash") || firstLine.includes("/sh")) return "shell";
2390
- if (firstLine.includes("ts-node")) return "typescript";
2391
- if (firstLine.includes("node")) return "javascript";
2977
+ function SkillTypeBadge({ type, className }) {
2978
+ return /* @__PURE__ */ jsxRuntime.jsx(
2979
+ "span",
2980
+ {
2981
+ className: ui.cn(
2982
+ "shrink-0 rounded bg-background px-1.5 py-0.5 text-xs uppercase tracking-wide text-muted-foreground",
2983
+ className
2984
+ ),
2985
+ "data-slot": "skill-type-badge",
2986
+ children: type
2392
2987
  }
2393
- }
2394
- return "markdown";
2988
+ );
2395
2989
  }
2396
- function parseSkillFrontmatter(raw, filename = "") {
2397
- const config = {};
2398
- let name = "";
2399
- let description = "";
2400
- let skillType = "markdown";
2401
- if (!raw.startsWith("---")) {
2402
- return {
2403
- content: raw,
2404
- name,
2405
- description,
2406
- config,
2407
- skillType: detectTypeFromContent(raw, filename)
2408
- };
2409
- }
2410
- const end = raw.indexOf("---", 3);
2411
- if (end === -1) {
2412
- return {
2413
- content: raw,
2414
- name,
2415
- description,
2416
- config,
2417
- skillType: detectTypeFromContent(raw, filename)
2418
- };
2419
- }
2420
- const frontmatter = raw.slice(3, end).trim();
2421
- const body = raw.slice(end + 3).trim();
2422
- for (const rawLine of frontmatter.split("\n")) {
2423
- const line = rawLine.trim();
2424
- if (!line || !line.includes(":")) continue;
2425
- const idx = line.indexOf(":");
2426
- const key = line.slice(0, idx).trim().toLowerCase();
2427
- const value = line.slice(idx + 1).trim();
2428
- if (key === "name" && value) {
2429
- name = value;
2430
- } else if (key === "description" && value) {
2431
- description = value;
2432
- } else if (key === "model" && value) {
2433
- config.model = value;
2434
- } else if (key === "temperature") {
2435
- const t = Number.parseFloat(value);
2436
- if (!Number.isNaN(t) && t >= 0 && t <= 2) config.temperature = t;
2437
- } else if (key === "agent") {
2438
- config.agent = ["true", "yes", "1"].includes(value.toLowerCase());
2439
- } else if (key === "tools" && value) {
2440
- config.tools = value.split(",").map((t) => t.trim()).filter(Boolean);
2441
- } else if (key === "type" && value) {
2442
- const v = value.toLowerCase();
2443
- if (v === "python" || v === "py") skillType = "python";
2444
- else if (v === "shell" || v === "sh" || v === "bash") skillType = "shell";
2445
- else if (v === "javascript" || v === "js" || v === "node") skillType = "javascript";
2446
- else if (v === "typescript" || v === "ts") skillType = "typescript";
2990
+ var DEFAULT_SKILL_GLOBAL_BADGE_LABELS = {
2991
+ global: "Global",
2992
+ globalTitle: "Shared with everyone in the marketplace"
2993
+ };
2994
+ function SkillGlobalBadge({
2995
+ className,
2996
+ labels
2997
+ }) {
2998
+ const l = { ...DEFAULT_SKILL_GLOBAL_BADGE_LABELS, ...labels };
2999
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3000
+ "span",
3001
+ {
3002
+ className: ui.cn(
3003
+ "inline-flex shrink-0 items-center gap-1 rounded bg-accent px-1.5 py-0.5 text-xs uppercase tracking-wide text-accent-foreground",
3004
+ className
3005
+ ),
3006
+ title: l.globalTitle,
3007
+ "data-slot": "skill-global-badge",
3008
+ children: [
3009
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "size-3" }),
3010
+ l.global
3011
+ ]
2447
3012
  }
2448
- }
2449
- if (skillType === "markdown") {
2450
- skillType = detectTypeFromContent(body, filename);
2451
- }
2452
- return { content: body, name, description, config, skillType };
3013
+ );
2453
3014
  }
2454
- function serializeSkill(input) {
3015
+ function SkillActionButton({
3016
+ label,
3017
+ tooltip,
3018
+ onClick,
3019
+ children,
3020
+ testId
3021
+ }) {
3022
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
3023
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, onFocusCapture: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(
3024
+ ui.Button,
3025
+ {
3026
+ variant: "ghost",
3027
+ size: "icon",
3028
+ className: "size-7 shrink-0 pointer-coarse:size-11",
3029
+ onClick: (e) => {
3030
+ e.stopPropagation();
3031
+ onClick(e);
3032
+ },
3033
+ "aria-label": label,
3034
+ "data-testid": testId,
3035
+ children
3036
+ }
3037
+ ) }),
3038
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: tooltip ?? label }) })
3039
+ ] });
3040
+ }
3041
+ function activateOnKey(handler) {
3042
+ return (e) => {
3043
+ if (e.target !== e.currentTarget) return;
3044
+ if (e.key === "Enter" || e.key === " ") {
3045
+ e.preventDefault();
3046
+ handler();
3047
+ }
3048
+ };
3049
+ }
3050
+ var DEFAULT_SKILL_GENERATE_FORM_LABELS = {
3051
+ title: "Generate with AI",
3052
+ hint: "Describe what the skill should do. The assistant drafts it in chat, then you can edit it here.",
3053
+ placeholder: "e.g. Summarize a contract into key obligations, dates, and parties",
3054
+ generate: "Generate with AI",
3055
+ writeManually: "\u2026or write it manually"
3056
+ };
3057
+ function SkillGenerateForm({
3058
+ onGenerate,
3059
+ onManual,
3060
+ icon,
3061
+ labels,
3062
+ testIds
3063
+ }) {
3064
+ const l = { ...DEFAULT_SKILL_GENERATE_FORM_LABELS, ...labels };
3065
+ const [desc, setDesc] = react.useState("");
3066
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4", "data-slot": "skill-generate-form", children: [
3067
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-muted p-4", children: [
3068
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex items-center gap-2", children: [
3069
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wand2, { className: "size-4 text-primary" }),
3070
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: l.title })
3071
+ ] }),
3072
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-3 text-xs text-muted-foreground", children: l.hint }),
3073
+ /* @__PURE__ */ jsxRuntime.jsx(
3074
+ ui.Textarea,
3075
+ {
3076
+ value: desc,
3077
+ onChange: (e) => setDesc(e.target.value),
3078
+ rows: 4,
3079
+ placeholder: l.placeholder,
3080
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.description, { testId: "skills-panel-ai-desc" })
3081
+ }
3082
+ ),
3083
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
3084
+ ui.Button,
3085
+ {
3086
+ size: "sm",
3087
+ disabled: !desc.trim(),
3088
+ onClick: () => onGenerate(desc.trim()),
3089
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.generate, { testId: "skills-panel-ai-generate" }),
3090
+ children: [
3091
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1 [&>svg]:size-4", children: icon }),
3092
+ l.generate
3093
+ ]
3094
+ }
3095
+ ) })
3096
+ ] }),
3097
+ /* @__PURE__ */ jsxRuntime.jsx(
3098
+ "button",
3099
+ {
3100
+ type: "button",
3101
+ className: "self-start text-sm text-muted-foreground underline-offset-2 hover:text-foreground hover:underline pointer-coarse:min-h-11",
3102
+ onClick: onManual,
3103
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.writeManually, { testId: "skills-panel-write-manually" }),
3104
+ children: l.writeManually
3105
+ }
3106
+ )
3107
+ ] });
3108
+ }
3109
+ var DEFAULT_SKILL_EDIT_FORM_LABELS = {
3110
+ name: "Name",
3111
+ namePlaceholder: "contract-summary",
3112
+ invokedAs: (name) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3113
+ "Invoked as ",
3114
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
3115
+ "/",
3116
+ name || "skill-name"
3117
+ ] })
3118
+ ] }),
3119
+ description: "Description",
3120
+ descriptionPlaceholder: "What it does and when to use it",
3121
+ instructions: "Instructions",
3122
+ cancel: "Cancel",
3123
+ saving: "Saving\u2026",
3124
+ saveChanges: "Save changes",
3125
+ create: "Create skill"
3126
+ };
3127
+ var FIELD_LABEL = "text-xs font-semibold uppercase tracking-wide text-muted-foreground";
3128
+ function SkillEditForm({
3129
+ name,
3130
+ onNameChange,
3131
+ isNameLocked,
3132
+ nameError,
3133
+ description,
3134
+ onDescriptionChange,
3135
+ editor,
3136
+ isSaving,
3137
+ isEditing,
3138
+ onSave,
3139
+ onCancel,
3140
+ labels,
3141
+ testIds
3142
+ }) {
3143
+ const l = { ...DEFAULT_SKILL_EDIT_FORM_LABELS, ...labels };
3144
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-slot": "skill-edit-form", children: [
3145
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-4", children: [
3146
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3147
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "sp-name", className: FIELD_LABEL, children: l.name }),
3148
+ /* @__PURE__ */ jsxRuntime.jsx(
3149
+ ui.Input,
3150
+ {
3151
+ id: "sp-name",
3152
+ value: name,
3153
+ disabled: isNameLocked,
3154
+ placeholder: l.namePlaceholder,
3155
+ onChange: (e) => onNameChange(e.target.value),
3156
+ className: "mt-1",
3157
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.name, { testId: "skills-panel-edit-name" })
3158
+ }
3159
+ ),
3160
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: l.invokedAs(name) }),
3161
+ nameError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: nameError })
3162
+ ] }),
3163
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3164
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "sp-desc", className: FIELD_LABEL, children: l.description }),
3165
+ /* @__PURE__ */ jsxRuntime.jsx(
3166
+ ui.Input,
3167
+ {
3168
+ id: "sp-desc",
3169
+ value: description,
3170
+ placeholder: l.descriptionPlaceholder,
3171
+ onChange: (e) => onDescriptionChange(e.target.value),
3172
+ className: "mt-1",
3173
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.description, { testId: "skills-panel-edit-desc" })
3174
+ }
3175
+ )
3176
+ ] }),
3177
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
3178
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: `${FIELD_LABEL} mb-1`, children: l.instructions }),
3179
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[240px] flex-1 overflow-hidden rounded-md border border-border", children: editor })
3180
+ ] })
3181
+ ] }),
3182
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end gap-2 border-t border-border px-4 py-3", children: [
3183
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", size: "sm", onClick: onCancel, children: l.cancel }),
3184
+ /* @__PURE__ */ jsxRuntime.jsx(
3185
+ ui.Button,
3186
+ {
3187
+ size: "sm",
3188
+ onClick: onSave,
3189
+ disabled: isSaving,
3190
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.save, { testId: "skills-panel-edit-save" }),
3191
+ children: isSaving ? l.saving : isEditing ? l.saveChanges : l.create
3192
+ }
3193
+ )
3194
+ ] })
3195
+ ] });
3196
+ }
3197
+ function SkillFilterChips({
3198
+ options,
3199
+ value,
3200
+ onChange,
3201
+ label,
3202
+ testIdPrefix = "skills-filter",
3203
+ className
3204
+ }) {
3205
+ return /* @__PURE__ */ jsxRuntime.jsx(
3206
+ "div",
3207
+ {
3208
+ role: "radiogroup",
3209
+ "aria-label": label,
3210
+ className: ui.cn("flex flex-wrap gap-2", className),
3211
+ "data-slot": "skill-filter-chips",
3212
+ children: options.map((option) => {
3213
+ const selected = option.id === value;
3214
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3215
+ "button",
3216
+ {
3217
+ type: "button",
3218
+ role: "radio",
3219
+ "aria-checked": selected,
3220
+ onClick: () => onChange(option.id),
3221
+ "data-testid": `${testIdPrefix}-${option.id}`,
3222
+ className: ui.cn(
3223
+ "inline-flex min-h-8 items-center gap-1.5 rounded-full border px-3 text-sm transition-colors pointer-coarse:min-h-11 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3224
+ selected ? "border-primary bg-primary/10 text-foreground" : "border-border bg-background text-muted-foreground [&:hover]:bg-muted"
3225
+ ),
3226
+ children: [
3227
+ option.label,
3228
+ option.count !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: option.count })
3229
+ ]
3230
+ },
3231
+ option.id
3232
+ );
3233
+ })
3234
+ }
3235
+ );
3236
+ }
3237
+ var DEFAULT_SKILL_VIEW_TOGGLE_LABELS = {
3238
+ group: "View",
3239
+ gallery: "Gallery",
3240
+ list: "List"
3241
+ };
3242
+ function SkillViewToggle({ value, onChange, labels, testId }) {
3243
+ const l = { ...DEFAULT_SKILL_VIEW_TOGGLE_LABELS, ...labels };
3244
+ const item = (view, label, icon) => /* @__PURE__ */ jsxRuntime.jsx(
3245
+ "button",
3246
+ {
3247
+ type: "button",
3248
+ role: "radio",
3249
+ "aria-checked": value === view,
3250
+ "aria-label": label,
3251
+ title: label,
3252
+ onClick: () => onChange(view),
3253
+ "data-testid": `${testId ?? "skills-view-toggle"}-${view}`,
3254
+ className: ui.cn(
3255
+ "flex size-8 items-center justify-center rounded-md pointer-coarse:size-11 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3256
+ value === view ? "bg-background text-foreground shadow-sm" : "text-muted-foreground"
3257
+ ),
3258
+ children: icon
3259
+ }
3260
+ );
3261
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3262
+ "div",
3263
+ {
3264
+ role: "radiogroup",
3265
+ "aria-label": l.group,
3266
+ className: "inline-flex shrink-0 gap-0.5 rounded-lg bg-muted p-0.5",
3267
+ "data-testid": testId ?? "skills-view-toggle",
3268
+ children: [
3269
+ item("gallery", l.gallery, /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { className: "size-4" })),
3270
+ item("list", l.list, /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "size-4" }))
3271
+ ]
3272
+ }
3273
+ );
3274
+ }
3275
+ function SkillTile({
3276
+ name,
3277
+ description,
3278
+ sourceLabel,
3279
+ type,
3280
+ icon,
3281
+ layout,
3282
+ selected,
3283
+ onSelect,
3284
+ testId
3285
+ }) {
3286
+ const isRow = layout === "list";
3287
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3288
+ "div",
3289
+ {
3290
+ role: "button",
3291
+ tabIndex: 0,
3292
+ "aria-pressed": selected,
3293
+ onClick: onSelect,
3294
+ onKeyDown: activateOnKey(onSelect),
3295
+ "data-testid": testId ?? `skill-tile-${name}`,
3296
+ "data-skill-name": name,
3297
+ "data-slot": "skill-tile",
3298
+ className: ui.cn(
3299
+ "flex cursor-pointer rounded-lg border p-3 text-left transition-colors pointer-coarse:min-h-11 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3300
+ isRow ? "items-center gap-3" : "h-full flex-col gap-2",
3301
+ selected ? "border-primary bg-primary/5" : "border-transparent bg-muted [&:hover]:bg-accent"
3302
+ ),
3303
+ children: [
3304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
3305
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-ai-ink [&>svg]:size-5", children: icon }),
3306
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate text-sm font-semibold text-foreground", children: name })
3307
+ ] }),
3308
+ /* @__PURE__ */ jsxRuntime.jsx(
3309
+ "p",
3310
+ {
3311
+ className: ui.cn(
3312
+ "min-w-0 text-sm text-muted-foreground",
3313
+ isRow ? "flex-1 truncate max-sm:hidden" : "line-clamp-3"
3314
+ ),
3315
+ children: description
3316
+ }
3317
+ ),
3318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex shrink-0 items-center gap-1.5", isRow && "ml-auto"), children: [
3319
+ type && type !== "markdown" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-background px-1.5 py-0.5 text-xs uppercase tracking-wide text-muted-foreground", children: type }),
3320
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-background px-1.5 py-0.5 text-xs text-muted-foreground", children: sourceLabel })
3321
+ ] })
3322
+ ]
3323
+ }
3324
+ );
3325
+ }
3326
+ function SkillDetail({
3327
+ title,
3328
+ sourceLabel,
3329
+ description,
3330
+ icon,
3331
+ notice,
3332
+ children,
3333
+ actions,
3334
+ testId
3335
+ }) {
3336
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3337
+ "section",
3338
+ {
3339
+ className: "flex min-h-0 flex-1 flex-col",
3340
+ "data-testid": testId ?? "skill-detail",
3341
+ "data-slot": "skill-detail",
3342
+ "aria-label": title,
3343
+ children: [
3344
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 space-y-4 overflow-y-auto p-4", children: [
3345
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "space-y-1", children: [
3346
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3347
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ai-ink [&>svg]:size-5", children: icon }),
3348
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold text-foreground", children: title }),
3349
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: sourceLabel })
3350
+ ] }),
3351
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
3352
+ notice && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: notice })
3353
+ ] }),
3354
+ children
3355
+ ] }),
3356
+ actions && /* @__PURE__ */ jsxRuntime.jsx(
3357
+ "div",
3358
+ {
3359
+ className: "flex flex-wrap gap-2 border-t border-border bg-background p-3",
3360
+ "data-slot": "skill-detail-actions",
3361
+ children: actions
3362
+ }
3363
+ )
3364
+ ]
3365
+ }
3366
+ );
3367
+ }
3368
+ function SkillDetailSection({
3369
+ title,
3370
+ children,
3371
+ testId
3372
+ }) {
3373
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [
3374
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: title }),
3375
+ children
3376
+ ] });
3377
+ }
3378
+
3379
+ // src/agents/skills/skillFiles.ts
3380
+ var SKILL_TYPES = ["markdown", "python", "shell", "javascript", "typescript"];
3381
+ var SKILL_MAIN_FILENAME = "SKILL.md";
3382
+ var MAIN_NAMES = /* @__PURE__ */ new Set(["skill.md", "skill.py", "skill.sh", "skill.js", "skill.ts"]);
3383
+ function isMainSkillFile(filename, skillName) {
3384
+ const lower = filename.toLowerCase();
3385
+ if (MAIN_NAMES.has(lower)) return true;
3386
+ const stem = lower.includes(".") ? lower.slice(0, lower.lastIndexOf(".")) : lower;
3387
+ return stem === skillName;
3388
+ }
3389
+ function detectTypeFromContent(content, filename) {
3390
+ if (filename) {
3391
+ const lower = filename.toLowerCase();
3392
+ if (lower.endsWith(".py")) return "python";
3393
+ if (lower.endsWith(".sh")) return "shell";
3394
+ if (lower.endsWith(".js")) return "javascript";
3395
+ if (lower.endsWith(".ts")) return "typescript";
3396
+ }
3397
+ if (content) {
3398
+ const firstLine = content.split("\n", 1)[0].trim();
3399
+ if (firstLine.startsWith("#!")) {
3400
+ if (firstLine.includes("python")) return "python";
3401
+ if (firstLine.includes("bash") || firstLine.includes("/sh")) return "shell";
3402
+ if (firstLine.includes("ts-node")) return "typescript";
3403
+ if (firstLine.includes("node")) return "javascript";
3404
+ }
3405
+ }
3406
+ return "markdown";
3407
+ }
3408
+ function parseSkillFrontmatter(raw, filename = "") {
3409
+ const config = {};
3410
+ let name = "";
3411
+ let description = "";
3412
+ let skillType = "markdown";
3413
+ if (!raw.startsWith("---")) {
3414
+ return {
3415
+ content: raw,
3416
+ name,
3417
+ description,
3418
+ config,
3419
+ skillType: detectTypeFromContent(raw, filename)
3420
+ };
3421
+ }
3422
+ const end = raw.indexOf("---", 3);
3423
+ if (end === -1) {
3424
+ return {
3425
+ content: raw,
3426
+ name,
3427
+ description,
3428
+ config,
3429
+ skillType: detectTypeFromContent(raw, filename)
3430
+ };
3431
+ }
3432
+ const frontmatter = raw.slice(3, end).trim();
3433
+ const body = raw.slice(end + 3).trim();
3434
+ for (const rawLine of frontmatter.split("\n")) {
3435
+ const line = rawLine.trim();
3436
+ if (!line || !line.includes(":")) continue;
3437
+ const idx = line.indexOf(":");
3438
+ const key = line.slice(0, idx).trim().toLowerCase();
3439
+ const value = line.slice(idx + 1).trim();
3440
+ if (key === "name" && value) {
3441
+ name = value;
3442
+ } else if (key === "description" && value) {
3443
+ description = value;
3444
+ } else if (key === "model" && value) {
3445
+ config.model = value;
3446
+ } else if (key === "temperature") {
3447
+ const t = Number.parseFloat(value);
3448
+ if (!Number.isNaN(t) && t >= 0 && t <= 2) config.temperature = t;
3449
+ } else if (key === "agent") {
3450
+ config.agent = ["true", "yes", "1"].includes(value.toLowerCase());
3451
+ } else if (key === "tools" && value) {
3452
+ config.tools = value.split(",").map((t) => t.trim()).filter(Boolean);
3453
+ } else if (key === "type" && value) {
3454
+ const v = value.toLowerCase();
3455
+ if (v === "python" || v === "py") skillType = "python";
3456
+ else if (v === "shell" || v === "sh" || v === "bash") skillType = "shell";
3457
+ else if (v === "javascript" || v === "js" || v === "node") skillType = "javascript";
3458
+ else if (v === "typescript" || v === "ts") skillType = "typescript";
3459
+ }
3460
+ }
3461
+ if (skillType === "markdown") {
3462
+ skillType = detectTypeFromContent(body, filename);
3463
+ }
3464
+ return { content: body, name, description, config, skillType };
3465
+ }
3466
+ function serializeSkill(input) {
2455
3467
  const lines = ["---", `name: ${input.name}`, `description: ${input.description}`];
2456
3468
  if (input.type && input.type !== "markdown") {
2457
3469
  lines.push(`type: ${input.type}`);
@@ -2565,6 +3577,883 @@ async function importSkillFromUrl(url) {
2565
3577
  const last = parsed.pathname.split("/").filter(Boolean).pop() ?? "skill";
2566
3578
  return importMarkdownSkill(last.includes(".") ? last : `${last}.md`, text);
2567
3579
  }
3580
+
3581
+ // src/agents/skills/skillLibrary.ts
3582
+ var SKILL_SOURCE_LABELS = {
3583
+ builtin: "Built in",
3584
+ mine: "Yours",
3585
+ shared: "Shared"
3586
+ };
3587
+ var SKILL_TYPE_LABELS = {
3588
+ markdown: "Instructions",
3589
+ python: "Python",
3590
+ shell: "Shell",
3591
+ javascript: "JavaScript",
3592
+ typescript: "TypeScript"
3593
+ };
3594
+ var SKILL_FIELD_TYPE_LABELS = {
3595
+ text: "Short answer",
3596
+ longtext: "Free text",
3597
+ boolean: "Yes or no",
3598
+ select: "A choice",
3599
+ number: "A number",
3600
+ date: "A date",
3601
+ scope: "Which files",
3602
+ documents: "Pick files",
3603
+ person: "A person"
3604
+ };
3605
+ function buildLibrarySkills(builtins, listings) {
3606
+ const { host, skills } = chunkOWCEQKAR_cjs.mergeSkillWorkflows(builtins, listings);
3607
+ const builtinIds = new Set(builtins.map((w) => w.id));
3608
+ const stored = new Map(listings.filter((s) => s.doc_ext_id).map((s) => [s.slug, s]));
3609
+ return [...host, ...skills].flatMap((workflow) => {
3610
+ if (workflow.run.kind !== "prompt") return [];
3611
+ const listing = stored.get(workflow.id);
3612
+ if (!listing?.doc_ext_id) {
3613
+ if (!builtinIds.has(workflow.id)) return [];
3614
+ return [
3615
+ {
3616
+ slug: workflow.id,
3617
+ title: workflow.title,
3618
+ description: workflow.description,
3619
+ source: "builtin",
3620
+ type: "markdown",
3621
+ isShared: false,
3622
+ replacesBuiltin: false,
3623
+ workflow
3624
+ }
3625
+ ];
3626
+ }
3627
+ const mine = listing.is_owner ?? true;
3628
+ return [
3629
+ {
3630
+ slug: workflow.id,
3631
+ title: workflow.title,
3632
+ description: listing.description || workflow.description,
3633
+ source: mine ? "mine" : "shared",
3634
+ type: listing.skill_type ?? "markdown",
3635
+ isShared: mine && listing.visibility === "global",
3636
+ replacesBuiltin: mine && builtinIds.has(listing.slug),
3637
+ workflow,
3638
+ docExtId: listing.doc_ext_id
3639
+ }
3640
+ ];
3641
+ });
3642
+ }
3643
+ function filterLibrarySkills(skills, f) {
3644
+ const q = f.query.trim().toLowerCase();
3645
+ return skills.filter((s) => f.source === "all" || s.source === f.source).filter((s) => f.type === "all" || s.type === f.type).filter(
3646
+ (s) => !q || s.title.toLowerCase().includes(q) || s.slug.toLowerCase().includes(q) || s.description.toLowerCase().includes(q)
3647
+ );
3648
+ }
3649
+ var ACTION = "pointer-coarse:min-h-11";
3650
+ function SkillLibraryDetail({
3651
+ skill,
3652
+ instructions,
3653
+ isLoading,
3654
+ actions,
3655
+ icon
3656
+ }) {
3657
+ const fields = skill.workflow.inputs;
3658
+ const isOwner = skill.source === "mine";
3659
+ const canCopy = skill.source !== "mine";
3660
+ const notice = skill.replacesBuiltin ? "Your copy is used instead of the original; delete it to go back." : skill.isShared ? "Shared with everyone." : void 0;
3661
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3662
+ SkillDetail,
3663
+ {
3664
+ title: skill.title,
3665
+ sourceLabel: SKILL_SOURCE_LABELS[skill.source],
3666
+ description: skill.description,
3667
+ icon,
3668
+ notice,
3669
+ testId: "skill-detail",
3670
+ actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3671
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: actions.onRun, className: ACTION, "data-testid": "skill-run", children: [
3672
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "mr-1.5 size-4" }),
3673
+ "Run"
3674
+ ] }),
3675
+ canCopy && /* @__PURE__ */ jsxRuntime.jsxs(
3676
+ ui.Button,
3677
+ {
3678
+ variant: "outline",
3679
+ onClick: actions.onCopy,
3680
+ disabled: actions.isBusy,
3681
+ className: ACTION,
3682
+ "data-testid": "skill-copy",
3683
+ children: [
3684
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "mr-1.5 size-4" }),
3685
+ "Make a copy"
3686
+ ]
3687
+ }
3688
+ ),
3689
+ isOwner && /* @__PURE__ */ jsxRuntime.jsxs(
3690
+ ui.Button,
3691
+ {
3692
+ variant: "outline",
3693
+ onClick: actions.onEdit,
3694
+ className: ACTION,
3695
+ "data-testid": "skill-edit",
3696
+ children: [
3697
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "mr-1.5 size-4" }),
3698
+ "Edit"
3699
+ ]
3700
+ }
3701
+ ),
3702
+ isOwner && /* @__PURE__ */ jsxRuntime.jsxs(
3703
+ ui.Button,
3704
+ {
3705
+ variant: "outline",
3706
+ onClick: actions.onToggleShare,
3707
+ disabled: actions.isBusy,
3708
+ className: ACTION,
3709
+ "data-testid": "skill-share",
3710
+ children: [
3711
+ skill.isShared ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "mr-1.5 size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "mr-1.5 size-4" }),
3712
+ skill.isShared ? "Make private" : "Share with everyone"
3713
+ ]
3714
+ }
3715
+ ),
3716
+ /* @__PURE__ */ jsxRuntime.jsxs(
3717
+ ui.Button,
3718
+ {
3719
+ variant: "outline",
3720
+ onClick: actions.onExport,
3721
+ className: ACTION,
3722
+ "data-testid": "skill-export",
3723
+ children: [
3724
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "mr-1.5 size-4" }),
3725
+ "Export"
3726
+ ]
3727
+ }
3728
+ ),
3729
+ isOwner && /* @__PURE__ */ jsxRuntime.jsxs(
3730
+ ui.Button,
3731
+ {
3732
+ variant: "ghost",
3733
+ onClick: actions.onDelete,
3734
+ disabled: actions.isBusy,
3735
+ className: `${ACTION} ml-auto text-destructive`,
3736
+ "data-testid": "skill-delete",
3737
+ children: [
3738
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-1.5 size-4" }),
3739
+ "Delete"
3740
+ ]
3741
+ }
3742
+ )
3743
+ ] }),
3744
+ children: [
3745
+ /* @__PURE__ */ jsxRuntime.jsx(SkillDetailSection, { title: "What it asks you", testId: "skill-inputs", children: fields.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Nothing: it starts right away." }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1 text-sm", children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-wrap items-baseline gap-x-2", children: [
3746
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: field.label }),
3747
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
3748
+ SKILL_FIELD_TYPE_LABELS[field.type],
3749
+ field.required ? "" : ", optional"
3750
+ ] })
3751
+ ] }, field.name)) }) }),
3752
+ /* @__PURE__ */ jsxRuntime.jsxs(
3753
+ SkillDetailSection,
3754
+ {
3755
+ title: skill.type === "markdown" ? "Instructions" : `Instructions (${SKILL_TYPE_LABELS[skill.type] ?? skill.type})`,
3756
+ children: [
3757
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Loading\u2026" }) : /* @__PURE__ */ jsxRuntime.jsx(
3758
+ "pre",
3759
+ {
3760
+ className: "max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-muted p-3 font-mono text-xs",
3761
+ tabIndex: 0,
3762
+ "aria-label": "Instructions",
3763
+ "data-testid": "skill-instructions",
3764
+ children: instructions || "No instructions."
3765
+ }
3766
+ ),
3767
+ !isOwner && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "You can read these. Make a copy to change them." })
3768
+ ]
3769
+ }
3770
+ )
3771
+ ]
3772
+ }
3773
+ );
3774
+ }
3775
+ function PersonPill({ person, size = "sm", testId }) {
3776
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": testId, className: "inline-flex min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
3777
+ ui.UserEntity,
3778
+ {
3779
+ variant: "pill",
3780
+ size,
3781
+ interactive: false,
3782
+ showTooltip: false,
3783
+ initials: chunkKDG6FER6_cjs.initials(person.label),
3784
+ displayName: person.label,
3785
+ avatarStyle: person.id ? ui.getEntityColorStyles(person.id) : void 0,
3786
+ isAgent: person.isAgent,
3787
+ isMe: person.isMe
3788
+ }
3789
+ ) });
3790
+ }
3791
+ var DEFAULT_TASK_TRIGGER_CHIP_LABELS = {
3792
+ after: (name) => `After \u201C${name}\u201D is done`,
3793
+ afterUnknown: "After another task is done",
3794
+ onDemand: "Manual"
3795
+ };
3796
+ function TriggerIcon({ type, chained }) {
3797
+ const cls = "size-3.5 shrink-0 text-muted-foreground";
3798
+ if (chained) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: cls, "aria-hidden": true });
3799
+ switch (type) {
3800
+ case "on_demand":
3801
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointerClick, { className: cls, "aria-hidden": true });
3802
+ case "recurring":
3803
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: cls, "aria-hidden": true });
3804
+ case "event":
3805
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bell, { className: cls, "aria-hidden": true });
3806
+ default:
3807
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: cls, "aria-hidden": true });
3808
+ }
3809
+ }
3810
+ function TaskTriggerChip({
3811
+ id,
3812
+ triggerType,
3813
+ summary,
3814
+ afterTaskId,
3815
+ afterTaskName,
3816
+ testId,
3817
+ labels
3818
+ }) {
3819
+ const l = { ...DEFAULT_TASK_TRIGGER_CHIP_LABELS, ...labels };
3820
+ const chained = Boolean(afterTaskId);
3821
+ const text = chained ? afterTaskName ? l.after(afterTaskName) : l.afterUnknown : triggerType === "on_demand" ? l.onDemand : summary;
3822
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3823
+ "span",
3824
+ {
3825
+ className: "inline-flex min-w-0 max-w-full items-center gap-1.5 text-sm font-normal text-foreground",
3826
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-trigger-${id}` }),
3827
+ "data-trigger": chained ? "task" : triggerType,
3828
+ children: [
3829
+ /* @__PURE__ */ jsxRuntime.jsx(TriggerIcon, { type: triggerType, chained }),
3830
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: text })
3831
+ ]
3832
+ }
3833
+ );
3834
+ }
3835
+
3836
+ // src/agents/tasks/workflowRows.ts
3837
+ var isSkillRow = (row) => row.kind === "skill";
3838
+ var hasTrigger = (row) => !row.on_demand && Boolean(row.rrule || row.run_at || row.event_kind || row.after_conversation_ext_id);
3839
+ function workflowStatus(row) {
3840
+ if (isSkillRow(row) || !hasTrigger(row)) return "on_demand";
3841
+ return row.active ? "active" : "paused";
3842
+ }
3843
+ function workflowTriggerType(workflow) {
3844
+ if (workflow.on_demand) return "on_demand";
3845
+ if (workflow.after_conversation_ext_id) return "after";
3846
+ if (workflow.event_kind) return "event";
3847
+ if (workflow.rrule) return "recurring";
3848
+ if (workflow.run_at) return "one_time";
3849
+ return "on_demand";
3850
+ }
3851
+ function workflowRunStatusLabel(status) {
3852
+ if (!status) return "None";
3853
+ const labels = {
3854
+ completed: "Success",
3855
+ success: "Success",
3856
+ failed: "Failed",
3857
+ running: "In progress",
3858
+ awaiting_authorization: "Awaiting access"
3859
+ };
3860
+ return labels[status] ?? status.replaceAll("_", " ");
3861
+ }
3862
+ function listedRunStatus(status, threadStatus) {
3863
+ if (threadStatus === "done" && status === "running") return "completed";
3864
+ return status;
3865
+ }
3866
+
3867
+ // src/agents/tasks/workflowColumns.tsx
3868
+ var WORKFLOW_COLUMN_ORDER = [
3869
+ "name",
3870
+ "trigger",
3871
+ "last_run",
3872
+ "result",
3873
+ "status",
3874
+ "shared",
3875
+ "actions"
3876
+ ];
3877
+ function cell(render) {
3878
+ return (params) => params.data ? render(params.data) : null;
3879
+ }
3880
+ var time = (iso) => iso ? Date.parse(iso) : Number.POSITIVE_INFINITY;
3881
+ function createWorkflowColumns(o) {
3882
+ const l = o.labels;
3883
+ const base = {
3884
+ sortable: false,
3885
+ cellStyle: { display: "flex", alignItems: "center" }
3886
+ };
3887
+ return [
3888
+ {
3889
+ ...base,
3890
+ colId: "name",
3891
+ sortable: true,
3892
+ headerName: l.colName,
3893
+ flex: 3,
3894
+ minWidth: 210,
3895
+ valueGetter: (p) => p.data?.name.toLowerCase() ?? "",
3896
+ cellRenderer: cell(o.renderName)
3897
+ },
3898
+ {
3899
+ ...base,
3900
+ colId: "trigger",
3901
+ headerName: l.colTrigger,
3902
+ flex: 2.4,
3903
+ minWidth: 185,
3904
+ valueGetter: (p) => p.data ? o.getTriggerText(p.data) : "",
3905
+ cellRenderer: cell(o.renderTrigger)
3906
+ },
3907
+ {
3908
+ ...base,
3909
+ colId: "last_run",
3910
+ sortable: true,
3911
+ headerName: l.colLastRun,
3912
+ flex: 1.4,
3913
+ minWidth: 140,
3914
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
3915
+ valueGetter: (p) => time(p.data?.last_fired_at),
3916
+ cellRenderer: cell(o.renderLastRun)
3917
+ },
3918
+ {
3919
+ ...base,
3920
+ colId: "result",
3921
+ headerName: "Result",
3922
+ width: 130,
3923
+ valueGetter: (p) => p.data?.last_run_status ?? "",
3924
+ cellStyle: { display: "flex", alignItems: "center", padding: 0 },
3925
+ cellRenderer: cell(o.renderResult)
3926
+ },
3927
+ {
3928
+ ...base,
3929
+ colId: "status",
3930
+ sortable: true,
3931
+ headerName: l.colStatus,
3932
+ width: 120,
3933
+ valueGetter: (p) => p.data ? workflowStatus(p.data) : "",
3934
+ cellRenderer: cell(o.renderStatus)
3935
+ },
3936
+ {
3937
+ ...base,
3938
+ colId: "shared",
3939
+ headerName: l.colShared,
3940
+ headerTooltip: l.shared,
3941
+ width: 96,
3942
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "center" },
3943
+ valueGetter: (p) => p.data?.shared ?? false,
3944
+ cellRenderer: cell(o.renderShared)
3945
+ },
3946
+ {
3947
+ ...base,
3948
+ colId: "actions",
3949
+ headerName: "",
3950
+ width: 180,
3951
+ minWidth: 180,
3952
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
3953
+ cellRenderer: cell(o.renderActions)
3954
+ }
3955
+ ];
3956
+ }
3957
+
3958
+ // src/agents/tasks/workflowTableLabels.ts
3959
+ var DEFAULT_WORKFLOW_LIST_LABELS = {
3960
+ colName: "Name",
3961
+ colType: "Type",
3962
+ colTrigger: "When",
3963
+ colAction: "What it does",
3964
+ colAgent: "Agent",
3965
+ colStatus: "Active",
3966
+ colShared: "Shared",
3967
+ colLastRun: "Last run",
3968
+ colNextRun: "Next run",
3969
+ shared: "Shared with the workspace",
3970
+ sharedOwnerOnly: "Only the creator can change who can see this",
3971
+ deleteOwnerOnly: "Only the creator or workspace owner can delete this",
3972
+ typeSkill: "Skill",
3973
+ typeWorkflow: "Workflow",
3974
+ statusActive: "Active",
3975
+ statusPaused: "Inactive",
3976
+ statusOnDemand: "On demand",
3977
+ activeSwitch: (name) => `Active: \u201C${name}\u201D`,
3978
+ agent: "Agent",
3979
+ myAssistant: "My assistant",
3980
+ me: "Me",
3981
+ someone: "Someone",
3982
+ never: "Never",
3983
+ none: "\u2014",
3984
+ reminder: "Reminder",
3985
+ failed: "Failed",
3986
+ lastRunFailed: "Last run failed",
3987
+ openLastRun: "Open the task this run created",
3988
+ editWorkflow: "Edit",
3989
+ run: "Run",
3990
+ runLater: "Run later",
3991
+ runNow: "Run now",
3992
+ runs: "Runs",
3993
+ delete: "Delete",
3994
+ moreActions: "More actions",
3995
+ searchLabel: "Search workflows",
3996
+ searchPlaceholder: "Search workflows and skills\u2026",
3997
+ emptyTitle: "Nothing to run yet",
3998
+ emptyMessage: "Skills and workflows you can run will appear here.",
3999
+ firstRun: "Run a skill now, or choose Run later to save it as a workflow that runs on its own.",
4000
+ noMatches: "Nothing in this view.",
4001
+ filterAll: "All",
4002
+ filterSkills: "Skills",
4003
+ filterWorkflows: "Workflows",
4004
+ filterActive: "Active",
4005
+ filterPaused: "Inactive",
4006
+ makeActive: "Make active",
4007
+ makePaused: "Deactivate",
4008
+ selectAll: "Select all",
4009
+ selectWorkflow: (name) => `Select ${name}`
4010
+ };
4011
+ var ROW_HEIGHT = 40;
4012
+ function WorkflowsTable(props) {
4013
+ const { workflows, isLoading, busyId, header, testId } = props;
4014
+ const l = { ...DEFAULT_WORKFLOW_LIST_LABELS, ...props.labels };
4015
+ const [filterStates, setFilterStates] = react.useState(/* @__PURE__ */ new Map());
4016
+ const [filterOpen, setFilterOpen] = react.useState(false);
4017
+ const [query, setQuery] = react.useState("");
4018
+ const [selected, setSelected] = react.useState([]);
4019
+ const apiRef = react.useRef(null);
4020
+ const q = query.trim().toLowerCase();
4021
+ const matches = (w) => !q || `${w.name} ${w.description ?? ""} ${w.prompt ?? ""} ${w.skill_ref ?? ""}`.toLowerCase().includes(q);
4022
+ const inFilter = (w, f) => f === "all" || f === "skills" && isSkillRow(w) || f === "workflows" && !isSkillRow(w) || f === "active" && workflowStatus(w) === "active" || f === "paused" && workflowStatus(w) === "paused";
4023
+ const counts = react.useMemo(() => {
4024
+ const out = { all: 0, skills: 0, workflows: 0, active: 0, paused: 0 };
4025
+ for (const w of workflows) {
4026
+ if (!matches(w)) continue;
4027
+ for (const f of Object.keys(out)) if (inFilter(w, f)) out[f] += 1;
4028
+ }
4029
+ return out;
4030
+ }, [workflows, q]);
4031
+ const shown = react.useMemo(
4032
+ () => workflows.filter((w) => {
4033
+ if (!matches(w)) return false;
4034
+ for (const group of [
4035
+ ["skills", "workflows"],
4036
+ ["active", "paused"]
4037
+ ]) {
4038
+ const included = group.filter((f) => filterStates.get(f) === "include");
4039
+ if (included.length && !included.some((f) => inFilter(w, f))) return false;
4040
+ if (group.some((f) => filterStates.get(f) === "exclude" && inFilter(w, f))) return false;
4041
+ }
4042
+ return true;
4043
+ }),
4044
+ [workflows, filterStates, q]
4045
+ );
4046
+ const renderPerson = props.renderPerson ?? ((p) => /* @__PURE__ */ jsxRuntime.jsx(PersonPill, { person: p }));
4047
+ const actionText = (w) => {
4048
+ if (w.action)
4049
+ return w.action.type === "email_documents" ? "Email latest documents" : "AI Review";
4050
+ if (isSkillRow(w))
4051
+ return w.description || w.skill_ref && props.skillNames?.[w.skill_ref] || w.name;
4052
+ return w.skill_ref ? props.skillNames?.[w.skill_ref] ?? w.skill_ref : w.prompt?.trim() || l.reminder;
4053
+ };
4054
+ const latest = react.useRef({ props, l, renderPerson, actionText });
4055
+ latest.current = { props, l, renderPerson, actionText };
4056
+ const columnDefs = react.useMemo(
4057
+ () => createWorkflowColumns({
4058
+ labels: l,
4059
+ getTriggerText: (w) => isSkillRow(w) ? l.statusOnDemand : latest.current.props.describeTrigger(w),
4060
+ renderName: (w) => {
4061
+ const { l: lb } = latest.current;
4062
+ const skill = isSkillRow(w);
4063
+ const text = skill ? latest.current.actionText(w) : w.description || latest.current.actionText(w);
4064
+ const stem = w.name.replace(/…$/, "").trim();
4065
+ const about = text && text.trim() !== w.name.trim() && text.trim() !== stem ? text : "";
4066
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 leading-tight", children: [
4067
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
4068
+ /* @__PURE__ */ jsxRuntime.jsx(
4069
+ "span",
4070
+ {
4071
+ className: ui.cn(
4072
+ "truncate text-sm font-normal",
4073
+ workflowStatus(w) === "paused" && "text-muted-foreground"
4074
+ ),
4075
+ "data-testid": `workflow-name-${w.external_id}`,
4076
+ children: w.name
4077
+ }
4078
+ ),
4079
+ skill && /* @__PURE__ */ jsxRuntime.jsx(
4080
+ "span",
4081
+ {
4082
+ className: "shrink-0 rounded-full border border-border px-1.5 text-[11px] text-muted-foreground",
4083
+ "data-testid": `workflow-type-${w.external_id}`,
4084
+ children: lb.typeSkill
4085
+ }
4086
+ )
4087
+ ] }),
4088
+ about && !latest.current.props.automationsOnly && /* @__PURE__ */ jsxRuntime.jsx(
4089
+ "p",
4090
+ {
4091
+ className: "truncate text-xs text-muted-foreground",
4092
+ "data-testid": `workflow-action-${w.external_id}`,
4093
+ children: about
4094
+ }
4095
+ )
4096
+ ] });
4097
+ },
4098
+ renderTrigger: (w) => {
4099
+ const { props: p } = latest.current;
4100
+ const after = w.after_conversation_ext_id;
4101
+ const skill = isSkillRow(w);
4102
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 leading-tight", children: /* @__PURE__ */ jsxRuntime.jsx(
4103
+ TaskTriggerChip,
4104
+ {
4105
+ id: w.external_id,
4106
+ testId: `workflow-trigger-${w.external_id}`,
4107
+ triggerType: workflowTriggerType(w),
4108
+ summary: skill ? "" : p.describeTrigger(w),
4109
+ afterTaskId: after,
4110
+ afterTaskName: after ? p.taskNames?.[after] : void 0,
4111
+ labels: p.triggerChipLabels
4112
+ }
4113
+ ) });
4114
+ },
4115
+ renderStatus: (w) => {
4116
+ const { props: p, l: lb } = latest.current;
4117
+ const canEdit = w.is_owner !== false || Boolean(p.canEditShared);
4118
+ return /* @__PURE__ */ jsxRuntime.jsx(
4119
+ ui.Switch,
4120
+ {
4121
+ checked: hasTrigger(w) && !isSkillRow(w) && Boolean(w.active),
4122
+ disabled: !hasTrigger(w) || isSkillRow(w) || !canEdit || p.busyId === w.external_id,
4123
+ onCheckedChange: (next) => p.onToggleActive(w, next),
4124
+ className: "disabled:data-[state=unchecked]:bg-muted dark:disabled:data-[state=unchecked]:bg-muted",
4125
+ "aria-label": lb.activeSwitch(w.name),
4126
+ "data-testid": `workflow-active-${w.external_id}`
4127
+ }
4128
+ );
4129
+ },
4130
+ renderShared: (w) => {
4131
+ const { props: p, l: lb } = latest.current;
4132
+ if (!p.onToggleShared || isSkillRow(w)) return null;
4133
+ const isCreator = w.is_owner !== false;
4134
+ return /* @__PURE__ */ jsxRuntime.jsx(
4135
+ ui.VisibilityToggle,
4136
+ {
4137
+ items: { shared: w.shared ?? false },
4138
+ onToggle: (share) => latest.current.props.onToggleShared?.(w, share),
4139
+ disabled: !isCreator || p.busyId === w.external_id,
4140
+ disabledTooltip: lb.sharedOwnerOnly,
4141
+ showLabel: false,
4142
+ "data-testid": `workflow-shared-${w.external_id}`
4143
+ }
4144
+ );
4145
+ },
4146
+ renderLastRun: (w) => {
4147
+ const { props: p, l: lb } = latest.current;
4148
+ const at = w.last_fired_at ?? p.lastRuns?.[w.external_id]?.at;
4149
+ return /* @__PURE__ */ jsxRuntime.jsx(
4150
+ "button",
4151
+ {
4152
+ type: "button",
4153
+ className: "h-full w-full truncate px-4 text-left text-sm hover:text-primary",
4154
+ onClick: () => p.onViewRuns?.(w),
4155
+ title: "View run history",
4156
+ "data-testid": `workflow-last-run-${w.external_id}`,
4157
+ children: at ? p.formatDate(at) : lb.never
4158
+ }
4159
+ );
4160
+ },
4161
+ renderResult: (w) => {
4162
+ const status = listedRunStatus(
4163
+ w.last_run_status,
4164
+ latest.current.props.lastRuns?.[w.external_id]?.threadStatus
4165
+ );
4166
+ const label = workflowRunStatusLabel(status);
4167
+ return /* @__PURE__ */ jsxRuntime.jsx(
4168
+ "button",
4169
+ {
4170
+ type: "button",
4171
+ onClick: () => latest.current.props.onViewRuns?.(w),
4172
+ title: "View run history",
4173
+ className: ui.cn(
4174
+ ui.badgeVariants({ variant: "outline" }),
4175
+ "mx-4 cursor-pointer text-xs font-medium",
4176
+ 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"
4177
+ ),
4178
+ "data-testid": `workflow-result-${w.external_id}`,
4179
+ children: label
4180
+ }
4181
+ );
4182
+ },
4183
+ renderActions: (w) => {
4184
+ const { props: p, l: lb } = latest.current;
4185
+ const id = w.external_id;
4186
+ const skill = isSkillRow(w);
4187
+ const busy = p.busyId === id;
4188
+ const isOwner = w.is_owner !== false;
4189
+ const canEdit = isOwner || Boolean(p.canEditShared);
4190
+ const canAdmin = isOwner || Boolean(p.isWorkspaceOwner);
4191
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1", children: [
4192
+ (skill || canEdit) && /* @__PURE__ */ jsxRuntime.jsxs(
4193
+ ui.Button,
4194
+ {
4195
+ size: "sm",
4196
+ variant: "outline",
4197
+ className: "h-8 gap-1.5 pointer-coarse:h-11",
4198
+ disabled: busy,
4199
+ onClick: () => p.onRun(w),
4200
+ "data-testid": `workflow-run-btn-${id}`,
4201
+ children: [
4202
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-3.5", "aria-hidden": true }),
4203
+ lb.run
4204
+ ]
4205
+ }
4206
+ ),
4207
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
4208
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4209
+ ui.Button,
4210
+ {
4211
+ variant: "ghost",
4212
+ size: "icon",
4213
+ className: "size-8 pointer-coarse:size-11",
4214
+ "aria-label": lb.moreActions,
4215
+ "data-testid": `workflow-menu-${id}`,
4216
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4", "aria-hidden": true })
4217
+ }
4218
+ ) }),
4219
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", children: [
4220
+ skill && p.onRunLater && /* @__PURE__ */ jsxRuntime.jsxs(
4221
+ ui.DropdownMenuItem,
4222
+ {
4223
+ onSelect: () => p.onRunLater?.(w),
4224
+ "data-testid": `workflow-run-later-${id}`,
4225
+ children: [
4226
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "mr-2 size-4", "aria-hidden": true }),
4227
+ lb.runLater
4228
+ ]
4229
+ }
4230
+ ),
4231
+ !skill && canEdit && /* @__PURE__ */ jsxRuntime.jsxs(
4232
+ ui.DropdownMenuItem,
4233
+ {
4234
+ onSelect: () => p.onEdit(w),
4235
+ "data-testid": `workflow-edit-${id}`,
4236
+ children: [
4237
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "mr-2 size-4", "aria-hidden": true }),
4238
+ lb.editWorkflow
4239
+ ]
4240
+ }
4241
+ ),
4242
+ !skill && p.onViewRuns && /* @__PURE__ */ jsxRuntime.jsxs(
4243
+ ui.DropdownMenuItem,
4244
+ {
4245
+ onSelect: () => p.onViewRuns?.(w),
4246
+ "data-testid": `workflow-runs-${id}`,
4247
+ children: [
4248
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "mr-2 size-4", "aria-hidden": true }),
4249
+ lb.runs
4250
+ ]
4251
+ }
4252
+ ),
4253
+ !skill && canEdit && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4254
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
4255
+ /* @__PURE__ */ jsxRuntime.jsxs(
4256
+ ui.DropdownMenuItem,
4257
+ {
4258
+ disabled: busy || !canAdmin,
4259
+ onSelect: () => p.onDelete(w),
4260
+ title: canAdmin ? void 0 : lb.deleteOwnerOnly,
4261
+ className: "text-destructive focus:text-destructive",
4262
+ "data-testid": `workflow-delete-${id}`,
4263
+ children: [
4264
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-2 size-4", "aria-hidden": true }),
4265
+ lb.delete
4266
+ ]
4267
+ }
4268
+ )
4269
+ ] })
4270
+ ] })
4271
+ ] })
4272
+ ] });
4273
+ }
4274
+ }),
4275
+ // Stable on purpose: only the header texts rebuild the columns (see `latest`).
4276
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4277
+ [
4278
+ l.colName,
4279
+ l.colType,
4280
+ l.colTrigger,
4281
+ l.colAction,
4282
+ l.colAgent,
4283
+ l.colStatus,
4284
+ l.colShared,
4285
+ l.shared,
4286
+ l.colLastRun,
4287
+ l.colNextRun
4288
+ ]
4289
+ );
4290
+ react.useEffect(() => {
4291
+ apiRef.current?.refreshCells({ force: true });
4292
+ }, [
4293
+ busyId,
4294
+ props.agentNames,
4295
+ props.skillNames,
4296
+ props.taskNames,
4297
+ props.lastRuns,
4298
+ props.renderPerson,
4299
+ props.labels,
4300
+ props.canEditShared,
4301
+ props.isWorkspaceOwner
4302
+ ]);
4303
+ const mine = selected.filter((w) => !isSkillRow(w));
4304
+ const adminSelected = mine.filter((w) => w.is_owner !== false || props.isWorkspaceOwner);
4305
+ const editableSelected = mine.filter(
4306
+ (w) => hasTrigger(w) && (w.is_owner !== false || props.canEditShared)
4307
+ );
4308
+ const clearSelection = () => setSelected([]);
4309
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4310
+ "div",
4311
+ {
4312
+ className: "flex min-h-0 flex-1 flex-col",
4313
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "workflow-list" }),
4314
+ children: [
4315
+ /* @__PURE__ */ jsxRuntime.jsx(
4316
+ chunk7RGLTF76_cjs.TabHeader,
4317
+ {
4318
+ testId: "automations-tab-header",
4319
+ tabs: [
4320
+ {
4321
+ id: "automations",
4322
+ label: "",
4323
+ count: shown.length,
4324
+ countIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "size-3.5" }),
4325
+ countPlacement: "leading",
4326
+ presentation: "count",
4327
+ hasActiveFilters: !!q || [...filterStates.values()].some(Boolean)
4328
+ },
4329
+ ...props.tabs ?? []
4330
+ ],
4331
+ activeTabId: props.activeTabId ?? "automations",
4332
+ onTabChange: props.onTabChange ?? (() => {
4333
+ }),
4334
+ firstTabContent: /* @__PURE__ */ jsxRuntime.jsx(
4335
+ chunk2EI7NCUA_cjs.FilterInput,
4336
+ {
4337
+ value: query,
4338
+ onChange: setQuery,
4339
+ fields: ["text"],
4340
+ onFieldsChange: () => {
4341
+ },
4342
+ hideFieldPicker: true,
4343
+ ariaLabel: l.searchLabel,
4344
+ testIds: { input: "workflow-search" },
4345
+ filter: /* @__PURE__ */ jsxRuntime.jsx(
4346
+ chunkRQ2Y7USX_cjs.TriStateFilterMenu,
4347
+ {
4348
+ testId: "automations-filter-button",
4349
+ open: filterOpen,
4350
+ onOpenChange: setFilterOpen,
4351
+ filterStates,
4352
+ onFiltersChange: setFilterStates,
4353
+ 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",
4354
+ renderChevron: true,
4355
+ disableHoverOpen: true,
4356
+ options: [
4357
+ ...!props.automationsOnly ? [
4358
+ { id: "skills", label: l.filterSkills, count: counts.skills },
4359
+ {
4360
+ id: "workflows",
4361
+ label: l.filterWorkflows,
4362
+ count: counts.workflows
4363
+ }
4364
+ ] : [],
4365
+ { id: "active", label: l.filterActive, count: counts.active },
4366
+ { id: "paused", label: l.filterPaused, count: counts.paused }
4367
+ ]
4368
+ }
4369
+ )
4370
+ }
4371
+ ),
4372
+ rightContent: header
4373
+ }
4374
+ ),
4375
+ props.content ? props.content : workflows.length === 0 && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
4376
+ chunkZW6FPIFC_cjs.EmptyState,
4377
+ {
4378
+ icon: lucideReact.Workflow,
4379
+ title: l.emptyTitle,
4380
+ description: l.emptyMessage,
4381
+ testId: "workflow-list-empty"
4382
+ }
4383
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
4384
+ chunkC2CWWEHO_cjs.GridView,
4385
+ {
4386
+ testId: "workflow-grid",
4387
+ gridId: props.gridId ?? "workflows-grid-v2",
4388
+ items: shown,
4389
+ columnDefs,
4390
+ getItemId: (w) => w.external_id,
4391
+ getRowTestId: (w) => `workflow-row-${w.external_id}`,
4392
+ isLoading,
4393
+ showEmpty: shown.length === 0,
4394
+ emptyState: { title: l.noMatches },
4395
+ rowHeight: ROW_HEIGHT,
4396
+ height: "100%",
4397
+ onGridReady: ({ api }) => {
4398
+ apiRef.current = api;
4399
+ },
4400
+ onRowClick: (row) => props.onOpenRow?.(row),
4401
+ selection: { mode: "multiple", selected, onSelectionChange: setSelected },
4402
+ gridOptions: GRID_OPTIONS
4403
+ }
4404
+ ) }),
4405
+ !props.content && /* @__PURE__ */ jsxRuntime.jsx(chunkV4ISCZJ7_cjs.SelectionBar, { count: selected.length, onClear: clearSelection, children: (isCompact) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4406
+ props.onToggleActiveMany && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4407
+ /* @__PURE__ */ jsxRuntime.jsx(
4408
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
4409
+ {
4410
+ icon: lucideReact.Play,
4411
+ label: l.makeActive,
4412
+ onClick: () => {
4413
+ props.onToggleActiveMany?.(editableSelected, true);
4414
+ clearSelection();
4415
+ },
4416
+ disabled: editableSelected.length === 0,
4417
+ isCompact,
4418
+ testId: "workflow-bulk-activate"
4419
+ }
4420
+ ),
4421
+ /* @__PURE__ */ jsxRuntime.jsx(
4422
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
4423
+ {
4424
+ icon: lucideReact.Workflow,
4425
+ label: l.makePaused,
4426
+ onClick: () => {
4427
+ props.onToggleActiveMany?.(editableSelected, false);
4428
+ clearSelection();
4429
+ },
4430
+ disabled: editableSelected.length === 0,
4431
+ isCompact,
4432
+ testId: "workflow-bulk-pause"
4433
+ }
4434
+ )
4435
+ ] }),
4436
+ props.onDeleteMany && /* @__PURE__ */ jsxRuntime.jsx(
4437
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
4438
+ {
4439
+ icon: lucideReact.Trash2,
4440
+ label: l.delete,
4441
+ onClick: () => {
4442
+ props.onDeleteMany?.(adminSelected);
4443
+ clearSelection();
4444
+ },
4445
+ disabled: adminSelected.length === 0,
4446
+ isCompact,
4447
+ className: "border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
4448
+ testId: "workflow-bulk-delete"
4449
+ }
4450
+ )
4451
+ ] }) })
4452
+ ]
4453
+ }
4454
+ );
4455
+ }
4456
+ var GRID_OPTIONS = { suppressClickEdit: true };
2568
4457
  var DEFAULT_TASK_ACTIVITY_LABELS = {
2569
4458
  title: "Activity",
2570
4459
  empty: "Nothing has happened yet.",
@@ -2758,35 +4647,75 @@ function TaskActivityTimeline({
2758
4647
  }
2759
4648
 
2760
4649
  exports.ActionStepBody = ActionStepBody;
4650
+ exports.AgentSelect = AgentSelect;
2761
4651
  exports.ApprovalEvidence = ApprovalEvidence;
2762
4652
  exports.AssigneeLine = AssigneeLine;
4653
+ exports.DEFAULT_AGENT_SELECT_LABELS = DEFAULT_AGENT_SELECT_LABELS;
2763
4654
  exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
4655
+ exports.DEFAULT_SKILL_EDIT_FORM_LABELS = DEFAULT_SKILL_EDIT_FORM_LABELS;
4656
+ exports.DEFAULT_SKILL_GENERATE_FORM_LABELS = DEFAULT_SKILL_GENERATE_FORM_LABELS;
4657
+ exports.DEFAULT_SKILL_GLOBAL_BADGE_LABELS = DEFAULT_SKILL_GLOBAL_BADGE_LABELS;
4658
+ exports.DEFAULT_SKILL_VIEW_TOGGLE_LABELS = DEFAULT_SKILL_VIEW_TOGGLE_LABELS;
2764
4659
  exports.DEFAULT_STEP_BAR_LABELS = DEFAULT_STEP_BAR_LABELS;
2765
4660
  exports.DEFAULT_TASK_ACTIVITY_LABELS = DEFAULT_TASK_ACTIVITY_LABELS;
4661
+ exports.DEFAULT_TASK_TRIGGER_CHIP_LABELS = DEFAULT_TASK_TRIGGER_CHIP_LABELS;
4662
+ exports.DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS = DEFAULT_WORKFLOW_CONFIG_DIALOG_LABELS;
4663
+ exports.DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS = DEFAULT_WORKFLOW_DOCUMENTS_FIELD_LABELS;
4664
+ exports.DEFAULT_WORKFLOW_LIST_LABELS = DEFAULT_WORKFLOW_LIST_LABELS;
2766
4665
  exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
2767
4666
  exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
4667
+ exports.PersonPill = PersonPill;
4668
+ exports.SKILL_FIELD_TYPE_LABELS = SKILL_FIELD_TYPE_LABELS;
2768
4669
  exports.SKILL_MAIN_FILENAME = SKILL_MAIN_FILENAME;
4670
+ exports.SKILL_SOURCE_LABELS = SKILL_SOURCE_LABELS;
2769
4671
  exports.SKILL_TYPES = SKILL_TYPES;
4672
+ exports.SKILL_TYPE_LABELS = SKILL_TYPE_LABELS;
2770
4673
  exports.STEP_LABEL = STEP_LABEL;
2771
4674
  exports.STEP_LABEL_CURRENT = STEP_LABEL_CURRENT;
2772
4675
  exports.STEP_LABEL_MAX = STEP_LABEL_MAX;
2773
4676
  exports.SchemaForm = SchemaForm;
2774
4677
  exports.SendBackControl = SendBackControl;
4678
+ exports.SkillActionButton = SkillActionButton;
4679
+ exports.SkillDetail = SkillDetail;
4680
+ exports.SkillDetailSection = SkillDetailSection;
4681
+ exports.SkillEditForm = SkillEditForm;
4682
+ exports.SkillFilterChips = SkillFilterChips;
4683
+ exports.SkillGenerateForm = SkillGenerateForm;
4684
+ exports.SkillGlobalBadge = SkillGlobalBadge;
4685
+ exports.SkillLibraryDetail = SkillLibraryDetail;
4686
+ exports.SkillTile = SkillTile;
4687
+ exports.SkillTypeBadge = SkillTypeBadge;
4688
+ exports.SkillViewToggle = SkillViewToggle;
2775
4689
  exports.StepBarFrame = StepBarFrame;
2776
4690
  exports.TaskActivityTimeline = TaskActivityTimeline;
4691
+ exports.TaskTriggerChip = TaskTriggerChip;
4692
+ exports.WORKFLOW_COLUMN_ORDER = WORKFLOW_COLUMN_ORDER;
4693
+ exports.WorkflowConfigDialog = WorkflowConfigDialog;
4694
+ exports.WorkflowDocumentsField = WorkflowDocumentsField;
4695
+ exports.WorkflowLauncher = WorkflowLauncher;
2777
4696
  exports.WorkflowRunner = WorkflowRunner;
2778
4697
  exports.WorkflowStepBar = WorkflowStepBar;
4698
+ exports.WorkflowsTable = WorkflowsTable;
4699
+ exports.activateOnKey = activateOnKey;
2779
4700
  exports.activeStepId = activeStepId;
4701
+ exports.buildLibrarySkills = buildLibrarySkills;
4702
+ exports.buildWorkflowScopeSource = buildWorkflowScopeSource;
2780
4703
  exports.buildZipSkillImport = buildZipSkillImport;
4704
+ exports.createWorkflowColumns = createWorkflowColumns;
4705
+ exports.documentScopeLabels = documentScopeLabels;
4706
+ exports.filterLibrarySkills = filterLibrarySkills;
2781
4707
  exports.fromPlanAssignee = fromPlanAssignee;
2782
4708
  exports.fromPlanDocumentRef = fromPlanDocumentRef;
2783
4709
  exports.fromPlanSteps = fromPlanSteps;
4710
+ exports.hasTrigger = hasTrigger;
2784
4711
  exports.importMarkdownSkill = importMarkdownSkill;
2785
4712
  exports.importSkillFile = importSkillFile;
2786
4713
  exports.importSkillFromUrl = importSkillFromUrl;
2787
4714
  exports.isIncompleteSignal = isIncompleteSignal;
2788
4715
  exports.isMainSkillFile = isMainSkillFile;
4716
+ exports.isSkillRow = isSkillRow;
2789
4717
  exports.layoutFromPlanSteps = layoutFromPlanSteps;
4718
+ exports.matchWorkflowScope = matchWorkflowScope;
2790
4719
  exports.parseSkillFrontmatter = parseSkillFrontmatter;
2791
4720
  exports.readSkillArchive = readSkillArchive;
2792
4721
  exports.serializeSkill = serializeSkill;
@@ -2796,8 +4725,12 @@ exports.taskActivityHeadline = taskActivityHeadline;
2796
4725
  exports.toPlanAssignee = toPlanAssignee;
2797
4726
  exports.toPlanDocumentRef = toPlanDocumentRef;
2798
4727
  exports.toPlanSteps = toPlanSteps;
4728
+ exports.useControllableState = useControllableState;
2799
4729
  exports.useWorkflowView = useWorkflowView;
2800
4730
  exports.workflowFromSkillMarkdown = workflowFromSkillMarkdown;
4731
+ exports.workflowRunStatusLabel = workflowRunStatusLabel;
4732
+ exports.workflowStatus = workflowStatus;
2801
4733
  exports.workflowToSkillMarkdown = workflowToSkillMarkdown;
2802
- //# sourceMappingURL=chunk-LIHRGG4M.cjs.map
2803
- //# sourceMappingURL=chunk-LIHRGG4M.cjs.map
4734
+ exports.workflowTriggerType = workflowTriggerType;
4735
+ //# sourceMappingURL=chunk-3BI6EWKP.cjs.map
4736
+ //# sourceMappingURL=chunk-3BI6EWKP.cjs.map