@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,346 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import {
|
|
4
|
+
ArrowRight,
|
|
5
|
+
CheckCircle2,
|
|
6
|
+
Circle,
|
|
7
|
+
Clock,
|
|
8
|
+
Hourglass,
|
|
9
|
+
Pause,
|
|
10
|
+
RotateCcw,
|
|
11
|
+
Scale,
|
|
12
|
+
ShieldCheck,
|
|
13
|
+
XCircle
|
|
14
|
+
} from "lucide-react";
|
|
15
|
+
import {
|
|
16
|
+
defaultPlanGraphLabels
|
|
17
|
+
} from "./plan-types";
|
|
18
|
+
function PlanCheckpointDetail({
|
|
19
|
+
checkpoint,
|
|
20
|
+
runtimeByTitle,
|
|
21
|
+
plan,
|
|
22
|
+
headerTrailing,
|
|
23
|
+
actionsSlot,
|
|
24
|
+
onOpenRelated,
|
|
25
|
+
labels,
|
|
26
|
+
className
|
|
27
|
+
}) {
|
|
28
|
+
const L = useMergedLabels(labels);
|
|
29
|
+
const after = checkpoint.afterTasks ?? [];
|
|
30
|
+
const blocks = checkpoint.blocksTasks ?? [];
|
|
31
|
+
return /* @__PURE__ */ React.createElement(
|
|
32
|
+
Frame,
|
|
33
|
+
{
|
|
34
|
+
tone: CHECKPOINT_TONE,
|
|
35
|
+
kind: L.checkpoint,
|
|
36
|
+
icon: /* @__PURE__ */ React.createElement(Hourglass, { className: "size-3.5", "aria-hidden": true }),
|
|
37
|
+
name: checkpoint.name,
|
|
38
|
+
headerTrailing,
|
|
39
|
+
actionsSlot,
|
|
40
|
+
className
|
|
41
|
+
},
|
|
42
|
+
checkpoint.message ? /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Kicker, null, "review prompt"), /* @__PURE__ */ React.createElement("p", { className: "mt-1 font-body text-[13px] leading-[1.55] text-p-ink-2" }, checkpoint.message)) : null,
|
|
43
|
+
/* @__PURE__ */ React.createElement(MetaGrid, null, /* @__PURE__ */ React.createElement(Cell, { label: "kind" }, /* @__PURE__ */ React.createElement(ChipText, { tone: CHECKPOINT_TONE }, L.checkpoint)), /* @__PURE__ */ React.createElement(Cell, { label: "gates" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10.5px] uppercase tracking-[0.14em] text-p-ink" }, "human review"))),
|
|
44
|
+
/* @__PURE__ */ React.createElement(
|
|
45
|
+
RelatedSections,
|
|
46
|
+
{
|
|
47
|
+
after,
|
|
48
|
+
blocks,
|
|
49
|
+
runtimeByTitle,
|
|
50
|
+
plan,
|
|
51
|
+
onOpenRelated,
|
|
52
|
+
L
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
function PlanQualityGateDetail({
|
|
58
|
+
gate,
|
|
59
|
+
runtimeByTitle,
|
|
60
|
+
plan,
|
|
61
|
+
headerTrailing,
|
|
62
|
+
actionsSlot,
|
|
63
|
+
onOpenRelated,
|
|
64
|
+
labels,
|
|
65
|
+
className
|
|
66
|
+
}) {
|
|
67
|
+
const L = useMergedLabels(labels);
|
|
68
|
+
const after = gate.afterTasks ?? [];
|
|
69
|
+
const blocks = gate.blocksTasks ?? [];
|
|
70
|
+
return /* @__PURE__ */ React.createElement(
|
|
71
|
+
Frame,
|
|
72
|
+
{
|
|
73
|
+
tone: GATE_TONE,
|
|
74
|
+
kind: L.qualityGate,
|
|
75
|
+
icon: /* @__PURE__ */ React.createElement(ShieldCheck, { className: "size-3.5", "aria-hidden": true }),
|
|
76
|
+
name: gate.name,
|
|
77
|
+
headerTrailing,
|
|
78
|
+
actionsSlot,
|
|
79
|
+
className
|
|
80
|
+
},
|
|
81
|
+
gate.condition ? /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Kicker, null, "condition"), /* @__PURE__ */ React.createElement("p", { className: "mt-1 font-body text-[13px] leading-[1.55] text-p-ink-2" }, gate.condition)) : null,
|
|
82
|
+
/* @__PURE__ */ React.createElement(MetaGrid, null, /* @__PURE__ */ React.createElement(Cell, { label: L.qualityMinScore }, typeof gate.minScore === "number" ? /* @__PURE__ */ React.createElement("span", { className: "font-display text-[16px] font-bold tabular-nums text-p-ink" }, gate.minScore, /* @__PURE__ */ React.createElement("span", { className: "ml-0.5 font-mono text-[10px] font-bold uppercase tracking-[0.14em] text-p-ink-3" }, "/10")) : /* @__PURE__ */ React.createElement(Dash, null)), /* @__PURE__ */ React.createElement(Cell, { label: L.qualityRequireAll }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10.5px] font-bold uppercase tracking-[0.14em] text-p-ink" }, gate.requireAllPassed ? "yes" : "no"))),
|
|
83
|
+
/* @__PURE__ */ React.createElement(
|
|
84
|
+
RelatedSections,
|
|
85
|
+
{
|
|
86
|
+
after,
|
|
87
|
+
blocks,
|
|
88
|
+
runtimeByTitle,
|
|
89
|
+
plan,
|
|
90
|
+
onOpenRelated,
|
|
91
|
+
L
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
function PlanDelayDetail({
|
|
97
|
+
delay,
|
|
98
|
+
runtimeByTitle,
|
|
99
|
+
plan,
|
|
100
|
+
headerTrailing,
|
|
101
|
+
actionsSlot,
|
|
102
|
+
onOpenRelated,
|
|
103
|
+
labels,
|
|
104
|
+
className
|
|
105
|
+
}) {
|
|
106
|
+
const L = useMergedLabels(labels);
|
|
107
|
+
const after = delay.afterTasks ?? [];
|
|
108
|
+
const blocks = delay.blocksTasks ?? [];
|
|
109
|
+
const human = useMemo(() => parseIsoDuration(delay.duration), [delay.duration]);
|
|
110
|
+
return /* @__PURE__ */ React.createElement(
|
|
111
|
+
Frame,
|
|
112
|
+
{
|
|
113
|
+
tone: DELAY_TONE,
|
|
114
|
+
kind: L.delay,
|
|
115
|
+
icon: /* @__PURE__ */ React.createElement(Clock, { className: "size-3.5", "aria-hidden": true }),
|
|
116
|
+
name: delay.name,
|
|
117
|
+
headerTrailing,
|
|
118
|
+
actionsSlot,
|
|
119
|
+
className
|
|
120
|
+
},
|
|
121
|
+
delay.message ? /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(Kicker, null, "note"), /* @__PURE__ */ React.createElement("p", { className: "mt-1 font-body text-[13px] leading-[1.55] text-p-ink-2" }, delay.message)) : null,
|
|
122
|
+
/* @__PURE__ */ React.createElement(MetaGrid, null, /* @__PURE__ */ React.createElement(Cell, { label: "duration" }, /* @__PURE__ */ React.createElement("span", { className: "font-display text-[18px] font-bold tabular-nums text-p-ink" }, human)), /* @__PURE__ */ React.createElement(Cell, { label: "iso" }, /* @__PURE__ */ React.createElement("code", { className: "font-mono text-[11px] tracking-[0.04em] text-p-ink-2" }, delay.duration))),
|
|
123
|
+
/* @__PURE__ */ React.createElement(
|
|
124
|
+
RelatedSections,
|
|
125
|
+
{
|
|
126
|
+
after,
|
|
127
|
+
blocks,
|
|
128
|
+
runtimeByTitle,
|
|
129
|
+
plan,
|
|
130
|
+
onOpenRelated,
|
|
131
|
+
L
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const CHECKPOINT_TONE = {
|
|
137
|
+
bg: "#FDF8E8",
|
|
138
|
+
fg: "#8A6B0B",
|
|
139
|
+
border: "#D4A017",
|
|
140
|
+
chipBg: "#FDF8E8",
|
|
141
|
+
chipFg: "#8A6B0B"
|
|
142
|
+
};
|
|
143
|
+
const GATE_TONE = {
|
|
144
|
+
bg: "var(--accent-light)",
|
|
145
|
+
fg: "var(--p-accent)",
|
|
146
|
+
border: "var(--p-accent)",
|
|
147
|
+
chipBg: "var(--accent-light)",
|
|
148
|
+
chipFg: "var(--p-accent)"
|
|
149
|
+
};
|
|
150
|
+
const DELAY_TONE = {
|
|
151
|
+
bg: "#F3EEFF",
|
|
152
|
+
fg: "#7B3FE4",
|
|
153
|
+
border: "#7B3FE4",
|
|
154
|
+
chipBg: "#F3EEFF",
|
|
155
|
+
chipFg: "#7B3FE4"
|
|
156
|
+
};
|
|
157
|
+
function Frame({
|
|
158
|
+
tone,
|
|
159
|
+
kind,
|
|
160
|
+
icon,
|
|
161
|
+
name,
|
|
162
|
+
children,
|
|
163
|
+
headerTrailing,
|
|
164
|
+
actionsSlot,
|
|
165
|
+
className
|
|
166
|
+
}) {
|
|
167
|
+
return /* @__PURE__ */ React.createElement(
|
|
168
|
+
"article",
|
|
169
|
+
{
|
|
170
|
+
className: [
|
|
171
|
+
"flex h-full min-h-0 flex-col overflow-hidden bg-p-surface",
|
|
172
|
+
className || ""
|
|
173
|
+
].join(" ")
|
|
174
|
+
},
|
|
175
|
+
/* @__PURE__ */ React.createElement(
|
|
176
|
+
"header",
|
|
177
|
+
{
|
|
178
|
+
className: "flex shrink-0 items-start gap-3 border-b border-p-line px-5 py-4",
|
|
179
|
+
style: { background: tone.bg }
|
|
180
|
+
},
|
|
181
|
+
/* @__PURE__ */ React.createElement(
|
|
182
|
+
"span",
|
|
183
|
+
{
|
|
184
|
+
"aria-hidden": true,
|
|
185
|
+
className: "mt-0.5 grid size-7 shrink-0 place-items-center rounded-full bg-p-surface ring-1",
|
|
186
|
+
style: { color: tone.fg, boxShadow: `inset 0 0 0 1px ${tone.border}` }
|
|
187
|
+
},
|
|
188
|
+
icon
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ React.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React.createElement(
|
|
191
|
+
"div",
|
|
192
|
+
{
|
|
193
|
+
className: "font-mono text-[10px] font-bold uppercase tracking-[0.22em]",
|
|
194
|
+
style: { color: tone.fg }
|
|
195
|
+
},
|
|
196
|
+
kind
|
|
197
|
+
), /* @__PURE__ */ React.createElement("h3", { className: "mt-1 font-display text-[18px] font-bold leading-tight tracking-[-0.01em] text-p-ink" }, name)),
|
|
198
|
+
headerTrailing
|
|
199
|
+
),
|
|
200
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-5 py-4" }, children),
|
|
201
|
+
actionsSlot ? /* @__PURE__ */ React.createElement("footer", { className: "flex shrink-0 items-center justify-end gap-2 border-t border-p-line bg-p-bg/50 px-5 py-3" }, actionsSlot) : null
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const STATUS_ICON = {
|
|
205
|
+
draft: Circle,
|
|
206
|
+
pending: Pause,
|
|
207
|
+
running: RotateCcw,
|
|
208
|
+
review: Scale,
|
|
209
|
+
done: CheckCircle2,
|
|
210
|
+
failed: XCircle
|
|
211
|
+
};
|
|
212
|
+
const STATUS_TONE = {
|
|
213
|
+
draft: "text-p-ink-3",
|
|
214
|
+
pending: "text-p-ink-3",
|
|
215
|
+
running: "text-p-accent",
|
|
216
|
+
review: "text-[#2B44FF]",
|
|
217
|
+
done: "text-p-green",
|
|
218
|
+
failed: "text-[#E63946]"
|
|
219
|
+
};
|
|
220
|
+
function useMergedLabels(labels) {
|
|
221
|
+
return useMemo(
|
|
222
|
+
() => ({ ...defaultPlanGraphLabels, ...labels }),
|
|
223
|
+
[labels]
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function Section({ children }) {
|
|
227
|
+
return /* @__PURE__ */ React.createElement("section", null, children);
|
|
228
|
+
}
|
|
229
|
+
function MetaGrid({ children }) {
|
|
230
|
+
return /* @__PURE__ */ React.createElement("section", { className: "grid grid-cols-2 gap-px overflow-hidden rounded-md border border-p-line bg-p-line text-[11px]" }, children);
|
|
231
|
+
}
|
|
232
|
+
function Cell({ label, children }) {
|
|
233
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1 bg-p-surface px-3 py-2" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[9.5px] font-bold uppercase tracking-[0.18em] text-p-ink-3" }, label), /* @__PURE__ */ React.createElement("span", { className: "min-h-[18px]" }, children));
|
|
234
|
+
}
|
|
235
|
+
function Kicker({
|
|
236
|
+
children,
|
|
237
|
+
icon
|
|
238
|
+
}) {
|
|
239
|
+
return /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1.5 font-mono text-[10px] font-bold uppercase tracking-[0.22em] text-p-ink-3" }, icon, children);
|
|
240
|
+
}
|
|
241
|
+
function Dash() {
|
|
242
|
+
return /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10.5px] uppercase tracking-[0.14em] text-p-ink-3" }, "\u2014");
|
|
243
|
+
}
|
|
244
|
+
function ChipText({
|
|
245
|
+
tone,
|
|
246
|
+
children
|
|
247
|
+
}) {
|
|
248
|
+
return /* @__PURE__ */ React.createElement(
|
|
249
|
+
"span",
|
|
250
|
+
{
|
|
251
|
+
className: "inline-flex items-center rounded-sm px-1.5 py-0.5 font-mono text-[10px] font-bold uppercase tracking-[0.16em]",
|
|
252
|
+
style: { background: tone.chipBg, color: tone.chipFg }
|
|
253
|
+
},
|
|
254
|
+
children
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
function RelatedSections({
|
|
258
|
+
after,
|
|
259
|
+
blocks,
|
|
260
|
+
runtimeByTitle,
|
|
261
|
+
plan,
|
|
262
|
+
onOpenRelated,
|
|
263
|
+
L
|
|
264
|
+
}) {
|
|
265
|
+
const knownTitles = useMemo(() => {
|
|
266
|
+
if (!plan) return null;
|
|
267
|
+
return new Set(plan.tasks.map((t) => t.title));
|
|
268
|
+
}, [plan]);
|
|
269
|
+
const filterValid = (titles) => knownTitles ? titles.filter((t) => knownTitles.has(t)) : titles;
|
|
270
|
+
const safeAfter = filterValid(after);
|
|
271
|
+
const safeBlocks = filterValid(blocks);
|
|
272
|
+
if (safeAfter.length === 0 && safeBlocks.length === 0) {
|
|
273
|
+
return /* @__PURE__ */ React.createElement("section", { className: "flex flex-col items-center gap-2 rounded-md border border-dashed border-p-line bg-p-bg p-6 text-center" }, /* @__PURE__ */ React.createElement("span", { className: "font-mono text-[10.5px] uppercase tracking-[0.16em] text-p-ink-3" }, "standalone \u2014 not gating any task"));
|
|
274
|
+
}
|
|
275
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, safeAfter.length > 0 ? /* @__PURE__ */ React.createElement("section", null, /* @__PURE__ */ React.createElement(Kicker, { icon: /* @__PURE__ */ React.createElement(ArrowRight, { className: "size-2.5 rotate-180" }) }, "after"), /* @__PURE__ */ React.createElement("ol", { className: "mt-1 flex flex-col gap-0.5" }, safeAfter.map((title) => /* @__PURE__ */ React.createElement(
|
|
276
|
+
RelatedRow,
|
|
277
|
+
{
|
|
278
|
+
key: title,
|
|
279
|
+
title,
|
|
280
|
+
runtime: runtimeByTitle?.get(title),
|
|
281
|
+
onOpen: onOpenRelated,
|
|
282
|
+
L
|
|
283
|
+
}
|
|
284
|
+
)))) : null, safeBlocks.length > 0 ? /* @__PURE__ */ React.createElement("section", null, /* @__PURE__ */ React.createElement(Kicker, { icon: /* @__PURE__ */ React.createElement(ArrowRight, { className: "size-2.5" }) }, "blocks"), /* @__PURE__ */ React.createElement("ol", { className: "mt-1 flex flex-col gap-0.5" }, safeBlocks.map((title) => /* @__PURE__ */ React.createElement(
|
|
285
|
+
RelatedRow,
|
|
286
|
+
{
|
|
287
|
+
key: title,
|
|
288
|
+
title,
|
|
289
|
+
runtime: runtimeByTitle?.get(title),
|
|
290
|
+
onOpen: onOpenRelated,
|
|
291
|
+
L
|
|
292
|
+
}
|
|
293
|
+
)))) : null);
|
|
294
|
+
}
|
|
295
|
+
function RelatedRow({
|
|
296
|
+
title,
|
|
297
|
+
runtime,
|
|
298
|
+
onOpen,
|
|
299
|
+
L
|
|
300
|
+
}) {
|
|
301
|
+
const status = runtime?.status ?? "draft";
|
|
302
|
+
const Icon = STATUS_ICON[status];
|
|
303
|
+
const tone = STATUS_TONE[status];
|
|
304
|
+
const interactive = !!onOpen;
|
|
305
|
+
const Wrapper = interactive ? "button" : "div";
|
|
306
|
+
return /* @__PURE__ */ React.createElement(
|
|
307
|
+
Wrapper,
|
|
308
|
+
{
|
|
309
|
+
type: interactive ? "button" : void 0,
|
|
310
|
+
onClick: interactive ? () => onOpen(title) : void 0,
|
|
311
|
+
className: [
|
|
312
|
+
"group flex items-center gap-2 rounded-md border border-p-line bg-p-surface px-2.5 py-1.5 text-left transition-colors",
|
|
313
|
+
interactive ? "cursor-pointer hover:border-p-ink-3 hover:bg-p-warm/40" : ""
|
|
314
|
+
].join(" ")
|
|
315
|
+
},
|
|
316
|
+
/* @__PURE__ */ React.createElement(Icon, { className: ["size-3 shrink-0", tone].join(" "), "aria-hidden": true }),
|
|
317
|
+
/* @__PURE__ */ React.createElement("span", { className: "min-w-0 flex-1 truncate font-display text-[12.5px] font-semibold text-p-ink" }, title),
|
|
318
|
+
/* @__PURE__ */ React.createElement(
|
|
319
|
+
"span",
|
|
320
|
+
{
|
|
321
|
+
className: [
|
|
322
|
+
"shrink-0 font-mono text-[9.5px] font-bold uppercase tracking-[0.16em]",
|
|
323
|
+
tone
|
|
324
|
+
].join(" ")
|
|
325
|
+
},
|
|
326
|
+
L.status[status]
|
|
327
|
+
)
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
function parseIsoDuration(iso) {
|
|
331
|
+
if (!iso) return "\u2014";
|
|
332
|
+
const m = iso.match(/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/);
|
|
333
|
+
if (!m) return iso;
|
|
334
|
+
const [, d, h, mi, s] = m;
|
|
335
|
+
const out = [];
|
|
336
|
+
if (d) out.push(`${d}d`);
|
|
337
|
+
if (h) out.push(`${h}h`);
|
|
338
|
+
if (mi) out.push(`${mi}m`);
|
|
339
|
+
if (s) out.push(`${s}s`);
|
|
340
|
+
return out.join(" ") || iso;
|
|
341
|
+
}
|
|
342
|
+
export {
|
|
343
|
+
PlanCheckpointDetail,
|
|
344
|
+
PlanDelayDetail,
|
|
345
|
+
PlanQualityGateDetail
|
|
346
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { PlanTask, Plan, PlanTaskRuntime, PlanGraphLabels } from './plan-types.js';
|
|
4
|
+
import { SwarmAgentRef } from './types.js';
|
|
5
|
+
|
|
6
|
+
type PlanTaskDetailVariant = "panel" | "page";
|
|
7
|
+
/**
|
|
8
|
+
* Async confirm slot — consumer wires this to `<ConfirmDialog>` (or
|
|
9
|
+
* `window.confirm` in dev). Returns `true` to proceed, `false` to abort.
|
|
10
|
+
*/
|
|
11
|
+
type PlanTaskConfirmFn = (opts: {
|
|
12
|
+
title: string;
|
|
13
|
+
message?: string;
|
|
14
|
+
confirmLabel: string;
|
|
15
|
+
cancelLabel?: string;
|
|
16
|
+
destructive?: boolean;
|
|
17
|
+
}) => Promise<boolean>;
|
|
18
|
+
interface PlanTaskActionConfig {
|
|
19
|
+
/** Fired after the user passes the confirm gate (or immediately when
|
|
20
|
+
* no confirm slot is wired). */
|
|
21
|
+
onConfirm: () => void;
|
|
22
|
+
/** Override the default confirm copy/strength. Pass `false` to skip
|
|
23
|
+
* the confirm gate entirely for this action. */
|
|
24
|
+
confirm?: false | {
|
|
25
|
+
title?: string;
|
|
26
|
+
message?: string;
|
|
27
|
+
confirmLabel?: string;
|
|
28
|
+
destructive?: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** Disable the button while another action is in flight. */
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
interface PlanTaskActions {
|
|
34
|
+
/** Start a fresh run for this task. Default copy: non-destructive. */
|
|
35
|
+
run?: PlanTaskActionConfig;
|
|
36
|
+
/** Re-run the task after success or failure. Non-destructive. */
|
|
37
|
+
retry?: PlanTaskActionConfig;
|
|
38
|
+
/** Re-evaluate outcomes (judge / quality gates). Non-destructive. */
|
|
39
|
+
reassess?: PlanTaskActionConfig;
|
|
40
|
+
/** Stop a running task. Default copy: DESTRUCTIVE. */
|
|
41
|
+
abort?: PlanTaskActionConfig;
|
|
42
|
+
}
|
|
43
|
+
interface PlanTaskDetailProps {
|
|
44
|
+
task: PlanTask;
|
|
45
|
+
/** When provided, used to resolve `dependsOn` titles and the
|
|
46
|
+
* reverse "blocks" list. */
|
|
47
|
+
plan?: Plan;
|
|
48
|
+
runtimeByTitle?: Map<string, PlanTaskRuntime>;
|
|
49
|
+
agents?: SwarmAgentRef[];
|
|
50
|
+
/** `"panel"` (default) — compact side-pane shape used in drawers and
|
|
51
|
+
* graph overlays. `"page"` — editorial full-page shape with pills
|
|
52
|
+
* row, big title and inline action dock. */
|
|
53
|
+
variant?: PlanTaskDetailVariant;
|
|
54
|
+
/** Trailing slot in the header (e.g. close button). */
|
|
55
|
+
headerTrailing?: ReactNode;
|
|
56
|
+
/** Footer slot — used by the panel variant for compact controls.
|
|
57
|
+
* Ignored by the page variant, which renders `actions` inline. */
|
|
58
|
+
actionsSlot?: ReactNode;
|
|
59
|
+
/** Declarative action descriptors. Each enabled action is rendered
|
|
60
|
+
* as a button; clicking gates through `confirm` (when supplied)
|
|
61
|
+
* before invoking `onConfirm`. */
|
|
62
|
+
actions?: PlanTaskActions;
|
|
63
|
+
/** Async confirm gate. When omitted, actions fire immediately. */
|
|
64
|
+
confirm?: PlanTaskConfirmFn;
|
|
65
|
+
/** Click on a related task (dep or dependent) — passes the title. */
|
|
66
|
+
onOpenRelated?: (title: string) => void;
|
|
67
|
+
/** Render the task description as Markdown — wire `<MarkdownViewer/>`
|
|
68
|
+
* from `@lumea-labs/markdown`. When omitted, description is plain
|
|
69
|
+
* text. */
|
|
70
|
+
renderMarkdown?: (text: string) => ReactNode;
|
|
71
|
+
labels?: Partial<PlanGraphLabels>;
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
declare function PlanTaskDetail({ task, plan, runtimeByTitle, agents, variant, headerTrailing, actionsSlot, actions, confirm, onOpenRelated, renderMarkdown, labels, className, }: PlanTaskDetailProps): react.JSX.Element;
|
|
75
|
+
|
|
76
|
+
export { type PlanTaskActionConfig, type PlanTaskActions, type PlanTaskConfirmFn, PlanTaskDetail, type PlanTaskDetailProps, type PlanTaskDetailVariant };
|