@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.cjs
CHANGED
|
@@ -23,6 +23,10 @@ function mapHandler(h) {
|
|
|
23
23
|
type: h.type,
|
|
24
24
|
agentUuid: h.agent_uuid,
|
|
25
25
|
teamUuid: h.team_uuid,
|
|
26
|
+
// FINDING-6: carry the remote_agent binding through the wire parse. The
|
|
27
|
+
// engine's remote_agent dispatch reads `remoteAgentUuid`; dropping it here
|
|
28
|
+
// made every published remote_agent lane dispatch-dead.
|
|
29
|
+
remoteAgentUuid: h.remote_agent_uuid,
|
|
26
30
|
agentRef: h.agent_ref,
|
|
27
31
|
webhook: h.webhook ? {
|
|
28
32
|
url: h.webhook.url,
|
|
@@ -2300,35 +2304,40 @@ function useCardRun(options) {
|
|
|
2300
2304
|
function cn9(...classes) {
|
|
2301
2305
|
return classes.filter(Boolean).join(" ");
|
|
2302
2306
|
}
|
|
2303
|
-
function
|
|
2304
|
-
switch (
|
|
2305
|
-
case "
|
|
2306
|
-
return
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
case "
|
|
2316
|
-
return
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
case "cancelled":
|
|
2321
|
-
return {
|
|
2322
|
-
label: "Cancelled",
|
|
2323
|
-
className: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400"
|
|
2324
|
-
};
|
|
2307
|
+
function badgeVariantClass(variant) {
|
|
2308
|
+
switch (variant) {
|
|
2309
|
+
case "default":
|
|
2310
|
+
return "bg-primary text-primary-foreground";
|
|
2311
|
+
case "secondary":
|
|
2312
|
+
return "border border-border bg-secondary text-secondary-foreground";
|
|
2313
|
+
case "outline":
|
|
2314
|
+
return "border border-border text-foreground";
|
|
2315
|
+
case "info":
|
|
2316
|
+
return "border border-info/30 bg-info/15 text-info";
|
|
2317
|
+
case "success":
|
|
2318
|
+
return "border border-success/30 bg-success/15 text-success";
|
|
2319
|
+
case "warning":
|
|
2320
|
+
return "border border-warning/40 bg-warning/15 text-warning";
|
|
2321
|
+
case "destructive":
|
|
2322
|
+
return "border border-destructive/40 bg-destructive/15 text-destructive";
|
|
2323
|
+
case "neutral":
|
|
2325
2324
|
default:
|
|
2326
|
-
return
|
|
2327
|
-
label: "Pending",
|
|
2328
|
-
className: "bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300"
|
|
2329
|
-
};
|
|
2325
|
+
return "border border-border bg-secondary text-muted-foreground";
|
|
2330
2326
|
}
|
|
2331
2327
|
}
|
|
2328
|
+
function runStatusTone(status) {
|
|
2329
|
+
const map = {
|
|
2330
|
+
running: { label: "Running", variant: "info" },
|
|
2331
|
+
completed: { label: "Completed", variant: "success" },
|
|
2332
|
+
failed: { label: "Failed", variant: "destructive" },
|
|
2333
|
+
cancelled: { label: "Cancelled", variant: "neutral" }
|
|
2334
|
+
};
|
|
2335
|
+
const { label, variant } = map[status ?? ""] ?? {
|
|
2336
|
+
label: "Pending",
|
|
2337
|
+
variant: "neutral"
|
|
2338
|
+
};
|
|
2339
|
+
return { label, variant, className: badgeVariantClass(variant) };
|
|
2340
|
+
}
|
|
2332
2341
|
function CardDrawer({
|
|
2333
2342
|
card,
|
|
2334
2343
|
adapter,
|
|
@@ -2447,11 +2456,11 @@ function CardDrawer({
|
|
|
2447
2456
|
role: "dialog",
|
|
2448
2457
|
"aria-label": `Card: ${card.title}`,
|
|
2449
2458
|
className: cn9(
|
|
2450
|
-
"flex h-full w-full sm:max-w-sm flex-col bg-
|
|
2459
|
+
"flex h-full w-full sm:max-w-sm flex-col bg-card border-l border-border shadow-xl",
|
|
2451
2460
|
className
|
|
2452
2461
|
),
|
|
2453
2462
|
children: [
|
|
2454
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 border-b border-
|
|
2463
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 border-b border-border px-4 py-3", children: [
|
|
2455
2464
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
2456
2465
|
isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2457
2466
|
"input",
|
|
@@ -2461,14 +2470,14 @@ function CardDrawer({
|
|
|
2461
2470
|
onChange: (e) => setEditTitle(e.target.value),
|
|
2462
2471
|
"aria-label": "Card title",
|
|
2463
2472
|
placeholder: "Card title",
|
|
2464
|
-
className: "w-full rounded-md border border-
|
|
2473
|
+
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"
|
|
2465
2474
|
}
|
|
2466
2475
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2467
2476
|
"h2",
|
|
2468
2477
|
{
|
|
2469
2478
|
className: cn9(
|
|
2470
|
-
"text-base font-semibold text-
|
|
2471
|
-
onUpdate && "cursor-text rounded hover:bg-
|
|
2479
|
+
"text-base font-semibold text-foreground truncate",
|
|
2480
|
+
onUpdate && "cursor-text rounded hover:bg-muted/60 -mx-1 px-1"
|
|
2472
2481
|
),
|
|
2473
2482
|
onClick: onUpdate ? () => setIsEditing(true) : void 0,
|
|
2474
2483
|
title: onUpdate ? "Click to edit" : void 0,
|
|
@@ -2476,7 +2485,7 @@ function CardDrawer({
|
|
|
2476
2485
|
}
|
|
2477
2486
|
),
|
|
2478
2487
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
2479
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-
|
|
2488
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: card.lane }),
|
|
2480
2489
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2481
2490
|
"span",
|
|
2482
2491
|
{
|
|
@@ -2496,7 +2505,7 @@ function CardDrawer({
|
|
|
2496
2505
|
type: "button",
|
|
2497
2506
|
onClick: () => setIsEditing(true),
|
|
2498
2507
|
"aria-label": "Edit card",
|
|
2499
|
-
className: "rounded p-1 text-
|
|
2508
|
+
className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2500
2509
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2501
2510
|
"svg",
|
|
2502
2511
|
{
|
|
@@ -2522,7 +2531,7 @@ function CardDrawer({
|
|
|
2522
2531
|
type: "button",
|
|
2523
2532
|
onClick: onClose,
|
|
2524
2533
|
"aria-label": "Close",
|
|
2525
|
-
className: "rounded p-1 text-
|
|
2534
|
+
className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2526
2535
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2527
2536
|
"svg",
|
|
2528
2537
|
{
|
|
@@ -2544,8 +2553,8 @@ function CardDrawer({
|
|
|
2544
2553
|
)
|
|
2545
2554
|
] })
|
|
2546
2555
|
] }),
|
|
2547
|
-
isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-
|
|
2548
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-1 block text-xs font-medium text-
|
|
2556
|
+
isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border px-4 py-3", children: [
|
|
2557
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Description" }),
|
|
2549
2558
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2550
2559
|
"textarea",
|
|
2551
2560
|
{
|
|
@@ -2554,7 +2563,7 @@ function CardDrawer({
|
|
|
2554
2563
|
"aria-label": "Card description",
|
|
2555
2564
|
rows: 4,
|
|
2556
2565
|
placeholder: "Add a description\u2026",
|
|
2557
|
-
className: "w-full resize-y rounded-md border border-
|
|
2566
|
+
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"
|
|
2558
2567
|
}
|
|
2559
2568
|
),
|
|
2560
2569
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-end gap-2", children: [
|
|
@@ -2564,7 +2573,7 @@ function CardDrawer({
|
|
|
2564
2573
|
type: "button",
|
|
2565
2574
|
onClick: handleCancel,
|
|
2566
2575
|
disabled: isSaving,
|
|
2567
|
-
className: "rounded-md px-3 py-1.5 text-sm font-medium text-
|
|
2576
|
+
className: "rounded-md px-3 py-1.5 text-sm font-medium text-muted-foreground hover:bg-muted disabled:opacity-50",
|
|
2568
2577
|
children: "Cancel"
|
|
2569
2578
|
}
|
|
2570
2579
|
),
|
|
@@ -2574,26 +2583,27 @@ function CardDrawer({
|
|
|
2574
2583
|
type: "button",
|
|
2575
2584
|
onClick: () => void handleSave(),
|
|
2576
2585
|
disabled: isSaving,
|
|
2577
|
-
className: "rounded-md bg-
|
|
2586
|
+
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",
|
|
2578
2587
|
children: isSaving ? "Saving\u2026" : "Save"
|
|
2579
2588
|
}
|
|
2580
2589
|
)
|
|
2581
2590
|
] })
|
|
2582
|
-
] }) : (card.description || onUpdate) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-
|
|
2591
|
+
] }) : (card.description || onUpdate) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2583
2592
|
"p",
|
|
2584
2593
|
{
|
|
2585
2594
|
className: cn9(
|
|
2586
2595
|
"text-sm whitespace-pre-wrap",
|
|
2587
|
-
card.description ? "text-
|
|
2588
|
-
onUpdate && "cursor-text rounded hover:bg-
|
|
2596
|
+
card.description ? "text-muted-foreground" : "italic text-muted-foreground/70",
|
|
2597
|
+
onUpdate && "cursor-text rounded hover:bg-muted/60 -mx-1 px-1"
|
|
2589
2598
|
),
|
|
2590
2599
|
onClick: onUpdate ? () => setIsEditing(true) : void 0,
|
|
2591
2600
|
title: onUpdate ? "Click to edit" : void 0,
|
|
2592
2601
|
children: card.description || "Add a description\u2026"
|
|
2593
2602
|
}
|
|
2594
2603
|
) }),
|
|
2595
|
-
showTransitionButtons ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 border-b border-
|
|
2596
|
-
isHumanGate &&
|
|
2604
|
+
showTransitionButtons ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 border-b border-border px-4 py-2", children: [
|
|
2605
|
+
isHumanGate && // Human gate = needs-you → warning (amber is reserved for this, F3).
|
|
2606
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-auto text-xs font-medium text-warning", children: "Awaiting your approval" }),
|
|
2597
2607
|
manualEdges.map((t, i) => {
|
|
2598
2608
|
const toLabel = laneByKey.get(t.toLane)?.label ?? t.toLane;
|
|
2599
2609
|
const isPrimary = isHumanGate ? i === 0 : false;
|
|
@@ -2606,26 +2616,27 @@ function CardDrawer({
|
|
|
2606
2616
|
onClick: () => void handleTransition(t.toLane),
|
|
2607
2617
|
disabled: pendingLane !== null,
|
|
2608
2618
|
className: cn9(
|
|
2609
|
-
|
|
2610
|
-
|
|
2619
|
+
// ≥44px touch (M12/F5) — density kept via padding, not height.
|
|
2620
|
+
"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",
|
|
2621
|
+
isPrimary ? "border border-border bg-secondary text-secondary-foreground hover:bg-muted" : "border border-border text-foreground hover:bg-muted"
|
|
2611
2622
|
),
|
|
2612
2623
|
children: busy ? "Moving\u2026" : label
|
|
2613
2624
|
},
|
|
2614
2625
|
t.id
|
|
2615
2626
|
);
|
|
2616
2627
|
})
|
|
2617
|
-
] }) : onAdvance && canAdvance && !isEditing && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end border-b border-
|
|
2628
|
+
] }) : onAdvance && canAdvance && !isEditing && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end border-b border-border px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2618
2629
|
"button",
|
|
2619
2630
|
{
|
|
2620
2631
|
type: "button",
|
|
2621
2632
|
onClick: () => void handleAdvance(),
|
|
2622
2633
|
disabled: isAdvancing,
|
|
2623
|
-
className: "rounded-md border border-
|
|
2634
|
+
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",
|
|
2624
2635
|
children: isAdvancing ? "Advancing\u2026" : "Advance \u2192"
|
|
2625
2636
|
}
|
|
2626
2637
|
) }),
|
|
2627
2638
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
2628
|
-
!hasExecution ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-
|
|
2639
|
+
!hasExecution ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center p-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No run yet for this card." }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2629
2640
|
MessageList,
|
|
2630
2641
|
{
|
|
2631
2642
|
messages: run.messages,
|
|
@@ -2638,14 +2649,14 @@ function CardDrawer({
|
|
|
2638
2649
|
className: "flex-1"
|
|
2639
2650
|
}
|
|
2640
2651
|
),
|
|
2641
|
-
failed && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-
|
|
2642
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-
|
|
2652
|
+
failed && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-destructive/40 bg-destructive/10 px-4 py-3", children: [
|
|
2653
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: run.error ?? "Run failed." }),
|
|
2643
2654
|
onRetry && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2644
2655
|
"button",
|
|
2645
2656
|
{
|
|
2646
2657
|
type: "button",
|
|
2647
2658
|
onClick: () => onRetry(card),
|
|
2648
|
-
className: "shrink-0 rounded-md bg-
|
|
2659
|
+
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",
|
|
2649
2660
|
children: "Retry"
|
|
2650
2661
|
}
|
|
2651
2662
|
)
|
|
@@ -2687,10 +2698,51 @@ function Spinner({ className }) {
|
|
|
2687
2698
|
}
|
|
2688
2699
|
);
|
|
2689
2700
|
}
|
|
2690
|
-
function
|
|
2701
|
+
function ClockIcon2() {
|
|
2702
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2703
|
+
"svg",
|
|
2704
|
+
{
|
|
2705
|
+
viewBox: "0 0 24 24",
|
|
2706
|
+
fill: "none",
|
|
2707
|
+
stroke: "currentColor",
|
|
2708
|
+
strokeWidth: "2",
|
|
2709
|
+
strokeLinecap: "round",
|
|
2710
|
+
strokeLinejoin: "round",
|
|
2711
|
+
"aria-hidden": true,
|
|
2712
|
+
className: "h-2.5 w-2.5",
|
|
2713
|
+
children: [
|
|
2714
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2715
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v5l3 2" })
|
|
2716
|
+
]
|
|
2717
|
+
}
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
function KanbanCard({
|
|
2721
|
+
card,
|
|
2722
|
+
onClick,
|
|
2723
|
+
selected,
|
|
2724
|
+
dueState,
|
|
2725
|
+
className
|
|
2726
|
+
}) {
|
|
2691
2727
|
const runStatus = card.run?.status;
|
|
2692
|
-
const
|
|
2693
|
-
const
|
|
2728
|
+
const isWorking = runStatus === "running";
|
|
2729
|
+
const failed = runStatus === "failed";
|
|
2730
|
+
let chip = null;
|
|
2731
|
+
if (failed) {
|
|
2732
|
+
chip = { label: "Failed", variant: "destructive" };
|
|
2733
|
+
} else if (dueState === "ready") {
|
|
2734
|
+
chip = { label: "Ready", variant: "success" };
|
|
2735
|
+
} else if (runStatus === "completed") {
|
|
2736
|
+
const t = runStatusTone(runStatus);
|
|
2737
|
+
chip = { label: t.label, variant: t.variant };
|
|
2738
|
+
} else if (dueState === "due") {
|
|
2739
|
+
chip = { label: "Due", variant: "neutral", icon: "clock" };
|
|
2740
|
+
} else if (dueState === "waiting") {
|
|
2741
|
+
chip = { label: "Waiting", variant: "neutral" };
|
|
2742
|
+
} else if (runStatus) {
|
|
2743
|
+
const t = runStatusTone(runStatus);
|
|
2744
|
+
chip = { label: t.label, variant: t.variant };
|
|
2745
|
+
}
|
|
2694
2746
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2695
2747
|
"button",
|
|
2696
2748
|
{
|
|
@@ -2699,46 +2751,311 @@ function KanbanCard({ card, onClick, selected, className }) {
|
|
|
2699
2751
|
"aria-pressed": selected,
|
|
2700
2752
|
"aria-busy": isWorking,
|
|
2701
2753
|
className: cn9(
|
|
2702
|
-
"relative w-full text-left rounded-lg border bg-
|
|
2703
|
-
"hover:shadow-md hover:border-
|
|
2704
|
-
"focus:outline-none focus:ring-2 focus:ring-
|
|
2705
|
-
|
|
2754
|
+
"relative w-full text-left rounded-lg border bg-card p-3 shadow-sm transition",
|
|
2755
|
+
"hover:shadow-md hover:border-primary/40",
|
|
2756
|
+
"focus:outline-none focus:ring-2 focus:ring-ring/50",
|
|
2757
|
+
// The working card carries the SINGLE focal motion on the board (F11).
|
|
2758
|
+
isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
|
|
2706
2759
|
className
|
|
2707
2760
|
),
|
|
2708
2761
|
children: [
|
|
2709
|
-
isWorking && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2710
|
-
"span",
|
|
2711
|
-
{
|
|
2712
|
-
"aria-hidden": true,
|
|
2713
|
-
className: "pointer-events-none absolute -top-1 -right-1 flex h-3 w-3",
|
|
2714
|
-
children: [
|
|
2715
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-amber-400 opacity-75" }),
|
|
2716
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-3 w-3 rounded-full bg-amber-500" })
|
|
2717
|
-
]
|
|
2718
|
-
}
|
|
2719
|
-
),
|
|
2720
2762
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2721
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-
|
|
2722
|
-
isWorking ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2723
|
-
/* @__PURE__ */ jsxRuntime.jsx(Spinner, {}),
|
|
2724
|
-
"Working"
|
|
2725
|
-
] }) : tone && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2763
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground line-clamp-2", children: card.title }),
|
|
2764
|
+
isWorking ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2726
2765
|
"span",
|
|
2727
2766
|
{
|
|
2728
2767
|
className: cn9(
|
|
2729
|
-
"shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2730
|
-
|
|
2768
|
+
"shrink-0 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2769
|
+
badgeVariantClass("info")
|
|
2731
2770
|
),
|
|
2732
|
-
children:
|
|
2771
|
+
children: [
|
|
2772
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, {}),
|
|
2773
|
+
"Working"
|
|
2774
|
+
]
|
|
2775
|
+
}
|
|
2776
|
+
) : chip && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2777
|
+
"span",
|
|
2778
|
+
{
|
|
2779
|
+
className: cn9(
|
|
2780
|
+
"shrink-0 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide",
|
|
2781
|
+
badgeVariantClass(chip.variant)
|
|
2782
|
+
),
|
|
2783
|
+
children: [
|
|
2784
|
+
chip.icon === "clock" && /* @__PURE__ */ jsxRuntime.jsx(ClockIcon2, {}),
|
|
2785
|
+
chip.label
|
|
2786
|
+
]
|
|
2733
2787
|
}
|
|
2734
2788
|
)
|
|
2735
2789
|
] }),
|
|
2736
|
-
card.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-
|
|
2737
|
-
card.type && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block rounded bg-
|
|
2790
|
+
card.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: card.description }),
|
|
2791
|
+
card.type && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: card.type }) })
|
|
2738
2792
|
]
|
|
2739
2793
|
}
|
|
2740
2794
|
);
|
|
2741
2795
|
}
|
|
2796
|
+
function CapMeter({ count, cap, className }) {
|
|
2797
|
+
const pct = cap > 0 ? Math.min(100, Math.round(count / cap * 100)) : 0;
|
|
2798
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2799
|
+
"div",
|
|
2800
|
+
{
|
|
2801
|
+
className: cn9(
|
|
2802
|
+
"mt-2 flex items-center gap-2 text-[11px] text-muted-foreground",
|
|
2803
|
+
className
|
|
2804
|
+
),
|
|
2805
|
+
children: [
|
|
2806
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums font-medium", children: [
|
|
2807
|
+
count,
|
|
2808
|
+
"/",
|
|
2809
|
+
cap
|
|
2810
|
+
] }),
|
|
2811
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2812
|
+
"span",
|
|
2813
|
+
{
|
|
2814
|
+
role: "progressbar",
|
|
2815
|
+
"aria-valuemin": 0,
|
|
2816
|
+
"aria-valuemax": cap,
|
|
2817
|
+
"aria-valuenow": count,
|
|
2818
|
+
"aria-label": `${count} of ${cap} used`,
|
|
2819
|
+
className: "h-1 flex-1 overflow-hidden rounded-full bg-secondary",
|
|
2820
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2821
|
+
"span",
|
|
2822
|
+
{
|
|
2823
|
+
className: "block h-full rounded-full bg-primary",
|
|
2824
|
+
style: { width: `${pct}%` }
|
|
2825
|
+
}
|
|
2826
|
+
)
|
|
2827
|
+
}
|
|
2828
|
+
)
|
|
2829
|
+
]
|
|
2830
|
+
}
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
function AgentKindIcon({ kind }) {
|
|
2834
|
+
const common = {
|
|
2835
|
+
viewBox: "0 0 24 24",
|
|
2836
|
+
fill: "none",
|
|
2837
|
+
stroke: "currentColor",
|
|
2838
|
+
strokeWidth: 2,
|
|
2839
|
+
strokeLinecap: "round",
|
|
2840
|
+
strokeLinejoin: "round",
|
|
2841
|
+
className: "h-3.5 w-3.5",
|
|
2842
|
+
"aria-hidden": true
|
|
2843
|
+
};
|
|
2844
|
+
if (kind === "remote") {
|
|
2845
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2846
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
|
|
2847
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 21h8M12 17v4" })
|
|
2848
|
+
] });
|
|
2849
|
+
}
|
|
2850
|
+
if (kind === "human") {
|
|
2851
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2852
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
2853
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "7", r: "4" })
|
|
2854
|
+
] });
|
|
2855
|
+
}
|
|
2856
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...common, children: [
|
|
2857
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "11", width: "18", height: "10", rx: "2" }),
|
|
2858
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "2" }),
|
|
2859
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v4M8 16h.01M16 16h.01" })
|
|
2860
|
+
] });
|
|
2861
|
+
}
|
|
2862
|
+
function OnlineDot({ online }) {
|
|
2863
|
+
if (online === void 0) return null;
|
|
2864
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2865
|
+
"span",
|
|
2866
|
+
{
|
|
2867
|
+
"aria-label": online ? "connected" : "offline",
|
|
2868
|
+
className: cn9(
|
|
2869
|
+
"h-1.5 w-1.5 shrink-0 rounded-full",
|
|
2870
|
+
online ? "bg-success" : "bg-muted-foreground"
|
|
2871
|
+
)
|
|
2872
|
+
}
|
|
2873
|
+
);
|
|
2874
|
+
}
|
|
2875
|
+
function LaneAgentPicker({
|
|
2876
|
+
selected,
|
|
2877
|
+
options,
|
|
2878
|
+
onSelect,
|
|
2879
|
+
canEdit = true,
|
|
2880
|
+
lockedReason,
|
|
2881
|
+
className
|
|
2882
|
+
}) {
|
|
2883
|
+
const [open, setOpen] = react.useState(false);
|
|
2884
|
+
const rootRef = react.useRef(null);
|
|
2885
|
+
const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
|
|
2886
|
+
react.useEffect(() => {
|
|
2887
|
+
if (!open) return;
|
|
2888
|
+
const onDocDown = (e) => {
|
|
2889
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
2890
|
+
setOpen(false);
|
|
2891
|
+
}
|
|
2892
|
+
};
|
|
2893
|
+
const onKey = (e) => {
|
|
2894
|
+
if (e.key === "Escape") setOpen(false);
|
|
2895
|
+
};
|
|
2896
|
+
document.addEventListener("mousedown", onDocDown);
|
|
2897
|
+
document.addEventListener("touchstart", onDocDown);
|
|
2898
|
+
document.addEventListener("keydown", onKey);
|
|
2899
|
+
return () => {
|
|
2900
|
+
document.removeEventListener("mousedown", onDocDown);
|
|
2901
|
+
document.removeEventListener("touchstart", onDocDown);
|
|
2902
|
+
document.removeEventListener("keydown", onKey);
|
|
2903
|
+
};
|
|
2904
|
+
}, [open]);
|
|
2905
|
+
const kind = selected?.kind ?? "cadra";
|
|
2906
|
+
const displayLabel = selected?.label ?? "Unassigned";
|
|
2907
|
+
const face = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2908
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2909
|
+
"span",
|
|
2910
|
+
{
|
|
2911
|
+
className: cn9(
|
|
2912
|
+
"grid h-5 w-5 shrink-0 place-items-center rounded-full",
|
|
2913
|
+
kind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
|
|
2914
|
+
),
|
|
2915
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(AgentKindIcon, { kind })
|
|
2916
|
+
}
|
|
2917
|
+
),
|
|
2918
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
|
|
2919
|
+
/* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: selected?.online })
|
|
2920
|
+
] });
|
|
2921
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
|
|
2922
|
+
editable ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2923
|
+
"button",
|
|
2924
|
+
{
|
|
2925
|
+
type: "button",
|
|
2926
|
+
onClick: () => setOpen((o) => !o),
|
|
2927
|
+
"aria-haspopup": "listbox",
|
|
2928
|
+
"aria-expanded": open,
|
|
2929
|
+
"aria-label": `Assigned agent: ${displayLabel}. Change`,
|
|
2930
|
+
className: cn9(
|
|
2931
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-lg border border-border bg-card px-2",
|
|
2932
|
+
"text-xs font-semibold text-foreground",
|
|
2933
|
+
"hover:border-primary/50 focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
2934
|
+
),
|
|
2935
|
+
children: [
|
|
2936
|
+
face,
|
|
2937
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2938
|
+
"svg",
|
|
2939
|
+
{
|
|
2940
|
+
viewBox: "0 0 24 24",
|
|
2941
|
+
fill: "none",
|
|
2942
|
+
stroke: "currentColor",
|
|
2943
|
+
strokeWidth: 2,
|
|
2944
|
+
strokeLinecap: "round",
|
|
2945
|
+
strokeLinejoin: "round",
|
|
2946
|
+
"aria-hidden": true,
|
|
2947
|
+
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
|
|
2948
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 9l6 6 6-6" })
|
|
2949
|
+
}
|
|
2950
|
+
)
|
|
2951
|
+
]
|
|
2952
|
+
}
|
|
2953
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2954
|
+
"div",
|
|
2955
|
+
{
|
|
2956
|
+
role: "group",
|
|
2957
|
+
"aria-label": `Assigned agent: ${displayLabel}`,
|
|
2958
|
+
className: cn9(
|
|
2959
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-lg border border-border bg-muted/60 px-2",
|
|
2960
|
+
"text-xs font-semibold text-muted-foreground"
|
|
2961
|
+
),
|
|
2962
|
+
children: [
|
|
2963
|
+
face,
|
|
2964
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2965
|
+
"svg",
|
|
2966
|
+
{
|
|
2967
|
+
viewBox: "0 0 24 24",
|
|
2968
|
+
fill: "none",
|
|
2969
|
+
stroke: "currentColor",
|
|
2970
|
+
strokeWidth: 2,
|
|
2971
|
+
strokeLinecap: "round",
|
|
2972
|
+
strokeLinejoin: "round",
|
|
2973
|
+
"aria-hidden": true,
|
|
2974
|
+
className: "h-3.5 w-3.5 shrink-0",
|
|
2975
|
+
children: [
|
|
2976
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "11", width: "14", height: "10", rx: "2" }),
|
|
2977
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })
|
|
2978
|
+
]
|
|
2979
|
+
}
|
|
2980
|
+
)
|
|
2981
|
+
]
|
|
2982
|
+
}
|
|
2983
|
+
),
|
|
2984
|
+
!editable && lockedReason && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
2985
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2986
|
+
"svg",
|
|
2987
|
+
{
|
|
2988
|
+
viewBox: "0 0 24 24",
|
|
2989
|
+
fill: "none",
|
|
2990
|
+
stroke: "currentColor",
|
|
2991
|
+
strokeWidth: 2,
|
|
2992
|
+
strokeLinecap: "round",
|
|
2993
|
+
strokeLinejoin: "round",
|
|
2994
|
+
"aria-hidden": true,
|
|
2995
|
+
className: "h-3 w-3 shrink-0",
|
|
2996
|
+
children: [
|
|
2997
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "11", width: "14", height: "10", rx: "2" }),
|
|
2998
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })
|
|
2999
|
+
]
|
|
3000
|
+
}
|
|
3001
|
+
),
|
|
3002
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: lockedReason })
|
|
3003
|
+
] }),
|
|
3004
|
+
editable && open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3005
|
+
"ul",
|
|
3006
|
+
{
|
|
3007
|
+
role: "listbox",
|
|
3008
|
+
"aria-label": "Assign an agent",
|
|
3009
|
+
className: cn9(
|
|
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"
|
|
3012
|
+
),
|
|
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(
|
|
3016
|
+
"button",
|
|
3017
|
+
{
|
|
3018
|
+
type: "button",
|
|
3019
|
+
onClick: () => {
|
|
3020
|
+
onSelect(opt.id);
|
|
3021
|
+
setOpen(false);
|
|
3022
|
+
},
|
|
3023
|
+
className: cn9(
|
|
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"
|
|
3027
|
+
),
|
|
3028
|
+
children: [
|
|
3029
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3030
|
+
"span",
|
|
3031
|
+
{
|
|
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" })
|
|
3037
|
+
}
|
|
3038
|
+
),
|
|
3039
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
|
|
3040
|
+
/* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: opt.online })
|
|
3041
|
+
]
|
|
3042
|
+
}
|
|
3043
|
+
) }, opt.id);
|
|
3044
|
+
})
|
|
3045
|
+
}
|
|
3046
|
+
)
|
|
3047
|
+
] });
|
|
3048
|
+
}
|
|
3049
|
+
function dueStateFor(card, lane, now) {
|
|
3050
|
+
const rs = card.run?.status;
|
|
3051
|
+
if (rs === "completed" && !lane.terminal) return "ready";
|
|
3052
|
+
if (card.nextDueAt) {
|
|
3053
|
+
const t = Date.parse(card.nextDueAt);
|
|
3054
|
+
if (!Number.isNaN(t) && t <= now) return "due";
|
|
3055
|
+
}
|
|
3056
|
+
if (lane.trigger === "scheduled" && !rs) return "waiting";
|
|
3057
|
+
return void 0;
|
|
3058
|
+
}
|
|
2742
3059
|
function KanbanColumn({
|
|
2743
3060
|
lane,
|
|
2744
3061
|
cards,
|
|
@@ -2746,29 +3063,82 @@ function KanbanColumn({
|
|
|
2746
3063
|
selectedCardId,
|
|
2747
3064
|
onCreateCard,
|
|
2748
3065
|
showCreate,
|
|
3066
|
+
count,
|
|
3067
|
+
agentPicker,
|
|
3068
|
+
canEditHandlers,
|
|
2749
3069
|
className
|
|
2750
3070
|
}) {
|
|
3071
|
+
const headerCount = count ?? cards.length;
|
|
3072
|
+
const isScheduled = lane.trigger === "scheduled";
|
|
3073
|
+
const showCapMeter = count !== void 0 && typeof lane.cap === "number" && lane.cap > 0;
|
|
3074
|
+
const showAgentBadge = lane.handler?.type === "cadra_agent" && !agentPicker;
|
|
3075
|
+
const now = Date.now();
|
|
2751
3076
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2752
3077
|
"div",
|
|
2753
3078
|
{
|
|
2754
3079
|
className: cn9(
|
|
2755
|
-
"flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-
|
|
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",
|
|
3081
|
+
isScheduled && "border-border",
|
|
2756
3082
|
className
|
|
2757
3083
|
),
|
|
2758
3084
|
children: [
|
|
2759
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
2760
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2
|
|
2761
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
3085
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border px-3 py-2.5", children: [
|
|
3086
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3087
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
3088
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-foreground truncate", children: lane.label }),
|
|
3089
|
+
showAgentBadge && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3090
|
+
"span",
|
|
3091
|
+
{
|
|
3092
|
+
title: lane.handler?.agentRef ? `Agent: ${lane.handler.agentRef}` : "Agent lane",
|
|
3093
|
+
className: cn9(
|
|
3094
|
+
// A static lane marker — NOT a run state. Uses neutral tokens,
|
|
3095
|
+
// never `info` (which means "running" in the F3 vocabulary).
|
|
3096
|
+
"rounded px-1.5 py-0.5 text-[10px] font-medium",
|
|
3097
|
+
badgeVariantClass("neutral")
|
|
3098
|
+
),
|
|
3099
|
+
children: "agent"
|
|
3100
|
+
}
|
|
3101
|
+
)
|
|
3102
|
+
] }),
|
|
3103
|
+
/* @__PURE__ */ jsxRuntime.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 })
|
|
2770
3104
|
] }),
|
|
2771
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
3105
|
+
isScheduled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex items-center gap-2 flex-wrap", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3106
|
+
"span",
|
|
3107
|
+
{
|
|
3108
|
+
className: cn9(
|
|
3109
|
+
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-semibold",
|
|
3110
|
+
badgeVariantClass("neutral")
|
|
3111
|
+
),
|
|
3112
|
+
children: [
|
|
3113
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3114
|
+
"svg",
|
|
3115
|
+
{
|
|
3116
|
+
viewBox: "0 0 24 24",
|
|
3117
|
+
fill: "none",
|
|
3118
|
+
stroke: "currentColor",
|
|
3119
|
+
strokeWidth: "2",
|
|
3120
|
+
strokeLinecap: "round",
|
|
3121
|
+
strokeLinejoin: "round",
|
|
3122
|
+
"aria-hidden": true,
|
|
3123
|
+
className: "h-3 w-3",
|
|
3124
|
+
children: [
|
|
3125
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
3126
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v5l3 2" })
|
|
3127
|
+
]
|
|
3128
|
+
}
|
|
3129
|
+
),
|
|
3130
|
+
"runs on schedule"
|
|
3131
|
+
]
|
|
3132
|
+
}
|
|
3133
|
+
) }),
|
|
3134
|
+
showCapMeter && /* @__PURE__ */ jsxRuntime.jsx(CapMeter, { count: headerCount, cap: lane.cap }),
|
|
3135
|
+
agentPicker && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3136
|
+
LaneAgentPicker,
|
|
3137
|
+
{
|
|
3138
|
+
...agentPicker,
|
|
3139
|
+
canEdit: agentPicker.canEdit ?? canEditHandlers
|
|
3140
|
+
}
|
|
3141
|
+
)
|
|
2772
3142
|
] }),
|
|
2773
3143
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-2 overflow-y-auto p-2", children: [
|
|
2774
3144
|
cards.map((card) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2776,21 +3146,23 @@ function KanbanColumn({
|
|
|
2776
3146
|
{
|
|
2777
3147
|
card,
|
|
2778
3148
|
onClick: onCardClick,
|
|
2779
|
-
selected: card.id === selectedCardId
|
|
3149
|
+
selected: card.id === selectedCardId,
|
|
3150
|
+
dueState: dueStateFor(card, lane, now)
|
|
2780
3151
|
},
|
|
2781
3152
|
card.id
|
|
2782
3153
|
)),
|
|
2783
|
-
cards.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 py-4 text-center text-xs text-
|
|
3154
|
+
cards.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 py-4 text-center text-xs text-muted-foreground", children: "No cards" }),
|
|
2784
3155
|
showCreate && onCreateCard && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2785
3156
|
"button",
|
|
2786
3157
|
{
|
|
2787
3158
|
type: "button",
|
|
2788
3159
|
onClick: () => onCreateCard(lane),
|
|
2789
3160
|
className: cn9(
|
|
2790
|
-
|
|
2791
|
-
"
|
|
2792
|
-
"
|
|
2793
|
-
"
|
|
3161
|
+
// ≥44px touch (M12/F5) — density kept via padding, not height.
|
|
3162
|
+
"mt-1 inline-flex min-h-11 w-full items-center justify-center rounded-lg border border-dashed border-border px-3 py-2",
|
|
3163
|
+
"text-sm font-medium text-muted-foreground",
|
|
3164
|
+
"hover:border-primary/50 hover:text-foreground transition",
|
|
3165
|
+
"focus:outline-none focus:ring-2 focus:ring-ring/40"
|
|
2794
3166
|
),
|
|
2795
3167
|
children: "+ New card"
|
|
2796
3168
|
}
|
|
@@ -2805,14 +3177,14 @@ function SkeletonCard() {
|
|
|
2805
3177
|
"div",
|
|
2806
3178
|
{
|
|
2807
3179
|
className: cn9(
|
|
2808
|
-
"w-full rounded-lg border border-
|
|
2809
|
-
"bg-
|
|
3180
|
+
"w-full rounded-lg border border-border",
|
|
3181
|
+
"bg-card p-3 shadow-sm"
|
|
2810
3182
|
),
|
|
2811
3183
|
"aria-hidden": "true",
|
|
2812
3184
|
children: [
|
|
2813
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-3/4 rounded bg-
|
|
2814
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 h-2.5 w-1/2 rounded bg-
|
|
2815
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 h-4 w-1/3 rounded bg-
|
|
3185
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-3/4 rounded bg-muted" }),
|
|
3186
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 h-2.5 w-1/2 rounded bg-muted" }),
|
|
3187
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 h-4 w-1/3 rounded bg-muted" })
|
|
2816
3188
|
]
|
|
2817
3189
|
}
|
|
2818
3190
|
);
|
|
@@ -2823,14 +3195,14 @@ function SkeletonColumn({ cardCount }) {
|
|
|
2823
3195
|
{
|
|
2824
3196
|
className: cn9(
|
|
2825
3197
|
"flex w-72 shrink-0 flex-col rounded-xl",
|
|
2826
|
-
"bg-
|
|
2827
|
-
"border border-
|
|
3198
|
+
"bg-muted/40",
|
|
3199
|
+
"border border-border"
|
|
2828
3200
|
),
|
|
2829
3201
|
"aria-hidden": "true",
|
|
2830
3202
|
children: [
|
|
2831
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2.5 border-b border-
|
|
2832
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-24 rounded bg-
|
|
2833
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-6 rounded-full bg-
|
|
3203
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2.5 border-b border-border", children: [
|
|
3204
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-24 rounded bg-muted" }),
|
|
3205
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-6 rounded-full bg-muted" })
|
|
2834
3206
|
] }),
|
|
2835
3207
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col gap-2 p-2", children: Array.from({ length: cardCount }).map((_, i) => (
|
|
2836
3208
|
// eslint-disable-next-line react/no-array-index-key
|
|
@@ -2859,6 +3231,67 @@ function KanbanBoardSkeleton({
|
|
|
2859
3231
|
}
|
|
2860
3232
|
);
|
|
2861
3233
|
}
|
|
3234
|
+
function formatCountdown(nextTickAt) {
|
|
3235
|
+
if (!nextTickAt) return null;
|
|
3236
|
+
const target = Date.parse(nextTickAt);
|
|
3237
|
+
if (Number.isNaN(target)) return null;
|
|
3238
|
+
const ms = target - Date.now();
|
|
3239
|
+
if (ms <= 0) return "any moment";
|
|
3240
|
+
const mins = Math.round(ms / 6e4);
|
|
3241
|
+
if (mins < 1) return "under a minute";
|
|
3242
|
+
if (mins < 60) return `${mins}m`;
|
|
3243
|
+
const hrs = Math.floor(mins / 60);
|
|
3244
|
+
const rem = mins % 60;
|
|
3245
|
+
return rem > 0 ? `${hrs}h ${rem}m` : `${hrs}h`;
|
|
3246
|
+
}
|
|
3247
|
+
var DOT_TONE = {
|
|
3248
|
+
"on-schedule": "bg-success",
|
|
3249
|
+
due: "bg-info",
|
|
3250
|
+
paused: "bg-muted-foreground"
|
|
3251
|
+
};
|
|
3252
|
+
var DEFAULT_LABEL = {
|
|
3253
|
+
"on-schedule": "On schedule",
|
|
3254
|
+
due: "Running now",
|
|
3255
|
+
paused: "Paused"
|
|
3256
|
+
};
|
|
3257
|
+
function ScheduleStatus({
|
|
3258
|
+
nextTickAt,
|
|
3259
|
+
dueByLane,
|
|
3260
|
+
label,
|
|
3261
|
+
tone = "on-schedule",
|
|
3262
|
+
className
|
|
3263
|
+
}) {
|
|
3264
|
+
const countdown = formatCountdown(nextTickAt);
|
|
3265
|
+
const totalDue = dueByLane ? Object.values(dueByLane).reduce((a, b) => a + b, 0) : 0;
|
|
3266
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3267
|
+
"div",
|
|
3268
|
+
{
|
|
3269
|
+
className: cn9(
|
|
3270
|
+
"flex items-center gap-2 text-xs text-muted-foreground",
|
|
3271
|
+
className
|
|
3272
|
+
),
|
|
3273
|
+
children: [
|
|
3274
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3275
|
+
"span",
|
|
3276
|
+
{
|
|
3277
|
+
"aria-hidden": true,
|
|
3278
|
+
className: cn9("h-2 w-2 shrink-0 rounded-full", DOT_TONE[tone])
|
|
3279
|
+
}
|
|
3280
|
+
),
|
|
3281
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: label ?? DEFAULT_LABEL[tone] }),
|
|
3282
|
+
countdown && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
|
|
3283
|
+
"\xB7 next run in ",
|
|
3284
|
+
countdown
|
|
3285
|
+
] }),
|
|
3286
|
+
totalDue > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
|
|
3287
|
+
"\xB7 ",
|
|
3288
|
+
totalDue,
|
|
3289
|
+
" due"
|
|
3290
|
+
] })
|
|
3291
|
+
]
|
|
3292
|
+
}
|
|
3293
|
+
);
|
|
3294
|
+
}
|
|
2862
3295
|
function KanbanBoard({
|
|
2863
3296
|
adapter,
|
|
2864
3297
|
onCreateCard,
|
|
@@ -2869,6 +3302,11 @@ function KanbanBoard({
|
|
|
2869
3302
|
enableEdit = true,
|
|
2870
3303
|
enableAdvance = true,
|
|
2871
3304
|
pollIntervalMs,
|
|
3305
|
+
laneCounts,
|
|
3306
|
+
canEditHandlers,
|
|
3307
|
+
laneAgentPicker,
|
|
3308
|
+
scheduleStatus,
|
|
3309
|
+
focusCardId,
|
|
2872
3310
|
className
|
|
2873
3311
|
}) {
|
|
2874
3312
|
const {
|
|
@@ -2885,6 +3323,16 @@ function KanbanBoard({
|
|
|
2885
3323
|
transitionCard,
|
|
2886
3324
|
handleRunTerminal
|
|
2887
3325
|
} = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
|
|
3326
|
+
const lastFocusedRef = react.useRef(void 0);
|
|
3327
|
+
react.useEffect(() => {
|
|
3328
|
+
if (!focusCardId) {
|
|
3329
|
+
lastFocusedRef.current = void 0;
|
|
3330
|
+
return;
|
|
3331
|
+
}
|
|
3332
|
+
if (lastFocusedRef.current === focusCardId) return;
|
|
3333
|
+
lastFocusedRef.current = focusCardId;
|
|
3334
|
+
void openCard(focusCardId);
|
|
3335
|
+
}, [focusCardId]);
|
|
2888
3336
|
const handleCardClick = react.useCallback(
|
|
2889
3337
|
(card) => {
|
|
2890
3338
|
void openCard(card.id);
|
|
@@ -2921,10 +3369,11 @@ function KanbanBoard({
|
|
|
2921
3369
|
const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
|
|
2922
3370
|
const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
|
|
2923
3371
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn9("flex h-full w-full flex-col", className), children: [
|
|
2924
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "m-3 rounded-md border border-
|
|
3372
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "m-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: error }),
|
|
3373
|
+
scheduleStatus && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-b border-border px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(ScheduleStatus, { ...scheduleStatus }) }),
|
|
2925
3374
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
2926
3375
|
lanes.length === 0 && isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KanbanBoardSkeleton, { className: "flex-1 overflow-x-auto p-4" }) : /* @__PURE__ */ jsxRuntime.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: [
|
|
2927
|
-
lanes.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-
|
|
3376
|
+
lanes.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No lanes configured." }),
|
|
2928
3377
|
lanes.map((lane) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2929
3378
|
KanbanColumn,
|
|
2930
3379
|
{
|
|
@@ -2933,7 +3382,10 @@ function KanbanBoard({
|
|
|
2933
3382
|
onCardClick: handleCardClick,
|
|
2934
3383
|
selectedCardId: selectedCard?.id,
|
|
2935
3384
|
onCreateCard: handleCreate,
|
|
2936
|
-
showCreate: enableCreate && lane.key === initialLaneKey
|
|
3385
|
+
showCreate: enableCreate && lane.key === initialLaneKey,
|
|
3386
|
+
count: laneCounts?.[lane.key],
|
|
3387
|
+
agentPicker: laneAgentPicker?.(lane),
|
|
3388
|
+
canEditHandlers
|
|
2937
3389
|
},
|
|
2938
3390
|
lane.id ?? lane.key
|
|
2939
3391
|
))
|
|
@@ -3675,15 +4127,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
3675
4127
|
sseClient = null;
|
|
3676
4128
|
status = "connecting";
|
|
3677
4129
|
reconnectAttempts = 0;
|
|
3678
|
-
// CAD-39 / webchat dual-plane create-connect race. `hasConnected` flips true on
|
|
3679
|
-
// the first successful SSE open; `notFoundRetries` bounds retries of a 404
|
|
3680
|
-
// encountered BEFORE we ever connect (the run row is persisted slightly AFTER
|
|
3681
|
-
// the client opens the stream — the norm on the webchat path where msg-api owns
|
|
3682
|
-
// the executionId and cadra persists the agent_executions row via an async
|
|
3683
|
-
// worker callback). See handleConnectionError.
|
|
3684
|
-
hasConnected = false;
|
|
3685
|
-
notFoundRetries = 0;
|
|
3686
|
-
maxConnectRaceRetries = 3;
|
|
3687
4130
|
seenEventIds = /* @__PURE__ */ new Set();
|
|
3688
4131
|
_lastEventId = null;
|
|
3689
4132
|
activityTimeoutId = null;
|
|
@@ -3823,8 +4266,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
3823
4266
|
if (connected) {
|
|
3824
4267
|
this.status = "connected";
|
|
3825
4268
|
this.reconnectAttempts = 0;
|
|
3826
|
-
this.hasConnected = true;
|
|
3827
|
-
this.notFoundRetries = 0;
|
|
3828
4269
|
this.resetActivityTimeout();
|
|
3829
4270
|
}
|
|
3830
4271
|
this.emit("connectionChange", { connected, usingFallback: false });
|
|
@@ -4114,38 +4555,6 @@ var ExecutionStreamControllerImpl = class {
|
|
|
4114
4555
|
return;
|
|
4115
4556
|
}
|
|
4116
4557
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4117
|
-
const isNotFound = /\b404\b/.test(msg);
|
|
4118
|
-
const isAuthFailure = /\b40[13]\b/.test(msg) || /INVALID_API_KEY|INVALID_REQUEST/.test(msg);
|
|
4119
|
-
if (isNotFound && !isAuthFailure && !this.hasConnected) {
|
|
4120
|
-
if (this.notFoundRetries < this.maxConnectRaceRetries) {
|
|
4121
|
-
this.notFoundRetries++;
|
|
4122
|
-
this.status = "reconnecting";
|
|
4123
|
-
const delay = Math.min(
|
|
4124
|
-
this.config.reconnectBaseDelayMs * this.notFoundRetries,
|
|
4125
|
-
this.config.reconnectMaxDelayMs
|
|
4126
|
-
);
|
|
4127
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
4128
|
-
if (this.status === "closed") {
|
|
4129
|
-
return;
|
|
4130
|
-
}
|
|
4131
|
-
try {
|
|
4132
|
-
await this.connectSSE();
|
|
4133
|
-
} catch (retryError) {
|
|
4134
|
-
await this.handleConnectionError(retryError);
|
|
4135
|
-
}
|
|
4136
|
-
return;
|
|
4137
|
-
}
|
|
4138
|
-
if (this.pollingEnabled) {
|
|
4139
|
-
if (this.sseClient) {
|
|
4140
|
-
this.sseClient.disconnect();
|
|
4141
|
-
this.sseClient = null;
|
|
4142
|
-
}
|
|
4143
|
-
this.status = "fallback_polling";
|
|
4144
|
-
this.emit("connectionChange", { connected: false, usingFallback: true });
|
|
4145
|
-
this.startPolling();
|
|
4146
|
-
return;
|
|
4147
|
-
}
|
|
4148
|
-
}
|
|
4149
4558
|
if (/\b4\d\d\b/.test(msg) || /INVALID_API_KEY|INVALID_REQUEST/.test(msg)) {
|
|
4150
4559
|
if (this.sseClient) {
|
|
4151
4560
|
this.sseClient.disconnect();
|
|
@@ -4395,6 +4804,7 @@ var AgentsAPI = class extends BaseResourceAPI {
|
|
|
4395
4804
|
super(http, "/api/v1/agents");
|
|
4396
4805
|
this.getStreamConfig = getStreamConfig;
|
|
4397
4806
|
}
|
|
4807
|
+
getStreamConfig;
|
|
4398
4808
|
// ===== LIST Operations =====
|
|
4399
4809
|
/**
|
|
4400
4810
|
* List all agents in the organization
|
|
@@ -5300,6 +5710,7 @@ var SessionsAPI = class extends BaseResourceAPI {
|
|
|
5300
5710
|
super(http, "/api/v1/sessions");
|
|
5301
5711
|
this.getStreamConfig = getStreamConfig;
|
|
5302
5712
|
}
|
|
5713
|
+
getStreamConfig;
|
|
5303
5714
|
// ===== LIST Operations =====
|
|
5304
5715
|
/**
|
|
5305
5716
|
* List all sessions in the organization
|
|
@@ -5619,6 +6030,7 @@ var KanbanAPI = class extends BaseResourceAPI {
|
|
|
5619
6030
|
super(http, "/api/v1/kanban");
|
|
5620
6031
|
this.getStreamConfig = getStreamConfig;
|
|
5621
6032
|
}
|
|
6033
|
+
getStreamConfig;
|
|
5622
6034
|
// ===== BOARD =====
|
|
5623
6035
|
/**
|
|
5624
6036
|
* Get the current org's board (lanes in declared order). Auto-provisions
|
|
@@ -5820,6 +6232,7 @@ var RemoteAgentsAPI = class extends BaseResourceAPI {
|
|
|
5820
6232
|
super(http, "/api/v1/remote-agents");
|
|
5821
6233
|
this.getStreamConfig = getStreamConfig;
|
|
5822
6234
|
}
|
|
6235
|
+
getStreamConfig;
|
|
5823
6236
|
/**
|
|
5824
6237
|
* List all remote agents in the organization
|
|
5825
6238
|
*
|
|
@@ -6196,12 +6609,18 @@ function createDefaultKanbanAdapter(config) {
|
|
|
6196
6609
|
exports.AgentBoard = AgentBoard;
|
|
6197
6610
|
exports.BoardConfigClient = BoardConfigClient;
|
|
6198
6611
|
exports.CadraLifecycleSource = CadraLifecycleSource;
|
|
6612
|
+
exports.CapMeter = CapMeter;
|
|
6199
6613
|
exports.CardDrawer = CardDrawer;
|
|
6200
6614
|
exports.KanbanBoard = KanbanBoard;
|
|
6201
6615
|
exports.KanbanCardTile = KanbanCard;
|
|
6202
6616
|
exports.KanbanColumn = KanbanColumn;
|
|
6617
|
+
exports.LaneAgentPicker = LaneAgentPicker;
|
|
6618
|
+
exports.ScheduleStatus = ScheduleStatus;
|
|
6619
|
+
exports.badgeVariantClass = badgeVariantClass;
|
|
6620
|
+
exports.cn = cn9;
|
|
6203
6621
|
exports.createDefaultKanbanAdapter = createDefaultKanbanAdapter;
|
|
6204
6622
|
exports.mapDefinitionToBoard = mapDefinitionToBoard;
|
|
6623
|
+
exports.runStatusTone = runStatusTone;
|
|
6205
6624
|
exports.toResolvedLifecycle = toResolvedLifecycle;
|
|
6206
6625
|
exports.useCardRun = useCardRun;
|
|
6207
6626
|
exports.useKanbanBoard = useKanbanBoard;
|