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,260 @@
1
+ /**
2
+ * Unified AI Provider - Single interface for all OpenAI-compatible APIs
3
+ * Supports: OpenAI, Groq, Mistral, Gemini, OpenRouter, Together, Ollama, LMStudio
4
+ */
5
+ import { z } from 'zod';
6
+ import OpenAI from 'openai';
7
+ import { config } from 'dotenv';
8
+ import * as path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ config({ path: path.resolve(__dirname, '../../../.env') });
13
+ // Provider configurations with their base URLs
14
+ const PROVIDER_CONFIGS = {
15
+ openai: {
16
+ base: 'https://api.openai.com/v1',
17
+ key: process.env.OPENAI_API_KEY,
18
+ models: ['gpt-5', 'gpt-5-mini', 'gpt-5-nano']
19
+ },
20
+ gpt5: {
21
+ base: 'https://api.openai.com/v1', // Uses /responses endpoint internally
22
+ key: process.env.OPENAI_API_KEY,
23
+ models: ['gpt-5', 'gpt-5-mini', 'gpt-5-nano'],
24
+ special: true // Needs special handling
25
+ },
26
+ mistral: {
27
+ base: 'https://api.mistral.ai/v1',
28
+ key: process.env.MISTRAL_API_KEY,
29
+ models: ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest']
30
+ },
31
+ gemini: {
32
+ base: 'https://generativelanguage.googleapis.com/v1beta/',
33
+ key: process.env.GOOGLE_API_KEY,
34
+ models: ['gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-2.5-flash-lite']
35
+ },
36
+ openrouter: {
37
+ base: 'https://openrouter.ai/api/v1',
38
+ key: process.env.OPENROUTER_API_KEY,
39
+ models: ['anthropic/claude-3.5-sonnet', 'meta-llama/llama-3.1-405b', 'google/gemini-pro']
40
+ },
41
+ together: {
42
+ base: 'https://api.together.xyz/v1',
43
+ key: process.env.TOGETHER_API_KEY,
44
+ models: ['Meta-Llama-3.1-405B-Instruct-Turbo', 'Qwen/Qwen2.5-72B-Instruct-Turbo']
45
+ },
46
+ ollama: {
47
+ base: process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
48
+ key: 'ollama', // Ollama doesn't need an API key
49
+ models: ['llama3.3', 'qwen2.5', 'mistral', 'gemma2']
50
+ },
51
+ lmstudio: {
52
+ base: process.env.LMSTUDIO_BASE_URL || 'http://localhost:1234/v1',
53
+ key: 'lmstudio', // LMStudio doesn't need an API key
54
+ models: ['local-model'] // Depends on what's loaded
55
+ }
56
+ };
57
+ /**
58
+ * Check if a provider is available (has API key configured)
59
+ */
60
+ export function isProviderAvailable(provider) {
61
+ const config = PROVIDER_CONFIGS[provider];
62
+ if (!config)
63
+ return false;
64
+ // Local providers are always available
65
+ if (provider === 'ollama' || provider === 'lmstudio') {
66
+ return true;
67
+ }
68
+ return !!config.key;
69
+ }
70
+ /**
71
+ * Get available providers
72
+ */
73
+ export function getAvailableProviders() {
74
+ return Object.keys(PROVIDER_CONFIGS)
75
+ .filter(p => isProviderAvailable(p));
76
+ }
77
+ /**
78
+ * Unified AI query function
79
+ */
80
+ export async function queryAI(prompt, options) {
81
+ const config = PROVIDER_CONFIGS[options.provider];
82
+ if (!config) {
83
+ throw new Error(`Unknown provider: ${options.provider}`);
84
+ }
85
+ if (!isProviderAvailable(options.provider)) {
86
+ throw new Error(`Provider ${options.provider} is not configured. Please set the appropriate API key.`);
87
+ }
88
+ // Handle GPT-5 special case
89
+ if (options.provider === 'gpt5' && 'special' in config && config.special) {
90
+ return await handleGPT5(prompt, options);
91
+ }
92
+ // Standard OpenAI-compatible handling
93
+ const client = new OpenAI({
94
+ apiKey: config.key,
95
+ baseURL: config.base
96
+ });
97
+ const model = options.model || config.models[0];
98
+ try {
99
+ const response = await client.chat.completions.create({
100
+ model,
101
+ messages: [
102
+ ...(options.systemPrompt ? [{ role: 'system', content: options.systemPrompt }] : []),
103
+ { role: 'user', content: prompt }
104
+ ],
105
+ temperature: options.temperature ?? 0.7,
106
+ max_tokens: options.maxTokens ?? 2000,
107
+ stream: false // Always false for now to avoid streaming complexity
108
+ });
109
+ return response.choices[0]?.message?.content || 'No response generated';
110
+ }
111
+ catch (error) {
112
+ const errorMessage = error instanceof Error ? error.message : String(error);
113
+ console.error(`Error with ${options.provider}:`, errorMessage);
114
+ throw new Error(`${options.provider} API error: ${errorMessage}`);
115
+ }
116
+ }
117
+ /**
118
+ * Special handling for GPT-5 (uses /responses endpoint)
119
+ */
120
+ async function handleGPT5(prompt, options) {
121
+ const config = PROVIDER_CONFIGS.gpt5;
122
+ const endpoint = 'https://api.openai.com/v1/responses';
123
+ const model = options.model || 'gpt-5-nano'; // Default to cheapest
124
+ const requestBody = {
125
+ model,
126
+ input: prompt,
127
+ reasoning: {
128
+ effort: model === 'gpt-5' ? 'high' : 'low'
129
+ },
130
+ text: {
131
+ verbosity: 'medium'
132
+ }
133
+ };
134
+ try {
135
+ const response = await fetch(endpoint, {
136
+ method: 'POST',
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ 'Authorization': `Bearer ${config.key}`
140
+ },
141
+ body: JSON.stringify(requestBody)
142
+ });
143
+ if (!response.ok) {
144
+ const error = await response.text();
145
+ throw new Error(`GPT-5 API error: ${error}`);
146
+ }
147
+ const data = await response.json();
148
+ return data.output || data.response || 'No response generated';
149
+ }
150
+ catch (error) {
151
+ console.error('GPT-5 error:', error);
152
+ throw error;
153
+ }
154
+ }
155
+ /**
156
+ * Mode-specific wrappers
157
+ */
158
+ export async function analyzeWithAI(content, provider, analysisType = 'code') {
159
+ const prompts = {
160
+ code: `Analyze this code for quality, bugs, and improvements:\n\n${content}`,
161
+ text: `Analyze this text for clarity, structure, and key points:\n\n${content}`,
162
+ security: `Analyze this code for security vulnerabilities:\n\n${content}`,
163
+ performance: `Analyze this code for performance issues:\n\n${content}`
164
+ };
165
+ return queryAI(prompts[analysisType], {
166
+ provider,
167
+ mode: 'analyze',
168
+ temperature: 0.3 // Lower temperature for analysis
169
+ });
170
+ }
171
+ export async function generateCode(requirements, provider, language) {
172
+ const prompt = language
173
+ ? `Generate ${language} code for: ${requirements}`
174
+ : `Generate code for: ${requirements}`;
175
+ return queryAI(prompt, {
176
+ provider,
177
+ mode: 'code',
178
+ temperature: 0.5,
179
+ systemPrompt: 'You are an expert programmer. Generate clean, efficient, well-commented code.'
180
+ });
181
+ }
182
+ export function getUnifiedAITools() {
183
+ const availableProviders = getAvailableProviders();
184
+ if (availableProviders.length === 0) {
185
+ console.error('⚠️ No AI providers configured. Please set API keys in .env');
186
+ return [];
187
+ }
188
+ return [
189
+ {
190
+ name: 'ai',
191
+ description: 'Query any AI model',
192
+ parameters: z.object({
193
+ prompt: z.string(),
194
+ provider: z.enum(availableProviders).optional(),
195
+ model: z.string().optional(),
196
+ mode: z.enum(['chat', 'complete', 'reason', 'analyze', 'code']).optional(),
197
+ temperature: z.number().min(0).max(2).optional(),
198
+ maxTokens: z.number().min(1).max(100000).optional()
199
+ }),
200
+ execute: async (args, context) => {
201
+ const typedArgs = args;
202
+ const provider = typedArgs.provider || availableProviders[0];
203
+ return await queryAI(typedArgs.prompt, {
204
+ provider,
205
+ model: typedArgs.model,
206
+ mode: typedArgs.mode,
207
+ temperature: typedArgs.temperature,
208
+ maxTokens: typedArgs.maxTokens
209
+ });
210
+ }
211
+ },
212
+ {
213
+ name: 'ai_analyze',
214
+ description: 'Analyze code or text',
215
+ parameters: z.object({
216
+ content: z.string(),
217
+ type: z.enum(['code', 'text', 'security', 'performance']),
218
+ provider: z.enum(availableProviders).optional()
219
+ }),
220
+ execute: async (args, context) => {
221
+ const typedArgs = args;
222
+ const provider = typedArgs.provider || availableProviders[0];
223
+ return await analyzeWithAI(typedArgs.content, provider, typedArgs.type);
224
+ }
225
+ },
226
+ {
227
+ name: 'ai_code',
228
+ description: 'Generate code',
229
+ parameters: z.object({
230
+ requirements: z.string(),
231
+ language: z.string().optional(),
232
+ provider: z.enum(availableProviders).optional()
233
+ }),
234
+ execute: async (args, context) => {
235
+ const typedArgs = args;
236
+ const provider = typedArgs.provider || availableProviders[0];
237
+ return await generateCode(typedArgs.requirements, provider, typedArgs.language);
238
+ }
239
+ }
240
+ ];
241
+ }
242
+ /**
243
+ * List available models for a provider
244
+ */
245
+ export function listModels(provider) {
246
+ return PROVIDER_CONFIGS[provider]?.models || [];
247
+ }
248
+ /**
249
+ * Get provider info
250
+ */
251
+ export function getProviderInfo() {
252
+ const info = {};
253
+ for (const [provider, config] of Object.entries(PROVIDER_CONFIGS)) {
254
+ info[provider] = {
255
+ available: isProviderAvailable(provider),
256
+ models: config.models
257
+ };
258
+ }
259
+ return info;
260
+ }
@@ -0,0 +1,425 @@
1
+ /**
2
+ * Workflow Runner Tool - Execute custom workflows via MCP
3
+ */
4
+ import { z } from 'zod';
5
+ import { workflowEngine } from '../workflows/custom-workflows.js';
6
+ import * as yaml from 'yaml';
7
+ import { isToolEnabled } from '../utils/tool-config.js';
8
+ /**
9
+ * Register workflow tools with the MCP server
10
+ */
11
+ export function registerWorkflowTools(server) {
12
+ const tools = [];
13
+ // Tool to execute workflows (by name or from file)
14
+ tools.push({
15
+ name: 'workflow',
16
+ description: 'Execute workflows',
17
+ parameters: z.object({
18
+ name: z.string().optional(),
19
+ file: z.string().optional(),
20
+ query: z.string(),
21
+ projectPath: z.string().optional(),
22
+ truncateSteps: z.boolean().optional(),
23
+ maxStepTokens: z.number().optional(),
24
+ }),
25
+ execute: async (args) => {
26
+ try {
27
+ // Validation: must specify exactly one
28
+ if (!args.name && !args.file) {
29
+ return "❌ Error: Must specify either 'name' or 'file' parameter\n\nExamples:\n workflow --name code-review --query 'input'\n workflow --file ./custom.yaml --query 'input'";
30
+ }
31
+ if (args.name && args.file) {
32
+ return "❌ Error: Cannot use both 'name' and 'file' parameters\n\nUse one or the other.";
33
+ }
34
+ let result;
35
+ if (args.file) {
36
+ // File-based execution (ad-hoc)
37
+ console.error(`🚀 Executing workflow from file: ${args.file}`);
38
+ result = await workflowEngine.loadAndExecuteWorkflowFile(args.file, args.query, {
39
+ variables: { query: args.query },
40
+ truncateSteps: args.truncateSteps,
41
+ maxStepTokens: args.maxStepTokens,
42
+ });
43
+ }
44
+ else {
45
+ // Named workflow execution (discovery-based)
46
+ console.error(`🚀 Executing named workflow: ${args.name}`);
47
+ result = await workflowEngine.executeWorkflow(args.name, args.query, {
48
+ variables: { query: args.query },
49
+ truncateSteps: args.truncateSteps,
50
+ maxStepTokens: args.maxStepTokens,
51
+ });
52
+ }
53
+ // ALWAYS format as string for Claude Code display
54
+ // Format result for readability
55
+ if (typeof result === 'string') {
56
+ return result;
57
+ }
58
+ // Format detailed workflow results
59
+ if (typeof result === 'object' && result !== null && 'steps' in result) {
60
+ const detailed = result;
61
+ // Determine truncation settings
62
+ // Default: truncate enabled, 2500 tokens (~10k chars)
63
+ const truncate = args.truncateSteps ?? true;
64
+ const maxTokens = args.maxStepTokens ?? 2500;
65
+ const maxChars = maxTokens * 4; // 1 token ≈ 4 chars
66
+ let output = `# Workflow: ${detailed.workflow}\n\n`;
67
+ output += `**Duration:** ${(detailed.duration / 1000).toFixed(1)}s\n`;
68
+ output += `**Steps Completed:** ${detailed.steps.length}\n\n`;
69
+ output += `---\n\n`;
70
+ // Format each step's output
71
+ for (let i = 0; i < detailed.steps.length; i++) {
72
+ const step = detailed.steps[i];
73
+ output += `## Step ${i + 1}: ${step.step}\n\n`;
74
+ // Format the step output - keep it clean and readable
75
+ let stepOutput = step.output;
76
+ // Truncate based on settings
77
+ if (truncate && typeof stepOutput === 'string' && stepOutput.length > maxChars) {
78
+ const approxTokens = Math.floor(stepOutput.length / 4);
79
+ output += stepOutput.substring(0, maxChars) +
80
+ '\n\n...(output truncated: ~' + approxTokens + ' tokens, limit: ' + maxTokens + ' tokens. Use truncateSteps=false for full output)...\n\n';
81
+ }
82
+ else {
83
+ output += `${stepOutput}\n\n`;
84
+ }
85
+ output += `---\n\n`;
86
+ }
87
+ // Add final summary footer
88
+ output += `\n**Workflow Complete** ✓\n`;
89
+ return output;
90
+ }
91
+ // Fallback for any other object type
92
+ return JSON.stringify(result, null, 2);
93
+ }
94
+ catch (error) {
95
+ return `Workflow execution failed: ${error.message}`;
96
+ }
97
+ },
98
+ });
99
+ // Tool to list all workflows
100
+ tools.push({
101
+ name: 'list_workflows',
102
+ description: 'List workflows',
103
+ parameters: z.object({
104
+ projectPath: z.string().optional(),
105
+ }),
106
+ execute: async (args) => {
107
+ const workflows = workflowEngine.listWorkflows();
108
+ const errors = workflowEngine.getValidationErrors();
109
+ let output = '';
110
+ // Show successful workflows
111
+ if (workflows.length > 0) {
112
+ const formatted = workflows.map(w => `• ${w.name}: ${w.description || 'No description'} (${w.steps} steps)`).join('\n');
113
+ output += `Available Workflows:\n\n${formatted}\n\nUse 'workflow' tool to execute any of these.\n`;
114
+ }
115
+ else {
116
+ output += `No workflows available.\n`;
117
+ }
118
+ // Show validation errors if any
119
+ if (errors.length > 0) {
120
+ output += `\n⚠️ Validation Errors (${errors.length} files failed to load):\n\n`;
121
+ errors.forEach(err => {
122
+ output += `❌ [${err.source}] ${err.file}\n`;
123
+ output += ` Error: ${err.error}\n\n`;
124
+ });
125
+ output += `Fix these files to make them available.\n`;
126
+ }
127
+ return output;
128
+ },
129
+ });
130
+ // Tool to create a new workflow
131
+ tools.push({
132
+ name: 'create_workflow',
133
+ description: 'Create workflow',
134
+ parameters: z.object({
135
+ name: z.string(),
136
+ type: z.enum(['code-review', 'brainstorm', 'debug', 'research', 'custom']),
137
+ steps: z.string().optional(),
138
+ }),
139
+ execute: async (args) => {
140
+ try {
141
+ let workflow;
142
+ // Create based on template
143
+ switch (args.type) {
144
+ case 'code-review':
145
+ workflow = {
146
+ name: args.name,
147
+ description: 'Custom code review workflow',
148
+ version: '1.0',
149
+ settings: {
150
+ optimization: {
151
+ enabled: true,
152
+ cacheResults: true,
153
+ compressPrompts: true,
154
+ smartRouting: true,
155
+ },
156
+ },
157
+ steps: [
158
+ { name: 'analyze', tool: 'gemini_analyze_code', input: { prompt: 'Analyze code' } },
159
+ { name: 'review', tool: 'grok_code', input: { prompt: 'Review for best practices' } },
160
+ { name: 'suggest', tool: 'ai', input: { prompt: 'Suggest improvements' }, model: 'openai' },
161
+ ],
162
+ };
163
+ break;
164
+ case 'brainstorm':
165
+ workflow = {
166
+ name: args.name,
167
+ description: 'Custom brainstorming workflow',
168
+ version: '1.0',
169
+ settings: {},
170
+ steps: [
171
+ { name: 'ideate', tool: 'gemini_brainstorm', input: { prompt: 'Generate ideas' } },
172
+ { name: 'expand', tool: 'openai_brainstorm', input: { prompt: 'Expand on ideas' } },
173
+ { name: 'research', tool: 'scout', input: { prompt: 'Find evidence' } },
174
+ ],
175
+ };
176
+ break;
177
+ case 'debug':
178
+ workflow = {
179
+ name: args.name,
180
+ description: 'Custom debugging workflow',
181
+ version: '1.0',
182
+ settings: {},
183
+ steps: [
184
+ { name: 'analyze', tool: 'grok_debug', input: { prompt: 'Analyze error' } },
185
+ { name: 'trace', tool: 'grok_code', input: { prompt: 'Analyze code path' } },
186
+ { name: 'fix', tool: 'ai_code', input: { prompt: 'Suggest fix' } },
187
+ ],
188
+ };
189
+ break;
190
+ case 'research':
191
+ workflow = {
192
+ name: args.name,
193
+ description: 'Custom research workflow',
194
+ version: '1.0',
195
+ settings: {},
196
+ steps: [
197
+ { name: 'search', tool: 'perplexity_ask', input: { prompt: 'Initial research' } },
198
+ { name: 'analyze', tool: 'ai_analyze', input: { prompt: 'Analyze findings' } },
199
+ { name: 'verify', tool: 'verifier', input: { prompt: 'Verify facts' } },
200
+ { name: 'synthesize', tool: 'focus', input: { prompt: 'Synthesize results' } },
201
+ ],
202
+ };
203
+ break;
204
+ case 'custom':
205
+ if (!args.steps) {
206
+ return 'Custom workflow requires steps in YAML or JSON format';
207
+ }
208
+ try {
209
+ const stepsData = args.steps.trim().startsWith('{')
210
+ ? JSON.parse(args.steps)
211
+ : yaml.parse(args.steps);
212
+ workflow = {
213
+ name: args.name,
214
+ description: 'Custom workflow',
215
+ version: '1.0',
216
+ settings: {},
217
+ steps: stepsData.steps || stepsData,
218
+ };
219
+ }
220
+ catch (error) {
221
+ return `Failed to parse custom steps: ${error}`;
222
+ }
223
+ break;
224
+ default:
225
+ return `Unknown workflow type: ${args.type}`;
226
+ }
227
+ // Save the workflow
228
+ await workflowEngine.saveWorkflow(workflow, 'yaml');
229
+ return `✅ Created workflow '${args.name}' successfully!
230
+
231
+ To use it: workflow --name ${args.name} --query "your input"
232
+
233
+ Workflow saved to: .tachi/workflows/${args.name}.yaml`;
234
+ }
235
+ catch (error) {
236
+ return `Failed to create workflow: ${error.message}`;
237
+ }
238
+ },
239
+ });
240
+ // Tool to visualize workflow
241
+ tools.push({
242
+ name: 'visualize_workflow',
243
+ description: 'Visualize workflow',
244
+ parameters: z.object({
245
+ name: z.string(),
246
+ }),
247
+ execute: async (args) => {
248
+ const workflow = workflowEngine.getWorkflow(args.name);
249
+ if (!workflow) {
250
+ return `Workflow '${args.name}' not found`;
251
+ }
252
+ // Create ASCII visualization
253
+ let viz = `
254
+ ┌─────────────────────────────────────┐
255
+ │ Workflow: ${workflow.name.padEnd(25)}│
256
+ └─────────────────────────────────────┘
257
+
258
+ ${workflow.description || 'No description'}
259
+
260
+ Settings:
261
+ • Optimization: ${workflow.settings?.optimization?.enabled ? '✅' : '❌'}
262
+ • Smart Routing: ${workflow.settings?.optimization?.smartRouting ? '✅' : '❌'}
263
+
264
+ Steps:
265
+ `;
266
+ for (let i = 0; i < workflow.steps.length; i++) {
267
+ const step = workflow.steps[i];
268
+ const isLast = i === workflow.steps.length - 1;
269
+ const prefix = isLast ? '└──' : '├──';
270
+ const connector = isLast ? ' ' : '│ ';
271
+ viz += `${prefix} ${i + 1}. ${step.name}\n`;
272
+ viz += `${connector} Tool: ${step.tool}\n`;
273
+ if (step.model)
274
+ viz += `${connector} Model: ${step.model}\n`;
275
+ if (step.parallel)
276
+ viz += `${connector} ⚡ Runs in parallel\n`;
277
+ if (step.condition)
278
+ viz += `${connector} ⚠️ Conditional\n`;
279
+ viz += '\n';
280
+ }
281
+ return viz;
282
+ },
283
+ });
284
+ // Tool to start workflow step-by-step (streaming mode)
285
+ tools.push({
286
+ name: 'workflow_start',
287
+ description: 'Start workflow session',
288
+ parameters: z.object({
289
+ name: z.string(),
290
+ query: z.string(),
291
+ variables: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
292
+ }),
293
+ execute: async (args) => {
294
+ try {
295
+ console.error(`🚀 Starting streaming workflow: ${args.name}`);
296
+ const result = await workflowEngine.startWorkflowStepByStep(args.name, args.query, { variables: args.variables });
297
+ const totalSteps = workflowEngine.getWorkflow(args.name)?.steps.length || '?';
298
+ const r = result;
299
+ return `# Workflow Started: ${args.name}
300
+
301
+ **Session ID:** \`${r.sessionId}\`
302
+
303
+ ✅ Step ${r.step}/${totalSteps}: **${r.stepName}**
304
+
305
+ ${r.output}
306
+
307
+ ---
308
+
309
+ ${r.hasMore ? `⏭️ **Next:** Use \`continue_workflow\` with session ID \`${r.sessionId}\` to execute step ${r.step + 1}` : '✓ Workflow complete!'}`;
310
+ }
311
+ catch (error) {
312
+ return `Failed to start workflow: ${error.message}`;
313
+ }
314
+ },
315
+ });
316
+ // Tool to continue workflow execution
317
+ tools.push({
318
+ name: 'continue_workflow',
319
+ description: 'Continue workflow',
320
+ parameters: z.object({
321
+ sessionId: z.string(),
322
+ }),
323
+ execute: async (args) => {
324
+ try {
325
+ const result = await workflowEngine.continueWorkflow(args.sessionId);
326
+ // Get workflow info for context
327
+ const session = workflowEngine.sessions?.get(args.sessionId);
328
+ const workflowName = session?.workflowName || 'unknown';
329
+ const totalSteps = session?.workflow?.steps.length || '?';
330
+ const r = result;
331
+ if (!r.hasMore) {
332
+ return `# Workflow Complete: ${workflowName}
333
+
334
+ **Session ID:** \`${r.sessionId}\`
335
+
336
+ ✅ All steps completed!
337
+
338
+ Final output from step ${r.step}:
339
+
340
+ ${r.output}
341
+
342
+ ---
343
+
344
+ ✓ Workflow finished successfully`;
345
+ }
346
+ return `# Workflow Progress: ${workflowName}
347
+
348
+ **Session ID:** \`${r.sessionId}\`
349
+
350
+ ✅ Step ${r.step}/${totalSteps}: **${r.stepName}**
351
+
352
+ ${r.output}
353
+
354
+ ---
355
+
356
+ ⏭️ **Next:** Call \`continue_workflow\` with session ID \`${r.sessionId}\` to execute step ${r.step + 1}`;
357
+ }
358
+ catch (error) {
359
+ return `Failed to continue workflow: ${error.message}`;
360
+ }
361
+ },
362
+ });
363
+ // Tool to check workflow session status
364
+ tools.push({
365
+ name: 'workflow_status',
366
+ description: 'Workflow status',
367
+ parameters: z.object({
368
+ sessionId: z.string(),
369
+ }),
370
+ execute: async (args) => {
371
+ try {
372
+ // Access internal session state (type assertion to access private members)
373
+ const session = workflowEngine.sessions?.get(args.sessionId);
374
+ if (!session) {
375
+ return `❌ Session '${args.sessionId}' not found. It may have completed or expired.`;
376
+ }
377
+ const totalSteps = session.workflow.steps.length;
378
+ const currentStep = session.currentStepIndex + 1;
379
+ const completed = session.currentStepIndex;
380
+ const remaining = totalSteps - completed;
381
+ const duration = ((Date.now() - session.startTime) / 1000).toFixed(1);
382
+ return `# Workflow Session Status
383
+
384
+ **Workflow:** ${session.workflowName}
385
+ **Session ID:** \`${args.sessionId}\`
386
+ **Status:** Running
387
+
388
+ **Progress:** ${completed}/${totalSteps} steps completed
389
+ **Current Step:** ${currentStep} - ${session.workflow.steps[session.currentStepIndex]?.name || 'N/A'}
390
+ **Remaining:** ${remaining} steps
391
+ **Duration:** ${duration}s
392
+
393
+ **Latest Output:**
394
+ ${session.previousOutput?.substring(0, 500) || 'No output yet'}${session.previousOutput?.length > 500 ? '...' : ''}
395
+
396
+ Use \`continue_workflow\` to execute the next step.`;
397
+ }
398
+ catch (error) {
399
+ return `Failed to get workflow status: ${error.message}`;
400
+ }
401
+ },
402
+ });
403
+ // Register tools with server (with profile filtering)
404
+ tools.forEach(tool => {
405
+ try {
406
+ // Check if tool is enabled in profile
407
+ if (!isToolEnabled(tool.name)) {
408
+ return; // Skip disabled tools
409
+ }
410
+ server.addTool(tool);
411
+ }
412
+ catch (error) {
413
+ console.error(`Failed to register tool ${tool.name}:`, error);
414
+ }
415
+ });
416
+ console.error('✅ Registered workflow tools:');
417
+ console.error(' - workflow: Execute complete workflows (all steps at once)');
418
+ console.error(' - workflow_start: Start streaming workflow (step-by-step mode)');
419
+ console.error(' - continue_workflow: Execute next step in streaming workflow');
420
+ console.error(' - workflow_status: Check progress of streaming workflow');
421
+ console.error(' - list_workflows: List available workflows');
422
+ console.error(' - create_workflow: Create new workflow from template');
423
+ console.error(' - visualize_workflow: Show workflow structure');
424
+ return tools;
425
+ }