@hileeon/mcc 0.1.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 (138) hide show
  1. package/.claude/CLAUDE.md +204 -0
  2. package/.claude/agents/.gitkeep +0 -0
  3. package/.claude/settings.json +9 -0
  4. package/.claude/skills/.gitkeep +0 -0
  5. package/README.md +127 -0
  6. package/dist/accounts/instance-manager.d.ts +11 -0
  7. package/dist/accounts/instance-manager.d.ts.map +1 -0
  8. package/dist/accounts/instance-manager.js +89 -0
  9. package/dist/accounts/instance-manager.js.map +1 -0
  10. package/dist/accounts/shared-manager.d.ts +25 -0
  11. package/dist/accounts/shared-manager.d.ts.map +1 -0
  12. package/dist/accounts/shared-manager.js +186 -0
  13. package/dist/accounts/shared-manager.js.map +1 -0
  14. package/dist/accounts/store.d.ts +30 -0
  15. package/dist/accounts/store.d.ts.map +1 -0
  16. package/dist/accounts/store.js +128 -0
  17. package/dist/accounts/store.js.map +1 -0
  18. package/dist/core/model-router.d.ts +30 -0
  19. package/dist/core/model-router.d.ts.map +1 -0
  20. package/dist/core/model-router.js +64 -0
  21. package/dist/core/model-router.js.map +1 -0
  22. package/dist/dashboard-server.d.ts +5 -0
  23. package/dist/dashboard-server.d.ts.map +1 -0
  24. package/dist/dashboard-server.js +387 -0
  25. package/dist/dashboard-server.js.map +1 -0
  26. package/dist/mcc.d.ts +8 -0
  27. package/dist/mcc.d.ts.map +1 -0
  28. package/dist/mcc.js +474 -0
  29. package/dist/mcc.js.map +1 -0
  30. package/dist/mcp/external-registry.d.ts +24 -0
  31. package/dist/mcp/external-registry.d.ts.map +1 -0
  32. package/dist/mcp/external-registry.js +99 -0
  33. package/dist/mcp/external-registry.js.map +1 -0
  34. package/dist/mcp/installer.d.ts +31 -0
  35. package/dist/mcp/installer.d.ts.map +1 -0
  36. package/dist/mcp/installer.js +273 -0
  37. package/dist/mcp/installer.js.map +1 -0
  38. package/dist/mcp/mcp-config.d.ts +86 -0
  39. package/dist/mcp/mcp-config.d.ts.map +1 -0
  40. package/dist/mcp/mcp-config.js +178 -0
  41. package/dist/mcp/mcp-config.js.map +1 -0
  42. package/dist/mcp/registry.d.ts +23 -0
  43. package/dist/mcp/registry.d.ts.map +1 -0
  44. package/dist/mcp/registry.js +100 -0
  45. package/dist/mcp/registry.js.map +1 -0
  46. package/dist/proxy/proxy-daemon.d.ts +27 -0
  47. package/dist/proxy/proxy-daemon.d.ts.map +1 -0
  48. package/dist/proxy/proxy-daemon.js +192 -0
  49. package/dist/proxy/proxy-daemon.js.map +1 -0
  50. package/dist/proxy/proxy-entry.d.ts +11 -0
  51. package/dist/proxy/proxy-entry.d.ts.map +1 -0
  52. package/dist/proxy/proxy-entry.js +74 -0
  53. package/dist/proxy/proxy-entry.js.map +1 -0
  54. package/dist/proxy/proxy-paths.d.ts +27 -0
  55. package/dist/proxy/proxy-paths.d.ts.map +1 -0
  56. package/dist/proxy/proxy-paths.js +125 -0
  57. package/dist/proxy/proxy-paths.js.map +1 -0
  58. package/dist/proxy/proxy-server.d.ts +20 -0
  59. package/dist/proxy/proxy-server.d.ts.map +1 -0
  60. package/dist/proxy/proxy-server.js +280 -0
  61. package/dist/proxy/proxy-server.js.map +1 -0
  62. package/dist/proxy/upstream-url.d.ts +7 -0
  63. package/dist/proxy/upstream-url.d.ts.map +1 -0
  64. package/dist/proxy/upstream-url.js +38 -0
  65. package/dist/proxy/upstream-url.js.map +1 -0
  66. package/dist/shared/logger.d.ts +23 -0
  67. package/dist/shared/logger.d.ts.map +1 -0
  68. package/dist/shared/logger.js +184 -0
  69. package/dist/shared/logger.js.map +1 -0
  70. package/dist/shared/provider-preset-catalog.d.ts +41 -0
  71. package/dist/shared/provider-preset-catalog.d.ts.map +1 -0
  72. package/dist/shared/provider-preset-catalog.js +299 -0
  73. package/dist/shared/provider-preset-catalog.js.map +1 -0
  74. package/docs/decisions.md +33 -0
  75. package/docs/lessons.md +8 -0
  76. package/docs/product.md +37 -0
  77. package/lib/mcp/mcc-image-analysis-server.cjs +454 -0
  78. package/lib/mcp/mcc-websearch-server.cjs +339 -0
  79. package/lib/mcp-hooks/image-analysis-runtime.cjs +510 -0
  80. package/lib/mcp-hooks/image-analyzer-transformer.cjs +526 -0
  81. package/lib/mcp-hooks/websearch-transformer.cjs +1421 -0
  82. package/lib/proxy/config/config-loader-facade.js +24 -0
  83. package/lib/proxy/glmt/delta-accumulator.js +363 -0
  84. package/lib/proxy/glmt/glmt-transformer.js +204 -0
  85. package/lib/proxy/glmt/index.js +41 -0
  86. package/lib/proxy/glmt/locale-enforcer.js +69 -0
  87. package/lib/proxy/glmt/pipeline/content-transformer.js +162 -0
  88. package/lib/proxy/glmt/pipeline/index.js +20 -0
  89. package/lib/proxy/glmt/pipeline/request-transformer.js +116 -0
  90. package/lib/proxy/glmt/pipeline/response-builder.js +205 -0
  91. package/lib/proxy/glmt/pipeline/stream-parser.js +234 -0
  92. package/lib/proxy/glmt/pipeline/tool-call-handler.js +78 -0
  93. package/lib/proxy/glmt/pipeline/types.js +6 -0
  94. package/lib/proxy/glmt/reasoning-enforcer.js +151 -0
  95. package/lib/proxy/glmt/sse-parser.js +102 -0
  96. package/lib/proxy/services/logging.js +13 -0
  97. package/lib/proxy/transformers/request-transformer.js +452 -0
  98. package/lib/proxy/transformers/sse-stream-transformer.js +199 -0
  99. package/lib/shared/logger.cjs +138 -0
  100. package/package.json +35 -0
  101. package/src/accounts/instance-manager.ts +58 -0
  102. package/src/accounts/shared-manager.ts +154 -0
  103. package/src/accounts/store.ts +111 -0
  104. package/src/core/model-router.ts +82 -0
  105. package/src/dashboard-server.ts +407 -0
  106. package/src/mcc.ts +474 -0
  107. package/src/mcp/external-registry.ts +73 -0
  108. package/src/mcp/installer.ts +258 -0
  109. package/src/mcp/mcp-config.ts +168 -0
  110. package/src/mcp/registry.ts +89 -0
  111. package/src/proxy/proxy-daemon.ts +184 -0
  112. package/src/proxy/proxy-entry.ts +63 -0
  113. package/src/proxy/proxy-paths.ts +97 -0
  114. package/src/proxy/proxy-server.ts +278 -0
  115. package/src/proxy/upstream-url.ts +38 -0
  116. package/src/shared/logger.ts +140 -0
  117. package/src/shared/provider-preset-catalog.ts +340 -0
  118. package/tsconfig.json +33 -0
  119. package/ui/.prettierrc +9 -0
  120. package/ui/index.html +12 -0
  121. package/ui/package.json +33 -0
  122. package/ui/postcss.config.js +6 -0
  123. package/ui/src/App.tsx +753 -0
  124. package/ui/src/components/ui/button.tsx +48 -0
  125. package/ui/src/components/ui/card.tsx +50 -0
  126. package/ui/src/components/ui/input.tsx +21 -0
  127. package/ui/src/components/ui/label.tsx +20 -0
  128. package/ui/src/components/ui/select.tsx +80 -0
  129. package/ui/src/components/ui/switch.tsx +26 -0
  130. package/ui/src/components/ui/tabs.tsx +52 -0
  131. package/ui/src/index.css +33 -0
  132. package/ui/src/lib/api.ts +185 -0
  133. package/ui/src/lib/utils.ts +6 -0
  134. package/ui/src/main.tsx +10 -0
  135. package/ui/src/vite-env.d.ts +1 -0
  136. package/ui/tailwind.config.js +49 -0
  137. package/ui/tsconfig.json +25 -0
  138. package/ui/vite.config.ts +20 -0
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ /**
3
+ * Shared provider preset catalog for CLI + Dashboard.
4
+ *
5
+ * Keep this file runtime-agnostic (no Node/browser APIs) so both
6
+ * backend and UI can import the same source of truth.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PROVIDER_PRESET_DEFINITIONS = exports.PROVIDER_PRESET_ALIASES = exports.OPENROUTER_BASE_URL = exports.PROVIDER_PRESET_IDS = void 0;
10
+ exports.createProviderPresetDefinitions = createProviderPresetDefinitions;
11
+ exports.normalizeProviderPresetId = normalizeProviderPresetId;
12
+ exports.PROVIDER_PRESET_IDS = [
13
+ 'openrouter',
14
+ 'alibaba-coding-plan',
15
+ 'huggingface',
16
+ 'ollama',
17
+ 'llamacpp',
18
+ 'anthropic',
19
+ 'glm',
20
+ 'km',
21
+ 'foundry',
22
+ 'mm',
23
+ 'deepseek',
24
+ 'qwen',
25
+ 'ollama-cloud',
26
+ 'novita',
27
+ ];
28
+ exports.OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1';
29
+ /**
30
+ * Legacy aliases mapped to canonical preset IDs.
31
+ * Keep this minimal and explicit to avoid hidden implicit behavior.
32
+ */
33
+ exports.PROVIDER_PRESET_ALIASES = Object.freeze({
34
+ glmt: 'glm',
35
+ kimi: 'km',
36
+ alibaba: 'alibaba-coding-plan',
37
+ acp: 'alibaba-coding-plan',
38
+ hf: 'huggingface',
39
+ });
40
+ const RAW_PROVIDER_PRESET_DEFINITIONS = [
41
+ {
42
+ id: 'openrouter',
43
+ name: 'OpenRouter',
44
+ description: '349+ models from OpenAI, Anthropic, Google, Meta',
45
+ baseUrl: exports.OPENROUTER_BASE_URL,
46
+ defaultProfileName: 'openrouter',
47
+ defaultModel: 'anthropic/claude-opus-4.5',
48
+ apiKeyPlaceholder: 'sk-or-...',
49
+ apiKeyHint: 'Get your API key at openrouter.ai/keys',
50
+ category: 'recommended',
51
+ requiresApiKey: true,
52
+ badge: '349+ models',
53
+ featured: true,
54
+ icon: '/icons/openrouter.svg',
55
+ },
56
+ {
57
+ id: 'alibaba-coding-plan',
58
+ name: 'Alibaba Coding Plan',
59
+ description: 'Alibaba Cloud Coding Plan via Anthropic-compatible endpoint',
60
+ baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/apps/anthropic',
61
+ defaultProfileName: 'albb',
62
+ defaultModel: 'qwen3-coder-plus',
63
+ apiKeyPlaceholder: 'sk-sp-...',
64
+ apiKeyHint: 'Get your Coding Plan key from Alibaba Cloud Model Studio',
65
+ category: 'recommended',
66
+ requiresApiKey: true,
67
+ badge: 'Coding Plan',
68
+ featured: true,
69
+ icon: '/assets/providers/alibabacloud-color.svg',
70
+ },
71
+ {
72
+ id: 'ollama',
73
+ name: 'Ollama (Local)',
74
+ description: 'Local open-source models via Ollama (32K+ context)',
75
+ baseUrl: 'http://localhost:11434',
76
+ defaultProfileName: 'ollama',
77
+ defaultModel: 'qwen3-coder',
78
+ apiKeyPlaceholder: 'ollama',
79
+ apiKeyHint: 'Install Ollama from ollama.com - no API key needed for local',
80
+ category: 'recommended',
81
+ requiresApiKey: false,
82
+ badge: 'Local',
83
+ featured: true,
84
+ icon: '/icons/ollama.svg',
85
+ },
86
+ {
87
+ id: 'llamacpp',
88
+ name: 'llama.cpp (Local)',
89
+ description: 'Local inference via llama.cpp (LLaMA models)',
90
+ baseUrl: 'http://127.0.0.1:8080',
91
+ defaultProfileName: 'llamacpp',
92
+ defaultModel: 'llama3-8b',
93
+ apiKeyPlaceholder: 'llamacpp',
94
+ apiKeyHint: 'Run llama.cpp server: ./server --host 0.0.0.0 --port 8080 -m model.gguf',
95
+ category: 'recommended',
96
+ requiresApiKey: false,
97
+ badge: 'Local',
98
+ featured: true,
99
+ icon: '/assets/providers/llama-cpp.svg',
100
+ },
101
+ {
102
+ id: 'anthropic',
103
+ name: 'Anthropic (Direct API)',
104
+ description: 'Use your own Anthropic API key (sk-ant-...)',
105
+ baseUrl: '',
106
+ defaultProfileName: 'anthropic',
107
+ defaultModel: 'claude-sonnet-4-5-20250929',
108
+ apiKeyPlaceholder: 'sk-ant-api03-...',
109
+ apiKeyHint: 'Get key at console.anthropic.com/settings/keys',
110
+ category: 'recommended',
111
+ requiresApiKey: true,
112
+ badge: 'Direct',
113
+ featured: true,
114
+ icon: '/assets/providers/claude.svg',
115
+ },
116
+ {
117
+ id: 'huggingface',
118
+ name: 'Hugging Face',
119
+ description: 'Inference Providers router via OpenAI-compatible chat completions',
120
+ baseUrl: 'https://router.huggingface.co/v1',
121
+ defaultProfileName: 'hf',
122
+ defaultModel: 'openai/gpt-oss-120b:fastest',
123
+ apiKeyPlaceholder: 'hf_...',
124
+ apiKeyHint: 'Create a User Access Token at hf.co/settings/tokens',
125
+ category: 'alternative',
126
+ requiresApiKey: true,
127
+ defaultTarget: 'droid',
128
+ badge: 'Router',
129
+ },
130
+ {
131
+ id: 'glm',
132
+ name: 'GLM',
133
+ description: 'Direct Z.AI Anthropic-compatible API profile',
134
+ baseUrl: 'https://api.z.ai/api/anthropic',
135
+ defaultProfileName: 'glm',
136
+ defaultModel: 'glm-5',
137
+ apiKeyPlaceholder: 'ghp_...',
138
+ apiKeyHint: 'Get your API key from Z.AI',
139
+ category: 'alternative',
140
+ requiresApiKey: true,
141
+ badge: 'Z.AI',
142
+ icon: '/icons/zai.svg',
143
+ },
144
+ {
145
+ id: 'km',
146
+ name: 'Kimi',
147
+ description: 'Moonshot AI - Fast reasoning model',
148
+ baseUrl: 'https://api.kimi.com/coding/',
149
+ defaultProfileName: 'km',
150
+ defaultModel: 'kimi-k2-thinking-turbo',
151
+ apiKeyPlaceholder: 'sk-...',
152
+ apiKeyHint: 'Get your API key from Moonshot AI',
153
+ category: 'alternative',
154
+ requiresApiKey: true,
155
+ alwaysThinkingEnabled: true,
156
+ badge: 'Reasoning',
157
+ icon: '/icons/kimi.svg',
158
+ },
159
+ {
160
+ id: 'foundry',
161
+ name: 'Azure Foundry',
162
+ description: 'Claude via Microsoft Azure AI Foundry',
163
+ baseUrl: 'https://<your-resource>.services.ai.azure.com/api/anthropic',
164
+ defaultProfileName: 'foundry',
165
+ defaultModel: 'claude-sonnet-4-5',
166
+ apiKeyPlaceholder: 'YOUR_AZURE_API_KEY',
167
+ apiKeyHint: 'Create resource at ai.azure.com, get API key from Keys tab',
168
+ category: 'alternative',
169
+ requiresApiKey: true,
170
+ badge: 'Azure',
171
+ icon: '/icons/azure.svg',
172
+ },
173
+ {
174
+ id: 'mm',
175
+ name: 'Minimax',
176
+ description: 'M2.1/M2.1-lightning/M2 - multilang coding (1M context)',
177
+ baseUrl: 'https://api.minimax.io/anthropic',
178
+ defaultProfileName: 'mm',
179
+ defaultModel: 'MiniMax-M2.1',
180
+ apiKeyPlaceholder: 'YOUR_MINIMAX_API_KEY_HERE',
181
+ apiKeyHint: 'Get your API key at platform.minimax.io',
182
+ category: 'alternative',
183
+ requiresApiKey: true,
184
+ badge: '1M context',
185
+ icon: '/icons/minimax.svg',
186
+ },
187
+ {
188
+ id: 'deepseek',
189
+ name: 'DeepSeek',
190
+ description: 'V3.2 and R1 reasoning model (128K context)',
191
+ baseUrl: 'https://api.deepseek.com/anthropic',
192
+ defaultProfileName: 'deepseek',
193
+ defaultModel: 'deepseek-chat',
194
+ apiKeyPlaceholder: 'sk-...',
195
+ apiKeyHint: 'Get your API key at platform.deepseek.com',
196
+ category: 'alternative',
197
+ requiresApiKey: true,
198
+ badge: 'Reasoning',
199
+ icon: '/icons/deepseek.svg',
200
+ },
201
+ {
202
+ id: 'qwen',
203
+ name: 'Qwen',
204
+ description: 'Alibaba Cloud - Qwen3 models (256K-1M context, thinking support)',
205
+ baseUrl: 'https://dashscope-intl.aliyuncs.com/apps/anthropic',
206
+ defaultProfileName: 'qwen-api',
207
+ defaultModel: 'qwen3-coder-plus',
208
+ apiKeyPlaceholder: 'sk-...',
209
+ apiKeyHint: 'Get your API key from Alibaba Cloud Model Studio',
210
+ category: 'alternative',
211
+ requiresApiKey: true,
212
+ badge: 'Alibaba',
213
+ icon: '/assets/providers/qwen-color.svg',
214
+ },
215
+ {
216
+ id: 'ollama-cloud',
217
+ name: 'Ollama Cloud',
218
+ description: 'Ollama cloud models via direct API (glm-5:cloud, minimax-m2.1:cloud)',
219
+ baseUrl: 'https://ollama.com',
220
+ defaultProfileName: 'ollama-cloud',
221
+ defaultModel: 'glm-5:cloud',
222
+ apiKeyPlaceholder: 'YOUR_OLLAMA_CLOUD_API_KEY',
223
+ apiKeyHint: 'Get your API key at ollama.com',
224
+ category: 'alternative',
225
+ requiresApiKey: true,
226
+ badge: 'Cloud',
227
+ icon: '/icons/ollama.svg',
228
+ },
229
+ {
230
+ id: 'novita',
231
+ name: 'Novita AI',
232
+ description: 'Anthropic-compatible API for Claude Code and CCS profiles',
233
+ baseUrl: 'https://api.novita.ai/anthropic',
234
+ defaultProfileName: 'novita',
235
+ defaultModel: 'deepseek/deepseek-v3.2',
236
+ apiKeyPlaceholder: 'YOUR_NOVITA_API_KEY',
237
+ apiKeyHint: 'Get your API key at novita.ai',
238
+ category: 'alternative',
239
+ requiresApiKey: true,
240
+ badge: 'Anthropic-compatible',
241
+ icon: '/icons/novita.svg',
242
+ },
243
+ ];
244
+ function clonePresetDefinition(preset) {
245
+ return {
246
+ ...preset,
247
+ extraEnv: preset.extraEnv ? { ...preset.extraEnv } : undefined,
248
+ };
249
+ }
250
+ function freezePresetDefinition(preset) {
251
+ const cloned = clonePresetDefinition(preset);
252
+ if (cloned.extraEnv) {
253
+ Object.freeze(cloned.extraEnv);
254
+ }
255
+ return Object.freeze(cloned);
256
+ }
257
+ function assertProviderPresetCatalogIntegrity(definitions, aliases) {
258
+ const presetIdSet = new Set();
259
+ for (const definition of definitions) {
260
+ const normalizedId = definition.id.trim().toLowerCase();
261
+ if (definition.id !== normalizedId) {
262
+ throw new Error(`Preset ID must be normalized: "${definition.id}"`);
263
+ }
264
+ if (presetIdSet.has(definition.id)) {
265
+ throw new Error(`Duplicate preset ID detected: "${definition.id}"`);
266
+ }
267
+ presetIdSet.add(definition.id);
268
+ }
269
+ const normalizedAliasSet = new Set();
270
+ for (const [alias, target] of Object.entries(aliases)) {
271
+ const normalizedAlias = alias.trim().toLowerCase();
272
+ if (!normalizedAlias) {
273
+ throw new Error('Preset alias keys cannot be empty');
274
+ }
275
+ if (alias !== normalizedAlias) {
276
+ throw new Error(`Preset alias must be normalized: "${alias}"`);
277
+ }
278
+ if (normalizedAliasSet.has(normalizedAlias)) {
279
+ throw new Error(`Duplicate normalized preset alias detected: "${alias}"`);
280
+ }
281
+ normalizedAliasSet.add(normalizedAlias);
282
+ if (!presetIdSet.has(target)) {
283
+ throw new Error(`Preset alias "${alias}" points to unknown target "${target}"`);
284
+ }
285
+ if (presetIdSet.has(normalizedAlias)) {
286
+ throw new Error(`Preset alias "${alias}" collides with canonical preset ID "${normalizedAlias}"`);
287
+ }
288
+ }
289
+ }
290
+ assertProviderPresetCatalogIntegrity(RAW_PROVIDER_PRESET_DEFINITIONS, exports.PROVIDER_PRESET_ALIASES);
291
+ exports.PROVIDER_PRESET_DEFINITIONS = Object.freeze(RAW_PROVIDER_PRESET_DEFINITIONS.map(freezePresetDefinition));
292
+ function createProviderPresetDefinitions() {
293
+ return exports.PROVIDER_PRESET_DEFINITIONS.map(clonePresetDefinition);
294
+ }
295
+ function normalizeProviderPresetId(id) {
296
+ const normalized = id.trim().toLowerCase();
297
+ return exports.PROVIDER_PRESET_ALIASES[normalized] || normalized;
298
+ }
299
+ //# sourceMappingURL=provider-preset-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-preset-catalog.js","sourceRoot":"","sources":["../../src/shared/provider-preset-catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ # 技术决策记录
2
+
3
+ 本文件追加记录本项目的重大技术决策。新决策追加到文件末尾;历史条目不修改;如某决策被推翻,新建条目并引用被推翻的条目(例如 "Supersedes 2026-01-15 14:30:45 +08:00 的条目")。所有条目标题必须带 24 小时制时分秒与时区,详见「时间戳规范」章节。
4
+
5
+ ---
6
+
7
+ ## 2026-05-14 17:37:50 +08:00: TypeScript + CommonJS + tsc,不引入 bundler
8
+
9
+ **背景**: 项目是 Node.js CLI 工具,需要编译到 JS 后通过 `node dist/mcc.js` 运行。
10
+
11
+ **选项**:
12
+ - esbuild / tsx 等快速工具:开发体验好但多一个依赖
13
+ - tsc:零额外依赖,TypeScript 自带
14
+
15
+ **选择**: `tsc` + CommonJS(`module: "commonjs"`)+ ES2020 target。`npm run build` 即 `tsc`,`npm run dev` 直接 `node dist/mcc.js`。
16
+
17
+ **代价**: 放弃了 esbuild 的 sub-second 编译速度和 ESM 生态。后续如果编译时间明显影响开发体验可重新评估。
18
+
19
+ ---
20
+
21
+ ## 2026-05-14 17:37:50 +08:00: KISS direct-API 路线——不做 OAuth、不做本地 proxy
22
+
23
+ **背景**: 现有工具 CCS 已经覆盖了 OAuth + local proxy + 多 runtime 的完整场景。MCC 的定位是极简替代——给只需要 API key 切换的用户一个更轻的选择。
24
+
25
+ **选项**:
26
+ - 沿用 CCS 架构(OAuth + proxy):功能完整但复杂度高
27
+ - 纯 CLI wrapper:直接设 env 然后 spawn Claude Code
28
+
29
+ **选择**: 纯 env-based direct API。`buildDirectApiEnv()` 返回 `ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_MODEL`,`cmdUse()` 拼上 `CLAUDE_CONFIG_DIR` 后 `spawn('claude', ...)`。
30
+
31
+ **代价**: 不支持 OAuth provider(Codex、Kiro 等),不支持 `profile:model` 运行时路由。这些场景留给 CCS。
32
+
33
+ ---
@@ -0,0 +1,8 @@
1
+ # 踩过的坑与学到的教训
2
+
3
+ 本文件记录"代码里看不出的东西":诡异 bug 的根因、反直觉的行为、重构中学到的教训。被修复的条目可以剪枝删除,但能长期留作警示的坑建议保留。
4
+
5
+ ---
6
+
7
+ <!-- 尚无记录 -->
8
+
@@ -0,0 +1,37 @@
1
+ # Product
2
+
3
+ ## 是什么
4
+
5
+ MCC(My Cloud Code)是一个轻量级 CLI 工具,用于在多个 Claude Code 账号(不同 API Provider)之间快速切换。不走 OAuth——直接设置环境变量后 `spawn` Claude Code。
6
+
7
+ 支持两种协议模式:
8
+ - **Anthropic 直接模式**:profile 的 `baseUrl` 直接对接 Anthropic 兼容 API
9
+ - **OpenAI 兼容模式**(`protocol: 'openai'`):自动启动本地翻译 proxy,把 Claude Code 的 Anthropic 请求转换为 OpenAI chat/completions 格式,转发给 upstream provider
10
+
11
+ ## 为谁做 / 解决什么问题
12
+
13
+ 为需要频繁在多个 AI provider(deepseek、qwen、glm、kimi、minimax、anthropic 等)之间切换的开发者,省去每次手动改 config、改环境变量的机械劳动。
14
+
15
+ ## 当前核心功能
16
+
17
+ - **多 profile 管理**:`mcc profile add/list/remove/default`,元数据存 `~/.mcc/profiles.json`,API key 存 `~/.mcc/profiles/<name>/.key`
18
+ - **一键切换**:`mcc <profile>` 设置 `ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_MODEL` / `CLAUDE_CONFIG_DIR` 后直接启动 Claude Code
19
+ - **实例隔离**:每个 profile 对应独立的 `CLAUDE_CONFIG_DIR`(`~/.mcc/instances/<name>/`),session 历史、MCP 配置互不干扰
20
+ - **OpenAI 兼容 + 翻译 proxy**:`protocol: 'openai'` 时自动在 `127.0.0.1:43456-43555` 范围内启动 proxy,支持所有 OpenAI-compatible provider(MiniMax 等)
21
+ - **Tiered model**:profile 支持 `opusModel`/`sonnetModel`/`haikuModel`,Claude Code 运行时根据任务级别自动选用
22
+ - **内置 MCP**:`mcc-websearch`(多源 web 搜索)和 `mcc-image-analysis`(图片/PDF 分析),自动安装到 instance 的 `.claude.json`
23
+ - **外部 MCP registry**:通过 `mcc mcp add` 注册第三方 MCP server,API key 通过 `${MCC_PROVIDER_KEY:<providerId>}` 引用 `~/.mcc/mcp-config.json` 中的配置
24
+ - **MCP provider 配置系统**:`~/.mcc/mcp-config.json` 统一管理 WebSearch(duckduckgo/exa/tavily/brave)和 ImageAnalysis(ali/kimi/minimax/deepseek)的 provider 开关和 API key
25
+ - **跨 instance 共享**:skills、commands、agents、plugins、settings.json 通过 symlink 在所有 instance 间共享(`~/.claude/` → `~/.mcc/instances/<name>/<item>`)
26
+ - **Session 日志**:每次启动生成独立 session 日志(`~/.mcc/logs/<profile>/<sessionId>/mcc.log`),自动 logrotate
27
+ - **Web Dashboard**:Express + 静态文件,提供 profile/MCP/模型配置的管理界面(`npm run dashboard`,端口 3000)
28
+
29
+ ## 明确不做什么
30
+
31
+ - 不做 OAuth 登录流程(账号靠 API key)
32
+ - 不做 Codex CLI / Factory Droid 等 runtime 桥接(只支持 Claude Code)
33
+ - 不做 quota 监控 / cost tracking
34
+
35
+ ## 待规划
36
+
37
+ - 多个 Claude Code 官方账号切换