tachibot-mcp 2.0.2

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 (214) hide show
  1. package/.env.example +260 -0
  2. package/CHANGELOG.md +54 -0
  3. package/CODE_OF_CONDUCT.md +56 -0
  4. package/CONTRIBUTING.md +54 -0
  5. package/Dockerfile +36 -0
  6. package/LICENSE +644 -0
  7. package/README.md +201 -0
  8. package/SECURITY.md +95 -0
  9. package/dist/personality/komaai-expressions.js +12 -0
  10. package/dist/profiles/balanced.json +33 -0
  11. package/dist/profiles/code_focus.json +33 -0
  12. package/dist/profiles/full.json +33 -0
  13. package/dist/profiles/minimal.json +33 -0
  14. package/dist/profiles/research_power.json +33 -0
  15. package/dist/scripts/build-profiles.js +46 -0
  16. package/dist/src/application/services/focus/FocusModeRegistry.js +46 -0
  17. package/dist/src/application/services/focus/FocusTool.service.js +109 -0
  18. package/dist/src/application/services/focus/ModeRegistry.js +46 -0
  19. package/dist/src/application/services/focus/modes/focus-deep.mode.js +27 -0
  20. package/dist/src/application/services/focus/modes/status.mode.js +50 -0
  21. package/dist/src/application/services/focus/modes/tachibot-status.mode.js +50 -0
  22. package/dist/src/collaborative-orchestrator.js +391 -0
  23. package/dist/src/config/model-constants.js +188 -0
  24. package/dist/src/config/model-defaults.js +57 -0
  25. package/dist/src/config/model-preferences.js +382 -0
  26. package/dist/src/config/timeout-config.js +130 -0
  27. package/dist/src/config.js +173 -0
  28. package/dist/src/domain/interfaces/IFocusMode.js +5 -0
  29. package/dist/src/domain/interfaces/IProvider.js +6 -0
  30. package/dist/src/domain/interfaces/ITool.js +5 -0
  31. package/dist/src/focus-deep.js +245 -0
  32. package/dist/src/infrastructure/ascii/art/robots.ascii.js +16 -0
  33. package/dist/src/mcp-client.js +90 -0
  34. package/dist/src/memory/index.js +17 -0
  35. package/dist/src/memory/memory-config.js +135 -0
  36. package/dist/src/memory/memory-interface.js +174 -0
  37. package/dist/src/memory/memory-manager.js +383 -0
  38. package/dist/src/memory/providers/devlog-provider.js +385 -0
  39. package/dist/src/memory/providers/hybrid-provider.js +399 -0
  40. package/dist/src/memory/providers/local-provider.js +388 -0
  41. package/dist/src/memory/providers/mem0-provider.js +337 -0
  42. package/dist/src/modes/architect.js +477 -0
  43. package/dist/src/modes/auditor.js +362 -0
  44. package/dist/src/modes/challenger.js +841 -0
  45. package/dist/src/modes/code-reviewer.js +382 -0
  46. package/dist/src/modes/commit-guardian.js +424 -0
  47. package/dist/src/modes/documentation-writer.js +572 -0
  48. package/dist/src/modes/scout.js +587 -0
  49. package/dist/src/modes/shared/helpers/challenger-helpers.js +454 -0
  50. package/dist/src/modes/shared/helpers/index.js +17 -0
  51. package/dist/src/modes/shared/helpers/scout-helpers.js +270 -0
  52. package/dist/src/modes/shared/helpers/verifier-helpers.js +332 -0
  53. package/dist/src/modes/test-architect.js +767 -0
  54. package/dist/src/modes/verifier.js +378 -0
  55. package/dist/src/monitoring/performance-monitor.js +435 -0
  56. package/dist/src/optimization/batch-executor.js +121 -0
  57. package/dist/src/optimization/context-pruner.js +196 -0
  58. package/dist/src/optimization/cost-monitor.js +338 -0
  59. package/dist/src/optimization/index.js +65 -0
  60. package/dist/src/optimization/model-router.js +264 -0
  61. package/dist/src/optimization/result-cache.js +114 -0
  62. package/dist/src/optimization/token-optimizer.js +257 -0
  63. package/dist/src/optimization/token-tracker.js +118 -0
  64. package/dist/src/orchestrator-instructions.js +128 -0
  65. package/dist/src/orchestrator-lite.js +139 -0
  66. package/dist/src/orchestrator.js +191 -0
  67. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionEngine.js +1 -0
  68. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionStrategy.js +5 -0
  69. package/dist/src/orchestrators/collaborative/interfaces/IVisualizationRenderer.js +1 -0
  70. package/dist/src/orchestrators/collaborative/registries/ModelProviderRegistry.js +95 -0
  71. package/dist/src/orchestrators/collaborative/registries/ToolAdapterRegistry.js +64 -0
  72. package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +502 -0
  73. package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +206 -0
  74. package/dist/src/orchestrators/collaborative/types/session-types.js +5 -0
  75. package/dist/src/profiles/balanced.js +37 -0
  76. package/dist/src/profiles/code_focus.js +37 -0
  77. package/dist/src/profiles/debug_intensive.js +59 -0
  78. package/dist/src/profiles/full.js +37 -0
  79. package/dist/src/profiles/minimal.js +37 -0
  80. package/dist/src/profiles/research_code.js +59 -0
  81. package/dist/src/profiles/research_power.js +37 -0
  82. package/dist/src/profiles/types.js +5 -0
  83. package/dist/src/profiles/workflow_builder.js +53 -0
  84. package/dist/src/prompt-engineer-lite.js +78 -0
  85. package/dist/src/prompt-engineer.js +399 -0
  86. package/dist/src/reasoning-chain.js +508 -0
  87. package/dist/src/sequential-thinking.js +291 -0
  88. package/dist/src/server-diagnostic.js +74 -0
  89. package/dist/src/server-raw.js +158 -0
  90. package/dist/src/server-simple.js +58 -0
  91. package/dist/src/server.js +514 -0
  92. package/dist/src/session/session-logger.js +617 -0
  93. package/dist/src/session/session-manager.js +571 -0
  94. package/dist/src/session/session-tools.js +400 -0
  95. package/dist/src/tools/advanced-modes.js +200 -0
  96. package/dist/src/tools/claude-integration.js +356 -0
  97. package/dist/src/tools/consolidated/ai-router.js +174 -0
  98. package/dist/src/tools/consolidated/ai-tool.js +48 -0
  99. package/dist/src/tools/consolidated/brainstorm-tool.js +87 -0
  100. package/dist/src/tools/consolidated/environment-detector.js +80 -0
  101. package/dist/src/tools/consolidated/index.js +50 -0
  102. package/dist/src/tools/consolidated/search-tool.js +110 -0
  103. package/dist/src/tools/consolidated/workflow-tool.js +238 -0
  104. package/dist/src/tools/gemini-tools.js +329 -0
  105. package/dist/src/tools/grok-enhanced.js +376 -0
  106. package/dist/src/tools/grok-tools.js +299 -0
  107. package/dist/src/tools/lmstudio-tools.js +223 -0
  108. package/dist/src/tools/openai-tools.js +498 -0
  109. package/dist/src/tools/openrouter-tools.js +317 -0
  110. package/dist/src/tools/optimized-wrapper.js +204 -0
  111. package/dist/src/tools/perplexity-tools.js +294 -0
  112. package/dist/src/tools/pingpong-tool.js +343 -0
  113. package/dist/src/tools/qwen-wrapper.js +74 -0
  114. package/dist/src/tools/tool-router.js +444 -0
  115. package/dist/src/tools/unified-ai-provider.js +260 -0
  116. package/dist/src/tools/workflow-runner.js +425 -0
  117. package/dist/src/tools/workflow-validator-tool.js +107 -0
  118. package/dist/src/types.js +23 -0
  119. package/dist/src/utils/input-validator.js +130 -0
  120. package/dist/src/utils/model-router.js +91 -0
  121. package/dist/src/utils/progress-stream.js +255 -0
  122. package/dist/src/utils/provider-router.js +88 -0
  123. package/dist/src/utils/smart-api-client.js +146 -0
  124. package/dist/src/utils/table-builder.js +218 -0
  125. package/dist/src/utils/timestamp-formatter.js +134 -0
  126. package/dist/src/utils/tool-compressor.js +257 -0
  127. package/dist/src/utils/tool-config.js +201 -0
  128. package/dist/src/validators/dependency-graph-validator.js +147 -0
  129. package/dist/src/validators/interpolation-validator.js +222 -0
  130. package/dist/src/validators/output-usage-validator.js +151 -0
  131. package/dist/src/validators/syntax-validator.js +102 -0
  132. package/dist/src/validators/tool-registry-validator.js +123 -0
  133. package/dist/src/validators/tool-types.js +97 -0
  134. package/dist/src/validators/types.js +8 -0
  135. package/dist/src/validators/workflow-validator.js +134 -0
  136. package/dist/src/visualizer-lite.js +42 -0
  137. package/dist/src/visualizer.js +179 -0
  138. package/dist/src/workflows/circuit-breaker.js +199 -0
  139. package/dist/src/workflows/custom-workflows.js +451 -0
  140. package/dist/src/workflows/engine/AutoSynthesizer.js +97 -0
  141. package/dist/src/workflows/engine/StepParameterResolver.js +74 -0
  142. package/dist/src/workflows/engine/VariableInterpolator.js +123 -0
  143. package/dist/src/workflows/engine/WorkflowDiscovery.js +125 -0
  144. package/dist/src/workflows/engine/WorkflowExecutionEngine.js +485 -0
  145. package/dist/src/workflows/engine/WorkflowExecutor.js +113 -0
  146. package/dist/src/workflows/engine/WorkflowFileManager.js +244 -0
  147. package/dist/src/workflows/engine/WorkflowHelpers.js +114 -0
  148. package/dist/src/workflows/engine/WorkflowOutputFormatter.js +83 -0
  149. package/dist/src/workflows/engine/events/WorkflowEventBus.js +132 -0
  150. package/dist/src/workflows/engine/events/interfaces/IEventBus.js +5 -0
  151. package/dist/src/workflows/engine/handlers/ErrorRecoveryHandler.js +162 -0
  152. package/dist/src/workflows/engine/handlers/PromptEnhancementHandler.js +115 -0
  153. package/dist/src/workflows/engine/handlers/SessionPersistenceHandler.js +167 -0
  154. package/dist/src/workflows/engine/handlers/StepExecutionHandler.js +231 -0
  155. package/dist/src/workflows/engine/handlers/ToolInvocationHandler.js +46 -0
  156. package/dist/src/workflows/engine/interfaces/IAutoSynthesizer.js +5 -0
  157. package/dist/src/workflows/engine/interfaces/IStepParameterResolver.js +5 -0
  158. package/dist/src/workflows/engine/interfaces/IVariableInterpolator.js +5 -0
  159. package/dist/src/workflows/engine/interfaces/IWorkflowDiscovery.js +4 -0
  160. package/dist/src/workflows/engine/interfaces/IWorkflowFileManager.js +5 -0
  161. package/dist/src/workflows/engine/interfaces/IWorkflowOutputFormatter.js +5 -0
  162. package/dist/src/workflows/engine/state/WorkflowStateMachine.js +194 -0
  163. package/dist/src/workflows/engine/state/interfaces/IStateMachine.js +17 -0
  164. package/dist/src/workflows/fallback-strategies.js +373 -0
  165. package/dist/src/workflows/message-queue.js +455 -0
  166. package/dist/src/workflows/model-router.js +189 -0
  167. package/dist/src/workflows/orchestrator-examples.js +174 -0
  168. package/dist/src/workflows/orchestrator-integration.js +200 -0
  169. package/dist/src/workflows/self-healing.js +524 -0
  170. package/dist/src/workflows/tool-mapper.js +407 -0
  171. package/dist/src/workflows/tool-orchestrator.js +796 -0
  172. package/dist/src/workflows/workflow-engine.js +573 -0
  173. package/dist/src/workflows/workflow-parser.js +283 -0
  174. package/dist/src/workflows/workflow-types.js +95 -0
  175. package/dist/src/workflows.js +568 -0
  176. package/dist/test-workflow-file-output.js +93 -0
  177. package/docs/API_KEYS.md +570 -0
  178. package/docs/CLAUDE_CODE_SETUP.md +181 -0
  179. package/docs/CLAUDE_DESKTOP_MANUAL.md +127 -0
  180. package/docs/CONFIGURATION.md +745 -0
  181. package/docs/FOCUS_MODES.md +240 -0
  182. package/docs/INSTALLATION_BOTH.md +145 -0
  183. package/docs/TERMS.md +352 -0
  184. package/docs/TOOLS_REFERENCE.md +1622 -0
  185. package/docs/TOOL_PARAMETERS.md +496 -0
  186. package/docs/TOOL_PROFILES.md +236 -0
  187. package/docs/WORKFLOWS.md +987 -0
  188. package/docs/WORKFLOW_OUTPUT.md +198 -0
  189. package/docs/WORKFLOW_PROGRESS_TRACKING.md +305 -0
  190. package/docs/workflows/design-brainstorm.md +335 -0
  191. package/package.json +97 -0
  192. package/profiles/balanced.json +37 -0
  193. package/profiles/code_focus.json +37 -0
  194. package/profiles/debug_intensive.json +34 -0
  195. package/profiles/full.json +37 -0
  196. package/profiles/minimal.json +37 -0
  197. package/profiles/research_power.json +37 -0
  198. package/profiles/workflow_builder.json +37 -0
  199. package/smithery.yaml +66 -0
  200. package/start.sh +8 -0
  201. package/tools.config.json +81 -0
  202. package/tsconfig.json +18 -0
  203. package/workflows/accessibility-code-audit.yaml +92 -0
  204. package/workflows/code-architecture-review.yaml +202 -0
  205. package/workflows/code-review.yaml +142 -0
  206. package/workflows/core/iterative-problem-solver.yaml +283 -0
  207. package/workflows/creative-brainstorm-yaml.yaml +215 -0
  208. package/workflows/pingpong.yaml +141 -0
  209. package/workflows/system/README.md +412 -0
  210. package/workflows/system/challenger.yaml +175 -0
  211. package/workflows/system/scout.yaml +164 -0
  212. package/workflows/system/verifier.yaml +133 -0
  213. package/workflows/ultra-creative-brainstorm.yaml +318 -0
  214. package/workflows/ux-research-flow.yaml +92 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Workflow File Manager
3
+ * Handles file references, output saving, and manifest management
4
+ */
5
+ import { promises as fsPromises } from 'fs';
6
+ import * as path from 'path';
7
+ export class WorkflowFileManager {
8
+ /**
9
+ * Extracts a summary from content (first 200 chars)
10
+ */
11
+ extractSummary(result) {
12
+ // Handle null/undefined explicitly
13
+ if (result === null)
14
+ return '[null]';
15
+ if (result === undefined)
16
+ return '[undefined]';
17
+ // Handle primitives (including falsy: 0, false, "")
18
+ if (typeof result === 'string') {
19
+ return this.truncateString(result, 200);
20
+ }
21
+ if (typeof result === 'number' || typeof result === 'boolean') {
22
+ return String(result);
23
+ }
24
+ // Handle objects with summary property
25
+ if (result && typeof result === 'object' && 'summary' in result) {
26
+ const summary = result.summary;
27
+ if (typeof summary === 'string') {
28
+ return this.truncateString(summary, 200);
29
+ }
30
+ // If summary is not a string, JSON.stringify it
31
+ try {
32
+ const summaryStr = JSON.stringify(summary, this.getCircularReplacer());
33
+ return this.truncateString(summaryStr, 200);
34
+ }
35
+ catch (error) {
36
+ return '[Summary unavailable]';
37
+ }
38
+ }
39
+ // Default: JSON.stringify with circular ref handling
40
+ try {
41
+ const resultStr = JSON.stringify(result, this.getCircularReplacer());
42
+ return this.truncateString(resultStr, 200);
43
+ }
44
+ catch (error) {
45
+ return '[Summary unavailable]';
46
+ }
47
+ }
48
+ /**
49
+ * Creates a file reference for step output
50
+ */
51
+ async createFileReference(options) {
52
+ const { stepName, content, workflowId, workflowName, saveToFile: initialSaveToFile, outputDir, stepNumber, modelName } = options;
53
+ const id = `${workflowId}-${stepName}-${Date.now()}`;
54
+ const summary = this.extractSummary(content);
55
+ const sizeBytes = Buffer.byteLength(content, 'utf-8');
56
+ let filePath = null;
57
+ let _inMemoryContent = undefined;
58
+ let saveToFile = initialSaveToFile;
59
+ // Auto-promote large in-memory results to file (>1MB)
60
+ if (!saveToFile && sizeBytes > 1000000) {
61
+ console.error(`⚠️ Step ${stepName} output is ${sizeBytes} bytes - forcing file save`);
62
+ saveToFile = true;
63
+ }
64
+ if (saveToFile && outputDir) {
65
+ // Save to file with step number and datetime
66
+ const safeStepName = stepName.replace(/[^a-zA-Z0-9_-]/g, '_');
67
+ // Generate datetime string: YYYY-MM-DD-HH-MM-SS-DayName
68
+ const now = new Date();
69
+ const year = now.getFullYear();
70
+ const month = String(now.getMonth() + 1).padStart(2, '0');
71
+ const day = String(now.getDate()).padStart(2, '0');
72
+ const hours = String(now.getHours()).padStart(2, '0');
73
+ const minutes = String(now.getMinutes()).padStart(2, '0');
74
+ const seconds = String(now.getSeconds()).padStart(2, '0');
75
+ const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
76
+ const dayName = dayNames[now.getDay()];
77
+ const datetime = `${year}-${month}-${day}-${hours}-${minutes}-${seconds}-${dayName}`;
78
+ // Sanitize model name for filename (remove special chars, keep alphanumeric and hyphens)
79
+ const safeModelName = modelName ? modelName.replace(/[^a-zA-Z0-9-]/g, '-') : undefined;
80
+ // Build filename: {stepNumber}-{stepName}-{modelName}-{datetime}.md
81
+ const filenamePrefix = stepNumber ? `${stepNumber}-` : '';
82
+ const modelSuffix = safeModelName ? `-${safeModelName}` : '';
83
+ const filename = `${filenamePrefix}${safeStepName}${modelSuffix}-${datetime}.md`;
84
+ filePath = path.join(outputDir, filename);
85
+ try {
86
+ // Format as markdown with metadata
87
+ const metadataLines = [
88
+ `# ${stepName}`,
89
+ '',
90
+ `**Workflow:** ${workflowName}`,
91
+ `**Workflow ID:** ${workflowId}`,
92
+ `**Timestamp:** ${new Date().toISOString()}`,
93
+ `**Size:** ${sizeBytes} bytes`,
94
+ ...(modelName ? [`**Model:** ${modelName}`] : []),
95
+ '',
96
+ '## Output',
97
+ '',
98
+ content,
99
+ ''
100
+ ];
101
+ await fsPromises.writeFile(filePath, metadataLines.join('\n'));
102
+ console.error(`💾 Saved step output to: ${filePath}`);
103
+ }
104
+ catch (error) {
105
+ console.error(`⚠️ File save failed for ${stepName}, falling back to in-memory:`, error);
106
+ filePath = null;
107
+ _inMemoryContent = content;
108
+ }
109
+ }
110
+ else {
111
+ // Keep in memory
112
+ _inMemoryContent = content;
113
+ }
114
+ // Create lazy loader with caching
115
+ let _cachedContent = null;
116
+ const getContent = async () => {
117
+ // Return cached content if available
118
+ if (_cachedContent)
119
+ return _cachedContent;
120
+ if (filePath) {
121
+ try {
122
+ const markdown = await fsPromises.readFile(filePath, 'utf-8');
123
+ // Extract content from markdown (skip metadata)
124
+ const outputMatch = markdown.match(/## Output\s*\n\n([\s\S]*)/);
125
+ _cachedContent = outputMatch ? outputMatch[1].trim() : markdown;
126
+ return _cachedContent;
127
+ }
128
+ catch (error) {
129
+ throw new Error(`Failed to load content from ${filePath}: ${error}`);
130
+ }
131
+ }
132
+ if (_inMemoryContent !== undefined) {
133
+ _cachedContent = _inMemoryContent;
134
+ return _cachedContent;
135
+ }
136
+ throw new Error(`No content available for step ${stepName}`);
137
+ };
138
+ return {
139
+ id,
140
+ stepName,
141
+ summary,
142
+ filePath,
143
+ sizeBytes,
144
+ getContent,
145
+ _inMemoryContent
146
+ };
147
+ }
148
+ /**
149
+ * Initializes output directory for workflow execution
150
+ */
151
+ async initializeOutputDirectory(workflowName, workflowId, query) {
152
+ const outputDir = path.join(process.cwd(), 'workflow-output', workflowName, workflowId);
153
+ try {
154
+ await fsPromises.mkdir(outputDir, { recursive: true });
155
+ // Create initial manifest
156
+ const manifest = {
157
+ workflowId,
158
+ workflowName,
159
+ startTime: new Date().toISOString(),
160
+ endTime: null,
161
+ status: 'running',
162
+ query,
163
+ steps: []
164
+ };
165
+ await fsPromises.writeFile(path.join(outputDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
166
+ console.error(`📁 Workflow output directory: ${outputDir}`);
167
+ return outputDir;
168
+ }
169
+ catch (error) {
170
+ console.error('⚠️ Failed to initialize workflow directory:', error);
171
+ throw error;
172
+ }
173
+ }
174
+ /**
175
+ * Updates workflow manifest with step status
176
+ */
177
+ async updateManifest(outputDir, stepId, status, outputFile, error) {
178
+ const manifestPath = path.join(outputDir, 'manifest.json');
179
+ try {
180
+ const data = await fsPromises.readFile(manifestPath, 'utf-8');
181
+ const manifest = JSON.parse(data);
182
+ // Update or add step
183
+ const existingIdx = manifest.steps.findIndex(s => s.id === stepId);
184
+ const stepData = {
185
+ id: stepId,
186
+ status,
187
+ outputFile,
188
+ error,
189
+ timestamp: new Date().toISOString()
190
+ };
191
+ if (existingIdx >= 0) {
192
+ manifest.steps[existingIdx] = stepData;
193
+ }
194
+ else {
195
+ manifest.steps.push(stepData);
196
+ }
197
+ // Update workflow status
198
+ const allCompleted = manifest.steps.every(s => s.status === 'completed');
199
+ const anyFailed = manifest.steps.some(s => s.status === 'failed');
200
+ if (anyFailed) {
201
+ manifest.status = 'failed';
202
+ manifest.endTime = new Date().toISOString();
203
+ }
204
+ else if (allCompleted) {
205
+ manifest.status = 'completed';
206
+ manifest.endTime = new Date().toISOString();
207
+ }
208
+ await fsPromises.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
209
+ }
210
+ catch (error) {
211
+ console.error('Failed to update manifest:', error);
212
+ // Don't throw - manifest updates are not critical
213
+ }
214
+ }
215
+ /**
216
+ * Unicode-safe truncation helper
217
+ */
218
+ truncateString(str, maxLength) {
219
+ if (str.length <= maxLength) {
220
+ return str;
221
+ }
222
+ // Use Array.from() for Unicode safety (handles emoji, multi-byte chars)
223
+ const chars = Array.from(str);
224
+ if (chars.length <= maxLength) {
225
+ return str;
226
+ }
227
+ return chars.slice(0, maxLength).join('') + '...';
228
+ }
229
+ /**
230
+ * Circular reference replacer for JSON.stringify
231
+ */
232
+ getCircularReplacer() {
233
+ const seen = new WeakSet();
234
+ return (key, value) => {
235
+ if (typeof value === 'object' && value !== null) {
236
+ if (seen.has(value)) {
237
+ return '[Circular]';
238
+ }
239
+ seen.add(value);
240
+ }
241
+ return value;
242
+ };
243
+ }
244
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Workflow Helper Utilities
3
+ * Small helper functions for workflow processing
4
+ */
5
+ export class WorkflowHelpers {
6
+ /**
7
+ * Group workflow steps by dependencies for parallel execution
8
+ * Steps with no dependencies run first, then steps depending on them, etc.
9
+ */
10
+ static groupStepsByDependencies(steps) {
11
+ const groups = [];
12
+ const processed = new Set();
13
+ while (processed.size < steps.length) {
14
+ const group = [];
15
+ for (const step of steps) {
16
+ if (processed.has(step.name))
17
+ continue;
18
+ // Check if all dependencies are satisfied
19
+ const ready = !step.dependsOn ||
20
+ step.dependsOn.every(dep => processed.has(dep));
21
+ if (ready) {
22
+ group.push(step);
23
+ }
24
+ }
25
+ if (group.length === 0) {
26
+ throw new Error('Circular dependency detected in workflow steps');
27
+ }
28
+ groups.push(group);
29
+ group.forEach(step => processed.add(step.name));
30
+ }
31
+ return groups;
32
+ }
33
+ /**
34
+ * Calculate step numbers for display (handles parallel execution)
35
+ * Example: step1=1, step2=2, step3=3a, step4=3b (parallel), step5=4
36
+ *
37
+ * Rules:
38
+ * - Steps are SEQUENTIAL by default (1, 2, 3...)
39
+ * - Steps marked with `parallel: true` share the same number (3a, 3b)
40
+ * - The `parallel` flag means "run in parallel with NEXT step"
41
+ */
42
+ static calculateStepNumbers(workflow) {
43
+ const stepNumbers = new Map();
44
+ let sequentialNumber = 1;
45
+ let i = 0;
46
+ while (i < workflow.steps.length) {
47
+ const step = workflow.steps[i];
48
+ // Check if this step and subsequent steps form a parallel group
49
+ const parallelGroup = [step];
50
+ let j = i + 1;
51
+ // If current step has parallel flag, collect all subsequent parallel steps
52
+ if (step.parallel === true) {
53
+ while (j < workflow.steps.length && workflow.steps[j - 1].parallel === true) {
54
+ parallelGroup.push(workflow.steps[j]);
55
+ j++;
56
+ }
57
+ }
58
+ // Assign numbers
59
+ console.error(`[WorkflowHelpers] Step ${step.name}: parallelGroup.length = ${parallelGroup.length}`);
60
+ if (parallelGroup.length === 1) {
61
+ // Single sequential step
62
+ stepNumbers.set(step.name, String(sequentialNumber));
63
+ console.error(`[WorkflowHelpers] Assigned sequential: ${step.name} -> ${sequentialNumber}`);
64
+ }
65
+ else {
66
+ // Parallel group - use letters (3a, 3b, 3c)
67
+ console.error(`[WorkflowHelpers] Parallel group with ${parallelGroup.length} steps`);
68
+ parallelGroup.forEach((parallelStep, index) => {
69
+ const letter = String.fromCharCode(97 + index); // 97 = 'a'
70
+ stepNumbers.set(parallelStep.name, `${sequentialNumber}${letter}`);
71
+ console.error(`[WorkflowHelpers] Assigned parallel: ${parallelStep.name} -> ${sequentialNumber}${letter}`);
72
+ });
73
+ }
74
+ sequentialNumber++;
75
+ i = j;
76
+ }
77
+ return stepNumbers;
78
+ }
79
+ /**
80
+ * Check if two dependency sets are identical
81
+ */
82
+ static haveSameDependencies(deps1, deps2) {
83
+ if (deps1.size !== deps2.size)
84
+ return false;
85
+ for (const dep of deps1) {
86
+ if (!deps2.has(dep))
87
+ return false;
88
+ }
89
+ return true;
90
+ }
91
+ /**
92
+ * Estimate token count for any data type
93
+ * Uses character-based approximation: tokens ≈ characters / 4
94
+ */
95
+ static estimateTokens(data) {
96
+ const text = typeof data === 'string' ? data : JSON.stringify(data);
97
+ return Math.ceil(text.length / 4);
98
+ }
99
+ /**
100
+ * Evaluate a condition string (basic implementation)
101
+ * Returns true/false based on condition evaluation
102
+ */
103
+ static evaluateCondition(condition, context) {
104
+ // Simple equality check: "variable == value"
105
+ const match = condition.match(/^(\w+)\s*==\s*(.+)$/);
106
+ if (match) {
107
+ const [, variable, expectedValue] = match;
108
+ const actualValue = context[variable];
109
+ return String(actualValue).trim() === expectedValue.trim().replace(/['"]/g, '');
110
+ }
111
+ // Default: if variable exists and is truthy
112
+ return !!context[condition];
113
+ }
114
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Workflow Output Formatter
3
+ * Formats workflow execution results in multiple formats (summary, detailed, JSON)
4
+ */
5
+ export class WorkflowOutputFormatter {
6
+ /**
7
+ * Formats workflow execution results
8
+ */
9
+ format(execution, format, truncateSteps, maxStepTokens) {
10
+ // Check if auto-synthesis ran - if so, return ONLY the synthesis
11
+ const synthesisStep = execution.outputs.find(step => step.step === 'auto-synthesis');
12
+ if (synthesisStep) {
13
+ // Auto-synthesis ran - return only the synthesis output to prevent MCP 25k limit
14
+ return synthesisStep.output;
15
+ }
16
+ switch (format) {
17
+ case "json":
18
+ return {
19
+ workflowName: execution.workflowName,
20
+ workflowId: execution.workflowId,
21
+ outputDir: execution.outputDir,
22
+ status: execution.status,
23
+ steps: execution.outputs.map(out => ({
24
+ step: out.step,
25
+ summary: out.output,
26
+ filePath: out.filePath
27
+ }))
28
+ };
29
+ case "detailed":
30
+ return this.formatDetailed(execution);
31
+ case "summary":
32
+ default:
33
+ return this.formatSummary(execution);
34
+ }
35
+ }
36
+ /**
37
+ * Formats detailed output with all step information
38
+ */
39
+ formatDetailed(execution) {
40
+ const duration = execution.endTime && execution.startTime
41
+ ? (execution.endTime.getTime() - execution.startTime.getTime()) / 1000
42
+ : 0;
43
+ let output = `# Workflow: ${execution.workflowName}\n\n`;
44
+ output += `**Duration:** ${duration.toFixed(1)}s\n`;
45
+ output += `**Steps Completed:** ${execution.outputs.length}\n`;
46
+ if (execution.outputDir) {
47
+ output += `**Output Directory:** ${execution.outputDir}\n`;
48
+ }
49
+ output += `\n---\n\n`;
50
+ // Show summaries for each step
51
+ for (let i = 0; i < execution.outputs.length; i++) {
52
+ const step = execution.outputs[i];
53
+ output += `## Step ${i + 1}: ${step.step}\n\n`;
54
+ if (step.input && step.input !== '[cached]') {
55
+ output += `**Input:**\n${step.input}...\n\n`;
56
+ }
57
+ output += `${step.output}\n\n`;
58
+ if (step.filePath) {
59
+ output += `📄 *Full output saved to: ${step.filePath}*\n\n`;
60
+ }
61
+ output += `---\n\n`;
62
+ }
63
+ output += `\n**Workflow Complete** ✓\n\n`;
64
+ output += `**Next Steps:**\nUse Read tool to analyze full outputs from saved files.\n`;
65
+ return output;
66
+ }
67
+ /**
68
+ * Formats summary output with last step and file paths
69
+ */
70
+ formatSummary(execution) {
71
+ const lastOutput = execution.outputs[execution.outputs.length - 1];
72
+ const savedFiles = execution.outputs
73
+ .filter(out => out.filePath)
74
+ .map(out => ` - ${out.step}: ${out.filePath}`)
75
+ .join('\n');
76
+ let result = lastOutput?.output || "Workflow completed";
77
+ if (savedFiles) {
78
+ result += `\n\n**Files saved:**\n${savedFiles}\n\n`;
79
+ result += `Use Read tool to access full content for detailed analysis.`;
80
+ }
81
+ return result;
82
+ }
83
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Workflow Event Bus
3
+ * Central pub/sub event bus for workflow coordination
4
+ * Extends EventEmitter pattern from MessageQueue
5
+ */
6
+ import { EventEmitter } from 'events';
7
+ /**
8
+ * Standard workflow event topics
9
+ */
10
+ export const WorkflowEvents = {
11
+ // Workflow lifecycle
12
+ WORKFLOW_STARTED: 'workflow.started',
13
+ WORKFLOW_VALIDATING: 'workflow.validating',
14
+ WORKFLOW_COMPLETED: 'workflow.completed',
15
+ WORKFLOW_FAILED: 'workflow.failed',
16
+ WORKFLOW_PAUSED: 'workflow.paused',
17
+ WORKFLOW_RESUMED: 'workflow.resumed',
18
+ // Step lifecycle
19
+ STEP_READY: 'workflow.step.ready',
20
+ STEP_STARTED: 'workflow.step.started',
21
+ STEP_COMPLETED: 'workflow.step.completed',
22
+ STEP_FAILED: 'workflow.step.failed',
23
+ STEP_SKIPPED: 'workflow.step.skipped',
24
+ STEP_RETRYING: 'workflow.step.retrying',
25
+ // Tool invocation
26
+ TOOL_BEFORE_INVOKE: 'workflow.tool.before_invoke',
27
+ TOOL_INVOKED: 'workflow.tool.invoked',
28
+ TOOL_SUCCESS: 'workflow.tool.success',
29
+ TOOL_FAILURE: 'workflow.tool.failure',
30
+ // Variable & file operations
31
+ VARIABLE_RESOLVED: 'workflow.variable.resolved',
32
+ FILE_CREATED: 'workflow.file.created',
33
+ FILE_REFERENCE_CREATED: 'workflow.file_reference.created',
34
+ // Synthesis
35
+ SYNTHESIS_STARTED: 'workflow.synthesis.started',
36
+ SYNTHESIS_COMPLETED: 'workflow.synthesis.completed',
37
+ // Session management
38
+ SESSION_CHECKPOINT: 'workflow.session.checkpoint',
39
+ SESSION_RESTORED: 'workflow.session.restored',
40
+ // Error handling
41
+ ERROR_OCCURRED: 'workflow.error.occurred',
42
+ ERROR_RECOVERED: 'workflow.error.recovered'
43
+ };
44
+ export class WorkflowEventBus extends EventEmitter {
45
+ constructor() {
46
+ super();
47
+ // Increase max listeners for complex workflows
48
+ this.setMaxListeners(100);
49
+ }
50
+ /**
51
+ * Singleton instance (optional - can also use new WorkflowEventBus())
52
+ */
53
+ static getInstance() {
54
+ if (!WorkflowEventBus.instance) {
55
+ WorkflowEventBus.instance = new WorkflowEventBus();
56
+ }
57
+ return WorkflowEventBus.instance;
58
+ }
59
+ subscribe(topic, handler) {
60
+ this.on(topic, handler);
61
+ // Return unsubscribe function
62
+ return () => {
63
+ this.off(topic, handler);
64
+ };
65
+ }
66
+ async publish(topic, data) {
67
+ // Log event for debugging (can be disabled in production)
68
+ if (process.env.DEBUG_WORKFLOW_EVENTS === 'true') {
69
+ console.error(`[EventBus] ${topic}:`, JSON.stringify(data, null, 2));
70
+ }
71
+ // Emit to all synchronous listeners
72
+ this.emit(topic, data);
73
+ // Get all listeners for this topic
74
+ const listeners = this.listeners(topic);
75
+ // Execute async handlers
76
+ const asyncHandlers = listeners.filter((listener) => listener.constructor.name === 'AsyncFunction');
77
+ if (asyncHandlers.length > 0) {
78
+ await Promise.all(asyncHandlers.map((handler) => Promise.resolve(handler(data))));
79
+ }
80
+ }
81
+ clear(topic) {
82
+ this.removeAllListeners(topic);
83
+ }
84
+ clearAll() {
85
+ this.removeAllListeners();
86
+ }
87
+ listenerCount(topic) {
88
+ return super.listenerCount(topic);
89
+ }
90
+ /**
91
+ * Subscribe to multiple topics with same handler
92
+ */
93
+ subscribeMultiple(topics, handler) {
94
+ const unsubscribers = topics.map((topic) => this.subscribe(topic, handler));
95
+ return () => {
96
+ unsubscribers.forEach((unsub) => unsub());
97
+ };
98
+ }
99
+ /**
100
+ * Wait for a specific event to occur (Promise-based)
101
+ */
102
+ async waitFor(topic, timeout = 30000) {
103
+ return new Promise((resolve, reject) => {
104
+ const timer = setTimeout(() => {
105
+ this.off(topic, handler);
106
+ reject(new Error(`Timeout waiting for event: ${topic}`));
107
+ }, timeout);
108
+ const handler = (data) => {
109
+ clearTimeout(timer);
110
+ resolve(data);
111
+ };
112
+ this.once(topic, handler);
113
+ });
114
+ }
115
+ /**
116
+ * Publish with error handling
117
+ */
118
+ async publishSafe(topic, data) {
119
+ try {
120
+ await this.publish(topic, data);
121
+ }
122
+ catch (error) {
123
+ console.error(`[EventBus] Error publishing to ${topic}:`, error);
124
+ // Emit error event for monitoring
125
+ this.emit(WorkflowEvents.ERROR_OCCURRED, {
126
+ topic,
127
+ error,
128
+ data
129
+ });
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Event Bus Interface
3
+ * Defines contract for pub/sub event system
4
+ */
5
+ export {};