yingclaw 2.5.1 → 2.5.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.
package/README.md CHANGED
@@ -47,8 +47,11 @@ claw code
47
47
  接入 Claude 桌面应用:
48
48
  ```bash
49
49
  claw desktop
50
+ claw gateway
50
51
  ```
51
- 将配置写入 Claude Desktop 第三方推理本地配置。macOS 会自动重启 Claude Desktop;Windows 需手动重新打开。
52
+ `claw desktop` 会把 Claude Desktop 指向 yingclaw 本机 Gateway,并只暴露 `claude-sonnet-4-6`、`claude-opus-4-7`、`claude-haiku-4-5` 这类 Claude Desktop 可接受的模型名。真实第三方模型仍按 `claw config` 保存的主模型和快速模型转发。
53
+
54
+ 使用 Claude Desktop 时需要保持 `claw gateway` 运行。
52
55
 
53
56
  ## 支持的厂商
54
57
 
@@ -71,6 +74,8 @@ claw # 交互菜单(无参数时自动进入)
71
74
  claw config # 配置 API 连接
72
75
  claw code # 接入 Claude Code 终端
73
76
  claw desktop # 接入 Claude 桌面应用
77
+ claw gateway # 启动 Claude 桌面应用本机 Gateway
78
+ claw desktop --direct # 高级:直连写入厂商 Gateway URL
74
79
  claw switch # 快速切换厂商或模型
75
80
  claw status # 查看当前配置,验证 Key 是否有效
76
81
  claw update # 检查并升级到最新版本
@@ -105,12 +110,14 @@ CLAUDE_CODE_SUBAGENT_MODEL
105
110
  CLAUDE_CODE_EFFORT_LEVEL
106
111
  ```
107
112
 
108
- **桌面接入**(`claw desktop`)写入 Claude Desktop 第三方推理配置:
113
+ **桌面接入**(`claw desktop`)默认写入本机 Gateway:
109
114
 
110
- - macOS:`~/Library/Application Support/Claude-3p/configLibrary/`
111
- - Windows:`%APPDATA%\Claude-3p\configLibrary\`
115
+ - macOS / Windows:写入 `Claude-3p/configLibrary/` 中的 yingclaw entry
116
+ - Claude Desktop 访问 `http://127.0.0.1:18080/yingclaw`
117
+ - Gateway 再转发到当前保存的 Anthropic 兼容接口
118
+ - 终端接入仍直接使用 `ANTHROPIC_*` 环境变量,不受桌面 Gateway 影响
112
119
 
113
- 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer`,将 Gateway Base URL 指向对应厂商的 Anthropic 兼容接口。桌面接入要求 Base URL 使用 HTTPS。
120
+ 使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer`,将 Gateway Base URL 指向 yingclaw 本机 Gateway。高级用户可用 `claw desktop --direct` 保留旧式直连写入,但新版 Claude Desktop 可能拒绝非 Claude 模型名。
114
121
 
115
122
  **自定义接口**需支持 Anthropic `/v1/messages` 格式;工具会根据 Base URL 自动尝试获取模型列表,失败则手动输入。
116
123
 
package/bin/cli.js CHANGED
@@ -23,6 +23,12 @@ const pkg = require('../package.json');
23
23
  const { buildMenuStatusLines, buildStatusView } = require('../lib/panel');
24
24
  const { buildClaudeInstallCommand, checkNodeEnv, getNodeInstallGuide, getInstallFailureHints } = require('../lib/install');
25
25
  const { clearClaudeDesktopConfig, isDesktopConfigured, openClaudeDesktop, writeClaudeDesktopConfig } = require('../lib/desktop');
26
+ const {
27
+ DEFAULT_DESKTOP_GATEWAY_PORT,
28
+ YINGCLAW_GATEWAY_PREFIX,
29
+ createGatewayServer,
30
+ ensureDesktopGatewayConfig,
31
+ } = require('../lib/gateway');
26
32
  const { runDoctorChecks, summarize, STATUS_OK, STATUS_FAIL, STATUS_WARN, STATUS_INFO } = require('../lib/doctor');
27
33
 
28
34
  const program = new Command();
@@ -662,10 +668,54 @@ program
662
668
  .description('查看当前配置和 Key 有效性')
663
669
  .action(showStatus);
664
670
 
671
+ program
672
+ .command('gateway')
673
+ .description('启动 Claude 桌面应用本机 Gateway')
674
+ .option('-p, --port <port>', '监听端口')
675
+ .action(async (options) => {
676
+ const chalk = (await import('chalk')).default;
677
+ const boxen = (await import('boxen')).default;
678
+
679
+ let config = loadConfig();
680
+ if (!config) {
681
+ console.log(chalk.red('\n未配置 API 连接,请先运行: claw config\n'));
682
+ return;
683
+ }
684
+ const configProblem = getConfigValidationMessage(config);
685
+ if (configProblem) {
686
+ console.log(chalk.red(`\n配置无效:${configProblem}`));
687
+ console.log(chalk.dim('请运行 claw config 重新配置。\n'));
688
+ return;
689
+ }
690
+
691
+ const ensuredConfig = ensureDesktopGatewayConfig(config);
692
+ if (ensuredConfig.desktopGatewayKey !== config.desktopGatewayKey || ensuredConfig.desktopGatewayPort !== config.desktopGatewayPort) {
693
+ saveConfig(ensuredConfig);
694
+ config = ensuredConfig;
695
+ }
696
+
697
+ const port = Number.parseInt(options.port || config.desktopGatewayPort || DEFAULT_DESKTOP_GATEWAY_PORT, 10);
698
+ const server = createGatewayServer();
699
+ server.listen(port, '127.0.0.1', () => {
700
+ console.log(boxen(
701
+ chalk.bold('yingclaw Desktop Gateway 已启动\n\n') +
702
+ chalk.dim('URL ') + chalk.cyan(`http://127.0.0.1:${port}${YINGCLAW_GATEWAY_PREFIX}`) + '\n' +
703
+ chalk.dim('模型 ') + chalk.yellow(config.model) + '\n\n' +
704
+ chalk.dim('保持此终端打开,Claude Desktop 才能访问第三方模型。'),
705
+ { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'green', margin: { top: 1, bottom: 1 } }
706
+ ));
707
+ });
708
+ server.on('error', (error) => {
709
+ console.error(chalk.red(`Gateway 启动失败: ${error.message}`));
710
+ process.exitCode = 1;
711
+ });
712
+ });
713
+
665
714
  program
666
715
  .command('desktop')
667
716
  .description('接入 Claude 桌面应用使用当前模型')
668
- .action(async () => {
717
+ .option('--direct', '高级:直接写入当前厂商 Gateway URL,不启用本机模型映射')
718
+ .action(async (options) => {
669
719
  const chalk = (await import('chalk')).default;
670
720
  const ora = (await import('ora')).default;
671
721
  const boxen = (await import('boxen')).default;
@@ -689,10 +739,18 @@ program
689
739
  return;
690
740
  }
691
741
 
742
+ let desktopConfig = config;
743
+ if (!options.direct) {
744
+ desktopConfig = ensureDesktopGatewayConfig(config);
745
+ if (desktopConfig.desktopGatewayKey !== config.desktopGatewayKey || desktopConfig.desktopGatewayPort !== config.desktopGatewayPort) {
746
+ saveConfig(desktopConfig);
747
+ }
748
+ }
749
+
692
750
  const spinner = ora('写入 Claude 桌面应用配置...').start();
693
751
  let result;
694
752
  try {
695
- result = writeClaudeDesktopConfig(config);
753
+ result = writeClaudeDesktopConfig(desktopConfig, { direct: options.direct });
696
754
  if (result.result === 'unsupported') {
697
755
  spinner.warn(chalk.yellow('当前系统暂不支持自动配置 Claude 桌面应用'));
698
756
  return;
@@ -703,13 +761,22 @@ program
703
761
  return;
704
762
  }
705
763
 
764
+ const gatewayUrl = `http://127.0.0.1:${desktopConfig.desktopGatewayPort}${YINGCLAW_GATEWAY_PREFIX}`;
765
+ const modeLines = options.direct
766
+ ? chalk.dim('Base URL ') + chalk.cyan(desktopConfig.baseUrl) + '\n' +
767
+ chalk.dim('模型 ') + chalk.yellow(desktopConfig.model) + '\n' +
768
+ chalk.yellow('直连模式可能被新版 Claude Desktop 拒绝非 Claude 模型名。')
769
+ : chalk.dim('Gateway ') + chalk.cyan(gatewayUrl) + '\n' +
770
+ chalk.dim('主模型 ') + chalk.yellow(desktopConfig.model) + '\n' +
771
+ chalk.dim('快速模型 ') + chalk.yellow(desktopConfig.fastModel || desktopConfig.model) + '\n\n' +
772
+ chalk.cyan('使用前请运行: claw gateway');
773
+
706
774
  console.log(boxen(
707
- chalk.bold('Claude 桌面应用已配置为 Gateway 模式\n\n') +
708
- chalk.dim('Base URL ') + chalk.cyan(config.baseUrl) + '\n' +
709
- chalk.dim('模型 ') + chalk.yellow(config.model) + '\n' +
775
+ chalk.bold(options.direct ? 'Claude 桌面应用已配置为直连 Gateway 模式\n\n' : 'Claude 桌面应用已配置为本机 Gateway 模式\n\n') +
776
+ modeLines + '\n' +
710
777
  chalk.dim('认证方式 ') + chalk.cyan('bearer') + '\n\n' +
711
778
  chalk.yellow(getDesktopOpenHint()) + '\n' +
712
- chalk.dim('要求:网关必须支持 Anthropic POST /v1/messages,且 Base URL 必须是 HTTPS。'),
779
+ chalk.dim(options.direct ? '要求:网关必须支持 Anthropic POST /v1/messages,且 Base URL 必须是 HTTPS。' : '要求:保持 claw gateway 运行,Claude Desktop 才能访问第三方模型。'),
713
780
  { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: 'cyan', margin: { top: 1, bottom: 1 } }
714
781
  ));
715
782
 
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  ...require('./lib/config'),
3
3
  ...require('./lib/desktop'),
4
+ ...require('./lib/gateway'),
4
5
  ...require('./lib/install'),
5
6
  ...require('./lib/panel'),
6
7
  };
package/lib/desktop.js CHANGED
@@ -4,6 +4,11 @@ const os = require('os');
4
4
  const path = require('path');
5
5
  const { spawnSync } = require('child_process');
6
6
  const { normalizeAnthropicBaseUrl } = require('./config');
7
+ const {
8
+ YINGCLAW_GATEWAY_PREFIX,
9
+ buildDesktopGatewayRoutes,
10
+ ensureDesktopGatewayConfig,
11
+ } = require('./gateway');
7
12
 
8
13
  const CLAUDE_DESKTOP_LABEL = 'Claude 桌面应用配置';
9
14
  const YINGCLAW_ENTRY_NAME = 'yingclaw';
@@ -60,16 +65,43 @@ function toDesktopModelId(model) {
60
65
  return model.startsWith('claude-') ? model : `claude-${model}`;
61
66
  }
62
67
 
63
- function collectModels(config) {
68
+ function collectDirectModels(config) {
64
69
  const list = Array.isArray(config.availableModels) && config.availableModels.length > 0
65
70
  ? [config.model, config.fastModel, ...config.availableModels]
66
71
  : [config.model, config.fastModel];
67
72
  return [...new Set(list.filter(Boolean).map(toDesktopModelId))];
68
73
  }
69
74
 
70
- // 按官方 schema:所有值必须是字符串(包括布尔、数组都序列化)
75
+ function buildGatewayBaseUrl(config) {
76
+ const port = config.desktopGatewayPort || 18080;
77
+ return `http://127.0.0.1:${port}${YINGCLAW_GATEWAY_PREFIX}`;
78
+ }
79
+
80
+ function serializeGatewayModels(config) {
81
+ return buildDesktopGatewayRoutes(config).map((route) => {
82
+ const item = { name: route.id, displayName: route.displayName };
83
+ if (route.supports1m) item.supports1m = true;
84
+ return item;
85
+ });
86
+ }
87
+
71
88
  function buildClaudeDesktopEnterpriseConfig(config, options = {}) {
72
- const models = collectModels(config);
89
+ const gatewayConfig = ensureDesktopGatewayConfig(config, options);
90
+ const models = serializeGatewayModels(gatewayConfig);
91
+ return {
92
+ inferenceProvider: 'gateway',
93
+ inferenceGatewayBaseUrl: buildGatewayBaseUrl(gatewayConfig),
94
+ inferenceGatewayApiKey: gatewayConfig.desktopGatewayKey,
95
+ inferenceGatewayAuthScheme: options.authScheme || 'bearer',
96
+ inferenceModels: JSON.stringify(models),
97
+ disableDeploymentModeChooser: 'true',
98
+ deploymentOrganizationUuid: options.uuid || crypto.randomUUID(),
99
+ };
100
+ }
101
+
102
+ // 兼容旧版直连模式:写入真实 provider Gateway URL 和真实 Key。
103
+ function buildClaudeDesktopDirectEnterpriseConfig(config, options = {}) {
104
+ const models = collectDirectModels(config);
73
105
  const baseUrl = normalizeAnthropicBaseUrl(config.baseUrl);
74
106
  if (!baseUrl.startsWith('https://')) {
75
107
  throw new Error('Claude 桌面应用要求 Gateway Base URL 使用 HTTPS');
@@ -131,10 +163,9 @@ function clearClaudeDesktopConfigLibrary(options = {}) {
131
163
 
132
164
  // 写入 Claude-3p/configLibrary/ 下的 enterprise config 条目(主进程从此处读取)
133
165
  function writeClaudeDesktopConfig(config, options = {}) {
134
- const baseUrl = normalizeAnthropicBaseUrl(config.baseUrl);
135
- if (!baseUrl.startsWith('https://')) {
136
- throw new Error('Claude 桌面应用要求 Gateway Base URL 使用 HTTPS');
137
- }
166
+ const effectiveConfig = options.direct
167
+ ? config
168
+ : ensureDesktopGatewayConfig(config, options);
138
169
 
139
170
  const dataDir = options.dataDir || getClaudeDesktopDataDir(options);
140
171
  if (!dataDir) {
@@ -149,13 +180,18 @@ function writeClaudeDesktopConfig(config, options = {}) {
149
180
  const existingYingclaw = existingEntries.find((entry) => entry && entry.name === YINGCLAW_ENTRY_NAME);
150
181
  const uuid = existingYingclaw?.id || options.uuid || crypto.randomUUID();
151
182
 
152
- const models = collectModels(config);
183
+ const models = options.direct
184
+ ? collectDirectModels(effectiveConfig)
185
+ : serializeGatewayModels(effectiveConfig);
186
+ const enterprise = options.direct
187
+ ? buildClaudeDesktopDirectEnterpriseConfig(effectiveConfig, { ...options, uuid })
188
+ : buildClaudeDesktopEnterpriseConfig(effectiveConfig, { ...options, uuid });
153
189
 
154
190
  const entry = {
155
- inferenceProvider: 'gateway',
156
- inferenceGatewayBaseUrl: baseUrl,
157
- inferenceGatewayApiKey: config.apiKey,
158
- inferenceGatewayAuthScheme: options.authScheme || 'bearer',
191
+ inferenceProvider: enterprise.inferenceProvider,
192
+ inferenceGatewayBaseUrl: enterprise.inferenceGatewayBaseUrl,
193
+ inferenceGatewayApiKey: enterprise.inferenceGatewayApiKey,
194
+ inferenceGatewayAuthScheme: enterprise.inferenceGatewayAuthScheme,
159
195
  inferenceModels: models,
160
196
  disableDeploymentModeChooser: true,
161
197
  deploymentOrganizationUuid: uuid,
@@ -184,7 +220,7 @@ function writeClaudeDesktopConfig(config, options = {}) {
184
220
  fs.mkdirSync(path.dirname(file), { recursive: true });
185
221
  fs.writeFileSync(file, JSON.stringify(next, null, 2) + '\n');
186
222
 
187
- return { result: beforeEntry === entryBody ? 'unchanged' : 'updated', file };
223
+ return { result: beforeEntry === entryBody ? 'unchanged' : 'updated', file, config: effectiveConfig };
188
224
  }
189
225
 
190
226
  function clearClaudeDesktopConfig(options = {}) {
@@ -293,8 +329,10 @@ async function openClaudeDesktop(options = {}) {
293
329
 
294
330
  module.exports = {
295
331
  buildClaudeDesktopEnterpriseConfig,
332
+ buildClaudeDesktopDirectEnterpriseConfig,
296
333
  buildClaudeDesktopOpenCommands,
297
334
  clearClaudeDesktopConfig,
335
+ getClaudeDesktopConfigLibraryDir,
298
336
  getClaudeDesktopConfigPath,
299
337
  getClaudeDesktopDataDir,
300
338
  isDesktopConfigured,
package/lib/gateway.js ADDED
@@ -0,0 +1,198 @@
1
+ const crypto = require('crypto');
2
+ const http = require('http');
3
+ const { loadConfig: defaultLoadConfig, normalizeAnthropicBaseUrl } = require('./config');
4
+
5
+ const DEFAULT_DESKTOP_GATEWAY_PORT = 18080;
6
+ const YINGCLAW_GATEWAY_PREFIX = '/yingclaw';
7
+ const DESKTOP_ROUTE_SPECS = [
8
+ { id: 'claude-sonnet-4-6', displayName: 'Sonnet', upstreamKey: 'model' },
9
+ { id: 'claude-opus-4-7', displayName: 'Opus', upstreamKey: 'model' },
10
+ { id: 'claude-haiku-4-5', displayName: 'Haiku', upstreamKey: 'fastModel' },
11
+ ];
12
+
13
+ function createGatewayKey() {
14
+ return `ygw-${crypto.randomUUID()}`;
15
+ }
16
+
17
+ function ensureDesktopGatewayConfig(config, options = {}) {
18
+ const keyFactory = options.keyFactory || createGatewayKey;
19
+ return {
20
+ ...config,
21
+ desktopGatewayPort: config.desktopGatewayPort || DEFAULT_DESKTOP_GATEWAY_PORT,
22
+ desktopGatewayKey: config.desktopGatewayKey || keyFactory(),
23
+ };
24
+ }
25
+
26
+ function modelSupports1m(model) {
27
+ return /\[1m\]/i.test(String(model || ''));
28
+ }
29
+
30
+ function buildDesktopGatewayRoutes(config) {
31
+ const fastModel = config.fastModel || config.model;
32
+ const source = { model: config.model, fastModel };
33
+ return DESKTOP_ROUTE_SPECS
34
+ .map((spec) => {
35
+ const upstreamModel = source[spec.upstreamKey];
36
+ return upstreamModel ? {
37
+ id: spec.id,
38
+ displayName: spec.displayName,
39
+ upstreamModel,
40
+ supports1m: modelSupports1m(upstreamModel),
41
+ } : null;
42
+ })
43
+ .filter(Boolean);
44
+ }
45
+
46
+ function mapDesktopRouteToUpstream(config, routeId) {
47
+ const route = buildDesktopGatewayRoutes(config).find((item) => item.id === routeId);
48
+ if (!route) {
49
+ throw new Error(`未配置的 Claude Desktop 模型路由: ${routeId}`);
50
+ }
51
+ return route.upstreamModel;
52
+ }
53
+
54
+ function buildGatewayModelsResponse(config) {
55
+ const data = buildDesktopGatewayRoutes(config).map((route) => {
56
+ const item = {
57
+ type: 'model',
58
+ id: route.id,
59
+ display_name: route.displayName,
60
+ created_at: '2024-01-01T00:00:00Z',
61
+ };
62
+ if (route.supports1m) item.supports1m = true;
63
+ return item;
64
+ });
65
+ return {
66
+ data,
67
+ has_more: false,
68
+ first_id: data[0]?.id || null,
69
+ last_id: data.at(-1)?.id || null,
70
+ };
71
+ }
72
+
73
+ function sendJson(res, status, body) {
74
+ res.writeHead(status, { 'content-type': 'application/json' });
75
+ res.end(JSON.stringify(body));
76
+ }
77
+
78
+ function readRequestBody(req) {
79
+ return new Promise((resolve, reject) => {
80
+ let raw = '';
81
+ req.setEncoding('utf8');
82
+ req.on('data', chunk => { raw += chunk; });
83
+ req.on('end', () => resolve(raw));
84
+ req.on('error', reject);
85
+ });
86
+ }
87
+
88
+ function isAuthorized(req, config) {
89
+ const key = config.desktopGatewayKey;
90
+ if (!key) return false;
91
+ const auth = String(req.headers.authorization || '');
92
+ const bearer = auth.replace(/^bearer\s+/i, '').trim();
93
+ const apiKey = String(req.headers['x-api-key'] || '').trim();
94
+ return bearer === key || apiKey === key;
95
+ }
96
+
97
+ function providerMessagesUrl(config) {
98
+ return `${normalizeAnthropicBaseUrl(config.baseUrl)}/v1/messages`;
99
+ }
100
+
101
+ async function proxyMessages(req, res, config) {
102
+ const raw = await readRequestBody(req);
103
+ let body;
104
+ try {
105
+ body = raw ? JSON.parse(raw) : {};
106
+ } catch {
107
+ sendJson(res, 400, { error: { message: '请求体不是有效 JSON' } });
108
+ return;
109
+ }
110
+
111
+ try {
112
+ body.model = mapDesktopRouteToUpstream(config, body.model);
113
+ } catch (error) {
114
+ sendJson(res, 400, { error: { message: error.message } });
115
+ return;
116
+ }
117
+
118
+ const upstream = await fetch(providerMessagesUrl(config), {
119
+ method: 'POST',
120
+ headers: {
121
+ 'content-type': 'application/json',
122
+ accept: body.stream ? 'text/event-stream' : 'application/json',
123
+ authorization: `Bearer ${config.apiKey}`,
124
+ 'x-api-key': config.apiKey,
125
+ 'anthropic-version': '2023-06-01',
126
+ },
127
+ body: JSON.stringify(body),
128
+ });
129
+
130
+ res.writeHead(upstream.status, {
131
+ 'content-type': upstream.headers.get('content-type') || (body.stream ? 'text/event-stream' : 'application/json'),
132
+ 'cache-control': upstream.headers.get('cache-control') || 'no-cache',
133
+ });
134
+
135
+ if (!upstream.body) {
136
+ res.end();
137
+ return;
138
+ }
139
+ for await (const chunk of upstream.body) {
140
+ res.write(chunk);
141
+ }
142
+ res.end();
143
+ }
144
+
145
+ function createGatewayServer(options = {}) {
146
+ const loadConfig = options.loadConfig || defaultLoadConfig;
147
+ return http.createServer(async (req, res) => {
148
+ try {
149
+ const url = new URL(req.url, 'http://127.0.0.1');
150
+ const config = loadConfig();
151
+
152
+ if (url.pathname === `${YINGCLAW_GATEWAY_PREFIX}/health`) {
153
+ sendJson(res, 200, { status: 'ok' });
154
+ return;
155
+ }
156
+
157
+ if (!config) {
158
+ sendJson(res, 503, { error: { message: 'yingclaw 尚未配置 API 连接' } });
159
+ return;
160
+ }
161
+
162
+ if (url.pathname === `${YINGCLAW_GATEWAY_PREFIX}/v1/models` && req.method === 'GET') {
163
+ if (!isAuthorized(req, config)) {
164
+ sendJson(res, 401, { error: { message: 'Invalid gateway API key' } });
165
+ return;
166
+ }
167
+ sendJson(res, 200, buildGatewayModelsResponse(config));
168
+ return;
169
+ }
170
+
171
+ if (url.pathname === `${YINGCLAW_GATEWAY_PREFIX}/v1/messages` && req.method === 'POST') {
172
+ if (!isAuthorized(req, config)) {
173
+ sendJson(res, 401, { error: { message: 'Invalid gateway API key' } });
174
+ return;
175
+ }
176
+ await proxyMessages(req, res, config);
177
+ return;
178
+ }
179
+
180
+ sendJson(res, 404, { error: { message: 'Not found' } });
181
+ } catch (error) {
182
+ sendJson(res, 500, { error: { message: error.message } });
183
+ }
184
+ });
185
+ }
186
+
187
+ module.exports = {
188
+ DEFAULT_DESKTOP_GATEWAY_PORT,
189
+ YINGCLAW_GATEWAY_PREFIX,
190
+ DESKTOP_ROUTE_SPECS,
191
+ createGatewayKey,
192
+ ensureDesktopGatewayConfig,
193
+ modelSupports1m,
194
+ buildDesktopGatewayRoutes,
195
+ mapDesktopRouteToUpstream,
196
+ buildGatewayModelsResponse,
197
+ createGatewayServer,
198
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {