@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,1015 +0,0 @@
1
- "use strict";
2
-
3
- // src/ui/session-bar.tsx
4
- var React = require("react");
5
- var { useState, useEffect, useCallback, useRef } = React;
6
- var { Flex, Typography, Icon, Button, Badge, toast, formatDuration, formatCost } = require("@fw/plugin-ui-kit");
7
- function SessionBar({ callTool, dispatchEvent }) {
8
- const [session, setSession] = useState(null);
9
- const [elapsed, setElapsed] = useState(0);
10
- const [starting, setStarting] = useState(false);
11
- const [stopping, setStopping] = useState(false);
12
- const [pausing, setPausing] = useState(false);
13
- const prevActiveRef = useRef(false);
14
- const pollStatus = useCallback(async () => {
15
- try {
16
- const result = await callTool("fw_weaver_session", { action: "status" });
17
- const isActive2 = result.status !== "no active session" && result.status !== "idle";
18
- setSession(isActive2 ? result : null);
19
- if (prevActiveRef.current && !isActive2) {
20
- dispatchEvent("fw:refresh-bot-workspace");
21
- }
22
- prevActiveRef.current = isActive2;
23
- } catch {
24
- }
25
- }, [callTool, dispatchEvent]);
26
- useEffect(() => {
27
- pollStatus();
28
- const interval = setInterval(pollStatus, 5e3);
29
- return () => clearInterval(interval);
30
- }, [pollStatus]);
31
- useEffect(() => {
32
- if (!session?.startedAt || session.status === "idle") return;
33
- const tick = () => setElapsed(Date.now() - (session.startedAt ?? Date.now()));
34
- tick();
35
- const interval = setInterval(tick, 1e3);
36
- return () => clearInterval(interval);
37
- }, [session?.startedAt, session?.status]);
38
- const [startError, setStartError] = useState(null);
39
- const handleStart = useCallback(async () => {
40
- setStarting(true);
41
- setStartError(null);
42
- try {
43
- const result = await callTool("fw_weaver_session", { action: "start" });
44
- const data = result;
45
- if (data?.error) {
46
- setStartError(data.error);
47
- toast(data.error, { type: "error" });
48
- setStarting(false);
49
- return;
50
- }
51
- toast("Session started", { type: "success" });
52
- dispatchEvent("fw:refresh-bot-workspace");
53
- await pollStatus();
54
- } catch (err) {
55
- const msg = err instanceof Error ? err.message : "Failed to start session";
56
- setStartError(msg);
57
- toast(msg, { type: "error" });
58
- }
59
- setStarting(false);
60
- }, [callTool, pollStatus, dispatchEvent]);
61
- const handleStop = useCallback(async () => {
62
- setStopping(true);
63
- try {
64
- await callTool("fw_weaver_session", { action: "stop" });
65
- toast("Session ended", { type: "info" });
66
- await pollStatus();
67
- } catch (err) {
68
- toast(err instanceof Error ? err.message : "Failed to stop session", { type: "error" });
69
- }
70
- setStopping(false);
71
- }, [callTool, pollStatus]);
72
- const handlePause = useCallback(async () => {
73
- setPausing(true);
74
- try {
75
- await callTool("fw_weaver_steer", { command: "pause" });
76
- toast("Session paused", { type: "info" });
77
- } catch (err) {
78
- toast(err instanceof Error ? err.message : "Failed to pause session", { type: "error" });
79
- }
80
- setPausing(false);
81
- }, [callTool]);
82
- const isActive = session && session.status !== "idle" && session.status !== "no active session";
83
- if (!isActive) {
84
- return React.createElement(
85
- Flex,
86
- {
87
- variant: "row-center-space-between-nowrap-10",
88
- style: { flexShrink: 0, padding: "8px 16px", backgroundColor: "transparent", borderBottom: "1px solid var(--color-border-default)" }
89
- },
90
- React.createElement(Icon, { name: "smartToy", size: 14, color: "color-text-subtle" }),
91
- React.createElement(
92
- Flex,
93
- { variant: "row-center-start-nowrap-12", style: { flex: 1, fontSize: "12px" } },
94
- React.createElement(Typography, {
95
- variant: "caption-regular",
96
- color: startError ? "color-status-negative" : "color-text-subtle"
97
- }, startError ?? "No active session")
98
- ),
99
- React.createElement(
100
- Flex,
101
- { variant: "row-center-start-nowrap-6", style: { flexShrink: 0 } },
102
- React.createElement(Button, {
103
- size: "sm",
104
- variant: "clear",
105
- onClick: handleStart,
106
- loading: starting,
107
- disabled: starting
108
- }, "Start Session")
109
- )
110
- );
111
- }
112
- return React.createElement(
113
- Flex,
114
- {
115
- variant: "row-center-space-between-nowrap-10",
116
- style: { flexShrink: 0, padding: "8px 16px", backgroundColor: "var(--color-brand-main-alpha-10)", borderBottom: "1px solid var(--color-brand-main)" }
117
- },
118
- React.createElement(Badge, { variant: "success" }, "Session"),
119
- React.createElement(
120
- Flex,
121
- {
122
- variant: "row-center-start-nowrap-12",
123
- style: { flex: 1, fontSize: "12px", color: "var(--color-text-medium)" }
124
- },
125
- session.completedTasks != null && React.createElement("span", null, `${session.completedTasks} tasks done`),
126
- session.totalCost != null && session.totalCost > 0 && React.createElement("span", null, formatCost(session.totalCost)),
127
- session.startedAt && React.createElement("span", null, `${formatDuration(elapsed)} elapsed`),
128
- session.currentTask && React.createElement("span", { style: { opacity: 0.7 } }, `\xB7 ${session.currentTask}`)
129
- ),
130
- React.createElement(
131
- Flex,
132
- { variant: "row-center-start-nowrap-6", style: { flexShrink: 0 } },
133
- React.createElement(Button, {
134
- size: "sm",
135
- variant: "clear",
136
- onClick: handlePause,
137
- loading: pausing,
138
- disabled: pausing || stopping
139
- }, "Pause"),
140
- React.createElement(Button, {
141
- size: "sm",
142
- variant: "clear",
143
- color: "danger",
144
- onClick: handleStop,
145
- loading: stopping,
146
- disabled: stopping || pausing
147
- }, "End")
148
- )
149
- );
150
- }
151
-
152
- // src/ui/settings-section.tsx
153
- var React2 = require("react");
154
- var { useState: useState2, useEffect: useEffect2, useCallback: useCallback2 } = React2;
155
- var { Flex: Flex2, Typography: Typography2, Button: Button2, CollapsibleSection, KeyValueRow, toast: toast2 } = require("@fw/plugin-ui-kit");
156
- function SettingsSection({ callTool, dispatchEvent }) {
157
- const [providers, setProviders] = useState2([]);
158
- const [insights, setInsights] = useState2(null);
159
- const handleClear = useCallback2(() => {
160
- if (!confirm("Clear all bot run history? This action cannot be undone.")) return;
161
- callTool("fw_weaver_history", { clear: true }).then(() => {
162
- dispatchEvent("fw:refresh-bot-workspace");
163
- toast2("Run history cleared", { type: "success" });
164
- }).catch(() => {
165
- toast2("Failed to clear history", { type: "error" });
166
- });
167
- }, [callTool, dispatchEvent]);
168
- useEffect2(() => {
169
- Promise.all([
170
- callTool("fw_weaver_providers"),
171
- callTool("fw_weaver_insights")
172
- ]).then(([prov, ins]) => {
173
- if (prov) setProviders(Array.isArray(prov) ? prov : []);
174
- if (ins) setInsights(ins);
175
- });
176
- }, [callTool]);
177
- const activeProvider = providers.find((p) => p.envVarsSet) ?? providers[0];
178
- const trustScore = insights?.trust?.score;
179
- const trustDisplay = trustScore != null ? (trustScore <= 1 ? (trustScore * 100).toFixed(0) : Math.round(trustScore)) + "%" : "\u2014";
180
- return React2.createElement(
181
- CollapsibleSection,
182
- {
183
- title: "Settings",
184
- variant: "list",
185
- defaultExpanded: false
186
- },
187
- React2.createElement(
188
- Flex2,
189
- { variant: "column-start-start-nowrap-4", style: { width: "100%" } },
190
- activeProvider && React2.createElement(KeyValueRow, {
191
- keyName: "Provider",
192
- value: `${activeProvider.name} (${activeProvider.source})`,
193
- size: "small"
194
- }),
195
- insights?.trust && React2.createElement(KeyValueRow, {
196
- keyName: "Trust",
197
- value: `Phase ${insights.trust.phase} \xB7 ${trustDisplay}`,
198
- size: "small"
199
- }),
200
- insights?.health && React2.createElement(KeyValueRow, {
201
- keyName: "Health",
202
- value: `${insights.health.overall}/100`,
203
- size: "small"
204
- }),
205
- insights?.cost && React2.createElement(KeyValueRow, {
206
- keyName: "Cost (7d)",
207
- value: `$${insights.cost.last7Days?.toFixed(2) ?? "0.00"} \xB7 ${insights.cost.trend ?? "stable"}`,
208
- size: "small"
209
- }),
210
- React2.createElement(
211
- Flex2,
212
- {
213
- variant: "row-center-space-between-nowrap-8",
214
- style: { width: "100%", marginTop: "4px" }
215
- },
216
- React2.createElement(Button2, {
217
- size: "xs",
218
- variant: "outlined",
219
- color: "danger",
220
- onClick: handleClear
221
- }, "Clear Run History"),
222
- React2.createElement(Typography2, {
223
- variant: "smallCaption-regular",
224
- color: "color-text-subtle"
225
- }, "Edit settings in .weaver.json")
226
- )
227
- )
228
- );
229
- }
230
-
231
- // src/ui/queue-input.tsx
232
- var React3 = require("react");
233
- var { useState: useState3, useCallback: useCallback3 } = React3;
234
- var { Flex: Flex3, IconButton, Input, toast: toast3 } = require("@fw/plugin-ui-kit");
235
- function QueueInput({ callTool, onTaskAdded }) {
236
- const [newTask, setNewTask] = useState3("");
237
- const [adding, setAdding] = useState3(false);
238
- const handleAdd = useCallback3(async () => {
239
- const instruction = newTask.trim();
240
- if (!instruction) return;
241
- setAdding(true);
242
- try {
243
- await callTool("fw_weaver_queue", { action: "add", task: instruction });
244
- setNewTask("");
245
- onTaskAdded?.();
246
- toast3("Task added to queue", { type: "success" });
247
- } catch (err) {
248
- toast3(err instanceof Error ? err.message : "Failed to add task", { type: "error" });
249
- }
250
- setAdding(false);
251
- }, [callTool, newTask, onTaskAdded]);
252
- return React3.createElement(
253
- Flex3,
254
- {
255
- variant: "row-center-start-nowrap-6",
256
- style: {
257
- flexShrink: 0,
258
- padding: "8px 16px",
259
- borderTop: "1px solid var(--color-border-default)",
260
- width: "100%",
261
- boxSizing: "border-box"
262
- }
263
- },
264
- React3.createElement(Input, {
265
- type: "text",
266
- size: "medium",
267
- placeholder: "Add a task...",
268
- value: newTask,
269
- onChange: setNewTask,
270
- onEnter: handleAdd,
271
- disabled: adding,
272
- defaultBoxStyle: { flex: 1, minWidth: 0 },
273
- inputBoxStyle: { maxWidth: "none" }
274
- }),
275
- React3.createElement(IconButton, {
276
- icon: "add",
277
- size: "md",
278
- variant: "fill",
279
- color: "primary",
280
- "aria-label": "Add task",
281
- onClick: handleAdd,
282
- loading: adding,
283
- disabled: adding || !newTask.trim()
284
- })
285
- );
286
- }
287
-
288
- // src/ui/genesis-block.tsx
289
- var React4 = require("react");
290
- var { useState: useState4, useCallback: useCallback4 } = React4;
291
- var { CollapsibleBlock, Flex: Flex4, Typography: Typography3, Icon: Icon2, Badge: Badge2, Tag, Button: Button3, toast: toast4, formatTimestamp } = require("@fw/plugin-ui-kit");
292
- var OUTCOME_BADGE_VARIANTS = {
293
- applied: "success",
294
- "rolled-back": "error",
295
- rejected: "warning",
296
- stabilized: "success",
297
- "no-change": "default",
298
- error: "error"
299
- };
300
- var OUTCOME_STATUS = {
301
- applied: "completed",
302
- stabilized: "completed",
303
- "rolled-back": "error",
304
- rejected: "error",
305
- error: "error",
306
- "no-change": "completed"
307
- };
308
- function GenesisBlock({ cycle, callTool }) {
309
- const [expanded, setExpanded] = useState4(false);
310
- const [rollingBack, setRollingBack] = useState4(false);
311
- const handleRollback = useCallback4(async () => {
312
- setRollingBack(true);
313
- try {
314
- await callTool("fw_weaver_genesis_rollback", { cycleId: cycle.id });
315
- toast4("Genesis cycle rolled back", { type: "success" });
316
- } catch (err) {
317
- toast4(err instanceof Error ? err.message : "Failed to rollback", { type: "error" });
318
- }
319
- setRollingBack(false);
320
- }, [callTool, cycle.id]);
321
- const summary = cycle.proposal?.summary ?? `Genesis cycle ${cycle.id.slice(0, 8)}`;
322
- const badgeVariant = OUTCOME_BADGE_VARIANTS[cycle.outcome] ?? "default";
323
- const status = OUTCOME_STATUS[cycle.outcome] ?? "pending";
324
- return React4.createElement(
325
- CollapsibleBlock,
326
- {
327
- status,
328
- icon: React4.createElement(Icon2, { name: "autorenew", size: 14, color: "color-brand-main" }),
329
- label: React4.createElement(Typography3, {
330
- variant: "caption-thick",
331
- color: "color-text-high",
332
- style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 }
333
- }, summary),
334
- headerSuffix: React4.createElement(
335
- Flex4,
336
- { variant: "row-center-start-nowrap-8" },
337
- React4.createElement(Typography3, { variant: "smallCaption-regular", color: "color-text-subtle" }, formatTimestamp(cycle.timestamp)),
338
- React4.createElement(Badge2, { variant: badgeVariant }, cycle.outcome)
339
- ),
340
- expanded,
341
- onToggle: () => setExpanded((v) => !v)
342
- },
343
- // Proposal
344
- cycle.proposal && React4.createElement(
345
- Flex4,
346
- {
347
- variant: "column-start-start-nowrap-6",
348
- style: { padding: "10px 12px", borderBottom: "1px solid var(--color-border-default)" }
349
- },
350
- React4.createElement(
351
- Typography3,
352
- { variant: "caption-bold", color: "color-text-subtle" },
353
- `Proposal \xB7 ${cycle.proposal.impactLevel}`
354
- ),
355
- React4.createElement(
356
- Typography3,
357
- { variant: "smallCaption-regular", color: "color-text-medium" },
358
- cycle.proposal.rationale
359
- ),
360
- ...cycle.proposal.operations.map(
361
- (op, i) => React4.createElement(
362
- Flex4,
363
- { key: i, variant: "row-center-start-nowrap-6", style: { fontSize: "11px" } },
364
- React4.createElement(Tag, { size: "small", color: "info" }, op.type),
365
- React4.createElement(Typography3, { variant: "smallCaption-regular", color: "color-text-medium" }, op.rationale)
366
- )
367
- )
368
- ),
369
- // Diff
370
- cycle.diffSummary && React4.createElement(
371
- Flex4,
372
- {
373
- variant: "column-start-start-nowrap-6",
374
- style: { padding: "10px 12px", borderBottom: "1px solid var(--color-border-default)" }
375
- },
376
- React4.createElement(Typography3, { variant: "caption-bold", color: "color-text-subtle" }, "Changes"),
377
- React4.createElement("pre", {
378
- style: {
379
- fontSize: "11px",
380
- fontFamily: "monospace",
381
- lineHeight: 1.4,
382
- padding: "8px",
383
- borderRadius: "var(--border-radius-compact, 4px)",
384
- backgroundColor: "var(--color-surface-raised)",
385
- color: "var(--color-text-medium)",
386
- whiteSpace: "pre-wrap",
387
- wordBreak: "break-word",
388
- maxHeight: "200px",
389
- overflow: "auto",
390
- margin: 0,
391
- width: "100%"
392
- }
393
- }, cycle.diffSummary)
394
- ),
395
- // Error
396
- cycle.error && React4.createElement("div", {
397
- style: { padding: "10px 12px", borderBottom: "1px solid var(--color-border-default)" }
398
- }, React4.createElement(Typography3, { variant: "smallCaption-regular", color: "color-status-negative" }, cycle.error)),
399
- // Rollback action
400
- cycle.outcome === "applied" && React4.createElement(
401
- Flex4,
402
- {
403
- variant: "row-center-start-nowrap-8",
404
- style: { padding: "10px 12px" }
405
- },
406
- React4.createElement(Button3, {
407
- size: "xs",
408
- variant: "outlined",
409
- color: "danger",
410
- onClick: handleRollback,
411
- loading: rollingBack,
412
- disabled: rollingBack
413
- }, "Rollback")
414
- )
415
- );
416
- }
417
-
418
- // src/ui/use-stream-timeline.ts
419
- var React5 = require("react");
420
- var { useMemo, useState: useState5, useEffect: useEffect3, useRef: useRef2 } = React5;
421
- function useStreamTimeline(events, isDone) {
422
- const [elapsed, setElapsed] = useState5(0);
423
- const startTimeRef = useRef2(null);
424
- useEffect3(() => {
425
- if (events.length === 0) {
426
- startTimeRef.current = null;
427
- setElapsed(0);
428
- } else if (startTimeRef.current === null) {
429
- startTimeRef.current = events[0].timestamp;
430
- }
431
- }, [events.length]);
432
- useEffect3(() => {
433
- if (isDone || !startTimeRef.current) return;
434
- const tick = () => setElapsed(Date.now() - (startTimeRef.current ?? Date.now()));
435
- tick();
436
- const interval = setInterval(tick, 1e3);
437
- return () => clearInterval(interval);
438
- }, [isDone, events.length]);
439
- const timeline = useMemo(() => {
440
- const entries = [];
441
- const nodeEntryIndex = /* @__PURE__ */ new Map();
442
- const nodeStarts = /* @__PURE__ */ new Map();
443
- let idCounter = 0;
444
- for (const event of events) {
445
- const d = event.data ?? {};
446
- switch (event.type) {
447
- case "bot-started":
448
- entries.push({
449
- id: `s-${idCounter++}`,
450
- timestamp: new Date(event.timestamp),
451
- type: "task-started",
452
- label: "Task started",
453
- detail: d.instruction
454
- });
455
- break;
456
- case "node-start": {
457
- const nodeId = d.nodeId;
458
- if (nodeId) nodeStarts.set(nodeId, event.timestamp);
459
- const idx = entries.length;
460
- nodeEntryIndex.set(nodeId, idx);
461
- entries.push({
462
- id: `s-${idCounter++}`,
463
- timestamp: new Date(event.timestamp),
464
- type: "node-started",
465
- nodeId,
466
- label: d.label ?? d.nodeType ?? nodeId ?? "Node"
467
- });
468
- break;
469
- }
470
- case "node-complete": {
471
- const nodeId = d.nodeId;
472
- const startTs = nodeStarts.get(nodeId);
473
- const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : void 0);
474
- if (nodeId) nodeStarts.delete(nodeId);
475
- const rawOutputs = d.outputs;
476
- const completed = {
477
- id: `s-${idCounter++}`,
478
- timestamp: new Date(startTs ?? event.timestamp),
479
- type: "node-completed",
480
- nodeId,
481
- label: d.label ?? d.nodeType ?? nodeId ?? "Node",
482
- duration,
483
- outputs: rawOutputs && rawOutputs.length > 0 ? rawOutputs : void 0
484
- };
485
- const existingIdx = nodeEntryIndex.get(nodeId);
486
- if (existingIdx != null && entries[existingIdx]) {
487
- entries[existingIdx] = completed;
488
- nodeEntryIndex.delete(nodeId);
489
- } else {
490
- entries.push(completed);
491
- }
492
- break;
493
- }
494
- case "node-error": {
495
- const nodeId = d.nodeId;
496
- const startTs = nodeStarts.get(nodeId);
497
- const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : void 0);
498
- if (nodeId) nodeStarts.delete(nodeId);
499
- const rawOutputs = d.outputs;
500
- const failed = {
501
- id: `s-${idCounter++}`,
502
- timestamp: new Date(startTs ?? event.timestamp),
503
- type: "node-failed",
504
- nodeId,
505
- label: d.label ?? d.nodeType ?? nodeId ?? "Node",
506
- detail: d.error,
507
- duration,
508
- outputs: rawOutputs && rawOutputs.length > 0 ? rawOutputs : void 0
509
- };
510
- const existingIdx = nodeEntryIndex.get(nodeId);
511
- if (existingIdx != null && entries[existingIdx]) {
512
- entries[existingIdx] = failed;
513
- nodeEntryIndex.delete(nodeId);
514
- } else {
515
- entries.push(failed);
516
- }
517
- break;
518
- }
519
- case "bot-completed":
520
- entries.push({
521
- id: `s-${idCounter++}`,
522
- timestamp: new Date(event.timestamp),
523
- type: "task-completed",
524
- label: d.success ? "Task completed" : "Task finished",
525
- detail: d.summary
526
- });
527
- break;
528
- case "bot-failed":
529
- entries.push({
530
- id: `s-${idCounter++}`,
531
- timestamp: new Date(event.timestamp),
532
- type: "task-failed",
533
- label: "Task failed",
534
- detail: d.error
535
- });
536
- break;
537
- // Skip audit, cost-update, done — they're used for metadata, not timeline
538
- default:
539
- break;
540
- }
541
- }
542
- return entries;
543
- }, [events]);
544
- const { phase, instruction, cost, plan, awaitingApproval } = useMemo(() => {
545
- let phase2 = "idle";
546
- let instruction2 = null;
547
- let cost2 = null;
548
- let plan2 = null;
549
- let awaitingApproval2 = false;
550
- for (const event of events) {
551
- const d = event.data ?? {};
552
- if (event.type === "bot-started") {
553
- phase2 = "planning";
554
- instruction2 = d.instruction ?? null;
555
- } else if (event.type === "node-start" && phase2 !== "completed" && phase2 !== "failed") {
556
- phase2 = "executing";
557
- } else if (event.type === "bot-completed") {
558
- phase2 = d.success ? "completed" : "failed";
559
- } else if (event.type === "bot-failed") {
560
- phase2 = "failed";
561
- } else if (event.type === "cost-update") {
562
- cost2 = d.totalCost ?? cost2;
563
- } else if (event.type === "audit:plan-created" || event.type === "plan-created") {
564
- const planData = d.plan ?? d;
565
- const summary = planData.summary ?? "";
566
- const steps = planData.steps ?? [];
567
- if (summary || steps.length > 0) {
568
- plan2 = { summary, steps };
569
- }
570
- } else if (event.type === "approval-needed") {
571
- awaitingApproval2 = true;
572
- } else if (event.type === "audit:approval-decision") {
573
- awaitingApproval2 = false;
574
- }
575
- }
576
- if (isDone && phase2 !== "completed" && phase2 !== "failed") {
577
- phase2 = "completed";
578
- }
579
- return { phase: phase2, instruction: instruction2, cost: cost2, plan: plan2, awaitingApproval: awaitingApproval2 };
580
- }, [events, isDone]);
581
- return { timeline, phase, instruction, elapsed, cost, plan, awaitingApproval };
582
- }
583
-
584
- // src/ui/trace-to-timeline.ts
585
- function traceToTimeline(run) {
586
- const entries = [];
587
- let idCounter = 0;
588
- const meta = run.nodeMeta ?? {};
589
- if (run.trace && run.trace.length > 0) {
590
- const nodeStarts = /* @__PURE__ */ new Map();
591
- for (const event of run.trace) {
592
- if (event.type === "node-start") {
593
- nodeStarts.set(event.nodeId, event);
594
- } else if (event.type === "node-complete" || event.type === "node-error") {
595
- const start = nodeStarts.get(event.nodeId);
596
- const duration = event.durationMs ?? (start ? event.timestamp - start.timestamp : void 0);
597
- const nm = meta[event.nodeId] ?? (event.nodeType ? meta[event.nodeType] : void 0);
598
- entries.push({
599
- id: `trace-${idCounter++}`,
600
- timestamp: new Date(event.timestamp),
601
- type: event.type === "node-complete" ? "node-completed" : "node-failed",
602
- nodeId: event.nodeId,
603
- label: nm?.label ?? event.nodeType ?? event.nodeId,
604
- detail: event.error,
605
- duration,
606
- color: nm?.color,
607
- icon: nm?.icon,
608
- outputs: event.outputs && event.outputs.length > 0 ? event.outputs : void 0
609
- });
610
- nodeStarts.delete(event.nodeId);
611
- }
612
- }
613
- for (const [nodeId, event] of nodeStarts) {
614
- const nm = meta[nodeId] ?? (event.nodeType ? meta[event.nodeType] : void 0);
615
- entries.push({
616
- id: `trace-${idCounter++}`,
617
- timestamp: new Date(event.timestamp),
618
- type: "node-started",
619
- nodeId,
620
- label: nm?.label ?? event.nodeType ?? nodeId,
621
- color: nm?.color,
622
- icon: nm?.icon
623
- });
624
- }
625
- } else if (run.stepLog && run.stepLog.length > 0) {
626
- for (const step of run.stepLog) {
627
- const type = step.status === "ok" ? "node-completed" : step.status === "error" ? "node-failed" : "node-completed";
628
- entries.push({
629
- id: `step-${idCounter++}`,
630
- timestamp: new Date(run.startedAt ?? Date.now()),
631
- type,
632
- label: step.step,
633
- detail: step.detail,
634
- icon: step.status === "ok" ? "success" : step.status === "error" ? "error" : "warning"
635
- });
636
- }
637
- }
638
- if (run.outcome === "failed" || run.outcome === "error") {
639
- let errorDetail = "";
640
- if (run.auditTrail) {
641
- for (const a of run.auditTrail) {
642
- if (a.type === "step-complete" && a.data) {
643
- const errors = a.data.errors;
644
- if (errors && errors.length > 0) {
645
- errorDetail = errors.map((e) => e.length > 120 ? e.slice(0, 117) + "..." : e).join("\n");
646
- break;
647
- }
648
- }
649
- }
650
- }
651
- if (!errorDetail && run.summary) {
652
- const parts = run.summary.split("|").map((p) => p.trim());
653
- const outcomePart = parts.find((p) => p.startsWith("Outcome:"));
654
- const summaryPart = parts.find((p) => p.startsWith("Summary:"));
655
- errorDetail = summaryPart?.replace("Summary:", "").trim() ?? outcomePart ?? run.summary;
656
- }
657
- entries.push({
658
- id: `result-${idCounter++}`,
659
- timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
660
- type: "task-failed",
661
- label: "Task failed",
662
- detail: errorDetail || "Unknown failure",
663
- icon: "error"
664
- });
665
- } else if (run.outcome === "completed" && run.success) {
666
- entries.push({
667
- id: `result-${idCounter++}`,
668
- timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
669
- type: "task-completed",
670
- label: "Task completed",
671
- detail: run.summary?.includes("|") ? run.summary.split("|").find((p) => p.trim().startsWith("Summary:"))?.replace("Summary:", "").trim() : void 0
672
- });
673
- }
674
- entries.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
675
- return entries;
676
- }
677
-
678
- // src/ui/steer-api.ts
679
- async function sendSteerCommand(callTool, command, payload) {
680
- await callTool("fw_weaver_steer", {
681
- command,
682
- ...payload ? { payload } : {}
683
- });
684
- }
685
-
686
- // src/ui/bot-workspace.tsx
687
- var React6 = require("react");
688
- var { useRef: useRef3, useEffect: useEffect4, useState: useState6, useCallback: useCallback5, useMemo: useMemo2 } = React6;
689
- var {
690
- Flex: Flex5,
691
- ScrollArea,
692
- EmptyState,
693
- TaskBlock,
694
- toast: toast5,
695
- usePackWorkspace,
696
- useEventStream
697
- } = require("@fw/plugin-ui-kit");
698
- function BotWorkspace() {
699
- const ctx = usePackWorkspace();
700
- const { callTool, windowData, dispatchEvent, onRefresh } = ctx;
701
- const packId = ctx.packId;
702
- const isLive = windowData?.live === true && !!windowData?.runId;
703
- const highlightRunId = windowData?.runId;
704
- const stream = useEventStream();
705
- const {
706
- timeline: liveTimeline,
707
- phase: livePhase,
708
- instruction: liveInstruction,
709
- elapsed,
710
- cost,
711
- plan,
712
- awaitingApproval
713
- } = useStreamTimeline(stream.events, stream.isDone);
714
- useEffect4(() => {
715
- if (!isLive || !windowData?.runId) return;
716
- stream.start(packId, "fw_weaver_events", windowData.runId);
717
- return () => stream.stop();
718
- }, [isLive, packId, windowData?.runId]);
719
- const [sessionRunId, setSessionRunId] = useState6(null);
720
- useEffect4(() => {
721
- if (isLive) return;
722
- const poll = async () => {
723
- try {
724
- const status = await callTool("fw_weaver_status");
725
- const runId = status?.currentRunId ?? null;
726
- const alive = status?.alive;
727
- if (runId && alive === false) {
728
- setSessionRunId(null);
729
- } else {
730
- setSessionRunId(runId);
731
- }
732
- } catch {
733
- }
734
- };
735
- poll();
736
- const interval = setInterval(poll, 3e3);
737
- return () => clearInterval(interval);
738
- }, [isLive, callTool]);
739
- useEffect4(() => {
740
- if (!sessionRunId || isLive) return;
741
- stream.start(packId, "fw_weaver_events", sessionRunId);
742
- return () => stream.stop();
743
- }, [sessionRunId, packId, isLive]);
744
- const scrollRef = useRef3(null);
745
- useEffect4(() => {
746
- const el = scrollRef.current;
747
- if (el) el.scrollTop = el.scrollHeight;
748
- }, [liveTimeline.length, stream.events.length]);
749
- const [pausing, setPausing] = useState6(false);
750
- const [stopping, setStopping] = useState6(false);
751
- const handlePause = useCallback5(async () => {
752
- setPausing(true);
753
- try {
754
- await sendSteerCommand(callTool, "pause");
755
- toast5("Pause signal sent", { type: "info" });
756
- } catch (err) {
757
- toast5(err instanceof Error ? err.message : "Failed to pause", { type: "error" });
758
- }
759
- setPausing(false);
760
- }, [callTool]);
761
- const handleStop = useCallback5(async () => {
762
- setStopping(true);
763
- try {
764
- await sendSteerCommand(callTool, "cancel");
765
- toast5("Stopping \u2014 will take effect after current node completes", { type: "info" });
766
- } catch (err) {
767
- toast5(err instanceof Error ? err.message : "Failed to stop", { type: "error" });
768
- setStopping(false);
769
- }
770
- }, [callTool]);
771
- const [history, setHistory] = useState6([]);
772
- const [genesisCycles, setGenesisCycles] = useState6([]);
773
- const [queuedTasks, setQueuedTasks] = useState6([]);
774
- const [removingIds, setRemovingIds] = useState6(/* @__PURE__ */ new Set());
775
- const [expandedRunId, setExpandedRunId] = useState6(
776
- highlightRunId && !isLive ? highlightRunId : null
777
- );
778
- const [liveExpanded, setLiveExpanded] = useState6(true);
779
- const refreshData = useCallback5(() => {
780
- callTool("fw_weaver_history", { limit: 20 }).then((data) => {
781
- if (Array.isArray(data)) {
782
- setHistory(
783
- data.map((r) => {
784
- const costObj = r.cost && typeof r.cost === "object" ? r.cost : void 0;
785
- return { ...r, costDetail: costObj, cost: costObj?.totalCost };
786
- })
787
- );
788
- } else {
789
- setHistory([]);
790
- }
791
- });
792
- callTool("fw_weaver_insights").then((data) => {
793
- const d = data;
794
- if (d?.evolution) {
795
- const evo = d.evolution;
796
- if (Array.isArray(evo.recentCycles)) {
797
- setGenesisCycles(evo.recentCycles.slice(0, 10));
798
- }
799
- }
800
- });
801
- callTool("fw_weaver_queue", { action: "list" }).then((data) => {
802
- const visible = (Array.isArray(data) ? data : []).filter(
803
- (t) => t.status === "pending" || t.status === "running"
804
- );
805
- setQueuedTasks(visible);
806
- });
807
- }, [callTool]);
808
- useEffect4(() => {
809
- refreshData();
810
- }, [refreshData]);
811
- useEffect4(() => {
812
- const interval = setInterval(() => {
813
- callTool("fw_weaver_queue", { action: "list" }).then((data) => {
814
- const visible = (Array.isArray(data) ? data : []).filter(
815
- (t) => t.status === "pending" || t.status === "running"
816
- );
817
- setQueuedTasks(visible);
818
- });
819
- }, 1e4);
820
- return () => clearInterval(interval);
821
- }, [callTool]);
822
- useEffect4(() => {
823
- return onRefresh(() => refreshData());
824
- }, [refreshData, onRefresh]);
825
- useEffect4(() => {
826
- if (sessionRunId !== null) refreshData();
827
- }, [sessionRunId, refreshData]);
828
- const handleRemoveTask = useCallback5(async (id) => {
829
- setRemovingIds((prev) => new Set(prev).add(id));
830
- try {
831
- await callTool("fw_weaver_queue", { action: "remove", id });
832
- refreshData();
833
- toast5("Task removed", { type: "warning" });
834
- } catch (err) {
835
- toast5(err instanceof Error ? err.message : "Failed to remove task", { type: "error" });
836
- }
837
- setRemovingIds((prev) => {
838
- const next = new Set(prev);
839
- next.delete(id);
840
- return next;
841
- });
842
- }, [callTool, refreshData]);
843
- const timelineItems = useMemo2(() => {
844
- const items = [];
845
- for (const run of history) {
846
- items.push({ kind: "run", timestamp: new Date(run.startedAt ?? 0).getTime(), run, runTimeline: traceToTimeline(run) });
847
- }
848
- for (const cycle of genesisCycles) {
849
- items.push({ kind: "genesis", timestamp: new Date(cycle.timestamp).getTime(), genesis: cycle });
850
- }
851
- items.sort((a, b) => a.timestamp - b.timestamp);
852
- return items;
853
- }, [history, genesisCycles]);
854
- const toggleExpand = useCallback5((id) => {
855
- setExpandedRunId((prev) => prev === id ? null : id);
856
- }, []);
857
- const isStreaming = isLive || !!sessionRunId;
858
- const hasContent = isStreaming || timelineItems.length > 0 || queuedTasks.length > 0;
859
- function extractInstruction(run) {
860
- let text = "";
861
- if (run.params) {
862
- try {
863
- const taskJson = run.params.taskJson;
864
- if (taskJson) {
865
- const task = JSON.parse(taskJson);
866
- if (task.instruction) text = task.instruction;
867
- }
868
- } catch {
869
- }
870
- }
871
- if (!text && run.summary) {
872
- const summary = run.summary;
873
- if (summary.includes("|")) {
874
- const parts = summary.split("|").map((p) => p.trim());
875
- const taskPart = parts.find((p) => p.startsWith("Task:"));
876
- const summaryPart = parts.find((p) => p.startsWith("Summary:"));
877
- text = taskPart?.replace("Task:", "").trim() ?? summaryPart?.replace("Summary:", "").trim() ?? parts[0] ?? "";
878
- } else {
879
- text = summary;
880
- }
881
- }
882
- if (!text) {
883
- const wf = run.workflowFile;
884
- if (wf) {
885
- const parts = wf.split("/");
886
- text = parts[parts.length - 1] ?? "Bot run";
887
- } else {
888
- text = "Bot run";
889
- }
890
- }
891
- if (text.length > 120) text = text.slice(0, 117) + "...";
892
- return text;
893
- }
894
- const [approvalStatus, setApprovalStatus] = useState6(null);
895
- const [approvalLoading, setApprovalLoading] = useState6(false);
896
- useEffect4(() => {
897
- if (awaitingApproval) setApprovalStatus("pending");
898
- }, [awaitingApproval]);
899
- useEffect4(() => {
900
- if (stream.events.length === 0) setApprovalStatus(null);
901
- }, [stream.events.length]);
902
- const handleApprove = useCallback5(async () => {
903
- setApprovalLoading(true);
904
- try {
905
- await callTool("fw_weaver_approve", { approved: true });
906
- setApprovalStatus("approved");
907
- toast5("Plan approved", { type: "success" });
908
- } catch (err) {
909
- toast5(err instanceof Error ? err.message : "Failed to approve", { type: "error" });
910
- }
911
- setApprovalLoading(false);
912
- }, [callTool]);
913
- const handleReject = useCallback5(async () => {
914
- setApprovalLoading(true);
915
- try {
916
- await callTool("fw_weaver_approve", { approved: false });
917
- setApprovalStatus("rejected");
918
- toast5("Plan rejected", { type: "info" });
919
- } catch (err) {
920
- toast5(err instanceof Error ? err.message : "Failed to reject", { type: "error" });
921
- }
922
- setApprovalLoading(false);
923
- }, [callTool]);
924
- return React6.createElement(
925
- Flex5,
926
- {
927
- variant: "column-stretch-start-nowrap-0",
928
- style: { width: "100%", height: "100%", overflow: "hidden" }
929
- },
930
- // Session bar
931
- React6.createElement(SessionBar, { callTool, dispatchEvent }),
932
- // Settings
933
- React6.createElement(SettingsSection, { callTool, dispatchEvent }),
934
- // Main scrollable timeline
935
- React6.createElement(
936
- Flex5,
937
- { variant: "column-stretch-start-nowrap-0", style: { flex: 1, minHeight: 0 } },
938
- React6.createElement(
939
- ScrollArea,
940
- { ref: scrollRef },
941
- React6.createElement(
942
- Flex5,
943
- { variant: "column-stretch-start-nowrap-8", style: { padding: "12px 16px" } },
944
- // Empty state
945
- !hasContent && React6.createElement(EmptyState, {
946
- icon: "smartToy",
947
- message: "No bot runs yet",
948
- description: "Ask the AI assistant to run a task, or add tasks below."
949
- }),
950
- ...timelineItems.map((item) => {
951
- if (item.kind === "genesis" && item.genesis) {
952
- return React6.createElement(GenesisBlock, {
953
- key: `genesis-${item.genesis.id}`,
954
- cycle: item.genesis,
955
- callTool
956
- });
957
- }
958
- if (item.kind === "run" && item.run) {
959
- const run = item.run;
960
- const runId = run.id;
961
- const isExpanded = expandedRunId === runId;
962
- const isSuccess = run.outcome === "completed" || run.success === true;
963
- return React6.createElement(TaskBlock, {
964
- key: `run-${runId}`,
965
- state: isSuccess ? "completed" : "failed",
966
- instruction: extractInstruction(run),
967
- timeline: item.runTimeline ?? [],
968
- cost: typeof run.cost === "number" ? run.cost : run.costDetail?.totalCost ?? null,
969
- plan: run.plan,
970
- startedAt: run.startedAt,
971
- durationMs: run.durationMs ?? run.duration,
972
- expanded: isExpanded,
973
- onToggleExpand: () => toggleExpand(runId)
974
- });
975
- }
976
- return null;
977
- }),
978
- // Live execution
979
- isStreaming && React6.createElement(TaskBlock, {
980
- state: "running",
981
- instruction: liveInstruction ?? windowData?.instruction ?? "Running...",
982
- timeline: liveTimeline,
983
- phase: livePhase,
984
- elapsed,
985
- cost,
986
- plan,
987
- error: stream.error,
988
- approval: approvalStatus ?? void 0,
989
- approvalLoading,
990
- onApprove: handleApprove,
991
- onReject: handleReject,
992
- onPause: handlePause,
993
- onStop: handleStop,
994
- pauseLoading: pausing,
995
- stopLoading: stopping,
996
- expanded: liveExpanded,
997
- onToggleExpand: () => setLiveExpanded((v) => !v)
998
- }),
999
- ...(isStreaming ? queuedTasks.filter((t) => t.status !== "running") : queuedTasks).map(
1000
- (task) => React6.createElement(TaskBlock, {
1001
- key: task.id,
1002
- state: "pending",
1003
- instruction: task.instruction,
1004
- onRemove: () => handleRemoveTask(task.id),
1005
- removeLoading: removingIds.has(task.id)
1006
- })
1007
- )
1008
- )
1009
- )
1010
- ),
1011
- // Input bar
1012
- React6.createElement(QueueInput, { callTool, onTaskAdded: refreshData })
1013
- );
1014
- }
1015
- module.exports = BotWorkspace;