@synergenius/flow-weaver-pack-weaver 0.9.199 → 0.9.201

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 (181) hide show
  1. package/dist/ai-chat-provider.js +5 -5
  2. package/dist/ai-chat-provider.js.map +1 -1
  3. package/dist/bot/acceptance-merge.d.ts +21 -0
  4. package/dist/bot/acceptance-merge.d.ts.map +1 -0
  5. package/dist/bot/acceptance-merge.js +46 -0
  6. package/dist/bot/acceptance-merge.js.map +1 -0
  7. package/dist/bot/ai-client.d.ts +14 -2
  8. package/dist/bot/ai-client.d.ts.map +1 -1
  9. package/dist/bot/ai-client.js +71 -24
  10. package/dist/bot/ai-client.js.map +1 -1
  11. package/dist/bot/assistant-tools.js +3 -3
  12. package/dist/bot/assistant-tools.js.map +1 -1
  13. package/dist/bot/audit-logger.d.ts.map +1 -1
  14. package/dist/bot/audit-logger.js +34 -14
  15. package/dist/bot/audit-logger.js.map +1 -1
  16. package/dist/bot/audit-trail.d.ts +67 -0
  17. package/dist/bot/audit-trail.d.ts.map +1 -0
  18. package/dist/bot/audit-trail.js +153 -0
  19. package/dist/bot/audit-trail.js.map +1 -0
  20. package/dist/bot/behavior-defaults.d.ts +1 -1
  21. package/dist/bot/behavior-defaults.d.ts.map +1 -1
  22. package/dist/bot/behavior-defaults.js +7 -3
  23. package/dist/bot/behavior-defaults.js.map +1 -1
  24. package/dist/bot/capability-registry.d.ts +9 -0
  25. package/dist/bot/capability-registry.d.ts.map +1 -1
  26. package/dist/bot/capability-registry.js +81 -27
  27. package/dist/bot/capability-registry.js.map +1 -1
  28. package/dist/bot/capability-types.d.ts +10 -0
  29. package/dist/bot/capability-types.d.ts.map +1 -1
  30. package/dist/bot/cli-provider.d.ts.map +1 -1
  31. package/dist/bot/cli-provider.js +8 -7
  32. package/dist/bot/cli-provider.js.map +1 -1
  33. package/dist/bot/preflight.d.ts +48 -0
  34. package/dist/bot/preflight.d.ts.map +1 -0
  35. package/dist/bot/preflight.js +247 -0
  36. package/dist/bot/preflight.js.map +1 -0
  37. package/dist/bot/provider-shim.d.ts +74 -0
  38. package/dist/bot/provider-shim.d.ts.map +1 -0
  39. package/dist/bot/provider-shim.js +176 -0
  40. package/dist/bot/provider-shim.js.map +1 -0
  41. package/dist/bot/runner.d.ts +2 -0
  42. package/dist/bot/runner.d.ts.map +1 -1
  43. package/dist/bot/runner.js +60 -17
  44. package/dist/bot/runner.js.map +1 -1
  45. package/dist/bot/step-executor.d.ts.map +1 -1
  46. package/dist/bot/step-executor.js +72 -115
  47. package/dist/bot/step-executor.js.map +1 -1
  48. package/dist/bot/swarm-controller.d.ts +2 -0
  49. package/dist/bot/swarm-controller.d.ts.map +1 -1
  50. package/dist/bot/swarm-controller.js +92 -20
  51. package/dist/bot/swarm-controller.js.map +1 -1
  52. package/dist/bot/task-create-handler.d.ts +37 -0
  53. package/dist/bot/task-create-handler.d.ts.map +1 -0
  54. package/dist/bot/task-create-handler.js +124 -0
  55. package/dist/bot/task-create-handler.js.map +1 -0
  56. package/dist/bot/task-store.d.ts +1 -0
  57. package/dist/bot/task-store.d.ts.map +1 -1
  58. package/dist/bot/task-store.js +67 -0
  59. package/dist/bot/task-store.js.map +1 -1
  60. package/dist/bot/types.d.ts +1 -1
  61. package/dist/bot/types.d.ts.map +1 -1
  62. package/dist/bot/weaver-tools.d.ts.map +1 -1
  63. package/dist/bot/weaver-tools.js +7 -39
  64. package/dist/bot/weaver-tools.js.map +1 -1
  65. package/dist/node-types/agent-execute.d.ts +25 -8
  66. package/dist/node-types/agent-execute.d.ts.map +1 -1
  67. package/dist/node-types/agent-execute.js +89 -23
  68. package/dist/node-types/agent-execute.js.map +1 -1
  69. package/dist/node-types/bot-report.d.ts.map +1 -1
  70. package/dist/node-types/bot-report.js +24 -3
  71. package/dist/node-types/bot-report.js.map +1 -1
  72. package/dist/node-types/plan-task.d.ts +8 -17
  73. package/dist/node-types/plan-task.d.ts.map +1 -1
  74. package/dist/node-types/plan-task.js +217 -256
  75. package/dist/node-types/plan-task.js.map +1 -1
  76. package/dist/node-types/review-result.js +8 -6
  77. package/dist/node-types/review-result.js.map +1 -1
  78. package/dist/palindrome.d.ts +9 -0
  79. package/dist/palindrome.d.ts.map +1 -0
  80. package/dist/palindrome.js +14 -0
  81. package/dist/palindrome.js.map +1 -0
  82. package/dist/ui/approval-card.js +91 -82
  83. package/dist/ui/bot-activity.js +73 -56
  84. package/dist/ui/bot-config.js +48 -31
  85. package/dist/ui/bot-dashboard.js +52 -36
  86. package/dist/ui/bot-panel.js +230 -228
  87. package/dist/ui/bot-slot-card.js +100 -90
  88. package/dist/ui/bot-status.js +37 -15
  89. package/dist/ui/budget-bar.js +57 -31
  90. package/dist/ui/capability-editor.js +447 -378
  91. package/dist/ui/chat-task-result.js +78 -71
  92. package/dist/ui/decision-log.js +68 -81
  93. package/dist/ui/genesis-block.js +86 -95
  94. package/dist/ui/instance-stream-view.js +722 -0
  95. package/dist/ui/profile-card.js +96 -221
  96. package/dist/ui/profile-editor.js +532 -575
  97. package/dist/ui/settings-section.js +41 -45
  98. package/dist/ui/swarm-controls.js +212 -135
  99. package/dist/ui/swarm-dashboard.js +3992 -2715
  100. package/dist/ui/task-detail-view.js +415 -521
  101. package/dist/ui/task-editor.js +339 -390
  102. package/dist/ui/task-pool-list.js +60 -55
  103. package/dist/workflows/src/palindrome.d.ts +11 -0
  104. package/dist/workflows/src/palindrome.d.ts.map +1 -0
  105. package/dist/workflows/src/palindrome.js +16 -0
  106. package/dist/workflows/src/palindrome.js.map +1 -0
  107. package/dist/workflows/tests/palindrome.test.d.ts +2 -0
  108. package/dist/workflows/tests/palindrome.test.d.ts.map +1 -0
  109. package/dist/workflows/tests/palindrome.test.js +41 -0
  110. package/dist/workflows/tests/palindrome.test.js.map +1 -0
  111. package/dist/workflows/weaver-bot-batch.js +1 -1
  112. package/dist/workflows/weaver-bot-batch.js.map +1 -1
  113. package/dist/workflows/weaver-bot.js +1 -1
  114. package/dist/workflows/weaver-bot.js.map +1 -1
  115. package/flowweaver.manifest.json +1 -1
  116. package/package.json +8 -2
  117. package/src/ai-chat-provider.ts +5 -5
  118. package/src/bot/acceptance-merge.ts +62 -0
  119. package/src/bot/ai-client.ts +77 -21
  120. package/src/bot/assistant-tools.ts +3 -3
  121. package/src/bot/audit-logger.ts +42 -14
  122. package/src/bot/audit-trail.ts +211 -0
  123. package/src/bot/behavior-defaults.ts +7 -2
  124. package/src/bot/capability-registry.ts +84 -28
  125. package/src/bot/capability-types.ts +11 -0
  126. package/src/bot/cli-provider.ts +8 -7
  127. package/src/bot/preflight.ts +285 -0
  128. package/src/bot/provider-shim.ts +218 -0
  129. package/src/bot/runner.ts +68 -20
  130. package/src/bot/step-executor.ts +69 -127
  131. package/src/bot/swarm-controller.ts +94 -20
  132. package/src/bot/task-create-handler.ts +164 -0
  133. package/src/bot/task-store.ts +83 -0
  134. package/src/bot/types.ts +4 -1
  135. package/src/bot/weaver-tools.ts +7 -45
  136. package/src/node-types/agent-execute.ts +102 -16
  137. package/src/node-types/bot-report.ts +24 -3
  138. package/src/node-types/plan-task.ts +238 -280
  139. package/src/node-types/review-result.ts +8 -6
  140. package/src/palindrome.ts +14 -0
  141. package/src/ui/approval-card.tsx +78 -62
  142. package/src/ui/bot-activity.tsx +12 -10
  143. package/src/ui/bot-config.tsx +12 -10
  144. package/src/ui/bot-dashboard.tsx +13 -11
  145. package/src/ui/bot-panel.tsx +189 -171
  146. package/src/ui/bot-slot-card.tsx +125 -70
  147. package/src/ui/bot-status.tsx +4 -4
  148. package/src/ui/budget-bar.tsx +86 -25
  149. package/src/ui/capability-editor.tsx +392 -257
  150. package/src/ui/chat-task-result.tsx +81 -78
  151. package/src/ui/decision-log.tsx +76 -73
  152. package/src/ui/genesis-block.tsx +91 -61
  153. package/src/ui/instance-stream-view.tsx +861 -0
  154. package/src/ui/profile-card.tsx +195 -168
  155. package/src/ui/profile-editor.tsx +453 -370
  156. package/src/ui/settings-section.tsx +46 -39
  157. package/src/ui/swarm-controls.tsx +252 -123
  158. package/src/ui/swarm-dashboard.tsx +999 -466
  159. package/src/ui/task-detail-view.tsx +485 -428
  160. package/src/ui/task-editor.tsx +329 -271
  161. package/src/ui/task-pool-list.tsx +68 -62
  162. package/src/workflows/src/palindrome.ts +16 -0
  163. package/src/workflows/tests/palindrome.test.ts +49 -0
  164. package/src/workflows/weaver-bot-batch.ts +1 -1
  165. package/src/workflows/weaver-bot.ts +1 -1
  166. package/dist/ui/bot-constants.d.ts +0 -14
  167. package/dist/ui/bot-constants.d.ts.map +0 -1
  168. package/dist/ui/bot-constants.js +0 -189
  169. package/dist/ui/bot-constants.js.map +0 -1
  170. package/dist/ui/steer-api.d.ts +0 -7
  171. package/dist/ui/steer-api.d.ts.map +0 -1
  172. package/dist/ui/steer-api.js +0 -11
  173. package/dist/ui/steer-api.js.map +0 -1
  174. package/dist/ui/trace-to-timeline.d.ts +0 -91
  175. package/dist/ui/trace-to-timeline.d.ts.map +0 -1
  176. package/dist/ui/trace-to-timeline.js +0 -116
  177. package/dist/ui/trace-to-timeline.js.map +0 -1
  178. package/dist/ui/use-stream-timeline.d.ts +0 -50
  179. package/dist/ui/use-stream-timeline.d.ts.map +0 -1
  180. package/dist/ui/use-stream-timeline.js +0 -245
  181. package/dist/ui/use-stream-timeline.js.map +0 -1
@@ -2,9 +2,8 @@
2
2
  * SettingsSection — inline collapsible settings, rendered inside workspace.
3
3
  * Starts collapsed; fetches provider/insight data on mount.
4
4
  */
5
- const React = require('react');
6
- const { useState, useEffect, useCallback } = React;
7
- const { Flex, Typography, Button, CollapsibleSection, KeyValueRow, toast } = require('@fw/plugin-ui-kit');
5
+ import React, { useState, useEffect, useCallback } from 'react';
6
+ import { Flex, Typography, Button, CollapsibleSection, KeyValueRow, toast } from '@fw/plugin-ui-kit';
8
7
 
9
8
  interface SettingsSectionProps {
10
9
  callTool: (tool: string, args?: Record<string, unknown>) => Promise<unknown>;
@@ -54,42 +53,50 @@ function SettingsSection({ callTool, dispatchEvent }: SettingsSectionProps) {
54
53
  ? (trustScore <= 1 ? (trustScore * 100).toFixed(0) : Math.round(trustScore)) + '%'
55
54
  : '\u2014';
56
55
 
57
- return React.createElement(CollapsibleSection, {
58
- title: 'Settings', variant: 'list', defaultExpanded: false,
59
- },
60
- React.createElement(Flex, { variant: 'column-start-start-nowrap-4', style: { width: '100%' } },
61
- activeProvider && React.createElement(KeyValueRow, {
62
- keyName: 'Provider',
63
- value: `${activeProvider.name} (${activeProvider.source})`,
64
- size: 'small',
65
- }),
66
- insights?.trust && React.createElement(KeyValueRow, {
67
- keyName: 'Trust',
68
- value: `Phase ${insights.trust.phase} · ${trustDisplay}`,
69
- size: 'small',
70
- }),
71
- insights?.health && React.createElement(KeyValueRow, {
72
- keyName: 'Health',
73
- value: `${insights.health.overall}/100`,
74
- size: 'small',
75
- }),
76
- insights?.cost && React.createElement(KeyValueRow, {
77
- keyName: 'Cost (7d)',
78
- value: `$${insights.cost.last7Days?.toFixed(2) ?? '0.00'} · ${insights.cost.trend ?? 'stable'}`,
79
- size: 'small',
80
- }),
81
- React.createElement(Flex, {
82
- variant: 'row-center-space-between-nowrap-8',
83
- style: { width: '100%', marginTop: '4px' },
84
- },
85
- React.createElement(Button, {
86
- size: 'xs', variant: 'outlined', color: 'danger', onClick: handleClear,
87
- }, 'Clear Run History'),
88
- React.createElement(Typography, {
89
- variant: 'smallCaption-regular', color: 'color-text-subtle',
90
- }, 'Edit settings in .weaver.json'),
91
- ),
92
- ),
56
+ return (
57
+ <CollapsibleSection title="Settings" variant="list" defaultExpanded={false}>
58
+ <Flex variant="column-start-start-nowrap-4" style={{ width: '100%' }}>
59
+ {activeProvider && (
60
+ <KeyValueRow
61
+ keyName="Provider"
62
+ value={`${activeProvider.name} (${activeProvider.source})`}
63
+ size="small"
64
+ />
65
+ )}
66
+ {insights?.trust && (
67
+ <KeyValueRow
68
+ keyName="Trust"
69
+ value={`Phase ${insights.trust.phase} · ${trustDisplay}`}
70
+ size="small"
71
+ />
72
+ )}
73
+ {insights?.health && (
74
+ <KeyValueRow
75
+ keyName="Health"
76
+ value={`${insights.health.overall}/100`}
77
+ size="small"
78
+ />
79
+ )}
80
+ {insights?.cost && (
81
+ <KeyValueRow
82
+ keyName="Cost (7d)"
83
+ value={`$${insights.cost.last7Days?.toFixed(2) ?? '0.00'} · ${insights.cost.trend ?? 'stable'}`}
84
+ size="small"
85
+ />
86
+ )}
87
+ <Flex
88
+ variant="row-center-space-between-nowrap-8"
89
+ style={{ width: '100%', marginTop: '4px' }}
90
+ >
91
+ <Button size="xs" variant="outlined" color="danger" onClick={handleClear}>
92
+ Clear Run History
93
+ </Button>
94
+ <Typography variant="smallCaption-regular" color="color-text-subtle">
95
+ Edit settings in .weaver.json
96
+ </Typography>
97
+ </Flex>
98
+ </Flex>
99
+ </CollapsibleSection>
93
100
  );
94
101
  }
95
102
 
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * SwarmControls — control bar for the swarm: start/pause/stop, status badge, active bots count.
3
- * Runs in the pack sandbox — uses CommonJS require, React.createElement throughout.
3
+ *
4
+ * When idle and Start is clicked, expands an inline config form for concurrency + budget params.
5
+ * When running, shows editable max concurrency inline in the stats area.
4
6
  */
5
- const React = require('react');
6
- const { useState, useCallback } = React;
7
- const {
8
- Flex, Button, Typography, IconButton, StatusIcon, toast, usePackWorkspace,
9
- } = require('@fw/plugin-ui-kit');
7
+ import React, { useState, useCallback } from 'react';
8
+ import {
9
+ Flex, Button, Typography, IconButton, StatusIcon, Input, Slider, Field, Section,
10
+ CollapsibleSection, toast, usePackWorkspace,
11
+ } from '@fw/plugin-ui-kit';
10
12
 
11
13
  // ---------------------------------------------------------------------------
12
14
  // Types
@@ -19,6 +21,13 @@ interface InstanceInfo {
19
21
  currentTaskId?: string;
20
22
  }
21
23
 
24
+ interface SwarmBudgetLayer {
25
+ limitTokens: number;
26
+ usedTokens: number;
27
+ limitCost: number;
28
+ usedCost: number;
29
+ }
30
+
22
31
  interface SwarmStatus {
23
32
  status: 'idle' | 'running' | 'paused' | 'stopping';
24
33
  instances: Record<string, InstanceInfo>;
@@ -28,6 +37,7 @@ interface SwarmStatus {
28
37
  totalTokensUsed: number;
29
38
  totalCost: number;
30
39
  startedAt?: string;
40
+ budgets?: { workspace: SwarmBudgetLayer; session: SwarmBudgetLayer };
31
41
  }
32
42
 
33
43
  interface SwarmControlsProps {
@@ -74,6 +84,16 @@ function SwarmControls({ swarmStatus, onRefresh }: SwarmControlsProps) {
74
84
  const [starting, setStarting] = useState(false);
75
85
  const [pausing, setPausing] = useState(false);
76
86
  const [stopping, setStopping] = useState(false);
87
+ const [showStartConfig, setShowStartConfig] = useState(false);
88
+
89
+ // Start config form state
90
+ const [maxConcurrent, setMaxConcurrent] = useState(5);
91
+ const [sessionTokenBudget, setSessionTokenBudget] = useState('');
92
+ const [sessionCostBudget, setSessionCostBudget] = useState('');
93
+
94
+ // Live concurrency edit
95
+ const [editingConcurrency, setEditingConcurrency] = useState(false);
96
+ const [liveConcurrency, setLiveConcurrency] = useState('');
77
97
 
78
98
  const status = swarmStatus?.status ?? 'idle';
79
99
  const instances = swarmStatus?.instances ?? {};
@@ -86,38 +106,39 @@ function SwarmControls({ swarmStatus, onRefresh }: SwarmControlsProps) {
86
106
 
87
107
  // --- Actions ---
88
108
 
89
- const handleStart = useCallback(async () => {
109
+ const handleStartWithConfig = useCallback(async () => {
90
110
  setStarting(true);
91
111
  try {
92
- const result = await ctx.callTool('fw_weaver_swarm_start', {});
112
+ const args: Record<string, unknown> = {};
113
+ if (maxConcurrent > 0) args.maxConcurrent = maxConcurrent;
114
+ const st = parseInt(sessionTokenBudget, 10);
115
+ if (st > 0) args.sessionBudgetTokens = st;
116
+ const sc = parseFloat(sessionCostBudget);
117
+ if (sc > 0) args.sessionBudgetCost = sc;
118
+
119
+ const result = await ctx.callTool('fw_weaver_swarm_start', args);
93
120
  const data = result as Record<string, unknown> | null;
94
121
  if (data?.error) {
95
122
  toast(String(data.error), { type: 'error' });
96
123
  } else {
97
124
  toast('Swarm started', { type: 'success' });
125
+ setShowStartConfig(false);
98
126
  }
99
127
  onRefresh();
100
128
  } catch (err: unknown) {
101
- const msg = err instanceof Error ? err.message : 'Failed to start swarm';
102
- toast(msg, { type: 'error' });
129
+ toast(err instanceof Error ? err.message : 'Failed to start swarm', { type: 'error' });
103
130
  }
104
131
  setStarting(false);
105
- }, [ctx, onRefresh]);
132
+ }, [ctx, onRefresh, maxConcurrent, sessionTokenBudget, sessionCostBudget]);
106
133
 
107
134
  const handlePause = useCallback(async () => {
108
135
  setPausing(true);
109
136
  try {
110
- const result = await ctx.callTool('fw_weaver_swarm_pause', {});
111
- const data = result as Record<string, unknown> | null;
112
- if (data?.error) {
113
- toast(String(data.error), { type: 'error' });
114
- } else {
115
- toast('Swarm paused', { type: 'info' });
116
- }
137
+ await ctx.callTool('fw_weaver_swarm_pause', {});
138
+ toast('Swarm paused', { type: 'info' });
117
139
  onRefresh();
118
140
  } catch (err: unknown) {
119
- const msg = err instanceof Error ? err.message : 'Failed to pause swarm';
120
- toast(msg, { type: 'error' });
141
+ toast(err instanceof Error ? err.message : 'Failed to pause', { type: 'error' });
121
142
  }
122
143
  setPausing(false);
123
144
  }, [ctx, onRefresh]);
@@ -125,17 +146,11 @@ function SwarmControls({ swarmStatus, onRefresh }: SwarmControlsProps) {
125
146
  const handleResume = useCallback(async () => {
126
147
  setStarting(true);
127
148
  try {
128
- const result = await ctx.callTool('fw_weaver_swarm_start', {});
129
- const data = result as Record<string, unknown> | null;
130
- if (data?.error) {
131
- toast(String(data.error), { type: 'error' });
132
- } else {
133
- toast('Swarm resumed', { type: 'success' });
134
- }
149
+ await ctx.callTool('fw_weaver_swarm_start', {});
150
+ toast('Swarm resumed', { type: 'success' });
135
151
  onRefresh();
136
152
  } catch (err: unknown) {
137
- const msg = err instanceof Error ? err.message : 'Failed to resume swarm';
138
- toast(msg, { type: 'error' });
153
+ toast(err instanceof Error ? err.message : 'Failed to resume', { type: 'error' });
139
154
  }
140
155
  setStarting(false);
141
156
  }, [ctx, onRefresh]);
@@ -149,112 +164,226 @@ function SwarmControls({ swarmStatus, onRefresh }: SwarmControlsProps) {
149
164
  });
150
165
  if (!ok) { setStopping(false); return; }
151
166
  try {
152
- const result = await ctx.callTool('fw_weaver_swarm_stop', {});
153
- const data = result as Record<string, unknown> | null;
154
- if (data?.error) {
155
- toast(String(data.error), { type: 'error' });
156
- } else {
157
- toast('Swarm stopped', { type: 'info' });
158
- }
167
+ await ctx.callTool('fw_weaver_swarm_stop', {});
168
+ toast('Swarm stopped', { type: 'info' });
159
169
  onRefresh();
160
170
  } catch (err: unknown) {
161
- const msg = err instanceof Error ? err.message : 'Failed to stop swarm';
162
- toast(msg, { type: 'error' });
171
+ toast(err instanceof Error ? err.message : 'Failed to stop', { type: 'error' });
163
172
  }
164
173
  setStopping(false);
165
174
  }, [ctx, onRefresh]);
166
175
 
176
+ const handleConcurrencyChange = useCallback(async () => {
177
+ const mc = parseInt(liveConcurrency, 10);
178
+ if (!mc || mc < 1) { setEditingConcurrency(false); return; }
179
+ try {
180
+ await ctx.callTool('fw_weaver_swarm_config', { maxConcurrent: mc });
181
+ toast(`Max concurrency set to ${mc}`, { type: 'success' });
182
+ onRefresh();
183
+ } catch (err: unknown) {
184
+ toast(err instanceof Error ? err.message : 'Failed to update config', { type: 'error' });
185
+ }
186
+ setEditingConcurrency(false);
187
+ }, [ctx, onRefresh, liveConcurrency]);
188
+
167
189
  // --- Render ---
168
190
 
169
191
  const anyLoading = starting || pausing || stopping;
170
192
 
171
- return React.createElement(Flex, {
172
- variant: 'row-center-space-between-nowrap-10',
173
- style: {
174
- padding: '8px 16px',
175
- borderBottom: '1px solid var(--color-border-default)',
176
- flexShrink: 0,
177
- backgroundColor: isRunning
178
- ? 'var(--color-brand-main-alpha-10)'
179
- : isPaused
180
- ? 'var(--color-status-caution-alpha-10)'
181
- : 'transparent',
182
- },
183
- },
184
- // Left: status icon + label
185
- React.createElement(Flex, { variant: 'row-center-start-nowrap-8', style: { flexShrink: 0 } },
186
- React.createElement(StatusIcon, {
187
- status: swarmStatusToIconStatus(status),
188
- size: 'sm',
189
- }),
190
- React.createElement(Typography, {
191
- variant: 'caption-bold',
192
- }, statusLabel(status)),
193
- ),
194
-
195
- // Center: bot count + stats
196
- React.createElement(Flex, {
197
- variant: 'row-center-start-nowrap-12',
198
- style: { flex: 1 },
199
- },
200
- total > 0 && React.createElement(Typography, {
201
- variant: 'caption-regular',
202
- color: 'color-text-medium',
203
- }, `${active}/${total} bots active`),
204
- swarmStatus && swarmStatus.tasksCompleted > 0 && React.createElement(Typography, {
205
- variant: 'caption-regular',
206
- color: 'color-text-subtle',
207
- }, `${swarmStatus.tasksCompleted} done`),
208
- swarmStatus && swarmStatus.runsIncomplete > 0 && React.createElement(Typography, {
209
- variant: 'caption-regular',
210
- color: 'color-status-negative',
211
- }, `${swarmStatus.runsIncomplete} incomplete`),
212
- ),
213
-
214
- // Right: action buttons
215
- React.createElement(Flex, { variant: 'row-center-start-nowrap-4', style: { flexShrink: 0 } },
216
- // Start / Resume button
217
- (isIdle || isPaused) && React.createElement(Button, {
218
- size: 'xs',
219
- variant: 'outlined',
220
- color: 'primary',
221
- onClick: isPaused ? handleResume : handleStart,
222
- loading: starting,
223
- disabled: anyLoading,
224
- }, isPaused ? 'Resume' : 'Start'),
225
-
226
- // Pause button (only when running)
227
- isRunning && React.createElement(Button, {
228
- size: 'xs',
229
- variant: 'outlined',
230
- color: 'warning',
231
- onClick: handlePause,
232
- loading: pausing,
233
- disabled: anyLoading,
234
- }, 'Pause'),
235
-
236
- // Stop button (when running or paused)
237
- (isRunning || isPaused) && React.createElement(Button, {
238
- size: 'xs',
239
- variant: 'outlined',
240
- color: 'danger',
241
- onClick: handleStop,
242
- loading: stopping,
243
- disabled: anyLoading || isStopping,
244
- }, 'Stop'),
245
-
246
- // Refresh button (always available)
247
- React.createElement(IconButton, {
248
- icon: 'reset',
249
- size: 'xs',
250
- variant: 'outlined',
251
- onClick: onRefresh,
252
- disabled: anyLoading,
253
- }),
254
- ),
193
+ return (
194
+ <Flex variant="column-stretch-start-nowrap-0">
195
+
196
+ {/* Main control bar */}
197
+ <Section
198
+ padding="compact"
199
+ border="bottom"
200
+ shrink={true}
201
+ background={isRunning ? 'none' : isPaused ? 'none' : 'none'}
202
+ >
203
+ <Flex variant="row-center-space-between-nowrap-10">
204
+
205
+ {/* Left: status icon + label */}
206
+ <Flex variant="row-center-start-nowrap-8">
207
+ <StatusIcon
208
+ status={swarmStatusToIconStatus(status)}
209
+ size="sm"
210
+ />
211
+ <Typography variant="caption-bold">{statusLabel(status)}</Typography>
212
+ </Flex>
213
+
214
+ {/* Center: bot count + stats + live concurrency */}
215
+ <Flex variant="row-center-start-nowrap-12">
216
+ {total > 0 && (
217
+ <Typography variant="caption-regular" color="color-text-medium">
218
+ {`${active}/${total} bots active`}
219
+ </Typography>
220
+ )}
221
+
222
+ {/* Concurrency display (when running) — edit in Control tab */}
223
+ {(isRunning || isPaused) && (
224
+ <Typography variant="caption-regular" color="color-text-subtle">
225
+ {`max ${swarmStatus?.maxConcurrent ?? '?'}`}
226
+ </Typography>
227
+ )}
228
+
229
+ {swarmStatus && swarmStatus.tasksCompleted > 0 && (
230
+ <Typography variant="caption-regular" color="color-text-subtle">
231
+ {`${swarmStatus.tasksCompleted} done`}
232
+ </Typography>
233
+ )}
234
+ {swarmStatus && swarmStatus.runsIncomplete > 0 && (
235
+ <Typography variant="caption-regular" color="color-status-negative">
236
+ {`${swarmStatus.runsIncomplete} incomplete`}
237
+ </Typography>
238
+ )}
239
+ </Flex>
240
+
241
+ {/* Right: action buttons */}
242
+ <Flex variant="row-center-start-nowrap-4">
243
+ {/* Start button (idle) opens config form */}
244
+ {isIdle && !showStartConfig && (
245
+ <Button
246
+ size="xs"
247
+ variant="outlined"
248
+ color="primary"
249
+ onClick={() => setShowStartConfig(true)}
250
+ disabled={anyLoading}
251
+ >
252
+ Start
253
+ </Button>
254
+ )}
255
+
256
+ {/* Resume button (paused) */}
257
+ {isPaused && (
258
+ <Button
259
+ size="xs"
260
+ variant="outlined"
261
+ color="primary"
262
+ onClick={handleResume}
263
+ loading={starting}
264
+ disabled={anyLoading}
265
+ >
266
+ Resume
267
+ </Button>
268
+ )}
269
+
270
+ {/* Pause button (running) */}
271
+ {isRunning && (
272
+ <Button
273
+ size="xs"
274
+ variant="outlined"
275
+ color="warning"
276
+ onClick={handlePause}
277
+ loading={pausing}
278
+ disabled={anyLoading}
279
+ >
280
+ Pause
281
+ </Button>
282
+ )}
283
+
284
+ {/* Stop button (running or paused) */}
285
+ {(isRunning || isPaused) && (
286
+ <Button
287
+ size="xs"
288
+ variant="outlined"
289
+ color="danger"
290
+ onClick={handleStop}
291
+ loading={stopping}
292
+ disabled={anyLoading || isStopping}
293
+ >
294
+ Stop
295
+ </Button>
296
+ )}
297
+
298
+ {/* Cancel start config */}
299
+ {isIdle && showStartConfig && (
300
+ <IconButton
301
+ icon="close"
302
+ size="xs"
303
+ variant="clear"
304
+ onClick={() => setShowStartConfig(false)}
305
+ />
306
+ )}
307
+
308
+ {/* Refresh */}
309
+ <IconButton
310
+ icon="reset"
311
+ size="xs"
312
+ variant="outlined"
313
+ onClick={onRefresh}
314
+ disabled={anyLoading}
315
+ />
316
+ </Flex>
317
+ </Flex>
318
+ </Section>
319
+
320
+ {/* Start config form (inline, when Start is clicked) */}
321
+ {isIdle && showStartConfig && (
322
+ <Section padding="default" border="bottom" shrink={true}>
323
+ <Flex variant="column-stretch-start-nowrap-8">
324
+ <Typography variant="caption-thick" color="color-text-high">
325
+ Start Configuration
326
+ </Typography>
327
+
328
+ <Flex variant="row-center-start-nowrap-12">
329
+ <Flex variant="row-center-start-nowrap-8">
330
+ <Typography variant="smallCaption-regular" color="color-text-subtle">Max</Typography>
331
+ <Slider
332
+ value={maxConcurrent}
333
+ min={1}
334
+ max={20}
335
+ step={1}
336
+ onChange={(val: number) => setMaxConcurrent(val)}
337
+ />
338
+ <Typography variant="caption-thick" color="color-text-high">{maxConcurrent}</Typography>
339
+ </Flex>
340
+ <Field label="Token Budget" labelWidth={100}>
341
+ <Input
342
+ value={sessionTokenBudget}
343
+ onChange={(value: string) => setSessionTokenBudget(value)}
344
+ type="number"
345
+ size="small"
346
+ placeholder="No limit"
347
+ />
348
+ </Field>
349
+ <Field label="Cost Budget ($)" labelWidth={100}>
350
+ <Input
351
+ value={sessionCostBudget}
352
+ onChange={(value: string) => setSessionCostBudget(value)}
353
+ type="number"
354
+ size="small"
355
+ placeholder="No limit"
356
+ />
357
+ </Field>
358
+ </Flex>
359
+
360
+ <Flex variant="row-center-start-nowrap-8">
361
+ <Button
362
+ size="xs"
363
+ variant="fill"
364
+ color="primary"
365
+ onClick={handleStartWithConfig}
366
+ loading={starting}
367
+ disabled={anyLoading}
368
+ leftIcon="playArrow"
369
+ >
370
+ Start Swarm
371
+ </Button>
372
+ <Button
373
+ size="xs"
374
+ variant="clear"
375
+ color="secondary"
376
+ onClick={() => setShowStartConfig(false)}
377
+ >
378
+ Cancel
379
+ </Button>
380
+ </Flex>
381
+ </Flex>
382
+ </Section>
383
+ )}
384
+ </Flex>
255
385
  );
256
386
  }
257
387
 
258
388
  export { SwarmControls };
259
389
  export default SwarmControls;
260
- module.exports = SwarmControls;