@gengjiawen/os-init 1.10.0 → 1.12.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/CHANGELOG.md +15 -0
- package/README.md +2 -3
- package/bin/bin.js +69 -4
- package/build/all-agents.d.ts +15 -0
- package/build/all-agents.js +20 -0
- package/build/claude-code.d.ts +4 -0
- package/build/claude-code.js +48 -0
- package/build/codex.d.ts +5 -0
- package/build/codex.js +46 -0
- package/build/gemini-cli.d.ts +5 -0
- package/build/gemini-cli.js +49 -0
- package/build/index.d.ts +4 -10
- package/build/index.js +15 -128
- package/build/utils.d.ts +2 -0
- package/build/utils.js +21 -0
- package/libs/all-agents.ts +27 -0
- package/libs/claude-code.ts +59 -0
- package/libs/codex.ts +56 -0
- package/libs/gemini-cli.ts +66 -0
- package/libs/index.ts +13 -163
- package/libs/utils.ts +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.12.0](https://github.com/gengjiawen/os-init/compare/v1.11.0...v1.12.0) (2026-01-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add command to setup all AI agents with configuration and dependency installation ([122973e](https://github.com/gengjiawen/os-init/commit/122973e87767713ac6f9a36d0197e53f98f0b323))
|
|
9
|
+
* add Gemini CLI setup command and configuration management ([9d8400a](https://github.com/gengjiawen/os-init/commit/9d8400acb48a4da3e0688b60d69f9ed1b1353b8d))
|
|
10
|
+
|
|
11
|
+
## [1.11.0](https://github.com/gengjiawen/os-init/compare/v1.10.0...v1.11.0) (2025-12-31)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* update model version in Codex config template from gpt-5.1 to gpt-5.2 ([56c36d3](https://github.com/gengjiawen/os-init/commit/56c36d3da5c3732100c090c4df3318b5cdd003cf))
|
|
17
|
+
|
|
3
18
|
## [1.10.0](https://github.com/gengjiawen/os-init/compare/v1.9.1...v1.10.0) (2025-12-06)
|
|
4
19
|
|
|
5
20
|
|
package/README.md
CHANGED
|
@@ -80,11 +80,10 @@ pnpx @gengjiawen/os-init set-fish
|
|
|
80
80
|
pnpx @gengjiawen/os-init set-cc <API_KEY>
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Configures Claude Code
|
|
83
|
+
Configures Claude Code with your API key. This command will:
|
|
84
84
|
|
|
85
|
-
- Write `~/.claude-code-router/config.json`
|
|
86
85
|
- Write `~/.claude/settings.json`
|
|
87
|
-
- Install global
|
|
86
|
+
- Install global tool: `@anthropic-ai/claude-code`
|
|
88
87
|
|
|
89
88
|
### Configure Codex CLI
|
|
90
89
|
|
package/bin/bin.js
CHANGED
|
@@ -6,6 +6,10 @@ const {
|
|
|
6
6
|
installDeps,
|
|
7
7
|
writeCodexConfig,
|
|
8
8
|
installCodexDeps,
|
|
9
|
+
writeGeminiConfig,
|
|
10
|
+
installGeminiDeps,
|
|
11
|
+
writeAllAgentsConfig,
|
|
12
|
+
installAllAgentsDeps,
|
|
9
13
|
writeRaycastConfig,
|
|
10
14
|
setupDevEnvironment,
|
|
11
15
|
setupAndroidEnvironment,
|
|
@@ -16,7 +20,7 @@ const program = new Command()
|
|
|
16
20
|
|
|
17
21
|
program
|
|
18
22
|
.command('set-cc')
|
|
19
|
-
.description('setup
|
|
23
|
+
.description('setup Claude Code')
|
|
20
24
|
.argument('<apiKey>', 'API key to set')
|
|
21
25
|
.action(async (apiKey) => {
|
|
22
26
|
// Ensure apiKey is provided
|
|
@@ -26,8 +30,7 @@ program
|
|
|
26
30
|
return
|
|
27
31
|
}
|
|
28
32
|
try {
|
|
29
|
-
const {
|
|
30
|
-
console.log(`Claude router config written to: ${routerConfigPath}`)
|
|
33
|
+
const { settingsPath } = writeClaudeConfig(apiKey)
|
|
31
34
|
console.log(`Claude settings written to: ${settingsPath}`)
|
|
32
35
|
await installDeps()
|
|
33
36
|
} catch (err) {
|
|
@@ -35,7 +38,7 @@ program
|
|
|
35
38
|
process.exit(1)
|
|
36
39
|
}
|
|
37
40
|
console.log(
|
|
38
|
-
'Claude
|
|
41
|
+
'Claude Code is ready, use `claude` in terminal to start building'
|
|
39
42
|
)
|
|
40
43
|
})
|
|
41
44
|
|
|
@@ -61,6 +64,68 @@ program
|
|
|
61
64
|
console.log('Codex is ready. use `codex` in terminal to start building')
|
|
62
65
|
})
|
|
63
66
|
|
|
67
|
+
program
|
|
68
|
+
.command('set-gemini')
|
|
69
|
+
.description('setup Gemini CLI config and auth')
|
|
70
|
+
.argument('<apiKey>', 'API key to set for Gemini CLI')
|
|
71
|
+
.action(async (apiKey) => {
|
|
72
|
+
if (!apiKey || String(apiKey).trim().length === 0) {
|
|
73
|
+
console.error('Missing required argument: <apiKey>')
|
|
74
|
+
program.help({ error: true })
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const { envPath, settingsPath } = writeGeminiConfig(apiKey)
|
|
79
|
+
console.log(`Gemini CLI env written to: ${envPath}`)
|
|
80
|
+
console.log(`Gemini CLI settings written to: ${settingsPath}`)
|
|
81
|
+
await installGeminiDeps()
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error('Failed to setup Gemini CLI:', err.message)
|
|
84
|
+
process.exit(1)
|
|
85
|
+
}
|
|
86
|
+
console.log(
|
|
87
|
+
'Gemini CLI is ready. use `gemini` in terminal to start building'
|
|
88
|
+
)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
program
|
|
92
|
+
.command('set-agents')
|
|
93
|
+
.description('setup all AI agents (Claude Code, Codex, Gemini CLI) at once')
|
|
94
|
+
.argument('<apiKey>', 'API key to set for all agents')
|
|
95
|
+
.action(async (apiKey) => {
|
|
96
|
+
if (!apiKey || String(apiKey).trim().length === 0) {
|
|
97
|
+
console.error('Missing required argument: <apiKey>')
|
|
98
|
+
program.help({ error: true })
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
console.log('Setting up all AI agents...\n')
|
|
103
|
+
|
|
104
|
+
const result = writeAllAgentsConfig(apiKey)
|
|
105
|
+
|
|
106
|
+
console.log('Claude Code:')
|
|
107
|
+
console.log(` Settings written to: ${result.claude.settingsPath}`)
|
|
108
|
+
|
|
109
|
+
console.log('\nCodex:')
|
|
110
|
+
console.log(` Config written to: ${result.codex.configPath}`)
|
|
111
|
+
console.log(` Auth written to: ${result.codex.authPath}`)
|
|
112
|
+
|
|
113
|
+
console.log('\nGemini CLI:')
|
|
114
|
+
console.log(` Env written to: ${result.gemini.envPath}`)
|
|
115
|
+
console.log(` Settings written to: ${result.gemini.settingsPath}`)
|
|
116
|
+
|
|
117
|
+
console.log('\nInstalling dependencies...')
|
|
118
|
+
await installAllAgentsDeps()
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error('Failed to setup agents:', err.message)
|
|
121
|
+
process.exit(1)
|
|
122
|
+
}
|
|
123
|
+
console.log('\nAll agents are ready!')
|
|
124
|
+
console.log(' - Use `claude` for Claude Code')
|
|
125
|
+
console.log(' - Use `codex` for Codex')
|
|
126
|
+
console.log(' - Use `gemini` for Gemini CLI')
|
|
127
|
+
})
|
|
128
|
+
|
|
64
129
|
program
|
|
65
130
|
.command('set-raycast-ai')
|
|
66
131
|
.description('setup Raycast AI providers config')
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AllAgentsResult {
|
|
2
|
+
claude: {
|
|
3
|
+
settingsPath: string;
|
|
4
|
+
};
|
|
5
|
+
codex: {
|
|
6
|
+
configPath: string;
|
|
7
|
+
authPath: string;
|
|
8
|
+
};
|
|
9
|
+
gemini: {
|
|
10
|
+
envPath: string;
|
|
11
|
+
settingsPath: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function writeAllAgentsConfig(apiKey: string): AllAgentsResult;
|
|
15
|
+
export declare function installAllAgentsDeps(): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeAllAgentsConfig = writeAllAgentsConfig;
|
|
4
|
+
exports.installAllAgentsDeps = installAllAgentsDeps;
|
|
5
|
+
const claude_code_1 = require("./claude-code");
|
|
6
|
+
const codex_1 = require("./codex");
|
|
7
|
+
const gemini_cli_1 = require("./gemini-cli");
|
|
8
|
+
function writeAllAgentsConfig(apiKey) {
|
|
9
|
+
const claudeResult = (0, claude_code_1.writeClaudeConfig)(apiKey);
|
|
10
|
+
const codexResult = (0, codex_1.writeCodexConfig)(apiKey);
|
|
11
|
+
const geminiResult = (0, gemini_cli_1.writeGeminiConfig)(apiKey);
|
|
12
|
+
return {
|
|
13
|
+
claude: claudeResult,
|
|
14
|
+
codex: codexResult,
|
|
15
|
+
gemini: geminiResult,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async function installAllAgentsDeps() {
|
|
19
|
+
await Promise.all([(0, claude_code_1.installDeps)(), (0, codex_1.installCodexDeps)(), (0, gemini_cli_1.installGeminiDeps)()]);
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeClaudeConfig = writeClaudeConfig;
|
|
4
|
+
exports.installDeps = installDeps;
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
const execa_1 = require("execa");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
function getClaudeSettingsDir() {
|
|
11
|
+
return path.join(os.homedir(), '.claude');
|
|
12
|
+
}
|
|
13
|
+
const CLAUDE_SETTINGS_TEMPLATE = `{
|
|
14
|
+
"env": {
|
|
15
|
+
"DISABLE_TELEMETRY": "1",
|
|
16
|
+
"OTEL_METRICS_EXPORTER": "otlp",
|
|
17
|
+
"ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
|
|
18
|
+
"ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
|
|
19
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
20
|
+
},
|
|
21
|
+
"includeCoAuthoredBy": false,
|
|
22
|
+
"apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
|
|
23
|
+
"permissions": {
|
|
24
|
+
"allow": [],
|
|
25
|
+
"deny": []
|
|
26
|
+
}
|
|
27
|
+
}`;
|
|
28
|
+
function writeClaudeConfig(apiKey) {
|
|
29
|
+
const settingsDir = getClaudeSettingsDir();
|
|
30
|
+
const settingsPath = path.join(settingsDir, 'settings.json');
|
|
31
|
+
(0, utils_1.ensureDir)(settingsDir);
|
|
32
|
+
const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(/API_KEY_PLACEHOLDER/g, apiKey);
|
|
33
|
+
fs.writeFileSync(settingsPath, settingsContent);
|
|
34
|
+
return { settingsPath };
|
|
35
|
+
}
|
|
36
|
+
async function installDeps() {
|
|
37
|
+
const packages = ['@anthropic-ai/claude-code'];
|
|
38
|
+
const usePnpm = await (0, utils_1.commandExists)('pnpm');
|
|
39
|
+
if (usePnpm) {
|
|
40
|
+
console.log('pnpm detected. Installing dependencies with pnpm...');
|
|
41
|
+
await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log('pnpm not found. Falling back to npm...');
|
|
45
|
+
await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
|
|
46
|
+
}
|
|
47
|
+
console.log('Dependencies installed successfully.');
|
|
48
|
+
}
|
package/build/codex.d.ts
ADDED
package/build/codex.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeCodexConfig = writeCodexConfig;
|
|
4
|
+
exports.installCodexDeps = installCodexDeps;
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
const execa_1 = require("execa");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
function getCodexConfigDir() {
|
|
11
|
+
return path.join(os.homedir(), '.codex');
|
|
12
|
+
}
|
|
13
|
+
const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
|
|
14
|
+
model = "gpt-5.2"
|
|
15
|
+
model_reasoning_effort = "high"
|
|
16
|
+
disable_response_storage = true
|
|
17
|
+
preferred_auth_method = "apikey"
|
|
18
|
+
|
|
19
|
+
[model_providers.jw]
|
|
20
|
+
name = "jw"
|
|
21
|
+
base_url = "https://ai.gengjiawen.com/api/openai"
|
|
22
|
+
wire_api = "responses"
|
|
23
|
+
`;
|
|
24
|
+
function writeCodexConfig(apiKey) {
|
|
25
|
+
const configDir = getCodexConfigDir();
|
|
26
|
+
(0, utils_1.ensureDir)(configDir);
|
|
27
|
+
const configPath = path.join(configDir, 'config.toml');
|
|
28
|
+
fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE);
|
|
29
|
+
const authPath = path.join(configDir, 'auth.json');
|
|
30
|
+
const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2);
|
|
31
|
+
fs.writeFileSync(authPath, authContent);
|
|
32
|
+
return { configPath, authPath };
|
|
33
|
+
}
|
|
34
|
+
async function installCodexDeps() {
|
|
35
|
+
const packages = ['@openai/codex'];
|
|
36
|
+
const usePnpm = await (0, utils_1.commandExists)('pnpm');
|
|
37
|
+
if (usePnpm) {
|
|
38
|
+
console.log('pnpm detected. Installing Codex dependency with pnpm...');
|
|
39
|
+
await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.log('pnpm not found. Falling back to npm...');
|
|
43
|
+
await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
|
|
44
|
+
}
|
|
45
|
+
console.log('Codex dependency installed successfully.');
|
|
46
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeGeminiConfig = writeGeminiConfig;
|
|
4
|
+
exports.installGeminiDeps = installGeminiDeps;
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
const execa_1 = require("execa");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
function getGeminiConfigDir() {
|
|
11
|
+
return path.join(os.homedir(), '.gemini');
|
|
12
|
+
}
|
|
13
|
+
const GEMINI_ENV_TEMPLATE = `GOOGLE_GEMINI_BASE_URL=https://ai.gengjiawen.com/api/gemini
|
|
14
|
+
GEMINI_API_KEY=API_KEY_PLACEHOLDER
|
|
15
|
+
GEMINI_MODEL=gemini-3-pro-preview
|
|
16
|
+
`;
|
|
17
|
+
const GEMINI_SETTINGS_TEMPLATE = {
|
|
18
|
+
ide: {
|
|
19
|
+
enabled: true,
|
|
20
|
+
},
|
|
21
|
+
security: {
|
|
22
|
+
auth: {
|
|
23
|
+
selectedType: 'gemini-api-key',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
function writeGeminiConfig(apiKey) {
|
|
28
|
+
const configDir = getGeminiConfigDir();
|
|
29
|
+
(0, utils_1.ensureDir)(configDir);
|
|
30
|
+
const envPath = path.join(configDir, '.env');
|
|
31
|
+
const envContent = GEMINI_ENV_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey);
|
|
32
|
+
fs.writeFileSync(envPath, envContent);
|
|
33
|
+
const settingsPath = path.join(configDir, 'settings.json');
|
|
34
|
+
fs.writeFileSync(settingsPath, JSON.stringify(GEMINI_SETTINGS_TEMPLATE, null, 2));
|
|
35
|
+
return { envPath, settingsPath };
|
|
36
|
+
}
|
|
37
|
+
async function installGeminiDeps() {
|
|
38
|
+
const usePnpm = await (0, utils_1.commandExists)('pnpm');
|
|
39
|
+
const geminiPackage = '@google/gemini-cli';
|
|
40
|
+
if (usePnpm) {
|
|
41
|
+
console.log('pnpm detected. Installing Gemini CLI with pnpm...');
|
|
42
|
+
await (0, execa_1.execa)('pnpm', ['add', '-g', geminiPackage], { stdio: 'inherit' });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log('pnpm not found. Falling back to npm...');
|
|
46
|
+
await (0, execa_1.execa)('npm', ['install', '-g', geminiPackage], { stdio: 'inherit' });
|
|
47
|
+
}
|
|
48
|
+
console.log('Gemini CLI installed successfully.');
|
|
49
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
export declare function writeClaudeConfig(apiKey: string): {
|
|
2
|
-
routerConfigPath: string;
|
|
3
|
-
settingsPath: string;
|
|
4
|
-
};
|
|
5
|
-
export declare function installDeps(): Promise<void>;
|
|
6
|
-
export declare function writeCodexConfig(apiKey: string): {
|
|
7
|
-
configPath: string;
|
|
8
|
-
authPath: string;
|
|
9
|
-
};
|
|
10
|
-
export declare function installCodexDeps(): Promise<void>;
|
|
11
1
|
export declare function writeRaycastConfig(apiKey: string): {
|
|
12
2
|
configPath: string;
|
|
13
3
|
};
|
|
4
|
+
export { writeClaudeConfig, installDeps } from './claude-code';
|
|
5
|
+
export { writeCodexConfig, installCodexDeps } from './codex';
|
|
6
|
+
export { writeGeminiConfig, installGeminiDeps } from './gemini-cli';
|
|
7
|
+
export { writeAllAgentsConfig, installAllAgentsDeps } from './all-agents';
|
|
14
8
|
export { setupDevEnvironment } from './dev-setup';
|
|
15
9
|
export { setupAndroidEnvironment } from './android-setup';
|
package/build/index.js
CHANGED
|
@@ -1,136 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupAndroidEnvironment = exports.setupDevEnvironment = void 0;
|
|
4
|
-
exports.writeClaudeConfig = writeClaudeConfig;
|
|
5
|
-
exports.installDeps = installDeps;
|
|
6
|
-
exports.writeCodexConfig = writeCodexConfig;
|
|
7
|
-
exports.installCodexDeps = installCodexDeps;
|
|
3
|
+
exports.setupAndroidEnvironment = exports.setupDevEnvironment = exports.installAllAgentsDeps = exports.writeAllAgentsConfig = exports.installGeminiDeps = exports.writeGeminiConfig = exports.installCodexDeps = exports.writeCodexConfig = exports.installDeps = exports.writeClaudeConfig = void 0;
|
|
8
4
|
exports.writeRaycastConfig = writeRaycastConfig;
|
|
9
5
|
const fs = require("fs");
|
|
10
6
|
const path = require("path");
|
|
11
7
|
const os = require("os");
|
|
12
|
-
const
|
|
13
|
-
function getDefaultConfigDir() {
|
|
14
|
-
return path.join(os.homedir(), '.claude-code-router');
|
|
15
|
-
}
|
|
16
|
-
function ensureDir(dirPath) {
|
|
17
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
const DEFAULT_TEMPLATE = `{
|
|
20
|
-
"Providers": [
|
|
21
|
-
{
|
|
22
|
-
"name": "jw",
|
|
23
|
-
"api_base_url": "https://ai.gengjiawen.com/api/openai/v1/chat/completions",
|
|
24
|
-
"api_key": "API_KEY_PLACEHOLDER",
|
|
25
|
-
"models": ["code", "free"],
|
|
26
|
-
"transformer": {
|
|
27
|
-
"use": ["openrouter"]
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
],
|
|
31
|
-
"Router": {
|
|
32
|
-
"default": "jw,code",
|
|
33
|
-
"background": "jw,code",
|
|
34
|
-
"think": "jw,code",
|
|
35
|
-
"longContext": "jw,code"
|
|
36
|
-
}
|
|
37
|
-
}`;
|
|
38
|
-
function getClaudeSettingsDir() {
|
|
39
|
-
return path.join(os.homedir(), '.claude');
|
|
40
|
-
}
|
|
41
|
-
const CLAUDE_SETTINGS_TEMPLATE = `{
|
|
42
|
-
"env": {
|
|
43
|
-
"DISABLE_TELEMETRY": "1",
|
|
44
|
-
"OTEL_METRICS_EXPORTER": "otlp",
|
|
45
|
-
"ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
|
|
46
|
-
"ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
|
|
47
|
-
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
48
|
-
},
|
|
49
|
-
"includeCoAuthoredBy": false,
|
|
50
|
-
"apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
|
|
51
|
-
"permissions": {
|
|
52
|
-
"allow": [],
|
|
53
|
-
"deny": []
|
|
54
|
-
}
|
|
55
|
-
}`;
|
|
56
|
-
function writeClaudeConfig(apiKey) {
|
|
57
|
-
const routerConfigDir = getDefaultConfigDir();
|
|
58
|
-
const routerConfigPath = path.join(routerConfigDir, 'config.json');
|
|
59
|
-
ensureDir(routerConfigDir);
|
|
60
|
-
const routerContent = DEFAULT_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey);
|
|
61
|
-
fs.writeFileSync(routerConfigPath, routerContent);
|
|
62
|
-
const settingsDir = getClaudeSettingsDir();
|
|
63
|
-
const settingsPath = path.join(settingsDir, 'settings.json');
|
|
64
|
-
ensureDir(settingsDir);
|
|
65
|
-
const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(/API_KEY_PLACEHOLDER/g, apiKey);
|
|
66
|
-
fs.writeFileSync(settingsPath, settingsContent);
|
|
67
|
-
return { routerConfigPath, settingsPath };
|
|
68
|
-
}
|
|
69
|
-
async function commandExists(command) {
|
|
70
|
-
try {
|
|
71
|
-
const { failed } = await (0, execa_1.execa)(command, ['--version'], {
|
|
72
|
-
stdio: 'ignore',
|
|
73
|
-
reject: false,
|
|
74
|
-
});
|
|
75
|
-
return !failed;
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
async function installDeps() {
|
|
82
|
-
const packages = [
|
|
83
|
-
'@anthropic-ai/claude-code',
|
|
84
|
-
'@musistudio/claude-code-router',
|
|
85
|
-
];
|
|
86
|
-
const usePnpm = await commandExists('pnpm');
|
|
87
|
-
if (usePnpm) {
|
|
88
|
-
console.log('pnpm detected. Installing dependencies with pnpm...');
|
|
89
|
-
await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
console.log('pnpm not found. Falling back to npm...');
|
|
93
|
-
await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
|
|
94
|
-
}
|
|
95
|
-
console.log('Dependencies installed successfully.');
|
|
96
|
-
}
|
|
97
|
-
function getCodexConfigDir() {
|
|
98
|
-
return path.join(os.homedir(), '.codex');
|
|
99
|
-
}
|
|
100
|
-
const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
|
|
101
|
-
model = "gpt-5.1"
|
|
102
|
-
model_reasoning_effort = "high"
|
|
103
|
-
disable_response_storage = true
|
|
104
|
-
preferred_auth_method = "apikey"
|
|
105
|
-
|
|
106
|
-
[model_providers.jw]
|
|
107
|
-
name = "jw"
|
|
108
|
-
base_url = "https://ai.gengjiawen.com/api/openai"
|
|
109
|
-
wire_api = "responses"
|
|
110
|
-
`;
|
|
111
|
-
function writeCodexConfig(apiKey) {
|
|
112
|
-
const configDir = getCodexConfigDir();
|
|
113
|
-
ensureDir(configDir);
|
|
114
|
-
const configPath = path.join(configDir, 'config.toml');
|
|
115
|
-
fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE);
|
|
116
|
-
const authPath = path.join(configDir, 'auth.json');
|
|
117
|
-
const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2);
|
|
118
|
-
fs.writeFileSync(authPath, authContent);
|
|
119
|
-
return { configPath, authPath };
|
|
120
|
-
}
|
|
121
|
-
async function installCodexDeps() {
|
|
122
|
-
const packages = ['@openai/codex'];
|
|
123
|
-
const usePnpm = await commandExists('pnpm');
|
|
124
|
-
if (usePnpm) {
|
|
125
|
-
console.log('pnpm detected. Installing Codex dependency with pnpm...');
|
|
126
|
-
await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
console.log('pnpm not found. Falling back to npm...');
|
|
130
|
-
await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
|
|
131
|
-
}
|
|
132
|
-
console.log('Codex dependency installed successfully.');
|
|
133
|
-
}
|
|
8
|
+
const utils_1 = require("./utils");
|
|
134
9
|
function getRaycastAIConfigDir() {
|
|
135
10
|
return path.join(os.homedir(), '.config', 'raycast', 'ai');
|
|
136
11
|
}
|
|
@@ -157,12 +32,24 @@ const RAYCAST_PROVIDERS_YAML_TEMPLATE = `providers:
|
|
|
157
32
|
`;
|
|
158
33
|
function writeRaycastConfig(apiKey) {
|
|
159
34
|
const configDir = getRaycastAIConfigDir();
|
|
160
|
-
ensureDir(configDir);
|
|
35
|
+
(0, utils_1.ensureDir)(configDir);
|
|
161
36
|
const configPath = path.join(configDir, 'providers.yaml');
|
|
162
37
|
const content = RAYCAST_PROVIDERS_YAML_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey);
|
|
163
38
|
fs.writeFileSync(configPath, content);
|
|
164
39
|
return { configPath };
|
|
165
40
|
}
|
|
41
|
+
var claude_code_1 = require("./claude-code");
|
|
42
|
+
Object.defineProperty(exports, "writeClaudeConfig", { enumerable: true, get: function () { return claude_code_1.writeClaudeConfig; } });
|
|
43
|
+
Object.defineProperty(exports, "installDeps", { enumerable: true, get: function () { return claude_code_1.installDeps; } });
|
|
44
|
+
var codex_1 = require("./codex");
|
|
45
|
+
Object.defineProperty(exports, "writeCodexConfig", { enumerable: true, get: function () { return codex_1.writeCodexConfig; } });
|
|
46
|
+
Object.defineProperty(exports, "installCodexDeps", { enumerable: true, get: function () { return codex_1.installCodexDeps; } });
|
|
47
|
+
var gemini_cli_1 = require("./gemini-cli");
|
|
48
|
+
Object.defineProperty(exports, "writeGeminiConfig", { enumerable: true, get: function () { return gemini_cli_1.writeGeminiConfig; } });
|
|
49
|
+
Object.defineProperty(exports, "installGeminiDeps", { enumerable: true, get: function () { return gemini_cli_1.installGeminiDeps; } });
|
|
50
|
+
var all_agents_1 = require("./all-agents");
|
|
51
|
+
Object.defineProperty(exports, "writeAllAgentsConfig", { enumerable: true, get: function () { return all_agents_1.writeAllAgentsConfig; } });
|
|
52
|
+
Object.defineProperty(exports, "installAllAgentsDeps", { enumerable: true, get: function () { return all_agents_1.installAllAgentsDeps; } });
|
|
166
53
|
var dev_setup_1 = require("./dev-setup");
|
|
167
54
|
Object.defineProperty(exports, "setupDevEnvironment", { enumerable: true, get: function () { return dev_setup_1.setupDevEnvironment; } });
|
|
168
55
|
var android_setup_1 = require("./android-setup");
|
package/build/utils.d.ts
ADDED
package/build/utils.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureDir = ensureDir;
|
|
4
|
+
exports.commandExists = commandExists;
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const execa_1 = require("execa");
|
|
7
|
+
function ensureDir(dirPath) {
|
|
8
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
async function commandExists(command) {
|
|
11
|
+
try {
|
|
12
|
+
const { failed } = await (0, execa_1.execa)(command, ['--version'], {
|
|
13
|
+
stdio: 'ignore',
|
|
14
|
+
reject: false,
|
|
15
|
+
});
|
|
16
|
+
return !failed;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { writeClaudeConfig, installDeps } from './claude-code'
|
|
2
|
+
import { writeCodexConfig, installCodexDeps } from './codex'
|
|
3
|
+
import { writeGeminiConfig, installGeminiDeps } from './gemini-cli'
|
|
4
|
+
|
|
5
|
+
export interface AllAgentsResult {
|
|
6
|
+
claude: { settingsPath: string }
|
|
7
|
+
codex: { configPath: string; authPath: string }
|
|
8
|
+
gemini: { envPath: string; settingsPath: string }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Write configuration for all three agents (Claude Code, Codex, Gemini CLI) */
|
|
12
|
+
export function writeAllAgentsConfig(apiKey: string): AllAgentsResult {
|
|
13
|
+
const claudeResult = writeClaudeConfig(apiKey)
|
|
14
|
+
const codexResult = writeCodexConfig(apiKey)
|
|
15
|
+
const geminiResult = writeGeminiConfig(apiKey)
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
claude: claudeResult,
|
|
19
|
+
codex: codexResult,
|
|
20
|
+
gemini: geminiResult,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Install dependencies for all three agents */
|
|
25
|
+
export async function installAllAgentsDeps(): Promise<void> {
|
|
26
|
+
await Promise.all([installDeps(), installCodexDeps(), installGeminiDeps()])
|
|
27
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import { execa } from 'execa'
|
|
5
|
+
import { ensureDir, commandExists } from './utils'
|
|
6
|
+
|
|
7
|
+
/** Return Claude settings directory path */
|
|
8
|
+
function getClaudeSettingsDir(): string {
|
|
9
|
+
return path.join(os.homedir(), '.claude')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Template for Claude settings.json */
|
|
13
|
+
const CLAUDE_SETTINGS_TEMPLATE = `{
|
|
14
|
+
"env": {
|
|
15
|
+
"DISABLE_TELEMETRY": "1",
|
|
16
|
+
"OTEL_METRICS_EXPORTER": "otlp",
|
|
17
|
+
"ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
|
|
18
|
+
"ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
|
|
19
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
20
|
+
},
|
|
21
|
+
"includeCoAuthoredBy": false,
|
|
22
|
+
"apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
|
|
23
|
+
"permissions": {
|
|
24
|
+
"allow": [],
|
|
25
|
+
"deny": []
|
|
26
|
+
}
|
|
27
|
+
}`
|
|
28
|
+
|
|
29
|
+
/** Write Claude config files */
|
|
30
|
+
export function writeClaudeConfig(apiKey: string): {
|
|
31
|
+
settingsPath: string
|
|
32
|
+
} {
|
|
33
|
+
// Write Claude settings
|
|
34
|
+
const settingsDir = getClaudeSettingsDir()
|
|
35
|
+
const settingsPath = path.join(settingsDir, 'settings.json')
|
|
36
|
+
ensureDir(settingsDir)
|
|
37
|
+
const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(
|
|
38
|
+
/API_KEY_PLACEHOLDER/g,
|
|
39
|
+
apiKey
|
|
40
|
+
)
|
|
41
|
+
fs.writeFileSync(settingsPath, settingsContent)
|
|
42
|
+
|
|
43
|
+
return { settingsPath }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Install global dependencies */
|
|
47
|
+
export async function installDeps(): Promise<void> {
|
|
48
|
+
const packages = ['@anthropic-ai/claude-code']
|
|
49
|
+
const usePnpm = await commandExists('pnpm')
|
|
50
|
+
|
|
51
|
+
if (usePnpm) {
|
|
52
|
+
console.log('pnpm detected. Installing dependencies with pnpm...')
|
|
53
|
+
await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
|
|
54
|
+
} else {
|
|
55
|
+
console.log('pnpm not found. Falling back to npm...')
|
|
56
|
+
await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
|
|
57
|
+
}
|
|
58
|
+
console.log('Dependencies installed successfully.')
|
|
59
|
+
}
|
package/libs/codex.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import { execa } from 'execa'
|
|
5
|
+
import { ensureDir, commandExists } from './utils'
|
|
6
|
+
|
|
7
|
+
/** Return Codex configuration directory path */
|
|
8
|
+
function getCodexConfigDir(): string {
|
|
9
|
+
return path.join(os.homedir(), '.codex')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Template for Codex config.toml */
|
|
13
|
+
const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
|
|
14
|
+
model = "gpt-5.2"
|
|
15
|
+
model_reasoning_effort = "high"
|
|
16
|
+
disable_response_storage = true
|
|
17
|
+
preferred_auth_method = "apikey"
|
|
18
|
+
|
|
19
|
+
[model_providers.jw]
|
|
20
|
+
name = "jw"
|
|
21
|
+
base_url = "https://ai.gengjiawen.com/api/openai"
|
|
22
|
+
wire_api = "responses"
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
/** Write Codex config.toml and auth.json */
|
|
26
|
+
export function writeCodexConfig(apiKey: string): {
|
|
27
|
+
configPath: string
|
|
28
|
+
authPath: string
|
|
29
|
+
} {
|
|
30
|
+
const configDir = getCodexConfigDir()
|
|
31
|
+
ensureDir(configDir)
|
|
32
|
+
|
|
33
|
+
const configPath = path.join(configDir, 'config.toml')
|
|
34
|
+
fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE)
|
|
35
|
+
|
|
36
|
+
const authPath = path.join(configDir, 'auth.json')
|
|
37
|
+
const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)
|
|
38
|
+
fs.writeFileSync(authPath, authContent)
|
|
39
|
+
|
|
40
|
+
return { configPath, authPath }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Install Codex dependency */
|
|
44
|
+
export async function installCodexDeps(): Promise<void> {
|
|
45
|
+
const packages = ['@openai/codex']
|
|
46
|
+
const usePnpm = await commandExists('pnpm')
|
|
47
|
+
|
|
48
|
+
if (usePnpm) {
|
|
49
|
+
console.log('pnpm detected. Installing Codex dependency with pnpm...')
|
|
50
|
+
await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
|
|
51
|
+
} else {
|
|
52
|
+
console.log('pnpm not found. Falling back to npm...')
|
|
53
|
+
await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
|
|
54
|
+
}
|
|
55
|
+
console.log('Codex dependency installed successfully.')
|
|
56
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import * as os from 'os'
|
|
4
|
+
import { execa } from 'execa'
|
|
5
|
+
import { ensureDir, commandExists } from './utils'
|
|
6
|
+
|
|
7
|
+
/** Return Gemini CLI configuration directory path */
|
|
8
|
+
function getGeminiConfigDir(): string {
|
|
9
|
+
return path.join(os.homedir(), '.gemini')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Template for Gemini CLI .env file */
|
|
13
|
+
const GEMINI_ENV_TEMPLATE = `GOOGLE_GEMINI_BASE_URL=https://ai.gengjiawen.com/api/gemini
|
|
14
|
+
GEMINI_API_KEY=API_KEY_PLACEHOLDER
|
|
15
|
+
GEMINI_MODEL=gemini-3-pro-preview
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
/** Template for Gemini CLI settings.json */
|
|
19
|
+
const GEMINI_SETTINGS_TEMPLATE = {
|
|
20
|
+
ide: {
|
|
21
|
+
enabled: true,
|
|
22
|
+
},
|
|
23
|
+
security: {
|
|
24
|
+
auth: {
|
|
25
|
+
selectedType: 'gemini-api-key',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Write Gemini CLI config files (.env and settings.json) */
|
|
31
|
+
export function writeGeminiConfig(apiKey: string): {
|
|
32
|
+
envPath: string
|
|
33
|
+
settingsPath: string
|
|
34
|
+
} {
|
|
35
|
+
const configDir = getGeminiConfigDir()
|
|
36
|
+
ensureDir(configDir)
|
|
37
|
+
|
|
38
|
+
// Write .env file
|
|
39
|
+
const envPath = path.join(configDir, '.env')
|
|
40
|
+
const envContent = GEMINI_ENV_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey)
|
|
41
|
+
fs.writeFileSync(envPath, envContent)
|
|
42
|
+
|
|
43
|
+
// Write settings.json file
|
|
44
|
+
const settingsPath = path.join(configDir, 'settings.json')
|
|
45
|
+
fs.writeFileSync(
|
|
46
|
+
settingsPath,
|
|
47
|
+
JSON.stringify(GEMINI_SETTINGS_TEMPLATE, null, 2)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return { envPath, settingsPath }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Install Gemini CLI dependency */
|
|
54
|
+
export async function installGeminiDeps(): Promise<void> {
|
|
55
|
+
const usePnpm = await commandExists('pnpm')
|
|
56
|
+
const geminiPackage = '@google/gemini-cli'
|
|
57
|
+
|
|
58
|
+
if (usePnpm) {
|
|
59
|
+
console.log('pnpm detected. Installing Gemini CLI with pnpm...')
|
|
60
|
+
await execa('pnpm', ['add', '-g', geminiPackage], { stdio: 'inherit' })
|
|
61
|
+
} else {
|
|
62
|
+
console.log('pnpm not found. Falling back to npm...')
|
|
63
|
+
await execa('npm', ['install', '-g', geminiPackage], { stdio: 'inherit' })
|
|
64
|
+
}
|
|
65
|
+
console.log('Gemini CLI installed successfully.')
|
|
66
|
+
}
|
package/libs/index.ts
CHANGED
|
@@ -1,169 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs'
|
|
2
2
|
import * as path from 'path'
|
|
3
3
|
import * as os from 'os'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
/** Return default configuration directory path */
|
|
7
|
-
function getDefaultConfigDir(): string {
|
|
8
|
-
return path.join(os.homedir(), '.claude-code-router')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Ensure directory exists */
|
|
12
|
-
function ensureDir(dirPath: string): void {
|
|
13
|
-
fs.mkdirSync(dirPath, { recursive: true })
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Template string used for simple string replacement */
|
|
17
|
-
const DEFAULT_TEMPLATE = `{
|
|
18
|
-
"Providers": [
|
|
19
|
-
{
|
|
20
|
-
"name": "jw",
|
|
21
|
-
"api_base_url": "https://ai.gengjiawen.com/api/openai/v1/chat/completions",
|
|
22
|
-
"api_key": "API_KEY_PLACEHOLDER",
|
|
23
|
-
"models": ["code", "free"],
|
|
24
|
-
"transformer": {
|
|
25
|
-
"use": ["openrouter"]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
"Router": {
|
|
30
|
-
"default": "jw,code",
|
|
31
|
-
"background": "jw,code",
|
|
32
|
-
"think": "jw,code",
|
|
33
|
-
"longContext": "jw,code"
|
|
34
|
-
}
|
|
35
|
-
}`
|
|
36
|
-
|
|
37
|
-
/** Return Claude settings directory path */
|
|
38
|
-
function getClaudeSettingsDir(): string {
|
|
39
|
-
return path.join(os.homedir(), '.claude')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Template for Claude settings.json */
|
|
43
|
-
const CLAUDE_SETTINGS_TEMPLATE = `{
|
|
44
|
-
"env": {
|
|
45
|
-
"DISABLE_TELEMETRY": "1",
|
|
46
|
-
"OTEL_METRICS_EXPORTER": "otlp",
|
|
47
|
-
"ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
|
|
48
|
-
"ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
|
|
49
|
-
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
50
|
-
},
|
|
51
|
-
"includeCoAuthoredBy": false,
|
|
52
|
-
"apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
|
|
53
|
-
"permissions": {
|
|
54
|
-
"allow": [],
|
|
55
|
-
"deny": []
|
|
56
|
-
}
|
|
57
|
-
}`
|
|
58
|
-
|
|
59
|
-
/** Write Claude config files (both router config and settings) */
|
|
60
|
-
export function writeClaudeConfig(apiKey: string): {
|
|
61
|
-
routerConfigPath: string
|
|
62
|
-
settingsPath: string
|
|
63
|
-
} {
|
|
64
|
-
// Write claude-code-router config
|
|
65
|
-
const routerConfigDir = getDefaultConfigDir()
|
|
66
|
-
const routerConfigPath = path.join(routerConfigDir, 'config.json')
|
|
67
|
-
ensureDir(routerConfigDir)
|
|
68
|
-
const routerContent = DEFAULT_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey)
|
|
69
|
-
fs.writeFileSync(routerConfigPath, routerContent)
|
|
70
|
-
|
|
71
|
-
// Write Claude settings
|
|
72
|
-
const settingsDir = getClaudeSettingsDir()
|
|
73
|
-
const settingsPath = path.join(settingsDir, 'settings.json')
|
|
74
|
-
ensureDir(settingsDir)
|
|
75
|
-
const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(
|
|
76
|
-
/API_KEY_PLACEHOLDER/g,
|
|
77
|
-
apiKey
|
|
78
|
-
)
|
|
79
|
-
fs.writeFileSync(settingsPath, settingsContent)
|
|
80
|
-
|
|
81
|
-
return { routerConfigPath, settingsPath }
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** Check if a command exists */
|
|
85
|
-
async function commandExists(command: string): Promise<boolean> {
|
|
86
|
-
try {
|
|
87
|
-
// execa with reject: false will not throw on non-zero exit codes.
|
|
88
|
-
const { failed } = await execa(command, ['--version'], {
|
|
89
|
-
stdio: 'ignore',
|
|
90
|
-
reject: false,
|
|
91
|
-
})
|
|
92
|
-
return !failed
|
|
93
|
-
} catch (error) {
|
|
94
|
-
// Catch errors for commands that don't support --version or other issues
|
|
95
|
-
return false
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Install global dependencies */
|
|
100
|
-
export async function installDeps(): Promise<void> {
|
|
101
|
-
const packages = [
|
|
102
|
-
'@anthropic-ai/claude-code',
|
|
103
|
-
'@musistudio/claude-code-router',
|
|
104
|
-
]
|
|
105
|
-
const usePnpm = await commandExists('pnpm')
|
|
106
|
-
|
|
107
|
-
if (usePnpm) {
|
|
108
|
-
console.log('pnpm detected. Installing dependencies with pnpm...')
|
|
109
|
-
await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
|
|
110
|
-
} else {
|
|
111
|
-
console.log('pnpm not found. Falling back to npm...')
|
|
112
|
-
await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
|
|
113
|
-
}
|
|
114
|
-
console.log('Dependencies installed successfully.')
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Return Codex configuration directory path */
|
|
118
|
-
function getCodexConfigDir(): string {
|
|
119
|
-
return path.join(os.homedir(), '.codex')
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Template for Codex config.toml */
|
|
123
|
-
const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
|
|
124
|
-
model = "gpt-5.1"
|
|
125
|
-
model_reasoning_effort = "high"
|
|
126
|
-
disable_response_storage = true
|
|
127
|
-
preferred_auth_method = "apikey"
|
|
128
|
-
|
|
129
|
-
[model_providers.jw]
|
|
130
|
-
name = "jw"
|
|
131
|
-
base_url = "https://ai.gengjiawen.com/api/openai"
|
|
132
|
-
wire_api = "responses"
|
|
133
|
-
`
|
|
134
|
-
|
|
135
|
-
/** Write Codex config.toml and auth.json */
|
|
136
|
-
export function writeCodexConfig(apiKey: string): {
|
|
137
|
-
configPath: string
|
|
138
|
-
authPath: string
|
|
139
|
-
} {
|
|
140
|
-
const configDir = getCodexConfigDir()
|
|
141
|
-
ensureDir(configDir)
|
|
142
|
-
|
|
143
|
-
const configPath = path.join(configDir, 'config.toml')
|
|
144
|
-
fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE)
|
|
145
|
-
|
|
146
|
-
const authPath = path.join(configDir, 'auth.json')
|
|
147
|
-
const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)
|
|
148
|
-
fs.writeFileSync(authPath, authContent)
|
|
149
|
-
|
|
150
|
-
return { configPath, authPath }
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** Install Codex dependency */
|
|
154
|
-
export async function installCodexDeps(): Promise<void> {
|
|
155
|
-
const packages = ['@openai/codex']
|
|
156
|
-
const usePnpm = await commandExists('pnpm')
|
|
157
|
-
|
|
158
|
-
if (usePnpm) {
|
|
159
|
-
console.log('pnpm detected. Installing Codex dependency with pnpm...')
|
|
160
|
-
await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
|
|
161
|
-
} else {
|
|
162
|
-
console.log('pnpm not found. Falling back to npm...')
|
|
163
|
-
await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
|
|
164
|
-
}
|
|
165
|
-
console.log('Codex dependency installed successfully.')
|
|
166
|
-
}
|
|
4
|
+
import { ensureDir } from './utils'
|
|
167
5
|
|
|
168
6
|
/** Return Raycast AI configuration directory path */
|
|
169
7
|
function getRaycastAIConfigDir(): string {
|
|
@@ -208,6 +46,18 @@ export function writeRaycastConfig(apiKey: string): { configPath: string } {
|
|
|
208
46
|
return { configPath }
|
|
209
47
|
}
|
|
210
48
|
|
|
49
|
+
// Re-export claude-code functionality
|
|
50
|
+
export { writeClaudeConfig, installDeps } from './claude-code'
|
|
51
|
+
|
|
52
|
+
// Re-export codex functionality
|
|
53
|
+
export { writeCodexConfig, installCodexDeps } from './codex'
|
|
54
|
+
|
|
55
|
+
// Re-export gemini-cli functionality
|
|
56
|
+
export { writeGeminiConfig, installGeminiDeps } from './gemini-cli'
|
|
57
|
+
|
|
58
|
+
// Re-export all-agents functionality
|
|
59
|
+
export { writeAllAgentsConfig, installAllAgentsDeps } from './all-agents'
|
|
60
|
+
|
|
211
61
|
// Re-export dev-setup functionality
|
|
212
62
|
export { setupDevEnvironment } from './dev-setup'
|
|
213
63
|
|
package/libs/utils.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import { execa } from 'execa'
|
|
3
|
+
|
|
4
|
+
/** Ensure directory exists */
|
|
5
|
+
export function ensureDir(dirPath: string): void {
|
|
6
|
+
fs.mkdirSync(dirPath, { recursive: true })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Check if a command exists */
|
|
10
|
+
export async function commandExists(command: string): Promise<boolean> {
|
|
11
|
+
try {
|
|
12
|
+
// execa with reject: false will not throw on non-zero exit codes.
|
|
13
|
+
const { failed } = await execa(command, ['--version'], {
|
|
14
|
+
stdio: 'ignore',
|
|
15
|
+
reject: false,
|
|
16
|
+
})
|
|
17
|
+
return !failed
|
|
18
|
+
} catch (error) {
|
|
19
|
+
// Catch errors for commands that don't support --version or other issues
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
}
|