tt-help-cli-ycl 1.4.134 → 1.4.135

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.
@@ -27,6 +27,44 @@ import { join, dirname } from "path";
27
27
  import { homedir, tmpdir } from "os";
28
28
  import { fileURLToPath } from "url";
29
29
 
30
+ // ── 看门狗自身日志环形缓冲(供后台页面按需拉取,经 report-logs 回传落盘) ──
31
+ // 包装 console.error:本进程所有 [watchdog]/[llm-analyzer]/[upgrade] 等日志
32
+ // 在正常输出的同时进内存环,最多保留 500 行。
33
+ // 托管进程日志走 process-manager 的 printProcessLine(stderr.write),不混入此环。
34
+ const WATCHDOG_SELF_LOG_MAX = 500;
35
+ const watchdogSelfLogs = [];
36
+ const _origConsoleError = console.error.bind(console);
37
+ console.error = (...args) => {
38
+ try {
39
+ const line = args
40
+ .map((a) =>
41
+ typeof a === "string"
42
+ ? a
43
+ : a instanceof Error
44
+ ? a.stack || a.message
45
+ : typeof a === "object"
46
+ ? JSON.stringify(a)
47
+ : String(a),
48
+ )
49
+ .join(" ");
50
+ watchdogSelfLogs.push(line);
51
+ if (watchdogSelfLogs.length > WATCHDOG_SELF_LOG_MAX)
52
+ watchdogSelfLogs.shift();
53
+ } catch {
54
+ /* 缓冲失败不影响原始输出 */
55
+ }
56
+ _origConsoleError(...args);
57
+ };
58
+
59
+ /** 取最近 tail 行看门狗自身日志(只读) */
60
+ export function getWatchdogSelfLogs(tail = 500) {
61
+ const n = Math.max(
62
+ 1,
63
+ Math.min(Number(tail) || WATCHDOG_SELF_LOG_MAX, watchdogSelfLogs.length),
64
+ );
65
+ return watchdogSelfLogs.slice(-n);
66
+ }
67
+
30
68
  const __dirname = dirname(fileURLToPath(import.meta.url));
31
69
  const homeDir = homedir() || process.env.HOME || process.env.USERPROFILE || "";
32
70
  const TT_HELP_CONFIG = join(homeDir, ".tt-help.json");
@@ -566,6 +604,11 @@ export class WatchdogAgent {
566
604
  }
567
605
  }
568
606
 
607
+ // 后台页面按需拉取日志(request-logs 入队 → 本心跳取走 → 收集后回传落盘)
608
+ if (Array.isArray(data.logRequests) && data.logRequests.length > 0) {
609
+ this._handleLogRequests(data.logRequests);
610
+ }
611
+
569
612
  // 服务端下发的客户端配置(远程修改 ~/.tt-help.json)
570
613
  if (data.clientConfig) {
571
614
  applyClientConfig(data.clientConfig);
@@ -754,6 +797,47 @@ export class WatchdogAgent {
754
797
  }
755
798
  }
756
799
 
800
+ /**
801
+ * 处理服务端下发的日志拉取请求(后台页面点击"日志"按钮触发)
802
+ * 收集本机日志(watchdog 自身环形缓冲 / 进程日志只读快照)→ POST 回传服务端落盘
803
+ * @param {Array<{cmdId:string, tail?:number}>} requests
804
+ */
805
+ async _handleLogRequests(requests) {
806
+ for (const req of requests) {
807
+ const cmdId = req && req.cmdId ? String(req.cmdId) : "";
808
+ if (!cmdId) continue;
809
+ const tail = Math.max(1, Math.min(Number(req.tail) || 500, 500));
810
+ let logs = [];
811
+ if (cmdId === "__watchdog__") {
812
+ logs = getWatchdogSelfLogs(tail);
813
+ } else {
814
+ logs = this.processManager.getProcessLogSnapshot(cmdId, tail);
815
+ }
816
+ try {
817
+ const resp = await fetch(`${this.serverUrl}/api/watchdog/report-logs`, {
818
+ method: "POST",
819
+ headers: { "Content-Type": "application/json" },
820
+ body: JSON.stringify({
821
+ clientId: this.clientId,
822
+ cmdId,
823
+ logs,
824
+ capturedAt: Date.now(),
825
+ }),
826
+ signal: AbortSignal.timeout(20000),
827
+ });
828
+ if (!resp.ok) {
829
+ console.error(
830
+ `[watchdog] 日志回传失败: ${cmdId} HTTP ${resp.status}`,
831
+ );
832
+ continue;
833
+ }
834
+ console.error(`[watchdog] 日志回传完成: ${cmdId} (${logs.length}行)`);
835
+ } catch (e) {
836
+ console.error(`[watchdog] 日志回传失败: ${cmdId}: ${e.message}`);
837
+ }
838
+ }
839
+ }
840
+
757
841
  /**
758
842
  * 启动 LLM 日志分析定时器(每 10 分钟调服务端接口)
759
843
  */
@@ -525,6 +525,23 @@ export class ProcessManager extends EventEmitter {
525
525
  return result;
526
526
  }
527
527
 
528
+ /**
529
+ * 只读获取某进程最近 tail 行日志快照(不清空,与 LLM 链路互不影响)
530
+ * 供后台页面点击"日志"按钮时按需拉取
531
+ * @param {string} cmdId - 命令 ID
532
+ * @param {number} [tail=500] - 取最近多少行
533
+ * @returns {string[]}
534
+ */
535
+ getProcessLogSnapshot(cmdId, tail = 500) {
536
+ const info = this.processes.get(cmdId);
537
+ if (!info || !info.logs || info.logs.length === 0) return [];
538
+ const n = Math.max(
539
+ 1,
540
+ Math.min(Number(tail) || 500, MAX_LOG_LINES, info.logs.length),
541
+ );
542
+ return info.logs.slice(-n);
543
+ }
544
+
528
545
  /**
529
546
  * 检测假死进程:超过 STALE_LOG_TIMEOUT_MS 无日志输出则自动重启
530
547
  * @returns {Array<{cmdId:string, silentMinutes:number}>} 被重启的进程列表