@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,18 +1,15 @@
1
1
  /**
2
- * BotSlotCard — compact per-bot status card for the swarm dashboard.
3
- * Displays bot name, status icon, current task, tokens used, and cost.
4
- * Designed for horizontal row layout (~120px wide).
5
- *
6
- * Runs in the pack sandbox — CommonJS require, React.createElement throughout.
2
+ * BotSlotCard — single row in the bot table for the swarm dashboard.
3
+ * Displays bot name, status, current task, tokens, and cost in a table row layout.
7
4
  */
8
- const React = require('react');
9
- const { Flex, Typography, IconButton, StatusIcon, Icon } = require('@fw/plugin-ui-kit');
5
+ import React from 'react';
6
+ import { Flex, Typography, Icon, IconButton } from '@fw/plugin-ui-kit';
10
7
 
11
8
  // ---------------------------------------------------------------------------
12
9
  // Types
13
10
  // ---------------------------------------------------------------------------
14
11
 
15
- interface BotSlot {
12
+ interface InstanceSlot {
16
13
  botId: string;
17
14
  botName: string;
18
15
  status: 'idle' | 'executing' | 'paused' | 'stopped';
@@ -24,9 +21,12 @@ interface BotSlot {
24
21
  }
25
22
 
26
23
  interface BotSlotCardProps {
27
- bot: BotSlot;
28
- /** Task title to display when executing (resolved externally) */
24
+ bot: InstanceSlot;
29
25
  currentTaskTitle?: string;
26
+ profileName?: string;
27
+ botDisplayName?: string;
28
+ botIcon?: string;
29
+ botColor?: string;
30
30
  onPause?: (botId: string) => void;
31
31
  onResume?: (botId: string) => void;
32
32
  onStop?: (botId: string) => void;
@@ -36,22 +36,6 @@ interface BotSlotCardProps {
36
36
  // Helpers
37
37
  // ---------------------------------------------------------------------------
38
38
 
39
- type DotStatus = 'positive' | 'negative' | 'caution' | 'neutral' | 'info';
40
-
41
- const statusToDot: Record<string, DotStatus> = {
42
- idle: 'neutral',
43
- executing: 'info',
44
- paused: 'caution',
45
- stopped: 'negative',
46
- };
47
-
48
- const statusToIcon: Record<string, string> = {
49
- idle: 'pending',
50
- executing: 'running',
51
- paused: 'pause',
52
- stopped: 'stop',
53
- };
54
-
55
39
  const statusToLabel: Record<string, string> = {
56
40
  idle: 'Idle',
57
41
  executing: 'Executing',
@@ -74,114 +58,82 @@ function formatCost(n: number): string {
74
58
  // Component
75
59
  // ---------------------------------------------------------------------------
76
60
 
77
- function BotSlotCard({ bot, currentTaskTitle, onPause, onResume, onStop }: BotSlotCardProps) {
61
+ function BotSlotCard({ bot, currentTaskTitle, profileName, botDisplayName, botIcon, botColor, onPause, onResume, onStop }: BotSlotCardProps) {
78
62
  const { botId, botName, status, currentTaskId, tokensUsed, cost } = bot;
79
- const dotStatus = statusToDot[status] ?? 'neutral';
80
- const iconName = statusToIcon[status] ?? 'pending';
81
- const label = statusToLabel[status] ?? status;
82
63
  const isExecuting = status === 'executing';
83
64
  const isPaused = status === 'paused';
65
+ const label = statusToLabel[status] ?? status;
66
+ const taskText = isExecuting ? (currentTaskTitle || currentTaskId || '-') : '-';
84
67
 
85
- // Status icon color
86
- const iconColor = dotStatus === 'neutral'
87
- ? 'color-text-subtle'
88
- : `color-status-${dotStatus}`;
89
-
90
- // Task display text
91
- const taskText = isExecuting
92
- ? (currentTaskTitle || currentTaskId || 'Working...')
93
- : null;
94
-
95
- // Per-bot action buttons
96
- const actions = React.createElement(Flex, {
97
- variant: 'row-center-center-nowrap-2',
98
- style: { marginTop: '4px' },
68
+ return React.createElement(Flex, {
69
+ variant: 'row-center-start-nowrap-8',
70
+ style: { padding: '6px 16px', minHeight: '38px', borderBottom: '1px solid var(--color-border-default)' },
99
71
  },
100
- // Pause / Resume button
101
- (isExecuting && onPause) ? React.createElement(IconButton, {
102
- icon: 'pause', size: 'xs', variant: 'clear',
103
- onClick: (e: React.MouseEvent) => { e.stopPropagation(); onPause(botId); },
104
- title: 'Pause bot',
105
- }) : null,
106
- (isPaused && onResume) ? React.createElement(IconButton, {
107
- icon: 'playArrow', size: 'xs', variant: 'clear',
108
- onClick: (e: React.MouseEvent) => { e.stopPropagation(); onResume(botId); },
109
- title: 'Resume bot',
110
- }) : null,
111
- // Stop button (available when executing or paused)
112
- ((isExecuting || isPaused) && onStop) ? React.createElement(IconButton, {
113
- icon: 'stop', size: 'xs', variant: 'clear',
114
- onClick: (e: React.MouseEvent) => { e.stopPropagation(); onStop(botId); },
115
- title: 'Stop bot',
116
- }) : null,
117
- );
118
-
119
- const hasActions = (isExecuting && onPause) || (isPaused && onResume) || ((isExecuting || isPaused) && onStop);
120
-
121
- return React.createElement('div', {
122
- style: {
123
- width: '120px',
124
- minWidth: '120px',
125
- padding: '8px',
126
- borderRadius: 'var(--border-radius-secondary)',
127
- border: '1px solid var(--color-border-default)',
128
- backgroundColor: 'var(--color-surface-elevated)',
129
- display: 'flex',
130
- flexDirection: 'column',
131
- gap: '4px',
132
- flexShrink: 0,
72
+ // Instance name
73
+ React.createElement(Typography, {
74
+ variant: 'smallCaption-regular', color: 'color-text-high',
75
+ style: { width: '120px', flexShrink: 0 },
76
+ }, profileName ? `${profileName} #${botId.split('-').pop() ?? '0'}` : botName),
77
+
78
+ // Bot (icon + name)
79
+ React.createElement(Flex, {
80
+ variant: 'row-center-start-nowrap-4',
81
+ style: { width: '110px', flexShrink: 0, color: botColor ? `var(--${botColor})` : undefined },
133
82
  },
134
- },
135
- // Row 1: Status icon + bot name
136
- React.createElement(Flex, { variant: 'row-center-start-nowrap-4' },
137
- React.createElement(Icon, {
138
- name: iconName as any, size: 12, color: iconColor,
139
- }),
83
+ React.createElement(Icon, { name: botIcon || 'smartToy', size: 12 }),
140
84
  React.createElement(Typography, {
141
- variant: 'caption-thick', color: 'color-text-high',
142
- style: {
143
- overflow: 'hidden',
144
- textOverflow: 'ellipsis',
145
- whiteSpace: 'nowrap',
146
- flex: 1,
147
- minWidth: 0,
148
- },
149
- }, botName),
85
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
86
+ }, botDisplayName || '-'),
150
87
  ),
151
88
 
152
- // Row 2: Status label
89
+ // Status
153
90
  React.createElement(Typography, {
154
91
  variant: 'smallCaption-regular',
155
- color: iconColor,
156
- style: { textTransform: 'capitalize' },
92
+ color: isExecuting ? 'color-brand-main' : 'color-text-subtle',
93
+ style: { width: '70px', flexShrink: 0 },
157
94
  }, label),
158
95
 
159
- // Row 3: Current task (if executing)
160
- taskText ? React.createElement(Typography, {
96
+ // Current task
97
+ React.createElement(Typography, {
161
98
  variant: 'smallCaption-regular',
162
- color: 'color-text-medium',
163
- style: {
164
- overflow: 'hidden',
165
- textOverflow: 'ellipsis',
166
- whiteSpace: 'nowrap',
167
- },
168
- }, taskText) : null,
169
-
170
- // Row 4: Tokens + cost
171
- React.createElement(Flex, { variant: 'row-center-between-nowrap-4', style: { marginTop: 'auto' } },
172
- React.createElement(Typography, {
173
- variant: 'smallCaption-regular', color: 'color-text-subtle',
174
- }, formatTokens(tokensUsed)),
175
- React.createElement(Typography, {
176
- variant: 'smallCaption-regular', color: 'color-text-subtle',
177
- }, formatCost(cost)),
178
- ),
99
+ color: isExecuting ? 'color-text-medium' : 'color-text-subtle',
100
+ style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
101
+ }, taskText),
102
+
103
+ // Tokens
104
+ React.createElement(Typography, {
105
+ variant: 'smallCaption-regular',
106
+ color: 'color-text-subtle',
107
+ style: { width: '50px', flexShrink: 0, textAlign: 'right' },
108
+ }, formatTokens(tokensUsed)),
179
109
 
180
- // Row 5: Actions (optional)
181
- hasActions ? actions : null,
110
+ // Cost
111
+ React.createElement(Typography, {
112
+ variant: 'smallCaption-regular',
113
+ color: 'color-text-subtle',
114
+ style: { width: '50px', flexShrink: 0, textAlign: 'right' },
115
+ }, formatCost(cost)),
116
+
117
+ // Actions
118
+ React.createElement(Flex, {
119
+ variant: 'row-center-end-nowrap-1',
120
+ style: { width: '50px', flexShrink: 0 },
121
+ },
122
+ isExecuting && onPause && React.createElement(IconButton, {
123
+ icon: 'pause', size: 'xs', variant: 'clear',
124
+ onClick: () => onPause(botId), title: 'Pause',
125
+ }),
126
+ isPaused && onResume && React.createElement(IconButton, {
127
+ icon: 'playArrow', size: 'xs', variant: 'clear',
128
+ onClick: () => onResume(botId), title: 'Resume',
129
+ }),
130
+ (isExecuting || isPaused) && onStop && React.createElement(IconButton, {
131
+ icon: 'stop', size: 'xs', variant: 'clear', color: 'danger',
132
+ onClick: () => onStop(botId), title: 'Stop',
133
+ }),
134
+ ),
182
135
  );
183
136
  }
184
137
 
185
138
  export { BotSlotCard };
186
139
  export default BotSlotCard;
187
- module.exports = BotSlotCard;
@@ -13,10 +13,12 @@ function BudgetBar({ label, used, limit, unit }: {
13
13
  React.createElement(Typography, { variant: 'smallCaption-regular', color: 'color-text-subtle' },
14
14
  `${used.toLocaleString()} / ${limit.toLocaleString()} ${unit}`),
15
15
  ),
16
- React.createElement('div', {
17
- style: { width: '100%', height: '4px', borderRadius: '2px', backgroundColor: 'var(--color-surface-raised)' },
16
+ React.createElement(Flex, {
17
+ variant: 'row-start-start-nowrap-0',
18
+ style: { width: '100%', height: '4px', borderRadius: '2px', backgroundColor: 'var(--color-surface-raised)', overflow: 'hidden' },
18
19
  },
19
- React.createElement('div', {
20
+ React.createElement(Flex, {
21
+ variant: 'row-start-start-nowrap-0',
20
22
  style: { width: `${pct}%`, height: '100%', borderRadius: '2px', backgroundColor: color, transition: 'width 0.3s' },
21
23
  }),
22
24
  ),
@@ -21,7 +21,7 @@ interface TaskData {
21
21
  status: 'pending' | 'in-progress' | 'blocked' | 'done' | 'failed' | 'cancelled';
22
22
  isParent: boolean;
23
23
  currentBotId?: string;
24
- assignedBots: string[];
24
+ assignedProfile?: string;
25
25
  }
26
26
 
27
27
  interface SubtaskData {
@@ -138,7 +138,6 @@ function ChatTaskResult({ result, args, callTool, openWorkspace }: ChatTaskResul
138
138
  return React.createElement(Flex, {
139
139
  variant: 'row-center-start-nowrap-10',
140
140
  style: {
141
- padding: '8px 12px',
142
141
  borderRadius: 'var(--border-radius-regular)',
143
142
  border: '1px solid var(--color-border-default)',
144
143
  backgroundColor: 'var(--color-surface-low)',
@@ -159,8 +158,8 @@ function ChatTaskResult({ result, args, callTool, openWorkspace }: ChatTaskResul
159
158
  // Bot info
160
159
  const botLabel = task.currentBotId
161
160
  ? `Bot: ${task.currentBotId}`
162
- : task.assignedBots?.length
163
- ? `Assigned: ${task.assignedBots.join(', ')}`
161
+ : task.assignedProfile
162
+ ? `Profile: ${task.assignedProfile}`
164
163
  : null;
165
164
 
166
165
  const handleOpenDashboard = useCallback(() => {
@@ -173,7 +172,6 @@ function ChatTaskResult({ result, args, callTool, openWorkspace }: ChatTaskResul
173
172
  return React.createElement(Flex, {
174
173
  variant: 'row-center-start-nowrap-10',
175
174
  style: {
176
- padding: '8px 12px',
177
175
  borderRadius: 'var(--border-radius-regular)',
178
176
  border: '1px solid var(--color-border-default)',
179
177
  backgroundColor: 'var(--color-surface-low)',
@@ -194,13 +192,12 @@ function ChatTaskResult({ result, args, callTool, openWorkspace }: ChatTaskResul
194
192
  React.createElement(Typography, {
195
193
  variant: 'caption-thick',
196
194
  color: 'color-text-high',
197
- style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '100%' },
195
+ truncate: true,
198
196
  }, task.title),
199
197
 
200
198
  // Status + subtask progress + bot
201
199
  React.createElement(Flex, {
202
- variant: 'row-center-start-nowrap-6',
203
- style: { flexWrap: 'wrap', gap: '4px 8px' },
200
+ variant: 'row-center-start-wrap-8',
204
201
  },
205
202
  // Status label
206
203
  React.createElement(Typography, {
@@ -221,7 +218,7 @@ function ChatTaskResult({ result, args, callTool, openWorkspace }: ChatTaskResul
221
218
  botLabel && React.createElement(Typography, {
222
219
  variant: 'smallCaption-regular',
223
220
  color: 'color-text-low',
224
- style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
221
+ truncate: true,
225
222
  }, botLabel),
226
223
  ),
227
224
  ),
@@ -0,0 +1,148 @@
1
+ /**
2
+ * DecisionLog — displays recent orchestrator routing decisions.
3
+ *
4
+ * Each decision shows timestamp, task title, assigned instance, routing method,
5
+ * and the reasoning. AI-routed decisions also show confidence percentage.
6
+ *
7
+ * Pattern: CommonJS require for platform deps, React.createElement throughout.
8
+ */
9
+ const React = require('react');
10
+ const {
11
+ Flex, Typography, ScrollArea, Tag, SectionTitle,
12
+ } = require('@fw/plugin-ui-kit');
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Types
16
+ // ---------------------------------------------------------------------------
17
+
18
+ type RoutingMethod = 'exact-match' | 'single-eligible' | 'ai-routed' | 'round-robin' | 'manual';
19
+
20
+ interface Decision {
21
+ id: number;
22
+ timestamp: number;
23
+ taskId: string;
24
+ taskTitle: string;
25
+ assignedProfileId: string;
26
+ assignedInstanceId: string;
27
+ reason: string;
28
+ method: RoutingMethod;
29
+ confidence?: number;
30
+ }
31
+
32
+ interface DecisionLogProps {
33
+ decisions: Decision[];
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Helpers
38
+ // ---------------------------------------------------------------------------
39
+
40
+ const methodColors: Record<RoutingMethod, string> = {
41
+ 'exact-match': 'info',
42
+ 'single-eligible': 'positive',
43
+ 'ai-routed': 'secondary',
44
+ 'round-robin': 'secondary',
45
+ 'manual': 'caution',
46
+ };
47
+
48
+ const methodLabels: Record<RoutingMethod, string> = {
49
+ 'exact-match': 'exact',
50
+ 'single-eligible': 'single',
51
+ 'ai-routed': 'ai',
52
+ 'round-robin': 'robin',
53
+ 'manual': 'manual',
54
+ };
55
+
56
+ function formatTime(ts: number): string {
57
+ const d = new Date(ts);
58
+ return d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
59
+ }
60
+
61
+ function truncate(text: string, max: number): string {
62
+ return text.length > max ? text.slice(0, max - 1) + '\u2026' : text;
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // Component
67
+ // ---------------------------------------------------------------------------
68
+
69
+ function DecisionLog({ decisions }: DecisionLogProps) {
70
+ if (!decisions || decisions.length === 0) {
71
+ return React.createElement(Flex, {
72
+ variant: 'column-stretch-start-nowrap-4',
73
+ },
74
+ React.createElement(SectionTitle, null, 'Decision Log'),
75
+ React.createElement(Typography, {
76
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
77
+ }, 'No routing decisions yet.'),
78
+ );
79
+ }
80
+
81
+ // Show newest first
82
+ const sorted = [...decisions].sort((a, b) => b.timestamp - a.timestamp);
83
+
84
+ return React.createElement(Flex, {
85
+ variant: 'column-stretch-start-nowrap-4',
86
+ },
87
+ React.createElement(SectionTitle, null, 'Decision Log'),
88
+ React.createElement(ScrollArea, {
89
+ style: { maxHeight: '260px' },
90
+ },
91
+ React.createElement(Flex, {
92
+ variant: 'column-stretch-start-nowrap-0',
93
+ },
94
+ ...sorted.map((d: Decision) => {
95
+ const methodLabel = d.method === 'ai-routed' && d.confidence != null
96
+ ? `ai ${d.confidence}%`
97
+ : methodLabels[d.method] || d.method;
98
+
99
+ return React.createElement(Flex, {
100
+ key: d.id,
101
+ variant: 'column-stretch-start-nowrap-2',
102
+ style: {
103
+ padding: '6px 8px',
104
+ borderBottom: '1px solid var(--color-border-default)',
105
+ },
106
+ },
107
+ // Main line: time, title, instance, method
108
+ React.createElement(Flex, { variant: 'row-center-start-nowrap-8' },
109
+ React.createElement(Typography, {
110
+ variant: 'smallCaption-regular',
111
+ color: 'color-text-subtle',
112
+ style: { flexShrink: 0, fontFamily: 'var(--font-mono, monospace)', fontSize: '11px' },
113
+ }, formatTime(d.timestamp)),
114
+
115
+ React.createElement(Typography, {
116
+ variant: 'smallCaption-regular',
117
+ color: 'color-text-high',
118
+ style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
119
+ }, `"${truncate(d.taskTitle, 40)}"`),
120
+
121
+ React.createElement(Typography, {
122
+ variant: 'smallCaption-regular',
123
+ color: 'color-text-medium',
124
+ style: { flexShrink: 0 },
125
+ }, `\u2192 ${d.assignedInstanceId}`),
126
+
127
+ React.createElement(Tag, {
128
+ size: 'small',
129
+ color: methodColors[d.method] || 'secondary',
130
+ }, methodLabel),
131
+ ),
132
+
133
+ // Reason line
134
+ React.createElement(Typography, {
135
+ variant: 'smallCaption-regular',
136
+ color: 'color-text-subtle',
137
+ style: { paddingLeft: '70px' },
138
+ }, d.reason),
139
+ );
140
+ }),
141
+ ),
142
+ ),
143
+ );
144
+ }
145
+
146
+ export { DecisionLog };
147
+ export default DecisionLog;
148
+ module.exports = DecisionLog;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * ProfileCard — displays a bot profile summary with capabilities, preferences,
3
+ * instance count, and budget info. Used in the Config tab of the swarm dashboard.
4
+ *
5
+ * Pattern: CommonJS require for platform deps, React.createElement throughout.
6
+ */
7
+ const React = require('react');
8
+ const {
9
+ Flex, Typography, Icon, Chip, IconButton, Tag,
10
+ } = require('@fw/plugin-ui-kit');
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Types
14
+ // ---------------------------------------------------------------------------
15
+
16
+ interface Capability {
17
+ name: string;
18
+ description: string;
19
+ }
20
+
21
+ interface ProfilePreferences {
22
+ costStrategy: 'frugal' | 'balanced' | 'performance';
23
+ maxCostPerRun?: number;
24
+ maxCostPerTask?: number;
25
+ requireApproval: boolean;
26
+ instructions?: string;
27
+ }
28
+
29
+ interface Profile {
30
+ id: string;
31
+ name: string;
32
+ description: string;
33
+ icon: string;
34
+ color: string;
35
+ botId: string;
36
+ capabilities: Capability[];
37
+ preferences: ProfilePreferences;
38
+ minInstances: number;
39
+ maxInstances: number;
40
+ }
41
+
42
+ interface ProfileCardProps {
43
+ profile: Profile;
44
+ activeInstances: number;
45
+ onEdit?: (id: string) => void;
46
+ onDelete?: (id: string) => void;
47
+ }
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Component
51
+ // ---------------------------------------------------------------------------
52
+
53
+ function ProfileCard({ profile, activeInstances, onEdit, onDelete }: ProfileCardProps) {
54
+ const {
55
+ id, name, description, icon, color, capabilities,
56
+ preferences, maxInstances,
57
+ } = profile;
58
+
59
+ const budgetParts: string[] = [];
60
+ if (preferences.maxCostPerRun) budgetParts.push(`$${preferences.maxCostPerRun.toFixed(2)}/run`);
61
+ if (preferences.maxCostPerTask) budgetParts.push(`$${preferences.maxCostPerTask.toFixed(2)}/task`);
62
+ const budgetText = budgetParts.length > 0 ? budgetParts.join(' / ') : null;
63
+
64
+ return React.createElement(Flex, {
65
+ variant: 'column-stretch-start-nowrap-6',
66
+ style: {
67
+ padding: '10px 12px',
68
+ borderRadius: '8px',
69
+ border: '1px solid var(--color-border-default)',
70
+ backgroundColor: 'var(--color-surface-elevated)',
71
+ },
72
+ },
73
+ // Row 1: Icon + Name + Edit/Delete buttons
74
+ React.createElement(Flex, { variant: 'row-center-start-nowrap-8' },
75
+ React.createElement(Flex, {
76
+ variant: 'row-center-center-nowrap-0',
77
+ style: { color: `var(--${color})`, flexShrink: 0 },
78
+ },
79
+ React.createElement(Icon, { name: icon || 'smartToy', size: 18 }),
80
+ ),
81
+ React.createElement(Typography, {
82
+ variant: 'caption-thick',
83
+ color: 'color-text-high',
84
+ style: { flex: 1, minWidth: 0 },
85
+ }, name),
86
+ onEdit && React.createElement(IconButton, {
87
+ icon: 'edit', size: 'xs', variant: 'clear',
88
+ onClick: () => onEdit(id),
89
+ title: 'Edit profile',
90
+ }),
91
+ onDelete && React.createElement(IconButton, {
92
+ icon: 'delete', size: 'xs', variant: 'clear', color: 'danger',
93
+ onClick: () => onDelete(id),
94
+ title: 'Delete profile',
95
+ }),
96
+ ),
97
+
98
+ // Description
99
+ description && React.createElement(Typography, {
100
+ variant: 'smallCaption-regular',
101
+ color: 'color-text-medium',
102
+ }, description),
103
+
104
+ // Divider
105
+ React.createElement(Flex, {
106
+ variant: 'row-center-start-nowrap-0',
107
+ style: { borderTop: '1px solid var(--color-border-default)', margin: '2px 0' },
108
+ }),
109
+
110
+ // Capabilities
111
+ capabilities.length > 0 && React.createElement(Flex, { variant: 'row-center-start-wrap-4' },
112
+ React.createElement(Typography, {
113
+ variant: 'smallCaption-regular',
114
+ color: 'color-text-subtle',
115
+ style: { flexShrink: 0 },
116
+ }, 'Capabilities:'),
117
+ ...capabilities.map((cap: Capability) =>
118
+ React.createElement('span', { key: cap.name, title: cap.description },
119
+ React.createElement(Chip, { label: cap.name, size: 'small', color: 'color-brand-main' }),
120
+ ),
121
+ ),
122
+ ),
123
+
124
+ // Cost strategy
125
+ React.createElement(Flex, { variant: 'row-center-start-wrap-12' },
126
+ React.createElement(Typography, {
127
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
128
+ }, `Cost strategy: ${preferences.costStrategy}`),
129
+ ),
130
+
131
+ // Instances + Approval + Budget
132
+ React.createElement(Flex, { variant: 'row-center-start-wrap-12' },
133
+ React.createElement(Typography, {
134
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
135
+ }, `Instances: ${activeInstances}/${maxInstances} active`),
136
+ React.createElement(Tag, {
137
+ size: 'small',
138
+ color: preferences.requireApproval ? 'caution' : 'positive',
139
+ }, preferences.requireApproval ? 'Approval required' : 'Auto-approve'),
140
+ ),
141
+
142
+ // Budget line
143
+ budgetText && React.createElement(Typography, {
144
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
145
+ }, `Budget: ${budgetText}`),
146
+
147
+ // Instructions
148
+ preferences.instructions && React.createElement(Typography, {
149
+ variant: 'smallCaption-regular', color: 'color-text-subtle',
150
+ style: { fontStyle: 'italic' },
151
+ }, preferences.instructions),
152
+ );
153
+ }
154
+
155
+ export { ProfileCard };
156
+ export default ProfileCard;
157
+ module.exports = ProfileCard;