@cadraos/sdk 0.3.11 → 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.
@@ -258,12 +258,9 @@ function useKanbanBoard(options) {
258
258
  ]);
259
259
  setBoard(nextBoard);
260
260
  setCards(cardList.cards);
261
- setSelectedCard((prev) => {
262
- if (!prev) return prev;
263
- const next = cardList.cards.find((c) => c.id === prev.id);
264
- if (!next) return prev;
265
- return next.run ? next : { ...next, run: prev.run };
266
- });
261
+ setSelectedCard(
262
+ (prev) => prev ? cardList.cards.find((c) => c.id === prev.id) ?? prev : prev
263
+ );
267
264
  } catch (err) {
268
265
  fail(err, "Failed to load board");
269
266
  } finally {
@@ -278,12 +275,9 @@ function useKanbanBoard(options) {
278
275
  ]);
279
276
  setBoard(nextBoard);
280
277
  setCards(cardList.cards);
281
- setSelectedCard((prev) => {
282
- if (!prev) return prev;
283
- const next = cardList.cards.find((c) => c.id === prev.id);
284
- if (!next) return prev;
285
- return next.run ? next : { ...next, run: prev.run };
286
- });
278
+ setSelectedCard(
279
+ (prev) => prev ? cardList.cards.find((c) => c.id === prev.id) ?? prev : prev
280
+ );
287
281
  } catch {
288
282
  }
289
283
  }, [adapter]);
@@ -304,7 +298,7 @@ function useKanbanBoard(options) {
304
298
  try {
305
299
  const full = await adapter.getCard(cardId);
306
300
  setSelectedCard(
307
- (prev) => prev == null || prev.id === cardId ? full : prev
301
+ (prev) => prev && prev.id === cardId ? full : prev
308
302
  );
309
303
  } catch (err) {
310
304
  if (!known) fail(err, "Failed to open card");
@@ -413,27 +407,6 @@ function useKanbanBoard(options) {
413
407
  },
414
408
  [refresh]
415
409
  );
416
- const deleteCard = useCallback(
417
- async (cardId) => {
418
- if (!adapter.deleteCard) return false;
419
- setError(null);
420
- const prevCards = cards;
421
- const prevSelected = selectedCard;
422
- setCards((prev) => prev.filter((c) => c.id !== cardId));
423
- setSelectedCard((prev) => prev && prev.id === cardId ? null : prev);
424
- try {
425
- await adapter.deleteCard(cardId);
426
- void silentRefresh();
427
- return true;
428
- } catch (err) {
429
- setCards(prevCards);
430
- setSelectedCard(prevSelected);
431
- fail(err, "Failed to delete card");
432
- return false;
433
- }
434
- },
435
- [adapter, cards, selectedCard, silentRefresh, fail]
436
- );
437
410
  return {
438
411
  board,
439
412
  lanes: board?.lanes ?? [],
@@ -449,7 +422,6 @@ function useKanbanBoard(options) {
449
422
  createCard,
450
423
  updateCard,
451
424
  transitionCard,
452
- deleteCard,
453
425
  handleRunTerminal
454
426
  };
455
427
  }
@@ -2743,9 +2715,6 @@ function KanbanCard({
2743
2715
  onClick,
2744
2716
  selected,
2745
2717
  dueState,
2746
- draggable,
2747
- onDragStart,
2748
- onDragEnd,
2749
2718
  className
2750
2719
  }) {
2751
2720
  const runStatus = card.run?.status;
@@ -2774,20 +2743,10 @@ function KanbanCard({
2774
2743
  onClick: () => onClick?.(card),
2775
2744
  "aria-pressed": selected,
2776
2745
  "aria-busy": isWorking,
2777
- draggable,
2778
- onDragStart: draggable ? (e) => {
2779
- e.dataTransfer.effectAllowed = "move";
2780
- e.dataTransfer.setData("text/plain", card.id);
2781
- onDragStart?.(card);
2782
- } : void 0,
2783
- onDragEnd: draggable ? () => onDragEnd?.() : void 0,
2784
2746
  className: cn9(
2785
- // Solid card: fill + border + a faint token top-sheen (adapts to theme),
2786
- // matching the host's cockpit cards (work-shell v2 visual pass).
2787
- "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",
2788
2748
  "hover:shadow-md hover:border-primary/40",
2789
2749
  "focus:outline-none focus:ring-2 focus:ring-ring/50",
2790
- draggable && "cursor-grab active:cursor-grabbing",
2791
2750
  // The working card carries the SINGLE focal motion on the board (F11).
2792
2751
  isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
2793
2752
  className
@@ -2864,11 +2823,6 @@ function CapMeter({ count, cap, className }) {
2864
2823
  }
2865
2824
  );
2866
2825
  }
2867
- var AGENT_GROUPS = [
2868
- { kind: "cadra", label: "Cadra agents" },
2869
- { kind: "remote", label: "Your own agents" },
2870
- { kind: "human", label: "Teammates" }
2871
- ];
2872
2826
  function AgentKindIcon({ kind }) {
2873
2827
  const common = {
2874
2828
  viewBox: "0 0 24 24",
@@ -2911,55 +2865,17 @@ function OnlineDot({ online }) {
2911
2865
  }
2912
2866
  );
2913
2867
  }
2914
- function RemoteBadge() {
2915
- 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" });
2916
- }
2917
2868
  function LaneAgentPicker({
2918
2869
  selected,
2919
2870
  options,
2920
2871
  onSelect,
2921
2872
  canEdit = true,
2922
2873
  lockedReason,
2923
- onEditAgent,
2924
2874
  className
2925
2875
  }) {
2926
2876
  const [open, setOpen] = useState(false);
2927
- const [placement, setPlacement] = useState(null);
2928
2877
  const rootRef = useRef(null);
2929
- const triggerRef = useRef(null);
2930
2878
  const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
2931
- const openMenu = () => {
2932
- const el = triggerRef.current;
2933
- if (el && typeof window !== "undefined") {
2934
- const rect = el.getBoundingClientRect();
2935
- const vw = window.innerWidth || 0;
2936
- const vh = window.innerHeight || 0;
2937
- const margin = 8;
2938
- const gap = 4;
2939
- const desired = 288;
2940
- const width = Math.max(
2941
- Math.min(rect.width || 224, Math.max(vw - margin * 2, 160)),
2942
- 160
2943
- );
2944
- const left = Math.min(
2945
- Math.max(rect.left, margin),
2946
- Math.max(vw - width - margin, margin)
2947
- );
2948
- const spaceBelow = vh - rect.bottom - gap - margin;
2949
- const spaceAbove = rect.top - gap - margin;
2950
- const flipUp = spaceBelow < desired && spaceAbove > spaceBelow;
2951
- const maxHeight = Math.max(
2952
- Math.min(desired, flipUp ? spaceAbove : spaceBelow),
2953
- 120
2954
- );
2955
- setPlacement(
2956
- flipUp ? { bottom: Math.max(vh - rect.top + gap, margin), left, width, maxHeight } : { top: rect.bottom + gap, left, width, maxHeight }
2957
- );
2958
- } else {
2959
- setPlacement(null);
2960
- }
2961
- setOpen(true);
2962
- };
2963
2879
  useEffect(() => {
2964
2880
  if (!open) return;
2965
2881
  const onDocDown = (e) => {
@@ -2993,28 +2909,14 @@ function LaneAgentPicker({
2993
2909
  }
2994
2910
  ),
2995
2911
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
2996
- kind === "remote" && /* @__PURE__ */ jsx(RemoteBadge, {}),
2997
2912
  /* @__PURE__ */ jsx(OnlineDot, { online: selected?.online })
2998
2913
  ] });
2999
- const grouped = AGENT_GROUPS.map((group) => ({
3000
- ...group,
3001
- items: (options ?? []).filter((opt) => (opt.kind ?? "cadra") === group.kind)
3002
- })).filter((group) => group.items.length > 0);
3003
- const menuStyle = placement ? {
3004
- position: "fixed",
3005
- top: placement.top,
3006
- bottom: placement.bottom,
3007
- left: placement.left,
3008
- width: placement.width,
3009
- maxHeight: placement.maxHeight
3010
- } : void 0;
3011
2914
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
3012
2915
  editable ? /* @__PURE__ */ jsxs(
3013
2916
  "button",
3014
2917
  {
3015
- ref: triggerRef,
3016
2918
  type: "button",
3017
- onClick: () => open ? setOpen(false) : openMenu(),
2919
+ onClick: () => setOpen((o) => !o),
3018
2920
  "aria-haspopup": "listbox",
3019
2921
  "aria-expanded": open,
3020
2922
  "aria-label": `Assigned agent: ${displayLabel}. Change`,
@@ -3092,106 +2994,47 @@ function LaneAgentPicker({
3092
2994
  ),
3093
2995
  /* @__PURE__ */ jsx("span", { children: lockedReason })
3094
2996
  ] }),
3095
- editable && open && /* @__PURE__ */ jsxs(
3096
- "div",
2997
+ editable && open && /* @__PURE__ */ jsx(
2998
+ "ul",
3097
2999
  {
3098
- style: menuStyle,
3000
+ role: "listbox",
3001
+ "aria-label": "Assign an agent",
3099
3002
  className: cn9(
3100
- "flex flex-col overflow-hidden rounded-lg border border-border bg-popover shadow-lg",
3101
- 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"
3102
3005
  ),
3103
- children: [
3104
- /* @__PURE__ */ jsx(
3105
- "ul",
3106
- {
3107
- role: "listbox",
3108
- "aria-label": "Assign an agent",
3109
- className: "min-h-0 flex-1 overflow-y-auto p-1",
3110
- children: grouped.map((group) => /* @__PURE__ */ jsxs("li", { role: "presentation", children: [
3111
- /* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.label }),
3112
- /* @__PURE__ */ jsx("ul", { role: "group", "aria-label": group.label, children: group.items.map((opt) => {
3113
- const isSelected = opt.id === selected?.id;
3114
- const optKind = opt.kind ?? "cadra";
3115
- return /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxs(
3116
- "button",
3117
- {
3118
- type: "button",
3119
- onClick: () => {
3120
- onSelect(opt.id);
3121
- setOpen(false);
3122
- },
3123
- className: cn9(
3124
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
3125
- "hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
3126
- isSelected ? "text-primary" : "text-foreground"
3127
- ),
3128
- children: [
3129
- /* @__PURE__ */ jsx(
3130
- "span",
3131
- {
3132
- className: cn9(
3133
- "grid h-5 w-5 shrink-0 place-items-center rounded-full",
3134
- optKind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
3135
- ),
3136
- children: /* @__PURE__ */ jsx(AgentKindIcon, { kind: optKind })
3137
- }
3138
- ),
3139
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3140
- optKind === "remote" && /* @__PURE__ */ jsx(RemoteBadge, {}),
3141
- /* @__PURE__ */ jsx(OnlineDot, { online: opt.online }),
3142
- isSelected && /* @__PURE__ */ jsx(
3143
- "svg",
3144
- {
3145
- viewBox: "0 0 24 24",
3146
- fill: "none",
3147
- stroke: "currentColor",
3148
- strokeWidth: 2,
3149
- strokeLinecap: "round",
3150
- strokeLinejoin: "round",
3151
- "aria-hidden": true,
3152
- className: "h-3.5 w-3.5 shrink-0",
3153
- children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" })
3154
- }
3155
- )
3156
- ]
3157
- }
3158
- ) }, opt.id);
3159
- }) })
3160
- ] }, group.kind))
3161
- }
3162
- ),
3163
- 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(
3164
3009
  "button",
3165
3010
  {
3166
3011
  type: "button",
3167
3012
  onClick: () => {
3168
- onEditAgent(selected.id);
3013
+ onSelect(opt.id);
3169
3014
  setOpen(false);
3170
3015
  },
3171
3016
  className: cn9(
3172
- "flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium text-foreground",
3173
- "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"
3174
3020
  ),
3175
3021
  children: [
3176
3022
  /* @__PURE__ */ jsx(
3177
- "svg",
3023
+ "span",
3178
3024
  {
3179
- viewBox: "0 0 24 24",
3180
- fill: "none",
3181
- stroke: "currentColor",
3182
- strokeWidth: 2,
3183
- strokeLinecap: "round",
3184
- strokeLinejoin: "round",
3185
- "aria-hidden": true,
3186
- className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
3187
- 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" })
3188
3030
  }
3189
3031
  ),
3190
- "Edit this agent"
3032
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
3033
+ /* @__PURE__ */ jsx(OnlineDot, { online: opt.online })
3191
3034
  ]
3192
3035
  }
3193
- ) })
3194
- ]
3036
+ ) }, opt.id);
3037
+ })
3195
3038
  }
3196
3039
  )
3197
3040
  ] });
@@ -3216,12 +3059,6 @@ function KanbanColumn({
3216
3059
  count,
3217
3060
  agentPicker,
3218
3061
  canEditHandlers,
3219
- draggableCards,
3220
- dragActive,
3221
- dropAllowed,
3222
- onCardDragStart,
3223
- onCardDragEnd,
3224
- onLaneDrop,
3225
3062
  className
3226
3063
  }) {
3227
3064
  const headerCount = count ?? cards.length;
@@ -3232,21 +3069,9 @@ function KanbanColumn({
3232
3069
  return /* @__PURE__ */ jsxs(
3233
3070
  "div",
3234
3071
  {
3235
- onDragOver: dropAllowed ? (e) => {
3236
- e.preventDefault();
3237
- e.dataTransfer.dropEffect = "move";
3238
- } : void 0,
3239
- onDrop: dropAllowed && onLaneDrop ? (e) => {
3240
- e.preventDefault();
3241
- onLaneDrop(lane);
3242
- } : void 0,
3243
3072
  className: cn9(
3244
- "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",
3245
3074
  isScheduled && "border-border",
3246
- // MV4 drag affordance: allowed targets glow; other lanes dim so the
3247
- // valid drop zones read at a glance.
3248
- dragActive && dropAllowed && "border-primary/60 ring-2 ring-primary/40 bg-primary/5",
3249
- dragActive && !dropAllowed && "opacity-55",
3250
3075
  className
3251
3076
  ),
3252
3077
  children: [
@@ -3315,10 +3140,7 @@ function KanbanColumn({
3315
3140
  card,
3316
3141
  onClick: onCardClick,
3317
3142
  selected: card.id === selectedCardId,
3318
- dueState: dueStateFor(card, lane, now),
3319
- draggable: draggableCards,
3320
- onDragStart: onCardDragStart,
3321
- onDragEnd: onCardDragEnd
3143
+ dueState: dueStateFor(card, lane, now)
3322
3144
  },
3323
3145
  card.id
3324
3146
  )),
@@ -3478,8 +3300,6 @@ function KanbanBoard({
3478
3300
  laneAgentPicker,
3479
3301
  scheduleStatus,
3480
3302
  focusCardId,
3481
- renderCardDrawer,
3482
- enableDrag,
3483
3303
  className
3484
3304
  }) {
3485
3305
  const {
@@ -3494,7 +3314,6 @@ function KanbanBoard({
3494
3314
  createCard,
3495
3315
  updateCard,
3496
3316
  transitionCard,
3497
- deleteCard,
3498
3317
  handleRunTerminal
3499
3318
  } = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
3500
3319
  const lastFocusedRef = useRef(void 0);
@@ -3539,44 +3358,6 @@ function KanbanBoard({
3539
3358
  (cardId, toLane) => transitionCard({ cardId, targetLane: toLane }),
3540
3359
  [transitionCard]
3541
3360
  );
3542
- const [dragging, setDragging] = useState(null);
3543
- const draggingRef = useRef(null);
3544
- const dropInFlightRef = useRef(null);
3545
- const allowedDropLanes = useMemo(() => {
3546
- if (!dragging || !board?.transitions) return /* @__PURE__ */ new Set();
3547
- return new Set(
3548
- board.transitions.filter((t) => t.fromLane === dragging.lane && t.manualAllowed).map((t) => t.toLane)
3549
- );
3550
- }, [dragging, board?.transitions]);
3551
- const handleCardDragStart = useCallback((card) => {
3552
- const d = { id: card.id, lane: card.lane };
3553
- draggingRef.current = d;
3554
- setDragging(d);
3555
- }, []);
3556
- const handleCardDragEnd = useCallback(() => {
3557
- draggingRef.current = null;
3558
- setDragging(null);
3559
- }, []);
3560
- const handleLaneDrop = useCallback(
3561
- (lane) => {
3562
- const cur = draggingRef.current;
3563
- draggingRef.current = null;
3564
- setDragging(null);
3565
- if (!cur || lane.key === cur.lane) return;
3566
- if (dropInFlightRef.current === cur.id) return;
3567
- const allowed = (board?.transitions ?? []).some(
3568
- (t) => t.fromLane === cur.lane && t.toLane === lane.key && t.manualAllowed
3569
- );
3570
- if (!allowed) return;
3571
- dropInFlightRef.current = cur.id;
3572
- void Promise.resolve(transitionCard({ cardId: cur.id, targetLane: lane.key })).finally(
3573
- () => {
3574
- if (dropInFlightRef.current === cur.id) dropInFlightRef.current = null;
3575
- }
3576
- );
3577
- },
3578
- [board?.transitions, transitionCard]
3579
- );
3580
3361
  const initialLaneKey = lanes.find((l) => !l.terminal)?.key ?? lanes[0]?.key;
3581
3362
  const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
3582
3363
  const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
@@ -3597,32 +3378,12 @@ function KanbanBoard({
3597
3378
  showCreate: enableCreate && lane.key === initialLaneKey,
3598
3379
  count: laneCounts?.[lane.key],
3599
3380
  agentPicker: laneAgentPicker?.(lane),
3600
- canEditHandlers,
3601
- draggableCards: enableDrag && enableAdvance,
3602
- dragActive: !!dragging,
3603
- dropAllowed: !!dragging && dragging.lane !== lane.key && allowedDropLanes.has(lane.key),
3604
- onCardDragStart: handleCardDragStart,
3605
- onCardDragEnd: handleCardDragEnd,
3606
- onLaneDrop: handleLaneDrop
3381
+ canEditHandlers
3607
3382
  },
3608
3383
  lane.id ?? lane.key
3609
3384
  ))
3610
3385
  ] }),
3611
- selectedCard && (renderCardDrawer ? renderCardDrawer({
3612
- card: selectedCard,
3613
- adapter,
3614
- lanes,
3615
- transitions: enableAdvance ? board?.transitions : void 0,
3616
- canAdvance: canAdvanceSelected,
3617
- onClose: closeCard,
3618
- onRetry: onRetryCard ? handleRetry : void 0,
3619
- onUpdate: enableEdit ? handleUpdate : void 0,
3620
- onAdvance: enableAdvance ? handleAdvance : void 0,
3621
- onTransition: enableAdvance ? handleTransition : void 0,
3622
- onDelete: adapter.deleteCard ? deleteCard : void 0,
3623
- onRunTerminal: handleRunTerminal,
3624
- onError
3625
- }) : /* @__PURE__ */ jsx(
3386
+ selectedCard && /* @__PURE__ */ jsx(
3626
3387
  CardDrawer,
3627
3388
  {
3628
3389
  card: selectedCard,
@@ -3638,7 +3399,7 @@ function KanbanBoard({
3638
3399
  onRunTerminal: handleRunTerminal,
3639
3400
  onError
3640
3401
  }
3641
- ))
3402
+ )
3642
3403
  ] })
3643
3404
  ] });
3644
3405
  }
@@ -3663,7 +3424,6 @@ function composeAdapter(source, boardConfigUuid, version, cardSource) {
3663
3424
  transitionCard(input) {
3664
3425
  return cardSource.transitionCard(input);
3665
3426
  },
3666
- ...cardSource.deleteCard ? { deleteCard: (id) => cardSource.deleteCard(id) } : {},
3667
3427
  ...cardSource.createRunStream ? { createRunStream: (id) => cardSource.createRunStream(id) } : {}
3668
3428
  };
3669
3429
  }