claude-codex-wechat 0.1.23 → 0.1.24
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/dist/server/cli.js +161 -108
- package/package.json +1 -1
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 existsSync10, readFileSync as readFileSync9 } from "node:fs";
|
|
6
|
-
import { dirname as
|
|
6
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
7
7
|
import { fileURLToPath as fileURLToPath2 } 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 dirname7, join as join11 } from "node:path";
|
|
16
16
|
import Fastify from "fastify";
|
|
17
17
|
|
|
18
18
|
// src/channels/platforms.ts
|
|
@@ -151,10 +151,76 @@ function normalizeWechatConfig(raw, env) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// src/daemon/configPersistence.ts
|
|
154
|
-
import {
|
|
154
|
+
import { readFile, rm } from "node:fs/promises";
|
|
155
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
156
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
157
|
+
|
|
158
|
+
// src/shared/atomicFile.ts
|
|
159
|
+
import { mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
160
|
+
import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
155
161
|
import { randomBytes } from "node:crypto";
|
|
156
|
-
import {
|
|
157
|
-
|
|
162
|
+
import { basename, dirname, join as join2 } from "node:path";
|
|
163
|
+
function tempPathFor(path) {
|
|
164
|
+
return join2(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
|
|
165
|
+
}
|
|
166
|
+
var RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
167
|
+
var MAX_RENAME_RETRIES = 10;
|
|
168
|
+
function isRetriableRenameError(error) {
|
|
169
|
+
if (process.platform !== "win32") return false;
|
|
170
|
+
const code = error?.code ?? "";
|
|
171
|
+
return RENAME_RETRY_CODES.has(code);
|
|
172
|
+
}
|
|
173
|
+
function sleepSync(ms) {
|
|
174
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
175
|
+
}
|
|
176
|
+
function sleep(ms) {
|
|
177
|
+
return new Promise((resolve2) => {
|
|
178
|
+
setTimeout(resolve2, ms);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function writeFileAtomicSync(path, data) {
|
|
182
|
+
const tmp = tempPathFor(path);
|
|
183
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
184
|
+
try {
|
|
185
|
+
writeFileSync(tmp, data, "utf8");
|
|
186
|
+
for (let attempt = 0; ; attempt++) {
|
|
187
|
+
try {
|
|
188
|
+
renameSync(tmp, path);
|
|
189
|
+
return;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (attempt >= MAX_RENAME_RETRIES || !isRetriableRenameError(error)) throw error;
|
|
192
|
+
sleepSync((attempt + 1) * 10);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
try {
|
|
197
|
+
unlinkSync(tmp);
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function writeFileAtomic(path, data) {
|
|
204
|
+
const tmp = tempPathFor(path);
|
|
205
|
+
await mkdir(dirname(path), { recursive: true });
|
|
206
|
+
try {
|
|
207
|
+
await writeFile(tmp, data, "utf8");
|
|
208
|
+
for (let attempt = 0; ; attempt++) {
|
|
209
|
+
try {
|
|
210
|
+
await rename(tmp, path);
|
|
211
|
+
return;
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (attempt >= MAX_RENAME_RETRIES || !isRetriableRenameError(error)) throw error;
|
|
214
|
+
await sleep((attempt + 1) * 10);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
await unlink(tmp).catch(() => void 0);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/daemon/configPersistence.ts
|
|
158
224
|
async function persistWechatCredentialsToConfigFile(input) {
|
|
159
225
|
const currentConfig = await readConfigFile(input.configPath);
|
|
160
226
|
const nextConfig = {
|
|
@@ -167,9 +233,8 @@ async function persistWechatCredentialsToConfigFile(input) {
|
|
|
167
233
|
accountId: input.accountId
|
|
168
234
|
}
|
|
169
235
|
};
|
|
170
|
-
await
|
|
171
|
-
|
|
172
|
-
`, "utf8");
|
|
236
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
237
|
+
`);
|
|
173
238
|
}
|
|
174
239
|
async function deleteConfigFile(configPath) {
|
|
175
240
|
try {
|
|
@@ -190,9 +255,8 @@ function persistUpdateStatusToConfigFile(input) {
|
|
|
190
255
|
...input.status.lastCheckedAt !== void 0 ? { lastCheckedAt: input.status.lastCheckedAt } : {}
|
|
191
256
|
}
|
|
192
257
|
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
`, "utf8");
|
|
258
|
+
writeFileAtomicSync(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
259
|
+
`);
|
|
196
260
|
}
|
|
197
261
|
async function persistBridgeDefaultsToConfigFile(input) {
|
|
198
262
|
const currentConfig = await readConfigFile(input.configPath);
|
|
@@ -215,9 +279,8 @@ async function persistBridgeDefaultsToConfigFile(input) {
|
|
|
215
279
|
}
|
|
216
280
|
} : {}
|
|
217
281
|
};
|
|
218
|
-
await
|
|
219
|
-
|
|
220
|
-
`, "utf8");
|
|
282
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
283
|
+
`);
|
|
221
284
|
}
|
|
222
285
|
function ensureRelayAuthTokenSync(input) {
|
|
223
286
|
const currentConfig = readConfigFileSync(input.configPath);
|
|
@@ -225,7 +288,7 @@ function ensureRelayAuthTokenSync(input) {
|
|
|
225
288
|
const currentRelay = isRecord(currentTunnel?.relay) ? currentTunnel.relay : void 0;
|
|
226
289
|
const existing = typeof currentRelay?.authToken === "string" && currentRelay.authToken.trim() ? currentRelay.authToken.trim() : "";
|
|
227
290
|
if (existing) return existing;
|
|
228
|
-
const authToken = `clrt_${
|
|
291
|
+
const authToken = `clrt_${randomBytes2(12).toString("hex")}`;
|
|
229
292
|
const nextConfig = {
|
|
230
293
|
...currentConfig,
|
|
231
294
|
tunnel: {
|
|
@@ -236,9 +299,8 @@ function ensureRelayAuthTokenSync(input) {
|
|
|
236
299
|
}
|
|
237
300
|
}
|
|
238
301
|
};
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
`, "utf8");
|
|
302
|
+
writeFileAtomicSync(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
303
|
+
`);
|
|
242
304
|
return authToken;
|
|
243
305
|
}
|
|
244
306
|
async function persistProviderCommandsToConfigFile(input) {
|
|
@@ -248,9 +310,8 @@ async function persistProviderCommandsToConfigFile(input) {
|
|
|
248
310
|
...currentConfig,
|
|
249
311
|
providers: normalizedProviders
|
|
250
312
|
};
|
|
251
|
-
await
|
|
252
|
-
|
|
253
|
-
`, "utf8");
|
|
313
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
314
|
+
`);
|
|
254
315
|
}
|
|
255
316
|
async function readConfigFile(path) {
|
|
256
317
|
try {
|
|
@@ -290,8 +351,7 @@ function normalizeProvidersForPersistence(providers) {
|
|
|
290
351
|
}
|
|
291
352
|
|
|
292
353
|
// src/channels/weixin-direct/weixinStateStore.ts
|
|
293
|
-
import { existsSync as existsSync3,
|
|
294
|
-
import { dirname as dirname2 } from "node:path";
|
|
354
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
295
355
|
var PUSH_QUOTA_LIMIT = 10;
|
|
296
356
|
var PUSH_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
297
357
|
var FileWeixinStateStore = class {
|
|
@@ -397,16 +457,15 @@ var FileWeixinStateStore = class {
|
|
|
397
457
|
...state,
|
|
398
458
|
bridge: { ...state.bridge ?? {}, weixinChannel: channel }
|
|
399
459
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
`, "utf8");
|
|
460
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(next, null, 2)}
|
|
461
|
+
`);
|
|
403
462
|
}
|
|
404
463
|
};
|
|
405
464
|
|
|
406
465
|
// src/providers/claude-code/nativeSessions.ts
|
|
407
466
|
import { appendFile, mkdir as mkdir2, readdir, readFile as readFile2, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
408
467
|
import { homedir as homedir2 } from "node:os";
|
|
409
|
-
import { basename, dirname as
|
|
468
|
+
import { basename as basename2, dirname as dirname2, join as join3 } from "node:path";
|
|
410
469
|
|
|
411
470
|
// src/session/sessionBridgeTag.ts
|
|
412
471
|
function buildSessionBridgeName(input) {
|
|
@@ -433,27 +492,27 @@ function parseSessionBridgeName(value) {
|
|
|
433
492
|
|
|
434
493
|
// src/providers/claude-code/nativeSessions.ts
|
|
435
494
|
function resolveClaudeConfigDir(env = process.env) {
|
|
436
|
-
return
|
|
495
|
+
return join3(env.HOME || homedir2(), ".claude");
|
|
437
496
|
}
|
|
438
497
|
async function listRecoverableClaudeSessions(env = process.env) {
|
|
439
|
-
const projectsDir =
|
|
498
|
+
const projectsDir = join3(resolveClaudeConfigDir(env), "projects");
|
|
440
499
|
const historyIndex = await readClaudeHistoryIndex(env);
|
|
441
500
|
const candidates = [];
|
|
442
501
|
try {
|
|
443
502
|
const projectEntries = await readdir(projectsDir, { withFileTypes: true });
|
|
444
503
|
for (const entry of projectEntries) {
|
|
445
504
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
446
|
-
const projectDir =
|
|
505
|
+
const projectDir = join3(projectsDir, String(entry.name));
|
|
447
506
|
const sessionEntries = await readdir(projectDir, { withFileTypes: true }).catch(() => []);
|
|
448
507
|
for (const sessionEntry of sessionEntries) {
|
|
449
508
|
if (!sessionEntry.isFile() || sessionEntry.isSymbolicLink()) continue;
|
|
450
509
|
const fileName = String(sessionEntry.name);
|
|
451
510
|
if (!fileName.endsWith(".jsonl")) continue;
|
|
452
|
-
const filePath =
|
|
511
|
+
const filePath = join3(projectDir, fileName);
|
|
453
512
|
const metadata = await stat(filePath).catch(() => null);
|
|
454
513
|
const parsedMeta = await readClaudeSessionMetadata(filePath).catch(() => null);
|
|
455
|
-
const historyMeta = historyIndex.get(
|
|
456
|
-
const sessionId =
|
|
514
|
+
const historyMeta = historyIndex.get(basename2(fileName, ".jsonl"));
|
|
515
|
+
const sessionId = basename2(fileName, ".jsonl");
|
|
457
516
|
const bridgeTag = historyMeta?.bridgeTag ?? parseSessionBridgeName(parsedMeta?.sessionName);
|
|
458
517
|
const cwd = parsedMeta?.cwd ?? historyMeta?.project;
|
|
459
518
|
candidates.push({
|
|
@@ -475,12 +534,12 @@ async function listRecoverableClaudeSessions(env = process.env) {
|
|
|
475
534
|
async function findRecoverableClaudeSessionPath(sessionId, env = process.env) {
|
|
476
535
|
const trimmed = sessionId.trim();
|
|
477
536
|
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\")) return null;
|
|
478
|
-
const projectsDir =
|
|
537
|
+
const projectsDir = join3(resolveClaudeConfigDir(env), "projects");
|
|
479
538
|
try {
|
|
480
539
|
const projectEntries = await readdir(projectsDir, { withFileTypes: true });
|
|
481
540
|
for (const entry of projectEntries) {
|
|
482
541
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
483
|
-
const sessionPath =
|
|
542
|
+
const sessionPath = join3(projectsDir, String(entry.name), `${trimmed}.jsonl`);
|
|
484
543
|
try {
|
|
485
544
|
const metadata = await stat(sessionPath);
|
|
486
545
|
if (metadata.isFile()) return sessionPath;
|
|
@@ -528,7 +587,7 @@ async function hasClaudeSessionBridgeMetadata(input) {
|
|
|
528
587
|
}
|
|
529
588
|
async function hasClaudeHistoryDisplay(input) {
|
|
530
589
|
const env = input.env ?? process.env;
|
|
531
|
-
const historyPath =
|
|
590
|
+
const historyPath = join3(resolveClaudeConfigDir(env), "history.jsonl");
|
|
532
591
|
try {
|
|
533
592
|
const content = await readFile2(historyPath, "utf8");
|
|
534
593
|
for (const line of content.split(/\r?\n/)) {
|
|
@@ -583,7 +642,7 @@ async function readClaudeSessionMetadata(filePath) {
|
|
|
583
642
|
return { aiTitle, lastPrompt, sessionName, cwd };
|
|
584
643
|
}
|
|
585
644
|
async function readClaudeHistoryIndex(env) {
|
|
586
|
-
const historyPath =
|
|
645
|
+
const historyPath = join3(resolveClaudeConfigDir(env), "history.jsonl");
|
|
587
646
|
const index = /* @__PURE__ */ new Map();
|
|
588
647
|
try {
|
|
589
648
|
const content = await readFile2(historyPath, "utf8");
|
|
@@ -608,7 +667,7 @@ async function readClaudeHistoryIndex(env) {
|
|
|
608
667
|
return index;
|
|
609
668
|
}
|
|
610
669
|
async function upsertClaudeHistoryDisplay(input) {
|
|
611
|
-
const historyPath =
|
|
670
|
+
const historyPath = join3(resolveClaudeConfigDir(input.env), "history.jsonl");
|
|
612
671
|
const lines = [];
|
|
613
672
|
let replaced = false;
|
|
614
673
|
let changed = false;
|
|
@@ -647,7 +706,7 @@ async function upsertClaudeHistoryDisplay(input) {
|
|
|
647
706
|
}));
|
|
648
707
|
}
|
|
649
708
|
if (!changed) return false;
|
|
650
|
-
await mkdir2(
|
|
709
|
+
await mkdir2(dirname2(historyPath), { recursive: true });
|
|
651
710
|
await writeFile2(historyPath, `${lines.join("\n")}
|
|
652
711
|
`, "utf8");
|
|
653
712
|
return true;
|
|
@@ -679,7 +738,7 @@ async function normalizeClaudeSessionFileForResume(sessionPath) {
|
|
|
679
738
|
nextLines.push(line);
|
|
680
739
|
}
|
|
681
740
|
if (sawSdkCliEntrypoint && !hasPermissionMode) {
|
|
682
|
-
const sessionId =
|
|
741
|
+
const sessionId = basename2(sessionPath, ".jsonl");
|
|
683
742
|
nextLines.unshift(JSON.stringify({
|
|
684
743
|
type: "permission-mode",
|
|
685
744
|
permissionMode: "bypassPermissions",
|
|
@@ -698,16 +757,16 @@ import Database from "better-sqlite3";
|
|
|
698
757
|
import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
699
758
|
import { existsSync as existsSync4 } from "node:fs";
|
|
700
759
|
import { homedir as homedir3 } from "node:os";
|
|
701
|
-
import { basename as
|
|
760
|
+
import { basename as basename3, join as join4 } from "node:path";
|
|
702
761
|
function resolveCodexSessionsRoot(env = process.env) {
|
|
703
|
-
return
|
|
762
|
+
return join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "sessions");
|
|
704
763
|
}
|
|
705
764
|
function isMatchingCodexRolloutFile(name) {
|
|
706
765
|
return name.startsWith("rollout-") && name.endsWith(".jsonl");
|
|
707
766
|
}
|
|
708
767
|
function extractCodexSessionId(name) {
|
|
709
768
|
if (!isMatchingCodexRolloutFile(name)) return null;
|
|
710
|
-
const withoutExt =
|
|
769
|
+
const withoutExt = basename3(name, ".jsonl");
|
|
711
770
|
const match = withoutExt.match(/^rollout-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-(.+)$/);
|
|
712
771
|
if (!match?.[1]) return null;
|
|
713
772
|
return match[1];
|
|
@@ -723,7 +782,7 @@ async function listRecoverableCodexSessions(env = process.env) {
|
|
|
723
782
|
for (const entry of entries) {
|
|
724
783
|
if (entry.isSymbolicLink()) continue;
|
|
725
784
|
const name = String(entry.name);
|
|
726
|
-
const path =
|
|
785
|
+
const path = join4(currentDir, name);
|
|
727
786
|
if (entry.isDirectory()) {
|
|
728
787
|
await walk(path, depth + 1);
|
|
729
788
|
continue;
|
|
@@ -759,7 +818,7 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
759
818
|
for (const entry of entries) {
|
|
760
819
|
if (entry.isSymbolicLink()) continue;
|
|
761
820
|
const name = String(entry.name);
|
|
762
|
-
const path =
|
|
821
|
+
const path = join4(currentDir, name);
|
|
763
822
|
if (entry.isDirectory()) {
|
|
764
823
|
const found = await walk(path, depth + 1);
|
|
765
824
|
if (found) return found;
|
|
@@ -773,7 +832,7 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
773
832
|
return await walk(root, 0);
|
|
774
833
|
}
|
|
775
834
|
async function readCodexSessionIndex(env) {
|
|
776
|
-
const indexPath =
|
|
835
|
+
const indexPath = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "session_index.jsonl");
|
|
777
836
|
const index = /* @__PURE__ */ new Map();
|
|
778
837
|
try {
|
|
779
838
|
const content = await readFile3(indexPath, "utf8");
|
|
@@ -796,7 +855,7 @@ async function readCodexSessionIndex(env) {
|
|
|
796
855
|
return index;
|
|
797
856
|
}
|
|
798
857
|
function readCodexThreadMetadata(env) {
|
|
799
|
-
const dbPath =
|
|
858
|
+
const dbPath = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "state_5.sqlite");
|
|
800
859
|
const metadata = /* @__PURE__ */ new Map();
|
|
801
860
|
if (!existsSync4(dbPath)) return metadata;
|
|
802
861
|
let db = null;
|
|
@@ -857,9 +916,9 @@ import { nanoid } from "nanoid";
|
|
|
857
916
|
// src/providers/codex/sessionIndex.ts
|
|
858
917
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
859
918
|
import { homedir as homedir4 } from "node:os";
|
|
860
|
-
import { dirname as
|
|
919
|
+
import { dirname as dirname3, join as join5 } from "node:path";
|
|
861
920
|
function resolveCodexIndexPath(env = process.env) {
|
|
862
|
-
return
|
|
921
|
+
return join5(env.CODEX_HOME || join5(env.HOME || homedir4(), ".codex"), "session_index.jsonl");
|
|
863
922
|
}
|
|
864
923
|
async function upsertCodexSessionIndexEntry(input, env = process.env) {
|
|
865
924
|
const indexPath = resolveCodexIndexPath(env);
|
|
@@ -895,7 +954,7 @@ async function upsertCodexSessionIndexEntry(input, env = process.env) {
|
|
|
895
954
|
updated_at: input.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
896
955
|
}));
|
|
897
956
|
}
|
|
898
|
-
await mkdir3(
|
|
957
|
+
await mkdir3(dirname3(indexPath), { recursive: true });
|
|
899
958
|
await writeFile3(indexPath, `${lines.join("\n")}
|
|
900
959
|
`, "utf8");
|
|
901
960
|
}
|
|
@@ -905,9 +964,9 @@ import Database2 from "better-sqlite3";
|
|
|
905
964
|
import { existsSync as existsSync5 } from "node:fs";
|
|
906
965
|
import { readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
907
966
|
import { homedir as homedir5 } from "node:os";
|
|
908
|
-
import { join as
|
|
967
|
+
import { join as join6 } from "node:path";
|
|
909
968
|
function resolveCodexStateDbPath(env = process.env) {
|
|
910
|
-
return
|
|
969
|
+
return join6(env.CODEX_HOME || join6(env.HOME || homedir5(), ".codex"), "state_5.sqlite");
|
|
911
970
|
}
|
|
912
971
|
async function syncCodexThreadForResume(input) {
|
|
913
972
|
const env = input.env ?? process.env;
|
|
@@ -1570,7 +1629,7 @@ function normalizeSettings(input, defaultWorkspace) {
|
|
|
1570
1629
|
// src/admin/fsBrowseRoutes.ts
|
|
1571
1630
|
import { readdir as readdir3 } from "node:fs/promises";
|
|
1572
1631
|
import { homedir as homedir7 } from "node:os";
|
|
1573
|
-
import { dirname as
|
|
1632
|
+
import { dirname as dirname4, join as join7, resolve } from "node:path";
|
|
1574
1633
|
|
|
1575
1634
|
// src/shared/expandTilde.ts
|
|
1576
1635
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -1596,8 +1655,8 @@ function registerFsBrowseRoutes(input) {
|
|
|
1596
1655
|
reply.code(400);
|
|
1597
1656
|
return { error: "cannot_read_directory", path: target };
|
|
1598
1657
|
}
|
|
1599
|
-
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path:
|
|
1600
|
-
const parent =
|
|
1658
|
+
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path: join7(target, dirent.name), isDirectory: true })).filter((entry) => !entry.name.startsWith(".") || isOnKeepChain(entry.path)).sort((a, b) => a.name.localeCompare(b.name));
|
|
1659
|
+
const parent = dirname4(target);
|
|
1601
1660
|
const isRoot = parent === target;
|
|
1602
1661
|
const listing = {
|
|
1603
1662
|
path: target,
|
|
@@ -1778,7 +1837,7 @@ var WeixinDirectApiClient = class {
|
|
|
1778
1837
|
|
|
1779
1838
|
// src/channels/weixin-direct/adapter.ts
|
|
1780
1839
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
1781
|
-
import { join as
|
|
1840
|
+
import { join as join8 } from "node:path";
|
|
1782
1841
|
|
|
1783
1842
|
// src/channels/weixin-direct/typingController.ts
|
|
1784
1843
|
var CONFIG_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2043,7 +2102,7 @@ var WeixinDirectAdapter = class _WeixinDirectAdapter {
|
|
|
2043
2102
|
continue;
|
|
2044
2103
|
}
|
|
2045
2104
|
const { ext, mimeType } = mediaExtAndMime(meta);
|
|
2046
|
-
const destPath =
|
|
2105
|
+
const destPath = join8(mediaDir, `${idPrefix}_${i}${ext}`);
|
|
2047
2106
|
const maxBytes = meta.kind === "video" ? VIDEO_MAX_BYTES : void 0;
|
|
2048
2107
|
const result = await downloader.download(meta.media ?? {}, { destPath, aeskeyOverride: meta.aeskey, maxBytes });
|
|
2049
2108
|
if (result.ok) {
|
|
@@ -2103,8 +2162,8 @@ function chunkText(text, limit) {
|
|
|
2103
2162
|
}
|
|
2104
2163
|
|
|
2105
2164
|
// src/channels/weixin-direct/mediaDownloader.ts
|
|
2106
|
-
import { mkdirSync as
|
|
2107
|
-
import { dirname as
|
|
2165
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2166
|
+
import { dirname as dirname5 } from "node:path";
|
|
2108
2167
|
|
|
2109
2168
|
// src/channels/weixin-direct/mediaCrypto.ts
|
|
2110
2169
|
import { createDecipheriv } from "node:crypto";
|
|
@@ -2167,8 +2226,8 @@ var WeixinMediaDownloader = class {
|
|
|
2167
2226
|
} catch {
|
|
2168
2227
|
return { ok: false, reason: "decrypt_failed" };
|
|
2169
2228
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2229
|
+
mkdirSync2(dirname5(input.destPath), { recursive: true });
|
|
2230
|
+
writeFileSync2(input.destPath, plaintext);
|
|
2172
2231
|
return { ok: true, localPath: input.destPath, bytes: plaintext.length };
|
|
2173
2232
|
}
|
|
2174
2233
|
};
|
|
@@ -2354,7 +2413,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
2354
2413
|
|
|
2355
2414
|
// src/shared/platform.ts
|
|
2356
2415
|
import { access, constants } from "node:fs/promises";
|
|
2357
|
-
import { delimiter, join as
|
|
2416
|
+
import { delimiter, join as join9 } from "node:path";
|
|
2358
2417
|
import { tmpdir } from "node:os";
|
|
2359
2418
|
import { spawn } from "node:child_process";
|
|
2360
2419
|
var isWindows = process.platform === "win32";
|
|
@@ -2382,7 +2441,7 @@ async function findExecutable(command) {
|
|
|
2382
2441
|
const dirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
2383
2442
|
for (const dir of dirs) {
|
|
2384
2443
|
for (const ext of extensions) {
|
|
2385
|
-
const candidate =
|
|
2444
|
+
const candidate = join9(dir, command + ext);
|
|
2386
2445
|
if (await isExecutableFile(candidate)) return candidate;
|
|
2387
2446
|
}
|
|
2388
2447
|
}
|
|
@@ -2405,13 +2464,13 @@ function terminateChild(child, signal = "SIGTERM") {
|
|
|
2405
2464
|
}
|
|
2406
2465
|
}
|
|
2407
2466
|
function defaultWorkspaceDir() {
|
|
2408
|
-
return
|
|
2467
|
+
return join9(tmpdir(), "project");
|
|
2409
2468
|
}
|
|
2410
2469
|
function useShellForCli() {
|
|
2411
2470
|
return isWindows;
|
|
2412
2471
|
}
|
|
2413
2472
|
function statePath(filename) {
|
|
2414
|
-
return
|
|
2473
|
+
return join9(tmpdir(), filename);
|
|
2415
2474
|
}
|
|
2416
2475
|
|
|
2417
2476
|
// src/providers/claude-code/assistantContent.ts
|
|
@@ -3399,8 +3458,7 @@ function buildBridgeCommandHelpMarkdown(input) {
|
|
|
3399
3458
|
}
|
|
3400
3459
|
|
|
3401
3460
|
// src/session/currentConversationStore.ts
|
|
3402
|
-
import { existsSync as existsSync6,
|
|
3403
|
-
import { dirname as dirname7 } from "node:path";
|
|
3461
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
|
|
3404
3462
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3405
3463
|
var CurrentConversationStore = class {
|
|
3406
3464
|
constructor(configPath, defaults) {
|
|
@@ -3482,9 +3540,8 @@ var CurrentConversationStore = class {
|
|
|
3482
3540
|
this.writeState(state);
|
|
3483
3541
|
}
|
|
3484
3542
|
writeState(state) {
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
`, "utf8");
|
|
3543
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
3544
|
+
`);
|
|
3488
3545
|
}
|
|
3489
3546
|
};
|
|
3490
3547
|
|
|
@@ -4017,8 +4074,7 @@ function composeInboundText(content) {
|
|
|
4017
4074
|
}
|
|
4018
4075
|
|
|
4019
4076
|
// src/storage/lastProviderSessionStore.ts
|
|
4020
|
-
import { existsSync as existsSync7,
|
|
4021
|
-
import { dirname as dirname8 } from "node:path";
|
|
4077
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
4022
4078
|
var LastProviderSessionStore = class {
|
|
4023
4079
|
constructor(configPath) {
|
|
4024
4080
|
this.configPath = configPath;
|
|
@@ -4049,15 +4105,13 @@ var LastProviderSessionStore = class {
|
|
|
4049
4105
|
return raw && typeof raw === "object" ? raw : {};
|
|
4050
4106
|
}
|
|
4051
4107
|
writeState(state) {
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
`, "utf8");
|
|
4108
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
4109
|
+
`);
|
|
4055
4110
|
}
|
|
4056
4111
|
};
|
|
4057
4112
|
|
|
4058
4113
|
// src/storage/runtimeUserStore.ts
|
|
4059
|
-
import {
|
|
4060
|
-
import { dirname as dirname9 } from "node:path";
|
|
4114
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "node:fs";
|
|
4061
4115
|
import { nanoid as nanoid3 } from "nanoid";
|
|
4062
4116
|
var RuntimeUserStore = class {
|
|
4063
4117
|
constructor(configPath) {
|
|
@@ -4122,9 +4176,8 @@ var RuntimeUserStore = class {
|
|
|
4122
4176
|
return raw && typeof raw === "object" ? raw : {};
|
|
4123
4177
|
}
|
|
4124
4178
|
writeState(state) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
`, "utf8");
|
|
4179
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
4180
|
+
`);
|
|
4128
4181
|
}
|
|
4129
4182
|
};
|
|
4130
4183
|
|
|
@@ -4452,12 +4505,12 @@ var RelayTunnelRouter = class {
|
|
|
4452
4505
|
|
|
4453
4506
|
// src/shared/version.ts
|
|
4454
4507
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
4455
|
-
import { dirname as
|
|
4508
|
+
import { dirname as dirname6, join as join10 } from "node:path";
|
|
4456
4509
|
import { fileURLToPath } from "node:url";
|
|
4457
4510
|
function readClientVersion() {
|
|
4458
4511
|
try {
|
|
4459
|
-
const here2 =
|
|
4460
|
-
const pkg = JSON.parse(readFileSync7(
|
|
4512
|
+
const here2 = dirname6(fileURLToPath(import.meta.url));
|
|
4513
|
+
const pkg = JSON.parse(readFileSync7(join10(here2, "..", "..", "package.json"), "utf8"));
|
|
4461
4514
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
4462
4515
|
} catch {
|
|
4463
4516
|
return "0.0.0";
|
|
@@ -4476,7 +4529,7 @@ function readUpdateStatusBestEffort(configPath) {
|
|
|
4476
4529
|
function createDaemonServer(options = {}) {
|
|
4477
4530
|
const app = Fastify({ logger: true });
|
|
4478
4531
|
const events = new BridgeEventHub();
|
|
4479
|
-
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ??
|
|
4532
|
+
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join11(mkdtempSync(join11(tmpdir2(), "claude-codex-wechat-")), "config.json");
|
|
4480
4533
|
const persistedConfig = loadBridgeConfig(configPath);
|
|
4481
4534
|
const bridgeDefaults = {
|
|
4482
4535
|
defaultProvider: options.bridgeDefaults?.defaultProvider ?? persistedConfig.bridge?.defaultProvider ?? "claude-code",
|
|
@@ -4533,7 +4586,7 @@ function createDaemonServer(options = {}) {
|
|
|
4533
4586
|
});
|
|
4534
4587
|
}
|
|
4535
4588
|
const weixinStateStore = configPath ? new FileWeixinStateStore(configPath) : void 0;
|
|
4536
|
-
const weixinMediaDir = configPath ?
|
|
4589
|
+
const weixinMediaDir = configPath ? join11(dirname7(configPath), "media") : void 0;
|
|
4537
4590
|
const managedWechatChannel = options.channel ? null : new ManagedWeixinDirectAdapter(options.wechat, weixinStateStore, weixinMediaDir);
|
|
4538
4591
|
const channel = options.channel ?? managedWechatChannel;
|
|
4539
4592
|
const weixinOutboundGate = managedWechatChannel && weixinStateStore ? new WeixinOutboundGate({
|
|
@@ -4824,7 +4877,7 @@ async function resolveProviderCommands(providers) {
|
|
|
4824
4877
|
|
|
4825
4878
|
// src/daemon/staticFrontend.ts
|
|
4826
4879
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
4827
|
-
import { join as
|
|
4880
|
+
import { join as join12 } from "node:path";
|
|
4828
4881
|
import fastifyStatic from "@fastify/static";
|
|
4829
4882
|
function attachStaticFrontend(webRoot2) {
|
|
4830
4883
|
return async (app) => {
|
|
@@ -4832,7 +4885,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4832
4885
|
root: webRoot2,
|
|
4833
4886
|
wildcard: false
|
|
4834
4887
|
});
|
|
4835
|
-
const indexHtml = readFileSync8(
|
|
4888
|
+
const indexHtml = readFileSync8(join12(webRoot2, "index.html"), "utf8");
|
|
4836
4889
|
app.setNotFoundHandler((request, reply) => {
|
|
4837
4890
|
if (request.url.startsWith("/api")) {
|
|
4838
4891
|
reply.code(404).send({ error: "not_found" });
|
|
@@ -4847,7 +4900,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4847
4900
|
import { existsSync as existsSync9, statSync, openSync, closeSync, watchFile } from "node:fs";
|
|
4848
4901
|
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
4849
4902
|
import { homedir as homedir8 } from "node:os";
|
|
4850
|
-
import { dirname as
|
|
4903
|
+
import { dirname as dirname8, join as join13 } from "node:path";
|
|
4851
4904
|
import { createReadStream } from "node:fs";
|
|
4852
4905
|
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
4853
4906
|
import { createInterface } from "node:readline";
|
|
@@ -4856,8 +4909,8 @@ var execFileAsync = promisify(execFile);
|
|
|
4856
4909
|
async function installService(context) {
|
|
4857
4910
|
if (process.platform === "darwin") {
|
|
4858
4911
|
const spec = buildLaunchdSpec(context);
|
|
4859
|
-
await mkdir4(
|
|
4860
|
-
await mkdir4(
|
|
4912
|
+
await mkdir4(dirname8(spec.plistPath), { recursive: true });
|
|
4913
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
4861
4914
|
await writeFile5(spec.plistPath, renderLaunchdPlist(spec), "utf8");
|
|
4862
4915
|
await runLaunchctl(["unload", spec.plistPath]).catch(() => void 0);
|
|
4863
4916
|
await runLaunchctl(["load", spec.plistPath]);
|
|
@@ -4866,8 +4919,8 @@ async function installService(context) {
|
|
|
4866
4919
|
}
|
|
4867
4920
|
if (process.platform === "linux") {
|
|
4868
4921
|
const spec = buildSystemdUserSpec(context);
|
|
4869
|
-
await mkdir4(
|
|
4870
|
-
await mkdir4(
|
|
4922
|
+
await mkdir4(dirname8(spec.unitPath), { recursive: true });
|
|
4923
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
4871
4924
|
await writeFile5(spec.unitPath, renderSystemdUnit(spec), "utf8");
|
|
4872
4925
|
await runSystemctl(["--user", "daemon-reload"]);
|
|
4873
4926
|
await runSystemctl(["--user", "enable", "--now", spec.unitName]);
|
|
@@ -5034,37 +5087,37 @@ async function readServiceStatus(context) {
|
|
|
5034
5087
|
throw new Error("service_status_not_supported_on_this_platform");
|
|
5035
5088
|
}
|
|
5036
5089
|
function buildLaunchdSpec(context) {
|
|
5037
|
-
const stateDir =
|
|
5090
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5038
5091
|
return {
|
|
5039
5092
|
label: "com.claude-codex-wechat",
|
|
5040
|
-
plistPath:
|
|
5093
|
+
plistPath: join13(homedir8(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
|
|
5041
5094
|
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5042
5095
|
workingDirectory: homedir8(),
|
|
5043
|
-
stdoutPath:
|
|
5044
|
-
stderrPath:
|
|
5096
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5097
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5045
5098
|
environment: buildServiceEnvironment(context)
|
|
5046
5099
|
};
|
|
5047
5100
|
}
|
|
5048
5101
|
function buildSystemdUserSpec(context) {
|
|
5049
|
-
const stateDir =
|
|
5102
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5050
5103
|
return {
|
|
5051
5104
|
unitName: "claude-codex-wechat.service",
|
|
5052
|
-
unitPath:
|
|
5105
|
+
unitPath: join13(homedir8(), ".config", "systemd", "user", "claude-codex-wechat.service"),
|
|
5053
5106
|
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5054
5107
|
workingDirectory: homedir8(),
|
|
5055
|
-
stdoutPath:
|
|
5056
|
-
stderrPath:
|
|
5108
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5109
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5057
5110
|
environment: buildServiceEnvironment(context)
|
|
5058
5111
|
};
|
|
5059
5112
|
}
|
|
5060
5113
|
function buildProcessSpec(context) {
|
|
5061
|
-
const stateDir =
|
|
5114
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5062
5115
|
return {
|
|
5063
|
-
pidPath:
|
|
5116
|
+
pidPath: join13(stateDir, "service.pid"),
|
|
5064
5117
|
command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5065
5118
|
workingDirectory: homedir8(),
|
|
5066
|
-
stdoutPath:
|
|
5067
|
-
stderrPath:
|
|
5119
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5120
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5068
5121
|
environment: buildServiceEnvironment(context)
|
|
5069
5122
|
};
|
|
5070
5123
|
}
|
|
@@ -5185,7 +5238,7 @@ async function readPidFile(pidPath) {
|
|
|
5185
5238
|
}
|
|
5186
5239
|
}
|
|
5187
5240
|
async function writePidFile(pidPath, pid) {
|
|
5188
|
-
await mkdir4(
|
|
5241
|
+
await mkdir4(dirname8(pidPath), { recursive: true });
|
|
5189
5242
|
await writeFile5(pidPath, `${pid}
|
|
5190
5243
|
`, "utf8");
|
|
5191
5244
|
}
|
|
@@ -5200,7 +5253,7 @@ async function killPid(pid) {
|
|
|
5200
5253
|
process.kill(pid, "SIGTERM");
|
|
5201
5254
|
}
|
|
5202
5255
|
async function spawnDetachedDaemon(spec) {
|
|
5203
|
-
await mkdir4(
|
|
5256
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
5204
5257
|
const outFd = openSync(spec.stdoutPath, "a");
|
|
5205
5258
|
const errFd = openSync(spec.stderrPath, "a");
|
|
5206
5259
|
try {
|
|
@@ -5286,8 +5339,8 @@ function fileSizeHint(path) {
|
|
|
5286
5339
|
}
|
|
5287
5340
|
|
|
5288
5341
|
// src/cli.ts
|
|
5289
|
-
var here =
|
|
5290
|
-
var webRoot =
|
|
5342
|
+
var here = dirname9(fileURLToPath2(import.meta.url));
|
|
5343
|
+
var webRoot = join14(here, "..", "web");
|
|
5291
5344
|
async function main() {
|
|
5292
5345
|
const command = process.argv[2];
|
|
5293
5346
|
switch (command) {
|