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

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.
@@ -0,0 +1,388 @@
1
+ "use strict";
2
+
3
+ // src/ui/bot-panel.tsx
4
+ var React = require("react");
5
+ var { useState, useEffect, useCallback, useRef } = React;
6
+ var {
7
+ Flex,
8
+ Typography,
9
+ Button,
10
+ IconButton,
11
+ Icon,
12
+ Input,
13
+ EmptyState,
14
+ ScrollArea,
15
+ StatusIcon,
16
+ toast,
17
+ usePackWorkspace
18
+ } = require("@fw/plugin-ui-kit");
19
+ function parseToolResult(raw) {
20
+ if (typeof raw === "string") {
21
+ try {
22
+ return JSON.parse(raw);
23
+ } catch {
24
+ return raw;
25
+ }
26
+ }
27
+ return raw;
28
+ }
29
+ function validationIcon(state) {
30
+ switch (state) {
31
+ case "valid":
32
+ return { icon: "checkCircle", color: "var(--color-success)" };
33
+ case "invalid":
34
+ return { icon: "error", color: "var(--color-danger)" };
35
+ case "checking":
36
+ return { icon: "sync", color: "var(--color-warning)" };
37
+ default:
38
+ return { icon: "helpOutline", color: "var(--color-text-subtle)" };
39
+ }
40
+ }
41
+ function BotPanel() {
42
+ const ctx = usePackWorkspace();
43
+ const { callTool, dispatchEvent } = ctx;
44
+ const packId = ctx.packId;
45
+ const [bots, setBots] = useState([]);
46
+ const [loading, setLoading] = useState(true);
47
+ const [error, setError] = useState(null);
48
+ const [showRegForm, setShowRegForm] = useState(false);
49
+ const [regName, setRegName] = useState("");
50
+ const [regFilePath, setRegFilePath] = useState("");
51
+ const [regExport, setRegExport] = useState("");
52
+ const [registering, setRegistering] = useState(false);
53
+ const [confirmUnregId, setConfirmUnregId] = useState(null);
54
+ const [unregistering, setUnregistering] = useState(false);
55
+ const loadBots = useCallback(async () => {
56
+ try {
57
+ setError(null);
58
+ const raw = await callTool("fw_weaver_list_bots");
59
+ const parsed = parseToolResult(raw);
60
+ if (Array.isArray(parsed)) {
61
+ setBots(parsed);
62
+ } else {
63
+ setBots([]);
64
+ }
65
+ } catch (err) {
66
+ const msg = err instanceof Error ? err.message : "Failed to load bots";
67
+ setError(msg);
68
+ } finally {
69
+ setLoading(false);
70
+ }
71
+ }, [callTool]);
72
+ const mountedRef = useRef(false);
73
+ useEffect(() => {
74
+ if (!mountedRef.current) {
75
+ mountedRef.current = true;
76
+ loadBots();
77
+ }
78
+ }, [loadBots]);
79
+ const handleRegister = useCallback(async () => {
80
+ if (!regName.trim() || !regFilePath.trim() || !regExport.trim()) return;
81
+ setRegistering(true);
82
+ try {
83
+ await callTool("fw_weaver_register_bot", {
84
+ name: regName.trim(),
85
+ filePath: regFilePath.trim(),
86
+ workflowExport: regExport.trim(),
87
+ paramName: "taskJson"
88
+ });
89
+ toast("Bot registered", { type: "success" });
90
+ setRegName("");
91
+ setRegFilePath("");
92
+ setRegExport("");
93
+ setShowRegForm(false);
94
+ await loadBots();
95
+ } catch (err) {
96
+ toast(err instanceof Error ? err.message : "Registration failed", { type: "error" });
97
+ } finally {
98
+ setRegistering(false);
99
+ }
100
+ }, [regName, regFilePath, regExport, callTool, loadBots]);
101
+ const handleUnregister = useCallback(async (id) => {
102
+ setUnregistering(true);
103
+ try {
104
+ await callTool("fw_weaver_unregister_bot", { id });
105
+ toast("Bot unregistered", { type: "warning" });
106
+ setConfirmUnregId(null);
107
+ await loadBots();
108
+ } catch (err) {
109
+ toast(err instanceof Error ? err.message : "Unregister failed", { type: "error" });
110
+ } finally {
111
+ setUnregistering(false);
112
+ }
113
+ }, [callTool, loadBots]);
114
+ const handleOpenWorkspace = useCallback((botId) => {
115
+ dispatchEvent("fw:open-bot-workspace", { botId, packId, live: false });
116
+ }, [dispatchEvent, packId]);
117
+ const hasBots = bots.length > 0;
118
+ const header = React.createElement(
119
+ Flex,
120
+ {
121
+ variant: "row-center-between-nowrap-8",
122
+ style: { padding: "8px 12px", borderBottom: "1px solid var(--color-border-default)", flexShrink: 0 }
123
+ },
124
+ React.createElement(
125
+ Flex,
126
+ { variant: "row-center-start-nowrap-6" },
127
+ React.createElement(Icon, { name: "smartToy", size: 16, color: "color-text-medium" }),
128
+ React.createElement(Typography, { variant: "caption-thick", color: "color-text-high" }, "Bots")
129
+ ),
130
+ React.createElement(
131
+ Flex,
132
+ { variant: "row-center-start-nowrap-4" },
133
+ React.createElement(IconButton, {
134
+ icon: "refresh",
135
+ size: "xs",
136
+ variant: "clear",
137
+ onClick: loadBots,
138
+ title: "Refresh"
139
+ }),
140
+ React.createElement(IconButton, {
141
+ icon: "add",
142
+ size: "xs",
143
+ variant: "clear",
144
+ onClick: () => setShowRegForm((v) => !v),
145
+ title: "Register bot"
146
+ })
147
+ )
148
+ );
149
+ const regForm = showRegForm ? React.createElement(
150
+ Flex,
151
+ {
152
+ variant: "column-start-start-nowrap-8",
153
+ style: {
154
+ padding: "10px 12px",
155
+ borderBottom: "1px solid var(--color-border-default)",
156
+ backgroundColor: "var(--color-surface-low)"
157
+ }
158
+ },
159
+ React.createElement(Typography, { variant: "smallCaption-thick", color: "color-text-medium" }, "Register Existing Workflow"),
160
+ React.createElement(Input, {
161
+ type: "text",
162
+ size: "small",
163
+ placeholder: "Bot name",
164
+ value: regName,
165
+ onChange: setRegName
166
+ }),
167
+ React.createElement(Input, {
168
+ type: "text",
169
+ size: "small",
170
+ placeholder: "File path (e.g. my-bot.ts)",
171
+ value: regFilePath,
172
+ onChange: setRegFilePath
173
+ }),
174
+ React.createElement(Input, {
175
+ type: "text",
176
+ size: "small",
177
+ placeholder: "Export name (e.g. myBot)",
178
+ value: regExport,
179
+ onChange: setRegExport
180
+ }),
181
+ React.createElement(
182
+ Flex,
183
+ { variant: "row-center-start-nowrap-6" },
184
+ React.createElement(Button, {
185
+ size: "xs",
186
+ variant: "fill",
187
+ color: "primary",
188
+ onClick: handleRegister,
189
+ disabled: registering || !regName.trim() || !regFilePath.trim() || !regExport.trim()
190
+ }, registering ? "Registering..." : "Register"),
191
+ React.createElement(Button, {
192
+ size: "xs",
193
+ variant: "clear",
194
+ color: "secondary",
195
+ onClick: () => {
196
+ setShowRegForm(false);
197
+ setRegName("");
198
+ setRegFilePath("");
199
+ setRegExport("");
200
+ }
201
+ }, "Cancel")
202
+ )
203
+ ) : null;
204
+ if (loading) {
205
+ return React.createElement(
206
+ Flex,
207
+ {
208
+ variant: "column-stretch-start-nowrap-0",
209
+ style: { width: "100%", height: "100%" }
210
+ },
211
+ header,
212
+ React.createElement(
213
+ Flex,
214
+ {
215
+ variant: "column-center-center-nowrap-8",
216
+ style: { flex: 1, padding: "24px" }
217
+ },
218
+ React.createElement(Typography, { variant: "caption-regular", color: "color-text-subtle" }, "Loading bots...")
219
+ )
220
+ );
221
+ }
222
+ if (error) {
223
+ return React.createElement(
224
+ Flex,
225
+ {
226
+ variant: "column-stretch-start-nowrap-0",
227
+ style: { width: "100%", height: "100%" }
228
+ },
229
+ header,
230
+ React.createElement(
231
+ Flex,
232
+ {
233
+ variant: "column-center-center-nowrap-8",
234
+ style: { flex: 1, padding: "24px" }
235
+ },
236
+ React.createElement(Typography, { variant: "caption-regular", color: "color-danger" }, error),
237
+ React.createElement(Button, { size: "xs", variant: "outlined", onClick: loadBots }, "Retry")
238
+ )
239
+ );
240
+ }
241
+ const botCards = bots.map((bot) => {
242
+ const vState = bot.validation?.state;
243
+ const vInfo = validationIcon(vState);
244
+ const isConfirming = confirmUnregId === bot.id;
245
+ return React.createElement(
246
+ Flex,
247
+ {
248
+ key: bot.id,
249
+ variant: "row-center-start-nowrap-8",
250
+ style: {
251
+ padding: "7px 8px",
252
+ borderRadius: "var(--border-radius-secondary)",
253
+ border: "1px solid var(--color-border-default)",
254
+ cursor: "pointer",
255
+ transition: "background-color 0.12s"
256
+ },
257
+ onClick: () => handleOpenWorkspace(bot.id),
258
+ onMouseEnter: (e) => {
259
+ e.currentTarget.style.backgroundColor = "var(--color-surface-raised)";
260
+ },
261
+ onMouseLeave: (e) => {
262
+ e.currentTarget.style.backgroundColor = "";
263
+ }
264
+ },
265
+ // Icon
266
+ React.createElement(
267
+ "div",
268
+ {
269
+ style: {
270
+ width: "26px",
271
+ height: "26px",
272
+ borderRadius: "var(--border-radius-compact)",
273
+ display: "flex",
274
+ alignItems: "center",
275
+ justifyContent: "center",
276
+ flexShrink: 0,
277
+ background: bot.color ? `color-mix(in srgb, ${bot.color} 14%, transparent)` : "var(--color-surface-low)"
278
+ }
279
+ },
280
+ React.createElement(Icon, {
281
+ name: bot.icon || "smartToy",
282
+ size: 14,
283
+ color: bot.color ? void 0 : "color-text-medium",
284
+ style: bot.color ? { color: bot.color } : void 0
285
+ })
286
+ ),
287
+ // Name + description
288
+ React.createElement(
289
+ Flex,
290
+ {
291
+ variant: "column-start-start-nowrap-1",
292
+ style: { flex: 1, minWidth: 0 }
293
+ },
294
+ React.createElement(
295
+ Flex,
296
+ { variant: "row-center-start-nowrap-4" },
297
+ React.createElement(Typography, {
298
+ variant: "caption-thick",
299
+ color: "color-text-high",
300
+ style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
301
+ }, bot.name),
302
+ // Validation badge
303
+ React.createElement(Icon, {
304
+ name: vInfo.icon,
305
+ size: 12,
306
+ style: { color: vInfo.color, flexShrink: 0 }
307
+ })
308
+ ),
309
+ bot.description ? React.createElement(Typography, {
310
+ variant: "smallCaption-regular",
311
+ color: "color-text-medium",
312
+ style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
313
+ }, bot.description) : null
314
+ ),
315
+ // Actions
316
+ isConfirming ? React.createElement(
317
+ Flex,
318
+ {
319
+ variant: "row-center-start-nowrap-4",
320
+ onClick: (e) => e.stopPropagation()
321
+ },
322
+ React.createElement(Button, {
323
+ size: "xs",
324
+ variant: "fill",
325
+ color: "danger",
326
+ onClick: () => handleUnregister(bot.id),
327
+ disabled: unregistering
328
+ }, unregistering ? "..." : "Yes"),
329
+ React.createElement(Button, {
330
+ size: "xs",
331
+ variant: "clear",
332
+ color: "secondary",
333
+ onClick: () => setConfirmUnregId(null)
334
+ }, "No")
335
+ ) : React.createElement(
336
+ Flex,
337
+ {
338
+ variant: "row-center-start-nowrap-2",
339
+ onClick: (e) => e.stopPropagation()
340
+ },
341
+ React.createElement(IconButton, {
342
+ icon: "openInNew",
343
+ size: "xs",
344
+ variant: "clear",
345
+ onClick: () => handleOpenWorkspace(bot.id),
346
+ title: "Open workspace"
347
+ }),
348
+ React.createElement(IconButton, {
349
+ icon: "close",
350
+ size: "xs",
351
+ variant: "clear",
352
+ onClick: () => setConfirmUnregId(bot.id),
353
+ title: "Unregister"
354
+ })
355
+ )
356
+ );
357
+ });
358
+ const content = hasBots ? React.createElement(
359
+ ScrollArea,
360
+ { style: { flex: 1 } },
361
+ React.createElement(Flex, {
362
+ variant: "column-start-start-nowrap-4",
363
+ style: { padding: "8px 12px" }
364
+ }, ...botCards)
365
+ ) : React.createElement(
366
+ Flex,
367
+ {
368
+ variant: "column-center-center-nowrap-0",
369
+ style: { flex: 1, padding: "24px" }
370
+ },
371
+ React.createElement(EmptyState, {
372
+ icon: "smartToy",
373
+ message: "No bots registered",
374
+ description: "Register an existing workflow or ask the AI assistant to create one."
375
+ })
376
+ );
377
+ return React.createElement(
378
+ Flex,
379
+ {
380
+ variant: "column-stretch-start-nowrap-0",
381
+ style: { width: "100%", height: "100%", overflow: "hidden" }
382
+ },
383
+ header,
384
+ regForm,
385
+ content
386
+ );
387
+ }
388
+ module.exports = BotPanel;