@unlinearity/cli-wechat-bridge 1.1.4 → 1.1.5
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 +14 -7
- package/bin/_run-entry.mjs +0 -12
- package/dist/bridge/bridge-adapters.claude.js +427 -10
- package/dist/bridge/bridge-adapters.codex.js +235 -7
- package/dist/bridge/bridge-adapters.opencode.js +392 -53
- package/dist/bridge/bridge-adapters.pi.js +32 -6
- package/dist/bridge/bridge-controller.js +3 -0
- package/dist/bridge/bridge-session-resume.js +151 -0
- package/dist/bridge/bridge-utils.js +26 -5
- package/dist/bridge/claude-hooks.js +1 -0
- package/dist/bridge/wechat-bridge.js +37 -29
- package/dist/companion/codex-remote-client.js +291 -32
- package/dist/companion/codex-visible-client-link.js +122 -0
- package/dist/companion/local-companion-link.js +26 -0
- package/dist/companion/local-companion-start.js +0 -1
- package/dist/companion/opencode-tui-bridge-plugin.js +73 -0
- package/dist/companion/pi-tui-bridge-extension.js +42 -3
- package/dist/daemon/wechat-daemon.js +35 -17
- package/package.json +1 -5
- package/bin/wechat-claude-start.mjs +0 -10
- package/bin/wechat-codex-start.mjs +0 -10
- package/bin/wechat-opencode-start.mjs +0 -10
- package/bin/wechat-pi-start.mjs +0 -10
|
@@ -12,11 +12,11 @@ import { forwardWechatFinalReply } from "../bridge/bridge-final-reply.js";
|
|
|
12
12
|
import { readBridgeLockFile, } from "../bridge/bridge-state.js";
|
|
13
13
|
import { getProcessRecordByPid, isWechatDaemonCommandLine, killProcessTreeSync, listWechatDaemonProcesses, reapOrphanedOpencodeProcesses, reapPeerBridgeProcesses, } from "../bridge/bridge-process-reaper.js";
|
|
14
14
|
import { buildOneTimeCode, buildWechatInboundPrompt, formatApprovalMessage, formatDuration, formatMirroredUserInputMessage, formatPendingApprovalReminder, formatPendingUserInputReminder, formatSessionSwitchMessage, formatTaskFailedMessage, formatUserInputRequestMessage, MESSAGE_START_GRACE_MS, nowIso, OutputBatcher, parsePendingUserInputAnswerCommand, parseWechatControlCommand, truncatePreview, } from "../bridge/bridge-utils.js";
|
|
15
|
+
import { ResumeSessionCoordinator, isWechatResumeEnabled, shouldForwardSessionSwitchEvent, } from "../bridge/bridge-session-resume.js";
|
|
15
16
|
import { WECHAT_SEND_MAX_ATTEMPTS, computeWechatSendRetryDelayMs, formatUserFacingBridgeFatalError, formatUserFacingInboundError, formatWechatContextTokenStaleLogEntry, formatWechatSendFailureLogEntry, isRetryableWechatSendError, shouldForwardBridgeEventToWechat, } from "../bridge/wechat-forwarding.js";
|
|
16
17
|
import { BRIDGE_LOCK_FILE, BRIDGE_LOG_FILE, appendBoundedLog, ensureChannelDataDir, migrateLegacyChannelFiles, } from "../wechat/channel-config.js";
|
|
17
18
|
import { ensureWechatCredentials } from "../wechat/setup.js";
|
|
18
19
|
import { formatBindCommandUsage, formatBindingsListMessage, isBindCommandPrefix, listBindings, loadEmojiBindings, parseEmojiBindingsCommand, removeBinding, resolveEmojiCommand, setBinding, } from "./emoji-bindings.js";
|
|
19
|
-
import { formatResumeSessionList } from "../bridge/bridge-utils.js";
|
|
20
20
|
import { classifyWechatTransportError, DEFAULT_LONG_POLL_TIMEOUT_MS, describeWechatTransportError, isWechatContextTokenStaleError, WeChatTransport, } from "../wechat/wechat-transport.js";
|
|
21
21
|
import { createRuntimeHost, } from "../runtime/create-runtime-host.js";
|
|
22
22
|
import { clearLocalCompanionEndpoint, clearLocalCompanionOccupancy, readLocalCompanionEndpoint, } from "../companion/local-companion-link.js";
|
|
@@ -893,6 +893,10 @@ class WechatDaemon {
|
|
|
893
893
|
}),
|
|
894
894
|
pendingConfirmations: [],
|
|
895
895
|
pendingUserInput: null,
|
|
896
|
+
resumeCoordinator: new ResumeSessionCoordinator({
|
|
897
|
+
adapter,
|
|
898
|
+
runtime,
|
|
899
|
+
}),
|
|
896
900
|
activeTask: null,
|
|
897
901
|
lastOutputAt: 0,
|
|
898
902
|
};
|
|
@@ -1014,8 +1018,12 @@ class WechatDaemon {
|
|
|
1014
1018
|
}
|
|
1015
1019
|
break;
|
|
1016
1020
|
case "session_switched":
|
|
1021
|
+
if (event.source === "local") {
|
|
1022
|
+
slot.resumeCoordinator.clear();
|
|
1023
|
+
}
|
|
1017
1024
|
appendDaemonLog(`session_switched: adapter=${slot.adapter} session=${event.sessionId} source=${event.source} reason=${event.reason}`);
|
|
1018
|
-
if (
|
|
1025
|
+
if (shouldForwardSessionSwitchEvent(event.reason) &&
|
|
1026
|
+
shouldForwardBridgeEventToWechat(slot.adapter, event.type)) {
|
|
1019
1027
|
this.trackWechatForwardTask(slot.outputBatcher.flushNow().then(async () => {
|
|
1020
1028
|
await this.queueWechatMessage(this.authorizedUserId, prefixDaemonAdapterMessage(slot.adapter, formatSessionSwitchMessage({
|
|
1021
1029
|
adapter: slot.adapter,
|
|
@@ -1027,8 +1035,12 @@ class WechatDaemon {
|
|
|
1027
1035
|
}
|
|
1028
1036
|
break;
|
|
1029
1037
|
case "thread_switched":
|
|
1038
|
+
if (event.source === "local") {
|
|
1039
|
+
slot.resumeCoordinator.clear();
|
|
1040
|
+
}
|
|
1030
1041
|
appendDaemonLog(`thread_switched: adapter=${slot.adapter} thread=${event.threadId} source=${event.source} reason=${event.reason}`);
|
|
1031
|
-
if (
|
|
1042
|
+
if (shouldForwardSessionSwitchEvent(event.reason) &&
|
|
1043
|
+
shouldForwardBridgeEventToWechat(slot.adapter, event.type)) {
|
|
1032
1044
|
this.trackWechatForwardTask(slot.outputBatcher.flushNow().then(async () => {
|
|
1033
1045
|
await this.queueWechatMessage(this.authorizedUserId, prefixDaemonAdapterMessage(slot.adapter, formatSessionSwitchMessage({
|
|
1034
1046
|
adapter: slot.adapter,
|
|
@@ -1207,29 +1219,33 @@ class WechatDaemon {
|
|
|
1207
1219
|
await this.queueWechatMessage(message.senderId, formatDaemonStatus(this.getStatus()));
|
|
1208
1220
|
return;
|
|
1209
1221
|
case "resume": {
|
|
1210
|
-
if (activeSlot.adapter
|
|
1222
|
+
if (!isWechatResumeEnabled(activeSlot.adapter)) {
|
|
1211
1223
|
await this.queueWechatMessage(message.senderId, `WeChat /resume is disabled for ${activeSlot.adapter} in daemon mode. Use /resume directly inside the visible terminal; WeChat will follow that local session.`);
|
|
1212
1224
|
return;
|
|
1213
1225
|
}
|
|
1214
|
-
if (command.type !== "resume") {
|
|
1215
|
-
return;
|
|
1216
|
-
}
|
|
1217
1226
|
try {
|
|
1227
|
+
let resumeSlot = activeSlot;
|
|
1228
|
+
if (activeSlot.adapter === "codex" && command.target) {
|
|
1229
|
+
const visible = await this.ensureSlot("codex", {
|
|
1230
|
+
openVisible: true,
|
|
1231
|
+
reuseExistingVisible: true,
|
|
1232
|
+
});
|
|
1233
|
+
if (!visible.activated) {
|
|
1234
|
+
throw new Error(formatDaemonSwitchResultDetail(visible));
|
|
1235
|
+
}
|
|
1236
|
+
resumeSlot = this.slots.get("codex") ?? activeSlot;
|
|
1237
|
+
}
|
|
1218
1238
|
if (command.target) {
|
|
1219
|
-
await
|
|
1220
|
-
await this.queueWechatMessage(message.senderId, prefixDaemonAdapterMessage(activeSlot.adapter, `Resumed OpenCode session ${command.target}.`));
|
|
1239
|
+
await resumeSlot.outputBatcher.flushNow();
|
|
1221
1240
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
adapter: activeSlot.adapter,
|
|
1226
|
-
candidates,
|
|
1227
|
-
currentSessionId: activeSlot.runtime.getState().sharedSessionId,
|
|
1228
|
-
})));
|
|
1241
|
+
const result = await resumeSlot.resumeCoordinator.execute(command.target);
|
|
1242
|
+
if (result.kind === "resumed") {
|
|
1243
|
+
resumeSlot.activeTask = null;
|
|
1229
1244
|
}
|
|
1245
|
+
await this.queueWechatMessage(message.senderId, prefixDaemonAdapterMessage(resumeSlot.adapter, result.message));
|
|
1230
1246
|
}
|
|
1231
1247
|
catch (error) {
|
|
1232
|
-
await this.queueWechatMessage(message.senderId, prefixDaemonAdapterMessage(activeSlot.adapter,
|
|
1248
|
+
await this.queueWechatMessage(message.senderId, prefixDaemonAdapterMessage(activeSlot.adapter, error instanceof Error ? error.message : String(error)));
|
|
1233
1249
|
}
|
|
1234
1250
|
return;
|
|
1235
1251
|
}
|
|
@@ -1242,6 +1258,7 @@ class WechatDaemon {
|
|
|
1242
1258
|
activeSlot.outputBatcher.clear();
|
|
1243
1259
|
activeSlot.pendingConfirmations = [];
|
|
1244
1260
|
activeSlot.pendingUserInput = null;
|
|
1261
|
+
activeSlot.resumeCoordinator.clear();
|
|
1245
1262
|
await activeSlot.runtime.createSession();
|
|
1246
1263
|
appendDaemonLog(`new_session: adapter=${activeSlot.adapter}`);
|
|
1247
1264
|
return;
|
|
@@ -1257,6 +1274,7 @@ class WechatDaemon {
|
|
|
1257
1274
|
activeSlot.outputBatcher.clear();
|
|
1258
1275
|
activeSlot.pendingConfirmations = [];
|
|
1259
1276
|
activeSlot.pendingUserInput = null;
|
|
1277
|
+
activeSlot.resumeCoordinator.clear();
|
|
1260
1278
|
await activeSlot.runtime.reset();
|
|
1261
1279
|
appendDaemonLog(`reset: adapter=${activeSlot.adapter}`);
|
|
1262
1280
|
await this.queueWechatMessage(message.senderId, prefixDaemonAdapterMessage(activeSlot.adapter, "Worker session has been reset."));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unlinearity/cli-wechat-bridge",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "CLI WeChat Bridge for Codex, Claude Code, OpenCode, and Pi over WeChat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -35,13 +35,9 @@
|
|
|
35
35
|
},
|
|
36
36
|
"bin": {
|
|
37
37
|
"wechat-codex": "bin/wechat-codex.mjs",
|
|
38
|
-
"wechat-codex-start": "bin/wechat-codex-start.mjs",
|
|
39
38
|
"wechat-claude": "bin/wechat-claude.mjs",
|
|
40
|
-
"wechat-claude-start": "bin/wechat-claude-start.mjs",
|
|
41
39
|
"wechat-opencode": "bin/wechat-opencode.mjs",
|
|
42
|
-
"wechat-opencode-start": "bin/wechat-opencode-start.mjs",
|
|
43
40
|
"wechat-pi": "bin/wechat-pi.mjs",
|
|
44
|
-
"wechat-pi-start": "bin/wechat-pi-start.mjs",
|
|
45
41
|
"wechat-daemon": "bin/wechat-daemon.mjs",
|
|
46
42
|
"wechat-setup": "bin/wechat-setup.mjs",
|
|
47
43
|
"wechat-check-update": "bin/wechat-check-update.mjs"
|