vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1739
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/README.md +240 -0
- package/package.json +10 -2
- package/src/agents/Agent.js +300 -0
- package/src/agents/AgentAdditionService.js +311 -0
- package/src/agents/AgentCheckService.js +690 -0
- package/src/agents/AgentInstallationService.js +140 -0
- package/src/agents/AgentSetupService.js +467 -0
- package/src/agents/AgentStatus.js +183 -0
- package/src/agents/AgentVerificationService.js +634 -0
- package/src/agents/ConfigurationSchemaValidator.js +543 -0
- package/src/agents/EnvironmentConfigurationManager.js +602 -0
- package/src/agents/InstallationErrorHandler.js +372 -0
- package/src/agents/InstallationLog.js +363 -0
- package/src/agents/InstallationMethod.js +510 -0
- package/src/agents/InstallationOrchestrator.js +352 -0
- package/src/agents/InstallationProgressReporter.js +372 -0
- package/src/agents/InstallationRetryManager.js +322 -0
- package/src/agents/InstallationType.js +254 -0
- package/src/agents/OperationTypes.js +310 -0
- package/src/agents/PerformanceMetricsCollector.js +493 -0
- package/src/agents/SecurityValidationService.js +534 -0
- package/src/agents/VerificationTest.js +354 -0
- package/src/agents/VerificationType.js +226 -0
- package/src/agents/WindowsPermissionHandler.js +518 -0
- package/src/agents/config/AgentConfigManager.js +393 -0
- package/src/agents/config/AgentDefaultsRegistry.js +373 -0
- package/src/agents/config/ConfigValidator.js +281 -0
- package/src/agents/discovery/AgentDiscoveryService.js +707 -0
- package/src/agents/logging/AgentLogger.js +511 -0
- package/src/agents/status/AgentStatusManager.js +481 -0
- package/src/agents/storage/FileManager.js +454 -0
- package/src/agents/verification/AgentCommunicationTester.js +474 -0
- package/src/agents/verification/BaseVerifier.js +430 -0
- package/src/agents/verification/CommandVerifier.js +480 -0
- package/src/agents/verification/FileOperationVerifier.js +453 -0
- package/src/agents/verification/ResultAnalyzer.js +707 -0
- package/src/agents/verification/TestRequirementManager.js +495 -0
- package/src/agents/verification/VerificationRunner.js +433 -0
- package/src/agents/windows/BaseWindowsInstaller.js +441 -0
- package/src/agents/windows/ChocolateyInstaller.js +509 -0
- package/src/agents/windows/DirectInstaller.js +443 -0
- package/src/agents/windows/InstallerFactory.js +391 -0
- package/src/agents/windows/NpmInstaller.js +505 -0
- package/src/agents/windows/PowerShellInstaller.js +458 -0
- package/src/agents/windows/WinGetInstaller.js +390 -0
- package/src/analysis/analysis-reporter.js +132 -0
- package/src/analysis/boundary-detector.js +712 -0
- package/src/analysis/categorizer.js +340 -0
- package/src/analysis/codebase-scanner.js +384 -0
- package/src/analysis/line-counter.js +513 -0
- package/src/analysis/priority-calculator.js +679 -0
- package/src/analysis/report/analysis-report.js +250 -0
- package/src/analysis/report/package-analyzer.js +278 -0
- package/src/analysis/report/recommendation-generator.js +382 -0
- package/src/analysis/report/statistics-generator.js +515 -0
- package/src/analysis/reports/analysis-report-model.js +101 -0
- package/src/analysis/reports/recommendation-generator.js +283 -0
- package/src/analysis/reports/report-generators.js +191 -0
- package/src/analysis/reports/statistics-calculator.js +231 -0
- package/src/analysis/reports/trend-analyzer.js +219 -0
- package/src/analysis/strategy-generator.js +814 -0
- package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
- package/src/config/refactoring-config.js +307 -0
- package/src/health-tracking/json-storage.js +38 -2
- package/src/ide-integration/applescript-manager-core.js +233 -0
- package/src/ide-integration/applescript-manager.cjs +357 -28
- package/src/ide-integration/applescript-manager.js +89 -3599
- package/src/ide-integration/cdp-manager.js +306 -0
- package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
- package/src/ide-integration/continuation-handler.js +337 -0
- package/src/ide-integration/ide-status-checker.js +292 -0
- package/src/ide-integration/macos-ide-manager.js +627 -0
- package/src/ide-integration/macos-text-sender.js +528 -0
- package/src/ide-integration/response-reader.js +548 -0
- package/src/ide-integration/windows-automation-manager.js +121 -0
- package/src/ide-integration/windows-ide-manager.js +373 -0
- package/src/index.cjs +25 -3
- package/src/index.js +15 -1
- package/src/llm/direct-llm-manager.cjs +90 -2
- package/src/models/compliance-report.js +538 -0
- package/src/models/file-analysis.js +681 -0
- package/src/models/refactoring-plan.js +770 -0
- package/src/monitoring/alert-system.js +834 -0
- package/src/monitoring/compliance-progress-tracker.js +437 -0
- package/src/monitoring/continuous-scan-notifications.js +661 -0
- package/src/monitoring/continuous-scanner.js +279 -0
- package/src/monitoring/file-monitor/file-analyzer.js +262 -0
- package/src/monitoring/file-monitor/file-monitor.js +237 -0
- package/src/monitoring/file-monitor/watcher.js +194 -0
- package/src/monitoring/file-monitor.js +17 -0
- package/src/monitoring/notification-manager.js +437 -0
- package/src/monitoring/scanner-core.js +368 -0
- package/src/monitoring/scanner-events.js +214 -0
- package/src/monitoring/violation-notification-system.js +515 -0
- package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
- package/src/refactoring/boundaries/extraction-result.js +285 -0
- package/src/refactoring/boundaries/extraction-strategies.js +392 -0
- package/src/refactoring/boundaries/module-boundary.js +209 -0
- package/src/refactoring/boundary/boundary-detector.js +741 -0
- package/src/refactoring/boundary/boundary-types.js +405 -0
- package/src/refactoring/boundary/extraction-strategies.js +554 -0
- package/src/refactoring/boundary-extraction-result.js +77 -0
- package/src/refactoring/boundary-extraction-strategies.js +330 -0
- package/src/refactoring/boundary-extractor.js +384 -0
- package/src/refactoring/boundary-types.js +46 -0
- package/src/refactoring/circular/circular-dependency.js +88 -0
- package/src/refactoring/circular/cycle-detection.js +147 -0
- package/src/refactoring/circular/dependency-node.js +82 -0
- package/src/refactoring/circular/dependency-result.js +107 -0
- package/src/refactoring/circular/dependency-types.js +58 -0
- package/src/refactoring/circular/graph-builder.js +213 -0
- package/src/refactoring/circular/resolution-strategy.js +72 -0
- package/src/refactoring/circular/strategy-generator.js +229 -0
- package/src/refactoring/circular-dependency-resolver-original.js +809 -0
- package/src/refactoring/circular-dependency-resolver.js +200 -0
- package/src/refactoring/code-mover.js +761 -0
- package/src/refactoring/file-splitter.js +696 -0
- package/src/refactoring/functionality-validator.js +816 -0
- package/src/refactoring/import-manager.js +774 -0
- package/src/refactoring/module-boundary.js +107 -0
- package/src/refactoring/refactoring-executor.js +672 -0
- package/src/refactoring/refactoring-rollback.js +614 -0
- package/src/refactoring/test-validator.js +631 -0
- package/src/requirement-management/default-requirement-manager.js +321 -0
- package/src/requirement-management/requirement-file-parser.js +159 -0
- package/src/requirement-management/requirement-sequencer.js +221 -0
- package/src/rui/commands/AgentCommandParser.js +600 -0
- package/src/rui/commands/AgentCommands.js +487 -0
- package/src/rui/commands/AgentResponseFormatter.js +832 -0
- package/src/scripts/verify-full-compliance.js +269 -0
- package/src/sync/sync-engine-core.js +1 -0
- package/src/sync/sync-engine-remote-handlers.js +135 -0
- package/src/task-generation/automated-task-generator.js +351 -0
- package/src/task-generation/prioritizer.js +287 -0
- package/src/task-generation/task-list-updater.js +215 -0
- package/src/task-generation/task-management-integration.js +480 -0
- package/src/task-generation/task-manager-integration.js +270 -0
- package/src/task-generation/violation-task-generator.js +474 -0
- package/src/task-management/continuous-scan-integration.js +342 -0
- package/src/timeout-management/index.js +12 -3
- package/src/timeout-management/response-time-tracker.js +167 -0
- package/src/timeout-management/timeout-calculator.js +159 -0
- package/src/timeout-management/timeout-config-manager.js +172 -0
- package/src/utils/ast-analyzer.js +417 -0
- package/src/utils/current-requirement-manager.js +276 -0
- package/src/utils/current-requirement-operations.js +472 -0
- package/src/utils/dependency-mapper.js +456 -0
- package/src/utils/download-with-progress.js +4 -2
- package/src/utils/electron-update-checker.js +4 -1
- package/src/utils/file-size-analyzer.js +272 -0
- package/src/utils/import-updater.js +280 -0
- package/src/utils/refactoring-tools.js +512 -0
- package/src/utils/report-generator.js +569 -0
- package/src/utils/reports/report-analysis.js +218 -0
- package/src/utils/reports/report-types.js +55 -0
- package/src/utils/reports/summary-generators.js +102 -0
- package/src/utils/requirement-file-management.js +157 -0
- package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
- package/src/utils/requirement-helpers/requirement-mover.js +414 -0
- package/src/utils/requirement-helpers/requirement-parser.js +326 -0
- package/src/utils/requirement-helpers/requirement-status.js +320 -0
- package/src/utils/requirement-helpers-new.js +55 -0
- package/src/utils/requirement-helpers-refactored.js +367 -0
- package/src/utils/requirement-helpers.js +291 -1191
- package/src/utils/requirement-movement-operations.js +450 -0
- package/src/utils/requirement-movement.js +312 -0
- package/src/utils/requirement-parsing-helpers.js +56 -0
- package/src/utils/requirement-statistics.js +200 -0
- package/src/utils/requirement-text-utils.js +58 -0
- package/src/utils/rollback/rollback-handlers.js +125 -0
- package/src/utils/rollback/rollback-operation.js +63 -0
- package/src/utils/rollback/rollback-recorder.js +166 -0
- package/src/utils/rollback/rollback-state-manager.js +175 -0
- package/src/utils/rollback/rollback-types.js +33 -0
- package/src/utils/rollback/rollback-utils.js +110 -0
- package/src/utils/rollback-manager-original.js +569 -0
- package/src/utils/rollback-manager.js +202 -0
- package/src/utils/smoke-test-cli.js +362 -0
- package/src/utils/smoke-test-gui.js +351 -0
- package/src/utils/smoke-test-orchestrator.js +321 -0
- package/src/utils/smoke-test-runner.js +60 -0
- package/src/utils/smoke-test-web.js +347 -0
- package/src/utils/specification-helpers.js +39 -13
- package/src/utils/specification-migration.js +97 -0
- package/src/utils/test-runner.js +579 -0
- package/src/utils/validation-framework.js +518 -0
- package/src/validation/compliance-analyzer.js +197 -0
- package/src/validation/compliance-report-generator.js +343 -0
- package/src/validation/compliance-reporter.js +711 -0
- package/src/validation/compliance-rules.js +127 -0
- package/src/validation/constitution-validator-new.js +196 -0
- package/src/validation/constitution-validator.js +17 -0
- package/src/validation/file-validators.js +170 -0
- package/src/validation/line-limit/file-analyzer.js +201 -0
- package/src/validation/line-limit/line-limit-validator.js +208 -0
- package/src/validation/line-limit/validation-result.js +144 -0
- package/src/validation/line-limit-core.js +225 -0
- package/src/validation/line-limit-reporter.js +134 -0
- package/src/validation/line-limit-result.js +125 -0
- package/src/validation/line-limit-validator.js +41 -0
- package/src/validation/metrics-calculator.js +660 -0
- package/src/sync/sync-engine-backup.js +0 -559
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Discovery Service
|
|
3
|
+
*
|
|
4
|
+
* Discovers and manages new agent CLI tools.
|
|
5
|
+
* Follows constitutional requirements: <555 lines, test-first approach.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { spawn, exec } = require('child_process');
|
|
11
|
+
const { promisify } = require('util');
|
|
12
|
+
|
|
13
|
+
const execAsync = promisify(exec);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Agent Discovery Service class
|
|
17
|
+
*/
|
|
18
|
+
class AgentDiscoveryService {
|
|
19
|
+
/**
|
|
20
|
+
* Create discovery service instance
|
|
21
|
+
* @param {Object} options - Service options
|
|
22
|
+
*/
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.configManager = options.configManager || null;
|
|
25
|
+
this.logger = options.logger || null;
|
|
26
|
+
this.fileManager = options.fileManager || null;
|
|
27
|
+
this.discoveryPaths = options.discoveryPaths || ['/usr/local/bin', '/opt/bin', '/usr/bin/local/bin', '/snap/bin'];
|
|
28
|
+
this.timeout = options.timeout || 30000;
|
|
29
|
+
this.maxConcurrency = options.maxConcurrency || 3;
|
|
30
|
+
this.discoveryHistoryFile = options.discoveryHistoryFile || './discovery-history.json';
|
|
31
|
+
this.discoveryStatusFile = options.discoveryStatusFile || './discovery-status.json';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Discover agents from configured paths
|
|
36
|
+
* @returns {Promise<Object>} - Discovery result
|
|
37
|
+
*/
|
|
38
|
+
async discoverAgents() {
|
|
39
|
+
const startTime = Date.now();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
if (this.logger) {
|
|
43
|
+
await this.logger.info('Starting agent discovery', {
|
|
44
|
+
paths: this.discoveryPaths,
|
|
45
|
+
timeout: this.timeout
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const discoveredAgents = [];
|
|
50
|
+
const warnings = [];
|
|
51
|
+
const errors = [];
|
|
52
|
+
|
|
53
|
+
// Discover agents from each path
|
|
54
|
+
const pathAgents = [];
|
|
55
|
+
|
|
56
|
+
for (const discoveryPath of this.discoveryPaths) {
|
|
57
|
+
try {
|
|
58
|
+
const agents = await this.discoverFromPath(discoveryPath);
|
|
59
|
+
discoveredAgents.push(...agents);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const errorMsg = `Discovery failed for path ${discoveryPath}: ${error.message}`;
|
|
62
|
+
errors.push(errorMsg);
|
|
63
|
+
|
|
64
|
+
if (this.logger) {
|
|
65
|
+
await this.logger.error(errorMsg);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Validate and deduplicate discovered agents
|
|
71
|
+
const validAgents = await this.validateAndDeduplicateAgents(discoveredAgents);
|
|
72
|
+
const duplicateCount = discoveredAgents.length - validAgents.length;
|
|
73
|
+
|
|
74
|
+
if (duplicateCount > 0) {
|
|
75
|
+
warnings.push(`Removed ${duplicateCount} duplicate agents`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Update discovery status
|
|
79
|
+
await this.updateDiscoveryStatus(validAgents, discoveredAgents.length, duplicateCount, warnings, errors);
|
|
80
|
+
|
|
81
|
+
const duration = Date.now() - startTime;
|
|
82
|
+
|
|
83
|
+
if (this.logger) {
|
|
84
|
+
await this.logger.info('Agent discovery completed', {
|
|
85
|
+
totalDiscovered: discoveredAgents.length,
|
|
86
|
+
validAgents: validAgents.length,
|
|
87
|
+
duplicates: duplicateCount,
|
|
88
|
+
warnings: warnings.length,
|
|
89
|
+
errors: errors.length,
|
|
90
|
+
duration
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await this.recordDiscoveryOperation('discover', {
|
|
95
|
+
totalDiscovered: discoveredAgents.length,
|
|
96
|
+
validAgents: validAgents.length,
|
|
97
|
+
duration
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
success: errors.length === 0,
|
|
102
|
+
agents: validAgents,
|
|
103
|
+
discovered: discoveredAgents,
|
|
104
|
+
warnings,
|
|
105
|
+
errors,
|
|
106
|
+
duration,
|
|
107
|
+
timestamp: new Date().toISOString()
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
const duration = Date.now() - startTime;
|
|
111
|
+
|
|
112
|
+
if (this.logger) {
|
|
113
|
+
await this.logger.error('Agent discovery failed', {
|
|
114
|
+
error: error.message,
|
|
115
|
+
duration
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
agents: [],
|
|
122
|
+
error: error.message,
|
|
123
|
+
duration,
|
|
124
|
+
timestamp: new Date().toISOString()
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Discover agents from each path
|
|
131
|
+
* @param {string} discoveryPath - Path to search for agents
|
|
132
|
+
* @returns {Promise<Array>} - Discovered agents
|
|
133
|
+
*/
|
|
134
|
+
async discoverFromPath(discoveryPath) {
|
|
135
|
+
try {
|
|
136
|
+
const stat = await fs.stat(discoveryPath);
|
|
137
|
+
|
|
138
|
+
if (!stat.isDirectory()) {
|
|
139
|
+
if (this.logger) {
|
|
140
|
+
await this.logger.warn(`Discovery path is not a directory: ${discoveryPath}`);
|
|
141
|
+
}
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const files = await fs.readdir(discoveryPath);
|
|
146
|
+
const agents = [];
|
|
147
|
+
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
const filePath = path.join(discoveryPath, file);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const fileStat = await fs.stat(filePath);
|
|
153
|
+
const isDirectory = await fs.stat(filePath).then(stat => stat.isDirectory());
|
|
154
|
+
if (isDirectory) {
|
|
155
|
+
const subAgents = await this.discoverFromPath(filePath);
|
|
156
|
+
agents.push(...subAgents);
|
|
157
|
+
} else {
|
|
158
|
+
// Check if it's an executable file
|
|
159
|
+
if (fileStat.isFile() && fileStat.mode & parseInt('111', 8)) {
|
|
160
|
+
const agentInfo = await this.analyzeExecutable(filePath);
|
|
161
|
+
|
|
162
|
+
if (agentInfo) {
|
|
163
|
+
agents.push(agentInfo);
|
|
164
|
+
|
|
165
|
+
if (this.logger) {
|
|
166
|
+
await this.logger.info(`Found potential agent: ${agentInfo.name} (${agentInfo.id})`, {
|
|
167
|
+
path: filePath,
|
|
168
|
+
type: agentInfo.type
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (this.logger) {
|
|
176
|
+
await this.logger.warn(`Error analyzing file ${filePath}: ${error.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return agents;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (this.logger) {
|
|
184
|
+
await this.logger.error(`Failed to read discovery path ${discoveryPath}: ${error.message}`);
|
|
185
|
+
}
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Analyze executable file for agent information
|
|
192
|
+
* @param {string} filePath - Path to executable file
|
|
193
|
+
* @returns {Promise<Object>} - Agent information or null
|
|
194
|
+
*/
|
|
195
|
+
async analyzeExecutable(filePath) {
|
|
196
|
+
try {
|
|
197
|
+
// Get file info
|
|
198
|
+
const stat = await fs.stat(filePath);
|
|
199
|
+
const fileName = path.basename(filePath);
|
|
200
|
+
|
|
201
|
+
// Try to get version information
|
|
202
|
+
let version = 'unknown';
|
|
203
|
+
let description = '';
|
|
204
|
+
|
|
205
|
+
// Execute file with --help or --version flag
|
|
206
|
+
try {
|
|
207
|
+
const { stdout } = await execAsync(`"${filePath}" --version`, {
|
|
208
|
+
timeout: 5000
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Parse version from output
|
|
212
|
+
const versionMatch = stdout.match(/(\d+\.\d+\.\d+)/);
|
|
213
|
+
if (versionMatch) {
|
|
214
|
+
version = versionMatch[1];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Try to get description from help output
|
|
218
|
+
const { stdout: helpOutput } = await execAsync(`"${filePath}" --help`, {
|
|
219
|
+
timeout: 5000
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Extract description from help output (first line that looks like a description)
|
|
223
|
+
const helpLines = helpOutput.split('\n');
|
|
224
|
+
const descriptionLine = helpLines.find(line =>
|
|
225
|
+
line && !line.startsWith('Usage:') &&
|
|
226
|
+
!line.startsWith('Options:') &&
|
|
227
|
+
line.trim().length > 10
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (descriptionLine) {
|
|
231
|
+
description = descriptionLine.trim();
|
|
232
|
+
}
|
|
233
|
+
} catch (versionError) {
|
|
234
|
+
// Version check failed, continue with unknown version
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Determine agent type based on file characteristics
|
|
238
|
+
let type = 'CLI';
|
|
239
|
+
if (fileName.includes('gui') || fileName.includes('window') || fileName.includes('app')) {
|
|
240
|
+
type = 'GUI';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Generate unique ID based on filename
|
|
244
|
+
const id = this.generateAgentId(fileName, filePath);
|
|
245
|
+
|
|
246
|
+
// Determine capabilities based on help output
|
|
247
|
+
const capabilities = await this.determineCapabilities(filePath, helpOutput);
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
id,
|
|
251
|
+
name: this.generateAgentName(fileName, description),
|
|
252
|
+
path: filePath,
|
|
253
|
+
version,
|
|
254
|
+
description,
|
|
255
|
+
type,
|
|
256
|
+
capabilities,
|
|
257
|
+
discovered: true,
|
|
258
|
+
discoveredAt: new Date().toISOString()
|
|
259
|
+
};
|
|
260
|
+
} catch (error) {
|
|
261
|
+
if (this.logger) {
|
|
262
|
+
await this.logger.warn(`Error analyzing executable ${filePath}: ${error.message}`);
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Generate agent ID from filename and path
|
|
270
|
+
* @param {string} fileName - File name
|
|
271
|
+
* @param {string} filePath - File path
|
|
272
|
+
* @returns {string} - Generated agent ID
|
|
273
|
+
*/
|
|
274
|
+
generateAgentId(fileName, filePath) {
|
|
275
|
+
// Use filename as base, make it lowercase and replace special chars
|
|
276
|
+
const baseId = fileName
|
|
277
|
+
.toLowerCase()
|
|
278
|
+
.replace(/[^a-z0-9]/g, '-')
|
|
279
|
+
.replace(/\.(exe|sh|bat|cmd)$/g, '');
|
|
280
|
+
|
|
281
|
+
// Add path hash for uniqueness
|
|
282
|
+
const pathHash = filePath
|
|
283
|
+
.split('/')
|
|
284
|
+
.slice(-2)
|
|
285
|
+
.join('-')
|
|
286
|
+
.substring(0, 8);
|
|
287
|
+
|
|
288
|
+
return `${baseId}-${pathHash}`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Generate agent name from filename and description
|
|
293
|
+
* @param {string} fileName - File name
|
|
294
|
+
* @param {string} description - Description from help output
|
|
295
|
+
* @returns {string} - Generated agent name
|
|
296
|
+
*/
|
|
297
|
+
generateAgentName(fileName, description) {
|
|
298
|
+
// Use description if available, otherwise generate from filename
|
|
299
|
+
if (description && description.trim()) {
|
|
300
|
+
return description.trim();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Generate name from filename
|
|
304
|
+
const name = fileName
|
|
305
|
+
.replace(/\.(exe|sh|bat|cmd)$/g, '')
|
|
306
|
+
.replace(/-/g, ' ')
|
|
307
|
+
.split(' ')
|
|
308
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
309
|
+
.join(' ');
|
|
310
|
+
|
|
311
|
+
return name;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Determine agent capabilities from help output
|
|
316
|
+
* @param {string} filePath - Path to executable
|
|
317
|
+
* @param {string} helpOutput - Help output from executable
|
|
318
|
+
* @returns {Array} - Array of capabilities
|
|
319
|
+
*/
|
|
320
|
+
async determineCapabilities(filePath, helpOutput) {
|
|
321
|
+
const capabilities = [];
|
|
322
|
+
const fileName = path.basename(filePath).toLowerCase();
|
|
323
|
+
|
|
324
|
+
// Common CLI capabilities
|
|
325
|
+
if (helpOutput.includes('--check') || helpOutput.includes('check ')) {
|
|
326
|
+
capabilities.push('check');
|
|
327
|
+
}
|
|
328
|
+
if (helpOutput.includes('--install') || helpOutput.includes('install ')) {
|
|
329
|
+
capabilities.push('install');
|
|
330
|
+
}
|
|
331
|
+
if (helpOutput.includes('--verify') || helpOutput.includes('verify ')) {
|
|
332
|
+
capabilities.push('verify');
|
|
333
|
+
}
|
|
334
|
+
if (helpOutput.includes('--logs') || helpOutput.includes('logs ')) {
|
|
335
|
+
capabilities.push('logs');
|
|
336
|
+
}
|
|
337
|
+
if (helpOutput.includes('--status') || helpOutput.includes('status ')) {
|
|
338
|
+
capabilities.push('status');
|
|
339
|
+
}
|
|
340
|
+
if (helpOutput.includes('--update') || helpOutput.includes('update ')) {
|
|
341
|
+
capabilities.push('update');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// GUI-specific capabilities
|
|
345
|
+
if (fileName.includes('gui') || fileName.includes('window')) {
|
|
346
|
+
capabilities.push('gui');
|
|
347
|
+
}
|
|
348
|
+
if (fileName.includes('app')) {
|
|
349
|
+
capabilities.push('app-interface');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Add default capabilities based on file type
|
|
353
|
+
capabilities.push('help');
|
|
354
|
+
|
|
355
|
+
return capabilities;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Validate and deduplicate discovered agents
|
|
360
|
+
* @param {Array} agents - Discovered agents
|
|
361
|
+
* @returns {Array} - Valid, deduplicated agents
|
|
362
|
+
*/
|
|
363
|
+
async validateAndDeduplicateAgents(agents) {
|
|
364
|
+
const validAgents = [];
|
|
365
|
+
const seenIds = new Set();
|
|
366
|
+
const seenPaths = new Set();
|
|
367
|
+
|
|
368
|
+
for (const agent of agents) {
|
|
369
|
+
// Validate required fields
|
|
370
|
+
if (!agent.id || !agent.name || !agent.path) {
|
|
371
|
+
if (this.logger) {
|
|
372
|
+
await this.logger.warn('Invalid agent configuration: missing required fields', {
|
|
373
|
+
agent: agent.id || 'unknown'
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Check for duplicates
|
|
380
|
+
if (seenIds.has(agent.id)) {
|
|
381
|
+
if (this.logger) {
|
|
382
|
+
await this.logger.warn('Duplicate agent ID found: ' + agent.id);
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (seenPaths.has(agent.path)) {
|
|
388
|
+
if (this.logger) {
|
|
389
|
+
await this.logger.warn('Duplicate agent path found: ' + agent.path);
|
|
390
|
+
}
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Additional validation
|
|
395
|
+
if (agent.version === 'unknown') {
|
|
396
|
+
if (this.logger) {
|
|
397
|
+
await this.logger.warn(`Agent ${agent.id} has unknown version`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
validAgents.push(agent);
|
|
402
|
+
seenIds.add(agent.id);
|
|
403
|
+
seenPaths.add(agent.path);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return validAgents;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Add discovered agent to configuration
|
|
411
|
+
* @param {Object} agent - Agent to add
|
|
412
|
+
* @returns {Promise<Object>} - Addition result
|
|
413
|
+
*/
|
|
414
|
+
async addAgent(agent) {
|
|
415
|
+
try {
|
|
416
|
+
if (this.logger) {
|
|
417
|
+
await this.logger.info('Adding discovered agent to configuration', {
|
|
418
|
+
agentId: agent.id,
|
|
419
|
+
agentName: agent.name,
|
|
420
|
+
path: agent.path
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Validate agent before adding
|
|
425
|
+
const validation = this.validateAgent(agent);
|
|
426
|
+
if (!validation.valid) {
|
|
427
|
+
return {
|
|
428
|
+
success: false,
|
|
429
|
+
error: 'Invalid agent configuration: ' + validation.errors.join(', '),
|
|
430
|
+
agentId: agent.id
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Add to configuration manager
|
|
435
|
+
if (this.configManager) {
|
|
436
|
+
await this.configManager.addAgent(agent);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Record addition in history
|
|
440
|
+
await this.recordDiscoveryOperation('add', {
|
|
441
|
+
agentId: agent.id,
|
|
442
|
+
agentName: agent.name
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
success: true,
|
|
447
|
+
agentId: agent.id,
|
|
448
|
+
message: `Agent ${agent.name} added successfully`
|
|
449
|
+
};
|
|
450
|
+
} catch (error) {
|
|
451
|
+
if (this.logger) {
|
|
452
|
+
await this.logger.error('Failed to add agent', {
|
|
453
|
+
agentId: agent.id,
|
|
454
|
+
error: error.message
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
success: false,
|
|
460
|
+
error: error.message,
|
|
461
|
+
agentId: agent.id
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Remove agent from configuration
|
|
468
|
+
* @param {string} agentId - ID of agent to remove
|
|
469
|
+
* @returns {Promise<Object>} - Removal result
|
|
470
|
+
*/
|
|
471
|
+
async removeAgent(agentId) {
|
|
472
|
+
try {
|
|
473
|
+
if (this.logger) {
|
|
474
|
+
await this.logger.info('Removing agent from configuration', {
|
|
475
|
+
agentId
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Get agent info before removal
|
|
480
|
+
let agentInfo = null;
|
|
481
|
+
if (this.configManager) {
|
|
482
|
+
agentInfo = await this.configManager.getAgent(agentId);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (!agentInfo) {
|
|
486
|
+
return {
|
|
487
|
+
success: false,
|
|
488
|
+
error: 'Agent not found',
|
|
489
|
+
agentId
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Remove from configuration manager
|
|
494
|
+
if (this.configManager) {
|
|
495
|
+
await this.configManager.removeAgent(agentId);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Record removal in history
|
|
499
|
+
await this.recordDiscoveryOperation('remove', {
|
|
500
|
+
agentId,
|
|
501
|
+
agentName: agentInfo.name
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
return {
|
|
505
|
+
success: true,
|
|
506
|
+
agentId,
|
|
507
|
+
message: `Agent ${agentInfo.name} removed successfully`
|
|
508
|
+
};
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if (this.logger) {
|
|
511
|
+
await this.logger.error('Failed to remove agent', {
|
|
512
|
+
agentId,
|
|
513
|
+
error: error.message
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return {
|
|
518
|
+
success: false,
|
|
519
|
+
error: error.message,
|
|
520
|
+
agentId
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Validate agent configuration
|
|
527
|
+
* @param {Object} agent - Agent to validate
|
|
528
|
+
* @returns {Object} - Validation result
|
|
529
|
+
*/
|
|
530
|
+
validateAgent(agent) {
|
|
531
|
+
const errors = [];
|
|
532
|
+
|
|
533
|
+
// Check required fields
|
|
534
|
+
if (!agent.id || !agent.id.trim()) {
|
|
535
|
+
errors.push('Agent ID is required');
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (!agent.name || !agent.name.trim()) {
|
|
539
|
+
errors.push('Agent name is required');
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (!agent.path || !agent.path.trim()) {
|
|
543
|
+
errors.push('Agent path is required');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (!agent.version || !agent.version.trim()) {
|
|
547
|
+
errors.push('Agent version is required');
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (!agent.description || !agent.description.trim()) {
|
|
551
|
+
errors.push('Agent description is required');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (!agent.type || !['CLI', 'GUI'].includes(agent.type)) {
|
|
555
|
+
errors.push('Agent type must be CLI or GUI');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
valid: errors.length === 0,
|
|
560
|
+
errors
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Update discovery status file
|
|
566
|
+
* @param {Array} validAgents - Valid discovered agents
|
|
567
|
+
* @param {number} totalDiscovered - Total agents discovered
|
|
568
|
+
* @param {number} duplicateCount - Number of duplicates removed
|
|
569
|
+
* @param {Array} warnings - Discovery warnings
|
|
570
|
+
* @param {Array} errors - Discovery errors
|
|
571
|
+
*/
|
|
572
|
+
async updateDiscoveryStatus(validAgents, totalDiscovered, duplicateCount, warnings, errors) {
|
|
573
|
+
const status = {
|
|
574
|
+
lastDiscovery: new Date().toISOString(),
|
|
575
|
+
totalDiscovered,
|
|
576
|
+
validAgents,
|
|
577
|
+
duplicates: duplicateCount,
|
|
578
|
+
warnings,
|
|
579
|
+
errors,
|
|
580
|
+
discoveryPaths: this.discoveryPaths
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
if (this.fileManager) {
|
|
584
|
+
await this.fileManager.writeFile('discovery-status', JSON.stringify(status, null, 2));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (this.logger) {
|
|
588
|
+
await this.logger.info('Discovery status updated', {
|
|
589
|
+
totalDiscovered,
|
|
590
|
+
validAgents,
|
|
591
|
+
duplicates: duplicateCount
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Record discovery operation in history
|
|
598
|
+
* @param {string} operation - Operation type
|
|
599
|
+
* @param {Object} details - Operation details
|
|
600
|
+
*/
|
|
601
|
+
async recordDiscoveryOperation(operation, details) {
|
|
602
|
+
const historyEntry = {
|
|
603
|
+
timestamp: new Date().toISOString(),
|
|
604
|
+
operation,
|
|
605
|
+
...details
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
let history = [];
|
|
609
|
+
if (this.fileManager) {
|
|
610
|
+
try {
|
|
611
|
+
const historyData = await this.fileManager.readFile('discovery-history');
|
|
612
|
+
history = JSON.parse(historyData || '[]');
|
|
613
|
+
} catch (error) {
|
|
614
|
+
// File doesn't exist yet, start with empty history
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
history.push(historyEntry);
|
|
619
|
+
|
|
620
|
+
// Keep only last 100 entries
|
|
621
|
+
if (history.length > 100) {
|
|
622
|
+
history = history.slice(-100);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (this.fileManager) {
|
|
626
|
+
await this.fileManager.writeFile('discovery-history', JSON.stringify(history, null, 2));
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (this.logger) {
|
|
630
|
+
await this.logger.info('Discovery operation recorded', {
|
|
631
|
+
operation,
|
|
632
|
+
details
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Get discovery status
|
|
639
|
+
* @returns {Promise<Object>} - Discovery status
|
|
640
|
+
*/
|
|
641
|
+
async getDiscoveryStatus() {
|
|
642
|
+
try {
|
|
643
|
+
if (this.fileManager) {
|
|
644
|
+
const statusData = await this.fileManager.readFile('discovery-status');
|
|
645
|
+
return {
|
|
646
|
+
success: true,
|
|
647
|
+
status: JSON.parse(statusData || '{}')
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
} catch (error) {
|
|
651
|
+
return {
|
|
652
|
+
success: false,
|
|
653
|
+
error: 'Discovery status file not found'
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Get discovery history
|
|
660
|
+
* @returns {Promise<Object>} - Discovery history
|
|
661
|
+
*/
|
|
662
|
+
async getDiscoveryHistory() {
|
|
663
|
+
try {
|
|
664
|
+
if (this.fileManager) {
|
|
665
|
+
const historyData = await this.fileManager.readFile('discovery-history');
|
|
666
|
+
return {
|
|
667
|
+
success: true,
|
|
668
|
+
history: JSON.parse(historyData || '[]')
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
} catch (error) {
|
|
672
|
+
return {
|
|
673
|
+
success: false,
|
|
674
|
+
error: 'Discovery history file not found'
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Get service information
|
|
681
|
+
* @returns {Object} - Service info
|
|
682
|
+
*/
|
|
683
|
+
getInfo() {
|
|
684
|
+
return {
|
|
685
|
+
name: 'Agent Discovery Service',
|
|
686
|
+
version: '1.0.0',
|
|
687
|
+
discoveryPaths: this.discoveryPaths,
|
|
688
|
+
timeout: this.timeout,
|
|
689
|
+
maxConcurrency: this.maxConcurrency,
|
|
690
|
+
features: [
|
|
691
|
+
'filesystem discovery',
|
|
692
|
+
'executable analysis',
|
|
693
|
+
'version detection',
|
|
694
|
+
'capability detection',
|
|
695
|
+
'agent validation',
|
|
696
|
+
'deduplication',
|
|
697
|
+
'configuration integration',
|
|
698
|
+
'discovery history',
|
|
699
|
+
'status tracking',
|
|
700
|
+
'error handling',
|
|
701
|
+
'concurrent discovery'
|
|
702
|
+
]
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
module.exports = AgentDiscoveryService;
|