ylib-syim 0.0.5 → 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 +12 -16
- 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
|
@@ -106,11 +106,7 @@ function applyRemoteRuntimeConfigToPluginHome(): void {
|
|
|
106
106
|
} else {
|
|
107
107
|
console.log(`[bridges/main] plugin temp HOME syim dir exists: ${syimDir}`);
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
fs.writeFileSync(syimPath, payload, "utf-8");
|
|
111
|
-
} else {
|
|
112
|
-
console.log(`[bridges/main] plugin temp HOME syim dir exists: ${syimPath}`);
|
|
113
|
-
}
|
|
109
|
+
fs.writeFileSync(syimPath, payload, "utf-8");
|
|
114
110
|
const openclawDir = path.join(pluginTempHomeDir, ".openclaw");
|
|
115
111
|
const openclawPath = path.join(openclawDir, "openclaw.json");
|
|
116
112
|
if (!fs.existsSync(openclawDir)) {
|
|
@@ -118,11 +114,7 @@ function applyRemoteRuntimeConfigToPluginHome(): void {
|
|
|
118
114
|
} else {
|
|
119
115
|
console.log(`[bridges/main] plugin temp HOME openclaw dir exists: ${openclawDir}`);
|
|
120
116
|
}
|
|
121
|
-
|
|
122
|
-
fs.writeFileSync(openclawPath, payload, "utf-8");
|
|
123
|
-
} else {
|
|
124
|
-
console.log(`[bridges/main] plugin temp HOME openclaw dir exists: ${openclawPath}`);
|
|
125
|
-
}
|
|
117
|
+
fs.writeFileSync(openclawPath, payload, "utf-8");
|
|
126
118
|
process.env.HOME = pluginTempHomeDir;
|
|
127
119
|
if (process.platform === "win32") process.env.USERPROFILE = pluginTempHomeDir;
|
|
128
120
|
console.log(
|
|
@@ -979,14 +971,18 @@ async function pullRuntimeConfigFromPython(forceFull = false): Promise<{
|
|
|
979
971
|
function startRuntimeConfigPollLoop(): void {
|
|
980
972
|
if (!runtimeConfigPullUrl) return;
|
|
981
973
|
if (runtimeConfigPollIntervalMs <= 0) return;
|
|
974
|
+
let recoveryHandled = false;
|
|
982
975
|
const timer = setInterval(() => {
|
|
983
976
|
void pullRuntimeConfigFromPython(false).then((result) => {
|
|
984
|
-
if (result.ok)
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
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);
|
|
990
986
|
});
|
|
991
987
|
}, runtimeConfigPollIntervalMs);
|
|
992
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",
|