ylib-syim 0.0.6 → 0.0.7
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/bridges/logger.ts +117 -7
- package/bridges/main.ts +10 -6
- package/package.json +2 -2
package/bridges/logger.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { format } from "node:util";
|
|
4
|
+
import type { WriteStream } from "node:fs";
|
|
4
5
|
|
|
5
6
|
type ConsoleMethod = (...args: unknown[]) => void;
|
|
6
7
|
|
|
@@ -27,21 +28,130 @@ function patchConsole(writeLine: (line: string) => void): void {
|
|
|
27
28
|
const original = console[method] as ConsoleMethod;
|
|
28
29
|
console[method] = (...args: unknown[]) => {
|
|
29
30
|
const line = format(...args);
|
|
30
|
-
|
|
31
|
+
try {
|
|
32
|
+
writeLine(`[${new Date().toISOString()}] [${method}] ${line}`);
|
|
33
|
+
} catch {
|
|
34
|
+
// logger 必须永不影响主进程
|
|
35
|
+
}
|
|
31
36
|
original(...args);
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
function parsePositiveInt(value: unknown, fallback: number): number {
|
|
42
|
+
const n = Number(String(value ?? "").trim());
|
|
43
|
+
if (!Number.isFinite(n)) return fallback;
|
|
44
|
+
if (n <= 0) return fallback;
|
|
45
|
+
return Math.floor(n);
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
export function setupBridgeLogger(prefix: string): string {
|
|
37
49
|
const exists = globalThis.__imAgentHubBridgeLogger;
|
|
38
50
|
if (exists?.enabled) return exists.logFilePath;
|
|
39
51
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
try {
|
|
53
|
+
const logFilePath = buildLogFilePath(prefix);
|
|
54
|
+
const maxLines = parsePositiveInt(
|
|
55
|
+
process.env.IM_AGENT_HUB_LOG_MAX_LINES,
|
|
56
|
+
20000,
|
|
57
|
+
);
|
|
58
|
+
const trimBatch = parsePositiveInt(
|
|
59
|
+
process.env.IM_AGENT_HUB_LOG_TRIM_BATCH,
|
|
60
|
+
1000,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
let stream: WriteStream = fs.createWriteStream(logFilePath, { flags: "a" });
|
|
64
|
+
stream.on("error", () => {
|
|
65
|
+
// logger 必须永不影响主进程;出现 stream 错误后,后续写入直接丢弃
|
|
66
|
+
});
|
|
67
|
+
let streamBroken = false;
|
|
68
|
+
stream.on("error", () => {
|
|
69
|
+
streamBroken = true;
|
|
70
|
+
});
|
|
71
|
+
let writtenLines = 0;
|
|
72
|
+
let trimming = false;
|
|
73
|
+
let paused = false;
|
|
74
|
+
const buffer: string[] = [];
|
|
75
|
+
|
|
76
|
+
function writeRaw(lineWithNewline: string): void {
|
|
77
|
+
try {
|
|
78
|
+
if (streamBroken) return;
|
|
79
|
+
if (paused) {
|
|
80
|
+
buffer.push(lineWithNewline);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
stream.write(lineWithNewline);
|
|
84
|
+
} catch {
|
|
85
|
+
// swallow
|
|
86
|
+
}
|
|
87
|
+
}
|
|
43
88
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
89
|
+
async function trimToLastLines(): Promise<void> {
|
|
90
|
+
if (trimming) return;
|
|
91
|
+
trimming = true;
|
|
92
|
+
paused = true;
|
|
93
|
+
try {
|
|
94
|
+
await new Promise<void>((resolve) => {
|
|
95
|
+
try {
|
|
96
|
+
stream.end(() => resolve());
|
|
97
|
+
} catch {
|
|
98
|
+
resolve();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
const text = fs.readFileSync(logFilePath, "utf-8");
|
|
102
|
+
const lines = text.split("\n");
|
|
103
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
104
|
+
const kept = lines.slice(-maxLines);
|
|
105
|
+
fs.writeFileSync(
|
|
106
|
+
logFilePath,
|
|
107
|
+
kept.join("\n") + (kept.length ? "\n" : ""),
|
|
108
|
+
"utf-8",
|
|
109
|
+
);
|
|
110
|
+
stream = fs.createWriteStream(logFilePath, { flags: "a" });
|
|
111
|
+
streamBroken = false;
|
|
112
|
+
stream.on("error", () => {
|
|
113
|
+
streamBroken = true;
|
|
114
|
+
});
|
|
115
|
+
for (const item of buffer) {
|
|
116
|
+
try {
|
|
117
|
+
if (streamBroken) break;
|
|
118
|
+
stream.write(item);
|
|
119
|
+
} catch {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
buffer.length = 0;
|
|
124
|
+
writtenLines = Math.min(maxLines, kept.length);
|
|
125
|
+
} catch {
|
|
126
|
+
try {
|
|
127
|
+
stream = fs.createWriteStream(logFilePath, { flags: "a" });
|
|
128
|
+
streamBroken = false;
|
|
129
|
+
stream.on("error", () => {
|
|
130
|
+
streamBroken = true;
|
|
131
|
+
});
|
|
132
|
+
} catch {
|
|
133
|
+
streamBroken = true;
|
|
134
|
+
}
|
|
135
|
+
} finally {
|
|
136
|
+
paused = false;
|
|
137
|
+
trimming = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
writeRaw(`[${new Date().toISOString()}] [system] bridge logger started\n`);
|
|
142
|
+
writtenLines += 1;
|
|
143
|
+
|
|
144
|
+
patchConsole((line) => {
|
|
145
|
+
writeRaw(`${line}\n`);
|
|
146
|
+
writtenLines += 1;
|
|
147
|
+
if (maxLines > 0 && writtenLines > maxLines + trimBatch && !trimming) {
|
|
148
|
+
void trimToLastLines();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
globalThis.__imAgentHubBridgeLogger = { enabled: true, logFilePath };
|
|
152
|
+
return logFilePath;
|
|
153
|
+
} catch {
|
|
154
|
+
globalThis.__imAgentHubBridgeLogger = { enabled: false, logFilePath: "" };
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
47
157
|
}
|
package/bridges/main.ts
CHANGED
|
@@ -971,14 +971,18 @@ async function pullRuntimeConfigFromPython(forceFull = false): Promise<{
|
|
|
971
971
|
function startRuntimeConfigPollLoop(): void {
|
|
972
972
|
if (!runtimeConfigPullUrl) return;
|
|
973
973
|
if (runtimeConfigPollIntervalMs <= 0) return;
|
|
974
|
+
let recoveryHandled = false;
|
|
974
975
|
const timer = setInterval(() => {
|
|
975
976
|
void pullRuntimeConfigFromPython(false).then((result) => {
|
|
976
|
-
if (result.ok)
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
977
|
+
if (!result.ok) return;
|
|
978
|
+
if (recoveryHandled) return;
|
|
979
|
+
recoveryHandled = true;
|
|
980
|
+
console.log(
|
|
981
|
+
"[bridges/main] poll pull recovered success, stop polling and exit for hard restart",
|
|
982
|
+
);
|
|
983
|
+
clearInterval(timer);
|
|
984
|
+
// 配置源(Python)恢复后硬重启:退出进程,由 PM2/系统守护重新拉起,下次启动走正常拉配置与起 bridge 流程。
|
|
985
|
+
setTimeout(() => process.exit(0), 100);
|
|
982
986
|
});
|
|
983
987
|
}, runtimeConfigPollIntervalMs);
|
|
984
988
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ylib-syim",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "多 IM / 多 Agent 的会话路由与上下文管理(支持 /new)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
43
43
|
"ylib-dingtalk-connector": "0.7.10-beata.2",
|
|
44
|
-
"ylib-openclaw-lark": "2026.3.17-beata.
|
|
44
|
+
"ylib-openclaw-lark": "2026.3.17-beata.6",
|
|
45
45
|
"axios": "^1.6.0",
|
|
46
46
|
"dingtalk-stream": "^2.1.4",
|
|
47
47
|
"fluent-ffmpeg": "^2.1.3",
|