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.
Files changed (202) hide show
  1. package/README.md +240 -0
  2. package/package.json +10 -2
  3. package/src/agents/Agent.js +300 -0
  4. package/src/agents/AgentAdditionService.js +311 -0
  5. package/src/agents/AgentCheckService.js +690 -0
  6. package/src/agents/AgentInstallationService.js +140 -0
  7. package/src/agents/AgentSetupService.js +467 -0
  8. package/src/agents/AgentStatus.js +183 -0
  9. package/src/agents/AgentVerificationService.js +634 -0
  10. package/src/agents/ConfigurationSchemaValidator.js +543 -0
  11. package/src/agents/EnvironmentConfigurationManager.js +602 -0
  12. package/src/agents/InstallationErrorHandler.js +372 -0
  13. package/src/agents/InstallationLog.js +363 -0
  14. package/src/agents/InstallationMethod.js +510 -0
  15. package/src/agents/InstallationOrchestrator.js +352 -0
  16. package/src/agents/InstallationProgressReporter.js +372 -0
  17. package/src/agents/InstallationRetryManager.js +322 -0
  18. package/src/agents/InstallationType.js +254 -0
  19. package/src/agents/OperationTypes.js +310 -0
  20. package/src/agents/PerformanceMetricsCollector.js +493 -0
  21. package/src/agents/SecurityValidationService.js +534 -0
  22. package/src/agents/VerificationTest.js +354 -0
  23. package/src/agents/VerificationType.js +226 -0
  24. package/src/agents/WindowsPermissionHandler.js +518 -0
  25. package/src/agents/config/AgentConfigManager.js +393 -0
  26. package/src/agents/config/AgentDefaultsRegistry.js +373 -0
  27. package/src/agents/config/ConfigValidator.js +281 -0
  28. package/src/agents/discovery/AgentDiscoveryService.js +707 -0
  29. package/src/agents/logging/AgentLogger.js +511 -0
  30. package/src/agents/status/AgentStatusManager.js +481 -0
  31. package/src/agents/storage/FileManager.js +454 -0
  32. package/src/agents/verification/AgentCommunicationTester.js +474 -0
  33. package/src/agents/verification/BaseVerifier.js +430 -0
  34. package/src/agents/verification/CommandVerifier.js +480 -0
  35. package/src/agents/verification/FileOperationVerifier.js +453 -0
  36. package/src/agents/verification/ResultAnalyzer.js +707 -0
  37. package/src/agents/verification/TestRequirementManager.js +495 -0
  38. package/src/agents/verification/VerificationRunner.js +433 -0
  39. package/src/agents/windows/BaseWindowsInstaller.js +441 -0
  40. package/src/agents/windows/ChocolateyInstaller.js +509 -0
  41. package/src/agents/windows/DirectInstaller.js +443 -0
  42. package/src/agents/windows/InstallerFactory.js +391 -0
  43. package/src/agents/windows/NpmInstaller.js +505 -0
  44. package/src/agents/windows/PowerShellInstaller.js +458 -0
  45. package/src/agents/windows/WinGetInstaller.js +390 -0
  46. package/src/analysis/analysis-reporter.js +132 -0
  47. package/src/analysis/boundary-detector.js +712 -0
  48. package/src/analysis/categorizer.js +340 -0
  49. package/src/analysis/codebase-scanner.js +384 -0
  50. package/src/analysis/line-counter.js +513 -0
  51. package/src/analysis/priority-calculator.js +679 -0
  52. package/src/analysis/report/analysis-report.js +250 -0
  53. package/src/analysis/report/package-analyzer.js +278 -0
  54. package/src/analysis/report/recommendation-generator.js +382 -0
  55. package/src/analysis/report/statistics-generator.js +515 -0
  56. package/src/analysis/reports/analysis-report-model.js +101 -0
  57. package/src/analysis/reports/recommendation-generator.js +283 -0
  58. package/src/analysis/reports/report-generators.js +191 -0
  59. package/src/analysis/reports/statistics-calculator.js +231 -0
  60. package/src/analysis/reports/trend-analyzer.js +219 -0
  61. package/src/analysis/strategy-generator.js +814 -0
  62. package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
  63. package/src/config/refactoring-config.js +307 -0
  64. package/src/health-tracking/json-storage.js +38 -2
  65. package/src/ide-integration/applescript-manager-core.js +233 -0
  66. package/src/ide-integration/applescript-manager.cjs +357 -28
  67. package/src/ide-integration/applescript-manager.js +89 -3599
  68. package/src/ide-integration/cdp-manager.js +306 -0
  69. package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
  70. package/src/ide-integration/continuation-handler.js +337 -0
  71. package/src/ide-integration/ide-status-checker.js +292 -0
  72. package/src/ide-integration/macos-ide-manager.js +627 -0
  73. package/src/ide-integration/macos-text-sender.js +528 -0
  74. package/src/ide-integration/response-reader.js +548 -0
  75. package/src/ide-integration/windows-automation-manager.js +121 -0
  76. package/src/ide-integration/windows-ide-manager.js +373 -0
  77. package/src/index.cjs +25 -3
  78. package/src/index.js +15 -1
  79. package/src/llm/direct-llm-manager.cjs +90 -2
  80. package/src/models/compliance-report.js +538 -0
  81. package/src/models/file-analysis.js +681 -0
  82. package/src/models/refactoring-plan.js +770 -0
  83. package/src/monitoring/alert-system.js +834 -0
  84. package/src/monitoring/compliance-progress-tracker.js +437 -0
  85. package/src/monitoring/continuous-scan-notifications.js +661 -0
  86. package/src/monitoring/continuous-scanner.js +279 -0
  87. package/src/monitoring/file-monitor/file-analyzer.js +262 -0
  88. package/src/monitoring/file-monitor/file-monitor.js +237 -0
  89. package/src/monitoring/file-monitor/watcher.js +194 -0
  90. package/src/monitoring/file-monitor.js +17 -0
  91. package/src/monitoring/notification-manager.js +437 -0
  92. package/src/monitoring/scanner-core.js +368 -0
  93. package/src/monitoring/scanner-events.js +214 -0
  94. package/src/monitoring/violation-notification-system.js +515 -0
  95. package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
  96. package/src/refactoring/boundaries/extraction-result.js +285 -0
  97. package/src/refactoring/boundaries/extraction-strategies.js +392 -0
  98. package/src/refactoring/boundaries/module-boundary.js +209 -0
  99. package/src/refactoring/boundary/boundary-detector.js +741 -0
  100. package/src/refactoring/boundary/boundary-types.js +405 -0
  101. package/src/refactoring/boundary/extraction-strategies.js +554 -0
  102. package/src/refactoring/boundary-extraction-result.js +77 -0
  103. package/src/refactoring/boundary-extraction-strategies.js +330 -0
  104. package/src/refactoring/boundary-extractor.js +384 -0
  105. package/src/refactoring/boundary-types.js +46 -0
  106. package/src/refactoring/circular/circular-dependency.js +88 -0
  107. package/src/refactoring/circular/cycle-detection.js +147 -0
  108. package/src/refactoring/circular/dependency-node.js +82 -0
  109. package/src/refactoring/circular/dependency-result.js +107 -0
  110. package/src/refactoring/circular/dependency-types.js +58 -0
  111. package/src/refactoring/circular/graph-builder.js +213 -0
  112. package/src/refactoring/circular/resolution-strategy.js +72 -0
  113. package/src/refactoring/circular/strategy-generator.js +229 -0
  114. package/src/refactoring/circular-dependency-resolver-original.js +809 -0
  115. package/src/refactoring/circular-dependency-resolver.js +200 -0
  116. package/src/refactoring/code-mover.js +761 -0
  117. package/src/refactoring/file-splitter.js +696 -0
  118. package/src/refactoring/functionality-validator.js +816 -0
  119. package/src/refactoring/import-manager.js +774 -0
  120. package/src/refactoring/module-boundary.js +107 -0
  121. package/src/refactoring/refactoring-executor.js +672 -0
  122. package/src/refactoring/refactoring-rollback.js +614 -0
  123. package/src/refactoring/test-validator.js +631 -0
  124. package/src/requirement-management/default-requirement-manager.js +321 -0
  125. package/src/requirement-management/requirement-file-parser.js +159 -0
  126. package/src/requirement-management/requirement-sequencer.js +221 -0
  127. package/src/rui/commands/AgentCommandParser.js +600 -0
  128. package/src/rui/commands/AgentCommands.js +487 -0
  129. package/src/rui/commands/AgentResponseFormatter.js +832 -0
  130. package/src/scripts/verify-full-compliance.js +269 -0
  131. package/src/sync/sync-engine-core.js +1 -0
  132. package/src/sync/sync-engine-remote-handlers.js +135 -0
  133. package/src/task-generation/automated-task-generator.js +351 -0
  134. package/src/task-generation/prioritizer.js +287 -0
  135. package/src/task-generation/task-list-updater.js +215 -0
  136. package/src/task-generation/task-management-integration.js +480 -0
  137. package/src/task-generation/task-manager-integration.js +270 -0
  138. package/src/task-generation/violation-task-generator.js +474 -0
  139. package/src/task-management/continuous-scan-integration.js +342 -0
  140. package/src/timeout-management/index.js +12 -3
  141. package/src/timeout-management/response-time-tracker.js +167 -0
  142. package/src/timeout-management/timeout-calculator.js +159 -0
  143. package/src/timeout-management/timeout-config-manager.js +172 -0
  144. package/src/utils/ast-analyzer.js +417 -0
  145. package/src/utils/current-requirement-manager.js +276 -0
  146. package/src/utils/current-requirement-operations.js +472 -0
  147. package/src/utils/dependency-mapper.js +456 -0
  148. package/src/utils/download-with-progress.js +4 -2
  149. package/src/utils/electron-update-checker.js +4 -1
  150. package/src/utils/file-size-analyzer.js +272 -0
  151. package/src/utils/import-updater.js +280 -0
  152. package/src/utils/refactoring-tools.js +512 -0
  153. package/src/utils/report-generator.js +569 -0
  154. package/src/utils/reports/report-analysis.js +218 -0
  155. package/src/utils/reports/report-types.js +55 -0
  156. package/src/utils/reports/summary-generators.js +102 -0
  157. package/src/utils/requirement-file-management.js +157 -0
  158. package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
  159. package/src/utils/requirement-helpers/requirement-mover.js +414 -0
  160. package/src/utils/requirement-helpers/requirement-parser.js +326 -0
  161. package/src/utils/requirement-helpers/requirement-status.js +320 -0
  162. package/src/utils/requirement-helpers-new.js +55 -0
  163. package/src/utils/requirement-helpers-refactored.js +367 -0
  164. package/src/utils/requirement-helpers.js +291 -1191
  165. package/src/utils/requirement-movement-operations.js +450 -0
  166. package/src/utils/requirement-movement.js +312 -0
  167. package/src/utils/requirement-parsing-helpers.js +56 -0
  168. package/src/utils/requirement-statistics.js +200 -0
  169. package/src/utils/requirement-text-utils.js +58 -0
  170. package/src/utils/rollback/rollback-handlers.js +125 -0
  171. package/src/utils/rollback/rollback-operation.js +63 -0
  172. package/src/utils/rollback/rollback-recorder.js +166 -0
  173. package/src/utils/rollback/rollback-state-manager.js +175 -0
  174. package/src/utils/rollback/rollback-types.js +33 -0
  175. package/src/utils/rollback/rollback-utils.js +110 -0
  176. package/src/utils/rollback-manager-original.js +569 -0
  177. package/src/utils/rollback-manager.js +202 -0
  178. package/src/utils/smoke-test-cli.js +362 -0
  179. package/src/utils/smoke-test-gui.js +351 -0
  180. package/src/utils/smoke-test-orchestrator.js +321 -0
  181. package/src/utils/smoke-test-runner.js +60 -0
  182. package/src/utils/smoke-test-web.js +347 -0
  183. package/src/utils/specification-helpers.js +39 -13
  184. package/src/utils/specification-migration.js +97 -0
  185. package/src/utils/test-runner.js +579 -0
  186. package/src/utils/validation-framework.js +518 -0
  187. package/src/validation/compliance-analyzer.js +197 -0
  188. package/src/validation/compliance-report-generator.js +343 -0
  189. package/src/validation/compliance-reporter.js +711 -0
  190. package/src/validation/compliance-rules.js +127 -0
  191. package/src/validation/constitution-validator-new.js +196 -0
  192. package/src/validation/constitution-validator.js +17 -0
  193. package/src/validation/file-validators.js +170 -0
  194. package/src/validation/line-limit/file-analyzer.js +201 -0
  195. package/src/validation/line-limit/line-limit-validator.js +208 -0
  196. package/src/validation/line-limit/validation-result.js +144 -0
  197. package/src/validation/line-limit-core.js +225 -0
  198. package/src/validation/line-limit-reporter.js +134 -0
  199. package/src/validation/line-limit-result.js +125 -0
  200. package/src/validation/line-limit-validator.js +41 -0
  201. package/src/validation/metrics-calculator.js +660 -0
  202. 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;