@workclaw/cli 1.0.17 → 1.0.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 +8 -12
- package/dist/{index-39c6v1yS.js → index-K7R_QFg0.js} +111 -88
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ npx @workclaw/cli local
|
|
|
21
21
|
| 命令 | 说明 |
|
|
22
22
|
|------|------|
|
|
23
23
|
| `workclaw local` | 本地账户安装(需要登录) |
|
|
24
|
-
| `workclaw box` |
|
|
24
|
+
| `workclaw box` | 盒子设备安装(无需登录,仅支持 Linux) |
|
|
25
25
|
|
|
26
26
|
### 交互式初始化
|
|
27
27
|
|
|
@@ -52,14 +52,13 @@ npx @workclaw/cli box
|
|
|
52
52
|
|
|
53
53
|
#### box 命令参数
|
|
54
54
|
|
|
55
|
-
| 参数 | 缩写 | 说明
|
|
56
|
-
| ---------------- | -- |
|
|
57
|
-
| --scenario | -s | 安装场景 |
|
|
55
|
+
| 参数 | 缩写 | 说明 |
|
|
56
|
+
| ---------------- | -- | ---- |
|
|
58
57
|
| --env | -e | 环境 (test/prod) |
|
|
59
|
-
| --app-key | 无 | App Key
|
|
60
|
-
| --app-secret | 无 | App Secret
|
|
61
|
-
| --plugin-version | 无 | 插件版本号
|
|
62
|
-
| --debug | 无 | 调试模式
|
|
58
|
+
| --app-key | 无 | App Key |
|
|
59
|
+
| --app-secret | 无 | App Secret |
|
|
60
|
+
| --plugin-version | 无 | 插件版本号 |
|
|
61
|
+
| --debug | 无 | 调试模式 |
|
|
63
62
|
|
|
64
63
|
### 安装场景
|
|
65
64
|
|
|
@@ -122,7 +121,7 @@ workclaw local --scenario linux-local --phone 13800138000 --user-pass your_passw
|
|
|
122
121
|
|
|
123
122
|
### 盒子安装
|
|
124
123
|
|
|
125
|
-
盒子安装适用于不需要用户登录的场景,直接使用 AppKey 和 AppSecret
|
|
124
|
+
盒子安装适用于不需要用户登录的场景,直接使用 AppKey 和 AppSecret 进行安装。**仅支持 Linux 环境**。
|
|
126
125
|
|
|
127
126
|
```bash
|
|
128
127
|
# 基本用法
|
|
@@ -130,9 +129,6 @@ workclaw box --app-key your_app_key --app-secret your_app_secret
|
|
|
130
129
|
|
|
131
130
|
# 指定环境
|
|
132
131
|
workclaw box --app-key your_app_key --app-secret your_app_secret --env prod
|
|
133
|
-
|
|
134
|
-
# 指定场景
|
|
135
|
-
workclaw box --app-key your_app_key --app-secret your_app_secret --scenario linux-local
|
|
136
132
|
```
|
|
137
133
|
|
|
138
134
|
### 指定插件版本
|
|
@@ -29,8 +29,10 @@ const ERROR_CODES$1 = {
|
|
|
29
29
|
LOGIN_FAILED: "LOGIN_FAILED",
|
|
30
30
|
GET_BOUND_CONFIG_FAILED: "GET_BOUND_CONFIG_FAILED",
|
|
31
31
|
NODE_VERSION_LOW: "NODE_VERSION_LOW",
|
|
32
|
+
NODE_NOT_FOUND: "NODE_NOT_FOUND",
|
|
32
33
|
NPM_NOT_FOUND: "NPM_NOT_FOUND",
|
|
33
|
-
NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED"
|
|
34
|
+
NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
|
|
35
|
+
CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED"
|
|
34
36
|
};
|
|
35
37
|
let AppError$1 = class AppError extends Error {
|
|
36
38
|
constructor(code, message) {
|
|
@@ -93,13 +95,38 @@ async function httpPost(url, data, config) {
|
|
|
93
95
|
debugLog(`[HTTP POST] 请求地址: ${url}`);
|
|
94
96
|
debugLog(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
|
|
95
97
|
debugLog(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
try {
|
|
99
|
+
const response = await client.post(url, data, config);
|
|
100
|
+
debugLog(`[HTTP POST] 响应状态: ${response.status}`);
|
|
101
|
+
debugLog(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
|
|
102
|
+
return {
|
|
103
|
+
status: response.status,
|
|
104
|
+
data: response.data
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
const axiosError = error;
|
|
108
|
+
if (axiosError.response) {
|
|
109
|
+
const responseData = axiosError.response.data;
|
|
110
|
+
debugLog(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
|
|
111
|
+
debugLog(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
|
|
112
|
+
debugLog(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
|
|
113
|
+
if (typeof responseData === "string") {
|
|
114
|
+
throw new Error(`请求失败 (${axiosError.response.status}): ${responseData}`);
|
|
115
|
+
} else if (responseData && typeof responseData === "object" && "message" in responseData) {
|
|
116
|
+
throw new Error(`请求失败 (${axiosError.response.status}): ${responseData.message}`);
|
|
117
|
+
} else {
|
|
118
|
+
throw new Error(`请求失败 (${axiosError.response.status}): ${axiosError.response.statusText}`);
|
|
119
|
+
}
|
|
120
|
+
} else if (axiosError.request) {
|
|
121
|
+
debugLog(`[HTTP POST] 未收到响应`);
|
|
122
|
+
debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
|
|
123
|
+
throw new Error(`网络错误: ${axiosError.message}`);
|
|
124
|
+
} else {
|
|
125
|
+
debugLog(`[HTTP POST] 请求配置错误`);
|
|
126
|
+
debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
|
|
127
|
+
throw new Error(`请求配置错误: ${axiosError.message}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
103
130
|
}
|
|
104
131
|
async function login(phone, password, env) {
|
|
105
132
|
const config = getConfig(env);
|
|
@@ -107,18 +134,26 @@ async function login(phone, password, env) {
|
|
|
107
134
|
debugLog("[登录] 开始登录...");
|
|
108
135
|
debugLog(`[登录] 请求地址: ${url}`);
|
|
109
136
|
debugLog(`[登录] 请求参数: phone=${phone}, password=***`);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
try {
|
|
138
|
+
const response = await httpPost(url, {
|
|
139
|
+
phone,
|
|
140
|
+
userPass: password
|
|
141
|
+
});
|
|
142
|
+
const data = response.data;
|
|
143
|
+
debugLog(`[登录] 响应数据: ${JSON.stringify(data)}`);
|
|
144
|
+
if (data.code === 200 && data.data?.token) {
|
|
145
|
+
debugLog("[登录] 登录成功,获取到 token");
|
|
146
|
+
return data.data.token;
|
|
147
|
+
}
|
|
148
|
+
debugLog("[登录] 登录失败");
|
|
149
|
+
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, data.message || "登录失败");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof AppError$1) {
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
debugLog(`[登录] 发生错误: ${error.message}`);
|
|
155
|
+
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, error.message);
|
|
119
156
|
}
|
|
120
|
-
debugLog("[登录] 登录失败");
|
|
121
|
-
throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, data.message || "登录失败");
|
|
122
157
|
}
|
|
123
158
|
async function fetchBoundConfig(token, phone, env) {
|
|
124
159
|
const config = getConfig(env);
|
|
@@ -127,40 +162,48 @@ async function fetchBoundConfig(token, phone, env) {
|
|
|
127
162
|
debugLog(`[获取绑定配置] 请求地址: ${url}`);
|
|
128
163
|
debugLog(`[获取绑定配置] 请求参数: phone=${phone}, localCode=001`);
|
|
129
164
|
debugLog(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
165
|
+
try {
|
|
166
|
+
const response = await httpPost(url, {
|
|
167
|
+
phone,
|
|
168
|
+
localCode: "001"
|
|
169
|
+
}, {
|
|
170
|
+
headers: {
|
|
171
|
+
Authorization: token
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
const data = response.data;
|
|
175
|
+
debugLog(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
|
|
176
|
+
if (data.code === 200 && data.data) {
|
|
177
|
+
const boundConfig = {
|
|
178
|
+
appKey: data.data.app_key,
|
|
179
|
+
appSecret: data.data.app_secret,
|
|
180
|
+
userId: data.data.user_id,
|
|
181
|
+
agentId: data.data.agent_id || data.data.agents?.[0]?.id,
|
|
182
|
+
modelApiKey: data.data.model_api_key,
|
|
183
|
+
modelApiBaseUrl: data.data.model_api_base_url
|
|
184
|
+
};
|
|
185
|
+
debugLog("[获取绑定配置] 获取绑定配置成功");
|
|
186
|
+
debugLog(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
|
|
187
|
+
debugLog(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
|
|
188
|
+
debugLog(`[获取绑定配置] userId: ${boundConfig.userId}`);
|
|
189
|
+
debugLog(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
|
|
190
|
+
debugLog(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
|
|
191
|
+
debugLog(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
|
|
192
|
+
if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
|
|
193
|
+
debugLog("[获取绑定配置] 缺少必要字段");
|
|
194
|
+
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
|
|
195
|
+
}
|
|
196
|
+
return boundConfig;
|
|
136
197
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
appKey: data.data.app_key,
|
|
143
|
-
appSecret: data.data.app_secret,
|
|
144
|
-
userId: data.data.user_id,
|
|
145
|
-
agentId: data.data.agent_id || data.data.agents?.[0]?.id,
|
|
146
|
-
modelApiKey: data.data.model_api_key,
|
|
147
|
-
modelApiBaseUrl: data.data.model_api_base_url
|
|
148
|
-
};
|
|
149
|
-
debugLog("[获取绑定配置] 获取绑定配置成功");
|
|
150
|
-
debugLog(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
|
|
151
|
-
debugLog(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
|
|
152
|
-
debugLog(`[获取绑定配置] userId: ${boundConfig.userId}`);
|
|
153
|
-
debugLog(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
|
|
154
|
-
debugLog(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
|
|
155
|
-
debugLog(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
|
|
156
|
-
if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
|
|
157
|
-
debugLog("[获取绑定配置] 缺少必要字段");
|
|
158
|
-
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
|
|
198
|
+
debugLog("[获取绑定配置] 获取绑定配置失败");
|
|
199
|
+
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (error instanceof AppError$1) {
|
|
202
|
+
throw error;
|
|
159
203
|
}
|
|
160
|
-
|
|
204
|
+
debugLog(`[获取绑定配置] 发生错误: ${error.message}`);
|
|
205
|
+
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, error.message);
|
|
161
206
|
}
|
|
162
|
-
debugLog("[获取绑定配置] 获取绑定配置失败");
|
|
163
|
-
throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
|
|
164
207
|
}
|
|
165
208
|
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
166
209
|
function int2char(n) {
|
|
@@ -4916,34 +4959,17 @@ function checkEnv() {
|
|
|
4916
4959
|
}
|
|
4917
4960
|
async function createBoxCommand(options) {
|
|
4918
4961
|
setDebug(!!options.debug);
|
|
4919
|
-
debugLog("[
|
|
4920
|
-
debugLog(`[
|
|
4962
|
+
debugLog("[盒子安装] 开始处理...");
|
|
4963
|
+
debugLog(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, debug=${options.debug}`);
|
|
4921
4964
|
checkEnv();
|
|
4922
|
-
debugLog("[
|
|
4965
|
+
debugLog("[盒子安装] 环境检查通过");
|
|
4923
4966
|
try {
|
|
4924
|
-
let scenario = options.scenario;
|
|
4925
4967
|
let env = options.env;
|
|
4926
4968
|
let appKey = options.appKey;
|
|
4927
4969
|
let appSecret = options.appSecret;
|
|
4928
4970
|
const questions = [];
|
|
4929
|
-
if (!scenario) {
|
|
4930
|
-
debugLog("[初始化] 需要选择安装场景");
|
|
4931
|
-
questions.push({
|
|
4932
|
-
type: "list",
|
|
4933
|
-
name: "scenario",
|
|
4934
|
-
message: `${nodeEmoji.get("desktop_computer")} 请选择安装场景:`,
|
|
4935
|
-
default: "windows-local",
|
|
4936
|
-
choices: [
|
|
4937
|
-
{ name: `${chalk.green("Windows")} ${chalk.gray("本地安装")}`, value: "windows-local" },
|
|
4938
|
-
{ name: `${chalk.green("macOS")} ${chalk.gray("本地安装")}`, value: "mac-local" },
|
|
4939
|
-
{ name: `${chalk.green("Linux")} ${chalk.gray("本地安装")}`, value: "linux-local" }
|
|
4940
|
-
]
|
|
4941
|
-
});
|
|
4942
|
-
} else {
|
|
4943
|
-
debugLog(`[初始化] 使用命令行参数: scenario=${scenario}`);
|
|
4944
|
-
}
|
|
4945
4971
|
if (!env) {
|
|
4946
|
-
debugLog("[
|
|
4972
|
+
debugLog("[盒子安装] 需要选择环境");
|
|
4947
4973
|
questions.push({
|
|
4948
4974
|
type: "list",
|
|
4949
4975
|
name: "env",
|
|
@@ -4955,10 +4981,10 @@ async function createBoxCommand(options) {
|
|
|
4955
4981
|
]
|
|
4956
4982
|
});
|
|
4957
4983
|
} else {
|
|
4958
|
-
debugLog(`[
|
|
4984
|
+
debugLog(`[盒子安装] 使用命令行参数: env=${env}`);
|
|
4959
4985
|
}
|
|
4960
4986
|
if (!appKey) {
|
|
4961
|
-
debugLog("[
|
|
4987
|
+
debugLog("[盒子安装] 需要输入 AppKey");
|
|
4962
4988
|
questions.push({
|
|
4963
4989
|
type: "input",
|
|
4964
4990
|
name: "appKey",
|
|
@@ -4971,10 +4997,10 @@ async function createBoxCommand(options) {
|
|
|
4971
4997
|
}
|
|
4972
4998
|
});
|
|
4973
4999
|
} else {
|
|
4974
|
-
debugLog("[
|
|
5000
|
+
debugLog("[盒子安装] 使用命令行参数: appKey");
|
|
4975
5001
|
}
|
|
4976
5002
|
if (!appSecret) {
|
|
4977
|
-
debugLog("[
|
|
5003
|
+
debugLog("[盒子安装] 需要输入 AppSecret");
|
|
4978
5004
|
questions.push({
|
|
4979
5005
|
type: "input",
|
|
4980
5006
|
name: "appSecret",
|
|
@@ -4987,29 +5013,26 @@ async function createBoxCommand(options) {
|
|
|
4987
5013
|
}
|
|
4988
5014
|
});
|
|
4989
5015
|
} else {
|
|
4990
|
-
debugLog("[
|
|
5016
|
+
debugLog("[盒子安装] 使用命令行参数: appSecret");
|
|
4991
5017
|
}
|
|
4992
5018
|
if (questions.length > 0) {
|
|
4993
|
-
debugLog(`[
|
|
5019
|
+
debugLog(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
|
|
4994
5020
|
const answers = await inquirer.prompt(questions);
|
|
4995
|
-
debugLog("[
|
|
4996
|
-
scenario = scenario || answers.scenario;
|
|
5021
|
+
debugLog("[盒子安装] 交互式问答完成");
|
|
4997
5022
|
env = env || answers.env || "test";
|
|
4998
5023
|
appKey = appKey || answers.appKey;
|
|
4999
5024
|
appSecret = appSecret || answers.appSecret;
|
|
5000
5025
|
}
|
|
5001
|
-
debugLog(`[
|
|
5002
|
-
debugLog("[
|
|
5026
|
+
debugLog(`[盒子安装] 最终参数: env=${env}`);
|
|
5027
|
+
debugLog("[盒子安装] 创建 BoxInstaller 实例...");
|
|
5003
5028
|
const installer = new BoxInstaller({
|
|
5004
5029
|
appKey,
|
|
5005
5030
|
appSecret,
|
|
5006
|
-
|
|
5007
|
-
env,
|
|
5008
|
-
pluginVersion: options.pluginVersion
|
|
5031
|
+
env
|
|
5009
5032
|
});
|
|
5010
|
-
debugLog("[
|
|
5033
|
+
debugLog("[盒子安装] 开始安装...");
|
|
5011
5034
|
await installer.install();
|
|
5012
|
-
debugLog("[
|
|
5035
|
+
debugLog("[盒子安装] 安装完成");
|
|
5013
5036
|
console.log(installer.getPrefixText() + boxen(
|
|
5014
5037
|
`${nodeEmoji.get("tada")} 插件初始化成功!`,
|
|
5015
5038
|
{
|
|
@@ -5023,7 +5046,7 @@ async function createBoxCommand(options) {
|
|
|
5023
5046
|
}
|
|
5024
5047
|
));
|
|
5025
5048
|
} catch (error) {
|
|
5026
|
-
debugLog(`[
|
|
5049
|
+
debugLog(`[盒子安装] 发生错误: ${error.message}`);
|
|
5027
5050
|
console.error(boxen(
|
|
5028
5051
|
`${chalk.yellow(error.message)}`,
|
|
5029
5052
|
{
|
|
@@ -5040,7 +5063,7 @@ async function createBoxCommand(options) {
|
|
|
5040
5063
|
}
|
|
5041
5064
|
}
|
|
5042
5065
|
function registerCommands(program2) {
|
|
5043
|
-
program2.command("box").description("盒子设备安装(无需登录)").option("-
|
|
5066
|
+
program2.command("box").description("盒子设备安装(无需登录)").option("-e, --env <env>", "环境 (test/prod)").option("--app-key <appKey>", "App Key").option("--app-secret <appSecret>", "App Secret").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--debug", "开启调试日志").action(createBoxCommand);
|
|
5044
5067
|
}
|
|
5045
5068
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
5046
5069
|
const __dirname$1 = dirname(__filename$1);
|
package/dist/index.js
CHANGED