@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,289 @@
1
+ "use client";
2
+ import { useState } from "react";
3
+ import {
4
+ AlertTriangle,
5
+ ArrowDown,
6
+ ArrowUp,
7
+ CheckCircle2,
8
+ ChevronDown,
9
+ ChevronUp,
10
+ ExternalLink,
11
+ FileText,
12
+ Hash,
13
+ Image as ImageIcon,
14
+ MessageSquareMore,
15
+ Quote,
16
+ RotateCcw,
17
+ Scale,
18
+ StickyNote,
19
+ Wrench
20
+ } from "lucide-react";
21
+ function buildSwarmRunActivity(run, options = {}) {
22
+ const events = [];
23
+ const startedAt = run.startedAt ?? run.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
24
+ const finishedAt = run.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
25
+ const tools = run.toolCalls ?? [];
26
+ if (tools.length > 0) {
27
+ const start = new Date(startedAt).getTime();
28
+ const end = new Date(finishedAt).getTime();
29
+ const span = Math.max(end - start, 1);
30
+ tools.forEach((tc, i) => {
31
+ const ts = new Date(start + Math.round(span * (i + 1) / (tools.length + 1))).toISOString();
32
+ events.push({
33
+ id: `tool:${tc.id}`,
34
+ ts,
35
+ kind: "tool_call",
36
+ agentName: run.agent?.name,
37
+ tool: {
38
+ id: tc.id,
39
+ name: tc.name,
40
+ state: tc.state,
41
+ arguments: tc.arguments,
42
+ result: tc.result,
43
+ summary: tc.summary
44
+ }
45
+ });
46
+ });
47
+ }
48
+ if (typeof run.retries === "number" && run.retries > 0) {
49
+ const start = new Date(startedAt).getTime();
50
+ const end = new Date(finishedAt).getTime();
51
+ const span = Math.max(end - start, 1);
52
+ for (let i = 1; i <= run.retries; i++) {
53
+ const ts = new Date(start + Math.round(span * i / (run.retries + 1))).toISOString();
54
+ events.push({
55
+ id: `retry:${i}`,
56
+ ts,
57
+ kind: "retry",
58
+ attempt: i,
59
+ agentName: run.agent?.name
60
+ });
61
+ }
62
+ }
63
+ if (run.output) {
64
+ events.push({
65
+ id: "output:final",
66
+ ts: finishedAt,
67
+ kind: "output",
68
+ text: run.output,
69
+ agentName: run.agent?.name
70
+ });
71
+ }
72
+ if (run.error) {
73
+ events.push({
74
+ id: "error:final",
75
+ ts: finishedAt,
76
+ kind: "error",
77
+ message: run.error,
78
+ agentName: run.agent?.name
79
+ });
80
+ }
81
+ for (const a of run.artifacts ?? []) {
82
+ events.push({
83
+ id: `artifact:${a.id}`,
84
+ ts: finishedAt,
85
+ kind: "artifact",
86
+ artifact: a,
87
+ agentName: run.agent?.name
88
+ });
89
+ }
90
+ if (options.extras?.length) events.push(...options.extras);
91
+ events.sort((a, b) => a.ts.localeCompare(b.ts));
92
+ return events;
93
+ }
94
+ function SwarmRunActivityStream({
95
+ events,
96
+ agents,
97
+ renderToolCall,
98
+ renderMarkdown,
99
+ renderEvent,
100
+ peek = 6,
101
+ emptyLabel = "No activity yet.",
102
+ className
103
+ }) {
104
+ const [expanded, setExpanded] = useState(false);
105
+ if (events.length === 0) {
106
+ return /* @__PURE__ */ React.createElement(
107
+ "div",
108
+ {
109
+ className: [
110
+ "px-4 py-6 text-center font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3",
111
+ className || ""
112
+ ].join(" ")
113
+ },
114
+ emptyLabel
115
+ );
116
+ }
117
+ const peekable = events.length > peek;
118
+ const visible = !peekable || expanded ? events : events.slice(events.length - peek);
119
+ const hidden = events.length - visible.length;
120
+ return /* @__PURE__ */ React.createElement("div", { className: className || "" }, peekable && !expanded ? /* @__PURE__ */ React.createElement(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ onClick: () => setExpanded(true),
125
+ className: "mb-2 inline-flex w-full items-center justify-center gap-1 rounded-md border border-dashed border-p-line bg-p-bg/40 py-1.5 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:border-p-ink-3 hover:text-p-ink"
126
+ },
127
+ /* @__PURE__ */ React.createElement(ChevronUp, { className: "size-3" }),
128
+ "show ",
129
+ hidden,
130
+ " earlier event",
131
+ hidden === 1 ? "" : "s"
132
+ ) : null, /* @__PURE__ */ React.createElement("ol", { className: "flex flex-col divide-y divide-p-line/60" }, visible.map((ev) => {
133
+ const custom = renderEvent?.(ev);
134
+ if (custom !== void 0) {
135
+ return /* @__PURE__ */ React.createElement("li", { key: ev.id, className: "py-3" }, custom);
136
+ }
137
+ return /* @__PURE__ */ React.createElement(
138
+ "li",
139
+ {
140
+ key: ev.id,
141
+ className: "grid grid-cols-[80px_24px_minmax(0,1fr)] items-start gap-3 py-3"
142
+ },
143
+ /* @__PURE__ */ React.createElement(TimeGutter, { ts: ev.ts }),
144
+ /* @__PURE__ */ React.createElement(KindGlyph, { kind: ev.kind }),
145
+ /* @__PURE__ */ React.createElement(
146
+ EventBody,
147
+ {
148
+ event: ev,
149
+ agents,
150
+ renderToolCall,
151
+ renderMarkdown
152
+ }
153
+ )
154
+ );
155
+ })), peekable && expanded ? /* @__PURE__ */ React.createElement(
156
+ "button",
157
+ {
158
+ type: "button",
159
+ onClick: () => setExpanded(false),
160
+ className: "mt-2 inline-flex w-full items-center justify-center gap-1 rounded-md border border-dashed border-p-line bg-p-bg/40 py-1.5 font-mono text-[10.5px] font-bold uppercase tracking-[0.16em] text-p-ink-3 transition-colors cursor-pointer hover:border-p-ink-3 hover:text-p-ink"
161
+ },
162
+ /* @__PURE__ */ React.createElement(ChevronDown, { className: "size-3" }),
163
+ "show less"
164
+ ) : null);
165
+ }
166
+ function TimeGutter({ ts }) {
167
+ const t = new Date(ts);
168
+ const hh = String(t.getHours()).padStart(2, "0");
169
+ const mm = String(t.getMinutes()).padStart(2, "0");
170
+ const ss = String(t.getSeconds()).padStart(2, "0");
171
+ return /* @__PURE__ */ React.createElement("span", { className: "pt-0.5 font-mono text-[10.5px] uppercase tracking-[0.16em] text-p-ink-3 tabular-nums" }, hh, ":", mm, ":", ss);
172
+ }
173
+ const KIND_TONE = {
174
+ phase: "text-[#2B44FF]",
175
+ thought: "text-p-ink-3",
176
+ tool_call: "text-p-ink-2",
177
+ ask_user: "text-p-accent",
178
+ user_input: "text-p-ink",
179
+ output: "text-p-ink",
180
+ artifact: "text-p-ink-2",
181
+ error: "text-[#E63946]",
182
+ retry: "text-[#D4A017]",
183
+ checkpoint: "text-[#8A6B0B]",
184
+ score: "text-p-green"
185
+ };
186
+ function KindGlyph({ kind }) {
187
+ const Icon = kind === "phase" ? RotateCcw : kind === "thought" ? Quote : kind === "tool_call" ? Wrench : kind === "ask_user" ? MessageSquareMore : kind === "user_input" ? ArrowDown : kind === "output" ? ArrowUp : kind === "artifact" ? FileText : kind === "error" ? AlertTriangle : kind === "retry" ? RotateCcw : kind === "checkpoint" ? CheckCircle2 : Scale;
188
+ return /* @__PURE__ */ React.createElement(
189
+ "span",
190
+ {
191
+ "aria-hidden": true,
192
+ className: [
193
+ "mt-1 grid size-5 place-items-center rounded-full border border-p-line bg-p-surface",
194
+ KIND_TONE[kind]
195
+ ].join(" ")
196
+ },
197
+ /* @__PURE__ */ React.createElement(Icon, { className: "size-3" })
198
+ );
199
+ }
200
+ function EventBody({
201
+ event,
202
+ agents,
203
+ renderToolCall,
204
+ renderMarkdown
205
+ }) {
206
+ const agent = event.agentName ? agents?.find((a) => a.name === event.agentName) : void 0;
207
+ return /* @__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(
208
+ "span",
209
+ {
210
+ className: [
211
+ "font-mono text-[10px] font-bold uppercase tracking-[0.18em]",
212
+ KIND_TONE[event.kind]
213
+ ].join(" ")
214
+ },
215
+ event.kind.replace(/_/g, " ")
216
+ ), agent ? /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1 font-mono text-[10px] uppercase tracking-[0.14em] text-p-ink-3" }, /* @__PURE__ */ React.createElement(
217
+ "span",
218
+ {
219
+ "aria-hidden": true,
220
+ className: "grid size-3.5 shrink-0 place-items-center rounded-[3px] font-display text-[8.5px] font-bold text-white",
221
+ style: { background: agent.color || "#999" }
222
+ },
223
+ agent.glyph || (agent.displayName ?? agent.name).charAt(0).toUpperCase()
224
+ ), agent.displayName ?? agent.name) : null), /* @__PURE__ */ React.createElement(
225
+ EventContent,
226
+ {
227
+ event,
228
+ renderToolCall,
229
+ renderMarkdown
230
+ }
231
+ ));
232
+ }
233
+ function EventContent({
234
+ event,
235
+ renderToolCall,
236
+ renderMarkdown
237
+ }) {
238
+ switch (event.kind) {
239
+ case "phase":
240
+ return /* @__PURE__ */ React.createElement("p", { className: "font-mono text-[11.5px] uppercase tracking-[0.14em] text-p-ink-2" }, "\u2192 ", event.phase);
241
+ case "thought":
242
+ return /* @__PURE__ */ React.createElement("p", { className: "font-body text-[13px] italic leading-[1.55] text-p-ink-3" }, event.text);
243
+ case "tool_call":
244
+ if (renderToolCall) return /* @__PURE__ */ React.createElement(React.Fragment, null, renderToolCall(event.tool));
245
+ return /* @__PURE__ */ React.createElement("div", { className: "rounded-md border border-p-line bg-p-bg px-2.5 py-1.5" }, /* @__PURE__ */ React.createElement("code", { className: "font-mono text-[11.5px] font-semibold text-p-ink" }, event.tool.name), event.tool.summary ? /* @__PURE__ */ React.createElement("span", { className: "ml-2 truncate font-mono text-[11px] text-p-ink-3" }, event.tool.summary) : null);
246
+ case "ask_user":
247
+ return /* @__PURE__ */ React.createElement("p", { className: "rounded-md border border-p-accent/40 bg-p-accent-light/40 px-3 py-2 font-body text-[13px] leading-[1.55] text-p-ink" }, event.question);
248
+ case "user_input":
249
+ return renderMarkdown ? /* @__PURE__ */ React.createElement("div", null, renderMarkdown(event.text)) : /* @__PURE__ */ React.createElement("p", { className: "font-body text-[13px] leading-[1.55] text-p-ink" }, event.text);
250
+ case "output":
251
+ return renderMarkdown ? /* @__PURE__ */ React.createElement("div", null, renderMarkdown(event.text)) : /* @__PURE__ */ React.createElement("pre", { className: "m-0 whitespace-pre-wrap break-words font-body text-[13px] leading-[1.55] text-p-ink-2" }, event.text);
252
+ case "artifact":
253
+ return /* @__PURE__ */ React.createElement(ArtifactRow, { artifact: event.artifact });
254
+ case "error":
255
+ return /* @__PURE__ */ React.createElement("pre", { className: "m-0 whitespace-pre-wrap break-words font-mono text-[11.5px] leading-relaxed text-[#E63946]" }, event.message);
256
+ case "retry":
257
+ return /* @__PURE__ */ React.createElement("p", { className: "font-mono text-[11.5px] uppercase tracking-[0.14em] text-p-ink-2" }, "attempt ", event.attempt, event.reason ? ` \xB7 ${event.reason}` : null);
258
+ case "checkpoint":
259
+ return /* @__PURE__ */ React.createElement("div", { className: "font-mono text-[11.5px] uppercase tracking-[0.14em] text-p-ink-2" }, /* @__PURE__ */ React.createElement("span", { className: "font-bold" }, event.name), /* @__PURE__ */ React.createElement("span", { className: "ml-2 text-p-ink-3" }, "\xB7 ", event.verdict), event.message ? /* @__PURE__ */ React.createElement("p", { className: "mt-1 normal-case font-body text-[13px] tracking-normal text-p-ink-3" }, event.message) : null);
260
+ case "score": {
261
+ const scale = event.scale ?? { min: 1, max: 5 };
262
+ return /* @__PURE__ */ React.createElement("div", { className: "flex items-baseline gap-2 font-mono text-[11.5px] uppercase tracking-[0.14em]" }, /* @__PURE__ */ React.createElement("span", { className: "text-p-ink-2" }, event.criterion), /* @__PURE__ */ React.createElement("span", { className: "font-display text-[16px] font-bold tabular-nums text-p-ink" }, event.value, /* @__PURE__ */ React.createElement("span", { className: "text-p-ink-3" }, "/", scale.max)), event.reasoning ? /* @__PURE__ */ React.createElement("span", { className: "ml-2 normal-case tracking-normal text-p-ink-3" }, event.reasoning) : null);
263
+ }
264
+ }
265
+ }
266
+ function ArtifactRow({
267
+ artifact
268
+ }) {
269
+ const Icon = artifact.kind === "url" ? ExternalLink : artifact.kind === "image" ? ImageIcon : artifact.kind === "data" ? Hash : artifact.kind === "note" ? StickyNote : FileText;
270
+ const interactive = !!artifact.url;
271
+ const Wrapper = interactive ? "a" : "div";
272
+ return /* @__PURE__ */ React.createElement(
273
+ Wrapper,
274
+ {
275
+ ...interactive ? { href: artifact.url, target: "_blank", rel: "noreferrer noopener" } : {},
276
+ className: [
277
+ "flex items-center gap-2 rounded-md border border-p-line bg-p-surface px-2.5 py-1.5 no-underline",
278
+ interactive ? "cursor-pointer hover:bg-p-warm/40" : ""
279
+ ].join(" ")
280
+ },
281
+ /* @__PURE__ */ React.createElement(Icon, { className: "size-3 shrink-0 text-p-ink-3", "aria-hidden": true }),
282
+ /* @__PURE__ */ React.createElement("span", { className: "min-w-0 flex-1 truncate font-display text-[12.5px] font-semibold text-p-ink" }, artifact.label),
283
+ artifact.path ? /* @__PURE__ */ React.createElement("code", { className: "hidden truncate font-mono text-[10.5px] text-p-ink-3 sm:inline" }, artifact.path) : null
284
+ );
285
+ }
286
+ export {
287
+ SwarmRunActivityStream,
288
+ buildSwarmRunActivity
289
+ };
@@ -0,0 +1,22 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SwarmRun, SwarmLabels } from './types.js';
4
+
5
+ interface SwarmRunCardProps {
6
+ run: SwarmRun;
7
+ /** Live clock — pass `state.now` from `useSwarm()` so the elapsed
8
+ * counter ticks. When omitted, falls back to `Date.now()` per render. */
9
+ now?: number;
10
+ /** Consumer-rendered avatar — overrides the glyph chip. */
11
+ renderAvatar?: (agent: SwarmRun["agent"]) => ReactNode;
12
+ /** Trailing slot for tool-call chips, log streams, custom adornments. */
13
+ bodySlot?: ReactNode;
14
+ onCancel?: (id: string) => void;
15
+ onRetry?: (id: string) => void;
16
+ onOpen?: (id: string) => void;
17
+ labels?: Partial<SwarmLabels>;
18
+ className?: string;
19
+ }
20
+ declare function SwarmRunCard({ run, now, renderAvatar, bodySlot, onCancel, onRetry, onOpen, labels, className, }: SwarmRunCardProps): react.JSX.Element;
21
+
22
+ export { SwarmRunCard, type SwarmRunCardProps };
@@ -0,0 +1,91 @@
1
+ "use client";
2
+ import { RotateCcw, Square } from "lucide-react";
3
+ import { defaultSwarmLabels } from "./types";
4
+ import { elapsedSeconds } from "./lib/format";
5
+ import { SwarmStatusPill } from "./swarm-status-pill";
6
+ import { SwarmAgentBadge } from "./swarm-agent-badge";
7
+ function SwarmRunCard({
8
+ run,
9
+ now,
10
+ renderAvatar,
11
+ bodySlot,
12
+ onCancel,
13
+ onRetry,
14
+ onOpen,
15
+ labels,
16
+ className
17
+ }) {
18
+ const L = { ...defaultSwarmLabels, ...labels };
19
+ const clock = now ?? Date.now();
20
+ const elapsed = elapsedSeconds(run.startedAt, run.finishedAt, clock);
21
+ const isLive = run.status === "running" || run.status === "pending";
22
+ const showCancel = onCancel && (run.status === "running" || run.status === "pending");
23
+ const showRetry = onRetry && (run.status === "failed" || run.status === "cancelled");
24
+ return /* @__PURE__ */ React.createElement(
25
+ "article",
26
+ {
27
+ className: [
28
+ "group relative flex flex-col gap-2 rounded-xl border bg-p-surface p-3 transition-shadow",
29
+ run.status === "running" ? "border-p-accent/40 shadow-[0_0_0_4px_rgba(226,115,61,0.05)]" : run.status === "failed" ? "border-[#E63946]/40" : "border-p-line",
30
+ onOpen ? "cursor-pointer hover:shadow-[0_8px_24px_-16px_rgba(0,0,0,0.18)]" : "",
31
+ className || ""
32
+ ].join(" "),
33
+ onClick: onOpen ? () => onOpen(run.id) : void 0
34
+ },
35
+ /* @__PURE__ */ React.createElement("header", { className: "flex items-start gap-2" }, /* @__PURE__ */ React.createElement(
36
+ SwarmAgentBadge,
37
+ {
38
+ agent: run.agent,
39
+ avatar: renderAvatar?.(run.agent),
40
+ size: "md",
41
+ showName: true
42
+ }
43
+ ), /* @__PURE__ */ React.createElement("span", { className: "ml-auto" }), /* @__PURE__ */ React.createElement(
44
+ SwarmStatusPill,
45
+ {
46
+ status: run.status,
47
+ label: L[run.status],
48
+ size: "sm"
49
+ }
50
+ )),
51
+ /* @__PURE__ */ React.createElement("p", { className: "line-clamp-2 font-body text-[13px] leading-snug text-p-ink-2" }, run.title),
52
+ run.progress !== void 0 && isLive ? /* @__PURE__ */ React.createElement("div", { className: "h-1 w-full overflow-hidden rounded-full bg-p-warm" }, /* @__PURE__ */ React.createElement(
53
+ "div",
54
+ {
55
+ className: "h-full rounded-full bg-p-accent transition-[width] duration-500 ease-out",
56
+ style: { width: `${Math.max(0, Math.min(100, run.progress * 100))}%` }
57
+ }
58
+ )) : null,
59
+ run.lastLog ? /* @__PURE__ */ React.createElement("div", { className: "rounded-md bg-p-bg px-2 py-1 font-mono text-[11px] leading-snug text-p-ink-3 truncate" }, run.lastLog) : null,
60
+ run.error ? /* @__PURE__ */ React.createElement("div", { className: "rounded-md border border-[#E63946]/30 bg-[#FEF2F2] px-2 py-1 font-mono text-[11px] leading-snug text-[#E63946]" }, run.error) : null,
61
+ bodySlot,
62
+ /* @__PURE__ */ React.createElement("footer", { className: "mt-1 flex items-center gap-2 font-mono text-[10px] uppercase tracking-[0.14em] text-p-ink-3" }, /* @__PURE__ */ React.createElement("span", { className: "tabular-nums" }, run.startedAt ? isLive ? L.startedAgo(elapsed) : L.duration(elapsed) : "\u2014"), run.background ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: "text-p-line" }, "\xB7"), /* @__PURE__ */ React.createElement("span", null, L.backgroundGroup)) : null, /* @__PURE__ */ React.createElement("span", { className: "ml-auto inline-flex items-center gap-1.5" }, showCancel ? /* @__PURE__ */ React.createElement(
63
+ "button",
64
+ {
65
+ type: "button",
66
+ onClick: (e) => {
67
+ e.stopPropagation();
68
+ onCancel(run.id);
69
+ },
70
+ className: "inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-[#E63946]"
71
+ },
72
+ /* @__PURE__ */ React.createElement(Square, { className: "size-2.5" }),
73
+ L.cancel
74
+ ) : null, showRetry ? /* @__PURE__ */ React.createElement(
75
+ "button",
76
+ {
77
+ type: "button",
78
+ onClick: (e) => {
79
+ e.stopPropagation();
80
+ onRetry(run.id);
81
+ },
82
+ className: "inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-p-ink-3 transition-colors cursor-pointer hover:bg-p-warm hover:text-p-ink"
83
+ },
84
+ /* @__PURE__ */ React.createElement(RotateCcw, { className: "size-2.5" }),
85
+ L.retry
86
+ ) : null))
87
+ );
88
+ }
89
+ export {
90
+ SwarmRunCard
91
+ };
@@ -0,0 +1,45 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SwarmRun, SwarmToolCall, SwarmArtifact, SwarmEvaluation, SwarmLabels } from './types.js';
4
+
5
+ type SwarmRunDetailVariant = "tabs" | "flat";
6
+ interface SwarmRunDetailProps {
7
+ run: SwarmRun;
8
+ now?: number;
9
+ /** `"tabs"` (default) — output / artifacts / tools in a tab strip.
10
+ * `"flat"` — every block stacked vertically, scroll-driven, in the
11
+ * shape of an editorial task report. */
12
+ variant?: SwarmRunDetailVariant;
13
+ renderAvatar?: (agent: SwarmRun["agent"]) => ReactNode;
14
+ /** Slot for rendering tool-call rows. Receives the run's tool
15
+ * calls; consumer wires `<ToolCallChip>` from `@lumea-labs/chat`. */
16
+ renderToolCalls?: (toolCalls: SwarmToolCall[]) => ReactNode;
17
+ /** Render the artifacts list. Falls back to a built-in ledger that
18
+ * groups by kind. */
19
+ renderArtifacts?: (artifacts: SwarmArtifact[]) => ReactNode;
20
+ /** Render the evaluation block (LLM-as-a-judge / G-Eval). Receives
21
+ * the run's `evaluation` overlay; consumer wires `<JudgeScoreRadar>`
22
+ * / `<JudgeVerdictHero>` from `@lumea-labs/judge` (or any custom
23
+ * view). When omitted but `run.evaluation` is present, a compact
24
+ * built-in summary is shown. */
25
+ renderEvaluation?: (evaluation: SwarmEvaluation) => ReactNode;
26
+ /** Render Markdown for the goal and output blocks. When omitted, the
27
+ * text is rendered as a `<pre>` (plain). The orchestrator package
28
+ * doesn't ship its own Markdown renderer — wire {@link
29
+ * https://github.com/vercel/streamdown streamdown} or any equivalent
30
+ * on the consumer side. */
31
+ renderMarkdown?: (text: string) => ReactNode;
32
+ /** Hide the tools tab (in `tabs` variant) and the tools section (in
33
+ * `flat` variant). Use this when the surface already shows tool
34
+ * calls inline in an activity stream — having them duplicated as a
35
+ * tab is noisy. Default `false`. */
36
+ hideTools?: boolean;
37
+ onClose?: () => void;
38
+ onCancel?: (id: string) => void;
39
+ onRetry?: (id: string) => void;
40
+ labels?: Partial<SwarmLabels>;
41
+ className?: string;
42
+ }
43
+ declare function SwarmRunDetail({ run, now, variant, renderAvatar, renderToolCalls, renderArtifacts, renderEvaluation, renderMarkdown, hideTools, onClose, onCancel, onRetry, labels, className, }: SwarmRunDetailProps): react.JSX.Element;
44
+
45
+ export { SwarmRunDetail, type SwarmRunDetailProps, type SwarmRunDetailVariant };