@cadraos/sdk 0.3.10 → 0.3.12

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.
@@ -298,7 +298,7 @@ function useKanbanBoard(options) {
298
298
  try {
299
299
  const full = await adapter.getCard(cardId);
300
300
  setSelectedCard(
301
- (prev) => prev == null || prev.id === cardId ? full : prev
301
+ (prev) => prev && prev.id === cardId ? full : prev
302
302
  );
303
303
  } catch (err) {
304
304
  if (!known) fail(err, "Failed to open card");
@@ -407,27 +407,6 @@ function useKanbanBoard(options) {
407
407
  },
408
408
  [refresh]
409
409
  );
410
- const deleteCard = useCallback(
411
- async (cardId) => {
412
- if (!adapter.deleteCard) return false;
413
- setError(null);
414
- const prevCards = cards;
415
- const prevSelected = selectedCard;
416
- setCards((prev) => prev.filter((c) => c.id !== cardId));
417
- setSelectedCard((prev) => prev && prev.id === cardId ? null : prev);
418
- try {
419
- await adapter.deleteCard(cardId);
420
- void silentRefresh();
421
- return true;
422
- } catch (err) {
423
- setCards(prevCards);
424
- setSelectedCard(prevSelected);
425
- fail(err, "Failed to delete card");
426
- return false;
427
- }
428
- },
429
- [adapter, cards, selectedCard, silentRefresh, fail]
430
- );
431
410
  return {
432
411
  board,
433
412
  lanes: board?.lanes ?? [],
@@ -443,7 +422,6 @@ function useKanbanBoard(options) {
443
422
  createCard,
444
423
  updateCard,
445
424
  transitionCard,
446
- deleteCard,
447
425
  handleRunTerminal
448
426
  };
449
427
  }
@@ -2737,9 +2715,6 @@ function KanbanCard({
2737
2715
  onClick,
2738
2716
  selected,
2739
2717
  dueState,
2740
- draggable,
2741
- onDragStart,
2742
- onDragEnd,
2743
2718
  className
2744
2719
  }) {
2745
2720
  const runStatus = card.run?.status;
@@ -2768,20 +2743,10 @@ function KanbanCard({
2768
2743
  onClick: () => onClick?.(card),
2769
2744
  "aria-pressed": selected,
2770
2745
  "aria-busy": isWorking,
2771
- draggable,
2772
- onDragStart: draggable ? (e) => {
2773
- e.dataTransfer.effectAllowed = "move";
2774
- e.dataTransfer.setData("text/plain", card.id);
2775
- onDragStart?.(card);
2776
- } : void 0,
2777
- onDragEnd: draggable ? () => onDragEnd?.() : void 0,
2778
2746
  className: cn9(
2779
- // Solid card: fill + border + a faint token top-sheen (adapts to theme),
2780
- // matching the host's cockpit cards (work-shell v2 visual pass).
2781
- "relative w-full text-left rounded-xl border bg-card bg-gradient-to-b from-foreground/[0.03] to-transparent p-3 shadow-sm motion-safe:transition-shadow",
2747
+ "relative w-full text-left rounded-lg border bg-card p-3 shadow-sm transition",
2782
2748
  "hover:shadow-md hover:border-primary/40",
2783
2749
  "focus:outline-none focus:ring-2 focus:ring-ring/50",
2784
- draggable && "cursor-grab active:cursor-grabbing",
2785
2750
  // The working card carries the SINGLE focal motion on the board (F11).
2786
2751
  isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
2787
2752
  className
@@ -2858,11 +2823,6 @@ function CapMeter({ count, cap, className }) {
2858
2823
  }
2859
2824
  );
2860
2825
  }
2861
- var AGENT_GROUPS = [
2862
- { kind: "cadra", label: "Cadra agents" },
2863
- { kind: "remote", label: "Your own agents" },
2864
- { kind: "human", label: "Teammates" }
2865
- ];
2866
2826
  function AgentKindIcon({ kind }) {
2867
2827
  const common = {
2868
2828
  viewBox: "0 0 24 24",
@@ -2905,55 +2865,17 @@ function OnlineDot({ online }) {
2905
2865
  }
2906
2866
  );
2907
2867
  }
2908
- function RemoteBadge() {
2909
- return /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full border border-accent/40 bg-accent/15 px-1.5 py-px text-[10px] font-semibold leading-4 text-accent", children: "Remote" });
2910
- }
2911
2868
  function LaneAgentPicker({
2912
2869
  selected,
2913
2870
  options,
2914
2871
  onSelect,
2915
2872
  canEdit = true,
2916
2873
  lockedReason,
2917
- onEditAgent,
2918
2874
  className
2919
2875
  }) {
2920
2876
  const [open, setOpen] = useState(false);
2921
- const [placement, setPlacement] = useState(null);
2922
2877
  const rootRef = useRef(null);
2923
- const triggerRef = useRef(null);
2924
2878
  const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
2925
- const openMenu = () => {
2926
- const el = triggerRef.current;
2927
- if (el && typeof window !== "undefined") {
2928
- const rect = el.getBoundingClientRect();
2929
- const vw = window.innerWidth || 0;
2930
- const vh = window.innerHeight || 0;
2931
- const margin = 8;
2932
- const gap = 4;
2933
- const desired = 288;
2934
- const width = Math.max(
2935
- Math.min(rect.width || 224, Math.max(vw - margin * 2, 160)),
2936
- 160
2937
- );
2938
- const left = Math.min(
2939
- Math.max(rect.left, margin),
2940
- Math.max(vw - width - margin, margin)
2941
- );
2942
- const spaceBelow = vh - rect.bottom - gap - margin;
2943
- const spaceAbove = rect.top - gap - margin;
2944
- const flipUp = spaceBelow < desired && spaceAbove > spaceBelow;
2945
- const maxHeight = Math.max(
2946
- Math.min(desired, flipUp ? spaceAbove : spaceBelow),
2947
- 120
2948
- );
2949
- setPlacement(
2950
- flipUp ? { bottom: Math.max(vh - rect.top + gap, margin), left, width, maxHeight } : { top: rect.bottom + gap, left, width, maxHeight }
2951
- );
2952
- } else {
2953
- setPlacement(null);
2954
- }
2955
- setOpen(true);
2956
- };
2957
2879
  useEffect(() => {
2958
2880
  if (!open) return;
2959
2881
  const onDocDown = (e) => {
@@ -2987,28 +2909,14 @@ function LaneAgentPicker({
2987
2909
  }
2988
2910
  ),
2989
2911
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
2990
- kind === "remote" && /* @__PURE__ */ jsx(RemoteBadge, {}),
2991
2912
  /* @__PURE__ */ jsx(OnlineDot, { online: selected?.online })
2992
2913
  ] });
2993
- const grouped = AGENT_GROUPS.map((group) => ({
2994
- ...group,
2995
- items: (options ?? []).filter((opt) => (opt.kind ?? "cadra") === group.kind)
2996
- })).filter((group) => group.items.length > 0);
2997
- const menuStyle = placement ? {
2998
- position: "fixed",
2999
- top: placement.top,
3000
- bottom: placement.bottom,
3001
- left: placement.left,
3002
- width: placement.width,
3003
- maxHeight: placement.maxHeight
3004
- } : void 0;
3005
2914
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
3006
2915
  editable ? /* @__PURE__ */ jsxs(
3007
2916
  "button",
3008
2917
  {
3009
- ref: triggerRef,
3010
2918
  type: "button",
3011
- onClick: () => open ? setOpen(false) : openMenu(),
2919
+ onClick: () => setOpen((o) => !o),
3012
2920
  "aria-haspopup": "listbox",
3013
2921
  "aria-expanded": open,
3014
2922
  "aria-label": `Assigned agent: ${displayLabel}. Change`,
@@ -3086,106 +2994,47 @@ function LaneAgentPicker({
3086
2994
  ),
3087
2995
  /* @__PURE__ */ jsx("span", { children: lockedReason })
3088
2996
  ] }),
3089
- editable && open && /* @__PURE__ */ jsxs(
3090
- "div",
2997
+ editable && open && /* @__PURE__ */ jsx(
2998
+ "ul",
3091
2999
  {
3092
- style: menuStyle,
3000
+ role: "listbox",
3001
+ "aria-label": "Assign an agent",
3093
3002
  className: cn9(
3094
- "flex flex-col overflow-hidden rounded-lg border border-border bg-popover shadow-lg",
3095
- menuStyle ? "z-50" : "absolute z-20 mt-1 max-h-64 w-full"
3003
+ "absolute z-20 mt-1 max-h-64 w-full overflow-y-auto rounded-lg border border-border",
3004
+ "bg-popover p-1 shadow-lg"
3096
3005
  ),
3097
- children: [
3098
- /* @__PURE__ */ jsx(
3099
- "ul",
3100
- {
3101
- role: "listbox",
3102
- "aria-label": "Assign an agent",
3103
- className: "min-h-0 flex-1 overflow-y-auto p-1",
3104
- children: grouped.map((group) => /* @__PURE__ */ jsxs("li", { role: "presentation", children: [
3105
- /* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.label }),
3106
- /* @__PURE__ */ jsx("ul", { role: "group", "aria-label": group.label, children: group.items.map((opt) => {
3107
- const isSelected = opt.id === selected?.id;
3108
- const optKind = opt.kind ?? "cadra";
3109
- return /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxs(
3110
- "button",
3111
- {
3112
- type: "button",
3113
- onClick: () => {
3114
- onSelect(opt.id);
3115
- setOpen(false);
3116
- },
3117
- className: cn9(
3118
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
3119
- "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
3120
- isSelected ? "text-primary" : "text-foreground"
3121
- ),
3122
- children: [
3123
- /* @__PURE__ */ jsx(
3124
- "span",
3125
- {
3126
- className: cn9(
3127
- "grid h-5 w-5 shrink-0 place-items-center rounded-full",
3128
- optKind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
3129
- ),
3130
- children: /* @__PURE__ */ jsx(AgentKindIcon, { kind: optKind })
3131
- }
3132
- ),
3133
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3134
- optKind === "remote" && /* @__PURE__ */ jsx(RemoteBadge, {}),
3135
- /* @__PURE__ */ jsx(OnlineDot, { online: opt.online }),
3136
- isSelected && /* @__PURE__ */ jsx(
3137
- "svg",
3138
- {
3139
- viewBox: "0 0 24 24",
3140
- fill: "none",
3141
- stroke: "currentColor",
3142
- strokeWidth: 2,
3143
- strokeLinecap: "round",
3144
- strokeLinejoin: "round",
3145
- "aria-hidden": true,
3146
- className: "h-3.5 w-3.5 shrink-0",
3147
- children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" })
3148
- }
3149
- )
3150
- ]
3151
- }
3152
- ) }, opt.id);
3153
- }) })
3154
- ] }, group.kind))
3155
- }
3156
- ),
3157
- onEditAgent && selected && /* @__PURE__ */ jsx("div", { className: "border-t border-border p-1", children: /* @__PURE__ */ jsxs(
3006
+ children: options.map((opt) => {
3007
+ const isSelected = opt.id === selected?.id;
3008
+ return /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxs(
3158
3009
  "button",
3159
3010
  {
3160
3011
  type: "button",
3161
3012
  onClick: () => {
3162
- onEditAgent(selected.id);
3013
+ onSelect(opt.id);
3163
3014
  setOpen(false);
3164
3015
  },
3165
3016
  className: cn9(
3166
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium text-foreground",
3167
- "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50"
3017
+ "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
3018
+ "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
3019
+ isSelected ? "text-primary" : "text-foreground"
3168
3020
  ),
3169
3021
  children: [
3170
3022
  /* @__PURE__ */ jsx(
3171
- "svg",
3023
+ "span",
3172
3024
  {
3173
- viewBox: "0 0 24 24",
3174
- fill: "none",
3175
- stroke: "currentColor",
3176
- strokeWidth: 2,
3177
- strokeLinecap: "round",
3178
- strokeLinejoin: "round",
3179
- "aria-hidden": true,
3180
- className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
3181
- children: /* @__PURE__ */ jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" })
3025
+ className: cn9(
3026
+ "grid h-5 w-5 shrink-0 place-items-center rounded-full",
3027
+ (opt.kind ?? "cadra") === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
3028
+ ),
3029
+ children: /* @__PURE__ */ jsx(AgentKindIcon, { kind: opt.kind ?? "cadra" })
3182
3030
  }
3183
3031
  ),
3184
- "Edit this agent"
3032
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3033
+ /* @__PURE__ */ jsx(OnlineDot, { online: opt.online })
3185
3034
  ]
3186
3035
  }
3187
- ) })
3188
- ]
3036
+ ) }, opt.id);
3037
+ })
3189
3038
  }
3190
3039
  )
3191
3040
  ] });
@@ -3210,12 +3059,6 @@ function KanbanColumn({
3210
3059
  count,
3211
3060
  agentPicker,
3212
3061
  canEditHandlers,
3213
- draggableCards,
3214
- dragActive,
3215
- dropAllowed,
3216
- onCardDragStart,
3217
- onCardDragEnd,
3218
- onLaneDrop,
3219
3062
  className
3220
3063
  }) {
3221
3064
  const headerCount = count ?? cards.length;
@@ -3226,21 +3069,9 @@ function KanbanColumn({
3226
3069
  return /* @__PURE__ */ jsxs(
3227
3070
  "div",
3228
3071
  {
3229
- onDragOver: dropAllowed ? (e) => {
3230
- e.preventDefault();
3231
- e.dataTransfer.dropEffect = "move";
3232
- } : void 0,
3233
- onDrop: dropAllowed && onLaneDrop ? (e) => {
3234
- e.preventDefault();
3235
- onLaneDrop(lane);
3236
- } : void 0,
3237
3072
  className: cn9(
3238
- "flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-muted/40 border border-border transition sm:w-72 sm:max-w-none",
3073
+ "flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-muted/40 border border-border sm:w-72 sm:max-w-none",
3239
3074
  isScheduled && "border-border",
3240
- // MV4 drag affordance: allowed targets glow; other lanes dim so the
3241
- // valid drop zones read at a glance.
3242
- dragActive && dropAllowed && "border-primary/60 ring-2 ring-primary/40 bg-primary/5",
3243
- dragActive && !dropAllowed && "opacity-55",
3244
3075
  className
3245
3076
  ),
3246
3077
  children: [
@@ -3309,10 +3140,7 @@ function KanbanColumn({
3309
3140
  card,
3310
3141
  onClick: onCardClick,
3311
3142
  selected: card.id === selectedCardId,
3312
- dueState: dueStateFor(card, lane, now),
3313
- draggable: draggableCards,
3314
- onDragStart: onCardDragStart,
3315
- onDragEnd: onCardDragEnd
3143
+ dueState: dueStateFor(card, lane, now)
3316
3144
  },
3317
3145
  card.id
3318
3146
  )),
@@ -3472,8 +3300,6 @@ function KanbanBoard({
3472
3300
  laneAgentPicker,
3473
3301
  scheduleStatus,
3474
3302
  focusCardId,
3475
- renderCardDrawer,
3476
- enableDrag,
3477
3303
  className
3478
3304
  }) {
3479
3305
  const {
@@ -3488,7 +3314,6 @@ function KanbanBoard({
3488
3314
  createCard,
3489
3315
  updateCard,
3490
3316
  transitionCard,
3491
- deleteCard,
3492
3317
  handleRunTerminal
3493
3318
  } = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
3494
3319
  const lastFocusedRef = useRef(void 0);
@@ -3533,44 +3358,6 @@ function KanbanBoard({
3533
3358
  (cardId, toLane) => transitionCard({ cardId, targetLane: toLane }),
3534
3359
  [transitionCard]
3535
3360
  );
3536
- const [dragging, setDragging] = useState(null);
3537
- const draggingRef = useRef(null);
3538
- const dropInFlightRef = useRef(null);
3539
- const allowedDropLanes = useMemo(() => {
3540
- if (!dragging || !board?.transitions) return /* @__PURE__ */ new Set();
3541
- return new Set(
3542
- board.transitions.filter((t) => t.fromLane === dragging.lane && t.manualAllowed).map((t) => t.toLane)
3543
- );
3544
- }, [dragging, board?.transitions]);
3545
- const handleCardDragStart = useCallback((card) => {
3546
- const d = { id: card.id, lane: card.lane };
3547
- draggingRef.current = d;
3548
- setDragging(d);
3549
- }, []);
3550
- const handleCardDragEnd = useCallback(() => {
3551
- draggingRef.current = null;
3552
- setDragging(null);
3553
- }, []);
3554
- const handleLaneDrop = useCallback(
3555
- (lane) => {
3556
- const cur = draggingRef.current;
3557
- draggingRef.current = null;
3558
- setDragging(null);
3559
- if (!cur || lane.key === cur.lane) return;
3560
- if (dropInFlightRef.current === cur.id) return;
3561
- const allowed = (board?.transitions ?? []).some(
3562
- (t) => t.fromLane === cur.lane && t.toLane === lane.key && t.manualAllowed
3563
- );
3564
- if (!allowed) return;
3565
- dropInFlightRef.current = cur.id;
3566
- void Promise.resolve(transitionCard({ cardId: cur.id, targetLane: lane.key })).finally(
3567
- () => {
3568
- if (dropInFlightRef.current === cur.id) dropInFlightRef.current = null;
3569
- }
3570
- );
3571
- },
3572
- [board?.transitions, transitionCard]
3573
- );
3574
3361
  const initialLaneKey = lanes.find((l) => !l.terminal)?.key ?? lanes[0]?.key;
3575
3362
  const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
3576
3363
  const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
@@ -3591,32 +3378,12 @@ function KanbanBoard({
3591
3378
  showCreate: enableCreate && lane.key === initialLaneKey,
3592
3379
  count: laneCounts?.[lane.key],
3593
3380
  agentPicker: laneAgentPicker?.(lane),
3594
- canEditHandlers,
3595
- draggableCards: enableDrag && enableAdvance,
3596
- dragActive: !!dragging,
3597
- dropAllowed: !!dragging && dragging.lane !== lane.key && allowedDropLanes.has(lane.key),
3598
- onCardDragStart: handleCardDragStart,
3599
- onCardDragEnd: handleCardDragEnd,
3600
- onLaneDrop: handleLaneDrop
3381
+ canEditHandlers
3601
3382
  },
3602
3383
  lane.id ?? lane.key
3603
3384
  ))
3604
3385
  ] }),
3605
- selectedCard && (renderCardDrawer ? renderCardDrawer({
3606
- card: selectedCard,
3607
- adapter,
3608
- lanes,
3609
- transitions: enableAdvance ? board?.transitions : void 0,
3610
- canAdvance: canAdvanceSelected,
3611
- onClose: closeCard,
3612
- onRetry: onRetryCard ? handleRetry : void 0,
3613
- onUpdate: enableEdit ? handleUpdate : void 0,
3614
- onAdvance: enableAdvance ? handleAdvance : void 0,
3615
- onTransition: enableAdvance ? handleTransition : void 0,
3616
- onDelete: adapter.deleteCard ? deleteCard : void 0,
3617
- onRunTerminal: handleRunTerminal,
3618
- onError
3619
- }) : /* @__PURE__ */ jsx(
3386
+ selectedCard && /* @__PURE__ */ jsx(
3620
3387
  CardDrawer,
3621
3388
  {
3622
3389
  card: selectedCard,
@@ -3632,7 +3399,7 @@ function KanbanBoard({
3632
3399
  onRunTerminal: handleRunTerminal,
3633
3400
  onError
3634
3401
  }
3635
- ))
3402
+ )
3636
3403
  ] })
3637
3404
  ] });
3638
3405
  }
@@ -3657,7 +3424,6 @@ function composeAdapter(source, boardConfigUuid, version, cardSource) {
3657
3424
  transitionCard(input) {
3658
3425
  return cardSource.transitionCard(input);
3659
3426
  },
3660
- ...cardSource.deleteCard ? { deleteCard: (id) => cardSource.deleteCard(id) } : {},
3661
3427
  ...cardSource.createRunStream ? { createRunStream: (id) => cardSource.createRunStream(id) } : {}
3662
3428
  };
3663
3429
  }