ltcraft-ai-auto 1.5.2 → 1.6.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.
@@ -0,0 +1,6 @@
1
+ {
2
+ "enabledMcpjsonServers": [
3
+ "proxy"
4
+ ],
5
+ "enableAllProjectMcpServers": true
6
+ }
package/bin/index.js CHANGED
@@ -91,13 +91,59 @@ function configureClaudeCode(apiKey) {
91
91
  ...(settings.env || {}),
92
92
  ANTHROPIC_BASE_URL: API_BASE_URL,
93
93
  API_TIMEOUT_MS: 3000000,
94
- ANTHROPIC_AUTH_TOKEN: apiKey
94
+ ANTHROPIC_AUTH_TOKEN: apiKey,
95
+ ANTHROPIC_API_KEY: apiKey
95
96
  };
96
97
  writeJsonFile(settingsPath, settings);
97
98
  console.log(`✓ 已配置: ${settingsPath}`);
98
99
  console.log('\n🎉 Claude Code 配置完成!');
99
100
  }
100
101
 
102
+ function readTomlValue(content, key) {
103
+ const match = content.match(new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, 'm'));
104
+ return match ? match[1] : null;
105
+ }
106
+
107
+ function mergeTomlConfig(existing, name, baseUrl, apiKey) {
108
+ let content = existing || '';
109
+
110
+ // 更新或插入顶层 model_provider
111
+ if (/^model_provider\s*=/m.test(content)) {
112
+ content = content.replace(/^model_provider\s*=.*/m, `model_provider = "ltcraftai"`);
113
+ } else {
114
+ content = `model_provider = "ltcraftai"\n` + content;
115
+ }
116
+
117
+ // 移除已有的 [model_providers.ltcraftai] 节(到下一个节或文件末尾)
118
+ content = content.replace(/\[model_providers\.ltcraftai\][\s\S]*?(?=\n\[|\s*$)/, '');
119
+
120
+ // 追加新节
121
+ content = content.trimEnd() + `\n\n[model_providers.ltcraftai]\nname = "${name}"\nbase_url = "${baseUrl}"\napi_key = "${apiKey}"\n`;
122
+ return content;
123
+ }
124
+
125
+ function configureCodex(apiKey) {
126
+ const homeDir = getHomeDir();
127
+ const codexDir = path.join(homeDir, '.codex');
128
+ const configPath = path.join(codexDir, 'config.toml');
129
+ const authPath = path.join(codexDir, 'auth.json');
130
+
131
+ backupFile(configPath);
132
+ backupFile(authPath);
133
+
134
+ ensureDir(codexDir);
135
+
136
+ const existingToml = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf-8') : '';
137
+ const merged = mergeTomlConfig(existingToml, 'LTCraftAI', `${API_BASE_URL}/v1`, apiKey);
138
+ fs.writeFileSync(configPath, merged, 'utf-8');
139
+ console.log(`✓ 已配置: ${configPath}`);
140
+
141
+ const existingAuth = readJsonFile(authPath);
142
+ writeJsonFile(authPath, { ...existingAuth, auth_mode: 'apikey', OPENAI_API_KEY: apiKey });
143
+ console.log(`✓ 已配置: ${authPath}`);
144
+ console.log('\n🎉 Codex 配置完成!');
145
+ }
146
+
101
147
  function configureOpenCode(apiKey) {
102
148
  const homeDir = getHomeDir();
103
149
  const configPath = path.join(homeDir, '.config', 'opencode', 'opencode.json');
@@ -432,6 +478,113 @@ function checkOpenClaw() {
432
478
  }
433
479
  }
434
480
 
481
+ function checkCodex() {
482
+ printSection('Codex 配置检测');
483
+ const homeDir = getHomeDir();
484
+ const cwd = process.cwd();
485
+ const isHomeDir = path.resolve(cwd) === path.resolve(homeDir);
486
+
487
+ if (isHomeDir) {
488
+ console.log(colorize('\n⚠️ 当前工作目录为用户主目录,跳过项目级配置检测(与全局配置路径相同)', 'yellow'));
489
+ }
490
+
491
+ const globalConfigPath = path.join(homeDir, '.codex', 'config.toml');
492
+ const globalAuthPath = path.join(homeDir, '.codex', 'auth.json');
493
+ const projectConfigPath = path.join(cwd, '.codex', 'config.toml');
494
+ const projectAuthPath = path.join(cwd, '.codex', 'auth.json');
495
+
496
+ console.log(colorize('\n📁 配置文件状态:', 'blue'));
497
+ printFileStatus('全局 config.toml', globalConfigPath, fileExists(globalConfigPath));
498
+ printFileStatus('全局 auth.json', globalAuthPath, fileExists(globalAuthPath));
499
+ if (!isHomeDir) {
500
+ printFileStatus('项目 config.toml', projectConfigPath, fileExists(projectConfigPath));
501
+ printFileStatus('项目 auth.json', projectAuthPath, fileExists(projectAuthPath));
502
+ }
503
+
504
+ const readToml = (p) => fileExists(p) ? fs.readFileSync(p, 'utf-8') : '';
505
+ const readAuth = (p) => readJsonFile(p);
506
+
507
+ const globalToml = readToml(globalConfigPath);
508
+ const projectToml = isHomeDir ? '' : readToml(projectConfigPath);
509
+ const globalAuth = readAuth(globalAuthPath);
510
+ const projectAuth = isHomeDir ? {} : readAuth(projectAuthPath);
511
+
512
+ const envBaseUrl = process.env.OPENAI_BASE_URL;
513
+ const envApiKey = process.env.OPENAI_API_KEY;
514
+
515
+ // 从 TOML 中提取值
516
+ const globalProvider = readTomlValue(globalToml, 'model_provider');
517
+ const globalBaseUrl = readTomlValue(globalToml, 'base_url');
518
+ const globalApiKeyToml = readTomlValue(globalToml, 'api_key');
519
+ const projectProvider = readTomlValue(projectToml, 'model_provider');
520
+ const projectBaseUrl = readTomlValue(projectToml, 'base_url');
521
+ const projectApiKeyToml = readTomlValue(projectToml, 'api_key');
522
+
523
+ const effectiveBaseUrl = envBaseUrl || projectBaseUrl || globalBaseUrl;
524
+ const effectiveApiKey = envApiKey || projectAuth.OPENAI_API_KEY || globalAuth.OPENAI_API_KEY || projectApiKeyToml || globalApiKeyToml;
525
+ const baseUrlSource = envBaseUrl ? '环境变量' : (projectBaseUrl ? '项目配置' : (globalBaseUrl ? '全局配置' : null));
526
+ const apiKeySource = envApiKey ? '环境变量' : (projectAuth.OPENAI_API_KEY ? '项目auth.json' : (globalAuth.OPENAI_API_KEY ? '全局auth.json' : (projectApiKeyToml ? '项目config.toml' : (globalApiKeyToml ? '全局config.toml' : null))));
527
+
528
+ console.log(colorize('\n🔧 关键配置项 (按优先级合并后):', 'blue'));
529
+ printConfigItem('model_provider', effectiveBaseUrl ? (projectProvider || globalProvider) : null, baseUrlSource ? '配置文件' : null);
530
+ printConfigItem('base_url', effectiveBaseUrl, baseUrlSource);
531
+ printConfigItem('OPENAI_API_KEY', effectiveApiKey, apiKeySource);
532
+
533
+ console.log(colorize('\n📊 各级配置详情:', 'blue'));
534
+
535
+ console.log(colorize('\n [环境变量]', 'yellow'));
536
+ console.log(` OPENAI_BASE_URL: ${envBaseUrl ? colorize(envBaseUrl, 'green') : colorize('未设置', 'gray')}`);
537
+ console.log(` OPENAI_API_KEY: ${envApiKey ? colorize(maskSecret(envApiKey), 'green') : colorize('未设置', 'gray')}`);
538
+
539
+ if (!isHomeDir) {
540
+ console.log(colorize('\n [项目配置] .codex/config.toml', 'yellow'));
541
+ if (fileExists(projectConfigPath)) {
542
+ console.log(` model_provider: ${projectProvider ? colorize(projectProvider, 'green') : colorize('未设置', 'gray')}`);
543
+ console.log(` base_url: ${projectBaseUrl ? colorize(projectBaseUrl, 'green') : colorize('未设置', 'gray')}`);
544
+ console.log(` api_key: ${projectApiKeyToml ? colorize(maskSecret(projectApiKeyToml), 'green') : colorize('未设置', 'gray')}`);
545
+ } else {
546
+ console.log(colorize(' (文件不存在)', 'gray'));
547
+ }
548
+
549
+ console.log(colorize('\n [项目配置] .codex/auth.json', 'yellow'));
550
+ if (fileExists(projectAuthPath)) {
551
+ console.log(` auth_mode: ${projectAuth.auth_mode ? colorize(projectAuth.auth_mode, 'green') : colorize('未设置', 'gray')}`);
552
+ console.log(` OPENAI_API_KEY: ${projectAuth.OPENAI_API_KEY ? colorize(maskSecret(projectAuth.OPENAI_API_KEY), 'green') : colorize('未设置', 'gray')}`);
553
+ } else {
554
+ console.log(colorize(' (文件不存在)', 'gray'));
555
+ }
556
+ }
557
+
558
+ console.log(colorize('\n [全局配置] ~/.codex/config.toml', 'yellow'));
559
+ if (fileExists(globalConfigPath)) {
560
+ console.log(` model_provider: ${globalProvider ? colorize(globalProvider, 'green') : colorize('未设置', 'gray')}`);
561
+ console.log(` base_url: ${globalBaseUrl ? colorize(globalBaseUrl, 'green') : colorize('未设置', 'gray')}`);
562
+ console.log(` api_key: ${globalApiKeyToml ? colorize(maskSecret(globalApiKeyToml), 'green') : colorize('未设置', 'gray')}`);
563
+ } else {
564
+ console.log(colorize(' (文件不存在)', 'gray'));
565
+ }
566
+
567
+ console.log(colorize('\n [全局配置] ~/.codex/auth.json', 'yellow'));
568
+ if (fileExists(globalAuthPath)) {
569
+ console.log(` auth_mode: ${globalAuth.auth_mode ? colorize(globalAuth.auth_mode, 'green') : colorize('未设置', 'gray')}`);
570
+ console.log(` OPENAI_API_KEY: ${globalAuth.OPENAI_API_KEY ? colorize(maskSecret(globalAuth.OPENAI_API_KEY), 'green') : colorize('未设置', 'gray')}`);
571
+ } else {
572
+ console.log(colorize(' (文件不存在)', 'gray'));
573
+ }
574
+
575
+ console.log(colorize('\n🎯 LTCraft API 配置状态:', 'blue'));
576
+ if (effectiveBaseUrl === `${API_BASE_URL}/v1` && effectiveApiKey) {
577
+ console.log(colorize(' ✓ LTCraft API 已正确配置', 'green'));
578
+ } else {
579
+ if (effectiveBaseUrl !== `${API_BASE_URL}/v1`) {
580
+ console.log(colorize(` ✗ base_url 不是 LTCraft (当前: ${effectiveBaseUrl || '未设置'})`, 'red'));
581
+ }
582
+ if (!effectiveApiKey) {
583
+ console.log(colorize(' ✗ OPENAI_API_KEY 未设置', 'red'));
584
+ }
585
+ }
586
+ }
587
+
435
588
  async function runCheck() {
436
589
  console.log('╔════════════════════════════════════════╗');
437
590
  console.log('║ LTCraft AI 配置检测工具 ║');
@@ -445,7 +598,8 @@ async function runCheck() {
445
598
  { name: '全部检测', value: 'all' },
446
599
  { name: 'Claude Code', value: 'claude-code' },
447
600
  { name: 'OpenCode', value: 'opencode' },
448
- { name: 'OpenClaw', value: 'openclaw' }
601
+ { name: 'OpenClaw', value: 'openclaw' },
602
+ { name: 'Codex', value: 'codex' }
449
603
  ],
450
604
  default: 'all'
451
605
  });
@@ -455,6 +609,7 @@ async function runCheck() {
455
609
  checkClaudeCode();
456
610
  checkOpenCode();
457
611
  checkOpenClaw();
612
+ checkCodex();
458
613
  break;
459
614
  case 'claude-code':
460
615
  checkClaudeCode();
@@ -465,6 +620,9 @@ async function runCheck() {
465
620
  case 'openclaw':
466
621
  checkOpenClaw();
467
622
  break;
623
+ case 'codex':
624
+ checkCodex();
625
+ break;
468
626
  }
469
627
 
470
628
  console.log(colorize('\n' + '━'.repeat(50), 'cyan'));
@@ -472,6 +630,7 @@ async function runCheck() {
472
630
  console.log(colorize(' Claude Code: 环境变量 > 项目本地配置 > 项目配置 > 全局配置', 'gray'));
473
631
  console.log(colorize(' OpenCode: 环境变量 > 项目配置 > 全局配置', 'gray'));
474
632
  console.log(colorize(' OpenClaw: 全局配置 (暂无项目级配置支持)', 'gray'));
633
+ console.log(colorize(' Codex: 环境变量 > 项目配置(.codex/) > 全局配置(~/.codex/)', 'gray'));
475
634
  console.log();
476
635
  }
477
636
 
@@ -486,7 +645,8 @@ async function main() {
486
645
  choices: [
487
646
  { name: 'Claude Code', value: 'claude-code' },
488
647
  { name: 'OpenCode', value: 'opencode' },
489
- { name: 'OpenClaw', value: 'openclaw' }
648
+ { name: 'OpenClaw', value: 'openclaw' },
649
+ { name: 'Codex', value: 'codex' }
490
650
  ],
491
651
  default: 'claude-code'
492
652
  });
@@ -514,6 +674,9 @@ async function main() {
514
674
  case 'openclaw':
515
675
  configureOpenClaw(trimmedKey);
516
676
  break;
677
+ case 'codex':
678
+ configureCodex(trimmedKey);
679
+ break;
517
680
  }
518
681
  }
519
682
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcraft-ai-auto",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "一键配置 Claude Code / OpenCode / OpenClaw 的 API 密钥工具",
5
5
  "type": "module",
6
6
  "main": "index.js",