chatccc 0.2.162 → 0.2.164

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/orchestrator.ts +76 -34
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.162",
3
+ "version": "0.2.164",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -7,8 +7,9 @@
7
7
 
8
8
  import { execSync, spawn } from "node:child_process";
9
9
  import { readdir, stat } from "node:fs/promises";
10
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
11
- import { resolve, dirname } from "node:path";
10
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
11
+ import { join, resolve, dirname } from "node:path";
12
+ import { homedir } from "node:os";
12
13
 
13
14
  import { makeTraceId, logTrace } from "./trace.ts";
14
15
  import { appendStartupTrace } from "./shared.ts";
@@ -169,33 +170,73 @@ function isRunningFromGlobalNpm(): boolean {
169
170
  }
170
171
  }
171
172
 
172
- /** 更新并重启:spawn detached Node.js 中间脚本,轮询父进程退出后执行 npm update + chatccc */
173
- function scheduleUpdateRestart(): void {
174
- const parentPid = process.pid;
175
- const watcherScript = `
176
- var spawn = require('child_process').spawn;
177
- var execSync = require('child_process').execSync;
178
- var parentPid = ${parentPid};
179
- (function wait() {
180
- try { process.kill(parentPid, 0); setTimeout(wait, 300); } catch (_) {
181
- try {
182
- var npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
183
- execSync(npmCmd + ' update -g chatccc', { stdio: 'inherit' });
184
- } catch (e) {
185
- console.error('npm update failed:', e.message);
186
- }
187
- var c = spawn('chatccc', [], { detached: true, stdio: 'ignore', shell: true });
188
- c.unref();
189
- process.exit(0);
190
- }
191
- })();
192
- `;
193
- const child = spawn("node", ["-e", watcherScript], {
194
- detached: true,
195
- stdio: "ignore",
196
- shell: true,
197
- });
198
- child.unref();
173
+ const UPDATEG_LOG = join(homedir(), ".chatccc", "logs", "updateg-watcher.log");
174
+
175
+ function updLog(msg: string): void {
176
+ const ts = new Date().toISOString();
177
+ try { appendFileSync(UPDATEG_LOG, `${ts} [UPG-SYNC] ${msg}\n`, "utf-8"); } catch {}
178
+ }
179
+
180
+ /** 同步更新 npm 全局包并重启(父进程存活等待,避免 systemd KillMode=control-group 杀 watcher) */
181
+ function syncUpdateAndRestart(): void {
182
+ updLog(`sync update start, pid=${process.pid}`);
183
+ appendStartupTrace("updateg: sync update start", { pid: process.pid });
184
+
185
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
186
+
187
+ // 1. npm update
188
+ updLog(`running: ${npmCmd} update -g chatccc`);
189
+ appendStartupTrace("updateg: npm update begin", { npmCmd });
190
+ const t0 = Date.now();
191
+ try {
192
+ const out = execSync(`${npmCmd} update -g chatccc 2>&1`, { encoding: "utf8", timeout: 120000, windowsHide: true });
193
+ const elapsed = Date.now() - t0;
194
+ updLog(`npm update OK (${elapsed}ms): ${out.slice(0, 500)}`);
195
+ appendStartupTrace("updateg: npm update OK", { elapsedMs: elapsed, outputLen: out.length });
196
+ } catch (e) {
197
+ const elapsed = Date.now() - t0;
198
+ const err = e as Error & { stderr?: string; stdout?: string; status?: number };
199
+ updLog(`npm update failed (${elapsed}ms): message=${err.message}, stderr=${(err.stderr || "").slice(0, 500)}, stdout=${(err.stdout || "").slice(0, 200)}`);
200
+ appendStartupTrace("updateg: npm update failed", { elapsedMs: elapsed, message: err.message, stderrLen: (err.stderr || "").length });
201
+
202
+ // fallback
203
+ updLog(`fallback: ${npmCmd} install -g chatccc@latest`);
204
+ appendStartupTrace("updateg: npm install fallback begin", { npmCmd });
205
+ const t1 = Date.now();
206
+ try {
207
+ const out2 = execSync(`${npmCmd} install -g chatccc@latest 2>&1`, { encoding: "utf8", timeout: 120000, windowsHide: true });
208
+ const elapsed2 = Date.now() - t1;
209
+ updLog(`npm install fallback OK (${elapsed2}ms): ${out2.slice(0, 500)}`);
210
+ appendStartupTrace("updateg: npm install fallback OK", { elapsedMs: elapsed2, outputLen: out2.length });
211
+ } catch (e2) {
212
+ const elapsed2 = Date.now() - t1;
213
+ const err2 = e2 as Error & { stderr?: string; stdout?: string };
214
+ updLog(`npm install fallback also failed (${elapsed2}ms): message=${err2.message}, stderr=${(err2.stderr || "").slice(0, 500)}`);
215
+ appendStartupTrace("updateg: npm install fallback failed", { elapsedMs: elapsed2, message: err2.message });
216
+ }
217
+ }
218
+
219
+ // 2. resolve bin path
220
+ const npmPrefix = process.env.NPM_PREFIX || "";
221
+ const binName = process.platform === "win32" ? "chatccc.cmd" : "chatccc";
222
+ const binPath = npmPrefix ? join(npmPrefix, binName) : "chatccc";
223
+ updLog(`bin path: npmPrefix=${npmPrefix || "(empty)"}, binPath=${binPath}`);
224
+ appendStartupTrace("updateg: spawn begin", { npmPrefix: npmPrefix || "(empty)", binPath });
225
+
226
+ // 3. spawn new chatccc
227
+ try {
228
+ const child = spawn(binPath, [], { detached: true, stdio: "ignore", shell: true });
229
+ child.unref();
230
+ updLog(`spawn new chatccc OK, childPid=${child.pid}, bin=${binPath}`);
231
+ appendStartupTrace("updateg: spawn OK", { childPid: child.pid, binPath });
232
+ } catch (e) {
233
+ const errMsg = (e as Error).message;
234
+ updLog(`spawn new chatccc failed: ${errMsg}`);
235
+ appendStartupTrace("updateg: spawn failed", { error: errMsg });
236
+ }
237
+
238
+ updLog("sync update done, parent exiting in 2s");
239
+ appendStartupTrace("updateg: sync update done, exiting in 2s", { pid: process.pid });
199
240
  }
200
241
 
201
242
  // ---------------------------------------------------------------------------
@@ -253,17 +294,18 @@ export async function handleCommand(
253
294
 
254
295
  if (textLower === "/updateg") {
255
296
  logTrace(tid, "BRANCH", { cmd: "/updateg" });
256
- if (!isRunningFromGlobalNpm()) {
297
+ const isGlobal = isRunningFromGlobalNpm();
298
+ appendStartupTrace("updateg: command received", { isGlobal, chatId });
299
+ if (!isGlobal) {
257
300
  await platform.sendText(chatId, "当前进程非 npm 全局安装,无法使用 /updateg 更新。请通过 npm install -g chatccc 安装后使用。").catch(() => {});
258
301
  logTrace(tid, "DONE", { outcome: "updateg_not_global" });
259
302
  return;
260
303
  }
261
304
  await platform.sendText(chatId, "正在更新并重启,请稍候...").catch(() => {});
262
305
  logTrace(tid, "DONE", { outcome: "updateg" });
263
- appendStartupTrace("updateg: spawn watcher begin", { fromPid: process.pid });
264
- scheduleUpdateRestart();
265
- // 短暂延迟确保消息发送后再退出
266
- setTimeout(() => process.exit(0), 500);
306
+ appendStartupTrace("updateg: sync update begin", { fromPid: process.pid });
307
+ syncUpdateAndRestart();
308
+ setTimeout(() => process.exit(0), 2000);
267
309
  return;
268
310
  }
269
311