neuro-cli 4.1.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -0
  3. package/dist/advisor/advisor.d.ts +50 -0
  4. package/dist/advisor/advisor.js +178 -0
  5. package/dist/agents/base.d.ts +62 -0
  6. package/dist/agents/base.js +215 -0
  7. package/dist/agents/orchestrator.d.ts +46 -0
  8. package/dist/agents/orchestrator.js +192 -0
  9. package/dist/agents/team.d.ts +51 -0
  10. package/dist/agents/team.js +210 -0
  11. package/dist/api/models.d.ts +23 -0
  12. package/dist/api/models.js +514 -0
  13. package/dist/api/ollama.d.ts +153 -0
  14. package/dist/api/ollama.js +751 -0
  15. package/dist/api/openrouter.d.ts +55 -0
  16. package/dist/api/openrouter.js +223 -0
  17. package/dist/commands/commands.d.ts +43 -0
  18. package/dist/commands/commands.js +308 -0
  19. package/dist/config/config.d.ts +8 -0
  20. package/dist/config/config.js +311 -0
  21. package/dist/context/compaction.d.ts +54 -0
  22. package/dist/context/compaction.js +251 -0
  23. package/dist/context/custom-agents.d.ts +107 -0
  24. package/dist/context/custom-agents.js +397 -0
  25. package/dist/context/custom-tools.d.ts +120 -0
  26. package/dist/context/custom-tools.js +564 -0
  27. package/dist/context/git-checkpoint.d.ts +52 -0
  28. package/dist/context/git-checkpoint.js +240 -0
  29. package/dist/context/neuro-md.d.ts +48 -0
  30. package/dist/context/neuro-md.js +202 -0
  31. package/dist/context/neuroignore.d.ts +102 -0
  32. package/dist/context/neuroignore.js +441 -0
  33. package/dist/context/repo-map.d.ts +38 -0
  34. package/dist/context/repo-map.js +220 -0
  35. package/dist/context/skill-standard.d.ts +262 -0
  36. package/dist/context/skill-standard.js +1156 -0
  37. package/dist/context/skill-system.d.ts +75 -0
  38. package/dist/context/skill-system.js +578 -0
  39. package/dist/context/tree-sitter.d.ts +99 -0
  40. package/dist/context/tree-sitter.js +1956 -0
  41. package/dist/core/acp.d.ts +325 -0
  42. package/dist/core/acp.js +1498 -0
  43. package/dist/core/api-server.d.ts +143 -0
  44. package/dist/core/api-server.js +550 -0
  45. package/dist/core/approval.d.ts +81 -0
  46. package/dist/core/approval.js +432 -0
  47. package/dist/core/auto-compact.d.ts +127 -0
  48. package/dist/core/auto-compact.js +436 -0
  49. package/dist/core/auto-mode.d.ts +232 -0
  50. package/dist/core/auto-mode.js +831 -0
  51. package/dist/core/background-session.d.ts +166 -0
  52. package/dist/core/background-session.js +696 -0
  53. package/dist/core/cicd.d.ts +257 -0
  54. package/dist/core/cicd.js +1443 -0
  55. package/dist/core/cloud-sync.d.ts +156 -0
  56. package/dist/core/cloud-sync.js +582 -0
  57. package/dist/core/code-review.d.ts +132 -0
  58. package/dist/core/code-review.js +1191 -0
  59. package/dist/core/completion.d.ts +49 -0
  60. package/dist/core/completion.js +384 -0
  61. package/dist/core/context.d.ts +38 -0
  62. package/dist/core/context.js +144 -0
  63. package/dist/core/diff-preview.d.ts +35 -0
  64. package/dist/core/diff-preview.js +173 -0
  65. package/dist/core/doom-loop.d.ts +51 -0
  66. package/dist/core/doom-loop.js +179 -0
  67. package/dist/core/engine.d.ts +183 -0
  68. package/dist/core/engine.js +942 -0
  69. package/dist/core/extended-thinking.d.ts +103 -0
  70. package/dist/core/extended-thinking.js +269 -0
  71. package/dist/core/fallback.d.ts +54 -0
  72. package/dist/core/fallback.js +104 -0
  73. package/dist/core/git-worktree.d.ts +139 -0
  74. package/dist/core/git-worktree.js +614 -0
  75. package/dist/core/headless.d.ts +30 -0
  76. package/dist/core/headless.js +101 -0
  77. package/dist/core/i18n.d.ts +83 -0
  78. package/dist/core/i18n.js +739 -0
  79. package/dist/core/linting.d.ts +129 -0
  80. package/dist/core/linting.js +699 -0
  81. package/dist/core/model-router.d.ts +109 -0
  82. package/dist/core/model-router.js +581 -0
  83. package/dist/core/multi-model.d.ts +243 -0
  84. package/dist/core/multi-model.js +1099 -0
  85. package/dist/core/multi-session.d.ts +144 -0
  86. package/dist/core/multi-session.js +442 -0
  87. package/dist/core/multimodal.d.ts +125 -0
  88. package/dist/core/multimodal.js +286 -0
  89. package/dist/core/observability.d.ts +93 -0
  90. package/dist/core/observability.js +737 -0
  91. package/dist/core/os-sandbox.d.ts +122 -0
  92. package/dist/core/os-sandbox.js +1193 -0
  93. package/dist/core/outcome-grading.d.ts +228 -0
  94. package/dist/core/outcome-grading.js +1123 -0
  95. package/dist/core/output-styles.d.ts +57 -0
  96. package/dist/core/output-styles.js +382 -0
  97. package/dist/core/parallel-agents.d.ts +183 -0
  98. package/dist/core/parallel-agents.js +563 -0
  99. package/dist/core/plugin-bundle.d.ts +236 -0
  100. package/dist/core/plugin-bundle.js +887 -0
  101. package/dist/core/plugin-sdk.d.ts +139 -0
  102. package/dist/core/plugin-sdk.js +273 -0
  103. package/dist/core/prompt-cache.d.ts +163 -0
  104. package/dist/core/prompt-cache.js +599 -0
  105. package/dist/core/sandbox.d.ts +127 -0
  106. package/dist/core/sandbox.js +369 -0
  107. package/dist/core/scheduled-tasks.d.ts +151 -0
  108. package/dist/core/scheduled-tasks.js +502 -0
  109. package/dist/core/security-scanner.d.ts +160 -0
  110. package/dist/core/security-scanner.js +1494 -0
  111. package/dist/core/session.d.ts +83 -0
  112. package/dist/core/session.js +269 -0
  113. package/dist/core/shell-completion.d.ts +51 -0
  114. package/dist/core/shell-completion.js +674 -0
  115. package/dist/core/smart-monitor.d.ts +146 -0
  116. package/dist/core/smart-monitor.js +1199 -0
  117. package/dist/core/spec-driven.d.ts +233 -0
  118. package/dist/core/spec-driven.js +1485 -0
  119. package/dist/core/spending-warnings.d.ts +123 -0
  120. package/dist/core/spending-warnings.js +456 -0
  121. package/dist/core/sub-agent.d.ts +298 -0
  122. package/dist/core/sub-agent.js +1023 -0
  123. package/dist/core/telemetry.d.ts +157 -0
  124. package/dist/core/telemetry.js +412 -0
  125. package/dist/core/terminal-ux.d.ts +134 -0
  126. package/dist/core/terminal-ux.js +649 -0
  127. package/dist/core/testing.d.ts +146 -0
  128. package/dist/core/testing.js +1200 -0
  129. package/dist/core/types.d.ts +439 -0
  130. package/dist/core/types.js +6 -0
  131. package/dist/core/undo-redo.d.ts +112 -0
  132. package/dist/core/undo-redo.js +290 -0
  133. package/dist/core/updater.d.ts +159 -0
  134. package/dist/core/updater.js +608 -0
  135. package/dist/core/vim-mode.d.ts +151 -0
  136. package/dist/core/vim-mode.js +771 -0
  137. package/dist/core/voice.d.ts +137 -0
  138. package/dist/core/voice.js +538 -0
  139. package/dist/core/web-dashboard.d.ts +109 -0
  140. package/dist/core/web-dashboard.js +484 -0
  141. package/dist/hooks/hooks.d.ts +74 -0
  142. package/dist/hooks/hooks.js +160 -0
  143. package/dist/hooks/llm-evaluator.d.ts +165 -0
  144. package/dist/hooks/llm-evaluator.js +560 -0
  145. package/dist/index.d.ts +3 -0
  146. package/dist/index.js +1186 -0
  147. package/dist/lsp/lsp-manager.d.ts +63 -0
  148. package/dist/lsp/lsp-manager.js +351 -0
  149. package/dist/mcp/client.d.ts +133 -0
  150. package/dist/mcp/client.js +684 -0
  151. package/dist/mcp/mcp-apps.d.ts +70 -0
  152. package/dist/mcp/mcp-apps.js +1007 -0
  153. package/dist/tools/bash.d.ts +5 -0
  154. package/dist/tools/bash.js +195 -0
  155. package/dist/tools/browser.d.ts +92 -0
  156. package/dist/tools/browser.js +1570 -0
  157. package/dist/tools/extended.d.ts +6 -0
  158. package/dist/tools/extended.js +191 -0
  159. package/dist/tools/file.d.ts +10 -0
  160. package/dist/tools/file.js +382 -0
  161. package/dist/tools/github.d.ts +389 -0
  162. package/dist/tools/github.js +759 -0
  163. package/dist/tools/index.d.ts +9 -0
  164. package/dist/tools/index.js +40 -0
  165. package/dist/tools/memory.d.ts +6 -0
  166. package/dist/tools/memory.js +197 -0
  167. package/dist/tools/registry.d.ts +29 -0
  168. package/dist/tools/registry.js +64 -0
  169. package/dist/tools/web.d.ts +6 -0
  170. package/dist/tools/web.js +150 -0
  171. package/dist/ui/renderer.d.ts +97 -0
  172. package/dist/ui/renderer.js +279 -0
  173. package/dist/ui/theme.d.ts +27 -0
  174. package/dist/ui/theme.js +106 -0
  175. package/package.json +83 -0
@@ -0,0 +1,942 @@
1
+ // ============================================================
2
+ // NeuroCLI - NeuroEngine v4.1.0
3
+ // The main engine that ties everything together
4
+ // Now with: Sandbox, Plugin SDK, Enhanced MCP, Enhanced Approval,
5
+ // Model Router, Prompt Cache, Undo/Redo, Output Styles,
6
+ // Skill System, Custom Agents, Custom Tools, Ollama,
7
+ // Extended Thinking, Spending Monitor, NeuroIgnore,
8
+ // Telemetry, Vim Mode, i18n, Multimodal, Voice I/O,
9
+ // API Server, Cloud Sync, Web Dashboard,
10
+ // SKILL.md Standard, Auto Mode, Scheduled Tasks,
11
+ // Parallel Agents, Background Sessions, Browser Automation,
12
+ // Tree-sitter, Linting, Testing, Code Review,
13
+ // GitHub Integration, CI/CD, Plugin Bundles, Security Scanner,
14
+ // Sub-Agent Spawning, ACP Protocol, OS-Level Sandbox,
15
+ // Spec-Driven Development, LLM Evaluator Hooks, MCP Apps,
16
+ // Multi-Model Orchestrator, Smart Monitor, Outcome Grading,
17
+ // Observability (OTLP), Auto-Compact, Terminal UX,
18
+ // Multi-Session, Git Worktree, Auto-Updater
19
+ // ============================================================
20
+ import { join } from 'path';
21
+ import { homedir } from 'os';
22
+ import { OpenRouterClient } from '../api/openrouter.js';
23
+ import { ToolRegistry } from '../tools/registry.js';
24
+ import { registerAllTools } from '../tools/index.js';
25
+ import { BaseAgent } from '../agents/base.js';
26
+ import { Orchestrator } from '../agents/orchestrator.js';
27
+ import { ContextManager } from '../core/context.js';
28
+ import { SessionManager } from '../core/session.js';
29
+ import { TerminalUI } from '../ui/renderer.js';
30
+ import { MODELS } from '../api/models.js';
31
+ import { ApprovalSystem } from '../core/approval.js';
32
+ import { MCPClient } from '../mcp/client.js';
33
+ import { DoomLoopProtection } from '../core/doom-loop.js';
34
+ import { FallbackChain } from '../core/fallback.js';
35
+ import { Sandbox } from '../core/sandbox.js';
36
+ import { PluginManager } from '../core/plugin-sdk.js';
37
+ import { UndoRedoSystem } from './undo-redo.js';
38
+ import { PromptCache } from './prompt-cache.js';
39
+ import { ModelRouter } from './model-router.js';
40
+ import { StyleManager } from './output-styles.js';
41
+ import { ExtendedThinking } from './extended-thinking.js';
42
+ import { SpendingMonitor } from './spending-warnings.js';
43
+ import { SkillSystem } from '../context/skill-system.js';
44
+ import { CustomAgentLoader } from '../context/custom-agents.js';
45
+ import { CustomToolLoader } from '../context/custom-tools.js';
46
+ import { NeuroIgnore } from '../context/neuroignore.js';
47
+ import { OllamaProvider } from '../api/ollama.js';
48
+ import { TelemetrySystem } from './telemetry.js';
49
+ import { VimModeManager } from './vim-mode.js';
50
+ import { I18nSystem } from './i18n.js';
51
+ import { MultimodalSupport } from './multimodal.js';
52
+ import { VoiceIO } from './voice.js';
53
+ import { APIServer } from './api-server.js';
54
+ import { CloudSync } from './cloud-sync.js';
55
+ import { WebDashboard } from './web-dashboard.js';
56
+ import { SkillStandard } from '../context/skill-standard.js';
57
+ import { AutoMode } from './auto-mode.js';
58
+ import { ScheduledTaskManager } from './scheduled-tasks.js';
59
+ import { ParallelAgentManager } from './parallel-agents.js';
60
+ import { BackgroundSessionManager } from './background-session.js';
61
+ import { TreeSitterIntegration } from '../context/tree-sitter.js';
62
+ import { LintingIntegration } from './linting.js';
63
+ import { TestingIntegration } from './testing.js';
64
+ import { CodeReviewSystem } from './code-review.js';
65
+ import { SecurityScanner } from './security-scanner.js';
66
+ import { PluginBundleManager } from './plugin-bundle.js';
67
+ import { SubAgentManager } from './sub-agent.js';
68
+ import { ACPServer } from './acp.js';
69
+ import { OSSandboxManager } from './os-sandbox.js';
70
+ import { SpecDrivenPipeline } from './spec-driven.js';
71
+ import { LLMEvaluatorManager } from '../hooks/llm-evaluator.js';
72
+ import { MCPAppManager } from '../mcp/mcp-apps.js';
73
+ import { MultiModelOrchestrator } from './multi-model.js';
74
+ import { SmartMonitor } from './smart-monitor.js';
75
+ import { OutcomeGrader } from './outcome-grading.js';
76
+ import { ObservabilityManager } from './observability.js';
77
+ import { AutoCompactManager } from './auto-compact.js';
78
+ import { TerminalUX } from './terminal-ux.js';
79
+ import { MultiSessionManager } from './multi-session.js';
80
+ import { GitWorktreeManager } from './git-worktree.js';
81
+ import { AutoUpdater } from './updater.js';
82
+ export class NeuroEngine {
83
+ config;
84
+ client;
85
+ registry;
86
+ orchestrator;
87
+ contextManager;
88
+ sessionManager;
89
+ ui;
90
+ agents = new Map();
91
+ mcpClient;
92
+ approval;
93
+ doomLoop;
94
+ fallback;
95
+ sandbox;
96
+ pluginManager;
97
+ // v3.0 new systems
98
+ undoRedo;
99
+ promptCache;
100
+ modelRouter;
101
+ styleManager;
102
+ extendedThinking;
103
+ spendingMonitor;
104
+ skillSystem;
105
+ customAgentLoader;
106
+ customToolLoader;
107
+ neuroIgnore;
108
+ ollamaProvider;
109
+ // P2/P3 new systems
110
+ telemetry;
111
+ vimMode;
112
+ i18n;
113
+ multimodal;
114
+ voice;
115
+ apiServer;
116
+ cloudSync;
117
+ dashboard;
118
+ // v4.0 new systems
119
+ skillStandard;
120
+ autoMode;
121
+ scheduledTasks;
122
+ parallelAgents;
123
+ backgroundSessions;
124
+ treeSitter;
125
+ linting;
126
+ testing;
127
+ codeReview;
128
+ securityScanner;
129
+ pluginBundles;
130
+ // v4.1 new systems
131
+ subAgentSpawner;
132
+ acp;
133
+ osSandbox;
134
+ specDriven;
135
+ llmEvaluator;
136
+ mcpApps;
137
+ multiModelOrchestrator;
138
+ smartMonitor;
139
+ outcomeGrading;
140
+ observability;
141
+ autoCompact;
142
+ terminalUX;
143
+ multiSession;
144
+ gitWorktree;
145
+ updater;
146
+ autoApproveSet;
147
+ requireApprovalSet;
148
+ constructor(config) {
149
+ this.config = config;
150
+ this.client = new OpenRouterClient(config.apiKey, config.baseUrl);
151
+ this.registry = registerAllTools(new ToolRegistry());
152
+ this.contextManager = new ContextManager(config.defaultModel, config.context.maxTokens);
153
+ this.sessionManager = new SessionManager();
154
+ this.ui = new TerminalUI(config.ui.theme, config.ui.showTokenCount, config.ui.showCost);
155
+ this.autoApproveSet = new Set(config.tools.autoApprove);
156
+ this.requireApprovalSet = new Set(config.tools.requireApproval);
157
+ // Initialize core systems
158
+ this.approval = new ApprovalSystem(config.permissionMode, {
159
+ showDiffPreview: config.diffPreview,
160
+ whitelist: config.tools.autoApprove,
161
+ blacklist: config.tools.denied,
162
+ });
163
+ this.mcpClient = new MCPClient();
164
+ this.doomLoop = new DoomLoopProtection(config.doomLoop, async (reason, state) => {
165
+ this.ui.warning(`Doom loop detected: ${reason}. Pausing agent.`);
166
+ return false;
167
+ });
168
+ this.fallback = new FallbackChain(this.client, config.fallbackChain);
169
+ // Sandbox system
170
+ this.sandbox = new Sandbox(config.sandbox);
171
+ // Plugin system
172
+ this.pluginManager = new PluginManager();
173
+ // --- v3.0 Systems ---
174
+ // Undo/Redo system
175
+ this.undoRedo = new UndoRedoSystem();
176
+ // Prompt cache
177
+ this.promptCache = new PromptCache({
178
+ cacheDir: config.promptCache.cacheDir,
179
+ maxEntries: config.promptCache.maxEntries,
180
+ ttlMs: config.promptCache.ttlMs,
181
+ similarityThreshold: config.promptCache.similarityThreshold,
182
+ enabled: config.promptCache.enabled,
183
+ });
184
+ // Model router
185
+ this.modelRouter = new ModelRouter({
186
+ defaultModel: config.defaultModel,
187
+ simpleModel: 'google/gemma-4-31b-it:free',
188
+ moderateModel: 'qwen/qwen3-coder:free',
189
+ complexModel: 'nvidia/nemotron-3-ultra-550b-a55b:free',
190
+ effortModels: {
191
+ low: 'google/gemma-4-31b-it:free',
192
+ medium: 'qwen/qwen3-coder:free',
193
+ high: 'nvidia/nemotron-3-super-120b-a12b:free',
194
+ ultrathink: 'nvidia/nemotron-3-ultra-550b-a55b:free',
195
+ },
196
+ categoryOverrides: {},
197
+ maxTokenBudget: config.context.maxTokens,
198
+ }, Object.fromEntries(Object.entries(MODELS).map(([id, m]) => [id, { name: m.name, contextWindow: m.contextWindow, maxOutput: m.maxOutput }])));
199
+ // Output styles
200
+ this.styleManager = new StyleManager(process.cwd());
201
+ // Extended thinking
202
+ this.extendedThinking = new ExtendedThinking({
203
+ mode: 'none',
204
+ showThinking: false,
205
+ });
206
+ // Spending monitor
207
+ this.spendingMonitor = new SpendingMonitor({
208
+ dailyLimit: config.spendingLimit > 0 ? config.spendingLimit : 0,
209
+ sessionLimit: 0,
210
+ autoStopAtLimit: config.spendingLimit > 0,
211
+ trackByModel: true,
212
+ });
213
+ // Skill system
214
+ this.skillSystem = new SkillSystem(process.cwd());
215
+ this.skillSystem.discover();
216
+ // Custom agents
217
+ this.customAgentLoader = new CustomAgentLoader(process.cwd());
218
+ this.customAgentLoader.discover();
219
+ // Custom tools
220
+ this.customToolLoader = new CustomToolLoader(process.cwd());
221
+ this.customToolLoader.discover();
222
+ // .neuroignore
223
+ this.neuroIgnore = new NeuroIgnore(process.cwd());
224
+ this.neuroIgnore.load();
225
+ // Ollama provider
226
+ this.ollamaProvider = new OllamaProvider({
227
+ baseUrl: process.env.OLLAMA_HOST || 'http://localhost:11434',
228
+ defaultModel: 'llama3',
229
+ });
230
+ // --- P2/P3 New Systems ---
231
+ // Telemetry (opt-in, disabled by default)
232
+ this.telemetry = new TelemetrySystem({
233
+ enabled: false,
234
+ });
235
+ // Vim mode
236
+ this.vimMode = new VimModeManager({
237
+ enabled: false,
238
+ });
239
+ // i18n
240
+ this.i18n = new I18nSystem();
241
+ // Multimodal support
242
+ this.multimodal = new MultimodalSupport();
243
+ // Voice I/O
244
+ this.voice = new VoiceIO({
245
+ enabled: false,
246
+ });
247
+ // API server
248
+ this.apiServer = new APIServer({
249
+ enabled: false,
250
+ });
251
+ this.apiServer.setEngine(this);
252
+ // Cloud sync
253
+ this.cloudSync = new CloudSync({
254
+ enabled: false,
255
+ });
256
+ // Web dashboard
257
+ this.dashboard = new WebDashboard({
258
+ enabled: false,
259
+ });
260
+ this.dashboard.setEngine(this);
261
+ // --- v4.0 New Systems ---
262
+ // SKILL.md standard (agentskills.io compliant)
263
+ this.skillStandard = new SkillStandard();
264
+ // Auto mode (full autonomous)
265
+ this.autoMode = new AutoMode({
266
+ enabled: false,
267
+ safetyLevel: 'conservative',
268
+ maxIterations: 50,
269
+ maxCost: 0,
270
+ maxTimeMs: 0,
271
+ blockedCommands: ['rm -rf /', 'mkfs', 'dd if=/dev/zero'],
272
+ blockedPatterns: ['/etc/passwd', '/etc/shadow'],
273
+ autoCommit: false,
274
+ autoTest: false,
275
+ pauseOnError: true,
276
+ });
277
+ // Scheduled tasks (/loop)
278
+ this.scheduledTasks = new ScheduledTaskManager();
279
+ // Parallel agents
280
+ this.parallelAgents = new ParallelAgentManager({
281
+ maxConcurrent: 5,
282
+ });
283
+ // Background sessions
284
+ this.backgroundSessions = new BackgroundSessionManager();
285
+ // Tree-sitter integration (repo map)
286
+ this.treeSitter = new TreeSitterIntegration(process.cwd());
287
+ // Linting integration
288
+ this.linting = new LintingIntegration(process.cwd(), {
289
+ enabled: true,
290
+ autoRunOnChange: false,
291
+ autoFix: false,
292
+ failOnError: false,
293
+ timeout: 30000,
294
+ excludePatterns: ['node_modules', '.git', 'dist'],
295
+ });
296
+ // Testing integration
297
+ this.testing = new TestingIntegration(process.cwd(), {
298
+ enabled: true,
299
+ autoRunOnChange: false,
300
+ runOnSave: false,
301
+ coverageThreshold: 80,
302
+ timeout: 60000,
303
+ relatedTestsOnly: false,
304
+ });
305
+ // Code review
306
+ this.codeReview = new CodeReviewSystem(process.cwd(), {
307
+ enabled: true,
308
+ autoReviewOnChange: false,
309
+ focusAreas: ['security', 'performance', 'correctness', 'style'],
310
+ severityThreshold: 'minor',
311
+ excludePatterns: ['node_modules', '.git', 'dist'],
312
+ });
313
+ // Security scanner
314
+ this.securityScanner = new SecurityScanner(process.cwd(), {
315
+ enabled: true,
316
+ autoScanOnChange: false,
317
+ failOnSeverity: 'high',
318
+ excludePatterns: ['node_modules', '.git', 'dist', 'coverage'],
319
+ customRules: [],
320
+ });
321
+ // Plugin bundles
322
+ this.pluginBundles = new PluginBundleManager(join(homedir(), '.neuro', 'bundles'));
323
+ // --- v4.1 New Systems ---
324
+ // Sub-Agent Spawner
325
+ this.subAgentSpawner = new SubAgentManager(this.client, this.registry, process.cwd(), this.sessionManager.getCurrent()?.id || 'default', config.defaultModel);
326
+ // ACP Protocol (Agent Client Protocol - JSON-RPC 2.0)
327
+ this.acp = new ACPServer(this, { enabled: false, port: 9256, host: 'localhost' });
328
+ // OS-Level Sandbox (Docker + native sandboxing + network isolation)
329
+ this.osSandbox = new OSSandboxManager({
330
+ type: 'os-native',
331
+ network: {
332
+ mode: 'filtered',
333
+ allowedDomains: [],
334
+ allowedPorts: [443, 80],
335
+ blockPrivateNetworks: true,
336
+ },
337
+ commands: {
338
+ blockedCommands: ['rm -rf /', 'mkfs', 'dd if=/dev/zero'],
339
+ allowedPrefixes: ['git', 'npm', 'node', 'npx', 'yarn', 'pnpm', 'ls', 'cat', 'echo'],
340
+ maxArgLength: 1024,
341
+ allowPipes: false,
342
+ allowBackground: false,
343
+ },
344
+ filesystem: {
345
+ readOnlyPaths: ['/etc', '/usr', '/bin'],
346
+ readWritePaths: [process.cwd()],
347
+ deniedPaths: ['/etc/passwd', '/etc/shadow', '/etc/ssh'],
348
+ allowHiddenFiles: false,
349
+ },
350
+ });
351
+ // Spec-Driven Development Pipeline
352
+ this.specDriven = new SpecDrivenPipeline({
353
+ runPrompt: async (prompt, model) => {
354
+ const result = await this.processMessage(prompt, 'direct', 'Coder');
355
+ return {
356
+ text: result.content,
357
+ inputTokens: result.usage.inputTokens,
358
+ outputTokens: result.usage.outputTokens,
359
+ cost: result.usage.cost,
360
+ filesChanged: 0,
361
+ commandsRun: 0,
362
+ };
363
+ },
364
+ }, process.cwd(), config.defaultModel);
365
+ // LLM Evaluator Hooks
366
+ this.llmEvaluator = new LLMEvaluatorManager(this.client, {
367
+ defaultModel: config.defaultModel,
368
+ defaultRubric: 'safety',
369
+ confidenceThreshold: 0.8,
370
+ cacheEnabled: true,
371
+ });
372
+ // MCP Apps (interactive tool UI extensions)
373
+ this.mcpApps = new MCPAppManager(this.mcpClient);
374
+ // Multi-Model Orchestrator/Worker (cost stratification)
375
+ this.multiModelOrchestrator = new MultiModelOrchestrator({
376
+ roles: {
377
+ orchestrator: {
378
+ name: 'Orchestrator',
379
+ model: config.defaultModel,
380
+ fallbackModels: ['qwen/qwen3-coder:free'],
381
+ maxTokensPerRequest: 4096,
382
+ description: 'Task decomposition and coordination',
383
+ },
384
+ worker: {
385
+ name: 'Worker',
386
+ model: 'google/gemma-4-31b-it:free',
387
+ fallbackModels: ['qwen/qwen3-coder:free'],
388
+ maxTokensPerRequest: 4096,
389
+ description: 'Code generation and modification',
390
+ },
391
+ evaluator: {
392
+ name: 'Evaluator',
393
+ model: 'qwen/qwen3-coder:free',
394
+ fallbackModels: ['google/gemma-4-31b-it:free'],
395
+ maxTokensPerRequest: 2048,
396
+ description: 'Quality evaluation and grading',
397
+ },
398
+ reviewer: {
399
+ name: 'Reviewer',
400
+ model: 'qwen/qwen3-coder:free',
401
+ fallbackModels: ['google/gemma-4-31b-it:free'],
402
+ maxTokensPerRequest: 2048,
403
+ description: 'Code review and feedback',
404
+ },
405
+ },
406
+ costBudget: {
407
+ maxPerSession: 1.0,
408
+ maxPerTask: 0.1,
409
+ warnThreshold: 0.8,
410
+ },
411
+ qualityGates: {
412
+ enabled: false,
413
+ evaluatorModel: config.defaultModel,
414
+ minConfidence: 0.7,
415
+ },
416
+ dynamicSwitching: true,
417
+ }, this.client);
418
+ // Smart Monitor (LLM-based risk scoring for auto mode)
419
+ this.smartMonitor = new SmartMonitor({
420
+ enabled: true,
421
+ evaluatorModel: config.defaultModel,
422
+ riskThresholds: {
423
+ autoApprove: 0.3,
424
+ askUser: 0.7,
425
+ },
426
+ learning: {
427
+ enabled: false,
428
+ storagePath: join(homedir(), '.neuro', 'monitor-learning'),
429
+ minSamples: 10,
430
+ },
431
+ escalationRules: [],
432
+ contextAwareness: {
433
+ checkGitStatus: true,
434
+ checkTestCoverage: false,
435
+ checkProductionFiles: true,
436
+ protectedPaths: ['prod', 'production', 'main'],
437
+ },
438
+ }, this.client);
439
+ // Outcome Grading (rubric-based quality evaluation with revision loops)
440
+ this.outcomeGrading = new OutcomeGrader(this.client, {
441
+ defaultEvaluatorModel: config.defaultModel,
442
+ globalMaxRevisions: 3,
443
+ rubricsDir: join(homedir(), '.neuro', 'rubrics'),
444
+ persistHistory: true,
445
+ historyDir: join(homedir(), '.neuro', 'grading-history'),
446
+ evaluatorTemperature: 0.3,
447
+ evaluatorTimeoutMs: 30000,
448
+ });
449
+ // Observability (OpenTelemetry OTLP JSON export)
450
+ this.observability = new ObservabilityManager({
451
+ enabled: false,
452
+ serviceName: 'neuro-cli',
453
+ endpoint: 'http://localhost:4318',
454
+ headers: {},
455
+ exportInterval: 30000,
456
+ maxBatchSize: 64,
457
+ consoleExporter: false,
458
+ sampleRate: 1.0,
459
+ });
460
+ // Auto-Compact (model-aware context compaction)
461
+ this.autoCompact = new AutoCompactManager({
462
+ enabled: true,
463
+ warningThreshold: 0.7,
464
+ compactThreshold: 0.85,
465
+ emergencyThreshold: 0.95,
466
+ preserveRecentCount: 5,
467
+ preserveSystemPrompt: true,
468
+ compactStrategy: 'summarize',
469
+ tokenBudget: {
470
+ systemPrompt: 2048,
471
+ conversation: 8192,
472
+ tools: 2048,
473
+ output: 2048,
474
+ },
475
+ });
476
+ // Terminal UX (OSC 52, TUI, syntax highlighting)
477
+ this.terminalUX = new TerminalUX();
478
+ // Multi-Session (parallel independent sessions)
479
+ this.multiSession = new MultiSessionManager({
480
+ maxConcurrent: 10,
481
+ });
482
+ // Git Worktree (agent-worktree binding)
483
+ this.gitWorktree = new GitWorktreeManager(process.cwd());
484
+ // Auto-Updater
485
+ this.updater = new AutoUpdater({
486
+ currentVersion: '4.1.0',
487
+ autoCheck: true,
488
+ autoUpdate: false,
489
+ });
490
+ // --- End v4.1 ---
491
+ // --- End v4.0 ---
492
+ // --- End P2/P3 ---
493
+ // --- End v3.0 ---
494
+ // Connect MCP servers if configured
495
+ if (config.mcp.autoConnect) {
496
+ this.mcpClient.connectAll().then(count => {
497
+ if (count > 0)
498
+ this.ui.info(`MCP: ${count} server(s) connected`);
499
+ }).catch(() => { });
500
+ }
501
+ // Load plugins
502
+ this.pluginManager.loadAll().then(count => {
503
+ if (count > 0)
504
+ this.ui.info(`Plugins: ${count} loaded`);
505
+ }).catch(() => { });
506
+ // Register plugin tools with the tool registry
507
+ this.registerPluginTools();
508
+ // Register custom tools
509
+ this.registerCustomTools();
510
+ // Initialize agents from config
511
+ this.initializeAgents();
512
+ // Load custom agents from .neuro/agents/
513
+ this.loadCustomAgents();
514
+ // Create orchestrator
515
+ const orchestratorConfig = {
516
+ name: 'Orchestrator',
517
+ description: 'Central coordinator that manages sub-agents for complex tasks',
518
+ systemPrompt: `You are the Orchestrator, the central coordinator of the NeuroCLI multi-agent system. Your job is to analyze tasks and delegate them to the appropriate specialist agents. You ensure tasks are completed efficiently and correctly.
519
+
520
+ Key responsibilities:
521
+ - Analyze complex tasks and break them into sub-tasks
522
+ - Assign sub-tasks to the most appropriate specialist agent
523
+ - Manage dependencies between sub-tasks
524
+ - Synthesize results from multiple agents
525
+ - Handle errors and re-plan if needed
526
+
527
+ Always consider the strengths of each agent when delegating:
528
+ - Planner: For task decomposition and architecture decisions
529
+ - Coder: For writing and modifying code
530
+ - Reviewer: For code quality assurance
531
+ - Researcher: For information gathering and documentation
532
+ - Tester: For writing and running tests
533
+ - Debugger: For investigating and fixing bugs
534
+ - Architect: For system design and technology decisions
535
+ - DevOps: For deployment and infrastructure`,
536
+ model: 'qwen/qwen3-coder:free',
537
+ temperature: 0.7,
538
+ maxTokens: 4096,
539
+ tools: [],
540
+ maxIterations: 5,
541
+ };
542
+ this.orchestrator = new Orchestrator(orchestratorConfig, this.client, this.registry, process.cwd(), this.sessionManager.getCurrent()?.id || 'default');
543
+ // Register all agents with orchestrator
544
+ for (const [name, agent] of this.agents) {
545
+ this.orchestrator.registerAgent(agent);
546
+ }
547
+ }
548
+ /**
549
+ * Register plugin tools with the tool registry
550
+ */
551
+ registerPluginTools() {
552
+ const pluginTools = this.pluginManager.getToolDefinitions();
553
+ for (const toolDef of pluginTools) {
554
+ this.registry.register({
555
+ name: toolDef.name,
556
+ risk: toolDef.risk,
557
+ execute: async (args, context) => {
558
+ const result = await this.pluginManager.executeTool(toolDef.name, args, {
559
+ workingDirectory: context.workingDirectory,
560
+ sessionId: context.sessionId,
561
+ agentName: context.agentName,
562
+ onProgress: context.onProgress || (() => { }),
563
+ callTool: async (name, callArgs) => {
564
+ return this.registry.execute(name, callArgs, context);
565
+ },
566
+ memory: {
567
+ get: () => undefined,
568
+ set: () => { },
569
+ delete: () => { },
570
+ list: () => [],
571
+ },
572
+ });
573
+ return result.content;
574
+ },
575
+ });
576
+ }
577
+ }
578
+ /**
579
+ * Register custom tools from .neuro/tools/
580
+ */
581
+ registerCustomTools() {
582
+ const customTools = this.customToolLoader.getAll();
583
+ for (const toolDef of customTools) {
584
+ const executor = this.customToolLoader.createExecutor(toolDef);
585
+ this.registry.register({
586
+ name: `custom_${toolDef.name}`,
587
+ risk: toolDef.risk || 'medium',
588
+ execute: async (args) => {
589
+ try {
590
+ const result = await executor(args);
591
+ return typeof result === 'string' ? result : JSON.stringify(result);
592
+ }
593
+ catch (error) {
594
+ return `Custom tool error: ${error instanceof Error ? error.message : String(error)}`;
595
+ }
596
+ },
597
+ });
598
+ }
599
+ }
600
+ /**
601
+ * Load custom agents from .neuro/agents/
602
+ */
603
+ loadCustomAgents() {
604
+ const customAgents = this.customAgentLoader.getAll();
605
+ const cwd = process.cwd();
606
+ const sessionId = this.sessionManager.getCurrent()?.id || 'default';
607
+ for (const def of customAgents) {
608
+ const agentConfig = this.customAgentLoader.toAgentConfig(def, this.config.defaultModel);
609
+ const agent = new BaseAgent(agentConfig, this.client, this.registry, cwd, sessionId);
610
+ this.agents.set(def.name, agent);
611
+ // Save to config custom agents
612
+ if (!this.config.customAgents)
613
+ this.config.customAgents = {};
614
+ this.config.customAgents[def.name] = agentConfig;
615
+ }
616
+ }
617
+ /**
618
+ * Initialize all agents from config
619
+ */
620
+ initializeAgents() {
621
+ const sessionId = 'init';
622
+ const cwd = process.cwd();
623
+ // Built-in agents
624
+ for (const [key, agentConfig] of Object.entries(this.config.agents)) {
625
+ const overrideConfig = { ...agentConfig, model: this.config.defaultModel };
626
+ const agent = new BaseAgent(overrideConfig, this.client, this.registry, cwd, sessionId);
627
+ this.agents.set(agentConfig.name, agent);
628
+ }
629
+ // Custom agents from config
630
+ for (const [key, agentConfig] of Object.entries(this.config.customAgents || {})) {
631
+ const overrideConfig = { ...agentConfig, model: this.config.defaultModel, isCustom: true };
632
+ const agent = new BaseAgent(overrideConfig, this.client, this.registry, cwd, sessionId);
633
+ this.agents.set(agentConfig.name, agent);
634
+ }
635
+ }
636
+ /**
637
+ * Process a user message
638
+ */
639
+ async processMessage(message, mode = 'auto', targetAgent) {
640
+ // Check spending limit via spending monitor
641
+ const limitCheck = this.spendingMonitor.checkLimit();
642
+ if (!limitCheck.allowed) {
643
+ this.ui.error(`Spending limit reached (${limitCheck.limitReached}). Use /spending to check or /config to adjust.`);
644
+ return { content: 'Spending limit reached.', usage: { inputTokens: 0, outputTokens: 0, cost: 0 } };
645
+ }
646
+ // Auto-activate skills based on prompt
647
+ const activatedSkills = this.skillSystem.autoActivate(message);
648
+ if (activatedSkills.length > 0) {
649
+ for (const skill of activatedSkills) {
650
+ this.ui.info(`Skill activated: ${skill.skill.name} (${skill.activatedBy})`);
651
+ }
652
+ }
653
+ // Model routing (if auto mode)
654
+ let routeDecision = null;
655
+ if (mode === 'auto') {
656
+ routeDecision = this.modelRouter.route(message);
657
+ if (routeDecision.model !== this.config.defaultModel) {
658
+ this.ui.info(`Model router: ${routeDecision.complexity} task -> ${MODELS[routeDecision.model]?.name || routeDecision.model}`);
659
+ }
660
+ }
661
+ // Check prompt cache
662
+ if (this.promptCache && this.config.promptCache.enabled) {
663
+ const session = this.sessionManager.getCurrent();
664
+ if (session) {
665
+ const cached = this.promptCache.get(routeDecision?.model || this.config.defaultModel, session.messages);
666
+ if (cached) {
667
+ this.ui.info('Cache hit - using cached response');
668
+ return {
669
+ content: cached.response,
670
+ usage: { inputTokens: cached.inputTokens, outputTokens: cached.outputTokens, cost: 0 },
671
+ };
672
+ }
673
+ }
674
+ }
675
+ // Start or get session
676
+ let session = this.sessionManager.getCurrent();
677
+ if (!session) {
678
+ session = this.sessionManager.create(process.cwd(), this.config.defaultModel);
679
+ }
680
+ // Add user message to session
681
+ this.sessionManager.addMessage({
682
+ role: 'user',
683
+ content: message,
684
+ timestamp: Date.now(),
685
+ });
686
+ // Build system prompt additions from skills and styles
687
+ const skillAdditions = this.skillSystem.getSystemPromptAdditions();
688
+ const styleAddition = this.styleManager.getSystemPromptAddition();
689
+ const thinkingAddition = this.extendedThinking.getSystemPromptAddition();
690
+ // Build UI callbacks
691
+ const callbacks = {
692
+ onThinking: (thinking) => this.ui.thinking(thinking),
693
+ onToken: (token) => this.ui.streamingToken(token),
694
+ onToolCall: (name, args) => {
695
+ // Check .neuroignore for file paths
696
+ if (args.path && typeof args.path === 'string' && this.neuroIgnore.isIgnored(args.path)) {
697
+ this.ui.warning(`Ignored path: ${args.path} (matches .neuroignore rule)`);
698
+ return;
699
+ }
700
+ // Sandbox check before tool execution
701
+ if (this.sandbox.isEnabled() && !this.checkSandboxForTool(name, args)) {
702
+ return;
703
+ }
704
+ 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
+ },
710
+ onToolResult: (name, result, isError) => this.ui.toolResult(name, result, isError),
711
+ onApprovalNeeded: async (name, args, risk) => {
712
+ return this.handleApproval(name, args, risk);
713
+ },
714
+ onIteration: (i, max) => {
715
+ this.ui.info(`Iteration ${i}/${max}`);
716
+ },
717
+ };
718
+ let result;
719
+ const activeModel = routeDecision?.model || this.config.defaultModel;
720
+ if (mode === 'direct' && targetAgent) {
721
+ const agent = this.agents.get(targetAgent);
722
+ if (!agent) {
723
+ this.ui.error(`Agent not found: ${targetAgent}`);
724
+ return { content: '', usage: { inputTokens: 0, outputTokens: 0, cost: 0 } };
725
+ }
726
+ // Override agent model if defaultModel differs from agent's model
727
+ const originalModel = agent.configModel;
728
+ if (this.config.defaultModel !== originalModel) {
729
+ agent.configModel = this.config.defaultModel;
730
+ }
731
+ this.ui.startStreaming();
732
+ result = await agent.run(message, callbacks);
733
+ this.ui.endStreaming();
734
+ // Restore original model
735
+ agent.configModel = originalModel;
736
+ }
737
+ else if (mode === 'agent') {
738
+ const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
739
+ result = {
740
+ content: orchestrateResult.content,
741
+ toolCallsMade: 0,
742
+ iterations: orchestrateResult.execution.iterations,
743
+ usage: orchestrateResult.totalUsage,
744
+ execution: orchestrateResult.execution,
745
+ };
746
+ }
747
+ else {
748
+ const complexity = routeDecision?.complexity || this.assessComplexity(message);
749
+ if (complexity === 'simple') {
750
+ const agent = this.agents.get('Coder');
751
+ if (agent) {
752
+ this.ui.startStreaming();
753
+ result = await agent.run(message, callbacks);
754
+ this.ui.endStreaming();
755
+ }
756
+ else {
757
+ throw new Error('Coder agent not initialized');
758
+ }
759
+ }
760
+ else {
761
+ this.ui.thinking('Analyzing task complexity... Using multi-agent orchestration');
762
+ const orchestrateResult = await this.orchestrator.orchestrate(message, callbacks);
763
+ result = {
764
+ content: orchestrateResult.content,
765
+ toolCallsMade: 0,
766
+ iterations: orchestrateResult.execution.iterations,
767
+ usage: orchestrateResult.totalUsage,
768
+ execution: orchestrateResult.execution,
769
+ };
770
+ }
771
+ }
772
+ // Parse extended thinking blocks from response
773
+ const thinkingResult = this.extendedThinking.parseResponse(result.content);
774
+ if (thinkingResult.hadThinking && this.extendedThinking.isDisplayEnabled()) {
775
+ // Thinking blocks were already displayed during streaming
776
+ }
777
+ // Use cleaned response (without thinking blocks) if thinking is hidden
778
+ if (thinkingResult.hadThinking && !this.extendedThinking.isDisplayEnabled()) {
779
+ result.content = thinkingResult.cleanedResponse;
780
+ }
781
+ // Record spending
782
+ const spendResult = this.spendingMonitor.record({
783
+ model: activeModel,
784
+ inputTokens: result.usage.inputTokens,
785
+ outputTokens: result.usage.outputTokens,
786
+ cost: result.usage.cost,
787
+ sessionId: this.sessionManager.getCurrent()?.id || 'unknown',
788
+ });
789
+ if (spendResult.warning) {
790
+ this.ui.warning(spendResult.warning);
791
+ }
792
+ if (!spendResult.allowed) {
793
+ this.ui.error('Spending limit reached. Operation completed but further requests may be blocked.');
794
+ }
795
+ // Cache the response if caching is enabled
796
+ if (this.promptCache && this.config.promptCache.enabled && session) {
797
+ this.promptCache.set(activeModel, session.messages, result.content, result.usage);
798
+ }
799
+ // Print usage
800
+ this.ui.tokenUsage(result.usage, activeModel);
801
+ // Update session
802
+ this.sessionManager.addMessage({
803
+ role: 'assistant',
804
+ content: result.content,
805
+ timestamp: Date.now(),
806
+ });
807
+ this.sessionManager.updateUsage(result.usage.inputTokens, result.usage.outputTokens, result.usage.cost);
808
+ this.sessionManager.save();
809
+ return {
810
+ content: result.content,
811
+ usage: result.usage,
812
+ execution: result.execution,
813
+ };
814
+ }
815
+ /**
816
+ * Check sandbox permissions for a tool call
817
+ */
818
+ checkSandboxForTool(toolName, args) {
819
+ // File operations
820
+ if (['write_file', 'edit_file', 'apply_diff'].includes(toolName)) {
821
+ const path = args.path;
822
+ if (path && !this.sandbox.canWrite(path)) {
823
+ this.ui.warning(`Sandbox: Write access denied for ${path}`);
824
+ return false;
825
+ }
826
+ // Check neuroignore
827
+ if (path && this.neuroIgnore.isIgnored(path)) {
828
+ this.ui.warning(`Ignored: ${path} is in .neuroignore`);
829
+ return false;
830
+ }
831
+ // Backup file before modification
832
+ if (path)
833
+ this.sandbox.backupFile(path);
834
+ }
835
+ if (['delete_file'].includes(toolName)) {
836
+ const path = args.path;
837
+ if (path && !this.sandbox.canDelete(path)) {
838
+ this.ui.warning(`Sandbox: Delete access denied for ${path}`);
839
+ return false;
840
+ }
841
+ if (path && this.neuroIgnore.isIgnored(path)) {
842
+ this.ui.warning(`Ignored: ${path} is in .neuroignore`);
843
+ return false;
844
+ }
845
+ }
846
+ if (['read_file', 'search_files', 'list_directory'].includes(toolName)) {
847
+ const path = (args.path || args.directory);
848
+ if (path && !this.sandbox.canRead(path)) {
849
+ this.ui.warning(`Sandbox: Read access denied for ${path}`);
850
+ return false;
851
+ }
852
+ if (path && this.neuroIgnore.isIgnored(path)) {
853
+ this.ui.warning(`Ignored: ${path} is in .neuroignore`);
854
+ return false;
855
+ }
856
+ }
857
+ // Command execution
858
+ if (['run_command', 'bash'].includes(toolName)) {
859
+ const command = args.command;
860
+ if (command && !this.sandbox.canRunCommand(command)) {
861
+ this.ui.warning('Sandbox: Command execution denied');
862
+ return false;
863
+ }
864
+ }
865
+ // Network access
866
+ if (['web_search', 'web_fetch'].includes(toolName)) {
867
+ if (!this.sandbox.canAccessNetwork()) {
868
+ this.ui.warning('Sandbox: Network access denied');
869
+ return false;
870
+ }
871
+ }
872
+ return true;
873
+ }
874
+ /**
875
+ * Handle tool approval using the enhanced ApprovalSystem
876
+ */
877
+ async handleApproval(toolName, args, risk) {
878
+ if (this.autoApproveSet.has(toolName))
879
+ return true;
880
+ const result = await this.approval.requestApproval(toolName, args, risk);
881
+ return result.approved;
882
+ }
883
+ /**
884
+ * Assess task complexity to decide execution mode
885
+ * Now delegates to ModelRouter for more sophisticated analysis
886
+ */
887
+ assessComplexity(message) {
888
+ const decision = this.modelRouter.route(message);
889
+ return decision.complexity;
890
+ }
891
+ /**
892
+ * Switch the active model
893
+ */
894
+ switchModel(modelId) {
895
+ if (!MODELS[modelId]) {
896
+ this.ui.error(`Unknown model: ${modelId}`);
897
+ return false;
898
+ }
899
+ this.config.defaultModel = modelId;
900
+ this.contextManager = new ContextManager(modelId, this.config.context.maxTokens);
901
+ this.ui.success(`Switched to ${MODELS[modelId].name}`);
902
+ return true;
903
+ }
904
+ /**
905
+ * Get current session stats
906
+ */
907
+ getSessionStats() {
908
+ const session = this.sessionManager.getCurrent();
909
+ if (!session)
910
+ return { inputTokens: 0, outputTokens: 0, cost: 0, messages: 0 };
911
+ return {
912
+ inputTokens: session.totalInputTokens,
913
+ outputTokens: session.totalOutputTokens,
914
+ cost: session.totalCost,
915
+ messages: session.messages.length,
916
+ };
917
+ }
918
+ /**
919
+ * Register a custom agent
920
+ */
921
+ registerCustomAgent(name, config) {
922
+ const agentConfig = {
923
+ name,
924
+ description: config.description,
925
+ systemPrompt: config.systemPrompt,
926
+ model: this.config.defaultModel,
927
+ temperature: 0.5,
928
+ maxTokens: 8192,
929
+ tools: config.tools || [],
930
+ maxIterations: config.maxIterations || 10,
931
+ isCustom: true,
932
+ };
933
+ const agent = new BaseAgent(agentConfig, this.client, this.registry, process.cwd(), this.sessionManager.getCurrent()?.id || 'default');
934
+ this.agents.set(name, agent);
935
+ this.orchestrator.registerAgent(agent);
936
+ // Save to config
937
+ if (!this.config.customAgents)
938
+ this.config.customAgents = {};
939
+ this.config.customAgents[name] = agentConfig;
940
+ }
941
+ }
942
+ //# sourceMappingURL=engine.js.map