@yeaft/webchat-agent 0.1.239 → 0.1.241

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.
@@ -15,10 +15,20 @@ const PM2_APP_NAME = 'yeaft-agent';
15
15
  // but process.execPath always points to the running node binary.
16
16
  const nodeBinDir = dirname(process.execPath);
17
17
  const isWin = platform() === 'win32';
18
- const npmPath = join(nodeBinDir, isWin ? 'npm.cmd' : 'npm');
19
- const pm2Path = join(nodeBinDir, isWin ? 'pm2.cmd' : 'pm2');
18
+ // Windows: use bare 'npm'/'pm2' + shell:true — cmd.exe finds them via PATH.
19
+ // This was the working pattern before ce58bbc. Absolute paths break when
20
+ // the path contains spaces (e.g., "C:\Program Files\nodejs\npm.cmd").
21
+ // macOS/Linux: use absolute path — launchd/systemd have minimal PATH.
22
+ const npmPath = isWin ? 'npm' : join(nodeBinDir, 'npm');
23
+ const pm2Path = isWin ? 'pm2' : join(nodeBinDir, 'pm2');
20
24
  const shellOpt = isWin ? { shell: true } : {};
21
25
 
26
+ // Ensure PATH includes nodeBinDir so that `#!/usr/bin/env node` shebangs
27
+ // can locate node in launchd/systemd environments with minimal PATH.
28
+ const currentPath = process.env.PATH || '/usr/bin:/bin:/usr/sbin:/sbin';
29
+ const safePath = currentPath.includes(nodeBinDir) ? currentPath : `${nodeBinDir}:${currentPath}`;
30
+ const safeEnv = { ...process.env, PATH: safePath };
31
+
22
32
  // Shared cleanup logic for restart/upgrade
23
33
  function cleanupAndExit(exitCode) {
24
34
  setTimeout(() => {
@@ -55,7 +65,7 @@ export async function handleUpgradeAgent() {
55
65
  const pkgName = ctx.pkgName || '@yeaft/webchat-agent';
56
66
  // Check latest version (async to avoid blocking heartbeat)
57
67
  const latestVersion = await new Promise((resolve, reject) => {
58
- execFile(npmPath, ['view', pkgName, 'version'], { stdio: 'pipe', ...shellOpt }, (err, stdout) => {
68
+ execFile(npmPath, ['view', pkgName, 'version'], { stdio: 'pipe', env: safeEnv, ...shellOpt }, (err, stdout) => {
59
69
  if (err) reject(err); else resolve(stdout.toString().trim());
60
70
  });
61
71
  });
@@ -83,7 +93,7 @@ export async function handleUpgradeAgent() {
83
93
 
84
94
  // 判断全局安装 vs 局部安装
85
95
  const isGlobalInstall = await new Promise((resolve) => {
86
- execFile(npmPath, ['prefix', '-g'], { ...shellOpt }, (err, stdout) => {
96
+ execFile(npmPath, ['prefix', '-g'], { env: safeEnv, ...shellOpt }, (err, stdout) => {
87
97
  if (err) { resolve(false); return; }
88
98
  const globalPrefix = stdout.toString().trim().replace(/\\/g, '/');
89
99
  resolve(installDir === globalPrefix || installDir === globalPrefix + '/lib');
@@ -103,7 +113,7 @@ export async function handleUpgradeAgent() {
103
113
  const isPm2 = !!process.env.pm_id;
104
114
  if (isPm2) {
105
115
  try {
106
- execFileSync(pm2Path, ['delete', PM2_APP_NAME], { stdio: 'pipe', ...shellOpt });
116
+ execFileSync(pm2Path, ['delete', PM2_APP_NAME], { stdio: 'pipe', env: safeEnv, ...shellOpt });
107
117
  console.log(`[Agent] PM2 app deleted to prevent auto-restart during upgrade`);
108
118
  } catch {
109
119
  console.log(`[Agent] PM2 delete skipped (app may not be registered)`);
@@ -252,17 +262,13 @@ function spawnUnixUpgradeScript(pkgName, installDir, isGlobalInstall, latestVers
252
262
  const isLaunchd = platform() === 'darwin' && existsSync(join(process.env.HOME || '', 'Library', 'LaunchAgents', 'com.yeaft.agent.plist'));
253
263
  const cwd = isGlobalInstall ? undefined : installDir;
254
264
 
255
- // Ensure PATH includes the node bin dir (critical for launchd which has minimal PATH)
256
- const currentPath = process.env.PATH || '/usr/bin:/bin:/usr/sbin:/sbin';
257
- const exportPath = currentPath.includes(nodeBinDir) ? currentPath : `${nodeBinDir}:${currentPath}`;
258
-
259
265
  const shLines = [
260
266
  '#!/bin/bash',
261
267
  `PID=${pid}`,
262
268
  `PKG="${pkgName}@latest"`,
263
269
  `NPM="${npmPath}"`,
264
270
  `LOGFILE="${join(configDir, 'logs', 'upgrade.log')}"`,
265
- `export PATH="${exportPath}"`,
271
+ `export PATH="${safePath}"`,
266
272
  '',
267
273
  '# Redirect all output to log file',
268
274
  'exec > "$LOGFILE" 2>&1',
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'dotenv/config';
2
2
  import { platform, homedir } from 'os';
3
- import { existsSync, readFileSync, writeFileSync } from 'fs';
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
4
4
  import { join, dirname } from 'path';
5
5
  import { exec } from 'child_process';
6
6
  import { promisify } from 'util';
@@ -138,6 +138,35 @@ async function ensureDependencies() {
138
138
  }
139
139
  }
140
140
 
141
+ // 确保 yeaft-skills 插件已安装/更新
142
+ async function ensureYeaftSkills() {
143
+ const skillsDir = join(homedir(), '.claude', 'skills', 'yeaft-skills');
144
+ const REPO_URL = 'https://github.com/yeaft/yeaft-skills.git';
145
+
146
+ try {
147
+ if (!existsSync(skillsDir)) {
148
+ console.log('[Startup] yeaft-skills not found, installing...');
149
+ const parentDir = join(homedir(), '.claude', 'skills');
150
+ mkdirSync(parentDir, { recursive: true });
151
+ await execAsync(`git clone ${REPO_URL} "${skillsDir}"`, { timeout: 60000 });
152
+ console.log('[Startup] yeaft-skills installed');
153
+ } else {
154
+ console.log('[Startup] yeaft-skills found, checking for updates...');
155
+ const { stdout } = await execAsync('git pull --ff-only', {
156
+ cwd: skillsDir,
157
+ timeout: 30000
158
+ });
159
+ if (stdout.includes('Already up to date')) {
160
+ console.log('[Startup] yeaft-skills is up to date');
161
+ } else {
162
+ console.log('[Startup] yeaft-skills updated');
163
+ }
164
+ }
165
+ } catch (e) {
166
+ console.warn('[Startup] yeaft-skills sync failed (skills will be unavailable):', e.message);
167
+ }
168
+ }
169
+
141
170
  // 优雅退出
142
171
  function cleanup() {
143
172
  // 清理所有终端
@@ -176,6 +205,7 @@ process.on('SIGTERM', () => {
176
205
  // 启动 - 先确保依赖,再检测能力,再连接
177
206
  (async () => {
178
207
  await ensureDependencies();
208
+ await ensureYeaftSkills();
179
209
  ctx.agentCapabilities = await detectCapabilities();
180
210
  connect();
181
211
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.239",
3
+ "version": "0.1.241",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",