@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.
- package/README.md +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +93 -0
- package/dist/lib/format.d.ts +3 -0
- package/dist/lib/format.js +9 -0
- package/dist/orchestrator-document.d.ts +37 -0
- package/dist/orchestrator-document.js +122 -0
- package/dist/plan-detail.d.ts +102 -0
- package/dist/plan-detail.js +385 -0
- package/dist/plan-graph.d.ts +39 -0
- package/dist/plan-graph.js +597 -0
- package/dist/plan-node-detail.d.ts +29 -0
- package/dist/plan-node-detail.js +346 -0
- package/dist/plan-task-detail.d.ts +76 -0
- package/dist/plan-task-detail.js +450 -0
- package/dist/plan-types.d.ts +85 -0
- package/dist/plan-types.js +51 -0
- package/dist/run-kanban-filter-menu.d.ts +24 -0
- package/dist/run-kanban-filter-menu.js +152 -0
- package/dist/run-kanban.d.ts +61 -0
- package/dist/run-kanban.js +234 -0
- package/dist/swarm-agent-badge.d.ts +15 -0
- package/dist/swarm-agent-badge.js +39 -0
- package/dist/swarm-run-activity.d.ts +39 -0
- package/dist/swarm-run-activity.js +289 -0
- package/dist/swarm-run-card.d.ts +22 -0
- package/dist/swarm-run-card.js +91 -0
- package/dist/swarm-run-detail.d.ts +45 -0
- package/dist/swarm-run-detail.js +559 -0
- package/dist/swarm-run-list.d.ts +22 -0
- package/dist/swarm-run-list.js +75 -0
- package/dist/swarm-run-row.d.ts +22 -0
- package/dist/swarm-run-row.js +125 -0
- package/dist/swarm-skeletons.d.ts +28 -0
- package/dist/swarm-skeletons.js +78 -0
- package/dist/swarm-status-bar.d.ts +15 -0
- package/dist/swarm-status-bar.js +79 -0
- package/dist/swarm-status-pill.d.ts +12 -0
- package/dist/swarm-status-pill.js +86 -0
- package/dist/swarm-timeline.d.ts +21 -0
- package/dist/swarm-timeline.js +414 -0
- package/dist/task-workspace-sidebar.d.ts +71 -0
- package/dist/task-workspace-sidebar.js +352 -0
- package/dist/types.d.ts +285 -0
- package/dist/types.js +44 -0
- package/package.json +41 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
CheckCircle2,
|
|
5
|
+
ChevronDown,
|
|
6
|
+
ChevronRight,
|
|
7
|
+
Circle,
|
|
8
|
+
Pause,
|
|
9
|
+
RotateCcw,
|
|
10
|
+
Scale,
|
|
11
|
+
XCircle
|
|
12
|
+
} from "lucide-react";
|
|
13
|
+
import { PlanGraph } from "./plan-graph";
|
|
14
|
+
import {
|
|
15
|
+
defaultPlanDetailLabels,
|
|
16
|
+
defaultPlanGraphLabels
|
|
17
|
+
} from "./plan-types";
|
|
18
|
+
const STATUS_ICON = {
|
|
19
|
+
draft: Circle,
|
|
20
|
+
pending: Pause,
|
|
21
|
+
running: RotateCcw,
|
|
22
|
+
review: Scale,
|
|
23
|
+
done: CheckCircle2,
|
|
24
|
+
failed: XCircle
|
|
25
|
+
};
|
|
26
|
+
const STATUS_TONE = {
|
|
27
|
+
draft: "text-p-ink-3",
|
|
28
|
+
pending: "text-p-ink-3",
|
|
29
|
+
running: "text-p-accent",
|
|
30
|
+
review: "text-[#2B44FF]",
|
|
31
|
+
done: "text-p-green",
|
|
32
|
+
failed: "text-[#E63946]"
|
|
33
|
+
};
|
|
34
|
+
function PlanDetailHeader({
|
|
35
|
+
plan,
|
|
36
|
+
runtimeByTitle,
|
|
37
|
+
briefSlot,
|
|
38
|
+
actionsSlot,
|
|
39
|
+
headerLeading,
|
|
40
|
+
headerTrailing,
|
|
41
|
+
labels,
|
|
42
|
+
className
|
|
43
|
+
}) {
|
|
44
|
+
const L = useMemo(
|
|
45
|
+
() => ({ ...defaultPlanDetailLabels, ...labels }),
|
|
46
|
+
[labels]
|
|
47
|
+
);
|
|
48
|
+
const taskCount = plan.tasks.length;
|
|
49
|
+
const cpCount = plan.checkpoints?.length ?? 0;
|
|
50
|
+
const gateCount = plan.qualityGates?.length ?? 0;
|
|
51
|
+
const delayCount = plan.delays?.length ?? 0;
|
|
52
|
+
const counts = useMemo(() => statusCounts(plan, runtimeByTitle), [
|
|
53
|
+
plan,
|
|
54
|
+
runtimeByTitle
|
|
55
|
+
]);
|
|
56
|
+
const hasRuntime = runtimeByTitle && runtimeByTitle.size > 0;
|
|
57
|
+
return /* @__PURE__ */ React.createElement(
|
|
58
|
+
"header",
|
|
59
|
+
{
|
|
60
|
+
className: [
|
|
61
|
+
"flex flex-col border-b border-p-line",
|
|
62
|
+
className || ""
|
|
63
|
+
].join(" ")
|
|
64
|
+
},
|
|
65
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 px-5 py-3" }, headerLeading, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.24em] text-p-ink-3" }, L.kicker), /* @__PURE__ */ React.createElement("h2", { className: "font-display text-[22px] font-bold leading-tight tracking-[-0.02em] text-p-ink" }, plan.name ?? "\u2014"), /* @__PURE__ */ React.createElement("span", { className: "ml-auto inline-flex items-center gap-2" }, headerTrailing, actionsSlot)),
|
|
66
|
+
/* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-2 gap-px border-t border-p-line bg-p-line sm:grid-cols-4" }, /* @__PURE__ */ React.createElement(MetaCell, { label: L.taskCountLabel(taskCount), accent: true }), /* @__PURE__ */ React.createElement(MetaCell, { label: L.checkpointCountLabel(cpCount) }), /* @__PURE__ */ React.createElement(MetaCell, { label: L.gateCountLabel(gateCount) }), /* @__PURE__ */ React.createElement(MetaCell, { label: L.delayCountLabel(delayCount) })),
|
|
67
|
+
hasRuntime ? /* @__PURE__ */ React.createElement(StatusCountsStrip, { counts, L }) : null,
|
|
68
|
+
briefSlot ? /* @__PURE__ */ React.createElement("div", { className: "border-t border-p-line px-5 py-4 font-body text-[14px] leading-[1.55] text-p-ink-2" }, briefSlot) : null
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
function PlanDetailMasthead({
|
|
72
|
+
plan,
|
|
73
|
+
runtimeByTitle,
|
|
74
|
+
briefSlot,
|
|
75
|
+
actionsSlot,
|
|
76
|
+
headerLeading,
|
|
77
|
+
headerTrailing,
|
|
78
|
+
labels,
|
|
79
|
+
className
|
|
80
|
+
}) {
|
|
81
|
+
const L = useMemo(
|
|
82
|
+
() => ({ ...defaultPlanDetailLabels, ...labels }),
|
|
83
|
+
[labels]
|
|
84
|
+
);
|
|
85
|
+
const taskCount = plan.tasks.length;
|
|
86
|
+
const cpCount = plan.checkpoints?.length ?? 0;
|
|
87
|
+
const gateCount = plan.qualityGates?.length ?? 0;
|
|
88
|
+
const delayCount = plan.delays?.length ?? 0;
|
|
89
|
+
const counts = useMemo(() => statusCounts(plan, runtimeByTitle), [
|
|
90
|
+
plan,
|
|
91
|
+
runtimeByTitle
|
|
92
|
+
]);
|
|
93
|
+
const hasRuntime = runtimeByTitle && runtimeByTitle.size > 0;
|
|
94
|
+
return /* @__PURE__ */ React.createElement(
|
|
95
|
+
"header",
|
|
96
|
+
{
|
|
97
|
+
className: [
|
|
98
|
+
"flex flex-col gap-5 border-b border-p-line px-7 py-7",
|
|
99
|
+
className || ""
|
|
100
|
+
].join(" ")
|
|
101
|
+
},
|
|
102
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-4" }, headerLeading ? /* @__PURE__ */ React.createElement("div", { className: "shrink-0 pt-1" }, headerLeading) : null, /* @__PURE__ */ React.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.24em] text-p-ink-3" }, L.kicker), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 font-display text-[34px] font-bold leading-[1.04] tracking-[-0.025em] text-p-ink" }, plan.name ?? "\u2014")), headerTrailing || actionsSlot ? /* @__PURE__ */ React.createElement("div", { className: "shrink-0 flex flex-col items-end gap-2" }, headerTrailing, actionsSlot) : null),
|
|
103
|
+
briefSlot ? /* @__PURE__ */ React.createElement("div", { className: "max-w-[64ch] font-body text-[14.5px] leading-[1.65] text-p-ink-2" }, briefSlot) : null,
|
|
104
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-baseline gap-x-4 gap-y-1.5 font-mono text-[10.5px] uppercase tracking-[0.22em]" }, /* @__PURE__ */ React.createElement(InventoryItem, { label: L.taskCountLabel(taskCount), accent: true }), /* @__PURE__ */ React.createElement(Sep, null), /* @__PURE__ */ React.createElement(InventoryItem, { label: L.checkpointCountLabel(cpCount) }), /* @__PURE__ */ React.createElement(Sep, null), /* @__PURE__ */ React.createElement(InventoryItem, { label: L.gateCountLabel(gateCount) }), /* @__PURE__ */ React.createElement(Sep, null), /* @__PURE__ */ React.createElement(InventoryItem, { label: L.delayCountLabel(delayCount) })),
|
|
105
|
+
hasRuntime ? /* @__PURE__ */ React.createElement(StatusCountsStrip, { counts, L, dense: true }) : null
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
function PlanDetailGraph({
|
|
109
|
+
plan,
|
|
110
|
+
runtimeByTitle,
|
|
111
|
+
agents,
|
|
112
|
+
graphHeight = 720,
|
|
113
|
+
fillHeight = false,
|
|
114
|
+
onOpenTask,
|
|
115
|
+
onOpenCheckpoint,
|
|
116
|
+
onOpenGate,
|
|
117
|
+
onOpenDelay,
|
|
118
|
+
selectedNodeId,
|
|
119
|
+
zoomToSelected,
|
|
120
|
+
graphLabels,
|
|
121
|
+
className
|
|
122
|
+
}) {
|
|
123
|
+
const GL = useMemo(
|
|
124
|
+
() => ({ ...defaultPlanGraphLabels, ...graphLabels }),
|
|
125
|
+
[graphLabels]
|
|
126
|
+
);
|
|
127
|
+
return /* @__PURE__ */ React.createElement(
|
|
128
|
+
"div",
|
|
129
|
+
{
|
|
130
|
+
className: [fillHeight ? "min-h-0 flex-1" : "", className || ""].join(" ").trim(),
|
|
131
|
+
style: fillHeight ? void 0 : { height: graphHeight }
|
|
132
|
+
},
|
|
133
|
+
/* @__PURE__ */ React.createElement(
|
|
134
|
+
PlanGraph,
|
|
135
|
+
{
|
|
136
|
+
tasks: plan.tasks,
|
|
137
|
+
runtimeByTitle,
|
|
138
|
+
checkpoints: plan.checkpoints,
|
|
139
|
+
qualityGates: plan.qualityGates,
|
|
140
|
+
delays: plan.delays,
|
|
141
|
+
agents,
|
|
142
|
+
onOpenTask,
|
|
143
|
+
onOpenCheckpoint,
|
|
144
|
+
onOpenGate,
|
|
145
|
+
onOpenDelay,
|
|
146
|
+
selectedNodeId,
|
|
147
|
+
zoomToSelected,
|
|
148
|
+
labels: GL,
|
|
149
|
+
className: "h-full"
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
function PlanDetailBreakdown({
|
|
155
|
+
plan,
|
|
156
|
+
runtimeByTitle,
|
|
157
|
+
agents,
|
|
158
|
+
defaultOpen = true,
|
|
159
|
+
alwaysOpen = false,
|
|
160
|
+
onOpenTask,
|
|
161
|
+
labels,
|
|
162
|
+
className
|
|
163
|
+
}) {
|
|
164
|
+
const L = useMemo(
|
|
165
|
+
() => ({ ...defaultPlanDetailLabels, ...labels }),
|
|
166
|
+
[labels]
|
|
167
|
+
);
|
|
168
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
169
|
+
const isOpen = alwaysOpen || open;
|
|
170
|
+
const agentByName = useMemo(() => {
|
|
171
|
+
const m = /* @__PURE__ */ new Map();
|
|
172
|
+
for (const a of agents ?? []) m.set(a.name, a);
|
|
173
|
+
return m;
|
|
174
|
+
}, [agents]);
|
|
175
|
+
return /* @__PURE__ */ React.createElement(
|
|
176
|
+
"section",
|
|
177
|
+
{
|
|
178
|
+
className: [
|
|
179
|
+
"flex flex-col gap-2 border-t border-p-line px-5 py-4",
|
|
180
|
+
className || ""
|
|
181
|
+
].join(" ")
|
|
182
|
+
},
|
|
183
|
+
alwaysOpen ? /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.22em] text-p-ink-3" }, L.breakdown), /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] tabular-nums text-p-ink-3" }, String(plan.tasks.length).padStart(2, "0")), /* @__PURE__ */ React.createElement("span", { className: "h-px flex-1 bg-p-line" })) : /* @__PURE__ */ React.createElement(
|
|
184
|
+
"button",
|
|
185
|
+
{
|
|
186
|
+
type: "button",
|
|
187
|
+
onClick: () => setOpen((v) => !v),
|
|
188
|
+
"aria-expanded": open,
|
|
189
|
+
className: "group flex items-center gap-3 rounded-md border-none bg-transparent p-0 text-left cursor-pointer"
|
|
190
|
+
},
|
|
191
|
+
/* @__PURE__ */ React.createElement("span", { className: "grid size-5 shrink-0 place-items-center rounded text-p-ink-3 transition-colors group-hover:bg-p-warm group-hover:text-p-ink" }, open ? /* @__PURE__ */ React.createElement(ChevronDown, { className: "size-3.5" }) : /* @__PURE__ */ React.createElement(ChevronRight, { className: "size-3.5" })),
|
|
192
|
+
/* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.22em] text-p-ink-3 group-hover:text-p-ink" }, L.breakdown),
|
|
193
|
+
/* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] tabular-nums text-p-ink-3" }, String(plan.tasks.length).padStart(2, "0")),
|
|
194
|
+
/* @__PURE__ */ React.createElement("span", { className: "h-px flex-1 bg-p-line" })
|
|
195
|
+
),
|
|
196
|
+
!isOpen ? null : plan.tasks.length === 0 ? /* @__PURE__ */ React.createElement("p", { className: "px-1 py-2 font-mono text-[11px] uppercase tracking-[0.16em] text-p-ink-3" }, L.noTasks) : /* @__PURE__ */ React.createElement("ol", { className: "flex flex-col divide-y divide-p-line/60" }, plan.tasks.map((tk, i) => {
|
|
197
|
+
const rt = runtimeByTitle?.get(tk.title);
|
|
198
|
+
const status = rt?.status ?? "draft";
|
|
199
|
+
const Icon = STATUS_ICON[status];
|
|
200
|
+
const tone = STATUS_TONE[status];
|
|
201
|
+
const agentName = rt?.agentName ?? tk.assignTo ?? void 0;
|
|
202
|
+
const agentRef = agentName ? agentByName.get(agentName) : void 0;
|
|
203
|
+
return /* @__PURE__ */ React.createElement(
|
|
204
|
+
"li",
|
|
205
|
+
{
|
|
206
|
+
key: tk.title,
|
|
207
|
+
className: [
|
|
208
|
+
"grid grid-cols-[24px_minmax(0,1fr)_auto_88px] items-center gap-3 py-2",
|
|
209
|
+
onOpenTask ? "cursor-pointer transition-colors hover:bg-p-warm/40" : ""
|
|
210
|
+
].join(" "),
|
|
211
|
+
onClick: onOpenTask ? () => onOpenTask({ title: tk.title }) : void 0
|
|
212
|
+
},
|
|
213
|
+
/* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10px] font-bold uppercase tracking-[0.14em] text-p-ink-3 tabular-nums" }, String(i + 1).padStart(2, "0")),
|
|
214
|
+
/* @__PURE__ */ React.createElement("div", { className: "min-w-0 flex flex-col leading-tight" }, /* @__PURE__ */ React.createElement("span", { className: "truncate font-display text-[13.5px] font-bold text-p-ink" }, tk.title), tk.description ? /* @__PURE__ */ React.createElement("span", { className: "truncate font-body text-[11.5px] text-p-ink-3" }, tk.description) : null),
|
|
215
|
+
/* @__PURE__ */ React.createElement("span", { className: "inline-flex shrink-0 items-center gap-1.5 font-mono text-[10.5px] uppercase tracking-[0.14em] text-p-ink-2" }, agentRef ? /* @__PURE__ */ React.createElement(
|
|
216
|
+
"span",
|
|
217
|
+
{
|
|
218
|
+
"aria-hidden": true,
|
|
219
|
+
className: "grid size-4 shrink-0 place-items-center rounded font-display text-[9px] font-bold text-white",
|
|
220
|
+
style: { background: agentRef.color || "#999" }
|
|
221
|
+
},
|
|
222
|
+
agentRef.glyph || (agentRef.displayName ?? agentRef.name).charAt(0).toUpperCase()
|
|
223
|
+
) : null, /* @__PURE__ */ React.createElement("span", { className: "truncate" }, agentName ?? "\u2014")),
|
|
224
|
+
/* @__PURE__ */ React.createElement(
|
|
225
|
+
"span",
|
|
226
|
+
{
|
|
227
|
+
className: [
|
|
228
|
+
"inline-flex shrink-0 items-center justify-end gap-1.5 font-mono text-[10.5px] font-bold uppercase tracking-[0.14em]",
|
|
229
|
+
tone
|
|
230
|
+
].join(" ")
|
|
231
|
+
},
|
|
232
|
+
/* @__PURE__ */ React.createElement(Icon, { className: "size-3" }),
|
|
233
|
+
L.status[status]
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
}))
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
function PlanDetail({
|
|
240
|
+
plan,
|
|
241
|
+
runtimeByTitle,
|
|
242
|
+
agents,
|
|
243
|
+
briefSlot,
|
|
244
|
+
actionsSlot,
|
|
245
|
+
headerTrailing,
|
|
246
|
+
hideBreakdown = false,
|
|
247
|
+
defaultBreakdownOpen = true,
|
|
248
|
+
graphHeight = 720,
|
|
249
|
+
onOpenTask,
|
|
250
|
+
labels,
|
|
251
|
+
graphLabels,
|
|
252
|
+
className
|
|
253
|
+
}) {
|
|
254
|
+
return /* @__PURE__ */ React.createElement(
|
|
255
|
+
"article",
|
|
256
|
+
{
|
|
257
|
+
className: [
|
|
258
|
+
"flex flex-col overflow-hidden rounded-2xl border border-p-line bg-p-surface",
|
|
259
|
+
className || ""
|
|
260
|
+
].join(" ")
|
|
261
|
+
},
|
|
262
|
+
/* @__PURE__ */ React.createElement(
|
|
263
|
+
PlanDetailHeader,
|
|
264
|
+
{
|
|
265
|
+
plan,
|
|
266
|
+
runtimeByTitle,
|
|
267
|
+
briefSlot,
|
|
268
|
+
actionsSlot,
|
|
269
|
+
headerTrailing,
|
|
270
|
+
labels
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
/* @__PURE__ */ React.createElement(
|
|
274
|
+
PlanDetailGraph,
|
|
275
|
+
{
|
|
276
|
+
plan,
|
|
277
|
+
runtimeByTitle,
|
|
278
|
+
agents,
|
|
279
|
+
graphHeight,
|
|
280
|
+
onOpenTask,
|
|
281
|
+
graphLabels
|
|
282
|
+
}
|
|
283
|
+
),
|
|
284
|
+
!hideBreakdown ? /* @__PURE__ */ React.createElement(
|
|
285
|
+
PlanDetailBreakdown,
|
|
286
|
+
{
|
|
287
|
+
plan,
|
|
288
|
+
runtimeByTitle,
|
|
289
|
+
agents,
|
|
290
|
+
defaultOpen: defaultBreakdownOpen,
|
|
291
|
+
onOpenTask,
|
|
292
|
+
labels
|
|
293
|
+
}
|
|
294
|
+
) : null
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function statusCounts(plan, runtimeByTitle) {
|
|
298
|
+
const c = {
|
|
299
|
+
draft: 0,
|
|
300
|
+
pending: 0,
|
|
301
|
+
running: 0,
|
|
302
|
+
review: 0,
|
|
303
|
+
done: 0,
|
|
304
|
+
failed: 0
|
|
305
|
+
};
|
|
306
|
+
for (const tk of plan.tasks) {
|
|
307
|
+
const s = runtimeByTitle?.get(tk.title)?.status ?? "draft";
|
|
308
|
+
c[s] += 1;
|
|
309
|
+
}
|
|
310
|
+
return c;
|
|
311
|
+
}
|
|
312
|
+
function StatusCountsStrip({
|
|
313
|
+
counts,
|
|
314
|
+
L,
|
|
315
|
+
dense
|
|
316
|
+
}) {
|
|
317
|
+
const order = [
|
|
318
|
+
"running",
|
|
319
|
+
"review",
|
|
320
|
+
"done",
|
|
321
|
+
"failed",
|
|
322
|
+
"pending",
|
|
323
|
+
"draft"
|
|
324
|
+
];
|
|
325
|
+
const visible = order.filter((s) => counts[s] > 0);
|
|
326
|
+
if (visible.length === 0) return null;
|
|
327
|
+
return /* @__PURE__ */ React.createElement(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
className: [
|
|
331
|
+
"flex flex-wrap items-center gap-3 font-mono text-[10.5px] uppercase tracking-[0.16em] text-p-ink-3",
|
|
332
|
+
dense ? "" : "border-t border-p-line px-5 py-2.5"
|
|
333
|
+
].join(" ")
|
|
334
|
+
},
|
|
335
|
+
visible.map((s) => {
|
|
336
|
+
const Icon = STATUS_ICON[s];
|
|
337
|
+
return /* @__PURE__ */ React.createElement(
|
|
338
|
+
"span",
|
|
339
|
+
{
|
|
340
|
+
key: s,
|
|
341
|
+
className: ["inline-flex items-center gap-1.5", STATUS_TONE[s]].join(
|
|
342
|
+
" "
|
|
343
|
+
)
|
|
344
|
+
},
|
|
345
|
+
/* @__PURE__ */ React.createElement(Icon, { className: "size-3" }),
|
|
346
|
+
/* @__PURE__ */ React.createElement("span", { className: "font-display text-[14px] font-bold tabular-nums leading-none text-p-ink" }, counts[s]),
|
|
347
|
+
/* @__PURE__ */ React.createElement("span", null, L.status[s])
|
|
348
|
+
);
|
|
349
|
+
})
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
function MetaCell({ label, accent }) {
|
|
353
|
+
return /* @__PURE__ */ React.createElement("div", { className: "bg-p-surface px-4 py-2.5" }, /* @__PURE__ */ React.createElement(
|
|
354
|
+
"span",
|
|
355
|
+
{
|
|
356
|
+
className: [
|
|
357
|
+
"block font-mono text-[10px] font-bold uppercase tracking-[0.18em]",
|
|
358
|
+
accent ? "text-p-accent" : "text-p-ink-3"
|
|
359
|
+
].join(" ")
|
|
360
|
+
},
|
|
361
|
+
label
|
|
362
|
+
));
|
|
363
|
+
}
|
|
364
|
+
function InventoryItem({ label, accent }) {
|
|
365
|
+
return /* @__PURE__ */ React.createElement(
|
|
366
|
+
"span",
|
|
367
|
+
{
|
|
368
|
+
className: [
|
|
369
|
+
"font-bold",
|
|
370
|
+
accent ? "text-p-accent" : "text-p-ink-2"
|
|
371
|
+
].join(" ")
|
|
372
|
+
},
|
|
373
|
+
label
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
function Sep() {
|
|
377
|
+
return /* @__PURE__ */ React.createElement("span", { "aria-hidden": true, className: "text-p-line" }, "\xB7");
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
PlanDetail,
|
|
381
|
+
PlanDetailBreakdown,
|
|
382
|
+
PlanDetailGraph,
|
|
383
|
+
PlanDetailHeader,
|
|
384
|
+
PlanDetailMasthead
|
|
385
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { PlanTask, PlanTaskRuntime, PlanCheckpoint, PlanQualityGate, PlanDelay, PlanGraphLabels } from './plan-types.js';
|
|
3
|
+
import { SwarmAgentRef } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface PlanGraphTaskRef {
|
|
6
|
+
title: string;
|
|
7
|
+
/** Optional opaque runtime id passed back to the consumer when present. */
|
|
8
|
+
runtimeId?: string;
|
|
9
|
+
}
|
|
10
|
+
interface PlanGraphProps {
|
|
11
|
+
tasks: PlanTask[];
|
|
12
|
+
/** Runtime status overlay, keyed by task title. */
|
|
13
|
+
runtimeByTitle?: Map<string, PlanTaskRuntime>;
|
|
14
|
+
checkpoints?: PlanCheckpoint[];
|
|
15
|
+
qualityGates?: PlanQualityGate[];
|
|
16
|
+
delays?: PlanDelay[];
|
|
17
|
+
agents?: SwarmAgentRef[];
|
|
18
|
+
onOpenTask?: (ref: PlanGraphTaskRef) => void;
|
|
19
|
+
/** Open callbacks for non-task nodes — receive the node's `name`. */
|
|
20
|
+
onOpenCheckpoint?: (name: string) => void;
|
|
21
|
+
onOpenGate?: (name: string) => void;
|
|
22
|
+
onOpenDelay?: (name: string) => void;
|
|
23
|
+
/** Controlled-selection prop — the canonical node id to highlight:
|
|
24
|
+
* - `task:<title>` for tasks
|
|
25
|
+
* - `cp:<name>` for checkpoints
|
|
26
|
+
* - `qg:<name>` for quality gates
|
|
27
|
+
* - `dl:<name>` for delays
|
|
28
|
+
* Pair with a toggle `onOpen*` handler to get "click again to
|
|
29
|
+
* deselect" behaviour. */
|
|
30
|
+
selectedNodeId?: string | null;
|
|
31
|
+
/** When `true`, animate the viewport to centre + zoom on the
|
|
32
|
+
* currently `selectedNodeId` node. Off by default. */
|
|
33
|
+
zoomToSelected?: boolean;
|
|
34
|
+
labels?: Partial<PlanGraphLabels>;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
declare function PlanGraph(props: PlanGraphProps): react.JSX.Element;
|
|
38
|
+
|
|
39
|
+
export { PlanGraph, type PlanGraphProps, type PlanGraphTaskRef };
|