@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.
Files changed (162) hide show
  1. package/dist/ai-chat-provider.d.ts +12 -0
  2. package/dist/ai-chat-provider.d.ts.map +1 -1
  3. package/dist/ai-chat-provider.js +173 -19
  4. package/dist/ai-chat-provider.js.map +1 -1
  5. package/dist/bot/agent-loop.d.ts +20 -0
  6. package/dist/bot/agent-loop.d.ts.map +1 -0
  7. package/dist/bot/agent-loop.js +331 -0
  8. package/dist/bot/agent-loop.js.map +1 -0
  9. package/dist/bot/ai-router.d.ts +19 -0
  10. package/dist/bot/ai-router.d.ts.map +1 -0
  11. package/dist/bot/ai-router.js +104 -0
  12. package/dist/bot/ai-router.js.map +1 -0
  13. package/dist/bot/bot-registry.js +2 -2
  14. package/dist/bot/bot-registry.js.map +1 -1
  15. package/dist/bot/conversation-store.d.ts +1 -0
  16. package/dist/bot/conversation-store.d.ts.map +1 -1
  17. package/dist/bot/conversation-store.js.map +1 -1
  18. package/dist/bot/improve-loop.js.map +1 -1
  19. package/dist/bot/instance-manager.d.ts +31 -0
  20. package/dist/bot/instance-manager.d.ts.map +1 -0
  21. package/dist/bot/instance-manager.js +115 -0
  22. package/dist/bot/instance-manager.js.map +1 -0
  23. package/dist/bot/orchestrator.d.ts +36 -0
  24. package/dist/bot/orchestrator.d.ts.map +1 -0
  25. package/dist/bot/orchestrator.js +176 -0
  26. package/dist/bot/orchestrator.js.map +1 -0
  27. package/dist/bot/profile-store.d.ts +36 -0
  28. package/dist/bot/profile-store.d.ts.map +1 -0
  29. package/dist/bot/profile-store.js +208 -0
  30. package/dist/bot/profile-store.js.map +1 -0
  31. package/dist/bot/profile-types.d.ts +126 -0
  32. package/dist/bot/profile-types.d.ts.map +1 -0
  33. package/dist/bot/profile-types.js +7 -0
  34. package/dist/bot/profile-types.js.map +1 -0
  35. package/dist/bot/session-state.d.ts +25 -0
  36. package/dist/bot/session-state.d.ts.map +1 -0
  37. package/dist/bot/session-state.js +110 -0
  38. package/dist/bot/session-state.js.map +1 -0
  39. package/dist/bot/swarm-controller.d.ts +37 -21
  40. package/dist/bot/swarm-controller.d.ts.map +1 -1
  41. package/dist/bot/swarm-controller.js +344 -163
  42. package/dist/bot/swarm-controller.js.map +1 -1
  43. package/dist/bot/task-prompt-builder.d.ts +2 -1
  44. package/dist/bot/task-prompt-builder.d.ts.map +1 -1
  45. package/dist/bot/task-prompt-builder.js +33 -10
  46. package/dist/bot/task-prompt-builder.js.map +1 -1
  47. package/dist/bot/task-queue.d.ts +46 -0
  48. package/dist/bot/task-queue.d.ts.map +1 -0
  49. package/dist/bot/task-queue.js +237 -0
  50. package/dist/bot/task-queue.js.map +1 -0
  51. package/dist/bot/task-store.d.ts +1 -6
  52. package/dist/bot/task-store.d.ts.map +1 -1
  53. package/dist/bot/task-store.js +27 -78
  54. package/dist/bot/task-store.js.map +1 -1
  55. package/dist/bot/task-types.d.ts +8 -4
  56. package/dist/bot/task-types.d.ts.map +1 -1
  57. package/dist/cli-handlers.d.ts.map +1 -1
  58. package/dist/cli-handlers.js +2 -3
  59. package/dist/cli-handlers.js.map +1 -1
  60. package/dist/cli.d.ts +3 -0
  61. package/dist/cli.d.ts.map +1 -0
  62. package/dist/cli.js +749 -0
  63. package/dist/cli.js.map +1 -0
  64. package/dist/docs/docs/weaver-bot-usage.md +35 -18
  65. package/dist/docs/docs/weaver-config.md +20 -0
  66. package/dist/docs/docs/weaver-task-queue.md +31 -19
  67. package/dist/docs/weaver-config.md +15 -9
  68. package/dist/mcp-tools.d.ts +17 -0
  69. package/dist/mcp-tools.d.ts.map +1 -1
  70. package/dist/mcp-tools.js +98 -232
  71. package/dist/mcp-tools.js.map +1 -1
  72. package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
  73. package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
  74. package/dist/node-types/orchestrator-dispatch.js +63 -0
  75. package/dist/node-types/orchestrator-dispatch.js.map +1 -0
  76. package/dist/node-types/orchestrator-load-state.d.ts +16 -0
  77. package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
  78. package/dist/node-types/orchestrator-load-state.js +60 -0
  79. package/dist/node-types/orchestrator-load-state.js.map +1 -0
  80. package/dist/node-types/orchestrator-route.d.ts +16 -0
  81. package/dist/node-types/orchestrator-route.d.ts.map +1 -0
  82. package/dist/node-types/orchestrator-route.js +28 -0
  83. package/dist/node-types/orchestrator-route.js.map +1 -0
  84. package/dist/node-types/receive-task.d.ts +2 -3
  85. package/dist/node-types/receive-task.d.ts.map +1 -1
  86. package/dist/node-types/receive-task.js +3 -28
  87. package/dist/node-types/receive-task.js.map +1 -1
  88. package/dist/templates/weaver-template.d.ts +11 -0
  89. package/dist/templates/weaver-template.d.ts.map +1 -0
  90. package/dist/templates/weaver-template.js +53 -0
  91. package/dist/templates/weaver-template.js.map +1 -0
  92. package/dist/ui/bot-constants.d.ts +14 -0
  93. package/dist/ui/bot-constants.d.ts.map +1 -0
  94. package/dist/ui/bot-constants.js +189 -0
  95. package/dist/ui/bot-constants.js.map +1 -0
  96. package/dist/ui/bot-panel.js +51 -90
  97. package/dist/ui/bot-slot-card.js +87 -122
  98. package/dist/ui/budget-bar.js +5 -3
  99. package/dist/ui/chat-task-result.js +4 -7
  100. package/dist/ui/decision-log.js +136 -0
  101. package/dist/ui/profile-card.js +158 -0
  102. package/dist/ui/profile-editor.js +597 -0
  103. package/dist/ui/swarm-controls.js +36 -27
  104. package/dist/ui/swarm-dashboard.js +2034 -736
  105. package/dist/ui/task-create-form.js +39 -116
  106. package/dist/ui/task-detail-view.js +490 -239
  107. package/dist/ui/task-pool-list.js +69 -94
  108. package/dist/workflows/orchestrator.d.ts +21 -0
  109. package/dist/workflows/orchestrator.d.ts.map +1 -0
  110. package/dist/workflows/orchestrator.js +281 -0
  111. package/dist/workflows/orchestrator.js.map +1 -0
  112. package/dist/workflows/weaver-bot-session.d.ts +65 -0
  113. package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
  114. package/dist/workflows/weaver-bot-session.js +68 -0
  115. package/dist/workflows/weaver-bot-session.js.map +1 -0
  116. package/dist/workflows/weaver.d.ts +24 -0
  117. package/dist/workflows/weaver.d.ts.map +1 -0
  118. package/dist/workflows/weaver.js +28 -0
  119. package/dist/workflows/weaver.js.map +1 -0
  120. package/flowweaver.manifest.json +253 -66
  121. package/package.json +1 -1
  122. package/src/ai-chat-provider.ts +184 -18
  123. package/src/bot/ai-router.ts +132 -0
  124. package/src/bot/bot-registry.ts +2 -2
  125. package/src/bot/conversation-store.ts +2 -1
  126. package/src/bot/improve-loop.ts +6 -6
  127. package/src/bot/instance-manager.ts +128 -0
  128. package/src/bot/orchestrator.ts +244 -0
  129. package/src/bot/profile-store.ts +225 -0
  130. package/src/bot/profile-types.ts +141 -0
  131. package/src/bot/swarm-controller.ts +385 -186
  132. package/src/bot/task-prompt-builder.ts +37 -6
  133. package/src/bot/task-store.ts +28 -89
  134. package/src/bot/task-types.ts +10 -4
  135. package/src/cli-handlers.ts +2 -3
  136. package/src/docs/weaver-bot-usage.md +35 -18
  137. package/src/docs/weaver-config.md +20 -0
  138. package/src/docs/weaver-task-queue.md +31 -19
  139. package/src/mcp-tools.ts +129 -320
  140. package/src/node-types/orchestrator-dispatch.ts +71 -0
  141. package/src/node-types/orchestrator-load-state.ts +66 -0
  142. package/src/node-types/orchestrator-route.ts +33 -0
  143. package/src/node-types/receive-task.ts +3 -26
  144. package/src/ui/bot-constants.ts +192 -0
  145. package/src/ui/bot-panel.tsx +55 -79
  146. package/src/ui/bot-slot-card.tsx +69 -117
  147. package/src/ui/budget-bar.tsx +5 -3
  148. package/src/ui/chat-task-result.tsx +6 -9
  149. package/src/ui/decision-log.tsx +148 -0
  150. package/src/ui/profile-card.tsx +157 -0
  151. package/src/ui/profile-editor.tsx +384 -0
  152. package/src/ui/swarm-controls.tsx +35 -31
  153. package/src/ui/swarm-dashboard.tsx +409 -80
  154. package/src/ui/task-create-form.tsx +29 -119
  155. package/src/ui/task-detail-view.tsx +461 -215
  156. package/src/ui/task-pool-list.tsx +74 -95
  157. package/src/workflows/orchestrator.ts +302 -0
  158. package/dist/docs/weaver-bot-usage.md +0 -34
  159. package/dist/docs/weaver-genesis.md +0 -32
  160. package/dist/docs/weaver-task-queue.md +0 -34
  161. package/src/bot/error-guide.ts +0 -4
  162. 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 statusToVariant(status) {
50
+ function swarmStatusToIconStatus(status) {
41
51
  switch (status) {
42
52
  case "running":
43
- return "positive";
53
+ return "running";
44
54
  case "paused":
45
- return "caution";
55
+ return "pending";
46
56
  case "stopping":
47
- return "negative";
57
+ return "failed";
48
58
  case "idle":
49
59
  default:
50
- return "neutral";
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 countActiveBots(bots) {
67
- const entries = Object.values(bots);
68
- const active = entries.filter((b) => b.status === "executing").length;
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 bots = swarmStatus?.bots ?? {};
78
- const { active, total } = countActiveBots(bots);
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
- variant: statusToVariant(status),
169
- size: 10
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, fontSize: "12px" }
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-6", style: { flexShrink: 0 } },
217
+ { variant: "row-center-start-nowrap-4", style: { flexShrink: 0 } },
200
218
  // Start / Resume button
201
219
  (isIdle || isPaused) && React.createElement(Button, {
202
- size: "sm",
203
- variant: "clear",
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: "sm",
211
- variant: "clear",
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: "sm",
219
- variant: "clear",
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: "refresh",
247
+ icon: "reset",
228
248
  size: "xs",
229
- variant: "clear",
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
- "div",
279
+ Flex2,
261
280
  {
262
- style: { width: "100%", height: "4px", borderRadius: "2px", backgroundColor: "var(--color-surface-raised)" }
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("div", {
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 React3 = require("react");
275
- var { Flex: Flex3, Typography: Typography3, IconButton: IconButton2, StatusIcon: StatusIcon2, Icon } = require("@fw/plugin-ui-kit");
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 iconColor = dotStatus === "neutral" ? "color-text-subtle" : `color-status-${dotStatus}`;
311
- const taskText = isExecuting ? currentTaskTitle || currentTaskId || "Working..." : null;
312
- const actions = React3.createElement(
313
- Flex3,
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-center-nowrap-2",
316
- style: { marginTop: "4px" }
321
+ variant: "row-center-start-nowrap-8",
322
+ style: { padding: "6px 16px", minHeight: "38px", borderBottom: "1px solid var(--color-border-default)" }
317
323
  },
318
- // Pause / Resume button
319
- isExecuting && onPause ? React3.createElement(IconButton2, {
320
- icon: "pause",
321
- size: "xs",
322
- variant: "clear",
323
- onClick: (e) => {
324
- e.stopPropagation();
325
- onPause(botId);
326
- },
327
- title: "Pause bot"
328
- }) : null,
329
- isPaused && onResume ? React3.createElement(IconButton2, {
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
- title: "Stop bot"
349
- }) : null
350
- );
351
- const hasActions = isExecuting && onPause || isPaused && onResume || (isExecuting || isPaused) && onStop;
352
- return React3.createElement(
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
- // Row 2: Status label
390
- React3.createElement(Typography3, {
343
+ // Status
344
+ import_react.default.createElement(import_plugin_ui_kit.Typography, {
391
345
  variant: "smallCaption-regular",
392
- color: iconColor,
393
- style: { textTransform: "capitalize" }
346
+ color: isExecuting ? "color-brand-main" : "color-text-subtle",
347
+ style: { width: "70px", flexShrink: 0 }
394
348
  }, label),
395
- // Row 3: Current task (if executing)
396
- taskText ? React3.createElement(Typography3, {
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
- overflow: "hidden",
401
- textOverflow: "ellipsis",
402
- whiteSpace: "nowrap"
403
- }
404
- }, taskText) : null,
405
- // Row 4: Tokens + cost
406
- React3.createElement(
407
- Flex3,
408
- { variant: "row-center-between-nowrap-4", style: { marginTop: "auto" } },
409
- React3.createElement(Typography3, {
410
- variant: "smallCaption-regular",
411
- color: "color-text-subtle"
412
- }, formatTokens(tokensUsed)),
413
- React3.createElement(Typography3, {
414
- variant: "smallCaption-regular",
415
- color: "color-text-subtle"
416
- }, formatCost(cost))
417
- ),
418
- // Row 5: Actions (optional)
419
- hasActions ? actions : null
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 { Flex: Flex4, Typography: Typography4, Icon: Icon2, StatusIcon: StatusIcon3, Tag, ScrollArea, Badge } = require("@fw/plugin-ui-kit");
428
- var { styled } = require("@fw/plugin-theme");
429
- var statusToIcon2 = {
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 statusToColor = {
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 $color-border-default",
458
- "&:hover": { backgroundColor: "$color-surface-elevated" }
459
- });
460
- var TitleText = styled.div({
461
- flex: 1,
462
- overflow: "hidden",
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 TaskPoolList({ tasks, onTaskClick }) {
517
- if (!tasks || tasks.length === 0) {
518
- return React4.createElement(
519
- EmptyState,
520
- null,
521
- React4.createElement(Icon2, { name: "inbox", size: 20, color: "color-text-subtle" }),
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
- }, "No tasks in the pool.")
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
- Container,
531
- null,
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
- TaskRow,
538
- {
539
- key: task.id,
540
- style: indent ? { paddingLeft: "32px" } : void 0,
541
- onClick: () => onTaskClick(task.id)
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 React5 = require("react");
584
- var { useState: useState2, useCallback: useCallback2 } = React5;
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 = usePackWorkspace2();
548
+ const ctx = (0, import_plugin_ui_kit2.usePackWorkspace)();
605
549
  const { callTool } = ctx;
606
- const [open, setOpen] = useState2(false);
607
- const [title, setTitle] = useState2("");
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 trimmedTitle = title.trim();
614
- if (!trimmedTitle) {
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
- const taskTitle = result?.task?.title ?? trimmedTitle;
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
- toast2(err instanceof Error ? err.message : "Failed to create task", { type: "error" });
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, description, priority, callTool, onTaskCreated]);
638
- const toggleButton = React5.createElement(Button2, {
639
- variant: "ghost",
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: "column-start-start-nowrap-2",
654
- style: { width: "100%" }
571
+ variant: "row-center-start-nowrap-6"
655
572
  },
656
- React5.createElement(Typography5, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Title *"),
657
- React5.createElement(Input, {
658
- placeholder: "Task title",
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
- disabled: creating
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
- multiline: true
677
- })
678
- );
679
- const priorityField = React5.createElement(
680
- Flex5,
681
- {
682
- variant: "column-start-start-nowrap-2",
683
- style: { width: "100%" }
684
- },
685
- React5.createElement(Typography5, { variant: "smallCaption-regular", color: "color-text-subtle" }, "Priority"),
686
- React5.createElement(Input, {
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: useState3, useEffect, useRef } = React6;
599
+ var { useMemo, useState: useState4, useEffect, useRef } = React6;
736
600
  function useStreamTimeline(events, isDone) {
737
- const [elapsed, setElapsed] = useState3(0);
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: useState4, useEffect: useEffect2, useCallback: useCallback3, useRef: useRef2, useMemo: useMemo2 } = React7;
859
+ var { useState: useState5, useEffect: useEffect2, useCallback: useCallback3, useRef: useRef2, useMemo: useMemo2 } = React7;
996
860
  var {
997
861
  Flex: Flex6,
998
- Typography: Typography6,
862
+ Typography: Typography5,
999
863
  ScrollArea: ScrollArea2,
1000
- StatusIcon: StatusIcon4,
864
+ StatusIcon: StatusIcon3,
1001
865
  Tag: Tag2,
1002
866
  Badge: Badge2,
1003
867
  Icon: Icon3,
868
+ IconButton: IconButton4,
1004
869
  TaskBlock,
1005
- Button: Button3,
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 { styled: styled2 } = require("@fw/plugin-theme");
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 priorityLabel = (p) => p >= 3 ? "High" : p === 2 ? "Medium" : p === 1 ? "Low" : "None";
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 $color-border-default",
1038
- display: "flex",
1039
- flexDirection: "column",
1040
- gap: "8px",
899
+ borderBottom: "1px solid var(--color-border-default)",
1041
900
  flexShrink: 0
1042
- });
1043
- var HeaderTopRow = styled2.div({
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: "$color-text-mid",
905
+ color: "var(--color-text-mid)",
1070
906
  padding: "2px 4px",
1071
- borderRadius: "4px",
1072
- "&:hover": { backgroundColor: "$color-surface-elevated" }
1073
- });
1074
- var NotesBlock = styled2.div({
1075
- whiteSpace: "pre-wrap",
1076
- fontSize: "13px",
1077
- color: "$color-text-mid",
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
- "&:hover": { backgroundColor: "$color-surface-elevated" }
1089
- });
1090
- var SubtaskTitle = styled2.div({
1091
- flex: 1,
1092
- overflow: "hidden",
1093
- textOverflow: "ellipsis",
1094
- whiteSpace: "nowrap",
1095
- minWidth: 0
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] = useState4(null);
1102
- const [subtasks, setSubtasks] = useState4([]);
1103
- const [history, setHistory] = useState4([]);
1104
- const [loading, setLoading] = useState4(true);
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 data = await callTool("fw_weaver_task_get", { id: taskId });
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 (t.isParent) {
1112
- const listData = await callTool("fw_weaver_task_list", { parentId: taskId });
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 data = await callTool("fw_weaver_history", { taskId });
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 [expandedRunId, setExpandedRunId] = useState4(null);
1164
- const [liveExpanded, setLiveExpanded] = useState4(true);
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] = useState4(null);
1174
- const [approvalLoading, setApprovalLoading] = useState4(false);
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
- Container2,
1230
- null,
1150
+ Flex6,
1151
+ {
1152
+ variant: "column-stretch-start-nowrap-0",
1153
+ style: { width: "100%", height: "100%", overflow: "hidden" }
1154
+ },
1231
1155
  React7.createElement(
1232
- Header,
1233
- null,
1156
+ Flex6,
1157
+ {
1158
+ variant: "column-stretch-start-nowrap-8",
1159
+ style: headerStyle
1160
+ },
1234
1161
  React7.createElement(
1235
- Button3,
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, padding: "24px" }
1172
+ style: { flex: 1 }
1246
1173
  },
1247
1174
  React7.createElement(
1248
- Typography6,
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
- Container2,
1258
- null,
1184
+ Flex6,
1185
+ {
1186
+ variant: "column-stretch-start-nowrap-0",
1187
+ style: { width: "100%", height: "100%", overflow: "hidden" }
1188
+ },
1259
1189
  React7.createElement(
1260
- Header,
1261
- null,
1190
+ Flex6,
1191
+ {
1192
+ variant: "column-stretch-start-nowrap-8",
1193
+ style: headerStyle
1194
+ },
1262
1195
  React7.createElement(
1263
- Button3,
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, padding: "24px" }
1206
+ style: { flex: 1 }
1274
1207
  },
1275
1208
  React7.createElement(
1276
- Typography6,
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
- Container2,
1288
- null,
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
- Header,
1292
- null,
1293
- // Back button
1294
- React7.createElement(
1295
- Button3,
1296
- { variant: "ghost", size: "sm", onClick: onBack },
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
- HeaderTopRow,
1303
- null,
1304
- React7.createElement(StatusIcon4, {
1305
- status: statusToIcon3[task.status] || "pending",
1306
- size: "md"
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(Typography6, { variant: "body-semibold" }, task.title)
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 label, assigned bots, priority, attempts
1252
+ // Meta row: status tag, assigned profile, priority, attempts
1311
1253
  React7.createElement(
1312
- HeaderMeta,
1313
- null,
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" : "default"
1317
- }, statusToLabel2[task.status]),
1318
- ...task.assignedBots.map(
1319
- (botId) => React7.createElement(Tag2, { key: `bot-${botId}`, size: "small", color: "info" }, botId)
1320
- ),
1321
- // Priority
1322
- task.priority > 0 && React7.createElement(Badge2, {
1323
- variant: task.priority >= 3 ? "warning" : "info"
1324
- }, `P${task.priority} ${priorityLabel(task.priority)}`),
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(Typography6, {
1333
- variant: "caption-regular",
1334
- color: "color-text-mid",
1335
- style: { marginTop: "4px" }
1336
- }, task.description)
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
- // ── Scrollable content ──
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-0" },
1345
- // ── Context section ──
1346
- hasContext && React7.createElement(
1347
- Section,
1348
- null,
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
- variant: "column-stretch-start-nowrap-4",
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
- FileList,
1364
- null,
1365
- ...task.context.files.map(
1366
- (file) => React7.createElement(FileItem, { key: file }, file)
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
- // Notes
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
- SectionTitle,
1384
- null,
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
- Typography6,
1387
- { variant: "caption-semibold", color: "color-text-high" },
1388
- `Subtasks (${subtasks.filter((s) => s.status === "done").length}/${subtasks.length} done)`
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
- React7.createElement(
1428
+ // Assign Profile
1429
+ availableProfiles.length > 0 && React7.createElement(
1392
1430
  Flex6,
1393
- { variant: "column-stretch-start-nowrap-0" },
1394
- ...subtasks.map(
1395
- (sub) => React7.createElement(
1396
- SubtaskRow,
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: sub.id,
1399
- onClick: () => {
1400
- onBack();
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
- React7.createElement(StatusIcon4, {
1404
- status: statusToIcon3[sub.status] || "pending",
1405
- size: "sm"
1406
- }),
1407
- React7.createElement(
1408
- SubtaskTitle,
1409
- null,
1410
- React7.createElement(Typography6, { variant: "caption-regular" }, sub.title)
1411
- ),
1412
- sub.assignedBots.length > 0 && React7.createElement(Tag2, {
1413
- size: "small",
1414
- color: "info"
1415
- }, sub.assignedBots[0]),
1416
- React7.createElement(Typography6, {
1417
- variant: "caption-regular",
1418
- color: "color-text-subtle"
1419
- }, `#${sub.attempt}`)
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
- // ── Run history section ──
1425
- (hasRuns || task.runs.length > 0) && React7.createElement(
1426
- Section,
1427
- { style: { borderBottom: "none" } },
1428
- React7.createElement(
1429
- SectionTitle,
1430
- null,
1431
- React7.createElement(
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
- { variant: "column-stretch-start-nowrap-8" },
1440
- ...runItems.map(({ run, runTimeline }) => {
1441
- const runId = run.id;
1442
- const isExpanded = expandedRunId === runId;
1443
- const isSuccess = run.outcome === "completed" || run.success === true;
1444
- return React7.createElement(TaskBlock, {
1445
- key: `run-${runId}`,
1446
- state: isSuccess ? "completed" : "failed",
1447
- instruction: extractInstruction(run),
1448
- timeline: runTimeline,
1449
- cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
1450
- plan: run.plan,
1451
- startedAt: run.startedAt,
1452
- durationMs: run.durationMs ?? run.duration,
1453
- expanded: isExpanded,
1454
- onToggleExpand: () => toggleExpand(runId)
1455
- });
1456
- }),
1457
- // Live run
1458
- isLive && React7.createElement(TaskBlock, {
1459
- key: "live-run",
1460
- state: "running",
1461
- instruction: liveInstruction ?? task.title,
1462
- timeline: liveTimeline,
1463
- phase: livePhase,
1464
- elapsed,
1465
- cost: liveCost,
1466
- plan,
1467
- error: stream.error,
1468
- approval: approvalStatus ?? void 0,
1469
- approvalLoading,
1470
- onApprove: handleApprove,
1471
- onReject: handleReject,
1472
- expanded: liveExpanded,
1473
- onToggleExpand: () => setLiveExpanded((v) => !v)
1474
- })
1475
- )
1476
- ),
1477
- // Empty state when no runs and no live
1478
- !hasRuns && task.runs.length === 0 && React7.createElement(
1479
- Section,
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-center-center-nowrap-0",
1485
- style: { padding: "16px" }
1545
+ variant: "column-stretch-start-nowrap-6"
1486
1546
  },
1487
- React7.createElement(Typography6, {
1488
- variant: "caption-regular",
1489
- color: "color-text-subtle"
1490
- }, "No runs yet for this task.")
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/swarm-dashboard.tsx
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
- ScrollArea: ScrollArea3,
1506
- EmptyState: EmptyState2,
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 = usePackWorkspace4();
2470
+ const ctx = usePackWorkspace5();
1527
2471
  const { callTool, onRefresh } = ctx;
1528
- const [selectedTaskId, setSelectedTaskId] = useState5(null);
1529
- const [swarmStatus, setSwarmStatus] = useState5(null);
1530
- const [tasks, setTasks] = useState5([]);
1531
- const [loading, setLoading] = useState5(true);
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
- useEffect3(() => {
2486
+ useEffect4(() => {
1534
2487
  mountedRef.current = true;
1535
2488
  return () => {
1536
2489
  mountedRef.current = false;
1537
2490
  };
1538
2491
  }, []);
1539
- const fetchSwarmStatus = useCallback4(async () => {
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 = useCallback4(async () => {
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 refreshAll = useCallback4(async () => {
1562
- await Promise.all([fetchSwarmStatus(), fetchTaskList()]);
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
- useEffect3(() => {
2561
+ }, [fetchSwarmStatus, fetchTaskList, fetchBots, fetchConfig, fetchProfiles, fetchOrchestratorStatus]);
2562
+ useEffect4(() => {
1566
2563
  refreshAll();
1567
2564
  }, [refreshAll]);
1568
- useEffect3(() => {
2565
+ useEffect4(() => {
1569
2566
  const interval = setInterval(fetchSwarmStatus, 3e3);
1570
2567
  return () => clearInterval(interval);
1571
2568
  }, [fetchSwarmStatus]);
1572
- useEffect3(() => {
2569
+ useEffect4(() => {
1573
2570
  const interval = setInterval(fetchTaskList, 5e3);
1574
2571
  return () => clearInterval(interval);
1575
2572
  }, [fetchTaskList]);
1576
- useEffect3(() => {
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 handleTaskClick = useCallback4((taskId) => {
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 = useCallback4(() => {
2604
+ const handleBack = useCallback5(() => {
1583
2605
  setSelectedTaskId(null);
1584
2606
  refreshAll();
1585
2607
  }, [refreshAll]);
1586
- const handleTaskCreated = useCallback4(() => {
2608
+ const handleTaskCreated = useCallback5(() => {
1587
2609
  fetchTaskList();
1588
2610
  }, [fetchTaskList]);
1589
2611
  if (selectedTaskId) {
1590
- return React8.createElement(task_detail_view_default, {
2612
+ return React11.createElement(task_detail_view_default, {
1591
2613
  taskId: selectedTaskId,
1592
2614
  onBack: handleBack
1593
2615
  });
1594
2616
  }
1595
- const bots = swarmStatus?.bots ?? {};
1596
- const botEntries = Object.values(bots);
1597
- const hasBots = botEntries.length > 0;
1598
- const hasBudget = !!swarmStatus?.budget;
1599
- const hasContent = hasBots || tasks.length > 0 || swarmStatus !== null;
1600
- return React8.createElement(
1601
- Flex7,
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
- React8.createElement(swarm_controls_default, {
2631
+ React11.createElement(swarm_controls_default, {
1608
2632
  swarmStatus,
1609
2633
  onRefresh: refreshAll
1610
2634
  }),
1611
2635
  // ── BudgetBar (below controls) ──────────────────────────────
1612
- hasBudget && React8.createElement(
1613
- Flex7,
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
- React8.createElement(budget_bar_default, {
2642
+ React11.createElement(budget_bar_default, {
1623
2643
  label: "Tokens",
1624
- used: swarmStatus.budget.tokensUsed,
1625
- limit: swarmStatus.budget.tokenLimit,
2644
+ used: sessionBudget.usedTokens,
2645
+ limit: sessionBudget.limitTokens,
1626
2646
  unit: "tokens"
1627
2647
  }),
1628
- React8.createElement(budget_bar_default, {
2648
+ React11.createElement(budget_bar_default, {
1629
2649
  label: "Cost",
1630
- used: swarmStatus.budget.costUsed,
1631
- limit: swarmStatus.budget.costLimit,
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
- hasBots && React8.createElement(
1637
- Flex7,
1638
- {
1639
- variant: "row-start-start-nowrap-8",
1640
- style: {
1641
- padding: "8px 16px",
1642
- overflowX: "auto",
1643
- overflowY: "hidden",
1644
- flexShrink: 0,
1645
- borderBottom: "1px solid var(--color-border-default)"
1646
- }
1647
- },
1648
- ...botEntries.map(
1649
- (bot) => React8.createElement(bot_slot_card_default, {
1650
- key: bot.botId,
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
- // Section header
1664
- React8.createElement(
1665
- Flex7,
2675
+ // Tasks tab
2676
+ activeTab === "tasks" && React11.createElement(
2677
+ Flex10,
1666
2678
  {
1667
- variant: "row-center-space-between-nowrap-8",
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
- React8.createElement(Typography7, {
1674
- variant: "caption-bold",
1675
- color: "color-text-medium"
1676
- }, `Task Pool (${tasks.length})`)
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
- // Task pool list (scrollable)
1679
- !hasContent && !loading && React8.createElement(EmptyState2, {
1680
- icon: "smartToy",
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
- React8.createElement(task_pool_list_default, {
1691
- tasks,
1692
- onTaskClick: handleTaskClick
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
  }