stigmergy 1.2.13 → 1.3.2-beta.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.
- package/README.md +39 -3
- package/STIGMERGY.md +3 -0
- package/config/enhanced-cli-config.json +438 -0
- package/docs/CLI_TOOLS_AGENT_SKILL_ANALYSIS.md +463 -0
- package/docs/ENHANCED_CLI_AGENT_SKILL_CONFIG.md +285 -0
- package/docs/INSTALLER_ARCHITECTURE.md +257 -0
- package/docs/SUDO_PROBLEM_AND_SOLUTION.md +529 -0
- package/package.json +16 -5
- package/scripts/analyze-router.js +168 -0
- package/scripts/run-comprehensive-tests.js +230 -0
- package/scripts/run-quick-tests.js +90 -0
- package/scripts/test-runner.js +344 -0
- package/src/cli/commands/autoinstall.js +158 -0
- package/src/cli/commands/errors.js +190 -0
- package/src/cli/commands/install.js +142 -0
- package/src/cli/commands/permissions.js +108 -0
- package/src/cli/commands/project.js +449 -0
- package/src/cli/commands/resume.js +136 -0
- package/src/cli/commands/scan.js +97 -0
- package/src/cli/commands/skills.js +158 -0
- package/src/cli/commands/status.js +106 -0
- package/src/cli/commands/system.js +301 -0
- package/src/cli/router-beta.js +477 -0
- package/src/cli/utils/environment.js +75 -0
- package/src/cli/utils/formatters.js +47 -0
- package/src/cli/utils/skills_cache.js +92 -0
- package/src/core/cache_cleaner.js +1 -0
- package/src/core/cli_adapters.js +345 -0
- package/src/core/cli_help_analyzer.js +473 -1
- package/src/core/cli_path_detector.js +2 -1
- package/src/core/cli_tools.js +107 -0
- package/src/core/coordination/nodejs/HookDeploymentManager.js +204 -416
- package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
- package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
- package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +703 -0
- package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1210 -0
- package/src/core/coordination/nodejs/generators/index.js +12 -0
- package/src/core/enhanced_cli_installer.js +375 -31
- package/src/core/enhanced_cli_parameter_handler.js +395 -0
- package/src/core/execution_mode_detector.js +222 -0
- package/src/core/installer.js +83 -67
- package/src/core/local_skill_scanner.js +732 -0
- package/src/core/multilingual/language-pattern-manager.js +1 -1
- package/src/core/skills/StigmergySkillManager.js +26 -8
- package/src/core/smart_router.js +279 -2
- package/src/index.js +10 -4
- package/test/cli-integration.test.js +304 -0
- package/test/enhanced-cli-agent-skill-test.js +485 -0
- package/test/specific-cli-agent-skill-analysis.js +385 -0
- package/src/cli/router.js +0 -1783
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stigmergy CLI - Modular Router
|
|
5
|
+
* Multi-Agents Cross-AI CLI Tools Collaboration System
|
|
6
|
+
* Modular implementation with separated concerns
|
|
7
|
+
* Version: 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Core imports
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const { Command } = require('commander');
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
|
|
16
|
+
// Import CLI tools configuration
|
|
17
|
+
const { CLI_TOOLS } = require('../core/cli_tools');
|
|
18
|
+
|
|
19
|
+
// Import modular components
|
|
20
|
+
const { formatBytes } = require('./utils/formatters');
|
|
21
|
+
const { getWorkingDirectoryForTool, getEnvironmentForTool } = require('./utils/environment');
|
|
22
|
+
|
|
23
|
+
// Import execution mode detection and CLI adapters
|
|
24
|
+
const ExecutionModeDetector = require('../core/execution_mode_detector');
|
|
25
|
+
const { CLIAdapterManager } = require('../core/cli_adapters');
|
|
26
|
+
|
|
27
|
+
// Create instances
|
|
28
|
+
const modeDetector = new ExecutionModeDetector();
|
|
29
|
+
const cliAdapterManager = new CLIAdapterManager();
|
|
30
|
+
const { handleInstallCommand } = require('./commands/install');
|
|
31
|
+
const { handleStatusCommand } = require('./commands/status');
|
|
32
|
+
const { handleScanCommand } = require('./commands/scan');
|
|
33
|
+
const { handlePermCheckCommand, handleFixPermsCommand } = require('./commands/permissions');
|
|
34
|
+
const { handleDiagnosticCommand, handleCleanCommand } = require('./commands/system');
|
|
35
|
+
const { handleSkillMainCommand, printSkillsHelp } = require('./commands/skills');
|
|
36
|
+
const { handleErrorsCommand } = require('./commands/errors');
|
|
37
|
+
const { handleAutoInstallCommand } = require('./commands/autoinstall');
|
|
38
|
+
const { handleResumeCommand, printResumeHelp } = require('./commands/resume');
|
|
39
|
+
const { getCLIPath } = require('../core/cli_tools');
|
|
40
|
+
const {
|
|
41
|
+
handleUpgradeCommand,
|
|
42
|
+
handleDeployCommand,
|
|
43
|
+
handleInitCommand,
|
|
44
|
+
handleSetupCommand,
|
|
45
|
+
handleCallCommand
|
|
46
|
+
} = require('./commands/project');
|
|
47
|
+
const SmartRouter = require('../core/smart_router');
|
|
48
|
+
const { errorHandler } = require('../core/error_handler');
|
|
49
|
+
const { executeCommand } = require('../utils');
|
|
50
|
+
const { setupGlobalErrorHandlers } = require('../core/error_handler');
|
|
51
|
+
|
|
52
|
+
// Set up global error handlers
|
|
53
|
+
setupGlobalErrorHandlers();
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Add OAuth authentication arguments to command
|
|
57
|
+
* @param {Command} command - Commander command instance
|
|
58
|
+
* @returns {Command} Command with OAuth args added
|
|
59
|
+
*/
|
|
60
|
+
function addOAuthAuthArgsCommand(command) {
|
|
61
|
+
return command
|
|
62
|
+
.option('--client-id <id>', 'OAuth client ID')
|
|
63
|
+
.option('--client-secret <secret>', 'OAuth client secret')
|
|
64
|
+
.option('--access-token <token>', 'OAuth access token')
|
|
65
|
+
.option('--auth-url <url>', 'OAuth authentication URL');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Add OAuth authentication arguments to command args for execution
|
|
70
|
+
* @param {string} toolName - Name of the CLI tool
|
|
71
|
+
* @param {Array} args - Current arguments array
|
|
72
|
+
* @returns {Array} Arguments with OAuth auth added
|
|
73
|
+
*/
|
|
74
|
+
function addOAuthAuthArgs(toolName, args = []) {
|
|
75
|
+
const toolConfig = CLI_TOOLS[toolName];
|
|
76
|
+
|
|
77
|
+
if (toolConfig && toolConfig.oauth) {
|
|
78
|
+
const oauth = toolConfig.oauth;
|
|
79
|
+
if (oauth.authRequired) {
|
|
80
|
+
// Qwen-specific OAuth handling
|
|
81
|
+
if (toolName === 'qwen' && process.env.QWEN_ACCESS_TOKEN) {
|
|
82
|
+
return [...args, '--access-token', process.env.QWEN_ACCESS_TOKEN];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return args;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Main CLI router function
|
|
92
|
+
*/
|
|
93
|
+
async function main() {
|
|
94
|
+
const program = new Command();
|
|
95
|
+
|
|
96
|
+
// Program setup
|
|
97
|
+
program
|
|
98
|
+
.version('1.3.0-beta.0')
|
|
99
|
+
.description('Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System')
|
|
100
|
+
.name('stigmergy');
|
|
101
|
+
|
|
102
|
+
// Version command (override the built-in --version)
|
|
103
|
+
program
|
|
104
|
+
.command('version')
|
|
105
|
+
.description('Show version information')
|
|
106
|
+
.action(() => {
|
|
107
|
+
const packageJson = require('../../package.json');
|
|
108
|
+
console.log(`Stigmergy CLI v${packageJson.version}`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Error reporting command
|
|
112
|
+
program
|
|
113
|
+
.command('errors')
|
|
114
|
+
.description('Generate comprehensive error report')
|
|
115
|
+
.option('--save', 'Save report to file')
|
|
116
|
+
.option('-v, --verbose', 'Verbose output')
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
await handleErrorsCommand(options);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Install command
|
|
122
|
+
program
|
|
123
|
+
.command('install')
|
|
124
|
+
.alias('inst')
|
|
125
|
+
.description('Install CLI tools')
|
|
126
|
+
.option('-c, --cli <cli>', 'Install specific CLI tool')
|
|
127
|
+
.option('-v, --verbose', 'Verbose output')
|
|
128
|
+
.option('-f, --force', 'Force installation')
|
|
129
|
+
.action(async (options) => {
|
|
130
|
+
await handleInstallCommand(options);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Project management commands
|
|
134
|
+
program
|
|
135
|
+
.command('upgrade')
|
|
136
|
+
.description('Upgrade AI CLI tools to latest versions')
|
|
137
|
+
.option('--dry-run', 'Show what would be upgraded without actually upgrading')
|
|
138
|
+
.option('-f, --force', 'Force upgrade')
|
|
139
|
+
.option('-v, --verbose', 'Verbose output')
|
|
140
|
+
.action(async (options) => {
|
|
141
|
+
await handleUpgradeCommand(options);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
program
|
|
145
|
+
.command('deploy')
|
|
146
|
+
.description('Deploy integration hooks to CLI tools')
|
|
147
|
+
.option('-v, --verbose', 'Verbose output')
|
|
148
|
+
.action(async (options) => {
|
|
149
|
+
await handleDeployCommand(options);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
program
|
|
153
|
+
.command('init')
|
|
154
|
+
.description('Initialize Stigmergy project in current directory')
|
|
155
|
+
.option('-v, --verbose', 'Verbose output')
|
|
156
|
+
.action(async (options) => {
|
|
157
|
+
await handleInitCommand(options);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
program
|
|
161
|
+
.command('setup')
|
|
162
|
+
.description('Complete Stigmergy setup (install + deploy + init)')
|
|
163
|
+
.option('-v, --verbose', 'Verbose output')
|
|
164
|
+
.action(async (options) => {
|
|
165
|
+
await handleSetupCommand(options);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
program
|
|
169
|
+
.command('call')
|
|
170
|
+
.description('Smart AI tool routing based on prompt')
|
|
171
|
+
.argument('<prompt>', 'Prompt to process with smart routing')
|
|
172
|
+
.option('-i, --interactive', 'Run in interactive mode (continuous conversation)')
|
|
173
|
+
.option('-p, --print', 'Run in one-time mode (print and exit)')
|
|
174
|
+
.option('-v, --verbose', 'Verbose output')
|
|
175
|
+
.action(async (prompt, options) => {
|
|
176
|
+
await handleCallCommand(prompt, options);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Status command
|
|
180
|
+
program
|
|
181
|
+
.command('status')
|
|
182
|
+
.description('Check CLI tools status')
|
|
183
|
+
.option('-c, --cli <cli>', 'Check status of specific CLI tool')
|
|
184
|
+
.option('--json', 'Output in JSON format')
|
|
185
|
+
.option('-v, --verbose', 'Verbose output')
|
|
186
|
+
.action(async (options) => {
|
|
187
|
+
await handleStatusCommand(options);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Scan command
|
|
191
|
+
program
|
|
192
|
+
.command('scan')
|
|
193
|
+
.description('Scan for available CLI tools')
|
|
194
|
+
.option('-d, --deep', 'Deep scan for CLI tools')
|
|
195
|
+
.option('--json', 'Output in JSON format')
|
|
196
|
+
.option('-v, --verbose', 'Verbose output')
|
|
197
|
+
.action(async (options) => {
|
|
198
|
+
await handleScanCommand(options);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Permission management commands
|
|
202
|
+
program
|
|
203
|
+
.command('fix-perms')
|
|
204
|
+
.description('Fix directory permissions automatically')
|
|
205
|
+
.option('-v, --verbose', 'Verbose output')
|
|
206
|
+
.action(async (options) => {
|
|
207
|
+
await handleFixPermsCommand(options);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
program
|
|
211
|
+
.command('perm-check')
|
|
212
|
+
.description('Check directory permissions')
|
|
213
|
+
.option('-v, --verbose', 'Verbose output')
|
|
214
|
+
.action(async (options) => {
|
|
215
|
+
await handlePermCheckCommand(options);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// System commands
|
|
219
|
+
program
|
|
220
|
+
.command('clean')
|
|
221
|
+
.alias('c')
|
|
222
|
+
.description('Intelligent cache cleaning')
|
|
223
|
+
.option('--dry-run', 'Show what would be cleaned without actually cleaning')
|
|
224
|
+
.option('-q, --quiet', 'Suppress detailed output, show only summary')
|
|
225
|
+
.option('-v, --verbose', 'Verbose output (show permission errors)')
|
|
226
|
+
.action(async (options) => {
|
|
227
|
+
await handleCleanCommand(options);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
program
|
|
231
|
+
.command('diagnostic')
|
|
232
|
+
.aliases(['diag', 'd'])
|
|
233
|
+
.description('System diagnostic')
|
|
234
|
+
.option('-v, --verbose', 'Verbose output')
|
|
235
|
+
.action(async (options) => {
|
|
236
|
+
await handleDiagnosticCommand(options);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Skills management commands
|
|
240
|
+
program
|
|
241
|
+
.command('skill')
|
|
242
|
+
.description('Skills management system')
|
|
243
|
+
.argument('[subcommand]', 'Skill subcommand (install/list/read/validate/remove/sync)')
|
|
244
|
+
.argument('[args...]', 'Additional arguments')
|
|
245
|
+
.option('-v, --verbose', 'Verbose output')
|
|
246
|
+
.option('-f, --force', 'Force operation')
|
|
247
|
+
.option('--no-auto-sync', 'Disable auto-sync')
|
|
248
|
+
.action(async (subcommand, args, options) => {
|
|
249
|
+
if (!subcommand) {
|
|
250
|
+
printSkillsHelp();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
await handleSkillMainCommand(subcommand, args, options);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Skill command aliases (shortcuts)
|
|
257
|
+
program
|
|
258
|
+
.command('skill-i')
|
|
259
|
+
.description('Install a skill (alias for: skill install)')
|
|
260
|
+
.argument('<source>', 'Skill source to install')
|
|
261
|
+
.option('-v, --verbose', 'Verbose output')
|
|
262
|
+
.action(async (source, options) => {
|
|
263
|
+
await handleSkillMainCommand('install', [source], options);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
program
|
|
267
|
+
.command('skill-l')
|
|
268
|
+
.description('List installed skills (alias for: skill list)')
|
|
269
|
+
.option('-v, --verbose', 'Verbose output')
|
|
270
|
+
.action(async (options) => {
|
|
271
|
+
await handleSkillMainCommand('list', [], options);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
program
|
|
275
|
+
.command('skill-r')
|
|
276
|
+
.description('Read a skill (alias for: skill read)')
|
|
277
|
+
.argument('<skill-name>', 'Name of skill to read')
|
|
278
|
+
.option('-v, --verbose', 'Verbose output')
|
|
279
|
+
.action(async (skillName, options) => {
|
|
280
|
+
await handleSkillMainCommand('read', [skillName], options);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
program
|
|
284
|
+
.command('skill-v')
|
|
285
|
+
.description('Validate/read skill (alias for: skill validate/read)')
|
|
286
|
+
.argument('<path-or-name>', 'Path to validate or skill name to read')
|
|
287
|
+
.option('-v, --verbose', 'Verbose output')
|
|
288
|
+
.action(async (pathOrName, options) => {
|
|
289
|
+
await handleSkillMainCommand('validate', [pathOrName], options);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
program
|
|
293
|
+
.command('skill-d')
|
|
294
|
+
.description('Remove a skill (alias for: skill remove)')
|
|
295
|
+
.argument('<skill-name>', 'Name of skill to remove')
|
|
296
|
+
.option('-v, --verbose', 'Verbose output')
|
|
297
|
+
.option('-f, --force', 'Force removal')
|
|
298
|
+
.action(async (skillName, options) => {
|
|
299
|
+
await handleSkillMainCommand('remove', [skillName], options);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
program
|
|
303
|
+
.command('skill-m')
|
|
304
|
+
.description('Remove a skill (移除 alias for: skill remove)')
|
|
305
|
+
.argument('<skill-name>', 'Name of skill to remove')
|
|
306
|
+
.option('-v, --verbose', 'Verbose output')
|
|
307
|
+
.option('-f, --force', 'Force removal')
|
|
308
|
+
.action(async (skillName, options) => {
|
|
309
|
+
await handleSkillMainCommand('remove', [skillName], options);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Auto-install command (for npm postinstall)
|
|
313
|
+
program
|
|
314
|
+
.command('auto-install')
|
|
315
|
+
.description('Automated installation for npm postinstall')
|
|
316
|
+
.option('-v, --verbose', 'Verbose output')
|
|
317
|
+
.option('-f, --force', 'Force installation')
|
|
318
|
+
.action(async (options) => {
|
|
319
|
+
await handleAutoInstallCommand(options);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Resume session commands
|
|
323
|
+
program
|
|
324
|
+
.command('resume')
|
|
325
|
+
.description('Resume session (forwards to @stigmergy/resume CLI tool)')
|
|
326
|
+
.argument('[args...]', 'Arguments to pass to resumesession')
|
|
327
|
+
.option('-v, --verbose', 'Verbose output')
|
|
328
|
+
.action(async (args, options) => {
|
|
329
|
+
await handleResumeCommand(args, options);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
program
|
|
333
|
+
.command('resumesession')
|
|
334
|
+
.description('Resume session management (forwards to @stigmergy/resume)')
|
|
335
|
+
.argument('[args...]', 'Arguments to pass to resumesession')
|
|
336
|
+
.option('-v, --verbose', 'Verbose output')
|
|
337
|
+
.action(async (args, options) => {
|
|
338
|
+
await handleResumeCommand(args, options);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
program
|
|
342
|
+
.command('sg-resume')
|
|
343
|
+
.description('Resume session management (short alias)')
|
|
344
|
+
.argument('[args...]', 'Arguments to pass to resumesession')
|
|
345
|
+
.option('-v, --verbose', 'Verbose output')
|
|
346
|
+
.action(async (args, options) => {
|
|
347
|
+
await handleResumeCommand(args, options);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Route commands to CLI tools
|
|
351
|
+
for (const tool of ['claude', 'gemini', 'qwen', 'codebuddy', 'codex', 'iflow', 'qodercli', 'copilot', 'kode']) {
|
|
352
|
+
program
|
|
353
|
+
.command(tool)
|
|
354
|
+
.description(`Use ${tool} CLI tool`)
|
|
355
|
+
.option('-i, --interactive', 'Run in interactive mode (continuous conversation)')
|
|
356
|
+
.option('-p, --print', 'Run in one-time mode (print and exit)')
|
|
357
|
+
.allowUnknownOption(true)
|
|
358
|
+
.action(async (options, command) => {
|
|
359
|
+
try {
|
|
360
|
+
// Get the tool path directly (we know the tool name)
|
|
361
|
+
const toolPath = await getCLIPath(tool);
|
|
362
|
+
|
|
363
|
+
if (toolPath) {
|
|
364
|
+
// Join args to form the prompt
|
|
365
|
+
const prompt = command.args.join(' ');
|
|
366
|
+
|
|
367
|
+
if (process.env.DEBUG === 'true') {
|
|
368
|
+
console.log(`[DEBUG] Tool path: ${toolPath}`);
|
|
369
|
+
console.log(`[DEBUG] Prompt: ${prompt}`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Detect execution mode
|
|
373
|
+
const mode = modeDetector.detect({
|
|
374
|
+
interactive: options.interactive,
|
|
375
|
+
print: options.print,
|
|
376
|
+
verbose: process.env.DEBUG === 'true'
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const modeDescription = modeDetector.getModeDescription(mode);
|
|
380
|
+
if (process.env.DEBUG === 'true' || options.interactive || options.print) {
|
|
381
|
+
console.log(chalk.gray(`[MODE] ${modeDescription}`));
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Use CLI adapter to get appropriate arguments for the tool and mode
|
|
385
|
+
const adaptedArgs = cliAdapterManager.getArguments(tool, mode, prompt);
|
|
386
|
+
|
|
387
|
+
if (process.env.DEBUG === 'true') {
|
|
388
|
+
console.log(`[DEBUG] Adapted args for ${tool} (${mode}): ${adaptedArgs.join(' ')}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Use enhanced parameter handling for intelligent argument generation
|
|
392
|
+
let toolArgs = adaptedArgs; // Start with adapted args
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
if (process.env.DEBUG === 'true') {
|
|
396
|
+
console.log('[DEBUG] Initializing parameter handler...');
|
|
397
|
+
}
|
|
398
|
+
const EnhancedCLIParameterHandler = require('../core/enhanced_cli_parameter_handler');
|
|
399
|
+
const paramHandler = new EnhancedCLIParameterHandler();
|
|
400
|
+
|
|
401
|
+
// Generate optimized arguments with agent/skill support
|
|
402
|
+
// Skip for interactive mode to avoid double-processing
|
|
403
|
+
if (mode === 'one-time') {
|
|
404
|
+
const paramResult = await paramHandler.generateArgumentsWithRetry(
|
|
405
|
+
tool,
|
|
406
|
+
prompt,
|
|
407
|
+
{
|
|
408
|
+
maxRetries: 3,
|
|
409
|
+
enableAgentSkillOptimization: true
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
toolArgs = paramResult.arguments;
|
|
414
|
+
|
|
415
|
+
if (process.env.DEBUG === 'true') {
|
|
416
|
+
console.log(`[DEBUG] Generated args: ${toolArgs.join(' ')}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
} catch (paramError) {
|
|
420
|
+
// Fallback to adapted args if parameter handler fails
|
|
421
|
+
if (process.env.DEBUG === 'true') {
|
|
422
|
+
console.log(chalk.yellow(`[WARN] Parameter handler failed, using adapted args: ${paramError.message}`));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Add OAuth authentication if needed
|
|
427
|
+
toolArgs = addOAuthAuthArgs(tool, toolArgs);
|
|
428
|
+
|
|
429
|
+
console.log(chalk.gray(`[EXEC] ${tool}: ${prompt}`));
|
|
430
|
+
|
|
431
|
+
// Set up environment for the tool
|
|
432
|
+
const toolEnv = getEnvironmentForTool(tool);
|
|
433
|
+
const workingDir = getWorkingDirectoryForTool(tool);
|
|
434
|
+
|
|
435
|
+
const result = await executeCommand(toolPath, toolArgs, {
|
|
436
|
+
stdio: 'inherit',
|
|
437
|
+
shell: true,
|
|
438
|
+
cwd: workingDir,
|
|
439
|
+
env: toolEnv
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
if (!result.success) {
|
|
443
|
+
console.log(chalk.yellow(`[WARN] ${tool} exited with code ${result.code}`));
|
|
444
|
+
}
|
|
445
|
+
process.exit(result.code || 0);
|
|
446
|
+
} else {
|
|
447
|
+
console.log(chalk.red(`[ERROR] Could not find ${tool}`));
|
|
448
|
+
console.log(chalk.yellow('[INFO] Make sure the tool is installed: stigmergy install'));
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
} catch (error) {
|
|
452
|
+
if (process.env.DEBUG === 'true') {
|
|
453
|
+
console.log(chalk.red(`[ERROR] Exception: ${error.message}`));
|
|
454
|
+
console.log(chalk.red(error.stack));
|
|
455
|
+
}
|
|
456
|
+
const cliError = await errorHandler.handleCLIError(tool, error, command.args.join(' '));
|
|
457
|
+
console.log(chalk.red(`[ERROR] Failed to execute ${tool}:`));
|
|
458
|
+
console.log(chalk.red(cliError.message));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Add OAuth arguments for OAuth-enabled tools
|
|
465
|
+
const oauthTools = ['gemini', 'claude']; // Tools that support OAuth
|
|
466
|
+
oauthTools.forEach(tool => {
|
|
467
|
+
const cmd = program.commands.find(c => c.name() === tool);
|
|
468
|
+
if (cmd) {
|
|
469
|
+
addOAuthAuthArgsCommand(cmd);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Parse command line arguments
|
|
474
|
+
program.parse(process.argv);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
module.exports = main;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Environment Module
|
|
3
|
+
* Contains environment and working directory management
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get appropriate working directory for CLI tools
|
|
11
|
+
* @param {string} toolName - Name of the CLI tool
|
|
12
|
+
* @returns {string} Working directory path
|
|
13
|
+
*/
|
|
14
|
+
function getWorkingDirectoryForTool(toolName) {
|
|
15
|
+
switch (toolName) {
|
|
16
|
+
case 'claude':
|
|
17
|
+
return process.cwd(); // Current working directory for Claude
|
|
18
|
+
case 'gemini':
|
|
19
|
+
return process.cwd(); // Current working directory for Gemini
|
|
20
|
+
case 'qwen':
|
|
21
|
+
return path.join(os.homedir(), '.qwen'); // Qwen's home directory
|
|
22
|
+
case 'codebuddy':
|
|
23
|
+
return process.cwd(); // Current working directory for CodeBuddy
|
|
24
|
+
case 'copilot':
|
|
25
|
+
return process.cwd(); // Current working directory for Copilot
|
|
26
|
+
default:
|
|
27
|
+
return process.cwd(); // Default to current working directory
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get environment variables for specific CLI tool
|
|
33
|
+
* @param {string} toolName - Name of the CLI tool
|
|
34
|
+
* @returns {Object} Environment variables object
|
|
35
|
+
*/
|
|
36
|
+
function getEnvironmentForTool(toolName) {
|
|
37
|
+
const env = { ...process.env };
|
|
38
|
+
|
|
39
|
+
// Tool-specific environment setup
|
|
40
|
+
switch (toolName) {
|
|
41
|
+
case 'qwen':
|
|
42
|
+
// For Qwen CLI, clear Node.js environment variables to avoid import conflicts
|
|
43
|
+
delete env.NODE_PATH;
|
|
44
|
+
delete env.NODE_OPTIONS;
|
|
45
|
+
// Ensure clean environment
|
|
46
|
+
env.PWD = getWorkingDirectoryForTool(toolName);
|
|
47
|
+
break;
|
|
48
|
+
case 'claude':
|
|
49
|
+
// Claude-specific environment setup if needed
|
|
50
|
+
break;
|
|
51
|
+
case 'gemini':
|
|
52
|
+
// Gemini-specific environment setup if needed
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
// Use default environment
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return env;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if CLI tool needs special working directory
|
|
64
|
+
* @param {string} toolName - Name of the CLI tool
|
|
65
|
+
* @returns {boolean} True if special directory needed
|
|
66
|
+
*/
|
|
67
|
+
function needsSpecialDirectory(toolName) {
|
|
68
|
+
return ['qwen'].includes(toolName);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
getWorkingDirectoryForTool,
|
|
73
|
+
getEnvironmentForTool,
|
|
74
|
+
needsSpecialDirectory
|
|
75
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Formatters Module
|
|
3
|
+
* Contains helper functions for formatting output
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Format bytes into human readable string
|
|
8
|
+
* @param {number} bytes - Number of bytes
|
|
9
|
+
* @returns {string} Formatted string
|
|
10
|
+
*/
|
|
11
|
+
function formatBytes(bytes) {
|
|
12
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
13
|
+
if (bytes === 0) return '0 Bytes';
|
|
14
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
15
|
+
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Format duration in milliseconds to human readable string
|
|
20
|
+
* @param {number} ms - Duration in milliseconds
|
|
21
|
+
* @returns {string} Formatted duration
|
|
22
|
+
*/
|
|
23
|
+
function formatDuration(ms) {
|
|
24
|
+
if (ms < 1000) return `${ms}ms`;
|
|
25
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
26
|
+
if (ms < 3600000) return `${(ms / 60000).toFixed(1)}m`;
|
|
27
|
+
return `${(ms / 3600000).toFixed(1)}h`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Format CLI tool status for display
|
|
32
|
+
* @param {Object} status - Status object
|
|
33
|
+
* @returns {string} Formatted status
|
|
34
|
+
*/
|
|
35
|
+
function formatToolStatus(status) {
|
|
36
|
+
if (status.installed) {
|
|
37
|
+
return `${status.tool}: ✅ Installed (v${status.version || 'unknown'})`;
|
|
38
|
+
} else {
|
|
39
|
+
return `${status.tool}: ❌ Not installed`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
formatBytes,
|
|
45
|
+
formatDuration,
|
|
46
|
+
formatToolStatus
|
|
47
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills/Agents Cache Management Utilities
|
|
3
|
+
* Provides centralized cache initialization and management for skills and agents
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const LocalSkillScanner = require('../../core/local_skill_scanner');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize or update skills/agents cache
|
|
10
|
+
* This function checks if cache exists, and if not, generates it.
|
|
11
|
+
* If cache exists, it performs incremental update (only scans changed directories).
|
|
12
|
+
*
|
|
13
|
+
* Called during: scan, install, setup, init, upgrade commands
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} options - Options
|
|
16
|
+
* @param {boolean} options.verbose - Show detailed output
|
|
17
|
+
* @param {boolean} options.force - Force full rescan
|
|
18
|
+
* @returns {Promise<Object>} Cache statistics
|
|
19
|
+
*/
|
|
20
|
+
async function ensureSkillsCache(options = {}) {
|
|
21
|
+
const { verbose = false, force = false } = options;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const scanner = new LocalSkillScanner();
|
|
25
|
+
|
|
26
|
+
// Check if cache exists
|
|
27
|
+
const hasCache = await scanner.hasCache();
|
|
28
|
+
|
|
29
|
+
if (!hasCache) {
|
|
30
|
+
// First time - generate cache
|
|
31
|
+
console.log('[CACHE] Generating skills/agents cache (first time)...');
|
|
32
|
+
await scanner.initialize();
|
|
33
|
+
const results = scanner.getScanResults();
|
|
34
|
+
|
|
35
|
+
if (results) {
|
|
36
|
+
const totalSkills = Object.values(results.skills || {}).flat().length;
|
|
37
|
+
const totalAgents = Object.values(results.agents || {}).flat().length;
|
|
38
|
+
console.log(`[CACHE] Cache generated: ${totalSkills} skills, ${totalAgents} agents`);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
skills: totalSkills,
|
|
43
|
+
agents: totalAgents,
|
|
44
|
+
action: 'generated'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
} else if (force) {
|
|
48
|
+
// Force refresh requested
|
|
49
|
+
console.log('[CACHE] Refreshing skills/agents cache...');
|
|
50
|
+
await scanner.initialize(true);
|
|
51
|
+
const results = scanner.getScanResults();
|
|
52
|
+
|
|
53
|
+
if (results) {
|
|
54
|
+
const totalSkills = Object.values(results.skills || {}).flat().length;
|
|
55
|
+
const totalAgents = Object.values(results.agents || {}).flat().length;
|
|
56
|
+
console.log(`[CACHE] Cache refreshed: ${totalSkills} skills, ${totalAgents} agents`);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
success: true,
|
|
60
|
+
skills: totalSkills,
|
|
61
|
+
agents: totalAgents,
|
|
62
|
+
action: 'refreshed'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
// Incremental update - only scan changed directories
|
|
67
|
+
if (verbose || process.env.DEBUG === 'true') {
|
|
68
|
+
console.log('[CACHE] Updating skills/agents cache (incremental)...');
|
|
69
|
+
}
|
|
70
|
+
await scanner.scanIncremental();
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
success: true,
|
|
74
|
+
action: 'updated'
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// Cache initialization is not critical - don't fail the command
|
|
79
|
+
if (verbose || process.env.DEBUG === 'true') {
|
|
80
|
+
console.log(`[CACHE] Warning: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: error.message
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
ensureSkillsCache
|
|
92
|
+
};
|