@marktoflow/gui 2.0.0-alpha.1

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 (165) hide show
  1. package/.turbo/turbo-build.log +26 -0
  2. package/.turbo/turbo-test.log +22 -0
  3. package/README.md +179 -0
  4. package/dist/client/assets/index-DwTI8opO.js +608 -0
  5. package/dist/client/assets/index-DwTI8opO.js.map +1 -0
  6. package/dist/client/assets/index-RoEdL6gO.css +1 -0
  7. package/dist/client/index.html +20 -0
  8. package/dist/client/vite.svg +9 -0
  9. package/dist/server/index.d.ts +3 -0
  10. package/dist/server/index.d.ts.map +1 -0
  11. package/dist/server/index.js +56 -0
  12. package/dist/server/index.js.map +1 -0
  13. package/dist/server/routes/ai.js +50 -0
  14. package/dist/server/routes/ai.js.map +1 -0
  15. package/dist/server/routes/execute.js +62 -0
  16. package/dist/server/routes/execute.js.map +1 -0
  17. package/dist/server/routes/workflows.js +99 -0
  18. package/dist/server/routes/workflows.js.map +1 -0
  19. package/dist/server/server/index.js +95 -0
  20. package/dist/server/server/index.js.map +1 -0
  21. package/dist/server/server/routes/ai.js +87 -0
  22. package/dist/server/server/routes/ai.js.map +1 -0
  23. package/dist/server/server/routes/execute.js +63 -0
  24. package/dist/server/server/routes/execute.js.map +1 -0
  25. package/dist/server/server/routes/tools.js +518 -0
  26. package/dist/server/server/routes/tools.js.map +1 -0
  27. package/dist/server/server/routes/workflows.js +99 -0
  28. package/dist/server/server/routes/workflows.js.map +1 -0
  29. package/dist/server/server/services/AIService.js +69 -0
  30. package/dist/server/server/services/AIService.js.map +1 -0
  31. package/dist/server/server/services/FileWatcher.js +60 -0
  32. package/dist/server/server/services/FileWatcher.js.map +1 -0
  33. package/dist/server/server/services/WorkflowService.js +363 -0
  34. package/dist/server/server/services/WorkflowService.js.map +1 -0
  35. package/dist/server/server/services/agents/claude-code-provider.js +250 -0
  36. package/dist/server/server/services/agents/claude-code-provider.js.map +1 -0
  37. package/dist/server/server/services/agents/claude-provider.js +204 -0
  38. package/dist/server/server/services/agents/claude-provider.js.map +1 -0
  39. package/dist/server/server/services/agents/copilot-provider.js +227 -0
  40. package/dist/server/server/services/agents/copilot-provider.js.map +1 -0
  41. package/dist/server/server/services/agents/demo-provider.js +167 -0
  42. package/dist/server/server/services/agents/demo-provider.js.map +1 -0
  43. package/dist/server/server/services/agents/index.js +31 -0
  44. package/dist/server/server/services/agents/index.js.map +1 -0
  45. package/dist/server/server/services/agents/ollama-provider.js +220 -0
  46. package/dist/server/server/services/agents/ollama-provider.js.map +1 -0
  47. package/dist/server/server/services/agents/prompts.js +436 -0
  48. package/dist/server/server/services/agents/prompts.js.map +1 -0
  49. package/dist/server/server/services/agents/registry.js +242 -0
  50. package/dist/server/server/services/agents/registry.js.map +1 -0
  51. package/dist/server/server/services/agents/types.js +6 -0
  52. package/dist/server/server/services/agents/types.js.map +1 -0
  53. package/dist/server/server/websocket/index.js +85 -0
  54. package/dist/server/server/websocket/index.js.map +1 -0
  55. package/dist/server/services/AIService.d.ts +30 -0
  56. package/dist/server/services/AIService.d.ts.map +1 -0
  57. package/dist/server/services/AIService.js +216 -0
  58. package/dist/server/services/AIService.js.map +1 -0
  59. package/dist/server/services/FileWatcher.d.ts +10 -0
  60. package/dist/server/services/FileWatcher.d.ts.map +1 -0
  61. package/dist/server/services/FileWatcher.js +62 -0
  62. package/dist/server/services/FileWatcher.js.map +1 -0
  63. package/dist/server/services/WorkflowService.d.ts +54 -0
  64. package/dist/server/services/WorkflowService.d.ts.map +1 -0
  65. package/dist/server/services/WorkflowService.js +323 -0
  66. package/dist/server/services/WorkflowService.js.map +1 -0
  67. package/dist/server/shared/constants.js +175 -0
  68. package/dist/server/shared/constants.js.map +1 -0
  69. package/dist/server/shared/types.js +3 -0
  70. package/dist/server/shared/types.js.map +1 -0
  71. package/dist/server/websocket/index.d.ts +10 -0
  72. package/dist/server/websocket/index.d.ts.map +1 -0
  73. package/dist/server/websocket/index.js +85 -0
  74. package/dist/server/websocket/index.js.map +1 -0
  75. package/index.html +19 -0
  76. package/package.json +96 -0
  77. package/playwright.config.ts +27 -0
  78. package/postcss.config.js +6 -0
  79. package/public/vite.svg +9 -0
  80. package/src/client/App.tsx +520 -0
  81. package/src/client/components/Canvas/Canvas.tsx +405 -0
  82. package/src/client/components/Canvas/ExecutionOverlay.tsx +847 -0
  83. package/src/client/components/Canvas/NodeContextMenu.tsx +188 -0
  84. package/src/client/components/Canvas/OutputNode.tsx +111 -0
  85. package/src/client/components/Canvas/StepNode.tsx +106 -0
  86. package/src/client/components/Canvas/SubWorkflowNode.tsx +141 -0
  87. package/src/client/components/Canvas/Toolbar.tsx +189 -0
  88. package/src/client/components/Canvas/TriggerNode.tsx +128 -0
  89. package/src/client/components/Editor/InputsEditor.tsx +458 -0
  90. package/src/client/components/Editor/NewStepWizard.tsx +344 -0
  91. package/src/client/components/Editor/StepEditor.tsx +532 -0
  92. package/src/client/components/Editor/YamlEditor.tsx +160 -0
  93. package/src/client/components/Panels/PropertiesPanel.tsx +589 -0
  94. package/src/client/components/Prompt/ChangePreview.tsx +281 -0
  95. package/src/client/components/Prompt/PromptHistoryPanel.tsx +209 -0
  96. package/src/client/components/Prompt/PromptInput.tsx +108 -0
  97. package/src/client/components/Sidebar/Sidebar.tsx +343 -0
  98. package/src/client/components/common/Breadcrumb.tsx +40 -0
  99. package/src/client/components/common/Button.tsx +68 -0
  100. package/src/client/components/common/ContextMenu.tsx +202 -0
  101. package/src/client/components/common/KeyboardShortcuts.tsx +143 -0
  102. package/src/client/components/common/Modal.tsx +93 -0
  103. package/src/client/components/common/Tabs.tsx +57 -0
  104. package/src/client/components/common/ThemeToggle.tsx +63 -0
  105. package/src/client/components/index.ts +32 -0
  106. package/src/client/hooks/index.ts +4 -0
  107. package/src/client/hooks/useAIPrompt.ts +108 -0
  108. package/src/client/hooks/useCanvas.ts +247 -0
  109. package/src/client/hooks/useWebSocket.ts +164 -0
  110. package/src/client/hooks/useWorkflow.ts +138 -0
  111. package/src/client/main.tsx +10 -0
  112. package/src/client/stores/canvasStore.ts +348 -0
  113. package/src/client/stores/editorStore.ts +133 -0
  114. package/src/client/stores/executionStore.ts +440 -0
  115. package/src/client/stores/index.ts +4 -0
  116. package/src/client/stores/layoutStore.ts +103 -0
  117. package/src/client/stores/navigationStore.ts +49 -0
  118. package/src/client/stores/promptStore.ts +113 -0
  119. package/src/client/stores/themeStore.ts +75 -0
  120. package/src/client/stores/workflowStore.ts +177 -0
  121. package/src/client/styles/globals.css +346 -0
  122. package/src/client/utils/cn.ts +9 -0
  123. package/src/client/utils/index.ts +4 -0
  124. package/src/client/utils/serviceIcons.tsx +64 -0
  125. package/src/client/utils/stepValidation.ts +155 -0
  126. package/src/client/utils/workflowToGraph.ts +299 -0
  127. package/src/server/index.ts +114 -0
  128. package/src/server/routes/ai.ts +91 -0
  129. package/src/server/routes/execute.ts +71 -0
  130. package/src/server/routes/tools.ts +564 -0
  131. package/src/server/routes/workflows.ts +106 -0
  132. package/src/server/services/AIService.ts +105 -0
  133. package/src/server/services/FileWatcher.ts +69 -0
  134. package/src/server/services/WorkflowService.ts +441 -0
  135. package/src/server/services/agents/claude-code-provider.ts +320 -0
  136. package/src/server/services/agents/claude-provider.ts +248 -0
  137. package/src/server/services/agents/copilot-provider.ts +311 -0
  138. package/src/server/services/agents/demo-provider.ts +184 -0
  139. package/src/server/services/agents/index.ts +31 -0
  140. package/src/server/services/agents/ollama-provider.ts +267 -0
  141. package/src/server/services/agents/prompts.ts +482 -0
  142. package/src/server/services/agents/registry.ts +289 -0
  143. package/src/server/services/agents/types.ts +146 -0
  144. package/src/server/websocket/index.ts +104 -0
  145. package/src/shared/constants.ts +180 -0
  146. package/src/shared/types.ts +179 -0
  147. package/tailwind.config.ts +73 -0
  148. package/tests/e2e/app.spec.ts +90 -0
  149. package/tests/e2e/canvas.spec.ts +128 -0
  150. package/tests/e2e/workflow.spec.ts +185 -0
  151. package/tests/integration/api.test.ts +250 -0
  152. package/tests/integration/testApp.ts +31 -0
  153. package/tests/setup.ts +37 -0
  154. package/tests/unit/canvasStore.test.ts +502 -0
  155. package/tests/unit/components.test.tsx +151 -0
  156. package/tests/unit/executionStore.test.ts +527 -0
  157. package/tests/unit/layoutStore.test.ts +194 -0
  158. package/tests/unit/navigationStore.test.ts +152 -0
  159. package/tests/unit/stepValidation.test.ts +226 -0
  160. package/tests/unit/themeStore.test.ts +141 -0
  161. package/tests/unit/workflowToGraph.test.ts +289 -0
  162. package/tsconfig.json +29 -0
  163. package/tsconfig.server.json +28 -0
  164. package/vite.config.ts +31 -0
  165. package/vitest.config.ts +26 -0
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Prompt Engineering Module for Workflow Modifications
3
+ *
4
+ * This module provides context-aware prompts for different workflow operations:
5
+ * - Adding/removing steps
6
+ * - Modifying step inputs
7
+ * - Adding error handling
8
+ * - Creating sub-workflows
9
+ * - Adding conditions
10
+ */
11
+
12
+ // Available service integrations with their SDK mappings
13
+ export const AVAILABLE_SERVICES = {
14
+ slack: {
15
+ sdk: '@slack/web-api',
16
+ description: 'Slack messaging and workspace management',
17
+ commonActions: [
18
+ 'chat.postMessage',
19
+ 'chat.update',
20
+ 'chat.delete',
21
+ 'conversations.list',
22
+ 'conversations.history',
23
+ 'users.list',
24
+ 'files.upload',
25
+ 'reactions.add',
26
+ ],
27
+ },
28
+ github: {
29
+ sdk: '@octokit/rest',
30
+ description: 'GitHub repository, issues, and PR management',
31
+ commonActions: [
32
+ 'pulls.get',
33
+ 'pulls.create',
34
+ 'pulls.list',
35
+ 'issues.create',
36
+ 'issues.update',
37
+ 'issues.list',
38
+ 'repos.getContent',
39
+ 'repos.createRelease',
40
+ ],
41
+ },
42
+ jira: {
43
+ sdk: 'jira.js',
44
+ description: 'Jira issue and project tracking',
45
+ commonActions: [
46
+ 'issues.createIssue',
47
+ 'issues.updateIssue',
48
+ 'issues.getIssue',
49
+ 'issues.searchJql',
50
+ 'projects.getProject',
51
+ 'transitions.transitionIssue',
52
+ ],
53
+ },
54
+ gmail: {
55
+ sdk: 'googleapis',
56
+ description: 'Gmail email sending and management',
57
+ commonActions: [
58
+ 'users.messages.send',
59
+ 'users.messages.list',
60
+ 'users.messages.get',
61
+ 'users.labels.list',
62
+ 'users.drafts.create',
63
+ ],
64
+ },
65
+ outlook: {
66
+ sdk: '@microsoft/microsoft-graph-client',
67
+ description: 'Microsoft Outlook email and calendar',
68
+ commonActions: [
69
+ 'mail.sendMail',
70
+ 'mail.listMessages',
71
+ 'calendar.createEvent',
72
+ 'calendar.listEvents',
73
+ ],
74
+ },
75
+ linear: {
76
+ sdk: '@linear/sdk',
77
+ description: 'Linear issue tracking and project management',
78
+ commonActions: [
79
+ 'issues.create',
80
+ 'issues.update',
81
+ 'issues.archive',
82
+ 'projects.list',
83
+ 'cycles.list',
84
+ ],
85
+ },
86
+ notion: {
87
+ sdk: '@notionhq/client',
88
+ description: 'Notion pages and databases',
89
+ commonActions: [
90
+ 'pages.create',
91
+ 'pages.update',
92
+ 'databases.query',
93
+ 'blocks.children.append',
94
+ ],
95
+ },
96
+ discord: {
97
+ sdk: 'discord.js',
98
+ description: 'Discord messaging and server management',
99
+ commonActions: [
100
+ 'channels.send',
101
+ 'channels.createWebhook',
102
+ 'guilds.members.fetch',
103
+ ],
104
+ },
105
+ airtable: {
106
+ sdk: 'airtable',
107
+ description: 'Airtable database and records',
108
+ commonActions: [
109
+ 'tables.list',
110
+ 'records.create',
111
+ 'records.update',
112
+ 'records.list',
113
+ ],
114
+ },
115
+ confluence: {
116
+ sdk: 'confluence.js',
117
+ description: 'Atlassian Confluence wiki pages',
118
+ commonActions: [
119
+ 'content.getContent',
120
+ 'content.createContent',
121
+ 'content.updateContent',
122
+ 'space.getSpaces',
123
+ ],
124
+ },
125
+ http: {
126
+ sdk: 'built-in',
127
+ description: 'Generic HTTP requests to any API',
128
+ commonActions: ['request', 'get', 'post', 'put', 'delete'],
129
+ },
130
+ claude: {
131
+ sdk: '@anthropic-ai/sdk',
132
+ description: 'Claude AI for text generation and analysis',
133
+ commonActions: ['messages.create', 'completions.create'],
134
+ },
135
+ opencode: {
136
+ sdk: '@anthropic-ai/claude-agent-sdk',
137
+ description: 'OpenCode for code generation and analysis',
138
+ commonActions: ['generate', 'analyze', 'refactor'],
139
+ },
140
+ ollama: {
141
+ sdk: 'ollama',
142
+ description: 'Local Ollama LLM for AI tasks',
143
+ commonActions: ['generate', 'chat', 'embeddings'],
144
+ },
145
+ } as const;
146
+
147
+ // Base system prompt with comprehensive context
148
+ export const BASE_SYSTEM_PROMPT = `You are an expert workflow automation assistant for Marktoflow, a markdown-based workflow automation framework.
149
+
150
+ ## Your Role
151
+ Help users modify their workflows based on natural language requests. You must:
152
+ 1. Understand the current workflow structure
153
+ 2. Make precise modifications based on user requests
154
+ 3. Explain what changes you made and why
155
+ 4. Return valid YAML that can be parsed
156
+
157
+ ## Workflow Structure
158
+
159
+ A workflow consists of:
160
+ - **metadata**: name, description, version, author, tags
161
+ - **inputs**: declared input variables with types and defaults
162
+ - **tools**: service SDK configurations with authentication
163
+ - **steps**: array of actions to execute
164
+
165
+ ### Step Structure
166
+ \`\`\`yaml
167
+ - id: unique-step-id # Required: kebab-case identifier
168
+ name: "Human Readable Name" # Optional: display name
169
+ action: service.method # Required: SDK method to call
170
+ inputs: # Required: method parameters
171
+ param1: value
172
+ param2: "{{ variable }}" # Template variables
173
+ output_variable: result_name # Optional: store output
174
+ conditions: # Optional: when to run
175
+ - "{{ previous_step.success }}"
176
+ errorHandling: # Optional: error handling
177
+ action: retry # stop | continue | retry
178
+ maxRetries: 3
179
+ \`\`\`
180
+
181
+ ### Template Variables
182
+ - Access inputs: \`{{ inputs.variable_name }}\`
183
+ - Access step outputs: \`{{ step_id.field }}\` or \`{{ output_variable.field }}\`
184
+ - JavaScript expressions: \`{{ inputs.count > 10 ? "many" : "few" }}\`
185
+
186
+ ### Available Services
187
+ ${Object.entries(AVAILABLE_SERVICES)
188
+ .map(([name, info]) => `- **${name}**: ${info.description} (SDK: ${info.sdk})`)
189
+ .join('\n')}
190
+
191
+ ## Response Format
192
+
193
+ Always respond with:
194
+ 1. A brief explanation (1-3 sentences) of what you changed
195
+ 2. The complete modified workflow in a YAML code block
196
+
197
+ \`\`\`yaml
198
+ # Your modified workflow here
199
+ \`\`\`
200
+
201
+ ## Important Guidelines
202
+ - Only make the changes requested - don't "improve" other parts
203
+ - Preserve existing step IDs unless explicitly asked to rename
204
+ - Generate unique IDs for new steps (use kebab-case)
205
+ - Ensure all YAML is valid and properly indented
206
+ - Keep the same workflow structure (don't remove required sections)
207
+ `;
208
+
209
+ // Operation-specific prompts for different modification types
210
+ export const OPERATION_PROMPTS = {
211
+ addStep: `
212
+ ## Adding Steps
213
+ When adding a new step:
214
+ 1. Generate a unique, descriptive kebab-case ID (e.g., "send-slack-notification")
215
+ 2. Add a human-readable name
216
+ 3. Use the correct action format: service.method
217
+ 4. Include all required inputs for the action
218
+ 5. Consider adding an output_variable if the result will be used later
219
+ 6. Place the step at a logical position in the workflow
220
+
221
+ Common step patterns:
222
+ - Notifications: slack.chat.postMessage, gmail.users.messages.send
223
+ - API calls: http.request, github.pulls.get
224
+ - Data processing: Transform data between steps
225
+ `,
226
+
227
+ removeStep: `
228
+ ## Removing Steps
229
+ When removing a step:
230
+ 1. Remove the entire step block from the steps array
231
+ 2. Check if other steps reference this step's output_variable
232
+ 3. If references exist, either:
233
+ - Update those references to use a different source
234
+ - Warn the user about broken references
235
+ 4. Preserve the workflow structure and other steps
236
+ `,
237
+
238
+ modifyInputs: `
239
+ ## Modifying Step Inputs
240
+ When modifying inputs:
241
+ 1. Only change the specified inputs
242
+ 2. Preserve other inputs unless asked to remove them
243
+ 3. Use template variables for dynamic values: {{ variable }}
244
+ 4. Ensure the value type matches what the action expects
245
+ 5. Consider adding validation or error handling if needed
246
+ `,
247
+
248
+ addErrorHandling: `
249
+ ## Adding Error Handling
250
+ Error handling options:
251
+ - **stop**: Halt workflow execution on error (default)
252
+ - **continue**: Log error and continue to next step
253
+ - **retry**: Retry the step with backoff
254
+
255
+ Example:
256
+ \`\`\`yaml
257
+ errorHandling:
258
+ action: retry
259
+ maxRetries: 3
260
+ retryDelay: 1000 # milliseconds
261
+ fallback:
262
+ action: slack.chat.postMessage
263
+ inputs:
264
+ channel: "#alerts"
265
+ text: "Step {{ step.name }} failed: {{ error.message }}"
266
+ \`\`\`
267
+ `,
268
+
269
+ addConditions: `
270
+ ## Adding Conditions
271
+ Conditions control when a step executes. They are JavaScript-like expressions.
272
+
273
+ Examples:
274
+ \`\`\`yaml
275
+ conditions:
276
+ - "{{ previous_step.success === true }}"
277
+ - "{{ inputs.environment === 'production' }}"
278
+ - "{{ pr_details.state === 'open' && pr_details.draft === false }}"
279
+ \`\`\`
280
+
281
+ Common patterns:
282
+ - Check previous step success: \`{{ step_id.success }}\`
283
+ - Check variable values: \`{{ output_var.field === 'value' }}\`
284
+ - Check input values: \`{{ inputs.flag === true }}\`
285
+ - Combine conditions: \`{{ condition1 && condition2 }}\`
286
+ `,
287
+
288
+ createSubWorkflow: `
289
+ ## Creating Sub-Workflows
290
+ A sub-workflow is referenced by path instead of an action:
291
+
292
+ \`\`\`yaml
293
+ - id: run-notification-workflow
294
+ name: "Run Notification Workflow"
295
+ workflowPath: "./workflows/notify.md"
296
+ inputs:
297
+ message: "{{ previous_step.summary }}"
298
+ channel: "{{ inputs.notification_channel }}"
299
+ output_variable: notification_result
300
+ \`\`\`
301
+
302
+ When creating sub-workflows:
303
+ 1. Use workflowPath instead of action
304
+ 2. Pass inputs that the sub-workflow expects
305
+ 3. The sub-workflow's outputs are available via output_variable
306
+ `,
307
+
308
+ addTool: `
309
+ ## Adding Tool Configurations
310
+ Tools are configured with their SDK and authentication:
311
+
312
+ \`\`\`yaml
313
+ tools:
314
+ slack:
315
+ sdk: '@slack/web-api'
316
+ auth:
317
+ token: '\${SLACK_BOT_TOKEN}'
318
+ github:
319
+ sdk: '@octokit/rest'
320
+ auth:
321
+ token: '\${GITHUB_TOKEN}'
322
+ \`\`\`
323
+
324
+ Authentication patterns:
325
+ - Environment variables: \${ENV_VAR_NAME}
326
+ - OAuth tokens: Stored and retrieved automatically
327
+ - API keys: Configured per-tool
328
+ `,
329
+ };
330
+
331
+ /**
332
+ * Build a context-aware prompt based on the user's request
333
+ */
334
+ export function buildPrompt(
335
+ userRequest: string,
336
+ workflow: { metadata?: Record<string, unknown>; steps: unknown[]; tools?: Record<string, unknown> },
337
+ context?: {
338
+ selectedStepId?: string;
339
+ recentHistory?: string[];
340
+ }
341
+ ): { systemPrompt: string; userPrompt: string } {
342
+ // Detect the type of operation requested
343
+ const operations = detectOperations(userRequest);
344
+
345
+ // Build system prompt with relevant operation guides
346
+ let systemPrompt = BASE_SYSTEM_PROMPT;
347
+ for (const op of operations) {
348
+ if (OPERATION_PROMPTS[op as keyof typeof OPERATION_PROMPTS]) {
349
+ systemPrompt += '\n' + OPERATION_PROMPTS[op as keyof typeof OPERATION_PROMPTS];
350
+ }
351
+ }
352
+
353
+ // Build user prompt with context
354
+ let userPrompt = `Current workflow:\n\`\`\`yaml\n${formatWorkflow(workflow)}\n\`\`\`\n\n`;
355
+
356
+ if (context?.selectedStepId) {
357
+ const selectedStep = workflow.steps?.find(
358
+ (s: any) => s.id === context.selectedStepId
359
+ );
360
+ if (selectedStep) {
361
+ userPrompt += `Currently selected step: "${context.selectedStepId}"\n\n`;
362
+ }
363
+ }
364
+
365
+ if (context?.recentHistory && context.recentHistory.length > 0) {
366
+ userPrompt += `Recent changes:\n${context.recentHistory.map((h) => `- ${h}`).join('\n')}\n\n`;
367
+ }
368
+
369
+ userPrompt += `User request: ${userRequest}`;
370
+
371
+ return { systemPrompt, userPrompt };
372
+ }
373
+
374
+ /**
375
+ * Detect what type of operations the user is requesting
376
+ */
377
+ function detectOperations(request: string): string[] {
378
+ const lower = request.toLowerCase();
379
+ const operations: string[] = [];
380
+
381
+ if (lower.includes('add') && (lower.includes('step') || lower.includes('action'))) {
382
+ operations.push('addStep');
383
+ }
384
+ if (lower.includes('remove') || lower.includes('delete')) {
385
+ operations.push('removeStep');
386
+ }
387
+ if (lower.includes('change') || lower.includes('modify') || lower.includes('update')) {
388
+ operations.push('modifyInputs');
389
+ }
390
+ if (lower.includes('error') || lower.includes('retry') || lower.includes('fallback')) {
391
+ operations.push('addErrorHandling');
392
+ }
393
+ if (lower.includes('condition') || lower.includes('if') || lower.includes('when')) {
394
+ operations.push('addConditions');
395
+ }
396
+ if (lower.includes('sub-workflow') || lower.includes('subworkflow') || lower.includes('nested')) {
397
+ operations.push('createSubWorkflow');
398
+ }
399
+ if (lower.includes('tool') || lower.includes('sdk') || lower.includes('connect')) {
400
+ operations.push('addTool');
401
+ }
402
+
403
+ // Default to addStep if no specific operation detected
404
+ if (operations.length === 0) {
405
+ operations.push('addStep');
406
+ }
407
+
408
+ return operations;
409
+ }
410
+
411
+ /**
412
+ * Format workflow for prompt (simplified YAML)
413
+ */
414
+ function formatWorkflow(workflow: {
415
+ metadata?: Record<string, unknown>;
416
+ steps: unknown[];
417
+ tools?: Record<string, unknown>;
418
+ }): string {
419
+ const { stringify } = require('yaml');
420
+ return stringify(workflow, { indent: 2, lineWidth: 0 });
421
+ }
422
+
423
+ /**
424
+ * Generate contextual suggestions based on workflow state
425
+ */
426
+ export function generateSuggestions(
427
+ workflow: { metadata?: Record<string, unknown>; steps: unknown[]; tools?: Record<string, unknown> },
428
+ selectedStepId?: string
429
+ ): string[] {
430
+ const suggestions: string[] = [];
431
+ const steps = workflow.steps || [];
432
+
433
+ // No steps - suggest getting started
434
+ if (steps.length === 0) {
435
+ return [
436
+ 'Add a step to send a Slack message',
437
+ 'Add a step to fetch data from GitHub',
438
+ 'Add an HTTP request step',
439
+ 'Create a workflow that monitors a webhook',
440
+ ];
441
+ }
442
+
443
+ // Check for missing error handling
444
+ const stepsWithoutErrorHandling = steps.filter((s: any) => !s.errorHandling);
445
+ if (stepsWithoutErrorHandling.length > 0) {
446
+ suggestions.push('Add error handling with retries to all steps');
447
+ }
448
+
449
+ // Check for missing notifications
450
+ const hasNotification = steps.some(
451
+ (s: any) =>
452
+ s.action?.includes('slack') ||
453
+ s.action?.includes('gmail') ||
454
+ s.action?.includes('discord')
455
+ );
456
+ if (!hasNotification) {
457
+ suggestions.push('Add a Slack notification at the end');
458
+ }
459
+
460
+ // Step-specific suggestions
461
+ if (selectedStepId) {
462
+ const step = steps.find((s: any) => s.id === selectedStepId) as any;
463
+ if (step) {
464
+ if (!step.errorHandling) {
465
+ suggestions.push(`Add retry logic to "${step.name || step.id}"`);
466
+ }
467
+ if (!step.conditions || step.conditions.length === 0) {
468
+ suggestions.push(`Add a condition to "${step.name || step.id}"`);
469
+ }
470
+ suggestions.push(`Duplicate "${step.name || step.id}" with modifications`);
471
+ }
472
+ }
473
+
474
+ // General suggestions
475
+ if (steps.length >= 3) {
476
+ suggestions.push('Convert these steps into a reusable sub-workflow');
477
+ }
478
+ suggestions.push('Add a step to log results to a database');
479
+ suggestions.push('Add parallel execution for independent steps');
480
+
481
+ return suggestions.slice(0, 5);
482
+ }