yingclaw 2.5.11 → 2.5.13

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
@@ -93,9 +93,9 @@ claw setup # 兼容旧命令:config + code
93
93
 
94
94
  | 平台 | 终端接入 | 桌面接入 |
95
95
  |------|---------|---------|
96
- | macOS | ✅ 写入 `~/.zshrc` | ✅ 自动重启 Claude Desktop |
96
+ | macOS | ✅ 写入 `~/.zshrc` | ✅ 自动启动本机 Gateway 并重启 Claude Desktop |
97
97
  | Linux / WSL | ✅ 写入 `~/.zshrc` / `~/.bashrc` | — |
98
- | Windows | ✅ 写入用户级环境变量(需重开终端) | ✅ 写入 `%APPDATA%\Claude-3p\` |
98
+ | Windows | ✅ 写入用户级环境变量(需重开终端) | ✅ 写入 `%APPDATA%\Claude-3p\`,并写入登录启动脚本 |
99
99
 
100
100
  ## 原理
101
101
 
@@ -115,6 +115,7 @@ CLAUDE_CODE_EFFORT_LEVEL
115
115
  - macOS / Windows:写入 `Claude-3p/configLibrary/` 中的 yingclaw entry
116
116
  - Claude Desktop 访问 `http://127.0.0.1:18080/yingclaw`
117
117
  - Gateway 再转发到当前保存的 Anthropic 兼容接口
118
+ - macOS 使用 LaunchAgent 登录启动 Gateway,Windows 使用 Startup 目录脚本登录启动 Gateway
118
119
  - 终端接入仍直接使用 `ANTHROPIC_*` 环境变量,不受桌面 Gateway 影响
119
120
 
120
121
  使用 `inferenceProvider=gateway`、`inferenceGatewayAuthScheme=bearer`,将 Gateway Base URL 指向 yingclaw 本机 Gateway。高级用户可用 `claw desktop --direct` 保留旧式直连写入,但新版 Claude Desktop 可能拒绝非 Claude 模型名。
package/lib/autostart.js CHANGED
@@ -1,9 +1,10 @@
1
1
  const fs = require('fs');
2
2
  const os = require('os');
3
3
  const path = require('path');
4
- const { spawnSync } = require('child_process');
4
+ const { spawn, spawnSync } = require('child_process');
5
5
 
6
6
  const GATEWAY_LAUNCH_AGENT_LABEL = 'com.yingclaw.gateway';
7
+ const WINDOWS_GATEWAY_STARTUP_SCRIPT = 'yingclaw-gateway.cmd';
7
8
 
8
9
  function xmlEscape(value) {
9
10
  return String(value)
@@ -19,6 +20,12 @@ function getMacLaunchAgentPath(options = {}) {
19
20
  return path.join(homeDir, 'Library', 'LaunchAgents', `${GATEWAY_LAUNCH_AGENT_LABEL}.plist`);
20
21
  }
21
22
 
23
+ function getWindowsStartupScriptPath(options = {}) {
24
+ const homeDir = options.homeDir || os.homedir();
25
+ const appData = options.appData || process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
26
+ return path.join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', WINDOWS_GATEWAY_STARTUP_SCRIPT);
27
+ }
28
+
22
29
  function buildMacLaunchAgentPlist(options = {}) {
23
30
  const nodePath = options.nodePath || process.execPath;
24
31
  const cliPath = options.cliPath || path.join(__dirname, '..', 'bin', 'cli.js');
@@ -54,6 +61,34 @@ function buildMacLaunchAgentPlist(options = {}) {
54
61
  `;
55
62
  }
56
63
 
64
+ function buildWindowsGatewayStartupScript(options = {}) {
65
+ const nodePath = options.nodePath || process.execPath;
66
+ const cliPath = options.cliPath || path.join(__dirname, '..', 'bin', 'cli.js');
67
+ const workingDirectory = options.workingDirectory || path.join(__dirname, '..');
68
+
69
+ return [
70
+ '@echo off',
71
+ `cd /d "${workingDirectory}"`,
72
+ `start "" /min "${nodePath}" "${cliPath}" gateway`,
73
+ '',
74
+ ].join('\r\n');
75
+ }
76
+
77
+ function startWindowsGateway(options = {}) {
78
+ const starter = options.starter || spawn;
79
+ const nodePath = options.nodePath || process.execPath;
80
+ const cliPath = options.cliPath || path.join(__dirname, '..', 'bin', 'cli.js');
81
+ const workingDirectory = options.workingDirectory || path.join(__dirname, '..');
82
+ const child = starter(nodePath, [cliPath, 'gateway'], {
83
+ cwd: workingDirectory,
84
+ detached: true,
85
+ stdio: 'ignore',
86
+ windowsHide: true,
87
+ });
88
+ if (child && typeof child.unref === 'function') child.unref();
89
+ return true;
90
+ }
91
+
57
92
  function runLaunchctl(runner, args, options = {}) {
58
93
  const result = runner('launchctl', args, { encoding: 'utf8', stdio: 'pipe' });
59
94
  if (result.status !== 0 && !options.optional) {
@@ -92,8 +127,30 @@ function waitForLaunchAgentUnload(runner, service, options = {}) {
92
127
  } while (true);
93
128
  }
94
129
 
130
+ function isWindowsPortListening(runner, port) {
131
+ const result = runner('powershell.exe', [
132
+ '-NoProfile',
133
+ '-Command',
134
+ `if (Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort ${Number(port)} -State Listen -ErrorAction SilentlyContinue) { 'LISTEN' }`,
135
+ ], { encoding: 'utf8', stdio: 'pipe', windowsHide: true });
136
+ return result.status === 0 && /LISTEN/i.test(`${result.stdout || ''}\n${result.stderr || ''}`);
137
+ }
138
+
95
139
  function installGatewayAutostart(options = {}) {
96
140
  const platform = options.platform || process.platform;
141
+ if (platform === 'win32') {
142
+ const file = options.file || getWindowsStartupScriptPath(options);
143
+ const runner = options.runner || spawnSync;
144
+ const port = options.port || 18080;
145
+ const wasRunning = isWindowsPortListening(runner, port);
146
+ fs.mkdirSync(path.dirname(file), { recursive: true });
147
+ fs.writeFileSync(file, buildWindowsGatewayStartupScript(options), 'utf8');
148
+ const started = !wasRunning && options.startNow !== false
149
+ ? startWindowsGateway(options)
150
+ : false;
151
+ return { result: 'installed', file, started };
152
+ }
153
+
97
154
  if (platform !== 'darwin') {
98
155
  return { result: 'unsupported', file: null };
99
156
  }
@@ -133,6 +190,18 @@ function installGatewayAutostart(options = {}) {
133
190
 
134
191
  function getGatewayAutostartStatus(options = {}) {
135
192
  const platform = options.platform || process.platform;
193
+ if (platform === 'win32') {
194
+ const file = options.file || getWindowsStartupScriptPath(options);
195
+ const runner = options.runner || spawnSync;
196
+ const port = options.port || 18080;
197
+ return {
198
+ supported: true,
199
+ installed: fs.existsSync(file),
200
+ running: isWindowsPortListening(runner, port),
201
+ file,
202
+ };
203
+ }
204
+
136
205
  if (platform !== 'darwin') {
137
206
  return { supported: false, installed: false, running: false, file: null };
138
207
  }
@@ -162,7 +231,10 @@ function getGatewayAutostartStatus(options = {}) {
162
231
  module.exports = {
163
232
  GATEWAY_LAUNCH_AGENT_LABEL,
164
233
  buildMacLaunchAgentPlist,
234
+ buildWindowsGatewayStartupScript,
235
+ startWindowsGateway,
165
236
  getGatewayAutostartStatus,
166
237
  getMacLaunchAgentPath,
238
+ getWindowsStartupScriptPath,
167
239
  installGatewayAutostart,
168
240
  };
package/lib/desktop.js CHANGED
@@ -363,11 +363,27 @@ function buildClaudeDesktopOpenCommands(platform = process.platform, options = {
363
363
  const localAppData = options.localAppData
364
364
  || process.env.LOCALAPPDATA
365
365
  || `${options.homeDir || os.homedir()}\\AppData\\Local`;
366
- const claudeDir = `${localAppData}\\AnthropicClaude`;
367
- // taskkill /T 连带杀子进程;start "" /D 切到 Claude 目录后启动 Claude.exe(Squirrel 标准安装位置)
366
+ const fileExists = options.fileExists || fs.existsSync;
367
+ const exeCandidates = [
368
+ `${localAppData}\\Programs\\Claude\\Claude.exe`,
369
+ `${localAppData}\\AnthropicClaude\\Claude.exe`,
370
+ ];
371
+ const updateCandidates = [
372
+ `${localAppData}\\AnthropicClaude\\Update.exe`,
373
+ `${localAppData}\\Programs\\Claude\\Update.exe`,
374
+ ];
375
+ const foundExe = exeCandidates.find((file) => fileExists(file));
376
+ const foundUpdate = foundExe ? null : updateCandidates.find((file) => fileExists(file));
377
+ const fallbackDir = `${localAppData}\\AnthropicClaude`;
378
+ const launchCommand = foundExe
379
+ ? { command: 'cmd', args: ['/c', 'start', '', '/D', path.win32.dirname(foundExe), 'Claude.exe'], optional: true, waitAfter: 800 }
380
+ : foundUpdate
381
+ ? { command: foundUpdate, args: ['--processStart', 'Claude.exe'], optional: true, waitAfter: 800 }
382
+ : { command: 'cmd', args: ['/c', 'start', '', '/D', fallbackDir, 'Claude.exe'], optional: true, waitAfter: 800 };
383
+ // taskkill /T 连带杀子进程;启动路径按实际安装位置选择,找不到时保留旧的 Squirrel 目录兜底
368
384
  return [
369
385
  { command: 'taskkill', args: ['/IM', 'Claude.exe', '/F', '/T'], optional: true, waitAfter: 1500 },
370
- { command: 'cmd', args: ['/c', 'start', '', '/D', claudeDir, 'Claude.exe'], optional: true, waitAfter: 800 },
386
+ launchCommand,
371
387
  ];
372
388
  }
373
389
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yingclaw",
3
- "version": "2.5.11",
3
+ "version": "2.5.13",
4
4
  "description": "Claude Code × 国产大模型一键接入:DeepSeek、Kimi、Qwen、MiniMax、GLM、MiMo",
5
5
  "main": "index.js",
6
6
  "bin": {