@synergenius/flow-weaver-pack-weaver 0.9.62 → 0.9.78
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/ai-chat-provider.d.ts +12 -0
- package/dist/ai-chat-provider.d.ts.map +1 -1
- package/dist/ai-chat-provider.js +173 -19
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/agent-loop.d.ts +20 -0
- package/dist/bot/agent-loop.d.ts.map +1 -0
- package/dist/bot/agent-loop.js +331 -0
- package/dist/bot/agent-loop.js.map +1 -0
- package/dist/bot/ai-router.d.ts +19 -0
- package/dist/bot/ai-router.d.ts.map +1 -0
- package/dist/bot/ai-router.js +104 -0
- package/dist/bot/ai-router.js.map +1 -0
- package/dist/bot/bot-registry.js +2 -2
- package/dist/bot/bot-registry.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +1 -0
- package/dist/bot/conversation-store.d.ts.map +1 -1
- package/dist/bot/conversation-store.js.map +1 -1
- package/dist/bot/improve-loop.js.map +1 -1
- package/dist/bot/instance-manager.d.ts +31 -0
- package/dist/bot/instance-manager.d.ts.map +1 -0
- package/dist/bot/instance-manager.js +115 -0
- package/dist/bot/instance-manager.js.map +1 -0
- package/dist/bot/orchestrator.d.ts +36 -0
- package/dist/bot/orchestrator.d.ts.map +1 -0
- package/dist/bot/orchestrator.js +176 -0
- package/dist/bot/orchestrator.js.map +1 -0
- package/dist/bot/profile-store.d.ts +36 -0
- package/dist/bot/profile-store.d.ts.map +1 -0
- package/dist/bot/profile-store.js +208 -0
- package/dist/bot/profile-store.js.map +1 -0
- package/dist/bot/profile-types.d.ts +126 -0
- package/dist/bot/profile-types.d.ts.map +1 -0
- package/dist/bot/profile-types.js +7 -0
- package/dist/bot/profile-types.js.map +1 -0
- package/dist/bot/session-state.d.ts +25 -0
- package/dist/bot/session-state.d.ts.map +1 -0
- package/dist/bot/session-state.js +110 -0
- package/dist/bot/session-state.js.map +1 -0
- package/dist/bot/swarm-controller.d.ts +37 -21
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +344 -163
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/task-prompt-builder.d.ts +2 -1
- package/dist/bot/task-prompt-builder.d.ts.map +1 -1
- package/dist/bot/task-prompt-builder.js +33 -10
- package/dist/bot/task-prompt-builder.js.map +1 -1
- package/dist/bot/task-queue.d.ts +46 -0
- package/dist/bot/task-queue.d.ts.map +1 -0
- package/dist/bot/task-queue.js +237 -0
- package/dist/bot/task-queue.js.map +1 -0
- package/dist/bot/task-store.d.ts +1 -6
- package/dist/bot/task-store.d.ts.map +1 -1
- package/dist/bot/task-store.js +27 -78
- package/dist/bot/task-store.js.map +1 -1
- package/dist/bot/task-types.d.ts +8 -4
- package/dist/bot/task-types.d.ts.map +1 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +2 -3
- package/dist/cli-handlers.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/docs/docs/weaver-bot-usage.md +35 -18
- package/dist/docs/docs/weaver-config.md +20 -0
- package/dist/docs/docs/weaver-task-queue.md +31 -19
- package/dist/docs/weaver-config.md +15 -9
- package/dist/mcp-tools.d.ts +17 -0
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +98 -232
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
- package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
- package/dist/node-types/orchestrator-dispatch.js +63 -0
- package/dist/node-types/orchestrator-dispatch.js.map +1 -0
- package/dist/node-types/orchestrator-load-state.d.ts +16 -0
- package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
- package/dist/node-types/orchestrator-load-state.js +60 -0
- package/dist/node-types/orchestrator-load-state.js.map +1 -0
- package/dist/node-types/orchestrator-route.d.ts +16 -0
- package/dist/node-types/orchestrator-route.d.ts.map +1 -0
- package/dist/node-types/orchestrator-route.js +28 -0
- package/dist/node-types/orchestrator-route.js.map +1 -0
- package/dist/node-types/receive-task.d.ts +2 -3
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +3 -28
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/templates/weaver-template.d.ts +11 -0
- package/dist/templates/weaver-template.d.ts.map +1 -0
- package/dist/templates/weaver-template.js +53 -0
- package/dist/templates/weaver-template.js.map +1 -0
- package/dist/ui/bot-constants.d.ts +14 -0
- package/dist/ui/bot-constants.d.ts.map +1 -0
- package/dist/ui/bot-constants.js +189 -0
- package/dist/ui/bot-constants.js.map +1 -0
- package/dist/ui/bot-panel.js +51 -90
- package/dist/ui/bot-slot-card.js +87 -122
- package/dist/ui/budget-bar.js +5 -3
- package/dist/ui/chat-task-result.js +4 -7
- package/dist/ui/decision-log.js +136 -0
- package/dist/ui/profile-card.js +158 -0
- package/dist/ui/profile-editor.js +597 -0
- package/dist/ui/swarm-controls.js +36 -27
- package/dist/ui/swarm-dashboard.js +2034 -736
- package/dist/ui/task-create-form.js +39 -116
- package/dist/ui/task-detail-view.js +490 -239
- package/dist/ui/task-pool-list.js +69 -94
- package/dist/workflows/orchestrator.d.ts +21 -0
- package/dist/workflows/orchestrator.d.ts.map +1 -0
- package/dist/workflows/orchestrator.js +281 -0
- package/dist/workflows/orchestrator.js.map +1 -0
- package/dist/workflows/weaver-bot-session.d.ts +65 -0
- package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
- package/dist/workflows/weaver-bot-session.js +68 -0
- package/dist/workflows/weaver-bot-session.js.map +1 -0
- package/dist/workflows/weaver.d.ts +24 -0
- package/dist/workflows/weaver.d.ts.map +1 -0
- package/dist/workflows/weaver.js +28 -0
- package/dist/workflows/weaver.js.map +1 -0
- package/flowweaver.manifest.json +253 -66
- package/package.json +1 -1
- package/src/ai-chat-provider.ts +184 -18
- package/src/bot/ai-router.ts +132 -0
- package/src/bot/bot-registry.ts +2 -2
- package/src/bot/conversation-store.ts +2 -1
- package/src/bot/improve-loop.ts +6 -6
- package/src/bot/instance-manager.ts +128 -0
- package/src/bot/orchestrator.ts +244 -0
- package/src/bot/profile-store.ts +225 -0
- package/src/bot/profile-types.ts +141 -0
- package/src/bot/swarm-controller.ts +385 -186
- package/src/bot/task-prompt-builder.ts +37 -6
- package/src/bot/task-store.ts +28 -89
- package/src/bot/task-types.ts +10 -4
- package/src/cli-handlers.ts +2 -3
- package/src/docs/weaver-bot-usage.md +35 -18
- package/src/docs/weaver-config.md +20 -0
- package/src/docs/weaver-task-queue.md +31 -19
- package/src/mcp-tools.ts +129 -320
- package/src/node-types/orchestrator-dispatch.ts +71 -0
- package/src/node-types/orchestrator-load-state.ts +66 -0
- package/src/node-types/orchestrator-route.ts +33 -0
- package/src/node-types/receive-task.ts +3 -26
- package/src/ui/bot-constants.ts +192 -0
- package/src/ui/bot-panel.tsx +55 -79
- package/src/ui/bot-slot-card.tsx +69 -117
- package/src/ui/budget-bar.tsx +5 -3
- package/src/ui/chat-task-result.tsx +6 -9
- package/src/ui/decision-log.tsx +148 -0
- package/src/ui/profile-card.tsx +157 -0
- package/src/ui/profile-editor.tsx +384 -0
- package/src/ui/swarm-controls.tsx +35 -31
- package/src/ui/swarm-dashboard.tsx +409 -80
- package/src/ui/task-create-form.tsx +29 -119
- package/src/ui/task-detail-view.tsx +461 -215
- package/src/ui/task-pool-list.tsx +74 -95
- package/src/workflows/orchestrator.ts +302 -0
- package/dist/docs/weaver-bot-usage.md +0 -34
- package/dist/docs/weaver-genesis.md +0 -32
- package/dist/docs/weaver-task-queue.md +0 -34
- package/src/bot/error-guide.ts +0 -4
- package/src/bot/retry-utils.ts +0 -4
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/ui/swarm-dashboard.tsx
|
|
@@ -37,17 +47,17 @@ var {
|
|
|
37
47
|
toast,
|
|
38
48
|
usePackWorkspace
|
|
39
49
|
} = require("@fw/plugin-ui-kit");
|
|
40
|
-
function
|
|
50
|
+
function swarmStatusToIconStatus(status) {
|
|
41
51
|
switch (status) {
|
|
42
52
|
case "running":
|
|
43
|
-
return "
|
|
53
|
+
return "running";
|
|
44
54
|
case "paused":
|
|
45
|
-
return "
|
|
55
|
+
return "pending";
|
|
46
56
|
case "stopping":
|
|
47
|
-
return "
|
|
57
|
+
return "failed";
|
|
48
58
|
case "idle":
|
|
49
59
|
default:
|
|
50
|
-
return "
|
|
60
|
+
return "completed";
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
function statusLabel(status) {
|
|
@@ -63,9 +73,9 @@ function statusLabel(status) {
|
|
|
63
73
|
return "Idle";
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
|
-
function
|
|
67
|
-
const entries = Object.values(
|
|
68
|
-
const active = entries.filter((
|
|
76
|
+
function countActiveInstances(instances) {
|
|
77
|
+
const entries = Object.values(instances);
|
|
78
|
+
const active = entries.filter((i) => i.status === "executing").length;
|
|
69
79
|
return { active, total: entries.length };
|
|
70
80
|
}
|
|
71
81
|
function SwarmControls({ swarmStatus, onRefresh }) {
|
|
@@ -74,8 +84,8 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
74
84
|
const [pausing, setPausing] = useState(false);
|
|
75
85
|
const [stopping, setStopping] = useState(false);
|
|
76
86
|
const status = swarmStatus?.status ?? "idle";
|
|
77
|
-
const
|
|
78
|
-
const { active, total } =
|
|
87
|
+
const instances = swarmStatus?.instances ?? {};
|
|
88
|
+
const { active, total } = countActiveInstances(instances);
|
|
79
89
|
const isIdle = status === "idle";
|
|
80
90
|
const isRunning = status === "running";
|
|
81
91
|
const isPaused = status === "paused";
|
|
@@ -133,6 +143,15 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
133
143
|
}, [ctx, onRefresh]);
|
|
134
144
|
const handleStop = useCallback(async () => {
|
|
135
145
|
setStopping(true);
|
|
146
|
+
const ok = await ctx.confirm("This will stop all running instances and abort active tasks.", {
|
|
147
|
+
title: "Stop Swarm",
|
|
148
|
+
confirmLabel: "Stop",
|
|
149
|
+
state: "danger"
|
|
150
|
+
});
|
|
151
|
+
if (!ok) {
|
|
152
|
+
setStopping(false);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
136
155
|
try {
|
|
137
156
|
const result = await ctx.callTool("fw_weaver_swarm_stop", {});
|
|
138
157
|
const data = result;
|
|
@@ -154,9 +173,9 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
154
173
|
{
|
|
155
174
|
variant: "row-center-space-between-nowrap-10",
|
|
156
175
|
style: {
|
|
157
|
-
flexShrink: 0,
|
|
158
176
|
padding: "8px 16px",
|
|
159
177
|
borderBottom: "1px solid var(--color-border-default)",
|
|
178
|
+
flexShrink: 0,
|
|
160
179
|
backgroundColor: isRunning ? "var(--color-brand-main-alpha-10)" : isPaused ? "var(--color-status-caution-alpha-10)" : "transparent"
|
|
161
180
|
}
|
|
162
181
|
},
|
|
@@ -165,12 +184,11 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
165
184
|
Flex,
|
|
166
185
|
{ variant: "row-center-start-nowrap-8", style: { flexShrink: 0 } },
|
|
167
186
|
React.createElement(StatusIcon, {
|
|
168
|
-
|
|
169
|
-
size:
|
|
187
|
+
status: swarmStatusToIconStatus(status),
|
|
188
|
+
size: "sm"
|
|
170
189
|
}),
|
|
171
190
|
React.createElement(Typography, {
|
|
172
|
-
variant: "caption-bold"
|
|
173
|
-
style: { textTransform: "capitalize" }
|
|
191
|
+
variant: "caption-bold"
|
|
174
192
|
}, statusLabel(status))
|
|
175
193
|
),
|
|
176
194
|
// Center: bot count + stats
|
|
@@ -178,7 +196,7 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
178
196
|
Flex,
|
|
179
197
|
{
|
|
180
198
|
variant: "row-center-start-nowrap-12",
|
|
181
|
-
style: { flex: 1
|
|
199
|
+
style: { flex: 1 }
|
|
182
200
|
},
|
|
183
201
|
total > 0 && React.createElement(Typography, {
|
|
184
202
|
variant: "caption-regular",
|
|
@@ -196,27 +214,29 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
196
214
|
// Right: action buttons
|
|
197
215
|
React.createElement(
|
|
198
216
|
Flex,
|
|
199
|
-
{ variant: "row-center-start-nowrap-
|
|
217
|
+
{ variant: "row-center-start-nowrap-4", style: { flexShrink: 0 } },
|
|
200
218
|
// Start / Resume button
|
|
201
219
|
(isIdle || isPaused) && React.createElement(Button, {
|
|
202
|
-
size: "
|
|
203
|
-
variant: "
|
|
220
|
+
size: "xs",
|
|
221
|
+
variant: "outlined",
|
|
222
|
+
color: "primary",
|
|
204
223
|
onClick: isPaused ? handleResume : handleStart,
|
|
205
224
|
loading: starting,
|
|
206
225
|
disabled: anyLoading
|
|
207
226
|
}, isPaused ? "Resume" : "Start"),
|
|
208
227
|
// Pause button (only when running)
|
|
209
228
|
isRunning && React.createElement(Button, {
|
|
210
|
-
size: "
|
|
211
|
-
variant: "
|
|
229
|
+
size: "xs",
|
|
230
|
+
variant: "outlined",
|
|
231
|
+
color: "warning",
|
|
212
232
|
onClick: handlePause,
|
|
213
233
|
loading: pausing,
|
|
214
234
|
disabled: anyLoading
|
|
215
235
|
}, "Pause"),
|
|
216
236
|
// Stop button (when running or paused)
|
|
217
237
|
(isRunning || isPaused) && React.createElement(Button, {
|
|
218
|
-
size: "
|
|
219
|
-
variant: "
|
|
238
|
+
size: "xs",
|
|
239
|
+
variant: "outlined",
|
|
220
240
|
color: "danger",
|
|
221
241
|
onClick: handleStop,
|
|
222
242
|
loading: stopping,
|
|
@@ -224,12 +244,11 @@ function SwarmControls({ swarmStatus, onRefresh }) {
|
|
|
224
244
|
}, "Stop"),
|
|
225
245
|
// Refresh button (always available)
|
|
226
246
|
React.createElement(IconButton, {
|
|
227
|
-
icon: "
|
|
247
|
+
icon: "reset",
|
|
228
248
|
size: "xs",
|
|
229
|
-
variant: "
|
|
249
|
+
variant: "outlined",
|
|
230
250
|
onClick: onRefresh,
|
|
231
|
-
disabled: anyLoading
|
|
232
|
-
title: "Refresh swarm status"
|
|
251
|
+
disabled: anyLoading
|
|
233
252
|
})
|
|
234
253
|
)
|
|
235
254
|
);
|
|
@@ -257,11 +276,13 @@ function BudgetBar({ label, used, limit, unit }) {
|
|
|
257
276
|
)
|
|
258
277
|
),
|
|
259
278
|
React2.createElement(
|
|
260
|
-
|
|
279
|
+
Flex2,
|
|
261
280
|
{
|
|
262
|
-
|
|
281
|
+
variant: "row-start-start-nowrap-0",
|
|
282
|
+
style: { width: "100%", height: "4px", borderRadius: "2px", backgroundColor: "var(--color-surface-raised)", overflow: "hidden" }
|
|
263
283
|
},
|
|
264
|
-
React2.createElement(
|
|
284
|
+
React2.createElement(Flex2, {
|
|
285
|
+
variant: "row-start-start-nowrap-0",
|
|
265
286
|
style: { width: `${pct}%`, height: "100%", borderRadius: "2px", backgroundColor: color, transition: "width 0.3s" }
|
|
266
287
|
})
|
|
267
288
|
)
|
|
@@ -271,20 +292,8 @@ var budget_bar_default = BudgetBar;
|
|
|
271
292
|
module.exports = BudgetBar;
|
|
272
293
|
|
|
273
294
|
// src/ui/bot-slot-card.tsx
|
|
274
|
-
var
|
|
275
|
-
var
|
|
276
|
-
var statusToDot = {
|
|
277
|
-
idle: "neutral",
|
|
278
|
-
executing: "info",
|
|
279
|
-
paused: "caution",
|
|
280
|
-
stopped: "negative"
|
|
281
|
-
};
|
|
282
|
-
var statusToIcon = {
|
|
283
|
-
idle: "pending",
|
|
284
|
-
executing: "running",
|
|
285
|
-
paused: "pause",
|
|
286
|
-
stopped: "stop"
|
|
287
|
-
};
|
|
295
|
+
var import_react = __toESM(require("react"), 1);
|
|
296
|
+
var import_plugin_ui_kit = require("@fw/plugin-ui-kit");
|
|
288
297
|
var statusToLabel = {
|
|
289
298
|
idle: "Idle",
|
|
290
299
|
executing: "Executing",
|
|
@@ -300,133 +309,100 @@ function formatCost(n) {
|
|
|
300
309
|
if (n < 0.01 && n > 0) return "<$0.01";
|
|
301
310
|
return `$${n.toFixed(2)}`;
|
|
302
311
|
}
|
|
303
|
-
function BotSlotCard({ bot, currentTaskTitle, onPause, onResume, onStop }) {
|
|
312
|
+
function BotSlotCard({ bot, currentTaskTitle, profileName, botDisplayName, botIcon, botColor, onPause, onResume, onStop }) {
|
|
304
313
|
const { botId, botName, status, currentTaskId, tokensUsed, cost } = bot;
|
|
305
|
-
const dotStatus = statusToDot[status] ?? "neutral";
|
|
306
|
-
const iconName = statusToIcon[status] ?? "pending";
|
|
307
|
-
const label = statusToLabel[status] ?? status;
|
|
308
314
|
const isExecuting = status === "executing";
|
|
309
315
|
const isPaused = status === "paused";
|
|
310
|
-
const
|
|
311
|
-
const taskText = isExecuting ? currentTaskTitle || currentTaskId || "
|
|
312
|
-
|
|
313
|
-
|
|
316
|
+
const label = statusToLabel[status] ?? status;
|
|
317
|
+
const taskText = isExecuting ? currentTaskTitle || currentTaskId || "-" : "-";
|
|
318
|
+
return import_react.default.createElement(
|
|
319
|
+
import_plugin_ui_kit.Flex,
|
|
314
320
|
{
|
|
315
|
-
variant: "row-center-
|
|
316
|
-
style: {
|
|
321
|
+
variant: "row-center-start-nowrap-8",
|
|
322
|
+
style: { padding: "6px 16px", minHeight: "38px", borderBottom: "1px solid var(--color-border-default)" }
|
|
317
323
|
},
|
|
318
|
-
//
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
icon: "playArrow",
|
|
331
|
-
size: "xs",
|
|
332
|
-
variant: "clear",
|
|
333
|
-
onClick: (e) => {
|
|
334
|
-
e.stopPropagation();
|
|
335
|
-
onResume(botId);
|
|
336
|
-
},
|
|
337
|
-
title: "Resume bot"
|
|
338
|
-
}) : null,
|
|
339
|
-
// Stop button (available when executing or paused)
|
|
340
|
-
(isExecuting || isPaused) && onStop ? React3.createElement(IconButton2, {
|
|
341
|
-
icon: "stop",
|
|
342
|
-
size: "xs",
|
|
343
|
-
variant: "clear",
|
|
344
|
-
onClick: (e) => {
|
|
345
|
-
e.stopPropagation();
|
|
346
|
-
onStop(botId);
|
|
324
|
+
// Instance name
|
|
325
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
326
|
+
variant: "smallCaption-regular",
|
|
327
|
+
color: "color-text-high",
|
|
328
|
+
style: { width: "120px", flexShrink: 0 }
|
|
329
|
+
}, profileName ? `${profileName} #${botId.split("-").pop() ?? "0"}` : botName),
|
|
330
|
+
// Bot (icon + name)
|
|
331
|
+
import_react.default.createElement(
|
|
332
|
+
import_plugin_ui_kit.Flex,
|
|
333
|
+
{
|
|
334
|
+
variant: "row-center-start-nowrap-4",
|
|
335
|
+
style: { width: "110px", flexShrink: 0, color: botColor ? `var(--${botColor})` : void 0 }
|
|
347
336
|
},
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
"div",
|
|
354
|
-
{
|
|
355
|
-
style: {
|
|
356
|
-
width: "120px",
|
|
357
|
-
minWidth: "120px",
|
|
358
|
-
padding: "8px",
|
|
359
|
-
borderRadius: "var(--border-radius-secondary)",
|
|
360
|
-
border: "1px solid var(--color-border-default)",
|
|
361
|
-
backgroundColor: "var(--color-surface-elevated)",
|
|
362
|
-
display: "flex",
|
|
363
|
-
flexDirection: "column",
|
|
364
|
-
gap: "4px",
|
|
365
|
-
flexShrink: 0
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
// Row 1: Status icon + bot name
|
|
369
|
-
React3.createElement(
|
|
370
|
-
Flex3,
|
|
371
|
-
{ variant: "row-center-start-nowrap-4" },
|
|
372
|
-
React3.createElement(Icon, {
|
|
373
|
-
name: iconName,
|
|
374
|
-
size: 12,
|
|
375
|
-
color: iconColor
|
|
376
|
-
}),
|
|
377
|
-
React3.createElement(Typography3, {
|
|
378
|
-
variant: "caption-thick",
|
|
379
|
-
color: "color-text-high",
|
|
380
|
-
style: {
|
|
381
|
-
overflow: "hidden",
|
|
382
|
-
textOverflow: "ellipsis",
|
|
383
|
-
whiteSpace: "nowrap",
|
|
384
|
-
flex: 1,
|
|
385
|
-
minWidth: 0
|
|
386
|
-
}
|
|
387
|
-
}, botName)
|
|
337
|
+
import_react.default.createElement(import_plugin_ui_kit.Icon, { name: botIcon || "smartToy", size: 12 }),
|
|
338
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
339
|
+
variant: "smallCaption-regular",
|
|
340
|
+
color: "color-text-subtle"
|
|
341
|
+
}, botDisplayName || "-")
|
|
388
342
|
),
|
|
389
|
-
//
|
|
390
|
-
|
|
343
|
+
// Status
|
|
344
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
391
345
|
variant: "smallCaption-regular",
|
|
392
|
-
color:
|
|
393
|
-
style: {
|
|
346
|
+
color: isExecuting ? "color-brand-main" : "color-text-subtle",
|
|
347
|
+
style: { width: "70px", flexShrink: 0 }
|
|
394
348
|
}, label),
|
|
395
|
-
//
|
|
396
|
-
|
|
349
|
+
// Current task
|
|
350
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
397
351
|
variant: "smallCaption-regular",
|
|
398
|
-
color: "color-text-medium",
|
|
399
|
-
style: {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
352
|
+
color: isExecuting ? "color-text-medium" : "color-text-subtle",
|
|
353
|
+
style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
|
|
354
|
+
}, taskText),
|
|
355
|
+
// Tokens
|
|
356
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
357
|
+
variant: "smallCaption-regular",
|
|
358
|
+
color: "color-text-subtle",
|
|
359
|
+
style: { width: "50px", flexShrink: 0, textAlign: "right" }
|
|
360
|
+
}, formatTokens(tokensUsed)),
|
|
361
|
+
// Cost
|
|
362
|
+
import_react.default.createElement(import_plugin_ui_kit.Typography, {
|
|
363
|
+
variant: "smallCaption-regular",
|
|
364
|
+
color: "color-text-subtle",
|
|
365
|
+
style: { width: "50px", flexShrink: 0, textAlign: "right" }
|
|
366
|
+
}, formatCost(cost)),
|
|
367
|
+
// Actions
|
|
368
|
+
import_react.default.createElement(
|
|
369
|
+
import_plugin_ui_kit.Flex,
|
|
370
|
+
{
|
|
371
|
+
variant: "row-center-end-nowrap-1",
|
|
372
|
+
style: { width: "50px", flexShrink: 0 }
|
|
373
|
+
},
|
|
374
|
+
isExecuting && onPause && import_react.default.createElement(import_plugin_ui_kit.IconButton, {
|
|
375
|
+
icon: "pause",
|
|
376
|
+
size: "xs",
|
|
377
|
+
variant: "clear",
|
|
378
|
+
onClick: () => onPause(botId),
|
|
379
|
+
title: "Pause"
|
|
380
|
+
}),
|
|
381
|
+
isPaused && onResume && import_react.default.createElement(import_plugin_ui_kit.IconButton, {
|
|
382
|
+
icon: "playArrow",
|
|
383
|
+
size: "xs",
|
|
384
|
+
variant: "clear",
|
|
385
|
+
onClick: () => onResume(botId),
|
|
386
|
+
title: "Resume"
|
|
387
|
+
}),
|
|
388
|
+
(isExecuting || isPaused) && onStop && import_react.default.createElement(import_plugin_ui_kit.IconButton, {
|
|
389
|
+
icon: "stop",
|
|
390
|
+
size: "xs",
|
|
391
|
+
variant: "clear",
|
|
392
|
+
color: "danger",
|
|
393
|
+
onClick: () => onStop(botId),
|
|
394
|
+
title: "Stop"
|
|
395
|
+
})
|
|
396
|
+
)
|
|
420
397
|
);
|
|
421
398
|
}
|
|
422
399
|
var bot_slot_card_default = BotSlotCard;
|
|
423
|
-
module.exports = BotSlotCard;
|
|
424
400
|
|
|
425
401
|
// src/ui/task-pool-list.tsx
|
|
426
402
|
var React4 = require("react");
|
|
427
|
-
var {
|
|
428
|
-
var {
|
|
429
|
-
var
|
|
403
|
+
var { useState: useState2 } = React4;
|
|
404
|
+
var { Flex: Flex4, Typography: Typography4, Icon: Icon2, StatusIcon: StatusIcon2, Tag, ScrollArea, Badge, EmptyState } = require("@fw/plugin-ui-kit");
|
|
405
|
+
var statusToIcon = {
|
|
430
406
|
"pending": "pending",
|
|
431
407
|
"in-progress": "running",
|
|
432
408
|
"done": "completed",
|
|
@@ -434,50 +410,15 @@ var statusToIcon2 = {
|
|
|
434
410
|
"blocked": "pending",
|
|
435
411
|
"cancelled": "failed"
|
|
436
412
|
};
|
|
437
|
-
var
|
|
438
|
-
"pending": "color-text-subtle",
|
|
439
|
-
"in-progress": "color-status-info",
|
|
440
|
-
"done": "color-status-positive",
|
|
441
|
-
"failed": "color-status-negative",
|
|
442
|
-
"blocked": "color-status-caution",
|
|
443
|
-
"cancelled": "color-text-subtle"
|
|
444
|
-
};
|
|
445
|
-
var Container = styled.div({
|
|
446
|
-
display: "flex",
|
|
447
|
-
flexDirection: "column",
|
|
448
|
-
height: "100%",
|
|
449
|
-
overflow: "hidden"
|
|
450
|
-
});
|
|
451
|
-
var TaskRow = styled.div({
|
|
452
|
-
display: "flex",
|
|
453
|
-
alignItems: "center",
|
|
454
|
-
gap: "8px",
|
|
413
|
+
var rowBaseStyle = {
|
|
455
414
|
padding: "8px 12px",
|
|
456
415
|
cursor: "pointer",
|
|
457
|
-
borderBottom: "1px solid
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
textOverflow: "ellipsis",
|
|
464
|
-
whiteSpace: "nowrap",
|
|
465
|
-
minWidth: 0
|
|
466
|
-
});
|
|
467
|
-
var BotTags = styled.div({
|
|
468
|
-
display: "flex",
|
|
469
|
-
gap: "4px",
|
|
470
|
-
flexShrink: 0
|
|
471
|
-
});
|
|
472
|
-
var EmptyState = styled.div({
|
|
473
|
-
display: "flex",
|
|
474
|
-
flexDirection: "column",
|
|
475
|
-
alignItems: "center",
|
|
476
|
-
justifyContent: "center",
|
|
477
|
-
gap: "8px",
|
|
478
|
-
padding: "24px 16px",
|
|
479
|
-
flex: 1
|
|
480
|
-
});
|
|
416
|
+
borderBottom: "1px solid var(--color-border-default)"
|
|
417
|
+
};
|
|
418
|
+
var indentedRowStyle = {
|
|
419
|
+
...rowBaseStyle,
|
|
420
|
+
paddingLeft: "32px"
|
|
421
|
+
};
|
|
481
422
|
function sortTasks(tasks) {
|
|
482
423
|
return [...tasks].sort((a, b) => {
|
|
483
424
|
if (b.priority !== a.priority) return b.priority - a.priority;
|
|
@@ -513,65 +454,75 @@ function buildHierarchy(tasks) {
|
|
|
513
454
|
}
|
|
514
455
|
return result;
|
|
515
456
|
}
|
|
516
|
-
function
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
457
|
+
function TaskRowItem({ task, indent, onClick }) {
|
|
458
|
+
const [hovered, setHovered] = useState2(false);
|
|
459
|
+
const style = {
|
|
460
|
+
...indent ? indentedRowStyle : rowBaseStyle,
|
|
461
|
+
...hovered ? { backgroundColor: "var(--color-surface-elevated)" } : void 0
|
|
462
|
+
};
|
|
463
|
+
return React4.createElement(
|
|
464
|
+
Flex4,
|
|
465
|
+
{
|
|
466
|
+
variant: "row-center-start-nowrap-8",
|
|
467
|
+
style,
|
|
468
|
+
onClick,
|
|
469
|
+
onMouseEnter: () => setHovered(true),
|
|
470
|
+
onMouseLeave: () => setHovered(false)
|
|
471
|
+
},
|
|
472
|
+
// Status icon
|
|
473
|
+
React4.createElement(StatusIcon2, {
|
|
474
|
+
status: statusToIcon[task.status] || "pending",
|
|
475
|
+
size: "sm"
|
|
476
|
+
}),
|
|
477
|
+
// Title
|
|
478
|
+
React4.createElement(
|
|
479
|
+
Flex4,
|
|
480
|
+
{
|
|
481
|
+
variant: "row-center-start-nowrap-0",
|
|
482
|
+
style: { flex: 1, minWidth: 0 }
|
|
483
|
+
},
|
|
522
484
|
React4.createElement(Typography4, {
|
|
523
485
|
variant: "caption-regular",
|
|
524
|
-
color: "color-text-subtle"
|
|
525
|
-
|
|
526
|
-
|
|
486
|
+
color: task.status === "cancelled" ? "color-text-subtle" : "color-text-high",
|
|
487
|
+
truncate: true,
|
|
488
|
+
style: task.status === "cancelled" ? { textDecoration: "line-through", opacity: 0.6 } : void 0
|
|
489
|
+
}, task.title)
|
|
490
|
+
),
|
|
491
|
+
// Assigned profile as Tag
|
|
492
|
+
task.assignedProfile && React4.createElement(Tag, {
|
|
493
|
+
size: "small",
|
|
494
|
+
color: "info"
|
|
495
|
+
}, task.assignedProfile),
|
|
496
|
+
// Priority badge (only if > 0)
|
|
497
|
+
task.priority > 0 && React4.createElement(Badge, {
|
|
498
|
+
variant: task.priority >= 3 ? "warning" : "info"
|
|
499
|
+
}, `P${task.priority}`)
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
function TaskPoolList({ tasks, onTaskClick }) {
|
|
503
|
+
if (!tasks || tasks.length === 0) {
|
|
504
|
+
return React4.createElement(EmptyState, {
|
|
505
|
+
icon: "inbox",
|
|
506
|
+
message: "No tasks in the pool."
|
|
507
|
+
});
|
|
527
508
|
}
|
|
528
509
|
const rows = buildHierarchy(tasks);
|
|
529
510
|
return React4.createElement(
|
|
530
|
-
|
|
531
|
-
|
|
511
|
+
Flex4,
|
|
512
|
+
{
|
|
513
|
+
variant: "column-stretch-start-nowrap-0",
|
|
514
|
+
style: { height: "100%", overflow: "hidden" }
|
|
515
|
+
},
|
|
532
516
|
React4.createElement(
|
|
533
517
|
ScrollArea,
|
|
534
518
|
{ style: { flex: 1 } },
|
|
535
519
|
rows.map(
|
|
536
|
-
({ task, indent }) => React4.createElement(
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
},
|
|
543
|
-
// Status icon
|
|
544
|
-
React4.createElement(StatusIcon3, {
|
|
545
|
-
status: statusToIcon2[task.status] || "pending",
|
|
546
|
-
size: "sm"
|
|
547
|
-
}),
|
|
548
|
-
// Title
|
|
549
|
-
React4.createElement(
|
|
550
|
-
TitleText,
|
|
551
|
-
null,
|
|
552
|
-
React4.createElement(Typography4, {
|
|
553
|
-
variant: "caption-regular",
|
|
554
|
-
color: statusToColor[task.status] === "color-text-subtle" && task.status === "cancelled" ? "color-text-subtle" : "color-text-high",
|
|
555
|
-
style: task.status === "cancelled" ? { textDecoration: "line-through", opacity: 0.6 } : void 0
|
|
556
|
-
}, task.title)
|
|
557
|
-
),
|
|
558
|
-
// Assigned bots as Tags
|
|
559
|
-
task.assignedBots.length > 0 && React4.createElement(
|
|
560
|
-
BotTags,
|
|
561
|
-
null,
|
|
562
|
-
task.assignedBots.map(
|
|
563
|
-
(botId) => React4.createElement(Tag, {
|
|
564
|
-
key: botId,
|
|
565
|
-
size: "small",
|
|
566
|
-
color: "info"
|
|
567
|
-
}, botId)
|
|
568
|
-
)
|
|
569
|
-
),
|
|
570
|
-
// Priority badge (only if > 0)
|
|
571
|
-
task.priority > 0 && React4.createElement(Badge, {
|
|
572
|
-
variant: task.priority >= 3 ? "warning" : "info"
|
|
573
|
-
}, `P${task.priority}`)
|
|
574
|
-
)
|
|
520
|
+
({ task, indent }) => React4.createElement(TaskRowItem, {
|
|
521
|
+
key: task.id,
|
|
522
|
+
task,
|
|
523
|
+
indent,
|
|
524
|
+
onClick: () => onTaskClick(task.id)
|
|
525
|
+
})
|
|
575
526
|
)
|
|
576
527
|
)
|
|
577
528
|
);
|
|
@@ -580,16 +531,9 @@ var task_pool_list_default = TaskPoolList;
|
|
|
580
531
|
module.exports = TaskPoolList;
|
|
581
532
|
|
|
582
533
|
// src/ui/task-create-form.tsx
|
|
583
|
-
var
|
|
584
|
-
var
|
|
585
|
-
var {
|
|
586
|
-
Flex: Flex5,
|
|
587
|
-
Typography: Typography5,
|
|
588
|
-
Input,
|
|
589
|
-
Button: Button2,
|
|
590
|
-
toast: toast2,
|
|
591
|
-
usePackWorkspace: usePackWorkspace2
|
|
592
|
-
} = require("@fw/plugin-ui-kit");
|
|
534
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
535
|
+
var import_plugin_ui_kit2 = require("@fw/plugin-ui-kit");
|
|
536
|
+
var { useState: useState3, useCallback: useCallback2 } = import_react2.default;
|
|
593
537
|
function parseToolResult(raw) {
|
|
594
538
|
if (typeof raw === "string") {
|
|
595
539
|
try {
|
|
@@ -601,140 +545,60 @@ function parseToolResult(raw) {
|
|
|
601
545
|
return raw;
|
|
602
546
|
}
|
|
603
547
|
function TaskCreateForm({ onTaskCreated }) {
|
|
604
|
-
const ctx =
|
|
548
|
+
const ctx = (0, import_plugin_ui_kit2.usePackWorkspace)();
|
|
605
549
|
const { callTool } = ctx;
|
|
606
|
-
const [
|
|
607
|
-
const [
|
|
608
|
-
const [description, setDescription] = useState2("");
|
|
609
|
-
const [priority, setPriority] = useState2("0");
|
|
610
|
-
const [creating, setCreating] = useState2(false);
|
|
611
|
-
const toggleOpen = useCallback2(() => setOpen((v) => !v), []);
|
|
550
|
+
const [title, setTitle] = useState3("");
|
|
551
|
+
const [creating, setCreating] = useState3(false);
|
|
612
552
|
const handleCreate = useCallback2(async () => {
|
|
613
|
-
const
|
|
614
|
-
if (!
|
|
615
|
-
toast2("Title is required", { type: "error" });
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
553
|
+
const trimmed = title.trim();
|
|
554
|
+
if (!trimmed) return;
|
|
618
555
|
setCreating(true);
|
|
619
556
|
try {
|
|
620
|
-
const raw = await callTool("fw_weaver_task_create", {
|
|
621
|
-
title: trimmedTitle,
|
|
622
|
-
description: description.trim() || void 0,
|
|
623
|
-
priority: Number(priority) || 0
|
|
624
|
-
});
|
|
557
|
+
const raw = await callTool("fw_weaver_task_create", { title: trimmed });
|
|
625
558
|
const result = parseToolResult(raw);
|
|
626
|
-
|
|
627
|
-
toast2(`Task created: ${taskTitle}`, { type: "success" });
|
|
559
|
+
(0, import_plugin_ui_kit2.toast)(`Task created: ${result?.task?.title ?? trimmed}`, { type: "success" });
|
|
628
560
|
setTitle("");
|
|
629
|
-
setDescription("");
|
|
630
|
-
setPriority("0");
|
|
631
561
|
onTaskCreated?.();
|
|
632
562
|
} catch (err) {
|
|
633
|
-
|
|
563
|
+
(0, import_plugin_ui_kit2.toast)(err instanceof Error ? err.message : "Failed to create task", { type: "error" });
|
|
634
564
|
} finally {
|
|
635
565
|
setCreating(false);
|
|
636
566
|
}
|
|
637
|
-
}, [title,
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
size: "sm",
|
|
641
|
-
onClick: toggleOpen,
|
|
642
|
-
style: { width: "100%" }
|
|
643
|
-
}, open ? "\u25BE Hide create form" : "\u25B8 Create new task");
|
|
644
|
-
if (!open) {
|
|
645
|
-
return React5.createElement(Flex5, {
|
|
646
|
-
variant: "column-start-start-nowrap-4",
|
|
647
|
-
style: { width: "100%" }
|
|
648
|
-
}, toggleButton);
|
|
649
|
-
}
|
|
650
|
-
const titleField = React5.createElement(
|
|
651
|
-
Flex5,
|
|
567
|
+
}, [title, callTool, onTaskCreated]);
|
|
568
|
+
return import_react2.default.createElement(
|
|
569
|
+
import_plugin_ui_kit2.Flex,
|
|
652
570
|
{
|
|
653
|
-
variant: "
|
|
654
|
-
style: { width: "100%" }
|
|
571
|
+
variant: "row-center-start-nowrap-6"
|
|
655
572
|
},
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
573
|
+
import_react2.default.createElement(import_plugin_ui_kit2.Input, {
|
|
574
|
+
type: "text",
|
|
575
|
+
size: "small",
|
|
576
|
+
placeholder: "What needs to be done?",
|
|
659
577
|
value: title,
|
|
660
578
|
onChange: (v) => setTitle(v),
|
|
661
|
-
|
|
662
|
-
})
|
|
663
|
-
);
|
|
664
|
-
const descriptionField = React5.createElement(
|
|
665
|
-
Flex5,
|
|
666
|
-
{
|
|
667
|
-
variant: "column-start-start-nowrap-2",
|
|
668
|
-
style: { width: "100%" }
|
|
669
|
-
},
|
|
670
|
-
React5.createElement(Typography5, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Description"),
|
|
671
|
-
React5.createElement(Input, {
|
|
672
|
-
placeholder: "Detailed instructions for the task",
|
|
673
|
-
value: description,
|
|
674
|
-
onChange: (v) => setDescription(v),
|
|
579
|
+
onEnter: handleCreate,
|
|
675
580
|
disabled: creating,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
variant: "
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
placeholder: "0",
|
|
688
|
-
value: priority,
|
|
689
|
-
onChange: (v) => setPriority(v),
|
|
690
|
-
disabled: creating,
|
|
691
|
-
type: "number"
|
|
581
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
582
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
583
|
+
}),
|
|
584
|
+
import_react2.default.createElement(import_plugin_ui_kit2.IconButton, {
|
|
585
|
+
icon: "add",
|
|
586
|
+
size: "sm",
|
|
587
|
+
variant: "fill",
|
|
588
|
+
color: "primary",
|
|
589
|
+
onClick: handleCreate,
|
|
590
|
+
disabled: creating || !title.trim(),
|
|
591
|
+
loading: creating
|
|
692
592
|
})
|
|
693
593
|
);
|
|
694
|
-
const createButton = React5.createElement(Button2, {
|
|
695
|
-
variant: "primary",
|
|
696
|
-
size: "sm",
|
|
697
|
-
onClick: handleCreate,
|
|
698
|
-
disabled: creating || !title.trim(),
|
|
699
|
-
style: { width: "100%" }
|
|
700
|
-
}, creating ? "Creating\u2026" : "Create Task");
|
|
701
|
-
return React5.createElement(
|
|
702
|
-
Flex5,
|
|
703
|
-
{
|
|
704
|
-
variant: "column-start-start-nowrap-4",
|
|
705
|
-
style: {
|
|
706
|
-
width: "100%",
|
|
707
|
-
padding: "0"
|
|
708
|
-
}
|
|
709
|
-
},
|
|
710
|
-
toggleButton,
|
|
711
|
-
React5.createElement(
|
|
712
|
-
Flex5,
|
|
713
|
-
{
|
|
714
|
-
variant: "column-start-start-nowrap-8",
|
|
715
|
-
style: {
|
|
716
|
-
width: "100%",
|
|
717
|
-
padding: "8px",
|
|
718
|
-
borderRadius: "6px",
|
|
719
|
-
backgroundColor: "var(--color-surface-raised)"
|
|
720
|
-
}
|
|
721
|
-
},
|
|
722
|
-
React5.createElement(Typography5, { variant: "caption-medium" }, "New Task"),
|
|
723
|
-
titleField,
|
|
724
|
-
descriptionField,
|
|
725
|
-
priorityField,
|
|
726
|
-
createButton
|
|
727
|
-
)
|
|
728
|
-
);
|
|
729
594
|
}
|
|
730
595
|
var task_create_form_default = TaskCreateForm;
|
|
731
|
-
module.exports = TaskCreateForm;
|
|
732
596
|
|
|
733
597
|
// src/ui/use-stream-timeline.ts
|
|
734
598
|
var React6 = require("react");
|
|
735
|
-
var { useMemo, useState:
|
|
599
|
+
var { useMemo, useState: useState4, useEffect, useRef } = React6;
|
|
736
600
|
function useStreamTimeline(events, isDone) {
|
|
737
|
-
const [elapsed, setElapsed] =
|
|
601
|
+
const [elapsed, setElapsed] = useState4(0);
|
|
738
602
|
const startTimeRef = useRef(null);
|
|
739
603
|
useEffect(() => {
|
|
740
604
|
if (events.length === 0) {
|
|
@@ -992,23 +856,29 @@ function traceToTimeline(run) {
|
|
|
992
856
|
|
|
993
857
|
// src/ui/task-detail-view.tsx
|
|
994
858
|
var React7 = require("react");
|
|
995
|
-
var { useState:
|
|
859
|
+
var { useState: useState5, useEffect: useEffect2, useCallback: useCallback3, useRef: useRef2, useMemo: useMemo2 } = React7;
|
|
996
860
|
var {
|
|
997
861
|
Flex: Flex6,
|
|
998
|
-
Typography:
|
|
862
|
+
Typography: Typography5,
|
|
999
863
|
ScrollArea: ScrollArea2,
|
|
1000
|
-
StatusIcon:
|
|
864
|
+
StatusIcon: StatusIcon3,
|
|
1001
865
|
Tag: Tag2,
|
|
1002
866
|
Badge: Badge2,
|
|
1003
867
|
Icon: Icon3,
|
|
868
|
+
IconButton: IconButton4,
|
|
1004
869
|
TaskBlock,
|
|
1005
|
-
Button:
|
|
870
|
+
Button: Button2,
|
|
871
|
+
Card,
|
|
872
|
+
Chip,
|
|
873
|
+
Checkbox,
|
|
874
|
+
Table,
|
|
875
|
+
Tabs,
|
|
876
|
+
EmptyState: EmptyState2,
|
|
1006
877
|
toast: toast3,
|
|
1007
878
|
usePackWorkspace: usePackWorkspace3,
|
|
1008
879
|
useEventStream
|
|
1009
880
|
} = require("@fw/plugin-ui-kit");
|
|
1010
|
-
var
|
|
1011
|
-
var statusToIcon3 = {
|
|
881
|
+
var statusToIcon2 = {
|
|
1012
882
|
"pending": "pending",
|
|
1013
883
|
"in-progress": "running",
|
|
1014
884
|
"done": "completed",
|
|
@@ -1024,92 +894,84 @@ var statusToLabel2 = {
|
|
|
1024
894
|
"blocked": "Blocked",
|
|
1025
895
|
"cancelled": "Cancelled"
|
|
1026
896
|
};
|
|
1027
|
-
var
|
|
1028
|
-
var Container2 = styled2.div({
|
|
1029
|
-
display: "flex",
|
|
1030
|
-
flexDirection: "column",
|
|
1031
|
-
width: "100%",
|
|
1032
|
-
height: "100%",
|
|
1033
|
-
overflow: "hidden"
|
|
1034
|
-
});
|
|
1035
|
-
var Header = styled2.div({
|
|
897
|
+
var headerStyle = {
|
|
1036
898
|
padding: "12px 16px",
|
|
1037
|
-
borderBottom: "1px solid
|
|
1038
|
-
display: "flex",
|
|
1039
|
-
flexDirection: "column",
|
|
1040
|
-
gap: "8px",
|
|
899
|
+
borderBottom: "1px solid var(--color-border-default)",
|
|
1041
900
|
flexShrink: 0
|
|
1042
|
-
}
|
|
1043
|
-
var
|
|
1044
|
-
display: "flex",
|
|
1045
|
-
alignItems: "center",
|
|
1046
|
-
gap: "8px"
|
|
1047
|
-
});
|
|
1048
|
-
var HeaderMeta = styled2.div({
|
|
1049
|
-
display: "flex",
|
|
1050
|
-
alignItems: "center",
|
|
1051
|
-
gap: "8px",
|
|
1052
|
-
flexWrap: "wrap"
|
|
1053
|
-
});
|
|
1054
|
-
var Section = styled2.div({
|
|
1055
|
-
padding: "12px 16px",
|
|
1056
|
-
borderBottom: "1px solid $color-border-default"
|
|
1057
|
-
});
|
|
1058
|
-
var SectionTitle = styled2.div({
|
|
1059
|
-
marginBottom: "8px"
|
|
1060
|
-
});
|
|
1061
|
-
var FileList = styled2.div({
|
|
1062
|
-
display: "flex",
|
|
1063
|
-
flexDirection: "column",
|
|
1064
|
-
gap: "2px"
|
|
1065
|
-
});
|
|
1066
|
-
var FileItem = styled2.div({
|
|
901
|
+
};
|
|
902
|
+
var fileItemStyle = {
|
|
1067
903
|
fontFamily: "monospace",
|
|
1068
904
|
fontSize: "12px",
|
|
1069
|
-
color: "
|
|
905
|
+
color: "var(--color-text-mid)",
|
|
1070
906
|
padding: "2px 4px",
|
|
1071
|
-
borderRadius: "4px"
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
lineHeight: 1.5,
|
|
1079
|
-
padding: "4px 0"
|
|
1080
|
-
});
|
|
1081
|
-
var SubtaskRow = styled2.div({
|
|
1082
|
-
display: "flex",
|
|
1083
|
-
alignItems: "center",
|
|
1084
|
-
gap: "8px",
|
|
907
|
+
borderRadius: "4px"
|
|
908
|
+
};
|
|
909
|
+
var fileItemHoverStyle = {
|
|
910
|
+
...fileItemStyle,
|
|
911
|
+
backgroundColor: "var(--color-surface-elevated)"
|
|
912
|
+
};
|
|
913
|
+
var subtaskRowStyle = {
|
|
1085
914
|
padding: "6px 8px",
|
|
1086
915
|
cursor: "pointer",
|
|
1087
|
-
borderRadius: "6px"
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
916
|
+
borderRadius: "6px"
|
|
917
|
+
};
|
|
918
|
+
var subtaskRowHoverStyle = {
|
|
919
|
+
...subtaskRowStyle,
|
|
920
|
+
backgroundColor: "var(--color-surface-elevated)"
|
|
921
|
+
};
|
|
922
|
+
function SubtaskRowItem({ sub, onBack }) {
|
|
923
|
+
const [hovered, setHovered] = useState5(false);
|
|
924
|
+
return React7.createElement(
|
|
925
|
+
Flex6,
|
|
926
|
+
{
|
|
927
|
+
variant: "row-center-start-nowrap-8",
|
|
928
|
+
style: hovered ? subtaskRowHoverStyle : subtaskRowStyle,
|
|
929
|
+
onClick: () => onBack(),
|
|
930
|
+
onMouseEnter: () => setHovered(true),
|
|
931
|
+
onMouseLeave: () => setHovered(false)
|
|
932
|
+
},
|
|
933
|
+
React7.createElement(StatusIcon3, {
|
|
934
|
+
status: statusToIcon2[sub.status] || "pending",
|
|
935
|
+
size: "sm"
|
|
936
|
+
}),
|
|
937
|
+
React7.createElement(
|
|
938
|
+
Flex6,
|
|
939
|
+
{
|
|
940
|
+
variant: "row-center-start-nowrap-0",
|
|
941
|
+
style: { flex: 1, minWidth: 0 }
|
|
942
|
+
},
|
|
943
|
+
React7.createElement(Typography5, { variant: "caption-regular", truncate: true }, sub.title)
|
|
944
|
+
),
|
|
945
|
+
sub.assignedProfile && React7.createElement(Tag2, {
|
|
946
|
+
size: "small",
|
|
947
|
+
color: "info"
|
|
948
|
+
}, sub.assignedProfile),
|
|
949
|
+
React7.createElement(Typography5, {
|
|
950
|
+
variant: "caption-regular",
|
|
951
|
+
color: "color-text-subtle"
|
|
952
|
+
}, `#${sub.attempt}`)
|
|
953
|
+
);
|
|
954
|
+
}
|
|
1097
955
|
function TaskDetailView({ taskId, onBack }) {
|
|
1098
956
|
const ctx = usePackWorkspace3();
|
|
1099
957
|
const { callTool } = ctx;
|
|
1100
958
|
const packId = ctx.packId;
|
|
1101
|
-
const [task, setTask] =
|
|
1102
|
-
const [subtasks, setSubtasks] =
|
|
1103
|
-
const [history, setHistory] =
|
|
1104
|
-
const [loading, setLoading] =
|
|
959
|
+
const [task, setTask] = useState5(null);
|
|
960
|
+
const [subtasks, setSubtasks] = useState5([]);
|
|
961
|
+
const [history, setHistory] = useState5([]);
|
|
962
|
+
const [loading, setLoading] = useState5(true);
|
|
1105
963
|
const fetchTask = useCallback3(async () => {
|
|
1106
964
|
try {
|
|
1107
|
-
const
|
|
965
|
+
const raw = await callTool("fw_weaver_task_get", { id: taskId });
|
|
966
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1108
967
|
if (!data) return;
|
|
1109
|
-
const t = data;
|
|
968
|
+
const t = data.task ?? data;
|
|
1110
969
|
setTask(t);
|
|
1111
|
-
if (
|
|
1112
|
-
|
|
970
|
+
if (data.subtasks && Array.isArray(data.subtasks)) {
|
|
971
|
+
setSubtasks(data.subtasks);
|
|
972
|
+
} else if (t.isParent) {
|
|
973
|
+
const listRaw = await callTool("fw_weaver_task_list", { parentId: taskId });
|
|
974
|
+
const listData = typeof listRaw === "string" ? JSON.parse(listRaw) : listRaw;
|
|
1113
975
|
if (Array.isArray(listData)) {
|
|
1114
976
|
setSubtasks(listData);
|
|
1115
977
|
}
|
|
@@ -1119,7 +981,8 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1119
981
|
}, [callTool, taskId]);
|
|
1120
982
|
const fetchHistory = useCallback3(async () => {
|
|
1121
983
|
try {
|
|
1122
|
-
const
|
|
984
|
+
const raw = await callTool("fw_weaver_history", { taskId });
|
|
985
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1123
986
|
if (Array.isArray(data)) {
|
|
1124
987
|
setHistory(
|
|
1125
988
|
data.map((r) => {
|
|
@@ -1160,8 +1023,66 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1160
1023
|
stream.start(packId, "fw_weaver_events", currentRunId);
|
|
1161
1024
|
return () => stream.stop();
|
|
1162
1025
|
}, [isLive, currentRunId, packId]);
|
|
1163
|
-
const [
|
|
1164
|
-
const [
|
|
1026
|
+
const [detailTab, setDetailTab] = useState5("runs");
|
|
1027
|
+
const [actionLoading, setActionLoading] = useState5(null);
|
|
1028
|
+
const [availableProfiles, setAvailableProfiles] = useState5([]);
|
|
1029
|
+
useEffect2(() => {
|
|
1030
|
+
callTool("fw_weaver_profile_list", {}).then((raw) => {
|
|
1031
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1032
|
+
if (Array.isArray(data)) setAvailableProfiles(data);
|
|
1033
|
+
}).catch(() => {
|
|
1034
|
+
});
|
|
1035
|
+
}, [callTool]);
|
|
1036
|
+
const handleRetry = useCallback3(async () => {
|
|
1037
|
+
setActionLoading("retry");
|
|
1038
|
+
try {
|
|
1039
|
+
await callTool("fw_weaver_task_retry", { id: taskId });
|
|
1040
|
+
toast3("Task retried, back in pool", { type: "success" });
|
|
1041
|
+
fetchTask();
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
toast3(err instanceof Error ? err.message : "Failed to retry", { type: "error" });
|
|
1044
|
+
}
|
|
1045
|
+
setActionLoading(null);
|
|
1046
|
+
}, [callTool, taskId, fetchTask]);
|
|
1047
|
+
const handleCancel = useCallback3(async () => {
|
|
1048
|
+
const ok = await ctx.confirm("Cancel this task? It cannot be undone.", {
|
|
1049
|
+
title: "Cancel Task",
|
|
1050
|
+
confirmLabel: "Cancel Task",
|
|
1051
|
+
state: "warning"
|
|
1052
|
+
});
|
|
1053
|
+
if (!ok) return;
|
|
1054
|
+
setActionLoading("cancel");
|
|
1055
|
+
try {
|
|
1056
|
+
await callTool("fw_weaver_task_cancel", { id: taskId });
|
|
1057
|
+
toast3("Task cancelled", { type: "info" });
|
|
1058
|
+
fetchTask();
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
toast3(err instanceof Error ? err.message : "Failed to cancel", { type: "error" });
|
|
1061
|
+
}
|
|
1062
|
+
setActionLoading(null);
|
|
1063
|
+
}, [callTool, taskId, fetchTask, ctx]);
|
|
1064
|
+
const handleAssignProfile = useCallback3(async (profileId) => {
|
|
1065
|
+
setActionLoading("assign-profile");
|
|
1066
|
+
try {
|
|
1067
|
+
const newProfile = task?.assignedProfile === profileId ? void 0 : profileId;
|
|
1068
|
+
await callTool("fw_weaver_task_update", { id: taskId, assignedProfile: newProfile ?? null });
|
|
1069
|
+
toast3(newProfile ? `Assigned profile ${profileId}` : `Unassigned profile`, { type: "success" });
|
|
1070
|
+
fetchTask();
|
|
1071
|
+
} catch (err) {
|
|
1072
|
+
toast3(err instanceof Error ? err.message : "Failed to assign profile", { type: "error" });
|
|
1073
|
+
}
|
|
1074
|
+
setActionLoading(null);
|
|
1075
|
+
}, [callTool, taskId, task, fetchTask]);
|
|
1076
|
+
const handlePriorityChange = useCallback3(async (delta) => {
|
|
1077
|
+
const newPriority = Math.max(0, (task?.priority ?? 0) + delta);
|
|
1078
|
+
try {
|
|
1079
|
+
await callTool("fw_weaver_task_update", { id: taskId, priority: newPriority });
|
|
1080
|
+
fetchTask();
|
|
1081
|
+
} catch {
|
|
1082
|
+
}
|
|
1083
|
+
}, [callTool, taskId, task, fetchTask]);
|
|
1084
|
+
const [expandedRunId, setExpandedRunId] = useState5(null);
|
|
1085
|
+
const [liveExpanded, setLiveExpanded] = useState5(true);
|
|
1165
1086
|
const toggleExpand = useCallback3((id) => {
|
|
1166
1087
|
setExpandedRunId((prev) => prev === id ? null : id);
|
|
1167
1088
|
}, []);
|
|
@@ -1170,8 +1091,8 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1170
1091
|
const el = scrollRef.current;
|
|
1171
1092
|
if (el) el.scrollTop = el.scrollHeight;
|
|
1172
1093
|
}, [liveTimeline.length, stream.events.length]);
|
|
1173
|
-
const [approvalStatus, setApprovalStatus] =
|
|
1174
|
-
const [approvalLoading, setApprovalLoading] =
|
|
1094
|
+
const [approvalStatus, setApprovalStatus] = useState5(null);
|
|
1095
|
+
const [approvalLoading, setApprovalLoading] = useState5(false);
|
|
1175
1096
|
useEffect2(() => {
|
|
1176
1097
|
if (awaitingApproval) setApprovalStatus("pending");
|
|
1177
1098
|
}, [awaitingApproval]);
|
|
@@ -1226,13 +1147,19 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1226
1147
|
}
|
|
1227
1148
|
if (loading && !task) {
|
|
1228
1149
|
return React7.createElement(
|
|
1229
|
-
|
|
1230
|
-
|
|
1150
|
+
Flex6,
|
|
1151
|
+
{
|
|
1152
|
+
variant: "column-stretch-start-nowrap-0",
|
|
1153
|
+
style: { width: "100%", height: "100%", overflow: "hidden" }
|
|
1154
|
+
},
|
|
1231
1155
|
React7.createElement(
|
|
1232
|
-
|
|
1233
|
-
|
|
1156
|
+
Flex6,
|
|
1157
|
+
{
|
|
1158
|
+
variant: "column-stretch-start-nowrap-8",
|
|
1159
|
+
style: headerStyle
|
|
1160
|
+
},
|
|
1234
1161
|
React7.createElement(
|
|
1235
|
-
|
|
1162
|
+
Button2,
|
|
1236
1163
|
{ variant: "ghost", size: "sm", onClick: onBack },
|
|
1237
1164
|
React7.createElement(Icon3, { name: "arrowBack", size: 16 }),
|
|
1238
1165
|
" Back"
|
|
@@ -1242,10 +1169,10 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1242
1169
|
Flex6,
|
|
1243
1170
|
{
|
|
1244
1171
|
variant: "column-center-center-nowrap-0",
|
|
1245
|
-
style: { flex: 1
|
|
1172
|
+
style: { flex: 1 }
|
|
1246
1173
|
},
|
|
1247
1174
|
React7.createElement(
|
|
1248
|
-
|
|
1175
|
+
Typography5,
|
|
1249
1176
|
{ variant: "caption-regular", color: "color-text-subtle" },
|
|
1250
1177
|
"Loading task..."
|
|
1251
1178
|
)
|
|
@@ -1254,13 +1181,19 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1254
1181
|
}
|
|
1255
1182
|
if (!task) {
|
|
1256
1183
|
return React7.createElement(
|
|
1257
|
-
|
|
1258
|
-
|
|
1184
|
+
Flex6,
|
|
1185
|
+
{
|
|
1186
|
+
variant: "column-stretch-start-nowrap-0",
|
|
1187
|
+
style: { width: "100%", height: "100%", overflow: "hidden" }
|
|
1188
|
+
},
|
|
1259
1189
|
React7.createElement(
|
|
1260
|
-
|
|
1261
|
-
|
|
1190
|
+
Flex6,
|
|
1191
|
+
{
|
|
1192
|
+
variant: "column-stretch-start-nowrap-8",
|
|
1193
|
+
style: headerStyle
|
|
1194
|
+
},
|
|
1262
1195
|
React7.createElement(
|
|
1263
|
-
|
|
1196
|
+
Button2,
|
|
1264
1197
|
{ variant: "ghost", size: "sm", onClick: onBack },
|
|
1265
1198
|
React7.createElement(Icon3, { name: "arrowBack", size: 16 }),
|
|
1266
1199
|
" Back"
|
|
@@ -1270,10 +1203,10 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1270
1203
|
Flex6,
|
|
1271
1204
|
{
|
|
1272
1205
|
variant: "column-center-center-nowrap-0",
|
|
1273
|
-
style: { flex: 1
|
|
1206
|
+
style: { flex: 1 }
|
|
1274
1207
|
},
|
|
1275
1208
|
React7.createElement(
|
|
1276
|
-
|
|
1209
|
+
Typography5,
|
|
1277
1210
|
{ variant: "caption-regular", color: "color-text-subtle" },
|
|
1278
1211
|
"Task not found."
|
|
1279
1212
|
)
|
|
@@ -1284,210 +1217,392 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1284
1217
|
const hasSubtasks = task.isParent && subtasks.length > 0;
|
|
1285
1218
|
const hasRuns = runItems.length > 0 || isLive;
|
|
1286
1219
|
return React7.createElement(
|
|
1287
|
-
|
|
1288
|
-
|
|
1220
|
+
Flex6,
|
|
1221
|
+
{
|
|
1222
|
+
variant: "column-stretch-start-nowrap-0",
|
|
1223
|
+
style: { width: "100%", height: "100%", overflow: "hidden" }
|
|
1224
|
+
},
|
|
1289
1225
|
// ── Header ──
|
|
1290
1226
|
React7.createElement(
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
React7.createElement(Icon3, { name: "arrowBack", size: 16 }),
|
|
1298
|
-
" Back"
|
|
1299
|
-
),
|
|
1300
|
-
// Title row
|
|
1227
|
+
Flex6,
|
|
1228
|
+
{
|
|
1229
|
+
variant: "column-stretch-start-nowrap-6",
|
|
1230
|
+
style: { ...headerStyle, padding: "12px 16px", borderBottom: "1px solid var(--color-border-default)" }
|
|
1231
|
+
},
|
|
1232
|
+
// Top row: back + title + status
|
|
1301
1233
|
React7.createElement(
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
React7.createElement(
|
|
1305
|
-
|
|
1306
|
-
size: "
|
|
1234
|
+
Flex6,
|
|
1235
|
+
{ variant: "row-center-start-nowrap-8" },
|
|
1236
|
+
React7.createElement(IconButton4, {
|
|
1237
|
+
icon: "back",
|
|
1238
|
+
size: "xs",
|
|
1239
|
+
variant: "clear",
|
|
1240
|
+
onClick: onBack
|
|
1241
|
+
}),
|
|
1242
|
+
React7.createElement(StatusIcon3, {
|
|
1243
|
+
status: statusToIcon2[task.status] || "pending",
|
|
1244
|
+
size: "sm"
|
|
1307
1245
|
}),
|
|
1308
|
-
React7.createElement(
|
|
1246
|
+
React7.createElement(Typography5, {
|
|
1247
|
+
variant: "caption-thick",
|
|
1248
|
+
color: "color-text-high",
|
|
1249
|
+
style: { flex: 1, minWidth: 0, wordBreak: "break-word" }
|
|
1250
|
+
}, task.title || "Untitled Task")
|
|
1309
1251
|
),
|
|
1310
|
-
// Meta row: status
|
|
1252
|
+
// Meta row: status tag, assigned profile, priority, attempts
|
|
1311
1253
|
React7.createElement(
|
|
1312
|
-
|
|
1313
|
-
|
|
1254
|
+
Flex6,
|
|
1255
|
+
{ variant: "row-center-start-wrap-6" },
|
|
1314
1256
|
React7.createElement(Tag2, {
|
|
1315
1257
|
size: "small",
|
|
1316
|
-
color: task.status === "done" ? "positive" : task.status === "failed" ? "negative" : task.status === "in-progress" ? "info" : task.status === "blocked" ? "caution" : "
|
|
1317
|
-
}, statusToLabel2[task.status]),
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
task.priority
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
// Attempt count
|
|
1326
|
-
React7.createElement(Typography6, {
|
|
1327
|
-
variant: "caption-regular",
|
|
1258
|
+
color: task.status === "done" ? "positive" : task.status === "failed" ? "negative" : task.status === "in-progress" ? "info" : task.status === "blocked" ? "caution" : "secondary"
|
|
1259
|
+
}, statusToLabel2[task.status] || task.status || "pending"),
|
|
1260
|
+
task.assignedProfile && React7.createElement(Tag2, { key: `profile-${task.assignedProfile}`, size: "small", color: "info" }, task.assignedProfile),
|
|
1261
|
+
task.priority > 0 && React7.createElement(Tag2, {
|
|
1262
|
+
size: "small",
|
|
1263
|
+
color: task.priority >= 3 ? "caution" : "info"
|
|
1264
|
+
}, `P${task.priority}`),
|
|
1265
|
+
task.attempt != null && task.maxAttempts != null && React7.createElement(Typography5, {
|
|
1266
|
+
variant: "smallCaption-regular",
|
|
1328
1267
|
color: "color-text-subtle"
|
|
1329
1268
|
}, `Attempt ${task.attempt}/${task.maxAttempts}`)
|
|
1330
1269
|
),
|
|
1331
1270
|
// Description
|
|
1332
|
-
task.description && React7.createElement(
|
|
1333
|
-
variant: "
|
|
1334
|
-
color: "color-text-
|
|
1335
|
-
|
|
1336
|
-
|
|
1271
|
+
task.description && React7.createElement(Typography5, {
|
|
1272
|
+
variant: "smallCaption-regular",
|
|
1273
|
+
color: "color-text-medium"
|
|
1274
|
+
}, task.description),
|
|
1275
|
+
// Profile routing info
|
|
1276
|
+
task.assignedProfile && React7.createElement(
|
|
1277
|
+
Flex6,
|
|
1278
|
+
{ variant: "column-stretch-start-nowrap-2" },
|
|
1279
|
+
React7.createElement(Typography5, {
|
|
1280
|
+
variant: "smallCaption-regular",
|
|
1281
|
+
color: "color-text-medium"
|
|
1282
|
+
}, `Profile: ${task.assignedProfile}`),
|
|
1283
|
+
task.routingReason && React7.createElement(Typography5, {
|
|
1284
|
+
variant: "smallCaption-regular",
|
|
1285
|
+
color: "color-text-subtle"
|
|
1286
|
+
}, task.routingReason)
|
|
1287
|
+
)
|
|
1288
|
+
// (Actions moved to tab)
|
|
1337
1289
|
),
|
|
1338
|
-
// ──
|
|
1290
|
+
// ── Tabs ──
|
|
1291
|
+
React7.createElement(Tabs, {
|
|
1292
|
+
tabs: [
|
|
1293
|
+
{ id: "runs", title: `Runs (${runItems.length}${isLive ? "+1" : ""})` },
|
|
1294
|
+
...hasSubtasks ? [{ id: "subtasks", title: `Subtasks (${subtasks.filter((s) => s.status === "done").length}/${subtasks.length})` }] : [],
|
|
1295
|
+
...task.status !== "done" && task.status !== "cancelled" ? [{ id: "actions", title: "Actions" }] : [],
|
|
1296
|
+
...hasContext ? [{ id: "context", title: "Context" }] : []
|
|
1297
|
+
],
|
|
1298
|
+
activeTabId: detailTab,
|
|
1299
|
+
onSelectTab: (id) => setDetailTab(id),
|
|
1300
|
+
size: "sm"
|
|
1301
|
+
}),
|
|
1302
|
+
// ── Tab content ──
|
|
1339
1303
|
React7.createElement(
|
|
1340
1304
|
ScrollArea2,
|
|
1341
1305
|
{ ref: scrollRef, style: { flex: 1 } },
|
|
1342
1306
|
React7.createElement(
|
|
1343
1307
|
Flex6,
|
|
1344
|
-
{ variant: "column-stretch-start-nowrap-
|
|
1345
|
-
// ──
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1308
|
+
{ variant: "column-stretch-start-nowrap-8", style: { padding: "12px 16px" } },
|
|
1309
|
+
// ── Runs tab ──
|
|
1310
|
+
detailTab === "runs" && (hasRuns || (task.runs?.length ?? 0) > 0) ? React7.createElement(
|
|
1311
|
+
Flex6,
|
|
1312
|
+
{ variant: "column-stretch-start-nowrap-8" },
|
|
1313
|
+
...runItems.map(({ run, runTimeline }) => {
|
|
1314
|
+
const runId = run.id;
|
|
1315
|
+
const isExpanded = expandedRunId === runId;
|
|
1316
|
+
const isSuccess = run.outcome === "completed" || run.success === true;
|
|
1317
|
+
return React7.createElement(TaskBlock, {
|
|
1318
|
+
key: `run-${runId}`,
|
|
1319
|
+
state: isSuccess ? "completed" : "failed",
|
|
1320
|
+
instruction: extractInstruction(run),
|
|
1321
|
+
timeline: runTimeline,
|
|
1322
|
+
cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
|
|
1323
|
+
plan: run.plan,
|
|
1324
|
+
startedAt: run.startedAt,
|
|
1325
|
+
durationMs: run.durationMs ?? run.duration,
|
|
1326
|
+
expanded: isExpanded,
|
|
1327
|
+
onToggleExpand: () => toggleExpand(runId)
|
|
1328
|
+
});
|
|
1329
|
+
}),
|
|
1330
|
+
// Live run
|
|
1331
|
+
isLive && React7.createElement(TaskBlock, {
|
|
1332
|
+
key: "live-run",
|
|
1333
|
+
state: "running",
|
|
1334
|
+
instruction: liveInstruction ?? task.title,
|
|
1335
|
+
timeline: liveTimeline,
|
|
1336
|
+
phase: livePhase,
|
|
1337
|
+
elapsed,
|
|
1338
|
+
cost: liveCost,
|
|
1339
|
+
plan,
|
|
1340
|
+
error: stream.error,
|
|
1341
|
+
approval: approvalStatus ?? void 0,
|
|
1342
|
+
approvalLoading,
|
|
1343
|
+
onApprove: handleApprove,
|
|
1344
|
+
onReject: handleReject,
|
|
1345
|
+
expanded: liveExpanded,
|
|
1346
|
+
onToggleExpand: () => setLiveExpanded((v) => !v)
|
|
1347
|
+
})
|
|
1348
|
+
) : detailTab === "runs" && React7.createElement(EmptyState2, {
|
|
1349
|
+
icon: "smartToy",
|
|
1350
|
+
message: "No runs yet",
|
|
1351
|
+
description: "This task has not been executed yet."
|
|
1352
|
+
}),
|
|
1353
|
+
// ── Subtasks tab ──
|
|
1354
|
+
detailTab === "subtasks" && hasSubtasks && React7.createElement(
|
|
1355
|
+
Flex6,
|
|
1356
|
+
{
|
|
1357
|
+
variant: "column-stretch-start-nowrap-0"
|
|
1358
|
+
},
|
|
1359
|
+
...(subtasks ?? []).map(
|
|
1360
|
+
(sub) => React7.createElement(SubtaskRowItem, {
|
|
1361
|
+
key: sub.id,
|
|
1362
|
+
sub,
|
|
1363
|
+
onBack
|
|
1364
|
+
})
|
|
1365
|
+
)
|
|
1366
|
+
),
|
|
1367
|
+
// ── Actions tab ──
|
|
1368
|
+
detailTab === "actions" && React7.createElement(
|
|
1369
|
+
Flex6,
|
|
1370
|
+
{
|
|
1371
|
+
variant: "column-stretch-start-nowrap-16"
|
|
1372
|
+
},
|
|
1373
|
+
// Status actions
|
|
1349
1374
|
React7.createElement(
|
|
1350
|
-
SectionTitle,
|
|
1351
|
-
null,
|
|
1352
|
-
React7.createElement(Typography6, { variant: "caption-semibold", color: "color-text-high" }, "Context")
|
|
1353
|
-
),
|
|
1354
|
-
// Files
|
|
1355
|
-
task.context.files.length > 0 && React7.createElement(
|
|
1356
1375
|
Flex6,
|
|
1357
|
-
{
|
|
1358
|
-
|
|
1359
|
-
style: { marginBottom: "8px" }
|
|
1360
|
-
},
|
|
1361
|
-
React7.createElement(Typography6, { variant: "caption-regular", color: "color-text-subtle" }, "Files:"),
|
|
1376
|
+
{ variant: "column-stretch-start-nowrap-8" },
|
|
1377
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Status"),
|
|
1362
1378
|
React7.createElement(
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1379
|
+
Flex6,
|
|
1380
|
+
{ variant: "row-center-start-nowrap-6" },
|
|
1381
|
+
task.status === "failed" && React7.createElement(Button2, {
|
|
1382
|
+
size: "xs",
|
|
1383
|
+
variant: "fill",
|
|
1384
|
+
color: "primary",
|
|
1385
|
+
onClick: handleRetry,
|
|
1386
|
+
loading: actionLoading === "retry",
|
|
1387
|
+
disabled: !!actionLoading
|
|
1388
|
+
}, "Retry Task"),
|
|
1389
|
+
(task.status === "pending" || task.status === "in-progress" || task.status === "blocked") && React7.createElement(Button2, {
|
|
1390
|
+
size: "xs",
|
|
1391
|
+
variant: "outlined",
|
|
1392
|
+
color: "danger",
|
|
1393
|
+
onClick: handleCancel,
|
|
1394
|
+
loading: actionLoading === "cancel",
|
|
1395
|
+
disabled: !!actionLoading
|
|
1396
|
+
}, "Cancel Task")
|
|
1368
1397
|
)
|
|
1369
1398
|
),
|
|
1370
|
-
//
|
|
1371
|
-
task.context.notes && React7.createElement(
|
|
1372
|
-
Flex6,
|
|
1373
|
-
{ variant: "column-stretch-start-nowrap-4" },
|
|
1374
|
-
React7.createElement(Typography6, { variant: "caption-regular", color: "color-text-subtle" }, "Notes:"),
|
|
1375
|
-
React7.createElement(NotesBlock, null, task.context.notes)
|
|
1376
|
-
)
|
|
1377
|
-
),
|
|
1378
|
-
// ── Subtasks section ──
|
|
1379
|
-
hasSubtasks && React7.createElement(
|
|
1380
|
-
Section,
|
|
1381
|
-
null,
|
|
1399
|
+
// Priority
|
|
1382
1400
|
React7.createElement(
|
|
1383
|
-
|
|
1384
|
-
|
|
1401
|
+
Flex6,
|
|
1402
|
+
{ variant: "column-stretch-start-nowrap-8" },
|
|
1403
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Priority"),
|
|
1385
1404
|
React7.createElement(
|
|
1386
|
-
|
|
1387
|
-
{ variant: "
|
|
1388
|
-
|
|
1405
|
+
Flex6,
|
|
1406
|
+
{ variant: "row-center-start-nowrap-8" },
|
|
1407
|
+
React7.createElement(IconButton4, {
|
|
1408
|
+
icon: "expandLess",
|
|
1409
|
+
size: "xs",
|
|
1410
|
+
variant: "outlined",
|
|
1411
|
+
onClick: () => handlePriorityChange(1),
|
|
1412
|
+
title: "Increase priority"
|
|
1413
|
+
}),
|
|
1414
|
+
React7.createElement(
|
|
1415
|
+
Typography5,
|
|
1416
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
1417
|
+
`P${task.priority ?? 0}`
|
|
1418
|
+
),
|
|
1419
|
+
React7.createElement(IconButton4, {
|
|
1420
|
+
icon: "expandMore",
|
|
1421
|
+
size: "xs",
|
|
1422
|
+
variant: "outlined",
|
|
1423
|
+
onClick: () => handlePriorityChange(-1),
|
|
1424
|
+
title: "Decrease priority"
|
|
1425
|
+
})
|
|
1389
1426
|
)
|
|
1390
1427
|
),
|
|
1391
|
-
|
|
1428
|
+
// Assign Profile
|
|
1429
|
+
availableProfiles.length > 0 && React7.createElement(
|
|
1392
1430
|
Flex6,
|
|
1393
|
-
{ variant: "column-stretch-start-nowrap-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1431
|
+
{ variant: "column-stretch-start-nowrap-8" },
|
|
1432
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Assign Profile"),
|
|
1433
|
+
React7.createElement(Table, {
|
|
1434
|
+
size: "compact",
|
|
1435
|
+
getRowKey: (row) => row.id,
|
|
1436
|
+
columns: [
|
|
1437
|
+
{
|
|
1438
|
+
key: "icon",
|
|
1439
|
+
header: "",
|
|
1440
|
+
width: "30px",
|
|
1441
|
+
render: (_, row) => React7.createElement(Icon3, {
|
|
1442
|
+
name: row.icon || "smartToy",
|
|
1443
|
+
size: 14,
|
|
1444
|
+
color: row.color || "color-text-medium"
|
|
1445
|
+
})
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
key: "name",
|
|
1449
|
+
header: "Profile"
|
|
1450
|
+
},
|
|
1397
1451
|
{
|
|
1398
|
-
key:
|
|
1399
|
-
|
|
1400
|
-
|
|
1452
|
+
key: "capabilities",
|
|
1453
|
+
header: "Capabilities",
|
|
1454
|
+
render: (_, row) => {
|
|
1455
|
+
const caps = row.capabilities || [];
|
|
1456
|
+
if (caps.length === 0) return null;
|
|
1457
|
+
return React7.createElement(
|
|
1458
|
+
Flex6,
|
|
1459
|
+
{ variant: "row-center-start-wrap-4" },
|
|
1460
|
+
...caps.slice(0, 4).map(
|
|
1461
|
+
(cap) => React7.createElement(
|
|
1462
|
+
"span",
|
|
1463
|
+
{ key: cap.name, title: cap.description },
|
|
1464
|
+
React7.createElement(Chip, { label: cap.name, size: "small", color: "color-brand-main" })
|
|
1465
|
+
)
|
|
1466
|
+
),
|
|
1467
|
+
caps.length > 4 && React7.createElement(Typography5, {
|
|
1468
|
+
variant: "smallCaption-regular",
|
|
1469
|
+
color: "color-text-subtle"
|
|
1470
|
+
}, `+${caps.length - 4}`)
|
|
1471
|
+
);
|
|
1401
1472
|
}
|
|
1402
1473
|
},
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
)
|
|
1421
|
-
)
|
|
1474
|
+
{
|
|
1475
|
+
key: "assigned",
|
|
1476
|
+
header: "Assign",
|
|
1477
|
+
width: "50px",
|
|
1478
|
+
align: "right",
|
|
1479
|
+
render: (_, row) => {
|
|
1480
|
+
const isAssigned = task.assignedProfile === row.id;
|
|
1481
|
+
return React7.createElement(Checkbox, {
|
|
1482
|
+
checked: isAssigned,
|
|
1483
|
+
onChange: () => handleAssignProfile(row.id),
|
|
1484
|
+
size: "sm"
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
],
|
|
1489
|
+
data: availableProfiles
|
|
1490
|
+
})
|
|
1422
1491
|
)
|
|
1423
1492
|
),
|
|
1424
|
-
// ──
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
{
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
Typography6,
|
|
1433
|
-
{ variant: "caption-semibold", color: "color-text-high" },
|
|
1434
|
-
`Run History (${runItems.length}${isLive ? " + 1 live" : ""})`
|
|
1435
|
-
)
|
|
1436
|
-
),
|
|
1437
|
-
React7.createElement(
|
|
1493
|
+
// ── Context tab ──
|
|
1494
|
+
detailTab === "context" && hasContext && React7.createElement(
|
|
1495
|
+
Flex6,
|
|
1496
|
+
{
|
|
1497
|
+
variant: "column-stretch-start-nowrap-12"
|
|
1498
|
+
},
|
|
1499
|
+
// Files
|
|
1500
|
+
(task.context?.files?.length ?? 0) > 0 && React7.createElement(
|
|
1438
1501
|
Flex6,
|
|
1439
|
-
{
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
key:
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
{ style: { borderBottom: "none" } },
|
|
1481
|
-
React7.createElement(
|
|
1502
|
+
{
|
|
1503
|
+
variant: "column-stretch-start-nowrap-4"
|
|
1504
|
+
},
|
|
1505
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Files"),
|
|
1506
|
+
...(task.context?.files ?? []).map(
|
|
1507
|
+
(file) => React7.createElement(Typography5, {
|
|
1508
|
+
key: file,
|
|
1509
|
+
variant: "smallCaption-regular",
|
|
1510
|
+
color: "color-text-high",
|
|
1511
|
+
style: { fontFamily: "var(--font-mono, monospace)" }
|
|
1512
|
+
}, file)
|
|
1513
|
+
)
|
|
1514
|
+
),
|
|
1515
|
+
// Notes
|
|
1516
|
+
task.context?.notes && React7.createElement(
|
|
1517
|
+
Flex6,
|
|
1518
|
+
{
|
|
1519
|
+
variant: "column-stretch-start-nowrap-4"
|
|
1520
|
+
},
|
|
1521
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Notes"),
|
|
1522
|
+
React7.createElement(Typography5, {
|
|
1523
|
+
variant: "smallCaption-regular",
|
|
1524
|
+
color: "color-text-high",
|
|
1525
|
+
style: { whiteSpace: "pre-wrap" }
|
|
1526
|
+
}, task.context.notes)
|
|
1527
|
+
),
|
|
1528
|
+
// Last error
|
|
1529
|
+
task.context?.lastError && React7.createElement(
|
|
1530
|
+
Flex6,
|
|
1531
|
+
{
|
|
1532
|
+
variant: "column-stretch-start-nowrap-4"
|
|
1533
|
+
},
|
|
1534
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-status-negative" }, "Last Error"),
|
|
1535
|
+
React7.createElement(Typography5, {
|
|
1536
|
+
variant: "smallCaption-regular",
|
|
1537
|
+
color: "color-text-high",
|
|
1538
|
+
style: { fontFamily: "var(--font-mono, monospace)", whiteSpace: "pre-wrap" }
|
|
1539
|
+
}, task.context.lastError)
|
|
1540
|
+
),
|
|
1541
|
+
// Run summaries (accumulated context)
|
|
1542
|
+
(task.context?.runSummaries?.length ?? 0) > 0 && React7.createElement(
|
|
1482
1543
|
Flex6,
|
|
1483
1544
|
{
|
|
1484
|
-
variant: "column-
|
|
1485
|
-
style: { padding: "16px" }
|
|
1545
|
+
variant: "column-stretch-start-nowrap-6"
|
|
1486
1546
|
},
|
|
1487
|
-
React7.createElement(
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1547
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Run Summaries"),
|
|
1548
|
+
...(task.context?.runSummaries ?? []).map(
|
|
1549
|
+
(rs, i) => React7.createElement(
|
|
1550
|
+
Card,
|
|
1551
|
+
{
|
|
1552
|
+
key: `rs-${i}`,
|
|
1553
|
+
variant: "bordered",
|
|
1554
|
+
padding: "compact",
|
|
1555
|
+
style: { gap: "4px" }
|
|
1556
|
+
},
|
|
1557
|
+
React7.createElement(
|
|
1558
|
+
Flex6,
|
|
1559
|
+
{ variant: "row-center-space-between-nowrap-8" },
|
|
1560
|
+
React7.createElement(Typography5, {
|
|
1561
|
+
variant: "smallCaption-thick",
|
|
1562
|
+
color: rs.outcome === "success" ? "color-status-positive" : "color-status-negative"
|
|
1563
|
+
}, `${rs.outcome === "success" ? "Success" : "Failed"} (${rs.botId ?? "unknown bot"})`),
|
|
1564
|
+
React7.createElement(Typography5, {
|
|
1565
|
+
variant: "smallCaption-regular",
|
|
1566
|
+
color: "color-text-subtle"
|
|
1567
|
+
}, `${Math.round((rs.durationMs ?? 0) / 1e3)}s \xB7 ${rs.tokensUsed ?? 0} tok \xB7 $${(rs.cost ?? 0).toFixed(3)}`)
|
|
1568
|
+
),
|
|
1569
|
+
React7.createElement(Typography5, {
|
|
1570
|
+
variant: "smallCaption-regular",
|
|
1571
|
+
color: "color-text-medium"
|
|
1572
|
+
}, rs.summary ?? ""),
|
|
1573
|
+
(rs.filesModified ?? []).length > 0 && React7.createElement(Typography5, {
|
|
1574
|
+
variant: "smallCaption-regular",
|
|
1575
|
+
color: "color-text-subtle",
|
|
1576
|
+
style: { fontFamily: "var(--font-mono, monospace)" }
|
|
1577
|
+
}, `Files: ${rs.filesModified.join(", ")}`),
|
|
1578
|
+
rs.error && React7.createElement(Typography5, {
|
|
1579
|
+
variant: "smallCaption-regular",
|
|
1580
|
+
color: "color-status-negative"
|
|
1581
|
+
}, `Error: ${rs.error}`)
|
|
1582
|
+
)
|
|
1583
|
+
)
|
|
1584
|
+
),
|
|
1585
|
+
// Budget
|
|
1586
|
+
(task.tokensUsed > 0 || task.costUsed > 0) && React7.createElement(
|
|
1587
|
+
Flex6,
|
|
1588
|
+
{
|
|
1589
|
+
variant: "column-stretch-start-nowrap-4"
|
|
1590
|
+
},
|
|
1591
|
+
React7.createElement(Typography5, { variant: "caption-thick", color: "color-text-medium" }, "Budget"),
|
|
1592
|
+
React7.createElement(
|
|
1593
|
+
Flex6,
|
|
1594
|
+
{ variant: "row-center-start-nowrap-16" },
|
|
1595
|
+
React7.createElement(
|
|
1596
|
+
Typography5,
|
|
1597
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
1598
|
+
`Tokens: ${task.tokensUsed?.toLocaleString() ?? 0}${task.budgetTokens ? ` / ${task.budgetTokens.toLocaleString()}` : ""}`
|
|
1599
|
+
),
|
|
1600
|
+
React7.createElement(
|
|
1601
|
+
Typography5,
|
|
1602
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
1603
|
+
`Cost: $${(task.costUsed ?? 0).toFixed(3)}${task.budgetCost ? ` / $${task.budgetCost.toFixed(2)}` : ""}`
|
|
1604
|
+
)
|
|
1605
|
+
)
|
|
1491
1606
|
)
|
|
1492
1607
|
)
|
|
1493
1608
|
)
|
|
@@ -1497,16 +1612,845 @@ function TaskDetailView({ taskId, onBack }) {
|
|
|
1497
1612
|
var task_detail_view_default = TaskDetailView;
|
|
1498
1613
|
module.exports = TaskDetailView;
|
|
1499
1614
|
|
|
1500
|
-
// src/ui/
|
|
1615
|
+
// src/ui/profile-card.tsx
|
|
1501
1616
|
var React8 = require("react");
|
|
1502
|
-
var { useState: useState5, useEffect: useEffect3, useCallback: useCallback4, useRef: useRef3 } = React8;
|
|
1503
1617
|
var {
|
|
1504
1618
|
Flex: Flex7,
|
|
1505
|
-
|
|
1506
|
-
|
|
1619
|
+
Typography: Typography6,
|
|
1620
|
+
Icon: Icon4,
|
|
1621
|
+
Chip: Chip2,
|
|
1622
|
+
IconButton: IconButton5,
|
|
1623
|
+
Tag: Tag3
|
|
1624
|
+
} = require("@fw/plugin-ui-kit");
|
|
1625
|
+
function ProfileCard({ profile, activeInstances, onEdit, onDelete }) {
|
|
1626
|
+
const {
|
|
1627
|
+
id,
|
|
1628
|
+
name,
|
|
1629
|
+
description,
|
|
1630
|
+
icon,
|
|
1631
|
+
color,
|
|
1632
|
+
capabilities,
|
|
1633
|
+
preferences,
|
|
1634
|
+
maxInstances
|
|
1635
|
+
} = profile;
|
|
1636
|
+
const budgetParts = [];
|
|
1637
|
+
if (preferences.maxCostPerRun) budgetParts.push(`$${preferences.maxCostPerRun.toFixed(2)}/run`);
|
|
1638
|
+
if (preferences.maxCostPerTask) budgetParts.push(`$${preferences.maxCostPerTask.toFixed(2)}/task`);
|
|
1639
|
+
const budgetText = budgetParts.length > 0 ? budgetParts.join(" / ") : null;
|
|
1640
|
+
return React8.createElement(
|
|
1641
|
+
Flex7,
|
|
1642
|
+
{
|
|
1643
|
+
variant: "column-stretch-start-nowrap-6",
|
|
1644
|
+
style: {
|
|
1645
|
+
padding: "10px 12px",
|
|
1646
|
+
borderRadius: "8px",
|
|
1647
|
+
border: "1px solid var(--color-border-default)",
|
|
1648
|
+
backgroundColor: "var(--color-surface-elevated)"
|
|
1649
|
+
}
|
|
1650
|
+
},
|
|
1651
|
+
// Row 1: Icon + Name + Edit/Delete buttons
|
|
1652
|
+
React8.createElement(
|
|
1653
|
+
Flex7,
|
|
1654
|
+
{ variant: "row-center-start-nowrap-8" },
|
|
1655
|
+
React8.createElement(
|
|
1656
|
+
Flex7,
|
|
1657
|
+
{
|
|
1658
|
+
variant: "row-center-center-nowrap-0",
|
|
1659
|
+
style: { color: `var(--${color})`, flexShrink: 0 }
|
|
1660
|
+
},
|
|
1661
|
+
React8.createElement(Icon4, { name: icon || "smartToy", size: 18 })
|
|
1662
|
+
),
|
|
1663
|
+
React8.createElement(Typography6, {
|
|
1664
|
+
variant: "caption-thick",
|
|
1665
|
+
color: "color-text-high",
|
|
1666
|
+
style: { flex: 1, minWidth: 0 }
|
|
1667
|
+
}, name),
|
|
1668
|
+
onEdit && React8.createElement(IconButton5, {
|
|
1669
|
+
icon: "edit",
|
|
1670
|
+
size: "xs",
|
|
1671
|
+
variant: "clear",
|
|
1672
|
+
onClick: () => onEdit(id),
|
|
1673
|
+
title: "Edit profile"
|
|
1674
|
+
}),
|
|
1675
|
+
onDelete && React8.createElement(IconButton5, {
|
|
1676
|
+
icon: "delete",
|
|
1677
|
+
size: "xs",
|
|
1678
|
+
variant: "clear",
|
|
1679
|
+
color: "danger",
|
|
1680
|
+
onClick: () => onDelete(id),
|
|
1681
|
+
title: "Delete profile"
|
|
1682
|
+
})
|
|
1683
|
+
),
|
|
1684
|
+
// Description
|
|
1685
|
+
description && React8.createElement(Typography6, {
|
|
1686
|
+
variant: "smallCaption-regular",
|
|
1687
|
+
color: "color-text-medium"
|
|
1688
|
+
}, description),
|
|
1689
|
+
// Divider
|
|
1690
|
+
React8.createElement(Flex7, {
|
|
1691
|
+
variant: "row-center-start-nowrap-0",
|
|
1692
|
+
style: { borderTop: "1px solid var(--color-border-default)", margin: "2px 0" }
|
|
1693
|
+
}),
|
|
1694
|
+
// Capabilities
|
|
1695
|
+
capabilities.length > 0 && React8.createElement(
|
|
1696
|
+
Flex7,
|
|
1697
|
+
{ variant: "row-center-start-wrap-4" },
|
|
1698
|
+
React8.createElement(Typography6, {
|
|
1699
|
+
variant: "smallCaption-regular",
|
|
1700
|
+
color: "color-text-subtle",
|
|
1701
|
+
style: { flexShrink: 0 }
|
|
1702
|
+
}, "Capabilities:"),
|
|
1703
|
+
...capabilities.map(
|
|
1704
|
+
(cap) => React8.createElement(
|
|
1705
|
+
"span",
|
|
1706
|
+
{ key: cap.name, title: cap.description },
|
|
1707
|
+
React8.createElement(Chip2, { label: cap.name, size: "small", color: "color-brand-main" })
|
|
1708
|
+
)
|
|
1709
|
+
)
|
|
1710
|
+
),
|
|
1711
|
+
// Cost strategy
|
|
1712
|
+
React8.createElement(
|
|
1713
|
+
Flex7,
|
|
1714
|
+
{ variant: "row-center-start-wrap-12" },
|
|
1715
|
+
React8.createElement(Typography6, {
|
|
1716
|
+
variant: "smallCaption-regular",
|
|
1717
|
+
color: "color-text-subtle"
|
|
1718
|
+
}, `Cost strategy: ${preferences.costStrategy}`)
|
|
1719
|
+
),
|
|
1720
|
+
// Instances + Approval + Budget
|
|
1721
|
+
React8.createElement(
|
|
1722
|
+
Flex7,
|
|
1723
|
+
{ variant: "row-center-start-wrap-12" },
|
|
1724
|
+
React8.createElement(Typography6, {
|
|
1725
|
+
variant: "smallCaption-regular",
|
|
1726
|
+
color: "color-text-subtle"
|
|
1727
|
+
}, `Instances: ${activeInstances}/${maxInstances} active`),
|
|
1728
|
+
React8.createElement(Tag3, {
|
|
1729
|
+
size: "small",
|
|
1730
|
+
color: preferences.requireApproval ? "caution" : "positive"
|
|
1731
|
+
}, preferences.requireApproval ? "Approval required" : "Auto-approve")
|
|
1732
|
+
),
|
|
1733
|
+
// Budget line
|
|
1734
|
+
budgetText && React8.createElement(Typography6, {
|
|
1735
|
+
variant: "smallCaption-regular",
|
|
1736
|
+
color: "color-text-subtle"
|
|
1737
|
+
}, `Budget: ${budgetText}`),
|
|
1738
|
+
// Instructions
|
|
1739
|
+
preferences.instructions && React8.createElement(Typography6, {
|
|
1740
|
+
variant: "smallCaption-regular",
|
|
1741
|
+
color: "color-text-subtle",
|
|
1742
|
+
style: { fontStyle: "italic" }
|
|
1743
|
+
}, preferences.instructions)
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
var profile_card_default = ProfileCard;
|
|
1747
|
+
module.exports = ProfileCard;
|
|
1748
|
+
|
|
1749
|
+
// src/ui/bot-constants.ts
|
|
1750
|
+
var ICON_CATALOG = [
|
|
1751
|
+
{
|
|
1752
|
+
category: "Actions",
|
|
1753
|
+
icons: [
|
|
1754
|
+
"playArrow",
|
|
1755
|
+
"stop",
|
|
1756
|
+
"pause",
|
|
1757
|
+
"restart",
|
|
1758
|
+
"send",
|
|
1759
|
+
"check",
|
|
1760
|
+
"edit",
|
|
1761
|
+
"copy",
|
|
1762
|
+
"add",
|
|
1763
|
+
"reset",
|
|
1764
|
+
"resume"
|
|
1765
|
+
]
|
|
1766
|
+
},
|
|
1767
|
+
{
|
|
1768
|
+
category: "AI & Science",
|
|
1769
|
+
icons: ["smartToy", "psychology", "autoAwesome", "modelTraining", "biotech", "science", "ai"]
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
category: "Data & Storage",
|
|
1773
|
+
icons: ["database", "dataObject", "dataArray", "tableChart", "token", "dns", "cloudStorage"]
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
category: "Logic & Flow",
|
|
1777
|
+
icons: [
|
|
1778
|
+
"altRoute",
|
|
1779
|
+
"callSplit",
|
|
1780
|
+
"callMerge",
|
|
1781
|
+
"rule",
|
|
1782
|
+
"filterAlt",
|
|
1783
|
+
"sort",
|
|
1784
|
+
"loop",
|
|
1785
|
+
"repeat",
|
|
1786
|
+
"compareArrows",
|
|
1787
|
+
"swapHoriz",
|
|
1788
|
+
"syncAlt",
|
|
1789
|
+
"changeCircle",
|
|
1790
|
+
"allInclusive"
|
|
1791
|
+
]
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
category: "Cloud & Network",
|
|
1795
|
+
icons: [
|
|
1796
|
+
"cloudSync",
|
|
1797
|
+
"cloudUpload",
|
|
1798
|
+
"cloudDownload",
|
|
1799
|
+
"cloudDone",
|
|
1800
|
+
"api",
|
|
1801
|
+
"webhook",
|
|
1802
|
+
"public",
|
|
1803
|
+
"router"
|
|
1804
|
+
]
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
category: "Communication",
|
|
1808
|
+
icons: ["email", "chat", "forum", "notifications", "campaign", "rssFeed", "sms"]
|
|
1809
|
+
},
|
|
1810
|
+
{
|
|
1811
|
+
category: "Security",
|
|
1812
|
+
icons: [
|
|
1813
|
+
"key",
|
|
1814
|
+
"shield",
|
|
1815
|
+
"security",
|
|
1816
|
+
"vpnKey",
|
|
1817
|
+
"adminPanel",
|
|
1818
|
+
"policy",
|
|
1819
|
+
"verified",
|
|
1820
|
+
"lockClosed",
|
|
1821
|
+
"lockOpened"
|
|
1822
|
+
]
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
category: "Time",
|
|
1826
|
+
icons: [
|
|
1827
|
+
"timer",
|
|
1828
|
+
"alarm",
|
|
1829
|
+
"hourglassEmpty",
|
|
1830
|
+
"pendingActions",
|
|
1831
|
+
"update",
|
|
1832
|
+
"watchLater",
|
|
1833
|
+
"scheduled"
|
|
1834
|
+
]
|
|
1835
|
+
},
|
|
1836
|
+
{
|
|
1837
|
+
category: "Tasks & Workflow",
|
|
1838
|
+
icons: [
|
|
1839
|
+
"task",
|
|
1840
|
+
"taskAlt",
|
|
1841
|
+
"checklist",
|
|
1842
|
+
"assignment",
|
|
1843
|
+
"publish",
|
|
1844
|
+
"build",
|
|
1845
|
+
"construction",
|
|
1846
|
+
"engineering"
|
|
1847
|
+
]
|
|
1848
|
+
},
|
|
1849
|
+
{
|
|
1850
|
+
category: "Analytics",
|
|
1851
|
+
icons: [
|
|
1852
|
+
"analytics",
|
|
1853
|
+
"insights",
|
|
1854
|
+
"barChart",
|
|
1855
|
+
"pieChart",
|
|
1856
|
+
"trendingUp",
|
|
1857
|
+
"showChart",
|
|
1858
|
+
"leaderboard",
|
|
1859
|
+
"monitoring"
|
|
1860
|
+
]
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
category: "Flow Nodes",
|
|
1864
|
+
icons: [
|
|
1865
|
+
"schema",
|
|
1866
|
+
"hub",
|
|
1867
|
+
"deviceHub",
|
|
1868
|
+
"source",
|
|
1869
|
+
"trigger",
|
|
1870
|
+
"pulse",
|
|
1871
|
+
"step",
|
|
1872
|
+
"event",
|
|
1873
|
+
"outlinedFlow"
|
|
1874
|
+
]
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
category: "Files & Documents",
|
|
1878
|
+
icons: [
|
|
1879
|
+
"file",
|
|
1880
|
+
"filePresent",
|
|
1881
|
+
"fileCopy",
|
|
1882
|
+
"textSnippet",
|
|
1883
|
+
"attachFile",
|
|
1884
|
+
"uploadFile",
|
|
1885
|
+
"save",
|
|
1886
|
+
"upload",
|
|
1887
|
+
"download"
|
|
1888
|
+
]
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
category: "General",
|
|
1892
|
+
icons: [
|
|
1893
|
+
"rocketLaunch",
|
|
1894
|
+
"code",
|
|
1895
|
+
"terminal",
|
|
1896
|
+
"logs",
|
|
1897
|
+
"info",
|
|
1898
|
+
"help",
|
|
1899
|
+
"list",
|
|
1900
|
+
"category",
|
|
1901
|
+
"hash",
|
|
1902
|
+
"calendar",
|
|
1903
|
+
"history",
|
|
1904
|
+
"integration",
|
|
1905
|
+
"layers",
|
|
1906
|
+
"link",
|
|
1907
|
+
"search",
|
|
1908
|
+
"outlinedSettings",
|
|
1909
|
+
"outlinedBug",
|
|
1910
|
+
"collaboration",
|
|
1911
|
+
"person",
|
|
1912
|
+
"people",
|
|
1913
|
+
"backup",
|
|
1914
|
+
"healthAndSafety"
|
|
1915
|
+
]
|
|
1916
|
+
}
|
|
1917
|
+
];
|
|
1918
|
+
var BOT_COLORS = [
|
|
1919
|
+
{ label: "Blue", token: "color-node-blue-icon" },
|
|
1920
|
+
{ label: "Purple", token: "color-node-purple-icon" },
|
|
1921
|
+
{ label: "Cyan", token: "color-node-cyan-icon" },
|
|
1922
|
+
{ label: "Orange", token: "color-node-orange-icon" },
|
|
1923
|
+
{ label: "Pink", token: "color-node-pink-icon" },
|
|
1924
|
+
{ label: "Green", token: "color-node-green-icon" },
|
|
1925
|
+
{ label: "Brand", token: "color-brand-main" },
|
|
1926
|
+
{ label: "Accent", token: "color-brand-alt" },
|
|
1927
|
+
{ label: "Positive", token: "color-status-positive" },
|
|
1928
|
+
{ label: "Info", token: "color-status-info" }
|
|
1929
|
+
];
|
|
1930
|
+
|
|
1931
|
+
// src/ui/profile-editor.tsx
|
|
1932
|
+
var React9 = require("react");
|
|
1933
|
+
var { useState: useState6, useEffect: useEffect3, useCallback: useCallback4 } = React9;
|
|
1934
|
+
var {
|
|
1935
|
+
Flex: Flex8,
|
|
1507
1936
|
Typography: Typography7,
|
|
1937
|
+
Input: Input2,
|
|
1938
|
+
Button: Button3,
|
|
1939
|
+
IconButton: IconButton6,
|
|
1940
|
+
Icon: Icon5,
|
|
1941
|
+
SectionTitle,
|
|
1942
|
+
Checkbox: Checkbox2,
|
|
1943
|
+
Field,
|
|
1944
|
+
IconPicker,
|
|
1945
|
+
ColorPicker,
|
|
1946
|
+
toast: toast4,
|
|
1508
1947
|
usePackWorkspace: usePackWorkspace4
|
|
1509
1948
|
} = require("@fw/plugin-ui-kit");
|
|
1949
|
+
function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
1950
|
+
const ctx = usePackWorkspace4();
|
|
1951
|
+
const { callTool } = ctx;
|
|
1952
|
+
const [name, setName] = useState6("");
|
|
1953
|
+
const [description, setDescription] = useState6("");
|
|
1954
|
+
const [botId, setBotId] = useState6(mode === "create" && bots.length > 0 ? bots[0].id : "");
|
|
1955
|
+
const [icon, setIcon] = useState6("smartToy");
|
|
1956
|
+
const [color, setColor] = useState6("color-node-blue-icon");
|
|
1957
|
+
const [costStrategy, setCostStrategy] = useState6("balanced");
|
|
1958
|
+
const [capabilities, setCapabilities] = useState6([]);
|
|
1959
|
+
const [capName, setCapName] = useState6("");
|
|
1960
|
+
const [capDescription, setCapDescription] = useState6("");
|
|
1961
|
+
const [instructions, setInstructions] = useState6("");
|
|
1962
|
+
const [requireApproval, setRequireApproval] = useState6(false);
|
|
1963
|
+
const [loading, setLoading] = useState6(mode === "edit");
|
|
1964
|
+
useEffect3(() => {
|
|
1965
|
+
if (mode !== "edit" || !profileId) return;
|
|
1966
|
+
let cancelled = false;
|
|
1967
|
+
(async () => {
|
|
1968
|
+
try {
|
|
1969
|
+
const raw = await callTool("fw_weaver_profile_list", {});
|
|
1970
|
+
if (cancelled) return;
|
|
1971
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
1972
|
+
const list = Array.isArray(data) ? data : [];
|
|
1973
|
+
const profile = list.find((p) => p.id === profileId);
|
|
1974
|
+
if (!profile) {
|
|
1975
|
+
toast4("Profile not found", { type: "error" });
|
|
1976
|
+
onCancel();
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
setName(profile.name || "");
|
|
1980
|
+
setDescription(profile.description || "");
|
|
1981
|
+
setBotId(profile.botId || "");
|
|
1982
|
+
setIcon(profile.icon || "smartToy");
|
|
1983
|
+
setColor(profile.color || "color-node-blue-icon");
|
|
1984
|
+
const prefs = profile.preferences || {};
|
|
1985
|
+
setCostStrategy(prefs.costStrategy || "balanced");
|
|
1986
|
+
setCapabilities(
|
|
1987
|
+
Array.isArray(profile.capabilities) ? profile.capabilities : []
|
|
1988
|
+
);
|
|
1989
|
+
setInstructions(prefs.instructions || "");
|
|
1990
|
+
setRequireApproval(!!prefs.requireApproval);
|
|
1991
|
+
} catch {
|
|
1992
|
+
toast4("Failed to load profile", { type: "error" });
|
|
1993
|
+
onCancel();
|
|
1994
|
+
} finally {
|
|
1995
|
+
if (!cancelled) setLoading(false);
|
|
1996
|
+
}
|
|
1997
|
+
})();
|
|
1998
|
+
return () => {
|
|
1999
|
+
cancelled = true;
|
|
2000
|
+
};
|
|
2001
|
+
}, [mode, profileId, callTool, onCancel]);
|
|
2002
|
+
const handleAddCapability = useCallback4(() => {
|
|
2003
|
+
const trimName = capName.trim();
|
|
2004
|
+
const trimDesc = capDescription.trim();
|
|
2005
|
+
if (!trimName || !trimDesc) return;
|
|
2006
|
+
setCapabilities((prev) => [...prev, { name: trimName, description: trimDesc }]);
|
|
2007
|
+
setCapName("");
|
|
2008
|
+
setCapDescription("");
|
|
2009
|
+
}, [capName, capDescription]);
|
|
2010
|
+
const handleRemoveCapability = useCallback4((index) => {
|
|
2011
|
+
setCapabilities((prev) => prev.filter((_, i) => i !== index));
|
|
2012
|
+
}, []);
|
|
2013
|
+
const handleSave = useCallback4(async () => {
|
|
2014
|
+
if (!name.trim()) {
|
|
2015
|
+
toast4("Profile name is required", { type: "error" });
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
if (!botId) {
|
|
2019
|
+
toast4("Select a bot workflow", { type: "error" });
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2022
|
+
if (capabilities.length === 0) {
|
|
2023
|
+
toast4("Add at least one capability", { type: "error" });
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
try {
|
|
2027
|
+
if (mode === "create") {
|
|
2028
|
+
await callTool("fw_weaver_profile_create", {
|
|
2029
|
+
name: name.trim(),
|
|
2030
|
+
description: description.trim(),
|
|
2031
|
+
botId,
|
|
2032
|
+
icon,
|
|
2033
|
+
color,
|
|
2034
|
+
capabilities,
|
|
2035
|
+
costStrategy,
|
|
2036
|
+
instructions: instructions.trim() || void 0,
|
|
2037
|
+
requireApproval
|
|
2038
|
+
});
|
|
2039
|
+
toast4("Profile created", { type: "success" });
|
|
2040
|
+
} else {
|
|
2041
|
+
await callTool("fw_weaver_profile_update", {
|
|
2042
|
+
id: profileId,
|
|
2043
|
+
name: name.trim(),
|
|
2044
|
+
description: description.trim(),
|
|
2045
|
+
icon,
|
|
2046
|
+
color,
|
|
2047
|
+
capabilities,
|
|
2048
|
+
costStrategy,
|
|
2049
|
+
instructions: instructions.trim() || void 0,
|
|
2050
|
+
requireApproval
|
|
2051
|
+
});
|
|
2052
|
+
toast4("Profile updated", { type: "success" });
|
|
2053
|
+
}
|
|
2054
|
+
onSave();
|
|
2055
|
+
} catch (err) {
|
|
2056
|
+
toast4(err instanceof Error ? err.message : `Failed to ${mode} profile`, { type: "error" });
|
|
2057
|
+
}
|
|
2058
|
+
}, [mode, profileId, name, description, botId, icon, color, costStrategy, capabilities, instructions, requireApproval, callTool, onSave]);
|
|
2059
|
+
const handleDelete = useCallback4(async () => {
|
|
2060
|
+
if (!profileId) return;
|
|
2061
|
+
const ok = await ctx.confirm("Are you sure you want to delete this profile?", {
|
|
2062
|
+
title: "Delete Profile",
|
|
2063
|
+
confirmLabel: "Delete",
|
|
2064
|
+
state: "danger"
|
|
2065
|
+
});
|
|
2066
|
+
if (!ok) return;
|
|
2067
|
+
try {
|
|
2068
|
+
await callTool("fw_weaver_profile_delete", { id: profileId });
|
|
2069
|
+
toast4("Profile deleted", { type: "success" });
|
|
2070
|
+
if (onDelete) onDelete();
|
|
2071
|
+
} catch (err) {
|
|
2072
|
+
toast4(err instanceof Error ? err.message : "Failed to delete profile", { type: "error" });
|
|
2073
|
+
}
|
|
2074
|
+
}, [profileId, callTool, onDelete, ctx]);
|
|
2075
|
+
if (loading) {
|
|
2076
|
+
return React9.createElement(
|
|
2077
|
+
Flex8,
|
|
2078
|
+
{
|
|
2079
|
+
variant: "column-center-center-nowrap-12",
|
|
2080
|
+
style: { padding: "24px 16px" }
|
|
2081
|
+
},
|
|
2082
|
+
React9.createElement(Typography7, { variant: "caption-regular", color: "color-text-subtle" }, "Loading profile...")
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
return React9.createElement(
|
|
2086
|
+
Flex8,
|
|
2087
|
+
{
|
|
2088
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2089
|
+
style: { width: "100%", height: "100%", overflow: "hidden" }
|
|
2090
|
+
},
|
|
2091
|
+
// ── Header bar ──
|
|
2092
|
+
React9.createElement(
|
|
2093
|
+
Flex8,
|
|
2094
|
+
{
|
|
2095
|
+
variant: "row-center-space-between-nowrap-8",
|
|
2096
|
+
style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" }
|
|
2097
|
+
},
|
|
2098
|
+
React9.createElement(
|
|
2099
|
+
Flex8,
|
|
2100
|
+
{ variant: "row-center-start-nowrap-8" },
|
|
2101
|
+
React9.createElement(IconButton6, {
|
|
2102
|
+
icon: "back",
|
|
2103
|
+
size: "xs",
|
|
2104
|
+
variant: "clear",
|
|
2105
|
+
onClick: onCancel,
|
|
2106
|
+
title: "Back"
|
|
2107
|
+
}),
|
|
2108
|
+
React9.createElement(Typography7, { variant: "caption-thick", color: "color-text-high" }, mode === "create" ? "Create Profile" : "Edit Profile")
|
|
2109
|
+
),
|
|
2110
|
+
mode === "edit" && onDelete && React9.createElement(IconButton6, {
|
|
2111
|
+
icon: "outlinedDelete",
|
|
2112
|
+
size: "sm",
|
|
2113
|
+
variant: "clear",
|
|
2114
|
+
color: "danger",
|
|
2115
|
+
onClick: handleDelete,
|
|
2116
|
+
title: "Delete profile"
|
|
2117
|
+
})
|
|
2118
|
+
),
|
|
2119
|
+
// ── Scrollable form body ──
|
|
2120
|
+
React9.createElement(
|
|
2121
|
+
Flex8,
|
|
2122
|
+
{
|
|
2123
|
+
variant: "column-stretch-start-nowrap-10",
|
|
2124
|
+
style: { flex: 1, minHeight: 0, overflow: "auto", padding: "12px 16px" }
|
|
2125
|
+
},
|
|
2126
|
+
// ── Name ──
|
|
2127
|
+
React9.createElement(
|
|
2128
|
+
Field,
|
|
2129
|
+
{ label: "Name" },
|
|
2130
|
+
React9.createElement(Input2, {
|
|
2131
|
+
type: "text",
|
|
2132
|
+
size: "small",
|
|
2133
|
+
placeholder: "Profile name",
|
|
2134
|
+
value: name,
|
|
2135
|
+
onChange: (v) => setName(v),
|
|
2136
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
2137
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
2138
|
+
})
|
|
2139
|
+
),
|
|
2140
|
+
// ── Description ──
|
|
2141
|
+
React9.createElement(
|
|
2142
|
+
Field,
|
|
2143
|
+
{ label: "Description" },
|
|
2144
|
+
React9.createElement(Input2, {
|
|
2145
|
+
type: "text",
|
|
2146
|
+
size: "small",
|
|
2147
|
+
placeholder: "What does this profile do?",
|
|
2148
|
+
value: description,
|
|
2149
|
+
onChange: (v) => setDescription(v),
|
|
2150
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
2151
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
2152
|
+
})
|
|
2153
|
+
),
|
|
2154
|
+
// ── Bot ──
|
|
2155
|
+
React9.createElement(
|
|
2156
|
+
Field,
|
|
2157
|
+
{ label: "Bot" },
|
|
2158
|
+
React9.createElement(Input2, {
|
|
2159
|
+
type: "select",
|
|
2160
|
+
size: "small",
|
|
2161
|
+
options: bots.map((b) => ({ id: b.id, label: b.name, icon: b.icon || "smartToy" })),
|
|
2162
|
+
optionId: botId,
|
|
2163
|
+
onChange: (id) => setBotId(id),
|
|
2164
|
+
disabled: mode === "edit",
|
|
2165
|
+
placeholder: "Select bot",
|
|
2166
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 }
|
|
2167
|
+
})
|
|
2168
|
+
),
|
|
2169
|
+
// ── Icon ──
|
|
2170
|
+
React9.createElement(
|
|
2171
|
+
Field,
|
|
2172
|
+
{ label: "Icon", align: "start" },
|
|
2173
|
+
React9.createElement(IconPicker, {
|
|
2174
|
+
catalog: ICON_CATALOG,
|
|
2175
|
+
value: icon,
|
|
2176
|
+
onChange: (v) => setIcon(v),
|
|
2177
|
+
accentColor: color,
|
|
2178
|
+
variant: "inline"
|
|
2179
|
+
})
|
|
2180
|
+
),
|
|
2181
|
+
// ── Color ──
|
|
2182
|
+
React9.createElement(
|
|
2183
|
+
Field,
|
|
2184
|
+
{ label: "Color", align: "start" },
|
|
2185
|
+
React9.createElement(ColorPicker, {
|
|
2186
|
+
colors: BOT_COLORS,
|
|
2187
|
+
value: color,
|
|
2188
|
+
onChange: (v) => setColor(v),
|
|
2189
|
+
variant: "inline"
|
|
2190
|
+
})
|
|
2191
|
+
),
|
|
2192
|
+
// ── Cost Strategy ──
|
|
2193
|
+
React9.createElement(
|
|
2194
|
+
Field,
|
|
2195
|
+
{ label: "Cost Strategy" },
|
|
2196
|
+
React9.createElement(Input2, {
|
|
2197
|
+
type: "select",
|
|
2198
|
+
size: "small",
|
|
2199
|
+
options: [
|
|
2200
|
+
{ id: "frugal", label: "Frugal", icon: "timer" },
|
|
2201
|
+
{ id: "balanced", label: "Balanced", icon: "syncAlt" },
|
|
2202
|
+
{ id: "performance", label: "Performance", icon: "rocketLaunch" }
|
|
2203
|
+
],
|
|
2204
|
+
optionId: costStrategy,
|
|
2205
|
+
onChange: (id) => setCostStrategy(id),
|
|
2206
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 }
|
|
2207
|
+
})
|
|
2208
|
+
),
|
|
2209
|
+
// ── Capabilities ──
|
|
2210
|
+
React9.createElement(
|
|
2211
|
+
Field,
|
|
2212
|
+
{ label: "Capabilities", align: "start" },
|
|
2213
|
+
React9.createElement(
|
|
2214
|
+
Flex8,
|
|
2215
|
+
{ variant: "column-stretch-start-nowrap-6" },
|
|
2216
|
+
// Add capability row
|
|
2217
|
+
React9.createElement(
|
|
2218
|
+
Flex8,
|
|
2219
|
+
{ variant: "row-center-start-nowrap-4", style: { overflow: "hidden" } },
|
|
2220
|
+
React9.createElement(Input2, {
|
|
2221
|
+
type: "text",
|
|
2222
|
+
size: "small",
|
|
2223
|
+
placeholder: "Name",
|
|
2224
|
+
value: capName,
|
|
2225
|
+
onChange: (v) => setCapName(v),
|
|
2226
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
2227
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
2228
|
+
}),
|
|
2229
|
+
React9.createElement(Input2, {
|
|
2230
|
+
type: "text",
|
|
2231
|
+
size: "small",
|
|
2232
|
+
placeholder: "Description",
|
|
2233
|
+
value: capDescription,
|
|
2234
|
+
onChange: (v) => setCapDescription(v),
|
|
2235
|
+
onEnter: handleAddCapability,
|
|
2236
|
+
defaultBoxStyle: { flex: 2, minWidth: 0 },
|
|
2237
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
2238
|
+
}),
|
|
2239
|
+
React9.createElement(IconButton6, {
|
|
2240
|
+
icon: "add",
|
|
2241
|
+
size: "sm",
|
|
2242
|
+
variant: "outlined",
|
|
2243
|
+
color: "primary",
|
|
2244
|
+
onClick: handleAddCapability,
|
|
2245
|
+
disabled: !capName.trim() || !capDescription.trim()
|
|
2246
|
+
})
|
|
2247
|
+
),
|
|
2248
|
+
...capabilities.map(
|
|
2249
|
+
(cap, idx) => React9.createElement(
|
|
2250
|
+
Flex8,
|
|
2251
|
+
{
|
|
2252
|
+
key: `${cap.name}-${idx}`,
|
|
2253
|
+
variant: "row-center-start-nowrap-6",
|
|
2254
|
+
style: { paddingLeft: "4px" }
|
|
2255
|
+
},
|
|
2256
|
+
React9.createElement(Typography7, {
|
|
2257
|
+
variant: "smallCaption-regular",
|
|
2258
|
+
color: "color-text-high",
|
|
2259
|
+
style: { flexShrink: 0 }
|
|
2260
|
+
}, `\u2022 ${cap.name}:`),
|
|
2261
|
+
React9.createElement(Typography7, {
|
|
2262
|
+
variant: "smallCaption-regular",
|
|
2263
|
+
color: "color-text-medium",
|
|
2264
|
+
style: { flex: 1, minWidth: 0 }
|
|
2265
|
+
}, cap.description),
|
|
2266
|
+
React9.createElement(IconButton6, {
|
|
2267
|
+
icon: "close",
|
|
2268
|
+
size: "xs",
|
|
2269
|
+
variant: "clear",
|
|
2270
|
+
color: "danger",
|
|
2271
|
+
onClick: () => handleRemoveCapability(idx)
|
|
2272
|
+
})
|
|
2273
|
+
)
|
|
2274
|
+
)
|
|
2275
|
+
)
|
|
2276
|
+
),
|
|
2277
|
+
// ── Instructions ──
|
|
2278
|
+
React9.createElement(
|
|
2279
|
+
Field,
|
|
2280
|
+
{ label: "Instructions" },
|
|
2281
|
+
React9.createElement(Input2, {
|
|
2282
|
+
type: "text",
|
|
2283
|
+
size: "small",
|
|
2284
|
+
placeholder: "Optional instructions for the bot",
|
|
2285
|
+
value: instructions,
|
|
2286
|
+
onChange: (v) => setInstructions(v),
|
|
2287
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
2288
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
2289
|
+
})
|
|
2290
|
+
),
|
|
2291
|
+
// ── Require Approval ──
|
|
2292
|
+
React9.createElement(
|
|
2293
|
+
Field,
|
|
2294
|
+
{ label: "" },
|
|
2295
|
+
React9.createElement(Checkbox2, {
|
|
2296
|
+
checked: requireApproval,
|
|
2297
|
+
onChange: (v) => setRequireApproval(v),
|
|
2298
|
+
label: "Require approval",
|
|
2299
|
+
size: "sm"
|
|
2300
|
+
})
|
|
2301
|
+
),
|
|
2302
|
+
// ── Save button ──
|
|
2303
|
+
React9.createElement(
|
|
2304
|
+
Flex8,
|
|
2305
|
+
{ variant: "row-center-end-nowrap-8" },
|
|
2306
|
+
React9.createElement(Button3, {
|
|
2307
|
+
size: "xs",
|
|
2308
|
+
variant: "fill",
|
|
2309
|
+
color: "primary",
|
|
2310
|
+
onClick: handleSave,
|
|
2311
|
+
disabled: !name.trim() || !botId || capabilities.length === 0
|
|
2312
|
+
}, mode === "create" ? "Create" : "Save")
|
|
2313
|
+
)
|
|
2314
|
+
)
|
|
2315
|
+
);
|
|
2316
|
+
}
|
|
2317
|
+
var profile_editor_default = ProfileEditor;
|
|
2318
|
+
module.exports = ProfileEditor;
|
|
2319
|
+
|
|
2320
|
+
// src/ui/decision-log.tsx
|
|
2321
|
+
var React10 = require("react");
|
|
2322
|
+
var {
|
|
2323
|
+
Flex: Flex9,
|
|
2324
|
+
Typography: Typography8,
|
|
2325
|
+
ScrollArea: ScrollArea3,
|
|
2326
|
+
Tag: Tag4,
|
|
2327
|
+
SectionTitle: SectionTitle2
|
|
2328
|
+
} = require("@fw/plugin-ui-kit");
|
|
2329
|
+
var methodColors = {
|
|
2330
|
+
"exact-match": "info",
|
|
2331
|
+
"single-eligible": "positive",
|
|
2332
|
+
"ai-routed": "secondary",
|
|
2333
|
+
"round-robin": "secondary",
|
|
2334
|
+
"manual": "caution"
|
|
2335
|
+
};
|
|
2336
|
+
var methodLabels = {
|
|
2337
|
+
"exact-match": "exact",
|
|
2338
|
+
"single-eligible": "single",
|
|
2339
|
+
"ai-routed": "ai",
|
|
2340
|
+
"round-robin": "robin",
|
|
2341
|
+
"manual": "manual"
|
|
2342
|
+
};
|
|
2343
|
+
function formatTime(ts) {
|
|
2344
|
+
const d = new Date(ts);
|
|
2345
|
+
return d.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
2346
|
+
}
|
|
2347
|
+
function truncate(text, max) {
|
|
2348
|
+
return text.length > max ? text.slice(0, max - 1) + "\u2026" : text;
|
|
2349
|
+
}
|
|
2350
|
+
function DecisionLog({ decisions }) {
|
|
2351
|
+
if (!decisions || decisions.length === 0) {
|
|
2352
|
+
return React10.createElement(
|
|
2353
|
+
Flex9,
|
|
2354
|
+
{
|
|
2355
|
+
variant: "column-stretch-start-nowrap-4"
|
|
2356
|
+
},
|
|
2357
|
+
React10.createElement(SectionTitle2, null, "Decision Log"),
|
|
2358
|
+
React10.createElement(Typography8, {
|
|
2359
|
+
variant: "smallCaption-regular",
|
|
2360
|
+
color: "color-text-subtle"
|
|
2361
|
+
}, "No routing decisions yet.")
|
|
2362
|
+
);
|
|
2363
|
+
}
|
|
2364
|
+
const sorted = [...decisions].sort((a, b) => b.timestamp - a.timestamp);
|
|
2365
|
+
return React10.createElement(
|
|
2366
|
+
Flex9,
|
|
2367
|
+
{
|
|
2368
|
+
variant: "column-stretch-start-nowrap-4"
|
|
2369
|
+
},
|
|
2370
|
+
React10.createElement(SectionTitle2, null, "Decision Log"),
|
|
2371
|
+
React10.createElement(
|
|
2372
|
+
ScrollArea3,
|
|
2373
|
+
{
|
|
2374
|
+
style: { maxHeight: "260px" }
|
|
2375
|
+
},
|
|
2376
|
+
React10.createElement(
|
|
2377
|
+
Flex9,
|
|
2378
|
+
{
|
|
2379
|
+
variant: "column-stretch-start-nowrap-0"
|
|
2380
|
+
},
|
|
2381
|
+
...sorted.map((d) => {
|
|
2382
|
+
const methodLabel = d.method === "ai-routed" && d.confidence != null ? `ai ${d.confidence}%` : methodLabels[d.method] || d.method;
|
|
2383
|
+
return React10.createElement(
|
|
2384
|
+
Flex9,
|
|
2385
|
+
{
|
|
2386
|
+
key: d.id,
|
|
2387
|
+
variant: "column-stretch-start-nowrap-2",
|
|
2388
|
+
style: {
|
|
2389
|
+
padding: "6px 8px",
|
|
2390
|
+
borderBottom: "1px solid var(--color-border-default)"
|
|
2391
|
+
}
|
|
2392
|
+
},
|
|
2393
|
+
// Main line: time, title, instance, method
|
|
2394
|
+
React10.createElement(
|
|
2395
|
+
Flex9,
|
|
2396
|
+
{ variant: "row-center-start-nowrap-8" },
|
|
2397
|
+
React10.createElement(Typography8, {
|
|
2398
|
+
variant: "smallCaption-regular",
|
|
2399
|
+
color: "color-text-subtle",
|
|
2400
|
+
style: { flexShrink: 0, fontFamily: "var(--font-mono, monospace)", fontSize: "11px" }
|
|
2401
|
+
}, formatTime(d.timestamp)),
|
|
2402
|
+
React10.createElement(Typography8, {
|
|
2403
|
+
variant: "smallCaption-regular",
|
|
2404
|
+
color: "color-text-high",
|
|
2405
|
+
style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
|
|
2406
|
+
}, `"${truncate(d.taskTitle, 40)}"`),
|
|
2407
|
+
React10.createElement(Typography8, {
|
|
2408
|
+
variant: "smallCaption-regular",
|
|
2409
|
+
color: "color-text-medium",
|
|
2410
|
+
style: { flexShrink: 0 }
|
|
2411
|
+
}, `\u2192 ${d.assignedInstanceId}`),
|
|
2412
|
+
React10.createElement(Tag4, {
|
|
2413
|
+
size: "small",
|
|
2414
|
+
color: methodColors[d.method] || "secondary"
|
|
2415
|
+
}, methodLabel)
|
|
2416
|
+
),
|
|
2417
|
+
// Reason line
|
|
2418
|
+
React10.createElement(Typography8, {
|
|
2419
|
+
variant: "smallCaption-regular",
|
|
2420
|
+
color: "color-text-subtle",
|
|
2421
|
+
style: { paddingLeft: "70px" }
|
|
2422
|
+
}, d.reason)
|
|
2423
|
+
);
|
|
2424
|
+
})
|
|
2425
|
+
)
|
|
2426
|
+
)
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
var decision_log_default = DecisionLog;
|
|
2430
|
+
module.exports = DecisionLog;
|
|
2431
|
+
|
|
2432
|
+
// src/ui/swarm-dashboard.tsx
|
|
2433
|
+
var React11 = require("react");
|
|
2434
|
+
var { useState: useState7, useEffect: useEffect4, useCallback: useCallback5, useRef: useRef3 } = React11;
|
|
2435
|
+
var {
|
|
2436
|
+
Flex: Flex10,
|
|
2437
|
+
ScrollArea: ScrollArea4,
|
|
2438
|
+
EmptyState: EmptyState3,
|
|
2439
|
+
Typography: Typography9,
|
|
2440
|
+
StatusIcon: StatusIcon4,
|
|
2441
|
+
Icon: Icon6,
|
|
2442
|
+
Tag: Tag5,
|
|
2443
|
+
Card: Card2,
|
|
2444
|
+
Tabs: Tabs2,
|
|
2445
|
+
SectionTitle: SectionTitle3,
|
|
2446
|
+
Button: Button4,
|
|
2447
|
+
Input: Input3,
|
|
2448
|
+
IconButton: IconButton7,
|
|
2449
|
+
IconPicker: IconPicker2,
|
|
2450
|
+
ColorPicker: ColorPicker2,
|
|
2451
|
+
toast: toast5,
|
|
2452
|
+
usePackWorkspace: usePackWorkspace5
|
|
2453
|
+
} = require("@fw/plugin-ui-kit");
|
|
1510
2454
|
function parseToolResult2(raw) {
|
|
1511
2455
|
if (typeof raw === "string") {
|
|
1512
2456
|
try {
|
|
@@ -1523,20 +2467,29 @@ function resolveTaskTitle(taskId, tasks) {
|
|
|
1523
2467
|
return task?.title;
|
|
1524
2468
|
}
|
|
1525
2469
|
function SwarmDashboard() {
|
|
1526
|
-
const ctx =
|
|
2470
|
+
const ctx = usePackWorkspace5();
|
|
1527
2471
|
const { callTool, onRefresh } = ctx;
|
|
1528
|
-
const [selectedTaskId, setSelectedTaskId] =
|
|
1529
|
-
const [
|
|
1530
|
-
const [
|
|
1531
|
-
const [
|
|
2472
|
+
const [selectedTaskId, setSelectedTaskId] = useState7(null);
|
|
2473
|
+
const [activeTab, setActiveTab] = useState7("tasks");
|
|
2474
|
+
const [editingBotId, setEditingBotId] = useState7(null);
|
|
2475
|
+
const [profileEditorMode, setProfileEditorMode] = useState7(null);
|
|
2476
|
+
const [editingProfileId, setEditingProfileId] = useState7(null);
|
|
2477
|
+
const [swarmStatus, setSwarmStatus] = useState7(null);
|
|
2478
|
+
const [tasks, setTasks] = useState7([]);
|
|
2479
|
+
const [registeredBots, setRegisteredBots] = useState7([]);
|
|
2480
|
+
const [providers, setProviders] = useState7([]);
|
|
2481
|
+
const [insights, setInsights] = useState7(null);
|
|
2482
|
+
const [profiles, setProfiles] = useState7([]);
|
|
2483
|
+
const [orchestratorDecisions, setOrchestratorDecisions] = useState7([]);
|
|
2484
|
+
const [loading, setLoading] = useState7(true);
|
|
1532
2485
|
const mountedRef = useRef3(true);
|
|
1533
|
-
|
|
2486
|
+
useEffect4(() => {
|
|
1534
2487
|
mountedRef.current = true;
|
|
1535
2488
|
return () => {
|
|
1536
2489
|
mountedRef.current = false;
|
|
1537
2490
|
};
|
|
1538
2491
|
}, []);
|
|
1539
|
-
const fetchSwarmStatus =
|
|
2492
|
+
const fetchSwarmStatus = useCallback5(async () => {
|
|
1540
2493
|
try {
|
|
1541
2494
|
const raw = await callTool("fw_weaver_swarm_status", {});
|
|
1542
2495
|
if (!mountedRef.current) return;
|
|
@@ -1545,7 +2498,7 @@ function SwarmDashboard() {
|
|
|
1545
2498
|
} catch {
|
|
1546
2499
|
}
|
|
1547
2500
|
}, [callTool]);
|
|
1548
|
-
const fetchTaskList =
|
|
2501
|
+
const fetchTaskList = useCallback5(async () => {
|
|
1549
2502
|
try {
|
|
1550
2503
|
const raw = await callTool("fw_weaver_task_list", {});
|
|
1551
2504
|
if (!mountedRef.current) return;
|
|
@@ -1558,155 +2511,500 @@ function SwarmDashboard() {
|
|
|
1558
2511
|
} catch {
|
|
1559
2512
|
}
|
|
1560
2513
|
}, [callTool]);
|
|
1561
|
-
const
|
|
1562
|
-
|
|
2514
|
+
const fetchBots = useCallback5(async () => {
|
|
2515
|
+
try {
|
|
2516
|
+
const raw = await callTool("fw_weaver_list_bots", {});
|
|
2517
|
+
if (!mountedRef.current) return;
|
|
2518
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2519
|
+
if (Array.isArray(data)) setRegisteredBots(data);
|
|
2520
|
+
} catch {
|
|
2521
|
+
}
|
|
2522
|
+
}, [callTool]);
|
|
2523
|
+
const fetchConfig = useCallback5(async () => {
|
|
2524
|
+
try {
|
|
2525
|
+
const [provRaw, insRaw] = await Promise.all([
|
|
2526
|
+
callTool("fw_weaver_providers", {}),
|
|
2527
|
+
callTool("fw_weaver_insights", {})
|
|
2528
|
+
]);
|
|
2529
|
+
if (!mountedRef.current) return;
|
|
2530
|
+
const provData = typeof provRaw === "string" ? JSON.parse(provRaw) : provRaw;
|
|
2531
|
+
const insData = typeof insRaw === "string" ? JSON.parse(insRaw) : insRaw;
|
|
2532
|
+
if (Array.isArray(provData)) setProviders(provData);
|
|
2533
|
+
if (insData && typeof insData === "object") setInsights(insData);
|
|
2534
|
+
} catch {
|
|
2535
|
+
}
|
|
2536
|
+
}, [callTool]);
|
|
2537
|
+
const fetchProfiles = useCallback5(async () => {
|
|
2538
|
+
try {
|
|
2539
|
+
const raw = await callTool("fw_weaver_profile_list", {});
|
|
2540
|
+
if (!mountedRef.current) return;
|
|
2541
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2542
|
+
if (Array.isArray(data)) setProfiles(data);
|
|
2543
|
+
} catch {
|
|
2544
|
+
}
|
|
2545
|
+
}, [callTool]);
|
|
2546
|
+
const fetchOrchestratorStatus = useCallback5(async () => {
|
|
2547
|
+
try {
|
|
2548
|
+
const raw = await callTool("fw_weaver_orchestrator_status", {});
|
|
2549
|
+
if (!mountedRef.current) return;
|
|
2550
|
+
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
2551
|
+
if (data && typeof data === "object") {
|
|
2552
|
+
const decisions = data.recentDecisions;
|
|
2553
|
+
if (Array.isArray(decisions)) setOrchestratorDecisions(decisions);
|
|
2554
|
+
}
|
|
2555
|
+
} catch {
|
|
2556
|
+
}
|
|
2557
|
+
}, [callTool]);
|
|
2558
|
+
const refreshAll = useCallback5(async () => {
|
|
2559
|
+
await Promise.all([fetchSwarmStatus(), fetchTaskList(), fetchBots(), fetchConfig(), fetchProfiles(), fetchOrchestratorStatus()]);
|
|
1563
2560
|
if (mountedRef.current) setLoading(false);
|
|
1564
|
-
}, [fetchSwarmStatus, fetchTaskList]);
|
|
1565
|
-
|
|
2561
|
+
}, [fetchSwarmStatus, fetchTaskList, fetchBots, fetchConfig, fetchProfiles, fetchOrchestratorStatus]);
|
|
2562
|
+
useEffect4(() => {
|
|
1566
2563
|
refreshAll();
|
|
1567
2564
|
}, [refreshAll]);
|
|
1568
|
-
|
|
2565
|
+
useEffect4(() => {
|
|
1569
2566
|
const interval = setInterval(fetchSwarmStatus, 3e3);
|
|
1570
2567
|
return () => clearInterval(interval);
|
|
1571
2568
|
}, [fetchSwarmStatus]);
|
|
1572
|
-
|
|
2569
|
+
useEffect4(() => {
|
|
1573
2570
|
const interval = setInterval(fetchTaskList, 5e3);
|
|
1574
2571
|
return () => clearInterval(interval);
|
|
1575
2572
|
}, [fetchTaskList]);
|
|
1576
|
-
|
|
2573
|
+
useEffect4(() => {
|
|
2574
|
+
const interval = setInterval(() => {
|
|
2575
|
+
fetchProfiles();
|
|
2576
|
+
fetchOrchestratorStatus();
|
|
2577
|
+
}, 1e4);
|
|
2578
|
+
return () => clearInterval(interval);
|
|
2579
|
+
}, [fetchProfiles, fetchOrchestratorStatus]);
|
|
2580
|
+
useEffect4(() => {
|
|
1577
2581
|
return onRefresh(() => refreshAll());
|
|
1578
2582
|
}, [refreshAll, onRefresh]);
|
|
1579
|
-
const
|
|
2583
|
+
const handleUpdateBot = useCallback5(async (botId, patch) => {
|
|
2584
|
+
try {
|
|
2585
|
+
await callTool("fw_weaver_register_bot", { id: botId, ...patch });
|
|
2586
|
+
await fetchBots();
|
|
2587
|
+
toast5("Bot updated", { type: "success" });
|
|
2588
|
+
} catch (err) {
|
|
2589
|
+
toast5(err instanceof Error ? err.message : "Failed to update bot", { type: "error" });
|
|
2590
|
+
}
|
|
2591
|
+
}, [callTool, fetchBots]);
|
|
2592
|
+
const handleSteerBot = useCallback5(async (botId, command) => {
|
|
2593
|
+
try {
|
|
2594
|
+
await callTool("fw_weaver_steer", { botId, command });
|
|
2595
|
+
toast5(`${command} signal sent to ${botId}`, { type: "info" });
|
|
2596
|
+
fetchSwarmStatus();
|
|
2597
|
+
} catch (err) {
|
|
2598
|
+
toast5(err instanceof Error ? err.message : `Failed to ${command}`, { type: "error" });
|
|
2599
|
+
}
|
|
2600
|
+
}, [callTool, fetchSwarmStatus]);
|
|
2601
|
+
const handleTaskClick = useCallback5((taskId) => {
|
|
1580
2602
|
setSelectedTaskId(taskId);
|
|
1581
2603
|
}, []);
|
|
1582
|
-
const handleBack =
|
|
2604
|
+
const handleBack = useCallback5(() => {
|
|
1583
2605
|
setSelectedTaskId(null);
|
|
1584
2606
|
refreshAll();
|
|
1585
2607
|
}, [refreshAll]);
|
|
1586
|
-
const handleTaskCreated =
|
|
2608
|
+
const handleTaskCreated = useCallback5(() => {
|
|
1587
2609
|
fetchTaskList();
|
|
1588
2610
|
}, [fetchTaskList]);
|
|
1589
2611
|
if (selectedTaskId) {
|
|
1590
|
-
return
|
|
2612
|
+
return React11.createElement(task_detail_view_default, {
|
|
1591
2613
|
taskId: selectedTaskId,
|
|
1592
2614
|
onBack: handleBack
|
|
1593
2615
|
});
|
|
1594
2616
|
}
|
|
1595
|
-
const
|
|
1596
|
-
const
|
|
1597
|
-
const
|
|
1598
|
-
const
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
2617
|
+
const swarmInstances = swarmStatus?.instances ?? {};
|
|
2618
|
+
const swarmInstanceEntries = Object.values(swarmInstances);
|
|
2619
|
+
const hasSwarmInstances = swarmInstanceEntries.length > 0;
|
|
2620
|
+
const hasRegisteredBots = registeredBots.length > 0;
|
|
2621
|
+
const sessionBudget = swarmStatus?.budgets?.session;
|
|
2622
|
+
const hasBudget = !!(sessionBudget && (sessionBudget.limitTokens > 0 || sessionBudget.limitCost > 0));
|
|
2623
|
+
const hasContent = hasSwarmInstances || hasRegisteredBots || tasks.length > 0 || swarmStatus !== null;
|
|
2624
|
+
return React11.createElement(
|
|
2625
|
+
Flex10,
|
|
1602
2626
|
{
|
|
1603
2627
|
variant: "column-stretch-start-nowrap-0",
|
|
1604
2628
|
style: { width: "100%", height: "100%", overflow: "hidden" }
|
|
1605
2629
|
},
|
|
1606
2630
|
// ── SwarmControls (top bar) ──────────────────────────────────
|
|
1607
|
-
|
|
2631
|
+
React11.createElement(swarm_controls_default, {
|
|
1608
2632
|
swarmStatus,
|
|
1609
2633
|
onRefresh: refreshAll
|
|
1610
2634
|
}),
|
|
1611
2635
|
// ── BudgetBar (below controls) ──────────────────────────────
|
|
1612
|
-
hasBudget &&
|
|
1613
|
-
|
|
2636
|
+
hasBudget && React11.createElement(
|
|
2637
|
+
Flex10,
|
|
1614
2638
|
{
|
|
1615
2639
|
variant: "column-stretch-start-nowrap-4",
|
|
1616
|
-
style: {
|
|
1617
|
-
padding: "8px 16px",
|
|
1618
|
-
borderBottom: "1px solid var(--color-border-default)",
|
|
1619
|
-
flexShrink: 0
|
|
1620
|
-
}
|
|
2640
|
+
style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" }
|
|
1621
2641
|
},
|
|
1622
|
-
|
|
2642
|
+
React11.createElement(budget_bar_default, {
|
|
1623
2643
|
label: "Tokens",
|
|
1624
|
-
used:
|
|
1625
|
-
limit:
|
|
2644
|
+
used: sessionBudget.usedTokens,
|
|
2645
|
+
limit: sessionBudget.limitTokens,
|
|
1626
2646
|
unit: "tokens"
|
|
1627
2647
|
}),
|
|
1628
|
-
|
|
2648
|
+
React11.createElement(budget_bar_default, {
|
|
1629
2649
|
label: "Cost",
|
|
1630
|
-
used:
|
|
1631
|
-
limit:
|
|
2650
|
+
used: sessionBudget.usedCost,
|
|
2651
|
+
limit: sessionBudget.limitCost,
|
|
1632
2652
|
unit: "USD"
|
|
1633
2653
|
})
|
|
1634
2654
|
),
|
|
1635
2655
|
// ── Bot slot cards (horizontal scrollable row) ──────────────
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
bot,
|
|
1652
|
-
currentTaskTitle: resolveTaskTitle(bot.currentTaskId, tasks)
|
|
1653
|
-
})
|
|
1654
|
-
)
|
|
1655
|
-
),
|
|
1656
|
-
// ── Main scrollable area ────────────────────────────────────
|
|
1657
|
-
React8.createElement(
|
|
1658
|
-
Flex7,
|
|
2656
|
+
// ── Tabs ──────────────────────────────────────────────────────
|
|
2657
|
+
React11.createElement(Tabs2, {
|
|
2658
|
+
tabs: [
|
|
2659
|
+
{ id: "tasks", title: `Tasks (${tasks.length})` },
|
|
2660
|
+
{ id: "bots", title: hasSwarmInstances ? `Instances (${swarmInstanceEntries.length})` : `Bots (${registeredBots.length})` },
|
|
2661
|
+
{ id: "profiles", title: `Profiles (${profiles.length})` },
|
|
2662
|
+
{ id: "config", title: "Config" }
|
|
2663
|
+
],
|
|
2664
|
+
activeTabId: activeTab,
|
|
2665
|
+
onSelectTab: (id) => setActiveTab(id),
|
|
2666
|
+
size: "sm"
|
|
2667
|
+
}),
|
|
2668
|
+
// ── Tab content ──────────────────────────────────────────────
|
|
2669
|
+
React11.createElement(
|
|
2670
|
+
Flex10,
|
|
1659
2671
|
{
|
|
1660
2672
|
variant: "column-stretch-start-nowrap-0",
|
|
1661
|
-
style: { flex: 1, minHeight: 0 }
|
|
2673
|
+
style: { flex: 1, minHeight: 0, overflow: "auto" }
|
|
1662
2674
|
},
|
|
1663
|
-
//
|
|
1664
|
-
|
|
1665
|
-
|
|
2675
|
+
// Tasks tab
|
|
2676
|
+
activeTab === "tasks" && React11.createElement(
|
|
2677
|
+
Flex10,
|
|
1666
2678
|
{
|
|
1667
|
-
variant: "
|
|
1668
|
-
style: {
|
|
1669
|
-
padding: "8px 16px 4px",
|
|
1670
|
-
flexShrink: 0
|
|
1671
|
-
}
|
|
2679
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2680
|
+
style: { flex: 1, minHeight: 0 }
|
|
1672
2681
|
},
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
2682
|
+
!hasContent && !loading && React11.createElement(EmptyState3, {
|
|
2683
|
+
icon: "smartToy",
|
|
2684
|
+
message: "Swarm not started",
|
|
2685
|
+
description: "Start the swarm to begin processing tasks, or create tasks below."
|
|
2686
|
+
}),
|
|
2687
|
+
hasContent && React11.createElement(task_pool_list_default, {
|
|
2688
|
+
tasks,
|
|
2689
|
+
onTaskClick: handleTaskClick
|
|
2690
|
+
}),
|
|
2691
|
+
// Task create form (inside Tasks tab)
|
|
2692
|
+
React11.createElement(
|
|
2693
|
+
Flex10,
|
|
2694
|
+
{
|
|
2695
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2696
|
+
style: { padding: "8px 16px", flexShrink: 0, borderTop: "1px solid var(--color-border-default)" }
|
|
2697
|
+
},
|
|
2698
|
+
React11.createElement(task_create_form_default, {
|
|
2699
|
+
onTaskCreated: handleTaskCreated
|
|
2700
|
+
})
|
|
2701
|
+
)
|
|
1677
2702
|
),
|
|
1678
|
-
//
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
message: "Swarm not started",
|
|
1682
|
-
description: "Start the swarm to begin processing tasks, or create tasks below."
|
|
1683
|
-
}),
|
|
1684
|
-
hasContent && React8.createElement(
|
|
1685
|
-
Flex7,
|
|
2703
|
+
// Bots tab
|
|
2704
|
+
activeTab === "bots" && React11.createElement(
|
|
2705
|
+
Flex10,
|
|
1686
2706
|
{
|
|
1687
2707
|
variant: "column-stretch-start-nowrap-0",
|
|
1688
2708
|
style: { flex: 1, minHeight: 0 }
|
|
1689
2709
|
},
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
2710
|
+
// When swarm is running: show swarm instances
|
|
2711
|
+
hasSwarmInstances && React11.createElement(
|
|
2712
|
+
Flex10,
|
|
2713
|
+
{
|
|
2714
|
+
variant: "column-stretch-start-nowrap-0"
|
|
2715
|
+
},
|
|
2716
|
+
React11.createElement(
|
|
2717
|
+
Flex10,
|
|
2718
|
+
{
|
|
2719
|
+
variant: "row-center-start-nowrap-8",
|
|
2720
|
+
style: { padding: "8px 16px", borderBottom: "1px solid var(--color-border-default)" }
|
|
2721
|
+
},
|
|
2722
|
+
React11.createElement(Typography9, {
|
|
2723
|
+
variant: "smallCaption-regular",
|
|
2724
|
+
color: "color-text-subtle",
|
|
2725
|
+
style: { width: "120px", flexShrink: 0 }
|
|
2726
|
+
}, "Instance"),
|
|
2727
|
+
React11.createElement(Typography9, {
|
|
2728
|
+
variant: "smallCaption-regular",
|
|
2729
|
+
color: "color-text-subtle",
|
|
2730
|
+
style: { width: "110px", flexShrink: 0 }
|
|
2731
|
+
}, "Bot"),
|
|
2732
|
+
React11.createElement(Typography9, {
|
|
2733
|
+
variant: "smallCaption-regular",
|
|
2734
|
+
color: "color-text-subtle",
|
|
2735
|
+
style: { width: "70px", flexShrink: 0 }
|
|
2736
|
+
}, "Status"),
|
|
2737
|
+
React11.createElement(Typography9, {
|
|
2738
|
+
variant: "smallCaption-regular",
|
|
2739
|
+
color: "color-text-subtle",
|
|
2740
|
+
style: { flex: 1, minWidth: 0 }
|
|
2741
|
+
}, "Task"),
|
|
2742
|
+
React11.createElement(Typography9, {
|
|
2743
|
+
variant: "smallCaption-regular",
|
|
2744
|
+
color: "color-text-subtle",
|
|
2745
|
+
style: { width: "50px", flexShrink: 0, textAlign: "right" }
|
|
2746
|
+
}, "Tokens"),
|
|
2747
|
+
React11.createElement(Typography9, {
|
|
2748
|
+
variant: "smallCaption-regular",
|
|
2749
|
+
color: "color-text-subtle",
|
|
2750
|
+
style: { width: "50px", flexShrink: 0, textAlign: "right" }
|
|
2751
|
+
}, "Cost"),
|
|
2752
|
+
React11.createElement(Typography9, {
|
|
2753
|
+
variant: "smallCaption-regular",
|
|
2754
|
+
color: "color-text-subtle",
|
|
2755
|
+
style: { width: "50px", flexShrink: 0 }
|
|
2756
|
+
}, "")
|
|
2757
|
+
),
|
|
2758
|
+
...swarmInstanceEntries.map((inst) => {
|
|
2759
|
+
const profile = profiles.find((p) => p.id === inst.profileId);
|
|
2760
|
+
const botId = profile?.botId;
|
|
2761
|
+
const bot = registeredBots.find((b) => b.id === botId);
|
|
2762
|
+
return React11.createElement(bot_slot_card_default, {
|
|
2763
|
+
key: inst.instanceId,
|
|
2764
|
+
bot: {
|
|
2765
|
+
botId: inst.instanceId,
|
|
2766
|
+
botName: `${inst.profileId} #${inst.index}`,
|
|
2767
|
+
status: inst.status,
|
|
2768
|
+
currentTaskId: inst.currentTaskId,
|
|
2769
|
+
currentRunId: inst.currentRunId,
|
|
2770
|
+
startedAt: inst.startedAt,
|
|
2771
|
+
tokensUsed: inst.tokensUsed,
|
|
2772
|
+
cost: inst.cost
|
|
2773
|
+
},
|
|
2774
|
+
profileName: profile?.name || inst.profileId,
|
|
2775
|
+
botDisplayName: bot?.name,
|
|
2776
|
+
botIcon: bot?.icon,
|
|
2777
|
+
botColor: bot?.color,
|
|
2778
|
+
currentTaskTitle: resolveTaskTitle(inst.currentTaskId, tasks),
|
|
2779
|
+
onPause: (id) => handleSteerBot(id, "pause"),
|
|
2780
|
+
onResume: (id) => handleSteerBot(id, "resume"),
|
|
2781
|
+
onStop: (id) => handleSteerBot(id, "cancel")
|
|
2782
|
+
});
|
|
2783
|
+
})
|
|
2784
|
+
),
|
|
2785
|
+
// When swarm is NOT running: show registered bots
|
|
2786
|
+
!hasSwarmInstances && hasRegisteredBots && React11.createElement(
|
|
2787
|
+
Flex10,
|
|
2788
|
+
{
|
|
2789
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2790
|
+
style: { padding: "8px 16px" }
|
|
2791
|
+
},
|
|
2792
|
+
...registeredBots.map((bot) => {
|
|
2793
|
+
const isEditing = editingBotId === bot.id;
|
|
2794
|
+
return React11.createElement(
|
|
2795
|
+
Flex10,
|
|
2796
|
+
{
|
|
2797
|
+
key: bot.id,
|
|
2798
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2799
|
+
style: { borderBottom: "1px solid var(--color-border-default)" }
|
|
2800
|
+
},
|
|
2801
|
+
// Bot row (clickable to toggle edit)
|
|
2802
|
+
React11.createElement(
|
|
2803
|
+
Flex10,
|
|
2804
|
+
{
|
|
2805
|
+
variant: "row-center-start-nowrap-8",
|
|
2806
|
+
style: { padding: "6px 0", cursor: "pointer" },
|
|
2807
|
+
onClick: () => setEditingBotId(isEditing ? null : bot.id)
|
|
2808
|
+
},
|
|
2809
|
+
React11.createElement(Icon6, {
|
|
2810
|
+
name: bot.icon || "smartToy",
|
|
2811
|
+
size: 16,
|
|
2812
|
+
color: bot.color || "color-text-medium"
|
|
2813
|
+
}),
|
|
2814
|
+
React11.createElement(
|
|
2815
|
+
Flex10,
|
|
2816
|
+
{ variant: "column-start-start-nowrap-1", style: { flex: 1, minWidth: 0 } },
|
|
2817
|
+
React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-high" }, bot.name),
|
|
2818
|
+
bot.description && React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-subtle" }, bot.description)
|
|
2819
|
+
),
|
|
2820
|
+
React11.createElement(Icon6, { name: isEditing ? "expandLess" : "expandMore", size: 14, color: "color-text-subtle" })
|
|
2821
|
+
),
|
|
2822
|
+
// Edit section (icon + color pickers)
|
|
2823
|
+
isEditing && React11.createElement(
|
|
2824
|
+
Flex10,
|
|
2825
|
+
{
|
|
2826
|
+
variant: "column-stretch-start-nowrap-12",
|
|
2827
|
+
style: { padding: "8px 0 12px 24px" }
|
|
2828
|
+
},
|
|
2829
|
+
React11.createElement(IconPicker2, {
|
|
2830
|
+
catalog: ICON_CATALOG,
|
|
2831
|
+
value: bot.icon || "smartToy",
|
|
2832
|
+
onChange: (icon) => handleUpdateBot(bot.id, { icon }),
|
|
2833
|
+
accentColor: bot.color || void 0,
|
|
2834
|
+
defaultExpanded: true
|
|
2835
|
+
}),
|
|
2836
|
+
React11.createElement(ColorPicker2, {
|
|
2837
|
+
colors: BOT_COLORS,
|
|
2838
|
+
value: bot.color || "",
|
|
2839
|
+
onChange: (color) => handleUpdateBot(bot.id, { color }),
|
|
2840
|
+
defaultExpanded: true
|
|
2841
|
+
})
|
|
2842
|
+
)
|
|
2843
|
+
);
|
|
2844
|
+
})
|
|
2845
|
+
),
|
|
2846
|
+
// No bots at all
|
|
2847
|
+
!hasSwarmInstances && !hasRegisteredBots && React11.createElement(EmptyState3, {
|
|
2848
|
+
icon: "smartToy",
|
|
2849
|
+
message: "No bots registered",
|
|
2850
|
+
description: "Register bots to start the swarm."
|
|
1693
2851
|
})
|
|
2852
|
+
),
|
|
2853
|
+
// Profiles tab — when ProfileEditor is open, render it INSTEAD of the list
|
|
2854
|
+
activeTab === "profiles" && profileEditorMode != null && React11.createElement(profile_editor_default, {
|
|
2855
|
+
mode: profileEditorMode,
|
|
2856
|
+
profileId: editingProfileId ?? void 0,
|
|
2857
|
+
bots: registeredBots.map((b) => ({ id: b.id, name: b.name, icon: b.icon, color: b.color })),
|
|
2858
|
+
onSave: () => {
|
|
2859
|
+
setProfileEditorMode(null);
|
|
2860
|
+
setEditingProfileId(null);
|
|
2861
|
+
fetchProfiles();
|
|
2862
|
+
},
|
|
2863
|
+
onCancel: () => {
|
|
2864
|
+
setProfileEditorMode(null);
|
|
2865
|
+
setEditingProfileId(null);
|
|
2866
|
+
},
|
|
2867
|
+
onDelete: profileEditorMode === "edit" ? () => {
|
|
2868
|
+
setProfileEditorMode(null);
|
|
2869
|
+
setEditingProfileId(null);
|
|
2870
|
+
fetchProfiles();
|
|
2871
|
+
} : void 0
|
|
2872
|
+
}),
|
|
2873
|
+
// Profiles tab — default list view
|
|
2874
|
+
activeTab === "profiles" && profileEditorMode == null && React11.createElement(
|
|
2875
|
+
Flex10,
|
|
2876
|
+
{
|
|
2877
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2878
|
+
style: { flex: 1, minHeight: 0 }
|
|
2879
|
+
},
|
|
2880
|
+
// ── Profile cards (scrollable) ──
|
|
2881
|
+
React11.createElement(
|
|
2882
|
+
Flex10,
|
|
2883
|
+
{
|
|
2884
|
+
variant: "column-stretch-start-nowrap-8",
|
|
2885
|
+
style: { flex: 1, minHeight: 0, overflow: "auto", padding: "12px 16px" }
|
|
2886
|
+
},
|
|
2887
|
+
profiles.length > 0 ? React11.createElement(
|
|
2888
|
+
Flex10,
|
|
2889
|
+
{ variant: "column-stretch-start-nowrap-8" },
|
|
2890
|
+
...profiles.map((p) => {
|
|
2891
|
+
const activeCount = swarmInstanceEntries.filter(
|
|
2892
|
+
(inst) => inst.profileId === p.id && inst.status === "executing"
|
|
2893
|
+
).length;
|
|
2894
|
+
return React11.createElement(profile_card_default, {
|
|
2895
|
+
key: p.id,
|
|
2896
|
+
profile: p,
|
|
2897
|
+
activeInstances: activeCount,
|
|
2898
|
+
onEdit: (id) => {
|
|
2899
|
+
setEditingProfileId(id);
|
|
2900
|
+
setProfileEditorMode("edit");
|
|
2901
|
+
},
|
|
2902
|
+
onDelete: async (id) => {
|
|
2903
|
+
const ok = await ctx.confirm("Are you sure you want to delete this profile?", {
|
|
2904
|
+
title: "Delete Profile",
|
|
2905
|
+
confirmLabel: "Delete",
|
|
2906
|
+
state: "danger"
|
|
2907
|
+
});
|
|
2908
|
+
if (!ok) return;
|
|
2909
|
+
try {
|
|
2910
|
+
await callTool("fw_weaver_profile_delete", { id });
|
|
2911
|
+
await fetchProfiles();
|
|
2912
|
+
toast5("Profile deleted", { type: "success" });
|
|
2913
|
+
} catch (err) {
|
|
2914
|
+
toast5(err instanceof Error ? err.message : "Failed to delete profile", { type: "error" });
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
});
|
|
2918
|
+
})
|
|
2919
|
+
) : React11.createElement(EmptyState3, {
|
|
2920
|
+
icon: "person",
|
|
2921
|
+
message: "No profiles",
|
|
2922
|
+
description: "Profiles define how bots behave. Start the swarm to create defaults, or create one below."
|
|
2923
|
+
}),
|
|
2924
|
+
// ── Routing / Decision Log (inside scrollable area) ──
|
|
2925
|
+
orchestratorDecisions.length > 0 && React11.createElement(decision_log_default, {
|
|
2926
|
+
decisions: orchestratorDecisions
|
|
2927
|
+
})
|
|
2928
|
+
),
|
|
2929
|
+
// ── New Profile button (bottom bar) ──
|
|
2930
|
+
React11.createElement(
|
|
2931
|
+
Flex10,
|
|
2932
|
+
{
|
|
2933
|
+
variant: "column-stretch-start-nowrap-0",
|
|
2934
|
+
style: { flexShrink: 0, borderTop: "1px solid var(--color-border-default)", padding: "8px 16px" }
|
|
2935
|
+
},
|
|
2936
|
+
React11.createElement(Button4, {
|
|
2937
|
+
size: "xs",
|
|
2938
|
+
variant: "clear",
|
|
2939
|
+
color: "primary",
|
|
2940
|
+
leftIcon: "add",
|
|
2941
|
+
onClick: () => setProfileEditorMode("create")
|
|
2942
|
+
}, "New Profile")
|
|
2943
|
+
)
|
|
2944
|
+
),
|
|
2945
|
+
// Config tab
|
|
2946
|
+
activeTab === "config" && React11.createElement(
|
|
2947
|
+
Flex10,
|
|
2948
|
+
{
|
|
2949
|
+
variant: "column-stretch-start-nowrap-12",
|
|
2950
|
+
style: { padding: "12px 16px" }
|
|
2951
|
+
},
|
|
2952
|
+
// ── Provider ──
|
|
2953
|
+
React11.createElement(
|
|
2954
|
+
Flex10,
|
|
2955
|
+
{ variant: "row-center-space-between-nowrap-8" },
|
|
2956
|
+
React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Provider"),
|
|
2957
|
+
React11.createElement(
|
|
2958
|
+
Flex10,
|
|
2959
|
+
{ variant: "row-center-start-nowrap-4" },
|
|
2960
|
+
React11.createElement(
|
|
2961
|
+
Typography9,
|
|
2962
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
2963
|
+
providers.find((p) => p.envVarsSet)?.name ?? "None detected"
|
|
2964
|
+
),
|
|
2965
|
+
providers.find((p) => p.envVarsSet) && React11.createElement(Tag5, { size: "small", color: "info" }, "active")
|
|
2966
|
+
)
|
|
2967
|
+
),
|
|
2968
|
+
// Trust
|
|
2969
|
+
insights?.trust && React11.createElement(
|
|
2970
|
+
Flex10,
|
|
2971
|
+
{ variant: "row-center-space-between-nowrap-8" },
|
|
2972
|
+
React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Trust"),
|
|
2973
|
+
React11.createElement(
|
|
2974
|
+
Typography9,
|
|
2975
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
2976
|
+
`Phase ${insights.trust.phase} \xB7 ${insights.trust.score}/100`
|
|
2977
|
+
)
|
|
2978
|
+
),
|
|
2979
|
+
// Health
|
|
2980
|
+
insights?.health && React11.createElement(
|
|
2981
|
+
Flex10,
|
|
2982
|
+
{ variant: "row-center-space-between-nowrap-8" },
|
|
2983
|
+
React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Health"),
|
|
2984
|
+
React11.createElement(
|
|
2985
|
+
Typography9,
|
|
2986
|
+
{ variant: "smallCaption-regular", color: "color-text-high" },
|
|
2987
|
+
`${insights.health.overall}/100`
|
|
2988
|
+
)
|
|
2989
|
+
),
|
|
2990
|
+
// Available providers
|
|
2991
|
+
providers.length > 0 && React11.createElement(
|
|
2992
|
+
Flex10,
|
|
2993
|
+
{ variant: "column-stretch-start-nowrap-4" },
|
|
2994
|
+
React11.createElement(Typography9, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Available Providers"),
|
|
2995
|
+
React11.createElement(
|
|
2996
|
+
Flex10,
|
|
2997
|
+
{ variant: "row-center-start-wrap-4" },
|
|
2998
|
+
...providers.map(
|
|
2999
|
+
(p) => React11.createElement(Tag5, {
|
|
3000
|
+
key: p.name,
|
|
3001
|
+
size: "small",
|
|
3002
|
+
color: p.envVarsSet ? "positive" : "secondary"
|
|
3003
|
+
}, p.name)
|
|
3004
|
+
)
|
|
3005
|
+
)
|
|
3006
|
+
)
|
|
1694
3007
|
)
|
|
1695
|
-
),
|
|
1696
|
-
// ── Task create form (bottom, collapsible) ──────────────────
|
|
1697
|
-
React8.createElement(
|
|
1698
|
-
Flex7,
|
|
1699
|
-
{
|
|
1700
|
-
variant: "column-stretch-start-nowrap-0",
|
|
1701
|
-
style: {
|
|
1702
|
-
padding: "8px 16px",
|
|
1703
|
-
borderTop: "1px solid var(--color-border-default)",
|
|
1704
|
-
flexShrink: 0
|
|
1705
|
-
}
|
|
1706
|
-
},
|
|
1707
|
-
React8.createElement(task_create_form_default, {
|
|
1708
|
-
onTaskCreated: handleTaskCreated
|
|
1709
|
-
})
|
|
1710
3008
|
)
|
|
1711
3009
|
);
|
|
1712
3010
|
}
|