omp-wechat 1.7.0 → 1.9.0
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/dist/index.js +146 -67
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
30
30
|
return to;
|
|
31
31
|
};
|
|
32
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __require = import.meta.require;
|
|
33
34
|
|
|
34
35
|
// node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
|
|
35
36
|
var require_QRMode = __commonJS((exports, module) => {
|
|
@@ -1188,6 +1189,11 @@ var logger = {
|
|
|
1188
1189
|
var STATE_DIR = join3(homedir2(), ".omp-wechat");
|
|
1189
1190
|
var CREDENTIALS_FILE = join3(STATE_DIR, "credentials.json");
|
|
1190
1191
|
var SYNC_BUF_FILE = join3(STATE_DIR, "sync_buf.txt");
|
|
1192
|
+
var CHANNEL_VERSION = "2.2.0";
|
|
1193
|
+
var BOT_AGENT = "OMP-Wechat/1.7.0";
|
|
1194
|
+
function baseInfo() {
|
|
1195
|
+
return { channel_version: CHANNEL_VERSION, bot_agent: BOT_AGENT };
|
|
1196
|
+
}
|
|
1191
1197
|
function loadCredentials() {
|
|
1192
1198
|
try {
|
|
1193
1199
|
return JSON.parse(readFileSync(CREDENTIALS_FILE, "utf8"));
|
|
@@ -1241,7 +1247,15 @@ async function apiFetch(creds, endpoint, body, timeoutMs = 15000) {
|
|
|
1241
1247
|
const text = await res.text();
|
|
1242
1248
|
if (!res.ok)
|
|
1243
1249
|
throw new Error(`${endpoint} ${res.status}: ${text}`);
|
|
1244
|
-
|
|
1250
|
+
const data = JSON.parse(text);
|
|
1251
|
+
const ret = typeof data.ret === "number" ? data.ret : undefined;
|
|
1252
|
+
const errcode = typeof data.errcode === "number" ? data.errcode : undefined;
|
|
1253
|
+
if (ret !== undefined && ret !== 0 || errcode !== undefined && errcode !== 0) {
|
|
1254
|
+
const code = errcode ?? ret ?? 0;
|
|
1255
|
+
const errmsg = typeof data.errmsg === "string" ? data.errmsg : "";
|
|
1256
|
+
throw new Error(`${endpoint} error ret=${ret} errcode=${errcode}${errmsg ? `: ${errmsg}` : ""} (code ${code})`);
|
|
1257
|
+
}
|
|
1258
|
+
return data;
|
|
1245
1259
|
} catch (err) {
|
|
1246
1260
|
clearTimeout(timer);
|
|
1247
1261
|
throw err;
|
|
@@ -1251,7 +1265,7 @@ async function getUpdates(creds, buf) {
|
|
|
1251
1265
|
try {
|
|
1252
1266
|
const resp = await apiFetch(creds, "ilink/bot/getupdates", {
|
|
1253
1267
|
get_updates_buf: buf,
|
|
1254
|
-
base_info:
|
|
1268
|
+
base_info: baseInfo()
|
|
1255
1269
|
}, 35000);
|
|
1256
1270
|
return resp;
|
|
1257
1271
|
} catch (err) {
|
|
@@ -1272,7 +1286,7 @@ async function sendMessage(creds, to, text, contextToken, clientId) {
|
|
|
1272
1286
|
item_list: [{ type: 1, text_item: { text } }],
|
|
1273
1287
|
context_token: contextToken
|
|
1274
1288
|
},
|
|
1275
|
-
base_info:
|
|
1289
|
+
base_info: baseInfo()
|
|
1276
1290
|
}, 15000);
|
|
1277
1291
|
}
|
|
1278
1292
|
var typingTicketCache = new Map;
|
|
@@ -1284,7 +1298,7 @@ async function ensureTypingTicket(creds, userId) {
|
|
|
1284
1298
|
try {
|
|
1285
1299
|
const resp = await apiFetch(creds, "ilink/bot/getconfig", {
|
|
1286
1300
|
ilink_user_id: userId,
|
|
1287
|
-
base_info:
|
|
1301
|
+
base_info: baseInfo()
|
|
1288
1302
|
}, 15000);
|
|
1289
1303
|
const data = resp;
|
|
1290
1304
|
if (data.typing_ticket) {
|
|
@@ -1306,10 +1320,9 @@ async function sendTyping(creds, userId, command) {
|
|
|
1306
1320
|
try {
|
|
1307
1321
|
await apiFetch(creds, "ilink/bot/sendtyping", {
|
|
1308
1322
|
ilink_user_id: userId,
|
|
1309
|
-
to_user_id: userId,
|
|
1310
1323
|
typing_ticket: ticket,
|
|
1311
|
-
command,
|
|
1312
|
-
base_info:
|
|
1324
|
+
status: command,
|
|
1325
|
+
base_info: baseInfo()
|
|
1313
1326
|
}, 1e4);
|
|
1314
1327
|
} catch (err) {
|
|
1315
1328
|
logger.debug(`sendTyping failed for ${userId}: ${err}`);
|
|
@@ -1491,6 +1504,64 @@ function listAllowed() {
|
|
|
1491
1504
|
return loadAccess().allowFrom;
|
|
1492
1505
|
}
|
|
1493
1506
|
|
|
1507
|
+
// src/utils/runtime-compat.ts
|
|
1508
|
+
import { spawnSync as nodeSpawnSync } from "child_process";
|
|
1509
|
+
import { createServer as createNetServer } from "net";
|
|
1510
|
+
function isBun() {
|
|
1511
|
+
return typeof globalThis.Bun !== "undefined" && typeof globalThis.Bun.sleep === "function";
|
|
1512
|
+
}
|
|
1513
|
+
function sleep(ms) {
|
|
1514
|
+
if (isBun()) {
|
|
1515
|
+
return globalThis.Bun.sleep(ms);
|
|
1516
|
+
}
|
|
1517
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1518
|
+
}
|
|
1519
|
+
function spawnSync(cmd, opts = {}) {
|
|
1520
|
+
if (isBun()) {
|
|
1521
|
+
const res2 = globalThis.Bun.spawnSync(cmd, opts);
|
|
1522
|
+
return {
|
|
1523
|
+
exitCode: res2.exitCode,
|
|
1524
|
+
stdout: Buffer.isBuffer(res2.stdout) ? res2.stdout : Buffer.from(res2.stdout ?? []),
|
|
1525
|
+
stderr: Buffer.isBuffer(res2.stderr) ? res2.stderr : Buffer.from(res2.stderr ?? [])
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
const [command, ...args] = cmd;
|
|
1529
|
+
const res = nodeSpawnSync(command, args, {
|
|
1530
|
+
cwd: opts.cwd,
|
|
1531
|
+
stdio: ["pipe", opts.stdout ?? "pipe", opts.stderr ?? "pipe"]
|
|
1532
|
+
});
|
|
1533
|
+
return {
|
|
1534
|
+
exitCode: res.status ?? (res.error || res.signal ? 1 : 0),
|
|
1535
|
+
stdout: res.stdout ?? Buffer.alloc(0),
|
|
1536
|
+
stderr: res.stderr ?? Buffer.alloc(0)
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
function listenPort(port) {
|
|
1540
|
+
if (isBun()) {
|
|
1541
|
+
const server2 = globalThis.Bun.serve({
|
|
1542
|
+
port,
|
|
1543
|
+
hostname: "127.0.0.1",
|
|
1544
|
+
fetch() {
|
|
1545
|
+
return new Response("ok");
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
return Promise.resolve({ stop: () => server2.stop(true) });
|
|
1549
|
+
}
|
|
1550
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
1551
|
+
const server = createNetServer((socket) => {
|
|
1552
|
+
socket.end("ok");
|
|
1553
|
+
});
|
|
1554
|
+
server.once("error", (err) => {
|
|
1555
|
+
reject(err);
|
|
1556
|
+
});
|
|
1557
|
+
server.listen(port, "127.0.0.1", () => {
|
|
1558
|
+
resolve({
|
|
1559
|
+
stop: () => server.close()
|
|
1560
|
+
});
|
|
1561
|
+
});
|
|
1562
|
+
return promise;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1494
1565
|
// src/ilink/login.ts
|
|
1495
1566
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
1496
1567
|
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com/";
|
|
@@ -1511,13 +1582,9 @@ async function login() {
|
|
|
1511
1582
|
}
|
|
1512
1583
|
try {
|
|
1513
1584
|
import_qrcode_terminal.default.generate(qrUrl, { small: true });
|
|
1514
|
-
} catch {
|
|
1515
|
-
logger.
|
|
1516
|
-
|
|
1517
|
-
cwd: process.cwd(),
|
|
1518
|
-
stderr: "inherit"
|
|
1519
|
-
});
|
|
1520
|
-
import_qrcode_terminal.default.generate(qrUrl, { small: true });
|
|
1585
|
+
} catch (err) {
|
|
1586
|
+
logger.error("qrcode-terminal failed to render QR code:", err);
|
|
1587
|
+
throw new Error("Could not render QR code. Please confirm the plugin's dependencies are installed (qrcode-terminal).");
|
|
1521
1588
|
}
|
|
1522
1589
|
process.stderr.write(`
|
|
1523
1590
|
Scan the QR code above with WeChat, or open this link:
|
|
@@ -1560,7 +1627,7 @@ Scan the QR code above with WeChat, or open this link:
|
|
|
1560
1627
|
return;
|
|
1561
1628
|
}
|
|
1562
1629
|
}
|
|
1563
|
-
await
|
|
1630
|
+
await sleep(POLL_INTERVAL_MS);
|
|
1564
1631
|
}
|
|
1565
1632
|
throw new Error("Login timeout, please run login again");
|
|
1566
1633
|
}
|
|
@@ -1873,7 +1940,7 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1873
1940
|
filesize: ciphertext.length,
|
|
1874
1941
|
no_need_thumb: true,
|
|
1875
1942
|
aeskey: aesKey.toString("hex"),
|
|
1876
|
-
base_info:
|
|
1943
|
+
base_info: baseInfo()
|
|
1877
1944
|
}, 15000);
|
|
1878
1945
|
const uploadFullUrl = uploadParams.upload_full_url?.trim();
|
|
1879
1946
|
if (!uploadFullUrl && !uploadParams.upload_param) {
|
|
@@ -1908,7 +1975,7 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1908
1975
|
lastError = err;
|
|
1909
1976
|
if (attempt < UPLOAD_MAX_RETRIES) {
|
|
1910
1977
|
logger.warn(`CDN upload attempt ${attempt}/${UPLOAD_MAX_RETRIES} failed, retrying:`, err);
|
|
1911
|
-
await
|
|
1978
|
+
await sleep(1000 * attempt);
|
|
1912
1979
|
}
|
|
1913
1980
|
}
|
|
1914
1981
|
}
|
|
@@ -1920,7 +1987,7 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1920
1987
|
}
|
|
1921
1988
|
const media = {
|
|
1922
1989
|
encrypt_query_param: encryptQueryParam,
|
|
1923
|
-
aes_key: aesKey.toString("base64"),
|
|
1990
|
+
aes_key: Buffer.from(aesKey.toString("hex"), "utf8").toString("base64"),
|
|
1924
1991
|
encrypt_type: 1
|
|
1925
1992
|
};
|
|
1926
1993
|
const item = mediaType === 1 /* IMAGE */ ? {
|
|
@@ -1931,7 +1998,6 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1931
1998
|
file_item: {
|
|
1932
1999
|
media,
|
|
1933
2000
|
file_name: fileName,
|
|
1934
|
-
md5: rawMd5,
|
|
1935
2001
|
len: String(data.length)
|
|
1936
2002
|
}
|
|
1937
2003
|
};
|
|
@@ -1948,7 +2014,7 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1948
2014
|
item_list: [item],
|
|
1949
2015
|
context_token: contextToken
|
|
1950
2016
|
},
|
|
1951
|
-
base_info:
|
|
2017
|
+
base_info: baseInfo()
|
|
1952
2018
|
}, 15000);
|
|
1953
2019
|
logger.info(`Sent ${mediaType === 1 /* IMAGE */ ? "image" : "file"} to ${to}: ${fileName} (${data.length} bytes)`);
|
|
1954
2020
|
return { status: "sent", mediaType, bytes: data.length };
|
|
@@ -1956,7 +2022,7 @@ async function uploadAndSendFile(creds, to, contextToken, filePath, maxSizeBytes
|
|
|
1956
2022
|
lastSendError = err;
|
|
1957
2023
|
if (attempt < SEND_MAX_RETRIES) {
|
|
1958
2024
|
logger.warn(`Send retry ${attempt + 1}/${SEND_MAX_RETRIES}:`, err);
|
|
1959
|
-
await
|
|
2025
|
+
await sleep(1000 * (attempt + 1));
|
|
1960
2026
|
}
|
|
1961
2027
|
}
|
|
1962
2028
|
}
|
|
@@ -1997,9 +2063,6 @@ function stripMarkdown(text) {
|
|
|
1997
2063
|
return result.trim();
|
|
1998
2064
|
}
|
|
1999
2065
|
|
|
2000
|
-
// src/engine/session.ts
|
|
2001
|
-
import { createAgentSession, SessionManager } from "@oh-my-pi/pi-coding-agent";
|
|
2002
|
-
|
|
2003
2066
|
// src/engine/session-store.ts
|
|
2004
2067
|
import { join as join7 } from "path";
|
|
2005
2068
|
import { homedir as homedir6 } from "os";
|
|
@@ -2137,6 +2200,17 @@ function clearAllSessions() {
|
|
|
2137
2200
|
// src/engine/session.ts
|
|
2138
2201
|
import { mkdirSync as mkdirSync6, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
2139
2202
|
import { join as join8 } from "path";
|
|
2203
|
+
var sdkPromise = null;
|
|
2204
|
+
function loadSdk() {
|
|
2205
|
+
sdkPromise ??= (async () => {
|
|
2206
|
+
try {
|
|
2207
|
+
return await import("@oh-my-pi/pi-coding-agent");
|
|
2208
|
+
} catch {
|
|
2209
|
+
return await import("@earendil-works/pi-coding-agent");
|
|
2210
|
+
}
|
|
2211
|
+
})();
|
|
2212
|
+
return sdkPromise;
|
|
2213
|
+
}
|
|
2140
2214
|
function outboxInstructions(outboxDir) {
|
|
2141
2215
|
return `## File delivery to WeChat
|
|
2142
2216
|
|
|
@@ -2195,9 +2269,10 @@ class ChatSession {
|
|
|
2195
2269
|
}
|
|
2196
2270
|
ensureSessionsDir();
|
|
2197
2271
|
const sessionDir = sessionDirFor(chatId);
|
|
2198
|
-
const
|
|
2272
|
+
const sdk = await loadSdk();
|
|
2273
|
+
const sessionManager = await sdk.SessionManager.continueRecent(config.cwd || process.cwd(), sessionDir);
|
|
2199
2274
|
logger.info(`Session dir: ${sessionDir} (resumed=${sessionManager.getSessionFile() !== null})`);
|
|
2200
|
-
const { session, modelFallbackMessage } = await createAgentSession({
|
|
2275
|
+
const { session, modelFallbackMessage } = await sdk.createAgentSession({
|
|
2201
2276
|
sessionManager,
|
|
2202
2277
|
enableMCP: false,
|
|
2203
2278
|
enableLsp: false,
|
|
@@ -2589,7 +2664,7 @@ class WeChatBridge {
|
|
|
2589
2664
|
this.commands.register(new ModelCommand);
|
|
2590
2665
|
this.commands.register(new NewSessionCommand);
|
|
2591
2666
|
}
|
|
2592
|
-
start() {
|
|
2667
|
+
async start() {
|
|
2593
2668
|
const config = loadConfig();
|
|
2594
2669
|
let creds;
|
|
2595
2670
|
try {
|
|
@@ -2600,7 +2675,7 @@ class WeChatBridge {
|
|
|
2600
2675
|
if (this.pollActive) {
|
|
2601
2676
|
return this.state;
|
|
2602
2677
|
}
|
|
2603
|
-
if (!this.acquireLock()) {
|
|
2678
|
+
if (!await this.acquireLock()) {
|
|
2604
2679
|
logger.debug("Another poll loop is running (port lock held), skipping");
|
|
2605
2680
|
return { running: false, config, creds, lastError: "another instance running" };
|
|
2606
2681
|
}
|
|
@@ -2653,15 +2728,9 @@ class WeChatBridge {
|
|
|
2653
2728
|
getPoolStatus() {
|
|
2654
2729
|
return this.pool?.getPoolStatus() ?? { count: 0, max: 0, chats: [] };
|
|
2655
2730
|
}
|
|
2656
|
-
acquireLock() {
|
|
2731
|
+
async acquireLock() {
|
|
2657
2732
|
try {
|
|
2658
|
-
this.lockServer =
|
|
2659
|
-
port: LOCK_PORT,
|
|
2660
|
-
hostname: "127.0.0.1",
|
|
2661
|
-
fetch() {
|
|
2662
|
-
return new Response("ok");
|
|
2663
|
-
}
|
|
2664
|
-
});
|
|
2733
|
+
this.lockServer = await listenPort(LOCK_PORT);
|
|
2665
2734
|
return true;
|
|
2666
2735
|
} catch {
|
|
2667
2736
|
return false;
|
|
@@ -2669,7 +2738,7 @@ class WeChatBridge {
|
|
|
2669
2738
|
}
|
|
2670
2739
|
releaseLock() {
|
|
2671
2740
|
if (this.lockServer) {
|
|
2672
|
-
this.lockServer.stop(
|
|
2741
|
+
this.lockServer.stop();
|
|
2673
2742
|
this.lockServer = null;
|
|
2674
2743
|
}
|
|
2675
2744
|
}
|
|
@@ -2685,9 +2754,9 @@ class WeChatBridge {
|
|
|
2685
2754
|
logger.warn(`getupdates error ret=${resp.ret} errmsg=${resp.errmsg ?? ""} (${failures}/${MAX_FAILURES})`);
|
|
2686
2755
|
if (failures >= MAX_FAILURES) {
|
|
2687
2756
|
failures = 0;
|
|
2688
|
-
await
|
|
2757
|
+
await sleep(BACKOFF_MS);
|
|
2689
2758
|
} else {
|
|
2690
|
-
await
|
|
2759
|
+
await sleep(RETRY_MS);
|
|
2691
2760
|
}
|
|
2692
2761
|
continue;
|
|
2693
2762
|
}
|
|
@@ -2708,9 +2777,9 @@ class WeChatBridge {
|
|
|
2708
2777
|
logger.error(`Poll error (${failures}/${MAX_FAILURES}):`, err);
|
|
2709
2778
|
if (failures >= MAX_FAILURES) {
|
|
2710
2779
|
failures = 0;
|
|
2711
|
-
await
|
|
2780
|
+
await sleep(BACKOFF_MS);
|
|
2712
2781
|
} else {
|
|
2713
|
-
await
|
|
2782
|
+
await sleep(RETRY_MS);
|
|
2714
2783
|
}
|
|
2715
2784
|
}
|
|
2716
2785
|
}
|
|
@@ -2879,7 +2948,7 @@ ${truncated}
|
|
|
2879
2948
|
return;
|
|
2880
2949
|
}
|
|
2881
2950
|
logger.warn(`[${chatId}] Send retry ${retries}/${MAX_SEND_RETRIES}:`, err);
|
|
2882
|
-
await
|
|
2951
|
+
await sleep(1000 * retries);
|
|
2883
2952
|
}
|
|
2884
2953
|
}
|
|
2885
2954
|
}
|
|
@@ -2958,21 +3027,21 @@ function installLaunchd() {
|
|
|
2958
3027
|
mkdirSync7(getLogDir(), { recursive: true });
|
|
2959
3028
|
const plist = plistPath();
|
|
2960
3029
|
if (existsSync3(plist)) {
|
|
2961
|
-
|
|
3030
|
+
spawnSync(["launchctl", "unload", plist], { stderr: "ignore" });
|
|
2962
3031
|
}
|
|
2963
3032
|
writeFileSync4(plist, generatePlist());
|
|
2964
|
-
const result =
|
|
3033
|
+
const result = spawnSync(["launchctl", "load", plist], { stderr: "inherit" });
|
|
2965
3034
|
if (result.exitCode !== 0) {
|
|
2966
3035
|
throw new Error("launchctl load failed");
|
|
2967
3036
|
}
|
|
2968
|
-
|
|
3037
|
+
spawnSync(["launchctl", "start", PLIST_LABEL], { stderr: "inherit" });
|
|
2969
3038
|
}
|
|
2970
3039
|
function uninstallLaunchd() {
|
|
2971
3040
|
const plist = plistPath();
|
|
2972
3041
|
if (!existsSync3(plist)) {
|
|
2973
3042
|
throw new Error("No launchd service found (may not be installed)");
|
|
2974
3043
|
}
|
|
2975
|
-
|
|
3044
|
+
spawnSync(["launchctl", "unload", plist], { stderr: "inherit" });
|
|
2976
3045
|
rmSync3(plist);
|
|
2977
3046
|
}
|
|
2978
3047
|
function servicePath() {
|
|
@@ -3015,20 +3084,20 @@ function installSystemd() {
|
|
|
3015
3084
|
const svc = servicePath();
|
|
3016
3085
|
mkdirSync7(getLogDir(), { recursive: true });
|
|
3017
3086
|
if (existsSync3(svc)) {
|
|
3018
|
-
|
|
3087
|
+
spawnSync(["sudo", "systemctl", "stop", SERVICE_NAME], { stderr: "inherit" });
|
|
3019
3088
|
}
|
|
3020
3089
|
const tmp = `/tmp/${SERVICE_NAME}.service`;
|
|
3021
3090
|
writeFileSync4(tmp, generateService());
|
|
3022
|
-
let result =
|
|
3091
|
+
let result = spawnSync(["sudo", "te", tmp, svc], { stderr: "inherit" });
|
|
3023
3092
|
if (result.exitCode !== 0) {
|
|
3024
|
-
result =
|
|
3093
|
+
result = spawnSync(["sudo", "cp", tmp, svc], { stderr: "inherit" });
|
|
3025
3094
|
}
|
|
3026
3095
|
rmSync3(tmp);
|
|
3027
3096
|
if (result.exitCode !== 0) {
|
|
3028
3097
|
throw new Error("Failed to write service file (need sudo)");
|
|
3029
3098
|
}
|
|
3030
|
-
|
|
3031
|
-
result =
|
|
3099
|
+
spawnSync(["sudo", "systemctl", "daemon-reload"], { stderr: "inherit" });
|
|
3100
|
+
result = spawnSync(["sudo", "systemctl", "enable", "--now", SERVICE_NAME], { stderr: "inherit" });
|
|
3032
3101
|
if (result.exitCode !== 0) {
|
|
3033
3102
|
throw new Error("systemctl enable failed");
|
|
3034
3103
|
}
|
|
@@ -3038,10 +3107,10 @@ function uninstallSystemd() {
|
|
|
3038
3107
|
if (!existsSync3(svc)) {
|
|
3039
3108
|
throw new Error("No systemd service found (may not be installed)");
|
|
3040
3109
|
}
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3110
|
+
spawnSync(["sudo", "systemctl", "stop", SERVICE_NAME], { stderr: "inherit" });
|
|
3111
|
+
spawnSync(["sudo", "systemctl", "disable", SERVICE_NAME], { stderr: "inherit" });
|
|
3112
|
+
spawnSync(["sudo", "rm", svc], { stderr: "inherit" });
|
|
3113
|
+
spawnSync(["sudo", "systemctl", "daemon-reload"], { stderr: "inherit" });
|
|
3045
3114
|
}
|
|
3046
3115
|
var WIN_TASK_NAME = "OMP-Wechat";
|
|
3047
3116
|
function winScriptPath() {
|
|
@@ -3091,22 +3160,22 @@ function installWinTask() {
|
|
|
3091
3160
|
mkdirSync7(join9(homedir7(), ".omp-wechat"), { recursive: true });
|
|
3092
3161
|
mkdirSync7(getLogDir(), { recursive: true });
|
|
3093
3162
|
writeFileSync4(winScriptPath(), generateWinScript());
|
|
3094
|
-
|
|
3095
|
-
|
|
3163
|
+
spawnSync(["schtasks", "/end", "/tn", WIN_TASK_NAME], { stderr: "ignore" });
|
|
3164
|
+
spawnSync(["schtasks", "/delete", "/tn", WIN_TASK_NAME, "/f"], { stderr: "ignore" });
|
|
3096
3165
|
const scriptPath = winScriptPath();
|
|
3097
3166
|
const taskCmd = `powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "${scriptPath}"`;
|
|
3098
|
-
const result =
|
|
3167
|
+
const result = spawnSync(["schtasks", "/create", "/tn", WIN_TASK_NAME, "/tr", taskCmd, "/sc", "onlogon", "/rl", "limited", "/f"], { stderr: "inherit" });
|
|
3099
3168
|
if (result.exitCode !== 0) {
|
|
3100
3169
|
throw new Error("schtasks /create failed");
|
|
3101
3170
|
}
|
|
3102
|
-
const runResult =
|
|
3171
|
+
const runResult = spawnSync(["schtasks", "/run", "/tn", WIN_TASK_NAME], { stderr: "inherit" });
|
|
3103
3172
|
if (runResult.exitCode !== 0) {
|
|
3104
3173
|
logger.warn(`schtasks /run failed (exit ${runResult.exitCode}) \u2014 task will start at next logon`);
|
|
3105
3174
|
}
|
|
3106
3175
|
}
|
|
3107
3176
|
function uninstallWinTask() {
|
|
3108
|
-
|
|
3109
|
-
const result =
|
|
3177
|
+
spawnSync(["schtasks", "/end", "/tn", WIN_TASK_NAME], { stderr: "ignore" });
|
|
3178
|
+
const result = spawnSync(["schtasks", "/delete", "/tn", WIN_TASK_NAME, "/f"], { stderr: "inherit" });
|
|
3110
3179
|
if (result.exitCode !== 0) {
|
|
3111
3180
|
throw new Error("Failed to delete scheduled task (may not be installed)");
|
|
3112
3181
|
}
|
|
@@ -3116,7 +3185,7 @@ function uninstallWinTask() {
|
|
|
3116
3185
|
}
|
|
3117
3186
|
}
|
|
3118
3187
|
function winTaskExists() {
|
|
3119
|
-
const r =
|
|
3188
|
+
const r = spawnSync(["schtasks", "/query", "/tn", WIN_TASK_NAME, "/fo", "list"], {
|
|
3120
3189
|
stdout: "ignore",
|
|
3121
3190
|
stderr: "ignore"
|
|
3122
3191
|
});
|
|
@@ -3171,20 +3240,25 @@ function isServiceInstalled() {
|
|
|
3171
3240
|
// src/index.ts
|
|
3172
3241
|
var bridge = null;
|
|
3173
3242
|
var daemonState = null;
|
|
3174
|
-
function wechatExtension(pi) {
|
|
3243
|
+
async function wechatExtension(pi) {
|
|
3175
3244
|
if (pi.pi && typeof pi.setLabel === "function") {
|
|
3176
3245
|
pi.setLabel("OMP-Wechat Bridge");
|
|
3177
3246
|
}
|
|
3178
3247
|
bridge = new WeChatBridge;
|
|
3179
|
-
daemonState = bridge.start();
|
|
3248
|
+
daemonState = await bridge.start();
|
|
3180
3249
|
if (daemonState.running) {
|
|
3181
3250
|
logger.info("WeChat bridge started at extension load");
|
|
3182
3251
|
} else {
|
|
3183
3252
|
logger.debug("WeChat bridge not running, starting 30s retry", { lastError: daemonState.lastError });
|
|
3184
|
-
setInterval(() => {
|
|
3253
|
+
setInterval(async () => {
|
|
3185
3254
|
if (daemonState?.running)
|
|
3186
3255
|
return;
|
|
3187
|
-
|
|
3256
|
+
try {
|
|
3257
|
+
daemonState = await bridge.start();
|
|
3258
|
+
} catch (err) {
|
|
3259
|
+
logger.error("WeChat bridge restart failed:", err);
|
|
3260
|
+
return;
|
|
3261
|
+
}
|
|
3188
3262
|
if (daemonState.running) {
|
|
3189
3263
|
logger.info("WeChat bridge: took over from failed instance");
|
|
3190
3264
|
}
|
|
@@ -3192,7 +3266,12 @@ function wechatExtension(pi) {
|
|
|
3192
3266
|
}
|
|
3193
3267
|
pi.on("session_start", async (_event, ctx) => {
|
|
3194
3268
|
if (bridge && !daemonState?.running) {
|
|
3195
|
-
|
|
3269
|
+
try {
|
|
3270
|
+
daemonState = await bridge.start();
|
|
3271
|
+
} catch (err) {
|
|
3272
|
+
logger.error("WeChat bridge start failed:", err);
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
3196
3275
|
if (daemonState.running) {
|
|
3197
3276
|
ctx.ui.notify("WeChat bridge started", "info");
|
|
3198
3277
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omp-wechat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "OMP/Pi extension: bridge WeChat messages to OMP's AI engine via the iLink Bot API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"README.md"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "bun build src/index.ts --outdir dist --target bun --external omp-legacy-pi-modules --external '@oh-my-pi/*'",
|
|
12
|
+
"build": "bun build src/index.ts --outdir dist --target bun --external omp-legacy-pi-modules --external '@oh-my-pi/*' --external '@earendil-works/*'",
|
|
13
13
|
"typecheck": "tsc --noEmit"
|
|
14
14
|
},
|
|
15
15
|
"omp": {
|