@cadraos/sdk 0.3.7 → 0.3.9
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.
- package/dist/board-host/index.d.cts +74 -6
- package/dist/board-host/index.d.ts +74 -6
- package/dist/board-host/server/index.d.cts +81 -6
- package/dist/board-host/server/index.d.ts +81 -6
- package/dist/chat/index.cjs +4 -43
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +7 -0
- package/dist/chat/index.d.ts +7 -0
- package/dist/chat/index.js +4 -43
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +4 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -43
- package/dist/index.js.map +1 -1
- package/dist/kanban/engine/index.cjs +119 -31
- package/dist/kanban/engine/index.cjs.map +1 -1
- package/dist/kanban/engine/index.d.cts +112 -6
- package/dist/kanban/engine/index.d.ts +112 -6
- package/dist/kanban/engine/index.js +119 -31
- package/dist/kanban/engine/index.js.map +1 -1
- package/dist/kanban/index.cjs +574 -155
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +277 -11
- package/dist/kanban/index.d.ts +277 -11
- package/dist/kanban/index.js +569 -156
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +4 -43
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.d.cts +7 -0
- package/dist/teams/index.d.ts +7 -0
- package/dist/teams/index.js +4 -43
- package/dist/teams/index.js.map +1 -1
- package/package.json +16 -15
package/dist/kanban/index.js
CHANGED
|
@@ -16,6 +16,10 @@ function mapHandler(h) {
|
|
|
16
16
|
type: h.type,
|
|
17
17
|
agentUuid: h.agent_uuid,
|
|
18
18
|
teamUuid: h.team_uuid,
|
|
19
|
+
// FINDING-6: carry the remote_agent binding through the wire parse. The
|
|
20
|
+
// engine's remote_agent dispatch reads `remoteAgentUuid`; dropping it here
|
|
21
|
+
// made every published remote_agent lane dispatch-dead.
|
|
22
|
+
remoteAgentUuid: h.remote_agent_uuid,
|
|
19
23
|
agentRef: h.agent_ref,
|
|
20
24
|
webhook: h.webhook ? {
|
|
21
25
|
url: h.webhook.url,
|
|
@@ -2293,35 +2297,40 @@ function useCardRun(options) {
|
|
|
2293
2297
|
function cn9(...classes) {
|
|
2294
2298
|
return classes.filter(Boolean).join(" ");
|
|
2295
2299
|
}
|
|
2296
|
-
function
|
|
2297
|
-
switch (
|
|
2298
|
-
case "
|
|
2299
|
-
return
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
case "
|
|
2309
|
-
return
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
case "cancelled":
|
|
2314
|
-
return {
|
|
2315
|
-
label: "Cancelled",
|
|
2316
|
-
className: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400"
|
|
2317
|
-
};
|
|
2300
|
+
function badgeVariantClass(variant) {
|
|
2301
|
+
switch (variant) {
|
|
2302
|
+
case "default":
|
|
2303
|
+
return "bg-primary text-primary-foreground";
|
|
2304
|
+
case "secondary":
|
|
2305
|
+
return "border border-border bg-secondary text-secondary-foreground";
|
|
2306
|
+
case "outline":
|
|
2307
|
+
return "border border-border text-foreground";
|
|
2308
|
+
case "info":
|
|
2309
|
+
return "border border-info/30 bg-info/15 text-info";
|
|
2310
|
+
case "success":
|
|
2311
|
+
return "border border-success/30 bg-success/15 text-success";
|
|
2312
|
+
case "warning":
|
|
2313
|
+
return "border border-warning/40 bg-warning/15 text-warning";
|
|
2314
|
+
case "destructive":
|
|
2315
|
+
return "border border-destructive/40 bg-destructive/15 text-destructive";
|
|
2316
|
+
case "neutral":
|
|
2318
2317
|
default:
|
|
2319
|
-
return
|
|
2320
|
-
label: "Pending",
|
|
2321
|
-
className: "bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300"
|
|
2322
|
-
};
|
|
2318
|
+
return "border border-border bg-secondary text-muted-foreground";
|
|
2323
2319
|
}
|
|
2324
2320
|
}
|
|
2321
|
+
function runStatusTone(status) {
|
|
2322
|
+
const map = {
|
|
2323
|
+
running: { label: "Running", variant: "info" },
|
|
2324
|
+
completed: { label: "Completed", variant: "success" },
|
|
2325
|
+
failed: { label: "Failed", variant: "destructive" },
|
|
2326
|
+
cancelled: { label: "Cancelled", variant: "neutral" }
|
|
2327
|
+
};
|
|
2328
|
+
const { label, variant } = map[status ?? ""] ?? {
|
|
2329
|
+
label: "Pending",
|
|
2330
|
+
variant: "neutral"
|
|
2331
|
+
};
|
|
2332
|
+
return { label, variant, className: badgeVariantClass(variant) };
|
|
2333
|
+
}
|
|
2325
2334
|
function CardDrawer({
|
|
2326
2335
|
card,
|
|
2327
2336
|
adapter,
|
|
@@ -2440,11 +2449,11 @@ function CardDrawer({
|
|
|
2440
2449
|
role: "dialog",
|
|
2441
2450
|
"aria-label": `Card: ${card.title}`,
|
|
2442
2451
|
className: cn9(
|
|
2443
|
-
"flex h-full w-full sm:max-w-sm flex-col bg-
|
|
2452
|
+
"flex h-full w-full sm:max-w-sm flex-col bg-card border-l border-border shadow-xl",
|
|
2444
2453
|
className
|
|
2445
2454
|
),
|
|
2446
2455
|
children: [
|
|
2447
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 border-b border-
|
|
2456
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 border-b border-border px-4 py-3", children: [
|
|
2448
2457
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
2449
2458
|
isEditing ? /* @__PURE__ */ jsx(
|
|
2450
2459
|
"input",
|
|
@@ -2454,14 +2463,14 @@ function CardDrawer({
|
|
|
2454
2463
|
onChange: (e) => setEditTitle(e.target.value),
|
|
2455
2464
|
"aria-label": "Card title",
|
|
2456
2465
|
placeholder: "Card title",
|
|
2457
|
-
className: "w-full rounded-md border border-
|
|
2466
|
+
className: "w-full rounded-md border border-input bg-background px-2 py-1 text-base font-semibold text-foreground focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
2458
2467
|
}
|
|
2459
2468
|
) : /* @__PURE__ */ jsx(
|
|
2460
2469
|
"h2",
|
|
2461
2470
|
{
|
|
2462
2471
|
className: cn9(
|
|
2463
|
-
"text-base font-semibold text-
|
|
2464
|
-
onUpdate && "cursor-text rounded hover:bg-
|
|
2472
|
+
"text-base font-semibold text-foreground truncate",
|
|
2473
|
+
onUpdate && "cursor-text rounded hover:bg-muted/60 -mx-1 px-1"
|
|
2465
2474
|
),
|
|
2466
2475
|
onClick: onUpdate ? () => setIsEditing(true) : void 0,
|
|
2467
2476
|
title: onUpdate ? "Click to edit" : void 0,
|
|
@@ -2469,7 +2478,7 @@ function CardDrawer({
|
|
|
2469
2478
|
}
|
|
2470
2479
|
),
|
|
2471
2480
|
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
2472
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-
|
|
2481
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: card.lane }),
|
|
2473
2482
|
/* @__PURE__ */ jsx(
|
|
2474
2483
|
"span",
|
|
2475
2484
|
{
|
|
@@ -2489,7 +2498,7 @@ function CardDrawer({
|
|
|
2489
2498
|
type: "button",
|
|
2490
2499
|
onClick: () => setIsEditing(true),
|
|
2491
2500
|
"aria-label": "Edit card",
|
|
2492
|
-
className: "rounded p-1 text-
|
|
2501
|
+
className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2493
2502
|
children: /* @__PURE__ */ jsxs(
|
|
2494
2503
|
"svg",
|
|
2495
2504
|
{
|
|
@@ -2515,7 +2524,7 @@ function CardDrawer({
|
|
|
2515
2524
|
type: "button",
|
|
2516
2525
|
onClick: onClose,
|
|
2517
2526
|
"aria-label": "Close",
|
|
2518
|
-
className: "rounded p-1 text-
|
|
2527
|
+
className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2519
2528
|
children: /* @__PURE__ */ jsxs(
|
|
2520
2529
|
"svg",
|
|
2521
2530
|
{
|
|
@@ -2537,8 +2546,8 @@ function CardDrawer({
|
|
|
2537
2546
|
)
|
|
2538
2547
|
] })
|
|
2539
2548
|
] }),
|
|
2540
|
-
isEditing ? /* @__PURE__ */ jsxs("div", { className: "border-b border-
|
|
2541
|
-
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-
|
|
2549
|
+
isEditing ? /* @__PURE__ */ jsxs("div", { className: "border-b border-border px-4 py-3", children: [
|
|
2550
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Description" }),
|
|
2542
2551
|
/* @__PURE__ */ jsx(
|
|
2543
2552
|
"textarea",
|
|
2544
2553
|
{
|
|
@@ -2547,7 +2556,7 @@ function CardDrawer({
|
|
|
2547
2556
|
"aria-label": "Card description",
|
|
2548
2557
|
rows: 4,
|
|
2549
2558
|
placeholder: "Add a description\u2026",
|
|
2550
|
-
className: "w-full resize-y rounded-md border border-
|
|
2559
|
+
className: "w-full resize-y rounded-md border border-input bg-background px-2 py-1.5 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
2551
2560
|
}
|
|
2552
2561
|
),
|
|
2553
2562
|
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center justify-end gap-2", children: [
|
|
@@ -2557,7 +2566,7 @@ function CardDrawer({
|
|
|
2557
2566
|
type: "button",
|
|
2558
2567
|
onClick: handleCancel,
|
|
2559
2568
|
disabled: isSaving,
|
|
2560
|
-
className: "rounded-md px-3 py-1.5 text-sm font-medium text-
|
|
2569
|
+
className: "rounded-md px-3 py-1.5 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-50",
|
|
2561
2570
|
children: "Cancel"
|
|
2562
2571
|
}
|
|
2563
2572
|
),
|
|
@@ -2567,26 +2576,27 @@ function CardDrawer({
|
|
|
2567
2576
|
type: "button",
|
|
2568
2577
|
onClick: () => void handleSave(),
|
|
2569
2578
|
disabled: isSaving,
|
|
2570
|
-
className: "rounded-md bg-
|
|
2579
|
+
className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-ring/50 disabled:opacity-50",
|
|
2571
2580
|
children: isSaving ? "Saving\u2026" : "Save"
|
|
2572
2581
|
}
|
|
2573
2582
|
)
|
|
2574
2583
|
] })
|
|
2575
|
-
] }) : (card.description || onUpdate) && /* @__PURE__ */ jsx("div", { className: "border-b border-
|
|
2584
|
+
] }) : (card.description || onUpdate) && /* @__PURE__ */ jsx("div", { className: "border-b border-border px-4 py-3", children: /* @__PURE__ */ jsx(
|
|
2576
2585
|
"p",
|
|
2577
2586
|
{
|
|
2578
2587
|
className: cn9(
|
|
2579
2588
|
"text-sm whitespace-pre-wrap",
|
|
2580
|
-
card.description ? "text-
|
|
2581
|
-
onUpdate && "cursor-text rounded hover:bg-
|
|
2589
|
+
card.description ? "text-muted-foreground" : "italic text-muted-foreground/70",
|
|
2590
|
+
onUpdate && "cursor-text rounded hover:bg-muted/60 -mx-1 px-1"
|
|
2582
2591
|
),
|
|
2583
2592
|
onClick: onUpdate ? () => setIsEditing(true) : void 0,
|
|
2584
2593
|
title: onUpdate ? "Click to edit" : void 0,
|
|
2585
2594
|
children: card.description || "Add a description\u2026"
|
|
2586
2595
|
}
|
|
2587
2596
|
) }),
|
|
2588
|
-
showTransitionButtons ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 border-b border-
|
|
2589
|
-
isHumanGate &&
|
|
2597
|
+
showTransitionButtons ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 border-b border-border px-4 py-2", children: [
|
|
2598
|
+
isHumanGate && // Human gate = needs-you → warning (amber is reserved for this, F3).
|
|
2599
|
+
/* @__PURE__ */ jsx("span", { className: "mr-auto text-xs font-medium text-warning", children: "Awaiting your approval" }),
|
|
2590
2600
|
manualEdges.map((t, i) => {
|
|
2591
2601
|
const toLabel = laneByKey.get(t.toLane)?.label ?? t.toLane;
|
|
2592
2602
|
const isPrimary = isHumanGate ? i === 0 : false;
|
|
@@ -2599,26 +2609,27 @@ function CardDrawer({
|
|
|
2599
2609
|
onClick: () => void handleTransition(t.toLane),
|
|
2600
2610
|
disabled: pendingLane !== null,
|
|
2601
2611
|
className: cn9(
|
|
2602
|
-
|
|
2603
|
-
|
|
2612
|
+
// ≥44px touch (M12/F5) — density kept via padding, not height.
|
|
2613
|
+
"inline-flex min-h-11 items-center justify-center rounded-md px-3 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-ring/50 disabled:opacity-50",
|
|
2614
|
+
isPrimary ? "border border-border bg-secondary text-secondary-foreground hover:bg-muted" : "border border-border text-foreground hover:bg-muted"
|
|
2604
2615
|
),
|
|
2605
2616
|
children: busy ? "Moving\u2026" : label
|
|
2606
2617
|
},
|
|
2607
2618
|
t.id
|
|
2608
2619
|
);
|
|
2609
2620
|
})
|
|
2610
|
-
] }) : onAdvance && canAdvance && !isEditing && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end border-b border-
|
|
2621
|
+
] }) : onAdvance && canAdvance && !isEditing && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end border-b border-border px-4 py-2", children: /* @__PURE__ */ jsx(
|
|
2611
2622
|
"button",
|
|
2612
2623
|
{
|
|
2613
2624
|
type: "button",
|
|
2614
2625
|
onClick: () => void handleAdvance(),
|
|
2615
2626
|
disabled: isAdvancing,
|
|
2616
|
-
className: "rounded-md border border-
|
|
2627
|
+
className: "inline-flex min-h-11 items-center justify-center rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50 disabled:opacity-50",
|
|
2617
2628
|
children: isAdvancing ? "Advancing\u2026" : "Advance \u2192"
|
|
2618
2629
|
}
|
|
2619
2630
|
) }),
|
|
2620
2631
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
2621
|
-
!hasExecution ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-
|
|
2632
|
+
!hasExecution ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No run yet for this card." }) }) : /* @__PURE__ */ jsx(
|
|
2622
2633
|
MessageList,
|
|
2623
2634
|
{
|
|
2624
2635
|
messages: run.messages,
|
|
@@ -2631,14 +2642,14 @@ function CardDrawer({
|
|
|
2631
2642
|
className: "flex-1"
|
|
2632
2643
|
}
|
|
2633
2644
|
),
|
|
2634
|
-
failed && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-
|
|
2635
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-
|
|
2645
|
+
failed && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-destructive/40 bg-destructive/10 px-4 py-3", children: [
|
|
2646
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: run.error ?? "Run failed." }),
|
|
2636
2647
|
onRetry && /* @__PURE__ */ jsx(
|
|
2637
2648
|
"button",
|
|
2638
2649
|
{
|
|
2639
2650
|
type: "button",
|
|
2640
2651
|
onClick: () => onRetry(card),
|
|
2641
|
-
className: "shrink-0 rounded-md bg-
|
|
2652
|
+
className: "inline-flex min-h-11 shrink-0 items-center justify-center rounded-md border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
|
|
2642
2653
|
children: "Retry"
|
|
2643
2654
|
}
|
|
2644
2655
|
)
|
|
@@ -2680,10 +2691,51 @@ function Spinner({ className }) {
|
|
|
2680
2691
|
}
|
|
2681
2692
|
);
|
|
2682
2693
|
}
|
|
2683
|
-
function
|
|
2694
|
+
function ClockIcon2() {
|
|
2695
|
+
return /* @__PURE__ */ jsxs(
|
|
2696
|
+
"svg",
|
|
2697
|
+
{
|
|
2698
|
+
viewBox: "0 0 24 24",
|
|
2699
|
+
fill: "none",
|
|
2700
|
+
stroke: "currentColor",
|
|
2701
|
+
strokeWidth: "2",
|
|
2702
|
+
strokeLinecap: "round",
|
|
2703
|
+
strokeLinejoin: "round",
|
|
2704
|
+
"aria-hidden": true,
|
|
2705
|
+
className: "h-2.5 w-2.5",
|
|
2706
|
+
children: [
|
|
2707
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2708
|
+
/* @__PURE__ */ jsx("path", { d: "M12 7v5l3 2" })
|
|
2709
|
+
]
|
|
2710
|
+
}
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
function KanbanCard({
|
|
2714
|
+
card,
|
|
2715
|
+
onClick,
|
|
2716
|
+
selected,
|
|
2717
|
+
dueState,
|
|
2718
|
+
className
|
|
2719
|
+
}) {
|
|
2684
2720
|
const runStatus = card.run?.status;
|
|
2685
|
-
const
|
|
2686
|
-
const
|
|
2721
|
+
const isWorking = runStatus === "running";
|
|
2722
|
+
const failed = runStatus === "failed";
|
|
2723
|
+
let chip = null;
|
|
2724
|
+
if (failed) {
|
|
2725
|
+
chip = { label: "Failed", variant: "destructive" };
|
|
2726
|
+
} else if (dueState === "ready") {
|
|
2727
|
+
chip = { label: "Ready", variant: "success" };
|
|
2728
|
+
} else if (runStatus === "completed") {
|
|
2729
|
+
const t = runStatusTone(runStatus);
|
|
2730
|
+
chip = { label: t.label, variant: t.variant };
|
|
2731
|
+
} else if (dueState === "due") {
|
|
2732
|
+
chip = { label: "Due", variant: "neutral", icon: "clock" };
|
|
2733
|
+
} else if (dueState === "waiting") {
|
|
2734
|
+
chip = { label: "Waiting", variant: "neutral" };
|
|
2735
|
+
} else if (runStatus) {
|
|
2736
|
+
const t = runStatusTone(runStatus);
|
|
2737
|
+
chip = { label: t.label, variant: t.variant };
|
|
2738
|
+
}
|
|
2687
2739
|
return /* @__PURE__ */ jsxs(
|
|
2688
2740
|
"button",
|
|
2689
2741
|
{
|
|
@@ -2692,46 +2744,311 @@ function KanbanCard({ card, onClick, selected, className }) {
|
|
|
2692
2744
|
"aria-pressed": selected,
|
|
2693
2745
|
"aria-busy": isWorking,
|
|
2694
2746
|
className: cn9(
|
|
2695
|
-
"relative w-full text-left rounded-lg border bg-
|
|
2696
|
-
"hover:shadow-md hover:border-
|
|
2697
|
-
"focus:outline-none focus:ring-2 focus:ring-
|
|
2698
|
-
|
|
2747
|
+
"relative w-full text-left rounded-lg border bg-card p-3 shadow-sm transition",
|
|
2748
|
+
"hover:shadow-md hover:border-primary/40",
|
|
2749
|
+
"focus:outline-none focus:ring-2 focus:ring-ring/50",
|
|
2750
|
+
// The working card carries the SINGLE focal motion on the board (F11).
|
|
2751
|
+
isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
|
|
2699
2752
|
className
|
|
2700
2753
|
),
|
|
2701
2754
|
children: [
|
|
2702
|
-
isWorking && /* @__PURE__ */ jsxs(
|
|
2703
|
-
"span",
|
|
2704
|
-
{
|
|
2705
|
-
"aria-hidden": true,
|
|
2706
|
-
className: "pointer-events-none absolute -top-1 -right-1 flex h-3 w-3",
|
|
2707
|
-
children: [
|
|
2708
|
-
/* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-amber-400 opacity-75" }),
|
|
2709
|
-
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-3 w-3 rounded-full bg-amber-500" })
|
|
2710
|
-
]
|
|
2711
|
-
}
|
|
2712
|
-
),
|
|
2713
2755
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2714
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-
|
|
2715
|
-
isWorking ? /* @__PURE__ */ jsxs(
|
|
2716
|
-
/* @__PURE__ */ jsx(Spinner, {}),
|
|
2717
|
-
"Working"
|
|
2718
|
-
] }) : tone && /* @__PURE__ */ jsx(
|
|
2756
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground line-clamp-2", children: card.title }),
|
|
2757
|
+
isWorking ? /* @__PURE__ */ jsxs(
|
|
2719
2758
|
"span",
|
|
2720
2759
|
{
|
|
2721
2760
|
className: cn9(
|
|
2722
|
-
"shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2723
|
-
|
|
2761
|
+
"shrink-0 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2762
|
+
badgeVariantClass("info")
|
|
2724
2763
|
),
|
|
2725
|
-
children:
|
|
2764
|
+
children: [
|
|
2765
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
2766
|
+
"Working"
|
|
2767
|
+
]
|
|
2768
|
+
}
|
|
2769
|
+
) : chip && /* @__PURE__ */ jsxs(
|
|
2770
|
+
"span",
|
|
2771
|
+
{
|
|
2772
|
+
className: cn9(
|
|
2773
|
+
"shrink-0 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2774
|
+
badgeVariantClass(chip.variant)
|
|
2775
|
+
),
|
|
2776
|
+
children: [
|
|
2777
|
+
chip.icon === "clock" && /* @__PURE__ */ jsx(ClockIcon2, {}),
|
|
2778
|
+
chip.label
|
|
2779
|
+
]
|
|
2726
2780
|
}
|
|
2727
2781
|
)
|
|
2728
2782
|
] }),
|
|
2729
|
-
card.description && /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs text-
|
|
2730
|
-
card.type && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx("span", { className: "inline-block rounded bg-
|
|
2783
|
+
card.description && /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: card.description }),
|
|
2784
|
+
card.type && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx("span", { className: "inline-block rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: card.type }) })
|
|
2731
2785
|
]
|
|
2732
2786
|
}
|
|
2733
2787
|
);
|
|
2734
2788
|
}
|
|
2789
|
+
function CapMeter({ count, cap, className }) {
|
|
2790
|
+
const pct = cap > 0 ? Math.min(100, Math.round(count / cap * 100)) : 0;
|
|
2791
|
+
return /* @__PURE__ */ jsxs(
|
|
2792
|
+
"div",
|
|
2793
|
+
{
|
|
2794
|
+
className: cn9(
|
|
2795
|
+
"mt-2 flex items-center gap-2 text-[11px] text-muted-foreground",
|
|
2796
|
+
className
|
|
2797
|
+
),
|
|
2798
|
+
children: [
|
|
2799
|
+
/* @__PURE__ */ jsxs("span", { className: "tabular-nums font-medium", children: [
|
|
2800
|
+
count,
|
|
2801
|
+
"/",
|
|
2802
|
+
cap
|
|
2803
|
+
] }),
|
|
2804
|
+
/* @__PURE__ */ jsx(
|
|
2805
|
+
"span",
|
|
2806
|
+
{
|
|
2807
|
+
role: "progressbar",
|
|
2808
|
+
"aria-valuemin": 0,
|
|
2809
|
+
"aria-valuemax": cap,
|
|
2810
|
+
"aria-valuenow": count,
|
|
2811
|
+
"aria-label": `${count} of ${cap} used`,
|
|
2812
|
+
className: "h-1 flex-1 overflow-hidden rounded-full bg-secondary",
|
|
2813
|
+
children: /* @__PURE__ */ jsx(
|
|
2814
|
+
"span",
|
|
2815
|
+
{
|
|
2816
|
+
className: "block h-full rounded-full bg-primary",
|
|
2817
|
+
style: { width: `${pct}%` }
|
|
2818
|
+
}
|
|
2819
|
+
)
|
|
2820
|
+
}
|
|
2821
|
+
)
|
|
2822
|
+
]
|
|
2823
|
+
}
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
function AgentKindIcon({ kind }) {
|
|
2827
|
+
const common = {
|
|
2828
|
+
viewBox: "0 0 24 24",
|
|
2829
|
+
fill: "none",
|
|
2830
|
+
stroke: "currentColor",
|
|
2831
|
+
strokeWidth: 2,
|
|
2832
|
+
strokeLinecap: "round",
|
|
2833
|
+
strokeLinejoin: "round",
|
|
2834
|
+
className: "h-3.5 w-3.5",
|
|
2835
|
+
"aria-hidden": true
|
|
2836
|
+
};
|
|
2837
|
+
if (kind === "remote") {
|
|
2838
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2839
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
|
|
2840
|
+
/* @__PURE__ */ jsx("path", { d: "M8 21h8M12 17v4" })
|
|
2841
|
+
] });
|
|
2842
|
+
}
|
|
2843
|
+
if (kind === "human") {
|
|
2844
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2845
|
+
/* @__PURE__ */ jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
2846
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "7", r: "4" })
|
|
2847
|
+
] });
|
|
2848
|
+
}
|
|
2849
|
+
return /* @__PURE__ */ jsxs("svg", { ...common, children: [
|
|
2850
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "11", width: "18", height: "10", rx: "2" }),
|
|
2851
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "2" }),
|
|
2852
|
+
/* @__PURE__ */ jsx("path", { d: "M12 7v4M8 16h.01M16 16h.01" })
|
|
2853
|
+
] });
|
|
2854
|
+
}
|
|
2855
|
+
function OnlineDot({ online }) {
|
|
2856
|
+
if (online === void 0) return null;
|
|
2857
|
+
return /* @__PURE__ */ jsx(
|
|
2858
|
+
"span",
|
|
2859
|
+
{
|
|
2860
|
+
"aria-label": online ? "connected" : "offline",
|
|
2861
|
+
className: cn9(
|
|
2862
|
+
"h-1.5 w-1.5 shrink-0 rounded-full",
|
|
2863
|
+
online ? "bg-success" : "bg-muted-foreground"
|
|
2864
|
+
)
|
|
2865
|
+
}
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
function LaneAgentPicker({
|
|
2869
|
+
selected,
|
|
2870
|
+
options,
|
|
2871
|
+
onSelect,
|
|
2872
|
+
canEdit = true,
|
|
2873
|
+
lockedReason,
|
|
2874
|
+
className
|
|
2875
|
+
}) {
|
|
2876
|
+
const [open, setOpen] = useState(false);
|
|
2877
|
+
const rootRef = useRef(null);
|
|
2878
|
+
const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
|
|
2879
|
+
useEffect(() => {
|
|
2880
|
+
if (!open) return;
|
|
2881
|
+
const onDocDown = (e) => {
|
|
2882
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
2883
|
+
setOpen(false);
|
|
2884
|
+
}
|
|
2885
|
+
};
|
|
2886
|
+
const onKey = (e) => {
|
|
2887
|
+
if (e.key === "Escape") setOpen(false);
|
|
2888
|
+
};
|
|
2889
|
+
document.addEventListener("mousedown", onDocDown);
|
|
2890
|
+
document.addEventListener("touchstart", onDocDown);
|
|
2891
|
+
document.addEventListener("keydown", onKey);
|
|
2892
|
+
return () => {
|
|
2893
|
+
document.removeEventListener("mousedown", onDocDown);
|
|
2894
|
+
document.removeEventListener("touchstart", onDocDown);
|
|
2895
|
+
document.removeEventListener("keydown", onKey);
|
|
2896
|
+
};
|
|
2897
|
+
}, [open]);
|
|
2898
|
+
const kind = selected?.kind ?? "cadra";
|
|
2899
|
+
const displayLabel = selected?.label ?? "Unassigned";
|
|
2900
|
+
const face = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2901
|
+
/* @__PURE__ */ jsx(
|
|
2902
|
+
"span",
|
|
2903
|
+
{
|
|
2904
|
+
className: cn9(
|
|
2905
|
+
"grid h-5 w-5 shrink-0 place-items-center rounded-full",
|
|
2906
|
+
kind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
|
|
2907
|
+
),
|
|
2908
|
+
children: /* @__PURE__ */ jsx(AgentKindIcon, { kind })
|
|
2909
|
+
}
|
|
2910
|
+
),
|
|
2911
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
|
|
2912
|
+
/* @__PURE__ */ jsx(OnlineDot, { online: selected?.online })
|
|
2913
|
+
] });
|
|
2914
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
|
|
2915
|
+
editable ? /* @__PURE__ */ jsxs(
|
|
2916
|
+
"button",
|
|
2917
|
+
{
|
|
2918
|
+
type: "button",
|
|
2919
|
+
onClick: () => setOpen((o) => !o),
|
|
2920
|
+
"aria-haspopup": "listbox",
|
|
2921
|
+
"aria-expanded": open,
|
|
2922
|
+
"aria-label": `Assigned agent: ${displayLabel}. Change`,
|
|
2923
|
+
className: cn9(
|
|
2924
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-lg border border-border bg-card px-2",
|
|
2925
|
+
"text-xs font-semibold text-foreground",
|
|
2926
|
+
"hover:border-primary/50 focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
2927
|
+
),
|
|
2928
|
+
children: [
|
|
2929
|
+
face,
|
|
2930
|
+
/* @__PURE__ */ jsx(
|
|
2931
|
+
"svg",
|
|
2932
|
+
{
|
|
2933
|
+
viewBox: "0 0 24 24",
|
|
2934
|
+
fill: "none",
|
|
2935
|
+
stroke: "currentColor",
|
|
2936
|
+
strokeWidth: 2,
|
|
2937
|
+
strokeLinecap: "round",
|
|
2938
|
+
strokeLinejoin: "round",
|
|
2939
|
+
"aria-hidden": true,
|
|
2940
|
+
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
|
|
2941
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" })
|
|
2942
|
+
}
|
|
2943
|
+
)
|
|
2944
|
+
]
|
|
2945
|
+
}
|
|
2946
|
+
) : /* @__PURE__ */ jsxs(
|
|
2947
|
+
"div",
|
|
2948
|
+
{
|
|
2949
|
+
role: "group",
|
|
2950
|
+
"aria-label": `Assigned agent: ${displayLabel}`,
|
|
2951
|
+
className: cn9(
|
|
2952
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-lg border border-border bg-muted/60 px-2",
|
|
2953
|
+
"text-xs font-semibold text-muted-foreground"
|
|
2954
|
+
),
|
|
2955
|
+
children: [
|
|
2956
|
+
face,
|
|
2957
|
+
/* @__PURE__ */ jsxs(
|
|
2958
|
+
"svg",
|
|
2959
|
+
{
|
|
2960
|
+
viewBox: "0 0 24 24",
|
|
2961
|
+
fill: "none",
|
|
2962
|
+
stroke: "currentColor",
|
|
2963
|
+
strokeWidth: 2,
|
|
2964
|
+
strokeLinecap: "round",
|
|
2965
|
+
strokeLinejoin: "round",
|
|
2966
|
+
"aria-hidden": true,
|
|
2967
|
+
className: "h-3.5 w-3.5 shrink-0",
|
|
2968
|
+
children: [
|
|
2969
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "11", width: "14", height: "10", rx: "2" }),
|
|
2970
|
+
/* @__PURE__ */ jsx("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })
|
|
2971
|
+
]
|
|
2972
|
+
}
|
|
2973
|
+
)
|
|
2974
|
+
]
|
|
2975
|
+
}
|
|
2976
|
+
),
|
|
2977
|
+
!editable && lockedReason && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2978
|
+
/* @__PURE__ */ jsxs(
|
|
2979
|
+
"svg",
|
|
2980
|
+
{
|
|
2981
|
+
viewBox: "0 0 24 24",
|
|
2982
|
+
fill: "none",
|
|
2983
|
+
stroke: "currentColor",
|
|
2984
|
+
strokeWidth: 2,
|
|
2985
|
+
strokeLinecap: "round",
|
|
2986
|
+
strokeLinejoin: "round",
|
|
2987
|
+
"aria-hidden": true,
|
|
2988
|
+
className: "h-3 w-3 shrink-0",
|
|
2989
|
+
children: [
|
|
2990
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "11", width: "14", height: "10", rx: "2" }),
|
|
2991
|
+
/* @__PURE__ */ jsx("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })
|
|
2992
|
+
]
|
|
2993
|
+
}
|
|
2994
|
+
),
|
|
2995
|
+
/* @__PURE__ */ jsx("span", { children: lockedReason })
|
|
2996
|
+
] }),
|
|
2997
|
+
editable && open && /* @__PURE__ */ jsx(
|
|
2998
|
+
"ul",
|
|
2999
|
+
{
|
|
3000
|
+
role: "listbox",
|
|
3001
|
+
"aria-label": "Assign an agent",
|
|
3002
|
+
className: cn9(
|
|
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"
|
|
3005
|
+
),
|
|
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(
|
|
3009
|
+
"button",
|
|
3010
|
+
{
|
|
3011
|
+
type: "button",
|
|
3012
|
+
onClick: () => {
|
|
3013
|
+
onSelect(opt.id);
|
|
3014
|
+
setOpen(false);
|
|
3015
|
+
},
|
|
3016
|
+
className: cn9(
|
|
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"
|
|
3020
|
+
),
|
|
3021
|
+
children: [
|
|
3022
|
+
/* @__PURE__ */ jsx(
|
|
3023
|
+
"span",
|
|
3024
|
+
{
|
|
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" })
|
|
3030
|
+
}
|
|
3031
|
+
),
|
|
3032
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
|
|
3033
|
+
/* @__PURE__ */ jsx(OnlineDot, { online: opt.online })
|
|
3034
|
+
]
|
|
3035
|
+
}
|
|
3036
|
+
) }, opt.id);
|
|
3037
|
+
})
|
|
3038
|
+
}
|
|
3039
|
+
)
|
|
3040
|
+
] });
|
|
3041
|
+
}
|
|
3042
|
+
function dueStateFor(card, lane, now) {
|
|
3043
|
+
const rs = card.run?.status;
|
|
3044
|
+
if (rs === "completed" && !lane.terminal) return "ready";
|
|
3045
|
+
if (card.nextDueAt) {
|
|
3046
|
+
const t = Date.parse(card.nextDueAt);
|
|
3047
|
+
if (!Number.isNaN(t) && t <= now) return "due";
|
|
3048
|
+
}
|
|
3049
|
+
if (lane.trigger === "scheduled" && !rs) return "waiting";
|
|
3050
|
+
return void 0;
|
|
3051
|
+
}
|
|
2735
3052
|
function KanbanColumn({
|
|
2736
3053
|
lane,
|
|
2737
3054
|
cards,
|
|
@@ -2739,29 +3056,82 @@ function KanbanColumn({
|
|
|
2739
3056
|
selectedCardId,
|
|
2740
3057
|
onCreateCard,
|
|
2741
3058
|
showCreate,
|
|
3059
|
+
count,
|
|
3060
|
+
agentPicker,
|
|
3061
|
+
canEditHandlers,
|
|
2742
3062
|
className
|
|
2743
3063
|
}) {
|
|
3064
|
+
const headerCount = count ?? cards.length;
|
|
3065
|
+
const isScheduled = lane.trigger === "scheduled";
|
|
3066
|
+
const showCapMeter = count !== void 0 && typeof lane.cap === "number" && lane.cap > 0;
|
|
3067
|
+
const showAgentBadge = lane.handler?.type === "cadra_agent" && !agentPicker;
|
|
3068
|
+
const now = Date.now();
|
|
2744
3069
|
return /* @__PURE__ */ jsxs(
|
|
2745
3070
|
"div",
|
|
2746
3071
|
{
|
|
2747
3072
|
className: cn9(
|
|
2748
|
-
"flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-
|
|
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",
|
|
3074
|
+
isScheduled && "border-border",
|
|
2749
3075
|
className
|
|
2750
3076
|
),
|
|
2751
3077
|
children: [
|
|
2752
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
2753
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
3078
|
+
/* @__PURE__ */ jsxs("div", { className: "border-b border-border px-3 py-2.5", children: [
|
|
3079
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3080
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
3081
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground truncate", children: lane.label }),
|
|
3082
|
+
showAgentBadge && /* @__PURE__ */ jsx(
|
|
3083
|
+
"span",
|
|
3084
|
+
{
|
|
3085
|
+
title: lane.handler?.agentRef ? `Agent: ${lane.handler.agentRef}` : "Agent lane",
|
|
3086
|
+
className: cn9(
|
|
3087
|
+
// A static lane marker — NOT a run state. Uses neutral tokens,
|
|
3088
|
+
// never `info` (which means "running" in the F3 vocabulary).
|
|
3089
|
+
"rounded px-1.5 py-0.5 text-[10px] font-medium",
|
|
3090
|
+
badgeVariantClass("neutral")
|
|
3091
|
+
),
|
|
3092
|
+
children: "agent"
|
|
3093
|
+
}
|
|
3094
|
+
)
|
|
3095
|
+
] }),
|
|
3096
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-secondary px-2 py-0.5 text-[11px] font-medium text-muted-foreground tabular-nums", children: headerCount })
|
|
2763
3097
|
] }),
|
|
2764
|
-
/* @__PURE__ */ jsx("
|
|
3098
|
+
isScheduled && /* @__PURE__ */ jsx("div", { className: "mt-2 flex items-center gap-2 flex-wrap", children: /* @__PURE__ */ jsxs(
|
|
3099
|
+
"span",
|
|
3100
|
+
{
|
|
3101
|
+
className: cn9(
|
|
3102
|
+
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-semibold",
|
|
3103
|
+
badgeVariantClass("neutral")
|
|
3104
|
+
),
|
|
3105
|
+
children: [
|
|
3106
|
+
/* @__PURE__ */ jsxs(
|
|
3107
|
+
"svg",
|
|
3108
|
+
{
|
|
3109
|
+
viewBox: "0 0 24 24",
|
|
3110
|
+
fill: "none",
|
|
3111
|
+
stroke: "currentColor",
|
|
3112
|
+
strokeWidth: "2",
|
|
3113
|
+
strokeLinecap: "round",
|
|
3114
|
+
strokeLinejoin: "round",
|
|
3115
|
+
"aria-hidden": true,
|
|
3116
|
+
className: "h-3 w-3",
|
|
3117
|
+
children: [
|
|
3118
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
3119
|
+
/* @__PURE__ */ jsx("path", { d: "M12 7v5l3 2" })
|
|
3120
|
+
]
|
|
3121
|
+
}
|
|
3122
|
+
),
|
|
3123
|
+
"runs on schedule"
|
|
3124
|
+
]
|
|
3125
|
+
}
|
|
3126
|
+
) }),
|
|
3127
|
+
showCapMeter && /* @__PURE__ */ jsx(CapMeter, { count: headerCount, cap: lane.cap }),
|
|
3128
|
+
agentPicker && /* @__PURE__ */ jsx(
|
|
3129
|
+
LaneAgentPicker,
|
|
3130
|
+
{
|
|
3131
|
+
...agentPicker,
|
|
3132
|
+
canEdit: agentPicker.canEdit ?? canEditHandlers
|
|
3133
|
+
}
|
|
3134
|
+
)
|
|
2765
3135
|
] }),
|
|
2766
3136
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-2 overflow-y-auto p-2", children: [
|
|
2767
3137
|
cards.map((card) => /* @__PURE__ */ jsx(
|
|
@@ -2769,21 +3139,23 @@ function KanbanColumn({
|
|
|
2769
3139
|
{
|
|
2770
3140
|
card,
|
|
2771
3141
|
onClick: onCardClick,
|
|
2772
|
-
selected: card.id === selectedCardId
|
|
3142
|
+
selected: card.id === selectedCardId,
|
|
3143
|
+
dueState: dueStateFor(card, lane, now)
|
|
2773
3144
|
},
|
|
2774
3145
|
card.id
|
|
2775
3146
|
)),
|
|
2776
|
-
cards.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-1 py-4 text-center text-xs text-
|
|
3147
|
+
cards.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-1 py-4 text-center text-xs text-muted-foreground", children: "No cards" }),
|
|
2777
3148
|
showCreate && onCreateCard && /* @__PURE__ */ jsx(
|
|
2778
3149
|
"button",
|
|
2779
3150
|
{
|
|
2780
3151
|
type: "button",
|
|
2781
3152
|
onClick: () => onCreateCard(lane),
|
|
2782
3153
|
className: cn9(
|
|
2783
|
-
|
|
2784
|
-
"
|
|
2785
|
-
"
|
|
2786
|
-
"
|
|
3154
|
+
// ≥44px touch (M12/F5) — density kept via padding, not height.
|
|
3155
|
+
"mt-1 inline-flex min-h-11 w-full items-center justify-center rounded-lg border border-dashed border-border px-3 py-2",
|
|
3156
|
+
"text-sm font-medium text-muted-foreground",
|
|
3157
|
+
"hover:border-primary/50 hover:text-foreground transition",
|
|
3158
|
+
"focus:outline-none focus:ring-2 focus:ring-ring/40"
|
|
2787
3159
|
),
|
|
2788
3160
|
children: "+ New card"
|
|
2789
3161
|
}
|
|
@@ -2798,14 +3170,14 @@ function SkeletonCard() {
|
|
|
2798
3170
|
"div",
|
|
2799
3171
|
{
|
|
2800
3172
|
className: cn9(
|
|
2801
|
-
"w-full rounded-lg border border-
|
|
2802
|
-
"bg-
|
|
3173
|
+
"w-full rounded-lg border border-border",
|
|
3174
|
+
"bg-card p-3 shadow-sm"
|
|
2803
3175
|
),
|
|
2804
3176
|
"aria-hidden": "true",
|
|
2805
3177
|
children: [
|
|
2806
|
-
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 rounded bg-
|
|
2807
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 h-2.5 w-1/2 rounded bg-
|
|
2808
|
-
/* @__PURE__ */ jsx("div", { className: "mt-3 h-4 w-1/3 rounded bg-
|
|
3178
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 rounded bg-muted" }),
|
|
3179
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 h-2.5 w-1/2 rounded bg-muted" }),
|
|
3180
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 h-4 w-1/3 rounded bg-muted" })
|
|
2809
3181
|
]
|
|
2810
3182
|
}
|
|
2811
3183
|
);
|
|
@@ -2816,14 +3188,14 @@ function SkeletonColumn({ cardCount }) {
|
|
|
2816
3188
|
{
|
|
2817
3189
|
className: cn9(
|
|
2818
3190
|
"flex w-72 shrink-0 flex-col rounded-xl",
|
|
2819
|
-
"bg-
|
|
2820
|
-
"border border-
|
|
3191
|
+
"bg-muted/40",
|
|
3192
|
+
"border border-border"
|
|
2821
3193
|
),
|
|
2822
3194
|
"aria-hidden": "true",
|
|
2823
3195
|
children: [
|
|
2824
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2.5 border-b border-
|
|
2825
|
-
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-24 rounded bg-
|
|
2826
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 w-6 rounded-full bg-
|
|
3196
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2.5 border-b border-border", children: [
|
|
3197
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-24 rounded bg-muted" }),
|
|
3198
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-6 rounded-full bg-muted" })
|
|
2827
3199
|
] }),
|
|
2828
3200
|
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-2 p-2", children: Array.from({ length: cardCount }).map((_, i) => (
|
|
2829
3201
|
// eslint-disable-next-line react/no-array-index-key
|
|
@@ -2852,6 +3224,67 @@ function KanbanBoardSkeleton({
|
|
|
2852
3224
|
}
|
|
2853
3225
|
);
|
|
2854
3226
|
}
|
|
3227
|
+
function formatCountdown(nextTickAt) {
|
|
3228
|
+
if (!nextTickAt) return null;
|
|
3229
|
+
const target = Date.parse(nextTickAt);
|
|
3230
|
+
if (Number.isNaN(target)) return null;
|
|
3231
|
+
const ms = target - Date.now();
|
|
3232
|
+
if (ms <= 0) return "any moment";
|
|
3233
|
+
const mins = Math.round(ms / 6e4);
|
|
3234
|
+
if (mins < 1) return "under a minute";
|
|
3235
|
+
if (mins < 60) return `${mins}m`;
|
|
3236
|
+
const hrs = Math.floor(mins / 60);
|
|
3237
|
+
const rem = mins % 60;
|
|
3238
|
+
return rem > 0 ? `${hrs}h ${rem}m` : `${hrs}h`;
|
|
3239
|
+
}
|
|
3240
|
+
var DOT_TONE = {
|
|
3241
|
+
"on-schedule": "bg-success",
|
|
3242
|
+
due: "bg-info",
|
|
3243
|
+
paused: "bg-muted-foreground"
|
|
3244
|
+
};
|
|
3245
|
+
var DEFAULT_LABEL = {
|
|
3246
|
+
"on-schedule": "On schedule",
|
|
3247
|
+
due: "Running now",
|
|
3248
|
+
paused: "Paused"
|
|
3249
|
+
};
|
|
3250
|
+
function ScheduleStatus({
|
|
3251
|
+
nextTickAt,
|
|
3252
|
+
dueByLane,
|
|
3253
|
+
label,
|
|
3254
|
+
tone = "on-schedule",
|
|
3255
|
+
className
|
|
3256
|
+
}) {
|
|
3257
|
+
const countdown = formatCountdown(nextTickAt);
|
|
3258
|
+
const totalDue = dueByLane ? Object.values(dueByLane).reduce((a, b) => a + b, 0) : 0;
|
|
3259
|
+
return /* @__PURE__ */ jsxs(
|
|
3260
|
+
"div",
|
|
3261
|
+
{
|
|
3262
|
+
className: cn9(
|
|
3263
|
+
"flex items-center gap-2 text-xs text-muted-foreground",
|
|
3264
|
+
className
|
|
3265
|
+
),
|
|
3266
|
+
children: [
|
|
3267
|
+
/* @__PURE__ */ jsx(
|
|
3268
|
+
"span",
|
|
3269
|
+
{
|
|
3270
|
+
"aria-hidden": true,
|
|
3271
|
+
className: cn9("h-2 w-2 shrink-0 rounded-full", DOT_TONE[tone])
|
|
3272
|
+
}
|
|
3273
|
+
),
|
|
3274
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: label ?? DEFAULT_LABEL[tone] }),
|
|
3275
|
+
countdown && /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
|
|
3276
|
+
"\xB7 next run in ",
|
|
3277
|
+
countdown
|
|
3278
|
+
] }),
|
|
3279
|
+
totalDue > 0 && /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
|
|
3280
|
+
"\xB7 ",
|
|
3281
|
+
totalDue,
|
|
3282
|
+
" due"
|
|
3283
|
+
] })
|
|
3284
|
+
]
|
|
3285
|
+
}
|
|
3286
|
+
);
|
|
3287
|
+
}
|
|
2855
3288
|
function KanbanBoard({
|
|
2856
3289
|
adapter,
|
|
2857
3290
|
onCreateCard,
|
|
@@ -2862,6 +3295,11 @@ function KanbanBoard({
|
|
|
2862
3295
|
enableEdit = true,
|
|
2863
3296
|
enableAdvance = true,
|
|
2864
3297
|
pollIntervalMs,
|
|
3298
|
+
laneCounts,
|
|
3299
|
+
canEditHandlers,
|
|
3300
|
+
laneAgentPicker,
|
|
3301
|
+
scheduleStatus,
|
|
3302
|
+
focusCardId,
|
|
2865
3303
|
className
|
|
2866
3304
|
}) {
|
|
2867
3305
|
const {
|
|
@@ -2878,6 +3316,16 @@ function KanbanBoard({
|
|
|
2878
3316
|
transitionCard,
|
|
2879
3317
|
handleRunTerminal
|
|
2880
3318
|
} = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
|
|
3319
|
+
const lastFocusedRef = useRef(void 0);
|
|
3320
|
+
useEffect(() => {
|
|
3321
|
+
if (!focusCardId) {
|
|
3322
|
+
lastFocusedRef.current = void 0;
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
if (lastFocusedRef.current === focusCardId) return;
|
|
3326
|
+
lastFocusedRef.current = focusCardId;
|
|
3327
|
+
void openCard(focusCardId);
|
|
3328
|
+
}, [focusCardId]);
|
|
2881
3329
|
const handleCardClick = useCallback(
|
|
2882
3330
|
(card) => {
|
|
2883
3331
|
void openCard(card.id);
|
|
@@ -2914,10 +3362,11 @@ function KanbanBoard({
|
|
|
2914
3362
|
const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
|
|
2915
3363
|
const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
|
|
2916
3364
|
return /* @__PURE__ */ jsxs("div", { className: cn9("flex h-full w-full flex-col", className), children: [
|
|
2917
|
-
error && /* @__PURE__ */ jsx("div", { className: "m-3 rounded-md border border-
|
|
3365
|
+
error && /* @__PURE__ */ jsx("div", { className: "m-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error }),
|
|
3366
|
+
scheduleStatus && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border px-4 py-2", children: /* @__PURE__ */ jsx(ScheduleStatus, { ...scheduleStatus }) }),
|
|
2918
3367
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
2919
3368
|
lanes.length === 0 && isLoading ? /* @__PURE__ */ jsx(KanbanBoardSkeleton, { className: "flex-1 overflow-x-auto p-4" }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-start gap-4 overflow-x-auto p-4 snap-x snap-mandatory no-scrollbar sm:snap-none", children: [
|
|
2920
|
-
lanes.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-
|
|
3369
|
+
lanes.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No lanes configured." }),
|
|
2921
3370
|
lanes.map((lane) => /* @__PURE__ */ jsx(
|
|
2922
3371
|
KanbanColumn,
|
|
2923
3372
|
{
|
|
@@ -2926,7 +3375,10 @@ function KanbanBoard({
|
|
|
2926
3375
|
onCardClick: handleCardClick,
|
|
2927
3376
|
selectedCardId: selectedCard?.id,
|
|
2928
3377
|
onCreateCard: handleCreate,
|
|
2929
|
-
showCreate: enableCreate && lane.key === initialLaneKey
|
|
3378
|
+
showCreate: enableCreate && lane.key === initialLaneKey,
|
|
3379
|
+
count: laneCounts?.[lane.key],
|
|
3380
|
+
agentPicker: laneAgentPicker?.(lane),
|
|
3381
|
+
canEditHandlers
|
|
2930
3382
|
},
|
|
2931
3383
|
lane.id ?? lane.key
|
|
2932
3384
|
))
|
|
@@ -3668,15 +4120,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
3668
4120
|
sseClient = null;
|
|
3669
4121
|
status = "connecting";
|
|
3670
4122
|
reconnectAttempts = 0;
|
|
3671
|
-
// CAD-39 / webchat dual-plane create-connect race. `hasConnected` flips true on
|
|
3672
|
-
// the first successful SSE open; `notFoundRetries` bounds retries of a 404
|
|
3673
|
-
// encountered BEFORE we ever connect (the run row is persisted slightly AFTER
|
|
3674
|
-
// the client opens the stream — the norm on the webchat path where msg-api owns
|
|
3675
|
-
// the executionId and cadra persists the agent_executions row via an async
|
|
3676
|
-
// worker callback). See handleConnectionError.
|
|
3677
|
-
hasConnected = false;
|
|
3678
|
-
notFoundRetries = 0;
|
|
3679
|
-
maxConnectRaceRetries = 3;
|
|
3680
4123
|
seenEventIds = /* @__PURE__ */ new Set();
|
|
3681
4124
|
_lastEventId = null;
|
|
3682
4125
|
activityTimeoutId = null;
|
|
@@ -3816,8 +4259,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
3816
4259
|
if (connected) {
|
|
3817
4260
|
this.status = "connected";
|
|
3818
4261
|
this.reconnectAttempts = 0;
|
|
3819
|
-
this.hasConnected = true;
|
|
3820
|
-
this.notFoundRetries = 0;
|
|
3821
4262
|
this.resetActivityTimeout();
|
|
3822
4263
|
}
|
|
3823
4264
|
this.emit("connectionChange", { connected, usingFallback: false });
|
|
@@ -4107,38 +4548,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
4107
4548
|
return;
|
|
4108
4549
|
}
|
|
4109
4550
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4110
|
-
const isNotFound = /\b404\b/.test(msg);
|
|
4111
|
-
const isAuthFailure = /\b40[13]\b/.test(msg) || /INVALID_API_KEY|INVALID_REQUEST/.test(msg);
|
|
4112
|
-
if (isNotFound && !isAuthFailure && !this.hasConnected) {
|
|
4113
|
-
if (this.notFoundRetries < this.maxConnectRaceRetries) {
|
|
4114
|
-
this.notFoundRetries++;
|
|
4115
|
-
this.status = "reconnecting";
|
|
4116
|
-
const delay = Math.min(
|
|
4117
|
-
this.config.reconnectBaseDelayMs * this.notFoundRetries,
|
|
4118
|
-
this.config.reconnectMaxDelayMs
|
|
4119
|
-
);
|
|
4120
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
4121
|
-
if (this.status === "closed") {
|
|
4122
|
-
return;
|
|
4123
|
-
}
|
|
4124
|
-
try {
|
|
4125
|
-
await this.connectSSE();
|
|
4126
|
-
} catch (retryError) {
|
|
4127
|
-
await this.handleConnectionError(retryError);
|
|
4128
|
-
}
|
|
4129
|
-
return;
|
|
4130
|
-
}
|
|
4131
|
-
if (this.pollingEnabled) {
|
|
4132
|
-
if (this.sseClient) {
|
|
4133
|
-
this.sseClient.disconnect();
|
|
4134
|
-
this.sseClient = null;
|
|
4135
|
-
}
|
|
4136
|
-
this.status = "fallback_polling";
|
|
4137
|
-
this.emit("connectionChange", { connected: false, usingFallback: true });
|
|
4138
|
-
this.startPolling();
|
|
4139
|
-
return;
|
|
4140
|
-
}
|
|
4141
|
-
}
|
|
4142
4551
|
if (/\b4\d\d\b/.test(msg) || /INVALID_API_KEY|INVALID_REQUEST/.test(msg)) {
|
|
4143
4552
|
if (this.sseClient) {
|
|
4144
4553
|
this.sseClient.disconnect();
|
|
@@ -4388,6 +4797,7 @@ var AgentsAPI = class extends BaseResourceAPI {
|
|
|
4388
4797
|
super(http, "/api/v1/agents");
|
|
4389
4798
|
this.getStreamConfig = getStreamConfig;
|
|
4390
4799
|
}
|
|
4800
|
+
getStreamConfig;
|
|
4391
4801
|
// ===== LIST Operations =====
|
|
4392
4802
|
/**
|
|
4393
4803
|
* List all agents in the organization
|
|
@@ -5293,6 +5703,7 @@ var SessionsAPI = class extends BaseResourceAPI {
|
|
|
5293
5703
|
super(http, "/api/v1/sessions");
|
|
5294
5704
|
this.getStreamConfig = getStreamConfig;
|
|
5295
5705
|
}
|
|
5706
|
+
getStreamConfig;
|
|
5296
5707
|
// ===== LIST Operations =====
|
|
5297
5708
|
/**
|
|
5298
5709
|
* List all sessions in the organization
|
|
@@ -5612,6 +6023,7 @@ var KanbanAPI = class extends BaseResourceAPI {
|
|
|
5612
6023
|
super(http, "/api/v1/kanban");
|
|
5613
6024
|
this.getStreamConfig = getStreamConfig;
|
|
5614
6025
|
}
|
|
6026
|
+
getStreamConfig;
|
|
5615
6027
|
// ===== BOARD =====
|
|
5616
6028
|
/**
|
|
5617
6029
|
* Get the current org's board (lanes in declared order). Auto-provisions
|
|
@@ -5813,6 +6225,7 @@ var RemoteAgentsAPI = class extends BaseResourceAPI {
|
|
|
5813
6225
|
super(http, "/api/v1/remote-agents");
|
|
5814
6226
|
this.getStreamConfig = getStreamConfig;
|
|
5815
6227
|
}
|
|
6228
|
+
getStreamConfig;
|
|
5816
6229
|
/**
|
|
5817
6230
|
* List all remote agents in the organization
|
|
5818
6231
|
*
|
|
@@ -6186,6 +6599,6 @@ function createDefaultKanbanAdapter(config) {
|
|
|
6186
6599
|
};
|
|
6187
6600
|
}
|
|
6188
6601
|
|
|
6189
|
-
export { AgentBoard, BoardConfigClient, CadraLifecycleSource, CardDrawer, KanbanBoard, KanbanCard as KanbanCardTile, KanbanColumn, createDefaultKanbanAdapter, mapDefinitionToBoard, toResolvedLifecycle, useCardRun, useKanbanBoard };
|
|
6602
|
+
export { AgentBoard, BoardConfigClient, CadraLifecycleSource, CapMeter, CardDrawer, KanbanBoard, KanbanCard as KanbanCardTile, KanbanColumn, LaneAgentPicker, ScheduleStatus, badgeVariantClass, cn9 as cn, createDefaultKanbanAdapter, mapDefinitionToBoard, runStatusTone, toResolvedLifecycle, useCardRun, useKanbanBoard };
|
|
6190
6603
|
//# sourceMappingURL=index.js.map
|
|
6191
6604
|
//# sourceMappingURL=index.js.map
|