claude-codex-wechat 0.1.7 → 0.1.11
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 +56 -104
- package/dist/server/cli.js +176 -173
- package/dist/web/assets/index-BW-_vdVB.js +10 -0
- package/dist/web/index.html +1 -1
- package/package.json +5 -1
- package/dist/web/assets/index-Dxzp2xaC.js +0 -10
package/dist/server/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __cjsCreateRequire } from 'node:module'; const require
|
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
6
|
-
import { dirname as
|
|
6
|
+
import { dirname as dirname12, join as join12 } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
|
|
9
9
|
// src/daemon/bootstrap.ts
|
|
@@ -12,7 +12,7 @@ import { networkInterfaces } from "node:os";
|
|
|
12
12
|
// src/daemon/server.ts
|
|
13
13
|
import { mkdtempSync } from "node:fs";
|
|
14
14
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
15
|
-
import { dirname as
|
|
15
|
+
import { dirname as dirname10, join as join9 } from "node:path";
|
|
16
16
|
import Fastify from "fastify";
|
|
17
17
|
|
|
18
18
|
// src/channels/platforms.ts
|
|
@@ -372,7 +372,7 @@ async function listRecoverableClaudeSessions(env = process.env) {
|
|
|
372
372
|
id: sessionId,
|
|
373
373
|
providerId: "claude-code",
|
|
374
374
|
...cwd ? { cwd } : {},
|
|
375
|
-
title: parsedMeta?.aiTitle ?? parsedMeta?.lastPrompt
|
|
375
|
+
...parsedMeta?.aiTitle ?? parsedMeta?.lastPrompt ? { title: parsedMeta?.aiTitle ?? parsedMeta?.lastPrompt } : {},
|
|
376
376
|
...parsedMeta?.sessionName ? { resumeTitle: parsedMeta.sessionName } : historyMeta?.display ? { resumeTitle: historyMeta.display } : {},
|
|
377
377
|
...historyMeta?.timestamp ? { lastActivityAt: historyMeta.timestamp } : metadata ? { lastActivityAt: Math.trunc(metadata.mtimeMs) } : {},
|
|
378
378
|
...bridgeTag ? { bridgeBindingSource: "bridge_tag", bridgeTag } : {}
|
|
@@ -880,7 +880,7 @@ async function syncCodexRolloutSessionMeta(rolloutPath) {
|
|
|
880
880
|
}
|
|
881
881
|
}
|
|
882
882
|
async function delay(ms) {
|
|
883
|
-
await new Promise((
|
|
883
|
+
await new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
884
884
|
}
|
|
885
885
|
|
|
886
886
|
// src/session/providerAutoAttach.ts
|
|
@@ -1061,7 +1061,7 @@ function registerChannelAdminRoutes(input) {
|
|
|
1061
1061
|
|
|
1062
1062
|
`);
|
|
1063
1063
|
while (true) {
|
|
1064
|
-
await new Promise((
|
|
1064
|
+
await new Promise((resolve2) => setTimeout(resolve2, client.pollIntervalMs));
|
|
1065
1065
|
const status = await client.pollQrCodeStatus(qr.ticket);
|
|
1066
1066
|
if (status.status === "waiting") continue;
|
|
1067
1067
|
if (status.status === "scanned") {
|
|
@@ -1431,6 +1431,48 @@ function normalizeSettings(input, defaultWorkspace) {
|
|
|
1431
1431
|
};
|
|
1432
1432
|
}
|
|
1433
1433
|
|
|
1434
|
+
// src/admin/fsBrowseRoutes.ts
|
|
1435
|
+
import { readdir as readdir3 } from "node:fs/promises";
|
|
1436
|
+
import { homedir as homedir7 } from "node:os";
|
|
1437
|
+
import { dirname as dirname5, join as join6, resolve } from "node:path";
|
|
1438
|
+
|
|
1439
|
+
// src/shared/expandTilde.ts
|
|
1440
|
+
import { homedir as homedir6 } from "node:os";
|
|
1441
|
+
function expandTilde(target) {
|
|
1442
|
+
if (!target) return target;
|
|
1443
|
+
if (target === "~") return homedir6();
|
|
1444
|
+
if (target.startsWith("~/")) return homedir6() + target.slice(1);
|
|
1445
|
+
return target;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// src/admin/fsBrowseRoutes.ts
|
|
1449
|
+
function registerFsBrowseRoutes(input) {
|
|
1450
|
+
input.app.get("/api/fs/list", async (request, reply) => {
|
|
1451
|
+
const raw = request.query.path?.trim();
|
|
1452
|
+
const target = resolve(expandTilde(raw && raw.length > 0 ? raw : homedir7()) ?? homedir7());
|
|
1453
|
+
const keepRaw = request.query.keep?.trim();
|
|
1454
|
+
const keep = keepRaw && keepRaw.length > 0 ? resolve(expandTilde(keepRaw) ?? keepRaw) : null;
|
|
1455
|
+
const isOnKeepChain = (path) => keep !== null && (keep === path || keep.startsWith(path + "/"));
|
|
1456
|
+
let dirents;
|
|
1457
|
+
try {
|
|
1458
|
+
dirents = await readdir3(target, { withFileTypes: true });
|
|
1459
|
+
} catch {
|
|
1460
|
+
reply.code(400);
|
|
1461
|
+
return { error: "cannot_read_directory", path: target };
|
|
1462
|
+
}
|
|
1463
|
+
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path: join6(target, dirent.name), isDirectory: true })).filter((entry) => !entry.name.startsWith(".") || isOnKeepChain(entry.path)).sort((a, b) => a.name.localeCompare(b.name));
|
|
1464
|
+
const parent = dirname5(target);
|
|
1465
|
+
const isRoot = parent === target;
|
|
1466
|
+
const listing = {
|
|
1467
|
+
path: target,
|
|
1468
|
+
parent: isRoot ? null : parent,
|
|
1469
|
+
isRoot,
|
|
1470
|
+
entries
|
|
1471
|
+
};
|
|
1472
|
+
return listing;
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1434
1476
|
// src/channels/weixin-direct/apiClient.ts
|
|
1435
1477
|
import { randomUUID } from "node:crypto";
|
|
1436
1478
|
function collectInboundItems(itemList) {
|
|
@@ -1600,7 +1642,7 @@ var WeixinDirectApiClient = class {
|
|
|
1600
1642
|
|
|
1601
1643
|
// src/channels/weixin-direct/adapter.ts
|
|
1602
1644
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
1603
|
-
import { join as
|
|
1645
|
+
import { join as join7 } from "node:path";
|
|
1604
1646
|
|
|
1605
1647
|
// src/channels/weixin-direct/typingController.ts
|
|
1606
1648
|
var CONFIG_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -1865,7 +1907,7 @@ var WeixinDirectAdapter = class _WeixinDirectAdapter {
|
|
|
1865
1907
|
continue;
|
|
1866
1908
|
}
|
|
1867
1909
|
const { ext, mimeType } = mediaExtAndMime(meta);
|
|
1868
|
-
const destPath =
|
|
1910
|
+
const destPath = join7(mediaDir, `${idPrefix}_${i}${ext}`);
|
|
1869
1911
|
const maxBytes = meta.kind === "video" ? VIDEO_MAX_BYTES : void 0;
|
|
1870
1912
|
const result = await downloader.download(meta.media ?? {}, { destPath, aeskeyOverride: meta.aeskey, maxBytes });
|
|
1871
1913
|
if (result.ok) {
|
|
@@ -1926,7 +1968,7 @@ function chunkText(text, limit) {
|
|
|
1926
1968
|
|
|
1927
1969
|
// src/channels/weixin-direct/mediaDownloader.ts
|
|
1928
1970
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1929
|
-
import { dirname as
|
|
1971
|
+
import { dirname as dirname6 } from "node:path";
|
|
1930
1972
|
|
|
1931
1973
|
// src/channels/weixin-direct/mediaCrypto.ts
|
|
1932
1974
|
import { createDecipheriv } from "node:crypto";
|
|
@@ -1989,7 +2031,7 @@ var WeixinMediaDownloader = class {
|
|
|
1989
2031
|
} catch {
|
|
1990
2032
|
return { ok: false, reason: "decrypt_failed" };
|
|
1991
2033
|
}
|
|
1992
|
-
mkdirSync2(
|
|
2034
|
+
mkdirSync2(dirname6(input.destPath), { recursive: true });
|
|
1993
2035
|
writeFileSync2(input.destPath, plaintext);
|
|
1994
2036
|
return { ok: true, localPath: input.destPath, bytes: plaintext.length };
|
|
1995
2037
|
}
|
|
@@ -2174,18 +2216,9 @@ var WeixinOutboundGate = class _WeixinOutboundGate {
|
|
|
2174
2216
|
import { spawn as spawn2 } from "node:child_process";
|
|
2175
2217
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2176
2218
|
|
|
2177
|
-
// src/shared/expandTilde.ts
|
|
2178
|
-
import { homedir as homedir6 } from "node:os";
|
|
2179
|
-
function expandTilde(target) {
|
|
2180
|
-
if (!target) return target;
|
|
2181
|
-
if (target === "~") return homedir6();
|
|
2182
|
-
if (target.startsWith("~/")) return homedir6() + target.slice(1);
|
|
2183
|
-
return target;
|
|
2184
|
-
}
|
|
2185
|
-
|
|
2186
2219
|
// src/shared/platform.ts
|
|
2187
2220
|
import { access, constants } from "node:fs/promises";
|
|
2188
|
-
import { delimiter, join as
|
|
2221
|
+
import { delimiter, join as join8 } from "node:path";
|
|
2189
2222
|
import { tmpdir } from "node:os";
|
|
2190
2223
|
import { spawn } from "node:child_process";
|
|
2191
2224
|
var isWindows = process.platform === "win32";
|
|
@@ -2213,7 +2246,7 @@ async function findExecutable(command) {
|
|
|
2213
2246
|
const dirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
2214
2247
|
for (const dir of dirs) {
|
|
2215
2248
|
for (const ext of extensions) {
|
|
2216
|
-
const candidate =
|
|
2249
|
+
const candidate = join8(dir, command + ext);
|
|
2217
2250
|
if (await isExecutableFile(candidate)) return candidate;
|
|
2218
2251
|
}
|
|
2219
2252
|
}
|
|
@@ -2236,10 +2269,10 @@ function terminateChild(child, signal = "SIGTERM") {
|
|
|
2236
2269
|
}
|
|
2237
2270
|
}
|
|
2238
2271
|
function defaultWorkspaceDir() {
|
|
2239
|
-
return
|
|
2272
|
+
return join8(tmpdir(), "project");
|
|
2240
2273
|
}
|
|
2241
2274
|
function statePath(filename) {
|
|
2242
|
-
return
|
|
2275
|
+
return join8(tmpdir(), filename);
|
|
2243
2276
|
}
|
|
2244
2277
|
|
|
2245
2278
|
// src/providers/claude-code/claudeStreamingRunner.ts
|
|
@@ -2418,10 +2451,10 @@ function defaultClaudeStreamSpawner(call) {
|
|
|
2418
2451
|
const queue = [];
|
|
2419
2452
|
let resolveNext = null;
|
|
2420
2453
|
const push = (chunk) => {
|
|
2421
|
-
const
|
|
2422
|
-
if (
|
|
2454
|
+
const resolve2 = resolveNext;
|
|
2455
|
+
if (resolve2) {
|
|
2423
2456
|
resolveNext = null;
|
|
2424
|
-
|
|
2457
|
+
resolve2(chunk);
|
|
2425
2458
|
} else {
|
|
2426
2459
|
queue.push(chunk);
|
|
2427
2460
|
}
|
|
@@ -2451,8 +2484,8 @@ function defaultClaudeStreamSpawner(call) {
|
|
|
2451
2484
|
read() {
|
|
2452
2485
|
const next = queue.shift();
|
|
2453
2486
|
if (next) return Promise.resolve(next);
|
|
2454
|
-
return new Promise((
|
|
2455
|
-
resolveNext =
|
|
2487
|
+
return new Promise((resolve2) => {
|
|
2488
|
+
resolveNext = resolve2;
|
|
2456
2489
|
});
|
|
2457
2490
|
},
|
|
2458
2491
|
close() {
|
|
@@ -2551,8 +2584,8 @@ var CodexAppServerClient = class {
|
|
|
2551
2584
|
const id = this.nextId++;
|
|
2552
2585
|
const key = String(id);
|
|
2553
2586
|
const payload = { id, method, ...params !== void 0 ? { params } : {} };
|
|
2554
|
-
const response = new Promise((
|
|
2555
|
-
this.pending.set(key, { resolve, reject });
|
|
2587
|
+
const response = new Promise((resolve2, reject) => {
|
|
2588
|
+
this.pending.set(key, { resolve: resolve2, reject });
|
|
2556
2589
|
});
|
|
2557
2590
|
this.child.stdin.write(`${JSON.stringify(payload)}
|
|
2558
2591
|
`);
|
|
@@ -2704,8 +2737,8 @@ var CodexInteractiveRunner = class {
|
|
|
2704
2737
|
const client = await this.ensureClient(session);
|
|
2705
2738
|
session.pendingText = [];
|
|
2706
2739
|
session.activeTurnId = void 0;
|
|
2707
|
-
session.turnCompletedPromise = new Promise((
|
|
2708
|
-
session.turnCompletedResolver =
|
|
2740
|
+
session.turnCompletedPromise = new Promise((resolve2) => {
|
|
2741
|
+
session.turnCompletedResolver = resolve2;
|
|
2709
2742
|
});
|
|
2710
2743
|
if (session.threadId) {
|
|
2711
2744
|
await client.request("thread/resume", {
|
|
@@ -2878,7 +2911,7 @@ function createDefaultProviders(input = {}) {
|
|
|
2878
2911
|
// src/providers/claude-code/claudeDetection.ts
|
|
2879
2912
|
import { spawn as spawn4 } from "node:child_process";
|
|
2880
2913
|
async function defaultCommandRunner(command, args) {
|
|
2881
|
-
return await new Promise((
|
|
2914
|
+
return await new Promise((resolve2) => {
|
|
2882
2915
|
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
2883
2916
|
let stdout = "";
|
|
2884
2917
|
let stderr = "";
|
|
@@ -2889,11 +2922,11 @@ async function defaultCommandRunner(command, args) {
|
|
|
2889
2922
|
stderr += String(chunk);
|
|
2890
2923
|
});
|
|
2891
2924
|
child.on("error", (error) => {
|
|
2892
|
-
|
|
2925
|
+
resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
|
|
2893
2926
|
});
|
|
2894
2927
|
child.on("close", (code) => {
|
|
2895
|
-
if (code === 0)
|
|
2896
|
-
else
|
|
2928
|
+
if (code === 0) resolve2({ ok: true, stdout, stderr });
|
|
2929
|
+
else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
|
|
2897
2930
|
});
|
|
2898
2931
|
});
|
|
2899
2932
|
}
|
|
@@ -2914,7 +2947,7 @@ ${result.stderr}`) };
|
|
|
2914
2947
|
// src/providers/codex/codexDetection.ts
|
|
2915
2948
|
import { spawn as spawn5 } from "node:child_process";
|
|
2916
2949
|
async function defaultCodexCommandRunner(command, args) {
|
|
2917
|
-
return await new Promise((
|
|
2950
|
+
return await new Promise((resolve2) => {
|
|
2918
2951
|
const child = spawn5(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
2919
2952
|
let stdout = "";
|
|
2920
2953
|
let stderr = "";
|
|
@@ -2925,11 +2958,11 @@ async function defaultCodexCommandRunner(command, args) {
|
|
|
2925
2958
|
stderr += String(chunk);
|
|
2926
2959
|
});
|
|
2927
2960
|
child.on("error", (error) => {
|
|
2928
|
-
|
|
2961
|
+
resolve2({ ok: false, code: error.code ?? "ERROR", stdout, stderr: stderr || error.message });
|
|
2929
2962
|
});
|
|
2930
2963
|
child.on("close", (code) => {
|
|
2931
|
-
if (code === 0)
|
|
2932
|
-
else
|
|
2964
|
+
if (code === 0) resolve2({ ok: true, stdout, stderr });
|
|
2965
|
+
else resolve2({ ok: false, code: code ?? "SIGNAL", stdout, stderr });
|
|
2933
2966
|
});
|
|
2934
2967
|
});
|
|
2935
2968
|
}
|
|
@@ -3060,7 +3093,7 @@ function buildBridgeCommandHelpMarkdown() {
|
|
|
3060
3093
|
|
|
3061
3094
|
// src/session/currentConversationStore.ts
|
|
3062
3095
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3063
|
-
import { dirname as
|
|
3096
|
+
import { dirname as dirname7 } from "node:path";
|
|
3064
3097
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3065
3098
|
var CurrentConversationStore = class {
|
|
3066
3099
|
constructor(configPath, defaults) {
|
|
@@ -3142,7 +3175,7 @@ var CurrentConversationStore = class {
|
|
|
3142
3175
|
this.writeState(state);
|
|
3143
3176
|
}
|
|
3144
3177
|
writeState(state) {
|
|
3145
|
-
mkdirSync3(
|
|
3178
|
+
mkdirSync3(dirname7(this.configPath), { recursive: true });
|
|
3146
3179
|
writeFileSync3(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
3147
3180
|
`, "utf8");
|
|
3148
3181
|
}
|
|
@@ -3350,8 +3383,8 @@ var MessageRouter = class _MessageRouter {
|
|
|
3350
3383
|
}
|
|
3351
3384
|
const genId = ++this.generationSeq;
|
|
3352
3385
|
let abortGeneration;
|
|
3353
|
-
const aborted = new Promise((
|
|
3354
|
-
abortGeneration = () =>
|
|
3386
|
+
const aborted = new Promise((resolve2) => {
|
|
3387
|
+
abortGeneration = () => resolve2("aborted");
|
|
3355
3388
|
});
|
|
3356
3389
|
this.activeGenerations.set(message.chatId, {
|
|
3357
3390
|
genId,
|
|
@@ -3576,7 +3609,7 @@ var MessageRouter = class _MessageRouter {
|
|
|
3576
3609
|
}
|
|
3577
3610
|
}
|
|
3578
3611
|
formatSessionLine(candidate) {
|
|
3579
|
-
const title = candidate.resumeTitle ?? candidate.title ?? candidate.id
|
|
3612
|
+
const title = candidate.resumeTitle ?? candidate.title ?? `\u672A\u547D\u540D\u4F1A\u8BDD \xB7 ${candidate.id.slice(0, 8)}`;
|
|
3580
3613
|
const cwd = candidate.cwd ? ` \xB7 ${candidate.cwd}` : "";
|
|
3581
3614
|
const when = candidate.lastActivityAt ? ` \xB7 ${formatRelativeTime(candidate.lastActivityAt)}` : "";
|
|
3582
3615
|
return `${title}${cwd}${when}`;
|
|
@@ -3649,7 +3682,7 @@ function composeInboundText(content) {
|
|
|
3649
3682
|
|
|
3650
3683
|
// src/storage/lastProviderSessionStore.ts
|
|
3651
3684
|
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3652
|
-
import { dirname as
|
|
3685
|
+
import { dirname as dirname8 } from "node:path";
|
|
3653
3686
|
var LastProviderSessionStore = class {
|
|
3654
3687
|
constructor(configPath) {
|
|
3655
3688
|
this.configPath = configPath;
|
|
@@ -3680,7 +3713,7 @@ var LastProviderSessionStore = class {
|
|
|
3680
3713
|
return raw && typeof raw === "object" ? raw : {};
|
|
3681
3714
|
}
|
|
3682
3715
|
writeState(state) {
|
|
3683
|
-
mkdirSync4(
|
|
3716
|
+
mkdirSync4(dirname8(this.configPath), { recursive: true });
|
|
3684
3717
|
writeFileSync4(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
3685
3718
|
`, "utf8");
|
|
3686
3719
|
}
|
|
@@ -3688,7 +3721,7 @@ var LastProviderSessionStore = class {
|
|
|
3688
3721
|
|
|
3689
3722
|
// src/storage/runtimeUserStore.ts
|
|
3690
3723
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "node:fs";
|
|
3691
|
-
import { dirname as
|
|
3724
|
+
import { dirname as dirname9 } from "node:path";
|
|
3692
3725
|
import { nanoid as nanoid3 } from "nanoid";
|
|
3693
3726
|
var RuntimeUserStore = class {
|
|
3694
3727
|
constructor(configPath) {
|
|
@@ -3753,7 +3786,7 @@ var RuntimeUserStore = class {
|
|
|
3753
3786
|
return raw && typeof raw === "object" ? raw : {};
|
|
3754
3787
|
}
|
|
3755
3788
|
writeState(state) {
|
|
3756
|
-
mkdirSync5(
|
|
3789
|
+
mkdirSync5(dirname9(this.configPath), { recursive: true });
|
|
3757
3790
|
writeFileSync5(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
3758
3791
|
`, "utf8");
|
|
3759
3792
|
}
|
|
@@ -3784,7 +3817,7 @@ function createDaemonServer(options = {}) {
|
|
|
3784
3817
|
defaultProvider: options.bridgeDefaults?.defaultProvider ?? "claude-code",
|
|
3785
3818
|
defaultWorkspace: options.bridgeDefaults?.defaultWorkspace ?? process.cwd()
|
|
3786
3819
|
};
|
|
3787
|
-
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ??
|
|
3820
|
+
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join9(mkdtempSync(join9(tmpdir2(), "claude-codex-wechat-")), "config.json");
|
|
3788
3821
|
const conversation = new CurrentConversationStore(configPath, {
|
|
3789
3822
|
defaultCwd: bridgeDefaults.defaultWorkspace,
|
|
3790
3823
|
defaultProviderId: bridgeDefaults.defaultProvider
|
|
@@ -3817,7 +3850,7 @@ function createDaemonServer(options = {}) {
|
|
|
3817
3850
|
});
|
|
3818
3851
|
}
|
|
3819
3852
|
const weixinStateStore = configPath ? new FileWeixinStateStore(configPath) : void 0;
|
|
3820
|
-
const weixinMediaDir = configPath ?
|
|
3853
|
+
const weixinMediaDir = configPath ? join9(dirname10(configPath), "media") : void 0;
|
|
3821
3854
|
const managedWechatChannel = options.channel ? null : new ManagedWeixinDirectAdapter(options.wechat, weixinStateStore, weixinMediaDir);
|
|
3822
3855
|
const channel = options.channel ?? managedWechatChannel;
|
|
3823
3856
|
const weixinOutboundGate = managedWechatChannel && weixinStateStore ? new WeixinOutboundGate({
|
|
@@ -3907,6 +3940,7 @@ function createDaemonServer(options = {}) {
|
|
|
3907
3940
|
defaults: bridgeDefaults,
|
|
3908
3941
|
configPath
|
|
3909
3942
|
});
|
|
3943
|
+
registerFsBrowseRoutes({ app });
|
|
3910
3944
|
app.get("/api/status", async () => ({
|
|
3911
3945
|
ok: true,
|
|
3912
3946
|
sessions: conversation.getCurrent() ? [conversation.getCurrent()] : []
|
|
@@ -3989,30 +4023,9 @@ async function resolveProviderCommands(providers) {
|
|
|
3989
4023
|
};
|
|
3990
4024
|
}
|
|
3991
4025
|
|
|
3992
|
-
// src/daemon/portGuard.ts
|
|
3993
|
-
import { execFile } from "node:child_process";
|
|
3994
|
-
import { promisify } from "node:util";
|
|
3995
|
-
var execFileAsync = promisify(execFile);
|
|
3996
|
-
async function findListeningProcess(port) {
|
|
3997
|
-
if (process.platform === "win32") return null;
|
|
3998
|
-
try {
|
|
3999
|
-
const { stdout } = await execFileAsync("lsof", ["-n", "-P", `-iTCP:${port}`, "-sTCP:LISTEN"]);
|
|
4000
|
-
const lines = stdout.trim().split(/\r?\n/).filter(Boolean);
|
|
4001
|
-
const record = lines.slice(1)[0];
|
|
4002
|
-
if (!record) return null;
|
|
4003
|
-
const parts = record.trim().split(/\s+/);
|
|
4004
|
-
const command = parts[0] ?? "";
|
|
4005
|
-
const pid = Number(parts[1] ?? "");
|
|
4006
|
-
if (!command || !Number.isFinite(pid)) return null;
|
|
4007
|
-
return { pid, command };
|
|
4008
|
-
} catch {
|
|
4009
|
-
return null;
|
|
4010
|
-
}
|
|
4011
|
-
}
|
|
4012
|
-
|
|
4013
4026
|
// src/daemon/staticFrontend.ts
|
|
4014
4027
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
4015
|
-
import { join as
|
|
4028
|
+
import { join as join10 } from "node:path";
|
|
4016
4029
|
import fastifyStatic from "@fastify/static";
|
|
4017
4030
|
function attachStaticFrontend(webRoot2) {
|
|
4018
4031
|
return async (app) => {
|
|
@@ -4020,7 +4033,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4020
4033
|
root: webRoot2,
|
|
4021
4034
|
wildcard: false
|
|
4022
4035
|
});
|
|
4023
|
-
const indexHtml = readFileSync6(
|
|
4036
|
+
const indexHtml = readFileSync6(join10(webRoot2, "index.html"), "utf8");
|
|
4024
4037
|
app.setNotFoundHandler((request, reply) => {
|
|
4025
4038
|
if (request.url.startsWith("/api")) {
|
|
4026
4039
|
reply.code(404).send({ error: "not_found" });
|
|
@@ -4034,18 +4047,18 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4034
4047
|
// src/daemon/service.ts
|
|
4035
4048
|
import { existsSync as existsSync8, statSync } from "node:fs";
|
|
4036
4049
|
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
4037
|
-
import { homedir as
|
|
4038
|
-
import { dirname as
|
|
4050
|
+
import { homedir as homedir8 } from "node:os";
|
|
4051
|
+
import { dirname as dirname11, join as join11 } from "node:path";
|
|
4039
4052
|
import { createReadStream } from "node:fs";
|
|
4040
|
-
import { execFile
|
|
4053
|
+
import { execFile, spawn as spawn6 } from "node:child_process";
|
|
4041
4054
|
import { createInterface } from "node:readline";
|
|
4042
|
-
import { promisify
|
|
4043
|
-
var
|
|
4055
|
+
import { promisify } from "node:util";
|
|
4056
|
+
var execFileAsync = promisify(execFile);
|
|
4044
4057
|
async function installService(context) {
|
|
4045
4058
|
if (process.platform === "darwin") {
|
|
4046
4059
|
const spec = buildLaunchdSpec(context);
|
|
4047
|
-
await mkdir4(
|
|
4048
|
-
await mkdir4(
|
|
4060
|
+
await mkdir4(dirname11(spec.plistPath), { recursive: true });
|
|
4061
|
+
await mkdir4(dirname11(spec.stdoutPath), { recursive: true });
|
|
4049
4062
|
await writeFile5(spec.plistPath, renderLaunchdPlist(spec), "utf8");
|
|
4050
4063
|
await runLaunchctl(["unload", spec.plistPath]).catch(() => void 0);
|
|
4051
4064
|
await runLaunchctl(["load", spec.plistPath]);
|
|
@@ -4054,8 +4067,8 @@ async function installService(context) {
|
|
|
4054
4067
|
}
|
|
4055
4068
|
if (process.platform === "linux") {
|
|
4056
4069
|
const spec = buildSystemdUserSpec(context);
|
|
4057
|
-
await mkdir4(
|
|
4058
|
-
await mkdir4(
|
|
4070
|
+
await mkdir4(dirname11(spec.unitPath), { recursive: true });
|
|
4071
|
+
await mkdir4(dirname11(spec.stdoutPath), { recursive: true });
|
|
4059
4072
|
await writeFile5(spec.unitPath, renderSystemdUnit(spec), "utf8");
|
|
4060
4073
|
await runSystemctl(["--user", "daemon-reload"]);
|
|
4061
4074
|
await runSystemctl(["--user", "enable", "--now", spec.unitName]);
|
|
@@ -4177,33 +4190,33 @@ async function readServiceStatus(context) {
|
|
|
4177
4190
|
throw new Error("service_status_not_supported_on_this_platform");
|
|
4178
4191
|
}
|
|
4179
4192
|
function buildLaunchdSpec(context) {
|
|
4180
|
-
const stateDir =
|
|
4193
|
+
const stateDir = join11(homedir8(), ".claude-codex-wechat");
|
|
4181
4194
|
return {
|
|
4182
4195
|
label: "com.claude-codex-wechat",
|
|
4183
|
-
plistPath:
|
|
4184
|
-
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "
|
|
4185
|
-
workingDirectory:
|
|
4186
|
-
stdoutPath:
|
|
4187
|
-
stderrPath:
|
|
4196
|
+
plistPath: join11(homedir8(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
|
|
4197
|
+
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
4198
|
+
workingDirectory: homedir8(),
|
|
4199
|
+
stdoutPath: join11(stateDir, "logs", "service.stdout.log"),
|
|
4200
|
+
stderrPath: join11(stateDir, "logs", "service.stderr.log"),
|
|
4188
4201
|
environment: buildServiceEnvironment(context)
|
|
4189
4202
|
};
|
|
4190
4203
|
}
|
|
4191
4204
|
function buildSystemdUserSpec(context) {
|
|
4192
|
-
const stateDir =
|
|
4205
|
+
const stateDir = join11(homedir8(), ".claude-codex-wechat");
|
|
4193
4206
|
return {
|
|
4194
4207
|
unitName: "claude-codex-wechat.service",
|
|
4195
|
-
unitPath:
|
|
4196
|
-
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "
|
|
4197
|
-
workingDirectory:
|
|
4198
|
-
stdoutPath:
|
|
4199
|
-
stderrPath:
|
|
4208
|
+
unitPath: join11(homedir8(), ".config", "systemd", "user", "claude-codex-wechat.service"),
|
|
4209
|
+
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
4210
|
+
workingDirectory: homedir8(),
|
|
4211
|
+
stdoutPath: join11(stateDir, "logs", "service.stdout.log"),
|
|
4212
|
+
stderrPath: join11(stateDir, "logs", "service.stderr.log"),
|
|
4200
4213
|
environment: buildServiceEnvironment(context)
|
|
4201
4214
|
};
|
|
4202
4215
|
}
|
|
4203
4216
|
function buildServiceEnvironment(context) {
|
|
4204
4217
|
const env = {
|
|
4205
4218
|
PATH: process.env.PATH ?? "",
|
|
4206
|
-
HOME: process.env.HOME ??
|
|
4219
|
+
HOME: process.env.HOME ?? homedir8()
|
|
4207
4220
|
};
|
|
4208
4221
|
const configPath = context.configPath ?? process.env.BRIDGE_CONFIG;
|
|
4209
4222
|
const port = context.port ?? Number(process.env.BRIDGE_PORT ?? 8787);
|
|
@@ -4292,10 +4305,10 @@ function quoteSystemdEnv(value) {
|
|
|
4292
4305
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
4293
4306
|
}
|
|
4294
4307
|
async function runLaunchctl(args) {
|
|
4295
|
-
await
|
|
4308
|
+
await execFileAsync("launchctl", args);
|
|
4296
4309
|
}
|
|
4297
4310
|
async function runSystemctl(args) {
|
|
4298
|
-
await
|
|
4311
|
+
await execFileAsync("systemctl", args);
|
|
4299
4312
|
}
|
|
4300
4313
|
async function ensureFileExists(path, errorCode) {
|
|
4301
4314
|
if (!existsSync8(path)) throw new Error(errorCode);
|
|
@@ -4325,8 +4338,8 @@ async function tailFiles(paths) {
|
|
|
4325
4338
|
child.stdout.on("data", (chunk) => {
|
|
4326
4339
|
process.stdout.write(String(chunk));
|
|
4327
4340
|
});
|
|
4328
|
-
await new Promise((
|
|
4329
|
-
child.on("exit", () =>
|
|
4341
|
+
await new Promise((resolve2, reject) => {
|
|
4342
|
+
child.on("exit", () => resolve2());
|
|
4330
4343
|
child.on("error", reject);
|
|
4331
4344
|
}).finally(() => {
|
|
4332
4345
|
for (const reader of readers) reader.close();
|
|
@@ -4341,8 +4354,8 @@ function fileSizeHint(path) {
|
|
|
4341
4354
|
}
|
|
4342
4355
|
|
|
4343
4356
|
// src/cli.ts
|
|
4344
|
-
var here =
|
|
4345
|
-
var webRoot =
|
|
4357
|
+
var here = dirname12(fileURLToPath(import.meta.url));
|
|
4358
|
+
var webRoot = join12(here, "..", "web");
|
|
4346
4359
|
async function main() {
|
|
4347
4360
|
const command = process.argv[2];
|
|
4348
4361
|
switch (command) {
|
|
@@ -4350,18 +4363,37 @@ async function main() {
|
|
|
4350
4363
|
case "start":
|
|
4351
4364
|
await cmdStart();
|
|
4352
4365
|
return;
|
|
4366
|
+
case "stop":
|
|
4367
|
+
await cmdStop();
|
|
4368
|
+
return;
|
|
4369
|
+
case "restart":
|
|
4370
|
+
await cmdRestart();
|
|
4371
|
+
return;
|
|
4372
|
+
case "status":
|
|
4373
|
+
await cmdStatus();
|
|
4374
|
+
return;
|
|
4375
|
+
case "logs":
|
|
4376
|
+
await cmdLogs();
|
|
4377
|
+
return;
|
|
4378
|
+
case "tail":
|
|
4379
|
+
await cmdTail();
|
|
4380
|
+
return;
|
|
4353
4381
|
case "init":
|
|
4354
4382
|
cmdInit();
|
|
4355
4383
|
return;
|
|
4356
4384
|
case "doctor":
|
|
4357
4385
|
await cmdDoctor();
|
|
4358
4386
|
return;
|
|
4359
|
-
case "
|
|
4360
|
-
await
|
|
4387
|
+
case "uninstall":
|
|
4388
|
+
await cmdUninstall();
|
|
4361
4389
|
return;
|
|
4362
4390
|
case "print-config":
|
|
4363
4391
|
cmdPrintConfig();
|
|
4364
4392
|
return;
|
|
4393
|
+
// 内部命令:service 文件实际拉起的前台 daemon 进程,不对外暴露。
|
|
4394
|
+
case "__daemon":
|
|
4395
|
+
await cmdDaemon();
|
|
4396
|
+
return;
|
|
4365
4397
|
case "help":
|
|
4366
4398
|
case "--help":
|
|
4367
4399
|
case "-h":
|
|
@@ -4377,24 +4409,38 @@ async function main() {
|
|
|
4377
4409
|
async function cmdStart() {
|
|
4378
4410
|
if (!existsSync9(webRoot)) {
|
|
4379
4411
|
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
4380
|
-
console.error("\u8BF7\
|
|
4412
|
+
console.error("\u8BF7\u91CD\u65B0\u5B89\u88C5\u5B8C\u6574\u7684 npm \u5305\u3002");
|
|
4381
4413
|
process.exitCode = 1;
|
|
4382
4414
|
return;
|
|
4383
4415
|
}
|
|
4384
4416
|
const context = createServiceContext();
|
|
4385
|
-
const
|
|
4386
|
-
const
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4417
|
+
const status = await readServiceStatus(context).catch(() => null);
|
|
4418
|
+
const result = status?.installed ? await startService(context) : await installService(context);
|
|
4419
|
+
printServiceStatus("service started", result);
|
|
4420
|
+
}
|
|
4421
|
+
async function cmdStop() {
|
|
4422
|
+
const status = await stopService(createServiceContext());
|
|
4423
|
+
printServiceStatus("service stopped", status);
|
|
4424
|
+
}
|
|
4425
|
+
async function cmdRestart() {
|
|
4426
|
+
const status = await restartService(createServiceContext());
|
|
4427
|
+
printServiceStatus("service restarted", status);
|
|
4428
|
+
}
|
|
4429
|
+
async function cmdStatus() {
|
|
4430
|
+
const status = await readServiceStatus(createServiceContext());
|
|
4431
|
+
printServiceStatus("service status", status);
|
|
4432
|
+
}
|
|
4433
|
+
async function cmdLogs() {
|
|
4434
|
+
console.log(await readServiceLogs(createServiceContext()));
|
|
4435
|
+
}
|
|
4436
|
+
async function cmdTail() {
|
|
4437
|
+
await tailServiceLogs(createServiceContext());
|
|
4438
|
+
}
|
|
4439
|
+
async function cmdDaemon() {
|
|
4440
|
+
if (!existsSync9(webRoot)) {
|
|
4441
|
+
console.error(`\u627E\u4E0D\u5230\u524D\u7AEF\u6784\u5EFA\u4EA7\u7269: ${webRoot}`);
|
|
4442
|
+
process.exitCode = 1;
|
|
4443
|
+
return;
|
|
4398
4444
|
}
|
|
4399
4445
|
await startDaemon({
|
|
4400
4446
|
attachFrontend: attachStaticFrontend(webRoot)
|
|
@@ -4402,7 +4448,7 @@ async function cmdStart() {
|
|
|
4402
4448
|
}
|
|
4403
4449
|
function cmdInit() {
|
|
4404
4450
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
4405
|
-
const dir =
|
|
4451
|
+
const dir = dirname12(configPath);
|
|
4406
4452
|
mkdirSync6(dir, { recursive: true });
|
|
4407
4453
|
if (existsSync9(configPath)) {
|
|
4408
4454
|
console.log(`\u914D\u7F6E\u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6: ${configPath}`);
|
|
@@ -4452,54 +4498,9 @@ function cmdPrintConfig() {
|
|
|
4452
4498
|
}
|
|
4453
4499
|
console.log(readFileSync7(configPath, "utf8"));
|
|
4454
4500
|
}
|
|
4455
|
-
async function
|
|
4456
|
-
const
|
|
4457
|
-
|
|
4458
|
-
switch (action) {
|
|
4459
|
-
case "install": {
|
|
4460
|
-
const status = await installService(context);
|
|
4461
|
-
printServiceStatus("service installed", status);
|
|
4462
|
-
return;
|
|
4463
|
-
}
|
|
4464
|
-
case "start": {
|
|
4465
|
-
const status = await startService(context);
|
|
4466
|
-
printServiceStatus("service started", status);
|
|
4467
|
-
return;
|
|
4468
|
-
}
|
|
4469
|
-
case "stop": {
|
|
4470
|
-
const status = await stopService(context);
|
|
4471
|
-
printServiceStatus("service stopped", status);
|
|
4472
|
-
return;
|
|
4473
|
-
}
|
|
4474
|
-
case "restart": {
|
|
4475
|
-
const status = await restartService(context);
|
|
4476
|
-
printServiceStatus("service restarted", status);
|
|
4477
|
-
return;
|
|
4478
|
-
}
|
|
4479
|
-
case "logs": {
|
|
4480
|
-
console.log(await readServiceLogs(context));
|
|
4481
|
-
return;
|
|
4482
|
-
}
|
|
4483
|
-
case "tail": {
|
|
4484
|
-
await tailServiceLogs(context);
|
|
4485
|
-
return;
|
|
4486
|
-
}
|
|
4487
|
-
case "uninstall": {
|
|
4488
|
-
const status = await uninstallService(context);
|
|
4489
|
-
printServiceStatus("service uninstalled", status);
|
|
4490
|
-
return;
|
|
4491
|
-
}
|
|
4492
|
-
case "status": {
|
|
4493
|
-
const status = await readServiceStatus(context);
|
|
4494
|
-
printServiceStatus("service status", status);
|
|
4495
|
-
return;
|
|
4496
|
-
}
|
|
4497
|
-
default:
|
|
4498
|
-
console.error(`\u672A\u77E5 service \u5B50\u547D\u4EE4: ${action}
|
|
4499
|
-
`);
|
|
4500
|
-
printUsage();
|
|
4501
|
-
process.exitCode = 1;
|
|
4502
|
-
}
|
|
4501
|
+
async function cmdUninstall() {
|
|
4502
|
+
const status = await uninstallService(createServiceContext());
|
|
4503
|
+
printServiceStatus("service uninstalled", status);
|
|
4503
4504
|
}
|
|
4504
4505
|
function createServiceContext() {
|
|
4505
4506
|
return {
|
|
@@ -4530,18 +4531,20 @@ function printUsage() {
|
|
|
4530
4531
|
claude-codex-wechat <command>
|
|
4531
4532
|
|
|
4532
4533
|
\u547D\u4EE4:
|
|
4533
|
-
start \u542F\u52A8
|
|
4534
|
-
|
|
4534
|
+
start \u540E\u53F0\u542F\u52A8\u670D\u52A1\uFF08\u672A\u5B89\u88C5\u5219\u81EA\u52A8\u5B89\u88C5\uFF0C\u9ED8\u8BA4\u547D\u4EE4\uFF09
|
|
4535
|
+
stop \u505C\u6B62\u540E\u53F0\u670D\u52A1
|
|
4536
|
+
restart \u91CD\u542F\u540E\u53F0\u670D\u52A1
|
|
4537
|
+
status \u67E5\u770B\u8FD0\u884C\u72B6\u6001
|
|
4538
|
+
logs \u6253\u5370\u6700\u8FD1\u65E5\u5FD7
|
|
4539
|
+
tail \u5B9E\u65F6\u8DDF\u968F\u65E5\u5FD7
|
|
4535
4540
|
doctor \u68C0\u67E5\u914D\u7F6E\u3001\u524D\u7AEF\u4EA7\u7269\u4E0E claude/codex \u53EF\u6267\u884C\u6587\u4EF6
|
|
4536
|
-
|
|
4541
|
+
init \u5728 ~/.claude-codex-wechat/ \u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E
|
|
4542
|
+
uninstall \u5378\u8F7D\u540E\u53F0\u670D\u52A1
|
|
4537
4543
|
print-config \u6253\u5370\u5F53\u524D\u914D\u7F6E\u6587\u4EF6\u5185\u5BB9
|
|
4538
4544
|
help \u663E\u793A\u672C\u5E2E\u52A9
|
|
4539
4545
|
|
|
4540
4546
|
\u73AF\u5883\u53D8\u91CF:
|
|
4541
4547
|
BRIDGE_PORT \u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8787\uFF09
|
|
4542
|
-
BRIDGE_CONFIG \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.claude-codex-wechat/config.json\uFF09
|
|
4543
|
-
|
|
4544
|
-
\u5E38\u9A7B\u8FD0\u884C\u8BF7\u7528\u8FDB\u7A0B\u7BA1\u7406\u5668\u6258\u7BA1\uFF0C\u4F8B\u5982:
|
|
4545
|
-
pm2 start claude-codex-wechat -- start`);
|
|
4548
|
+
BRIDGE_CONFIG \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.claude-codex-wechat/config.json\uFF09`);
|
|
4546
4549
|
}
|
|
4547
4550
|
await main();
|