neuro-cli 4.3.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,12 @@ export interface AgentCallbacks {
16
16
  onApprovalNeeded?: (toolName: string, args: Record<string, unknown>, risk: string) => Promise<boolean>;
17
17
  onIteration?: (iteration: number, maxIterations: number) => void;
18
18
  onComplete?: (result: AgentRunResult) => void;
19
+ /** Called when the agent starts a new agentic cycle */
20
+ onCycleStart?: (cycle: number, summary: string) => void;
21
+ /** Called when the agent detects task completion */
22
+ onTaskComplete?: (reason: string) => void;
23
+ /** Signal to abort the agent loop (e.g. user pressed Ctrl+C) */
24
+ abortSignal?: AbortSignal;
19
25
  }
20
26
  export declare class BaseAgent {
21
27
  protected config: AgentConfig;
@@ -24,6 +30,11 @@ export declare class BaseAgent {
24
30
  protected workingDirectory: string;
25
31
  protected sessionId: string;
26
32
  protected messages: Message[];
33
+ private lastToolCalls;
34
+ private repeatedActionCount;
35
+ private static readonly MAX_REPEATED_ACTIONS;
36
+ private static readonly MAX_CONSECUTIVE_ERRORS;
37
+ private static readonly ABSOLUTE_MAX_CYCLES;
27
38
  constructor(config: AgentConfig, client: OpenRouterClient, registry: ToolRegistry, workingDirectory: string, sessionId: string);
28
39
  get name(): string;
29
40
  get description(): string;
@@ -35,7 +46,7 @@ export declare class BaseAgent {
35
46
  */
36
47
  protected initializeMessages(taskContext?: string): Message[];
37
48
  /**
38
- * Build the system prompt with context
49
+ * Build the system prompt with context — Claude Code-style
39
50
  */
40
51
  protected buildSystemPrompt(taskContext?: string): string;
41
52
  /**
@@ -51,7 +62,15 @@ export declare class BaseAgent {
51
62
  */
52
63
  protected addToolResult(toolCallId: string, content: string, name: string, isError?: boolean): void;
53
64
  /**
54
- * Run the agent loop
65
+ * Detect if the model's response indicates the task is complete
66
+ */
67
+ private isTaskComplete;
68
+ /**
69
+ * Detect doom-loop: same tool+args repeated too many times
70
+ */
71
+ private detectDoomLoop;
72
+ /**
73
+ * Run the agent loop — Claude Code style: keep going until task is truly done
55
74
  */
56
75
  run(task: string, callbacks?: AgentCallbacks, maxIterations?: number): Promise<AgentRunResult>;
57
76
  /**
@@ -1,8 +1,28 @@
1
1
  // ============================================================
2
- // NeuroCLI - Base Agent
2
+ // NeuroCLI - Base Agent v5.0 (Claude Code-style Agentic Loop)
3
3
  // Foundation class for all agents
4
+ // Key changes:
5
+ // - No arbitrary iteration limits; loops until task is complete
6
+ // - Self-evaluation after each LLM turn (is the task done?)
7
+ // - Error recovery with alternative approaches
8
+ // - Continuous tool chaining until the model says "I'm done"
9
+ // - Doom-loop detection replaces hard iteration caps
4
10
  // ============================================================
5
11
  import { MODELS } from '../api/models.js';
12
+ // Patterns that indicate the model considers the task complete
13
+ const TASK_COMPLETE_PATTERNS = [
14
+ /\b(task|job|work|mission|assignment)\s+(is\s+)?(complete|done|finished|accomplished|fulfilled)\b/i,
15
+ /\bi('ve| have)\s+(completed|finished|done|accomplished)\b/i,
16
+ /\b(all|every)\s+(the\s+)?(task|step|item|file|change|modification)s?\s+(are|is|have been)\s+(done|complete|applied|made|created)\b/i,
17
+ /\bnothing\s+(more|else)\s+(to\s+)?(do|change|modify|update)\b/i,
18
+ /\beverything\s+(is\s+)?(done|complete|ready|set|in\s+place)\b/i,
19
+ ];
20
+ // Patterns that indicate the model is still working
21
+ const STILL_WORKING_PATTERNS = [
22
+ /\b(next|then|now|i\s+need\s+to|i\s+should|i\s+will|let\s+me)\b/i,
23
+ /\b(create|write|modify|edit|update|add|remove|delete|fix|implement|refactor|install)\b/i,
24
+ /\b(read|check|verify|test|run|execute|search|find|look)\b/i,
25
+ ];
6
26
  export class BaseAgent {
7
27
  config;
8
28
  client;
@@ -10,6 +30,13 @@ export class BaseAgent {
10
30
  workingDirectory;
11
31
  sessionId;
12
32
  messages = [];
33
+ // Track repetitive actions for doom-loop detection
34
+ lastToolCalls = [];
35
+ repeatedActionCount = 0;
36
+ static MAX_REPEATED_ACTIONS = 4;
37
+ static MAX_CONSECUTIVE_ERRORS = 5;
38
+ // Safety ceiling: prevent truly infinite loops (extremely high, only for runaway agents)
39
+ static ABSOLUTE_MAX_CYCLES = 500;
13
40
  constructor(config, client, registry, workingDirectory, sessionId) {
14
41
  this.config = config;
15
42
  this.client = client;
@@ -41,7 +68,7 @@ export class BaseAgent {
41
68
  return this.messages;
42
69
  }
43
70
  /**
44
- * Build the system prompt with context
71
+ * Build the system prompt with context — Claude Code-style
45
72
  */
46
73
  buildSystemPrompt(taskContext) {
47
74
  const model = MODELS[this.config.model || ''];
@@ -55,14 +82,20 @@ export class BaseAgent {
55
82
  if (taskContext) {
56
83
  prompt += `\n\n## Task Context\n${taskContext}`;
57
84
  }
58
- prompt += `\n\n## Guidelines
59
- - Be precise and thorough in your responses
60
- - Use tools to verify your assumptions before making changes
61
- - When modifying files, make minimal, targeted changes
62
- - Always read a file before editing it
63
- - Report what you've done and what still needs to be done
64
- - If you encounter errors, analyze them before retrying
65
- - Do NOT repeat the same action if it failed - try a different approach`;
85
+ // Claude Code-style guidelines: work until the task is TRULY done
86
+ prompt += `\n\n## Critical Operating Guidelines
87
+ - You MUST continue working until the ENTIRE task is complete — do not stop after partial progress
88
+ - After each tool call, evaluate: "Is the task fully done? If not, what's the next step?"
89
+ - If a tool call fails, try a DIFFERENT approach never repeat the exact same failed action
90
+ - If you encounter an error, analyze it, understand the root cause, and fix it before moving on
91
+ - When creating or modifying files, verify your changes by reading the file back
92
+ - When implementing features, check that all related files are updated consistently
93
+ - Be thorough: create ALL necessary files, update ALL relevant imports, handle ALL edge cases
94
+ - Do NOT say "I've completed the task" unless you have verified everything works
95
+ - Chain tools naturally: read → understand → plan → implement → verify → continue if needed
96
+ - If you realize the task requires more work than initially thought, KEEP GOING
97
+ - Never use phrases like "the rest is left as an exercise" or "you can continue from here"
98
+ - Your job is to deliver a COMPLETE, WORKING solution — not a partial outline`;
66
99
  return prompt;
67
100
  }
68
101
  /**
@@ -90,14 +123,60 @@ export class BaseAgent {
90
123
  });
91
124
  }
92
125
  /**
93
- * Run the agent loop
126
+ * Detect if the model's response indicates the task is complete
127
+ */
128
+ isTaskComplete(response, hasToolCalls) {
129
+ // If the model is still calling tools, it's not done
130
+ if (hasToolCalls)
131
+ return false;
132
+ // Check for explicit completion signals
133
+ for (const pattern of TASK_COMPLETE_PATTERNS) {
134
+ if (pattern.test(response))
135
+ return true;
136
+ }
137
+ // If no tool calls and the response contains "still working" patterns, it might be stuck
138
+ // But if there are no tool calls and no "still working" patterns, assume done
139
+ const hasWorkingSignals = STILL_WORKING_PATTERNS.some(p => p.test(response));
140
+ if (!hasWorkingSignals && !hasToolCalls) {
141
+ // No tool calls + no "still working" language = probably done
142
+ return true;
143
+ }
144
+ return false;
145
+ }
146
+ /**
147
+ * Detect doom-loop: same tool+args repeated too many times
148
+ */
149
+ detectDoomLoop(toolName, args) {
150
+ const callSig = `${toolName}:${JSON.stringify(args)}`;
151
+ if (this.lastToolCalls.length >= BaseAgent.MAX_REPEATED_ACTIONS &&
152
+ this.lastToolCalls.slice(-BaseAgent.MAX_REPEATED_ACTIONS).every(c => c === callSig)) {
153
+ this.repeatedActionCount++;
154
+ if (this.repeatedActionCount >= BaseAgent.MAX_REPEATED_ACTIONS) {
155
+ return true;
156
+ }
157
+ }
158
+ else {
159
+ this.repeatedActionCount = 0;
160
+ }
161
+ this.lastToolCalls.push(callSig);
162
+ // Keep only recent history
163
+ if (this.lastToolCalls.length > 20) {
164
+ this.lastToolCalls = this.lastToolCalls.slice(-20);
165
+ }
166
+ return false;
167
+ }
168
+ /**
169
+ * Run the agent loop — Claude Code style: keep going until task is truly done
94
170
  */
95
171
  async run(task, callbacks, maxIterations) {
96
- const maxIter = maxIterations || this.config.maxIterations || 10;
172
+ // maxIterations is now a SOFT ceiling with override for continued work
173
+ // If not specified, we use our absolute max (effectively no limit)
174
+ const softCap = maxIterations || this.config.maxIterations || BaseAgent.ABSOLUTE_MAX_CYCLES;
97
175
  const startTime = Date.now();
98
176
  let totalUsage = { inputTokens: 0, outputTokens: 0, cost: 0 };
99
177
  let toolCallsMade = 0;
100
178
  let iteration = 0;
179
+ let consecutiveErrors = 0;
101
180
  const execution = {
102
181
  agentName: this.config.name,
103
182
  task,
@@ -109,8 +188,18 @@ export class BaseAgent {
109
188
  // Initialize messages
110
189
  this.initializeMessages();
111
190
  this.addUserMessage(task);
112
- for (iteration = 1; iteration <= maxIter; iteration++) {
113
- callbacks?.onIteration?.(iteration, maxIter);
191
+ this.lastToolCalls = [];
192
+ this.repeatedActionCount = 0;
193
+ // Main agentic loop — Claude Code style: keep going until done
194
+ for (iteration = 1; iteration <= BaseAgent.ABSOLUTE_MAX_CYCLES; iteration++) {
195
+ // Check abort signal
196
+ if (callbacks?.abortSignal?.aborted) {
197
+ execution.status = 'cancelled';
198
+ execution.result = 'Task cancelled by user';
199
+ break;
200
+ }
201
+ // Report iteration progress (0 means "no fixed limit")
202
+ callbacks?.onIteration?.(iteration, 0);
114
203
  // Get tool definitions for this agent
115
204
  const toolDefs = this.registry.getDefinitions(this.config.tools);
116
205
  // Prepare stream callbacks
@@ -134,19 +223,35 @@ export class BaseAgent {
134
223
  tools: toolDefs.length > 0 ? toolDefs : undefined,
135
224
  temperature: this.config.temperature,
136
225
  maxTokens: this.config.maxTokens,
137
- stream: false, // Disable streaming for better compatibility with free models
226
+ stream: false,
138
227
  }, streamCallbacks);
139
228
  totalUsage.inputTokens += response.usage.inputTokens;
140
229
  totalUsage.outputTokens += response.usage.outputTokens;
141
230
  totalUsage.cost += response.usage.cost;
142
- // If no tool calls, we're done
231
+ // Reset error counter on successful response
232
+ consecutiveErrors = 0;
233
+ // Check if task is complete (no tool calls + completion signals)
143
234
  if (response.toolCalls.length === 0) {
144
235
  this.addAssistantMessage(response.content);
145
- execution.status = 'completed';
146
- execution.result = response.content;
147
- break;
236
+ if (this.isTaskComplete(response.content, false)) {
237
+ callbacks?.onTaskComplete?.('Task completed successfully');
238
+ execution.status = 'completed';
239
+ execution.result = response.content;
240
+ break;
241
+ }
242
+ // Model returned text without tool calls but didn't signal completion
243
+ // This might be a summary or partial completion — check if we should continue
244
+ // If the soft cap is reached and there are no tool calls, we're likely done
245
+ if (iteration >= softCap) {
246
+ execution.status = 'completed';
247
+ execution.result = response.content;
248
+ break;
249
+ }
250
+ // Otherwise, add a nudge to continue working
251
+ this.addUserMessage('Continue working on the task. If there is more to do, use your tools. If the task is truly complete, say "Task complete" and summarize what was done.');
252
+ continue;
148
253
  }
149
- // Process tool calls
254
+ // Process tool calls — the agent is still working
150
255
  this.addAssistantMessage(response.content, response.toolCalls);
151
256
  for (const toolCall of response.toolCalls) {
152
257
  let args;
@@ -158,11 +263,20 @@ export class BaseAgent {
158
263
  }
159
264
  const toolName = toolCall.function.name;
160
265
  toolCallsMade++;
266
+ // Doom-loop detection
267
+ if (this.detectDoomLoop(toolName, args)) {
268
+ const msg = `Doom loop detected: "${toolName}" called with the same arguments too many times. Breaking the loop.`;
269
+ callbacks?.onThinking?.(msg);
270
+ this.addToolResult(toolCall.id, msg, toolName, true);
271
+ // Add a nudge to try a different approach
272
+ this.addUserMessage('You seem to be stuck in a loop, calling the same tool with the same arguments repeatedly. Try a completely different approach to solve this problem.');
273
+ break;
274
+ }
161
275
  callbacks?.onToolCall?.(toolName, args);
162
276
  // Check if approval is needed
163
277
  const needsApproval = this.registry.getApprovalRequest(toolName, args);
164
278
  if (needsApproval && this.config.autoApprove !== true) {
165
- const approved = await callbacks?.onApprovalNeeded?.(toolName, args, needsApproval.risk) ?? true; // Default to approve if no callback
279
+ const approved = await callbacks?.onApprovalNeeded?.(toolName, args, needsApproval.risk) ?? true;
166
280
  if (!approved) {
167
281
  this.addToolResult(toolCall.id, 'User denied this tool call.', toolName);
168
282
  callbacks?.onToolResult?.(toolName, 'Denied by user', false);
@@ -176,23 +290,52 @@ export class BaseAgent {
176
290
  agentName: this.config.name,
177
291
  onProgress: (msg) => callbacks?.onThinking?.(msg),
178
292
  };
179
- const result = await this.registry.execute(toolName, args, toolContext);
180
- // Use the original tool_call_id from the assistant's tool call, not the registry's generated one
181
- this.addToolResult(toolCall.id, result.content, toolName, result.isError);
182
- callbacks?.onToolResult?.(toolName, result.content, result.isError || false);
293
+ try {
294
+ const result = await this.registry.execute(toolName, args, toolContext);
295
+ this.addToolResult(toolCall.id, result.content, toolName, result.isError);
296
+ callbacks?.onToolResult?.(toolName, result.content, result.isError || false);
297
+ // If tool had an error, note it but continue (error recovery)
298
+ if (result.isError) {
299
+ consecutiveErrors++;
300
+ if (consecutiveErrors >= BaseAgent.MAX_CONSECUTIVE_ERRORS) {
301
+ // Add context about repeated failures
302
+ this.addUserMessage(`The last ${consecutiveErrors} tool calls have resulted in errors. Please step back, analyze the situation, and try a completely different approach. Read relevant files first to understand the current state before making changes.`);
303
+ consecutiveErrors = 0; // Reset after nudge
304
+ }
305
+ }
306
+ }
307
+ catch (toolError) {
308
+ const errMsg = toolError instanceof Error ? toolError.message : String(toolError);
309
+ this.addToolResult(toolCall.id, `Tool execution error: ${errMsg}`, toolName, true);
310
+ callbacks?.onToolResult?.(toolName, errMsg, true);
311
+ consecutiveErrors++;
312
+ }
183
313
  }
314
+ // After processing all tool calls for this iteration, report cycle progress
315
+ const cycleSummary = `${toolCallsMade} tools used, iteration ${iteration}`;
316
+ callbacks?.onCycleStart?.(iteration, cycleSummary);
184
317
  }
185
318
  catch (error) {
186
319
  const errMsg = error instanceof Error ? error.message : String(error);
187
- this.addAssistantMessage(`Error encountered: ${errMsg}`);
188
- execution.status = 'failed';
189
- execution.result = errMsg;
190
- break;
320
+ consecutiveErrors++;
321
+ // If we've had too many consecutive API errors, stop
322
+ if (consecutiveErrors >= BaseAgent.MAX_CONSECUTIVE_ERRORS) {
323
+ this.addAssistantMessage(`Error encountered: ${errMsg}. Too many consecutive errors, stopping.`);
324
+ execution.status = 'failed';
325
+ execution.result = errMsg;
326
+ break;
327
+ }
328
+ // Otherwise, add error to conversation and let the model try to recover
329
+ this.addAssistantMessage(`Error encountered: ${errMsg}. Retrying...`);
330
+ // Brief delay before retry
331
+ await new Promise(resolve => setTimeout(resolve, 1000 * consecutiveErrors));
332
+ continue;
191
333
  }
192
334
  }
193
- if (iteration > maxIter && execution.status === 'running') {
335
+ // If we hit the absolute max, mark as completed (not failed the work might be sufficient)
336
+ if (iteration > BaseAgent.ABSOLUTE_MAX_CYCLES && execution.status === 'running') {
194
337
  execution.status = 'completed';
195
- execution.result = `Max iterations reached (${maxIter}). The task may not be fully completed. Consider using a higher effort level or switching to /orchestrate mode for complex tasks.`;
338
+ execution.result = `Agent reached maximum processing cycles (${BaseAgent.ABSOLUTE_MAX_CYCLES}). The task has been worked on extensively. Review the results and provide further instructions if needed.`;
196
339
  }
197
340
  execution.endTime = Date.now();
198
341
  execution.iterations = iteration;
@@ -35,7 +35,9 @@ export declare class Orchestrator extends BaseAgent {
35
35
  */
36
36
  plan(task: string, callbacks?: AgentCallbacks): Promise<OrchestratedPlan>;
37
37
  /**
38
- * Execute a planned task with sub-agents
38
+ * Execute a planned task with sub-agents — Claude Code style
39
+ * Sub-agents run until their tasks are complete.
40
+ * After all tasks complete, verify the overall result and re-plan if needed.
39
41
  */
40
42
  orchestrate(task: string, callbacks?: AgentCallbacks, autoPlan?: boolean): Promise<OrchestratorResult>;
41
43
  /**
@@ -1,6 +1,10 @@
1
1
  // ============================================================
2
- // NeuroCLI - Orchestrator Agent
2
+ // NeuroCLI - Orchestrator Agent v5.0 (Claude Code-style)
3
3
  // Central coordinator that manages sub-agents
4
+ // Key changes:
5
+ // - Sub-agents run until their tasks are complete (no hard limits)
6
+ // - Re-planning when sub-tasks fail or need follow-up
7
+ // - Verification loop after all sub-tasks complete
4
8
  // ============================================================
5
9
  import { BaseAgent } from './base.js';
6
10
  export class Orchestrator extends BaseAgent {
@@ -40,6 +44,7 @@ ${task}
40
44
  2. Assign each sub-task to the most appropriate agent
41
45
  3. Specify dependencies between tasks (which tasks must complete before others can start)
42
46
  4. Provide any context each agent needs
47
+ 5. IMPORTANT: Be thorough — include ALL steps needed to complete the task end-to-end
43
48
 
44
49
  Respond with a JSON plan in this exact format:
45
50
  \`\`\`json
@@ -56,7 +61,7 @@ Respond with a JSON plan in this exact format:
56
61
  }
57
62
  \`\`\``;
58
63
  const messages = [
59
- { role: 'system', content: 'You are an expert task orchestrator. Always respond with valid JSON.', timestamp: Date.now() },
64
+ { role: 'system', content: 'You are an expert task orchestrator. Always respond with valid JSON. Be thorough — include every step needed.', timestamp: Date.now() },
60
65
  { role: 'user', content: planPrompt, timestamp: Date.now() },
61
66
  ];
62
67
  let response;
@@ -64,21 +69,18 @@ Respond with a JSON plan in this exact format:
64
69
  response = await this.client.quickChat(this.config.model || 'anthropic/claude-sonnet-4', messages);
65
70
  }
66
71
  catch {
67
- // API error during planning, fallback to direct approach
68
72
  return {
69
73
  reasoning: 'API error during planning, falling back to direct approach',
70
74
  tasks: [{ agent: 'Coder', task, dependsOn: [] }],
71
75
  };
72
76
  }
73
77
  try {
74
- // Extract JSON from response
75
78
  const jsonMatch = response.content.match(/```json\n([\s\S]*?)\n```/) ||
76
79
  response.content.match(/\{[\s\S]*\}/);
77
80
  const jsonStr = jsonMatch ? (jsonMatch[1] || jsonMatch[0]) : response.content;
78
81
  return JSON.parse(jsonStr);
79
82
  }
80
83
  catch {
81
- // Fallback: use coder agent directly
82
84
  return {
83
85
  reasoning: 'Could not parse plan, defaulting to direct coding approach',
84
86
  tasks: [{ agent: 'Coder', task, dependsOn: [] }],
@@ -86,7 +88,9 @@ Respond with a JSON plan in this exact format:
86
88
  }
87
89
  }
88
90
  /**
89
- * Execute a planned task with sub-agents
91
+ * Execute a planned task with sub-agents — Claude Code style
92
+ * Sub-agents run until their tasks are complete.
93
+ * After all tasks complete, verify the overall result and re-plan if needed.
90
94
  */
91
95
  async orchestrate(task, callbacks, autoPlan = true) {
92
96
  const startTime = Date.now();
@@ -103,7 +107,7 @@ Respond with a JSON plan in this exact format:
103
107
  // Step 1: Create execution plan
104
108
  let plan;
105
109
  if (autoPlan) {
106
- callbacks?.onThinking?.('🧠 Planning task decomposition...');
110
+ callbacks?.onThinking?.('Planning task decomposition...');
107
111
  plan = await this.plan(task, callbacks);
108
112
  }
109
113
  else {
@@ -112,11 +116,11 @@ Respond with a JSON plan in this exact format:
112
116
  tasks: [{ agent: 'Coder', task }],
113
117
  };
114
118
  }
115
- callbacks?.onThinking?.(`📋 Plan: ${plan.tasks.length} sub-tasks`);
116
- callbacks?.onThinking?.(`💭 ${plan.reasoning}`);
117
- // Step 2: Execute tasks respecting dependencies
119
+ callbacks?.onThinking?.(`Plan: ${plan.tasks.length} sub-tasks — ${plan.reasoning}`);
120
+ // Step 2: Execute tasks respecting dependencies — each agent runs until done
118
121
  const completedTasks = new Set();
119
122
  let taskIndex = 0;
123
+ let maxReplans = 3; // Allow up to 3 re-planning cycles
120
124
  while (completedTasks.size < plan.tasks.length) {
121
125
  // Find tasks whose dependencies are all completed
122
126
  const readyTasks = plan.tasks.filter(t => {
@@ -127,23 +131,28 @@ Respond with a JSON plan in this exact format:
127
131
  return t.dependsOn.every(dep => completedTasks.has(dep));
128
132
  });
129
133
  if (readyTasks.length === 0) {
130
- // Deadlock detection - log unresolved tasks
134
+ // Deadlock detection
131
135
  const unresolved = plan.tasks.filter(t => !completedTasks.has(t.agent + ':' + t.task));
132
136
  if (unresolved.length > 0) {
133
- callbacks?.onThinking?.(`⚠️ Deadlock detected. Unresolved tasks: ${unresolved.map(t => t.agent + ':' + t.task).join(', ')}`);
137
+ callbacks?.onThinking?.(`Deadlock detected. Unresolved tasks: ${unresolved.map(t => t.agent + ':' + t.task).join(', ')}`);
138
+ // Clear dependency constraints to break deadlock
139
+ for (const t of unresolved) {
140
+ t.dependsOn = [];
141
+ }
142
+ continue;
134
143
  }
135
144
  break;
136
145
  }
137
- // Execute ready tasks (could be parallelized in future)
146
+ // Execute ready tasks (sequentially for safety, could parallelize in future)
138
147
  for (const subTask of readyTasks) {
139
148
  const agent = this.agents.get(subTask.agent);
140
149
  if (!agent) {
141
- callbacks?.onThinking?.(`⚠️ Agent not found: ${subTask.agent}`);
150
+ callbacks?.onThinking?.(`Agent not found: ${subTask.agent}`);
142
151
  completedTasks.add(subTask.agent + ':' + subTask.task);
143
152
  continue;
144
153
  }
145
154
  taskIndex++;
146
- callbacks?.onThinking?.(`\n🤖 [${taskIndex}/${plan.tasks.length}] Running ${subTask.agent}: ${subTask.task.slice(0, 80)}...`);
155
+ callbacks?.onThinking?.(`[${taskIndex}/${plan.tasks.length}] Running ${subTask.agent}: ${subTask.task.slice(0, 80)}...`);
147
156
  // Build context from previous agent results
148
157
  let fullTask = subTask.task;
149
158
  if (subTask.context) {
@@ -160,16 +169,23 @@ Respond with a JSON plan in this exact format:
160
169
  fullTask = `${fullTask}\n\n## Context from previous agents:\n${depResults}`;
161
170
  }
162
171
  }
172
+ // Run the sub-agent — it will keep going until its task is complete
163
173
  let result;
164
174
  try {
165
175
  result = await agent.run(fullTask, {
166
176
  onToken: (token) => callbacks?.onToken?.(token),
167
177
  onToolCall: (name, args) => callbacks?.onToolCall?.(name, args),
168
- onToolResult: (name, result, isError) => callbacks?.onToolResult?.(name, result, isError),
178
+ onToolResult: (name, res, isError) => callbacks?.onToolResult?.(name, res, isError),
169
179
  onApprovalNeeded: async (name, args, risk) => {
170
180
  return callbacks?.onApprovalNeeded?.(name, args, risk) ?? true;
171
181
  },
172
182
  onThinking: (thinking) => callbacks?.onThinking?.(thinking),
183
+ onIteration: (i, _max) => {
184
+ callbacks?.onThinking?.(` ${subTask.agent} step ${i}`);
185
+ },
186
+ onTaskComplete: (reason) => {
187
+ callbacks?.onThinking?.(` ${subTask.agent}: ${reason}`);
188
+ },
173
189
  });
174
190
  }
175
191
  catch (error) {
@@ -14,82 +14,82 @@ export const DEFAULT_CONFIG = {
14
14
  planner: {
15
15
  name: 'Planner',
16
16
  description: 'Task decomposition and planning specialist',
17
- systemPrompt: `You are an expert software architect and planner. Your job is to break down complex tasks into clear, actionable steps. For each step, specify which agent should handle it and what tools they should use. Be thorough but concise.`,
17
+ systemPrompt: `You are an expert software architect and planner. Your job is to break down complex tasks into clear, actionable steps. For each step, specify which agent should handle it and what tools they should use. Be thorough but concise. Keep working until you have a COMPLETE plan covering every aspect of the task.`,
18
18
  model: 'qwen/qwen3-coder:free',
19
19
  temperature: 0.7,
20
20
  maxTokens: 4096,
21
21
  tools: ['read_file', 'search_files', 'list_directory'],
22
- maxIterations: 10,
22
+ maxIterations: 0, // 0 = no limit, run until done
23
23
  },
24
24
  coder: {
25
25
  name: 'Coder',
26
26
  description: 'Code generation and modification specialist',
27
- systemPrompt: `You are an expert software developer. You write clean, efficient, well-documented code. You understand design patterns, best practices, and can work with any programming language or framework. When modifying existing code, you make minimal, targeted changes. Always consider edge cases and error handling.`,
27
+ systemPrompt: `You are an expert software developer. You write clean, efficient, well-documented code. You understand design patterns, best practices, and can work with any programming language or framework. When modifying existing code, you make minimal, targeted changes. Always consider edge cases and error handling. IMPORTANT: You MUST keep working until the entire task is COMPLETE — do not stop after creating only some files. Create ALL necessary files, update ALL imports, and verify your work.`,
28
28
  model: 'qwen/qwen3-coder:free',
29
29
  temperature: 0.4,
30
30
  maxTokens: 16384,
31
31
  tools: ['read_file', 'write_file', 'edit_file', 'search_files', 'list_directory', 'run_command', 'apply_diff'],
32
- maxIterations: 50,
32
+ maxIterations: 0, // 0 = no limit, run until done
33
33
  },
34
34
  reviewer: {
35
35
  name: 'Reviewer',
36
36
  description: 'Code review and quality assurance specialist',
37
- systemPrompt: `You are an expert code reviewer. You analyze code for bugs, security vulnerabilities, performance issues, and adherence to best practices. You provide specific, actionable feedback with line references. You categorize issues by severity (critical, warning, suggestion). You also check for test coverage and documentation.`,
37
+ systemPrompt: `You are an expert code reviewer. You analyze code for bugs, security vulnerabilities, performance issues, and adherence to best practices. You provide specific, actionable feedback with line references. You categorize issues by severity (critical, warning, suggestion). You also check for test coverage and documentation. Keep reviewing until you have checked ALL relevant files.`,
38
38
  model: 'nvidia/nemotron-3-super-120b-a12b:free',
39
39
  temperature: 0.3,
40
40
  maxTokens: 8192,
41
41
  tools: ['read_file', 'search_files', 'list_directory'],
42
- maxIterations: 15,
42
+ maxIterations: 0,
43
43
  },
44
44
  researcher: {
45
45
  name: 'Researcher',
46
46
  description: 'Information gathering and analysis specialist',
47
- systemPrompt: `You are an expert researcher and analyst. You gather information from files, web resources, and codebases. You synthesize findings into clear, structured reports. You can explain complex technical concepts and find relevant examples or documentation.`,
47
+ systemPrompt: `You are an expert researcher and analyst. You gather information from files, web resources, and codebases. You synthesize findings into clear, structured reports. You can explain complex technical concepts and find relevant examples or documentation. Keep researching until you have a COMPLETE picture.`,
48
48
  model: 'google/gemma-4-31b-it:free',
49
49
  temperature: 0.5,
50
50
  maxTokens: 8192,
51
51
  tools: ['read_file', 'search_files', 'list_directory', 'web_search', 'web_fetch'],
52
- maxIterations: 20,
52
+ maxIterations: 0,
53
53
  },
54
54
  tester: {
55
55
  name: 'Tester',
56
56
  description: 'Test generation and execution specialist',
57
- systemPrompt: `You are an expert QA engineer. You write comprehensive test suites covering unit tests, integration tests, and edge cases. You run tests and analyze failures to identify root causes. You ensure code meets quality standards before it's considered complete.`,
57
+ systemPrompt: `You are an expert QA engineer. You write comprehensive test suites covering unit tests, integration tests, and edge cases. You run tests and analyze failures to identify root causes. You ensure code meets quality standards before it's considered complete. Keep testing until ALL tests pass.`,
58
58
  model: 'qwen/qwen3-coder:free',
59
59
  temperature: 0.3,
60
60
  maxTokens: 8192,
61
61
  tools: ['read_file', 'write_file', 'search_files', 'run_command', 'list_directory'],
62
- maxIterations: 25,
62
+ maxIterations: 0,
63
63
  },
64
64
  debugger: {
65
65
  name: 'Debugger',
66
66
  description: 'Bug investigation and fixing specialist',
67
- systemPrompt: `You are an expert debugger. You systematically investigate bugs by reading code, running diagnostic commands, analyzing error messages and stack traces. You identify root causes and implement targeted fixes. You verify fixes work before reporting completion.`,
67
+ systemPrompt: `You are an expert debugger. You systematically investigate bugs by reading code, running diagnostic commands, analyzing error messages and stack traces. You identify root causes and implement targeted fixes. You verify fixes work before reporting completion. Keep debugging until the bug is COMPLETELY fixed and verified.`,
68
68
  model: 'qwen/qwen3-coder:free',
69
69
  temperature: 0.2,
70
70
  maxTokens: 8192,
71
71
  tools: ['read_file', 'edit_file', 'search_files', 'run_command', 'list_directory', 'apply_diff'],
72
- maxIterations: 20,
72
+ maxIterations: 0,
73
73
  },
74
74
  architect: {
75
75
  name: 'Architect',
76
76
  description: 'System design and architecture specialist',
77
- systemPrompt: `You are an expert software architect. You design scalable, maintainable system architectures. You make technology stack decisions, define component boundaries, and establish coding standards. You create detailed technical specifications that other agents can implement.`,
77
+ systemPrompt: `You are an expert software architect. You design scalable, maintainable system architectures. You make technology stack decisions, define component boundaries, and establish coding standards. You create detailed technical specifications that other agents can implement. Keep designing until the architecture is COMPLETE and all components are specified.`,
78
78
  model: 'nvidia/nemotron-3-ultra-550b-a55b:free',
79
79
  temperature: 0.7,
80
80
  maxTokens: 8192,
81
81
  tools: ['read_file', 'search_files', 'list_directory'],
82
- maxIterations: 15,
82
+ maxIterations: 0,
83
83
  },
84
84
  devops: {
85
85
  name: 'DevOps',
86
86
  description: 'Deployment and infrastructure specialist',
87
- systemPrompt: `You are an expert DevOps engineer. You handle CI/CD pipelines, Docker configurations, cloud deployments, and infrastructure as code. You optimize build processes and ensure reliable deployments.`,
87
+ systemPrompt: `You are an expert DevOps engineer. You handle CI/CD pipelines, Docker configurations, cloud deployments, and infrastructure as code. You optimize build processes and ensure reliable deployments. Keep working until the deployment is FULLY configured and verified.`,
88
88
  model: 'cohere/north-mini-code:free',
89
89
  temperature: 0.3,
90
90
  maxTokens: 8192,
91
91
  tools: ['read_file', 'write_file', 'edit_file', 'run_command', 'search_files', 'list_directory'],
92
- maxIterations: 25,
92
+ maxIterations: 0,
93
93
  },
94
94
  },
95
95
  tools: {
@@ -208,7 +208,7 @@ export const DEFAULT_CONFIG = {
208
208
  autoMode: {
209
209
  enabled: false,
210
210
  safetyLevel: 'conservative',
211
- maxIterations: 50,
211
+ maxIterations: 0, // 0 = no limit, run until done (Claude Code style)
212
212
  maxCost: 0,
213
213
  maxTimeMs: 0,
214
214
  blockedCommands: ['rm -rf /', 'mkfs', 'dd if=/dev/zero'],
@@ -137,7 +137,9 @@ export declare class NeuroEngine {
137
137
  */
138
138
  private initializeAgents;
139
139
  /**
140
- * Process a user message
140
+ * Process a user message — Claude Code style
141
+ * Every task is sent to the best agent which runs until completion.
142
+ * No arbitrary early termination — the agent keeps working until done.
141
143
  */
142
144
  processMessage(message: string, mode?: 'auto' | 'agent' | 'direct', targetAgent?: string): Promise<{
143
145
  content: string;
@@ -153,8 +155,9 @@ export declare class NeuroEngine {
153
155
  */
154
156
  private handleApproval;
155
157
  /**
156
- * Assess task complexity to decide execution mode
157
- * Now delegates to ModelRouter for more sophisticated analysis
158
+ * Assess task complexity delegates to ModelRouter
159
+ * Note: complexity no longer determines execution mode (all tasks run until complete)
160
+ * but is still used for model selection
158
161
  */
159
162
  private assessComplexity;
160
163
  /**
@@ -1,5 +1,5 @@
1
1
  // ============================================================
2
- // NeuroCLI - NeuroEngine v4.1.3
2
+ // NeuroCLI - NeuroEngine v5.0 (Claude Code-style Agentic Loop)
3
3
  // The main engine that ties everything together
4
4
  // Now with: Sandbox, Plugin SDK, Enhanced MCP, Enhanced Approval,
5
5
  // Model Router, Prompt Cache, Undo/Redo, Output Styles,
@@ -483,7 +483,7 @@ export class NeuroEngine {
483
483
  this.gitWorktree = new GitWorktreeManager(process.cwd());
484
484
  // Auto-Updater
485
485
  this.updater = new AutoUpdater({
486
- currentVersion: '4.1.3',
486
+ currentVersion: '5.0.0',
487
487
  autoCheck: true,
488
488
  autoUpdate: false,
489
489
  });
@@ -523,6 +523,7 @@ Key responsibilities:
523
523
  - Manage dependencies between sub-tasks
524
524
  - Synthesize results from multiple agents
525
525
  - Handle errors and re-plan if needed
526
+ - IMPORTANT: Keep working until the ENTIRE task is COMPLETE
526
527
 
527
528
  Always consider the strengths of each agent when delegating:
528
529
  - Planner: For task decomposition and architecture decisions
@@ -537,7 +538,7 @@ Always consider the strengths of each agent when delegating:
537
538
  temperature: 0.7,
538
539
  maxTokens: 4096,
539
540
  tools: [],
540
- maxIterations: 20,
541
+ maxIterations: 0, // 0 = no limit, run until done
541
542
  };
542
543
  this.orchestrator = new Orchestrator(orchestratorConfig, this.client, this.registry, process.cwd(), this.sessionManager.getCurrent()?.id || 'default');
543
544
  // Register all agents with orchestrator
@@ -634,7 +635,9 @@ Always consider the strengths of each agent when delegating:
634
635
  }
635
636
  }
636
637
  /**
637
- * Process a user message
638
+ * Process a user message — Claude Code style
639
+ * Every task is sent to the best agent which runs until completion.
640
+ * No arbitrary early termination — the agent keeps working until done.
638
641
  */
639
642
  async processMessage(message, mode = 'auto', targetAgent) {
640
643
  // Check spending limit via spending monitor
@@ -687,7 +690,7 @@ Always consider the strengths of each agent when delegating:
687
690
  const skillAdditions = this.skillSystem.getSystemPromptAdditions();
688
691
  const styleAddition = this.styleManager.getSystemPromptAddition();
689
692
  const thinkingAddition = this.extendedThinking.getSystemPromptAddition();
690
- // Build UI callbacks
693
+ // Build UI callbacks — Claude Code style
691
694
  const callbacks = {
692
695
  onThinking: (thinking) => this.ui.thinking(thinking),
693
696
  onToken: (token) => this.ui.streamingToken(token),
@@ -702,28 +705,32 @@ Always consider the strengths of each agent when delegating:
702
705
  return;
703
706
  }
704
707
  this.ui.toolCall(name, args);
705
- // Record in undo/redo for file modification tools
706
- if (['write_file', 'edit_file', 'apply_diff', 'delete_file'].includes(name)) {
707
- // The undo/redo push will happen in the tool execution result handler
708
- }
709
708
  },
710
709
  onToolResult: (name, result, isError) => this.ui.toolResult(name, result, isError),
711
710
  onApprovalNeeded: async (name, args, risk) => {
712
711
  return this.handleApproval(name, args, risk);
713
712
  },
714
- onIteration: (i, max) => {
715
- this.ui.info(`Iteration ${i}/${max}`);
713
+ onIteration: (i, _max) => {
714
+ // Claude Code style: show iteration count without a ceiling
715
+ this.ui.agentActivity(this.config.defaultModel, 'working', `step ${i}`);
716
+ },
717
+ onCycleStart: (cycle, summary) => {
718
+ this.ui.agentActivity(this.config.defaultModel, 'working', `cycle ${cycle}: ${summary}`);
719
+ },
720
+ onTaskComplete: (reason) => {
721
+ this.ui.agentActivity(this.config.defaultModel, 'done', reason);
716
722
  },
717
723
  };
718
724
  let result;
719
725
  const activeModel = routeDecision?.model || this.config.defaultModel;
726
+ // === Claude Code-style routing: always send to the best agent and let it run until done ===
720
727
  if (mode === 'direct' && targetAgent) {
728
+ // Direct mode: use specified agent
721
729
  const agent = this.agents.get(targetAgent);
722
730
  if (!agent) {
723
731
  this.ui.error(`Agent not found: ${targetAgent}`);
724
732
  return { content: '', usage: { inputTokens: 0, outputTokens: 0, cost: 0 } };
725
733
  }
726
- // Override agent model if defaultModel differs from agent's model
727
734
  const originalModel = agent.configModel;
728
735
  if (this.config.defaultModel !== originalModel) {
729
736
  agent.configModel = this.config.defaultModel;
@@ -735,10 +742,10 @@ Always consider the strengths of each agent when delegating:
735
742
  finally {
736
743
  this.ui.endStreaming();
737
744
  }
738
- // Restore original model
739
745
  agent.configModel = originalModel;
740
746
  }
741
747
  else if (mode === 'agent') {
748
+ // Orchestration mode: multi-agent with re-planning
742
749
  const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
743
750
  result = {
744
751
  content: orchestrateResult.content,
@@ -749,58 +756,52 @@ Always consider the strengths of each agent when delegating:
749
756
  };
750
757
  }
751
758
  else {
752
- const complexity = routeDecision?.complexity || this.assessComplexity(message);
759
+ // Auto mode Claude Code style: route to best agent, let it run until done
753
760
  const category = routeDecision?.category || this.modelRouter.getCategory(message);
754
- if (complexity === 'simple') {
755
- // Route to the best agent based on task category
756
- const targetAgentName = this.selectAgentForCategory(category);
757
- const agent = this.agents.get(targetAgentName);
758
- if (agent) {
759
- this.ui.info(`Using ${targetAgentName} agent (${category} task)`);
761
+ const targetAgentName = this.selectAgentForCategory(category);
762
+ const agent = this.agents.get(targetAgentName);
763
+ if (agent) {
764
+ // Override agent model with routed model if different
765
+ const originalModel = agent.configModel;
766
+ if (activeModel !== originalModel) {
767
+ agent.configModel = activeModel;
768
+ }
769
+ this.ui.info(`Using ${targetAgentName} agent (${category} task) — will run until complete`);
770
+ this.ui.startStreaming();
771
+ try {
772
+ result = await agent.run(message, callbacks);
773
+ }
774
+ finally {
775
+ this.ui.endStreaming();
776
+ }
777
+ // Restore original model
778
+ agent.configModel = originalModel;
779
+ }
780
+ else {
781
+ // Fallback: try Coder, then orchestrator
782
+ const coderAgent = this.agents.get('Coder');
783
+ if (coderAgent) {
784
+ this.ui.info(`Using Coder agent — will run until complete`);
760
785
  this.ui.startStreaming();
761
786
  try {
762
- result = await agent.run(message, callbacks);
787
+ result = await coderAgent.run(message, callbacks);
763
788
  }
764
789
  finally {
765
790
  this.ui.endStreaming();
766
791
  }
767
792
  }
768
793
  else {
769
- // Fallback to Coder
770
- const coderAgent = this.agents.get('Coder');
771
- if (coderAgent) {
772
- this.ui.startStreaming();
773
- try {
774
- result = await coderAgent.run(message, callbacks);
775
- }
776
- finally {
777
- this.ui.endStreaming();
778
- }
779
- }
780
- else {
781
- this.ui.warning('No agents initialized, using orchestration mode');
782
- const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
783
- result = {
784
- content: orchestrateResult.content,
785
- toolCallsMade: 0,
786
- iterations: orchestrateResult.execution.iterations,
787
- usage: orchestrateResult.totalUsage,
788
- execution: orchestrateResult.execution,
789
- };
790
- }
794
+ this.ui.warning('No agents initialized, using orchestration mode');
795
+ const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
796
+ result = {
797
+ content: orchestrateResult.content,
798
+ toolCallsMade: 0,
799
+ iterations: orchestrateResult.execution.iterations,
800
+ usage: orchestrateResult.totalUsage,
801
+ execution: orchestrateResult.execution,
802
+ };
791
803
  }
792
804
  }
793
- else {
794
- this.ui.thinking('Analyzing task complexity... Using multi-agent orchestration');
795
- const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
796
- result = {
797
- content: orchestrateResult.content,
798
- toolCallsMade: 0,
799
- iterations: orchestrateResult.execution.iterations,
800
- usage: orchestrateResult.totalUsage,
801
- execution: orchestrateResult.execution,
802
- };
803
- }
804
805
  }
805
806
  // Parse extended thinking blocks from response
806
807
  const thinkingResult = this.extendedThinking.parseResponse(result.content);
@@ -914,8 +915,9 @@ Always consider the strengths of each agent when delegating:
914
915
  return result.approved;
915
916
  }
916
917
  /**
917
- * Assess task complexity to decide execution mode
918
- * Now delegates to ModelRouter for more sophisticated analysis
918
+ * Assess task complexity delegates to ModelRouter
919
+ * Note: complexity no longer determines execution mode (all tasks run until complete)
920
+ * but is still used for model selection
919
921
  */
920
922
  assessComplexity(message) {
921
923
  const decision = this.modelRouter.route(message);
@@ -72,7 +72,7 @@ const COMPLEXITY_SIGNALS = {
72
72
  /\b(hello|hi|thanks|yes|no|ok|sure|done|correct|right|please)\b/i,
73
73
  ],
74
74
  lengthThreshold: 80,
75
- maxSteps: 5,
75
+ maxSteps: 0, // 0 = no limit (Claude Code style)
76
76
  },
77
77
  moderate: {
78
78
  patterns: [
@@ -83,7 +83,7 @@ const COMPLEXITY_SIGNALS = {
83
83
  /\b(refactor|clean|simplify|optimize|restructure)\b/i,
84
84
  ],
85
85
  lengthThreshold: 300,
86
- maxSteps: 15,
86
+ maxSteps: 0, // 0 = no limit (Claude Code style)
87
87
  },
88
88
  complex: {
89
89
  patterns: [
@@ -97,7 +97,7 @@ const COMPLEXITY_SIGNALS = {
97
97
  /\b(security\s+(audit|review|hardening)|performance\s+(optim|tuning|profiling)|scalab(ility|le))\b/i,
98
98
  ],
99
99
  lengthThreshold: 500,
100
- maxSteps: 30,
100
+ maxSteps: 0, // 0 = no limit (Claude Code style)
101
101
  },
102
102
  };
103
103
  // ---------------------------------------------------------------------------
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // ============================================================
3
3
  // NeuroCLI - Advanced AI Terminal Coding Assistant
4
- // Main Entry Point - v4.1.3 with robust error handling
4
+ // Main Entry Point - v5.0 (Claude Code-style Agentic Loop)
5
5
  // ============================================================
6
6
  import { Command } from 'commander';
7
7
  import { createInterface } from 'readline';
@@ -16,7 +16,7 @@ import { HeadlessMode } from './core/headless.js';
16
16
  import { ShellCompletionGenerator } from './core/shell-completion.js';
17
17
  import chalk from 'chalk';
18
18
  import { AutoUpdater } from './core/updater.js';
19
- const VERSION = '4.3.0';
19
+ const VERSION = '5.0.0';
20
20
  // ---- Global Error Handlers (prevent crashes) ----
21
21
  process.on('unhandledRejection', (reason) => {
22
22
  console.error(chalk.red('\n⚠️ Unhandled promise rejection:'), reason);
@@ -21,7 +21,7 @@ export declare class TerminalUI {
21
21
  approvalRequest(toolName: string, args: Record<string, unknown>, risk: 'low' | 'medium' | 'high'): boolean;
22
22
  tokenUsage(usage: TokenUsage, modelId: string): void;
23
23
  sessionStats(totalInput: number, totalOutput: number, totalCost: number): void;
24
- agentActivity(agentName: string, status: 'starting' | 'working' | 'done' | 'error'): void;
24
+ agentActivity(agentName: string, status: 'starting' | 'working' | 'done' | 'error', detail?: string): void;
25
25
  error(message: string): void;
26
26
  info(message: string): void;
27
27
  success(message: string): void;
@@ -165,7 +165,7 @@ export class TerminalUI {
165
165
  console.log(` ${this.theme.muted('Session:')}`, this.theme.dim(`${totalInput.toLocaleString()} in · ${totalOutput.toLocaleString()} out · $${totalCost.toFixed(4)}`));
166
166
  }
167
167
  // ── Agent Activity (subtle indicator) ───────────────────
168
- agentActivity(agentName, status) {
168
+ agentActivity(agentName, status, detail) {
169
169
  const indicators = {
170
170
  starting: this.theme.muted('○'),
171
171
  working: this.theme.accent('◎'),
@@ -178,7 +178,8 @@ export class TerminalUI {
178
178
  done: 'done',
179
179
  error: 'failed',
180
180
  };
181
- console.log(` ${indicators[status]} ${this.theme.muted(agentName)} ${this.theme.dim(statusText[status])}`);
181
+ const detailStr = detail ? ` ${this.theme.dim(detail)}` : '';
182
+ console.log(` ${indicators[status]} ${this.theme.muted(agentName)} ${this.theme.dim(statusText[status])}${detailStr}`);
182
183
  }
183
184
  // ── Status Messages (minimal) ───────────────────────────
184
185
  error(message) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neuro-cli",
3
- "version": "4.3.0",
3
+ "version": "5.0.0",
4
4
  "description": "Advanced AI-powered terminal coding assistant with multi-agent orchestration, sub-agent spawning, ACP protocol, OS-level sandboxing, spec-driven development, smart monitoring, multi-model routing, MCP Apps, auto-updater, and 23+ free models",
5
5
  "main": "dist/index.js",
6
6
  "bin": {