@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.
@@ -28,7 +28,7 @@ import { SessionBar } from './session-bar';
28
28
  import { SettingsSection } from './settings-section';
29
29
  import { QueueInput } from './queue-input';
30
30
  import { GenesisBlock } from './genesis-block';
31
- import { ApprovalCard } from './approval-card';
31
+ // ApprovalCard no longer needed — TaskBlock handles approval UI natively
32
32
  import { useStreamTimeline } from './use-stream-timeline';
33
33
  import { traceToTimeline } from './trace-to-timeline';
34
34
  import { sendSteerCommand } from './steer-api';
@@ -313,10 +313,43 @@ function BotWorkspace() {
313
313
  return text;
314
314
  }
315
315
 
316
- // Approval slot for running TaskBlock
317
- const approvalSlot = awaitingApproval && plan
318
- ? React.createElement(ApprovalCard, { plan, callTool })
319
- : null;
316
+ // Approval state for running TaskBlock
317
+ const [approvalStatus, setApprovalStatus] = useState<'pending' | 'approved' | 'rejected' | null>(null);
318
+ const [approvalLoading, setApprovalLoading] = useState(false);
319
+
320
+ // Sync approval status with stream events
321
+ useEffect(() => {
322
+ if (awaitingApproval) setApprovalStatus('pending');
323
+ }, [awaitingApproval]);
324
+
325
+ // Reset approval when stream restarts (new run)
326
+ useEffect(() => {
327
+ if (stream.events.length === 0) setApprovalStatus(null);
328
+ }, [stream.events.length]);
329
+
330
+ const handleApprove = useCallback(async () => {
331
+ setApprovalLoading(true);
332
+ try {
333
+ await callTool('fw_weaver_approve', { approved: true });
334
+ setApprovalStatus('approved');
335
+ toast('Plan approved', { type: 'success' });
336
+ } catch (err: unknown) {
337
+ toast(err instanceof Error ? err.message : 'Failed to approve', { type: 'error' });
338
+ }
339
+ setApprovalLoading(false);
340
+ }, [callTool]);
341
+
342
+ const handleReject = useCallback(async () => {
343
+ setApprovalLoading(true);
344
+ try {
345
+ await callTool('fw_weaver_approve', { approved: false });
346
+ setApprovalStatus('rejected');
347
+ toast('Plan rejected', { type: 'info' });
348
+ } catch (err: unknown) {
349
+ toast(err instanceof Error ? err.message : 'Failed to reject', { type: 'error' });
350
+ }
351
+ setApprovalLoading(false);
352
+ }, [callTool]);
320
353
 
321
354
  return React.createElement(Flex, {
322
355
  variant: 'column-stretch-start-nowrap-0',
@@ -376,7 +409,10 @@ function BotWorkspace() {
376
409
  cost,
377
410
  plan,
378
411
  error: stream.error,
379
- approvalSlot,
412
+ approval: approvalStatus ?? undefined,
413
+ approvalLoading,
414
+ onApprove: handleApprove,
415
+ onReject: handleReject,
380
416
  onPause: handlePause,
381
417
  onStop: handleStop,
382
418
  pauseLoading: pausing,
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Chat Bot Result — compact inline card for the AI chat thread.
3
+ *
4
+ * Renders when `fw_weaver_bot` returns a result. Shows task instruction,
5
+ * live status (polls fw_weaver_status), and an "Open" button to launch
6
+ * the full workspace.
7
+ */
8
+ const React = require('react');
9
+ const { useState, useEffect, useCallback } = React;
10
+ const { Flex, Typography, StatusIcon, Button, toast } = require('@fw/plugin-ui-kit');
11
+
12
+ interface ChatBotResultProps {
13
+ result: unknown;
14
+ toolName: string;
15
+ args: Record<string, unknown>;
16
+ callTool: (tool: string, args?: Record<string, unknown>) => Promise<unknown>;
17
+ openWorkspace: (data: Record<string, unknown>) => void;
18
+ }
19
+
20
+ function ChatBotResult({ result, args, callTool, openWorkspace }: ChatBotResultProps) {
21
+ const [status, setStatus] = useState<'running' | 'completed' | 'failed'>('running');
22
+ const [summary, setSummary] = useState<string | null>(null);
23
+
24
+ const parsed = typeof result === 'string' ? JSON.parse(result) : result;
25
+ const runId = parsed?.runId;
26
+ const instruction = parsed?.instruction || (args?.task as string) || 'Bot task';
27
+
28
+ // Poll status briefly
29
+ useEffect(() => {
30
+ if (!runId || status !== 'running') return;
31
+ const poll = async () => {
32
+ try {
33
+ const s = await callTool('fw_weaver_status') as Record<string, unknown>;
34
+ if (s?.currentRunId !== runId) {
35
+ // Run finished — check history
36
+ const history = await callTool('fw_weaver_history', { id: runId }) as unknown[];
37
+ if (Array.isArray(history) && history.length > 0) {
38
+ const run = history[0] as Record<string, unknown>;
39
+ setStatus(run.success ? 'completed' : 'failed');
40
+ setSummary(run.summary as string || null);
41
+ } else {
42
+ setStatus('completed');
43
+ }
44
+ }
45
+ } catch { /* non-fatal */ }
46
+ };
47
+ const interval = setInterval(poll, 3000);
48
+ poll();
49
+ return () => clearInterval(interval);
50
+ }, [runId, status, callTool]);
51
+
52
+ return React.createElement(Flex, {
53
+ variant: 'row-center-start-nowrap-10',
54
+ style: {
55
+ padding: '8px 12px',
56
+ borderRadius: 'var(--border-radius-regular)',
57
+ border: '1px solid var(--color-border-default)',
58
+ backgroundColor: 'var(--color-surface-low)',
59
+ },
60
+ },
61
+ React.createElement(StatusIcon, {
62
+ status: status === 'running' ? 'running' : status === 'completed' ? 'completed' : 'failed',
63
+ size: 'sm',
64
+ }),
65
+ React.createElement(Flex, { variant: 'column-start-start-nowrap-2', style: { flex: 1, minWidth: 0 } },
66
+ React.createElement(Typography, {
67
+ variant: 'caption-thick', color: 'color-text-high',
68
+ style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
69
+ }, instruction),
70
+ summary && React.createElement(Typography, {
71
+ variant: 'smallCaption-regular', color: 'color-text-medium',
72
+ }, summary),
73
+ ),
74
+ React.createElement(Button, {
75
+ size: 'xs', variant: 'clear', color: 'secondary',
76
+ onClick: () => openWorkspace({ runId, packId: '@synergenius/flow-weaver-pack-weaver', live: status === 'running' }),
77
+ }, 'Open'),
78
+ );
79
+ }
80
+
81
+ module.exports = ChatBotResult;