@workclaw/cli 1.0.27 → 1.0.30

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.
Files changed (77) hide show
  1. package/README.md +119 -161
  2. package/dist/bin/cli.d.ts +3 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/box/error/index.d.ts +30 -0
  5. package/dist/box/error/index.d.ts.map +1 -0
  6. package/dist/box/index.d.ts +3 -0
  7. package/dist/box/index.d.ts.map +1 -0
  8. package/dist/box/installer/index.d.ts +2 -0
  9. package/dist/box/installer/index.d.ts.map +1 -0
  10. package/dist/box/installer/installer.d.ts +16 -0
  11. package/dist/box/installer/installer.d.ts.map +1 -0
  12. package/dist/box/src/box.d.ts +3 -0
  13. package/dist/box/src/box.d.ts.map +1 -0
  14. package/dist/box/types/index.d.ts +30 -0
  15. package/dist/box/types/index.d.ts.map +1 -0
  16. package/dist/box/utils/index.d.ts +2 -0
  17. package/dist/box/utils/index.d.ts.map +1 -0
  18. package/dist/box/utils/path.d.ts +2 -0
  19. package/dist/box/utils/path.d.ts.map +1 -0
  20. package/dist/command/index.d.ts +3 -0
  21. package/dist/command/index.d.ts.map +1 -0
  22. package/dist/command/src/base-command.d.ts +12 -0
  23. package/dist/command/src/base-command.d.ts.map +1 -0
  24. package/dist/command/types/index.d.ts +14 -0
  25. package/dist/command/types/index.d.ts.map +1 -0
  26. package/dist/{index-BWLa_Wav.js → index-DCWFh-f4.js} +1461 -1689
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.js +1 -1
  29. package/dist/lib/command/base-command.d.ts +16 -0
  30. package/dist/lib/command/base-command.d.ts.map +1 -0
  31. package/dist/lib/index.d.ts +2 -0
  32. package/dist/lib/index.d.ts.map +1 -0
  33. package/dist/local/apis/index.d.ts +11 -0
  34. package/dist/local/apis/index.d.ts.map +1 -0
  35. package/dist/local/error/index.d.ts +33 -0
  36. package/dist/local/error/index.d.ts.map +1 -0
  37. package/dist/local/index.d.ts +3 -0
  38. package/dist/local/index.d.ts.map +1 -0
  39. package/dist/local/installer/index.d.ts +2 -0
  40. package/dist/local/installer/index.d.ts.map +1 -0
  41. package/dist/local/installer/installer.d.ts +16 -0
  42. package/dist/local/installer/installer.d.ts.map +1 -0
  43. package/dist/local/src/local.d.ts +3 -0
  44. package/dist/local/src/local.d.ts.map +1 -0
  45. package/dist/local/types/index.d.ts +41 -0
  46. package/dist/local/types/index.d.ts.map +1 -0
  47. package/dist/local/utils/crypto.d.ts +2 -0
  48. package/dist/local/utils/crypto.d.ts.map +1 -0
  49. package/dist/local/utils/index.d.ts +4 -0
  50. package/dist/local/utils/index.d.ts.map +1 -0
  51. package/dist/local/utils/path.d.ts +9 -0
  52. package/dist/local/utils/path.d.ts.map +1 -0
  53. package/dist/shared/config/index.d.ts +48 -0
  54. package/dist/shared/config/index.d.ts.map +1 -0
  55. package/dist/shared/utils/debug.d.ts +4 -0
  56. package/dist/shared/utils/debug.d.ts.map +1 -0
  57. package/dist/shared/utils/index.d.ts +4 -0
  58. package/dist/shared/utils/index.d.ts.map +1 -0
  59. package/dist/shared/utils/logger.d.ts +14 -0
  60. package/dist/shared/utils/logger.d.ts.map +1 -0
  61. package/dist/utils/config-default.d.ts +28 -0
  62. package/dist/utils/config-default.d.ts.map +1 -0
  63. package/dist/utils/config.d.ts +21 -0
  64. package/dist/utils/config.d.ts.map +1 -0
  65. package/dist/utils/crypto.d.ts +13 -0
  66. package/dist/utils/crypto.d.ts.map +1 -0
  67. package/dist/utils/error.d.ts +34 -0
  68. package/dist/utils/error.d.ts.map +1 -0
  69. package/dist/utils/http.d.ts +27 -0
  70. package/dist/utils/http.d.ts.map +1 -0
  71. package/dist/utils/index.d.ts +8 -0
  72. package/dist/utils/index.d.ts.map +1 -0
  73. package/dist/utils/logger.d.ts +16 -0
  74. package/dist/utils/logger.d.ts.map +1 -0
  75. package/dist/utils/path.d.ts +23 -0
  76. package/dist/utils/path.d.ts.map +1 -0
  77. package/package.json +2 -4
@@ -3,15 +3,13 @@ import path, { resolve, dirname } from "node:path";
3
3
  import process$1 from "node:process";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { Command } from "commander";
6
- import { execSync } from "node:child_process";
6
+ import { exec, execSync } from "node:child_process";
7
7
  import boxen from "boxen";
8
8
  import chalk from "chalk";
9
9
  import inquirer from "inquirer";
10
- import * as nodeEmoji from "node-emoji";
11
10
  import semver from "semver";
12
11
  import fs from "node:fs/promises";
13
12
  import ora from "ora";
14
- import * as tar from "tar";
15
13
  import axios from "axios";
16
14
  import "node:os";
17
15
  let isDebug = false;
@@ -24,17 +22,11 @@ function debugLog(...args) {
24
22
  }
25
23
  }
26
24
  const ERROR_CODES$1 = {
27
- PHONE_REQUIRED: "PHONE_REQUIRED",
28
- USER_PASS_REQUIRED: "USER_PASS_REQUIRED",
29
- LOGIN_FAILED: "LOGIN_FAILED",
30
- GET_BOUND_CONFIG_FAILED: "GET_BOUND_CONFIG_FAILED",
25
+ APP_KEY_REQUIRED: "APP_KEY_REQUIRED",
26
+ APP_SECRET_REQUIRED: "APP_SECRET_REQUIRED",
31
27
  NODE_VERSION_LOW: "NODE_VERSION_LOW",
32
- NODE_NOT_FOUND: "NODE_NOT_FOUND",
33
28
  NPM_NOT_FOUND: "NPM_NOT_FOUND",
34
- NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
35
- CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED",
36
- HTTP_ERROR: "HTTP_ERROR",
37
- NETWORK_ERROR: "NETWORK_ERROR"
29
+ NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED"
38
30
  };
39
31
  let AppError$1 = class AppError extends Error {
40
32
  constructor(code, message) {
@@ -84,305 +76,829 @@ const TEST_CONFIG = {
84
76
  function getConfig(env) {
85
77
  return env === "test" ? TEST_CONFIG : CONFIG;
86
78
  }
87
- function createHttpClient() {
88
- return axios.create({
89
- timeout: 1e4,
90
- headers: {
91
- "Content-Type": "application/json"
92
- }
93
- });
79
+ function getHomeDir$1() {
80
+ return process$1.env.HOME || process$1.env.USERPROFILE || "";
94
81
  }
95
- async function httpPost(url, data, config) {
96
- const client = createHttpClient();
97
- debugLog(`[HTTP POST] 请求地址: ${url}`);
98
- debugLog(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
99
- debugLog(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
100
- try {
101
- const response = await client.post(url, data, config);
102
- debugLog(`[HTTP POST] 响应状态: ${response.status}`);
103
- debugLog(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
104
- return {
105
- status: response.status,
106
- data: response.data
107
- };
108
- } catch (error) {
109
- const axiosError = error;
110
- if (axiosError.response) {
111
- const responseData = axiosError.response.data;
112
- debugLog(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
113
- debugLog(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
114
- debugLog(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
115
- if (typeof responseData === "string") {
116
- throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData}`);
117
- } else if (responseData && typeof responseData === "object" && "message" in responseData) {
118
- throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData.message}`);
82
+ const PLUGIN_PACKAGE_NAME$1 = "@workclaw/openclaw-workclaw";
83
+ function execAsync$1(command, options) {
84
+ return new Promise((resolve2, reject) => {
85
+ exec(command, { cwd: options.cwd, timeout: options.timeout }, (error, stdout, stderr) => {
86
+ if (error) {
87
+ reject(new Error(stderr || error.message));
119
88
  } else {
120
- throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${axiosError.response.statusText}`);
89
+ resolve2(stdout);
121
90
  }
122
- } else if (axiosError.request) {
123
- debugLog(`[HTTP POST] 未收到响应`);
124
- debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
125
- throw new AppError$1(ERROR_CODES$1.NETWORK_ERROR, `网络错误: ${axiosError.message}`);
126
- } else {
127
- debugLog(`[HTTP POST] 请求配置错误`);
128
- debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
129
- throw new AppError$1(ERROR_CODES$1.HTTP_ERROR, `请求配置错误: ${axiosError.message}`);
130
- }
131
- }
132
- }
133
- async function login(phone, password, env) {
134
- const config = getConfig(env);
135
- const url = `${config.API.TUZAI_BASE_URL}/user/login/pass`;
136
- debugLog("[登录] 开始登录...");
137
- debugLog(`[登录] 请求地址: ${url}`);
138
- debugLog(`[登录] 请求参数: phone=${phone}, password=***`);
139
- try {
140
- const response = await httpPost(url, {
141
- phone,
142
- userPass: password
143
91
  });
144
- const data = response.data;
145
- debugLog(`[登录] 响应数据: ${JSON.stringify(data)}`);
146
- if (data.code === 200 && data.data?.token) {
147
- debugLog("[登录] 登录成功,获取到 token");
148
- return data.data.token;
149
- }
150
- debugLog("[登录] 登录失败");
151
- throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, data.message || "登录失败");
152
- } catch (error) {
153
- if (error instanceof AppError$1) {
154
- throw error;
155
- }
156
- debugLog(`[登录] 发生错误: ${error.message}`);
157
- throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, error.message);
158
- }
92
+ });
159
93
  }
160
- async function fetchBoundConfig(token, phone, env) {
161
- const config = getConfig(env);
162
- const url = `${config.API.TUZAI_BASE_URL}/work-bot/local/bound/init`;
163
- debugLog("[获取绑定配置] 开始获取绑定配置...");
164
- debugLog(`[获取绑定配置] 请求地址: ${url}`);
165
- debugLog(`[获取绑定配置] 请求参数: phone=${phone}, localCode=001`);
166
- debugLog(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
167
- try {
168
- const response = await httpPost(url, {
169
- phone,
170
- localCode: "001"
171
- }, {
172
- headers: {
173
- Authorization: token
174
- }
175
- });
176
- const data = response.data;
177
- debugLog(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
178
- if (data.code === 200 && data.data) {
179
- const boundConfig = {
180
- appKey: data.data.app_key,
181
- appSecret: data.data.app_secret,
182
- userId: data.data.user_id,
183
- agentId: data.data.agent_id || data.data.agents?.[0]?.id,
184
- modelApiKey: data.data.model_api_key,
185
- modelApiBaseUrl: data.data.model_api_base_url
186
- };
187
- debugLog("[获取绑定配置] 获取绑定配置成功");
188
- debugLog(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
189
- debugLog(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
190
- debugLog(`[获取绑定配置] userId: ${boundConfig.userId}`);
191
- debugLog(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
192
- debugLog(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
193
- debugLog(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
194
- if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
195
- debugLog("[获取绑定配置] 缺少必要字段");
196
- throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
197
- }
198
- return boundConfig;
199
- }
200
- debugLog("[获取绑定配置] 获取绑定配置失败");
201
- throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
202
- } catch (error) {
203
- if (error instanceof AppError$1) {
204
- throw error;
94
+ function deepMerge$1(target, source) {
95
+ const result = { ...target };
96
+ for (const key in source) {
97
+ const sourceValue = source[key];
98
+ const targetValue = target[key];
99
+ if (sourceValue !== void 0 && sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
100
+ result[key] = deepMerge$1(targetValue, sourceValue);
101
+ } else if (sourceValue !== void 0) {
102
+ result[key] = sourceValue;
205
103
  }
206
- debugLog(`[获取绑定配置] 发生错误: ${error.message}`);
207
- throw new AppError$1(ERROR_CODES$1.GET_BOUND_CONFIG_FAILED, error.message);
208
104
  }
105
+ return result;
209
106
  }
210
- var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
211
- function int2char(n) {
212
- return BI_RM.charAt(n);
213
- }
214
- function op_and(x, y) {
215
- return x & y;
216
- }
217
- function op_or(x, y) {
218
- return x | y;
219
- }
220
- function op_xor(x, y) {
221
- return x ^ y;
222
- }
223
- function op_andnot(x, y) {
224
- return x & ~y;
225
- }
226
- function lbit(x) {
227
- if (x == 0) {
228
- return -1;
107
+ class BoxInstaller {
108
+ constructor(config) {
109
+ this.config = config;
110
+ this.spinner = ora({ color: "cyan" }).start();
229
111
  }
230
- var r = 0;
231
- if ((x & 65535) == 0) {
232
- x >>= 16;
233
- r += 16;
112
+ spinner;
113
+ prefixText = "";
114
+ validateConfig() {
115
+ debugLog("[验证配置] 检查 appKey 和 appSecret...");
116
+ if (!this.config.appKey) {
117
+ throw new AppError$1(ERROR_CODES$1.APP_KEY_REQUIRED, "AppKey 不能为空,请使用 --app-key 参数");
118
+ }
119
+ if (!this.config.appSecret) {
120
+ throw new AppError$1(ERROR_CODES$1.APP_SECRET_REQUIRED, "AppSecret 不能为空,请使用 --app-secret 参数");
121
+ }
122
+ debugLog("[验证配置] 配置检查通过");
234
123
  }
235
- if ((x & 255) == 0) {
236
- x >>= 8;
237
- r += 8;
124
+ getPaths() {
125
+ const home = getHomeDir$1();
126
+ const openclawDir = path.join(home, ".openclaw");
127
+ const extensionsDir = path.join(openclawDir, "extensions");
128
+ const targetDir = path.join(extensionsDir, "openclaw-workclaw");
129
+ const configFile = path.join(openclawDir, "openclaw.json");
130
+ const workspaceDir = path.join(openclawDir, "workspace");
131
+ const tempDir = path.join(openclawDir, ".temp");
132
+ return {
133
+ home,
134
+ extensions: extensionsDir,
135
+ target: targetDir,
136
+ config: configFile,
137
+ workspace: workspaceDir,
138
+ temp: tempDir
139
+ };
238
140
  }
239
- if ((x & 15) == 0) {
240
- x >>= 4;
241
- r += 4;
141
+ updateSpinner(text) {
142
+ this.spinner.prefixText = this.prefixText;
143
+ this.spinner.text = chalk.cyan(text);
144
+ debugLog(`[Spinner] ${text}`);
242
145
  }
243
- if ((x & 3) == 0) {
244
- x >>= 2;
245
- r += 2;
146
+ getPrefixText() {
147
+ return this.prefixText;
246
148
  }
247
- if ((x & 1) == 0) {
248
- ++r;
149
+ async install() {
150
+ try {
151
+ debugLog("[盒子安装] 开始安装...");
152
+ this.validateConfig();
153
+ this.prefixText += chalk.green(` ✓ 配置验证完成
154
+ `);
155
+ this.updateSpinner("配置验证完成");
156
+ const paths = this.getPaths();
157
+ await this.doCleanOldFiles(paths);
158
+ await this.doDownloadFromNpm();
159
+ await this.doUpdateConfig(paths);
160
+ this.spinner.stop();
161
+ debugLog("[盒子安装] 安装完成");
162
+ } catch (error) {
163
+ this.spinner.stop();
164
+ debugLog(`[盒子安装] 安装失败: ${error.message}`);
165
+ throw error;
166
+ }
249
167
  }
250
- return r;
251
- }
252
- function cbit(x) {
253
- var r = 0;
254
- while (x != 0) {
255
- x &= x - 1;
256
- ++r;
168
+ async doCleanOldFiles(paths) {
169
+ debugLog("[清理旧版本] 开始清理旧版本...");
170
+ this.prefixText += chalk.green(` ✓ 开始清理旧版本
171
+ `);
172
+ this.updateSpinner("正在清理旧版本...");
173
+ try {
174
+ await fs.access(paths.target);
175
+ debugLog("[清理旧版本] 删除旧版本目录...");
176
+ await fs.rm(paths.target, { recursive: true, force: true });
177
+ this.prefixText += chalk.green(` ✓ 旧版本清理成功
178
+ `);
179
+ debugLog("[清理旧版本] 旧版本清理成功");
180
+ } catch {
181
+ debugLog("[清理旧版本] 无旧版本需要清理");
182
+ this.prefixText += chalk.green(` ✓ 无旧版本需要清理
183
+ `);
184
+ }
185
+ try {
186
+ await fs.access(paths.temp);
187
+ await fs.rm(paths.temp, { recursive: true, force: true });
188
+ } catch {
189
+ debugLog("[清理旧版本] 无临时目录需要清理");
190
+ }
257
191
  }
258
- return r;
259
- }
260
- var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
261
- var b64pad = "=";
262
- function hex2b64(h) {
263
- var i;
264
- var c;
265
- var ret = "";
266
- for (i = 0; i + 3 <= h.length; i += 3) {
267
- c = parseInt(h.substring(i, i + 3), 16);
268
- ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
192
+ async doDownloadFromNpm() {
193
+ debugLog("[安装插件] 开始安装插件...");
194
+ this.prefixText += chalk.green(` ✓ 开始安装插件
195
+ `);
196
+ this.spinner.prefixText = this.prefixText;
197
+ this.spinner.text = chalk.cyan("正在安装插件...");
198
+ try {
199
+ await execAsync$1(
200
+ `openclaw plugins install ${PLUGIN_PACKAGE_NAME$1} --dangerously-force-unsafe-install`,
201
+ { timeout: 12e4 }
202
+ );
203
+ debugLog("[安装插件] openclaw plugins install 执行成功");
204
+ this.prefixText += chalk.green(` ✓ 插件安装完成
205
+ `);
206
+ } catch (error) {
207
+ const errorMsg = error.message || "未知错误";
208
+ debugLog(`[安装插件] 安装失败: ${errorMsg}`);
209
+ this.prefixText += chalk.red(`✗ 安装失败
210
+ `);
211
+ throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `插件安装失败: ${errorMsg}`);
212
+ }
269
213
  }
270
- if (i + 1 == h.length) {
271
- c = parseInt(h.substring(i, i + 1), 16);
272
- ret += b64map.charAt(c << 2);
273
- } else if (i + 2 == h.length) {
274
- c = parseInt(h.substring(i, i + 2), 16);
275
- ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
214
+ async doUpdateConfig(paths) {
215
+ debugLog("[更新配置] 开始更新配置...");
216
+ this.prefixText += chalk.green(` ✓ 开始更新配置
217
+ `);
218
+ this.updateSpinner("正在生成配置...");
219
+ let originalConfig = {};
220
+ try {
221
+ const content = await fs.readFile(paths.config, "utf-8");
222
+ originalConfig = JSON.parse(content);
223
+ debugLog("[更新配置] 读取原有配置成功");
224
+ } catch {
225
+ debugLog("[更新配置] 无原有配置");
226
+ }
227
+ const config = getConfig(this.config.env);
228
+ const newConfig = {
229
+ // diagnostics: 诊断配置
230
+ diagnostics: {
231
+ // 启用诊断功能
232
+ enabled: true,
233
+ // 启用所有诊断标志 ['*'] 表示全部,[] 表示禁用所有
234
+ flags: ["*"]
235
+ },
236
+ // browser: 浏览器配置
237
+ browser: {
238
+ // 禁用浏览器工具
239
+ enabled: false
240
+ },
241
+ // models: 模型配置
242
+ models: {
243
+ // 配置合并模式:'merge' 合并 | 'replace' 替换
244
+ mode: "merge",
245
+ providers: {
246
+ "siliconflow-minimax": {
247
+ // 模型 API 基础地址
248
+ baseUrl: config.MODEL_BASE_URL,
249
+ // API 密钥(留空,由外部提供)
250
+ apiKey: "",
251
+ // API 类型:'openai-completions' | 'openai-chat' 等
252
+ api: "openai-completions",
253
+ // 是否使用 Authorization header 认证
254
+ authHeader: true,
255
+ models: [{
256
+ // 模型 ID(provider/model 格式)
257
+ id: "Pro/MiniMaxAI/MiniMax-M2.5",
258
+ // 模型显示名称
259
+ name: "MiniMax-M2.5",
260
+ // 是否启用推理能力
261
+ reasoning: false,
262
+ // 支持的输入类型:['text'] | ['text', 'image']
263
+ input: ["text"],
264
+ // 价格(0 表示免费或未设置)
265
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
266
+ // 上下文窗口大小(token)
267
+ contextWindow: 2e5,
268
+ // 最大输出 token 数
269
+ maxTokens: 65536
270
+ }]
271
+ }
272
+ }
273
+ },
274
+ // agents: 代理配置
275
+ agents: {
276
+ defaults: {
277
+ // 默认使用的模型
278
+ model: { primary: "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5" },
279
+ models: {
280
+ "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5": {
281
+ // 模型别名,用于显示
282
+ alias: "Pro/MiniMaxAI/MiniMax-M2.5"
283
+ }
284
+ },
285
+ // 工作区目录路径
286
+ workspace: paths.workspace,
287
+ // 会话压缩模式:'safeguard' 保守模式
288
+ compaction: { mode: "safeguard" },
289
+ // 详细程度:'full' | 'short' | 'off'
290
+ verboseDefault: "full",
291
+ // 最大并发任务数
292
+ maxConcurrent: 4,
293
+ // 子代理最大并发数
294
+ subagents: { maxConcurrent: 8 }
295
+ },
296
+ // 代理列表
297
+ list: [{ id: "main", workspace: paths.workspace }]
298
+ },
299
+ // tools: 工具配置
300
+ tools: {
301
+ // 禁用的工具列表(优先于 allow)
302
+ deny: ["image", "web_search", "web_fetch"],
303
+ // 图像分析工具
304
+ media: { image: { enabled: false } },
305
+ // 网络搜索和抓取工具
306
+ web: { search: { enabled: false }, fetch: { enabled: false } },
307
+ // 提升权限工具(host=gateway)
308
+ elevated: { enabled: true, allowFrom: { webchat: ["*"] } },
309
+ // exec 工具安全级别:'deny' | 'allowlist' | 'full'
310
+ exec: { security: "full" }
311
+ },
312
+ // bindings: 绑定配置
313
+ bindings: [{
314
+ // 绑定的代理 ID
315
+ agentId: "main",
316
+ // 匹配的通道和账户
317
+ match: { channel: "openclaw-workclaw", accountId: "default" }
318
+ }],
319
+ // messages: 消息配置
320
+ messages: {
321
+ // 消息确认范围
322
+ ackReactionScope: "group-mentions"
323
+ },
324
+ // commands: 命令配置
325
+ commands: {
326
+ // 本机命令:'auto' | 'on' | 'off'
327
+ native: "auto",
328
+ // 本机技能:'auto' | 'on' | 'off'
329
+ nativeSkills: "auto",
330
+ // 是否允许重启命令
331
+ restart: true,
332
+ // 所有者显示格式:'raw' | 'name' | 'hidden'
333
+ ownerDisplay: "raw"
334
+ },
335
+ // session: 会话配置
336
+ session: {
337
+ // DM 作用域
338
+ dmScope: "per-account-channel-peer"
339
+ },
340
+ // hooks: 钩子配置
341
+ hooks: {
342
+ internal: {
343
+ // 启用内部钩子
344
+ enabled: true,
345
+ entries: {
346
+ // 启动 Markdown 钩子
347
+ "boot-md": { enabled: true },
348
+ // 引导额外文件钩子
349
+ "bootstrap-extra-files": { enabled: true },
350
+ // 命令日志钩子
351
+ "command-logger": { enabled: true },
352
+ // 会话记忆钩子
353
+ "session-memory": { enabled: true }
354
+ }
355
+ }
356
+ },
357
+ // channels: 通道配置
358
+ channels: {
359
+ "openclaw-workclaw": {
360
+ // 启用通道
361
+ enabled: true,
362
+ // 连接模式:'websocket' | 'http'
363
+ connectionMode: "websocket",
364
+ // 应用密钥
365
+ appKey: this.config.appKey,
366
+ // 应用密钥
367
+ appSecret: this.config.appSecret,
368
+ // API 基础 URL
369
+ baseUrl: this.config.baseUrl || config.DEFAULT_BASE_URL,
370
+ // WebSocket URL
371
+ websocketUrl: this.config.wsUrl || config.DEFAULT_WS_URL,
372
+ // 允许不安全的 TLS 连接
373
+ allowInsecureTls: true,
374
+ // 允许原始 JSON 载荷
375
+ allowRawJsonPayload: true,
376
+ // 用户 ID
377
+ userId: "",
378
+ // DM 策略
379
+ dmPolicy: "open",
380
+ // 允许所有来源
381
+ allowFrom: ["*"],
382
+ accounts: {
383
+ // 账户配置(agentId 为空表示待分配)
384
+ default: { enabled: true, agentId: "" }
385
+ }
386
+ }
387
+ },
388
+ // gateway: 网关配置
389
+ gateway: {
390
+ // 网关模式:'local' | 'hosted'
391
+ mode: "local",
392
+ // 网关端口
393
+ port: 18789,
394
+ // 绑定地址:'loopback' | 'lan' | 'all'
395
+ bind: "loopback",
396
+ // 认证模式(token字段未设置,是因为需要使用原始配置的token)
397
+ auth: {
398
+ mode: "token"
399
+ },
400
+ // Tailscale 配置
401
+ tailscale: { mode: "off", resetOnExit: false },
402
+ nodes: {
403
+ // 节点上禁止的命令
404
+ denyCommands: [
405
+ "camera.snap",
406
+ "camera.clip",
407
+ "screen.record",
408
+ "contacts.add",
409
+ "calendar.add",
410
+ "reminders.add",
411
+ "sms.send",
412
+ "sms.search"
413
+ ]
414
+ },
415
+ controlUi: {
416
+ // 允许不安全认证
417
+ allowInsecureAuth: true,
418
+ // 禁用设备认证(仅用于开发)
419
+ dangerouslyDisableDeviceAuth: true,
420
+ // 允许 Host 头源回退
421
+ dangerouslyAllowHostHeaderOriginFallback: true,
422
+ // 允许的源
423
+ allowedOrigins: ["http://localhost:18789", "http://127.0.0.1:18789"]
424
+ }
425
+ },
426
+ // skills: 技能配置
427
+ skills: {
428
+ // 技能加载监视模式
429
+ load: { watch: true }
430
+ },
431
+ // logging: 日志配置
432
+ logging: {
433
+ // 日志级别:'debug' | 'info' | 'warn' | 'error'
434
+ level: "info",
435
+ // 控制台日志级别
436
+ consoleLevel: "info",
437
+ // 控制台样式:'pretty' | 'basic' | 'raw'
438
+ consoleStyle: "pretty",
439
+ // 敏感信息脱敏:'off' | 'keys' | 'all'
440
+ redactSensitive: "off",
441
+ // 日志文件路径(空表示不写入文件)
442
+ file: "",
443
+ // 脱敏模式(正则表达式)
444
+ redactPatterns: ["sk-.*"]
445
+ },
446
+ // plugins: 插件配置
447
+ plugins: {}
448
+ };
449
+ const finalConfig = deepMerge$1(originalConfig, newConfig);
450
+ this.updateSpinner("正在写入配置...");
451
+ debugLog("[更新配置] 写入配置文件...");
452
+ await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
453
+ this.prefixText += chalk.green(` ✓ 配置文件更新成功
454
+ `);
455
+ debugLog(`[更新配置] 配置文件写入成功: ${paths.config}`);
276
456
  }
277
- while ((ret.length & 3) > 0) {
278
- ret += b64pad;
457
+ }
458
+ function checkEnv$1() {
459
+ debugLog("[环境检查] 检测 Node.js 版本...");
460
+ const nodeVersion = execSync("node --version", { stdio: "pipe" }).toString().trim();
461
+ debugLog(`[环境检查] Node.js 版本: ${nodeVersion}`);
462
+ if (!semver.gte(nodeVersion, "18.0.0")) {
463
+ throw new AppError$1(ERROR_CODES$1.NODE_VERSION_LOW, `Node.js 版本需要 >= 18.0.0,当前版本: ${nodeVersion}`);
464
+ }
465
+ debugLog("[环境检查] Node.js 版本检查通过");
466
+ debugLog("[环境检查] 检测 npm...");
467
+ try {
468
+ const npmVersion = execSync("npm --version", { stdio: "pipe" }).toString().trim();
469
+ debugLog(`[环境检查] npm 版本: ${npmVersion}`);
470
+ debugLog("[环境检查] npm 检测通过");
471
+ } catch {
472
+ throw new AppError$1(ERROR_CODES$1.NPM_NOT_FOUND, "未检测到 npm,请先安装 Node.js 和 npm");
279
473
  }
280
- return ret;
281
474
  }
282
- function b64tohex(s) {
283
- var ret = "";
284
- var i;
285
- var k = 0;
286
- var slop = 0;
287
- for (i = 0; i < s.length; ++i) {
288
- if (s.charAt(i) == b64pad) {
289
- break;
475
+ async function createBoxCommand(options) {
476
+ setDebug(!!options.debug);
477
+ debugLog("[盒子安装] 开始处理...");
478
+ debugLog(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, debug=${options.debug}`);
479
+ checkEnv$1();
480
+ debugLog("[盒子安装] 环境检查通过");
481
+ try {
482
+ let env = options.env;
483
+ let appKey = options.appKey;
484
+ let appSecret = options.appSecret;
485
+ const questions = [];
486
+ if (!env) {
487
+ debugLog("[盒子安装] 需要选择环境");
488
+ questions.push({
489
+ type: "list",
490
+ name: "env",
491
+ message: chalk.cyan("请选择环境:"),
492
+ default: "test",
493
+ choices: [
494
+ { name: `${chalk.green("测试环境")} ${chalk.dim("(test)")}`, value: "test" },
495
+ { name: `${chalk.red("正式环境")} ${chalk.dim("(prod)")}`, value: "prod" }
496
+ ]
497
+ });
498
+ } else {
499
+ debugLog(`[盒子安装] 使用命令行参数: env=${env}`);
290
500
  }
291
- var v = b64map.indexOf(s.charAt(i));
292
- if (v < 0) {
293
- continue;
501
+ if (!appKey) {
502
+ debugLog("[盒子安装] 需要输入 AppKey");
503
+ questions.push({
504
+ type: "input",
505
+ name: "appKey",
506
+ message: chalk.cyan("请输入 AppKey:"),
507
+ validate: (value) => {
508
+ if (!value || value.trim() === "") {
509
+ return chalk.red("AppKey 不能为空");
510
+ }
511
+ return true;
512
+ }
513
+ });
514
+ } else {
515
+ debugLog("[盒子安装] 使用命令行参数: appKey");
294
516
  }
295
- if (k == 0) {
296
- ret += int2char(v >> 2);
297
- slop = v & 3;
298
- k = 1;
299
- } else if (k == 1) {
300
- ret += int2char(slop << 2 | v >> 4);
301
- slop = v & 15;
302
- k = 2;
303
- } else if (k == 2) {
304
- ret += int2char(slop);
305
- ret += int2char(v >> 2);
306
- slop = v & 3;
307
- k = 3;
517
+ if (!appSecret) {
518
+ debugLog("[盒子安装] 需要输入 AppSecret");
519
+ questions.push({
520
+ type: "input",
521
+ name: "appSecret",
522
+ message: chalk.cyan("请输入 AppSecret:"),
523
+ validate: (value) => {
524
+ if (!value || value.trim() === "") {
525
+ return chalk.red("AppSecret 不能为空");
526
+ }
527
+ return true;
528
+ }
529
+ });
308
530
  } else {
309
- ret += int2char(slop << 2 | v >> 4);
310
- ret += int2char(v & 15);
311
- k = 0;
531
+ debugLog("[盒子安装] 使用命令行参数: appSecret");
532
+ }
533
+ if (questions.length > 0) {
534
+ debugLog(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
535
+ const answers = await inquirer.prompt(questions);
536
+ debugLog("[盒子安装] 交互式问答完成");
537
+ env = env || answers.env || "test";
538
+ appKey = appKey || answers.appKey;
539
+ appSecret = appSecret || answers.appSecret;
312
540
  }
541
+ debugLog(`[盒子安装] 最终参数: env=${env}`);
542
+ debugLog("[盒子安装] 创建 BoxInstaller 实例...");
543
+ const installer = new BoxInstaller({
544
+ appKey,
545
+ appSecret,
546
+ env
547
+ });
548
+ debugLog("[盒子安装] 开始安装...");
549
+ await installer.install();
550
+ debugLog("[盒子安装] 安装完成");
551
+ console.log(installer.getPrefixText() + boxen(
552
+ `${chalk.green("✦")} 插件初始化成功!`,
553
+ {
554
+ title: `${chalk.bold.green("初始化成功")}`,
555
+ titleAlignment: "center",
556
+ padding: { top: 1, bottom: 1, left: 5, right: 5 },
557
+ margin: 1,
558
+ borderStyle: "round",
559
+ borderColor: "green",
560
+ textAlignment: "center"
561
+ }
562
+ ));
563
+ } catch (error) {
564
+ debugLog(`[盒子安装] 发生错误: ${error.message}`);
565
+ console.error(boxen(
566
+ `${chalk.yellow(error.message)}`,
567
+ {
568
+ title: `${chalk.bold.red("初始化失败")}`,
569
+ titleAlignment: "center",
570
+ padding: { top: 1, bottom: 1, left: 5, right: 5 },
571
+ margin: 1,
572
+ borderStyle: "round",
573
+ borderColor: "red",
574
+ textAlignment: "center"
575
+ }
576
+ ));
577
+ process$1.exit(1);
313
578
  }
314
- if (k == 1) {
315
- ret += int2char(slop << 2);
579
+ }
580
+ function registerCommands$1(program2) {
581
+ 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);
582
+ }
583
+ const ERROR_CODES = {
584
+ PHONE_REQUIRED: "PHONE_REQUIRED",
585
+ USER_PASS_REQUIRED: "USER_PASS_REQUIRED",
586
+ LOGIN_FAILED: "LOGIN_FAILED",
587
+ GET_BOUND_CONFIG_FAILED: "GET_BOUND_CONFIG_FAILED",
588
+ NODE_VERSION_LOW: "NODE_VERSION_LOW",
589
+ NODE_NOT_FOUND: "NODE_NOT_FOUND",
590
+ NPM_NOT_FOUND: "NPM_NOT_FOUND",
591
+ NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
592
+ CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED",
593
+ HTTP_ERROR: "HTTP_ERROR",
594
+ NETWORK_ERROR: "NETWORK_ERROR"
595
+ };
596
+ class AppError2 extends Error {
597
+ constructor(code, message) {
598
+ super(message);
599
+ this.code = code;
600
+ this.name = "AppError";
316
601
  }
317
- return ret;
318
602
  }
319
- var decoder$1;
320
- var Hex = {
321
- decode: function(a) {
322
- var i;
323
- if (decoder$1 === void 0) {
324
- var hex = "0123456789ABCDEF";
325
- var ignore = " \f\n\r  \u2028\u2029";
326
- decoder$1 = {};
327
- for (i = 0; i < 16; ++i) {
328
- decoder$1[hex.charAt(i)] = i;
329
- }
330
- hex = hex.toLowerCase();
331
- for (i = 10; i < 16; ++i) {
332
- decoder$1[hex.charAt(i)] = i;
333
- }
334
- for (i = 0; i < ignore.length; ++i) {
335
- decoder$1[ignore.charAt(i)] = -1;
336
- }
603
+ function createHttpClient() {
604
+ return axios.create({
605
+ timeout: 1e4,
606
+ headers: {
607
+ "Content-Type": "application/json"
337
608
  }
338
- var out = [];
339
- var bits = 0;
340
- var char_count = 0;
341
- for (i = 0; i < a.length; ++i) {
342
- var c = a.charAt(i);
343
- if (c == "=") {
344
- break;
345
- }
346
- c = decoder$1[c];
347
- if (c == -1) {
348
- continue;
349
- }
350
- if (c === void 0) {
351
- throw new Error("Illegal character at offset " + i);
352
- }
353
- bits |= c;
354
- if (++char_count >= 2) {
355
- out[out.length] = bits;
356
- bits = 0;
357
- char_count = 0;
609
+ });
610
+ }
611
+ async function httpPost(url, data, config) {
612
+ const client = createHttpClient();
613
+ debugLog(`[HTTP POST] 请求地址: ${url}`);
614
+ debugLog(`[HTTP POST] 请求参数: ${JSON.stringify(data)}`);
615
+ debugLog(`[HTTP POST] 请求头: ${JSON.stringify(config?.headers || {})}`);
616
+ try {
617
+ const response = await client.post(url, data, config);
618
+ debugLog(`[HTTP POST] 响应状态: ${response.status}`);
619
+ debugLog(`[HTTP POST] 响应内容: ${JSON.stringify(response.data)}`);
620
+ return {
621
+ status: response.status,
622
+ data: response.data
623
+ };
624
+ } catch (error) {
625
+ const axiosError = error;
626
+ if (axiosError.response) {
627
+ const responseData = axiosError.response.data;
628
+ debugLog(`[HTTP POST] 响应状态: ${axiosError.response.status}`);
629
+ debugLog(`[HTTP POST] 响应状态文本: ${axiosError.response.statusText}`);
630
+ debugLog(`[HTTP POST] 响应数据: ${JSON.stringify(responseData)}`);
631
+ if (typeof responseData === "string") {
632
+ throw new AppError2(ERROR_CODES.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData}`);
633
+ } else if (responseData && typeof responseData === "object" && "message" in responseData) {
634
+ throw new AppError2(ERROR_CODES.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${responseData.message}`);
358
635
  } else {
359
- bits <<= 4;
636
+ throw new AppError2(ERROR_CODES.HTTP_ERROR, `请求失败 (${axiosError.response.status}): ${axiosError.response.statusText}`);
360
637
  }
638
+ } else if (axiosError.request) {
639
+ debugLog(`[HTTP POST] 未收到响应`);
640
+ debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
641
+ throw new AppError2(ERROR_CODES.NETWORK_ERROR, `网络错误: ${axiosError.message}`);
642
+ } else {
643
+ debugLog(`[HTTP POST] 请求配置错误`);
644
+ debugLog(`[HTTP POST] 错误信息: ${axiosError.message}`);
645
+ throw new AppError2(ERROR_CODES.HTTP_ERROR, `请求配置错误: ${axiosError.message}`);
361
646
  }
362
- if (char_count) {
363
- throw new Error("Hex encoding incomplete: 4 bits missing");
364
- }
365
- return out;
366
647
  }
367
- };
368
- var decoder;
369
- var Base64 = {
370
- decode: function(a) {
371
- var i;
372
- if (decoder === void 0) {
373
- var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
374
- var ignore = "= \f\n\r  \u2028\u2029";
375
- decoder = /* @__PURE__ */ Object.create(null);
376
- for (i = 0; i < 64; ++i) {
377
- decoder[b64.charAt(i)] = i;
378
- }
379
- decoder["-"] = 62;
380
- decoder["_"] = 63;
381
- for (i = 0; i < ignore.length; ++i) {
382
- decoder[ignore.charAt(i)] = -1;
383
- }
648
+ }
649
+ async function login(phone, password, env) {
650
+ const config = getConfig(env);
651
+ const url = `${config.API.TUZAI_BASE_URL}/user/login/pass`;
652
+ debugLog("[登录] 开始登录...");
653
+ debugLog(`[登录] 请求地址: ${url}`);
654
+ debugLog(`[登录] 请求参数: phone=${phone}, password=***`);
655
+ try {
656
+ const response = await httpPost(url, {
657
+ phone,
658
+ userPass: password
659
+ });
660
+ const data = response.data;
661
+ debugLog(`[登录] 响应数据: ${JSON.stringify(data)}`);
662
+ if (data.code === 200 && data.data?.token) {
663
+ debugLog("[登录] 登录成功,获取到 token");
664
+ return data.data.token;
384
665
  }
385
- var out = [];
666
+ debugLog("[登录] 登录失败");
667
+ throw new AppError2(ERROR_CODES.LOGIN_FAILED, data.message || "登录失败");
668
+ } catch (error) {
669
+ if (error instanceof AppError2) {
670
+ throw error;
671
+ }
672
+ debugLog(`[登录] 发生错误: ${error.message}`);
673
+ throw new AppError2(ERROR_CODES.LOGIN_FAILED, error.message);
674
+ }
675
+ }
676
+ async function fetchBoundConfig(token, phone, env) {
677
+ const config = getConfig(env);
678
+ const url = `${config.API.TUZAI_BASE_URL}/work-bot/local/bound/init`;
679
+ debugLog("[获取绑定配置] 开始获取绑定配置...");
680
+ debugLog(`[获取绑定配置] 请求地址: ${url}`);
681
+ debugLog(`[获取绑定配置] 请求参数: phone=${phone}, localCode=001`);
682
+ debugLog(`[获取绑定配置] 请求头: Authorization=${token.substring(0, 20)}...`);
683
+ try {
684
+ const response = await httpPost(url, {
685
+ phone,
686
+ localCode: "001"
687
+ }, {
688
+ headers: {
689
+ Authorization: token
690
+ }
691
+ });
692
+ const data = response.data;
693
+ debugLog(`[获取绑定配置] 响应数据: ${JSON.stringify(data)}`);
694
+ if (data.code === 200 && data.data) {
695
+ const boundConfig = {
696
+ appKey: data.data.app_key,
697
+ appSecret: data.data.app_secret,
698
+ userId: data.data.user_id,
699
+ agentId: data.data.agent_id || data.data.agents?.[0]?.id,
700
+ modelApiKey: data.data.model_api_key,
701
+ modelApiBaseUrl: data.data.model_api_base_url
702
+ };
703
+ debugLog("[获取绑定配置] 获取绑定配置成功");
704
+ debugLog(`[获取绑定配置] appKey: ${boundConfig.appKey}`);
705
+ debugLog(`[获取绑定配置] appSecret: ${boundConfig.appSecret ? "***" : "undefined"}`);
706
+ debugLog(`[获取绑定配置] userId: ${boundConfig.userId}`);
707
+ debugLog(`[获取绑定配置] agentId: ${boundConfig.agentId}`);
708
+ debugLog(`[获取绑定配置] modelApiKey: ${boundConfig.modelApiKey || "undefined"}`);
709
+ debugLog(`[获取绑定配置] modelApiBaseUrl: ${boundConfig.modelApiBaseUrl || "undefined"}`);
710
+ if (!boundConfig.appKey || !boundConfig.appSecret || !boundConfig.agentId) {
711
+ debugLog("[获取绑定配置] 缺少必要字段");
712
+ throw new AppError2(ERROR_CODES.GET_BOUND_CONFIG_FAILED, "获取绑定配置失败:缺少必要字段");
713
+ }
714
+ return boundConfig;
715
+ }
716
+ debugLog("[获取绑定配置] 获取绑定配置失败");
717
+ throw new AppError2(ERROR_CODES.GET_BOUND_CONFIG_FAILED, data.message || data.msg || "获取绑定配置失败");
718
+ } catch (error) {
719
+ if (error instanceof AppError2) {
720
+ throw error;
721
+ }
722
+ debugLog(`[获取绑定配置] 发生错误: ${error.message}`);
723
+ throw new AppError2(ERROR_CODES.GET_BOUND_CONFIG_FAILED, error.message);
724
+ }
725
+ }
726
+ var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
727
+ function int2char(n) {
728
+ return BI_RM.charAt(n);
729
+ }
730
+ function op_and(x, y) {
731
+ return x & y;
732
+ }
733
+ function op_or(x, y) {
734
+ return x | y;
735
+ }
736
+ function op_xor(x, y) {
737
+ return x ^ y;
738
+ }
739
+ function op_andnot(x, y) {
740
+ return x & ~y;
741
+ }
742
+ function lbit(x) {
743
+ if (x == 0) {
744
+ return -1;
745
+ }
746
+ var r = 0;
747
+ if ((x & 65535) == 0) {
748
+ x >>= 16;
749
+ r += 16;
750
+ }
751
+ if ((x & 255) == 0) {
752
+ x >>= 8;
753
+ r += 8;
754
+ }
755
+ if ((x & 15) == 0) {
756
+ x >>= 4;
757
+ r += 4;
758
+ }
759
+ if ((x & 3) == 0) {
760
+ x >>= 2;
761
+ r += 2;
762
+ }
763
+ if ((x & 1) == 0) {
764
+ ++r;
765
+ }
766
+ return r;
767
+ }
768
+ function cbit(x) {
769
+ var r = 0;
770
+ while (x != 0) {
771
+ x &= x - 1;
772
+ ++r;
773
+ }
774
+ return r;
775
+ }
776
+ var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
777
+ var b64pad = "=";
778
+ function hex2b64(h) {
779
+ var i;
780
+ var c;
781
+ var ret = "";
782
+ for (i = 0; i + 3 <= h.length; i += 3) {
783
+ c = parseInt(h.substring(i, i + 3), 16);
784
+ ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
785
+ }
786
+ if (i + 1 == h.length) {
787
+ c = parseInt(h.substring(i, i + 1), 16);
788
+ ret += b64map.charAt(c << 2);
789
+ } else if (i + 2 == h.length) {
790
+ c = parseInt(h.substring(i, i + 2), 16);
791
+ ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
792
+ }
793
+ while ((ret.length & 3) > 0) {
794
+ ret += b64pad;
795
+ }
796
+ return ret;
797
+ }
798
+ function b64tohex(s) {
799
+ var ret = "";
800
+ var i;
801
+ var k = 0;
802
+ var slop = 0;
803
+ for (i = 0; i < s.length; ++i) {
804
+ if (s.charAt(i) == b64pad) {
805
+ break;
806
+ }
807
+ var v = b64map.indexOf(s.charAt(i));
808
+ if (v < 0) {
809
+ continue;
810
+ }
811
+ if (k == 0) {
812
+ ret += int2char(v >> 2);
813
+ slop = v & 3;
814
+ k = 1;
815
+ } else if (k == 1) {
816
+ ret += int2char(slop << 2 | v >> 4);
817
+ slop = v & 15;
818
+ k = 2;
819
+ } else if (k == 2) {
820
+ ret += int2char(slop);
821
+ ret += int2char(v >> 2);
822
+ slop = v & 3;
823
+ k = 3;
824
+ } else {
825
+ ret += int2char(slop << 2 | v >> 4);
826
+ ret += int2char(v & 15);
827
+ k = 0;
828
+ }
829
+ }
830
+ if (k == 1) {
831
+ ret += int2char(slop << 2);
832
+ }
833
+ return ret;
834
+ }
835
+ var decoder$1;
836
+ var Hex = {
837
+ decode: function(a) {
838
+ var i;
839
+ if (decoder$1 === void 0) {
840
+ var hex = "0123456789ABCDEF";
841
+ var ignore = " \f\n\r  \u2028\u2029";
842
+ decoder$1 = {};
843
+ for (i = 0; i < 16; ++i) {
844
+ decoder$1[hex.charAt(i)] = i;
845
+ }
846
+ hex = hex.toLowerCase();
847
+ for (i = 10; i < 16; ++i) {
848
+ decoder$1[hex.charAt(i)] = i;
849
+ }
850
+ for (i = 0; i < ignore.length; ++i) {
851
+ decoder$1[ignore.charAt(i)] = -1;
852
+ }
853
+ }
854
+ var out = [];
855
+ var bits = 0;
856
+ var char_count = 0;
857
+ for (i = 0; i < a.length; ++i) {
858
+ var c = a.charAt(i);
859
+ if (c == "=") {
860
+ break;
861
+ }
862
+ c = decoder$1[c];
863
+ if (c == -1) {
864
+ continue;
865
+ }
866
+ if (c === void 0) {
867
+ throw new Error("Illegal character at offset " + i);
868
+ }
869
+ bits |= c;
870
+ if (++char_count >= 2) {
871
+ out[out.length] = bits;
872
+ bits = 0;
873
+ char_count = 0;
874
+ } else {
875
+ bits <<= 4;
876
+ }
877
+ }
878
+ if (char_count) {
879
+ throw new Error("Hex encoding incomplete: 4 bits missing");
880
+ }
881
+ return out;
882
+ }
883
+ };
884
+ var decoder;
885
+ var Base64 = {
886
+ decode: function(a) {
887
+ var i;
888
+ if (decoder === void 0) {
889
+ var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
890
+ var ignore = "= \f\n\r  \u2028\u2029";
891
+ decoder = /* @__PURE__ */ Object.create(null);
892
+ for (i = 0; i < 64; ++i) {
893
+ decoder[b64.charAt(i)] = i;
894
+ }
895
+ decoder["-"] = 62;
896
+ decoder["_"] = 63;
897
+ for (i = 0; i < ignore.length; ++i) {
898
+ decoder[ignore.charAt(i)] = -1;
899
+ }
900
+ }
901
+ var out = [];
386
902
  var bits = 0;
387
903
  var char_count = 0;
388
904
  for (i = 0; i < a.length; ++i) {
@@ -3578,1167 +4094,540 @@ KJUR.asn1.DERObjectIdentifier = function(params) {
3578
4094
  for (var i = 0; i < a.length; i++) {
3579
4095
  h += roidtox(a[i]);
3580
4096
  }
3581
- this.hTLV = null;
3582
- this.isModified = true;
3583
- this.s = null;
3584
- this.hV = h;
3585
- };
3586
- this.setValueName = function(oidName) {
3587
- var oid = KJUR.asn1.x509.OID.name2oid(oidName);
3588
- if (oid !== "") {
3589
- this.setValueOidString(oid);
3590
- } else {
3591
- throw "DERObjectIdentifier oidName undefined: " + oidName;
3592
- }
3593
- };
3594
- this.getFreshValueHex = function() {
3595
- return this.hV;
3596
- };
3597
- if (params !== void 0) {
3598
- if (typeof params === "string") {
3599
- if (params.match(/^[0-2].[0-9.]+$/)) {
3600
- this.setValueOidString(params);
3601
- } else {
3602
- this.setValueName(params);
3603
- }
3604
- } else if (params.oid !== void 0) {
3605
- this.setValueOidString(params.oid);
3606
- } else if (params.hex !== void 0) {
3607
- this.setValueHex(params.hex);
3608
- } else if (params.name !== void 0) {
3609
- this.setValueName(params.name);
3610
- }
3611
- }
3612
- };
3613
- extendClass(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object);
3614
- KJUR.asn1.DEREnumerated = function(params) {
3615
- KJUR.asn1.DEREnumerated.superclass.constructor.call(this);
3616
- this.hT = "0a";
3617
- this.setByBigInteger = function(bigIntegerValue) {
3618
- this.hTLV = null;
3619
- this.isModified = true;
3620
- this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue);
3621
- };
3622
- this.setByInteger = function(intValue) {
3623
- var bi = new BigInteger(String(intValue), 10);
3624
- this.setByBigInteger(bi);
3625
- };
3626
- this.setValueHex = function(newHexString) {
3627
- this.hV = newHexString;
3628
- };
3629
- this.getFreshValueHex = function() {
3630
- return this.hV;
3631
- };
3632
- if (typeof params != "undefined") {
3633
- if (typeof params["int"] != "undefined") {
3634
- this.setByInteger(params["int"]);
3635
- } else if (typeof params == "number") {
3636
- this.setByInteger(params);
3637
- } else if (typeof params["hex"] != "undefined") {
3638
- this.setValueHex(params["hex"]);
3639
- }
3640
- }
3641
- };
3642
- extendClass(KJUR.asn1.DEREnumerated, KJUR.asn1.ASN1Object);
3643
- KJUR.asn1.DERUTF8String = function(params) {
3644
- KJUR.asn1.DERUTF8String.superclass.constructor.call(this, params);
3645
- this.hT = "0c";
3646
- };
3647
- extendClass(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString);
3648
- KJUR.asn1.DERNumericString = function(params) {
3649
- KJUR.asn1.DERNumericString.superclass.constructor.call(this, params);
3650
- this.hT = "12";
3651
- };
3652
- extendClass(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString);
3653
- KJUR.asn1.DERPrintableString = function(params) {
3654
- KJUR.asn1.DERPrintableString.superclass.constructor.call(this, params);
3655
- this.hT = "13";
3656
- };
3657
- extendClass(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString);
3658
- KJUR.asn1.DERTeletexString = function(params) {
3659
- KJUR.asn1.DERTeletexString.superclass.constructor.call(this, params);
3660
- this.hT = "14";
3661
- };
3662
- extendClass(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString);
3663
- KJUR.asn1.DERIA5String = function(params) {
3664
- KJUR.asn1.DERIA5String.superclass.constructor.call(this, params);
3665
- this.hT = "16";
3666
- };
3667
- extendClass(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString);
3668
- KJUR.asn1.DERUTCTime = function(params) {
3669
- KJUR.asn1.DERUTCTime.superclass.constructor.call(this, params);
3670
- this.hT = "17";
3671
- this.setByDate = function(dateObject) {
3672
- this.hTLV = null;
3673
- this.isModified = true;
3674
- this.date = dateObject;
3675
- this.s = this.formatDate(this.date, "utc");
3676
- this.hV = stohex(this.s);
3677
- };
3678
- this.getFreshValueHex = function() {
3679
- if (typeof this.date == "undefined" && typeof this.s == "undefined") {
3680
- this.date = /* @__PURE__ */ new Date();
3681
- this.s = this.formatDate(this.date, "utc");
3682
- this.hV = stohex(this.s);
3683
- }
3684
- return this.hV;
3685
- };
3686
- if (params !== void 0) {
3687
- if (params.str !== void 0) {
3688
- this.setString(params.str);
3689
- } else if (typeof params == "string" && params.match(/^[0-9]{12}Z$/)) {
3690
- this.setString(params);
3691
- } else if (params.hex !== void 0) {
3692
- this.setStringHex(params.hex);
3693
- } else if (params.date !== void 0) {
3694
- this.setByDate(params.date);
3695
- }
3696
- }
3697
- };
3698
- extendClass(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime);
3699
- KJUR.asn1.DERGeneralizedTime = function(params) {
3700
- KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, params);
3701
- this.hT = "18";
3702
- this.withMillis = false;
3703
- this.setByDate = function(dateObject) {
3704
- this.hTLV = null;
3705
- this.isModified = true;
3706
- this.date = dateObject;
3707
- this.s = this.formatDate(this.date, "gen", this.withMillis);
3708
- this.hV = stohex(this.s);
3709
- };
3710
- this.getFreshValueHex = function() {
3711
- if (this.date === void 0 && this.s === void 0) {
3712
- this.date = /* @__PURE__ */ new Date();
3713
- this.s = this.formatDate(this.date, "gen", this.withMillis);
3714
- this.hV = stohex(this.s);
3715
- }
3716
- return this.hV;
3717
- };
3718
- if (params !== void 0) {
3719
- if (params.str !== void 0) {
3720
- this.setString(params.str);
3721
- } else if (typeof params == "string" && params.match(/^[0-9]{14}Z$/)) {
3722
- this.setString(params);
3723
- } else if (params.hex !== void 0) {
3724
- this.setStringHex(params.hex);
3725
- } else if (params.date !== void 0) {
3726
- this.setByDate(params.date);
3727
- }
3728
- if (params.millis === true) {
3729
- this.withMillis = true;
3730
- }
3731
- }
3732
- };
3733
- extendClass(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime);
3734
- KJUR.asn1.DERSequence = function(params) {
3735
- KJUR.asn1.DERSequence.superclass.constructor.call(this, params);
3736
- this.hT = "30";
3737
- this.getFreshValueHex = function() {
3738
- var h = "";
3739
- for (var i = 0; i < this.asn1Array.length; i++) {
3740
- var asn1Obj = this.asn1Array[i];
3741
- h += asn1Obj.getEncodedHex();
3742
- }
3743
- this.hV = h;
3744
- return this.hV;
3745
- };
3746
- };
3747
- extendClass(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured);
3748
- KJUR.asn1.DERSet = function(params) {
3749
- KJUR.asn1.DERSet.superclass.constructor.call(this, params);
3750
- this.hT = "31";
3751
- this.sortFlag = true;
3752
- this.getFreshValueHex = function() {
3753
- var a = new Array();
3754
- for (var i = 0; i < this.asn1Array.length; i++) {
3755
- var asn1Obj = this.asn1Array[i];
3756
- a.push(asn1Obj.getEncodedHex());
3757
- }
3758
- if (this.sortFlag == true)
3759
- a.sort();
3760
- this.hV = a.join("");
3761
- return this.hV;
3762
- };
3763
- if (typeof params != "undefined") {
3764
- if (typeof params.sortflag != "undefined" && params.sortflag == false)
3765
- this.sortFlag = false;
3766
- }
3767
- };
3768
- extendClass(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured);
3769
- KJUR.asn1.DERTaggedObject = function(params) {
3770
- KJUR.asn1.DERTaggedObject.superclass.constructor.call(this);
3771
- this.hT = "a0";
3772
- this.hV = "";
3773
- this.isExplicit = true;
3774
- this.asn1Object = null;
3775
- this.setASN1Object = function(isExplicitFlag, tagNoHex, asn1Object) {
3776
- this.hT = tagNoHex;
3777
- this.isExplicit = isExplicitFlag;
3778
- this.asn1Object = asn1Object;
3779
- if (this.isExplicit) {
3780
- this.hV = this.asn1Object.getEncodedHex();
3781
- this.hTLV = null;
3782
- this.isModified = true;
3783
- } else {
3784
- this.hV = null;
3785
- this.hTLV = asn1Object.getEncodedHex();
3786
- this.hTLV = this.hTLV.replace(/^../, tagNoHex);
3787
- this.isModified = false;
3788
- }
3789
- };
3790
- this.getFreshValueHex = function() {
3791
- return this.hV;
3792
- };
3793
- if (typeof params != "undefined") {
3794
- if (typeof params["tag"] != "undefined") {
3795
- this.hT = params["tag"];
3796
- }
3797
- if (typeof params["explicit"] != "undefined") {
3798
- this.isExplicit = params["explicit"];
3799
- }
3800
- if (typeof params["obj"] != "undefined") {
3801
- this.asn1Object = params["obj"];
3802
- this.setASN1Object(this.isExplicit, this.hT, this.asn1Object);
3803
- }
3804
- }
3805
- };
3806
- extendClass(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object);
3807
- var __extends = /* @__PURE__ */ function() {
3808
- var extendStatics = function(d, b) {
3809
- extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
3810
- d2.__proto__ = b2;
3811
- } || function(d2, b2) {
3812
- for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];
3813
- };
3814
- return extendStatics(d, b);
3815
- };
3816
- return function(d, b) {
3817
- if (typeof b !== "function" && b !== null)
3818
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
3819
- extendStatics(d, b);
3820
- function __() {
3821
- this.constructor = d;
3822
- }
3823
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
3824
- };
3825
- }();
3826
- var JSEncryptRSAKey = (
3827
- /** @class */
3828
- function(_super) {
3829
- __extends(JSEncryptRSAKey2, _super);
3830
- function JSEncryptRSAKey2(key) {
3831
- var _this = _super.call(this) || this;
3832
- if (key) {
3833
- if (typeof key === "string") {
3834
- _this.parseKey(key);
3835
- } else if (JSEncryptRSAKey2.hasPrivateKeyProperty(key) || JSEncryptRSAKey2.hasPublicKeyProperty(key)) {
3836
- _this.parsePropertiesFrom(key);
3837
- }
3838
- }
3839
- return _this;
3840
- }
3841
- JSEncryptRSAKey2.prototype.parseKey = function(pem) {
3842
- try {
3843
- var modulus = 0;
3844
- var public_exponent = 0;
3845
- var reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/;
3846
- var der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem);
3847
- var asn1 = ASN1.decode(der);
3848
- if (asn1.sub.length === 3) {
3849
- asn1 = asn1.sub[2].sub[0];
3850
- }
3851
- if (asn1.sub.length === 9) {
3852
- modulus = asn1.sub[1].getHexStringValue();
3853
- this.n = parseBigInt(modulus, 16);
3854
- public_exponent = asn1.sub[2].getHexStringValue();
3855
- this.e = parseInt(public_exponent, 16);
3856
- var private_exponent = asn1.sub[3].getHexStringValue();
3857
- this.d = parseBigInt(private_exponent, 16);
3858
- var prime1 = asn1.sub[4].getHexStringValue();
3859
- this.p = parseBigInt(prime1, 16);
3860
- var prime2 = asn1.sub[5].getHexStringValue();
3861
- this.q = parseBigInt(prime2, 16);
3862
- var exponent1 = asn1.sub[6].getHexStringValue();
3863
- this.dmp1 = parseBigInt(exponent1, 16);
3864
- var exponent2 = asn1.sub[7].getHexStringValue();
3865
- this.dmq1 = parseBigInt(exponent2, 16);
3866
- var coefficient = asn1.sub[8].getHexStringValue();
3867
- this.coeff = parseBigInt(coefficient, 16);
3868
- } else if (asn1.sub.length === 2) {
3869
- if (asn1.sub[0].sub) {
3870
- var bit_string = asn1.sub[1];
3871
- var sequence = bit_string.sub[0];
3872
- modulus = sequence.sub[0].getHexStringValue();
3873
- this.n = parseBigInt(modulus, 16);
3874
- public_exponent = sequence.sub[1].getHexStringValue();
3875
- this.e = parseInt(public_exponent, 16);
3876
- } else {
3877
- modulus = asn1.sub[0].getHexStringValue();
3878
- this.n = parseBigInt(modulus, 16);
3879
- public_exponent = asn1.sub[1].getHexStringValue();
3880
- this.e = parseInt(public_exponent, 16);
3881
- }
3882
- } else {
3883
- return false;
3884
- }
3885
- return true;
3886
- } catch (ex) {
3887
- return false;
3888
- }
3889
- };
3890
- JSEncryptRSAKey2.prototype.getPrivateBaseKey = function() {
3891
- var options = {
3892
- array: [
3893
- new KJUR.asn1.DERInteger({ int: 0 }),
3894
- new KJUR.asn1.DERInteger({ bigint: this.n }),
3895
- new KJUR.asn1.DERInteger({ int: this.e }),
3896
- new KJUR.asn1.DERInteger({ bigint: this.d }),
3897
- new KJUR.asn1.DERInteger({ bigint: this.p }),
3898
- new KJUR.asn1.DERInteger({ bigint: this.q }),
3899
- new KJUR.asn1.DERInteger({ bigint: this.dmp1 }),
3900
- new KJUR.asn1.DERInteger({ bigint: this.dmq1 }),
3901
- new KJUR.asn1.DERInteger({ bigint: this.coeff })
3902
- ]
3903
- };
3904
- var seq = new KJUR.asn1.DERSequence(options);
3905
- return seq.getEncodedHex();
3906
- };
3907
- JSEncryptRSAKey2.prototype.getPrivateBaseKeyB64 = function() {
3908
- return hex2b64(this.getPrivateBaseKey());
3909
- };
3910
- JSEncryptRSAKey2.prototype.getPublicBaseKey = function() {
3911
- var first_sequence = new KJUR.asn1.DERSequence({
3912
- array: [
3913
- new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }),
3914
- // RSA Encryption pkcs #1 oid
3915
- new KJUR.asn1.DERNull()
3916
- ]
3917
- });
3918
- var second_sequence = new KJUR.asn1.DERSequence({
3919
- array: [
3920
- new KJUR.asn1.DERInteger({ bigint: this.n }),
3921
- new KJUR.asn1.DERInteger({ int: this.e })
3922
- ]
3923
- });
3924
- var bit_string = new KJUR.asn1.DERBitString({
3925
- hex: "00" + second_sequence.getEncodedHex()
3926
- });
3927
- var seq = new KJUR.asn1.DERSequence({
3928
- array: [first_sequence, bit_string]
3929
- });
3930
- return seq.getEncodedHex();
3931
- };
3932
- JSEncryptRSAKey2.prototype.getPublicBaseKeyB64 = function() {
3933
- return hex2b64(this.getPublicBaseKey());
3934
- };
3935
- JSEncryptRSAKey2.wordwrap = function(str, width) {
3936
- width = width || 64;
3937
- if (!str) {
3938
- return str;
3939
- }
3940
- var regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
3941
- return str.match(RegExp(regex, "g")).join("\n");
3942
- };
3943
- JSEncryptRSAKey2.prototype.getPrivateKey = function() {
3944
- var key = "-----BEGIN RSA PRIVATE KEY-----\n";
3945
- key += JSEncryptRSAKey2.wordwrap(this.getPrivateBaseKeyB64()) + "\n";
3946
- key += "-----END RSA PRIVATE KEY-----";
3947
- return key;
3948
- };
3949
- JSEncryptRSAKey2.prototype.getPublicKey = function() {
3950
- var key = "-----BEGIN PUBLIC KEY-----\n";
3951
- key += JSEncryptRSAKey2.wordwrap(this.getPublicBaseKeyB64()) + "\n";
3952
- key += "-----END PUBLIC KEY-----";
3953
- return key;
3954
- };
3955
- JSEncryptRSAKey2.hasPublicKeyProperty = function(obj) {
3956
- obj = obj || {};
3957
- return obj.hasOwnProperty("n") && obj.hasOwnProperty("e");
3958
- };
3959
- JSEncryptRSAKey2.hasPrivateKeyProperty = function(obj) {
3960
- obj = obj || {};
3961
- return obj.hasOwnProperty("n") && obj.hasOwnProperty("e") && obj.hasOwnProperty("d") && obj.hasOwnProperty("p") && obj.hasOwnProperty("q") && obj.hasOwnProperty("dmp1") && obj.hasOwnProperty("dmq1") && obj.hasOwnProperty("coeff");
3962
- };
3963
- JSEncryptRSAKey2.prototype.parsePropertiesFrom = function(obj) {
3964
- this.n = obj.n;
3965
- this.e = obj.e;
3966
- if (obj.hasOwnProperty("d")) {
3967
- this.d = obj.d;
3968
- this.p = obj.p;
3969
- this.q = obj.q;
3970
- this.dmp1 = obj.dmp1;
3971
- this.dmq1 = obj.dmq1;
3972
- this.coeff = obj.coeff;
3973
- }
3974
- };
3975
- return JSEncryptRSAKey2;
3976
- }(RSAKey)
3977
- );
3978
- var _a;
3979
- var version = typeof process !== "undefined" ? (_a = process.env) === null || _a === void 0 ? void 0 : _a.npm_package_version : void 0;
3980
- var JSEncrypt = (
3981
- /** @class */
3982
- function() {
3983
- function JSEncrypt2(options) {
3984
- if (options === void 0) {
3985
- options = {};
3986
- }
3987
- this.default_key_size = options.default_key_size ? parseInt(options.default_key_size, 10) : 1024;
3988
- this.default_public_exponent = options.default_public_exponent || "010001";
3989
- this.log = options.log || false;
3990
- this.key = options.key || null;
3991
- }
3992
- JSEncrypt2.prototype.setKey = function(key) {
3993
- if (key) {
3994
- if (this.log && this.key) {
3995
- console.warn("A key was already set, overriding existing.");
3996
- }
3997
- this.key = new JSEncryptRSAKey(key);
3998
- } else if (!this.key && this.log) {
3999
- console.error("A key was not set.");
4000
- }
4001
- };
4002
- JSEncrypt2.prototype.setPrivateKey = function(privkey) {
4003
- this.setKey(privkey);
4004
- };
4005
- JSEncrypt2.prototype.setPublicKey = function(pubkey) {
4006
- this.setKey(pubkey);
4007
- };
4008
- JSEncrypt2.prototype.decrypt = function(str) {
4009
- try {
4010
- return this.getKey().decrypt(b64tohex(str));
4011
- } catch (ex) {
4012
- return false;
4013
- }
4014
- };
4015
- JSEncrypt2.prototype.encrypt = function(str) {
4016
- try {
4017
- return hex2b64(this.getKey().encrypt(str));
4018
- } catch (ex) {
4019
- return false;
4020
- }
4021
- };
4022
- JSEncrypt2.prototype.encryptOAEP = function(str) {
4023
- try {
4024
- return hex2b64(this.getKey().encrypt(str, oaep_pad));
4025
- } catch (ex) {
4026
- return false;
4027
- }
4028
- };
4029
- JSEncrypt2.prototype.sign = function(str, digestMethod, digestName) {
4030
- if (digestMethod === void 0) {
4031
- digestMethod = function(raw) {
4032
- return raw;
4033
- };
4034
- }
4035
- if (digestName === void 0) {
4036
- digestName = "";
4037
- }
4038
- try {
4039
- return hex2b64(this.getKey().sign(str, digestMethod, digestName));
4040
- } catch (ex) {
4041
- return false;
4042
- }
4043
- };
4044
- JSEncrypt2.prototype.signSha256 = function(str) {
4045
- return this.sign(str, function(text) {
4046
- return rstr2hex(rstr_sha256(text));
4047
- }, "sha256");
4048
- };
4049
- JSEncrypt2.prototype.verify = function(str, signature, digestMethod) {
4050
- if (digestMethod === void 0) {
4051
- digestMethod = function(raw) {
4052
- return raw;
4053
- };
4054
- }
4055
- try {
4056
- return this.getKey().verify(str, b64tohex(signature), digestMethod);
4057
- } catch (ex) {
4058
- return false;
4059
- }
4060
- };
4061
- JSEncrypt2.prototype.verifySha256 = function(str, signature) {
4062
- return this.verify(str, signature, function(text) {
4063
- return rstr2hex(rstr_sha256(text));
4064
- });
4065
- };
4066
- JSEncrypt2.prototype.getKey = function(cb) {
4067
- if (!this.key) {
4068
- this.key = new JSEncryptRSAKey();
4069
- if (cb && {}.toString.call(cb) === "[object Function]") {
4070
- this.key.generateAsync(this.default_key_size, this.default_public_exponent, cb);
4071
- return;
4072
- }
4073
- this.key.generate(this.default_key_size, this.default_public_exponent);
4074
- }
4075
- return this.key;
4076
- };
4077
- JSEncrypt2.prototype.getPrivateKey = function() {
4078
- return this.getKey().getPrivateKey();
4079
- };
4080
- JSEncrypt2.prototype.getPrivateKeyB64 = function() {
4081
- return this.getKey().getPrivateBaseKeyB64();
4082
- };
4083
- JSEncrypt2.prototype.getPublicKey = function() {
4084
- return this.getKey().getPublicKey();
4085
- };
4086
- JSEncrypt2.prototype.getPublicKeyB64 = function() {
4087
- return this.getKey().getPublicBaseKeyB64();
4088
- };
4089
- JSEncrypt2.version = version;
4090
- return JSEncrypt2;
4091
- }()
4092
- );
4093
- const PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBSYtNb6neLrrwsuPBsIFjpZBrffdkA8bpp2S35o2TCdhfdxS0nc4pkv9cJLkUvFa+gdQ5nLifnK9B1XoVbIQwY212QAftTDbl77bcHu7GAbv2TZr9pelSeUm1SrtMK5HDr/LzxTutGr4DovVHiDgEn45GQ1X5U+zC0Jp4Awn6ZwIDAQAB";
4094
- function rsaEncrypt(txt) {
4095
- const encrypt = new JSEncrypt();
4096
- encrypt.setPublicKey(PUBLIC_KEY);
4097
- const result = encrypt.encrypt(txt);
4098
- return result || null;
4099
- }
4100
- function getHomeDir$1() {
4101
- return process$1.env.HOME || process$1.env.USERPROFILE || "";
4102
- }
4103
- const PLUGIN_PACKAGE_NAME$1 = "@workclaw/openclaw-workclaw";
4104
- function deepMerge$1(target, source) {
4105
- const result = { ...target };
4106
- for (const key in source) {
4107
- const sourceValue = source[key];
4108
- const targetValue = target[key];
4109
- if (sourceValue !== void 0 && sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
4110
- result[key] = deepMerge$1(targetValue, sourceValue);
4111
- } else if (sourceValue !== void 0) {
4112
- result[key] = sourceValue;
4097
+ this.hTLV = null;
4098
+ this.isModified = true;
4099
+ this.s = null;
4100
+ this.hV = h;
4101
+ };
4102
+ this.setValueName = function(oidName) {
4103
+ var oid = KJUR.asn1.x509.OID.name2oid(oidName);
4104
+ if (oid !== "") {
4105
+ this.setValueOidString(oid);
4106
+ } else {
4107
+ throw "DERObjectIdentifier oidName undefined: " + oidName;
4108
+ }
4109
+ };
4110
+ this.getFreshValueHex = function() {
4111
+ return this.hV;
4112
+ };
4113
+ if (params !== void 0) {
4114
+ if (typeof params === "string") {
4115
+ if (params.match(/^[0-2].[0-9.]+$/)) {
4116
+ this.setValueOidString(params);
4117
+ } else {
4118
+ this.setValueName(params);
4119
+ }
4120
+ } else if (params.oid !== void 0) {
4121
+ this.setValueOidString(params.oid);
4122
+ } else if (params.hex !== void 0) {
4123
+ this.setValueHex(params.hex);
4124
+ } else if (params.name !== void 0) {
4125
+ this.setValueName(params.name);
4113
4126
  }
4114
4127
  }
4115
- return result;
4116
- }
4117
- class LocalInstaller {
4118
- constructor(config) {
4119
- this.config = config;
4120
- this.spinner = ora({ color: "cyan" }).start();
4121
- }
4122
- spinner;
4123
- prefixText = "";
4124
- getPackageName() {
4125
- if (this.config.pluginVersion) {
4126
- return `${PLUGIN_PACKAGE_NAME$1}@${this.config.pluginVersion}`;
4128
+ };
4129
+ extendClass(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object);
4130
+ KJUR.asn1.DEREnumerated = function(params) {
4131
+ KJUR.asn1.DEREnumerated.superclass.constructor.call(this);
4132
+ this.hT = "0a";
4133
+ this.setByBigInteger = function(bigIntegerValue) {
4134
+ this.hTLV = null;
4135
+ this.isModified = true;
4136
+ this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue);
4137
+ };
4138
+ this.setByInteger = function(intValue) {
4139
+ var bi = new BigInteger(String(intValue), 10);
4140
+ this.setByBigInteger(bi);
4141
+ };
4142
+ this.setValueHex = function(newHexString) {
4143
+ this.hV = newHexString;
4144
+ };
4145
+ this.getFreshValueHex = function() {
4146
+ return this.hV;
4147
+ };
4148
+ if (typeof params != "undefined") {
4149
+ if (typeof params["int"] != "undefined") {
4150
+ this.setByInteger(params["int"]);
4151
+ } else if (typeof params == "number") {
4152
+ this.setByInteger(params);
4153
+ } else if (typeof params["hex"] != "undefined") {
4154
+ this.setValueHex(params["hex"]);
4127
4155
  }
4128
- return PLUGIN_PACKAGE_NAME$1;
4129
4156
  }
4130
- validateConfig() {
4131
- debugLog("[验证配置] 检查手机号码和密码...");
4132
- if (!this.config.phone) {
4133
- throw new AppError$1(ERROR_CODES$1.PHONE_REQUIRED, "手机号码不能为空,请使用 --phone 参数");
4157
+ };
4158
+ extendClass(KJUR.asn1.DEREnumerated, KJUR.asn1.ASN1Object);
4159
+ KJUR.asn1.DERUTF8String = function(params) {
4160
+ KJUR.asn1.DERUTF8String.superclass.constructor.call(this, params);
4161
+ this.hT = "0c";
4162
+ };
4163
+ extendClass(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString);
4164
+ KJUR.asn1.DERNumericString = function(params) {
4165
+ KJUR.asn1.DERNumericString.superclass.constructor.call(this, params);
4166
+ this.hT = "12";
4167
+ };
4168
+ extendClass(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString);
4169
+ KJUR.asn1.DERPrintableString = function(params) {
4170
+ KJUR.asn1.DERPrintableString.superclass.constructor.call(this, params);
4171
+ this.hT = "13";
4172
+ };
4173
+ extendClass(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString);
4174
+ KJUR.asn1.DERTeletexString = function(params) {
4175
+ KJUR.asn1.DERTeletexString.superclass.constructor.call(this, params);
4176
+ this.hT = "14";
4177
+ };
4178
+ extendClass(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString);
4179
+ KJUR.asn1.DERIA5String = function(params) {
4180
+ KJUR.asn1.DERIA5String.superclass.constructor.call(this, params);
4181
+ this.hT = "16";
4182
+ };
4183
+ extendClass(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString);
4184
+ KJUR.asn1.DERUTCTime = function(params) {
4185
+ KJUR.asn1.DERUTCTime.superclass.constructor.call(this, params);
4186
+ this.hT = "17";
4187
+ this.setByDate = function(dateObject) {
4188
+ this.hTLV = null;
4189
+ this.isModified = true;
4190
+ this.date = dateObject;
4191
+ this.s = this.formatDate(this.date, "utc");
4192
+ this.hV = stohex(this.s);
4193
+ };
4194
+ this.getFreshValueHex = function() {
4195
+ if (typeof this.date == "undefined" && typeof this.s == "undefined") {
4196
+ this.date = /* @__PURE__ */ new Date();
4197
+ this.s = this.formatDate(this.date, "utc");
4198
+ this.hV = stohex(this.s);
4134
4199
  }
4135
- if (!this.config.userPass) {
4136
- throw new AppError$1(ERROR_CODES$1.USER_PASS_REQUIRED, "用户密码不能为空,请使用 --user-pass 参数");
4200
+ return this.hV;
4201
+ };
4202
+ if (params !== void 0) {
4203
+ if (params.str !== void 0) {
4204
+ this.setString(params.str);
4205
+ } else if (typeof params == "string" && params.match(/^[0-9]{12}Z$/)) {
4206
+ this.setString(params);
4207
+ } else if (params.hex !== void 0) {
4208
+ this.setStringHex(params.hex);
4209
+ } else if (params.date !== void 0) {
4210
+ this.setByDate(params.date);
4137
4211
  }
4138
- debugLog("[验证配置] 配置验证通过");
4139
4212
  }
4140
- async install() {
4141
- try {
4142
- debugLog("[安装开始]");
4143
- this.validateConfig();
4144
- const env = this.config.env || "test";
4145
- const config = getConfig(env);
4146
- const homeDir = getHomeDir$1();
4147
- const paths = {
4148
- home: path.join(homeDir, config.DIRS.OPENCLAW),
4149
- extensions: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS),
4150
- target: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS, config.PLUGIN_NAME),
4151
- config: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.CONFIG_FILE),
4152
- workspace: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.WORKSPACE),
4153
- temp: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.TEMP)
4154
- };
4155
- debugLog(`[路径配置] home=${paths.home}`);
4156
- debugLog(`[路径配置] extensions=${paths.extensions}`);
4157
- debugLog(`[路径配置] target=${paths.target}`);
4158
- debugLog(`[路径配置] config=${paths.config}`);
4159
- debugLog(`[路径配置] workspace=${paths.workspace}`);
4160
- const token = await this.doLogin(env);
4161
- const boundConfig = await this.doFetchBoundConfig(env, token);
4162
- await this.doCleanOldFiles(paths.target);
4163
- await this.doDownloadFromNpm(paths);
4164
- await this.doUpdateConfig(paths, boundConfig, env);
4165
- this.spinner.stop();
4166
- } catch (error) {
4167
- this.spinner.stop();
4168
- throw error;
4213
+ };
4214
+ extendClass(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime);
4215
+ KJUR.asn1.DERGeneralizedTime = function(params) {
4216
+ KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, params);
4217
+ this.hT = "18";
4218
+ this.withMillis = false;
4219
+ this.setByDate = function(dateObject) {
4220
+ this.hTLV = null;
4221
+ this.isModified = true;
4222
+ this.date = dateObject;
4223
+ this.s = this.formatDate(this.date, "gen", this.withMillis);
4224
+ this.hV = stohex(this.s);
4225
+ };
4226
+ this.getFreshValueHex = function() {
4227
+ if (this.date === void 0 && this.s === void 0) {
4228
+ this.date = /* @__PURE__ */ new Date();
4229
+ this.s = this.formatDate(this.date, "gen", this.withMillis);
4230
+ this.hV = stohex(this.s);
4169
4231
  }
4170
- }
4171
- getPrefixText() {
4172
- return this.prefixText;
4173
- }
4174
- async doLogin(env) {
4175
- this.spinner.prefixText = this.prefixText;
4176
- this.spinner.text = `${chalk.cyan("用户登录")} ${chalk.dim("→")} ${chalk.yellow("正在登录...")}`;
4177
- debugLog(`[用户登录] 手机号: ${this.config.phone}`);
4178
- debugLog("[用户登录] RSA 加密密码...");
4179
- const encryptedPassword = rsaEncrypt(this.config.userPass);
4180
- if (!encryptedPassword) {
4181
- throw new AppError$1(ERROR_CODES$1.LOGIN_FAILED, "密码加密失败");
4232
+ return this.hV;
4233
+ };
4234
+ if (params !== void 0) {
4235
+ if (params.str !== void 0) {
4236
+ this.setString(params.str);
4237
+ } else if (typeof params == "string" && params.match(/^[0-9]{14}Z$/)) {
4238
+ this.setString(params);
4239
+ } else if (params.hex !== void 0) {
4240
+ this.setStringHex(params.hex);
4241
+ } else if (params.date !== void 0) {
4242
+ this.setByDate(params.date);
4182
4243
  }
4183
- debugLog("[用户登录] 密码加密成功");
4184
- debugLog("[用户登录] 调用登录接口...");
4185
- const token = await login(this.config.phone, encryptedPassword, env);
4186
- this.prefixText += chalk.green(`✓ 用户登录成功
4187
- `);
4188
- debugLog("[用户登录] 登录成功");
4189
- return token;
4190
- }
4191
- async doFetchBoundConfig(env, token) {
4192
- this.spinner.prefixText = this.prefixText;
4193
- this.spinner.text = `${chalk.cyan("获取配置")} ${chalk.dim("→")} ${chalk.yellow("正在获取绑定配置...")}`;
4194
- debugLog("[获取配置] 调用绑定配置接口...");
4195
- const boundConfig = await fetchBoundConfig(token, this.config.phone, env);
4196
- debugLog(`[获取配置] agentId=${boundConfig.agentId}, appKey=${boundConfig.appKey?.slice(0, 8)}...`);
4197
- this.prefixText += chalk.green(`✓ 绑定配置获取成功
4198
- `);
4199
- debugLog("[获取配置] 获取成功");
4200
- return boundConfig;
4201
- }
4202
- async doCleanOldFiles(targetPath) {
4203
- this.spinner.prefixText = this.prefixText;
4204
- this.spinner.text = `${chalk.cyan("清理旧版本")} ${chalk.dim("→")} ${chalk.yellow("检查目录...")}`;
4205
- debugLog(`[清理旧版本] 检查目录: ${targetPath}`);
4206
- try {
4207
- await fs.access(targetPath);
4208
- debugLog("[清理旧版本] 发现旧版本,开始清理...");
4209
- this.spinner.prefixText = this.prefixText;
4210
- this.spinner.text = `${chalk.cyan("清理旧版本")} ${chalk.dim("→")} ${chalk.yellow("正在清理...")}`;
4211
- await fs.rm(targetPath, { recursive: true, force: true });
4212
- this.prefixText += chalk.green(`✓ 旧版本清理完成
4213
- `);
4214
- debugLog("[清理旧版本] 清理完成");
4215
- } catch {
4216
- this.prefixText += chalk.green(`✓ 未发现旧版本
4217
- `);
4218
- debugLog("[清理旧版本] 未发现旧版本");
4244
+ if (params.millis === true) {
4245
+ this.withMillis = true;
4219
4246
  }
4220
4247
  }
4221
- async doDownloadFromNpm(paths) {
4222
- this.spinner.prefixText = this.prefixText;
4223
- this.spinner.text = `${chalk.cyan("下载插件")} ${chalk.dim("→")} ${chalk.yellow("准备目录")}`;
4224
- debugLog("[下载插件] 创建扩展目录...");
4225
- await fs.mkdir(paths.extensions, { recursive: true });
4226
- debugLog(`[下载插件] 扩展目录: ${paths.extensions}`);
4227
- const tempDir = path.join(paths.temp, `install-${Date.now()}`);
4228
- debugLog(`[下载插件] 创建临时目录: ${tempDir}`);
4229
- await fs.mkdir(tempDir, { recursive: true });
4230
- this.spinner.prefixText = this.prefixText;
4231
- this.spinner.text = `${chalk.cyan("下载插件")} ${chalk.dim("→")} ${chalk.yellow("下载 tarball")}`;
4232
- debugLog("[下载插件] 执行 npm pack 下载源码包");
4233
- debugLog(`[下载插件] 工作目录: ${tempDir}`);
4234
- const maxRetries = 3;
4235
- let lastError = "";
4236
- let tarballPath = "";
4237
- for (let i = 1; i <= maxRetries; i++) {
4238
- debugLog(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
4239
- try {
4240
- const packageName = this.getPackageName();
4241
- debugLog(`[下载插件] 下载包名: ${packageName}`);
4242
- const output = execSync(
4243
- `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts`,
4244
- { cwd: tempDir, encoding: "utf-8", timeout: 6e4 }
4245
- );
4246
- const filename = output.trim().split("\n").pop() || "";
4247
- tarballPath = path.join(tempDir, filename);
4248
- debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
4249
- break;
4250
- } catch (error) {
4251
- lastError = error.stderr?.toString() || error.message || "未知错误";
4252
- debugLog(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
4253
- if (i < maxRetries) {
4254
- debugLog("[下载插件] 等待 3 秒后重试...");
4255
- await new Promise((resolve2) => setTimeout(resolve2, 3e3));
4256
- }
4257
- }
4248
+ };
4249
+ extendClass(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime);
4250
+ KJUR.asn1.DERSequence = function(params) {
4251
+ KJUR.asn1.DERSequence.superclass.constructor.call(this, params);
4252
+ this.hT = "30";
4253
+ this.getFreshValueHex = function() {
4254
+ var h = "";
4255
+ for (var i = 0; i < this.asn1Array.length; i++) {
4256
+ var asn1Obj = this.asn1Array[i];
4257
+ h += asn1Obj.getEncodedHex();
4258
4258
  }
4259
- if (!tarballPath || !await fs.access(tarballPath).then(() => true).catch(() => false)) {
4260
- throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 下载失败: ${lastError}`);
4259
+ this.hV = h;
4260
+ return this.hV;
4261
+ };
4262
+ };
4263
+ extendClass(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured);
4264
+ KJUR.asn1.DERSet = function(params) {
4265
+ KJUR.asn1.DERSet.superclass.constructor.call(this, params);
4266
+ this.hT = "31";
4267
+ this.sortFlag = true;
4268
+ this.getFreshValueHex = function() {
4269
+ var a = new Array();
4270
+ for (var i = 0; i < this.asn1Array.length; i++) {
4271
+ var asn1Obj = this.asn1Array[i];
4272
+ a.push(asn1Obj.getEncodedHex());
4261
4273
  }
4262
- this.spinner.prefixText = this.prefixText;
4263
- this.spinner.text = `${chalk.cyan("下载插件")} ${chalk.dim("→")} ${chalk.yellow("解压 tarball")}`;
4264
- debugLog(`[下载插件] 创建插件目录: ${paths.target}`);
4265
- await fs.mkdir(paths.target, { recursive: true });
4266
- debugLog(`[下载插件] 解压 tarball 到: ${paths.target}`);
4267
- try {
4268
- await tar.extract({
4269
- file: tarballPath,
4270
- cwd: paths.target,
4271
- strip: 1
4272
- });
4273
- debugLog("[下载插件] tarball 解压成功");
4274
- } catch (error) {
4275
- throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, `tarball 解压失败: ${error.message}`);
4274
+ if (this.sortFlag == true)
4275
+ a.sort();
4276
+ this.hV = a.join("");
4277
+ return this.hV;
4278
+ };
4279
+ if (typeof params != "undefined") {
4280
+ if (typeof params.sortflag != "undefined" && params.sortflag == false)
4281
+ this.sortFlag = false;
4282
+ }
4283
+ };
4284
+ extendClass(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured);
4285
+ KJUR.asn1.DERTaggedObject = function(params) {
4286
+ KJUR.asn1.DERTaggedObject.superclass.constructor.call(this);
4287
+ this.hT = "a0";
4288
+ this.hV = "";
4289
+ this.isExplicit = true;
4290
+ this.asn1Object = null;
4291
+ this.setASN1Object = function(isExplicitFlag, tagNoHex, asn1Object) {
4292
+ this.hT = tagNoHex;
4293
+ this.isExplicit = isExplicitFlag;
4294
+ this.asn1Object = asn1Object;
4295
+ if (this.isExplicit) {
4296
+ this.hV = this.asn1Object.getEncodedHex();
4297
+ this.hTLV = null;
4298
+ this.isModified = true;
4299
+ } else {
4300
+ this.hV = null;
4301
+ this.hTLV = asn1Object.getEncodedHex();
4302
+ this.hTLV = this.hTLV.replace(/^../, tagNoHex);
4303
+ this.isModified = false;
4276
4304
  }
4277
- const pluginPath = path.join(paths.target, "package.json");
4278
- const pluginExists = await fs.access(pluginPath).then(() => true).catch(() => false);
4279
- if (!pluginExists) {
4280
- throw new AppError$1(ERROR_CODES$1.NPM_INSTALL_FAILED, "插件解压后未找到 package.json");
4305
+ };
4306
+ this.getFreshValueHex = function() {
4307
+ return this.hV;
4308
+ };
4309
+ if (typeof params != "undefined") {
4310
+ if (typeof params["tag"] != "undefined") {
4311
+ this.hT = params["tag"];
4281
4312
  }
4282
- debugLog("[下载插件] 插件解压成功");
4283
- this.spinner.prefixText = this.prefixText;
4284
- this.spinner.text = `${chalk.cyan("下载插件")} ${chalk.dim("→")} ${chalk.yellow("安装依赖")}`;
4285
- debugLog("[下载插件] 执行 npm install 安装生产环境依赖");
4286
- try {
4287
- execSync("npm install --omit=dev --ignore-scripts", {
4288
- cwd: paths.target,
4289
- stdio: "pipe",
4290
- timeout: 12e4
4291
- });
4292
- debugLog("[下载插件] npm install 执行成功");
4293
- } catch (error) {
4294
- const stderr = error.stderr?.toString() || "";
4295
- const stdout = error.stdout?.toString() || "";
4296
- const combinedOutput = stderr + stdout;
4297
- if (combinedOutput.includes("npm warn") || combinedOutput.includes("deprecated")) {
4298
- debugLog("[下载插件] npm install 有警告但可能成功,继续流程");
4299
- } else {
4300
- debugLog(`[下载插件] npm install 失败: ${combinedOutput}`);
4301
- }
4313
+ if (typeof params["explicit"] != "undefined") {
4314
+ this.isExplicit = params["explicit"];
4302
4315
  }
4303
- this.prefixText += chalk.green(`✓ 插件下载完成
4304
- `);
4305
- try {
4306
- await fs.rm(tempDir, { recursive: true, force: true });
4307
- debugLog("[下载插件] 清理临时目录完成");
4308
- } catch {
4309
- debugLog("[下载插件] 清理临时目录失败(忽略)");
4316
+ if (typeof params["obj"] != "undefined") {
4317
+ this.asn1Object = params["obj"];
4318
+ this.setASN1Object(this.isExplicit, this.hT, this.asn1Object);
4310
4319
  }
4311
4320
  }
4312
- async doUpdateConfig(paths, boundConfig, env) {
4313
- this.spinner.prefixText = this.prefixText;
4314
- this.spinner.text = `${chalk.cyan("更新配置")} ${chalk.dim("→")} ${chalk.yellow("写入配置文件")}`;
4315
- debugLog("[更新配置] 创建目录...");
4316
- await fs.mkdir(paths.home, { recursive: true });
4317
- await fs.mkdir(paths.workspace, { recursive: true });
4318
- debugLog("[更新配置] 目录创建完成");
4319
- debugLog("[更新配置] 读取原有配置...");
4320
- let originalConfig = {};
4321
- try {
4322
- const content = await fs.readFile(paths.config, "utf-8");
4323
- originalConfig = JSON.parse(content);
4324
- debugLog("[更新配置] 读取原有配置成功");
4325
- } catch {
4326
- debugLog("[更新配置] 无原有配置");
4327
- }
4328
- const config = getConfig(env);
4329
- const newConfig = {
4330
- // diagnostics: 诊断配置
4331
- diagnostics: {
4332
- // 启用诊断功能
4333
- enabled: true,
4334
- // 启用所有诊断标志 ['*'] 表示全部,[] 表示禁用所有
4335
- flags: ["*"]
4336
- },
4337
- // browser: 浏览器配置
4338
- browser: {
4339
- // 禁用浏览器工具
4340
- enabled: false
4341
- },
4342
- // models: 模型配置
4343
- models: {
4344
- // 配置合并模式:'merge' 合并 | 'replace' 替换
4345
- mode: "merge",
4346
- providers: {
4347
- "siliconflow-minimax": {
4348
- // 模型 API 基础地址
4349
- baseUrl: boundConfig.modelApiBaseUrl || config.MODEL_BASE_URL,
4350
- // API 密钥(从服务器获取)
4351
- apiKey: boundConfig.modelApiKey,
4352
- // API 类型:'openai-completions' | 'openai-chat' 等
4353
- api: "openai-completions",
4354
- // 是否使用 Authorization header 认证
4355
- authHeader: true,
4356
- models: [{
4357
- // 模型 ID(provider/model 格式)
4358
- id: "Pro/MiniMaxAI/MiniMax-M2.5",
4359
- // 模型显示名称
4360
- name: "MiniMax-M2.5",
4361
- // 是否启用推理能力
4362
- reasoning: false,
4363
- // 支持的输入类型:['text'] | ['text', 'image']
4364
- input: ["text"],
4365
- // 价格(0 表示免费或未设置)
4366
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
4367
- // 上下文窗口大小(token)
4368
- contextWindow: 2e5,
4369
- // 最大输出 token 数
4370
- maxTokens: 65536
4371
- }]
4372
- }
4373
- }
4374
- },
4375
- // agents: 代理配置
4376
- agents: {
4377
- defaults: {
4378
- // 默认使用的模型
4379
- model: { primary: "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5" },
4380
- models: {
4381
- "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5": {
4382
- // 模型别名,用于显示
4383
- alias: "Pro/MiniMaxAI/MiniMax-M2.5"
4384
- }
4385
- },
4386
- // 工作区目录路径
4387
- workspace: paths.workspace,
4388
- // 会话压缩模式:'safeguard' 保守模式
4389
- compaction: { mode: "safeguard" },
4390
- // 详细程度:'full' | 'short' | 'off'
4391
- verboseDefault: "full",
4392
- // 最大并发任务数
4393
- maxConcurrent: 4,
4394
- // 子代理最大并发数
4395
- subagents: { maxConcurrent: 8 }
4396
- },
4397
- // 代理列表
4398
- list: [{ id: "main", workspace: paths.workspace }]
4399
- },
4400
- // tools: 工具配置
4401
- tools: {
4402
- // 禁用的工具列表(优先于 allow)
4403
- deny: ["image", "web_search", "web_fetch"],
4404
- // 图像分析工具
4405
- media: { image: { enabled: false } },
4406
- // 网络搜索和抓取工具
4407
- web: { search: { enabled: false }, fetch: { enabled: false } },
4408
- // 提升权限工具(host=gateway)
4409
- elevated: { enabled: true, allowFrom: { webchat: ["*"] } },
4410
- // exec 工具安全级别:'deny' | 'allowlist' | 'full'
4411
- exec: { security: "full" }
4412
- },
4413
- // bindings: 绑定配置
4414
- bindings: [{
4415
- // 绑定的代理 ID
4416
- agentId: "main",
4417
- // 匹配的通道和账户
4418
- match: { channel: "openclaw-workclaw", accountId: "default" }
4419
- }],
4420
- // messages: 消息配置
4421
- messages: {
4422
- // 消息确认范围
4423
- ackReactionScope: "group-mentions"
4424
- },
4425
- // commands: 命令配置
4426
- commands: {
4427
- // 本机命令:'auto' | 'on' | 'off'
4428
- native: "auto",
4429
- // 本机技能:'auto' | 'on' | 'off'
4430
- nativeSkills: "auto",
4431
- // 是否允许重启命令
4432
- restart: true,
4433
- // 所有者显示格式:'raw' | 'name' | 'hidden'
4434
- ownerDisplay: "raw"
4435
- },
4436
- // session: 会话配置
4437
- session: {
4438
- // DM 作用域
4439
- dmScope: "per-account-channel-peer"
4440
- },
4441
- // hooks: 钩子配置
4442
- hooks: {
4443
- internal: {
4444
- // 启用内部钩子
4445
- enabled: true,
4446
- entries: {
4447
- // 启动 Markdown 钩子
4448
- "boot-md": { enabled: true },
4449
- // 引导额外文件钩子
4450
- "bootstrap-extra-files": { enabled: true },
4451
- // 命令日志钩子
4452
- "command-logger": { enabled: true },
4453
- // 会话记忆钩子
4454
- "session-memory": { enabled: true }
4455
- }
4456
- }
4457
- },
4458
- // channels: 通道配置
4459
- channels: {
4460
- "openclaw-workclaw": {
4461
- // 启用通道
4462
- enabled: true,
4463
- // 连接模式:'websocket' | 'http'
4464
- connectionMode: "websocket",
4465
- // WebSocket 连接策略
4466
- wsConnectionStrategy: "per-appKey",
4467
- // 应用密钥(从服务器获取)
4468
- appKey: boundConfig.appKey,
4469
- // 应用密钥(从服务器获取)
4470
- appSecret: boundConfig.appSecret,
4471
- // API 基础 URL
4472
- baseUrl: this.config.baseUrl || config.DEFAULT_BASE_URL,
4473
- // WebSocket URL
4474
- websocketUrl: this.config.wsUrl || config.DEFAULT_WS_URL,
4475
- // 允许不安全的 TLS 连接
4476
- allowInsecureTls: true,
4477
- // 允许原始 JSON 载荷
4478
- allowRawJsonPayload: true,
4479
- accounts: {
4480
- // 账户配置(agentId 从服务器获取)
4481
- default: { enabled: true, agentId: boundConfig.agentId }
4482
- }
4483
- }
4484
- },
4485
- // gateway: 网关配置
4486
- gateway: {
4487
- // 网关模式:'local' | 'hosted'
4488
- mode: "local",
4489
- // 网关端口
4490
- port: 18789,
4491
- // 绑定地址:'loopback' | 'lan' | 'all'
4492
- bind: "lan",
4493
- // 认证模式(token字段未设置,是因为需要使用原始配置的token)
4494
- auth: {
4495
- mode: "token"
4496
- },
4497
- // Tailscale 配置
4498
- tailscale: { mode: "off", resetOnExit: false },
4499
- nodes: {
4500
- // 节点上禁止的命令
4501
- denyCommands: [
4502
- "camera.snap",
4503
- "camera.clip",
4504
- "screen.record",
4505
- "contacts.add",
4506
- "calendar.add",
4507
- "reminders.add"
4508
- ]
4509
- },
4510
- controlUi: {
4511
- // 允许不安全认证
4512
- allowInsecureAuth: true,
4513
- // 禁用设备认证(仅用于开发)
4514
- dangerouslyDisableDeviceAuth: true,
4515
- // 允许 Host 头源回退
4516
- dangerouslyAllowHostHeaderOriginFallback: true,
4517
- // 允许的源
4518
- allowedOrigins: ["http://localhost:18789", "http://127.0.0.1:18789"]
4321
+ };
4322
+ extendClass(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object);
4323
+ var __extends = /* @__PURE__ */ function() {
4324
+ var extendStatics = function(d, b) {
4325
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
4326
+ d2.__proto__ = b2;
4327
+ } || function(d2, b2) {
4328
+ for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];
4329
+ };
4330
+ return extendStatics(d, b);
4331
+ };
4332
+ return function(d, b) {
4333
+ if (typeof b !== "function" && b !== null)
4334
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
4335
+ extendStatics(d, b);
4336
+ function __() {
4337
+ this.constructor = d;
4338
+ }
4339
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
4340
+ };
4341
+ }();
4342
+ var JSEncryptRSAKey = (
4343
+ /** @class */
4344
+ function(_super) {
4345
+ __extends(JSEncryptRSAKey2, _super);
4346
+ function JSEncryptRSAKey2(key) {
4347
+ var _this = _super.call(this) || this;
4348
+ if (key) {
4349
+ if (typeof key === "string") {
4350
+ _this.parseKey(key);
4351
+ } else if (JSEncryptRSAKey2.hasPrivateKeyProperty(key) || JSEncryptRSAKey2.hasPublicKeyProperty(key)) {
4352
+ _this.parsePropertiesFrom(key);
4519
4353
  }
4520
- },
4521
- // skills: 技能配置
4522
- skills: {
4523
- // 技能加载监视模式
4524
- load: { watch: true }
4525
- },
4526
- // logging: 日志配置
4527
- logging: {
4528
- // 日志级别:'debug' | 'info' | 'warn' | 'error'
4529
- level: "trace",
4530
- // 控制台日志级别
4531
- consoleLevel: "trace",
4532
- // 控制台样式:'pretty' | 'basic' | 'raw'
4533
- consoleStyle: "pretty",
4534
- // 敏感信息脱敏:'off' | 'keys' | 'all'
4535
- redactSensitive: "off",
4536
- // 日志文件路径(空表示不写入文件)
4537
- file: "",
4538
- // 脱敏模式(正则表达式)
4539
- redactPatterns: ["sk-.*"]
4540
- },
4541
- // plugins: 插件配置
4542
- plugins: {
4543
- // 允许的插件列表
4544
- allow: [config.PLUGIN_NAME],
4545
- // 插件安装跟踪(支持 openclaw plugins update 命令)
4546
- installs: {
4547
- [config.PLUGIN_NAME]: {
4548
- // 安装来源
4549
- source: "npm",
4550
- // npm 包名
4551
- spec: PLUGIN_PACKAGE_NAME$1,
4552
- // 安装路径
4553
- installPath: paths.target
4354
+ }
4355
+ return _this;
4356
+ }
4357
+ JSEncryptRSAKey2.prototype.parseKey = function(pem) {
4358
+ try {
4359
+ var modulus = 0;
4360
+ var public_exponent = 0;
4361
+ var reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/;
4362
+ var der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem);
4363
+ var asn1 = ASN1.decode(der);
4364
+ if (asn1.sub.length === 3) {
4365
+ asn1 = asn1.sub[2].sub[0];
4366
+ }
4367
+ if (asn1.sub.length === 9) {
4368
+ modulus = asn1.sub[1].getHexStringValue();
4369
+ this.n = parseBigInt(modulus, 16);
4370
+ public_exponent = asn1.sub[2].getHexStringValue();
4371
+ this.e = parseInt(public_exponent, 16);
4372
+ var private_exponent = asn1.sub[3].getHexStringValue();
4373
+ this.d = parseBigInt(private_exponent, 16);
4374
+ var prime1 = asn1.sub[4].getHexStringValue();
4375
+ this.p = parseBigInt(prime1, 16);
4376
+ var prime2 = asn1.sub[5].getHexStringValue();
4377
+ this.q = parseBigInt(prime2, 16);
4378
+ var exponent1 = asn1.sub[6].getHexStringValue();
4379
+ this.dmp1 = parseBigInt(exponent1, 16);
4380
+ var exponent2 = asn1.sub[7].getHexStringValue();
4381
+ this.dmq1 = parseBigInt(exponent2, 16);
4382
+ var coefficient = asn1.sub[8].getHexStringValue();
4383
+ this.coeff = parseBigInt(coefficient, 16);
4384
+ } else if (asn1.sub.length === 2) {
4385
+ if (asn1.sub[0].sub) {
4386
+ var bit_string = asn1.sub[1];
4387
+ var sequence = bit_string.sub[0];
4388
+ modulus = sequence.sub[0].getHexStringValue();
4389
+ this.n = parseBigInt(modulus, 16);
4390
+ public_exponent = sequence.sub[1].getHexStringValue();
4391
+ this.e = parseInt(public_exponent, 16);
4392
+ } else {
4393
+ modulus = asn1.sub[0].getHexStringValue();
4394
+ this.n = parseBigInt(modulus, 16);
4395
+ public_exponent = asn1.sub[1].getHexStringValue();
4396
+ this.e = parseInt(public_exponent, 16);
4554
4397
  }
4555
- },
4556
- load: {
4557
- paths: [paths.target]
4558
- },
4559
- // 插件条目启用状态
4560
- entries: {
4561
- [config.PLUGIN_NAME]: { enabled: true }
4398
+ } else {
4399
+ return false;
4562
4400
  }
4401
+ return true;
4402
+ } catch (ex) {
4403
+ return false;
4563
4404
  }
4564
4405
  };
4565
- const finalConfig = deepMerge$1(originalConfig, newConfig);
4566
- debugLog("[更新配置] 写入配置文件...");
4567
- await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
4568
- this.prefixText += chalk.green(`✓ 配置文件更新成功
4569
- `);
4570
- debugLog(`[更新配置] 配置文件写入成功: ${paths.config}`);
4571
- }
4572
- }
4573
- function checkEnv$1() {
4574
- debugLog("[环境检查] 检测 Node.js 版本...");
4575
- const nodeVersion = execSync("node --version", { stdio: "pipe" }).toString().trim();
4576
- debugLog(`[环境检查] Node.js 版本: ${nodeVersion}`);
4577
- if (!semver.gte(nodeVersion, "18.0.0")) {
4578
- throw new AppError$1(ERROR_CODES$1.NODE_VERSION_LOW, `Node.js 版本需要 >= 18.0.0,当前版本: ${nodeVersion}`);
4579
- }
4580
- debugLog("[环境检查] Node.js 版本检查通过");
4581
- debugLog("[环境检查] 检测 npm...");
4582
- try {
4583
- const npmVersion = execSync("npm --version", { stdio: "pipe" }).toString().trim();
4584
- debugLog(`[环境检查] npm 版本: ${npmVersion}`);
4585
- debugLog("[环境检查] npm 检测通过");
4586
- } catch {
4587
- throw new AppError$1(ERROR_CODES$1.NPM_NOT_FOUND, "未检测到 npm,请先安装 Node.js 和 npm");
4588
- }
4589
- }
4590
- async function createLocalCommand(options) {
4591
- setDebug(!!options.debug);
4592
- debugLog("[初始化] 开始处理...");
4593
- debugLog(`[初始化] 参数: scenario=${options.scenario}, env=${options.env}, phone=${options.phone}, debug=${options.debug}`);
4594
- checkEnv$1();
4595
- debugLog("[初始化] 环境检查通过");
4596
- try {
4597
- let scenario = options.scenario;
4598
- let env = options.env;
4599
- let phone = options.phone;
4600
- let userPass = options.userPass;
4601
- const questions = [];
4602
- if (!scenario) {
4603
- debugLog("[初始化] 需要选择安装场景");
4604
- questions.push({
4605
- type: "list",
4606
- name: "scenario",
4607
- message: `${nodeEmoji.get("desktop_computer")} 请选择安装场景:`,
4608
- default: "windows-local",
4609
- choices: [
4610
- { name: `${chalk.green("Windows")} ${chalk.gray("本地安装")}`, value: "windows-local" },
4611
- { name: `${chalk.green("macOS")} ${chalk.gray("本地安装")}`, value: "mac-local" },
4612
- { name: `${chalk.green("Linux")} ${chalk.gray("本地安装")}`, value: "linux-local" }
4406
+ JSEncryptRSAKey2.prototype.getPrivateBaseKey = function() {
4407
+ var options = {
4408
+ array: [
4409
+ new KJUR.asn1.DERInteger({ int: 0 }),
4410
+ new KJUR.asn1.DERInteger({ bigint: this.n }),
4411
+ new KJUR.asn1.DERInteger({ int: this.e }),
4412
+ new KJUR.asn1.DERInteger({ bigint: this.d }),
4413
+ new KJUR.asn1.DERInteger({ bigint: this.p }),
4414
+ new KJUR.asn1.DERInteger({ bigint: this.q }),
4415
+ new KJUR.asn1.DERInteger({ bigint: this.dmp1 }),
4416
+ new KJUR.asn1.DERInteger({ bigint: this.dmq1 }),
4417
+ new KJUR.asn1.DERInteger({ bigint: this.coeff })
4418
+ ]
4419
+ };
4420
+ var seq = new KJUR.asn1.DERSequence(options);
4421
+ return seq.getEncodedHex();
4422
+ };
4423
+ JSEncryptRSAKey2.prototype.getPrivateBaseKeyB64 = function() {
4424
+ return hex2b64(this.getPrivateBaseKey());
4425
+ };
4426
+ JSEncryptRSAKey2.prototype.getPublicBaseKey = function() {
4427
+ var first_sequence = new KJUR.asn1.DERSequence({
4428
+ array: [
4429
+ new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }),
4430
+ // RSA Encryption pkcs #1 oid
4431
+ new KJUR.asn1.DERNull()
4613
4432
  ]
4614
4433
  });
4615
- } else {
4616
- debugLog(`[初始化] 使用命令行参数: scenario=${scenario}`);
4617
- }
4618
- if (!env) {
4619
- debugLog("[初始化] 需要选择环境");
4620
- questions.push({
4621
- type: "list",
4622
- name: "env",
4623
- message: `${nodeEmoji.get("globe_with_meridians")} 请选择环境:`,
4624
- default: "test",
4625
- choices: [
4626
- { name: `${chalk.green("测试环境")} ${chalk.gray("(test)")}`, value: "test" },
4627
- { name: `${chalk.red("正式环境")} ${chalk.gray("(prod)")}`, value: "prod" }
4434
+ var second_sequence = new KJUR.asn1.DERSequence({
4435
+ array: [
4436
+ new KJUR.asn1.DERInteger({ bigint: this.n }),
4437
+ new KJUR.asn1.DERInteger({ int: this.e })
4628
4438
  ]
4629
4439
  });
4630
- } else {
4631
- debugLog(`[初始化] 使用命令行参数: env=${env}`);
4440
+ var bit_string = new KJUR.asn1.DERBitString({
4441
+ hex: "00" + second_sequence.getEncodedHex()
4442
+ });
4443
+ var seq = new KJUR.asn1.DERSequence({
4444
+ array: [first_sequence, bit_string]
4445
+ });
4446
+ return seq.getEncodedHex();
4447
+ };
4448
+ JSEncryptRSAKey2.prototype.getPublicBaseKeyB64 = function() {
4449
+ return hex2b64(this.getPublicBaseKey());
4450
+ };
4451
+ JSEncryptRSAKey2.wordwrap = function(str, width) {
4452
+ width = width || 64;
4453
+ if (!str) {
4454
+ return str;
4455
+ }
4456
+ var regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
4457
+ return str.match(RegExp(regex, "g")).join("\n");
4458
+ };
4459
+ JSEncryptRSAKey2.prototype.getPrivateKey = function() {
4460
+ var key = "-----BEGIN RSA PRIVATE KEY-----\n";
4461
+ key += JSEncryptRSAKey2.wordwrap(this.getPrivateBaseKeyB64()) + "\n";
4462
+ key += "-----END RSA PRIVATE KEY-----";
4463
+ return key;
4464
+ };
4465
+ JSEncryptRSAKey2.prototype.getPublicKey = function() {
4466
+ var key = "-----BEGIN PUBLIC KEY-----\n";
4467
+ key += JSEncryptRSAKey2.wordwrap(this.getPublicBaseKeyB64()) + "\n";
4468
+ key += "-----END PUBLIC KEY-----";
4469
+ return key;
4470
+ };
4471
+ JSEncryptRSAKey2.hasPublicKeyProperty = function(obj) {
4472
+ obj = obj || {};
4473
+ return obj.hasOwnProperty("n") && obj.hasOwnProperty("e");
4474
+ };
4475
+ JSEncryptRSAKey2.hasPrivateKeyProperty = function(obj) {
4476
+ obj = obj || {};
4477
+ return obj.hasOwnProperty("n") && obj.hasOwnProperty("e") && obj.hasOwnProperty("d") && obj.hasOwnProperty("p") && obj.hasOwnProperty("q") && obj.hasOwnProperty("dmp1") && obj.hasOwnProperty("dmq1") && obj.hasOwnProperty("coeff");
4478
+ };
4479
+ JSEncryptRSAKey2.prototype.parsePropertiesFrom = function(obj) {
4480
+ this.n = obj.n;
4481
+ this.e = obj.e;
4482
+ if (obj.hasOwnProperty("d")) {
4483
+ this.d = obj.d;
4484
+ this.p = obj.p;
4485
+ this.q = obj.q;
4486
+ this.dmp1 = obj.dmp1;
4487
+ this.dmq1 = obj.dmq1;
4488
+ this.coeff = obj.coeff;
4489
+ }
4490
+ };
4491
+ return JSEncryptRSAKey2;
4492
+ }(RSAKey)
4493
+ );
4494
+ var _a;
4495
+ var version = typeof process !== "undefined" ? (_a = process.env) === null || _a === void 0 ? void 0 : _a.npm_package_version : void 0;
4496
+ var JSEncrypt = (
4497
+ /** @class */
4498
+ function() {
4499
+ function JSEncrypt2(options) {
4500
+ if (options === void 0) {
4501
+ options = {};
4502
+ }
4503
+ this.default_key_size = options.default_key_size ? parseInt(options.default_key_size, 10) : 1024;
4504
+ this.default_public_exponent = options.default_public_exponent || "010001";
4505
+ this.log = options.log || false;
4506
+ this.key = options.key || null;
4632
4507
  }
4633
- if (!phone) {
4634
- debugLog("[初始化] 需要输入手机号码");
4635
- questions.push({
4636
- type: "input",
4637
- name: "phone",
4638
- message: `${nodeEmoji.get("phone")} 请输入手机号码:`,
4639
- validate: (value) => {
4640
- if (!value || value.trim() === "") {
4641
- return `${nodeEmoji.get("x")} 手机号码不能为空`;
4642
- }
4643
- if (!/^1[3-9]\d{9}$/.test(value)) {
4644
- return `${nodeEmoji.get("warning")} 请输入正确的手机号码`;
4645
- }
4646
- return true;
4508
+ JSEncrypt2.prototype.setKey = function(key) {
4509
+ if (key) {
4510
+ if (this.log && this.key) {
4511
+ console.warn("A key was already set, overriding existing.");
4647
4512
  }
4513
+ this.key = new JSEncryptRSAKey(key);
4514
+ } else if (!this.key && this.log) {
4515
+ console.error("A key was not set.");
4516
+ }
4517
+ };
4518
+ JSEncrypt2.prototype.setPrivateKey = function(privkey) {
4519
+ this.setKey(privkey);
4520
+ };
4521
+ JSEncrypt2.prototype.setPublicKey = function(pubkey) {
4522
+ this.setKey(pubkey);
4523
+ };
4524
+ JSEncrypt2.prototype.decrypt = function(str) {
4525
+ try {
4526
+ return this.getKey().decrypt(b64tohex(str));
4527
+ } catch (ex) {
4528
+ return false;
4529
+ }
4530
+ };
4531
+ JSEncrypt2.prototype.encrypt = function(str) {
4532
+ try {
4533
+ return hex2b64(this.getKey().encrypt(str));
4534
+ } catch (ex) {
4535
+ return false;
4536
+ }
4537
+ };
4538
+ JSEncrypt2.prototype.encryptOAEP = function(str) {
4539
+ try {
4540
+ return hex2b64(this.getKey().encrypt(str, oaep_pad));
4541
+ } catch (ex) {
4542
+ return false;
4543
+ }
4544
+ };
4545
+ JSEncrypt2.prototype.sign = function(str, digestMethod, digestName) {
4546
+ if (digestMethod === void 0) {
4547
+ digestMethod = function(raw) {
4548
+ return raw;
4549
+ };
4550
+ }
4551
+ if (digestName === void 0) {
4552
+ digestName = "";
4553
+ }
4554
+ try {
4555
+ return hex2b64(this.getKey().sign(str, digestMethod, digestName));
4556
+ } catch (ex) {
4557
+ return false;
4558
+ }
4559
+ };
4560
+ JSEncrypt2.prototype.signSha256 = function(str) {
4561
+ return this.sign(str, function(text) {
4562
+ return rstr2hex(rstr_sha256(text));
4563
+ }, "sha256");
4564
+ };
4565
+ JSEncrypt2.prototype.verify = function(str, signature, digestMethod) {
4566
+ if (digestMethod === void 0) {
4567
+ digestMethod = function(raw) {
4568
+ return raw;
4569
+ };
4570
+ }
4571
+ try {
4572
+ return this.getKey().verify(str, b64tohex(signature), digestMethod);
4573
+ } catch (ex) {
4574
+ return false;
4575
+ }
4576
+ };
4577
+ JSEncrypt2.prototype.verifySha256 = function(str, signature) {
4578
+ return this.verify(str, signature, function(text) {
4579
+ return rstr2hex(rstr_sha256(text));
4648
4580
  });
4649
- } else {
4650
- debugLog("[初始化] 使用命令行参数: phone");
4651
- }
4652
- if (!userPass) {
4653
- debugLog("[初始化] 需要输入用户密码");
4654
- questions.push({
4655
- type: "input",
4656
- name: "userPass",
4657
- message: `${nodeEmoji.get("key")} 请输入用户密码:`,
4658
- validate: (value) => {
4659
- if (!value || value.trim() === "") {
4660
- return `${nodeEmoji.get("x")} 用户密码不能为空`;
4661
- }
4662
- return true;
4581
+ };
4582
+ JSEncrypt2.prototype.getKey = function(cb) {
4583
+ if (!this.key) {
4584
+ this.key = new JSEncryptRSAKey();
4585
+ if (cb && {}.toString.call(cb) === "[object Function]") {
4586
+ this.key.generateAsync(this.default_key_size, this.default_public_exponent, cb);
4587
+ return;
4663
4588
  }
4664
- });
4665
- } else {
4666
- debugLog("[初始化] 使用命令行参数: userPass");
4667
- }
4668
- if (questions.length > 0) {
4669
- debugLog(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
4670
- const answers = await inquirer.prompt(questions);
4671
- debugLog("[初始化] 交互式问答完成");
4672
- scenario = scenario || answers.scenario;
4673
- env = env || answers.env || "test";
4674
- phone = phone || answers.phone;
4675
- userPass = userPass || answers.userPass;
4676
- }
4677
- debugLog(`[初始化] 最终参数: scenario=${scenario}, env=${env}, phone=${phone}, pluginVersion=${options.pluginVersion}`);
4678
- debugLog("[初始化] 创建 LocalInstaller 实例...");
4679
- const installer = new LocalInstaller({
4680
- phone,
4681
- userPass,
4682
- scenario,
4683
- env,
4684
- pluginVersion: options.pluginVersion
4685
- });
4686
- debugLog("[初始化] 开始安装...");
4687
- await installer.install();
4688
- debugLog("[初始化] 安装完成");
4689
- console.log(installer.getPrefixText() + boxen(
4690
- `${nodeEmoji.get("tada")} 插件初始化成功!`,
4691
- {
4692
- title: `${chalk.bold.green("初始化成功")}`,
4693
- titleAlignment: "center",
4694
- padding: { top: 1, bottom: 1, left: 5, right: 5 },
4695
- margin: 1,
4696
- borderStyle: "round",
4697
- borderColor: "green",
4698
- textAlignment: "center"
4699
- }
4700
- ));
4701
- } catch (error) {
4702
- debugLog(`[初始化] 发生错误: ${error.message}`);
4703
- console.error(boxen(
4704
- `${chalk.yellow(error.message)}`,
4705
- {
4706
- title: `${chalk.bold.red("初始化失败")}`,
4707
- titleAlignment: "center",
4708
- padding: { top: 1, bottom: 1, left: 5, right: 5 },
4709
- margin: 1,
4710
- borderStyle: "round",
4711
- borderColor: "red",
4712
- textAlignment: "center"
4589
+ this.key.generate(this.default_key_size, this.default_public_exponent);
4713
4590
  }
4714
- ));
4715
- process$1.exit(1);
4716
- }
4717
- }
4718
- function registerCommands$1(program2) {
4719
- program2.command("local").description("本地账户安装(需要登录)").option("-s, --scenario <scenario>", "安装场景").option("-e, --env <env>", "环境 (test/prod)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--debug", "开启调试日志").action(createLocalCommand);
4720
- }
4721
- const ERROR_CODES = {
4722
- APP_KEY_REQUIRED: "APP_KEY_REQUIRED",
4723
- APP_SECRET_REQUIRED: "APP_SECRET_REQUIRED",
4724
- NODE_VERSION_LOW: "NODE_VERSION_LOW",
4725
- NODE_NOT_FOUND: "NODE_NOT_FOUND",
4726
- NPM_NOT_FOUND: "NPM_NOT_FOUND",
4727
- NPM_INSTALL_FAILED: "NPM_INSTALL_FAILED",
4728
- CONFIG_WRITE_FAILED: "CONFIG_WRITE_FAILED",
4729
- PLUGIN_EXTRACT_FAILED: "PLUGIN_EXTRACT_FAILED"
4730
- };
4731
- class AppError2 extends Error {
4732
- constructor(code, message) {
4733
- super(message);
4734
- this.code = code;
4735
- this.name = "AppError";
4736
- }
4591
+ return this.key;
4592
+ };
4593
+ JSEncrypt2.prototype.getPrivateKey = function() {
4594
+ return this.getKey().getPrivateKey();
4595
+ };
4596
+ JSEncrypt2.prototype.getPrivateKeyB64 = function() {
4597
+ return this.getKey().getPrivateBaseKeyB64();
4598
+ };
4599
+ JSEncrypt2.prototype.getPublicKey = function() {
4600
+ return this.getKey().getPublicKey();
4601
+ };
4602
+ JSEncrypt2.prototype.getPublicKeyB64 = function() {
4603
+ return this.getKey().getPublicBaseKeyB64();
4604
+ };
4605
+ JSEncrypt2.version = version;
4606
+ return JSEncrypt2;
4607
+ }()
4608
+ );
4609
+ const PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBSYtNb6neLrrwsuPBsIFjpZBrffdkA8bpp2S35o2TCdhfdxS0nc4pkv9cJLkUvFa+gdQ5nLifnK9B1XoVbIQwY212QAftTDbl77bcHu7GAbv2TZr9pelSeUm1SrtMK5HDr/LzxTutGr4DovVHiDgEn45GQ1X5U+zC0Jp4Awn6ZwIDAQAB";
4610
+ function rsaEncrypt(txt) {
4611
+ const encrypt = new JSEncrypt();
4612
+ encrypt.setPublicKey(PUBLIC_KEY);
4613
+ const result = encrypt.encrypt(txt);
4614
+ return result || null;
4737
4615
  }
4738
4616
  function getHomeDir() {
4739
4617
  return process$1.env.HOME || process$1.env.USERPROFILE || "";
4740
4618
  }
4741
4619
  const PLUGIN_PACKAGE_NAME = "@workclaw/openclaw-workclaw";
4620
+ function execAsync(command, options) {
4621
+ return new Promise((resolve2, reject) => {
4622
+ exec(command, { cwd: options.cwd, timeout: options.timeout }, (error, stdout, stderr) => {
4623
+ if (error) {
4624
+ reject(new Error(stderr || error.message));
4625
+ } else {
4626
+ resolve2(stdout);
4627
+ }
4628
+ });
4629
+ });
4630
+ }
4742
4631
  function deepMerge(target, source) {
4743
4632
  const result = { ...target };
4744
4633
  for (const key in source) {
@@ -4752,194 +4641,132 @@ function deepMerge(target, source) {
4752
4641
  }
4753
4642
  return result;
4754
4643
  }
4755
- class BoxInstaller {
4644
+ class LocalInstaller {
4756
4645
  constructor(config) {
4757
4646
  this.config = config;
4758
4647
  this.spinner = ora({ color: "cyan" }).start();
4759
4648
  }
4760
4649
  spinner;
4761
4650
  prefixText = "";
4762
- getPackageName() {
4763
- if (this.config.pluginVersion) {
4764
- return `${PLUGIN_PACKAGE_NAME}@${this.config.pluginVersion}`;
4765
- }
4766
- return PLUGIN_PACKAGE_NAME;
4767
- }
4768
4651
  validateConfig() {
4769
- debugLog("[验证配置] 检查 appKey 和 appSecret...");
4770
- if (!this.config.appKey) {
4771
- throw new AppError2(ERROR_CODES.APP_KEY_REQUIRED, "AppKey 不能为空,请使用 --app-key 参数");
4652
+ debugLog("[验证配置] 检查手机号码和密码...");
4653
+ if (!this.config.phone) {
4654
+ throw new AppError2(ERROR_CODES.PHONE_REQUIRED, "手机号码不能为空,请使用 --phone 参数");
4772
4655
  }
4773
- if (!this.config.appSecret) {
4774
- throw new AppError2(ERROR_CODES.APP_SECRET_REQUIRED, "AppSecret 不能为空,请使用 --app-secret 参数");
4656
+ if (!this.config.userPass) {
4657
+ throw new AppError2(ERROR_CODES.USER_PASS_REQUIRED, "用户密码不能为空,请使用 --user-pass 参数");
4775
4658
  }
4776
- debugLog("[验证配置] 配置检查通过");
4777
- }
4778
- getPaths() {
4779
- const home = getHomeDir();
4780
- const openclawDir = path.join(home, ".openclaw");
4781
- const extensionsDir = path.join(openclawDir, "extensions");
4782
- const targetDir = path.join(extensionsDir, "openclaw-workclaw");
4783
- const configFile = path.join(openclawDir, "openclaw.json");
4784
- const workspaceDir = path.join(openclawDir, "workspace");
4785
- const tempDir = path.join(openclawDir, ".temp");
4786
- return {
4787
- home,
4788
- extensions: extensionsDir,
4789
- target: targetDir,
4790
- config: configFile,
4791
- workspace: workspaceDir,
4792
- temp: tempDir
4793
- };
4794
- }
4795
- updateSpinner(text) {
4796
- this.spinner.prefixText = this.prefixText;
4797
- this.spinner.text = `${chalk.cyan("安装进度")} ${chalk.dim("→")} ${chalk.yellow(text)}`;
4798
- debugLog(`[Spinner] ${text}`);
4799
- }
4800
- getPrefixText() {
4801
- return this.prefixText;
4659
+ debugLog("[验证配置] 配置验证通过");
4802
4660
  }
4803
4661
  async install() {
4804
4662
  try {
4805
- debugLog("[盒子安装] 开始安装...");
4663
+ debugLog("[安装开始]");
4806
4664
  this.validateConfig();
4807
- this.updateSpinner("验证配置完成");
4808
- const paths = this.getPaths();
4809
- await this.doCleanOldFiles(paths);
4810
- this.updateSpinner("清理旧版本完成");
4665
+ const env = this.config.env || "test";
4666
+ const config = getConfig(env);
4667
+ const homeDir = getHomeDir();
4668
+ const paths = {
4669
+ home: path.join(homeDir, config.DIRS.OPENCLAW),
4670
+ extensions: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS),
4671
+ target: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.EXTENSIONS, config.PLUGIN_NAME),
4672
+ config: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.CONFIG_FILE),
4673
+ workspace: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.WORKSPACE),
4674
+ temp: path.join(homeDir, config.DIRS.OPENCLAW, config.DIRS.TEMP)
4675
+ };
4676
+ debugLog(`[路径配置] home=${paths.home}`);
4677
+ debugLog(`[路径配置] extensions=${paths.extensions}`);
4678
+ debugLog(`[路径配置] target=${paths.target}`);
4679
+ debugLog(`[路径配置] config=${paths.config}`);
4680
+ debugLog(`[路径配置] workspace=${paths.workspace}`);
4681
+ const token = await this.doLogin(env);
4682
+ const boundConfig = await this.doFetchBoundConfig(env, token);
4683
+ await this.doCleanOldFiles(paths.target);
4811
4684
  await this.doDownloadFromNpm(paths);
4812
- this.updateSpinner("下载插件完成");
4813
- await this.doUpdateConfig(paths);
4814
- this.updateSpinner("更新配置完成");
4685
+ await this.doUpdateConfig(paths, boundConfig, env);
4815
4686
  this.spinner.stop();
4816
- debugLog("[盒子安装] 安装完成");
4817
4687
  } catch (error) {
4818
4688
  this.spinner.stop();
4819
- debugLog(`[盒子安装] 安装失败: ${error.message}`);
4820
4689
  throw error;
4821
4690
  }
4822
4691
  }
4823
- async doCleanOldFiles(paths) {
4824
- debugLog("[清理旧版本] 开始清理旧版本...");
4825
- this.prefixText += chalk.green(`✓ 开始清理旧版本
4692
+ getPrefixText() {
4693
+ return this.prefixText;
4694
+ }
4695
+ async doLogin(env) {
4696
+ this.spinner.prefixText = this.prefixText;
4697
+ this.spinner.text = chalk.cyan("正在验证账号...");
4698
+ debugLog(`[用户登录] 手机号: ${this.config.phone}`);
4699
+ debugLog("[用户登录] RSA 加密密码...");
4700
+ const encryptedPassword = rsaEncrypt(this.config.userPass);
4701
+ if (!encryptedPassword) {
4702
+ throw new AppError2(ERROR_CODES.LOGIN_FAILED, "密码加密失败");
4703
+ }
4704
+ debugLog("[用户登录] 密码加密成功");
4705
+ debugLog("[用户登录] 调用登录接口...");
4706
+ const token = await login(this.config.phone, encryptedPassword, env);
4707
+ this.prefixText += chalk.green(` ✓ 账号验证成功
4708
+ `);
4709
+ debugLog("[用户登录] 登录成功");
4710
+ return token;
4711
+ }
4712
+ async doFetchBoundConfig(env, token) {
4713
+ this.spinner.prefixText = this.prefixText;
4714
+ this.spinner.text = chalk.cyan("正在获取绑定信息...");
4715
+ debugLog("[获取配置] 调用绑定配置接口...");
4716
+ const boundConfig = await fetchBoundConfig(token, this.config.phone, env);
4717
+ debugLog(`[获取配置] agentId=${boundConfig.agentId}, appKey=${boundConfig.appKey?.slice(0, 8)}...`);
4718
+ this.prefixText += chalk.green(` ✓ 绑定信息获取成功
4826
4719
  `);
4720
+ debugLog("[获取配置] 获取成功");
4721
+ return boundConfig;
4722
+ }
4723
+ async doCleanOldFiles(targetPath) {
4724
+ this.spinner.prefixText = this.prefixText;
4725
+ this.spinner.text = chalk.cyan("正在检查已安装版本...");
4726
+ debugLog(`[清理旧版本] 检查目录: ${targetPath}`);
4827
4727
  try {
4828
- await fs.access(paths.target);
4829
- debugLog("[清理旧版本] 删除旧版本目录...");
4830
- await fs.rm(paths.target, { recursive: true, force: true });
4831
- this.prefixText += chalk.green(`✓ 旧版本清理成功
4728
+ await fs.access(targetPath);
4729
+ this.spinner.text = chalk.cyan("正在清理旧文件...");
4730
+ debugLog("[清理旧版本] 发现旧版本,开始清理...");
4731
+ await fs.rm(targetPath, { recursive: true, force: true });
4732
+ this.prefixText += chalk.green(` ✓ 旧版本清理完成
4832
4733
  `);
4833
- debugLog("[清理旧版本] 旧版本清理成功");
4734
+ debugLog("[清理旧版本] 清理完成");
4834
4735
  } catch {
4835
- debugLog("[清理旧版本] 无旧版本需要清理");
4836
- this.prefixText += chalk.green(`✓ 无旧版本需要清理
4736
+ this.prefixText += chalk.green(` ✓ 无旧版本需要清理
4837
4737
  `);
4838
- }
4839
- try {
4840
- await fs.access(paths.temp);
4841
- await fs.rm(paths.temp, { recursive: true, force: true });
4842
- } catch {
4843
- debugLog("[清理旧版本] 无临时目录需要清理");
4738
+ debugLog("[清理旧版本] 未发现旧版本");
4844
4739
  }
4845
4740
  }
4846
4741
  async doDownloadFromNpm(paths) {
4847
- debugLog("[下载插件] 开始下载插件...");
4848
- this.prefixText += chalk.green(`✓ 开始下载插件
4849
- `);
4850
- const maxRetries = 3;
4851
- let lastError = "";
4852
- let tarballPath = "";
4853
- for (let i = 1; i <= maxRetries; i++) {
4854
- debugLog(`[下载插件] 第 ${i} 次尝试下载 tarball...`);
4855
- try {
4856
- const packageName = this.getPackageName();
4857
- debugLog(`[下载插件] 下载包名: ${packageName}`);
4858
- const { execSync: execSync2 } = await import("node:child_process");
4859
- const output = execSync2(
4860
- `npm pack ${packageName} --registry=https://mirrors.tencent.com/npm/ --ignore-scripts`,
4861
- { cwd: paths.temp, encoding: "utf-8", timeout: 6e4 }
4862
- );
4863
- const filename = output.trim().split("\n").pop() || "";
4864
- tarballPath = path.join(paths.temp, filename);
4865
- debugLog(`[下载插件] tarball 下载成功: ${tarballPath}`);
4866
- break;
4867
- } catch (error) {
4868
- lastError = error.stderr?.toString() || error.message || "未知错误";
4869
- debugLog(`[下载插件] 第 ${i} 次尝试失败: ${lastError}`);
4870
- if (i < maxRetries) {
4871
- debugLog("[下载插件] 等待 3 秒后重试...");
4872
- await new Promise((resolve2) => setTimeout(resolve2, 3e3));
4873
- }
4874
- }
4875
- }
4876
- if (!tarballPath) {
4877
- this.prefixText += chalk.red(`✗ 下载失败
4878
- `);
4879
- throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `插件下载失败: ${lastError}`);
4880
- }
4881
- this.prefixText += chalk.green(`✓ 插件下载成功
4882
- `);
4883
- await this.extractTarball(tarballPath, paths);
4884
- }
4885
- async extractTarball(tarballPath, paths) {
4886
- debugLog("[解压插件] 开始解压 tarball...");
4742
+ this.spinner.prefixText = this.prefixText;
4743
+ this.spinner.text = chalk.cyan("正在安装插件...");
4744
+ debugLog("[安装插件] 创建扩展目录...");
4745
+ await fs.mkdir(paths.extensions, { recursive: true });
4746
+ debugLog(`[安装插件] 扩展目录: ${paths.extensions}`);
4747
+ debugLog("[安装插件] 执行 openclaw plugins install 命令");
4887
4748
  try {
4888
- await fs.mkdir(paths.temp, { recursive: true });
4889
- await tar.extract({
4890
- file: tarballPath,
4891
- cwd: paths.temp
4892
- });
4893
- const packageDir = path.join(paths.temp, "package");
4894
- const stat = await fs.stat(packageDir);
4895
- if (stat.isDirectory()) {
4896
- await fs.mkdir(paths.extensions, { recursive: true });
4897
- await fs.cp(packageDir, paths.target, { recursive: true });
4898
- debugLog(`[解压插件] 插件解压成功: ${paths.target}`);
4899
- this.prefixText += chalk.green(`✓ 插件解压成功
4900
- `);
4901
- this.spinner.prefixText = this.prefixText;
4902
- this.spinner.text = `${chalk.cyan("安装依赖")} ${chalk.dim("→")} ${chalk.yellow("正在安装...")}`;
4903
- debugLog("[安装依赖] 执行 npm install 安装生产环境依赖");
4904
- try {
4905
- execSync("npm install --omit=dev --ignore-scripts", {
4906
- cwd: paths.target,
4907
- stdio: "pipe",
4908
- timeout: 12e4
4909
- });
4910
- debugLog("[安装依赖] npm install 执行成功");
4911
- this.prefixText += chalk.green(`✓ 依赖安装成功
4912
- `);
4913
- } catch (error) {
4914
- const stderr = error.stderr?.toString() || "";
4915
- const stdout = error.stdout?.toString() || "";
4916
- const combinedOutput = stderr + stdout;
4917
- if (combinedOutput.includes("npm warn") || combinedOutput.includes("deprecated")) {
4918
- debugLog("[安装依赖] npm install 有警告但可能成功,继续流程");
4919
- this.prefixText += chalk.green(`✓ 依赖安装完成
4920
- `);
4921
- } else {
4922
- debugLog(`[安装依赖] npm install 失败: ${combinedOutput}`);
4923
- }
4924
- }
4925
- await fs.rm(paths.temp, { recursive: true, force: true });
4926
- debugLog(`[解压插件] 清理临时文件成功`);
4927
- this.prefixText += chalk.green(`✓ 清理临时文件成功
4749
+ await execAsync(
4750
+ `openclaw plugins install ${PLUGIN_PACKAGE_NAME} --dangerously-force-unsafe-install`,
4751
+ { timeout: 12e4 }
4752
+ );
4753
+ debugLog("[安装插件] openclaw plugins install 执行成功");
4754
+ this.prefixText += chalk.green(` ✓ 插件安装完成
4928
4755
  `);
4929
- } else {
4930
- throw new AppError2(ERROR_CODES.PLUGIN_EXTRACT_FAILED, "解压失败:package 目录不存在");
4931
- }
4932
4756
  } catch (error) {
4933
- debugLog(`[解压插件] 解压失败: ${error.message}`);
4934
- this.prefixText += chalk.red(`✗ 解压失败
4935
- `);
4936
- throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `插件解压失败: ${error.message}`);
4757
+ const errorMsg = error.message || "未知错误";
4758
+ debugLog(`[安装插件] 安装失败: ${errorMsg}`);
4759
+ throw new AppError2(ERROR_CODES.NPM_INSTALL_FAILED, `插件安装失败: ${errorMsg}`);
4937
4760
  }
4938
4761
  }
4939
- async doUpdateConfig(paths) {
4940
- debugLog("[更新配置] 开始更新配置...");
4941
- this.prefixText += chalk.green(`✓ 开始更新配置
4942
- `);
4762
+ async doUpdateConfig(paths, boundConfig, env) {
4763
+ this.spinner.prefixText = this.prefixText;
4764
+ this.spinner.text = chalk.cyan("正在生成配置...");
4765
+ debugLog("[更新配置] 创建目录...");
4766
+ await fs.mkdir(paths.home, { recursive: true });
4767
+ await fs.mkdir(paths.workspace, { recursive: true });
4768
+ debugLog("[更新配置] 目录创建完成");
4769
+ debugLog("[更新配置] 读取原有配置...");
4943
4770
  let originalConfig = {};
4944
4771
  try {
4945
4772
  const content = await fs.readFile(paths.config, "utf-8");
@@ -4948,48 +4775,33 @@ class BoxInstaller {
4948
4775
  } catch {
4949
4776
  debugLog("[更新配置] 无原有配置");
4950
4777
  }
4951
- const config = getConfig(this.config.env);
4778
+ const config = getConfig(env);
4952
4779
  const newConfig = {
4953
4780
  // diagnostics: 诊断配置
4954
4781
  diagnostics: {
4955
- // 启用诊断功能
4956
4782
  enabled: true,
4957
- // 启用所有诊断标志 ['*'] 表示全部,[] 表示禁用所有
4958
4783
  flags: ["*"]
4959
4784
  },
4960
4785
  // browser: 浏览器配置
4961
4786
  browser: {
4962
- // 禁用浏览器工具
4963
4787
  enabled: false
4964
4788
  },
4965
4789
  // models: 模型配置
4966
4790
  models: {
4967
- // 配置合并模式:'merge' 合并 | 'replace' 替换
4968
4791
  mode: "merge",
4969
4792
  providers: {
4970
4793
  "siliconflow-minimax": {
4971
- // 模型 API 基础地址
4972
- baseUrl: config.MODEL_BASE_URL,
4973
- // API 密钥(留空,由外部提供)
4974
- apiKey: "",
4975
- // API 类型:'openai-completions' | 'openai-chat' 等
4794
+ baseUrl: boundConfig.modelApiBaseUrl || config.MODEL_BASE_URL,
4795
+ apiKey: boundConfig.modelApiKey,
4976
4796
  api: "openai-completions",
4977
- // 是否使用 Authorization header 认证
4978
4797
  authHeader: true,
4979
4798
  models: [{
4980
- // 模型 ID(provider/model 格式)
4981
4799
  id: "Pro/MiniMaxAI/MiniMax-M2.5",
4982
- // 模型显示名称
4983
4800
  name: "MiniMax-M2.5",
4984
- // 是否启用推理能力
4985
4801
  reasoning: false,
4986
- // 支持的输入类型:['text'] | ['text', 'image']
4987
4802
  input: ["text"],
4988
- // 价格(0 表示免费或未设置)
4989
4803
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
4990
- // 上下文窗口大小(token)
4991
4804
  contextWindow: 2e5,
4992
- // 最大输出 token 数
4993
4805
  maxTokens: 65536
4994
4806
  }]
4995
4807
  }
@@ -4998,82 +4810,56 @@ class BoxInstaller {
4998
4810
  // agents: 代理配置
4999
4811
  agents: {
5000
4812
  defaults: {
5001
- // 默认使用的模型
5002
4813
  model: { primary: "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5" },
5003
4814
  models: {
5004
4815
  "siliconflow-minimax/Pro/MiniMaxAI/MiniMax-M2.5": {
5005
- // 模型别名,用于显示
5006
4816
  alias: "Pro/MiniMaxAI/MiniMax-M2.5"
5007
4817
  }
5008
4818
  },
5009
- // 工作区目录路径
5010
4819
  workspace: paths.workspace,
5011
- // 会话压缩模式:'safeguard' 保守模式
5012
4820
  compaction: { mode: "safeguard" },
5013
- // 详细程度:'full' | 'short' | 'off'
5014
4821
  verboseDefault: "full",
5015
- // 最大并发任务数
5016
4822
  maxConcurrent: 4,
5017
- // 子代理最大并发数
5018
4823
  subagents: { maxConcurrent: 8 }
5019
4824
  },
5020
- // 代理列表
5021
4825
  list: [{ id: "main", workspace: paths.workspace }]
5022
4826
  },
5023
4827
  // tools: 工具配置
5024
4828
  tools: {
5025
- // 禁用的工具列表(优先于 allow)
5026
4829
  deny: ["image", "web_search", "web_fetch"],
5027
- // 图像分析工具
5028
4830
  media: { image: { enabled: false } },
5029
- // 网络搜索和抓取工具
5030
4831
  web: { search: { enabled: false }, fetch: { enabled: false } },
5031
- // 提升权限工具(host=gateway)
5032
4832
  elevated: { enabled: true, allowFrom: { webchat: ["*"] } },
5033
- // exec 工具安全级别:'deny' | 'allowlist' | 'full'
5034
4833
  exec: { security: "full" }
5035
4834
  },
5036
4835
  // bindings: 绑定配置
5037
4836
  bindings: [{
5038
- // 绑定的代理 ID
5039
4837
  agentId: "main",
5040
- // 匹配的通道和账户
5041
4838
  match: { channel: "openclaw-workclaw", accountId: "default" }
5042
4839
  }],
5043
4840
  // messages: 消息配置
5044
4841
  messages: {
5045
- // 消息确认范围
5046
4842
  ackReactionScope: "group-mentions"
5047
4843
  },
5048
4844
  // commands: 命令配置
5049
4845
  commands: {
5050
- // 本机命令:'auto' | 'on' | 'off'
5051
4846
  native: "auto",
5052
- // 本机技能:'auto' | 'on' | 'off'
5053
4847
  nativeSkills: "auto",
5054
- // 是否允许重启命令
5055
4848
  restart: true,
5056
- // 所有者显示格式:'raw' | 'name' | 'hidden'
5057
4849
  ownerDisplay: "raw"
5058
4850
  },
5059
4851
  // session: 会话配置
5060
4852
  session: {
5061
- // DM 作用域
5062
4853
  dmScope: "per-account-channel-peer"
5063
4854
  },
5064
4855
  // hooks: 钩子配置
5065
4856
  hooks: {
5066
4857
  internal: {
5067
- // 启用内部钩子
5068
4858
  enabled: true,
5069
4859
  entries: {
5070
- // 启动 Markdown 钩子
5071
4860
  "boot-md": { enabled: true },
5072
- // 引导额外文件钩子
5073
4861
  "bootstrap-extra-files": { enabled: true },
5074
- // 命令日志钩子
5075
4862
  "command-logger": { enabled: true },
5076
- // 会话记忆钩子
5077
4863
  "session-memory": { enabled: true }
5078
4864
  }
5079
4865
  }
@@ -5081,119 +4867,82 @@ class BoxInstaller {
5081
4867
  // channels: 通道配置
5082
4868
  channels: {
5083
4869
  "openclaw-workclaw": {
5084
- // 启用通道
5085
4870
  enabled: true,
5086
- // 连接模式:'websocket' | 'http'
5087
4871
  connectionMode: "websocket",
5088
- // WebSocket 连接策略
5089
- wsConnectionStrategy: "per-appKey",
5090
- // 应用密钥
5091
- appKey: this.config.appKey,
5092
- // 应用密钥
5093
- appSecret: this.config.appSecret,
5094
- // API 基础 URL
4872
+ appKey: boundConfig.appKey,
4873
+ appSecret: boundConfig.appSecret,
5095
4874
  baseUrl: this.config.baseUrl || config.DEFAULT_BASE_URL,
5096
- // WebSocket URL
5097
4875
  websocketUrl: this.config.wsUrl || config.DEFAULT_WS_URL,
5098
- // 允许不安全的 TLS 连接
5099
4876
  allowInsecureTls: true,
5100
- // 允许原始 JSON 载荷
5101
4877
  allowRawJsonPayload: true,
5102
- // 用户 ID
5103
- userId: "",
4878
+ userId: boundConfig.userId,
4879
+ dmPolicy: "open",
4880
+ allowFrom: ["*"],
5104
4881
  accounts: {
5105
- // 账户配置(agentId 为空表示待分配)
5106
- default: { enabled: true, agentId: "" }
4882
+ default: { enabled: true, agentId: boundConfig.agentId }
5107
4883
  }
5108
4884
  }
5109
4885
  },
5110
4886
  // gateway: 网关配置
5111
4887
  gateway: {
5112
- // 网关模式:'local' | 'hosted'
5113
4888
  mode: "local",
5114
- // 网关端口
5115
4889
  port: 18789,
5116
- // 绑定地址:'loopback' | 'lan' | 'all'
5117
- bind: "loopback",
5118
- // 认证模式(token字段未设置,是因为需要使用原始配置的token)
4890
+ bind: "lan",
5119
4891
  auth: {
5120
4892
  mode: "token"
5121
4893
  },
5122
- // Tailscale 配置
5123
4894
  tailscale: { mode: "off", resetOnExit: false },
5124
4895
  nodes: {
5125
- // 节点上禁止的命令
5126
4896
  denyCommands: [
5127
4897
  "camera.snap",
5128
4898
  "camera.clip",
5129
4899
  "screen.record",
5130
4900
  "contacts.add",
5131
4901
  "calendar.add",
5132
- "reminders.add",
5133
- "sms.send",
5134
- "sms.search"
4902
+ "reminders.add"
5135
4903
  ]
5136
4904
  },
5137
4905
  controlUi: {
5138
- // 允许不安全认证
5139
4906
  allowInsecureAuth: true,
5140
- // 禁用设备认证(仅用于开发)
5141
4907
  dangerouslyDisableDeviceAuth: true,
5142
- // 允许 Host 头源回退
5143
4908
  dangerouslyAllowHostHeaderOriginFallback: true,
5144
- // 允许的源
5145
4909
  allowedOrigins: ["http://localhost:18789", "http://127.0.0.1:18789"]
5146
4910
  }
5147
4911
  },
5148
4912
  // skills: 技能配置
5149
4913
  skills: {
5150
- // 技能加载监视模式
5151
4914
  load: { watch: true }
5152
4915
  },
5153
4916
  // logging: 日志配置
5154
4917
  logging: {
5155
- // 日志级别:'debug' | 'info' | 'warn' | 'error'
5156
4918
  level: "info",
5157
- // 控制台日志级别
5158
4919
  consoleLevel: "info",
5159
- // 控制台样式:'pretty' | 'basic' | 'raw'
5160
4920
  consoleStyle: "pretty",
5161
- // 敏感信息脱敏:'off' | 'keys' | 'all'
5162
4921
  redactSensitive: "off",
5163
- // 日志文件路径(空表示不写入文件)
5164
4922
  file: "",
5165
- // 脱敏模式(正则表达式)
5166
4923
  redactPatterns: ["sk-.*"]
5167
4924
  },
5168
4925
  // plugins: 插件配置
5169
4926
  plugins: {
5170
- // 允许的插件列表
5171
4927
  allow: [config.PLUGIN_NAME],
5172
- // 插件安装跟踪(支持 openclaw plugins update 命令)
5173
4928
  installs: {
5174
4929
  [config.PLUGIN_NAME]: {
5175
- // 安装来源
5176
4930
  source: "npm",
5177
- // npm 包名
5178
4931
  spec: PLUGIN_PACKAGE_NAME,
5179
- // 安装路径
5180
4932
  installPath: paths.target
5181
4933
  }
5182
4934
  },
5183
- // 插件加载路径
5184
- load: {
5185
- paths: [paths.target]
5186
- },
5187
- // 插件条目启用状态
5188
4935
  entries: {
5189
4936
  [config.PLUGIN_NAME]: { enabled: true }
5190
4937
  }
5191
4938
  }
5192
4939
  };
5193
4940
  const finalConfig = deepMerge(originalConfig, newConfig);
4941
+ this.spinner.prefixText = this.prefixText;
4942
+ this.spinner.text = chalk.cyan("正在写入配置...");
5194
4943
  debugLog("[更新配置] 写入配置文件...");
5195
4944
  await fs.writeFile(paths.config, JSON.stringify(finalConfig, null, 2), "utf-8");
5196
- this.prefixText += chalk.green(`✓ 配置文件更新成功
4945
+ this.prefixText += chalk.green(` ✓ 配置更新完成
5197
4946
  `);
5198
4947
  debugLog(`[更新配置] 配置文件写入成功: ${paths.config}`);
5199
4948
  }
@@ -5215,84 +4964,107 @@ function checkEnv() {
5215
4964
  throw new AppError2(ERROR_CODES.NPM_NOT_FOUND, "未检测到 npm,请先安装 Node.js 和 npm");
5216
4965
  }
5217
4966
  }
5218
- async function createBoxCommand(options) {
4967
+ async function createLocalCommand(options) {
5219
4968
  setDebug(!!options.debug);
5220
- debugLog("[盒子安装] 开始处理...");
5221
- debugLog(`[盒子安装] 参数: env=${options.env}, appKey=${options.appKey ? "***" : "未提供"}, debug=${options.debug}`);
4969
+ debugLog("[初始化] 开始处理...");
4970
+ debugLog(`[初始化] 参数: scenario=${options.scenario}, env=${options.env}, phone=${options.phone}, debug=${options.debug}`);
5222
4971
  checkEnv();
5223
- debugLog("[盒子安装] 环境检查通过");
4972
+ debugLog("[初始化] 环境检查通过");
5224
4973
  try {
4974
+ let scenario = options.scenario;
5225
4975
  let env = options.env;
5226
- let appKey = options.appKey;
5227
- let appSecret = options.appSecret;
4976
+ let phone = options.phone;
4977
+ let userPass = options.userPass;
5228
4978
  const questions = [];
4979
+ if (!scenario) {
4980
+ debugLog("[初始化] 需要选择安装场景");
4981
+ questions.push({
4982
+ type: "list",
4983
+ name: "scenario",
4984
+ message: chalk.cyan("请选择安装场景:"),
4985
+ default: "windows-local",
4986
+ choices: [
4987
+ { name: `${chalk.green("Windows")} ${chalk.dim("本地安装")}`, value: "windows-local" },
4988
+ { name: `${chalk.green("macOS")} ${chalk.dim("本地安装")}`, value: "mac-local" },
4989
+ { name: `${chalk.green("Linux")} ${chalk.dim("本地安装")}`, value: "linux-local" }
4990
+ ]
4991
+ });
4992
+ } else {
4993
+ debugLog(`[初始化] 使用命令行参数: scenario=${scenario}`);
4994
+ }
5229
4995
  if (!env) {
5230
- debugLog("[盒子安装] 需要选择环境");
4996
+ debugLog("[初始化] 需要选择环境");
5231
4997
  questions.push({
5232
4998
  type: "list",
5233
4999
  name: "env",
5234
- message: `${nodeEmoji.get("globe_with_meridians")} 请选择环境:`,
5000
+ message: chalk.cyan("请选择环境:"),
5235
5001
  default: "test",
5236
5002
  choices: [
5237
- { name: `${chalk.green("测试环境")} ${chalk.gray("(test)")}`, value: "test" },
5238
- { name: `${chalk.red("正式环境")} ${chalk.gray("(prod)")}`, value: "prod" }
5003
+ { name: `${chalk.green("测试环境")} ${chalk.dim("(test)")}`, value: "test" },
5004
+ { name: `${chalk.red("正式环境")} ${chalk.dim("(prod)")}`, value: "prod" }
5239
5005
  ]
5240
5006
  });
5241
5007
  } else {
5242
- debugLog(`[盒子安装] 使用命令行参数: env=${env}`);
5008
+ debugLog(`[初始化] 使用命令行参数: env=${env}`);
5243
5009
  }
5244
- if (!appKey) {
5245
- debugLog("[盒子安装] 需要输入 AppKey");
5010
+ if (!phone) {
5011
+ debugLog("[初始化] 需要输入手机号码");
5246
5012
  questions.push({
5247
5013
  type: "input",
5248
- name: "appKey",
5249
- message: `${nodeEmoji.get("key")} 请输入 AppKey:`,
5014
+ name: "phone",
5015
+ message: chalk.cyan("请输入手机号码:"),
5250
5016
  validate: (value) => {
5251
5017
  if (!value || value.trim() === "") {
5252
- return `${nodeEmoji.get("x")} AppKey 不能为空`;
5018
+ return chalk.red("手机号码不能为空");
5019
+ }
5020
+ if (!/^1[3-9]\d{9}$/.test(value)) {
5021
+ return chalk.yellow("请输入正确的手机号码");
5253
5022
  }
5254
5023
  return true;
5255
5024
  }
5256
5025
  });
5257
5026
  } else {
5258
- debugLog("[盒子安装] 使用命令行参数: appKey");
5027
+ debugLog("[初始化] 使用命令行参数: phone");
5259
5028
  }
5260
- if (!appSecret) {
5261
- debugLog("[盒子安装] 需要输入 AppSecret");
5029
+ if (!userPass) {
5030
+ debugLog("[初始化] 需要输入用户密码");
5262
5031
  questions.push({
5263
5032
  type: "input",
5264
- name: "appSecret",
5265
- message: `${nodeEmoji.get("key")} 请输入 AppSecret:`,
5033
+ name: "userPass",
5034
+ message: chalk.cyan("请输入用户密码:"),
5266
5035
  validate: (value) => {
5267
5036
  if (!value || value.trim() === "") {
5268
- return `${nodeEmoji.get("x")} AppSecret 不能为空`;
5037
+ return chalk.red("用户密码不能为空");
5269
5038
  }
5270
5039
  return true;
5271
5040
  }
5272
5041
  });
5273
5042
  } else {
5274
- debugLog("[盒子安装] 使用命令行参数: appSecret");
5043
+ debugLog("[初始化] 使用命令行参数: userPass");
5275
5044
  }
5276
5045
  if (questions.length > 0) {
5277
- debugLog(`[盒子安装] 开始交互式问答,共 ${questions.length} 个问题`);
5046
+ debugLog(`[初始化] 开始交互式问答,共 ${questions.length} 个问题`);
5278
5047
  const answers = await inquirer.prompt(questions);
5279
- debugLog("[盒子安装] 交互式问答完成");
5048
+ debugLog("[初始化] 交互式问答完成");
5049
+ scenario = scenario || answers.scenario;
5280
5050
  env = env || answers.env || "test";
5281
- appKey = appKey || answers.appKey;
5282
- appSecret = appSecret || answers.appSecret;
5051
+ phone = phone || answers.phone;
5052
+ userPass = userPass || answers.userPass;
5283
5053
  }
5284
- debugLog(`[盒子安装] 最终参数: env=${env}`);
5285
- debugLog("[盒子安装] 创建 BoxInstaller 实例...");
5286
- const installer = new BoxInstaller({
5287
- appKey,
5288
- appSecret,
5289
- env
5054
+ debugLog(`[初始化] 最终参数: scenario=${scenario}, env=${env}, phone=${phone}, pluginVersion=${options.pluginVersion}`);
5055
+ debugLog("[初始化] 创建 LocalInstaller 实例...");
5056
+ const installer = new LocalInstaller({
5057
+ phone,
5058
+ userPass,
5059
+ scenario,
5060
+ env,
5061
+ pluginVersion: options.pluginVersion
5290
5062
  });
5291
- debugLog("[盒子安装] 开始安装...");
5063
+ debugLog("[初始化] 开始安装...");
5292
5064
  await installer.install();
5293
- debugLog("[盒子安装] 安装完成");
5065
+ debugLog("[初始化] 安装完成");
5294
5066
  console.log(installer.getPrefixText() + boxen(
5295
- `${nodeEmoji.get("tada")} 插件初始化成功!`,
5067
+ `${chalk.green("")} 插件初始化成功!`,
5296
5068
  {
5297
5069
  title: `${chalk.bold.green("初始化成功")}`,
5298
5070
  titleAlignment: "center",
@@ -5304,7 +5076,7 @@ async function createBoxCommand(options) {
5304
5076
  }
5305
5077
  ));
5306
5078
  } catch (error) {
5307
- debugLog(`[盒子安装] 发生错误: ${error.message}`);
5079
+ debugLog(`[初始化] 发生错误: ${error.message}`);
5308
5080
  console.error(boxen(
5309
5081
  `${chalk.yellow(error.message)}`,
5310
5082
  {
@@ -5321,7 +5093,7 @@ async function createBoxCommand(options) {
5321
5093
  }
5322
5094
  }
5323
5095
  function registerCommands(program2) {
5324
- 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);
5096
+ program2.command("local").description("本地账户安装(需要登录)").option("-s, --scenario <scenario>", "安装场景").option("-e, --env <env>", "环境 (test/prod)").option("--phone <phone>", "手机号码").option("--user-pass <userPass>", "用户密码").option("--plugin-version <plugin-version>", "插件版本号(默认最新版)").option("--debug", "开启调试日志").action(createLocalCommand);
5325
5097
  }
5326
5098
  const __filename$1 = fileURLToPath(import.meta.url);
5327
5099
  const __dirname$1 = dirname(__filename$1);
@@ -5329,8 +5101,8 @@ const pkg = JSON.parse(readFileSync(resolve(__dirname$1, "../package.json"), "ut
5329
5101
  const program = new Command();
5330
5102
  function index() {
5331
5103
  program.name(Object.keys(pkg.bin)[0]).version(pkg.version).description(pkg.description);
5332
- registerCommands$1(program);
5333
5104
  registerCommands(program);
5105
+ registerCommands$1(program);
5334
5106
  program.parse(process$1.argv);
5335
5107
  }
5336
5108
  export {