@kaitranntt/ccs 4.4.0 → 5.0.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 +14 -7
- package/VERSION +1 -1
- package/config/base-agy.settings.json +10 -0
- package/config/base-codex.settings.json +10 -0
- package/config/base-gemini.settings.json +10 -0
- package/dist/auth/auth-commands.d.ts +52 -0
- package/dist/auth/auth-commands.d.ts.map +1 -0
- package/dist/auth/auth-commands.js +479 -0
- package/dist/auth/auth-commands.js.map +1 -0
- package/dist/auth/profile-detector.d.ts +68 -0
- package/dist/auth/profile-detector.d.ts.map +1 -0
- package/dist/auth/profile-detector.js +209 -0
- package/dist/auth/profile-detector.js.map +1 -0
- package/dist/auth/profile-registry.d.ts +60 -0
- package/dist/auth/profile-registry.d.ts.map +1 -0
- package/dist/auth/profile-registry.js +188 -0
- package/dist/auth/profile-registry.js.map +1 -0
- package/dist/ccs.d.ts +10 -0
- package/dist/ccs.d.ts.map +1 -0
- package/dist/ccs.js +320 -0
- package/dist/ccs.js.map +1 -0
- package/dist/cliproxy/auth-handler.d.ts +93 -0
- package/dist/cliproxy/auth-handler.d.ts.map +1 -0
- package/dist/cliproxy/auth-handler.js +402 -0
- package/dist/cliproxy/auth-handler.js.map +1 -0
- package/dist/cliproxy/base-config-loader.d.ts +42 -0
- package/dist/cliproxy/base-config-loader.d.ts.map +1 -0
- package/dist/cliproxy/base-config-loader.js +123 -0
- package/dist/cliproxy/base-config-loader.js.map +1 -0
- package/dist/cliproxy/binary-manager.d.ts +104 -0
- package/dist/cliproxy/binary-manager.d.ts.map +1 -0
- package/dist/cliproxy/binary-manager.js +567 -0
- package/dist/cliproxy/binary-manager.js.map +1 -0
- package/dist/cliproxy/cliproxy-executor.d.ts +33 -0
- package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -0
- package/dist/cliproxy/cliproxy-executor.js +297 -0
- package/dist/cliproxy/cliproxy-executor.js.map +1 -0
- package/dist/cliproxy/config-generator.d.ts +89 -0
- package/dist/cliproxy/config-generator.d.ts.map +1 -0
- package/dist/cliproxy/config-generator.js +263 -0
- package/dist/cliproxy/config-generator.js.map +1 -0
- package/dist/cliproxy/index.d.ts +13 -0
- package/dist/cliproxy/index.d.ts.map +1 -0
- package/dist/cliproxy/index.js +62 -0
- package/dist/cliproxy/index.js.map +1 -0
- package/dist/cliproxy/platform-detector.d.ts +48 -0
- package/dist/cliproxy/platform-detector.d.ts.map +1 -0
- package/dist/cliproxy/platform-detector.js +118 -0
- package/dist/cliproxy/platform-detector.js.map +1 -0
- package/dist/cliproxy/types.d.ts +169 -0
- package/dist/cliproxy/types.d.ts.map +1 -0
- package/dist/cliproxy/types.js +7 -0
- package/dist/cliproxy/types.js.map +1 -0
- package/dist/commands/doctor-command.d.ts +10 -0
- package/dist/commands/doctor-command.d.ts.map +1 -0
- package/dist/commands/doctor-command.js +44 -0
- package/dist/commands/doctor-command.js.map +1 -0
- package/dist/commands/help-command.d.ts +5 -0
- package/dist/commands/help-command.d.ts.map +1 -0
- package/dist/commands/help-command.js +104 -0
- package/dist/commands/help-command.js.map +1 -0
- package/dist/commands/install-command.d.ts +14 -0
- package/dist/commands/install-command.d.ts.map +1 -0
- package/dist/commands/install-command.js +39 -0
- package/dist/commands/install-command.js.map +1 -0
- package/dist/commands/shell-completion-command.d.ts +10 -0
- package/dist/commands/shell-completion-command.d.ts.map +1 -0
- package/dist/commands/shell-completion-command.js +85 -0
- package/dist/commands/shell-completion-command.js.map +1 -0
- package/dist/commands/sync-command.d.ts +10 -0
- package/dist/commands/sync-command.d.ts.map +1 -0
- package/dist/commands/sync-command.js +59 -0
- package/dist/commands/sync-command.js.map +1 -0
- package/dist/commands/update-command.d.ts +12 -0
- package/dist/commands/update-command.d.ts.map +1 -0
- package/dist/commands/update-command.js +295 -0
- package/dist/commands/update-command.js.map +1 -0
- package/dist/commands/version-command.d.ts +10 -0
- package/dist/commands/version-command.d.ts.map +1 -0
- package/dist/commands/version-command.js +100 -0
- package/dist/commands/version-command.js.map +1 -0
- package/dist/delegation/delegation-handler.d.ts +60 -0
- package/dist/delegation/delegation-handler.d.ts.map +1 -0
- package/dist/delegation/delegation-handler.js +174 -0
- package/dist/delegation/delegation-handler.js.map +1 -0
- package/dist/delegation/headless-executor.d.ts +114 -0
- package/dist/delegation/headless-executor.d.ts.map +1 -0
- package/dist/delegation/headless-executor.js +562 -0
- package/dist/delegation/headless-executor.js.map +1 -0
- package/dist/delegation/result-formatter.d.ts +108 -0
- package/dist/delegation/result-formatter.d.ts.map +1 -0
- package/dist/delegation/result-formatter.js +391 -0
- package/dist/delegation/result-formatter.js.map +1 -0
- package/dist/delegation/session-manager.d.ts +58 -0
- package/dist/delegation/session-manager.d.ts.map +1 -0
- package/dist/delegation/session-manager.js +153 -0
- package/dist/delegation/session-manager.js.map +1 -0
- package/dist/delegation/settings-parser.d.ts +31 -0
- package/dist/delegation/settings-parser.d.ts.map +1 -0
- package/dist/delegation/settings-parser.js +107 -0
- package/dist/delegation/settings-parser.js.map +1 -0
- package/dist/glmt/delta-accumulator.d.ts +210 -0
- package/dist/glmt/delta-accumulator.d.ts.map +1 -0
- package/dist/glmt/delta-accumulator.js +351 -0
- package/dist/glmt/delta-accumulator.js.map +1 -0
- package/dist/glmt/glmt-proxy.d.ts +72 -0
- package/dist/glmt/glmt-proxy.d.ts.map +1 -0
- package/dist/glmt/glmt-proxy.js +427 -0
- package/dist/glmt/glmt-proxy.js.map +1 -0
- package/dist/glmt/glmt-transformer.d.ts +265 -0
- package/dist/glmt/glmt-transformer.d.ts.map +1 -0
- package/dist/glmt/glmt-transformer.js +832 -0
- package/dist/glmt/glmt-transformer.js.map +1 -0
- package/dist/glmt/locale-enforcer.d.ts +38 -0
- package/dist/glmt/locale-enforcer.d.ts.map +1 -0
- package/dist/glmt/locale-enforcer.js +69 -0
- package/dist/glmt/locale-enforcer.js.map +1 -0
- package/dist/glmt/reasoning-enforcer.d.ts +52 -0
- package/dist/glmt/reasoning-enforcer.d.ts.map +1 -0
- package/dist/glmt/reasoning-enforcer.js +151 -0
- package/dist/glmt/reasoning-enforcer.js.map +1 -0
- package/dist/glmt/sse-parser.d.ts +47 -0
- package/dist/glmt/sse-parser.d.ts.map +1 -0
- package/dist/glmt/sse-parser.js +93 -0
- package/dist/glmt/sse-parser.js.map +1 -0
- package/dist/management/doctor.d.ts +104 -0
- package/dist/management/doctor.d.ts.map +1 -0
- package/dist/management/doctor.js +673 -0
- package/dist/management/doctor.js.map +1 -0
- package/dist/management/instance-manager.d.ts +57 -0
- package/dist/management/instance-manager.d.ts.map +1 -0
- package/dist/management/instance-manager.js +195 -0
- package/dist/management/instance-manager.js.map +1 -0
- package/dist/management/recovery-manager.d.ts +39 -0
- package/dist/management/recovery-manager.d.ts.map +1 -0
- package/dist/management/recovery-manager.js +141 -0
- package/dist/management/recovery-manager.js.map +1 -0
- package/dist/management/shared-manager.d.ts +47 -0
- package/dist/management/shared-manager.d.ts.map +1 -0
- package/dist/management/shared-manager.js +388 -0
- package/dist/management/shared-manager.js.map +1 -0
- package/dist/types/cli.d.ts +50 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +16 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/config.d.ts +51 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +26 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/delegation.d.ts +61 -0
- package/dist/types/delegation.d.ts.map +1 -0
- package/dist/types/delegation.js +6 -0
- package/dist/types/delegation.js.map +1 -0
- package/dist/types/glmt.d.ts +95 -0
- package/dist/types/glmt.d.ts.map +1 -0
- package/dist/types/glmt.js +7 -0
- package/dist/types/glmt.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/utils.d.ts +36 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +22 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/utils/claude-detector.d.ts +14 -0
- package/dist/utils/claude-detector.d.ts.map +1 -0
- package/dist/utils/claude-detector.js +112 -0
- package/dist/utils/claude-detector.js.map +1 -0
- package/dist/utils/claude-dir-installer.d.ts +46 -0
- package/dist/utils/claude-dir-installer.d.ts.map +1 -0
- package/dist/utils/claude-dir-installer.js +289 -0
- package/dist/utils/claude-dir-installer.js.map +1 -0
- package/dist/utils/claude-symlink-manager.d.ts +61 -0
- package/dist/utils/claude-symlink-manager.d.ts.map +1 -0
- package/dist/utils/claude-symlink-manager.js +291 -0
- package/dist/utils/claude-symlink-manager.js.map +1 -0
- package/dist/utils/config-manager.d.ts +32 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +143 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/delegation-validator.d.ts +39 -0
- package/dist/utils/delegation-validator.d.ts.map +1 -0
- package/dist/utils/delegation-validator.js +161 -0
- package/dist/utils/delegation-validator.js.map +1 -0
- package/dist/utils/error-codes.d.ts +36 -0
- package/dist/utils/error-codes.d.ts.map +1 -0
- package/dist/utils/error-codes.js +63 -0
- package/dist/utils/error-codes.js.map +1 -0
- package/dist/utils/error-manager.d.ts +59 -0
- package/dist/utils/error-manager.d.ts.map +1 -0
- package/dist/utils/error-manager.js +228 -0
- package/dist/utils/error-manager.js.map +1 -0
- package/dist/utils/helpers.d.ts +27 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +150 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/package-manager-detector.d.ts +14 -0
- package/dist/utils/package-manager-detector.d.ts.map +1 -0
- package/dist/utils/package-manager-detector.js +162 -0
- package/dist/utils/package-manager-detector.js.map +1 -0
- package/dist/utils/progress-indicator.d.ts +52 -0
- package/dist/utils/progress-indicator.d.ts.map +1 -0
- package/dist/utils/progress-indicator.js +102 -0
- package/dist/utils/progress-indicator.js.map +1 -0
- package/dist/utils/prompt.d.ts +29 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +116 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/shell-completion.d.ts +52 -0
- package/dist/utils/shell-completion.d.ts.map +1 -0
- package/dist/utils/shell-completion.js +231 -0
- package/dist/utils/shell-completion.js.map +1 -0
- package/dist/utils/shell-executor.d.ts +15 -0
- package/dist/utils/shell-executor.d.ts.map +1 -0
- package/dist/utils/shell-executor.js +57 -0
- package/dist/utils/shell-executor.js.map +1 -0
- package/dist/utils/update-checker.d.ts +48 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +241 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/lib/ccs +21 -1907
- package/lib/ccs.ps1 +26 -1800
- package/lib/error-codes.ps1 +2 -1
- package/lib/prompt.ps1 +2 -2
- package/package.json +31 -11
- package/scripts/add-shebang.js +39 -0
- package/scripts/bump-version.sh +25 -37
- package/scripts/dev-install.sh +32 -11
- package/scripts/postinstall.js +29 -29
- package/bin/auth/auth-commands.js +0 -499
- package/bin/auth/profile-detector.js +0 -204
- package/bin/auth/profile-registry.js +0 -225
- package/bin/ccs.js +0 -1034
- package/bin/delegation/README.md +0 -191
- package/bin/delegation/delegation-handler.js +0 -212
- package/bin/delegation/headless-executor.js +0 -618
- package/bin/delegation/result-formatter.js +0 -485
- package/bin/delegation/session-manager.js +0 -157
- package/bin/delegation/settings-parser.js +0 -109
- package/bin/glmt/delta-accumulator.js +0 -276
- package/bin/glmt/glmt-proxy.js +0 -495
- package/bin/glmt/glmt-transformer.js +0 -999
- package/bin/glmt/locale-enforcer.js +0 -72
- package/bin/glmt/reasoning-enforcer.js +0 -173
- package/bin/glmt/sse-parser.js +0 -96
- package/bin/management/doctor.js +0 -721
- package/bin/management/instance-manager.js +0 -202
- package/bin/management/recovery-manager.js +0 -135
- package/bin/management/shared-manager.js +0 -402
- package/bin/utils/claude-detector.js +0 -73
- package/bin/utils/claude-dir-installer.js +0 -283
- package/bin/utils/claude-symlink-manager.js +0 -289
- package/bin/utils/config-manager.js +0 -103
- package/bin/utils/delegation-validator.js +0 -154
- package/bin/utils/error-codes.js +0 -59
- package/bin/utils/error-manager.js +0 -165
- package/bin/utils/helpers.js +0 -136
- package/bin/utils/progress-indicator.js +0 -111
- package/bin/utils/prompt.js +0 -134
- package/bin/utils/shell-completion.js +0 -256
- package/bin/utils/update-checker.js +0 -243
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CCS Health Check and Diagnostics
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
|
+
if (mod && mod.__esModule) return mod;
|
|
23
|
+
var result = {};
|
|
24
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
25
|
+
__setModuleDefault(result, mod);
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
29
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
30
|
+
};
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
const fs = __importStar(require("fs"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
34
|
+
const os = __importStar(require("os"));
|
|
35
|
+
const child_process_1 = require("child_process");
|
|
36
|
+
const helpers_1 = require("../utils/helpers");
|
|
37
|
+
const claude_detector_1 = require("../utils/claude-detector");
|
|
38
|
+
const package_json_1 = __importDefault(require("../../package.json"));
|
|
39
|
+
const cliproxy_1 = require("../cliproxy");
|
|
40
|
+
let ora;
|
|
41
|
+
try {
|
|
42
|
+
const oraModule = require('ora');
|
|
43
|
+
ora = oraModule.default || oraModule;
|
|
44
|
+
}
|
|
45
|
+
catch (_e) {
|
|
46
|
+
// ora not available, create fallback spinner that uses console.log
|
|
47
|
+
ora = function (text) {
|
|
48
|
+
return {
|
|
49
|
+
start: () => ({
|
|
50
|
+
succeed: (msg) => console.log(msg || `[OK] ${text}`),
|
|
51
|
+
fail: (msg) => console.log(msg || `[X] ${text}`),
|
|
52
|
+
warn: (msg) => console.log(msg || `[!] ${text}`),
|
|
53
|
+
info: (msg) => console.log(msg || `[i] ${text}`),
|
|
54
|
+
text: '',
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Import cli-table3
|
|
60
|
+
const Table = require('cli-table3');
|
|
61
|
+
/**
|
|
62
|
+
* Health check results
|
|
63
|
+
*/
|
|
64
|
+
class HealthCheck {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.checks = [];
|
|
67
|
+
this.warnings = [];
|
|
68
|
+
this.errors = [];
|
|
69
|
+
this.details = {};
|
|
70
|
+
}
|
|
71
|
+
addCheck(name, status, message = '', fix = undefined, details = undefined) {
|
|
72
|
+
this.checks.push({ name, status, message, fix });
|
|
73
|
+
if (status === 'error')
|
|
74
|
+
this.errors.push({ name, message, fix });
|
|
75
|
+
if (status === 'warning')
|
|
76
|
+
this.warnings.push({ name, message, fix });
|
|
77
|
+
// Store details for summary table
|
|
78
|
+
if (details) {
|
|
79
|
+
this.details[name] = details;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
hasErrors() {
|
|
83
|
+
return this.errors.length > 0;
|
|
84
|
+
}
|
|
85
|
+
hasWarnings() {
|
|
86
|
+
return this.warnings.length > 0;
|
|
87
|
+
}
|
|
88
|
+
isHealthy() {
|
|
89
|
+
return !this.hasErrors();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Doctor Class
|
|
94
|
+
*/
|
|
95
|
+
class Doctor {
|
|
96
|
+
constructor() {
|
|
97
|
+
this.homedir = os.homedir();
|
|
98
|
+
this.ccsDir = path.join(this.homedir, '.ccs');
|
|
99
|
+
this.claudeDir = path.join(this.homedir, '.claude');
|
|
100
|
+
this.results = new HealthCheck();
|
|
101
|
+
this.ccsVersion = package_json_1.default.version;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Run all health checks
|
|
105
|
+
*/
|
|
106
|
+
async runAllChecks() {
|
|
107
|
+
console.log((0, helpers_1.colored)('Running CCS Health Check...', 'cyan'));
|
|
108
|
+
console.log('');
|
|
109
|
+
// Store CCS version in details
|
|
110
|
+
this.results.details['CCS Version'] = { status: 'OK', info: `v${this.ccsVersion}` };
|
|
111
|
+
// Group 1: System
|
|
112
|
+
console.log((0, helpers_1.colored)('System:', 'bold'));
|
|
113
|
+
await this.checkClaudeCli();
|
|
114
|
+
this.checkCcsDirectory();
|
|
115
|
+
console.log('');
|
|
116
|
+
// Group 2: Configuration
|
|
117
|
+
console.log((0, helpers_1.colored)('Configuration:', 'bold'));
|
|
118
|
+
this.checkConfigFiles();
|
|
119
|
+
this.checkClaudeSettings();
|
|
120
|
+
console.log('');
|
|
121
|
+
// Group 3: Profiles & Delegation
|
|
122
|
+
console.log((0, helpers_1.colored)('Profiles & Delegation:', 'bold'));
|
|
123
|
+
this.checkProfiles();
|
|
124
|
+
this.checkInstances();
|
|
125
|
+
this.checkDelegation();
|
|
126
|
+
console.log('');
|
|
127
|
+
// Group 4: System Health
|
|
128
|
+
console.log((0, helpers_1.colored)('System Health:', 'bold'));
|
|
129
|
+
this.checkPermissions();
|
|
130
|
+
this.checkCcsSymlinks();
|
|
131
|
+
this.checkSettingsSymlinks();
|
|
132
|
+
console.log('');
|
|
133
|
+
// Group 5: CLIProxy (OAuth profiles)
|
|
134
|
+
console.log((0, helpers_1.colored)('CLIProxy (OAuth Profiles):', 'bold'));
|
|
135
|
+
await this.checkCLIProxy();
|
|
136
|
+
console.log('');
|
|
137
|
+
this.showReport();
|
|
138
|
+
return this.results;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check 1: Claude CLI availability
|
|
142
|
+
*/
|
|
143
|
+
async checkClaudeCli() {
|
|
144
|
+
const spinner = ora('Checking Claude CLI').start();
|
|
145
|
+
const claudeCli = (0, claude_detector_1.detectClaudeCli)();
|
|
146
|
+
if (!claudeCli) {
|
|
147
|
+
spinner.fail(` ${'Claude CLI'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Not found in PATH`);
|
|
148
|
+
this.results.addCheck('Claude CLI', 'error', 'Claude CLI not found in PATH', 'Install from: https://docs.claude.com/en/docs/claude-code/installation', { status: 'ERROR', info: 'Not installed' });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Try to execute claude --version
|
|
152
|
+
try {
|
|
153
|
+
const result = await new Promise((resolve, reject) => {
|
|
154
|
+
const child = (0, child_process_1.spawn)(claudeCli, ['--version'], {
|
|
155
|
+
stdio: 'pipe',
|
|
156
|
+
timeout: 5000,
|
|
157
|
+
});
|
|
158
|
+
let output = '';
|
|
159
|
+
child.stdout?.on('data', (data) => (output += data));
|
|
160
|
+
child.stderr?.on('data', (data) => (output += data));
|
|
161
|
+
child.on('close', (code) => {
|
|
162
|
+
if (code === 0)
|
|
163
|
+
resolve(output);
|
|
164
|
+
else
|
|
165
|
+
reject(new Error('Exit code ' + code));
|
|
166
|
+
});
|
|
167
|
+
child.on('error', reject);
|
|
168
|
+
});
|
|
169
|
+
// Extract version from output
|
|
170
|
+
const versionMatch = result.match(/(\d+\.\d+\.\d+)/);
|
|
171
|
+
const version = versionMatch ? versionMatch[1] : 'unknown';
|
|
172
|
+
spinner.succeed(` ${'Claude CLI'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${claudeCli} (v${version})`);
|
|
173
|
+
this.results.addCheck('Claude CLI', 'success', `Found: ${claudeCli}`, undefined, {
|
|
174
|
+
status: 'OK',
|
|
175
|
+
info: `v${version} (${claudeCli})`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch (_err) {
|
|
179
|
+
spinner.fail(` ${'Claude CLI'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Not found or not working`);
|
|
180
|
+
this.results.addCheck('Claude CLI', 'error', 'Claude CLI not found or not working', 'Install from: https://docs.claude.com/en/docs/claude-code/installation', { status: 'ERROR', info: 'Not installed' });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check 2: ~/.ccs/ directory
|
|
185
|
+
*/
|
|
186
|
+
checkCcsDirectory() {
|
|
187
|
+
const spinner = ora('Checking ~/.ccs/ directory').start();
|
|
188
|
+
if (fs.existsSync(this.ccsDir)) {
|
|
189
|
+
spinner.succeed(` ${'CCS Directory'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ~/.ccs/`);
|
|
190
|
+
this.results.addCheck('CCS Directory', 'success', undefined, undefined, {
|
|
191
|
+
status: 'OK',
|
|
192
|
+
info: '~/.ccs/',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
spinner.fail(` ${'CCS Directory'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Not found`);
|
|
197
|
+
this.results.addCheck('CCS Directory', 'error', '~/.ccs/ directory not found', 'Run: npm install -g @kaitranntt/ccs --force', { status: 'ERROR', info: 'Not found' });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check 3: Config files
|
|
202
|
+
*/
|
|
203
|
+
checkConfigFiles() {
|
|
204
|
+
const files = [
|
|
205
|
+
{ path: path.join(this.ccsDir, 'config.json'), name: 'config.json', key: 'config.json' },
|
|
206
|
+
{
|
|
207
|
+
path: path.join(this.ccsDir, 'glm.settings.json'),
|
|
208
|
+
name: 'glm.settings.json',
|
|
209
|
+
key: 'GLM Settings',
|
|
210
|
+
profile: 'glm',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
path: path.join(this.ccsDir, 'kimi.settings.json'),
|
|
214
|
+
name: 'kimi.settings.json',
|
|
215
|
+
key: 'Kimi Settings',
|
|
216
|
+
profile: 'kimi',
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
const { DelegationValidator } = require('../utils/delegation-validator');
|
|
220
|
+
for (const file of files) {
|
|
221
|
+
const spinner = ora(`Checking ${file.name}`).start();
|
|
222
|
+
if (!fs.existsSync(file.path)) {
|
|
223
|
+
spinner.fail(` ${file.name.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Not found`);
|
|
224
|
+
this.results.addCheck(file.name, 'error', `${file.name} not found`, 'Run: npm install -g @kaitranntt/ccs --force', { status: 'ERROR', info: 'Not found' });
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// Validate JSON
|
|
228
|
+
try {
|
|
229
|
+
const content = fs.readFileSync(file.path, 'utf8');
|
|
230
|
+
JSON.parse(content);
|
|
231
|
+
// Extract useful info based on file type
|
|
232
|
+
let info = 'Valid';
|
|
233
|
+
let status = 'OK';
|
|
234
|
+
if (file.profile) {
|
|
235
|
+
// For settings files, check if API key is configured
|
|
236
|
+
const validation = DelegationValidator.validate(file.profile);
|
|
237
|
+
if (validation.valid) {
|
|
238
|
+
info = 'Key configured';
|
|
239
|
+
status = 'OK';
|
|
240
|
+
}
|
|
241
|
+
else if (validation.error && validation.error.includes('placeholder')) {
|
|
242
|
+
info = 'Placeholder key (not configured)';
|
|
243
|
+
status = 'WARN';
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
info = 'Valid JSON';
|
|
247
|
+
status = 'OK';
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const statusIcon = status === 'OK' ? (0, helpers_1.colored)('[OK]', 'green') : (0, helpers_1.colored)('[!]', 'yellow');
|
|
251
|
+
if (status === 'WARN') {
|
|
252
|
+
spinner.warn(` ${file.name.padEnd(26)}${statusIcon} ${info}`);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
spinner.succeed(` ${file.name.padEnd(26)}${statusIcon} ${info}`);
|
|
256
|
+
}
|
|
257
|
+
this.results.addCheck(file.name, status === 'OK' ? 'success' : 'warning', undefined, undefined, {
|
|
258
|
+
status: status,
|
|
259
|
+
info: info,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
spinner.fail(` ${file.name.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Invalid JSON`);
|
|
264
|
+
this.results.addCheck(file.name, 'error', `Invalid JSON: ${e.message}`, `Backup and recreate: mv ${file.path} ${file.path}.backup && npm install -g @kaitranntt/ccs --force`, { status: 'ERROR', info: 'Invalid JSON' });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check 4: Claude settings
|
|
270
|
+
*/
|
|
271
|
+
checkClaudeSettings() {
|
|
272
|
+
const spinner = ora('Checking ~/.claude/settings.json').start();
|
|
273
|
+
const settingsPath = path.join(this.claudeDir, 'settings.json');
|
|
274
|
+
if (!fs.existsSync(settingsPath)) {
|
|
275
|
+
spinner.warn(` ${'~/.claude/settings.json'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Not found`);
|
|
276
|
+
this.results.addCheck('Claude Settings', 'warning', '~/.claude/settings.json not found', 'Run: claude /login');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// Validate JSON
|
|
280
|
+
try {
|
|
281
|
+
const content = fs.readFileSync(settingsPath, 'utf8');
|
|
282
|
+
JSON.parse(content);
|
|
283
|
+
spinner.succeed(` ${'~/.claude/settings.json'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')}`);
|
|
284
|
+
this.results.addCheck('Claude Settings', 'success');
|
|
285
|
+
}
|
|
286
|
+
catch (e) {
|
|
287
|
+
spinner.warn(` ${'~/.claude/settings.json'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Invalid JSON`);
|
|
288
|
+
this.results.addCheck('Claude Settings', 'warning', `Invalid JSON: ${e.message}`, 'Run: claude /login');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Check 5: Profile configurations
|
|
293
|
+
*/
|
|
294
|
+
checkProfiles() {
|
|
295
|
+
const spinner = ora('Checking profiles').start();
|
|
296
|
+
const configPath = path.join(this.ccsDir, 'config.json');
|
|
297
|
+
if (!fs.existsSync(configPath)) {
|
|
298
|
+
spinner.info(` ${'Profiles'.padEnd(26)}${(0, helpers_1.colored)('[SKIP]', 'cyan')} config.json not found`);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
303
|
+
if (!config.profiles || typeof config.profiles !== 'object') {
|
|
304
|
+
spinner.fail(` ${'Profiles'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Missing profiles object`);
|
|
305
|
+
this.results.addCheck('Profiles', 'error', 'config.json missing profiles object', 'Run: npm install -g @kaitranntt/ccs --force', { status: 'ERROR', info: 'Missing profiles object' });
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const profileCount = Object.keys(config.profiles).length;
|
|
309
|
+
const profileNames = Object.keys(config.profiles).join(', ');
|
|
310
|
+
spinner.succeed(` ${'Profiles'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${profileCount} configured (${profileNames})`);
|
|
311
|
+
this.results.addCheck('Profiles', 'success', `${profileCount} profiles configured`, undefined, {
|
|
312
|
+
status: 'OK',
|
|
313
|
+
info: `${profileCount} configured (${profileNames.length > 30 ? profileNames.substring(0, 27) + '...' : profileNames})`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
catch (e) {
|
|
317
|
+
spinner.fail(` ${'Profiles'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} ${e.message}`);
|
|
318
|
+
this.results.addCheck('Profiles', 'error', e.message, undefined, {
|
|
319
|
+
status: 'ERROR',
|
|
320
|
+
info: e.message,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Check 6: Instance directories (account-based profiles)
|
|
326
|
+
*/
|
|
327
|
+
checkInstances() {
|
|
328
|
+
const spinner = ora('Checking instances').start();
|
|
329
|
+
const instancesDir = path.join(this.ccsDir, 'instances');
|
|
330
|
+
if (!fs.existsSync(instancesDir)) {
|
|
331
|
+
spinner.info(` ${'Instances'.padEnd(26)}${(0, helpers_1.colored)('[i]', 'cyan')} No account profiles`);
|
|
332
|
+
this.results.addCheck('Instances', 'success', 'No account profiles configured');
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const instances = fs.readdirSync(instancesDir).filter((name) => {
|
|
336
|
+
return fs.statSync(path.join(instancesDir, name)).isDirectory();
|
|
337
|
+
});
|
|
338
|
+
if (instances.length === 0) {
|
|
339
|
+
spinner.info(` ${'Instances'.padEnd(26)}${(0, helpers_1.colored)('[i]', 'cyan')} No account profiles`);
|
|
340
|
+
this.results.addCheck('Instances', 'success', 'No account profiles');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
spinner.succeed(` ${'Instances'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${instances.length} account profiles`);
|
|
344
|
+
this.results.addCheck('Instances', 'success', `${instances.length} account profiles`);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Check 7: Delegation system
|
|
348
|
+
*/
|
|
349
|
+
checkDelegation() {
|
|
350
|
+
const spinner = ora('Checking delegation').start();
|
|
351
|
+
// Check if delegation commands exist in ~/.ccs/.claude/commands/
|
|
352
|
+
const ccsClaudeCommandsDir = path.join(this.ccsDir, '.claude', 'commands');
|
|
353
|
+
const hasCcsCommand = fs.existsSync(path.join(ccsClaudeCommandsDir, 'ccs.md'));
|
|
354
|
+
const hasContinueCommand = fs.existsSync(path.join(ccsClaudeCommandsDir, 'ccs', 'continue.md'));
|
|
355
|
+
if (!hasCcsCommand || !hasContinueCommand) {
|
|
356
|
+
spinner.warn(` ${'Delegation'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Not installed`);
|
|
357
|
+
this.results.addCheck('Delegation', 'warning', 'Delegation commands not found', 'Install with: npm install -g @kaitranntt/ccs --force', { status: 'WARN', info: 'Not installed' });
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
// Check profile validity using DelegationValidator
|
|
361
|
+
const { DelegationValidator } = require('../utils/delegation-validator');
|
|
362
|
+
const readyProfiles = [];
|
|
363
|
+
for (const profile of ['glm', 'kimi']) {
|
|
364
|
+
const validation = DelegationValidator.validate(profile);
|
|
365
|
+
if (validation.valid) {
|
|
366
|
+
readyProfiles.push(profile);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (readyProfiles.length === 0) {
|
|
370
|
+
spinner.warn(` ${'Delegation'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} No profiles ready`);
|
|
371
|
+
this.results.addCheck('Delegation', 'warning', 'Delegation installed but no profiles configured', 'Configure profiles with valid API keys (not placeholders)', { status: 'WARN', info: 'No profiles ready' });
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
spinner.succeed(` ${'Delegation'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${readyProfiles.length} profiles ready (${readyProfiles.join(', ')})`);
|
|
375
|
+
this.results.addCheck('Delegation', 'success', `${readyProfiles.length} profile(s) ready: ${readyProfiles.join(', ')}`, undefined, { status: 'OK', info: `${readyProfiles.length} profiles ready` });
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Check 8: File permissions
|
|
379
|
+
*/
|
|
380
|
+
checkPermissions() {
|
|
381
|
+
const spinner = ora('Checking permissions').start();
|
|
382
|
+
const testFile = path.join(this.ccsDir, '.permission-test');
|
|
383
|
+
try {
|
|
384
|
+
fs.writeFileSync(testFile, 'test', 'utf8');
|
|
385
|
+
fs.unlinkSync(testFile);
|
|
386
|
+
spinner.succeed(` ${'Permissions'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} Write access verified`);
|
|
387
|
+
this.results.addCheck('Permissions', 'success', undefined, undefined, {
|
|
388
|
+
status: 'OK',
|
|
389
|
+
info: 'Write access verified',
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
catch (_e) {
|
|
393
|
+
spinner.fail(` ${'Permissions'.padEnd(26)}${(0, helpers_1.colored)('[X]', 'red')} Cannot write to ~/.ccs/`);
|
|
394
|
+
this.results.addCheck('Permissions', 'error', 'Cannot write to ~/.ccs/', 'Fix: sudo chown -R $USER ~/.ccs ~/.claude && chmod 755 ~/.ccs ~/.claude', { status: 'ERROR', info: 'Cannot write to ~/.ccs/' });
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Check 9: CCS symlinks to ~/.claude/
|
|
399
|
+
*/
|
|
400
|
+
checkCcsSymlinks() {
|
|
401
|
+
const spinner = ora('Checking CCS symlinks').start();
|
|
402
|
+
try {
|
|
403
|
+
const { ClaudeSymlinkManager } = require('../utils/claude-symlink-manager');
|
|
404
|
+
const manager = new ClaudeSymlinkManager();
|
|
405
|
+
const health = manager.checkHealth();
|
|
406
|
+
if (health.healthy) {
|
|
407
|
+
const itemCount = manager.ccsItems.length;
|
|
408
|
+
spinner.succeed(` ${'CCS Symlinks'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${itemCount}/${itemCount} items linked`);
|
|
409
|
+
this.results.addCheck('CCS Symlinks', 'success', 'All CCS items properly symlinked', undefined, {
|
|
410
|
+
status: 'OK',
|
|
411
|
+
info: `${itemCount}/${itemCount} items synced`,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
spinner.warn(` ${'CCS Symlinks'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} ${health.issues.length} issues found`);
|
|
416
|
+
this.results.addCheck('CCS Symlinks', 'warning', health.issues.join(', '), 'Run: ccs sync', { status: 'WARN', info: `${health.issues.length} issues` });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
catch (e) {
|
|
420
|
+
spinner.warn(` ${'CCS Symlinks'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Could not check`);
|
|
421
|
+
this.results.addCheck('CCS Symlinks', 'warning', 'Could not check CCS symlinks: ' + e.message, 'Run: ccs sync', { status: 'WARN', info: 'Could not check' });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Check 10: settings.json symlinks
|
|
426
|
+
*/
|
|
427
|
+
checkSettingsSymlinks() {
|
|
428
|
+
const spinner = ora('Checking settings.json symlinks').start();
|
|
429
|
+
try {
|
|
430
|
+
const sharedDir = path.join(this.homedir, '.ccs', 'shared');
|
|
431
|
+
const sharedSettings = path.join(sharedDir, 'settings.json');
|
|
432
|
+
const claudeSettings = path.join(this.claudeDir, 'settings.json');
|
|
433
|
+
// Check shared settings exists and points to ~/.claude/
|
|
434
|
+
if (!fs.existsSync(sharedSettings)) {
|
|
435
|
+
spinner.warn(` ${'settings.json (shared)'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Not found`);
|
|
436
|
+
this.results.addCheck('Settings Symlinks', 'warning', 'Shared settings.json not found', 'Run: ccs sync');
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const sharedStats = fs.lstatSync(sharedSettings);
|
|
440
|
+
if (!sharedStats.isSymbolicLink()) {
|
|
441
|
+
spinner.warn(` ${'settings.json (shared)'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Not a symlink`);
|
|
442
|
+
this.results.addCheck('Settings Symlinks', 'warning', 'Shared settings.json is not a symlink', 'Run: ccs sync');
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const sharedTarget = fs.readlinkSync(sharedSettings);
|
|
446
|
+
const resolvedShared = path.resolve(path.dirname(sharedSettings), sharedTarget);
|
|
447
|
+
if (resolvedShared !== claudeSettings) {
|
|
448
|
+
spinner.warn(` ${'settings.json (shared)'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Wrong target`);
|
|
449
|
+
this.results.addCheck('Settings Symlinks', 'warning', `Points to ${resolvedShared} instead of ${claudeSettings}`, 'Run: ccs sync');
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
// Check each instance
|
|
453
|
+
const instancesDir = path.join(this.ccsDir, 'instances');
|
|
454
|
+
if (!fs.existsSync(instancesDir)) {
|
|
455
|
+
spinner.succeed(` ${'settings.json'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} Shared symlink valid`);
|
|
456
|
+
this.results.addCheck('Settings Symlinks', 'success', 'Shared symlink valid', undefined, {
|
|
457
|
+
status: 'OK',
|
|
458
|
+
info: 'Shared symlink valid',
|
|
459
|
+
});
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const instances = fs.readdirSync(instancesDir).filter((name) => {
|
|
463
|
+
return fs.statSync(path.join(instancesDir, name)).isDirectory();
|
|
464
|
+
});
|
|
465
|
+
let broken = 0;
|
|
466
|
+
for (const instance of instances) {
|
|
467
|
+
const instancePath = path.join(instancesDir, instance);
|
|
468
|
+
const instanceSettings = path.join(instancePath, 'settings.json');
|
|
469
|
+
if (!fs.existsSync(instanceSettings)) {
|
|
470
|
+
broken++;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
const stats = fs.lstatSync(instanceSettings);
|
|
475
|
+
if (!stats.isSymbolicLink()) {
|
|
476
|
+
broken++;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const target = fs.readlinkSync(instanceSettings);
|
|
480
|
+
const resolved = path.resolve(path.dirname(instanceSettings), target);
|
|
481
|
+
if (resolved !== sharedSettings) {
|
|
482
|
+
broken++;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
catch (_err) {
|
|
486
|
+
broken++;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (broken > 0) {
|
|
490
|
+
spinner.warn(` ${'settings.json'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} ${broken} broken instance(s)`);
|
|
491
|
+
this.results.addCheck('Settings Symlinks', 'warning', `${broken} instance(s) have broken symlinks`, 'Run: ccs sync', { status: 'WARN', info: `${broken} broken instance(s)` });
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
spinner.succeed(` ${'settings.json'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${instances.length} instance(s) valid`);
|
|
495
|
+
this.results.addCheck('Settings Symlinks', 'success', 'All instance symlinks valid', undefined, {
|
|
496
|
+
status: 'OK',
|
|
497
|
+
info: `${instances.length} instance(s) valid`,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
spinner.warn(` ${'settings.json'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} Check failed`);
|
|
503
|
+
this.results.addCheck('Settings Symlinks', 'warning', `Failed to check: ${err.message}`, 'Run: ccs sync', { status: 'WARN', info: 'Check failed' });
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Check 11: CLIProxy health (OAuth profiles: gemini, codex, agy)
|
|
508
|
+
*/
|
|
509
|
+
async checkCLIProxy() {
|
|
510
|
+
// 1. Binary installed?
|
|
511
|
+
const binarySpinner = ora('Checking CLIProxy binary').start();
|
|
512
|
+
if ((0, cliproxy_1.isCLIProxyInstalled)()) {
|
|
513
|
+
const binaryPath = (0, cliproxy_1.getCLIProxyPath)();
|
|
514
|
+
binarySpinner.succeed(` ${'CLIProxy Binary'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} v${cliproxy_1.CLIPROXY_VERSION}`);
|
|
515
|
+
this.results.addCheck('CLIProxy Binary', 'success', undefined, undefined, {
|
|
516
|
+
status: 'OK',
|
|
517
|
+
info: `v${cliproxy_1.CLIPROXY_VERSION} (${binaryPath})`,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
binarySpinner.info(` ${'CLIProxy Binary'.padEnd(26)}${(0, helpers_1.colored)('[i]', 'cyan')} Not installed (downloads on first use)`);
|
|
522
|
+
this.results.addCheck('CLIProxy Binary', 'success', 'Not installed yet', 'Run: ccs gemini "test" (will download automatically)', { status: 'OK', info: 'Not installed (downloads on first use)' });
|
|
523
|
+
}
|
|
524
|
+
// 2. Config file exists?
|
|
525
|
+
const configSpinner = ora('Checking CLIProxy config').start();
|
|
526
|
+
const configPath = (0, cliproxy_1.getConfigPath)();
|
|
527
|
+
if (fs.existsSync(configPath)) {
|
|
528
|
+
configSpinner.succeed(` ${'CLIProxy Config'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} cliproxy/config.yaml`);
|
|
529
|
+
this.results.addCheck('CLIProxy Config', 'success', undefined, undefined, {
|
|
530
|
+
status: 'OK',
|
|
531
|
+
info: 'cliproxy/config.yaml',
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
configSpinner.info(` ${'CLIProxy Config'.padEnd(26)}${(0, helpers_1.colored)('[i]', 'cyan')} Not created (generated on first use)`);
|
|
536
|
+
this.results.addCheck('CLIProxy Config', 'success', 'Not created yet', undefined, {
|
|
537
|
+
status: 'OK',
|
|
538
|
+
info: 'Generated on first use',
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
// 3. OAuth status for each provider
|
|
542
|
+
const authStatuses = (0, cliproxy_1.getAllAuthStatus)();
|
|
543
|
+
for (const status of authStatuses) {
|
|
544
|
+
const authSpinner = ora(`Checking ${status.provider} auth`).start();
|
|
545
|
+
const providerName = status.provider.charAt(0).toUpperCase() + status.provider.slice(1);
|
|
546
|
+
if (status.authenticated) {
|
|
547
|
+
const lastAuth = status.lastAuth ? ` (${status.lastAuth.toLocaleDateString()})` : '';
|
|
548
|
+
authSpinner.succeed(` ${`${providerName} Auth`.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} Authenticated${lastAuth}`);
|
|
549
|
+
this.results.addCheck(`${providerName} Auth`, 'success', undefined, undefined, {
|
|
550
|
+
status: 'OK',
|
|
551
|
+
info: `Authenticated${lastAuth}`,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
authSpinner.info(` ${`${providerName} Auth`.padEnd(26)}${(0, helpers_1.colored)('[i]', 'cyan')} Not authenticated`);
|
|
556
|
+
this.results.addCheck(`${providerName} Auth`, 'success', 'Not authenticated', `Run: ccs ${status.provider} --auth`, { status: 'OK', info: 'Not authenticated (run ccs <profile> to login)' });
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// 4. Port availability
|
|
560
|
+
const portSpinner = ora(`Checking port ${cliproxy_1.CLIPROXY_DEFAULT_PORT}`).start();
|
|
561
|
+
const portAvailable = await (0, cliproxy_1.isPortAvailable)(cliproxy_1.CLIPROXY_DEFAULT_PORT);
|
|
562
|
+
if (portAvailable) {
|
|
563
|
+
portSpinner.succeed(` ${'CLIProxy Port'.padEnd(26)}${(0, helpers_1.colored)('[OK]', 'green')} ${cliproxy_1.CLIPROXY_DEFAULT_PORT} available`);
|
|
564
|
+
this.results.addCheck('CLIProxy Port', 'success', undefined, undefined, {
|
|
565
|
+
status: 'OK',
|
|
566
|
+
info: `Port ${cliproxy_1.CLIPROXY_DEFAULT_PORT} available`,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
portSpinner.warn(` ${'CLIProxy Port'.padEnd(26)}${(0, helpers_1.colored)('[!]', 'yellow')} ${cliproxy_1.CLIPROXY_DEFAULT_PORT} in use`);
|
|
571
|
+
this.results.addCheck('CLIProxy Port', 'warning', `Port ${cliproxy_1.CLIPROXY_DEFAULT_PORT} is in use`, `Check: lsof -i :${cliproxy_1.CLIPROXY_DEFAULT_PORT}`, { status: 'WARN', info: `Port ${cliproxy_1.CLIPROXY_DEFAULT_PORT} in use` });
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Show health check report
|
|
576
|
+
*/
|
|
577
|
+
showReport() {
|
|
578
|
+
console.log('');
|
|
579
|
+
// Calculate exact table width to match header bars
|
|
580
|
+
// colWidths: [20, 10, 35] = 65 + borders (4) = 69 total
|
|
581
|
+
const tableWidth = 69;
|
|
582
|
+
const headerBar = '═'.repeat(tableWidth);
|
|
583
|
+
console.log((0, helpers_1.colored)(headerBar, 'cyan'));
|
|
584
|
+
console.log((0, helpers_1.colored)(' Health Check Summary', 'bold'));
|
|
585
|
+
console.log((0, helpers_1.colored)(headerBar, 'cyan'));
|
|
586
|
+
// Create summary table with detailed information
|
|
587
|
+
const table = new Table({
|
|
588
|
+
head: [(0, helpers_1.colored)('Component', 'cyan'), (0, helpers_1.colored)('Status', 'cyan'), (0, helpers_1.colored)('Details', 'cyan')],
|
|
589
|
+
colWidths: [20, 10, 35],
|
|
590
|
+
wordWrap: true,
|
|
591
|
+
chars: {
|
|
592
|
+
top: '═',
|
|
593
|
+
'top-mid': '╤',
|
|
594
|
+
'top-left': '╔',
|
|
595
|
+
'top-right': '╗',
|
|
596
|
+
bottom: '═',
|
|
597
|
+
'bottom-mid': '╧',
|
|
598
|
+
'bottom-left': '╚',
|
|
599
|
+
'bottom-right': '╝',
|
|
600
|
+
left: '║',
|
|
601
|
+
'left-mid': '╟',
|
|
602
|
+
mid: '─',
|
|
603
|
+
'mid-mid': '┼',
|
|
604
|
+
right: '║',
|
|
605
|
+
'right-mid': '╢',
|
|
606
|
+
middle: '│',
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
// Populate table with collected details
|
|
610
|
+
for (const [component, detail] of Object.entries(this.results.details)) {
|
|
611
|
+
const statusColor = detail.status === 'OK' ? 'green' : detail.status === 'ERROR' ? 'red' : 'yellow';
|
|
612
|
+
table.push([component, (0, helpers_1.colored)(detail.status, statusColor), detail.info || '']);
|
|
613
|
+
}
|
|
614
|
+
console.log(table.toString());
|
|
615
|
+
console.log('');
|
|
616
|
+
// Show errors and warnings if present
|
|
617
|
+
if (this.results.hasErrors()) {
|
|
618
|
+
console.log((0, helpers_1.colored)('Errors:', 'red'));
|
|
619
|
+
this.results.errors.forEach((err) => {
|
|
620
|
+
console.log(` [X] ${err.name}: ${err.message}`);
|
|
621
|
+
if (err.fix) {
|
|
622
|
+
console.log(` Fix: ${err.fix}`);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
console.log('');
|
|
626
|
+
}
|
|
627
|
+
if (this.results.hasWarnings()) {
|
|
628
|
+
console.log((0, helpers_1.colored)('Warnings:', 'yellow'));
|
|
629
|
+
this.results.warnings.forEach((warn) => {
|
|
630
|
+
console.log(` [!] ${warn.name}: ${warn.message}`);
|
|
631
|
+
if (warn.fix) {
|
|
632
|
+
console.log(` Fix: ${warn.fix}`);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
console.log('');
|
|
636
|
+
}
|
|
637
|
+
// Final status
|
|
638
|
+
if (this.results.isHealthy() && !this.results.hasWarnings()) {
|
|
639
|
+
console.log((0, helpers_1.colored)('[OK] All checks passed! Your CCS installation is healthy.', 'green'));
|
|
640
|
+
}
|
|
641
|
+
else if (this.results.hasErrors()) {
|
|
642
|
+
console.log((0, helpers_1.colored)('[X] Status: Installation has errors', 'red'));
|
|
643
|
+
console.log('Run suggested fixes above to resolve issues.');
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
console.log((0, helpers_1.colored)('[OK] Status: Installation healthy (warnings only)', 'green'));
|
|
647
|
+
}
|
|
648
|
+
console.log('');
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Generate JSON report
|
|
652
|
+
*/
|
|
653
|
+
generateJsonReport() {
|
|
654
|
+
return JSON.stringify({
|
|
655
|
+
timestamp: new Date().toISOString(),
|
|
656
|
+
platform: process.platform,
|
|
657
|
+
nodeVersion: process.version,
|
|
658
|
+
ccsVersion: package_json_1.default.version,
|
|
659
|
+
checks: this.results.checks,
|
|
660
|
+
errors: this.results.errors,
|
|
661
|
+
warnings: this.results.warnings,
|
|
662
|
+
healthy: this.results.isHealthy(),
|
|
663
|
+
}, null, 2);
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Check if the health check results are healthy
|
|
667
|
+
*/
|
|
668
|
+
isHealthy() {
|
|
669
|
+
return this.results.isHealthy();
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
exports.default = Doctor;
|
|
673
|
+
//# sourceMappingURL=doctor.js.map
|