claude-codex-wechat 0.1.59 → 0.1.61
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.
|
@@ -31,6 +31,7 @@ const PLAYER_VIRTUAL_TIME_MS = 15_000;
|
|
|
31
31
|
const PLAYER_ATTEMPTS = 2;
|
|
32
32
|
const MAX_DOM_BYTES = 2 * 1024 * 1024;
|
|
33
33
|
const ALLOWED_VIDEO_HOST_SUFFIXES = [".douyinvod.com", ".douyin.com", ".snssdk.com"];
|
|
34
|
+
const ALLOWED_VIDEO_HOSTS = new Set(["v3-dy-o.zjcdn.com"]);
|
|
34
35
|
|
|
35
36
|
// ─── 带重试/超时的 fetch ─────────────────────────────────────────────────────
|
|
36
37
|
|
|
@@ -159,7 +160,9 @@ export function parseOfficialVideoUrl(dom) {
|
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
const allowed =
|
|
162
|
-
url.protocol === "https:" &&
|
|
163
|
+
url.protocol === "https:" &&
|
|
164
|
+
(ALLOWED_VIDEO_HOSTS.has(url.hostname) ||
|
|
165
|
+
ALLOWED_VIDEO_HOST_SUFFIXES.some((suffix) => url.hostname.endsWith(suffix)));
|
|
163
166
|
if (!allowed) throw new Error(`抖音官方播放器返回了非预期的视频域名:${url.hostname}`);
|
|
164
167
|
return url.toString();
|
|
165
168
|
}
|
package/dist/server/cli.js
CHANGED
|
@@ -757,10 +757,23 @@ async function hasClaudeHistoryDisplay(input) {
|
|
|
757
757
|
async function getClaudeNativeVersion(input) {
|
|
758
758
|
const sessionPath = await findRecoverableClaudeSessionPath(input.sessionId, input.env ?? process.env);
|
|
759
759
|
if (!sessionPath) return null;
|
|
760
|
-
const
|
|
761
|
-
if (
|
|
760
|
+
const content = await readFile2(sessionPath, "utf8").catch(() => null);
|
|
761
|
+
if (content === null) return null;
|
|
762
|
+
let count = 0;
|
|
763
|
+
let lastUuid = "";
|
|
764
|
+
for (const line of content.split(/\r?\n/)) {
|
|
765
|
+
if (!line.trim()) continue;
|
|
766
|
+
try {
|
|
767
|
+
const record = JSON.parse(line);
|
|
768
|
+
if ((record.type === "user" || record.type === "assistant") && typeof record.uuid === "string") {
|
|
769
|
+
count += 1;
|
|
770
|
+
lastUuid = record.uuid;
|
|
771
|
+
}
|
|
772
|
+
} catch {
|
|
773
|
+
}
|
|
774
|
+
}
|
|
762
775
|
return {
|
|
763
|
-
fingerprint: `claude:${input.sessionId}:${
|
|
776
|
+
fingerprint: `claude:${input.sessionId}:conv:${count}:${lastUuid}`,
|
|
764
777
|
observedAt: Date.now()
|
|
765
778
|
};
|
|
766
779
|
}
|
|
@@ -1017,10 +1030,23 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
1017
1030
|
async function getCodexNativeVersion(input) {
|
|
1018
1031
|
const sessionPath = await findRecoverableCodexSessionPath(input.sessionId, input.env ?? process.env);
|
|
1019
1032
|
if (!sessionPath) return null;
|
|
1020
|
-
const
|
|
1021
|
-
if (
|
|
1033
|
+
const content = await readFile3(sessionPath, "utf8").catch(() => null);
|
|
1034
|
+
if (content === null) return null;
|
|
1035
|
+
let count = 0;
|
|
1036
|
+
let lastTimestamp = "";
|
|
1037
|
+
for (const line of content.split(/\r?\n/)) {
|
|
1038
|
+
if (!line.trim()) continue;
|
|
1039
|
+
try {
|
|
1040
|
+
const record = JSON.parse(line);
|
|
1041
|
+
if (record.type === "response_item") {
|
|
1042
|
+
count += 1;
|
|
1043
|
+
lastTimestamp = typeof record.timestamp === "string" ? record.timestamp : "";
|
|
1044
|
+
}
|
|
1045
|
+
} catch {
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1022
1048
|
return {
|
|
1023
|
-
fingerprint: `codex:${input.sessionId}:${
|
|
1049
|
+
fingerprint: `codex:${input.sessionId}:conv:${count}:${lastTimestamp}`,
|
|
1024
1050
|
observedAt: Date.now()
|
|
1025
1051
|
};
|
|
1026
1052
|
}
|
|
@@ -4617,11 +4643,10 @@ var MessageRouter = class _MessageRouter {
|
|
|
4617
4643
|
if ((this.latestMutatingSeq.get(message.chatId) ?? 0) > seq) {
|
|
4618
4644
|
return { status: "accepted" };
|
|
4619
4645
|
}
|
|
4620
|
-
|
|
4621
|
-
if (await this.maybeSteer(message.chatId, chatText)) {
|
|
4646
|
+
if (await this.maybeSteer(message.chatId, command.text)) {
|
|
4622
4647
|
return { status: "accepted" };
|
|
4623
4648
|
}
|
|
4624
|
-
await this.runExclusive(() => this.runChatGeneration(message, user,
|
|
4649
|
+
await this.runExclusive(() => this.runChatGeneration(message, user, command.text, seq));
|
|
4625
4650
|
return { status: "accepted" };
|
|
4626
4651
|
}
|
|
4627
4652
|
// 消费一次上一轮暂存的 AskUserQuestion 选项:纯序号回复翻译成对应选项文字,
|
|
@@ -4643,7 +4668,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
4643
4668
|
if (!active) return Promise.resolve(false);
|
|
4644
4669
|
const provider = this.providers.get(active.providerId);
|
|
4645
4670
|
if (!provider?.steerSession) return Promise.resolve(false);
|
|
4646
|
-
return provider.steerSession(active.bridgeSessionId, text).then(() => true);
|
|
4671
|
+
return provider.steerSession(active.bridgeSessionId, this.resolveChoiceReply(chatId, text)).then(() => true);
|
|
4647
4672
|
}
|
|
4648
4673
|
// Serialize session-mutating work onto one global chain. The chain is updated
|
|
4649
4674
|
// synchronously (no await before the assignment) so two non-blocking channel
|
|
@@ -4687,6 +4712,17 @@ var MessageRouter = class _MessageRouter {
|
|
|
4687
4712
|
}).catch(() => null);
|
|
4688
4713
|
if (!version || !session.lastSeenNativeFingerprint) return { ok: true };
|
|
4689
4714
|
if (version.fingerprint === session.lastSeenNativeFingerprint) return { ok: true };
|
|
4715
|
+
if (LEGACY_NATIVE_FINGERPRINT.test(session.lastSeenNativeFingerprint)) {
|
|
4716
|
+
this.conversation.update({ lastSeenNativeFingerprint: version.fingerprint }, session.id);
|
|
4717
|
+
return { ok: true };
|
|
4718
|
+
}
|
|
4719
|
+
if (provider.attachSession) {
|
|
4720
|
+
try {
|
|
4721
|
+
await this.reattachSession(session, provider);
|
|
4722
|
+
return { ok: true };
|
|
4723
|
+
} catch {
|
|
4724
|
+
}
|
|
4725
|
+
}
|
|
4690
4726
|
this.conversation.update({
|
|
4691
4727
|
staleReason: "native_advanced_elsewhere",
|
|
4692
4728
|
lastActivityAt: Date.now()
|
|
@@ -4696,6 +4732,27 @@ var MessageRouter = class _MessageRouter {
|
|
|
4696
4732
|
message: "\u8BE5\u4F1A\u8BDD\u5DF2\u5728\u53E6\u4E00\u7AEF\u7EE7\u7EED\uFF0C\u5F53\u524D\u6865\u63A5\u72B6\u6001\u5DF2\u8FC7\u671F\u3002\u8BF7\u5148 /reload \u540E\u518D\u7EE7\u7EED\u3002"
|
|
4697
4733
|
};
|
|
4698
4734
|
}
|
|
4735
|
+
// 回收旧子进程并以 resume 方式重新挂载同一原生会话,使其加载另一端追加的最新历史。
|
|
4736
|
+
async reattachSession(current, provider) {
|
|
4737
|
+
if (!current.providerSessionId || !provider.attachSession) return;
|
|
4738
|
+
for (const [chatId, pending] of this.pendingChoices) {
|
|
4739
|
+
if (pending.sessionId === current.id) this.pendingChoices.delete(chatId);
|
|
4740
|
+
}
|
|
4741
|
+
this.recycleProviderProcess(current);
|
|
4742
|
+
const reattached = await provider.attachSession({
|
|
4743
|
+
candidateId: current.providerSessionId,
|
|
4744
|
+
bridgeSessionId: current.id,
|
|
4745
|
+
cwd: current.cwd
|
|
4746
|
+
});
|
|
4747
|
+
this.conversation.update({
|
|
4748
|
+
providerSessionId: reattached.providerSessionId ?? current.providerSessionId,
|
|
4749
|
+
status: reattached.status,
|
|
4750
|
+
lastSeenNativeFingerprint: void 0,
|
|
4751
|
+
lastReloadedAt: Date.now(),
|
|
4752
|
+
staleReason: void 0,
|
|
4753
|
+
lastActivityAt: Date.now()
|
|
4754
|
+
}, current.id);
|
|
4755
|
+
}
|
|
4699
4756
|
async refreshNativeFingerprint(session, provider) {
|
|
4700
4757
|
if (!session.providerSessionId || !provider.getNativeVersion) return;
|
|
4701
4758
|
const version = await provider.getNativeVersion({
|
|
@@ -4709,7 +4766,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
4709
4766
|
lastActivityAt: Date.now()
|
|
4710
4767
|
}, session.id);
|
|
4711
4768
|
}
|
|
4712
|
-
async runChatGeneration(message, user,
|
|
4769
|
+
async runChatGeneration(message, user, rawText, seq) {
|
|
4713
4770
|
const superseded = () => (this.latestMutatingSeq.get(message.chatId) ?? 0) > seq;
|
|
4714
4771
|
if (superseded()) return;
|
|
4715
4772
|
const sessionResumeTitle = buildSessionBridgeName({
|
|
@@ -4765,6 +4822,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
4765
4822
|
await this.sendToChat({ chatId: message.chatId, kind: "status", text: freshness.message });
|
|
4766
4823
|
return;
|
|
4767
4824
|
}
|
|
4825
|
+
const text = this.resolveChoiceReply(message.chatId, rawText);
|
|
4768
4826
|
const genId = ++this.generationSeq;
|
|
4769
4827
|
let abortGeneration;
|
|
4770
4828
|
const aborted = new Promise((resolve3) => {
|
|
@@ -4912,20 +4970,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
4912
4970
|
return;
|
|
4913
4971
|
}
|
|
4914
4972
|
await this.preemptActiveGeneration(chatId);
|
|
4915
|
-
this.
|
|
4916
|
-
const reattached = await provider.attachSession({
|
|
4917
|
-
candidateId: current.providerSessionId,
|
|
4918
|
-
bridgeSessionId: current.id,
|
|
4919
|
-
cwd: current.cwd
|
|
4920
|
-
});
|
|
4921
|
-
this.conversation.update({
|
|
4922
|
-
providerSessionId: reattached.providerSessionId ?? current.providerSessionId,
|
|
4923
|
-
status: reattached.status,
|
|
4924
|
-
lastSeenNativeFingerprint: void 0,
|
|
4925
|
-
lastReloadedAt: Date.now(),
|
|
4926
|
-
staleReason: void 0,
|
|
4927
|
-
lastActivityAt: Date.now()
|
|
4928
|
-
}, current.id);
|
|
4973
|
+
await this.reattachSession(current, provider);
|
|
4929
4974
|
await this.sendToChat({ chatId, kind: "status", text: "\u5DF2\u91CD\u65B0\u52A0\u8F7D\u5F53\u524D\u4F1A\u8BDD\uFF0C\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u3002" });
|
|
4930
4975
|
return;
|
|
4931
4976
|
}
|
|
@@ -5087,6 +5132,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
5087
5132
|
}
|
|
5088
5133
|
}
|
|
5089
5134
|
};
|
|
5135
|
+
var LEGACY_NATIVE_FINGERPRINT = /^(claude|codex):[^:]+:\d+:\d+$/;
|
|
5090
5136
|
function summarizeResumeTitle(text) {
|
|
5091
5137
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
5092
5138
|
if (!normalized) return void 0;
|