claude-codex-wechat 0.1.16 → 0.1.17
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 +1 -1
- package/dist/server/cli.js +166 -25
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/server/cli.js
CHANGED
|
@@ -2377,6 +2377,9 @@ function terminateChild(child, signal = "SIGTERM") {
|
|
|
2377
2377
|
function defaultWorkspaceDir() {
|
|
2378
2378
|
return join8(tmpdir(), "project");
|
|
2379
2379
|
}
|
|
2380
|
+
function useShellForCli() {
|
|
2381
|
+
return isWindows;
|
|
2382
|
+
}
|
|
2380
2383
|
function statePath(filename) {
|
|
2381
2384
|
return join8(tmpdir(), filename);
|
|
2382
2385
|
}
|
|
@@ -2551,7 +2554,7 @@ function parseJsonLine(line) {
|
|
|
2551
2554
|
}
|
|
2552
2555
|
}
|
|
2553
2556
|
function defaultClaudeStreamSpawner(call) {
|
|
2554
|
-
const child = spawn2(call.command, call.args, { cwd: expandTilde(call.cwd) ?? call.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
2557
|
+
const child = spawn2(call.command, call.args, { cwd: expandTilde(call.cwd) ?? call.cwd, stdio: ["pipe", "pipe", "pipe"], shell: useShellForCli() });
|
|
2555
2558
|
let stderr = "";
|
|
2556
2559
|
let buffer = "";
|
|
2557
2560
|
const queue = [];
|
|
@@ -2663,7 +2666,8 @@ var CodexAppServerClient = class {
|
|
|
2663
2666
|
const command = input.command ?? "codex";
|
|
2664
2667
|
this.child = spawn3(command, ["app-server", "--listen", "stdio://"], {
|
|
2665
2668
|
cwd: input.cwd,
|
|
2666
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
2669
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2670
|
+
shell: useShellForCli()
|
|
2667
2671
|
});
|
|
2668
2672
|
this.child.stdout.on("data", (chunk) => this.onStdout(String(chunk)));
|
|
2669
2673
|
this.child.stderr.on("data", () => {
|
|
@@ -3070,7 +3074,7 @@ function createDefaultProviders(input = {}) {
|
|
|
3070
3074
|
import { spawn as spawn4 } from "node:child_process";
|
|
3071
3075
|
async function defaultCommandRunner(command, args) {
|
|
3072
3076
|
return await new Promise((resolve2) => {
|
|
3073
|
-
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
3077
|
+
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
|
|
3074
3078
|
let stdout = "";
|
|
3075
3079
|
let stderr = "";
|
|
3076
3080
|
child.stdout.on("data", (chunk) => {
|
|
@@ -3106,7 +3110,7 @@ ${result.stderr}`) };
|
|
|
3106
3110
|
import { spawn as spawn5 } from "node:child_process";
|
|
3107
3111
|
async function defaultCodexCommandRunner(command, args) {
|
|
3108
3112
|
return await new Promise((resolve2) => {
|
|
3109
|
-
const child = spawn5(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
3113
|
+
const child = spawn5(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: useShellForCli() });
|
|
3110
3114
|
let stdout = "";
|
|
3111
3115
|
let stderr = "";
|
|
3112
3116
|
child.stdout.on("data", (chunk) => {
|
|
@@ -4456,7 +4460,7 @@ function attachStaticFrontend(webRoot2) {
|
|
|
4456
4460
|
}
|
|
4457
4461
|
|
|
4458
4462
|
// src/daemon/service.ts
|
|
4459
|
-
import { existsSync as existsSync9, statSync } from "node:fs";
|
|
4463
|
+
import { existsSync as existsSync9, statSync, openSync, closeSync, watchFile } from "node:fs";
|
|
4460
4464
|
import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
4461
4465
|
import { homedir as homedir8 } from "node:os";
|
|
4462
4466
|
import { dirname as dirname11, join as join11 } from "node:path";
|
|
@@ -4485,6 +4489,9 @@ async function installService(context) {
|
|
|
4485
4489
|
await runSystemctl(["--user", "enable", "--now", spec.unitName]);
|
|
4486
4490
|
return await readServiceStatus(context);
|
|
4487
4491
|
}
|
|
4492
|
+
if (process.platform === "win32") {
|
|
4493
|
+
return await startService(context);
|
|
4494
|
+
}
|
|
4488
4495
|
throw new Error("service_install_not_supported_on_this_platform");
|
|
4489
4496
|
}
|
|
4490
4497
|
async function startService(context) {
|
|
@@ -4501,6 +4508,15 @@ async function startService(context) {
|
|
|
4501
4508
|
await runSystemctl(["--user", "start", spec.unitName]);
|
|
4502
4509
|
return await readServiceStatus(context);
|
|
4503
4510
|
}
|
|
4511
|
+
if (process.platform === "win32") {
|
|
4512
|
+
const spec = buildProcessSpec(context);
|
|
4513
|
+
const existingPid = await readPidFile(spec.pidPath);
|
|
4514
|
+
if (existingPid !== null && isProcessAlive(existingPid)) {
|
|
4515
|
+
return await readServiceStatus(context);
|
|
4516
|
+
}
|
|
4517
|
+
await spawnDetachedDaemon(spec);
|
|
4518
|
+
return await readServiceStatus(context);
|
|
4519
|
+
}
|
|
4504
4520
|
throw new Error("service_start_not_supported_on_this_platform");
|
|
4505
4521
|
}
|
|
4506
4522
|
async function stopService(context) {
|
|
@@ -4516,6 +4532,15 @@ async function stopService(context) {
|
|
|
4516
4532
|
await runSystemctl(["--user", "stop", spec.unitName]).catch(() => void 0);
|
|
4517
4533
|
return await readServiceStatus(context);
|
|
4518
4534
|
}
|
|
4535
|
+
if (process.platform === "win32") {
|
|
4536
|
+
const spec = buildProcessSpec(context);
|
|
4537
|
+
const pid = await readPidFile(spec.pidPath);
|
|
4538
|
+
if (pid !== null && isProcessAlive(pid)) {
|
|
4539
|
+
await killPid(pid).catch(() => void 0);
|
|
4540
|
+
}
|
|
4541
|
+
await removePidFile(spec.pidPath);
|
|
4542
|
+
return await readServiceStatus(context);
|
|
4543
|
+
}
|
|
4519
4544
|
throw new Error("service_stop_not_supported_on_this_platform");
|
|
4520
4545
|
}
|
|
4521
4546
|
async function uninstallService(context) {
|
|
@@ -4536,6 +4561,9 @@ async function uninstallService(context) {
|
|
|
4536
4561
|
}
|
|
4537
4562
|
return await readServiceStatus(context);
|
|
4538
4563
|
}
|
|
4564
|
+
if (process.platform === "win32") {
|
|
4565
|
+
return await stopService(context);
|
|
4566
|
+
}
|
|
4539
4567
|
throw new Error("service_uninstall_not_supported_on_this_platform");
|
|
4540
4568
|
}
|
|
4541
4569
|
async function restartService(context) {
|
|
@@ -4551,6 +4579,10 @@ async function restartService(context) {
|
|
|
4551
4579
|
await runSystemctl(["--user", "restart", spec.unitName]);
|
|
4552
4580
|
return await readServiceStatus(context);
|
|
4553
4581
|
}
|
|
4582
|
+
if (process.platform === "win32") {
|
|
4583
|
+
await stopService(context);
|
|
4584
|
+
return await startService(context);
|
|
4585
|
+
}
|
|
4554
4586
|
throw new Error("service_restart_not_supported_on_this_platform");
|
|
4555
4587
|
}
|
|
4556
4588
|
async function readServiceLogs(context, lines = 120) {
|
|
@@ -4598,6 +4630,21 @@ async function readServiceStatus(context) {
|
|
|
4598
4630
|
stderrPath: spec.stderrPath
|
|
4599
4631
|
};
|
|
4600
4632
|
}
|
|
4633
|
+
if (process.platform === "win32") {
|
|
4634
|
+
const spec = buildProcessSpec(context);
|
|
4635
|
+
const pid = await readPidFile(spec.pidPath);
|
|
4636
|
+
const installed = pid !== null;
|
|
4637
|
+
const running = pid !== null && isProcessAlive(pid);
|
|
4638
|
+
return {
|
|
4639
|
+
manager: "process",
|
|
4640
|
+
installed,
|
|
4641
|
+
running,
|
|
4642
|
+
serviceFilePath: spec.pidPath,
|
|
4643
|
+
label: "claude-codex-wechat",
|
|
4644
|
+
stdoutPath: spec.stdoutPath,
|
|
4645
|
+
stderrPath: spec.stderrPath
|
|
4646
|
+
};
|
|
4647
|
+
}
|
|
4601
4648
|
throw new Error("service_status_not_supported_on_this_platform");
|
|
4602
4649
|
}
|
|
4603
4650
|
function buildLaunchdSpec(context) {
|
|
@@ -4624,6 +4671,17 @@ function buildSystemdUserSpec(context) {
|
|
|
4624
4671
|
environment: buildServiceEnvironment(context)
|
|
4625
4672
|
};
|
|
4626
4673
|
}
|
|
4674
|
+
function buildProcessSpec(context) {
|
|
4675
|
+
const stateDir = join11(homedir8(), ".claude-codex-wechat");
|
|
4676
|
+
return {
|
|
4677
|
+
pidPath: join11(stateDir, "service.pid"),
|
|
4678
|
+
command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
|
|
4679
|
+
workingDirectory: homedir8(),
|
|
4680
|
+
stdoutPath: join11(stateDir, "logs", "service.stdout.log"),
|
|
4681
|
+
stderrPath: join11(stateDir, "logs", "service.stderr.log"),
|
|
4682
|
+
environment: buildServiceEnvironment(context)
|
|
4683
|
+
};
|
|
4684
|
+
}
|
|
4627
4685
|
function buildServiceEnvironment(context) {
|
|
4628
4686
|
const env = {
|
|
4629
4687
|
PATH: process.env.PATH ?? "",
|
|
@@ -4721,6 +4779,66 @@ async function runLaunchctl(args) {
|
|
|
4721
4779
|
async function runSystemctl(args) {
|
|
4722
4780
|
await execFileAsync("systemctl", args);
|
|
4723
4781
|
}
|
|
4782
|
+
function isProcessAlive(pid) {
|
|
4783
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
4784
|
+
try {
|
|
4785
|
+
process.kill(pid, 0);
|
|
4786
|
+
return true;
|
|
4787
|
+
} catch (error) {
|
|
4788
|
+
return error.code === "EPERM";
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
async function readPidFile(pidPath) {
|
|
4792
|
+
if (!existsSync9(pidPath)) return null;
|
|
4793
|
+
try {
|
|
4794
|
+
const raw = (await readFile6(pidPath, "utf8")).trim();
|
|
4795
|
+
const pid = Number.parseInt(raw, 10);
|
|
4796
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
4797
|
+
} catch {
|
|
4798
|
+
return null;
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
async function writePidFile(pidPath, pid) {
|
|
4802
|
+
await mkdir4(dirname11(pidPath), { recursive: true });
|
|
4803
|
+
await writeFile5(pidPath, `${pid}
|
|
4804
|
+
`, "utf8");
|
|
4805
|
+
}
|
|
4806
|
+
async function removePidFile(pidPath) {
|
|
4807
|
+
await rm2(pidPath, { force: true });
|
|
4808
|
+
}
|
|
4809
|
+
async function killPid(pid) {
|
|
4810
|
+
if (process.platform === "win32") {
|
|
4811
|
+
await execFileAsync("taskkill", ["/PID", String(pid), "/T", "/F"]);
|
|
4812
|
+
return;
|
|
4813
|
+
}
|
|
4814
|
+
process.kill(pid, "SIGTERM");
|
|
4815
|
+
}
|
|
4816
|
+
async function spawnDetachedDaemon(spec) {
|
|
4817
|
+
await mkdir4(dirname11(spec.stdoutPath), { recursive: true });
|
|
4818
|
+
const outFd = openSync(spec.stdoutPath, "a");
|
|
4819
|
+
const errFd = openSync(spec.stderrPath, "a");
|
|
4820
|
+
try {
|
|
4821
|
+
const [command, ...args] = spec.command;
|
|
4822
|
+
const child = spawn6(command, args, {
|
|
4823
|
+
cwd: spec.workingDirectory,
|
|
4824
|
+
// Windows 分离进程需继承完整 process.env(SystemRoot/APPDATA/PATHEXT 等),
|
|
4825
|
+
// 否则子进程及其拉起的 claude/codex 会异常;spec.environment 仅作 BRIDGE_* 等覆盖层。
|
|
4826
|
+
env: { ...process.env, ...spec.environment },
|
|
4827
|
+
detached: true,
|
|
4828
|
+
windowsHide: true,
|
|
4829
|
+
stdio: ["ignore", outFd, errFd]
|
|
4830
|
+
});
|
|
4831
|
+
if (typeof child.pid !== "number") {
|
|
4832
|
+
throw new Error("service_spawn_failed");
|
|
4833
|
+
}
|
|
4834
|
+
await writePidFile(spec.pidPath, child.pid);
|
|
4835
|
+
child.unref();
|
|
4836
|
+
return child.pid;
|
|
4837
|
+
} finally {
|
|
4838
|
+
closeSync(outFd);
|
|
4839
|
+
closeSync(errFd);
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4724
4842
|
async function ensureFileExists(path, errorCode) {
|
|
4725
4843
|
if (!existsSync9(path)) throw new Error(errorCode);
|
|
4726
4844
|
await readFile6(path, "utf8");
|
|
@@ -4731,29 +4849,46 @@ async function tailFile(path, lines) {
|
|
|
4731
4849
|
return content.split(/\r?\n/).slice(-lines).join("\n").trim();
|
|
4732
4850
|
}
|
|
4733
4851
|
async function tailFiles(paths) {
|
|
4734
|
-
const
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
rl.on("line", (line) => {
|
|
4740
|
-
process.stdout.write(`[${path}] ${line}
|
|
4852
|
+
const existing = paths.filter((path) => existsSync9(path));
|
|
4853
|
+
for (const path of existing) {
|
|
4854
|
+
const tail = await tailFile(path, 200);
|
|
4855
|
+
if (tail) process.stdout.write(`[${path}]
|
|
4856
|
+
${tail}
|
|
4741
4857
|
`);
|
|
4858
|
+
}
|
|
4859
|
+
if (process.platform === "linux" || process.platform === "darwin") {
|
|
4860
|
+
const child = spawn6("tail", ["-f", ...existing], { stdio: ["ignore", "pipe", "inherit"] });
|
|
4861
|
+
child.stdout.on("data", (chunk) => {
|
|
4862
|
+
process.stdout.write(String(chunk));
|
|
4863
|
+
});
|
|
4864
|
+
await new Promise((resolve2, reject) => {
|
|
4865
|
+
child.on("exit", () => resolve2());
|
|
4866
|
+
child.on("error", reject);
|
|
4742
4867
|
});
|
|
4743
|
-
return rl;
|
|
4744
|
-
});
|
|
4745
|
-
if (process.platform !== "linux" && process.platform !== "darwin") {
|
|
4746
4868
|
return;
|
|
4747
4869
|
}
|
|
4748
|
-
const
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4870
|
+
const offsets = new Map(existing.map((path) => [path, fileSizeHint(path)]));
|
|
4871
|
+
for (const path of existing) {
|
|
4872
|
+
watchFile(path, { interval: 1e3 }, (curr) => {
|
|
4873
|
+
const prevSize = offsets.get(path) ?? 0;
|
|
4874
|
+
if (curr.size < prevSize) {
|
|
4875
|
+
offsets.set(path, 0);
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
if (curr.size === prevSize) return;
|
|
4879
|
+
const start = prevSize;
|
|
4880
|
+
offsets.set(path, curr.size);
|
|
4881
|
+
const rl = createInterface({
|
|
4882
|
+
input: createReadStream(path, { encoding: "utf8", start, end: curr.size - 1 }),
|
|
4883
|
+
crlfDelay: Infinity
|
|
4884
|
+
});
|
|
4885
|
+
rl.on("line", (line) => {
|
|
4886
|
+
process.stdout.write(`[${path}] ${line}
|
|
4887
|
+
`);
|
|
4888
|
+
});
|
|
4889
|
+
});
|
|
4890
|
+
}
|
|
4891
|
+
await new Promise(() => {
|
|
4757
4892
|
});
|
|
4758
4893
|
}
|
|
4759
4894
|
function fileSizeHint(path) {
|
|
@@ -4882,6 +5017,7 @@ function cmdInit() {
|
|
|
4882
5017
|
`, "utf8");
|
|
4883
5018
|
console.log(`\u5DF2\u521B\u5EFA\u914D\u7F6E: ${configPath}`);
|
|
4884
5019
|
console.log("\u8BF7\u586B\u5165\u5FAE\u4FE1 token / accountId \u540E\u8FD0\u884C: claude-codex-wechat start");
|
|
5020
|
+
console.log("\u9996\u6B21\u542F\u52A8\u65F6\u5C06\u81EA\u52A8\u751F\u6210 relay \u63A5\u5165\u51ED\u636E\uFF08tunnel.relay.authToken\uFF09\u5E76\u5199\u56DE\u914D\u7F6E\uFF0C\u65E0\u9700\u624B\u52A8\u586B\u5199\u3002");
|
|
4885
5021
|
}
|
|
4886
5022
|
async function cmdDoctor() {
|
|
4887
5023
|
const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
|
|
@@ -4956,6 +5092,11 @@ function printUsage() {
|
|
|
4956
5092
|
|
|
4957
5093
|
\u73AF\u5883\u53D8\u91CF:
|
|
4958
5094
|
BRIDGE_PORT \u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8787\uFF09
|
|
4959
|
-
BRIDGE_CONFIG \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.claude-codex-wechat/config.json\uFF09
|
|
5095
|
+
BRIDGE_CONFIG \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.claude-codex-wechat/config.json\uFF09
|
|
5096
|
+
|
|
5097
|
+
\u5E73\u53F0\u8BF4\u660E:
|
|
5098
|
+
macOS \u7528 launchd\u3001Linux \u7528 systemd --user \u6258\u7BA1\uFF0C\u767B\u5F55\u81EA\u542F\u4E14\u5D29\u6E83\u81EA\u52A8\u91CD\u542F\u3002
|
|
5099
|
+
Windows \u91C7\u7528\u540E\u53F0\u8FDB\u7A0B + PID \u6587\u4EF6\u6258\u7BA1\uFF08\u514D\u7BA1\u7406\u5458\uFF09\uFF0C\u4E0D\u968F\u5F00\u673A\u81EA\u542F\uFF0C
|
|
5100
|
+
\u91CD\u542F\u7535\u8111\u540E\u9700\u91CD\u65B0\u8FD0\u884C start\u3002`);
|
|
4960
5101
|
}
|
|
4961
5102
|
await main();
|