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.
- package/LICENSE +21 -0
- package/README.md +510 -0
- package/dist/advisor/advisor.d.ts +50 -0
- package/dist/advisor/advisor.js +178 -0
- package/dist/agents/base.d.ts +62 -0
- package/dist/agents/base.js +215 -0
- package/dist/agents/orchestrator.d.ts +46 -0
- package/dist/agents/orchestrator.js +192 -0
- package/dist/agents/team.d.ts +51 -0
- package/dist/agents/team.js +210 -0
- package/dist/api/models.d.ts +23 -0
- package/dist/api/models.js +514 -0
- package/dist/api/ollama.d.ts +153 -0
- package/dist/api/ollama.js +751 -0
- package/dist/api/openrouter.d.ts +55 -0
- package/dist/api/openrouter.js +223 -0
- package/dist/commands/commands.d.ts +43 -0
- package/dist/commands/commands.js +308 -0
- package/dist/config/config.d.ts +8 -0
- package/dist/config/config.js +311 -0
- package/dist/context/compaction.d.ts +54 -0
- package/dist/context/compaction.js +251 -0
- package/dist/context/custom-agents.d.ts +107 -0
- package/dist/context/custom-agents.js +397 -0
- package/dist/context/custom-tools.d.ts +120 -0
- package/dist/context/custom-tools.js +564 -0
- package/dist/context/git-checkpoint.d.ts +52 -0
- package/dist/context/git-checkpoint.js +240 -0
- package/dist/context/neuro-md.d.ts +48 -0
- package/dist/context/neuro-md.js +202 -0
- package/dist/context/neuroignore.d.ts +102 -0
- package/dist/context/neuroignore.js +441 -0
- package/dist/context/repo-map.d.ts +38 -0
- package/dist/context/repo-map.js +220 -0
- package/dist/context/skill-standard.d.ts +262 -0
- package/dist/context/skill-standard.js +1156 -0
- package/dist/context/skill-system.d.ts +75 -0
- package/dist/context/skill-system.js +578 -0
- package/dist/context/tree-sitter.d.ts +99 -0
- package/dist/context/tree-sitter.js +1956 -0
- package/dist/core/acp.d.ts +325 -0
- package/dist/core/acp.js +1498 -0
- package/dist/core/api-server.d.ts +143 -0
- package/dist/core/api-server.js +550 -0
- package/dist/core/approval.d.ts +81 -0
- package/dist/core/approval.js +432 -0
- package/dist/core/auto-compact.d.ts +127 -0
- package/dist/core/auto-compact.js +436 -0
- package/dist/core/auto-mode.d.ts +232 -0
- package/dist/core/auto-mode.js +831 -0
- package/dist/core/background-session.d.ts +166 -0
- package/dist/core/background-session.js +696 -0
- package/dist/core/cicd.d.ts +257 -0
- package/dist/core/cicd.js +1443 -0
- package/dist/core/cloud-sync.d.ts +156 -0
- package/dist/core/cloud-sync.js +582 -0
- package/dist/core/code-review.d.ts +132 -0
- package/dist/core/code-review.js +1191 -0
- package/dist/core/completion.d.ts +49 -0
- package/dist/core/completion.js +384 -0
- package/dist/core/context.d.ts +38 -0
- package/dist/core/context.js +144 -0
- package/dist/core/diff-preview.d.ts +35 -0
- package/dist/core/diff-preview.js +173 -0
- package/dist/core/doom-loop.d.ts +51 -0
- package/dist/core/doom-loop.js +179 -0
- package/dist/core/engine.d.ts +183 -0
- package/dist/core/engine.js +942 -0
- package/dist/core/extended-thinking.d.ts +103 -0
- package/dist/core/extended-thinking.js +269 -0
- package/dist/core/fallback.d.ts +54 -0
- package/dist/core/fallback.js +104 -0
- package/dist/core/git-worktree.d.ts +139 -0
- package/dist/core/git-worktree.js +614 -0
- package/dist/core/headless.d.ts +30 -0
- package/dist/core/headless.js +101 -0
- package/dist/core/i18n.d.ts +83 -0
- package/dist/core/i18n.js +739 -0
- package/dist/core/linting.d.ts +129 -0
- package/dist/core/linting.js +699 -0
- package/dist/core/model-router.d.ts +109 -0
- package/dist/core/model-router.js +581 -0
- package/dist/core/multi-model.d.ts +243 -0
- package/dist/core/multi-model.js +1099 -0
- package/dist/core/multi-session.d.ts +144 -0
- package/dist/core/multi-session.js +442 -0
- package/dist/core/multimodal.d.ts +125 -0
- package/dist/core/multimodal.js +286 -0
- package/dist/core/observability.d.ts +93 -0
- package/dist/core/observability.js +737 -0
- package/dist/core/os-sandbox.d.ts +122 -0
- package/dist/core/os-sandbox.js +1193 -0
- package/dist/core/outcome-grading.d.ts +228 -0
- package/dist/core/outcome-grading.js +1123 -0
- package/dist/core/output-styles.d.ts +57 -0
- package/dist/core/output-styles.js +382 -0
- package/dist/core/parallel-agents.d.ts +183 -0
- package/dist/core/parallel-agents.js +563 -0
- package/dist/core/plugin-bundle.d.ts +236 -0
- package/dist/core/plugin-bundle.js +887 -0
- package/dist/core/plugin-sdk.d.ts +139 -0
- package/dist/core/plugin-sdk.js +273 -0
- package/dist/core/prompt-cache.d.ts +163 -0
- package/dist/core/prompt-cache.js +599 -0
- package/dist/core/sandbox.d.ts +127 -0
- package/dist/core/sandbox.js +369 -0
- package/dist/core/scheduled-tasks.d.ts +151 -0
- package/dist/core/scheduled-tasks.js +502 -0
- package/dist/core/security-scanner.d.ts +160 -0
- package/dist/core/security-scanner.js +1494 -0
- package/dist/core/session.d.ts +83 -0
- package/dist/core/session.js +269 -0
- package/dist/core/shell-completion.d.ts +51 -0
- package/dist/core/shell-completion.js +674 -0
- package/dist/core/smart-monitor.d.ts +146 -0
- package/dist/core/smart-monitor.js +1199 -0
- package/dist/core/spec-driven.d.ts +233 -0
- package/dist/core/spec-driven.js +1485 -0
- package/dist/core/spending-warnings.d.ts +123 -0
- package/dist/core/spending-warnings.js +456 -0
- package/dist/core/sub-agent.d.ts +298 -0
- package/dist/core/sub-agent.js +1023 -0
- package/dist/core/telemetry.d.ts +157 -0
- package/dist/core/telemetry.js +412 -0
- package/dist/core/terminal-ux.d.ts +134 -0
- package/dist/core/terminal-ux.js +649 -0
- package/dist/core/testing.d.ts +146 -0
- package/dist/core/testing.js +1200 -0
- package/dist/core/types.d.ts +439 -0
- package/dist/core/types.js +6 -0
- package/dist/core/undo-redo.d.ts +112 -0
- package/dist/core/undo-redo.js +290 -0
- package/dist/core/updater.d.ts +159 -0
- package/dist/core/updater.js +608 -0
- package/dist/core/vim-mode.d.ts +151 -0
- package/dist/core/vim-mode.js +771 -0
- package/dist/core/voice.d.ts +137 -0
- package/dist/core/voice.js +538 -0
- package/dist/core/web-dashboard.d.ts +109 -0
- package/dist/core/web-dashboard.js +484 -0
- package/dist/hooks/hooks.d.ts +74 -0
- package/dist/hooks/hooks.js +160 -0
- package/dist/hooks/llm-evaluator.d.ts +165 -0
- package/dist/hooks/llm-evaluator.js +560 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1186 -0
- package/dist/lsp/lsp-manager.d.ts +63 -0
- package/dist/lsp/lsp-manager.js +351 -0
- package/dist/mcp/client.d.ts +133 -0
- package/dist/mcp/client.js +684 -0
- package/dist/mcp/mcp-apps.d.ts +70 -0
- package/dist/mcp/mcp-apps.js +1007 -0
- package/dist/tools/bash.d.ts +5 -0
- package/dist/tools/bash.js +195 -0
- package/dist/tools/browser.d.ts +92 -0
- package/dist/tools/browser.js +1570 -0
- package/dist/tools/extended.d.ts +6 -0
- package/dist/tools/extended.js +191 -0
- package/dist/tools/file.d.ts +10 -0
- package/dist/tools/file.js +382 -0
- package/dist/tools/github.d.ts +389 -0
- package/dist/tools/github.js +759 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.js +40 -0
- package/dist/tools/memory.d.ts +6 -0
- package/dist/tools/memory.js +197 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/web.d.ts +6 -0
- package/dist/tools/web.js +150 -0
- package/dist/ui/renderer.d.ts +97 -0
- package/dist/ui/renderer.js +279 -0
- package/dist/ui/theme.d.ts +27 -0
- package/dist/ui/theme.js +106 -0
- 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
|