@adversity/coding-tool-x 3.1.0 → 3.1.2

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +39 -18
  2. package/README.md +8 -8
  3. package/dist/web/assets/ConfigTemplates-Bidwfdf2.css +1 -0
  4. package/dist/web/assets/ConfigTemplates-DvcbKKdS.js +1 -0
  5. package/dist/web/assets/Home-BJKPCBuk.css +1 -0
  6. package/dist/web/assets/Home-Cw-F_Wnu.js +1 -0
  7. package/dist/web/assets/PluginManager-ROyoZ-6m.css +1 -0
  8. package/dist/web/assets/PluginManager-jy_4GVxI.js +1 -0
  9. package/dist/web/assets/ProjectList-C1fQb9OW.css +1 -0
  10. package/dist/web/assets/ProjectList-Df1-NcNr.js +1 -0
  11. package/dist/web/assets/SessionList-BGJWyneI.css +1 -0
  12. package/dist/web/assets/SessionList-UWcZtC2r.js +1 -0
  13. package/dist/web/assets/SkillManager-D7pd-d_P.css +1 -0
  14. package/dist/web/assets/SkillManager-IRdseMKB.js +1 -0
  15. package/dist/web/assets/Terminal-BasTyDut.js +1 -0
  16. package/dist/web/assets/Terminal-DGNJeVtc.css +1 -0
  17. package/dist/web/assets/WorkspaceManager-CrwgQgmP.css +1 -0
  18. package/dist/web/assets/WorkspaceManager-D-D2kK1V.js +1 -0
  19. package/dist/web/assets/icons-kcfLIMBB.js +1 -0
  20. package/dist/web/assets/index-CoB3zF0K.css +1 -0
  21. package/dist/web/assets/index-CryrSLv8.js +2 -0
  22. package/dist/web/assets/markdown-BfC0goYb.css +10 -0
  23. package/dist/web/assets/markdown-C9MYpaSi.js +1 -0
  24. package/dist/web/assets/naive-ui-CSrLusZZ.js +1 -0
  25. package/dist/web/assets/{vendors-D2HHw_aW.js → vendors-CO3Upi1d.js} +2 -2
  26. package/dist/web/assets/vue-vendor-DqyWIXEb.js +45 -0
  27. package/dist/web/assets/xterm-6GBZ9nXN.css +32 -0
  28. package/dist/web/assets/xterm-BJzAjXCH.js +13 -0
  29. package/dist/web/index.html +8 -6
  30. package/package.json +4 -2
  31. package/src/commands/channels.js +48 -1
  32. package/src/commands/cli-type.js +4 -2
  33. package/src/commands/daemon.js +81 -12
  34. package/src/commands/doctor.js +10 -9
  35. package/src/commands/list.js +1 -1
  36. package/src/commands/logs.js +6 -4
  37. package/src/commands/port-config.js +24 -4
  38. package/src/commands/proxy-control.js +12 -6
  39. package/src/commands/search.js +1 -1
  40. package/src/commands/security.js +3 -2
  41. package/src/commands/stats.js +226 -52
  42. package/src/commands/switch.js +1 -1
  43. package/src/commands/toggle-proxy.js +31 -6
  44. package/src/commands/update.js +97 -0
  45. package/src/commands/workspace.js +1 -1
  46. package/src/config/default.js +41 -2
  47. package/src/config/loader.js +74 -8
  48. package/src/config/model-metadata.js +415 -0
  49. package/src/config/model-pricing.js +23 -93
  50. package/src/config/paths.js +105 -33
  51. package/src/index.js +64 -3
  52. package/src/plugins/constants.js +3 -2
  53. package/src/plugins/plugin-api.js +1 -1
  54. package/src/reset-config.js +4 -2
  55. package/src/server/api/agents.js +57 -14
  56. package/src/server/api/channels.js +112 -33
  57. package/src/server/api/codex-channels.js +111 -18
  58. package/src/server/api/codex-proxy.js +14 -8
  59. package/src/server/api/commands.js +71 -18
  60. package/src/server/api/config-export.js +0 -6
  61. package/src/server/api/config-registry.js +11 -3
  62. package/src/server/api/config.js +376 -5
  63. package/src/server/api/convert.js +133 -0
  64. package/src/server/api/dashboard.js +22 -6
  65. package/src/server/api/gemini-channels.js +107 -18
  66. package/src/server/api/gemini-proxy.js +14 -8
  67. package/src/server/api/gemini-sessions.js +1 -1
  68. package/src/server/api/health-check.js +4 -3
  69. package/src/server/api/mcp.js +3 -3
  70. package/src/server/api/opencode-channels.js +497 -0
  71. package/src/server/api/opencode-projects.js +99 -0
  72. package/src/server/api/opencode-proxy.js +207 -0
  73. package/src/server/api/opencode-sessions.js +345 -0
  74. package/src/server/api/opencode-statistics.js +57 -0
  75. package/src/server/api/plugins.js +66 -19
  76. package/src/server/api/prompts.js +2 -2
  77. package/src/server/api/proxy.js +7 -4
  78. package/src/server/api/sessions.js +3 -0
  79. package/src/server/api/settings.js +111 -0
  80. package/src/server/api/skills.js +69 -18
  81. package/src/server/api/workspaces.js +78 -6
  82. package/src/server/codex-proxy-server.js +36 -22
  83. package/src/server/dev-server.js +1 -1
  84. package/src/server/gemini-proxy-server.js +21 -7
  85. package/src/server/index.js +174 -58
  86. package/src/server/opencode-proxy-server.js +5486 -0
  87. package/src/server/proxy-server.js +33 -22
  88. package/src/server/services/agents-service.js +61 -24
  89. package/src/server/services/channel-scheduler.js +9 -5
  90. package/src/server/services/channels.js +64 -37
  91. package/src/server/services/codex-channels.js +56 -43
  92. package/src/server/services/codex-sessions.js +105 -6
  93. package/src/server/services/codex-settings-manager.js +271 -49
  94. package/src/server/services/codex-statistics-service.js +2 -2
  95. package/src/server/services/commands-service.js +84 -25
  96. package/src/server/services/config-export-service.js +7 -45
  97. package/src/server/services/config-registry-service.js +63 -17
  98. package/src/server/services/config-sync-manager.js +160 -7
  99. package/src/server/services/config-templates-service.js +204 -51
  100. package/src/server/services/env-checker.js +50 -13
  101. package/src/server/services/env-manager.js +155 -19
  102. package/src/server/services/favorites.js +5 -3
  103. package/src/server/services/gemini-channels.js +33 -44
  104. package/src/server/services/gemini-statistics-service.js +2 -2
  105. package/src/server/services/mcp-service.js +350 -9
  106. package/src/server/services/model-detector.js +707 -221
  107. package/src/server/services/network-access.js +80 -0
  108. package/src/server/services/opencode-channels.js +208 -0
  109. package/src/server/services/opencode-gateway-converter.js +639 -0
  110. package/src/server/services/opencode-sessions.js +931 -0
  111. package/src/server/services/opencode-settings-manager.js +478 -0
  112. package/src/server/services/opencode-statistics-service.js +255 -0
  113. package/src/server/services/plugins-service.js +479 -22
  114. package/src/server/services/prompts-service.js +53 -11
  115. package/src/server/services/proxy-runtime.js +1 -1
  116. package/src/server/services/repo-scanner-base.js +1 -1
  117. package/src/server/services/response-decoder.js +21 -0
  118. package/src/server/services/security-config.js +1 -1
  119. package/src/server/services/session-cache.js +1 -1
  120. package/src/server/services/skill-service.js +300 -46
  121. package/src/server/services/speed-test.js +464 -186
  122. package/src/server/services/statistics-service.js +2 -2
  123. package/src/server/services/terminal-commands.js +10 -3
  124. package/src/server/services/terminal-config.js +1 -1
  125. package/src/server/services/ui-config.js +1 -1
  126. package/src/server/services/workspace-service.js +57 -100
  127. package/src/server/websocket-server.js +156 -8
  128. package/src/ui/menu.js +49 -40
  129. package/src/utils/port-helper.js +22 -8
  130. package/src/utils/session.js +5 -4
  131. package/dist/web/assets/icons-CO_2OFES.js +0 -1
  132. package/dist/web/assets/index-DI8QOi-E.js +0 -14
  133. package/dist/web/assets/index-uLHGdeZh.css +0 -41
  134. package/dist/web/assets/naive-ui-B1re3c-e.js +0 -1
  135. package/dist/web/assets/vue-vendor-6JaYHOiI.js +0 -44
  136. package/src/server/api/oauth.js +0 -294
  137. package/src/server/api/permissions.js +0 -385
  138. package/src/server/config/oauth-providers.js +0 -68
  139. package/src/server/services/oauth-callback-server.js +0 -284
  140. package/src/server/services/oauth-service.js +0 -378
  141. package/src/server/services/oauth-token-storage.js +0 -135
  142. package/src/server/services/permission-templates-service.js +0 -308
@@ -3,9 +3,18 @@ const fs = require('fs');
3
3
  const path = require('path');
4
4
  const os = require('os');
5
5
  const DEFAULT_CONFIG = require('./default');
6
+ const { PATHS, ensureStorageDirMigrated } = require('./paths');
6
7
  const eventBus = require('../plugins/event-bus');
7
8
 
8
- const CONFIG_FILE = path.join(__dirname, '../../config.json');
9
+ const LEGACY_CONFIG_FILES = [
10
+ path.join(__dirname, '../../config.json'),
11
+ path.join(os.homedir(), '.claude', 'config.json')
12
+ ];
13
+
14
+ function getConfigFilePath() {
15
+ ensureStorageDirMigrated();
16
+ return PATHS.configFile;
17
+ }
9
18
 
10
19
  /**
11
20
  * 展开 ~ 为用户主目录
@@ -31,19 +40,66 @@ function mergePricing(defaultPricing, overrides = {}) {
31
40
  return merged;
32
41
  }
33
42
 
43
+ function mergeDefaultModels(defaultModels, overrides = {}) {
44
+ const merged = {};
45
+ Object.keys(defaultModels).forEach((key) => {
46
+ // If user config has this tool type, use it; otherwise use default
47
+ merged[key] = (overrides && overrides[key]) ? overrides[key] : defaultModels[key];
48
+ });
49
+ return merged;
50
+ }
51
+
52
+ function mergeModelDiscovery(defaultModelDiscovery, overrides = {}) {
53
+ return {
54
+ ...defaultModelDiscovery,
55
+ ...(overrides || {})
56
+ };
57
+ }
58
+
59
+ function readJsonFile(filePath) {
60
+ const content = fs.readFileSync(filePath, 'utf8');
61
+ return JSON.parse(content);
62
+ }
63
+
64
+ function migrateLegacyConfigIfNeeded(configFilePath) {
65
+ if (fs.existsSync(configFilePath)) return;
66
+
67
+ for (const legacyPath of LEGACY_CONFIG_FILES) {
68
+ try {
69
+ if (!legacyPath || legacyPath === configFilePath) continue;
70
+ if (!fs.existsSync(legacyPath)) continue;
71
+ const legacyConfig = readJsonFile(legacyPath);
72
+ const dir = path.dirname(configFilePath);
73
+ if (!fs.existsSync(dir)) {
74
+ fs.mkdirSync(dir, { recursive: true });
75
+ }
76
+ fs.writeFileSync(configFilePath, JSON.stringify(legacyConfig, null, 2), 'utf8');
77
+ console.log(`[Config] 已迁移历史配置: ${legacyPath} -> ${configFilePath}`);
78
+ return;
79
+ } catch (error) {
80
+ console.warn(`[Config] 迁移历史配置失败: ${legacyPath}`, error.message);
81
+ }
82
+ }
83
+ }
84
+
34
85
  /**
35
86
  * 加载配置
36
87
  */
37
88
  function loadConfig() {
89
+ const configFilePath = getConfigFilePath();
90
+ migrateLegacyConfigIfNeeded(configFilePath);
91
+
38
92
  try {
39
- if (fs.existsSync(CONFIG_FILE)) {
40
- const userConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
93
+ if (fs.existsSync(configFilePath)) {
94
+ const userConfig = readJsonFile(configFilePath);
41
95
  const config = { ...DEFAULT_CONFIG, ...userConfig };
42
- config.projectsDir = expandHome(config.projectsDir);
96
+ config.projectsDir = expandHome(config.projectsDir || DEFAULT_CONFIG.projectsDir);
43
97
 
44
98
  // 合并 ports 配置
45
99
  config.ports = { ...DEFAULT_CONFIG.ports, ...userConfig.ports };
46
100
  config.pricing = mergePricing(DEFAULT_CONFIG.pricing, userConfig.pricing);
101
+ config.defaultModels = mergeDefaultModels(DEFAULT_CONFIG.defaultModels, userConfig.defaultModels);
102
+ config.modelDiscovery = mergeModelDiscovery(DEFAULT_CONFIG.modelDiscovery, userConfig.modelDiscovery);
47
103
 
48
104
  // 确保有 currentProject,使用 defaultProject 作为 currentProject
49
105
  if (!config.currentProject && config.defaultProject) {
@@ -54,9 +110,13 @@ function loadConfig() {
54
110
  return config;
55
111
  }
56
112
  } catch (error) {
57
- console.error('加载配置文件失败,使用默认配置');
113
+ console.error(`加载配置文件失败,使用默认配置: ${configFilePath}`);
58
114
  }
59
- const defaultConfig = { ...DEFAULT_CONFIG, currentProject: DEFAULT_CONFIG.defaultProject };
115
+ const defaultConfig = {
116
+ ...DEFAULT_CONFIG,
117
+ projectsDir: expandHome(DEFAULT_CONFIG.projectsDir),
118
+ currentProject: DEFAULT_CONFIG.defaultProject
119
+ };
60
120
  eventBus.emitSync('config:loaded', { config: defaultConfig });
61
121
  return defaultConfig;
62
122
  }
@@ -65,11 +125,16 @@ function loadConfig() {
65
125
  * 保存配置
66
126
  */
67
127
  function saveConfig(config) {
128
+ const configFilePath = getConfigFilePath();
68
129
  try {
69
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
130
+ const dir = path.dirname(configFilePath);
131
+ if (!fs.existsSync(dir)) {
132
+ fs.mkdirSync(dir, { recursive: true });
133
+ }
134
+ fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), 'utf8');
70
135
  eventBus.emitSync('config:saved', { config });
71
136
  } catch (error) {
72
- console.error('保存配置失败:', error.message);
137
+ console.error(`保存配置失败 (${configFilePath}):`, error.message);
73
138
  }
74
139
  }
75
140
 
@@ -77,4 +142,5 @@ module.exports = {
77
142
  loadConfig,
78
143
  saveConfig,
79
144
  expandHome,
145
+ getConfigFilePath
80
146
  };
@@ -0,0 +1,415 @@
1
+ /**
2
+ * Centralized Model Metadata Configuration
3
+ *
4
+ * Single source of truth for all mainstream Claude, Codex (OpenAI), and Gemini model metadata.
5
+ * Includes:
6
+ * - limit: context window (tokens) and max output (tokens)
7
+ * - pricing: input/output/cache prices in USD per million tokens
8
+ *
9
+ * Sources (as of 2026-02):
10
+ * - Claude: https://docs.anthropic.com/en/docs/about-claude/models
11
+ * - OpenAI: https://platform.openai.com/docs/models
12
+ * - Gemini: https://ai.google.dev/gemini-api/docs/models
13
+ */
14
+
15
+ const MODEL_METADATA = {
16
+ // ─── Claude 4.6 ───────────────────────────────────────────────────────────
17
+ 'claude-opus-4-6': {
18
+ limit: { context: 200000, output: 32000 },
19
+ pricing: { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.50 }
20
+ },
21
+ 'claude-sonnet-4-6': {
22
+ limit: { context: 200000, output: 64000 },
23
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
24
+ },
25
+ 'claude-haiku-4-6': {
26
+ limit: { context: 200000, output: 8096 },
27
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
28
+ },
29
+
30
+ // ─── Claude 4.5 ───────────────────────────────────────────────────────────
31
+ 'claude-opus-4-5': {
32
+ limit: { context: 200000, output: 32000 },
33
+ pricing: { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.50 }
34
+ },
35
+ 'claude-opus-4-5-20250929': {
36
+ limit: { context: 200000, output: 32000 },
37
+ pricing: { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.50 }
38
+ },
39
+ 'claude-opus-4-5-20251101': {
40
+ limit: { context: 200000, output: 32000 },
41
+ pricing: { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.50 }
42
+ },
43
+ 'claude-sonnet-4-5': {
44
+ limit: { context: 200000, output: 64000 },
45
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
46
+ },
47
+ 'claude-sonnet-4-5-20250929': {
48
+ limit: { context: 200000, output: 64000 },
49
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
50
+ },
51
+ 'claude-haiku-4-5': {
52
+ limit: { context: 200000, output: 8096 },
53
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
54
+ },
55
+ 'claude-haiku-4-5-20250929': {
56
+ limit: { context: 200000, output: 8096 },
57
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
58
+ },
59
+ 'claude-haiku-4-5-20251001': {
60
+ limit: { context: 200000, output: 8096 },
61
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
62
+ },
63
+
64
+ // ─── Claude 4 ─────────────────────────────────────────────────────────────
65
+ 'claude-opus-4': {
66
+ limit: { context: 200000, output: 32000 },
67
+ pricing: { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.50 }
68
+ },
69
+ 'claude-opus-4-20250514': {
70
+ limit: { context: 200000, output: 32000 },
71
+ pricing: { input: 5, output: 25, cacheCreation: 6.25, cacheRead: 0.50 }
72
+ },
73
+ 'claude-sonnet-4': {
74
+ limit: { context: 200000, output: 64000 },
75
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
76
+ },
77
+ 'claude-sonnet-4-20250514': {
78
+ limit: { context: 200000, output: 64000 },
79
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
80
+ },
81
+
82
+ // ─── Claude 3.7 ───────────────────────────────────────────────────────────
83
+ 'claude-sonnet-3-7': {
84
+ limit: { context: 200000, output: 64000 },
85
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
86
+ },
87
+ 'claude-sonnet-3-7-20250219': {
88
+ limit: { context: 200000, output: 64000 },
89
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
90
+ },
91
+
92
+ // ─── Claude 3.5 ───────────────────────────────────────────────────────────
93
+ 'claude-sonnet-3-5': {
94
+ limit: { context: 200000, output: 8096 },
95
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
96
+ },
97
+ 'claude-sonnet-3-5-20241022': {
98
+ limit: { context: 200000, output: 8096 },
99
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
100
+ },
101
+ 'claude-sonnet-3-5-20240620': {
102
+ limit: { context: 200000, output: 8096 },
103
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
104
+ },
105
+ 'claude-3-5-sonnet-20241022': {
106
+ limit: { context: 200000, output: 8096 },
107
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
108
+ },
109
+ 'claude-3-5-sonnet-20240620': {
110
+ limit: { context: 200000, output: 8096 },
111
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
112
+ },
113
+ 'claude-haiku-3-5': {
114
+ limit: { context: 200000, output: 8096 },
115
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
116
+ },
117
+ 'claude-haiku-3-5-20241022': {
118
+ limit: { context: 200000, output: 8096 },
119
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
120
+ },
121
+ 'claude-haiku-3-5-20250307': {
122
+ limit: { context: 200000, output: 8096 },
123
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
124
+ },
125
+ 'claude-3-5-haiku-20241022': {
126
+ limit: { context: 200000, output: 8096 },
127
+ pricing: { input: 1, output: 5, cacheCreation: 1.25, cacheRead: 0.10 }
128
+ },
129
+
130
+ // ─── Claude 3 (legacy) ────────────────────────────────────────────────────
131
+ 'claude-opus-3': {
132
+ limit: { context: 200000, output: 4096 },
133
+ pricing: { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.50 }
134
+ },
135
+ 'claude-opus-3-20240229': {
136
+ limit: { context: 200000, output: 4096 },
137
+ pricing: { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.50 }
138
+ },
139
+ 'claude-3-opus-20240229': {
140
+ limit: { context: 200000, output: 4096 },
141
+ pricing: { input: 15, output: 75, cacheCreation: 18.75, cacheRead: 1.50 }
142
+ },
143
+
144
+ // ─── OpenAI GPT-4o ────────────────────────────────────────────────────────
145
+ 'gpt-4o': {
146
+ limit: { context: 128000, output: 16384 },
147
+ pricing: { input: 2.50, output: 10.00 }
148
+ },
149
+ 'gpt-4o-2024-11-20': {
150
+ limit: { context: 128000, output: 16384 },
151
+ pricing: { input: 2.50, output: 10.00 }
152
+ },
153
+ 'gpt-4o-2024-08-06': {
154
+ limit: { context: 128000, output: 16384 },
155
+ pricing: { input: 2.50, output: 10.00 }
156
+ },
157
+ 'gpt-4o-mini': {
158
+ limit: { context: 128000, output: 16384 },
159
+ pricing: { input: 0.15, output: 0.60 }
160
+ },
161
+ 'gpt-4o-mini-2024-07-18': {
162
+ limit: { context: 128000, output: 16384 },
163
+ pricing: { input: 0.15, output: 0.60 }
164
+ },
165
+ 'gpt-4-turbo': {
166
+ limit: { context: 128000, output: 4096 },
167
+ pricing: { input: 10.00, output: 30.00 }
168
+ },
169
+
170
+ // ─── OpenAI o-series ──────────────────────────────────────────────────────
171
+ 'o1': {
172
+ limit: { context: 200000, output: 100000 },
173
+ pricing: { input: 15.00, output: 60.00 }
174
+ },
175
+ 'o1-2024-12-17': {
176
+ limit: { context: 200000, output: 100000 },
177
+ pricing: { input: 15.00, output: 60.00 }
178
+ },
179
+ 'o1-mini': {
180
+ limit: { context: 128000, output: 65536 },
181
+ pricing: { input: 1.10, output: 4.40 }
182
+ },
183
+ 'o1-mini-2024-09-12': {
184
+ limit: { context: 128000, output: 65536 },
185
+ pricing: { input: 1.10, output: 4.40 }
186
+ },
187
+ 'o3': {
188
+ limit: { context: 200000, output: 100000 },
189
+ pricing: { input: 10.00, output: 40.00 }
190
+ },
191
+ 'o3-mini': {
192
+ limit: { context: 200000, output: 100000 },
193
+ pricing: { input: 1.10, output: 4.40 }
194
+ },
195
+ 'o3-mini-2025-01-31': {
196
+ limit: { context: 200000, output: 100000 },
197
+ pricing: { input: 1.10, output: 4.40 }
198
+ },
199
+ 'o4-mini': {
200
+ limit: { context: 200000, output: 100000 },
201
+ pricing: { input: 1.10, output: 4.40 }
202
+ },
203
+
204
+ // ─── OpenAI GPT-5 / Codex ─────────────────────────────────────────────────
205
+ 'gpt-5': {
206
+ limit: { context: 1000000, output: 32768 },
207
+ pricing: { input: 2.00, output: 8.00 }
208
+ },
209
+ 'gpt-5.1': {
210
+ limit: { context: 1000000, output: 32768 },
211
+ pricing: { input: 2.00, output: 8.00 }
212
+ },
213
+ 'gpt-5.2': {
214
+ limit: { context: 1000000, output: 32768 },
215
+ pricing: { input: 2.00, output: 8.00 }
216
+ },
217
+ 'gpt-5-codex': {
218
+ limit: { context: 1000000, output: 32768 },
219
+ pricing: { input: 2.00, output: 8.00 }
220
+ },
221
+ 'gpt-5.1-codex': {
222
+ limit: { context: 1000000, output: 32768 },
223
+ pricing: { input: 2.00, output: 8.00 }
224
+ },
225
+ 'gpt-5.1-codex-mini': {
226
+ limit: { context: 1000000, output: 32768 },
227
+ pricing: { input: 1.50, output: 6.00 }
228
+ },
229
+ 'gpt-5.1-codex-max': {
230
+ limit: { context: 1000000, output: 32768 },
231
+ pricing: { input: 3.00, output: 12.00 }
232
+ },
233
+ 'gpt-5.2-codex': {
234
+ limit: { context: 1000000, output: 32768 },
235
+ pricing: { input: 2.00, output: 8.00 }
236
+ },
237
+ 'gpt-5.3-codex': {
238
+ limit: { context: 1000000, output: 32768 },
239
+ pricing: { input: 2.00, output: 8.00 }
240
+ },
241
+
242
+ // ─── Gemini 2.5 ───────────────────────────────────────────────────────────
243
+ 'gemini-2.5-pro': {
244
+ limit: { context: 1048576, output: 65536 },
245
+ pricing: { input: 1.25, output: 10.00 }
246
+ },
247
+ 'gemini-2.5-pro-preview': {
248
+ limit: { context: 1048576, output: 65536 },
249
+ pricing: { input: 1.25, output: 10.00 }
250
+ },
251
+ 'gemini-2.5-pro-exp-03-25': {
252
+ limit: { context: 1048576, output: 65536 },
253
+ pricing: { input: 1.25, output: 10.00 }
254
+ },
255
+ 'gemini-2.5-flash': {
256
+ limit: { context: 1048576, output: 65536 },
257
+ pricing: { input: 0.15, output: 0.60 }
258
+ },
259
+ 'gemini-2.5-flash-preview': {
260
+ limit: { context: 1048576, output: 65536 },
261
+ pricing: { input: 0.15, output: 0.60 }
262
+ },
263
+ 'gemini-2.5-flash-lite': {
264
+ limit: { context: 1048576, output: 65536 },
265
+ pricing: { input: 0.10, output: 0.40 }
266
+ },
267
+
268
+ // ─── Gemini 2.0 ───────────────────────────────────────────────────────────
269
+ 'gemini-2.0-flash': {
270
+ limit: { context: 1048576, output: 8192 },
271
+ pricing: { input: 0.10, output: 0.40 }
272
+ },
273
+ 'gemini-2.0-flash-exp': {
274
+ limit: { context: 1048576, output: 8192 },
275
+ pricing: { input: 0.10, output: 0.40 }
276
+ },
277
+ 'gemini-2.0-flash-lite': {
278
+ limit: { context: 1048576, output: 8192 },
279
+ pricing: { input: 0.075, output: 0.30 }
280
+ },
281
+
282
+ // ─── Gemini 1.5 ───────────────────────────────────────────────────────────
283
+ 'gemini-1.5-pro': {
284
+ limit: { context: 2097152, output: 8192 },
285
+ pricing: { input: 1.25, output: 5.00 }
286
+ },
287
+ 'gemini-1.5-pro-002': {
288
+ limit: { context: 2097152, output: 8192 },
289
+ pricing: { input: 1.25, output: 5.00 }
290
+ },
291
+ 'gemini-1.5-flash': {
292
+ limit: { context: 1048576, output: 8192 },
293
+ pricing: { input: 0.075, output: 0.30 }
294
+ },
295
+ 'gemini-1.5-flash-002': {
296
+ limit: { context: 1048576, output: 8192 },
297
+ pricing: { input: 0.075, output: 0.30 }
298
+ },
299
+ 'gemini-1.5-flash-8b': {
300
+ limit: { context: 1048576, output: 8192 },
301
+ pricing: { input: 0.0375, output: 0.15 }
302
+ },
303
+
304
+ // ─── Gemini 3 (future/preview) ────────────────────────────────────────────
305
+ 'gemini-3-pro-preview': {
306
+ limit: { context: 2097152, output: 65536 },
307
+ pricing: { input: 2.50, output: 15.00 }
308
+ },
309
+ 'gemini-3.1-pro': {
310
+ limit: { context: 2097152, output: 65536 },
311
+ pricing: { input: 2.50, output: 15.00 }
312
+ },
313
+ 'gemini-3-flash-preview': {
314
+ limit: { context: 1048576, output: 65536 },
315
+ pricing: { input: 0.30, output: 1.20 }
316
+ }
317
+ };
318
+
319
+ /**
320
+ * Model aliases: short name → canonical model ID
321
+ * Used for prefix/alias lookups
322
+ */
323
+ const MODEL_ALIASES = {
324
+ // Claude aliases
325
+ 'claude-opus-4-6': 'claude-opus-4-6',
326
+ 'claude-sonnet-4-6': 'claude-sonnet-4-6',
327
+ 'claude-haiku-4-6': 'claude-haiku-4-6',
328
+ 'claude-opus-4-5': 'claude-opus-4-5-20250929',
329
+ 'claude-sonnet-4-5': 'claude-sonnet-4-5-20250929',
330
+ 'claude-haiku-4-5': 'claude-haiku-4-5-20250929',
331
+ 'claude-opus-4': 'claude-opus-4-20250514',
332
+ 'claude-sonnet-4': 'claude-sonnet-4-20250514',
333
+ 'claude-sonnet-3-7': 'claude-sonnet-3-7-20250219',
334
+ 'claude-haiku-3-5': 'claude-haiku-3-5-20241022',
335
+ 'claude-sonnet-3-5': 'claude-sonnet-3-5-20241022',
336
+ 'claude-opus-3': 'claude-opus-3-20240229'
337
+ };
338
+
339
+ /**
340
+ * Resolve model metadata (limit + pricing) for a given model ID.
341
+ * Supports: exact match → alias match → prefix match → generic Claude fallback
342
+ *
343
+ * @param {string} modelId
344
+ * @returns {{ limit: {context, output}, pricing: {input, output, cacheCreation?, cacheRead?} } | null}
345
+ */
346
+ function resolveModelMetadata(modelId) {
347
+ if (!modelId) return null;
348
+ const id = String(modelId).toLowerCase().trim();
349
+
350
+ // Exact match
351
+ for (const [key, meta] of Object.entries(MODEL_METADATA)) {
352
+ if (id === key.toLowerCase()) return meta;
353
+ }
354
+
355
+ // Alias match → canonical
356
+ for (const [alias, canonical] of Object.entries(MODEL_ALIASES)) {
357
+ if (id === alias.toLowerCase()) {
358
+ const meta = MODEL_METADATA[canonical];
359
+ if (meta) return meta;
360
+ }
361
+ }
362
+
363
+ // Prefix match (e.g. "claude-sonnet-4-6-xxx" matches "claude-sonnet-4-6")
364
+ for (const [key, meta] of Object.entries(MODEL_METADATA)) {
365
+ if (id.startsWith(key.toLowerCase())) return meta;
366
+ }
367
+
368
+ // Generic fallback for unknown Claude models
369
+ if (id.startsWith('claude-')) {
370
+ return {
371
+ limit: { context: 200000, output: 32000 },
372
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.30 }
373
+ };
374
+ }
375
+
376
+ return null;
377
+ }
378
+
379
+ /**
380
+ * Get just the limit (context + output) for a model.
381
+ * @param {string} modelId
382
+ * @returns {{ context: number, output: number } | null}
383
+ */
384
+ function resolveModelLimit(modelId) {
385
+ const meta = resolveModelMetadata(modelId);
386
+ return meta ? meta.limit : null;
387
+ }
388
+
389
+ /**
390
+ * Get just the pricing for a model.
391
+ * @param {string} modelId
392
+ * @returns {{ input: number, output: number, cacheCreation?: number, cacheRead?: number } | null}
393
+ */
394
+ function resolveModelPricing(modelId) {
395
+ const meta = resolveModelMetadata(modelId);
396
+ return meta ? meta.pricing : null;
397
+ }
398
+
399
+ /**
400
+ * Get all model IDs in the metadata table.
401
+ * @returns {string[]}
402
+ */
403
+ function getAllModelIds() {
404
+ return Object.keys(MODEL_METADATA);
405
+ }
406
+
407
+ module.exports = {
408
+ MODEL_METADATA,
409
+ MODEL_ALIASES,
410
+ resolveModelMetadata,
411
+ resolveModelLimit,
412
+ resolveModelPricing,
413
+ getAllModelIds,
414
+ METADATA_LAST_UPDATED: '2026-02-27'
415
+ };
@@ -1,105 +1,35 @@
1
1
  /**
2
- * Centralized Claude Model Pricing
2
+ * Claude Model Pricing - Backward Compatibility Re-export
3
3
  *
4
- * Official Anthropic pricing as of 2026-02-02
5
- * Source: https://claude.com/pricing
6
- *
7
- * All prices in USD per million tokens
4
+ * This file re-exports Claude-specific pricing and aliases from the centralized
5
+ * model-metadata.js config. Use model-metadata.js directly for new code.
8
6
  */
9
7
 
10
- const CLAUDE_MODEL_PRICING = {
11
- // Claude 4.5 (current generation)
12
- 'claude-opus-4-5-20250929': {
13
- input: 5,
14
- output: 25,
15
- cacheCreation: 6.25,
16
- cacheRead: 0.50
17
- },
18
- 'claude-sonnet-4-5-20250929': {
19
- input: 3,
20
- output: 15,
21
- cacheCreation: 3.75,
22
- cacheRead: 0.30
23
- },
24
- 'claude-haiku-4-5-20250929': {
25
- input: 1,
26
- output: 5,
27
- cacheCreation: 1.25,
28
- cacheRead: 0.10
29
- },
30
-
31
- // Claude 4 (previous generation)
32
- 'claude-opus-4-20250514': {
33
- input: 5,
34
- output: 25,
35
- cacheCreation: 6.25,
36
- cacheRead: 0.50
37
- },
38
- 'claude-sonnet-4-20250514': {
39
- input: 3,
40
- output: 15,
41
- cacheCreation: 3.75,
42
- cacheRead: 0.30
43
- },
8
+ const { MODEL_METADATA, MODEL_ALIASES, METADATA_LAST_UPDATED } = require('./model-metadata');
44
9
 
45
- // Claude 3.5
46
- 'claude-haiku-3-5-20241022': {
47
- input: 1,
48
- output: 5,
49
- cacheCreation: 1.25,
50
- cacheRead: 0.10
51
- },
52
- 'claude-3-5-haiku-20241022': {
53
- input: 1,
54
- output: 5,
55
- cacheCreation: 1.25,
56
- cacheRead: 0.10
57
- },
58
- 'claude-sonnet-3-5-20241022': {
59
- input: 3,
60
- output: 15,
61
- cacheCreation: 3.75,
62
- cacheRead: 0.30
63
- },
64
- 'claude-sonnet-3-5-20240620': {
65
- input: 3,
66
- output: 15,
67
- cacheCreation: 3.75,
68
- cacheRead: 0.30
69
- },
70
-
71
- // Claude 3 (legacy)
72
- 'claude-opus-3-20240229': {
73
- input: 15,
74
- output: 75,
75
- cacheCreation: 18.75,
76
- cacheRead: 1.50
77
- },
78
- 'claude-3-opus-20240229': {
79
- input: 15,
80
- output: 75,
81
- cacheCreation: 18.75,
82
- cacheRead: 1.50
10
+ // Build CLAUDE_MODEL_PRICING from centralized metadata (Claude models only)
11
+ const CLAUDE_MODEL_PRICING = {};
12
+ for (const [id, meta] of Object.entries(MODEL_METADATA)) {
13
+ if (id.startsWith('claude-') && meta.pricing) {
14
+ CLAUDE_MODEL_PRICING[id] = {
15
+ input: meta.pricing.input,
16
+ output: meta.pricing.output,
17
+ cacheCreation: meta.pricing.cacheCreation,
18
+ cacheRead: meta.pricing.cacheRead
19
+ };
83
20
  }
84
- };
21
+ }
85
22
 
86
- /**
87
- * Model name aliases for normalization
88
- * Maps short names to full model identifiers
89
- */
90
- const CLAUDE_MODEL_ALIASES = {
91
- 'claude-opus-4-5': 'claude-opus-4-5-20250929',
92
- 'claude-sonnet-4-5': 'claude-sonnet-4-5-20250929',
93
- 'claude-haiku-4-5': 'claude-haiku-4-5-20250929',
94
- 'claude-opus-4': 'claude-opus-4-20250514',
95
- 'claude-sonnet-4': 'claude-sonnet-4-20250514',
96
- 'claude-haiku-3-5': 'claude-haiku-3-5-20241022',
97
- 'claude-sonnet-3-5': 'claude-sonnet-3-5-20241022',
98
- 'claude-opus-3': 'claude-opus-3-20240229'
99
- };
23
+ // Build CLAUDE_MODEL_ALIASES from centralized aliases (Claude models only)
24
+ const CLAUDE_MODEL_ALIASES = {};
25
+ for (const [alias, canonical] of Object.entries(MODEL_ALIASES)) {
26
+ if (alias.startsWith('claude-')) {
27
+ CLAUDE_MODEL_ALIASES[alias] = canonical;
28
+ }
29
+ }
100
30
 
101
31
  module.exports = {
102
32
  CLAUDE_MODEL_PRICING,
103
33
  CLAUDE_MODEL_ALIASES,
104
- PRICING_LAST_UPDATED: '2026-02-02'
34
+ PRICING_LAST_UPDATED: METADATA_LAST_UPDATED
105
35
  };