claude-codex-wechat 0.1.16 → 0.1.18

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 CHANGED
@@ -47,7 +47,7 @@
47
47
  ### 作为 npm 包安装
48
48
 
49
49
  ```bash
50
- npm install -g claude-codex-wechat
50
+ npm install -g claude-codex-wechat --registry=https://registry.npmmirror.com/
51
51
  # 或
52
52
  pnpm add -g claude-codex-wechat
53
53
  ```
@@ -64,26 +64,24 @@ pnpm add -g claude-codex-wechat
64
64
  安装后按以下顺序跑通:
65
65
 
66
66
  ```bash
67
- # 1. 生成默认配置
68
- claude-codex-wechat init
69
-
70
- # 2. 编辑 ~/.claude-codex-wechat/config.json,填入微信 token / accountId
71
- # (配置说明见下方「配置」一节)
72
-
73
- # 3. 检查环境(配置、前端产物、claude/codex 是否就绪)
74
- claude-codex-wechat doctor
75
-
76
- # 4. 后台启动(首次会自动注册为系统服务并守护运行)
67
+ # 1. 后台启动(首次会自动注册为系统服务并守护运行;
68
+ # 首次启动自动生成 relay 接入凭据、自动连接默认中转,无需手动配置)
77
69
  claude-codex-wechat start
78
70
 
79
- # 5. 查看状态 / 日志
71
+ # 2. 打开管理页,用微信扫码登录完成绑定
72
+ # http://127.0.0.1:8787
73
+
74
+ # 3. 查看状态 / 日志
80
75
  claude-codex-wechat status
81
76
  claude-codex-wechat logs
77
+
78
+ # 可选:检查环境(配置、前端产物、claude/codex 是否就绪)
79
+ claude-codex-wechat doctor
82
80
  ```
83
81
 
84
82
  启动后:
85
83
 
86
- - 管理页:`http://127.0.0.1:8787`
84
+ - 管理页:`http://127.0.0.1:8787`(在此扫码登录微信)
87
85
  - 微信侧即可直接给机器人发消息,驱动本机 `Claude Code` / `Codex CLI` 会话
88
86
 
89
87
  停止 / 重启 / 卸载:
@@ -119,8 +117,6 @@ pnpm install
119
117
  - 打印 / 实时跟随日志
120
118
  - `claude-codex-wechat doctor`
121
119
  - 检查配置、前端产物、`claude`/`codex` 可执行文件
122
- - `claude-codex-wechat init`
123
- - 写默认配置到 `~/.claude-codex-wechat/config.json`
124
120
  - `claude-codex-wechat uninstall`
125
121
  - 卸载后台服务
126
122
  - `claude-codex-wechat print-config`
@@ -140,13 +136,7 @@ pnpm install
140
136
  ~/.claude-codex-wechat/config.json
141
137
  ```
142
138
 
143
- 推荐先初始化:
144
-
145
- ```bash
146
- claude-codex-wechat init
147
- ```
148
-
149
- 最小配置示例:
139
+ 该文件在**首次 `start` 时自动创建**(并自动写入生成的 relay 接入凭据),正常使用无需手动编辑。以下为可选的进阶自定义示例:
150
140
 
151
141
  ```json
152
142
  {
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __cjsCreateRequire } from 'node:module'; const require = __cjsCreateRequire(import.meta.url);
3
3
 
4
4
  // src/cli.ts
5
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
5
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
6
6
  import { dirname as dirname12, join as join12 } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
@@ -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) => {
@@ -3990,6 +3994,9 @@ var RelayTunnelProvider = class {
3990
3994
  running: false,
3991
3995
  status: "stopped"
3992
3996
  };
3997
+ stopped = true;
3998
+ reconnectAttempts = 0;
3999
+ reconnectTimer = null;
3993
4000
  static defaultCreateSocket(url) {
3994
4001
  const socket = new WebSocket(url);
3995
4002
  return {
@@ -4011,13 +4018,34 @@ var RelayTunnelProvider = class {
4011
4018
  return { ...this.status };
4012
4019
  }
4013
4020
  async start() {
4021
+ this.stopped = false;
4022
+ return await this.connect();
4023
+ }
4024
+ async stop() {
4025
+ this.stopped = true;
4026
+ if (this.reconnectTimer) {
4027
+ clearTimeout(this.reconnectTimer);
4028
+ this.reconnectTimer = null;
4029
+ }
4030
+ this.socket?.close();
4031
+ this.socket = null;
4032
+ this.status = {
4033
+ installed: true,
4034
+ running: false,
4035
+ status: "stopped"
4036
+ };
4037
+ return { ...this.status };
4038
+ }
4039
+ // 单次连接尝试:成功注册即 resolve。底层连接断开(close/error)时,
4040
+ // 只要未被 stop(),就按指数退避自动重连,直到恢复。
4041
+ connect() {
4014
4042
  this.status = {
4015
4043
  ...this.status,
4016
4044
  status: "starting"
4017
4045
  };
4018
4046
  const socket = this.options.createSocket(this.options.serverUrl);
4019
4047
  this.socket = socket;
4020
- return await new Promise((resolve2, reject) => {
4048
+ return new Promise((resolve2, reject) => {
4021
4049
  let settled = false;
4022
4050
  const finishResolve = (value) => {
4023
4051
  if (settled) return;
@@ -4048,9 +4076,11 @@ var RelayTunnelProvider = class {
4048
4076
  error: message
4049
4077
  };
4050
4078
  finishReject(new Error(message));
4079
+ this.scheduleReconnect();
4051
4080
  return;
4052
4081
  }
4053
4082
  if (payload?.type === "registered") {
4083
+ this.reconnectAttempts = 0;
4054
4084
  const publicUrl = typeof payload?.publicUrl === "string" && payload.publicUrl ? payload.publicUrl : typeof payload?.token === "string" ? `${derivePublicBaseUrl(this.options.serverUrl)}/${payload.token}` : void 0;
4055
4085
  this.status = {
4056
4086
  installed: true,
@@ -4066,6 +4096,10 @@ var RelayTunnelProvider = class {
4066
4096
  }
4067
4097
  });
4068
4098
  socket.on("close", () => {
4099
+ if (this.stopped) {
4100
+ finishReject(new Error("relay_stopped"));
4101
+ return;
4102
+ }
4069
4103
  this.status = {
4070
4104
  ...this.status,
4071
4105
  running: false,
@@ -4073,8 +4107,13 @@ var RelayTunnelProvider = class {
4073
4107
  error: "relay_disconnected"
4074
4108
  };
4075
4109
  finishReject(new Error("relay_disconnected"));
4110
+ this.scheduleReconnect();
4076
4111
  });
4077
4112
  socket.on("error", (error) => {
4113
+ if (this.stopped) {
4114
+ finishReject(new Error("relay_stopped"));
4115
+ return;
4116
+ }
4078
4117
  const message = error instanceof Error ? error.message : String(error);
4079
4118
  this.status = {
4080
4119
  ...this.status,
@@ -4083,18 +4122,22 @@ var RelayTunnelProvider = class {
4083
4122
  error: message
4084
4123
  };
4085
4124
  finishReject(error);
4125
+ this.scheduleReconnect();
4086
4126
  });
4087
4127
  });
4088
4128
  }
4089
- async stop() {
4090
- this.socket?.close();
4091
- this.socket = null;
4092
- this.status = {
4093
- installed: true,
4094
- running: false,
4095
- status: "stopped"
4096
- };
4097
- return { ...this.status };
4129
+ scheduleReconnect() {
4130
+ if (this.stopped) return;
4131
+ if (this.reconnectTimer) return;
4132
+ const maxDelay = this.options.maxReconnectDelayMs ?? 3e4;
4133
+ const delay3 = Math.min(maxDelay, 1e3 * 2 ** this.reconnectAttempts);
4134
+ this.reconnectAttempts += 1;
4135
+ this.reconnectTimer = setTimeout(() => {
4136
+ this.reconnectTimer = null;
4137
+ if (this.stopped) return;
4138
+ void this.connect().catch(() => void 0);
4139
+ }, delay3);
4140
+ this.reconnectTimer.unref?.();
4098
4141
  }
4099
4142
  async handleRequest(payload) {
4100
4143
  const fetchImpl = this.options.fetchImpl ?? fetch;
@@ -4456,7 +4499,7 @@ function attachStaticFrontend(webRoot2) {
4456
4499
  }
4457
4500
 
4458
4501
  // src/daemon/service.ts
4459
- import { existsSync as existsSync9, statSync } from "node:fs";
4502
+ import { existsSync as existsSync9, statSync, openSync, closeSync, watchFile } from "node:fs";
4460
4503
  import { mkdir as mkdir4, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
4461
4504
  import { homedir as homedir8 } from "node:os";
4462
4505
  import { dirname as dirname11, join as join11 } from "node:path";
@@ -4485,6 +4528,9 @@ async function installService(context) {
4485
4528
  await runSystemctl(["--user", "enable", "--now", spec.unitName]);
4486
4529
  return await readServiceStatus(context);
4487
4530
  }
4531
+ if (process.platform === "win32") {
4532
+ return await startService(context);
4533
+ }
4488
4534
  throw new Error("service_install_not_supported_on_this_platform");
4489
4535
  }
4490
4536
  async function startService(context) {
@@ -4501,6 +4547,15 @@ async function startService(context) {
4501
4547
  await runSystemctl(["--user", "start", spec.unitName]);
4502
4548
  return await readServiceStatus(context);
4503
4549
  }
4550
+ if (process.platform === "win32") {
4551
+ const spec = buildProcessSpec(context);
4552
+ const existingPid = await readPidFile(spec.pidPath);
4553
+ if (existingPid !== null && isProcessAlive(existingPid)) {
4554
+ return await readServiceStatus(context);
4555
+ }
4556
+ await spawnDetachedDaemon(spec);
4557
+ return await readServiceStatus(context);
4558
+ }
4504
4559
  throw new Error("service_start_not_supported_on_this_platform");
4505
4560
  }
4506
4561
  async function stopService(context) {
@@ -4516,6 +4571,15 @@ async function stopService(context) {
4516
4571
  await runSystemctl(["--user", "stop", spec.unitName]).catch(() => void 0);
4517
4572
  return await readServiceStatus(context);
4518
4573
  }
4574
+ if (process.platform === "win32") {
4575
+ const spec = buildProcessSpec(context);
4576
+ const pid = await readPidFile(spec.pidPath);
4577
+ if (pid !== null && isProcessAlive(pid)) {
4578
+ await killPid(pid).catch(() => void 0);
4579
+ }
4580
+ await removePidFile(spec.pidPath);
4581
+ return await readServiceStatus(context);
4582
+ }
4519
4583
  throw new Error("service_stop_not_supported_on_this_platform");
4520
4584
  }
4521
4585
  async function uninstallService(context) {
@@ -4536,6 +4600,9 @@ async function uninstallService(context) {
4536
4600
  }
4537
4601
  return await readServiceStatus(context);
4538
4602
  }
4603
+ if (process.platform === "win32") {
4604
+ return await stopService(context);
4605
+ }
4539
4606
  throw new Error("service_uninstall_not_supported_on_this_platform");
4540
4607
  }
4541
4608
  async function restartService(context) {
@@ -4551,6 +4618,10 @@ async function restartService(context) {
4551
4618
  await runSystemctl(["--user", "restart", spec.unitName]);
4552
4619
  return await readServiceStatus(context);
4553
4620
  }
4621
+ if (process.platform === "win32") {
4622
+ await stopService(context);
4623
+ return await startService(context);
4624
+ }
4554
4625
  throw new Error("service_restart_not_supported_on_this_platform");
4555
4626
  }
4556
4627
  async function readServiceLogs(context, lines = 120) {
@@ -4598,6 +4669,21 @@ async function readServiceStatus(context) {
4598
4669
  stderrPath: spec.stderrPath
4599
4670
  };
4600
4671
  }
4672
+ if (process.platform === "win32") {
4673
+ const spec = buildProcessSpec(context);
4674
+ const pid = await readPidFile(spec.pidPath);
4675
+ const installed = pid !== null;
4676
+ const running = pid !== null && isProcessAlive(pid);
4677
+ return {
4678
+ manager: "process",
4679
+ installed,
4680
+ running,
4681
+ serviceFilePath: spec.pidPath,
4682
+ label: "claude-codex-wechat",
4683
+ stdoutPath: spec.stdoutPath,
4684
+ stderrPath: spec.stderrPath
4685
+ };
4686
+ }
4601
4687
  throw new Error("service_status_not_supported_on_this_platform");
4602
4688
  }
4603
4689
  function buildLaunchdSpec(context) {
@@ -4624,6 +4710,17 @@ function buildSystemdUserSpec(context) {
4624
4710
  environment: buildServiceEnvironment(context)
4625
4711
  };
4626
4712
  }
4713
+ function buildProcessSpec(context) {
4714
+ const stateDir = join11(homedir8(), ".claude-codex-wechat");
4715
+ return {
4716
+ pidPath: join11(stateDir, "service.pid"),
4717
+ command: [context.nodePath ?? process.execPath, context.cliEntrypointPath, "__daemon"],
4718
+ workingDirectory: homedir8(),
4719
+ stdoutPath: join11(stateDir, "logs", "service.stdout.log"),
4720
+ stderrPath: join11(stateDir, "logs", "service.stderr.log"),
4721
+ environment: buildServiceEnvironment(context)
4722
+ };
4723
+ }
4627
4724
  function buildServiceEnvironment(context) {
4628
4725
  const env = {
4629
4726
  PATH: process.env.PATH ?? "",
@@ -4721,6 +4818,66 @@ async function runLaunchctl(args) {
4721
4818
  async function runSystemctl(args) {
4722
4819
  await execFileAsync("systemctl", args);
4723
4820
  }
4821
+ function isProcessAlive(pid) {
4822
+ if (!Number.isInteger(pid) || pid <= 0) return false;
4823
+ try {
4824
+ process.kill(pid, 0);
4825
+ return true;
4826
+ } catch (error) {
4827
+ return error.code === "EPERM";
4828
+ }
4829
+ }
4830
+ async function readPidFile(pidPath) {
4831
+ if (!existsSync9(pidPath)) return null;
4832
+ try {
4833
+ const raw = (await readFile6(pidPath, "utf8")).trim();
4834
+ const pid = Number.parseInt(raw, 10);
4835
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
4836
+ } catch {
4837
+ return null;
4838
+ }
4839
+ }
4840
+ async function writePidFile(pidPath, pid) {
4841
+ await mkdir4(dirname11(pidPath), { recursive: true });
4842
+ await writeFile5(pidPath, `${pid}
4843
+ `, "utf8");
4844
+ }
4845
+ async function removePidFile(pidPath) {
4846
+ await rm2(pidPath, { force: true });
4847
+ }
4848
+ async function killPid(pid) {
4849
+ if (process.platform === "win32") {
4850
+ await execFileAsync("taskkill", ["/PID", String(pid), "/T", "/F"]);
4851
+ return;
4852
+ }
4853
+ process.kill(pid, "SIGTERM");
4854
+ }
4855
+ async function spawnDetachedDaemon(spec) {
4856
+ await mkdir4(dirname11(spec.stdoutPath), { recursive: true });
4857
+ const outFd = openSync(spec.stdoutPath, "a");
4858
+ const errFd = openSync(spec.stderrPath, "a");
4859
+ try {
4860
+ const [command, ...args] = spec.command;
4861
+ const child = spawn6(command, args, {
4862
+ cwd: spec.workingDirectory,
4863
+ // Windows 分离进程需继承完整 process.env(SystemRoot/APPDATA/PATHEXT 等),
4864
+ // 否则子进程及其拉起的 claude/codex 会异常;spec.environment 仅作 BRIDGE_* 等覆盖层。
4865
+ env: { ...process.env, ...spec.environment },
4866
+ detached: true,
4867
+ windowsHide: true,
4868
+ stdio: ["ignore", outFd, errFd]
4869
+ });
4870
+ if (typeof child.pid !== "number") {
4871
+ throw new Error("service_spawn_failed");
4872
+ }
4873
+ await writePidFile(spec.pidPath, child.pid);
4874
+ child.unref();
4875
+ return child.pid;
4876
+ } finally {
4877
+ closeSync(outFd);
4878
+ closeSync(errFd);
4879
+ }
4880
+ }
4724
4881
  async function ensureFileExists(path, errorCode) {
4725
4882
  if (!existsSync9(path)) throw new Error(errorCode);
4726
4883
  await readFile6(path, "utf8");
@@ -4731,29 +4888,46 @@ async function tailFile(path, lines) {
4731
4888
  return content.split(/\r?\n/).slice(-lines).join("\n").trim();
4732
4889
  }
4733
4890
  async function tailFiles(paths) {
4734
- const readers = paths.filter((path) => existsSync9(path)).map((path) => {
4735
- const rl = createInterface({
4736
- input: createReadStream(path, { encoding: "utf8", start: Math.max(0, fileSizeHint(path) - 8192) }),
4737
- crlfDelay: Infinity
4738
- });
4739
- rl.on("line", (line) => {
4740
- process.stdout.write(`[${path}] ${line}
4891
+ const existing = paths.filter((path) => existsSync9(path));
4892
+ for (const path of existing) {
4893
+ const tail = await tailFile(path, 200);
4894
+ if (tail) process.stdout.write(`[${path}]
4895
+ ${tail}
4741
4896
  `);
4897
+ }
4898
+ if (process.platform === "linux" || process.platform === "darwin") {
4899
+ const child = spawn6("tail", ["-f", ...existing], { stdio: ["ignore", "pipe", "inherit"] });
4900
+ child.stdout.on("data", (chunk) => {
4901
+ process.stdout.write(String(chunk));
4902
+ });
4903
+ await new Promise((resolve2, reject) => {
4904
+ child.on("exit", () => resolve2());
4905
+ child.on("error", reject);
4742
4906
  });
4743
- return rl;
4744
- });
4745
- if (process.platform !== "linux" && process.platform !== "darwin") {
4746
4907
  return;
4747
4908
  }
4748
- const child = spawn6("tail", ["-f", ...paths.filter((path) => existsSync9(path))], { stdio: ["ignore", "pipe", "inherit"] });
4749
- child.stdout.on("data", (chunk) => {
4750
- process.stdout.write(String(chunk));
4751
- });
4752
- await new Promise((resolve2, reject) => {
4753
- child.on("exit", () => resolve2());
4754
- child.on("error", reject);
4755
- }).finally(() => {
4756
- for (const reader of readers) reader.close();
4909
+ const offsets = new Map(existing.map((path) => [path, fileSizeHint(path)]));
4910
+ for (const path of existing) {
4911
+ watchFile(path, { interval: 1e3 }, (curr) => {
4912
+ const prevSize = offsets.get(path) ?? 0;
4913
+ if (curr.size < prevSize) {
4914
+ offsets.set(path, 0);
4915
+ return;
4916
+ }
4917
+ if (curr.size === prevSize) return;
4918
+ const start = prevSize;
4919
+ offsets.set(path, curr.size);
4920
+ const rl = createInterface({
4921
+ input: createReadStream(path, { encoding: "utf8", start, end: curr.size - 1 }),
4922
+ crlfDelay: Infinity
4923
+ });
4924
+ rl.on("line", (line) => {
4925
+ process.stdout.write(`[${path}] ${line}
4926
+ `);
4927
+ });
4928
+ });
4929
+ }
4930
+ await new Promise(() => {
4757
4931
  });
4758
4932
  }
4759
4933
  function fileSizeHint(path) {
@@ -4789,9 +4963,6 @@ async function main() {
4789
4963
  case "tail":
4790
4964
  await cmdTail();
4791
4965
  return;
4792
- case "init":
4793
- cmdInit();
4794
- return;
4795
4966
  case "doctor":
4796
4967
  await cmdDoctor();
4797
4968
  return;
@@ -4857,36 +5028,10 @@ async function cmdDaemon() {
4857
5028
  attachFrontend: attachStaticFrontend(webRoot)
4858
5029
  });
4859
5030
  }
4860
- function cmdInit() {
4861
- const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
4862
- const dir = dirname12(configPath);
4863
- mkdirSync7(dir, { recursive: true });
4864
- if (existsSync10(configPath)) {
4865
- console.log(`\u914D\u7F6E\u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6: ${configPath}`);
4866
- return;
4867
- }
4868
- const template = {
4869
- wechat: {
4870
- enabled: true,
4871
- baseUrl: "https://ilinkai.weixin.qq.com",
4872
- token: "replace-with-weixin-bot-token",
4873
- accountId: "replace-with-weixin-account-id"
4874
- },
4875
- providers: {},
4876
- bridge: {
4877
- defaultProvider: "claude-code",
4878
- defaultWorkspace: process.cwd()
4879
- }
4880
- };
4881
- writeFileSync7(configPath, `${JSON.stringify(template, null, 2)}
4882
- `, "utf8");
4883
- console.log(`\u5DF2\u521B\u5EFA\u914D\u7F6E: ${configPath}`);
4884
- console.log("\u8BF7\u586B\u5165\u5FAE\u4FE1 token / accountId \u540E\u8FD0\u884C: claude-codex-wechat start");
4885
- }
4886
5031
  async function cmdDoctor() {
4887
5032
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
4888
5033
  console.log("claude-codex-wechat doctor\n");
4889
- report("\u914D\u7F6E\u6587\u4EF6", existsSync10(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u8FD0\u884C init \u521B\u5EFA`);
5034
+ report("\u914D\u7F6E\u6587\u4EF6", existsSync10(configPath) ? configPath : `\u7F3A\u5931 (${configPath})\uFF0C\u9996\u6B21 start \u65F6\u81EA\u52A8\u521B\u5EFA`);
4890
5035
  report("\u524D\u7AEF\u4EA7\u7269", existsSync10(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
4891
5036
  const claude = await findExecutable("claude");
4892
5037
  report("claude \u53EF\u6267\u884C", claude ?? "\u672A\u627E\u5230\uFF0C\u9700\u5148\u5B89\u88C5\u5E76\u767B\u5F55 Claude Code");
@@ -4903,7 +5048,7 @@ async function cmdDoctor() {
4903
5048
  function cmdPrintConfig() {
4904
5049
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
4905
5050
  if (!existsSync10(configPath)) {
4906
- console.error(`\u914D\u7F6E\u4E0D\u5B58\u5728: ${configPath}\uFF08\u8FD0\u884C init \u521B\u5EFA\uFF09`);
5051
+ console.error(`\u914D\u7F6E\u4E0D\u5B58\u5728: ${configPath}\uFF08\u9996\u6B21 start \u540E\u81EA\u52A8\u751F\u6210\uFF09`);
4907
5052
  process.exitCode = 1;
4908
5053
  return;
4909
5054
  }
@@ -4949,13 +5094,17 @@ function printUsage() {
4949
5094
  logs \u6253\u5370\u6700\u8FD1\u65E5\u5FD7
4950
5095
  tail \u5B9E\u65F6\u8DDF\u968F\u65E5\u5FD7
4951
5096
  doctor \u68C0\u67E5\u914D\u7F6E\u3001\u524D\u7AEF\u4EA7\u7269\u4E0E claude/codex \u53EF\u6267\u884C\u6587\u4EF6
4952
- init \u5728 ~/.claude-codex-wechat/ \u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E
4953
5097
  uninstall \u5378\u8F7D\u540E\u53F0\u670D\u52A1
4954
5098
  print-config \u6253\u5370\u5F53\u524D\u914D\u7F6E\u6587\u4EF6\u5185\u5BB9
4955
5099
  help \u663E\u793A\u672C\u5E2E\u52A9
4956
5100
 
4957
5101
  \u73AF\u5883\u53D8\u91CF:
4958
5102
  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`);
5103
+ BRIDGE_CONFIG \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.claude-codex-wechat/config.json\uFF09
5104
+
5105
+ \u5E73\u53F0\u8BF4\u660E:
5106
+ macOS \u7528 launchd\u3001Linux \u7528 systemd --user \u6258\u7BA1\uFF0C\u767B\u5F55\u81EA\u542F\u4E14\u5D29\u6E83\u81EA\u52A8\u91CD\u542F\u3002
5107
+ 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
5108
+ \u91CD\u542F\u7535\u8111\u540E\u9700\u91CD\u65B0\u8FD0\u884C start\u3002`);
4960
5109
  }
4961
5110
  await main();
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "claude-codex-wechat",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "private": false,
5
5
  "type": "module",
6
+ "packageManager": "pnpm@11.5.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/izerui/claude-codex-wechat.git"
10
+ },
6
11
  "bin": {
7
12
  "claude-codex-wechat": "./dist/server/cli.js"
8
13
  },
@@ -29,7 +34,7 @@
29
34
  "build": "vite build && node scripts/build-server.mjs",
30
35
  "relay:start": "pnpm --dir relay-server start",
31
36
  "relay:test": "pnpm --dir relay-server test",
32
- "prepublishOnly": "npm version patch --no-git-tag-version"
37
+ "prepublishOnly": "npm run build"
33
38
  },
34
39
  "dependencies": {
35
40
  "@fastify/static": "^9.1.3",