@unlinearity/cli-wechat-bridge 1.1.6 → 1.2.1
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/LICENSE.txt +661 -661
- package/README.md +468 -475
- package/bin/_run-entry.mjs +29 -6
- package/bin/wechat-check-update.mjs +6 -1
- package/bin/wechat-claude.mjs +6 -1
- package/bin/wechat-codex.mjs +6 -1
- package/bin/wechat-daemon.mjs +6 -1
- package/bin/wechat-opencode.mjs +6 -1
- package/bin/wechat-pi.mjs +6 -1
- package/bin/wechat-setup.mjs +6 -1
- package/bin/wecom-check-update.mjs +10 -0
- package/bin/wecom-claude.mjs +10 -0
- package/bin/wecom-codex.mjs +10 -0
- package/bin/wecom-daemon.mjs +10 -0
- package/bin/wecom-opencode.mjs +10 -0
- package/bin/wecom-pi.mjs +10 -0
- package/bin/wecom-setup.mjs +10 -0
- package/dist/bridge/adapter-control.js +58 -0
- package/dist/bridge/bridge-adapters.claude.js +161 -4
- package/dist/bridge/bridge-adapters.codex.js +206 -14
- package/dist/bridge/bridge-adapters.core.js +25 -1
- package/dist/bridge/bridge-adapters.opencode.js +298 -20
- package/dist/bridge/bridge-adapters.pi.js +45 -0
- package/dist/bridge/bridge-adapters.shared.js +6 -0
- package/dist/bridge/bridge-controller.js +6 -0
- package/dist/bridge/bridge-final-reply.js +6 -0
- package/dist/bridge/bridge-process-reaper.js +41 -2
- package/dist/bridge/bridge-state.js +16 -3
- package/dist/bridge/bridge-utils.js +6 -31
- package/dist/bridge/claude-hook.js +6 -0
- package/dist/bridge/claude-native-controls.js +145 -0
- package/dist/bridge/codex-visible-thread-proxy.js +140 -0
- package/dist/bridge/native-terminal-control.js +271 -0
- package/dist/bridge/opencode-v2-compat.js +450 -0
- package/dist/bridge/wechat-bridge.js +380 -171
- package/dist/bridge/wechat-forwarding.js +6 -0
- package/dist/bridge/wechat-outbound-queue.js +6 -0
- package/dist/channels/wechat/bridge-final-reply.js +13 -22
- package/dist/channels/wechat/index.js +6 -0
- package/dist/channels/wechat/wechat-driver.js +191 -0
- package/dist/channels/wechat/wechat-forwarding.js +18 -0
- package/dist/channels/wechat/wechat-outbound-queue.js +49 -3
- package/dist/channels/wecom/bridge-final-reply.js +32 -0
- package/dist/channels/wecom/setup-cli.js +12 -0
- package/dist/channels/wecom/setup.js +182 -0
- package/dist/channels/wecom/wecom-channel-port.js +45 -0
- package/dist/channels/wecom/wecom-config.js +72 -0
- package/dist/channels/wecom/wecom-driver.js +106 -0
- package/dist/channels/wecom/wecom-media.js +147 -0
- package/dist/channels/wecom/wecom-message.js +149 -0
- package/dist/channels/wecom/wecom-transport.js +314 -0
- package/dist/commands/check-update.js +6 -0
- package/dist/companion/codex-remote-client.js +30 -3
- package/dist/companion/codex-visible-client-link.js +107 -0
- package/dist/companion/local-companion-link.js +6 -0
- package/dist/companion/local-companion-start.js +62 -11
- package/dist/companion/local-companion.js +25 -1
- package/dist/companion/opencode-tui-bridge-plugin.js +6 -0
- package/dist/companion/opencode-v2-tui-bridge-plugin.js +93 -0
- package/dist/companion/pi-tui-bridge-extension.js +62 -3
- package/dist/core/bridge-control.js +10 -0
- package/dist/core/bridge-defer.js +25 -0
- package/dist/core/channel-driver.js +1 -0
- package/dist/core/channel-types.js +3 -1
- package/dist/core/conversation-routing.js +58 -0
- package/dist/core/direct-run.js +23 -0
- package/dist/core/inbound-message-claims.js +67 -0
- package/dist/core/outbound-target.js +32 -0
- package/dist/core/text-utils.js +6 -0
- package/dist/core/turn-coordinator.js +85 -0
- package/dist/daemon/daemon-link.js +9 -0
- package/dist/daemon/emoji-bindings.js +6 -0
- package/dist/daemon/wechat-daemon.js +675 -122
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/messages-en.js +9 -1
- package/dist/i18n/messages-zh.js +9 -1
- package/dist/runtime/create-runtime-host.js +6 -0
- package/dist/runtime/legacy-adapter-runtime.js +15 -0
- package/dist/runtime/runtime-types.js +3 -0
- package/dist/utils/atomic-file.js +6 -0
- package/dist/utils/doctor.js +36 -10
- package/dist/utils/version-checker.js +17 -11
- package/dist/wechat/channel-config.js +6 -0
- package/dist/wechat/setup.js +119 -13
- package/dist/wechat/wechat-channel.js +6 -0
- package/dist/wechat/wechat-transport.js +169 -58
- package/package.json +16 -4
- package/scripts/ensure-node-pty-permissions.mjs +73 -73
package/bin/_run-entry.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { spawn } from "node:child_process";
|
|
4
9
|
import path from "node:path";
|
|
5
10
|
import { fileURLToPath } from "node:url";
|
|
@@ -8,6 +13,8 @@ const BIN_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
|
8
13
|
const PROJECT_DIR = path.resolve(BIN_DIR, "..");
|
|
9
14
|
export const MIN_NODE_VERSION = Object.freeze([22, 13, 0]);
|
|
10
15
|
export const MIN_NODE_VERSION_TEXT = MIN_NODE_VERSION.join(".");
|
|
16
|
+
export const MIN_PI_NODE_VERSION = Object.freeze([22, 19, 0]);
|
|
17
|
+
export const MIN_PI_NODE_VERSION_TEXT = MIN_PI_NODE_VERSION.join(".");
|
|
11
18
|
|
|
12
19
|
export function isSupportedNodeVersion(version) {
|
|
13
20
|
const match = /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(version);
|
|
@@ -24,19 +31,21 @@ export function isSupportedNodeVersion(version) {
|
|
|
24
31
|
return true;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
function ensureSupportedNodeVersion() {
|
|
34
|
+
function ensureSupportedNodeVersion(extraArgs = []) {
|
|
28
35
|
if (process.env.CLI_BRIDGE_SKIP_NODE_CHECK === "1") {
|
|
29
36
|
return;
|
|
30
37
|
}
|
|
31
38
|
|
|
39
|
+
const piRequested = extraArgs.some((arg, index) => arg === "pi" && extraArgs[index - 1] === "--adapter");
|
|
32
40
|
if (isSupportedNodeVersion(process.versions.node)) {
|
|
33
|
-
return;
|
|
41
|
+
if (!piRequested || compareNodeVersion(process.versions.node, MIN_PI_NODE_VERSION) >= 0) return;
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
const minimumText = piRequested ? MIN_PI_NODE_VERSION_TEXT : MIN_NODE_VERSION_TEXT;
|
|
36
45
|
process.stderr.write(
|
|
37
46
|
[
|
|
38
|
-
`[cli-wechat-bridge] Node.js >= ${
|
|
39
|
-
`[cli-wechat-bridge] 需要 Node.js >= ${
|
|
47
|
+
`[cli-wechat-bridge] Node.js >= ${minimumText} is required, but you are running ${process.version}.`,
|
|
48
|
+
`[cli-wechat-bridge] 需要 Node.js >= ${minimumText},当前版本为 ${process.version}。`,
|
|
40
49
|
"Install the latest LTS from https://nodejs.org/ (or via nvm), then retry.",
|
|
41
50
|
"Set CLI_BRIDGE_SKIP_NODE_CHECK=1 to bypass this check at your own risk.",
|
|
42
51
|
"",
|
|
@@ -45,8 +54,22 @@ function ensureSupportedNodeVersion() {
|
|
|
45
54
|
process.exit(1);
|
|
46
55
|
}
|
|
47
56
|
|
|
57
|
+
function compareNodeVersion(version, minimum) {
|
|
58
|
+
const match = /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(version);
|
|
59
|
+
if (!match) return -1;
|
|
60
|
+
const current = [Number(match[1]), Number(match[2] ?? 0), Number(match[3] ?? 0)];
|
|
61
|
+
for (let index = 0; index < minimum.length; index += 1) {
|
|
62
|
+
if (current[index] !== minimum[index]) return current[index] > minimum[index] ? 1 : -1;
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isSupportedPiNodeVersion(version) {
|
|
68
|
+
return compareNodeVersion(version, MIN_PI_NODE_VERSION) >= 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
48
71
|
export function runJsEntry(relativeEntryPath, extraArgs = []) {
|
|
49
|
-
ensureSupportedNodeVersion();
|
|
72
|
+
ensureSupportedNodeVersion([...extraArgs, ...process.argv.slice(2)]);
|
|
50
73
|
const entryPath = path.join(PROJECT_DIR, relativeEntryPath);
|
|
51
74
|
const child = spawn(
|
|
52
75
|
process.execPath,
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/commands/check-update.js", []);
|
package/bin/wechat-claude.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "claude"]);
|
package/bin/wechat-codex.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "codex"]);
|
package/bin/wechat-daemon.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/daemon/wechat-daemon.js");
|
package/bin/wechat-opencode.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "opencode"]);
|
package/bin/wechat-pi.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "pi"]);
|
package/bin/wechat-setup.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
3
8
|
import { runJsEntry } from "./_run-entry.mjs";
|
|
4
9
|
|
|
5
10
|
runJsEntry("dist/wechat/setup.js");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/commands/check-update.js");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "claude", "--channel", "wecom"]);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "codex", "--channel", "wecom"]);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/daemon/wechat-daemon.js", ["--channel", "wecom"]);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "opencode", "--channel", "wecom"]);
|
package/bin/wecom-pi.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/companion/local-companion-start.js", ["--adapter", "pi", "--channel", "wecom"]);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
4
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
5
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
6
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
7
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
8
|
+
import { runJsEntry } from "./_run-entry.mjs";
|
|
9
|
+
|
|
10
|
+
runJsEntry("dist/channels/wecom/setup-cli.js");
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const snapshots = new WeakMap();
|
|
2
|
+
export const MODEL_SNAPSHOT_TTL_MS = 5 * 60_000;
|
|
3
|
+
export function invalidateModelSnapshot(adapter) {
|
|
4
|
+
snapshots.delete(adapter);
|
|
5
|
+
}
|
|
6
|
+
function snapshotOwner(adapter, senderId) {
|
|
7
|
+
const state = adapter.getState();
|
|
8
|
+
return JSON.stringify([
|
|
9
|
+
senderId, state.kind, state.cwd, state.pid, state.startedAt,
|
|
10
|
+
state.resumeConversationId ?? state.sharedSessionId ?? state.sharedThreadId,
|
|
11
|
+
state.lastSessionSwitchAt ?? state.lastThreadSwitchAt,
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
export async function handleAdapterControl(adapter, senderId, command) {
|
|
15
|
+
const kind = adapter.getState().kind;
|
|
16
|
+
const name = kind === "claude" ? "Claude Code" : kind === "opencode" ? "OpenCode" : kind === "codex" ? "Codex" : "Pi";
|
|
17
|
+
try {
|
|
18
|
+
if (command.type === "plan") {
|
|
19
|
+
if (!adapter.setPlanMode)
|
|
20
|
+
throw new Error(`Plan mode is not available for ${name}.`);
|
|
21
|
+
const enabled = await adapter.setPlanMode(command.enabled);
|
|
22
|
+
return enabled
|
|
23
|
+
? `${name} plan mode enabled. Send /plan off to restore the previous mode.`
|
|
24
|
+
: `${name} plan mode disabled.`;
|
|
25
|
+
}
|
|
26
|
+
if (!adapter.listModels || !adapter.selectModel)
|
|
27
|
+
throw new Error(`Model selection is not available for ${name}.`);
|
|
28
|
+
const owner = snapshotOwner(adapter, senderId);
|
|
29
|
+
if (!command.target) {
|
|
30
|
+
snapshots.delete(adapter);
|
|
31
|
+
const models = await adapter.listModels();
|
|
32
|
+
if (snapshotOwner(adapter, senderId) !== owner)
|
|
33
|
+
throw new Error("The active session changed. Send /model again.");
|
|
34
|
+
if (!models.length)
|
|
35
|
+
return `${name} did not return any available models.`;
|
|
36
|
+
snapshots.set(adapter, { owner, createdAtMs: Date.now(), models });
|
|
37
|
+
return [
|
|
38
|
+
`Available ${name} models:`, "",
|
|
39
|
+
...models.map((model, index) => `${index + 1}. ${model.displayName}${model.isCurrent ? " (current)" : ""}`),
|
|
40
|
+
"", "Reply with /model <number> to switch. The list is valid for 5 minutes.",
|
|
41
|
+
].join("\n");
|
|
42
|
+
}
|
|
43
|
+
const snapshot = snapshots.get(adapter);
|
|
44
|
+
if (!snapshot || snapshot.owner !== owner || Date.now() - snapshot.createdAtMs > MODEL_SNAPSHOT_TTL_MS) {
|
|
45
|
+
throw new Error("The model list has expired or belongs to another session. Send /model again.");
|
|
46
|
+
}
|
|
47
|
+
const index = Number(command.target);
|
|
48
|
+
if (!/^\d+$/.test(command.target) || !Number.isSafeInteger(index) || index < 1 || index > snapshot.models.length) {
|
|
49
|
+
throw new Error("Model selection is outside the displayed range. Send /model again to refresh the list.");
|
|
50
|
+
}
|
|
51
|
+
const model = await adapter.selectModel(snapshot.models[index - 1].id);
|
|
52
|
+
snapshots.delete(adapter);
|
|
53
|
+
return `${name} model switched to ${model.displayName}.`;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return error instanceof Error ? error.message : String(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (c) 2026 UNLINEARITY <unlinearity@gmail.com>
|
|
3
|
+
// Source: https://github.com/UNLINEARITY/CLI-WeChat-Bridge
|
|
4
|
+
// This file is part of CLI-WeChat-Bridge. Modifications and derivative works
|
|
5
|
+
// must be released under AGPL-3.0-or-later with full source code; see
|
|
6
|
+
// LICENSE.txt. Network services built on it must offer source to users.
|
|
7
|
+
import { NativeTerminalControl, readClaudePermissionMode } from "./native-terminal-control.js";
|
|
8
|
+
import { ClaudeNativeControls } from "./claude-native-controls.js";
|
|
1
9
|
import fs from "node:fs";
|
|
2
10
|
import net from "node:net";
|
|
3
11
|
import os from "node:os";
|
|
@@ -18,6 +26,8 @@ const CLAUDE_COMPACT_DEDUP_MS = 2_000;
|
|
|
18
26
|
const CLAUDE_BRACKETED_PASTE_START = "\u001b[200~";
|
|
19
27
|
const CLAUDE_BRACKETED_PASTE_END = "\u001b[201~";
|
|
20
28
|
const CLAUDE_REMOTE_ENTER_DELAY_MS = 40;
|
|
29
|
+
const CLAUDE_REMOTE_ENTER_RETRY_DELAYS_MS = [200, 500, 1_000];
|
|
30
|
+
const CLAUDE_INTERACTIVE_READY_TIMEOUT_MS = 10_000;
|
|
21
31
|
const CLAUDE_STARTUP_OUTPUT_BUFFER_LIMIT = 4_000;
|
|
22
32
|
const CLAUDE_SESSION_METADATA_READ_BYTES = 64 * 1024;
|
|
23
33
|
const CLAUDE_MAX_SANITIZED_PROJECT_PATH = 200;
|
|
@@ -337,6 +347,26 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
337
347
|
polledTranscriptSessionId = null;
|
|
338
348
|
pendingResume = null;
|
|
339
349
|
localResumeSessionEndObserved = false;
|
|
350
|
+
interactiveReady = true;
|
|
351
|
+
interactiveReadyTimer = null;
|
|
352
|
+
interactiveReadyWaiters = new Set();
|
|
353
|
+
remoteSubmitRetryTimer = null;
|
|
354
|
+
remoteSubmitRetryIndex = 0;
|
|
355
|
+
remoteSubmitText = null;
|
|
356
|
+
terminalControl = new NativeTerminalControl({
|
|
357
|
+
write: (text) => this.writeToPty(text),
|
|
358
|
+
identity: () => JSON.stringify([this.state.pid, this.runtimeSessionId, this.resumeConversationId]),
|
|
359
|
+
isPromptEmpty: () => readClaudePermissionMode(this.terminalControl.text) !== null,
|
|
360
|
+
assertReady: () => {
|
|
361
|
+
if (!this.pty || this.state.status !== "idle" || this.pendingApproval || this.pendingResume) {
|
|
362
|
+
throw new Error("Claude must be idle with no pending approval before using remote controls.");
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
nativeControls = new ClaudeNativeControls(this.terminalControl, () => this.resumeConversationId ?? this.runtimeSessionId ?? "");
|
|
367
|
+
async listModels() { return this.nativeControls.listModels(); }
|
|
368
|
+
async selectModel(modelId) { return this.nativeControls.selectModel(modelId); }
|
|
369
|
+
async setPlanMode(enabled) { return this.nativeControls.setPlanMode(enabled); }
|
|
340
370
|
constructor(options) {
|
|
341
371
|
super(options);
|
|
342
372
|
const shouldRestoreInitialSession = options.sessionStartMode !== "new";
|
|
@@ -364,6 +394,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
364
394
|
if (this.pty) {
|
|
365
395
|
return;
|
|
366
396
|
}
|
|
397
|
+
this.beginInteractiveReadinessWait();
|
|
367
398
|
this.startupOutputBuffer = "";
|
|
368
399
|
this.hasAutoConfirmedWorkspaceTrustPrompt = false;
|
|
369
400
|
ensureClaudeWorkspaceTrustAccepted(this.options.cwd);
|
|
@@ -385,16 +416,22 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
385
416
|
this.state.activeRuntimeSessionId = undefined;
|
|
386
417
|
}
|
|
387
418
|
}
|
|
388
|
-
await this.startHookServer();
|
|
389
419
|
try {
|
|
420
|
+
await this.startHookServer();
|
|
390
421
|
await super.start();
|
|
422
|
+
if (!this.interactiveReady) {
|
|
423
|
+
this.setStatus("starting", "Waiting for Claude interactive session...");
|
|
424
|
+
}
|
|
391
425
|
}
|
|
392
426
|
catch (error) {
|
|
427
|
+
this.rejectInteractiveReadiness(error instanceof Error ? error : new Error(String(error)));
|
|
393
428
|
await this.stopHookServer();
|
|
394
429
|
throw error;
|
|
395
430
|
}
|
|
396
431
|
}
|
|
397
432
|
async sendInput(text) {
|
|
433
|
+
if (this.terminalControl.active)
|
|
434
|
+
throw new Error("A Claude control operation is in progress.");
|
|
398
435
|
if (!this.pty) {
|
|
399
436
|
throw new Error("claude adapter is not running.");
|
|
400
437
|
}
|
|
@@ -404,7 +441,18 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
404
441
|
if (this.pendingApproval) {
|
|
405
442
|
throw new Error("A Claude approval request is pending. Reply with /confirm or /deny.");
|
|
406
443
|
}
|
|
444
|
+
await this.waitForInteractiveReadiness();
|
|
445
|
+
if (!this.pty) {
|
|
446
|
+
throw new Error("claude adapter is not running.");
|
|
447
|
+
}
|
|
448
|
+
if (this.getState().status === "busy") {
|
|
449
|
+
throw new Error("claude is still working. Wait for the current reply or use /stop.");
|
|
450
|
+
}
|
|
451
|
+
if (this.pendingApproval) {
|
|
452
|
+
throw new Error("A Claude approval request is pending. Reply with /confirm or /deny.");
|
|
453
|
+
}
|
|
407
454
|
const normalizedText = normalizeOutput(text).trim();
|
|
455
|
+
this.clearRemoteSubmitRetry();
|
|
408
456
|
this.pendingInjectedInputs.push({
|
|
409
457
|
normalizedText,
|
|
410
458
|
createdAtMs: Date.now(),
|
|
@@ -421,12 +469,15 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
421
469
|
this.writeToPty(this.buildRemoteInputPayload(text));
|
|
422
470
|
await delay(CLAUDE_REMOTE_ENTER_DELAY_MS);
|
|
423
471
|
this.writeToPty("\r");
|
|
472
|
+
this.armRemoteSubmitRetry(normalizedText);
|
|
424
473
|
this.armWechatWorkingNotice();
|
|
425
474
|
}
|
|
426
475
|
async listResumeSessions(limit = 10) {
|
|
427
476
|
return listClaudeResumeSessions(this.options.cwd, limit);
|
|
428
477
|
}
|
|
429
478
|
async resumeSession(sessionId) {
|
|
479
|
+
if (this.terminalControl.active)
|
|
480
|
+
throw new Error("A CLI control operation is in progress. Wait for it to finish before switching sessions.");
|
|
430
481
|
if (!this.pty) {
|
|
431
482
|
throw new Error("Claude is not running yet.");
|
|
432
483
|
}
|
|
@@ -523,6 +574,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
523
574
|
return findClaudeResumeSessionFile(this.options.cwd, sessionId);
|
|
524
575
|
}
|
|
525
576
|
async interrupt() {
|
|
577
|
+
this.terminalControl.cancel("The remote control operation was interrupted.");
|
|
526
578
|
if (!this.pty) {
|
|
527
579
|
return false;
|
|
528
580
|
}
|
|
@@ -530,6 +582,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
530
582
|
return false;
|
|
531
583
|
}
|
|
532
584
|
this.clearWechatWorkingNotice(true);
|
|
585
|
+
this.clearRemoteSubmitRetry();
|
|
533
586
|
this.pendingCliApprovalHints = null;
|
|
534
587
|
this.flushPendingClaudeHookApprovals();
|
|
535
588
|
if (this.pendingApproval) {
|
|
@@ -552,6 +605,8 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
552
605
|
return true;
|
|
553
606
|
}
|
|
554
607
|
async reset() {
|
|
608
|
+
if (this.terminalControl.active)
|
|
609
|
+
throw new Error("A CLI control operation is in progress. Wait for it to finish before switching sessions.");
|
|
555
610
|
this.rejectPendingResume(new Error("Claude was reset during session switching."));
|
|
556
611
|
this.clearWechatWorkingNotice(true);
|
|
557
612
|
this.pendingCliApprovalHints = null;
|
|
@@ -566,7 +621,8 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
566
621
|
this.state.lastSessionSwitchAt = undefined;
|
|
567
622
|
this.state.lastSessionSwitchSource = undefined;
|
|
568
623
|
this.state.lastSessionSwitchReason = undefined;
|
|
569
|
-
await
|
|
624
|
+
await this.dispose();
|
|
625
|
+
await this.start();
|
|
570
626
|
}
|
|
571
627
|
async resolveApproval(action) {
|
|
572
628
|
if (!this.pendingApproval) {
|
|
@@ -620,9 +676,12 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
620
676
|
return ok ? 1 : 0;
|
|
621
677
|
}
|
|
622
678
|
async dispose() {
|
|
679
|
+
this.terminalControl.cancel("Claude is shutting down.");
|
|
623
680
|
this.rejectPendingResume(new Error("Claude is shutting down during session switching."));
|
|
624
681
|
this.detachLocalTerminal();
|
|
625
682
|
this.clearWechatWorkingNotice(true);
|
|
683
|
+
this.clearRemoteSubmitRetry();
|
|
684
|
+
this.rejectInteractiveReadiness(new Error("Claude is shutting down."));
|
|
626
685
|
this.pendingCliApprovalHints = null;
|
|
627
686
|
this.flushPendingClaudeHookApprovals();
|
|
628
687
|
this.stopTranscriptThinkingWatch();
|
|
@@ -647,6 +706,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
647
706
|
this.startHookHealthCheck();
|
|
648
707
|
}
|
|
649
708
|
handleData(rawText) {
|
|
709
|
+
this.terminalControl.feed(rawText);
|
|
650
710
|
this.renderLocalOutput(rawText);
|
|
651
711
|
const text = normalizeOutput(rawText);
|
|
652
712
|
if (!text) {
|
|
@@ -718,10 +778,15 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
718
778
|
return true;
|
|
719
779
|
}
|
|
720
780
|
handleExit(exitCode) {
|
|
781
|
+
this.terminalControl.cancel("Claude exited during the control operation.");
|
|
721
782
|
this.detachLocalTerminal();
|
|
722
783
|
this.clearWechatWorkingNotice(true);
|
|
784
|
+
this.clearRemoteSubmitRetry();
|
|
723
785
|
this.pendingCliApprovalHints = null;
|
|
724
786
|
this.rejectPendingResume(new Error("Claude exited before the requested session switch completed."));
|
|
787
|
+
if (!this.recoveringInvalidResume) {
|
|
788
|
+
this.rejectInteractiveReadiness(new Error("Claude exited before its interactive session became ready."));
|
|
789
|
+
}
|
|
725
790
|
void this.stopHookServer();
|
|
726
791
|
if (this.recoveringInvalidResume && !this.shuttingDown) {
|
|
727
792
|
this.clearCompletionTimer();
|
|
@@ -870,6 +935,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
870
935
|
}
|
|
871
936
|
this.localTerminalInputListener = (chunk) => {
|
|
872
937
|
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
938
|
+
this.terminalControl.localInput(text);
|
|
873
939
|
this.writeToPty(text);
|
|
874
940
|
};
|
|
875
941
|
process.stdin.on("data", this.localTerminalInputListener);
|
|
@@ -898,10 +964,11 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
898
964
|
}
|
|
899
965
|
}
|
|
900
966
|
resizePtyToTerminal() {
|
|
901
|
-
if (!this.pty
|
|
967
|
+
if (!this.pty) {
|
|
902
968
|
return;
|
|
903
969
|
}
|
|
904
970
|
try {
|
|
971
|
+
this.terminalControl.resize(process.stdout.columns || DEFAULT_COLS, process.stdout.rows || DEFAULT_ROWS);
|
|
905
972
|
this.pty.resize?.(process.stdout.columns || DEFAULT_COLS, process.stdout.rows || DEFAULT_ROWS);
|
|
906
973
|
}
|
|
907
974
|
catch {
|
|
@@ -996,6 +1063,91 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
996
1063
|
}
|
|
997
1064
|
return `${CLAUDE_BRACKETED_PASTE_START}${normalizedText}${CLAUDE_BRACKETED_PASTE_END}`;
|
|
998
1065
|
}
|
|
1066
|
+
beginInteractiveReadinessWait() {
|
|
1067
|
+
this.clearInteractiveReadinessTimer();
|
|
1068
|
+
this.interactiveReady = false;
|
|
1069
|
+
this.interactiveReadyTimer = setTimeout(() => {
|
|
1070
|
+
this.interactiveReadyTimer = null;
|
|
1071
|
+
this.markInteractiveReady();
|
|
1072
|
+
}, CLAUDE_INTERACTIVE_READY_TIMEOUT_MS);
|
|
1073
|
+
this.interactiveReadyTimer.unref?.();
|
|
1074
|
+
}
|
|
1075
|
+
waitForInteractiveReadiness() {
|
|
1076
|
+
if (this.interactiveReady) {
|
|
1077
|
+
return Promise.resolve();
|
|
1078
|
+
}
|
|
1079
|
+
return new Promise((resolve, reject) => {
|
|
1080
|
+
this.interactiveReadyWaiters.add({ resolve, reject });
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
markInteractiveReady() {
|
|
1084
|
+
if (this.interactiveReady) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
this.interactiveReady = true;
|
|
1088
|
+
this.clearInteractiveReadinessTimer();
|
|
1089
|
+
for (const waiter of this.interactiveReadyWaiters) {
|
|
1090
|
+
waiter.resolve();
|
|
1091
|
+
}
|
|
1092
|
+
this.interactiveReadyWaiters.clear();
|
|
1093
|
+
if (this.state.status === "starting" && !this.hasAcceptedInput) {
|
|
1094
|
+
this.setStatus("idle", "Claude interactive session is ready.");
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
rejectInteractiveReadiness(error) {
|
|
1098
|
+
this.clearInteractiveReadinessTimer();
|
|
1099
|
+
for (const waiter of this.interactiveReadyWaiters) {
|
|
1100
|
+
waiter.reject(error);
|
|
1101
|
+
}
|
|
1102
|
+
this.interactiveReadyWaiters.clear();
|
|
1103
|
+
this.interactiveReady = true;
|
|
1104
|
+
}
|
|
1105
|
+
clearInteractiveReadinessTimer() {
|
|
1106
|
+
if (!this.interactiveReadyTimer) {
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
clearTimeout(this.interactiveReadyTimer);
|
|
1110
|
+
this.interactiveReadyTimer = null;
|
|
1111
|
+
}
|
|
1112
|
+
armRemoteSubmitRetry(normalizedText) {
|
|
1113
|
+
this.clearRemoteSubmitRetry();
|
|
1114
|
+
this.remoteSubmitText = normalizedText;
|
|
1115
|
+
this.remoteSubmitRetryIndex = 0;
|
|
1116
|
+
this.scheduleRemoteSubmitRetry();
|
|
1117
|
+
}
|
|
1118
|
+
scheduleRemoteSubmitRetry() {
|
|
1119
|
+
const delayMs = CLAUDE_REMOTE_ENTER_RETRY_DELAYS_MS[this.remoteSubmitRetryIndex];
|
|
1120
|
+
if (delayMs === undefined || !this.remoteSubmitText) {
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
this.remoteSubmitRetryTimer = setTimeout(() => {
|
|
1124
|
+
this.remoteSubmitRetryTimer = null;
|
|
1125
|
+
if (!this.remoteSubmitText ||
|
|
1126
|
+
!this.pty ||
|
|
1127
|
+
this.state.status !== "busy" ||
|
|
1128
|
+
!this.pendingInjectedInputs.some((input) => input.normalizedText === this.remoteSubmitText)) {
|
|
1129
|
+
this.clearRemoteSubmitRetry();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
this.writeToPty("\r");
|
|
1133
|
+
this.remoteSubmitRetryIndex += 1;
|
|
1134
|
+
if (this.remoteSubmitRetryIndex >= CLAUDE_REMOTE_ENTER_RETRY_DELAYS_MS.length) {
|
|
1135
|
+
this.clearRemoteSubmitRetry();
|
|
1136
|
+
this.emitClaudeNotice("Claude did not confirm the WeChat message submission. Press Enter in the local Claude terminal to retry.", "warning");
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
this.scheduleRemoteSubmitRetry();
|
|
1140
|
+
}, delayMs);
|
|
1141
|
+
this.remoteSubmitRetryTimer.unref?.();
|
|
1142
|
+
}
|
|
1143
|
+
clearRemoteSubmitRetry() {
|
|
1144
|
+
if (this.remoteSubmitRetryTimer) {
|
|
1145
|
+
clearTimeout(this.remoteSubmitRetryTimer);
|
|
1146
|
+
this.remoteSubmitRetryTimer = null;
|
|
1147
|
+
}
|
|
1148
|
+
this.remoteSubmitRetryIndex = 0;
|
|
1149
|
+
this.remoteSubmitText = null;
|
|
1150
|
+
}
|
|
999
1151
|
// Fallback heuristic for older Claude Code versions that lack PostCompact hooks.
|
|
1000
1152
|
// The structured PostCompact hook event (handled in handleClaudeHookEnvelope) is
|
|
1001
1153
|
// the reliable signal; this regex match serves as a best-effort fallback.
|
|
@@ -1044,6 +1196,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1044
1196
|
}
|
|
1045
1197
|
this.clearCompletionTimer();
|
|
1046
1198
|
this.clearWechatWorkingNotice(true);
|
|
1199
|
+
this.clearRemoteSubmitRetry();
|
|
1047
1200
|
this.pendingCliApprovalHints = null;
|
|
1048
1201
|
this.flushPendingClaudeHookApprovals();
|
|
1049
1202
|
this.pendingApproval = null;
|
|
@@ -1079,6 +1232,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1079
1232
|
const completedPreview = this.currentPreview;
|
|
1080
1233
|
this.clearCompletionTimer();
|
|
1081
1234
|
this.clearWechatWorkingNotice(true);
|
|
1235
|
+
this.clearRemoteSubmitRetry();
|
|
1082
1236
|
this.pendingCliApprovalHints = null;
|
|
1083
1237
|
this.flushPendingClaudeHookApprovals();
|
|
1084
1238
|
this.pendingApproval = null;
|
|
@@ -1168,6 +1322,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1168
1322
|
}
|
|
1169
1323
|
}
|
|
1170
1324
|
handleClaudeSessionStart(payload) {
|
|
1325
|
+
this.markInteractiveReady();
|
|
1171
1326
|
if (!payload.session_id) {
|
|
1172
1327
|
return;
|
|
1173
1328
|
}
|
|
@@ -1290,6 +1445,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1290
1445
|
}
|
|
1291
1446
|
const injectedIndex = findInjectedClaudePromptIndex(prompt, this.pendingInjectedInputs);
|
|
1292
1447
|
if (injectedIndex >= 0) {
|
|
1448
|
+
this.clearRemoteSubmitRetry();
|
|
1293
1449
|
this.pendingInjectedInputs.splice(injectedIndex, 1);
|
|
1294
1450
|
return;
|
|
1295
1451
|
}
|
|
@@ -1332,7 +1488,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1332
1488
|
this.state.lastSessionSwitchReason = undefined;
|
|
1333
1489
|
this.emitClaudeNotice(`Saved Claude conversation ${failedResumeConversationId} is no longer available. Starting a fresh Claude session.`, "warning");
|
|
1334
1490
|
try {
|
|
1335
|
-
await
|
|
1491
|
+
await this.reset();
|
|
1336
1492
|
}
|
|
1337
1493
|
catch (error) {
|
|
1338
1494
|
// recoverFromInvalidResume is invoked fire-and-forget (void) and there is
|
|
@@ -1441,6 +1597,7 @@ export class ClaudeCompanionAdapter extends AbstractPtyAdapter {
|
|
|
1441
1597
|
this.currentPreview === "(idle)") {
|
|
1442
1598
|
return;
|
|
1443
1599
|
}
|
|
1600
|
+
this.clearRemoteSubmitRetry();
|
|
1444
1601
|
this.clearWechatWorkingNotice(true);
|
|
1445
1602
|
this.pendingCliApprovalHints = null;
|
|
1446
1603
|
this.lastAutoApprovedPayload = null;
|