@ace-sdk/cli
Version:
ACE CLI - Command-line tool for intelligent pattern learning and playbook management
187 lines ⢠6.91 kB
JavaScript
/**
* Health diagnostics command
*/
import { existsSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import { globalOptions } from '../cli.js';
import { getConfig } from '../types/config.js';
import { ACEServerClient } from '../services/server-client.js';
import { Logger } from '../services/logger.js';
import chalk from 'chalk';
/**
* Run diagnostics on ACE configuration and connectivity
*/
export async function doctorCommand() {
const logger = new Logger(globalOptions);
const results = [];
// Check 1: Config file exists
let spinner = logger.spinner('Checking configuration file...');
const configPath = join(homedir(), '.ace', 'config.json');
if (existsSync(configPath)) {
results.push({
check: 'Config File',
status: 'pass',
message: `Found at ${configPath}`
});
spinner?.succeed('Configuration file found');
}
else {
results.push({
check: 'Config File',
status: 'fail',
message: 'Configuration file not found. Run "ce-ace config" to set up.'
});
spinner?.fail('Configuration file not found');
}
// Check 2: Config is valid
spinner = logger.spinner('Validating configuration...');
let config;
try {
config = getConfig();
results.push({
check: 'Config Validity',
status: 'pass',
message: 'Configuration is valid',
details: {
serverUrl: config.serverUrl,
projectId: config.projectId,
hasApiToken: !!config.apiToken
}
});
spinner?.succeed('Configuration is valid');
}
catch (error) {
results.push({
check: 'Config Validity',
status: 'fail',
message: error instanceof Error ? error.message : String(error)
});
spinner?.fail('Configuration is invalid');
}
// Check 3: Server connectivity
if (config) {
spinner = logger.spinner('Testing server connectivity...');
try {
const client = new ACEServerClient(config, logger);
// Try to get playbook analytics (minimal request)
await client.getAnalytics();
results.push({
check: 'Server Connectivity',
status: 'pass',
message: `Connected to ${config.serverUrl}`
});
spinner?.succeed('Server is reachable');
}
catch (error) {
results.push({
check: 'Server Connectivity',
status: 'fail',
message: error instanceof Error ? error.message : String(error),
details: {
serverUrl: config.serverUrl
}
});
spinner?.fail('Cannot reach server');
}
// Check 4: API token validity
spinner = logger.spinner('Validating API token...');
try {
const client = new ACEServerClient(config, logger);
// Getting playbook also validates the token
await client.getPlaybook({ forceRefresh: false, include_metadata: false });
results.push({
check: 'API Token',
status: 'pass',
message: 'API token is valid'
});
spinner?.succeed('API token is valid');
}
catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error);
if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) {
results.push({
check: 'API Token',
status: 'fail',
message: 'API token is invalid or expired'
});
spinner?.fail('API token is invalid');
}
else {
results.push({
check: 'API Token',
status: 'warn',
message: 'Could not validate API token',
details: { error: errorMsg }
});
spinner?.warn('Could not validate API token');
}
}
// Check 5: Project/org existence
spinner = logger.spinner('Verifying project access...');
try {
const client = new ACEServerClient(config, logger);
const analytics = await client.getAnalytics();
results.push({
check: 'Project Access',
status: 'pass',
message: `Project ${config.projectId} is accessible`,
details: {
totalBullets: analytics.total_bullets || 0
}
});
spinner?.succeed('Project is accessible');
}
catch (error) {
results.push({
check: 'Project Access',
status: 'fail',
message: `Cannot access project ${config.projectId}`,
details: {
error: error instanceof Error ? error.message : String(error)
}
});
spinner?.fail('Project is not accessible');
}
}
// Output results
if (logger.isJson()) {
logger.output({
timestamp: new Date().toISOString(),
results,
summary: {
total: results.length,
passed: results.filter(r => r.status === 'pass').length,
failed: results.filter(r => r.status === 'fail').length,
warnings: results.filter(r => r.status === 'warn').length
}
});
}
else {
logger.info(chalk.bold('\nš Diagnostic Results\n'));
results.forEach(result => {
const symbol = result.status === 'pass' ? chalk.green('ā') :
result.status === 'fail' ? chalk.red('ā') :
chalk.yellow('ā ');
logger.info(`${symbol} ${chalk.bold(result.check)}: ${result.message}`);
if (result.details && logger.isVerbose()) {
logger.debug(` ${JSON.stringify(result.details, null, 2)}`);
}
});
const passed = results.filter(r => r.status === 'pass').length;
const failed = results.filter(r => r.status === 'fail').length;
const warned = results.filter(r => r.status === 'warn').length;
logger.info('');
logger.info(chalk.bold('Summary:'));
logger.info(` ${chalk.green('ā')} Passed: ${passed}`);
if (failed > 0)
logger.info(` ${chalk.red('ā')} Failed: ${failed}`);
if (warned > 0)
logger.info(` ${chalk.yellow('ā ')} Warnings: ${warned}`);
logger.info('');
if (failed > 0) {
process.exit(1);
}
}
}
//# sourceMappingURL=doctor.js.map