orquesta-cli 0.2.47 → 0.2.49

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.
@@ -1,7 +1,7 @@
1
1
  import { logger } from '../../utils/logger.js';
2
2
  class ContextTrackerClass {
3
3
  lastPromptTokens = 0;
4
- autoCompactThreshold = 70;
4
+ autoCompactThreshold = 50;
5
5
  autoCompactTriggered = false;
6
6
  recentFiles = new Set();
7
7
  maxRecentFiles = 20;
@@ -0,0 +1,5 @@
1
+ export declare function getCachedFile(path: string): string | null;
2
+ export declare function setCachedFile(path: string, content: string): void;
3
+ export declare function invalidateCache(path: string): void;
4
+ export declare function clearFileCache(): void;
5
+ //# sourceMappingURL=file-cache.d.ts.map
@@ -0,0 +1,27 @@
1
+ import * as fs from 'fs';
2
+ const cache = new Map();
3
+ export function getCachedFile(path) {
4
+ const entry = cache.get(path);
5
+ if (!entry)
6
+ return null;
7
+ try {
8
+ const stat = fs.statSync(path);
9
+ if (stat.mtimeMs === entry.mtime)
10
+ return entry.content;
11
+ cache.delete(path);
12
+ }
13
+ catch {
14
+ cache.delete(path);
15
+ }
16
+ return null;
17
+ }
18
+ export function setCachedFile(path, content) {
19
+ try {
20
+ const stat = fs.statSync(path);
21
+ cache.set(path, { content, mtime: stat.mtimeMs });
22
+ }
23
+ catch { }
24
+ }
25
+ export function invalidateCache(path) { cache.delete(path); }
26
+ export function clearFileCache() { cache.clear(); }
27
+ //# sourceMappingURL=file-cache.js.map
@@ -1,4 +1,5 @@
1
1
  import { Message, LLMRequestOptions } from '../../types/index.js';
2
+ export declare function fetchWithRetry(url: string, options: RequestInit, maxRetries?: number): Promise<Response>;
2
3
  export interface LLMResponse {
3
4
  id: string;
4
5
  object: string;
@@ -100,6 +100,20 @@ function captureBatutaHeaders(headers) {
100
100
  setLastBatutaRoute({ tier, routedTo, routedFrom });
101
101
  }
102
102
  }
103
+ export async function fetchWithRetry(url, options, maxRetries = 3) {
104
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
105
+ const res = await fetch(url, options);
106
+ if (res.ok || attempt === maxRetries)
107
+ return res;
108
+ if (res.status === 429 || res.status >= 500) {
109
+ const delay = Math.min(1000 * 2 ** attempt, 30000);
110
+ await new Promise(r => setTimeout(r, delay));
111
+ continue;
112
+ }
113
+ return res;
114
+ }
115
+ throw new Error('Unreachable');
116
+ }
103
117
  export class LLMClient {
104
118
  axiosInstance;
105
119
  baseUrl;
@@ -138,29 +152,33 @@ export class LLMClient {
138
152
  });
139
153
  }
140
154
  preprocessMessages(messages, modelId) {
155
+ const isGptOss = /^gpt-oss-(120b|20b)$/i.test(modelId);
141
156
  return messages.map((msg) => {
142
- let processedMsg = { ...msg };
143
- const multimodal = processedMsg.multimodal;
157
+ const multimodal = msg.multimodal;
144
158
  if (multimodal && Array.isArray(multimodal)) {
159
+ const processedMsg = { ...msg };
145
160
  processedMsg.content = multimodal;
146
161
  delete processedMsg.multimodal;
147
162
  return processedMsg;
148
163
  }
149
164
  if (msg.role !== 'assistant') {
150
- return processedMsg;
165
+ return msg;
166
+ }
167
+ const msgAny = msg;
168
+ const needsReasoningFix = msgAny.reasoning_content && (!msg.content || msg.content.trim() === '');
169
+ const needsHarmonyFix = isGptOss && msg.tool_calls && msg.tool_calls.length > 0 && (!msg.content || msg.content.trim() === '');
170
+ const needsNullFix = msg.content === undefined || msg.content === null;
171
+ if (!needsReasoningFix && !needsHarmonyFix && !needsNullFix) {
172
+ return msg;
151
173
  }
152
- const msgAny = processedMsg;
153
- if (msgAny.reasoning_content && (!msg.content || msg.content.trim() === '')) {
174
+ const processedMsg = { ...msg };
175
+ if (needsReasoningFix) {
154
176
  processedMsg.content = msgAny.reasoning_content;
155
177
  delete processedMsg.reasoning_content;
156
178
  }
157
- if (/^gpt-oss-(120b|20b)$/i.test(modelId)) {
158
- if (msg.tool_calls && msg.tool_calls.length > 0) {
159
- if (!processedMsg.content || processedMsg.content.trim() === '') {
160
- const toolNames = msg.tool_calls.map(tc => tc.function.name).join(', ');
161
- processedMsg.content = msgAny.reasoning || `Calling tools: ${toolNames}`;
162
- }
163
- }
179
+ if (needsHarmonyFix) {
180
+ const toolNames = msg.tool_calls.map(tc => tc.function.name).join(', ');
181
+ processedMsg.content = msgAny.reasoning || `Calling tools: ${toolNames}`;
164
182
  }
165
183
  if (processedMsg.content === undefined || processedMsg.content === null) {
166
184
  processedMsg.content = '';
@@ -185,12 +203,14 @@ export class LLMClient {
185
203
  const processedMessages = options.messages ?
186
204
  this.preprocessMessages(options.messages, modelId) : [];
187
205
  logger.vars({ name: 'modelId', value: modelId }, { name: 'originalMessages', value: options.messages?.length || 0 }, { name: 'processedMessages', value: processedMessages.length }, { name: 'temperature', value: options.temperature ?? 0 });
206
+ const isClaudeModel = /claude|sonnet|opus|haiku/i.test(modelId);
188
207
  const requestBody = {
189
208
  model: modelId,
190
209
  messages: processedMessages,
191
210
  temperature: options.temperature ?? 0,
192
211
  max_tokens: options.max_tokens,
193
212
  stream: false,
213
+ ...(isClaudeModel && { thinking: { type: 'enabled', budget_tokens: 10000 } }),
194
214
  ...(options.tools && {
195
215
  tools: options.tools,
196
216
  parallel_tool_calls: false,
@@ -451,12 +471,14 @@ export class LLMClient {
451
471
  const modelId = options.model || this.model;
452
472
  const processedMessages = options.messages ?
453
473
  this.preprocessMessages(options.messages, modelId) : [];
474
+ const isClaudeModel = /claude|sonnet|opus|haiku/i.test(modelId);
454
475
  const requestBody = {
455
476
  model: modelId,
456
477
  messages: processedMessages,
457
478
  temperature: options.temperature ?? 0,
458
479
  max_tokens: options.max_tokens,
459
480
  stream: true,
481
+ ...(isClaudeModel && { thinking: { type: 'enabled', budget_tokens: 10000 } }),
460
482
  ...(options.tools && {
461
483
  tools: options.tools,
462
484
  ...(options.tool_choice && { tool_choice: options.tool_choice }),
@@ -597,6 +619,7 @@ export class LLMClient {
597
619
  let contextLengthRecoveryAttempted = false;
598
620
  let finalResponseFailures = 0;
599
621
  const MAX_FINAL_RESPONSE_FAILURES = 3;
622
+ const { executeFileTool, requestToolApproval, emitAssistantResponse } = await import('../../tools/llm/simple/file-tools.js');
600
623
  const recentToolSignatures = [];
601
624
  const recentNormalizedSignatures = [];
602
625
  const LOOP_WINDOW = 5;
@@ -736,7 +759,6 @@ export class LLMClient {
736
759
  });
737
760
  continue;
738
761
  }
739
- const { executeFileTool, requestToolApproval } = await import('../../tools/llm/simple/file-tools.js');
740
762
  const approvalResult = await requestToolApproval(toolName, toolArgs);
741
763
  if (approvalResult && typeof approvalResult === 'object' && approvalResult.reject) {
742
764
  logger.flow(`Tool rejected by user: ${toolName}`);
@@ -791,7 +813,6 @@ export class LLMClient {
791
813
  if (finalResponseFailures >= MAX_FINAL_RESPONSE_FAILURES) {
792
814
  logger.warn('Max final_response failures exceeded - forcing completion');
793
815
  const fallbackMessage = toolArgs['message'] || 'Task completed with incomplete TODOs.';
794
- const { emitAssistantResponse } = await import('../../tools/llm/simple/file-tools.js');
795
816
  emitAssistantResponse(fallbackMessage);
796
817
  return {
797
818
  message: { role: 'assistant', content: fallbackMessage },
@@ -198,13 +198,13 @@ class UsageTrackerClass {
198
198
  tokenStr = `${(tokens / 1000000).toFixed(2)}M`;
199
199
  }
200
200
  const activity = currentActivity || 'Processing';
201
- return `✶ ${activity}… (esc to interrupt · ${timeStr} · ↑ ${tokenStr} tokens)`;
201
+ return `🎵 ${activity}… (esc to interrupt · ${timeStr} · ↑ ${tokenStr} tokens)`;
202
202
  }
203
203
  formatUsageDisplay() {
204
204
  logger.enter('UsageTracker.formatUsageDisplay');
205
205
  const summary = this.getSummary();
206
206
  const lines = [];
207
- lines.push('📊 Usage Statistics');
207
+ lines.push('🎼 Usage Statistics');
208
208
  lines.push('');
209
209
  lines.push('📅 Today');
210
210
  if (summary.today) {
@@ -5,7 +5,9 @@ import type { StateCallbacks } from './types.js';
5
5
  export declare function setAppendedSystemPrompt(text: string): void;
6
6
  export declare class PlanExecutor {
7
7
  private currentLLMClient;
8
+ private cachedSystemPrompt;
8
9
  constructor();
10
+ private getSystemPrompt;
9
11
  executePlanMode(userMessage: string, llmClient: LLMClient, messages: Message[], isInterruptedRef: {
10
12
  current: boolean;
11
13
  }, callbacks: StateCallbacks): Promise<void>;
@@ -40,8 +40,15 @@ function buildSystemPrompt() {
40
40
  }
41
41
  export class PlanExecutor {
42
42
  currentLLMClient = null;
43
+ cachedSystemPrompt = null;
43
44
  constructor() {
44
45
  }
46
+ getSystemPrompt() {
47
+ if (!this.cachedSystemPrompt) {
48
+ this.cachedSystemPrompt = buildSystemPrompt();
49
+ }
50
+ return this.cachedSystemPrompt;
51
+ }
45
52
  async executePlanMode(userMessage, llmClient, messages, isInterruptedRef, callbacks) {
46
53
  const planningStartTime = Date.now();
47
54
  const streamLogger = getStreamLogger();
@@ -139,8 +146,8 @@ export class PlanExecutor {
139
146
  callbacks.setTodos(currentTodos);
140
147
  emitPlanCreated(currentTodos.map(t => t.title));
141
148
  const planMessage = planResult.docsSearchNeeded
142
- ? `📋 Created ${currentTodos.length} tasks (including docs search). Starting execution...`
143
- : `📋 Created ${currentTodos.length} tasks. Starting execution...`;
149
+ ? `🎼 Created ${currentTodos.length} tasks (including docs search). Starting execution...`
150
+ : `🎼 Created ${currentTodos.length} tasks. Starting execution...`;
144
151
  const lastMsgForPlan = currentMessages[currentMessages.length - 1];
145
152
  const needsUserMessageForPlan = !(lastMsgForPlan?.role === 'user' && lastMsgForPlan?.content === userMessage);
146
153
  currentMessages = needsUserMessageForPlan
@@ -163,7 +170,7 @@ export class PlanExecutor {
163
170
  const hasSystemMessage = currentMessages.some(m => m.role === 'system');
164
171
  if (!hasSystemMessage) {
165
172
  currentMessages = [
166
- { role: 'system', content: buildSystemPrompt() },
173
+ { role: 'system', content: this.getSystemPrompt() },
167
174
  ...currentMessages
168
175
  ];
169
176
  }
@@ -191,7 +198,7 @@ export class PlanExecutor {
191
198
  });
192
199
  if (useParallel && sessionId) {
193
200
  logger.flow('Dispatching parallel orchestrator', { todoCount: currentTodos.length });
194
- const baseSystem = currentMessages.find(m => m.role === 'system')?.content || buildSystemPrompt();
201
+ const baseSystem = currentMessages.find(m => m.role === 'system')?.content || this.getSystemPrompt();
195
202
  const graphResult = await runParallelGraph({
196
203
  llmClient,
197
204
  todos: currentTodos,
@@ -285,6 +292,7 @@ export class PlanExecutor {
285
292
  clearFinalResponseCallbacks();
286
293
  clearDocsSearchLLMClientGetter();
287
294
  this.currentLLMClient = null;
295
+ this.cachedSystemPrompt = null;
288
296
  }
289
297
  }
290
298
  async resumeTodoExecution(userMessage, llmClient, messages, todos, isInterruptedRef, callbacks) {
@@ -311,7 +319,7 @@ export class PlanExecutor {
311
319
  const hasSystemMessage = currentMessages.some(m => m.role === 'system');
312
320
  if (!hasSystemMessage) {
313
321
  currentMessages = [
314
- { role: 'system', content: buildSystemPrompt() },
322
+ { role: 'system', content: this.getSystemPrompt() },
315
323
  ...currentMessages
316
324
  ];
317
325
  }
@@ -355,6 +363,7 @@ export class PlanExecutor {
355
363
  clearFinalResponseCallbacks();
356
364
  clearDocsSearchLLMClientGetter();
357
365
  this.currentLLMClient = null;
366
+ this.cachedSystemPrompt = null;
358
367
  }
359
368
  }
360
369
  async executeAutoMode(userMessage, llmClient, messages, _todos, isInterruptedRef, callbacks) {
@@ -47,7 +47,7 @@ export function buildTodoContext(todos) {
47
47
  }).join('\n');
48
48
  return `
49
49
  ---
50
- ## 📋 Current TODO List (${completedCount}/${todos.length} completed)
50
+ ## 🎼 Current TODO List (${completedCount}/${todos.length} completed)
51
51
 
52
52
  ${todoList}
53
53
 
@@ -2,6 +2,7 @@ import * as fs from 'fs/promises';
2
2
  import * as path from 'path';
3
3
  import { logger } from '../../../utils/logger.js';
4
4
  import { shouldIgnore } from '../../../core/ignore-filter.js';
5
+ import { getCachedFile, setCachedFile, invalidateCache } from '../../../core/file-cache.js';
5
6
  const EXCLUDED_DIRS = new Set([
6
7
  'node_modules',
7
8
  '.git',
@@ -71,7 +72,8 @@ async function _executeReadFile(args) {
71
72
  error: `File too large to read (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum: ${MAX_FILE_SIZE / 1024 / 1024}MB`,
72
73
  };
73
74
  }
74
- const content = await fs.readFile(resolvedPath, 'utf-8');
75
+ const content = getCachedFile(resolvedPath) ?? await fs.readFile(resolvedPath, 'utf-8');
76
+ setCachedFile(resolvedPath, content);
75
77
  const allLines = content.split('\n');
76
78
  const totalLines = allLines.length;
77
79
  const startIdx = offset - 1;
@@ -192,6 +194,7 @@ async function _executeCreateFile(args) {
192
194
  const dir = path.dirname(resolvedPath);
193
195
  await fs.mkdir(dir, { recursive: true });
194
196
  await fs.writeFile(resolvedPath, content, 'utf-8');
197
+ invalidateCache(resolvedPath);
195
198
  const lines = content.split('\n').length;
196
199
  logger.toolSuccess('create_file', args, { file: displayPath, lines }, 0);
197
200
  return {
@@ -354,6 +357,7 @@ async function _executeEditFile(args) {
354
357
  };
355
358
  }
356
359
  await fs.writeFile(resolvedPath, newContent, 'utf-8');
360
+ invalidateCache(resolvedPath);
357
361
  const oldLinesArr = oldString.split('\n');
358
362
  const newLinesArr = newString.split('\n');
359
363
  const replacements = replaceAll ? occurrences : 1;
@@ -106,6 +106,20 @@ export function emitReasoning(content, isStreaming = false) {
106
106
  reasoningCallback(content, isStreaming);
107
107
  }
108
108
  }
109
+ function truncateToolResult(toolName, result) {
110
+ const totalChars = result.length;
111
+ if (toolName === 'read_file') {
112
+ const totalLines = result.split('\n').length;
113
+ return result.slice(0, 20000) + `\n\n[...truncated. File has ${totalLines} total lines. Use offset parameter to read more.]`;
114
+ }
115
+ if (toolName === 'bash') {
116
+ return result.slice(0, 10000) + `\n\n[...truncated middle. Total output: ${totalChars} chars]\n\n` + result.slice(-5000);
117
+ }
118
+ if (toolName === 'search_content' || toolName === 'find_files') {
119
+ return result.slice(0, 15000) + `\n\n[...truncated. Total output: ${totalChars} chars]`;
120
+ }
121
+ return result.slice(0, 20000) + `\n\n[...truncated. Total output: ${totalChars} chars]`;
122
+ }
109
123
  export async function executeSimpleTool(toolName, args) {
110
124
  const startTime = Date.now();
111
125
  const logger = getStreamLogger();
@@ -141,6 +155,9 @@ export async function executeSimpleTool(toolName, args) {
141
155
  error: result.success ? undefined : result.error,
142
156
  });
143
157
  }
158
+ if (result.success && result.result && result.result.length > 30000) {
159
+ return { ...result, result: truncateToolResult(toolName, result.result) };
160
+ }
144
161
  return result;
145
162
  }
146
163
  export const executeFileTool = executeSimpleTool;
@@ -3,16 +3,16 @@ import { Box, Text } from 'ink';
3
3
  import Spinner from 'ink-spinner';
4
4
  import { logger } from '../../utils/logger.js';
5
5
  const ACTIVITY_INFO = {
6
- thinking: { icon: '💭', label: 'Thinking', color: 'magenta', spinnerType: 'dots' },
7
- planning: { icon: '💭', label: 'Thinking', color: 'blue', spinnerType: 'dots' },
8
- executing: { icon: '', label: 'Executing', color: 'green', spinnerType: 'line' },
9
- docs_search: { icon: '📚', label: 'Searching docs', color: 'yellow', spinnerType: 'dots' },
10
- file_read: { icon: '📖', label: 'Reading file', color: 'cyan', spinnerType: 'pipe' },
11
- file_write: { icon: '✏️', label: 'Writing file', color: 'green', spinnerType: 'pipe' },
12
- file_search: { icon: '🔍', label: 'Searching files', color: 'yellow', spinnerType: 'dots' },
13
- tool_call: { icon: '🔧', label: 'Tool call', color: 'yellow', spinnerType: 'star' },
14
- validating: { icon: '', label: 'Validating', color: 'cyan', spinnerType: 'dots' },
15
- waiting: { icon: '', label: 'Waiting', color: 'gray', spinnerType: 'dots' },
6
+ thinking: { icon: '🎵', label: 'Thinking', color: 'magenta', spinnerType: 'dots' },
7
+ planning: { icon: '🎼', label: 'Composing', color: 'blue', spinnerType: 'dots' },
8
+ executing: { icon: '🥁', label: 'Executing', color: 'green', spinnerType: 'line' },
9
+ docs_search: { icon: '🎷', label: 'Searching docs', color: 'yellow', spinnerType: 'dots' },
10
+ file_read: { icon: '🎸', label: 'Reading file', color: 'cyan', spinnerType: 'pipe' },
11
+ file_write: { icon: '🎹', label: 'Writing file', color: 'green', spinnerType: 'pipe' },
12
+ file_search: { icon: '🎺', label: 'Searching files', color: 'yellow', spinnerType: 'dots' },
13
+ tool_call: { icon: '🪕', label: 'Tool call', color: 'yellow', spinnerType: 'star' },
14
+ validating: { icon: '🎻', label: 'Validating', color: 'cyan', spinnerType: 'dots' },
15
+ waiting: { icon: '🪘', label: 'Waiting', color: 'gray', spinnerType: 'dots' },
16
16
  };
17
17
  function formatTokens(count) {
18
18
  if (count < 1000)
@@ -1233,21 +1233,21 @@ export const PlanExecuteApp = ({ llmClient: initialLlmClient, modelInfo, resumeL
1233
1233
  return '🌐';
1234
1234
  switch (toolName) {
1235
1235
  case 'read_file':
1236
- return '📖';
1236
+ return '🎸';
1237
1237
  case 'create_file':
1238
- return '📝';
1238
+ return '🎹';
1239
1239
  case 'edit_file':
1240
- return '✏️';
1240
+ return '🎻';
1241
1241
  case 'list_files':
1242
- return '📂';
1242
+ return '🎼';
1243
1243
  case 'find_files':
1244
- return '🔍';
1244
+ return '🎷';
1245
1245
  case 'tell_to_user':
1246
- return '💬';
1246
+ return '🎺';
1247
1247
  case 'bash':
1248
- return '';
1248
+ return '🥁';
1249
1249
  default:
1250
- return '🔧';
1250
+ return '🪕';
1251
1251
  }
1252
1252
  };
1253
1253
  const getToolParams = (toolName, args) => {
@@ -30,7 +30,7 @@ const Clock = () => {
30
30
  };
31
31
  const AnimatedStar = () => {
32
32
  const [phase, setPhase] = useState(0);
33
- const stars = ['', '', '', ''];
33
+ const stars = ['🎵', '🎶', '', ''];
34
34
  const colors = ['magentaBright', 'magenta', 'gray', 'magenta'];
35
35
  useEffect(() => {
36
36
  const interval = setInterval(() => {
@@ -3,13 +3,13 @@ import { Box, Text } from 'ink';
3
3
  import Spinner from 'ink-spinner';
4
4
  import { logger } from '../../utils/logger.js';
5
5
  const PHASE_INFO = {
6
- analyzing: { icon: '🔍', label: 'Analyzing', color: 'yellow' },
7
- planning: { icon: '💭', label: 'Thinking', color: 'blue' },
8
- generating: { icon: '', label: 'Generating', color: 'magenta' },
9
- executing: { icon: '', label: 'Executing', color: 'green' },
10
- validating: { icon: '', label: 'Validating', color: 'cyan' },
11
- tool_calling: { icon: '🔧', label: 'Tool Call', color: 'yellow' },
12
- waiting: { icon: '', label: 'Waiting', color: 'gray' },
6
+ analyzing: { icon: '🎷', label: 'Analyzing', color: 'yellow' },
7
+ planning: { icon: '🎼', label: 'Composing', color: 'blue' },
8
+ generating: { icon: '🎹', label: 'Generating', color: 'magenta' },
9
+ executing: { icon: '🥁', label: 'Executing', color: 'green' },
10
+ validating: { icon: '🎻', label: 'Validating', color: 'cyan' },
11
+ tool_calling: { icon: '🪕', label: 'Tool Call', color: 'yellow' },
12
+ waiting: { icon: '🪘', label: 'Waiting', color: 'gray' },
13
13
  };
14
14
  export const ThinkingIndicator = ({ phase, startTime, currentStep, totalSteps, completedSteps, }) => {
15
15
  const [elapsedSeconds, setElapsedSeconds] = useState(0);
@@ -66,22 +66,22 @@ export const ChatView = ({ messages, currentResponse, maxDisplayMessages = 10, s
66
66
  content.includes('`');
67
67
  };
68
68
  const TOOL_ICONS = {
69
- 'read_file': '📖',
70
- 'Read': '📖',
71
- 'create_file': '📝',
72
- 'Create': '📝',
73
- 'edit_file': '✏️',
74
- 'Edit': '✏️',
75
- 'search_files': '🔍',
76
- 'Search': '🔍',
77
- 'Grep': '🔍',
78
- 'grep_search': '🔍',
79
- 'list_files': '📁',
80
- 'list_directory': '📁',
81
- 'Glob': '📁',
82
- 'find_files': '🔎',
83
- 'execute_command': '',
84
- 'Bash': '',
69
+ 'read_file': '🎸',
70
+ 'Read': '🎸',
71
+ 'create_file': '🎹',
72
+ 'Create': '🎹',
73
+ 'edit_file': '🎻',
74
+ 'Edit': '🎻',
75
+ 'search_files': '🎷',
76
+ 'Search': '🎷',
77
+ 'Grep': '🎷',
78
+ 'grep_search': '🎷',
79
+ 'list_files': '🎼',
80
+ 'list_directory': '🎼',
81
+ 'Glob': '🎼',
82
+ 'find_files': '🎷',
83
+ 'execute_command': '🥁',
84
+ 'Bash': '🥁',
85
85
  };
86
86
  const normalizeToolName = (name) => {
87
87
  const nameMap = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orquesta-cli",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "description": "Orquesta CLI - AI-powered coding assistant with team collaboration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",