@gengjiawen/os-init 1.19.0 → 1.21.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.
@@ -21,11 +21,14 @@ jobs:
21
21
  version: 9
22
22
  - name: Envinfo
23
23
  run: npx envinfo
24
- - name: Install, build, and test (pnpm)
24
+ - name: Install and build (pnpm)
25
25
  run: |
26
26
  pnpm install --frozen-lockfile=false
27
27
  pnpm build
28
- pnpm format:check
29
- pnpm test
28
+ - name: Check formatting (pnpm)
29
+ if: runner.os != 'Windows'
30
+ run: pnpm format:check
31
+ - name: Test (pnpm)
32
+ run: pnpm test
30
33
  env:
31
34
  CI: true
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.21.0](https://github.com/gengjiawen/os-init/compare/v1.20.0...v1.21.0) (2026-03-31)
4
+
5
+
6
+ ### Features
7
+
8
+ * limit claude code context defaults ([bc40196](https://github.com/gengjiawen/os-init/commit/bc40196bbb4be0187ebbd2ed6a695808636b3554))
9
+
10
+ ## [1.20.0](https://github.com/gengjiawen/os-init/compare/v1.19.0...v1.20.0) (2026-03-27)
11
+
12
+
13
+ ### Features
14
+
15
+ * add more opencode models ([e04e0d1](https://github.com/gengjiawen/os-init/commit/e04e0d1fc52b7a93cf51436d23c82b1e725daff6))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * add Claude nonessential traffic env ([9bf1bac](https://github.com/gengjiawen/os-init/commit/9bf1bac9f09e8c9a3e8c740834a1d5ad7986f1b9))
21
+ * CI ([166259f](https://github.com/gengjiawen/os-init/commit/166259f104bdda2dc57cd4678d9e03d739c472a9))
22
+ * use absolute codex model catalog path on windows ([fb8f19f](https://github.com/gengjiawen/os-init/commit/fb8f19f8f6b3de437b2192e57ec7e7fe1e48ee5a))
23
+
3
24
  ## [1.19.0](https://github.com/gengjiawen/os-init/compare/v1.18.1...v1.19.0) (2026-03-19)
4
25
 
5
26
 
@@ -9,6 +9,8 @@ const execa_1 = require("execa");
9
9
  const jsonc_parser_1 = require("jsonc-parser");
10
10
  const utils_1 = require("./utils");
11
11
  const CLAUDE_BASE_URL = 'https://ai.gengjiawen.com/api/claude/';
12
+ const CLAUDE_AUTO_COMPACT_WINDOW = '128000';
13
+ const CLAUDE_DISABLE_1M_CONTEXT = '1';
12
14
  function getClaudeSettingsDir() {
13
15
  return path.join(os.homedir(), '.claude');
14
16
  }
@@ -29,7 +31,9 @@ const CLAUDE_SETTINGS_TEMPLATE = `{
29
31
  "OTEL_METRICS_EXPORTER": "otlp",
30
32
  "ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
31
33
  "ANTHROPIC_BASE_URL": "${CLAUDE_BASE_URL}",
32
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
34
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
35
+ "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "${CLAUDE_AUTO_COMPACT_WINDOW}",
36
+ "CLAUDE_CODE_DISABLE_1M_CONTEXT": "${CLAUDE_DISABLE_1M_CONTEXT}"
33
37
  },
34
38
  "includeCoAuthoredBy": false,
35
39
  "apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
@@ -62,6 +66,15 @@ function writeVSCodeClaudePluginConfig(apiKey) {
62
66
  const edits = (0, jsonc_parser_1.modify)(sourceContent, ['claudeCode.environmentVariables'], [
63
67
  { name: 'ANTHROPIC_BASE_URL', value: CLAUDE_BASE_URL },
64
68
  { name: 'ANTHROPIC_AUTH_TOKEN', value: apiKey },
69
+ { name: 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', value: '1' },
70
+ {
71
+ name: 'CLAUDE_CODE_AUTO_COMPACT_WINDOW',
72
+ value: CLAUDE_AUTO_COMPACT_WINDOW,
73
+ },
74
+ {
75
+ name: 'CLAUDE_CODE_DISABLE_1M_CONTEXT',
76
+ value: CLAUDE_DISABLE_1M_CONTEXT,
77
+ },
65
78
  ], {
66
79
  formattingOptions: {
67
80
  insertSpaces: true,
package/build/codex.js CHANGED
@@ -17,6 +17,11 @@ function getCodexConfigDir() {
17
17
  function getCodexModelCatalogPath() {
18
18
  return path.join(getCodexConfigDir(), CODEX_MODEL_CATALOG_FILENAME);
19
19
  }
20
+ function getCodexModelCatalogConfigPath() {
21
+ return os.platform() === 'win32'
22
+ ? getCodexModelCatalogPath()
23
+ : CODEX_MODEL_CATALOG_CONFIG_PATH;
24
+ }
20
25
  function getCodexConfigTomlTemplate() {
21
26
  return `model_provider = "jw"
22
27
  model = "gpt-5.4"
@@ -26,7 +31,7 @@ model_auto_compact_token_limit = 131072
26
31
  disable_response_storage = true
27
32
  preferred_auth_method = "apikey"
28
33
  service_tier = "fast"
29
- model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}"
34
+ model_catalog_json = ${JSON.stringify(getCodexModelCatalogConfigPath())}
30
35
 
31
36
  [model_providers.jw]
32
37
  name = "jw"
package/build/opencode.js CHANGED
@@ -9,8 +9,14 @@ const execa_1 = require("execa");
9
9
  const utils_1 = require("./utils");
10
10
  const OPENCODE_PROVIDER_ID = 'MyCustomProvider';
11
11
  const OPENCODE_MODEL_ID = 'code';
12
- const OPENCODE_GLM_MODEL_ID = 'glm';
13
- const OPENCODE_KIMI_MODEL_ID = 'kimi';
12
+ const OPENCODE_MODEL_IDS = [
13
+ OPENCODE_MODEL_ID,
14
+ 'glm',
15
+ 'kimi',
16
+ 'minimax',
17
+ 'deepseek',
18
+ 'gemini-flash',
19
+ ];
14
20
  const OPENCODE_BASE_URL = 'https://ai.gengjiawen.com/api/openai/v1';
15
21
  function createOpencodeModelConfig(modelId) {
16
22
  return {
@@ -22,6 +28,12 @@ function createOpencodeModelConfig(modelId) {
22
28
  },
23
29
  };
24
30
  }
31
+ function createOpencodeModelsConfig() {
32
+ return Object.fromEntries(OPENCODE_MODEL_IDS.map((modelId) => [
33
+ modelId,
34
+ createOpencodeModelConfig(modelId),
35
+ ]));
36
+ }
25
37
  function getOpencodeConfigDir() {
26
38
  return path.join(os.homedir(), '.config', 'opencode');
27
39
  }
@@ -38,11 +50,7 @@ function writeOpencodeConfig(apiKey) {
38
50
  baseURL: OPENCODE_BASE_URL,
39
51
  apiKey,
40
52
  },
41
- models: {
42
- [OPENCODE_MODEL_ID]: createOpencodeModelConfig(OPENCODE_MODEL_ID),
43
- [OPENCODE_GLM_MODEL_ID]: createOpencodeModelConfig(OPENCODE_GLM_MODEL_ID),
44
- [OPENCODE_KIMI_MODEL_ID]: createOpencodeModelConfig(OPENCODE_KIMI_MODEL_ID),
45
- },
53
+ models: createOpencodeModelsConfig(),
46
54
  },
47
55
  },
48
56
  model: `${OPENCODE_PROVIDER_ID}/${OPENCODE_MODEL_ID}`,
@@ -71,12 +71,26 @@ describe('writeClaudeConfig', () => {
71
71
  expect(claudeSettings).toContain(
72
72
  '"ANTHROPIC_BASE_URL": "https://ai.gengjiawen.com/api/claude/"'
73
73
  )
74
+ expect(claudeSettings).toContain(
75
+ '"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"'
76
+ )
77
+ expect(claudeSettings).toContain(
78
+ '"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "128000"'
79
+ )
80
+ expect(claudeSettings).toContain('"CLAUDE_CODE_DISABLE_1M_CONTEXT": "1"')
74
81
 
75
82
  const vscodeSettings = fs.readFileSync(result.vscodeSettingsPath, 'utf8')
76
83
  expect(vscodeSettings).toContain('"editor.fontSize": 14')
77
84
  expect(vscodeSettings).toContain('"claudeCode.environmentVariables"')
78
85
  expect(vscodeSettings).toContain('"ANTHROPIC_BASE_URL"')
79
86
  expect(vscodeSettings).toContain('"ANTHROPIC_AUTH_TOKEN"')
87
+ expect(vscodeSettings).toContain(
88
+ '"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC"'
89
+ )
90
+ expect(vscodeSettings).toContain('"CLAUDE_CODE_AUTO_COMPACT_WINDOW"')
91
+ expect(vscodeSettings).toContain('"128000"')
92
+ expect(vscodeSettings).toContain('"CLAUDE_CODE_DISABLE_1M_CONTEXT"')
93
+ expect(vscodeSettings).toContain('"1"')
80
94
  expect(vscodeSettings).toContain('"test-api-key"')
81
95
  })
82
96
 
@@ -6,6 +6,8 @@ import { ParseError, applyEdits, modify, parse } from 'jsonc-parser'
6
6
  import { ensureDir, commandExists, PNPM_INSTALL_ENV } from './utils'
7
7
 
8
8
  const CLAUDE_BASE_URL = 'https://ai.gengjiawen.com/api/claude/'
9
+ const CLAUDE_AUTO_COMPACT_WINDOW = '128000'
10
+ const CLAUDE_DISABLE_1M_CONTEXT = '1'
9
11
 
10
12
  /** Return Claude settings directory path */
11
13
  function getClaudeSettingsDir(): string {
@@ -43,7 +45,9 @@ const CLAUDE_SETTINGS_TEMPLATE = `{
43
45
  "OTEL_METRICS_EXPORTER": "otlp",
44
46
  "ANTHROPIC_API_KEY": "API_KEY_PLACEHOLDER",
45
47
  "ANTHROPIC_BASE_URL": "${CLAUDE_BASE_URL}",
46
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
48
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
49
+ "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "${CLAUDE_AUTO_COMPACT_WINDOW}",
50
+ "CLAUDE_CODE_DISABLE_1M_CONTEXT": "${CLAUDE_DISABLE_1M_CONTEXT}"
47
51
  },
48
52
  "includeCoAuthoredBy": false,
49
53
  "apiKeyHelper": "echo 'API_KEY_PLACEHOLDER'",
@@ -94,6 +98,15 @@ function writeVSCodeClaudePluginConfig(apiKey: string): {
94
98
  [
95
99
  { name: 'ANTHROPIC_BASE_URL', value: CLAUDE_BASE_URL },
96
100
  { name: 'ANTHROPIC_AUTH_TOKEN', value: apiKey },
101
+ { name: 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', value: '1' },
102
+ {
103
+ name: 'CLAUDE_CODE_AUTO_COMPACT_WINDOW',
104
+ value: CLAUDE_AUTO_COMPACT_WINDOW,
105
+ },
106
+ {
107
+ name: 'CLAUDE_CODE_DISABLE_1M_CONTEXT',
108
+ value: CLAUDE_DISABLE_1M_CONTEXT,
109
+ },
97
110
  ],
98
111
  {
99
112
  formattingOptions: {
@@ -14,6 +14,12 @@ describe('writeCodexConfig', () => {
14
14
  let homedirSpy: jest.SpiedFunction<typeof os.homedir>
15
15
  let originalFetch: typeof global.fetch | undefined
16
16
 
17
+ function getExpectedModelCatalogConfigPath(): string {
18
+ return os.platform() === 'win32'
19
+ ? path.join(tempHome, '.codex', 'remote-model-catalog.json')
20
+ : '~/.codex/remote-model-catalog.json'
21
+ }
22
+
17
23
  function mockCatalogFetch(
18
24
  catalog: { models: Array<Record<string, unknown>> } = {
19
25
  models: [{ id: 'gpt-5.4' }],
@@ -52,7 +58,7 @@ describe('writeCodexConfig', () => {
52
58
  }
53
59
 
54
60
  expect(config.model_auto_compact_token_limit).toBe(131072)
55
- expect(config.model_catalog_json).toBe('~/.codex/remote-model-catalog.json')
61
+ expect(config.model_catalog_json).toBe(getExpectedModelCatalogConfigPath())
56
62
  expect(fs.existsSync(result.catalogPath)).toBe(true)
57
63
  })
58
64
 
@@ -91,7 +97,7 @@ custom_model = "keep-me"
91
97
  expect(config.service_tier).toBe('fast')
92
98
  expect(config.custom_flag).toBe(true)
93
99
  expect(config.model).toBe('gpt-5.4')
94
- expect(config.model_catalog_json).toBe('~/.codex/remote-model-catalog.json')
100
+ expect(config.model_catalog_json).toBe(getExpectedModelCatalogConfigPath())
95
101
  expect(config.preferred_auth_method).toBe('apikey')
96
102
  expect(config.model_providers.jw.base_url).toBe(
97
103
  'https://ai.gengjiawen.com/api/openai'
@@ -129,7 +135,7 @@ base_url = "https://example.com"
129
135
  }
130
136
 
131
137
  expect(config.model).toBe('gpt-5.4')
132
- expect(config.model_catalog_json).toBe('~/.codex/remote-model-catalog.json')
138
+ expect(config.model_catalog_json).toBe(getExpectedModelCatalogConfigPath())
133
139
  expect(config.preferred_auth_method).toBe('apikey')
134
140
  expect(config.model_providers.jw.name).toBe('jw')
135
141
  expect(config.service_tier).toBe('fast')
@@ -170,6 +176,23 @@ base_url = "https://example.com"
170
176
  })
171
177
  })
172
178
 
179
+ test('writes an absolute model catalog path on Windows', async () => {
180
+ const platformSpy = jest.spyOn(os, 'platform').mockReturnValue('win32')
181
+
182
+ try {
183
+ const result = await writeCodexConfig('test-api-key')
184
+ const config = TOML.parse(fs.readFileSync(result.configPath, 'utf8')) as {
185
+ model_catalog_json: string
186
+ }
187
+
188
+ expect(config.model_catalog_json).toBe(
189
+ path.join(tempHome, '.codex', 'remote-model-catalog.json')
190
+ )
191
+ } finally {
192
+ platformSpy.mockRestore()
193
+ }
194
+ })
195
+
173
196
  test('throws when refreshing the remote model catalog fails', async () => {
174
197
  global.fetch = jest.fn().mockResolvedValue({
175
198
  ok: false,
package/libs/codex.ts CHANGED
@@ -21,6 +21,12 @@ function getCodexModelCatalogPath(): string {
21
21
  return path.join(getCodexConfigDir(), CODEX_MODEL_CATALOG_FILENAME)
22
22
  }
23
23
 
24
+ function getCodexModelCatalogConfigPath(): string {
25
+ return os.platform() === 'win32'
26
+ ? getCodexModelCatalogPath()
27
+ : CODEX_MODEL_CATALOG_CONFIG_PATH
28
+ }
29
+
24
30
  function getCodexConfigTomlTemplate(): string {
25
31
  return `model_provider = "jw"
26
32
  model = "gpt-5.4"
@@ -30,7 +36,7 @@ model_auto_compact_token_limit = 131072
30
36
  disable_response_storage = true
31
37
  preferred_auth_method = "apikey"
32
38
  service_tier = "fast"
33
- model_catalog_json = "${CODEX_MODEL_CATALOG_CONFIG_PATH}"
39
+ model_catalog_json = ${JSON.stringify(getCodexModelCatalogConfigPath())}
34
40
 
35
41
  [model_providers.jw]
36
42
  name = "jw"
@@ -58,6 +58,15 @@ describe('writeOpencodeConfig', () => {
58
58
  expect(config.provider.MyCustomProvider.models.kimi).toEqual(
59
59
  expectedModelConfig('kimi')
60
60
  )
61
+ expect(config.provider.MyCustomProvider.models.minimax).toEqual(
62
+ expectedModelConfig('minimax')
63
+ )
64
+ expect(config.provider.MyCustomProvider.models.deepseek).toEqual(
65
+ expectedModelConfig('deepseek')
66
+ )
67
+ expect(config.provider.MyCustomProvider.models['gemini-flash']).toEqual(
68
+ expectedModelConfig('gemini-flash')
69
+ )
61
70
  expect(config.model).toBe('MyCustomProvider/code')
62
71
  expect(config.small_model).toBe('MyCustomProvider/code')
63
72
  })
package/libs/opencode.ts CHANGED
@@ -6,8 +6,14 @@ import { commandExists, ensureDir, PNPM_INSTALL_ENV } from './utils'
6
6
 
7
7
  const OPENCODE_PROVIDER_ID = 'MyCustomProvider'
8
8
  const OPENCODE_MODEL_ID = 'code'
9
- const OPENCODE_GLM_MODEL_ID = 'glm'
10
- const OPENCODE_KIMI_MODEL_ID = 'kimi'
9
+ const OPENCODE_MODEL_IDS = [
10
+ OPENCODE_MODEL_ID,
11
+ 'glm',
12
+ 'kimi',
13
+ 'minimax',
14
+ 'deepseek',
15
+ 'gemini-flash',
16
+ ]
11
17
  const OPENCODE_BASE_URL = 'https://ai.gengjiawen.com/api/openai/v1'
12
18
 
13
19
  function createOpencodeModelConfig(modelId: string) {
@@ -21,6 +27,15 @@ function createOpencodeModelConfig(modelId: string) {
21
27
  }
22
28
  }
23
29
 
30
+ function createOpencodeModelsConfig() {
31
+ return Object.fromEntries(
32
+ OPENCODE_MODEL_IDS.map((modelId) => [
33
+ modelId,
34
+ createOpencodeModelConfig(modelId),
35
+ ])
36
+ )
37
+ }
38
+
24
39
  /** Return OpenCode configuration directory path */
25
40
  function getOpencodeConfigDir(): string {
26
41
  return path.join(os.homedir(), '.config', 'opencode')
@@ -41,15 +56,7 @@ export function writeOpencodeConfig(apiKey: string): { configPath: string } {
41
56
  baseURL: OPENCODE_BASE_URL,
42
57
  apiKey,
43
58
  },
44
- models: {
45
- [OPENCODE_MODEL_ID]: createOpencodeModelConfig(OPENCODE_MODEL_ID),
46
- [OPENCODE_GLM_MODEL_ID]: createOpencodeModelConfig(
47
- OPENCODE_GLM_MODEL_ID
48
- ),
49
- [OPENCODE_KIMI_MODEL_ID]: createOpencodeModelConfig(
50
- OPENCODE_KIMI_MODEL_ID
51
- ),
52
- },
59
+ models: createOpencodeModelsConfig(),
53
60
  },
54
61
  },
55
62
  model: `${OPENCODE_PROVIDER_ID}/${OPENCODE_MODEL_ID}`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gengjiawen/os-init",
3
3
  "private": false,
4
- "version": "1.19.0",
4
+ "version": "1.21.0",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "bin": {