stigmergy 1.2.13 ā 1.3.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +14 -5
- package/scripts/analyze-router.js +168 -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 +185 -422
- 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 +701 -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 +220 -30
- package/src/core/enhanced_cli_parameter_handler.js +395 -0
- package/src/core/execution_mode_detector.js +222 -0
- package/src/core/installer.js +51 -70
- 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,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Management Commands
|
|
3
|
+
* Modular implementation for all skill-related commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const { handleSkillCommand } = require('../../commands/skill-handler');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle main skill command with all subcommands
|
|
11
|
+
* @param {string} subcommand - Skill subcommand (install/list/read/remove/validate/sync)
|
|
12
|
+
* @param {Array} args - Additional arguments
|
|
13
|
+
* @param {Object} options - Command options
|
|
14
|
+
*/
|
|
15
|
+
async function handleSkillMainCommand(subcommand, args = [], options = {}) {
|
|
16
|
+
try {
|
|
17
|
+
// Handle skill command aliases from router-beta.js
|
|
18
|
+
let action;
|
|
19
|
+
let skillArgs;
|
|
20
|
+
|
|
21
|
+
switch (subcommand) {
|
|
22
|
+
case 'skill-i':
|
|
23
|
+
action = 'install';
|
|
24
|
+
skillArgs = args;
|
|
25
|
+
break;
|
|
26
|
+
case 'skill-l':
|
|
27
|
+
action = 'list';
|
|
28
|
+
skillArgs = args;
|
|
29
|
+
break;
|
|
30
|
+
case 'skill-v':
|
|
31
|
+
// skill-v can be validate or read, based on parameters
|
|
32
|
+
action = args[0] && (args[0].endsWith('.md') || args[0].includes('/') || args[0].includes('\\'))
|
|
33
|
+
? 'validate'
|
|
34
|
+
: 'read';
|
|
35
|
+
skillArgs = args;
|
|
36
|
+
break;
|
|
37
|
+
case 'skill-r':
|
|
38
|
+
action = 'read';
|
|
39
|
+
skillArgs = args;
|
|
40
|
+
break;
|
|
41
|
+
case 'skill-d':
|
|
42
|
+
case 'skill-m':
|
|
43
|
+
action = 'remove';
|
|
44
|
+
skillArgs = args;
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
action = subcommand || 'help';
|
|
48
|
+
skillArgs = args;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const exitCode = await handleSkillCommand(action, skillArgs, {
|
|
53
|
+
verbose: options.verbose || false,
|
|
54
|
+
force: options.force || false,
|
|
55
|
+
autoSync: !options.noAutoSync
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return { success: exitCode === 0, exitCode };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(chalk.red(`[ERROR] Skill command failed: ${error.message}`));
|
|
61
|
+
return { success: false, error: error.message };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handle skill install command (skill-i alias)
|
|
67
|
+
* @param {Array} args - Arguments
|
|
68
|
+
* @param {Object} options - Options
|
|
69
|
+
*/
|
|
70
|
+
async function handleSkillInstallCommand(args = [], options = {}) {
|
|
71
|
+
return await handleSkillMainCommand('install', args, options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle skill list command (skill-l alias)
|
|
76
|
+
* @param {Array} args - Arguments
|
|
77
|
+
* @param {Object} options - Options
|
|
78
|
+
*/
|
|
79
|
+
async function handleSkillListCommand(args = [], options = {}) {
|
|
80
|
+
return await handleSkillMainCommand('list', args, options);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Handle skill read command (skill-r alias)
|
|
85
|
+
* @param {Array} args - Arguments
|
|
86
|
+
* @param {Object} options - Options
|
|
87
|
+
*/
|
|
88
|
+
async function handleSkillReadCommand(args = [], options = {}) {
|
|
89
|
+
return await handleSkillMainCommand('read', args, options);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Handle skill validate/read command (skill-v alias)
|
|
94
|
+
* @param {Array} args - Arguments
|
|
95
|
+
* @param {Object} options - Options
|
|
96
|
+
*/
|
|
97
|
+
async function handleSkillValidateCommand(args = [], options = {}) {
|
|
98
|
+
return await handleSkillMainCommand('validate', args, options);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Handle skill remove command (skill-d, skill-m aliases)
|
|
103
|
+
* @param {Array} args - Arguments
|
|
104
|
+
* @param {Object} options - Options
|
|
105
|
+
*/
|
|
106
|
+
async function handleSkillRemoveCommand(args = [], options = {}) {
|
|
107
|
+
return await handleSkillMainCommand('remove', args, options);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Print skills help information
|
|
112
|
+
*/
|
|
113
|
+
function printSkillsHelp() {
|
|
114
|
+
console.log(chalk.cyan(`
|
|
115
|
+
šÆ Stigmergy Skills Management System
|
|
116
|
+
|
|
117
|
+
š Available Commands:
|
|
118
|
+
stigmergy skill install <source> Install a skill from source
|
|
119
|
+
stigmergy skill list List all installed skills
|
|
120
|
+
stigmergy skill read <skill-name> Read skill content and description
|
|
121
|
+
stigmergy skill validate <path> Validate skill file or directory
|
|
122
|
+
stigmergy skill remove <skill-name> Remove installed skill
|
|
123
|
+
stigmergy skill sync Sync skills with remote repositories
|
|
124
|
+
|
|
125
|
+
š Aliases (Shortcuts):
|
|
126
|
+
skill-i ā skill install
|
|
127
|
+
skill-l ā skill list
|
|
128
|
+
skill-r ā skill read
|
|
129
|
+
skill-v ā skill validate/read (auto-detect)
|
|
130
|
+
skill-d ā skill remove
|
|
131
|
+
skill-m ā skill remove (ē§»é¤)
|
|
132
|
+
|
|
133
|
+
š” Examples:
|
|
134
|
+
stigmergy skill install anthropics/skills
|
|
135
|
+
stigmergy skill-i anthropics/skills # Using alias
|
|
136
|
+
stigmergy skill list
|
|
137
|
+
stigmergy skill-l # Using alias
|
|
138
|
+
stigmergy skill read canvas-design
|
|
139
|
+
stigmergy skill-v ./my-skill.md # Validate file
|
|
140
|
+
stigmergy skill-r docx # Using alias
|
|
141
|
+
stigmergy skill remove old-skill
|
|
142
|
+
stigmergy skill-d old-skill # Using alias
|
|
143
|
+
|
|
144
|
+
š More Information:
|
|
145
|
+
Skills extend CLI tool capabilities with specialized workflows and tools.
|
|
146
|
+
Each skill contains instructions for specific tasks and integrations.
|
|
147
|
+
`));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
handleSkillMainCommand,
|
|
152
|
+
handleSkillInstallCommand,
|
|
153
|
+
handleSkillListCommand,
|
|
154
|
+
handleSkillReadCommand,
|
|
155
|
+
handleSkillValidateCommand,
|
|
156
|
+
handleSkillRemoveCommand,
|
|
157
|
+
printSkillsHelp
|
|
158
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command Module
|
|
3
|
+
* Handles CLI tool status checking commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { CLI_TOOLS } = require('../../core/cli_tools');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const { formatToolStatus } = require('../utils/formatters');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Handle status command
|
|
12
|
+
* @param {Object} options - Command options
|
|
13
|
+
* @param {string} options.cli - Specific CLI to check
|
|
14
|
+
* @param {boolean} options.json - Output in JSON format
|
|
15
|
+
* @param {boolean} options.verbose - Verbose output
|
|
16
|
+
*/
|
|
17
|
+
async function handleStatusCommand(options = {}) {
|
|
18
|
+
try {
|
|
19
|
+
const supportedTools = ['claude', 'gemini', 'qwen', 'codebuddy', 'codex', 'iflow', 'qodercli', 'copilot'];
|
|
20
|
+
|
|
21
|
+
if (options.cli) {
|
|
22
|
+
// Check specific CLI
|
|
23
|
+
if (!supportedTools.includes(options.cli)) {
|
|
24
|
+
console.log(chalk.red(`ā Unknown CLI tool: ${options.cli}`));
|
|
25
|
+
console.log(chalk.yellow(`Supported tools: ${supportedTools.join(', ')}`));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const status = await CLI_TOOLS.checkInstallation(options.cli);
|
|
31
|
+
|
|
32
|
+
if (options.json) {
|
|
33
|
+
console.log(JSON.stringify(status, null, 2));
|
|
34
|
+
} else {
|
|
35
|
+
console.log(chalk.cyan(`š ${options.cli} Status:`));
|
|
36
|
+
console.log(formatToolStatus({ ...status, tool: options.cli }));
|
|
37
|
+
|
|
38
|
+
if (options.verbose && status.installed) {
|
|
39
|
+
if (status.version) {
|
|
40
|
+
console.log(chalk.gray(` š¦ Version: ${status.version}`));
|
|
41
|
+
}
|
|
42
|
+
if (status.path) {
|
|
43
|
+
console.log(chalk.gray(` š Path: ${status.path}`));
|
|
44
|
+
}
|
|
45
|
+
if (status.lastChecked) {
|
|
46
|
+
console.log(chalk.gray(` š Last checked: ${status.lastChecked}`));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(chalk.red(`ā Error checking ${options.cli}: ${error.message}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
// Check all CLIs
|
|
56
|
+
console.log(chalk.cyan('š CLI Tools Status:'));
|
|
57
|
+
|
|
58
|
+
let installedCount = 0;
|
|
59
|
+
const results = [];
|
|
60
|
+
|
|
61
|
+
for (const tool of supportedTools) {
|
|
62
|
+
try {
|
|
63
|
+
const status = await CLI_TOOLS.checkInstallation(tool);
|
|
64
|
+
results.push({ tool, ...status });
|
|
65
|
+
|
|
66
|
+
if (status.installed) {
|
|
67
|
+
installedCount++;
|
|
68
|
+
console.log(chalk.green(` ā
${tool}`));
|
|
69
|
+
} else {
|
|
70
|
+
console.log(chalk.red(` ā ${tool}`));
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
results.push({ tool, installed: false, error: error.message });
|
|
74
|
+
console.log(chalk.yellow(` ā ļø ${tool}: Error checking status`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Summary
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log(chalk.blue(`š Summary: ${installedCount}/${supportedTools.length} tools installed`));
|
|
81
|
+
|
|
82
|
+
if (installedCount < supportedTools.length) {
|
|
83
|
+
console.log(chalk.yellow('\nš” To install missing tools, run:'));
|
|
84
|
+
console.log(chalk.cyan(' stigmergy install'));
|
|
85
|
+
|
|
86
|
+
const missing = results.filter(r => !r.installed);
|
|
87
|
+
if (missing.length > 0 && missing.length < supportedTools.length) {
|
|
88
|
+
console.log(chalk.cyan(` stigmergy install --cli ${missing.map(r => r.tool).join(',')}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (options.json) {
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(chalk.blue('š Detailed JSON output:'));
|
|
95
|
+
console.log(JSON.stringify(results, null, 2));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(chalk.red(`ā Status check failed: ${error.message}`));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
handleStatusCommand
|
|
106
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Commands
|
|
3
|
+
* Modular implementation for clean, diagnostic, and other system commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const fs = require('fs').promises;
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Handle diagnostic command
|
|
13
|
+
* @param {Object} options - Command options
|
|
14
|
+
*/
|
|
15
|
+
async function handleDiagnosticCommand(options = {}) {
|
|
16
|
+
try {
|
|
17
|
+
console.log(chalk.cyan('[DIAGNOSTIC] Stigmergy CLI System Diagnostic...\n'));
|
|
18
|
+
|
|
19
|
+
const results = {
|
|
20
|
+
system: {},
|
|
21
|
+
directories: {},
|
|
22
|
+
files: {},
|
|
23
|
+
permissions: {},
|
|
24
|
+
summary: { issues: 0, warnings: 0, ok: 0 }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// System information
|
|
28
|
+
console.log(chalk.blue('š„ļø System Information:'));
|
|
29
|
+
const systemInfo = {
|
|
30
|
+
platform: os.platform(),
|
|
31
|
+
arch: os.arch(),
|
|
32
|
+
nodeVersion: process.version,
|
|
33
|
+
memory: Math.round(os.totalmem() / 1024 / 1024) + ' MB',
|
|
34
|
+
freeMemory: Math.round(os.freemem() / 1024 / 1024) + ' MB',
|
|
35
|
+
homeDir: os.homedir(),
|
|
36
|
+
currentDir: process.cwd()
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
results.system = systemInfo;
|
|
40
|
+
Object.entries(systemInfo).forEach(([key, value]) => {
|
|
41
|
+
console.log(` ${key}: ${chalk.green(value)}`);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Directory checks
|
|
45
|
+
console.log(chalk.blue('\nš Directory Structure:'));
|
|
46
|
+
const directories = [
|
|
47
|
+
path.join(os.homedir(), '.stigmergy'),
|
|
48
|
+
path.join(os.homedir(), '.claude'),
|
|
49
|
+
path.join(os.homedir(), '.gemini'),
|
|
50
|
+
path.join(os.homedir(), '.qwen'),
|
|
51
|
+
path.join(process.cwd(), 'node_modules')
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const dir of directories) {
|
|
55
|
+
try {
|
|
56
|
+
const stats = await fs.stat(dir);
|
|
57
|
+
results.directories[dir] = { exists: true, size: stats.size };
|
|
58
|
+
console.log(` ${chalk.green('ā
')} ${dir}`);
|
|
59
|
+
results.summary.ok++;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
results.directories[dir] = { exists: false, error: error.code };
|
|
62
|
+
console.log(` ${chalk.yellow('ā ļø')} ${dir} (${error.code})`);
|
|
63
|
+
results.summary.warnings++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Permission checks
|
|
68
|
+
console.log(chalk.blue('\nš Permission Checks:'));
|
|
69
|
+
try {
|
|
70
|
+
await fs.access(process.cwd(), fs.constants.W_OK);
|
|
71
|
+
console.log(` ${chalk.green('ā
')} Current directory writable`);
|
|
72
|
+
results.permissions.currentDir = true;
|
|
73
|
+
results.summary.ok++;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.log(` ${chalk.red('ā')} Current directory not writable`);
|
|
76
|
+
results.permissions.currentDir = false;
|
|
77
|
+
results.summary.issues++;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await fs.access(os.homedir(), fs.constants.W_OK);
|
|
82
|
+
console.log(` ${chalk.green('ā
')} Home directory writable`);
|
|
83
|
+
results.permissions.homeDir = true;
|
|
84
|
+
results.summary.ok++;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.log(` ${chalk.red('ā')} Home directory not writable`);
|
|
87
|
+
results.permissions.homeDir = false;
|
|
88
|
+
results.summary.issues++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Summary
|
|
92
|
+
console.log(chalk.blue('\nš Diagnostic Summary:'));
|
|
93
|
+
console.log(` Issues: ${chalk.red(results.summary.issues)}`);
|
|
94
|
+
console.log(` Warnings: ${chalk.yellow(results.summary.warnings)}`);
|
|
95
|
+
console.log(` OK: ${chalk.green(results.summary.ok)}`);
|
|
96
|
+
|
|
97
|
+
if (results.summary.issues > 0) {
|
|
98
|
+
console.log(chalk.red('\nā Critical issues found - Fix recommended'));
|
|
99
|
+
console.log('Run: stigmergy fix-perms');
|
|
100
|
+
} else if (results.summary.warnings > 0) {
|
|
101
|
+
console.log(chalk.yellow('\nā ļø Some warnings found - Check recommended'));
|
|
102
|
+
} else {
|
|
103
|
+
console.log(chalk.green('\nā
System looks healthy!'));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { success: true, results };
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error(chalk.red('[ERROR] Diagnostic failed:'), error.message);
|
|
109
|
+
return { success: false, error: error.message };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Handle clean command
|
|
115
|
+
* @param {Object} options - Command options
|
|
116
|
+
*/
|
|
117
|
+
async function handleCleanCommand(options = {}) {
|
|
118
|
+
try {
|
|
119
|
+
console.log(chalk.cyan('[CLEAN] Starting intelligent cache cleaning...\n'));
|
|
120
|
+
|
|
121
|
+
const stats = {
|
|
122
|
+
found: 0,
|
|
123
|
+
cleaned: 0,
|
|
124
|
+
skipped: 0,
|
|
125
|
+
totalSize: 0,
|
|
126
|
+
cleanedSize: 0,
|
|
127
|
+
errors: []
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Define cleanup targets with priority and safety levels
|
|
131
|
+
const cleanupTargets = [
|
|
132
|
+
// Priority 1: Always safe to clean
|
|
133
|
+
{
|
|
134
|
+
path: path.join(os.tmpdir(), 'stigmergy-*'),
|
|
135
|
+
priority: 1,
|
|
136
|
+
safe: true,
|
|
137
|
+
description: 'Stigmergy temporary files'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
path: path.join(os.homedir(), '.stigmergy', 'cache'),
|
|
141
|
+
priority: 1,
|
|
142
|
+
safe: true,
|
|
143
|
+
description: 'Stigmergy cache'
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// Priority 2: Generally safe (user data)
|
|
147
|
+
{
|
|
148
|
+
path: path.join(process.cwd(), 'node_modules', '.cache'),
|
|
149
|
+
priority: 2,
|
|
150
|
+
safe: true,
|
|
151
|
+
description: 'Project cache'
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
// Priority 3: CLI tool caches (may have permission issues)
|
|
155
|
+
{
|
|
156
|
+
path: path.join(os.homedir(), '.claude', 'cache'),
|
|
157
|
+
priority: 3,
|
|
158
|
+
safe: false,
|
|
159
|
+
description: 'Claude CLI cache'
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
path: path.join(os.homedir(), '.gemini', 'cache'),
|
|
163
|
+
priority: 3,
|
|
164
|
+
safe: false,
|
|
165
|
+
description: 'Gemini CLI cache'
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
path: path.join(os.homedir(), '.qwen', 'cache'),
|
|
169
|
+
priority: 3,
|
|
170
|
+
safe: false,
|
|
171
|
+
description: 'Qwen CLI cache'
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
// Sort by priority
|
|
176
|
+
cleanupTargets.sort((a, b) => a.priority - b.priority);
|
|
177
|
+
|
|
178
|
+
console.log(chalk.blue('š Scanning cleanup targets...'));
|
|
179
|
+
|
|
180
|
+
for (const target of cleanupTargets) {
|
|
181
|
+
try {
|
|
182
|
+
const isPattern = target.path.includes('*');
|
|
183
|
+
let targetPaths = [];
|
|
184
|
+
|
|
185
|
+
if (isPattern) {
|
|
186
|
+
// Simple glob pattern handling
|
|
187
|
+
const baseDir = path.dirname(target.path);
|
|
188
|
+
const pattern = path.basename(target.path).replace('*', '');
|
|
189
|
+
try {
|
|
190
|
+
const files = await fs.readdir(baseDir);
|
|
191
|
+
targetPaths = files
|
|
192
|
+
.filter(file => file.includes(pattern))
|
|
193
|
+
.map(file => path.join(baseDir, file));
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// Directory doesn't exist, skip silently
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
targetPaths = [target.path];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
for (const targetPath of targetPaths) {
|
|
203
|
+
try {
|
|
204
|
+
const targetStats = await fs.stat(targetPath);
|
|
205
|
+
stats.found++;
|
|
206
|
+
stats.totalSize += targetStats.size;
|
|
207
|
+
|
|
208
|
+
if (!options.dryRun) {
|
|
209
|
+
// Attempt to clean with better error handling
|
|
210
|
+
try {
|
|
211
|
+
if (targetStats.isDirectory()) {
|
|
212
|
+
await fs.rmdir(targetPath, { recursive: true });
|
|
213
|
+
} else {
|
|
214
|
+
await fs.unlink(targetPath);
|
|
215
|
+
}
|
|
216
|
+
stats.cleaned++;
|
|
217
|
+
stats.cleanedSize += targetStats.size;
|
|
218
|
+
|
|
219
|
+
// Only show successful cleanups in normal mode
|
|
220
|
+
if (!options.quiet) {
|
|
221
|
+
console.log(` ${chalk.green('ā
')} Cleaned ${target.description}`);
|
|
222
|
+
}
|
|
223
|
+
} catch (cleanError) {
|
|
224
|
+
// Silent failure for permission issues
|
|
225
|
+
stats.skipped++;
|
|
226
|
+
stats.errors.push({
|
|
227
|
+
path: targetPath,
|
|
228
|
+
error: cleanError.code,
|
|
229
|
+
safe: target.safe
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// Dry run mode
|
|
234
|
+
console.log(` ${chalk.blue('š')} Would clean: ${target.description} (${Math.round(targetStats.size / 1024)} KB)`);
|
|
235
|
+
}
|
|
236
|
+
} catch (statError) {
|
|
237
|
+
// File might be locked or in use
|
|
238
|
+
stats.skipped++;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
// Silently skip inaccessible targets
|
|
243
|
+
stats.skipped++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Show summary with user-friendly output
|
|
248
|
+
console.log(chalk.blue('\nš Cleanup Results:'));
|
|
249
|
+
|
|
250
|
+
if (stats.cleaned > 0) {
|
|
251
|
+
console.log(` ${chalk.green('ā
')} Cleaned: ${stats.cleaned} items (${Math.round(stats.cleanedSize / 1024)} KB)`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (stats.skipped > 0) {
|
|
255
|
+
console.log(` ${chalk.yellow('ā ļø')} Skipped: ${stats.skipped} items (in use or permission protected)`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Show critical errors only (safe targets that failed)
|
|
259
|
+
const criticalErrors = stats.errors.filter(e => e.safe && e.error === 'EPERM');
|
|
260
|
+
if (criticalErrors.length > 0 && options.verbose) {
|
|
261
|
+
console.log(` ${chalk.red('ā')} Permission issues on ${criticalErrors.length} safe targets`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Final user-friendly message
|
|
265
|
+
if (!options.dryRun) {
|
|
266
|
+
if (stats.cleaned > 0) {
|
|
267
|
+
console.log(chalk.green('\nā
Cache cleanup completed successfully!'));
|
|
268
|
+
} else {
|
|
269
|
+
console.log(chalk.yellow('\nš” No cache files were available for cleaning'));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (stats.skipped > 0 && stats.cleaned === 0) {
|
|
273
|
+
console.log(chalk.gray(' Some files were in use or require admin permissions'));
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
console.log(chalk.blue('\nš” Dry run completed. Run without --dry-run to actually clean.'));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
success: true,
|
|
281
|
+
stats: {
|
|
282
|
+
cleaned: stats.cleaned,
|
|
283
|
+
skipped: stats.skipped,
|
|
284
|
+
totalSize: Math.round(stats.totalSize / 1024),
|
|
285
|
+
cleanedSize: Math.round(stats.cleanedSize / 1024)
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
} catch (error) {
|
|
290
|
+
// Show only critical errors to user
|
|
291
|
+
if (options.verbose) {
|
|
292
|
+
console.error(chalk.red('[ERROR] Cache cleaning failed:'), error.message);
|
|
293
|
+
}
|
|
294
|
+
return { success: false, error: error.message };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = {
|
|
299
|
+
handleDiagnosticCommand,
|
|
300
|
+
handleCleanCommand
|
|
301
|
+
};
|