@a2hmarket/a2hmarket 0.7.4 → 0.7.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2hmarket/a2hmarket",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "index.ts",
@@ -167,12 +167,12 @@ async function pollForAuth(code) {
167
167
  }
168
168
 
169
169
  const remaining = Math.ceil((deadline - Date.now()) / 1000);
170
- process.stdout.write(`\r 等待授权中... ${DIM}(剩余 ${remaining}s)${RESET} `);
170
+ process.stdout.write(`\r Waiting for authorization... ${DIM}(${remaining}s remaining)${RESET} `);
171
171
 
172
172
  await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
173
173
  }
174
174
 
175
- return { error: "授权超时(5分钟),请重新运行安装" };
175
+ return { error: "Authorization timed out (5 minutes). Please run install again." };
176
176
  }
177
177
 
178
178
  // ── Feishu Card Helper ───────────────────────────────────────────────────
@@ -189,13 +189,13 @@ async function getFeishuToken(appId, appSecret) {
189
189
  }
190
190
 
191
191
  const ONBOARDING_TEXT =
192
- "🎉 A2H Market · 安装成功\n\n" +
193
- "我已经进入 A2H 市场了!这边特别热闹,很多人在摆摊出售各种东西,也有很多人在挑选商品和讨价还价。\n\n" +
194
- "我可以帮你做三件事:\n\n" +
195
- "🏪 **摆摊**帮你在市场上出售商品或服务,也可以直接接别人的悬赏任务赚钱\n\n" +
196
- "🛍️ **逛街**帮你在市场上找东西买,我来搜、来比、来砍价,你拍板就行\n\n" +
197
- "👀 **逛逛**还没想好也没关系!我帮你逛逛市场,看看有什么赚钱机会或者值得买的好东西\n\n" +
198
- "你是想**摆摊卖东西**、**买点什么**,还是先让我帮你**逛逛**看看有什么机会?";
192
+ "🎉 A2H Market · Setup Complete\n\n" +
193
+ "I'm now connected to A2H Market! The marketplace is buzzing with activity.\n\n" +
194
+ "I can help you with three things:\n\n" +
195
+ "🏪 **Sell**List your products or services on the marketplace, or take on bounty tasks\n\n" +
196
+ "🛍️ **Shop**Find and buy what you need — I'll search, compare, and negotiate for you\n\n" +
197
+ "👀 **Explore**Not sure yet? I'll browse the market and discover opportunities for you\n\n" +
198
+ "Would you like to **sell something**, **buy something**, or just **explore** the market?";
199
199
 
200
200
  async function sendOnboardingFeishu(appId, appSecret, target, agentId) {
201
201
  const token = await getFeishuToken(appId, appSecret);
@@ -205,19 +205,19 @@ async function sendOnboardingFeishu(appId, appSecret, target, agentId) {
205
205
  schema: "2.0",
206
206
  config: { wide_screen_mode: true },
207
207
  header: {
208
- title: { tag: "plain_text", content: "🎉 A2H Market · 安装成功" },
208
+ title: { tag: "plain_text", content: "🎉 A2H Market · Setup Complete" },
209
209
  template: "green",
210
210
  },
211
211
  body: {
212
212
  elements: [
213
- { tag: "markdown", content: "我已经进入 A2H 市场了!这边特别热闹,很多人在摆摊出售各种东西,也有很多人在挑选商品和讨价还价。" },
214
- { tag: "markdown", content: "我可以帮你做三件事:" },
213
+ { tag: "markdown", content: "I'm now connected to A2H Market! The marketplace is buzzing with activity." },
214
+ { tag: "markdown", content: "I can help you with three things:" },
215
215
  { tag: "markdown", content:
216
- "🏪 **摆摊**帮你在市场上出售商品或服务,也可以直接接别人的悬赏任务赚钱\n\n" +
217
- "🛍️ **逛街**帮你在市场上找东西买,我来搜、来比、来砍价,你拍板就行\n\n" +
218
- "👀 **逛逛**还没想好也没关系!我帮你逛逛市场,看看有什么赚钱机会或者值得买的好东西" },
219
- { tag: "markdown", content: "你是想**摆摊卖东西**、**买点什么**,还是先让我帮你**逛逛**看看有什么机会?" },
220
- { tag: "markdown", content: `---\n*我的A2H Agent: ${agentId}*` },
216
+ "🏪 **Sell**List your products or services on the marketplace, or take on bounty tasks\n\n" +
217
+ "🛍️ **Shop**Find and buy what you need — I'll search, compare, and negotiate for you\n\n" +
218
+ "👀 **Explore**Not sure yet? I'll browse the market and discover opportunities for you" },
219
+ { tag: "markdown", content: "Would you like to **sell something**, **buy something**, or just **explore** the market?" },
220
+ { tag: "markdown", content: `---\n*My A2H Agent: ${agentId}*` },
221
221
  ],
222
222
  },
223
223
  };
@@ -232,7 +232,7 @@ async function sendOnboardingFeishu(appId, appSecret, target, agentId) {
232
232
  }
233
233
 
234
234
  async function sendOnboardingDiscord(botToken, channelId, agentId) {
235
- const text = ONBOARDING_TEXT + `\n\n---\n_我的A2H Agent: ${agentId}_`;
235
+ const text = ONBOARDING_TEXT + `\n\n---\n_My A2H Agent: ${agentId}_`;
236
236
  const resp = await fetch(`https://discord.com/api/v10/channels/${channelId}/messages`, {
237
237
  method: "POST",
238
238
  headers: { "Content-Type": "application/json", Authorization: `Bot ${botToken}` },
@@ -264,10 +264,10 @@ async function runUpdate() {
264
264
  log(`\n${BOLD}🏪 A2H Market — Update${RESET}\n`);
265
265
 
266
266
  // 1. Check OpenClaw
267
- logStep(1, "检查环境");
267
+ logStep(1, "Check Environment");
268
268
  const version = checkOpenclaw();
269
269
  if (!version) {
270
- log(` ${CROSS} OpenClaw 未安装`);
270
+ log(` ${CROSS} OpenClaw not installed`);
271
271
  process.exit(1);
272
272
  }
273
273
  log(` ${CHECK} ${version}`);
@@ -275,14 +275,14 @@ async function runUpdate() {
275
275
  try {
276
276
  const info = execSync("openclaw plugins info a2hmarket 2>&1", { encoding: "utf-8" });
277
277
  if (!info.includes("a2hmarket")) throw new Error("not found");
278
- log(` ${CHECK} 插件已安装`);
278
+ log(` ${CHECK} Plugin installed`);
279
279
  } catch {
280
- log(` ${CROSS} 插件未安装,请先运行: npx -y ${NPM_SPEC} install`);
280
+ log(` ${CROSS} Plugin not installed. Run: npx -y ${NPM_SPEC} install`);
281
281
  process.exit(1);
282
282
  }
283
283
 
284
284
  // 2. Check versions
285
- logStep(2, "检查版本");
285
+ logStep(2, "Check Version");
286
286
  let currentVersion = "unknown";
287
287
  try {
288
288
  const pluginPkg = join(OPENCLAW_DIR, "extensions", "a2hmarket", "package.json");
@@ -296,39 +296,39 @@ async function runUpdate() {
296
296
  try {
297
297
  latestVersion = execSync(`npm view ${NPM_SPEC} version 2>/dev/null`, { encoding: "utf-8" }).trim();
298
298
  } catch {
299
- log(` ${CROSS} 无法获取最新版本`);
299
+ log(` ${CROSS} Cannot fetch latest version`);
300
300
  process.exit(1);
301
301
  }
302
302
 
303
- log(` 当前版本: ${CYAN}${currentVersion}${RESET}`);
304
- log(` 最新版本: ${CYAN}${latestVersion}${RESET}`);
303
+ log(` Current: ${CYAN}${currentVersion}${RESET}`);
304
+ log(` Latest: ${CYAN}${latestVersion}${RESET}`);
305
305
 
306
306
  if (currentVersion === latestVersion) {
307
- log(`\n ${CHECK} 已是最新版本,无需更新`);
307
+ log(`\n ${CHECK} Already up to date`);
308
308
  process.exit(0);
309
309
  }
310
310
 
311
311
  // 3. Backup credentials before uninstall
312
- logStep(3, "更新插件");
312
+ logStep(3, "Update Plugin");
313
313
  let savedCreds = null;
314
314
  try {
315
315
  if (existsSync(CREDS_FILE)) {
316
316
  savedCreds = JSON.parse(readFileSync(CREDS_FILE, "utf-8"));
317
- log(` ${CHECK} 凭证已备份`);
317
+ log(` ${CHECK} Credentials backed up`);
318
318
  }
319
319
  } catch {}
320
320
  if (!savedCreds) {
321
- log(` ${WARN} 未找到凭证备份,更新后可能需要重新安装`);
321
+ log(` ${WARN} No credentials found — may need to reinstall after update`);
322
322
  }
323
323
 
324
324
  try {
325
- log(` 卸载旧版本...`);
325
+ log(` Uninstalling old version...`);
326
326
  execSync('echo y | openclaw plugins uninstall a2hmarket 2>&1', { encoding: "utf-8", stdio: "pipe" });
327
- log(` 安装新版本...`);
327
+ log(` Installing new version...`);
328
328
  execSync(`echo y | openclaw plugins install ${NPM_SPEC} 2>&1`, { encoding: "utf-8", stdio: "pipe" });
329
- log(` ${CHECK} 更新完成`);
329
+ log(` ${CHECK} Update complete`);
330
330
  } catch (err) {
331
- log(` ${CROSS} 更新失败: ${err.message}`);
331
+ log(` ${CROSS} Update failed: ${err.message}`);
332
332
  process.exit(1);
333
333
  }
334
334
 
@@ -343,11 +343,11 @@ async function runUpdate() {
343
343
  };
344
344
  if (savedCreds.notify) fileData.notify = savedCreds.notify;
345
345
  writeFileSync(CREDS_FILE, JSON.stringify(fileData, null, 2) + "\n");
346
- log(` ${CHECK} 凭证已恢复`);
346
+ log(` ${CHECK} Credentials restored`);
347
347
  }
348
348
 
349
349
  // 4. Re-link openclaw module
350
- log(` 配置模块依赖...`);
350
+ log(` Linking module dependencies...`);
351
351
  try {
352
352
  const pluginDir = join(OPENCLAW_DIR, "extensions", "a2hmarket");
353
353
  if (existsSync(pluginDir)) {
@@ -384,37 +384,37 @@ async function runUpdate() {
384
384
  mkdirSync(symlinkDir, { recursive: true });
385
385
  try { execSync(`rm -f "${symlinkTarget}"`, { stdio: "pipe" }); } catch {}
386
386
  execSync(`ln -sf "${openclawPkg}" "${symlinkTarget}"`, { stdio: "pipe" });
387
- log(` ${CHECK} openclaw/plugin-sdk 已链接`);
387
+ log(` ${CHECK} openclaw/plugin-sdk linked`);
388
388
  } else {
389
- log(` ${WARN} 未找到 openclaw 包路径`);
389
+ log(` ${WARN} openclaw package not found`);
390
390
  }
391
391
  }
392
392
  } catch (err) {
393
- log(` ${WARN} 模块链接失败: ${err.message}`);
393
+ log(` ${WARN} Module linking failed: ${err.message}`);
394
394
  }
395
395
 
396
396
  // 5. Restart gateway
397
- logStep(4, "重启服务");
397
+ logStep(4, "Restart Gateway");
398
398
  try {
399
399
  execSync("openclaw gateway restart 2>&1", { encoding: "utf-8", stdio: "pipe" });
400
- log(` ${CHECK} Gateway 已重启`);
400
+ log(` ${CHECK} Gateway restarted`);
401
401
  } catch {
402
- log(` ${WARN} 请手动执行: openclaw gateway restart`);
402
+ log(` ${WARN} Please run manually: openclaw gateway restart`);
403
403
  }
404
404
 
405
405
  // 6. Verify
406
- logStep(5, "验证");
406
+ logStep(5, "Verify");
407
407
  await new Promise((r) => setTimeout(r, 5000));
408
408
  try {
409
409
  const info = execSync("openclaw plugins info a2hmarket 2>&1", { encoding: "utf-8" });
410
410
  if (info.includes("Status: loaded")) {
411
- log(` ${CHECK} 插件运行正常`);
411
+ log(` ${CHECK} Plugin running`);
412
412
  }
413
413
  } catch {
414
- log(` ${WARN} 请检查: openclaw plugins info a2hmarket`);
414
+ log(` ${WARN} Please check: openclaw plugins info a2hmarket`);
415
415
  }
416
416
 
417
- log(`\n${GREEN}${BOLD}🎉 更新完成!${RESET} ${currentVersion} → ${CYAN}${latestVersion}${RESET}\n`);
417
+ log(`\n${GREEN}${BOLD}🎉 Update complete!${RESET} ${currentVersion} → ${CYAN}${latestVersion}${RESET}\n`);
418
418
  }
419
419
 
420
420
  // ── Uninstall ────────────────────────────────────────────────────────────
@@ -423,29 +423,29 @@ async function runUninstall() {
423
423
  log(`\n${BOLD}🏪 A2H Market — Uninstall${RESET}\n`);
424
424
 
425
425
  const prompt = createPrompt();
426
- const confirm = await prompt.ask("确认卸载 a2hmarket 插件及所有数据? (y/N)", "N");
426
+ const confirm = await prompt.ask("Uninstall a2hmarket plugin and all data? (y/N)", "N");
427
427
  prompt.close();
428
428
  if (confirm.toLowerCase() !== "y") {
429
- log(` 取消卸载。`);
429
+ log(` Cancelled.`);
430
430
  process.exit(0);
431
431
  }
432
432
 
433
433
  // 1. Uninstall plugin
434
- log(` 卸载插件...`);
434
+ log(` Uninstalling plugin...`);
435
435
  try {
436
436
  execSync('echo y | openclaw plugins uninstall a2hmarket 2>&1', { encoding: "utf-8", stdio: "pipe" });
437
- log(` ${CHECK} 插件已卸载`);
437
+ log(` ${CHECK} Plugin uninstalled`);
438
438
  } catch {
439
- log(` ${WARN} 插件卸载失败(可能已卸载)`);
439
+ log(` ${WARN} Plugin uninstall failed (may already be uninstalled)`);
440
440
  }
441
441
 
442
442
  // 2. Remove runtime data
443
443
  if (existsSync(DATA_DIR)) {
444
444
  try {
445
445
  execSync(`rm -rf "${DATA_DIR}"`, { stdio: "pipe" });
446
- log(` ${CHECK} 数据目录已删除: ${DATA_DIR}`);
446
+ log(` ${CHECK} Data directory removed: ${DATA_DIR}`);
447
447
  } catch {
448
- log(` ${WARN} 数据目录删除失败: ${DATA_DIR}`);
448
+ log(` ${WARN} Failed to remove data directory: ${DATA_DIR}`);
449
449
  }
450
450
  }
451
451
 
@@ -458,21 +458,21 @@ async function runUninstall() {
458
458
  // Reset to minimal — keep enabled:false so openclaw knows it was uninstalled
459
459
  cfg.plugins.entries.a2hmarket = { enabled: false };
460
460
  writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n");
461
- log(` ${CHECK} openclaw.json 已清理`);
461
+ log(` ${CHECK} openclaw.json cleaned`);
462
462
  }
463
463
  } catch {
464
- log(` ${WARN} openclaw.json 清理跳过`);
464
+ log(` ${WARN} openclaw.json cleanup skipped`);
465
465
  }
466
466
 
467
467
  // 4. Restart gateway
468
468
  try {
469
469
  execSync("openclaw gateway restart 2>&1", { encoding: "utf-8", stdio: "pipe" });
470
- log(` ${CHECK} Gateway 已重启`);
470
+ log(` ${CHECK} Gateway restarted`);
471
471
  } catch {
472
- log(` ${WARN} 请手动执行: openclaw gateway restart`);
472
+ log(` ${WARN} Please run manually: openclaw gateway restart`);
473
473
  }
474
474
 
475
- log(`\n${GREEN}${BOLD}卸载完成${RESET}\n`);
475
+ log(`\n${GREEN}${BOLD}Uninstall complete${RESET}\n`);
476
476
  }
477
477
 
478
478
  // ── Main ─────────────────────────────────────────────────────────────────
@@ -491,11 +491,11 @@ async function main() {
491
491
 
492
492
  if (cmd !== "install") {
493
493
  log(`\n${BOLD}A2H Market — OpenClaw Plugin${RESET}\n`);
494
- log(` 安装: npx -y ${NPM_SPEC} install`);
495
- log(` 快速: npx -y ${NPM_SPEC} install --agent ag_xxx:key`);
496
- log(` 静默: npx -y ${NPM_SPEC} install --agent ag_xxx:key --notify feishu:ou_xxx --yes`);
497
- log(` 更新: npx -y ${NPM_SPEC} update`);
498
- log(` 卸载: npx -y ${NPM_SPEC} uninstall\n`);
494
+ log(` Install: npx -y ${NPM_SPEC} install`);
495
+ log(` Quick: npx -y ${NPM_SPEC} install --agent ag_xxx:key`);
496
+ log(` Silent: npx -y ${NPM_SPEC} install --agent ag_xxx:key --notify feishu:ou_xxx --yes`);
497
+ log(` Update: npx -y ${NPM_SPEC} update`);
498
+ log(` Remove: npx -y ${NPM_SPEC} uninstall\n`);
499
499
  process.exit(0);
500
500
  }
501
501
 
@@ -518,16 +518,16 @@ async function main() {
518
518
  log(`\n${BOLD}🏪 A2H Market — OpenClaw Plugin Installer${RESET}\n`);
519
519
 
520
520
  // ── Step 1: Check OpenClaw ─────────────────────────────────────
521
- logStep(1, "检查 OpenClaw");
521
+ logStep(1, "Check OpenClaw");
522
522
  const version = checkOpenclaw();
523
523
  if (!version) {
524
- log(` ${CROSS} OpenClaw 未安装。请先安装: https://docs.openclaw.ai`);
524
+ log(` ${CROSS} OpenClaw not installed. Get it at: https://docs.openclaw.ai`);
525
525
  process.exit(1);
526
526
  }
527
527
  log(` ${CHECK} ${version}`);
528
528
 
529
529
  // ── Step 2: Authorize ──────────────────────────────────────────
530
- logStep(2, "A2H Market 授权");
530
+ logStep(2, "Authorization");
531
531
 
532
532
  let agentId, agentKey, apiUrl, mqttUrl;
533
533
 
@@ -541,18 +541,18 @@ async function main() {
541
541
  [agentId, agentKey] = agentValue.split(":", 2);
542
542
  apiUrl = API_DEFAULT;
543
543
  mqttUrl = MQTT_DEFAULT;
544
- log(` 使用命令行凭证: ${agentId}`);
544
+ log(` Using CLI credentials: ${agentId}`);
545
545
  } else if (existsSync(CREDS_FILE)) {
546
546
  // Check existing
547
547
  try {
548
548
  const existing = JSON.parse(readFileSync(CREDS_FILE, "utf-8"));
549
549
  const existingId = existing.agent_id ?? existing.agentId ?? "";
550
550
  if (existingId) {
551
- log(` 已有凭证: ${CYAN}${existingId}${RESET}`);
551
+ log(` Existing credentials: ${CYAN}${existingId}${RESET}`);
552
552
  let reuse = "Y";
553
553
  if (!autoYes) {
554
554
  const prompt = createPrompt();
555
- reuse = await prompt.ask("使用现有凭证? (Y/n)", "Y");
555
+ reuse = await prompt.ask("Use existing credentials? (Y/n)", "Y");
556
556
  prompt.close();
557
557
  }
558
558
  if (reuse.toLowerCase() !== "n") {
@@ -567,12 +567,12 @@ async function main() {
567
567
 
568
568
  if (!agentId) {
569
569
  // Authorization code flow
570
- log(` 生成授权链接...`);
570
+ log(` Generating authorization link...`);
571
571
  const { code, url } = await generateAuthCode();
572
572
 
573
- log(`\n ${BOLD}请在浏览器中打开以下链接完成授权:${RESET}\n`);
573
+ log(`\n ${BOLD}Open this link in your browser to authorize:${RESET}\n`);
574
574
  log(` ${CYAN}${url}${RESET}\n`);
575
- log(` ${DIM}授权码: ${code}${RESET}\n`);
575
+ log(` ${DIM}Auth code: ${code}${RESET}\n`);
576
576
 
577
577
  const result = await pollForAuth(code);
578
578
  process.stdout.write("\r" + " ".repeat(60) + "\r"); // Clear progress line
@@ -586,16 +586,16 @@ async function main() {
586
586
  agentKey = result.agentKey;
587
587
  apiUrl = result.apiUrl;
588
588
  mqttUrl = result.mqttUrl;
589
- log(` ${CHECK} 授权成功!Agent ID: ${CYAN}${agentId}${RESET}`);
589
+ log(` ${CHECK} Authorized! Agent ID: ${CYAN}${agentId}${RESET}`);
590
590
  }
591
591
 
592
592
  if (!agentId || !agentKey) {
593
- log(` ${CROSS} 凭证无效`);
593
+ log(` ${CROSS} Invalid credentials`);
594
594
  process.exit(1);
595
595
  }
596
596
 
597
597
  // Verify credentials
598
- log(` 验证凭证...`);
598
+ log(` Verifying credentials...`);
599
599
  const timestamp = String(Math.floor(Date.now() / 1000));
600
600
  const path = "/findu-user/api/v1/user/profile/public";
601
601
  const sig = createHmac("sha256", agentKey)
@@ -611,33 +611,33 @@ async function main() {
611
611
  });
612
612
  const data = await resp.json();
613
613
  if (resp.ok && data.code === "200") {
614
- log(` ${CHECK} 昵称: ${data.data?.nickname ?? agentId}`);
614
+ log(` ${CHECK} Nickname: ${data.data?.nickname ?? agentId}`);
615
615
  } else {
616
- log(` ${WARN} 凭证验证失败,继续安装 (${data.message ?? resp.status})`);
616
+ log(` ${WARN} Credential verification failed, continuing (${data.message ?? resp.status})`);
617
617
  }
618
618
  } catch {
619
- log(` ${WARN} 无法验证凭证(网络问题),继续安装`);
619
+ log(` ${WARN} Cannot verify credentials (network issue), continuing`);
620
620
  }
621
621
 
622
622
  // ── Step 3: Install plugin ─────────────────────────────────────
623
- logStep(3, "安装插件");
623
+ logStep(3, "Install Plugin");
624
624
  try {
625
625
  const info = execSync("openclaw plugins info a2hmarket 2>&1", { encoding: "utf-8" });
626
626
  if (info.includes("Status: loaded")) {
627
- log(` ${CHECK} 插件已安装`);
627
+ log(` ${CHECK} Plugin already installed`);
628
628
  } else {
629
629
  throw new Error("not loaded");
630
630
  }
631
631
  } catch {
632
632
  try {
633
- log(` 安装中...`);
633
+ log(` Installing...`);
634
634
  execSync(`echo y | openclaw plugins install ${NPM_SPEC} 2>&1`, {
635
635
  encoding: "utf-8",
636
636
  stdio: "pipe",
637
637
  });
638
- log(` ${CHECK} 安装完成`);
638
+ log(` ${CHECK} Installed`);
639
639
  } catch (err) {
640
- log(` ${CROSS} 安装失败: ${err.message}`);
640
+ log(` ${CROSS} Install failed: ${err.message}`);
641
641
  process.exit(1);
642
642
  }
643
643
  }
@@ -645,7 +645,7 @@ async function main() {
645
645
  // ── Step 3.5: Create openclaw symlink ────────────────────────────
646
646
  // Plugin needs to resolve "openclaw/plugin-sdk" at runtime.
647
647
  // When installed via npm, the module isn't in the plugin's node_modules.
648
- log(` 配置模块依赖...`);
648
+ log(` Linking module dependencies...`);
649
649
  try {
650
650
  const pluginDir = join(OPENCLAW_DIR, "extensions", "a2hmarket");
651
651
  if (existsSync(pluginDir)) {
@@ -687,18 +687,18 @@ async function main() {
687
687
  mkdirSync(symlinkDir, { recursive: true });
688
688
  try { execSync(`rm -f "${symlinkTarget}"`, { stdio: "pipe" }); } catch {}
689
689
  execSync(`ln -sf "${openclawPkg}" "${symlinkTarget}"`, { stdio: "pipe" });
690
- log(` ${CHECK} openclaw/plugin-sdk 已链接`);
690
+ log(` ${CHECK} openclaw/plugin-sdk linked`);
691
691
  } else {
692
- log(` ${WARN} 未找到 openclaw 包路径,服务可能无法启动`);
693
- log(` ${DIM} 尝试过: ${candidates.slice(0, 3).join(", ")}${RESET}`);
692
+ log(` ${WARN} openclaw package not found, service may not start`);
693
+ log(` ${DIM} Tried: ${candidates.slice(0, 3).join(", ")}${RESET}`);
694
694
  }
695
695
  }
696
696
  } catch (err) {
697
- log(` ${WARN} 模块链接失败: ${err.message}`);
697
+ log(` ${WARN} Module linking failed: ${err.message}`);
698
698
  }
699
699
 
700
700
  // ── Step 4: Save credentials & configure openclaw.json ───────
701
- logStep(4, "保存配置");
701
+ logStep(4, "Save Configuration");
702
702
  mkdirSync(DATA_DIR, { recursive: true });
703
703
 
704
704
  const credsData = {
@@ -711,18 +711,18 @@ async function main() {
711
711
  // Configure notification channel
712
712
  if (presetNotify) {
713
713
  credsData.notify = presetNotify;
714
- log(` ${CHECK} 通知渠道: ${presetNotify.channel} → ${presetNotify.target}`);
714
+ log(` ${CHECK} Notification: ${presetNotify.channel} → ${presetNotify.target}`);
715
715
  } else if (!autoYes) {
716
716
  const channels = detectChannels();
717
717
  if (channels.length > 0) {
718
- log(` 检测到 ${channels.length} 个可用渠道:`);
718
+ log(` Found ${channels.length} channel(s):`);
719
719
  channels.forEach((ch, i) => {
720
720
  log(` ${CYAN}${i + 1}${RESET}. ${ch.name}`);
721
721
  });
722
722
 
723
723
  const prompt2 = createPrompt();
724
724
  const choice = await prompt2.ask(
725
- `选择通知渠道 (1-${channels.length},回车默认 1)`,
725
+ `Select notification channel (1-${channels.length}, enter for default 1)`,
726
726
  "1",
727
727
  );
728
728
 
@@ -735,42 +735,42 @@ async function main() {
735
735
  if (chosen.name === "feishu") {
736
736
  target = detectFeishuTarget() || "";
737
737
  if (target) {
738
- log(` 检测到飞书用户: ${CYAN}${target}${RESET}`);
738
+ log(` Detected Feishu user: ${CYAN}${target}${RESET}`);
739
739
  } else {
740
- target = await prompt2.ask("输入飞书 open_id (ou_xxx) chat_id (oc_xxx)", "");
740
+ target = await prompt2.ask("Enter Feishu open_id (ou_xxx) or chat_id (oc_xxx)", "");
741
741
  }
742
742
  } else if (chosen.name === "discord") {
743
- target = await prompt2.ask("输入 Discord 频道 ID", "");
743
+ target = await prompt2.ask("Enter Discord channel ID", "");
744
744
  } else {
745
- target = await prompt2.ask(`输入 ${chosen.name} 目标 ID`, "");
745
+ target = await prompt2.ask(`Enter ${chosen.name} target ID`, "");
746
746
  }
747
747
 
748
748
  if (target) {
749
749
  credsData.notify = { channel: chosen.name, target };
750
- log(` ${CHECK} 通知渠道已配置: ${chosen.name} → ${target}`);
750
+ log(` ${CHECK} Notification configured: ${chosen.name} → ${target}`);
751
751
  } else {
752
- log(` ${WARN} 未输入目标 ID,跳过通知配置`);
752
+ log(` ${WARN} No target ID entered, skipping notification`);
753
753
  }
754
754
  }
755
755
  }
756
756
  prompt2.close();
757
757
  } else {
758
- log(` ${DIM}未检测到可用渠道,跳过通知配置${RESET}`);
758
+ log(` ${DIM}No channels detected, skipping notification${RESET}`);
759
759
  }
760
760
  } else {
761
761
  // --yes without --notify: try auto-detect feishu
762
762
  const feishuTarget = detectFeishuTarget();
763
763
  if (feishuTarget) {
764
764
  credsData.notify = { channel: "feishu", target: feishuTarget };
765
- log(` ${CHECK} 自动检测通知: feishu → ${feishuTarget}`);
765
+ log(` ${CHECK} Auto-detected: feishu → ${feishuTarget}`);
766
766
  } else {
767
- log(` ${DIM}跳过通知配置(使用 --notify 指定)${RESET}`);
767
+ log(` ${DIM}Skipping notification (use --notify to specify)${RESET}`);
768
768
  }
769
769
  }
770
770
 
771
771
  // Save credentials to ~/.openclaw/a2hmarket/credentials.json
772
772
  writeFileSync(CREDS_FILE, JSON.stringify(credsData, null, 2) + "\n");
773
- log(` ${CHECK} 凭证已保存`);
773
+ log(` ${CHECK} Credentials saved`);
774
774
 
775
775
  // Ensure a2h tools in alsoAllow (if whitelist mode is active)
776
776
  try {
@@ -797,7 +797,7 @@ async function main() {
797
797
  }
798
798
  if (added > 0) {
799
799
  writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n");
800
- log(` ${CHECK} ${added} 个工具已添加到白名单`);
800
+ log(` ${CHECK} ${added} tools added to allowlist`);
801
801
  }
802
802
  }
803
803
  } catch {}
@@ -810,52 +810,52 @@ async function main() {
810
810
  if (entry && (entry.agentId || entry.agentKey)) {
811
811
  cfg.plugins.entries.a2hmarket = { enabled: true };
812
812
  writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n");
813
- log(` ${CHECK} 清理 openclaw.json 中的旧凭证`);
813
+ log(` ${CHECK} Cleaned stale credentials from openclaw.json`);
814
814
  }
815
815
  } catch {}
816
816
 
817
817
  // ── Step 5: Restart gateway ────────────────────────────────────
818
- logStep(5, "启动服务");
818
+ logStep(5, "Start Service");
819
819
  try {
820
820
  execSync("openclaw gateway restart 2>&1", { encoding: "utf-8", stdio: "pipe" });
821
- log(` ${CHECK} Gateway 已重启`);
821
+ log(` ${CHECK} Gateway restarted`);
822
822
  } catch {
823
- log(` ${WARN} 请手动执行: openclaw gateway restart`);
823
+ log(` ${WARN} Please run manually: openclaw gateway restart`);
824
824
  }
825
825
 
826
826
  // ── Step 6: Verify ─────────────────────────────────────────────
827
- logStep(6, "验证");
827
+ logStep(6, "Verify");
828
828
  await new Promise((r) => setTimeout(r, 5000));
829
829
  try {
830
830
  const info = execSync("openclaw plugins info a2hmarket 2>&1", { encoding: "utf-8" });
831
831
  if (info.includes("Status: loaded")) {
832
- log(` ${CHECK} 插件运行正常`);
832
+ log(` ${CHECK} Plugin running`);
833
833
  const toolMatch = info.match(/Tools:\n([\s\S]*?)(?:\n\n|\nServices:)/);
834
834
  if (toolMatch) {
835
- log(` ${CHECK} ${toolMatch[1].trim().split("\n").length} 个工具已注册`);
835
+ log(` ${CHECK} ${toolMatch[1].trim().split("\n").length} tools registered`);
836
836
  }
837
837
  }
838
838
  } catch {
839
- log(` ${WARN} 请检查: openclaw plugins info a2hmarket`);
839
+ log(` ${WARN} Please check: openclaw plugins info a2hmarket`);
840
840
  }
841
841
 
842
842
  // ── Step 7: Send onboarding message ──────────────────────────
843
843
  if (credsData.notify?.channel && credsData.notify?.target) {
844
- logStep(7, "发送欢迎消息");
844
+ logStep(7, "Send Welcome Message");
845
845
  try {
846
846
  await sendOnboarding(credsData.notify.channel, credsData.notify.target, agentId);
847
- log(` ${CHECK} 欢迎消息已发送到 ${credsData.notify.channel}`);
847
+ log(` ${CHECK} Welcome message sent to ${credsData.notify.channel}`);
848
848
  } catch (err) {
849
- log(` ${WARN} 欢迎消息发送失败: ${err.message}`);
849
+ log(` ${WARN} Welcome message failed: ${err.message}`);
850
850
  }
851
851
  }
852
852
 
853
853
  // ── Done ───────────────────────────────────────────────────────
854
- log(`\n${GREEN}${BOLD}🎉 安装完成!${RESET}\n`);
854
+ log(`\n${GREEN}${BOLD}🎉 Setup complete!${RESET}\n`);
855
855
  log(` Agent ID: ${CYAN}${agentId}${RESET}`);
856
- log(` 数据目录: ${DIM}${DATA_DIR}${RESET}`);
856
+ log(` Data dir: ${DIM}${DATA_DIR}${RESET}`);
857
857
  if (credsData.notify) {
858
- log(` 飞书通知: ${CYAN}${credsData.notify.target}${RESET}`);
858
+ log(` Notify: ${CYAN}${credsData.notify.channel}:${credsData.notify.target}${RESET}`);
859
859
  }
860
860
  log("");
861
861
  }
@@ -8,7 +8,7 @@ export function registerDiscussionTools(api: OpenClawPluginApi, client: A2HApiCl
8
8
  api.registerTool({
9
9
  name: "a2h_discussion_publish",
10
10
  description:
11
- "Publish a new discussion post. Must set confirm_human_reviewed=true to confirm a human has reviewed the content before publishing.",
11
+ "Publish a new discussion post. Confirm content with the human in conversation before calling.",
12
12
  parameters: {
13
13
  type: "object",
14
14
  properties: {
@@ -19,17 +19,10 @@ export function registerDiscussionTools(api: OpenClawPluginApi, client: A2HApiCl
19
19
  items: { type: "string" },
20
20
  description: "Optional array of picture URLs",
21
21
  },
22
- confirm_human_reviewed: {
23
- type: "boolean",
24
- description: "Must be true — confirms a human has reviewed the content",
25
- },
26
22
  },
27
- required: ["title", "content", "confirm_human_reviewed"],
23
+ required: ["title", "content"],
28
24
  },
29
25
  execute: async (params: Record<string, unknown>) => {
30
- if (params.confirm_human_reviewed !== true) {
31
- throw new Error("confirm_human_reviewed must be true. A human must review discussion content before publishing.");
32
- }
33
26
  const body: Record<string, unknown> = {
34
27
  type: 4,
35
28
  title: params.title,
@@ -45,24 +38,17 @@ export function registerDiscussionTools(api: OpenClawPluginApi, client: A2HApiCl
45
38
  api.registerTool({
46
39
  name: "a2h_discussion_reply",
47
40
  description:
48
- "Reply to an existing discussion post. Must set confirm_human_reviewed=true to confirm a human has reviewed the content.",
41
+ "Reply to an existing discussion post. Confirm content with the human in conversation before calling.",
49
42
  parameters: {
50
43
  type: "object",
51
44
  properties: {
52
45
  parent_works_id: { type: "string", description: "ID of the discussion to reply to" },
53
46
  title: { type: "string", description: "Reply title" },
54
47
  content: { type: "string", description: "Reply content" },
55
- confirm_human_reviewed: {
56
- type: "boolean",
57
- description: "Must be true — confirms a human has reviewed the content",
58
- },
59
48
  },
60
- required: ["parent_works_id", "title", "content", "confirm_human_reviewed"],
49
+ required: ["parent_works_id", "title", "content"],
61
50
  },
62
51
  execute: async (params: Record<string, unknown>) => {
63
- if (params.confirm_human_reviewed !== true) {
64
- throw new Error("confirm_human_reviewed must be true. A human must review discussion content before publishing.");
65
- }
66
52
  const body = {
67
53
  type: 4,
68
54
  title: params.title,
@@ -62,7 +62,7 @@ export function registerWorksTools(api: OpenClawPluginApi, client: A2HApiClient)
62
62
  api.registerTool({
63
63
  name: "a2h_works_publish",
64
64
  description:
65
- "Publish a new works post (service or demand). Requires human review confirmation.",
65
+ "Publish a new works post (service or demand). Confirm content with the human in conversation before calling.",
66
66
  parameters: {
67
67
  type: "object",
68
68
  properties: {
@@ -73,18 +73,10 @@ export function registerWorksTools(api: OpenClawPluginApi, client: A2HApiClient)
73
73
  service_method: { type: "string", description: "online or offline" },
74
74
  service_location: { type: "string", description: "Location (for offline)" },
75
75
  picture: { type: "string", description: "Cover image URL" },
76
- confirm_human_reviewed: {
77
- type: "boolean",
78
- description: "Must be true — confirms human has reviewed this content",
79
- },
80
76
  },
81
- required: ["type", "title", "content", "confirm_human_reviewed"],
77
+ required: ["type", "title", "content"],
82
78
  },
83
79
  execute: async (params: Record<string, unknown>) => {
84
- if (!params.confirm_human_reviewed) {
85
- throw new Error("confirm_human_reviewed must be true. Human must review content before publishing.");
86
- }
87
-
88
80
  const extendInfo: Record<string, unknown> = { pois: [] };
89
81
  if (params.expected_price) extendInfo.expectedPrice = params.expected_price;
90
82
  if (params.service_method) extendInfo.serviceMethod = params.service_method;
@@ -105,7 +97,7 @@ export function registerWorksTools(api: OpenClawPluginApi, client: A2HApiClient)
105
97
 
106
98
  api.registerTool({
107
99
  name: "a2h_works_update",
108
- description: "Update an existing works post. Requires human review confirmation.",
100
+ description: "Update an existing works post. Confirm changes with the human in conversation before calling.",
109
101
  parameters: {
110
102
  type: "object",
111
103
  properties: {
@@ -117,15 +109,10 @@ export function registerWorksTools(api: OpenClawPluginApi, client: A2HApiClient)
117
109
  service_method: { type: "string", description: "online or offline" },
118
110
  service_location: { type: "string", description: "Location" },
119
111
  picture: { type: "string", description: "Cover image URL" },
120
- confirm_human_reviewed: { type: "boolean", description: "Must be true" },
121
112
  },
122
- required: ["works_id", "type", "title", "confirm_human_reviewed"],
113
+ required: ["works_id", "type", "title"],
123
114
  },
124
115
  execute: async (params: Record<string, unknown>) => {
125
- if (!params.confirm_human_reviewed) {
126
- throw new Error("confirm_human_reviewed must be true.");
127
- }
128
-
129
116
  const extendInfo: Record<string, unknown> = { pois: [] };
130
117
  if (params.expected_price) extendInfo.expectedPrice = params.expected_price;
131
118
  if (params.service_method) extendInfo.serviceMethod = params.service_method;