claude-codex-wechat 0.1.17 → 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
@@ -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
 
@@ -3994,6 +3994,9 @@ var RelayTunnelProvider = class {
3994
3994
  running: false,
3995
3995
  status: "stopped"
3996
3996
  };
3997
+ stopped = true;
3998
+ reconnectAttempts = 0;
3999
+ reconnectTimer = null;
3997
4000
  static defaultCreateSocket(url) {
3998
4001
  const socket = new WebSocket(url);
3999
4002
  return {
@@ -4015,13 +4018,34 @@ var RelayTunnelProvider = class {
4015
4018
  return { ...this.status };
4016
4019
  }
4017
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() {
4018
4042
  this.status = {
4019
4043
  ...this.status,
4020
4044
  status: "starting"
4021
4045
  };
4022
4046
  const socket = this.options.createSocket(this.options.serverUrl);
4023
4047
  this.socket = socket;
4024
- return await new Promise((resolve2, reject) => {
4048
+ return new Promise((resolve2, reject) => {
4025
4049
  let settled = false;
4026
4050
  const finishResolve = (value) => {
4027
4051
  if (settled) return;
@@ -4052,9 +4076,11 @@ var RelayTunnelProvider = class {
4052
4076
  error: message
4053
4077
  };
4054
4078
  finishReject(new Error(message));
4079
+ this.scheduleReconnect();
4055
4080
  return;
4056
4081
  }
4057
4082
  if (payload?.type === "registered") {
4083
+ this.reconnectAttempts = 0;
4058
4084
  const publicUrl = typeof payload?.publicUrl === "string" && payload.publicUrl ? payload.publicUrl : typeof payload?.token === "string" ? `${derivePublicBaseUrl(this.options.serverUrl)}/${payload.token}` : void 0;
4059
4085
  this.status = {
4060
4086
  installed: true,
@@ -4070,6 +4096,10 @@ var RelayTunnelProvider = class {
4070
4096
  }
4071
4097
  });
4072
4098
  socket.on("close", () => {
4099
+ if (this.stopped) {
4100
+ finishReject(new Error("relay_stopped"));
4101
+ return;
4102
+ }
4073
4103
  this.status = {
4074
4104
  ...this.status,
4075
4105
  running: false,
@@ -4077,8 +4107,13 @@ var RelayTunnelProvider = class {
4077
4107
  error: "relay_disconnected"
4078
4108
  };
4079
4109
  finishReject(new Error("relay_disconnected"));
4110
+ this.scheduleReconnect();
4080
4111
  });
4081
4112
  socket.on("error", (error) => {
4113
+ if (this.stopped) {
4114
+ finishReject(new Error("relay_stopped"));
4115
+ return;
4116
+ }
4082
4117
  const message = error instanceof Error ? error.message : String(error);
4083
4118
  this.status = {
4084
4119
  ...this.status,
@@ -4087,18 +4122,22 @@ var RelayTunnelProvider = class {
4087
4122
  error: message
4088
4123
  };
4089
4124
  finishReject(error);
4125
+ this.scheduleReconnect();
4090
4126
  });
4091
4127
  });
4092
4128
  }
4093
- async stop() {
4094
- this.socket?.close();
4095
- this.socket = null;
4096
- this.status = {
4097
- installed: true,
4098
- running: false,
4099
- status: "stopped"
4100
- };
4101
- 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?.();
4102
4141
  }
4103
4142
  async handleRequest(payload) {
4104
4143
  const fetchImpl = this.options.fetchImpl ?? fetch;
@@ -4924,9 +4963,6 @@ async function main() {
4924
4963
  case "tail":
4925
4964
  await cmdTail();
4926
4965
  return;
4927
- case "init":
4928
- cmdInit();
4929
- return;
4930
4966
  case "doctor":
4931
4967
  await cmdDoctor();
4932
4968
  return;
@@ -4992,37 +5028,10 @@ async function cmdDaemon() {
4992
5028
  attachFrontend: attachStaticFrontend(webRoot)
4993
5029
  });
4994
5030
  }
4995
- function cmdInit() {
4996
- const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
4997
- const dir = dirname12(configPath);
4998
- mkdirSync7(dir, { recursive: true });
4999
- if (existsSync10(configPath)) {
5000
- console.log(`\u914D\u7F6E\u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6: ${configPath}`);
5001
- return;
5002
- }
5003
- const template = {
5004
- wechat: {
5005
- enabled: true,
5006
- baseUrl: "https://ilinkai.weixin.qq.com",
5007
- token: "replace-with-weixin-bot-token",
5008
- accountId: "replace-with-weixin-account-id"
5009
- },
5010
- providers: {},
5011
- bridge: {
5012
- defaultProvider: "claude-code",
5013
- defaultWorkspace: process.cwd()
5014
- }
5015
- };
5016
- writeFileSync7(configPath, `${JSON.stringify(template, null, 2)}
5017
- `, "utf8");
5018
- console.log(`\u5DF2\u521B\u5EFA\u914D\u7F6E: ${configPath}`);
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");
5021
- }
5022
5031
  async function cmdDoctor() {
5023
5032
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
5024
5033
  console.log("claude-codex-wechat doctor\n");
5025
- 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`);
5026
5035
  report("\u524D\u7AEF\u4EA7\u7269", existsSync10(webRoot) ? webRoot : `\u7F3A\u5931 (${webRoot})`);
5027
5036
  const claude = await findExecutable("claude");
5028
5037
  report("claude \u53EF\u6267\u884C", claude ?? "\u672A\u627E\u5230\uFF0C\u9700\u5148\u5B89\u88C5\u5E76\u767B\u5F55 Claude Code");
@@ -5039,7 +5048,7 @@ async function cmdDoctor() {
5039
5048
  function cmdPrintConfig() {
5040
5049
  const configPath = process.env.BRIDGE_CONFIG ?? defaultConfigPath();
5041
5050
  if (!existsSync10(configPath)) {
5042
- 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`);
5043
5052
  process.exitCode = 1;
5044
5053
  return;
5045
5054
  }
@@ -5085,7 +5094,6 @@ function printUsage() {
5085
5094
  logs \u6253\u5370\u6700\u8FD1\u65E5\u5FD7
5086
5095
  tail \u5B9E\u65F6\u8DDF\u968F\u65E5\u5FD7
5087
5096
  doctor \u68C0\u67E5\u914D\u7F6E\u3001\u524D\u7AEF\u4EA7\u7269\u4E0E claude/codex \u53EF\u6267\u884C\u6587\u4EF6
5088
- init \u5728 ~/.claude-codex-wechat/ \u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E
5089
5097
  uninstall \u5378\u8F7D\u540E\u53F0\u670D\u52A1
5090
5098
  print-config \u6253\u5370\u5F53\u524D\u914D\u7F6E\u6587\u4EF6\u5185\u5BB9
5091
5099
  help \u663E\u793A\u672C\u5E2E\u52A9
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "claude-codex-wechat",
3
- "version": "0.1.17",
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",