taphoaapi 1.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 +48 -0
- package/bin/cli.js +121 -0
- package/index.js +15 -0
- package/package.json +38 -0
- package/src/config.js +131 -0
- package/src/env.js +101 -0
- package/src/installer.js +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# prox-claude-installer
|
|
2
|
+
|
|
3
|
+
CLI tool to install and configure Claude Code with custom proxy settings.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g prox-claude-installer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly with bunx/npx:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bunx prox-claude-installer
|
|
15
|
+
# or
|
|
16
|
+
npx prox-claude-installer
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Simply run:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
prox-claude-installer
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The CLI will guide you through:
|
|
28
|
+
1. Enter your Anthropic Auth Token
|
|
29
|
+
2. Enter your proxy Base URL
|
|
30
|
+
3. Select your operating system
|
|
31
|
+
4. Choose default Claude model
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- Interactive CLI with Vietnamese interface
|
|
36
|
+
- Automatic Claude Code installation
|
|
37
|
+
- Configuration management for Claude Code
|
|
38
|
+
- Permanent environment variable setup
|
|
39
|
+
- Support for Windows, macOS, and Linux
|
|
40
|
+
|
|
41
|
+
## Requirements
|
|
42
|
+
|
|
43
|
+
- Node.js >= 18.0.0
|
|
44
|
+
- Bun or npm (for running the installer)
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI Entry Point for prox-claude-installer
|
|
5
|
+
* Main interactive CLI for setting up Claude Code with proxy
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { installClaude } from '../src/installer.js';
|
|
11
|
+
import { updateConfig } from '../src/config.js';
|
|
12
|
+
import { setEnvironmentVariable } from '../src/env.js';
|
|
13
|
+
|
|
14
|
+
const QUESTIONS = [
|
|
15
|
+
{
|
|
16
|
+
type: 'input',
|
|
17
|
+
name: 'authToken',
|
|
18
|
+
message: '🔑 Nhập Auth Token của bạn:',
|
|
19
|
+
validate: (input) => {
|
|
20
|
+
if (!input || input.trim() === '') {
|
|
21
|
+
return 'Vui lòng nhập Auth Token!';
|
|
22
|
+
}
|
|
23
|
+
if (!input.startsWith('sk-')) {
|
|
24
|
+
return 'Token phải bắt đầu bằng sk-';
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'baseUrl',
|
|
32
|
+
message: '🌐 Nhập Base URL (proxy):',
|
|
33
|
+
default: 'https://taphoaapi.info.vn/',
|
|
34
|
+
validate: (input) => {
|
|
35
|
+
if (!input || input.trim() === '') {
|
|
36
|
+
return 'Vui lòng nhập Base URL!';
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
new URL(input);
|
|
40
|
+
return true;
|
|
41
|
+
} catch {
|
|
42
|
+
return 'URL không hợp lệ!';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'list',
|
|
48
|
+
name: 'os',
|
|
49
|
+
message: '🖥️ Chọn hệ điều hành của bạn:',
|
|
50
|
+
choices: [
|
|
51
|
+
{ name: 'Windows (PowerShell)', value: 'windows' },
|
|
52
|
+
{ name: 'macOS (Zsh)', value: 'macos' },
|
|
53
|
+
{ name: 'Linux (Bash)', value: 'linux' }
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'list',
|
|
58
|
+
name: 'model',
|
|
59
|
+
message: '🤖 Chọn model Claude mặc định:',
|
|
60
|
+
choices: [
|
|
61
|
+
{ name: 'Opus (cao cấp nhất)', value: 'opus' },
|
|
62
|
+
{ name: 'Sonnet (cân bằng)', value: 'sonnet' },
|
|
63
|
+
{ name: 'Haiku (nhanh nhất)', value: 'haiku' }
|
|
64
|
+
],
|
|
65
|
+
default: 'sonnet'
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
async function main() {
|
|
70
|
+
// Banner
|
|
71
|
+
console.log(chalk.cyan(`
|
|
72
|
+
╔═══════════════════════════════════════════╗
|
|
73
|
+
║ ║
|
|
74
|
+
║ 🚀 TaphoaAPI Claude Setup ║
|
|
75
|
+
║ ║
|
|
76
|
+
╚═══════════════════════════════════════════╝
|
|
77
|
+
`));
|
|
78
|
+
|
|
79
|
+
console.log(chalk.gray(' Đang khởi động installer...\n'));
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Collect user inputs
|
|
83
|
+
const answers = await inquirer.prompt(QUESTIONS);
|
|
84
|
+
|
|
85
|
+
console.log(chalk.yellow('\n⚙️ Đang xử lý...\n'));
|
|
86
|
+
|
|
87
|
+
// Step 1: Install Claude Code
|
|
88
|
+
console.log(chalk.blue('📦 Đang cài đặt Claude Code...'));
|
|
89
|
+
await installClaude();
|
|
90
|
+
console.log(chalk.green('✅ Claude Code đã cài đặt thành công!'));
|
|
91
|
+
|
|
92
|
+
// Step 2: Update config
|
|
93
|
+
console.log(chalk.blue('\n⚙️ Đang cập nhật cấu hình...'));
|
|
94
|
+
await updateConfig(answers);
|
|
95
|
+
console.log(chalk.green('✅ Cấu hình đã được cập nhật!'));
|
|
96
|
+
|
|
97
|
+
// Step 3: Set environment variables
|
|
98
|
+
console.log(chalk.blue('\n🔧 Đang thiết lập biến môi trường...'));
|
|
99
|
+
await setEnvironmentVariable('ANTHROPIC_AUTH_TOKEN', answers.authToken, answers.os);
|
|
100
|
+
await setEnvironmentVariable('ANTHROPIC_BASE_URL', answers.baseUrl, answers.os);
|
|
101
|
+
console.log(chalk.green('✅ Thiết lập biến môi trường thành công!'));
|
|
102
|
+
|
|
103
|
+
// Success message
|
|
104
|
+
console.log(chalk.green(`
|
|
105
|
+
|
|
106
|
+
╔═══════════════════════════════════════════╗
|
|
107
|
+
║ ║
|
|
108
|
+
║ ✨ Setup complete! ║
|
|
109
|
+
║ ║
|
|
110
|
+
║ Gõ "claude" để bắt đầu sử dụng ║
|
|
111
|
+
║ ║
|
|
112
|
+
╚═══════════════════════════════════════════╝
|
|
113
|
+
`));
|
|
114
|
+
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error(chalk.red('\n❌ Lỗi:'), error.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main();
|
package/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prox-claude-installer
|
|
3
|
+
* CLI tool to install and configure Claude Code with custom proxy settings
|
|
4
|
+
*
|
|
5
|
+
* @module prox-claude-installer
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export all modules
|
|
9
|
+
export { installClaude, isClaudeInstalled, getClaudeVersion } from './src/installer.js';
|
|
10
|
+
export { updateConfig, readCurrentConfig, getConfigValue } from './src/config.js';
|
|
11
|
+
export { setEnvironmentVariable, getEnv, hasEnv } from './src/env.js';
|
|
12
|
+
|
|
13
|
+
// Package info
|
|
14
|
+
export const name = 'prox-claude-installer';
|
|
15
|
+
export const version = '1.0.3';
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "taphoaapi",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to install and configure Claude Code with taphoaapi proxy",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"taphoaapi": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/cli.js",
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"claude",
|
|
16
|
+
"anthropic",
|
|
17
|
+
"ai",
|
|
18
|
+
"cli",
|
|
19
|
+
"installer",
|
|
20
|
+
"taphoaapi"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"chalk": "^5.3.0",
|
|
26
|
+
"inquirer": "^9.2.0"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/yourusername/taphoaapi"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/yourusername/taphoaapi/issues"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Manager Module
|
|
3
|
+
* Handles reading and writing Claude Code settings
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the Claude config directory path
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
function getConfigDir() {
|
|
16
|
+
const homeDir = os.homedir();
|
|
17
|
+
return path.join(homeDir, '.claude');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the Claude settings.json path
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
function getConfigPath() {
|
|
25
|
+
return path.join(getConfigDir(), 'settings.json');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Read existing config or create default
|
|
30
|
+
* @returns {Object}
|
|
31
|
+
*/
|
|
32
|
+
function readConfig() {
|
|
33
|
+
const configPath = getConfigPath();
|
|
34
|
+
|
|
35
|
+
if (fs.existsSync(configPath)) {
|
|
36
|
+
try {
|
|
37
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
38
|
+
return JSON.parse(content);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log(chalk.yellow(' ⚠️ Config file corrupted, creating new...'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
env: {},
|
|
46
|
+
permissions: {
|
|
47
|
+
allow: [],
|
|
48
|
+
deny: []
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Update Claude Code configuration
|
|
55
|
+
* @param {Object} answers - User answers from CLI
|
|
56
|
+
* @returns {Promise<void>}
|
|
57
|
+
*/
|
|
58
|
+
export async function updateConfig(answers) {
|
|
59
|
+
const configPath = getConfigPath();
|
|
60
|
+
const configDir = getConfigDir();
|
|
61
|
+
|
|
62
|
+
// Ensure config directory exists
|
|
63
|
+
if (!fs.existsSync(configDir)) {
|
|
64
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
65
|
+
console.log(chalk.gray(` Created config directory: ${configDir}`));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Read existing config
|
|
69
|
+
const config = readConfig();
|
|
70
|
+
|
|
71
|
+
// Prepare model mapping
|
|
72
|
+
const modelMap = {
|
|
73
|
+
opus: 'claude-opus-4-8',
|
|
74
|
+
sonnet: 'claude-sonnet-4-6',
|
|
75
|
+
haiku: 'claude-haiku-4-5-20251001'
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Update env variables
|
|
79
|
+
config.env = {
|
|
80
|
+
ANTHROPIC_AUTH_TOKEN: answers.authToken,
|
|
81
|
+
ANTHROPIC_BASE_URL: answers.baseUrl,
|
|
82
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: modelMap.opus,
|
|
83
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: modelMap.sonnet,
|
|
84
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: modelMap.haiku,
|
|
85
|
+
CLAUDE_CODE_SUBAGENT_MODEL: modelMap[answers.model] || modelMap.sonnet,
|
|
86
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
|
|
87
|
+
API_TIMEOUT_MS: '3000000'
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Add default permissions if not exists
|
|
91
|
+
if (!config.permissions) {
|
|
92
|
+
config.permissions = {
|
|
93
|
+
allow: [],
|
|
94
|
+
deny: []
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Write config
|
|
99
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
100
|
+
console.log(chalk.gray(` Updated: ${configPath}`));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Read current configuration
|
|
105
|
+
* @returns {Object|null}
|
|
106
|
+
*/
|
|
107
|
+
export function readCurrentConfig() {
|
|
108
|
+
const configPath = getConfigPath();
|
|
109
|
+
|
|
110
|
+
if (!fs.existsSync(configPath)) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
116
|
+
return JSON.parse(content);
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get a specific config value
|
|
124
|
+
* @param {string} key - Config key
|
|
125
|
+
* @returns {string|null}
|
|
126
|
+
*/
|
|
127
|
+
export function getConfigValue(key) {
|
|
128
|
+
const config = readCurrentConfig();
|
|
129
|
+
if (!config || !config.env) return null;
|
|
130
|
+
return config.env[key] || null;
|
|
131
|
+
}
|
package/src/env.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Manager Module
|
|
3
|
+
* Handles setting permanent environment variables across OS
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Set environment variable for Windows (PowerShell)
|
|
12
|
+
* @param {string} key - Environment variable name
|
|
13
|
+
* @param {string} value - Environment variable value
|
|
14
|
+
*/
|
|
15
|
+
function setWindows(key, value) {
|
|
16
|
+
const escapedValue = value.replace(/"/g, '\\"');
|
|
17
|
+
const cmd = `[Environment]::SetEnvironmentVariable("${key}", "${escapedValue}", "User")`;
|
|
18
|
+
|
|
19
|
+
execSync(`powershell -Command "${cmd}"`, {
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
shell: true
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Set environment variable for macOS/Linux (bash/zsh)
|
|
27
|
+
* @param {string} key - Environment variable name
|
|
28
|
+
* @param {string} value - Environment variable value
|
|
29
|
+
* @param {string} shellType - 'bash' or 'zsh'
|
|
30
|
+
*/
|
|
31
|
+
async function setUnix(key, value, shellType) {
|
|
32
|
+
const configFile = shellType === 'zsh' ? '.zshrc' : '.bashrc';
|
|
33
|
+
const exportLine = `\nexport ${key}="${value}"\n`;
|
|
34
|
+
|
|
35
|
+
// Check if export already exists
|
|
36
|
+
const homeDir = process.env.HOME;
|
|
37
|
+
const configPath = `${homeDir}/${configFile}`;
|
|
38
|
+
|
|
39
|
+
let content = '';
|
|
40
|
+
if (fs.existsSync(configPath)) {
|
|
41
|
+
content = fs.readFileSync(configPath, 'utf-8');
|
|
42
|
+
|
|
43
|
+
// Check if key already exists
|
|
44
|
+
const regex = new RegExp(`^export\\s+${key}=`, 'm');
|
|
45
|
+
if (regex.test(content)) {
|
|
46
|
+
// Replace existing export
|
|
47
|
+
content = content.replace(
|
|
48
|
+
new RegExp(`^export\\s+${key}=.*$\\n?`, 'm'),
|
|
49
|
+
`export ${key}="${value}"\n`
|
|
50
|
+
);
|
|
51
|
+
} else {
|
|
52
|
+
// Append new export
|
|
53
|
+
content += exportLine;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
content = exportLine;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(configPath, content);
|
|
60
|
+
console.log(chalk.gray(` Added to ~/${configFile}`));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set environment variable permanently
|
|
65
|
+
* @param {string} key - Environment variable name
|
|
66
|
+
* @param {string} value - Environment variable value
|
|
67
|
+
* @param {string} os - Operating system: 'windows', 'macos', or 'linux'
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
export async function setEnvironmentVariable(key, value, os) {
|
|
71
|
+
console.log(chalk.gray(` Setting ${key}=${value.substring(0, 10)}...`));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
if (os === 'windows') {
|
|
75
|
+
setWindows(key, value);
|
|
76
|
+
} else {
|
|
77
|
+
const shellType = os === 'macos' ? 'zsh' : 'bash';
|
|
78
|
+
await setUnix(key, value, shellType);
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw new Error(`Failed to set environment variable ${key}: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get environment variable (current session only)
|
|
87
|
+
* @param {string} key - Environment variable name
|
|
88
|
+
* @returns {string|null}
|
|
89
|
+
*/
|
|
90
|
+
export function getEnv(key) {
|
|
91
|
+
return process.env[key] || null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if environment variable is set
|
|
96
|
+
* @param {string} key - Environment variable name
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
export function hasEnv(key) {
|
|
100
|
+
return key in process.env;
|
|
101
|
+
}
|
package/src/installer.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Installer Module
|
|
3
|
+
* Handles installation of Claude Code CLI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Install Claude Code using bunx
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
13
|
+
export async function installClaude() {
|
|
14
|
+
try {
|
|
15
|
+
console.log(chalk.gray(' Running: bunx @anthropic-ai/claude-code'));
|
|
16
|
+
|
|
17
|
+
execSync('bunx @anthropic-ai/claude-code', {
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
env: { ...process.env }
|
|
20
|
+
});
|
|
21
|
+
} catch (error) {
|
|
22
|
+
// If bunx fails, try npm
|
|
23
|
+
console.log(chalk.yellow(' bunx not available, trying npm...'));
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
execSync('npx @anthropic-ai/claude-code', {
|
|
27
|
+
stdio: 'inherit',
|
|
28
|
+
env: { ...process.env }
|
|
29
|
+
});
|
|
30
|
+
} catch (npmError) {
|
|
31
|
+
throw new Error('Không thể cài đặt Claude Code. Vui lòng kiểm tra kết nối mạng.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if Claude Code is already installed
|
|
38
|
+
* @returns {boolean}
|
|
39
|
+
*/
|
|
40
|
+
export function isClaudeInstalled() {
|
|
41
|
+
try {
|
|
42
|
+
execSync('claude --version', { stdio: 'ignore' });
|
|
43
|
+
return true;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get Claude Code version
|
|
51
|
+
* @returns {string|null}
|
|
52
|
+
*/
|
|
53
|
+
export function getClaudeVersion() {
|
|
54
|
+
try {
|
|
55
|
+
const version = execSync('claude --version', { encoding: 'utf-8' });
|
|
56
|
+
return version.trim();
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|