@synergenius/flow-weaver 0.20.7 → 0.21.0

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 (54) hide show
  1. package/dist/api/command-runner.d.ts +13 -0
  2. package/dist/api/command-runner.js +217 -0
  3. package/dist/api/index.d.ts +1 -0
  4. package/dist/api/index.js +1 -0
  5. package/dist/cli/flow-weaver.mjs +24064 -38374
  6. package/dist/cli/index.js +0 -60
  7. package/dist/doc-metadata/extractors/cli-commands.js +37 -56
  8. package/dist/doc-metadata/extractors/mcp-tools.d.ts +1 -1
  9. package/dist/doc-metadata/extractors/mcp-tools.js +1 -213
  10. package/dist/doc-metadata/types.d.ts +2 -0
  11. package/dist/generated-version.d.ts +1 -1
  12. package/dist/generated-version.js +1 -1
  13. package/dist/mcp/index.d.ts +1 -5
  14. package/dist/mcp/index.js +0 -4
  15. package/dist/mcp/server.js +3 -55
  16. package/dist/mcp/types.d.ts +0 -50
  17. package/dist/mcp/types.js +1 -7
  18. package/dist/mcp/workflow-executor.js +23 -1
  19. package/dist/parser.js +5 -1
  20. package/package.json +1 -2
  21. package/dist/cli/commands/listen.d.ts +0 -16
  22. package/dist/cli/commands/listen.js +0 -39
  23. package/dist/cli/commands/tunnel.d.ts +0 -19
  24. package/dist/cli/commands/tunnel.js +0 -119
  25. package/dist/cli/commands/ui.d.ts +0 -16
  26. package/dist/cli/commands/ui.js +0 -130
  27. package/dist/cli/tunnel/dispatch.d.ts +0 -18
  28. package/dist/cli/tunnel/dispatch.js +0 -36
  29. package/dist/cli/tunnel/file-lock.d.ts +0 -9
  30. package/dist/cli/tunnel/file-lock.js +0 -36
  31. package/dist/cli/tunnel/handlers/ast-ops.d.ts +0 -10
  32. package/dist/cli/tunnel/handlers/ast-ops.js +0 -252
  33. package/dist/cli/tunnel/handlers/execution.d.ts +0 -7
  34. package/dist/cli/tunnel/handlers/execution.js +0 -89
  35. package/dist/cli/tunnel/handlers/file-ops.d.ts +0 -7
  36. package/dist/cli/tunnel/handlers/file-ops.js +0 -204
  37. package/dist/cli/tunnel/handlers/mutations.d.ts +0 -7
  38. package/dist/cli/tunnel/handlers/mutations.js +0 -285
  39. package/dist/cli/tunnel/handlers/stubs.d.ts +0 -7
  40. package/dist/cli/tunnel/handlers/stubs.js +0 -143
  41. package/dist/cli/tunnel/handlers/templates.d.ts +0 -7
  42. package/dist/cli/tunnel/handlers/templates.js +0 -123
  43. package/dist/cli/tunnel/path-resolver.d.ts +0 -17
  44. package/dist/cli/tunnel/path-resolver.js +0 -54
  45. package/dist/defaults.d.ts +0 -3
  46. package/dist/defaults.js +0 -3
  47. package/dist/mcp/editor-connection.d.ts +0 -52
  48. package/dist/mcp/editor-connection.js +0 -142
  49. package/dist/mcp/event-buffer.d.ts +0 -62
  50. package/dist/mcp/event-buffer.js +0 -150
  51. package/dist/mcp/resources.d.ts +0 -14
  52. package/dist/mcp/resources.js +0 -55
  53. package/dist/mcp/tools-editor.d.ts +0 -5
  54. package/dist/mcp/tools-editor.js +0 -283
@@ -1,283 +0,0 @@
1
- import { z } from 'zod';
2
- import { makeToolResult, makeErrorResult } from './response-utils.js';
3
- import { executeWorkflowFromFile } from './workflow-executor.js';
4
- import { AgentChannel } from './agent-channel.js';
5
- import { storePendingRun, getPendingRun, removePendingRun, listPendingRuns } from './run-registry.js';
6
- /**
7
- * Unwrap Studio ack responses to flatten double-nested results.
8
- * Studio returns { requestId, success, result: { actualData } },
9
- * we extract the `result` field to avoid double-nesting in MCP output.
10
- */
11
- function unwrapAckResult(ack) {
12
- if (ack && typeof ack === 'object' && 'result' in ack && ack.result !== undefined) {
13
- return ack.result;
14
- }
15
- return ack;
16
- }
17
- export function registerEditorTools(mcp, connection, buffer) {
18
- mcp.tool('fw_check_events', 'Get buffered Studio events. Returns and clears the event buffer unless peek=true.', { peek: z.boolean().optional().describe('If true, read events without clearing the buffer') }, async (args) => {
19
- const events = args.peek ? buffer.peek() : buffer.drain();
20
- return makeToolResult(events);
21
- });
22
- mcp.tool('fw_get_state', 'Get the current Studio/workflow state from Flow Weaver.', {}, async () => {
23
- if (!connection.isConnected) {
24
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
25
- }
26
- const result = await connection.sendCommand('get-state', {});
27
- return makeToolResult(unwrapAckResult(result));
28
- });
29
- mcp.tool('fw_focus_node', 'Select and center a node in Flow Weaver Studio.', { nodeId: z.string().describe('The ID of the node to focus') }, async (args) => {
30
- if (!connection.isConnected) {
31
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
32
- }
33
- const result = await connection.sendCommand('focus-node', { nodeId: args.nodeId });
34
- return makeToolResult(unwrapAckResult(result));
35
- });
36
- mcp.tool('fw_add_node', 'Add a new node to the workflow in Flow Weaver Studio.', {
37
- nodeTypeName: z.string().describe('The name of the node type to add'),
38
- nodeTypeDefinition: z
39
- .record(z.unknown())
40
- .optional()
41
- .describe('Optional node type definition object'),
42
- }, async (args) => {
43
- if (!connection.isConnected) {
44
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
45
- }
46
- const params = { nodeTypeName: args.nodeTypeName };
47
- if (args.nodeTypeDefinition) {
48
- params.nodeTypeDefinition = args.nodeTypeDefinition;
49
- }
50
- const result = await connection.sendCommand('add-node', params);
51
- return makeToolResult(unwrapAckResult(result));
52
- });
53
- mcp.tool('fw_open_workflow', 'Open a workflow file in Flow Weaver Studio.', { filePath: z.string().describe('The path to the workflow file to open') }, async (args) => {
54
- if (!connection.isConnected) {
55
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
56
- }
57
- const result = await connection.sendCommand('open-workflow', { filePath: args.filePath });
58
- return makeToolResult(unwrapAckResult(result));
59
- });
60
- mcp.tool('fw_send_command', 'Send a generic command to Flow Weaver Studio.', {
61
- action: z.string().describe('The command action name'),
62
- params: z.record(z.unknown()).optional().describe('Optional parameters for the command'),
63
- }, async (args) => {
64
- if (!connection.isConnected) {
65
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
66
- }
67
- const result = await connection.sendCommand(args.action, args.params ?? {});
68
- return makeToolResult(unwrapAckResult(result));
69
- });
70
- mcp.tool('fw_batch', 'Execute a batch of commands with auto-snapshot rollback support.', {
71
- commands: z
72
- .array(z.object({
73
- action: z.string(),
74
- params: z.record(z.unknown()).optional(),
75
- }))
76
- .describe('Array of commands to execute as a batch'),
77
- }, async (args) => {
78
- if (!connection.isConnected) {
79
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
80
- }
81
- const result = await connection.sendBatch(args.commands);
82
- return makeToolResult(unwrapAckResult(result));
83
- });
84
- // --- New tools ---
85
- mcp.tool('fw_remove_node', 'Remove a node and its connections from the workflow.', { nodeName: z.string().describe('The name/ID of the node to remove') }, async (args) => {
86
- if (!connection.isConnected) {
87
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
88
- }
89
- const result = await connection.sendCommand('remove-node', { nodeName: args.nodeName });
90
- return makeToolResult(unwrapAckResult(result));
91
- });
92
- mcp.tool('fw_connect', 'Add or remove a connection between ports.', {
93
- action: z.enum(['add', 'remove']).describe('Whether to add or remove the connection'),
94
- connection: z
95
- .object({
96
- sourceNode: z.string().describe('Source node ID'),
97
- sourcePort: z.string().describe('Source port name'),
98
- targetNode: z.string().describe('Target node ID'),
99
- targetPort: z.string().describe('Target port name'),
100
- })
101
- .describe('Connection specification'),
102
- }, async (args) => {
103
- if (!connection.isConnected) {
104
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
105
- }
106
- const bridgeAction = args.action === 'add' ? 'add-connection' : 'remove-connection';
107
- const result = await connection.sendCommand(bridgeAction, {
108
- connection: args.connection,
109
- });
110
- return makeToolResult(unwrapAckResult(result));
111
- });
112
- mcp.tool('fw_undo_redo', 'Undo or redo the last workflow change.', { action: z.enum(['undo', 'redo']).describe('Whether to undo or redo') }, async (args) => {
113
- if (!connection.isConnected) {
114
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
115
- }
116
- const result = await connection.sendCommand(args.action, {});
117
- return makeToolResult(unwrapAckResult(result));
118
- });
119
- mcp.tool('fw_execute_workflow', 'Run the current workflow with optional parameters and return the result. ' +
120
- 'Includes per-node execution trace by default (STATUS_CHANGED, VARIABLE_SET events) — ' +
121
- 'use includeTrace: false to disable. If the workflow pauses at a waitForAgent node, ' +
122
- 'returns immediately with status "waiting" and a runId — use fw_resume_workflow to continue.', {
123
- filePath: z
124
- .string()
125
- .optional()
126
- .describe('Path to workflow file. When provided, compiles and executes directly (no Studio needed)'),
127
- workflowName: z
128
- .string()
129
- .optional()
130
- .describe('Specific workflow function name (for multi-workflow files)'),
131
- params: z.record(z.unknown()).optional().describe('Optional execution parameters'),
132
- includeTrace: z
133
- .boolean()
134
- .optional()
135
- .describe('Include execution trace events (default: true)'),
136
- }, async (args, extra) => {
137
- // When filePath is provided, compile and execute directly (no Studio needed)
138
- if (args.filePath) {
139
- try {
140
- const channel = new AgentChannel();
141
- const runId = `run-${Date.now()}-${Math.random().toString(36).slice(2)}`;
142
- // Send progress notifications for trace events when client supports it
143
- const progressToken = extra._meta?.progressToken;
144
- let eventCount = 0;
145
- const onEvent = progressToken
146
- ? (event) => {
147
- eventCount++;
148
- extra.sendNotification({
149
- method: 'notifications/progress',
150
- params: {
151
- progressToken,
152
- progress: eventCount,
153
- message: event.type === 'STATUS_CHANGED'
154
- ? `${event.data?.id ?? ''}: ${event.data?.status ?? ''}`
155
- : event.type,
156
- },
157
- }).catch(() => { });
158
- }
159
- : undefined;
160
- const execPromise = executeWorkflowFromFile(args.filePath, args.params, {
161
- workflowName: args.workflowName,
162
- includeTrace: args.includeTrace,
163
- agentChannel: channel,
164
- onEvent,
165
- });
166
- // Race between workflow completing and workflow pausing
167
- const raceResult = await Promise.race([
168
- execPromise.then((r) => ({ type: 'completed', result: r })),
169
- channel.onPause().then((req) => ({ type: 'paused', request: req })),
170
- ]);
171
- if (raceResult.type === 'paused') {
172
- // Store the pending run for later resumption
173
- storePendingRun({
174
- runId,
175
- filePath: args.filePath,
176
- workflowName: args.workflowName,
177
- executionPromise: execPromise,
178
- agentChannel: channel,
179
- request: raceResult.request,
180
- createdAt: Date.now(),
181
- tmpFiles: [], // executor manages its own cleanup
182
- });
183
- return makeToolResult({
184
- status: 'waiting',
185
- runId,
186
- request: raceResult.request,
187
- message: 'Workflow paused at waitForAgent node. Use fw_resume_workflow to continue.',
188
- });
189
- }
190
- // Completed without pausing, return flat result
191
- return makeToolResult(raceResult.result);
192
- }
193
- catch (err) {
194
- const message = err instanceof Error ? err.message : String(err);
195
- // Distinguish compile errors from execution errors
196
- const code = message.includes('Parse errors') ? 'COMPILE_ERROR' : 'EXECUTION_ERROR';
197
- return makeErrorResult(code, message);
198
- }
199
- }
200
- // No filePath: delegate to Studio via Socket.io (existing behavior)
201
- if (!connection.isConnected) {
202
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
203
- }
204
- const result = await connection.sendCommand('execute-workflow', args.params ?? {});
205
- return makeToolResult(unwrapAckResult(result));
206
- });
207
- mcp.tool('fw_resume_workflow', 'Resume a paused workflow that is waiting for agent input. ' +
208
- 'Use this after fw_execute_workflow returns status "waiting".', {
209
- runId: z.string().describe('The runId from the waiting execution result'),
210
- result: z.record(z.unknown()).describe('The agent result to send back to the workflow'),
211
- }, async (args) => {
212
- const run = getPendingRun(args.runId);
213
- if (!run) {
214
- return makeErrorResult('RUN_NOT_FOUND', `No pending run found with ID "${args.runId}". It may have already completed or been cancelled.`);
215
- }
216
- try {
217
- // Resume the workflow by resolving the agent channel's Promise
218
- run.agentChannel.resume(args.result);
219
- // Wait for the workflow to either complete or pause again
220
- const raceResult = await Promise.race([
221
- run.executionPromise.then((r) => ({ type: 'completed', result: r })),
222
- run.agentChannel.onPause().then((req) => ({ type: 'paused', request: req })),
223
- ]);
224
- if (raceResult.type === 'paused') {
225
- // Workflow paused again at another waitForAgent node
226
- run.request = raceResult.request;
227
- return makeToolResult({
228
- status: 'waiting',
229
- runId: args.runId,
230
- request: raceResult.request,
231
- message: 'Workflow paused again at another waitForAgent node.',
232
- });
233
- }
234
- // Workflow completed
235
- removePendingRun(args.runId);
236
- return makeToolResult({ status: 'completed', result: raceResult.result });
237
- }
238
- catch (err) {
239
- removePendingRun(args.runId);
240
- const message = err instanceof Error ? err.message : String(err);
241
- return makeErrorResult('EXECUTION_ERROR', message);
242
- }
243
- });
244
- mcp.tool('fw_list_pending_runs', 'List workflows that are currently paused waiting for agent input.', {}, async () => {
245
- const runs = listPendingRuns();
246
- return makeToolResult(runs);
247
- });
248
- mcp.tool('fw_get_workflow_details', 'Get full workflow structure including nodes, connections, types, and positions.', {}, async () => {
249
- if (!connection.isConnected) {
250
- return makeErrorResult('EDITOR_NOT_CONNECTED', 'Not connected to Studio. Is Studio running?');
251
- }
252
- const result = await connection.sendCommand('get-workflow-details', {});
253
- return makeToolResult(unwrapAckResult(result));
254
- });
255
- mcp.tool('fw_configure_events', 'Configure event include/exclude filters, dedup window, and buffer size. Returns the active config after applying updates.', {
256
- include: z
257
- .array(z.string())
258
- .optional()
259
- .describe('Event patterns to include (empty = all). Supports trailing * for prefix match'),
260
- exclude: z
261
- .array(z.string())
262
- .optional()
263
- .describe('Event patterns to exclude (applied after include)'),
264
- dedupeWindowMs: z
265
- .number()
266
- .optional()
267
- .describe('Collapse same-type events within this window in ms (0 = disabled)'),
268
- maxBufferSize: z.number().optional().describe('Max events before oldest are evicted'),
269
- }, async (args) => {
270
- const partial = {};
271
- if (args.include !== undefined)
272
- partial.include = args.include;
273
- if (args.exclude !== undefined)
274
- partial.exclude = args.exclude;
275
- if (args.dedupeWindowMs !== undefined)
276
- partial.dedupeWindowMs = args.dedupeWindowMs;
277
- if (args.maxBufferSize !== undefined)
278
- partial.maxBufferSize = args.maxBufferSize;
279
- const config = buffer.setFilter(partial);
280
- return makeToolResult(config);
281
- });
282
- }
283
- //# sourceMappingURL=tools-editor.js.map