@tuannvm/ccodex 0.1.0 → 0.1.9
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 +38 -3
- package/dist/aliases.d.ts +3 -8
- package/dist/aliases.d.ts.map +1 -1
- package/dist/aliases.js +72 -79
- package/dist/aliases.js.map +1 -1
- package/dist/claude.d.ts +5 -1
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +133 -37
- package/dist/claude.js.map +1 -1
- package/dist/cli.js +137 -17
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +0 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -15
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/powershell.js +11 -11
- package/dist/powershell.js.map +1 -1
- package/dist/proxy.d.ts +2 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +320 -44
- package/dist/proxy.js.map +1 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +7 -9
- package/dist/status.js.map +1 -1
- package/dist/utils.d.ts +11 -7
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +51 -32
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# ccodex
|
|
1
|
+
# @tuannvm/ccodex
|
|
2
2
|
|
|
3
3
|
TypeScript reimplementation of `ccodex` — run Claude Code CLI with OpenAI GPT models via CLIProxyAPI.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx -y ccodex
|
|
8
|
+
npx -y @tuannvm/ccodex
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
That's it. `ccodex` will automatically:
|
|
@@ -21,7 +21,7 @@ That's it. `ccodex` will automatically:
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
# First run - sets everything up automatically
|
|
24
|
-
npx -y ccodex
|
|
24
|
+
npx -y @tuannvm/ccodex
|
|
25
25
|
|
|
26
26
|
# After setup - use aliases
|
|
27
27
|
ccodex
|
|
@@ -45,6 +45,41 @@ Every time you run `ccodex`, it:
|
|
|
45
45
|
|
|
46
46
|
This makes it "just work" without manual setup steps.
|
|
47
47
|
|
|
48
|
+
## Production Readiness (v0.1.8)
|
|
49
|
+
|
|
50
|
+
`ccodex` v0.1.8 is production-ready for:
|
|
51
|
+
- ✅ **macOS** (arm64, x64)
|
|
52
|
+
- ✅ **Linux** (arm64, x64)
|
|
53
|
+
|
|
54
|
+
### Windows Status (Known Limitations)
|
|
55
|
+
|
|
56
|
+
Windows support is currently partial and is not yet production-ready.
|
|
57
|
+
|
|
58
|
+
Current Windows limitations:
|
|
59
|
+
- `CLIProxyAPI` auto-install is not fully automated; manual proxy setup is required.
|
|
60
|
+
- Shell/profile integration differs across `PowerShell`, `Windows PowerShell`, and `cmd`, and may need manual adjustment.
|
|
61
|
+
- Path and wrapper differences (`.cmd`/`.exe`) are handled in detection, but end-to-end setup remains less reliable than macOS/Linux.
|
|
62
|
+
|
|
63
|
+
Recommended Windows flow for now:
|
|
64
|
+
1. Install Claude Code CLI manually and verify `claude` is on `PATH`.
|
|
65
|
+
2. Install and run proxy components manually.
|
|
66
|
+
3. Use `ccodex --status` to verify runtime before interactive use.
|
|
67
|
+
|
|
68
|
+
For team rollouts, treat Windows as "best effort" until full installer parity lands.
|
|
69
|
+
|
|
70
|
+
### Security Features
|
|
71
|
+
|
|
72
|
+
- **Allowlist environment passing**: Only essential environment variables are passed to Claude subprocess (PATH, HOME, TMP, etc.)
|
|
73
|
+
- **Mandatory checksum verification**: Downloaded binaries are verified against SHA-256 checksums before installation
|
|
74
|
+
- **Fail-closed policy**: Installation fails hard if checksums cannot be verified
|
|
75
|
+
- **No API key leakage**: All Anthropic/OpenAI variables are explicitly excluded from subprocess environment
|
|
76
|
+
|
|
77
|
+
### Known Limitations
|
|
78
|
+
|
|
79
|
+
- **Checksum trust model**: Binary and checksum are both fetched from the same GitHub release. If the release account is compromised, both could be malicious. Future versions may add signature verification.
|
|
80
|
+
- **Concurrency**: No install lock file; concurrent installations may race (low frequency issue).
|
|
81
|
+
- **Platform support**: Only arm64 and x64 architectures are supported.
|
|
82
|
+
|
|
48
83
|
## Model Mapping
|
|
49
84
|
|
|
50
85
|
| Claude Tier | GPT Model |
|
package/dist/aliases.d.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Install alias file (Unix/macOS only)
|
|
3
|
-
*/
|
|
4
|
-
export declare function installAliases(): Promise<void>;
|
|
5
|
-
/**
|
|
6
|
-
* Check if alias file exists and is valid
|
|
7
|
-
*/
|
|
8
|
-
export declare function hasAliasFile(): Promise<boolean>;
|
|
9
1
|
/**
|
|
10
2
|
* Configure shell integration
|
|
3
|
+
* Adds aliases directly to rc files (no separate alias file)
|
|
11
4
|
*/
|
|
12
5
|
export declare function configureShellIntegration(): Promise<void>;
|
|
13
6
|
/**
|
|
14
7
|
* Check if shell integration is configured
|
|
8
|
+
* Checks if rc file contains the aliases directly
|
|
9
|
+
* Checks both .zshrc and .bashrc since user may have installed to either
|
|
15
10
|
*/
|
|
16
11
|
export declare function isShellIntegrationConfigured(): Promise<boolean>;
|
|
17
12
|
//# sourceMappingURL=aliases.d.ts.map
|
package/dist/aliases.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"AAkGA;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE/D;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAsBrE"}
|
package/dist/aliases.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
|
-
import { getShellRcFile,
|
|
2
|
+
import { getShellRcFile, ensureDir, appendFile, readFile, fileExists, detectPlatform, isInteractive, } from './utils.js';
|
|
3
3
|
import { installPowerShellAliases, isPowerShellIntegrationConfigured } from './powershell.js';
|
|
4
4
|
// Use npx directly - no local bin installation
|
|
5
|
-
const CCODEX_NPX_CMD = 'npx -y ccodex';
|
|
5
|
+
const CCODEX_NPX_CMD = 'npx -y @tuannvm/ccodex';
|
|
6
6
|
/**
|
|
7
|
-
* Generate alias
|
|
7
|
+
* Generate alias content for Unix shells (zsh/bash)
|
|
8
|
+
* Direct embedding into rc files - no separate alias file
|
|
9
|
+
* All three functions are guarded to avoid conflicts with existing user definitions
|
|
10
|
+
* Uses START/END markers for safe removal during updates
|
|
8
11
|
*/
|
|
9
|
-
function
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
function generateAliasesForRc() {
|
|
13
|
+
return `
|
|
14
|
+
|
|
15
|
+
# >>> ccodex aliases START >>> # generated by npx @tuannvm/ccodex
|
|
16
|
+
if ! typeset -f ccodex >/dev/null 2>&1; then
|
|
17
|
+
ccodex() {
|
|
18
|
+
command ${CCODEX_NPX_CMD} "$@"
|
|
19
|
+
}
|
|
20
|
+
fi
|
|
14
21
|
|
|
15
22
|
if ! typeset -f co >/dev/null 2>&1; then
|
|
16
23
|
co() {
|
|
@@ -18,55 +25,39 @@ if ! typeset -f co >/dev/null 2>&1; then
|
|
|
18
25
|
}
|
|
19
26
|
fi
|
|
20
27
|
|
|
21
|
-
claude-openai
|
|
22
|
-
|
|
23
|
-
}
|
|
28
|
+
if ! typeset -f claude-openai >/dev/null 2>&1; then
|
|
29
|
+
claude-openai() {
|
|
30
|
+
command ${CCODEX_NPX_CMD} "$@"
|
|
31
|
+
}
|
|
32
|
+
fi
|
|
33
|
+
# <<< ccodex aliases END <<<
|
|
24
34
|
`;
|
|
25
35
|
}
|
|
26
36
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
export async function installAliases() {
|
|
30
|
-
const platform = detectPlatform();
|
|
31
|
-
// On Windows, use PowerShell aliases instead
|
|
32
|
-
if (platform.os === 'windows') {
|
|
33
|
-
await installPowerShellAliases();
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const aliasFile = getAliasFile();
|
|
37
|
-
await ensureDir(join(aliasFile, '..'));
|
|
38
|
-
await writeFile(aliasFile, generateAliasContent());
|
|
39
|
-
console.log(`Installed alias file: ${aliasFile}`);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if alias file exists and is valid
|
|
37
|
+
* Check if ccodex block marker exists in content
|
|
38
|
+
* Checks for our START marker to identify our alias block
|
|
43
39
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// On Windows, check PowerShell integration
|
|
47
|
-
if (platform.os === 'windows') {
|
|
48
|
-
return await isPowerShellIntegrationConfigured();
|
|
49
|
-
}
|
|
50
|
-
const aliasFile = getAliasFile();
|
|
51
|
-
if (!fileExists(aliasFile)) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
const content = await readFile(aliasFile);
|
|
55
|
-
return (content.includes('ccodex()') &&
|
|
56
|
-
content.includes('co()') &&
|
|
57
|
-
content.includes('claude-openai()'));
|
|
40
|
+
function hasCcodexBlock(content) {
|
|
41
|
+
return content.includes('# >>> ccodex aliases START >>>');
|
|
58
42
|
}
|
|
59
43
|
/**
|
|
60
|
-
*
|
|
44
|
+
* Remove existing ccodex alias block from content
|
|
45
|
+
* Finds and removes the entire block between START and END markers
|
|
46
|
+
* Uses explicit markers to avoid deleting unrelated user content
|
|
61
47
|
*/
|
|
62
|
-
function
|
|
63
|
-
|
|
48
|
+
function removeCcodexBlock(content) {
|
|
49
|
+
// Match the entire ccodex alias block from START marker to END marker
|
|
50
|
+
const blockRegex = /# >>> ccodex aliases START >>>[\s\S]*?# <<< ccodex aliases END <<<\n?/g;
|
|
51
|
+
return content.replace(blockRegex, '').trimEnd();
|
|
64
52
|
}
|
|
65
53
|
/**
|
|
66
|
-
* Add
|
|
54
|
+
* Add aliases to shell rc file
|
|
55
|
+
* Creates file if needed, removes any existing ccodex blocks, then adds fresh aliases
|
|
56
|
+
* This ensures idempotency - no duplicate blocks even if run multiple times
|
|
67
57
|
*/
|
|
68
|
-
async function
|
|
69
|
-
|
|
58
|
+
async function addAliasesToRc(rcFile) {
|
|
59
|
+
// Ensure rc file directory exists
|
|
60
|
+
await ensureDir(join(rcFile, '..'));
|
|
70
61
|
// Create rc file if it doesn't exist
|
|
71
62
|
const fs = await import('fs/promises');
|
|
72
63
|
try {
|
|
@@ -75,18 +66,22 @@ async function addSourceToRc(rcFile) {
|
|
|
75
66
|
catch {
|
|
76
67
|
// File exists, that's fine
|
|
77
68
|
}
|
|
78
|
-
|
|
79
|
-
// Check if already
|
|
80
|
-
if (content
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
let content = await readFile(rcFile);
|
|
70
|
+
// Check if aliases already present
|
|
71
|
+
if (hasCcodexBlock(content)) {
|
|
72
|
+
// Remove existing block to prevent duplicates
|
|
73
|
+
content = removeCcodexBlock(content);
|
|
74
|
+
// Write back the cleaned content
|
|
75
|
+
await fs.writeFile(rcFile, content + '\n', 'utf-8');
|
|
76
|
+
console.log(`Cleaned existing ccodex aliases: ${rcFile}`);
|
|
83
77
|
}
|
|
84
|
-
|
|
85
|
-
await appendFile(rcFile,
|
|
86
|
-
console.log(`Added
|
|
78
|
+
// Append fresh aliases
|
|
79
|
+
await appendFile(rcFile, generateAliasesForRc());
|
|
80
|
+
console.log(`Added aliases to: ${rcFile}`);
|
|
87
81
|
}
|
|
88
82
|
/**
|
|
89
83
|
* Configure shell integration
|
|
84
|
+
* Adds aliases directly to rc files (no separate alias file)
|
|
90
85
|
*/
|
|
91
86
|
export async function configureShellIntegration() {
|
|
92
87
|
const platform = detectPlatform();
|
|
@@ -98,20 +93,11 @@ export async function configureShellIntegration() {
|
|
|
98
93
|
return;
|
|
99
94
|
}
|
|
100
95
|
// Unix/macOS: use zsh/bash
|
|
101
|
-
//
|
|
96
|
+
// Get the appropriate rc file
|
|
102
97
|
const rcFile = getShellRcFile(platform);
|
|
103
|
-
const aliasFile = getAliasFile();
|
|
104
|
-
if (fileExists(rcFile)) {
|
|
105
|
-
const content = await readFile(rcFile);
|
|
106
|
-
if (content.includes(aliasFile)) {
|
|
107
|
-
// Already configured, skip
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// Not configured, proceed with setup
|
|
112
98
|
if (!isInteractive()) {
|
|
113
|
-
// Non-interactive: auto-detect
|
|
114
|
-
await
|
|
99
|
+
// Non-interactive: auto-detect and add
|
|
100
|
+
await addAliasesToRc(rcFile);
|
|
115
101
|
return;
|
|
116
102
|
}
|
|
117
103
|
// Interactive: ask user
|
|
@@ -122,7 +108,7 @@ export async function configureShellIntegration() {
|
|
|
122
108
|
console.log(' 1) ~/.zshrc');
|
|
123
109
|
console.log(' 2) ~/.bashrc');
|
|
124
110
|
console.log(' 3) Both');
|
|
125
|
-
console.log(' 4) Skip (manual
|
|
111
|
+
console.log(' 4) Skip (manual setup)');
|
|
126
112
|
const readline = await import('readline');
|
|
127
113
|
const rl = readline.createInterface({
|
|
128
114
|
input: process.stdin,
|
|
@@ -138,25 +124,27 @@ export async function configureShellIntegration() {
|
|
|
138
124
|
const bashrc = join(platform.home, '.bashrc');
|
|
139
125
|
switch (choice) {
|
|
140
126
|
case '1':
|
|
141
|
-
await
|
|
127
|
+
await addAliasesToRc(zshrc);
|
|
142
128
|
break;
|
|
143
129
|
case '2':
|
|
144
|
-
await
|
|
130
|
+
await addAliasesToRc(bashrc);
|
|
145
131
|
break;
|
|
146
132
|
case '3':
|
|
147
|
-
await
|
|
148
|
-
await
|
|
133
|
+
await addAliasesToRc(zshrc);
|
|
134
|
+
await addAliasesToRc(bashrc);
|
|
149
135
|
break;
|
|
150
136
|
case '4':
|
|
151
137
|
console.log('Skipped rc integration.');
|
|
152
138
|
break;
|
|
153
139
|
default:
|
|
154
140
|
console.log('Invalid choice. Using ~/.zshrc');
|
|
155
|
-
await
|
|
141
|
+
await addAliasesToRc(zshrc);
|
|
156
142
|
}
|
|
157
143
|
}
|
|
158
144
|
/**
|
|
159
145
|
* Check if shell integration is configured
|
|
146
|
+
* Checks if rc file contains the aliases directly
|
|
147
|
+
* Checks both .zshrc and .bashrc since user may have installed to either
|
|
160
148
|
*/
|
|
161
149
|
export async function isShellIntegrationConfigured() {
|
|
162
150
|
const platform = detectPlatform();
|
|
@@ -164,12 +152,17 @@ export async function isShellIntegrationConfigured() {
|
|
|
164
152
|
if (platform.os === 'windows') {
|
|
165
153
|
return await isPowerShellIntegrationConfigured();
|
|
166
154
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
155
|
+
// Check both possible rc files (user may have installed to either)
|
|
156
|
+
const zshrc = join(platform.home, '.zshrc');
|
|
157
|
+
const bashrc = join(platform.home, '.bashrc');
|
|
158
|
+
for (const rcFile of [zshrc, bashrc]) {
|
|
159
|
+
if (fileExists(rcFile)) {
|
|
160
|
+
const content = await readFile(rcFile);
|
|
161
|
+
if (hasCcodexBlock(content)) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
170
165
|
}
|
|
171
|
-
|
|
172
|
-
const aliasFile = getAliasFile();
|
|
173
|
-
return content.includes(aliasFile);
|
|
166
|
+
return false;
|
|
174
167
|
}
|
|
175
168
|
//# sourceMappingURL=aliases.js.map
|
package/dist/aliases.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"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"}
|
package/dist/claude.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Detect Claude Code installation
|
|
3
|
+
* Checks multiple sources in priority order:
|
|
4
|
+
* 1. Process-local path (fast path for current process)
|
|
5
|
+
* 2. Persistent local fallback path (for previously-installed local CLI)
|
|
6
|
+
* 3. System PATH (for globally-installed CLI)
|
|
3
7
|
*/
|
|
4
8
|
export declare function detectClaudeCommand(): Promise<{
|
|
5
9
|
cmd: string | null;
|
|
6
10
|
path: string | null;
|
|
7
11
|
}>;
|
|
8
12
|
/**
|
|
9
|
-
* Install Claude Code via npm
|
|
13
|
+
* Install Claude Code via npm with fallback to local prefix
|
|
10
14
|
*/
|
|
11
15
|
export declare function installClaudeCode(): Promise<void>;
|
|
12
16
|
/**
|
package/dist/claude.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAoBhG;AAoBD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAuCvD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoI7D"}
|
package/dist/claude.js
CHANGED
|
@@ -1,25 +1,72 @@
|
|
|
1
1
|
import spawnCmd from 'cross-spawn';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { hasCommand, getCommandPath, ensureDir, getUid, fileExists } from './utils.js';
|
|
4
5
|
import { startProxy, checkAuthConfigured, launchLogin, waitForAuth } from './proxy.js';
|
|
6
|
+
// Track locally installed Claude CLI path for this process
|
|
7
|
+
let installedClaudePath = null;
|
|
8
|
+
/**
|
|
9
|
+
* Get the deterministic persistent path for local Claude CLI installation
|
|
10
|
+
* This path is used across process invocations to persistently discover
|
|
11
|
+
* locally-installed Claude CLI when global install fails
|
|
12
|
+
* Handles platform differences (Unix vs Windows)
|
|
13
|
+
*/
|
|
14
|
+
function getPersistentLocalClaudePath() {
|
|
15
|
+
const home = homedir();
|
|
16
|
+
if (process.platform === 'win32') {
|
|
17
|
+
// Windows: npm installs to AppData/local/prefix, with .cmd wrappers
|
|
18
|
+
// Try claude.cmd first (npm wrapper), then claude.exe (actual binary)
|
|
19
|
+
const localPrefix = join(home, 'AppData', 'Local', 'ccodex', 'npm');
|
|
20
|
+
return join(localPrefix, 'node_modules', '.bin', 'claude.cmd');
|
|
21
|
+
}
|
|
22
|
+
// Unix/macOS: ~/.local/ccodex/npm/node_modules/.bin/claude
|
|
23
|
+
return join(home, '.local', 'ccodex', 'npm', 'node_modules', '.bin', 'claude');
|
|
24
|
+
}
|
|
5
25
|
/**
|
|
6
26
|
* Detect Claude Code installation
|
|
27
|
+
* Checks multiple sources in priority order:
|
|
28
|
+
* 1. Process-local path (fast path for current process)
|
|
29
|
+
* 2. Persistent local fallback path (for previously-installed local CLI)
|
|
30
|
+
* 3. System PATH (for globally-installed CLI)
|
|
7
31
|
*/
|
|
8
32
|
export async function detectClaudeCommand() {
|
|
33
|
+
// 1. Prefer locally installed binary from this process (fast path)
|
|
34
|
+
if (installedClaudePath && fileExists(installedClaudePath)) {
|
|
35
|
+
return { cmd: installedClaudePath, path: installedClaudePath };
|
|
36
|
+
}
|
|
37
|
+
// 2. Check persistent local fallback path (for previously-installed CLI)
|
|
38
|
+
const persistentLocal = getPersistentLocalClaudePath();
|
|
39
|
+
if (fileExists(persistentLocal)) {
|
|
40
|
+
// Update process-local cache for faster subsequent checks
|
|
41
|
+
installedClaudePath = persistentLocal;
|
|
42
|
+
return { cmd: persistentLocal, path: persistentLocal };
|
|
43
|
+
}
|
|
44
|
+
// 3. Check system PATH for global installation
|
|
9
45
|
if (await hasCommand('claude')) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const path = await execCommand('which', ['claude']);
|
|
13
|
-
return { cmd: 'claude', path };
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return { cmd: 'claude', path: null };
|
|
17
|
-
}
|
|
46
|
+
const resolved = await getCommandPath('claude');
|
|
47
|
+
return { cmd: 'claude', path: resolved };
|
|
18
48
|
}
|
|
19
49
|
return { cmd: null, path: null };
|
|
20
50
|
}
|
|
21
51
|
/**
|
|
22
|
-
*
|
|
52
|
+
* Helper to run npm install and capture stderr
|
|
53
|
+
*/
|
|
54
|
+
async function runNpmInstall(args) {
|
|
55
|
+
const spawn = (await import('cross-spawn')).default;
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const child = spawn('npm', args, { stdio: ['ignore', 'inherit', 'pipe'] });
|
|
58
|
+
let stderr = '';
|
|
59
|
+
child.stderr?.on('data', (d) => {
|
|
60
|
+
const s = d.toString();
|
|
61
|
+
stderr += s;
|
|
62
|
+
process.stderr.write(s);
|
|
63
|
+
});
|
|
64
|
+
child.on('error', reject);
|
|
65
|
+
child.on('close', code => resolve({ ok: code === 0, stderr }));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Install Claude Code via npm with fallback to local prefix
|
|
23
70
|
*/
|
|
24
71
|
export async function installClaudeCode() {
|
|
25
72
|
// Check if npm is available
|
|
@@ -27,30 +74,46 @@ export async function installClaudeCode() {
|
|
|
27
74
|
throw new Error('npm not found. Install Node.js with npm first.');
|
|
28
75
|
}
|
|
29
76
|
console.log('Installing Claude Code CLI via npm...');
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
77
|
+
// Try global install first
|
|
78
|
+
const global = await runNpmInstall(['install', '-g', '@anthropic-ai/claude-code']);
|
|
79
|
+
if (global.ok) {
|
|
80
|
+
console.log('Claude Code CLI installed successfully via npm global');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Check if it was a permission error
|
|
84
|
+
const permissionDenied = /EACCES|permission denied/i.test(global.stderr);
|
|
85
|
+
if (!permissionDenied) {
|
|
86
|
+
throw new Error('Failed to install Claude Code CLI');
|
|
87
|
+
}
|
|
88
|
+
// Fallback to local install
|
|
89
|
+
// Use platform-specific local prefix path
|
|
90
|
+
let localPrefix;
|
|
91
|
+
if (process.platform === 'win32') {
|
|
92
|
+
localPrefix = join(homedir(), 'AppData', 'Local', 'ccodex', 'npm');
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
localPrefix = join(homedir(), '.local', 'ccodex', 'npm');
|
|
96
|
+
}
|
|
97
|
+
console.log(`Global install denied. Falling back to local prefix: ${localPrefix}`);
|
|
98
|
+
const local = await runNpmInstall(['install', '--prefix', localPrefix, '@anthropic-ai/claude-code']);
|
|
99
|
+
if (!local.ok) {
|
|
100
|
+
throw new Error('Failed to install Claude Code CLI (global + local fallback both failed)');
|
|
101
|
+
}
|
|
102
|
+
// Store the installed path using the persistent path function
|
|
103
|
+
installedClaudePath = getPersistentLocalClaudePath();
|
|
104
|
+
console.log(`Claude Code CLI installed locally: ${installedClaudePath}`);
|
|
46
105
|
}
|
|
47
106
|
/**
|
|
48
107
|
* Run Claude Code CLI with proxy environment
|
|
49
108
|
*/
|
|
50
109
|
export async function runClaude(args) {
|
|
51
|
-
|
|
52
|
-
|
|
110
|
+
// Detect Claude CLI using comprehensive detection (process-local, persistent local, system PATH)
|
|
111
|
+
const claudeCmd = await detectClaudeCommand();
|
|
112
|
+
if (!claudeCmd.cmd) {
|
|
113
|
+
throw new Error('claude CLI not found in PATH\nInstall Claude Code CLI first, then rerun: npx -y @tuannvm/ccodex');
|
|
53
114
|
}
|
|
115
|
+
// Use detected command (absolute path or command name)
|
|
116
|
+
const claudeExe = claudeCmd.cmd;
|
|
54
117
|
// Ensure proxy is running
|
|
55
118
|
await startProxy();
|
|
56
119
|
// Check auth, launch login if needed
|
|
@@ -75,14 +138,47 @@ export async function runClaude(args) {
|
|
|
75
138
|
const { homedir } = await import('os');
|
|
76
139
|
const userHome = homedir();
|
|
77
140
|
// Environment for Claude with proxy
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
141
|
+
// Minimal allowlist for subprocess environment.
|
|
142
|
+
// Default-deny: only pass values required for process execution and terminal UX.
|
|
143
|
+
const allowedEnvKeys = new Set([
|
|
144
|
+
'PATH',
|
|
145
|
+
'HOME',
|
|
146
|
+
'USERPROFILE',
|
|
147
|
+
'SYSTEMROOT',
|
|
148
|
+
'WINDIR',
|
|
149
|
+
'COMSPEC',
|
|
150
|
+
'PATHEXT',
|
|
151
|
+
'TMPDIR',
|
|
152
|
+
'TMP',
|
|
153
|
+
'TEMP',
|
|
154
|
+
'LANG',
|
|
155
|
+
'LC_ALL',
|
|
156
|
+
'LC_CTYPE',
|
|
157
|
+
'TERM',
|
|
158
|
+
'COLORTERM',
|
|
159
|
+
'NO_COLOR',
|
|
160
|
+
'FORCE_COLOR',
|
|
161
|
+
'CI',
|
|
162
|
+
'SHELL',
|
|
163
|
+
'PWD',
|
|
164
|
+
'OLDPWD',
|
|
165
|
+
'XDG_CONFIG_HOME',
|
|
166
|
+
'XDG_CACHE_HOME',
|
|
167
|
+
'XDG_DATA_HOME',
|
|
168
|
+
]);
|
|
169
|
+
const env = {};
|
|
170
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
171
|
+
if (value === undefined)
|
|
172
|
+
continue;
|
|
173
|
+
// On Windows env keys are case-insensitive; normalize for allowlist matching.
|
|
174
|
+
const normalized = process.platform === 'win32' ? key.toUpperCase() : key;
|
|
175
|
+
const allowed = allowedEnvKeys.has(normalized);
|
|
176
|
+
if (allowed) {
|
|
177
|
+
env[key] = value;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Set proxy config - dummy token is replaced by CLIProxyAPI's OAuth credentials
|
|
181
|
+
// The proxy handles ChatGPT authentication, this is just a format placeholder
|
|
86
182
|
env.ANTHROPIC_AUTH_TOKEN = 'sk-dummy';
|
|
87
183
|
env.ANTHROPIC_BASE_URL = 'http://127.0.0.1:8317';
|
|
88
184
|
env.API_TIMEOUT_MS = '120000';
|
|
@@ -105,7 +201,7 @@ export async function runClaude(args) {
|
|
|
105
201
|
env.DISABLE_ERROR_REPORTING = '1';
|
|
106
202
|
env.CLAUDE_CONFIG_DIR = join(userHome, '.claude-openai');
|
|
107
203
|
// Spawn Claude with modified environment
|
|
108
|
-
const child = spawnCmd(
|
|
204
|
+
const child = spawnCmd(claudeExe, args, {
|
|
109
205
|
stdio: 'inherit',
|
|
110
206
|
env,
|
|
111
207
|
});
|
package/dist/claude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
|