duojie-helper 0.2.17 → 0.2.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "duojie-helper",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "Duojie API 一键配置助手 - 支持 Claude Code, Droid, OpenClaw, Cursor, Cline 等主流 AI 编程工具",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -52,17 +52,41 @@ export function getApiBaseForProtocol(protocol = '') {
52
52
  return withoutV1(API_CONFIG.baseUrl);
53
53
  }
54
54
 
55
+ /**
56
+ * 从 pricing 页面获取公开模型 ID 集合
57
+ * 返回 null 表示获取失败,调用方应跳过过滤
58
+ */
59
+ async function fetchPublicModelIds(apiKey) {
60
+ try {
61
+ const response = await fetch(`${API_CONFIG.baseUrl}/pricing`, {
62
+ headers: { 'Authorization': `Bearer ${apiKey}` },
63
+ });
64
+ if (!response.ok) return null;
65
+ const html = await response.text();
66
+ const ids = new Set();
67
+ for (const m of (html.match(/###\s+([^\n\r]+)/g) || [])) {
68
+ ids.add(m.replace(/^###\s+/, '').trim());
69
+ }
70
+ return ids.size > 0 ? ids : null;
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+
55
76
  /**
56
77
  * 从 API 获取模型列表
57
78
  */
58
79
  export async function fetchModels(apiKey) {
59
80
  try {
60
- const response = await fetch(`${API_CONFIG.baseUrl}/v1/models`, {
61
- headers: {
62
- 'Authorization': `Bearer ${apiKey}`,
63
- 'Content-Type': 'application/json',
64
- },
65
- });
81
+ const [response, publicIds] = await Promise.all([
82
+ fetch(`${API_CONFIG.baseUrl}/v1/models`, {
83
+ headers: {
84
+ 'Authorization': `Bearer ${apiKey}`,
85
+ 'Content-Type': 'application/json',
86
+ },
87
+ }),
88
+ fetchPublicModelIds(apiKey),
89
+ ]);
66
90
 
67
91
  if (!response.ok) {
68
92
  throw new Error(`HTTP ${response.status}`);
@@ -79,6 +103,8 @@ export async function fetchModels(apiKey) {
79
103
  if (data.data && Array.isArray(data.data)) {
80
104
  for (const model of data.data) {
81
105
  const id = model.id;
106
+ // 跳过未在 pricing 页面公开的隐藏模型
107
+ if (publicIds && !publicIds.has(id)) continue;
82
108
  const endpoints = model.supported_endpoint_types || [];
83
109
 
84
110
  // 判断最佳协议
@@ -48,7 +48,7 @@ ${chalk.cyan('步骤 4:')} 填入以下配置:
48
48
  ${chalk.green('Base URL:')} ${baseUrl}
49
49
  ${chalk.green('API Key:')} ${apiKey}
50
50
  ${chalk.green('Model:')} 选择 "Enter model ID" 并输入模型名称
51
- 例如: gpt-5.2 或 claude-opus-4-6-kiro
51
+ 例如: gpt-5.2 或 claude-sonnet-4-6
52
52
 
53
53
  ${chalk.cyan('步骤 5:')} 可选配置:
54
54
  • ${chalk.green('Max Tokens:')} 8192 (推荐)
@@ -5,7 +5,7 @@ import TOML from '@iarna/toml';
5
5
  import { getApiBaseForProtocol } from '../index.js';
6
6
 
7
7
  const DUOJIE_PROVIDER_ID = 'duojie';
8
- const DEFAULT_MODEL = 'gpt-5.2';
8
+ const DEFAULT_MODEL = 'gpt-5.4';
9
9
 
10
10
  /**
11
11
  * 获取 Codex CLI 配置路径
@@ -48,7 +48,7 @@ ${chalk.cyan('步骤 3:')} 填入以下配置:
48
48
  ${chalk.green('Override OpenAI Base URL:')} ${baseUrl}
49
49
  ${chalk.green('Model Name:')} 输入模型名称(注意大小写)
50
50
  例如: gpt-5.2
51
- 或: claude-opus-4-6-kiro
51
+ 或: claude-sonnet-4-6
52
52
 
53
53
  ${chalk.cyan('步骤 4:')} 点击保存,然后在模型列表中选择刚添加的模型
54
54
 
@@ -15,6 +15,7 @@ function getDroidConfigPaths() {
15
15
  return {
16
16
  configDir: path.join(home, '.factory'),
17
17
  configFile: path.join(home, '.factory', 'config.json'),
18
+ settingsFile: path.join(home, '.factory', 'settings.json'),
18
19
  };
19
20
  }
20
21
 
@@ -69,7 +70,8 @@ function generateDisplayName(modelId) {
69
70
  * @returns {string} provider 名称
70
71
  */
71
72
  function determineProvider(modelId, endpoints = []) {
72
- return 'anthropic';
73
+ if (modelId.startsWith('claude')) return 'anthropic';
74
+ return 'openai';
73
75
  }
74
76
 
75
77
  /**
@@ -166,6 +168,19 @@ export async function configureDroid(apiKey) {
166
168
  // 6. 写入配置文件
167
169
  await fs.writeJson(paths.configFile, newConfig, { spaces: 2 });
168
170
 
171
+ // 7. 清空 settings.json 中的 customModels(如文件和字段存在)
172
+ if (await fs.pathExists(paths.settingsFile)) {
173
+ try {
174
+ const settings = await fs.readJson(paths.settingsFile);
175
+ if (Array.isArray(settings.customModels) && settings.customModels.length > 0) {
176
+ settings.customModels = [];
177
+ await fs.writeJson(paths.settingsFile, settings, { spaces: 2 });
178
+ }
179
+ } catch {
180
+ // 忽略,不影响主流程
181
+ }
182
+ }
183
+
169
184
  return {
170
185
  success: true,
171
186
  message: `已配置 ${duojieModels.length} 个模型 → ${paths.configFile}`,
@@ -149,17 +149,15 @@ export async function configureOpenClaw(apiKey) {
149
149
 
150
150
  // 默认模型:优先 gpt-5.2(如存在)
151
151
  const gpt52 = gptModels.find(m => m.id === 'gpt-5.2')?.id || null;
152
- let defaultProvider = modelIdToProvider.get('claude-opus-4-6-kiro') || 'duojie-claude';
153
- let defaultModelId = 'claude-opus-4-6-kiro';
152
+ let defaultProvider = 'duojie-claude';
153
+ let defaultModelId = claudeModels[0]?.id || allModels[0]?.id || '';
154
154
 
155
155
  if (gpt52) {
156
156
  defaultProvider = modelIdToProvider.get(gpt52) || providerNameForApi('openai-completions');
157
157
  defaultModelId = gpt52;
158
158
  } else if (claudeModels.length > 0) {
159
159
  defaultModelId = (
160
- claudeModels.find(m => m.id.includes('opus-4-6') && m.id.includes('kiro')) ||
161
160
  claudeModels.find(m => m.id.includes('opus-4-6')) ||
162
- claudeModels.find(m => m.id.includes('opus') && m.id.includes('kiro')) ||
163
161
  claudeModels.find(m => m.id.includes('opus')) ||
164
162
  claudeModels.find(m => m.id.includes('sonnet')) ||
165
163
  claudeModels[0]