coding-tool-x 3.2.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.
Files changed (185) hide show
  1. package/CHANGELOG.md +599 -0
  2. package/LICENSE +21 -0
  3. package/README.md +439 -0
  4. package/bin/ctx.js +8 -0
  5. package/dist/web/assets/Analytics-DN_YsnkW.js +39 -0
  6. package/dist/web/assets/Analytics-DuYvId7u.css +1 -0
  7. package/dist/web/assets/ConfigTemplates-Bidwfdf2.css +1 -0
  8. package/dist/web/assets/ConfigTemplates-DpXIMy0p.js +1 -0
  9. package/dist/web/assets/Home-38JTUlYt.js +1 -0
  10. package/dist/web/assets/Home-CjupSEWE.css +1 -0
  11. package/dist/web/assets/PluginManager-CX2tgq2H.js +1 -0
  12. package/dist/web/assets/PluginManager-ROyoZ-6m.css +1 -0
  13. package/dist/web/assets/ProjectList-C1lDcsn6.js +1 -0
  14. package/dist/web/assets/ProjectList-oJIyIRkP.css +1 -0
  15. package/dist/web/assets/SessionList-C55tjV7i.css +1 -0
  16. package/dist/web/assets/SessionList-CZ7T6rVx.js +1 -0
  17. package/dist/web/assets/SkillManager-D7pd-d_P.css +1 -0
  18. package/dist/web/assets/SkillManager-DLN9f79y.js +1 -0
  19. package/dist/web/assets/WorkspaceManager-CrwgQgmP.css +1 -0
  20. package/dist/web/assets/WorkspaceManager-DxlHZkpZ.js +1 -0
  21. package/dist/web/assets/icons-DRrXwWZi.js +1 -0
  22. package/dist/web/assets/index-CetESrXw.css +1 -0
  23. package/dist/web/assets/index-Cfvn-2Gb.js +2 -0
  24. package/dist/web/assets/markdown-BfC0goYb.css +10 -0
  25. package/dist/web/assets/markdown-C9MYpaSi.js +1 -0
  26. package/dist/web/assets/naive-ui-DlpKk-8M.js +1 -0
  27. package/dist/web/assets/vendors-DMjSfzlv.js +7 -0
  28. package/dist/web/assets/vue-vendor-DET08QYg.js +45 -0
  29. package/dist/web/favicon.ico +0 -0
  30. package/dist/web/index.html +20 -0
  31. package/dist/web/logo.png +0 -0
  32. package/docs/bannel.png +0 -0
  33. package/docs/home.png +0 -0
  34. package/docs/logo.png +0 -0
  35. package/docs/model-redirection.md +251 -0
  36. package/docs/multi-channel-load-balancing.md +249 -0
  37. package/package.json +80 -0
  38. package/src/commands/channels.js +551 -0
  39. package/src/commands/cli-type.js +101 -0
  40. package/src/commands/daemon.js +365 -0
  41. package/src/commands/doctor.js +333 -0
  42. package/src/commands/export-config.js +205 -0
  43. package/src/commands/list.js +222 -0
  44. package/src/commands/logs.js +261 -0
  45. package/src/commands/plugin.js +585 -0
  46. package/src/commands/port-config.js +135 -0
  47. package/src/commands/proxy-control.js +264 -0
  48. package/src/commands/proxy.js +152 -0
  49. package/src/commands/resume.js +137 -0
  50. package/src/commands/search.js +190 -0
  51. package/src/commands/security.js +37 -0
  52. package/src/commands/stats.js +398 -0
  53. package/src/commands/switch.js +48 -0
  54. package/src/commands/toggle-proxy.js +247 -0
  55. package/src/commands/ui.js +99 -0
  56. package/src/commands/update.js +97 -0
  57. package/src/commands/workspace.js +454 -0
  58. package/src/config/default.js +69 -0
  59. package/src/config/loader.js +149 -0
  60. package/src/config/model-metadata.js +167 -0
  61. package/src/config/model-metadata.json +125 -0
  62. package/src/config/model-pricing.js +35 -0
  63. package/src/config/paths.js +190 -0
  64. package/src/index.js +680 -0
  65. package/src/plugins/constants.js +15 -0
  66. package/src/plugins/event-bus.js +54 -0
  67. package/src/plugins/manifest-validator.js +129 -0
  68. package/src/plugins/plugin-api.js +128 -0
  69. package/src/plugins/plugin-installer.js +601 -0
  70. package/src/plugins/plugin-loader.js +229 -0
  71. package/src/plugins/plugin-manager.js +170 -0
  72. package/src/plugins/registry.js +152 -0
  73. package/src/plugins/schema/plugin-manifest.json +115 -0
  74. package/src/reset-config.js +94 -0
  75. package/src/server/api/agents.js +826 -0
  76. package/src/server/api/aliases.js +36 -0
  77. package/src/server/api/channels.js +368 -0
  78. package/src/server/api/claude-hooks.js +480 -0
  79. package/src/server/api/codex-channels.js +417 -0
  80. package/src/server/api/codex-projects.js +104 -0
  81. package/src/server/api/codex-proxy.js +195 -0
  82. package/src/server/api/codex-sessions.js +483 -0
  83. package/src/server/api/codex-statistics.js +57 -0
  84. package/src/server/api/commands.js +482 -0
  85. package/src/server/api/config-export.js +212 -0
  86. package/src/server/api/config-registry.js +357 -0
  87. package/src/server/api/config-sync.js +155 -0
  88. package/src/server/api/config-templates.js +248 -0
  89. package/src/server/api/config.js +521 -0
  90. package/src/server/api/convert.js +260 -0
  91. package/src/server/api/dashboard.js +142 -0
  92. package/src/server/api/env.js +144 -0
  93. package/src/server/api/favorites.js +77 -0
  94. package/src/server/api/gemini-channels.js +366 -0
  95. package/src/server/api/gemini-projects.js +91 -0
  96. package/src/server/api/gemini-proxy.js +173 -0
  97. package/src/server/api/gemini-sessions.js +376 -0
  98. package/src/server/api/gemini-statistics.js +57 -0
  99. package/src/server/api/health-check.js +31 -0
  100. package/src/server/api/mcp.js +399 -0
  101. package/src/server/api/opencode-channels.js +419 -0
  102. package/src/server/api/opencode-projects.js +99 -0
  103. package/src/server/api/opencode-proxy.js +207 -0
  104. package/src/server/api/opencode-sessions.js +327 -0
  105. package/src/server/api/opencode-statistics.js +57 -0
  106. package/src/server/api/plugins.js +463 -0
  107. package/src/server/api/pm2-autostart.js +269 -0
  108. package/src/server/api/projects.js +124 -0
  109. package/src/server/api/prompts.js +279 -0
  110. package/src/server/api/proxy.js +306 -0
  111. package/src/server/api/security.js +53 -0
  112. package/src/server/api/sessions.js +514 -0
  113. package/src/server/api/settings.js +142 -0
  114. package/src/server/api/skills.js +570 -0
  115. package/src/server/api/statistics.js +238 -0
  116. package/src/server/api/ui-config.js +64 -0
  117. package/src/server/api/workspaces.js +456 -0
  118. package/src/server/codex-proxy-server.js +681 -0
  119. package/src/server/dev-server.js +26 -0
  120. package/src/server/gemini-proxy-server.js +610 -0
  121. package/src/server/index.js +422 -0
  122. package/src/server/opencode-proxy-server.js +4771 -0
  123. package/src/server/proxy-server.js +669 -0
  124. package/src/server/services/agents-service.js +1137 -0
  125. package/src/server/services/alias.js +71 -0
  126. package/src/server/services/channel-health.js +234 -0
  127. package/src/server/services/channel-scheduler.js +240 -0
  128. package/src/server/services/channels.js +447 -0
  129. package/src/server/services/codex-channels.js +705 -0
  130. package/src/server/services/codex-config.js +90 -0
  131. package/src/server/services/codex-parser.js +322 -0
  132. package/src/server/services/codex-sessions.js +936 -0
  133. package/src/server/services/codex-settings-manager.js +619 -0
  134. package/src/server/services/codex-speed-test-template.json +24 -0
  135. package/src/server/services/codex-statistics-service.js +161 -0
  136. package/src/server/services/commands-service.js +574 -0
  137. package/src/server/services/config-export-service.js +1165 -0
  138. package/src/server/services/config-registry-service.js +828 -0
  139. package/src/server/services/config-sync-manager.js +941 -0
  140. package/src/server/services/config-sync-service.js +504 -0
  141. package/src/server/services/config-templates-service.js +913 -0
  142. package/src/server/services/enhanced-cache.js +196 -0
  143. package/src/server/services/env-checker.js +409 -0
  144. package/src/server/services/env-manager.js +436 -0
  145. package/src/server/services/favorites.js +165 -0
  146. package/src/server/services/format-converter.js +620 -0
  147. package/src/server/services/gemini-channels.js +459 -0
  148. package/src/server/services/gemini-config.js +73 -0
  149. package/src/server/services/gemini-sessions.js +689 -0
  150. package/src/server/services/gemini-settings-manager.js +263 -0
  151. package/src/server/services/gemini-statistics-service.js +157 -0
  152. package/src/server/services/health-check.js +85 -0
  153. package/src/server/services/mcp-client.js +790 -0
  154. package/src/server/services/mcp-service.js +1732 -0
  155. package/src/server/services/model-detector.js +1245 -0
  156. package/src/server/services/network-access.js +80 -0
  157. package/src/server/services/opencode-channels.js +366 -0
  158. package/src/server/services/opencode-gateway-adapters.js +1168 -0
  159. package/src/server/services/opencode-gateway-converter.js +639 -0
  160. package/src/server/services/opencode-sessions.js +931 -0
  161. package/src/server/services/opencode-settings-manager.js +478 -0
  162. package/src/server/services/opencode-statistics-service.js +161 -0
  163. package/src/server/services/plugins-service.js +1268 -0
  164. package/src/server/services/prompts-service.js +534 -0
  165. package/src/server/services/proxy-runtime.js +79 -0
  166. package/src/server/services/repo-scanner-base.js +708 -0
  167. package/src/server/services/request-logger.js +130 -0
  168. package/src/server/services/response-decoder.js +21 -0
  169. package/src/server/services/security-config.js +131 -0
  170. package/src/server/services/session-cache.js +127 -0
  171. package/src/server/services/session-converter.js +577 -0
  172. package/src/server/services/sessions.js +900 -0
  173. package/src/server/services/settings-manager.js +163 -0
  174. package/src/server/services/skill-service.js +1482 -0
  175. package/src/server/services/speed-test.js +1146 -0
  176. package/src/server/services/statistics-service.js +1043 -0
  177. package/src/server/services/ui-config.js +132 -0
  178. package/src/server/services/workspace-service.js +830 -0
  179. package/src/server/utils/pricing.js +73 -0
  180. package/src/server/websocket-server.js +513 -0
  181. package/src/ui/menu.js +139 -0
  182. package/src/ui/prompts.js +100 -0
  183. package/src/utils/format.js +43 -0
  184. package/src/utils/port-helper.js +108 -0
  185. package/src/utils/session.js +240 -0
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Model metadata runtime helpers.
3
+ * Data source: ./model-metadata.json
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const metadataConfig = require('./model-metadata.json');
9
+ const METADATA_FILE_PATH = path.join(__dirname, 'model-metadata.json');
10
+
11
+ const MODEL_METADATA = metadataConfig.models || {};
12
+ const MODEL_ALIASES = metadataConfig.aliases || {};
13
+ const DEFAULT_MODELS = metadataConfig.defaultModels || { claude: [], codex: [], gemini: [] };
14
+ const DEFAULT_SPEED_TEST_MODELS = metadataConfig.defaultSpeedTestModels || {
15
+ claude: 'claude-haiku-4-5',
16
+ codex: 'gpt-5.2',
17
+ gemini: 'gemini-2.5-pro'
18
+ };
19
+
20
+ function normalizeNonEmptyString(value) {
21
+ if (typeof value !== 'string') return null;
22
+ const trimmed = value.trim();
23
+ return trimmed || null;
24
+ }
25
+
26
+ function loadMetadataConfigFromFile() {
27
+ try {
28
+ const raw = fs.readFileSync(METADATA_FILE_PATH, 'utf8');
29
+ const parsed = JSON.parse(raw);
30
+ if (parsed && typeof parsed === 'object') {
31
+ return parsed;
32
+ }
33
+ } catch (error) {
34
+ console.warn(`[model-metadata] Failed to read metadata file, fallback to in-memory config: ${error.message}`);
35
+ }
36
+ return metadataConfig;
37
+ }
38
+
39
+ /**
40
+ * Resolve model metadata (limit + pricing) for a given model ID.
41
+ * Supports: exact match -> alias match -> prefix match -> generic Claude fallback
42
+ *
43
+ * @param {string} modelId
44
+ * @returns {{ limit: {context, output}, pricing: {input, output, cacheCreation?, cacheRead?} } | null}
45
+ */
46
+ function resolveModelMetadata(modelId) {
47
+ if (!modelId) return null;
48
+ const id = String(modelId).toLowerCase().trim();
49
+
50
+ // Exact match
51
+ for (const [key, meta] of Object.entries(MODEL_METADATA)) {
52
+ if (id === key.toLowerCase()) return meta;
53
+ }
54
+
55
+ // Alias match -> canonical
56
+ for (const [alias, canonical] of Object.entries(MODEL_ALIASES)) {
57
+ if (id === alias.toLowerCase()) {
58
+ const meta = MODEL_METADATA[canonical];
59
+ if (meta) return meta;
60
+ }
61
+ }
62
+
63
+ // Prefix match
64
+ for (const [key, meta] of Object.entries(MODEL_METADATA)) {
65
+ if (id.startsWith(key.toLowerCase())) return meta;
66
+ }
67
+
68
+ // Generic fallback for unknown Claude models
69
+ if (id.startsWith('claude-')) {
70
+ return {
71
+ limit: { context: 200000, output: 32000 },
72
+ pricing: { input: 3, output: 15, cacheCreation: 3.75, cacheRead: 0.3 }
73
+ };
74
+ }
75
+
76
+ return null;
77
+ }
78
+
79
+ function resolveModelLimit(modelId) {
80
+ const meta = resolveModelMetadata(modelId);
81
+ return meta ? meta.limit : null;
82
+ }
83
+
84
+ function resolveModelPricing(modelId) {
85
+ const meta = resolveModelMetadata(modelId);
86
+ return meta ? meta.pricing : null;
87
+ }
88
+
89
+ function getAllModelIds() {
90
+ return Object.keys(MODEL_METADATA);
91
+ }
92
+
93
+ function getDefaultModels() {
94
+ return {
95
+ claude: [...(DEFAULT_MODELS.claude || [])],
96
+ codex: [...(DEFAULT_MODELS.codex || [])],
97
+ gemini: [...(DEFAULT_MODELS.gemini || [])]
98
+ };
99
+ }
100
+
101
+ function getDefaultModelsByToolType(toolType) {
102
+ const key = String(toolType || '').trim().toLowerCase();
103
+ if (key === 'openai_compatible') return [...(DEFAULT_MODELS.codex || [])];
104
+ if (key === 'claude' || key === 'codex' || key === 'gemini') {
105
+ return [...(DEFAULT_MODELS[key] || [])];
106
+ }
107
+ return [];
108
+ }
109
+
110
+ function getDefaultSpeedTestModels() {
111
+ const fileConfig = loadMetadataConfigFromFile();
112
+ const raw = fileConfig.defaultSpeedTestModels || DEFAULT_SPEED_TEST_MODELS;
113
+ return {
114
+ claude: normalizeNonEmptyString(raw.claude) || DEFAULT_SPEED_TEST_MODELS.claude,
115
+ codex: normalizeNonEmptyString(raw.codex) || DEFAULT_SPEED_TEST_MODELS.codex,
116
+ gemini: normalizeNonEmptyString(raw.gemini) || DEFAULT_SPEED_TEST_MODELS.gemini
117
+ };
118
+ }
119
+
120
+ function getDefaultSpeedTestModelByToolType(toolType) {
121
+ const key = String(toolType || '').trim().toLowerCase();
122
+ const defaults = getDefaultSpeedTestModels();
123
+ if (key === 'openai_compatible') return defaults.codex;
124
+ if (key === 'claude' || key === 'codex' || key === 'gemini') {
125
+ return defaults[key];
126
+ }
127
+ return defaults.codex;
128
+ }
129
+
130
+ function saveDefaultSpeedTestModels(nextDefaults) {
131
+ const current = loadMetadataConfigFromFile();
132
+ const merged = {
133
+ ...getDefaultSpeedTestModels(),
134
+ ...(nextDefaults || {})
135
+ };
136
+
137
+ const normalized = {
138
+ claude: normalizeNonEmptyString(merged.claude) || DEFAULT_SPEED_TEST_MODELS.claude,
139
+ codex: normalizeNonEmptyString(merged.codex) || DEFAULT_SPEED_TEST_MODELS.codex,
140
+ gemini: normalizeNonEmptyString(merged.gemini) || DEFAULT_SPEED_TEST_MODELS.gemini
141
+ };
142
+
143
+ const nextConfig = {
144
+ ...current,
145
+ defaultSpeedTestModels: normalized
146
+ };
147
+ fs.writeFileSync(METADATA_FILE_PATH, `${JSON.stringify(nextConfig, null, 2)}\n`, 'utf8');
148
+ metadataConfig.defaultSpeedTestModels = normalized;
149
+ return normalized;
150
+ }
151
+
152
+ module.exports = {
153
+ MODEL_METADATA,
154
+ MODEL_ALIASES,
155
+ DEFAULT_MODELS,
156
+ DEFAULT_SPEED_TEST_MODELS,
157
+ resolveModelMetadata,
158
+ resolveModelLimit,
159
+ resolveModelPricing,
160
+ getAllModelIds,
161
+ getDefaultModels,
162
+ getDefaultModelsByToolType,
163
+ getDefaultSpeedTestModels,
164
+ getDefaultSpeedTestModelByToolType,
165
+ saveDefaultSpeedTestModels,
166
+ METADATA_LAST_UPDATED: metadataConfig.lastUpdated || '2026-02-27'
167
+ };
@@ -0,0 +1,125 @@
1
+ {
2
+ "lastUpdated": "2026-02-27",
3
+ "defaultModels": {
4
+ "claude": [
5
+ "claude-opus-4-6",
6
+ "claude-sonnet-4-6",
7
+ "claude-opus-4-5-20251101",
8
+ "claude-sonnet-4-5-20250929",
9
+ "claude-haiku-4-5-20251001"
10
+ ],
11
+ "codex": [
12
+ "gpt-5.3-codex",
13
+ "gpt-5.2-codex",
14
+ "gpt-5.1-codex-max",
15
+ "gpt-5.1-codex",
16
+ "gpt-5.1-codex-mini",
17
+ "gpt-5-codex",
18
+ "gpt-5.2",
19
+ "gpt-5.1",
20
+ "gpt-5"
21
+ ],
22
+ "gemini": [
23
+ "gemini-3.1-pro",
24
+ "gemini-3-pro-preview",
25
+ "gemini-3-flash-preview",
26
+ "gemini-2.5-pro",
27
+ "gemini-2.5-flash",
28
+ "gemini-2.5-flash-lite"
29
+ ]
30
+ },
31
+ "defaultSpeedTestModels": {
32
+ "claude": "claude-haiku-4-5",
33
+ "codex": "gpt-5.2",
34
+ "gemini": "gemini-2.5-pro"
35
+ },
36
+ "aliases": {
37
+ "claude-opus-4-6": "claude-opus-4-6",
38
+ "claude-sonnet-4-6": "claude-sonnet-4-6",
39
+ "claude-opus-4-5": "claude-opus-4-5-20251101",
40
+ "claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
41
+ "claude-haiku-4-5": "claude-haiku-4-5-20251001"
42
+ },
43
+ "models": {
44
+ "claude-opus-4-6": {
45
+ "limit": { "context": 200000, "output": 32000 },
46
+ "pricing": { "input": 15, "output": 75, "cacheCreation": 18.75, "cacheRead": 1.5 }
47
+ },
48
+ "claude-sonnet-4-6": {
49
+ "limit": { "context": 200000, "output": 64000 },
50
+ "pricing": { "input": 3, "output": 15, "cacheCreation": 3.75, "cacheRead": 0.3 }
51
+ },
52
+ "claude-opus-4-5-20251101": {
53
+ "limit": { "context": 200000, "output": 32000 },
54
+ "pricing": { "input": 5, "output": 25, "cacheCreation": 6.25, "cacheRead": 0.5 }
55
+ },
56
+ "claude-sonnet-4-5-20250929": {
57
+ "limit": { "context": 200000, "output": 64000 },
58
+ "pricing": { "input": 3, "output": 15, "cacheCreation": 3.75, "cacheRead": 0.3 }
59
+ },
60
+ "claude-haiku-4-5-20251001": {
61
+ "limit": { "context": 200000, "output": 8096 },
62
+ "pricing": { "input": 1, "output": 5, "cacheCreation": 1.25, "cacheRead": 0.1 }
63
+ },
64
+ "gpt-5": {
65
+ "limit": { "context": 1000000, "output": 32768 },
66
+ "pricing": { "input": 2, "output": 8 }
67
+ },
68
+ "gpt-5.1": {
69
+ "limit": { "context": 1000000, "output": 32768 },
70
+ "pricing": { "input": 2, "output": 8 }
71
+ },
72
+ "gpt-5.2": {
73
+ "limit": { "context": 1000000, "output": 32768 },
74
+ "pricing": { "input": 2, "output": 8 }
75
+ },
76
+ "gpt-5-codex": {
77
+ "limit": { "context": 1000000, "output": 32768 },
78
+ "pricing": { "input": 2, "output": 8 }
79
+ },
80
+ "gpt-5.1-codex": {
81
+ "limit": { "context": 1000000, "output": 32768 },
82
+ "pricing": { "input": 2, "output": 8 }
83
+ },
84
+ "gpt-5.1-codex-mini": {
85
+ "limit": { "context": 1000000, "output": 32768 },
86
+ "pricing": { "input": 1.5, "output": 6 }
87
+ },
88
+ "gpt-5.1-codex-max": {
89
+ "limit": { "context": 1000000, "output": 32768 },
90
+ "pricing": { "input": 3, "output": 12 }
91
+ },
92
+ "gpt-5.2-codex": {
93
+ "limit": { "context": 1000000, "output": 32768 },
94
+ "pricing": { "input": 2, "output": 8 }
95
+ },
96
+ "gpt-5.3-codex": {
97
+ "limit": { "context": 1000000, "output": 32768 },
98
+ "pricing": { "input": 2, "output": 8 }
99
+ },
100
+ "gemini-3.1-pro": {
101
+ "limit": { "context": 2097152, "output": 65536 },
102
+ "pricing": { "input": 2.5, "output": 15 }
103
+ },
104
+ "gemini-3-pro-preview": {
105
+ "limit": { "context": 2097152, "output": 65536 },
106
+ "pricing": { "input": 2.5, "output": 15 }
107
+ },
108
+ "gemini-3-flash-preview": {
109
+ "limit": { "context": 1048576, "output": 65536 },
110
+ "pricing": { "input": 0.3, "output": 1.2 }
111
+ },
112
+ "gemini-2.5-pro": {
113
+ "limit": { "context": 1048576, "output": 65536 },
114
+ "pricing": { "input": 1.25, "output": 10 }
115
+ },
116
+ "gemini-2.5-flash": {
117
+ "limit": { "context": 1048576, "output": 65536 },
118
+ "pricing": { "input": 0.15, "output": 0.6 }
119
+ },
120
+ "gemini-2.5-flash-lite": {
121
+ "limit": { "context": 1048576, "output": 65536 },
122
+ "pricing": { "input": 0.1, "output": 0.4 }
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Claude Model Pricing - Backward Compatibility Re-export
3
+ *
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.
6
+ */
7
+
8
+ const { MODEL_METADATA, MODEL_ALIASES, METADATA_LAST_UPDATED } = require('./model-metadata');
9
+
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
+ };
20
+ }
21
+ }
22
+
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
+ }
30
+
31
+ module.exports = {
32
+ CLAUDE_MODEL_PRICING,
33
+ CLAUDE_MODEL_ALIASES,
34
+ PRICING_LAST_UPDATED: METADATA_LAST_UPDATED
35
+ };
@@ -0,0 +1,190 @@
1
+ // CTX 工具路径配置
2
+ // 所有路径统一使用 ~/.cc-tool 目录
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ // 基础目录
8
+ const CC_TOOL_BASE_DIR = path.join(os.homedir(), '.cc-tool');
9
+ // 兼容旧变量名,避免外部调用方断裂
10
+ const CTX_BASE_DIR = CC_TOOL_BASE_DIR;
11
+
12
+ // 旧目录(升级时自动合并到 ~/.cc-tool)
13
+ const LEGACY_BASE_DIRS = [
14
+ path.join(os.homedir(), '.claude', 'ctx'),
15
+ path.join(os.homedir(), '.claude', 'cc-tool')
16
+ ];
17
+
18
+ let migrationChecked = false;
19
+
20
+ function mergeDirectory(sourceDir, targetDir) {
21
+ if (!fs.existsSync(sourceDir)) return;
22
+
23
+ const sourceStat = fs.statSync(sourceDir);
24
+ if (sourceStat.isDirectory()) {
25
+ if (!fs.existsSync(targetDir)) {
26
+ fs.mkdirSync(targetDir, { recursive: true });
27
+ }
28
+
29
+ const entries = fs.readdirSync(sourceDir);
30
+ entries.forEach((entry) => {
31
+ mergeDirectory(path.join(sourceDir, entry), path.join(targetDir, entry));
32
+ });
33
+ return;
34
+ }
35
+
36
+ if (!fs.existsSync(targetDir)) {
37
+ fs.copyFileSync(sourceDir, targetDir);
38
+ }
39
+ }
40
+
41
+ function ensureStorageDirMigrated() {
42
+ if (migrationChecked) {
43
+ return CC_TOOL_BASE_DIR;
44
+ }
45
+ migrationChecked = true;
46
+
47
+ if (!fs.existsSync(CC_TOOL_BASE_DIR)) {
48
+ fs.mkdirSync(CC_TOOL_BASE_DIR, { recursive: true });
49
+ }
50
+
51
+ LEGACY_BASE_DIRS.forEach((legacyDir) => {
52
+ if (!fs.existsSync(legacyDir)) return;
53
+ try {
54
+ mergeDirectory(legacyDir, CC_TOOL_BASE_DIR);
55
+ } catch (error) {
56
+ console.warn(`[paths] 迁移目录失败: ${legacyDir} -> ${CC_TOOL_BASE_DIR}`, error.message);
57
+ }
58
+ });
59
+
60
+ return CC_TOOL_BASE_DIR;
61
+ }
62
+
63
+ // 路径配置
64
+ const PATHS = {
65
+ // 基础目录
66
+ base: CC_TOOL_BASE_DIR,
67
+
68
+ // 项目目录(存储项目配置和会话)
69
+ projects: path.join(CC_TOOL_BASE_DIR, 'projects'),
70
+
71
+ // 配置文件目录
72
+ config: path.join(CC_TOOL_BASE_DIR, 'config'),
73
+ configFile: path.join(CC_TOOL_BASE_DIR, 'config.json'),
74
+
75
+ // 日志目录
76
+ logs: path.join(CC_TOOL_BASE_DIR, 'logs'),
77
+
78
+ // 别名存储
79
+ aliases: path.join(CC_TOOL_BASE_DIR, 'aliases.json'),
80
+
81
+ // 收藏夹存储
82
+ favorites: path.join(CC_TOOL_BASE_DIR, 'favorites.json'),
83
+
84
+ // 渠道配置
85
+ channels: {
86
+ claude: path.join(CC_TOOL_BASE_DIR, 'channels.json'),
87
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-channels.json'),
88
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-channels.json'),
89
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-channels.json')
90
+ },
91
+
92
+ // 激活渠道标记
93
+ activeChannel: {
94
+ claude: path.join(CC_TOOL_BASE_DIR, 'active-channel.json'),
95
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-active-channel.json'),
96
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-active-channel.json'),
97
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-active-channel.json')
98
+ },
99
+
100
+ // 统计数据
101
+ statistics: {
102
+ claude: path.join(CC_TOOL_BASE_DIR, 'statistics.json'),
103
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-statistics.json'),
104
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-statistics.json'),
105
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-statistics.json'),
106
+ dailyStats: {
107
+ claude: path.join(CC_TOOL_BASE_DIR, 'daily-stats'),
108
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-daily-stats'),
109
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-daily-stats'),
110
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-daily-stats')
111
+ }
112
+ },
113
+
114
+ // 会话缓存
115
+ sessionCache: path.join(CC_TOOL_BASE_DIR, 'session-cache.json'),
116
+
117
+ // 项目顺序
118
+ projectOrder: path.join(CC_TOOL_BASE_DIR, 'project-order.json'),
119
+
120
+ // 环境备份
121
+ envBackups: path.join(CC_TOOL_BASE_DIR, 'env-backups'),
122
+
123
+ // UI 配置
124
+ uiConfig: path.join(CC_TOOL_BASE_DIR, 'ui-config.json'),
125
+
126
+ // 飞书通知脚本
127
+ notifyHook: path.join(CC_TOOL_BASE_DIR, 'notify-hook.js'),
128
+
129
+ // Skills 安装目录(注意:这个仍使用 Claude 原生路径)
130
+ skills: path.join(os.homedir(), '.claude', 'skills'),
131
+
132
+ // MCP 配置(注意:这个仍使用 Claude 原生路径)
133
+ mcpConfig: path.join(CC_TOOL_BASE_DIR, 'mcp-config.json'),
134
+
135
+ // Prompts
136
+ prompts: path.join(CC_TOOL_BASE_DIR, 'prompts.json'),
137
+
138
+ // 代理运行时状态
139
+ proxyRuntime: {
140
+ claude: path.join(CC_TOOL_BASE_DIR, 'proxy-runtime.json'),
141
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-proxy-runtime.json'),
142
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-proxy-runtime.json'),
143
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-proxy-runtime.json')
144
+ }
145
+ };
146
+
147
+ // 工具特定的原生配置路径(不改变)
148
+ const NATIVE_PATHS = {
149
+ // Claude Code 原生配置
150
+ claude: {
151
+ settings: path.join(os.homedir(), '.claude', 'settings.json'),
152
+ settingsBackup: path.join(os.homedir(), '.claude', 'settings.json.cc-tool-backup'),
153
+ projects: path.join(os.homedir(), '.claude', 'projects')
154
+ },
155
+
156
+ // Codex 原生配置
157
+ codex: {
158
+ config: path.join(os.homedir(), '.codex', 'config.toml'),
159
+ configBackup: path.join(os.homedir(), '.codex', 'config.toml.cc-tool-backup'),
160
+ auth: path.join(os.homedir(), '.codex', 'auth.json'),
161
+ authBackup: path.join(os.homedir(), '.codex', 'auth.json.cc-tool-backup'),
162
+ sessions: path.join(os.homedir(), '.codex', 'sessions')
163
+ },
164
+
165
+ // Gemini 原生配置
166
+ gemini: {
167
+ env: path.join(os.homedir(), '.gemini', '.env'),
168
+ envBackup: path.join(os.homedir(), '.gemini', '.env.cc-tool-backup'),
169
+ tmp: path.join(os.homedir(), '.gemini', 'tmp')
170
+ },
171
+
172
+ // OpenCode 原生配置
173
+ opencode: {
174
+ data: path.join(os.homedir(), '.local', 'share', 'opencode'),
175
+ config: path.join(os.homedir(), '.config', 'opencode'),
176
+ sessions: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'session'),
177
+ projects: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'project'),
178
+ messages: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'message'),
179
+ log: path.join(os.homedir(), '.local', 'share', 'opencode', 'log')
180
+ }
181
+ };
182
+
183
+ module.exports = {
184
+ PATHS,
185
+ NATIVE_PATHS,
186
+ CTX_BASE_DIR,
187
+ CC_TOOL_BASE_DIR,
188
+ LEGACY_BASE_DIRS,
189
+ ensureStorageDirMigrated
190
+ };