@loxia-labs/loxia-autopilot-one 1.0.1

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 (80) hide show
  1. package/LICENSE +267 -0
  2. package/README.md +509 -0
  3. package/bin/cli.js +117 -0
  4. package/package.json +94 -0
  5. package/scripts/install-scanners.js +236 -0
  6. package/src/analyzers/CSSAnalyzer.js +297 -0
  7. package/src/analyzers/ConfigValidator.js +690 -0
  8. package/src/analyzers/ESLintAnalyzer.js +320 -0
  9. package/src/analyzers/JavaScriptAnalyzer.js +261 -0
  10. package/src/analyzers/PrettierFormatter.js +247 -0
  11. package/src/analyzers/PythonAnalyzer.js +266 -0
  12. package/src/analyzers/SecurityAnalyzer.js +729 -0
  13. package/src/analyzers/TypeScriptAnalyzer.js +247 -0
  14. package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
  15. package/src/analyzers/codeCloneDetector/detector.js +203 -0
  16. package/src/analyzers/codeCloneDetector/index.js +160 -0
  17. package/src/analyzers/codeCloneDetector/parser.js +199 -0
  18. package/src/analyzers/codeCloneDetector/reporter.js +148 -0
  19. package/src/analyzers/codeCloneDetector/scanner.js +59 -0
  20. package/src/core/agentPool.js +1474 -0
  21. package/src/core/agentScheduler.js +2147 -0
  22. package/src/core/contextManager.js +709 -0
  23. package/src/core/messageProcessor.js +732 -0
  24. package/src/core/orchestrator.js +548 -0
  25. package/src/core/stateManager.js +877 -0
  26. package/src/index.js +631 -0
  27. package/src/interfaces/cli.js +549 -0
  28. package/src/interfaces/webServer.js +2162 -0
  29. package/src/modules/fileExplorer/controller.js +280 -0
  30. package/src/modules/fileExplorer/index.js +37 -0
  31. package/src/modules/fileExplorer/middleware.js +92 -0
  32. package/src/modules/fileExplorer/routes.js +125 -0
  33. package/src/modules/fileExplorer/types.js +44 -0
  34. package/src/services/aiService.js +1232 -0
  35. package/src/services/apiKeyManager.js +164 -0
  36. package/src/services/benchmarkService.js +366 -0
  37. package/src/services/budgetService.js +539 -0
  38. package/src/services/contextInjectionService.js +247 -0
  39. package/src/services/conversationCompactionService.js +637 -0
  40. package/src/services/errorHandler.js +810 -0
  41. package/src/services/fileAttachmentService.js +544 -0
  42. package/src/services/modelRouterService.js +366 -0
  43. package/src/services/modelsService.js +322 -0
  44. package/src/services/qualityInspector.js +796 -0
  45. package/src/services/tokenCountingService.js +536 -0
  46. package/src/tools/agentCommunicationTool.js +1344 -0
  47. package/src/tools/agentDelayTool.js +485 -0
  48. package/src/tools/asyncToolManager.js +604 -0
  49. package/src/tools/baseTool.js +800 -0
  50. package/src/tools/browserTool.js +920 -0
  51. package/src/tools/cloneDetectionTool.js +621 -0
  52. package/src/tools/dependencyResolverTool.js +1215 -0
  53. package/src/tools/fileContentReplaceTool.js +875 -0
  54. package/src/tools/fileSystemTool.js +1107 -0
  55. package/src/tools/fileTreeTool.js +853 -0
  56. package/src/tools/imageTool.js +901 -0
  57. package/src/tools/importAnalyzerTool.js +1060 -0
  58. package/src/tools/jobDoneTool.js +248 -0
  59. package/src/tools/seekTool.js +956 -0
  60. package/src/tools/staticAnalysisTool.js +1778 -0
  61. package/src/tools/taskManagerTool.js +2873 -0
  62. package/src/tools/terminalTool.js +2304 -0
  63. package/src/tools/webTool.js +1430 -0
  64. package/src/types/agent.js +519 -0
  65. package/src/types/contextReference.js +972 -0
  66. package/src/types/conversation.js +730 -0
  67. package/src/types/toolCommand.js +747 -0
  68. package/src/utilities/attachmentValidator.js +292 -0
  69. package/src/utilities/configManager.js +582 -0
  70. package/src/utilities/constants.js +722 -0
  71. package/src/utilities/directoryAccessManager.js +535 -0
  72. package/src/utilities/fileProcessor.js +307 -0
  73. package/src/utilities/logger.js +436 -0
  74. package/src/utilities/tagParser.js +1246 -0
  75. package/src/utilities/toolConstants.js +317 -0
  76. package/web-ui/build/index.html +15 -0
  77. package/web-ui/build/logo.png +0 -0
  78. package/web-ui/build/logo2.png +0 -0
  79. package/web-ui/build/static/index-CjkkcnFA.js +344 -0
  80. package/web-ui/build/static/index-Dy2bYbOa.css +1 -0
@@ -0,0 +1,549 @@
1
+ /**
2
+ * CLI Interface - Command Line Interface for Loxia AI Agents System
3
+ *
4
+ * Purpose:
5
+ * - Provide command-line interaction with the orchestrator
6
+ * - Handle user input and display responses
7
+ * - Support basic agent management and messaging
8
+ * - Interactive REPL-style interface
9
+ */
10
+
11
+ import readline from 'readline';
12
+ import { INTERFACE_TYPES, ORCHESTRATOR_ACTIONS } from '../utilities/constants.js';
13
+
14
+ class CLIInterface {
15
+ constructor(orchestrator, logger, config = {}) {
16
+ this.orchestrator = orchestrator;
17
+ this.logger = logger;
18
+ this.config = config;
19
+
20
+ this.rl = null;
21
+ this.sessionId = `cli-${Date.now()}`;
22
+ this.currentAgent = null;
23
+ this.isRunning = false;
24
+ this.historySize = config.historySize || 1000;
25
+ this.commandHistory = [];
26
+
27
+ // CLI commands
28
+ this.commands = {
29
+ help: this.showHelp.bind(this),
30
+ exit: this.exit.bind(this),
31
+ quit: this.exit.bind(this),
32
+ status: this.showStatus.bind(this),
33
+ agents: this.listAgents.bind(this),
34
+ create: this.createAgent.bind(this),
35
+ switch: this.switchAgent.bind(this),
36
+ pause: this.pauseAgent.bind(this),
37
+ resume: this.resumeAgent.bind(this),
38
+ clear: this.clearScreen.bind(this),
39
+ history: this.showHistory.bind(this)
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Initialize CLI interface
45
+ * @returns {Promise<void>}
46
+ */
47
+ async initialize() {
48
+ this.rl = readline.createInterface({
49
+ input: process.stdin,
50
+ output: process.stdout,
51
+ prompt: this.getPrompt(),
52
+ historySize: this.historySize
53
+ });
54
+
55
+ // Setup input handling
56
+ this.rl.on('line', this.handleInput.bind(this));
57
+ this.rl.on('close', this.exit.bind(this));
58
+
59
+ // Setup tab completion
60
+ this.rl.on('SIGINT', () => {
61
+ console.log('\n(To exit, type "exit" or press Ctrl+C again)');
62
+ this.rl.prompt();
63
+ });
64
+
65
+ this.isRunning = true;
66
+
67
+ // Show welcome message
68
+ this.showWelcome();
69
+
70
+ // Start the prompt
71
+ this.rl.prompt();
72
+ }
73
+
74
+ /**
75
+ * Handle user input
76
+ * @private
77
+ */
78
+ async handleInput(input) {
79
+ const trimmedInput = input.trim();
80
+
81
+ if (trimmedInput.length === 0) {
82
+ this.rl.prompt();
83
+ return;
84
+ }
85
+
86
+ // Add to history
87
+ this.commandHistory.push({
88
+ command: trimmedInput,
89
+ timestamp: new Date().toISOString()
90
+ });
91
+
92
+ // Keep history within limits
93
+ if (this.commandHistory.length > this.historySize) {
94
+ this.commandHistory.shift();
95
+ }
96
+
97
+ try {
98
+ await this.processInput(trimmedInput);
99
+ } catch (error) {
100
+ console.error('❌ Error:', error.message);
101
+ this.logger?.error('CLI command error', {
102
+ command: trimmedInput,
103
+ error: error.message
104
+ });
105
+ }
106
+
107
+ if (this.isRunning) {
108
+ this.rl.prompt();
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Process user input
114
+ * @private
115
+ */
116
+ async processInput(input) {
117
+ // Check for CLI commands
118
+ if (input.startsWith('/')) {
119
+ const commandParts = input.slice(1).split(' ');
120
+ const command = commandParts[0].toLowerCase();
121
+ const args = commandParts.slice(1);
122
+
123
+ if (this.commands[command]) {
124
+ await this.commands[command](args);
125
+ return;
126
+ } else {
127
+ console.log(`❌ Unknown command: /${command}`);
128
+ console.log('Type /help for available commands');
129
+ return;
130
+ }
131
+ }
132
+
133
+ // If no current agent, suggest creating one
134
+ if (!this.currentAgent) {
135
+ console.log('💡 No agent selected. Create an agent first with: /create <agent-name>');
136
+ return;
137
+ }
138
+
139
+ // Send message to current agent
140
+ await this.sendMessageToAgent(input);
141
+ }
142
+
143
+ /**
144
+ * Send message to current agent
145
+ * @private
146
+ */
147
+ async sendMessageToAgent(message) {
148
+ console.log('📤 Sending to agent...');
149
+
150
+ try {
151
+ const request = {
152
+ interface: INTERFACE_TYPES.CLI,
153
+ sessionId: this.sessionId,
154
+ action: ORCHESTRATOR_ACTIONS.SEND_MESSAGE,
155
+ payload: {
156
+ agentId: this.currentAgent.id,
157
+ message,
158
+ mode: 'chat'
159
+ },
160
+ projectDir: process.cwd()
161
+ };
162
+
163
+ const response = await this.orchestrator.processRequest(request);
164
+
165
+ if (response.success) {
166
+ console.log('🤖 Agent response:');
167
+ console.log(response.data.message.content);
168
+
169
+ // Show tool results if any
170
+ if (response.data.toolResults && response.data.toolResults.length > 0) {
171
+ console.log('\n🔧 Tool execution results:');
172
+ for (const result of response.data.toolResults) {
173
+ console.log(` ${result.toolId}: ${result.status}`);
174
+ if (result.result) {
175
+ console.log(` Result: ${JSON.stringify(result.result, null, 2)}`);
176
+ }
177
+ }
178
+ }
179
+
180
+ } else {
181
+ console.error('❌ Agent response failed:', response.error);
182
+ }
183
+
184
+ } catch (error) {
185
+ console.error('❌ Failed to send message:', error.message);
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Show welcome message
191
+ * @private
192
+ */
193
+ showWelcome() {
194
+ console.log('');
195
+ console.log('🎯 Welcome to Loxia Autopilot One CLI');
196
+ console.log(' Type /help for available commands');
197
+ console.log(' Type /create <name> to create your first agent');
198
+ console.log('');
199
+ }
200
+
201
+ /**
202
+ * Show help information
203
+ * @private
204
+ */
205
+ async showHelp() {
206
+ console.log('');
207
+ console.log('📚 Loxia Autopilot One CLI Commands:');
208
+ console.log('');
209
+ console.log(' /help - Show this help message');
210
+ console.log(' /status - Show system status');
211
+ console.log(' /agents - List all agents');
212
+ console.log(' /create <name> - Create a new agent');
213
+ console.log(' /switch <agent-id> - Switch to different agent');
214
+ console.log(' /pause <agent-id> - Pause an agent');
215
+ console.log(' /resume <agent-id> - Resume a paused agent');
216
+ console.log(' /history - Show command history');
217
+ console.log(' /clear - Clear screen');
218
+ console.log(' /exit or /quit - Exit the CLI');
219
+ console.log('');
220
+ console.log('💬 Chat with agents:');
221
+ console.log(' Simply type your message to send it to the current agent');
222
+ console.log(' Agents can use tools and communicate with other agents');
223
+ console.log('');
224
+ }
225
+
226
+ /**
227
+ * Show system status
228
+ * @private
229
+ */
230
+ async showStatus() {
231
+ try {
232
+ const request = {
233
+ interface: INTERFACE_TYPES.CLI,
234
+ sessionId: this.sessionId,
235
+ action: ORCHESTRATOR_ACTIONS.GET_SESSION_STATE,
236
+ payload: {},
237
+ projectDir: process.cwd()
238
+ };
239
+
240
+ const response = await this.orchestrator.processRequest(request);
241
+
242
+ if (response.success) {
243
+ const state = response.data;
244
+ console.log('');
245
+ console.log('📊 System Status:');
246
+ console.log(` Session ID: ${state.sessionId}`);
247
+ console.log(` Project: ${state.projectDir}`);
248
+ console.log(` Agents: ${state.agents.length}`);
249
+ console.log(` Current Agent: ${this.currentAgent ? this.currentAgent.name : 'None'}`);
250
+ console.log('');
251
+
252
+ if (state.agents.length > 0) {
253
+ console.log('🤖 Active Agents:');
254
+ for (const agent of state.agents) {
255
+ const status = agent.isPaused ? `${agent.status} (until ${agent.pausedUntil})` : agent.status;
256
+ console.log(` ${agent.id}: ${agent.name} (${status})`);
257
+ }
258
+ console.log('');
259
+ }
260
+ } else {
261
+ console.error('❌ Failed to get status:', response.error);
262
+ }
263
+
264
+ } catch (error) {
265
+ console.error('❌ Status command failed:', error.message);
266
+ }
267
+ }
268
+
269
+ /**
270
+ * List all agents
271
+ * @private
272
+ */
273
+ async listAgents() {
274
+ try {
275
+ const request = {
276
+ interface: INTERFACE_TYPES.CLI,
277
+ sessionId: this.sessionId,
278
+ action: ORCHESTRATOR_ACTIONS.LIST_AGENTS,
279
+ payload: {},
280
+ projectDir: process.cwd()
281
+ };
282
+
283
+ const response = await this.orchestrator.processRequest(request);
284
+
285
+ if (response.success) {
286
+ const agents = response.data;
287
+ console.log('');
288
+
289
+ if (agents.length === 0) {
290
+ console.log('📭 No agents created yet');
291
+ console.log(' Use /create <name> to create your first agent');
292
+ } else {
293
+ console.log('🤖 Available Agents:');
294
+
295
+ for (const agent of agents) {
296
+ const current = this.currentAgent && this.currentAgent.id === agent.id ? ' (current)' : '';
297
+ const status = agent.isPaused ? `${agent.status} (until ${agent.pausedUntil})` : agent.status;
298
+
299
+ console.log(` ${agent.id}: ${agent.name}${current}`);
300
+ console.log(` Status: ${status}`);
301
+ console.log(` Model: ${agent.currentModel}`);
302
+ console.log(` Messages: ${agent.messageCount}`);
303
+ console.log('');
304
+ }
305
+ }
306
+
307
+ } else {
308
+ console.error('❌ Failed to list agents:', response.error);
309
+ }
310
+
311
+ } catch (error) {
312
+ console.error('❌ List agents command failed:', error.message);
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Create a new agent
318
+ * @private
319
+ */
320
+ async createAgent(args) {
321
+ if (args.length === 0) {
322
+ console.log('❌ Usage: /create <agent-name> [model]');
323
+ return;
324
+ }
325
+
326
+ const name = args[0];
327
+ const model = args[1] || 'anthropic-sonnet';
328
+
329
+ console.log(`🔨 Creating agent "${name}" with model ${model}...`);
330
+
331
+ try {
332
+ const request = {
333
+ interface: INTERFACE_TYPES.CLI,
334
+ sessionId: this.sessionId,
335
+ action: ORCHESTRATOR_ACTIONS.CREATE_AGENT,
336
+ payload: {
337
+ name,
338
+ systemPrompt: `You are ${name}, an AI assistant created in the Loxia Autopilot One system. You can help with coding, analysis, and various tasks using the available tools.`,
339
+ model,
340
+ capabilities: ['terminal', 'filesystem', 'agentdelay', 'browser']
341
+ },
342
+ projectDir: process.cwd()
343
+ };
344
+
345
+ const response = await this.orchestrator.processRequest(request);
346
+
347
+ if (response.success) {
348
+ const agent = response.data;
349
+ this.currentAgent = agent;
350
+
351
+ console.log('✅ Agent created successfully!');
352
+ console.log(` ID: ${agent.id}`);
353
+ console.log(` Name: ${agent.name}`);
354
+ console.log(` Model: ${agent.preferredModel}`);
355
+ console.log(' Switched to this agent automatically');
356
+
357
+ // Update prompt
358
+ this.rl.setPrompt(this.getPrompt());
359
+
360
+ } else {
361
+ console.error('❌ Failed to create agent:', response.error);
362
+ }
363
+
364
+ } catch (error) {
365
+ console.error('❌ Create agent command failed:', error.message);
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Switch to different agent
371
+ * @private
372
+ */
373
+ async switchAgent(args) {
374
+ if (args.length === 0) {
375
+ console.log('❌ Usage: /switch <agent-id>');
376
+ return;
377
+ }
378
+
379
+ const agentId = args[0];
380
+
381
+ try {
382
+ // First, get the agent to verify it exists
383
+ const request = {
384
+ interface: INTERFACE_TYPES.CLI,
385
+ sessionId: this.sessionId,
386
+ action: ORCHESTRATOR_ACTIONS.GET_AGENT_STATUS,
387
+ payload: { agentId },
388
+ projectDir: process.cwd()
389
+ };
390
+
391
+ const response = await this.orchestrator.processRequest(request);
392
+
393
+ if (response.success) {
394
+ this.currentAgent = response.data;
395
+ console.log(`✅ Switched to agent: ${this.currentAgent.name} (${this.currentAgent.id})`);
396
+
397
+ // Update prompt
398
+ this.rl.setPrompt(this.getPrompt());
399
+
400
+ } else {
401
+ console.error('❌ Failed to switch agent:', response.error);
402
+ }
403
+
404
+ } catch (error) {
405
+ console.error('❌ Switch agent command failed:', error.message);
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Pause an agent
411
+ * @private
412
+ */
413
+ async pauseAgent(args) {
414
+ if (args.length === 0) {
415
+ console.log('❌ Usage: /pause <agent-id> [duration] [reason]');
416
+ return;
417
+ }
418
+
419
+ const agentId = args[0];
420
+ const duration = parseInt(args[1]) || 60;
421
+ const reason = args.slice(2).join(' ') || 'Manual pause from CLI';
422
+
423
+ try {
424
+ const request = {
425
+ interface: INTERFACE_TYPES.CLI,
426
+ sessionId: this.sessionId,
427
+ action: ORCHESTRATOR_ACTIONS.PAUSE_AGENT,
428
+ payload: { agentId, duration, reason },
429
+ projectDir: process.cwd()
430
+ };
431
+
432
+ const response = await this.orchestrator.processRequest(request);
433
+
434
+ if (response.success) {
435
+ console.log(`✅ Agent paused for ${duration} seconds`);
436
+ console.log(` Reason: ${reason}`);
437
+ } else {
438
+ console.error('❌ Failed to pause agent:', response.error);
439
+ }
440
+
441
+ } catch (error) {
442
+ console.error('❌ Pause agent command failed:', error.message);
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Resume a paused agent
448
+ * @private
449
+ */
450
+ async resumeAgent(args) {
451
+ if (args.length === 0) {
452
+ console.log('❌ Usage: /resume <agent-id>');
453
+ return;
454
+ }
455
+
456
+ const agentId = args[0];
457
+
458
+ try {
459
+ const request = {
460
+ interface: INTERFACE_TYPES.CLI,
461
+ sessionId: this.sessionId,
462
+ action: ORCHESTRATOR_ACTIONS.RESUME_AGENT,
463
+ payload: { agentId },
464
+ projectDir: process.cwd()
465
+ };
466
+
467
+ const response = await this.orchestrator.processRequest(request);
468
+
469
+ if (response.success) {
470
+ console.log('✅ Agent resumed successfully');
471
+ } else {
472
+ console.error('❌ Failed to resume agent:', response.error);
473
+ }
474
+
475
+ } catch (error) {
476
+ console.error('❌ Resume agent command failed:', error.message);
477
+ }
478
+ }
479
+
480
+ /**
481
+ * Show command history
482
+ * @private
483
+ */
484
+ async showHistory() {
485
+ console.log('');
486
+ console.log('📜 Command History:');
487
+
488
+ if (this.commandHistory.length === 0) {
489
+ console.log(' No commands executed yet');
490
+ } else {
491
+ const recent = this.commandHistory.slice(-10); // Show last 10 commands
492
+
493
+ for (let i = 0; i < recent.length; i++) {
494
+ const entry = recent[i];
495
+ const time = new Date(entry.timestamp).toLocaleTimeString();
496
+ console.log(` ${i + 1}. [${time}] ${entry.command}`);
497
+ }
498
+
499
+ if (this.commandHistory.length > 10) {
500
+ console.log(` ... and ${this.commandHistory.length - 10} more commands`);
501
+ }
502
+ }
503
+
504
+ console.log('');
505
+ }
506
+
507
+ /**
508
+ * Clear screen
509
+ * @private
510
+ */
511
+ async clearScreen() {
512
+ console.clear();
513
+ this.showWelcome();
514
+ }
515
+
516
+ /**
517
+ * Exit the CLI
518
+ * @private
519
+ */
520
+ async exit() {
521
+ if (this.isRunning) {
522
+ console.log('\n👋 Goodbye!');
523
+ this.isRunning = false;
524
+
525
+ if (this.rl) {
526
+ this.rl.close();
527
+ }
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Get command prompt
533
+ * @private
534
+ */
535
+ getPrompt() {
536
+ const agentName = this.currentAgent ? this.currentAgent.name : 'no-agent';
537
+ return `loxia:${agentName}> `;
538
+ }
539
+
540
+ /**
541
+ * Shutdown the CLI interface
542
+ * @returns {Promise<void>}
543
+ */
544
+ async shutdown() {
545
+ await this.exit();
546
+ }
547
+ }
548
+
549
+ export default CLIInterface;