glad-web 1.0.7

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.
@@ -0,0 +1,88 @@
1
+ // 50 randomized responses for demo mode
2
+ // Topics: AI coding, mobile development, remote terminals, vibe coding, tech wisdom
3
+
4
+ const RESPONSES = [
5
+ // AI Coding Assistant vibes
6
+ "AI-powered coding is like having a genius pair programmer who never sleeps!",
7
+ "The future of development is collaborative - humans and AI working together.",
8
+ "Code faster, debug smarter, ship sooner. That's the AI advantage.",
9
+ "Sometimes the best code is written when you're away from your desk.",
10
+ "AI assistants don't replace developers, they amplify their potential.",
11
+
12
+ // Mobile development
13
+ "Mobile-first isn't just design philosophy - it's a lifestyle.",
14
+ "Your next breakthrough idea might come while you're on the go.",
15
+ "The best development environment is the one you have with you.",
16
+ "Coding from your phone? Welcome to the future!",
17
+ "Distance is no barrier when your terminal fits in your pocket.",
18
+
19
+ // Remote terminal access
20
+ "SSH has evolved - now it's in your hand.",
21
+ "Terminal access from anywhere opens infinite possibilities.",
22
+ "Your development machine, always within reach.",
23
+ "The cloud isn't just for deployment anymore.",
24
+ "Remote doesn't mean disconnected.",
25
+
26
+ // Vibe coding
27
+ "Great code comes from great vibes.",
28
+ "The best debugging happens with a clear mind.",
29
+ "Inspiration strikes at unexpected moments - be ready!",
30
+ "Code flows better when you're in the zone.",
31
+ "Sometimes you need to step away to see the solution clearly.",
32
+
33
+ // Tech wisdom
34
+ "The right tool at the right time makes all the difference.",
35
+ "Automation isn't lazy - it's efficient.",
36
+ "Every line of code is a conversation with the future.",
37
+ "Simplicity is the ultimate sophistication.",
38
+ "Build tools that make you excited to work.",
39
+
40
+ // AI tools ecosystem
41
+ "Claude, Aider, Copilot - choose your AI companion wisely.",
42
+ "The best AI tool is the one that matches your workflow.",
43
+ "Multiple AI assistants? Why choose when you can have them all?",
44
+ "Each AI has its strengths - know when to use which.",
45
+ "The AI coding revolution is here, and it's spectacular.",
46
+
47
+ // Developer productivity
48
+ "Context switching costs time - keep your flow intact.",
49
+ "The fastest code is the code you don't have to write.",
50
+ "Good tools get out of your way. Great tools elevate your work.",
51
+ "Productivity isn't about hours - it's about focus.",
52
+ "Work smarter, not just harder.",
53
+
54
+ // Terminal culture
55
+ "The terminal is where magic happens.",
56
+ "Command line mastery is a superpower.",
57
+ "GUI is great, but CLI is poetry.",
58
+ "Real developers aren't afraid of the terminal.",
59
+ "There's something beautiful about green text on black.",
60
+
61
+ // Innovation & future
62
+ "The tools we build today shape tomorrow's possibilities.",
63
+ "Innovation happens when convenience meets capability.",
64
+ "The future of coding is more accessible than ever.",
65
+ "Technology should adapt to you, not the other way around.",
66
+ "We're living in the golden age of developer tools.",
67
+
68
+ // Collaboration
69
+ "The best solutions come from diverse perspectives.",
70
+ "Share your workflow, inspire others.",
71
+ "Community-driven development moves faster.",
72
+ "Open source is the rising tide that lifts all boats.",
73
+ "Collaboration multiplies creativity.",
74
+ ];
75
+
76
+ /**
77
+ * Get a random response from the pool
78
+ * @returns {string} Random response
79
+ */
80
+ function getRandomResponse() {
81
+ const index = Math.floor(Math.random() * RESPONSES.length);
82
+ return RESPONSES[index];
83
+ }
84
+
85
+ module.exports = {
86
+ RESPONSES,
87
+ getRandomResponse
88
+ };
@@ -0,0 +1,76 @@
1
+ const { getAllTools, getToolVersion } = require('./registry');
2
+ const logger = require('../utils/logger');
3
+
4
+ // Detect all installed AI tools
5
+ async function detectInstalledTools() {
6
+ const allTools = getAllTools();
7
+ const installedTools = [];
8
+
9
+ logger.debug('Detecting installed AI tools...');
10
+
11
+ for (const tool of allTools) {
12
+ // Skip demo mode from auto-detection (only available via --ai demo)
13
+ if (tool.key === 'demo') {
14
+ continue;
15
+ }
16
+
17
+ try {
18
+ const isInstalled = await tool.checkInstalled();
19
+
20
+ if (isInstalled) {
21
+ const version = await getToolVersion(tool);
22
+
23
+ // Always use short command name - PTY will have npm bin in PATH
24
+ installedTools.push({
25
+ ...tool,
26
+ version,
27
+ installed: true
28
+ });
29
+
30
+ logger.debug(`Found: ${tool.displayName} v${version} (command: ${tool.command})`);
31
+ }
32
+ } catch (err) {
33
+ logger.debug(`Check failed for ${tool.displayName}: ${err.message}`);
34
+ }
35
+ }
36
+
37
+ logger.debug(`Detected ${installedTools.length} installed AI tools`);
38
+
39
+ return installedTools;
40
+ }
41
+
42
+ // Check if specific tool is installed
43
+ async function isToolInstalled(toolKey) {
44
+ const { getToolByKey } = require('./registry');
45
+ const tool = getToolByKey(toolKey);
46
+
47
+ if (!tool) {
48
+ return { installed: false, error: 'Unknown tool' };
49
+ }
50
+
51
+ try {
52
+ const isInstalled = await tool.checkInstalled();
53
+
54
+ if (isInstalled) {
55
+ const version = await getToolVersion(tool);
56
+
57
+ // Always use short command name - PTY will have npm bin in PATH
58
+ return {
59
+ installed: true,
60
+ tool: {
61
+ ...tool,
62
+ version
63
+ }
64
+ };
65
+ }
66
+
67
+ return { installed: false, tool };
68
+ } catch (err) {
69
+ return { installed: false, tool, error: err.message };
70
+ }
71
+ }
72
+
73
+ module.exports = {
74
+ detectInstalledTools,
75
+ isToolInstalled
76
+ };
@@ -0,0 +1,300 @@
1
+ const { exec } = require('child_process');
2
+ const { promisify } = require('util');
3
+ const execAsync = promisify(exec);
4
+ const logger = require('../utils/logger');
5
+
6
+ function preview(text, maxChars = 500) {
7
+ const value = String(text || '')
8
+ .replace(/\r/g, '\\r')
9
+ .replace(/\n/g, '\\n')
10
+ .replace(/\t/g, '\\t')
11
+ .replace(/\x1b/g, '\\x1b');
12
+ return value.length > maxChars ? value.slice(0, maxChars) + '...' : value;
13
+ }
14
+
15
+ // AI Tools Registry
16
+ const AI_TOOLS = {
17
+ 'claude-code': {
18
+ key: 'claude-code',
19
+ command: 'claude',
20
+ args: [],
21
+ displayName: 'Claude',
22
+ description: 'Anthropic\'s AI coding assistant',
23
+ website: 'https://docs.claude.com',
24
+ checkInstalled: async () => await commandExists('claude')
25
+ },
26
+ 'aider': {
27
+ key: 'aider',
28
+ command: 'aider',
29
+ args: [],
30
+ displayName: 'Aider',
31
+ description: 'AI pair programming in your terminal',
32
+ website: 'https://aider.chat',
33
+ checkInstalled: async () => await commandExists('aider')
34
+ },
35
+ 'codex': {
36
+ key: 'codex',
37
+ command: 'codex',
38
+ args: [],
39
+ displayName: 'Codex',
40
+ description: 'Official OpenAI Codex CLI (launched April 2025)',
41
+ website: 'https://openai.com/codex',
42
+ checkInstalled: async () => await commandExists('codex')
43
+ },
44
+ 'github-copilot': {
45
+ key: 'github-copilot',
46
+ command: 'copilot',
47
+ args: [],
48
+ displayName: 'Copilot',
49
+ description: 'GitHub\'s command line AI',
50
+ website: 'https://github.com/features/copilot',
51
+ checkInstalled: async () => await commandExists('copilot')
52
+ },
53
+ 'cody': {
54
+ key: 'cody',
55
+ command: 'cody',
56
+ args: ['chat'],
57
+ displayName: 'Cody',
58
+ description: 'Sourcegraph\'s AI assistant (Beta)',
59
+ website: 'https://sourcegraph.com/cody',
60
+ checkInstalled: async () => await commandExists('cody')
61
+ },
62
+ 'gemini': {
63
+ key: 'gemini',
64
+ command: 'gemini',
65
+ args: [],
66
+ displayName: 'Gemini',
67
+ description: 'Official Google Gemini CLI with 1M token context',
68
+ website: 'https://developers.google.com/gemini-code-assist',
69
+ checkInstalled: async () => await commandExists('gemini')
70
+ },
71
+ 'continue': {
72
+ key: 'continue',
73
+ command: 'cn',
74
+ args: [],
75
+ displayName: 'Continue',
76
+ description: 'Open-source modular AI coding assistant',
77
+ website: 'https://continue.dev',
78
+ checkInstalled: async () => await commandExists('cn')
79
+ },
80
+ 'cursor': {
81
+ key: 'cursor',
82
+ command: 'cursor-agent',
83
+ args: [],
84
+ displayName: 'Cursor',
85
+ description: 'Cursor\'s AI coding assistant CLI (Beta)',
86
+ website: 'https://cursor.com/blog/cli',
87
+ checkInstalled: async () => await commandExists('cursor-agent')
88
+ },
89
+ 'chatgpt': {
90
+ key: 'chatgpt',
91
+ command: 'chatgpt',
92
+ args: [],
93
+ displayName: 'ChatGPT',
94
+ description: 'ChatGPT in your terminal (Go implementation)',
95
+ website: 'https://github.com/j178/chatgpt',
96
+ checkInstalled: async () => await commandExists('chatgpt')
97
+ },
98
+ 'sgpt': {
99
+ key: 'sgpt',
100
+ command: 'sgpt',
101
+ args: ['--repl', 'temp'],
102
+ displayName: 'ShellGPT',
103
+ description: 'ChatGPT-powered shell assistant with REPL mode',
104
+ website: 'https://github.com/TheR1D/shell_gpt',
105
+ checkInstalled: async () => await commandExists('sgpt')
106
+ },
107
+ 'mentat': {
108
+ key: 'mentat',
109
+ command: 'mentat',
110
+ args: [],
111
+ displayName: 'Mentat',
112
+ description: 'AI coding assistant with Git integration',
113
+ website: 'https://www.mentat.ai',
114
+ checkInstalled: async () => await commandExists('mentat')
115
+ },
116
+ 'grok': {
117
+ key: 'grok',
118
+ command: 'grok',
119
+ args: [],
120
+ displayName: 'Grok',
121
+ description: 'xAI\'s Grok AI assistant (by Elon Musk)',
122
+ website: 'https://grok.x.ai',
123
+ checkInstalled: async () => await commandExists('grok')
124
+ },
125
+ 'ollama': {
126
+ key: 'ollama',
127
+ command: 'ollama',
128
+ args: ['run', 'codellama'],
129
+ displayName: 'Ollama',
130
+ description: 'Run LLMs locally (CodeLlama, Llama, etc)',
131
+ website: 'https://ollama.ai',
132
+ checkInstalled: async () => await commandExists('ollama')
133
+ },
134
+ 'openhands': {
135
+ key: 'openhands',
136
+ command: 'openhands',
137
+ args: [],
138
+ displayName: 'OpenHands',
139
+ description: 'Open-source AI software engineer (formerly OpenDevin)',
140
+ website: 'https://github.com/All-Hands-AI/OpenHands',
141
+ checkInstalled: async () => await commandExists('openhands')
142
+ },
143
+ 'opencode': {
144
+ key: 'opencode',
145
+ command: 'opencode',
146
+ args: [],
147
+ displayName: 'OpenCode',
148
+ description: 'Open-source AI coding agent with LSP integration and 75+ LLM providers',
149
+ website: 'https://opencode.ai',
150
+ checkInstalled: async () => await commandExists('opencode')
151
+ },
152
+ 'blackbox': {
153
+ key: 'blackbox',
154
+ command: 'blackboxai',
155
+ args: [],
156
+ displayName: 'Blackbox AI',
157
+ description: 'AI coding assistant with debugging & file editing',
158
+ website: 'https://blackbox.ai',
159
+ checkInstalled: async () => await commandExists('blackboxai')
160
+ },
161
+ 'amazon-q': {
162
+ key: 'amazon-q',
163
+ command: 'q',
164
+ args: [],
165
+ displayName: 'Amazon Q',
166
+ description: 'AWS\'s AI coding companion with free tier',
167
+ website: 'https://aws.amazon.com/q/developer',
168
+ checkInstalled: async () => await commandExists('q')
169
+ },
170
+ 'pi': {
171
+ key: 'pi',
172
+ command: 'pi',
173
+ args: [],
174
+ displayName: 'Pi',
175
+ description: 'Minimal AI coding agent with extensions, skills, and 15+ LLM providers',
176
+ website: 'https://shittycodingagent.ai',
177
+ checkInstalled: async () => await commandExists('pi')
178
+ },
179
+ 'kilo': {
180
+ key: 'kilo',
181
+ command: 'kilo',
182
+ args: [],
183
+ displayName: 'Kilo',
184
+ description: 'Agentic engineering CLI with 500+ models and parallel mode',
185
+ website: 'https://kilo.ai',
186
+ checkInstalled: async () => await commandExists('kilo')
187
+ },
188
+ 'qodercli': {
189
+ key: 'qodercli',
190
+ command: 'qodercli',
191
+ args: [],
192
+ displayName: 'Qoder',
193
+ description: 'Qoder AI coding assistant with interactive CLI',
194
+ website: 'https://qoder.com',
195
+ checkInstalled: async () => await commandExists('qodercli')
196
+ },
197
+ 'demo': {
198
+ key: 'demo',
199
+ command: 'node',
200
+ args: [require('path').join(__dirname, 'demo', 'index.js')],
201
+ displayName: 'Demo',
202
+ description: 'Interactive demo for testing (no AI installation required)',
203
+ website: 'https://gitee.com/next2012/glad',
204
+ checkInstalled: async () => true // Always available
205
+ }
206
+ };
207
+
208
+ // Check if command exists
209
+ async function commandExists(command) {
210
+ try {
211
+ const isWindows = process.platform === 'win32';
212
+ const checkCommand = isWindows ? `where ${command}` : `command -v ${command}`;
213
+ const { stdout, stderr } = await execAsync(checkCommand, { timeout: 5000 });
214
+ logger.debugInfo(`[tool-detect] command exists: ${command}; stdout="${preview(stdout)}"; stderr="${preview(stderr)}"`);
215
+ return true;
216
+ } catch (err) {
217
+ logger.debugInfo(`[tool-detect] command missing: ${command}; error="${preview(err.message)}"; stdout="${preview(err.stdout)}"; stderr="${preview(err.stderr)}"`);
218
+ return false;
219
+ }
220
+ }
221
+
222
+ // Get tool version
223
+ async function getToolVersion(tool) {
224
+ // Try --version first
225
+ try {
226
+ const { stdout, stderr } = await execAsync(`${tool.command} --version 2>&1`, { timeout: 8000 });
227
+ logger.debugInfo(`[tool-version] ${tool.displayName} --version stdout="${preview(stdout)}"; stderr="${preview(stderr)}"`);
228
+ const version = parseVersion(stdout);
229
+ if (version !== 'unknown') {
230
+ return version;
231
+ }
232
+ } catch (err) {
233
+ logger.debugInfo(`[tool-version] ${tool.displayName} --version failed: ${preview(err.message)}; stdout="${preview(err.stdout)}"; stderr="${preview(err.stderr)}"`);
234
+ // Ignore error, will try -v next
235
+ }
236
+
237
+ // Try -v as fallback
238
+ try {
239
+ const { stdout, stderr } = await execAsync(`${tool.command} -v 2>&1`, { timeout: 8000 });
240
+ logger.debugInfo(`[tool-version] ${tool.displayName} -v stdout="${preview(stdout)}"; stderr="${preview(stderr)}"`);
241
+ const version = parseVersion(stdout);
242
+ logger.debugInfo(`[tool-version] ${tool.displayName} parsed version="${version}"`);
243
+ return version;
244
+ } catch (err) {
245
+ logger.debugInfo(`[tool-version] ${tool.displayName} -v failed: ${preview(err.message)}; stdout="${preview(err.stdout)}"; stderr="${preview(err.stderr)}"`);
246
+ return 'unknown';
247
+ }
248
+ }
249
+
250
+ // Parse version from output
251
+ function parseVersion(output) {
252
+ const versionMatch = output.match(/(\d+\.\d+\.\d+)/);
253
+ if (versionMatch) {
254
+ return versionMatch[1];
255
+ }
256
+
257
+ const simpleMatch = output.match(/(\d+\.\d+)/);
258
+ if (simpleMatch) {
259
+ return simpleMatch[1];
260
+ }
261
+
262
+ return 'unknown';
263
+ }
264
+
265
+ // Get tool by key
266
+ function getToolByKey(key) {
267
+ // Normalize key
268
+ const normalizedKey = key.toLowerCase().replace(/\s+/g, '-');
269
+
270
+ // Try exact match
271
+ if (AI_TOOLS[normalizedKey]) {
272
+ return AI_TOOLS[normalizedKey];
273
+ }
274
+
275
+ // Try fuzzy match
276
+ for (const [toolKey, tool] of Object.entries(AI_TOOLS)) {
277
+ if (tool.displayName.toLowerCase() === key.toLowerCase()) {
278
+ return tool;
279
+ }
280
+ if (tool.command === key) {
281
+ return tool;
282
+ }
283
+ }
284
+
285
+ return null;
286
+ }
287
+
288
+ // Get all tools
289
+ function getAllTools() {
290
+ return Object.values(AI_TOOLS);
291
+ }
292
+
293
+ module.exports = {
294
+ AI_TOOLS,
295
+ commandExists,
296
+ getToolVersion,
297
+ parseVersion,
298
+ getToolByKey,
299
+ getAllTools
300
+ };
@@ -0,0 +1,78 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, setConfig, getConfigPath } = require('../config/manager');
3
+ const logger = require('../utils/logger');
4
+
5
+ async function configShowCommand() {
6
+ const config = getConfig();
7
+
8
+ console.log(chalk.bold('Glad Configuration:'));
9
+ console.log('');
10
+ console.log(chalk.bold.cyan('User Settings:'));
11
+ console.log(` Default AI: ${config.defaultAI || '(auto-detect)'}`);
12
+ console.log('');
13
+ console.log(chalk.bold.cyan('System:'));
14
+ console.log(` Config file: ${chalk.gray(getConfigPath())}`);
15
+ console.log(` Last updated: ${config.lastUpdated || 'Never'}`);
16
+ console.log('');
17
+ console.log(`To change settings: ${chalk.cyan('glad config set <key> <value>')}`);
18
+ }
19
+
20
+ async function configGetCommand(key) {
21
+ if (!key) {
22
+ return configShowCommand();
23
+ }
24
+
25
+ const value = getConfig(key);
26
+
27
+ if (value === undefined) {
28
+ console.error(chalk.red(`Unknown config key: ${key}`));
29
+ console.error('');
30
+ console.error('Available keys: defaultAI');
31
+ return;
32
+ }
33
+
34
+ console.log(value);
35
+ }
36
+
37
+ async function configSetCommand(key, value) {
38
+ if (!key || !value) {
39
+ console.error(chalk.red('Usage: glad config set <key> <value>'));
40
+ console.error('');
41
+ console.error('Examples:');
42
+ console.error(chalk.cyan(' glad config set defaultAI aider'));
43
+ return;
44
+ }
45
+
46
+ const validKeys = ['defaultAI'];
47
+
48
+ if (!validKeys.includes(key)) {
49
+ console.error(chalk.red(`Invalid config key: ${key}`));
50
+ console.error('');
51
+ console.error(`Valid keys: ${validKeys.join(', ')}`);
52
+ return;
53
+ }
54
+
55
+ setConfig(key, value);
56
+ logger.success(`Config updated: ${key} = ${value}`);
57
+ }
58
+
59
+ async function configCommand(action, key, value) {
60
+ if (!action) {
61
+ return configShowCommand();
62
+ }
63
+
64
+ switch (action) {
65
+ case 'get':
66
+ await configGetCommand(key);
67
+ break;
68
+
69
+ case 'set':
70
+ await configSetCommand(key, value);
71
+ break;
72
+
73
+ default:
74
+ await configGetCommand(action);
75
+ }
76
+ }
77
+
78
+ module.exports = configCommand;
@@ -0,0 +1,128 @@
1
+ const chalk = require('chalk');
2
+ const { getAllTools, getToolByKey } = require('../ai-tools/registry');
3
+ const { detectInstalledTools } = require('../ai-tools/detector');
4
+
5
+ async function toolsListCommand() {
6
+ console.log(chalk.bold('Available AI Tools:'));
7
+ console.log('');
8
+
9
+ const allTools = getAllTools();
10
+ const installedTools = await detectInstalledTools();
11
+
12
+ const installedKeys = new Set(installedTools.map(t => t.key));
13
+
14
+ for (const tool of allTools) {
15
+ // Skip demo mode from tools list (it's a special hidden mode)
16
+ if (tool.key === 'demo') {
17
+ continue;
18
+ }
19
+
20
+ const isInstalled = installedKeys.has(tool.key);
21
+ const icon = isInstalled ? chalk.green('✓') : chalk.red('✗');
22
+ const status = isInstalled ? chalk.green('installed') : chalk.gray('not installed');
23
+
24
+ const installedTool = installedTools.find(t => t.key === tool.key);
25
+ const version = installedTool ? ` v${installedTool.version}` : '';
26
+
27
+ console.log(` ${icon} ${chalk.bold(tool.displayName)} (${tool.command})${version} - ${status}`);
28
+ }
29
+
30
+ console.log('');
31
+ console.log(`Use ${chalk.cyan('glad')} and choose a tool from the Web UI, or start Glad in your target directory`);
32
+ }
33
+
34
+ async function toolsDetectCommand() {
35
+ console.log(chalk.bold('🔍 Detecting installed AI tools...'));
36
+ console.log('');
37
+
38
+ const installedTools = await detectInstalledTools();
39
+
40
+ if (installedTools.length === 0) {
41
+ console.log(chalk.yellow('No AI tools found'));
42
+ console.log('');
43
+ console.log('Install an AI coding assistant:');
44
+ console.log(' • Claude Code: https://docs.claude.com');
45
+ console.log(' • Aider: pip install aider-chat');
46
+ console.log(' • GitHub Copilot: gh extension install github/gh-copilot');
47
+ return;
48
+ }
49
+
50
+ console.log(chalk.green(`Found ${installedTools.length} AI tool${installedTools.length > 1 ? 's' : ''}:`));
51
+ console.log('');
52
+
53
+ installedTools.forEach(tool => {
54
+ console.log(` • ${chalk.bold(tool.displayName)} v${tool.version}`);
55
+ });
56
+
57
+ console.log('');
58
+ if (installedTools.length === 1) {
59
+ console.log(chalk.cyan(`Recommended: ${installedTools[0].displayName}`));
60
+ }
61
+ }
62
+
63
+ async function toolsInfoCommand(toolName) {
64
+ if (!toolName) {
65
+ console.error(chalk.red('Please specify a tool name'));
66
+ console.error('');
67
+ console.error(`Usage: ${chalk.cyan('glad tools info <tool-name>')}`);
68
+ return;
69
+ }
70
+
71
+ const tool = getToolByKey(toolName);
72
+
73
+ if (!tool) {
74
+ console.error(chalk.red(`Unknown tool: ${toolName}`));
75
+ console.error('');
76
+ console.error(`Use ${chalk.cyan('glad tools list')} to see available tools`);
77
+ return;
78
+ }
79
+
80
+ console.log(chalk.bold(tool.displayName));
81
+ console.log('─'.repeat(tool.displayName.length));
82
+ console.log(`${chalk.gray('Command:')} ${tool.command}`);
83
+ console.log(`${chalk.gray('Description:')} ${tool.description}`);
84
+ console.log(`${chalk.gray('Website:')} ${tool.website}`);
85
+
86
+ const { isToolInstalled } = require('../ai-tools/detector');
87
+ const result = await isToolInstalled(tool.key);
88
+
89
+ if (result.installed) {
90
+ console.log(`${chalk.gray('Installed:')} ${chalk.green('✓ Yes')} (v${result.tool.version})`);
91
+ } else {
92
+ console.log(`${chalk.gray('Installed:')} ${chalk.red('✗ No')}`);
93
+ }
94
+
95
+ console.log('');
96
+ console.log(chalk.bold('Example usage:'));
97
+ console.log(chalk.cyan(` glad`));
98
+
99
+ if (tool.key === 'aider') {
100
+ console.log(chalk.cyan(' glad /path/to/project'));
101
+ }
102
+ }
103
+
104
+ async function toolsCommand(action, toolName) {
105
+ switch (action) {
106
+ case 'list':
107
+ await toolsListCommand();
108
+ break;
109
+
110
+ case 'detect':
111
+ await toolsDetectCommand();
112
+ break;
113
+
114
+ case 'info':
115
+ await toolsInfoCommand(toolName);
116
+ break;
117
+
118
+ default:
119
+ console.error(chalk.red(`Unknown action: ${action}`));
120
+ console.error('');
121
+ console.error('Available actions:');
122
+ console.error(chalk.cyan(' glad tools list'));
123
+ console.error(chalk.cyan(' glad tools detect'));
124
+ console.error(chalk.cyan(' glad tools info <tool-name>'));
125
+ }
126
+ }
127
+
128
+ module.exports = toolsCommand;