@synergenius/flow-weaver-pack-weaver 0.9.53 → 0.9.55

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,115 @@
1
+ // -- Trace-to-timeline conversion --
2
+ export function traceToTimeline(run) {
3
+ const entries = [];
4
+ let idCounter = 0;
5
+ const meta = run.nodeMeta ?? {};
6
+ // Prefer node-level trace events (richer, with timing); fall back to stepLog
7
+ if (run.trace && run.trace.length > 0) {
8
+ const nodeStarts = new Map();
9
+ for (const event of run.trace) {
10
+ if (event.type === 'node-start') {
11
+ nodeStarts.set(event.nodeId, event);
12
+ }
13
+ else if (event.type === 'node-complete' || event.type === 'node-error') {
14
+ const start = nodeStarts.get(event.nodeId);
15
+ const duration = event.durationMs ?? (start ? event.timestamp - start.timestamp : undefined);
16
+ const nm = meta[event.nodeId] ?? (event.nodeType ? meta[event.nodeType] : undefined);
17
+ entries.push({
18
+ id: `trace-${idCounter++}`,
19
+ timestamp: new Date(event.timestamp),
20
+ type: event.type === 'node-complete' ? 'node-completed' : 'node-failed',
21
+ nodeId: event.nodeId,
22
+ label: nm?.label ?? event.nodeType ?? event.nodeId,
23
+ detail: event.error,
24
+ duration,
25
+ color: nm?.color,
26
+ icon: nm?.icon,
27
+ });
28
+ nodeStarts.delete(event.nodeId);
29
+ }
30
+ }
31
+ // Any nodes still in nodeStarts are still running (shouldn't happen for historical)
32
+ for (const [nodeId, event] of nodeStarts) {
33
+ const nm = meta[nodeId] ?? (event.nodeType ? meta[event.nodeType] : undefined);
34
+ entries.push({
35
+ id: `trace-${idCounter++}`,
36
+ timestamp: new Date(event.timestamp),
37
+ type: 'node-started',
38
+ nodeId,
39
+ label: nm?.label ?? event.nodeType ?? nodeId,
40
+ color: nm?.color,
41
+ icon: nm?.icon,
42
+ });
43
+ }
44
+ }
45
+ else if (run.stepLog && run.stepLog.length > 0) {
46
+ // Fallback: use stepLog (coarser, from plan execution steps)
47
+ for (const step of run.stepLog) {
48
+ const type = step.status === 'ok'
49
+ ? 'node-completed'
50
+ : step.status === 'error'
51
+ ? 'node-failed'
52
+ : 'node-completed'; // 'blocked' treated as completed with detail
53
+ entries.push({
54
+ id: `step-${idCounter++}`,
55
+ timestamp: new Date(run.startedAt ?? Date.now()),
56
+ type: type,
57
+ label: step.step,
58
+ detail: step.detail,
59
+ icon: step.status === 'ok' ? 'success' : step.status === 'error' ? 'error' : 'warning',
60
+ });
61
+ }
62
+ }
63
+ // Append a task-level result entry for failed/completed runs
64
+ if (run.outcome === 'failed' || run.outcome === 'error') {
65
+ // Extract error details from audit trail
66
+ let errorDetail = '';
67
+ if (run.auditTrail) {
68
+ for (const a of run.auditTrail) {
69
+ if (a.type === 'step-complete' && a.data) {
70
+ const errors = a.data.errors;
71
+ if (errors && errors.length > 0) {
72
+ errorDetail = errors
73
+ .map((e) => (e.length > 120 ? e.slice(0, 117) + '...' : e))
74
+ .join('\n');
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ // Fallback to summary
81
+ if (!errorDetail && run.summary) {
82
+ const parts = run.summary.split('|').map((p) => p.trim());
83
+ const outcomePart = parts.find((p) => p.startsWith('Outcome:'));
84
+ const summaryPart = parts.find((p) => p.startsWith('Summary:'));
85
+ errorDetail = summaryPart?.replace('Summary:', '').trim() ?? outcomePart ?? run.summary;
86
+ }
87
+ entries.push({
88
+ id: `result-${idCounter++}`,
89
+ timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
90
+ type: 'task-failed',
91
+ label: 'Task failed',
92
+ detail: errorDetail || 'Unknown failure',
93
+ icon: 'error',
94
+ });
95
+ }
96
+ else if (run.outcome === 'completed' && run.success) {
97
+ entries.push({
98
+ id: `result-${idCounter++}`,
99
+ timestamp: new Date(run.finishedAt ?? run.startedAt ?? Date.now()),
100
+ type: 'task-completed',
101
+ label: 'Task completed',
102
+ detail: run.summary?.includes('|')
103
+ ? run.summary
104
+ .split('|')
105
+ .find((p) => p.trim().startsWith('Summary:'))
106
+ ?.replace('Summary:', '')
107
+ .trim()
108
+ : undefined,
109
+ });
110
+ }
111
+ // Sort by timestamp
112
+ entries.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
113
+ return entries;
114
+ }
115
+ //# sourceMappingURL=trace-to-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-to-timeline.js","sourceRoot":"","sources":["../../src/ui/trace-to-timeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Convert a progressive stream of execution events into TimelineEntry[]
3
+ * that ExecutionTimeline can render.
4
+ *
5
+ * Handles: node-start/complete/error, bot-started/completed/failed,
6
+ * audit:plan-created, cost-update.
7
+ */
8
+ interface StreamEvent {
9
+ id: number;
10
+ type: string;
11
+ timestamp: number;
12
+ taskId?: string;
13
+ data?: Record<string, unknown>;
14
+ }
15
+ interface TimelineEntry {
16
+ id: string;
17
+ timestamp: Date;
18
+ type: 'task-started' | 'node-started' | 'node-completed' | 'node-failed' | 'agent-request' | 'user-action' | 'task-completed' | 'task-failed';
19
+ nodeId?: string;
20
+ label: string;
21
+ detail?: string;
22
+ outputs?: Array<{
23
+ portLabel: string;
24
+ value: unknown;
25
+ }>;
26
+ duration?: number;
27
+ color?: string;
28
+ icon?: string;
29
+ }
30
+ export interface StreamTimelineState {
31
+ timeline: TimelineEntry[];
32
+ phase: 'idle' | 'planning' | 'executing' | 'completed' | 'failed';
33
+ instruction: string | null;
34
+ elapsed: number;
35
+ cost: number | null;
36
+ plan: {
37
+ summary: string;
38
+ steps: Array<{
39
+ id: string;
40
+ operation: string;
41
+ description: string;
42
+ }>;
43
+ } | null;
44
+ awaitingApproval: boolean;
45
+ }
46
+ export declare function useStreamTimeline(events: StreamEvent[], isDone: boolean): StreamTimelineState;
47
+ export {};
48
+ //# sourceMappingURL=use-stream-timeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-stream-timeline.d.ts","sourceRoot":"","sources":["../../src/ui/use-stream-timeline.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,cAAc,GAAG,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,aAAa,GAAG,gBAAgB,GAAG,aAAa,CAAC;IAC9I,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;IAClE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACtE,GAAG,IAAI,CAAC;IACT,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,OAAO,GAAG,mBAAmB,CAiM7F"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Convert a progressive stream of execution events into TimelineEntry[]
3
+ * that ExecutionTimeline can render.
4
+ *
5
+ * Handles: node-start/complete/error, bot-started/completed/failed,
6
+ * audit:plan-created, cost-update.
7
+ */
8
+ const React = require('react');
9
+ const { useMemo, useState, useEffect, useRef } = React;
10
+ export function useStreamTimeline(events, isDone) {
11
+ const [elapsed, setElapsed] = useState(0);
12
+ const startTimeRef = useRef(null);
13
+ // Track start time from first event; reset when events are cleared (new run)
14
+ useEffect(() => {
15
+ if (events.length === 0) {
16
+ startTimeRef.current = null;
17
+ setElapsed(0);
18
+ }
19
+ else if (startTimeRef.current === null) {
20
+ startTimeRef.current = events[0].timestamp;
21
+ }
22
+ }, [events.length]);
23
+ // Elapsed timer — ticks every second while streaming
24
+ useEffect(() => {
25
+ if (isDone || !startTimeRef.current)
26
+ return;
27
+ const tick = () => setElapsed(Date.now() - (startTimeRef.current ?? Date.now()));
28
+ tick();
29
+ const interval = setInterval(tick, 1000);
30
+ return () => clearInterval(interval);
31
+ }, [isDone, events.length]); // re-run when events arrive to start timer
32
+ // Convert events to timeline entries.
33
+ // Collapses node-start + node-complete into a single entry per node:
34
+ // - While a node is running: shows as 'node-started' (spinner)
35
+ // - When it completes/fails: replaces with 'node-completed'/'node-failed' (with duration)
36
+ const timeline = useMemo(() => {
37
+ const entries = [];
38
+ // Map nodeId → index in entries[] so we can replace start with complete
39
+ const nodeEntryIndex = new Map();
40
+ const nodeStarts = new Map();
41
+ let idCounter = 0;
42
+ for (const event of events) {
43
+ const d = event.data ?? {};
44
+ switch (event.type) {
45
+ case 'bot-started':
46
+ entries.push({
47
+ id: `s-${idCounter++}`,
48
+ timestamp: new Date(event.timestamp),
49
+ type: 'task-started',
50
+ label: 'Task started',
51
+ detail: d.instruction,
52
+ });
53
+ break;
54
+ case 'node-start': {
55
+ const nodeId = d.nodeId;
56
+ if (nodeId)
57
+ nodeStarts.set(nodeId, event.timestamp);
58
+ const idx = entries.length;
59
+ nodeEntryIndex.set(nodeId, idx);
60
+ entries.push({
61
+ id: `s-${idCounter++}`,
62
+ timestamp: new Date(event.timestamp),
63
+ type: 'node-started',
64
+ nodeId,
65
+ label: d.label ?? d.nodeType ?? nodeId ?? 'Node',
66
+ });
67
+ break;
68
+ }
69
+ case 'node-complete': {
70
+ const nodeId = d.nodeId;
71
+ const startTs = nodeStarts.get(nodeId);
72
+ const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : undefined);
73
+ if (nodeId)
74
+ nodeStarts.delete(nodeId);
75
+ const completed = {
76
+ id: `s-${idCounter++}`,
77
+ timestamp: new Date(startTs ?? event.timestamp),
78
+ type: 'node-completed',
79
+ nodeId,
80
+ label: d.label ?? d.nodeType ?? nodeId ?? 'Node',
81
+ duration,
82
+ };
83
+ // Replace the node-started entry in-place
84
+ const existingIdx = nodeEntryIndex.get(nodeId);
85
+ if (existingIdx != null && entries[existingIdx]) {
86
+ entries[existingIdx] = completed;
87
+ nodeEntryIndex.delete(nodeId);
88
+ }
89
+ else {
90
+ entries.push(completed);
91
+ }
92
+ break;
93
+ }
94
+ case 'node-error': {
95
+ const nodeId = d.nodeId;
96
+ const startTs = nodeStarts.get(nodeId);
97
+ const duration = d.durationMs ?? (startTs ? event.timestamp - startTs : undefined);
98
+ if (nodeId)
99
+ nodeStarts.delete(nodeId);
100
+ const failed = {
101
+ id: `s-${idCounter++}`,
102
+ timestamp: new Date(startTs ?? event.timestamp),
103
+ type: 'node-failed',
104
+ nodeId,
105
+ label: d.label ?? d.nodeType ?? nodeId ?? 'Node',
106
+ detail: d.error,
107
+ duration,
108
+ };
109
+ // Replace the node-started entry in-place
110
+ const existingIdx = nodeEntryIndex.get(nodeId);
111
+ if (existingIdx != null && entries[existingIdx]) {
112
+ entries[existingIdx] = failed;
113
+ nodeEntryIndex.delete(nodeId);
114
+ }
115
+ else {
116
+ entries.push(failed);
117
+ }
118
+ break;
119
+ }
120
+ case 'bot-completed':
121
+ entries.push({
122
+ id: `s-${idCounter++}`,
123
+ timestamp: new Date(event.timestamp),
124
+ type: 'task-completed',
125
+ label: d.success ? 'Task completed' : 'Task finished',
126
+ detail: d.summary,
127
+ });
128
+ break;
129
+ case 'bot-failed':
130
+ entries.push({
131
+ id: `s-${idCounter++}`,
132
+ timestamp: new Date(event.timestamp),
133
+ type: 'task-failed',
134
+ label: 'Task failed',
135
+ detail: d.error,
136
+ });
137
+ break;
138
+ // Skip audit, cost-update, done — they're used for metadata, not timeline
139
+ default:
140
+ break;
141
+ }
142
+ }
143
+ return entries;
144
+ }, [events]);
145
+ // Extract metadata from events
146
+ const { phase, instruction, cost, plan, awaitingApproval } = useMemo(() => {
147
+ let phase = 'idle';
148
+ let instruction = null;
149
+ let cost = null;
150
+ let plan = null;
151
+ let awaitingApproval = false;
152
+ for (const event of events) {
153
+ const d = event.data ?? {};
154
+ if (event.type === 'bot-started') {
155
+ phase = 'planning';
156
+ instruction = d.instruction ?? null;
157
+ }
158
+ else if (event.type === 'node-start' && phase !== 'completed' && phase !== 'failed') {
159
+ phase = 'executing';
160
+ }
161
+ else if (event.type === 'bot-completed') {
162
+ phase = d.success ? 'completed' : 'failed';
163
+ }
164
+ else if (event.type === 'bot-failed') {
165
+ phase = 'failed';
166
+ }
167
+ else if (event.type === 'cost-update') {
168
+ cost = d.totalCost ?? cost;
169
+ }
170
+ else if (event.type === 'audit:plan-created' || event.type === 'plan-created') {
171
+ // Plan data may be at d.plan (structured) or directly on d (audit event)
172
+ const planData = d.plan ?? d;
173
+ const summary = planData.summary ?? '';
174
+ const steps = planData.steps ?? [];
175
+ if (summary || steps.length > 0) {
176
+ plan = { summary, steps };
177
+ }
178
+ }
179
+ else if (event.type === 'approval-needed') {
180
+ awaitingApproval = true;
181
+ }
182
+ else if (event.type === 'audit:approval-decision') {
183
+ awaitingApproval = false;
184
+ }
185
+ }
186
+ if (isDone && phase !== 'completed' && phase !== 'failed') {
187
+ phase = 'completed'; // Stream ended but no explicit completion event
188
+ }
189
+ return { phase, instruction, cost, plan, awaitingApproval };
190
+ }, [events, isDone]);
191
+ return { timeline, phase, instruction, elapsed, cost, plan, awaitingApproval };
192
+ }
193
+ //# sourceMappingURL=use-stream-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-stream-timeline.js","sourceRoot":"","sources":["../../src/ui/use-stream-timeline.ts"],"names":[],"mappings":"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"}
@@ -1077,8 +1077,10 @@
1077
1077
  "activity": "dist/ui/bot-activity.js",
1078
1078
  "config": "dist/ui/bot-config.js",
1079
1079
  "status": "dist/ui/bot-status.js",
1080
- "dashboard": "dist/ui/bot-dashboard.js"
1080
+ "dashboard": "dist/ui/bot-dashboard.js",
1081
+ "workspace": "dist/ui/bot-workspace.js"
1081
1082
  },
1083
+ "openWorkspaceOnTool": "fw_weaver_bot",
1082
1084
  "sandboxCapabilities": [
1083
1085
  "fetch:hooks.slack.com",
1084
1086
  "fetch:discord.com",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver-pack-weaver",
3
- "version": "0.9.53",
3
+ "version": "0.9.55",
4
4
  "description": "AI bot for Flow Weaver. Execute tasks, run workflows, evolve autonomously.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Inline approval card — shows the bot's plan with approve/reject actions.
3
+ * Rendered inside TaskBlock when phase is 'planning' and a plan is available.
4
+ * Uses the workspace context's callTool for approval.
5
+ */
6
+ const React = require('react');
7
+ const { useState, useCallback } = React;
8
+ const {
9
+ CollapsibleBlock,
10
+ Flex,
11
+ Typography,
12
+ Badge,
13
+ Tag,
14
+ Button,
15
+ toast,
16
+ } = require('@fw/plugin-ui-kit');
17
+
18
+ interface PlanStep {
19
+ id: string;
20
+ operation: string;
21
+ description: string;
22
+ }
23
+
24
+ interface ApprovalCardProps {
25
+ plan: { summary: string; steps: PlanStep[] };
26
+ callTool: (tool: string, args?: Record<string, unknown>) => Promise<unknown>;
27
+ onDecision?: (approved: boolean) => void;
28
+ }
29
+
30
+ function ApprovalCard({ plan, callTool, onDecision }: ApprovalCardProps) {
31
+ const [deciding, setDeciding] = useState(false);
32
+ const [decided, setDecided] = useState<boolean | null>(null);
33
+
34
+ const handleDecision = useCallback(
35
+ async (approved: boolean) => {
36
+ setDeciding(true);
37
+ try {
38
+ await callTool('fw_weaver_approve', { approved });
39
+ setDecided(approved);
40
+ onDecision?.(approved);
41
+ toast(approved ? 'Plan approved' : 'Plan rejected', {
42
+ type: approved ? 'success' : 'info',
43
+ });
44
+ } catch (err: unknown) {
45
+ toast(err instanceof Error ? err.message : 'Failed to send decision', { type: 'error' });
46
+ } finally {
47
+ setDeciding(false);
48
+ }
49
+ },
50
+ [callTool, onDecision],
51
+ );
52
+
53
+ if (decided !== null) {
54
+ return React.createElement(CollapsibleBlock, {
55
+ status: decided ? 'completed' : 'error',
56
+ label: React.createElement(Typography, {
57
+ variant: 'caption-bold',
58
+ color: decided ? 'color-status-positive' : 'color-status-negative',
59
+ }, decided ? 'Plan Approved' : 'Plan Rejected'),
60
+ expanded: false,
61
+ canExpand: false,
62
+ });
63
+ }
64
+
65
+ return React.createElement(CollapsibleBlock, {
66
+ status: 'pending',
67
+ label: React.createElement(Flex, { variant: 'row-center-start-nowrap-8' },
68
+ React.createElement(Badge, { variant: 'warning' }, 'Approval Needed'),
69
+ React.createElement(Typography, { variant: 'caption-bold', color: 'color-text-high' },
70
+ plan.summary || `${plan.steps.length} step plan`),
71
+ ),
72
+ expanded: true,
73
+ canExpand: false,
74
+ },
75
+ React.createElement(Flex, {
76
+ variant: 'column-start-start-nowrap-6',
77
+ style: { padding: '10px 12px' },
78
+ },
79
+ ...plan.steps.map((step: PlanStep, i: number) =>
80
+ React.createElement(Flex, {
81
+ key: step.id || i,
82
+ variant: 'row-center-start-nowrap-6',
83
+ style: { fontSize: '11px' },
84
+ },
85
+ React.createElement(Tag, { size: 'small', color: 'info' }, step.operation),
86
+ React.createElement(Typography, {
87
+ variant: 'smallCaption-regular',
88
+ color: 'color-text-medium',
89
+ }, step.description),
90
+ ),
91
+ ),
92
+ ),
93
+ React.createElement(Flex, {
94
+ variant: 'row-center-start-nowrap-8',
95
+ style: { padding: '10px 12px', borderTop: '1px solid var(--color-border-default)' },
96
+ },
97
+ React.createElement(Button, {
98
+ variant: 'fill',
99
+ color: 'primary',
100
+ size: 'xs',
101
+ onClick: () => handleDecision(true),
102
+ loading: deciding,
103
+ disabled: deciding,
104
+ }, 'Approve'),
105
+ React.createElement(Button, {
106
+ variant: 'outlined',
107
+ color: 'danger',
108
+ size: 'xs',
109
+ onClick: () => handleDecision(false),
110
+ loading: deciding,
111
+ disabled: deciding,
112
+ }, 'Reject'),
113
+ ),
114
+ );
115
+ }
116
+
117
+ export { ApprovalCard };
118
+ export default ApprovalCard;