@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.
@@ -305,7 +305,7 @@ function useKanbanBoard(options) {
305
305
  try {
306
306
  const full = await adapter.getCard(cardId);
307
307
  setSelectedCard(
308
- (prev) => prev == null || prev.id === cardId ? full : prev
308
+ (prev) => prev && prev.id === cardId ? full : prev
309
309
  );
310
310
  } catch (err) {
311
311
  if (!known) fail(err, "Failed to open card");
@@ -414,27 +414,6 @@ function useKanbanBoard(options) {
414
414
  },
415
415
  [refresh]
416
416
  );
417
- const deleteCard = react.useCallback(
418
- async (cardId) => {
419
- if (!adapter.deleteCard) return false;
420
- setError(null);
421
- const prevCards = cards;
422
- const prevSelected = selectedCard;
423
- setCards((prev) => prev.filter((c) => c.id !== cardId));
424
- setSelectedCard((prev) => prev && prev.id === cardId ? null : prev);
425
- try {
426
- await adapter.deleteCard(cardId);
427
- void silentRefresh();
428
- return true;
429
- } catch (err) {
430
- setCards(prevCards);
431
- setSelectedCard(prevSelected);
432
- fail(err, "Failed to delete card");
433
- return false;
434
- }
435
- },
436
- [adapter, cards, selectedCard, silentRefresh, fail]
437
- );
438
417
  return {
439
418
  board,
440
419
  lanes: board?.lanes ?? [],
@@ -450,7 +429,6 @@ function useKanbanBoard(options) {
450
429
  createCard,
451
430
  updateCard,
452
431
  transitionCard,
453
- deleteCard,
454
432
  handleRunTerminal
455
433
  };
456
434
  }
@@ -2744,9 +2722,6 @@ function KanbanCard({
2744
2722
  onClick,
2745
2723
  selected,
2746
2724
  dueState,
2747
- draggable,
2748
- onDragStart,
2749
- onDragEnd,
2750
2725
  className
2751
2726
  }) {
2752
2727
  const runStatus = card.run?.status;
@@ -2775,20 +2750,10 @@ function KanbanCard({
2775
2750
  onClick: () => onClick?.(card),
2776
2751
  "aria-pressed": selected,
2777
2752
  "aria-busy": isWorking,
2778
- draggable,
2779
- onDragStart: draggable ? (e) => {
2780
- e.dataTransfer.effectAllowed = "move";
2781
- e.dataTransfer.setData("text/plain", card.id);
2782
- onDragStart?.(card);
2783
- } : void 0,
2784
- onDragEnd: draggable ? () => onDragEnd?.() : void 0,
2785
2753
  className: cn9(
2786
- // Solid card: fill + border + a faint token top-sheen (adapts to theme),
2787
- // matching the host's cockpit cards (work-shell v2 visual pass).
2788
- "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",
2754
+ "relative w-full text-left rounded-lg border bg-card p-3 shadow-sm transition",
2789
2755
  "hover:shadow-md hover:border-primary/40",
2790
2756
  "focus:outline-none focus:ring-2 focus:ring-ring/50",
2791
- draggable && "cursor-grab active:cursor-grabbing",
2792
2757
  // The working card carries the SINGLE focal motion on the board (F11).
2793
2758
  isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
2794
2759
  className
@@ -2865,11 +2830,6 @@ function CapMeter({ count, cap, className }) {
2865
2830
  }
2866
2831
  );
2867
2832
  }
2868
- var AGENT_GROUPS = [
2869
- { kind: "cadra", label: "Cadra agents" },
2870
- { kind: "remote", label: "Your own agents" },
2871
- { kind: "human", label: "Teammates" }
2872
- ];
2873
2833
  function AgentKindIcon({ kind }) {
2874
2834
  const common = {
2875
2835
  viewBox: "0 0 24 24",
@@ -2912,55 +2872,17 @@ function OnlineDot({ online }) {
2912
2872
  }
2913
2873
  );
2914
2874
  }
2915
- function RemoteBadge() {
2916
- return /* @__PURE__ */ jsxRuntime.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" });
2917
- }
2918
2875
  function LaneAgentPicker({
2919
2876
  selected,
2920
2877
  options,
2921
2878
  onSelect,
2922
2879
  canEdit = true,
2923
2880
  lockedReason,
2924
- onEditAgent,
2925
2881
  className
2926
2882
  }) {
2927
2883
  const [open, setOpen] = react.useState(false);
2928
- const [placement, setPlacement] = react.useState(null);
2929
2884
  const rootRef = react.useRef(null);
2930
- const triggerRef = react.useRef(null);
2931
2885
  const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
2932
- const openMenu = () => {
2933
- const el = triggerRef.current;
2934
- if (el && typeof window !== "undefined") {
2935
- const rect = el.getBoundingClientRect();
2936
- const vw = window.innerWidth || 0;
2937
- const vh = window.innerHeight || 0;
2938
- const margin = 8;
2939
- const gap = 4;
2940
- const desired = 288;
2941
- const width = Math.max(
2942
- Math.min(rect.width || 224, Math.max(vw - margin * 2, 160)),
2943
- 160
2944
- );
2945
- const left = Math.min(
2946
- Math.max(rect.left, margin),
2947
- Math.max(vw - width - margin, margin)
2948
- );
2949
- const spaceBelow = vh - rect.bottom - gap - margin;
2950
- const spaceAbove = rect.top - gap - margin;
2951
- const flipUp = spaceBelow < desired && spaceAbove > spaceBelow;
2952
- const maxHeight = Math.max(
2953
- Math.min(desired, flipUp ? spaceAbove : spaceBelow),
2954
- 120
2955
- );
2956
- setPlacement(
2957
- flipUp ? { bottom: Math.max(vh - rect.top + gap, margin), left, width, maxHeight } : { top: rect.bottom + gap, left, width, maxHeight }
2958
- );
2959
- } else {
2960
- setPlacement(null);
2961
- }
2962
- setOpen(true);
2963
- };
2964
2886
  react.useEffect(() => {
2965
2887
  if (!open) return;
2966
2888
  const onDocDown = (e) => {
@@ -2994,28 +2916,14 @@ function LaneAgentPicker({
2994
2916
  }
2995
2917
  ),
2996
2918
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
2997
- kind === "remote" && /* @__PURE__ */ jsxRuntime.jsx(RemoteBadge, {}),
2998
2919
  /* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: selected?.online })
2999
2920
  ] });
3000
- const grouped = AGENT_GROUPS.map((group) => ({
3001
- ...group,
3002
- items: (options ?? []).filter((opt) => (opt.kind ?? "cadra") === group.kind)
3003
- })).filter((group) => group.items.length > 0);
3004
- const menuStyle = placement ? {
3005
- position: "fixed",
3006
- top: placement.top,
3007
- bottom: placement.bottom,
3008
- left: placement.left,
3009
- width: placement.width,
3010
- maxHeight: placement.maxHeight
3011
- } : void 0;
3012
2921
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
3013
2922
  editable ? /* @__PURE__ */ jsxRuntime.jsxs(
3014
2923
  "button",
3015
2924
  {
3016
- ref: triggerRef,
3017
2925
  type: "button",
3018
- onClick: () => open ? setOpen(false) : openMenu(),
2926
+ onClick: () => setOpen((o) => !o),
3019
2927
  "aria-haspopup": "listbox",
3020
2928
  "aria-expanded": open,
3021
2929
  "aria-label": `Assigned agent: ${displayLabel}. Change`,
@@ -3093,106 +3001,47 @@ function LaneAgentPicker({
3093
3001
  ),
3094
3002
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: lockedReason })
3095
3003
  ] }),
3096
- editable && open && /* @__PURE__ */ jsxRuntime.jsxs(
3097
- "div",
3004
+ editable && open && /* @__PURE__ */ jsxRuntime.jsx(
3005
+ "ul",
3098
3006
  {
3099
- style: menuStyle,
3007
+ role: "listbox",
3008
+ "aria-label": "Assign an agent",
3100
3009
  className: cn9(
3101
- "flex flex-col overflow-hidden rounded-lg border border-border bg-popover shadow-lg",
3102
- menuStyle ? "z-50" : "absolute z-20 mt-1 max-h-64 w-full"
3010
+ "absolute z-20 mt-1 max-h-64 w-full overflow-y-auto rounded-lg border border-border",
3011
+ "bg-popover p-1 shadow-lg"
3103
3012
  ),
3104
- children: [
3105
- /* @__PURE__ */ jsxRuntime.jsx(
3106
- "ul",
3107
- {
3108
- role: "listbox",
3109
- "aria-label": "Assign an agent",
3110
- className: "min-h-0 flex-1 overflow-y-auto p-1",
3111
- children: grouped.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("li", { role: "presentation", children: [
3112
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.label }),
3113
- /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "group", "aria-label": group.label, children: group.items.map((opt) => {
3114
- const isSelected = opt.id === selected?.id;
3115
- const optKind = opt.kind ?? "cadra";
3116
- return /* @__PURE__ */ jsxRuntime.jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxRuntime.jsxs(
3117
- "button",
3118
- {
3119
- type: "button",
3120
- onClick: () => {
3121
- onSelect(opt.id);
3122
- setOpen(false);
3123
- },
3124
- className: cn9(
3125
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
3126
- "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
3127
- isSelected ? "text-primary" : "text-foreground"
3128
- ),
3129
- children: [
3130
- /* @__PURE__ */ jsxRuntime.jsx(
3131
- "span",
3132
- {
3133
- className: cn9(
3134
- "grid h-5 w-5 shrink-0 place-items-center rounded-full",
3135
- optKind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
3136
- ),
3137
- children: /* @__PURE__ */ jsxRuntime.jsx(AgentKindIcon, { kind: optKind })
3138
- }
3139
- ),
3140
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3141
- optKind === "remote" && /* @__PURE__ */ jsxRuntime.jsx(RemoteBadge, {}),
3142
- /* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: opt.online }),
3143
- isSelected && /* @__PURE__ */ jsxRuntime.jsx(
3144
- "svg",
3145
- {
3146
- viewBox: "0 0 24 24",
3147
- fill: "none",
3148
- stroke: "currentColor",
3149
- strokeWidth: 2,
3150
- strokeLinecap: "round",
3151
- strokeLinejoin: "round",
3152
- "aria-hidden": true,
3153
- className: "h-3.5 w-3.5 shrink-0",
3154
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
3155
- }
3156
- )
3157
- ]
3158
- }
3159
- ) }, opt.id);
3160
- }) })
3161
- ] }, group.kind))
3162
- }
3163
- ),
3164
- onEditAgent && selected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border p-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
3013
+ children: options.map((opt) => {
3014
+ const isSelected = opt.id === selected?.id;
3015
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxRuntime.jsxs(
3165
3016
  "button",
3166
3017
  {
3167
3018
  type: "button",
3168
3019
  onClick: () => {
3169
- onEditAgent(selected.id);
3020
+ onSelect(opt.id);
3170
3021
  setOpen(false);
3171
3022
  },
3172
3023
  className: cn9(
3173
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium text-foreground",
3174
- "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50"
3024
+ "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
3025
+ "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
3026
+ isSelected ? "text-primary" : "text-foreground"
3175
3027
  ),
3176
3028
  children: [
3177
3029
  /* @__PURE__ */ jsxRuntime.jsx(
3178
- "svg",
3030
+ "span",
3179
3031
  {
3180
- viewBox: "0 0 24 24",
3181
- fill: "none",
3182
- stroke: "currentColor",
3183
- strokeWidth: 2,
3184
- strokeLinecap: "round",
3185
- strokeLinejoin: "round",
3186
- "aria-hidden": true,
3187
- className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
3188
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" })
3032
+ className: cn9(
3033
+ "grid h-5 w-5 shrink-0 place-items-center rounded-full",
3034
+ (opt.kind ?? "cadra") === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
3035
+ ),
3036
+ children: /* @__PURE__ */ jsxRuntime.jsx(AgentKindIcon, { kind: opt.kind ?? "cadra" })
3189
3037
  }
3190
3038
  ),
3191
- "Edit this agent"
3039
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3040
+ /* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: opt.online })
3192
3041
  ]
3193
3042
  }
3194
- ) })
3195
- ]
3043
+ ) }, opt.id);
3044
+ })
3196
3045
  }
3197
3046
  )
3198
3047
  ] });
@@ -3217,12 +3066,6 @@ function KanbanColumn({
3217
3066
  count,
3218
3067
  agentPicker,
3219
3068
  canEditHandlers,
3220
- draggableCards,
3221
- dragActive,
3222
- dropAllowed,
3223
- onCardDragStart,
3224
- onCardDragEnd,
3225
- onLaneDrop,
3226
3069
  className
3227
3070
  }) {
3228
3071
  const headerCount = count ?? cards.length;
@@ -3233,21 +3076,9 @@ function KanbanColumn({
3233
3076
  return /* @__PURE__ */ jsxRuntime.jsxs(
3234
3077
  "div",
3235
3078
  {
3236
- onDragOver: dropAllowed ? (e) => {
3237
- e.preventDefault();
3238
- e.dataTransfer.dropEffect = "move";
3239
- } : void 0,
3240
- onDrop: dropAllowed && onLaneDrop ? (e) => {
3241
- e.preventDefault();
3242
- onLaneDrop(lane);
3243
- } : void 0,
3244
3079
  className: cn9(
3245
- "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",
3080
+ "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",
3246
3081
  isScheduled && "border-border",
3247
- // MV4 drag affordance: allowed targets glow; other lanes dim so the
3248
- // valid drop zones read at a glance.
3249
- dragActive && dropAllowed && "border-primary/60 ring-2 ring-primary/40 bg-primary/5",
3250
- dragActive && !dropAllowed && "opacity-55",
3251
3082
  className
3252
3083
  ),
3253
3084
  children: [
@@ -3316,10 +3147,7 @@ function KanbanColumn({
3316
3147
  card,
3317
3148
  onClick: onCardClick,
3318
3149
  selected: card.id === selectedCardId,
3319
- dueState: dueStateFor(card, lane, now),
3320
- draggable: draggableCards,
3321
- onDragStart: onCardDragStart,
3322
- onDragEnd: onCardDragEnd
3150
+ dueState: dueStateFor(card, lane, now)
3323
3151
  },
3324
3152
  card.id
3325
3153
  )),
@@ -3479,8 +3307,6 @@ function KanbanBoard({
3479
3307
  laneAgentPicker,
3480
3308
  scheduleStatus,
3481
3309
  focusCardId,
3482
- renderCardDrawer,
3483
- enableDrag,
3484
3310
  className
3485
3311
  }) {
3486
3312
  const {
@@ -3495,7 +3321,6 @@ function KanbanBoard({
3495
3321
  createCard,
3496
3322
  updateCard,
3497
3323
  transitionCard,
3498
- deleteCard,
3499
3324
  handleRunTerminal
3500
3325
  } = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
3501
3326
  const lastFocusedRef = react.useRef(void 0);
@@ -3540,44 +3365,6 @@ function KanbanBoard({
3540
3365
  (cardId, toLane) => transitionCard({ cardId, targetLane: toLane }),
3541
3366
  [transitionCard]
3542
3367
  );
3543
- const [dragging, setDragging] = react.useState(null);
3544
- const draggingRef = react.useRef(null);
3545
- const dropInFlightRef = react.useRef(null);
3546
- const allowedDropLanes = react.useMemo(() => {
3547
- if (!dragging || !board?.transitions) return /* @__PURE__ */ new Set();
3548
- return new Set(
3549
- board.transitions.filter((t) => t.fromLane === dragging.lane && t.manualAllowed).map((t) => t.toLane)
3550
- );
3551
- }, [dragging, board?.transitions]);
3552
- const handleCardDragStart = react.useCallback((card) => {
3553
- const d = { id: card.id, lane: card.lane };
3554
- draggingRef.current = d;
3555
- setDragging(d);
3556
- }, []);
3557
- const handleCardDragEnd = react.useCallback(() => {
3558
- draggingRef.current = null;
3559
- setDragging(null);
3560
- }, []);
3561
- const handleLaneDrop = react.useCallback(
3562
- (lane) => {
3563
- const cur = draggingRef.current;
3564
- draggingRef.current = null;
3565
- setDragging(null);
3566
- if (!cur || lane.key === cur.lane) return;
3567
- if (dropInFlightRef.current === cur.id) return;
3568
- const allowed = (board?.transitions ?? []).some(
3569
- (t) => t.fromLane === cur.lane && t.toLane === lane.key && t.manualAllowed
3570
- );
3571
- if (!allowed) return;
3572
- dropInFlightRef.current = cur.id;
3573
- void Promise.resolve(transitionCard({ cardId: cur.id, targetLane: lane.key })).finally(
3574
- () => {
3575
- if (dropInFlightRef.current === cur.id) dropInFlightRef.current = null;
3576
- }
3577
- );
3578
- },
3579
- [board?.transitions, transitionCard]
3580
- );
3581
3368
  const initialLaneKey = lanes.find((l) => !l.terminal)?.key ?? lanes[0]?.key;
3582
3369
  const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
3583
3370
  const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
@@ -3598,32 +3385,12 @@ function KanbanBoard({
3598
3385
  showCreate: enableCreate && lane.key === initialLaneKey,
3599
3386
  count: laneCounts?.[lane.key],
3600
3387
  agentPicker: laneAgentPicker?.(lane),
3601
- canEditHandlers,
3602
- draggableCards: enableDrag && enableAdvance,
3603
- dragActive: !!dragging,
3604
- dropAllowed: !!dragging && dragging.lane !== lane.key && allowedDropLanes.has(lane.key),
3605
- onCardDragStart: handleCardDragStart,
3606
- onCardDragEnd: handleCardDragEnd,
3607
- onLaneDrop: handleLaneDrop
3388
+ canEditHandlers
3608
3389
  },
3609
3390
  lane.id ?? lane.key
3610
3391
  ))
3611
3392
  ] }),
3612
- selectedCard && (renderCardDrawer ? renderCardDrawer({
3613
- card: selectedCard,
3614
- adapter,
3615
- lanes,
3616
- transitions: enableAdvance ? board?.transitions : void 0,
3617
- canAdvance: canAdvanceSelected,
3618
- onClose: closeCard,
3619
- onRetry: onRetryCard ? handleRetry : void 0,
3620
- onUpdate: enableEdit ? handleUpdate : void 0,
3621
- onAdvance: enableAdvance ? handleAdvance : void 0,
3622
- onTransition: enableAdvance ? handleTransition : void 0,
3623
- onDelete: adapter.deleteCard ? deleteCard : void 0,
3624
- onRunTerminal: handleRunTerminal,
3625
- onError
3626
- }) : /* @__PURE__ */ jsxRuntime.jsx(
3393
+ selectedCard && /* @__PURE__ */ jsxRuntime.jsx(
3627
3394
  CardDrawer,
3628
3395
  {
3629
3396
  card: selectedCard,
@@ -3639,7 +3406,7 @@ function KanbanBoard({
3639
3406
  onRunTerminal: handleRunTerminal,
3640
3407
  onError
3641
3408
  }
3642
- ))
3409
+ )
3643
3410
  ] })
3644
3411
  ] });
3645
3412
  }
@@ -3664,7 +3431,6 @@ function composeAdapter(source, boardConfigUuid, version, cardSource) {
3664
3431
  transitionCard(input) {
3665
3432
  return cardSource.transitionCard(input);
3666
3433
  },
3667
- ...cardSource.deleteCard ? { deleteCard: (id) => cardSource.deleteCard(id) } : {},
3668
3434
  ...cardSource.createRunStream ? { createRunStream: (id) => cardSource.createRunStream(id) } : {}
3669
3435
  };
3670
3436
  }