@searchfe/openclaw-baiduapp 0.1.11-beta.1 → 0.1.12-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js ADDED
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execSync, spawnSync} from 'node:child_process';
4
+ import readline from 'node:readline';
5
+
6
+ import {printQRCode} from './src/cli-qrcode.mjs';
7
+
8
+ const PLUGIN_SPEC = '@searchfe/openclaw-baiduapp';
9
+ const CHANNEL_ID = 'openclaw-baiduapp';
10
+ const QR_URL = 'https://www.baidu.com';
11
+
12
+ function parseArgs(argv) {
13
+ const args = argv.slice(2);
14
+ let command;
15
+ let ak;
16
+ let sk;
17
+
18
+ for (let index = 0; index < args.length; index++) {
19
+ const token = args[index];
20
+
21
+ if (token === '--help' || token === '-h') {
22
+ if (!command) {
23
+ command = token;
24
+ }
25
+ continue;
26
+ }
27
+
28
+ if (token === '--ak') {
29
+ ak = args[index + 1];
30
+ index += 1;
31
+ continue;
32
+ }
33
+
34
+ if (token.startsWith('--ak=')) {
35
+ ak = token.slice('--ak='.length);
36
+ continue;
37
+ }
38
+
39
+ if (token === '--sk') {
40
+ sk = args[index + 1];
41
+ index += 1;
42
+ continue;
43
+ }
44
+
45
+ if (token.startsWith('--sk=')) {
46
+ sk = token.slice('--sk='.length);
47
+ continue;
48
+ }
49
+
50
+ if (!token.startsWith('--') && !command) {
51
+ command = token;
52
+ }
53
+ }
54
+
55
+ return {command, ak, sk};
56
+ }
57
+
58
+ function prompt(question, {hidden = false} = {}) {
59
+ if (!process.stdin.isTTY) {
60
+ throw new Error('非交互环境:请通过 --ak/--sk 参数传入凭证');
61
+ }
62
+
63
+ const askOnce = () => new Promise(resolve => {
64
+ const rl = readline.createInterface({
65
+ input: process.stdin,
66
+ output: process.stdout,
67
+ terminal: true,
68
+ });
69
+
70
+ rl.on('SIGINT', () => {
71
+ rl.close();
72
+ process.exit(1);
73
+ });
74
+
75
+ if (hidden) {
76
+ rl.stdoutMuted = true;
77
+ rl._writeToOutput = chunk => {
78
+ if (rl.stdoutMuted) {
79
+ if (chunk.startsWith(question)) {
80
+ rl.output.write(chunk);
81
+ }
82
+ return;
83
+ }
84
+
85
+ rl.output.write(chunk);
86
+ };
87
+ }
88
+
89
+ rl.question(question, answer => {
90
+ rl.close();
91
+ if (hidden) {
92
+ process.stdout.write('\n');
93
+ }
94
+ resolve(String(answer || '').trim());
95
+ });
96
+ });
97
+
98
+ return (async () => {
99
+ for (let attempt = 0; attempt < 3; attempt++) {
100
+ const answer = await askOnce();
101
+ if (answer) {
102
+ return answer;
103
+ }
104
+
105
+ if (attempt < 2) {
106
+ error('输入不能为空,请重试');
107
+ }
108
+ }
109
+
110
+ throw new Error('输入不能为空,已超过最大重试次数');
111
+ })();
112
+ }
113
+
114
+ function run(cmd, args = [], {silent = true} = {}) {
115
+ const stdio = silent ? ['pipe', 'pipe', 'pipe'] : 'inherit';
116
+ const result = spawnSync(cmd, args, {encoding: 'utf-8', stdio});
117
+
118
+ if (result.error) {
119
+ const err = new Error(`Command failed: ${cmd}`);
120
+ err.stderr = silent ? String(result.stderr || result.error.message || '') : '';
121
+ throw err;
122
+ }
123
+
124
+ if (result.status !== 0) {
125
+ const err = new Error(`Command failed with exit code ${result.status}: ${cmd}`);
126
+ err.stderr = silent ? String(result.stderr || '') : '';
127
+ throw err;
128
+ }
129
+
130
+ return silent ? String(result.stdout || '').trim() : '';
131
+ }
132
+
133
+ function which(bin) {
134
+ const cmd = process.platform === 'win32' ? `where ${bin}` : `which ${bin}`;
135
+
136
+ try {
137
+ return execSync(cmd, {
138
+ encoding: 'utf-8',
139
+ shell: true,
140
+ stdio: ['pipe', 'pipe', 'pipe'],
141
+ }).trim();
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ function log(msg) {
148
+ console.log(`\x1b[36m[openclaw-baiduapp]\x1b[0m ${msg}`);
149
+ }
150
+
151
+ function error(msg) {
152
+ console.error(`\x1b[31m[openclaw-baiduapp]\x1b[0m ${msg}`);
153
+ }
154
+
155
+ async function install() {
156
+ let {ak, sk} = parseArgs(process.argv);
157
+
158
+ if ((!ak || !sk) && !process.stdin.isTTY) {
159
+ error('非交互环境:请通过 --ak/--sk 参数传入凭证');
160
+ process.exit(1);
161
+ }
162
+
163
+ if (!which('openclaw')) {
164
+ error('未找到 openclaw,请先安装:');
165
+ console.log(' npm install -g openclaw');
166
+ console.log(' 详见 https://docs.openclaw.ai/install');
167
+ process.exit(1);
168
+ }
169
+ log('已找到本地安装的 openclaw');
170
+
171
+ log('正在安装插件...');
172
+ try {
173
+ const out = run('openclaw', ['plugins', 'install', PLUGIN_SPEC]);
174
+ if (out) {
175
+ log(out);
176
+ }
177
+ } catch (installErr) {
178
+ if (installErr.stderr && installErr.stderr.includes('already exists')) {
179
+ log('检测到本地已安装,正在更新...');
180
+ try {
181
+ const updateOut = run('openclaw', ['plugins', 'update', CHANNEL_ID]);
182
+ if (updateOut) {
183
+ log(updateOut);
184
+ }
185
+ } catch (updateErr) {
186
+ error('插件更新失败,请手动执行:');
187
+ if (updateErr.stderr) {
188
+ console.error(updateErr.stderr);
189
+ }
190
+ console.log(` openclaw plugins update "${CHANNEL_ID}"`);
191
+ process.exit(1);
192
+ }
193
+ } else {
194
+ error('插件安装失败,请手动执行:');
195
+ if (installErr.stderr) {
196
+ console.error(installErr.stderr);
197
+ }
198
+ console.log(` openclaw plugins install "${PLUGIN_SPEC}"`);
199
+ process.exit(1);
200
+ }
201
+ }
202
+
203
+ try {
204
+ if (!ak) {
205
+ ak = await prompt('请输入 App Key (appKey): ');
206
+ }
207
+ if (!sk) {
208
+ sk = await prompt('请输入 App Secret (appSecret): ', {hidden: true});
209
+ }
210
+ } catch (promptErr) {
211
+ error(promptErr instanceof Error ? promptErr.message : String(promptErr));
212
+ process.exit(1);
213
+ }
214
+
215
+ if (!ak.trim() || !sk.trim()) {
216
+ error('appKey 和 appSecret 不能为空');
217
+ process.exit(1);
218
+ }
219
+
220
+ log('正在写入配置...');
221
+ try {
222
+ run('openclaw', ['config', 'set', `channels.${CHANNEL_ID}.appKey`, ak.trim()]);
223
+ run('openclaw', ['config', 'set', `channels.${CHANNEL_ID}.appSecret`, sk.trim()]);
224
+ } catch {
225
+ error('配置写入失败,请手动执行:');
226
+ console.log(` openclaw config set channels.${CHANNEL_ID}.appKey <your-app-key>`);
227
+ console.log(` openclaw config set channels.${CHANNEL_ID}.appSecret <your-app-secret>`);
228
+ process.exit(1);
229
+ }
230
+ log('配置写入成功');
231
+
232
+ log('正在重启 OpenClaw Gateway...');
233
+ try {
234
+ run('openclaw', ['gateway', 'restart'], {silent: false});
235
+ } catch {
236
+ error('重启失败,可手动执行:');
237
+ console.log(' openclaw gateway restart');
238
+ }
239
+
240
+ console.log();
241
+ log('安装完成!扫描下方二维码访问:');
242
+ console.log();
243
+ printQRCode(QR_URL);
244
+ console.log();
245
+ console.log(` ${QR_URL}`);
246
+ console.log();
247
+ }
248
+
249
+ function help() {
250
+ console.log(`用法: npx @searchfe/openclaw-baiduapp <命令> [选项]
251
+
252
+ 命令:
253
+ install 安装百度App插件并配置 AK/SK
254
+
255
+ 选项:
256
+ --ak <appKey> App Key(必填,缺省时交互输入)
257
+ --sk <appSecret> App Secret(必填,缺省时交互输入,不回显)
258
+ --help, -h 显示帮助信息
259
+
260
+ 示例:
261
+ npx @searchfe/openclaw-baiduapp install --ak your-key --sk your-secret
262
+ npx @searchfe/openclaw-baiduapp install`);
263
+ }
264
+
265
+ const {command} = parseArgs(process.argv);
266
+
267
+ switch (command) {
268
+ case 'install':
269
+ await install();
270
+ break;
271
+ case 'help':
272
+ case '--help':
273
+ case '-h':
274
+ help();
275
+ break;
276
+ default:
277
+ if (command) {
278
+ error(`未知命令: ${command}`);
279
+ }
280
+ help();
281
+ process.exit(command ? 1 : 0);
282
+ }
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "@searchfe/openclaw-baiduapp",
3
- "version": "0.1.11-beta.1",
3
+ "version": "0.1.12-beta.1",
4
4
  "type": "module",
5
5
  "description": "OpenClaw Baidu App channel plugin (百度App消息渠道插件)",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "dist",
9
- "openclaw.plugin.json"
9
+ "openclaw.plugin.json",
10
+ "cli.js",
11
+ "src/cli-qrcode.mjs"
10
12
  ],
11
13
  "openclaw": {
12
14
  "extensions": [
@@ -71,6 +73,9 @@
71
73
  "defaultChoice": "npm"
72
74
  }
73
75
  },
76
+ "bin": {
77
+ "openclaw-baiduapp": "cli.js"
78
+ },
74
79
  "main": "./dist/index.js",
75
80
  "types": "./dist/index.d.ts",
76
81
  "exports": {
@@ -90,7 +95,8 @@
90
95
  "release:major": "npm run build && npm version major && npm publish"
91
96
  },
92
97
  "dependencies": {
93
- "@baiducloud/sdk": "^1.0.7"
98
+ "@baiducloud/sdk": "^1.0.7",
99
+ "qrcode-terminal": "^0.12.0"
94
100
  },
95
101
  "devDependencies": {
96
102
  "@types/node": "^22.0.0",
@@ -0,0 +1,5 @@
1
+ import qrcodeTerminal from 'qrcode-terminal';
2
+
3
+ export function printQRCode(url) {
4
+ qrcodeTerminal.generate(String(url), {small: true}, qrcode => console.log(qrcode));
5
+ }