@synergenius/flow-weaver-pack-weaver 0.9.59 → 0.9.77

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 (217) 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 +351 -335
  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/assistant-tools.d.ts.map +1 -1
  14. package/dist/bot/assistant-tools.js +49 -33
  15. package/dist/bot/assistant-tools.js.map +1 -1
  16. package/dist/bot/async-mutex.d.ts +13 -0
  17. package/dist/bot/async-mutex.d.ts.map +1 -0
  18. package/dist/bot/async-mutex.js +37 -0
  19. package/dist/bot/async-mutex.js.map +1 -0
  20. package/dist/bot/bot-manager.d.ts +2 -2
  21. package/dist/bot/bot-manager.d.ts.map +1 -1
  22. package/dist/bot/bot-manager.js +3 -3
  23. package/dist/bot/bot-manager.js.map +1 -1
  24. package/dist/bot/bot-registry.js +2 -2
  25. package/dist/bot/bot-registry.js.map +1 -1
  26. package/dist/bot/conversation-store.d.ts +1 -0
  27. package/dist/bot/conversation-store.d.ts.map +1 -1
  28. package/dist/bot/conversation-store.js.map +1 -1
  29. package/dist/bot/dashboard.d.ts.map +1 -1
  30. package/dist/bot/dashboard.js +17 -8
  31. package/dist/bot/dashboard.js.map +1 -1
  32. package/dist/bot/improve-loop.js.map +1 -1
  33. package/dist/bot/index.d.ts +2 -4
  34. package/dist/bot/index.d.ts.map +1 -1
  35. package/dist/bot/index.js +1 -2
  36. package/dist/bot/index.js.map +1 -1
  37. package/dist/bot/instance-manager.d.ts +31 -0
  38. package/dist/bot/instance-manager.d.ts.map +1 -0
  39. package/dist/bot/instance-manager.js +115 -0
  40. package/dist/bot/instance-manager.js.map +1 -0
  41. package/dist/bot/orchestrator.d.ts +36 -0
  42. package/dist/bot/orchestrator.d.ts.map +1 -0
  43. package/dist/bot/orchestrator.js +176 -0
  44. package/dist/bot/orchestrator.js.map +1 -0
  45. package/dist/bot/profile-store.d.ts +36 -0
  46. package/dist/bot/profile-store.d.ts.map +1 -0
  47. package/dist/bot/profile-store.js +208 -0
  48. package/dist/bot/profile-store.js.map +1 -0
  49. package/dist/bot/profile-types.d.ts +126 -0
  50. package/dist/bot/profile-types.d.ts.map +1 -0
  51. package/dist/bot/profile-types.js +7 -0
  52. package/dist/bot/profile-types.js.map +1 -0
  53. package/dist/bot/run-store.d.ts.map +1 -1
  54. package/dist/bot/run-store.js +8 -0
  55. package/dist/bot/run-store.js.map +1 -1
  56. package/dist/bot/runner.d.ts +4 -0
  57. package/dist/bot/runner.d.ts.map +1 -1
  58. package/dist/bot/runner.js +5 -1
  59. package/dist/bot/runner.js.map +1 -1
  60. package/dist/bot/swarm-controller.d.ts +109 -0
  61. package/dist/bot/swarm-controller.d.ts.map +1 -0
  62. package/dist/bot/swarm-controller.js +640 -0
  63. package/dist/bot/swarm-controller.js.map +1 -0
  64. package/dist/bot/swarm-event-log.d.ts +28 -0
  65. package/dist/bot/swarm-event-log.d.ts.map +1 -0
  66. package/dist/bot/swarm-event-log.js +54 -0
  67. package/dist/bot/swarm-event-log.js.map +1 -0
  68. package/dist/bot/task-prompt-builder.d.ts +22 -0
  69. package/dist/bot/task-prompt-builder.d.ts.map +1 -0
  70. package/dist/bot/task-prompt-builder.js +240 -0
  71. package/dist/bot/task-prompt-builder.js.map +1 -0
  72. package/dist/bot/task-store.d.ts +21 -0
  73. package/dist/bot/task-store.d.ts.map +1 -0
  74. package/dist/bot/task-store.js +364 -0
  75. package/dist/bot/task-store.js.map +1 -0
  76. package/dist/bot/task-types.d.ts +79 -0
  77. package/dist/bot/task-types.d.ts.map +1 -0
  78. package/dist/bot/task-types.js +6 -0
  79. package/dist/bot/task-types.js.map +1 -0
  80. package/dist/bot/types.d.ts +8 -0
  81. package/dist/bot/types.d.ts.map +1 -1
  82. package/dist/cli-handlers.d.ts.map +1 -1
  83. package/dist/cli-handlers.js +79 -54
  84. package/dist/cli-handlers.js.map +1 -1
  85. package/dist/cli.d.ts +3 -0
  86. package/dist/cli.d.ts.map +1 -0
  87. package/dist/cli.js +749 -0
  88. package/dist/cli.js.map +1 -0
  89. package/dist/docs/docs/weaver-bot-usage.md +35 -18
  90. package/dist/docs/docs/weaver-config.md +20 -0
  91. package/dist/docs/docs/weaver-task-queue.md +31 -19
  92. package/dist/docs/weaver-config.md +15 -9
  93. package/dist/index.d.ts +2 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -1
  96. package/dist/index.js.map +1 -1
  97. package/dist/mcp-tools.d.ts +17 -0
  98. package/dist/mcp-tools.d.ts.map +1 -1
  99. package/dist/mcp-tools.js +98 -279
  100. package/dist/mcp-tools.js.map +1 -1
  101. package/dist/node-types/bot-report.d.ts.map +1 -1
  102. package/dist/node-types/bot-report.js +6 -24
  103. package/dist/node-types/bot-report.js.map +1 -1
  104. package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
  105. package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
  106. package/dist/node-types/orchestrator-dispatch.js +63 -0
  107. package/dist/node-types/orchestrator-dispatch.js.map +1 -0
  108. package/dist/node-types/orchestrator-load-state.d.ts +16 -0
  109. package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
  110. package/dist/node-types/orchestrator-load-state.js +60 -0
  111. package/dist/node-types/orchestrator-load-state.js.map +1 -0
  112. package/dist/node-types/orchestrator-route.d.ts +16 -0
  113. package/dist/node-types/orchestrator-route.d.ts.map +1 -0
  114. package/dist/node-types/orchestrator-route.js +28 -0
  115. package/dist/node-types/orchestrator-route.js.map +1 -0
  116. package/dist/node-types/receive-task.d.ts +2 -3
  117. package/dist/node-types/receive-task.d.ts.map +1 -1
  118. package/dist/node-types/receive-task.js +3 -48
  119. package/dist/node-types/receive-task.js.map +1 -1
  120. package/dist/templates/weaver-template.d.ts +11 -0
  121. package/dist/templates/weaver-template.d.ts.map +1 -0
  122. package/dist/templates/weaver-template.js +53 -0
  123. package/dist/templates/weaver-template.js.map +1 -0
  124. package/dist/ui/bot-activity.js +2 -2
  125. package/dist/ui/bot-constants.d.ts +14 -0
  126. package/dist/ui/bot-constants.d.ts.map +1 -0
  127. package/dist/ui/bot-constants.js +189 -0
  128. package/dist/ui/bot-constants.js.map +1 -0
  129. package/dist/ui/bot-panel.js +207 -245
  130. package/dist/ui/bot-slot-card.js +141 -0
  131. package/dist/ui/budget-bar.js +59 -0
  132. package/dist/ui/chat-task-result.js +178 -0
  133. package/dist/ui/decision-log.js +136 -0
  134. package/dist/ui/profile-card.js +158 -0
  135. package/dist/ui/profile-editor.js +597 -0
  136. package/dist/ui/swarm-controls.js +245 -0
  137. package/dist/ui/swarm-dashboard.js +3012 -0
  138. package/dist/ui/task-create-form.js +98 -0
  139. package/dist/ui/task-detail-view.js +1044 -0
  140. package/dist/ui/task-pool-list.js +156 -0
  141. package/dist/workflows/orchestrator.d.ts +21 -0
  142. package/dist/workflows/orchestrator.d.ts.map +1 -0
  143. package/dist/workflows/orchestrator.js +281 -0
  144. package/dist/workflows/orchestrator.js.map +1 -0
  145. package/dist/workflows/weaver-bot-session.d.ts +65 -0
  146. package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
  147. package/dist/workflows/weaver-bot-session.js +68 -0
  148. package/dist/workflows/weaver-bot-session.js.map +1 -0
  149. package/dist/workflows/weaver.d.ts +24 -0
  150. package/dist/workflows/weaver.d.ts.map +1 -0
  151. package/dist/workflows/weaver.js +28 -0
  152. package/dist/workflows/weaver.js.map +1 -0
  153. package/flowweaver.manifest.json +547 -133
  154. package/package.json +1 -1
  155. package/src/ai-chat-provider.ts +378 -371
  156. package/src/bot/ai-router.ts +132 -0
  157. package/src/bot/assistant-tools.ts +47 -29
  158. package/src/bot/async-mutex.ts +37 -0
  159. package/src/bot/bot-manager.ts +3 -3
  160. package/src/bot/bot-registry.ts +2 -2
  161. package/src/bot/conversation-store.ts +2 -1
  162. package/src/bot/dashboard.ts +17 -8
  163. package/src/bot/improve-loop.ts +6 -6
  164. package/src/bot/index.ts +2 -4
  165. package/src/bot/instance-manager.ts +128 -0
  166. package/src/bot/orchestrator.ts +244 -0
  167. package/src/bot/profile-store.ts +225 -0
  168. package/src/bot/profile-types.ts +141 -0
  169. package/src/bot/run-store.ts +8 -0
  170. package/src/bot/runner.ts +9 -1
  171. package/src/bot/swarm-controller.ts +780 -0
  172. package/src/bot/swarm-event-log.ts +57 -0
  173. package/src/bot/task-prompt-builder.ts +309 -0
  174. package/src/bot/task-store.ts +407 -0
  175. package/src/bot/task-types.ts +100 -0
  176. package/src/bot/types.ts +8 -0
  177. package/src/cli-handlers.ts +78 -53
  178. package/src/docs/weaver-bot-usage.md +35 -18
  179. package/src/docs/weaver-config.md +20 -0
  180. package/src/docs/weaver-task-queue.md +31 -19
  181. package/src/index.ts +5 -4
  182. package/src/mcp-tools.ts +129 -372
  183. package/src/node-types/bot-report.ts +6 -24
  184. package/src/node-types/orchestrator-dispatch.ts +71 -0
  185. package/src/node-types/orchestrator-load-state.ts +66 -0
  186. package/src/node-types/orchestrator-route.ts +33 -0
  187. package/src/node-types/receive-task.ts +3 -57
  188. package/src/ui/bot-activity.tsx +2 -2
  189. package/src/ui/bot-constants.ts +192 -0
  190. package/src/ui/bot-panel.tsx +213 -247
  191. package/src/ui/bot-slot-card.tsx +139 -0
  192. package/src/ui/budget-bar.tsx +30 -0
  193. package/src/ui/chat-task-result.tsx +236 -0
  194. package/src/ui/decision-log.tsx +148 -0
  195. package/src/ui/profile-card.tsx +157 -0
  196. package/src/ui/profile-editor.tsx +384 -0
  197. package/src/ui/swarm-controls.tsx +260 -0
  198. package/src/ui/swarm-dashboard.tsx +647 -0
  199. package/src/ui/task-create-form.tsx +87 -0
  200. package/src/ui/task-detail-view.tsx +841 -0
  201. package/src/ui/task-pool-list.tsx +187 -0
  202. package/src/workflows/orchestrator.ts +302 -0
  203. package/dist/docs/weaver-bot-usage.md +0 -34
  204. package/dist/docs/weaver-genesis.md +0 -32
  205. package/dist/docs/weaver-task-queue.md +0 -34
  206. package/dist/ui/bot-workspace.js +0 -1015
  207. package/dist/ui/chat-bot-result.js +0 -71
  208. package/dist/ui/queue-input.js +0 -82
  209. package/dist/ui/session-bar.js +0 -174
  210. package/src/bot/error-guide.ts +0 -4
  211. package/src/bot/retry-utils.ts +0 -4
  212. package/src/bot/session-state.ts +0 -116
  213. package/src/bot/task-queue.ts +0 -262
  214. package/src/ui/bot-workspace.tsx +0 -442
  215. package/src/ui/chat-bot-result.tsx +0 -81
  216. package/src/ui/queue-input.tsx +0 -56
  217. package/src/ui/session-bar.tsx +0 -157
@@ -1,45 +1,49 @@
1
1
  /**
2
- * Weaver Bot Panel — sidebar component.
2
+ * Weaver Bot Panel — sidebar fleet overview.
3
3
  *
4
- * Replaces BotPanel.tsx + BotLibrary.tsx from the platform's cloud-bot-panel.
5
- * Runs in the pack sandbox uses CommonJS require for platform deps,
6
- * React.createElement throughout (no JSX transform in sandbox).
4
+ * Simplified panel that shows swarm status at a glance:
5
+ * - Bot list with current status (idle/executing/paused)
6
+ * - Quick stats: tasks completed, tokens used, cost
7
+ * - "Open Dashboard" button to launch the swarm-dashboard workspace
7
8
  *
8
- * Features:
9
- * - Lists registered bots via fw_weaver_list_bots
10
- * - Validation badges per bot
11
- * - Register existing workflow form
12
- * - Open workspace action per bot
13
- * - Unregister action per bot
9
+ * Polls fw_weaver_swarm_status every 5s for live updates.
10
+ *
11
+ * Pattern: CommonJS require, React.createElement, module.exports, usePackWorkspace.
14
12
  */
15
13
  const React = require('react');
16
14
  const { useState, useEffect, useCallback, useRef } = React;
17
15
  const {
18
- Flex, Typography, Button, IconButton, Icon, Input, EmptyState,
19
- ScrollArea, StatusIcon, toast, usePackWorkspace,
16
+ Flex, Typography, Button, IconButton, Icon, EmptyState,
17
+ ScrollArea, StatusIcon, usePackWorkspace,
20
18
  } = require('@fw/plugin-ui-kit');
21
19
 
22
20
  // ---------------------------------------------------------------------------
23
21
  // Types
24
22
  // ---------------------------------------------------------------------------
25
23
 
26
- interface Bot {
27
- id: string;
28
- name: string;
29
- description: string;
30
- icon?: string;
31
- color?: string;
32
- filePath: string;
33
- workflowExport: string;
34
- paramName: string;
35
- packId?: string;
36
- ejected?: boolean;
37
- validation?: {
38
- state: 'valid' | 'invalid' | 'checking' | 'unknown';
39
- fileExists?: boolean;
40
- exportValid?: boolean;
41
- errorMessage?: string;
42
- };
24
+ interface InstanceInfo {
25
+ instanceId: string;
26
+ profileId: string;
27
+ index: number;
28
+ status: 'idle' | 'executing' | 'paused' | 'stopped';
29
+ currentTaskId?: string;
30
+ currentRunId?: string;
31
+ startedAt?: string;
32
+ tokensUsed: number;
33
+ cost: number;
34
+ tasksCompleted: number;
35
+ tasksFailed: number;
36
+ }
37
+
38
+ interface SwarmStatus {
39
+ status: 'idle' | 'running' | 'paused' | 'stopping';
40
+ instances: Record<string, InstanceInfo>;
41
+ maxConcurrent: number;
42
+ tasksCompleted: number;
43
+ tasksFailed: number;
44
+ totalTokensUsed: number;
45
+ totalCost: number;
46
+ startedAt?: string;
43
47
  }
44
48
 
45
49
  // ---------------------------------------------------------------------------
@@ -53,171 +57,117 @@ function parseToolResult(raw: unknown): unknown {
53
57
  return raw;
54
58
  }
55
59
 
56
- function validationIcon(state: string | undefined): { icon: string; color: string } {
57
- switch (state) {
58
- case 'valid': return { icon: 'checkCircle', color: 'var(--color-success)' };
59
- case 'invalid': return { icon: 'error', color: 'var(--color-danger)' };
60
- case 'checking': return { icon: 'sync', color: 'var(--color-warning)' };
61
- default: return { icon: 'helpOutline', color: 'var(--color-text-subtle)' };
60
+ function statusToIconStatus(status: string): 'pending' | 'running' | 'completed' | 'failed' {
61
+ switch (status) {
62
+ case 'executing': case 'running': return 'running';
63
+ case 'paused': return 'pending';
64
+ case 'stopped': case 'stopping': return 'failed';
65
+ default: return 'completed';
66
+ }
67
+ }
68
+
69
+ function statusLabel(status: string): string {
70
+ switch (status) {
71
+ case 'executing': return 'Executing';
72
+ case 'running': return 'Running';
73
+ case 'paused': return 'Paused';
74
+ case 'stopped': return 'Stopped';
75
+ case 'stopping': return 'Stopping';
76
+ default: return 'Idle';
62
77
  }
63
78
  }
64
79
 
80
+ function formatTokens(n: number): string {
81
+ if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
82
+ if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
83
+ return String(n);
84
+ }
85
+
86
+ function formatCost(n: number): string {
87
+ return `$${n.toFixed(2)}`;
88
+ }
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // Constants
92
+ // ---------------------------------------------------------------------------
93
+
94
+ const POLL_INTERVAL_MS = 5000;
95
+
65
96
  // ---------------------------------------------------------------------------
66
97
  // Component
67
98
  // ---------------------------------------------------------------------------
68
99
 
69
100
  function BotPanel() {
70
101
  const ctx = usePackWorkspace();
71
- const { callTool, dispatchEvent } = ctx;
102
+ const { callTool } = ctx;
72
103
  const packId = ctx.packId;
73
104
 
74
- // Bot list state
75
- const [bots, setBots] = useState<Bot[]>([]);
105
+ const [swarm, setSwarm] = useState<SwarmStatus | null>(null);
76
106
  const [loading, setLoading] = useState(true);
77
107
  const [error, setError] = useState<string | null>(null);
78
108
 
79
- // Register form state
80
- const [showRegForm, setShowRegForm] = useState(false);
81
- const [regName, setRegName] = useState('');
82
- const [regFilePath, setRegFilePath] = useState('');
83
- const [regExport, setRegExport] = useState('');
84
- const [registering, setRegistering] = useState(false);
85
-
86
- // Unregister confirmation
87
- const [confirmUnregId, setConfirmUnregId] = useState<string | null>(null);
88
- const [unregistering, setUnregistering] = useState(false);
109
+ const mountedRef = useRef(true);
110
+ useEffect(() => {
111
+ mountedRef.current = true;
112
+ return () => { mountedRef.current = false; };
113
+ }, []);
89
114
 
90
- // ── Load bots ──────────────────────────────────────────────────
91
- const loadBots = useCallback(async () => {
115
+ // ── Fetch swarm status ──────────────────────────────────────────
116
+ const fetchStatus = useCallback(async () => {
92
117
  try {
93
118
  setError(null);
94
- const raw = await callTool('fw_weaver_list_bots');
95
- const parsed = parseToolResult(raw);
96
- if (Array.isArray(parsed)) {
97
- setBots(parsed as Bot[]);
98
- } else {
99
- setBots([]);
100
- }
119
+ const raw = await callTool('fw_weaver_swarm_status', {});
120
+ if (!mountedRef.current) return;
121
+ const parsed = parseToolResult(raw) as SwarmStatus | null;
122
+ if (parsed) setSwarm(parsed);
101
123
  } catch (err: unknown) {
102
- const msg = err instanceof Error ? err.message : 'Failed to load bots';
124
+ if (!mountedRef.current) return;
125
+ const msg = err instanceof Error ? err.message : 'Failed to load swarm status';
103
126
  setError(msg);
104
127
  } finally {
105
- setLoading(false);
128
+ if (mountedRef.current) setLoading(false);
106
129
  }
107
130
  }, [callTool]);
108
131
 
109
- // Load on mount
110
- const mountedRef = useRef(false);
132
+ // Fetch on mount + poll every 5s
111
133
  useEffect(() => {
112
- if (!mountedRef.current) {
113
- mountedRef.current = true;
114
- loadBots();
115
- }
116
- }, [loadBots]);
134
+ fetchStatus();
135
+ const timer = setInterval(fetchStatus, POLL_INTERVAL_MS);
136
+ return () => clearInterval(timer);
137
+ }, [fetchStatus]);
117
138
 
118
- // ── Register bot ───────────────────────────────────────────────
119
- const handleRegister = useCallback(async () => {
120
- if (!regName.trim() || !regFilePath.trim() || !regExport.trim()) return;
121
- setRegistering(true);
122
- try {
123
- await callTool('fw_weaver_register_bot', {
124
- name: regName.trim(),
125
- filePath: regFilePath.trim(),
126
- workflowExport: regExport.trim(),
127
- paramName: 'taskJson',
128
- });
129
- toast('Bot registered', { type: 'success' });
130
- setRegName('');
131
- setRegFilePath('');
132
- setRegExport('');
133
- setShowRegForm(false);
134
- await loadBots();
135
- } catch (err: unknown) {
136
- toast(err instanceof Error ? err.message : 'Registration failed', { type: 'error' });
137
- } finally {
138
- setRegistering(false);
139
- }
140
- }, [regName, regFilePath, regExport, callTool, loadBots]);
141
-
142
- // ── Unregister bot ─────────────────────────────────────────────
143
- const handleUnregister = useCallback(async (id: string) => {
144
- setUnregistering(true);
145
- try {
146
- await callTool('fw_weaver_unregister_bot', { id });
147
- toast('Bot unregistered', { type: 'warning' });
148
- setConfirmUnregId(null);
149
- await loadBots();
150
- } catch (err: unknown) {
151
- toast(err instanceof Error ? err.message : 'Unregister failed', { type: 'error' });
152
- } finally {
153
- setUnregistering(false);
154
- }
155
- }, [callTool, loadBots]);
156
-
157
- // ── Open workspace ─────────────────────────────────────────────
158
- const handleOpenWorkspace = useCallback((botId: string) => {
159
- dispatchEvent('fw:open-bot-workspace', { botId, packId, live: false });
160
- }, [dispatchEvent, packId]);
161
-
162
- // ── Render ─────────────────────────────────────────────────────
139
+ // ── Open dashboard ──────────────────────────────────────────────
140
+ const handleOpenDashboard = useCallback(() => {
141
+ ctx.openWindow({
142
+ type: 'custom',
143
+ title: 'Swarm Dashboard',
144
+ icon: 'dashboard',
145
+ contentType: 'bot-workspace',
146
+ displayState: 'docked',
147
+ dockZone: 'center',
148
+ definitionId: 'bot-workspace',
149
+ size: { width: 1000, height: 700 },
150
+ singleton: true,
151
+ data: { packId },
152
+ } as Record<string, unknown>);
153
+ }, [ctx, packId]);
163
154
 
164
- const hasBots = bots.length > 0;
155
+ // ── Render ──────────────────────────────────────────────────────
165
156
 
166
- // Header row with title + actions
157
+ // Header
167
158
  const header = React.createElement(Flex, {
168
- variant: 'row-center-between-nowrap-8',
159
+ variant: 'row-center-space-between-nowrap-8',
169
160
  style: { padding: '8px 12px', borderBottom: '1px solid var(--color-border-default)', flexShrink: 0 },
170
161
  },
171
162
  React.createElement(Flex, { variant: 'row-center-start-nowrap-6' },
172
163
  React.createElement(Icon, { name: 'smartToy', size: 16, color: 'color-text-medium' }),
173
- React.createElement(Typography, { variant: 'caption-thick', color: 'color-text-high' }, 'Bots'),
164
+ React.createElement(Typography, { variant: 'caption-thick', color: 'color-text-high' }, 'Swarm'),
174
165
  ),
175
- React.createElement(Flex, { variant: 'row-center-start-nowrap-4' },
176
- React.createElement(IconButton, {
177
- icon: 'refresh', size: 'xs', variant: 'clear',
178
- onClick: loadBots, title: 'Refresh',
179
- }),
180
- React.createElement(IconButton, {
181
- icon: 'add', size: 'xs', variant: 'clear',
182
- onClick: () => setShowRegForm((v: boolean) => !v), title: 'Register bot',
183
- }),
184
- ),
185
- );
186
-
187
- // Registration form
188
- const regForm = showRegForm ? React.createElement(Flex, {
189
- variant: 'column-start-start-nowrap-8',
190
- style: {
191
- padding: '10px 12px',
192
- borderBottom: '1px solid var(--color-border-default)',
193
- backgroundColor: 'var(--color-surface-low)',
194
- },
195
- },
196
- React.createElement(Typography, { variant: 'smallCaption-thick', color: 'color-text-medium' }, 'Register Existing Workflow'),
197
- React.createElement(Input, {
198
- type: 'text', size: 'small', placeholder: 'Bot name',
199
- value: regName, onChange: setRegName,
200
- }),
201
- React.createElement(Input, {
202
- type: 'text', size: 'small', placeholder: 'File path (e.g. my-bot.ts)',
203
- value: regFilePath, onChange: setRegFilePath,
204
- }),
205
- React.createElement(Input, {
206
- type: 'text', size: 'small', placeholder: 'Export name (e.g. myBot)',
207
- value: regExport, onChange: setRegExport,
166
+ React.createElement(IconButton, {
167
+ icon: 'reset', size: 'xs', variant: 'clear',
168
+ onClick: fetchStatus, title: 'Refresh',
208
169
  }),
209
- React.createElement(Flex, { variant: 'row-center-start-nowrap-6' },
210
- React.createElement(Button, {
211
- size: 'xs', variant: 'fill', color: 'primary',
212
- onClick: handleRegister,
213
- disabled: registering || !regName.trim() || !regFilePath.trim() || !regExport.trim(),
214
- }, registering ? 'Registering...' : 'Register'),
215
- React.createElement(Button, {
216
- size: 'xs', variant: 'clear', color: 'secondary',
217
- onClick: () => { setShowRegForm(false); setRegName(''); setRegFilePath(''); setRegExport(''); },
218
- }, 'Cancel'),
219
- ),
220
- ) : null;
170
+ );
221
171
 
222
172
  // Loading state
223
173
  if (loading) {
@@ -228,9 +178,9 @@ function BotPanel() {
228
178
  header,
229
179
  React.createElement(Flex, {
230
180
  variant: 'column-center-center-nowrap-8',
231
- style: { flex: 1, padding: '24px' },
181
+ style: { flex: 1 },
232
182
  },
233
- React.createElement(Typography, { variant: 'caption-regular', color: 'color-text-subtle' }, 'Loading bots...'),
183
+ React.createElement(Typography, { variant: 'caption-regular', color: 'color-text-subtle' }, 'Loading swarm status...'),
234
184
  ),
235
185
  );
236
186
  }
@@ -244,57 +194,91 @@ function BotPanel() {
244
194
  header,
245
195
  React.createElement(Flex, {
246
196
  variant: 'column-center-center-nowrap-8',
247
- style: { flex: 1, padding: '24px' },
197
+ style: { flex: 1 },
248
198
  },
249
- React.createElement(Typography, { variant: 'caption-regular', color: 'color-danger' }, error),
250
- React.createElement(Button, { size: 'xs', variant: 'outlined', onClick: loadBots }, 'Retry'),
199
+ React.createElement(Typography, { variant: 'caption-regular', color: 'color-status-negative' }, error),
200
+ React.createElement(Button, { size: 'xs', variant: 'outlined', onClick: fetchStatus }, 'Retry'),
251
201
  ),
252
202
  );
253
203
  }
254
204
 
255
- // Bot cards
256
- const botCards = bots.map((bot: Bot) => {
257
- const vState = bot.validation?.state;
258
- const vInfo = validationIcon(vState);
259
- const isConfirming = confirmUnregId === bot.id;
205
+ // Swarm status indicator
206
+ const swarmStatus = swarm?.status ?? 'idle';
260
207
 
261
- return React.createElement(Flex, {
262
- key: bot.id,
208
+ const statusRow = React.createElement(Flex, {
209
+ variant: 'row-center-space-between-nowrap-8',
210
+ style: { padding: '8px 12px', borderBottom: '1px solid var(--color-border-default)' },
211
+ },
212
+ React.createElement(Flex, { variant: 'row-center-start-nowrap-6' },
213
+ React.createElement(StatusIcon, {
214
+ status: statusToIconStatus(swarmStatus),
215
+ size: 'sm',
216
+ }),
217
+ React.createElement(Typography, { variant: 'caption-thick', color: 'color-text-high' },
218
+ statusLabel(swarmStatus),
219
+ ),
220
+ ),
221
+ React.createElement(Button, {
222
+ size: 'xs', variant: 'outlined', color: 'primary',
223
+ onClick: handleOpenDashboard,
224
+ }, 'Open Dashboard'),
225
+ );
226
+
227
+ // Quick stats
228
+ const statsRow = React.createElement(Flex, {
229
+ variant: 'row-center-space-between-nowrap-8',
230
+ style: { padding: '8px 12px', borderBottom: '1px solid var(--color-border-default)', backgroundColor: 'var(--color-surface-low)' },
231
+ },
232
+ React.createElement(Flex, { variant: 'column-center-center-nowrap-1' },
233
+ React.createElement(Typography, { variant: 'smallCaption-thick', color: 'color-text-high' },
234
+ String(swarm?.tasksCompleted ?? 0),
235
+ ),
236
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' }, 'Done'),
237
+ ),
238
+ React.createElement(Flex, { variant: 'column-center-center-nowrap-1' },
239
+ React.createElement(Typography, { variant: 'smallCaption-thick', color: 'color-text-high' },
240
+ String(swarm?.tasksFailed ?? 0),
241
+ ),
242
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' }, 'Failed'),
243
+ ),
244
+ React.createElement(Flex, { variant: 'column-center-center-nowrap-1' },
245
+ React.createElement(Typography, { variant: 'smallCaption-thick', color: 'color-text-high' },
246
+ formatTokens(swarm?.totalTokensUsed ?? 0),
247
+ ),
248
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' }, 'Tokens'),
249
+ ),
250
+ React.createElement(Flex, { variant: 'column-center-center-nowrap-1' },
251
+ React.createElement(Typography, { variant: 'smallCaption-thick', color: 'color-text-high' },
252
+ formatCost(swarm?.totalCost ?? 0),
253
+ ),
254
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' }, 'Cost'),
255
+ ),
256
+ );
257
+
258
+ // Bot list
259
+ const instanceEntries = Object.values(swarm?.instances ?? {}) as InstanceInfo[];
260
+ const hasBots = instanceEntries.length > 0;
261
+
262
+ const botCards = instanceEntries.map((inst: InstanceInfo) =>
263
+ React.createElement(Flex, {
264
+ key: inst.instanceId,
263
265
  variant: 'row-center-start-nowrap-8',
264
- style: {
265
- padding: '7px 8px',
266
- borderRadius: 'var(--border-radius-secondary)',
267
- border: '1px solid var(--color-border-default)',
268
- cursor: 'pointer',
269
- transition: 'background-color 0.12s',
270
- },
271
- onClick: () => handleOpenWorkspace(bot.id),
272
- onMouseEnter: (e: React.MouseEvent) => {
273
- (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--color-surface-raised)';
274
- },
275
- onMouseLeave: (e: React.MouseEvent) => {
276
- (e.currentTarget as HTMLElement).style.backgroundColor = '';
277
- },
266
+ style: { padding: '8px', borderRadius: 'var(--border-radius-regular)', border: '1px solid var(--color-border-default)' },
278
267
  },
279
- // Icon
280
- React.createElement('div', {
268
+ // Bot icon
269
+ React.createElement(Flex, {
270
+ variant: 'row-center-center-nowrap-0',
281
271
  style: {
282
- width: '26px', height: '26px',
272
+ width: 26, height: 26,
283
273
  borderRadius: 'var(--border-radius-compact)',
284
- display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
285
- background: bot.color
286
- ? `color-mix(in srgb, ${bot.color} 14%, transparent)`
287
- : 'var(--color-surface-low)',
274
+ flexShrink: 0,
275
+ background: 'var(--color-surface-low)',
288
276
  },
289
277
  },
290
- React.createElement(Icon, {
291
- name: bot.icon || 'smartToy', size: 14,
292
- color: bot.color ? undefined : 'color-text-medium',
293
- style: bot.color ? { color: bot.color } : undefined,
294
- }),
278
+ React.createElement(Icon, { name: 'smartToy', size: 14, color: 'color-text-medium' }),
295
279
  ),
296
280
 
297
- // Name + description
281
+ // Name + status + task
298
282
  React.createElement(Flex, {
299
283
  variant: 'column-start-start-nowrap-1',
300
284
  style: { flex: 1, minWidth: 0 },
@@ -302,70 +286,51 @@ function BotPanel() {
302
286
  React.createElement(Flex, { variant: 'row-center-start-nowrap-4' },
303
287
  React.createElement(Typography, {
304
288
  variant: 'caption-thick', color: 'color-text-high',
305
- style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
306
- }, bot.name),
307
- // Validation badge
308
- React.createElement(Icon, {
309
- name: vInfo.icon, size: 12,
310
- style: { color: vInfo.color, flexShrink: 0 },
289
+ }, `${inst.profileId} #${inst.index}`),
290
+ React.createElement(StatusIcon, {
291
+ status: statusToIconStatus(inst.status),
292
+ size: 'sm',
311
293
  }),
294
+ React.createElement(Typography, {
295
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
296
+ }, statusLabel(inst.status)),
312
297
  ),
313
- bot.description ? React.createElement(Typography, {
298
+ inst.currentTaskId ? React.createElement(Typography, {
314
299
  variant: 'smallCaption-regular', color: 'color-text-medium',
315
- style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
316
- }, bot.description) : null,
300
+ truncate: true,
301
+ }, `Task: ${inst.currentTaskId}`) : null,
317
302
  ),
318
303
 
319
- // Actions
320
- isConfirming
321
- ? React.createElement(Flex, {
322
- variant: 'row-center-start-nowrap-4',
323
- onClick: (e: React.MouseEvent) => e.stopPropagation(),
324
- },
325
- React.createElement(Button, {
326
- size: 'xs', variant: 'fill', color: 'danger',
327
- onClick: () => handleUnregister(bot.id),
328
- disabled: unregistering,
329
- }, unregistering ? '...' : 'Yes'),
330
- React.createElement(Button, {
331
- size: 'xs', variant: 'clear', color: 'secondary',
332
- onClick: () => setConfirmUnregId(null),
333
- }, 'No'),
334
- )
335
- : React.createElement(Flex, {
336
- variant: 'row-center-start-nowrap-2',
337
- onClick: (e: React.MouseEvent) => e.stopPropagation(),
338
- },
339
- React.createElement(IconButton, {
340
- icon: 'openInNew', size: 'xs', variant: 'clear',
341
- onClick: () => handleOpenWorkspace(bot.id),
342
- title: 'Open workspace',
343
- }),
344
- React.createElement(IconButton, {
345
- icon: 'close', size: 'xs', variant: 'clear',
346
- onClick: () => setConfirmUnregId(bot.id),
347
- title: 'Unregister',
348
- }),
349
- ),
350
- );
351
- });
304
+ // Per-instance stats
305
+ React.createElement(Flex, {
306
+ variant: 'column-end-end-nowrap-1',
307
+ style: { flexShrink: 0 },
308
+ },
309
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' },
310
+ formatTokens(inst.tokensUsed),
311
+ ),
312
+ React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' },
313
+ formatCost(inst.cost),
314
+ ),
315
+ ),
316
+ ),
317
+ );
352
318
 
353
- // Main content
354
319
  const content = hasBots
355
320
  ? React.createElement(ScrollArea, { style: { flex: 1 } },
356
321
  React.createElement(Flex, {
357
- variant: 'column-start-start-nowrap-4',
322
+ variant: 'column-stretch-start-nowrap-6',
358
323
  style: { padding: '8px 12px' },
359
324
  }, ...botCards),
360
325
  )
361
326
  : React.createElement(Flex, {
362
327
  variant: 'column-center-center-nowrap-0',
363
- style: { flex: 1, padding: '24px' },
328
+ style: { flex: 1 },
364
329
  },
365
330
  React.createElement(EmptyState, {
366
331
  icon: 'smartToy',
367
- message: 'No bots registered',
368
- description: 'Register an existing workflow or ask the AI assistant to create one.',
332
+ message: swarmStatus === 'idle' ? 'Swarm idle' : 'No bots active',
333
+ description: 'Open the dashboard to configure and start the swarm.',
369
334
  }),
370
335
  );
371
336
 
@@ -374,7 +339,8 @@ function BotPanel() {
374
339
  style: { width: '100%', height: '100%', overflow: 'hidden' },
375
340
  },
376
341
  header,
377
- regForm,
342
+ statusRow,
343
+ statsRow,
378
344
  content,
379
345
  );
380
346
  }