ylib-syim 0.0.1 → 0.0.2
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/bin/syim.mjs +76 -13
- package/bridges/dingtalk-stdio-bridge.ts +54 -2
- package/bridges/lark-stdio-bridge.ts +54 -2
- package/bridges/main.ts +1996 -62
- package/bridges/runtime-event-reporter.ts +224 -0
- package/ecosystem.config.cjs +24 -0
- package/package.json +6 -5
- package/scripts/dingtalk-stdio-bridge.ts +329 -90
- package/scripts/feishu-yuce-bridge.ts +3 -3
- package/scripts/lark-stdio-bridge.ts +256 -42
package/bin/syim.mjs
CHANGED
|
@@ -1,34 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import path from "node:path";
|
|
7
8
|
|
|
8
9
|
const major = Number.parseInt(process.versions.node.split(".")[0] || "0", 10);
|
|
9
|
-
if (major <
|
|
10
|
-
console.error(`[syim] Node.js >=
|
|
11
|
-
console.error("[syim] please run: nvm use
|
|
10
|
+
if (major < 20) {
|
|
11
|
+
console.error(`[syim] Node.js >= 20 is required, current: v${process.versions.node}`);
|
|
12
|
+
console.error("[syim] please run: nvm use 20");
|
|
12
13
|
process.exit(1);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const thisFile = fileURLToPath(import.meta.url);
|
|
16
17
|
const pkgRoot = path.resolve(path.dirname(thisFile), "..");
|
|
18
|
+
const ecosystemConfigPath = path.join(pkgRoot, "ecosystem.config.cjs");
|
|
17
19
|
const entry = path.join(pkgRoot, "bridges", "main.ts");
|
|
18
20
|
const require = createRequire(import.meta.url);
|
|
19
21
|
const tsxPkgJson = require.resolve("tsx/package.json", { paths: [pkgRoot] });
|
|
20
22
|
const tsxCli = path.join(path.dirname(tsxPkgJson), "dist", "cli.mjs");
|
|
21
23
|
|
|
22
|
-
const
|
|
23
|
-
stdio: "inherit",
|
|
24
|
-
env: process.env,
|
|
25
|
-
});
|
|
24
|
+
const forwardArgv = process.argv.slice(2);
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
if (forwardArgv[0] === "-h" || forwardArgv[0] === "--help") {
|
|
27
|
+
let name = "@ylib/syim";
|
|
28
|
+
let version = "";
|
|
29
|
+
let desc = "";
|
|
30
|
+
try {
|
|
31
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf-8"));
|
|
32
|
+
name = String(pkg.name || name);
|
|
33
|
+
version = String(pkg.version || "");
|
|
34
|
+
desc = String(pkg.description || "");
|
|
35
|
+
} catch {}
|
|
36
|
+
const verLine = version ? ` ${version}` : "";
|
|
37
|
+
const descLine = desc ? `\n${desc}\n` : "\n";
|
|
38
|
+
console.log(
|
|
39
|
+
`${name}${verLine}${descLine}
|
|
40
|
+
用法:
|
|
41
|
+
syim [参数...] 通过 tsx 运行 bridges/main.ts,参数原样传入
|
|
42
|
+
syim pm2-bridges [pm2参数...] pm2 start <包内 ecosystem.config.cjs> --only im-agent-hub-bridges
|
|
43
|
+
|
|
44
|
+
选项:
|
|
45
|
+
-h, --help 显示本说明
|
|
46
|
+
|
|
47
|
+
需要 Node.js >= 20;pm2-bridges 需已安装 pm2(npm i -g pm2)。
|
|
48
|
+
`,
|
|
49
|
+
);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 等价 pm2 start ./ecosystem.config.cjs --only im-agent-hub-bridges(包内绝对路径) */
|
|
54
|
+
if (forwardArgv[0] === "pm2-bridges") {
|
|
55
|
+
if (!fs.existsSync(ecosystemConfigPath)) {
|
|
56
|
+
console.error(`[syim] 未找到: ${ecosystemConfigPath}`);
|
|
57
|
+
process.exit(1);
|
|
31
58
|
}
|
|
32
|
-
|
|
33
|
-
|
|
59
|
+
const extra = forwardArgv.slice(1);
|
|
60
|
+
const child = spawn(
|
|
61
|
+
"pm2",
|
|
62
|
+
["start", ecosystemConfigPath, "--only", "im-agent-hub-bridges", ...extra],
|
|
63
|
+
{
|
|
64
|
+
stdio: "inherit",
|
|
65
|
+
env: process.env,
|
|
66
|
+
shell: process.platform === "win32",
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
child.on("exit", (code, signal) => {
|
|
70
|
+
if (signal) {
|
|
71
|
+
process.kill(process.pid, signal);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
process.exit(code ?? 0);
|
|
75
|
+
});
|
|
76
|
+
child.on("error", (err) => {
|
|
77
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code === "ENOENT") {
|
|
78
|
+
console.error("[syim] 未找到 pm2,请先: npm install -g pm2");
|
|
79
|
+
process.exit(127);
|
|
80
|
+
}
|
|
81
|
+
console.error(err);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
const child = spawn(process.execPath, [tsxCli, entry, ...forwardArgv], {
|
|
86
|
+
stdio: "inherit",
|
|
87
|
+
env: process.env,
|
|
88
|
+
});
|
|
34
89
|
|
|
90
|
+
child.on("exit", (code, signal) => {
|
|
91
|
+
if (signal) {
|
|
92
|
+
process.kill(process.pid, signal);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
process.exit(code ?? 0);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -3,8 +3,60 @@
|
|
|
3
3
|
* 真实实现暂保留在 scripts,避免一次性迁移带来路径风险。
|
|
4
4
|
*/
|
|
5
5
|
import { setupBridgeLogger } from "./logger.ts";
|
|
6
|
+
import {
|
|
7
|
+
wireBridgeLifecycleReporter,
|
|
8
|
+
installConsoleEventHook,
|
|
9
|
+
reportRuntimeEvent,
|
|
10
|
+
} from "./runtime-event-reporter.ts";
|
|
11
|
+
|
|
12
|
+
function formatErr(err: unknown): string {
|
|
13
|
+
if (err instanceof Error) {
|
|
14
|
+
return `${err.message}\n${err.stack || ""}`.trim();
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
return JSON.stringify(err);
|
|
18
|
+
} catch {
|
|
19
|
+
return String(err);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
6
22
|
|
|
7
23
|
const logFilePath = setupBridgeLogger("dingtalk-bridge");
|
|
8
|
-
console.
|
|
24
|
+
console.log("[dingtalk-bridge] log file:", logFilePath);
|
|
25
|
+
|
|
26
|
+
wireBridgeLifecycleReporter("dingtalk");
|
|
27
|
+
installConsoleEventHook("dingtalk");
|
|
28
|
+
|
|
29
|
+
process.on("uncaughtException", (err) => {
|
|
30
|
+
console.error("[dingtalk-bridge] uncaughtException:\n" + formatErr(err));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
process.on("unhandledRejection", (reason) => {
|
|
34
|
+
console.error("[dingtalk-bridge] unhandledRejection:\n" + formatErr(reason));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
(globalThis as any).__IM_RUNTIME_EVENT_REPORTER__ = (payload: {
|
|
38
|
+
accountId: string;
|
|
39
|
+
linkStatus:
|
|
40
|
+
| "connecting"
|
|
41
|
+
| "connected"
|
|
42
|
+
| "degraded"
|
|
43
|
+
| "disconnected"
|
|
44
|
+
| "error";
|
|
45
|
+
lastError?: string | null;
|
|
46
|
+
}) => {
|
|
47
|
+
return reportRuntimeEvent(
|
|
48
|
+
"dingtalk",
|
|
49
|
+
payload.accountId,
|
|
50
|
+
payload.linkStatus,
|
|
51
|
+
payload.lastError || null,
|
|
52
|
+
);
|
|
53
|
+
};
|
|
9
54
|
|
|
10
|
-
|
|
55
|
+
try {
|
|
56
|
+
await import("../scripts/dingtalk-stdio-bridge.ts");
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(
|
|
59
|
+
"[dingtalk-bridge] failed to load/start script:\n" + formatErr(err),
|
|
60
|
+
);
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
@@ -3,8 +3,60 @@
|
|
|
3
3
|
* 真实实现暂保留在 scripts,避免一次性迁移带来路径风险。
|
|
4
4
|
*/
|
|
5
5
|
import { setupBridgeLogger } from "./logger.ts";
|
|
6
|
+
import {
|
|
7
|
+
wireBridgeLifecycleReporter,
|
|
8
|
+
installConsoleEventHook,
|
|
9
|
+
reportRuntimeEvent,
|
|
10
|
+
} from "./runtime-event-reporter.ts";
|
|
11
|
+
|
|
12
|
+
function formatErr(err: unknown): string {
|
|
13
|
+
if (err instanceof Error) {
|
|
14
|
+
return `${err.message}\n${err.stack || ""}`.trim();
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
return JSON.stringify(err);
|
|
18
|
+
} catch {
|
|
19
|
+
return String(err);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
6
22
|
|
|
7
23
|
const logFilePath = setupBridgeLogger("lark-bridge");
|
|
8
|
-
console.
|
|
24
|
+
console.log("[lark-bridge] log file:", logFilePath);
|
|
25
|
+
|
|
26
|
+
wireBridgeLifecycleReporter("feishu");
|
|
27
|
+
installConsoleEventHook("feishu");
|
|
28
|
+
|
|
29
|
+
process.on("uncaughtException", (err) => {
|
|
30
|
+
console.error("[lark-bridge] uncaughtException:\n" + formatErr(err));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
process.on("unhandledRejection", (reason) => {
|
|
34
|
+
console.error("[lark-bridge] unhandledRejection:\n" + formatErr(reason));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
(globalThis as any).__IM_RUNTIME_EVENT_REPORTER__ = (payload: {
|
|
38
|
+
accountId: string;
|
|
39
|
+
linkStatus:
|
|
40
|
+
| "connecting"
|
|
41
|
+
| "connected"
|
|
42
|
+
| "degraded"
|
|
43
|
+
| "disconnected"
|
|
44
|
+
| "error";
|
|
45
|
+
lastError?: string | null;
|
|
46
|
+
}) => {
|
|
47
|
+
return reportRuntimeEvent(
|
|
48
|
+
"feishu",
|
|
49
|
+
payload.accountId,
|
|
50
|
+
payload.linkStatus,
|
|
51
|
+
payload.lastError || null,
|
|
52
|
+
);
|
|
53
|
+
};
|
|
9
54
|
|
|
10
|
-
|
|
55
|
+
try {
|
|
56
|
+
await import("../scripts/lark-stdio-bridge.ts");
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(
|
|
59
|
+
"[lark-bridge] failed to load/start script:\n" + formatErr(err),
|
|
60
|
+
);
|
|
61
|
+
throw err;
|
|
62
|
+
}
|