tt-help-cli-ycl 1.4.134 → 1.4.136
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/package.json +1 -1
- package/scripts/backup-db.mjs +73 -0
- package/scripts/check-queues.sh +37 -0
- package/scripts/migrate-jobs-done.mjs +124 -0
- package/scripts/migrate-tags-db.mjs +163 -0
- package/src/cli/tag.js +68 -9
- package/src/lib/tag-discover.js +21 -0
- package/src/watch/data-store.js +131 -77
- package/src/watch/db-crud.js +35 -10
- package/src/watch/db-schema.js +249 -100
- package/src/watch/db-stats.js +53 -23
- package/src/watch/db-tags.js +5 -2
- package/src/watch/llm-config.js +31 -1
- package/src/watch/public/app.js +162 -11
- package/src/watch/public/index.html +19 -1
- package/src/watch/server.js +338 -62
- package/src/watch/tag-selflearn.js +2 -1
- package/src/watch/watchdog-server.js +129 -1
- package/src/watchdog/agent.js +76 -0
- package/src/watchdog/process-manager.js +21 -0
- package/src/watchdog/self-log-buffer.js +25 -0
package/src/watchdog/agent.js
CHANGED
|
@@ -26,6 +26,36 @@ import { spawn } from "child_process";
|
|
|
26
26
|
import { join, dirname } from "path";
|
|
27
27
|
import { homedir, tmpdir } from "os";
|
|
28
28
|
import { fileURLToPath } from "url";
|
|
29
|
+
import { pushSelfLog, getSelfLogs } from "./self-log-buffer.js";
|
|
30
|
+
|
|
31
|
+
// ── 看门狗自身日志入环(供后台页面按需拉取,经 report-logs 回传落盘) ──
|
|
32
|
+
// 包装 console.error:本进程所有 [watchdog]/[llm-analyzer]/[upgrade] 等日志
|
|
33
|
+
// 在正常输出的同时进共享环形缓冲(与托管进程日志同环,见 self-log-buffer.js)。
|
|
34
|
+
const _origConsoleError = console.error.bind(console);
|
|
35
|
+
console.error = (...args) => {
|
|
36
|
+
try {
|
|
37
|
+
const line = args
|
|
38
|
+
.map((a) =>
|
|
39
|
+
typeof a === "string"
|
|
40
|
+
? a
|
|
41
|
+
: a instanceof Error
|
|
42
|
+
? a.stack || a.message
|
|
43
|
+
: typeof a === "object"
|
|
44
|
+
? JSON.stringify(a)
|
|
45
|
+
: String(a),
|
|
46
|
+
)
|
|
47
|
+
.join(" ");
|
|
48
|
+
pushSelfLog(line);
|
|
49
|
+
} catch {
|
|
50
|
+
/* 缓冲失败不影响原始输出 */
|
|
51
|
+
}
|
|
52
|
+
_origConsoleError(...args);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** 取最近 tail 行看门狗自身日志(含托管进程日志,只读) */
|
|
56
|
+
export function getWatchdogSelfLogs(tail = 500) {
|
|
57
|
+
return getSelfLogs(tail);
|
|
58
|
+
}
|
|
29
59
|
|
|
30
60
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
61
|
const homeDir = homedir() || process.env.HOME || process.env.USERPROFILE || "";
|
|
@@ -566,6 +596,11 @@ export class WatchdogAgent {
|
|
|
566
596
|
}
|
|
567
597
|
}
|
|
568
598
|
|
|
599
|
+
// 后台页面按需拉取日志(request-logs 入队 → 本心跳取走 → 收集后回传落盘)
|
|
600
|
+
if (Array.isArray(data.logRequests) && data.logRequests.length > 0) {
|
|
601
|
+
this._handleLogRequests(data.logRequests);
|
|
602
|
+
}
|
|
603
|
+
|
|
569
604
|
// 服务端下发的客户端配置(远程修改 ~/.tt-help.json)
|
|
570
605
|
if (data.clientConfig) {
|
|
571
606
|
applyClientConfig(data.clientConfig);
|
|
@@ -754,6 +789,47 @@ export class WatchdogAgent {
|
|
|
754
789
|
}
|
|
755
790
|
}
|
|
756
791
|
|
|
792
|
+
/**
|
|
793
|
+
* 处理服务端下发的日志拉取请求(后台页面点击"日志"按钮触发)
|
|
794
|
+
* 收集本机日志(watchdog 自身环形缓冲 / 进程日志只读快照)→ POST 回传服务端落盘
|
|
795
|
+
* @param {Array<{cmdId:string, tail?:number}>} requests
|
|
796
|
+
*/
|
|
797
|
+
async _handleLogRequests(requests) {
|
|
798
|
+
for (const req of requests) {
|
|
799
|
+
const cmdId = req && req.cmdId ? String(req.cmdId) : "";
|
|
800
|
+
if (!cmdId) continue;
|
|
801
|
+
const tail = Math.max(1, Math.min(Number(req.tail) || 500, 500));
|
|
802
|
+
let logs = [];
|
|
803
|
+
if (cmdId === "__watchdog__") {
|
|
804
|
+
logs = getWatchdogSelfLogs(tail);
|
|
805
|
+
} else {
|
|
806
|
+
logs = this.processManager.getProcessLogSnapshot(cmdId, tail);
|
|
807
|
+
}
|
|
808
|
+
try {
|
|
809
|
+
const resp = await fetch(`${this.serverUrl}/api/watchdog/report-logs`, {
|
|
810
|
+
method: "POST",
|
|
811
|
+
headers: { "Content-Type": "application/json" },
|
|
812
|
+
body: JSON.stringify({
|
|
813
|
+
clientId: this.clientId,
|
|
814
|
+
cmdId,
|
|
815
|
+
logs,
|
|
816
|
+
capturedAt: Date.now(),
|
|
817
|
+
}),
|
|
818
|
+
signal: AbortSignal.timeout(20000),
|
|
819
|
+
});
|
|
820
|
+
if (!resp.ok) {
|
|
821
|
+
console.error(
|
|
822
|
+
`[watchdog] 日志回传失败: ${cmdId} HTTP ${resp.status}`,
|
|
823
|
+
);
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
console.error(`[watchdog] 日志回传完成: ${cmdId} (${logs.length}行)`);
|
|
827
|
+
} catch (e) {
|
|
828
|
+
console.error(`[watchdog] 日志回传失败: ${cmdId}: ${e.message}`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
757
833
|
/**
|
|
758
834
|
* 启动 LLM 日志分析定时器(每 10 分钟调服务端接口)
|
|
759
835
|
*/
|
|
@@ -15,6 +15,7 @@ import { killEdgeProcesses } from "../lib/browser/cdp.js";
|
|
|
15
15
|
import { writeFileSync, unlinkSync } from "fs";
|
|
16
16
|
import { tmpdir } from "os";
|
|
17
17
|
import { join } from "path";
|
|
18
|
+
import { pushSelfLog } from "./self-log-buffer.js";
|
|
18
19
|
|
|
19
20
|
// === 2026-08-07 变更 ===
|
|
20
21
|
// syncCommands 改为 async,批量启动时每个进程间隔 SPAWN_STAGGER_MS(30s),避免抢网络
|
|
@@ -60,6 +61,7 @@ function fmtClock(d = new Date()) {
|
|
|
60
61
|
/**
|
|
61
62
|
* 打印子进程日志行(替代裸 console.error)。
|
|
62
63
|
* 只改显示形态,msg 内容一行不少;多行消息逐行加前缀。
|
|
64
|
+
* 同时以纯文本(无 ANSI 颜色)写入共享环形缓冲,供后台按需拉取。
|
|
63
65
|
*/
|
|
64
66
|
function printProcessLine(id, msg) {
|
|
65
67
|
const lines = String(msg).split(/\r?\n/);
|
|
@@ -68,6 +70,8 @@ function printProcessLine(id, msg) {
|
|
|
68
70
|
const useColor = canUseColor();
|
|
69
71
|
for (const line of lines) {
|
|
70
72
|
const clock = fmtClock();
|
|
73
|
+
// 环形缓冲:与 cmd 窗口同格式(时间 [cmdId] 内容),无颜色
|
|
74
|
+
pushSelfLog(`${clock} ${prefixId} ${line}`);
|
|
71
75
|
if (useColor) {
|
|
72
76
|
process.stderr.write(
|
|
73
77
|
`\x1b[90m${clock}\x1b[0m \x1b[${color}m${prefixId}\x1b[0m ${line}\n`,
|
|
@@ -525,6 +529,23 @@ export class ProcessManager extends EventEmitter {
|
|
|
525
529
|
return result;
|
|
526
530
|
}
|
|
527
531
|
|
|
532
|
+
/**
|
|
533
|
+
* 只读获取某进程最近 tail 行日志快照(不清空,与 LLM 链路互不影响)
|
|
534
|
+
* 供后台页面点击"日志"按钮时按需拉取
|
|
535
|
+
* @param {string} cmdId - 命令 ID
|
|
536
|
+
* @param {number} [tail=500] - 取最近多少行
|
|
537
|
+
* @returns {string[]}
|
|
538
|
+
*/
|
|
539
|
+
getProcessLogSnapshot(cmdId, tail = 500) {
|
|
540
|
+
const info = this.processes.get(cmdId);
|
|
541
|
+
if (!info || !info.logs || info.logs.length === 0) return [];
|
|
542
|
+
const n = Math.max(
|
|
543
|
+
1,
|
|
544
|
+
Math.min(Number(tail) || 500, MAX_LOG_LINES, info.logs.length),
|
|
545
|
+
);
|
|
546
|
+
return info.logs.slice(-n);
|
|
547
|
+
}
|
|
548
|
+
|
|
528
549
|
/**
|
|
529
550
|
* 检测假死进程:超过 STALE_LOG_TIMEOUT_MS 无日志输出则自动重启
|
|
530
551
|
* @returns {Array<{cmdId:string, silentMinutes:number}>} 被重启的进程列表
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 看门狗客户端本机日志环形缓冲(供后台页面按需拉取,经 report-logs 回传落盘)
|
|
3
|
+
*
|
|
4
|
+
* 两路来源:
|
|
5
|
+
* 1. watchdog 自身日志 —— agent.js 包装 console.error 写入([watchdog]/[llm-analyzer]/[upgrade] 等)
|
|
6
|
+
* 2. 托管进程日志 —— process-manager.js 的 printProcessLine 写入(纯文本,无 ANSI 颜色)
|
|
7
|
+
*
|
|
8
|
+
* 独立成模块是为了避免 agent.js ↔ process-manager.js 相互 import 形成循环依赖。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const MAX_LINES = 500; // 最多保留行数
|
|
12
|
+
|
|
13
|
+
const ring = [];
|
|
14
|
+
|
|
15
|
+
/** 追加一行(超容量丢弃最旧) */
|
|
16
|
+
export function pushSelfLog(line) {
|
|
17
|
+
ring.push(String(line));
|
|
18
|
+
if (ring.length > MAX_LINES) ring.shift();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 取最近 tail 行(只读) */
|
|
22
|
+
export function getSelfLogs(tail = MAX_LINES) {
|
|
23
|
+
const n = Math.max(1, Math.min(Number(tail) || MAX_LINES, ring.length));
|
|
24
|
+
return ring.slice(-n);
|
|
25
|
+
}
|