ai-account-switch 1.5.5 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [简体中文](README_ZH.md)
4
4
 
5
- A cross-platform CLI tool to manage and switch between Claude/Codex account configurations for different projects.
5
+ A cross-platform CLI tool to manage and switch between Claude/Codex/Droids account configurations for different projects.
6
6
 
7
7
  ## Features
8
8
 
@@ -13,7 +13,7 @@ A cross-platform CLI tool to manage and switch between Claude/Codex account conf
13
13
  - **Claude Code Integration**: Automatically generates `.claude/settings.local.json` for Claude Code CLI
14
14
  - **Secure Storage**: Account credentials stored locally in your home directory
15
15
  - **Interactive CLI**: Easy-to-use interactive prompts for all operations
16
- - **Account Types**: Support for Claude, Codex, and other AI services
16
+ - **Account Types**: Support for Claude, Codex, Droids, and other AI services
17
17
 
18
18
  ## Installation
19
19
 
@@ -329,6 +329,108 @@ grep -A 10 "$(cat .codex-profile)" ~/.codex/config.toml
329
329
  ais doctor
330
330
  ```
331
331
 
332
+ ### Droids Integration
333
+
334
+ When you add a **Droids** type account and run `ais use`, the tool automatically creates a configuration file at `.droids/config.json` in your project directory.
335
+
336
+ #### Adding a Droids Account
337
+
338
+ When adding a Droids account, you'll see helpful configuration tips:
339
+
340
+ ```bash
341
+ ais add my-droids-account
342
+
343
+ ? Select account type: Droids
344
+
345
+ 📝 Droids Configuration Tips:
346
+ • Droids configuration will be stored in .droids/config.json
347
+ • API URL is optional (defaults to Droids default endpoint)
348
+ • You can configure custom models and settings
349
+
350
+ ? Enter API Key: sk-xxx...
351
+ ? Enter API URL (optional): https://api.example.com
352
+ ? Do you want to specify a model? (Optional) Yes
353
+ ? Enter model name: droids-model-v1
354
+ ```
355
+
356
+ #### Using Droids with Your Project
357
+
358
+ After running `ais use` with a Droids account:
359
+
360
+ ```bash
361
+ cd ~/my-project
362
+ ais use my-droids-account
363
+
364
+ # Output:
365
+ # ✓ Switched to account 'my-droids-account' for current project.
366
+ # ✓ Droids configuration generated at: .droids/config.json
367
+ #
368
+ # 📖 Next Steps:
369
+ # Start interactive session: droid
370
+ # This will enter project-level interactive mode
371
+ # Droids will automatically use the configuration from .droids/config.json
372
+ ```
373
+
374
+ The tool creates:
375
+ - **Project Configuration**: `.droids/config.json` with your account settings
376
+
377
+ #### Running Droids
378
+
379
+ Start Droids interactive session:
380
+
381
+ ```bash
382
+ # In your project directory
383
+ droid
384
+
385
+ # Droids will automatically load configuration from .droids/config.json
386
+ ```
387
+
388
+ #### Droids Configuration Structure
389
+
390
+ The generated configuration in `.droids/config.json`:
391
+
392
+ ```json
393
+ {
394
+ "apiKey": "your-api-key",
395
+ "baseUrl": "https://api.example.com",
396
+ "model": "droids-model-v1",
397
+ "customSettings": {
398
+ "CUSTOM_VAR": "value"
399
+ }
400
+ }
401
+ ```
402
+
403
+ #### Switching Between Projects
404
+
405
+ Each project can use a different Droids account:
406
+
407
+ ```bash
408
+ # Project A
409
+ cd ~/project-a
410
+ ais use droids-account-1
411
+ droid
412
+
413
+ # Project B
414
+ cd ~/project-b
415
+ ais use droids-account-2
416
+ droid
417
+ ```
418
+
419
+ #### Troubleshooting Droids
420
+
421
+ **Check Droids Configuration**
422
+ ```bash
423
+ # View your Droids configuration
424
+ cat .droids/config.json
425
+
426
+ # Or use the doctor command
427
+ ais doctor
428
+ ```
429
+
430
+ **Droids CLI not found**
431
+ - Make sure Droids CLI is installed and available in your PATH
432
+ - Run `droid --version` to verify installation
433
+
332
434
  #### Custom Environment Variables
333
435
 
334
436
  You can add custom environment variables when creating an account. When prompted, enter them in `KEY=VALUE` format:
@@ -370,6 +472,9 @@ ais add work-claude
370
472
  # Add a Codex account
371
473
  ais add codex-dev
372
474
 
475
+ # Add a Droids account
476
+ ais add droids-dev
477
+
373
478
  # List all accounts
374
479
  ais list
375
480
  ```
@@ -517,6 +622,28 @@ MIT License - feel free to use this tool in your projects!
517
622
 
518
623
  ## Changelog
519
624
 
625
+ ### v1.5.7
626
+ - **Droids Integration**:
627
+ - Added full support for Droids AI assistant
628
+ - Automatic generation of `.droids/config.json` configuration
629
+ - Simple model configuration for Droids accounts
630
+ - Interactive session command: `droid`
631
+ - Enhanced `ais doctor` command with Droids configuration detection
632
+ - **UI Enhancements**:
633
+ - Added type filter dropdown for quick account filtering
634
+ - Color-coded account cards by type (Claude: blue, Codex: purple, Droids: green, Other: orange)
635
+ - Left border color indicators on account cards
636
+ - Improved visual hierarchy and user experience
637
+ - **Model Configuration Improvements**:
638
+ - Separated model configuration for different account types
639
+ - Claude: Complex model groups with multiple model settings
640
+ - Codex/Droids: Simple model field for straightforward configuration
641
+ - All model settings moved to collapsible "Advanced Configuration" section
642
+ - **Better User Guidance**:
643
+ - Enhanced `ais use` command with clear next-step instructions
644
+ - Type-specific usage examples for each AI assistant
645
+ - Interactive mode prompts instead of one-time command examples
646
+
520
647
  ### v1.5.1
521
648
  - **Codex Integration Enhancements**:
522
649
  - Added full support for Codex CLI with profile-based configuration
package/README_ZH.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | 简体中文
4
4
 
5
- 一个跨平台的命令行工具,用于管理和切换不同项目的 Claude/Codex 账户配置。
5
+ 一个跨平台的命令行工具,用于管理和切换不同项目的 Claude/Codex/Droids 账户配置。
6
6
 
7
7
  ## 特性
8
8
 
@@ -21,7 +21,7 @@
21
21
  - 🎯 主题自动跟随系统设置
22
22
  - **安全存储**:账户凭证仅存储在本地
23
23
  - **交互式命令行**:所有操作都有易用的交互式提示
24
- - **多种账户类型**:支持 Claude、Codex 和其他 AI 服务
24
+ - **多种账户类型**:支持 Claude、Codex、Droids 和其他 AI 服务
25
25
 
26
26
  ## 安装
27
27
 
@@ -384,6 +384,108 @@ grep -A 10 "$(cat .codex-profile)" ~/.codex/config.toml
384
384
  ais doctor
385
385
  ```
386
386
 
387
+ ### Droids 集成
388
+
389
+ 当你添加 **Droids** 类型账户并运行 `ais use` 时,工具会自动在项目目录中创建 `.droids/config.json` 配置文件。
390
+
391
+ #### 添加 Droids 账户
392
+
393
+ 添加 Droids 账户时,你会看到有用的配置提示:
394
+
395
+ ```bash
396
+ ais add my-droids-account
397
+
398
+ ? Select account type: Droids
399
+
400
+ 📝 Droids Configuration Tips:
401
+ • Droids configuration will be stored in .droids/config.json
402
+ • API URL is optional (defaults to Droids default endpoint)
403
+ • You can configure custom models and settings
404
+
405
+ ? Enter API Key: sk-xxx...
406
+ ? Enter API URL (optional): https://api.example.com
407
+ ? Do you want to specify a model? (Optional) Yes
408
+ ? Enter model name: droids-model-v1
409
+ ```
410
+
411
+ #### 在项目中使用 Droids
412
+
413
+ 使用 Droids 账户运行 `ais use` 后:
414
+
415
+ ```bash
416
+ cd ~/my-project
417
+ ais use my-droids-account
418
+
419
+ # 输出:
420
+ # ✓ Switched to account 'my-droids-account' for current project.
421
+ # ✓ Droids configuration generated at: .droids/config.json
422
+ #
423
+ # 📖 Next Steps:
424
+ # Start interactive session: droid
425
+ # This will enter project-level interactive mode
426
+ # Droids will automatically use the configuration from .droids/config.json
427
+ ```
428
+
429
+ 工具会创建:
430
+ - **项目配置**:`.droids/config.json` 包含你的账户设置
431
+
432
+ #### 运行 Droids
433
+
434
+ 启动 Droids 交互会话:
435
+
436
+ ```bash
437
+ # 在项目目录中
438
+ droid
439
+
440
+ # Droids 会自动从 .droids/config.json 加载配置
441
+ ```
442
+
443
+ #### Droids 配置结构
444
+
445
+ 在 `.droids/config.json` 中生成的配置:
446
+
447
+ ```json
448
+ {
449
+ "apiKey": "your-api-key",
450
+ "baseUrl": "https://api.example.com",
451
+ "model": "droids-model-v1",
452
+ "customSettings": {
453
+ "CUSTOM_VAR": "value"
454
+ }
455
+ }
456
+ ```
457
+
458
+ #### 在不同项目间切换
459
+
460
+ 每个项目可以使用不同的 Droids 账户:
461
+
462
+ ```bash
463
+ # 项目 A
464
+ cd ~/project-a
465
+ ais use droids-account-1
466
+ droid
467
+
468
+ # 项目 B
469
+ cd ~/project-b
470
+ ais use droids-account-2
471
+ droid
472
+ ```
473
+
474
+ #### Droids 故障排除
475
+
476
+ **检查 Droids 配置**
477
+ ```bash
478
+ # 查看你的 Droids 配置
479
+ cat .droids/config.json
480
+
481
+ # 或使用 doctor 命令
482
+ ais doctor
483
+ ```
484
+
485
+ **Droids CLI 未找到**
486
+ - 确保 Droids CLI 已安装并在 PATH 中可用
487
+ - 运行 `droid --version` 验证安装
488
+
387
489
  #### 自定义环境变量
388
490
 
389
491
  在创建账户时可以添加自定义环境变量。在提示时,使用 `KEY=VALUE` 格式输入:
@@ -425,6 +527,9 @@ ais add work-claude
425
527
  # 添加 Codex 账户
426
528
  ais add codex-dev
427
529
 
530
+ # 添加 Droids 账户
531
+ ais add droids-dev
532
+
428
533
  # 列出所有账户
429
534
  ais list
430
535
  ```
@@ -594,6 +699,28 @@ MIT License - 欢迎在你的项目中使用此工具!
594
699
 
595
700
  ## 更新日志
596
701
 
702
+ ### v1.5.7
703
+ - **Droids 集成**:
704
+ - 完整支持 Droids AI 助手
705
+ - 自动生成 `.droids/config.json` 配置文件
706
+ - Droids 账户的简单模型配置
707
+ - 交互会话命令:`droid`
708
+ - 增强 `ais doctor` 命令,支持 Droids 配置检测
709
+ - **UI 增强**:
710
+ - 添加类型筛选下拉框,快速过滤账户
711
+ - 按类型为账户卡片着色(Claude: 蓝色,Codex: 紫色,Droids: 绿色,Other: 橙色)
712
+ - 账户卡片左侧边框颜色指示器
713
+ - 改进视觉层次和用户体验
714
+ - **模型配置改进**:
715
+ - 为不同账户类型分离模型配置
716
+ - Claude: 复杂的模型组,支持多个模型设置
717
+ - Codex/Droids: 简单的模型字段,配置更直观
718
+ - 所有模型设置移至可折叠的"高级配置"区域
719
+ - **更好的用户指引**:
720
+ - 增强 `ais use` 命令,提供清晰的下一步操作说明
721
+ - 为每个 AI 助手提供特定类型的使用示例
722
+ - 交互模式提示而非一次性命令示例
723
+
597
724
  ### v1.5.1
598
725
  - **Codex 集成增强**:
599
726
  - 完整支持 Codex CLI 的 profile 配置
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-account-switch",
3
- "version": "1.5.5",
4
- "description": "A cross-platform CLI tool to manage and switch Claude/Codex account configurations",
3
+ "version": "1.5.7",
4
+ "description": "A cross-platform CLI tool to manage and switch Claude/Codex/Droids account configurations",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "ais": "./bin/ais.js"
@@ -14,11 +14,13 @@
14
14
  "cli",
15
15
  "claude",
16
16
  "codex",
17
+ "droids",
17
18
  "account",
18
19
  "switch",
19
20
  "cross-platform",
20
21
  "claude-code",
21
- "ai"
22
+ "ai",
23
+ "ai-assistant"
22
24
  ],
23
25
  "author": "deanwanghewei@gmail.comnpm view ai-account-switch",
24
26
  "license": "MIT",
@@ -30,24 +32,9 @@
30
32
  "chalk": "^4.1.2",
31
33
  "inquirer": "^8.2.5"
32
34
  },
33
- "devDependencies": {
34
- "pkg": "^5.8.1"
35
- },
36
35
  "engines": {
37
36
  "node": ">=14.0.0"
38
37
  },
39
- "pkg": {
40
- "scripts": [
41
- "src/**/*.js"
42
- ],
43
- "assets": [],
44
- "targets": [
45
- "node18-linux-x64",
46
- "node18-macos-x64",
47
- "node18-win-x64"
48
- ],
49
- "outputPath": "dist"
50
- },
51
38
  "repository": {
52
39
  "type": "git",
53
40
  "url": "https://github.com/yourusername/ai-agent-user-swith.git"
package/src/commands.js CHANGED
@@ -44,7 +44,7 @@ async function addAccount(name, options) {
44
44
  type: 'list',
45
45
  name: 'type',
46
46
  message: 'Select account type:',
47
- choices: ['Claude', 'Codex', 'Other'],
47
+ choices: ['Claude', 'Codex', 'Droids', 'Other'],
48
48
  default: 'Claude'
49
49
  }
50
50
  ]);
@@ -55,6 +55,11 @@ async function addAccount(name, options) {
55
55
  console.log(chalk.gray(' • API URL should include the full path (e.g., https://api.example.com/v1)'));
56
56
  console.log(chalk.gray(' • AIS will automatically add /v1 if missing'));
57
57
  console.log(chalk.gray(' • Codex uses OpenAI-compatible API format\n'));
58
+ } else if (typeAnswer.type === 'Droids') {
59
+ console.log(chalk.cyan('\n📝 Droids Configuration Tips:'));
60
+ console.log(chalk.gray(' • Droids configuration will be stored in .droids/config.json'));
61
+ console.log(chalk.gray(' • API URL is optional (defaults to Droids default endpoint)'));
62
+ console.log(chalk.gray(' • You can configure custom models and settings\n'));
58
63
  }
59
64
 
60
65
  // Prompt for remaining account details
@@ -183,28 +188,57 @@ async function addAccount(name, options) {
183
188
  // Remove the addCustomEnv flag before saving
184
189
  delete accountData.addCustomEnv;
185
190
 
186
- // Initialize model groups structure
187
- accountData.modelGroups = {};
188
- accountData.activeModelGroup = null;
191
+ // Handle model configuration based on account type
192
+ if (accountData.type === 'Claude') {
193
+ // Claude uses complex model groups
194
+ accountData.modelGroups = {};
195
+ accountData.activeModelGroup = null;
189
196
 
190
- // Prompt for model group configuration
191
- const { createModelGroup } = await inquirer.prompt([
192
- {
193
- type: 'confirm',
194
- name: 'createModelGroup',
195
- message: 'Do you want to create a model group? (Recommended)',
196
- default: true
197
+ // Prompt for model group configuration
198
+ const { createModelGroup } = await inquirer.prompt([
199
+ {
200
+ type: 'confirm',
201
+ name: 'createModelGroup',
202
+ message: 'Do you want to create a model group? (Recommended)',
203
+ default: true
204
+ }
205
+ ]);
206
+
207
+ if (createModelGroup) {
208
+ const groupName = 'default';
209
+ const modelGroupConfig = await promptForModelGroup();
210
+
211
+ if (Object.keys(modelGroupConfig).length > 0) {
212
+ accountData.modelGroups[groupName] = modelGroupConfig;
213
+ accountData.activeModelGroup = groupName;
214
+ console.log(chalk.green(`\n✓ Created model group '${groupName}'`));
215
+ }
197
216
  }
198
- ]);
217
+ } else if (accountData.type === 'Codex' || accountData.type === 'Droids') {
218
+ // Codex and Droids use simple model field
219
+ const { addModel } = await inquirer.prompt([
220
+ {
221
+ type: 'confirm',
222
+ name: 'addModel',
223
+ message: 'Do you want to specify a model? (Optional)',
224
+ default: false
225
+ }
226
+ ]);
199
227
 
200
- if (createModelGroup) {
201
- const groupName = 'default';
202
- const modelGroupConfig = await promptForModelGroup();
228
+ if (addModel) {
229
+ const { model } = await inquirer.prompt([
230
+ {
231
+ type: 'input',
232
+ name: 'model',
233
+ message: 'Enter model name:',
234
+ default: ''
235
+ }
236
+ ]);
203
237
 
204
- if (Object.keys(modelGroupConfig).length > 0) {
205
- accountData.modelGroups[groupName] = modelGroupConfig;
206
- accountData.activeModelGroup = groupName;
207
- console.log(chalk.green(`\n✓ Created model group '${groupName}'`));
238
+ if (model.trim()) {
239
+ accountData.model = model.trim();
240
+ console.log(chalk.green(`\n✓ Model set to: ${accountData.model}`));
241
+ }
208
242
  }
209
243
  }
210
244
 
@@ -212,10 +246,13 @@ async function addAccount(name, options) {
212
246
  config.addAccount(name, accountData);
213
247
  console.log(chalk.green(`✓ Account '${name}' added successfully!`));
214
248
 
215
- if (accountData.activeModelGroup) {
249
+ // Show model configuration tips based on account type
250
+ if (accountData.type === 'Claude' && accountData.activeModelGroup) {
216
251
  console.log(chalk.cyan(`✓ Active model group: ${accountData.activeModelGroup}\n`));
217
252
  console.log(chalk.gray('💡 Tip: Use "ais model add" to create more model groups'));
218
253
  console.log(chalk.gray('💡 Tip: Use "ais model list" to view all model groups\n'));
254
+ } else if ((accountData.type === 'Codex' || accountData.type === 'Droids') && accountData.model) {
255
+ console.log(chalk.cyan(`✓ Model: ${accountData.model}\n`));
219
256
  }
220
257
 
221
258
  // Show usage instructions based on account type
@@ -232,6 +269,12 @@ async function addAccount(name, options) {
232
269
  console.log(chalk.cyan(` ais use ${name}\n`));
233
270
  console.log(chalk.gray('2. Start Claude Code in your project directory'));
234
271
  console.log(chalk.gray('3. Claude Code will automatically use the project configuration\n'));
272
+ } else if (accountData.type === 'Droids') {
273
+ console.log(chalk.bold.cyan('\n📖 Droids Usage Instructions:\n'));
274
+ console.log(chalk.gray('1. Switch to this account in your project:'));
275
+ console.log(chalk.cyan(` ais use ${name}\n`));
276
+ console.log(chalk.gray('2. Start Droids in your project directory'));
277
+ console.log(chalk.gray('3. Droids will automatically use the configuration from .droids/config.json\n'));
235
278
  }
236
279
  }
237
280
 
@@ -344,11 +387,13 @@ function listAccounts() {
344
387
  if (account.customEnv && Object.keys(account.customEnv).length > 0) {
345
388
  console.log(` Custom Env: ${Object.keys(account.customEnv).join(', ')}`);
346
389
  }
347
- // Display model groups
348
- if (account.modelGroups && Object.keys(account.modelGroups).length > 0) {
390
+ // Display model configuration based on account type
391
+ if (account.type === 'Claude' && account.modelGroups && Object.keys(account.modelGroups).length > 0) {
349
392
  const groupNames = Object.keys(account.modelGroups);
350
393
  const activeMarker = account.activeModelGroup ? ` (active: ${account.activeModelGroup})` : '';
351
394
  console.log(` Model Groups: ${groupNames.join(', ')}${activeMarker}`);
395
+ } else if ((account.type === 'Codex' || account.type === 'Droids') && account.model) {
396
+ console.log(` Model: ${account.model}`);
352
397
  }
353
398
  console.log(` Created: ${new Date(account.createdAt).toLocaleString()}`);
354
399
  console.log('');
@@ -408,16 +453,32 @@ async function useAccount(name) {
408
453
  if (fs.existsSync(profileFile)) {
409
454
  const profileName = fs.readFileSync(profileFile, 'utf8').trim();
410
455
  console.log(chalk.cyan(`✓ Codex profile created: ${profileName}`));
411
- console.log(chalk.yellow(` Use: codex --profile ${profileName} [prompt]`));
456
+ console.log('');
457
+ console.log(chalk.bold.cyan('📖 Next Steps:'));
458
+ console.log(chalk.yellow(` Start interactive session: ${chalk.bold(`codex --profile ${profileName}`)}`));
459
+ console.log(chalk.gray(' This will enter project-level interactive mode'));
412
460
  }
461
+ } else if (account && account.type === 'Droids') {
462
+ console.log(chalk.cyan(`✓ Droids configuration generated at: .droids/config.json`));
463
+ console.log('');
464
+ console.log(chalk.bold.cyan('📖 Next Steps:'));
465
+ console.log(chalk.yellow(` Start interactive session: ${chalk.bold('droid')}`));
466
+ console.log(chalk.gray(' This will enter project-level interactive mode'));
467
+ console.log(chalk.gray(' Droids will automatically use the configuration from .droids/config.json'));
413
468
  } else {
414
469
  console.log(chalk.cyan(`✓ Claude configuration generated at: .claude/settings.local.json`));
470
+ console.log('');
471
+ console.log(chalk.bold.cyan('📖 Next Steps:'));
472
+ console.log(chalk.yellow(` Start interactive session: ${chalk.bold('claude')}`));
473
+ console.log(chalk.gray(' This will enter project-level interactive mode'));
474
+ console.log(chalk.gray(' Claude Code will automatically use the project configuration'));
415
475
  }
416
476
 
417
477
  // Check if .gitignore was updated
418
478
  const gitignorePath = path.join(process.cwd(), '.gitignore');
419
479
  const gitDir = path.join(process.cwd(), '.git');
420
480
  if (fs.existsSync(gitDir) && fs.existsSync(gitignorePath)) {
481
+ console.log('');
421
482
  console.log(chalk.cyan(`✓ Updated .gitignore to exclude AIS configuration files`));
422
483
  }
423
484
  } else {
@@ -451,8 +512,8 @@ function showInfo() {
451
512
  console.log(` ${chalk.gray('•')} ${key}: ${value}`);
452
513
  });
453
514
  }
454
- // Display model groups
455
- if (projectAccount.modelGroups && Object.keys(projectAccount.modelGroups).length > 0) {
515
+ // Display model configuration based on account type
516
+ if (projectAccount.type === 'Claude' && projectAccount.modelGroups && Object.keys(projectAccount.modelGroups).length > 0) {
456
517
  console.log(`${chalk.cyan('Model Groups:')}`);
457
518
  Object.keys(projectAccount.modelGroups).forEach(groupName => {
458
519
  const isActive = projectAccount.activeModelGroup === groupName;
@@ -462,6 +523,8 @@ function showInfo() {
462
523
  if (projectAccount.activeModelGroup) {
463
524
  console.log(`${chalk.cyan('Active Model Group:')} ${chalk.green.bold(projectAccount.activeModelGroup)}`);
464
525
  }
526
+ } else if ((projectAccount.type === 'Codex' || projectAccount.type === 'Droids') && projectAccount.model) {
527
+ console.log(`${chalk.cyan('Model:')} ${projectAccount.model}`);
465
528
  }
466
529
  console.log(`${chalk.cyan('Set At:')} ${new Date(projectAccount.setAt).toLocaleString()}`);
467
530
  console.log(`${chalk.cyan('Project Root:')} ${projectAccount.projectRoot}`);
@@ -697,11 +760,47 @@ async function doctor() {
697
760
  console.log(chalk.yellow(' Run "ais use <account>" to generate it'));
698
761
  }
699
762
 
763
+ // Check Droids config
764
+ const droidsDir = path.join(projectRoot, '.droids');
765
+ const droidsConfigPath = path.join(droidsDir, 'config.json');
766
+
767
+ console.log(chalk.bold('\n5. Droids Configuration:'));
768
+ console.log(` Expected location: ${droidsConfigPath}`);
769
+
770
+ if (fs.existsSync(droidsConfigPath)) {
771
+ console.log(chalk.green(' ✓ Droids config exists'));
772
+ try {
773
+ const droidsConfig = JSON.parse(fs.readFileSync(droidsConfigPath, 'utf8'));
774
+
775
+ if (droidsConfig.apiKey) {
776
+ const masked = droidsConfig.apiKey.substring(0, 6) + '****' + droidsConfig.apiKey.substring(droidsConfig.apiKey.length - 4);
777
+ console.log(` API Key: ${masked}`);
778
+ }
779
+
780
+ if (droidsConfig.baseUrl) {
781
+ console.log(` Base URL: ${droidsConfig.baseUrl}`);
782
+ }
783
+
784
+ if (droidsConfig.model) {
785
+ console.log(` Model: ${droidsConfig.model}`);
786
+ }
787
+
788
+ if (droidsConfig.customSettings) {
789
+ console.log(` Custom Settings: ${Object.keys(droidsConfig.customSettings).join(', ')}`);
790
+ }
791
+ } catch (e) {
792
+ console.log(chalk.red(` ✗ Error reading Droids config: ${e.message}`));
793
+ }
794
+ } else {
795
+ console.log(chalk.yellow(' ⚠ Droids config not found'));
796
+ console.log(chalk.yellow(' Run "ais use <droids-account>" to generate it'));
797
+ }
798
+
700
799
  // Check Codex profile
701
800
  const codexProfilePath = path.join(projectRoot, '.codex-profile');
702
801
  const globalCodexConfig = path.join(os.homedir(), '.codex', 'config.toml');
703
802
 
704
- console.log(chalk.bold('\n5. Codex Configuration:'));
803
+ console.log(chalk.bold('\n6. Codex Configuration:'));
705
804
  console.log(` Profile file: ${codexProfilePath}`);
706
805
 
707
806
  if (fs.existsSync(codexProfilePath)) {
@@ -750,7 +849,7 @@ async function doctor() {
750
849
 
751
850
  // Check global Claude config
752
851
  const globalClaudeConfig = path.join(os.homedir(), '.claude', 'settings.json');
753
- console.log(chalk.bold('\n6. Global Claude Configuration:'));
852
+ console.log(chalk.bold('\n7. Global Claude Configuration:'));
754
853
  console.log(` Location: ${globalClaudeConfig}`);
755
854
 
756
855
  if (fs.existsSync(globalClaudeConfig)) {
@@ -773,7 +872,7 @@ async function doctor() {
773
872
  }
774
873
 
775
874
  // Check current account availability
776
- console.log(chalk.bold('\n7. Current Account Availability:'));
875
+ console.log(chalk.bold('\n8. Current Account Availability:'));
777
876
  const projectAccount = config.getProjectAccount();
778
877
 
779
878
  if (projectAccount && projectAccount.apiKey) {
@@ -812,6 +911,15 @@ async function doctor() {
812
911
  } catch (e) {
813
912
  console.log(chalk.yellow(' ⚠ Codex CLI not found'));
814
913
  }
914
+ } else if (projectAccount.type === 'Droids') {
915
+ console.log(' Testing with Droids CLI...');
916
+ const { execSync } = require('child_process');
917
+ try {
918
+ execSync('droid --version', { stdio: 'pipe', timeout: 5000 });
919
+ console.log(chalk.green(' ✓ Droids CLI is available'));
920
+ } catch (e) {
921
+ console.log(chalk.yellow(' ⚠ Droids CLI not found'));
922
+ }
815
923
  }
816
924
 
817
925
  console.log(` API URL: ${projectAccount.apiUrl || 'https://api.anthropic.com'}`);
@@ -840,7 +948,7 @@ async function doctor() {
840
948
  }
841
949
 
842
950
  // Recommendations
843
- console.log(chalk.bold('\n8. Recommendations:'));
951
+ console.log(chalk.bold('\n9. Recommendations:'));
844
952
 
845
953
  if (projectRoot && process.cwd() !== projectRoot) {
846
954
  console.log(chalk.yellow(` ⚠ You are in a subdirectory (${path.relative(projectRoot, process.cwd())})`));
@@ -855,9 +963,9 @@ async function doctor() {
855
963
  console.log(chalk.gray(` • File: ${globalClaudeConfig}`));
856
964
  }
857
965
 
858
- console.log(chalk.bold('\n9. Next Steps:'));
859
- console.log(chalk.cyan(' • Start Claude Code from your project directory or subdirectory'));
860
- console.log(chalk.cyan(' • Check which account Claude Code is using'));
966
+ console.log(chalk.bold('\n10. Next Steps:'));
967
+ console.log(chalk.cyan(' • Start Claude Code/Codex/Droids from your project directory or subdirectory'));
968
+ console.log(chalk.cyan(' • Check which account is being used'));
861
969
  console.log(chalk.cyan(' • If wrong account is used, run: ais use <correct-account>'));
862
970
  console.log('');
863
971
  }
package/src/config.js CHANGED
@@ -146,6 +146,9 @@ class ConfigManager {
146
146
  if (account.type === 'Codex') {
147
147
  // Codex type accounts only need Codex configuration
148
148
  this.generateCodexConfig(account, projectRoot);
149
+ } else if (account.type === 'Droids') {
150
+ // Droids type accounts only need Droids configuration
151
+ this.generateDroidsConfig(account, projectRoot);
149
152
  } else {
150
153
  // Claude and other types need Claude Code configuration
151
154
  this.generateClaudeConfig(account, projectRoot);
@@ -173,7 +176,8 @@ class ConfigManager {
173
176
  const filesToIgnore = [
174
177
  this.projectConfigFilename,
175
178
  '.claude/settings.local.json',
176
- '.codex-profile'
179
+ '.codex-profile',
180
+ '.droids/config.json'
177
181
  ];
178
182
 
179
183
  let gitignoreContent = '';
@@ -346,6 +350,42 @@ class ConfigManager {
346
350
  fs.writeFileSync(claudeConfigFile, JSON.stringify(claudeConfig, null, 2), 'utf8');
347
351
  }
348
352
 
353
+ /**
354
+ * Generate Droids configuration in .droids/config.json
355
+ */
356
+ generateDroidsConfig(account, projectRoot = process.cwd()) {
357
+ const droidsDir = path.join(projectRoot, '.droids');
358
+ const droidsConfigFile = path.join(droidsDir, 'config.json');
359
+
360
+ // Create .droids directory if it doesn't exist
361
+ if (!fs.existsSync(droidsDir)) {
362
+ fs.mkdirSync(droidsDir, { recursive: true });
363
+ }
364
+
365
+ // Build Droids configuration
366
+ const droidsConfig = {
367
+ apiKey: account.apiKey
368
+ };
369
+
370
+ // Add API URL if specified
371
+ if (account.apiUrl) {
372
+ droidsConfig.baseUrl = account.apiUrl;
373
+ }
374
+
375
+ // Add model configuration - Droids uses simple model field
376
+ if (account.model) {
377
+ droidsConfig.model = account.model;
378
+ }
379
+
380
+ // Add custom environment variables as customSettings
381
+ if (account.customEnv && typeof account.customEnv === 'object') {
382
+ droidsConfig.customSettings = account.customEnv;
383
+ }
384
+
385
+ // Write Droids configuration
386
+ fs.writeFileSync(droidsConfigFile, JSON.stringify(droidsConfig, null, 2), 'utf8');
387
+ }
388
+
349
389
  /**
350
390
  * Generate Codex profile in global ~/.codex/config.toml
351
391
  */
@@ -385,12 +425,9 @@ class ConfigManager {
385
425
 
386
426
  profileConfig += `model_provider = "${providerName}"\n`;
387
427
 
388
- // Add model configuration from active model group if available
389
- if (account.modelGroups && account.activeModelGroup) {
390
- const activeGroup = account.modelGroups[account.activeModelGroup];
391
- if (activeGroup && activeGroup.DEFAULT_MODEL) {
392
- profileConfig += `model = "${activeGroup.DEFAULT_MODEL}"\n`;
393
- }
428
+ // Add model configuration - Codex uses simple model field
429
+ if (account.model) {
430
+ profileConfig += `model = "${account.model}"\n`;
394
431
  }
395
432
 
396
433
  // Ensure API URL has proper path
package/src/index.js CHANGED
@@ -25,7 +25,7 @@ const packageJson = require('../package.json');
25
25
 
26
26
  program
27
27
  .name('ais')
28
- .description('AI Account Switch - Manage and switch Claude/Codex account configurations')
28
+ .description('AI Account Switch - Manage and switch Claude/Codex/Droids account configurations')
29
29
  .version(packageJson.version);
30
30
 
31
31
  // Add account command
package/src/ui-server.js CHANGED
@@ -482,6 +482,21 @@ class UIServer {
482
482
  color: var(--text-primary);
483
483
  }
484
484
 
485
+ .filter-box {
486
+ min-width: 150px;
487
+ }
488
+
489
+ .filter-box select {
490
+ width: 100%;
491
+ padding: 10px;
492
+ border: 1px solid var(--input-border);
493
+ border-radius: 5px;
494
+ font-size: 14px;
495
+ background: var(--input-bg);
496
+ color: var(--text-primary);
497
+ cursor: pointer;
498
+ }
499
+
485
500
  .accounts-grid {
486
501
  display: grid;
487
502
  grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
@@ -497,6 +512,7 @@ class UIServer {
497
512
  display: flex;
498
513
  flex-direction: column;
499
514
  min-height: 200px;
515
+ border-left: 4px solid transparent;
500
516
  }
501
517
 
502
518
  .account-card:hover {
@@ -504,6 +520,22 @@ class UIServer {
504
520
  box-shadow: 0 6px 12px var(--card-shadow-hover);
505
521
  }
506
522
 
523
+ .account-card.type-claude {
524
+ border-left-color: #1976d2;
525
+ }
526
+
527
+ .account-card.type-codex {
528
+ border-left-color: #7b1fa2;
529
+ }
530
+
531
+ .account-card.type-droids {
532
+ border-left-color: #388e3c;
533
+ }
534
+
535
+ .account-card.type-other {
536
+ border-left-color: #f57c00;
537
+ }
538
+
507
539
  .account-content {
508
540
  flex: 1;
509
541
  }
@@ -527,10 +559,28 @@ class UIServer {
527
559
  border-radius: 4px;
528
560
  font-size: 12px;
529
561
  font-weight: 500;
562
+ }
563
+
564
+ .account-type.type-claude {
530
565
  background: #e3f2fd;
531
566
  color: #1976d2;
532
567
  }
533
568
 
569
+ .account-type.type-codex {
570
+ background: #f3e5f5;
571
+ color: #7b1fa2;
572
+ }
573
+
574
+ .account-type.type-droids {
575
+ background: #e8f5e9;
576
+ color: #388e3c;
577
+ }
578
+
579
+ .account-type.type-other {
580
+ background: #fff3e0;
581
+ color: #f57c00;
582
+ }
583
+
534
584
  .account-info {
535
585
  margin-bottom: 10px;
536
586
  }
@@ -807,6 +857,15 @@ class UIServer {
807
857
  <div class="search-box">
808
858
  <input type="text" id="searchInput" data-i18n-placeholder="searchPlaceholder" placeholder="搜索账号...">
809
859
  </div>
860
+ <div class="filter-box">
861
+ <select id="typeFilter" onchange="renderAccounts()">
862
+ <option value="" data-i18n="allTypes">所有类型</option>
863
+ <option value="Claude">Claude</option>
864
+ <option value="Codex">Codex</option>
865
+ <option value="Droids">Droids</option>
866
+ <option value="Other" data-i18n="other">其他</option>
867
+ </select>
868
+ </div>
810
869
  <button class="btn btn-primary" onclick="showAddModal()" data-i18n="addAccount">+ 添加账号</button>
811
870
  <button class="btn btn-secondary" onclick="exportAccounts()" data-i18n="exportAll">导出全部</button>
812
871
  <button class="btn btn-secondary" onclick="document.getElementById('importFile').click()" data-i18n="import">导入</button>
@@ -832,9 +891,10 @@ class UIServer {
832
891
  </div>
833
892
  <div class="form-group">
834
893
  <label for="accountType" data-i18n="type">类型 *</label>
835
- <select id="accountType" required>
894
+ <select id="accountType" required onchange="toggleModelFields()">
836
895
  <option value="Claude">Claude</option>
837
896
  <option value="Codex">Codex</option>
897
+ <option value="Droids">Droids</option>
838
898
  <option value="Other" data-i18n="other">其他</option>
839
899
  </select>
840
900
  </div>
@@ -854,19 +914,31 @@ class UIServer {
854
914
  <label for="description" data-i18n="description">描述 (可选)</label>
855
915
  <textarea id="description" data-i18n-placeholder="descriptionPlaceholder" placeholder="用于生产环境的主账号"></textarea>
856
916
  </div>
857
- <div class="form-group">
858
- <label data-i18n="customEnv">自定义环境变量 (可选)</label>
859
- <div id="envVarsList"></div>
860
- <button type="button" class="btn btn-secondary btn-small" onclick="addEnvVar()" data-i18n="addVariable">+ 添加变量</button>
861
- </div>
862
917
  <div class="form-group">
863
918
  <div class="advanced-toggle" onclick="toggleAdvancedSettings()">
864
919
  <span class="advanced-toggle-icon" id="advancedToggleIcon">▶</span>
865
- <span data-i18n="advancedSettings">高级设置 - 模型组</span>
920
+ <span data-i18n="advancedSettings">高级配置</span>
866
921
  </div>
867
922
  <div class="advanced-content" id="advancedContent">
868
- <div id="modelGroupsList" style="margin-bottom: 10px;"></div>
869
- <button type="button" class="btn btn-secondary btn-small" onclick="addModelGroupUI()" data-i18n="addModelGroup">+ 添加模型组</button>
923
+ <!-- Custom Environment Variables -->
924
+ <div class="form-group">
925
+ <label data-i18n="customEnv">自定义环境变量</label>
926
+ <div id="envVarsList"></div>
927
+ <button type="button" class="btn btn-secondary btn-small" onclick="addEnvVar()" data-i18n="addVariable">+ 添加变量</button>
928
+ </div>
929
+ <!-- Model Configuration -->
930
+ <div class="form-group">
931
+ <label data-i18n="modelConfig">模型配置</label>
932
+ <!-- Simple model field for Codex/Droids -->
933
+ <div id="simpleModelGroup" style="display: none;">
934
+ <input type="text" id="simpleModel" data-i18n-placeholder="simpleModelPlaceholder" placeholder="例如: gpt-4, droids-model-v1">
935
+ </div>
936
+ <!-- Model groups for Claude -->
937
+ <div id="claudeModelGroup" style="display: none;">
938
+ <div id="modelGroupsList" style="margin-bottom: 10px;"></div>
939
+ <button type="button" class="btn btn-secondary btn-small" onclick="addModelGroupUI()" data-i18n="addModelGroup">+ 添加模型组</button>
940
+ </div>
941
+ </div>
870
942
  </div>
871
943
  </div>
872
944
  <div class="form-actions">
@@ -885,6 +957,7 @@ class UIServer {
885
957
  subtitle: '管理你的 AI 账号配置',
886
958
  themeLabel: '主题',
887
959
  searchPlaceholder: '搜索账号...',
960
+ allTypes: '所有类型',
888
961
  addAccount: '+ 添加账号',
889
962
  exportAll: '导出全部',
890
963
  import: '导入',
@@ -904,9 +977,12 @@ class UIServer {
904
977
  emailPlaceholder: 'user@example.com',
905
978
  description: '描述 (可选)',
906
979
  descriptionPlaceholder: '用于生产环境的主账号',
907
- customEnv: '自定义环境变量 (可选)',
980
+ advancedSettings: '高级配置',
981
+ customEnv: '自定义环境变量',
908
982
  addVariable: '+ 添加变量',
909
- advancedSettings: '高级设置 - 模型组',
983
+ modelConfig: '模型配置',
984
+ simpleModel: '模型',
985
+ simpleModelPlaceholder: '例如: gpt-4, droids-model-v1',
910
986
  addModelGroup: '+ 添加模型组',
911
987
  modelGroupName: '模型组名称',
912
988
  setActive: '设为激活',
@@ -937,6 +1013,7 @@ class UIServer {
937
1013
  subtitle: 'Manage your AI account configurations',
938
1014
  themeLabel: 'Theme',
939
1015
  searchPlaceholder: 'Search accounts...',
1016
+ allTypes: 'All Types',
940
1017
  addAccount: '+ Add Account',
941
1018
  exportAll: 'Export All',
942
1019
  import: 'Import',
@@ -956,9 +1033,12 @@ class UIServer {
956
1033
  emailPlaceholder: 'user@example.com',
957
1034
  description: 'Description (optional)',
958
1035
  descriptionPlaceholder: 'Main account for production environment',
959
- customEnv: 'Custom Environment Variables (optional)',
1036
+ advancedSettings: 'Advanced Configuration',
1037
+ customEnv: 'Custom Environment Variables',
960
1038
  addVariable: '+ Add Variable',
961
- advancedSettings: 'Advanced Settings - Model Groups',
1039
+ modelConfig: 'Model Configuration',
1040
+ simpleModel: 'Model',
1041
+ simpleModelPlaceholder: 'e.g., gpt-4, droids-model-v1',
962
1042
  addModelGroup: '+ Add Model Group',
963
1043
  modelGroupName: 'Model Group Name',
964
1044
  setActive: 'Set Active',
@@ -1068,11 +1148,18 @@ class UIServer {
1068
1148
  const container = document.getElementById('accountsContainer');
1069
1149
  const emptyState = document.getElementById('emptyState');
1070
1150
  const searchTerm = document.getElementById('searchInput').value.toLowerCase();
1151
+ const typeFilter = document.getElementById('typeFilter').value;
1071
1152
 
1072
1153
  const filteredAccounts = Object.entries(accounts).filter(([name, data]) => {
1073
- return name.toLowerCase().includes(searchTerm) ||
1154
+ // Search filter
1155
+ const matchesSearch = name.toLowerCase().includes(searchTerm) ||
1074
1156
  (data.email && data.email.toLowerCase().includes(searchTerm)) ||
1075
1157
  (data.type && data.type.toLowerCase().includes(searchTerm));
1158
+
1159
+ // Type filter
1160
+ const matchesType = !typeFilter || data.type === typeFilter;
1161
+
1162
+ return matchesSearch && matchesType;
1076
1163
  });
1077
1164
 
1078
1165
  if (filteredAccounts.length === 0) {
@@ -1082,12 +1169,14 @@ class UIServer {
1082
1169
  }
1083
1170
 
1084
1171
  emptyState.classList.add('hidden');
1085
- container.innerHTML = filteredAccounts.map(([name, data]) => \`
1086
- <div class="account-card">
1172
+ container.innerHTML = filteredAccounts.map(([name, data]) => {
1173
+ const typeClass = data.type ? \`type-\${data.type.toLowerCase()}\` : 'type-other';
1174
+ return \`
1175
+ <div class="account-card \${typeClass}">
1087
1176
  <div class="account-content">
1088
1177
  <div class="account-header">
1089
1178
  <div class="account-name">\${name}</div>
1090
- <div class="account-type">\${data.type || 'N/A'}</div>
1179
+ <div class="account-type \${typeClass}">\${data.type || 'N/A'}</div>
1091
1180
  </div>
1092
1181
  <div class="account-info">
1093
1182
  <div class="info-label">\${t('apiKeyLabel')}</div>
@@ -1117,19 +1206,26 @@ class UIServer {
1117
1206
  <div class="info-value">\${Object.keys(data.customEnv).join(', ')}</div>
1118
1207
  </div>
1119
1208
  \` : ''}
1120
- \${data.modelGroups && Object.keys(data.modelGroups).length > 0 ? \`
1209
+ \${data.type === 'Claude' && data.modelGroups && Object.keys(data.modelGroups).length > 0 ? \`
1121
1210
  <div class="account-info">
1122
1211
  <div class="info-label">Model Groups</div>
1123
1212
  <div class="info-value">\${Object.keys(data.modelGroups).join(', ')} \${data.activeModelGroup ? '(active: ' + data.activeModelGroup + ')' : ''}</div>
1124
1213
  </div>
1125
1214
  \` : ''}
1215
+ \${(data.type === 'Codex' || data.type === 'Droids') && data.model ? \`
1216
+ <div class="account-info">
1217
+ <div class="info-label">Model</div>
1218
+ <div class="info-value">\${data.model}</div>
1219
+ </div>
1220
+ \` : ''}
1126
1221
  </div>
1127
1222
  <div class="account-actions">
1128
1223
  <button class="btn btn-secondary btn-small" onclick="editAccount('\${name}')">\${t('edit')}</button>
1129
1224
  <button class="btn btn-danger btn-small" onclick="deleteAccount('\${name}')">\${t('delete')}</button>
1130
1225
  </div>
1131
1226
  </div>
1132
- \`).join('');
1227
+ \`;
1228
+ }).join('');
1133
1229
  }
1134
1230
 
1135
1231
  function maskApiKey(key) {
@@ -1137,6 +1233,22 @@ class UIServer {
1137
1233
  return key.substring(0, 4) + '****' + key.substring(key.length - 4);
1138
1234
  }
1139
1235
 
1236
+ function toggleModelFields() {
1237
+ const accountType = document.getElementById('accountType').value;
1238
+ const simpleModelGroup = document.getElementById('simpleModelGroup');
1239
+ const claudeModelGroup = document.getElementById('claudeModelGroup');
1240
+
1241
+ if (accountType === 'Codex' || accountType === 'Droids') {
1242
+ // Show simple model field, hide Claude model groups
1243
+ simpleModelGroup.style.display = 'block';
1244
+ claudeModelGroup.style.display = 'none';
1245
+ } else {
1246
+ // Show Claude model groups, hide simple model field
1247
+ simpleModelGroup.style.display = 'none';
1248
+ claudeModelGroup.style.display = 'block';
1249
+ }
1250
+ }
1251
+
1140
1252
  function showAddModal() {
1141
1253
  editingAccount = null;
1142
1254
  document.getElementById('modalTitle').textContent = t('addAccountTitle');
@@ -1148,9 +1260,13 @@ class UIServer {
1148
1260
  document.getElementById('modelGroupsList').innerHTML = '';
1149
1261
  modelGroupCount = 0;
1150
1262
  activeModelGroup = null;
1263
+ // Clear simple model
1264
+ document.getElementById('simpleModel').value = '';
1151
1265
  // Collapse advanced settings
1152
1266
  document.getElementById('advancedContent').classList.remove('expanded');
1153
1267
  document.getElementById('advancedToggleIcon').classList.remove('expanded');
1268
+ // Toggle model fields based on default type (Claude)
1269
+ toggleModelFields();
1154
1270
  document.getElementById('accountModal').classList.add('active');
1155
1271
  }
1156
1272
 
@@ -1176,13 +1292,27 @@ class UIServer {
1176
1292
  });
1177
1293
  }
1178
1294
 
1179
- // Load model groups
1180
- document.getElementById('modelGroupsList').innerHTML = '';
1181
- modelGroupCount = 0;
1182
- activeModelGroup = null;
1183
-
1184
- const hasModelGroups = account.modelGroups && Object.keys(account.modelGroups).length > 0;
1185
- if (hasModelGroups) {
1295
+ // Toggle model fields based on account type
1296
+ toggleModelFields();
1297
+
1298
+ // Load model configuration based on account type
1299
+ if (account.type === 'Codex' || account.type === 'Droids') {
1300
+ // Load simple model field
1301
+ document.getElementById('simpleModel').value = account.model || '';
1302
+ // Clear model groups
1303
+ document.getElementById('modelGroupsList').innerHTML = '';
1304
+ modelGroupCount = 0;
1305
+ activeModelGroup = null;
1306
+ } else {
1307
+ // Load model groups for Claude
1308
+ document.getElementById('modelGroupsList').innerHTML = '';
1309
+ modelGroupCount = 0;
1310
+ activeModelGroup = null;
1311
+ // Clear simple model
1312
+ document.getElementById('simpleModel').value = '';
1313
+
1314
+ const hasModelGroups = account.modelGroups && Object.keys(account.modelGroups).length > 0;
1315
+ if (hasModelGroups) {
1186
1316
  Object.entries(account.modelGroups).forEach(([groupName, groupConfig]) => {
1187
1317
  const groupId = modelGroupCount++;
1188
1318
  const isActive = account.activeModelGroup === groupName;
@@ -1237,13 +1367,14 @@ class UIServer {
1237
1367
  container.appendChild(div);
1238
1368
  });
1239
1369
 
1240
- // Expand advanced settings if model groups exist
1241
- document.getElementById('advancedContent').classList.add('expanded');
1242
- document.getElementById('advancedToggleIcon').classList.add('expanded');
1243
- } else {
1244
- // Collapse advanced settings if no model groups
1245
- document.getElementById('advancedContent').classList.remove('expanded');
1246
- document.getElementById('advancedToggleIcon').classList.remove('expanded');
1370
+ // Expand advanced settings if model groups exist
1371
+ document.getElementById('advancedContent').classList.add('expanded');
1372
+ document.getElementById('advancedToggleIcon').classList.add('expanded');
1373
+ } else {
1374
+ // Collapse advanced settings if no model groups
1375
+ document.getElementById('advancedContent').classList.remove('expanded');
1376
+ document.getElementById('advancedToggleIcon').classList.remove('expanded');
1377
+ }
1247
1378
  }
1248
1379
 
1249
1380
  document.getElementById('accountModal').classList.add('active');
@@ -1404,12 +1535,22 @@ class UIServer {
1404
1535
  delete accountData.customEnv;
1405
1536
  }
1406
1537
 
1407
- // Collect model groups
1408
- accountData.modelGroups = {};
1409
- accountData.activeModelGroup = null;
1538
+ // Collect model configuration based on account type
1539
+ const accountType = document.getElementById('accountType').value;
1410
1540
 
1411
- const modelGroupsList = document.getElementById('modelGroupsList');
1412
- modelGroupsList.querySelectorAll('.model-group-item').forEach(item => {
1541
+ if (accountType === 'Codex' || accountType === 'Droids') {
1542
+ // Use simple model field
1543
+ const simpleModel = document.getElementById('simpleModel').value.trim();
1544
+ if (simpleModel) {
1545
+ accountData.model = simpleModel;
1546
+ }
1547
+ } else {
1548
+ // Collect model groups for Claude
1549
+ accountData.modelGroups = {};
1550
+ accountData.activeModelGroup = null;
1551
+
1552
+ const modelGroupsList = document.getElementById('modelGroupsList');
1553
+ modelGroupsList.querySelectorAll('.model-group-item').forEach(item => {
1413
1554
  const groupId = parseInt(item.id.replace('modelGroup', ''));
1414
1555
  const groupName = document.getElementById(\`groupName\${groupId}\`).value;
1415
1556
 
@@ -1430,15 +1571,16 @@ class UIServer {
1430
1571
 
1431
1572
  accountData.modelGroups[groupName] = groupConfig;
1432
1573
 
1433
- // Check if this is the active group
1434
- if (activeModelGroup === groupId) {
1435
- accountData.activeModelGroup = groupName;
1436
- }
1437
- });
1574
+ // Check if this is the active group
1575
+ if (activeModelGroup === groupId) {
1576
+ accountData.activeModelGroup = groupName;
1577
+ }
1578
+ });
1438
1579
 
1439
- if (Object.keys(accountData.modelGroups).length === 0) {
1440
- delete accountData.modelGroups;
1441
- delete accountData.activeModelGroup;
1580
+ if (Object.keys(accountData.modelGroups).length === 0) {
1581
+ delete accountData.modelGroups;
1582
+ delete accountData.activeModelGroup;
1583
+ }
1442
1584
  }
1443
1585
 
1444
1586
  try {