@lumea-labs/orchestrator 0.1.0

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.
Files changed (46) hide show
  1. package/README.md +21 -0
  2. package/dist/index.d.ts +21 -0
  3. package/dist/index.js +93 -0
  4. package/dist/lib/format.d.ts +3 -0
  5. package/dist/lib/format.js +9 -0
  6. package/dist/orchestrator-document.d.ts +37 -0
  7. package/dist/orchestrator-document.js +122 -0
  8. package/dist/plan-detail.d.ts +102 -0
  9. package/dist/plan-detail.js +385 -0
  10. package/dist/plan-graph.d.ts +39 -0
  11. package/dist/plan-graph.js +597 -0
  12. package/dist/plan-node-detail.d.ts +29 -0
  13. package/dist/plan-node-detail.js +346 -0
  14. package/dist/plan-task-detail.d.ts +76 -0
  15. package/dist/plan-task-detail.js +450 -0
  16. package/dist/plan-types.d.ts +85 -0
  17. package/dist/plan-types.js +51 -0
  18. package/dist/run-kanban-filter-menu.d.ts +24 -0
  19. package/dist/run-kanban-filter-menu.js +152 -0
  20. package/dist/run-kanban.d.ts +61 -0
  21. package/dist/run-kanban.js +234 -0
  22. package/dist/swarm-agent-badge.d.ts +15 -0
  23. package/dist/swarm-agent-badge.js +39 -0
  24. package/dist/swarm-run-activity.d.ts +39 -0
  25. package/dist/swarm-run-activity.js +289 -0
  26. package/dist/swarm-run-card.d.ts +22 -0
  27. package/dist/swarm-run-card.js +91 -0
  28. package/dist/swarm-run-detail.d.ts +45 -0
  29. package/dist/swarm-run-detail.js +559 -0
  30. package/dist/swarm-run-list.d.ts +22 -0
  31. package/dist/swarm-run-list.js +75 -0
  32. package/dist/swarm-run-row.d.ts +22 -0
  33. package/dist/swarm-run-row.js +125 -0
  34. package/dist/swarm-skeletons.d.ts +28 -0
  35. package/dist/swarm-skeletons.js +78 -0
  36. package/dist/swarm-status-bar.d.ts +15 -0
  37. package/dist/swarm-status-bar.js +79 -0
  38. package/dist/swarm-status-pill.d.ts +12 -0
  39. package/dist/swarm-status-pill.js +86 -0
  40. package/dist/swarm-timeline.d.ts +21 -0
  41. package/dist/swarm-timeline.js +414 -0
  42. package/dist/task-workspace-sidebar.d.ts +71 -0
  43. package/dist/task-workspace-sidebar.js +352 -0
  44. package/dist/types.d.ts +285 -0
  45. package/dist/types.js +44 -0
  46. package/package.json +41 -0
@@ -0,0 +1,125 @@
1
+ "use client";
2
+ import { RotateCcw, Square } from "lucide-react";
3
+ import {
4
+ defaultSwarmLabels
5
+ } from "./types";
6
+ import { elapsedSeconds } from "./lib/format";
7
+ const DOT = {
8
+ scheduled: "bg-[#7B3FE4]",
9
+ pending: "bg-p-ink-3",
10
+ running: "bg-p-accent",
11
+ review: "bg-[#2B44FF]",
12
+ done: "bg-p-green",
13
+ failed: "bg-[#E63946]",
14
+ cancelled: "bg-p-ink-3/50"
15
+ };
16
+ function SwarmRunRow({
17
+ run,
18
+ now,
19
+ renderAvatar,
20
+ onCancel,
21
+ onRetry,
22
+ onOpen,
23
+ active,
24
+ labels,
25
+ className
26
+ }) {
27
+ const L = { ...defaultSwarmLabels, ...labels };
28
+ const clock = now ?? Date.now();
29
+ const elapsed = elapsedSeconds(run.startedAt, run.finishedAt, clock);
30
+ const isLive = run.status === "running" || run.status === "pending";
31
+ const showCancel = onCancel && isLive;
32
+ const showRetry = onRetry && (run.status === "failed" || run.status === "cancelled");
33
+ const glyph = run.agent.glyph || (run.agent.displayName || run.agent.name).charAt(0).toUpperCase();
34
+ return /* @__PURE__ */ React.createElement(
35
+ "div",
36
+ {
37
+ role: onOpen ? "button" : void 0,
38
+ tabIndex: onOpen ? 0 : void 0,
39
+ onClick: onOpen ? () => onOpen(run.id) : void 0,
40
+ onKeyDown: onOpen ? (e) => {
41
+ if (e.key === "Enter" || e.key === " ") {
42
+ e.preventDefault();
43
+ onOpen(run.id);
44
+ }
45
+ } : void 0,
46
+ className: [
47
+ "group relative flex items-center gap-3 border-b border-p-line/70 px-3 py-1.5 transition-colors",
48
+ active ? "bg-p-warm" : onOpen ? "cursor-pointer hover:bg-p-warm/60" : "",
49
+ className || ""
50
+ ].join(" ")
51
+ },
52
+ /* @__PURE__ */ React.createElement("span", { className: "relative inline-flex size-2 shrink-0" }, /* @__PURE__ */ React.createElement(
53
+ "span",
54
+ {
55
+ "aria-hidden": true,
56
+ className: [
57
+ "absolute inset-0 rounded-full",
58
+ DOT[run.status],
59
+ run.status === "running" ? "animate-ping opacity-60" : ""
60
+ ].join(" ")
61
+ }
62
+ ), /* @__PURE__ */ React.createElement(
63
+ "span",
64
+ {
65
+ "aria-hidden": true,
66
+ className: ["relative inline-block size-2 rounded-full", DOT[run.status]].join(" ")
67
+ }
68
+ )),
69
+ renderAvatar ? renderAvatar(run.agent) : /* @__PURE__ */ React.createElement(
70
+ "span",
71
+ {
72
+ "aria-hidden": true,
73
+ className: "grid size-[18px] shrink-0 place-items-center rounded font-display text-[10px] font-bold text-white",
74
+ style: { background: run.agent.color || "#999" }
75
+ },
76
+ glyph
77
+ ),
78
+ /* @__PURE__ */ React.createElement("span", { className: "w-[68px] shrink-0 truncate font-mono text-[10.5px] font-bold uppercase tracking-[0.14em] text-p-ink" }, run.agent.displayName || run.agent.name),
79
+ /* @__PURE__ */ React.createElement("span", { className: "min-w-0 flex-1 truncate font-body text-[12.5px] leading-tight text-p-ink" }, run.title),
80
+ run.lastLog ? /* @__PURE__ */ React.createElement("span", { className: "hidden min-w-0 max-w-[28%] truncate font-mono text-[10.5px] text-p-ink-3 md:inline" }, run.lastLog) : null,
81
+ /* @__PURE__ */ React.createElement("span", { className: "w-12 shrink-0 text-right font-mono text-[10.5px] tabular-nums text-p-ink-3" }, run.startedAt ? isLive ? L.startedAgo(elapsed) : L.duration(elapsed) : "\u2014"),
82
+ /* @__PURE__ */ React.createElement("span", { className: "w-14 shrink-0 text-right" }, showCancel ? /* @__PURE__ */ React.createElement(
83
+ "button",
84
+ {
85
+ type: "button",
86
+ onClick: (e) => {
87
+ e.stopPropagation();
88
+ onCancel(run.id);
89
+ },
90
+ className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 font-mono text-[10px] font-bold uppercase tracking-[0.12em] text-p-ink-3 opacity-0 transition-all cursor-pointer group-hover:opacity-100 hover:bg-p-surface hover:text-[#E63946]"
91
+ },
92
+ /* @__PURE__ */ React.createElement(Square, { className: "size-2.5" }),
93
+ L.cancel
94
+ ) : showRetry ? /* @__PURE__ */ React.createElement(
95
+ "button",
96
+ {
97
+ type: "button",
98
+ onClick: (e) => {
99
+ e.stopPropagation();
100
+ onRetry(run.id);
101
+ },
102
+ className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 font-mono text-[10px] font-bold uppercase tracking-[0.12em] text-p-ink-3 opacity-0 transition-all cursor-pointer group-hover:opacity-100 hover:bg-p-surface hover:text-p-ink"
103
+ },
104
+ /* @__PURE__ */ React.createElement(RotateCcw, { className: "size-2.5" }),
105
+ L.retry
106
+ ) : null),
107
+ run.progress !== void 0 && isLive ? /* @__PURE__ */ React.createElement(
108
+ "span",
109
+ {
110
+ "aria-hidden": true,
111
+ className: "absolute inset-x-0 bottom-0 h-px bg-p-warm"
112
+ },
113
+ /* @__PURE__ */ React.createElement(
114
+ "span",
115
+ {
116
+ className: "block h-full bg-p-accent transition-[width] duration-500",
117
+ style: { width: `${Math.max(0, Math.min(100, run.progress * 100))}%` }
118
+ }
119
+ )
120
+ ) : null
121
+ );
122
+ }
123
+ export {
124
+ SwarmRunRow
125
+ };
@@ -0,0 +1,28 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * Skeleton loaders for orchestrator surfaces — mirror the layout of
5
+ * `<SwarmRunDetail/>` and `<SwarmRunActivityStream/>` so the loading
6
+ * state feels native rather than a generic spinner.
7
+ *
8
+ * Pattern stolen from `@lumea/chat`'s ChatSkeleton: a `<Bone/>` primitive
9
+ * + composed silhouettes of the real components. Pure presentation, no
10
+ * data dependencies — drop in while the SwarmRun is fetching.
11
+ */
12
+ interface SwarmRunDetailSkeletonProps {
13
+ /** Mirror the variant prop of `<SwarmRunDetail/>` so the silhouette
14
+ * matches the consumer's chosen layout. Default `"tabs"`. */
15
+ variant?: "tabs" | "flat";
16
+ /** Hide the tools row so the silhouette matches `hideTools` consumers. */
17
+ hideTools?: boolean;
18
+ className?: string;
19
+ }
20
+ declare function SwarmRunDetailSkeleton({ variant, hideTools, className, }: SwarmRunDetailSkeletonProps): react.JSX.Element;
21
+ interface SwarmRunActivityStreamSkeletonProps {
22
+ /** How many event rows to fake. Default `4`. */
23
+ count?: number;
24
+ className?: string;
25
+ }
26
+ declare function SwarmRunActivityStreamSkeleton({ count, className, }: SwarmRunActivityStreamSkeletonProps): react.JSX.Element;
27
+
28
+ export { SwarmRunActivityStreamSkeleton, type SwarmRunActivityStreamSkeletonProps, SwarmRunDetailSkeleton, type SwarmRunDetailSkeletonProps };
@@ -0,0 +1,78 @@
1
+ function Bone({
2
+ width,
3
+ height = 14,
4
+ rounded
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "div",
8
+ {
9
+ className: "bg-p-warm animate-pulse",
10
+ style: {
11
+ width,
12
+ height,
13
+ borderRadius: rounded === "full" ? 9999 : rounded ?? (height > 20 ? 8 : 4)
14
+ }
15
+ }
16
+ );
17
+ }
18
+ function SwarmRunDetailSkeleton({
19
+ variant = "tabs",
20
+ hideTools = false,
21
+ className
22
+ }) {
23
+ return /* @__PURE__ */ React.createElement(
24
+ "section",
25
+ {
26
+ "aria-busy": true,
27
+ "aria-label": "Loading run",
28
+ className: [
29
+ "flex h-full min-h-0 flex-col overflow-hidden rounded-2xl border border-p-line bg-p-surface",
30
+ className || ""
31
+ ].join(" ")
32
+ },
33
+ /* @__PURE__ */ React.createElement("header", { className: "flex shrink-0 items-center gap-2 border-b border-p-line px-4 py-3" }, /* @__PURE__ */ React.createElement("div", { className: "size-6 shrink-0 rounded-md bg-p-warm animate-pulse" }), /* @__PURE__ */ React.createElement(Bone, { width: "9rem", height: 13 }), /* @__PURE__ */ React.createElement("span", { className: "ml-auto inline-flex items-center gap-1" }, /* @__PURE__ */ React.createElement(Bone, { width: 56, height: 20, rounded: 6 }), /* @__PURE__ */ React.createElement("div", { className: "size-7 rounded-md bg-p-warm animate-pulse" }))),
34
+ /* @__PURE__ */ React.createElement("div", { className: "grid shrink-0 grid-cols-4 gap-3 border-b border-p-line px-4 py-3" }, Array.from({ length: 4 }, (_, i) => /* @__PURE__ */ React.createElement("div", { key: i, className: "flex flex-col gap-1.5" }, /* @__PURE__ */ React.createElement(Bone, { width: "3.5rem", height: 9 }), /* @__PURE__ */ React.createElement(Bone, { width: "4.5rem", height: 16 })))),
35
+ /* @__PURE__ */ React.createElement("div", { className: "shrink-0 border-b border-p-line px-4 py-3" }, /* @__PURE__ */ React.createElement(Bone, { width: "2.5rem", height: 9 }), /* @__PURE__ */ React.createElement("div", { className: "mt-2 flex flex-col gap-1.5" }, /* @__PURE__ */ React.createElement(Bone, { width: "92%", height: 14 }), /* @__PURE__ */ React.createElement(Bone, { width: "74%", height: 14 }))),
36
+ variant === "tabs" ? /* @__PURE__ */ React.createElement(TabsBodySkeleton, { hideTools }) : /* @__PURE__ */ React.createElement(FlatBodySkeleton, { hideTools })
37
+ );
38
+ }
39
+ function TabsBodySkeleton({ hideTools }) {
40
+ const tabCount = hideTools ? 2 : 3;
41
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex shrink-0 items-center gap-1 border-b border-p-line px-3 py-2" }, Array.from({ length: tabCount }, (_, i) => /* @__PURE__ */ React.createElement(Bone, { key: i, width: "5rem", height: 20, rounded: 6 }))), /* @__PURE__ */ React.createElement("div", { className: "min-h-0 flex-1 overflow-hidden px-4 py-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React.createElement(Bone, { width: "88%" }), /* @__PURE__ */ React.createElement(Bone, { width: "76%" }), /* @__PURE__ */ React.createElement(Bone, { width: "92%" }), /* @__PURE__ */ React.createElement(Bone, { width: "60%" }), /* @__PURE__ */ React.createElement(Bone, { width: "80%" }))));
42
+ }
43
+ function FlatBodySkeleton({ hideTools }) {
44
+ return /* @__PURE__ */ React.createElement("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 py-4" }, /* @__PURE__ */ React.createElement(FlatSectionSkeleton, { lines: 3 }), !hideTools ? /* @__PURE__ */ React.createElement(FlatSectionSkeleton, { lines: 2, chips: true }) : null, /* @__PURE__ */ React.createElement(FlatSectionSkeleton, { lines: 4 }));
45
+ }
46
+ function FlatSectionSkeleton({
47
+ lines,
48
+ chips
49
+ }) {
50
+ const widths = ["88%", "76%", "92%", "60%", "82%"];
51
+ return /* @__PURE__ */ React.createElement("div", { className: "border-b border-p-line/60 py-3 last:border-0" }, /* @__PURE__ */ React.createElement(Bone, { width: "3.5rem", height: 9 }), /* @__PURE__ */ React.createElement("div", { className: "mt-2 flex flex-col gap-1.5" }, chips ? /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap gap-1.5" }, Array.from({ length: lines * 2 }, (_, i) => /* @__PURE__ */ React.createElement(Bone, { key: i, width: "6rem", height: 22, rounded: 8 }))) : Array.from({ length: lines }, (_, i) => /* @__PURE__ */ React.createElement(Bone, { key: i, width: widths[i % widths.length] }))));
52
+ }
53
+ function SwarmRunActivityStreamSkeleton({
54
+ count = 4,
55
+ className
56
+ }) {
57
+ return /* @__PURE__ */ React.createElement(
58
+ "ol",
59
+ {
60
+ "aria-busy": true,
61
+ "aria-label": "Loading activity",
62
+ className: [
63
+ "flex flex-col divide-y divide-p-line/60",
64
+ className || ""
65
+ ].join(" ")
66
+ },
67
+ Array.from({ length: count }, (_, i) => /* @__PURE__ */ React.createElement(ActivityRowSkeleton, { key: i, index: i }))
68
+ );
69
+ }
70
+ function ActivityRowSkeleton({ index }) {
71
+ const bodyWidths = ["88%", "62%", "94%", "70%", "78%"];
72
+ const showAgent = index % 2 === 0;
73
+ return /* @__PURE__ */ React.createElement("li", { className: "grid grid-cols-[80px_24px_minmax(0,1fr)] items-start gap-3 py-3" }, /* @__PURE__ */ React.createElement(Bone, { width: "3.25rem", height: 9 }), /* @__PURE__ */ React.createElement("div", { className: "mt-1 size-5 rounded-full bg-p-warm animate-pulse" }), /* @__PURE__ */ React.createElement("div", { className: "min-w-0 flex flex-col gap-1.5" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-baseline gap-2" }, /* @__PURE__ */ React.createElement(Bone, { width: "4.5rem", height: 9 }), showAgent ? /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1" }, /* @__PURE__ */ React.createElement("div", { className: "size-3.5 rounded-[3px] bg-p-warm animate-pulse" }), /* @__PURE__ */ React.createElement(Bone, { width: "4rem", height: 9 })) : null), /* @__PURE__ */ React.createElement(Bone, { width: bodyWidths[index % bodyWidths.length], height: 13 }), index % 3 === 0 ? /* @__PURE__ */ React.createElement(Bone, { width: "55%", height: 13 }) : null));
74
+ }
75
+ export {
76
+ SwarmRunActivityStreamSkeleton,
77
+ SwarmRunDetailSkeleton
78
+ };
@@ -0,0 +1,15 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SwarmCounts, SwarmLabels } from './types.js';
4
+
5
+ interface SwarmStatusBarProps {
6
+ counts: SwarmCounts;
7
+ onCancelAll?: () => void;
8
+ onRetryFailed?: () => void;
9
+ trailing?: ReactNode;
10
+ labels?: Partial<SwarmLabels>;
11
+ className?: string;
12
+ }
13
+ declare function SwarmStatusBar({ counts, onCancelAll, onRetryFailed, trailing, labels, className, }: SwarmStatusBarProps): react.JSX.Element;
14
+
15
+ export { SwarmStatusBar, type SwarmStatusBarProps };
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { RotateCcw, Square } from "lucide-react";
3
+ import {
4
+ defaultSwarmLabels
5
+ } from "./types";
6
+ function SwarmStatusBar({
7
+ counts,
8
+ onCancelAll,
9
+ onRetryFailed,
10
+ trailing,
11
+ labels,
12
+ className
13
+ }) {
14
+ const L = { ...defaultSwarmLabels, ...labels };
15
+ const showCancelAll = onCancelAll && counts.running + counts.pending > 0;
16
+ const showRetryFailed = onRetryFailed && counts.failed > 0;
17
+ return /* @__PURE__ */ React.createElement(
18
+ "div",
19
+ {
20
+ className: [
21
+ "flex flex-wrap items-center gap-3 rounded-xl border border-p-line bg-p-surface px-4 py-2.5",
22
+ className || ""
23
+ ].join(" ")
24
+ },
25
+ /* @__PURE__ */ React.createElement(Stat, { label: L.running, value: counts.running, tone: "accent", pulse: counts.running > 0 }),
26
+ /* @__PURE__ */ React.createElement("span", { className: "h-4 w-px bg-p-line" }),
27
+ /* @__PURE__ */ React.createElement(Stat, { label: L.done, value: counts.done, tone: "green" }),
28
+ /* @__PURE__ */ React.createElement("span", { className: "h-4 w-px bg-p-line" }),
29
+ /* @__PURE__ */ React.createElement(Stat, { label: L.failed, value: counts.failed, tone: "red" }),
30
+ /* @__PURE__ */ React.createElement("span", { className: "ml-auto inline-flex items-center gap-1.5" }, showCancelAll ? /* @__PURE__ */ React.createElement(
31
+ "button",
32
+ {
33
+ type: "button",
34
+ onClick: onCancelAll,
35
+ className: "inline-flex items-center gap-1 rounded-md px-2 py-1 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-[#E63946]"
36
+ },
37
+ /* @__PURE__ */ React.createElement(Square, { className: "size-2.5" }),
38
+ L.cancelAll
39
+ ) : null, showRetryFailed ? /* @__PURE__ */ React.createElement(
40
+ "button",
41
+ {
42
+ type: "button",
43
+ onClick: onRetryFailed,
44
+ className: "inline-flex items-center gap-1 rounded-md px-2 py-1 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-p-ink"
45
+ },
46
+ /* @__PURE__ */ React.createElement(RotateCcw, { className: "size-2.5" }),
47
+ L.retryFailed
48
+ ) : null, trailing)
49
+ );
50
+ }
51
+ function Stat({
52
+ label,
53
+ value,
54
+ tone,
55
+ pulse
56
+ }) {
57
+ const fg = tone === "accent" ? "text-p-accent" : tone === "green" ? "text-p-green" : "text-[#E63946]";
58
+ const dot = tone === "accent" ? "bg-p-accent" : tone === "green" ? "bg-p-green" : "bg-[#E63946]";
59
+ return /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1.5" }, /* @__PURE__ */ React.createElement("span", { className: "relative inline-flex size-2 shrink-0" }, pulse ? /* @__PURE__ */ React.createElement(
60
+ "span",
61
+ {
62
+ className: [
63
+ "absolute inset-0 rounded-full opacity-60",
64
+ dot,
65
+ "animate-ping"
66
+ ].join(" "),
67
+ "aria-hidden": true
68
+ }
69
+ ) : null, /* @__PURE__ */ React.createElement(
70
+ "span",
71
+ {
72
+ className: ["relative inline-block size-2 rounded-full", dot].join(" "),
73
+ "aria-hidden": true
74
+ }
75
+ )), /* @__PURE__ */ React.createElement("span", { className: ["font-display text-[14px] font-bold tabular-nums", fg].join(" ") }, value), /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.18em] text-p-ink-3" }, label));
76
+ }
77
+ export {
78
+ SwarmStatusBar
79
+ };
@@ -0,0 +1,12 @@
1
+ import * as react from 'react';
2
+ import { SwarmRunStatus } from './types.js';
3
+
4
+ interface SwarmStatusPillProps {
5
+ status: SwarmRunStatus;
6
+ label?: string;
7
+ size?: "sm" | "md";
8
+ className?: string;
9
+ }
10
+ declare function SwarmStatusPill({ status, label, size, className, }: SwarmStatusPillProps): react.JSX.Element;
11
+
12
+ export { SwarmStatusPill, type SwarmStatusPillProps };
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import {
3
+ CalendarClock,
4
+ CheckCircle2,
5
+ Circle,
6
+ Loader2,
7
+ Pause,
8
+ Scale,
9
+ XCircle
10
+ } from "lucide-react";
11
+ const TONE = {
12
+ scheduled: {
13
+ fg: "text-[#7B3FE4]",
14
+ bg: "bg-[#F3EEFF]",
15
+ ring: "ring-[#7B3FE4]/30"
16
+ },
17
+ pending: { fg: "text-p-ink-3", bg: "bg-p-warm", ring: "ring-p-line" },
18
+ running: {
19
+ fg: "text-p-accent",
20
+ bg: "bg-p-accent-light",
21
+ ring: "ring-p-accent/30"
22
+ },
23
+ review: {
24
+ fg: "text-[#2B44FF]",
25
+ bg: "bg-[#EEF2FF]",
26
+ ring: "ring-[#2B44FF]/30"
27
+ },
28
+ done: {
29
+ fg: "text-p-green",
30
+ bg: "bg-p-green-light",
31
+ ring: "ring-p-green/30"
32
+ },
33
+ failed: {
34
+ fg: "text-[#E63946]",
35
+ bg: "bg-[#FEF2F2]",
36
+ ring: "ring-[#E63946]/30"
37
+ },
38
+ cancelled: { fg: "text-p-ink-3", bg: "bg-p-warm", ring: "ring-p-line" }
39
+ };
40
+ const ICON = {
41
+ scheduled: CalendarClock,
42
+ pending: Pause,
43
+ running: Loader2,
44
+ review: Scale,
45
+ done: CheckCircle2,
46
+ failed: XCircle,
47
+ cancelled: Circle
48
+ };
49
+ function SwarmStatusPill({
50
+ status,
51
+ label,
52
+ size = "md",
53
+ className
54
+ }) {
55
+ const Icon = ICON[status];
56
+ const tone = TONE[status];
57
+ const text = label ?? status;
58
+ const px = size === "sm" ? "px-1.5 py-[1px]" : "px-2 py-0.5";
59
+ const txt = size === "sm" ? "text-[9.5px]" : "text-[10px]";
60
+ const icon = size === "sm" ? "size-2.5" : "size-3";
61
+ return /* @__PURE__ */ React.createElement(
62
+ "span",
63
+ {
64
+ className: [
65
+ "inline-flex items-center gap-1 rounded-full ring-1 font-mono font-bold uppercase tracking-[0.16em]",
66
+ tone.fg,
67
+ tone.bg,
68
+ tone.ring,
69
+ px,
70
+ txt,
71
+ className || ""
72
+ ].join(" ")
73
+ },
74
+ /* @__PURE__ */ React.createElement(
75
+ Icon,
76
+ {
77
+ "aria-hidden": true,
78
+ className: [icon, status === "running" ? "animate-spin" : ""].join(" ")
79
+ }
80
+ ),
81
+ text
82
+ );
83
+ }
84
+ export {
85
+ SwarmStatusPill
86
+ };
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SwarmRun, SwarmLabels } from './types.js';
4
+
5
+ interface SwarmTimelineProps {
6
+ runs: SwarmRun[];
7
+ /** Live clock — pass `state.now` from `useSwarm()` to make active
8
+ * bars extend in real time and the now-cursor advance. */
9
+ now?: number;
10
+ renderAvatar?: (agent: SwarmRun["agent"]) => ReactNode;
11
+ onOpen?: (id: string) => void;
12
+ /** Pixel height per row. Default 32. */
13
+ rowHeight?: number;
14
+ /** Width reserved for the agent + goal label column. Default 264. */
15
+ labelWidth?: number;
16
+ labels?: Partial<SwarmLabels>;
17
+ className?: string;
18
+ }
19
+ declare function SwarmTimeline({ runs, now, renderAvatar, onOpen, rowHeight, labelWidth, labels, className, }: SwarmTimelineProps): react.JSX.Element;
20
+
21
+ export { SwarmTimeline, type SwarmTimelineProps };