@gengjiawen/os-init 1.11.0 → 1.13.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/AGENTS.md ADDED
@@ -0,0 +1,42 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure
4
+
5
+ - `bin/`: Node CLI entrypoint (`bin/bin.js`) and command definitions (e.g., `set-codex`, `set-gemini`).
6
+ - `libs/`: TypeScript source for config writers/installers and setup utilities (main exports in `libs/index.ts`).
7
+ - `build/`: Compiled JS + `.d.ts` output from `tsc` (`outDir`), consumed by the CLI and published to npm.
8
+ - `dev-setup/`: Optional Docker-based dev environment (sshd + compose) for remote/portable workflows.
9
+ - `.github/workflows/`: CI (`nodejs.yml`) and automated releases via Release Please (`release-please.yml`).
10
+
11
+ ## Build, Test, and Development Commands
12
+
13
+ Use `pnpm` (CI uses it).
14
+
15
+ - `pnpm install`: install dependencies.
16
+ - `pnpm dev`: run TypeScript compiler in watch mode.
17
+ - `pnpm build`: clean and compile to `build/` (then copies non-TS assets from `libs/`).
18
+ - `pnpm test`: run Jest (TypeScript via `ts-jest`).
19
+ - `pnpm format` / `pnpm format:check`: format or verify formatting with Prettier.
20
+
21
+ ## Coding Style & Naming Conventions
22
+
23
+ - Formatting: Prettier (no semicolons, single quotes). Run `pnpm format` before pushing.
24
+ - TypeScript: strict options are enabled; prefer explicit, typed helpers over `any`.
25
+ - Naming: files are kebab-case in `libs/` (e.g., `gemini-cli.ts`); exported functions are `camelCase`.
26
+
27
+ ## Testing Guidelines
28
+
29
+ - Framework: Jest + `ts-jest`.
30
+ - Naming: place tests next to code as `*.test.ts` (example: `libs/index.test.ts`).
31
+ - Keep tests hermetic: avoid writing to real user paths; prefer temp dirs/mocks when testing config output.
32
+
33
+ ## Commit & Pull Request Guidelines
34
+
35
+ - Commits follow Conventional Commits (observed history): `feat: ...`, `fix: ...`, `refactor: ...`, `chore: ...`.
36
+ - Releases are automated on `master` via Release Please; don’t manually bump versions in PRs.
37
+ - PRs should include: a clear description, validation steps (`pnpm build && pnpm test && pnpm format:check`), and any relevant config/output examples.
38
+
39
+ ## Security & Configuration Tips
40
+
41
+ - This repo generates local agent config files and may handle API keys. Never commit secrets or generated config files.
42
+ - When adding new setup commands, document where files are written and keep defaults safe/least-privilege.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.13.0](https://github.com/gengjiawen/os-init/compare/v1.12.0...v1.13.0) (2026-01-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add --full to include gemini in set-agents ([defdaca](https://github.com/gengjiawen/os-init/commit/defdaca67c0cea3d2d449a68b69080f68cf6f771))
9
+
10
+ ## [1.12.0](https://github.com/gengjiawen/os-init/compare/v1.11.0...v1.12.0) (2026-01-05)
11
+
12
+
13
+ ### Features
14
+
15
+ * add command to setup all AI agents with configuration and dependency installation ([122973e](https://github.com/gengjiawen/os-init/commit/122973e87767713ac6f9a36d0197e53f98f0b323))
16
+ * add Gemini CLI setup command and configuration management ([9d8400a](https://github.com/gengjiawen/os-init/commit/9d8400acb48a4da3e0688b60d69f9ed1b1353b8d))
17
+
3
18
  ## [1.11.0](https://github.com/gengjiawen/os-init/compare/v1.10.0...v1.11.0) (2025-12-31)
4
19
 
5
20
 
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,
@@ -60,6 +64,81 @@ program
60
64
  console.log('Codex is ready. use `codex` in terminal to start building')
61
65
  })
62
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(
94
+ 'setup Claude Code and Codex at once (use --full to include Gemini CLI)'
95
+ )
96
+ .argument('<apiKey>', 'API key to set for agents')
97
+ .option('--full', 'Also setup Gemini CLI')
98
+ .action(async (apiKey, options) => {
99
+ if (!apiKey || String(apiKey).trim().length === 0) {
100
+ console.error('Missing required argument: <apiKey>')
101
+ program.help({ error: true })
102
+ return
103
+ }
104
+
105
+ const full = Boolean(options.full)
106
+
107
+ try {
108
+ console.log(
109
+ full
110
+ ? 'Setting up Claude Code + Codex + Gemini CLI...\n'
111
+ : 'Setting up Claude Code + Codex...\n'
112
+ )
113
+
114
+ const result = writeAllAgentsConfig(apiKey, { full })
115
+
116
+ console.log('Claude Code:')
117
+ console.log(` Settings written to: ${result.claude.settingsPath}`)
118
+
119
+ console.log('\nCodex:')
120
+ console.log(` Config written to: ${result.codex.configPath}`)
121
+ console.log(` Auth written to: ${result.codex.authPath}`)
122
+
123
+ if (result.gemini) {
124
+ console.log('\nGemini CLI:')
125
+ console.log(` Env written to: ${result.gemini.envPath}`)
126
+ console.log(` Settings written to: ${result.gemini.settingsPath}`)
127
+ }
128
+
129
+ console.log('\nInstalling dependencies...')
130
+ await installAllAgentsDeps({ full })
131
+ } catch (err) {
132
+ console.error('Failed to setup agents:', err.message)
133
+ process.exit(1)
134
+ }
135
+
136
+ console.log('\nSetup complete!')
137
+ console.log(' - Use `claude` for Claude Code')
138
+ console.log(' - Use `codex` for Codex')
139
+ if (full) console.log(' - Use `gemini` for Gemini CLI')
140
+ })
141
+
63
142
  program
64
143
  .command('set-raycast-ai')
65
144
  .description('setup Raycast AI providers config')
@@ -0,0 +1,18 @@
1
+ export interface AllAgentsOptions {
2
+ full?: boolean;
3
+ }
4
+ export interface AllAgentsResult {
5
+ claude: {
6
+ settingsPath: string;
7
+ };
8
+ codex: {
9
+ configPath: string;
10
+ authPath: string;
11
+ };
12
+ gemini?: {
13
+ envPath: string;
14
+ settingsPath: string;
15
+ };
16
+ }
17
+ export declare function writeAllAgentsConfig(apiKey: string, options?: AllAgentsOptions): AllAgentsResult;
18
+ export declare function installAllAgentsDeps(options?: AllAgentsOptions): Promise<void>;
@@ -0,0 +1,25 @@
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, options = {}) {
9
+ const claudeResult = (0, claude_code_1.writeClaudeConfig)(apiKey);
10
+ const codexResult = (0, codex_1.writeCodexConfig)(apiKey);
11
+ const result = {
12
+ claude: claudeResult,
13
+ codex: codexResult,
14
+ };
15
+ if (options.full) {
16
+ result.gemini = (0, gemini_cli_1.writeGeminiConfig)(apiKey);
17
+ }
18
+ return result;
19
+ }
20
+ async function installAllAgentsDeps(options = {}) {
21
+ const installers = [(0, claude_code_1.installDeps)(), (0, codex_1.installCodexDeps)()];
22
+ if (options.full)
23
+ installers.push((0, gemini_cli_1.installGeminiDeps)());
24
+ await Promise.all(installers);
25
+ }
@@ -0,0 +1,4 @@
1
+ export declare function writeClaudeConfig(apiKey: string): {
2
+ settingsPath: string;
3
+ };
4
+ export declare function installDeps(): Promise<void>;
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ export declare function writeCodexConfig(apiKey: string): {
2
+ configPath: string;
3
+ authPath: string;
4
+ };
5
+ export declare function installCodexDeps(): Promise<void>;
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,5 @@
1
+ export declare function writeGeminiConfig(apiKey: string): {
2
+ envPath: string;
3
+ settingsPath: string;
4
+ };
5
+ export declare function installGeminiDeps(): Promise<void>;
@@ -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,14 +1,9 @@
1
- export declare function writeClaudeConfig(apiKey: string): {
2
- settingsPath: string;
3
- };
4
- export declare function installDeps(): Promise<void>;
5
- export declare function writeCodexConfig(apiKey: string): {
6
- configPath: string;
7
- authPath: string;
8
- };
9
- export declare function installCodexDeps(): Promise<void>;
10
1
  export declare function writeRaycastConfig(apiKey: string): {
11
2
  configPath: string;
12
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';
13
8
  export { setupDevEnvironment } from './dev-setup';
14
9
  export { setupAndroidEnvironment } from './android-setup';
package/build/index.js CHANGED
@@ -1,106 +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 execa_1 = require("execa");
13
- function ensureDir(dirPath) {
14
- fs.mkdirSync(dirPath, { recursive: true });
15
- }
16
- function getClaudeSettingsDir() {
17
- return path.join(os.homedir(), '.claude');
18
- }
19
- const CLAUDE_SETTINGS_TEMPLATE = `{
20
- "env": {
21
- "DISABLE_TELEMETRY": "1",
22
- "OTEL_METRICS_EXPORTER": "otlp",
23
- "ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
24
- "ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
25
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
26
- },
27
- "includeCoAuthoredBy": false,
28
- "apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
29
- "permissions": {
30
- "allow": [],
31
- "deny": []
32
- }
33
- }`;
34
- function writeClaudeConfig(apiKey) {
35
- const settingsDir = getClaudeSettingsDir();
36
- const settingsPath = path.join(settingsDir, 'settings.json');
37
- ensureDir(settingsDir);
38
- const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(/API_KEY_PLACEHOLDER/g, apiKey);
39
- fs.writeFileSync(settingsPath, settingsContent);
40
- return { settingsPath };
41
- }
42
- async function commandExists(command) {
43
- try {
44
- const { failed } = await (0, execa_1.execa)(command, ['--version'], {
45
- stdio: 'ignore',
46
- reject: false,
47
- });
48
- return !failed;
49
- }
50
- catch (error) {
51
- return false;
52
- }
53
- }
54
- async function installDeps() {
55
- const packages = ['@anthropic-ai/claude-code'];
56
- const usePnpm = await commandExists('pnpm');
57
- if (usePnpm) {
58
- console.log('pnpm detected. Installing dependencies with pnpm...');
59
- await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
60
- }
61
- else {
62
- console.log('pnpm not found. Falling back to npm...');
63
- await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
64
- }
65
- console.log('Dependencies installed successfully.');
66
- }
67
- function getCodexConfigDir() {
68
- return path.join(os.homedir(), '.codex');
69
- }
70
- const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
71
- model = "gpt-5.2"
72
- model_reasoning_effort = "high"
73
- disable_response_storage = true
74
- preferred_auth_method = "apikey"
75
-
76
- [model_providers.jw]
77
- name = "jw"
78
- base_url = "https://ai.gengjiawen.com/api/openai"
79
- wire_api = "responses"
80
- `;
81
- function writeCodexConfig(apiKey) {
82
- const configDir = getCodexConfigDir();
83
- ensureDir(configDir);
84
- const configPath = path.join(configDir, 'config.toml');
85
- fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE);
86
- const authPath = path.join(configDir, 'auth.json');
87
- const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2);
88
- fs.writeFileSync(authPath, authContent);
89
- return { configPath, authPath };
90
- }
91
- async function installCodexDeps() {
92
- const packages = ['@openai/codex'];
93
- const usePnpm = await commandExists('pnpm');
94
- if (usePnpm) {
95
- console.log('pnpm detected. Installing Codex dependency with pnpm...');
96
- await (0, execa_1.execa)('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' });
97
- }
98
- else {
99
- console.log('pnpm not found. Falling back to npm...');
100
- await (0, execa_1.execa)('npm', ['install', '-g', ...packages], { stdio: 'inherit' });
101
- }
102
- console.log('Codex dependency installed successfully.');
103
- }
8
+ const utils_1 = require("./utils");
104
9
  function getRaycastAIConfigDir() {
105
10
  return path.join(os.homedir(), '.config', 'raycast', 'ai');
106
11
  }
@@ -127,12 +32,24 @@ const RAYCAST_PROVIDERS_YAML_TEMPLATE = `providers:
127
32
  `;
128
33
  function writeRaycastConfig(apiKey) {
129
34
  const configDir = getRaycastAIConfigDir();
130
- ensureDir(configDir);
35
+ (0, utils_1.ensureDir)(configDir);
131
36
  const configPath = path.join(configDir, 'providers.yaml');
132
37
  const content = RAYCAST_PROVIDERS_YAML_TEMPLATE.replace('API_KEY_PLACEHOLDER', apiKey);
133
38
  fs.writeFileSync(configPath, content);
134
39
  return { configPath };
135
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; } });
136
53
  var dev_setup_1 = require("./dev-setup");
137
54
  Object.defineProperty(exports, "setupDevEnvironment", { enumerable: true, get: function () { return dev_setup_1.setupDevEnvironment; } });
138
55
  var android_setup_1 = require("./android-setup");
@@ -0,0 +1,2 @@
1
+ export declare function ensureDir(dirPath: string): void;
2
+ export declare function commandExists(command: string): Promise<boolean>;
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,43 @@
1
+ import { writeClaudeConfig, installDeps } from './claude-code'
2
+ import { writeCodexConfig, installCodexDeps } from './codex'
3
+ import { writeGeminiConfig, installGeminiDeps } from './gemini-cli'
4
+
5
+ export interface AllAgentsOptions {
6
+ /** When true, also include Gemini CLI in the combined setup. */
7
+ full?: boolean
8
+ }
9
+
10
+ export interface AllAgentsResult {
11
+ claude: { settingsPath: string }
12
+ codex: { configPath: string; authPath: string }
13
+ gemini?: { envPath: string; settingsPath: string }
14
+ }
15
+
16
+ /** Write configuration for the combined setup (Claude Code + Codex, optional Gemini CLI). */
17
+ export function writeAllAgentsConfig(
18
+ apiKey: string,
19
+ options: AllAgentsOptions = {}
20
+ ): AllAgentsResult {
21
+ const claudeResult = writeClaudeConfig(apiKey)
22
+ const codexResult = writeCodexConfig(apiKey)
23
+
24
+ const result: AllAgentsResult = {
25
+ claude: claudeResult,
26
+ codex: codexResult,
27
+ }
28
+
29
+ if (options.full) {
30
+ result.gemini = writeGeminiConfig(apiKey)
31
+ }
32
+
33
+ return result
34
+ }
35
+
36
+ /** Install dependencies for the combined setup (Claude Code + Codex, optional Gemini CLI). */
37
+ export async function installAllAgentsDeps(
38
+ options: AllAgentsOptions = {}
39
+ ): Promise<void> {
40
+ const installers = [installDeps(), installCodexDeps()]
41
+ if (options.full) installers.push(installGeminiDeps())
42
+ await Promise.all(installers)
43
+ }
@@ -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,132 +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 { execa } from 'execa'
5
-
6
- /** Ensure directory exists */
7
- function ensureDir(dirPath: string): void {
8
- fs.mkdirSync(dirPath, { recursive: true })
9
- }
10
-
11
- /** Return Claude settings directory path */
12
- function getClaudeSettingsDir(): string {
13
- return path.join(os.homedir(), '.claude')
14
- }
15
-
16
- /** Template for Claude settings.json */
17
- const CLAUDE_SETTINGS_TEMPLATE = `{
18
- "env": {
19
- "DISABLE_TELEMETRY": "1",
20
- "OTEL_METRICS_EXPORTER": "otlp",
21
- "ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
22
- "ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/",
23
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
24
- },
25
- "includeCoAuthoredBy": false,
26
- "apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
27
- "permissions": {
28
- "allow": [],
29
- "deny": []
30
- }
31
- }`
32
-
33
- /** Write Claude config files */
34
- export function writeClaudeConfig(apiKey: string): {
35
- settingsPath: string
36
- } {
37
- // Write Claude settings
38
- const settingsDir = getClaudeSettingsDir()
39
- const settingsPath = path.join(settingsDir, 'settings.json')
40
- ensureDir(settingsDir)
41
- const settingsContent = CLAUDE_SETTINGS_TEMPLATE.replace(
42
- /API_KEY_PLACEHOLDER/g,
43
- apiKey
44
- )
45
- fs.writeFileSync(settingsPath, settingsContent)
46
-
47
- return { settingsPath }
48
- }
49
-
50
- /** Check if a command exists */
51
- async function commandExists(command: string): Promise<boolean> {
52
- try {
53
- // execa with reject: false will not throw on non-zero exit codes.
54
- const { failed } = await execa(command, ['--version'], {
55
- stdio: 'ignore',
56
- reject: false,
57
- })
58
- return !failed
59
- } catch (error) {
60
- // Catch errors for commands that don't support --version or other issues
61
- return false
62
- }
63
- }
64
-
65
- /** Install global dependencies */
66
- export async function installDeps(): Promise<void> {
67
- const packages = ['@anthropic-ai/claude-code']
68
- const usePnpm = await commandExists('pnpm')
69
-
70
- if (usePnpm) {
71
- console.log('pnpm detected. Installing dependencies with pnpm...')
72
- await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
73
- } else {
74
- console.log('pnpm not found. Falling back to npm...')
75
- await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
76
- }
77
- console.log('Dependencies installed successfully.')
78
- }
79
-
80
- /** Return Codex configuration directory path */
81
- function getCodexConfigDir(): string {
82
- return path.join(os.homedir(), '.codex')
83
- }
84
-
85
- /** Template for Codex config.toml */
86
- const CODEX_CONFIG_TOML_TEMPLATE = `model_provider = "jw"
87
- model = "gpt-5.2"
88
- model_reasoning_effort = "high"
89
- disable_response_storage = true
90
- preferred_auth_method = "apikey"
91
-
92
- [model_providers.jw]
93
- name = "jw"
94
- base_url = "https://ai.gengjiawen.com/api/openai"
95
- wire_api = "responses"
96
- `
97
-
98
- /** Write Codex config.toml and auth.json */
99
- export function writeCodexConfig(apiKey: string): {
100
- configPath: string
101
- authPath: string
102
- } {
103
- const configDir = getCodexConfigDir()
104
- ensureDir(configDir)
105
-
106
- const configPath = path.join(configDir, 'config.toml')
107
- fs.writeFileSync(configPath, CODEX_CONFIG_TOML_TEMPLATE)
108
-
109
- const authPath = path.join(configDir, 'auth.json')
110
- const authContent = JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)
111
- fs.writeFileSync(authPath, authContent)
112
-
113
- return { configPath, authPath }
114
- }
115
-
116
- /** Install Codex dependency */
117
- export async function installCodexDeps(): Promise<void> {
118
- const packages = ['@openai/codex']
119
- const usePnpm = await commandExists('pnpm')
120
-
121
- if (usePnpm) {
122
- console.log('pnpm detected. Installing Codex dependency with pnpm...')
123
- await execa('pnpm', ['add', '-g', ...packages], { stdio: 'inherit' })
124
- } else {
125
- console.log('pnpm not found. Falling back to npm...')
126
- await execa('npm', ['install', '-g', ...packages], { stdio: 'inherit' })
127
- }
128
- console.log('Codex dependency installed successfully.')
129
- }
4
+ import { ensureDir } from './utils'
130
5
 
131
6
  /** Return Raycast AI configuration directory path */
132
7
  function getRaycastAIConfigDir(): string {
@@ -171,6 +46,18 @@ export function writeRaycastConfig(apiKey: string): { configPath: string } {
171
46
  return { configPath }
172
47
  }
173
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
+
174
61
  // Re-export dev-setup functionality
175
62
  export { setupDevEnvironment } from './dev-setup'
176
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
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gengjiawen/os-init",
3
3
  "private": false,
4
- "version": "1.11.0",
4
+ "version": "1.13.0",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "bin": {