cli-wechat-bridge 1.1.2 → 1.1.4
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/README.md +129 -150
- package/bin/_run-entry.mjs +12 -0
- package/bin/wechat-claude-start.mjs +7 -2
- package/bin/wechat-claude.mjs +1 -1
- package/bin/wechat-codex-start.mjs +7 -2
- package/bin/wechat-codex.mjs +1 -1
- package/bin/wechat-opencode-start.mjs +7 -2
- package/bin/wechat-opencode.mjs +1 -1
- package/bin/wechat-pi-start.mjs +10 -0
- package/bin/wechat-pi.mjs +5 -0
- package/dist/bridge/bridge-adapter-common.js +2 -0
- package/dist/bridge/bridge-adapters.claude.js +21 -1
- package/dist/bridge/bridge-adapters.codex.js +85 -6
- package/dist/bridge/bridge-adapters.core.js +112 -6
- package/dist/bridge/bridge-adapters.js +5 -3
- package/dist/bridge/bridge-adapters.opencode.js +390 -52
- package/dist/bridge/bridge-adapters.pi.js +707 -0
- package/dist/bridge/bridge-adapters.shared.js +22 -102
- package/dist/bridge/bridge-final-reply.js +17 -2
- package/dist/bridge/bridge-process-reaper.js +14 -4
- package/dist/bridge/bridge-state.js +42 -6
- package/dist/bridge/bridge-utils.js +94 -237
- package/dist/bridge/wechat-bridge.js +77 -131
- package/dist/bridge/wechat-forwarding.js +58 -0
- package/dist/companion/codex-remote-client.js +20 -6
- package/dist/companion/local-companion-link.js +13 -3
- package/dist/companion/local-companion-start.js +64 -16
- package/dist/companion/local-companion.js +8 -5
- package/dist/companion/pi-tui-bridge-extension.js +256 -0
- package/dist/daemon/daemon-link.js +25 -3
- package/dist/daemon/wechat-daemon.js +264 -77
- package/dist/i18n/index.js +0 -3
- package/dist/i18n/messages-en.js +4 -5
- package/dist/i18n/messages-zh.js +4 -5
- package/dist/utils/atomic-file.js +15 -0
- package/dist/utils/doctor.js +27 -11
- package/dist/wechat/channel-config.js +0 -2
- package/dist/wechat/setup.js +5 -9
- package/dist/wechat/wechat-transport.js +14 -8
- package/package.json +113 -102
- package/bin/wechat-bridge-claude.mjs +0 -5
- package/bin/wechat-bridge-codex.mjs +0 -5
- package/bin/wechat-bridge-opencode.mjs +0 -5
- package/bin/wechat-bridge-shell.mjs +0 -5
- package/bin/wechat-bridge.mjs +0 -5
- package/dist/bridge/bridge-adapters.shell.js +0 -363
package/dist/i18n/messages-zh.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
// === 桥接欢迎 & 控制 ===
|
|
3
|
-
"bridge.welcome": "微信桥接就绪 ({adapter})。\n工作目录: {cwd}
|
|
3
|
+
"bridge.welcome": "微信桥接就绪 ({adapter})。\n工作目录: {cwd}",
|
|
4
4
|
"bridge.stopped": "桥接已停止。",
|
|
5
5
|
"bridge.interrupt.sent": "已发送中断信号。",
|
|
6
6
|
"bridge.interrupt.notBusy": "没有正在执行的任务可中断。",
|
|
@@ -11,8 +11,8 @@ export const messages = {
|
|
|
11
11
|
"bridge.fatalError": "桥接错误: {message}",
|
|
12
12
|
"bridge.backlogIgnored": "已忽略 {count} 条桥接启动前的积压消息(不会自动处理)。\n如果你是在桥接启动后才发送的消息却看到此提示,说明本机系统时钟可能不准(偏差超过 {graceSeconds} 秒),请校准时间后重启桥接。",
|
|
13
13
|
// === Daemon 欢迎 & 控制 ===
|
|
14
|
-
"daemon.welcome": "微信 Daemon 就绪。\n工作目录: {cwd}\n当前: {adapter}\n\n命令: /claude, /codex, /opencode, /stop, /confirm, /deny, /status\n{bindings}\n\n管理: /bind [表情] 命令, /unbind [表情], /bindings",
|
|
15
|
-
"daemon.noActiveAdapter": "未选择活跃终端。发送 /codex、/claude 或 /
|
|
14
|
+
"daemon.welcome": "微信 Daemon 就绪。\n工作目录: {cwd}\n当前: {adapter}\n\n命令: /claude, /codex, /opencode, /pi, /stop, /confirm, /deny, /status\n{bindings}\n\n管理: /bind [表情] 命令, /unbind [表情], /bindings",
|
|
15
|
+
"daemon.noActiveAdapter": "未选择活跃终端。发送 /codex、/claude、/opencode 或 /pi 启动一个。",
|
|
16
16
|
"daemon.switchResult.new": "已启动新的可见 CLI。",
|
|
17
17
|
"daemon.switchResult.reused": "已复用现有的可见 CLI。",
|
|
18
18
|
// === 审批 ===
|
|
@@ -66,7 +66,6 @@ export const messages = {
|
|
|
66
66
|
"doctor.clock.ok": "与服务器时间偏差约 {skewSeconds}s",
|
|
67
67
|
"doctor.clock.skewWarning": "与服务器时间偏差约 {skewSeconds}s(偏差过大会导致桥接启动后的消息被当作积压忽略,请校准系统时间)",
|
|
68
68
|
"doctor.label.nodePty": "node-pty",
|
|
69
|
-
"doctor.label.shell": "shell",
|
|
70
69
|
"doctor.label.dataDir": "数据目录",
|
|
71
70
|
"doctor.label.credentials": "凭据",
|
|
72
71
|
"doctor.label.mode": "模式",
|
|
@@ -79,7 +78,6 @@ export const messages = {
|
|
|
79
78
|
"doctor.winBuildConpty": "(ConPTY 需要 build 18309+)",
|
|
80
79
|
"doctor.nodePty.loaded": "已加载",
|
|
81
80
|
"doctor.nodePty.fix": "修复: {fix}",
|
|
82
|
-
"doctor.adapterCli.shellNative": "使用本机 shell,无需检查其它适配器 CLI。",
|
|
83
81
|
"doctor.adapterCli.notFound": "未找到{optional}",
|
|
84
82
|
"doctor.dataDirMissing": "(首次运行会创建)",
|
|
85
83
|
"doctor.credentialsFound": "已找到",
|
|
@@ -88,6 +86,7 @@ export const messages = {
|
|
|
88
86
|
"doctor.mode.generic": "通用",
|
|
89
87
|
"doctor.notSpecified": "(未指定)",
|
|
90
88
|
"doctor.none": "无",
|
|
89
|
+
"doctor.endpoint.corrupted": "endpoint 文件存在但无法解析;下次成功写入时将被替换",
|
|
91
90
|
"doctor.unknown": "未知",
|
|
92
91
|
"doctor.yes": "是",
|
|
93
92
|
"doctor.no": "否",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { ensureChannelDataDir } from "../wechat/channel-config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Write JSON atomically via temp file + rename, so a crash mid-write cannot
|
|
5
|
+
* leave a truncated or half-written file behind. Cross-process readers (the
|
|
6
|
+
* daemon, launchers, companions) either see the previous complete file or the
|
|
7
|
+
* new complete file — never a torn write.
|
|
8
|
+
*/
|
|
9
|
+
export function writeJsonFileAtomic(filePath, value) {
|
|
10
|
+
ensureChannelDataDir();
|
|
11
|
+
const data = JSON.stringify(value, null, 2);
|
|
12
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
13
|
+
fs.writeFileSync(tempPath, data, "utf-8");
|
|
14
|
+
fs.renameSync(tempPath, filePath);
|
|
15
|
+
}
|
package/dist/utils/doctor.js
CHANGED
|
@@ -7,7 +7,7 @@ import { normalizeBridgeLockPayload, shouldAutoReclaimBridgeLock, } from "../bri
|
|
|
7
7
|
import { readLocalCompanionEndpoint as readWorkspaceEndpoint, } from "../companion/local-companion-link.js";
|
|
8
8
|
import { isDaemonEndpointAlive, } from "../daemon/daemon-link.js";
|
|
9
9
|
import { t } from "../i18n/index.js";
|
|
10
|
-
import { DEFAULT_BASE_URL, resolveChannelDataDir } from "../wechat/channel-config.js";
|
|
10
|
+
import { DEFAULT_BASE_URL, getWorkspaceAdapterEndpointFile, getWorkspaceChannelPaths, resolveChannelDataDir, } from "../wechat/channel-config.js";
|
|
11
11
|
const STATE_OK = "[ok]";
|
|
12
12
|
const STATE_WARN = "[warn]";
|
|
13
13
|
const STATE_FAIL = "[fail]";
|
|
@@ -174,7 +174,7 @@ function isBridgeAdapterKind(value) {
|
|
|
174
174
|
return (value === "codex" ||
|
|
175
175
|
value === "claude" ||
|
|
176
176
|
value === "opencode" ||
|
|
177
|
-
value === "
|
|
177
|
+
value === "pi");
|
|
178
178
|
}
|
|
179
179
|
export function parseDoctorCliArgs(argv, mode = "generic", fallbackCwd = process.cwd()) {
|
|
180
180
|
let cwd = fallbackCwd;
|
|
@@ -402,7 +402,7 @@ function chooseEndpointAdapters(options, lock) {
|
|
|
402
402
|
return [lock.adapter];
|
|
403
403
|
}
|
|
404
404
|
return options.mode === "daemon"
|
|
405
|
-
? ["codex", "claude", "opencode"]
|
|
405
|
+
? ["codex", "claude", "opencode", "pi"]
|
|
406
406
|
: ["codex"];
|
|
407
407
|
}
|
|
408
408
|
function chooseCliChecks(options) {
|
|
@@ -414,8 +414,8 @@ function chooseCliChecks(options) {
|
|
|
414
414
|
return [{ name: "claude", label: "Claude CLI", optional: false }];
|
|
415
415
|
case "opencode":
|
|
416
416
|
return [{ name: "opencode", label: "OpenCode", optional: false }];
|
|
417
|
-
case "
|
|
418
|
-
return [];
|
|
417
|
+
case "pi":
|
|
418
|
+
return [{ name: "pi", label: "Pi", optional: false }];
|
|
419
419
|
default:
|
|
420
420
|
return [];
|
|
421
421
|
}
|
|
@@ -424,15 +424,11 @@ function chooseCliChecks(options) {
|
|
|
424
424
|
{ name: "codex", label: "Codex CLI", optional: true },
|
|
425
425
|
{ name: "claude", label: "Claude CLI", optional: true },
|
|
426
426
|
{ name: "opencode", label: "OpenCode", optional: true },
|
|
427
|
+
{ name: "pi", label: "Pi", optional: true },
|
|
427
428
|
];
|
|
428
429
|
}
|
|
429
430
|
function appendCliLines(lines, options, deps) {
|
|
430
431
|
const clis = chooseCliChecks(options);
|
|
431
|
-
if (options.mode === "bridge" && options.adapter === "shell") {
|
|
432
|
-
section(lines, msg("section.adapterCli"));
|
|
433
|
-
lines.push(row(STATE_OK, msg("label.shell"), msg("adapterCli.shellNative")));
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
432
|
if (clis.length === 0) {
|
|
437
433
|
return;
|
|
438
434
|
}
|
|
@@ -515,6 +511,18 @@ async function appendEndpointSummary(lines, label, endpoint, options, lock, deps
|
|
|
515
511
|
lines.push(detail(msg("issue", { issue })));
|
|
516
512
|
}
|
|
517
513
|
}
|
|
514
|
+
function endpointFileState(filePath) {
|
|
515
|
+
if (!fs.existsSync(filePath)) {
|
|
516
|
+
return "missing";
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
520
|
+
return "readable";
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
return "corrupted";
|
|
524
|
+
}
|
|
525
|
+
}
|
|
518
526
|
async function appendWorkspaceEndpointLines(lines, options, lock, deps) {
|
|
519
527
|
const adapters = chooseEndpointAdapters(options, lock);
|
|
520
528
|
const seenEndpoints = new Set();
|
|
@@ -523,12 +531,20 @@ async function appendWorkspaceEndpointLines(lines, options, lock, deps) {
|
|
|
523
531
|
if (endpoint) {
|
|
524
532
|
seenEndpoints.add(`${endpoint.kind}:${endpoint.instanceId}:${endpoint.port}`);
|
|
525
533
|
}
|
|
534
|
+
else if (endpointFileState(getWorkspaceAdapterEndpointFile(options.cwd, adapter)) ===
|
|
535
|
+
"corrupted") {
|
|
536
|
+
// A torn or otherwise unparsable endpoint file must not read as a
|
|
537
|
+
// healthy "none" — surface it so the operator knows to clear it.
|
|
538
|
+
lines.push(row(STATE_WARN, msg("label.workspaceEndpoint", { adapter }), msg("endpoint.corrupted")));
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
526
541
|
await appendEndpointSummary(lines, msg("label.workspaceEndpoint", { adapter }), endpoint, { ...options, adapter }, lock, deps);
|
|
527
542
|
}
|
|
528
543
|
const legacyEndpoint = deps.readLocalCompanionEndpoint(options.cwd);
|
|
529
544
|
const legacyLabel = msg("label.legacyEndpoint");
|
|
530
545
|
if (!legacyEndpoint) {
|
|
531
|
-
|
|
546
|
+
const legacyFileState = endpointFileState(getWorkspaceChannelPaths(options.cwd).endpointFile);
|
|
547
|
+
lines.push(row(legacyFileState === "corrupted" ? STATE_WARN : STATE_OK, legacyLabel, legacyFileState === "corrupted" ? msg("endpoint.corrupted") : msg("none")));
|
|
532
548
|
return;
|
|
533
549
|
}
|
|
534
550
|
const legacyKey = `${legacyEndpoint.kind}:${legacyEndpoint.instanceId}:${legacyEndpoint.port}`;
|
|
@@ -16,7 +16,6 @@ export const CHANNEL_DATA_DIR = resolveChannelDataDir();
|
|
|
16
16
|
export const CREDENTIALS_FILE = path.join(CHANNEL_DATA_DIR, "account.json");
|
|
17
17
|
export const SYNC_BUF_FILE = path.join(CHANNEL_DATA_DIR, "sync_buf.txt");
|
|
18
18
|
export const CONTEXT_CACHE_FILE = path.join(CHANNEL_DATA_DIR, "context_tokens.json");
|
|
19
|
-
export const BRIDGE_STATE_FILE = path.join(CHANNEL_DATA_DIR, "bridge-state.json");
|
|
20
19
|
export const BRIDGE_LOG_FILE = path.join(CHANNEL_DATA_DIR, "bridge.log");
|
|
21
20
|
// Hard cap for bridge.log. Long-running daemons otherwise grow it without bound.
|
|
22
21
|
export const BRIDGE_LOG_MAX_BYTES = 5 * 1024 * 1024; // 5 MiB
|
|
@@ -48,7 +47,6 @@ export function appendBoundedLog(filePath, line) {
|
|
|
48
47
|
}
|
|
49
48
|
export const BRIDGE_LOCK_FILE = path.join(CHANNEL_DATA_DIR, "bridge.lock.json");
|
|
50
49
|
export const DAEMON_ENDPOINT_FILE = path.join(CHANNEL_DATA_DIR, "daemon-endpoint.json");
|
|
51
|
-
export const CODEX_PANEL_ENDPOINT_FILE = path.join(CHANNEL_DATA_DIR, "codex-panel-endpoint.json");
|
|
52
50
|
export const WORKSPACES_DIR = path.join(CHANNEL_DATA_DIR, "workspaces");
|
|
53
51
|
export const INBOUND_MESSAGE_CLAIMS_DIR = path.join(CHANNEL_DATA_DIR, "inbound-message-claims");
|
|
54
52
|
export const INBOUND_ATTACHMENTS_DIR = path.join(CHANNEL_DATA_DIR, "inbound-attachments");
|
package/dist/wechat/setup.js
CHANGED
|
@@ -166,15 +166,11 @@ function printPostLoginHelp(log) {
|
|
|
166
166
|
log("This WeChat account is now authorized for the bridge.");
|
|
167
167
|
log("");
|
|
168
168
|
log("Start from any project directory with one of:");
|
|
169
|
-
log(" wechat-codex
|
|
170
|
-
log(" wechat-claude
|
|
171
|
-
log(" wechat-opencode
|
|
172
|
-
log(" wechat-
|
|
173
|
-
log("");
|
|
174
|
-
log("Manual two-terminal mode is also available:");
|
|
175
|
-
log(" wechat-bridge-codex + wechat-codex");
|
|
176
|
-
log(" wechat-bridge-claude + wechat-claude");
|
|
177
|
-
log(" wechat-bridge-opencode + wechat-opencode");
|
|
169
|
+
log(" wechat-codex");
|
|
170
|
+
log(" wechat-claude");
|
|
171
|
+
log(" wechat-opencode");
|
|
172
|
+
log(" wechat-pi");
|
|
173
|
+
log(" wechat-daemon");
|
|
178
174
|
log("");
|
|
179
175
|
log("Run wechat-setup again any time you need to refresh the login.");
|
|
180
176
|
}
|
|
@@ -3,6 +3,7 @@ import { createCipheriv, createDecipheriv } from "node:crypto";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { CONTEXT_CACHE_FILE, CREDENTIALS_FILE, ensureChannelDataDir, INBOUND_ATTACHMENTS_DIR, INBOUND_MESSAGE_CLAIMS_DIR, migrateLegacyChannelFiles, SYNC_BUF_FILE, } from "./channel-config.js";
|
|
6
|
+
import { writeJsonFileAtomic } from "../utils/atomic-file.js";
|
|
6
7
|
export const DEFAULT_LONG_POLL_TIMEOUT_MS = 35_000;
|
|
7
8
|
const CDN_BASE_URL = "https://novac2c.cdn.weixin.qq.com/c2c";
|
|
8
9
|
const CHANNEL_VERSION = "0.3.0";
|
|
@@ -10,6 +11,7 @@ const RECENT_MESSAGE_CACHE_SIZE = 500;
|
|
|
10
11
|
const BYTES_PER_MB = 1024 * 1024;
|
|
11
12
|
const SEND_TIMEOUT_MS = 15_000;
|
|
12
13
|
const INBOUND_DOWNLOAD_TIMEOUT_MS = 30_000;
|
|
14
|
+
const CDN_UPLOAD_TIMEOUT_MS = 60_000;
|
|
13
15
|
const CDN_MAX_RETRIES = 3;
|
|
14
16
|
const ERROR_CAUSE_DEPTH_LIMIT = 4;
|
|
15
17
|
const INBOUND_MESSAGE_CLAIM_TTL_MS = 10 * 60 * 1000;
|
|
@@ -305,13 +307,7 @@ export function classifyWechatTransportError(error) {
|
|
|
305
307
|
return { kind: "unknown", retryable: false };
|
|
306
308
|
}
|
|
307
309
|
function writeJsonFile(filePath, value) {
|
|
308
|
-
|
|
309
|
-
const data = JSON.stringify(value, null, 2);
|
|
310
|
-
// Atomic write via temp file + rename, so a crash mid-write cannot leave a
|
|
311
|
-
// truncated/half-written JSON that would break readers on the next launch.
|
|
312
|
-
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
313
|
-
fs.writeFileSync(tempPath, data, "utf-8");
|
|
314
|
-
fs.renameSync(tempPath, filePath);
|
|
310
|
+
writeJsonFileAtomic(filePath, value);
|
|
315
311
|
}
|
|
316
312
|
function randomWechatUin() {
|
|
317
313
|
const uint32 = crypto.randomBytes(4).readUInt32BE(0);
|
|
@@ -343,8 +339,11 @@ async function apiFetch(params) {
|
|
|
343
339
|
body: params.body,
|
|
344
340
|
signal: controller.signal,
|
|
345
341
|
});
|
|
346
|
-
|
|
342
|
+
// Keep the abort timer armed until the body has been fully read: a server
|
|
343
|
+
// that sends headers and then stalls would otherwise leave res.text()
|
|
344
|
+
// pending forever, freezing the long-poll loop with no timeout at all.
|
|
347
345
|
const text = await res.text();
|
|
346
|
+
clearTimeout(timer);
|
|
348
347
|
if (!res.ok) {
|
|
349
348
|
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
350
349
|
}
|
|
@@ -495,12 +494,18 @@ async function uploadBufferToCdn(params) {
|
|
|
495
494
|
let downloadParam;
|
|
496
495
|
let lastError;
|
|
497
496
|
for (let attempt = 1; attempt <= CDN_MAX_RETRIES; attempt += 1) {
|
|
497
|
+
// Abort guard mirrors the download path: without it a stalled CDN upload
|
|
498
|
+
// hangs the send queue forever (no timeout, no signal).
|
|
499
|
+
const controller = new AbortController();
|
|
500
|
+
const timer = setTimeout(() => controller.abort(), CDN_UPLOAD_TIMEOUT_MS);
|
|
498
501
|
try {
|
|
499
502
|
const res = await fetch(cdnUrl, {
|
|
500
503
|
method: "POST",
|
|
501
504
|
headers: { "Content-Type": "application/octet-stream" },
|
|
502
505
|
body: new Uint8Array(ciphertext),
|
|
506
|
+
signal: controller.signal,
|
|
503
507
|
});
|
|
508
|
+
clearTimeout(timer);
|
|
504
509
|
if (res.status >= 400 && res.status < 500) {
|
|
505
510
|
const errMsg = res.headers.get("x-error-message") ?? (await res.text());
|
|
506
511
|
throw new Error(`CDN client error ${res.status}: ${errMsg}`);
|
|
@@ -516,6 +521,7 @@ async function uploadBufferToCdn(params) {
|
|
|
516
521
|
break;
|
|
517
522
|
}
|
|
518
523
|
catch (err) {
|
|
524
|
+
clearTimeout(timer);
|
|
519
525
|
lastError = err;
|
|
520
526
|
if (err instanceof Error && err.message.includes("client error")) {
|
|
521
527
|
throw err;
|
package/package.json
CHANGED
|
@@ -1,102 +1,113 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cli-wechat-bridge",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "CLI WeChat Bridge for Codex, Claude Code, OpenCode, and
|
|
5
|
-
"type": "module",
|
|
6
|
-
"files": [
|
|
7
|
-
"bin/",
|
|
8
|
-
"dist/",
|
|
9
|
-
"scripts/ensure-node-pty-permissions.mjs",
|
|
10
|
-
"README.md",
|
|
11
|
-
"LICENSE.txt"
|
|
12
|
-
],
|
|
13
|
-
"keywords": [
|
|
14
|
-
"wechat",
|
|
15
|
-
"cli",
|
|
16
|
-
"bridge",
|
|
17
|
-
"codex",
|
|
18
|
-
"claude",
|
|
19
|
-
"opencode",
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"wechat-
|
|
38
|
-
"wechat-codex": "bin/wechat-codex.mjs",
|
|
39
|
-
"wechat-
|
|
40
|
-
"wechat-claude": "bin/wechat-claude.mjs",
|
|
41
|
-
"wechat-
|
|
42
|
-
"wechat-
|
|
43
|
-
"wechat-
|
|
44
|
-
"wechat-
|
|
45
|
-
"wechat-
|
|
46
|
-
"wechat-
|
|
47
|
-
"wechat-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"bridge": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"claude
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"bridge:
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"bridge:bun": "bun src/bridge/wechat-bridge.ts",
|
|
78
|
-
"test": "bun test test",
|
|
79
|
-
"test:bridge": "bun test test/bridge",
|
|
80
|
-
"test:companion": "bun test test/companion",
|
|
81
|
-
"test:wechat": "bun test test/wechat",
|
|
82
|
-
"test:watch": "bun test --watch test"
|
|
83
|
-
},
|
|
84
|
-
"dependencies": {
|
|
85
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
86
|
-
"@opencode-ai/sdk": "^1.
|
|
87
|
-
"node-pty": "^1.1.0",
|
|
88
|
-
"qrcode-terminal": "^0.12.0"
|
|
89
|
-
},
|
|
90
|
-
"
|
|
91
|
-
"@
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "cli-wechat-bridge",
|
|
3
|
+
"version": "1.1.4",
|
|
4
|
+
"description": "CLI WeChat Bridge for Codex, Claude Code, OpenCode, and Pi over WeChat",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"bin/",
|
|
8
|
+
"dist/",
|
|
9
|
+
"scripts/ensure-node-pty-permissions.mjs",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE.txt"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"wechat",
|
|
15
|
+
"cli",
|
|
16
|
+
"bridge",
|
|
17
|
+
"codex",
|
|
18
|
+
"claude",
|
|
19
|
+
"opencode",
|
|
20
|
+
"pi",
|
|
21
|
+
"terminal"
|
|
22
|
+
],
|
|
23
|
+
"author": "UNLINEARITY",
|
|
24
|
+
"license": "AGPL-3.0-or-later",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/UNLINEARITY/CLI-WeChat-Bridge.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/UNLINEARITY/CLI-WeChat-Bridge#readme",
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"wechat-codex": "bin/wechat-codex.mjs",
|
|
38
|
+
"wechat-codex-start": "bin/wechat-codex-start.mjs",
|
|
39
|
+
"wechat-claude": "bin/wechat-claude.mjs",
|
|
40
|
+
"wechat-claude-start": "bin/wechat-claude-start.mjs",
|
|
41
|
+
"wechat-opencode": "bin/wechat-opencode.mjs",
|
|
42
|
+
"wechat-opencode-start": "bin/wechat-opencode-start.mjs",
|
|
43
|
+
"wechat-pi": "bin/wechat-pi.mjs",
|
|
44
|
+
"wechat-pi-start": "bin/wechat-pi-start.mjs",
|
|
45
|
+
"wechat-daemon": "bin/wechat-daemon.mjs",
|
|
46
|
+
"wechat-setup": "bin/wechat-setup.mjs",
|
|
47
|
+
"wechat-check-update": "bin/wechat-check-update.mjs"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"postinstall": "node scripts/ensure-node-pty-permissions.mjs",
|
|
51
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
52
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
53
|
+
"prepack": "npm run build",
|
|
54
|
+
"lint": "eslint bin src test",
|
|
55
|
+
"lint:fix": "eslint bin src test --fix",
|
|
56
|
+
"typecheck:src": "tsc -p tsconfig.typecheck.src.json --noEmit --pretty false",
|
|
57
|
+
"quality": "npm run lint && npm run typecheck:src && bun test test && npm run build",
|
|
58
|
+
"smoke:global": "node scripts/smoke-global-install.mjs",
|
|
59
|
+
"publish:dual": "node scripts/publish-dual.mjs",
|
|
60
|
+
"setup": "node --no-warnings --experimental-strip-types src/wechat/setup.ts",
|
|
61
|
+
"start": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts",
|
|
62
|
+
"check": "node --no-warnings --experimental-strip-types src/wechat/wechat-channel.ts --check",
|
|
63
|
+
"bridge": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts",
|
|
64
|
+
"daemon": "node --no-warnings --experimental-strip-types src/daemon/wechat-daemon.ts",
|
|
65
|
+
"bridge:codex": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter codex",
|
|
66
|
+
"codex:panel": "node --no-warnings --experimental-strip-types src/companion/codex-remote-client.ts",
|
|
67
|
+
"codex:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts",
|
|
68
|
+
"claude:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter claude",
|
|
69
|
+
"claude:companion": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter claude",
|
|
70
|
+
"bridge:claude": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter claude",
|
|
71
|
+
"bridge:opencode": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter opencode",
|
|
72
|
+
"opencode:panel": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter opencode",
|
|
73
|
+
"opencode:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter opencode",
|
|
74
|
+
"bridge:pi": "node --no-warnings --experimental-strip-types src/bridge/wechat-bridge.ts --adapter pi",
|
|
75
|
+
"pi:companion": "node --no-warnings --experimental-strip-types src/companion/local-companion.ts --adapter pi",
|
|
76
|
+
"pi:start": "node --no-warnings --experimental-strip-types src/companion/local-companion-start.ts --adapter pi",
|
|
77
|
+
"bridge:bun": "bun src/bridge/wechat-bridge.ts",
|
|
78
|
+
"test": "bun test test",
|
|
79
|
+
"test:bridge": "bun test test/bridge",
|
|
80
|
+
"test:companion": "bun test test/companion",
|
|
81
|
+
"test:wechat": "bun test test/wechat",
|
|
82
|
+
"test:watch": "bun test --watch test"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
86
|
+
"@opencode-ai/sdk": "^1.18.0",
|
|
87
|
+
"node-pty": "^1.1.0",
|
|
88
|
+
"qrcode-terminal": "^0.12.0"
|
|
89
|
+
},
|
|
90
|
+
"overrides": {
|
|
91
|
+
"@hono/node-server": "2.1.1",
|
|
92
|
+
"body-parser": "2.3.0",
|
|
93
|
+
"brace-expansion": "5.0.9",
|
|
94
|
+
"express-rate-limit": "8.6.2",
|
|
95
|
+
"fast-uri": "3.1.5",
|
|
96
|
+
"hono": "4.13.3",
|
|
97
|
+
"ip-address": "10.5.0",
|
|
98
|
+
"path-to-regexp": "8.4.2",
|
|
99
|
+
"qs": "6.15.3"
|
|
100
|
+
},
|
|
101
|
+
"devDependencies": {
|
|
102
|
+
"@eslint/js": "^10.0.1",
|
|
103
|
+
"@types/bun": "latest",
|
|
104
|
+
"@types/node": "^24.12.4",
|
|
105
|
+
"eslint": "^10.3.0",
|
|
106
|
+
"typescript": "^6.0.2",
|
|
107
|
+
"typescript-eslint": "^8.59.3"
|
|
108
|
+
},
|
|
109
|
+
"engines": {
|
|
110
|
+
"bun": ">=1.0.0",
|
|
111
|
+
"node": ">=24.0.0"
|
|
112
|
+
}
|
|
113
|
+
}
|