claude-codex-wechat 0.1.23 → 0.1.25
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 +232 -142
- 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,109 @@ 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 { closeSync, fsyncSync, mkdirSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
160
|
+
import { mkdir, open, readdir, rename, stat, unlink } 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
|
+
var FILE_MODE = 384;
|
|
164
|
+
function tempPathFor(path) {
|
|
165
|
+
return join2(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
|
|
166
|
+
}
|
|
167
|
+
var RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
168
|
+
var MAX_RENAME_RETRIES = 10;
|
|
169
|
+
function isRetriableRenameError(error) {
|
|
170
|
+
if (process.platform !== "win32") return false;
|
|
171
|
+
const code = error?.code ?? "";
|
|
172
|
+
return RENAME_RETRY_CODES.has(code);
|
|
173
|
+
}
|
|
174
|
+
function sleepSync(ms) {
|
|
175
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
176
|
+
}
|
|
177
|
+
function sleep(ms) {
|
|
178
|
+
return new Promise((resolve2) => {
|
|
179
|
+
setTimeout(resolve2, ms);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function writeFileAtomicSync(path, data) {
|
|
183
|
+
const tmp = tempPathFor(path);
|
|
184
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
185
|
+
try {
|
|
186
|
+
const fd = openSync(tmp, "w", FILE_MODE);
|
|
187
|
+
try {
|
|
188
|
+
writeSync(fd, data, null, "utf8");
|
|
189
|
+
fsyncSync(fd);
|
|
190
|
+
} finally {
|
|
191
|
+
closeSync(fd);
|
|
192
|
+
}
|
|
193
|
+
for (let attempt = 0; ; attempt++) {
|
|
194
|
+
try {
|
|
195
|
+
renameSync(tmp, path);
|
|
196
|
+
return;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (attempt >= MAX_RENAME_RETRIES || !isRetriableRenameError(error)) throw error;
|
|
199
|
+
sleepSync((attempt + 1) * 10);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
try {
|
|
204
|
+
unlinkSync(tmp);
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function writeFileAtomic(path, data) {
|
|
211
|
+
const tmp = tempPathFor(path);
|
|
212
|
+
await mkdir(dirname(path), { recursive: true });
|
|
213
|
+
try {
|
|
214
|
+
const handle = await open(tmp, "w", FILE_MODE);
|
|
215
|
+
try {
|
|
216
|
+
await handle.writeFile(data, "utf8");
|
|
217
|
+
await handle.sync();
|
|
218
|
+
} finally {
|
|
219
|
+
await handle.close();
|
|
220
|
+
}
|
|
221
|
+
for (let attempt = 0; ; attempt++) {
|
|
222
|
+
try {
|
|
223
|
+
await rename(tmp, path);
|
|
224
|
+
return;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (attempt >= MAX_RENAME_RETRIES || !isRetriableRenameError(error)) throw error;
|
|
227
|
+
await sleep((attempt + 1) * 10);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch (error) {
|
|
231
|
+
await unlink(tmp).catch(() => void 0);
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async function cleanupStaleTempFiles(targetPath, maxAgeMs = 36e5) {
|
|
236
|
+
const dir = dirname(targetPath);
|
|
237
|
+
const prefix = `.${basename(targetPath)}.`;
|
|
238
|
+
let entries;
|
|
239
|
+
try {
|
|
240
|
+
entries = await readdir(dir);
|
|
241
|
+
} catch {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const now = Date.now();
|
|
245
|
+
await Promise.all(entries.map(async (name) => {
|
|
246
|
+
if (!name.startsWith(prefix) || !name.endsWith(".tmp")) return;
|
|
247
|
+
const full = join2(dir, name);
|
|
248
|
+
try {
|
|
249
|
+
const info = await stat(full);
|
|
250
|
+
if (now - info.mtimeMs >= maxAgeMs) await unlink(full);
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// src/daemon/configPersistence.ts
|
|
158
257
|
async function persistWechatCredentialsToConfigFile(input) {
|
|
159
258
|
const currentConfig = await readConfigFile(input.configPath);
|
|
160
259
|
const nextConfig = {
|
|
@@ -167,9 +266,8 @@ async function persistWechatCredentialsToConfigFile(input) {
|
|
|
167
266
|
accountId: input.accountId
|
|
168
267
|
}
|
|
169
268
|
};
|
|
170
|
-
await
|
|
171
|
-
|
|
172
|
-
`, "utf8");
|
|
269
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
270
|
+
`);
|
|
173
271
|
}
|
|
174
272
|
async function deleteConfigFile(configPath) {
|
|
175
273
|
try {
|
|
@@ -190,9 +288,8 @@ function persistUpdateStatusToConfigFile(input) {
|
|
|
190
288
|
...input.status.lastCheckedAt !== void 0 ? { lastCheckedAt: input.status.lastCheckedAt } : {}
|
|
191
289
|
}
|
|
192
290
|
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
`, "utf8");
|
|
291
|
+
writeFileAtomicSync(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
292
|
+
`);
|
|
196
293
|
}
|
|
197
294
|
async function persistBridgeDefaultsToConfigFile(input) {
|
|
198
295
|
const currentConfig = await readConfigFile(input.configPath);
|
|
@@ -215,9 +312,8 @@ async function persistBridgeDefaultsToConfigFile(input) {
|
|
|
215
312
|
}
|
|
216
313
|
} : {}
|
|
217
314
|
};
|
|
218
|
-
await
|
|
219
|
-
|
|
220
|
-
`, "utf8");
|
|
315
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
316
|
+
`);
|
|
221
317
|
}
|
|
222
318
|
function ensureRelayAuthTokenSync(input) {
|
|
223
319
|
const currentConfig = readConfigFileSync(input.configPath);
|
|
@@ -225,7 +321,7 @@ function ensureRelayAuthTokenSync(input) {
|
|
|
225
321
|
const currentRelay = isRecord(currentTunnel?.relay) ? currentTunnel.relay : void 0;
|
|
226
322
|
const existing = typeof currentRelay?.authToken === "string" && currentRelay.authToken.trim() ? currentRelay.authToken.trim() : "";
|
|
227
323
|
if (existing) return existing;
|
|
228
|
-
const authToken = `clrt_${
|
|
324
|
+
const authToken = `clrt_${randomBytes2(12).toString("hex")}`;
|
|
229
325
|
const nextConfig = {
|
|
230
326
|
...currentConfig,
|
|
231
327
|
tunnel: {
|
|
@@ -236,9 +332,8 @@ function ensureRelayAuthTokenSync(input) {
|
|
|
236
332
|
}
|
|
237
333
|
}
|
|
238
334
|
};
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
`, "utf8");
|
|
335
|
+
writeFileAtomicSync(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
336
|
+
`);
|
|
242
337
|
return authToken;
|
|
243
338
|
}
|
|
244
339
|
async function persistProviderCommandsToConfigFile(input) {
|
|
@@ -248,9 +343,8 @@ async function persistProviderCommandsToConfigFile(input) {
|
|
|
248
343
|
...currentConfig,
|
|
249
344
|
providers: normalizedProviders
|
|
250
345
|
};
|
|
251
|
-
await
|
|
252
|
-
|
|
253
|
-
`, "utf8");
|
|
346
|
+
await writeFileAtomic(input.configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
347
|
+
`);
|
|
254
348
|
}
|
|
255
349
|
async function readConfigFile(path) {
|
|
256
350
|
try {
|
|
@@ -290,8 +384,7 @@ function normalizeProvidersForPersistence(providers) {
|
|
|
290
384
|
}
|
|
291
385
|
|
|
292
386
|
// src/channels/weixin-direct/weixinStateStore.ts
|
|
293
|
-
import { existsSync as existsSync3,
|
|
294
|
-
import { dirname as dirname2 } from "node:path";
|
|
387
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
295
388
|
var PUSH_QUOTA_LIMIT = 10;
|
|
296
389
|
var PUSH_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
297
390
|
var FileWeixinStateStore = class {
|
|
@@ -397,16 +490,15 @@ var FileWeixinStateStore = class {
|
|
|
397
490
|
...state,
|
|
398
491
|
bridge: { ...state.bridge ?? {}, weixinChannel: channel }
|
|
399
492
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
`, "utf8");
|
|
493
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(next, null, 2)}
|
|
494
|
+
`);
|
|
403
495
|
}
|
|
404
496
|
};
|
|
405
497
|
|
|
406
498
|
// src/providers/claude-code/nativeSessions.ts
|
|
407
|
-
import { appendFile, mkdir as mkdir2, readdir, readFile as readFile2, stat, writeFile
|
|
499
|
+
import { appendFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile2, stat as stat2, writeFile } from "node:fs/promises";
|
|
408
500
|
import { homedir as homedir2 } from "node:os";
|
|
409
|
-
import { basename, dirname as
|
|
501
|
+
import { basename as basename2, dirname as dirname2, join as join3 } from "node:path";
|
|
410
502
|
|
|
411
503
|
// src/session/sessionBridgeTag.ts
|
|
412
504
|
function buildSessionBridgeName(input) {
|
|
@@ -433,27 +525,27 @@ function parseSessionBridgeName(value) {
|
|
|
433
525
|
|
|
434
526
|
// src/providers/claude-code/nativeSessions.ts
|
|
435
527
|
function resolveClaudeConfigDir(env = process.env) {
|
|
436
|
-
return
|
|
528
|
+
return join3(env.HOME || homedir2(), ".claude");
|
|
437
529
|
}
|
|
438
530
|
async function listRecoverableClaudeSessions(env = process.env) {
|
|
439
|
-
const projectsDir =
|
|
531
|
+
const projectsDir = join3(resolveClaudeConfigDir(env), "projects");
|
|
440
532
|
const historyIndex = await readClaudeHistoryIndex(env);
|
|
441
533
|
const candidates = [];
|
|
442
534
|
try {
|
|
443
|
-
const projectEntries = await
|
|
535
|
+
const projectEntries = await readdir2(projectsDir, { withFileTypes: true });
|
|
444
536
|
for (const entry of projectEntries) {
|
|
445
537
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
446
|
-
const projectDir =
|
|
447
|
-
const sessionEntries = await
|
|
538
|
+
const projectDir = join3(projectsDir, String(entry.name));
|
|
539
|
+
const sessionEntries = await readdir2(projectDir, { withFileTypes: true }).catch(() => []);
|
|
448
540
|
for (const sessionEntry of sessionEntries) {
|
|
449
541
|
if (!sessionEntry.isFile() || sessionEntry.isSymbolicLink()) continue;
|
|
450
542
|
const fileName = String(sessionEntry.name);
|
|
451
543
|
if (!fileName.endsWith(".jsonl")) continue;
|
|
452
|
-
const filePath =
|
|
453
|
-
const metadata = await
|
|
544
|
+
const filePath = join3(projectDir, fileName);
|
|
545
|
+
const metadata = await stat2(filePath).catch(() => null);
|
|
454
546
|
const parsedMeta = await readClaudeSessionMetadata(filePath).catch(() => null);
|
|
455
|
-
const historyMeta = historyIndex.get(
|
|
456
|
-
const sessionId =
|
|
547
|
+
const historyMeta = historyIndex.get(basename2(fileName, ".jsonl"));
|
|
548
|
+
const sessionId = basename2(fileName, ".jsonl");
|
|
457
549
|
const bridgeTag = historyMeta?.bridgeTag ?? parseSessionBridgeName(parsedMeta?.sessionName);
|
|
458
550
|
const cwd = parsedMeta?.cwd ?? historyMeta?.project;
|
|
459
551
|
candidates.push({
|
|
@@ -475,14 +567,14 @@ async function listRecoverableClaudeSessions(env = process.env) {
|
|
|
475
567
|
async function findRecoverableClaudeSessionPath(sessionId, env = process.env) {
|
|
476
568
|
const trimmed = sessionId.trim();
|
|
477
569
|
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\")) return null;
|
|
478
|
-
const projectsDir =
|
|
570
|
+
const projectsDir = join3(resolveClaudeConfigDir(env), "projects");
|
|
479
571
|
try {
|
|
480
|
-
const projectEntries = await
|
|
572
|
+
const projectEntries = await readdir2(projectsDir, { withFileTypes: true });
|
|
481
573
|
for (const entry of projectEntries) {
|
|
482
574
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
483
|
-
const sessionPath =
|
|
575
|
+
const sessionPath = join3(projectsDir, String(entry.name), `${trimmed}.jsonl`);
|
|
484
576
|
try {
|
|
485
|
-
const metadata = await
|
|
577
|
+
const metadata = await stat2(sessionPath);
|
|
486
578
|
if (metadata.isFile()) return sessionPath;
|
|
487
579
|
} catch {
|
|
488
580
|
}
|
|
@@ -528,7 +620,7 @@ async function hasClaudeSessionBridgeMetadata(input) {
|
|
|
528
620
|
}
|
|
529
621
|
async function hasClaudeHistoryDisplay(input) {
|
|
530
622
|
const env = input.env ?? process.env;
|
|
531
|
-
const historyPath =
|
|
623
|
+
const historyPath = join3(resolveClaudeConfigDir(env), "history.jsonl");
|
|
532
624
|
try {
|
|
533
625
|
const content = await readFile2(historyPath, "utf8");
|
|
534
626
|
for (const line of content.split(/\r?\n/)) {
|
|
@@ -583,7 +675,7 @@ async function readClaudeSessionMetadata(filePath) {
|
|
|
583
675
|
return { aiTitle, lastPrompt, sessionName, cwd };
|
|
584
676
|
}
|
|
585
677
|
async function readClaudeHistoryIndex(env) {
|
|
586
|
-
const historyPath =
|
|
678
|
+
const historyPath = join3(resolveClaudeConfigDir(env), "history.jsonl");
|
|
587
679
|
const index = /* @__PURE__ */ new Map();
|
|
588
680
|
try {
|
|
589
681
|
const content = await readFile2(historyPath, "utf8");
|
|
@@ -608,7 +700,7 @@ async function readClaudeHistoryIndex(env) {
|
|
|
608
700
|
return index;
|
|
609
701
|
}
|
|
610
702
|
async function upsertClaudeHistoryDisplay(input) {
|
|
611
|
-
const historyPath =
|
|
703
|
+
const historyPath = join3(resolveClaudeConfigDir(input.env), "history.jsonl");
|
|
612
704
|
const lines = [];
|
|
613
705
|
let replaced = false;
|
|
614
706
|
let changed = false;
|
|
@@ -647,8 +739,8 @@ async function upsertClaudeHistoryDisplay(input) {
|
|
|
647
739
|
}));
|
|
648
740
|
}
|
|
649
741
|
if (!changed) return false;
|
|
650
|
-
await mkdir2(
|
|
651
|
-
await
|
|
742
|
+
await mkdir2(dirname2(historyPath), { recursive: true });
|
|
743
|
+
await writeFile(historyPath, `${lines.join("\n")}
|
|
652
744
|
`, "utf8");
|
|
653
745
|
return true;
|
|
654
746
|
}
|
|
@@ -679,7 +771,7 @@ async function normalizeClaudeSessionFileForResume(sessionPath) {
|
|
|
679
771
|
nextLines.push(line);
|
|
680
772
|
}
|
|
681
773
|
if (sawSdkCliEntrypoint && !hasPermissionMode) {
|
|
682
|
-
const sessionId =
|
|
774
|
+
const sessionId = basename2(sessionPath, ".jsonl");
|
|
683
775
|
nextLines.unshift(JSON.stringify({
|
|
684
776
|
type: "permission-mode",
|
|
685
777
|
permissionMode: "bypassPermissions",
|
|
@@ -688,26 +780,26 @@ async function normalizeClaudeSessionFileForResume(sessionPath) {
|
|
|
688
780
|
changed = true;
|
|
689
781
|
}
|
|
690
782
|
if (!changed) return false;
|
|
691
|
-
await
|
|
783
|
+
await writeFile(sessionPath, `${nextLines.join("\n")}
|
|
692
784
|
`, "utf8");
|
|
693
785
|
return true;
|
|
694
786
|
}
|
|
695
787
|
|
|
696
788
|
// src/providers/codex/nativeSessions.ts
|
|
697
789
|
import Database from "better-sqlite3";
|
|
698
|
-
import { readdir as
|
|
790
|
+
import { readdir as readdir3, readFile as readFile3, stat as stat3 } from "node:fs/promises";
|
|
699
791
|
import { existsSync as existsSync4 } from "node:fs";
|
|
700
792
|
import { homedir as homedir3 } from "node:os";
|
|
701
|
-
import { basename as
|
|
793
|
+
import { basename as basename3, join as join4 } from "node:path";
|
|
702
794
|
function resolveCodexSessionsRoot(env = process.env) {
|
|
703
|
-
return
|
|
795
|
+
return join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "sessions");
|
|
704
796
|
}
|
|
705
797
|
function isMatchingCodexRolloutFile(name) {
|
|
706
798
|
return name.startsWith("rollout-") && name.endsWith(".jsonl");
|
|
707
799
|
}
|
|
708
800
|
function extractCodexSessionId(name) {
|
|
709
801
|
if (!isMatchingCodexRolloutFile(name)) return null;
|
|
710
|
-
const withoutExt =
|
|
802
|
+
const withoutExt = basename3(name, ".jsonl");
|
|
711
803
|
const match = withoutExt.match(/^rollout-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-(.+)$/);
|
|
712
804
|
if (!match?.[1]) return null;
|
|
713
805
|
return match[1];
|
|
@@ -719,11 +811,11 @@ async function listRecoverableCodexSessions(env = process.env) {
|
|
|
719
811
|
const candidates = [];
|
|
720
812
|
async function walk(currentDir, depth) {
|
|
721
813
|
if (depth > 8) return;
|
|
722
|
-
const entries = await
|
|
814
|
+
const entries = await readdir3(currentDir, { withFileTypes: true }).catch(() => []);
|
|
723
815
|
for (const entry of entries) {
|
|
724
816
|
if (entry.isSymbolicLink()) continue;
|
|
725
817
|
const name = String(entry.name);
|
|
726
|
-
const path =
|
|
818
|
+
const path = join4(currentDir, name);
|
|
727
819
|
if (entry.isDirectory()) {
|
|
728
820
|
await walk(path, depth + 1);
|
|
729
821
|
continue;
|
|
@@ -755,11 +847,11 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
755
847
|
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\")) return null;
|
|
756
848
|
async function walk(currentDir, depth) {
|
|
757
849
|
if (depth > 8) return null;
|
|
758
|
-
const entries = await
|
|
850
|
+
const entries = await readdir3(currentDir, { withFileTypes: true }).catch(() => []);
|
|
759
851
|
for (const entry of entries) {
|
|
760
852
|
if (entry.isSymbolicLink()) continue;
|
|
761
853
|
const name = String(entry.name);
|
|
762
|
-
const path =
|
|
854
|
+
const path = join4(currentDir, name);
|
|
763
855
|
if (entry.isDirectory()) {
|
|
764
856
|
const found = await walk(path, depth + 1);
|
|
765
857
|
if (found) return found;
|
|
@@ -773,7 +865,7 @@ async function findRecoverableCodexSessionPath(sessionId, env = process.env) {
|
|
|
773
865
|
return await walk(root, 0);
|
|
774
866
|
}
|
|
775
867
|
async function readCodexSessionIndex(env) {
|
|
776
|
-
const indexPath =
|
|
868
|
+
const indexPath = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "session_index.jsonl");
|
|
777
869
|
const index = /* @__PURE__ */ new Map();
|
|
778
870
|
try {
|
|
779
871
|
const content = await readFile3(indexPath, "utf8");
|
|
@@ -796,7 +888,7 @@ async function readCodexSessionIndex(env) {
|
|
|
796
888
|
return index;
|
|
797
889
|
}
|
|
798
890
|
function readCodexThreadMetadata(env) {
|
|
799
|
-
const dbPath =
|
|
891
|
+
const dbPath = join4(env.CODEX_HOME || join4(env.HOME || homedir3(), ".codex"), "state_5.sqlite");
|
|
800
892
|
const metadata = /* @__PURE__ */ new Map();
|
|
801
893
|
if (!existsSync4(dbPath)) return metadata;
|
|
802
894
|
let db = null;
|
|
@@ -841,7 +933,7 @@ async function readCodexSessionMeta(filePath) {
|
|
|
841
933
|
} catch {
|
|
842
934
|
}
|
|
843
935
|
}
|
|
844
|
-
const metadata = await
|
|
936
|
+
const metadata = await stat3(filePath).catch(() => null);
|
|
845
937
|
return {
|
|
846
938
|
cwd,
|
|
847
939
|
lastActivityAt: metadata ? Math.trunc(metadata.mtimeMs) : void 0
|
|
@@ -855,11 +947,11 @@ async function readCodexSessionMeta(filePath) {
|
|
|
855
947
|
import { nanoid } from "nanoid";
|
|
856
948
|
|
|
857
949
|
// src/providers/codex/sessionIndex.ts
|
|
858
|
-
import { mkdir as mkdir3, readFile as readFile4, writeFile as
|
|
950
|
+
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
859
951
|
import { homedir as homedir4 } from "node:os";
|
|
860
|
-
import { dirname as
|
|
952
|
+
import { dirname as dirname3, join as join5 } from "node:path";
|
|
861
953
|
function resolveCodexIndexPath(env = process.env) {
|
|
862
|
-
return
|
|
954
|
+
return join5(env.CODEX_HOME || join5(env.HOME || homedir4(), ".codex"), "session_index.jsonl");
|
|
863
955
|
}
|
|
864
956
|
async function upsertCodexSessionIndexEntry(input, env = process.env) {
|
|
865
957
|
const indexPath = resolveCodexIndexPath(env);
|
|
@@ -895,19 +987,19 @@ async function upsertCodexSessionIndexEntry(input, env = process.env) {
|
|
|
895
987
|
updated_at: input.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
896
988
|
}));
|
|
897
989
|
}
|
|
898
|
-
await mkdir3(
|
|
899
|
-
await
|
|
990
|
+
await mkdir3(dirname3(indexPath), { recursive: true });
|
|
991
|
+
await writeFile2(indexPath, `${lines.join("\n")}
|
|
900
992
|
`, "utf8");
|
|
901
993
|
}
|
|
902
994
|
|
|
903
995
|
// src/providers/codex/nativeThreads.ts
|
|
904
996
|
import Database2 from "better-sqlite3";
|
|
905
997
|
import { existsSync as existsSync5 } from "node:fs";
|
|
906
|
-
import { readFile as readFile5, writeFile as
|
|
998
|
+
import { readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
907
999
|
import { homedir as homedir5 } from "node:os";
|
|
908
|
-
import { join as
|
|
1000
|
+
import { join as join6 } from "node:path";
|
|
909
1001
|
function resolveCodexStateDbPath(env = process.env) {
|
|
910
|
-
return
|
|
1002
|
+
return join6(env.CODEX_HOME || join6(env.HOME || homedir5(), ".codex"), "state_5.sqlite");
|
|
911
1003
|
}
|
|
912
1004
|
async function syncCodexThreadForResume(input) {
|
|
913
1005
|
const env = input.env ?? process.env;
|
|
@@ -963,7 +1055,7 @@ async function syncCodexRolloutSessionMeta(rolloutPath) {
|
|
|
963
1055
|
payload.originator = "codex-tui";
|
|
964
1056
|
first.payload = payload;
|
|
965
1057
|
lines[0] = JSON.stringify(first);
|
|
966
|
-
await
|
|
1058
|
+
await writeFile3(rolloutPath, lines.join("\n"), "utf8");
|
|
967
1059
|
} catch {
|
|
968
1060
|
}
|
|
969
1061
|
}
|
|
@@ -1568,9 +1660,9 @@ function normalizeSettings(input, defaultWorkspace) {
|
|
|
1568
1660
|
}
|
|
1569
1661
|
|
|
1570
1662
|
// src/admin/fsBrowseRoutes.ts
|
|
1571
|
-
import { readdir as
|
|
1663
|
+
import { readdir as readdir4 } from "node:fs/promises";
|
|
1572
1664
|
import { homedir as homedir7 } from "node:os";
|
|
1573
|
-
import { dirname as
|
|
1665
|
+
import { dirname as dirname4, join as join7, resolve } from "node:path";
|
|
1574
1666
|
|
|
1575
1667
|
// src/shared/expandTilde.ts
|
|
1576
1668
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -1591,13 +1683,13 @@ function registerFsBrowseRoutes(input) {
|
|
|
1591
1683
|
const isOnKeepChain = (path) => keep !== null && (keep === path || keep.startsWith(path + "/"));
|
|
1592
1684
|
let dirents;
|
|
1593
1685
|
try {
|
|
1594
|
-
dirents = await
|
|
1686
|
+
dirents = await readdir4(target, { withFileTypes: true });
|
|
1595
1687
|
} catch {
|
|
1596
1688
|
reply.code(400);
|
|
1597
1689
|
return { error: "cannot_read_directory", path: target };
|
|
1598
1690
|
}
|
|
1599
|
-
const entries = dirents.filter((dirent) => dirent.isDirectory()).map((dirent) => ({ name: dirent.name, path:
|
|
1600
|
-
const parent =
|
|
1691
|
+
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));
|
|
1692
|
+
const parent = dirname4(target);
|
|
1601
1693
|
const isRoot = parent === target;
|
|
1602
1694
|
const listing = {
|
|
1603
1695
|
path: target,
|
|
@@ -1778,7 +1870,7 @@ var WeixinDirectApiClient = class {
|
|
|
1778
1870
|
|
|
1779
1871
|
// src/channels/weixin-direct/adapter.ts
|
|
1780
1872
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
1781
|
-
import { join as
|
|
1873
|
+
import { join as join8 } from "node:path";
|
|
1782
1874
|
|
|
1783
1875
|
// src/channels/weixin-direct/typingController.ts
|
|
1784
1876
|
var CONFIG_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2043,7 +2135,7 @@ var WeixinDirectAdapter = class _WeixinDirectAdapter {
|
|
|
2043
2135
|
continue;
|
|
2044
2136
|
}
|
|
2045
2137
|
const { ext, mimeType } = mediaExtAndMime(meta);
|
|
2046
|
-
const destPath =
|
|
2138
|
+
const destPath = join8(mediaDir, `${idPrefix}_${i}${ext}`);
|
|
2047
2139
|
const maxBytes = meta.kind === "video" ? VIDEO_MAX_BYTES : void 0;
|
|
2048
2140
|
const result = await downloader.download(meta.media ?? {}, { destPath, aeskeyOverride: meta.aeskey, maxBytes });
|
|
2049
2141
|
if (result.ok) {
|
|
@@ -2103,8 +2195,8 @@ function chunkText(text, limit) {
|
|
|
2103
2195
|
}
|
|
2104
2196
|
|
|
2105
2197
|
// src/channels/weixin-direct/mediaDownloader.ts
|
|
2106
|
-
import { mkdirSync as
|
|
2107
|
-
import { dirname as
|
|
2198
|
+
import { mkdirSync as mkdirSync2, writeFileSync } from "node:fs";
|
|
2199
|
+
import { dirname as dirname5 } from "node:path";
|
|
2108
2200
|
|
|
2109
2201
|
// src/channels/weixin-direct/mediaCrypto.ts
|
|
2110
2202
|
import { createDecipheriv } from "node:crypto";
|
|
@@ -2167,8 +2259,8 @@ var WeixinMediaDownloader = class {
|
|
|
2167
2259
|
} catch {
|
|
2168
2260
|
return { ok: false, reason: "decrypt_failed" };
|
|
2169
2261
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2262
|
+
mkdirSync2(dirname5(input.destPath), { recursive: true });
|
|
2263
|
+
writeFileSync(input.destPath, plaintext);
|
|
2172
2264
|
return { ok: true, localPath: input.destPath, bytes: plaintext.length };
|
|
2173
2265
|
}
|
|
2174
2266
|
};
|
|
@@ -2354,7 +2446,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
2354
2446
|
|
|
2355
2447
|
// src/shared/platform.ts
|
|
2356
2448
|
import { access, constants } from "node:fs/promises";
|
|
2357
|
-
import { delimiter, join as
|
|
2449
|
+
import { delimiter, join as join9 } from "node:path";
|
|
2358
2450
|
import { tmpdir } from "node:os";
|
|
2359
2451
|
import { spawn } from "node:child_process";
|
|
2360
2452
|
var isWindows = process.platform === "win32";
|
|
@@ -2382,7 +2474,7 @@ async function findExecutable(command) {
|
|
|
2382
2474
|
const dirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
2383
2475
|
for (const dir of dirs) {
|
|
2384
2476
|
for (const ext of extensions) {
|
|
2385
|
-
const candidate =
|
|
2477
|
+
const candidate = join9(dir, command + ext);
|
|
2386
2478
|
if (await isExecutableFile(candidate)) return candidate;
|
|
2387
2479
|
}
|
|
2388
2480
|
}
|
|
@@ -2405,13 +2497,13 @@ function terminateChild(child, signal = "SIGTERM") {
|
|
|
2405
2497
|
}
|
|
2406
2498
|
}
|
|
2407
2499
|
function defaultWorkspaceDir() {
|
|
2408
|
-
return
|
|
2500
|
+
return join9(tmpdir(), "project");
|
|
2409
2501
|
}
|
|
2410
2502
|
function useShellForCli() {
|
|
2411
2503
|
return isWindows;
|
|
2412
2504
|
}
|
|
2413
2505
|
function statePath(filename) {
|
|
2414
|
-
return
|
|
2506
|
+
return join9(tmpdir(), filename);
|
|
2415
2507
|
}
|
|
2416
2508
|
|
|
2417
2509
|
// src/providers/claude-code/assistantContent.ts
|
|
@@ -3399,8 +3491,7 @@ function buildBridgeCommandHelpMarkdown(input) {
|
|
|
3399
3491
|
}
|
|
3400
3492
|
|
|
3401
3493
|
// src/session/currentConversationStore.ts
|
|
3402
|
-
import { existsSync as existsSync6,
|
|
3403
|
-
import { dirname as dirname7 } from "node:path";
|
|
3494
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
|
|
3404
3495
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3405
3496
|
var CurrentConversationStore = class {
|
|
3406
3497
|
constructor(configPath, defaults) {
|
|
@@ -3482,9 +3573,8 @@ var CurrentConversationStore = class {
|
|
|
3482
3573
|
this.writeState(state);
|
|
3483
3574
|
}
|
|
3484
3575
|
writeState(state) {
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
`, "utf8");
|
|
3576
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
3577
|
+
`);
|
|
3488
3578
|
}
|
|
3489
3579
|
};
|
|
3490
3580
|
|
|
@@ -4017,8 +4107,7 @@ function composeInboundText(content) {
|
|
|
4017
4107
|
}
|
|
4018
4108
|
|
|
4019
4109
|
// src/storage/lastProviderSessionStore.ts
|
|
4020
|
-
import { existsSync as existsSync7,
|
|
4021
|
-
import { dirname as dirname8 } from "node:path";
|
|
4110
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
4022
4111
|
var LastProviderSessionStore = class {
|
|
4023
4112
|
constructor(configPath) {
|
|
4024
4113
|
this.configPath = configPath;
|
|
@@ -4049,15 +4138,13 @@ var LastProviderSessionStore = class {
|
|
|
4049
4138
|
return raw && typeof raw === "object" ? raw : {};
|
|
4050
4139
|
}
|
|
4051
4140
|
writeState(state) {
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
`, "utf8");
|
|
4141
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
4142
|
+
`);
|
|
4055
4143
|
}
|
|
4056
4144
|
};
|
|
4057
4145
|
|
|
4058
4146
|
// src/storage/runtimeUserStore.ts
|
|
4059
|
-
import {
|
|
4060
|
-
import { dirname as dirname9 } from "node:path";
|
|
4147
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8 } from "node:fs";
|
|
4061
4148
|
import { nanoid as nanoid3 } from "nanoid";
|
|
4062
4149
|
var RuntimeUserStore = class {
|
|
4063
4150
|
constructor(configPath) {
|
|
@@ -4122,9 +4209,8 @@ var RuntimeUserStore = class {
|
|
|
4122
4209
|
return raw && typeof raw === "object" ? raw : {};
|
|
4123
4210
|
}
|
|
4124
4211
|
writeState(state) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
`, "utf8");
|
|
4212
|
+
writeFileAtomicSync(this.configPath, `${JSON.stringify(state, null, 2)}
|
|
4213
|
+
`);
|
|
4128
4214
|
}
|
|
4129
4215
|
};
|
|
4130
4216
|
|
|
@@ -4452,12 +4538,12 @@ var RelayTunnelRouter = class {
|
|
|
4452
4538
|
|
|
4453
4539
|
// src/shared/version.ts
|
|
4454
4540
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
4455
|
-
import { dirname as
|
|
4541
|
+
import { dirname as dirname6, join as join10 } from "node:path";
|
|
4456
4542
|
import { fileURLToPath } from "node:url";
|
|
4457
4543
|
function readClientVersion() {
|
|
4458
4544
|
try {
|
|
4459
|
-
const here2 =
|
|
4460
|
-
const pkg = JSON.parse(readFileSync7(
|
|
4545
|
+
const here2 = dirname6(fileURLToPath(import.meta.url));
|
|
4546
|
+
const pkg = JSON.parse(readFileSync7(join10(here2, "..", "..", "package.json"), "utf8"));
|
|
4461
4547
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
4462
4548
|
} catch {
|
|
4463
4549
|
return "0.0.0";
|
|
@@ -4476,7 +4562,7 @@ function readUpdateStatusBestEffort(configPath) {
|
|
|
4476
4562
|
function createDaemonServer(options = {}) {
|
|
4477
4563
|
const app = Fastify({ logger: true });
|
|
4478
4564
|
const events = new BridgeEventHub();
|
|
4479
|
-
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ??
|
|
4565
|
+
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? join11(mkdtempSync(join11(tmpdir2(), "claude-codex-wechat-")), "config.json");
|
|
4480
4566
|
const persistedConfig = loadBridgeConfig(configPath);
|
|
4481
4567
|
const bridgeDefaults = {
|
|
4482
4568
|
defaultProvider: options.bridgeDefaults?.defaultProvider ?? persistedConfig.bridge?.defaultProvider ?? "claude-code",
|
|
@@ -4533,7 +4619,7 @@ function createDaemonServer(options = {}) {
|
|
|
4533
4619
|
});
|
|
4534
4620
|
}
|
|
4535
4621
|
const weixinStateStore = configPath ? new FileWeixinStateStore(configPath) : void 0;
|
|
4536
|
-
const weixinMediaDir = configPath ?
|
|
4622
|
+
const weixinMediaDir = configPath ? join11(dirname7(configPath), "media") : void 0;
|
|
4537
4623
|
const managedWechatChannel = options.channel ? null : new ManagedWeixinDirectAdapter(options.wechat, weixinStateStore, weixinMediaDir);
|
|
4538
4624
|
const channel = options.channel ?? managedWechatChannel;
|
|
4539
4625
|
const weixinOutboundGate = managedWechatChannel && weixinStateStore ? new WeixinOutboundGate({
|
|
@@ -4770,6 +4856,7 @@ async function startDaemon(options) {
|
|
|
4770
4856
|
const port = options.port ?? Number(process.env.BRIDGE_PORT ?? 8787);
|
|
4771
4857
|
const host = options.host ?? "0.0.0.0";
|
|
4772
4858
|
const configPath = options.configPath ?? process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
4859
|
+
await cleanupStaleTempFiles(configPath).catch(() => void 0);
|
|
4773
4860
|
const config = loadBridgeConfig(configPath);
|
|
4774
4861
|
const providerCommands = await resolveProviderCommands(config.providers);
|
|
4775
4862
|
await persistProviderCommandsToConfigFile({
|
|
@@ -4824,7 +4911,7 @@ async function resolveProviderCommands(providers) {
|
|
|
4824
4911
|
|
|
4825
4912
|
// src/daemon/staticFrontend.ts
|
|
4826
4913
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
4827
|
-
import { join as
|
|
4914
|
+
import { join as join12 } from "node:path";
|
|
4828
4915
|
import fastifyStatic from "@fastify/static";
|
|
4829
4916
|
function attachStaticFrontend(webRoot2) {
|
|
4830
4917
|
return async (app) => {
|
|
@@ -4832,7 +4919,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4832
4919
|
root: webRoot2,
|
|
4833
4920
|
wildcard: false
|
|
4834
4921
|
});
|
|
4835
|
-
const indexHtml = readFileSync8(
|
|
4922
|
+
const indexHtml = readFileSync8(join12(webRoot2, "index.html"), "utf8");
|
|
4836
4923
|
app.setNotFoundHandler((request, reply) => {
|
|
4837
4924
|
if (request.url.startsWith("/api")) {
|
|
4838
4925
|
reply.code(404).send({ error: "not_found" });
|
|
@@ -4844,10 +4931,10 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4844
4931
|
}
|
|
4845
4932
|
|
|
4846
4933
|
// src/daemon/service.ts
|
|
4847
|
-
import { existsSync as existsSync9, statSync, openSync, closeSync, watchFile } from "node:fs";
|
|
4848
|
-
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as
|
|
4934
|
+
import { existsSync as existsSync9, statSync, openSync as openSync2, closeSync as closeSync2, watchFile } from "node:fs";
|
|
4935
|
+
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
|
|
4849
4936
|
import { homedir as homedir8 } from "node:os";
|
|
4850
|
-
import { dirname as
|
|
4937
|
+
import { dirname as dirname8, join as join13 } from "node:path";
|
|
4851
4938
|
import { createReadStream } from "node:fs";
|
|
4852
4939
|
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
4853
4940
|
import { createInterface } from "node:readline";
|
|
@@ -4856,19 +4943,20 @@ var execFileAsync = promisify(execFile);
|
|
|
4856
4943
|
async function installService(context) {
|
|
4857
4944
|
if (process.platform === "darwin") {
|
|
4858
4945
|
const spec = buildLaunchdSpec(context);
|
|
4859
|
-
await mkdir4(
|
|
4860
|
-
await mkdir4(
|
|
4861
|
-
await
|
|
4862
|
-
|
|
4863
|
-
await runLaunchctl(["
|
|
4864
|
-
await runLaunchctl(["
|
|
4946
|
+
await mkdir4(dirname8(spec.plistPath), { recursive: true });
|
|
4947
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
4948
|
+
await writeFile4(spec.plistPath, renderLaunchdPlist(spec), "utf8");
|
|
4949
|
+
const guiDomain = `gui/${process.getuid?.() ?? 0}`;
|
|
4950
|
+
await runLaunchctl(["bootout", guiDomain, spec.plistPath]).catch(() => void 0);
|
|
4951
|
+
await runLaunchctl(["bootstrap", guiDomain, spec.plistPath]);
|
|
4952
|
+
await runLaunchctl(["kickstart", "-k", `${guiDomain}/${spec.label}`]);
|
|
4865
4953
|
return await readServiceStatus(context);
|
|
4866
4954
|
}
|
|
4867
4955
|
if (process.platform === "linux") {
|
|
4868
4956
|
const spec = buildSystemdUserSpec(context);
|
|
4869
|
-
await mkdir4(
|
|
4870
|
-
await mkdir4(
|
|
4871
|
-
await
|
|
4957
|
+
await mkdir4(dirname8(spec.unitPath), { recursive: true });
|
|
4958
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
4959
|
+
await writeFile4(spec.unitPath, renderSystemdUnit(spec), "utf8");
|
|
4872
4960
|
await runSystemctl(["--user", "daemon-reload"]);
|
|
4873
4961
|
await runSystemctl(["--user", "enable", "--now", spec.unitName]);
|
|
4874
4962
|
return await readServiceStatus(context);
|
|
@@ -4882,8 +4970,9 @@ async function startService(context) {
|
|
|
4882
4970
|
if (process.platform === "darwin") {
|
|
4883
4971
|
const spec = buildLaunchdSpec(context);
|
|
4884
4972
|
await ensureFileExists(spec.plistPath, "service_not_installed");
|
|
4885
|
-
|
|
4886
|
-
await runLaunchctl(["
|
|
4973
|
+
const guiDomain = `gui/${process.getuid?.() ?? 0}`;
|
|
4974
|
+
await runLaunchctl(["bootstrap", guiDomain, spec.plistPath]).catch(() => void 0);
|
|
4975
|
+
await runLaunchctl(["kickstart", "-k", `${guiDomain}/${spec.label}`]);
|
|
4887
4976
|
return await readServiceStatus(context);
|
|
4888
4977
|
}
|
|
4889
4978
|
if (process.platform === "linux") {
|
|
@@ -4954,8 +5043,9 @@ async function restartService(context) {
|
|
|
4954
5043
|
if (process.platform === "darwin") {
|
|
4955
5044
|
const spec = buildLaunchdSpec(context);
|
|
4956
5045
|
await ensureFileExists(spec.plistPath, "service_not_installed");
|
|
4957
|
-
|
|
4958
|
-
await runLaunchctl(["
|
|
5046
|
+
const guiDomain = `gui/${process.getuid?.() ?? 0}`;
|
|
5047
|
+
await runLaunchctl(["bootstrap", guiDomain, spec.plistPath]).catch(() => void 0);
|
|
5048
|
+
await runLaunchctl(["kickstart", "-k", `${guiDomain}/${spec.label}`]);
|
|
4959
5049
|
return await readServiceStatus(context);
|
|
4960
5050
|
}
|
|
4961
5051
|
if (process.platform === "linux") {
|
|
@@ -5034,37 +5124,37 @@ async function readServiceStatus(context) {
|
|
|
5034
5124
|
throw new Error("service_status_not_supported_on_this_platform");
|
|
5035
5125
|
}
|
|
5036
5126
|
function buildLaunchdSpec(context) {
|
|
5037
|
-
const stateDir =
|
|
5127
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5038
5128
|
return {
|
|
5039
5129
|
label: "com.claude-codex-wechat",
|
|
5040
|
-
plistPath:
|
|
5130
|
+
plistPath: join13(homedir8(), "Library", "LaunchAgents", "com.claude-codex-wechat.plist"),
|
|
5041
5131
|
programArgs: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5042
5132
|
workingDirectory: homedir8(),
|
|
5043
|
-
stdoutPath:
|
|
5044
|
-
stderrPath:
|
|
5133
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5134
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5045
5135
|
environment: buildServiceEnvironment(context)
|
|
5046
5136
|
};
|
|
5047
5137
|
}
|
|
5048
5138
|
function buildSystemdUserSpec(context) {
|
|
5049
|
-
const stateDir =
|
|
5139
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5050
5140
|
return {
|
|
5051
5141
|
unitName: "claude-codex-wechat.service",
|
|
5052
|
-
unitPath:
|
|
5142
|
+
unitPath: join13(homedir8(), ".config", "systemd", "user", "claude-codex-wechat.service"),
|
|
5053
5143
|
execStart: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5054
5144
|
workingDirectory: homedir8(),
|
|
5055
|
-
stdoutPath:
|
|
5056
|
-
stderrPath:
|
|
5145
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5146
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5057
5147
|
environment: buildServiceEnvironment(context)
|
|
5058
5148
|
};
|
|
5059
5149
|
}
|
|
5060
5150
|
function buildProcessSpec(context) {
|
|
5061
|
-
const stateDir =
|
|
5151
|
+
const stateDir = join13(homedir8(), ".claude-codex-wechat");
|
|
5062
5152
|
return {
|
|
5063
|
-
pidPath:
|
|
5153
|
+
pidPath: join13(stateDir, "service.pid"),
|
|
5064
5154
|
command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
5065
5155
|
workingDirectory: homedir8(),
|
|
5066
|
-
stdoutPath:
|
|
5067
|
-
stderrPath:
|
|
5156
|
+
stdoutPath: join13(stateDir, "logs", "service.stdout.log"),
|
|
5157
|
+
stderrPath: join13(stateDir, "logs", "service.stderr.log"),
|
|
5068
5158
|
environment: buildServiceEnvironment(context)
|
|
5069
5159
|
};
|
|
5070
5160
|
}
|
|
@@ -5185,8 +5275,8 @@ async function readPidFile(pidPath) {
|
|
|
5185
5275
|
}
|
|
5186
5276
|
}
|
|
5187
5277
|
async function writePidFile(pidPath, pid) {
|
|
5188
|
-
await mkdir4(
|
|
5189
|
-
await
|
|
5278
|
+
await mkdir4(dirname8(pidPath), { recursive: true });
|
|
5279
|
+
await writeFile4(pidPath, `${pid}
|
|
5190
5280
|
`, "utf8");
|
|
5191
5281
|
}
|
|
5192
5282
|
async function removePidFile(pidPath) {
|
|
@@ -5200,9 +5290,9 @@ async function killPid(pid) {
|
|
|
5200
5290
|
process.kill(pid, "SIGTERM");
|
|
5201
5291
|
}
|
|
5202
5292
|
async function spawnDetachedDaemon(spec) {
|
|
5203
|
-
await mkdir4(
|
|
5204
|
-
const outFd =
|
|
5205
|
-
const errFd =
|
|
5293
|
+
await mkdir4(dirname8(spec.stdoutPath), { recursive: true });
|
|
5294
|
+
const outFd = openSync2(spec.stdoutPath, "a");
|
|
5295
|
+
const errFd = openSync2(spec.stderrPath, "a");
|
|
5206
5296
|
try {
|
|
5207
5297
|
const [command, ...args] = spec.command;
|
|
5208
5298
|
const child = spawn7(command, args, {
|
|
@@ -5221,8 +5311,8 @@ async function spawnDetachedDaemon(spec) {
|
|
|
5221
5311
|
child.unref();
|
|
5222
5312
|
return child.pid;
|
|
5223
5313
|
} finally {
|
|
5224
|
-
|
|
5225
|
-
|
|
5314
|
+
closeSync2(outFd);
|
|
5315
|
+
closeSync2(errFd);
|
|
5226
5316
|
}
|
|
5227
5317
|
}
|
|
5228
5318
|
async function ensureFileExists(path, errorCode) {
|
|
@@ -5286,8 +5376,8 @@ function fileSizeHint(path) {
|
|
|
5286
5376
|
}
|
|
5287
5377
|
|
|
5288
5378
|
// src/cli.ts
|
|
5289
|
-
var here =
|
|
5290
|
-
var webRoot =
|
|
5379
|
+
var here = dirname9(fileURLToPath2(import.meta.url));
|
|
5380
|
+
var webRoot = join14(here, "..", "web");
|
|
5291
5381
|
async function main() {
|
|
5292
5382
|
const command = process.argv[2];
|
|
5293
5383
|
switch (command) {
|