claude-codex-wechat 0.1.17 → 0.1.19
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 +11 -21
- package/dist/server/cli.js +52 -44
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -64,26 +64,24 @@ pnpm add -g claude-codex-wechat
|
|
|
64
64
|
安装后按以下顺序跑通:
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
# 1.
|
|
68
|
-
|
|
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
|
-
#
|
|
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
|
{
|
package/dist/server/cli.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
|
|
4094
|
-
this.
|
|
4095
|
-
this.
|
|
4096
|
-
this.
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
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\
|
|
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\
|
|
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.
|
|
3
|
+
"version": "0.1.19",
|
|
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
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
33
38
|
},
|
|
34
39
|
"dependencies": {
|
|
35
40
|
"@fastify/static": "^9.1.3",
|